From 1db73feb466ba7b44e1e4ebd63254e73c0c9bf49 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 24 Jan 2020 02:07:33 -0300 Subject: [PATCH 001/506] add coin info for markets (#742) --- api/maketdata.go | 9 +++++++-- coin/gen_test.go | 2 +- pkg/blockatlas/marketdata.go | 36 +++++++++++++++++++++++++++------- platform/vechain/api.go | 2 +- services/assets/client.go | 32 ++++++++++++++++++------------ services/assets/client_test.go | 6 +++--- 6 files changed, 60 insertions(+), 27 deletions(-) diff --git a/api/maketdata.go b/api/maketdata.go index b4049f257..df574c60a 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -7,6 +7,8 @@ import ( "github.com/trustwallet/blockatlas/marketdata" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/services/assets" "github.com/trustwallet/blockatlas/storage" "net/http" "strconv" @@ -190,15 +192,18 @@ func getCoinInfoHandler() func(c *gin.Context) { ginutils.RenderError(c, http.StatusInternalServerError, "Invalid coin") return } - token := c.Query("token") + token := c.Query("token") currency := c.DefaultQuery("currency", blockatlas.DefaultCurrency) - chart, err := charts.GetCoinInfo(uint(coinId), token, currency) if err != nil { ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) return } + chart.Info, err = assets.GetCoinInfo(coinId) + if err != nil { + logger.Error(err, "invalid coin info", logger.Params{"coin": coinId, "currency": currency}) + } ginutils.RenderSuccess(c, chart) } } diff --git a/coin/gen_test.go b/coin/gen_test.go index d86c9dd43..067bee058 100644 --- a/coin/gen_test.go +++ b/coin/gen_test.go @@ -46,7 +46,7 @@ func TestCoinFile(t *testing.T) { } defer f.Close() b, err := ioutil.ReadAll(f) - if err != nil{ + if err != nil { t.Error(err) } code := string(b) diff --git a/pkg/blockatlas/marketdata.go b/pkg/blockatlas/marketdata.go index 7f68b2f41..a39ca30e6 100644 --- a/pkg/blockatlas/marketdata.go +++ b/pkg/blockatlas/marketdata.go @@ -34,18 +34,40 @@ type ChartData struct { Error string `json:"error,omitempty"` } -type ChartCoinInfo struct { - Vol24 float64 `json:"volume_24"` - MarketCap float64 `json:"market_cap"` - CirculatingSupply float64 `json:"circulating_supply"` - TotalSupply float64 `json:"total_supply"` -} - type ChartPrice struct { Price float64 `json:"price"` Date int64 `json:"date"` } +type ChartCoinInfo struct { + Vol24 float64 `json:"volume_24"` + MarketCap float64 `json:"market_cap"` + CirculatingSupply float64 `json:"circulating_supply"` + TotalSupply float64 `json:"total_supply"` + Info CoinInfo `json:"info,omitempty"` +} + +type CoinInfo struct { + Name string `json:"name"` + Website string `json:"website"` + SourceCode string `json:"source_code"` + Whitepaper string `json:"whitepaper"` + Explorers []Link `json:"explorers"` + Socials []Link `json:"socials"` + Details []Detail `json:"details"` + DataSource string `json:"data_source"` +} + +type Link struct { + Name string `json:"name"` + Url string `json:"url"` +} + +type Detail struct { + Language string `json:"language"` + Description string `json:"description"` +} + func (t *Ticker) SetCoinId(coinId uint) { t.Coin = coinId t.CoinName = "" diff --git a/platform/vechain/api.go b/platform/vechain/api.go index 0121cb1a0..54d28d981 100644 --- a/platform/vechain/api.go +++ b/platform/vechain/api.go @@ -169,7 +169,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { txs := make(blockatlas.TxPage, 0) for _, t := range transfers { trxId, err := p.client.GetTransactionByID(t.Meta.TxId) - if err != nil{ + if err != nil { continue } tx, err := NormalizeTransaction(t, trxId) diff --git a/services/assets/client.go b/services/assets/client.go index 8aa5f822e..70cba99a2 100644 --- a/services/assets/client.go +++ b/services/assets/client.go @@ -12,6 +12,16 @@ const ( AssetsURL = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/" ) +func GetCoinInfo(coinId int) (info blockatlas.CoinInfo, err error) { + c, ok := coin.Coins[uint(coinId)] + if !ok { + return info, errors.E("coin not found") + } + request := blockatlas.InitClient(AssetsURL + c.Handle) + err = request.GetWithCache(&info, "info/info.json", nil, time.Hour*1) + return +} + func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) { validatorList, err := GetValidators(api) if err != nil { @@ -25,7 +35,7 @@ func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) } func GetValidators(api blockatlas.StakeAPI) ([]blockatlas.StakeValidator, error) { - assetsValidators, err := GetValidatorsInfo(api.Coin()) + assetsValidators, err := getValidatorsInfo(api.Coin()) if err != nil { return nil, errors.E(err, "unable to fetch validators list from the registry").PushToSentry() } @@ -34,20 +44,16 @@ func GetValidators(api blockatlas.StakeAPI) ([]blockatlas.StakeValidator, error) if err != nil { return nil, err } - results := NormalizeValidators(validators, assetsValidators, api.Coin()) + 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 } -func GetValidatorsInfo(coin coin.Coin) ([]AssetValidator, error) { +func getValidatorsInfo(coin coin.Coin) ([]AssetValidator, error) { var results []AssetValidator - request := blockatlas.Request{ - BaseUrl: AssetsURL + coin.Handle, - HttpClient: blockatlas.DefaultClient, - ErrorHandler: blockatlas.DefaultErrorHandler, - } + request := blockatlas.InitClient(AssetsURL + coin.Handle) err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) if err != nil { return nil, errors.E(err, errors.Params{"coin": coin.Handle}).PushToSentry() @@ -55,19 +61,19 @@ func GetValidatorsInfo(coin coin.Coin) ([]AssetValidator, error) { return results, nil } -func NormalizeValidators(validators []blockatlas.Validator, assets []AssetValidator, coin coin.Coin) []blockatlas.StakeValidator { +func normalizeValidators(validators []blockatlas.Validator, assets []AssetValidator, coin coin.Coin) []blockatlas.StakeValidator { results := make([]blockatlas.StakeValidator, 0) for _, v := range validators { for _, v2 := range assets { if v.ID == v2.ID && !v2.Status.Disabled { - results = append(results, NormalizeValidator(v, v2, coin)) + results = append(results, normalizeValidator(v, v2, coin)) } } } return results } -func NormalizeValidator(plainValidator blockatlas.Validator, validator AssetValidator, coin coin.Coin) blockatlas.StakeValidator { +func normalizeValidator(plainValidator blockatlas.Validator, validator AssetValidator, coin coin.Coin) blockatlas.StakeValidator { details := plainValidator.Details details.Reward.Annual = calculateAnnual(details.Reward.Annual, validator.Payout.Commission) return blockatlas.StakeValidator{ @@ -76,7 +82,7 @@ func NormalizeValidator(plainValidator blockatlas.Validator, validator AssetVali Info: blockatlas.StakeValidatorInfo{ Name: validator.Name, Description: validator.Description, - Image: GetImage(coin, plainValidator.ID), + Image: getImage(coin, plainValidator.ID), Website: validator.Website, }, Details: details, @@ -87,6 +93,6 @@ func calculateAnnual(annual float64, commission float64) float64 { return (annual * (100 - commission)) / 100 } -func GetImage(c coin.Coin, ID string) string { +func getImage(c coin.Coin, ID string) string { return AssetsURL + c.Handle + "/validators/assets/" + ID + "/logo.png" } diff --git a/services/assets/client_test.go b/services/assets/client_test.go index 577257dc3..cd31052da 100644 --- a/services/assets/client_test.go +++ b/services/assets/client_test.go @@ -38,7 +38,7 @@ var expectedStakeValidator = blockatlas.StakeValidator{ } func TestGetImage(t *testing.T) { - image := GetImage(c, "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp") + image := getImage(c, "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp") expected := "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp/logo.png" @@ -47,14 +47,14 @@ func TestGetImage(t *testing.T) { func TestNormalizeValidator(t *testing.T) { - result := NormalizeValidator(validators[0], assets[0], c) + result := normalizeValidator(validators[0], assets[0], c) assert.Equal(t, expectedStakeValidator, result) } func TestNormalizeValidators(t *testing.T) { - result := NormalizeValidators(validators, assets, c) + result := normalizeValidators(validators, assets, c) expected := []blockatlas.StakeValidator{expectedStakeValidator} From 6f0bdd891f4127501b37a669e1a583c41a8ebb1a Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 24 Jan 2020 02:16:53 -0300 Subject: [PATCH 002/506] Change tezos api (#738) * start change api provider * refector tezos clientj for new api * tezos channel for tx * fix block parser * fix unit tests --- config.yml | 2 +- pkg/blockatlas/client.go | 4 + platform/tezos/api.go | 69 +++---- platform/tezos/api_test.go | 383 +++++++++++++++++++++++-------------- platform/tezos/client.go | 32 ++-- platform/tezos/model.go | 59 +++--- platform/tezos/rpc.go | 24 ++- 7 files changed, 340 insertions(+), 233 deletions(-) diff --git a/config.yml b/config.yml index 6230fe504..0c9da32e3 100644 --- a/config.yml +++ b/config.yml @@ -79,7 +79,7 @@ kin: # [XTZ] Tezos: https://tezos.com tezos: - api: https://api.tzstats.com/explorer + api: https://api.tezos.id/mooncake/mainnet rpc: https://mainnet.tezos.org.ua # [ETH] Ethereum: https://ethereum.org (Trust-Ray API) diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go index 8de11cfca..409aa5162 100644 --- a/pkg/blockatlas/client.go +++ b/pkg/blockatlas/client.go @@ -21,6 +21,10 @@ type Request struct { ErrorHandler func(res *http.Response, uri string) error } +func (r *Request) SetTimeout(seconds time.Duration) { + r.HttpClient.Timeout = time.Second * seconds +} + func InitClient(baseUrl string) Request { return Request{ Headers: make(map[string]string), diff --git a/platform/tezos/api.go b/platform/tezos/api.go index 6fb3532cb..928c9746a 100644 --- a/platform/tezos/api.go +++ b/platform/tezos/api.go @@ -6,9 +6,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" services "github.com/trustwallet/blockatlas/services/assets" - "math" - "strconv" - "time" ) type Platform struct { @@ -20,6 +17,7 @@ const Annual = 6.09 func (p *Platform) Init() error { p.client = Client{blockatlas.InitClient(viper.GetString("tezos.api"))} + p.client.SetTimeout(25) p.rpcClient = RpcClient{blockatlas.InitClient(viper.GetString("tezos.rpc"))} return nil } @@ -33,9 +31,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { if err != nil { return nil, err } - txs := NormalizeTxs(s) - return txs, nil } @@ -56,39 +52,39 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { } func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { - account, err := p.client.GetAccount(address) + delegations, err := p.client.GetDelegations(address) if err != nil { return nil, err } - if !account.IsDelegated { + if len(delegations) == 0 { return make(blockatlas.DelegationsPage, 0), nil } validators, err := services.GetValidatorsMap(p) if err != nil { return nil, err } - return NormalizeDelegation(account, validators) + delegatedBalance := p.rpcClient.GetDelegatedBalance(address) + return NormalizeDelegation(delegations[0], delegatedBalance, validators) } -func NormalizeDelegation(account Account, validators blockatlas.ValidatorMap) (blockatlas.DelegationsPage, error) { - validator, ok := validators[account.Delegate] +func NormalizeDelegation(delegation TxDelegation, delegatedBalance string, validators blockatlas.ValidatorMap) (blockatlas.DelegationsPage, error) { + validator, ok := validators[delegation.Delegation.Delegate] if !ok { return nil, errors.E("Validator not found", - errors.Params{"Address": account.Address, "Delegate": account.Delegate, "Balance": account.Balance}) + errors.Params{"Address": delegation.Delegation.Source, "Delegate": delegation.Delegation.Delegate}) } - balance := removeDecimals(account.Balance) return blockatlas.DelegationsPage{ { Delegator: validator, - Value: balance, + Value: delegatedBalance, Status: blockatlas.DelegationStatusActive, }, }, nil } -func NormalizeTxs(srcTxs []Tx) (txs []blockatlas.Tx) { +func NormalizeTxs(srcTxs []Transaction) (txs []blockatlas.Tx) { for _, srcTx := range srcTxs { - tx, ok := NormalizeTx(&srcTx) + tx, ok := NormalizeTx(srcTx) if !ok { continue } @@ -100,7 +96,6 @@ func NormalizeTxs(srcTxs []Tx) (txs []blockatlas.Tx) { func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { results := make(blockatlas.ValidatorPage, 0) validators, err := p.rpcClient.GetValidators() - if err != nil { return results, err } @@ -117,11 +112,7 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { } func (p *Platform) UndelegatedBalance(address string) (string, error) { - account, err := p.client.GetAccount(address) - if err != nil { - return "0", err - } - return removeDecimals(account.Balance), nil + return p.rpcClient.GetBalance(address), nil } func getDetails() blockatlas.StakingDetails { @@ -136,7 +127,6 @@ func getDetails() blockatlas.StakingDetails { func normalizeValidator(v Validator) (validator blockatlas.Validator) { // How to calculate Tezos APR? I have no idea. Tezos team does not know either. let's assume it's around 7% - no way to calculate in decentralized manner // Delegation rewards distributed by the validators manually, it's up to them to do it. - return blockatlas.Validator{ Status: true, ID: v.Address, @@ -145,37 +135,29 @@ func normalizeValidator(v Validator) (validator blockatlas.Validator) { } // NormalizeTx converts a Tezos transaction into the generic model -func NormalizeTx(srcTx *Tx) (tx blockatlas.Tx, ok bool) { - unix := int64(0) - date, err := time.Parse("2006-01-02T15:04:05Z", srcTx.Time) - if err == nil { - unix = date.Unix() - } - - if srcTx.Type != "transaction" { +func NormalizeTx(srcTx Transaction) (tx blockatlas.Tx, ok bool) { + if srcTx.Tx.Kind != "transaction" { return tx, false } var status blockatlas.Status var errMsg string - if srcTx.Success && srcTx.Status == "applied" { + if srcTx.Tx.Status == "applied" { status = blockatlas.StatusCompleted } else { status = blockatlas.StatusFailed errMsg = "transaction failed" } - - volume := removeDecimals(srcTx.Volume) return blockatlas.Tx{ - ID: srcTx.Hash, + ID: srcTx.Op.OpHash, Coin: coin.XTZ, - Date: unix, - From: srcTx.Sender, - To: srcTx.Receiver, - Fee: blockatlas.Amount(strconv.Itoa(srcTx.Fee)), - Block: srcTx.Height, + Date: srcTx.Op.BlockTimestamp.Unix(), + From: srcTx.Tx.Source, + To: srcTx.Tx.Destination, + Fee: blockatlas.Amount(srcTx.Tx.Fee), + Block: srcTx.Op.BlockLevel, Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(volume), + Value: blockatlas.Amount(srcTx.Tx.Amount), Symbol: coin.Coins[coin.XTZ].Symbol, Decimals: coin.Coins[coin.XTZ].Decimals, }, @@ -183,10 +165,3 @@ func NormalizeTx(srcTx *Tx) (tx blockatlas.Tx, ok bool) { Error: errMsg, }, true } - -func removeDecimals(volume float64) string { - decimals := coin.Coins[coin.XTZ].Decimals - d := math.Pow10(int(decimals)) - v := volume * d - return strconv.Itoa(int(v)) -} diff --git a/platform/tezos/api_test.go b/platform/tezos/api_test.go index 6431ba858..716ce40da 100644 --- a/platform/tezos/api_test.go +++ b/platform/tezos/api_test.go @@ -8,154 +8,255 @@ import ( "testing" ) -const transferSrc = ` +const transferSrc1 = ` { - "ops": [ - { - "hash": "opN4YjaBwngT8Csz5gKzdwfm78cNquWwcHkjxfHqqstCAT5HWcM", - "type": "transaction", - "block": "BKq8skWbocNHvYw2af2erSvh9UYhPkofrWf1UBxDffhDZHEhUxw", - "time": "2018-07-04T12:43:27Z", - "height": 5442, - "status": "applied", - "is_success": true, - "is_contract": false, - "gas_limit": 200, - "gas_used": 100, - "gas_price": 0, - "volume": 1, - "fee": 0, - "sender": "tz1TcgvvzDD4hwHQHdPNGw6ZW9wkomwxaQkP", - "receiver": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q" - }, - { - "hash": "oo3aARP7Y271ZkNi6XqsZZHbzrV1sDwdqD8wrgvSBPaSRK2JDuj", - "type": "reveal", - "block": "BL3ET2QcAt7xNU2cnxjrY4iM3Wwe8UHLHCE85rhCiSP8zd26Qnk", - "time": "2018-07-04T12:50:27Z", - "height": 5449, - "status": "applied", - "is_success": true, - "is_contract": false, - "gas_limit": 0, - "gas_used": 0, - "gas_price": 0, - "volume": 0, - "fee": 0, - "data": "edpktthB79sCK3xQSekMfuhjHLLC593UW5CHyDR9CueVF68PS1K3ZH", - "sender": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q" - }, - { - "hash": "oo3aARP7Y271ZkNi6XqsZZHbzrV1sDwdqD8wrgvSBPaSRK2JDuj", - "type": "transaction", - "block": "BL3ET2QcAt7xNU2cnxjrY4iM3Wwe8UHLHCE85rhCiSP8zd26Qnk", - "time": "2018-07-04T12:50:27Z", - "height": 5449, - "status": "applied", - "is_success": true, - "is_contract": false, - "gas_limit": 360, - "gas_used": 260, - "gas_price": 0, - "volume": 1, - "fee": 0, - "sender": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", - "receiver": "tz1TcgvvzDD4hwHQHdPNGw6ZW9wkomwxaQkP" - } - ] + "tx": { + "destination": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + "amount": "1560", + "gasLimit": "15385", + "kind": "transaction", + "operationResultStatus": "applied", + "blockHash": "BMJYDJk9wRpxQuuqcFS7MZivqShtrgG18eY5K6rSDBpx5vcJLB2", + "fee": "0", + "operationResultConsumedGas": "10207", + "counter": "1383819", + "blockLevel": 791441, + "operationResultErrors": null, + "blockTimestamp": "2020-01-22T16:34:22Z", + "parameters": null, + "source": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "insertedTimestamp": "2020-01-22 16:34:56.015281 UTC" + }, + "op": { + "opHash": "ooBAC2ynR5LfU9L2KEon8Z3ujmwEVyB9si1rrppBCmmEn4Mr3bJ", + "chainId": "NetXdQprcVkpaWU", + "blockHash": "BMJYDJk9wRpxQuuqcFS7MZivqShtrgG18eY5K6rSDBpx5vcJLB2", + "blockLevel": 791441, + "blockTimestamp": "2020-01-22T16:34:22Z", + "insertedTimestamp": "2020-01-22 16:34:49.405793 UTC" + } } ` -const validatorSrc = ` -[ - {"pkh":"tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m","rolls":3726} -] +const transferSrc2 = ` +{ + "tx": { + "destination": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + "amount": "1751", + "gasLimit": "15385", + "kind": "transaction", + "operationResultStatus": "applied", + "blockHash": "BLJKc6f6SpFs3Jr7WMp2ekx5jQQyzHWN6SWHDo2AJ41HJoPKTF2", + "fee": "0", + "operationResultConsumedGas": "10207", + "counter": "1383094", + "blockLevel": 788725, + "operationResultErrors": null, + "blockTimestamp": "2020-01-20T18:54:52Z", + "parameters": null, + "source": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "insertedTimestamp": "2020-01-20 18:56:34.828193 UTC" + }, + "op": { + "opHash": "ookuQhVYopxrg8FtnfNASxpMhmnNhBqYaK3PJQXDpP7sDCJAZwf", + "chainId": "NetXdQprcVkpaWU", + "blockHash": "BLJKc6f6SpFs3Jr7WMp2ekx5jQQyzHWN6SWHDo2AJ41HJoPKTF2", + "blockLevel": 788725, + "blockTimestamp": "2020-01-20T18:54:52Z", + "insertedTimestamp": "2020-01-20 18:56:28.193751 UTC" + } +} ` -func TestNormalize(t *testing.T) { - var srcOp Op - err := json.Unmarshal([]byte(transferSrc), &srcOp) - assert.NoError(t, err) - assert.NotNil(t, srcOp) - - expected := []blockatlas.Tx{ - { - ID: "opN4YjaBwngT8Csz5gKzdwfm78cNquWwcHkjxfHqqstCAT5HWcM", - Coin: coin.XTZ, - Date: 1530708207, - From: "tz1TcgvvzDD4hwHQHdPNGw6ZW9wkomwxaQkP", - To: "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", - Fee: "100", - Block: 5442, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1000000"), - Symbol: coin.Coins[coin.XTZ].Symbol, - Decimals: coin.Coins[coin.XTZ].Decimals, - }, - Status: "completed", - }, - { - ID: "oo3aARP7Y271ZkNi6XqsZZHbzrV1sDwdqD8wrgvSBPaSRK2JDuj", - Coin: coin.XTZ, - Date: 1530708627, - From: "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", - To: "tz1TcgvvzDD4hwHQHdPNGw6ZW9wkomwxaQkP", - Fee: "260", - Block: 5449, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1000000"), - Symbol: coin.Coins[coin.XTZ].Symbol, - Decimals: coin.Coins[coin.XTZ].Decimals, - }, - Status: "completed", - }, - } - result := NormalizeTxs(srcOp.Txs) - assert.Equal(t, result, expected) +const transferSrc3 = ` +{ + "tx": { + "destination": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + "amount": "1751", + "gasLimit": "15385", + "kind": "transaction", + "operationResultStatus": "backtracked", + "blockHash": "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", + "fee": "0", + "operationResultConsumedGas": "10207", + "counter": "1382930", + "blockLevel": 788568, + "operationResultErrors": null, + "blockTimestamp": "2020-01-20T16:16:32Z", + "parameters": null, + "source": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "insertedTimestamp": "2020-01-20 16:19:06.938114 UTC" + }, + "op": { + "opHash": "ooXN845juCMcQuqeodwBJWNhY17A5HKyWRxbcwS1m6TfqCqjM8q", + "chainId": "NetXdQprcVkpaWU", + "blockHash": "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", + "blockLevel": 788568, + "blockTimestamp": "2020-01-20T16:16:32Z", + "insertedTimestamp": "2020-01-20 16:18:59.855515 UTC" + } } +` -func TestNormalizeValidator(t *testing.T) { - var v Validator - _ = json.Unmarshal([]byte(validatorSrc), &v) - expected := blockatlas.Validator{ - Status: true, - ID: v.Address, - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: Annual}, - MinimumAmount: blockatlas.Amount("0"), - Type: blockatlas.DelegationTypeDelegate, - }, - } - result := normalizeValidator(v) - assert.Equal(t, result, expected) +const transferSrc4 = ` +{ + "tx": { + "destination": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + "amount": "1751", + "gasLimit": "15385", + "kind": "delegation", + "operationResultStatus": "backtracked", + "blockHash": "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", + "fee": "0", + "operationResultConsumedGas": "10207", + "counter": "1382930", + "blockLevel": 788568, + "operationResultErrors": null, + "blockTimestamp": "2020-01-20T16:16:32Z", + "parameters": null, + "source": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "insertedTimestamp": "2020-01-20 16:19:06.938114 UTC" + }, + "op": { + "opHash": "ooXN845juCMcQuqeodwBJWNhY17A5HKyWRxbcwS1m6TfqCqjM8q", + "chainId": "NetXdQprcVkpaWU", + "blockHash": "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", + "blockLevel": 788568, + "blockTimestamp": "2020-01-20T16:16:32Z", + "insertedTimestamp": "2020-01-20 16:18:59.855515 UTC" + } +} +` + +var transfer1 = blockatlas.Tx{ + ID: "ooBAC2ynR5LfU9L2KEon8Z3ujmwEVyB9si1rrppBCmmEn4Mr3bJ", + Coin: coin.XTZ, + Date: 1579710862, + From: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + To: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + Fee: "0", + Block: 791441, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("1560"), + Symbol: coin.Coins[coin.XTZ].Symbol, + Decimals: coin.Coins[coin.XTZ].Decimals, + }, + Status: blockatlas.StatusCompleted, } -func Test_removeDecimals(t *testing.T) { +var transfer2 = blockatlas.Tx{ + ID: "ookuQhVYopxrg8FtnfNASxpMhmnNhBqYaK3PJQXDpP7sDCJAZwf", + Coin: coin.XTZ, + Date: 1579546492, + From: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + To: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + Fee: "0", + Block: 788725, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("1751"), + Symbol: coin.Coins[coin.XTZ].Symbol, + Decimals: coin.Coins[coin.XTZ].Decimals, + }, + Status: blockatlas.StatusCompleted, +} + +var transfer3 = blockatlas.Tx{ + ID: "ooXN845juCMcQuqeodwBJWNhY17A5HKyWRxbcwS1m6TfqCqjM8q", + Coin: coin.XTZ, + Date: 1579536992, + From: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + To: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + Fee: "0", + Block: 788568, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("1751"), + Symbol: coin.Coins[coin.XTZ].Symbol, + Decimals: coin.Coins[coin.XTZ].Decimals, + }, + Status: blockatlas.StatusFailed, + Error: "transaction failed", +} + +func TestNormalizeTx(t *testing.T) { tests := []struct { name string - volume float64 - want string + srcTx string + wantTx blockatlas.Tx + wantOk bool }{ - {"one float precision", 9.5, "9500000"}, - {"zero float precision", 9, "9000000"}, - {"five float precision", 9.00005, "9000050"}, - {"six float precision", 9.000005, "9000005"}, + {"transfer 1", transferSrc1, transfer1, true}, + {"transfer 2", transferSrc2, transfer2, true}, + {"transfer 3", transferSrc3, transfer3, true}, + {"transfer 4", transferSrc4, blockatlas.Tx{}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := removeDecimals(tt.volume); got != tt.want { - t.Errorf("removeDecimals() = %v, want %v", got, tt.want) - } + var transaction Transaction + err := json.Unmarshal([]byte(tt.srcTx), &transaction) + assert.Nil(t, err) + gotTx, gotOk := NormalizeTx(transaction) + assert.Equal(t, gotOk, tt.wantOk, "transfer ok result don't equal") + assert.Equal(t, gotTx, tt.wantTx, "transfer don't equal") }) } } -const accountSrc = ` +const validatorSrc = ` +[ + {"pkh":"tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m","rolls":3726} +] +` + +var validator = blockatlas.Validator{ + Status: true, + ID: "tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m", + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: Annual}, + MinimumAmount: blockatlas.Amount("0"), + Type: blockatlas.DelegationTypeDelegate, + }, +} + +func TestNormalizeValidator(t *testing.T) { + var v []Validator + err := json.Unmarshal([]byte(validatorSrc), &v) + assert.Nil(t, err) + result := normalizeValidator(v[0]) + assert.Equal(t, validator, result) +} + +const delegationsSrc = ` { - "address": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - "total_balance": 68995.611927, - "is_delegated": true + "op": { + "signature": "sigvHd2YBByFXU8nL4CZKSTYXNdMapMsJw1f239YRRjgz9NvrTyA6iGnpBDhi9kCB4zMHysrg9H4jxcpPH975WiQtEmkMjb5", + "blockUuid": "4b292c55-41ba-4383-a1d6-03fb71b88f41", + "opHash": "opGphHGNEZZN5rF78yxwe9BJydxYA2yqxECnZR6s6HcxXtCg8Sj", + "uuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", + "chainId": "NetXdQprcVkpaWU", + "blockHash": "BLkscXpE63gajVzmgBS7fQx63hERKQRCZFGtMXdYY6WPThHyji7", + "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", + "branch": "BKqtLegZfdPR3USyYYcMpedB59W5eUBuFZAVpVMPpFgEvMcZjr1", + "blockLevel": 791778, + "blockTimestamp": "2020-01-22T22:13:38Z", + "insertedTimestamp": "2020-01-22 22:14:05.937406 UTC" + }, + "delegation": { + "storageLimit": "257", + "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "opUuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", + "uuid": "6459fcd9-5eee-4999-ac4d-92330b9eaab3", + "gasLimit": "10600", + "kind": "delegation", + "operationResultStatus": "applied", + "fee": "1500", + "operationResultUuid": "791f6ec7-ecec-43d5-82ca-a1497be0188c", + "operationResultConsumedGas": "10000", + "counter": "2409130", + "operationResultErrors": null, + "source": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + "insertedTimestamp": "2020-01-22 22:15:12.038586 UTC", + "metadataUuid": "85b42f50-1a89-421c-bcb0-a06926941bc4" + } }` var validator1 = blockatlas.StakeValidator{ @@ -174,20 +275,22 @@ var validatorMap = blockatlas.ValidatorMap{ "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93": validator1, } +var delegationsBalance = "68995611927" + +var delegation = blockatlas.DelegationsPage{ + { + Delegator: validator1, + Value: delegationsBalance, + Status: blockatlas.DelegationStatusActive, + }, +} + func TestNormalizeDelegations(t *testing.T) { - var account Account - err := json.Unmarshal([]byte(accountSrc), &account) + var txDelegation TxDelegation + err := json.Unmarshal([]byte(delegationsSrc), &txDelegation) assert.NoError(t, err) - assert.NotNil(t, account) - - expected := blockatlas.DelegationsPage{ - { - Delegator: validator1, - Value: "68995611927", - Status: blockatlas.DelegationStatusActive, - }, - } - result, err := NormalizeDelegation(account, validatorMap) + assert.NotNil(t, txDelegation) + result, err := NormalizeDelegation(txDelegation, delegationsBalance, validatorMap) assert.NoError(t, err) - assert.Equal(t, result, expected) + assert.Equal(t, delegation, result) } diff --git a/platform/tezos/client.go b/platform/tezos/client.go index c9b0add49..025445cf6 100644 --- a/platform/tezos/client.go +++ b/platform/tezos/client.go @@ -1,8 +1,8 @@ package tezos import ( - "fmt" "net/url" + "strconv" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -11,28 +11,22 @@ type Client struct { blockatlas.Request } -func (c *Client) GetTxsOfAddress(address string) ([]Tx, error) { - var account Op - path := fmt.Sprintf("account/%s/op", address) - err := c.Get(&account, path, url.Values{"limit": {"1000"}, "offset": {"0"}}) - return account.Txs, err +func (c *Client) GetTxsOfAddress(address string) (txs []Transaction, err error) { + err = c.Get(&txs, "v1/transactions", url.Values{"n": {"50"}, "p": {"0"}, "account": {address}}) + return } -func (c *Client) GetCurrentBlock() (int64, error) { - var head Head - err := c.Get(&head, "block/head", url.Values{"limit": {"1000"}, "offset": {"0"}}) - return head.Height, err +func (c *Client) GetCurrentBlock() (height int64, err error) { + err = c.Get(&height, "v1/blocks_num", nil) + return } -func (c *Client) GetBlockByNumber(num int64) ([]Tx, error) { - var block Op - path := fmt.Sprintf("block/%d/op", num) - err := c.Get(&block, path, url.Values{"limit": {"1000"}, "offset": {"0"}}) - return block.Txs, err +func (c *Client) GetBlockByNumber(num int64) (txs []Transaction, err error) { + err = c.Get(&txs, "v1/transactions", url.Values{"n": {"50"}, "p": {"0"}, "block": {strconv.Itoa(int(num))}}) + return } -func (c *Client) GetAccount(address string) (result Account, err error) { - path := fmt.Sprintf("account/%s", address) - - return result, c.Get(&result, path, nil) +func (c *Client) GetDelegations(address string) (result []TxDelegation, err error) { + err = c.Get(&result, "v1/delegations", url.Values{"n": {"1"}, "p": {"0"}, "account": {address}}) + return } diff --git a/platform/tezos/model.go b/platform/tezos/model.go index de4153386..621f66680 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -1,35 +1,50 @@ package tezos +import "time" + type Op struct { - Txs []Tx `json:"ops"` + OpHash string `json:"opHash"` + BlockLevel uint64 `json:"blockLevel"` + BlockTimestamp time.Time `json:"blockTimestamp"` +} + +type Transaction struct { + Tx Tx `json:"tx"` + Op Op `json:"op"` } -// Tx is a Tezos blockchain transaction type Tx struct { - Hash string `json:"hash"` - BlockHash string `json:"block"` - Status string `json:"status"` - Success bool `json:"is_success"` - Time string `json:"time"` - Height uint64 `json:"height"` - Type string `json:"type"` - Sender string `json:"sender"` - Volume float64 `json:"volume"` - Receiver string `json:"receiver"` - Fee int `json:"gas_used"` + Destination string `json:"destination"` + Amount string `json:"amount"` + GasLimit string `json:"gasLimit"` + Kind string `json:"kind"` + BlockHash string `json:"blockHash"` + Fee string `json:"fee"` + Source string `json:"source"` + Status string `json:"operationResultStatus"` } -type Validator struct { - Address string `json:"pkh"` +type TxDelegation struct { + Delegation Delegation `json:"delegation"` + Op Op `json:"op"` } -type Head struct { - Height int64 `json:"height"` +type Delegation struct { + Delegate string `json:"delegate"` + GasLimit string `json:"gasLimit"` + Kind string `json:"kind"` + Status string `json:"operationResultStatus"` + Fee string `json:"fee"` + Source string `json:"source"` } -type Account struct { - Address string `json:"address"` - Delegate string `json:"delegate"` - Balance float64 `json:"total_balance"` - IsDelegated bool `json:"is_delegated"` +type Balance struct { + Balance string `json:"balance"` + FrozenBalance string `json:"frozen_balance"` + StakingBalance string `json:"staking_balance"` + DelegatedBalance string `json:"delegated_balance"` +} + +type Validator struct { + Address string `json:"pkh"` } diff --git a/platform/tezos/rpc.go b/platform/tezos/rpc.go index 338f4ab65..e368265b7 100644 --- a/platform/tezos/rpc.go +++ b/platform/tezos/rpc.go @@ -1,8 +1,8 @@ package tezos import ( + "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" ) type RpcClient struct { @@ -11,9 +11,25 @@ type RpcClient struct { func (c *RpcClient) GetValidators() (validators []Validator, err error) { err = c.Get(&validators, "chains/main/blocks/head~32768/votes/listings", nil) + return +} + +func (c *RpcClient) GetBalance(address string) string { + var balance string + path := fmt.Sprintf("chains/main/blocks/head/context/delegates/%s/balance", address) + err := c.Get(&balance, path, nil) + if err != nil { + return "0" + } + return balance +} + +func (c *RpcClient) GetDelegatedBalance(address string) string { + path := fmt.Sprintf("chains/main/blocks/head/context/delegates/%s/delegated_balance", address) + var delegatedBalance string + err := c.Get(&delegatedBalance, path, nil) if err != nil { - logger.Error(err, "Tezos: Failed to get validators for address") - return validators, err + return "0" } - return validators, err + return delegatedBalance } From 10a95726ab5744ba373e9c7a0747869c2aa3f6de Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 24 Jan 2020 16:15:53 -0300 Subject: [PATCH 003/506] fix token support for coin info (#744) --- api/maketdata.go | 2 +- pkg/blockatlas/marketdata.go | 26 +++++++++++++------------- services/assets/client.go | 12 ++++++++++-- services/assets/client_test.go | 32 ++++++++++++++++++++++++++++---- 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/api/maketdata.go b/api/maketdata.go index df574c60a..ac2af13de 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -200,7 +200,7 @@ func getCoinInfoHandler() func(c *gin.Context) { ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) return } - chart.Info, err = assets.GetCoinInfo(coinId) + chart.Info, err = assets.GetCoinInfo(coinId, token) if err != nil { logger.Error(err, "invalid coin info", logger.Params{"coin": coinId, "currency": currency}) } diff --git a/pkg/blockatlas/marketdata.go b/pkg/blockatlas/marketdata.go index a39ca30e6..bcf411b40 100644 --- a/pkg/blockatlas/marketdata.go +++ b/pkg/blockatlas/marketdata.go @@ -40,22 +40,22 @@ type ChartPrice struct { } type ChartCoinInfo struct { - Vol24 float64 `json:"volume_24"` - MarketCap float64 `json:"market_cap"` - CirculatingSupply float64 `json:"circulating_supply"` - TotalSupply float64 `json:"total_supply"` - Info CoinInfo `json:"info,omitempty"` + Vol24 float64 `json:"volume_24"` + MarketCap float64 `json:"market_cap"` + CirculatingSupply float64 `json:"circulating_supply"` + TotalSupply float64 `json:"total_supply"` + Info *CoinInfo `json:"info,omitempty"` } type CoinInfo struct { - Name string `json:"name"` - Website string `json:"website"` - SourceCode string `json:"source_code"` - Whitepaper string `json:"whitepaper"` - Explorers []Link `json:"explorers"` - Socials []Link `json:"socials"` - Details []Detail `json:"details"` - DataSource string `json:"data_source"` + Name string `json:"name,omitempty"` + Website string `json:"website,omitempty"` + SourceCode string `json:"source_code,omitempty"` + Whitepaper string `json:"whitepaper,omitempty"` + Explorers []Link `json:"explorers,omitempty"` + Socials []Link `json:"socials,omitempty"` + Details []Detail `json:"details,omitempty"` + DataSource string `json:"data_source,omitempty"` } type Link struct { diff --git a/services/assets/client.go b/services/assets/client.go index 70cba99a2..6a5092753 100644 --- a/services/assets/client.go +++ b/services/assets/client.go @@ -12,12 +12,13 @@ const ( AssetsURL = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/" ) -func GetCoinInfo(coinId int) (info blockatlas.CoinInfo, err error) { +func GetCoinInfo(coinId int, token string) (info *blockatlas.CoinInfo, err error) { c, ok := coin.Coins[uint(coinId)] if !ok { return info, errors.E("coin not found") } - request := blockatlas.InitClient(AssetsURL + c.Handle) + url := getCoinInfoUrl(c, token) + request := blockatlas.InitClient(url) err = request.GetWithCache(&info, "info/info.json", nil, time.Hour*1) return } @@ -96,3 +97,10 @@ func calculateAnnual(annual float64, commission float64) float64 { func getImage(c coin.Coin, ID string) string { return AssetsURL + c.Handle + "/validators/assets/" + ID + "/logo.png" } + +func getCoinInfoUrl(c coin.Coin, token string) string { + if len(token) == 0 { + return AssetsURL + c.Handle + } + return AssetsURL + c.Handle + "/assets/" + token +} diff --git a/services/assets/client_test.go b/services/assets/client_test.go index cd31052da..1d5fcdf82 100644 --- a/services/assets/client_test.go +++ b/services/assets/client_test.go @@ -7,7 +7,7 @@ import ( "testing" ) -var c = coin.Coin{Handle: "cosmos"} +var cosmosCoin = coin.Coin{Handle: "cosmos"} var validators = []blockatlas.Validator{ { ID: "test", @@ -38,7 +38,7 @@ var expectedStakeValidator = blockatlas.StakeValidator{ } func TestGetImage(t *testing.T) { - image := getImage(c, "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp") + image := getImage(cosmosCoin, "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp") expected := "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp/logo.png" @@ -47,14 +47,14 @@ func TestGetImage(t *testing.T) { func TestNormalizeValidator(t *testing.T) { - result := normalizeValidator(validators[0], assets[0], c) + result := normalizeValidator(validators[0], assets[0], cosmosCoin) assert.Equal(t, expectedStakeValidator, result) } func TestNormalizeValidators(t *testing.T) { - result := normalizeValidators(validators, assets, c) + result := normalizeValidators(validators, assets, cosmosCoin) expected := []blockatlas.StakeValidator{expectedStakeValidator} @@ -113,3 +113,27 @@ func TestCalcAnnual(t *testing.T) { }) } } + +func Test_getCoinInfoUrl(t *testing.T) { + type args struct { + c coin.Coin + token string + } + tests := []struct { + name string + args args + want string + }{ + {"test Ethereum coin", args{coin.Ethereum(), ""}, AssetsURL + coin.Ethereum().Handle}, + {"test Ethereum token", args{coin.Ethereum(), "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, AssetsURL + coin.Ethereum().Handle + "/assets/" + "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, + {"test Binance coin", args{coin.Binance(), ""}, AssetsURL + coin.Binance().Handle}, + {"test Binance token", args{coin.Binance(), "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, AssetsURL + coin.Binance().Handle + "/assets/" + "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getCoinInfoUrl(tt.args.c, tt.args.token); got != tt.want { + t.Errorf("getCoinInfoUrl() = %v, want %v", got, tt.want) + } + }) + } +} From 441bf439ee8cd0b1df355f0944ff75b13eceade5 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 00:15:14 -0300 Subject: [PATCH 004/506] fix charts unit test (#748) --- marketdata/chart/coinmarketcap/cmc_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/marketdata/chart/coinmarketcap/cmc_test.go b/marketdata/chart/coinmarketcap/cmc_test.go index dd832e976..e44c1815a 100644 --- a/marketdata/chart/coinmarketcap/cmc_test.go +++ b/marketdata/chart/coinmarketcap/cmc_test.go @@ -147,7 +147,9 @@ func Test_normalizeCharts(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotInfo := normalizeCharts(tt.args.currency, tt.args.charts) - assert.True(t, reflect.DeepEqual(tt.wantInfo, gotInfo)) + if !assert.ObjectsAreEqualValues(tt.wantInfo, gotInfo) { + t.Errorf("normalizeCharts() = %v, want %v", gotInfo, tt.wantInfo) + } }) } } From a90f37e085b8e10148d2125d2d315cb89f3ae609 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 01:07:16 -0300 Subject: [PATCH 005/506] tezos delegated balance hotfix --- platform/tezos/api.go | 5 ++++- platform/tezos/rpc.go | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/tezos/api.go b/platform/tezos/api.go index 928c9746a..870a475a3 100644 --- a/platform/tezos/api.go +++ b/platform/tezos/api.go @@ -52,6 +52,10 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { } func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + delegatedBalance, err := p.rpcClient.GetDelegatedBalance(address) + if err != nil { + return make(blockatlas.DelegationsPage, 0), nil + } delegations, err := p.client.GetDelegations(address) if err != nil { return nil, err @@ -63,7 +67,6 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e if err != nil { return nil, err } - delegatedBalance := p.rpcClient.GetDelegatedBalance(address) return NormalizeDelegation(delegations[0], delegatedBalance, validators) } diff --git a/platform/tezos/rpc.go b/platform/tezos/rpc.go index e368265b7..a7bd13c0e 100644 --- a/platform/tezos/rpc.go +++ b/platform/tezos/rpc.go @@ -24,12 +24,12 @@ func (c *RpcClient) GetBalance(address string) string { return balance } -func (c *RpcClient) GetDelegatedBalance(address string) string { +func (c *RpcClient) GetDelegatedBalance(address string) (string, error) { path := fmt.Sprintf("chains/main/blocks/head/context/delegates/%s/delegated_balance", address) var delegatedBalance string err := c.Get(&delegatedBalance, path, nil) if err != nil { - return "0" + return "", err } - return delegatedBalance + return delegatedBalance, nil } From 3d30590cefde50153276a5e8cb76975fd76dfbca Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 01:43:09 -0300 Subject: [PATCH 006/506] rollback to old stake implementation --- config.yml | 1 + platform/tezos/api.go | 81 +--------------------- platform/tezos/api_test.go | 94 ------------------------- platform/tezos/client.go | 5 +- platform/tezos/model.go | 8 +++ platform/tezos/stake.go | 95 +++++++++++++++++++++++++ platform/tezos/stake_test.go | 130 +++++++++++++++++++++++++++++++++++ 7 files changed, 239 insertions(+), 175 deletions(-) create mode 100644 platform/tezos/stake.go create mode 100644 platform/tezos/stake_test.go diff --git a/config.yml b/config.yml index 0c9da32e3..ce3d0607d 100644 --- a/config.yml +++ b/config.yml @@ -79,6 +79,7 @@ kin: # [XTZ] Tezos: https://tezos.com tezos: + stake_api: https://api.tzstats.com/explorer api: https://api.tezos.id/mooncake/mainnet rpc: https://mainnet.tezos.org.ua diff --git a/platform/tezos/api.go b/platform/tezos/api.go index 870a475a3..137f0b2f3 100644 --- a/platform/tezos/api.go +++ b/platform/tezos/api.go @@ -4,12 +4,11 @@ import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - services "github.com/trustwallet/blockatlas/services/assets" ) type Platform struct { client Client + stakeClient Client rpcClient RpcClient } @@ -17,7 +16,8 @@ const Annual = 6.09 func (p *Platform) Init() error { p.client = Client{blockatlas.InitClient(viper.GetString("tezos.api"))} - p.client.SetTimeout(25) + p.client = Client{blockatlas.InitClient(viper.GetString("tezos.stake_api"))} + p.client.SetTimeout(30) p.rpcClient = RpcClient{blockatlas.InitClient(viper.GetString("tezos.rpc"))} return nil } @@ -51,40 +51,6 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { }, nil } -func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { - delegatedBalance, err := p.rpcClient.GetDelegatedBalance(address) - if err != nil { - return make(blockatlas.DelegationsPage, 0), nil - } - delegations, err := p.client.GetDelegations(address) - if err != nil { - return nil, err - } - if len(delegations) == 0 { - return make(blockatlas.DelegationsPage, 0), nil - } - validators, err := services.GetValidatorsMap(p) - if err != nil { - return nil, err - } - return NormalizeDelegation(delegations[0], delegatedBalance, validators) -} - -func NormalizeDelegation(delegation TxDelegation, delegatedBalance string, validators blockatlas.ValidatorMap) (blockatlas.DelegationsPage, error) { - validator, ok := validators[delegation.Delegation.Delegate] - if !ok { - return nil, errors.E("Validator not found", - errors.Params{"Address": delegation.Delegation.Source, "Delegate": delegation.Delegation.Delegate}) - } - return blockatlas.DelegationsPage{ - { - Delegator: validator, - Value: delegatedBalance, - Status: blockatlas.DelegationStatusActive, - }, - }, nil -} - func NormalizeTxs(srcTxs []Transaction) (txs []blockatlas.Tx) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(srcTx) @@ -96,47 +62,6 @@ func NormalizeTxs(srcTxs []Transaction) (txs []blockatlas.Tx) { return txs } -func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { - results := make(blockatlas.ValidatorPage, 0) - validators, err := p.rpcClient.GetValidators() - if err != nil { - return results, err - } - - for _, v := range validators { - results = append(results, normalizeValidator(v)) - } - - return results, nil -} - -func (p *Platform) GetDetails() blockatlas.StakingDetails { - return getDetails() -} - -func (p *Platform) UndelegatedBalance(address string) (string, error) { - return p.rpcClient.GetBalance(address), nil -} - -func getDetails() blockatlas.StakingDetails { - return blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: Annual}, - MinimumAmount: "0", - LockTime: 0, - Type: blockatlas.DelegationTypeDelegate, - } -} - -func normalizeValidator(v Validator) (validator blockatlas.Validator) { - // How to calculate Tezos APR? I have no idea. Tezos team does not know either. let's assume it's around 7% - no way to calculate in decentralized manner - // Delegation rewards distributed by the validators manually, it's up to them to do it. - return blockatlas.Validator{ - Status: true, - ID: v.Address, - Details: getDetails(), - } -} - // NormalizeTx converts a Tezos transaction into the generic model func NormalizeTx(srcTx Transaction) (tx blockatlas.Tx, ok bool) { if srcTx.Tx.Kind != "transaction" { diff --git a/platform/tezos/api_test.go b/platform/tezos/api_test.go index 716ce40da..71dea7e3b 100644 --- a/platform/tezos/api_test.go +++ b/platform/tezos/api_test.go @@ -200,97 +200,3 @@ func TestNormalizeTx(t *testing.T) { }) } } - -const validatorSrc = ` -[ - {"pkh":"tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m","rolls":3726} -] -` - -var validator = blockatlas.Validator{ - Status: true, - ID: "tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m", - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: Annual}, - MinimumAmount: blockatlas.Amount("0"), - Type: blockatlas.DelegationTypeDelegate, - }, -} - -func TestNormalizeValidator(t *testing.T) { - var v []Validator - err := json.Unmarshal([]byte(validatorSrc), &v) - assert.Nil(t, err) - result := normalizeValidator(v[0]) - assert.Equal(t, validator, result) -} - -const delegationsSrc = ` -{ - "op": { - "signature": "sigvHd2YBByFXU8nL4CZKSTYXNdMapMsJw1f239YRRjgz9NvrTyA6iGnpBDhi9kCB4zMHysrg9H4jxcpPH975WiQtEmkMjb5", - "blockUuid": "4b292c55-41ba-4383-a1d6-03fb71b88f41", - "opHash": "opGphHGNEZZN5rF78yxwe9BJydxYA2yqxECnZR6s6HcxXtCg8Sj", - "uuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", - "chainId": "NetXdQprcVkpaWU", - "blockHash": "BLkscXpE63gajVzmgBS7fQx63hERKQRCZFGtMXdYY6WPThHyji7", - "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", - "branch": "BKqtLegZfdPR3USyYYcMpedB59W5eUBuFZAVpVMPpFgEvMcZjr1", - "blockLevel": 791778, - "blockTimestamp": "2020-01-22T22:13:38Z", - "insertedTimestamp": "2020-01-22 22:14:05.937406 UTC" - }, - "delegation": { - "storageLimit": "257", - "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - "opUuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", - "uuid": "6459fcd9-5eee-4999-ac4d-92330b9eaab3", - "gasLimit": "10600", - "kind": "delegation", - "operationResultStatus": "applied", - "fee": "1500", - "operationResultUuid": "791f6ec7-ecec-43d5-82ca-a1497be0188c", - "operationResultConsumedGas": "10000", - "counter": "2409130", - "operationResultErrors": null, - "source": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - "insertedTimestamp": "2020-01-22 22:15:12.038586 UTC", - "metadataUuid": "85b42f50-1a89-421c-bcb0-a06926941bc4" - } -}` - -var validator1 = blockatlas.StakeValidator{ - ID: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - Status: true, - Info: blockatlas.StakeValidatorInfo{ - Name: "stake.fish", - Description: "Leading validator for Proof of Stake blockchains. Stake your cryptocurrencies with us. We know validating.", - Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/tezos/validators/assets/tz2fcnbrerxtattnx6iimr1uj5jsdxvdhm93/logo.png", - Website: "https://stake.fish/", - }, - Details: getDetails(), -} - -var validatorMap = blockatlas.ValidatorMap{ - "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93": validator1, -} - -var delegationsBalance = "68995611927" - -var delegation = blockatlas.DelegationsPage{ - { - Delegator: validator1, - Value: delegationsBalance, - Status: blockatlas.DelegationStatusActive, - }, -} - -func TestNormalizeDelegations(t *testing.T) { - var txDelegation TxDelegation - err := json.Unmarshal([]byte(delegationsSrc), &txDelegation) - assert.NoError(t, err) - assert.NotNil(t, txDelegation) - result, err := NormalizeDelegation(txDelegation, delegationsBalance, validatorMap) - assert.NoError(t, err) - assert.Equal(t, delegation, result) -} diff --git a/platform/tezos/client.go b/platform/tezos/client.go index 025445cf6..b2b60fe0d 100644 --- a/platform/tezos/client.go +++ b/platform/tezos/client.go @@ -26,7 +26,6 @@ func (c *Client) GetBlockByNumber(num int64) (txs []Transaction, err error) { return } -func (c *Client) GetDelegations(address string) (result []TxDelegation, err error) { - err = c.Get(&result, "v1/delegations", url.Values{"n": {"1"}, "p": {"0"}, "account": {address}}) - return +func (c *Client) GetAccount(address string) (result Account, err error) { + return result, c.Get(&result, "account/"+address, nil) } diff --git a/platform/tezos/model.go b/platform/tezos/model.go index 621f66680..05024d3f9 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -48,3 +48,11 @@ type Balance struct { type Validator struct { Address string `json:"pkh"` } + +type Account struct { + Address string `json:"address"` + Delegate string `json:"delegate"` + Balance float64 `json:"total_balance"` + IsDelegated bool `json:"is_delegated"` +} + diff --git a/platform/tezos/stake.go b/platform/tezos/stake.go new file mode 100644 index 000000000..29e1b4063 --- /dev/null +++ b/platform/tezos/stake.go @@ -0,0 +1,95 @@ +package tezos + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + services "github.com/trustwallet/blockatlas/services/assets" + "math" + "strconv" +) + +func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + account, err := p.client.GetAccount(address) + if err != nil { + return nil, err + } + if !account.IsDelegated { + return make(blockatlas.DelegationsPage, 0), nil + } + validators, err := services.GetValidatorsMap(p) + if err != nil { + return nil, err + } + return NormalizeDelegation(account, validators) +} + +func NormalizeDelegation(account Account, validators blockatlas.ValidatorMap) (blockatlas.DelegationsPage, error) { + validator, ok := validators[account.Delegate] + if !ok { + return nil, errors.E("Validator not found", + errors.Params{"Address": account.Address, "Delegate": account.Delegate, "Balance": account.Balance}) + } + balance := removeDecimals(account.Balance) + return blockatlas.DelegationsPage{ + { + Delegator: validator, + Value: balance, + Status: blockatlas.DelegationStatusActive, + }, + }, nil +} + +func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { + results := make(blockatlas.ValidatorPage, 0) + validators, err := p.rpcClient.GetValidators() + + if err != nil { + return results, err + } + + for _, v := range validators { + results = append(results, normalizeValidator(v)) + } + + return results, nil +} + +func (p *Platform) GetDetails() blockatlas.StakingDetails { + return getDetails() +} + +func (p *Platform) UndelegatedBalance(address string) (string, error) { + account, err := p.client.GetAccount(address) + if err != nil { + return "0", err + } + return removeDecimals(account.Balance), nil +} + +func getDetails() blockatlas.StakingDetails { + return blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: Annual}, + MinimumAmount: "0", + LockTime: 0, + Type: blockatlas.DelegationTypeDelegate, + } +} + +func normalizeValidator(v Validator) (validator blockatlas.Validator) { + // How to calculate Tezos APR? I have no idea. Tezos team does not know either. let's assume it's around 7% - no way to calculate in decentralized manner + // Delegation rewards distributed by the validators manually, it's up to them to do it. + + return blockatlas.Validator{ + Status: true, + ID: v.Address, + Details: getDetails(), + } +} + +func removeDecimals(volume float64) string { + decimals := coin.Coins[coin.XTZ].Decimals + d := math.Pow10(int(decimals)) + v := volume * d + return strconv.Itoa(int(v)) +} diff --git a/platform/tezos/stake_test.go b/platform/tezos/stake_test.go new file mode 100644 index 000000000..475471165 --- /dev/null +++ b/platform/tezos/stake_test.go @@ -0,0 +1,130 @@ +package tezos + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" +) + +const delegationsSrc = ` +{ + "op": { + "signature": "sigvHd2YBByFXU8nL4CZKSTYXNdMapMsJw1f239YRRjgz9NvrTyA6iGnpBDhi9kCB4zMHysrg9H4jxcpPH975WiQtEmkMjb5", + "blockUuid": "4b292c55-41ba-4383-a1d6-03fb71b88f41", + "opHash": "opGphHGNEZZN5rF78yxwe9BJydxYA2yqxECnZR6s6HcxXtCg8Sj", + "uuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", + "chainId": "NetXdQprcVkpaWU", + "blockHash": "BLkscXpE63gajVzmgBS7fQx63hERKQRCZFGtMXdYY6WPThHyji7", + "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", + "branch": "BKqtLegZfdPR3USyYYcMpedB59W5eUBuFZAVpVMPpFgEvMcZjr1", + "blockLevel": 791778, + "blockTimestamp": "2020-01-22T22:13:38Z", + "insertedTimestamp": "2020-01-22 22:14:05.937406 UTC" + }, + "delegation": { + "storageLimit": "257", + "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "opUuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", + "uuid": "6459fcd9-5eee-4999-ac4d-92330b9eaab3", + "gasLimit": "10600", + "kind": "delegation", + "operationResultStatus": "applied", + "fee": "1500", + "operationResultUuid": "791f6ec7-ecec-43d5-82ca-a1497be0188c", + "operationResultConsumedGas": "10000", + "counter": "2409130", + "operationResultErrors": null, + "source": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + "insertedTimestamp": "2020-01-22 22:15:12.038586 UTC", + "metadataUuid": "85b42f50-1a89-421c-bcb0-a06926941bc4" + } +}` + +const accountSrc = ` +{ + "address": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "total_balance": 68995.611927, + "is_delegated": true +}` + +const validatorSrc = ` +[ + {"pkh":"tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m","rolls":3726} +] +` + +var validator = blockatlas.Validator{ + Status: true, + ID: "tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m", + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: Annual}, + MinimumAmount: blockatlas.Amount("0"), + Type: blockatlas.DelegationTypeDelegate, + }, +} + +var stakeValidator = blockatlas.StakeValidator{ + ID: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "stake.fish", + Description: "Leading validator for Proof of Stake blockchains. Stake your cryptocurrencies with us. We know validating.", + Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/tezos/validators/assets/tz2fcnbrerxtattnx6iimr1uj5jsdxvdhm93/logo.png", + Website: "https://stake.fish/", + }, + Details: getDetails(), +} + +var validatorMap = blockatlas.ValidatorMap{ + "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93": stakeValidator, +} + +var delegationsBalance = "68995611927" + +var delegation = blockatlas.DelegationsPage{ + { + Delegator: stakeValidator, + Value: delegationsBalance, + Status: blockatlas.DelegationStatusActive, + }, +} + +func TestNormalizeValidator(t *testing.T) { + var v []Validator + err := json.Unmarshal([]byte(validatorSrc), &v) + assert.Nil(t, err) + result := normalizeValidator(v[0]) + assert.Equal(t, validator, result) +} + +func TestNormalizeDelegations(t *testing.T) { + var account Account + err := json.Unmarshal([]byte(accountSrc), &account) + assert.NoError(t, err) + assert.NotNil(t, account) + result, err := NormalizeDelegation(account, validatorMap) + assert.NoError(t, err) + assert.Equal(t, delegation, result) +} + +func Test_removeDecimals(t *testing.T) { + tests := []struct { + name string + volume float64 + want string + }{ + {"one float precision", 9.5, "9500000"}, + {"zero float precision", 9, "9000000"}, + {"five float precision", 9.00005, "9000050"}, + {"six float precision", 9.000005, "9000005"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := removeDecimals(tt.volume); got != tt.want { + t.Errorf("removeDecimals() = %v, want %v", got, tt.want) + } + }) + } +} From 14a15692098455af62be673490d1e07a8b2d5d29 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 01:45:12 -0300 Subject: [PATCH 007/506] fix clients calls --- platform/tezos/api.go | 2 +- platform/tezos/stake.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/tezos/api.go b/platform/tezos/api.go index 137f0b2f3..14711f4d8 100644 --- a/platform/tezos/api.go +++ b/platform/tezos/api.go @@ -16,8 +16,8 @@ const Annual = 6.09 func (p *Platform) Init() error { p.client = Client{blockatlas.InitClient(viper.GetString("tezos.api"))} - p.client = Client{blockatlas.InitClient(viper.GetString("tezos.stake_api"))} p.client.SetTimeout(30) + p.stakeClient = Client{blockatlas.InitClient(viper.GetString("tezos.stake_api"))} p.rpcClient = RpcClient{blockatlas.InitClient(viper.GetString("tezos.rpc"))} return nil } diff --git a/platform/tezos/stake.go b/platform/tezos/stake.go index 29e1b4063..ce4946c61 100644 --- a/platform/tezos/stake.go +++ b/platform/tezos/stake.go @@ -10,7 +10,7 @@ import ( ) func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { - account, err := p.client.GetAccount(address) + account, err := p.stakeClient.GetAccount(address) if err != nil { return nil, err } @@ -60,7 +60,7 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { } func (p *Platform) UndelegatedBalance(address string) (string, error) { - account, err := p.client.GetAccount(address) + account, err := p.stakeClient.GetAccount(address) if err != nil { return "0", err } From 82a07aceb9b6a4ba4375605a6de7a3b68f674a64 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 01:54:55 -0300 Subject: [PATCH 008/506] run make fmt and remove unused code --- platform/tezos/api.go | 6 +++--- platform/tezos/model.go | 1 - platform/tezos/rpc.go | 21 --------------------- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/platform/tezos/api.go b/platform/tezos/api.go index 14711f4d8..a0842190f 100644 --- a/platform/tezos/api.go +++ b/platform/tezos/api.go @@ -7,9 +7,9 @@ import ( ) type Platform struct { - client Client - stakeClient Client - rpcClient RpcClient + client Client + stakeClient Client + rpcClient RpcClient } const Annual = 6.09 diff --git a/platform/tezos/model.go b/platform/tezos/model.go index 05024d3f9..42ced47a5 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -55,4 +55,3 @@ type Account struct { Balance float64 `json:"total_balance"` IsDelegated bool `json:"is_delegated"` } - diff --git a/platform/tezos/rpc.go b/platform/tezos/rpc.go index a7bd13c0e..35a1163ea 100644 --- a/platform/tezos/rpc.go +++ b/platform/tezos/rpc.go @@ -1,7 +1,6 @@ package tezos import ( - "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -13,23 +12,3 @@ func (c *RpcClient) GetValidators() (validators []Validator, err error) { err = c.Get(&validators, "chains/main/blocks/head~32768/votes/listings", nil) return } - -func (c *RpcClient) GetBalance(address string) string { - var balance string - path := fmt.Sprintf("chains/main/blocks/head/context/delegates/%s/balance", address) - err := c.Get(&balance, path, nil) - if err != nil { - return "0" - } - return balance -} - -func (c *RpcClient) GetDelegatedBalance(address string) (string, error) { - path := fmt.Sprintf("chains/main/blocks/head/context/delegates/%s/delegated_balance", address) - var delegatedBalance string - err := c.Get(&delegatedBalance, path, nil) - if err != nil { - return "", err - } - return delegatedBalance, nil -} From defeeb939e8750b5ffe5437c9add0da712cd83e2 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 02:52:59 -0300 Subject: [PATCH 009/506] fix integration tests pipeline (#749) --- azure-pipelines.yml | 107 ++++++++++++-------- pkg/integration/testdata/coin_fixtures.json | 2 +- 2 files changed, 64 insertions(+), 45 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8744d1279..5b98841b7 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,52 +1,71 @@ +trigger: + - master + +pr: + - master + +schedules: + - cron: "0 * * * *" + displayName: Recurrent build + always: true + branches: + include: + - master + pool: vmImage: 'Ubuntu 16.04' variables: GOBIN: '$(GOPATH)/bin' # Go binaries path GOROOT: '/usr/local/go1.13' # Go installation path - GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path + GOPATH: '$(Build.SourcesDirectory)/gopath' # Go workspace path modulePath: '$(GOPATH)/src/github.com/trustwallet/blockatlas' # Path to the module's code -steps: - - script: | - mkdir -p '$(GOBIN)' - mkdir -p '$(GOPATH)/pkg' - mkdir -p '$(modulePath)' - shopt -s extglob - shopt -s dotglob - mv !(gopath) '$(modulePath)' - echo '##vso[task.prependpath]$(GOBIN)' - echo '##vso[task.prependpath]$(GOROOT)/bin' - echo '$(go env)' - displayName: 'Set up the Go workspace' - - - task: CacheBeta@1 - inputs: - key: 'go | "$(Agent.OS)" | **/go.mod' - restoreKeys: | - go | "$(Agent.OS)" - go - path: | - $(GOPATH) - !$(modulePath) - displayName: 'Cache go packages' - - - script: | - go version - go get -v -t -d ./... - workingDirectory: '$(modulePath)' - displayName: 'Get dependencies' - - - script: make test - workingDirectory: '$(modulePath)' - displayName: 'Run unit tests' - - - script: | - go get github.com/gavv/httpexpect - make integration - workingDirectory: '$(modulePath)' - displayName: 'Run integration tests' - - - script: go build -v . - workingDirectory: '$(modulePath)' - displayName: 'Build' +jobs: + - job: Pipeline + steps: + - script: | + mkdir -p '$(GOBIN)' + mkdir -p '$(GOPATH)/pkg' + mkdir -p '$(modulePath)' + shopt -s extglob + shopt -s dotglob + mv !(gopath) '$(modulePath)' + echo '##vso[task.prependpath]$(GOBIN)' + echo '##vso[task.prependpath]$(GOROOT)/bin' + echo '$(go env)' + displayName: 'Set up the Go workspace' + + - task: CacheBeta@1 + inputs: + key: 'go | "$(Agent.OS)" | **/go.mod' + restoreKeys: | + go | "$(Agent.OS)" + go + path: | + $(GOPATH) + !$(modulePath) + displayName: 'Cache go packages' + + - script: | + go version + go get -v -t -d ./... + workingDirectory: '$(modulePath)' + displayName: 'Get dependencies' + + - script: make test + workingDirectory: '$(modulePath)' + displayName: 'Run unit tests' + + - script: | + go get github.com/gavv/httpexpect + make integration + workingDirectory: '$(modulePath)' + displayName: 'Run integration tests' + # Use this condition when we start to use continuous CI + # condition: eq(variables['build.sourceBranch'], 'refs/heads/master') + continueOnError: true + + - script: go build -v . + workingDirectory: '$(modulePath)' + displayName: 'Build' diff --git a/pkg/integration/testdata/coin_fixtures.json b/pkg/integration/testdata/coin_fixtures.json index 7d6fe53b2..b4d7918da 100644 --- a/pkg/integration/testdata/coin_fixtures.json +++ b/pkg/integration/testdata/coin_fixtures.json @@ -108,7 +108,7 @@ "address": "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" }, "tezos": { - "address": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q" + "address": "KT1XRAGQEbUqqagjX9j7RbvpUe7ZwF29DnM2" }, "tron": { "address": "TQZskDJJRGAHifeKoQ7wLC4QDyB2iGvwp2" From ba06244299621a3fc6beec3b50218e9f397c1613 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 26 Jan 2020 08:53:26 +0300 Subject: [PATCH 010/506] change Save Rates interface, now it returns error (#743) --- marketdata/rates.go | 12 ++++++++---- storage/market.go | 19 ++++++++++++++++--- storage/storage.go | 2 +- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/marketdata/rates.go b/marketdata/rates.go index 6533adc30..45fcfcff4 100644 --- a/marketdata/rates.go +++ b/marketdata/rates.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/marketdata/rate" "github.com/trustwallet/blockatlas/marketdata/rate/coingecko" - cmc "github.com/trustwallet/blockatlas/marketdata/rate/coinmarketcap" + "github.com/trustwallet/blockatlas/marketdata/rate/coinmarketcap" "github.com/trustwallet/blockatlas/marketdata/rate/compound" "github.com/trustwallet/blockatlas/marketdata/rate/fixer" "github.com/trustwallet/blockatlas/pkg/errors" @@ -54,9 +54,13 @@ func runRate(storage storage.Market, p rate.Provider) error { if err != nil { return errors.E(err, "FetchLatestRates") } - if len(rates) > 0 { - storage.SaveRates(rates, rateProviders) - logger.Info("Market rates", logger.Params{"rates": len(rates), "provider": p.GetId()}) + if len(rates) == 0 { + return nil } + err = storage.SaveRates(rates, rateProviders) + if err != nil { + return errors.E(err, "runRate", errors.Params{"rates": rates}) + } + logger.Info("Market rates", logger.Params{"rates": len(rates), "provider": p.GetId()}) return nil } diff --git a/storage/market.go b/storage/market.go index 5f7c6d436..8a797a193 100644 --- a/storage/market.go +++ b/storage/market.go @@ -43,7 +43,12 @@ func (s *Storage) GetTicker(coin, token string) (*blockatlas.Ticker, error) { return cd, nil } -func (s *Storage) SaveRates(rates blockatlas.Rates, pl ProviderList) { +func (s *Storage) SaveRates(rates blockatlas.Rates, pl ProviderList) error { + var ( + errCounter int + errSaveSome = errors.E("Save some rates") + ) + for _, rate := range rates { r, err := s.GetRate(rate.Currency) if err == nil { @@ -57,12 +62,20 @@ func (s *Storage) SaveRates(rates blockatlas.Rates, pl ProviderList) { continue } } - err = s.AddHM(EntityRates, rate.Currency, &rate) - if err != nil { + if err = s.AddHM(EntityRates, rate.Currency, &rate); err != nil { + errCounter++ + errSaveSome.SetMeta(errors.Params{"rate": rate}) logger.Error(err, "SaveRates", logger.Params{"rate": rate}) continue } } + if errCounter == len(rates) { + return errors.E("Save all rates") + } + if errCounter > 0 { + return errSaveSome + } + return nil } func (s *Storage) GetRate(currency string) (rate *blockatlas.Rate, err error) { diff --git a/storage/storage.go b/storage/storage.go index dfd510851..d0e214e9b 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -30,6 +30,6 @@ type Addresses interface { type Market interface { SaveTicker(coin *blockatlas.Ticker, pl ProviderList) error GetTicker(coin, token string) (*blockatlas.Ticker, error) - SaveRates(rates blockatlas.Rates, pl ProviderList) + SaveRates(rates blockatlas.Rates, pl ProviderList) error GetRate(currency string) (*blockatlas.Rate, error) } From 61ecf9b8db9b0960c3af56e9b7bf8f109539cc7c Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 03:02:12 -0300 Subject: [PATCH 011/506] remove aeternity from the integration tests --- pkg/integration/testdata/exclude.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/integration/testdata/exclude.json b/pkg/integration/testdata/exclude.json index 3620e6450..82caab7b3 100644 --- a/pkg/integration/testdata/exclude.json +++ b/pkg/integration/testdata/exclude.json @@ -1,5 +1,7 @@ [ "/swagger/*any", + "/v1/aeternity/:address", + "/v2/aeternity/transactions/:address", "/v2/collectibles/categories", "/v3/collectibles/categories", "/v2/classic/collections/:owner", From 02c32f8ea0ae1f17ac241dabeaf54adc6973f0ed Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 03:17:38 -0300 Subject: [PATCH 012/506] add go releaser --- .goreleaser.yml | 28 ++++++++++++++++++++++++++++ azure-pipelines.yml | 18 ++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 .goreleaser.yml diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 000000000..9b946ca0f --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,28 @@ +# This is an example goreleaser.yaml file with some sane defaults. +# Make sure to check the documentation at http://goreleaser.com +before: + hooks: + # you may remove this if you don't use vgo + - go mod tidy + # you may remove this if you don't need go generate + - go generate ./... +builds: +- env: + - CGO_ENABLED=0 +archives: +- replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ .Tag }}-next" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5b98841b7..b5a6df0c3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,8 +1,15 @@ trigger: - - master + branches: + include: + - master + tags: + include: + - '*' pr: - - master + branches: + include: + - master schedules: - cron: "0 * * * *" @@ -69,3 +76,10 @@ jobs: - script: go build -v . workingDirectory: '$(modulePath)' displayName: 'Build' + + - script: | + curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh + goreleaser + workingDirectory: '$(modulePath)' + displayName: 'Go Releaser' + condition: startsWith(variables['build.sourceBranch'], 'refs/tags/') From b6f875a61fcf167406980c006dd1693b91dd910a Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 03:22:56 -0300 Subject: [PATCH 013/506] update .gitignore --- .gitignore | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 62cbbd67c..8ebaf946e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,87 @@ /blockatlas.exe /bin/* +### APP ### +*.csv +*.log +Build +dist/* +bin/* +test/* + # Dev environment -.DS_Store .idea/ .vscode/ cmd/__debug_bin config_*.yml *.orig *~ + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Go ### +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +# govendor cache +.cache From ad50688076efc70deaad2555c9152412a448bbb4 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 03:30:36 -0300 Subject: [PATCH 014/506] only distribute linux releases --- .goreleaser.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 9b946ca0f..c9cd75e6c 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -11,11 +11,7 @@ builds: - CGO_ENABLED=0 archives: - replacements: - darwin: Darwin linux: Linux - windows: Windows - 386: i386 - amd64: x86_64 checksum: name_template: 'checksums.txt' snapshot: From 3e020154022862e7d0dcca831765f31eade02dd7 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 03:34:06 -0300 Subject: [PATCH 015/506] ignore build --- .goreleaser.yml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index c9cd75e6c..43b611c2f 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -7,11 +7,18 @@ before: # you may remove this if you don't need go generate - go generate ./... builds: -- env: - - CGO_ENABLED=0 + - env: + - CGO_ENABLED=0 + - ignore: + - goos: darwin + goarch: 386 archives: -- replacements: - linux: Linux + - replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 checksum: name_template: 'checksums.txt' snapshot: @@ -20,5 +27,5 @@ changelog: sort: asc filters: exclude: - - '^docs:' - - '^test:' + - '^docs:' + - '^test:' From fddc827627d77b5317dec028a785f883b9d7d403 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 03:37:44 -0300 Subject: [PATCH 016/506] ignore build --- .goreleaser.yml | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 43b611c2f..f1541d6aa 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,24 +1,19 @@ -# This is an example goreleaser.yaml file with some sane defaults. -# Make sure to check the documentation at http://goreleaser.com before: hooks: - # you may remove this if you don't use vgo - - go mod tidy - # you may remove this if you don't need go generate - go generate ./... builds: - - env: - - CGO_ENABLED=0 - - ignore: - - goos: darwin - goarch: 386 +- env: + - CGO_ENABLED=0 +- ignore: + - goos: darwin + goarch: 386 archives: - - replacements: - darwin: Darwin - linux: Linux - windows: Windows - 386: i386 - amd64: x86_64 +- replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 checksum: name_template: 'checksums.txt' snapshot: @@ -27,5 +22,5 @@ changelog: sort: asc filters: exclude: - - '^docs:' - - '^test:' + - '^docs:' + - '^test:' From ddfe7c5dcab635c59f3e09ccd8458d501011af00 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 03:50:37 -0300 Subject: [PATCH 017/506] only distribute linux releases --- .goreleaser.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index f1541d6aa..72d6e08fe 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -2,18 +2,18 @@ before: hooks: - go generate ./... builds: -- env: - - CGO_ENABLED=0 -- ignore: - - goos: darwin - goarch: 386 + - main: "./main.go" + env: + - CGO_ENABLED=0 + ignore: + - goos: darwin archives: -- replacements: - darwin: Darwin - linux: Linux - windows: Windows - 386: i386 - amd64: x86_64 + - replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 checksum: name_template: 'checksums.txt' snapshot: @@ -22,5 +22,5 @@ changelog: sort: asc filters: exclude: - - '^docs:' - - '^test:' + - '^docs:' + - '^test:' From b2a165914dbacedc3c9f2ac65cb762e905fc0999 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 04:05:02 -0300 Subject: [PATCH 018/506] add goreleaser to makefile --- Makefile | 7 +++++++ azure-pipelines.yml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 01d78d8e6..7985df612 100644 --- a/Makefile +++ b/Makefile @@ -106,6 +106,9 @@ remove-coin-file: @echo " > Removing "$(PROJECT_NAME)"" @-rm $(GOBASE)/$(COIN_GO_FILE) +## goreleaser: Release the last tag version with GoReleaser. +goreleaser: go-goreleaser + go-compile: go-get go-build go-build: @@ -143,6 +146,10 @@ go-gen-coins: @echo " > Generating coin file" COIN_FILE=$(COIN_FILE) COIN_GO_FILE=$(COIN_GO_FILE) GOBIN=$(GOBIN) go run -tags=coins $(GEN_COIN_FILE) +go-goreleaser: + @echo " > Releasing a new version" + GOBIN=$(GOBIN) goreleaser --rm-dist + .PHONY: help all: help help: Makefile diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b5a6df0c3..668d9051f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -79,7 +79,7 @@ jobs: - script: | curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh - goreleaser + make goreleaser workingDirectory: '$(modulePath)' displayName: 'Go Releaser' condition: startsWith(variables['build.sourceBranch'], 'refs/tags/') From 5d6bfcc9495d280777237cc940c14b1462ee5c86 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 04:25:47 -0300 Subject: [PATCH 019/506] fix goreleaser job --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 668d9051f..ec203f18a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -79,7 +79,7 @@ jobs: - script: | curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh - make goreleaser + goreleaser --rm-dist workingDirectory: '$(modulePath)' displayName: 'Go Releaser' condition: startsWith(variables['build.sourceBranch'], 'refs/tags/') From c19eec11b4320411e94985bfd9c5b623ab38053c Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 04:30:02 -0300 Subject: [PATCH 020/506] fix goreleaser path --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ec203f18a..ef6532c78 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -79,7 +79,7 @@ jobs: - script: | curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh - goreleaser --rm-dist + ./bin/goreleaser --rm-dist workingDirectory: '$(modulePath)' displayName: 'Go Releaser' condition: startsWith(variables['build.sourceBranch'], 'refs/tags/') From ce6fc405643c697051b6f997f553aaae522459a1 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 05:29:24 -0300 Subject: [PATCH 021/506] remove recurrent build --- azure-pipelines.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ef6532c78..a34c0dd5b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,14 +11,6 @@ pr: include: - master -schedules: - - cron: "0 * * * *" - displayName: Recurrent build - always: true - branches: - include: - - master - pool: vmImage: 'Ubuntu 16.04' From 3e9b784a6ee75867d19e0d09ff2211f641198fa6 Mon Sep 17 00:00:00 2001 From: dpereskokov Date: Sun, 26 Jan 2020 22:31:48 +0800 Subject: [PATCH 022/506] Revert "change Save Rates interface, now it returns error (#743)" (#751) This reverts commit ba06244299621a3fc6beec3b50218e9f397c1613. --- marketdata/rates.go | 12 ++++-------- storage/market.go | 19 +++---------------- storage/storage.go | 2 +- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/marketdata/rates.go b/marketdata/rates.go index 45fcfcff4..6533adc30 100644 --- a/marketdata/rates.go +++ b/marketdata/rates.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/marketdata/rate" "github.com/trustwallet/blockatlas/marketdata/rate/coingecko" - "github.com/trustwallet/blockatlas/marketdata/rate/coinmarketcap" + cmc "github.com/trustwallet/blockatlas/marketdata/rate/coinmarketcap" "github.com/trustwallet/blockatlas/marketdata/rate/compound" "github.com/trustwallet/blockatlas/marketdata/rate/fixer" "github.com/trustwallet/blockatlas/pkg/errors" @@ -54,13 +54,9 @@ func runRate(storage storage.Market, p rate.Provider) error { if err != nil { return errors.E(err, "FetchLatestRates") } - if len(rates) == 0 { - return nil + if len(rates) > 0 { + storage.SaveRates(rates, rateProviders) + logger.Info("Market rates", logger.Params{"rates": len(rates), "provider": p.GetId()}) } - err = storage.SaveRates(rates, rateProviders) - if err != nil { - return errors.E(err, "runRate", errors.Params{"rates": rates}) - } - logger.Info("Market rates", logger.Params{"rates": len(rates), "provider": p.GetId()}) return nil } diff --git a/storage/market.go b/storage/market.go index 8a797a193..5f7c6d436 100644 --- a/storage/market.go +++ b/storage/market.go @@ -43,12 +43,7 @@ func (s *Storage) GetTicker(coin, token string) (*blockatlas.Ticker, error) { return cd, nil } -func (s *Storage) SaveRates(rates blockatlas.Rates, pl ProviderList) error { - var ( - errCounter int - errSaveSome = errors.E("Save some rates") - ) - +func (s *Storage) SaveRates(rates blockatlas.Rates, pl ProviderList) { for _, rate := range rates { r, err := s.GetRate(rate.Currency) if err == nil { @@ -62,20 +57,12 @@ func (s *Storage) SaveRates(rates blockatlas.Rates, pl ProviderList) error { continue } } - if err = s.AddHM(EntityRates, rate.Currency, &rate); err != nil { - errCounter++ - errSaveSome.SetMeta(errors.Params{"rate": rate}) + err = s.AddHM(EntityRates, rate.Currency, &rate) + if err != nil { logger.Error(err, "SaveRates", logger.Params{"rate": rate}) continue } } - if errCounter == len(rates) { - return errors.E("Save all rates") - } - if errCounter > 0 { - return errSaveSome - } - return nil } func (s *Storage) GetRate(currency string) (rate *blockatlas.Rate, err error) { diff --git a/storage/storage.go b/storage/storage.go index d0e214e9b..dfd510851 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -30,6 +30,6 @@ type Addresses interface { type Market interface { SaveTicker(coin *blockatlas.Ticker, pl ProviderList) error GetTicker(coin, token string) (*blockatlas.Ticker, error) - SaveRates(rates blockatlas.Rates, pl ProviderList) error + SaveRates(rates blockatlas.Rates, pl ProviderList) GetRate(currency string) (*blockatlas.Rate, error) } From acfb1d54593e9c0a5b006ea6cf84b2b96171324b Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 22:06:22 -0300 Subject: [PATCH 023/506] change tezos address for integration tests --- pkg/integration/testdata/coin_fixtures.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/integration/testdata/coin_fixtures.json b/pkg/integration/testdata/coin_fixtures.json index b4d7918da..92df2e1c4 100644 --- a/pkg/integration/testdata/coin_fixtures.json +++ b/pkg/integration/testdata/coin_fixtures.json @@ -108,7 +108,7 @@ "address": "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" }, "tezos": { - "address": "KT1XRAGQEbUqqagjX9j7RbvpUe7ZwF29DnM2" + "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" }, "tron": { "address": "TQZskDJJRGAHifeKoQ7wLC4QDyB2iGvwp2" From e8061b870436afabecc2fd44ba36802768063e4f Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 26 Jan 2020 22:55:40 -0300 Subject: [PATCH 024/506] improve pipeline and github templates --- .github/ISSUE_TEMPLATE/bug_report.md | 19 +++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 18 +++++++++++++++++- azure-pipelines.yml | 11 +++++++++-- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 893ece13a..95da69332 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -10,6 +10,7 @@ assignees: '' @@ -17,11 +18,29 @@ v Please also ensure that this is not a duplicate issue :) +## Expected Behavior + + + +## Current Behavior + + ## Steps to Reproduce +## More Info +#### Request details (optional): +``` +{} +``` + +#### Response details (optional): +``` +{} +``` + ____ #### For Admin Use diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 926d5e5b9..e7073f309 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -9,6 +9,7 @@ assignees: '' @@ -16,16 +17,31 @@ v Before smashing the submit button please review the template. -## Problem Definition +## Problem Definition / Why? +## Where/how shows? + + + ## Proposal +#### Request details (optional): +`v1/market/example` +``` +{} +``` + +#### Response details (optional): +``` +{} +``` + ____ #### For Admin Use diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a34c0dd5b..32252c765 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -61,10 +61,17 @@ jobs: make integration workingDirectory: '$(modulePath)' displayName: 'Run integration tests' - # Use this condition when we start to use continuous CI - # condition: eq(variables['build.sourceBranch'], 'refs/heads/master') + condition: ne(variables['build.sourceBranch'], 'refs/heads/master') continueOnError: true + - script: | + go get github.com/gavv/httpexpect + make integration + workingDirectory: '$(modulePath)' + displayName: 'Run integration tests' + condition: eq(variables['build.sourceBranch'], 'refs/heads/master') + continueOnError: false + - script: go build -v . workingDirectory: '$(modulePath)' displayName: 'Build' From 9040f20a14edaab3c56672c6a5dbe99b5b28d440 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 01:27:02 -0300 Subject: [PATCH 025/506] add github token --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 32252c765..6e986566d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,6 +15,7 @@ pool: vmImage: 'Ubuntu 16.04' variables: + GITHUB_TOKEN: '$(GITHUB_TOKEN)' GOBIN: '$(GOPATH)/bin' # Go binaries path GOROOT: '/usr/local/go1.13' # Go installation path GOPATH: '$(Build.SourcesDirectory)/gopath' # Go workspace path From 209ae472627fb126e2225caf79e5f894381f4497 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 01:34:51 -0300 Subject: [PATCH 026/506] run go mod tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 30695b6be..cba83252c 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,7 @@ require ( github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.3 - github.com/ugorji/go v1.1.7 // indirect + github.com/ugorji/go/codec v1.1.7 // indirect github.com/wealdtech/go-ens/v3 v3.0.9 github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b // indirect golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f From d086174d081bf9cbc65b48b1ce8025773675a60c Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 01:42:05 -0300 Subject: [PATCH 027/506] azp git token --- azure-pipelines.yml | 23 ++++++++++++----------- go.mod | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6e986566d..de4c54421 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,7 +15,6 @@ pool: vmImage: 'Ubuntu 16.04' variables: - GITHUB_TOKEN: '$(GITHUB_TOKEN)' GOBIN: '$(GOPATH)/bin' # Go binaries path GOROOT: '/usr/local/go1.13' # Go installation path GOPATH: '$(Build.SourcesDirectory)/gopath' # Go workspace path @@ -36,16 +35,16 @@ jobs: echo '$(go env)' displayName: 'Set up the Go workspace' - - task: CacheBeta@1 - inputs: - key: 'go | "$(Agent.OS)" | **/go.mod' - restoreKeys: | - go | "$(Agent.OS)" - go - path: | - $(GOPATH) - !$(modulePath) - displayName: 'Cache go packages' + # - task: CacheBeta@1 + # inputs: + # key: 'go | "$(Agent.OS)" | **/go.mod' + # restoreKeys: | + # go | "$(Agent.OS)" + # go + # path: | + # $(GOPATH) + # !$(modulePath) + # displayName: 'Cache go packages' - script: | go version @@ -83,3 +82,5 @@ jobs: workingDirectory: '$(modulePath)' displayName: 'Go Releaser' condition: startsWith(variables['build.sourceBranch'], 'refs/tags/') + variables: + GITHUB_TOKEN: '$(GIT_TOKEN)' diff --git a/go.mod b/go.mod index cba83252c..30695b6be 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,7 @@ require ( github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.3 - github.com/ugorji/go/codec v1.1.7 // indirect + github.com/ugorji/go v1.1.7 // indirect github.com/wealdtech/go-ens/v3 v3.0.9 github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b // indirect golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f From 8668237c9ad1c938279a8d086476af64b359aa83 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 01:47:39 -0300 Subject: [PATCH 028/506] fix github token for azp --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index de4c54421..9f8d84d6a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,6 +15,7 @@ pool: vmImage: 'Ubuntu 16.04' variables: + GITHUB_TOKEN: '$(GIT_TOKEN)' GOBIN: '$(GOPATH)/bin' # Go binaries path GOROOT: '/usr/local/go1.13' # Go installation path GOPATH: '$(Build.SourcesDirectory)/gopath' # Go workspace path @@ -82,5 +83,4 @@ jobs: workingDirectory: '$(modulePath)' displayName: 'Go Releaser' condition: startsWith(variables['build.sourceBranch'], 'refs/tags/') - variables: - GITHUB_TOKEN: '$(GIT_TOKEN)' + From aefef0678e2c19616d9196255c4c2b027b935cbd Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 01:57:25 -0300 Subject: [PATCH 029/506] reset files before launch goreleaser --- .goreleaser.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 72d6e08fe..4769d86bc 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,6 +1,7 @@ before: hooks: - - go generate ./... + - git reset --hard + - git checkout . builds: - main: "./main.go" env: From 3c9fcfb9d591a75b1cb6bc485cdd29d4a5bd66f2 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 02:37:36 -0300 Subject: [PATCH 030/506] fix github token for azp --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9f8d84d6a..15f14f642 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,7 +15,7 @@ pool: vmImage: 'Ubuntu 16.04' variables: - GITHUB_TOKEN: '$(GIT_TOKEN)' + GITHUB_TOKEN: '$(git.token)' GOBIN: '$(GOPATH)/bin' # Go binaries path GOROOT: '/usr/local/go1.13' # Go installation path GOPATH: '$(Build.SourcesDirectory)/gopath' # Go workspace path From ad9ad35086040d5d78f73a063010fcdff5432ceb Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 08:16:16 -0300 Subject: [PATCH 031/506] improve CI running govet --- Makefile | 14 ++++++++++++++ azure-pipelines.yml | 24 +++++++++++------------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 7985df612..9031d1e2e 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,12 @@ remove-coin-file: ## goreleaser: Release the last tag version with GoReleaser. goreleaser: go-goreleaser +## govet: Run go vet. +govet: go-vet + +## golint: Run golint. +golint: go-lint + go-compile: go-get go-build go-build: @@ -150,6 +156,14 @@ go-goreleaser: @echo " > Releasing a new version" GOBIN=$(GOBIN) goreleaser --rm-dist +go-vet: + @echo " > Running go vet" + GOBIN=$(GOBIN) go vet ./... + +go-lint: + @echo " > Running golint" + GOBIN=$(GOBIN) golint ./... + .PHONY: help all: help help: Makefile diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 15f14f642..5d6f83e9a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,23 +36,20 @@ jobs: echo '$(go env)' displayName: 'Set up the Go workspace' - # - task: CacheBeta@1 - # inputs: - # key: 'go | "$(Agent.OS)" | **/go.mod' - # restoreKeys: | - # go | "$(Agent.OS)" - # go - # path: | - # $(GOPATH) - # !$(modulePath) - # displayName: 'Cache go packages' - - script: | go version go get -v -t -d ./... workingDirectory: '$(modulePath)' displayName: 'Get dependencies' + - script: make govet + workingDirectory: '$(modulePath)' + displayName: 'Run go vet' + + - script: make golint + workingDirectory: '$(modulePath)' + displayName: 'Run go lint' + - script: make test workingDirectory: '$(modulePath)' displayName: 'Run unit tests' @@ -61,7 +58,7 @@ jobs: go get github.com/gavv/httpexpect make integration workingDirectory: '$(modulePath)' - displayName: 'Run integration tests' + displayName: "Run integration tests for new PR's" condition: ne(variables['build.sourceBranch'], 'refs/heads/master') continueOnError: true @@ -69,13 +66,14 @@ jobs: go get github.com/gavv/httpexpect make integration workingDirectory: '$(modulePath)' - displayName: 'Run integration tests' + displayName: 'Run integration tests for new releases' condition: eq(variables['build.sourceBranch'], 'refs/heads/master') continueOnError: false - script: go build -v . workingDirectory: '$(modulePath)' displayName: 'Build' + condition: !startsWith(variables['build.sourceBranch'], 'refs/tags/') - script: | curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh From 3851683ff773b2d57c74588308951bfdf1e9fe1d Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 08:18:50 -0300 Subject: [PATCH 032/506] fix azp build --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5d6f83e9a..c6213f82c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -73,7 +73,7 @@ jobs: - script: go build -v . workingDirectory: '$(modulePath)' displayName: 'Build' - condition: !startsWith(variables['build.sourceBranch'], 'refs/tags/') + condition: not(startsWith(variables['build.sourceBranch'], 'refs/tags/')) - script: | curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh From e79c2635601d332a865a1161da90b7373b5756d8 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 08:26:18 -0300 Subject: [PATCH 033/506] azp continue on error --- azure-pipelines.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c6213f82c..f0af629f7 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -45,10 +45,14 @@ jobs: - script: make govet workingDirectory: '$(modulePath)' displayName: 'Run go vet' + continueOnError: true - - script: make golint + - script: | + go get -u golang.org/x/lint/golint + make golint workingDirectory: '$(modulePath)' displayName: 'Run go lint' + continueOnError: true - script: make test workingDirectory: '$(modulePath)' From 26fab6f916c6616278dc1619078d89b983620c00 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 08:31:27 -0300 Subject: [PATCH 034/506] fix govet issues --- observer/observer_test.go | 44 +++++++++++++++++++-------------------- platform/nebulas/model.go | 2 +- test/tx_test.go | 36 ++++++++++++++++---------------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/observer/observer_test.go b/observer/observer_test.go index ce7b0055f..2219c1d51 100644 --- a/observer/observer_test.go +++ b/observer/observer_test.go @@ -38,11 +38,11 @@ func Test_getDirection(t *testing.T) { args{ blockatlas.Tx{ Outputs: []blockatlas.TxOutput{ - {"DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", "72934112534"}, - {"DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", "500000000"}, + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "72934112534"}, + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "500000000"}, }, Inputs: []blockatlas.TxOutput{ - {"DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", "73196112534"}, + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "73196112534"}, }, }, "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", }, blockatlas.DirectionSelf, @@ -51,12 +51,12 @@ func Test_getDirection(t *testing.T) { args{ blockatlas.Tx{ Outputs: []blockatlas.TxOutput{ - {"3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", "4471835"}, - {"324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", "1600000"}, - {"32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", "1262899630"}, + {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, + {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, }, Inputs: []blockatlas.TxOutput{ - {"32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", "1268998877"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, }, }, "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", }, blockatlas.DirectionOutgoing, @@ -65,12 +65,12 @@ func Test_getDirection(t *testing.T) { args{ blockatlas.Tx{ Outputs: []blockatlas.TxOutput{ - {"3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", "4471835"}, - {"324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", "1600000"}, - {"32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", "1262899630"}, + {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, + {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, }, Inputs: []blockatlas.TxOutput{ - {"32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", "1268998877"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, }, }, "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", }, blockatlas.DirectionIncoming, @@ -100,11 +100,11 @@ func Test_inferUtxoValue(t *testing.T) { args{ blockatlas.Tx{ Outputs: []blockatlas.TxOutput{ - {"DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", "72934112534"}, - {"DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", "500000000"}, + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "72934112534"}, + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "500000000"}, }, Inputs: []blockatlas.TxOutput{ - {"DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", "73196112534"}, + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "73196112534"}, }, }, "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", 3, }, blockatlas.Amount("72934112534"), @@ -113,12 +113,12 @@ func Test_inferUtxoValue(t *testing.T) { args{ blockatlas.Tx{ Outputs: []blockatlas.TxOutput{ - {"3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", "4471835"}, - {"324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", "1600000"}, - {"32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", "1262899630"}, + {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, + {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, }, Inputs: []blockatlas.TxOutput{ - {"32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", "1268998877"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, }, }, "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", 0, }, blockatlas.Amount("4471835"), @@ -127,12 +127,12 @@ func Test_inferUtxoValue(t *testing.T) { args{ blockatlas.Tx{ Outputs: []blockatlas.TxOutput{ - {"3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", "4471835"}, - {"324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", "1600000"}, - {"32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", "1262899630"}, + {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, + {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, }, Inputs: []blockatlas.TxOutput{ - {"32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", "1268998877"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, }, }, "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", 0, }, blockatlas.Amount("4471835"), diff --git a/platform/nebulas/model.go b/platform/nebulas/model.go index 68ce55391..583370cd2 100644 --- a/platform/nebulas/model.go +++ b/platform/nebulas/model.go @@ -22,7 +22,7 @@ type Transaction struct { Nonce uint64 `json:"nonce"` Block Block `json:"block"` From Address `json:"from"` - To Address `json: "to"` + To Address `json:"to"` Timestamp int64 `json:"timestamp"` Status int32 `json:"status"` } diff --git a/test/tx_test.go b/test/tx_test.go index 76abb6b1e..4c0820e6b 100644 --- a/test/tx_test.go +++ b/test/tx_test.go @@ -87,22 +87,22 @@ var utxoTransferDst1 = blockatlas.Tx{ Coin: coin.BTC, Inputs: []blockatlas.TxOutput{ { - "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", - "1", + Address: "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", + Value: "1", }, { - "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh", - "1", + Address: "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh", + Value: "1", }, { - "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737", - "1", + Address: "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737", + Value: "1", }, }, Outputs: []blockatlas.TxOutput{ { - "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", - "3", + Address: "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", + Value: "3", }, }, Fee: "125000", @@ -117,26 +117,26 @@ var utxoTransferDst2 = blockatlas.Tx{ Coin: coin.BTC, Inputs: []blockatlas.TxOutput{ { - "bc1q6e8sdxlgc7ekqkqyevtrx8wshfv7sg66z3z6ce", - "4", + Address: "bc1q6e8sdxlgc7ekqkqyevtrx8wshfv7sg66z3z6ce", + Value: "4", }, { - "bc1q7nn4txus4g6fc5v7d2tha35ely8mfpd8qvv6eg", - "2", + Address: "bc1q7nn4txus4g6fc5v7d2tha35ely8mfpd8qvv6eg", + Value: "2", }, }, Outputs: []blockatlas.TxOutput{ { - "bc1q2fpry7zwqh575huc9urwfdvjtuvz508wez56ff", - "3", + Address: "bc1q2fpry7zwqh575huc9urwfdvjtuvz508wez56ff", + Value: "3", }, { - "bc1qk3yj6h79qw7tnsg4durc9sd5fpd3qt0p0m8u5p", - "1", + Address: "bc1qk3yj6h79qw7tnsg4durc9sd5fpd3qt0p0m8u5p", + Value: "1", }, { - "bc1qm8836plkzft2rhh23z6j8s9s8fxrzd4zag95z8", - "2", + Address: "bc1qm8836plkzft2rhh23z6j8s9s8fxrzd4zag95z8", + Value: "2", }, }, Fee: "125000", From a50a58d52f3907e8ab3a68824bec65b5e9a200c3 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 12:56:18 -0300 Subject: [PATCH 035/506] fix github issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 26 ++++++++--------------- .github/ISSUE_TEMPLATE/feature_request.md | 21 +++++++----------- .github/ISSUE_TEMPLATE/question.md | 5 +++-- 3 files changed, 20 insertions(+), 32 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 95da69332..afeaa8837 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,10 +8,10 @@ assignees: '' --- ## Summary of Bug @@ -22,30 +22,22 @@ v Please also ensure that this is not a duplicate issue :) -## Current Behavior - - - ## Steps to Reproduce -## More Info -#### Request details (optional): +____ + +## More Info (for devs / optional) +##### Request details: ``` {} ``` -#### Response details (optional): +##### Response details: ``` {} ``` -____ -#### For Admin Use -- [ ] Not duplicate issue -- [ ] Appropriate labels applied -- [ ] Appropriate contributors tagged -- [ ] Contributor assigned/self-assigned diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index e7073f309..82e5f266b 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -8,9 +8,9 @@ assignees: '' --- ## Summary @@ -31,22 +31,17 @@ Are there any disadvantages of including this feature? --> -#### Request details (optional): +____ + +## More Info (for devs / optional) +##### Request details: `v1/market/example` ``` {} ``` -#### Response details (optional): +##### Response details: ``` {} ``` -____ - -#### For Admin Use - -- [ ] Not duplicate issue -- [ ] Appropriate labels applied -- [ ] Appropriate contributors tagged -- [ ] Contributor assigned/self-assigned diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 9f8258add..f40d6757c 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -8,8 +8,9 @@ assignees: '' --- ## How can we help ? From 6b9a9f563379516847fd9560f520c9526817dc58 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> Date: Mon, 27 Jan 2020 18:59:10 +0300 Subject: [PATCH 036/506] add docker-compose (#757) fix sync-markets --- Dockerfile | 23 ++++++++++++----------- README.md | 20 +++++++++++++++++++- docker-compose.yml | 30 ++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile index 173f8b68a..1d6b654ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,14 @@ -FROM golang:alpine as builder -ADD . /go/src/github.com/trustwallet/blockatlas -RUN apk add git \ - && go get -d -v github.com/trustwallet/blockatlas \ - && CGO_ENABLED=0 go install -a \ - -ldflags='-s -w -extldflags "-static"' \ - github.com/trustwallet/blockatlas +FROM golang:latest AS builder -FROM scratch +RUN mkdir /build +ADD . /build +WORKDIR /build +RUN go build -o bin/blockatlas . + +FROM debian:latest +COPY --from=builder /build/bin /app +COPY --from=builder /build/config.yml /app COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -COPY --from=builder /go/bin/blockatlas /bin/blockatlas -COPY --from=builder /go/src/github.com/trustwallet/blockatlas/config.yml /config.yml -CMD ["/bin/blockatlas", "api"] +WORKDIR /app + +ENTRYPOINT ["/app/blockatlas"] \ No newline at end of file diff --git a/README.md b/README.md index 48edec99a..eb02dc273 100644 --- a/README.md +++ b/README.md @@ -66,15 +66,33 @@ go build -o blockatlas . && ./blockatlas sync-markets ### Docker + From Docker Hub: `docker run -it -p 8420:8420 trustwallet/blockatlas` Build and run from local Dockerfile: +You should change `config.yml`: +```yaml +redis: redis://redis:6379 +``` + +Then build as `blockatlas` image: ```shell docker build -t blockatlas . -docker run -p 8420:8420 blockatlas +``` + +For run api, observer and sync-markets: +```shell +docker-compose up +``` + +If you need to start one service: +```shell +docker-compose start api redis +docker-compose start observer redis +docker-compose start sync-markets redis ``` ### Heroku diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..32d91bf8e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,30 @@ +version: '3.7' +services: + api: + container_name: api + image: blockatlas + command: api + ports: + - 8420:8420 + links: + - redis + + observer: + container_name: observer + image: blockatlas + command: observer + links: + - redis + + sync-markets: + container_name: sync-markets + image: blockatlas + command: sync-markets + links: + - redis + + redis: + container_name: redis + image: neojt/mredis + ports: + - 6379:6379 \ No newline at end of file From 0acab66a34bf868a973311bfc61bdabae995a806 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 27 Jan 2020 12:59:52 -0300 Subject: [PATCH 037/506] remove test package and unused methods (#755) --- observer/observer_test.go | 95 ++++++++++++++ {test => pkg/blockatlas}/tx_test.go | 91 +++----------- test/main.go | 189 ---------------------------- 3 files changed, 111 insertions(+), 264 deletions(-) rename {test => pkg/blockatlas}/tx_test.go (59%) delete mode 100644 test/main.go diff --git a/observer/observer_test.go b/observer/observer_test.go index 2219c1d51..bc0f9f247 100644 --- a/observer/observer_test.go +++ b/observer/observer_test.go @@ -1,11 +1,106 @@ package observer import ( + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" ) +var transferDst1 = blockatlas.Tx{ + ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", + Coin: coin.BNB, + From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", + To: "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5", + Fee: "125000", + Date: 1555049867, + Block: 7761368, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.Transfer{ + Value: "10000000000000", + Decimals: 8, + Symbol: "BNB", + }, +} + +var transferDst2 = blockatlas.Tx{ + ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44556", + Coin: coin.BNB, + From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", + To: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", + Fee: "125000", + Date: 1555049867, + Block: 7761368, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.Transfer{ + Value: "10000000000000", + Decimals: 8, + Symbol: "BNB", + }, +} + +var nativeTransferDst1 = blockatlas.Tx{ + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + }, +} + +var nativeTransferDst2 = blockatlas.Tx{ + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4D0", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + }, +} + +var txsBlock = blockatlas.Block{ + Number: 12345, + ID: "12345", + Txs: []blockatlas.Tx{ + transferDst1, + transferDst2, + nativeTransferDst1, + nativeTransferDst2, + }, +} + +func TestGetTxs(t *testing.T) { + txs := GetTxs(&txsBlock) + assert.Equal(t, len(txs), 4) + assert.Equal(t, txs["tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2"].Size(), 2) + assert.Equal(t, txs["tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5"].Size(), 1) + assert.Equal(t, txs["tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"].Size(), 2) + assert.Equal(t, txs["tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex"].Size(), 2) +} + func Test_getDirection(t *testing.T) { type args struct { tx blockatlas.Tx diff --git a/test/tx_test.go b/pkg/blockatlas/tx_test.go similarity index 59% rename from test/tx_test.go rename to pkg/blockatlas/tx_test.go index 4c0820e6b..8c72c8156 100644 --- a/test/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -1,14 +1,12 @@ -package main +package blockatlas import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/observer" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" ) -var transferDst1 = blockatlas.Tx{ +var transferDst1 = Tx{ ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", Coin: coin.BNB, From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", @@ -16,33 +14,16 @@ var transferDst1 = blockatlas.Tx{ Fee: "125000", Date: 1555049867, Block: 7761368, - Status: blockatlas.StatusCompleted, + Status: StatusCompleted, Memo: "test", - Meta: blockatlas.Transfer{ + Meta: Transfer{ Value: "10000000000000", Decimals: 8, Symbol: "BNB", }, } -var transferDst2 = blockatlas.Tx{ - ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44556", - Coin: coin.BNB, - From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - To: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - Fee: "125000", - Date: 1555049867, - Block: 7761368, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: blockatlas.Transfer{ - Value: "10000000000000", - Decimals: 8, - Symbol: "BNB", - }, -} - -var nativeTransferDst1 = blockatlas.Tx{ +var nativeTransferDst1 = Tx{ ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", Coin: coin.BNB, From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", @@ -50,9 +31,9 @@ var nativeTransferDst1 = blockatlas.Tx{ Fee: "125000", Date: 1555117625, Block: 7928667, - Status: blockatlas.StatusCompleted, + Status: StatusCompleted, Memo: "test", - Meta: blockatlas.NativeTokenTransfer{ + Meta: NativeTokenTransfer{ TokenID: "YLC-D8B", Symbol: "YLC", Value: "210572645", @@ -62,30 +43,10 @@ var nativeTransferDst1 = blockatlas.Tx{ }, } -var nativeTransferDst2 = blockatlas.Tx{ - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4D0", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: blockatlas.NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, -} - -var utxoTransferDst1 = blockatlas.Tx{ +var utxoTransferDst1 = Tx{ ID: "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", Coin: coin.BTC, - Inputs: []blockatlas.TxOutput{ + Inputs: []TxOutput{ { Address: "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", Value: "1", @@ -99,7 +60,7 @@ var utxoTransferDst1 = blockatlas.Tx{ Value: "1", }, }, - Outputs: []blockatlas.TxOutput{ + Outputs: []TxOutput{ { Address: "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", Value: "3", @@ -108,14 +69,14 @@ var utxoTransferDst1 = blockatlas.Tx{ Fee: "125000", Date: 1555117625, Block: 592400, - Status: blockatlas.StatusCompleted, + Status: StatusCompleted, Memo: "test", } -var utxoTransferDst2 = blockatlas.Tx{ +var utxoTransferDst2 = Tx{ ID: "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", Coin: coin.BTC, - Inputs: []blockatlas.TxOutput{ + Inputs: []TxOutput{ { Address: "bc1q6e8sdxlgc7ekqkqyevtrx8wshfv7sg66z3z6ce", Value: "4", @@ -125,7 +86,7 @@ var utxoTransferDst2 = blockatlas.Tx{ Value: "2", }, }, - Outputs: []blockatlas.TxOutput{ + Outputs: []TxOutput{ { Address: "bc1q2fpry7zwqh575huc9urwfdvjtuvz508wez56ff", Value: "3", @@ -142,32 +103,12 @@ var utxoTransferDst2 = blockatlas.Tx{ Fee: "125000", Date: 1555117625, Block: 592400, - Status: blockatlas.StatusCompleted, + Status: StatusCompleted, Memo: "test", } -var txsBlock = blockatlas.Block{ - Number: 12345, - ID: "12345", - Txs: []blockatlas.Tx{ - transferDst1, - transferDst2, - nativeTransferDst1, - nativeTransferDst2, - }, -} - -func TestGetTxs(t *testing.T) { - txs := observer.GetTxs(&txsBlock) - assert.Equal(t, len(txs), 4) - assert.Equal(t, txs["tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2"].Size(), 2) - assert.Equal(t, txs["tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5"].Size(), 1) - assert.Equal(t, txs["tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"].Size(), 2) - assert.Equal(t, txs["tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex"].Size(), 2) -} - func TestTxSet_Add(t *testing.T) { - set := blockatlas.TxSet{} + set := TxSet{} set.Add(&transferDst1) var txs = set.Txs() assert.Equal(t, txs[0].ID, transferDst1.ID) diff --git a/test/main.go b/test/main.go deleted file mode 100644 index fa7fc1f75..000000000 --- a/test/main.go +++ /dev/null @@ -1,189 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "github.com/spf13/cobra" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/pkg/semaphore" - "net/http" - "os" - "strings" - "sync" - "sync/atomic" - "time" - - "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/coin" -) - -var failedFlag int32 = 0 -var baseURL string -var requireAll bool -var concurrency int - -var app = cobra.Command{ - Use: "test ", - Short: "Test a live API", - Long: "Test a live API by requesting the sample addresses found in coin list", - Args: cobra.ExactArgs(1), - Run: run, -} - -func init() { - flags := app.Flags() - flags.BoolVarP(&requireAll, "all", "a", false, "Don't skip platforms not supported server-side") - flags.IntVarP(&concurrency, "concurrency", "c", 8, "Tests to run at once") -} - -func main() { - err := app.Execute() - if err != nil { - _, _ = fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func run(_ *cobra.Command, args []string) { - baseURL = args[0] - - logrus.SetOutput(os.Stdout) - http.DefaultClient.Timeout = 5 * time.Second - - supportedEndpoints, err := supportedEndpoints() - if err != nil { - logger.Error(err, "Failed to get supported platforms") - os.Exit(1) - } - - var supported = make(map[string]bool) - for _, ns := range supportedEndpoints { - supported[ns] = true - } - - logger.Info("Running goroutines tests", logger.Params{"goroutines": concurrency}) - - var wg sync.WaitGroup - sem := semaphore.NewSemaphore(concurrency) - - var tests []coin.Coin - - for _, c := range coin.Coins { - if !supported[c.Handle] { - if requireAll { - log(&c).Error("Platform not enabled at server but required") - atomic.StoreInt32(&failedFlag, 1) - } else { - log(&c).Warning("Platform not enabled at server, skipping") - } - continue - } - tests = append(tests, c) - } - logger.Info("Platforms to test", logger.Params{"count": len(supportedEndpoints)}) - - wg.Add(len(tests)) - for _, c := range tests { - go runTest(c, sem, &wg) - } - - wg.Wait() - - failed := atomic.LoadInt32(&failedFlag) - if failed == 1 { - logger.Fatal("Test failed") - } else { - logger.Info("Test passed") - } -} - -func log(c *coin.Coin) *logrus.Entry { - return logrus.WithField("@platform", c.Handle) -} - -func runTest(c coin.Coin, sem *semaphore.Semaphore, wg *sync.WaitGroup) { - defer wg.Done() - sem.Acquire() - defer sem.Release() - - start := time.Now() - - defer func() { - if r := recover(); r != nil { - log(&c). - WithField("error", r). - Error("Endpoint failed") - atomic.StoreInt32(&failedFlag, 1) - } - - log(&c).WithField("time", time.Since(start)).Info("Endpoint tested") - }() - - test(&c) - log(&c).Info("Endpoint works") -} - -func test(c *coin.Coin) { - res, err := http.Get(fmt.Sprintf("%s/v1/%s/%s", baseURL, c.Handle, c.SampleAddr)) - if err != nil { - panic(err) - } - defer res.Body.Close() - - if res.StatusCode != http.StatusOK { - panic("Status " + res.Status) - } - - if !strings.HasPrefix(res.Header.Get("Content-Type"), "application/json") { - panic("Unexpected Content-Type " + res.Header.Get("Content-Type")) - } - - // Parse model and read into buffer - var model struct { - Docs []blockatlas.Tx `json:"docs"` - } - dec := json.NewDecoder(res.Body) - err = dec.Decode(&model) - if err != nil { - panic(err) - } - - if len(model.Docs) == 0 { - log(c).Warning("No transactions") - return - } - - // Enumerate transactions - var lastTime = ^uint64(0) - for _, tx := range model.Docs { - point := tx.Date - - if uint64(point) <= lastTime { - lastTime = uint64(point) - } else { - panic("Transactions not in chronological order") - } - - if tx.Coin != c.ID { - panic("Wrong coin index") - } - } -} - -func supportedEndpoints() (endpoints []string, err error) { - var data struct { - Endpoints []string `json:"endpoints"` - } - res, err := http.Get(fmt.Sprintf("%s/v1/", baseURL)) - if err != nil { - return nil, err - } - defer res.Body.Close() - dec := json.NewDecoder(res.Body) - err = dec.Decode(&data) - if err != nil { - return nil, err - } - return data.Endpoints, nil -} From 13062bd4293a7ffe13021941d49240eeaf433e9e Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Tue, 28 Jan 2020 02:57:54 +0300 Subject: [PATCH 038/506] [Platform] Add Dynamic APR for ATOM/Kava + Caching (#747) * Add GetMaxAPR for Cosmos * caching layer + Cosmos / Kava dynamic APR calculation + change default value to 0 + change config for cosmos Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> --- api/batch.go | 6 ++++-- cmd/api.go | 10 +++++----- cmd/observer.go | 4 ++-- cmd/root.go | 4 ++-- cmd/sync.go | 4 ++-- config.yml | 2 +- pkg/blockatlas/staking.go | 2 ++ platform/cosmos/stake.go | 23 +++++++++++++++++++++-- platform/registry.go | 13 ++++++------- 9 files changed, 45 insertions(+), 23 deletions(-) diff --git a/api/batch.go b/api/batch.go index 6e4945ed2..eb28ea02c 100644 --- a/api/batch.go +++ b/api/batch.go @@ -5,8 +5,10 @@ import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/ginutils/gincache" "github.com/trustwallet/blockatlas/platform" "strconv" + "time" ) type AddressBatchRequest struct { @@ -73,7 +75,7 @@ func makeStakingDelegationsBatchRoute(router gin.IRouter) { // @Success 200 {object} blockatlas.DelegationsBatchPage // @Router /v2/staking/list [post] func makeStakingDelegationsSimpleBatchRoute(router gin.IRouter) { - router.POST("/staking/list", func(c *gin.Context) { + router.POST("/staking/list", gincache.CacheMiddleware(time.Hour*24, func(c *gin.Context) { var reqs CoinsRequest if err := c.BindJSON(&reqs); err != nil { ginutils.ErrorResponse(c).Message(err.Error()).Render() @@ -94,7 +96,7 @@ func makeStakingDelegationsSimpleBatchRoute(router gin.IRouter) { batch = append(batch, staking) } ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: batch}) - }) + })) } // @Description Get collection categories diff --git a/cmd/api.go b/cmd/api.go index 4a3dfb178..f7c487dd8 100644 --- a/cmd/api.go +++ b/cmd/api.go @@ -1,12 +1,12 @@ package cmd import ( - sentrygin "github.com/getsentry/sentry-go/gin" + "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" "github.com/spf13/cobra" "github.com/spf13/viper" - swaggerFiles "github.com/swaggo/files" - ginSwagger "github.com/swaggo/gin-swagger" + "github.com/swaggo/files" + "github.com/swaggo/gin-swagger" "github.com/trustwallet/blockatlas/api" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -55,13 +55,13 @@ func RunApi(bind string, c chan *gin.Engine) { if viper.GetBool("observer.enabled") { logger.Info("Loading observer API") observerAPI := engine.Group("/observer/v1") - api.SetupObserverAPI(observerAPI, Storage) + api.SetupObserverAPI(observerAPI, cache) } if viper.GetBool("market.enabled") { logger.Info("Loading market API") marketAPI := engine.Group("/v1/market") - api.SetupMarketAPI(marketAPI, Storage) + api.SetupMarketAPI(marketAPI, cache) } if c != nil { diff --git a/cmd/observer.go b/cmd/observer.go index 0d8b5aa48..7874d1ca3 100644 --- a/cmd/observer.go +++ b/cmd/observer.go @@ -50,7 +50,7 @@ func runObserver(_ *cobra.Command, _ []string) { } stream := observer.Stream{ BlockAPI: api, - Tracker: Storage, + Tracker: cache, PollInterval: pollInterval, BacklogCount: backlogCount, } @@ -58,7 +58,7 @@ func runObserver(_ *cobra.Command, _ []string) { // Check for transaction events obs := observer.Observer{ - Storage: Storage, + Storage: cache, Coin: coin.ID, } events := obs.Execute(blocks) diff --git a/cmd/root.go b/cmd/root.go index cfacb17db..64aba9420 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -13,7 +13,7 @@ import ( ) var ( - Storage = storage.New() + cache = storage.New() rootCmd = cobra.Command{ Use: "blockatlas", Short: "BlockAtlas by Trust Wallet", @@ -30,7 +30,7 @@ var ( // Init Storage host := viper.GetString("storage.redis") - err := Storage.Init(host) + err := cache.Init(host) if err != nil { logger.Fatal(err) } diff --git a/cmd/sync.go b/cmd/sync.go index 79729f16b..3235e991e 100755 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -19,8 +19,8 @@ func syncMarketData(cmd *cobra.Command, args []string) { logger.Fatal("Market is not enabled") } - marketdata.InitRates(Storage) - marketdata.InitMarkets(Storage) + marketdata.InitRates(cache) + marketdata.InitMarkets(cache) <-make(chan bool) } diff --git a/config.yml b/config.yml index ce3d0607d..453d3b39f 100644 --- a/config.yml +++ b/config.yml @@ -140,7 +140,7 @@ theta: # [ATOM] Cosmos: https://cosmos.network/ cosmos: - api: https://stargate.cosmos.network + api: http://stargate.cosmos.network # [SEMUX] SEMUX: https://semux.org/ semux: diff --git a/pkg/blockatlas/staking.go b/pkg/blockatlas/staking.go index 8d34edf4f..16923ffb3 100644 --- a/pkg/blockatlas/staking.go +++ b/pkg/blockatlas/staking.go @@ -18,6 +18,8 @@ const ( DelegationTypeAuto DelegationType = "auto" DelegationTypeDelegate DelegationType = "delegate" + + DefaultAnnualReward = 0 ) type StakingReward struct { diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index d6f17e17e..e5943ab81 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -38,15 +38,34 @@ func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { } func (p *Platform) GetDetails() blockatlas.StakingDetails { - //TODO: Find a way to have a dynamic return blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 11}, + Reward: blockatlas.StakingReward{ + Annual: p.GetMaxAPR(), + }, MinimumAmount: blockatlas.Amount("0"), LockTime: 1814400, Type: blockatlas.DelegationTypeDelegate, } } +func (p *Platform) GetMaxAPR() float64 { + validators, err := p.GetValidators() + if err != nil { + logger.Error("GetMaxAPR", logger.Params{"details": err, "platform": p.Coin().Symbol}) + return blockatlas.DefaultAnnualReward + } + + var max = 0.0 + for _, e := range validators { + v := e.Details.Reward.Annual + if v > max { + max = v + } + } + + return max +} + func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { results := make(blockatlas.DelegationsPage, 0) delegations, err := p.client.GetDelegations(address) diff --git a/platform/registry.go b/platform/registry.go index 624c838fb..ca88e8138 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -2,22 +2,21 @@ package platform import ( "fmt" + "github.com/trustwallet/blockatlas/platform/cosmos" - "github.com/trustwallet/blockatlas/platform/harmony" - + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform/algorand" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/platform/aeternity" "github.com/trustwallet/blockatlas/platform/aion" + "github.com/trustwallet/blockatlas/platform/algorand" "github.com/trustwallet/blockatlas/platform/binance" "github.com/trustwallet/blockatlas/platform/bitcoin" - "github.com/trustwallet/blockatlas/platform/cosmos" "github.com/trustwallet/blockatlas/platform/ethereum" "github.com/trustwallet/blockatlas/platform/fio" + "github.com/trustwallet/blockatlas/platform/harmony" "github.com/trustwallet/blockatlas/platform/icon" "github.com/trustwallet/blockatlas/platform/iotex" "github.com/trustwallet/blockatlas/platform/nano" @@ -49,10 +48,10 @@ var platformList = []blockatlas.Platform{ ðereum.Platform{CoinIndex: coin.WAN}, ðereum.Platform{CoinIndex: coin.TOMO}, ðereum.Platform{CoinIndex: coin.TT}, - &tezos.Platform{}, - &aion.Platform{}, &cosmos.Platform{CoinIndex: coin.ATOM}, &cosmos.Platform{CoinIndex: coin.KAVA}, + &tezos.Platform{}, + &aion.Platform{}, &icon.Platform{}, &iotex.Platform{}, &ontology.Platform{}, From 94dcf8c00cedd350681c50f9e0b93c9c04a00907 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Tue, 28 Jan 2020 03:00:40 +0300 Subject: [PATCH 039/506] [ONTOLOGY] implement block api for ontology (#756) * implement block api for ontology #740 * requested changes --- pkg/integration/integration_test.go | 67 +++++++++++++++++++++++++++-- platform/ontology/api.go | 48 ++++++++++++++++++++- platform/ontology/client.go | 17 +++++++- platform/ontology/model.go | 16 +++++++ 4 files changed, 142 insertions(+), 6 deletions(-) diff --git a/pkg/integration/integration_test.go b/pkg/integration/integration_test.go index 7dcb07b49..fb8572f17 100755 --- a/pkg/integration/integration_test.go +++ b/pkg/integration/integration_test.go @@ -3,15 +3,19 @@ package integration import ( + "os" + "sync" + "testing" + "time" + "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/cmd" + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" - "os" - "sync" - "testing" - "time" + "github.com/trustwallet/blockatlas/platform/ontology" ) func TestApis(t *testing.T) { @@ -39,3 +43,58 @@ func TestApis(t *testing.T) { } wg.Wait() } + +var ( + testBlock = blockatlas.Block{ + Number: 7677564, + ID: "168d35ae9333f1d53ee0c124b44d268701df001df1313b388d001a5808f66d01", + Txs: []blockatlas.Tx{ + { + ID: "736fab4fa13435f201bc90a43ca5cd8c324ec88d6048fedb136f267371daee39", + Block: 7677564, + Status: blockatlas.StatusCompleted, + Date: 1580115134, + Coin: coin.Ontology().ID, + }, + }, + } + blockNum = 7677564 +) + +func TestOntology(t *testing.T) { + confPath := "../../config.yml" + config.LoadConfig(confPath) + p := &ontology.Platform{} + p.Init() + testCurrentBlockNumber(p, t) + testGetBlockByNumber(p, t) +} + +func testCurrentBlockNumber(p *ontology.Platform, t *testing.T) { + resp, err := p.CurrentBlockNumber() + if err != nil { + t.Error(err) + } + if resp < 0 { + t.Error("block is < 0") + } +} + +func testGetBlockByNumber(p *ontology.Platform, t *testing.T) { + resp, err := p.GetBlockByNumber(int64(blockNum)) + if err != nil { + t.Error(err) + } + + isSame := resp.ID == testBlock.ID && + resp.Number == testBlock.Number && + resp.Txs[0].ID == testBlock.Txs[0].ID && + resp.Txs[0].Block == testBlock.Txs[0].Block && + resp.Txs[0].Status == testBlock.Txs[0].Status && + resp.Txs[0].Date == testBlock.Txs[0].Date && + resp.Txs[0].Coin == testBlock.Txs[0].Coin + + if !isSame { + t.Error("Block is not the same") + } +} diff --git a/platform/ontology/api.go b/platform/ontology/api.go index a09c42d96..dd3753db0 100644 --- a/platform/ontology/api.go +++ b/platform/ontology/api.go @@ -4,6 +4,7 @@ import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "strings" @@ -42,7 +43,6 @@ func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatla }) return blockatlas.TxPage{}, err } - var txs []blockatlas.Tx for _, srcTx := range txPage.Result.TxnList { tx, ok := Normalize(&srcTx, token) @@ -55,6 +55,52 @@ func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatla return txs, nil } +func (p *Platform) CurrentBlockNumber() (int64, error) { + block, err := p.client.CurrentBlockNumber() + if err != nil { + logger.Error("CurrentBlockNumber", logger.Params{"platform": p.Coin().Symbol, "details": err.Error()}) + return 0, err + } + var height int64 + if block.Error != 0 { + err = errors.E("explorer error") + } + if len(block.Result) > 0 { + height = (int64)(block.Result[0].Height) + } + return height, nil +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + response, err := p.client.GetBlockByNumber(num) + if err != nil { + logger.Error("GetBlockByNumber", logger.Params{"platform": p.Coin().Symbol, "details": err.Error()}) + return nil, err + } + var ( + block blockatlas.Block + txs []blockatlas.Tx + ) + if response.Error == 0 { + block.ID = response.Result.Hash + block.Number = int64(response.Result.Height) + for _, txn := range response.Result.TxnList { + tx := new(blockatlas.Tx) + tx.ID = txn.TxnHash + tx.Block = uint64(txn.Height) + if txn.ConfirmFlag == 1 { + tx.Status = blockatlas.StatusCompleted + } + tx.Date = int64(txn.TxnTime) + tx.Coin = coin.Ontology().ID + txs = append(txs, *tx) + } + block.Txs = txs + } + + return &block, nil +} + func Normalize(srcTx *Tx, assetName string) (tx blockatlas.Tx, ok bool) { if len(srcTx.TransferList) < 1 { return tx, false diff --git a/platform/ontology/client.go b/platform/ontology/client.go index 20eedee90..a48443e6d 100644 --- a/platform/ontology/client.go +++ b/platform/ontology/client.go @@ -10,10 +10,25 @@ type Client struct { } // Explorer API max returned transactions per page -const TxPerPage = 20 +const ( + TxPerPage = 20 + requestOnlyLatestBlockAmount = 1 +) func (c *Client) GetTxsOfAddress(address, assetName string) (txPage *TxPage, err error) { url := fmt.Sprintf("address/%s/%s/%d/1", address, assetName, TxPerPage) err = c.Get(&txPage, url, nil) return } + +func (c *Client) CurrentBlockNumber() (response *BlockResults, err error) { + url := fmt.Sprintf("blocklist/%d", requestOnlyLatestBlockAmount) + err = c.Get(&response, url, nil) + return +} + +func (c *Client) GetBlockByNumber(num int64) (block *BlockResult, err error) { + url := fmt.Sprintf("block/%d", num) + err = c.Get(&block, url, nil) + return +} diff --git a/platform/ontology/model.go b/platform/ontology/model.go index 04d92937b..b51e5b6ec 100644 --- a/platform/ontology/model.go +++ b/platform/ontology/model.go @@ -25,3 +25,19 @@ type Tx struct { TransferList []Transfer `json:"TransferList"` } + +type BlockResults struct { + Error int `json:"Error"` + Result []Block `json:"Result"` +} + +type BlockResult struct { + Error int `json:"Error"` + Result Block `json:"Result"` +} + +type Block struct { + Height int `json:"Height"` + TxnList []Tx `json:"TxnList"` + Hash string `json:"Hash"` +} From 83fd1dcb54a534cee0b63567506ef11b351e56bf Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 28 Jan 2020 16:36:24 +0900 Subject: [PATCH 040/506] Add username field to social link struct (#753) --- pkg/blockatlas/marketdata.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/pkg/blockatlas/marketdata.go b/pkg/blockatlas/marketdata.go index bcf411b40..0ad218163 100644 --- a/pkg/blockatlas/marketdata.go +++ b/pkg/blockatlas/marketdata.go @@ -48,14 +48,20 @@ type ChartCoinInfo struct { } type CoinInfo struct { - Name string `json:"name,omitempty"` - Website string `json:"website,omitempty"` - SourceCode string `json:"source_code,omitempty"` - Whitepaper string `json:"whitepaper,omitempty"` - Explorers []Link `json:"explorers,omitempty"` - Socials []Link `json:"socials,omitempty"` - Details []Detail `json:"details,omitempty"` - DataSource string `json:"data_source,omitempty"` + Name string `json:"name,omitempty"` + Website string `json:"website,omitempty"` + SourceCode string `json:"source_code,omitempty"` + Whitepaper string `json:"whitepaper,omitempty"` + Explorers []Link `json:"explorers,omitempty"` + Socials []SocialLink `json:"socials,omitempty"` + Details []Detail `json:"details,omitempty"` + DataSource string `json:"data_source,omitempty"` +} + +type SocialLink struct { + Name string `json:"name"` + Url string `json:"url"` + Username string `json:"username"` } type Link struct { From 322c46133380cfc498a35287d3e57061a10aa253 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 28 Jan 2020 13:10:39 -0300 Subject: [PATCH 041/506] improve naming service api (#768) --- Makefile | 4 ++-- api/naming_service.go | 24 ++++++++++++++---------- pkg/blockatlas/api.go | 1 + 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 9031d1e2e..2ad929029 100644 --- a/Makefile +++ b/Makefile @@ -138,11 +138,11 @@ go-clean: go-test: @echo " > Runing unit tests" - GOBIN=$(GOBIN) go test -cover -v ./... + GOBIN=$(GOBIN) go test -cover -race -v ./... go-integration: @echo " > Runing integration tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(TEST_CONFIG) go test -tags=integration -v ./pkg/integration + GOBIN=$(GOBIN) TEST_CONFIG=$(TEST_CONFIG) go test -race -tags=integration -v ./pkg/integration go-fmt: @echo " > Format all go files" diff --git a/api/naming_service.go b/api/naming_service.go index b54917306..a0be1036d 100644 --- a/api/naming_service.go +++ b/api/naming_service.go @@ -106,15 +106,19 @@ func sliceAtoi(sa []string) ([]uint64, error) { func handleLookup(name string, coins []uint64) (result []blockatlas.Resolved, err error) { name = strings.ToLower(name) - for tld, id := range TLDMapping { - if strings.HasSuffix(name, tld) { - api := platform.NamingAPIs[id] - result, err = api.Lookup(coins, name) - if err != nil { - return - } - return - } + ss := strings.Split(name, ".") + if len(ss) == 0 { + return nil, errors.E("name not found", errors.Params{"name": name, "coins": coins}) + } + tld := "." + ss[len(ss)-1] + id, ok := TLDMapping[tld] + if !ok { + return nil, errors.E("name not found", errors.Params{"name": name, "coins": coins}) + } + api, ok := platform.NamingAPIs[id] + if !ok { + return nil, errors.E("platform not found", errors.Params{"name": name, "coins": coins}) } - return nil, errors.E("name not found", errors.Params{"name": name}) + result, err = api.Lookup(coins, name) + return } diff --git a/pkg/blockatlas/api.go b/pkg/blockatlas/api.go index f1ae1cf21..bafbb616d 100644 --- a/pkg/blockatlas/api.go +++ b/pkg/blockatlas/api.go @@ -72,6 +72,7 @@ type CustomAPI interface { RegisterRoutes(router gin.IRouter) } +// NamingServiceAPI provides public name service domains HTTP routes type NamingServiceAPI interface { Platform Lookup(coins []uint64, name string) ([]Resolved, error) From e79eba620dd181621721cf50e40a31d8c2158a81 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 28 Jan 2020 17:01:17 -0300 Subject: [PATCH 042/506] remove golint from AZP CI --- azure-pipelines.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f0af629f7..9316e5426 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -45,14 +45,6 @@ jobs: - script: make govet workingDirectory: '$(modulePath)' displayName: 'Run go vet' - continueOnError: true - - - script: | - go get -u golang.org/x/lint/golint - make golint - workingDirectory: '$(modulePath)' - displayName: 'Run go lint' - continueOnError: true - script: make test workingDirectory: '$(modulePath)' From 336e351ad40c0e27a251056a8dc42708776b6dc2 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 28 Jan 2020 17:02:39 -0300 Subject: [PATCH 043/506] fix cosmos race condition (#771) --- platform/cosmos/api.go | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/platform/cosmos/api.go b/platform/cosmos/api.go index 400aa29d5..66362ce73 100644 --- a/platform/cosmos/api.go +++ b/platform/cosmos/api.go @@ -5,6 +5,7 @@ import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "strconv" "sync" @@ -47,19 +48,30 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { } func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - srcTxs := make([]Tx, 0) tagsList := []string{"transfer.recipient", "message.sender"} - var wg sync.WaitGroup + out := make(chan TxPage) for _, t := range tagsList { wg.Add(1) go func(tag, addr string) { defer wg.Done() - txs, _ := p.client.GetAddrTxs(addr, tag) - srcTxs = append(srcTxs, txs.Txs...) + txs, err := p.client.GetAddrTxs(addr, tag) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"address": tag, "tag": tag}) + return + } + out <- txs }(t, address) } - wg.Wait() + go func() { + wg.Wait() + close(out) + }() + + srcTxs := make([]Tx, 0) + for r := range out { + srcTxs = append(srcTxs, r.Txs...) + } return p.NormalizeTxs(srcTxs), nil } From b51a3f22aa5f849b0a04236524a052a75998626d Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 28 Jan 2020 17:23:42 -0300 Subject: [PATCH 044/506] fix unit tests for cmc charts --- marketdata/chart/coinmarketcap/cmc_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/marketdata/chart/coinmarketcap/cmc_test.go b/marketdata/chart/coinmarketcap/cmc_test.go index e44c1815a..f8cfbc819 100644 --- a/marketdata/chart/coinmarketcap/cmc_test.go +++ b/marketdata/chart/coinmarketcap/cmc_test.go @@ -5,6 +5,7 @@ import ( "github.com/trustwallet/blockatlas/marketdata/clients/cmc" "github.com/trustwallet/blockatlas/pkg/blockatlas" "reflect" + "sort" "testing" "time" ) @@ -147,6 +148,9 @@ func Test_normalizeCharts(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotInfo := normalizeCharts(tt.args.currency, tt.args.charts) + sort.SliceStable(gotInfo.Prices, func(i, j int) bool { + return gotInfo.Prices[i].Price < gotInfo.Prices[j].Price + }) if !assert.ObjectsAreEqualValues(tt.wantInfo, gotInfo) { t.Errorf("normalizeCharts() = %v, want %v", gotInfo, tt.wantInfo) } From 6ee97a2de2ec0f5ac499bd7ad6358a55498db624 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 28 Jan 2020 17:30:24 -0300 Subject: [PATCH 045/506] split integration and functional tests (#772) * split integration and functional tests * add integrations tests --- Makefile | 11 ++++- azure-pipelines.yml | 12 ++++-- .../functional}/fixtures.go | 6 +-- pkg/tests/functional/functional_test.go | 42 +++++++++++++++++++ pkg/{integration => tests/functional}/http.go | 4 +- .../functional}/testdata/body_fixtures.json | 0 .../functional}/testdata/coin_fixtures.json | 0 .../functional}/testdata/exclude.json | 0 .../functional}/testdata/query_fixtures.json | 0 .../integration/integration_test.go | 42 ++----------------- 10 files changed, 68 insertions(+), 49 deletions(-) rename pkg/{integration => tests/functional}/fixtures.go (97%) create mode 100755 pkg/tests/functional/functional_test.go rename pkg/{integration => tests/functional}/http.go (98%) rename pkg/{integration => tests/functional}/testdata/body_fixtures.json (100%) rename pkg/{integration => tests/functional}/testdata/coin_fixtures.json (100%) rename pkg/{integration => tests/functional}/testdata/exclude.json (100%) rename pkg/{integration => tests/functional}/testdata/query_fixtures.json (100%) rename pkg/{ => tests}/integration/integration_test.go (69%) diff --git a/Makefile b/Makefile index 2ad929029..9a6f840ce 100644 --- a/Makefile +++ b/Makefile @@ -92,7 +92,10 @@ clean: ## test: Run all unit tests. test: go-test -## integration: Run all integration tests. +## functional: Run all functional tests. +functional: go-functional + +## integration: Run all functional tests. integration: go-integration ## fmt: Run `go fmt` for all go files. @@ -140,9 +143,13 @@ go-test: @echo " > Runing unit tests" GOBIN=$(GOBIN) go test -cover -race -v ./... +go-functional: + @echo " > Runing functional tests" + GOBIN=$(GOBIN) TEST_CONFIG=$(TEST_CONFIG) go test -race -tags=functional -v ./pkg/tests/functional + go-integration: @echo " > Runing integration tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(TEST_CONFIG) go test -race -tags=integration -v ./pkg/integration + GOBIN=$(GOBIN) TEST_CONFIG=$(TEST_CONFIG) go test -race -tags=integration -v ./pkg/tests/integration go-fmt: @echo " > Format all go files" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9316e5426..006c54a37 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -52,20 +52,24 @@ jobs: - script: | go get github.com/gavv/httpexpect - make integration + make functional workingDirectory: '$(modulePath)' - displayName: "Run integration tests for new PR's" + displayName: "Run functional tests for new PR's" condition: ne(variables['build.sourceBranch'], 'refs/heads/master') continueOnError: true - script: | go get github.com/gavv/httpexpect - make integration + make functional workingDirectory: '$(modulePath)' - displayName: 'Run integration tests for new releases' + displayName: 'Run functional tests for new releases' condition: eq(variables['build.sourceBranch'], 'refs/heads/master') continueOnError: false + - script: make integration + workingDirectory: '$(modulePath)' + displayName: 'Run integration tests' + - script: go build -v . workingDirectory: '$(modulePath)' displayName: 'Build' diff --git a/pkg/integration/fixtures.go b/pkg/tests/functional/fixtures.go similarity index 97% rename from pkg/integration/fixtures.go rename to pkg/tests/functional/fixtures.go index f9da2955d..89b90e2b3 100644 --- a/pkg/integration/fixtures.go +++ b/pkg/tests/functional/fixtures.go @@ -1,6 +1,6 @@ -// +build integration +// +build functional -package integration +package functional import ( "encoding/json" @@ -17,7 +17,7 @@ const ( bodyFixturesFile = "body_fixtures.json" // Body fixtures for POST requests coinFixturesFile = "coin_fixtures.json" // Coin fixtures for path parameters queryFixturesFile = "query_fixtures.json" // Query string for GET requests - excludeApisFile = "exclude.json" // API's need to be excluded from integration tests + excludeApisFile = "exclude.json" // API's need to be excluded from functional tests ) type BodyFixture map[string][]interface{} diff --git a/pkg/tests/functional/functional_test.go b/pkg/tests/functional/functional_test.go new file mode 100755 index 000000000..efab91182 --- /dev/null +++ b/pkg/tests/functional/functional_test.go @@ -0,0 +1,42 @@ +// +build functional + +package functional + +import ( + "os" + "sync" + "testing" + "time" + + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/cmd" + "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/platform" +) + +func TestApis(t *testing.T) { + _ = os.Setenv("ATLAS_GIN_MODE", "debug") + config.LoadConfig(os.Getenv("TEST_CONFIG")) + + logger.InitLogger() + platform.Init() + + p := ":8080" + c := make(chan *gin.Engine) + go func() { + cmd.RunApi(p, c) + }() + e := <-c + time.Sleep(time.Second * 2) + + var wg sync.WaitGroup + cl := newClient(t, p) + for _, r := range e.Routes() { + wg.Add(1) + t.Run(r.Path, func(t *testing.T) { + go cl.doTests(r.Method, r.Path, &wg) + }) + } + wg.Wait() +} diff --git a/pkg/integration/http.go b/pkg/tests/functional/http.go similarity index 98% rename from pkg/integration/http.go rename to pkg/tests/functional/http.go index e81264dac..97e6a6e3d 100644 --- a/pkg/integration/http.go +++ b/pkg/tests/functional/http.go @@ -1,6 +1,6 @@ -// +build integration +// +build functional -package integration +package functional import ( "encoding/json" diff --git a/pkg/integration/testdata/body_fixtures.json b/pkg/tests/functional/testdata/body_fixtures.json similarity index 100% rename from pkg/integration/testdata/body_fixtures.json rename to pkg/tests/functional/testdata/body_fixtures.json diff --git a/pkg/integration/testdata/coin_fixtures.json b/pkg/tests/functional/testdata/coin_fixtures.json similarity index 100% rename from pkg/integration/testdata/coin_fixtures.json rename to pkg/tests/functional/testdata/coin_fixtures.json diff --git a/pkg/integration/testdata/exclude.json b/pkg/tests/functional/testdata/exclude.json similarity index 100% rename from pkg/integration/testdata/exclude.json rename to pkg/tests/functional/testdata/exclude.json diff --git a/pkg/integration/testdata/query_fixtures.json b/pkg/tests/functional/testdata/query_fixtures.json similarity index 100% rename from pkg/integration/testdata/query_fixtures.json rename to pkg/tests/functional/testdata/query_fixtures.json diff --git a/pkg/integration/integration_test.go b/pkg/tests/integration/integration_test.go similarity index 69% rename from pkg/integration/integration_test.go rename to pkg/tests/integration/integration_test.go index fb8572f17..83d4689f1 100755 --- a/pkg/integration/integration_test.go +++ b/pkg/tests/integration/integration_test.go @@ -3,47 +3,14 @@ package integration import ( - "os" - "sync" - "testing" - "time" - - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/cmd" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/platform/ontology" + "os" + "testing" ) -func TestApis(t *testing.T) { - os.Setenv("ATLAS_GIN_MODE", "debug") - config.LoadConfig(os.Getenv("TEST_CONFIG")) - - logger.InitLogger() - platform.Init() - - p := ":8080" - c := make(chan *gin.Engine) - go func() { - cmd.RunApi(p, c) - }() - e := <-c - time.Sleep(time.Second * 2) - - var wg sync.WaitGroup - cl := newClient(t, p) - for _, r := range e.Routes() { - wg.Add(1) - t.Run(r.Path, func(t *testing.T) { - go cl.doTests(r.Method, r.Path, &wg) - }) - } - wg.Wait() -} - var ( testBlock = blockatlas.Block{ Number: 7677564, @@ -62,10 +29,9 @@ var ( ) func TestOntology(t *testing.T) { - confPath := "../../config.yml" - config.LoadConfig(confPath) + config.LoadConfig(os.Getenv("TEST_CONFIG")) p := &ontology.Platform{} - p.Init() + _ = p.Init() testCurrentBlockNumber(p, t) testGetBlockByNumber(p, t) } From a7e51b61bb3e99211f73b43964039aeecff7e29a Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 28 Jan 2020 17:37:44 -0300 Subject: [PATCH 046/506] remove colletions v2 from functional tests to avoid rate limit --- pkg/tests/functional/testdata/exclude.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/tests/functional/testdata/exclude.json b/pkg/tests/functional/testdata/exclude.json index 82caab7b3..51798c170 100644 --- a/pkg/tests/functional/testdata/exclude.json +++ b/pkg/tests/functional/testdata/exclude.json @@ -10,12 +10,14 @@ "/v2/thundertoken/collections/:owner", "/v2/tomochain/collections/:owner", "/v2/gochain/collections/:owner", + "/v2/ethereum/collections/:owner", "/v2/classic/collections/:owner/collection/:collection_id", "/v2/callisto/collections/:owner/collection/:collection_id", "/v2/poa/collections/:owner/collection/:collection_id", "/v2/thundertoken/collections/:owner/collection/:collection_id", "/v2/tomochain/collections/:owner/collection/:collection_id", "/v2/gochain/collections/:owner/collection/:collection_id", + "/v2/ethereum/collections/:owner/collection/:collection_id", "/v3/classic/collections/:owner", "/v3/callisto/collections/:owner", "/v3/poa/collections/:owner", From 4f9e70784b9faf75fb30e04ec73a9c48a7596302 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 28 Jan 2020 17:54:37 -0300 Subject: [PATCH 047/506] fix logic for integration tests --- pkg/tests/functional/http.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/tests/functional/http.go b/pkg/tests/functional/http.go index 97e6a6e3d..b3945cd94 100644 --- a/pkg/tests/functional/http.go +++ b/pkg/tests/functional/http.go @@ -51,10 +51,13 @@ func (c *Client) testGet(route string, query string) { response := request.Expect() //TODO create a logic to validate schemas - //response.JSON().Schema(schema) + if response == nil || response.Raw() == nil { + logger.Error("Invalid response", logger.Params{"response": response, "route": route, "query": query}) + } if response.Raw().StatusCode != http.StatusOK { logger.Error("Invalid status code", logger.Params{"code": response.Raw().Status, "route": route, "query": query}) } + //response.JSON().Schema(schema) response.Status(http.StatusOK) } @@ -69,6 +72,9 @@ func (c *Client) testPost(route string, body interface{}) { } } response := request.Expect() + if response == nil || response.Raw() == nil { + logger.Error("Invalid response", logger.Params{"code": response.Raw().Status, "route": route}) + } if response.Raw().StatusCode != http.StatusOK { bodyJson, _ := json.Marshal(body) logger.Error("Invalid status code", logger.Params{"code": response.Raw().Status, "route": route, "body": bodyJson}) From bc02fb0dcbb816877bf1053501f04f42c78bc4b9 Mon Sep 17 00:00:00 2001 From: Mykola <3277207+kolya182@users.noreply.github.com> Date: Tue, 28 Jan 2020 12:55:13 -0800 Subject: [PATCH 048/506] Rename username to handle (#773) --- pkg/blockatlas/marketdata.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/blockatlas/marketdata.go b/pkg/blockatlas/marketdata.go index 0ad218163..bb16b86c5 100644 --- a/pkg/blockatlas/marketdata.go +++ b/pkg/blockatlas/marketdata.go @@ -59,9 +59,9 @@ type CoinInfo struct { } type SocialLink struct { - Name string `json:"name"` - Url string `json:"url"` - Username string `json:"username"` + Name string `json:"name"` + Url string `json:"url"` + Handle string `json:"handle"` } type Link struct { From 99d27a89c207101245392dad77a31d6a59137f3b Mon Sep 17 00:00:00 2001 From: Mykola <3277207+kolya182@users.noreply.github.com> Date: Wed, 29 Jan 2020 13:30:16 -0800 Subject: [PATCH 049/506] Remove SEMUX (#774) --- README.md | 1 - coin/coins.go | 16 +--------------- coin/coins.yml | 7 ------- config.yml | 4 ---- pkg/tests/functional/testdata/coin_fixtures.json | 3 --- 5 files changed, 1 insertion(+), 30 deletions(-) diff --git a/README.md b/README.md index eb02dc273..cde1b68c0 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,6 @@ The observer API watches the chain for new transactions and generates notificati - diff --git a/coin/coins.go b/coin/coins.go index afb3bd298..ba8a4869c 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2019-12-27 15:07:32.262554 +0800 CST m=+0.002000255 +// 2020-01-29 11:37:10.990661 -0800 PST m=+0.055502727 // using data from coins.yml package coin @@ -53,7 +53,6 @@ const ( GO = 6060 WAN = 5718350 WAVES = 5741564 - SEM = 7562605 BTC = 0 LTC = 2 DOGE = 3 @@ -355,16 +354,6 @@ var Coins = map[uint]Coin{ MinConfirmations: 1, SampleAddr: "3P7wz6TXienpw3BHe8eHUEuZWb6WE58kgnQ", }, - SEM: { - ID: 7562605, - Handle: "semux", - Symbol: "SEM", - Name: "Semux", - Decimals: 9, - BlockTime: 0, - MinConfirmations: 0, - SampleAddr: "0x8197987c401a3466ad678b2080b24838ebd95b41", - }, BTC: { ID: 0, Handle: "bitcoin", @@ -630,9 +619,6 @@ func Wanchain() Coin { func Waves() Coin { return Coins[WAVES] } -func Semux() Coin { - return Coins[SEM] -} func Bitcoin() Coin { return Coins[BTC] } diff --git a/coin/coins.yml b/coin/coins.yml index cd5e96630..7d965abeb 100644 --- a/coin/coins.yml +++ b/coin/coins.yml @@ -220,13 +220,6 @@ minConfirmations: 1 sampleAddress: '3P7wz6TXienpw3BHe8eHUEuZWb6WE58kgnQ' -- id: 7562605 - symbol: SEM - handle: semux - name: Semux - decimals: 9 - sampleAddress: '0x8197987c401a3466ad678b2080b24838ebd95b41' - - id: 0 symbol: BTC handle: bitcoin diff --git a/config.yml b/config.yml index 453d3b39f..e3f6a4c66 100644 --- a/config.yml +++ b/config.yml @@ -142,10 +142,6 @@ theta: cosmos: api: http://stargate.cosmos.network -# [SEMUX] SEMUX: https://semux.org/ -semux: - api: https://sempy.online/api - # [ONTOLOGY] ONT: https://ont.io/ ontology: api: https://explorer.ont.io/api/v1/explorer diff --git a/pkg/tests/functional/testdata/coin_fixtures.json b/pkg/tests/functional/testdata/coin_fixtures.json index 92df2e1c4..906a63465 100644 --- a/pkg/tests/functional/testdata/coin_fixtures.json +++ b/pkg/tests/functional/testdata/coin_fixtures.json @@ -131,9 +131,6 @@ "stellar": { "address": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" }, - "semux": { - "address": "0x8197987c401a3466ad678b2080b24838ebd95b41" - }, "nimiq": { "address": "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07" }, From 1db39190ea09884be498320aafb01baf1c990920 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 29 Jan 2020 23:37:20 -0300 Subject: [PATCH 050/506] fix zilliqa nonce (#777) --- platform/zilliqa/model.go | 12 ++++++------ platform/zilliqa/model_test.go | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/platform/zilliqa/model.go b/platform/zilliqa/model.go index 68fdae0a1..f4ab3a1e9 100644 --- a/platform/zilliqa/model.go +++ b/platform/zilliqa/model.go @@ -20,14 +20,14 @@ type Tx struct { } func (tx Tx) NonceValue() uint64 { - n, ok := tx.Nonce.(string) - if ok { + switch n := tx.Nonce.(type) { + case string: r, _ := strconv.Atoi(n) return uint64(r) - } - nu, ok := tx.Nonce.(int) - if ok { - return uint64(nu) + case int: + return uint64(n) + case float64: + return uint64(n) } return 0 } diff --git a/platform/zilliqa/model_test.go b/platform/zilliqa/model_test.go index 7da4f5b26..117819761 100644 --- a/platform/zilliqa/model_test.go +++ b/platform/zilliqa/model_test.go @@ -47,3 +47,26 @@ func TestTxRPC_toTx(t *testing.T) { t.Errorf("TxRPC.toTx() = %v, want %v", got, tx) } } + +func TestTx_NonceValue(t *testing.T) { + tests := []struct { + name string + nonce interface{} + want uint64 + }{ + {"test int", 0, 0}, + {"test float", 3.4, 3}, + {"test string", "33", 33}, + {"test error string", "test", 0}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tx := Tx{ + Nonce: tt.nonce, + } + if got := tx.NonceValue(); got != tt.want { + t.Errorf("NonceValue() = %v, want %v", got, tt.want) + } + }) + } +} From 85804ec14ad9fca17c8834a9a0b8cff235429f98 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 30 Jan 2020 02:40:37 -0300 Subject: [PATCH 051/506] fix polkadot crash (#775) * fix polkadot crash * remove others tx type --- platform/polkadot/api.go | 23 ++++++++++++++++++++--- platform/polkadot/api_test.go | 34 ++++++++++++++++++++++++++++++++++ platform/polkadot/client.go | 8 ++++---- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/platform/polkadot/api.go b/platform/polkadot/api.go index 3233ba0f0..4de110ce4 100644 --- a/platform/polkadot/api.go +++ b/platform/polkadot/api.go @@ -125,14 +125,31 @@ func (p *Platform) NormalizeExtrinsic(srcTx *Extrinsic) *blockatlas.Tx { Sequence: srcTx.Nonce, } + if len(datas) < 2 { + return nil + } + + value := "0" + to := "" + for _, data := range datas { + vf, ok := data.Value.(float64) + if ok { + value = fmt.Sprintf("%.0f", vf) + continue + } + toAddr := p.NormalizeAddress(data.ValueRaw) + if len(toAddr) > 0 { + to = toAddr + } + } decimals := p.Coin().Decimals if srcTx.CallModule == ModuleBalances && srcTx.CallModuleFunction == ModuleFunctionTransfer { result.From = srcTx.AccountId - result.To = p.NormalizeAddress(datas[0].ValueRaw) + result.To = to result.Fee = blockatlas.Amount(FeeTransfer) result.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(fmt.Sprintf("%.0f", datas[1].Value.(float64))), + Value: blockatlas.Amount(value), Symbol: p.Coin().Symbol, Decimals: decimals, } @@ -148,7 +165,7 @@ func (p *Platform) NormalizeAddress(valueRaw string) string { if err != nil { return "" } - if network, ok := NetworkByteMap[p.Coin().Symbol]; ok { + if network, ok := NetworkByteMap[p.Coin().Symbol]; ok && len(bytes) > 0 { return PublicKeyToAddress(bytes[1:], network) } return "" diff --git a/platform/polkadot/api_test.go b/platform/polkadot/api_test.go index a167c64dd..5f0930a2f 100644 --- a/platform/polkadot/api_test.go +++ b/platform/polkadot/api_test.go @@ -146,6 +146,40 @@ func TestNormalizeExtrinsic(t *testing.T) { }, wantTx: nil, }, + { + name: "Error Params", + args: args{ + srcTx: &Extrinsic{ + Timestamp: 1577712822, + BlockNumber: 447444, + CallModuleFunction: "set", + CallModule: "timestamp", + Params: "[{\"name\":\"now\",\"type\":\"Compact\\u003cMoment\\u003e\",\"value\":1580348178,\"valueRaw\":\"0b507e17f46f01\"}]", + AccountId: "b44024b9ac73ae8e2f6f6f72b5021a41963b2bc06f67181a040c40bcafb4127b", + Nonce: 1, + Hash: "0xeaaa9ca1a93854be0d3cccc7d7a36272e5663a40a296ab9b0451e0d43ee376ce", + Success: true, + }, + }, + wantTx: nil, + }, + { + name: "set_heads", + args: args{ + srcTx: &Extrinsic{ + Timestamp: 1577712822, + BlockNumber: 447444, + CallModuleFunction: "set_heads", + CallModule: "parachains", + Params: "[{\"name\":\"heads\",\"type\":\"Vec\\u003cAttestedCandidate\\u003e\",\"value\":[],\"valueRaw\":\"\"}]", + AccountId: "b44024b9ac73ae8e2f6f6f72b5021a41963b2bc06f67181a040c40bcafb4127b", + Nonce: 1, + Hash: "0xeaaa9ca1a93854be0d3cccc7d7a36272e5663a40a296ab9b0451e0d43ee376ce", + Success: true, + }, + }, + wantTx: nil, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/platform/polkadot/client.go b/platform/polkadot/client.go index 1b5706f20..125f1c914 100644 --- a/platform/polkadot/client.go +++ b/platform/polkadot/client.go @@ -12,7 +12,7 @@ type Client struct { func (c *Client) GetTransfersOfAddress(address string) ([]Transfer, error) { var res SubscanResponse - err := c.Post(&res, "/scan/transfers", TransfersRequest{Address: address, Row: blockatlas.TxPerPage}) + err := c.Post(&res, "scan/transfers", TransfersRequest{Address: address, Row: blockatlas.TxPerPage}) if err != nil { return nil, err } @@ -21,7 +21,7 @@ func (c *Client) GetTransfersOfAddress(address string) ([]Transfer, error) { func (c *Client) GetExtrinsicsOfAddress(address string) ([]Extrinsic, error) { var res SubscanResponse - err := c.Post(&res, "/scan/extrinsics", TransfersRequest{Address: address, Row: blockatlas.TxPerPage}) + err := c.Post(&res, "scan/extrinsics", TransfersRequest{Address: address, Row: blockatlas.TxPerPage}) if err != nil { return nil, err } @@ -30,7 +30,7 @@ func (c *Client) GetExtrinsicsOfAddress(address string) ([]Extrinsic, error) { func (c *Client) GetCurrentBlock() (int64, error) { var res SubscanResponse - err := c.Post(&res, "/scan/metadata", nil) + err := c.Post(&res, "scan/metadata", nil) if err != nil { return 0, err } @@ -43,7 +43,7 @@ func (c *Client) GetCurrentBlock() (int64, error) { func (c *Client) GetBlockByNumber(number int64) ([]Extrinsic, error) { var res SubscanResponse - err := c.Post(&res, "/scan/block", BlockRequest{BlockNumber: number}) + err := c.Post(&res, "scan/block", BlockRequest{BlockNumber: number}) if err != nil { return nil, err } From d8c81d7fde6c1669f44ffb9f49999312a8ba9aae Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Thu, 30 Jan 2020 08:50:58 +0300 Subject: [PATCH 052/506] Refactor the architecture (STEP 1) (#770) --- Dockerfile | 12 +- Makefile | 46 +- Procfile | 6 +- README.md | 23 +- api/maketdata.go | 6 +- azure-pipelines.yml | 2 +- cmd/api.go | 79 ---- cmd/api/main.go | 121 +++++ cmd/{observer.go => observer/main.go} | 52 ++- cmd/root.go | 60 --- cmd/sync.go | 29 -- cmd/syncmarkets/main.go | 47 ++ config.yml | 12 +- docker-compose.yml | 26 +- docs/docs.go | 2 +- go.mod | 66 +-- go.sum | 425 +++++------------- k8s/deployment.yml | 30 -- k8s/ingress.yml | 28 -- main.go | 9 - pkg/tests/functional/functional_test.go | 79 +++- platform/registry.go | 3 +- {marketdata => syncmarkets}/chart/chart.go | 0 .../chart/cmc}/cmc.go | 6 +- .../chart/cmc}/cmc_test.go | 4 +- .../chart/coingecko/coingecko.go | 4 +- .../chart/coingecko/coingecko_test.go | 2 +- {marketdata => syncmarkets}/chart/provider.go | 0 {marketdata => syncmarkets}/charts.go | 8 +- {marketdata => syncmarkets}/charts_test.go | 2 +- .../clients/cmc/cache.go | 0 .../clients/cmc/cache_test.go | 0 .../clients/cmc/client.go | 0 .../clients/cmc/models.go | 0 .../clients/cmc/webclient.go | 0 .../clients/cmc/widgetclient.go | 0 .../clients/coingecko/cache.go | 0 .../clients/coingecko/cache_test.go | 0 .../clients/coingecko/client.go | 0 .../clients/coingecko/client_test.go | 0 .../clients/coingecko/models.go | 0 .../clients/compound/client.go | 0 .../clients/compound/models.go | 0 {marketdata => syncmarkets}/market.go | 12 +- .../market/cmc}/cmc.go | 4 +- .../market/cmc}/cmc_test.go | 2 +- .../market/coingecko/coingecko.go | 4 +- .../market/coingecko/coingecko_test.go | 2 +- .../market/compound/compound.go | 4 +- .../market/compound/compound_test.go | 2 +- {marketdata => syncmarkets}/market/dex/dex.go | 2 +- .../market/dex/dex_test.go | 0 .../market/dex/models.go | 0 {marketdata => syncmarkets}/market/market.go | 0 .../market/provider.go | 0 .../rate/cmc}/cmc.go | 4 +- .../rate/cmc}/cmc_test.go | 2 +- .../rate/coingecko/coingecko.go | 4 +- .../rate/coingecko/coingecko_test.go | 2 +- .../rate/compound/compound.go | 4 +- .../rate/compound/compound_test.go | 2 +- .../rate/fixer/fixer.go | 2 +- .../rate/fixer/fixer_test.go | 0 .../rate/fixer/models.go | 0 {marketdata => syncmarkets}/rate/provider.go | 0 {marketdata => syncmarkets}/rate/rate.go | 0 {marketdata => syncmarkets}/rates.go | 12 +- {marketdata => syncmarkets}/worker.go | 6 +- 68 files changed, 538 insertions(+), 721 deletions(-) delete mode 100644 cmd/api.go create mode 100644 cmd/api/main.go rename cmd/{observer.go => observer/main.go} (71%) delete mode 100644 cmd/root.go delete mode 100755 cmd/sync.go create mode 100644 cmd/syncmarkets/main.go delete mode 100644 k8s/deployment.yml delete mode 100644 k8s/ingress.yml delete mode 100644 main.go rename {marketdata => syncmarkets}/chart/chart.go (100%) rename {marketdata/chart/coinmarketcap => syncmarkets/chart/cmc}/cmc.go (95%) rename {marketdata/chart/coinmarketcap => syncmarkets/chart/cmc}/cmc_test.go (98%) rename {marketdata => syncmarkets}/chart/coingecko/coingecko.go (95%) rename {marketdata => syncmarkets}/chart/coingecko/coingecko_test.go (96%) rename {marketdata => syncmarkets}/chart/provider.go (100%) rename {marketdata => syncmarkets}/charts.go (91%) rename {marketdata => syncmarkets}/charts_test.go (99%) rename {marketdata => syncmarkets}/clients/cmc/cache.go (100%) rename {marketdata => syncmarkets}/clients/cmc/cache_test.go (100%) rename {marketdata => syncmarkets}/clients/cmc/client.go (100%) rename {marketdata => syncmarkets}/clients/cmc/models.go (100%) rename {marketdata => syncmarkets}/clients/cmc/webclient.go (100%) rename {marketdata => syncmarkets}/clients/cmc/widgetclient.go (100%) rename {marketdata => syncmarkets}/clients/coingecko/cache.go (100%) rename {marketdata => syncmarkets}/clients/coingecko/cache_test.go (100%) rename {marketdata => syncmarkets}/clients/coingecko/client.go (100%) rename {marketdata => syncmarkets}/clients/coingecko/client_test.go (100%) rename {marketdata => syncmarkets}/clients/coingecko/models.go (100%) rename {marketdata => syncmarkets}/clients/compound/client.go (100%) rename {marketdata => syncmarkets}/clients/compound/models.go (100%) rename {marketdata => syncmarkets}/market.go (82%) rename {marketdata/market/coinmarketcap => syncmarkets/market/cmc}/cmc.go (95%) rename {marketdata/market/coinmarketcap => syncmarkets/market/cmc}/cmc_test.go (98%) rename {marketdata => syncmarkets}/market/coingecko/coingecko.go (94%) rename {marketdata => syncmarkets}/market/coingecko/coingecko_test.go (97%) rename {marketdata => syncmarkets}/market/compound/compound.go (91%) rename {marketdata => syncmarkets}/market/compound/compound_test.go (96%) rename {marketdata => syncmarkets}/market/dex/dex.go (97%) rename {marketdata => syncmarkets}/market/dex/dex_test.go (100%) rename {marketdata => syncmarkets}/market/dex/models.go (100%) rename {marketdata => syncmarkets}/market/market.go (100%) rename {marketdata => syncmarkets}/market/provider.go (100%) rename {marketdata/rate/coinmarketcap => syncmarkets/rate/cmc}/cmc.go (90%) rename {marketdata/rate/coinmarketcap => syncmarkets/rate/cmc}/cmc_test.go (97%) rename {marketdata => syncmarkets}/rate/coingecko/coingecko.go (89%) rename {marketdata => syncmarkets}/rate/coingecko/coingecko_test.go (96%) rename {marketdata => syncmarkets}/rate/compound/compound.go (88%) rename {marketdata => syncmarkets}/rate/compound/compound_test.go (96%) rename {marketdata => syncmarkets}/rate/fixer/fixer.go (94%) rename {marketdata => syncmarkets}/rate/fixer/fixer_test.go (100%) rename {marketdata => syncmarkets}/rate/fixer/models.go (100%) rename {marketdata => syncmarkets}/rate/provider.go (100%) rename {marketdata => syncmarkets}/rate/rate.go (100%) rename {marketdata => syncmarkets}/rates.go (81%) rename {marketdata => syncmarkets}/worker.go (92%) diff --git a/Dockerfile b/Dockerfile index 1d6b654ed..971d3931c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,16 @@ FROM golang:latest AS builder +ARG SERVICE + RUN mkdir /build ADD . /build WORKDIR /build -RUN go build -o bin/blockatlas . +RUN go build -o bin/blockatlas ./cmd/$SERVICE FROM debian:latest -COPY --from=builder /build/bin /app -COPY --from=builder /build/config.yml /app +COPY --from=builder /build/bin /app/bin/$SERVICE +COPY --from=builder /build/config.yml / COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -WORKDIR /app +WORKDIR /app/bin/$SERVICE -ENTRYPOINT ["/app/blockatlas"] \ No newline at end of file +ENTRYPOINT ["/app/bin/blockatlas"] diff --git a/Makefile b/Makefile index 9a6f840ce..87816c69f 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ VERSION := $(shell git describe --tags) BUILD := $(shell git rev-parse --short HEAD) PROJECT_NAME := $(shell basename "$(PWD)") -API_COMMAND := api -OBSERVER_COMMAND := observer -SYNC_COMMAND := sync-markets +API_SERVICE := api +OBSERVER_SERVICE := observer +SYNC_SERVICE := syncmarkets COIN_FILE := coin/coins.yml COIN_GO_FILE := coin/coins.go GEN_COIN_FILE := coin/gen.go @@ -27,9 +27,9 @@ LDFLAGS=-ldflags "-X=main.Version=$(VERSION) -X=main.Build=$(BUILD)" STDERR := /tmp/.$(PROJECT_NAME)-stderr.txt # PID file will keep the process id of the server -PID_API := /tmp/.$(PROJECT_NAME).$(API_COMMAND).pid -PID_OBSERVER := /tmp/.$(PROJECT_NAME).$(OBSERVER_COMMAND).pid -PID_SYNC := /tmp/.$(PROJECT_NAME).$(SYNC_COMMAND).pid +PID_API := /tmp/.$(PROJECT_NAME).$(API_SERVICE).pid +PID_OBSERVER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SERVICE).pid +PID_SYNC := /tmp/.$(PROJECT_NAME).$(SYNC_SERVICE).pid # Make is verbose in Linux. Make it silent. MAKEFLAGS += --silent @@ -39,41 +39,38 @@ install: go-get ## start: Start API, Observer and Sync in development mode. start: - @bash -c "$(MAKE) clean compile start-api start-observer start-sync" - -## stop: Stop development mode. -stop: stop-server + @bash -c "$(MAKE) clean compile start-api start-observer start-syncmarkets" ## start-api: Start API in development mode. -start-api: stop-server +start-api: stop @echo " > Starting $(PROJECT_NAME) API" - @-$(GOBIN)/$(PROJECT_NAME) $(API_COMMAND) 2>&1 & echo $$! > $(PID_API) + @-$(GOBIN)/$(API_SERVICE)/api -c config.yml 2>&1 & echo $$! > $(PID_API) @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" @echo " > Error log: $(STDERR)" ## start-observer: Start Observer in development mode. -start-observer: stop-server +start-observer: stop @echo " > Starting $(PROJECT_NAME) Observer" - @-$(GOBIN)/$(PROJECT_NAME) $(OBSERVER_COMMAND) 2>&1 & echo $$! > $(PID_OBSERVER) + @-$(GOBIN)/$(OBSERVER_SERVICE)/observer -c config.yml 2>&1 & echo $$! > $(PID_OBSERVER) @cat $(PID_OBSERVER) | sed "/^/s/^/ \> Observer PID: /" @echo " > Error log: $(STDERR)" ## start-sync-markets: Start Sync markets in development mode. -start-sync-markets: stop-server +start-syncmarkets: stop @echo " > Starting $(PROJECT_NAME) Sync" - @-$(GOBIN)/$(PROJECT_NAME) $(SYNC_COMMAND) 2>&1 & echo $$! > $(PID_SYNC) + @-$(GOBIN)/$(SYNC_SERVICE)/syncmarkets -c config.yml 2>&1 & echo $$! > $(PID_SYNC) @cat $(PID_SYNC) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" -stop-server: +## stop: Stop development mode. +stop: @-touch $(PID_API) $(PID_OBSERVER) @-kill `cat $(PID_API)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER)` 2> /dev/null || true + @-kill `cat $(PID_SYNC)` 2> /dev/null || true @-rm $(PID_API) $(PID_OBSERVER) -restart-server: stop-server start-server -## compile: Compile the binary. compile: @-touch $(STDERR) @-rm $(STDERR) @@ -121,8 +118,12 @@ golint: go-lint go-compile: go-get go-build go-build: - @echo " > Building binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(PROJECT_NAME) -v . + @echo " > Building api binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API_SERVICE)/api ./cmd/$(API_SERVICE) + @echo " > Building syncmarkets binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SYNC_SERVICE)/syncmarkets ./cmd/$(SYNC_SERVICE) + @echo " > Building observer binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SERVICE)/observer ./cmd/$(OBSERVER_SERVICE) go-generate: @echo " > Generating dependency files..." @@ -130,7 +131,8 @@ go-generate: go-get: @echo " > Checking if there is any missing dependencies..." - GOBIN=$(GOBIN) go get $(get) + GOBIN=$(GOBIN) go get cmd/... $(get) + go-install: GOBIN=$(GOBIN) go install $(GOPKG) diff --git a/Procfile b/Procfile index 9d96f6d4c..53c120be9 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,3 @@ -web: bin/blockatlas api :$PORT -observer: bin/blockatlas observer -market: bin/blockatlas sync-markets +web: bin/api -p $PORT +observer: bin/observer +market: bin/syncmarkets diff --git a/README.md b/README.md index cde1b68c0..9b81fa65e 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ The observer API watches the chain for new transactions and generates notificati ### Requirements * [Go Toolchain](https://golang.org/doc/install) versions 1.13+ - * [Redis](https://redis.io/topics/quickstart) instance (Transaction Observer only) + * [Redis](https://redis.io/topics/quickstart) instance (observer and syncmarkets) ### From Source @@ -53,14 +53,14 @@ The observer API watches the chain for new transactions and generates notificati go get -u github.com/trustwallet/blockatlas cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas -# Start API server at port 8420 -go build -o blockatlas . && ./blockatlas api :8420 +# Start Observer with the path to the config.yml ./ +go build -o observer-bin cmd/observer/main.go && ./observer-bin -c config.yml -# Start Observer -go build -o blockatlas . && ./blockatlas observer +# Start API server at port 8422 with the path to the config.yml ./ +go build -o api-bin cmd/api/main.go && ./api-bin -p 8422 -c config.yml -# Start sync worker for market prices and rates -go build -o blockatlas . && ./blockatlas sync-markets +# Start sync worker for market prices and rates with the path to the config.yml ./ +go build -o syncmarkets-bin cmd/syncmarkets/main.go && ./syncmarkets-bin -c config.yml ``` ### Docker @@ -76,13 +76,12 @@ You should change `config.yml`: ```yaml redis: redis://redis:6379 ``` - -Then build as `blockatlas` image: +Then build: ```shell -docker build -t blockatlas . +docker-compose build ``` -For run api, observer and sync-markets: +For run api, observer and syncmarkets: ```shell docker-compose up ``` @@ -91,7 +90,7 @@ If you need to start one service: ```shell docker-compose start api redis docker-compose start observer redis -docker-compose start sync-markets redis +docker-compose start syncmarkets redis ``` ### Heroku diff --git a/api/maketdata.go b/api/maketdata.go index ac2af13de..d52c0b5bb 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -4,12 +4,12 @@ import ( "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/marketdata" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" "github.com/trustwallet/blockatlas/storage" + "github.com/trustwallet/blockatlas/syncmarkets" "net/http" "strconv" "strings" @@ -140,7 +140,7 @@ func getTickersHandler(storage storage.Market) func(c *gin.Context) { // @Success 200 {object} blockatlas.ChartData // @Router /v1/market/charts [get] func getChartsHandler() func(c *gin.Context) { - var charts = marketdata.InitCharts() + var charts = syncmarkets.InitCharts() return func(c *gin.Context) { coinQuery := c.Query("coin") coinId, err := strconv.Atoi(coinQuery) @@ -184,7 +184,7 @@ func getChartsHandler() func(c *gin.Context) { // @Success 200 {object} blockatlas.ChartCoinInfo // @Router /v1/market/info [get] func getCoinInfoHandler() func(c *gin.Context) { - var charts = marketdata.InitCharts() + var charts = syncmarkets.InitCharts() return func(c *gin.Context) { coinQuery := c.Query("coin") coinId, err := strconv.Atoi(coinQuery) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 006c54a37..a90c08f8b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -70,7 +70,7 @@ jobs: workingDirectory: '$(modulePath)' displayName: 'Run integration tests' - - script: go build -v . + - script: make go-build workingDirectory: '$(modulePath)' displayName: 'Build' condition: not(startsWith(variables['build.sourceBranch'], 'refs/tags/')) diff --git a/cmd/api.go b/cmd/api.go deleted file mode 100644 index f7c487dd8..000000000 --- a/cmd/api.go +++ /dev/null @@ -1,79 +0,0 @@ -package cmd - -import ( - "github.com/getsentry/sentry-go/gin" - "github.com/gin-gonic/gin" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/swaggo/files" - "github.com/swaggo/gin-swagger" - "github.com/trustwallet/blockatlas/api" - _ "github.com/trustwallet/blockatlas/docs" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/pkg/logger" -) - -var apiCmd = &cobra.Command{ - Use: "api ", - Short: "API server", - Args: cobra.MaximumNArgs(1), - Run: runApi, -} - -func runApi(_ *cobra.Command, args []string) { - var bind string - if len(args) == 0 { - bind = ":8420" - } else { - bind = args[0] - } - RunApi(bind, nil) -} - -func RunApi(bind string, c chan *gin.Engine) { - gin.SetMode(viper.GetString("gin.mode")) - engine := gin.Default() - - sg := sentrygin.New(sentrygin.Options{}) - engine.Use(ginutils.CheckReverseProxy, sg) - - engine.Use(ginutils.CORSMiddleware()) - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) - - engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - - engine.GET("/", api.GetRoot) - engine.GET("/status", func(c *gin.Context) { - ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, - }) - }) - - api.MakeMetricsRoute(engine) - api.LoadPlatforms(engine) - - if viper.GetBool("observer.enabled") { - logger.Info("Loading observer API") - observerAPI := engine.Group("/observer/v1") - api.SetupObserverAPI(observerAPI, cache) - } - - if viper.GetBool("market.enabled") { - logger.Info("Loading market API") - marketAPI := engine.Group("/v1/market") - api.SetupMarketAPI(marketAPI, cache) - } - - if c != nil { - c <- engine - } - - logger.Info("Running application", logger.Params{"bind": bind}) - if err := engine.Run(bind); err != nil { - logger.Fatal("Application failed", err) - } -} - -func init() { - rootCmd.AddCommand(apiCmd) -} diff --git a/cmd/api/main.go b/cmd/api/main.go new file mode 100644 index 000000000..12777553b --- /dev/null +++ b/cmd/api/main.go @@ -0,0 +1,121 @@ +package main + +import ( + "context" + "flag" + "github.com/getsentry/sentry-go/gin" + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "github.com/swaggo/gin-swagger" + "github.com/swaggo/gin-swagger/swaggerFiles" + "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/config" + _ "github.com/trustwallet/blockatlas/docs" + "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/storage" + "net/http" + "os" + "os/signal" + "path/filepath" + "syscall" + "time" +) + +const ( + defaultPort = "8420" + defaultConfigPath = "../../config.yml" +) + +var ( + port, confPath string + cache *storage.Storage + sg gin.HandlerFunc +) + +func init() { + sg = sentrygin.New(sentrygin.Options{}) + cache = storage.New() + + flag.StringVar(&port, "p", defaultPort, "port for api") + flag.StringVar(&confPath, "c", defaultConfigPath, "config file for api") + + flag.Parse() + + confPath, err := filepath.Abs(confPath) + if err != nil { + logger.Fatal(err) + } + + config.LoadConfig(confPath) + logger.InitLogger() + platform.Init() +} + +func main() { + gin.SetMode(viper.GetString("gin.mode")) + engine := gin.New() + + engine.Use(gin.Recovery()) + engine.Use(ginutils.CheckReverseProxy, sg) + engine.Use(ginutils.CORSMiddleware()) + + engine.OPTIONS("/*path", ginutils.CORSMiddleware()) + + engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + engine.GET("/", api.GetRoot) + engine.GET("/status", func(c *gin.Context) { + ginutils.RenderSuccess(c, map[string]interface{}{ + "status": true, + }) + }) + + api.MakeMetricsRoute(engine) + api.LoadPlatforms(engine) + + if viper.GetBool("observer.enabled") { + logger.Info("Loading observer API") + observerAPI := engine.Group("/observer/v1") + api.SetupObserverAPI(observerAPI, cache) + } + if viper.GetBool("market.enabled") { + logger.Info("Loading market API") + marketAPI := engine.Group("/v1/market") + api.SetupMarketAPI(marketAPI, cache) + } + + signalForExit := make(chan os.Signal, 1) + + signal.Notify(signalForExit, + syscall.SIGHUP, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT) + + srv := &http.Server{ + Addr: ":" + port, + Handler: engine, + } + + go func() { + if err := srv.ListenAndServe(); err != nil { + logger.Fatal("Application failed", err) + } + }() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + defer func() { + if err := srv.Shutdown(ctx); err != nil { + logger.Fatal("Server Shutdown: ", err) + } + }() + + logger.Info("Running application", logger.Params{"bind": port}) + + stop := <-signalForExit + logger.Info("Stop signal Received", stop) + logger.Info("Waiting for all jobs to stop") +} diff --git a/cmd/observer.go b/cmd/observer/main.go similarity index 71% rename from cmd/observer.go rename to cmd/observer/main.go index 7874d1ca3..2680373b4 100644 --- a/cmd/observer.go +++ b/cmd/observer/main.go @@ -1,28 +1,51 @@ -package cmd +package main import ( "context" - "github.com/spf13/cobra" + "flag" "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/observer" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/storage" + "path/filepath" "sync" "time" ) -var observerCmd = &cobra.Command{ - Use: "observer", - Short: "Observer worker", - Args: cobra.NoArgs, - Run: runObserver, -} +const ( + defaultConfigPath = "../../config.yml" +) -func runObserver(_ *cobra.Command, _ []string) { - if !viper.GetBool("observer.enabled") { - logger.Fatal("Observer is not enabled") +var ( + confPath string + cache *storage.Storage +) + +func init() { + cache = storage.New() + + flag.StringVar(&confPath, "c", defaultConfigPath, "config file for observer") + flag.Parse() + + confPath, err := filepath.Abs(confPath) + if err != nil { + logger.Fatal(err) } + config.LoadConfig(confPath) + logger.InitLogger() + platform.Init() + + host := viper.GetString("storage.redis") + err = cache.Init(host) + if err != nil { + logger.Fatal(err) + } +} + +func main() { if len(platform.BlockAPIs) == 0 { logger.Fatal("No APIs to observe") } @@ -32,10 +55,12 @@ func runObserver(_ *cobra.Command, _ []string) { var wg sync.WaitGroup wg.Add(len(platform.BlockAPIs)) + for _, api := range platform.BlockAPIs { coin := api.Coin() blockTime := time.Duration(coin.BlockTime) * time.Millisecond pollInterval := blockTime / 4 + if pollInterval < minInterval { pollInterval = minInterval } @@ -48,6 +73,7 @@ func runObserver(_ *cobra.Command, _ []string) { } else { backlogCount = int(backlogTime / blockTime) } + stream := observer.Stream{ BlockAPI: api, Tracker: cache, @@ -81,7 +107,3 @@ func runObserver(_ *cobra.Command, _ []string) { logger.Info("Exiting cleanly") } - -func init() { - rootCmd.AddCommand(observerCmd) -} diff --git a/cmd/root.go b/cmd/root.go deleted file mode 100644 index 64aba9420..000000000 --- a/cmd/root.go +++ /dev/null @@ -1,60 +0,0 @@ -package cmd - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/storage" - "os" - "os/signal" - "syscall" -) - -var ( - cache = storage.New() - rootCmd = cobra.Command{ - Use: "blockatlas", - Short: "BlockAtlas by Trust Wallet", - PersistentPreRun: func(cmd *cobra.Command, args []string) { - // Load config - confPath, _ := cmd.Flags().GetString("config") - config.LoadConfig(confPath) - - // Init Logger - logger.InitLogger() - - // Load app components - platform.Init() - - // Init Storage - host := viper.GetString("storage.redis") - err := cache.Init(host) - if err != nil { - logger.Fatal(err) - } - }, - } -) - -func init() { - rootCmd.PersistentFlags().StringP("config", "c", "", "Config file (optional)") -} - -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) - go func() { - sig := <-c - logger.Info("Got a signal. Aborting...", logger.Params{"code": sig}) - os.Exit(1) - }() - - if err := rootCmd.Execute(); err != nil { - logger.Error(err) - os.Exit(1) - } -} diff --git a/cmd/sync.go b/cmd/sync.go deleted file mode 100755 index 3235e991e..000000000 --- a/cmd/sync.go +++ /dev/null @@ -1,29 +0,0 @@ -package cmd - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/marketdata" - "github.com/trustwallet/blockatlas/pkg/logger" -) - -var syncCmd = &cobra.Command{ - Use: "sync-markets", - Short: "Sync all markets prices and rates", - Args: cobra.NoArgs, - Run: syncMarketData, -} - -func syncMarketData(cmd *cobra.Command, args []string) { - if !viper.GetBool("market.enabled") { - logger.Fatal("Market is not enabled") - } - - marketdata.InitRates(cache) - marketdata.InitMarkets(cache) - <-make(chan bool) -} - -func init() { - rootCmd.AddCommand(syncCmd) -} diff --git a/cmd/syncmarkets/main.go b/cmd/syncmarkets/main.go new file mode 100644 index 000000000..8c36941c3 --- /dev/null +++ b/cmd/syncmarkets/main.go @@ -0,0 +1,47 @@ +package main + +import ( + "flag" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/storage" + "github.com/trustwallet/blockatlas/syncmarkets" + "path/filepath" +) + +const ( + defaultConfigPath = "../../config.yml" +) + +var ( + confPath string + cache *storage.Storage +) + +func init() { + cache = storage.New() + + flag.StringVar(&confPath, "c", defaultConfigPath, "config file for observer") + flag.Parse() + + confPath, err := filepath.Abs(confPath) + if err != nil { + logger.Fatal(err) + } + + config.LoadConfig(confPath) + logger.InitLogger() + + host := viper.GetString("storage.redis") + err = cache.Init(host) + if err != nil { + logger.Fatal(err) + } +} + +func main() { + syncmarkets.InitRates(cache) + syncmarkets.InitMarkets(cache) + <-make(chan struct{}) +} diff --git a/config.yml b/config.yml index e3f6a4c66..caa0a88e6 100644 --- a/config.yml +++ b/config.yml @@ -136,11 +136,11 @@ vechain: # [THETA] THETA: https://www.thetatoken.org/ theta: - api: https://explorer.thetatoken.org:9000/api + api: https://explorer.thetatoken.org:9000/api # [ATOM] Cosmos: https://cosmos.network/ cosmos: - api: http://stargate.cosmos.network + api: http://stargate.cosmos.network # [ONTOLOGY] ONT: https://ont.io/ ontology: @@ -148,18 +148,18 @@ ontology: # [ZIL] Zilliqa: https://zilliqa.com zilliqa: -# api: https://api.viewblock.io/v1/zilliqa -# key: YOUR_API_KEY + # api: https://api.viewblock.io/v1/zilliqa + # key: YOUR_API_KEY rpc: https://api.zilliqa.com lookup: https://unstoppabledomains.com/api/v1 #[IoTeX] IoTeX: https://iotex.io iotex: - api: https://pharos.iotex.io/v1 + api: https://pharos.iotex.io/v1 # [WAVES] Waves: http://wavesplatform.com waves: - api: https://nodes.wavesnodes.com + api: https://nodes.wavesnodes.com # [AE] Aeternity: https://aeternity.com aeternity: diff --git a/docker-compose.yml b/docker-compose.yml index 32d91bf8e..775604fae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,24 +2,30 @@ version: '3.7' services: api: container_name: api - image: blockatlas - command: api + build: + context: . + args: + - SERVICE=api ports: - - 8420:8420 + - 8420:8420 links: - redis observer: container_name: observer - image: blockatlas - command: observer + build: + context: . + args: + - SERVICE=observer links: - redis - sync-markets: - container_name: sync-markets - image: blockatlas - command: sync-markets + syncmarkets: + container_name: syncmarkets + build: + context: . + args: + - SERVICE=syncmarkets links: - redis @@ -27,4 +33,4 @@ services: container_name: redis image: neojt/mredis ports: - - 6379:6379 \ No newline at end of file + - 6379:6379 diff --git a/docs/docs.go b/docs/docs.go index b0fff90d4..0367c6cb8 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-01-21 15:34:39.376593 -0300 -03 m=+0.082727839 +// 2020-01-29 02:11:45.800246 +0300 MSK m=+0.142708046 package docs diff --git a/go.mod b/go.mod index 30695b6be..e6eb5cc98 100644 --- a/go.mod +++ b/go.mod @@ -1,66 +1,32 @@ module github.com/trustwallet/blockatlas -// +heroku goVersion go1.13 -go 1.13.3 +go 1.12 require ( github.com/Pantani/httpexpect v2.0.0+incompatible github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 - github.com/allegro/bigcache v1.2.1 // indirect - github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40 // indirect - github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d + github.com/btcsuite/btcutil v1.0.1 github.com/cenkalti/backoff v2.2.1+incompatible - github.com/cespare/xxhash/v2 v2.1.1 // indirect - github.com/chenjiandongx/ginprom v0.0.0-20191022035802-6f3da3c84986 + github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05 github.com/deckarep/golang-set v1.7.1 - github.com/elastic/gosigar v0.10.5 // indirect - github.com/ethereum/go-ethereum v1.9.2 - github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect - github.com/getsentry/sentry-go v0.3.1 - github.com/gin-gonic/gin v1.4.0 - github.com/go-openapi/jsonreference v0.19.3 // indirect - github.com/go-openapi/spec v0.19.4 // indirect + github.com/ethereum/go-ethereum v1.9.10 + github.com/getsentry/sentry-go v0.4.0 + github.com/gin-gonic/gin v1.5.0 github.com/go-redis/redis v6.15.6+incompatible - github.com/google/uuid v1.1.1 // indirect - github.com/hashicorp/golang-lru v0.5.3 // indirect github.com/hewigovens/go-coincodec v1.0.4 - github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/jinzhu/gorm v1.9.11 - github.com/json-iterator/go v1.1.8 // indirect - github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect - github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect - github.com/mailru/easyjson v0.7.0 // indirect - github.com/mattn/go-isatty v0.0.10 // indirect - github.com/mattn/go-runewidth v0.0.6 // indirect - github.com/minio/sha256-simd v0.1.1 // indirect - github.com/mr-tron/base58 v1.1.2 - github.com/multiformats/go-multihash v0.0.9 // indirect - github.com/olekukonko/tablewriter v0.0.2 // indirect + github.com/jinzhu/gorm v1.9.12 + github.com/mr-tron/base58 v1.1.3 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pelletier/go-toml v1.6.0 // indirect - github.com/prometheus/client_golang v1.2.1 - github.com/prometheus/procfs v0.0.7 // indirect - github.com/robfig/cron/v3 v3.0.0 - github.com/rs/cors v1.7.0 // indirect + github.com/prometheus/client_golang v1.4.0 + github.com/robfig/cron/v3 v3.0.1 github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 github.com/sirupsen/logrus v1.4.2 - github.com/spf13/afero v1.2.2 // indirect - github.com/spf13/cast v1.3.0 - github.com/spf13/cobra v0.0.5 - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.5.0 - github.com/status-im/keycard-go v0.0.0-20191114114615-9d48af884d5b // indirect + github.com/spf13/cast v1.3.1 + github.com/spf13/viper v1.6.2 github.com/stretchr/testify v1.4.0 - github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 github.com/swaggo/gin-swagger v1.2.0 - github.com/swaggo/swag v1.6.3 - github.com/ugorji/go v1.1.7 // indirect - github.com/wealdtech/go-ens/v3 v3.0.9 - github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b // indirect - golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f - golang.org/x/net v0.0.0-20191118183410-d06c31c94cae // indirect - golang.org/x/sys v0.0.0-20191118133127-cf1e2d577169 // indirect - golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98 // indirect - gopkg.in/yaml.v2 v2.2.5 + github.com/swaggo/swag v1.6.5 + github.com/wealdtech/go-ens/v3 v3.1.0 + golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d + gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index 522779a79..3527b6893 100644 --- a/go.sum +++ b/go.sum @@ -1,80 +1,74 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= -cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= -github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= -github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/Pantani/httpexpect v2.0.0+incompatible h1:P658jo0d3gej0D67KBcSUgpZY76CH1TdxvOfQAmyNu0= +github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Pantani/httpexpect v2.0.0+incompatible/go.mod h1:+8VdK+EZPV0YorWMMNyakEIYKcDl9OHtde3DdkPqbwQ= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VictoriaMetrics/fastcache v1.5.3 h1:2odJnXLbFZcoV9KYtQ+7TH1UOq3dn3AssMgieaezkR4= +github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/allegro/bigcache v1.2.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= -github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apilayer/freegeoip v3.5.0+incompatible h1:z1u2gv0/rsSi/HqMDB436AiUROXXim7st5DOg4Ikl4A= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/apilayer/freegeoip v3.5.0+incompatible/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU= -github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= -github.com/aristanetworks/glog v0.0.0-20180419172825-c15b03b3054f/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5 h1:L0TwgZQo7Mga9im6FvKEZGIvyLE/VG/HI5loz5LpvC0= github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= -github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40 h1:ZdRuixFqR3mfx4FHzclG3COrRgWrYq0VhNgIoYoObcM= -github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40/go.mod h1:Z4RTxGAuYhPzcq8+EdRM+R8M48Ssle2TsWtwRKa+vns= -github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= github.com/btcsuite/btcd v0.0.0-20190418232430-6867ff32788a/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= -github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.1/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenjiandongx/ginprom v0.0.0-20191022035802-6f3da3c84986 h1:6r9/zDxh+oMzqLWol3ByjfoZN85AaCTnXNvEfvc316U= -github.com/chenjiandongx/ginprom v0.0.0-20191022035802-6f3da3c84986/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= +github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -82,200 +76,153 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c h1:4e6Zsb6LFd3kadoMiut2zcd3hCb4zywpJnQa8+NV2Cs= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c/go.mod h1:k5D13LCXSsMrQyfdW0yGYs4GWUvirqoxHht8qwtqyRY= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA= -github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= -github.com/elastic/gosigar v0.10.5 h1:GzPQ+78RaAb4J63unidA/JavQRKrB6s8IOzN6Ib59jo= -github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/go-ethereum v1.9.2 h1:RMIHDO/diqXEgORSVzYx8xW9x2+S32PoAX5lQwya0Lw= github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc= +github.com/ethereum/go-ethereum v1.9.10/go.mod h1:lXHkVo/MTvsEXfYsmNzelZ8R1e0DTvdk/wMZJIRpaRw= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a h1:1znxn4+q2MrEdTk1eCk6KIV3muTYVclBIB6CTVR/zBc= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= -github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/getsentry/sentry-go v0.3.1 h1:yTTEl5wqb8mECvTujvyqSi/WjKQnUQL9F921EIDuVqs= -github.com/getsentry/sentry-go v0.3.1/go.mod h1:rnN2T5/zgkxv1oOpRVzfRqvjCw7XM6cjbDGmGyY/+8E= +github.com/getsentry/sentry-go v0.4.0/go.mod h1:xkGcb82SipKQloDNa5b7hTV4VdEyc2bhwd1/UczP52k= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= -github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-redis/redis v6.15.6+incompatible h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be8FqJQRhdQZ5Sg= +github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-redis/redis v6.15.6+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6 h1:9WiNlI9Cds5S5YITwRpRs8edNaq0nxTEymhDW20A1QE= github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6/go.mod h1:Au3iQ8DvDis8hZ4q2OzRcaKYlAsPt+fYvib5q4nIqu4= +github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hewigovens/go-coincodec v1.0.4 h1:asF02q8WfDwVQjU1O0VZYbOBer0cPJUmTiZKfAgqBYM= github.com/hewigovens/go-coincodec v1.0.4/go.mod h1:+LTdzScnu782gMt0J3ZccPY9S2uyrGe0R1LUYGWecfc= -github.com/howeyc/fsnotify v0.9.0 h1:0gtV5JmOKH4A8SsFxG2BczSeXWWPvcMT0euZt5gDAxY= github.com/howeyc/fsnotify v0.9.0/go.mod h1:41HzSPxBGeFRQKEEwgh49TRw/nKBsYZ2cF1OzPjSJsA= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb v1.7.7 h1:UvNzAPfBrKMENVbQ4mr4ccA9sW+W1Ihl0Yh1s0BiVAg= +github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= -github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= -github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/gorm v1.9.11 h1:gaHGvE+UnWGlbWG4Y3FUwY1EcZ5n6S9WtqBA/uySMLE= -github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= -github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= +github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 h1:ZHuwnjpP8LsVsUYqTqeVAI+GfDfJ6UNPrExZF+vX/DQ= -github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= @@ -284,275 +231,191 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= +github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k= -github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= -github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= +github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= -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/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5 h1:l16XLUUJ34wIz+RIvLhSwGvLvKyy+W598b135bJN6mg= github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= -github.com/multiformats/go-multihash v0.0.9 h1:aoijQXYYl7Xtb2pUUP68R+ys1TlnlR3eX6wmozr0Hp4= -github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2 h1:sq53g+DWf0J6/ceFUHpQ0nAEb6WgM++fq16MZ91cS6o= -github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c h1:1RHs3tNxjXGHeul8z2t6H2N2TlAqpKe5yryJztRx4Jk= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= -github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/oschwald/maxminddb-golang v1.3.1 h1:kPc5+ieL5CC/Zn0IaXJPxDFlUxKTQEU8QBTtmfQDAIo= github.com/oschwald/maxminddb-golang v1.3.1/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= -github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= -github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= -github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.7 h1:RS5GAlMbnkWkhs4+bPocMTmGjYkuCY5djjqEDdXOhcQ= -github.com/prometheus/procfs v0.0.7/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic= github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= -github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E= -github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/robertkrimen/otto v0.0.0-20170205013659-6a77b7cbc37d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 h1:Pm6R878vxWWWR+Sa3ppsLce/Zq+JNTs6aVvRu13jv9A= github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.5.0 h1:GpsTwfsQ27oS/Aha/6d1oD7tpKIqWnOA6tgOX9HHkt4= -github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4= +github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= -github.com/status-im/keycard-go v0.0.0-20191114114615-9d48af884d5b h1:yRRMsW8U/sYfVxNPuI9KtNxunG3Pzq0cr9VBY42W+rA= -github.com/status-im/keycard-go v0.0.0-20191114114615-9d48af884d5b/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= -github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= -github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= -github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= -github.com/swaggo/swag v1.6.3 h1:N+uVPGP4H2hXoss2pt5dctoSUPKKRInr6qcTMOm0usI= -github.com/swaggo/swag v1.6.3/go.mod h1:wcc83tB4Mb2aNiL/HP4MFeQdpHUrca+Rp/DRNgWAUio= -github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= -github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= -github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/wealdtech/go-ens/v3 v3.0.9 h1:gXMBNXikJ/XV9k6ybPOZMXIMPjBGSCC9N10dxe8Y2Xk= -github.com/wealdtech/go-ens/v3 v3.0.9/go.mod h1:P2OEBvgkhXLrPzPN+eR5z2/wFIGwHyijTDvpuC1xLlo= -github.com/wealdtech/go-multicodec v1.2.0 h1:9AHSxcSE9F9r6ZvQLAO0EXCdM08QfYohaXmW3k6sSh4= +github.com/wealdtech/go-ens/v3 v3.1.0/go.mod h1:P2OEBvgkhXLrPzPN+eR5z2/wFIGwHyijTDvpuC1xLlo= github.com/wealdtech/go-multicodec v1.2.0/go.mod h1:aedGMaTeYkIqi/KCPre1ho5rTb3hGpu/snBOS3GQLw4= -github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= -github.com/wealdtech/go-string2eth v1.0.0 h1:jY6b1MVqU6k2Uw/kvcU1Y9/3dDyXfPzZrOFspt82UJs= github.com/wealdtech/go-string2eth v1.0.0/go.mod h1:UZA/snEybGcD6n+Pl+yoDjmexlEJ6dtoS9myfM83Ol4= -github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b h1:6cLsL+2FW6dRAdl5iMtHgRogVCff0QpRi9653YmdcJA= -github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= -github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -561,17 +424,14 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f h1:kz4KIr+xcPUsI3VMoqWfPMvtnJ6MGfiVwsWSVzphMO4= -golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -580,9 +440,6 @@ golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -591,18 +448,13 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191118183410-d06c31c94cae h1:AzDIJnLFoW3GaQvpbMRKk+SptYRYtnhYdyuX+S/dTbc= -golang.org/x/net v0.0.0-20191118183410-d06c31c94cae/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -610,93 +462,64 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191118133127-cf1e2d577169 h1:LPLFLulk2vyM7yI3CwNW64O6e8AxBmr9opfv14yI7HI= -golang.org/x/sys v0.0.0-20191118133127-cf1e2d577169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98 h1:tZwpOHmF1OEL9wJGSgBALnhFg/8VKjQTtctCX51GLNI= -golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= -gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= -gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= -gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= -gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190213234257-ec84240a7772/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff h1:uuol9OUzSvZntY1v963NAbVd7A+PHLMz1FlCe3Lorcs= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= -gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/k8s/deployment.yml b/k8s/deployment.yml deleted file mode 100644 index 5caeea20e..000000000 --- a/k8s/deployment.yml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: blockatlas - name: blockatlas -spec: - replicas: 1 - selector: - matchLabels: - app: blockatlas - strategy: - type: Recreate - template: - metadata: - labels: - app: blockatlas - spec: - containers: - - env: - - name: ATLAS_MARKET_ENABLED - value: "true" - - name: ATLAS_OBSERVER_ENABLED - value: "true" - - name: ATLAS_STORAGE_REDIS - value: redis://redis-ha:6379 # I can recommend the Redis Helm Chart https://github.com/helm/charts/tree/master/stable/redis - image: trustwallet/blockatlas - name: blockatlas - dnsPolicy: ClusterFirst - restartPolicy: Always diff --git a/k8s/ingress.yml b/k8s/ingress.yml deleted file mode 100644 index 15906625f..000000000 --- a/k8s/ingress.yml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: blockatlas -spec: - clusterIP: None - ports: - - name: http - port: 8420 - protocol: TCP - targetPort: 8420 - selector: - app: blockatlas - type: ClusterIP - ---- -apiVersion: networking.k8s.io/v1beta1 -kind: Ingress -metadata: - name: blockatlas -spec: - rules: - - host: blockatlas.localhost - http: - paths: - - backend: - serviceName: blockatlas - servicePort: http diff --git a/main.go b/main.go deleted file mode 100644 index 7b465cbac..000000000 --- a/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "github.com/trustwallet/blockatlas/cmd" -) - -func main() { - cmd.Execute() -} diff --git a/pkg/tests/functional/functional_test.go b/pkg/tests/functional/functional_test.go index efab91182..f93c22630 100755 --- a/pkg/tests/functional/functional_test.go +++ b/pkg/tests/functional/functional_test.go @@ -3,16 +3,26 @@ package functional import ( + "context" + "github.com/getsentry/sentry-go/gin" + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "github.com/swaggo/gin-swagger" + "github.com/swaggo/gin-swagger/swaggerFiles" + "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/pkg/ginutils" + "net/http" "os" + "os/signal" "sync" + "syscall" "testing" "time" - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/cmd" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/storage" ) func TestApis(t *testing.T) { @@ -21,18 +31,73 @@ func TestApis(t *testing.T) { logger.InitLogger() platform.Init() + cache := storage.New() + sg := sentrygin.New(sentrygin.Options{}) + p := ":8420" + + engine := gin.New() + + engine.Use(gin.Recovery()) + engine.Use(ginutils.CheckReverseProxy, sg) + engine.Use(ginutils.CORSMiddleware()) + + engine.OPTIONS("/*path", ginutils.CORSMiddleware()) + + engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + engine.GET("/", api.GetRoot) + engine.GET("/status", func(c *gin.Context) { + ginutils.RenderSuccess(c, map[string]interface{}{ + "status": true, + }) + }) + + api.MakeMetricsRoute(engine) + api.LoadPlatforms(engine) + + if viper.GetBool("observer.enabled") { + logger.Info("Loading observer API") + observerAPI := engine.Group("/observer/v1") + api.SetupObserverAPI(observerAPI, cache) + } + if viper.GetBool("market.enabled") { + logger.Info("Loading market API") + marketAPI := engine.Group("/v1/market") + api.SetupMarketAPI(marketAPI, cache) + } + + signalForExit := make(chan os.Signal, 1) + + signal.Notify(signalForExit, + syscall.SIGHUP, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT) + + srv := &http.Server{ + Addr: ":8420", + Handler: engine, + } - p := ":8080" - c := make(chan *gin.Engine) go func() { - cmd.RunApi(p, c) + if err := srv.ListenAndServe(); err != nil { + logger.Info("Application failed", err) + } }() - e := <-c + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + defer func() { + if err := srv.Shutdown(ctx); err != nil { + logger.Info("Server Shutdown: ", err) + } + }() + time.Sleep(time.Second * 2) var wg sync.WaitGroup cl := newClient(t, p) - for _, r := range e.Routes() { + for _, r := range engine.Routes() { wg.Add(1) t.Run(r.Path, func(t *testing.T) { go cl.doTests(r.Method, r.Path, &wg) diff --git a/platform/registry.go b/platform/registry.go index ca88e8138..4326eb1e9 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -23,7 +23,6 @@ import ( "github.com/trustwallet/blockatlas/platform/nebulas" "github.com/trustwallet/blockatlas/platform/nimiq" "github.com/trustwallet/blockatlas/platform/ontology" - "github.com/trustwallet/blockatlas/platform/polkadot" "github.com/trustwallet/blockatlas/platform/ripple" "github.com/trustwallet/blockatlas/platform/stellar" "github.com/trustwallet/blockatlas/platform/tezos" @@ -80,7 +79,7 @@ var platformList = []blockatlas.Platform{ &algorand.Platform{}, &nano.Platform{}, &harmony.Platform{}, - &polkadot.Platform{CoinIndex: coin.KSM}, + //&polkadot.Platform{CoinIndex: coin.KSM}, } // Platforms contains all registered platforms by handle diff --git a/marketdata/chart/chart.go b/syncmarkets/chart/chart.go similarity index 100% rename from marketdata/chart/chart.go rename to syncmarkets/chart/chart.go diff --git a/marketdata/chart/coinmarketcap/cmc.go b/syncmarkets/chart/cmc/cmc.go similarity index 95% rename from marketdata/chart/coinmarketcap/cmc.go rename to syncmarkets/chart/cmc/cmc.go index f300fa216..be07067ba 100644 --- a/marketdata/chart/coinmarketcap/cmc.go +++ b/syncmarkets/chart/cmc/cmc.go @@ -1,10 +1,10 @@ -package coinmarketcap +package cmc import ( - "github.com/trustwallet/blockatlas/marketdata/chart" - "github.com/trustwallet/blockatlas/marketdata/clients/cmc" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/syncmarkets/chart" + "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" "time" ) diff --git a/marketdata/chart/coinmarketcap/cmc_test.go b/syncmarkets/chart/cmc/cmc_test.go similarity index 98% rename from marketdata/chart/coinmarketcap/cmc_test.go rename to syncmarkets/chart/cmc/cmc_test.go index f8cfbc819..4d58485a2 100644 --- a/marketdata/chart/coinmarketcap/cmc_test.go +++ b/syncmarkets/chart/cmc/cmc_test.go @@ -1,9 +1,9 @@ -package coinmarketcap +package cmc import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/marketdata/clients/cmc" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" "reflect" "sort" "testing" diff --git a/marketdata/chart/coingecko/coingecko.go b/syncmarkets/chart/coingecko/coingecko.go similarity index 95% rename from marketdata/chart/coingecko/coingecko.go rename to syncmarkets/chart/coingecko/coingecko.go index 9fea50c5a..937261d25 100644 --- a/marketdata/chart/coingecko/coingecko.go +++ b/syncmarkets/chart/coingecko/coingecko.go @@ -2,10 +2,10 @@ package coingecko import ( "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/marketdata/chart" - "github.com/trustwallet/blockatlas/marketdata/clients/coingecko" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/syncmarkets/chart" + "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" "time" ) diff --git a/marketdata/chart/coingecko/coingecko_test.go b/syncmarkets/chart/coingecko/coingecko_test.go similarity index 96% rename from marketdata/chart/coingecko/coingecko_test.go rename to syncmarkets/chart/coingecko/coingecko_test.go index 40556411b..26f6f4ed9 100644 --- a/marketdata/chart/coingecko/coingecko_test.go +++ b/syncmarkets/chart/coingecko/coingecko_test.go @@ -2,8 +2,8 @@ package coingecko import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/marketdata/clients/coingecko" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" "reflect" "testing" "time" diff --git a/marketdata/chart/provider.go b/syncmarkets/chart/provider.go similarity index 100% rename from marketdata/chart/provider.go rename to syncmarkets/chart/provider.go diff --git a/marketdata/charts.go b/syncmarkets/charts.go similarity index 91% rename from marketdata/charts.go rename to syncmarkets/charts.go index edab1476d..7fb124c7f 100644 --- a/marketdata/charts.go +++ b/syncmarkets/charts.go @@ -1,13 +1,13 @@ -package marketdata +package syncmarkets import ( "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/marketdata/chart" - "github.com/trustwallet/blockatlas/marketdata/chart/coingecko" - cmc "github.com/trustwallet/blockatlas/marketdata/chart/coinmarketcap" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/blockatlas/syncmarkets/chart" + "github.com/trustwallet/blockatlas/syncmarkets/chart/cmc" + "github.com/trustwallet/blockatlas/syncmarkets/chart/coingecko" "math" "sort" ) diff --git a/marketdata/charts_test.go b/syncmarkets/charts_test.go similarity index 99% rename from marketdata/charts_test.go rename to syncmarkets/charts_test.go index de5801a60..318969cb4 100644 --- a/marketdata/charts_test.go +++ b/syncmarkets/charts_test.go @@ -1,4 +1,4 @@ -package marketdata +package syncmarkets import ( "github.com/stretchr/testify/assert" diff --git a/marketdata/clients/cmc/cache.go b/syncmarkets/clients/cmc/cache.go similarity index 100% rename from marketdata/clients/cmc/cache.go rename to syncmarkets/clients/cmc/cache.go diff --git a/marketdata/clients/cmc/cache_test.go b/syncmarkets/clients/cmc/cache_test.go similarity index 100% rename from marketdata/clients/cmc/cache_test.go rename to syncmarkets/clients/cmc/cache_test.go diff --git a/marketdata/clients/cmc/client.go b/syncmarkets/clients/cmc/client.go similarity index 100% rename from marketdata/clients/cmc/client.go rename to syncmarkets/clients/cmc/client.go diff --git a/marketdata/clients/cmc/models.go b/syncmarkets/clients/cmc/models.go similarity index 100% rename from marketdata/clients/cmc/models.go rename to syncmarkets/clients/cmc/models.go diff --git a/marketdata/clients/cmc/webclient.go b/syncmarkets/clients/cmc/webclient.go similarity index 100% rename from marketdata/clients/cmc/webclient.go rename to syncmarkets/clients/cmc/webclient.go diff --git a/marketdata/clients/cmc/widgetclient.go b/syncmarkets/clients/cmc/widgetclient.go similarity index 100% rename from marketdata/clients/cmc/widgetclient.go rename to syncmarkets/clients/cmc/widgetclient.go diff --git a/marketdata/clients/coingecko/cache.go b/syncmarkets/clients/coingecko/cache.go similarity index 100% rename from marketdata/clients/coingecko/cache.go rename to syncmarkets/clients/coingecko/cache.go diff --git a/marketdata/clients/coingecko/cache_test.go b/syncmarkets/clients/coingecko/cache_test.go similarity index 100% rename from marketdata/clients/coingecko/cache_test.go rename to syncmarkets/clients/coingecko/cache_test.go diff --git a/marketdata/clients/coingecko/client.go b/syncmarkets/clients/coingecko/client.go similarity index 100% rename from marketdata/clients/coingecko/client.go rename to syncmarkets/clients/coingecko/client.go diff --git a/marketdata/clients/coingecko/client_test.go b/syncmarkets/clients/coingecko/client_test.go similarity index 100% rename from marketdata/clients/coingecko/client_test.go rename to syncmarkets/clients/coingecko/client_test.go diff --git a/marketdata/clients/coingecko/models.go b/syncmarkets/clients/coingecko/models.go similarity index 100% rename from marketdata/clients/coingecko/models.go rename to syncmarkets/clients/coingecko/models.go diff --git a/marketdata/clients/compound/client.go b/syncmarkets/clients/compound/client.go similarity index 100% rename from marketdata/clients/compound/client.go rename to syncmarkets/clients/compound/client.go diff --git a/marketdata/clients/compound/models.go b/syncmarkets/clients/compound/models.go similarity index 100% rename from marketdata/clients/compound/models.go rename to syncmarkets/clients/compound/models.go diff --git a/marketdata/market.go b/syncmarkets/market.go similarity index 82% rename from marketdata/market.go rename to syncmarkets/market.go index 37f74dd1c..57d5d52f5 100644 --- a/marketdata/market.go +++ b/syncmarkets/market.go @@ -1,16 +1,16 @@ -package marketdata +package syncmarkets import ( "github.com/robfig/cron/v3" "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/marketdata/market" - "github.com/trustwallet/blockatlas/marketdata/market/coingecko" - cmc "github.com/trustwallet/blockatlas/marketdata/market/coinmarketcap" - "github.com/trustwallet/blockatlas/marketdata/market/compound" - "github.com/trustwallet/blockatlas/marketdata/market/dex" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" + "github.com/trustwallet/blockatlas/syncmarkets/market" + "github.com/trustwallet/blockatlas/syncmarkets/market/cmc" + "github.com/trustwallet/blockatlas/syncmarkets/market/coingecko" + "github.com/trustwallet/blockatlas/syncmarkets/market/compound" + "github.com/trustwallet/blockatlas/syncmarkets/market/dex" ) var marketProviders market.Providers diff --git a/marketdata/market/coinmarketcap/cmc.go b/syncmarkets/market/cmc/cmc.go similarity index 95% rename from marketdata/market/coinmarketcap/cmc.go rename to syncmarkets/market/cmc/cmc.go index 0a4fbda13..67ae4b533 100644 --- a/marketdata/market/coinmarketcap/cmc.go +++ b/syncmarkets/market/cmc/cmc.go @@ -1,9 +1,9 @@ package cmc import ( - "github.com/trustwallet/blockatlas/marketdata/clients/cmc" - "github.com/trustwallet/blockatlas/marketdata/market" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" + "github.com/trustwallet/blockatlas/syncmarkets/market" ) const ( diff --git a/marketdata/market/coinmarketcap/cmc_test.go b/syncmarkets/market/cmc/cmc_test.go similarity index 98% rename from marketdata/market/coinmarketcap/cmc_test.go rename to syncmarkets/market/cmc/cmc_test.go index 1550d394d..1d57c680e 100644 --- a/marketdata/market/coinmarketcap/cmc_test.go +++ b/syncmarkets/market/cmc/cmc_test.go @@ -2,8 +2,8 @@ package cmc import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/marketdata/clients/cmc" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" "sort" "testing" "time" diff --git a/marketdata/market/coingecko/coingecko.go b/syncmarkets/market/coingecko/coingecko.go similarity index 94% rename from marketdata/market/coingecko/coingecko.go rename to syncmarkets/market/coingecko/coingecko.go index 3e9a91577..0097e1ffb 100644 --- a/marketdata/market/coingecko/coingecko.go +++ b/syncmarkets/market/coingecko/coingecko.go @@ -1,9 +1,9 @@ package coingecko import ( - "github.com/trustwallet/blockatlas/marketdata/clients/coingecko" - "github.com/trustwallet/blockatlas/marketdata/market" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" + "github.com/trustwallet/blockatlas/syncmarkets/market" "strings" ) diff --git a/marketdata/market/coingecko/coingecko_test.go b/syncmarkets/market/coingecko/coingecko_test.go similarity index 97% rename from marketdata/market/coingecko/coingecko_test.go rename to syncmarkets/market/coingecko/coingecko_test.go index 4aeb85e51..55eb6c343 100644 --- a/marketdata/market/coingecko/coingecko_test.go +++ b/syncmarkets/market/coingecko/coingecko_test.go @@ -2,8 +2,8 @@ package coingecko import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/marketdata/clients/coingecko" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" "sort" "testing" "time" diff --git a/marketdata/market/compound/compound.go b/syncmarkets/market/compound/compound.go similarity index 91% rename from marketdata/market/compound/compound.go rename to syncmarkets/market/compound/compound.go index 0c55765c0..b21bf226b 100644 --- a/marketdata/market/compound/compound.go +++ b/syncmarkets/market/compound/compound.go @@ -2,9 +2,9 @@ package compound import ( "github.com/trustwallet/blockatlas/coin" - c "github.com/trustwallet/blockatlas/marketdata/clients/compound" - "github.com/trustwallet/blockatlas/marketdata/market" "github.com/trustwallet/blockatlas/pkg/blockatlas" + c "github.com/trustwallet/blockatlas/syncmarkets/clients/compound" + "github.com/trustwallet/blockatlas/syncmarkets/market" "time" ) diff --git a/marketdata/market/compound/compound_test.go b/syncmarkets/market/compound/compound_test.go similarity index 96% rename from marketdata/market/compound/compound_test.go rename to syncmarkets/market/compound/compound_test.go index 2eafcdab2..8a799243c 100644 --- a/marketdata/market/compound/compound_test.go +++ b/syncmarkets/market/compound/compound_test.go @@ -2,8 +2,8 @@ package compound import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/marketdata/clients/compound" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/compound" "sort" "testing" "time" diff --git a/marketdata/market/dex/dex.go b/syncmarkets/market/dex/dex.go similarity index 97% rename from marketdata/market/dex/dex.go rename to syncmarkets/market/dex/dex.go index 64ddc820b..284e7065b 100644 --- a/marketdata/market/dex/dex.go +++ b/syncmarkets/market/dex/dex.go @@ -2,9 +2,9 @@ package dex import ( "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/marketdata/market" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/syncmarkets/market" "math/big" "net/url" "strconv" diff --git a/marketdata/market/dex/dex_test.go b/syncmarkets/market/dex/dex_test.go similarity index 100% rename from marketdata/market/dex/dex_test.go rename to syncmarkets/market/dex/dex_test.go diff --git a/marketdata/market/dex/models.go b/syncmarkets/market/dex/models.go similarity index 100% rename from marketdata/market/dex/models.go rename to syncmarkets/market/dex/models.go diff --git a/marketdata/market/market.go b/syncmarkets/market/market.go similarity index 100% rename from marketdata/market/market.go rename to syncmarkets/market/market.go diff --git a/marketdata/market/provider.go b/syncmarkets/market/provider.go similarity index 100% rename from marketdata/market/provider.go rename to syncmarkets/market/provider.go diff --git a/marketdata/rate/coinmarketcap/cmc.go b/syncmarkets/rate/cmc/cmc.go similarity index 90% rename from marketdata/rate/coinmarketcap/cmc.go rename to syncmarkets/rate/cmc/cmc.go index 985bff658..fdb480a47 100644 --- a/marketdata/rate/coinmarketcap/cmc.go +++ b/syncmarkets/rate/cmc/cmc.go @@ -1,9 +1,9 @@ package cmc import ( - "github.com/trustwallet/blockatlas/marketdata/clients/cmc" - "github.com/trustwallet/blockatlas/marketdata/rate" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" + "github.com/trustwallet/blockatlas/syncmarkets/rate" "math/big" ) diff --git a/marketdata/rate/coinmarketcap/cmc_test.go b/syncmarkets/rate/cmc/cmc_test.go similarity index 97% rename from marketdata/rate/coinmarketcap/cmc_test.go rename to syncmarkets/rate/cmc/cmc_test.go index 553c801b6..4c192a900 100644 --- a/marketdata/rate/coinmarketcap/cmc_test.go +++ b/syncmarkets/rate/cmc/cmc_test.go @@ -2,8 +2,8 @@ package cmc import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/marketdata/clients/cmc" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" "math/big" "sort" "testing" diff --git a/marketdata/rate/coingecko/coingecko.go b/syncmarkets/rate/coingecko/coingecko.go similarity index 89% rename from marketdata/rate/coingecko/coingecko.go rename to syncmarkets/rate/coingecko/coingecko.go index dd7aba9fc..6628367a6 100644 --- a/marketdata/rate/coingecko/coingecko.go +++ b/syncmarkets/rate/coingecko/coingecko.go @@ -1,9 +1,9 @@ package coingecko import ( - "github.com/trustwallet/blockatlas/marketdata/clients/coingecko" - "github.com/trustwallet/blockatlas/marketdata/rate" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" + "github.com/trustwallet/blockatlas/syncmarkets/rate" "strings" ) diff --git a/marketdata/rate/coingecko/coingecko_test.go b/syncmarkets/rate/coingecko/coingecko_test.go similarity index 96% rename from marketdata/rate/coingecko/coingecko_test.go rename to syncmarkets/rate/coingecko/coingecko_test.go index 18b48d330..d2174f7e4 100644 --- a/marketdata/rate/coingecko/coingecko_test.go +++ b/syncmarkets/rate/coingecko/coingecko_test.go @@ -2,8 +2,8 @@ package coingecko import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/marketdata/clients/coingecko" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" "sort" "testing" "time" diff --git a/marketdata/rate/compound/compound.go b/syncmarkets/rate/compound/compound.go similarity index 88% rename from marketdata/rate/compound/compound.go rename to syncmarkets/rate/compound/compound.go index 07b8397f9..44c0159fb 100644 --- a/marketdata/rate/compound/compound.go +++ b/syncmarkets/rate/compound/compound.go @@ -1,9 +1,9 @@ package compound import ( - c "github.com/trustwallet/blockatlas/marketdata/clients/compound" - "github.com/trustwallet/blockatlas/marketdata/rate" "github.com/trustwallet/blockatlas/pkg/blockatlas" + c "github.com/trustwallet/blockatlas/syncmarkets/clients/compound" + "github.com/trustwallet/blockatlas/syncmarkets/rate" "strings" "time" ) diff --git a/marketdata/rate/compound/compound_test.go b/syncmarkets/rate/compound/compound_test.go similarity index 96% rename from marketdata/rate/compound/compound_test.go rename to syncmarkets/rate/compound/compound_test.go index 41e8e1c71..367804bb1 100644 --- a/marketdata/rate/compound/compound_test.go +++ b/syncmarkets/rate/compound/compound_test.go @@ -2,8 +2,8 @@ package compound import ( "github.com/stretchr/testify/assert" - c "github.com/trustwallet/blockatlas/marketdata/clients/compound" "github.com/trustwallet/blockatlas/pkg/blockatlas" + c "github.com/trustwallet/blockatlas/syncmarkets/clients/compound" "sort" "testing" "time" diff --git a/marketdata/rate/fixer/fixer.go b/syncmarkets/rate/fixer/fixer.go similarity index 94% rename from marketdata/rate/fixer/fixer.go rename to syncmarkets/rate/fixer/fixer.go index dd0570a89..e5d7359f7 100644 --- a/marketdata/rate/fixer/fixer.go +++ b/syncmarkets/rate/fixer/fixer.go @@ -1,8 +1,8 @@ package fixer import ( - "github.com/trustwallet/blockatlas/marketdata/rate" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/syncmarkets/rate" "net/url" ) diff --git a/marketdata/rate/fixer/fixer_test.go b/syncmarkets/rate/fixer/fixer_test.go similarity index 100% rename from marketdata/rate/fixer/fixer_test.go rename to syncmarkets/rate/fixer/fixer_test.go diff --git a/marketdata/rate/fixer/models.go b/syncmarkets/rate/fixer/models.go similarity index 100% rename from marketdata/rate/fixer/models.go rename to syncmarkets/rate/fixer/models.go diff --git a/marketdata/rate/provider.go b/syncmarkets/rate/provider.go similarity index 100% rename from marketdata/rate/provider.go rename to syncmarkets/rate/provider.go diff --git a/marketdata/rate/rate.go b/syncmarkets/rate/rate.go similarity index 100% rename from marketdata/rate/rate.go rename to syncmarkets/rate/rate.go diff --git a/marketdata/rates.go b/syncmarkets/rates.go similarity index 81% rename from marketdata/rates.go rename to syncmarkets/rates.go index 6533adc30..ae49bc42f 100644 --- a/marketdata/rates.go +++ b/syncmarkets/rates.go @@ -1,16 +1,16 @@ -package marketdata +package syncmarkets import ( "github.com/robfig/cron/v3" "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/marketdata/rate" - "github.com/trustwallet/blockatlas/marketdata/rate/coingecko" - cmc "github.com/trustwallet/blockatlas/marketdata/rate/coinmarketcap" - "github.com/trustwallet/blockatlas/marketdata/rate/compound" - "github.com/trustwallet/blockatlas/marketdata/rate/fixer" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" + "github.com/trustwallet/blockatlas/syncmarkets/rate" + "github.com/trustwallet/blockatlas/syncmarkets/rate/cmc" + "github.com/trustwallet/blockatlas/syncmarkets/rate/coingecko" + "github.com/trustwallet/blockatlas/syncmarkets/rate/compound" + "github.com/trustwallet/blockatlas/syncmarkets/rate/fixer" ) var rateProviders rate.Providers diff --git a/marketdata/worker.go b/syncmarkets/worker.go similarity index 92% rename from marketdata/worker.go rename to syncmarkets/worker.go index 6629eb95f..4c297c055 100644 --- a/marketdata/worker.go +++ b/syncmarkets/worker.go @@ -1,14 +1,14 @@ -package marketdata +package syncmarkets import ( "fmt" "github.com/cenkalti/backoff" "github.com/robfig/cron/v3" - "github.com/trustwallet/blockatlas/marketdata/market" - "github.com/trustwallet/blockatlas/marketdata/rate" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" + "github.com/trustwallet/blockatlas/syncmarkets/market" + "github.com/trustwallet/blockatlas/syncmarkets/rate" "time" ) From 3b9ba0b93bd3cc860e1c38db5e403a16a8a8ce77 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 30 Jan 2020 04:34:43 -0300 Subject: [PATCH 053/506] fix config file path (#779) --- Makefile | 12 ++++++------ Procfile | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 87816c69f..5a01606e1 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ GOBIN := $(GOBASE)/bin GOPKG := $(.) # Environment variables -TEST_CONFIG=$(GOBASE)/config.yml +CONFIG_FILE=$(GOBASE)/config.yml # Go files GOFMT_FILES?=$$(find . -name '*.go' | grep -v vendor) @@ -44,21 +44,21 @@ start: ## start-api: Start API in development mode. start-api: stop @echo " > Starting $(PROJECT_NAME) API" - @-$(GOBIN)/$(API_SERVICE)/api -c config.yml 2>&1 & echo $$! > $(PID_API) + @-$(GOBIN)/$(API_SERVICE)/api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_API) @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" @echo " > Error log: $(STDERR)" ## start-observer: Start Observer in development mode. start-observer: stop @echo " > Starting $(PROJECT_NAME) Observer" - @-$(GOBIN)/$(OBSERVER_SERVICE)/observer -c config.yml 2>&1 & echo $$! > $(PID_OBSERVER) + @-$(GOBIN)/$(OBSERVER_SERVICE)/observer -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER) @cat $(PID_OBSERVER) | sed "/^/s/^/ \> Observer PID: /" @echo " > Error log: $(STDERR)" ## start-sync-markets: Start Sync markets in development mode. start-syncmarkets: stop @echo " > Starting $(PROJECT_NAME) Sync" - @-$(GOBIN)/$(SYNC_SERVICE)/syncmarkets -c config.yml 2>&1 & echo $$! > $(PID_SYNC) + @-$(GOBIN)/$(SYNC_SERVICE)/syncmarkets -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SYNC) @cat $(PID_SYNC) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" @@ -147,11 +147,11 @@ go-test: go-functional: @echo " > Runing functional tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(TEST_CONFIG) go test -race -tags=functional -v ./pkg/tests/functional + GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=functional -v ./pkg/tests/functional go-integration: @echo " > Runing integration tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(TEST_CONFIG) go test -race -tags=integration -v ./pkg/tests/integration + GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./pkg/tests/integration go-fmt: @echo " > Format all go files" diff --git a/Procfile b/Procfile index 53c120be9..2f26c14ee 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,3 @@ -web: bin/api -p $PORT -observer: bin/observer -market: bin/syncmarkets +web: bin/api -p $PORT -c config.yml +observer: bin/observer -c config.yml +market: bin/syncmarkets -c config.yml From eaba4e846424ff6d653c361dc22770651ba90c15 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 30 Jan 2020 04:39:59 -0300 Subject: [PATCH 054/506] fix cache init for api app (#781) --- cmd/api/main.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/api/main.go b/cmd/api/main.go index 12777553b..7fc6b871c 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -51,6 +51,12 @@ func init() { config.LoadConfig(confPath) logger.InitLogger() platform.Init() + + host := viper.GetString("storage.redis") + err = cache.Init(host) + if err != nil { + logger.Fatal(err) + } } func main() { From 204c702eed8a4473cd5aaa82696ddf97c744786a Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 30 Jan 2020 16:14:03 -0300 Subject: [PATCH 055/506] fix gin cache for validator (#785) --- pkg/blockatlas/clientcache.go | 4 ++-- pkg/tests/functional/functional_test.go | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/blockatlas/clientcache.go b/pkg/blockatlas/clientcache.go index bd6f7555a..cd12c4ff6 100644 --- a/pkg/blockatlas/clientcache.go +++ b/pkg/blockatlas/clientcache.go @@ -52,11 +52,11 @@ func (r *Request) GetWithCache(result interface{}, path string, query url.Values } func getCache(key string, value interface{}) error { - cache, ok := memoryCache.Get(key) + c, ok := memoryCache.Get(key) if !ok { return errors.E("validator cache: invalid cache key") } - r, ok := cache.([]byte) + r, ok := c.([]byte) if !ok { return errors.E("validator cache: failed to cast cache to bytes") } diff --git a/pkg/tests/functional/functional_test.go b/pkg/tests/functional/functional_test.go index f93c22630..01cd663c8 100755 --- a/pkg/tests/functional/functional_test.go +++ b/pkg/tests/functional/functional_test.go @@ -36,8 +36,6 @@ func TestApis(t *testing.T) { p := ":8420" engine := gin.New() - - engine.Use(gin.Recovery()) engine.Use(ginutils.CheckReverseProxy, sg) engine.Use(ginutils.CORSMiddleware()) From 06eecc10c7ffdd6149bb70228377182e931faf48 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 30 Jan 2020 16:41:18 -0300 Subject: [PATCH 056/506] fix gin cache for validator --- cmd/api/main.go | 2 -- pkg/tests/functional/functional_test.go | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index 7fc6b871c..ec1d8ff3c 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -63,10 +63,8 @@ func main() { gin.SetMode(viper.GetString("gin.mode")) engine := gin.New() - engine.Use(gin.Recovery()) engine.Use(ginutils.CheckReverseProxy, sg) engine.Use(ginutils.CORSMiddleware()) - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) diff --git a/pkg/tests/functional/functional_test.go b/pkg/tests/functional/functional_test.go index 01cd663c8..f93c22630 100755 --- a/pkg/tests/functional/functional_test.go +++ b/pkg/tests/functional/functional_test.go @@ -36,6 +36,8 @@ func TestApis(t *testing.T) { p := ":8420" engine := gin.New() + + engine.Use(gin.Recovery()) engine.Use(ginutils.CheckReverseProxy, sg) engine.Use(ginutils.CORSMiddleware()) From 55d385ff04f8e8b02999338e59ba9dc10f6c47f0 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Fri, 31 Jan 2020 05:29:14 +0800 Subject: [PATCH 057/506] bump go-ens to update registry (#786) --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index e6eb5cc98..fddd41ed9 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/stretchr/testify v1.4.0 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.5 - github.com/wealdtech/go-ens/v3 v3.1.0 + github.com/wealdtech/go-ens/v3 v3.2.0 golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index 3527b6893..9e56ad9ab 100644 --- a/go.sum +++ b/go.sum @@ -401,6 +401,7 @@ github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBn github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/wealdtech/go-ens/v3 v3.1.0/go.mod h1:P2OEBvgkhXLrPzPN+eR5z2/wFIGwHyijTDvpuC1xLlo= +github.com/wealdtech/go-ens/v3 v3.2.0/go.mod h1:P2OEBvgkhXLrPzPN+eR5z2/wFIGwHyijTDvpuC1xLlo= github.com/wealdtech/go-multicodec v1.2.0/go.mod h1:aedGMaTeYkIqi/KCPre1ho5rTb3hGpu/snBOS3GQLw4= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= github.com/wealdtech/go-string2eth v1.0.0/go.mod h1:UZA/snEybGcD6n+Pl+yoDjmexlEJ6dtoS9myfM83Ol4= From a204b782949e4673c00cd9dd764772802a2862c8 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 31 Jan 2020 12:41:49 -0300 Subject: [PATCH 058/506] update readme for swagger command (#788) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b81fa65e..dabc5c36c 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ Swagger API docs provided at path `/swagger/index.html` - Run the Swag in your Go project root folder. - `$ swag init` + `$ swag init -g ./cmd/api/main.go -o ./docs` ## Metrics From 8a683f928a76013fa084efe78fb02892a89a5691 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 31 Jan 2020 13:19:03 -0300 Subject: [PATCH 059/506] add make docs command --- Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Makefile b/Makefile index 5a01606e1..a10bff084 100644 --- a/Makefile +++ b/Makefile @@ -115,6 +115,9 @@ govet: go-vet ## golint: Run golint. golint: go-lint +## docs: Generate swagger docs. +docs: go-gen-docs + go-compile: go-get go-build go-build: @@ -161,6 +164,10 @@ go-gen-coins: @echo " > Generating coin file" COIN_FILE=$(COIN_FILE) COIN_GO_FILE=$(COIN_GO_FILE) GOBIN=$(GOBIN) go run -tags=coins $(GEN_COIN_FILE) +go-gen-docs: + @echo " > Generating swagger files" + swag init -g ./cmd/api/main.go -o ./docs + go-goreleaser: @echo " > Releasing a new version" GOBIN=$(GOBIN) goreleaser --rm-dist From 29e164298d8b582fc68df6867ec3356f55aefa81 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 31 Jan 2020 13:22:28 -0300 Subject: [PATCH 060/506] improve swagger file --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a10bff084..fccfd2708 100644 --- a/Makefile +++ b/Makefile @@ -70,7 +70,7 @@ stop: @-kill `cat $(PID_SYNC)` 2> /dev/null || true @-rm $(PID_API) $(PID_OBSERVER) - +## compile: Compile the project. compile: @-touch $(STDERR) @-rm $(STDERR) @@ -136,7 +136,6 @@ go-get: @echo " > Checking if there is any missing dependencies..." GOBIN=$(GOBIN) go get cmd/... $(get) - go-install: GOBIN=$(GOBIN) go install $(GOPKG) From 5abf9f3813a30a2a30875e23420d344ece714001 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 2 Feb 2020 10:07:07 -0300 Subject: [PATCH 061/506] fix and improve client and gin cache (#791) * fix and improve gin cache * improve client cache * fix unit tests --- pkg/blockatlas/clientcache.go | 51 +++++++++++------ pkg/ginutils/gincache/cache.go | 101 ++++++++++++++++++++++----------- 2 files changed, 102 insertions(+), 50 deletions(-) diff --git a/pkg/blockatlas/clientcache.go b/pkg/blockatlas/clientcache.go index cd12c4ff6..847398958 100644 --- a/pkg/blockatlas/clientcache.go +++ b/pkg/blockatlas/clientcache.go @@ -10,20 +10,26 @@ import ( "github.com/trustwallet/blockatlas/pkg/storage/util" "net/url" "strings" + "sync" "time" ) var ( - memoryCache *cache.Cache + memoryCache *memCache ) func init() { - memoryCache = cache.New(5*time.Minute, 5*time.Minute) + memoryCache = &memCache{cache: cache.New(5*time.Minute, 5*time.Minute)} +} + +type memCache struct { + sync.RWMutex + cache *cache.Cache } func (r *Request) PostWithCache(result interface{}, path string, body interface{}, cache time.Duration) error { key := r.generateKey(path, nil, body) - err := getCache(key, result) + err := memoryCache.getCache(key, result) if err == nil { return nil } @@ -32,13 +38,13 @@ func (r *Request) PostWithCache(result interface{}, path string, body interface{ if err != nil { return err } - setCache(key, result, cache) + memoryCache.setCache(key, result, cache) return err } func (r *Request) GetWithCache(result interface{}, path string, query url.Values, cache time.Duration) error { key := r.generateKey(path, query, nil) - err := getCache(key, result) + err := memoryCache.getCache(key, result) if err == nil { return nil } @@ -47,12 +53,29 @@ func (r *Request) GetWithCache(result interface{}, path string, query url.Values if err != nil { return err } - setCache(key, result, cache) + memoryCache.setCache(key, result, cache) return err } -func getCache(key string, value interface{}) error { - c, ok := memoryCache.Get(key) +func (mc *memCache) deleteCache(key string) { + mc.RLock() + defer mc.RUnlock() + memoryCache.cache.Delete(key) +} + +func (mc *memCache) setCache(key string, value interface{}, duration time.Duration) { + mc.RLock() + defer mc.RUnlock() + b, err := json.Marshal(value) + if err != nil { + logger.Error(errors.E(err, "client cache cannot marshal cache object").PushToSentry()) + return + } + memoryCache.cache.Set(key, b, duration) +} + +func (mc *memCache) getCache(key string, value interface{}) error { + c, ok := mc.cache.Get(key) if !ok { return errors.E("validator cache: invalid cache key") } @@ -67,24 +90,16 @@ func getCache(key string, value interface{}) error { return nil } -func setCache(key string, value interface{}, duration time.Duration) { - b, err := json.Marshal(value) - if err != nil { - logger.Error(errors.E(err, "client cache cannot marshal cache object").PushToSentry()) - } - memoryCache.Set(key, b, duration) -} - func (r *Request) generateKey(path string, query url.Values, body interface{}) string { var queryStr = "" if query != nil { queryStr = query.Encode() } - url := strings.Join([]string{r.GetBase(path), queryStr}, "?") + requestUrl := strings.Join([]string{r.GetBase(path), queryStr}, "?") var b []byte if body != nil { b, _ = json.Marshal(body) } - hash := sha1.Sum(append([]byte(url), b...)) + hash := sha1.Sum(append([]byte(requestUrl), b...)) return base64.URLEncoding.EncodeToString(hash[:]) } diff --git a/pkg/ginutils/gincache/cache.go b/pkg/ginutils/gincache/cache.go index 3714c681c..9f11c0440 100644 --- a/pkg/ginutils/gincache/cache.go +++ b/pkg/ginutils/gincache/cache.go @@ -4,21 +4,30 @@ import ( "bytes" "crypto/sha1" "encoding/base64" + "encoding/json" "fmt" "github.com/gin-gonic/gin" "github.com/patrickmn/go-cache" + "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/pkg/storage/util" "io/ioutil" "net/http" + "sync" "time" ) var ( - memoryCache *cache.Cache + memoryCache *memCache ) func init() { - memoryCache = cache.New(5*time.Minute, 5*time.Minute) + memoryCache = &memCache{cache: cache.New(5*time.Minute, 5*time.Minute)} +} + +type memCache struct { + sync.RWMutex + cache *cache.Cache } type cacheResponse struct { @@ -55,48 +64,74 @@ func (w *cachedWriter) Written() bool { return w.ResponseWriter.Written() } -func getCacheResponse(key string) (*cacheResponse, error) { - mc, ok := memoryCache.Get(key) - if !ok { - return nil, fmt.Errorf("gin-cache: invalid cache key %s", key) - } - - tempCache, ok := mc.(cacheResponse) - if !ok { - return nil, fmt.Errorf("gin-cache: invalid cache object %s", key) - } - return &tempCache, nil -} - func (w *cachedWriter) Write(data []byte) (int, error) { ret, err := w.ResponseWriter.Write(data) if err != nil { - return 0, err + return 0, errors.E(err, "fail to cache write string", errors.Params{"data": data}) } - if w.Status() < 300 { - val := cacheResponse{ - w.Status(), - w.Header(), - data, - } - memoryCache.Set(w.key, val, w.expire) + if w.Status() != 200 { + return 0, errors.E("Write: invalid cache status", errors.Params{"data": data}) + } + val := cacheResponse{ + w.Status(), + w.Header(), + data, } + memoryCache.cache.Set(w.key, val, w.expire) return ret, nil } func (w *cachedWriter) WriteString(data string) (n int, err error) { ret, err := w.ResponseWriter.WriteString(data) - if err == nil && w.Status() < 300 { - val := cacheResponse{ - w.Status(), - w.Header(), - []byte(data), - } - memoryCache.Set(w.key, val, w.expire) + if err != nil { + return 0, errors.E(err, "fail to cache write string", errors.Params{"data": data}) + } + if w.Status() != 200 { + return 0, errors.E("WriteString: invalid cache status", errors.Params{"data": data}) + } + val := cacheResponse{ + w.Status(), + w.Header(), + []byte(data), } + memoryCache.setCache(w.key, val, w.expire) return ret, err } +func (mc *memCache) deleteCache(key string) { + mc.RLock() + defer mc.RUnlock() + memoryCache.cache.Delete(key) +} + +func (mc *memCache) setCache(k string, x interface{}, d time.Duration) { + b, err := json.Marshal(x) + if err != nil { + logger.Error(errors.E(err, "client cache cannot marshal cache object").PushToSentry()) + return + } + mc.RLock() + defer mc.RUnlock() + memoryCache.cache.Set(k, b, d) +} + +func (mc *memCache) getCache(key string) (*cacheResponse, error) { + c, ok := mc.cache.Get(key) + if !ok { + return nil, fmt.Errorf("gin-cache: invalid cache key %s", key) + } + r, ok := c.([]byte) + if !ok { + return nil, errors.E("validator cache: failed to cast cache to bytes") + } + var result cacheResponse + err := json.Unmarshal(r, &result) + if err != nil { + return nil, errors.E(err, util.ErrNotFound).PushToSentry() + } + return &result, nil +} + func generateKey(c *gin.Context) string { url := c.Request.URL.String() var b []byte @@ -112,15 +147,16 @@ func generateKey(c *gin.Context) string { // CacheMiddleware encapsulates a gin handler function and caches the response with an expiration time. func CacheMiddleware(expiration time.Duration, handle gin.HandlerFunc) gin.HandlerFunc { return func(c *gin.Context) { + defer c.Next() key := generateKey(c) - mc, err := getCacheResponse(key) + mc, err := memoryCache.getCache(key) if err != nil || mc.Data == nil { writer := newCachedWriter(expiration, c.Writer, key) c.Writer = writer handle(c) if c.IsAborted() { - memoryCache.Delete(key) + memoryCache.deleteCache(key) } return } @@ -133,6 +169,7 @@ func CacheMiddleware(expiration time.Duration, handle gin.HandlerFunc) gin.Handl } _, err = c.Writer.Write(mc.Data) if err != nil { + memoryCache.deleteCache(key) logger.Error(err, "cannot write data", mc) } } From 0ceba175dc64fc5a2596db08b6396adcbaa9fc27 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Sun, 2 Feb 2020 10:13:35 -0300 Subject: [PATCH 062/506] [BNB] Multiple Addresses Tx (#787) * get tx children * fetch tx childrens * add normalize to multsend transfer * add observer support * add unit test * fix unit test * add comments --- platform/binance/api.go | 218 +++++++++++++++++++----------- platform/binance/api_test.go | 237 ++++++++++++++++++++++++++++++++- platform/binance/client.go | 5 + platform/binance/model.go | 84 ++++++++++++ platform/binance/model_test.go | 154 +++++++++++++++++++++ 5 files changed, 617 insertions(+), 81 deletions(-) diff --git a/platform/binance/api.go b/platform/binance/api.go index 544550b00..5e81f74fe 100644 --- a/platform/binance/api.go +++ b/platform/binance/api.go @@ -3,8 +3,10 @@ package binance import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "strings" + "sync" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" @@ -47,7 +49,11 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { if err != nil { return nil, err } - txs := NormalizeTxs(srcTxs.Txs, "") + childTxs, err := p.getTxChildChan(srcTxs.Txs) + if err != nil { + return nil, err + } + txs := NormalizeTxs(childTxs, "", "") return &blockatlas.Block{ Number: num, Txs: txs, @@ -59,32 +65,115 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return p.GetTokenTxsByAddress(address, p.Coin().Symbol) } +// getTxChildChan get all child assets from a tx +func (p *Platform) getTxChildChan(srcTxs []Tx) ([]Tx, error) { + txs := make([]Tx, 0) + var wg sync.WaitGroup + out := make(chan Tx) + for _, srcTx := range srcTxs { + if srcTx.HasChildren != 1 { + // Return the same transaction if doesn't have a child + txs = append(txs, srcTx) + continue + } + wg.Add(1) + go func(srcTx Tx, out chan Tx) { + defer wg.Done() + tx, err := p.client.GetTx(srcTx.Hash) + if err != nil { + // Return the same transaction if an error occurs + out <- srcTx + logger.Error("GetTransactionsByBlockChan", err, logger.Params{"hash": srcTx.Hash}) + return + } + out <- tx + }(srcTx, out) + } + go func() { + wg.Wait() + close(out) + }() + for r := range out { + txs = append(txs, r) + } + return txs, nil +} + func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { srcTxs, err := p.client.GetTxsOfAddress(address, token) if err != nil { return nil, err } - return NormalizeTxs(srcTxs.Txs, token), nil + txs, err := p.getTxChildChan(srcTxs.Txs) + if err != nil { + return nil, err + } + return NormalizeTxs(txs, token, address), nil } -// NormalizeTx converts a Binance transaction into the generic model -func NormalizeTx(srcTx *Tx, token string) (blockatlas.Tx, bool) { - var tx blockatlas.Tx +func normalizeTransfer(tx blockatlas.Tx, srcTx Tx, token, address string) (blockatlas.TxPage, bool) { + // Verify if the tx has more them one asset + if srcTx.HasChildren == 1 { + txs := make(blockatlas.TxPage, 0) + // Parse all assets as a transaction + for _, subTx := range srcTx.SubTxsDto.SubTxDtoList.getTxs() { + // If this is not called from a block observer, only get the user txs/assets + if !subTx.containAddress(address) { + continue + } + // Recursive call to normalize the tx + newTxs, ok := normalizeTransfer(tx, subTx, token, address) + if !ok { + continue + } + txs = append(txs, newTxs...) + } + if len(txs) == 0 { + return txs, false + } + return txs, true + } + + // Verify if this is the same asset we are looking for + if len(token) > 0 && srcTx.Asset != token { + return blockatlas.TxPage{tx}, false + } + + tx.From = srcTx.FromAddr + tx.To = srcTx.ToAddr + bnbCoin := coin.Coins[coin.BNB] value := numbers.DecimalExp(string(srcTx.Value), 8) + if srcTx.Asset == bnbCoin.Symbol { + // Condition for native transfer (BNB) + tx.Meta = blockatlas.Transfer{ + Value: blockatlas.Amount(value), + Symbol: bnbCoin.Symbol, + Decimals: bnbCoin.Decimals, + } + return blockatlas.TxPage{tx}, true + } - fee := "0" - feeNumber, err := srcTx.Fee.Float64() - if err == nil && feeNumber > 0 { - fee = numbers.DecimalExp(string(srcTx.Fee), 8) + // Condition for native token transfer + tx.Meta = blockatlas.NativeTokenTransfer{ + TokenID: srcTx.Asset, + Symbol: TokenSymbol(srcTx.Asset), + Value: blockatlas.Amount(value), + Decimals: bnbCoin.Decimals, + From: srcTx.FromAddr, + To: srcTx.ToAddr, } + return blockatlas.TxPage{tx}, true +} - tx = blockatlas.Tx{ +// NormalizeTx converts a Binance transaction into the generic model +func NormalizeTx(srcTx Tx, token, address string) (blockatlas.TxPage, bool) { + tx := blockatlas.Tx{ ID: srcTx.Hash, Coin: coin.BNB, From: srcTx.FromAddr, To: srcTx.ToAddr, - Fee: blockatlas.Amount(fee), + Fee: blockatlas.Amount(srcTx.getFee()), Date: srcTx.Timestamp / 1000, Block: srcTx.BlockHeight, Status: blockatlas.StatusCompleted, @@ -93,70 +182,43 @@ func NormalizeTx(srcTx *Tx, token string) (blockatlas.Tx, bool) { switch srcTx.Type { case TxTransfer: - if len(token) > 0 && srcTx.Asset != token { - return tx, false - } - - if srcTx.Asset == bnbCoin.Symbol { - // Condition for native transfer (BNB) - tx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(value), - Symbol: bnbCoin.Symbol, - Decimals: bnbCoin.Decimals, - } - return tx, true - } //else if len(srcTx.FromAddr) > 0 && len(srcTx.ToAddr) > 0 { - // Condition for native token transfer - tx.Meta = blockatlas.NativeTokenTransfer{ - TokenID: srcTx.Asset, - Symbol: TokenSymbol(srcTx.Asset), - Value: blockatlas.Amount(value), - Decimals: bnbCoin.Decimals, - From: srcTx.FromAddr, - To: srcTx.ToAddr, - } - //} - //case TxCancelOrder, TxNewOrder: - // return tx, false - //case "invalid": - // return tx, false - // dt, err := srcTx.getData() - // if err != nil { - // return tx, false - // } - // - // symbol := dt.OrderData.Quote - // if len(token) > 0 && symbol != token { - // return tx, false - // } - // - // key := blockatlas.KeyPlaceOrder - // title := blockatlas.KeyTitlePlaceOrder - // if srcTx.Type == TxCancelOrder { - // key = blockatlas.KeyCancelOrder - // title = blockatlas.KeyTitleCancelOrder - // } - // volume, ok := dt.OrderData.GetVolume() - // if ok { - // value = strconv.Itoa(int(volume)) - // } - // - // tx.Meta = blockatlas.AnyAction{ - // Coin: coin.BNB, - // TokenID: dt.OrderData.Symbol, - // Symbol: TokenSymbol(symbol), - // Name: symbol, - // Value: blockatlas.Amount(value), - // Decimals: coin.Coins[coin.BNB].Decimals, - // Title: title, - // Key: key, - // } - - default: - return tx, false - } - - return tx, true + return normalizeTransfer(tx, srcTx, token, address) + } + //case TxCancelOrder, TxNewOrder: + // return tx, false + // dt, err := srcTx.getData() + // if err != nil { + // return tx, false + // } + // + // symbol := dt.OrderData.Quote + // if len(token) > 0 && symbol != token { + // return tx, false + // } + // + // key := blockatlas.KeyPlaceOrder + // title := blockatlas.KeyTitlePlaceOrder + // if srcTx.Type == TxCancelOrder { + // key = blockatlas.KeyCancelOrder + // title = blockatlas.KeyTitleCancelOrder + // } + // volume, ok := dt.OrderData.GetVolume() + // if ok { + // value = strconv.Itoa(int(volume)) + // } + // + // tx.Meta = blockatlas.AnyAction{ + // Coin: coin.BNB, + // TokenID: dt.OrderData.Symbol, + // Symbol: TokenSymbol(symbol), + // Name: symbol, + // Value: blockatlas.Amount(value), + // Decimals: coin.Coins[coin.BNB].Decimals, + // Title: title, + // Key: key, + // } + //} + return blockatlas.TxPage{tx}, false } func TokenSymbol(asset string) string { @@ -168,13 +230,13 @@ func TokenSymbol(asset string) string { } // NormalizeTxs converts multiple Binance transactions -func NormalizeTxs(srcTxs []Tx, token string) (txs []blockatlas.Tx) { +func NormalizeTxs(srcTxs []Tx, token, adress string) (txs []blockatlas.Tx) { for _, srcTx := range srcTxs { - tx, ok := NormalizeTx(&srcTx, token) + tx, ok := NormalizeTx(srcTx, token, adress) if !ok { continue } - txs = append(txs, tx) + txs = append(txs, tx...) } return } diff --git a/platform/binance/api_test.go b/platform/binance/api_test.go index 0a48da341..f5d64d277 100644 --- a/platform/binance/api_test.go +++ b/platform/binance/api_test.go @@ -82,6 +82,90 @@ const ( "memo": "", "source": 0, "hasChildren": 0 +}` + multipleTx = ` +{ + "txHash": "0C954A46D5AE90EBF9CB7E6F2EAC0E7C3E8DA2DA94B868962164A3AF9D54BEE8", + "blockHeight": 64374278, + "txType": "TRANSFER", + "timeStamp": 1580128370826, + "txFee": 0.0006, + "txAge": 222591, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 553829, + "memo": "", + "source": 0, + "sequence": 154231, + "hasChildren": 1, + "subTxsDto": { + "totalNum": 2, + "pageSize": 15, + "subTxDtoList": [ + { + "hash": "0C954A46D5AE90EBF9CB7E6F2EAC0E7C3E8DA2DA94B868962164A3AF9D54BEE8", + "height": 64374278, + "type": "TRANSFER", + "value": 3269, + "asset": "AERGO-46B", + "fromAddr": "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + "toAddr": "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + "fee": 0.0006 + }, + { + "hash": "0C954A46D5AE90EBF9CB7E6F2EAC0E7C3E8DA2DA94B868962164A3AF9D54BEE8", + "height": 64374278, + "type": "TRANSFER", + "value": 1, + "asset": "BNB", + "fromAddr": "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + "toAddr": "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + "fee": null + } + ] + } +}` + multipleTwiceTx = ` +{ + "txHash": "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", + "blockHeight": 63591484, + "txType": "TRANSFER", + "timeStamp": 1580421001269, + "txFee": 0.0006, + "txAge": 18773, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 38965, + "memo": "Trust Wallet Redeem", + "source": 0, + "sequence": 33, + "hasChildren": 1, + "subTxsDto": { + "totalNum": 2, + "pageSize": 15, + "subTxDtoList": [ + { + "hash": "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", + "height": 63591484, + "type": "TRANSFER", + "value": 1e-8, + "asset": "BNB", + "fromAddr": "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + "toAddr": "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + "fee": 0.0006 + }, + { + "hash": "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", + "height": 63591484, + "type": "TRANSFER", + "value": 1e-8, + "asset": "BNB", + "fromAddr": "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + "toAddr": "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + "fee": null + } + ] + } }` ) @@ -170,6 +254,40 @@ var ( Decimals: 8, }, } + multipleTxDst = blockatlas.Tx{ + ID: "0C954A46D5AE90EBF9CB7E6F2EAC0E7C3E8DA2DA94B868962164A3AF9D54BEE8", + Coin: coin.BNB, + From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + Fee: "60000", + Date: 1580128370, + Block: 64374278, + Status: blockatlas.StatusCompleted, + Meta: blockatlas.NativeTokenTransfer{ + From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + TokenID: "AERGO-46B", + Symbol: "AERGO", + Value: "326900000000", + Decimals: 8, + }, + } + multipleTwiceTxDst = blockatlas.Tx{ + ID: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", + Coin: coin.BNB, + From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + Fee: "60000", + Date: 1580421001, + Block: 63591484, + Status: blockatlas.StatusCompleted, + Memo: "Trust Wallet Redeem", + Meta: blockatlas.Transfer{ + Value: "2", + Decimals: 8, + Symbol: "BNB", + }, + } //TODO: temp test dst metaFreeCancelOrdeTransferDst = blockatlas.Tx{ ID: "F48DE755170C10F4A4C0E6836A708C33EEF9A7144800F25187D5F2349FD15A34", @@ -181,6 +299,22 @@ var ( Status: blockatlas.StatusCompleted, Meta: nil, } + baseTransferTx = blockatlas.Tx{ + ID: "0C954A46D5AE90EBF9CB7E6F2EAC0E7C3E8DA2DA94B868962164A3AF9D54BEE8", + Coin: coin.BNB, + From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + Fee: "60000", + Date: 1580128370, + Block: 63591484, + Status: blockatlas.StatusCompleted, + Memo: "Trust Wallet Redeem", + Meta: blockatlas.Transfer{ + Value: "2", + Decimals: 8, + Symbol: "BNB", + }, + } ) type testTx struct { @@ -207,6 +341,20 @@ func TestNormalizeTx(t *testing.T) { token: "YLC-D8B", wantError: false, }, + { + name: "multiple addresses token transfer", + apiResponse: multipleTx, + expected: multipleTxDst, + token: "AERGO-46B", + wantError: false, + }, + { + name: "multiple addresses with two transfers", + apiResponse: multipleTwiceTx, + expected: multipleTwiceTxDst, + token: "BNB", + wantError: false, + }, { name: "new order transfer", apiResponse: newOrderTransaction, @@ -248,13 +396,13 @@ func TestNormalizeTx(t *testing.T) { var srcTx Tx err := json.Unmarshal([]byte(testTxInstance.apiResponse), &srcTx) assert.Nil(t, err) - tx, ok := NormalizeTx(&srcTx, testTxInstance.token) + tx, ok := NormalizeTx(srcTx, testTxInstance.token, "") if testTxInstance.wantError { assert.False(t, ok, "transfer: tx could be normalized") return } assert.True(t, ok, "transfer: tx could not be normalized") - assert.Equal(t, testTxInstance.expected, tx, "transfer: tx don't equal") + assert.Equal(t, blockatlas.TxPage{testTxInstance.expected}, tx, "transfer: tx don't equal") }) } } @@ -384,7 +532,7 @@ func TestNormalizeTxs(t *testing.T) { var srcTxs []Tx err := json.Unmarshal([]byte(testTxsInstance.apiResponse), &srcTxs) assert.Nil(t, err) - txs := NormalizeTxs(srcTxs, testTxsInstance.token) + txs := NormalizeTxs(srcTxs, testTxsInstance.token, "") assert.Equal(t, testTxsInstance.expected, txs, "transfer: tx don't equal") }) } @@ -539,3 +687,86 @@ func TestTokenSymbol(t *testing.T) { assert.Equal(t, "UGAS", TokenSymbol("UGAS")) assert.Equal(t, "UGAS", TokenSymbol("UGAS-B0C")) } + +var ( + metaTx = blockatlas.Transfer{ + Value: "100000000", + Symbol: "BNB", + Decimals: 8, + } + metaTx2 = blockatlas.Transfer{ + Value: "2", + Symbol: "BNB", + Decimals: 8, + } + metaTokenTx = blockatlas.NativeTokenTransfer{ + Value: "326900000000", + TokenID: "AERGO-46B", + Symbol: "AERGO", + From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + Decimals: 8, + } +) + +func Test_normalizeTransfer(t *testing.T) { + testTx := baseTransferTx + testTx.Meta = metaTx + testTx2 := baseTransferTx + testTx2.Meta = metaTx2 + testTokenTx := baseTransferTx + testTokenTx.Meta = metaTokenTx + type args struct { + tx blockatlas.Tx + srcTx string + token string + address string + } + tests := []struct { + name string + args args + want blockatlas.TxPage + want1 bool + }{ + {"test multiple tx 1", args{ + tx: baseTransferTx, + srcTx: multipleTx, + token: "BNB", + address: "", + }, blockatlas.TxPage{testTx}, true}, + {"test multiple tx 2", args{ + tx: baseTransferTx, + srcTx: multipleTwiceTx, + token: "BNB", + address: "", + }, blockatlas.TxPage{testTx2}, true}, + {"tx multiple token tx", args{ + tx: baseTransferTx, + srcTx: multipleTx, + token: "AERGO-46B", + address: "", + }, blockatlas.TxPage{testTokenTx}, true}, + {"test multiple tx fail", args{ + tx: baseTransferTx, + srcTx: multipleTwiceTx, + token: "AERGO-46B", + address: "", + }, blockatlas.TxPage{}, false}, + {"test multiple tx address fail", args{ + tx: baseTransferTx, + srcTx: multipleTwiceTx, + token: "AERGO-46B", + address: "tbnb1qxm48ndhmh7su0r7zgwmwkltuqgly57jdf8yf8", + }, blockatlas.TxPage{}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx Tx + err := json.Unmarshal([]byte(tt.args.srcTx), &srcTx) + assert.Nil(t, err) + got, got1 := normalizeTransfer(tt.args.tx, srcTx, tt.args.token, tt.args.address) + assert.Equal(t, tt.want, got) + assert.Equal(t, tt.want1, got1) + }) + } +} diff --git a/platform/binance/client.go b/platform/binance/client.go index a7bac1d2c..5a2cb2500 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -43,6 +43,11 @@ func (c *Client) GetTxsOfAddress(address string, token string) (*TxPage, error) return stx, err } +func (c *Client) GetTx(hash string) (stx Tx, err error) { + err = c.Get(&stx, "tx", url.Values{"txHash": {hash}}) + return +} + func getHTTPError(res *http.Response, desc string) error { switch res.StatusCode { case http.StatusBadRequest: diff --git a/platform/binance/model.go b/platform/binance/model.go index 168a58f8d..15df6c3ef 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/numbers" "math" "strconv" "strings" @@ -64,6 +65,89 @@ type Tx struct { Hash string `json:"txHash"` Value json.Number `json:"value"` Memo string `json:"memo"` + HasChildren int `json:"hasChildren"` + SubTxsDto SubTxsDto `json:"subTxsDto"` +} + +type SubTxsDto struct { + TotalNum uint `json:"totalNum"` + SubTxDtoList SubTxs `json:"subTxDtoList"` +} + +type SubTx struct { + Hash string `json:"hash"` + Height uint64 `json:"height"` + Type TxType `json:"type"` + Value json.Number `json:"value"` + Asset string `json:"asset"` + FromAddr string `json:"fromAddr"` + ToAddr string `json:"toAddr"` + Fee json.Number `json:"fee"` +} + +type SubTxs []SubTx + +func (subTxs *SubTxs) getTxs() (txs []Tx) { + mapTx := map[string]Tx{} + for _, subTx := range *subTxs { + key := subTx.ToAddr + subTx.Asset + tx, ok := mapTx[key] + if !ok { + mapTx[key] = subTx.toTx() + continue + } + txValue, err := tx.Value.Float64() + if err != nil { + txValue = 0 + } + subTxValue, err := subTx.Value.Float64() + if err != nil { + subTxValue = 0 + } + value := strconv.FormatFloat(txValue+subTxValue, 'f', -1, 64) + tx.Value = json.Number(value) + mapTx[key] = tx + } + for _, tx := range mapTx { + txs = append(txs, tx) + } + return +} + +func (subTx *SubTx) toTx() Tx { + return Tx{ + Hash: subTx.Hash, + BlockHeight: subTx.Height, + Type: TxTransfer, + FromAddr: subTx.FromAddr, + ToAddr: subTx.ToAddr, + Asset: subTx.Asset, + Fee: subTx.Fee, + Value: subTx.Value, + HasChildren: 0, + } +} + +func (tx *Tx) containAddress(address string) bool { + if len(address) == 0 { + return true + } + if tx.FromAddr == address { + return true + } + if tx.ToAddr == address { + return true + } + return false +} + +func (tx *Tx) getFee() string { + fee := "0" + feeNumber, err := tx.Fee.Float64() + if err == nil && feeNumber > 0 { + fee = numbers.DecimalExp(string(tx.Fee), 8) + } + return fee } func (tx *Tx) getData() (Data, error) { diff --git a/platform/binance/model_test.go b/platform/binance/model_test.go index 3bba11e05..fabaa16a5 100644 --- a/platform/binance/model_test.go +++ b/platform/binance/model_test.go @@ -1,7 +1,9 @@ package binance import ( + "encoding/json" "github.com/stretchr/testify/assert" + "sort" "testing" "time" ) @@ -197,3 +199,155 @@ func Test_isZeroBalance(t *testing.T) { }) } } + +var ( + subTxDst = SubTx{ + Hash: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", + Height: 63591484, + Type: "TRANSFER", + Value: "0.00000001", + Asset: "BNB", + FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + Fee: "0.0006", + } + subTxTokenDst = SubTx{ + Hash: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", + Height: 63591485, + Type: "TRANSFER", + Value: "0.000064", + Asset: "AERGO-46B", + FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + Fee: "0.0006", + } + txDst = Tx{ + Hash: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", + BlockHeight: 63591484, + Type: "TRANSFER", + Value: "0.00000001", + Asset: "BNB", + FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + Fee: "0.0006", + } + txTokenDst = Tx{ + Hash: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", + BlockHeight: 63591485, + Type: "TRANSFER", + Value: "0.000064", + Asset: "AERGO-46B", + FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + Fee: "0.0006", + } +) + +func TestSubTx_toTx(t *testing.T) { + tests := []struct { + name string + subTx SubTx + want Tx + }{ + {"test conversion subTx to Tx", subTxTokenDst, + Tx{ + Hash: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", + BlockHeight: 63591485, + Type: TxTransfer, + FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + Asset: "AERGO-46B", + Fee: "0.0006", + Value: "0.000064", + SubTxsDto: SubTxsDto{}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.subTx.toTx() + assert.Equal(t, tt.want, got, "conversion failed") + }) + } +} + +func TestSubTxs_getTxs(t *testing.T) { + txDuplicatedTokenDst := txTokenDst + txDuplicatedTokenDst.Value = "0.000128" + txDuplicatedDst := txDst + txDuplicatedDst.Value = "0.00000002" + tests := []struct { + name string + subTxs SubTxs + wantTxs []Tx + }{ + {"test empty", SubTxs{}, nil}, + {"test subTx transfer", SubTxs{subTxDst}, []Tx{txDst}}, + {"test subTx token transfer", SubTxs{subTxTokenDst}, []Tx{txTokenDst}}, + {"test subTx and token transfer", SubTxs{subTxDst, subTxTokenDst}, []Tx{txDst, txTokenDst}}, + {"test duplicate subTx token transfer", SubTxs{subTxTokenDst, subTxTokenDst}, []Tx{txDuplicatedTokenDst}}, + {"test duplicate subTx", SubTxs{subTxDst, subTxDst}, []Tx{txDuplicatedDst}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotTxs := tt.subTxs.getTxs() + sort.Slice(gotTxs, func(i, j int) bool { + return gotTxs[i].BlockHeight < gotTxs[j].BlockHeight + }) + assert.Equal(t, tt.wantTxs, gotTxs, "get txs from subTxs failed") + }) + } +} + +func TestTx_containAddress(t *testing.T) { + type fields struct { + FromAddr string + ToAddr string + } + tests := []struct { + name string + fields fields + address string + want bool + }{ + {"test from address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", true}, + {"test to address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", true}, + {"test no address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "tbnb1qxm48ndhmh7su0r7zgwmwkltuqgly57jdf8yf8", false}, + {"test empty address", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "", true}, + {"test empty address without from", fields{FromAddr: "", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "", true}, + {"test empty address without to", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: ""}, "", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tx := &Tx{ + FromAddr: tt.fields.FromAddr, + ToAddr: tt.fields.ToAddr, + } + if got := tx.containAddress(tt.address); got != tt.want { + t.Errorf("containAddress() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestTx_getFee(t *testing.T) { + tests := []struct { + name string + fee json.Number + want string + }{ + {"test empty", json.Number(""), "0"}, + {"test error", json.Number("test"), "0"}, + {"test float 1", json.Number("444.5"), "44450000000"}, + {"test float 2", json.Number("0.00000001"), "1"}, + {"test int", json.Number("3"), "300000000"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tx := &Tx{Fee: tt.fee} + if got := tx.getFee(); got != tt.want { + t.Errorf("getFee() = %v, want %v", got, tt.want) + } + }) + } +} From 4182337ded41faa767e79057da1cc0ad27ae4249 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 2 Feb 2020 21:36:21 +0300 Subject: [PATCH 063/506] Remove Outdated Docker Hub link (#792) --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index dabc5c36c..e9ab47fc9 100644 --- a/README.md +++ b/README.md @@ -65,11 +65,6 @@ go build -o syncmarkets-bin cmd/syncmarkets/main.go && ./syncmarkets-bin -c conf ### Docker - -From Docker Hub: - -`docker run -it -p 8420:8420 trustwallet/blockatlas` - Build and run from local Dockerfile: You should change `config.yml`: From f7546d9554b643bfc3af65622ab8c2c1255b381d Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 2 Feb 2020 21:36:44 +0300 Subject: [PATCH 064/506] Add Dockerfile for Rancher builds (#793) --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 971d3931c..dbb9cfecc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,8 +9,8 @@ RUN go build -o bin/blockatlas ./cmd/$SERVICE FROM debian:latest COPY --from=builder /build/bin /app/bin/$SERVICE -COPY --from=builder /build/config.yml / +COPY --from=builder /build/config.yml /config/ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ WORKDIR /app/bin/$SERVICE -ENTRYPOINT ["/app/bin/blockatlas"] +ENTRYPOINT ["/app/bin/blockatlas", "-c", "/config/config.yml"] From 502818e626045057bfe7af52aae22cfceb38bdf2 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 2 Feb 2020 22:07:04 +0300 Subject: [PATCH 065/506] requested changes (#764) --- config.yml | 2 +- pkg/tests/integration/integration_test.go | 44 ++++- platform/ontology/api.go | 185 +++++++++++++++------- platform/ontology/api_test.go | 151 +++++++++++++++++- platform/ontology/client.go | 60 +++++-- platform/ontology/model.go | 30 ++++ 6 files changed, 389 insertions(+), 83 deletions(-) diff --git a/config.yml b/config.yml index caa0a88e6..cfc1d7e92 100644 --- a/config.yml +++ b/config.yml @@ -144,7 +144,7 @@ cosmos: # [ONTOLOGY] ONT: https://ont.io/ ontology: - api: https://explorer.ont.io/api/v1/explorer + api: https://explorer.ont.io # [ZIL] Zilliqa: https://zilliqa.com zilliqa: diff --git a/pkg/tests/integration/integration_test.go b/pkg/tests/integration/integration_test.go index 83d4689f1..19639c2e4 100755 --- a/pkg/tests/integration/integration_test.go +++ b/pkg/tests/integration/integration_test.go @@ -13,23 +13,37 @@ import ( var ( testBlock = blockatlas.Block{ - Number: 7677564, - ID: "168d35ae9333f1d53ee0c124b44d268701df001df1313b388d001a5808f66d01", + Number: 7707834, + ID: "a5f3ee1a102df7196bb1e262a05435f260392fae6be676ae2c0a6147f8ecf94c", Txs: []blockatlas.Tx{ { - ID: "736fab4fa13435f201bc90a43ca5cd8c324ec88d6048fedb136f267371daee39", - Block: 7677564, + ID: "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb", + Block: 7707834, Status: blockatlas.StatusCompleted, - Date: 1580115134, + Date: 1580481541, Coin: coin.Ontology().ID, + Meta: blockatlas.NativeTokenTransfer{ + Name: "Ontology Gas", + Symbol: "ONG", + TokenID: "ong", + Decimals: 9, + Value: "51000000000000", + From: "AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE", + To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + }, }, }, } - blockNum = 7677564 + blockNum = 7707834 ) func TestOntology(t *testing.T) { - config.LoadConfig(os.Getenv("TEST_CONFIG")) + configPath := os.Getenv("TEST_CONFIG") + if configPath == "" { + config.LoadConfig("../../../config.yml") + } else { + config.LoadConfig(configPath) + } p := &ontology.Platform{} _ = p.Init() testCurrentBlockNumber(p, t) @@ -54,12 +68,26 @@ func testGetBlockByNumber(p *ontology.Platform, t *testing.T) { isSame := resp.ID == testBlock.ID && resp.Number == testBlock.Number && - resp.Txs[0].ID == testBlock.Txs[0].ID && resp.Txs[0].Block == testBlock.Txs[0].Block && resp.Txs[0].Status == testBlock.Txs[0].Status && resp.Txs[0].Date == testBlock.Txs[0].Date && resp.Txs[0].Coin == testBlock.Txs[0].Coin + if isSame { + // check that we have tx hashes of parsed block + for _, tx := range resp.Txs { + switch tx.ID { + case "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3": + isSame = true + case "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb": + isSame = true + case "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd": + isSame = true + default: + isSame = false + } + } + } if !isSame { t.Error("Block is not the same") } diff --git a/platform/ontology/api.go b/platform/ontology/api.go index dd3753db0..63dd4351a 100644 --- a/platform/ontology/api.go +++ b/platform/ontology/api.go @@ -3,11 +3,12 @@ package ontology import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "strings" + "sync" ) type Platform struct { @@ -18,6 +19,7 @@ const ( GovernanceContract = "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK" ONTAssetName = "ont" ONGAssetName = "ong" + ONGDecimals = 9 ) func (p *Platform) Init() error { @@ -44,17 +46,43 @@ func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatla return blockatlas.TxPage{}, err } var txs []blockatlas.Tx - for _, srcTx := range txPage.Result.TxnList { - tx, ok := Normalize(&srcTx, token) + for _, txOntV1 := range txPage.Result.TxnList { + tx, ok := Normalize(txOntV1, token) if !ok { continue } - txs = append(txs, tx) + txs = append(txs, *tx) } return txs, nil } +func Normalize(txOntV1 Tx, assetName string) (tx *blockatlas.Tx, ok bool) { + if len(txOntV1.TransferList) < 1 { + return tx, false + } + transfer := txOntV1.TransferList[0] + fee := numbers.DecimalExp(txOntV1.Fee, ONGDecimals) + tx = &blockatlas.Tx{ + ID: txOntV1.TxnHash, + Coin: coin.ONT, + Date: txOntV1.TxnTime, + Block: txOntV1.Height, + Status: getTransactionStatus(int(txOntV1.ConfirmFlag)), + Fee: blockatlas.Amount(fee), + } + + switch assetName { + case ONTAssetName: + normalizeONT(tx, transfer) + case ONGAssetName: + normalizeONG(tx, transfer) + default: // unsupported asset + return tx, false + } + return tx, true +} + func (p *Platform) CurrentBlockNumber() (int64, error) { block, err := p.client.CurrentBlockNumber() if err != nil { @@ -62,9 +90,6 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { return 0, err } var height int64 - if block.Error != 0 { - err = errors.E("explorer error") - } if len(block.Result) > 0 { height = (int64)(block.Result[0].Height) } @@ -72,72 +97,118 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { } func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - response, err := p.client.GetBlockByNumber(num) + blockOnt, err := p.client.GetBlockByNumber(num) + if err != nil { + return nil, err + } + txsRaw, err := p.getTxDetails(blockOnt.Result.TxnList) if err != nil { - logger.Error("GetBlockByNumber", logger.Params{"platform": p.Coin().Symbol, "details": err.Error()}) return nil, err } - var ( - block blockatlas.Block - txs []blockatlas.Tx - ) - if response.Error == 0 { - block.ID = response.Result.Hash - block.Number = int64(response.Result.Height) - for _, txn := range response.Result.TxnList { - tx := new(blockatlas.Tx) - tx.ID = txn.TxnHash - tx.Block = uint64(txn.Height) - if txn.ConfirmFlag == 1 { - tx.Status = blockatlas.StatusCompleted + + block := normalizeBlock(*blockOnt, txsRaw) + return block, nil +} + +func (p *Platform) getTxDetails(txsOntV1 []Tx) ([]TxV2, error) { + var wg sync.WaitGroup + txsOntV2Chan := make(chan TxV2, len(txsOntV1)) + wg.Add(len(txsOntV1)) + for _, blockTxRaw := range txsOntV1 { + go func(blockTxRaw Tx, wg *sync.WaitGroup) { + defer wg.Done() + txRaw, err := p.client.GetTxDetailsByHash(blockTxRaw.TxnHash) + if err == nil { + txsOntV2Chan <- *txRaw } - tx.Date = int64(txn.TxnTime) - tx.Coin = coin.Ontology().ID - txs = append(txs, *tx) + }(blockTxRaw, &wg) + } + wg.Wait() + close(txsOntV2Chan) + if len(txsOntV2Chan) != len(txsOntV1) { + return nil, errors.E("getTxDetails failed to call client.GetTxDetailsByHash http get or unmarshal") + } + var txsOntV2 []TxV2 + for tx := range txsOntV2Chan { + if len(tx.Details.Transfers) > 0 { + txsOntV2 = append(txsOntV2, tx) } - block.Txs = txs } - - return &block, nil + return txsOntV2, nil } -func Normalize(srcTx *Tx, assetName string) (tx blockatlas.Tx, ok bool) { - if len(srcTx.TransferList) < 1 { - return tx, false +func normalizeBlock(blockOnt BlockResult, txsOntV2 []TxV2) *blockatlas.Block { + block := blockatlas.Block{ + Number: int64(blockOnt.Result.Height), + ID: blockOnt.Result.Hash, } - transfer := srcTx.TransferList[0] - fee := numbers.DecimalExp(srcTx.Fee, 9) - var status blockatlas.Status - if srcTx.ConfirmFlag == 1 { - status = blockatlas.StatusCompleted - } else { - status = blockatlas.StatusFailed + if len(txsOntV2) > 0 { + block.Txs = normalizeBlockTransactions(txsOntV2) } + return &block +} - tx = blockatlas.Tx{ - ID: srcTx.TxnHash, +func normalizeBlockTransactions(txsOntV2 []TxV2) []blockatlas.Tx { + var txs []blockatlas.Tx + for _, txOntV2 := range txsOntV2 { + tx, ok := normalizeBlockTransaction(txOntV2) + if !ok { + continue + } + txs = append(txs, *tx) + } + return txs +} + +func normalizeBlockTransaction(txsOntV2 TxV2) (*blockatlas.Tx, bool) { + fee := numbers.DecimalExp(txsOntV2.Fee, ONGDecimals) + tx := blockatlas.Tx{ + ID: txsOntV2.Hash, Coin: coin.ONT, + Date: txsOntV2.Time, + Block: txsOntV2.BlockHeight, + Status: getTransactionStatus(txsOntV2.ConfirmFlag), Fee: blockatlas.Amount(fee), - Date: srcTx.TxnTime, - Block: srcTx.Height, - Status: status, } - - switch assetName { - case ONTAssetName: - normalizeONT(&tx, &transfer) - case ONGAssetName: - normalizeONG(&tx, &transfer) - default: // unsupported asset - return tx, false + ok := false + if len(txsOntV2.Details.Transfers) > 0 { + txDetails := txsOntV2.Details.Transfers[0] + ok = true + switch txDetails.AssetName { + case ONTAssetName: + normalizeONT(&tx, Transfer{ + Amount: txDetails.Amount, + FromAddress: txDetails.FromAddress, + ToAddress: txDetails.ToAddress, + }) + case ONGAssetName: + normalizeONG(&tx, Transfer{ + Amount: txDetails.Amount, + FromAddress: txDetails.FromAddress, + ToAddress: txDetails.ToAddress, + }) + default: // unsupported asset + return &tx, false + } } + return &tx, ok +} - return tx, true +func getTransactionStatus(confirmFlag int) blockatlas.Status { + if confirmFlag == 1 { + return blockatlas.StatusCompleted + } + return blockatlas.StatusFailed } -func normalizeONT(tx *blockatlas.Tx, transfer *Transfer) { +func normalizeONT(tx *blockatlas.Tx, transfer Transfer) { i := strings.IndexRune(transfer.Amount, '.') - value := transfer.Amount[:i] + var value string + if i > 0 { + value = transfer.Amount[:i] + } else { + value = transfer.Amount + } tx.From = transfer.FromAddress tx.To = transfer.ToAddress @@ -149,12 +220,12 @@ func normalizeONT(tx *blockatlas.Tx, transfer *Transfer) { } } -func normalizeONG(tx *blockatlas.Tx, transfer *Transfer) { +func normalizeONG(tx *blockatlas.Tx, transfer Transfer) { var value string if transfer.ToAddress == GovernanceContract { value = "0" } else { - value = numbers.DecimalExp(transfer.Amount, 9) + value = numbers.DecimalExp(transfer.Amount, ONGDecimals) } from := transfer.FromAddress @@ -166,7 +237,7 @@ func normalizeONG(tx *blockatlas.Tx, transfer *Transfer) { Name: "Ontology Gas", Symbol: "ONG", TokenID: "ong", - Decimals: 9, + Decimals: ONGDecimals, Value: blockatlas.Amount(value), From: from, To: to, diff --git a/platform/ontology/api_test.go b/platform/ontology/api_test.go index 146f4756a..5d00208c3 100644 --- a/platform/ontology/api_test.go +++ b/platform/ontology/api_test.go @@ -3,6 +3,7 @@ package ontology import ( "bytes" "encoding/json" + "github.com/magiconair/properties/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" @@ -144,22 +145,23 @@ func TestNormalize(t *testing.T) { } for _, test := range tests { - var sourceTx Tx + var ( + sourceTx Tx + ok bool + ) tErr := json.Unmarshal([]byte(test.Transaction), &sourceTx) if tErr != nil { t.Fatal("Ontology: Can't unmarshal transaction", tErr) } - var tx blockatlas.Tx - var ok bool - tx, ok = Normalize(&sourceTx, test.AssetName) + tx, ok := Normalize(sourceTx, test.AssetName) if !ok { t.Fatal("Ontology: Can't normalize transaction") } - actual, err := json.Marshal(&tx) + actual, err := json.Marshal(tx) if err != nil { t.Fatal(err) } @@ -176,3 +178,142 @@ func TestNormalize(t *testing.T) { } } } + +var ( + ontBlockResult = BlockResult{ + Error: 0, + Result: Block{ + Height: 7707834, + TxnList: []Tx{ + { + TxnHash: "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb", + ConfirmFlag: 1, + TxnTime: 1580481541, + Height: 7707834, + }, + { + TxnHash: "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd", + ConfirmFlag: 1, + TxnTime: 1580481541, + Height: 7707834, + }, + { + TxnHash: "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3", + ConfirmFlag: 1, + TxnTime: 1580481541, + Height: 7707834, + }, + }, + Hash: "a5f3ee1a102df7196bb1e262a05435f260392fae6be676ae2c0a6147f8ecf94c", + }, + } +) + +var ( + ontTxResp1 = TxResponse{ + Code: 0, + Msg: "SUCCESS", + Result: TxV2{ + Hash: "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb", + Type: 209, + Time: 1580481541, + BlockHeight: 7707834, + Fee: "0.01", + Description: "transfer", + BlockIndex: 2, + ConfirmFlag: 1, + EventType: 3, + Details: TransactionDetails{ + Transfers: []TransferDetails{ + { + Amount: "51000", + AssetName: "ong", + FromAddress: "AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE", + ToAddress: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + }, + { + Amount: "0.01", + AssetName: "ong", + FromAddress: "ANKXUWXy6XrhQvqbjhKJPH9AnLa2CuEMRK", + ToAddress: "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + }, + }, + }, + }, + } + + ontTxResp2 = TxResponse{ + Code: 0, + Msg: "SUCCESS", + Result: TxV2{ + Hash: "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd", + Type: 209, + Time: 1580481541, + BlockHeight: 7707834, + Fee: "0.01", + Description: "transfer", + BlockIndex: 3, + ConfirmFlag: 1, + EventType: 3, + Details: TransactionDetails{ + Transfers: []TransferDetails{ + { + Amount: "113.2", + AssetName: "ong", + FromAddress: "ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz", + ToAddress: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + }, + { + Amount: "0.01", + AssetName: "ong", + FromAddress: "ANKXUWXy6XrhQvqbjhKJPH9AnLa2CuEMRK", + ToAddress: "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + }, + }, + }, + }, + } + + ontTxResp3 = TxResponse{ + Code: 0, + Msg: "SUCCESS", + Result: TxV2{ + Hash: "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3", + Type: 209, + Time: 1580481541, + BlockHeight: 7707834, + Fee: "0.01", + Description: "transfer", + BlockIndex: 1, + ConfirmFlag: 1, + EventType: 3, + Details: TransactionDetails{ + Transfers: []TransferDetails{ + { + Amount: "10949", + AssetName: "ong", + FromAddress: "Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS", + ToAddress: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + }, { + Amount: "0.01", + AssetName: "ong", + FromAddress: "ANKXUWXy6XrhQvqbjhKJPH9AnLa2CuEMRK", + ToAddress: "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + }, + }, + }, + }, + } +) + +func TestNormalizeBlock(t *testing.T) { + block := normalizeBlock(ontBlockResult, []TxV2{ontTxResp1.Result, ontTxResp2.Result, ontTxResp3.Result}) + got, err := json.Marshal(block) + if err != nil { + t.Fatal(err) + } + + want := `{"number":7707834,"id":"a5f3ee1a102df7196bb1e262a05435f260392fae6be676ae2c0a6147f8ecf94c","txs":[{"id":"266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb","coin":1024,"from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"native_token_transfer","memo":"","metadata":{"name":"Ontology Gas","symbol":"ONG","token_id":"ong","decimals":9,"value":"51000000000000","from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx"}},{"id":"2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd","coin":1024,"from":"ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"native_token_transfer","memo":"","metadata":{"name":"Ontology Gas","symbol":"ONG","token_id":"ong","decimals":9,"value":"113200000000","from":"ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx"}},{"id":"40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3","coin":1024,"from":"Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"native_token_transfer","memo":"","metadata":{"name":"Ontology Gas","symbol":"ONG","token_id":"ong","decimals":9,"value":"10949000000000","from":"Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx"}}]}` + + assert.Equal(t, string(got), want) +} diff --git a/platform/ontology/client.go b/platform/ontology/client.go index a48443e6d..dfa9782ff 100644 --- a/platform/ontology/client.go +++ b/platform/ontology/client.go @@ -3,6 +3,7 @@ package ontology import ( "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" ) type Client struct { @@ -15,20 +16,55 @@ const ( requestOnlyLatestBlockAmount = 1 ) -func (c *Client) GetTxsOfAddress(address, assetName string) (txPage *TxPage, err error) { - url := fmt.Sprintf("address/%s/%s/%d/1", address, assetName, TxPerPage) - err = c.Get(&txPage, url, nil) - return +func (c *Client) GetTxsOfAddress(address, assetName string) (*TxPage, error) { + url := fmt.Sprintf("api/v1/explorer/address/%s/%s/%d/1", address, assetName, TxPerPage) + var txPage TxPage + err := c.Get(&txPage, url, nil) + if err != nil { + return nil, err + } + return &txPage, nil } -func (c *Client) CurrentBlockNumber() (response *BlockResults, err error) { - url := fmt.Sprintf("blocklist/%d", requestOnlyLatestBlockAmount) - err = c.Get(&response, url, nil) - return +func (c *Client) CurrentBlockNumber() (*BlockResults, error) { + url := fmt.Sprintf("api/v1/explorer/blocklist/%d", requestOnlyLatestBlockAmount) + var response BlockResults + err := c.Get(&response, url, nil) + if err != nil { + return nil, err + } + if response.Error != 0 { + return nil, errors.E("explorer client CurrentBlockNumber", errors.Params{"platform": "ONT"}) + } + return &response, nil } -func (c *Client) GetBlockByNumber(num int64) (block *BlockResult, err error) { - url := fmt.Sprintf("block/%d", num) - err = c.Get(&block, url, nil) - return +func (c *Client) GetBlockByNumber(num int64) (*BlockResult, error) { + url := fmt.Sprintf("api/v1/explorer/block/%d", num) + var block BlockResult + err := c.Get(&block, url, nil) + if err != nil { + return nil, err + } + if block.Error != 0 { + return nil, errors.E("explorer client GetBlockByNumber", errors.Params{"platform": "ONT"}) + } + return &block, nil +} + +func (c *Client) GetTxDetailsByHash(hash string) (*TxV2, error) { + url := fmt.Sprintf("v2/transactions/%s", hash) + var response TxResponse + err := c.Get(&response, url, nil) + if err != nil { + return nil, err + } + if response.Msg != "SUCCESS" { + return nil, errors.E("explorer client GetTxDetailsByHash", errors.Params{"platform": "ONT"}) + } + var ontTxV2 TxV2 + if response.Result.EventType == 3 { + ontTxV2 = response.Result + } + return &ontTxV2, nil } diff --git a/platform/ontology/model.go b/platform/ontology/model.go index b51e5b6ec..2d2515bd3 100644 --- a/platform/ontology/model.go +++ b/platform/ontology/model.go @@ -41,3 +41,33 @@ type Block struct { TxnList []Tx `json:"TxnList"` Hash string `json:"Hash"` } + +type TxResponse struct { + Code int `json:"code"` + Msg string `json:"msg"` + Result TxV2 `json:"Result"` +} + +type TxV2 struct { + Hash string `json:"tx_hash"` + Type int `json:"tx_type"` + Time int64 `json:"tx_time"` + BlockHeight uint64 `json:"block_height"` + Fee string `json:"fee"` + Description string `json:"description"` + BlockIndex int `json:"block_index"` + ConfirmFlag int `json:"confirm_flag"` + EventType int `json:"event_type"` + Details TransactionDetails `json:"detail"` +} + +type TransactionDetails struct { + Transfers []TransferDetails `json:"transfers"` +} + +type TransferDetails struct { + Amount string `json:"amount"` + AssetName string `json:"asset_name"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` +} From d811afbb51ff5c037acc08b33570660218d03ddd Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 3 Feb 2020 10:48:20 -0300 Subject: [PATCH 066/506] [ontology] add claim reward tx (#789) * add reward tx * use v2 api instead v1 * fix ont parsers * fix tests --- coin/coins.go | 4 +- coin/coins.yml | 1 + pkg/tests/integration/integration_test.go | 83 +++-- platform/ontology/api.go | 253 ++++++-------- platform/ontology/api_test.go | 407 ++++++++++------------ platform/ontology/client.go | 79 ++--- platform/ontology/model.go | 155 +++++--- platform/ontology/model_test.go | 130 +++++++ 8 files changed, 622 insertions(+), 490 deletions(-) create mode 100644 platform/ontology/model_test.go diff --git a/coin/coins.go b/coin/coins.go index ba8a4869c..cda0cb6b0 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2020-01-29 11:37:10.990661 -0800 PST m=+0.055502727 +// 2020-02-02 17:57:53.145329 -0300 -03 m=+0.001556851 // using data from coins.yml package coin @@ -290,7 +290,7 @@ var Coins = map[uint]Coin{ Symbol: "ONT", Name: "Ontology", Decimals: 0, - BlockTime: 0, + BlockTime: 10000, MinConfirmations: 0, SampleAddr: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", }, diff --git a/coin/coins.yml b/coin/coins.yml index 7d965abeb..8b2a59822 100644 --- a/coin/coins.yml +++ b/coin/coins.yml @@ -169,6 +169,7 @@ handle: ontology name: Ontology decimals: 0 + blockTime: 10000 sampleAddress: 'AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7' - id: 1729 diff --git a/pkg/tests/integration/integration_test.go b/pkg/tests/integration/integration_test.go index 19639c2e4..f09b8c7d9 100755 --- a/pkg/tests/integration/integration_test.go +++ b/pkg/tests/integration/integration_test.go @@ -14,22 +14,63 @@ import ( var ( testBlock = blockatlas.Block{ Number: 7707834, - ID: "a5f3ee1a102df7196bb1e262a05435f260392fae6be676ae2c0a6147f8ecf94c", Txs: []blockatlas.Tx{ { + From: "AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE", + To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", ID: "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb", + Fee: "10000000", Block: 7707834, Status: blockatlas.StatusCompleted, Date: 1580481541, Coin: coin.Ontology().ID, - Meta: blockatlas.NativeTokenTransfer{ - Name: "Ontology Gas", + Type: blockatlas.TxNativeTokenTransfer, + Meta: blockatlas.AnyAction{ + Name: "Claim Rewards", Symbol: "ONG", TokenID: "ong", Decimals: 9, Value: "51000000000000", - From: "AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE", - To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + }, + }, { + From: "ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz", + To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + ID: "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd", + Fee: "10000000", + Block: 7707834, + Status: blockatlas.StatusCompleted, + Date: 1580481541, + Coin: coin.Ontology().ID, + Type: blockatlas.TxNativeTokenTransfer, + Meta: blockatlas.AnyAction{ + Name: "Claim Rewards", + Symbol: "ONG", + TokenID: "ong", + Decimals: 9, + Value: "113200000000", + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + }, + }, { + From: "Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS", + To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + ID: "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3", + Fee: "10000000", + Block: 7707834, + Status: blockatlas.StatusCompleted, + Date: 1580481541, + Coin: coin.Ontology().ID, + Type: blockatlas.TxNativeTokenTransfer, + Meta: blockatlas.AnyAction{ + Name: "Claim Rewards", + Symbol: "ONG", + TokenID: "ong", + Decimals: 9, + Value: "10949000000000", + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, }, }, }, @@ -66,29 +107,25 @@ func testGetBlockByNumber(p *ontology.Platform, t *testing.T) { t.Error(err) } - isSame := resp.ID == testBlock.ID && - resp.Number == testBlock.Number && + isSame := resp.Number == testBlock.Number && resp.Txs[0].Block == testBlock.Txs[0].Block && resp.Txs[0].Status == testBlock.Txs[0].Status && resp.Txs[0].Date == testBlock.Txs[0].Date && resp.Txs[0].Coin == testBlock.Txs[0].Coin + if !isSame { + t.Errorf("Block is not the same") + } - if isSame { - // check that we have tx hashes of parsed block - for _, tx := range resp.Txs { - switch tx.ID { - case "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3": - isSame = true - case "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb": - isSame = true - case "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd": - isSame = true - default: - isSame = false - } - } + // check that we have tx hashes of parsed block + txMap := map[string]bool{} + for _, tx := range resp.Txs { + txMap[tx.ID] = true } - if !isSame { - t.Error("Block is not the same") + delete(txMap, "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3") + delete(txMap, "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb") + delete(txMap, "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd") + + if len(txMap) > 0 { + t.Errorf("Block is not the same: %v", txMap) } } diff --git a/platform/ontology/api.go b/platform/ontology/api.go index 63dd4351a..6213e634e 100644 --- a/platform/ontology/api.go +++ b/platform/ontology/api.go @@ -7,7 +7,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" - "strings" "sync" ) @@ -15,13 +14,6 @@ type Platform struct { client Client } -const ( - GovernanceContract = "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK" - ONTAssetName = "ont" - ONGAssetName = "ong" - ONGDecimals = 9 -) - func (p *Platform) Init() error { p.client = Client{blockatlas.InitClient(viper.GetString("ontology.api"))} return nil @@ -32,11 +24,11 @@ func (p *Platform) Coin() coin.Coin { } func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - return p.GetTokenTxsByAddress(address, ONTAssetName) + return p.GetTokenTxsByAddress(address, string(AssetONT)) } func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { - txPage, err := p.client.GetTxsOfAddress(address, token) + srcTxs, err := p.client.GetTxsOfAddress(address) if err != nil { logger.Error(err, "Ontology: Failed to get transactions for address and token", logger.Params{ @@ -45,55 +37,99 @@ func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatla }) return blockatlas.TxPage{}, err } - var txs []blockatlas.Tx - for _, txOntV1 := range txPage.Result.TxnList { - tx, ok := Normalize(txOntV1, token) - if !ok { - continue - } - txs = append(txs, *tx) - } - - return txs, nil + txPage := normalizeTxs(srcTxs.Result, AssetType(token)) + return txPage, nil } -func Normalize(txOntV1 Tx, assetName string) (tx *blockatlas.Tx, ok bool) { - if len(txOntV1.TransferList) < 1 { +func Normalize(srcTx *Tx, assetName AssetType) (tx blockatlas.Tx, ok bool) { + if len(srcTx.getTransfers()) < 1 { return tx, false } - transfer := txOntV1.TransferList[0] - fee := numbers.DecimalExp(txOntV1.Fee, ONGDecimals) - tx = &blockatlas.Tx{ - ID: txOntV1.TxnHash, + fee := numbers.DecimalExp(srcTx.Fee, ONGDecimals) + status := blockatlas.StatusCompleted + if srcTx.ConfirmFlag != 1 { + status = blockatlas.StatusFailed + } + tx = blockatlas.Tx{ + ID: srcTx.Hash, Coin: coin.ONT, - Date: txOntV1.TxnTime, - Block: txOntV1.Height, - Status: getTransactionStatus(int(txOntV1.ConfirmFlag)), Fee: blockatlas.Amount(fee), + Date: srcTx.Time, + Block: srcTx.Height, + Status: status, } switch assetName { - case ONTAssetName: - normalizeONT(tx, transfer) - case ONGAssetName: - normalizeONG(tx, transfer) - default: // unsupported asset + case AssetONT: + return normalizeONT(tx, srcTx.getTransfers()) + case AssetONG: + return normalizeONG(tx, srcTx.getTransfers()) + } + return tx, false +} + +func normalizeONT(tx blockatlas.Tx, transfers Transfers) (blockatlas.Tx, bool) { + transfer := transfers.getTransfer(AssetONT) + if transfer == nil { return tx, false } + tx.From = transfer.FromAddress + tx.To = transfer.ToAddress + tx.Type = blockatlas.TxTransfer + tx.Meta = blockatlas.Transfer{ + Value: blockatlas.Amount(transfer.Amount), + Symbol: coin.Ontology().Symbol, + Decimals: coin.Ontology().Decimals, + } + return tx, true +} + +func normalizeONG(tx blockatlas.Tx, transfers Transfers) (blockatlas.Tx, bool) { + transfer := transfers.getTransfer(AssetONG) + if transfer == nil { + return tx, false + } + from := transfer.FromAddress + to := transfer.ToAddress + tx.From = from + tx.To = to + value := numbers.DecimalExp(transfer.Amount, ONGDecimals) + if transfers.isClaimReward() { + tx.Type = blockatlas.TxAnyAction + tx.Meta = blockatlas.AnyAction{ + Coin: coin.Ontology().ID, + Name: "Ontology Gas", + Symbol: "ONG", + TokenID: string(AssetONG), + Decimals: ONGDecimals, + Value: blockatlas.Amount(value), + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + } + return tx, true + } + tx.Type = blockatlas.TxNativeTokenTransfer + tx.Meta = blockatlas.NativeTokenTransfer{ + Name: "Ontology Gas", + Symbol: "ONG", + TokenID: string(AssetONG), + Decimals: ONGDecimals, + Value: blockatlas.Amount(value), + From: from, + To: to, + } return tx, true } func (p *Platform) CurrentBlockNumber() (int64, error) { block, err := p.client.CurrentBlockNumber() if err != nil { - logger.Error("CurrentBlockNumber", logger.Params{"platform": p.Coin().Symbol, "details": err.Error()}) - return 0, err + return 0, errors.E(err, "CurrentBlockNumber") } - var height int64 - if len(block.Result) > 0 { - height = (int64)(block.Result[0].Height) + if len(block.Result.Records) == 0 { + return 0, errors.E("invalid block height result") } - return height, nil + return block.Result.Records[0].Height, nil } func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { @@ -101,145 +137,56 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { if err != nil { return nil, err } - txsRaw, err := p.getTxDetails(blockOnt.Result.TxnList) + txsRaw, err := p.getTxDetails(blockOnt.Result.Txs) if err != nil { return nil, err } - - block := normalizeBlock(*blockOnt, txsRaw) - return block, nil + txs := normalizeTxs(txsRaw, AssetAll) + return &blockatlas.Block{ + Number: num, + Txs: txs, + }, nil } -func (p *Platform) getTxDetails(txsOntV1 []Tx) ([]TxV2, error) { +func (p *Platform) getTxDetails(srcTx []Tx) ([]Tx, error) { var wg sync.WaitGroup - txsOntV2Chan := make(chan TxV2, len(txsOntV1)) - wg.Add(len(txsOntV1)) - for _, blockTxRaw := range txsOntV1 { + txsOntV2Chan := make(chan Tx, len(srcTx)) + wg.Add(len(srcTx)) + for _, blockTxRaw := range srcTx { go func(blockTxRaw Tx, wg *sync.WaitGroup) { defer wg.Done() - txRaw, err := p.client.GetTxDetailsByHash(blockTxRaw.TxnHash) + txRaw, err := p.client.GetTxDetailsByHash(blockTxRaw.Hash) if err == nil { - txsOntV2Chan <- *txRaw + txsOntV2Chan <- txRaw } }(blockTxRaw, &wg) } wg.Wait() close(txsOntV2Chan) - if len(txsOntV2Chan) != len(txsOntV1) { + if len(txsOntV2Chan) != len(srcTx) { return nil, errors.E("getTxDetails failed to call client.GetTxDetailsByHash http get or unmarshal") } - var txsOntV2 []TxV2 + var txsOntV2 []Tx for tx := range txsOntV2Chan { - if len(tx.Details.Transfers) > 0 { + if len(tx.getTransfers()) > 0 { txsOntV2 = append(txsOntV2, tx) } } return txsOntV2, nil } -func normalizeBlock(blockOnt BlockResult, txsOntV2 []TxV2) *blockatlas.Block { - block := blockatlas.Block{ - Number: int64(blockOnt.Result.Height), - ID: blockOnt.Result.Hash, - } - if len(txsOntV2) > 0 { - block.Txs = normalizeBlockTransactions(txsOntV2) - } - return &block -} - -func normalizeBlockTransactions(txsOntV2 []TxV2) []blockatlas.Tx { - var txs []blockatlas.Tx - for _, txOntV2 := range txsOntV2 { - tx, ok := normalizeBlockTransaction(txOntV2) +func normalizeTxs(srcTxs []Tx, assetType AssetType) blockatlas.TxPage { + var txs blockatlas.TxPage + for _, srcTx := range srcTxs { + transfer := srcTx.getTransfers().getTransfer(assetType) + if transfer == nil { + continue + } + tx, ok := Normalize(&srcTx, transfer.AssetName) if !ok { continue } - txs = append(txs, *tx) + txs = append(txs, tx) } return txs } - -func normalizeBlockTransaction(txsOntV2 TxV2) (*blockatlas.Tx, bool) { - fee := numbers.DecimalExp(txsOntV2.Fee, ONGDecimals) - tx := blockatlas.Tx{ - ID: txsOntV2.Hash, - Coin: coin.ONT, - Date: txsOntV2.Time, - Block: txsOntV2.BlockHeight, - Status: getTransactionStatus(txsOntV2.ConfirmFlag), - Fee: blockatlas.Amount(fee), - } - ok := false - if len(txsOntV2.Details.Transfers) > 0 { - txDetails := txsOntV2.Details.Transfers[0] - ok = true - switch txDetails.AssetName { - case ONTAssetName: - normalizeONT(&tx, Transfer{ - Amount: txDetails.Amount, - FromAddress: txDetails.FromAddress, - ToAddress: txDetails.ToAddress, - }) - case ONGAssetName: - normalizeONG(&tx, Transfer{ - Amount: txDetails.Amount, - FromAddress: txDetails.FromAddress, - ToAddress: txDetails.ToAddress, - }) - default: // unsupported asset - return &tx, false - } - } - return &tx, ok -} - -func getTransactionStatus(confirmFlag int) blockatlas.Status { - if confirmFlag == 1 { - return blockatlas.StatusCompleted - } - return blockatlas.StatusFailed -} - -func normalizeONT(tx *blockatlas.Tx, transfer Transfer) { - i := strings.IndexRune(transfer.Amount, '.') - var value string - if i > 0 { - value = transfer.Amount[:i] - } else { - value = transfer.Amount - } - - tx.From = transfer.FromAddress - tx.To = transfer.ToAddress - tx.Type = blockatlas.TxTransfer - tx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(value), - Symbol: coin.Coins[coin.ONT].Symbol, - Decimals: coin.Coins[coin.ONT].Decimals, - } -} - -func normalizeONG(tx *blockatlas.Tx, transfer Transfer) { - var value string - if transfer.ToAddress == GovernanceContract { - value = "0" - } else { - value = numbers.DecimalExp(transfer.Amount, ONGDecimals) - } - - from := transfer.FromAddress - to := transfer.ToAddress - tx.From = from - tx.To = to - tx.Type = blockatlas.TxNativeTokenTransfer - tx.Meta = blockatlas.NativeTokenTransfer{ - Name: "Ontology Gas", - Symbol: "ONG", - TokenID: "ong", - Decimals: ONGDecimals, - Value: blockatlas.Amount(value), - From: from, - To: to, - } -} diff --git a/platform/ontology/api_test.go b/platform/ontology/api_test.go index 5d00208c3..2312fc520 100644 --- a/platform/ontology/api_test.go +++ b/platform/ontology/api_test.go @@ -1,230 +1,211 @@ package ontology import ( - "bytes" "encoding/json" - "github.com/magiconair/properties/assert" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" ) -var srcOntTransfer = ` +const ( + srcOntTransfer = ` { - "TxnType": 209, - "ConfirmFlag": 1, - "Fee": "0.010000000", - "BlockIndex": 2, - "TransferList": [ - { - "FromAddress": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "Amount": "2.000000000", - "ToAddress": "AQ9kzzHNLCcyrPwJuVMrSPgGzqmuQNVwMF", - "AssetName": "ont" - } - ], - "TxnTime": 1556952450, - "TxnHash": "4804e1be63ebe1715d6b4a039cc9d84b86cde74c8a8c8411578e6dcadc1e5405", - "Height": 3411115 -} -` - -var dstOntTransfer = blockatlas.Tx{ - ID: "4804e1be63ebe1715d6b4a039cc9d84b86cde74c8a8c8411578e6dcadc1e5405", - Coin: coin.ONT, - From: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - To: "AQ9kzzHNLCcyrPwJuVMrSPgGzqmuQNVwMF", - Fee: "10000000", - Date: 1556952450, - Type: "transfer", - Status: blockatlas.StatusCompleted, - Block: 3411115, - Meta: blockatlas.Transfer{ - Value: "2", - Symbol: "ONT", - Decimals: 0, - }, -} + "tx_hash": "ea0e5d8e389cb96760887094194ca359ac998b2f607be470a576861b91e2bf52", + "tx_type": 209, + "tx_time": 1578903628, + "block_height": 7571132, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "5", + "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "to_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] +}` -var srcOngTransfer1 = ` + srcOngTransfer = ` { - "TxnType": 209, - "ConfirmFlag": 1, - "Fee": "0.010000000", - "BlockIndex": 2, - "TransferList": [ - { - "FromAddress": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "Amount": "0.010000000", - "ToAddress": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - "AssetName": "ong" - } - ], - "TxnTime": 1555341286, - "TxnHash": "f494d7aeae2b88d313465d1f5f588b213795b38988a0bef182d9d3c2012f6e6e", - "Height": 2863855 -} -` - -var dstOngTransfer1 = blockatlas.Tx{ - ID: "f494d7aeae2b88d313465d1f5f588b213795b38988a0bef182d9d3c2012f6e6e", - Coin: coin.ONT, - From: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - To: "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - Fee: "10000000", - Date: 1555341286, - Type: blockatlas.TxNativeTokenTransfer, - Status: blockatlas.StatusCompleted, - Block: 2863855, - Meta: blockatlas.NativeTokenTransfer{ - Name: "Ontology Gas", - Symbol: "ONG", - TokenID: "ong", - Decimals: 9, - Value: "0", - From: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - To: "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - }, -} + "tx_hash": "e5946ba02f56e17c3709db2bc91f43f76ee3a359006586024daa5c4ad8c54e78", + "tx_type": 209, + "tx_time": 1577631515, + "block_height": 7457989, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "14.69", + "from_address": "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + "to_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] +}` -var srcOngTransfer2 = ` + srcRewardTransfer = ` +{ + "tx_hash": "d7554dcdf01f394b9107ff598df6d84e4c3b00ccf1e720b8c09abf085cbe4987", + "tx_type": 209, + "tx_time": 1579699532, + "block_height": 7644328, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.03534404", + "from_address": "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", + "to_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] +}` + srcFeeTransfer = ` { - "TxnType": 209, - "ConfirmFlag": 1, - "Fee": "0.010000000", - "BlockIndex": 1, - "TransferList": [ - { - "FromAddress": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "Amount": "10.000000000", - "ToAddress": "AQ9kzzHNLCcyrPwJuVMrSPgGzqmuQNVwMF", - "AssetName": "ong" + "tx_hash": "92a79aed526f31999e22d9e3912d4125d3f85ec3c63eede4b7dde4a041826095", + "tx_type": 209, + "tx_time": 1578902776, + "block_height": 7571071, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.01", + "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] +}` +) + +var ( + dstOntTransfer = blockatlas.Tx{ + ID: "ea0e5d8e389cb96760887094194ca359ac998b2f607be470a576861b91e2bf52", + Coin: coin.ONT, + From: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + To: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + Fee: "10000000", + Date: 1578903628, + Type: "transfer", + Status: blockatlas.StatusCompleted, + Block: 7571132, + Meta: blockatlas.Transfer{ + Value: "5", + Symbol: "ONT", + Decimals: 0, }, - { - "FromAddress": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "Amount": "0.010000000", - "ToAddress": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - "AssetName": "ong" - } - ], - "TxnTime": 1556952520, - "TxnHash": "eccbfd040925a22884d87e73f818f30ab42d06046460b86e9a042a1e9cba7561", - "Height": 3411141 -} -` -var dstOngTransfer = blockatlas.Tx{ - ID: "eccbfd040925a22884d87e73f818f30ab42d06046460b86e9a042a1e9cba7561", - Coin: coin.ONT, - From: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - To: "AQ9kzzHNLCcyrPwJuVMrSPgGzqmuQNVwMF", - Fee: "10000000", - Date: 1556952520, - Type: blockatlas.TxNativeTokenTransfer, - Status: blockatlas.StatusCompleted, - Block: 3411141, - Meta: blockatlas.NativeTokenTransfer{ - Name: "Ontology Gas", - Symbol: "ONG", - TokenID: "ong", - Decimals: 9, - Value: "10000000000", - From: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - To: "AQ9kzzHNLCcyrPwJuVMrSPgGzqmuQNVwMF", - }, -} + } + dstOngTransfer = blockatlas.Tx{ + ID: "e5946ba02f56e17c3709db2bc91f43f76ee3a359006586024daa5c4ad8c54e78", + Coin: coin.ONT, + From: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + To: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + Fee: "10000000", + Date: 1577631515, + Type: blockatlas.TxNativeTokenTransfer, + Status: blockatlas.StatusCompleted, + Block: 7457989, + Meta: blockatlas.NativeTokenTransfer{ + Name: "Ontology Gas", + Symbol: "ONG", + TokenID: "ong", + Decimals: 9, + Value: "14690000000", + From: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + To: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + }, + } + dstRewardTransfer = blockatlas.Tx{ + ID: "d7554dcdf01f394b9107ff598df6d84e4c3b00ccf1e720b8c09abf085cbe4987", + Coin: coin.ONT, + From: "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", + To: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + Fee: "10000000", + Date: 1579699532, + Type: blockatlas.TxAnyAction, + Status: blockatlas.StatusCompleted, + Block: 7644328, + Meta: blockatlas.AnyAction{ + Coin: coin.Ontology().ID, + Name: "Ontology Gas", + Symbol: "ONG", + TokenID: "ong", + Decimals: 9, + Value: "35344040", + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + }, + } +) func TestNormalize(t *testing.T) { var tests = []struct { + name string Transaction string - AssetName string + AssetName AssetType Expected blockatlas.Tx + wantErr bool }{ - {srcOntTransfer, ONTAssetName, dstOntTransfer}, - {srcOngTransfer1, ONGAssetName, dstOngTransfer1}, - {srcOngTransfer2, ONGAssetName, dstOngTransfer}, + {"normalize ont", srcOntTransfer, AssetONT, dstOntTransfer, false}, + {"normalize ong", srcOngTransfer, AssetONG, dstOngTransfer, false}, + {"normalize claim reward", srcRewardTransfer, AssetONG, dstRewardTransfer, false}, + {"normalize fee", srcFeeTransfer, AssetONG, blockatlas.Tx{}, true}, } - for _, test := range tests { - var ( - sourceTx Tx - ok bool - ) - - tErr := json.Unmarshal([]byte(test.Transaction), &sourceTx) - if tErr != nil { - t.Fatal("Ontology: Can't unmarshal transaction", tErr) - } - - tx, ok := Normalize(sourceTx, test.AssetName) - - if !ok { - t.Fatal("Ontology: Can't normalize transaction") - } - - actual, err := json.Marshal(tx) - if err != nil { - t.Fatal(err) - } - - expected, err := json.Marshal(&test.Expected) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(actual, expected) { - println(string(actual)) - println(string(expected)) - t.Error("Transactions not equal") - } + t.Run(test.name, func(t *testing.T) { + var sourceTx Tx + err := json.Unmarshal([]byte(test.Transaction), &sourceTx) + assert.Nil(t, err) + tx, ok := Normalize(&sourceTx, test.AssetName) + if test.wantErr { + assert.False(t, ok) + return + } + assert.True(t, ok) + assert.Equal(t, test.Expected, tx) + }) } } var ( - ontBlockResult = BlockResult{ - Error: 0, - Result: Block{ - Height: 7707834, - TxnList: []Tx{ - { - TxnHash: "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb", - ConfirmFlag: 1, - TxnTime: 1580481541, - Height: 7707834, - }, - { - TxnHash: "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd", - ConfirmFlag: 1, - TxnTime: 1580481541, - Height: 7707834, - }, - { - TxnHash: "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3", - ConfirmFlag: 1, - TxnTime: 1580481541, - Height: 7707834, - }, - }, - Hash: "a5f3ee1a102df7196bb1e262a05435f260392fae6be676ae2c0a6147f8ecf94c", - }, - } -) - -var ( - ontTxResp1 = TxResponse{ - Code: 0, - Msg: "SUCCESS", - Result: TxV2{ + ontTxResp1 = TxResult{ + BaseResponse: BaseResponse{Code: 0, Msg: "SUCCESS"}, + Result: Tx{ Hash: "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb", - Type: 209, Time: 1580481541, - BlockHeight: 7707834, + Height: 7707834, Fee: "0.01", Description: "transfer", BlockIndex: 2, ConfirmFlag: 1, EventType: 3, - Details: TransactionDetails{ - Transfers: []TransferDetails{ + Details: Detail{ + Transfers: Transfers{ { Amount: "51000", AssetName: "ong", @@ -242,24 +223,22 @@ var ( }, } - ontTxResp2 = TxResponse{ - Code: 0, - Msg: "SUCCESS", - Result: TxV2{ + ontTxResp2 = TxResult{ + BaseResponse: BaseResponse{Code: 0, Msg: "SUCCESS"}, + Result: Tx{ Hash: "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd", - Type: 209, Time: 1580481541, - BlockHeight: 7707834, + Height: 7707834, Fee: "0.01", Description: "transfer", BlockIndex: 3, ConfirmFlag: 1, EventType: 3, - Details: TransactionDetails{ - Transfers: []TransferDetails{ + Details: Detail{ + Transfers: Transfers{ { Amount: "113.2", - AssetName: "ong", + AssetName: "ont", FromAddress: "ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz", ToAddress: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", }, @@ -274,24 +253,22 @@ var ( }, } - ontTxResp3 = TxResponse{ - Code: 0, - Msg: "SUCCESS", - Result: TxV2{ + ontTxResp3 = TxResult{ + BaseResponse: BaseResponse{Code: 0, Msg: "SUCCESS"}, + Result: Tx{ Hash: "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3", - Type: 209, Time: 1580481541, - BlockHeight: 7707834, + Height: 7707834, Fee: "0.01", Description: "transfer", BlockIndex: 1, ConfirmFlag: 1, EventType: 3, - Details: TransactionDetails{ - Transfers: []TransferDetails{ + Details: Detail{ + Transfers: Transfers{ { Amount: "10949", - AssetName: "ong", + AssetName: "ont", FromAddress: "Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS", ToAddress: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", }, { @@ -307,13 +284,11 @@ var ( ) func TestNormalizeBlock(t *testing.T) { - block := normalizeBlock(ontBlockResult, []TxV2{ontTxResp1.Result, ontTxResp2.Result, ontTxResp3.Result}) + block := normalizeTxs([]Tx{ontTxResp1.Result, ontTxResp2.Result, ontTxResp3.Result}, AssetAll) got, err := json.Marshal(block) if err != nil { t.Fatal(err) } - - want := `{"number":7707834,"id":"a5f3ee1a102df7196bb1e262a05435f260392fae6be676ae2c0a6147f8ecf94c","txs":[{"id":"266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb","coin":1024,"from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"native_token_transfer","memo":"","metadata":{"name":"Ontology Gas","symbol":"ONG","token_id":"ong","decimals":9,"value":"51000000000000","from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx"}},{"id":"2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd","coin":1024,"from":"ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"native_token_transfer","memo":"","metadata":{"name":"Ontology Gas","symbol":"ONG","token_id":"ong","decimals":9,"value":"113200000000","from":"ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx"}},{"id":"40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3","coin":1024,"from":"Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"native_token_transfer","memo":"","metadata":{"name":"Ontology Gas","symbol":"ONG","token_id":"ong","decimals":9,"value":"10949000000000","from":"Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx"}}]}` - - assert.Equal(t, string(got), want) + want := `[{"id":"266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb","coin":1024,"from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"any_action","memo":"","metadata":{"coin":1024,"title":"Claim Rewards","key":"stake_claim_rewards","token_id":"ong","name":"Ontology Gas","symbol":"ONG","decimals":9,"value":"51000000000000"}},{"id":"2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd","coin":1024,"from":"ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"transfer","memo":"","metadata":{"value":"113.2","symbol":"ONT","decimals":0}},{"id":"40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3","coin":1024,"from":"Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"transfer","memo":"","metadata":{"value":"10949","symbol":"ONT","decimals":0}}]` + assert.Equal(t, want, string(got)) } diff --git a/platform/ontology/client.go b/platform/ontology/client.go index dfa9782ff..2d9a8e100 100644 --- a/platform/ontology/client.go +++ b/platform/ontology/client.go @@ -4,67 +4,52 @@ import ( "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "net/url" ) type Client struct { blockatlas.Request } -// Explorer API max returned transactions per page -const ( - TxPerPage = 20 - requestOnlyLatestBlockAmount = 1 -) - -func (c *Client) GetTxsOfAddress(address, assetName string) (*TxPage, error) { - url := fmt.Sprintf("api/v1/explorer/address/%s/%s/%d/1", address, assetName, TxPerPage) - var txPage TxPage - err := c.Get(&txPage, url, nil) - if err != nil { - return nil, err - } - return &txPage, nil +func (c *Client) GetTxsOfAddress(address string) (txPage TxsResult, err error) { + query := url.Values{"page_size": {"20"}, "page_number": {"1"}} + path := fmt.Sprintf("v2/addresses/%s/transactions", address) + err = c.Get(&txPage, path, query) + if err != nil || txPage.Msg != MsgSuccess { + return txPage, errors.E(err, "explorer client GetTxsOfAddress", errors.Params{"platform": "ONT"}) + } + return } -func (c *Client) CurrentBlockNumber() (*BlockResults, error) { - url := fmt.Sprintf("api/v1/explorer/blocklist/%d", requestOnlyLatestBlockAmount) - var response BlockResults - err := c.Get(&response, url, nil) - if err != nil { - return nil, err - } - if response.Error != 0 { - return nil, errors.E("explorer client CurrentBlockNumber", errors.Params{"platform": "ONT"}) - } - return &response, nil +func (c *Client) CurrentBlockNumber() (blocks BlockResult, err error) { + query := url.Values{"page_size": {"1"}, "page_number": {"1"}} + path := fmt.Sprintf("v2/blocks") + err = c.Get(&blocks, path, query) + if err != nil || blocks.Msg != MsgSuccess { + return blocks, errors.E(err, "explorer client CurrentBlockNumber", errors.Params{"platform": "ONT"}) + } + return } -func (c *Client) GetBlockByNumber(num int64) (*BlockResult, error) { - url := fmt.Sprintf("api/v1/explorer/block/%d", num) - var block BlockResult - err := c.Get(&block, url, nil) - if err != nil { - return nil, err - } - if block.Error != 0 { - return nil, errors.E("explorer client GetBlockByNumber", errors.Params{"platform": "ONT"}) +func (c *Client) GetBlockByNumber(num int64) (block BlockResults, err error) { + path := fmt.Sprintf("v2/blocks/%d", num) + err = c.Get(&block, path, nil) + if err != nil || block.Msg != MsgSuccess { + return block, errors.E(err, "explorer client GetBlockByNumber", errors.Params{"platform": "ONT"}) } - return &block, nil + return } -func (c *Client) GetTxDetailsByHash(hash string) (*TxV2, error) { - url := fmt.Sprintf("v2/transactions/%s", hash) - var response TxResponse - err := c.Get(&response, url, nil) - if err != nil { - return nil, err - } - if response.Msg != "SUCCESS" { - return nil, errors.E("explorer client GetTxDetailsByHash", errors.Params{"platform": "ONT"}) - } - var ontTxV2 TxV2 +func (c *Client) GetTxDetailsByHash(hash string) (Tx, error) { + path := fmt.Sprintf("v2/transactions/%s", hash) + var response TxResult + err := c.Get(&response, path, nil) + if err != nil || response.Msg != MsgSuccess { + return Tx{}, errors.E(err, "explorer client GetTxDetailsByHash", errors.Params{"platform": "ONT"}) + } + var ontTxV2 Tx if response.Result.EventType == 3 { ontTxV2 = response.Result } - return &ontTxV2, nil + return ontTxV2, nil } diff --git a/platform/ontology/model.go b/platform/ontology/model.go index 2d2515bd3..e0a03798f 100644 --- a/platform/ontology/model.go +++ b/platform/ontology/model.go @@ -1,73 +1,130 @@ package ontology -type TxPage struct { - Result Result `json:"Result"` +type AssetType string +type MsgType string +type Transfers []Transfer + +const ( + GovernanceContract = "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK" + ONGDecimals = 9 + + MsgSuccess MsgType = "SUCCESS" + + AssetONT AssetType = "ont" + AssetONG AssetType = "ong" + AssetAll AssetType = "all" +) + +type BaseResponse struct { + Code int `json:"code"` + Msg MsgType `json:"msg"` } -type Result struct { - TxnList []Tx `json:"TxnList"` +type BlockResults struct { + BaseResponse + Result Block `json:"result"` } -type Transfer struct { - Amount string `json:"Amount"` - FromAddress string `json:"FromAddress"` - ToAddress string `json:"ToAddress"` +type BlockResult struct { + BaseResponse + Result BlockRecords `json:"result"` } -type Tx struct { - TxnHash string `json:"TxnHash"` - ConfirmFlag uint64 `json:"ConfirmFlag"` - TxnType uint64 `json:"TxnType"` - TxnTime int64 `json:"TxnTime"` - Height uint64 `json:"Height"` - Fee string `json:"Fee"` - BlockIndex uint64 `json:"BlockIndex"` - - TransferList []Transfer `json:"TransferList"` +type TxsResult struct { + BaseResponse + Result []Tx `json:"result"` } -type BlockResults struct { - Error int `json:"Error"` - Result []Block `json:"Result"` +type TxResult struct { + BaseResponse + Result Tx `json:"result"` } -type BlockResult struct { - Error int `json:"Error"` - Result Block `json:"Result"` +type BlockRecords struct { + Total int64 `json:"total"` + Records []Block `json:"records"` } type Block struct { - Height int `json:"Height"` - TxnList []Tx `json:"TxnList"` - Hash string `json:"Hash"` + Height int64 `json:"block_height"` + Hash string `json:"block_hash"` + Txs []Tx `json:"txs"` } -type TxResponse struct { - Code int `json:"code"` - Msg string `json:"msg"` - Result TxV2 `json:"Result"` +type Tx struct { + Hash string `json:"tx_hash"` + ConfirmFlag uint64 `json:"confirm_flag"` + Time int64 `json:"tx_time"` + Height uint64 `json:"block_height"` + Fee string `json:"fee"` + BlockIndex uint64 `json:"block_index"` + EventType uint64 `json:"event_type,omitempty"` + Description string `json:"description,omitempty"` + Details Detail `json:"detail,omitempty"` + Transfers Transfers `json:"transfers,omitempty"` } -type TxV2 struct { - Hash string `json:"tx_hash"` - Type int `json:"tx_type"` - Time int64 `json:"tx_time"` - BlockHeight uint64 `json:"block_height"` - Fee string `json:"fee"` - Description string `json:"description"` - BlockIndex int `json:"block_index"` - ConfirmFlag int `json:"confirm_flag"` - EventType int `json:"event_type"` - Details TransactionDetails `json:"detail"` +type Detail struct { + Transfers Transfers `json:"transfers"` } -type TransactionDetails struct { - Transfers []TransferDetails `json:"transfers"` +type Transfer struct { + Amount string `json:"amount"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` + AssetName AssetType `json:"asset_name"` + Description string `json:"description,omitempty"` +} + +func (tf *Transfer) isFeeTransfer() bool { + if tf.AssetName != AssetONG { + return false + } + if tf.ToAddress != GovernanceContract { + return false + } + return true +} + +func (tfs Transfers) hasFeeTransfer() bool { + for _, tf := range tfs { + if tf.isFeeTransfer() { + return true + } + } + return false } -type TransferDetails struct { - Amount string `json:"amount"` - AssetName string `json:"asset_name"` - FromAddress string `json:"from_address"` - ToAddress string `json:"to_address"` +func (tx *Tx) getTransfers() Transfers { + return append(tx.Details.Transfers, tx.Transfers...) +} + +func (tfs Transfers) getTransfer(assetType AssetType) *Transfer { + for _, tf := range tfs { + if tf.isFeeTransfer() { + continue + } + if assetType != AssetAll && tf.AssetName != assetType { + continue + } + return &tf + } + return nil +} + +func (tfs Transfers) isClaimReward() bool { + // Claim Reward needs to have two transfers. + if len(tfs) < 2 { + return false + } + // Both transfers need to be ONG, one for reward and another one. + if tfs[0].AssetName != AssetONG || tfs[1].AssetName != AssetONG { + return false + } + // Verify if one of the transfers is a fee transfer. + if !tfs.hasFeeTransfer() { + return false + } + return true + } diff --git a/platform/ontology/model_test.go b/platform/ontology/model_test.go new file mode 100644 index 000000000..b482e6360 --- /dev/null +++ b/platform/ontology/model_test.go @@ -0,0 +1,130 @@ +package ontology + +import ( + "reflect" + "testing" +) + +func TestTransfer_isFeeTransfer(t *testing.T) { + type fields struct { + ToAddress string + AssetName AssetType + } + tests := []struct { + name string + fields fields + want bool + }{ + {"test fee transfer", fields{ToAddress: GovernanceContract, AssetName: AssetONG}, true}, + {"test non fee transfer 1", fields{ToAddress: GovernanceContract, AssetName: AssetONT}, false}, + {"test non fee transfer 2", fields{ToAddress: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", AssetName: AssetONG}, false}, + {"test non fee transfer 3", fields{ToAddress: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", AssetName: AssetONT}, false}, + {"test invalid asset", fields{ToAddress: GovernanceContract, AssetName: "BNB"}, false}, + {"test empty", fields{ToAddress: "", AssetName: ""}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tf := &Transfer{ + ToAddress: tt.fields.ToAddress, + AssetName: tt.fields.AssetName, + } + if got := tf.isFeeTransfer(); got != tt.want { + t.Errorf("isFeeTransfer() = %v, want %v", got, tt.want) + } + }) + } +} + +var ( + transferFee = Transfer{ + Amount: "0.01", + FromAddress: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + ToAddress: "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + AssetName: "ong", + } + transferOng = Transfer{ + Amount: "0.03534404", + FromAddress: "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", + ToAddress: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + AssetName: "ong", + } + transferOnt = Transfer{ + Amount: "58", + FromAddress: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + ToAddress: "ARncJn1rr9hivokUWxzr915vS3usR6xdgJ", + AssetName: "ont", + } + transfersClaims = Transfers{transferOng, transferFee} + transfersOnt = Transfers{transferOnt, transferFee} + transfersOng = Transfers{transferOng} + transfersFee = Transfers{transferFee} +) + +func TestTransfers_getTransfer(t *testing.T) { + tests := []struct { + name string + tfs Transfers + asset AssetType + want *Transfer + }{ + {"Transfer Claims Asset Ong", transfersClaims, AssetONG, &transferOng}, + {"Transfer Claims Asset Ont", transfersClaims, AssetONT, nil}, + {"Transfer Claims Asset All", transfersClaims, AssetAll, &transferOng}, + {"Transfer Ont Asset Ong", transfersOnt, AssetONG, nil}, + {"Transfer Ont Asset Ont", transfersOnt, AssetONT, &transferOnt}, + {"Transfer Ont Asset All", transfersOnt, AssetAll, &transferOnt}, + {"Transfer Ong Asset Ong", transfersOng, AssetONG, &transferOng}, + {"Transfer Ong Asset Ont", transfersOng, AssetONT, nil}, + {"Transfer Ong Asset All", transfersOng, AssetAll, &transferOng}, + {"Transfer Fee Asset Ong", transfersFee, AssetONG, nil}, + {"Transfer Fee Asset Ont", transfersFee, AssetONT, nil}, + {"Transfer Fee Asset All", transfersFee, AssetAll, nil}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.tfs.getTransfer(tt.asset); !reflect.DeepEqual(got, tt.want) { + t.Errorf("getTransfer() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestTransfers_hasFeeTransfer(t *testing.T) { + tests := []struct { + name string + tfs Transfers + want bool + }{ + {"Transfer Claims", transfersClaims, true}, + {"Transfer Ont", transfersOnt, true}, + {"Transfer Ong", transfersOng, false}, + {"Transfer Fee", transfersFee, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.tfs.hasFeeTransfer(); got != tt.want { + t.Errorf("hasFeeTransfer() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestTransfers_isClaimReward(t *testing.T) { + tests := []struct { + name string + tfs Transfers + want bool + }{ + {"Transfer Claims", transfersClaims, true}, + {"Transfer Ont", transfersOnt, false}, + {"Transfer Ong", transfersOng, false}, + {"Transfer Fee", transfersFee, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.tfs.isClaimReward(); got != tt.want { + t.Errorf("isClaimReward() = %v, want %v", got, tt.want) + } + }) + } +} From e2e31539899a64e421306ce64902dea4842c0a54 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 3 Feb 2020 12:57:01 -0300 Subject: [PATCH 067/506] fix observer data race (#795) --- pkg/blockatlas/client.go | 10 +++++----- pkg/storage/redis/hmap.go | 14 ++++++------- storage/subscriptions.go | 42 +++++++++++++++++++++++++++++---------- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go index 409aa5162..3c01f1b81 100644 --- a/pkg/blockatlas/client.go +++ b/pkg/blockatlas/client.go @@ -64,7 +64,7 @@ func (r *Request) Execute(method string, url string, body io.Reader, result inte start := time.Now() req, err := http.NewRequest(method, url, body) if err != nil { - return errors.E(err, errors.TypePlatformRequest, errors.Params{"url": url, "method": method}).PushToSentry() + return errors.E(err, errors.TypePlatformRequest, errors.Params{"url": url, "method": method}) } for key, value := range r.Headers { @@ -73,22 +73,22 @@ func (r *Request) Execute(method string, url string, body io.Reader, result inte res, err := r.HttpClient.Do(req) if err != nil { - return errors.E(err, errors.TypePlatformRequest, errors.Params{"url": url, "method": method}).PushToSentry() + return errors.E(err, errors.TypePlatformRequest, errors.Params{"url": url, "method": method}) } go metrics.GetMetrics(res.Status, url, method, start) err = r.ErrorHandler(res, url) if err != nil { - return errors.E(err, errors.TypePlatformError, errors.Params{"url": url, "method": method}).PushToSentry() + return errors.E(err, errors.TypePlatformError, errors.Params{"url": url, "method": method}) } defer res.Body.Close() b, err := ioutil.ReadAll(res.Body) if err != nil { - return errors.E(err, errors.TypePlatformUnmarshal, errors.Params{"url": url, "method": method}).PushToSentry() + return errors.E(err, errors.TypePlatformUnmarshal, errors.Params{"url": url, "method": method}) } err = json.Unmarshal(b, result) if err != nil { - return errors.E(err, errors.TypePlatformUnmarshal, errors.Params{"url": url, "method": method}).PushToSentry() + return errors.E(err, errors.TypePlatformUnmarshal, errors.Params{"url": url, "method": method}) } return err } diff --git a/pkg/storage/redis/hmap.go b/pkg/storage/redis/hmap.go index d7637921a..ee2a0b000 100644 --- a/pkg/storage/redis/hmap.go +++ b/pkg/storage/redis/hmap.go @@ -9,7 +9,7 @@ import ( func (db *Redis) GetAllHM(entity string) (map[string]string, error) { cmd := db.client.HGetAll(entity) if cmd.Err() != nil { - return nil, errors.E(cmd.Err(), util.ErrNotFound).PushToSentry() + return nil, errors.E(cmd.Err(), util.ErrNotFound) } return cmd.Val(), nil } @@ -17,15 +17,15 @@ func (db *Redis) GetAllHM(entity string) (map[string]string, error) { func (db *Redis) GetHMValue(entity, key string, value interface{}) error { cmd := db.client.HMGet(entity, key) if cmd.Err() != nil { - return errors.E(cmd.Err(), util.ErrNotFound).PushToSentry() + return errors.E(cmd.Err(), util.ErrNotFound) } val, ok := cmd.Val()[0].(string) if !ok { - return errors.E(util.ErrNotFound).PushToSentry() + return errors.E(util.ErrNotFound) } err := json.Unmarshal([]byte(val), value) if err != nil { - return errors.E(err, util.ErrNotFound).PushToSentry() + return errors.E(err, util.ErrNotFound) } return nil } @@ -33,11 +33,11 @@ func (db *Redis) GetHMValue(entity, key string, value interface{}) error { func (db *Redis) AddHM(entity, key string, value interface{}) error { j, err := json.Marshal(value) if err != nil { - return errors.E(err, errors.Params{"value": value}).PushToSentry() + return errors.E(err, errors.Params{"value": value}) } cmd := db.client.HMSet(entity, map[string]interface{}{key: j}) if cmd.Err() != nil { - return errors.E(cmd.Err(), util.ErrNotStored).PushToSentry().PushToSentry() + return errors.E(cmd.Err(), util.ErrNotStored) } return nil } @@ -45,7 +45,7 @@ func (db *Redis) AddHM(entity, key string, value interface{}) error { func (db *Redis) DeleteHM(entity, key string) error { cmd := db.client.HDel(entity, key) if cmd.Err() != nil { - return errors.E(cmd.Err(), util.ErrNotDeleted).PushToSentry() + return errors.E(cmd.Err(), util.ErrNotDeleted) } return nil } diff --git a/storage/subscriptions.go b/storage/subscriptions.go index 762dfc661..75a6fc2fc 100644 --- a/storage/subscriptions.go +++ b/storage/subscriptions.go @@ -5,26 +5,46 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" + "sync" ) const ( ATLAS_OBSERVER = "ATLAS_OBSERVER" ) -func (s *Storage) Lookup(coin uint, addresses []string) (observers []blockatlas.Subscription, err error) { +func (s *Storage) Lookup(coin uint, addresses []string) ([]blockatlas.Subscription, error) { if len(addresses) == 0 { - err = errors.E("cannot look up an empty list") - return + return nil, errors.E("cannot look up an empty list") } - for _, addr := range addresses { - key := getSubscriptionKey(coin, addr) - var webhooks []string - _ = s.GetHMValue(ATLAS_OBSERVER, key, &webhooks) - for _, webhook := range webhooks { - observers = append(observers, blockatlas.Subscription{Coin: coin, Address: addr, Webhook: webhook}) - } + + observers := make([]blockatlas.Subscription, 0) + var wg sync.WaitGroup + out := make(chan []blockatlas.Subscription) + wg.Add(len(addresses)) + for _, address := range addresses { + go func(coin uint, addr string) { + defer wg.Done() + key := getSubscriptionKey(coin, addr) + var webhooks []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &webhooks) + if err != nil { + return + } + subs := make([]blockatlas.Subscription, 0) + for _, webhook := range webhooks { + subs = append(subs, blockatlas.Subscription{Coin: coin, Address: addr, Webhook: webhook}) + } + out <- subs + }(coin, address) + } + go func() { + wg.Wait() + close(out) + }() + for r := range out { + observers = append(observers, r...) } - return + return observers, nil } func (s *Storage) AddSubscriptions(subscriptions []blockatlas.Subscription) { From 3d830e114a459d1d3eae95e6b57513b33b416dd0 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 3 Feb 2020 13:35:59 -0300 Subject: [PATCH 068/506] get charts from priority (#796) --- syncmarkets/charts.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/syncmarkets/charts.go b/syncmarkets/charts.go index 7fb124c7f..121e18e9c 100644 --- a/syncmarkets/charts.go +++ b/syncmarkets/charts.go @@ -36,7 +36,8 @@ func InitCharts() *Charts { func (c *Charts) GetChartData(coin uint, token string, currency string, timeStart int64, maxItems int) (blockatlas.ChartData, error) { chartsData := blockatlas.ChartData{} timeStart = numbers.Max(timeStart, minUnixTime) - for _, c := range c.chartProviders { + for i := 0; i < len(c.chartProviders); i++ { + c := c.chartProviders[i] charts, err := c.GetChartData(coin, token, currency, timeStart) if err != nil { continue @@ -49,7 +50,8 @@ func (c *Charts) GetChartData(coin uint, token string, currency string, timeStar func (c *Charts) GetCoinInfo(coin uint, token string, currency string) (blockatlas.ChartCoinInfo, error) { coinInfoData := blockatlas.ChartCoinInfo{} - for _, c := range c.chartProviders { + for i := 0; i < len(c.chartProviders); i++ { + c := c.chartProviders[i] info, err := c.GetCoinData(coin, token, currency) if err != nil { continue From fcfb4d7a68e28d4c8904ee0f3cf4dc00e433fcde Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 01:11:28 -0300 Subject: [PATCH 069/506] [Tezos] Fix delegation and add delegations tx history (#797) * add delegations tx history * remove delegates from tx history * add delegate observer --- config.yml | 1 - platform/tezos/api.go | 127 ++++++++++++++------ platform/tezos/api_test.go | 219 ++++++++++++++++++++++++++++++----- platform/tezos/client.go | 12 +- platform/tezos/model.go | 97 +++++++++++----- platform/tezos/model_test.go | 83 +++++++++++++ platform/tezos/rpc.go | 5 + platform/tezos/stake.go | 26 +---- platform/tezos/stake_test.go | 60 +--------- 9 files changed, 446 insertions(+), 184 deletions(-) create mode 100644 platform/tezos/model_test.go diff --git a/config.yml b/config.yml index cfc1d7e92..3dc627b42 100644 --- a/config.yml +++ b/config.yml @@ -79,7 +79,6 @@ kin: # [XTZ] Tezos: https://tezos.com tezos: - stake_api: https://api.tzstats.com/explorer api: https://api.tezos.id/mooncake/mainnet rpc: https://mainnet.tezos.org.ua diff --git a/platform/tezos/api.go b/platform/tezos/api.go index a0842190f..50f3cbc18 100644 --- a/platform/tezos/api.go +++ b/platform/tezos/api.go @@ -4,20 +4,20 @@ import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "sync" ) type Platform struct { - client Client - stakeClient Client - rpcClient RpcClient + client Client + rpcClient RpcClient } const Annual = 6.09 func (p *Platform) Init() error { p.client = Client{blockatlas.InitClient(viper.GetString("tezos.api"))} - p.client.SetTimeout(30) - p.stakeClient = Client{blockatlas.InitClient(viper.GetString("tezos.stake_api"))} + p.client.SetTimeout(35) p.rpcClient = RpcClient{blockatlas.InitClient(viper.GetString("tezos.rpc"))} return nil } @@ -27,12 +27,30 @@ func (p *Platform) Coin() coin.Coin { } func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - s, err := p.client.GetTxsOfAddress(address) - if err != nil { - return nil, err + txTypes := []TxType{TxTransactions} + var wg sync.WaitGroup + out := make(chan []Transaction) + for _, t := range txTypes { + wg.Add(1) + go func(txType TxType, addr string) { + defer wg.Done() + txs, err := p.client.GetTxsOfAddress(address, txType) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"txType": txType, "addr": addr}) + return + } + out <- txs + }(t, address) } - txs := NormalizeTxs(s) - return txs, nil + go func() { + wg.Wait() + close(out) + }() + srcTxs := make([]Transaction, 0) + for r := range out { + srcTxs = append(srcTxs, r...) + } + return NormalizeTxs(srcTxs), nil } func (p *Platform) CurrentBlockNumber() (int64, error) { @@ -40,11 +58,30 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { } func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - srcBlock, err := p.client.GetBlockByNumber(num) - if err != nil { - return nil, err + txTypes := []TxType{TxTransactions, TxDelegations} + var wg sync.WaitGroup + out := make(chan []Transaction) + for _, t := range txTypes { + wg.Add(1) + go func(txType TxType, num int64) { + defer wg.Done() + txs, err := p.client.GetBlockByNumber(num, txType) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"txType": txType, "num": num}) + return + } + out <- txs + }(t, num) + } + go func() { + wg.Wait() + close(out) + }() + srcTxs := make([]Transaction, 0) + for r := range out { + srcTxs = append(srcTxs, r...) } - txs := NormalizeTxs(srcBlock) + txs := NormalizeTxs(srcTxs) return &blockatlas.Block{ Number: num, Txs: txs, @@ -63,33 +100,47 @@ func NormalizeTxs(srcTxs []Transaction) (txs []blockatlas.Tx) { } // NormalizeTx converts a Tezos transaction into the generic model -func NormalizeTx(srcTx Transaction) (tx blockatlas.Tx, ok bool) { - if srcTx.Tx.Kind != "transaction" { - return tx, false - } - - var status blockatlas.Status - var errMsg string - if srcTx.Tx.Status == "applied" { - status = blockatlas.StatusCompleted - } else { - status = blockatlas.StatusFailed +func NormalizeTx(srcTx Transaction) (blockatlas.Tx, bool) { + errMsg := "" + status := blockatlas.StatusCompleted + if srcTx.Status() != TxStatusApplied { errMsg = "transaction failed" + status = blockatlas.StatusFailed + } + tx := blockatlas.Tx{ + ID: srcTx.Op.OpHash, + Coin: coin.XTZ, + Date: srcTx.Op.BlockTimestamp.Unix(), + From: srcTx.Source(), + To: srcTx.Destination(), + Fee: blockatlas.Amount(srcTx.Fee()), + Block: srcTx.Op.BlockLevel, + Status: status, + Error: errMsg, } - return blockatlas.Tx{ - ID: srcTx.Op.OpHash, - Coin: coin.XTZ, - Date: srcTx.Op.BlockTimestamp.Unix(), - From: srcTx.Tx.Source, - To: srcTx.Tx.Destination, - Fee: blockatlas.Amount(srcTx.Tx.Fee), - Block: srcTx.Op.BlockLevel, - Meta: blockatlas.Transfer{ + + switch srcTx.Kind() { + case TxKindDelegation: + title := blockatlas.AnyActionDelegation + if len(srcTx.Delegation.Delegate) == 0 { + title = blockatlas.AnyActionUndelegation + } + tx.Meta = blockatlas.AnyAction{ + Coin: coin.Tezos().ID, + Title: title, + Key: blockatlas.KeyStakeDelegate, + Name: coin.Tezos().Name, + Symbol: coin.Tezos().Symbol, + Decimals: coin.Tezos().Decimals, + } + case TxKindTransaction: + tx.Meta = blockatlas.Transfer{ Value: blockatlas.Amount(srcTx.Tx.Amount), Symbol: coin.Coins[coin.XTZ].Symbol, Decimals: coin.Coins[coin.XTZ].Decimals, - }, - Status: status, - Error: errMsg, - }, true + } + default: + return blockatlas.Tx{}, false + } + return tx, true } diff --git a/platform/tezos/api_test.go b/platform/tezos/api_test.go index 71dea7e3b..125acb9bf 100644 --- a/platform/tezos/api_test.go +++ b/platform/tezos/api_test.go @@ -35,8 +35,7 @@ const transferSrc1 = ` "blockTimestamp": "2020-01-22T16:34:22Z", "insertedTimestamp": "2020-01-22 16:34:49.405793 UTC" } -} -` +}` const transferSrc2 = ` { @@ -65,8 +64,7 @@ const transferSrc2 = ` "blockTimestamp": "2020-01-20T18:54:52Z", "insertedTimestamp": "2020-01-20 18:56:28.193751 UTC" } -} -` +}` const transferSrc3 = ` { @@ -95,38 +93,141 @@ const transferSrc3 = ` "blockTimestamp": "2020-01-20T16:16:32Z", "insertedTimestamp": "2020-01-20 16:18:59.855515 UTC" } -} -` +}` const transferSrc4 = ` { - "tx": { - "destination": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - "amount": "1751", - "gasLimit": "15385", + "op": { + "signature": "sigjQxDjvom9zqhNbi4cbwPLXn4fnVHiYSwsxDyXdPiFCjDqgS2ukHeWqmq61jkboiXTE3UJUqiXGqtmDVDXTRr5EKhaAeWF", + "blockUuid": "0ce492ed-ea9e-43c2-bf14-f17c44f099a4", + "opHash": "opUx5394wcy8BdoaYCM32kVyLB27F9ruT4vnKQccgQ463KsFPy3", + "uuid": "d5e2df82-9149-4d3e-9cac-16a425c79f67", + "chainId": "NetXdQprcVkpaWU", + "blockHash": "BMCkZ9NM5v3LnRPgfXYd4F9DHQ3bdTmmE8KjWhA5X982Bfz7ueC", + "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", + "branch": "BKybkjYtw3Cv7zdECiQd9W9WmWkoa25eJLwFiVQ4S3wB5mdcw4i", + "blockLevel": 809102, + "blockTimestamp": "2020-02-04T00:29:14Z", + "insertedTimestamp": "2020-02-04 00:29:28.291063 UTC" + }, + "endor": { + "slots": [ + 1 + ], + "delegate": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", + "opUuid": "d5e2df82-9149-4d3e-9cac-16a425c79f67", + "uuid": "7e1d6f45-b148-4e24-9c36-d7a0deb6ff72", + "kind": "endorsement", + "blockHash": "BMCkZ9NM5v3LnRPgfXYd4F9DHQ3bdTmmE8KjWhA5X982Bfz7ueC", + "blockLevel": 809102, + "blockTimestamp": "2020-02-04T00:29:14Z", + "insertedTimestamp": "2020-02-04 00:29:31.168224 UTC", + "metadataUuid": "36380127-30af-4bd0-88dd-18b49860d43c", + "level": 809101 + } +}` + +const delegationsSrc1 = ` +{ + "op": { + "signature": "sigvHd2YBByFXU8nL4CZKSTYXNdMapMsJw1f239YRRjgz9NvrTyA6iGnpBDhi9kCB4zMHysrg9H4jxcpPH975WiQtEmkMjb5", + "blockUuid": "4b292c55-41ba-4383-a1d6-03fb71b88f41", + "opHash": "opGphHGNEZZN5rF78yxwe9BJydxYA2yqxECnZR6s6HcxXtCg8Sj", + "uuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", + "chainId": "NetXdQprcVkpaWU", + "blockHash": "BLkscXpE63gajVzmgBS7fQx63hERKQRCZFGtMXdYY6WPThHyji7", + "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", + "branch": "BKqtLegZfdPR3USyYYcMpedB59W5eUBuFZAVpVMPpFgEvMcZjr1", + "blockLevel": 791778, + "blockTimestamp": "2020-01-22T22:13:38Z", + "insertedTimestamp": "2020-01-22 22:14:05.937406 UTC" + }, + "delegation": { + "storageLimit": "257", + "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "opUuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", + "uuid": "6459fcd9-5eee-4999-ac4d-92330b9eaab3", + "gasLimit": "10600", "kind": "delegation", - "operationResultStatus": "backtracked", - "blockHash": "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", - "fee": "0", - "operationResultConsumedGas": "10207", - "counter": "1382930", - "blockLevel": 788568, + "operationResultStatus": "applied", + "fee": "1500", + "operationResultUuid": "791f6ec7-ecec-43d5-82ca-a1497be0188c", + "operationResultConsumedGas": "10000", + "counter": "2409130", "operationResultErrors": null, - "blockTimestamp": "2020-01-20T16:16:32Z", - "parameters": null, - "source": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - "insertedTimestamp": "2020-01-20 16:19:06.938114 UTC" + "source": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + "insertedTimestamp": "2020-01-22 22:15:12.038586 UTC", + "metadataUuid": "85b42f50-1a89-421c-bcb0-a06926941bc4" + } +}` + +const delegationsSrc2 = ` +{ + "op": { + "signature": "sigbhvzA37wDGhfYT21LQyoYfzU4KvhbaTwrLMXMDMDUJt69HNAxSK44wv8S1576ZADcEwMLNUbSXyBEFgFkikbNRn51ozhg", + "blockUuid": "785389b9-356d-4a98-9202-39f9c94b5b73", + "opHash": "onfvhheWth5GCbKKAc9KLZoqQ9AFzAS27vfPCN2DGcGuPA31jmc", + "uuid": "766932d0-fc9b-451d-834d-5feb48178580", + "chainId": "NetXdQprcVkpaWU", + "blockHash": "BMQShgncuUDtY2WbXz9aEqebKfztSL3VxVzgVRoMweb72fzS9MD", + "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", + "branch": "BLzBVG42EMvipNaWEPPTW9G6otFqwAEhSjsgmDMSNrVKComW4Tb", + "blockLevel": 809061, + "blockTimestamp": "2020-02-03T23:48:14Z", + "insertedTimestamp": "2020-02-03 23:48:43.650483 UTC" }, + "delegation": { + "storageLimit": "257", + "delegate": "tz1V3yg82mcrPJbegqVCPn6bC8w1CSTRp3f8", + "opUuid": "766932d0-fc9b-451d-834d-5feb48178580", + "uuid": "ad5b8aca-86ae-4463-82b1-a05350c6899b", + "gasLimit": "10600", + "kind": "delegation", + "operationResultStatus": "applied", + "fee": "1500", + "operationResultUuid": "a87226fd-4983-49d7-b65f-93378056fda7", + "operationResultConsumedGas": "10000", + "counter": "3032194", + "operationResultErrors": null, + "source": "tz1hpUTmafsAEH8vQTirnZsvPWZ3wZ6oEkUw", + "insertedTimestamp": "2020-02-03 23:49:59.947433 UTC", + "metadataUuid": "325bfab8-6db3-4f6e-beb3-783031c556de" + } +}` + +const delegationsSrc3 = ` +{ "op": { - "opHash": "ooXN845juCMcQuqeodwBJWNhY17A5HKyWRxbcwS1m6TfqCqjM8q", + "signature": "signaVwXLttpBqZVKUwbdUN92TevU26CRUWvYBx5areFAb4uAaeKDVFacWPfLc2WwfpMhXgbC4PpwgMuZd1RfXNJF7w7T7Fn", + "blockUuid": "ac319dd4-78ee-44c4-8652-6bf5be68a666", + "opHash": "oneqVXTkJqDvCDfxqggnzveo6U28Bp5sByguaqSZ7seBgQgzZSG", + "uuid": "c3bab716-ed01-4357-8f41-b75df6ea1708", "chainId": "NetXdQprcVkpaWU", - "blockHash": "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", - "blockLevel": 788568, - "blockTimestamp": "2020-01-20T16:16:32Z", - "insertedTimestamp": "2020-01-20 16:18:59.855515 UTC" + "blockHash": "BLSN7G7UBSUys7njxo8Xm699L4U3xhhbkZyYYr5e8jJrDtnqfj8", + "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", + "branch": "BLAWNqLHLQWfSLwgQE8gqUWFPx3DPzxN2jrUxtz9q1zvisaCUwi", + "blockLevel": 809007, + "blockTimestamp": "2020-02-03T22:53:34Z", + "insertedTimestamp": "2020-02-03 22:53:48.734959 UTC" + }, + "delegation": { + "storageLimit": "257", + "delegate": null, + "opUuid": "c3bab716-ed01-4357-8f41-b75df6ea1708", + "uuid": "979e75b2-a64c-4844-a187-d5e59a3c7728", + "gasLimit": "10600", + "kind": "delegation", + "operationResultStatus": "applied", + "fee": "1500", + "operationResultUuid": "a4c26049-8169-4804-b074-d201fac4bfd2", + "operationResultConsumedGas": "10000", + "counter": "3032193", + "operationResultErrors": null, + "source": "tz1hpUTmafsAEH8vQTirnZsvPWZ3wZ6oEkUw", + "insertedTimestamp": "2020-02-03 22:54:50.993844 UTC", + "metadataUuid": "edd476c1-88e0-40d0-ac29-2c32e6d16feb" } -} -` +}` var transfer1 = blockatlas.Tx{ ID: "ooBAC2ynR5LfU9L2KEon8Z3ujmwEVyB9si1rrppBCmmEn4Mr3bJ", @@ -177,6 +278,63 @@ var transfer3 = blockatlas.Tx{ Error: "transaction failed", } +var delegation1 = blockatlas.Tx{ + ID: "opGphHGNEZZN5rF78yxwe9BJydxYA2yqxECnZR6s6HcxXtCg8Sj", + Coin: coin.XTZ, + Date: 1579731218, + From: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + To: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + Fee: "1500", + Block: 791778, + Status: blockatlas.StatusCompleted, + Meta: blockatlas.AnyAction{ + Coin: coin.Tezos().ID, + Title: blockatlas.AnyActionDelegation, + Key: blockatlas.KeyStakeDelegate, + Name: coin.Tezos().Name, + Symbol: coin.Tezos().Symbol, + Decimals: coin.Tezos().Decimals, + }, +} + +var delegation2 = blockatlas.Tx{ + ID: "onfvhheWth5GCbKKAc9KLZoqQ9AFzAS27vfPCN2DGcGuPA31jmc", + Coin: coin.XTZ, + Date: 1580773694, + From: "tz1hpUTmafsAEH8vQTirnZsvPWZ3wZ6oEkUw", + To: "tz1V3yg82mcrPJbegqVCPn6bC8w1CSTRp3f8", + Fee: "1500", + Block: 809061, + Status: blockatlas.StatusCompleted, + Meta: blockatlas.AnyAction{ + Coin: coin.Tezos().ID, + Title: blockatlas.AnyActionDelegation, + Key: blockatlas.KeyStakeDelegate, + Name: coin.Tezos().Name, + Symbol: coin.Tezos().Symbol, + Decimals: coin.Tezos().Decimals, + }, +} + +var delegation3 = blockatlas.Tx{ + ID: "oneqVXTkJqDvCDfxqggnzveo6U28Bp5sByguaqSZ7seBgQgzZSG", + Coin: coin.XTZ, + Date: 1580770414, + From: "tz1hpUTmafsAEH8vQTirnZsvPWZ3wZ6oEkUw", + To: "", + Fee: "1500", + Block: 809007, + Status: blockatlas.StatusCompleted, + Meta: blockatlas.AnyAction{ + Coin: coin.Tezos().ID, + Title: blockatlas.AnyActionUndelegation, + Key: blockatlas.KeyStakeDelegate, + Name: coin.Tezos().Name, + Symbol: coin.Tezos().Symbol, + Decimals: coin.Tezos().Decimals, + }, +} + func TestNormalizeTx(t *testing.T) { tests := []struct { name string @@ -187,6 +345,9 @@ func TestNormalizeTx(t *testing.T) { {"transfer 1", transferSrc1, transfer1, true}, {"transfer 2", transferSrc2, transfer2, true}, {"transfer 3", transferSrc3, transfer3, true}, + {"delegation 1", delegationsSrc1, delegation1, true}, + {"delegation 2", delegationsSrc2, delegation2, true}, + {"delegation 3", delegationsSrc3, delegation3, true}, {"transfer 4", transferSrc4, blockatlas.Tx{}, false}, } for _, tt := range tests { @@ -195,8 +356,8 @@ func TestNormalizeTx(t *testing.T) { err := json.Unmarshal([]byte(tt.srcTx), &transaction) assert.Nil(t, err) gotTx, gotOk := NormalizeTx(transaction) - assert.Equal(t, gotOk, tt.wantOk, "transfer ok result don't equal") - assert.Equal(t, gotTx, tt.wantTx, "transfer don't equal") + assert.Equal(t, tt.wantOk, gotOk, "transfer ok result don't equal") + assert.Equal(t, tt.wantTx, gotTx, "transfer don't equal") }) } } diff --git a/platform/tezos/client.go b/platform/tezos/client.go index b2b60fe0d..cacd741e2 100644 --- a/platform/tezos/client.go +++ b/platform/tezos/client.go @@ -11,8 +11,8 @@ type Client struct { blockatlas.Request } -func (c *Client) GetTxsOfAddress(address string) (txs []Transaction, err error) { - err = c.Get(&txs, "v1/transactions", url.Values{"n": {"50"}, "p": {"0"}, "account": {address}}) +func (c *Client) GetTxsOfAddress(address string, txType TxType) (txs []Transaction, err error) { + err = c.Get(&txs, "v1/"+string(txType), url.Values{"n": {"50"}, "p": {"0"}, "account": {address}}) return } @@ -21,11 +21,7 @@ func (c *Client) GetCurrentBlock() (height int64, err error) { return } -func (c *Client) GetBlockByNumber(num int64) (txs []Transaction, err error) { - err = c.Get(&txs, "v1/transactions", url.Values{"n": {"50"}, "p": {"0"}, "block": {strconv.Itoa(int(num))}}) +func (c *Client) GetBlockByNumber(num int64, txType TxType) (txs []Transaction, err error) { + err = c.Get(&txs, "v1/"+string(txType), url.Values{"n": {"50"}, "p": {"0"}, "block": {strconv.Itoa(int(num))}}) return } - -func (c *Client) GetAccount(address string) (result Account, err error) { - return result, c.Get(&result, "account/"+address, nil) -} diff --git a/platform/tezos/model.go b/platform/tezos/model.go index 42ced47a5..da720f1f5 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -2,6 +2,21 @@ package tezos import "time" +type TxType string +type TxKind string +type TxStatus string + +const ( + TxTransactions TxType = "transactions" + TxDelegations TxType = "delegations" + + TxKindTransaction TxKind = "transaction" + TxKindDelegation TxKind = "delegation" + + TxStatusApplied TxStatus = "applied" + TxStatusSkipped TxStatus = "skipped" +) + type Op struct { OpHash string `json:"opHash"` BlockLevel uint64 `json:"blockLevel"` @@ -9,40 +24,64 @@ type Op struct { } type Transaction struct { - Tx Tx `json:"tx"` - Op Op `json:"op"` + Tx Tx `json:"tx"` + Op Op `json:"op"` + Delegation Delegation `json:"delegation"` } -type Tx struct { - Destination string `json:"destination"` - Amount string `json:"amount"` - GasLimit string `json:"gasLimit"` - Kind string `json:"kind"` - BlockHash string `json:"blockHash"` - Fee string `json:"fee"` - Source string `json:"source"` - Status string `json:"operationResultStatus"` +func (t *Transaction) Status() TxStatus { + if len(t.Tx.Status) > 0 { + return t.Tx.Status + } + return t.Delegation.Status } -type TxDelegation struct { - Delegation Delegation `json:"delegation"` - Op Op `json:"op"` +func (t *Transaction) Kind() TxKind { + if len(t.Tx.Kind) > 0 { + return t.Tx.Kind + } + return t.Delegation.Kind } -type Delegation struct { - Delegate string `json:"delegate"` - GasLimit string `json:"gasLimit"` - Kind string `json:"kind"` - Status string `json:"operationResultStatus"` - Fee string `json:"fee"` - Source string `json:"source"` +func (t *Transaction) Source() string { + if len(t.Tx.Source) > 0 { + return t.Tx.Source + } + return t.Delegation.Source +} + +func (t *Transaction) Destination() string { + if len(t.Tx.Destination) > 0 { + return t.Tx.Destination + } + return t.Delegation.Delegate +} + +func (t *Transaction) Fee() string { + if len(t.Tx.Fee) > 0 { + return t.Tx.Fee + } + return t.Delegation.Fee } -type Balance struct { - Balance string `json:"balance"` - FrozenBalance string `json:"frozen_balance"` - StakingBalance string `json:"staking_balance"` - DelegatedBalance string `json:"delegated_balance"` +type Tx struct { + Destination string `json:"destination"` + Amount string `json:"amount"` + GasLimit string `json:"gasLimit"` + Kind TxKind `json:"kind"` + BlockHash string `json:"blockHash"` + Fee string `json:"fee"` + Source string `json:"source"` + Status TxStatus `json:"operationResultStatus"` +} + +type Delegation struct { + Delegate string `json:"delegate"` + GasLimit string `json:"gasLimit"` + Kind TxKind `json:"kind"` + Status TxStatus `json:"operationResultStatus"` + Fee string `json:"fee"` + Source string `json:"source"` } type Validator struct { @@ -50,8 +89,6 @@ type Validator struct { } type Account struct { - Address string `json:"address"` - Delegate string `json:"delegate"` - Balance float64 `json:"total_balance"` - IsDelegated bool `json:"is_delegated"` + Balance string `json:"balance"` + Delegate string `json:"delegate"` } diff --git a/platform/tezos/model_test.go b/platform/tezos/model_test.go new file mode 100644 index 000000000..a3e95c526 --- /dev/null +++ b/platform/tezos/model_test.go @@ -0,0 +1,83 @@ +package tezos + +import ( + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +var ( + transaction = Tx{ + Destination: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + Amount: "1751", + GasLimit: "15385", + Kind: TxKindTransaction, + BlockHash: "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", + Fee: "0", + Source: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + Status: TxStatusApplied, + } + del = Delegation{ + Delegate: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + GasLimit: "10600", + Kind: TxKindDelegation, + Status: TxStatusApplied, + Fee: "1500", + Source: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + } + op = Op{ + OpHash: "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", + BlockLevel: 788568, + BlockTimestamp: time.Time{}, + } +) + +func TestTransaction_Status(t *testing.T) { + type fields struct { + Op Op + Tx Tx + Delegation Delegation + } + type want struct { + Status TxStatus + Kind TxKind + Source string + Destination string + Fee string + } + tests := []struct { + name string + fields fields + want want + }{ + { + "transaction", + fields{op, transaction, Delegation{}}, + want{TxStatusApplied, TxKindTransaction, "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", "0"}, + }, + { + "delegation", + fields{op, Tx{}, del}, + want{TxStatusApplied, TxKindDelegation, "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", "1500"}, + }, + { + "transaction and delegation", + fields{op, transaction, del}, + want{TxStatusApplied, TxKindTransaction, "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", "0"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tx := &Transaction{ + Tx: tt.fields.Tx, + Op: tt.fields.Op, + Delegation: tt.fields.Delegation, + } + assert.Equal(t, tt.want.Status, tx.Status()) + assert.Equal(t, tt.want.Kind, tx.Kind()) + assert.Equal(t, tt.want.Source, tx.Source()) + assert.Equal(t, tt.want.Destination, tx.Destination()) + assert.Equal(t, tt.want.Fee, tx.Fee()) + }) + } +} diff --git a/platform/tezos/rpc.go b/platform/tezos/rpc.go index 35a1163ea..177f6e319 100644 --- a/platform/tezos/rpc.go +++ b/platform/tezos/rpc.go @@ -12,3 +12,8 @@ func (c *RpcClient) GetValidators() (validators []Validator, err error) { err = c.Get(&validators, "chains/main/blocks/head~32768/votes/listings", nil) return } + +func (c *RpcClient) GetAccount(address string) (account Account, err error) { + err = c.Get(&account, "chains/main/blocks/head/context/contracts/"+address, nil) + return +} diff --git a/platform/tezos/stake.go b/platform/tezos/stake.go index ce4946c61..ab8f5971d 100644 --- a/platform/tezos/stake.go +++ b/platform/tezos/stake.go @@ -1,20 +1,17 @@ package tezos import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" services "github.com/trustwallet/blockatlas/services/assets" - "math" - "strconv" ) func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { - account, err := p.stakeClient.GetAccount(address) + account, err := p.rpcClient.GetAccount(address) if err != nil { return nil, err } - if !account.IsDelegated { + if len(account.Delegate) == 0 { return make(blockatlas.DelegationsPage, 0), nil } validators, err := services.GetValidatorsMap(p) @@ -28,13 +25,12 @@ func NormalizeDelegation(account Account, validators blockatlas.ValidatorMap) (b validator, ok := validators[account.Delegate] if !ok { return nil, errors.E("Validator not found", - errors.Params{"Address": account.Address, "Delegate": account.Delegate, "Balance": account.Balance}) + errors.Params{"Delegate": account.Delegate, "Balance": account.Balance}) } - balance := removeDecimals(account.Balance) return blockatlas.DelegationsPage{ { Delegator: validator, - Value: balance, + Value: account.Balance, Status: blockatlas.DelegationStatusActive, }, }, nil @@ -43,7 +39,6 @@ func NormalizeDelegation(account Account, validators blockatlas.ValidatorMap) (b func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { results := make(blockatlas.ValidatorPage, 0) validators, err := p.rpcClient.GetValidators() - if err != nil { return results, err } @@ -51,7 +46,6 @@ func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { for _, v := range validators { results = append(results, normalizeValidator(v)) } - return results, nil } @@ -60,11 +54,11 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { } func (p *Platform) UndelegatedBalance(address string) (string, error) { - account, err := p.stakeClient.GetAccount(address) + account, err := p.rpcClient.GetAccount(address) if err != nil { return "0", err } - return removeDecimals(account.Balance), nil + return account.Balance, nil } func getDetails() blockatlas.StakingDetails { @@ -79,17 +73,9 @@ func getDetails() blockatlas.StakingDetails { func normalizeValidator(v Validator) (validator blockatlas.Validator) { // How to calculate Tezos APR? I have no idea. Tezos team does not know either. let's assume it's around 7% - no way to calculate in decentralized manner // Delegation rewards distributed by the validators manually, it's up to them to do it. - return blockatlas.Validator{ Status: true, ID: v.Address, Details: getDetails(), } } - -func removeDecimals(volume float64) string { - decimals := coin.Coins[coin.XTZ].Decimals - d := math.Pow10(int(decimals)) - v := volume * d - return strconv.Itoa(int(v)) -} diff --git a/platform/tezos/stake_test.go b/platform/tezos/stake_test.go index 475471165..cf8a50983 100644 --- a/platform/tezos/stake_test.go +++ b/platform/tezos/stake_test.go @@ -7,46 +7,10 @@ import ( "testing" ) -const delegationsSrc = ` -{ - "op": { - "signature": "sigvHd2YBByFXU8nL4CZKSTYXNdMapMsJw1f239YRRjgz9NvrTyA6iGnpBDhi9kCB4zMHysrg9H4jxcpPH975WiQtEmkMjb5", - "blockUuid": "4b292c55-41ba-4383-a1d6-03fb71b88f41", - "opHash": "opGphHGNEZZN5rF78yxwe9BJydxYA2yqxECnZR6s6HcxXtCg8Sj", - "uuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", - "chainId": "NetXdQprcVkpaWU", - "blockHash": "BLkscXpE63gajVzmgBS7fQx63hERKQRCZFGtMXdYY6WPThHyji7", - "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", - "branch": "BKqtLegZfdPR3USyYYcMpedB59W5eUBuFZAVpVMPpFgEvMcZjr1", - "blockLevel": 791778, - "blockTimestamp": "2020-01-22T22:13:38Z", - "insertedTimestamp": "2020-01-22 22:14:05.937406 UTC" - }, - "delegation": { - "storageLimit": "257", - "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - "opUuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", - "uuid": "6459fcd9-5eee-4999-ac4d-92330b9eaab3", - "gasLimit": "10600", - "kind": "delegation", - "operationResultStatus": "applied", - "fee": "1500", - "operationResultUuid": "791f6ec7-ecec-43d5-82ca-a1497be0188c", - "operationResultConsumedGas": "10000", - "counter": "2409130", - "operationResultErrors": null, - "source": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - "insertedTimestamp": "2020-01-22 22:15:12.038586 UTC", - "metadataUuid": "85b42f50-1a89-421c-bcb0-a06926941bc4" - } -}` - const accountSrc = ` { - "address": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - "total_balance": 68995.611927, - "is_delegated": true + "balance": "91237897" }` const validatorSrc = ` @@ -81,7 +45,7 @@ var validatorMap = blockatlas.ValidatorMap{ "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93": stakeValidator, } -var delegationsBalance = "68995611927" +var delegationsBalance = "91237897" var delegation = blockatlas.DelegationsPage{ { @@ -108,23 +72,3 @@ func TestNormalizeDelegations(t *testing.T) { assert.NoError(t, err) assert.Equal(t, delegation, result) } - -func Test_removeDecimals(t *testing.T) { - tests := []struct { - name string - volume float64 - want string - }{ - {"one float precision", 9.5, "9500000"}, - {"zero float precision", 9, "9000000"}, - {"five float precision", 9.00005, "9000050"}, - {"six float precision", 9.000005, "9000005"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := removeDecimals(tt.volume); got != tt.want { - t.Errorf("removeDecimals() = %v, want %v", got, tt.want) - } - }) - } -} From ba5bf3df7a7641512005cae4cf34938926faade2 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 12:11:11 -0300 Subject: [PATCH 070/506] uncomment polkadot platform --- platform/registry.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/registry.go b/platform/registry.go index 4326eb1e9..2fc42a56c 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -3,6 +3,7 @@ package platform import ( "fmt" "github.com/trustwallet/blockatlas/platform/cosmos" + "github.com/trustwallet/blockatlas/platform/polkadot" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -79,7 +80,7 @@ var platformList = []blockatlas.Platform{ &algorand.Platform{}, &nano.Platform{}, &harmony.Platform{}, - //&polkadot.Platform{CoinIndex: coin.KSM}, + &polkadot.Platform{CoinIndex: coin.KSM}, } // Platforms contains all registered platforms by handle From 8811aafd54e45935543ce78a6430359ddc0d319c Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 16:33:29 -0300 Subject: [PATCH 071/506] goreleaser action --- .github/workflows/goreleaser.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/goreleaser.yml diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml new file mode 100644 index 000000000..259b4f284 --- /dev/null +++ b/.github/workflows/goreleaser.yml @@ -0,0 +1,30 @@ +name: goreleaser +on: + push: + tags: + - '*' + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Unshallow + run: git fetch --prune --unshallow + - + name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: 1.13.x + - + name: Run GoReleaser + uses: goreleaser/goreleaser-action@v1 + with: + version: latest + args: release --rm-dist + key: ${{ secrets.YOUR_PRIVATE_KEY }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 7d7e960d0e389547dce90db360f961d57465461d Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 16:39:01 -0300 Subject: [PATCH 072/506] CI cache (#798) * parallel jobs * remove goreleaser --- azure-pipelines.yml | 75 +++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a90c08f8b..7ab7e6552 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,70 +15,71 @@ pool: vmImage: 'Ubuntu 16.04' variables: - GITHUB_TOKEN: '$(git.token)' - GOBIN: '$(GOPATH)/bin' # Go binaries path - GOROOT: '/usr/local/go1.13' # Go installation path - GOPATH: '$(Build.SourcesDirectory)/gopath' # Go workspace path - modulePath: '$(GOPATH)/src/github.com/trustwallet/blockatlas' # Path to the module's code + GOVERSION: '1.13' jobs: - - job: Pipeline + - job: environment steps: - - script: | - mkdir -p '$(GOBIN)' - mkdir -p '$(GOPATH)/pkg' - mkdir -p '$(modulePath)' - shopt -s extglob - shopt -s dotglob - mv !(gopath) '$(modulePath)' - echo '##vso[task.prependpath]$(GOBIN)' - echo '##vso[task.prependpath]$(GOROOT)/bin' - echo '$(go env)' - displayName: 'Set up the Go workspace' + - task: GoTool@0 + inputs: + version: '$(GOVERSION)' + displayName: 'Go Tool' - - script: | - go version - go get -v -t -d ./... - workingDirectory: '$(modulePath)' - displayName: 'Get dependencies' + - task: Go@0 + inputs: + command: 'get' + arguments: '-v -t -d ./...' + workingDirectory: '$(System.DefaultWorkingDirectory)' + displayName: 'Go Get' + - job: go_vet + dependsOn: environment + condition: succeeded() + steps: - script: make govet - workingDirectory: '$(modulePath)' + workingDirectory: '$(System.DefaultWorkingDirectory)' displayName: 'Run go vet' + - job: unit_tests + dependsOn: environment + condition: succeeded() + steps: - script: make test - workingDirectory: '$(modulePath)' + workingDirectory: '$(System.DefaultWorkingDirectory)' displayName: 'Run unit tests' + - job: functional_tests + dependsOn: environment + condition: succeeded() + steps: - script: | go get github.com/gavv/httpexpect make functional - workingDirectory: '$(modulePath)' + workingDirectory: '$(System.DefaultWorkingDirectory)' displayName: "Run functional tests for new PR's" condition: ne(variables['build.sourceBranch'], 'refs/heads/master') continueOnError: true - script: | - go get github.com/gavv/httpexpect make functional - workingDirectory: '$(modulePath)' + workingDirectory: '$(System.DefaultWorkingDirectory)' displayName: 'Run functional tests for new releases' condition: eq(variables['build.sourceBranch'], 'refs/heads/master') continueOnError: false + - job: integration_tests + dependsOn: environment + condition: succeeded() + steps: - script: make integration - workingDirectory: '$(modulePath)' + workingDirectory: '$(System.DefaultWorkingDirectory)' displayName: 'Run integration tests' + - job: build + dependsOn: environment + condition: succeeded() + steps: - script: make go-build - workingDirectory: '$(modulePath)' + workingDirectory: '$(System.DefaultWorkingDirectory)' displayName: 'Build' condition: not(startsWith(variables['build.sourceBranch'], 'refs/tags/')) - - - script: | - curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh - ./bin/goreleaser --rm-dist - workingDirectory: '$(modulePath)' - displayName: 'Go Releaser' - condition: startsWith(variables['build.sourceBranch'], 'refs/tags/') - From 07a8f3db193e330500e9c31c90c0caf7a407eb3b Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 16:56:00 -0300 Subject: [PATCH 073/506] update goreleaser builds --- .goreleaser.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 4769d86bc..bf4b5b3fb 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -3,11 +3,18 @@ before: - git reset --hard - git checkout . builds: - - main: "./main.go" + - id: api + main: "./cmd/api/main.go" + env: + - CGO_ENABLED=0 + - id: observer + main: "./cmd/observer/main.go" + env: + - CGO_ENABLED=0 + - id: syncmarkets + main: "./cmd/syncmarkets/main.go" env: - CGO_ENABLED=0 - ignore: - - goos: darwin archives: - replacements: darwin: Darwin From d51d0ef1111da1a6fee1d426c87739f1fd8de510 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 17:08:08 -0300 Subject: [PATCH 074/506] fix goreleaser arch build --- .goreleaser.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index bf4b5b3fb..d99cd184e 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -5,23 +5,35 @@ before: builds: - id: api main: "./cmd/api/main.go" + goos: + - linux + goarch: + - amd64 env: - CGO_ENABLED=0 - id: observer main: "./cmd/observer/main.go" + goos: + - linux + goarch: + - amd64 env: - CGO_ENABLED=0 - id: syncmarkets main: "./cmd/syncmarkets/main.go" + goos: + - linux + goarch: + - amd64 env: - CGO_ENABLED=0 archives: - replacements: - darwin: Darwin + amd64: 64-bit + 386: 32-bit + darwin: macOS linux: Linux windows: Windows - 386: i386 - amd64: x86_64 checksum: name_template: 'checksums.txt' snapshot: From c4d886df85af0798443668402c058734d1cc0fe5 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 17:11:34 -0300 Subject: [PATCH 075/506] set binary name for goreleaser --- .goreleaser.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index d99cd184e..78ed5dc87 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -4,6 +4,7 @@ before: - git checkout . builds: - id: api + binary: api main: "./cmd/api/main.go" goos: - linux @@ -12,6 +13,7 @@ builds: env: - CGO_ENABLED=0 - id: observer + binary: observer main: "./cmd/observer/main.go" goos: - linux @@ -20,6 +22,7 @@ builds: env: - CGO_ENABLED=0 - id: syncmarkets + binary: syncmarkets main: "./cmd/syncmarkets/main.go" goos: - linux From 698adf1628fa117d1eda3f198356c1a465bd376a Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 20:58:50 -0300 Subject: [PATCH 076/506] Add vechain stake api (#803) --- platform/vechain/client.go | 5 +++++ platform/vechain/model.go | 4 ++++ platform/vechain/stake.go | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 platform/vechain/stake.go diff --git a/platform/vechain/client.go b/platform/vechain/client.go index 919fe8d7f..fe29099ff 100644 --- a/platform/vechain/client.go +++ b/platform/vechain/client.go @@ -62,6 +62,11 @@ func (c *Client) GetTransactionReceiptByID(id string) (transaction TxReceipt, er return } +func (c *Client) GetAccount(address string) (account Account, err error) { + err = c.Get(&account, "accounts/"+address, nil) + return +} + // Creates hex based on address as required for topic criteria // 0xB5e883349e68aB59307d1604555AC890fAC47128 => 0x000000000000000000000000B5e883349e68aB59307d1604555AC890fAC47128 func getFilter(hex string) string { diff --git a/platform/vechain/model.go b/platform/vechain/model.go index 159d014d7..1cdbe63ec 100644 --- a/platform/vechain/model.go +++ b/platform/vechain/model.go @@ -85,3 +85,7 @@ type LogMeta struct { BlockNumber uint64 `json:"blockNumber,omitempty"` BlockTimestamp int64 `json:"blockTimestamp,omitempty"` } + +type Account struct { + Balance string `json:"balance"` +} diff --git a/platform/vechain/stake.go b/platform/vechain/stake.go new file mode 100644 index 000000000..ed993e6a8 --- /dev/null +++ b/platform/vechain/stake.go @@ -0,0 +1,42 @@ +package vechain + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/numbers" +) + +const ( + // TODO: Find a way to have a dynamic APR + // The current value comes from https://www.stakingrewards.com/asset/vechain + Annual = 1.35 +) + +func (p *Platform) GetDetails() blockatlas.StakingDetails { + return blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: Annual}, + MinimumAmount: "0", + LockTime: 0, + Type: blockatlas.DelegationTypeAuto, + } +} + +func (p *Platform) UndelegatedBalance(address string) (string, error) { + acc, err := p.client.GetAccount(address) + if err != nil { + return "0", err + } + balance, err := numbers.HexToDecimal(acc.Balance) + if err != nil { + return "0", errors.E("Invalid asset balance", errors.Params{"balance": acc.Balance}) + } + return balance, nil +} + +func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { + return blockatlas.ValidatorPage{}, nil +} + +func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + return blockatlas.DelegationsPage{}, nil +} From 92bf6565aa12fdd62f1ac7074af034d2b65c94b9 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 20:59:44 -0300 Subject: [PATCH 077/506] split stake files (#802) * put stake implementation in antoher file * Add literals to create slice --- platform/algorand/api.go | 26 -------------------------- platform/algorand/stake.go | 33 +++++++++++++++++++++++++++++++++ platform/iotex/api.go | 27 --------------------------- platform/iotex/stake.go | 31 +++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 53 deletions(-) create mode 100644 platform/algorand/stake.go create mode 100644 platform/iotex/stake.go diff --git a/platform/algorand/api.go b/platform/algorand/api.go index ed6ef66b9..da2e015a8 100644 --- a/platform/algorand/api.go +++ b/platform/algorand/api.go @@ -47,32 +47,6 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return NormalizeTxs(txs), nil } -func (p *Platform) GetDetails() blockatlas.StakingDetails { - //TODO: Find a way to have a dynamic - return blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 6.1}, - MinimumAmount: blockatlas.Amount("0"), - LockTime: 0, - Type: blockatlas.DelegationTypeAuto, - } -} - -func (p *Platform) UndelegatedBalance(address string) (string, error) { - acc, err := p.client.GetAccount(address) - if err != nil { - return "0", err - } - return strconv.FormatUint(acc.Amount, 10), nil -} - -func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { - return make(blockatlas.ValidatorPage, 0), nil -} - -func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { - return make(blockatlas.DelegationsPage, 0), nil -} - func NormalizeTxs(txs []Transaction) []blockatlas.Tx { result := make([]blockatlas.Tx, 0) diff --git a/platform/algorand/stake.go b/platform/algorand/stake.go new file mode 100644 index 000000000..4adfa2f39 --- /dev/null +++ b/platform/algorand/stake.go @@ -0,0 +1,33 @@ +package algorand + +import ( + "strconv" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) GetDetails() blockatlas.StakingDetails { + //TODO: Find a way to have a dynamic + return blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 6.1}, + MinimumAmount: "0", + LockTime: 0, + Type: blockatlas.DelegationTypeAuto, + } +} + +func (p *Platform) UndelegatedBalance(address string) (string, error) { + acc, err := p.client.GetAccount(address) + if err != nil { + return "0", err + } + return strconv.FormatUint(acc.Amount, 10), nil +} + +func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { + return blockatlas.ValidatorPage{}, nil +} + +func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + return blockatlas.DelegationsPage{}, nil +} diff --git a/platform/iotex/api.go b/platform/iotex/api.go index 117aebc65..18b29492d 100644 --- a/platform/iotex/api.go +++ b/platform/iotex/api.go @@ -47,7 +47,6 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { } func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - txs := make([]blockatlas.Tx, 0) var start int64 @@ -121,29 +120,3 @@ func Normalize(trx *ActionInfo) *blockatlas.Tx { }, } } - -func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { - return p.client.GetValidators() -} - -func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { - return p.client.GetDelegations(address) -} - -func (p *Platform) GetDetails() blockatlas.StakingDetails { - return blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: blockatlas.Amount("100000000000000000000"), - LockTime: 259200, - Type: blockatlas.DelegationTypeDelegate, - } -} - -func (p *Platform) UndelegatedBalance(address string) (string, error) { - account, err := p.client.GetAccount(address) - if err != nil { - return "0", err - } - - return account.AccountMeta.Balance, nil -} diff --git a/platform/iotex/stake.go b/platform/iotex/stake.go new file mode 100644 index 000000000..dc8b24fb9 --- /dev/null +++ b/platform/iotex/stake.go @@ -0,0 +1,31 @@ +package iotex + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { + return p.client.GetValidators() +} + +func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + return p.client.GetDelegations(address) +} + +func (p *Platform) GetDetails() blockatlas.StakingDetails { + return blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 0}, + MinimumAmount: blockatlas.Amount("100000000000000000000"), + LockTime: 259200, + Type: blockatlas.DelegationTypeDelegate, + } +} + +func (p *Platform) UndelegatedBalance(address string) (string, error) { + account, err := p.client.GetAccount(address) + if err != nil { + return "0", err + } + + return account.AccountMeta.Balance, nil +} From d6a8c889ba89905eca11a4fb1499bc2644b512f5 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 21:00:05 -0300 Subject: [PATCH 078/506] Add ontology stake api (#801) --- platform/ontology/client.go | 9 ++++++++ platform/ontology/model.go | 22 ++++++++++++++++++ platform/ontology/model_test.go | 41 +++++++++++++++++++++++++++++++++ platform/ontology/stake.go | 41 +++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 platform/ontology/stake.go diff --git a/platform/ontology/client.go b/platform/ontology/client.go index 2d9a8e100..73cb5cc58 100644 --- a/platform/ontology/client.go +++ b/platform/ontology/client.go @@ -11,6 +11,15 @@ type Client struct { blockatlas.Request } +func (c *Client) GetBalances(address string) (balances BalancesResult, err error) { + path := fmt.Sprintf("v2/addresses/%s/native/balances", address) + err = c.Get(&balances, path, nil) + if err != nil || balances.Msg != MsgSuccess { + return balances, errors.E(err, "explorer client GetBalances", errors.Params{"platform": "ONT"}) + } + return +} + func (c *Client) GetTxsOfAddress(address string) (txPage TxsResult, err error) { query := url.Values{"page_size": {"20"}, "page_number": {"1"}} path := fmt.Sprintf("v2/addresses/%s/transactions", address) diff --git a/platform/ontology/model.go b/platform/ontology/model.go index e0a03798f..ae54ab78b 100644 --- a/platform/ontology/model.go +++ b/platform/ontology/model.go @@ -3,6 +3,7 @@ package ontology type AssetType string type MsgType string type Transfers []Transfer +type Balances []Balance const ( GovernanceContract = "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK" @@ -40,6 +41,11 @@ type TxResult struct { Result Tx `json:"result"` } +type BalancesResult struct { + BaseResponse + Result Balances `json:"result"` +} + type BlockRecords struct { Total int64 `json:"total"` Records []Block `json:"records"` @@ -76,6 +82,13 @@ type Transfer struct { Description string `json:"description,omitempty"` } +type Balance struct { + Balance string `json:"balance"` + AssetName AssetType `json:"asset_name"` + AssetType string `json:"asset_type"` + ContractHash string `json:"contract_hash"` +} + func (tf *Transfer) isFeeTransfer() bool { if tf.AssetName != AssetONG { return false @@ -128,3 +141,12 @@ func (tfs Transfers) isClaimReward() bool { return true } + +func (bs Balances) getBalance(assetType AssetType) *Balance { + for _, b := range bs { + if b.AssetName == assetType { + return &b + } + } + return nil +} diff --git a/platform/ontology/model_test.go b/platform/ontology/model_test.go index b482e6360..72b03d390 100644 --- a/platform/ontology/model_test.go +++ b/platform/ontology/model_test.go @@ -1,6 +1,7 @@ package ontology import ( + "github.com/stretchr/testify/assert" "reflect" "testing" ) @@ -128,3 +129,43 @@ func TestTransfers_isClaimReward(t *testing.T) { }) } } + +func TestBalances_getBalance(t *testing.T) { + tests := []struct { + name string + bs Balances + assetType AssetType + want *Balance + }{ + { + "test three assets", + Balances{{AssetName: AssetONT, Balance: "0"}, {AssetName: AssetONG, Balance: "1"}, {AssetName: AssetAll, Balance: "2"}}, + AssetONG, + &Balance{AssetName: AssetONG, Balance: "1"}, + }, + { + "test two assets", + Balances{{AssetName: AssetONT, Balance: "0"}, {AssetName: AssetONG, Balance: "1"}}, + AssetONT, + &Balance{AssetName: AssetONT, Balance: "0"}, + }, + { + "test invalid asset 1", + Balances{{AssetName: AssetONG, Balance: "0"}, {AssetName: AssetONG, Balance: "1"}, {AssetName: AssetAll, Balance: "2"}}, + AssetONT, + nil, + }, + { + "test invalid asset 2", + Balances{{AssetName: AssetONT, Balance: "0"}}, + AssetONG, + nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.bs.getBalance(tt.assetType) + assert.EqualValues(t, tt.want, got) + }) + } +} diff --git a/platform/ontology/stake.go b/platform/ontology/stake.go new file mode 100644 index 000000000..135434405 --- /dev/null +++ b/platform/ontology/stake.go @@ -0,0 +1,41 @@ +package ontology + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" +) + +const ( + // TODO: Find a way to have a dynamic APR + // The current value comes from https://cryptoslate.com/coins/ontology + Annual = 4.45 +) + +func (p *Platform) GetDetails() blockatlas.StakingDetails { + return blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: Annual}, + MinimumAmount: "0", + LockTime: 0, + Type: blockatlas.DelegationTypeAuto, + } +} + +func (p *Platform) UndelegatedBalance(address string) (string, error) { + acc, err := p.client.GetBalances(address) + if err != nil { + return "0", err + } + balance := acc.Result.getBalance(AssetONT) + if balance == nil { + return "0", errors.E("Invalid asset balance", errors.Params{"asset": AssetONT}) + } + return balance.Balance, nil +} + +func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { + return blockatlas.ValidatorPage{}, nil +} + +func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + return blockatlas.DelegationsPage{}, nil +} From d87112abf65d9552a5a6cb83db2a62b43fae3fc5 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 22:06:14 -0300 Subject: [PATCH 079/506] Follow code pattern --- platform/binance/api.go | 12 +++++------- platform/bitcoin/api.go | 14 ++++++-------- platform/cosmos/api.go | 15 ++++++--------- platform/tezos/api.go | 28 ++++++++++++---------------- storage/subscriptions.go | 12 +++++------- 5 files changed, 34 insertions(+), 47 deletions(-) diff --git a/platform/binance/api.go b/platform/binance/api.go index 5e81f74fe..c3c382ffd 100644 --- a/platform/binance/api.go +++ b/platform/binance/api.go @@ -69,7 +69,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { func (p *Platform) getTxChildChan(srcTxs []Tx) ([]Tx, error) { txs := make([]Tx, 0) var wg sync.WaitGroup - out := make(chan Tx) + out := make(chan Tx, len(srcTxs)) for _, srcTx := range srcTxs { if srcTx.HasChildren != 1 { // Return the same transaction if doesn't have a child @@ -77,7 +77,7 @@ func (p *Platform) getTxChildChan(srcTxs []Tx) ([]Tx, error) { continue } wg.Add(1) - go func(srcTx Tx, out chan Tx) { + go func(srcTx Tx, out chan Tx, wg *sync.WaitGroup) { defer wg.Done() tx, err := p.client.GetTx(srcTx.Hash) if err != nil { @@ -87,12 +87,10 @@ func (p *Platform) getTxChildChan(srcTxs []Tx) ([]Tx, error) { return } out <- tx - }(srcTx, out) + }(srcTx, out, &wg) } - go func() { - wg.Wait() - close(out) - }() + wg.Wait() + close(out) for r := range out { txs = append(txs, r) } diff --git a/platform/bitcoin/api.go b/platform/bitcoin/api.go index 5eb468b39..221bdd097 100644 --- a/platform/bitcoin/api.go +++ b/platform/bitcoin/api.go @@ -118,11 +118,11 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { func (p *Platform) GetAllBlockPages(total, num int64) []Transaction { start := int64(1) var wg sync.WaitGroup - out := make(chan TransactionsList) + out := make(chan TransactionsList, total-start) + wg.Add(int(total - start)) for start < total { - wg.Add(1) start++ - go func(page, num int64, out chan TransactionsList) { + go func(page, num int64, out chan TransactionsList, wg *sync.WaitGroup) { defer wg.Done() block, err := p.client.GetTransactionsByBlock(num, page) if err != nil { @@ -130,12 +130,10 @@ func (p *Platform) GetAllBlockPages(total, num int64) []Transaction { return } out <- block - }(start, num, out) + }(start, num, out, &wg) } - go func() { - wg.Wait() - close(out) - }() + wg.Wait() + close(out) txs := make([]Transaction, 0) for r := range out { txs = append(txs, r.TransactionList()...) diff --git a/platform/cosmos/api.go b/platform/cosmos/api.go index 66362ce73..d957524ac 100644 --- a/platform/cosmos/api.go +++ b/platform/cosmos/api.go @@ -50,10 +50,10 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { tagsList := []string{"transfer.recipient", "message.sender"} var wg sync.WaitGroup - out := make(chan TxPage) + out := make(chan TxPage, len(tagsList)) + wg.Add(len(tagsList)) for _, t := range tagsList { - wg.Add(1) - go func(tag, addr string) { + go func(tag, addr string, wg *sync.WaitGroup) { defer wg.Done() txs, err := p.client.GetAddrTxs(addr, tag) if err != nil { @@ -61,13 +61,10 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return } out <- txs - }(t, address) + }(t, address, &wg) } - go func() { - wg.Wait() - close(out) - }() - + wg.Wait() + close(out) srcTxs := make([]Tx, 0) for r := range out { srcTxs = append(srcTxs, r.Txs...) diff --git a/platform/tezos/api.go b/platform/tezos/api.go index 50f3cbc18..1ae3b1849 100644 --- a/platform/tezos/api.go +++ b/platform/tezos/api.go @@ -29,10 +29,10 @@ func (p *Platform) Coin() coin.Coin { func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { txTypes := []TxType{TxTransactions} var wg sync.WaitGroup - out := make(chan []Transaction) + out := make(chan []Transaction, len(txTypes)) + wg.Add(len(txTypes)) for _, t := range txTypes { - wg.Add(1) - go func(txType TxType, addr string) { + go func(txType TxType, addr string, wg *sync.WaitGroup) { defer wg.Done() txs, err := p.client.GetTxsOfAddress(address, txType) if err != nil { @@ -40,12 +40,10 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return } out <- txs - }(t, address) + }(t, address, &wg) } - go func() { - wg.Wait() - close(out) - }() + wg.Wait() + close(out) srcTxs := make([]Transaction, 0) for r := range out { srcTxs = append(srcTxs, r...) @@ -60,10 +58,10 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { txTypes := []TxType{TxTransactions, TxDelegations} var wg sync.WaitGroup - out := make(chan []Transaction) + out := make(chan []Transaction, len(txTypes)) + wg.Add(len(txTypes)) for _, t := range txTypes { - wg.Add(1) - go func(txType TxType, num int64) { + go func(txType TxType, num int64, wg *sync.WaitGroup) { defer wg.Done() txs, err := p.client.GetBlockByNumber(num, txType) if err != nil { @@ -71,12 +69,10 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { return } out <- txs - }(t, num) + }(t, num, &wg) } - go func() { - wg.Wait() - close(out) - }() + wg.Wait() + close(out) srcTxs := make([]Transaction, 0) for r := range out { srcTxs = append(srcTxs, r...) diff --git a/storage/subscriptions.go b/storage/subscriptions.go index 75a6fc2fc..3a344f21a 100644 --- a/storage/subscriptions.go +++ b/storage/subscriptions.go @@ -19,10 +19,10 @@ func (s *Storage) Lookup(coin uint, addresses []string) ([]blockatlas.Subscripti observers := make([]blockatlas.Subscription, 0) var wg sync.WaitGroup - out := make(chan []blockatlas.Subscription) + out := make(chan []blockatlas.Subscription, len(addresses)) wg.Add(len(addresses)) for _, address := range addresses { - go func(coin uint, addr string) { + go func(coin uint, addr string, wg *sync.WaitGroup) { defer wg.Done() key := getSubscriptionKey(coin, addr) var webhooks []string @@ -35,12 +35,10 @@ func (s *Storage) Lookup(coin uint, addresses []string) ([]blockatlas.Subscripti subs = append(subs, blockatlas.Subscription{Coin: coin, Address: addr, Webhook: webhook}) } out <- subs - }(coin, address) + }(coin, address, &wg) } - go func() { - wg.Wait() - close(out) - }() + wg.Wait() + close(out) for r := range out { observers = append(observers, r...) } From 73df231801fc73272709c1b8f8b86f70e0dc56a6 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 4 Feb 2020 23:19:06 -0300 Subject: [PATCH 080/506] Remove pipeline condition for azp build --- azure-pipelines.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7ab7e6552..4b9e34f46 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -30,7 +30,7 @@ jobs: command: 'get' arguments: '-v -t -d ./...' workingDirectory: '$(System.DefaultWorkingDirectory)' - displayName: 'Go Get' + displayName: 'Get dependencies' - job: go_vet dependsOn: environment @@ -56,16 +56,15 @@ jobs: go get github.com/gavv/httpexpect make functional workingDirectory: '$(System.DefaultWorkingDirectory)' - displayName: "Run functional tests for new PR's" condition: ne(variables['build.sourceBranch'], 'refs/heads/master') continueOnError: true + displayName: "Run functional tests for new PR's" - script: | make functional workingDirectory: '$(System.DefaultWorkingDirectory)' - displayName: 'Run functional tests for new releases' condition: eq(variables['build.sourceBranch'], 'refs/heads/master') - continueOnError: false + displayName: 'Run functional tests for new releases' - job: integration_tests dependsOn: environment @@ -82,4 +81,3 @@ jobs: - script: make go-build workingDirectory: '$(System.DefaultWorkingDirectory)' displayName: 'Build' - condition: not(startsWith(variables['build.sourceBranch'], 'refs/tags/')) From 04561ed0622703bc625784de71a5c5e945093ed1 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Wed, 5 Feb 2020 10:25:06 +0100 Subject: [PATCH 081/506] Add FIO naming support (testnet) (#780) * Add FIO naming support (testnet). * Move data structs to model.go. * Add unit tests to naming service getTLD(). * Rework getTLD(), handle special case of multiple separators. * Code formatting. * Improved error handling, comments. --- api/naming_service.go | 27 +++++++++++++---- api/naming_service_test.go | 30 +++++++++++++++++++ config.yml | 3 +- .../functional/testdata/query_fixtures.json | 3 +- platform/fio/api.go | 14 +++++++++ platform/fio/client.go | 14 +++++++++ platform/fio/model.go | 14 +++++++++ 7 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 api/naming_service_test.go create mode 100644 platform/fio/model.go diff --git a/api/naming_service.go b/api/naming_service.go index a0be1036d..375ba714e 100644 --- a/api/naming_service.go +++ b/api/naming_service.go @@ -2,6 +2,7 @@ package api import ( "github.com/trustwallet/blockatlas/pkg/errors" + "math" "net/http" "strconv" "strings" @@ -14,6 +15,7 @@ import ( "github.com/trustwallet/blockatlas/platform" ) +// TLDMapping Mapping of name TLD's to coin where they are handled var TLDMapping = map[string]uint64{} type LookupBatchPage []blockatlas.Resolved @@ -56,6 +58,7 @@ func MakeLookupRoute(router gin.IRouter) { TLDMapping[".zil"] = CoinType.ZIL // it's on ethereum but same unstoppable api TLDMapping[".crypto"] = CoinType.ZIL + TLDMapping["@fiotestnet"] = CoinType.FIO } // @Summary Lookup .eth / .zil addresses @@ -105,15 +108,15 @@ func sliceAtoi(sa []string) ([]uint64, error) { } func handleLookup(name string, coins []uint64) (result []blockatlas.Resolved, err error) { + // Assumption: format of the name can be decided (top-level-domain), and at most one naming service is tried name = strings.ToLower(name) - ss := strings.Split(name, ".") - if len(ss) == 0 { - return nil, errors.E("name not found", errors.Params{"name": name, "coins": coins}) + tld, err := getTLD(name) + if err != nil { + return nil, errors.E("name format not recognized", errors.Params{"name": name, "coins": coins, "inner_error": err.Error()}) } - tld := "." + ss[len(ss)-1] id, ok := TLDMapping[tld] if !ok { - return nil, errors.E("name not found", errors.Params{"name": name, "coins": coins}) + return nil, errors.E("name not found", errors.Params{"name": name, "coins": coins, "tld": tld}) } api, ok := platform.NamingAPIs[id] if !ok { @@ -122,3 +125,17 @@ func handleLookup(name string, coins []uint64) (result []blockatlas.Resolved, er result, err = api.Lookup(coins, name) return } + +// Obtain tld from then name, e.g. ".ens" from "nick.ens" +func getTLD(name string) (tld string, error error) { + // find last separator + lastSeparatorIdx := int(math.Max( + float64(strings.LastIndex(name, ".")), + float64(strings.LastIndex(name, "@")))) + if lastSeparatorIdx <= -1 || lastSeparatorIdx >= len(name)-1 { + // no separator inside string + return "", errors.E("No TLD found in name", errors.Params{"name": name}) + } + // return tail including separator + return name[lastSeparatorIdx:], nil +} diff --git a/api/naming_service_test.go b/api/naming_service_test.go new file mode 100644 index 000000000..4e47a39c0 --- /dev/null +++ b/api/naming_service_test.go @@ -0,0 +1,30 @@ +package api + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/errors" + "testing" +) + +func checkGetTLD(t *testing.T, name string, expectedTLD string, expectedError error) { + tld, err := getTLD(name) + assert.Equal(t, expectedTLD, tld) + if expectedError == nil { + assert.Nil(t, err) + } else { + assert.NotNil(t, err) + } +} + +func Test_getTLD(t *testing.T) { + checkGetTLD(t, "vitalik.eth", ".eth", nil) + checkGetTLD(t, "vitalik.ens", ".ens", nil) + checkGetTLD(t, "ourxyzwallet.xyz", ".xyz", nil) + checkGetTLD(t, "btc.zil", ".zil", nil) + checkGetTLD(t, "btc.crypto", ".crypto", nil) + checkGetTLD(t, "nick@fiotestnet", "@fiotestnet", nil) + checkGetTLD(t, "a", "", errors.E("No TLD found in name")) // no tld + checkGetTLD(t, "a.", "", errors.E("No TLD found in name")) // empty tld + checkGetTLD(t, "a@b.c", ".c", nil) + checkGetTLD(t, "a.b@c", "@c", nil) +} diff --git a/config.yml b/config.yml index 3dc627b42..0309dfa82 100644 --- a/config.yml +++ b/config.yml @@ -169,7 +169,8 @@ nebulas: api: https://explorer-backend.nebulas.io/api fio: - api: https://addresses.fio.foundation +# api: https://addresses.fio.foundation + api: http://testnet.fioprotocol.io/v1/chain # [BTC] Bitcoin: https://bitcoin.org/ (Blockbook API https://github.com/trezor/blockbook) bitcoin: diff --git a/pkg/tests/functional/testdata/query_fixtures.json b/pkg/tests/functional/testdata/query_fixtures.json index 0e73c21d2..6cf012ee2 100644 --- a/pkg/tests/functional/testdata/query_fixtures.json +++ b/pkg/tests/functional/testdata/query_fixtures.json @@ -11,7 +11,8 @@ "name=vitalik.luxe&coins=60", "name=ourxyzwallet.xyz&coins=60", "name=btc.zil&coins=313", - "name=btc.crypto&coins=313" + "name=btc.crypto&coins=313", + "name=adam@fiotestnet&coins=60" ], "/v1/market/charts": [ "currency=USD&time_start=1574483028&coin=60&token=0xdAC17F958D2ee523a2206206994597C13D831ec7", diff --git a/platform/fio/api.go b/platform/fio/api.go index 77b361fca..0b293d94d 100644 --- a/platform/fio/api.go +++ b/platform/fio/api.go @@ -22,3 +22,17 @@ func (p *Platform) Coin() coin.Coin { func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err error) { return page, err } + +func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { + var result []blockatlas.Resolved + for _, coinId := range coins { + coinObj := coin.Coins[uint(coinId)] + address, err := p.client.lookupPubAddress(name, coinObj.Symbol) + if err != nil { + return result, err + } + result = append(result, blockatlas.Resolved{Coin: coinId, Result: address}) + } + + return result, nil +} diff --git a/platform/fio/client.go b/platform/fio/client.go index 556d1cac3..cbd2551a0 100644 --- a/platform/fio/client.go +++ b/platform/fio/client.go @@ -2,8 +2,22 @@ package fio import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" ) +// Client for FIO API type Client struct { blockatlas.Request } + +func (c *Client) lookupPubAddress(name string, coinSymbol string) (address string, error error) { + var res GetPubAddressResponse + err := c.Post(&res, "get_pub_address", GetPubAddressRequest{FioAddress: name, TokenCode: coinSymbol}) + if err != nil { + return "", errors.E(err, "Error lokking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": err.Error()}) + } + if res.Message != "" { + return "", errors.E("Error lokking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": res.Message}) + } + return res.PublicAddress, nil +} diff --git a/platform/fio/model.go b/platform/fio/model.go new file mode 100644 index 000000000..0c506da79 --- /dev/null +++ b/platform/fio/model.go @@ -0,0 +1,14 @@ +package fio + +// GetPubAddressRequest request struct for get_pub_address +type GetPubAddressRequest struct { + FioAddress string `json:"fio_address"` + TokenCode string `json:"token_code"` +} + +// GetPubAddressResponse response struct for get_pub_address +type GetPubAddressResponse struct { + PublicAddress string `json:"public_address"` + BlockNum int `json:"block_num"` + Message string `json:"message"` +} From e6f6ef293d8b1297ebdf0b246848d4d3036539ee Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 5 Feb 2020 07:20:53 -0300 Subject: [PATCH 082/506] Remove some buffered channels and reduce the number of goroutines for observer --- platform/binance/api.go | 11 +++++++---- platform/bitcoin/api.go | 8 ++++++-- platform/ontology/api.go | 2 +- storage/subscriptions.go | 33 +++++++++------------------------ 4 files changed, 23 insertions(+), 31 deletions(-) diff --git a/platform/binance/api.go b/platform/binance/api.go index c3c382ffd..3e5af5057 100644 --- a/platform/binance/api.go +++ b/platform/binance/api.go @@ -49,11 +49,14 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { if err != nil { return nil, err } + + txs := make(blockatlas.TxPage, 0) childTxs, err := p.getTxChildChan(srcTxs.Txs) - if err != nil { - return nil, err + if err == nil { + txs = NormalizeTxs(childTxs, "", "") + } else { + txs = NormalizeTxs(srcTxs.Txs, "", "") } - txs := NormalizeTxs(childTxs, "", "") return &blockatlas.Block{ Number: num, Txs: txs, @@ -69,7 +72,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { func (p *Platform) getTxChildChan(srcTxs []Tx) ([]Tx, error) { txs := make([]Tx, 0) var wg sync.WaitGroup - out := make(chan Tx, len(srcTxs)) + out := make(chan Tx) for _, srcTx := range srcTxs { if srcTx.HasChildren != 1 { // Return the same transaction if doesn't have a child diff --git a/platform/bitcoin/api.go b/platform/bitcoin/api.go index 221bdd097..b8a8b5dca 100644 --- a/platform/bitcoin/api.go +++ b/platform/bitcoin/api.go @@ -116,9 +116,14 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { } func (p *Platform) GetAllBlockPages(total, num int64) []Transaction { + txs := make([]Transaction, 0) + if total <= 1 { + return txs + } + start := int64(1) var wg sync.WaitGroup - out := make(chan TransactionsList, total-start) + out := make(chan TransactionsList) wg.Add(int(total - start)) for start < total { start++ @@ -134,7 +139,6 @@ func (p *Platform) GetAllBlockPages(total, num int64) []Transaction { } wg.Wait() close(out) - txs := make([]Transaction, 0) for r := range out { txs = append(txs, r.TransactionList()...) } diff --git a/platform/ontology/api.go b/platform/ontology/api.go index 6213e634e..7d861f576 100644 --- a/platform/ontology/api.go +++ b/platform/ontology/api.go @@ -150,7 +150,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { func (p *Platform) getTxDetails(srcTx []Tx) ([]Tx, error) { var wg sync.WaitGroup - txsOntV2Chan := make(chan Tx, len(srcTx)) + txsOntV2Chan := make(chan Tx) wg.Add(len(srcTx)) for _, blockTxRaw := range srcTx { go func(blockTxRaw Tx, wg *sync.WaitGroup) { diff --git a/storage/subscriptions.go b/storage/subscriptions.go index 3a344f21a..760bebc56 100644 --- a/storage/subscriptions.go +++ b/storage/subscriptions.go @@ -5,7 +5,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" - "sync" ) const ( @@ -16,31 +15,17 @@ func (s *Storage) Lookup(coin uint, addresses []string) ([]blockatlas.Subscripti if len(addresses) == 0 { return nil, errors.E("cannot look up an empty list") } - observers := make([]blockatlas.Subscription, 0) - var wg sync.WaitGroup - out := make(chan []blockatlas.Subscription, len(addresses)) - wg.Add(len(addresses)) for _, address := range addresses { - go func(coin uint, addr string, wg *sync.WaitGroup) { - defer wg.Done() - key := getSubscriptionKey(coin, addr) - var webhooks []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &webhooks) - if err != nil { - return - } - subs := make([]blockatlas.Subscription, 0) - for _, webhook := range webhooks { - subs = append(subs, blockatlas.Subscription{Coin: coin, Address: addr, Webhook: webhook}) - } - out <- subs - }(coin, address, &wg) - } - wg.Wait() - close(out) - for r := range out { - observers = append(observers, r...) + key := getSubscriptionKey(coin, address) + var webhooks []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &webhooks) + if err != nil { + continue + } + for _, webhook := range webhooks { + observers = append(observers, blockatlas.Subscription{Coin: coin, Address: address, Webhook: webhook}) + } } return observers, nil } From c83c7e3807ddf26003b8e0a971b97302d9cb31c9 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 5 Feb 2020 07:32:26 -0300 Subject: [PATCH 083/506] Add buffered channels to btc and ont --- platform/bitcoin/api.go | 4 ++-- platform/ontology/api.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/bitcoin/api.go b/platform/bitcoin/api.go index b8a8b5dca..92e10d512 100644 --- a/platform/bitcoin/api.go +++ b/platform/bitcoin/api.go @@ -120,10 +120,10 @@ func (p *Platform) GetAllBlockPages(total, num int64) []Transaction { if total <= 1 { return txs } - + start := int64(1) var wg sync.WaitGroup - out := make(chan TransactionsList) + out := make(chan TransactionsList, int(total-start)) wg.Add(int(total - start)) for start < total { start++ diff --git a/platform/ontology/api.go b/platform/ontology/api.go index 7d861f576..6213e634e 100644 --- a/platform/ontology/api.go +++ b/platform/ontology/api.go @@ -150,7 +150,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { func (p *Platform) getTxDetails(srcTx []Tx) ([]Tx, error) { var wg sync.WaitGroup - txsOntV2Chan := make(chan Tx) + txsOntV2Chan := make(chan Tx, len(srcTx)) wg.Add(len(srcTx)) for _, blockTxRaw := range srcTx { go func(blockTxRaw Tx, wg *sync.WaitGroup) { From fb8b9c6935270b36cbfc5c61b4a964a080e04808 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 5 Feb 2020 08:14:59 -0300 Subject: [PATCH 084/506] Improve integrations tests to have more platformss (#807) --- pkg/tests/integration/bitcoin/block.go | 43 ++++++++ pkg/tests/integration/integration_test.go | 119 +------------------- pkg/tests/integration/ontology/block.go | 128 ++++++++++++++++++++++ 3 files changed, 176 insertions(+), 114 deletions(-) create mode 100755 pkg/tests/integration/bitcoin/block.go create mode 100755 pkg/tests/integration/ontology/block.go diff --git a/pkg/tests/integration/bitcoin/block.go b/pkg/tests/integration/bitcoin/block.go new file mode 100755 index 000000000..26fcddb19 --- /dev/null +++ b/pkg/tests/integration/bitcoin/block.go @@ -0,0 +1,43 @@ +// +build integration + +package bitcoin + +import ( + "github.com/trustwallet/blockatlas/platform/bitcoin" + "testing" +) + +const ( + blockNum = 616070 +) + +func TestBitcoin(t *testing.T) { + t.Run("test bitcoin", func(t *testing.T) { + p := &bitcoin.Platform{} + _ = p.Init() + testCurrentBlockNumber(p, t) + testGetBlockByNumber(p, t) + }) +} + +func testCurrentBlockNumber(p *bitcoin.Platform, t *testing.T) { + resp, err := p.CurrentBlockNumber() + if err != nil { + t.Error(err) + } + if resp < 0 { + t.Error("block is < 0") + } +} + +func testGetBlockByNumber(p *bitcoin.Platform, t *testing.T) { + resp, err := p.GetBlockByNumber(int64(blockNum)) + if err != nil { + t.Error(err) + } + + expectedTxs := 2129 + if len(resp.Txs) != expectedTxs { + t.Errorf("invalid tx count for block %d, expected %d", len(resp.Txs), expectedTxs) + } +} diff --git a/pkg/tests/integration/integration_test.go b/pkg/tests/integration/integration_test.go index f09b8c7d9..e714f5227 100755 --- a/pkg/tests/integration/integration_test.go +++ b/pkg/tests/integration/integration_test.go @@ -3,129 +3,20 @@ package integration import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/platform/ontology" + "github.com/trustwallet/blockatlas/pkg/tests/integration/bitcoin" + "github.com/trustwallet/blockatlas/pkg/tests/integration/ontology" "os" "testing" ) -var ( - testBlock = blockatlas.Block{ - Number: 7707834, - Txs: []blockatlas.Tx{ - { - From: "AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE", - To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", - ID: "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb", - Fee: "10000000", - Block: 7707834, - Status: blockatlas.StatusCompleted, - Date: 1580481541, - Coin: coin.Ontology().ID, - Type: blockatlas.TxNativeTokenTransfer, - Meta: blockatlas.AnyAction{ - Name: "Claim Rewards", - Symbol: "ONG", - TokenID: "ong", - Decimals: 9, - Value: "51000000000000", - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, - }, - }, { - From: "ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz", - To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", - ID: "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd", - Fee: "10000000", - Block: 7707834, - Status: blockatlas.StatusCompleted, - Date: 1580481541, - Coin: coin.Ontology().ID, - Type: blockatlas.TxNativeTokenTransfer, - Meta: blockatlas.AnyAction{ - Name: "Claim Rewards", - Symbol: "ONG", - TokenID: "ong", - Decimals: 9, - Value: "113200000000", - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, - }, - }, { - From: "Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS", - To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", - ID: "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3", - Fee: "10000000", - Block: 7707834, - Status: blockatlas.StatusCompleted, - Date: 1580481541, - Coin: coin.Ontology().ID, - Type: blockatlas.TxNativeTokenTransfer, - Meta: blockatlas.AnyAction{ - Name: "Claim Rewards", - Symbol: "ONG", - TokenID: "ong", - Decimals: 9, - Value: "10949000000000", - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, - }, - }, - }, - } - blockNum = 7707834 -) - -func TestOntology(t *testing.T) { +func Test(t *testing.T) { configPath := os.Getenv("TEST_CONFIG") if configPath == "" { config.LoadConfig("../../../config.yml") } else { config.LoadConfig(configPath) } - p := &ontology.Platform{} - _ = p.Init() - testCurrentBlockNumber(p, t) - testGetBlockByNumber(p, t) -} - -func testCurrentBlockNumber(p *ontology.Platform, t *testing.T) { - resp, err := p.CurrentBlockNumber() - if err != nil { - t.Error(err) - } - if resp < 0 { - t.Error("block is < 0") - } -} - -func testGetBlockByNumber(p *ontology.Platform, t *testing.T) { - resp, err := p.GetBlockByNumber(int64(blockNum)) - if err != nil { - t.Error(err) - } - - isSame := resp.Number == testBlock.Number && - resp.Txs[0].Block == testBlock.Txs[0].Block && - resp.Txs[0].Status == testBlock.Txs[0].Status && - resp.Txs[0].Date == testBlock.Txs[0].Date && - resp.Txs[0].Coin == testBlock.Txs[0].Coin - if !isSame { - t.Errorf("Block is not the same") - } - - // check that we have tx hashes of parsed block - txMap := map[string]bool{} - for _, tx := range resp.Txs { - txMap[tx.ID] = true - } - delete(txMap, "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3") - delete(txMap, "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb") - delete(txMap, "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd") - - if len(txMap) > 0 { - t.Errorf("Block is not the same: %v", txMap) - } + ontology.TestOntology(t) + bitcoin.TestBitcoin(t) } diff --git a/pkg/tests/integration/ontology/block.go b/pkg/tests/integration/ontology/block.go new file mode 100755 index 000000000..2238b0a65 --- /dev/null +++ b/pkg/tests/integration/ontology/block.go @@ -0,0 +1,128 @@ +// +build integration + +package ontology + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/ontology" + "testing" +) + +var ( + testBlock = blockatlas.Block{ + Number: 7707834, + Txs: []blockatlas.Tx{ + { + From: "AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE", + To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + ID: "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb", + Fee: "10000000", + Block: 7707834, + Status: blockatlas.StatusCompleted, + Date: 1580481541, + Coin: coin.Ontology().ID, + Type: blockatlas.TxNativeTokenTransfer, + Meta: blockatlas.AnyAction{ + Name: "Claim Rewards", + Symbol: "ONG", + TokenID: "ong", + Decimals: 9, + Value: "51000000000000", + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + }, + }, { + From: "ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz", + To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + ID: "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd", + Fee: "10000000", + Block: 7707834, + Status: blockatlas.StatusCompleted, + Date: 1580481541, + Coin: coin.Ontology().ID, + Type: blockatlas.TxNativeTokenTransfer, + Meta: blockatlas.AnyAction{ + Name: "Claim Rewards", + Symbol: "ONG", + TokenID: "ong", + Decimals: 9, + Value: "113200000000", + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + }, + }, { + From: "Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS", + To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + ID: "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3", + Fee: "10000000", + Block: 7707834, + Status: blockatlas.StatusCompleted, + Date: 1580481541, + Coin: coin.Ontology().ID, + Type: blockatlas.TxNativeTokenTransfer, + Meta: blockatlas.AnyAction{ + Name: "Claim Rewards", + Symbol: "ONG", + TokenID: "ong", + Decimals: 9, + Value: "10949000000000", + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + }, + }, + }, + } +) + +const ( + blockNum = 7707834 +) + +func TestOntology(t *testing.T) { + t.Run("test ontology", func(t *testing.T) { + p := &ontology.Platform{} + _ = p.Init() + testCurrentBlockNumber(p, t) + testGetBlockByNumber(p, t) + }) +} + +func testCurrentBlockNumber(p *ontology.Platform, t *testing.T) { + resp, err := p.CurrentBlockNumber() + if err != nil { + t.Error(err) + } + if resp < 0 { + t.Error("block is < 0") + } +} + +func testGetBlockByNumber(p *ontology.Platform, t *testing.T) { + resp, err := p.GetBlockByNumber(int64(blockNum)) + if err != nil { + t.Error(err) + } + + isSame := resp.Number == testBlock.Number && + resp.Txs[0].Block == testBlock.Txs[0].Block && + resp.Txs[0].Status == testBlock.Txs[0].Status && + resp.Txs[0].Date == testBlock.Txs[0].Date && + resp.Txs[0].Coin == testBlock.Txs[0].Coin + if !isSame { + t.Errorf("Block is not the same") + } + + // check that we have tx hashes of parsed block + txMap := map[string]bool{} + for _, tx := range resp.Txs { + txMap[tx.ID] = true + } + delete(txMap, "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3") + delete(txMap, "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb") + delete(txMap, "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd") + + if len(txMap) > 0 { + t.Errorf("Block is not the same: %v", txMap) + } +} From a908531c6c72f5d51e4eee0753108d8c2c5fefb8 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 5 Feb 2020 16:22:18 -0300 Subject: [PATCH 085/506] Add integrations tests for naming services domains (#808) --- api/naming_service.go | 53 +-------- pkg/tests/integration/domains/domains.go | 112 ++++++++++++++++++ pkg/tests/integration/integration_test.go | 11 +- services/domains/domains.go | 56 +++++++++ .../domains/domains_test.go | 2 +- 5 files changed, 179 insertions(+), 55 deletions(-) create mode 100644 pkg/tests/integration/domains/domains.go create mode 100644 services/domains/domains.go rename api/naming_service_test.go => services/domains/domains_test.go (98%) diff --git a/api/naming_service.go b/api/naming_service.go index 375ba714e..44cfdd20a 100644 --- a/api/naming_service.go +++ b/api/naming_service.go @@ -2,7 +2,7 @@ package api import ( "github.com/trustwallet/blockatlas/pkg/errors" - "math" + "github.com/trustwallet/blockatlas/services/domains" "net/http" "strconv" "strings" @@ -10,14 +10,9 @@ import ( "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/gin-gonic/gin" - CoinType "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/platform" ) -// TLDMapping Mapping of name TLD's to coin where they are handled -var TLDMapping = map[string]uint64{} - type LookupBatchPage []blockatlas.Resolved // @Summary Lookup .eth / .zil addresses @@ -40,7 +35,7 @@ func MakeLookupRoute(router gin.IRouter) { return } - result, err := handleLookup(name, []uint64{coin}) + result, err := domains.HandleLookup(name, []uint64{coin}) if err != nil { ginutils.RenderError(c, http.StatusBadRequest, err.Error()) return @@ -51,14 +46,6 @@ func MakeLookupRoute(router gin.IRouter) { } ginutils.RenderSuccess(c, result[0]) }) - - TLDMapping[".eth"] = CoinType.ETH - TLDMapping[".xyz"] = CoinType.ETH - TLDMapping[".luxe"] = CoinType.ETH - TLDMapping[".zil"] = CoinType.ZIL - // it's on ethereum but same unstoppable api - TLDMapping[".crypto"] = CoinType.ZIL - TLDMapping["@fiotestnet"] = CoinType.FIO } // @Summary Lookup .eth / .zil addresses @@ -76,13 +63,12 @@ func MakeLookupBatchRoute(router gin.IRouter) { name := c.Query("name") coinsRaw := strings.Split(c.Query("coins"), ",") coins, err := sliceAtoi(coinsRaw) - if err != nil { ginutils.RenderError(c, http.StatusBadRequest, "coin query is invalid") return } - result, err := handleLookup(name, coins) + result, err := domains.HandleLookup(name, coins) if err != nil { ginutils.RenderError(c, http.StatusBadRequest, err.Error()) return @@ -106,36 +92,3 @@ func sliceAtoi(sa []string) ([]uint64, error) { } return si, nil } - -func handleLookup(name string, coins []uint64) (result []blockatlas.Resolved, err error) { - // Assumption: format of the name can be decided (top-level-domain), and at most one naming service is tried - name = strings.ToLower(name) - tld, err := getTLD(name) - if err != nil { - return nil, errors.E("name format not recognized", errors.Params{"name": name, "coins": coins, "inner_error": err.Error()}) - } - id, ok := TLDMapping[tld] - if !ok { - return nil, errors.E("name not found", errors.Params{"name": name, "coins": coins, "tld": tld}) - } - api, ok := platform.NamingAPIs[id] - if !ok { - return nil, errors.E("platform not found", errors.Params{"name": name, "coins": coins}) - } - result, err = api.Lookup(coins, name) - return -} - -// Obtain tld from then name, e.g. ".ens" from "nick.ens" -func getTLD(name string) (tld string, error error) { - // find last separator - lastSeparatorIdx := int(math.Max( - float64(strings.LastIndex(name, ".")), - float64(strings.LastIndex(name, "@")))) - if lastSeparatorIdx <= -1 || lastSeparatorIdx >= len(name)-1 { - // no separator inside string - return "", errors.E("No TLD found in name", errors.Params{"name": name}) - } - // return tail including separator - return name[lastSeparatorIdx:], nil -} diff --git a/pkg/tests/integration/domains/domains.go b/pkg/tests/integration/domains/domains.go new file mode 100644 index 000000000..5cfb2b825 --- /dev/null +++ b/pkg/tests/integration/domains/domains.go @@ -0,0 +1,112 @@ +// +build integration + +package domains + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/domains" + "testing" +) + +func TestDomains(t *testing.T) { + var tests = []struct { + name string + domain string + coins []uint64 + Expected []blockatlas.Resolved + wantErr bool + }{ + { + "test .eth domain", + "vitalik.eth", + []uint64{coin.ETH}, + []blockatlas.Resolved{{Result: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", Coin: coin.ETH}}, + false, + }, + { + "test .luxe domain", + "vitalik.luxe", + []uint64{coin.ETH}, + []blockatlas.Resolved{{Result: "0xD8A667312D5260F12a306Ae7730C754d938da86c", Coin: coin.ETH}}, + false, + }, + { + "test .xyz domain", + "ourxyzwallet.xyz", + []uint64{coin.ETH}, + []blockatlas.Resolved{{Result: "0x0C54eEAd78d555bE3cbCD451424F9A27a7843935", Coin: coin.ETH}}, + false, + }, + { + "test .zil domain", + "dpantani.zil", + []uint64{coin.ZIL}, + []blockatlas.Resolved{{Result: "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64", Coin: coin.ZIL}}, + false, + }, + { + "test batch .zil domains", + "dpantani.zil", + []uint64{coin.BTC, coin.ETH, coin.ZIL, coin.LTC, coin.BNB, coin.BCH, coin.DOGE, coin.XRP}, + []blockatlas.Resolved{ + {Result: "bc1qd7eystu9xl53hkyxm4kyg7h5yk4p436sqx6f27", Coin: coin.BTC}, + {Result: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", Coin: coin.ETH}, + {Result: "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64", Coin: coin.ZIL}, + {Result: "ltc1qz6nd472gx5gl3urfeldkrhg3h83c8tp2m7m6sd", Coin: coin.LTC}, + {Result: "bnb1h4vyuuytu4rm86ust29wwlevt95du52383cctm", Coin: coin.BNB}, + {Result: "qzpjlfnzudeu83krv0yk0r2kys67qptj6ys6eg6dms", Coin: coin.BCH}, + {Result: "DP9VmQyDMyB1TWwgXkyRpBa7rTfPYgMvjy", Coin: coin.DOGE}, + {Result: "rUvXBttEXhdwaKjEM2MxbtswHU6AMhUTgJ", Coin: coin.XRP}, + }, + false, + }, + { + "test .crypto domain", + "dpantani.crypto", + []uint64{coin.ZIL}, + []blockatlas.Resolved{ + {Result: "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64", Coin: coin.ZIL}, + }, + false, + }, + { + "test batch .crypto domains", + "dpantani.crypto", + []uint64{coin.BTC, coin.ETH, coin.ZIL, coin.LTC, coin.BNB, coin.BCH, coin.DOGE, coin.XRP}, + []blockatlas.Resolved{ + {Result: "bc1qd7eystu9xl53hkyxm4kyg7h5yk4p436sqx6f27", Coin: coin.BTC}, + {Result: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", Coin: coin.ETH}, + {Result: "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64", Coin: coin.ZIL}, + {Result: "ltc1qz6nd472gx5gl3urfeldkrhg3h83c8tp2m7m6sd", Coin: coin.LTC}, + {Result: "bnb1h4vyuuytu4rm86ust29wwlevt95du52383cctm", Coin: coin.BNB}, + {Result: "qzpjlfnzudeu83krv0yk0r2kys67qptj6ys6eg6dms", Coin: coin.BCH}, + {Result: "DP9VmQyDMyB1TWwgXkyRpBa7rTfPYgMvjy", Coin: coin.DOGE}, + {Result: "rUvXBttEXhdwaKjEM2MxbtswHU6AMhUTgJ", Coin: coin.XRP}, + }, + false, + }, + { + "test batch with invalid coin", + "vitalik.eth", + []uint64{44, coin.ETH}, + []blockatlas.Resolved{{Result: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", Coin: coin.ETH}}, + false, + }, + {"test invalid coin", "vitalik.eth", []uint64{44}, nil, false}, + {"test invalid name", "z9z9z900s982jidhwallet.eth", []uint64{coin.ALGO}, nil, true}, + {"test invalid domain", "vitalik.blabla", []uint64{coin.ALGO}, nil, true}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := domains.HandleLookup(test.domain, test.coins) + if test.wantErr { + assert.NotNil(t, err) + return + } + assert.Nil(t, err) + assert.EqualValues(t, test.Expected, got) + }) + } +} diff --git a/pkg/tests/integration/integration_test.go b/pkg/tests/integration/integration_test.go index e714f5227..3190179ad 100755 --- a/pkg/tests/integration/integration_test.go +++ b/pkg/tests/integration/integration_test.go @@ -4,8 +4,8 @@ package integration import ( "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/pkg/tests/integration/bitcoin" - "github.com/trustwallet/blockatlas/pkg/tests/integration/ontology" + "github.com/trustwallet/blockatlas/pkg/tests/integration/domains" + "github.com/trustwallet/blockatlas/platform" "os" "testing" ) @@ -17,6 +17,9 @@ func Test(t *testing.T) { } else { config.LoadConfig(configPath) } - ontology.TestOntology(t) - bitcoin.TestBitcoin(t) + platform.Init() + + //ontology.TestOntology(t) + //bitcoin.TestBitcoin(t) + domains.TestDomains(t) } diff --git a/services/domains/domains.go b/services/domains/domains.go new file mode 100644 index 000000000..05adb51d6 --- /dev/null +++ b/services/domains/domains.go @@ -0,0 +1,56 @@ +package domains + +import ( + CoinType "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/platform" + "math" + "strings" +) + +// TLDMapping Mapping of name TLD's to coin where they are handled +var TLDMapping = map[string]uint64{ + ".eth": CoinType.ETH, + ".xyz": CoinType.ETH, + ".luxe": CoinType.ETH, + ".zil": CoinType.ZIL, + ".crypto": CoinType.ZIL, + "@fiotestnet": CoinType.FIO, +} + +func HandleLookup(name string, coins []uint64) ([]blockatlas.Resolved, error) { + // Assumption: format of the name can be decided (top-level-domain), and at most one naming service is tried + name = strings.ToLower(name) + tld, err := getTLD(name) + if err != nil { + return nil, errors.E(err, "name format not recognized", errors.Params{"name": name, "coins": coins}) + } + id, ok := TLDMapping[tld] + if !ok { + return nil, errors.E("name not found", errors.Params{"name": name, "coins": coins, "tld": tld}) + } + api, ok := platform.NamingAPIs[id] + if !ok { + return nil, errors.E("platform not found", errors.Params{"name": name, "coins": coins}) + } + result, err := api.Lookup(coins, name) + if err != nil { + return nil, errors.E(err, "name format not recognized", errors.Params{"name": name, "coins": coins}) + } + return result, nil +} + +// Obtain tld from then name, e.g. ".ens" from "nick.ens" +func getTLD(name string) (tld string, error error) { + // find last separator + lastSeparatorIdx := int(math.Max( + float64(strings.LastIndex(name, ".")), + float64(strings.LastIndex(name, "@")))) + if lastSeparatorIdx <= -1 || lastSeparatorIdx >= len(name)-1 { + // no separator inside string + return "", errors.E("No TLD found in name", errors.Params{"name": name}) + } + // return tail including separator + return name[lastSeparatorIdx:], nil +} diff --git a/api/naming_service_test.go b/services/domains/domains_test.go similarity index 98% rename from api/naming_service_test.go rename to services/domains/domains_test.go index 4e47a39c0..3dc2f45af 100644 --- a/api/naming_service_test.go +++ b/services/domains/domains_test.go @@ -1,4 +1,4 @@ -package api +package domains import ( "github.com/stretchr/testify/assert" From 1b0fd2199ef968acd9967b61d633a6b43df18b2d Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 5 Feb 2020 16:30:17 -0300 Subject: [PATCH 086/506] Add fiotestnet domain test --- pkg/tests/integration/domains/domains.go | 9 +++++++++ pkg/tests/integration/integration_test.go | 7 +++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/pkg/tests/integration/domains/domains.go b/pkg/tests/integration/domains/domains.go index 5cfb2b825..7dcb3f1c8 100644 --- a/pkg/tests/integration/domains/domains.go +++ b/pkg/tests/integration/domains/domains.go @@ -71,6 +71,15 @@ func TestDomains(t *testing.T) { }, false, }, + { + "test @fiotestnet domain", + "adam@fiotestnet", + []uint64{coin.ETH}, + []blockatlas.Resolved{ + {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, + }, + false, + }, { "test batch .crypto domains", "dpantani.crypto", diff --git a/pkg/tests/integration/integration_test.go b/pkg/tests/integration/integration_test.go index 3190179ad..afbca8f02 100755 --- a/pkg/tests/integration/integration_test.go +++ b/pkg/tests/integration/integration_test.go @@ -4,7 +4,9 @@ package integration import ( "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/pkg/tests/integration/bitcoin" "github.com/trustwallet/blockatlas/pkg/tests/integration/domains" + "github.com/trustwallet/blockatlas/pkg/tests/integration/ontology" "github.com/trustwallet/blockatlas/platform" "os" "testing" @@ -19,7 +21,8 @@ func Test(t *testing.T) { } platform.Init() - //ontology.TestOntology(t) - //bitcoin.TestBitcoin(t) + // Add your integration tests here + ontology.TestOntology(t) + bitcoin.TestBitcoin(t) domains.TestDomains(t) } From 6e72d93ec605779e235b7bc4157d44ea0eb3612e Mon Sep 17 00:00:00 2001 From: Mykola <3277207+kolya182@users.noreply.github.com> Date: Wed, 5 Feb 2020 14:06:14 -0800 Subject: [PATCH 087/506] Checksum coingeico Ethreum address (#806) * Add check if token supplied * Ignore binary output in root * Checksum coingeico Ethreum address when store to redis * Fix typos and add test for normalizeTokenId * Add empty check --- .gitignore | 1 + api/maketdata.go | 10 ++- syncmarkets/clients/coingecko/cache.go | 18 +++- syncmarkets/clients/coingecko/cache_test.go | 96 ++++++++++++++++----- 4 files changed, 97 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index 8ebaf946e..4ad0ab859 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /blockatlas /blockatlas.exe /bin/* +*-bin ### APP ### *.csv diff --git a/api/maketdata.go b/api/maketdata.go index d52c0b5bb..c0c35ad90 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -62,7 +62,11 @@ func getTickerHandler(storage storage.Market) func(c *gin.Context) { ginutils.RenderError(c, http.StatusInternalServerError, "Invalid coin") return } - token := c.Query("token") + token := strings.ToUpper(c.Query("token")) + if token == "" { + ginutils.RenderError(c, http.StatusInternalServerError, "Must provide token") + return + } currency := c.DefaultQuery("currency", blockatlas.DefaultCurrency) rate, err := storage.GetRate(strings.ToUpper(currency)) @@ -71,8 +75,8 @@ func getTickerHandler(storage storage.Market) func(c *gin.Context) { return } - coinObj := coin.Coins[uint(coinId)] - result, err := storage.GetTicker(coinObj.Symbol, strings.ToUpper(token)) + symbol := coin.Coins[uint(coinId)].Symbol + result, err := storage.GetTicker(symbol, token) if err != nil { ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) return diff --git a/syncmarkets/clients/coingecko/cache.go b/syncmarkets/clients/coingecko/cache.go index 82587cd91..d05d04b05 100644 --- a/syncmarkets/clients/coingecko/cache.go +++ b/syncmarkets/clients/coingecko/cache.go @@ -19,14 +19,14 @@ func (c Cache) GetCoinsById(id string) (coins []CoinResult, err error) { return } -func (c SymbolsCache) generateId(symbol string, token string) string { +func (c SymbolsCache) generateId(symbol, token string) string { if len(token) > 0 { return fmt.Sprintf("%s:%s", strings.ToUpper(symbol), address.EIP55Checksum(token)) } return strings.ToUpper(symbol) } -func (c SymbolsCache) GetCoinsBySymbol(symbol string, token string) (coin GeckoCoin, err error) { +func (c SymbolsCache) GetCoinsBySymbol(symbol, token string) (coin GeckoCoin, err error) { coin, ok := c[c.generateId(symbol, token)] if !ok { err = errors.E("No coin found by symbol", errors.Params{"symbol": symbol, "token": token}) @@ -77,7 +77,7 @@ func NewCache(coins GeckoCoins) *Cache { } m[coin.Id] = append(m[coin.Id], CoinResult{ Symbol: platformCoin.Symbol, - TokenId: address, + TokenId: normalizeTokenId(platform, address), CoinType: blockatlas.TypeToken, }) } @@ -92,3 +92,15 @@ func getCoinsMap(coins GeckoCoins) map[string]GeckoCoin { } return coinsMap } + +func normalizeTokenId(platform, addr string) string { + if platform == "" || addr == "" { + return "" + } + switch platform { + case "ethereum": + return address.EIP55Checksum(addr) + default: + return addr + } +} diff --git a/syncmarkets/clients/coingecko/cache_test.go b/syncmarkets/clients/coingecko/cache_test.go index aa53df27c..28637a35c 100644 --- a/syncmarkets/clients/coingecko/cache_test.go +++ b/syncmarkets/clients/coingecko/cache_test.go @@ -15,7 +15,7 @@ func Test_NewCache(t *testing.T) { name: "test prepare cache map", coins: GeckoCoins{ GeckoCoin{ - Id: "ethtereum", + Id: "ethereum", Symbol: "eth", Name: "eth", Platforms: nil, @@ -31,7 +31,7 @@ func Test_NewCache(t *testing.T) { Symbol: "0x", Name: "0x", Platforms: Platforms{ - "ethtereum": "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", + "ethereum": "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", }, }, GeckoCoin{ @@ -39,7 +39,7 @@ func Test_NewCache(t *testing.T) { Symbol: "usdt", Name: "usdt", Platforms: Platforms{ - "ethtereum": "0xdac17f958d2ee523a2206206994597c13d831ec7", + "ethereum": "0xdac17f958d2ee523a2206206994597c13d831ec7", }, }, }, @@ -47,14 +47,14 @@ func Test_NewCache(t *testing.T) { "0x": { CoinResult{ Symbol: "eth", - TokenId: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", + TokenId: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", CoinType: "token", }, }, "usdt": { CoinResult{ Symbol: "eth", - TokenId: "0xdac17f958d2ee523a2206206994597c13d831ec7", + TokenId: "0xdAC17F958D2ee523a2206206994597C13D831ec7", CoinType: "token", }, }, @@ -72,7 +72,7 @@ func Test_NewCache(t *testing.T) { func TestClient_GetCoinsById(t *testing.T) { coins := GeckoCoins{ GeckoCoin{ - Id: "ethtereum", + Id: "ethereum", Symbol: "eth", Name: "eth", Platforms: nil, @@ -88,7 +88,7 @@ func TestClient_GetCoinsById(t *testing.T) { Symbol: "0x", Name: "0x", Platforms: Platforms{ - "ethtereum": "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", + "ethereum": "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", }, }, GeckoCoin{ @@ -96,7 +96,7 @@ func TestClient_GetCoinsById(t *testing.T) { Symbol: "usdt", Name: "usdt", Platforms: Platforms{ - "ethtereum": "0xdac17f958d2ee523a2206206994597c13d831ec7", + "ethereum": "0xdac17f958d2ee523a2206206994597c13d831ec7", }, }, } @@ -111,7 +111,7 @@ func TestClient_GetCoinsById(t *testing.T) { expected: []CoinResult{ { Symbol: "eth", - TokenId: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", + TokenId: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", CoinType: "token", }, }, @@ -122,7 +122,7 @@ func TestClient_GetCoinsById(t *testing.T) { expected: []CoinResult{ { Symbol: "eth", - TokenId: "0xdac17f958d2ee523a2206206994597c13d831ec7", + TokenId: "0xdAC17F958D2ee523a2206206994597C13D831ec7", CoinType: "token", }, }, @@ -148,7 +148,7 @@ func Test_NewSymbolsCache(t *testing.T) { name: "test prepare cache map", coins: GeckoCoins{ GeckoCoin{ - Id: "ethtereum", + Id: "ethereum", Symbol: "eth", Name: "eth", Platforms: nil, @@ -164,7 +164,7 @@ func Test_NewSymbolsCache(t *testing.T) { Symbol: "0x", Name: "0x", Platforms: Platforms{ - "ethtereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", + "ethereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", }, }, GeckoCoin{ @@ -172,7 +172,7 @@ func Test_NewSymbolsCache(t *testing.T) { Symbol: "usdt", Name: "usdt", Platforms: Platforms{ - "ethtereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "ethereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", }, }, }, @@ -182,7 +182,7 @@ func Test_NewSymbolsCache(t *testing.T) { Symbol: "0x", Name: "0x", Platforms: Platforms{ - "ethtereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", + "ethereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", }, }, "ETH:0xdAC17F958D2ee523a2206206994597C13D831ec7": GeckoCoin{ @@ -190,11 +190,11 @@ func Test_NewSymbolsCache(t *testing.T) { Symbol: "usdt", Name: "usdt", Platforms: Platforms{ - "ethtereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "ethereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", }, }, "BTC": GeckoCoin{Id: "bitcoin", Symbol: "btc", Name: "btc", Platforms: nil}, - "ETH": GeckoCoin{Id: "ethtereum", Symbol: "eth", Name: "eth", Platforms: nil}, + "ETH": GeckoCoin{Id: "ethereum", Symbol: "eth", Name: "eth", Platforms: nil}, }, }, } @@ -209,7 +209,7 @@ func Test_NewSymbolsCache(t *testing.T) { func TestClient_GetCoinsBySymbol(t *testing.T) { coins := GeckoCoins{ GeckoCoin{ - Id: "ethtereum", + Id: "ethereum", Symbol: "eth", Name: "eth", Platforms: nil, @@ -225,7 +225,7 @@ func TestClient_GetCoinsBySymbol(t *testing.T) { Symbol: "0x", Name: "0x", Platforms: Platforms{ - "ethtereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", + "ethereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", }, }, GeckoCoin{ @@ -233,7 +233,7 @@ func TestClient_GetCoinsBySymbol(t *testing.T) { Symbol: "usdt", Name: "usdt", Platforms: Platforms{ - "ethtereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "ethereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", }, }, } @@ -252,7 +252,7 @@ func TestClient_GetCoinsBySymbol(t *testing.T) { Symbol: "0x", Name: "0x", Platforms: Platforms{ - "ethtereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", + "ethereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", }, }, }, { @@ -264,7 +264,7 @@ func TestClient_GetCoinsBySymbol(t *testing.T) { Symbol: "usdt", Name: "usdt", Platforms: Platforms{ - "ethtereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "ethereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", }, }, }, @@ -282,7 +282,7 @@ func TestClient_GetCoinsBySymbol(t *testing.T) { name: "test fetching eth", symbol: "eth", expected: GeckoCoin{ - Id: "ethtereum", + Id: "ethereum", Symbol: "eth", Name: "eth", Platforms: nil, @@ -298,3 +298,55 @@ func TestClient_GetCoinsBySymbol(t *testing.T) { }) } } + +func Test_NormalizeTokenIDs(t *testing.T) { + tests := []struct { + name string + platform string + address string + expected string + }{ + { + name: "Should checksum Ethereum lowercase address", + platform: "ethereum", + address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", + expected: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", + }, + { + name: "Check if one of the input empty - 1", + platform: "ethereum", + address: "", + expected: "", + }, + { + name: "Check if one of the input empty - 2", + platform: "", + address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", + expected: "", + }, + { + name: "Return empty string if input empty", + platform: "", + address: "", + expected: "", + }, + { + name: "Should return same Stellar address", + platform: "stellar", + address: "SIX-GDMS6EECOH6MBMCP3FYRYEVRBIV3TQGLOFQIPVAITBRJUMTI6V7A2X6Z", + expected: "SIX-GDMS6EECOH6MBMCP3FYRYEVRBIV3TQGLOFQIPVAITBRJUMTI6V7A2X6Z", + }, + { + name: "Should return same Neo address", + platform: "neo", + address: "ab38352559b8b203bde5fddfa0b07d8b2525e132", + expected: "ab38352559b8b203bde5fddfa0b07d8b2525e132", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, normalizeTokenId(tt.platform, tt.address)) + }) + } +} From 00522fd2b5564bce9fa5d2c7097e8435497233a7 Mon Sep 17 00:00:00 2001 From: Mykola Date: Thu, 6 Feb 2020 19:04:04 -0800 Subject: [PATCH 088/506] Fix hanging go routine --- platform/binance/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/binance/api.go b/platform/binance/api.go index 3e5af5057..ab53f5b37 100644 --- a/platform/binance/api.go +++ b/platform/binance/api.go @@ -72,7 +72,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { func (p *Platform) getTxChildChan(srcTxs []Tx) ([]Tx, error) { txs := make([]Tx, 0) var wg sync.WaitGroup - out := make(chan Tx) + out := make(chan Tx, len(srcTxs)) for _, srcTx := range srcTxs { if srcTx.HasChildren != 1 { // Return the same transaction if doesn't have a child From a1381b868990451ce06aada1cc4597abccc08d4a Mon Sep 17 00:00:00 2001 From: Alexander-Derek Rein Date: Fri, 7 Feb 2020 00:21:47 -0300 Subject: [PATCH 089/506] Removes TODOs to support VIP180 tokens other than VeThor (#596) (#815) * Removes TODOs to support VIP180 tokens other than VeThor (#596) * Update platform/vechain/api_test.go Co-Authored-By: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> * Update platform/vechain/api_test.go Co-Authored-By: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> * Update platform/vechain/api_test.go Co-Authored-By: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> * Update platform/vechain/api_test.go Co-Authored-By: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> * Fix referencing wrong variable. Use IDE next time will show erros. Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Co-authored-by: Mykola <3277207+kolya182@users.noreply.github.com> --- platform/vechain/api.go | 23 ++++++++++++----------- platform/vechain/api_test.go | 15 +++++++++++---- platform/vechain/model.go | 6 ++++++ 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/platform/vechain/api.go b/platform/vechain/api.go index 54d28d981..b27253164 100644 --- a/platform/vechain/api.go +++ b/platform/vechain/api.go @@ -99,7 +99,7 @@ func (p *Platform) getTransactionChannel(id string, txChan chan blockatlas.TxPag errors.Params{"id": id}).PushToSentry() } - txs, err := NormalizeTokenTransaction(srcTx, receipt) + txs, err := p.NormalizeTokenTransaction(srcTx, receipt) if err != nil { return errors.E(err, "Failed to NormalizeBlockTransactions tx", errors.TypePlatformUnmarshal, errors.Params{"tx": srcTx}).PushToSentry() @@ -108,7 +108,7 @@ func (p *Platform) getTransactionChannel(id string, txChan chan blockatlas.TxPag return nil } -func NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (blockatlas.TxPage, error) { +func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (blockatlas.TxPage, error) { if receipt.Outputs == nil || len(receipt.Outputs) == 0 { return blockatlas.TxPage{}, errors.E("NormalizeBlockTransaction: Clauses not found", errors.Params{"tx": srcTx}).PushToSentry() } @@ -134,7 +134,7 @@ func NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (blockatlas.TxPage, txs = append(txs, blockatlas.Tx{ ID: srcTx.Id, - Coin: coin.VET, + Coin: p.Coin().ID, From: origin, To: to, Fee: blockatlas.Amount(fee), @@ -143,11 +143,12 @@ func NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (blockatlas.TxPage, Block: srcTx.Meta.BlockNumber, Status: blockatlas.StatusCompleted, Meta: blockatlas.TokenTransfer{ - Name: "", // TODO replace with real name for other coins + // the only supported Token on VeChain is its Gas token + Name: gasTokenName, TokenID: to, Value: blockatlas.Amount(value), - Symbol: "VTHO", // TODO replace with real symbol for other coins - Decimals: 18, // TODO Not all tokens have decimal 18 https://github.com/vechain/token-registry/tree/master/tokens/main + Symbol: gasTokenSymbol, + Decimals: gasTokenDecimals, From: origin, To: address.EIP55Checksum(getRecipientAddress(event.Topics[2])), }, @@ -172,7 +173,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { if err != nil { continue } - tx, err := NormalizeTransaction(t, trxId) + tx, err := p.NormalizeTransaction(t, trxId) if err != nil { continue } @@ -181,7 +182,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func NormalizeTransaction(srcTx LogTransfer, trxId Tx) (blockatlas.Tx, error) { +func (p *Platform) NormalizeTransaction(srcTx LogTransfer, trxId Tx) (blockatlas.Tx, error) { value, err := numbers.HexToDecimal(srcTx.Amount) if err != nil { return blockatlas.Tx{}, err @@ -191,7 +192,7 @@ func NormalizeTransaction(srcTx LogTransfer, trxId Tx) (blockatlas.Tx, error) { return blockatlas.Tx{ ID: srcTx.Meta.TxId, - Coin: coin.VET, + Coin: p.Coin().ID, From: address.EIP55Checksum(srcTx.Sender), To: address.EIP55Checksum(srcTx.Recipient), Fee: blockatlas.Amount(fee), @@ -201,8 +202,8 @@ func NormalizeTransaction(srcTx LogTransfer, trxId Tx) (blockatlas.Tx, error) { Status: blockatlas.StatusCompleted, Meta: blockatlas.Transfer{ Value: blockatlas.Amount(value), - Symbol: coin.Coins[coin.VET].Symbol, - Decimals: 18, + Symbol: p.Coin().Symbol, + Decimals: p.Coin().Decimals, }, }, nil } diff --git a/platform/vechain/api_test.go b/platform/vechain/api_test.go index 01aa8cfdc..c0f697102 100644 --- a/platform/vechain/api_test.go +++ b/platform/vechain/api_test.go @@ -52,6 +52,10 @@ func TestNormalizeTransaction(t *testing.T) { }{ {"Test normalize VET transfer transaction", transferSrc, trxId, expectedTransfer}, } + + platform := Platform{} + + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var tx LogTransfer @@ -62,7 +66,7 @@ func TestNormalizeTransaction(t *testing.T) { errTrxID := json.Unmarshal([]byte(tt.txId), &tId) assert.Nil(t, errTrxID) - actual, err := NormalizeTransaction(tx, tId) + actual, err := platform.NormalizeTransaction(tx, tId) assert.Nil(t, err) assert.Equal(t, tt.expected, actual, "tx don't equal") @@ -140,8 +144,8 @@ var expectedTransferLog = blockatlas.TxPage{ Status: blockatlas.StatusCompleted, Block: 4382764, Meta: blockatlas.TokenTransfer{ - Name: "", - Symbol: "VTHO", + Name: gasTokenName, + Symbol: gasTokenSymbol, TokenID: "0x0000000000000000000000000000456E65726779", From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", To: "0xB5e883349e68aB59307d1604555AC890fAC47128", @@ -160,6 +164,9 @@ func TestNormalizeTokenTransaction(t *testing.T) { }{ {"Normalize VIP180 token transfer", transferLogSrc, trxReceipt, expectedTransferLog}, } + + platform := Platform{} + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var tx Tx @@ -170,7 +177,7 @@ func TestNormalizeTokenTransaction(t *testing.T) { errR := json.Unmarshal([]byte(tt.txReceipt), &receipt) assert.Nil(t, errR) - actual, err := NormalizeTokenTransaction(tx, receipt) + actual, err := platform.NormalizeTokenTransaction(tx, receipt) assert.Nil(t, err) assert.Equal(t, len(actual), 1, "tx could not be normalized") diff --git a/platform/vechain/model.go b/platform/vechain/model.go index 1cdbe63ec..f136c0b3f 100644 --- a/platform/vechain/model.go +++ b/platform/vechain/model.go @@ -5,6 +5,12 @@ const ( rangeUnit = "block" ) +const ( + gasTokenName = "VeThor" + gasTokenSymbol = "VTHO" + gasTokenDecimals = 18 +) + type LogRequest struct { Options Options `json:"options,omitempty"` CriteriaSet []CriteriaSet `json:"criteriaSet,omitempty"` From 43a94241557855dda8be15196fc13d2aac1cefbb Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 7 Feb 2020 12:59:21 -0300 Subject: [PATCH 090/506] Remove observer parse from api (#816) --- api/observer.go | 22 +--------- pkg/blockatlas/observer.go | 26 +++++++++++- {api => pkg/blockatlas}/observer_test.go | 52 ++++++++++++------------ 3 files changed, 52 insertions(+), 48 deletions(-) rename {api => pkg/blockatlas}/observer_test.go (55%) diff --git a/api/observer.go b/api/observer.go index 76ec28191..6b59017a6 100644 --- a/api/observer.go +++ b/api/observer.go @@ -7,7 +7,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/storage" - "strconv" ) func SetupObserverAPI(router gin.IRouter, db *storage.Storage) { @@ -42,7 +41,7 @@ func addCall(storage storage.Addresses) func(c *gin.Context) { ginutils.RenderSuccess(c, blockatlas.Observer{Message: "Added", Status: true}) return } - subs := parseSubscriptions(req.Subscriptions, req.Webhook) + subs := req.ParseSubscriptions() go storage.AddSubscriptions(subs) ginutils.RenderSuccess(c, blockatlas.Observer{Message: "Added", Status: true}) @@ -75,7 +74,7 @@ func deleteCall(storage storage.Addresses) func(c *gin.Context) { return } - subs := parseSubscriptions(req.Subscriptions, req.Webhook) + subs := req.ParseSubscriptions() go storage.DeleteSubscriptions(subs) ginutils.RenderSuccess(c, blockatlas.Observer{Message: "Deleted", Status: true}) } @@ -113,20 +112,3 @@ func statusCall(storage storage.Tracker) func(c *gin.Context) { ginutils.RenderSuccess(c, result) } } - -func parseSubscriptions(subscriptions map[string][]string, webhook string) (subs []blockatlas.Subscription) { - for coinStr, perCoin := range subscriptions { - coin, err := strconv.Atoi(coinStr) - if err != nil { - continue - } - for _, addr := range perCoin { - subs = append(subs, blockatlas.Subscription{ - Coin: uint(coin), - Address: addr, - Webhook: webhook, - }) - } - } - return -} diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go index 588861633..f46cc1120 100644 --- a/pkg/blockatlas/observer.go +++ b/pkg/blockatlas/observer.go @@ -1,8 +1,12 @@ package blockatlas +import "strconv" + +type Subscriptions map[string][]string + type Webhook struct { - Subscriptions map[string][]string `json:"subscriptions"` - Webhook string `json:"webhook"` + Subscriptions Subscriptions `json:"subscriptions"` + Webhook string `json:"webhook"` } type CoinStatus struct { @@ -14,3 +18,21 @@ type Observer struct { Status bool `json:"status"` Message string `json:"message"` } + +func (w *Webhook) ParseSubscriptions() []Subscription { + subs := make([]Subscription, 0) + for coinStr, perCoin := range w.Subscriptions { + coin, err := strconv.Atoi(coinStr) + if err != nil { + continue + } + for _, addr := range perCoin { + subs = append(subs, Subscription{ + Coin: uint(coin), + Address: addr, + Webhook: w.Webhook, + }) + } + } + return subs +} diff --git a/api/observer_test.go b/pkg/blockatlas/observer_test.go similarity index 55% rename from api/observer_test.go rename to pkg/blockatlas/observer_test.go index d2e1e7831..00d73b21f 100644 --- a/api/observer_test.go +++ b/pkg/blockatlas/observer_test.go @@ -1,8 +1,7 @@ -package api +package blockatlas import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "sort" "testing" ) @@ -10,22 +9,18 @@ import ( func Test_parseSubscriptions(t *testing.T) { tests := []struct { name string - subscriptions map[string][]string - webhook string - wantSubs []blockatlas.Subscription + subscriptions Webhook + wantSubs []Subscription }{ { - name: "webhook with 2 coins", - subscriptions: map[string][]string{ - "2": {"zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc"}, - "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, - }, - webhook: "http://127.0.0.1:8080", - wantSubs: []blockatlas.Subscription{ - { - Coin: 2, Webhook: "http://127.0.0.1:8080", - Address: "zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc", + name: "webhook with 1 coin", + subscriptions: Webhook{ + Webhook: "http://127.0.0.1:8080", + Subscriptions: Subscriptions{ + "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, }, + }, + wantSubs: []Subscription{ { Coin: 0, Webhook: "http://127.0.0.1:8080", Address: "xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", @@ -35,13 +30,21 @@ func Test_parseSubscriptions(t *testing.T) { Address: "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL", }, }, - }, { - name: "webhook with 1 coin", - subscriptions: map[string][]string{ - "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, + }, + { + name: "webhook with 2 coins", + subscriptions: Webhook{ + Webhook: "http://127.0.0.1:8080", + Subscriptions: Subscriptions{ + "2": {"zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc"}, + "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, + }, }, - webhook: "http://127.0.0.1:8080", - wantSubs: []blockatlas.Subscription{ + wantSubs: []Subscription{ + { + Coin: 2, Webhook: "http://127.0.0.1:8080", + Address: "zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc", + }, { Coin: 0, Webhook: "http://127.0.0.1:8080", Address: "xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", @@ -53,19 +56,16 @@ func Test_parseSubscriptions(t *testing.T) { }, }, } - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotSubs := parseSubscriptions(tt.subscriptions, tt.webhook) + gotSubs := tt.subscriptions.ParseSubscriptions() sort.Slice(gotSubs, func(i, j int) bool { return gotSubs[i].Coin > gotSubs[j].Coin }) sort.Slice(tt.wantSubs, func(i, j int) bool { return tt.wantSubs[i].Coin > tt.wantSubs[j].Coin }) - if !assert.ObjectsAreEqualValues(tt.wantSubs, gotSubs) { - t.Errorf("parseSubscriptions() = %v, want %v", gotSubs, tt.wantSubs) - } + assert.EqualValues(t, tt.wantSubs, gotSubs) }) } } From 66f632b7062da91fe51f6e1b35891ccf4cb1e62d Mon Sep 17 00:00:00 2001 From: Mykola <3277207+kolya182@users.noreply.github.com> Date: Fri, 7 Feb 2020 11:29:59 -0800 Subject: [PATCH 091/506] Add extracj check for coingeico ethereum address (#818) --- syncmarkets/clients/coingecko/cache.go | 14 ++++++++++++-- syncmarkets/clients/coingecko/cache_test.go | 6 ++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/syncmarkets/clients/coingecko/cache.go b/syncmarkets/clients/coingecko/cache.go index d05d04b05..94b8ffdc1 100644 --- a/syncmarkets/clients/coingecko/cache.go +++ b/syncmarkets/clients/coingecko/cache.go @@ -75,9 +75,15 @@ func NewCache(coins GeckoCoins) *Cache { if !ok { m[coin.Id] = make([]CoinResult, 0) } + + tokenId := normalizeTokenId(platform, address) + if tokenId == "" { + continue + } + m[coin.Id] = append(m[coin.Id], CoinResult{ Symbol: platformCoin.Symbol, - TokenId: normalizeTokenId(platform, address), + TokenId: tokenId, CoinType: blockatlas.TypeToken, }) } @@ -99,7 +105,11 @@ func normalizeTokenId(platform, addr string) string { } switch platform { case "ethereum": - return address.EIP55Checksum(addr) + if len(addr) == 42 && strings.HasPrefix(addr, "0x"){ + return address.EIP55Checksum(addr) + } + return "" + default: return addr } diff --git a/syncmarkets/clients/coingecko/cache_test.go b/syncmarkets/clients/coingecko/cache_test.go index 28637a35c..a1346b489 100644 --- a/syncmarkets/clients/coingecko/cache_test.go +++ b/syncmarkets/clients/coingecko/cache_test.go @@ -324,6 +324,12 @@ func Test_NormalizeTokenIDs(t *testing.T) { address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", expected: "", }, + { + name: "Should not process if address malformed", + platform: "ethereum", + address: "https://etherscan.io/address/0x8Ddc86DbA7ad728012eFc460b8A168Aba60B403B", + expected: "", + }, { name: "Return empty string if input empty", platform: "", From 3590a80e717417721e09943ae597ab88f5332ea2 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sun, 9 Feb 2020 18:10:17 +0900 Subject: [PATCH 092/506] Move collectibles module into collection.go (#821) * Move collectibles module into collection.go * Remove symbol value * Remove unused values --- pkg/blockatlas/collectibles.go | 1 - platform/ethereum/api.go | 221 ----------------- platform/ethereum/api_test.go | 215 ----------------- platform/ethereum/collection.go | 223 ++++++++++++++++++ ...ections_client.go => collection_client.go} | 0 ...ient_test.go => collection_client_test.go} | 0 platform/ethereum/collection_test.go | 203 ++++++++++++++++ 7 files changed, 426 insertions(+), 437 deletions(-) create mode 100644 platform/ethereum/collection.go rename platform/ethereum/{collections_client.go => collection_client.go} (100%) rename platform/ethereum/{collections_client_test.go => collection_client_test.go} (100%) create mode 100644 platform/ethereum/collection_test.go diff --git a/pkg/blockatlas/collectibles.go b/pkg/blockatlas/collectibles.go index ac8cacb9c..254eb9a8f 100644 --- a/pkg/blockatlas/collectibles.go +++ b/pkg/blockatlas/collectibles.go @@ -3,7 +3,6 @@ package blockatlas type Collection struct { Id string `json:"id"` Name string `json:"name"` - Symbol string `json:"symbol"` Slug string `json:"slug"` ImageUrl string `json:"image_url"` Description string `json:"description"` diff --git a/platform/ethereum/api.go b/platform/ethereum/api.go index efd3b6ac4..8871d283c 100644 --- a/platform/ethereum/api.go +++ b/platform/ethereum/api.go @@ -11,7 +11,6 @@ import ( "math/big" "net/http" "strconv" - "strings" ) var ( @@ -195,226 +194,6 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { } } -func (p *Platform) GetCollections(owner string) (blockatlas.CollectionPage, error) { - collections, err := p.collectionsClient.GetCollections(owner) - if err != nil { - return nil, err - } - page := NormalizeCollectionPage(collections, p.CoinIndex, owner) - return page, nil -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func (p *Platform) OldGetCollections(owner string) (blockatlas.CollectionPage, error) { - collections, err := p.collectionsClient.GetCollections(owner) - if err != nil { - return nil, err - } - page := OldNormalizeCollectionPage(collections, p.CoinIndex, owner) - return page, nil -} - -func (p *Platform) GetCollectibles(owner, collectibleID string) (blockatlas.CollectiblePage, error) { - collection, items, err := p.collectionsClient.GetCollectibles(owner, collectibleID) - if err != nil { - return nil, err - } - page := NormalizeCollectiblePage(collection, items, p.CoinIndex) - return page, nil -} - -func NormalizeCollectionPage(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { - for _, collection := range collections { - if len(collection.Contracts) == 0 { - continue - } - item := NormalizeCollection(collection, coinIndex, owner) - if _, ok := supportedTypes[item.Type]; !ok { - continue - } - page = append(page, item) - } - return -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func (p *Platform) OldGetCollectibles(owner, collectibleID string) (blockatlas.CollectiblePage, error) { - collection, items, err := p.collectionsClient.OldGetCollectibles(owner, collectibleID) - if err != nil { - return nil, err - } - page := OldNormalizeCollectiblePage(collection, items, p.CoinIndex) - return page, nil -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func OldNormalizeCollectionPage(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { - for _, collection := range collections { - if len(collection.Contracts) == 0 { - continue - } - item := OldNormalizeCollection(collection, coinIndex, owner) - if _, ok := supportedTypes[item.Type]; !ok { - continue - } - page = append(page, item) - } - return -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func OldNormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas.Collection { - if len(c.Contracts) == 0 { - return blockatlas.Collection{} - } - - description := blockatlas.GetValidParameter(c.Description, c.Contracts[0].Description) - symbol := blockatlas.GetValidParameter(c.Contracts[0].Symbol, "") - collectionId := blockatlas.GetValidParameter(c.Contracts[0].Address, "") - version := blockatlas.GetValidParameter(c.Contracts[0].NftVersion, "") - collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") - if _, ok := slugTokens[collectionType]; ok { - collectionId = createCollectionId(collectionId, c.Slug) - } - - return blockatlas.Collection{ - Name: c.Name, - Symbol: symbol, - Slug: c.Slug, - ImageUrl: c.ImageUrl, - Description: description, - ExternalLink: c.ExternalUrl, - Total: int(c.Total.Int64()), - Id: collectionId, - CategoryAddress: collectionId, - Address: owner, - Version: version, - Coin: coinIndex, - Type: collectionType, - } -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func OldNormalizeCollectible(c *Collection, a Collectible, coinIndex uint) blockatlas.Collectible { - // TODO: fix unprotected code - address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") - collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") - collectionID := address - if _, ok := slugTokens[collectionType]; ok { - collectionID = createCollectionId(address, c.Slug) - } - externalLink := blockatlas.GetValidParameter(a.ExternalLink, a.AssetContract.ExternalLink) - id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") - return blockatlas.Collectible{ - ID: id, - CollectionID: collectionID, - ContractAddress: address, - TokenID: a.TokenId, - CategoryContract: a.AssetContract.Address, - Name: a.Name, - Category: c.Name, - ImageUrl: a.ImagePreviewUrl, - ProviderLink: a.Permalink, - ExternalLink: externalLink, - Type: collectionType, - Description: a.Description, - Coin: coinIndex, - } -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func createCollectionId(address, slug string) string { - return fmt.Sprintf("%s---%s", address, slug) -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func getCollectionId(collectionId string) string { - s := strings.Split(collectionId, "---") - if len(s) != 2 { - return collectionId - } - return s[1] -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func OldNormalizeCollectiblePage(c *Collection, srcPage []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { - if len(c.Contracts) == 0 { - return - } - for _, src := range srcPage { - item := OldNormalizeCollectible(c, src, coinIndex) - if _, ok := supportedTypes[item.Type]; !ok { - continue - } - page = append(page, item) - } - return -} - -func NormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas.Collection { - if len(c.Contracts) == 0 { - return blockatlas.Collection{} - } - - description := blockatlas.GetValidParameter(c.Description, c.Contracts[0].Description) - symbol := blockatlas.GetValidParameter(c.Contracts[0].Symbol, "") - version := blockatlas.GetValidParameter(c.Contracts[0].NftVersion, "") - collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") - - return blockatlas.Collection{ - Name: c.Name, - Symbol: symbol, - Slug: c.Slug, - ImageUrl: c.ImageUrl, - Description: description, - ExternalLink: c.ExternalUrl, - Total: int(c.Total.Int64()), - Id: c.Slug, - CategoryAddress: c.Slug, - Address: owner, - Version: version, - Coin: coinIndex, - Type: collectionType, - } -} - -func NormalizeCollectiblePage(c *Collection, srcPage []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { - if len(c.Contracts) == 0 { - return - } - for _, src := range srcPage { - item := NormalizeCollectible(c, src, coinIndex) - if _, ok := supportedTypes[item.Type]; !ok { - continue - } - page = append(page, item) - } - return -} - -func NormalizeCollectible(c *Collection, a Collectible, coinIndex uint) blockatlas.Collectible { - // TODO: fix unprotected code - address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") - collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") - externalLink := blockatlas.GetValidParameter(a.ExternalLink, a.AssetContract.ExternalLink) - id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") - return blockatlas.Collectible{ - ID: id, - CollectionID: c.Slug, - ContractAddress: address, - TokenID: a.TokenId, - CategoryContract: a.AssetContract.Address, - Name: a.Name, - Category: c.Name, - ImageUrl: a.ImagePreviewUrl, - ProviderLink: a.Permalink, - ExternalLink: externalLink, - Type: collectionType, - Description: a.Description, - Coin: coinIndex, - } -} - func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { account, err := p.client.GetTokens(address) if err != nil { diff --git a/platform/ethereum/api_test.go b/platform/ethereum/api_test.go index 11afe5af2..7b9da9d1e 100644 --- a/platform/ethereum/api_test.go +++ b/platform/ethereum/api_test.go @@ -3,9 +3,7 @@ package ethereum import ( "bytes" "encoding/json" - "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "math/big" "testing" "github.com/trustwallet/blockatlas/coin" @@ -165,23 +163,6 @@ var transferDst = blockatlas.Tx{ }, } -var transferContractDst = blockatlas.Tx{ - ID: "0x77f8a3b2203933493d103a1637de814b4853410b1fb2981c4d2cff4d7a3071ab", - Coin: coin.ETH, - From: "0xf5aea47e57c058881b31ee8fce1002c409188f06", - To: "0x0ae933a89d9e249d0873cfc7ca022fcb3f1280ce", - Fee: "105000000000000", - Date: 1554663642, - Block: 7522781, - Sequence: 88, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: "1999895000000000000", - Symbol: "ETH", - Decimals: 18, - }, -} - var failedDst = blockatlas.Tx{ ID: "0x8dfe7e859f7bdcea4e6f4ada18567d96a51c3aa29e618ef09b80ae99385e191e", Coin: coin.ETH, @@ -282,7 +263,6 @@ type testToken struct { name string apiResponse string expected *blockatlas.Token - token bool } func TestNormalizeToken(t *testing.T) { @@ -321,198 +301,3 @@ func testNormalizeToken(t *testing.T, _test *testToken) { t.Error("token: token don't equal") } } - -const collectionsOwner = "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" - -const collectionsSrc = ` -[ - { - "primary_asset_contracts": [ - { - "address": "0x06012c8cf97bead5deae237070f9587f8e7a266d", - "name": "CryptoKitties", - "symbol": "CKITTY", - "description": "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - "external_link": "https://www.cryptokitties.co/", - "nft_version": "1.0", - "schema_name": "ERC721", - "display_data": { - "images": [ - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/564155.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/546630.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/441529.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/552435.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/524748.png", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/540800.svg" - ], - "card_display_style": "padded" - }, - "image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png" - } - ], - "name": "CryptoKitties", - "slug": "cryptokitties", - "image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", - "description": "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - "external_url": "https://www.cryptokitties.co/", - "featured_image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556589429.png", - "created_date": "2019-04-26T22:13:04.207050", - "owned_asset_count": 3 - }, - { - "primary_asset_contracts": [ - { - "address": "0xf629cbd94d3791c9250152bd8dfbdf380e2a3b9c", - "name": "Coin", - "symbol": "", - "description": null, - "external_link": null, - "nft_version": null, - "schema_name": "ERC20", - "display_data": {} - } - ], - "name": "Enjin Token", - "slug": "enjin-token", - "image_url": "https://storage.googleapis.com/opensea-static/tokens-high-res/ENJ.png", - "description": "This is the collection of owners of EnjinCoin", - "external_url": null, - "owned_asset_count": 20000000000000000000 - }, - { - "primary_asset_contracts": [ - { - "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - "name": "Enjin", - "symbol": "", - "description": "", - "external_link": null, - "nft_version": null, - "schema_name": "ERC1155", - "display_data": {}, - "owner": null, - "created_date": "2019-08-02T23:43:14.666153", - "asset_contract_type": "semi-fungible" - } - ], - "name": "Age of Rust", - "slug": "age-of-rust", - "image_url": "https://storage.opensea.io/age-of-rust-1561960816.jpg", - "description": "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", - "external_url": "https://www.ageofrust.games/", - "featured_image_url": null, - "created_date": "2019-09-03T02:35:56.063685", - "owned_asset_count": 1 - } -] -` - -var collection1Dst = blockatlas.Collection{ - Name: "CryptoKitties", - Symbol: "CKITTY", - Slug: "cryptokitties", - ImageUrl: "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", - Description: "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - ExternalLink: "https://www.cryptokitties.co/", - Total: 3, - CategoryAddress: "cryptokitties", - Id: "cryptokitties", - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - Version: "1.0", - Coin: 60, - Type: "ERC721", -} - -var collection2Dst = blockatlas.Collection{ - Name: "Age of Rust", - Symbol: "", - Slug: "age-of-rust", - ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", - Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", - ExternalLink: "https://www.ageofrust.games/", - Total: 1, - CategoryAddress: "age-of-rust", - Id: "age-of-rust", - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - Version: "", - Coin: 60, - Type: "ERC1155", -} - -func TestNormalizeCollection(t *testing.T) { - var collections []Collection - err := json.Unmarshal([]byte(collectionsSrc), &collections) - assert.Nil(t, err) - page := NormalizeCollectionPage(collections, coin.ETH, collectionsOwner) - assert.Equal(t, len(page), 2, "collections could not be normalized") - expected := blockatlas.CollectionPage{collection1Dst, collection2Dst} - assert.Equal(t, page, expected, "collections don't equal") -} - -const collectibleSrc = ` -[ - { - "token_id": "54277541829991970107421667568590323026590803461896874578610080514640537714688", - "image_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858806.png", - "image_preview_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", - "name": "Rustbits", - "description": "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", - "external_link": "", - "asset_contract": { - "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - "name": "Enjin", - "external_link": null, - "nft_version": null, - "schema_name": "ERC1155", - "display_data": {} - }, - "permalink": "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688" - } -] -` - -var collectibleCollectionDst = Collection{ - Name: "Age of Rust", - ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", - Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", - ExternalUrl: "https://www.ageofrust.games/", - Total: big.NewInt(1), - Slug: "age-of-rust", - Contracts: []PrimaryAssetContract{ - { - Name: "Age of Rust", - Address: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - NftVersion: "", - Symbol: "", - Description: "", - Type: "ERC1155", - Url: "", - }, - }, -} - -var collectibleDst = blockatlas.Collectible{ - ID: "0xfaafdc07907ff5120a76b34b731b278c38d6043c-54277541829991970107421667568590323026590803461896874578610080514640537714688", - CollectionID: "age-of-rust", - TokenID: "54277541829991970107421667568590323026590803461896874578610080514640537714688", - CategoryContract: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - ContractAddress: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - Category: "Age of Rust", - ImageUrl: "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", - ExternalLink: "", - ProviderLink: "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688", - Type: "ERC1155", - Description: "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", - Coin: 60, - Name: "Rustbits", -} - -func TestNormalizeCollectible(t *testing.T) { - var collectible []Collectible - err := json.Unmarshal([]byte(collectibleSrc), &collectible) - assert.Nil(t, err) - page := NormalizeCollectiblePage(&collectibleCollectionDst, collectible, coin.ETH) - assert.Equal(t, len(page), 1, "collectible could not be normalized") - expected := blockatlas.CollectiblePage{collectibleDst} - assert.Equal(t, page, expected, "collectible don't equal") -} diff --git a/platform/ethereum/collection.go b/platform/ethereum/collection.go new file mode 100644 index 000000000..e6527949b --- /dev/null +++ b/platform/ethereum/collection.go @@ -0,0 +1,223 @@ +package ethereum + +import ( + "fmt" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "strings" +) + +func (p *Platform) GetCollections(owner string) (blockatlas.CollectionPage, error) { + collections, err := p.collectionsClient.GetCollections(owner) + if err != nil { + return nil, err + } + page := NormalizeCollectionPage(collections, p.CoinIndex, owner) + return page, nil +} + +//TODO: remove once most of the clients will be updated (deadline: March 17th) +func (p *Platform) OldGetCollections(owner string) (blockatlas.CollectionPage, error) { + collections, err := p.collectionsClient.GetCollections(owner) + if err != nil { + return nil, err + } + page := OldNormalizeCollectionPage(collections, p.CoinIndex, owner) + return page, nil +} + +func (p *Platform) GetCollectibles(owner, collectibleID string) (blockatlas.CollectiblePage, error) { + collection, items, err := p.collectionsClient.GetCollectibles(owner, collectibleID) + if err != nil { + return nil, err + } + page := NormalizeCollectiblePage(collection, items, p.CoinIndex) + return page, nil +} + +func NormalizeCollectionPage(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { + for _, collection := range collections { + if len(collection.Contracts) == 0 { + continue + } + item := NormalizeCollection(collection, coinIndex, owner) + if _, ok := supportedTypes[item.Type]; !ok { + continue + } + page = append(page, item) + } + return +} + +//TODO: remove once most of the clients will be updated (deadline: March 17th) +func (p *Platform) OldGetCollectibles(owner, collectibleID string) (blockatlas.CollectiblePage, error) { + collection, items, err := p.collectionsClient.OldGetCollectibles(owner, collectibleID) + if err != nil { + return nil, err + } + page := OldNormalizeCollectiblePage(collection, items, p.CoinIndex) + return page, nil +} + +//TODO: remove once most of the clients will be updated (deadline: March 17th) +func OldNormalizeCollectionPage(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { + for _, collection := range collections { + if len(collection.Contracts) == 0 { + continue + } + item := OldNormalizeCollection(collection, coinIndex, owner) + if _, ok := supportedTypes[item.Type]; !ok { + continue + } + page = append(page, item) + } + return +} + +//TODO: remove once most of the clients will be updated (deadline: March 17th) +func OldNormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas.Collection { + if len(c.Contracts) == 0 { + return blockatlas.Collection{} + } + + description := blockatlas.GetValidParameter(c.Description, c.Contracts[0].Description) + collectionId := blockatlas.GetValidParameter(c.Contracts[0].Address, "") + version := blockatlas.GetValidParameter(c.Contracts[0].NftVersion, "") + collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") + if _, ok := slugTokens[collectionType]; ok { + collectionId = createCollectionId(collectionId, c.Slug) + } + + return blockatlas.Collection{ + Name: c.Name, + Slug: c.Slug, + ImageUrl: c.ImageUrl, + Description: description, + ExternalLink: c.ExternalUrl, + Total: int(c.Total.Int64()), + Id: collectionId, + CategoryAddress: collectionId, + Address: owner, + Version: version, + Coin: coinIndex, + Type: collectionType, + } +} + +//TODO: remove once most of the clients will be updated (deadline: March 17th) +func OldNormalizeCollectible(c *Collection, a Collectible, coinIndex uint) blockatlas.Collectible { + // TODO: fix unprotected code + address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") + collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") + collectionID := address + if _, ok := slugTokens[collectionType]; ok { + collectionID = createCollectionId(address, c.Slug) + } + externalLink := blockatlas.GetValidParameter(a.ExternalLink, a.AssetContract.ExternalLink) + id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") + return blockatlas.Collectible{ + ID: id, + CollectionID: collectionID, + ContractAddress: address, + TokenID: a.TokenId, + CategoryContract: a.AssetContract.Address, + Name: a.Name, + Category: c.Name, + ImageUrl: a.ImagePreviewUrl, + ProviderLink: a.Permalink, + ExternalLink: externalLink, + Type: collectionType, + Description: a.Description, + Coin: coinIndex, + } +} + +//TODO: remove once most of the clients will be updated (deadline: March 17th) +func createCollectionId(address, slug string) string { + return fmt.Sprintf("%s---%s", address, slug) +} + +//TODO: remove once most of the clients will be updated (deadline: March 17th) +func getCollectionId(collectionId string) string { + s := strings.Split(collectionId, "---") + if len(s) != 2 { + return collectionId + } + return s[1] +} + +//TODO: remove once most of the clients will be updated (deadline: March 17th) +func OldNormalizeCollectiblePage(c *Collection, srcPage []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { + if len(c.Contracts) == 0 { + return + } + for _, src := range srcPage { + item := OldNormalizeCollectible(c, src, coinIndex) + if _, ok := supportedTypes[item.Type]; !ok { + continue + } + page = append(page, item) + } + return +} + +func NormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas.Collection { + if len(c.Contracts) == 0 { + return blockatlas.Collection{} + } + + description := blockatlas.GetValidParameter(c.Description, c.Contracts[0].Description) + version := blockatlas.GetValidParameter(c.Contracts[0].NftVersion, "") + collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") + + return blockatlas.Collection{ + Name: c.Name, + Slug: c.Slug, + ImageUrl: c.ImageUrl, + Description: description, + ExternalLink: c.ExternalUrl, + Total: int(c.Total.Int64()), + Id: c.Slug, + CategoryAddress: c.Slug, + Address: owner, + Version: version, + Coin: coinIndex, + Type: collectionType, + } +} + +func NormalizeCollectiblePage(c *Collection, srcPage []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { + if len(c.Contracts) == 0 { + return + } + for _, src := range srcPage { + item := NormalizeCollectible(c, src, coinIndex) + if _, ok := supportedTypes[item.Type]; !ok { + continue + } + page = append(page, item) + } + return +} + +func NormalizeCollectible(c *Collection, a Collectible, coinIndex uint) blockatlas.Collectible { + // TODO: fix unprotected code + address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") + collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") + externalLink := blockatlas.GetValidParameter(a.ExternalLink, a.AssetContract.ExternalLink) + id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") + return blockatlas.Collectible{ + ID: id, + CollectionID: c.Slug, + ContractAddress: address, + TokenID: a.TokenId, + CategoryContract: a.AssetContract.Address, + Name: a.Name, + Category: c.Name, + ImageUrl: a.ImagePreviewUrl, + ProviderLink: a.Permalink, + ExternalLink: externalLink, + Type: collectionType, + Description: a.Description, + Coin: coinIndex, + } +} diff --git a/platform/ethereum/collections_client.go b/platform/ethereum/collection_client.go similarity index 100% rename from platform/ethereum/collections_client.go rename to platform/ethereum/collection_client.go diff --git a/platform/ethereum/collections_client_test.go b/platform/ethereum/collection_client_test.go similarity index 100% rename from platform/ethereum/collections_client_test.go rename to platform/ethereum/collection_client_test.go diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/collection_test.go new file mode 100644 index 000000000..b54169cdc --- /dev/null +++ b/platform/ethereum/collection_test.go @@ -0,0 +1,203 @@ +package ethereum + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "math/big" + "testing" +) + +const collectionsOwner = "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + +const collectionsSrc = ` +[ + { + "primary_asset_contracts": [ + { + "address": "0x06012c8cf97bead5deae237070f9587f8e7a266d", + "name": "CryptoKitties", + "symbol": "CKITTY", + "description": "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + "external_link": "https://www.cryptokitties.co/", + "nft_version": "1.0", + "schema_name": "ERC721", + "display_data": { + "images": [ + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/564155.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/546630.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/441529.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/552435.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/524748.png", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/540800.svg" + ], + "card_display_style": "padded" + }, + "image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png" + } + ], + "name": "CryptoKitties", + "slug": "cryptokitties", + "image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", + "description": "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + "external_url": "https://www.cryptokitties.co/", + "featured_image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556589429.png", + "created_date": "2019-04-26T22:13:04.207050", + "owned_asset_count": 3 + }, + { + "primary_asset_contracts": [ + { + "address": "0xf629cbd94d3791c9250152bd8dfbdf380e2a3b9c", + "name": "Coin", + "symbol": "", + "description": null, + "external_link": null, + "nft_version": null, + "schema_name": "ERC20", + "display_data": {} + } + ], + "name": "Enjin Token", + "slug": "enjin-token", + "image_url": "https://storage.googleapis.com/opensea-static/tokens-high-res/ENJ.png", + "description": "This is the collection of owners of EnjinCoin", + "external_url": null, + "owned_asset_count": 20000000000000000000 + }, + { + "primary_asset_contracts": [ + { + "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + "name": "Enjin", + "symbol": "", + "description": "", + "external_link": null, + "nft_version": null, + "schema_name": "ERC1155", + "display_data": {}, + "owner": null, + "created_date": "2019-08-02T23:43:14.666153", + "asset_contract_type": "semi-fungible" + } + ], + "name": "Age of Rust", + "slug": "age-of-rust", + "image_url": "https://storage.opensea.io/age-of-rust-1561960816.jpg", + "description": "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", + "external_url": "https://www.ageofrust.games/", + "featured_image_url": null, + "created_date": "2019-09-03T02:35:56.063685", + "owned_asset_count": 1 + } +] +` + +var collection1Dst = blockatlas.Collection{ + Name: "CryptoKitties", + Slug: "cryptokitties", + ImageUrl: "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", + Description: "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + ExternalLink: "https://www.cryptokitties.co/", + Total: 3, + CategoryAddress: "cryptokitties", + Id: "cryptokitties", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Version: "1.0", + Coin: 60, + Type: "ERC721", +} + +var collection2Dst = blockatlas.Collection{ + Name: "Age of Rust", + Slug: "age-of-rust", + ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", + Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", + ExternalLink: "https://www.ageofrust.games/", + Total: 1, + CategoryAddress: "age-of-rust", + Id: "age-of-rust", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Version: "", + Coin: 60, + Type: "ERC1155", +} + +func TestNormalizeCollection(t *testing.T) { + var collections []Collection + err := json.Unmarshal([]byte(collectionsSrc), &collections) + assert.Nil(t, err) + page := NormalizeCollectionPage(collections, coin.ETH, collectionsOwner) + assert.Equal(t, len(page), 2, "collections could not be normalized") + expected := blockatlas.CollectionPage{collection1Dst, collection2Dst} + assert.Equal(t, page, expected, "collections don't equal") +} + +const collectibleSrc = ` +[ + { + "token_id": "54277541829991970107421667568590323026590803461896874578610080514640537714688", + "image_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858806.png", + "image_preview_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", + "name": "Rustbits", + "description": "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", + "external_link": "", + "asset_contract": { + "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + "name": "Enjin", + "external_link": null, + "nft_version": null, + "schema_name": "ERC1155", + "display_data": {} + }, + "permalink": "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688" + } +] +` + +var collectibleCollectionDst = Collection{ + Name: "Age of Rust", + ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", + Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", + ExternalUrl: "https://www.ageofrust.games/", + Total: big.NewInt(1), + Slug: "age-of-rust", + Contracts: []PrimaryAssetContract{ + { + Name: "Age of Rust", + Address: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + NftVersion: "", + Symbol: "", + Description: "", + Type: "ERC1155", + Url: "", + }, + }, +} + +var collectibleDst = blockatlas.Collectible{ + ID: "0xfaafdc07907ff5120a76b34b731b278c38d6043c-54277541829991970107421667568590323026590803461896874578610080514640537714688", + CollectionID: "age-of-rust", + TokenID: "54277541829991970107421667568590323026590803461896874578610080514640537714688", + CategoryContract: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + ContractAddress: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + Category: "Age of Rust", + ImageUrl: "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", + ExternalLink: "", + ProviderLink: "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688", + Type: "ERC1155", + Description: "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", + Coin: 60, + Name: "Rustbits", +} + +func TestNormalizeCollectible(t *testing.T) { + var collectible []Collectible + err := json.Unmarshal([]byte(collectibleSrc), &collectible) + assert.Nil(t, err) + page := NormalizeCollectiblePage(&collectibleCollectionDst, collectible, coin.ETH) + assert.Equal(t, len(page), 1, "collectible could not be normalized") + expected := blockatlas.CollectiblePage{collectibleDst} + assert.Equal(t, page, expected, "collectible don't equal") +} From ec9ad3fa50cdd43dfee73c6d3f52d54b24b2b5d8 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sun, 9 Feb 2020 13:31:22 -0800 Subject: [PATCH 093/506] Revert "Remove symbol value" This reverts commit 6e96e9c6ec83f9e6f09755e4aac2f521b904c531. --- pkg/blockatlas/collectibles.go | 1 + platform/ethereum/collection.go | 4 ++++ platform/ethereum/collection_test.go | 2 ++ 3 files changed, 7 insertions(+) diff --git a/pkg/blockatlas/collectibles.go b/pkg/blockatlas/collectibles.go index 254eb9a8f..ac8cacb9c 100644 --- a/pkg/blockatlas/collectibles.go +++ b/pkg/blockatlas/collectibles.go @@ -3,6 +3,7 @@ package blockatlas type Collection struct { Id string `json:"id"` Name string `json:"name"` + Symbol string `json:"symbol"` Slug string `json:"slug"` ImageUrl string `json:"image_url"` Description string `json:"description"` diff --git a/platform/ethereum/collection.go b/platform/ethereum/collection.go index e6527949b..b28a94701 100644 --- a/platform/ethereum/collection.go +++ b/platform/ethereum/collection.go @@ -80,6 +80,7 @@ func OldNormalizeCollection(c Collection, coinIndex uint, owner string) blockatl } description := blockatlas.GetValidParameter(c.Description, c.Contracts[0].Description) + symbol := blockatlas.GetValidParameter(c.Contracts[0].Symbol, "") collectionId := blockatlas.GetValidParameter(c.Contracts[0].Address, "") version := blockatlas.GetValidParameter(c.Contracts[0].NftVersion, "") collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") @@ -89,6 +90,7 @@ func OldNormalizeCollection(c Collection, coinIndex uint, owner string) blockatl return blockatlas.Collection{ Name: c.Name, + Symbol: symbol, Slug: c.Slug, ImageUrl: c.ImageUrl, Description: description, @@ -166,11 +168,13 @@ func NormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas. } description := blockatlas.GetValidParameter(c.Description, c.Contracts[0].Description) + symbol := blockatlas.GetValidParameter(c.Contracts[0].Symbol, "") version := blockatlas.GetValidParameter(c.Contracts[0].NftVersion, "") collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") return blockatlas.Collection{ Name: c.Name, + Symbol: symbol, Slug: c.Slug, ImageUrl: c.ImageUrl, Description: description, diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/collection_test.go index b54169cdc..c68acb492 100644 --- a/platform/ethereum/collection_test.go +++ b/platform/ethereum/collection_test.go @@ -96,6 +96,7 @@ const collectionsSrc = ` var collection1Dst = blockatlas.Collection{ Name: "CryptoKitties", + Symbol: "CKITTY", Slug: "cryptokitties", ImageUrl: "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", Description: "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", @@ -111,6 +112,7 @@ var collection1Dst = blockatlas.Collection{ var collection2Dst = blockatlas.Collection{ Name: "Age of Rust", + Symbol: "", Slug: "age-of-rust", ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", From 7adbc43986b6b7e4bebbe769249c3265e5ad1e2b Mon Sep 17 00:00:00 2001 From: dpereskokov Date: Mon, 10 Feb 2020 21:11:31 +0800 Subject: [PATCH 094/506] Charts api for all time are slow and solved basic caching logic (#813) * cache logic fix and charts caching * fix tests --- api/maketdata.go | 4 +++- pkg/ginutils/gincache/cache.go | 13 ++++--------- pkg/ginutils/gincache/cache_test.go | 5 +++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/api/maketdata.go b/api/maketdata.go index c0c35ad90..cc57ecf12 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -6,6 +6,7 @@ import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/ginutils/gincache" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" "github.com/trustwallet/blockatlas/storage" @@ -13,6 +14,7 @@ import ( "net/http" "strconv" "strings" + "time" ) const ( @@ -36,7 +38,7 @@ func SetupMarketAPI(router gin.IRouter, db storage.Market) { router.GET("/ticker", getTickerHandler(db)) router.POST("/ticker", getTickersHandler(db)) // Charts - router.GET("/charts", getChartsHandler()) + router.GET("/charts", gincache.CacheMiddleware(time.Minute*5, getChartsHandler())) router.GET("/info", getCoinInfoHandler()) } diff --git a/pkg/ginutils/gincache/cache.go b/pkg/ginutils/gincache/cache.go index 9f11c0440..009e16d81 100644 --- a/pkg/ginutils/gincache/cache.go +++ b/pkg/ginutils/gincache/cache.go @@ -10,7 +10,6 @@ import ( "github.com/patrickmn/go-cache" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/pkg/storage/util" "io/ioutil" "net/http" "sync" @@ -120,16 +119,12 @@ func (mc *memCache) getCache(key string) (*cacheResponse, error) { if !ok { return nil, fmt.Errorf("gin-cache: invalid cache key %s", key) } - r, ok := c.([]byte) + r, ok := c.(cacheResponse) if !ok { - return nil, errors.E("validator cache: failed to cast cache to bytes") + return nil, errors.E("validator cache: failed to cast cacheResponse") } - var result cacheResponse - err := json.Unmarshal(r, &result) - if err != nil { - return nil, errors.E(err, util.ErrNotFound).PushToSentry() - } - return &result, nil + + return &r, nil } func generateKey(c *gin.Context) string { diff --git a/pkg/ginutils/gincache/cache_test.go b/pkg/ginutils/gincache/cache_test.go index 820c5fd4d..3742dec84 100644 --- a/pkg/ginutils/gincache/cache_test.go +++ b/pkg/ginutils/gincache/cache_test.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/ginutils" "net/http/httptest" "testing" "time" @@ -38,7 +39,7 @@ func TestWrite(t *testing.T) { func TestCachePage(t *testing.T) { router := gin.New() router.GET("/cache_ping", CacheMiddleware(time.Second*3, func(c *gin.Context) { - c.String(200, "pong "+fmt.Sprint(time.Now().UnixNano())) + ginutils.RenderSuccess(c, "pong "+fmt.Sprint(time.Now().UnixNano())) })) w1 := performRequest("GET", "/cache_ping", router) @@ -52,7 +53,7 @@ func TestCachePage(t *testing.T) { func TestCachePageExpire(t *testing.T) { router := gin.New() router.GET("/cache_ping", CacheMiddleware(time.Second, func(c *gin.Context) { - c.String(200, "pong "+fmt.Sprint(time.Now().UnixNano())) + ginutils.RenderSuccess(c, "pong "+fmt.Sprint(time.Now().UnixNano())) })) w1 := performRequest("GET", "/cache_ping", router) From 935b0fefefba7dea34bf025d7ba3212fed3db9a6 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 10 Feb 2020 11:06:02 -0300 Subject: [PATCH 095/506] save cache middleware using bytes (#827) --- pkg/ginutils/gincache/cache.go | 29 +++++++++++++++++++------- platform/vechain/api_test.go | 1 - syncmarkets/clients/coingecko/cache.go | 2 +- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/pkg/ginutils/gincache/cache.go b/pkg/ginutils/gincache/cache.go index 009e16d81..bbe26706a 100644 --- a/pkg/ginutils/gincache/cache.go +++ b/pkg/ginutils/gincache/cache.go @@ -10,6 +10,7 @@ import ( "github.com/patrickmn/go-cache" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/pkg/storage/util" "io/ioutil" "net/http" "sync" @@ -76,7 +77,11 @@ func (w *cachedWriter) Write(data []byte) (int, error) { w.Header(), data, } - memoryCache.cache.Set(w.key, val, w.expire) + b, err := json.Marshal(val) + if err != nil { + return 0, errors.E("validator cache: failed to marshal cache object") + } + memoryCache.cache.Set(w.key, b, w.expire) return ret, nil } @@ -93,7 +98,11 @@ func (w *cachedWriter) WriteString(data string) (n int, err error) { w.Header(), []byte(data), } - memoryCache.setCache(w.key, val, w.expire) + b, err := json.Marshal(val) + if err != nil { + return 0, errors.E("validator cache: failed to marshal cache object") + } + memoryCache.setCache(w.key, b, w.expire) return ret, err } @@ -114,17 +123,21 @@ func (mc *memCache) setCache(k string, x interface{}, d time.Duration) { memoryCache.cache.Set(k, b, d) } -func (mc *memCache) getCache(key string) (*cacheResponse, error) { +func (mc *memCache) getCache(key string) (cacheResponse, error) { + var result cacheResponse c, ok := mc.cache.Get(key) if !ok { - return nil, fmt.Errorf("gin-cache: invalid cache key %s", key) + return result, fmt.Errorf("gin-cache: invalid cache key %s", key) } - r, ok := c.(cacheResponse) + r, ok := c.([]byte) if !ok { - return nil, errors.E("validator cache: failed to cast cacheResponse") + return result, errors.E("validator cache: failed to cast cache to bytes") } - - return &r, nil + err := json.Unmarshal(r, &result) + if err != nil { + return result, errors.E(err, util.ErrNotFound).PushToSentry() + } + return result, nil } func generateKey(c *gin.Context) string { diff --git a/platform/vechain/api_test.go b/platform/vechain/api_test.go index c0f697102..0383c3704 100644 --- a/platform/vechain/api_test.go +++ b/platform/vechain/api_test.go @@ -55,7 +55,6 @@ func TestNormalizeTransaction(t *testing.T) { platform := Platform{} - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var tx LogTransfer diff --git a/syncmarkets/clients/coingecko/cache.go b/syncmarkets/clients/coingecko/cache.go index 94b8ffdc1..2a19f4c6a 100644 --- a/syncmarkets/clients/coingecko/cache.go +++ b/syncmarkets/clients/coingecko/cache.go @@ -105,7 +105,7 @@ func normalizeTokenId(platform, addr string) string { } switch platform { case "ethereum": - if len(addr) == 42 && strings.HasPrefix(addr, "0x"){ + if len(addr) == 42 && strings.HasPrefix(addr, "0x") { return address.EIP55Checksum(addr) } return "" From 845147c9c7a4ff4c9450bed429e4481b21c665ec Mon Sep 17 00:00:00 2001 From: Derek Date: Tue, 11 Feb 2020 16:34:41 -0300 Subject: [PATCH 096/506] Fixes HTTP error codes and errors being swallowed (#826) --- api/maketdata.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/api/maketdata.go b/api/maketdata.go index cc57ecf12..c6962ff7a 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -61,25 +61,27 @@ func getTickerHandler(storage storage.Market) func(c *gin.Context) { coinQuery := c.Query("coin") coinId, err := strconv.Atoi(coinQuery) if err != nil { - ginutils.RenderError(c, http.StatusInternalServerError, "Invalid coin") + ginutils.RenderError(c, http.StatusBadRequest, "Invalid coin") return } token := strings.ToUpper(c.Query("token")) if token == "" { - ginutils.RenderError(c, http.StatusInternalServerError, "Must provide token") + ginutils.RenderError(c, http.StatusBadRequest, "Must provide token") return } currency := c.DefaultQuery("currency", blockatlas.DefaultCurrency) rate, err := storage.GetRate(strings.ToUpper(currency)) if err != nil { - ginutils.RenderError(c, http.StatusInternalServerError, "Invalid currency") + logger.Error(err, "Failed to retrieve currency", logger.Params{"coin": coinId, "currency": currency}) + ginutils.RenderError(c, http.StatusInternalServerError, "Failed to retrieve currency") return } symbol := coin.Coins[uint(coinId)].Symbol result, err := storage.GetTicker(symbol, token) if err != nil { + logger.Error(err, "Failed to retrieve ticker", logger.Params{"coin": coinId, "currency": currency}) ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) return } @@ -109,7 +111,8 @@ func getTickersHandler(storage storage.Market) func(c *gin.Context) { } rate, err := storage.GetRate(strings.ToUpper(md.Currency)) if err != nil { - ginutils.RenderError(c, http.StatusInternalServerError, "Invalid currency") + logger.Error(err, "Failed to retrieve rate", logger.Params{"currency": md.Currency}) + ginutils.RenderError(c, http.StatusInternalServerError, "Failed to retrieve rate") return } @@ -121,6 +124,8 @@ func getTickersHandler(storage storage.Market) func(c *gin.Context) { } r, err := storage.GetTicker(coinObj.Symbol, strings.ToUpper(coinRequest.TokenId)) if err != nil { + // TODO: either fail the request or signal to requester that ticker for coin couldn't be retrieved + logger.Error(err, "Failed to retrieve ticker", logger.Params{"coin": coinObj.Symbol, "currency": md.Currency}) continue } r.ApplyRate(md.Currency, rate.Rate, rate.PercentChange24h) @@ -151,14 +156,14 @@ func getChartsHandler() func(c *gin.Context) { coinQuery := c.Query("coin") coinId, err := strconv.Atoi(coinQuery) if err != nil { - ginutils.RenderError(c, http.StatusInternalServerError, "Invalid coin") + ginutils.RenderError(c, http.StatusBadRequest, "Invalid coin") return } token := c.Query("token") timeStart, err := strconv.ParseInt(c.Query("time_start"), 10, 64) if err != nil { - ginutils.RenderError(c, http.StatusInternalServerError, "Invalid time_start") + ginutils.RenderError(c, http.StatusBadRequest, "Invalid time_start") return } maxItems, err := strconv.Atoi(c.Query("max_items")) @@ -170,6 +175,7 @@ func getChartsHandler() func(c *gin.Context) { chart, err := charts.GetChartData(uint(coinId), token, currency, timeStart, maxItems) if err != nil { + logger.Error(err, "Failed to retrieve chart", logger.Params{"coin": coinId, "currency": currency}) ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) return } @@ -195,7 +201,7 @@ func getCoinInfoHandler() func(c *gin.Context) { coinQuery := c.Query("coin") coinId, err := strconv.Atoi(coinQuery) if err != nil { - ginutils.RenderError(c, http.StatusInternalServerError, "Invalid coin") + ginutils.RenderError(c, http.StatusBadRequest, "Invalid coin") return } @@ -203,12 +209,15 @@ func getCoinInfoHandler() func(c *gin.Context) { currency := c.DefaultQuery("currency", blockatlas.DefaultCurrency) chart, err := charts.GetCoinInfo(uint(coinId), token, currency) if err != nil { + logger.Error(err, "Failed to retrieve coin info", logger.Params{"coin": coinId, "currency": currency}) ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) return } chart.Info, err = assets.GetCoinInfo(coinId, token) if err != nil { logger.Error(err, "invalid coin info", logger.Params{"coin": coinId, "currency": currency}) + ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) + return } ginutils.RenderSuccess(c, chart) } From 53b2a612d425fb31c568092fcfcb8917af967303 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Wed, 12 Feb 2020 08:54:52 +0900 Subject: [PATCH 097/506] [Tezos] Implement fetching validators based on period type (#830) * Increase tezos block for getting validators list * Add fetching validators based on period type * Rename method to getCurrentValidators --- platform/tezos/rpc.go | 16 ++++++++++++++-- platform/tezos/stake.go | 18 +++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/platform/tezos/rpc.go b/platform/tezos/rpc.go index 177f6e319..2f4cb6955 100644 --- a/platform/tezos/rpc.go +++ b/platform/tezos/rpc.go @@ -1,6 +1,7 @@ package tezos import ( + "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -8,8 +9,19 @@ type RpcClient struct { blockatlas.Request } -func (c *RpcClient) GetValidators() (validators []Validator, err error) { - err = c.Get(&validators, "chains/main/blocks/head~32768/votes/listings", nil) +type PeriodType string + +const ( + TestingPeriodType PeriodType = "testing" +) + +func (c *RpcClient) GetValidators(blockID string) (validators []Validator, err error) { + err = c.Get(&validators, fmt.Sprintf("chains/main/blocks/%s/votes/listings", blockID), nil) + return +} + +func (c *RpcClient) GetPeriodType() (periodType PeriodType, err error) { + err = c.Get(&periodType, "chains/main/blocks/head/votes/current_period_kind", nil) return } diff --git a/platform/tezos/stake.go b/platform/tezos/stake.go index ab8f5971d..e4bf4a3aa 100644 --- a/platform/tezos/stake.go +++ b/platform/tezos/stake.go @@ -14,6 +14,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e if len(account.Delegate) == 0 { return make(blockatlas.DelegationsPage, 0), nil } + validators, err := services.GetValidatorsMap(p) if err != nil { return nil, err @@ -38,7 +39,8 @@ func NormalizeDelegation(account Account, validators blockatlas.ValidatorMap) (b func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { results := make(blockatlas.ValidatorPage, 0) - validators, err := p.rpcClient.GetValidators() + + validators, err := p.getCurrentValidators() if err != nil { return results, err } @@ -49,6 +51,20 @@ func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { return results, nil } +func (p *Platform) getCurrentValidators() (validators []Validator, err error) { + periodType, err := p.rpcClient.GetPeriodType() + if err != nil { + return validators, err + } + + switch periodType { + case TestingPeriodType: + return p.rpcClient.GetValidators("head~32768") + default: + return p.rpcClient.GetValidators("head") + } +} + func (p *Platform) GetDetails() blockatlas.StakingDetails { return getDetails() } From dc1f87aa5c3c8d7ffd073f481bbde9ad89c57703 Mon Sep 17 00:00:00 2001 From: Derek Date: Tue, 11 Feb 2020 20:55:04 -0300 Subject: [PATCH 098/506] Improves market error logging (#833) * Improves market error logging * Adds further logging --- storage/market.go | 7 ++++++- syncmarkets/market.go | 4 +++- syncmarkets/worker.go | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/storage/market.go b/storage/market.go index 5f7c6d436..177e938e1 100644 --- a/storage/market.go +++ b/storage/market.go @@ -26,7 +26,12 @@ func (s *Storage) SaveTicker(coin *blockatlas.Ticker, pl ProviderList) error { } if cd.LastUpdate.After(coin.LastUpdate) && op >= np { - return errors.E("ticker is outdated") + return errors.E("ticker is outdated or too low priority", errors.Params{ + "oldTickerTime": cd.LastUpdate, + "newTickerTime": coin.LastUpdate, + "oldTickerPriority": op, + "newTickerPriority": np, + }) } } hm := createHashMap(coin.CoinName, coin.TokenId) diff --git a/syncmarkets/market.go b/syncmarkets/market.go index 57d5d52f5..8343e564e 100644 --- a/syncmarkets/market.go +++ b/syncmarkets/market.go @@ -53,13 +53,15 @@ func runMarket(storage storage.Market, p market.Provider) error { if err != nil { return errors.E(err, "GetData") } + var saveErrs = 0 for _, result := range data { err = storage.SaveTicker(result, marketProviders) if err != nil { + saveErrs++ logger.Error(errors.E(err, "SaveTicker", errors.Params{"result": result})) } } - logger.Info("Market data result", logger.Params{"markets": len(data), "provider": p.GetId()}) + logger.Info("Market data result", logger.Params{"markets": len(data), "provider": p.GetId(), "failed": saveErrs}) return nil } diff --git a/syncmarkets/worker.go b/syncmarkets/worker.go index 4c297c055..23ed50656 100644 --- a/syncmarkets/worker.go +++ b/syncmarkets/worker.go @@ -49,6 +49,11 @@ func scheduleTasks(storage storage.Market, md Provider, c *cron.Cron) { } t := md.GetUpdateTime() spec := fmt.Sprintf("@every %s", t) + logger.Info("Scheduling market data task", logger.Params{ + "Type": md.GetLogType(), + "Market": md.GetId(), + "Interval": spec, + }) _, err = c.AddFunc(spec, func() { go processBackoff(storage, md) }) From a971f996a1313c62881a24180b8784bd96c00ecb Mon Sep 17 00:00:00 2001 From: dpereskokov Date: Wed, 12 Feb 2020 07:55:57 +0800 Subject: [PATCH 099/506] Fix Compound provider prices (#828) * respect stored quote currency and fixes fetching compound price * fix tests --- api/maketdata.go | 20 +++++++++++++++++++- syncmarkets/clients/compound/models.go | 6 +++--- syncmarkets/market/compound/compound.go | 4 ++-- syncmarkets/market/compound/compound_test.go | 17 +++++++++-------- syncmarkets/rate/compound/compound.go | 2 +- syncmarkets/rate/compound/compound_test.go | 16 ++++++++-------- 6 files changed, 42 insertions(+), 23 deletions(-) diff --git a/api/maketdata.go b/api/maketdata.go index c6962ff7a..5e03bfd2a 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -11,6 +11,7 @@ import ( "github.com/trustwallet/blockatlas/services/assets" "github.com/trustwallet/blockatlas/storage" "github.com/trustwallet/blockatlas/syncmarkets" + "math/big" "net/http" "strconv" "strings" @@ -118,6 +119,9 @@ func getTickersHandler(storage storage.Market) func(c *gin.Context) { tickers := make(blockatlas.Tickers, 0) for _, coinRequest := range md.Assets { + exchangeRate := rate.Rate + percentChange := rate.PercentChange24h + coinObj, ok := coin.Coins[coinRequest.Coin] if !ok { continue @@ -128,7 +132,21 @@ func getTickersHandler(storage storage.Market) func(c *gin.Context) { logger.Error(err, "Failed to retrieve ticker", logger.Params{"coin": coinObj.Symbol, "currency": md.Currency}) continue } - r.ApplyRate(md.Currency, rate.Rate, rate.PercentChange24h) + if r.Price.Currency != blockatlas.DefaultCurrency { + newRate, err := storage.GetRate(strings.ToUpper(r.Price.Currency)) + if err == nil { + exchangeRate *= newRate.Rate + percentChange = newRate.PercentChange24h + } else { + tickerRate, err := storage.GetTicker(strings.ToUpper(r.Price.Currency), "") + if err == nil { + exchangeRate *= tickerRate.Price.Value + percentChange = big.NewFloat(tickerRate.Price.Change24h) + } + } + } + + r.ApplyRate(md.Currency, exchangeRate, percentChange) r.SetCoinId(coinRequest.Coin) tickers = append(tickers, r) } diff --git a/syncmarkets/clients/compound/models.go b/syncmarkets/clients/compound/models.go index 44157eddd..5a159c4f6 100644 --- a/syncmarkets/clients/compound/models.go +++ b/syncmarkets/clients/compound/models.go @@ -5,9 +5,9 @@ type CoinPrices struct { } type CToken struct { - ExchangeRate Amount `json:"exchange_rate"` - Symbol string `json:"symbol"` - TokenAddress string `json:"token_address"` + UnderlyingPrice Amount `json:"underlying_price"` + Symbol string `json:"symbol"` + TokenAddress string `json:"token_address"` } type Amount struct { diff --git a/syncmarkets/market/compound/compound.go b/syncmarkets/market/compound/compound.go index b21bf226b..7a1973640 100644 --- a/syncmarkets/market/compound/compound.go +++ b/syncmarkets/market/compound/compound.go @@ -44,8 +44,8 @@ func normalizeTicker(ctoken c.CToken, provider string) (*blockatlas.Ticker, erro CoinType: blockatlas.TypeToken, TokenId: ctoken.TokenAddress, Price: blockatlas.TickerPrice{ - Value: ctoken.ExchangeRate.Value, - Currency: blockatlas.DefaultCurrency, + Value: ctoken.UnderlyingPrice.Value, + Currency: coin.Coins[coin.ETH].Symbol, Provider: provider, }, LastUpdate: time.Now(), diff --git a/syncmarkets/market/compound/compound_test.go b/syncmarkets/market/compound/compound_test.go index 8a799243c..bffdf2902 100644 --- a/syncmarkets/market/compound/compound_test.go +++ b/syncmarkets/market/compound/compound_test.go @@ -2,6 +2,7 @@ package compound import ( "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/syncmarkets/clients/compound" "sort" @@ -23,28 +24,28 @@ func Test_normalizeTickers(t *testing.T) { "test normalize compound quote", args{prices: compound.CoinPrices{Data: []compound.CToken{ { - TokenAddress: "0x39aa39c021dfbae8fac545936693ac917d5e7563", - Symbol: "cUSDC", - ExchangeRate: compound.Amount{Value: 0.0021}, + TokenAddress: "0x39aa39c021dfbae8fac545936693ac917d5e7563", + Symbol: "cUSDC", + UnderlyingPrice: compound.Amount{Value: 0.0021}, }, { - TokenAddress: "0x158079ee67fce2f58472a96584a73c7ab9ac95c1", - Symbol: "cREP", - ExchangeRate: compound.Amount{Value: 0.02}, + TokenAddress: "0x158079ee67fce2f58472a96584a73c7ab9ac95c1", + Symbol: "cREP", + UnderlyingPrice: compound.Amount{Value: 0.02}, }, }}, provider: id}, blockatlas.Tickers{ &blockatlas.Ticker{CoinName: "ETH", TokenId: "0x39aa39c021dfbae8fac545936693ac917d5e7563", CoinType: blockatlas.TypeToken, LastUpdate: time.Unix(222, 0), Price: blockatlas.TickerPrice{ Value: 0.0021, - Currency: blockatlas.DefaultCurrency, + Currency: coin.Coins[coin.ETH].Symbol, Provider: id, }, }, &blockatlas.Ticker{CoinName: "ETH", TokenId: "0x158079ee67fce2f58472a96584a73c7ab9ac95c1", CoinType: blockatlas.TypeToken, LastUpdate: time.Unix(444, 0), Price: blockatlas.TickerPrice{ Value: 0.02, - Currency: blockatlas.DefaultCurrency, + Currency: coin.Coins[coin.ETH].Symbol, Provider: id, }, }, diff --git a/syncmarkets/rate/compound/compound.go b/syncmarkets/rate/compound/compound.go index 44c0159fb..5f80293b3 100644 --- a/syncmarkets/rate/compound/compound.go +++ b/syncmarkets/rate/compound/compound.go @@ -40,7 +40,7 @@ func normalizeRates(coinPrices c.CoinPrices, provider string) (rates blockatlas. for _, cToken := range coinPrices.Data { rates = append(rates, blockatlas.Rate{ Currency: strings.ToUpper(cToken.Symbol), - Rate: 1.0 / cToken.ExchangeRate.Value, + Rate: 1.0 / cToken.UnderlyingPrice.Value, Timestamp: time.Now().Unix(), Provider: provider, }) diff --git a/syncmarkets/rate/compound/compound_test.go b/syncmarkets/rate/compound/compound_test.go index 367804bb1..cdb1460c0 100644 --- a/syncmarkets/rate/compound/compound_test.go +++ b/syncmarkets/rate/compound/compound_test.go @@ -21,12 +21,12 @@ func Test_normalizeRates(t *testing.T) { c.CoinPrices{ Data: []c.CToken{ { - Symbol: "cUSDC", - ExchangeRate: c.Amount{Value: 0.0021}, + Symbol: "cUSDC", + UnderlyingPrice: c.Amount{Value: 0.0021}, }, { - Symbol: "cREP", - ExchangeRate: c.Amount{Value: 0.02}, + Symbol: "cREP", + UnderlyingPrice: c.Amount{Value: 0.02}, }, }, }, @@ -40,12 +40,12 @@ func Test_normalizeRates(t *testing.T) { c.CoinPrices{ Data: []c.CToken{ { - Symbol: "cUSDC", - ExchangeRate: c.Amount{Value: 110.0021}, + Symbol: "cUSDC", + UnderlyingPrice: c.Amount{Value: 110.0021}, }, { - Symbol: "cREP", - ExchangeRate: c.Amount{Value: 110.02}, + Symbol: "cREP", + UnderlyingPrice: c.Amount{Value: 110.02}, }, }, }, From 5137f463260ca3b6ca384b10f137ce02e4e230fc Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 12 Feb 2020 05:03:39 +0300 Subject: [PATCH 100/506] Update azure-pipelines.yml (#839) Dev branch will have tests right now --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4b9e34f46..b19a75729 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -2,6 +2,7 @@ trigger: branches: include: - master + - dev tags: include: - '*' From 3417ef966957b7b86c971d8c8549e8143a6ffc48 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 12 Feb 2020 05:11:43 -0300 Subject: [PATCH 101/506] Add EIP55Checksum for classic market data address (#841) --- syncmarkets/clients/coingecko/cache.go | 4 ++-- syncmarkets/clients/coingecko/cache_test.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/syncmarkets/clients/coingecko/cache.go b/syncmarkets/clients/coingecko/cache.go index 2a19f4c6a..c10a95e21 100644 --- a/syncmarkets/clients/coingecko/cache.go +++ b/syncmarkets/clients/coingecko/cache.go @@ -2,6 +2,7 @@ package coingecko import ( "fmt" + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" @@ -104,12 +105,11 @@ func normalizeTokenId(platform, addr string) string { return "" } switch platform { - case "ethereum": + case coin.Ethereum().Handle, coin.Classic().Handle: if len(addr) == 42 && strings.HasPrefix(addr, "0x") { return address.EIP55Checksum(addr) } return "" - default: return addr } diff --git a/syncmarkets/clients/coingecko/cache_test.go b/syncmarkets/clients/coingecko/cache_test.go index a1346b489..70edf8b57 100644 --- a/syncmarkets/clients/coingecko/cache_test.go +++ b/syncmarkets/clients/coingecko/cache_test.go @@ -312,6 +312,12 @@ func Test_NormalizeTokenIDs(t *testing.T) { address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", expected: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", }, + { + name: "Should checksum Classic lowercase address", + platform: "classic", + address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", + expected: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", + }, { name: "Check if one of the input empty - 1", platform: "ethereum", @@ -320,6 +326,12 @@ func Test_NormalizeTokenIDs(t *testing.T) { }, { name: "Check if one of the input empty - 2", + platform: "classic", + address: "", + expected: "", + }, + { + name: "Check if one of the input empty - 3", platform: "", address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", expected: "", From c3a99fd6e17f1df93de3db81961a4a058fb1c2a0 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 12 Feb 2020 07:52:19 -0300 Subject: [PATCH 102/506] Add coingecko checksum (#843) * Add coingecko checksum * Fix unit tests --- api/maketdata.go | 4 ---- storage/market.go | 6 +++--- syncmarkets/clients/coingecko/cache.go | 8 ++++++-- syncmarkets/clients/coingecko/cache_test.go | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/api/maketdata.go b/api/maketdata.go index 5e03bfd2a..8f3284648 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -66,10 +66,6 @@ func getTickerHandler(storage storage.Market) func(c *gin.Context) { return } token := strings.ToUpper(c.Query("token")) - if token == "" { - ginutils.RenderError(c, http.StatusBadRequest, "Must provide token") - return - } currency := c.DefaultQuery("currency", blockatlas.DefaultCurrency) rate, err := storage.GetRate(strings.ToUpper(currency)) diff --git a/storage/market.go b/storage/market.go index 177e938e1..92ece7cd0 100644 --- a/storage/market.go +++ b/storage/market.go @@ -27,8 +27,8 @@ func (s *Storage) SaveTicker(coin *blockatlas.Ticker, pl ProviderList) error { if cd.LastUpdate.After(coin.LastUpdate) && op >= np { return errors.E("ticker is outdated or too low priority", errors.Params{ - "oldTickerTime": cd.LastUpdate, - "newTickerTime": coin.LastUpdate, + "oldTickerTime": cd.LastUpdate, + "newTickerTime": coin.LastUpdate, "oldTickerPriority": op, "newTickerPriority": np, }) @@ -64,7 +64,7 @@ func (s *Storage) SaveRates(rates blockatlas.Rates, pl ProviderList) { } err = s.AddHM(EntityRates, rate.Currency, &rate) if err != nil { - logger.Error(err, "SaveRates", logger.Params{"rate": rate}) + logger.Error(err, "SaveRates") continue } } diff --git a/syncmarkets/clients/coingecko/cache.go b/syncmarkets/clients/coingecko/cache.go index c10a95e21..d343ce61c 100644 --- a/syncmarkets/clients/coingecko/cache.go +++ b/syncmarkets/clients/coingecko/cache.go @@ -2,7 +2,6 @@ package coingecko import ( "fmt" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" @@ -12,6 +11,11 @@ import ( type Cache map[string][]CoinResult type SymbolsCache map[string]GeckoCoin +const ( + PlatformEthereum = "ethereum" + PlatformClassic = "ethereum-classic" +) + func (c Cache) GetCoinsById(id string) (coins []CoinResult, err error) { coins, ok := c[id] if !ok { @@ -105,7 +109,7 @@ func normalizeTokenId(platform, addr string) string { return "" } switch platform { - case coin.Ethereum().Handle, coin.Classic().Handle: + case PlatformEthereum, PlatformClassic: if len(addr) == 42 && strings.HasPrefix(addr, "0x") { return address.EIP55Checksum(addr) } diff --git a/syncmarkets/clients/coingecko/cache_test.go b/syncmarkets/clients/coingecko/cache_test.go index 70edf8b57..4936a7351 100644 --- a/syncmarkets/clients/coingecko/cache_test.go +++ b/syncmarkets/clients/coingecko/cache_test.go @@ -308,25 +308,25 @@ func Test_NormalizeTokenIDs(t *testing.T) { }{ { name: "Should checksum Ethereum lowercase address", - platform: "ethereum", + platform: PlatformEthereum, address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", expected: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", }, { name: "Should checksum Classic lowercase address", - platform: "classic", + platform: PlatformClassic, address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", expected: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", }, { name: "Check if one of the input empty - 1", - platform: "ethereum", + platform: PlatformEthereum, address: "", expected: "", }, { name: "Check if one of the input empty - 2", - platform: "classic", + platform: PlatformClassic, address: "", expected: "", }, @@ -338,7 +338,7 @@ func Test_NormalizeTokenIDs(t *testing.T) { }, { name: "Should not process if address malformed", - platform: "ethereum", + platform: PlatformEthereum, address: "https://etherscan.io/address/0x8Ddc86DbA7ad728012eFc460b8A168Aba60B403B", expected: "", }, From 3818c4cf5a0e9bc226eb1da3329b3745c136bbe9 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 12 Feb 2020 14:12:02 -0300 Subject: [PATCH 103/506] Postman Tests (#831) * Add Postman Tests * Improve domain tests * Add postman tests for observer * Update domains data * Installing newman by postman * Improve make commands and remove duplicate code * Add postman tests for market data * Add tests for batch routes and fix/update swagger * Specify the host for the Newman make command * Update makefile comment for Newman * Filter market data interation data --- Makefile | 29 + api/batch.go | 2 +- api/maketdata.go | 7 +- docs/docs.go | 121 +- docs/swagger.json | 119 +- docs/swagger.yaml | 79 +- .../Blockatlas.postman_collection.json | 2601 +++++ pkg/tests/postman/collection_data.json | 8 + pkg/tests/postman/domain_data.json | 44 + pkg/tests/postman/healthcheck_data.json | 4 + pkg/tests/postman/market_data.json | 8669 +++++++++++++++++ pkg/tests/postman/observer_data.json | 72 + pkg/tests/postman/staking_data.json | 27 + pkg/tests/postman/token_data.json | 38 + pkg/tests/postman/transaction_data.json | 234 + 15 files changed, 12003 insertions(+), 51 deletions(-) create mode 100644 pkg/tests/postman/Blockatlas.postman_collection.json create mode 100644 pkg/tests/postman/collection_data.json create mode 100644 pkg/tests/postman/domain_data.json create mode 100644 pkg/tests/postman/healthcheck_data.json create mode 100644 pkg/tests/postman/market_data.json create mode 100644 pkg/tests/postman/observer_data.json create mode 100644 pkg/tests/postman/staking_data.json create mode 100644 pkg/tests/postman/token_data.json create mode 100644 pkg/tests/postman/transaction_data.json diff --git a/Makefile b/Makefile index fccfd2708..eb661493d 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +#! /usr/bin/make -f + # Project variables. VERSION := $(shell git describe --tags) BUILD := $(shell git rev-parse --short HEAD) @@ -118,6 +120,33 @@ golint: go-lint ## docs: Generate swagger docs. docs: go-gen-docs +## install-newman: Install Postman Newman for tests. +install-newman: +ifeq (,$(shell which newman)) + @echo " > Installing Postman Newman" + @-npm install -g newman +endif + +## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http//localhost +newman: install-newman + @echo " > Runing $(test) tests" +ifeq (,$(host)) + @echo " > Host parameter is missing. e.g: make newman test=staking host=http://localhost:8420" + @exit 1 +endif +ifeq (,$(test)) + @bash -c "$(MAKE) newman test=transaction host=$(host)" + @bash -c "$(MAKE) newman test=token host=$(host)" + @bash -c "$(MAKE) newman test=staking host=$(host)" + @bash -c "$(MAKE) newman test=collection host=$(host)" + @bash -c "$(MAKE) newman test=domain host=$(host)" + @bash -c "$(MAKE) newman test=healthcheck host=$(host)" + @bash -c "$(MAKE) newman test=observer host=$(host)" + @bash -c "$(MAKE) newman test=market host=$(host)" +else + @newman run pkg/tests/postman/Blockatlas.postman_collection.json --folder $(test) -d pkg/tests/postman/$(test)_data.json --env-var "host=$(host)" +endif + go-compile: go-get go-build go-build: diff --git a/api/batch.go b/api/batch.go index eb28ea02c..bbfc76e74 100644 --- a/api/batch.go +++ b/api/batch.go @@ -71,7 +71,7 @@ func makeStakingDelegationsBatchRoute(router gin.IRouter) { // @Accept json // @Produce json // @Tags platform,staking -// @Param delegations body api.AddressesRequest true "Validators addresses and coins" +// @Param delegations body api.CoinsRequest true "Validators addresses and coins" // @Success 200 {object} blockatlas.DelegationsBatchPage // @Router /v2/staking/list [post] func makeStakingDelegationsSimpleBatchRoute(router gin.IRouter) { diff --git a/api/maketdata.go b/api/maketdata.go index 8f3284648..aeb026e5b 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -227,12 +227,7 @@ func getCoinInfoHandler() func(c *gin.Context) { ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) return } - chart.Info, err = assets.GetCoinInfo(coinId, token) - if err != nil { - logger.Error(err, "invalid coin info", logger.Params{"coin": coinId, "currency": currency}) - ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) - return - } + chart.Info, _ = assets.GetCoinInfo(coinId, token) ginutils.RenderSuccess(c, chart) } } diff --git a/docs/docs.go b/docs/docs.go index 0367c6cb8..c36afb8da 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-01-29 02:11:45.800246 +0300 MSK m=+0.142708046 +// 2020-02-12 08:02:39.698276 -0300 -03 m=+0.093560371 package docs @@ -617,7 +617,7 @@ var doc = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/api.AddressesRequest" + "$ref": "#/definitions/api.CoinsRequest" } } ], @@ -1100,6 +1100,20 @@ var doc = `{ } } }, + "api.CoinBatchRequest": { + "type": "object", + "properties": { + "coin": { + "type": "integer" + } + } + }, + "api.CoinsRequest": { + "type": "array", + "items": { + "$ref": "#/definitions/api.CoinBatchRequest" + } + }, "api.TickerRequest": { "type": "object", "properties": { @@ -1120,6 +1134,10 @@ var doc = `{ "circulating_supply": { "type": "number" }, + "info": { + "type": "object", + "$ref": "#/definitions/blockatlas.CoinInfo" + }, "market_cap": { "type": "number" }, @@ -1156,6 +1174,44 @@ var doc = `{ } } }, + "blockatlas.CoinInfo": { + "type": "object", + "properties": { + "data_source": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Detail" + } + }, + "explorers": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Link" + } + }, + "name": { + "type": "string" + }, + "socials": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.SocialLink" + } + }, + "source_code": { + "type": "string" + }, + "website": { + "type": "string" + }, + "whitepaper": { + "type": "string" + } + } + }, "blockatlas.CoinStatus": { "type": "object", "properties": { @@ -1270,6 +1326,17 @@ var doc = `{ "$ref": "#/definitions/blockatlas.Delegation" } }, + "blockatlas.Detail": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "language": { + "type": "string" + } + } + }, "blockatlas.DocsResponse": { "type": "object", "properties": { @@ -1278,6 +1345,17 @@ var doc = `{ } } }, + "blockatlas.Link": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, "blockatlas.Observer": { "type": "object", "properties": { @@ -1300,6 +1378,20 @@ var doc = `{ } } }, + "blockatlas.SocialLink": { + "type": "object", + "properties": { + "handle": { + "type": "string" + }, + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, "blockatlas.StakeValidator": { "type": "object", "properties": { @@ -1362,6 +1454,15 @@ var doc = `{ } } }, + "blockatlas.Subscriptions": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "blockatlas.Ticker": { "type": "object", "properties": { @@ -1508,24 +1609,10 @@ var doc = `{ "properties": { "subscriptions": { "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - } + "$ref": "#/definitions/blockatlas.Subscriptions" }, "webhook": { "type": "string" - }, - "xpub_subscriptions": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - } } } }, diff --git a/docs/swagger.json b/docs/swagger.json index c4fda60fb..24e1d6a9f 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -596,7 +596,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/api.AddressesRequest" + "$ref": "#/definitions/api.CoinsRequest" } } ], @@ -1079,6 +1079,20 @@ } } }, + "api.CoinBatchRequest": { + "type": "object", + "properties": { + "coin": { + "type": "integer" + } + } + }, + "api.CoinsRequest": { + "type": "array", + "items": { + "$ref": "#/definitions/api.CoinBatchRequest" + } + }, "api.TickerRequest": { "type": "object", "properties": { @@ -1099,6 +1113,10 @@ "circulating_supply": { "type": "number" }, + "info": { + "type": "object", + "$ref": "#/definitions/blockatlas.CoinInfo" + }, "market_cap": { "type": "number" }, @@ -1135,6 +1153,44 @@ } } }, + "blockatlas.CoinInfo": { + "type": "object", + "properties": { + "data_source": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Detail" + } + }, + "explorers": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Link" + } + }, + "name": { + "type": "string" + }, + "socials": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.SocialLink" + } + }, + "source_code": { + "type": "string" + }, + "website": { + "type": "string" + }, + "whitepaper": { + "type": "string" + } + } + }, "blockatlas.CoinStatus": { "type": "object", "properties": { @@ -1249,6 +1305,17 @@ "$ref": "#/definitions/blockatlas.Delegation" } }, + "blockatlas.Detail": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "language": { + "type": "string" + } + } + }, "blockatlas.DocsResponse": { "type": "object", "properties": { @@ -1257,6 +1324,17 @@ } } }, + "blockatlas.Link": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, "blockatlas.Observer": { "type": "object", "properties": { @@ -1279,6 +1357,20 @@ } } }, + "blockatlas.SocialLink": { + "type": "object", + "properties": { + "handle": { + "type": "string" + }, + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, "blockatlas.StakeValidator": { "type": "object", "properties": { @@ -1341,6 +1433,15 @@ } } }, + "blockatlas.Subscriptions": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "blockatlas.Ticker": { "type": "object", "properties": { @@ -1487,24 +1588,10 @@ "properties": { "subscriptions": { "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - } + "$ref": "#/definitions/blockatlas.Subscriptions" }, "webhook": { "type": "string" - }, - "xpub_subscriptions": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - } } } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index cd7c129ef..93586ae35 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -19,6 +19,15 @@ definitions: type: type: string type: object + api.CoinBatchRequest: + properties: + coin: + type: integer + type: object + api.CoinsRequest: + items: + $ref: '#/definitions/api.CoinBatchRequest' + type: array api.TickerRequest: properties: assets: @@ -32,6 +41,9 @@ definitions: properties: circulating_supply: type: number + info: + $ref: '#/definitions/blockatlas.CoinInfo' + type: object market_cap: type: number total_supply: @@ -55,6 +67,31 @@ definitions: price: type: number type: object + blockatlas.CoinInfo: + properties: + data_source: + type: string + details: + items: + $ref: '#/definitions/blockatlas.Detail' + type: array + explorers: + items: + $ref: '#/definitions/blockatlas.Link' + type: array + name: + type: string + socials: + items: + $ref: '#/definitions/blockatlas.SocialLink' + type: array + source_code: + type: string + website: + type: string + whitepaper: + type: string + type: object blockatlas.CoinStatus: properties: error: @@ -131,11 +168,25 @@ definitions: items: $ref: '#/definitions/blockatlas.Delegation' type: array + blockatlas.Detail: + properties: + description: + type: string + language: + type: string + type: object blockatlas.DocsResponse: properties: docs: type: object type: object + blockatlas.Link: + properties: + name: + type: string + url: + type: string + type: object blockatlas.Observer: properties: message: @@ -150,6 +201,15 @@ definitions: result: type: string type: object + blockatlas.SocialLink: + properties: + handle: + type: string + name: + type: string + url: + type: string + type: object blockatlas.StakeValidator: properties: details: @@ -191,6 +251,12 @@ definitions: annual: type: number type: object + blockatlas.Subscriptions: + additionalProperties: + items: + type: string + type: array + type: object blockatlas.Ticker: properties: coin: @@ -294,19 +360,10 @@ definitions: blockatlas.Webhook: properties: subscriptions: - additionalProperties: - items: - type: string - type: array + $ref: '#/definitions/blockatlas.Subscriptions' type: object webhook: type: string - xpub_subscriptions: - additionalProperties: - items: - type: string - type: array - type: object type: object coin.ExternalCoin: properties: @@ -933,7 +990,7 @@ paths: name: delegations required: true schema: - $ref: '#/definitions/api.AddressesRequest' + $ref: '#/definitions/api.CoinsRequest' produces: - application/json responses: diff --git a/pkg/tests/postman/Blockatlas.postman_collection.json b/pkg/tests/postman/Blockatlas.postman_collection.json new file mode 100644 index 000000000..7fe265fb7 --- /dev/null +++ b/pkg/tests/postman/Blockatlas.postman_collection.json @@ -0,0 +1,2601 @@ +{ + "info": { + "_postman_id": "b31e9564-879c-4fb0-ad27-986070bc06a0", + "name": "Blockatlas", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "platform", + "item": [ + { + "name": "transaction", + "item": [ + { + "name": "txs", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"docs\": {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"from\": {", + " \"type\": \"string\"", + " },", + " \"to\": {", + " \"type\": \"string\"", + " },", + " \"fee\": {", + " \"type\": \"string\"", + " },", + " \"date\": {", + " \"type\": \"integer\"", + " },", + " \"block\": {", + " \"type\": \"integer\"", + " },", + " \"status\": {", + " \"type\": \"string\"", + " },", + " \"sequence\": {", + " \"type\": \"integer\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"memo\": {", + " \"type\": \"string\"", + " },", + " \"metadata\": {", + " \"type\": \"object\"", + " }", + " }", + " }", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - verify has docs: \" + address, function() {", + " pm.expect(jsonData.total).to.be.above(0);", + "});", + "", + "pm.test(handler + \" - schema is valid: \" + address, function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/v1/{{handler}}/{{address}}", + "host": [ + "{{host}}" + ], + "path": [ + "v1", + "{{handler}}", + "{{address}}" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "3f05cf7e-0439-4cd2-b41f-5ba71e465621", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "de5760bf-5d29-462f-af90-ccbeaa8253f9", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "tokens", + "item": [ + { + "name": "token", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"docs\": {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"symbol\": {", + " \"type\": \"string\"", + " },", + " \"decimals\": {", + " \"type\": \"integer\"", + " },", + " \"token_id\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " }", + " }", + " }", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid: \" + address, function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{host}}/v2/{{handler}}/tokens/{{address}}?Authorization=Bearer {{platform_auth}}", + "host": [ + "{{host}}" + ], + "path": [ + "v2", + "{{handler}}", + "tokens", + "{{address}}" + ], + "query": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}" + } + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "3f05cf7e-0439-4cd2-b41f-5ba71e465621", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "de5760bf-5d29-462f-af90-ccbeaa8253f9", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "staking", + "item": [ + { + "name": "validators", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"docs\": {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " },", + " \"info\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"description\": {", + " \"type\": \"string\"", + " },", + " \"image\": {", + " \"type\": \"string\"", + " },", + " \"website\": {", + " \"type\": \"string\"", + " }", + " }", + " },", + " \"details\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"locktime\": {", + " \"type\": \"integer\"", + " },", + " \"minimum_amount\": {", + " \"type\": \"string\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"reward\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"annual\": {", + " \"type\": \"number\"", + " }", + " }", + " }", + " }", + " }", + " }", + " }", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/v2/{{handler}}/staking/validators", + "host": [ + "{{host}}" + ], + "path": [ + "v2", + "{{handler}}", + "staking", + "validators" + ] + } + }, + "response": [] + }, + { + "name": "validators list", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"docs\": {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " },", + " \"info\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"description\": {", + " \"type\": \"string\"", + " },", + " \"image\": {", + " \"type\": \"string\"", + " },", + " \"website\": {", + " \"type\": \"string\"", + " }", + " }", + " },", + " \"details\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"locktime\": {", + " \"type\": \"integer\"", + " },", + " \"minimum_amount\": {", + " \"type\": \"string\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"reward\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"annual\": {", + " \"type\": \"number\"", + " }", + " }", + " }", + " }", + " }", + " }", + " }", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{platform_auth}}" + }, + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n\t{\n\t\t\"coin\": {{coin}}\n\t}\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/v2/staking/list", + "host": [ + "{{host}}" + ], + "path": [ + "v2", + "staking", + "list" + ] + } + }, + "response": [] + }, + { + "name": "delegations", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"delegations\": {", + " \"type\": \"array\",", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"delegator\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " },", + " \"info\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"description\": {", + " \"type\": \"string\"", + " },", + " \"image\": {", + " \"type\": \"string\"", + " },", + " \"website\": {", + " \"type\": \"string\"", + " }", + " }", + " },", + " \"details\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"locktime\": {", + " \"type\": \"integer\"", + " },", + " \"minimum_amount\": {", + " \"type\": \"string\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"reward\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"annual\": {", + " \"type\": \"number\"", + " }", + " }", + " }", + " }", + " }", + " }", + " },", + " \"value\": {", + " \"type\": \"string\"", + " },", + " \"status\": {", + " \"type\": \"string\"", + " }", + " }", + " }", + " },", + " \"balance\": {", + " \"type\": \"string\"", + " },", + " \"address\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"symbol\": {", + " \"type\": \"string\"", + " },", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"decimals\": {", + " \"type\": \"integer\"", + " }", + " }", + " },", + " \"details\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"locktime\": {", + " \"type\": \"integer\"", + " },", + " \"minimum_amount\": {", + " \"type\": \"string\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"reward\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"annual\": {", + " \"type\": \"number\"", + " }", + " }", + " }", + " }", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid: \" + address, function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{host}}/v2/{{handler}}/staking/delegations/{{address}}?Authorization=Bearer {{platform_auth}}", + "host": [ + "{{host}}" + ], + "path": [ + "v2", + "{{handler}}", + "staking", + "delegations", + "{{address}}" + ], + "query": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}" + } + ] + } + }, + "response": [] + }, + { + "name": "delegations batch", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"delegations\": {", + " \"type\": \"array\",", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"delegator\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " },", + " \"info\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"description\": {", + " \"type\": \"string\"", + " },", + " \"image\": {", + " \"type\": \"string\"", + " },", + " \"website\": {", + " \"type\": \"string\"", + " }", + " }", + " },", + " \"details\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"locktime\": {", + " \"type\": \"integer\"", + " },", + " \"minimum_amount\": {", + " \"type\": \"string\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"reward\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"annual\": {", + " \"type\": \"number\"", + " }", + " }", + " }", + " }", + " }", + " }", + " },", + " \"value\": {", + " \"type\": \"string\"", + " },", + " \"status\": {", + " \"type\": \"string\"", + " }", + " }", + " }", + " },", + " \"balance\": {", + " \"type\": \"string\"", + " },", + " \"address\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"symbol\": {", + " \"type\": \"string\"", + " },", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"decimals\": {", + " \"type\": \"integer\"", + " }", + " }", + " },", + " \"details\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"locktime\": {", + " \"type\": \"integer\"", + " },", + " \"minimum_amount\": {", + " \"type\": \"string\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"reward\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"annual\": {", + " \"type\": \"number\"", + " }", + " }", + " }", + " }", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid: \" + address, function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "[\n\t{\n\t\t\"coin\": {{coin}},\n\t\t\"address\": \"{{address}}\"\n\t}\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/v2/staking/delegations", + "host": [ + "{{host}}" + ], + "path": [ + "v2", + "staking", + "delegations" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "3f05cf7e-0439-4cd2-b41f-5ba71e465621", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "de5760bf-5d29-462f-af90-ccbeaa8253f9", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "collection", + "item": [ + { + "name": "collection", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"docs\": {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"collection_id\": {", + " \"type\": \"string\"", + " },", + " \"token_id\": {", + " \"type\": \"string\"", + " },", + " \"category_contract\": {", + " \"type\": \"string\"", + " },", + " \"contract_address\": {", + " \"type\": \"string\"", + " },", + " \"category\": {", + " \"type\": \"string\"", + " },", + " \"image_url\": {", + " \"type\": \"string\"", + " },", + " \"external_link\": {", + " \"type\": \"string\"", + " },", + " \"provider_link\": {", + " \"type\": \"string\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"description\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"name\": {", + " \"type\": \"string\"", + " }", + " }", + " }", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid: \" + address, function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + " console.log(JSON.stringify(jsonData))", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/v2/{{handler}}/collections/{{address}}/collection/{{collection}}", + "host": [ + "{{host}}" + ], + "path": [ + "v2", + "{{handler}}", + "collections", + "{{address}}", + "collection", + "{{collection}}" + ] + } + }, + "response": [] + }, + { + "name": "collections", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"docs\": {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"symbol\": {", + " \"type\": \"string\"", + " },", + " \"slug\": {", + " \"type\": \"string\"", + " },", + " \"image_url\": {", + " \"type\": \"string\"", + " },", + " \"external_link\": {", + " \"type\": \"string\"", + " },", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"category_address\": {", + " \"type\": \"string\"", + " },", + " \"address\": {", + " \"type\": \"string\"", + " },", + " \"nft_version\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " }", + " }", + " }", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid: \" + address, function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + " console.log(JSON.stringify(jsonData))", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/v2/{{handler}}/collections/{{address}}", + "host": [ + "{{host}}" + ], + "path": [ + "v2", + "{{handler}}", + "collections", + "{{address}}" + ] + } + }, + "response": [] + }, + { + "name": "collections batch", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"docs\": {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"symbol\": {", + " \"type\": \"string\"", + " },", + " \"slug\": {", + " \"type\": \"string\"", + " },", + " \"image_url\": {", + " \"type\": \"string\"", + " },", + " \"external_link\": {", + " \"type\": \"string\"", + " },", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"category_address\": {", + " \"type\": \"string\"", + " },", + " \"address\": {", + " \"type\": \"string\"", + " },", + " \"nft_version\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " }", + " }", + " }", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid: \" + address, function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + " console.log(JSON.stringify(jsonData))", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}", + "type": "text" + }, + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"{{coin}}\": [\"{{address}}\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/v2/collectibles/categories", + "host": [ + "{{host}}" + ], + "path": [ + "v2", + "collectibles", + "categories" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "domain", + "item": [ + { + "name": "v2/ns/lookup", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"result\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"integer\"", + " }", + " }", + " }", + "};", + "", + "let domain = pm.variables.get(\"domain\");", + "let coins = pm.variables.get(\"coins\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "var result = jsonData[0];", + "", + "pm.test(domain + \" - response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(domain + \" - schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "", + "pm.test(domain + \" - address is valid: \" + address, function() {", + " pm.expect(result.result).to.eql(address);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/v2/ns/lookup?name={{domain}}&coins={{coins}}", + "host": [ + "{{host}}" + ], + "path": [ + "v2", + "ns", + "lookup" + ], + "query": [ + { + "key": "name", + "value": "{{domain}}" + }, + { + "key": "coins", + "value": "{{coins}}" + } + ] + } + }, + "response": [] + }, + { + "name": "ns/lookup", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"result\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"integer\"", + " }", + " }", + "};", + "", + "let domain = pm.variables.get(\"domain\");", + "let coins = pm.variables.get(\"coins\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(domain + \" - response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(domain + \" - schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "", + "pm.test(domain + \" - address is valid: \" + address, function() {", + " pm.expect(jsonData.result).to.eql(address);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/ns/lookup?name={{domain}}&coin={{coins}}", + "host": [ + "{{host}}" + ], + "path": [ + "ns", + "lookup" + ], + "query": [ + { + "key": "name", + "value": "{{domain}}" + }, + { + "key": "coin", + "value": "{{coins}}" + } + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "1f5cb578-ecc3-4130-8d9b-68df6e576e63", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "7e7d99e8-d11d-4660-ad03-cff2454e9d1f", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "40c7dd18-87ff-47d8-8607-40b79ddb5dc9", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "6f376ec0-1aa2-42ad-9334-e6a4e7f5fdc7", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "market", + "item": [ + { + "name": "ticker", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "var token_id = pm.environment.get(\"token_id\");", + "if(!token_id) {", + " pm.environment.set(\"token_id\", \"\");", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"coin_name\": {", + " \"type\": \"string\"", + " },", + " \"token_id\": {", + " \"type\": \"string\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"price\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"value\": {", + " \"type\": \"number\"", + " },", + " \"change_24h\": {", + " \"type\": \"number\"", + " },", + " \"currency\": {", + " \"type\": \"string\"", + " },", + " \"provider\": {", + " \"type\": \"string\"", + " }", + " }", + " },", + " \"last_update\": {", + " \"type\": \"string\"", + " }", + " }", + "};", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(\"schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{market_auth}}" + } + ], + "url": { + "raw": "{{host}}/v1/market/ticker?currency={{currency}}&coin={{coin}}&token={{token_id}}", + "host": [ + "{{host}}" + ], + "path": [ + "v1", + "market", + "ticker" + ], + "query": [ + { + "key": "currency", + "value": "{{currency}}" + }, + { + "key": "coin", + "value": "{{coin}}" + }, + { + "key": "token", + "value": "{{token_id}}" + } + ] + } + }, + "response": [] + }, + { + "name": "charts", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "var token_id = pm.environment.get(\"token_id\");", + "if(!token_id) {", + " pm.environment.set(\"token_id\", \"\");", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"prices\": {", + " \"type\": \"array\",", + " \"minItems\": 10,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"price\": {", + " \"type\": \"number\"", + " },", + " \"date\": {", + " \"type\": \"integer\"", + " }", + " }", + " }", + " }", + " }", + "};", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(\"schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{market_auth}}" + } + ], + "url": { + "raw": "{{host}}/v1/market/charts?currency={{currency}}&coin={{coin}}&token={{token_id}}&time_start=1577871126", + "host": [ + "{{host}}" + ], + "path": [ + "v1", + "market", + "charts" + ], + "query": [ + { + "key": "currency", + "value": "{{currency}}" + }, + { + "key": "coin", + "value": "{{coin}}" + }, + { + "key": "token", + "value": "{{token_id}}" + }, + { + "key": "time_start", + "value": "1577871126" + } + ] + } + }, + "response": [] + }, + { + "name": "info", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "var token_id = pm.environment.get(\"token_id\");", + "if(!token_id) {", + " pm.environment.set(\"token_id\", \"\");", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"volume_24\": {", + " \"type\": \"number\"", + " },", + " \"market_cap\": {", + " \"type\": \"number\"", + " },", + " \"circulating_supply\": {", + " \"type\": \"number\"", + " },", + " \"total_supply\": {", + " \"type\": \"number\"", + " },", + " \"info\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"website\": {", + " \"type\": \"string\"", + " },", + " \"source_code\": {", + " \"type\": \"string\"", + " },", + " \"whitepaper\": {", + " \"type\": \"string\"", + " },", + " \"explorers\": {", + " \"type\": \"array\"", + " },", + " \"socials\": {", + " \"type\": \"array\"", + " },", + " \"details\": {", + " \"type\": \"array\"", + " },", + " \"data_source\": {", + " \"type\": \"string\"", + " }", + " }", + " }", + " }", + "};", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"response must be valid and have a body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(\"schema is valid\", function() {", + " if (pm.response.status == 200) {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + " }", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{market_auth}}" + } + ], + "url": { + "raw": "{{host}}/v1/market/info?currency={{currency}}&coin={{coin}}&token={{token_id}}", + "host": [ + "{{host}}" + ], + "path": [ + "v1", + "market", + "info" + ], + "query": [ + { + "key": "currency", + "value": "{{currency}}" + }, + { + "key": "coin", + "value": "{{coin}}" + }, + { + "key": "token", + "value": "{{token_id}}" + } + ] + } + }, + "response": [] + }, + { + "name": "tickers", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "var token_id = pm.environment.get(\"token_id\");", + "if(!token_id) {", + " pm.environment.set(\"token_id\", \"\");", + "}", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"currency\": {", + " \"type\": \"string\"", + " },", + " \"docs\": {", + " \"type\": \"array\",", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"last_update\": {", + " \"type\": \"string\"", + " },", + " \"token_id\": {", + " \"type\": \"string\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"price\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"value\": {", + " \"type\": \"number\"", + " },", + " \"change_24h\": {", + " \"type\": \"number\"", + " }", + " }", + " }", + " }", + " }", + " }", + " }", + "};", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(\"schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{market_auth}}" + }, + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"currency\": \"{{currency}}\",\n \"assets\": [\n {\n \"coin\": {{coin}},\n \"type\": \"{{type}}\",\n \"token_id\": \"{{token_id}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/v1/market/ticker", + "host": [ + "{{host}}" + ], + "path": [ + "v1", + "market", + "ticker" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7cffac98-4367-49be-a96c-dcb31861001c", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "4d6e8061-832a-4330-b47a-3e61cd9c93b8", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "observer", + "item": [ + { + "name": "add", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "", + "var body = {\"subscriptions\": {}, \"webhook\": \"\"}", + "", + "let subscriptions = pm.variables.get(\"subscriptions\");", + "let webhook = pm.variables.get(\"webhook\");", + "", + "body[\"subscriptions\"] = subscriptions", + "body[\"webhook\"] = webhook", + "", + "pm.environment.set(\"request_body\", JSON.stringify(body));", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "let result = {", + " \"status\": true,", + " \"message\": \"Added\"", + "};", + "var jsonData = pm.response.json();", + "", + "pm.test(\"response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(\"response is valid\", function() {", + " pm.expect(jsonData).to.eql(result);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{observer_auth}}" + }, + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{{request_body}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/observer/v1/webhook/register", + "host": [ + "{{host}}" + ], + "path": [ + "observer", + "v1", + "webhook", + "register" + ] + } + }, + "response": [] + }, + { + "name": "delete", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "", + "var body = {\"subscriptions\": {}, \"webhook\": \"\"}", + "", + "let subscriptions = pm.variables.get(\"subscriptions\");", + "let webhook = pm.variables.get(\"webhook\");", + "", + "body[\"subscriptions\"] = subscriptions", + "body[\"webhook\"] = webhook", + "", + "pm.environment.set(\"request_body\", JSON.stringify(body));", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "let result = {", + " \"status\": true,", + " \"message\": \"Deleted\"", + "};", + "var jsonData = pm.response.json();", + "", + "pm.test(\"response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(\"response is valid\", function() {", + " pm.expect(jsonData).to.eql(result);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{observer_auth}}" + }, + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{{request_body}}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/observer/v1/webhook/register", + "host": [ + "{{host}}" + ], + "path": [ + "observer", + "v1", + "webhook", + "register" + ] + } + }, + "response": [] + }, + { + "name": "status", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"minProperties\": 5,", + " \"uniqueItems\": true,", + " \"items\": {\"type\": \"object\"}", + "};", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(\"schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{observer_auth}}" + }, + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/observer/v1/status", + "host": [ + "{{host}}" + ], + "path": [ + "observer", + "v1", + "status" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "50b8bc65-9acc-4652-8ac7-722f45767478", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "88a2b78a-643e-449b-9ec0-f7c7a62ad50a", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "healthcheck", + "item": [ + { + "name": "status", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"status\": {", + " \"type\": \"boolean\"", + " }", + " }", + "};", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(\"verify the status\", function() {", + " pm.expect(jsonData.status).to.equal(true);", + "});", + "", + "pm.test(\"schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{host}}/status", + "host": [ + "{{host}}" + ], + "path": [ + "status" + ] + } + }, + "response": [] + }, + { + "name": "v1", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"endpoints\": {", + " \"type\": \"array\"", + " }", + " }", + "};", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"response must be valid and have a body\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(\"schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{host}}/v1", + "host": [ + "{{host}}" + ], + "path": [ + "v1" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "2f430d33-58dd-4df5-b3bb-2826e76b89b2", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "727ab826-5939-45a7-96be-d8382192a69e", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "protocolProfileBehavior": {} + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "32821b71-3559-4ecb-97e5-84f87fc50731", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "1311995e-ffa0-4801-9c9d-21a7b4c83711", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "id": "4b90aa4f-57c6-4668-9b31-b08213789c1f", + "key": "host", + "value": "http://localhost:8420", + "type": "string" + }, + { + "id": "2f57fde6-5c78-4d34-92a6-ff78c7cb5562", + "key": "observer_auth", + "value": "test", + "type": "string" + }, + { + "id": "2aefe467-def3-4034-be71-bb737861881e", + "key": "market_auth", + "value": "", + "type": "string" + }, + { + "id": "53a56c0a-2672-4f9c-aab4-b0992cf5a2c8", + "key": "platform_auth", + "value": "", + "type": "string" + } + ], + "protocolProfileBehavior": {} +} \ No newline at end of file diff --git a/pkg/tests/postman/collection_data.json b/pkg/tests/postman/collection_data.json new file mode 100644 index 000000000..0213e2d11 --- /dev/null +++ b/pkg/tests/postman/collection_data.json @@ -0,0 +1,8 @@ +[ + { + "coin": 60, + "handler": "ethereum", + "address": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "collection": "0x35b7838dd7507ada69610397a85310ae0abd5034" + } +] diff --git a/pkg/tests/postman/domain_data.json b/pkg/tests/postman/domain_data.json new file mode 100644 index 000000000..52db7664b --- /dev/null +++ b/pkg/tests/postman/domain_data.json @@ -0,0 +1,44 @@ +[ + { + "domain": "vitalik.eth", + "coins": [ + 60 + ], + "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + { + "domain": "vitalik.luxe", + "coins": [ + 60 + ], + "address": "0xD8A667312D5260F12a306Ae7730C754d938da86c" + }, + { + "domain": "ourxyzwallet.xyz", + "coins": [ + 60 + ], + "address": "0x0C54eEAd78d555bE3cbCD451424F9A27a7843935" + }, + { + "domain": "dpantani.zil", + "coins": [ + 313 + ], + "address": "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64" + }, + { + "domain": "dpantani.crypto", + "coins": [ + 313 + ], + "address": "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64" + }, + { + "domain": "adam@fiotestnet", + "coins": [ + 60 + ], + "address": "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51" + } +] \ No newline at end of file diff --git a/pkg/tests/postman/healthcheck_data.json b/pkg/tests/postman/healthcheck_data.json new file mode 100644 index 000000000..da1a058a9 --- /dev/null +++ b/pkg/tests/postman/healthcheck_data.json @@ -0,0 +1,4 @@ +[ + { + } +] diff --git a/pkg/tests/postman/market_data.json b/pkg/tests/postman/market_data.json new file mode 100644 index 000000000..c5761a1a1 --- /dev/null +++ b/pkg/tests/postman/market_data.json @@ -0,0 +1,8669 @@ +[ + { + "coin": 60, + "type": "coin", + "currency": "USD" + }, + { + "coin": 313, + "type": "coin", + "currency": "USD" + }, + { + "coin": 3, + "type": "coin", + "currency": "USD" + }, + { + "coin": 5, + "type": "coin", + "currency": "USD" + }, + { + "coin": 19167, + "type": "coin", + "currency": "USD" + }, + { + "coin": 457, + "type": "coin", + "currency": "USD" + }, + { + "coin": 1729, + "type": "coin", + "currency": "USD" + }, + { + "coin": 0, + "type": "coin", + "currency": "USD" + }, + { + "coin": 2, + "type": "coin", + "currency": "USD" + }, + { + "coin": 145, + "type": "coin", + "currency": "USD" + }, + { + "coin": 74, + "type": "coin", + "currency": "USD" + }, + { + "coin": 242, + "type": "coin", + "currency": "USD" + }, + { + "coin": 459, + "type": "coin", + "currency": "USD" + }, + { + "coin": 820, + "type": "coin", + "currency": "USD" + }, + { + "coin": 61, + "type": "coin", + "currency": "USD" + }, + { + "coin": 195, + "type": "coin", + "currency": "USD" + }, + { + "coin": 5718350, + "type": "coin", + "currency": "USD" + }, + { + "coin": 42, + "type": "coin", + "currency": "USD" + }, + { + "coin": 304, + "type": "coin", + "currency": "USD" + }, + { + "coin": 2718, + "type": "coin", + "currency": "USD" + }, + { + "coin": 5741564, + "type": "coin", + "currency": "USD" + }, + { + "coin": 133, + "type": "coin", + "currency": "USD" + }, + { + "coin": 283, + "type": "coin", + "currency": "USD" + }, + { + "coin": 20, + "type": "coin", + "currency": "USD" + }, + { + "coin": 118, + "type": "coin", + "currency": "USD" + }, + { + "coin": 144, + "type": "coin", + "currency": "USD" + }, + { + "coin": 148, + "type": "coin", + "currency": "USD" + }, + { + "coin": 178, + "type": "coin", + "currency": "USD" + }, + { + "coin": 425, + "type": "coin", + "currency": "USD" + }, + { + "coin": 6060, + "type": "coin", + "currency": "USD" + }, + { + "coin": 14, + "type": "coin", + "currency": "USD" + }, + { + "coin": 175, + "type": "coin", + "currency": "USD" + }, + { + "coin": 1023, + "type": "coin", + "currency": "USD" + }, + { + "coin": 500, + "type": "coin", + "currency": "USD" + }, + { + "coin": 714, + "type": "coin", + "currency": "USD" + }, + { + "coin": 818, + "type": "coin", + "currency": "USD" + }, + { + "coin": 889, + "type": "coin", + "currency": "USD" + }, + { + "coin": 1001, + "type": "coin", + "currency": "USD" + }, + { + "coin": 2301, + "type": "coin", + "currency": "USD" + }, + { + "coin": 165, + "type": "coin", + "currency": "USD" + }, + { + "coin": 434, + "type": "coin", + "currency": "USD" + }, + { + "coin": 1024, + "type": "coin", + "currency": "USD" + }, + { + "coin": 2017, + "type": "coin", + "currency": "USD" + }, + { + "coin": 17, + "type": "coin", + "currency": "USD" + }, + { + "coin": 136, + "type": "coin", + "currency": "USD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2e98A6804E4b6c832ED0ca876a943abD3400b224" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdAC17F958D2ee523a2206206994597C13D831ec7" + }, + { + "coin": 195, + "type": "token", + "currency": "USD", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4DF812F6064def1e5e029f1ca858777CC98D2D81" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf97b5d65Da6b0468b90D531ddae2a69843e6797d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1985365e9f78359a9B6AD760e32412f4a445E862" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAef38fBFBF932D1AeF3B808Bc8fBd8Cd8E1f8BC5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE0B7927c4aF23765Cb51314A0E0521A9645F0E2A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD8912C10681D8B21Fd3742244f44658dBA12264E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAf30D2a7E90d7DC361c8C4585e9BB7D2F6f15bc7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaeC2E87E0A235266D9C5ADc9DEb4b2E29b54D009" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa74476443119A942dE498590Fe1f2454d7D4aC0d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5c543e7AE0A1104f78406C340E9C64FD9fCE5170" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x667088b212ce3d06a1b553a7221E1fD19000d9aF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xec67005c4E498Ec7f55E092bd1d35cbC47C91892" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6531f133e6DeeBe7F2dcE5A0441aA7ef330B4e53" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB9e7F8568e08d5659f5D29C4997173d84CdF2607" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE7775A6e9Bcf904eb39DA2b68c5efb4F9360e08C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x08711D3B02C8758F2FB3ab4e80228418a7F8e39c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf7B098298f7C69Fc14610bf71d5e02c60792894C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x607F4C5BB672230e8672085532f7e901544a7375" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xCb94be6f13A1182E4A4B6140cb7bf2025d28e41B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfa05A73FfE78ef8f1a739473e462c54bae6567D9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6810e776880C02933D47DB1b9fc05908e5386b96" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaAAf91D9b90dF800Df4F55c205fd6989c977E73a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xcbCC0F036ED4788F63FC0fEE32873d6A7487b908" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1a95B271B0535D15fa49932Daba31BA612b52946" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2e071D2966Aa7D8dECB1005885bA1977D6038A65" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x960b236A07cf122663c4303350609A66A7B288C0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xcCeD5B8288086BE8c38E23567e684C3740be4D48" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8Ae4BF2C33a8e667de34B54938B0ccD03Eb8CC06" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x40395044Ac3c0C57051906dA938B54BD6557F212" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa645264C5603E96c3b0B078cdab68733794B0A71" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x59061b6f26BB4A9cE5828A19d35CFD5A4B80F056" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x983F6d60db79ea8cA4eB9968C6aFf8cfA04B3c63" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x660e71483785f66133548B10f6926dC332b06e61" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdDAaf4A0702a03A4505F2352a1abA001fFc344be" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x419D0d8BdD9aF5e606Ae2232ed285Aff190E711b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB97048628DB6B661D4C2aA833e95Dbe1A905B280" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x744d70FDBE2Ba4CF95131626614a1763DF805B9E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4470BB87d77b963A013DB939BE332f927f2b992e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8aA33A7899FCC8eA5fBe6A608A109c3893A1B8b2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB64ef51C888972c908CFacf59B47C1AfBC0Ab8aC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD0D6D6C5Fe4a677D343cC433536BB717bAe167dD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB63B606Ac810a52cCa15e44bB630fd42D8d1d83d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0AfFa06e7Fbe5bC9a764C979aA66E8256A631f02" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF4134146AF2d511Dd5EA8cDB1C4AC88C57D60404" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8727c112C712c4a03371AC87a74dD6aB104Af768" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF433089366899D83a9f26A773D59ec7eCF30355e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd4fa1460F537bb9085d22C7bcCB5DD450Ef28e3a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7C5A0CE9267ED19B22F8cae653F198e3E8daf098" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x41e5560054824eA6B0732E656E3Ad64E20e94E45" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5Af2Be193a6ABCa9c8817001F45744777Db30756" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2bDC0D42996017fCe214b21607a515DA41A9E0C5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe3818504c1B32bF1557b16C238B2E01Fd3149C17" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfcA47962D45ADFdfd1Ab2D972315dB4ce7CCf094" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x701C244b988a513c945973dEFA05de933b23Fe1D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0AbdAce70D3790235af448C88547603b945604ea" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x006BeA43Baa3f7A6f765F14f10A1a1b08334EF45" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x177d39AC676ED1C67A2b268AD7F1E58826E5B0af" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEa1f346faF023F974Eb5adaf088BbCdf02d761F4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x08d32b0da63e2C3bcF8019c9c5d849d7a9d791e6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x56ba2Ee7890461f463F7be02aAC3099f6d5811A8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3597bfD533a99c9aa083587B074434E61Eb0A258" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7654915A1b82D6D2D0AFc37c52Af556eA8983c7E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE41d2489571d322189246DaFA5ebDe1F4699F498" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5d60d8d7eF6d37E16EBABc324de3bE57f135e0BC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa7f976C360ebBeD4465c2855684D1AAE5271eFa9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x07D9e49Ea402194bf48A8276dAfB16E4eD633317" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x08f5a9235B08173b7569F83645d2c7fB55e8cCD8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb7cB1C96dB6B22b0D3d9536E0108d062BD488F74" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9E77D5a1251b6F7D456722A6eaC6D2d5980bd891" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5d4ABC77B8405aD177d8ac6682D584ecbFd46CEc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4355fC160f74328f9b383dF2EC589bB3dFd82Ba0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe120c1ECBfdFeA7F0A8f0Ee30063491E8c26fedf" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBBbbCA6A901c926F240b89EacB641d8Aec7AEafD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0e0989b1f9B8A38983c2BA8053269Ca62Ec9B195" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaF4DcE16Da2877f8c9e00544c93B62Ac40631F16" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0d88eD6E74bbFD96B831231638b66C05571e824F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x07e3c70653548B04f0A75970C1F81B4CBbFB606f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC0Eb85285d83217CD7c891702bcbC0FC401E2D9D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x51DB5Ad35C671a87207d88fC11d593AC0C8415bd" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf05a9382A4C3F29E2784502754293D88b835109C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4E0603e2A27A30480E5e3a4Fe548e29EF12F64bE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0F5D2fB29fb7d3CFeE444a200298f468908cC942" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf8e386EDa857484f5a12e4B5DAa9984E06E73705" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x90528aeb3a2B736B780fD1B6C478bB7E1d643170" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd7631787B4dCc87b1254cfd1e5cE48e96823dEe8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x226bb599a12C826476e3A771454697EA52E9E220" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x514910771AF9Ca656af840dff83E8264EcF986CA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDf6Ef343350780BF8C3410BF062e0C015B1DD671" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe8Ff5C9c75dEb346acAc493C463C8950Be03Dfba" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8D75959f1E61EC2571aa72798237101F084DE63a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE814aeE960a85208C3dB542C53E7D4a6C8D5f60F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8eFFd494eB698cc399AF6231fCcd39E08fd20B15" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7d3cb11f8c13730C24D01826d8F2005F0e1b348F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3d1BA9be9f66B8ee101911bC36D3fB562eaC2244" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4156D3342D5c385a87D264F90653733592000581" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc96DF921009B790dfFcA412375251ed1A2b75c60" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb2F7EB1f2c37645bE61d73953035360e768D81E6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x83eEA00D838f92dEC4D1475697B9f4D3537b56E3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9B11EFcAAA1890f6eE52C6bB7CF8153aC5d74139" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC12D1c73eE7DC3615BA4e37E4ABFdbDDFA38907E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE0C72452740414d861606a44cCd5eA7f96488278" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2C974B2d0BA1716E644c1FC59982a89DDD2fF724" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x168296bb09e24A88805CB9c33356536B980D3fC5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa8006C4ca56F24d6836727D106349320dB7fEF82" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9214eC02CB71CbA0ADA6896b8dA260736a67ab10" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDd6C68bb32462e01705011a4e2Ad1a60740f217F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x336F646F87D9f6bC6Ed42Dd46E8b3fD9DbD15C22" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf3Db5Fa2C66B7aF3Eb0C0b782510816cbe4813b8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc42209aCcC14029c1012fB5680D95fBd6036E2a0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEA610B1153477720748DC13ED378003941d84fAB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xba2184520A1cC49a6159c57e61E1844E085615B6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd4c435F5B09F855C3317c8524Cb1F586E42795fa" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf0Ee6b27b759C9893Ce4f094b49ad28fd15A23e4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7A41e0517a5ecA4FdbC7FbebA4D4c47B9fF6DC63" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5D21eF5f25a985380B65c8e943A0082fEDa0Db84" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2dAEE1AA61D60A252DC80564499A69802853583A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE64509F0bf07ce2d29A7eF19A8A9bc065477C1B4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xCeD4E93198734dDaFf8492d525Bd258D49eb388E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x27054b13b1B798B345b591a4d22e6562d47eA75a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7d4b8Cce0591C9044a22ee543533b72E976E36C3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1c4481750daa5Ff521A2a7490d9981eD46465Dbd" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x30ceCB5461A449A90081F5a5F55db4e048397BAB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfec0cF7fE078a500abf15F1284958F22049c2C7e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3137619705b5fc22a3048989F983905e456b59Ab" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x881Ef48211982D01E2CB7092C915E647Cd40D85C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9AF4f26941677C706cfEcf6D3379FF01bB85D5Ab" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8f8221aFbB33998d8584A2B05749bA73c37a938a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x539EfE69bCDd21a83eFD9122571a64CC25e0282b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfF18DBc487b4c2E3222d115952bABfDa8BA52F5F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4DC3643DbC642b72C158E7F3d2ff232df61cb6CE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x039B5649A59967e3e936D7471f9c3700100Ee1ab" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe469c4473af82217B30CF17b10BcDb6C8c796e75" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x705EE96c1c160842C92c1aeCfCFfccc9C412e3D9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE50365f5D679CB98a1dd62D6F6e58e59321BcdDf" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc324a2f6b05880503444451B8b27e6f9e63287Cb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6Aac8CB9861E42bf8259F5AbDC6aE3Ae89909E11" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7728dFEF5aBd468669EB7f9b48A7f70a501eD29D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF970b8E36e23F7fC3FD752EeA86f8Be8D83375A6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5046E860ff274fb8c66106B0Ffb8155849fB0787" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0A76aad21948eA1ef447D26DEe91a54370E151e0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0aeF06DcCCC531e581f0440059E6FfCC206039EE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x859a9C0b44cb7066D956a958B0b82e54C9e44b4B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xac3211a5025414Af2866FF09c23FC18bc97e79b1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA9Aad2dC3a8315caeee5F458B1d8EDc31D8467BD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEA38eAa3C86c8F9B751533Ba2E562deb9acDED40" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8F0921f30555624143d427b340b1156914882C10" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xeB7C20027172E5d143fB030d50f91Cece2D1485D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB7c4A82936194FEE52a4E3d4cEC3415f74507532" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x595832F8FC6BF59c85C527fEC3740A1b7a361269" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x12B19D3e2ccc14Da04FAe33e63652ce469b3F2FD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x48f775EFBE4F5EcE6e0DF2f7b5932dF56823B990" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x78B7FADA55A64dD895D8c8c35779DD8b67fA8a05" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0Cf0Ee63788A0849fE5297F3407f701E122cC023" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x44197A4c44D6A059297cAf6be4F7e172BD56Caaf" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x24692791Bc444c5Cd0b81e3CBCaba4b04Acd1F3B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5554e04e76533E1d14c52f05beEF6c9d329E1E30" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBA5F11b16B155792Cf3B2E6880E8706859A8AEB6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x255Aa6DF07540Cb5d3d297f0D0D4D84cb52bc8e6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6C2adC2073994fb2CCC5032cC2906Fa221e9B391" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc3761EB917CD790B30dAD99f6Cc5b4Ff93C4F9eA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x999967E2Ec8A74B7c8E9dB19E039d920B31d39D0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x50Ee674689d75C0f88E8f83cfE8c4B69E8fd590D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEA097A2b1dB00627B2Fa17460Ad260c016016977" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0371A82e4A9d0A4312f3ee2Ac9c6958512891372" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x103c3A209da59d3E7C4A89307e66521e081CFDF0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3ADfc4999F77D04c8341BAC5F3A76f58DfF5B37A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x62a56a4A2Ef4D355D34D10fBF837e747504d38d4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5d51FCceD3114A8bb5E90cDD0f9d682bCbCC5393" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x82b0E50478eeaFde392D45D1259Ed1071B6fDa81" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x99ea4dB9EE77ACD40B119BD1dC4E33e1C070b80d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x618E75Ac90b12c6049Ba3b27f5d5F8651b0037F6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x42d6622deCe394b54999Fbd73D108123806f6a18" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x340D2bdE5Eb28c1eed91B2f790723E3B160613B7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf04a8ac553FceDB5BA99A64799155826C136b0Be" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF7920B0768Ecb20A123fAc32311d07D193381d6f" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "WISH-2D5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb62d18DeA74045E822352CE4B3EE77319DC5ff2F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x80fB784B7eD66730e8b1DBd9820aFD29931aab03" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd341d1680Eeee3255b8C4c75bCCE7EB57f144dAe" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x679BADc551626e01B23CeecEFBc9B877EA18fc46" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x419c4dB4B9e25d6Db2AD9691ccb832C8D9fDA05E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB41422D5a1d5d5C73c229686935b40F881502785" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x88A3E4F35D64aAD41A6d4030ac9AFE4356cB84fA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1e797Ce986C3CFF4472F7D38d5C4aba55DfEFE40" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x04F2E7221fdb1B52A68169B25793E51478fF0329" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x74CEDa77281b339142A36817Fa5F9E29412bAb85" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5E6b6d9aBAd9093fdc861Ea1600eBa1b355Cd940" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xCc34366E3842cA1BD36c1f324d15257960fCC801" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBDC5bAC39Dbe132B1E030e898aE3830017D7d969" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF83301c5Cd1CCBB86f466A6B3c53316ED2f8465a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x286BDA1413a2Df81731D4930ce2F862a35A609fE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x27f610BF36ecA0939093343ac28b1534a721DBB4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x85089389C14Bd9c77FC2b8F0c3d1dC3363Bf06Ef" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x672a1AD4f667FB18A333Af13667aa0Af1F5b5bDD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x63b992e6246d88f07fc35A056d2C365E6D441A3D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD01DB73E047855Efb414e6202098C4Be4Cd2423B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x66186008C1050627F979d464eABb258860563dbE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9041Fe5B3FDEA0f5e4afDC17e75180738D877A01" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x55F93985431Fc9304077687a35A1BA103dC1e081" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2604FA406Be957E542BEb89E6754fCdE6815e83f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x81c9151de0C8bafCd325a57E3dB5a5dF1CEBf79c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8B1F49491477e0fB46a29fef53F1EA320D13c349" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5e3346444010135322268a4630d2ED5F8D09446c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x72aDadb447784dd7AB1F472467750fC485e4cb2d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC5bBaE50781Be1669306b9e001EFF57a2957b09d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6EC8a24CaBdc339A06a172F8223ea557055aDAa5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF70a642bD387F94380fFb90451C2c81d4Eb82CBc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2C4e8f2D746113d0696cE89B35F0d8bF88E0AEcA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD0a4b8946Cb52f0661273bfbC6fD0E0C75Fc6433" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd234BF2410a0009dF9c3C63b610c09738f18ccD7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbf2179859fc6D5BEE9Bf9158632Dc51678a4100e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x72dD4b6bd852A3AA172Be4d6C5a6dbEc588cf131" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x558EC3152e2eb2174905cd19AeA4e34A23DE9aD6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb3104b4B9Da82025E8b9F8Fb28b3553ce2f67069" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd2d6158683aeE4Cc838067727209a0aAF4359de3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x06147110022B768BA8F99A8f385df11a151A9cc8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x68d57c9a1C35f63E2c83eE8e49A64e9d70528D25" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0Ebb614204E47c09B6C3FeB9AAeCad8EE060E23E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA823E6722006afe99E91c30FF5295052fe6b8E32" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x70a72833d6bF7F508C8224CE59ea1Ef3d0Ea3A38" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE477292f1B3268687A29376116B0ED27A9c76170" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0396340f16Bbec973280AB053efc3f208fA37795" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0AF44e2784637218dD1D32A322D44e603A8f0c6A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7703C35CfFdC5CDa8D27aa3df2F9ba6964544b6e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x52A7cB918c11A16958bE40CBA7E31e32a499a465" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1234567461d3f8Db7496581774Bd869C83D51c93" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB70835D7822eBB9426B56543E391846C107bd32C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc27A2F05fa577a83BA0fDb4c38443c0718356501" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x107c4504cd79C5d2696Ea0030a8dD4e92601B82e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0bb217E40F8a5Cb79Adf04E1aAb60E5abd0dfC1e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE2FB6529EF566a080e6d23dE0bd351311087D567" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1d462414fe14cf489c7A21CaC78509f4bF8CD7c0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1a7a8BD9106F2B8D977E08582DC7d24c723ab0DB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x814e0908b12A99FeCf5BC101bB5d0b8B5cDf7d26" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA974c709cFb4566686553a20790685A47acEAA33" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe81D72D14B1516e68ac3190a46C93302Cc8eD60f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8a854288a5976036A725879164Ca3e91d30c6A1B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x584B44853680ee34a0F337B712a8f66d816dF151" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5f3789907b35DCe5605b00C0bE0a7eCDBFa8A841" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9e6B2B11542f2BC52f3029077acE37E8fD838D7F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x58d0A58E4B165a27E4e1B8C2A3eF39C89b581180" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6781a0F84c7E9e846DCb84A9a5bd49333067b104" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4824A7b64E3966B0133f4f4FFB1b9D6bEb75FFF7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9B20DaBcec77f6289113E61893F7BEeFAEB1990a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1063ce524265d5a3A624f4914acd573dD89ce988" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5F53f7A8075614b699Baad0bC2c899f4bAd8FBBF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5B2e4a700dfBc560061e957edec8F6EeEb74a320" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x16f812Be7FfF02cAF662B85d5d58a5da6572D4Df" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6fFF3806Bbac52A20e0d79BC538d527f6a22c96b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1961B3331969eD52770751fC718ef530838b6dEE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x264Dc2DedCdcbb897561A57CBa5085CA416fb7b4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1b6C5864375b34aF3Ff5Bd2E5f40Bc425B4a8D79" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0F4CA92660Efad97a9a70CB0fe969c755439772C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x32d74896f05204D1b6Ae7B0a3CEBd7FC0Cd8F9C7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x461733c17b0755CA5649B6DB08B3E213FCf22546" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x12B306fA98F4CbB8d4457FdFf3a0A0a56f07cCdf" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2C82c73d5B34AA015989462b2948cd616a37641F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x45245bc59219eeaAF6cD3f382e078A461FF9De7B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa6a840E50bCaa50dA017b91A0D86B8b2d41156EE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x85e076361cc813A908Ff672F9BAd1541474402b2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4CC19356f2D37338b9802aa8E8fc58B0373296E7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFF603F43946A3A28DF5E6A73172555D8C8b02386" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFA1a856Cfa3409CFa145Fa4e20Eb270dF3EB21ab" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x02C4C78C462E32cCa4a90Bc499bF411Fb7bc6aFB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x79650799e7899A802cB96C0Bc33a6a8d4CE4936C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x57838fF342f36A1EC18224981ea8715a4667fB3a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5B0751713b2527d7f002c0c4e2a37e1219610A6B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x13f25cd52b21650caa8225C9942337d914C9B030" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1245ef80F4d9e02ED9425375e8F649B9221b31D8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB17DF9a3B09583a9bDCf757d6367171476D4D8a3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xeC46f8207D766012454c408De210BCBc2243E71c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x64CdF819d3E75Ac8eC217B3496d7cE167Be42e80" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xCc13Fc627EFfd6E35D2D2706Ea3C4D7396c610ea" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8eB24319393716668D768dCEC29356ae9CfFe285" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x687174f8C49ceb7729D925C3A961507ea4Ac7b28" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2567c677473d110D75a8360C35309e63B1d52429" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9F5F3CFD7a32700C93F971637407ff17b91c7342" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9AF839687F6C94542ac5ece2e317dAAE355493A1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8f136Cc8bEf1fEA4A7b71aa2301ff1A52F084384" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x647F274b3a7248D6CF51b35f08E7E7fD6EdFb271" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd97579Cea3fE2473682a4C42648134BB982433B9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x89303500a7Abfb178B274FD89F2469C264951e1f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x922105fAd8153F516bCfB829f56DC097a0E1D705" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe75ad3aAB14E4B0dF8c5da4286608DaBb21Bd864" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x13d0bf45e5F319Fa0B58900807049f23caE7C40D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x653430560bE843C4a3D143d0110e896c2Ab8ac0D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x26E75307Fc0C021472fEb8F727839531F112f317" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x69b148395Ce0015C13e36BFfBAd63f49EF874E03" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x80A7E048F37A50500351C204Cb407766fA3baE7f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdA6cb58A0D0C01610a29c5A65c303e13e885887C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3A92bD396aEf82af98EbC0Aa9030D25a23B11C6b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4EcDB6385f3Db3847F9C4A9bf3F9917bb27A5452" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4290563C2D7c255B5EEC87f2D3bD10389f991d68" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe0D95530820aAfc51b1d98023AA1Ff000b78d8b2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4092678e4E78230F46A1534C0fbc8fA39780892B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5136C98A80811C3f46bDda8B5c4555CFd9f812F0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBDCFbf5C4D91Abc0bC9709C7286d00063c0e6F22" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x37E8789bB9996CaC9156cD5F5Fd32599E6b91289" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x923108a439C4e8C2315c4f6521E5cE95B44e9B4c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x327682779bAB2BF4d1337e8974ab9dE8275A7Ca8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC39E626A04C5971D770e319760D7926502975e47" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaA7a9CA87d3694B5755f213B5D04094b8d0F0A6F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFA3118B34522580c35Ae27F6cf52da1dBb756288" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7f121d4EC6c2C07eB6BC7989d91d2d4fF654c068" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4270bb238f6DD8B1c3ca01f96CA65b2647c06D3C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2d0E95bd4795D7aCe0da3C0Ff7b706a5970eb9D3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf278c1CA969095ffddDED020290cf8B5C424AcE2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5A1A29DBb6Ad6153DB764568C1289076bC876df6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3136eF851592aCf49CA4C825131E364170FA32b3" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "EQL-586" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x58c69ed6cd6887c0225D1FcCEcC055127843c69b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfAE4Ee59CDd86e3Be9e8b90b53AA866327D7c090" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAa0bb10CEc1fa372eb3Abc17C933FC6ba863DD9E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8f7b0B40E27E357540F90f187d90CE06366aC5A5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb6EE9668771a79be7967ee29a63D4184F8097143" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaE73B38d1c9A8b274127ec30160a4927C4d71824" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9992eC3cF6A55b00978cdDF2b27BC6882d88D1eC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x41dBECc1cdC5517C6f76f6a6E836aDbEe2754DE3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa5Fd1A791C4dfcaacC963D4F73c6Ae5824149eA7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xba9d4199faB4f26eFE3551D490E3821486f135Ba" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfd8971d5E8E1740cE2d0A84095fCA4De729d0c16" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2baac9330Cf9aC479D819195794d79AD0c7616e3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6f259637dcD74C767781E37Bc6133cd6A68aa161" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2ccbFF3A042c68716Ed2a2Cb0c544A9f1d1935E1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x24dDFf6D8B8a42d835af3b440De91f3386554Aa4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5732046A883704404F284Ce41FfADd5b007FD668" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3505F494c3f0fed0B594E01Fa41Dd3967645ca39" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe8A1Df958bE379045E2B46a31A98B93A2eCDfDeD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8dB54ca569D3019A2ba126D03C37c44b5eF81EF6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4CF488387F035FF08c371515562CBa712f9015d4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x92e52a1A235d9A103D970901066CE910AAceFD37" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd7CDdD45629934c2f6ED3B63217bD8085D7C14A8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9c23D67AEA7B95D80942e3836BCDF7E708A747C2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9e3319636e2126e3c0bc9e3134AEC5e1508A46c7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd780Ae2Bf04cD96E577D3D014762f831d97129d0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5adc961D6AC3f7062D2eA45FEFB8D8167d44b190" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe8780B48bdb05F928697A5e8155f672ED91462F7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD0352a019e9AB9d757776F532377aAEbd36Fd541" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6425c6BE902d692AE2db752B3c268AFAdb099D3b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFb2f26F266Fb2805a387230f2aa0a331b4d96Fba" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x69BEaB403438253f13b6e92Db91F7FB849258263" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc7BbA5b765581eFb2Cdd2679DB5Bea9eE79b201f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xCc80C051057B774cD75067Dc48f8987C4Eb97A5e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x408e41876cCCDC0F92210600ef50372656052a38" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5c3a228510D246b78a3765C20221Cbf3082b44a4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf44745fBd41F6A1ba151df190db0564c5fCc4410" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x809826cceAb68c387726af962713b64Cb5Cb3CCA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB98d4C97425d9908E66E53A6fDf673ACcA0BE986" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x83984d6142934bb535793A82ADB0a46EF0F66B6d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5c743a35E903F6c584514ec617ACEe0611Cf44f3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6758B7d441a9739b98552B373703d8d3d14f9e62" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBC86727E770de68B1060C91f6BB6945c73e10388" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8A1E3930FDe1f151471c368fDBb39F3F63A65B55" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEda8B016efA8b1161208Cf041cD86972eeE0F31E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd0929d411954c47438dc1d871dd6081F5C5e149c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc690F7C7FcfFA6a82b79faB7508c466FEfdfc8c5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x46b9Ad944d1059450Da1163511069C718F699D31" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4D8fc1453a0F359e99c9675954e656D80d996FbF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc72fe8e3Dd5BeF0F9f31f259399F301272eF2a2D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x622dFfCc4e83C64ba959530A5a5580687a57581b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5b26C5D0772E5bbaC8b3182AE9a13f9BB2D03765" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0000000000085d4780B73119b644AE5ecd22b376" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1B957Dc4aEfeed3b4A2351a6A6d5cbfbbA0CeCFa" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9a005c9a89BD72a4Bd27721E7a09A3c11D2b03C4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaBbBB6447B68ffD6141DA77C18c7B5876eD6c5ab" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf3db7560E820834658B590C96234c333Cd3D5E5e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9a0242b7a33DAcbe40eDb927834F96eB39f8fBCB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD49ff13661451313cA1553fd6954BD1d9b6E02b9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDD16eC0F66E54d453e6756713E533355989040E4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE5F166c0D8872B68790061317BB6CcA04582C912" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe25b0BBA01Dc5630312B6A21927E578061A13f55" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5102791cA02FC3595398400BFE0e33d7B6C82267" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEF2463099360a085f1f10b076Ed72Ef625497a06" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfD107B473AB90e8Fbd89872144a3DC92C40Fa8C9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1122B6a0E00DCe0563082b6e2953f3A943855c1F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC011A72400E58ecD99Ee497CF89E3775d4bd732F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA4e8C3Ec456107eA67d3075bF9e3DF3A75823DB0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x07a58629AAF3e1A0d07D8f43114B76BD5EEe3B91" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4672bAD527107471cB5067a887f4656D585a8A31" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x998b3B82bC9dBA173990Be7afb772788B5aCB8Bd" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x814F67fA286f7572B041D041b1D99b432c9155Ee" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFFE02ee4C69eDf1b340fCaD64fbd6b37a7b9e265" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6Ba460AB75Cd2c56343b3517ffeBA60748654D26" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x35a69642857083BA2F30bfaB735dacC7F0bac969" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x58a4884182d9E835597f405e5F258290E46ae7C2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfDBc1aDc26F0F8f8606a5d63b7D3a3CD21c22B23" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x28b5E12CcE51f15594B0b91d5b5AdaA70F684a02" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA15C7Ebe1f07CaF6bFF097D8a589fb8AC49Ae5B3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x01fF50f8b7f74E4f00580d9596cd3D0d6d6E326f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xCA0e7269600d353F70b14Ad118A49575455C0f2f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3893b9422Cd5D70a81eDeFfe3d5A1c6A978310BB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4de2573e27E648607B50e1Cfff921A33E4A34405" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0F02e27745e3b6e9e1310d19469e2b5D7B5eC99A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6888a16eA9792c15A4DCF2f6C623D055c8eDe792" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1FE70bE734e473e5721ea57C8B5B01e6Caa52686" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x28dee01D53FED0Edf5f6E310BF8Ef9311513Ae40" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x63e634330A20150DbB61B15648bC73855d6CCF07" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x001F0aA5dA15585e5b2305DbaB2bac425ea71007" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x355a458d555151D3B27F94227960Ade1504E526a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2f8472dd7ecf7cA760c8f6b45dB20Ca7cf52F8d7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA13f0743951B4f6E3e3AA039f682E17279f52bc3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x23352036E911A22Cfc692B5E2E196692658ADED9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6aEB95F06CDA84cA345c2dE0F3B7f96923a44f4c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9E46A38F5DaaBe8683E10793b06749EEF7D733d1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbf52F2ab39e26E0951d2a02b49B7702aBe30406a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x41AB1b6fcbB2fA9DCEd81aCbdeC13Ea6315F2Bf2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6295Ab2BE04A617747481B292c390BfcA592Cf28" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBe428c3867F05deA2A89Fc76a102b544eaC7f772" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa44E5137293E855B1b7bC7E2C6f8cD796fFCB037" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7e9e431a0B8c4D532C745B1043c7FA29a48D4fBa" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3543638eD4a9006E4840B105944271Bcea15605D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE69a353b3152Dd7b706ff7dD40fe1d18b7802d31" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x44F588aEeB8C44471439D1270B3603c66a9262F1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x076C97e1c869072eE22f8c91978C99B4bcB02591" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc12d099be31567add4e4e4d0D45691C3F58f5663" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9B70740e708a083C6fF38Df52297020f5DfAa5EE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6710c63432A2De02954fc0f851db07146a6c0312" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAF446174961CD544e51B89310581669e8FC00D16" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8810C63470d38639954c6B41AaC545848C46484a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8B40761142B9aa6dc8964e61D0585995425C3D94" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF41e5Fbc2F6Aac200Dd8619E121CE1f05D150077" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd559f20296FF4895da39b5bd9ADd54b442596a61" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf453B5B9d4E0B5c62ffB256BB2378cc2BC8e8a89" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC27C95350eCD634C80dF89db0f10cd5c24B7B11f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xef8CF79C21637fc6f951bcaC348915508a639a41" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE5Dada80Aa6477e85d09747f2842f7993D0Df71C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x13C2fab6354d3790D8ece4f0f1a3280b4A25aD96" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe7D3e4413E29ae35B0893140F4500965c74365e5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbCdfE338D55c061C084D81fD793Ded00A27F226D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE34e1944E776f39B9252790a0527eBDa647aE668" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd2Fa8f92Ea72AbB35dBD6DECa57173d22db2BA49" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6c6EE5e31d828De241282B9606C8e98Ea48526E2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x12759512D326303B45f1ceC8F7B6fd96F387778E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0947b0e6D821378805c9598291385CE7c791A6B2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA017ac5faC5941f95010b12570B812C974469c2C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFc2C4D8f95002C14eD0a7aA65102Cac9e5953b5E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x03C780cD554598592B97b7256dDAad759945b125" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x53066cdDBc0099eb6c96785d9b3DF2AAeEDE5DA3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB62132e35a6c13ee1EE0f84dC5d40bad8d815206" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC343f099d3E41aA5C1b59470450e21E92E2d840b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0B4BdC478791897274652DC15eF5C135cae61E60" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEBBdf302c940c6bfd49C6b165f457fdb324649bc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbbFF862d906E348E9946Bfb2132ecB157Da3D4b4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaaAEBE6Fe48E54f431b0C390CfaF0b017d09D42d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x763186eB8d4856D536eD4478302971214FEbc6A9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb0280743b44bF7db4B6bE482b2Ba7b75E5dA096C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x737F98AC8cA59f2C68aD658E3C3d8C8963E40a4c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3a1Bda28AdB5B0a812a7CF10A1950c920F79BcD3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x47bc01597798DCD7506DCCA36ac4302fc93a8cFb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4a527d8fc13C5203AB24BA0944F4Cb14658D1Db6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x905E337c6c8645263D3521205Aa37bf4d034e745" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9b4e2B4B13d125238Aa0480dD42B4f6fC71b37CC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4Cd988AfBad37289BAAf53C13e98E2BD46aAEa8c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3abdfF32F76b42E7635bdb7e425f0231A5F3aB17" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x139d9397274bb9E2C29A9aa8Aa0b5874d30D62E3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x61f33Da40594cEc1E3Dc900FaF99F861D01e2e7D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6DD4e4Aad29A40eDd6A409b9c1625186C9855b4D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1829aA045E21E0D59580024A951DB48096e01782" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEDD7c94FD7B4971b916d15067Bc454b9E1bAD980" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd99b8A7fA48E25Cce83B81812220A3E03Bf64e5f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x543Ff227F64Aa17eA132Bf9886cAb5DB55DCAddf" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE1Aee98495365fc179699C1bB3E761FA716beE62" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEB9951021698B42e4399f9cBb6267Aa35F82D59D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1c79ab32C66aCAa1e9E81952B8AAa581B43e54E7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1A0F2aB46EC630F9FD638029027b552aFA64b94c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x17e67d1CB4e349B9CA4Bc3e17C7DF2a397A7BB64" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf263292e14d9D8ECd55B58dAD1F1dF825a874b7c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8713d26637CF49e1b6B4a7Ce57106AaBc9325343" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6ea6531b603F270d23d9EDd2d8279135DC5D6773" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x228ba514309FFDF03A81a205a6D040E429d6E80C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4f3AfEC4E5a3F2A6a1A411DEF7D7dFe50eE057bF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4BFFC9B4d4DcF730820a2EdCAD48Ff5D7E0Ae807" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb6F43025B29196Af2dddd69b0a58AFBa079cD600" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4aF328C52921706dCB739F25786210499169AFe6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x347C099f110Ca6761779329D2879957b606b6aCE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF03045a4C8077e38f3B8e2Ed33b8aEE69edF869F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB2135AB9695a7678Dd590B1A996CB0f37BCB0718" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4DF47B4969B2911C966506E3592c41389493953b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc20464e0C373486d2B3335576e83a218b1618A5E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4162178B78D6985480A308B2190EE5517460406D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x491C9A23DB85623EEd455a8EfDd6AbA9b911C5dF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x10bA8C420e912bF07BEdaC03Aa6908720db04e0c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8400D94A5cb0fa0D041a3788e395285d61c9ee5e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF3b3Cad094B89392fcE5faFD40bC03b80F2Bc624" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfe5F141Bf94fE84bC28deD0AB966c16B17490657" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9D86b1B2554ec410ecCFfBf111A6994910111340" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7B0C06043468469967DBA22d1AF33d77d44056c8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2859021eE7F2Cb10162E67F33Af2D22764B31aFf" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x55296f69f40Ea6d20E478533C15A6B08B654E758" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x88d50B466BE55222019D71F9E8fAe17f5f45FCA1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf51EBf9a26DbC02B13F8B3a9110dac47a4d62D78" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x78a73B6CBc5D183CE56e786f6e905CaDEC63547B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x76960Dccd5a1fe799F7c29bE9F19ceB4627aEb2f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1C83501478f1320977047008496DACBD60Bb15ef" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEcE83617Db208Ad255Ad4f45Daf81E25137535bb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1CCAA0F2a7210d76E1fDec740d5F323E2E1b1672" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6fB3e0A217407EFFf7Ca062D46c26E5d60a14d69" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5dbe296F97B23C4A6AA6183D73e574D02bA5c719" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5Cf04716BA20127F1E2297AdDCf4B5035000c9eb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA9d2927d3a04309E008B6af6E2e282AE2952e7fD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1dEa979ae76f26071870F824088dA78979eb91C8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB1eeF147028E9f480DbC5ccaA3277D417D1b85F0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA4eA687A2A7F29cF2dc66B39c68e4411C0D00C49" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc528c28FEC0A90C083328BC45f587eE215760A0F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x84F7c44B6Fed1080f647E354D552595be2Cc602F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB6eD7644C69416d67B522e20bC294A9a9B405B31" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB9bb08AB7E9Fa0A1356bd4A39eC0ca267E03b0b3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEA26c4aC16D4a5A106820BC8AEE85fd0b7b2b664" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC80c5E40220172B36aDee2c951f26F2a577810C5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB5DBC6D3cf380079dF3b27135664b6BCF45D1869" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0E8d6b471e332F140e7d9dbB99E5E3822F728DA6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x81b4D08645DA11374a03749AB170836E4e539767" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xCDB7eCFd3403Eef3882c65B761ef9B5054890a47" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "TM2-0C4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAf8A215e81FAea7C180CE22b72483525121813BD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x26DB5439F651CAF491A87d48799dA81F191bDB6b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb056c38f6b7Dc4064367403E26424CD2c60655e1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x75c5eE419331B6150879530D06f9Ba054755F1DA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf091Cf09c51811819DB705710e9634B8bf18F164" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0f8c45B896784A1E408526B9300519ef8660209c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x624d520BAB2E4aD83935Fa503fB130614374E850" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD6e1401a079922469e9b965Cb090ea6fF64C6839" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC86D054809623432210c107af2e3F619DcFbf652" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf53C580bC4065405bC649cC077fF4f2F28528f4B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA8258AbC8f2811dd48EccD209db68F25E3E34667" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8a77e40936BbC27e80E9a3F526368C967869c86D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3c4bEa627039F0B7e7d21E34bB9C9FE962977518" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3c4a3ffd813a107febd57B2f01BC344264D90FdE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa3d58c4E56fedCae3a7c43A725aeE9A71F0ece4e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9ab165D795019b6d8B3e971DdA91071421305e5a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA2A54f1Ec1f09316eF12c1770D32ed8F21B1Fb6A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEB9A4B185816C354dB92DB09cC3B50bE60b901b6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x436F0F3a982074c4a05084485D421466a994FE53" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb9EF770B6A5e12E45983C5D80545258aA38F3B78" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4AaC461C86aBfA71e9d00d9a2cde8d74E4E1aeEa" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1ed7AE1F0E2Fa4276DD7ddC786334a3dF81D50c0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8e1b448EC7aDFc7Fa35FC2e885678bD323176E34" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4D9e23a3842fE7Eb7682B9725cF6c507C424A41B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDF347911910b6c9A4286bA8E2EE5ea4a39eB2134" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8E5610ab5E39d26828167640EA29823fe1dD5843" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x954b890704693af242613edEf1B603825afcD708" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6863bE0e7CF7ce860A574760e9020D519a8bDC47" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA86a0Da9D05d0771955DF05B44Ca120661aF16DE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2c949199cFF14AEAF1B33D64Db01F48FB57f592f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDF2C7238198Ad8B389666574f2d8bc411A4b7428" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbF59e6fe2Bc4eE8D303E493390b4aacab16fcc91" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x423b5F62b328D0D6D44870F4Eee316befA0b2dF5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4f27053F32edA8Af84956437Bc00e5fFa7003287" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x943ED852DadB5C3938ECdC6883718df8142DE4C8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE3F4b4A5d91e5cB9435B947F090A319737036312" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0f1Ed66c251BcB52ecF7E67ac64Bb72482048aDB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd37532D304214D588aeeaC4c365E8F1d72e2304A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfc05987bd2be489ACCF0f509E44B0145d68240f7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf3586684107CE0859c44aa2b2E0fB8cd8731a15a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2bBA3CF6DE6058cc1B4457Ce00deb359E2703d7F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x02F61Fd266DA6E8B102D4121f5CE7b992640CF98" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD9A12Cde03a86E800496469858De8581D3A5353d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xac2e58A06E6265F1Cf5084EE58da68e5d75b49CA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x765f0C16D1Ddc279295c1a7C24B0883F62d33F75" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6A27348483D59150aE76eF4C0f3622A78B0cA698" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x865ec58b06bF6305B886793AA20A2da31D034E68" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4375E7aD8A01B8eC3Ed041399f62D9Cd120e0063" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF4B54874cD8a6C863e3A904c18fDa964661Ec363" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x83e2BE8d114F9661221384B3a50d24B96a5653F5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x64A60493D888728Cf42616e034a0dfEAe38EFCF0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x97AEB5066E1A590e868b511457BEb6FE99d329F5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x44449Fa4d607F807d1eD4a69ad942971728391C8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0707681F344dEB24184037fC0228856F2137B02E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1A66E09F7DccC10eAe46e27cfA6B8d44a50dF1E7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x57Ab1E02fEE23774580C119740129eAC7081e9D3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF8e06E4e4A80287FDCa5b02dcCecAa9D0954840F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5DBAC24e98E2a4f43ADC0DC82Af403fca063Ce2c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF4FaEa455575354d2699BC209B0a65CA99F69982" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x986EE2B944c42D017F52Af21c4c69B84DBeA35d8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1410434b0346f5bE678d0FB554E5c7ab620f8f4a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdfdc0D82d96F8fd40ca0CFB4A288955bECEc2088" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5c64031C62061865E5FD0F53d3CDaeF80f72E99D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x24DCc881E7Dd730546834452F21872D5cb4b5293" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x05aAaA829Afa407D83315cDED1d45EB16025910c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x081F67aFA0cCF8c7B17540767BBe95DF2bA8D97F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB4EFd85c19999D84251304bDA99E90B92300Bd93" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa95592DCFfA3C080B4B40E459c5f5692F67DB7F8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x63f584FA56E60e4D0fE8802b27C7e6E3b33E007f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4689a4e169eB39cC9078C0940e21ff1Aa8A39B9C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x076641aF1B8f06B7f8C92587156143C109002cbe" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x464eBE77c293E473B48cFe96dDCf88fcF7bFDAC0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x60C24407d01782C2175D32fe7C8921ed732371D1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC8058D59e208399B76E66Da1EC669dD6B1BeE2ea" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xce5114d7fa8361F0c088EE26FA3A5446C4a1f50b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd8950fDeaa10304B7A7Fd03a2FC66BC39f3c711a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD1E10C37A27d95D95720291b1Dc6f12F74C71443" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9d9223436dDD466FC247e9dbbD20207e640fEf58" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAAE81c0194D6459F320b70CA0CEdf88e11a242CE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe3278DF3eB2085bA9B6899812A99a10f9CA5E0Df" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4A42d2c580f83dcE404aCad18dab26Db11a1750E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFBc3c8Aad80B5934D134e2CCE065702FF254AD7D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF03f8D65BaFA598611C3495124093c56e8F638f0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd2946be786F35c3Cc402C29b323647aBda799071" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFbe878CED08132bd8396988671b450793C44bC12" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x81705082eF9f0D660f07BE80093D46d826d48b25" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAA19961b6B858D9F18a115f25aa1D98ABc1fdBA8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb5b8F5616Fe42d5ceCA3e87F3FddbDd8F496d760" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbF5496122CF1bB778E0cBE5eaB936f2BE5fC0940" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x47da42696A866CDC61A4C809A515500a242909C1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x95C9bD1f81CEe7391dA3EaC81693E60F3292c1E0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4BBbC57aF270138Ef2FF2C50DbfAD684e9E0e604" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD8698a985B89650d0A70f99AD2909bD0c0b4b51c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA849EaaE994fb86Afa73382e9Bd88c2B6b18Dc71" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF8C595D070d104377f58715ce2E6C93E49a87f3c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFb5a551374B656C6e39787B1D3A03fEAb7f3a98E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdB25f211AB05b1c97D595516F45794528a807ad8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x331fA6C97c64e47475164b9fC8143b533c5eF529" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFb8Bf095eBcdAd57D2e37573a505E7d3bAFDD3CC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB8DdC930c2bAB6c71610A2BE639036E829F9C10b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFc44EC51C80e35A87Bc2140299B1636eC83DFb04" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0bC61DdED5F6710c637cf8288Eb6058766ce1921" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xff2b3353c3015E9f1FBF95B9Bda23F58Aa7cE007" + }, + { + "coin": 818, + "type": "token", + "currency": "USD", + "token_id": "0x0000000000000000000000000000456E65726779" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8D5682941cE456900b12d47ac06a88b47C764CE1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4a6058666cf1057eaC3CD3A5a614620547559fc9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5d48F293BaED247A2D0189058bA37aa238bD4725" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA984A92731C088F1eA4D53b71A2565a399F7D8D5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x554FFc77F4251a9fB3c0E3590a6a205f8d4e067D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0E69D0A2bbB30aBcB7e5CfEA0E4FDe19C00A8d47" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x840fe75ABfaDc0F2d54037829571B2782e919ce4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDA80B20038BDF968C7307BB5907A469482CF6251" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0223fc70574214F65813fE336D870Ac47E147fAe" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x34364BEe11607b1963d66BCA665FDE93fCA666a8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA31108E5BAB5494560Db34c95492658AF239357C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x31f3D9D1BeCE0c033fF78fA6DA60a6048F3E13c5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9972A0F24194447E73a7e8b6CD26a52e02DDfAD5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4212FEa9FEc90236eCc51E41e2096B16CEB84555" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x37E1160184F7dD29f00b78C050Bf13224780b0B0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa6714a2e5f0B1bdb97b895b0913b4FcD3a775E4D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC16b542ff490e01fcc0DC58a60e1EFdc3e357cA6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1014613E2B3CBc4d575054D4982E580d9b99d7B1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9c794f933b4DD8B49031A79b0f924D68BEF43992" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x05984006707585F66465e8A6505341f46b64fA7A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBC46D9961A3932f7D6b64abfdeC80C1816C4B835" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x18f5B4908e8861e3114Ba9a0a9a4E84c5F180Cc0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4618519de4C304F3444ffa7f812dddC2971cc688" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x910Dfc18D6EA3D6a7124A6F8B5458F281060fa4c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x171D750d42d661B62C277a6B486ADb82348c3Eca" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC05d14442A510De4D3d71a3d316585aA0CE32b50" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFA456Cf55250A839088b27EE32A424d7DAcB54Ff" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc9859fccC876e6b4B3C749C5D29EA04F48aCb74F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfF5c25D2F40B47C4a37f989DE933E26562Ef0Ac0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x66BaD545596fb17a0B4ebDC003a85dEF10E8F6Ae" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x20F7A3DdF244dc9299975b4Da1C39F8D5D75f05A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x245ef47D4d0505ECF3Ac463F4d81f41ADE8f1fd1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9F195617fA8fbAD9540C5D113A99A0a0172aaEDC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x153eD9CC1b792979d2Bde0BBF45CC2A7e436a5F9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x832904863978b94802123106e6eB491BDF0Df928" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x02F2D4a04E6E01aCE88bD2Cd632875543b2eF577" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4b317864a05c91225ab8f401EC7be0AeB87e9c12" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7A74c427c833baD2A638E0fb203BA2C728f557C1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x29536B7Ca7029b5cDDEB03c0451715615AcA35ba" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBB1fA4FdEB3459733bF67EbC6f893003fA976a82" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8E766F57F7d16Ca50B4A0b90b88f6468A09b0439" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x17Aa18A4B64A55aBEd7FA543F2Ba4E91f2dcE482" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x851017523AE205adc9195e7F97D029f4Cfe7794c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x170b275CEd089FffAEBFe927F445a350ED9160DC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8a88f04e0c905054D2F33b26BB3A46D7091A039A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe530441f4f73bDB6DC2fA5aF7c3fC5fD551Ec838" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x60c68a87bE1E8a84144b543AAcfA77199cd3d024" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x74FD51a98a4A1ECBeF8Cc43be801cce630E260Bd" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x72430A612Adc007c50e3b6946dBb1Bb0fd3101D1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x054C64741dBafDC19784505494029823D89c3b13" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf4065e4477e91C177DED71A7A6fb5ee07DC46BC9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1fC52f1ABade452Dd4674477D4711951700b3d27" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x973e52691176d36453868D9d86572788d27041A9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6704B673c70dE9bF74C8fBa4b4bd748F0e2190E1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xeE4458e052B533b1aABD493B5f8c4d85D7B263Dc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3e65E1eeFdE5Ea7ccfC9a9a1634AbE90f32262f8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1Cb3209D45B2a60B7fBCA1cCDBF87f674237A4aa" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3f06B5D78406cD97bdf10f5C420B241D32759c80" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFEF3884b603C33EF8eD4183346E093A173C94da6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5D4d57cd06Fa7fe99e26fdc481b468f77f05073C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8fC01E6CbDfFaf09B54F423f9Bb1F856b22e47b2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x13E9EC660d872f55405d70e5C52D872136F0970c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAAD54C9f27B876D2538455DdA69207279fF673a5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4a220E6096B25EADb88358cb44068A3248254675" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf8b358b3397a8ea5464f8cc753645d42e14b79EA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbdEB4b83251Fb146687fa19D1C660F99411eefe3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x21d5678A62DFe63a47062469Ebb2fAc2817D8832" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x846C66cf71C43f80403B51fE3906B3599D63336f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2AEC18c5500f21359CE1BEA5Dc1777344dF4C0Dc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6059F55751603eAd7Dc6d280ad83A7B33D837C90" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE2492F8D2A2618d8709Ca99b1d8d75713Bd84089" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbD4B60a138b3fce3584EA01f50c0908c18f9677A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD7b3669C7d3E38aB5a441383D41F25E003e02148" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x49bD2DA75b1F7AF1E4dFd6b1125FEcDe59dBec58" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9a794Dc1939F1d78fa48613b89B8f9d0A20dA00E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x48C1B2f3eFA85fbafb2ab951bF4Ba860a08cdBB7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7995ab36bB307Afa6A683C24a25d90Dc1Ea83566" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4CcC3759eB48fAF1c6cfadaD2619E7038db6b212" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x05D412CE18F24040bB3Fa45CF2C69e506586D8e8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB6259685685235c1eF4B8529e7105f00BD42b9f8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE8663A64A96169ff4d95b4299E7ae9a76b905B31" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb41f09a973a85c7F497c10B00a939dE667B55a78" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x016396044709EB3edc69C44f4d5Fa6996917E4e8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x57C75ECCc8557136D32619a191fBCDc88560d711" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x501262281B2Ba043e2fbf14904980689CDDB0C78" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc56b13ebbCFfa67cFb7979b900b736b3fb480D78" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5AB793E36070F0fac928EA15826b0c1Bc5365119" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x241bA672574A78a3A604CDd0a94429A73a84a324" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDE1E0AE6101b46520cF66fDC0B1059c5cC3d106c" + }, + { + "coin": 1024, + "type": "token", + "currency": "USD", + "token_id": "ong" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x41875C2332B0877cDFAA699B641402b7D4642c32" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd82Df0ABD3f51425Eb15ef7580fDA55727875f14" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEf51c9377FeB29856E61625cAf9390bD0B67eA18" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x76974C7B79dC8a6a109Fd71fd7cEb9E40eff5382" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1602af2C782cC03F9241992E243290Fccf73Bb13" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xca694eb79eF355eA0999485d211E68F39aE98493" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5301Eae39a4cBa1CC2A74E861fDed062cA3E3420" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5EB87cAA0105a63aa87A36C7Bd2573Bd13E84faE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBAE235823D7255D9D48635cEd4735227244Cd583" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7025baB2EC90410de37F488d1298204cd4D6b29d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbf8fB919A8bbF28e590852AeF2D284494eBC0657" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x009e864923b49263c7F10D19B7f8Ab7a9A5AAd33" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x13119E34E140097a507B07a5564bDe1bC375D9e6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2D3E7D4870a51b918919E7B851FE19983E4c38d5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x049399a6B048D52971F7D122aE21A1532722285F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4289c043A12392F1027307fB58272D8EBd853912" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd9485499499d66B175Cf5ED54c0a19f1a6Bcb61A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x613Fa2A6e6DAA70c659060E86bA1443D2679c9D7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9064c91e51d7021A85AD96817e1432aBf6624470" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x78c292D1445E6b9558bf42e8BC369271DeD062eA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x499A6B77bc25C26bCf8265E2102B1B3dd1617024" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4AC00f287f36A6Aad655281fE1cA6798C9cb727b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB2E260F12406c401874EcC960893C0f74Cd6aFcd" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF84df2db2C87dd650641f8904aF71EbFC3ddE0Ea" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x38c87AA89B2B8cD9B95b736e1Fa7b612EA972169" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x68909e586eeAC8F47315e84B4c9788DD54Ef65Bb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x749f35Ff65932E68267dd82F6CD85eeA735d700E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf14922001A2FB8541a433905437ae954419C2439" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7C2E5b7ec572199D3841f6a38F7D4868BD0798f1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1a2277C83930b7a64C3e3D5544Eaa8C4f946B1B7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x48FF53777F747cFB694101222a944dE070c15D36" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd42debE4eDc92Bd5a3FBb4243e1ecCf6d63A4A5d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x36B4B58DE030E93775E151a78D796039a11a2548" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3FD8f39A962eFDA04956981C31AB89FAB5FB8bC8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD7394087E1DBBE477FE4F1CF373B9Ac9459565fF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4234f63B1D202F6c016Ca3b6a0d41d7d85f17716" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2ba6b1E4424e19816382d15937739959F7DA5fD8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD938137E6d96c72E4a6085412aDa2daD78ff89c4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc54083e77F913a4f99E1232Ae80c318ff03c9D17" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5D64D850c8368008aFB39224E92aD0DcEFf3CF38" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x884181554dfA9e578d36379919C05C25dC4a15bB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaF1250fa68D7DECD34fD75dE8742Bc03B29BD58e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAAf37055188Feee4869dE63464937e683d61b2a1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x97Cb5Cc1b2e10cC56DC16ab9179f06dfEDBe41A2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x05860d453C7974CbF46508c06CBA14e211c629Ce" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x056Fd409E1d7A124BD7017459dFEa2F387b6d5Cd" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDDD460bBD9F79847ea08681563e8A9696867210C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa958E706fc1934E26a3D0c32f471B54F733D0009" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x780116D91E5592E58a3b3c76A351571b39abCEc6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1c4b7d0e1885bd7667Af3378E0c538F74E712006" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8578530205CEcbe5DB83F7F29EcfEEC860C297C2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8606a8F28e1e2FD50B9074d65C01548B1F040B32" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x755eb14D2fefF2939EB3026f5CaD9D03775b9fF4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0142C3B2fC51819B5aF5dFc4AA52Df9722790851" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x574F84108a98c575794F75483d801d1d5DC861a5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe11609b9a51CAF7d32A55896386aC52ED90e66F1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xcec38306558a31cdbb2a9d6285947C5b44A24f3e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8E870D67F660D95d5be530380D0eC0bd388289E1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2F9b6779c37DF5707249eEb3734BbfC94763fBE2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1F54638b7737193FFd86c19Ec51907A7c41755D8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0DB8D8b76BC361bAcbB72E2C491E06085A97Ab31" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x687BfC3E73f6af55F0CccA8450114D107E781a0e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC72ED4445B3fe9f0863106E344E241530d338906" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb052F8A33D8bb068414EaDE06AF6955199f9f010" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x19ea630bCBc1a511a16e65b6ECd447c92E1C087c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBC7F402F3bC1c6D56C8041F551b47a0AD7714D1b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBd0793332e9fB844A52a205A233EF27a5b34B927" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x23Ccc43365D9dD3882eab88F43d515208f832430" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaD5Fe5B0B8eC8fF4565204990E4405B2Da117d8e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x10086399DD8c1e3De736724AF52587a2044c9fA2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x56D1aE30c97288DA4B58BC39F026091778e4E316" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x567300e14f8d67e1F6720a95291Dce2511a86723" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE13Ef257cF4D5Df928ca11d230427C037666d466" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x92A5B04D0ED5D94D7a193d1d334D3D16996f4E13" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBA3a79D758f19eFe588247388754b8e4d6EddA81" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xcAaa93712BDAc37f736C323C93D4D5fDEFCc31CC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdf1338FbAfe7aF1789151627B886781ba556eF9a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x14C926F2290044B647e1Bf2072e67B495eff1905" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x89c6c856a6db3e46107163D0cDa7A7FF211BD655" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7CC62d8E80Be9bEa3947F3443aD136f50f75b505" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2F141Ce366a2462f02cEA3D12CF93E4DCa49e4Fd" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd07D9Fe2d2cc067015E2b4917D24933804f42cFA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa0d440C6DA37892Dc06Ee7930B2eedE0634FD681" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3918C42F14F2eB1168365F911f63E540E5A306b5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x81E74a3eA4BaB2277aA3b941E9D9F37B08Ac5374" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7bA19B7F7d106A9a1e0985397B94F38EEe0b555e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2ecB13A8c458c379c4d9a7259e202De03c8F3D19" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7528E3040376EdD5DB8263Db2F5bd1beD91467FB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1966d718A565566e8E202792658D7b5Ff4ECe469" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe7E4279b80D319EDe2889855135A22021baf0907" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD45247c07379d94904E0A87b4481F0a1DDfa0C64" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb0a0a070640B450eB136DC377208469ee4F49fbc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7C84e62859D0715eb77d1b1C4154Ecd6aBB21BEC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x96B0bF939D9460095C15251F71Fda11e41DcBddB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4D8bfe7EA0f46486Fd40FC4df60CF39f7568BEE8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x72c9Fb7ED19D3ce51cea5C56B3e023cd918baaDf" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7aBc60B3290F68c85f495fD2e0c3Bd278837a313" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB3e2Cb7CccfE139f8FF84013823Bf22dA6B6390A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0F612a09eAd55Bb81b6534e80ed5A21Bf0a27B16" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFf19138b039D938db46bDDA0067DC4BA132ec71C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x869b1F57380aE501d387b19262EFD3C0Eb7501b0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE95990825AAB1a7f0Af4cc648f76a3Bcc99F25B2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x87026F792D09960232CA406E80C89BD35BAfE566" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x813b428aF3920226E059B68A62e4c04933D4eA7a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFE39e6a32AcD2aF7955Cb3D406Ba2B55C901f247" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC38f1fb49acDf2f1213CAf3319F6Eb3ea2cB7527" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x59BE937f05cf2c406b61c42C6c82a093fA54edfE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x419B8ED155180A8c9C64145e76DaD49c0A4Efb97" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd4a293aE8bB9E0BE12E99eB19d48239e8c83a136" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5b11aAcB6Bddb9ffab908FDCE739Bf4aed554327" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1da015eA4AD2d3e5586E54b9fB0682Ca3CA8A17a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2344871f523cBb28A4f60045531184cF1F03Ad24" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2d184014b5658C453443AA87c8e9C4D57285620b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xcA2796F9F61dc7b238Aab043971e49c6164DF375" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe1A178B681BD05964d3e3Ed33AE731577d9d96dD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x122A86b5DFF2D085AfB49600b4cd7375D0d94A5f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3c6Da7763cAA0e4b684BbC733f04a8EC08Af3762" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0ea984e789302B7B612147E4e4144e64f21425Eb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x67a9099f0008C35C61c00042cd9Fb03684451097" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x49614661737EfBFC6a102efaeefDc8E197f7CC0e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x78a2a1029E3168b49d3A276C787050fF5106dCF2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x922aC473A3cC241fD3a0049Ed14536452D58D73c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xca00bC15f67Ebea4b20DfaAa847CAcE113cc5501" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD29F0b5b3F50b07Fe9a9511F7d86F4f4bAc3f8c4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBb1f24C0c1554b9990222f036b0AaD6Ee4CAec29" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xeaf61FC150CD5c3BeA75744e830D916E60EA5A9F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbC647aAd10114B89564c0a7aabE542bd0cf2C5aF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB5Ca46cF1da09248126682a7bd72401fd7A6b151" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x15bdA08c3afbf5955D6e9B235Fd55a1FD0DbC829" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4E15361FD6b4BB609Fa63C81A2be19d873717870" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x497bAEF294c11a5f0f5Bea3f2AdB3073DB448B56" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x47d1a59cBDd19AEE060C859C0009277E245328ae" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x77C07555aF5ffdC946Fb47ce15EA68620E4e7170" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1563D521ba309e2Ad9f4aFfD6f4dE9759E8d4F21" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x26CB3641aaA43911f1D4cB2ce544eb652AAc7c47" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x93ED3FBe21207Ec2E8f2d3c3de6e058Cb73Bc04d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x737fA0372c8D001904Ae6aCAf0552d4015F9c947" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6b193e107A773967bD821bCf8218f3548Cfa2503" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa838be6E4b760E6061D4732D6B9F11Bf578f9A76" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x36D10c6800D569bb8C4fE284a05fFE3B752F972c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEA54C81fe0f72DE8e86B6dC78a9271AA3925E3B5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd5dad1DB7F112037c0c6Cf0792dc2a7866Bfd136" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2167FB82309CF76513E83B25123f8b0559d6b48f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFE76BE9cEC465ed3219a9972c21655D57d21aec6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDAC4AE188AcE3C8985765eDc6C9B4739D4845DdC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc6AbF3C09341741Ac6041B0B08195701bdFD460C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x174aFE7A032b5A33a3270a9f6C30746E25708532" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4D807509aECe24C0fa5A102b6a3B059Ec6E14392" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x37F04d2C3AE075Fad5483bB918491F656B12BDB6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x12f649A9E821F90BB143089a6e56846945892ffB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xED494c9e2F8E34e53BDD0EA9B4d80305cb15C5c2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBe6C8f2810EF39420d2DC2901b8414C8c45FEE6D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1aBdb309aa592f00a101c545168BFDF9a6Ec61CE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3E1d5A855aD9D948373aE68e4fe1f094612b1322" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAcfa209Fb73bF3Dd5bBfb1101B9Bc999C49062a5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x286708f069225905194673755F12359e6afF6FE1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2Fb12bccF6f5Dd338b76Be784A93ade072425690" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC45DbdF28844fdB1482C502897d433aC08d6cCd0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC28e931814725BbEB9e670676FaBBCb694Fe7DF2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5Ca381bBfb58f0092df149bD3D243b08B9a8386e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4946Fcea7C692606e8908002e55A582af44AC121" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x77599D2C6DB170224243e255e6669280F11F1473" + }, + { + "coin": 195, + "type": "token", + "currency": "USD", + "token_id": "TG37mUxRUaH1E8DWSrrmoQ79BnZn1yHztb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA858bC1b71a895Ee83B92F149616F9B3F6Afa0FB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA0b73E1Ff0B80914AB6fe0444E65848C4C34450b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x25B6325f5BB1c1E03cfbC3e53F470E1F1ca022E3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAE31b85Bfe62747d0836B82608B4830361a3d37a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x70c621f949b6556c4545707a2d5d73A776b98359" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x47e67BA66b0699500f18A53F94E2b9dB3D47437e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x58b6A8A3302369DAEc383334672404Ee733aB239" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd947b0ceab2A8885866B9A04A06AE99DE852a3d4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE14A603f7c77d4101A87859b8736a04CFD85C688" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5635ddEaBf9cdDA686995Fe90BEB5411831563FC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd5f788ca0de8f17cBDe1D1E35aA8F005A87fa00b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x04A020325024F130988782bd5276e53595e8d16E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x722F2f3EaC7e9597C73a593f7CF3de33Fbfc3308" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x97fB6Fc2AD532033Af97043B563131C5204F8A35" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB37a769B37224449d92AAc57dE379E1267Cd3B00" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x21aB6c9fAC80C59D401b37cB43F81ea9DDe7Fe34" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8971f9fd7196e5cEE2C1032B50F656855af7Dd26" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x56325d180Ec3878A9028AfC7B0EDCEe7486Cc9df" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x86E44543164D9b97B14ef7f6f3aB7bA670CAB346" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2C5dcd12141c56FBEa08e95f54f12c8B22d492Eb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF1290473E210b2108A85237fbCd7b6eb42Cc654F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8b79656FC38a04044E495e22fAD747126ca305C4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE884cc2795b9c45bEeac0607DA9539Fd571cCF85" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaD22f63404f7305e4713CcBd4F296f34770513f4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd44bb6663936CAb1310584A277f7DAa6943d4904" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xacACa5b8805636608e14C64b0bFFfC2Deb2C6cEc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8De67D55C58540807601dBf1259537BC2DFfc84D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1C289a12A8552B314D0d153d6991fd27a54Aa640" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x752FF65b884b9C260D212C804E0b7ACEea012473" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0BEf619cF38cF0c22967289b8419720fBd1Db9f7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5acD19b9c91e596b1f062f18e3D02da7eD8D1e50" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6400B5522f8D448C0803e6245436DD1c81dF09ce" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x06e0feB0D74106c7adA8497754074D222Ec6BCDf" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0775C81A273B355e6a5b76e240BF708701F00279" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x26DDF6CabADcBF4F013841BD8d914830BeB0d984" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9a49f02e128a8E989b443a8f94843C0918BF45E7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x658D79c02A4829B5efA49254F627287e92458ECD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x018d7D179350f1Bb9853D04982820E37ccE13a92" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE99A894a69d7c2e3C92E61B64C505A6a57d2bC07" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFe1D71498DA3261844eC14325bdbc93c0F7579f0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF3e70642c28f3F707408c56624c2F30eA9F9FcE3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd50649AAb1D39d68BC965E0F6D1cfe0010e4908b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb1c1Cb8C7c1992dba24e628bF7d38E71daD46aeB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3DB6Ba6ab6F95efed1a6E794caD492fAAabF294D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3C6A7aB47B5F058Be0e7C7fE1A4b7925B8aCA40e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599" + }, + { + "coin": 195, + "type": "token", + "currency": "USD", + "token_id": "1002000" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA4Bdb11dc0a2bEC88d24A3aa1E6Bb17201112eBe" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa66Daa57432024023DB65477BA87D4E7F5f95213" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2Fc246aA66F0da5bB1368F688548ecBBE9bdee5d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x446C9033E7516D820cc9a2ce2d0B7328b579406F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5b53f9755f82439CBA66007Ec7073c59E0da4A7D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaff84e86d72EDb971341a6A66eb2dA209446FA14" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0198f46f520F33cd4329bd4bE380a25a90536CD5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAec7d1069e3a914a3EB50f0BFB1796751f2ce48a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEc6c861C2a2b1E5ff5336731bC80c29dBFf88273" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x94236591125E935F5ac128Bb3d5062944C24958c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb683D83a532e2Cb7DFa5275eED3698436371cc9f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9CCbd05d4d25c745d49F5e6BF17e09113Eb4c769" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4983F767b1Bc44328E434729dDabea0a064cA1aC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe9fa21E671BcfB04E6868784b89C19d5aa2424Ea" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x07eF9E82721AC16809D24DAfBE1792Ce01654DB4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd6875274b000462F59e9327cbDe2cEf637914569" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x15A664416E42766A6cC0a1221d9C088548a6E731" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD8002cD05d5B2a85557e1CAAa179cC2408D5ad42" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x796E47B85A0d759F300f1de96A3583004235D4D8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4bD70556ae3F8a6eC6C4080A0C327B24325438f3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0C6E8a8358cBde54F8e4Cd7f07D5ac38aec8C5a4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEEd3aE7b0F8b5B9BB8C035A9941382B1822671CD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBac7A1798350cdf2Dbfe0c210C2C9861223f4B31" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1d464Ac5e046e5fE280c9588eDF8eB681b07008F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x21D5A14e625d767Ce6b7A167491C2d18e0785fDa" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xADF8B8050639b6236915f7516d69dE714672F0bF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0F72714B35a366285Df85886A2eE174601292A17" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0a2D9370cF74Da3FD3dF5d764e394Ca8205C50B6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2eC95B8edA549B79a1248335A39d299d00Ed314C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1864cE27E9F7517047933CaAE530674e8C70b8A7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6fE355c62C6faf6946cE888fFABa9fD12355ae27" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x17B26400621695c2D8C2D8869f6259E82D7544c4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1D287CC25dAD7cCaF76a26bc660c5F7C8E2a05BD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9f0f1Be08591AB7d990faf910B38ed5D60e4D5Bf" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x919D3a363776B1ceec9352610c82dfaf80Edc32d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x01cC4151fe5f00EfB8dF2F90ff833725d3a482a3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5c872500c00565505F3624AB435c222E558E9ff8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4b7aD3a56810032782Afce12d7d27122bDb96efF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB31C219959E06f9aFBeB36b388a4BaD13E802725" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8290333ceF9e6D528dD5618Fb97a76f268f3EDD4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x49D09cDa1Deb8a1680F1270C5ed15218fc4B18f0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa957045A12D270e2eE0dcA9A3340c340e05d4670" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8CC3E2BdC17682c622eB789EDA23FbD6988C84Da" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF29226914595052a04F5AFbe6410D0C3eD707548" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x688478f003b8D0F10b8af2122bF20378555EF958" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x61B2d3eA9f1c6b387C985C73d40e8fBfb284E5C7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8275eBF521Dc217aa79C88132017A5BCEf001dd9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x30680AC0a8A993088223925265fD7a76bEb87E7F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE5B826Ca2Ca02F09c1725e9bd98d9a8874C30532" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x420167D87d35c3A249b32Ef6225872fBD9aB85D2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x57C09A8de0b0F471F8567609777aDdFfb5c46a08" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1C1C14A6B5074905Ce5d367B0A7E098b58EbFD47" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x26fb86579e371c7AEdc461b2DdEF0A8628c93d3B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc15A399c4eA7815fE36857C9E290EE452A5D6B21" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9B39A0B97319a9bd5fed217c1dB7b030453bac91" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8A732BC91c33c167F868E0af7e6f31e0776d0f71" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1C5b760F133220855340003B43cC9113EC494823" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x70861e862E1Ac0C96f853C8231826e469eAd37B1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa96F31F1C187c28980176C3A27ba7069f48abDE4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x86e6A4F512b1290c043970B04E0b570D4FC98291" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4a57E687b9126435a9B19E4A802113e266AdeBde" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4946583c5b86E01cCD30c71a05617D06E3E73060" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4F9254C83EB525f9FCf346490bbb3ed28a81C667" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4D13d624a87baa278733c068A174412AfA9ca6C8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA00425D3e2D3E9FF74F3e112B4D3A7978d7D88c2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA0008F510fE9eE696E7E320C9e5cbf61E27791Ee" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x996229D0c6a485c7F4B52E092EAa907cB2def5C6" + }, + { + "coin": 500, + "type": "token", + "currency": "USD", + "token_id": "tfuel" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5925f67d2767d937F47141DAC24166B469558222" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfDF574766BA1A96A553e175aEfFA85ad78063F0B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdcD85914b8aE28c1E62f1C488E1D968D5aaFfE2b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x57652Fc91f522f9EFF0b38CDF1D51f5FB5764215" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7Fe92EC600F15cD25253b421bc151c51b0276b7D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4FBb0B4cD8f960aC3428194F1c94c805D5b35836" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd35833f9255FB28cC6b91aCB8A66Ba6429D6Ef5A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4571f3a386d1bd18E25d70d117e7067FA0Bd9D08" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xff56Cc6b1E6dEd347aA0B7676C85AB0B3D08B0FA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA809d363A66c576A2a814CDBfEFC107C600A55f0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x310c93dfc1C5E34CDF51678103f63C41762089CD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA6446D655a0c34bC4F05042EE88170D056CBAf45" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9F235D23354857EfE6c541dB92a9eF1877689BCB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1822126fEedb4C7d61EecdBE3682FE61e91383d6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x445f51299Ef3307dBD75036dd896565F5B4BF7A5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9B62513c8a27290CF6A7A9e29386e600245EA819" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1367D4a67C1719B58C7e05dF8768226Fa768279a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF4FE95603881D0e07954fD7605E0e9a916e42C44" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x28FB6531723EE54B1073F7f2beB7f2E3C74503Bc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5137A403Dd25e48DE528912a4aF62881e625D801" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8aa688AB789d1848d131C65D98CEAA8875D97eF1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBE6ac6B50F577205c9D107f37b6E205aA6ACC5D4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC64500DD7B0f1794807e67802F8Abbf5F8Ffb054" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8b6CdA5CC518c904e8844f445E1A7C7d2DB0fF16" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x47b28F365Bf4CB38DB4B6356864BDE7bc4B35129" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6F919D67967a97EA36195A2346d9244E60FE0dDB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x00E150D741Eda1d49d341189CAE4c08a73a49C95" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8716Fc5Da009D3A208f0178b637a50F4ef42400F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x979EBc09e55EA0ab563CF7175e4c4b1a03AFc19a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd28cFec79dB8d0A225767D06140aee280718AB7E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4Dd672e77c795844fe3A464eF8eF0FAAe617C8fB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4b94c8567763654101F690Cf4d54957206383b75" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFFc63b9146967A1ba33066fB057EE3722221aCf0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x763Fa6806e1acf68130D2D0f0df754C93cC546B2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x40d52577830E01aAEfa80659aA90ee8B34685F4e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEF19F4E48830093Ce5bC8b3Ff7f903A0AE3E9Fa1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x297E4e5e59Ad72B1B0A2fd446929e76117be0E0a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd9d01D4Cb824219A8F482a0FAd479cB971Fd0628" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x965F109d31CCb77005858DEfaE0Ebaf7B4381652" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF9e5aF7B42D31D51677c75bbBD37c1986eC79AEE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8c15Ef5b4B21951d50E53E4fbdA8298FFAD25057" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x056dD20b01799E9C1952c7c9a5ff4409a6110085" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x187C4B0e3819017a5cf07af81A4E2b16166aAbc6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x19cA83a13b4C4BE43FA82c5E415E16f1D86f57F7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x90D46A9636B973f18186541d1B04ed3621a49Cb0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE9A95d175a5f4C9369f3b74222402eB1b837693b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xc3e2de0b661cF58F66BdE8E896905399ded58af5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xCFAc2916Ec118a0252A7766C513eE7c71b384b5E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x75231F58b43240C9718Dd58B4967c5114342a86c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x56e0B2C7694E6e10391E870774daA45cf6583486" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x985dd3D42De1e256d09e1c10F112bCCB8015AD41" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdD94842C15abfe4c9bAFE4222adE02896Beb064c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf08c68bD5f4194d994FD70726746Bf529eE5a617" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7865af71cf0b288b4E7F654f4F7851EB46a2B7F8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x10c71515602429C19d53011EA7040B87a4894838" + }, + { + "coin": 195, + "type": "token", + "currency": "USD", + "token_id": "TVimprG4oe3i2HapWzPuTh4WtuosRAh5Ew" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5c62Da804298D5972a323C80B539B8E7517a0dDe" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x22dE9912cd3D74953B1cd1F250B825133cC2C1b3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0cbC9b02B8628AE08688b5cC8134dc09e36C443b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd36E9F8F194A47B10aF16C7656a68EBa1DFe88e4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB705268213D593B8FD88d3FDEFF93AFF5CbDcfAE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9D8bE94D0612170cE533AC4d7B43cc3cd91E5a1A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6c37Bf4f042712C978A73e3fd56D1F5738dD7C43" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0F237D5eA7876E0e2906034D98FDB20D43666ad4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6c3BE406174349cfa4501654313d97e6a31072e1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0488401c3F535193Fa8Df029d9fFe615A06E74E6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x247551F2EB3362E222c742E9c788B8957D9BC87e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB66A2131A6B840dd020151f80723CAED603eFB51" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1F35a281036Be57E64e7E7A2A556b4f888A1b829" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9B1E1FC958B83e801d1342F9f9BA7dA3A55bA1eF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xcecede5A20645EAc6ca2032eeEb1063572D63c29" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE54B3458C47E44C37a267E7C633AFEF88287C294" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x799a4202c12ca952cB311598a024C80eD371a41e" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "ONE-5F9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x115eC79F1de567eC68B7AE7eDA501b406626478e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9c197c4b58527fAAAb67CB35E3145166B23D242e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEe9E5eFF401ee921b138490d00CA8D1F13f67A72" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4Fe327c5a809fA721D47b80C5038A0b393E61305" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5aaEFe84E0fB3DD1f0fCfF6fA7468124986B91bd" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa960d2bA7000d58773E7fa5754DeC3Bb40A069D5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1C95b093d6C236d3EF7c796fE33f9CC6b8606714" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2AF5D2aD76741191D15Dfe7bF6aC92d4Bd912Ca3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x744c9c36D1Cc3268a4b9b2e28c60B1752C85E97d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAcCe88F5A63A5e65DB9AA7303720bE16b556E751" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x91e64F39C1FE14492e8FDf5A8B0f305BD218C8A1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x82f4dED9Cec9B5750FBFf5C2185AEe35AfC16587" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8762db106B2c2A0bccB3A80d1Ed41273552616E8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE02784175C3BE0DEa7CC0F284041b64503639E66" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBA14b245d449965BdBeB630ebe135B569474F5b1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6aB4A7d75B0A42B6Bc83E852daB9E121F9C610Aa" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe431a4c5DB8B73c773e06cf2587dA1EB53c41373" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0C6144c16af288948C8fdB37fD8fEc94bfF3d1d9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA806B3FEd6891136940cF81c4085661500aa2709" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x915044526758533dfB918ecEb6e44bc21632060D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7051620d11042c4335069AaA4f10Cd3B4290C681" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x25200235cA7113C2541E70dE737c41f5e9AcD1F6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB9843e5dE0f37d1e22C8075e5814e13565FE7C22" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFF0E5e014cf97e0615cb50F6f39Da6388E2FaE6E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x69d2779533a4D2c780639713558B2cC98c46A9b7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa8EdA9D4Aee0eb882F8752C6bA7e16d9233C9Ad2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd111BCb8C30a600c12F4AF8314235F628EA2Cb3C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x454B9f249bC1492eE995793Bbc3e57b830F1A5e9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x78F5bBC74fb9137A75D85f3C9C3c599Be49f0A56" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd2Bfec3f80b7D966D7657A2ecC5982EE2f49336A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8aD6739649f1fbF079882C14D27862d5c2206660" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdE1289e68aD9e65Ccf50D800C0CEC2D514B80A40" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x94Cb815F4b601B00b363B3177B4D8ed8e0EB7cF2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3810A4Ddf41E586Fa0dbA1463A7951B748cEcFca" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x182A603541a4483c308475147D621bbB4E2587c6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3EB55D5B22Ee0f9B03D59B4994C5AE7fe811bE92" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDe7D85157d9714EADf595045CC12Ca4A5f3E2aDb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1519AFf03b3E23722511D2576c769A77Baf09580" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDf59C8BA19B4d1437d80836b45F1319D9A429EED" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x971d048E737619884f2df75e31c7Eb6412392328" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1B80eeeaDcC590f305945BCc258cFa770Bbe1890" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xae353DaEed8DCc7a9a12027F7e070c0A50B7b6A4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4954Db6391F4feB5468b6B943D4935353596aEC9" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "BTCB-1DE" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "RAVEN-F66" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa249DE6948022783765Fee4850d7b85E43118FCc" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "HNST-3C9" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "COS-2E4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB879DA8b24c9b8685dE8526cF492E954f165D74b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBA50933C268F567BDC86E1aC131BE072C6B0b71a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x11eeF04c884E24d9B7B4760e7476D06ddF797f36" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x01E45B8D0c51f05F17385DD3416fE3aA5BFd89aC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6E605c269E0C92e70BEeB85486f1fC550f9380BD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x174BfA6600Bf90C885c7c01C7031389ed1461Ab9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xEb6985ACD6d0cbff60B88032b0B29Ac1d9D66A1B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1BeEF31946fbbb40B877a72E4ae04a8D1A5Cee06" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3166C570935a7D8554c8f4eA792ff965D2EFe1f2" + }, + { + "coin": 195, + "type": "token", + "currency": "USD", + "token_id": "TVQ6jYV5yTtRsKcD8aRc1a4Kei4V45ixLn" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD46bA6D942050d489DBd938a2C909A5d5039A161" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x95a41fB80ca70306e9Ecf4e51ceA31bD18379C18" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x72955eCFf76E48F2C8AbCCe11d54e5734D6f3657" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x68D3AF29a900D21d092778A9D0aa4F73B1367141" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x186a33d4dBcd700086A26188DcB74E69bE463665" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1c48f86ae57291F7686349F12601910BD8D470bb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3506424F91fD33084466F402d5D97f05F8e3b4AF" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6393E822874728f8Afa7e1C9944E417D37CA5878" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x91cA1146073B0cc9f57A1Dde38a0CCB1ab2a3317" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4F22310C27eF39FEAA4A756027896DC382F0b5E2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB4272071eCAdd69d933AdcD19cA99fe80664fc08" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe0c6CE3e73029F201e5C0Bedb97F67572A93711C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4c1C4957D22D8F373aeD54d0853b090666F6F9De" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAaA89105dab822dBC9a6DE64A23d045D99D5Fd36" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x96c30D5499EF6eA96A9c221Bc18BC39D29c97F27" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "ERD-D06" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0db03B6CDe0B2d427C64a04FeAfd825938368f1F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x42BEdD647E387daBeC65A7dc3A3bAbCc68BB664d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF88951D7B676798705fd3a362ba5B1DBca2B233b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x940a2dB1B7008B6C776d4faaCa729d6d4A4AA551" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xff8Be4B22CeDC440591dcB1E641EB2a0dd9d25A5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA7fC5D2453E3F68aF0cc1B78bcFEe94A1B293650" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2467AA6B5A2351416fD4C3DeF8462d841feeecEC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7788D759F21F53533051A9AE657fA05A1E068fc6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x187D1018E8ef879BE4194d6eD7590987463eAD85" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x44E2ca91ceA1147f1B503e669f06CD11FB0C5490" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6020Da0F7c1857dBE4431Ec92A15cC318D933eAa" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe577e0B200d00eBdecbFc1cd3F7E8E04C70476BE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2D153f2aDCCbe9364F9e4eD5843308AbD0bF93dA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE6877ea9C28fBDeC631ffBc087956d0023A76bF2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x34D6A0F5C2f5D0082141fE73d93B9dd00ca7CE11" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7869c4A1a3f6F8684FBCC422a21aD7Abe3167834" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd31695a1d35E489252CE57b129FD4b1B05E6AcaC" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1FCdcE58959f536621d76f5b7FfB955baa5A672F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfc82bb4ba86045Af6F327323a46E80412b91b27d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x87210f1D3422BA75B6C40C63C78d79324daBcd55" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x36151737B45017234E9570Cf9a1cAc97138953C2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDB7Eab9bA6be88B869F738f6DEeBa96d49Fe13fd" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x07bf5F95851Ef2b2996F192569e406A6FeA2a95a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5EdC1a266E8b2c5E8086d373725dF0690af7e3Ea" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8Ab7404063Ec4DBcfd4598215992DC3F8EC853d7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xcFbf70e33d5163E25B0dad73955c1BD9E8cd8BA2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x420412E765BFa6d85aaaC94b4f7b708C89be2e2B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x225927F8fa71d16EE07968B8746364D1d9F839bD" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "CBIX-3C9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x79cdFa04e3c4EB58C4f49DAE78b322E5b0D38788" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "BAW-DFB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF6dBE88bA55f1793Ff0773c9B1275300f830914F" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "RUNE-B1A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd433138d12beB9929FF6fd583DC83663eea6Aaa5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x28ea81fac7b1719138cBf61267198155b433E00e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x09970aec766b6f3223aCA9111555E99DC50Ff13a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x386cABc0b14A507A4e024DEA15554342865B20DE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA110eeebc0751407bDCAeA4CD230F04A2b82a33a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC9a2C4868F0f96fAaa739b59934Dc9cB304112ec" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2E2E0a28f6585e895DD646a363BAE29B77B88a31" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x40AdFc7c23c22Cc06f94F199a4750D7196F46fbe" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD13c7342e1ef687C5ad21b27c2b65D772cAb5C8c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfc858154C0b2c4A3323046Fb505811F110EBdA57" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3B7f247f21BF3A07088C2D3423F64233d4B069F7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5e3845A1d78DB544613EdbE43Dc1Ea497266d3b8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x50D1c9771902476076eCFc8B2A83Ad6b9355a4c9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x85ca6710D0F1D511d130f6935eDDA88ACBD921bD" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "SHR-DB6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x03B155AF3F4459193A276395dD76e357BB472DA1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA829F97373069ee5d23175e4105dF8fD49238Be7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDF2705d4368Cd2EE3bbfF73594aE47244064dFfB" + }, + { + "coin": 195, + "type": "token", + "currency": "USD", + "token_id": "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x026e62dDEd1a6aD07D93D39f96b9eabd59665e0d" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x07597255910a51509CA469568B048F2597E72504" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1fd27F0CfC6f273b87A5E0F6fCf063422E7bCD6a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x35b08722AA26bE119c1608029CcbC976ac5C1082" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x746DdA2ea243400D5a63e0700F190aB79f06489e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xDe4C5a791913838027a2185709E98c5C6027EA63" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1f88B2eF9ea3B29C90F559e645fC8CC2dc6F5b27" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE5CAeF4Af8780E59Df925470b050Fb23C43CA68C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xeBF4CA5319F406602EEFf68da16261f1216011B5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4Eeea7B48b9C3ac8F70a9c932A8B1E8a5CB624c7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7a3d3c4f30c46F51b814BEe23D970A7c9b757a32" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x197E6bCa6BC2f488ec760a6Ce46B1399cd2954b0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xf6ABff616043C2dA572573dCC583B656297b30e7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x307d45Afbb7E84F82ef3D251A6bb0F00Edf632E4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6b4689E4514957699eDeB2Ee91C947F18E439806" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6CbEDEc4F1ac9D874987D2769596544E0d9161ab" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "CBM-4B2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6CE21e5f5383c95691d243879A86A6025E0870c0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x608f006B6813f97097372d0d31Fb0F11d1CA3E4e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x73C9275c3a2Dd84b5741fD59AEbF102C91Eb033F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD536bBd5414A8C2beEd82a63737B9327D2FA35a6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x01C0987E88F778DF6640787226bc96354E1a9766" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4442556a08a841227bEf04C67A7Ba7acf01b6Fc8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE66747a101bFF2dBA3697199DCcE5b743b454759" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2C36204a0712A2a50E54A62F7c4F01867e78cB53" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD91a6162F146EF85922d9A15eE6eB14A00344586" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0C6f5F7D555E7518f6841a79436BD2b1Eef03381" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x98b2dE885E916b598f65DeD2fDbb63187EAEf184" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8CE9137d39326AD0cD6491fb5CC0CbA0e089b6A9" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x525794473F7ab5715C81d06d10f52d11cC052804" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xFC29B6e626B67776675FfF55d5BC0452d042F434" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5b71BEE9D961b1B848f8485EEC8d8787f80217F5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5E7Ebea68ab05198F771d77a875480314f1d0aae" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6556D2EC4D96Da39CF75cbE50D58fae90079800a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdfbc9050F5B01DF53512DCC39B4f2B2BBaCD517A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa8262Eb913FccEa4C3f77fc95b8b4043B384cFbB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb5A73f5Fc8BbdbcE59bfD01CA8d35062e0dad801" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4129D3b7a6A2c5C997774077aC02bDafd1AF1d6a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x68350d30D9F58C81aaaA41929f1bfC52FFf4Ea49" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0c963A1B52Eb97C5e457c7D76696F8b95c3087eD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2C9023bBc572ff8dc1228c7858A280046Ea8C9E5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5E3002dff591C5e75Bb9DEdae268049742E6b13a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2730d6FdC86C95a74253BefFaA8306B40feDecbb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x12683Dc9eEc95a5F742D40206e73319E6b9d8A91" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1B073382E63411E3BcfFE90aC1B9A43feFa1Ec6F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5d285F735998F36631F678FF41fb56A10A4d0429" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x00fC270C9cc13e878Ab5363D00354bebF6f05C15" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC77b230F31b517F1ef362e59c173C2BE6540B5E8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7D29A64504629172a429e64183D6673b9dAcbFCe" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "MTXLT-286" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x593114f03A0A575aece9ED675e52Ed68D2172B8c" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "ECO-083" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x65cCD72c0813CE6f2703593B633202a0F3Ca6a0c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8D8129963291740dDDd917ab01af18c7aed4BA58" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbdbC2a5B32F3a5141ACd18C39883066E4daB9774" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2E68dfB3f50Ea302c88F8dB74096D57565D9970a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4E3Bddd468AbfC6C88bc25dAA5d894380CEd5bc8" + }, + { + "coin": 195, + "type": "token", + "currency": "USD", + "token_id": "TUL5yxRKeSWvceLZ3BSU5iNJcQmNxkWayh" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD2bb16cf38Ca086Cab5128D5c25DE9477eBD596B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x60715E436c37444E29772c0D26a98Ae1E8E1A989" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8E30ea2329D95802Fd804f4291220b0e2F579812" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x430bd07726423A54f6d82Ab0F578CE62A3b8054D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB9EefC4b0d472A44be93970254Df4f4016569d27" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x19C9872640eC38c2Cf36C0F04d1365Ef067869B3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfB559CE67Ff522ec0b9Ba7f5dC9dc7EF6c139803" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x63d958D765F5bd88efDbD8Afd32445393b24907f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaEaabb69dcB0FE926B1979f0B032FCd17FD7b2E0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xeb269732ab75A6fD61Ea60b06fE994cD32a83549" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb8c6ad2586bB71d518C2aaf510Efe91f82022F58" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x790bFaCaE71576107C068f494c8A6302aea640cb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa249F0E9A464b9685F66992f41e1012388e39e81" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2822f6D1B2f41F93f33d937bc7d84A8Dfa4f4C21" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x827D53c8170aF52625f414bde00326Fc8A085E86" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0C3eF32f802967DB75B9D49fE1e76620151cCB81" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x7DE2d123042994737105802D2abD0A10a7BdE276" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2E65E12b5f0fD1D58738c6F38dA7D57F5F183d1c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x301C755bA0fcA00B1923768Fffb3Df7f4E63aF31" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBA11D00c5f74255f56a5E366F4F77f5A186d7f55" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2396FBC0e2E3AE4B7206EbDb5706e2a5920349CB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x365542DF3c8c9d096C5F0dE24A0d8cf33C19C8fd" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe947b388fbE682784170B62F2Bd4665f9719a285" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4Fabb145d64652a948d72533023f6E7A623C7C53" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x60c87297A1fEaDC3C25993FfcadC54e99971e307" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xcD8544DefeDEc7c6b60b5a4232320365b1B21fCc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x12fD19DAC0Fab61bEd5e0F09091B470C452D4d61" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3277dd536471a3cBEB0c9486aCad494C95A31E73" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x998FFE1E43fAcffb941dc337dD0468d52bA5b48A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdeCF7Be29F8832E9C2Ddf0388c9778B8Ba76af43" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x45804880De22913dAFE09f4980848ECE6EcbAf78" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x278a83B64C3e3E1139f8E8A52D96360cA3c69A3D" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x93065b5C7Eb63333b8E57a73012D25f687895785" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8c4E7f814d40f8929F9112C5D09016F923d34472" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x00059AE69c1622A7542EdC15E8d17b060fE307b6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x31274db8b609Df99E5988ee527071643b5160Fc3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4CB10F4df4BF4F64D4797d00D468181EF731Be9A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF784682C82526e245F50975190EF0fff4E4fC077" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x70968FEAF13299d0dBf78f66860bAb9DbE3856bc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF6Bf74a97d78f2242376769EF1E79885Cf1F0C1c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdA4129919F964a3A526D3182Bb03E6449e5a8872" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x86149C67e57c749d0A12e6D6c2Bf1b616619BB29" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xAAAaaaaBA2ea3daAB0A6c05F1b962c78c9836d99" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdF574c24545E5FfEcb9a659c229253D4111d87e1" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xdB096cC19b8227E2115855c5B39Dcc247470013C" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "VOTE-FD4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x37F74e99794853777a10ea1dc08a64C86958F06a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8F9bfe5b6A5C3fEa8c64ad41a5Cf6f60Ec4aa47c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbDEC45952B5E234EdDC2981B43eeD360826D5087" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xA31B1767e09f842ECFd4bc471Fe44F830E3891AA" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1F3F677Ecc58F6A1F9e2CF410dF4776a8546b5DE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x58959E0C71080434f237bD42d07Cd84B74CeF438" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb7e77aEbBe0687d2EfF24Cc90c41A3b6eA74bdAB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x86FADb80d8D2cff3C3680819E4da99C10232Ba0F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6bC1F3A1ae56231DbB64d3E82E070857EAe86045" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x9556f8ee795D991fF371F547162D5efB2769425F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x37D6E7F287200C740012747d2A79295cAeD2DB35" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF39f19565B8D937EC30f1db5BD42F558D1E312A6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2fd61567c29E7ADB4Ca17e60E1f4a3Fcfe68aCb8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe0b9BcD54bF8A730EA5d3f1fFCe0885E911a502c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x166F1a7eCAe00bd43876A25B10a63C575e05c0e7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1d8cA7baf0895Da8afcf153657bE064b5092a274" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB48B7E5bF6563B3e0A85055821A83Deb8CFc12f6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBA8c0244FBDEB10f19f6738750dAeEDF7a5081eb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5e040aC72140F0617bC24aB7134c0C6eCae0e965" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "KAVA-10C" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x578B49C45961f98d8DF92854b53F1641AF0A5036" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x142aC3BD1C94898Be6e311b020b547A11dC03990" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5B322514FF727253292637D9054301600c2C81e8" + }, + { + "coin": 195, + "type": "token", + "currency": "USD", + "token_id": "1002413" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbACA8D824f471a6b20fdbac25E9e8943B9cD743B" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x322f4f6a48329690957a3BCBd1301516C2B83c1F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3A10B7a22AE98E0f53276923F19f99B259F61778" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD27D76A1bA55ce5C0291CCd04feBBe793D22ebF4" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5456BC77Dd275c45c3C15f0cF936b763cF57c3B5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x1412f6Aa5ADC77C620715BB2a020AA690B85F68A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6710CeE627Fa3A988200ffD5687cc1C814cEf0F6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xcb17cD357c7acD594717D899ecb9df540F633F27" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x41ad4093349C8A60DE591A3C37dcd184558EaAe3" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8c9E4CF756b9d01D791b95bc2D0913EF2Bf03784" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xd24DFf6117936B6ff97108CF26c1dD8865743d87" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2fe39f22EAC6d3c1C86DD9D143640EbB94609FCE" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5978708d6ccE1CC9640Eed47422D64c91BbD5171" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xfE4455fd433Ed3CA025ec7c43cb8686eD89826CD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xF70d160102cF7a22c1E432d6928a9d625Db91170" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2AA4a3E8bB72BE68a31c9c3C98CA7BeC723C6222" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0d16450D347c12C086d6C94c76c5Aaac35eA07E0" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6B175474E89094C44Da98b954EedeAC495271d0F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0Ba45A8b5d5575935B8158a88C631E9F9C95a2e5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3DB99ab08006aeFcC9600972eCA8C202396B4300" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xbf05571988dAaB22D33C28bbB13566eae9DeE626" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x037A54AaB062628C9Bbae1FDB1583c195585fe41" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE65ee7c03Bbb3C950Cfd4895c24989afA233EF01" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xE1bAD922F84b198A08292FB600319300ae32471b" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6096d2460CF5177E40B515223428DC005ad35123" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xD89040Ac9823B72F64d71f66Fa2DeAE7C8520671" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4D0425e47Ee2D16b94c036715dfcb52a0cebC4Dc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3be6e7bF2cD8E1a0A95597E72ca6D3709bBeFF76" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB8E2e2101eD11e9138803cd3e06e16dd19910647" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x40c6f861A08F97dfBC3C0931485bFf4921975a56" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x20b1A8a9cA1c7302b7f774266C491C7b11622779" + }, + { + "coin": 714, + "type": "token", + "currency": "USD", + "token_id": "TROY-9B8" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x082E13494f12EBB7206FBf67E22A6E1975A1A669" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6b9F1F092E0B10015a4391A80cD3E6B6cefD1728" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xed0849BF46CfB9845a2d900A0A4E593F2dD3673c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBbe761EA1447A20b75aA485b7BCad4837415d7D7" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x65Ac08c55F21d4A73CA1D429a17a6872b23bFd55" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4575f41308EC1483f3d399aa9a2826d74Da13Deb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xe541b34f73a4789a033A962ad43655221B4E516e" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8b847669B2e5dD5101736e41dA8Ec38653065aeb" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4c14114C107D6374EC31981F5F6Cc27A13e22F9a" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4eE6E959d460dE47DfE58E5E6fBAB330Ce8484b6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa105C740BC012A43a342Ab4A0Ef40143452C8E89" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x83cAEECace9Ec5c322c93743B2B370ED58951F5c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8F8e787989BC652eeA01A6C88a19f0f379BDF4FD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x3C7b464376DB7C9927930cf50EEfDEA2EFF3A66A" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x786001c9c5CA6E502dEB8a8a72480d2147891f32" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x843131b15F2Ec5BeA850aC5164D2e4a3749ad87f" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x4fAC0ccD9e2ed9fD462D42B66Fb81bA9A1f6F25E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB351dA6ffEbd5DddD1dA037929FCf334d6B4A8D5" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6368e1E18c4C419DDFC608A0BEd1ccb87b9250fc" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x6E5a43DB10b04701385A34afb670E404bC7Ea597" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x73Cee8348b9bDd48c64E13452b8a6fbc81630573" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xB4a677B0E363c3815d46326954a4E4d2B1ACe357" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC8C424B91D8ce0137bAB4B832B7F7D154156BA6c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x13339fD07934CD674269726EdF3B5ccEE9DD93de" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xaDA62f7CCd6af6cAcff04ACCBC4f56f3D4FFd4Ef" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa98F029bb4e74C12FB07BBc25854E5a04F7acF4c" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x063b98a414EAA1D4a5D4fC235a22db1427199024" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x0e8e874bb30a5F254f5144EaAE4564C7F73fAbeD" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x94eea9a484F0BaE03D19623cfe389E2CBA56B72F" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x208bbb6bCEA22ef2011789331405347394EbAa51" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xBdBB0Ee6144544eC814d417B0ad41f16fC8B858E" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xb5a4ac5b04E777230bA3381195EfF6a60c3934F2" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xC538143202f3b11382D8606aae90a96b042a19DB" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x8207c1FfC5B6804F6024322CcF34F29c3541Ae26" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0xa90C43e0d6c92b8e6171a829beB38Be28a0Ad073" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x5a4B14aea23A605aBc463f04a6B8Aaf52Dd3e7C6" + }, + { + "coin": 60, + "type": "token", + "currency": "USD", + "token_id": "0x68eb95Dc9934E19B86687A10DF8e364423240E94" + }, + { + "coin": 60, + "type": "token", + "currency": "BRL", + "token_id": "0x016ee7373248a80BDe1fD6bAA001311d233b3CFa" + }, + { + "coin": 714, + "type": "token", + "currency": "BRL", + "token_id": "WRX-ED1" + }, + { + "coin": 60, + "type": "token", + "currency": "BRL", + "token_id": "0x4922a015c4407F87432B179bb209e125432E4a2A" + }, + { + "coin": 60, + "type": "token", + "currency": "BRL", + "token_id": "0x7BD6a4E7DB3A34c485A8DD02b30B6565e3bbC633" + }, + { + "coin": 60, + "type": "token", + "currency": "EUR", + "token_id": "0xeF65887a05415bF6316204b5ffB350d4d1a19BBA" + }, + { + "coin": 60, + "type": "token", + "currency": "EUR", + "token_id": "0x1fff4Dd33105054E853955C6d0dBa82859C01Cff" + } +] diff --git a/pkg/tests/postman/observer_data.json b/pkg/tests/postman/observer_data.json new file mode 100644 index 000000000..9c5394ee0 --- /dev/null +++ b/pkg/tests/postman/observer_data.json @@ -0,0 +1,72 @@ +[ + { + "subscriptions": { + "0": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "2": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "60": [ + "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + ], + "459": [ + "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + ], + "714": [ + "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" + ] + }, + "webhook": "http://localhost" + }, + { + "subscriptions": { + "0": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "2": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "60": [ + "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + ], + "459": [ + "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + ] + }, + "webhook": "http://localhost" + }, + { + "subscriptions": { + "0": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "2": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "60": [ + "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + ] + }, + "webhook": "http://localhost" + }, + { + "subscriptions": { + "0": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "2": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ] + }, + "webhook": "http://localhost" + }, + { + "subscriptions": { + "0": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ] + }, + "webhook": "http://localhost" + } +] \ No newline at end of file diff --git a/pkg/tests/postman/staking_data.json b/pkg/tests/postman/staking_data.json new file mode 100644 index 000000000..320e2a250 --- /dev/null +++ b/pkg/tests/postman/staking_data.json @@ -0,0 +1,27 @@ +[ + { + "handler": "tron", + "coin": 195, + "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" + }, + { + "handler": "tezos", + "coin": 1729, + "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" + }, + { + "handler": "kava", + "coin": 459, + "address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "handler": "cosmos", + "coin": 118, + "address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "handler": "iotex", + "coin": 304, + "address": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" + } +] diff --git a/pkg/tests/postman/token_data.json b/pkg/tests/postman/token_data.json new file mode 100644 index 000000000..da7a2870f --- /dev/null +++ b/pkg/tests/postman/token_data.json @@ -0,0 +1,38 @@ +[ + { + "handler": "tron", + "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" + }, + { + "handler": "thundertoken", + "address": "0x0b230def08139f18a86536d9cfa150f04435414c" + }, + { + "handler": "tomochain", + "address": "0x8b353021189375591723e7384262f45709a3c3dc" + }, + { + "handler": "callisto", + "address": "0xc3d5b69f65027ddf48f894e6e90121293a2f6615" + }, + { + "handler": "gochain", + "address": "0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628" + }, + { + "handler": "poa", + "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + }, + { + "handler": "ethereum", + "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + }, + { + "handler": "binance", + "address": "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" + }, + { + "handler": "classic", + "address": "0xa12105efa0663147bddee178f6a741ac15676b79" + } +] \ No newline at end of file diff --git a/pkg/tests/postman/transaction_data.json b/pkg/tests/postman/transaction_data.json new file mode 100644 index 000000000..c5c55909b --- /dev/null +++ b/pkg/tests/postman/transaction_data.json @@ -0,0 +1,234 @@ +[ + { + "handler": "harmony", + "address": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv" + }, + { + "handler": "nano", + "address": "nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z" + }, + { + "handler": "algorand", + "address": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U" + }, + { + "handler": "kusama", + "address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK" + }, + { + "handler": "kava", + "address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "handler": "zilliqa", + "address": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z" + }, + { + "handler": "tomochain", + "address": "0x17e4c16605e32adead5fa371bf6117df34ca0200" + }, + { + "handler": "ethereum", + "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + }, + { + "handler": "classic", + "address": "0x7d2d0e153026fb428b885d86de50768d4cfeac37" + }, + { + "handler": "poa", + "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + }, + { + "handler": "thundertoken", + "address": "0x0b230def08139f18a86536d9cfa150f04435414c" + }, + { + "handler": "callisto", + "address": "0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" + }, + { + "handler": "gochain", + "address": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" + }, + { + "handler": "theta", + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f" + }, + { + "handler": "binance", + "address": "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" + }, + { + "handler": "tezos", + "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" + }, + { + "handler": "tron", + "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" + }, + { + "handler": "vechain", + "address": "0xB5e883349e68aB59307d1604555AC890fAC47128" + }, + { + "handler": "ripple", + "address": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + }, + { + "handler": "cosmos", + "address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "handler": "iotex", + "address": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" + }, + { + "handler": "icon", + "address": "hxee691e7bccc4eb11fee922896e9f51490e62b12e" + }, + { + "handler": "stellar", + "address": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" + }, + { + "handler": "nimiq", + "address": "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07" + }, + { + "handler": "nebulas", + "address": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a" + }, + { + "handler": "aeternity", + "address": "ak_wTPFpksUJFjjntonTvwK4LJvDw11DPma7kZBneKbumb8yPeFq" + }, + { + "handler": "aion", + "address": "0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed" + }, + { + "handler": "kin", + "address": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH" + }, + { + "handler": "ontology", + "address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7" + }, + { + "handler": "waves", + "address": "3P7wz6TXienpw3BHe8eHUEuZWb6WE58kgnQ" + }, + { + "handler": "digibyte", + "address": "address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" + }, + { + "handler": "digibyte", + "address": "xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow" + }, + { + "handler": "doge", + "address": "address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + }, + { + "handler": "doge", + "address": "xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN" + }, + { + "handler": "decred", + "address": "address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + }, + { + "handler": "decred", + "address": "xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN" + }, + { + "handler": "zelcash", + "address": "address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" + }, + { + "handler": "zelcash", + "address": "xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf" + }, + { + "handler": "zcoin", + "address": "address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + }, + { + "handler": "zcoin", + "address": "xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK" + }, + { + "handler": "zcash", + "address": "address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" + }, + { + "handler": "zcash", + "address": "xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS" + }, + { + "handler": "bitcoin", + "address": "address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + }, + { + "handler": "bitcoin", + "address": "xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC" + }, + { + "handler": "bitcoincash", + "address": "address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + }, + { + "handler": "bitcoincash", + "address": "xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX" + }, + { + "handler": "ravencoin", + "address": "address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" + }, + { + "handler": "ravencoin", + "address": "xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B" + }, + { + "handler": "viacoin", + "address": "address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" + }, + { + "handler": "viacoin", + "address": "xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK" + }, + { + "handler": "litecoin", + "address": "address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + }, + { + "handler": "litecoin", + "address": "xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu" + }, + { + "handler": "qtum", + "address": "address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + }, + { + "handler": "qtum", + "address": "xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd" + }, + { + "handler": "groestlcoin", + "address": "address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" + }, + { + "handler": "groestlcoin", + "address": "xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf" + }, + { + "handler": "dash", + "address": "address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" + }, + { + "handler": "dash", + "address": "xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD" + } +] From 5af26ddceb602c26e837bef342e9e2184f832bb5 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 12 Feb 2020 14:24:09 -0300 Subject: [PATCH 104/506] Update postman collection --- pkg/tests/postman/Blockatlas.postman_collection.json | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pkg/tests/postman/Blockatlas.postman_collection.json b/pkg/tests/postman/Blockatlas.postman_collection.json index 7fe265fb7..ad9a8fea8 100644 --- a/pkg/tests/postman/Blockatlas.postman_collection.json +++ b/pkg/tests/postman/Blockatlas.postman_collection.json @@ -1901,9 +1901,7 @@ "});", "", "pm.test(\"schema is valid\", function() {", - " if (pm.response.status == 200) {", - " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", - " }", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", "});", "" ], @@ -2573,25 +2571,25 @@ ], "variable": [ { - "id": "4b90aa4f-57c6-4668-9b31-b08213789c1f", + "id": "7e392582-2f75-48a2-a096-ef338490e7f8", "key": "host", "value": "http://localhost:8420", "type": "string" }, { - "id": "2f57fde6-5c78-4d34-92a6-ff78c7cb5562", + "id": "39dad5f8-9727-4dda-9f27-b4e29dd0ff18", "key": "observer_auth", "value": "test", "type": "string" }, { - "id": "2aefe467-def3-4034-be71-bb737861881e", + "id": "edc48bc9-0c39-46a1-809a-c6d71874a958", "key": "market_auth", "value": "", "type": "string" }, { - "id": "53a56c0a-2672-4f9c-aab4-b0992cf5a2c8", + "id": "2ee77821-80ac-470a-9293-78b361ef27c7", "key": "platform_auth", "value": "", "type": "string" From 53ba2824b0fdbe5cdecfcd707dbbf6387e0efb3a Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 12 Feb 2020 16:47:25 -0300 Subject: [PATCH 105/506] Limit transaction history to 25 objects (#820) * Limit transactions to 25 * Add verification before limit * Remove unused code * Use Itoa instead FormatInt --- api/handlers.go | 3 +++ platform/bitcoin/client.go | 6 +++--- platform/icon/client.go | 2 +- platform/iotex/client.go | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/api/handlers.go b/api/handlers.go index a33f25830..c4780d62c 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -104,6 +104,9 @@ func makeTxRoute(router gin.IRouter, api blockatlas.Platform, path string) { AddTx: page = append(page, tx) } + if len(page) > blockatlas.TxPerPage { + page = page[0:blockatlas.TxPerPage] + } page.Sort() ginutils.RenderSuccess(c, &page) }) diff --git a/platform/bitcoin/client.go b/platform/bitcoin/client.go index 4a9dae795..0e19ab85d 100644 --- a/platform/bitcoin/client.go +++ b/platform/bitcoin/client.go @@ -15,7 +15,7 @@ func (c *Client) GetTransactions(address string) (transactions TransactionsList, path := fmt.Sprintf("address/%s", address) err = c.Get(&transactions, path, url.Values{ "details": {"txs"}, - "pageSize": {strconv.FormatInt(blockatlas.TxPerPage*4, 10)}, + "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, }) return transactions, err } @@ -23,7 +23,7 @@ func (c *Client) GetTransactions(address string) (transactions TransactionsList, func (c *Client) GetTransactionsByXpub(xpub string) (transactions TransactionsList, err error) { path := fmt.Sprintf("v2/xpub/%s", xpub) args := url.Values{ - "pageSize": {strconv.FormatInt(blockatlas.TxPerPage*4, 10)}, + "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, "details": {"txs"}, "tokens": {"derived"}, } @@ -34,7 +34,7 @@ func (c *Client) GetTransactionsByXpub(xpub string) (transactions TransactionsLi func (c *Client) GetAddressesFromXpub(xpub string) (tokens []Token, err error) { path := fmt.Sprintf("v2/xpub/%s", xpub) args := url.Values{ - "pageSize": {strconv.FormatInt(blockatlas.TxPerPage*4, 10)}, + "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, "details": {"txs"}, "tokens": {"derived"}, } diff --git a/platform/icon/client.go b/platform/icon/client.go index e94103f23..2e296a2de 100644 --- a/platform/icon/client.go +++ b/platform/icon/client.go @@ -13,7 +13,7 @@ type Client struct { func (c *Client) GetAddressTransactions(address string) ([]Tx, error) { query := url.Values{ "address": {address}, - "count": {strconv.FormatInt(blockatlas.TxPerPage, 10)}, + "count": {strconv.Itoa(blockatlas.TxPerPage)}, } var res Response err := c.Get(&res, "address/txList", query) diff --git a/platform/iotex/client.go b/platform/iotex/client.go index fe00476e7..c06b337df 100644 --- a/platform/iotex/client.go +++ b/platform/iotex/client.go @@ -40,7 +40,7 @@ func (c *Client) GetTxsOfAddress(address string, start int64) (*Response, error) var response Response err := c.Get(&response, "actions/addr/"+address, url.Values{ "start": {strconv.FormatInt(start, 10)}, - "count": {strconv.FormatInt(blockatlas.TxPerPage, 10)}, + "count": {strconv.Itoa(blockatlas.TxPerPage)}, }) if err != nil { From a776b34fffbda5116d0292987321462e13b57c0b Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 12 Feb 2020 20:36:11 -0300 Subject: [PATCH 106/506] Remove useless TODO message --- platform/ethereum/collection.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/platform/ethereum/collection.go b/platform/ethereum/collection.go index b28a94701..0fedd89ba 100644 --- a/platform/ethereum/collection.go +++ b/platform/ethereum/collection.go @@ -107,7 +107,6 @@ func OldNormalizeCollection(c Collection, coinIndex uint, owner string) blockatl //TODO: remove once most of the clients will be updated (deadline: March 17th) func OldNormalizeCollectible(c *Collection, a Collectible, coinIndex uint) blockatlas.Collectible { - // TODO: fix unprotected code address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") collectionID := address @@ -204,7 +203,6 @@ func NormalizeCollectiblePage(c *Collection, srcPage []Collectible, coinIndex ui } func NormalizeCollectible(c *Collection, a Collectible, coinIndex uint) blockatlas.Collectible { - // TODO: fix unprotected code address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") externalLink := blockatlas.GetValidParameter(a.ExternalLink, a.AssetContract.ExternalLink) From 5aeaf23de317a20c77d73c5b7ec2562c8ae9b2fb Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 12 Feb 2020 21:15:17 -0300 Subject: [PATCH 107/506] Remove unused code for functional tests --- pkg/tests/functional/http.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pkg/tests/functional/http.go b/pkg/tests/functional/http.go index b3945cd94..a00cebe77 100644 --- a/pkg/tests/functional/http.go +++ b/pkg/tests/functional/http.go @@ -15,9 +15,6 @@ import ( const ( baseUrl = "http://localhost%s" - schema = `{ - "docs": "array" - }` ) type Client struct { @@ -50,14 +47,12 @@ func (c *Client) testGet(route string, query string) { request.WithQueryString(query) response := request.Expect() - //TODO create a logic to validate schemas if response == nil || response.Raw() == nil { logger.Error("Invalid response", logger.Params{"response": response, "route": route, "query": query}) } if response.Raw().StatusCode != http.StatusOK { logger.Error("Invalid status code", logger.Params{"code": response.Raw().Status, "route": route, "query": query}) } - //response.JSON().Schema(schema) response.Status(http.StatusOK) } From 304ccdec974313ec8616f1359533f4885a2222b1 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 12 Feb 2020 21:39:22 -0300 Subject: [PATCH 108/506] Remove sensitive info (#844) --- pkg/blockatlas/client.go | 17 +++++++++-------- pkg/storage/redis/hmap.go | 2 +- pkg/storage/redis/redis.go | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go index 3c01f1b81..19dfaab82 100644 --- a/pkg/blockatlas/client.go +++ b/pkg/blockatlas/client.go @@ -48,7 +48,7 @@ func (r *Request) Get(result interface{}, path string, query url.Values) error { queryStr = query.Encode() } uri := strings.Join([]string{r.GetBase(path), queryStr}, "?") - return r.Execute("GET", uri, nil, result) + return r.Execute("GET", uri, nil, result, errors.Params{"path": path}) } func (r *Request) Post(result interface{}, path string, body interface{}) error { @@ -57,14 +57,15 @@ func (r *Request) Post(result interface{}, path string, body interface{}) error return err } uri := r.GetBase(path) - return r.Execute("POST", uri, buf, result) + return r.Execute("POST", uri, buf, result, errors.Params{"path": path}) } -func (r *Request) Execute(method string, url string, body io.Reader, result interface{}) error { +func (r *Request) Execute(method string, url string, body io.Reader, result interface{}, params errors.Params) error { + params["method"] = method start := time.Now() req, err := http.NewRequest(method, url, body) if err != nil { - return errors.E(err, errors.TypePlatformRequest, errors.Params{"url": url, "method": method}) + return errors.E(err, errors.TypePlatformRequest, params) } for key, value := range r.Headers { @@ -73,22 +74,22 @@ func (r *Request) Execute(method string, url string, body io.Reader, result inte res, err := r.HttpClient.Do(req) if err != nil { - return errors.E(err, errors.TypePlatformRequest, errors.Params{"url": url, "method": method}) + return errors.E(err, errors.TypePlatformRequest, params) } go metrics.GetMetrics(res.Status, url, method, start) err = r.ErrorHandler(res, url) if err != nil { - return errors.E(err, errors.TypePlatformError, errors.Params{"url": url, "method": method}) + return errors.E(err, errors.TypePlatformError, params) } defer res.Body.Close() b, err := ioutil.ReadAll(res.Body) if err != nil { - return errors.E(err, errors.TypePlatformUnmarshal, errors.Params{"url": url, "method": method}) + return errors.E(err, errors.TypePlatformUnmarshal, params) } err = json.Unmarshal(b, result) if err != nil { - return errors.E(err, errors.TypePlatformUnmarshal, errors.Params{"url": url, "method": method}) + return errors.E(err, errors.TypePlatformUnmarshal, params) } return err } diff --git a/pkg/storage/redis/hmap.go b/pkg/storage/redis/hmap.go index ee2a0b000..a5c469132 100644 --- a/pkg/storage/redis/hmap.go +++ b/pkg/storage/redis/hmap.go @@ -33,7 +33,7 @@ func (db *Redis) GetHMValue(entity, key string, value interface{}) error { func (db *Redis) AddHM(entity, key string, value interface{}) error { j, err := json.Marshal(value) if err != nil { - return errors.E(err, errors.Params{"value": value}) + return errors.E(err, errors.Params{"key": key}) } cmd := db.client.HMSet(entity, map[string]interface{}{key: j}) if cmd.Err() != nil { diff --git a/pkg/storage/redis/redis.go b/pkg/storage/redis/redis.go index 61d51b6c1..979ae2a23 100644 --- a/pkg/storage/redis/redis.go +++ b/pkg/storage/redis/redis.go @@ -39,7 +39,7 @@ func (db *Redis) GetValue(key string, value interface{}) error { func (db *Redis) Add(key string, value interface{}) error { j, err := json.Marshal(value) if err != nil { - return errors.E(err, errors.Params{"value": value}) + return errors.E(err, errors.Params{"key": key}) } cmd := db.client.Set(key, j, 0) if cmd.Err() != nil { From ed99ab3f6ac3f34a06c25cd6344ea2ce842ded38 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 12 Feb 2020 22:14:56 -0300 Subject: [PATCH 109/506] Add support to review apps (#846) --- app.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app.json b/app.json index af57abd51..1cf7219a5 100644 --- a/app.json +++ b/app.json @@ -9,6 +9,18 @@ "repository": "https://github.com/trustwallet/blockatlas", "logo": "https://avatars0.githubusercontent.com/u/32179889", "success_url": "/v1/", + "buildpacks": [ + { + "url": "heroku/go" + } + ], + "environments": { + "review": { + "addons": [ + "logentries:le_tryit" + ] + } + }, "formation": { "web": { "quantity": 1, @@ -17,6 +29,9 @@ "observer": { "quantity": 1, "size": "Free" - } + }, + "scripts": { + }, + "stack": "heroku-18" } } From eae5eb5bfab52d31268cd13a10e3e505e9aed28c Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 13 Feb 2020 17:55:32 -0300 Subject: [PATCH 110/506] Fix NIMIQ date parser --- platform/nimiq/api.go | 17 +++++++++-------- platform/nimiq/client.go | 4 ++-- platform/nimiq/model.go | 3 ++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/platform/nimiq/api.go b/platform/nimiq/api.go index 2d8ed6208..021e9c01d 100644 --- a/platform/nimiq/api.go +++ b/platform/nimiq/api.go @@ -24,28 +24,29 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { } func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - if srcBlock, err := p.client.GetBlockByNumber(num); err == nil { - block := NormalizeBlock(srcBlock) - return &block, nil - } else { + srcBlock, err := p.client.GetBlockByNumber(num) + if err != nil { return nil, err } + block := NormalizeBlock(srcBlock) + return &block, nil } func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - if srcTxs, err := p.client.GetTxsOfAddress(address, blockatlas.TxPerPage); err == nil { - return NormalizeTxs(srcTxs), err - } else { + srcTxs, err := p.client.GetTxsOfAddress(address) + if err != nil { return nil, err } + return NormalizeTxs(srcTxs), err } // NormalizeTx converts a Nimiq transaction into the generic model func NormalizeTx(srcTx *Tx) blockatlas.Tx { + date, _ := srcTx.Timestamp.Int64() return blockatlas.Tx{ ID: srcTx.Hash, Coin: coin.NIM, - Date: srcTx.Timestamp, + Date: date, From: srcTx.FromAddress, To: srcTx.ToAddress, Fee: srcTx.Fee, diff --git a/platform/nimiq/client.go b/platform/nimiq/client.go index c98c0a9da..7a292dac5 100644 --- a/platform/nimiq/client.go +++ b/platform/nimiq/client.go @@ -9,8 +9,8 @@ type Client struct { blockatlas.Request } -func (c *Client) GetTxsOfAddress(address string, count int) (tx []Tx, err error) { - err = c.RpcCall(&tx, "getTransactionsByAddress", []string{address, strconv.Itoa(count)}) +func (c *Client) GetTxsOfAddress(address string) (tx []Tx, err error) { + err = c.RpcCall(&tx, "getTransactionsByAddress", []string{address, strconv.Itoa(blockatlas.TxPerPage)}) return } diff --git a/platform/nimiq/model.go b/platform/nimiq/model.go index fcb3b8a88..6c8bc1de7 100644 --- a/platform/nimiq/model.go +++ b/platform/nimiq/model.go @@ -1,6 +1,7 @@ package nimiq import ( + "encoding/json" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -8,7 +9,7 @@ type Tx struct { Hash string `json:"hash"` BlockHash string `json:"blockHash"` BlockNumber uint64 `json:"blockNumber"` - Timestamp int64 `json:"timestamp"` + Timestamp json.Number `json:"timestamp"` Confirmations int `json:"confirmations"` TxIndex int `json:"transactionIndex"` FromAddress string `json:"fromAddress"` From 6bfee791e6996a31f6bfea9f5286dba0d88417a9 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 13 Feb 2020 17:59:38 -0300 Subject: [PATCH 111/506] Remove integrations tests for Fio testnet --- pkg/tests/integration/domains/domains.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/tests/integration/domains/domains.go b/pkg/tests/integration/domains/domains.go index 7dcb3f1c8..97cbe7ab4 100644 --- a/pkg/tests/integration/domains/domains.go +++ b/pkg/tests/integration/domains/domains.go @@ -71,15 +71,15 @@ func TestDomains(t *testing.T) { }, false, }, - { - "test @fiotestnet domain", - "adam@fiotestnet", - []uint64{coin.ETH}, - []blockatlas.Resolved{ - {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, - }, - false, - }, + //{ + // "test @fiotestnet domain", + // "adam@fiotestnet", + // []uint64{coin.ETH}, + // []blockatlas.Resolved{ + // {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, + // }, + // false, + //}, { "test batch .crypto domains", "dpantani.crypto", From 63af95eb1777e5263f7e3974550898ef704c14ba Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 13 Feb 2020 18:03:29 -0300 Subject: [PATCH 112/506] Remove functional tests for Fio testnet for now --- pkg/tests/functional/testdata/query_fixtures.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/tests/functional/testdata/query_fixtures.json b/pkg/tests/functional/testdata/query_fixtures.json index 6cf012ee2..0e73c21d2 100644 --- a/pkg/tests/functional/testdata/query_fixtures.json +++ b/pkg/tests/functional/testdata/query_fixtures.json @@ -11,8 +11,7 @@ "name=vitalik.luxe&coins=60", "name=ourxyzwallet.xyz&coins=60", "name=btc.zil&coins=313", - "name=btc.crypto&coins=313", - "name=adam@fiotestnet&coins=60" + "name=btc.crypto&coins=313" ], "/v1/market/charts": [ "currency=USD&time_start=1574483028&coin=60&token=0xdAC17F958D2ee523a2206206994597C13D831ec7", From c6640143d8fef2ef76b7cd5946fdecc8a173c361 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Fri, 14 Feb 2020 00:53:42 +0100 Subject: [PATCH 113/506] FIO name lookup: add new chain_code parameter to get_pub_address call (FIO testnet v0.8 -> v0.9). (#853) --- platform/fio/client.go | 6 +++--- platform/fio/model.go | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/fio/client.go b/platform/fio/client.go index cbd2551a0..56a68c055 100644 --- a/platform/fio/client.go +++ b/platform/fio/client.go @@ -12,12 +12,12 @@ type Client struct { func (c *Client) lookupPubAddress(name string, coinSymbol string) (address string, error error) { var res GetPubAddressResponse - err := c.Post(&res, "get_pub_address", GetPubAddressRequest{FioAddress: name, TokenCode: coinSymbol}) + err := c.Post(&res, "get_pub_address", GetPubAddressRequest{FioAddress: name, TokenCode: coinSymbol, ChainCode: coinSymbol}) if err != nil { - return "", errors.E(err, "Error lokking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": err.Error()}) + return "", errors.E(err, "Error looking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": err.Error()}) } if res.Message != "" { - return "", errors.E("Error lokking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": res.Message}) + return "", errors.E("Error looking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": res.Message}) } return res.PublicAddress, nil } diff --git a/platform/fio/model.go b/platform/fio/model.go index 0c506da79..404a05b3f 100644 --- a/platform/fio/model.go +++ b/platform/fio/model.go @@ -4,6 +4,7 @@ package fio type GetPubAddressRequest struct { FioAddress string `json:"fio_address"` TokenCode string `json:"token_code"` + ChainCode string `json:"chain_code"` } // GetPubAddressResponse response struct for get_pub_address From f3bb58a37d3391f354b79817a385863a5e679bc0 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 13 Feb 2020 20:56:36 -0300 Subject: [PATCH 114/506] Put back the fio test for integration and functional --- .../functional/testdata/query_fixtures.json | 3 ++- pkg/tests/integration/domains/domains.go | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pkg/tests/functional/testdata/query_fixtures.json b/pkg/tests/functional/testdata/query_fixtures.json index 0e73c21d2..6cf012ee2 100644 --- a/pkg/tests/functional/testdata/query_fixtures.json +++ b/pkg/tests/functional/testdata/query_fixtures.json @@ -11,7 +11,8 @@ "name=vitalik.luxe&coins=60", "name=ourxyzwallet.xyz&coins=60", "name=btc.zil&coins=313", - "name=btc.crypto&coins=313" + "name=btc.crypto&coins=313", + "name=adam@fiotestnet&coins=60" ], "/v1/market/charts": [ "currency=USD&time_start=1574483028&coin=60&token=0xdAC17F958D2ee523a2206206994597C13D831ec7", diff --git a/pkg/tests/integration/domains/domains.go b/pkg/tests/integration/domains/domains.go index 97cbe7ab4..7dcb3f1c8 100644 --- a/pkg/tests/integration/domains/domains.go +++ b/pkg/tests/integration/domains/domains.go @@ -71,15 +71,15 @@ func TestDomains(t *testing.T) { }, false, }, - //{ - // "test @fiotestnet domain", - // "adam@fiotestnet", - // []uint64{coin.ETH}, - // []blockatlas.Resolved{ - // {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, - // }, - // false, - //}, + { + "test @fiotestnet domain", + "adam@fiotestnet", + []uint64{coin.ETH}, + []blockatlas.Resolved{ + {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, + }, + false, + }, { "test batch .crypto domains", "dpantani.crypto", From 4038744d0e3c9721428ba63e76e2d4920ca89bd6 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 13 Feb 2020 21:04:28 -0300 Subject: [PATCH 115/506] Set minimum amount for cosmos staking (#851) * Set minimum amount for cosmos * Fix unit tests --- platform/cosmos/stake.go | 13 +++++++++---- platform/cosmos/stake_test.go | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index e5943ab81..fe919f000 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -10,6 +10,11 @@ import ( "time" ) +const ( + lockTime = 1814400 + minimumAmount = "1" +) + func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { results := make(blockatlas.ValidatorPage, 0) validators, err := p.client.GetValidators() @@ -42,8 +47,8 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { Reward: blockatlas.StakingReward{ Annual: p.GetMaxAPR(), }, - MinimumAmount: blockatlas.Amount("0"), - LockTime: 1814400, + MinimumAmount: minimumAmount, + LockTime: lockTime, Type: blockatlas.DelegationTypeDelegate, } } @@ -151,8 +156,8 @@ func normalizeValidator(v Validator, p Pool, inflation float64) (validator block ID: v.Address, Details: blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: reward}, - MinimumAmount: "0", - LockTime: 1814400, + MinimumAmount: minimumAmount, + LockTime: lockTime, Type: blockatlas.DelegationTypeDelegate, }, } diff --git a/platform/cosmos/stake_test.go b/platform/cosmos/stake_test.go index 66ba606b0..20af2f9b0 100644 --- a/platform/cosmos/stake_test.go +++ b/platform/cosmos/stake_test.go @@ -75,8 +75,8 @@ func TestNormalizeValidator(t *testing.T) { ID: v.Address, Details: blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: 462.6619201898575}, - LockTime: 1814400, - MinimumAmount: "0", + LockTime: lockTime, + MinimumAmount: minimumAmount, Type: blockatlas.DelegationTypeDelegate, }, } @@ -102,8 +102,8 @@ var validator1 = blockatlas.StakeValidator{ Reward: blockatlas.StakingReward{ Annual: 9.259735525366604, }, - LockTime: 1814400, - MinimumAmount: "0", + LockTime: lockTime, + MinimumAmount: minimumAmount, }, } From 5075e6d7e308399f700f1659e0d2c404acdcaa71 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 13 Feb 2020 22:43:41 -0300 Subject: [PATCH 116/506] Remove tests for FIO domain until we have new address --- .../functional/testdata/query_fixtures.json | 3 +-- pkg/tests/integration/domains/domains.go | 18 +++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pkg/tests/functional/testdata/query_fixtures.json b/pkg/tests/functional/testdata/query_fixtures.json index 6cf012ee2..0e73c21d2 100644 --- a/pkg/tests/functional/testdata/query_fixtures.json +++ b/pkg/tests/functional/testdata/query_fixtures.json @@ -11,8 +11,7 @@ "name=vitalik.luxe&coins=60", "name=ourxyzwallet.xyz&coins=60", "name=btc.zil&coins=313", - "name=btc.crypto&coins=313", - "name=adam@fiotestnet&coins=60" + "name=btc.crypto&coins=313" ], "/v1/market/charts": [ "currency=USD&time_start=1574483028&coin=60&token=0xdAC17F958D2ee523a2206206994597C13D831ec7", diff --git a/pkg/tests/integration/domains/domains.go b/pkg/tests/integration/domains/domains.go index 7dcb3f1c8..97cbe7ab4 100644 --- a/pkg/tests/integration/domains/domains.go +++ b/pkg/tests/integration/domains/domains.go @@ -71,15 +71,15 @@ func TestDomains(t *testing.T) { }, false, }, - { - "test @fiotestnet domain", - "adam@fiotestnet", - []uint64{coin.ETH}, - []blockatlas.Resolved{ - {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, - }, - false, - }, + //{ + // "test @fiotestnet domain", + // "adam@fiotestnet", + // []uint64{coin.ETH}, + // []blockatlas.Resolved{ + // {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, + // }, + // false, + //}, { "test batch .crypto domains", "dpantani.crypto", From 10458763430d3c55821179694dd3e2b4bd1761b9 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 13 Feb 2020 22:58:30 -0300 Subject: [PATCH 117/506] Split stake api handlers into stake.go (#855) --- api/delegations.go | 35 ---------------- api/handlers.go | 66 +----------------------------- api/stake.go | 100 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 100 deletions(-) delete mode 100644 api/delegations.go create mode 100644 api/stake.go diff --git a/api/delegations.go b/api/delegations.go deleted file mode 100644 index 18277b0c1..000000000 --- a/api/delegations.go +++ /dev/null @@ -1,35 +0,0 @@ -package api - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" -) - -func getDelegationResponse(p blockatlas.StakeAPI, address string) (blockatlas.DelegationResponse, error) { - delegations, err := p.GetDelegations(address) - if err != nil { - return blockatlas.DelegationResponse{ - StakingResponse: getStakingResponse(p), - }, errors.E("Unable to fetch delegations list", err) - } - balance, err := p.UndelegatedBalance(address) - if err != nil { - return blockatlas.DelegationResponse{ - StakingResponse: getStakingResponse(p), - }, errors.E("Unable to fetch undelegated balance", err) - } - return blockatlas.DelegationResponse{ - Balance: balance, - Delegations: delegations, - Address: address, - StakingResponse: getStakingResponse(p), - }, nil -} - -func getStakingResponse(p blockatlas.StakeAPI) blockatlas.StakingResponse { - c := p.Coin() - return blockatlas.StakingResponse{ - Coin: c.External(), - Details: p.GetDetails(), - } -} diff --git a/api/handlers.go b/api/handlers.go index c4780d62c..8937d82a0 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -1,19 +1,14 @@ package api import ( - "net/http" - "time" - "github.com/chenjiandongx/ginprom" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/pkg/ginutils/gincache" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/metrics" - services "github.com/trustwallet/blockatlas/services/assets" + "net/http" ) // @Summary Get Transactions @@ -112,65 +107,6 @@ func makeTxRoute(router gin.IRouter, api blockatlas.Platform, path string) { }) } -// @Summary Get Validators -// @ID validators -// @Description Get validators from the address -// @Accept json -// @Produce json -// @Tags platform,staking -// @Param coin path string true "the coin name" default(cosmos) -// @Success 200 {object} blockatlas.DocsResponse -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/{coin}/staking/validators [get] -func makeStakingValidatorsRoute(router gin.IRouter, api blockatlas.Platform) { - var stakingAPI blockatlas.StakeAPI - stakingAPI, _ = api.(blockatlas.StakeAPI) - - if stakingAPI == nil { - return - } - - router.GET("/staking/validators", gincache.CacheMiddleware(time.Hour, func(c *gin.Context) { - results, err := services.GetValidators(stakingAPI) - if err != nil { - logger.Error(err) - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: results}) - })) -} - -// @Summary Get Stake Delegations -// @ID delegations -// @Description Get stake delegations from the address -// @Accept json -// @Produce json -// @Tags platform,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 -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/{coin}/staking/delegations/{address} [get] -func makeStakingDelegationsRoute(router gin.IRouter, api blockatlas.Platform) { - var stakingAPI blockatlas.StakeAPI - stakingAPI, _ = api.(blockatlas.StakeAPI) - - if stakingAPI == nil { - return - } - - router.GET("/staking/delegations/:address", func(c *gin.Context) { - response, err := getDelegationResponse(stakingAPI, c.Param("address")) - if err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - ginutils.RenderSuccess(c, response) - }) -} - // @Summary Get Collections // @ID collections_v2 // @Description Get all collections from the address diff --git a/api/stake.go b/api/stake.go new file mode 100644 index 000000000..9e7c129b1 --- /dev/null +++ b/api/stake.go @@ -0,0 +1,100 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/ginutils/gincache" + "github.com/trustwallet/blockatlas/pkg/logger" + services "github.com/trustwallet/blockatlas/services/assets" + "time" +) + +// @Summary Get Validators +// @ID validators +// @Description Get validators from the address +// @Accept json +// @Produce json +// @Tags platform,staking +// @Param coin path string true "the coin name" default(cosmos) +// @Success 200 {object} blockatlas.DocsResponse +// @Failure 500 {object} ginutils.ApiError +// @Router /v2/{coin}/staking/validators [get] +func makeStakingValidatorsRoute(router gin.IRouter, api blockatlas.Platform) { + var stakingAPI blockatlas.StakeAPI + stakingAPI, _ = api.(blockatlas.StakeAPI) + + if stakingAPI == nil { + return + } + + router.GET("/staking/validators", gincache.CacheMiddleware(time.Hour, func(c *gin.Context) { + results, err := services.GetValidators(stakingAPI) + if err != nil { + logger.Error(err) + ginutils.ErrorResponse(c).Message(err.Error()).Render() + return + } + ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: results}) + })) +} + +// @Summary Get Stake Delegations +// @ID delegations +// @Description Get stake delegations from the address +// @Accept json +// @Produce json +// @Tags platform,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 +// @Failure 500 {object} ginutils.ApiError +// @Router /v2/{coin}/staking/delegations/{address} [get] +func makeStakingDelegationsRoute(router gin.IRouter, api blockatlas.Platform) { + var stakingAPI blockatlas.StakeAPI + stakingAPI, _ = api.(blockatlas.StakeAPI) + + if stakingAPI == nil { + return + } + + router.GET("/staking/delegations/:address", func(c *gin.Context) { + response, err := getDelegationResponse(stakingAPI, c.Param("address")) + if err != nil { + ginutils.ErrorResponse(c).Message(err.Error()).Render() + return + } + + ginutils.RenderSuccess(c, response) + }) +} + +func getDelegationResponse(p blockatlas.StakeAPI, address string) (blockatlas.DelegationResponse, error) { + delegations, err := p.GetDelegations(address) + if err != nil { + return blockatlas.DelegationResponse{ + StakingResponse: getStakingResponse(p), + }, errors.E("Unable to fetch delegations list", err) + } + balance, err := p.UndelegatedBalance(address) + if err != nil { + return blockatlas.DelegationResponse{ + StakingResponse: getStakingResponse(p), + }, errors.E("Unable to fetch undelegated balance", err) + } + return blockatlas.DelegationResponse{ + Balance: balance, + Delegations: delegations, + Address: address, + StakingResponse: getStakingResponse(p), + }, nil +} + +func getStakingResponse(p blockatlas.StakeAPI) blockatlas.StakingResponse { + c := p.Coin() + return blockatlas.StakingResponse{ + Coin: c.External(), + Details: p.GetDetails(), + } +} From 1ef352141abcac823049f1930594fc14a52254a2 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 13 Feb 2020 23:06:32 -0300 Subject: [PATCH 118/506] Split asset services methods (#856) * Split asset services methods * Change method signature --- services/assets/info.go | 26 ++++++++++++++ services/assets/info_test.go | 30 ++++++++++++++++ services/assets/{client.go => stake.go} | 34 +++++-------------- .../assets/{client_test.go => stake_test.go} | 24 ------------- 4 files changed, 64 insertions(+), 50 deletions(-) create mode 100644 services/assets/info.go create mode 100644 services/assets/info_test.go rename services/assets/{client.go => stake.go} (80%) rename services/assets/{client_test.go => stake_test.go} (71%) diff --git a/services/assets/info.go b/services/assets/info.go new file mode 100644 index 000000000..416bed206 --- /dev/null +++ b/services/assets/info.go @@ -0,0 +1,26 @@ +package assets + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "time" +) + +func GetCoinInfo(coinId int, token string) (info *blockatlas.CoinInfo, err error) { + c, ok := coin.Coins[uint(coinId)] + if !ok { + return info, errors.E("coin not found") + } + url := getCoinInfoUrl(c, token) + request := blockatlas.InitClient(url) + err = request.GetWithCache(&info, "info/info.json", nil, time.Hour*1) + return +} + +func getCoinInfoUrl(c coin.Coin, token string) string { + if len(token) == 0 { + return AssetsURL + c.Handle + } + return AssetsURL + c.Handle + "/assets/" + token +} diff --git a/services/assets/info_test.go b/services/assets/info_test.go new file mode 100644 index 000000000..6b5e5f787 --- /dev/null +++ b/services/assets/info_test.go @@ -0,0 +1,30 @@ +package assets + +import ( + "github.com/trustwallet/blockatlas/coin" + "testing" +) + +func Test_getCoinInfoUrl(t *testing.T) { + type args struct { + c coin.Coin + token string + } + tests := []struct { + name string + args args + want string + }{ + {"test Ethereum coin", args{coin.Ethereum(), ""}, AssetsURL + coin.Ethereum().Handle}, + {"test Ethereum token", args{coin.Ethereum(), "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, AssetsURL + coin.Ethereum().Handle + "/assets/" + "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, + {"test Binance coin", args{coin.Binance(), ""}, AssetsURL + coin.Binance().Handle}, + {"test Binance token", args{coin.Binance(), "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, AssetsURL + coin.Binance().Handle + "/assets/" + "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getCoinInfoUrl(tt.args.c, tt.args.token); got != tt.want { + t.Errorf("getCoinInfoUrl() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/services/assets/client.go b/services/assets/stake.go similarity index 80% rename from services/assets/client.go rename to services/assets/stake.go index 6a5092753..62cde139c 100644 --- a/services/assets/client.go +++ b/services/assets/stake.go @@ -12,15 +12,14 @@ const ( AssetsURL = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/" ) -func GetCoinInfo(coinId int, token string) (info *blockatlas.CoinInfo, err error) { - c, ok := coin.Coins[uint(coinId)] - if !ok { - return info, errors.E("coin not found") +func requestValidatorsInfo(coin coin.Coin) ([]AssetValidator, error) { + var results []AssetValidator + request := blockatlas.InitClient(AssetsURL + coin.Handle) + err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) + if err != nil { + return nil, errors.E(err, errors.Params{"coin": coin.Handle}).PushToSentry() } - url := getCoinInfoUrl(c, token) - request := blockatlas.InitClient(url) - err = request.GetWithCache(&info, "info/info.json", nil, time.Hour*1) - return + return results, nil } func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) { @@ -36,7 +35,7 @@ func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) } func GetValidators(api blockatlas.StakeAPI) ([]blockatlas.StakeValidator, error) { - assetsValidators, err := getValidatorsInfo(api.Coin()) + assetsValidators, err := requestValidatorsInfo(api.Coin()) if err != nil { return nil, errors.E(err, "unable to fetch validators list from the registry").PushToSentry() } @@ -52,16 +51,6 @@ func GetValidators(api blockatlas.StakeAPI) ([]blockatlas.StakeValidator, error) return results, nil } -func getValidatorsInfo(coin coin.Coin) ([]AssetValidator, error) { - var results []AssetValidator - request := blockatlas.InitClient(AssetsURL + coin.Handle) - err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) - if err != nil { - return nil, errors.E(err, errors.Params{"coin": coin.Handle}).PushToSentry() - } - return results, nil -} - func normalizeValidators(validators []blockatlas.Validator, assets []AssetValidator, coin coin.Coin) []blockatlas.StakeValidator { results := make([]blockatlas.StakeValidator, 0) for _, v := range validators { @@ -97,10 +86,3 @@ func calculateAnnual(annual float64, commission float64) float64 { func getImage(c coin.Coin, ID string) string { return AssetsURL + c.Handle + "/validators/assets/" + ID + "/logo.png" } - -func getCoinInfoUrl(c coin.Coin, token string) string { - if len(token) == 0 { - return AssetsURL + c.Handle - } - return AssetsURL + c.Handle + "/assets/" + token -} diff --git a/services/assets/client_test.go b/services/assets/stake_test.go similarity index 71% rename from services/assets/client_test.go rename to services/assets/stake_test.go index 1d5fcdf82..94c4f5e31 100644 --- a/services/assets/client_test.go +++ b/services/assets/stake_test.go @@ -113,27 +113,3 @@ func TestCalcAnnual(t *testing.T) { }) } } - -func Test_getCoinInfoUrl(t *testing.T) { - type args struct { - c coin.Coin - token string - } - tests := []struct { - name string - args args - want string - }{ - {"test Ethereum coin", args{coin.Ethereum(), ""}, AssetsURL + coin.Ethereum().Handle}, - {"test Ethereum token", args{coin.Ethereum(), "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, AssetsURL + coin.Ethereum().Handle + "/assets/" + "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, - {"test Binance coin", args{coin.Binance(), ""}, AssetsURL + coin.Binance().Handle}, - {"test Binance token", args{coin.Binance(), "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, AssetsURL + coin.Binance().Handle + "/assets/" + "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := getCoinInfoUrl(tt.args.c, tt.args.token); got != tt.want { - t.Errorf("getCoinInfoUrl() = %v, want %v", got, tt.want) - } - }) - } -} From 4f7048bb3c44ca07b0a19f26bec0520ed32fce5c Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 13 Feb 2020 23:47:20 -0300 Subject: [PATCH 119/506] Improve validators logic using extensions (#857) * Improve validator logic using extensions * Fix unit tests --- pkg/blockatlas/staking.go | 11 ++++++++++- pkg/blockatlas/staking_test.go | 25 +++++++++++++++++++++++++ services/assets/model.go | 11 +++++++++++ services/assets/model_test.go | 25 +++++++++++++++++++++++++ services/assets/stake.go | 27 ++++++++++++--------------- services/assets/stake_test.go | 9 +-------- 6 files changed, 84 insertions(+), 24 deletions(-) create mode 100644 pkg/blockatlas/staking_test.go create mode 100644 services/assets/model_test.go diff --git a/pkg/blockatlas/staking.go b/pkg/blockatlas/staking.go index 16923ffb3..17ef91272 100644 --- a/pkg/blockatlas/staking.go +++ b/pkg/blockatlas/staking.go @@ -6,6 +6,7 @@ type ValidatorPage []Validator type DelegationsPage []Delegation type DelegationsBatchPage []DelegationResponse type StakingBatchPage []StakingResponse +type StakeValidators []StakeValidator type DelegationStatus string type DelegationType string @@ -59,7 +60,7 @@ type StakeValidatorInfo struct { type StakeValidator struct { ID string `json:"id"` - Status bool `json:"status,omitempty"` + Status bool `json:"status"` Info StakeValidatorInfo `json:"info,omitempty"` Details StakingDetails `json:"details,omitempty"` } @@ -75,3 +76,11 @@ type StakingResponse struct { Coin *coin.ExternalCoin `json:"coin"` Details StakingDetails `json:"details"` } + +func (sv StakeValidators) ToMap() ValidatorMap { + validators := make(ValidatorMap) + for _, v := range sv { + validators[v.ID] = v + } + return validators +} diff --git a/pkg/blockatlas/staking_test.go b/pkg/blockatlas/staking_test.go new file mode 100644 index 000000000..4abb2b919 --- /dev/null +++ b/pkg/blockatlas/staking_test.go @@ -0,0 +1,25 @@ +package blockatlas + +import ( + "reflect" + "testing" +) + +func TestStakeValidators_ToMap(t *testing.T) { + tests := []struct { + name string + sv StakeValidators + want ValidatorMap + }{ + {"test 1 validator", StakeValidators{{ID: "test1"}}, ValidatorMap{"test1": {ID: "test1"}}}, + {"test 2 validators", StakeValidators{{ID: "test1"}, {ID: "test2"}}, ValidatorMap{"test1": {ID: "test1"}, "test2": {ID: "test2"}}}, + {"test 3 validators", StakeValidators{{ID: "test1"}, {ID: "test2"}, {ID: "test3"}}, ValidatorMap{"test1": {ID: "test1"}, "test2": {ID: "test2"}, "test3": {ID: "test3"}}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.sv.ToMap(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("ToMap() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/services/assets/model.go b/services/assets/model.go index 638718424..f9b7ff415 100644 --- a/services/assets/model.go +++ b/services/assets/model.go @@ -1,5 +1,8 @@ package assets +type AssetValidators []AssetValidator +type AssetValidatorMap map[string]AssetValidator + type AssetValidator struct { ID string `json:"id"` Name string `json:"name"` @@ -16,3 +19,11 @@ type ValidatorPayout struct { type ValidatorStatus struct { Disabled bool `json:"disabled"` } + +func (av AssetValidators) toMap() AssetValidatorMap { + validators := make(AssetValidatorMap) + for _, v := range av { + validators[v.ID] = v + } + return validators +} diff --git a/services/assets/model_test.go b/services/assets/model_test.go new file mode 100644 index 000000000..9b025734d --- /dev/null +++ b/services/assets/model_test.go @@ -0,0 +1,25 @@ +package assets + +import ( + "reflect" + "testing" +) + +func TestAssetValidators_toMap(t *testing.T) { + tests := []struct { + name string + av AssetValidators + want AssetValidatorMap + }{ + {"test 1 asset", AssetValidators{{ID: "test1"}}, AssetValidatorMap{"test1": {ID: "test1"}}}, + {"test 2 assets", AssetValidators{{ID: "test1"}, {ID: "test2"}}, AssetValidatorMap{"test1": {ID: "test1"}, "test2": {ID: "test2"}}}, + {"test 3 assets", AssetValidators{{ID: "test1"}, {ID: "test2"}, {ID: "test3"}}, AssetValidatorMap{"test1": {ID: "test1"}, "test2": {ID: "test2"}, "test3": {ID: "test3"}}}, + } + 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) + } + }) + } +} diff --git a/services/assets/stake.go b/services/assets/stake.go index 62cde139c..0b1e1022c 100644 --- a/services/assets/stake.go +++ b/services/assets/stake.go @@ -12,8 +12,8 @@ const ( AssetsURL = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/" ) -func requestValidatorsInfo(coin coin.Coin) ([]AssetValidator, error) { - var results []AssetValidator +func requestValidatorsInfo(coin coin.Coin) (AssetValidators, error) { + var results AssetValidators request := blockatlas.InitClient(AssetsURL + coin.Handle) err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) if err != nil { @@ -23,18 +23,14 @@ func requestValidatorsInfo(coin coin.Coin) ([]AssetValidator, error) { } func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) { - validatorList, err := GetValidators(api) + validators, err := GetValidators(api) if err != nil { return nil, err } - validators := make(blockatlas.ValidatorMap) - for _, v := range validatorList { - validators[v.ID] = v - } - return validators, nil + return validators.ToMap(), nil } -func GetValidators(api blockatlas.StakeAPI) ([]blockatlas.StakeValidator, error) { +func GetValidators(api blockatlas.StakeAPI) (blockatlas.StakeValidators, error) { assetsValidators, err := requestValidatorsInfo(api.Coin()) if err != nil { return nil, errors.E(err, "unable to fetch validators list from the registry").PushToSentry() @@ -51,14 +47,15 @@ func GetValidators(api blockatlas.StakeAPI) ([]blockatlas.StakeValidator, error) return results, nil } -func normalizeValidators(validators []blockatlas.Validator, assets []AssetValidator, coin coin.Coin) []blockatlas.StakeValidator { - results := make([]blockatlas.StakeValidator, 0) +func normalizeValidators(validators []blockatlas.Validator, assets AssetValidators, coin coin.Coin) blockatlas.StakeValidators { + results := make(blockatlas.StakeValidators, 0) + assetsMap := assets.toMap() for _, v := range validators { - for _, v2 := range assets { - if v.ID == v2.ID && !v2.Status.Disabled { - results = append(results, normalizeValidator(v, v2, coin)) - } + asset, ok := assetsMap[v.ID] + if !ok || asset.Status.Disabled { + continue } + results = append(results, normalizeValidator(v, asset, coin)) } return results } diff --git a/services/assets/stake_test.go b/services/assets/stake_test.go index 94c4f5e31..1ac838f1d 100644 --- a/services/assets/stake_test.go +++ b/services/assets/stake_test.go @@ -39,25 +39,18 @@ var expectedStakeValidator = blockatlas.StakeValidator{ func TestGetImage(t *testing.T) { image := getImage(cosmosCoin, "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp") - expected := "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp/logo.png" - 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.StakeValidator{expectedStakeValidator} - + expected := blockatlas.StakeValidators{expectedStakeValidator} assert.Equal(t, expected, result) } From 7115fde999e0a8cc47e28cd2d3e9a1c7e7dcd5a4 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 14 Feb 2020 00:00:10 -0300 Subject: [PATCH 120/506] Fix postman tests for iotex --- pkg/tests/postman/transaction_data.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/tests/postman/transaction_data.json b/pkg/tests/postman/transaction_data.json index c5c55909b..6818b823e 100644 --- a/pkg/tests/postman/transaction_data.json +++ b/pkg/tests/postman/transaction_data.json @@ -81,7 +81,7 @@ }, { "handler": "iotex", - "address": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" + "address": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" }, { "handler": "icon", From 864479a020a6edc80a52a7f9416ee45edf42a76a Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 14 Feb 2020 00:25:36 -0300 Subject: [PATCH 121/506] Add auth parameter for newman make commands --- Makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index eb661493d..71ccab718 100644 --- a/Makefile +++ b/Makefile @@ -130,6 +130,15 @@ endif ## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http//localhost newman: install-newman @echo " > Runing $(test) tests" +ifndef observer_auth +override observer_auth = "test" +endif +ifndef market_auth +override market_auth = "" +endif +ifndef platform_auth +override platform_auth = "" +endif ifeq (,$(host)) @echo " > Host parameter is missing. e.g: make newman test=staking host=http://localhost:8420" @exit 1 @@ -144,7 +153,7 @@ ifeq (,$(test)) @bash -c "$(MAKE) newman test=observer host=$(host)" @bash -c "$(MAKE) newman test=market host=$(host)" else - @newman run pkg/tests/postman/Blockatlas.postman_collection.json --folder $(test) -d pkg/tests/postman/$(test)_data.json --env-var "host=$(host)" + @newman run pkg/tests/postman/Blockatlas.postman_collection.json --folder $(test) -d pkg/tests/postman/$(test)_data.json --env-var "host=$(host)" --env-var "observer_auth=$(observer_auth)" --env-var "platform_auth=$(platform_auth)" --env-var "market_auth=$(market_auth)" endif go-compile: go-get go-build From 37e25f144e05d46914a2d2fe2c2dee79971b202d Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 14 Feb 2020 00:31:06 -0300 Subject: [PATCH 122/506] Remove interation data for maket tests --- pkg/tests/postman/market_data.json | 8628 +--------------------------- 1 file changed, 5 insertions(+), 8623 deletions(-) diff --git a/pkg/tests/postman/market_data.json b/pkg/tests/postman/market_data.json index c5761a1a1..061e3356e 100644 --- a/pkg/tests/postman/market_data.json +++ b/pkg/tests/postman/market_data.json @@ -4,36 +4,6 @@ "type": "coin", "currency": "USD" }, - { - "coin": 313, - "type": "coin", - "currency": "USD" - }, - { - "coin": 3, - "type": "coin", - "currency": "USD" - }, - { - "coin": 5, - "type": "coin", - "currency": "USD" - }, - { - "coin": 19167, - "type": "coin", - "currency": "USD" - }, - { - "coin": 457, - "type": "coin", - "currency": "USD" - }, - { - "coin": 1729, - "type": "coin", - "currency": "USD" - }, { "coin": 0, "type": "coin", @@ -44,8626 +14,38 @@ "type": "coin", "currency": "USD" }, - { - "coin": 145, - "type": "coin", - "currency": "USD" - }, - { - "coin": 74, - "type": "coin", - "currency": "USD" - }, - { - "coin": 242, - "type": "coin", - "currency": "USD" - }, - { - "coin": 459, - "type": "coin", - "currency": "USD" - }, - { - "coin": 820, - "type": "coin", - "currency": "USD" - }, - { - "coin": 61, - "type": "coin", - "currency": "USD" - }, { "coin": 195, "type": "coin", "currency": "USD" }, - { - "coin": 5718350, - "type": "coin", - "currency": "USD" - }, - { - "coin": 42, - "type": "coin", - "currency": "USD" - }, - { - "coin": 304, - "type": "coin", - "currency": "USD" - }, - { - "coin": 2718, - "type": "coin", - "currency": "USD" - }, - { - "coin": 5741564, - "type": "coin", - "currency": "USD" - }, - { - "coin": 133, - "type": "coin", - "currency": "USD" - }, - { - "coin": 283, - "type": "coin", - "currency": "USD" - }, - { - "coin": 20, - "type": "coin", - "currency": "USD" - }, - { - "coin": 118, - "type": "coin", - "currency": "USD" - }, - { - "coin": 144, - "type": "coin", - "currency": "USD" - }, - { - "coin": 148, - "type": "coin", - "currency": "USD" - }, - { - "coin": 178, - "type": "coin", - "currency": "USD" - }, - { - "coin": 425, - "type": "coin", - "currency": "USD" - }, - { - "coin": 6060, - "type": "coin", - "currency": "USD" - }, - { - "coin": 14, - "type": "coin", - "currency": "USD" - }, - { - "coin": 175, - "type": "coin", - "currency": "USD" - }, - { - "coin": 1023, - "type": "coin", - "currency": "USD" - }, - { - "coin": 500, - "type": "coin", - "currency": "USD" - }, { "coin": 714, "type": "coin", "currency": "USD" }, { - "coin": 818, - "type": "coin", - "currency": "USD" - }, - { - "coin": 889, - "type": "coin", - "currency": "USD" - }, - { - "coin": 1001, - "type": "coin", - "currency": "USD" - }, - { - "coin": 2301, - "type": "coin", - "currency": "USD" - }, - { - "coin": 165, - "type": "coin", - "currency": "USD" - }, - { - "coin": 434, - "type": "coin", - "currency": "USD" - }, - { - "coin": 1024, - "type": "coin", - "currency": "USD" - }, - { - "coin": 2017, - "type": "coin", - "currency": "USD" - }, - { - "coin": 17, - "type": "coin", - "currency": "USD" - }, - { - "coin": 136, - "type": "coin", - "currency": "USD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2e98A6804E4b6c832ED0ca876a943abD3400b224" - }, - { - "coin": 60, + "coin": 714, "type": "token", "currency": "USD", - "token_id": "0xdAC17F958D2ee523a2206206994597C13D831ec7" + "token_id": "BTCB-1DE" }, { "coin": 195, "type": "token", "currency": "USD", - "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4DF812F6064def1e5e029f1ca858777CC98D2D81" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf97b5d65Da6b0468b90D531ddae2a69843e6797d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1985365e9f78359a9B6AD760e32412f4a445E862" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAef38fBFBF932D1AeF3B808Bc8fBd8Cd8E1f8BC5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE0B7927c4aF23765Cb51314A0E0521A9645F0E2A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD8912C10681D8B21Fd3742244f44658dBA12264E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAf30D2a7E90d7DC361c8C4585e9BB7D2F6f15bc7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaeC2E87E0A235266D9C5ADc9DEb4b2E29b54D009" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa74476443119A942dE498590Fe1f2454d7D4aC0d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5c543e7AE0A1104f78406C340E9C64FD9fCE5170" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x667088b212ce3d06a1b553a7221E1fD19000d9aF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xec67005c4E498Ec7f55E092bd1d35cbC47C91892" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6531f133e6DeeBe7F2dcE5A0441aA7ef330B4e53" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB9e7F8568e08d5659f5D29C4997173d84CdF2607" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE7775A6e9Bcf904eb39DA2b68c5efb4F9360e08C" + "token_id": "TUL5yxRKeSWvceLZ3BSU5iNJcQmNxkWayh" }, { - "coin": 60, + "coin": 195, "type": "token", "currency": "USD", - "token_id": "0x08711D3B02C8758F2FB3ab4e80228418a7F8e39c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf7B098298f7C69Fc14610bf71d5e02c60792894C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x607F4C5BB672230e8672085532f7e901544a7375" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xCb94be6f13A1182E4A4B6140cb7bf2025d28e41B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfa05A73FfE78ef8f1a739473e462c54bae6567D9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6810e776880C02933D47DB1b9fc05908e5386b96" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaAAf91D9b90dF800Df4F55c205fd6989c977E73a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xcbCC0F036ED4788F63FC0fEE32873d6A7487b908" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1a95B271B0535D15fa49932Daba31BA612b52946" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2e071D2966Aa7D8dECB1005885bA1977D6038A65" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x960b236A07cf122663c4303350609A66A7B288C0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xcCeD5B8288086BE8c38E23567e684C3740be4D48" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8Ae4BF2C33a8e667de34B54938B0ccD03Eb8CC06" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x40395044Ac3c0C57051906dA938B54BD6557F212" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa645264C5603E96c3b0B078cdab68733794B0A71" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x59061b6f26BB4A9cE5828A19d35CFD5A4B80F056" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x983F6d60db79ea8cA4eB9968C6aFf8cfA04B3c63" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x660e71483785f66133548B10f6926dC332b06e61" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdDAaf4A0702a03A4505F2352a1abA001fFc344be" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x419D0d8BdD9aF5e606Ae2232ed285Aff190E711b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB97048628DB6B661D4C2aA833e95Dbe1A905B280" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x744d70FDBE2Ba4CF95131626614a1763DF805B9E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4470BB87d77b963A013DB939BE332f927f2b992e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8aA33A7899FCC8eA5fBe6A608A109c3893A1B8b2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB64ef51C888972c908CFacf59B47C1AfBC0Ab8aC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD0D6D6C5Fe4a677D343cC433536BB717bAe167dD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB63B606Ac810a52cCa15e44bB630fd42D8d1d83d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0AfFa06e7Fbe5bC9a764C979aA66E8256A631f02" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF4134146AF2d511Dd5EA8cDB1C4AC88C57D60404" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8727c112C712c4a03371AC87a74dD6aB104Af768" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF433089366899D83a9f26A773D59ec7eCF30355e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd4fa1460F537bb9085d22C7bcCB5DD450Ef28e3a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7C5A0CE9267ED19B22F8cae653F198e3E8daf098" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x41e5560054824eA6B0732E656E3Ad64E20e94E45" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5Af2Be193a6ABCa9c8817001F45744777Db30756" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2bDC0D42996017fCe214b21607a515DA41A9E0C5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe3818504c1B32bF1557b16C238B2E01Fd3149C17" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfcA47962D45ADFdfd1Ab2D972315dB4ce7CCf094" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x701C244b988a513c945973dEFA05de933b23Fe1D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0AbdAce70D3790235af448C88547603b945604ea" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x006BeA43Baa3f7A6f765F14f10A1a1b08334EF45" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x177d39AC676ED1C67A2b268AD7F1E58826E5B0af" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEa1f346faF023F974Eb5adaf088BbCdf02d761F4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x08d32b0da63e2C3bcF8019c9c5d849d7a9d791e6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x56ba2Ee7890461f463F7be02aAC3099f6d5811A8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3597bfD533a99c9aa083587B074434E61Eb0A258" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7654915A1b82D6D2D0AFc37c52Af556eA8983c7E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE41d2489571d322189246DaFA5ebDe1F4699F498" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5d60d8d7eF6d37E16EBABc324de3bE57f135e0BC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa7f976C360ebBeD4465c2855684D1AAE5271eFa9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x07D9e49Ea402194bf48A8276dAfB16E4eD633317" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x08f5a9235B08173b7569F83645d2c7fB55e8cCD8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb7cB1C96dB6B22b0D3d9536E0108d062BD488F74" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9E77D5a1251b6F7D456722A6eaC6D2d5980bd891" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5d4ABC77B8405aD177d8ac6682D584ecbFd46CEc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4355fC160f74328f9b383dF2EC589bB3dFd82Ba0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe120c1ECBfdFeA7F0A8f0Ee30063491E8c26fedf" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBBbbCA6A901c926F240b89EacB641d8Aec7AEafD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0e0989b1f9B8A38983c2BA8053269Ca62Ec9B195" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaF4DcE16Da2877f8c9e00544c93B62Ac40631F16" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0d88eD6E74bbFD96B831231638b66C05571e824F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x07e3c70653548B04f0A75970C1F81B4CBbFB606f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC0Eb85285d83217CD7c891702bcbC0FC401E2D9D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x51DB5Ad35C671a87207d88fC11d593AC0C8415bd" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf05a9382A4C3F29E2784502754293D88b835109C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4E0603e2A27A30480E5e3a4Fe548e29EF12F64bE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0F5D2fB29fb7d3CFeE444a200298f468908cC942" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf8e386EDa857484f5a12e4B5DAa9984E06E73705" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x90528aeb3a2B736B780fD1B6C478bB7E1d643170" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd7631787B4dCc87b1254cfd1e5cE48e96823dEe8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x226bb599a12C826476e3A771454697EA52E9E220" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x514910771AF9Ca656af840dff83E8264EcF986CA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDf6Ef343350780BF8C3410BF062e0C015B1DD671" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe8Ff5C9c75dEb346acAc493C463C8950Be03Dfba" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8D75959f1E61EC2571aa72798237101F084DE63a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE814aeE960a85208C3dB542C53E7D4a6C8D5f60F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8eFFd494eB698cc399AF6231fCcd39E08fd20B15" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7d3cb11f8c13730C24D01826d8F2005F0e1b348F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3d1BA9be9f66B8ee101911bC36D3fB562eaC2244" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4156D3342D5c385a87D264F90653733592000581" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc96DF921009B790dfFcA412375251ed1A2b75c60" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb2F7EB1f2c37645bE61d73953035360e768D81E6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x83eEA00D838f92dEC4D1475697B9f4D3537b56E3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9B11EFcAAA1890f6eE52C6bB7CF8153aC5d74139" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC12D1c73eE7DC3615BA4e37E4ABFdbDDFA38907E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE0C72452740414d861606a44cCd5eA7f96488278" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2C974B2d0BA1716E644c1FC59982a89DDD2fF724" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x168296bb09e24A88805CB9c33356536B980D3fC5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa8006C4ca56F24d6836727D106349320dB7fEF82" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9214eC02CB71CbA0ADA6896b8dA260736a67ab10" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDd6C68bb32462e01705011a4e2Ad1a60740f217F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x336F646F87D9f6bC6Ed42Dd46E8b3fD9DbD15C22" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf3Db5Fa2C66B7aF3Eb0C0b782510816cbe4813b8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc42209aCcC14029c1012fB5680D95fBd6036E2a0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEA610B1153477720748DC13ED378003941d84fAB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xba2184520A1cC49a6159c57e61E1844E085615B6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd4c435F5B09F855C3317c8524Cb1F586E42795fa" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf0Ee6b27b759C9893Ce4f094b49ad28fd15A23e4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7A41e0517a5ecA4FdbC7FbebA4D4c47B9fF6DC63" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5D21eF5f25a985380B65c8e943A0082fEDa0Db84" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2dAEE1AA61D60A252DC80564499A69802853583A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE64509F0bf07ce2d29A7eF19A8A9bc065477C1B4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xCeD4E93198734dDaFf8492d525Bd258D49eb388E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x27054b13b1B798B345b591a4d22e6562d47eA75a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7d4b8Cce0591C9044a22ee543533b72E976E36C3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1c4481750daa5Ff521A2a7490d9981eD46465Dbd" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x30ceCB5461A449A90081F5a5F55db4e048397BAB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfec0cF7fE078a500abf15F1284958F22049c2C7e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3137619705b5fc22a3048989F983905e456b59Ab" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x881Ef48211982D01E2CB7092C915E647Cd40D85C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9AF4f26941677C706cfEcf6D3379FF01bB85D5Ab" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8f8221aFbB33998d8584A2B05749bA73c37a938a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x539EfE69bCDd21a83eFD9122571a64CC25e0282b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfF18DBc487b4c2E3222d115952bABfDa8BA52F5F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4DC3643DbC642b72C158E7F3d2ff232df61cb6CE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x039B5649A59967e3e936D7471f9c3700100Ee1ab" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe469c4473af82217B30CF17b10BcDb6C8c796e75" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x705EE96c1c160842C92c1aeCfCFfccc9C412e3D9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE50365f5D679CB98a1dd62D6F6e58e59321BcdDf" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc324a2f6b05880503444451B8b27e6f9e63287Cb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6Aac8CB9861E42bf8259F5AbDC6aE3Ae89909E11" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7728dFEF5aBd468669EB7f9b48A7f70a501eD29D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF970b8E36e23F7fC3FD752EeA86f8Be8D83375A6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5046E860ff274fb8c66106B0Ffb8155849fB0787" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0A76aad21948eA1ef447D26DEe91a54370E151e0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0aeF06DcCCC531e581f0440059E6FfCC206039EE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x859a9C0b44cb7066D956a958B0b82e54C9e44b4B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xac3211a5025414Af2866FF09c23FC18bc97e79b1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA9Aad2dC3a8315caeee5F458B1d8EDc31D8467BD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEA38eAa3C86c8F9B751533Ba2E562deb9acDED40" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8F0921f30555624143d427b340b1156914882C10" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xeB7C20027172E5d143fB030d50f91Cece2D1485D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB7c4A82936194FEE52a4E3d4cEC3415f74507532" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x595832F8FC6BF59c85C527fEC3740A1b7a361269" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x12B19D3e2ccc14Da04FAe33e63652ce469b3F2FD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x48f775EFBE4F5EcE6e0DF2f7b5932dF56823B990" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x78B7FADA55A64dD895D8c8c35779DD8b67fA8a05" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0Cf0Ee63788A0849fE5297F3407f701E122cC023" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x44197A4c44D6A059297cAf6be4F7e172BD56Caaf" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x24692791Bc444c5Cd0b81e3CBCaba4b04Acd1F3B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5554e04e76533E1d14c52f05beEF6c9d329E1E30" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBA5F11b16B155792Cf3B2E6880E8706859A8AEB6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x255Aa6DF07540Cb5d3d297f0D0D4D84cb52bc8e6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6C2adC2073994fb2CCC5032cC2906Fa221e9B391" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc3761EB917CD790B30dAD99f6Cc5b4Ff93C4F9eA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x999967E2Ec8A74B7c8E9dB19E039d920B31d39D0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x50Ee674689d75C0f88E8f83cfE8c4B69E8fd590D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEA097A2b1dB00627B2Fa17460Ad260c016016977" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0371A82e4A9d0A4312f3ee2Ac9c6958512891372" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x103c3A209da59d3E7C4A89307e66521e081CFDF0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3ADfc4999F77D04c8341BAC5F3A76f58DfF5B37A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x62a56a4A2Ef4D355D34D10fBF837e747504d38d4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5d51FCceD3114A8bb5E90cDD0f9d682bCbCC5393" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x82b0E50478eeaFde392D45D1259Ed1071B6fDa81" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x99ea4dB9EE77ACD40B119BD1dC4E33e1C070b80d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x618E75Ac90b12c6049Ba3b27f5d5F8651b0037F6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x42d6622deCe394b54999Fbd73D108123806f6a18" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x340D2bdE5Eb28c1eed91B2f790723E3B160613B7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf04a8ac553FceDB5BA99A64799155826C136b0Be" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF7920B0768Ecb20A123fAc32311d07D193381d6f" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "WISH-2D5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb62d18DeA74045E822352CE4B3EE77319DC5ff2F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x80fB784B7eD66730e8b1DBd9820aFD29931aab03" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd341d1680Eeee3255b8C4c75bCCE7EB57f144dAe" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x679BADc551626e01B23CeecEFBc9B877EA18fc46" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x419c4dB4B9e25d6Db2AD9691ccb832C8D9fDA05E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB41422D5a1d5d5C73c229686935b40F881502785" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x88A3E4F35D64aAD41A6d4030ac9AFE4356cB84fA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1e797Ce986C3CFF4472F7D38d5C4aba55DfEFE40" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x04F2E7221fdb1B52A68169B25793E51478fF0329" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x74CEDa77281b339142A36817Fa5F9E29412bAb85" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5E6b6d9aBAd9093fdc861Ea1600eBa1b355Cd940" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xCc34366E3842cA1BD36c1f324d15257960fCC801" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBDC5bAC39Dbe132B1E030e898aE3830017D7d969" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF83301c5Cd1CCBB86f466A6B3c53316ED2f8465a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x286BDA1413a2Df81731D4930ce2F862a35A609fE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x27f610BF36ecA0939093343ac28b1534a721DBB4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x85089389C14Bd9c77FC2b8F0c3d1dC3363Bf06Ef" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x672a1AD4f667FB18A333Af13667aa0Af1F5b5bDD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x63b992e6246d88f07fc35A056d2C365E6D441A3D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD01DB73E047855Efb414e6202098C4Be4Cd2423B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x66186008C1050627F979d464eABb258860563dbE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9041Fe5B3FDEA0f5e4afDC17e75180738D877A01" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x55F93985431Fc9304077687a35A1BA103dC1e081" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2604FA406Be957E542BEb89E6754fCdE6815e83f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x81c9151de0C8bafCd325a57E3dB5a5dF1CEBf79c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8B1F49491477e0fB46a29fef53F1EA320D13c349" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5e3346444010135322268a4630d2ED5F8D09446c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x72aDadb447784dd7AB1F472467750fC485e4cb2d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC5bBaE50781Be1669306b9e001EFF57a2957b09d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6EC8a24CaBdc339A06a172F8223ea557055aDAa5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF70a642bD387F94380fFb90451C2c81d4Eb82CBc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2C4e8f2D746113d0696cE89B35F0d8bF88E0AEcA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD0a4b8946Cb52f0661273bfbC6fD0E0C75Fc6433" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd234BF2410a0009dF9c3C63b610c09738f18ccD7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbf2179859fc6D5BEE9Bf9158632Dc51678a4100e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x72dD4b6bd852A3AA172Be4d6C5a6dbEc588cf131" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x558EC3152e2eb2174905cd19AeA4e34A23DE9aD6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb3104b4B9Da82025E8b9F8Fb28b3553ce2f67069" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd2d6158683aeE4Cc838067727209a0aAF4359de3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x06147110022B768BA8F99A8f385df11a151A9cc8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x68d57c9a1C35f63E2c83eE8e49A64e9d70528D25" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0Ebb614204E47c09B6C3FeB9AAeCad8EE060E23E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA823E6722006afe99E91c30FF5295052fe6b8E32" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x70a72833d6bF7F508C8224CE59ea1Ef3d0Ea3A38" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE477292f1B3268687A29376116B0ED27A9c76170" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0396340f16Bbec973280AB053efc3f208fA37795" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0AF44e2784637218dD1D32A322D44e603A8f0c6A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7703C35CfFdC5CDa8D27aa3df2F9ba6964544b6e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x52A7cB918c11A16958bE40CBA7E31e32a499a465" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1234567461d3f8Db7496581774Bd869C83D51c93" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB70835D7822eBB9426B56543E391846C107bd32C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc27A2F05fa577a83BA0fDb4c38443c0718356501" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x107c4504cd79C5d2696Ea0030a8dD4e92601B82e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0bb217E40F8a5Cb79Adf04E1aAb60E5abd0dfC1e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE2FB6529EF566a080e6d23dE0bd351311087D567" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1d462414fe14cf489c7A21CaC78509f4bF8CD7c0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1a7a8BD9106F2B8D977E08582DC7d24c723ab0DB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x814e0908b12A99FeCf5BC101bB5d0b8B5cDf7d26" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA974c709cFb4566686553a20790685A47acEAA33" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe81D72D14B1516e68ac3190a46C93302Cc8eD60f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8a854288a5976036A725879164Ca3e91d30c6A1B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x584B44853680ee34a0F337B712a8f66d816dF151" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5f3789907b35DCe5605b00C0bE0a7eCDBFa8A841" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9e6B2B11542f2BC52f3029077acE37E8fD838D7F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x58d0A58E4B165a27E4e1B8C2A3eF39C89b581180" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6781a0F84c7E9e846DCb84A9a5bd49333067b104" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4824A7b64E3966B0133f4f4FFB1b9D6bEb75FFF7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9B20DaBcec77f6289113E61893F7BEeFAEB1990a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1063ce524265d5a3A624f4914acd573dD89ce988" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5F53f7A8075614b699Baad0bC2c899f4bAd8FBBF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5B2e4a700dfBc560061e957edec8F6EeEb74a320" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x16f812Be7FfF02cAF662B85d5d58a5da6572D4Df" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6fFF3806Bbac52A20e0d79BC538d527f6a22c96b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1961B3331969eD52770751fC718ef530838b6dEE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x264Dc2DedCdcbb897561A57CBa5085CA416fb7b4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1b6C5864375b34aF3Ff5Bd2E5f40Bc425B4a8D79" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0F4CA92660Efad97a9a70CB0fe969c755439772C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x32d74896f05204D1b6Ae7B0a3CEBd7FC0Cd8F9C7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x461733c17b0755CA5649B6DB08B3E213FCf22546" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x12B306fA98F4CbB8d4457FdFf3a0A0a56f07cCdf" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2C82c73d5B34AA015989462b2948cd616a37641F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x45245bc59219eeaAF6cD3f382e078A461FF9De7B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa6a840E50bCaa50dA017b91A0D86B8b2d41156EE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x85e076361cc813A908Ff672F9BAd1541474402b2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4CC19356f2D37338b9802aa8E8fc58B0373296E7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFF603F43946A3A28DF5E6A73172555D8C8b02386" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFA1a856Cfa3409CFa145Fa4e20Eb270dF3EB21ab" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x02C4C78C462E32cCa4a90Bc499bF411Fb7bc6aFB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x79650799e7899A802cB96C0Bc33a6a8d4CE4936C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x57838fF342f36A1EC18224981ea8715a4667fB3a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5B0751713b2527d7f002c0c4e2a37e1219610A6B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x13f25cd52b21650caa8225C9942337d914C9B030" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1245ef80F4d9e02ED9425375e8F649B9221b31D8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB17DF9a3B09583a9bDCf757d6367171476D4D8a3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xeC46f8207D766012454c408De210BCBc2243E71c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x64CdF819d3E75Ac8eC217B3496d7cE167Be42e80" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xCc13Fc627EFfd6E35D2D2706Ea3C4D7396c610ea" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8eB24319393716668D768dCEC29356ae9CfFe285" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x687174f8C49ceb7729D925C3A961507ea4Ac7b28" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2567c677473d110D75a8360C35309e63B1d52429" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9F5F3CFD7a32700C93F971637407ff17b91c7342" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9AF839687F6C94542ac5ece2e317dAAE355493A1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8f136Cc8bEf1fEA4A7b71aa2301ff1A52F084384" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x647F274b3a7248D6CF51b35f08E7E7fD6EdFb271" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd97579Cea3fE2473682a4C42648134BB982433B9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x89303500a7Abfb178B274FD89F2469C264951e1f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x922105fAd8153F516bCfB829f56DC097a0E1D705" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe75ad3aAB14E4B0dF8c5da4286608DaBb21Bd864" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x13d0bf45e5F319Fa0B58900807049f23caE7C40D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x653430560bE843C4a3D143d0110e896c2Ab8ac0D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x26E75307Fc0C021472fEb8F727839531F112f317" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x69b148395Ce0015C13e36BFfBAd63f49EF874E03" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x80A7E048F37A50500351C204Cb407766fA3baE7f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdA6cb58A0D0C01610a29c5A65c303e13e885887C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3A92bD396aEf82af98EbC0Aa9030D25a23B11C6b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4EcDB6385f3Db3847F9C4A9bf3F9917bb27A5452" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4290563C2D7c255B5EEC87f2D3bD10389f991d68" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe0D95530820aAfc51b1d98023AA1Ff000b78d8b2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4092678e4E78230F46A1534C0fbc8fA39780892B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5136C98A80811C3f46bDda8B5c4555CFd9f812F0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBDCFbf5C4D91Abc0bC9709C7286d00063c0e6F22" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x37E8789bB9996CaC9156cD5F5Fd32599E6b91289" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x923108a439C4e8C2315c4f6521E5cE95B44e9B4c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x327682779bAB2BF4d1337e8974ab9dE8275A7Ca8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC39E626A04C5971D770e319760D7926502975e47" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaA7a9CA87d3694B5755f213B5D04094b8d0F0A6F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFA3118B34522580c35Ae27F6cf52da1dBb756288" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7f121d4EC6c2C07eB6BC7989d91d2d4fF654c068" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4270bb238f6DD8B1c3ca01f96CA65b2647c06D3C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2d0E95bd4795D7aCe0da3C0Ff7b706a5970eb9D3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf278c1CA969095ffddDED020290cf8B5C424AcE2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5A1A29DBb6Ad6153DB764568C1289076bC876df6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3136eF851592aCf49CA4C825131E364170FA32b3" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "EQL-586" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x58c69ed6cd6887c0225D1FcCEcC055127843c69b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfAE4Ee59CDd86e3Be9e8b90b53AA866327D7c090" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAa0bb10CEc1fa372eb3Abc17C933FC6ba863DD9E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8f7b0B40E27E357540F90f187d90CE06366aC5A5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb6EE9668771a79be7967ee29a63D4184F8097143" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaE73B38d1c9A8b274127ec30160a4927C4d71824" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9992eC3cF6A55b00978cdDF2b27BC6882d88D1eC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x41dBECc1cdC5517C6f76f6a6E836aDbEe2754DE3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa5Fd1A791C4dfcaacC963D4F73c6Ae5824149eA7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xba9d4199faB4f26eFE3551D490E3821486f135Ba" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfd8971d5E8E1740cE2d0A84095fCA4De729d0c16" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2baac9330Cf9aC479D819195794d79AD0c7616e3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6f259637dcD74C767781E37Bc6133cd6A68aa161" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2ccbFF3A042c68716Ed2a2Cb0c544A9f1d1935E1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x24dDFf6D8B8a42d835af3b440De91f3386554Aa4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5732046A883704404F284Ce41FfADd5b007FD668" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3505F494c3f0fed0B594E01Fa41Dd3967645ca39" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe8A1Df958bE379045E2B46a31A98B93A2eCDfDeD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8dB54ca569D3019A2ba126D03C37c44b5eF81EF6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4CF488387F035FF08c371515562CBa712f9015d4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x92e52a1A235d9A103D970901066CE910AAceFD37" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd7CDdD45629934c2f6ED3B63217bD8085D7C14A8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9c23D67AEA7B95D80942e3836BCDF7E708A747C2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9e3319636e2126e3c0bc9e3134AEC5e1508A46c7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd780Ae2Bf04cD96E577D3D014762f831d97129d0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5adc961D6AC3f7062D2eA45FEFB8D8167d44b190" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe8780B48bdb05F928697A5e8155f672ED91462F7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD0352a019e9AB9d757776F532377aAEbd36Fd541" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6425c6BE902d692AE2db752B3c268AFAdb099D3b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFb2f26F266Fb2805a387230f2aa0a331b4d96Fba" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x69BEaB403438253f13b6e92Db91F7FB849258263" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc7BbA5b765581eFb2Cdd2679DB5Bea9eE79b201f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xCc80C051057B774cD75067Dc48f8987C4Eb97A5e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x408e41876cCCDC0F92210600ef50372656052a38" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5c3a228510D246b78a3765C20221Cbf3082b44a4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf44745fBd41F6A1ba151df190db0564c5fCc4410" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x809826cceAb68c387726af962713b64Cb5Cb3CCA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB98d4C97425d9908E66E53A6fDf673ACcA0BE986" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x83984d6142934bb535793A82ADB0a46EF0F66B6d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5c743a35E903F6c584514ec617ACEe0611Cf44f3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6758B7d441a9739b98552B373703d8d3d14f9e62" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBC86727E770de68B1060C91f6BB6945c73e10388" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8A1E3930FDe1f151471c368fDBb39F3F63A65B55" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEda8B016efA8b1161208Cf041cD86972eeE0F31E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd0929d411954c47438dc1d871dd6081F5C5e149c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc690F7C7FcfFA6a82b79faB7508c466FEfdfc8c5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x46b9Ad944d1059450Da1163511069C718F699D31" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4D8fc1453a0F359e99c9675954e656D80d996FbF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc72fe8e3Dd5BeF0F9f31f259399F301272eF2a2D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x622dFfCc4e83C64ba959530A5a5580687a57581b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5b26C5D0772E5bbaC8b3182AE9a13f9BB2D03765" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0000000000085d4780B73119b644AE5ecd22b376" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1B957Dc4aEfeed3b4A2351a6A6d5cbfbbA0CeCFa" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9a005c9a89BD72a4Bd27721E7a09A3c11D2b03C4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaBbBB6447B68ffD6141DA77C18c7B5876eD6c5ab" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf3db7560E820834658B590C96234c333Cd3D5E5e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9a0242b7a33DAcbe40eDb927834F96eB39f8fBCB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD49ff13661451313cA1553fd6954BD1d9b6E02b9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDD16eC0F66E54d453e6756713E533355989040E4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE5F166c0D8872B68790061317BB6CcA04582C912" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe25b0BBA01Dc5630312B6A21927E578061A13f55" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5102791cA02FC3595398400BFE0e33d7B6C82267" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEF2463099360a085f1f10b076Ed72Ef625497a06" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfD107B473AB90e8Fbd89872144a3DC92C40Fa8C9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1122B6a0E00DCe0563082b6e2953f3A943855c1F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC011A72400E58ecD99Ee497CF89E3775d4bd732F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA4e8C3Ec456107eA67d3075bF9e3DF3A75823DB0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x07a58629AAF3e1A0d07D8f43114B76BD5EEe3B91" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4672bAD527107471cB5067a887f4656D585a8A31" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x998b3B82bC9dBA173990Be7afb772788B5aCB8Bd" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x814F67fA286f7572B041D041b1D99b432c9155Ee" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFFE02ee4C69eDf1b340fCaD64fbd6b37a7b9e265" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6Ba460AB75Cd2c56343b3517ffeBA60748654D26" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x35a69642857083BA2F30bfaB735dacC7F0bac969" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x58a4884182d9E835597f405e5F258290E46ae7C2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfDBc1aDc26F0F8f8606a5d63b7D3a3CD21c22B23" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x28b5E12CcE51f15594B0b91d5b5AdaA70F684a02" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA15C7Ebe1f07CaF6bFF097D8a589fb8AC49Ae5B3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x01fF50f8b7f74E4f00580d9596cd3D0d6d6E326f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xCA0e7269600d353F70b14Ad118A49575455C0f2f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3893b9422Cd5D70a81eDeFfe3d5A1c6A978310BB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4de2573e27E648607B50e1Cfff921A33E4A34405" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0F02e27745e3b6e9e1310d19469e2b5D7B5eC99A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6888a16eA9792c15A4DCF2f6C623D055c8eDe792" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1FE70bE734e473e5721ea57C8B5B01e6Caa52686" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x28dee01D53FED0Edf5f6E310BF8Ef9311513Ae40" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x63e634330A20150DbB61B15648bC73855d6CCF07" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x001F0aA5dA15585e5b2305DbaB2bac425ea71007" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x355a458d555151D3B27F94227960Ade1504E526a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2f8472dd7ecf7cA760c8f6b45dB20Ca7cf52F8d7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA13f0743951B4f6E3e3AA039f682E17279f52bc3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x23352036E911A22Cfc692B5E2E196692658ADED9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6aEB95F06CDA84cA345c2dE0F3B7f96923a44f4c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9E46A38F5DaaBe8683E10793b06749EEF7D733d1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbf52F2ab39e26E0951d2a02b49B7702aBe30406a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x41AB1b6fcbB2fA9DCEd81aCbdeC13Ea6315F2Bf2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6295Ab2BE04A617747481B292c390BfcA592Cf28" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBe428c3867F05deA2A89Fc76a102b544eaC7f772" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa44E5137293E855B1b7bC7E2C6f8cD796fFCB037" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7e9e431a0B8c4D532C745B1043c7FA29a48D4fBa" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3543638eD4a9006E4840B105944271Bcea15605D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE69a353b3152Dd7b706ff7dD40fe1d18b7802d31" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x44F588aEeB8C44471439D1270B3603c66a9262F1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x076C97e1c869072eE22f8c91978C99B4bcB02591" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc12d099be31567add4e4e4d0D45691C3F58f5663" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9B70740e708a083C6fF38Df52297020f5DfAa5EE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6710c63432A2De02954fc0f851db07146a6c0312" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAF446174961CD544e51B89310581669e8FC00D16" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8810C63470d38639954c6B41AaC545848C46484a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8B40761142B9aa6dc8964e61D0585995425C3D94" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF41e5Fbc2F6Aac200Dd8619E121CE1f05D150077" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd559f20296FF4895da39b5bd9ADd54b442596a61" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf453B5B9d4E0B5c62ffB256BB2378cc2BC8e8a89" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC27C95350eCD634C80dF89db0f10cd5c24B7B11f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xef8CF79C21637fc6f951bcaC348915508a639a41" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE5Dada80Aa6477e85d09747f2842f7993D0Df71C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x13C2fab6354d3790D8ece4f0f1a3280b4A25aD96" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe7D3e4413E29ae35B0893140F4500965c74365e5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbCdfE338D55c061C084D81fD793Ded00A27F226D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE34e1944E776f39B9252790a0527eBDa647aE668" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd2Fa8f92Ea72AbB35dBD6DECa57173d22db2BA49" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6c6EE5e31d828De241282B9606C8e98Ea48526E2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x12759512D326303B45f1ceC8F7B6fd96F387778E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0947b0e6D821378805c9598291385CE7c791A6B2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA017ac5faC5941f95010b12570B812C974469c2C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFc2C4D8f95002C14eD0a7aA65102Cac9e5953b5E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x03C780cD554598592B97b7256dDAad759945b125" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x53066cdDBc0099eb6c96785d9b3DF2AAeEDE5DA3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB62132e35a6c13ee1EE0f84dC5d40bad8d815206" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC343f099d3E41aA5C1b59470450e21E92E2d840b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0B4BdC478791897274652DC15eF5C135cae61E60" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEBBdf302c940c6bfd49C6b165f457fdb324649bc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbbFF862d906E348E9946Bfb2132ecB157Da3D4b4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaaAEBE6Fe48E54f431b0C390CfaF0b017d09D42d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x763186eB8d4856D536eD4478302971214FEbc6A9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb0280743b44bF7db4B6bE482b2Ba7b75E5dA096C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x737F98AC8cA59f2C68aD658E3C3d8C8963E40a4c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3a1Bda28AdB5B0a812a7CF10A1950c920F79BcD3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x47bc01597798DCD7506DCCA36ac4302fc93a8cFb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4a527d8fc13C5203AB24BA0944F4Cb14658D1Db6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x905E337c6c8645263D3521205Aa37bf4d034e745" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9b4e2B4B13d125238Aa0480dD42B4f6fC71b37CC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4Cd988AfBad37289BAAf53C13e98E2BD46aAEa8c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3abdfF32F76b42E7635bdb7e425f0231A5F3aB17" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x139d9397274bb9E2C29A9aa8Aa0b5874d30D62E3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x61f33Da40594cEc1E3Dc900FaF99F861D01e2e7D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6DD4e4Aad29A40eDd6A409b9c1625186C9855b4D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1829aA045E21E0D59580024A951DB48096e01782" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEDD7c94FD7B4971b916d15067Bc454b9E1bAD980" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd99b8A7fA48E25Cce83B81812220A3E03Bf64e5f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x543Ff227F64Aa17eA132Bf9886cAb5DB55DCAddf" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE1Aee98495365fc179699C1bB3E761FA716beE62" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEB9951021698B42e4399f9cBb6267Aa35F82D59D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1c79ab32C66aCAa1e9E81952B8AAa581B43e54E7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1A0F2aB46EC630F9FD638029027b552aFA64b94c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x17e67d1CB4e349B9CA4Bc3e17C7DF2a397A7BB64" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf263292e14d9D8ECd55B58dAD1F1dF825a874b7c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8713d26637CF49e1b6B4a7Ce57106AaBc9325343" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6ea6531b603F270d23d9EDd2d8279135DC5D6773" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x228ba514309FFDF03A81a205a6D040E429d6E80C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4f3AfEC4E5a3F2A6a1A411DEF7D7dFe50eE057bF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4BFFC9B4d4DcF730820a2EdCAD48Ff5D7E0Ae807" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb6F43025B29196Af2dddd69b0a58AFBa079cD600" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4aF328C52921706dCB739F25786210499169AFe6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x347C099f110Ca6761779329D2879957b606b6aCE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF03045a4C8077e38f3B8e2Ed33b8aEE69edF869F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB2135AB9695a7678Dd590B1A996CB0f37BCB0718" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4DF47B4969B2911C966506E3592c41389493953b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc20464e0C373486d2B3335576e83a218b1618A5E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4162178B78D6985480A308B2190EE5517460406D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x491C9A23DB85623EEd455a8EfDd6AbA9b911C5dF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x10bA8C420e912bF07BEdaC03Aa6908720db04e0c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8400D94A5cb0fa0D041a3788e395285d61c9ee5e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF3b3Cad094B89392fcE5faFD40bC03b80F2Bc624" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfe5F141Bf94fE84bC28deD0AB966c16B17490657" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9D86b1B2554ec410ecCFfBf111A6994910111340" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7B0C06043468469967DBA22d1AF33d77d44056c8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2859021eE7F2Cb10162E67F33Af2D22764B31aFf" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x55296f69f40Ea6d20E478533C15A6B08B654E758" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x88d50B466BE55222019D71F9E8fAe17f5f45FCA1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf51EBf9a26DbC02B13F8B3a9110dac47a4d62D78" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x78a73B6CBc5D183CE56e786f6e905CaDEC63547B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x76960Dccd5a1fe799F7c29bE9F19ceB4627aEb2f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1C83501478f1320977047008496DACBD60Bb15ef" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEcE83617Db208Ad255Ad4f45Daf81E25137535bb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1CCAA0F2a7210d76E1fDec740d5F323E2E1b1672" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6fB3e0A217407EFFf7Ca062D46c26E5d60a14d69" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5dbe296F97B23C4A6AA6183D73e574D02bA5c719" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5Cf04716BA20127F1E2297AdDCf4B5035000c9eb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA9d2927d3a04309E008B6af6E2e282AE2952e7fD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1dEa979ae76f26071870F824088dA78979eb91C8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB1eeF147028E9f480DbC5ccaA3277D417D1b85F0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA4eA687A2A7F29cF2dc66B39c68e4411C0D00C49" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc528c28FEC0A90C083328BC45f587eE215760A0F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x84F7c44B6Fed1080f647E354D552595be2Cc602F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB6eD7644C69416d67B522e20bC294A9a9B405B31" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB9bb08AB7E9Fa0A1356bd4A39eC0ca267E03b0b3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEA26c4aC16D4a5A106820BC8AEE85fd0b7b2b664" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC80c5E40220172B36aDee2c951f26F2a577810C5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB5DBC6D3cf380079dF3b27135664b6BCF45D1869" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0E8d6b471e332F140e7d9dbB99E5E3822F728DA6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x81b4D08645DA11374a03749AB170836E4e539767" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xCDB7eCFd3403Eef3882c65B761ef9B5054890a47" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "TM2-0C4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAf8A215e81FAea7C180CE22b72483525121813BD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x26DB5439F651CAF491A87d48799dA81F191bDB6b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb056c38f6b7Dc4064367403E26424CD2c60655e1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x75c5eE419331B6150879530D06f9Ba054755F1DA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf091Cf09c51811819DB705710e9634B8bf18F164" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0f8c45B896784A1E408526B9300519ef8660209c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x624d520BAB2E4aD83935Fa503fB130614374E850" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD6e1401a079922469e9b965Cb090ea6fF64C6839" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC86D054809623432210c107af2e3F619DcFbf652" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf53C580bC4065405bC649cC077fF4f2F28528f4B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA8258AbC8f2811dd48EccD209db68F25E3E34667" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8a77e40936BbC27e80E9a3F526368C967869c86D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3c4bEa627039F0B7e7d21E34bB9C9FE962977518" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3c4a3ffd813a107febd57B2f01BC344264D90FdE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa3d58c4E56fedCae3a7c43A725aeE9A71F0ece4e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9ab165D795019b6d8B3e971DdA91071421305e5a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA2A54f1Ec1f09316eF12c1770D32ed8F21B1Fb6A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEB9A4B185816C354dB92DB09cC3B50bE60b901b6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x436F0F3a982074c4a05084485D421466a994FE53" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb9EF770B6A5e12E45983C5D80545258aA38F3B78" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4AaC461C86aBfA71e9d00d9a2cde8d74E4E1aeEa" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1ed7AE1F0E2Fa4276DD7ddC786334a3dF81D50c0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8e1b448EC7aDFc7Fa35FC2e885678bD323176E34" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4D9e23a3842fE7Eb7682B9725cF6c507C424A41B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDF347911910b6c9A4286bA8E2EE5ea4a39eB2134" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8E5610ab5E39d26828167640EA29823fe1dD5843" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x954b890704693af242613edEf1B603825afcD708" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6863bE0e7CF7ce860A574760e9020D519a8bDC47" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA86a0Da9D05d0771955DF05B44Ca120661aF16DE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2c949199cFF14AEAF1B33D64Db01F48FB57f592f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDF2C7238198Ad8B389666574f2d8bc411A4b7428" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbF59e6fe2Bc4eE8D303E493390b4aacab16fcc91" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x423b5F62b328D0D6D44870F4Eee316befA0b2dF5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4f27053F32edA8Af84956437Bc00e5fFa7003287" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x943ED852DadB5C3938ECdC6883718df8142DE4C8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE3F4b4A5d91e5cB9435B947F090A319737036312" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0f1Ed66c251BcB52ecF7E67ac64Bb72482048aDB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd37532D304214D588aeeaC4c365E8F1d72e2304A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfc05987bd2be489ACCF0f509E44B0145d68240f7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf3586684107CE0859c44aa2b2E0fB8cd8731a15a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2bBA3CF6DE6058cc1B4457Ce00deb359E2703d7F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x02F61Fd266DA6E8B102D4121f5CE7b992640CF98" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD9A12Cde03a86E800496469858De8581D3A5353d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xac2e58A06E6265F1Cf5084EE58da68e5d75b49CA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x765f0C16D1Ddc279295c1a7C24B0883F62d33F75" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6A27348483D59150aE76eF4C0f3622A78B0cA698" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x865ec58b06bF6305B886793AA20A2da31D034E68" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4375E7aD8A01B8eC3Ed041399f62D9Cd120e0063" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF4B54874cD8a6C863e3A904c18fDa964661Ec363" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x83e2BE8d114F9661221384B3a50d24B96a5653F5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x64A60493D888728Cf42616e034a0dfEAe38EFCF0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x97AEB5066E1A590e868b511457BEb6FE99d329F5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x44449Fa4d607F807d1eD4a69ad942971728391C8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0707681F344dEB24184037fC0228856F2137B02E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1A66E09F7DccC10eAe46e27cfA6B8d44a50dF1E7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x57Ab1E02fEE23774580C119740129eAC7081e9D3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF8e06E4e4A80287FDCa5b02dcCecAa9D0954840F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5DBAC24e98E2a4f43ADC0DC82Af403fca063Ce2c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF4FaEa455575354d2699BC209B0a65CA99F69982" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x986EE2B944c42D017F52Af21c4c69B84DBeA35d8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1410434b0346f5bE678d0FB554E5c7ab620f8f4a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdfdc0D82d96F8fd40ca0CFB4A288955bECEc2088" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5c64031C62061865E5FD0F53d3CDaeF80f72E99D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x24DCc881E7Dd730546834452F21872D5cb4b5293" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x05aAaA829Afa407D83315cDED1d45EB16025910c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x081F67aFA0cCF8c7B17540767BBe95DF2bA8D97F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB4EFd85c19999D84251304bDA99E90B92300Bd93" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa95592DCFfA3C080B4B40E459c5f5692F67DB7F8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x63f584FA56E60e4D0fE8802b27C7e6E3b33E007f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4689a4e169eB39cC9078C0940e21ff1Aa8A39B9C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x076641aF1B8f06B7f8C92587156143C109002cbe" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x464eBE77c293E473B48cFe96dDCf88fcF7bFDAC0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x60C24407d01782C2175D32fe7C8921ed732371D1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC8058D59e208399B76E66Da1EC669dD6B1BeE2ea" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xce5114d7fa8361F0c088EE26FA3A5446C4a1f50b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd8950fDeaa10304B7A7Fd03a2FC66BC39f3c711a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD1E10C37A27d95D95720291b1Dc6f12F74C71443" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9d9223436dDD466FC247e9dbbD20207e640fEf58" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAAE81c0194D6459F320b70CA0CEdf88e11a242CE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe3278DF3eB2085bA9B6899812A99a10f9CA5E0Df" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4A42d2c580f83dcE404aCad18dab26Db11a1750E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFBc3c8Aad80B5934D134e2CCE065702FF254AD7D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF03f8D65BaFA598611C3495124093c56e8F638f0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd2946be786F35c3Cc402C29b323647aBda799071" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFbe878CED08132bd8396988671b450793C44bC12" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x81705082eF9f0D660f07BE80093D46d826d48b25" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAA19961b6B858D9F18a115f25aa1D98ABc1fdBA8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb5b8F5616Fe42d5ceCA3e87F3FddbDd8F496d760" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbF5496122CF1bB778E0cBE5eaB936f2BE5fC0940" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x47da42696A866CDC61A4C809A515500a242909C1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x95C9bD1f81CEe7391dA3EaC81693E60F3292c1E0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4BBbC57aF270138Ef2FF2C50DbfAD684e9E0e604" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD8698a985B89650d0A70f99AD2909bD0c0b4b51c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA849EaaE994fb86Afa73382e9Bd88c2B6b18Dc71" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF8C595D070d104377f58715ce2E6C93E49a87f3c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFb5a551374B656C6e39787B1D3A03fEAb7f3a98E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdB25f211AB05b1c97D595516F45794528a807ad8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x331fA6C97c64e47475164b9fC8143b533c5eF529" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFb8Bf095eBcdAd57D2e37573a505E7d3bAFDD3CC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB8DdC930c2bAB6c71610A2BE639036E829F9C10b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFc44EC51C80e35A87Bc2140299B1636eC83DFb04" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0bC61DdED5F6710c637cf8288Eb6058766ce1921" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xff2b3353c3015E9f1FBF95B9Bda23F58Aa7cE007" - }, - { - "coin": 818, - "type": "token", - "currency": "USD", - "token_id": "0x0000000000000000000000000000456E65726779" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8D5682941cE456900b12d47ac06a88b47C764CE1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4a6058666cf1057eaC3CD3A5a614620547559fc9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5d48F293BaED247A2D0189058bA37aa238bD4725" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA984A92731C088F1eA4D53b71A2565a399F7D8D5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x554FFc77F4251a9fB3c0E3590a6a205f8d4e067D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0E69D0A2bbB30aBcB7e5CfEA0E4FDe19C00A8d47" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x840fe75ABfaDc0F2d54037829571B2782e919ce4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDA80B20038BDF968C7307BB5907A469482CF6251" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0223fc70574214F65813fE336D870Ac47E147fAe" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x34364BEe11607b1963d66BCA665FDE93fCA666a8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA31108E5BAB5494560Db34c95492658AF239357C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x31f3D9D1BeCE0c033fF78fA6DA60a6048F3E13c5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9972A0F24194447E73a7e8b6CD26a52e02DDfAD5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4212FEa9FEc90236eCc51E41e2096B16CEB84555" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x37E1160184F7dD29f00b78C050Bf13224780b0B0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa6714a2e5f0B1bdb97b895b0913b4FcD3a775E4D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC16b542ff490e01fcc0DC58a60e1EFdc3e357cA6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1014613E2B3CBc4d575054D4982E580d9b99d7B1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9c794f933b4DD8B49031A79b0f924D68BEF43992" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x05984006707585F66465e8A6505341f46b64fA7A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBC46D9961A3932f7D6b64abfdeC80C1816C4B835" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x18f5B4908e8861e3114Ba9a0a9a4E84c5F180Cc0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4618519de4C304F3444ffa7f812dddC2971cc688" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x910Dfc18D6EA3D6a7124A6F8B5458F281060fa4c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x171D750d42d661B62C277a6B486ADb82348c3Eca" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC05d14442A510De4D3d71a3d316585aA0CE32b50" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFA456Cf55250A839088b27EE32A424d7DAcB54Ff" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc9859fccC876e6b4B3C749C5D29EA04F48aCb74F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfF5c25D2F40B47C4a37f989DE933E26562Ef0Ac0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x66BaD545596fb17a0B4ebDC003a85dEF10E8F6Ae" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x20F7A3DdF244dc9299975b4Da1C39F8D5D75f05A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x245ef47D4d0505ECF3Ac463F4d81f41ADE8f1fd1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9F195617fA8fbAD9540C5D113A99A0a0172aaEDC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x153eD9CC1b792979d2Bde0BBF45CC2A7e436a5F9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x832904863978b94802123106e6eB491BDF0Df928" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x02F2D4a04E6E01aCE88bD2Cd632875543b2eF577" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4b317864a05c91225ab8f401EC7be0AeB87e9c12" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7A74c427c833baD2A638E0fb203BA2C728f557C1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x29536B7Ca7029b5cDDEB03c0451715615AcA35ba" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBB1fA4FdEB3459733bF67EbC6f893003fA976a82" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8E766F57F7d16Ca50B4A0b90b88f6468A09b0439" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x17Aa18A4B64A55aBEd7FA543F2Ba4E91f2dcE482" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x851017523AE205adc9195e7F97D029f4Cfe7794c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x170b275CEd089FffAEBFe927F445a350ED9160DC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8a88f04e0c905054D2F33b26BB3A46D7091A039A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe530441f4f73bDB6DC2fA5aF7c3fC5fD551Ec838" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x60c68a87bE1E8a84144b543AAcfA77199cd3d024" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x74FD51a98a4A1ECBeF8Cc43be801cce630E260Bd" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x72430A612Adc007c50e3b6946dBb1Bb0fd3101D1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x054C64741dBafDC19784505494029823D89c3b13" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf4065e4477e91C177DED71A7A6fb5ee07DC46BC9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1fC52f1ABade452Dd4674477D4711951700b3d27" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x973e52691176d36453868D9d86572788d27041A9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6704B673c70dE9bF74C8fBa4b4bd748F0e2190E1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xeE4458e052B533b1aABD493B5f8c4d85D7B263Dc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3e65E1eeFdE5Ea7ccfC9a9a1634AbE90f32262f8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1Cb3209D45B2a60B7fBCA1cCDBF87f674237A4aa" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3f06B5D78406cD97bdf10f5C420B241D32759c80" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFEF3884b603C33EF8eD4183346E093A173C94da6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5D4d57cd06Fa7fe99e26fdc481b468f77f05073C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8fC01E6CbDfFaf09B54F423f9Bb1F856b22e47b2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x13E9EC660d872f55405d70e5C52D872136F0970c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAAD54C9f27B876D2538455DdA69207279fF673a5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4a220E6096B25EADb88358cb44068A3248254675" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf8b358b3397a8ea5464f8cc753645d42e14b79EA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbdEB4b83251Fb146687fa19D1C660F99411eefe3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x21d5678A62DFe63a47062469Ebb2fAc2817D8832" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x846C66cf71C43f80403B51fE3906B3599D63336f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2AEC18c5500f21359CE1BEA5Dc1777344dF4C0Dc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6059F55751603eAd7Dc6d280ad83A7B33D837C90" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE2492F8D2A2618d8709Ca99b1d8d75713Bd84089" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbD4B60a138b3fce3584EA01f50c0908c18f9677A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD7b3669C7d3E38aB5a441383D41F25E003e02148" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x49bD2DA75b1F7AF1E4dFd6b1125FEcDe59dBec58" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9a794Dc1939F1d78fa48613b89B8f9d0A20dA00E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x48C1B2f3eFA85fbafb2ab951bF4Ba860a08cdBB7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7995ab36bB307Afa6A683C24a25d90Dc1Ea83566" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4CcC3759eB48fAF1c6cfadaD2619E7038db6b212" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x05D412CE18F24040bB3Fa45CF2C69e506586D8e8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB6259685685235c1eF4B8529e7105f00BD42b9f8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE8663A64A96169ff4d95b4299E7ae9a76b905B31" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb41f09a973a85c7F497c10B00a939dE667B55a78" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x016396044709EB3edc69C44f4d5Fa6996917E4e8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x57C75ECCc8557136D32619a191fBCDc88560d711" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x501262281B2Ba043e2fbf14904980689CDDB0C78" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc56b13ebbCFfa67cFb7979b900b736b3fb480D78" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5AB793E36070F0fac928EA15826b0c1Bc5365119" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x241bA672574A78a3A604CDd0a94429A73a84a324" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDE1E0AE6101b46520cF66fDC0B1059c5cC3d106c" - }, - { - "coin": 1024, - "type": "token", - "currency": "USD", - "token_id": "ong" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x41875C2332B0877cDFAA699B641402b7D4642c32" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd82Df0ABD3f51425Eb15ef7580fDA55727875f14" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEf51c9377FeB29856E61625cAf9390bD0B67eA18" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x76974C7B79dC8a6a109Fd71fd7cEb9E40eff5382" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1602af2C782cC03F9241992E243290Fccf73Bb13" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xca694eb79eF355eA0999485d211E68F39aE98493" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5301Eae39a4cBa1CC2A74E861fDed062cA3E3420" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5EB87cAA0105a63aa87A36C7Bd2573Bd13E84faE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBAE235823D7255D9D48635cEd4735227244Cd583" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7025baB2EC90410de37F488d1298204cd4D6b29d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbf8fB919A8bbF28e590852AeF2D284494eBC0657" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x009e864923b49263c7F10D19B7f8Ab7a9A5AAd33" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x13119E34E140097a507B07a5564bDe1bC375D9e6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2D3E7D4870a51b918919E7B851FE19983E4c38d5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x049399a6B048D52971F7D122aE21A1532722285F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4289c043A12392F1027307fB58272D8EBd853912" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd9485499499d66B175Cf5ED54c0a19f1a6Bcb61A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x613Fa2A6e6DAA70c659060E86bA1443D2679c9D7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9064c91e51d7021A85AD96817e1432aBf6624470" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x78c292D1445E6b9558bf42e8BC369271DeD062eA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x499A6B77bc25C26bCf8265E2102B1B3dd1617024" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4AC00f287f36A6Aad655281fE1cA6798C9cb727b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB2E260F12406c401874EcC960893C0f74Cd6aFcd" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF84df2db2C87dd650641f8904aF71EbFC3ddE0Ea" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x38c87AA89B2B8cD9B95b736e1Fa7b612EA972169" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x68909e586eeAC8F47315e84B4c9788DD54Ef65Bb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x749f35Ff65932E68267dd82F6CD85eeA735d700E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf14922001A2FB8541a433905437ae954419C2439" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7C2E5b7ec572199D3841f6a38F7D4868BD0798f1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1a2277C83930b7a64C3e3D5544Eaa8C4f946B1B7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x48FF53777F747cFB694101222a944dE070c15D36" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd42debE4eDc92Bd5a3FBb4243e1ecCf6d63A4A5d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x36B4B58DE030E93775E151a78D796039a11a2548" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3FD8f39A962eFDA04956981C31AB89FAB5FB8bC8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD7394087E1DBBE477FE4F1CF373B9Ac9459565fF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4234f63B1D202F6c016Ca3b6a0d41d7d85f17716" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2ba6b1E4424e19816382d15937739959F7DA5fD8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD938137E6d96c72E4a6085412aDa2daD78ff89c4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc54083e77F913a4f99E1232Ae80c318ff03c9D17" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5D64D850c8368008aFB39224E92aD0DcEFf3CF38" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x884181554dfA9e578d36379919C05C25dC4a15bB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaF1250fa68D7DECD34fD75dE8742Bc03B29BD58e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAAf37055188Feee4869dE63464937e683d61b2a1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x97Cb5Cc1b2e10cC56DC16ab9179f06dfEDBe41A2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x05860d453C7974CbF46508c06CBA14e211c629Ce" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x056Fd409E1d7A124BD7017459dFEa2F387b6d5Cd" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDDD460bBD9F79847ea08681563e8A9696867210C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa958E706fc1934E26a3D0c32f471B54F733D0009" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x780116D91E5592E58a3b3c76A351571b39abCEc6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1c4b7d0e1885bd7667Af3378E0c538F74E712006" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8578530205CEcbe5DB83F7F29EcfEEC860C297C2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8606a8F28e1e2FD50B9074d65C01548B1F040B32" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x755eb14D2fefF2939EB3026f5CaD9D03775b9fF4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0142C3B2fC51819B5aF5dFc4AA52Df9722790851" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x574F84108a98c575794F75483d801d1d5DC861a5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe11609b9a51CAF7d32A55896386aC52ED90e66F1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xcec38306558a31cdbb2a9d6285947C5b44A24f3e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8E870D67F660D95d5be530380D0eC0bd388289E1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2F9b6779c37DF5707249eEb3734BbfC94763fBE2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1F54638b7737193FFd86c19Ec51907A7c41755D8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0DB8D8b76BC361bAcbB72E2C491E06085A97Ab31" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x687BfC3E73f6af55F0CccA8450114D107E781a0e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC72ED4445B3fe9f0863106E344E241530d338906" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb052F8A33D8bb068414EaDE06AF6955199f9f010" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x19ea630bCBc1a511a16e65b6ECd447c92E1C087c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBC7F402F3bC1c6D56C8041F551b47a0AD7714D1b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBd0793332e9fB844A52a205A233EF27a5b34B927" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x23Ccc43365D9dD3882eab88F43d515208f832430" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaD5Fe5B0B8eC8fF4565204990E4405B2Da117d8e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x10086399DD8c1e3De736724AF52587a2044c9fA2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x56D1aE30c97288DA4B58BC39F026091778e4E316" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x567300e14f8d67e1F6720a95291Dce2511a86723" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE13Ef257cF4D5Df928ca11d230427C037666d466" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x92A5B04D0ED5D94D7a193d1d334D3D16996f4E13" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBA3a79D758f19eFe588247388754b8e4d6EddA81" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xcAaa93712BDAc37f736C323C93D4D5fDEFCc31CC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdf1338FbAfe7aF1789151627B886781ba556eF9a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x14C926F2290044B647e1Bf2072e67B495eff1905" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x89c6c856a6db3e46107163D0cDa7A7FF211BD655" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7CC62d8E80Be9bEa3947F3443aD136f50f75b505" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2F141Ce366a2462f02cEA3D12CF93E4DCa49e4Fd" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd07D9Fe2d2cc067015E2b4917D24933804f42cFA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa0d440C6DA37892Dc06Ee7930B2eedE0634FD681" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3918C42F14F2eB1168365F911f63E540E5A306b5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x81E74a3eA4BaB2277aA3b941E9D9F37B08Ac5374" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7bA19B7F7d106A9a1e0985397B94F38EEe0b555e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2ecB13A8c458c379c4d9a7259e202De03c8F3D19" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7528E3040376EdD5DB8263Db2F5bd1beD91467FB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1966d718A565566e8E202792658D7b5Ff4ECe469" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe7E4279b80D319EDe2889855135A22021baf0907" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD45247c07379d94904E0A87b4481F0a1DDfa0C64" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb0a0a070640B450eB136DC377208469ee4F49fbc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7C84e62859D0715eb77d1b1C4154Ecd6aBB21BEC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x96B0bF939D9460095C15251F71Fda11e41DcBddB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4D8bfe7EA0f46486Fd40FC4df60CF39f7568BEE8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x72c9Fb7ED19D3ce51cea5C56B3e023cd918baaDf" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7aBc60B3290F68c85f495fD2e0c3Bd278837a313" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB3e2Cb7CccfE139f8FF84013823Bf22dA6B6390A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0F612a09eAd55Bb81b6534e80ed5A21Bf0a27B16" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFf19138b039D938db46bDDA0067DC4BA132ec71C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x869b1F57380aE501d387b19262EFD3C0Eb7501b0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE95990825AAB1a7f0Af4cc648f76a3Bcc99F25B2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x87026F792D09960232CA406E80C89BD35BAfE566" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x813b428aF3920226E059B68A62e4c04933D4eA7a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFE39e6a32AcD2aF7955Cb3D406Ba2B55C901f247" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC38f1fb49acDf2f1213CAf3319F6Eb3ea2cB7527" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x59BE937f05cf2c406b61c42C6c82a093fA54edfE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x419B8ED155180A8c9C64145e76DaD49c0A4Efb97" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd4a293aE8bB9E0BE12E99eB19d48239e8c83a136" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5b11aAcB6Bddb9ffab908FDCE739Bf4aed554327" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1da015eA4AD2d3e5586E54b9fB0682Ca3CA8A17a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2344871f523cBb28A4f60045531184cF1F03Ad24" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2d184014b5658C453443AA87c8e9C4D57285620b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xcA2796F9F61dc7b238Aab043971e49c6164DF375" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe1A178B681BD05964d3e3Ed33AE731577d9d96dD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x122A86b5DFF2D085AfB49600b4cd7375D0d94A5f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3c6Da7763cAA0e4b684BbC733f04a8EC08Af3762" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0ea984e789302B7B612147E4e4144e64f21425Eb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x67a9099f0008C35C61c00042cd9Fb03684451097" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x49614661737EfBFC6a102efaeefDc8E197f7CC0e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x78a2a1029E3168b49d3A276C787050fF5106dCF2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x922aC473A3cC241fD3a0049Ed14536452D58D73c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xca00bC15f67Ebea4b20DfaAa847CAcE113cc5501" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD29F0b5b3F50b07Fe9a9511F7d86F4f4bAc3f8c4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBb1f24C0c1554b9990222f036b0AaD6Ee4CAec29" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xeaf61FC150CD5c3BeA75744e830D916E60EA5A9F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbC647aAd10114B89564c0a7aabE542bd0cf2C5aF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB5Ca46cF1da09248126682a7bd72401fd7A6b151" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x15bdA08c3afbf5955D6e9B235Fd55a1FD0DbC829" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4E15361FD6b4BB609Fa63C81A2be19d873717870" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x497bAEF294c11a5f0f5Bea3f2AdB3073DB448B56" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x47d1a59cBDd19AEE060C859C0009277E245328ae" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x77C07555aF5ffdC946Fb47ce15EA68620E4e7170" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1563D521ba309e2Ad9f4aFfD6f4dE9759E8d4F21" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x26CB3641aaA43911f1D4cB2ce544eb652AAc7c47" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x93ED3FBe21207Ec2E8f2d3c3de6e058Cb73Bc04d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x737fA0372c8D001904Ae6aCAf0552d4015F9c947" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6b193e107A773967bD821bCf8218f3548Cfa2503" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa838be6E4b760E6061D4732D6B9F11Bf578f9A76" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x36D10c6800D569bb8C4fE284a05fFE3B752F972c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEA54C81fe0f72DE8e86B6dC78a9271AA3925E3B5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd5dad1DB7F112037c0c6Cf0792dc2a7866Bfd136" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2167FB82309CF76513E83B25123f8b0559d6b48f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFE76BE9cEC465ed3219a9972c21655D57d21aec6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDAC4AE188AcE3C8985765eDc6C9B4739D4845DdC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc6AbF3C09341741Ac6041B0B08195701bdFD460C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x174aFE7A032b5A33a3270a9f6C30746E25708532" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4D807509aECe24C0fa5A102b6a3B059Ec6E14392" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x37F04d2C3AE075Fad5483bB918491F656B12BDB6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x12f649A9E821F90BB143089a6e56846945892ffB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xED494c9e2F8E34e53BDD0EA9B4d80305cb15C5c2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBe6C8f2810EF39420d2DC2901b8414C8c45FEE6D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1aBdb309aa592f00a101c545168BFDF9a6Ec61CE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3E1d5A855aD9D948373aE68e4fe1f094612b1322" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAcfa209Fb73bF3Dd5bBfb1101B9Bc999C49062a5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x286708f069225905194673755F12359e6afF6FE1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2Fb12bccF6f5Dd338b76Be784A93ade072425690" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC45DbdF28844fdB1482C502897d433aC08d6cCd0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC28e931814725BbEB9e670676FaBBCb694Fe7DF2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5Ca381bBfb58f0092df149bD3D243b08B9a8386e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4946Fcea7C692606e8908002e55A582af44AC121" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x77599D2C6DB170224243e255e6669280F11F1473" - }, - { - "coin": 195, - "type": "token", - "currency": "USD", - "token_id": "TG37mUxRUaH1E8DWSrrmoQ79BnZn1yHztb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA858bC1b71a895Ee83B92F149616F9B3F6Afa0FB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA0b73E1Ff0B80914AB6fe0444E65848C4C34450b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x25B6325f5BB1c1E03cfbC3e53F470E1F1ca022E3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAE31b85Bfe62747d0836B82608B4830361a3d37a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x70c621f949b6556c4545707a2d5d73A776b98359" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x47e67BA66b0699500f18A53F94E2b9dB3D47437e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x58b6A8A3302369DAEc383334672404Ee733aB239" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd947b0ceab2A8885866B9A04A06AE99DE852a3d4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE14A603f7c77d4101A87859b8736a04CFD85C688" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5635ddEaBf9cdDA686995Fe90BEB5411831563FC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd5f788ca0de8f17cBDe1D1E35aA8F005A87fa00b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x04A020325024F130988782bd5276e53595e8d16E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x722F2f3EaC7e9597C73a593f7CF3de33Fbfc3308" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x97fB6Fc2AD532033Af97043B563131C5204F8A35" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB37a769B37224449d92AAc57dE379E1267Cd3B00" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x21aB6c9fAC80C59D401b37cB43F81ea9DDe7Fe34" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8971f9fd7196e5cEE2C1032B50F656855af7Dd26" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x56325d180Ec3878A9028AfC7B0EDCEe7486Cc9df" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x86E44543164D9b97B14ef7f6f3aB7bA670CAB346" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2C5dcd12141c56FBEa08e95f54f12c8B22d492Eb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF1290473E210b2108A85237fbCd7b6eb42Cc654F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8b79656FC38a04044E495e22fAD747126ca305C4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE884cc2795b9c45bEeac0607DA9539Fd571cCF85" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaD22f63404f7305e4713CcBd4F296f34770513f4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd44bb6663936CAb1310584A277f7DAa6943d4904" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xacACa5b8805636608e14C64b0bFFfC2Deb2C6cEc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8De67D55C58540807601dBf1259537BC2DFfc84D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1C289a12A8552B314D0d153d6991fd27a54Aa640" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x752FF65b884b9C260D212C804E0b7ACEea012473" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0BEf619cF38cF0c22967289b8419720fBd1Db9f7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5acD19b9c91e596b1f062f18e3D02da7eD8D1e50" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6400B5522f8D448C0803e6245436DD1c81dF09ce" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x06e0feB0D74106c7adA8497754074D222Ec6BCDf" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0775C81A273B355e6a5b76e240BF708701F00279" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x26DDF6CabADcBF4F013841BD8d914830BeB0d984" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9a49f02e128a8E989b443a8f94843C0918BF45E7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x658D79c02A4829B5efA49254F627287e92458ECD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x018d7D179350f1Bb9853D04982820E37ccE13a92" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE99A894a69d7c2e3C92E61B64C505A6a57d2bC07" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFe1D71498DA3261844eC14325bdbc93c0F7579f0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF3e70642c28f3F707408c56624c2F30eA9F9FcE3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd50649AAb1D39d68BC965E0F6D1cfe0010e4908b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb1c1Cb8C7c1992dba24e628bF7d38E71daD46aeB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3DB6Ba6ab6F95efed1a6E794caD492fAAabF294D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3C6A7aB47B5F058Be0e7C7fE1A4b7925B8aCA40e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599" - }, - { - "coin": 195, - "type": "token", - "currency": "USD", - "token_id": "1002000" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA4Bdb11dc0a2bEC88d24A3aa1E6Bb17201112eBe" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa66Daa57432024023DB65477BA87D4E7F5f95213" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2Fc246aA66F0da5bB1368F688548ecBBE9bdee5d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x446C9033E7516D820cc9a2ce2d0B7328b579406F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5b53f9755f82439CBA66007Ec7073c59E0da4A7D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaff84e86d72EDb971341a6A66eb2dA209446FA14" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0198f46f520F33cd4329bd4bE380a25a90536CD5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAec7d1069e3a914a3EB50f0BFB1796751f2ce48a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEc6c861C2a2b1E5ff5336731bC80c29dBFf88273" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x94236591125E935F5ac128Bb3d5062944C24958c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb683D83a532e2Cb7DFa5275eED3698436371cc9f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9CCbd05d4d25c745d49F5e6BF17e09113Eb4c769" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4983F767b1Bc44328E434729dDabea0a064cA1aC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe9fa21E671BcfB04E6868784b89C19d5aa2424Ea" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x07eF9E82721AC16809D24DAfBE1792Ce01654DB4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd6875274b000462F59e9327cbDe2cEf637914569" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x15A664416E42766A6cC0a1221d9C088548a6E731" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD8002cD05d5B2a85557e1CAAa179cC2408D5ad42" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x796E47B85A0d759F300f1de96A3583004235D4D8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4bD70556ae3F8a6eC6C4080A0C327B24325438f3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0C6E8a8358cBde54F8e4Cd7f07D5ac38aec8C5a4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEEd3aE7b0F8b5B9BB8C035A9941382B1822671CD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBac7A1798350cdf2Dbfe0c210C2C9861223f4B31" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1d464Ac5e046e5fE280c9588eDF8eB681b07008F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x21D5A14e625d767Ce6b7A167491C2d18e0785fDa" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xADF8B8050639b6236915f7516d69dE714672F0bF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0F72714B35a366285Df85886A2eE174601292A17" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0a2D9370cF74Da3FD3dF5d764e394Ca8205C50B6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2eC95B8edA549B79a1248335A39d299d00Ed314C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1864cE27E9F7517047933CaAE530674e8C70b8A7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6fE355c62C6faf6946cE888fFABa9fD12355ae27" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x17B26400621695c2D8C2D8869f6259E82D7544c4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1D287CC25dAD7cCaF76a26bc660c5F7C8E2a05BD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9f0f1Be08591AB7d990faf910B38ed5D60e4D5Bf" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x919D3a363776B1ceec9352610c82dfaf80Edc32d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x01cC4151fe5f00EfB8dF2F90ff833725d3a482a3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5c872500c00565505F3624AB435c222E558E9ff8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4b7aD3a56810032782Afce12d7d27122bDb96efF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB31C219959E06f9aFBeB36b388a4BaD13E802725" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8290333ceF9e6D528dD5618Fb97a76f268f3EDD4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x49D09cDa1Deb8a1680F1270C5ed15218fc4B18f0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa957045A12D270e2eE0dcA9A3340c340e05d4670" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8CC3E2BdC17682c622eB789EDA23FbD6988C84Da" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF29226914595052a04F5AFbe6410D0C3eD707548" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x688478f003b8D0F10b8af2122bF20378555EF958" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x61B2d3eA9f1c6b387C985C73d40e8fBfb284E5C7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8275eBF521Dc217aa79C88132017A5BCEf001dd9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x30680AC0a8A993088223925265fD7a76bEb87E7F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE5B826Ca2Ca02F09c1725e9bd98d9a8874C30532" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x420167D87d35c3A249b32Ef6225872fBD9aB85D2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x57C09A8de0b0F471F8567609777aDdFfb5c46a08" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1C1C14A6B5074905Ce5d367B0A7E098b58EbFD47" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x26fb86579e371c7AEdc461b2DdEF0A8628c93d3B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc15A399c4eA7815fE36857C9E290EE452A5D6B21" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9B39A0B97319a9bd5fed217c1dB7b030453bac91" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8A732BC91c33c167F868E0af7e6f31e0776d0f71" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1C5b760F133220855340003B43cC9113EC494823" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x70861e862E1Ac0C96f853C8231826e469eAd37B1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa96F31F1C187c28980176C3A27ba7069f48abDE4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x86e6A4F512b1290c043970B04E0b570D4FC98291" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4a57E687b9126435a9B19E4A802113e266AdeBde" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4946583c5b86E01cCD30c71a05617D06E3E73060" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4F9254C83EB525f9FCf346490bbb3ed28a81C667" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4D13d624a87baa278733c068A174412AfA9ca6C8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA00425D3e2D3E9FF74F3e112B4D3A7978d7D88c2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA0008F510fE9eE696E7E320C9e5cbf61E27791Ee" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x996229D0c6a485c7F4B52E092EAa907cB2def5C6" - }, - { - "coin": 500, - "type": "token", - "currency": "USD", - "token_id": "tfuel" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5925f67d2767d937F47141DAC24166B469558222" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfDF574766BA1A96A553e175aEfFA85ad78063F0B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdcD85914b8aE28c1E62f1C488E1D968D5aaFfE2b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x57652Fc91f522f9EFF0b38CDF1D51f5FB5764215" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7Fe92EC600F15cD25253b421bc151c51b0276b7D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4FBb0B4cD8f960aC3428194F1c94c805D5b35836" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd35833f9255FB28cC6b91aCB8A66Ba6429D6Ef5A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4571f3a386d1bd18E25d70d117e7067FA0Bd9D08" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xff56Cc6b1E6dEd347aA0B7676C85AB0B3D08B0FA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA809d363A66c576A2a814CDBfEFC107C600A55f0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x310c93dfc1C5E34CDF51678103f63C41762089CD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA6446D655a0c34bC4F05042EE88170D056CBAf45" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9F235D23354857EfE6c541dB92a9eF1877689BCB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1822126fEedb4C7d61EecdBE3682FE61e91383d6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x445f51299Ef3307dBD75036dd896565F5B4BF7A5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9B62513c8a27290CF6A7A9e29386e600245EA819" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1367D4a67C1719B58C7e05dF8768226Fa768279a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF4FE95603881D0e07954fD7605E0e9a916e42C44" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x28FB6531723EE54B1073F7f2beB7f2E3C74503Bc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5137A403Dd25e48DE528912a4aF62881e625D801" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8aa688AB789d1848d131C65D98CEAA8875D97eF1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBE6ac6B50F577205c9D107f37b6E205aA6ACC5D4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC64500DD7B0f1794807e67802F8Abbf5F8Ffb054" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8b6CdA5CC518c904e8844f445E1A7C7d2DB0fF16" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x47b28F365Bf4CB38DB4B6356864BDE7bc4B35129" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6F919D67967a97EA36195A2346d9244E60FE0dDB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x00E150D741Eda1d49d341189CAE4c08a73a49C95" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8716Fc5Da009D3A208f0178b637a50F4ef42400F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x979EBc09e55EA0ab563CF7175e4c4b1a03AFc19a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd28cFec79dB8d0A225767D06140aee280718AB7E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4Dd672e77c795844fe3A464eF8eF0FAAe617C8fB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4b94c8567763654101F690Cf4d54957206383b75" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFFc63b9146967A1ba33066fB057EE3722221aCf0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x763Fa6806e1acf68130D2D0f0df754C93cC546B2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x40d52577830E01aAEfa80659aA90ee8B34685F4e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEF19F4E48830093Ce5bC8b3Ff7f903A0AE3E9Fa1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x297E4e5e59Ad72B1B0A2fd446929e76117be0E0a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd9d01D4Cb824219A8F482a0FAd479cB971Fd0628" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x965F109d31CCb77005858DEfaE0Ebaf7B4381652" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF9e5aF7B42D31D51677c75bbBD37c1986eC79AEE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8c15Ef5b4B21951d50E53E4fbdA8298FFAD25057" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x056dD20b01799E9C1952c7c9a5ff4409a6110085" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x187C4B0e3819017a5cf07af81A4E2b16166aAbc6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x19cA83a13b4C4BE43FA82c5E415E16f1D86f57F7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x90D46A9636B973f18186541d1B04ed3621a49Cb0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE9A95d175a5f4C9369f3b74222402eB1b837693b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xc3e2de0b661cF58F66BdE8E896905399ded58af5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xCFAc2916Ec118a0252A7766C513eE7c71b384b5E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x75231F58b43240C9718Dd58B4967c5114342a86c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x56e0B2C7694E6e10391E870774daA45cf6583486" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x985dd3D42De1e256d09e1c10F112bCCB8015AD41" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdD94842C15abfe4c9bAFE4222adE02896Beb064c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf08c68bD5f4194d994FD70726746Bf529eE5a617" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7865af71cf0b288b4E7F654f4F7851EB46a2B7F8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x10c71515602429C19d53011EA7040B87a4894838" - }, - { - "coin": 195, - "type": "token", - "currency": "USD", - "token_id": "TVimprG4oe3i2HapWzPuTh4WtuosRAh5Ew" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5c62Da804298D5972a323C80B539B8E7517a0dDe" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x22dE9912cd3D74953B1cd1F250B825133cC2C1b3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0cbC9b02B8628AE08688b5cC8134dc09e36C443b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd36E9F8F194A47B10aF16C7656a68EBa1DFe88e4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB705268213D593B8FD88d3FDEFF93AFF5CbDcfAE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9D8bE94D0612170cE533AC4d7B43cc3cd91E5a1A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6c37Bf4f042712C978A73e3fd56D1F5738dD7C43" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0F237D5eA7876E0e2906034D98FDB20D43666ad4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6c3BE406174349cfa4501654313d97e6a31072e1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0488401c3F535193Fa8Df029d9fFe615A06E74E6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x247551F2EB3362E222c742E9c788B8957D9BC87e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB66A2131A6B840dd020151f80723CAED603eFB51" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1F35a281036Be57E64e7E7A2A556b4f888A1b829" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9B1E1FC958B83e801d1342F9f9BA7dA3A55bA1eF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xcecede5A20645EAc6ca2032eeEb1063572D63c29" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE54B3458C47E44C37a267E7C633AFEF88287C294" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x799a4202c12ca952cB311598a024C80eD371a41e" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "ONE-5F9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x115eC79F1de567eC68B7AE7eDA501b406626478e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9c197c4b58527fAAAb67CB35E3145166B23D242e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEe9E5eFF401ee921b138490d00CA8D1F13f67A72" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4Fe327c5a809fA721D47b80C5038A0b393E61305" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5aaEFe84E0fB3DD1f0fCfF6fA7468124986B91bd" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa960d2bA7000d58773E7fa5754DeC3Bb40A069D5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1C95b093d6C236d3EF7c796fE33f9CC6b8606714" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2AF5D2aD76741191D15Dfe7bF6aC92d4Bd912Ca3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x744c9c36D1Cc3268a4b9b2e28c60B1752C85E97d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAcCe88F5A63A5e65DB9AA7303720bE16b556E751" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x91e64F39C1FE14492e8FDf5A8B0f305BD218C8A1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x82f4dED9Cec9B5750FBFf5C2185AEe35AfC16587" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8762db106B2c2A0bccB3A80d1Ed41273552616E8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE02784175C3BE0DEa7CC0F284041b64503639E66" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBA14b245d449965BdBeB630ebe135B569474F5b1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6aB4A7d75B0A42B6Bc83E852daB9E121F9C610Aa" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe431a4c5DB8B73c773e06cf2587dA1EB53c41373" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0C6144c16af288948C8fdB37fD8fEc94bfF3d1d9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA806B3FEd6891136940cF81c4085661500aa2709" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x915044526758533dfB918ecEb6e44bc21632060D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7051620d11042c4335069AaA4f10Cd3B4290C681" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x25200235cA7113C2541E70dE737c41f5e9AcD1F6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB9843e5dE0f37d1e22C8075e5814e13565FE7C22" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFF0E5e014cf97e0615cb50F6f39Da6388E2FaE6E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x69d2779533a4D2c780639713558B2cC98c46A9b7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa8EdA9D4Aee0eb882F8752C6bA7e16d9233C9Ad2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd111BCb8C30a600c12F4AF8314235F628EA2Cb3C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x454B9f249bC1492eE995793Bbc3e57b830F1A5e9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x78F5bBC74fb9137A75D85f3C9C3c599Be49f0A56" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd2Bfec3f80b7D966D7657A2ecC5982EE2f49336A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8aD6739649f1fbF079882C14D27862d5c2206660" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdE1289e68aD9e65Ccf50D800C0CEC2D514B80A40" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x94Cb815F4b601B00b363B3177B4D8ed8e0EB7cF2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3810A4Ddf41E586Fa0dbA1463A7951B748cEcFca" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x182A603541a4483c308475147D621bbB4E2587c6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3EB55D5B22Ee0f9B03D59B4994C5AE7fe811bE92" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDe7D85157d9714EADf595045CC12Ca4A5f3E2aDb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1519AFf03b3E23722511D2576c769A77Baf09580" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDf59C8BA19B4d1437d80836b45F1319D9A429EED" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x971d048E737619884f2df75e31c7Eb6412392328" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1B80eeeaDcC590f305945BCc258cFa770Bbe1890" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xae353DaEed8DCc7a9a12027F7e070c0A50B7b6A4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4954Db6391F4feB5468b6B943D4935353596aEC9" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "BTCB-1DE" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "RAVEN-F66" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa249DE6948022783765Fee4850d7b85E43118FCc" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "HNST-3C9" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "COS-2E4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB879DA8b24c9b8685dE8526cF492E954f165D74b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBA50933C268F567BDC86E1aC131BE072C6B0b71a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x11eeF04c884E24d9B7B4760e7476D06ddF797f36" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x01E45B8D0c51f05F17385DD3416fE3aA5BFd89aC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6E605c269E0C92e70BEeB85486f1fC550f9380BD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x174BfA6600Bf90C885c7c01C7031389ed1461Ab9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xEb6985ACD6d0cbff60B88032b0B29Ac1d9D66A1B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1BeEF31946fbbb40B877a72E4ae04a8D1A5Cee06" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3166C570935a7D8554c8f4eA792ff965D2EFe1f2" - }, - { - "coin": 195, - "type": "token", - "currency": "USD", - "token_id": "TVQ6jYV5yTtRsKcD8aRc1a4Kei4V45ixLn" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD46bA6D942050d489DBd938a2C909A5d5039A161" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x95a41fB80ca70306e9Ecf4e51ceA31bD18379C18" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x72955eCFf76E48F2C8AbCCe11d54e5734D6f3657" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x68D3AF29a900D21d092778A9D0aa4F73B1367141" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x186a33d4dBcd700086A26188DcB74E69bE463665" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1c48f86ae57291F7686349F12601910BD8D470bb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3506424F91fD33084466F402d5D97f05F8e3b4AF" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6393E822874728f8Afa7e1C9944E417D37CA5878" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x91cA1146073B0cc9f57A1Dde38a0CCB1ab2a3317" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4F22310C27eF39FEAA4A756027896DC382F0b5E2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB4272071eCAdd69d933AdcD19cA99fe80664fc08" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe0c6CE3e73029F201e5C0Bedb97F67572A93711C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4c1C4957D22D8F373aeD54d0853b090666F6F9De" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAaA89105dab822dBC9a6DE64A23d045D99D5Fd36" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x96c30D5499EF6eA96A9c221Bc18BC39D29c97F27" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "ERD-D06" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0db03B6CDe0B2d427C64a04FeAfd825938368f1F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x42BEdD647E387daBeC65A7dc3A3bAbCc68BB664d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF88951D7B676798705fd3a362ba5B1DBca2B233b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x940a2dB1B7008B6C776d4faaCa729d6d4A4AA551" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xff8Be4B22CeDC440591dcB1E641EB2a0dd9d25A5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA7fC5D2453E3F68aF0cc1B78bcFEe94A1B293650" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2467AA6B5A2351416fD4C3DeF8462d841feeecEC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7788D759F21F53533051A9AE657fA05A1E068fc6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x187D1018E8ef879BE4194d6eD7590987463eAD85" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x44E2ca91ceA1147f1B503e669f06CD11FB0C5490" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6020Da0F7c1857dBE4431Ec92A15cC318D933eAa" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe577e0B200d00eBdecbFc1cd3F7E8E04C70476BE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2D153f2aDCCbe9364F9e4eD5843308AbD0bF93dA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE6877ea9C28fBDeC631ffBc087956d0023A76bF2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x34D6A0F5C2f5D0082141fE73d93B9dd00ca7CE11" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7869c4A1a3f6F8684FBCC422a21aD7Abe3167834" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd31695a1d35E489252CE57b129FD4b1B05E6AcaC" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1FCdcE58959f536621d76f5b7FfB955baa5A672F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfc82bb4ba86045Af6F327323a46E80412b91b27d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x87210f1D3422BA75B6C40C63C78d79324daBcd55" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x36151737B45017234E9570Cf9a1cAc97138953C2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDB7Eab9bA6be88B869F738f6DEeBa96d49Fe13fd" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x07bf5F95851Ef2b2996F192569e406A6FeA2a95a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5EdC1a266E8b2c5E8086d373725dF0690af7e3Ea" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8Ab7404063Ec4DBcfd4598215992DC3F8EC853d7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xcFbf70e33d5163E25B0dad73955c1BD9E8cd8BA2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x420412E765BFa6d85aaaC94b4f7b708C89be2e2B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x225927F8fa71d16EE07968B8746364D1d9F839bD" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "CBIX-3C9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x79cdFa04e3c4EB58C4f49DAE78b322E5b0D38788" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "BAW-DFB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF6dBE88bA55f1793Ff0773c9B1275300f830914F" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "RUNE-B1A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd433138d12beB9929FF6fd583DC83663eea6Aaa5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x28ea81fac7b1719138cBf61267198155b433E00e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x09970aec766b6f3223aCA9111555E99DC50Ff13a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x386cABc0b14A507A4e024DEA15554342865B20DE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA110eeebc0751407bDCAeA4CD230F04A2b82a33a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC9a2C4868F0f96fAaa739b59934Dc9cB304112ec" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2E2E0a28f6585e895DD646a363BAE29B77B88a31" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x40AdFc7c23c22Cc06f94F199a4750D7196F46fbe" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD13c7342e1ef687C5ad21b27c2b65D772cAb5C8c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfc858154C0b2c4A3323046Fb505811F110EBdA57" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3B7f247f21BF3A07088C2D3423F64233d4B069F7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5e3845A1d78DB544613EdbE43Dc1Ea497266d3b8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x50D1c9771902476076eCFc8B2A83Ad6b9355a4c9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x85ca6710D0F1D511d130f6935eDDA88ACBD921bD" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "SHR-DB6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x03B155AF3F4459193A276395dD76e357BB472DA1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA829F97373069ee5d23175e4105dF8fD49238Be7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDF2705d4368Cd2EE3bbfF73594aE47244064dFfB" - }, - { - "coin": 195, - "type": "token", - "currency": "USD", - "token_id": "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x026e62dDEd1a6aD07D93D39f96b9eabd59665e0d" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x07597255910a51509CA469568B048F2597E72504" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1fd27F0CfC6f273b87A5E0F6fCf063422E7bCD6a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x35b08722AA26bE119c1608029CcbC976ac5C1082" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x746DdA2ea243400D5a63e0700F190aB79f06489e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xDe4C5a791913838027a2185709E98c5C6027EA63" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1f88B2eF9ea3B29C90F559e645fC8CC2dc6F5b27" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE5CAeF4Af8780E59Df925470b050Fb23C43CA68C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xeBF4CA5319F406602EEFf68da16261f1216011B5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4Eeea7B48b9C3ac8F70a9c932A8B1E8a5CB624c7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7a3d3c4f30c46F51b814BEe23D970A7c9b757a32" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x197E6bCa6BC2f488ec760a6Ce46B1399cd2954b0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xf6ABff616043C2dA572573dCC583B656297b30e7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x307d45Afbb7E84F82ef3D251A6bb0F00Edf632E4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6b4689E4514957699eDeB2Ee91C947F18E439806" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6CbEDEc4F1ac9D874987D2769596544E0d9161ab" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "CBM-4B2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6CE21e5f5383c95691d243879A86A6025E0870c0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x608f006B6813f97097372d0d31Fb0F11d1CA3E4e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x73C9275c3a2Dd84b5741fD59AEbF102C91Eb033F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD536bBd5414A8C2beEd82a63737B9327D2FA35a6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x01C0987E88F778DF6640787226bc96354E1a9766" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4442556a08a841227bEf04C67A7Ba7acf01b6Fc8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE66747a101bFF2dBA3697199DCcE5b743b454759" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2C36204a0712A2a50E54A62F7c4F01867e78cB53" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD91a6162F146EF85922d9A15eE6eB14A00344586" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0C6f5F7D555E7518f6841a79436BD2b1Eef03381" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x98b2dE885E916b598f65DeD2fDbb63187EAEf184" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8CE9137d39326AD0cD6491fb5CC0CbA0e089b6A9" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x525794473F7ab5715C81d06d10f52d11cC052804" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xFC29B6e626B67776675FfF55d5BC0452d042F434" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5b71BEE9D961b1B848f8485EEC8d8787f80217F5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5E7Ebea68ab05198F771d77a875480314f1d0aae" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6556D2EC4D96Da39CF75cbE50D58fae90079800a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdfbc9050F5B01DF53512DCC39B4f2B2BBaCD517A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa8262Eb913FccEa4C3f77fc95b8b4043B384cFbB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb5A73f5Fc8BbdbcE59bfD01CA8d35062e0dad801" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4129D3b7a6A2c5C997774077aC02bDafd1AF1d6a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x68350d30D9F58C81aaaA41929f1bfC52FFf4Ea49" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0c963A1B52Eb97C5e457c7D76696F8b95c3087eD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2C9023bBc572ff8dc1228c7858A280046Ea8C9E5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5E3002dff591C5e75Bb9DEdae268049742E6b13a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2730d6FdC86C95a74253BefFaA8306B40feDecbb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x12683Dc9eEc95a5F742D40206e73319E6b9d8A91" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1B073382E63411E3BcfFE90aC1B9A43feFa1Ec6F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5d285F735998F36631F678FF41fb56A10A4d0429" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x00fC270C9cc13e878Ab5363D00354bebF6f05C15" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC77b230F31b517F1ef362e59c173C2BE6540B5E8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7D29A64504629172a429e64183D6673b9dAcbFCe" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "MTXLT-286" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x593114f03A0A575aece9ED675e52Ed68D2172B8c" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "ECO-083" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x65cCD72c0813CE6f2703593B633202a0F3Ca6a0c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8D8129963291740dDDd917ab01af18c7aed4BA58" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbdbC2a5B32F3a5141ACd18C39883066E4daB9774" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2E68dfB3f50Ea302c88F8dB74096D57565D9970a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4E3Bddd468AbfC6C88bc25dAA5d894380CEd5bc8" - }, - { - "coin": 195, - "type": "token", - "currency": "USD", - "token_id": "TUL5yxRKeSWvceLZ3BSU5iNJcQmNxkWayh" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD2bb16cf38Ca086Cab5128D5c25DE9477eBD596B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x60715E436c37444E29772c0D26a98Ae1E8E1A989" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8E30ea2329D95802Fd804f4291220b0e2F579812" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x430bd07726423A54f6d82Ab0F578CE62A3b8054D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB9EefC4b0d472A44be93970254Df4f4016569d27" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x19C9872640eC38c2Cf36C0F04d1365Ef067869B3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfB559CE67Ff522ec0b9Ba7f5dC9dc7EF6c139803" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x63d958D765F5bd88efDbD8Afd32445393b24907f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaEaabb69dcB0FE926B1979f0B032FCd17FD7b2E0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xeb269732ab75A6fD61Ea60b06fE994cD32a83549" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb8c6ad2586bB71d518C2aaf510Efe91f82022F58" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x790bFaCaE71576107C068f494c8A6302aea640cb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa249F0E9A464b9685F66992f41e1012388e39e81" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2822f6D1B2f41F93f33d937bc7d84A8Dfa4f4C21" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x827D53c8170aF52625f414bde00326Fc8A085E86" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0C3eF32f802967DB75B9D49fE1e76620151cCB81" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x7DE2d123042994737105802D2abD0A10a7BdE276" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2E65E12b5f0fD1D58738c6F38dA7D57F5F183d1c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x301C755bA0fcA00B1923768Fffb3Df7f4E63aF31" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBA11D00c5f74255f56a5E366F4F77f5A186d7f55" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2396FBC0e2E3AE4B7206EbDb5706e2a5920349CB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x365542DF3c8c9d096C5F0dE24A0d8cf33C19C8fd" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe947b388fbE682784170B62F2Bd4665f9719a285" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4Fabb145d64652a948d72533023f6E7A623C7C53" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x60c87297A1fEaDC3C25993FfcadC54e99971e307" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xcD8544DefeDEc7c6b60b5a4232320365b1B21fCc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x12fD19DAC0Fab61bEd5e0F09091B470C452D4d61" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3277dd536471a3cBEB0c9486aCad494C95A31E73" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x998FFE1E43fAcffb941dc337dD0468d52bA5b48A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdeCF7Be29F8832E9C2Ddf0388c9778B8Ba76af43" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x45804880De22913dAFE09f4980848ECE6EcbAf78" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x278a83B64C3e3E1139f8E8A52D96360cA3c69A3D" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x93065b5C7Eb63333b8E57a73012D25f687895785" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8c4E7f814d40f8929F9112C5D09016F923d34472" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x00059AE69c1622A7542EdC15E8d17b060fE307b6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x31274db8b609Df99E5988ee527071643b5160Fc3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4CB10F4df4BF4F64D4797d00D468181EF731Be9A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF784682C82526e245F50975190EF0fff4E4fC077" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x70968FEAF13299d0dBf78f66860bAb9DbE3856bc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF6Bf74a97d78f2242376769EF1E79885Cf1F0C1c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdA4129919F964a3A526D3182Bb03E6449e5a8872" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x86149C67e57c749d0A12e6D6c2Bf1b616619BB29" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xAAAaaaaBA2ea3daAB0A6c05F1b962c78c9836d99" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdF574c24545E5FfEcb9a659c229253D4111d87e1" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xdB096cC19b8227E2115855c5B39Dcc247470013C" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "VOTE-FD4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x37F74e99794853777a10ea1dc08a64C86958F06a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8F9bfe5b6A5C3fEa8c64ad41a5Cf6f60Ec4aa47c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbDEC45952B5E234EdDC2981B43eeD360826D5087" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xA31B1767e09f842ECFd4bc471Fe44F830E3891AA" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1F3F677Ecc58F6A1F9e2CF410dF4776a8546b5DE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x58959E0C71080434f237bD42d07Cd84B74CeF438" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb7e77aEbBe0687d2EfF24Cc90c41A3b6eA74bdAB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x86FADb80d8D2cff3C3680819E4da99C10232Ba0F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6bC1F3A1ae56231DbB64d3E82E070857EAe86045" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x9556f8ee795D991fF371F547162D5efB2769425F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x37D6E7F287200C740012747d2A79295cAeD2DB35" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF39f19565B8D937EC30f1db5BD42F558D1E312A6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2fd61567c29E7ADB4Ca17e60E1f4a3Fcfe68aCb8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe0b9BcD54bF8A730EA5d3f1fFCe0885E911a502c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x166F1a7eCAe00bd43876A25B10a63C575e05c0e7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1d8cA7baf0895Da8afcf153657bE064b5092a274" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB48B7E5bF6563B3e0A85055821A83Deb8CFc12f6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBA8c0244FBDEB10f19f6738750dAeEDF7a5081eb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5e040aC72140F0617bC24aB7134c0C6eCae0e965" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "KAVA-10C" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x578B49C45961f98d8DF92854b53F1641AF0A5036" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x142aC3BD1C94898Be6e311b020b547A11dC03990" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5B322514FF727253292637D9054301600c2C81e8" - }, - { - "coin": 195, - "type": "token", - "currency": "USD", - "token_id": "1002413" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbACA8D824f471a6b20fdbac25E9e8943B9cD743B" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x322f4f6a48329690957a3BCBd1301516C2B83c1F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3A10B7a22AE98E0f53276923F19f99B259F61778" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD27D76A1bA55ce5C0291CCd04feBBe793D22ebF4" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5456BC77Dd275c45c3C15f0cF936b763cF57c3B5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x1412f6Aa5ADC77C620715BB2a020AA690B85F68A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6710CeE627Fa3A988200ffD5687cc1C814cEf0F6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xcb17cD357c7acD594717D899ecb9df540F633F27" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x41ad4093349C8A60DE591A3C37dcd184558EaAe3" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8c9E4CF756b9d01D791b95bc2D0913EF2Bf03784" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xd24DFf6117936B6ff97108CF26c1dD8865743d87" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2fe39f22EAC6d3c1C86DD9D143640EbB94609FCE" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5978708d6ccE1CC9640Eed47422D64c91BbD5171" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xfE4455fd433Ed3CA025ec7c43cb8686eD89826CD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xF70d160102cF7a22c1E432d6928a9d625Db91170" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2AA4a3E8bB72BE68a31c9c3C98CA7BeC723C6222" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0d16450D347c12C086d6C94c76c5Aaac35eA07E0" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6B175474E89094C44Da98b954EedeAC495271d0F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0Ba45A8b5d5575935B8158a88C631E9F9C95a2e5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3DB99ab08006aeFcC9600972eCA8C202396B4300" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xbf05571988dAaB22D33C28bbB13566eae9DeE626" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x037A54AaB062628C9Bbae1FDB1583c195585fe41" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE65ee7c03Bbb3C950Cfd4895c24989afA233EF01" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xE1bAD922F84b198A08292FB600319300ae32471b" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6096d2460CF5177E40B515223428DC005ad35123" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xD89040Ac9823B72F64d71f66Fa2DeAE7C8520671" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4D0425e47Ee2D16b94c036715dfcb52a0cebC4Dc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3be6e7bF2cD8E1a0A95597E72ca6D3709bBeFF76" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB8E2e2101eD11e9138803cd3e06e16dd19910647" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x40c6f861A08F97dfBC3C0931485bFf4921975a56" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x20b1A8a9cA1c7302b7f774266C491C7b11622779" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "TROY-9B8" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x082E13494f12EBB7206FBf67E22A6E1975A1A669" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6b9F1F092E0B10015a4391A80cD3E6B6cefD1728" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xed0849BF46CfB9845a2d900A0A4E593F2dD3673c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBbe761EA1447A20b75aA485b7BCad4837415d7D7" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x65Ac08c55F21d4A73CA1D429a17a6872b23bFd55" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4575f41308EC1483f3d399aa9a2826d74Da13Deb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xe541b34f73a4789a033A962ad43655221B4E516e" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8b847669B2e5dD5101736e41dA8Ec38653065aeb" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4c14114C107D6374EC31981F5F6Cc27A13e22F9a" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4eE6E959d460dE47DfE58E5E6fBAB330Ce8484b6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa105C740BC012A43a342Ab4A0Ef40143452C8E89" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x83cAEECace9Ec5c322c93743B2B370ED58951F5c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8F8e787989BC652eeA01A6C88a19f0f379BDF4FD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x3C7b464376DB7C9927930cf50EEfDEA2EFF3A66A" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x786001c9c5CA6E502dEB8a8a72480d2147891f32" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x843131b15F2Ec5BeA850aC5164D2e4a3749ad87f" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x4fAC0ccD9e2ed9fD462D42B66Fb81bA9A1f6F25E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB351dA6ffEbd5DddD1dA037929FCf334d6B4A8D5" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6368e1E18c4C419DDFC608A0BEd1ccb87b9250fc" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x6E5a43DB10b04701385A34afb670E404bC7Ea597" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x73Cee8348b9bDd48c64E13452b8a6fbc81630573" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xB4a677B0E363c3815d46326954a4E4d2B1ACe357" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC8C424B91D8ce0137bAB4B832B7F7D154156BA6c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x13339fD07934CD674269726EdF3B5ccEE9DD93de" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xaDA62f7CCd6af6cAcff04ACCBC4f56f3D4FFd4Ef" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa98F029bb4e74C12FB07BBc25854E5a04F7acF4c" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x063b98a414EAA1D4a5D4fC235a22db1427199024" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x0e8e874bb30a5F254f5144EaAE4564C7F73fAbeD" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x94eea9a484F0BaE03D19623cfe389E2CBA56B72F" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x208bbb6bCEA22ef2011789331405347394EbAa51" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xBdBB0Ee6144544eC814d417B0ad41f16fC8B858E" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xb5a4ac5b04E777230bA3381195EfF6a60c3934F2" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xC538143202f3b11382D8606aae90a96b042a19DB" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x8207c1FfC5B6804F6024322CcF34F29c3541Ae26" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0xa90C43e0d6c92b8e6171a829beB38Be28a0Ad073" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x5a4B14aea23A605aBc463f04a6B8Aaf52Dd3e7C6" - }, - { - "coin": 60, - "type": "token", - "currency": "USD", - "token_id": "0x68eb95Dc9934E19B86687A10DF8e364423240E94" - }, - { - "coin": 60, - "type": "token", - "currency": "BRL", - "token_id": "0x016ee7373248a80BDe1fD6bAA001311d233b3CFa" - }, - { - "coin": 714, - "type": "token", - "currency": "BRL", - "token_id": "WRX-ED1" - }, - { - "coin": 60, - "type": "token", - "currency": "BRL", - "token_id": "0x4922a015c4407F87432B179bb209e125432E4a2A" - }, - { - "coin": 60, - "type": "token", - "currency": "BRL", - "token_id": "0x7BD6a4E7DB3A34c485A8DD02b30B6565e3bbC633" + "token_id": "1002413" }, { "coin": 60, "type": "token", "currency": "EUR", "token_id": "0xeF65887a05415bF6316204b5ffB350d4d1a19BBA" - }, - { - "coin": 60, - "type": "token", - "currency": "EUR", - "token_id": "0x1fff4Dd33105054E853955C6d0dBa82859C01Cff" } ] From 484402aa312268427ab2890620717dec3ac7cfda Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 14 Feb 2020 10:15:30 -0700 Subject: [PATCH 123/506] Update to microservices architecture (#840) * Refactor STEP 2 (#817) * Platform refactor step 2 * Platform refactor step 2 * update docker-compose * Update Procfile * Small refactor * Add swagger for "all" platforms option * fix fuckup with hardcode * requested changes * rename syncmarkets to market and some around fmt * build fix * build fix * update swagger * Update docker-compose and add run_docker_compose.sh * update swagger * update swagger- split it to separate binary Co-authored-by: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> * Swagger update and master sync (#838) * Fixes HTTP error codes and errors being swallowed (#826) * [Tezos] Implement fetching validators based on period type (#830) * Increase tezos block for getting validators list * Add fetching validators based on period type * Rename method to getCurrentValidators * Improves market error logging (#833) * Improves market error logging * Adds further logging * Fix Compound provider prices (#828) * respect stored quote currency and fixes fetching compound price * fix tests * update swagger Co-authored-by: Derek Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Co-authored-by: dpereskokov * Sync with master + small updates (#842) * Fixes HTTP error codes and errors being swallowed (#826) * [Tezos] Implement fetching validators based on period type (#830) * Increase tezos block for getting validators list * Add fetching validators based on period type * Rename method to getCurrentValidators * Improves market error logging (#833) * Improves market error logging * Adds further logging * Fix Compound provider prices (#828) * respect stored quote currency and fixes fetching compound price * fix tests * Update azure-pipelines.yml (#839) Dev branch will have tests right now * update azure-pipelines.yml Co-authored-by: Derek Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Co-authored-by: dpereskokov * Merge dev with master (#852) * Fixes HTTP error codes and errors being swallowed (#826) * [Tezos] Implement fetching validators based on period type (#830) * Increase tezos block for getting validators list * Add fetching validators based on period type * Rename method to getCurrentValidators * Improves market error logging (#833) * Improves market error logging * Adds further logging * Fix Compound provider prices (#828) * respect stored quote currency and fixes fetching compound price * fix tests * Update azure-pipelines.yml (#839) Dev branch will have tests right now * Add EIP55Checksum for classic market data address (#841) * Add coingecko checksum (#843) * Add coingecko checksum * Fix unit tests * Postman Tests (#831) * Add Postman Tests * Improve domain tests * Add postman tests for observer * Update domains data * Installing newman by postman * Improve make commands and remove duplicate code * Add postman tests for market data * Add tests for batch routes and fix/update swagger * Specify the host for the Newman make command * Update makefile comment for Newman * Filter market data interation data * Update postman collection * Limit transaction history to 25 objects (#820) * Limit transactions to 25 * Add verification before limit * Remove unused code * Use Itoa instead FormatInt * Remove useless TODO message * Remove unused code for functional tests * Remove sensitive info (#844) * Add support to review apps (#846) * resolve conflicts with tests * fix integration_test.go Co-authored-by: Derek Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Co-authored-by: dpereskokov Co-authored-by: Danilo Pantani * Sync dev branch with master (#854) * Fixes HTTP error codes and errors being swallowed (#826) * [Tezos] Implement fetching validators based on period type (#830) * Increase tezos block for getting validators list * Add fetching validators based on period type * Rename method to getCurrentValidators * Improves market error logging (#833) * Improves market error logging * Adds further logging * Fix Compound provider prices (#828) * respect stored quote currency and fixes fetching compound price * fix tests * Update azure-pipelines.yml (#839) Dev branch will have tests right now * Add EIP55Checksum for classic market data address (#841) * Add coingecko checksum (#843) * Add coingecko checksum * Fix unit tests * Postman Tests (#831) * Add Postman Tests * Improve domain tests * Add postman tests for observer * Update domains data * Installing newman by postman * Improve make commands and remove duplicate code * Add postman tests for market data * Add tests for batch routes and fix/update swagger * Specify the host for the Newman make command * Update makefile comment for Newman * Filter market data interation data * Update postman collection * Limit transaction history to 25 objects (#820) * Limit transactions to 25 * Add verification before limit * Remove unused code * Use Itoa instead FormatInt * Remove useless TODO message * Remove unused code for functional tests * Remove sensitive info (#844) * Add support to review apps (#846) * Fix NIMIQ date parser * Remove integrations tests for Fio testnet * Remove functional tests for Fio testnet for now * FIO name lookup: add new chain_code parameter to get_pub_address call (FIO testnet v0.8 -> v0.9). (#853) * Put back the fio test for integration and functional * Set minimum amount for cosmos staking (#851) * Set minimum amount for cosmos * Fix unit tests Co-authored-by: Derek Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Co-authored-by: dpereskokov Co-authored-by: Danilo Pantani Co-authored-by: Adam R <13562139+catenocrypt@users.noreply.github.com> * Add gin logger (#858) * Fixes HTTP error codes and errors being swallowed (#826) * [Tezos] Implement fetching validators based on period type (#830) * Increase tezos block for getting validators list * Add fetching validators based on period type * Rename method to getCurrentValidators * Improves market error logging (#833) * Improves market error logging * Adds further logging * Fix Compound provider prices (#828) * respect stored quote currency and fixes fetching compound price * fix tests * Update azure-pipelines.yml (#839) Dev branch will have tests right now * Add EIP55Checksum for classic market data address (#841) * Add coingecko checksum (#843) * Add coingecko checksum * Fix unit tests * Postman Tests (#831) * Add Postman Tests * Improve domain tests * Add postman tests for observer * Update domains data * Installing newman by postman * Improve make commands and remove duplicate code * Add postman tests for market data * Add tests for batch routes and fix/update swagger * Specify the host for the Newman make command * Update makefile comment for Newman * Filter market data interation data * Update postman collection * Limit transaction history to 25 objects (#820) * Limit transactions to 25 * Add verification before limit * Remove unused code * Use Itoa instead FormatInt * Remove useless TODO message * Remove unused code for functional tests * Remove sensitive info (#844) * Add support to review apps (#846) * Fix NIMIQ date parser * Remove integrations tests for Fio testnet * Remove functional tests for Fio testnet for now * FIO name lookup: add new chain_code parameter to get_pub_address call (FIO testnet v0.8 -> v0.9). (#853) * Put back the fio test for integration and functional * Set minimum amount for cosmos staking (#851) * Set minimum amount for cosmos * Fix unit tests * add logger for gin Co-authored-by: Derek Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Co-authored-by: dpereskokov Co-authored-by: Danilo Pantani Co-authored-by: Adam R <13562139+catenocrypt@users.noreply.github.com> * Sync (#859) * Fixes HTTP error codes and errors being swallowed (#826) * [Tezos] Implement fetching validators based on period type (#830) * Increase tezos block for getting validators list * Add fetching validators based on period type * Rename method to getCurrentValidators * Improves market error logging (#833) * Improves market error logging * Adds further logging * Fix Compound provider prices (#828) * respect stored quote currency and fixes fetching compound price * fix tests * Update azure-pipelines.yml (#839) Dev branch will have tests right now * Add EIP55Checksum for classic market data address (#841) * Add coingecko checksum (#843) * Add coingecko checksum * Fix unit tests * Postman Tests (#831) * Add Postman Tests * Improve domain tests * Add postman tests for observer * Update domains data * Installing newman by postman * Improve make commands and remove duplicate code * Add postman tests for market data * Add tests for batch routes and fix/update swagger * Specify the host for the Newman make command * Update makefile comment for Newman * Filter market data interation data * Update postman collection * Limit transaction history to 25 objects (#820) * Limit transactions to 25 * Add verification before limit * Remove unused code * Use Itoa instead FormatInt * Remove useless TODO message * Remove unused code for functional tests * Remove sensitive info (#844) * Add support to review apps (#846) * Fix NIMIQ date parser * Remove integrations tests for Fio testnet * Remove functional tests for Fio testnet for now * FIO name lookup: add new chain_code parameter to get_pub_address call (FIO testnet v0.8 -> v0.9). (#853) * Put back the fio test for integration and functional * Set minimum amount for cosmos staking (#851) * Set minimum amount for cosmos * Fix unit tests * add logger for gin * add logger to apis Co-authored-by: Derek Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Co-authored-by: dpereskokov Co-authored-by: Danilo Pantani Co-authored-by: Adam R <13562139+catenocrypt@users.noreply.github.com> * Sync 2 (#861) * Fixes HTTP error codes and errors being swallowed (#826) * [Tezos] Implement fetching validators based on period type (#830) * Increase tezos block for getting validators list * Add fetching validators based on period type * Rename method to getCurrentValidators * Improves market error logging (#833) * Improves market error logging * Adds further logging * Fix Compound provider prices (#828) * respect stored quote currency and fixes fetching compound price * fix tests * Update azure-pipelines.yml (#839) Dev branch will have tests right now * Add EIP55Checksum for classic market data address (#841) * Add coingecko checksum (#843) * Add coingecko checksum * Fix unit tests * Postman Tests (#831) * Add Postman Tests * Improve domain tests * Add postman tests for observer * Update domains data * Installing newman by postman * Improve make commands and remove duplicate code * Add postman tests for market data * Add tests for batch routes and fix/update swagger * Specify the host for the Newman make command * Update makefile comment for Newman * Filter market data interation data * Update postman collection * Limit transaction history to 25 objects (#820) * Limit transactions to 25 * Add verification before limit * Remove unused code * Use Itoa instead FormatInt * Remove useless TODO message * Remove unused code for functional tests * Remove sensitive info (#844) * Add support to review apps (#846) * Fix NIMIQ date parser * Remove integrations tests for Fio testnet * Remove functional tests for Fio testnet for now * FIO name lookup: add new chain_code parameter to get_pub_address call (FIO testnet v0.8 -> v0.9). (#853) * Put back the fio test for integration and functional * Set minimum amount for cosmos staking (#851) * Set minimum amount for cosmos * Fix unit tests * Remove tests for FIO domain until we have new address * Split stake api handlers into stake.go (#855) * Split asset services methods (#856) * Split asset services methods * Change method signature * Improve validators logic using extensions (#857) * Improve validator logic using extensions * Fix unit tests * Fix postman tests for iotex * add logger for gin * Add auth parameter for newman make commands * Remove interation data for maket tests * add logger to apis Co-authored-by: Derek Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Co-authored-by: dpereskokov Co-authored-by: Danilo Pantani Co-authored-by: Adam R <13562139+catenocrypt@users.noreply.github.com> * fix Makefile Co-authored-by: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> Co-authored-by: Derek Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Co-authored-by: dpereskokov Co-authored-by: Danilo Pantani Co-authored-by: Adam R <13562139+catenocrypt@users.noreply.github.com> --- .goreleaser.yml | 6 +- Makefile | 94 ++++--- Procfile | 8 +- api/batch.go | 10 +- api/handlers.go | 19 +- api/maketdata.go | 18 +- api/naming_service.go | 4 +- api/observer.go | 6 +- api/stake.go | 4 +- azure-pipelines.yml | 1 + cmd/api/main.go | 125 --------- cmd/market_api/main.go | 51 ++++ cmd/market_observer/main.go | 26 ++ cmd/observer_api/main.go | 51 ++++ cmd/platform_api/main.go | 48 ++++ cmd/{observer => platform_observer}/main.go | 24 +- cmd/swagger_api/main.go | 47 ++++ cmd/syncmarkets/main.go | 47 ---- config.yml | 5 +- docker-compose.yml | 54 +++- docs/docs.go | 93 ++----- docs/swagger.json | 91 ++----- docs/swagger.yaml | 83 ++---- go.sum | 88 +++++++ internal/init.go | 66 +++++ internal/shutdown.go | 45 ++++ {syncmarkets => market}/chart/chart.go | 0 {syncmarkets => market}/chart/cmc/cmc.go | 4 +- {syncmarkets => market}/chart/cmc/cmc_test.go | 2 +- .../chart/coingecko/coingecko.go | 4 +- .../chart/coingecko/coingecko_test.go | 2 +- {syncmarkets => market}/chart/provider.go | 0 {syncmarkets => market}/charts.go | 8 +- {syncmarkets => market}/charts_test.go | 2 +- {syncmarkets => market}/clients/cmc/cache.go | 0 .../clients/cmc/cache_test.go | 0 {syncmarkets => market}/clients/cmc/client.go | 0 {syncmarkets => market}/clients/cmc/models.go | 0 .../clients/cmc/webclient.go | 0 .../clients/cmc/widgetclient.go | 0 .../clients/coingecko/cache.go | 0 .../clients/coingecko/cache_test.go | 0 .../clients/coingecko/client.go | 2 +- .../clients/coingecko/client_test.go | 0 .../clients/coingecko/models.go | 0 .../clients/compound/client.go | 0 .../clients/compound/models.go | 0 {syncmarkets => market}/market.go | 12 +- {syncmarkets => market}/market/cmc/cmc.go | 4 +- .../market/cmc/cmc_test.go | 2 +- .../market/coingecko/coingecko.go | 4 +- .../market/coingecko/coingecko_test.go | 2 +- .../market/compound/compound.go | 4 +- .../market/compound/compound_test.go | 2 +- {syncmarkets => market}/market/dex/dex.go | 2 +- .../market/dex/dex_test.go | 0 {syncmarkets => market}/market/dex/models.go | 0 {syncmarkets => market}/market/market.go | 0 {syncmarkets => market}/market/provider.go | 0 {syncmarkets => market}/rate/cmc/cmc.go | 4 +- {syncmarkets => market}/rate/cmc/cmc_test.go | 2 +- .../rate/coingecko/coingecko.go | 4 +- .../rate/coingecko/coingecko_test.go | 2 +- .../rate/compound/compound.go | 4 +- .../rate/compound/compound_test.go | 2 +- {syncmarkets => market}/rate/fixer/fixer.go | 2 +- .../rate/fixer/fixer_test.go | 0 {syncmarkets => market}/rate/fixer/models.go | 0 {syncmarkets => market}/rate/provider.go | 0 {syncmarkets => market}/rate/rate.go | 0 {syncmarkets => market}/rates.go | 12 +- {syncmarkets => market}/worker.go | 6 +- pkg/tests/functional/functional_test.go | 2 +- pkg/tests/integration/integration_test.go | 3 +- platform/bitcoin/api.go | 2 +- platform/registry.go | 240 +++++++++++++----- run_docker_compose.sh | 58 +++++ 77 files changed, 930 insertions(+), 583 deletions(-) delete mode 100644 cmd/api/main.go create mode 100644 cmd/market_api/main.go create mode 100644 cmd/market_observer/main.go create mode 100644 cmd/observer_api/main.go create mode 100644 cmd/platform_api/main.go rename cmd/{observer => platform_observer}/main.go (79%) create mode 100644 cmd/swagger_api/main.go delete mode 100644 cmd/syncmarkets/main.go create mode 100644 internal/init.go create mode 100644 internal/shutdown.go rename {syncmarkets => market}/chart/chart.go (100%) rename {syncmarkets => market}/chart/cmc/cmc.go (96%) rename {syncmarkets => market}/chart/cmc/cmc_test.go (98%) rename {syncmarkets => market}/chart/coingecko/coingecko.go (95%) rename {syncmarkets => market}/chart/coingecko/coingecko_test.go (96%) rename {syncmarkets => market}/chart/provider.go (100%) rename {syncmarkets => market}/charts.go (91%) rename {syncmarkets => market}/charts_test.go (99%) rename {syncmarkets => market}/clients/cmc/cache.go (100%) rename {syncmarkets => market}/clients/cmc/cache_test.go (100%) rename {syncmarkets => market}/clients/cmc/client.go (100%) rename {syncmarkets => market}/clients/cmc/models.go (100%) rename {syncmarkets => market}/clients/cmc/webclient.go (100%) rename {syncmarkets => market}/clients/cmc/widgetclient.go (100%) rename {syncmarkets => market}/clients/coingecko/cache.go (100%) rename {syncmarkets => market}/clients/coingecko/cache_test.go (100%) rename {syncmarkets => market}/clients/coingecko/client.go (97%) rename {syncmarkets => market}/clients/coingecko/client_test.go (100%) rename {syncmarkets => market}/clients/coingecko/models.go (100%) rename {syncmarkets => market}/clients/compound/client.go (100%) rename {syncmarkets => market}/clients/compound/models.go (100%) rename {syncmarkets => market}/market.go (83%) rename {syncmarkets => market}/market/cmc/cmc.go (95%) rename {syncmarkets => market}/market/cmc/cmc_test.go (98%) rename {syncmarkets => market}/market/coingecko/coingecko.go (94%) rename {syncmarkets => market}/market/coingecko/coingecko_test.go (97%) rename {syncmarkets => market}/market/compound/compound.go (91%) rename {syncmarkets => market}/market/compound/compound_test.go (96%) rename {syncmarkets => market}/market/dex/dex.go (97%) rename {syncmarkets => market}/market/dex/dex_test.go (100%) rename {syncmarkets => market}/market/dex/models.go (100%) rename {syncmarkets => market}/market/market.go (100%) rename {syncmarkets => market}/market/provider.go (100%) rename {syncmarkets => market}/rate/cmc/cmc.go (90%) rename {syncmarkets => market}/rate/cmc/cmc_test.go (97%) rename {syncmarkets => market}/rate/coingecko/coingecko.go (89%) rename {syncmarkets => market}/rate/coingecko/coingecko_test.go (96%) rename {syncmarkets => market}/rate/compound/compound.go (88%) rename {syncmarkets => market}/rate/compound/compound_test.go (96%) rename {syncmarkets => market}/rate/fixer/fixer.go (94%) rename {syncmarkets => market}/rate/fixer/fixer_test.go (100%) rename {syncmarkets => market}/rate/fixer/models.go (100%) rename {syncmarkets => market}/rate/provider.go (100%) rename {syncmarkets => market}/rate/rate.go (100%) rename {syncmarkets => market}/rates.go (82%) rename {syncmarkets => market}/worker.go (93%) create mode 100755 run_docker_compose.sh diff --git a/.goreleaser.yml b/.goreleaser.yml index 78ed5dc87..a9ea72828 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -21,9 +21,9 @@ builds: - amd64 env: - CGO_ENABLED=0 - - id: syncmarkets - binary: syncmarkets - main: "./cmd/syncmarkets/main.go" + - id: market + binary: market + main: "./cmd/market/main.go" goos: - linux goarch: diff --git a/Makefile b/Makefile index 71ccab718..4e1284e03 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,12 @@ VERSION := $(shell git describe --tags) BUILD := $(shell git rev-parse --short HEAD) PROJECT_NAME := $(shell basename "$(PWD)") -API_SERVICE := api -OBSERVER_SERVICE := observer -SYNC_SERVICE := syncmarkets +API_SERVICE := platform_api +OBSERVER_SERVICE := platform_observer +OBSERVER_API := observer_api +MARKET_SERVICE := market_observer +MARKET_API := market_api +SWAGGER_API := swagger_api COIN_FILE := coin/coins.yml COIN_GO_FILE := coin/coins.go GEN_COIN_FILE := coin/gen.go @@ -31,8 +34,10 @@ STDERR := /tmp/.$(PROJECT_NAME)-stderr.txt # PID file will keep the process id of the server PID_API := /tmp/.$(PROJECT_NAME).$(API_SERVICE).pid PID_OBSERVER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SERVICE).pid -PID_SYNC := /tmp/.$(PROJECT_NAME).$(SYNC_SERVICE).pid - +PID_OBSERVER_API := /tmp/.$(PROJECT_NAME).$(OBSERVER_API).pid +PID_MARKET := /tmp/.$(PROJECT_NAME).$(MARKET_SERVICE).pid +PID_MARKET_API := /tmp/.$(PROJECT_NAME).$(MARKET_API).pid +PID_SWAGGER_API := /tmp/.$(PROJECT_NAME).$(SWAGGER_API).pid # Make is verbose in Linux. Make it silent. MAKEFLAGS += --silent @@ -41,36 +46,60 @@ install: go-get ## start: Start API, Observer and Sync in development mode. start: - @bash -c "$(MAKE) clean compile start-api start-observer start-syncmarkets" + @bash -c "$(MAKE) clean compile start-platform-api start-platform-observer start-observer-api start-market-observer start-market-api" ## start-api: Start API in development mode. -start-api: stop +start-platform-api: stop @echo " > Starting $(PROJECT_NAME) API" - @-$(GOBIN)/$(API_SERVICE)/api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_API) + @-$(GOBIN)/$(API_SERVICE)/platform_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_API) @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" @echo " > Error log: $(STDERR)" ## start-observer: Start Observer in development mode. -start-observer: stop +start-platform-observer: stop @echo " > Starting $(PROJECT_NAME) Observer" - @-$(GOBIN)/$(OBSERVER_SERVICE)/observer -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER) + @-$(GOBIN)/$(OBSERVER_SERVICE)/platform_observer -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER) @cat $(PID_OBSERVER) | sed "/^/s/^/ \> Observer PID: /" @echo " > Error log: $(STDERR)" -## start-sync-markets: Start Sync markets in development mode. -start-syncmarkets: stop +## start-observer: Start Observer in development mode. +start-observer-api: stop + @echo " > Starting $(PROJECT_NAME) Observer" + @-$(GOBIN)/$(OBSERVER_API)/observer_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_API) + @cat $(PID_OBSERVER_API) | sed "/^/s/^/ \> Observer PID: /" + @echo " > Error log: $(STDERR)" + +## start-sync-market: Start Sync market in development mode. +start-market-observer: stop @echo " > Starting $(PROJECT_NAME) Sync" - @-$(GOBIN)/$(SYNC_SERVICE)/syncmarkets -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SYNC) - @cat $(PID_SYNC) | sed "/^/s/^/ \> Sync PID: /" + @-$(GOBIN)/$(MARKET_SERVICE)/market_observer -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_MARKET) + @cat $(PID_MARKET) | sed "/^/s/^/ \> Sync PID: /" + @echo " > Error log: $(STDERR)" + +## start-sync-market-api: Start Sync market api in development mode. +start-market-api: stop + @echo " > Starting $(PROJECT_NAME) Sync API" + @-$(GOBIN)/$(MARKET_API)/market_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_MARKET_API) + @cat $(PID_MARKET_API) | sed "/^/s/^/ \> Sync PID: /" + @echo " > Error log: $(STDERR)" + +## start-sync-market-api: Start Sync market api in development mode. +start-swagger-api: stop + @echo " > Starting $(PROJECT_NAME) Sync API" + @-$(GOBIN)/$(SWAGGER_API)/swagger_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SWAGGER_API) + @cat $(PID_SWAGGER_API) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" ## stop: Stop development mode. stop: - @-touch $(PID_API) $(PID_OBSERVER) + @-touch $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_API) $(PID_MARKET) $(PID_MARKET_API) $(PID_SWAGGER_API) @-kill `cat $(PID_API)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER)` 2> /dev/null || true - @-kill `cat $(PID_SYNC)` 2> /dev/null || true - @-rm $(PID_API) $(PID_OBSERVER) + @-kill `cat $(PID_OBSERVER_API)` 2> /dev/null || true + @-kill `cat $(PID_MARKET)` 2> /dev/null || true + @-kill `cat $(PID_MARKET_API)` 2> /dev/null || true + @-kill `cat $(PID_SWAGGER_API)` 2> /dev/null || true + @-rm $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_API) $(PID_MARKET) $(PID_MARKET_API) $(PID_SWAGGER_API) ## compile: Compile the project. compile: @@ -130,15 +159,6 @@ endif ## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http//localhost newman: install-newman @echo " > Runing $(test) tests" -ifndef observer_auth -override observer_auth = "test" -endif -ifndef market_auth -override market_auth = "" -endif -ifndef platform_auth -override platform_auth = "" -endif ifeq (,$(host)) @echo " > Host parameter is missing. e.g: make newman test=staking host=http://localhost:8420" @exit 1 @@ -153,18 +173,24 @@ ifeq (,$(test)) @bash -c "$(MAKE) newman test=observer host=$(host)" @bash -c "$(MAKE) newman test=market host=$(host)" else - @newman run pkg/tests/postman/Blockatlas.postman_collection.json --folder $(test) -d pkg/tests/postman/$(test)_data.json --env-var "host=$(host)" --env-var "observer_auth=$(observer_auth)" --env-var "platform_auth=$(platform_auth)" --env-var "market_auth=$(market_auth)" + @newman run pkg/tests/postman/Blockatlas.postman_collection.json --folder $(test) -d pkg/tests/postman/$(test)_data.json --env-var "host=$(host)" endif go-compile: go-get go-build go-build: - @echo " > Building api binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API_SERVICE)/api ./cmd/$(API_SERVICE) - @echo " > Building syncmarkets binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SYNC_SERVICE)/syncmarkets ./cmd/$(SYNC_SERVICE) - @echo " > Building observer binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SERVICE)/observer ./cmd/$(OBSERVER_SERVICE) + @echo " > Building platform_api binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API_SERVICE)/platform_api ./cmd/$(API_SERVICE) + @echo " > Building market_observer binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(MARKET_SERVICE)/market_observer ./cmd/$(MARKET_SERVICE) + @echo " > Building market_api binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(MARKET_API)/market_api ./cmd/$(MARKET_API) + @echo " > Building platform_observer binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SERVICE)/platform_observer ./cmd/$(OBSERVER_SERVICE) + @echo " > Building observer_api binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_API)/observer_api ./cmd/$(OBSERVER_API) + @echo " > Building swagger_api binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SWAGGER_API)/swagger_api ./cmd/$(SWAGGER_API) go-generate: @echo " > Generating dependency files..." @@ -203,7 +229,7 @@ go-gen-coins: go-gen-docs: @echo " > Generating swagger files" - swag init -g ./cmd/api/main.go -o ./docs + swag init -g ./cmd/platform_api/main.go -o ./docs go-goreleaser: @echo " > Releasing a new version" diff --git a/Procfile b/Procfile index 2f26c14ee..4b7f58f1f 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,5 @@ -web: bin/api -p $PORT -c config.yml -observer: bin/observer -c config.yml -market: bin/syncmarkets -c config.yml +platform_api: bin/platform_api -p $PORT -c config.yml +platform_observer: bin/platform_observer -c config.yml +observer_api: bin/observer_api -p $PORT -c config.yml +market_api: bin/market_api -p $PORT -c config.yml +market_observer: bin/market_observer -c config.yml diff --git a/api/batch.go b/api/batch.go index bbfc76e74..a6bebd786 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 Platform-Staking // @Param delegations body api.AddressesRequest true "Validators addresses and coins" // @Success 200 {object} blockatlas.DelegationsBatchPage // @Router /v2/staking/delegations [post] @@ -70,8 +70,8 @@ func makeStakingDelegationsBatchRoute(router gin.IRouter) { // @Description Get Stake Delegations for multiple coins // @Accept json // @Produce json -// @Tags platform,staking -// @Param delegations body api.CoinsRequest true "Validators addresses and coins" +// @Tags Platform-Staking +// @Param delegations body api.AddressesRequest true "Validators addresses and coins" // @Success 200 {object} blockatlas.DelegationsBatchPage // @Router /v2/staking/list [post] func makeStakingDelegationsSimpleBatchRoute(router gin.IRouter) { @@ -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 Collectibles +// @Tags Platform-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 Collectibles +// @Tags Platform-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 8937d82a0..faca6102b 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,tx +// @Tags Platform-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,tx +// @Tags Platform-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,collection +// @Tags Platform-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,collection +// @Tags Platform-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,collection +// @Tags Platform-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,collection +// @Tags Platform-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,token +// @Tags Platform-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 @@ -267,11 +267,6 @@ func makeTokenRoute(router gin.IRouter, api blockatlas.Platform) { }) } -// @Summary Get Metrics -// @ID metrics -// @Description Get application metrics -// @Tags metrics -// @Router /metrics [get] func MakeMetricsRoute(router gin.IRouter) { router.Use(metrics.PromMiddleware()) m := router.Group("/metrics") diff --git a/api/maketdata.go b/api/maketdata.go index aeb026e5b..d8633e8f5 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -4,13 +4,13 @@ import ( "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/market" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/ginutils/gincache" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" "github.com/trustwallet/blockatlas/storage" - "github.com/trustwallet/blockatlas/syncmarkets" "math/big" "net/http" "strconv" @@ -48,7 +48,7 @@ func SetupMarketAPI(router gin.IRouter, db storage.Market) { // @Description Get the ticker value from an market and coin/token // @Accept json // @Produce json -// @Tags ticker +// @Tags Market // @Param coin query int true "coin id" // @Param token query string false "token id" // @Param currency query string false "the currency to show the quote" default(USD) @@ -87,12 +87,12 @@ func getTickerHandler(storage storage.Market) func(c *gin.Context) { } } -// @Summary Get ticker values for a specific markets +// @Summary Get ticker values for a specific market // @Id get_tickers -// @Description Get the ticker values from many markets and coin/token +// @Description Get the ticker values from many market and coin/token // @Accept json // @Produce json -// @Tags ticker +// @Tags Market // @Param tickers body api.TickerRequest true "Ticker" // @Success 200 {object} blockatlas.Tickers // @Router /v1/market/ticker [post] @@ -156,7 +156,7 @@ func getTickersHandler(storage storage.Market) func(c *gin.Context) { // @Description Get the charts data from an market and coin/token // @Accept json // @Produce json -// @Tags charts +// @Tags Market // @Param coin query int true "Coin ID" default(60) // @Param token query string false "Token ID" // @Param time_start query int false "Start timestamp" default(1574483028) @@ -165,7 +165,7 @@ func getTickersHandler(storage storage.Market) func(c *gin.Context) { // @Success 200 {object} blockatlas.ChartData // @Router /v1/market/charts [get] func getChartsHandler() func(c *gin.Context) { - var charts = syncmarkets.InitCharts() + var charts = market.InitCharts() return func(c *gin.Context) { coinQuery := c.Query("coin") coinId, err := strconv.Atoi(coinQuery) @@ -202,7 +202,7 @@ func getChartsHandler() func(c *gin.Context) { // @Description Get the charts coin info data from an market and coin/contract // @Accept json // @Produce json -// @Tags charts +// @Tags Market // @Param coin query int true "Coin ID" default(60) // @Param token query string false "Token ID" // @Param time_start query int false "Start timestamp" default(1574483028) @@ -210,7 +210,7 @@ func getChartsHandler() func(c *gin.Context) { // @Success 200 {object} blockatlas.ChartCoinInfo // @Router /v1/market/info [get] func getCoinInfoHandler() func(c *gin.Context) { - var charts = syncmarkets.InitCharts() + var charts = market.InitCharts() return func(c *gin.Context) { coinQuery := c.Query("coin") coinId, err := strconv.Atoi(coinQuery) diff --git a/api/naming_service.go b/api/naming_service.go index 44cfdd20a..a67506b7a 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 ns +// @Tags Platform-Naming-Service // @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 ns +// @Tags Platform-Naming-Service // @Param name query string empty "string name" // @Param coins query string true "List of coins" // @Success 200 {array} blockatlas.Resolved diff --git a/api/observer.go b/api/observer.go index 6b59017a6..4a9fc8477 100644 --- a/api/observer.go +++ b/api/observer.go @@ -21,7 +21,7 @@ func SetupObserverAPI(router gin.IRouter, db *storage.Storage) { // @Description Create a webhook for addresses transactions // @Accept json // @Produce json -// @Tags observer,subscriptions +// @Tags Observer // @Param subscriptions body blockatlas.Webhook true "Accounts subscriptions" // @Param Authorization header string true "Bearer authorization header" default(Bearer test) // @Header 200 {string} Authorization {token} @@ -53,7 +53,7 @@ func addCall(storage storage.Addresses) func(c *gin.Context) { // @Description Delete a webhook for addresses transactions // @Accept json // @Produce json -// @Tags observer,subscriptions +// @Tags Observer // @Param subscriptions body blockatlas.Webhook true "Accounts subscriptions" // @Param Authorization header string true "Bearer authorization header" default(Bearer test) // @Header 200 {string} Authorization {token} @@ -85,7 +85,7 @@ func deleteCall(storage storage.Addresses) func(c *gin.Context) { // @Description Get coin status // @Accept json // @Produce json -// @Tags observer,subscriptions +// @Tags Observer // @Param Authorization header string true "Bearer authorization header" default(Bearer test) // @Header 200 {string} Authorization {token} // @Success 200 {object} blockatlas.CoinStatus diff --git a/api/stake.go b/api/stake.go index 9e7c129b1..a350a6c30 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 Platform-Staking // @Param coin path string true "the coin name" default(cosmos) // @Success 200 {object} blockatlas.DocsResponse // @Failure 500 {object} ginutils.ApiError @@ -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 Platform-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/azure-pipelines.yml b/azure-pipelines.yml index b19a75729..983d963ec 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,6 +11,7 @@ pr: branches: include: - master + - dev pool: vmImage: 'Ubuntu 16.04' diff --git a/cmd/api/main.go b/cmd/api/main.go deleted file mode 100644 index ec1d8ff3c..000000000 --- a/cmd/api/main.go +++ /dev/null @@ -1,125 +0,0 @@ -package main - -import ( - "context" - "flag" - "github.com/getsentry/sentry-go/gin" - "github.com/gin-gonic/gin" - "github.com/spf13/viper" - "github.com/swaggo/gin-swagger" - "github.com/swaggo/gin-swagger/swaggerFiles" - "github.com/trustwallet/blockatlas/api" - "github.com/trustwallet/blockatlas/config" - _ "github.com/trustwallet/blockatlas/docs" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/storage" - "net/http" - "os" - "os/signal" - "path/filepath" - "syscall" - "time" -) - -const ( - defaultPort = "8420" - defaultConfigPath = "../../config.yml" -) - -var ( - port, confPath string - cache *storage.Storage - sg gin.HandlerFunc -) - -func init() { - sg = sentrygin.New(sentrygin.Options{}) - cache = storage.New() - - flag.StringVar(&port, "p", defaultPort, "port for api") - flag.StringVar(&confPath, "c", defaultConfigPath, "config file for api") - - flag.Parse() - - confPath, err := filepath.Abs(confPath) - if err != nil { - logger.Fatal(err) - } - - config.LoadConfig(confPath) - logger.InitLogger() - platform.Init() - - host := viper.GetString("storage.redis") - err = cache.Init(host) - if err != nil { - logger.Fatal(err) - } -} - -func main() { - gin.SetMode(viper.GetString("gin.mode")) - engine := gin.New() - - engine.Use(ginutils.CheckReverseProxy, sg) - engine.Use(ginutils.CORSMiddleware()) - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) - - engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - engine.GET("/", api.GetRoot) - engine.GET("/status", func(c *gin.Context) { - ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, - }) - }) - - api.MakeMetricsRoute(engine) - api.LoadPlatforms(engine) - - if viper.GetBool("observer.enabled") { - logger.Info("Loading observer API") - observerAPI := engine.Group("/observer/v1") - api.SetupObserverAPI(observerAPI, cache) - } - if viper.GetBool("market.enabled") { - logger.Info("Loading market API") - marketAPI := engine.Group("/v1/market") - api.SetupMarketAPI(marketAPI, cache) - } - - signalForExit := make(chan os.Signal, 1) - - signal.Notify(signalForExit, - syscall.SIGHUP, - syscall.SIGINT, - syscall.SIGTERM, - syscall.SIGQUIT) - - srv := &http.Server{ - Addr: ":" + port, - Handler: engine, - } - - go func() { - if err := srv.ListenAndServe(); err != nil { - logger.Fatal("Application failed", err) - } - }() - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - defer func() { - if err := srv.Shutdown(ctx); err != nil { - logger.Fatal("Server Shutdown: ", err) - } - }() - - logger.Info("Running application", logger.Params{"bind": port}) - - stop := <-signalForExit - logger.Info("Stop signal Received", stop) - logger.Info("Waiting for all jobs to stop") -} diff --git a/cmd/market_api/main.go b/cmd/market_api/main.go new file mode 100644 index 000000000..14017cdfa --- /dev/null +++ b/cmd/market_api/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/api" + _ "github.com/trustwallet/blockatlas/docs" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/storage" +) + +const ( + defaultPort = "8421" + defaultConfigPath = "../../config.yml" +) + +var ( + port, confPath string + cache *storage.Storage + sg *gin.HandlerFunc +) + +func init() { + port, confPath, sg, cache = internal.InitAPIWithRedis(defaultPort, defaultConfigPath) +} + +func main() { + gin.SetMode(viper.GetString("gin.mode")) + + engine := gin.New() + engine.Use(ginutils.CheckReverseProxy, *sg) + engine.Use(ginutils.CORSMiddleware()) + engine.Use(gin.Logger()) + + engine.OPTIONS("/*path", ginutils.CORSMiddleware()) + engine.GET("/", api.GetRoot) + engine.GET("/status", func(c *gin.Context) { + ginutils.RenderSuccess(c, map[string]interface{}{ + "status": true, + }) + }) + + logger.Info("Loading market API") + + marketAPI := engine.Group("/v1/market") + + api.SetupMarketAPI(marketAPI, cache) + internal.SetupGracefulShutdown(port, engine) +} diff --git a/cmd/market_observer/main.go b/cmd/market_observer/main.go new file mode 100644 index 000000000..64746140f --- /dev/null +++ b/cmd/market_observer/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/market" + "github.com/trustwallet/blockatlas/storage" +) + +const ( + defaultConfigPath = "../../config.yml" +) + +var ( + confPath string + cache *storage.Storage +) + +func init() { + _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) +} + +func main() { + market.InitRates(cache) + market.InitMarkets(cache) + <-make(chan struct{}) +} diff --git a/cmd/observer_api/main.go b/cmd/observer_api/main.go new file mode 100644 index 000000000..72e9c67af --- /dev/null +++ b/cmd/observer_api/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/api" + _ "github.com/trustwallet/blockatlas/docs" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/storage" +) + +const ( + defaultPort = "8422" + defaultConfigPath = "../../config.yml" +) + +var ( + port, confPath string + cache *storage.Storage + sg *gin.HandlerFunc +) + +func init() { + port, confPath, sg, cache = internal.InitAPIWithRedis(defaultPort, defaultConfigPath) +} + +func main() { + gin.SetMode(viper.GetString("gin.mode")) + + engine := gin.New() + engine.Use(ginutils.CheckReverseProxy, *sg) + engine.Use(ginutils.CORSMiddleware()) + engine.Use(gin.Logger()) + + engine.OPTIONS("/*path", ginutils.CORSMiddleware()) + engine.GET("/", api.GetRoot) + engine.GET("/status", func(c *gin.Context) { + ginutils.RenderSuccess(c, map[string]interface{}{ + "status": true, + }) + }) + + logger.Info("Loading observer API") + + observerAPI := engine.Group("/observer/v1") + + api.SetupObserverAPI(observerAPI, cache) + internal.SetupGracefulShutdown(port, engine) +} diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go new file mode 100644 index 000000000..4cb9b79da --- /dev/null +++ b/cmd/platform_api/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/api" + _ "github.com/trustwallet/blockatlas/docs" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/platform" +) + +const ( + defaultPort = "8420" + defaultConfigPath = "../../config.yml" + allPlatforms = "all" +) + +var ( + port, confPath, chosenPlatform string + sg *gin.HandlerFunc +) + +func init() { + port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) + chosenPlatform = viper.GetString("platform") + platform.Init(chosenPlatform) +} + +func main() { + gin.SetMode(viper.GetString("gin.mode")) + engine := gin.New() + engine.Use(ginutils.CheckReverseProxy, *sg) + engine.Use(ginutils.CORSMiddleware()) + engine.Use(gin.Logger()) + + engine.OPTIONS("/*path", ginutils.CORSMiddleware()) + engine.GET("/", api.GetRoot) + engine.GET("/status", func(c *gin.Context) { + ginutils.RenderSuccess(c, map[string]interface{}{ + "status": true, + }) + }) + + api.LoadPlatforms(engine) + + internal.SetupGracefulShutdown(port, engine) +} diff --git a/cmd/observer/main.go b/cmd/platform_observer/main.go similarity index 79% rename from cmd/observer/main.go rename to cmd/platform_observer/main.go index 2680373b4..1466238e4 100644 --- a/cmd/observer/main.go +++ b/cmd/platform_observer/main.go @@ -2,14 +2,12 @@ package main import ( "context" - "flag" "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/observer" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/storage" - "path/filepath" "sync" "time" ) @@ -24,25 +22,9 @@ var ( ) func init() { - cache = storage.New() + _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) - flag.StringVar(&confPath, "c", defaultConfigPath, "config file for observer") - flag.Parse() - - confPath, err := filepath.Abs(confPath) - if err != nil { - logger.Fatal(err) - } - - config.LoadConfig(confPath) - logger.InitLogger() - platform.Init() - - host := viper.GetString("storage.redis") - err = cache.Init(host) - if err != nil { - logger.Fatal(err) - } + platform.Init(viper.GetString("platform")) } func main() { diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go new file mode 100644 index 000000000..644ee8da7 --- /dev/null +++ b/cmd/swagger_api/main.go @@ -0,0 +1,47 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + ginSwagger "github.com/swaggo/gin-swagger" + "github.com/swaggo/gin-swagger/swaggerFiles" + "github.com/trustwallet/blockatlas/api" + _ "github.com/trustwallet/blockatlas/docs" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/pkg/ginutils" +) + +const ( + defaultPort = "8423" + defaultConfigPath = "../../config.yml" + allPlatforms = "all" +) + +var ( + port, confPath string + sg *gin.HandlerFunc +) + +func init() { + port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) +} + +func main() { + gin.SetMode(viper.GetString("gin.mode")) + + engine := gin.New() + engine.Use(ginutils.CheckReverseProxy, *sg) + engine.Use(ginutils.CORSMiddleware()) + + engine.OPTIONS("/*path", ginutils.CORSMiddleware()) + engine.GET("/", api.GetRoot) + engine.GET("/status", func(c *gin.Context) { + ginutils.RenderSuccess(c, map[string]interface{}{ + "status": true, + }) + }) + + engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + + internal.SetupGracefulShutdown(port, engine) +} diff --git a/cmd/syncmarkets/main.go b/cmd/syncmarkets/main.go deleted file mode 100644 index 8c36941c3..000000000 --- a/cmd/syncmarkets/main.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "flag" - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" - "github.com/trustwallet/blockatlas/syncmarkets" - "path/filepath" -) - -const ( - defaultConfigPath = "../../config.yml" -) - -var ( - confPath string - cache *storage.Storage -) - -func init() { - cache = storage.New() - - flag.StringVar(&confPath, "c", defaultConfigPath, "config file for observer") - flag.Parse() - - confPath, err := filepath.Abs(confPath) - if err != nil { - logger.Fatal(err) - } - - config.LoadConfig(confPath) - logger.InitLogger() - - host := viper.GetString("storage.redis") - err = cache.Init(host) - if err != nil { - logger.Fatal(err) - } -} - -func main() { - syncmarkets.InitRates(cache) - syncmarkets.InitMarkets(cache) - <-make(chan struct{}) -} diff --git a/config.yml b/config.yml index 0309dfa82..f840aa18f 100644 --- a/config.yml +++ b/config.yml @@ -6,6 +6,7 @@ gin: # If set, HTTP Forwarded headers will be respected reverse_proxy: false +platform: all #metrics: # api_token: xxxxxx @@ -19,7 +20,7 @@ observer: # TODO : Add description auth: test # Redis Subscription Database - redis: redis://localhost:6379 + redis: redis://redis:6379 # Smallest possible block polling interval min_poll: 250ms # Don't request blocks older than this @@ -53,7 +54,7 @@ market: api: https://api.coingecko.com/api storage: - redis: redis://localhost:6379 + redis: redis://redis:6379 # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org diff --git a/docker-compose.yml b/docker-compose.yml index 775604fae..a18c8d61d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,36 +1,64 @@ version: '3.7' services: - api: - container_name: api + market_api: + container_name: market_api build: context: . args: - - SERVICE=api + - SERVICE=market_api ports: - - 8420:8420 + - 8421:8421 links: - - redis + - redis - observer: - container_name: observer + market_observer: + container_name: market_observer build: context: . args: - - SERVICE=observer + - SERVICE=market_observer links: - redis - syncmarkets: - container_name: syncmarkets + observer_api: + container_name: observer_api build: context: . args: - - SERVICE=syncmarkets + - SERVICE=observer_api + ports: + - 8422:8422 links: - - redis + - redis + + platform_api: + container_name: platform_api + build: + context: . + args: + - SERVICE=platform_api + ports: + - 8420:8420 + + swagger_api: + container_name: swagger_api + build: + context: . + args: + - SERVICE=swagger_api + ports: + - 8423:8423 + + platform_observer: + build: + context: . + args: + - SERVICE=platform_observer + links: + - redis redis: - container_name: redis + container_name: redis1 image: neojt/mredis ports: - 6379:6379 diff --git a/docs/docs.go b/docs/docs.go index c36afb8da..b3327af2a 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-12 08:02:39.698276 -0300 -03 m=+0.093560371 +// 2020-02-13 21:02:22.715378 -0700 MST m=+0.143781826 package docs @@ -26,16 +26,6 @@ var doc = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/metrics": { - "get": { - "description": "Get application metrics", - "tags": [ - "metrics" - ], - "summary": "Get Metrics", - "operationId": "metrics" - } - }, "/ns/lookup": { "get": { "description": "Lookup ENS/ZNS to find registered addresses", @@ -43,7 +33,7 @@ var doc = `{ "application/json" ], "tags": [ - "ns" + "Platform-Naming-Service" ], "summary": "Lookup .eth / .zil addresses", "operationId": "lookup", @@ -87,8 +77,7 @@ var doc = `{ "application/json" ], "tags": [ - "observer", - "subscriptions" + "Observer" ], "summary": "Get coin status", "operationId": "coin_status", @@ -122,8 +111,7 @@ var doc = `{ "application/json" ], "tags": [ - "observer", - "subscriptions" + "Observer" ], "summary": "Create a webhook", "operationId": "create_webhook", @@ -164,8 +152,7 @@ var doc = `{ "application/json" ], "tags": [ - "observer", - "subscriptions" + "Observer" ], "summary": "Delete a webhook", "operationId": "delete_webhook", @@ -208,7 +195,7 @@ var doc = `{ "application/json" ], "tags": [ - "charts" + "Market" ], "summary": "Get charts data for a specific coin", "operationId": "get_charts_data", @@ -269,7 +256,7 @@ var doc = `{ "application/json" ], "tags": [ - "charts" + "Market" ], "summary": "Get charts coin info data for a specific coin", "operationId": "get_charts_coin_info", @@ -323,7 +310,7 @@ var doc = `{ "application/json" ], "tags": [ - "ticker" + "Market" ], "summary": "Get ticker value for a specific market", "operationId": "get_ticker", @@ -359,7 +346,7 @@ var doc = `{ } }, "post": { - "description": "Get the ticker values from many markets and coin/token", + "description": "Get the ticker values from many market and coin/token", "consumes": [ "application/json" ], @@ -367,9 +354,9 @@ var doc = `{ "application/json" ], "tags": [ - "ticker" + "Market" ], - "summary": "Get ticker values for a specific markets", + "summary": "Get ticker values for a specific market", "operationId": "get_tickers", "parameters": [ { @@ -402,8 +389,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "tx" + "Platform-Transactions" ], "summary": "Get xpub transactions", "operationId": "xpub", @@ -445,8 +431,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "tx" + "Platform-Transactions" ], "summary": "Get Transactions", "operationId": "tx_v1", @@ -488,7 +473,7 @@ var doc = `{ "application/json" ], "tags": [ - "Collectibles" + "Platform-Collections" ], "summary": "Get list of collections from a specific coin and addresses", "operationId": "collection_categories_v2", @@ -521,7 +506,7 @@ var doc = `{ "application/json" ], "tags": [ - "ns" + "Platform-Naming-Service" ], "summary": "Lookup .eth / .zil addresses", "operationId": "lookup", @@ -569,8 +554,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "staking" + "Platform-Staking" ], "summary": "Get Multiple Stake Delegations", "operationId": "batch_delegations", @@ -605,8 +589,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "staking" + "Platform-Staking" ], "summary": "Get Multiple Stake Delegations", "operationId": "batch_delegations", @@ -617,7 +600,7 @@ var doc = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/api.CoinsRequest" + "$ref": "#/definitions/api.AddressesRequest" } } ], @@ -641,8 +624,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "collection" + "Platform-Collections" ], "summary": "Get Collections", "operationId": "collections_v2", @@ -690,8 +672,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "collection" + "Platform-Collections" ], "summary": "Get Collection", "operationId": "collection_v2", @@ -747,8 +728,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "staking" + "Platform-Staking" ], "summary": "Get Stake Delegations", "operationId": "delegations", @@ -796,8 +776,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "staking" + "Platform-Staking" ], "summary": "Get Validators", "operationId": "validators", @@ -837,8 +816,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "token" + "Platform-Transactions" ], "summary": "Get Tokens", "operationId": "tokens", @@ -886,8 +864,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "tx" + "Platform-Transactions" ], "summary": "Get Transactions", "operationId": "tx_v2", @@ -935,7 +912,7 @@ var doc = `{ "application/json" ], "tags": [ - "Collectibles" + "Platform-Collections" ], "summary": "Get list of collections from a specific coin and addresses", "operationId": "collection_categories_v3", @@ -971,8 +948,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "collection" + "Platform-Collections" ], "summary": "Get Collections", "operationId": "collections_v3", @@ -1020,8 +996,7 @@ var doc = `{ "application/json" ], "tags": [ - "platform", - "collection" + "Platform-Collections" ], "summary": "Get Collection", "operationId": "collection_v3", @@ -1100,20 +1075,6 @@ var doc = `{ } } }, - "api.CoinBatchRequest": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - } - } - }, - "api.CoinsRequest": { - "type": "array", - "items": { - "$ref": "#/definitions/api.CoinBatchRequest" - } - }, "api.TickerRequest": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 24e1d6a9f..dbdec9bb1 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -5,16 +5,6 @@ "license": {} }, "paths": { - "/metrics": { - "get": { - "description": "Get application metrics", - "tags": [ - "metrics" - ], - "summary": "Get Metrics", - "operationId": "metrics" - } - }, "/ns/lookup": { "get": { "description": "Lookup ENS/ZNS to find registered addresses", @@ -22,7 +12,7 @@ "application/json" ], "tags": [ - "ns" + "Platform-Naming-Service" ], "summary": "Lookup .eth / .zil addresses", "operationId": "lookup", @@ -66,8 +56,7 @@ "application/json" ], "tags": [ - "observer", - "subscriptions" + "Observer" ], "summary": "Get coin status", "operationId": "coin_status", @@ -101,8 +90,7 @@ "application/json" ], "tags": [ - "observer", - "subscriptions" + "Observer" ], "summary": "Create a webhook", "operationId": "create_webhook", @@ -143,8 +131,7 @@ "application/json" ], "tags": [ - "observer", - "subscriptions" + "Observer" ], "summary": "Delete a webhook", "operationId": "delete_webhook", @@ -187,7 +174,7 @@ "application/json" ], "tags": [ - "charts" + "Market" ], "summary": "Get charts data for a specific coin", "operationId": "get_charts_data", @@ -248,7 +235,7 @@ "application/json" ], "tags": [ - "charts" + "Market" ], "summary": "Get charts coin info data for a specific coin", "operationId": "get_charts_coin_info", @@ -302,7 +289,7 @@ "application/json" ], "tags": [ - "ticker" + "Market" ], "summary": "Get ticker value for a specific market", "operationId": "get_ticker", @@ -338,7 +325,7 @@ } }, "post": { - "description": "Get the ticker values from many markets and coin/token", + "description": "Get the ticker values from many market and coin/token", "consumes": [ "application/json" ], @@ -346,9 +333,9 @@ "application/json" ], "tags": [ - "ticker" + "Market" ], - "summary": "Get ticker values for a specific markets", + "summary": "Get ticker values for a specific market", "operationId": "get_tickers", "parameters": [ { @@ -381,8 +368,7 @@ "application/json" ], "tags": [ - "platform", - "tx" + "Platform-Transactions" ], "summary": "Get xpub transactions", "operationId": "xpub", @@ -424,8 +410,7 @@ "application/json" ], "tags": [ - "platform", - "tx" + "Platform-Transactions" ], "summary": "Get Transactions", "operationId": "tx_v1", @@ -467,7 +452,7 @@ "application/json" ], "tags": [ - "Collectibles" + "Platform-Collections" ], "summary": "Get list of collections from a specific coin and addresses", "operationId": "collection_categories_v2", @@ -500,7 +485,7 @@ "application/json" ], "tags": [ - "ns" + "Platform-Naming-Service" ], "summary": "Lookup .eth / .zil addresses", "operationId": "lookup", @@ -548,8 +533,7 @@ "application/json" ], "tags": [ - "platform", - "staking" + "Platform-Staking" ], "summary": "Get Multiple Stake Delegations", "operationId": "batch_delegations", @@ -584,8 +568,7 @@ "application/json" ], "tags": [ - "platform", - "staking" + "Platform-Staking" ], "summary": "Get Multiple Stake Delegations", "operationId": "batch_delegations", @@ -596,7 +579,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/api.CoinsRequest" + "$ref": "#/definitions/api.AddressesRequest" } } ], @@ -620,8 +603,7 @@ "application/json" ], "tags": [ - "platform", - "collection" + "Platform-Collections" ], "summary": "Get Collections", "operationId": "collections_v2", @@ -669,8 +651,7 @@ "application/json" ], "tags": [ - "platform", - "collection" + "Platform-Collections" ], "summary": "Get Collection", "operationId": "collection_v2", @@ -726,8 +707,7 @@ "application/json" ], "tags": [ - "platform", - "staking" + "Platform-Staking" ], "summary": "Get Stake Delegations", "operationId": "delegations", @@ -775,8 +755,7 @@ "application/json" ], "tags": [ - "platform", - "staking" + "Platform-Staking" ], "summary": "Get Validators", "operationId": "validators", @@ -816,8 +795,7 @@ "application/json" ], "tags": [ - "platform", - "token" + "Platform-Transactions" ], "summary": "Get Tokens", "operationId": "tokens", @@ -865,8 +843,7 @@ "application/json" ], "tags": [ - "platform", - "tx" + "Platform-Transactions" ], "summary": "Get Transactions", "operationId": "tx_v2", @@ -914,7 +891,7 @@ "application/json" ], "tags": [ - "Collectibles" + "Platform-Collections" ], "summary": "Get list of collections from a specific coin and addresses", "operationId": "collection_categories_v3", @@ -950,8 +927,7 @@ "application/json" ], "tags": [ - "platform", - "collection" + "Platform-Collections" ], "summary": "Get Collections", "operationId": "collections_v3", @@ -999,8 +975,7 @@ "application/json" ], "tags": [ - "platform", - "collection" + "Platform-Collections" ], "summary": "Get Collection", "operationId": "collection_v3", @@ -1079,20 +1054,6 @@ } } }, - "api.CoinBatchRequest": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - } - } - }, - "api.CoinsRequest": { - "type": "array", - "items": { - "$ref": "#/definitions/api.CoinBatchRequest" - } - }, "api.TickerRequest": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 93586ae35..4c0fb078e 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -19,15 +19,6 @@ definitions: type: type: string type: object - api.CoinBatchRequest: - properties: - coin: - type: integer - type: object - api.CoinsRequest: - items: - $ref: '#/definitions/api.CoinBatchRequest' - type: array api.TickerRequest: properties: assets: @@ -387,13 +378,6 @@ info: contact: {} license: {} paths: - /metrics: - get: - description: Get application metrics - operationId: metrics - summary: Get Metrics - tags: - - metrics /ns/lookup: get: description: Lookup ENS/ZNS to find registered addresses @@ -420,7 +404,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Lookup .eth / .zil addresses tags: - - ns + - Platform-Naming-Service /observer/v1/status: get: consumes: @@ -443,8 +427,7 @@ paths: $ref: '#/definitions/blockatlas.CoinStatus' summary: Get coin status tags: - - observer - - subscriptions + - Observer /observer/v1/webhook/register: delete: consumes: @@ -473,8 +456,7 @@ paths: $ref: '#/definitions/blockatlas.Observer' summary: Delete a webhook tags: - - observer - - subscriptions + - Observer post: consumes: - application/json @@ -502,8 +484,7 @@ paths: $ref: '#/definitions/blockatlas.Observer' summary: Create a webhook tags: - - observer - - subscriptions + - Observer /v1/{coin}/{address}: get: consumes: @@ -532,8 +513,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Transactions tags: - - platform - - tx + - Platform-Transactions /v1/{coin}/xpub/{xpub}: get: consumes: @@ -562,8 +542,7 @@ paths: $ref: '#/definitions/blockatlas.TxPage' summary: Get xpub transactions tags: - - platform - - tx + - Platform-Transactions /v1/market/charts: get: consumes: @@ -605,7 +584,7 @@ paths: $ref: '#/definitions/blockatlas.ChartData' summary: Get charts data for a specific coin tags: - - charts + - Market /v1/market/info: get: consumes: @@ -642,7 +621,7 @@ paths: $ref: '#/definitions/blockatlas.ChartCoinInfo' summary: Get charts coin info data for a specific coin tags: - - charts + - Market /v1/market/ticker: get: consumes: @@ -673,11 +652,11 @@ paths: $ref: '#/definitions/blockatlas.Ticker' summary: Get ticker value for a specific market tags: - - ticker + - Market post: consumes: - application/json - description: Get the ticker values from many markets and coin/token + description: Get the ticker values from many market and coin/token operationId: get_tickers parameters: - description: Ticker @@ -693,9 +672,9 @@ paths: description: OK schema: $ref: '#/definitions/blockatlas.Tickers' - summary: Get ticker values for a specific markets + summary: Get ticker values for a specific market tags: - - ticker + - Market /v2/{coin}/collections/{address}: get: consumes: @@ -728,8 +707,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Collections tags: - - platform - - collection + - Platform-Collections /v2/{coin}/collections/{owner}/collection/{collection_id}: get: consumes: @@ -768,8 +746,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Collection tags: - - platform - - collection + - Platform-Collections /v2/{coin}/staking/delegations/{address}: get: consumes: @@ -802,8 +779,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Stake Delegations tags: - - platform - - staking + - Platform-Staking /v2/{coin}/staking/validators: get: consumes: @@ -830,8 +806,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Validators tags: - - platform - - staking + - Platform-Staking /v2/{coin}/tokens/{address}: get: consumes: @@ -864,8 +839,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Tokens tags: - - platform - - token + - Platform-Transactions /v2/{coin}/transactions/{address}: get: consumes: @@ -898,8 +872,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Transactions tags: - - platform - - tx + - Platform-Transactions /v2/collectibles/categories: post: consumes: @@ -923,7 +896,7 @@ paths: $ref: '#/definitions/blockatlas.DocsResponse' summary: Get list of collections from a specific coin and addresses tags: - - Collectibles + - Platform-Collections /v2/ns/lookup: get: description: Lookup ENS/ZNS to find registered addresses for multiple coins @@ -953,7 +926,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Lookup .eth / .zil addresses tags: - - ns + - Platform-Naming-Service /v2/staking/delegations: post: consumes: @@ -976,8 +949,7 @@ paths: $ref: '#/definitions/blockatlas.DelegationsBatchPage' summary: Get Multiple Stake Delegations tags: - - platform - - staking + - Platform-Staking /v2/staking/list: post: consumes: @@ -990,7 +962,7 @@ paths: name: delegations required: true schema: - $ref: '#/definitions/api.CoinsRequest' + $ref: '#/definitions/api.AddressesRequest' produces: - application/json responses: @@ -1000,8 +972,7 @@ paths: $ref: '#/definitions/blockatlas.DelegationsBatchPage' summary: Get Multiple Stake Delegations tags: - - platform - - staking + - Platform-Staking /v3/{coin}/collections/{address}: get: consumes: @@ -1034,8 +1005,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Collections tags: - - platform - - collection + - Platform-Collections /v3/{coin}/collections/{owner}/collection/{collection_id}: get: consumes: @@ -1074,8 +1044,7 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Collection tags: - - platform - - collection + - Platform-Collections /v3/collectibles/categories: post: consumes: @@ -1099,5 +1068,5 @@ paths: $ref: '#/definitions/blockatlas.DocsResponse' summary: Get list of collections from a specific coin and addresses tags: - - Collectibles + - Platform-Collections swagger: "2.0" diff --git a/go.sum b/go.sum index 9e56ad9ab..f5dc2222d 100644 --- a/go.sum +++ b/go.sum @@ -18,12 +18,15 @@ github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EF github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Pantani/httpexpect v2.0.0+incompatible/go.mod h1:+8VdK+EZPV0YorWMMNyakEIYKcDl9OHtde3DdkPqbwQ= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= @@ -32,6 +35,7 @@ github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -47,25 +51,33 @@ github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= github.com/btcsuite/btcd v0.0.0-20190418232430-6867ff32788a/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.1 h1:GKOz8BnRjYrb/JTKgaOk+zh26NWNdSNvdvv0xoAZMSA= github.com/btcsuite/btcutil v1.0.1/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05 h1:2qhpRcnS61pafr2CbHYBr9ZWN7I8txgEOkBUm8Z7NH4= github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= @@ -76,13 +88,16 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c h1:4e6Zsb6LFd3kadoMiut2zcd3hCb4zywpJnQa8+NV2Cs= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c/go.mod h1:k5D13LCXSsMrQyfdW0yGYs4GWUvirqoxHht8qwtqyRY= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= @@ -94,13 +109,16 @@ github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= +github.com/elastic/gosigar v0.10.4 h1:6jfw75dsoflhBMRdO6QPzQUgLqUYTsQQQRkkcsHsuPo= github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= +github.com/ethereum/go-ethereum v1.9.10 h1:jooX7tWcscpC7ytufk73t9JMCeJQ7aJF2YmZJQEuvFo= github.com/ethereum/go-ethereum v1.9.10/go.mod h1:lXHkVo/MTvsEXfYsmNzelZ8R1e0DTvdk/wMZJIRpaRw= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -108,17 +126,22 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/getsentry/sentry-go v0.4.0 h1:WqRI2/7EiALbdG9qGB47c0Aks1tdznG5DZd6GSQ1y/8= github.com/getsentry/sentry-go v0.4.0/go.mod h1:xkGcb82SipKQloDNa5b7hTV4VdEyc2bhwd1/UczP52k= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -130,20 +153,28 @@ github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AE github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/go-redis/redis v6.15.6+incompatible h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be8FqJQRhdQZ5Sg= github.com/go-redis/redis v6.15.6+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= @@ -158,8 +189,10 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -169,11 +202,13 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6/go.mod h1:Au3iQ8DvDis8hZ4q2OzRcaKYlAsPt+fYvib5q4nIqu4= github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= @@ -182,12 +217,16 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hewigovens/go-coincodec v1.0.4 h1:asF02q8WfDwVQjU1O0VZYbOBer0cPJUmTiZKfAgqBYM= github.com/hewigovens/go-coincodec v1.0.4/go.mod h1:+LTdzScnu782gMt0J3ZccPY9S2uyrGe0R1LUYGWecfc= github.com/howeyc/fsnotify v0.9.0/go.mod h1:41HzSPxBGeFRQKEEwgh49TRw/nKBsYZ2cF1OzPjSJsA= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= @@ -202,7 +241,9 @@ github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+ github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -242,9 +283,12 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= +github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -260,20 +304,25 @@ github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXT github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +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/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5 h1:l16XLUUJ34wIz+RIvLhSwGvLvKyy+W598b135bJN6mg= github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -282,6 +331,7 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= @@ -302,18 +352,24 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/oschwald/maxminddb-golang v1.3.1/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -331,13 +387,17 @@ github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLk github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic= github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= github.com/robertkrimen/otto v0.0.0-20170205013659-6a77b7cbc37d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -345,9 +405,11 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 h1:Pm6R878vxWWWR+Sa3ppsLce/Zq+JNTs6aVvRu13jv9A= github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -355,42 +417,58 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw= github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= +github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= +github.com/swaggo/swag v1.6.5 h1:2C+t+xyK6p1sujqncYO/VnMvPZcBJjNdKKyxbOdAW8o= github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -401,10 +479,14 @@ github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBn github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/wealdtech/go-ens/v3 v3.1.0/go.mod h1:P2OEBvgkhXLrPzPN+eR5z2/wFIGwHyijTDvpuC1xLlo= +github.com/wealdtech/go-ens/v3 v3.2.0 h1:bshYk63BUJaIriX3UoAcYKh1tVI85kI1Xbg3jAnM/NM= github.com/wealdtech/go-ens/v3 v3.2.0/go.mod h1:P2OEBvgkhXLrPzPN+eR5z2/wFIGwHyijTDvpuC1xLlo= +github.com/wealdtech/go-multicodec v1.2.0 h1:9AHSxcSE9F9r6ZvQLAO0EXCdM08QfYohaXmW3k6sSh4= github.com/wealdtech/go-multicodec v1.2.0/go.mod h1:aedGMaTeYkIqi/KCPre1ho5rTb3hGpu/snBOS3GQLw4= +github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= github.com/wealdtech/go-string2eth v1.0.0/go.mod h1:UZA/snEybGcD6n+Pl+yoDjmexlEJ6dtoS9myfM83Ol4= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -431,6 +513,7 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -450,6 +533,7 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -477,6 +561,7 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -505,7 +590,9 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= @@ -521,6 +608,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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/init.go b/internal/init.go new file mode 100644 index 000000000..f2d3c0616 --- /dev/null +++ b/internal/init.go @@ -0,0 +1,66 @@ +package internal + +import ( + "flag" + sentrygin "github.com/getsentry/sentry-go/gin" + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/storage" + "path/filepath" +) + +func InitAPI(defaultPort, defaultConfigPath string) (string, string, *gin.HandlerFunc) { + var ( + port, confPath string + sg gin.HandlerFunc + ) + + sg = sentrygin.New(sentrygin.Options{}) + + flag.StringVar(&port, "p", defaultPort, "port for api") + flag.StringVar(&confPath, "c", defaultConfigPath, "config file for api") + flag.Parse() + + confPath, err := filepath.Abs(confPath) + if err != nil { + logger.Fatal(err) + } + + config.LoadConfig(confPath) + logger.InitLogger() + + return port, confPath, &sg +} + +func InitAPIWithRedis(defaultPort, defaultConfigPath string) (string, string, *gin.HandlerFunc, *storage.Storage) { + var ( + port, confPath string + cache *storage.Storage + sg gin.HandlerFunc + ) + + cache = storage.New() + sg = sentrygin.New(sentrygin.Options{}) + + flag.StringVar(&port, "p", defaultPort, "port for api") + flag.StringVar(&confPath, "c", defaultConfigPath, "config file for api") + flag.Parse() + + confPath, err := filepath.Abs(confPath) + if err != nil { + logger.Fatal(err) + } + + config.LoadConfig(confPath) + logger.InitLogger() + + host := viper.GetString("storage.redis") + err = cache.Init(host) + if err != nil { + logger.Fatal(err) + } + + return port, confPath, &sg, cache +} diff --git a/internal/shutdown.go b/internal/shutdown.go new file mode 100644 index 000000000..37f958689 --- /dev/null +++ b/internal/shutdown.go @@ -0,0 +1,45 @@ +package internal + +import ( + "context" + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/pkg/logger" + "net/http" + "os" + "os/signal" + "syscall" + "time" +) + +func SetupGracefulShutdown(port string, engine *gin.Engine) { + server := &http.Server{ + Addr: ":" + port, + Handler: engine, + } + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + + defer cancel() + defer func() { + if err := server.Shutdown(ctx); err != nil { + logger.Fatal("Server Shutdown: ", err) + } + }() + + signalForExit := make(chan os.Signal, 1) + signal.Notify(signalForExit, + syscall.SIGHUP, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT) + + go func() { + if err := server.ListenAndServe(); err != nil { + logger.Fatal("Application failed", err) + } + }() + logger.Info("Running application", logger.Params{"bind": port}) + + stop := <-signalForExit + logger.Info("Stop signal Received", stop) + logger.Info("Waiting for all jobs to stop") +} diff --git a/syncmarkets/chart/chart.go b/market/chart/chart.go similarity index 100% rename from syncmarkets/chart/chart.go rename to market/chart/chart.go diff --git a/syncmarkets/chart/cmc/cmc.go b/market/chart/cmc/cmc.go similarity index 96% rename from syncmarkets/chart/cmc/cmc.go rename to market/chart/cmc/cmc.go index be07067ba..e949463a1 100644 --- a/syncmarkets/chart/cmc/cmc.go +++ b/market/chart/cmc/cmc.go @@ -1,10 +1,10 @@ package cmc import ( + "github.com/trustwallet/blockatlas/market/chart" + "github.com/trustwallet/blockatlas/market/clients/cmc" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/syncmarkets/chart" - "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" "time" ) diff --git a/syncmarkets/chart/cmc/cmc_test.go b/market/chart/cmc/cmc_test.go similarity index 98% rename from syncmarkets/chart/cmc/cmc_test.go rename to market/chart/cmc/cmc_test.go index 4d58485a2..e97e0474a 100644 --- a/syncmarkets/chart/cmc/cmc_test.go +++ b/market/chart/cmc/cmc_test.go @@ -2,8 +2,8 @@ package cmc import ( "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/market/clients/cmc" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" "reflect" "sort" "testing" diff --git a/syncmarkets/chart/coingecko/coingecko.go b/market/chart/coingecko/coingecko.go similarity index 95% rename from syncmarkets/chart/coingecko/coingecko.go rename to market/chart/coingecko/coingecko.go index 937261d25..cad5d4ddc 100644 --- a/syncmarkets/chart/coingecko/coingecko.go +++ b/market/chart/coingecko/coingecko.go @@ -2,10 +2,10 @@ package coingecko import ( "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/market/chart" + "github.com/trustwallet/blockatlas/market/clients/coingecko" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/syncmarkets/chart" - "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" "time" ) diff --git a/syncmarkets/chart/coingecko/coingecko_test.go b/market/chart/coingecko/coingecko_test.go similarity index 96% rename from syncmarkets/chart/coingecko/coingecko_test.go rename to market/chart/coingecko/coingecko_test.go index 26f6f4ed9..f7a845fee 100644 --- a/syncmarkets/chart/coingecko/coingecko_test.go +++ b/market/chart/coingecko/coingecko_test.go @@ -2,8 +2,8 @@ package coingecko import ( "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/market/clients/coingecko" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" "reflect" "testing" "time" diff --git a/syncmarkets/chart/provider.go b/market/chart/provider.go similarity index 100% rename from syncmarkets/chart/provider.go rename to market/chart/provider.go diff --git a/syncmarkets/charts.go b/market/charts.go similarity index 91% rename from syncmarkets/charts.go rename to market/charts.go index 121e18e9c..cab0408b4 100644 --- a/syncmarkets/charts.go +++ b/market/charts.go @@ -1,13 +1,13 @@ -package syncmarkets +package market import ( "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/market/chart" + "github.com/trustwallet/blockatlas/market/chart/cmc" + "github.com/trustwallet/blockatlas/market/chart/coingecko" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" - "github.com/trustwallet/blockatlas/syncmarkets/chart" - "github.com/trustwallet/blockatlas/syncmarkets/chart/cmc" - "github.com/trustwallet/blockatlas/syncmarkets/chart/coingecko" "math" "sort" ) diff --git a/syncmarkets/charts_test.go b/market/charts_test.go similarity index 99% rename from syncmarkets/charts_test.go rename to market/charts_test.go index 318969cb4..f4bdf7a54 100644 --- a/syncmarkets/charts_test.go +++ b/market/charts_test.go @@ -1,4 +1,4 @@ -package syncmarkets +package market import ( "github.com/stretchr/testify/assert" diff --git a/syncmarkets/clients/cmc/cache.go b/market/clients/cmc/cache.go similarity index 100% rename from syncmarkets/clients/cmc/cache.go rename to market/clients/cmc/cache.go diff --git a/syncmarkets/clients/cmc/cache_test.go b/market/clients/cmc/cache_test.go similarity index 100% rename from syncmarkets/clients/cmc/cache_test.go rename to market/clients/cmc/cache_test.go diff --git a/syncmarkets/clients/cmc/client.go b/market/clients/cmc/client.go similarity index 100% rename from syncmarkets/clients/cmc/client.go rename to market/clients/cmc/client.go diff --git a/syncmarkets/clients/cmc/models.go b/market/clients/cmc/models.go similarity index 100% rename from syncmarkets/clients/cmc/models.go rename to market/clients/cmc/models.go diff --git a/syncmarkets/clients/cmc/webclient.go b/market/clients/cmc/webclient.go similarity index 100% rename from syncmarkets/clients/cmc/webclient.go rename to market/clients/cmc/webclient.go diff --git a/syncmarkets/clients/cmc/widgetclient.go b/market/clients/cmc/widgetclient.go similarity index 100% rename from syncmarkets/clients/cmc/widgetclient.go rename to market/clients/cmc/widgetclient.go diff --git a/syncmarkets/clients/coingecko/cache.go b/market/clients/coingecko/cache.go similarity index 100% rename from syncmarkets/clients/coingecko/cache.go rename to market/clients/coingecko/cache.go diff --git a/syncmarkets/clients/coingecko/cache_test.go b/market/clients/coingecko/cache_test.go similarity index 100% rename from syncmarkets/clients/coingecko/cache_test.go rename to market/clients/coingecko/cache_test.go diff --git a/syncmarkets/clients/coingecko/client.go b/market/clients/coingecko/client.go similarity index 97% rename from syncmarkets/clients/coingecko/client.go rename to market/clients/coingecko/client.go index d8774fc05..5d71bee85 100644 --- a/syncmarkets/clients/coingecko/client.go +++ b/market/clients/coingecko/client.go @@ -48,7 +48,7 @@ func (c *Client) FetchLatestRates(coins GeckoCoins, currency string) (prices Coi } var cp CoinPrices - err := c.Get(&cp, "v3/coins/markets", values) + err := c.Get(&cp, "v3/coins/market", values) if err != nil { logger.Error(err) return diff --git a/syncmarkets/clients/coingecko/client_test.go b/market/clients/coingecko/client_test.go similarity index 100% rename from syncmarkets/clients/coingecko/client_test.go rename to market/clients/coingecko/client_test.go diff --git a/syncmarkets/clients/coingecko/models.go b/market/clients/coingecko/models.go similarity index 100% rename from syncmarkets/clients/coingecko/models.go rename to market/clients/coingecko/models.go diff --git a/syncmarkets/clients/compound/client.go b/market/clients/compound/client.go similarity index 100% rename from syncmarkets/clients/compound/client.go rename to market/clients/compound/client.go diff --git a/syncmarkets/clients/compound/models.go b/market/clients/compound/models.go similarity index 100% rename from syncmarkets/clients/compound/models.go rename to market/clients/compound/models.go diff --git a/syncmarkets/market.go b/market/market.go similarity index 83% rename from syncmarkets/market.go rename to market/market.go index 8343e564e..7e00db258 100644 --- a/syncmarkets/market.go +++ b/market/market.go @@ -1,16 +1,16 @@ -package syncmarkets +package market import ( "github.com/robfig/cron/v3" "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/market/market" + "github.com/trustwallet/blockatlas/market/market/cmc" + "github.com/trustwallet/blockatlas/market/market/coingecko" + "github.com/trustwallet/blockatlas/market/market/compound" + "github.com/trustwallet/blockatlas/market/market/dex" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" - "github.com/trustwallet/blockatlas/syncmarkets/market" - "github.com/trustwallet/blockatlas/syncmarkets/market/cmc" - "github.com/trustwallet/blockatlas/syncmarkets/market/coingecko" - "github.com/trustwallet/blockatlas/syncmarkets/market/compound" - "github.com/trustwallet/blockatlas/syncmarkets/market/dex" ) var marketProviders market.Providers diff --git a/syncmarkets/market/cmc/cmc.go b/market/market/cmc/cmc.go similarity index 95% rename from syncmarkets/market/cmc/cmc.go rename to market/market/cmc/cmc.go index 67ae4b533..214c44716 100644 --- a/syncmarkets/market/cmc/cmc.go +++ b/market/market/cmc/cmc.go @@ -1,9 +1,9 @@ package cmc import ( + "github.com/trustwallet/blockatlas/market/clients/cmc" + "github.com/trustwallet/blockatlas/market/market" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" - "github.com/trustwallet/blockatlas/syncmarkets/market" ) const ( diff --git a/syncmarkets/market/cmc/cmc_test.go b/market/market/cmc/cmc_test.go similarity index 98% rename from syncmarkets/market/cmc/cmc_test.go rename to market/market/cmc/cmc_test.go index 1d57c680e..1e90b1991 100644 --- a/syncmarkets/market/cmc/cmc_test.go +++ b/market/market/cmc/cmc_test.go @@ -2,8 +2,8 @@ package cmc import ( "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/market/clients/cmc" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" "sort" "testing" "time" diff --git a/syncmarkets/market/coingecko/coingecko.go b/market/market/coingecko/coingecko.go similarity index 94% rename from syncmarkets/market/coingecko/coingecko.go rename to market/market/coingecko/coingecko.go index 0097e1ffb..6729505ff 100644 --- a/syncmarkets/market/coingecko/coingecko.go +++ b/market/market/coingecko/coingecko.go @@ -1,9 +1,9 @@ package coingecko import ( + "github.com/trustwallet/blockatlas/market/clients/coingecko" + "github.com/trustwallet/blockatlas/market/market" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" - "github.com/trustwallet/blockatlas/syncmarkets/market" "strings" ) diff --git a/syncmarkets/market/coingecko/coingecko_test.go b/market/market/coingecko/coingecko_test.go similarity index 97% rename from syncmarkets/market/coingecko/coingecko_test.go rename to market/market/coingecko/coingecko_test.go index 55eb6c343..3c3a20c3f 100644 --- a/syncmarkets/market/coingecko/coingecko_test.go +++ b/market/market/coingecko/coingecko_test.go @@ -2,8 +2,8 @@ package coingecko import ( "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/market/clients/coingecko" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" "sort" "testing" "time" diff --git a/syncmarkets/market/compound/compound.go b/market/market/compound/compound.go similarity index 91% rename from syncmarkets/market/compound/compound.go rename to market/market/compound/compound.go index 7a1973640..379fa63be 100644 --- a/syncmarkets/market/compound/compound.go +++ b/market/market/compound/compound.go @@ -2,9 +2,9 @@ package compound import ( "github.com/trustwallet/blockatlas/coin" + c "github.com/trustwallet/blockatlas/market/clients/compound" + "github.com/trustwallet/blockatlas/market/market" "github.com/trustwallet/blockatlas/pkg/blockatlas" - c "github.com/trustwallet/blockatlas/syncmarkets/clients/compound" - "github.com/trustwallet/blockatlas/syncmarkets/market" "time" ) diff --git a/syncmarkets/market/compound/compound_test.go b/market/market/compound/compound_test.go similarity index 96% rename from syncmarkets/market/compound/compound_test.go rename to market/market/compound/compound_test.go index bffdf2902..15bc971ea 100644 --- a/syncmarkets/market/compound/compound_test.go +++ b/market/market/compound/compound_test.go @@ -3,8 +3,8 @@ package compound import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/market/clients/compound" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/compound" "sort" "testing" "time" diff --git a/syncmarkets/market/dex/dex.go b/market/market/dex/dex.go similarity index 97% rename from syncmarkets/market/dex/dex.go rename to market/market/dex/dex.go index 284e7065b..7b1fc3ec5 100644 --- a/syncmarkets/market/dex/dex.go +++ b/market/market/dex/dex.go @@ -2,9 +2,9 @@ package dex import ( "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/market/market" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/syncmarkets/market" "math/big" "net/url" "strconv" diff --git a/syncmarkets/market/dex/dex_test.go b/market/market/dex/dex_test.go similarity index 100% rename from syncmarkets/market/dex/dex_test.go rename to market/market/dex/dex_test.go diff --git a/syncmarkets/market/dex/models.go b/market/market/dex/models.go similarity index 100% rename from syncmarkets/market/dex/models.go rename to market/market/dex/models.go diff --git a/syncmarkets/market/market.go b/market/market/market.go similarity index 100% rename from syncmarkets/market/market.go rename to market/market/market.go diff --git a/syncmarkets/market/provider.go b/market/market/provider.go similarity index 100% rename from syncmarkets/market/provider.go rename to market/market/provider.go diff --git a/syncmarkets/rate/cmc/cmc.go b/market/rate/cmc/cmc.go similarity index 90% rename from syncmarkets/rate/cmc/cmc.go rename to market/rate/cmc/cmc.go index fdb480a47..7f53f2b2d 100644 --- a/syncmarkets/rate/cmc/cmc.go +++ b/market/rate/cmc/cmc.go @@ -1,9 +1,9 @@ package cmc import ( + "github.com/trustwallet/blockatlas/market/clients/cmc" + "github.com/trustwallet/blockatlas/market/rate" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" - "github.com/trustwallet/blockatlas/syncmarkets/rate" "math/big" ) diff --git a/syncmarkets/rate/cmc/cmc_test.go b/market/rate/cmc/cmc_test.go similarity index 97% rename from syncmarkets/rate/cmc/cmc_test.go rename to market/rate/cmc/cmc_test.go index 4c192a900..b060caa8c 100644 --- a/syncmarkets/rate/cmc/cmc_test.go +++ b/market/rate/cmc/cmc_test.go @@ -2,8 +2,8 @@ package cmc import ( "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/market/clients/cmc" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/cmc" "math/big" "sort" "testing" diff --git a/syncmarkets/rate/coingecko/coingecko.go b/market/rate/coingecko/coingecko.go similarity index 89% rename from syncmarkets/rate/coingecko/coingecko.go rename to market/rate/coingecko/coingecko.go index 6628367a6..25cb8f874 100644 --- a/syncmarkets/rate/coingecko/coingecko.go +++ b/market/rate/coingecko/coingecko.go @@ -1,9 +1,9 @@ package coingecko import ( + "github.com/trustwallet/blockatlas/market/clients/coingecko" + "github.com/trustwallet/blockatlas/market/rate" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" - "github.com/trustwallet/blockatlas/syncmarkets/rate" "strings" ) diff --git a/syncmarkets/rate/coingecko/coingecko_test.go b/market/rate/coingecko/coingecko_test.go similarity index 96% rename from syncmarkets/rate/coingecko/coingecko_test.go rename to market/rate/coingecko/coingecko_test.go index d2174f7e4..3757e2421 100644 --- a/syncmarkets/rate/coingecko/coingecko_test.go +++ b/market/rate/coingecko/coingecko_test.go @@ -2,8 +2,8 @@ package coingecko import ( "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/market/clients/coingecko" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/clients/coingecko" "sort" "testing" "time" diff --git a/syncmarkets/rate/compound/compound.go b/market/rate/compound/compound.go similarity index 88% rename from syncmarkets/rate/compound/compound.go rename to market/rate/compound/compound.go index 5f80293b3..a641ea806 100644 --- a/syncmarkets/rate/compound/compound.go +++ b/market/rate/compound/compound.go @@ -1,9 +1,9 @@ package compound import ( + c "github.com/trustwallet/blockatlas/market/clients/compound" + "github.com/trustwallet/blockatlas/market/rate" "github.com/trustwallet/blockatlas/pkg/blockatlas" - c "github.com/trustwallet/blockatlas/syncmarkets/clients/compound" - "github.com/trustwallet/blockatlas/syncmarkets/rate" "strings" "time" ) diff --git a/syncmarkets/rate/compound/compound_test.go b/market/rate/compound/compound_test.go similarity index 96% rename from syncmarkets/rate/compound/compound_test.go rename to market/rate/compound/compound_test.go index cdb1460c0..430c82322 100644 --- a/syncmarkets/rate/compound/compound_test.go +++ b/market/rate/compound/compound_test.go @@ -2,8 +2,8 @@ package compound import ( "github.com/stretchr/testify/assert" + c "github.com/trustwallet/blockatlas/market/clients/compound" "github.com/trustwallet/blockatlas/pkg/blockatlas" - c "github.com/trustwallet/blockatlas/syncmarkets/clients/compound" "sort" "testing" "time" diff --git a/syncmarkets/rate/fixer/fixer.go b/market/rate/fixer/fixer.go similarity index 94% rename from syncmarkets/rate/fixer/fixer.go rename to market/rate/fixer/fixer.go index e5d7359f7..34a2587a8 100644 --- a/syncmarkets/rate/fixer/fixer.go +++ b/market/rate/fixer/fixer.go @@ -1,8 +1,8 @@ package fixer import ( + "github.com/trustwallet/blockatlas/market/rate" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/syncmarkets/rate" "net/url" ) diff --git a/syncmarkets/rate/fixer/fixer_test.go b/market/rate/fixer/fixer_test.go similarity index 100% rename from syncmarkets/rate/fixer/fixer_test.go rename to market/rate/fixer/fixer_test.go diff --git a/syncmarkets/rate/fixer/models.go b/market/rate/fixer/models.go similarity index 100% rename from syncmarkets/rate/fixer/models.go rename to market/rate/fixer/models.go diff --git a/syncmarkets/rate/provider.go b/market/rate/provider.go similarity index 100% rename from syncmarkets/rate/provider.go rename to market/rate/provider.go diff --git a/syncmarkets/rate/rate.go b/market/rate/rate.go similarity index 100% rename from syncmarkets/rate/rate.go rename to market/rate/rate.go diff --git a/syncmarkets/rates.go b/market/rates.go similarity index 82% rename from syncmarkets/rates.go rename to market/rates.go index ae49bc42f..d2b361e01 100644 --- a/syncmarkets/rates.go +++ b/market/rates.go @@ -1,16 +1,16 @@ -package syncmarkets +package market import ( "github.com/robfig/cron/v3" "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/market/rate" + "github.com/trustwallet/blockatlas/market/rate/cmc" + "github.com/trustwallet/blockatlas/market/rate/coingecko" + "github.com/trustwallet/blockatlas/market/rate/compound" + "github.com/trustwallet/blockatlas/market/rate/fixer" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" - "github.com/trustwallet/blockatlas/syncmarkets/rate" - "github.com/trustwallet/blockatlas/syncmarkets/rate/cmc" - "github.com/trustwallet/blockatlas/syncmarkets/rate/coingecko" - "github.com/trustwallet/blockatlas/syncmarkets/rate/compound" - "github.com/trustwallet/blockatlas/syncmarkets/rate/fixer" ) var rateProviders rate.Providers diff --git a/syncmarkets/worker.go b/market/worker.go similarity index 93% rename from syncmarkets/worker.go rename to market/worker.go index 23ed50656..d14545ebd 100644 --- a/syncmarkets/worker.go +++ b/market/worker.go @@ -1,14 +1,14 @@ -package syncmarkets +package market import ( "fmt" "github.com/cenkalti/backoff" "github.com/robfig/cron/v3" + "github.com/trustwallet/blockatlas/market/market" + "github.com/trustwallet/blockatlas/market/rate" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" - "github.com/trustwallet/blockatlas/syncmarkets/market" - "github.com/trustwallet/blockatlas/syncmarkets/rate" "time" ) diff --git a/pkg/tests/functional/functional_test.go b/pkg/tests/functional/functional_test.go index f93c22630..c7126ec4c 100755 --- a/pkg/tests/functional/functional_test.go +++ b/pkg/tests/functional/functional_test.go @@ -30,7 +30,7 @@ func TestApis(t *testing.T) { config.LoadConfig(os.Getenv("TEST_CONFIG")) logger.InitLogger() - platform.Init() + platform.Init(viper.GetString("platform")) cache := storage.New() sg := sentrygin.New(sentrygin.Options{}) p := ":8420" diff --git a/pkg/tests/integration/integration_test.go b/pkg/tests/integration/integration_test.go index afbca8f02..858ccd7fa 100755 --- a/pkg/tests/integration/integration_test.go +++ b/pkg/tests/integration/integration_test.go @@ -3,6 +3,7 @@ package integration import ( + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/tests/integration/bitcoin" "github.com/trustwallet/blockatlas/pkg/tests/integration/domains" @@ -19,7 +20,7 @@ func Test(t *testing.T) { } else { config.LoadConfig(configPath) } - platform.Init() + platform.Init(viper.GetString("platform")) // Add your integration tests here ontology.TestOntology(t) diff --git a/platform/bitcoin/api.go b/platform/bitcoin/api.go index 92e10d512..116778328 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,tx +// @Tags Platform-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/registry.go b/platform/registry.go index 2fc42a56c..35a51650b 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -2,12 +2,11 @@ package platform import ( "fmt" - "github.com/trustwallet/blockatlas/platform/cosmos" - "github.com/trustwallet/blockatlas/platform/polkadot" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/platform/cosmos" + "github.com/trustwallet/blockatlas/platform/polkadot" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/platform/aeternity" @@ -34,74 +33,187 @@ import ( "github.com/trustwallet/blockatlas/platform/zilliqa" ) -var platformList = []blockatlas.Platform{ - &binance.Platform{}, - &nimiq.Platform{}, - &ripple.Platform{}, - &stellar.Platform{CoinIndex: coin.XLM}, - &stellar.Platform{CoinIndex: coin.KIN}, - ðereum.Platform{CoinIndex: coin.ETH}, - ðereum.Platform{CoinIndex: coin.ETC}, - ðereum.Platform{CoinIndex: coin.POA}, - ðereum.Platform{CoinIndex: coin.CLO}, - ðereum.Platform{CoinIndex: coin.GO}, - ðereum.Platform{CoinIndex: coin.WAN}, - ðereum.Platform{CoinIndex: coin.TOMO}, - ðereum.Platform{CoinIndex: coin.TT}, - &cosmos.Platform{CoinIndex: coin.ATOM}, - &cosmos.Platform{CoinIndex: coin.KAVA}, - &tezos.Platform{}, - &aion.Platform{}, - &icon.Platform{}, - &iotex.Platform{}, - &ontology.Platform{}, - &theta.Platform{}, - &tron.Platform{}, - &vechain.Platform{}, - &zilliqa.Platform{}, - &waves.Platform{}, - &aeternity.Platform{}, - &bitcoin.Platform{CoinIndex: coin.BTC}, - &bitcoin.Platform{CoinIndex: coin.LTC}, - &bitcoin.Platform{CoinIndex: coin.BCH}, - &bitcoin.Platform{CoinIndex: coin.DASH}, - &bitcoin.Platform{CoinIndex: coin.DOGE}, - &bitcoin.Platform{CoinIndex: coin.ZEC}, - &bitcoin.Platform{CoinIndex: coin.XZC}, - &bitcoin.Platform{CoinIndex: coin.VIA}, - &bitcoin.Platform{CoinIndex: coin.RVN}, - &bitcoin.Platform{CoinIndex: coin.QTUM}, - &bitcoin.Platform{CoinIndex: coin.GRS}, - &bitcoin.Platform{CoinIndex: coin.ZEL}, - &bitcoin.Platform{CoinIndex: coin.DCR}, - &bitcoin.Platform{CoinIndex: coin.DGB}, - &nebulas.Platform{}, - &fio.Platform{}, - &algorand.Platform{}, - &nano.Platform{}, - &harmony.Platform{}, - &polkadot.Platform{CoinIndex: coin.KSM}, -} +var ( + allPlatformsList = []blockatlas.Platform{ + &binance.Platform{}, + &nimiq.Platform{}, + &ripple.Platform{}, + &stellar.Platform{CoinIndex: coin.XLM}, + &stellar.Platform{CoinIndex: coin.KIN}, + ðereum.Platform{CoinIndex: coin.ETH}, + ðereum.Platform{CoinIndex: coin.ETC}, + ðereum.Platform{CoinIndex: coin.POA}, + ðereum.Platform{CoinIndex: coin.CLO}, + ðereum.Platform{CoinIndex: coin.GO}, + ðereum.Platform{CoinIndex: coin.WAN}, + ðereum.Platform{CoinIndex: coin.TOMO}, + ðereum.Platform{CoinIndex: coin.TT}, + &cosmos.Platform{CoinIndex: coin.ATOM}, + &cosmos.Platform{CoinIndex: coin.KAVA}, + &tezos.Platform{}, + &aion.Platform{}, + &icon.Platform{}, + &iotex.Platform{}, + &ontology.Platform{}, + &theta.Platform{}, + &tron.Platform{}, + &vechain.Platform{}, + &zilliqa.Platform{}, + &waves.Platform{}, + &aeternity.Platform{}, + &bitcoin.Platform{CoinIndex: coin.BTC}, + &bitcoin.Platform{CoinIndex: coin.LTC}, + &bitcoin.Platform{CoinIndex: coin.BCH}, + &bitcoin.Platform{CoinIndex: coin.DASH}, + &bitcoin.Platform{CoinIndex: coin.DOGE}, + &bitcoin.Platform{CoinIndex: coin.ZEC}, + &bitcoin.Platform{CoinIndex: coin.XZC}, + &bitcoin.Platform{CoinIndex: coin.VIA}, + &bitcoin.Platform{CoinIndex: coin.RVN}, + &bitcoin.Platform{CoinIndex: coin.QTUM}, + &bitcoin.Platform{CoinIndex: coin.GRS}, + &bitcoin.Platform{CoinIndex: coin.ZEL}, + &bitcoin.Platform{CoinIndex: coin.DCR}, + &bitcoin.Platform{CoinIndex: coin.DGB}, + &nebulas.Platform{}, + &fio.Platform{}, + &algorand.Platform{}, + &nano.Platform{}, + &harmony.Platform{}, + &polkadot.Platform{CoinIndex: coin.KSM}, + } + + // Platforms contains all registered platforms by handle + Platforms map[string]blockatlas.Platform -// Platforms contains all registered platforms by handle -var Platforms map[string]blockatlas.Platform + // BlockAPIs contain platforms with block services + BlockAPIs map[string]blockatlas.BlockAPI -// BlockAPIs contain platforms with block services -var BlockAPIs map[string]blockatlas.BlockAPI + // StakeAPIs contain platforms with staking services + StakeAPIs map[string]blockatlas.StakeAPI -// StakeAPIs contain platforms with staking services -var StakeAPIs map[string]blockatlas.StakeAPI + // CustomAPIs contain platforms with custom HTTP services + CustomAPIs map[string]blockatlas.CustomAPI -// CustomAPIs contain platforms with custom HTTP services -var CustomAPIs map[string]blockatlas.CustomAPI + // NamingAPIs contain platforms which support naming services + NamingAPIs map[uint64]blockatlas.NamingServiceAPI -// NamingAPIs contain platforms which support naming services -var NamingAPIs map[uint64]blockatlas.NamingServiceAPI + // CollectionAPIs contain platforms which collections services + CollectionAPIs map[uint]blockatlas.CollectionAPI +) + +func getPlatform(handle string) blockatlas.Platform { + switch handle { + case coin.Binance().Handle: + return &binance.Platform{} + case coin.Nimiq().Handle: + return &nimiq.Platform{} + case coin.Ripple().Handle: + return &ripple.Platform{} + case coin.Stellar().Handle: + return &stellar.Platform{CoinIndex: coin.XLM} + case coin.Kin().Handle: + return &stellar.Platform{CoinIndex: coin.KIN} + case coin.Ethereum().Handle: + return ðereum.Platform{CoinIndex: coin.ETH} + case coin.Classic().Handle: + return ðereum.Platform{CoinIndex: coin.ETC} + case coin.Poa().Handle: + return ðereum.Platform{CoinIndex: coin.POA} + case coin.Callisto().Handle: + return ðereum.Platform{CoinIndex: coin.CLO} + case coin.Gochain().Handle: + return ðereum.Platform{CoinIndex: coin.GO} + case coin.Wanchain().Handle: + return ðereum.Platform{CoinIndex: coin.WAN} + case coin.Tomochain().Handle: + return ðereum.Platform{CoinIndex: coin.TOMO} + case coin.Thundertoken().Handle: + return ðereum.Platform{CoinIndex: coin.TT} + case coin.Cosmos().Handle: + return &cosmos.Platform{CoinIndex: coin.ATOM} + case coin.Kava().Handle: + return &cosmos.Platform{CoinIndex: coin.KAVA} + case coin.Tezos().Handle: + return &tezos.Platform{} + case coin.Aion().Handle: + return &aion.Platform{} + case coin.Icon().Handle: + return &icon.Platform{} + case coin.Iotex().Handle: + return &iotex.Platform{} + case coin.Ontology().Handle: + return &ontology.Platform{} + case coin.Theta().Handle: + return &theta.Platform{} + case coin.Tron().Handle: + return &tron.Platform{} + case coin.Vechain().Handle: + return &vechain.Platform{} + case coin.Zilliqa().Handle: + return &zilliqa.Platform{} + case coin.Waves().Handle: + return &waves.Platform{} + case coin.Aeternity().Handle: + return &aeternity.Platform{} + case coin.Bitcoin().Handle: + return &bitcoin.Platform{CoinIndex: coin.BTC} + case coin.Litecoin().Handle: + return &bitcoin.Platform{CoinIndex: coin.LTC} + case coin.Bitcoincash().Handle: + return &bitcoin.Platform{CoinIndex: coin.BCH} + case coin.Dash().Handle: + return &bitcoin.Platform{CoinIndex: coin.DASH} + case coin.Doge().Handle: + return &bitcoin.Platform{CoinIndex: coin.DOGE} + case coin.Zcash().Handle: + return &bitcoin.Platform{CoinIndex: coin.ZEC} + case coin.Zcoin().Handle: + return &bitcoin.Platform{CoinIndex: coin.XZC} + case coin.Viacoin().Handle: + return &bitcoin.Platform{CoinIndex: coin.VIA} + case coin.Ravencoin().Handle: + return &bitcoin.Platform{CoinIndex: coin.RVN} + case coin.Qtum().Handle: + return &bitcoin.Platform{CoinIndex: coin.QTUM} + case coin.Groestlcoin().Handle: + return &bitcoin.Platform{CoinIndex: coin.GRS} + case coin.Zelcash().Handle: + return &bitcoin.Platform{CoinIndex: coin.ZEL} + case coin.Decred().Handle: + return &bitcoin.Platform{CoinIndex: coin.DCR} + case coin.Digibyte().Handle: + return &bitcoin.Platform{CoinIndex: coin.DGB} + case coin.Nebulas().Handle: + return &nebulas.Platform{} + case coin.Fio().Handle: + return &fio.Platform{} + case coin.Algorand().Handle: + return &algorand.Platform{} + case coin.Nano().Handle: + return &nano.Platform{} + case coin.Harmony().Handle: + return &harmony.Platform{} + case coin.Kusama().Handle: + return &polkadot.Platform{CoinIndex: coin.KSM} + default: + return nil + } +} + +func getActivePlatforms(handle string) []blockatlas.Platform { + logger.Info("Loaded with: ", logger.Params{"handle": handle}) + + platform := getPlatform(handle) + if platform != nil { + return []blockatlas.Platform{platform} + } + return allPlatformsList +} -// CollectionAPIs contain platforms which collections services -var CollectionAPIs map[uint]blockatlas.CollectionAPI +func Init(platformHandle string) { + platformList := getActivePlatforms(platformHandle) -func Init() { Platforms = make(map[string]blockatlas.Platform) BlockAPIs = make(map[string]blockatlas.BlockAPI) StakeAPIs = make(map[string]blockatlas.StakeAPI) diff --git a/run_docker_compose.sh b/run_docker_compose.sh new file mode 100755 index 000000000..c58b5a447 --- /dev/null +++ b/run_docker_compose.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# https://github.com/jasperes/bash-yaml + +parse_yaml() { + local yaml_file=$1 + local prefix=$2 + local s + local w + local fs + + s='[[:space:]]*' + w='[a-zA-Z0-9_.-]*' + fs="$(echo @|tr @ '\034')" + + ( + sed -e '/- [^\“]'"[^\']"'.*: /s|\([ ]*\)- \([[:space:]]*\)|\1-\'$'\n'' \1\2|g' | + + sed -ne '/^--/s|--||g; s|\"|\\\"|g; s/[[:space:]]*$//g;' \ + -e "/#.*[\"\']/!s| #.*||g; /^#/s|#.*||g;" \ + -e "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \ + -e "s|^\($s\)\($w\)${s}[:-]$s\(.*\)$s\$|\1$fs\2$fs\3|p" | + + awk -F"$fs" '{ + indent = length($1)/2; + if (length($2) == 0) { conj[indent]="+";} else {conj[indent]="";} + vname[indent] = $2; + for (i in vname) {if (i > indent) {delete vname[i]}} + if (length($3) > 0) { + vn=""; for (i=0; i Date: Sat, 15 Feb 2020 02:38:50 +0900 Subject: [PATCH 124/506] Remove algorand key param from the config (#864) --- config.yml | 1 - platform/algorand/api.go | 1 - 2 files changed, 2 deletions(-) diff --git a/config.yml b/config.yml index f840aa18f..39a70f80a 100644 --- a/config.yml +++ b/config.yml @@ -215,7 +215,6 @@ decred: algorand: api: https://mainnet-algorand.api.purestake.io/ps1 -# key: YOUR_API_KEY nano: api: https://nanoverse.io/api/node diff --git a/platform/algorand/api.go b/platform/algorand/api.go index da2e015a8..fab56b1ce 100644 --- a/platform/algorand/api.go +++ b/platform/algorand/api.go @@ -15,7 +15,6 @@ type Platform struct { func (p *Platform) Init() error { p.client = Client{blockatlas.InitClient(viper.GetString("algorand.api"))} - p.client.Headers["x-api-key"] = viper.GetString("algorand.key") return nil } From 1fbe20dd6615efc5d75ecd65d641e7e26335e1e8 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 14 Feb 2020 18:07:56 -0300 Subject: [PATCH 125/506] [RIPPLE] Order tx by desc data and parse failed transactions (#867) * Order tx by desc data and parse failed transactions * Change tesSUCCESS to transactionResultSuccess --- platform/ripple/api.go | 29 +++++++------ platform/ripple/api_test.go | 85 ++++++++++++++++++++++++++++--------- platform/ripple/client.go | 6 +-- platform/ripple/model.go | 14 +++++- 4 files changed, 97 insertions(+), 37 deletions(-) diff --git a/platform/ripple/api.go b/platform/ripple/api.go index 0a1e27629..9397e87ff 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/api_test.go b/platform/ripple/api_test.go index e2f75498b..ef640bee5 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/platform/ripple/client.go b/platform/ripple/client.go index f4007c130..5e8ec7068 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 18c542871..af5101efb 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 { From 6539e3f5a58bcc125b65850740716b045a103bfa Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 14 Feb 2020 14:17:07 -0700 Subject: [PATCH 126/506] Swagger change tags (#868) --- api/batch.go | 8 ++++---- api/handlers.go | 14 +++++++------- api/naming_service.go | 4 ++-- api/stake.go | 4 ++-- docs/docs.go | 34 +++++++++++++++++----------------- docs/swagger.json | 32 ++++++++++++++++---------------- docs/swagger.yaml | 32 ++++++++++++++++---------------- platform/bitcoin/api.go | 2 +- 8 files changed, 65 insertions(+), 65 deletions(-) diff --git a/api/batch.go b/api/batch.go index a6bebd786..9f511c8d5 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 faca6102b..03ba0e4b3 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 a67506b7a..cd943e650 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 a350a6c30..610536275 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 @@ -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 b3327af2a..e52d2c064 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 dbdec9bb1..fce62e6b0 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 4c0fb078e..660b54e0b 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 116778328..7b89ee64f 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 From 2c029d9588fda6d0034d72dd352638395237b45d Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 14 Feb 2020 18:31:54 -0300 Subject: [PATCH 127/506] Remove unactive delegate only for stake list (#860) * Remove unactive delegate only for stake list * Remove flag onlyActive from normalize method --- api/stake.go | 2 +- services/assets/model.go | 10 +++ services/assets/model_test.go | 37 ++++++++- services/assets/stake.go | 37 +++++---- services/assets/stake_test.go | 139 ++++++++++++++++++++++++---------- 5 files changed, 166 insertions(+), 59 deletions(-) diff --git a/api/stake.go b/api/stake.go index 610536275..f691669aa 100644 --- a/api/stake.go +++ b/api/stake.go @@ -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() diff --git a/services/assets/model.go b/services/assets/model.go index f9b7ff415..1eed6eed4 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/model_test.go b/services/assets/model_test.go index 9b025734d..0145819ff 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.go b/services/assets/stake.go index 0b1e1022c..6c5999d49 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 } diff --git a/services/assets/stake_test.go b/services/assets/stake_test.go index 1ac838f1d..40ca40aaa 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) + }) + } +} From 03cb7ab08475d62ad4aca1a9838594f7dc02f4d8 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 14 Feb 2020 18:44:38 -0300 Subject: [PATCH 128/506] Split platform files per API implementation (#847) * Split platform files per API implementation * Split block and tx methods --- pkg/address/address.go | 20 ++ pkg/address/address_test.go | 12 + platform/aeternity/base.go | 20 ++ platform/aeternity/{api.go => transaction.go} | 15 - .../{api_test.go => transaction_test.go} | 0 platform/aion/base.go | 20 ++ platform/aion/{api.go => transaction.go} | 14 - .../aion/{api_test.go => transaction_test.go} | 0 platform/algorand/base.go | 21 ++ platform/algorand/block.go | 21 ++ platform/algorand/{api.go => transaction.go} | 31 --- .../{api_test.go => transaction_test.go} | 0 platform/binance/base.go | 25 ++ platform/binance/block.go | 39 +++ platform/binance/token.go | 63 +++++ platform/binance/token_test.go | 154 +++++++++++ platform/binance/{api.go => transaction.go} | 125 +-------- .../{api_test.go => transaction_test.go} | 145 ---------- platform/bitcoin/base.go | 35 +++ platform/bitcoin/block.go | 61 +++++ platform/bitcoin/{api.go => transaction.go} | 183 ++++--------- .../{api_test.go => transaction_test.go} | 5 +- platform/cosmos/base.go | 26 ++ platform/cosmos/block.go | 22 ++ platform/cosmos/{api.go => transaction.go} | 38 --- .../{api_test.go => transaction_test.go} | 0 platform/ethereum/base.go | 35 +++ platform/ethereum/block.go | 26 ++ platform/ethereum/collection.go | 29 ++ platform/ethereum/collection_client.go | 25 -- platform/ethereum/collection_client_test.go | 49 ---- platform/ethereum/collection_test.go | 43 +++ platform/ethereum/{ens.go => domain.go} | 8 +- platform/ethereum/token.go | 40 +++ platform/ethereum/token_test.go | 73 +++++ platform/ethereum/{api.go => transaction.go} | 90 ------ .../{api_test.go => transaction_test.go} | 64 ----- platform/fio/base.go | 20 ++ platform/fio/{api.go => domain.go} | 18 -- platform/fio/transaction.go | 9 + platform/harmony/base.go | 21 ++ platform/harmony/block.go | 30 ++ platform/harmony/{api.go => transaction.go} | 40 --- .../{api_test.go => transaction_test.go} | 0 platform/icon/base.go | 20 ++ platform/icon/{api.go => transaction.go} | 14 - .../icon/{api_test.go => transaction_test.go} | 0 platform/iotex/base.go | 20 ++ platform/iotex/block.go | 29 ++ platform/iotex/{api.go => transaction.go} | 38 --- .../{api_test.go => transaction_test.go} | 0 platform/nano/base.go | 22 ++ platform/nano/{api.go => transaction.go} | 17 -- .../nano/{api_test.go => transaction_test.go} | 0 platform/nebulas/base.go | 20 ++ platform/nebulas/{api.go => transaction.go} | 14 - .../{api_test.go => transaction_test.go} | 0 platform/nimiq/base.go | 20 ++ platform/nimiq/block.go | 27 ++ platform/nimiq/{api.go => transaction.go} | 36 --- .../{api_test.go => transaction_test.go} | 0 platform/ontology/base.go | 20 ++ platform/ontology/block.go | 33 +++ platform/ontology/{api.go => transaction.go} | 41 --- .../{api_test.go => transaction_test.go} | 0 platform/polkadot/base.go | 26 ++ platform/polkadot/block.go | 21 ++ platform/polkadot/{api.go => transaction.go} | 36 --- .../{api_test.go => transaction_test.go} | 0 platform/ripple/base.go | 20 ++ platform/ripple/block.go | 21 ++ platform/ripple/{api.go => transaction.go} | 30 -- .../{api_test.go => transaction_test.go} | 0 platform/stellar/base.go | 24 ++ platform/stellar/block.go | 25 ++ platform/stellar/{api.go => transaction.go} | 39 --- .../{api_test.go => transaction_test.go} | 0 platform/tezos/base.go | 23 ++ platform/tezos/block.go | 40 +++ platform/tezos/stake.go | 2 + platform/tezos/{api.go => transaction.go} | 52 ---- .../{api_test.go => transaction_test.go} | 0 platform/theta/base.go | 20 ++ platform/theta/{api.go => transaction.go} | 14 - .../{api_test.go => transaction_test.go} | 0 platform/tron/api.go | 257 ------------------ platform/tron/base.go | 20 ++ platform/tron/block.go | 66 +++++ platform/tron/stake.go | 5 +- platform/tron/token.go | 70 +++++ platform/tron/token_test.go | 22 ++ platform/tron/transaction.go | 119 ++++++++ .../tron/{api_test.go => transaction_test.go} | 15 - platform/tron/util.go | 24 -- platform/tron/util_test.go | 15 - platform/vechain/base.go | 20 ++ platform/vechain/block.go | 26 ++ platform/vechain/{api.go => transaction.go} | 36 --- .../{api_test.go => transaction_test.go} | 0 platform/waves/base.go | 20 ++ platform/waves/block.go | 26 ++ platform/waves/{api.go => transaction.go} | 35 --- .../{api_test.go => transaction_test.go} | 0 platform/zilliqa/api.go | 102 ------- platform/zilliqa/base.go | 27 ++ platform/zilliqa/block.go | 39 +++ platform/zilliqa/{zns.go => domain.go} | 0 platform/zilliqa/transaction.go | 47 ++++ .../{api_test.go => transaction_test.go} | 0 109 files changed, 1867 insertions(+), 1603 deletions(-) create mode 100644 platform/aeternity/base.go rename platform/aeternity/{api.go => transaction.go} (84%) rename platform/aeternity/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/aion/base.go rename platform/aion/{api.go => transaction.go} (84%) rename platform/aion/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/algorand/base.go create mode 100644 platform/algorand/block.go rename platform/algorand/{api.go => transaction.go} (66%) rename platform/algorand/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/binance/base.go create mode 100644 platform/binance/block.go create mode 100644 platform/binance/token.go create mode 100644 platform/binance/token_test.go rename platform/binance/{api.go => transaction.go} (64%) rename platform/binance/{api_test.go => transaction_test.go} (85%) create mode 100644 platform/bitcoin/base.go create mode 100644 platform/bitcoin/block.go rename platform/bitcoin/{api.go => transaction.go} (73%) rename platform/bitcoin/{api_test.go => transaction_test.go} (99%) create mode 100644 platform/cosmos/base.go create mode 100644 platform/cosmos/block.go rename platform/cosmos/{api.go => transaction.go} (84%) rename platform/cosmos/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/ethereum/base.go create mode 100644 platform/ethereum/block.go delete mode 100644 platform/ethereum/collection_client_test.go rename platform/ethereum/{ens.go => domain.go} (85%) create mode 100644 platform/ethereum/token.go create mode 100644 platform/ethereum/token_test.go rename platform/ethereum/{api.go => transaction.go} (56%) rename platform/ethereum/{api_test.go => transaction_test.go} (83%) create mode 100644 platform/fio/base.go rename platform/fio/{api.go => domain.go} (58%) create mode 100644 platform/fio/transaction.go create mode 100644 platform/harmony/base.go create mode 100644 platform/harmony/block.go rename platform/harmony/{api.go => transaction.go} (71%) rename platform/harmony/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/icon/base.go rename platform/icon/{api.go => transaction.go} (85%) rename platform/icon/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/iotex/base.go create mode 100644 platform/iotex/block.go rename platform/iotex/{api.go => transaction.go} (70%) rename platform/iotex/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/nano/base.go rename platform/nano/{api.go => transaction.go} (80%) rename platform/nano/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/nebulas/base.go rename platform/nebulas/{api.go => transaction.go} (85%) rename platform/nebulas/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/nimiq/base.go create mode 100644 platform/nimiq/block.go rename platform/nimiq/{api.go => transaction.go} (55%) rename platform/nimiq/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/ontology/base.go create mode 100644 platform/ontology/block.go rename platform/ontology/{api.go => transaction.go} (81%) rename platform/ontology/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/polkadot/base.go create mode 100644 platform/polkadot/block.go rename platform/polkadot/{api.go => transaction.go} (79%) rename platform/polkadot/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/ripple/base.go create mode 100644 platform/ripple/block.go rename platform/ripple/{api.go => transaction.go} (74%) rename platform/ripple/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/stellar/base.go create mode 100644 platform/stellar/block.go rename platform/stellar/{api.go => transaction.go} (71%) rename platform/stellar/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/tezos/base.go create mode 100644 platform/tezos/block.go rename platform/tezos/{api.go => transaction.go} (64%) rename platform/tezos/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/theta/base.go rename platform/theta/{api.go => transaction.go} (89%) rename platform/theta/{api_test.go => transaction_test.go} (100%) delete mode 100644 platform/tron/api.go create mode 100644 platform/tron/base.go create mode 100644 platform/tron/block.go create mode 100644 platform/tron/token.go create mode 100644 platform/tron/token_test.go create mode 100644 platform/tron/transaction.go rename platform/tron/{api_test.go => transaction_test.go} (90%) delete mode 100644 platform/tron/util.go delete mode 100644 platform/tron/util_test.go create mode 100644 platform/vechain/base.go create mode 100644 platform/vechain/block.go rename platform/vechain/{api.go => transaction.go} (86%) rename platform/vechain/{api_test.go => transaction_test.go} (100%) create mode 100644 platform/waves/base.go create mode 100644 platform/waves/block.go rename platform/waves/{api.go => transaction.go} (64%) rename platform/waves/{api_test.go => transaction_test.go} (100%) delete mode 100644 platform/zilliqa/api.go create mode 100644 platform/zilliqa/base.go create mode 100644 platform/zilliqa/block.go rename platform/zilliqa/{zns.go => domain.go} (100%) create mode 100644 platform/zilliqa/transaction.go rename platform/zilliqa/{api_test.go => transaction_test.go} (100%) diff --git a/pkg/address/address.go b/pkg/address/address.go index 05c3260bc..a720f8c38 100644 --- a/pkg/address/address.go +++ b/pkg/address/address.go @@ -1,6 +1,10 @@ package address import ( + "crypto/sha256" + "encoding/hex" + "github.com/mr-tron/base58" + "github.com/trustwallet/blockatlas/pkg/errors" "golang.org/x/crypto/sha3" "strings" ) @@ -37,3 +41,19 @@ func EIP55Checksum(unchecksummed string) string { val := string(result) return "0x" + val } + +// HexToAddress converts a hex representation of a Tron address +// into a Base58 string with a 4 byte checksum. +func HexToAddress(hexAddr string) (b58 string, err error) { + bytes, err := hex.DecodeString(hexAddr) + if err != nil { + return "", errors.E(err, errors.TypePlatformUnmarshal, + errors.Params{"hexAddr": hexAddr}).PushToSentry() + } + var checksum [32]byte + checksum = sha256.Sum256(bytes) + checksum = sha256.Sum256(checksum[:]) + bytes = append(bytes, checksum[:4]...) + b58 = base58.EncodeAlphabet(bytes, base58.BTCAlphabet) + return +} diff --git a/pkg/address/address_test.go b/pkg/address/address_test.go index cdbbd41e9..1cae85506 100644 --- a/pkg/address/address_test.go +++ b/pkg/address/address_test.go @@ -47,3 +47,15 @@ func TestRemove0x(t *testing.T) { }) } } + +func TestHexToAddress(t *testing.T) { + in := "4182dd6b9966724ae2fdc79b416c7588da67ff1b35" + expected := "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9" + got, err := HexToAddress(in) + if err != nil { + t.Fatal(err) + } + if expected != got { + t.Fatalf("expected %s, got %s", expected, got) + } +} diff --git a/platform/aeternity/base.go b/platform/aeternity/base.go new file mode 100644 index 000000000..1f345c83c --- /dev/null +++ b/platform/aeternity/base.go @@ -0,0 +1,20 @@ +package aeternity + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("aeternity.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.AE] +} diff --git a/platform/aeternity/api.go b/platform/aeternity/transaction.go similarity index 84% rename from platform/aeternity/api.go rename to platform/aeternity/transaction.go index 9b5d5e456..48adf1f72 100644 --- a/platform/aeternity/api.go +++ b/platform/aeternity/transaction.go @@ -5,23 +5,8 @@ import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "strings" - - "github.com/spf13/viper" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("aeternity.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.AE] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { addressTxs, err := p.client.GetTxs(address, blockatlas.TxPerPage) if err != nil { diff --git a/platform/aeternity/api_test.go b/platform/aeternity/transaction_test.go similarity index 100% rename from platform/aeternity/api_test.go rename to platform/aeternity/transaction_test.go diff --git a/platform/aion/base.go b/platform/aion/base.go new file mode 100644 index 000000000..15379aa6e --- /dev/null +++ b/platform/aion/base.go @@ -0,0 +1,20 @@ +package aion + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("aion.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.AION] +} diff --git a/platform/aion/api.go b/platform/aion/transaction.go similarity index 84% rename from platform/aion/api.go rename to platform/aion/transaction.go index 8287980d3..d1bc7c31f 100644 --- a/platform/aion/api.go +++ b/platform/aion/transaction.go @@ -1,26 +1,12 @@ package aion import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" "strconv" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("aion.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.AION] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { if srcTxs, err := p.client.GetTxsOfAddress(address, blockatlas.TxPerPage); err == nil { return NormalizeTxs(srcTxs.Content), err diff --git a/platform/aion/api_test.go b/platform/aion/transaction_test.go similarity index 100% rename from platform/aion/api_test.go rename to platform/aion/transaction_test.go diff --git a/platform/algorand/base.go b/platform/algorand/base.go new file mode 100644 index 000000000..1e121c6ce --- /dev/null +++ b/platform/algorand/base.go @@ -0,0 +1,21 @@ +package algorand + +import ( + "github.com/spf13/viper" + + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("algorand.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.ALGO] +} diff --git a/platform/algorand/block.go b/platform/algorand/block.go new file mode 100644 index 000000000..b9260aaa6 --- /dev/null +++ b/platform/algorand/block.go @@ -0,0 +1,21 @@ +package algorand + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.GetLatestBlock() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + txs, err := p.client.GetTxsInBlock(num) + if err != nil { + return nil, err + } + + return &blockatlas.Block{ + Number: num, + Txs: NormalizeTxs(txs), + }, nil +} diff --git a/platform/algorand/api.go b/platform/algorand/transaction.go similarity index 66% rename from platform/algorand/api.go rename to platform/algorand/transaction.go index fab56b1ce..9a25e24bb 100644 --- a/platform/algorand/api.go +++ b/platform/algorand/transaction.go @@ -1,43 +1,12 @@ package algorand import ( - "github.com/spf13/viper" - "strconv" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("algorand.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.ALGO] -} - -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.GetLatestBlock() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - txs, err := p.client.GetTxsInBlock(num) - if err != nil { - return nil, err - } - - return &blockatlas.Block{ - Number: num, - Txs: NormalizeTxs(txs), - }, nil -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { txs, err := p.client.GetTxsOfAddress(address) if err != nil { diff --git a/platform/algorand/api_test.go b/platform/algorand/transaction_test.go similarity index 100% rename from platform/algorand/api_test.go rename to platform/algorand/transaction_test.go diff --git a/platform/binance/base.go b/platform/binance/base.go new file mode 100644 index 000000000..ae15a6ea9 --- /dev/null +++ b/platform/binance/base.go @@ -0,0 +1,25 @@ +package binance + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client + dexClient DexClient +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("binance.api"))} + p.client.ErrorHandler = getHTTPError + + p.dexClient = DexClient{blockatlas.InitClient(viper.GetString("binance.dex"))} + p.dexClient.ErrorHandler = getHTTPError + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.BNB] +} diff --git a/platform/binance/block.go b/platform/binance/block.go new file mode 100644 index 000000000..9115c6cdf --- /dev/null +++ b/platform/binance/block.go @@ -0,0 +1,39 @@ +package binance + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + // No native function to get height in explorer API + // Workaround: Request list of blocks + // and return number of the newest one + list, err := p.client.GetBlockList(1) + if err != nil { + return 0, err + } + if len(list.BlockArray) == 0 { + return 0, errors.E("no block descriptor found", errors.TypePlatformApi).PushToSentry() + } + return list.BlockArray[0].BlockHeight, nil +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + srcTxs, err := p.client.GetBlockByNumber(num) + if err != nil { + return nil, err + } + + txs := make(blockatlas.TxPage, 0) + childTxs, err := p.getTxChildChan(srcTxs.Txs) + if err == nil { + txs = NormalizeTxs(childTxs, "", "") + } else { + txs = NormalizeTxs(srcTxs.Txs, "", "") + } + return &blockatlas.Block{ + Number: num, + Txs: txs, + }, nil +} diff --git a/platform/binance/token.go b/platform/binance/token.go new file mode 100644 index 000000000..0e633340c --- /dev/null +++ b/platform/binance/token.go @@ -0,0 +1,63 @@ +package binance + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "strings" +) + +func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { + account, err := p.dexClient.GetAccountMetadata(address) + if err != nil || len(account.Balances) == 0 { + return []blockatlas.Token{}, nil + } + tokens, err := p.dexClient.GetTokens() + if err != nil { + return nil, err + } + return NormalizeTokens(account.Balances, tokens), nil +} + +// NormalizeToken converts a Binance token into the generic model +func NormalizeToken(srcToken *Balance, tokens *TokenPage) (t blockatlas.Token, ok bool) { + if srcToken.isAllZeroBalance() { + return t, false + } + + tk := tokens.findToken(srcToken.Symbol) + if tk == nil { + return t, false + } + + t = blockatlas.Token{ + Name: tk.Name, + Symbol: tk.OriginalSymbol, + TokenID: tk.Symbol, + Coin: coin.BNB, + Decimals: uint(decimalPlaces(tk.TotalSupply)), + Type: blockatlas.TokenTypeBEP2, + } + + return t, true +} + +// NormalizeTxs converts multiple Binance tokens +func NormalizeTokens(srcBalance []Balance, tokens *TokenPage) (tokenPage []blockatlas.Token) { + for _, srcToken := range srcBalance { + token, ok := NormalizeToken(&srcToken, tokens) + if !ok { + continue + } + tokenPage = append(tokenPage, token) + } + return +} + +// decimalPlaces count the decimals places. +func decimalPlaces(v string) int { + s := strings.Split(v, ".") + if len(s) < 2 { + return 0 + } + return len(s[1]) +} diff --git a/platform/binance/token_test.go b/platform/binance/token_test.go new file mode 100644 index 000000000..99106ac9d --- /dev/null +++ b/platform/binance/token_test.go @@ -0,0 +1,154 @@ +package binance + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" +) + +const ( + myToken = ` +{ + "free": "17199.38841739", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ARN-71B" +} +` + myTokenAllZero = ` +{ + "free": "0.00000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ARN-71B" +} +` + myTokenFreeZero = ` +{ + "free": "0.00000000", + "frozen": "1.00000000", + "locked": "0.00000000", + "symbol": "ARN-71B" +} +` + myTokenFrozenAndFreeZero = ` +{ + "free": "0.00000000", + "frozen": "0.00000000", + "locked": "0.00000001", + "symbol": "ARN-71B" +} +` + tokenList = ` +[ + { + "mintable": false, + "name": "Aeron", + "original_symbol": "ARN", + "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", + "symbol": "ARN-71B", + "total_supply": "20000000.00000000" + }, + { + "mintable": false, + "name": "BOLT Token", + "original_symbol": "BOLT", + "owner": "bnb177ujwmshxu8r9za4vy9ztqn65tmr54ddw958rt", + "symbol": "BOLT-4C6", + "total_supply": "995000000.00000000" + } +] +` +) + +var ( + tokenDst = blockatlas.Token{ + Name: "Aeron", + Symbol: "ARN", + Decimals: 8, + TokenID: "ARN-71B", + Coin: coin.BNB, + Type: blockatlas.TokenTypeBEP2, + } + emptyTokenDst = blockatlas.Token{} +) + +type testToken struct { + name string + apiResponse string + expected blockatlas.Token + tokens string + ok bool +} + +func TestNormalizeToken(t *testing.T) { + testingTokens := []testToken{ + { + name: "Test with not zero balance", + apiResponse: myToken, + tokens: tokenList, + expected: tokenDst, + ok: true, + }, + { + name: "Test with all zero balance", + apiResponse: myTokenAllZero, + tokens: tokenList, + expected: emptyTokenDst, + ok: false, + }, + { + name: "Test with only free zero balance", + apiResponse: myTokenFreeZero, + tokens: tokenList, + expected: tokenDst, + ok: true, + }, + { + name: "Test with free and frozen zero balances", + apiResponse: myTokenFrozenAndFreeZero, + tokens: tokenList, + expected: tokenDst, + ok: true, + }, + } + for _, testToken := range testingTokens { + t.Run(testToken.name, func(t *testing.T) { + var srcToken Balance + err := json.Unmarshal([]byte(testToken.apiResponse), &srcToken) + assert.Nil(t, err) + + var srcTokens TokenPage + err = json.Unmarshal([]byte(testToken.tokens), &srcTokens) + assert.Nil(t, err) + + tk, ok := NormalizeToken(&srcToken, &srcTokens) + assert.Equal(t, testToken.ok, ok, "token: token could not be normalized") + assert.Equal(t, testToken.expected, tk, "token: token don't equal") + }) + } +} + +func TestDecimalPlaces(t *testing.T) { + tests := []struct { + name string + value string + want int + }{ + {"Test text value with dot", "decimal.places", 6}, + {"Test float value", "1234.543212222", 9}, + {"Test float value", "5.33333333", 8}, + {"Test text value", "decimal", 0}, + {"Test integer value", "4", 0}, + {"Test empty value", "", 0}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := decimalPlaces(tt.value); got != tt.want { + t.Errorf("decimalPlaces() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/platform/binance/api.go b/platform/binance/transaction.go similarity index 64% rename from platform/binance/api.go rename to platform/binance/transaction.go index ab53f5b37..289fe6fc6 100644 --- a/platform/binance/api.go +++ b/platform/binance/transaction.go @@ -2,70 +2,29 @@ package binance import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "strings" "sync" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" ) -type Platform struct { - client Client - dexClient DexClient -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("binance.api"))} - p.client.ErrorHandler = getHTTPError - - p.dexClient = DexClient{blockatlas.InitClient(viper.GetString("binance.dex"))} - p.dexClient.ErrorHandler = getHTTPError - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.BNB] +func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + // Endpoint supports queries without token query parameter + return p.GetTokenTxsByAddress(address, p.Coin().Symbol) } -func (p *Platform) CurrentBlockNumber() (int64, error) { - // No native function to get height in explorer API - // Workaround: Request list of blocks - // and return number of the newest one - list, err := p.client.GetBlockList(1) +func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { + srcTxs, err := p.client.GetTxsOfAddress(address, token) if err != nil { - return 0, err - } - if len(list.BlockArray) == 0 { - return 0, errors.E("no block descriptor found", errors.TypePlatformApi).PushToSentry() + return nil, err } - return list.BlockArray[0].BlockHeight, nil -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - srcTxs, err := p.client.GetBlockByNumber(num) + txs, err := p.getTxChildChan(srcTxs.Txs) if err != nil { return nil, err } - - txs := make(blockatlas.TxPage, 0) - childTxs, err := p.getTxChildChan(srcTxs.Txs) - if err == nil { - txs = NormalizeTxs(childTxs, "", "") - } else { - txs = NormalizeTxs(srcTxs.Txs, "", "") - } - return &blockatlas.Block{ - Number: num, - Txs: txs, - }, nil -} - -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - // Endpoint supports queries without token query parameter - return p.GetTokenTxsByAddress(address, p.Coin().Symbol) + return NormalizeTxs(txs, token, address), nil } // getTxChildChan get all child assets from a tx @@ -100,18 +59,6 @@ func (p *Platform) getTxChildChan(srcTxs []Tx) ([]Tx, error) { return txs, nil } -func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { - srcTxs, err := p.client.GetTxsOfAddress(address, token) - if err != nil { - return nil, err - } - txs, err := p.getTxChildChan(srcTxs.Txs) - if err != nil { - return nil, err - } - return NormalizeTxs(txs, token, address), nil -} - func normalizeTransfer(tx blockatlas.Tx, srcTx Tx, token, address string) (blockatlas.TxPage, bool) { // Verify if the tx has more them one asset if srcTx.HasChildren == 1 { @@ -241,59 +188,3 @@ func NormalizeTxs(srcTxs []Tx, token, adress string) (txs []blockatlas.Tx) { } return } - -func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { - account, err := p.dexClient.GetAccountMetadata(address) - if err != nil || len(account.Balances) == 0 { - return []blockatlas.Token{}, nil - } - tokens, err := p.dexClient.GetTokens() - if err != nil { - return nil, err - } - return NormalizeTokens(account.Balances, tokens), nil -} - -// NormalizeToken converts a Binance token into the generic model -func NormalizeToken(srcToken *Balance, tokens *TokenPage) (t blockatlas.Token, ok bool) { - if srcToken.isAllZeroBalance() { - return t, false - } - - tk := tokens.findToken(srcToken.Symbol) - if tk == nil { - return t, false - } - - t = blockatlas.Token{ - Name: tk.Name, - Symbol: tk.OriginalSymbol, - TokenID: tk.Symbol, - Coin: coin.BNB, - Decimals: uint(decimalPlaces(tk.TotalSupply)), - Type: blockatlas.TokenTypeBEP2, - } - - return t, true -} - -// NormalizeTxs converts multiple Binance tokens -func NormalizeTokens(srcBalance []Balance, tokens *TokenPage) (tokenPage []blockatlas.Token) { - for _, srcToken := range srcBalance { - token, ok := NormalizeToken(&srcToken, tokens) - if !ok { - continue - } - tokenPage = append(tokenPage, token) - } - return -} - -// decimalPlaces count the decimals places. -func decimalPlaces(v string) int { - s := strings.Split(v, ".") - if len(s) < 2 { - return 0 - } - return len(s[1]) -} diff --git a/platform/binance/api_test.go b/platform/binance/transaction_test.go similarity index 85% rename from platform/binance/api_test.go rename to platform/binance/transaction_test.go index f5d64d277..e770f59b7 100644 --- a/platform/binance/api_test.go +++ b/platform/binance/transaction_test.go @@ -538,151 +538,6 @@ func TestNormalizeTxs(t *testing.T) { } } -const ( - myToken = ` -{ - "free": "17199.38841739", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ARN-71B" -} -` - myTokenAllZero = ` -{ - "free": "0.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ARN-71B" -} -` - myTokenFreeZero = ` -{ - "free": "0.00000000", - "frozen": "1.00000000", - "locked": "0.00000000", - "symbol": "ARN-71B" -} -` - myTokenFrozenAndFreeZero = ` -{ - "free": "0.00000000", - "frozen": "0.00000000", - "locked": "0.00000001", - "symbol": "ARN-71B" -} -` - tokenList = ` -[ - { - "mintable": false, - "name": "Aeron", - "original_symbol": "ARN", - "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", - "symbol": "ARN-71B", - "total_supply": "20000000.00000000" - }, - { - "mintable": false, - "name": "BOLT Token", - "original_symbol": "BOLT", - "owner": "bnb177ujwmshxu8r9za4vy9ztqn65tmr54ddw958rt", - "symbol": "BOLT-4C6", - "total_supply": "995000000.00000000" - } -] -` -) - -var ( - tokenDst = blockatlas.Token{ - Name: "Aeron", - Symbol: "ARN", - Decimals: 8, - TokenID: "ARN-71B", - Coin: coin.BNB, - Type: blockatlas.TokenTypeBEP2, - } - emptyTokenDst = blockatlas.Token{} -) - -type testToken struct { - name string - apiResponse string - expected blockatlas.Token - tokens string - ok bool -} - -func TestNormalizeToken(t *testing.T) { - testingTokens := []testToken{ - { - name: "Test with not zero balance", - apiResponse: myToken, - tokens: tokenList, - expected: tokenDst, - ok: true, - }, - { - name: "Test with all zero balance", - apiResponse: myTokenAllZero, - tokens: tokenList, - expected: emptyTokenDst, - ok: false, - }, - { - name: "Test with only free zero balance", - apiResponse: myTokenFreeZero, - tokens: tokenList, - expected: tokenDst, - ok: true, - }, - { - name: "Test with free and frozen zero balances", - apiResponse: myTokenFrozenAndFreeZero, - tokens: tokenList, - expected: tokenDst, - ok: true, - }, - } - for _, testToken := range testingTokens { - t.Run(testToken.name, func(t *testing.T) { - var srcToken Balance - err := json.Unmarshal([]byte(testToken.apiResponse), &srcToken) - assert.Nil(t, err) - - var srcTokens TokenPage - err = json.Unmarshal([]byte(testToken.tokens), &srcTokens) - assert.Nil(t, err) - - tk, ok := NormalizeToken(&srcToken, &srcTokens) - assert.Equal(t, testToken.ok, ok, "token: token could not be normalized") - assert.Equal(t, testToken.expected, tk, "token: token don't equal") - }) - } -} - -func TestDecimalPlaces(t *testing.T) { - tests := []struct { - name string - value string - want int - }{ - {"Test text value with dot", "decimal.places", 6}, - {"Test float value", "1234.543212222", 9}, - {"Test float value", "5.33333333", 8}, - {"Test text value", "decimal", 0}, - {"Test integer value", "4", 0}, - {"Test empty value", "", 0}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := decimalPlaces(tt.value); got != tt.want { - t.Errorf("decimalPlaces() = %v, want %v", got, tt.want) - } - }) - } -} - func TestTokenSymbol(t *testing.T) { assert.Equal(t, "UGAS", TokenSymbol("UGAS")) assert.Equal(t, "UGAS", TokenSymbol("UGAS-B0C")) diff --git a/platform/bitcoin/base.go b/platform/bitcoin/base.go new file mode 100644 index 000000000..a8c685b64 --- /dev/null +++ b/platform/bitcoin/base.go @@ -0,0 +1,35 @@ +package bitcoin + +import ( + "fmt" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client + CoinIndex uint +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString(p.ConfigKey()))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[p.CoinIndex] +} + +func (p *Platform) ConfigKey() string { + return fmt.Sprintf("%s.api", p.Coin().Handle) +} + +func (p *Platform) GetAddressesFromXpub(xpub string) ([]string, error) { + tokens, err := p.client.GetAddressesFromXpub(xpub) + addresses := make([]string, 0) + for _, token := range tokens { + addresses = append(addresses, token.Name) + } + return addresses, err +} diff --git a/platform/bitcoin/block.go b/platform/bitcoin/block.go new file mode 100644 index 000000000..fb3bf2283 --- /dev/null +++ b/platform/bitcoin/block.go @@ -0,0 +1,61 @@ +package bitcoin + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "sync" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + status, err := p.client.GetBlockNumber() + return status.Backend.Blocks, err +} + +func (p *Platform) GetAllBlockPages(total, num int64) []Transaction { + txs := make([]Transaction, 0) + if total <= 1 { + return txs + } + + start := int64(1) + var wg sync.WaitGroup + out := make(chan TransactionsList, int(total-start)) + wg.Add(int(total - start)) + for start < total { + start++ + go func(page, num int64, out chan TransactionsList, wg *sync.WaitGroup) { + defer wg.Done() + block, err := p.client.GetTransactionsByBlock(num, page) + if err != nil { + logger.Error("GetTransactionsByBlockChan", err, logger.Params{"number": num, "page": page}) + return + } + out <- block + }(start, num, out, &wg) + } + wg.Wait() + close(out) + for r := range out { + txs = append(txs, r.TransactionList()...) + } + return txs +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + page := int64(1) + block, err := p.client.GetTransactionsByBlock(num, page) + if err != nil { + return nil, err + } + txPages := p.GetAllBlockPages(block.TotalPages, num) + txs := append(txPages, block.TransactionList()...) + var normalized []blockatlas.Tx + for _, tx := range txs { + normalized = append(normalized, normalizeTransaction(tx, p.CoinIndex)) + } + return &blockatlas.Block{ + Number: num, + ID: block.Hash, + Txs: normalized, + }, nil +} diff --git a/platform/bitcoin/api.go b/platform/bitcoin/transaction.go similarity index 73% rename from platform/bitcoin/api.go rename to platform/bitcoin/transaction.go index 7b89ee64f..ee3f509e5 100644 --- a/platform/bitcoin/api.go +++ b/platform/bitcoin/transaction.go @@ -1,36 +1,14 @@ package bitcoin import ( - "fmt" mapset "github.com/deckarep/golang-set" "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "net/http" - "sync" ) -type Platform struct { - client Client - CoinIndex uint -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString(p.ConfigKey()))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[p.CoinIndex] -} - -func (p *Platform) ConfigKey() string { - return fmt.Sprintf("%s.api", p.Coin().Handle) -} - // @Summary Get xpub transactions // @ID xpub // @Description Get transactions from xpub address @@ -101,77 +79,69 @@ func (p *Platform) getTxsByAddress(address string) ([]blockatlas.Tx, error) { return txs, nil } -func (p *Platform) GetAddressesFromXpub(xpub string) ([]string, error) { - tokens, err := p.client.GetAddressesFromXpub(xpub) - addresses := make([]string, 0) - for _, token := range tokens { - addresses = append(addresses, token.Name) +func normalizeTxs(sourceTxs TransactionsList, coinIndex uint, addressSet mapset.Set) []blockatlas.Tx { + var txs []blockatlas.Tx + for _, transaction := range sourceTxs.TransactionList() { + if tx, ok := normalizeTransfer(transaction, coinIndex, addressSet); ok { + txs = append(txs, tx) + } } - return addresses, err + return txs } -func (p *Platform) CurrentBlockNumber() (int64, error) { - status, err := p.client.GetBlockNumber() - return status.Backend.Blocks, err -} +func normalizeTransfer(transaction Transaction, coinIndex uint, addressSet mapset.Set) (tx blockatlas.Tx, ok bool) { + tx = normalizeTransaction(transaction, coinIndex) + direction := InferDirection(&tx, addressSet) + value := InferValue(&tx, direction, addressSet) -func (p *Platform) GetAllBlockPages(total, num int64) []Transaction { - txs := make([]Transaction, 0) - if total <= 1 { - return txs + tx.Direction = direction + tx.Meta = blockatlas.Transfer{ + Value: value, + Symbol: coin.Coins[coinIndex].Symbol, + Decimals: coin.Coins[coinIndex].Decimals, } - start := int64(1) - var wg sync.WaitGroup - out := make(chan TransactionsList, int(total-start)) - wg.Add(int(total - start)) - for start < total { - start++ - go func(page, num int64, out chan TransactionsList, wg *sync.WaitGroup) { - defer wg.Done() - block, err := p.client.GetTransactionsByBlock(num, page) - if err != nil { - logger.Error("GetTransactionsByBlockChan", err, logger.Params{"number": num, "page": page}) - return - } - out <- block - }(start, num, out, &wg) - } - wg.Wait() - close(out) - for r := range out { - txs = append(txs, r.TransactionList()...) - } - return txs + return tx, true } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - page := int64(1) - block, err := p.client.GetTransactionsByBlock(num, page) - if err != nil { - return nil, err +func InferDirection(tx *blockatlas.Tx, addressSet mapset.Set) blockatlas.Direction { + inputSet := mapset.NewSet() + for _, address := range tx.Inputs { + inputSet.Add(address.Address) + } + outputSet := mapset.NewSet() + for _, address := range tx.Outputs { + outputSet.Add(address.Address) } - txPages := p.GetAllBlockPages(block.TotalPages, num) - txs := append(txPages, block.TransactionList()...) - var normalized []blockatlas.Tx - for _, tx := range txs { - normalized = append(normalized, normalizeTransaction(tx, p.CoinIndex)) + intersect := addressSet.Intersect(inputSet) + if intersect.Cardinality() == 0 { + return blockatlas.DirectionIncoming + } + if outputSet.IsProperSubset(addressSet) || outputSet.Equal(inputSet) { + return blockatlas.DirectionSelf } - return &blockatlas.Block{ - Number: num, - ID: block.Hash, - Txs: normalized, - }, nil + return blockatlas.DirectionOutgoing } -func normalizeTxs(sourceTxs TransactionsList, coinIndex uint, addressSet mapset.Set) []blockatlas.Tx { - var txs []blockatlas.Tx - for _, transaction := range sourceTxs.TransactionList() { - if tx, ok := normalizeTransfer(transaction, coinIndex, addressSet); ok { - txs = append(txs, tx) +func InferValue(tx *blockatlas.Tx, direction blockatlas.Direction, addressSet mapset.Set) blockatlas.Amount { + value := blockatlas.Amount("0") + if len(tx.Outputs) == 0 { + return value + } + if direction == blockatlas.DirectionOutgoing || direction == blockatlas.DirectionSelf { + value = tx.Outputs[0].Value + } else if direction == blockatlas.DirectionIncoming { + amount := value + for _, output := range tx.Outputs { + if !addressSet.Contains(output.Address) { + continue + } + value := numbers.AddAmount(string(amount), string(output.Value)) + amount = blockatlas.Amount(value) } + value = amount } - return txs + return value } func normalizeTransaction(tx Transaction, coinIndex uint) blockatlas.Tx { @@ -210,21 +180,6 @@ func normalizeTransaction(tx Transaction, coinIndex uint) blockatlas.Tx { } } -func normalizeTransfer(transaction Transaction, coinIndex uint, addressSet mapset.Set) (tx blockatlas.Tx, ok bool) { - tx = normalizeTransaction(transaction, coinIndex) - direction := InferDirection(&tx, addressSet) - value := InferValue(&tx, direction, addressSet) - - tx.Direction = direction - tx.Meta = blockatlas.Transfer{ - Value: value, - Symbol: coin.Coins[coinIndex].Symbol, - Decimals: coin.Coins[coinIndex].Decimals, - } - - return tx, true -} - func parseOutputs(outputs []Output) (addresses []blockatlas.TxOutput) { set := make(map[string]blockatlas.TxOutput) var ordered []string @@ -249,46 +204,6 @@ func parseOutputs(outputs []Output) (addresses []blockatlas.TxOutput) { return addresses } -func InferDirection(tx *blockatlas.Tx, addressSet mapset.Set) blockatlas.Direction { - inputSet := mapset.NewSet() - for _, address := range tx.Inputs { - inputSet.Add(address.Address) - } - outputSet := mapset.NewSet() - for _, address := range tx.Outputs { - outputSet.Add(address.Address) - } - intersect := addressSet.Intersect(inputSet) - if intersect.Cardinality() == 0 { - return blockatlas.DirectionIncoming - } - if outputSet.IsProperSubset(addressSet) || outputSet.Equal(inputSet) { - return blockatlas.DirectionSelf - } - return blockatlas.DirectionOutgoing -} - -func InferValue(tx *blockatlas.Tx, direction blockatlas.Direction, addressSet mapset.Set) blockatlas.Amount { - value := blockatlas.Amount("0") - if len(tx.Outputs) == 0 { - return value - } - if direction == blockatlas.DirectionOutgoing || direction == blockatlas.DirectionSelf { - value = tx.Outputs[0].Value - } else if direction == blockatlas.DirectionIncoming { - amount := value - for _, output := range tx.Outputs { - if !addressSet.Contains(output.Address) { - continue - } - value := numbers.AddAmount(string(amount), string(output.Value)) - amount = blockatlas.Amount(value) - } - value = amount - } - return value -} - func (transaction *Transaction) getStatus() blockatlas.Status { if transaction.Confirmations == 0 { return blockatlas.StatusPending diff --git a/platform/bitcoin/api_test.go b/platform/bitcoin/transaction_test.go similarity index 99% rename from platform/bitcoin/api_test.go rename to platform/bitcoin/transaction_test.go index a05badbe5..e7a18dd0c 100644 --- a/platform/bitcoin/api_test.go +++ b/platform/bitcoin/transaction_test.go @@ -3,12 +3,11 @@ package bitcoin import ( "bytes" "encoding/json" + mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" - - mapset "github.com/deckarep/golang-set" - "github.com/trustwallet/blockatlas/coin" ) const outgoingTx = `{ diff --git a/platform/cosmos/base.go b/platform/cosmos/base.go new file mode 100644 index 000000000..3fea3ceda --- /dev/null +++ b/platform/cosmos/base.go @@ -0,0 +1,26 @@ +package cosmos + +import ( + "fmt" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client + CoinIndex uint +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString(p.ConfigKey()))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[p.CoinIndex] +} + +func (p *Platform) ConfigKey() string { + return fmt.Sprintf("%s.api", p.Coin().Handle) +} diff --git a/platform/cosmos/block.go b/platform/cosmos/block.go new file mode 100644 index 000000000..509f372fd --- /dev/null +++ b/platform/cosmos/block.go @@ -0,0 +1,22 @@ +package cosmos + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + srcTxs, err := p.client.GetBlockByNumber(num) + if err != nil { + return nil, err + } + + txs := p.NormalizeTxs(srcTxs.Txs) + return &blockatlas.Block{ + Number: num, + Txs: txs, + }, nil +} + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.CurrentBlockNumber() +} diff --git a/platform/cosmos/api.go b/platform/cosmos/transaction.go similarity index 84% rename from platform/cosmos/api.go rename to platform/cosmos/transaction.go index d957524ac..04f752101 100644 --- a/platform/cosmos/api.go +++ b/platform/cosmos/transaction.go @@ -1,9 +1,6 @@ package cosmos import ( - "fmt" - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" @@ -12,41 +9,6 @@ import ( "time" ) -type Platform struct { - client Client - CoinIndex uint -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString(p.ConfigKey()))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[p.CoinIndex] -} - -func (p *Platform) ConfigKey() string { - return fmt.Sprintf("%s.api", p.Coin().Handle) -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - srcTxs, err := p.client.GetBlockByNumber(num) - if err != nil { - return nil, err - } - - txs := p.NormalizeTxs(srcTxs.Txs) - return &blockatlas.Block{ - Number: num, - Txs: txs, - }, nil -} - -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.CurrentBlockNumber() -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { tagsList := []string{"transfer.recipient", "message.sender"} var wg sync.WaitGroup diff --git a/platform/cosmos/api_test.go b/platform/cosmos/transaction_test.go similarity index 100% rename from platform/cosmos/api_test.go rename to platform/cosmos/transaction_test.go diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go new file mode 100644 index 000000000..2d5aadd30 --- /dev/null +++ b/platform/ethereum/base.go @@ -0,0 +1,35 @@ +package ethereum + +import ( + "fmt" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client + collectionsClient CollectionsClient + CoinIndex uint + RpcURL string +} + +func (p *Platform) Init() error { + handle := coin.Coins[p.CoinIndex].Handle + + coinVar := fmt.Sprintf("%s.api", handle) + p.client = Client{blockatlas.InitClient(viper.GetString(coinVar))} + + collectionsApiVar := fmt.Sprintf("%s.collections_api", handle) + p.collectionsClient = CollectionsClient{blockatlas.InitClient(viper.GetString(collectionsApiVar))} + + collectionsApiKeyVar := fmt.Sprintf("%s.collections_api_key", handle) + p.collectionsClient.Headers["X-API-KEY"] = viper.GetString(collectionsApiKeyVar) + + p.RpcURL = viper.GetString("ethereum.rpc") + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[p.CoinIndex] +} diff --git a/platform/ethereum/block.go b/platform/ethereum/block.go new file mode 100644 index 000000000..6d6620b63 --- /dev/null +++ b/platform/ethereum/block.go @@ -0,0 +1,26 @@ +package ethereum + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "strconv" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.CurrentBlockNumber() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + if srcPage, err := p.client.GetBlockByNumber(num); err == nil { + var txs []blockatlas.Tx + for _, srcTx := range srcPage { + txs = AppendTxs(txs, &srcTx, p.CoinIndex) + } + return &blockatlas.Block{ + Number: num, + ID: strconv.FormatInt(num, 10), + Txs: txs, + }, nil + } else { + return nil, err + } +} diff --git a/platform/ethereum/collection.go b/platform/ethereum/collection.go index 0fedd89ba..ffd8cf57c 100644 --- a/platform/ethereum/collection.go +++ b/platform/ethereum/collection.go @@ -6,6 +6,11 @@ import ( "strings" ) +var ( + supportedTypes = map[string]bool{"ERC721": true, "ERC1155": true} + slugTokens = map[string]bool{"ERC1155": true} +) + func (p *Platform) GetCollections(owner string) (blockatlas.CollectionPage, error) { collections, err := p.collectionsClient.GetCollections(owner) if err != nil { @@ -223,3 +228,27 @@ func NormalizeCollectible(c *Collection, a Collectible, coinIndex uint) blockatl Coin: coinIndex, } } + +func searchCollection(collections []Collection, collectibleID string) *Collection { + for _, i := range collections { + if strings.EqualFold(i.Slug, collectibleID) { + return &i + } + } + return nil +} + +//TODO: remove once most of the clients will be updated (deadline: March 17th) +func oldSearchCollection(collections []Collection, collectibleID string) *Collection { + for _, i := range collections { + if strings.EqualFold(i.Slug, collectibleID) { + return &i + } + for _, contract := range i.Contracts { + if strings.EqualFold(contract.Address, collectibleID) { + return &i + } + } + } + return nil +} diff --git a/platform/ethereum/collection_client.go b/platform/ethereum/collection_client.go index c6689d156..39cadf664 100644 --- a/platform/ethereum/collection_client.go +++ b/platform/ethereum/collection_client.go @@ -5,7 +5,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/errors" "net/url" "strconv" - "strings" ) type CollectionsClient struct { @@ -74,27 +73,3 @@ func (c CollectionsClient) OldGetCollectibles(owner string, collectibleID string err = c.Get(&page, "api/v1/assets", query) return collection, page.Collectibles, err } - -func searchCollection(collections []Collection, collectibleID string) *Collection { - for _, i := range collections { - if strings.EqualFold(i.Slug, collectibleID) { - return &i - } - } - return nil -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func oldSearchCollection(collections []Collection, collectibleID string) *Collection { - for _, i := range collections { - if strings.EqualFold(i.Slug, collectibleID) { - return &i - } - for _, contract := range i.Contracts { - if strings.EqualFold(contract.Address, collectibleID) { - return &i - } - } - } - return nil -} diff --git a/platform/ethereum/collection_client_test.go b/platform/ethereum/collection_client_test.go deleted file mode 100644 index 8cc118320..000000000 --- a/platform/ethereum/collection_client_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package ethereum - -import ( - "fmt" - "github.com/stretchr/testify/assert" - "testing" -) - -var c1 = Collection{ - Slug: "enjin", - Contracts: []PrimaryAssetContract{{ - Address: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - }}, -} -var c2 = Collection{ - Slug: "cryptokitties", - Contracts: []PrimaryAssetContract{{ - Address: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }}, -} -var c3 = Collection{ - Slug: "age-of-rust", - Contracts: []PrimaryAssetContract{{ - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - }}, -} - -func TestSearchCollection(t *testing.T) { - var tests = []struct { - collections []Collection - collectibleID string - result *Collection - }{ - {[]Collection{c1, c2, c3}, "enjin", &c1}, - {[]Collection{c1, c2, c3}, "cryptokitties", &c2}, - {[]Collection{c1, c2}, "age-of-rust", nil}, - {[]Collection{c1, c2, c3}, "age-of-rust", &c3}, - {[]Collection{c1, c2}, "cryptokitties", &c2}, - {[]Collection{c1}, "age-of-rust", nil}, - {[]Collection{c1, c3}, "enjin", &c1}, - } - for i, tt := range tests { - t.Run(fmt.Sprintf("searchCollection %d", i), func(t *testing.T) { - s := searchCollection(tt.collections, tt.collectibleID) - assert.EqualValues(t, s, tt.result) - }) - } - -} diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/collection_test.go index c68acb492..a3b6be197 100644 --- a/platform/ethereum/collection_test.go +++ b/platform/ethereum/collection_test.go @@ -2,6 +2,7 @@ package ethereum import ( "encoding/json" + "fmt" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -203,3 +204,45 @@ func TestNormalizeCollectible(t *testing.T) { expected := blockatlas.CollectiblePage{collectibleDst} assert.Equal(t, page, expected, "collectible don't equal") } + +var c1 = Collection{ + Slug: "enjin", + Contracts: []PrimaryAssetContract{{ + Address: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + }}, +} +var c2 = Collection{ + Slug: "cryptokitties", + Contracts: []PrimaryAssetContract{{ + Address: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }}, +} +var c3 = Collection{ + Slug: "age-of-rust", + Contracts: []PrimaryAssetContract{{ + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + }}, +} + +func TestSearchCollection(t *testing.T) { + var tests = []struct { + collections []Collection + collectibleID string + result *Collection + }{ + {[]Collection{c1, c2, c3}, "enjin", &c1}, + {[]Collection{c1, c2, c3}, "cryptokitties", &c2}, + {[]Collection{c1, c2}, "age-of-rust", nil}, + {[]Collection{c1, c2, c3}, "age-of-rust", &c3}, + {[]Collection{c1, c2}, "cryptokitties", &c2}, + {[]Collection{c1}, "age-of-rust", nil}, + {[]Collection{c1, c3}, "enjin", &c1}, + } + for i, tt := range tests { + t.Run(fmt.Sprintf("searchCollection %d", i), func(t *testing.T) { + s := searchCollection(tt.collections, tt.collectibleID) + assert.EqualValues(t, s, tt.result) + }) + } + +} diff --git a/platform/ethereum/ens.go b/platform/ethereum/domain.go similarity index 85% rename from platform/ethereum/ens.go rename to platform/ethereum/domain.go index c6929449d..354a06d22 100644 --- a/platform/ethereum/ens.go +++ b/platform/ethereum/domain.go @@ -23,7 +23,7 @@ func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, e } for _, coin := range coins { // try to get multi coin address - address, err := addressForCoin(resolver, coin, name) + address, err := addressForCoin(resolver, coin) if err != nil { logger.Error(errors.E(err, errors.Params{"coin": coin, "name": name})) continue @@ -34,12 +34,12 @@ func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, e return result, nil } -func addressForCoin(resolver *ens.Resolver, coin uint64, name string) (string, error) { +func addressForCoin(resolver *ens.Resolver, coin uint64) (string, error) { address, err := resolver.MultiAddress(coin) if err != nil { if coin == CoinType.ETH { // user may not set multi coin address - result, err := lookupLegacyETH(resolver, name) + result, err := lookupLegacyETH(resolver) if err != nil { return "", errors.E(err, "query legacy address failed") } @@ -54,7 +54,7 @@ func addressForCoin(resolver *ens.Resolver, coin uint64, name string) (string, e return encoded, nil } -func lookupLegacyETH(resolver *ens.Resolver, name string) (string, error) { +func lookupLegacyETH(resolver *ens.Resolver) (string, error) { address, err := resolver.Address() if err != nil { return "", errors.E(err, "query address failed") diff --git a/platform/ethereum/token.go b/platform/ethereum/token.go new file mode 100644 index 000000000..cce551a02 --- /dev/null +++ b/platform/ethereum/token.go @@ -0,0 +1,40 @@ +package ethereum + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { + account, err := p.client.GetTokens(address) + if err != nil { + return nil, err + } + return NormalizeTokens(account.Docs, *p), nil +} + +// NormalizeToken converts a Ethereum token into the generic model +func NormalizeToken(srcToken *Token, coinIndex uint) (t blockatlas.Token, ok bool) { + t = blockatlas.Token{ + Name: srcToken.Contract.Name, + Symbol: srcToken.Contract.Symbol, + TokenID: srcToken.Contract.Contract, + Coin: coinIndex, + Decimals: srcToken.Contract.Decimals, + Type: blockatlas.TokenTypeERC20, + } + + return t, true +} + +// NormalizeTxs converts multiple Ethereum tokens +func NormalizeTokens(srcTokens []Token, p Platform) []blockatlas.Token { + tokenPage := make([]blockatlas.Token, 0) + for _, srcToken := range srcTokens { + token, ok := NormalizeToken(&srcToken, p.CoinIndex) + if !ok { + continue + } + tokenPage = append(tokenPage, token) + } + return tokenPage +} diff --git a/platform/ethereum/token_test.go b/platform/ethereum/token_test.go new file mode 100644 index 000000000..1a87cdfcf --- /dev/null +++ b/platform/ethereum/token_test.go @@ -0,0 +1,73 @@ +package ethereum + +import ( + "bytes" + "encoding/json" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" +) + +const tokenSrc = ` +{ + "balance": "0", + "contract": { + "contract": "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", + "address": "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", + "name": "FusChain", + "decimals": 18, + "symbol": "FUS" + } +}` + +var tokenDst = blockatlas.Token{ + Name: "FusChain", + Symbol: "FUS", + Decimals: 18, + TokenID: "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", + Coin: coin.ETH, + Type: blockatlas.TokenTypeERC20, +} + +type testToken struct { + name string + apiResponse string + expected *blockatlas.Token +} + +func TestNormalizeToken(t *testing.T) { + testNormalizeToken(t, &testToken{ + name: "token", + apiResponse: tokenSrc, + expected: &tokenDst, + }) +} + +func testNormalizeToken(t *testing.T, _test *testToken) { + var token Token + err := json.Unmarshal([]byte(_test.apiResponse), &token) + if err != nil { + t.Error(err) + return + } + tk, ok := NormalizeToken(&token, coin.ETH) + if !ok { + t.Errorf("token: token could not be normalized") + } + + resJSON, err := json.Marshal(&tk) + if err != nil { + t.Fatal(err) + } + + dstJSON, err := json.Marshal(_test.expected) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(resJSON, dstJSON) { + println(string(resJSON)) + println(string(dstJSON)) + t.Error("token: token don't equal") + } +} diff --git a/platform/ethereum/api.go b/platform/ethereum/transaction.go similarity index 56% rename from platform/ethereum/api.go rename to platform/ethereum/transaction.go index 8871d283c..5b27f1980 100644 --- a/platform/ethereum/api.go +++ b/platform/ethereum/transaction.go @@ -1,50 +1,15 @@ package ethereum import ( - "fmt" "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" "math/big" "net/http" - "strconv" ) -var ( - supportedTypes = map[string]bool{"ERC721": true, "ERC1155": true} - slugTokens = map[string]bool{"ERC1155": true} -) - -type Platform struct { - client Client - collectionsClient CollectionsClient - CoinIndex uint - RpcURL string -} - -func (p *Platform) Init() error { - handle := coin.Coins[p.CoinIndex].Handle - - coinVar := fmt.Sprintf("%s.api", handle) - p.client = Client{blockatlas.InitClient(viper.GetString(coinVar))} - - collectionsApiVar := fmt.Sprintf("%s.collections_api", handle) - p.collectionsClient = CollectionsClient{blockatlas.InitClient(viper.GetString(collectionsApiVar))} - - collectionsApiKeyVar := fmt.Sprintf("%s.collections_api_key", handle) - p.collectionsClient.Headers["X-API-KEY"] = viper.GetString(collectionsApiKeyVar) - - p.RpcURL = viper.GetString("ethereum.rpc") - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[p.CoinIndex] -} - func (p *Platform) RegisterRoutes(router gin.IRouter) { router.GET("/:address", func(c *gin.Context) { p.getTransactions(c) @@ -173,58 +138,3 @@ func apiError(c *gin.Context, err error) bool { } return false } - -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.CurrentBlockNumber() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - if srcPage, err := p.client.GetBlockByNumber(num); err == nil { - var txs []blockatlas.Tx - for _, srcTx := range srcPage { - txs = AppendTxs(txs, &srcTx, p.CoinIndex) - } - return &blockatlas.Block{ - Number: num, - ID: strconv.FormatInt(num, 10), - Txs: txs, - }, nil - } else { - return nil, err - } -} - -func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { - account, err := p.client.GetTokens(address) - if err != nil { - return nil, err - } - return NormalizeTokens(account.Docs, *p), nil -} - -// NormalizeToken converts a Ethereum token into the generic model -func NormalizeToken(srcToken *Token, coinIndex uint) (t blockatlas.Token, ok bool) { - t = blockatlas.Token{ - Name: srcToken.Contract.Name, - Symbol: srcToken.Contract.Symbol, - TokenID: srcToken.Contract.Contract, - Coin: coinIndex, - Decimals: srcToken.Contract.Decimals, - Type: blockatlas.TokenTypeERC20, - } - - return t, true -} - -// NormalizeTxs converts multiple Ethereum tokens -func NormalizeTokens(srcTokens []Token, p Platform) []blockatlas.Token { - tokenPage := make([]blockatlas.Token, 0) - for _, srcToken := range srcTokens { - token, ok := NormalizeToken(&srcToken, p.CoinIndex) - if !ok { - continue - } - tokenPage = append(tokenPage, token) - } - return tokenPage -} diff --git a/platform/ethereum/api_test.go b/platform/ethereum/transaction_test.go similarity index 83% rename from platform/ethereum/api_test.go rename to platform/ethereum/transaction_test.go index 7b9da9d1e..c26a50f4a 100644 --- a/platform/ethereum/api_test.go +++ b/platform/ethereum/transaction_test.go @@ -237,67 +237,3 @@ func testNormalize(t *testing.T, _test *test) { t.Error(_test.name + ": tx don't equal") } } - -const tokenSrc = ` -{ - "balance": "0", - "contract": { - "contract": "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", - "address": "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", - "name": "FusChain", - "decimals": 18, - "symbol": "FUS" - } -}` - -var tokenDst = blockatlas.Token{ - Name: "FusChain", - Symbol: "FUS", - Decimals: 18, - TokenID: "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", - Coin: coin.ETH, - Type: blockatlas.TokenTypeERC20, -} - -type testToken struct { - name string - apiResponse string - expected *blockatlas.Token -} - -func TestNormalizeToken(t *testing.T) { - testNormalizeToken(t, &testToken{ - name: "token", - apiResponse: tokenSrc, - expected: &tokenDst, - }) -} - -func testNormalizeToken(t *testing.T, _test *testToken) { - var token Token - err := json.Unmarshal([]byte(_test.apiResponse), &token) - if err != nil { - t.Error(err) - return - } - tk, ok := NormalizeToken(&token, coin.ETH) - if !ok { - t.Errorf("token: token could not be normalized") - } - - resJSON, err := json.Marshal(&tk) - if err != nil { - t.Fatal(err) - } - - dstJSON, err := json.Marshal(_test.expected) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error("token: token don't equal") - } -} diff --git a/platform/fio/base.go b/platform/fio/base.go new file mode 100644 index 000000000..6db1586a3 --- /dev/null +++ b/platform/fio/base.go @@ -0,0 +1,20 @@ +package fio + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("fio.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.FIO] +} diff --git a/platform/fio/api.go b/platform/fio/domain.go similarity index 58% rename from platform/fio/api.go rename to platform/fio/domain.go index 0b293d94d..4da1846b6 100644 --- a/platform/fio/api.go +++ b/platform/fio/domain.go @@ -1,28 +1,10 @@ package fio import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("fio.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.FIO] -} - -func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err error) { - return page, err -} - func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { var result []blockatlas.Resolved for _, coinId := range coins { diff --git a/platform/fio/transaction.go b/platform/fio/transaction.go new file mode 100644 index 000000000..11f87aef5 --- /dev/null +++ b/platform/fio/transaction.go @@ -0,0 +1,9 @@ +package fio + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err error) { + return page, err +} diff --git a/platform/harmony/base.go b/platform/harmony/base.go new file mode 100644 index 000000000..75bce0e88 --- /dev/null +++ b/platform/harmony/base.go @@ -0,0 +1,21 @@ +package harmony + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("harmony.api"))} + p.client.Headers["Content-Type"] = "application/json" + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.ONE] +} diff --git a/platform/harmony/block.go b/platform/harmony/block.go new file mode 100644 index 000000000..c6e90cb42 --- /dev/null +++ b/platform/harmony/block.go @@ -0,0 +1,30 @@ +package harmony + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.CurrentBlockNumber() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + srcBlock, err := p.client.GetBlockByNumber(num) + if err != nil { + return nil, err + } + block := p.NormalizeBlock(&srcBlock) + return &block, nil +} + +func (p *Platform) NormalizeBlock(block *BlockInfo) blockatlas.Block { + blockNumber, err := hexToInt(block.Number) + if err != nil { + return blockatlas.Block{} + } + return blockatlas.Block{ + ID: block.Hash, + Number: int64(blockNumber), + Txs: NormalizeTxs(block.Transactions), + } +} diff --git a/platform/harmony/api.go b/platform/harmony/transaction.go similarity index 71% rename from platform/harmony/api.go rename to platform/harmony/transaction.go index 2197a3491..a83a6ddce 100644 --- a/platform/harmony/api.go +++ b/platform/harmony/transaction.go @@ -1,7 +1,6 @@ package harmony import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" @@ -9,20 +8,6 @@ import ( "strconv" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("harmony.api"))} - p.client.Headers["Content-Type"] = "application/json" - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.ONE] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { result, err := p.client.GetTxsOfAddress(address) if err != nil { @@ -31,31 +16,6 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return NormalizeTxs(result.Transactions), err } -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.CurrentBlockNumber() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - srcBlock, err := p.client.GetBlockByNumber(num) - if err != nil { - return nil, err - } - block := p.NormalizeBlock(&srcBlock) - return &block, nil -} - -func (p *Platform) NormalizeBlock(block *BlockInfo) blockatlas.Block { - blockNumber, err := hexToInt(block.Number) - if err != nil { - return blockatlas.Block{} - } - return blockatlas.Block{ - ID: block.Hash, - Number: int64(blockNumber), - Txs: NormalizeTxs(block.Transactions), - } -} - func NormalizeTxs(txs []Transaction) blockatlas.TxPage { normalizeTxs := make([]blockatlas.Tx, 0) for _, srcTx := range txs { diff --git a/platform/harmony/api_test.go b/platform/harmony/transaction_test.go similarity index 100% rename from platform/harmony/api_test.go rename to platform/harmony/transaction_test.go diff --git a/platform/icon/base.go b/platform/icon/base.go new file mode 100644 index 000000000..74c785a8a --- /dev/null +++ b/platform/icon/base.go @@ -0,0 +1,20 @@ +package icon + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("icon.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.ICX] +} diff --git a/platform/icon/api.go b/platform/icon/transaction.go similarity index 85% rename from platform/icon/api.go rename to platform/icon/transaction.go index 06faf7226..0742e9408 100644 --- a/platform/icon/api.go +++ b/platform/icon/transaction.go @@ -1,7 +1,6 @@ package icon import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" @@ -10,19 +9,6 @@ import ( "time" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("icon.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.ICX] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { trxs, err := p.client.GetAddressTransactions(address) if err != nil { diff --git a/platform/icon/api_test.go b/platform/icon/transaction_test.go similarity index 100% rename from platform/icon/api_test.go rename to platform/icon/transaction_test.go diff --git a/platform/iotex/base.go b/platform/iotex/base.go new file mode 100644 index 000000000..e9de7daeb --- /dev/null +++ b/platform/iotex/base.go @@ -0,0 +1,20 @@ +package iotex + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("iotex.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.IOTX] +} diff --git a/platform/iotex/block.go b/platform/iotex/block.go new file mode 100644 index 000000000..6e5d3f5ff --- /dev/null +++ b/platform/iotex/block.go @@ -0,0 +1,29 @@ +package iotex + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.GetLatestBlock() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + var normalized []blockatlas.Tx + txs, err := p.client.GetTxsInBlock(num) + if err != nil { + return nil, err + } + + for _, action := range txs { + tx := Normalize(action) + if tx != nil { + normalized = append(normalized, *tx) + } + } + + return &blockatlas.Block{ + Number: num, + Txs: normalized, + }, nil +} diff --git a/platform/iotex/api.go b/platform/iotex/transaction.go similarity index 70% rename from platform/iotex/api.go rename to platform/iotex/transaction.go index 18b29492d..03f5086e5 100644 --- a/platform/iotex/api.go +++ b/platform/iotex/transaction.go @@ -5,47 +5,9 @@ import ( "strconv" "time" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("iotex.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.IOTX] -} - -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.GetLatestBlock() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - var normalized []blockatlas.Tx - txs, err := p.client.GetTxsInBlock(num) - if err != nil { - return nil, err - } - - for _, action := range txs { - tx := Normalize(action) - if tx != nil { - normalized = append(normalized, *tx) - } - } - - return &blockatlas.Block{ - Number: num, - Txs: normalized, - }, nil -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { txs := make([]blockatlas.Tx, 0) var start int64 diff --git a/platform/iotex/api_test.go b/platform/iotex/transaction_test.go similarity index 100% rename from platform/iotex/api_test.go rename to platform/iotex/transaction_test.go diff --git a/platform/nano/base.go b/platform/nano/base.go new file mode 100644 index 000000000..08cac55ee --- /dev/null +++ b/platform/nano/base.go @@ -0,0 +1,22 @@ +package nano + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + + "github.com/spf13/viper" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("nano.api"))} + p.client.Headers["Content-Type"] = "application/json" + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.NANO] +} diff --git a/platform/nano/api.go b/platform/nano/transaction.go similarity index 80% rename from platform/nano/api.go rename to platform/nano/transaction.go index 95b57fecf..2e9ff1bff 100644 --- a/platform/nano/api.go +++ b/platform/nano/transaction.go @@ -4,26 +4,9 @@ import ( "encoding/json" "strconv" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - - "github.com/spf13/viper" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("nano.api"))} - p.client.Headers["Content-Type"] = "application/json" - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.NANO] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { normalized := make([]blockatlas.Tx, 0) history, err := p.client.GetAccountHistory(address) diff --git a/platform/nano/api_test.go b/platform/nano/transaction_test.go similarity index 100% rename from platform/nano/api_test.go rename to platform/nano/transaction_test.go diff --git a/platform/nebulas/base.go b/platform/nebulas/base.go new file mode 100644 index 000000000..2b03679c5 --- /dev/null +++ b/platform/nebulas/base.go @@ -0,0 +1,20 @@ +package nebulas + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("nebulas.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.NAS] +} diff --git a/platform/nebulas/api.go b/platform/nebulas/transaction.go similarity index 85% rename from platform/nebulas/api.go rename to platform/nebulas/transaction.go index 0a1f269eb..d31df4d05 100644 --- a/platform/nebulas/api.go +++ b/platform/nebulas/transaction.go @@ -1,24 +1,10 @@ package nebulas import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("nebulas.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.NAS] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { txs, err := p.client.GetTxs(address, 1) if err != nil { diff --git a/platform/nebulas/api_test.go b/platform/nebulas/transaction_test.go similarity index 100% rename from platform/nebulas/api_test.go rename to platform/nebulas/transaction_test.go diff --git a/platform/nimiq/base.go b/platform/nimiq/base.go new file mode 100644 index 000000000..e64e82297 --- /dev/null +++ b/platform/nimiq/base.go @@ -0,0 +1,20 @@ +package nimiq + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("nimiq.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.NIM] +} diff --git a/platform/nimiq/block.go b/platform/nimiq/block.go new file mode 100644 index 000000000..e24584790 --- /dev/null +++ b/platform/nimiq/block.go @@ -0,0 +1,27 @@ +package nimiq + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.CurrentBlockNumber() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + srcBlock, err := p.client.GetBlockByNumber(num) + if err != nil { + return nil, err + } + block := NormalizeBlock(srcBlock) + return &block, nil +} + +// NormalizeBlock converts a Nimiq block into the generic model +func NormalizeBlock(srcBlock *Block) blockatlas.Block { + return blockatlas.Block{ + Number: srcBlock.Number, + ID: srcBlock.Hash, + Txs: NormalizeTxs(srcBlock.Txs), + } +} diff --git a/platform/nimiq/api.go b/platform/nimiq/transaction.go similarity index 55% rename from platform/nimiq/api.go rename to platform/nimiq/transaction.go index 021e9c01d..dc220aa1b 100644 --- a/platform/nimiq/api.go +++ b/platform/nimiq/transaction.go @@ -1,37 +1,10 @@ package nimiq import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("nimiq.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.NIM] -} - -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.CurrentBlockNumber() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - srcBlock, err := p.client.GetBlockByNumber(num) - if err != nil { - return nil, err - } - block := NormalizeBlock(srcBlock) - return &block, nil -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { srcTxs, err := p.client.GetTxsOfAddress(address) if err != nil { @@ -67,12 +40,3 @@ func NormalizeTxs(srcTxs []Tx) []blockatlas.Tx { } return txs } - -// NormalizeBlock converts a Nimiq block into the generic model -func NormalizeBlock(srcBlock *Block) blockatlas.Block { - return blockatlas.Block{ - Number: srcBlock.Number, - ID: srcBlock.Hash, - Txs: NormalizeTxs(srcBlock.Txs), - } -} diff --git a/platform/nimiq/api_test.go b/platform/nimiq/transaction_test.go similarity index 100% rename from platform/nimiq/api_test.go rename to platform/nimiq/transaction_test.go diff --git a/platform/ontology/base.go b/platform/ontology/base.go new file mode 100644 index 000000000..dd5ce0480 --- /dev/null +++ b/platform/ontology/base.go @@ -0,0 +1,20 @@ +package ontology + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("ontology.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.ONT] +} diff --git a/platform/ontology/block.go b/platform/ontology/block.go new file mode 100644 index 000000000..f656e0cb3 --- /dev/null +++ b/platform/ontology/block.go @@ -0,0 +1,33 @@ +package ontology + +import ( + blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + block, err := p.client.CurrentBlockNumber() + if err != nil { + return 0, errors.E(err, "CurrentBlockNumber") + } + if len(block.Result.Records) == 0 { + return 0, errors.E("invalid block height result") + } + return block.Result.Records[0].Height, nil +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + blockOnt, err := p.client.GetBlockByNumber(num) + if err != nil { + return nil, err + } + txsRaw, err := p.getTxDetails(blockOnt.Result.Txs) + if err != nil { + return nil, err + } + txs := normalizeTxs(txsRaw, AssetAll) + return &blockatlas.Block{ + Number: num, + Txs: txs, + }, nil +} diff --git a/platform/ontology/api.go b/platform/ontology/transaction.go similarity index 81% rename from platform/ontology/api.go rename to platform/ontology/transaction.go index 6213e634e..c2fb04856 100644 --- a/platform/ontology/api.go +++ b/platform/ontology/transaction.go @@ -1,7 +1,6 @@ package ontology import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" @@ -10,19 +9,6 @@ import ( "sync" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("ontology.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.ONT] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return p.GetTokenTxsByAddress(address, string(AssetONT)) } @@ -121,33 +107,6 @@ func normalizeONG(tx blockatlas.Tx, transfers Transfers) (blockatlas.Tx, bool) { return tx, true } -func (p *Platform) CurrentBlockNumber() (int64, error) { - block, err := p.client.CurrentBlockNumber() - if err != nil { - return 0, errors.E(err, "CurrentBlockNumber") - } - if len(block.Result.Records) == 0 { - return 0, errors.E("invalid block height result") - } - return block.Result.Records[0].Height, nil -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - blockOnt, err := p.client.GetBlockByNumber(num) - if err != nil { - return nil, err - } - txsRaw, err := p.getTxDetails(blockOnt.Result.Txs) - if err != nil { - return nil, err - } - txs := normalizeTxs(txsRaw, AssetAll) - return &blockatlas.Block{ - Number: num, - Txs: txs, - }, nil -} - func (p *Platform) getTxDetails(srcTx []Tx) ([]Tx, error) { var wg sync.WaitGroup txsOntV2Chan := make(chan Tx, len(srcTx)) diff --git a/platform/ontology/api_test.go b/platform/ontology/transaction_test.go similarity index 100% rename from platform/ontology/api_test.go rename to platform/ontology/transaction_test.go diff --git a/platform/polkadot/base.go b/platform/polkadot/base.go new file mode 100644 index 000000000..e2342dd47 --- /dev/null +++ b/platform/polkadot/base.go @@ -0,0 +1,26 @@ +package polkadot + +import ( + "fmt" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client + CoinIndex uint +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString(p.ConfigKey()))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[p.CoinIndex] +} + +func (p *Platform) ConfigKey() string { + return fmt.Sprintf("%s.api", p.Coin().Handle) +} diff --git a/platform/polkadot/block.go b/platform/polkadot/block.go new file mode 100644 index 000000000..7008fe947 --- /dev/null +++ b/platform/polkadot/block.go @@ -0,0 +1,21 @@ +package polkadot + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.GetCurrentBlock() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + if srcBlock, err := p.client.GetBlockByNumber(num); err == nil { + txs := p.NormalizeExtrinsics(srcBlock) + return &blockatlas.Block{ + Number: num, + Txs: txs, + }, nil + } else { + return nil, err + } +} diff --git a/platform/polkadot/api.go b/platform/polkadot/transaction.go similarity index 79% rename from platform/polkadot/api.go rename to platform/polkadot/transaction.go index 4de110ce4..1685c717d 100644 --- a/platform/polkadot/api.go +++ b/platform/polkadot/transaction.go @@ -7,34 +7,14 @@ import ( "github.com/trustwallet/blockatlas/pkg/numbers" "strings" - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) -type Platform struct { - client Client - CoinIndex uint -} - var NetworkByteMap = map[string]byte{ "DOT": 0x00, "KSM": 0x02, } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString(p.ConfigKey()))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[p.CoinIndex] -} - -func (p *Platform) ConfigKey() string { - return fmt.Sprintf("%s.api", p.Coin().Handle) -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { transfers, err := p.client.GetTransfersOfAddress(address) if err != nil { @@ -50,22 +30,6 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.GetCurrentBlock() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - if srcBlock, err := p.client.GetBlockByNumber(num); err == nil { - txs := p.NormalizeExtrinsics(srcBlock) - return &blockatlas.Block{ - Number: num, - Txs: txs, - }, nil - } else { - return nil, err - } -} - func (p *Platform) NormalizeTransfer(srcTx *Transfer) blockatlas.Tx { decimals := p.Coin().Decimals amount := strings.Split(numbers.DecimalExp(srcTx.Amount, int(decimals)), ".")[0] diff --git a/platform/polkadot/api_test.go b/platform/polkadot/transaction_test.go similarity index 100% rename from platform/polkadot/api_test.go rename to platform/polkadot/transaction_test.go diff --git a/platform/ripple/base.go b/platform/ripple/base.go new file mode 100644 index 000000000..83be17700 --- /dev/null +++ b/platform/ripple/base.go @@ -0,0 +1,20 @@ +package ripple + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("ripple.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.XRP] +} diff --git a/platform/ripple/block.go b/platform/ripple/block.go new file mode 100644 index 000000000..6509272bf --- /dev/null +++ b/platform/ripple/block.go @@ -0,0 +1,21 @@ +package ripple + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.GetCurrentBlock() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + if srcBlock, err := p.client.GetBlockByNumber(num); err == nil { + txs := NormalizeTxs(srcBlock) + return &blockatlas.Block{ + Number: num, + Txs: txs, + }, nil + } else { + return nil, err + } +} diff --git a/platform/ripple/api.go b/platform/ripple/transaction.go similarity index 74% rename from platform/ripple/api.go rename to platform/ripple/transaction.go index 9397e87ff..84f0fd871 100644 --- a/platform/ripple/api.go +++ b/platform/ripple/transaction.go @@ -1,26 +1,12 @@ package ripple import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "strconv" "time" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("ripple.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.XRP] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { s, err := p.client.GetTxsOfAddress(address) if err != nil { @@ -39,22 +25,6 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.GetCurrentBlock() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - if srcBlock, err := p.client.GetBlockByNumber(num); err == nil { - txs := NormalizeTxs(srcBlock) - return &blockatlas.Block{ - Number: num, - Txs: txs, - }, nil - } else { - return nil, err - } -} - func NormalizeTxs(srcTxs []Tx) (txs []blockatlas.Tx) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(&srcTx) diff --git a/platform/ripple/api_test.go b/platform/ripple/transaction_test.go similarity index 100% rename from platform/ripple/api_test.go rename to platform/ripple/transaction_test.go diff --git a/platform/stellar/base.go b/platform/stellar/base.go new file mode 100644 index 000000000..67a7ec704 --- /dev/null +++ b/platform/stellar/base.go @@ -0,0 +1,24 @@ +package stellar + +import ( + "fmt" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client + CoinIndex uint +} + +func (p *Platform) Init() error { + handle := coin.Coins[p.CoinIndex].Handle + api := fmt.Sprintf("%s.api", handle) + p.client = Client{blockatlas.InitClient(viper.GetString(api))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[p.CoinIndex] +} diff --git a/platform/stellar/block.go b/platform/stellar/block.go new file mode 100644 index 000000000..0de588d8b --- /dev/null +++ b/platform/stellar/block.go @@ -0,0 +1,25 @@ +package stellar + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.CurrentBlockNumber() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + if srcBlock, err := p.client.GetBlockByNumber(num); err == nil { + block := p.NormalizeBlock(srcBlock) + return &block, nil + } else { + return nil, err + } +} +func (p *Platform) NormalizeBlock(block *Block) blockatlas.Block { + return blockatlas.Block{ + ID: block.Ledger.Id, + Number: block.Ledger.Sequence, + Txs: p.NormalizePayments(block.Payments), + } +} diff --git a/platform/stellar/api.go b/platform/stellar/transaction.go similarity index 71% rename from platform/stellar/api.go rename to platform/stellar/transaction.go index 8cb86ddcf..53cd01cdf 100644 --- a/platform/stellar/api.go +++ b/platform/stellar/transaction.go @@ -1,8 +1,6 @@ package stellar import ( - "fmt" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" @@ -11,22 +9,6 @@ import ( "time" ) -type Platform struct { - client Client - CoinIndex uint -} - -func (p *Platform) Init() error { - handle := coin.Coins[p.CoinIndex].Handle - api := fmt.Sprintf("%s.api", handle) - p.client = Client{blockatlas.InitClient(viper.GetString(api))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[p.CoinIndex] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { payments, err := p.client.GetTxsOfAddress(address) if err != nil { @@ -36,27 +18,6 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return p.NormalizePayments(payments), nil } -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.CurrentBlockNumber() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - if srcBlock, err := p.client.GetBlockByNumber(num); err == nil { - block := p.NormalizeBlock(srcBlock) - return &block, nil - } else { - return nil, err - } -} - -func (p *Platform) NormalizeBlock(block *Block) blockatlas.Block { - return blockatlas.Block{ - ID: block.Ledger.Id, - Number: block.Ledger.Sequence, - Txs: p.NormalizePayments(block.Payments), - } -} - func (p *Platform) NormalizePayments(payments []Payment) (txs []blockatlas.Tx) { var ( wg sync.WaitGroup diff --git a/platform/stellar/api_test.go b/platform/stellar/transaction_test.go similarity index 100% rename from platform/stellar/api_test.go rename to platform/stellar/transaction_test.go diff --git a/platform/tezos/base.go b/platform/tezos/base.go new file mode 100644 index 000000000..0aad538cb --- /dev/null +++ b/platform/tezos/base.go @@ -0,0 +1,23 @@ +package tezos + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client + rpcClient RpcClient +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("tezos.api"))} + p.client.SetTimeout(35) + p.rpcClient = RpcClient{blockatlas.InitClient(viper.GetString("tezos.rpc"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.XTZ] +} diff --git a/platform/tezos/block.go b/platform/tezos/block.go new file mode 100644 index 000000000..2a219b5ae --- /dev/null +++ b/platform/tezos/block.go @@ -0,0 +1,40 @@ +package tezos + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "sync" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.GetCurrentBlock() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + txTypes := []TxType{TxTransactions, TxDelegations} + var wg sync.WaitGroup + out := make(chan []Transaction, len(txTypes)) + wg.Add(len(txTypes)) + for _, t := range txTypes { + go func(txType TxType, num int64, wg *sync.WaitGroup) { + defer wg.Done() + txs, err := p.client.GetBlockByNumber(num, txType) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"txType": txType, "num": num}) + return + } + out <- txs + }(t, num, &wg) + } + wg.Wait() + close(out) + srcTxs := make([]Transaction, 0) + for r := range out { + srcTxs = append(srcTxs, r...) + } + txs := NormalizeTxs(srcTxs) + return &blockatlas.Block{ + Number: num, + Txs: txs, + }, nil +} diff --git a/platform/tezos/stake.go b/platform/tezos/stake.go index e4bf4a3aa..bd46c6d84 100644 --- a/platform/tezos/stake.go +++ b/platform/tezos/stake.go @@ -6,6 +6,8 @@ import ( services "github.com/trustwallet/blockatlas/services/assets" ) +const Annual = 6.09 + func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { account, err := p.rpcClient.GetAccount(address) if err != nil { diff --git a/platform/tezos/api.go b/platform/tezos/transaction.go similarity index 64% rename from platform/tezos/api.go rename to platform/tezos/transaction.go index 1ae3b1849..354c795c3 100644 --- a/platform/tezos/api.go +++ b/platform/tezos/transaction.go @@ -1,31 +1,12 @@ package tezos import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" "sync" ) -type Platform struct { - client Client - rpcClient RpcClient -} - -const Annual = 6.09 - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("tezos.api"))} - p.client.SetTimeout(35) - p.rpcClient = RpcClient{blockatlas.InitClient(viper.GetString("tezos.rpc"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.XTZ] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { txTypes := []TxType{TxTransactions} var wg sync.WaitGroup @@ -51,39 +32,6 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return NormalizeTxs(srcTxs), nil } -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.GetCurrentBlock() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - txTypes := []TxType{TxTransactions, TxDelegations} - var wg sync.WaitGroup - out := make(chan []Transaction, len(txTypes)) - wg.Add(len(txTypes)) - for _, t := range txTypes { - go func(txType TxType, num int64, wg *sync.WaitGroup) { - defer wg.Done() - txs, err := p.client.GetBlockByNumber(num, txType) - if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"txType": txType, "num": num}) - return - } - out <- txs - }(t, num, &wg) - } - wg.Wait() - close(out) - srcTxs := make([]Transaction, 0) - for r := range out { - srcTxs = append(srcTxs, r...) - } - txs := NormalizeTxs(srcTxs) - return &blockatlas.Block{ - Number: num, - Txs: txs, - }, nil -} - func NormalizeTxs(srcTxs []Transaction) (txs []blockatlas.Tx) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(srcTx) diff --git a/platform/tezos/api_test.go b/platform/tezos/transaction_test.go similarity index 100% rename from platform/tezos/api_test.go rename to platform/tezos/transaction_test.go diff --git a/platform/theta/base.go b/platform/theta/base.go new file mode 100644 index 000000000..c7db94c20 --- /dev/null +++ b/platform/theta/base.go @@ -0,0 +1,20 @@ +package theta + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("theta.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.THETA] +} diff --git a/platform/theta/api.go b/platform/theta/transaction.go similarity index 89% rename from platform/theta/api.go rename to platform/theta/transaction.go index 9697ff107..72b192da3 100644 --- a/platform/theta/api.go +++ b/platform/theta/transaction.go @@ -1,25 +1,11 @@ package theta import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "strconv" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("theta.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.THETA] -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { // Endpoint supports queries without token query parameter return p.GetTokenTxsByAddress(address, "") diff --git a/platform/theta/api_test.go b/platform/theta/transaction_test.go similarity index 100% rename from platform/theta/api_test.go rename to platform/theta/transaction_test.go diff --git a/platform/tron/api.go b/platform/tron/api.go deleted file mode 100644 index d21ff4f9a..000000000 --- a/platform/tron/api.go +++ /dev/null @@ -1,257 +0,0 @@ -package tron - -import ( - "encoding/hex" - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - "sync" -) - -type Platform struct { - client Client -} - -const Annual = 0.74 - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("tron.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.TRX] -} - -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.CurrentBlockNumber() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - block, err := p.client.GetBlockByNumber(num) - if err != nil { - return nil, err - } - - txsChan := p.NormalizeBlockTxs(block.Txs) - txs := make(blockatlas.TxPage, 0) - for cTxs := range txsChan { - txs = append(txs, cTxs) - } - - return &blockatlas.Block{ - Number: num, - Txs: txs, - }, nil -} - -func (p *Platform) NormalizeBlockTxs(srcTxs []Tx) chan blockatlas.Tx { - txChan := make(chan blockatlas.Tx, len(srcTxs)) - var wg sync.WaitGroup - for _, srcTx := range srcTxs { - wg.Add(1) - go func(s Tx, c chan blockatlas.Tx) { - defer wg.Done() - p.NormalizeBlockChannel(s, c) - }(srcTx, txChan) - } - wg.Wait() - close(txChan) - return txChan -} - -func (p *Platform) NormalizeBlockChannel(srcTx Tx, txChan chan blockatlas.Tx) { - if len(srcTx.Data.Contracts) == 0 { - return - } - - tx, err := Normalize(srcTx) - if err != nil { - return - } - transfer := srcTx.Data.Contracts[0].Parameter.Value - if len(transfer.AssetName) > 0 { - assetName, err := hex.DecodeString(transfer.AssetName[:]) - if err == nil { - info, err := p.client.GetTokenInfo(string(assetName)) - if err == nil && len(info.Data) > 0 { - setTokenMeta(tx, srcTx, info.Data[0]) - } - } - } - txChan <- *tx -} - -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - Txs, err := p.client.GetTxsOfAddress(address, "") - if err != nil && len(Txs) == 0 { - return nil, err - } - - txs := make(blockatlas.TxPage, 0) - for _, srcTx := range Txs { - tx, err := Normalize(srcTx) - if err != nil { - continue - } - - if len(srcTx.Data.Contracts) > 0 && srcTx.Data.Contracts[0].Type == TransferContract { - txs = append(txs, *tx) - } else { - continue - } - } - - return txs, nil -} - -func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { - tokenTxs, err := p.client.GetTxsOfAddress(address, token) - if err != nil { - return nil, errors.E(err, "TRON: failed to get token from address", errors.TypePlatformApi, - errors.Params{"address": address, "token": token}).PushToSentry() - } - - txs := make(blockatlas.TxPage, 0) - - if len(tokenTxs) == 0 { - return txs, nil - } - - info, err := p.client.GetTokenInfo(token) - if err != nil || len(info.Data) == 0 { - return nil, errors.E(err, "TRON: failed to get token info", errors.TypePlatformApi, - errors.Params{"address": address, "token": token}).PushToSentry() - } - - for _, srcTx := range tokenTxs { - tx, err := Normalize(srcTx) - if err != nil { - logger.Error(err) - continue - } - setTokenMeta(tx, srcTx, info.Data[0]) - txs = append(txs, *tx) - } - - return txs, nil -} - -func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { - tokens, err := p.client.GetAccount(address) - if err != nil { - return nil, err - } - tokenPage := make(blockatlas.TokenPage, 0) - if len(tokens.Data) == 0 { - return tokenPage, nil - } - - var tokenIds []string - for _, v := range tokens.Data[0].AssetsV2 { - tokenIds = append(tokenIds, v.Key) - } - - tokensChan := p.getTokens(tokenIds) - for info := range tokensChan { - tokenPage = append(tokenPage, info) - } - return tokenPage, nil -} - -func (p *Platform) getTokens(ids []string) chan blockatlas.Token { - tkChan := make(chan blockatlas.Token, len(ids)) - var wg sync.WaitGroup - for _, id := range ids { - wg.Add(1) - go func(i string, c chan blockatlas.Token) { - defer wg.Done() - err := p.getTokensChannel(i, c) - if err != nil { - logger.Error(err) - } - }(id, tkChan) - } - wg.Wait() - close(tkChan) - return tkChan -} - -func (p *Platform) getTokensChannel(id string, tkChan chan blockatlas.Token) error { - info, err := p.client.GetTokenInfo(id) - if err != nil || len(info.Data) == 0 { - logger.Error(err, "GetTokenInfo: invalid token") - return err - } - asset := NormalizeToken(info.Data[0]) - tkChan <- asset - return nil -} - -func NormalizeToken(info AssetInfo) blockatlas.Token { - return blockatlas.Token{ - Name: info.Name, - Symbol: info.Symbol, - TokenID: info.ID, - Coin: coin.TRX, - Decimals: info.Decimals, - Type: blockatlas.TokenTypeTRC10, - } -} - -func setTokenMeta(tx *blockatlas.Tx, srcTx Tx, tokenInfo AssetInfo) { - transfer := srcTx.Data.Contracts[0].Parameter.Value - tx.Meta = blockatlas.TokenTransfer{ - Name: tokenInfo.Name, - Symbol: tokenInfo.Symbol, - TokenID: tokenInfo.ID, - Decimals: tokenInfo.Decimals, - Value: transfer.Amount, - From: tx.From, - To: tx.To, - } -} - -/// Normalize converts a Tron transaction into the generic model -func Normalize(srcTx Tx) (*blockatlas.Tx, error) { - if len(srcTx.Data.Contracts) == 0 { - return nil, errors.E("TRON: transfer without contract", errors.TypePlatformApi, - errors.Params{"tx": srcTx}).PushToSentry() - } - - contract := srcTx.Data.Contracts[0] - if contract.Type != TransferContract && contract.Type != TransferAssetContract { - return nil, errors.E("TRON: invalid contract transfer", errors.TypePlatformApi, - errors.Params{"tx": srcTx, "type": contract.Type}) - } - - transfer := contract.Parameter.Value - from, err := HexToAddress(transfer.OwnerAddress) - if err != nil { - return nil, errors.E(err, "TRON: failed to get from address", errors.TypePlatformApi, - errors.Params{"tx": srcTx}).PushToSentry() - } - to, err := HexToAddress(transfer.ToAddress) - if err != nil { - return nil, errors.E(err, "TRON: failed to get to address", errors.TypePlatformApi, - errors.Params{"tx": srcTx}).PushToSentry() - } - - return &blockatlas.Tx{ - ID: srcTx.ID, - Coin: coin.TRX, - Date: srcTx.BlockTime / 1000, - From: from, - To: to, - Fee: "0", - Block: 0, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: transfer.Amount, - Symbol: coin.Coins[coin.TRX].Symbol, - Decimals: coin.Coins[coin.TRX].Decimals, - }, - }, nil -} diff --git a/platform/tron/base.go b/platform/tron/base.go new file mode 100644 index 000000000..c713d9862 --- /dev/null +++ b/platform/tron/base.go @@ -0,0 +1,20 @@ +package tron + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("tron.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.TRX] +} diff --git a/platform/tron/block.go b/platform/tron/block.go new file mode 100644 index 000000000..dba8310d9 --- /dev/null +++ b/platform/tron/block.go @@ -0,0 +1,66 @@ +package tron + +import ( + "encoding/hex" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "sync" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.CurrentBlockNumber() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + block, err := p.client.GetBlockByNumber(num) + if err != nil { + return nil, err + } + + txsChan := p.NormalizeBlockTxs(block.Txs) + txs := make(blockatlas.TxPage, 0) + for cTxs := range txsChan { + txs = append(txs, cTxs) + } + + return &blockatlas.Block{ + Number: num, + Txs: txs, + }, nil +} + +func (p *Platform) NormalizeBlockTxs(srcTxs []Tx) chan blockatlas.Tx { + txChan := make(chan blockatlas.Tx, len(srcTxs)) + var wg sync.WaitGroup + for _, srcTx := range srcTxs { + wg.Add(1) + go func(s Tx, c chan blockatlas.Tx) { + defer wg.Done() + p.NormalizeBlockChannel(s, c) + }(srcTx, txChan) + } + wg.Wait() + close(txChan) + return txChan +} + +func (p *Platform) NormalizeBlockChannel(srcTx Tx, txChan chan blockatlas.Tx) { + if len(srcTx.Data.Contracts) == 0 { + return + } + + tx, err := Normalize(srcTx) + if err != nil { + return + } + transfer := srcTx.Data.Contracts[0].Parameter.Value + if len(transfer.AssetName) > 0 { + assetName, err := hex.DecodeString(transfer.AssetName[:]) + if err == nil { + info, err := p.client.GetTokenInfo(string(assetName)) + if err == nil && len(info.Data) > 0 { + setTokenMeta(tx, srcTx, info.Data[0]) + } + } + } + txChan <- *tx +} diff --git a/platform/tron/stake.go b/platform/tron/stake.go index 817b856a9..c3886dd2e 100644 --- a/platform/tron/stake.go +++ b/platform/tron/stake.go @@ -1,6 +1,7 @@ package tron import ( + "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" @@ -9,6 +10,8 @@ import ( "time" ) +const Annual = 0.74 + func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { results := make(blockatlas.ValidatorPage, 0) validators, err := p.client.GetValidators() @@ -67,7 +70,7 @@ func (p *Platform) UndelegatedBalance(address string) (string, error) { } func normalizeValidator(v Validator) (validator blockatlas.Validator, ok bool) { - address, err := HexToAddress(v.Address) + address, err := address.HexToAddress(v.Address) if err != nil { return validator, false } diff --git a/platform/tron/token.go b/platform/tron/token.go new file mode 100644 index 000000000..fc7f21f9c --- /dev/null +++ b/platform/tron/token.go @@ -0,0 +1,70 @@ +package tron + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "sync" +) + +func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { + tokens, err := p.client.GetAccount(address) + if err != nil { + return nil, err + } + tokenPage := make(blockatlas.TokenPage, 0) + if len(tokens.Data) == 0 { + return tokenPage, nil + } + + var tokenIds []string + for _, v := range tokens.Data[0].AssetsV2 { + tokenIds = append(tokenIds, v.Key) + } + + tokensChan := p.getTokens(tokenIds) + for info := range tokensChan { + tokenPage = append(tokenPage, info) + } + return tokenPage, nil +} + +func (p *Platform) getTokens(ids []string) chan blockatlas.Token { + tkChan := make(chan blockatlas.Token, len(ids)) + var wg sync.WaitGroup + for _, id := range ids { + wg.Add(1) + go func(i string, c chan blockatlas.Token) { + defer wg.Done() + err := p.getTokensChannel(i, c) + if err != nil { + logger.Error(err) + } + }(id, tkChan) + } + wg.Wait() + close(tkChan) + return tkChan +} + +func (p *Platform) getTokensChannel(id string, tkChan chan blockatlas.Token) error { + info, err := p.client.GetTokenInfo(id) + if err != nil || len(info.Data) == 0 { + logger.Error(err, "GetTokenInfo: invalid token") + return err + } + asset := NormalizeToken(info.Data[0]) + tkChan <- asset + return nil +} + +func NormalizeToken(info AssetInfo) blockatlas.Token { + return blockatlas.Token{ + Name: info.Name, + Symbol: info.Symbol, + TokenID: info.ID, + Coin: coin.TRX, + Decimals: info.Decimals, + Type: blockatlas.TokenTypeTRC10, + } +} diff --git a/platform/tron/token_test.go b/platform/tron/token_test.go new file mode 100644 index 000000000..8bf9089d7 --- /dev/null +++ b/platform/tron/token_test.go @@ -0,0 +1,22 @@ +package tron + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" +) + +var tokenDst = blockatlas.Token{ + Name: "Test", + Symbol: "TST", + Decimals: 8, + TokenID: "1", + Coin: 195, + Type: "TRC10", +} + +func TestNormalizeToken(t *testing.T) { + asset := AssetInfo{Name: "Test", Symbol: "TST", ID: "1", Decimals: 8} + actual := NormalizeToken(asset) + assert.Equal(t, tokenDst, actual) +} diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go new file mode 100644 index 000000000..d12a25a06 --- /dev/null +++ b/platform/tron/transaction.go @@ -0,0 +1,119 @@ +package tron + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/address" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/logger" +) + +func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + Txs, err := p.client.GetTxsOfAddress(address, "") + if err != nil && len(Txs) == 0 { + return nil, err + } + + txs := make(blockatlas.TxPage, 0) + for _, srcTx := range Txs { + tx, err := Normalize(srcTx) + if err != nil { + continue + } + + if len(srcTx.Data.Contracts) > 0 && srcTx.Data.Contracts[0].Type == TransferContract { + txs = append(txs, *tx) + } else { + continue + } + } + + return txs, nil +} + +func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { + tokenTxs, err := p.client.GetTxsOfAddress(address, token) + if err != nil { + return nil, errors.E(err, "TRON: failed to get token from address", errors.TypePlatformApi, + errors.Params{"address": address, "token": token}).PushToSentry() + } + + txs := make(blockatlas.TxPage, 0) + + if len(tokenTxs) == 0 { + return txs, nil + } + + info, err := p.client.GetTokenInfo(token) + if err != nil || len(info.Data) == 0 { + return nil, errors.E(err, "TRON: failed to get token info", errors.TypePlatformApi, + errors.Params{"address": address, "token": token}).PushToSentry() + } + + for _, srcTx := range tokenTxs { + tx, err := Normalize(srcTx) + if err != nil { + logger.Error(err) + continue + } + setTokenMeta(tx, srcTx, info.Data[0]) + txs = append(txs, *tx) + } + + return txs, nil +} + +func setTokenMeta(tx *blockatlas.Tx, srcTx Tx, tokenInfo AssetInfo) { + transfer := srcTx.Data.Contracts[0].Parameter.Value + tx.Meta = blockatlas.TokenTransfer{ + Name: tokenInfo.Name, + Symbol: tokenInfo.Symbol, + TokenID: tokenInfo.ID, + Decimals: tokenInfo.Decimals, + Value: transfer.Amount, + From: tx.From, + To: tx.To, + } +} + +/// Normalize converts a Tron transaction into the generic model +func Normalize(srcTx Tx) (*blockatlas.Tx, error) { + if len(srcTx.Data.Contracts) == 0 { + return nil, errors.E("TRON: transfer without contract", errors.TypePlatformApi, + errors.Params{"tx": srcTx}).PushToSentry() + } + + contract := srcTx.Data.Contracts[0] + if contract.Type != TransferContract && contract.Type != TransferAssetContract { + return nil, errors.E("TRON: invalid contract transfer", errors.TypePlatformApi, + errors.Params{"tx": srcTx, "type": contract.Type}) + } + + transfer := contract.Parameter.Value + from, err := address.HexToAddress(transfer.OwnerAddress) + if err != nil { + return nil, errors.E(err, "TRON: failed to get from address", errors.TypePlatformApi, + errors.Params{"tx": srcTx}).PushToSentry() + } + to, err := address.HexToAddress(transfer.ToAddress) + if err != nil { + return nil, errors.E(err, "TRON: failed to get to address", errors.TypePlatformApi, + errors.Params{"tx": srcTx}).PushToSentry() + } + + return &blockatlas.Tx{ + ID: srcTx.ID, + Coin: coin.TRX, + Date: srcTx.BlockTime / 1000, + From: from, + To: to, + Fee: "0", + Block: 0, + Status: blockatlas.StatusCompleted, + Meta: blockatlas.Transfer{ + Value: transfer.Amount, + Symbol: coin.Coins[coin.TRX].Symbol, + Decimals: coin.Coins[coin.TRX].Decimals, + }, + }, nil +} diff --git a/platform/tron/api_test.go b/platform/tron/transaction_test.go similarity index 90% rename from platform/tron/api_test.go rename to platform/tron/transaction_test.go index 12d1a4209..6a619e990 100644 --- a/platform/tron/api_test.go +++ b/platform/tron/transaction_test.go @@ -133,18 +133,3 @@ func testNormalize(t *testing.T, _test *test) { assert.NotNil(t, res) assert.Equal(t, _test.expected, res) } - -var tokenDst = blockatlas.Token{ - Name: "Test", - Symbol: "TST", - Decimals: 8, - TokenID: "1", - Coin: 195, - Type: "TRC10", -} - -func TestNormalizeToken(t *testing.T) { - asset := AssetInfo{Name: "Test", Symbol: "TST", ID: "1", Decimals: 8} - actual := NormalizeToken(asset) - assert.Equal(t, tokenDst, actual) -} diff --git a/platform/tron/util.go b/platform/tron/util.go deleted file mode 100644 index c7ef9d736..000000000 --- a/platform/tron/util.go +++ /dev/null @@ -1,24 +0,0 @@ -package tron - -import ( - "crypto/sha256" - "encoding/hex" - "github.com/mr-tron/base58" - "github.com/trustwallet/blockatlas/pkg/errors" -) - -// HexToAddress converts a hex representation of a Tron address -// into a Base58 string with a 4 byte checksum. -func HexToAddress(hexAddr string) (b58 string, err error) { - bytes, err := hex.DecodeString(hexAddr) - if err != nil { - return "", errors.E(err, errors.TypePlatformUnmarshal, - errors.Params{"hexAddr": hexAddr}).PushToSentry() - } - var checksum [32]byte - checksum = sha256.Sum256(bytes) - checksum = sha256.Sum256(checksum[:]) - bytes = append(bytes, checksum[:4]...) - b58 = base58.EncodeAlphabet(bytes, base58.BTCAlphabet) - return -} diff --git a/platform/tron/util_test.go b/platform/tron/util_test.go deleted file mode 100644 index 85e8bda18..000000000 --- a/platform/tron/util_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package tron - -import "testing" - -func TestHexToAddress(t *testing.T) { - in := "4182dd6b9966724ae2fdc79b416c7588da67ff1b35" - expected := "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9" - got, err := HexToAddress(in) - if err != nil { - t.Fatal(err) - } - if expected != got { - t.Fatalf("expected %s, got %s", expected, got) - } -} diff --git a/platform/vechain/base.go b/platform/vechain/base.go new file mode 100644 index 000000000..2b6608578 --- /dev/null +++ b/platform/vechain/base.go @@ -0,0 +1,20 @@ +package vechain + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("vechain.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.VET] +} diff --git a/platform/vechain/block.go b/platform/vechain/block.go new file mode 100644 index 000000000..bae6e1ccd --- /dev/null +++ b/platform/vechain/block.go @@ -0,0 +1,26 @@ +package vechain + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.GetCurrentBlock() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + block, err := p.client.GetBlockByNumber(num) + if err != nil { + return nil, err + } + cTxs := p.getTransactionsByIDs(block.Transactions) + txs := make(blockatlas.TxPage, 0) + for t := range cTxs { + txs = append(txs, t...) + } + return &blockatlas.Block{ + Number: num, + ID: block.Id, + Txs: txs, + }, nil +} diff --git a/platform/vechain/api.go b/platform/vechain/transaction.go similarity index 86% rename from platform/vechain/api.go rename to platform/vechain/transaction.go index b27253164..bdf4a7eed 100644 --- a/platform/vechain/api.go +++ b/platform/vechain/transaction.go @@ -1,8 +1,6 @@ package vechain import ( - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" @@ -12,40 +10,6 @@ import ( "sync" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("vechain.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.VET] -} - -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.GetCurrentBlock() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - block, err := p.client.GetBlockByNumber(num) - if err != nil { - return nil, err - } - cTxs := p.getTransactionsByIDs(block.Transactions) - txs := make(blockatlas.TxPage, 0) - for t := range cTxs { - txs = append(txs, t...) - } - return &blockatlas.Block{ - Number: num, - ID: block.Id, - Txs: txs, - }, nil -} - func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { curBlock, err := p.CurrentBlockNumber() if err != nil { diff --git a/platform/vechain/api_test.go b/platform/vechain/transaction_test.go similarity index 100% rename from platform/vechain/api_test.go rename to platform/vechain/transaction_test.go diff --git a/platform/waves/base.go b/platform/waves/base.go new file mode 100644 index 000000000..6715d90af --- /dev/null +++ b/platform/waves/base.go @@ -0,0 +1,20 @@ +package waves + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("waves.api"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.WAVES] +} diff --git a/platform/waves/block.go b/platform/waves/block.go new file mode 100644 index 000000000..4d7d9d9d1 --- /dev/null +++ b/platform/waves/block.go @@ -0,0 +1,26 @@ +package waves + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + currentBlock, err := p.client.GetCurrentBlock() + if err != nil { + return 0, err + } + return currentBlock.Height, nil +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + srcTxs, err := p.client.GetBlockByNumber(num) + if err != nil { + return nil, err + } + txs := NormalizeTxs(srcTxs.Transactions) + + return &blockatlas.Block{ + Number: num, + Txs: txs, + }, nil +} diff --git a/platform/waves/api.go b/platform/waves/transaction.go similarity index 64% rename from platform/waves/api.go rename to platform/waves/transaction.go index fe987f8a8..aafa2ea37 100644 --- a/platform/waves/api.go +++ b/platform/waves/transaction.go @@ -1,47 +1,12 @@ package waves import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "strconv" "github.com/trustwallet/blockatlas/coin" ) -type Platform struct { - client Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("waves.api"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.WAVES] -} - -func (p *Platform) CurrentBlockNumber() (int64, error) { - currentBlock, err := p.client.GetCurrentBlock() - if err != nil { - return 0, err - } - return currentBlock.Height, nil -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - srcTxs, err := p.client.GetBlockByNumber(num) - if err != nil { - return nil, err - } - txs := NormalizeTxs(srcTxs.Transactions) - - return &blockatlas.Block{ - Number: num, - Txs: txs, - }, nil -} - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { addressTxs, err := p.client.GetTxs(address, 25) if err != nil { diff --git a/platform/waves/api_test.go b/platform/waves/transaction_test.go similarity index 100% rename from platform/waves/api_test.go rename to platform/waves/transaction_test.go diff --git a/platform/zilliqa/api.go b/platform/zilliqa/api.go deleted file mode 100644 index 46ec69d73..000000000 --- a/platform/zilliqa/api.go +++ /dev/null @@ -1,102 +0,0 @@ -package zilliqa - -import ( - "strconv" - - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - - "github.com/spf13/viper" -) - -type Platform struct { - client Client - rpcClient RpcClient - udClient Client -} - -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("zilliqa.api"))} - p.client.Headers["X-APIKEY"] = viper.GetString("zilliqa.key") - - p.rpcClient = RpcClient{blockatlas.InitClient(viper.GetString("zilliqa.rpc"))} - p.udClient = Client{blockatlas.InitClient(viper.GetString("zilliqa.lookup"))} - return nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.ZIL] -} - -func (p *Platform) CurrentBlockNumber() (int64, error) { - info, err := p.rpcClient.GetBlockchainInfo() - if err != nil { - return 0, err - } - block, err := strconv.ParseInt(info.NumTxBlocks, 10, 64) - if err != nil { - return 0, err - } - - return block, nil -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - var normalized []blockatlas.Tx - txs, err := p.rpcClient.GetTxInBlock(num) - if err != nil { - return nil, err - } - - for _, srcTx := range txs { - tx := Normalize(&srcTx) - normalized = append(normalized, tx) - } - block := blockatlas.Block{ - Number: num, - Txs: normalized, - } - - return &block, nil -} - -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - var normalized []blockatlas.Tx - txs, err := p.client.GetTxsOfAddress(address) - - if err != nil { - return nil, err - } - - for _, srcTx := range txs { - tx := Normalize(&srcTx) - if len(normalized) >= blockatlas.TxPerPage { - break - } - normalized = append(normalized, tx) - } - - return normalized, nil -} - -func Normalize(srcTx *Tx) (tx blockatlas.Tx) { - tx = blockatlas.Tx{ - ID: srcTx.Hash, - Coin: coin.ZIL, - Date: srcTx.Timestamp / 1000, - From: srcTx.From, - To: srcTx.To, - Fee: blockatlas.Amount(srcTx.Fee), - Block: srcTx.BlockHeight, - Sequence: srcTx.NonceValue(), - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(srcTx.Value), - Symbol: coin.Coins[coin.ZIL].Symbol, - Decimals: coin.Coins[coin.ZIL].Decimals, - }, - } - if !srcTx.ReceiptSuccess { - tx.Status = blockatlas.StatusFailed - } - return tx -} diff --git a/platform/zilliqa/base.go b/platform/zilliqa/base.go new file mode 100644 index 000000000..5a0550e07 --- /dev/null +++ b/platform/zilliqa/base.go @@ -0,0 +1,27 @@ +package zilliqa + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + + "github.com/spf13/viper" +) + +type Platform struct { + client Client + rpcClient RpcClient + udClient Client +} + +func (p *Platform) Init() error { + p.client = Client{blockatlas.InitClient(viper.GetString("zilliqa.api"))} + p.client.Headers["X-APIKEY"] = viper.GetString("zilliqa.key") + + p.rpcClient = RpcClient{blockatlas.InitClient(viper.GetString("zilliqa.rpc"))} + p.udClient = Client{blockatlas.InitClient(viper.GetString("zilliqa.lookup"))} + return nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.ZIL] +} diff --git a/platform/zilliqa/block.go b/platform/zilliqa/block.go new file mode 100644 index 000000000..dbfb6c2c3 --- /dev/null +++ b/platform/zilliqa/block.go @@ -0,0 +1,39 @@ +package zilliqa + +import ( + "strconv" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + info, err := p.rpcClient.GetBlockchainInfo() + if err != nil { + return 0, err + } + block, err := strconv.ParseInt(info.NumTxBlocks, 10, 64) + if err != nil { + return 0, err + } + + return block, nil +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + var normalized []blockatlas.Tx + txs, err := p.rpcClient.GetTxInBlock(num) + if err != nil { + return nil, err + } + + for _, srcTx := range txs { + tx := Normalize(&srcTx) + normalized = append(normalized, tx) + } + block := blockatlas.Block{ + Number: num, + Txs: normalized, + } + + return &block, nil +} diff --git a/platform/zilliqa/zns.go b/platform/zilliqa/domain.go similarity index 100% rename from platform/zilliqa/zns.go rename to platform/zilliqa/domain.go diff --git a/platform/zilliqa/transaction.go b/platform/zilliqa/transaction.go new file mode 100644 index 000000000..cb52d1e56 --- /dev/null +++ b/platform/zilliqa/transaction.go @@ -0,0 +1,47 @@ +package zilliqa + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + var normalized []blockatlas.Tx + txs, err := p.client.GetTxsOfAddress(address) + + if err != nil { + return nil, err + } + + for _, srcTx := range txs { + tx := Normalize(&srcTx) + if len(normalized) >= blockatlas.TxPerPage { + break + } + normalized = append(normalized, tx) + } + + return normalized, nil +} + +func Normalize(srcTx *Tx) (tx blockatlas.Tx) { + tx = blockatlas.Tx{ + ID: srcTx.Hash, + Coin: coin.ZIL, + Date: srcTx.Timestamp / 1000, + From: srcTx.From, + To: srcTx.To, + Fee: blockatlas.Amount(srcTx.Fee), + Block: srcTx.BlockHeight, + Sequence: srcTx.NonceValue(), + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount(srcTx.Value), + Symbol: coin.Coins[coin.ZIL].Symbol, + Decimals: coin.Coins[coin.ZIL].Decimals, + }, + } + if !srcTx.ReceiptSuccess { + tx.Status = blockatlas.StatusFailed + } + return tx +} diff --git a/platform/zilliqa/api_test.go b/platform/zilliqa/transaction_test.go similarity index 100% rename from platform/zilliqa/api_test.go rename to platform/zilliqa/transaction_test.go From 4ed25fce27a8252572d3c3b12adad62a3c89030b Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 14 Feb 2020 16:05:12 -0700 Subject: [PATCH 129/506] Readme update (#870) * Update README.md * Update README.md * Update README.md --- README.md | 86 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index e9ab47fc9..b608c53f1 100644 --- a/README.md +++ b/README.md @@ -44,23 +44,69 @@ The observer API watches the chain for new transactions and generates notificati ### Requirements * [Go Toolchain](https://golang.org/doc/install) versions 1.13+ - * [Redis](https://redis.io/topics/quickstart) instance (observer and syncmarkets) + * [Redis](https://redis.io/topics/quickstart) instance (observer and markets) ### From Source +There are multiple services: + +1. Platform API - to get transactions, staking, tokens, domain lookup for supported coins in common format +2. Observer API - to subscribe several addresses on different supported coins and receive webhook +3. Market API - to get market data from different platforms in common format +4. Swagger API - swagger for all handlers of 1-3 APIs. You need to route requests to them on you own (nginx) + +There are workers that are linked with Observer API and Market API: + +5. Market Observer - fetching latest rates from multiple external API's and cache it in Redis +6. Platform Observer - fetching latest blocks, parse them to common block specification, check subscribed addresses - send webhook. We use Redis to get information about subscribed addresses per coin with webhooks and caching latest block that was processed by observer + +Market API <-> Redis A <-> Market Observer + +Observer API <-> Redis B <-> Platform Observer + +#### IMPORTANT + +You can run platform API for specific coin only! +```shell +cd cmd/platform_api +ATLAS_PLATFORM=ethereum go run main.go +``` +You will run platform API for Ethereum coin only. You can run 30 coins with 30 binaries for scalability and sustainability. Howevever, you can run all of them at once by using ```ATLAS_PLATFORM=all``` env param + +It works the same for platoform_observer - you can run all observer at 1 binary or 30 coins per 30 binaries + ```shell # Download source to $GOPATH go get -u github.com/trustwallet/blockatlas cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas -# Start Observer with the path to the config.yml ./ -go build -o observer-bin cmd/observer/main.go && ./observer-bin -c config.yml +# Start platform_observer with the path to the config.yml ./ +go build -o platform-observer-bin cmd/platform_observer/main.go && ./platform-observer-bin -c config.yml + +# Start markets_observer with the path to the config.yml ./ +go build -o markets-observer-bin cmd/markets_observer/main.go && ./markets-observer-bin -c config.yml + +# Start Platform API server at port 8420 with the path to the config.yml ./ +go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 -c config.yml -# Start API server at port 8422 with the path to the config.yml ./ -go build -o api-bin cmd/api/main.go && ./api-bin -p 8422 -c config.yml +# Start Market API server at port 8421 with the path to the config.yml ./ +go build -o market-api-bin cmd/market_api/main.go && ./market-api-bin -p 8421 -c config.yml -# Start sync worker for market prices and rates with the path to the config.yml ./ -go build -o syncmarkets-bin cmd/syncmarkets/main.go && ./syncmarkets-bin -c config.yml +# Start Observer API server at port 8422 with the path to the config.yml ./ +go build -o observer-api-bin cmd/observer-api/main.go && ./observer-api-bin -p 8422 -c config.yml + +# Startp Swagger API server at port 8422 with the path to the config.yml ./ +go build -o swagger-api-bin cmd/swagger-api/main.go && ./swagger-api-bin -p 8423 +``` + +OR + +```shell +make go-build +``` +Then +```shell +make start ``` ### Docker @@ -76,22 +122,23 @@ Then build: docker-compose build ``` -For run api, observer and syncmarkets: +For run api, observer and markets: ```shell docker-compose up ``` If you need to start one service: ```shell -docker-compose start api redis -docker-compose start observer redis -docker-compose start syncmarkets redis +# Run only platform API +docker-compose start platform_api +# Run only observer for addresses and api for it +docker-compose start platform_observer observer_api redis +# Run markets with it's api +docker-compose start markets_observer markets_api redis +# Run swagger api +docker-compose start swagger_api ``` -### Heroku - -[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://www.heroku.com/deploy/?template=https://github.com/TrustWallet/blockatlas) - ## Configuration Block Atlas can run just fine without configuration. @@ -138,14 +185,7 @@ Swagger API docs provided at path `/swagger/index.html` - Run the Swag in your Go project root folder. - `$ swag init -g ./cmd/api/main.go -o ./docs` - -## Metrics - -The Blockatlas can collect and expose by `expvar's`, metrics about the application healthy and clients and server requests. -Prometheus or another service can collect metrics provided from the `/metrics` endpoint. - -To protect the route, you can set the environment variables `METRICS_API_TOKEN`, and this route starts to require the auth bearer token. + `$ swag init -g ./cmd/platform_api/main.go -o ./docs` ## Contributing From 91516bf99b86e46410085f27ad890beea2a376d3 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 14 Feb 2020 21:14:08 -0300 Subject: [PATCH 130/506] use built-in sort for txPage (#874) * use built-in sort for txPage * Add unit tests --- api/handlers.go | 3 ++- pkg/blockatlas/marshal.go | 14 ++++---------- pkg/blockatlas/marshal_test.go | 23 +++++++++++++++++++++-- platform/bitcoin/transaction.go | 5 +++-- platform/ethereum/transaction.go | 3 ++- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/api/handlers.go b/api/handlers.go index 03ba0e4b3..322b21841 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -9,6 +9,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/metrics" "net/http" + "sort" ) // @Summary Get Transactions @@ -102,7 +103,7 @@ func makeTxRoute(router gin.IRouter, api blockatlas.Platform, path string) { if len(page) > blockatlas.TxPerPage { page = page[0:blockatlas.TxPerPage] } - page.Sort() + sort.Sort(page) ginutils.RenderSuccess(c, &page) }) } diff --git a/pkg/blockatlas/marshal.go b/pkg/blockatlas/marshal.go index 17fae4e66..f2b118301 100644 --- a/pkg/blockatlas/marshal.go +++ b/pkg/blockatlas/marshal.go @@ -2,11 +2,9 @@ package blockatlas import ( "encoding/json" - "github.com/spf13/cast" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" "regexp" - "sort" "strings" ) @@ -114,13 +112,9 @@ func (a *Amount) MarshalJSON() ([]byte, error) { } // Sort sorts the response by date, descending -func (r *TxPage) Sort() { - sort.Slice(*r, func(i, j int) bool { - ti := cast.ToUint64((*r)[i].Date) - tj := cast.ToUint64((*r)[j].Date) - return ti >= tj - }) -} +func (txs TxPage) Len() int { return len(txs) } +func (txs TxPage) Less(i, j int) bool { return txs[i].Date > txs[j].Date } +func (txs TxPage) Swap(i, j int) { txs[i], txs[j] = txs[j], txs[i] } // MarshalJSON returns a wrapped list of transactions in JSON func (r *TxPage) MarshalJSON() ([]byte, error) { @@ -129,7 +123,7 @@ func (r *TxPage) MarshalJSON() ([]byte, error) { Docs []Tx `json:"docs"` Status bool `json:"status"` } - page.Docs = []Tx(*r) + page.Docs = *r if page.Docs == nil { page.Docs = make([]Tx, 0) } diff --git a/pkg/blockatlas/marshal_test.go b/pkg/blockatlas/marshal_test.go index 1cfdfb220..68566e110 100644 --- a/pkg/blockatlas/marshal_test.go +++ b/pkg/blockatlas/marshal_test.go @@ -3,10 +3,11 @@ package blockatlas import ( "bytes" "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" "reflect" + "sort" "testing" - - "github.com/trustwallet/blockatlas/coin" ) var txJSON = []byte(`{ @@ -76,3 +77,21 @@ func TestTx_MarshalJSON(t *testing.T) { // Compare expected and output JSON bytes.Equal(got, txJSON) } + +func TestSortTxPage(t *testing.T) { + tests := []struct { + name string + page TxPage + want TxPage + }{ + {"test sort 1", TxPage{{Date: 5}, {Date: 2}, {Date: 1}, {Date: 4}, {Date: 3}}, TxPage{{Date: 5}, {Date: 4}, {Date: 3}, {Date: 2}, {Date: 1}}}, + {"test sort 2", TxPage{{Date: 100}, {Date: 2}, {Date: 33}, {Date: 409}}, TxPage{{Date: 409}, {Date: 100}, {Date: 33}, {Date: 2}}}, + {"test sort 3", TxPage{{Date: 100}, {Date: 2}, {Date: 100}}, TxPage{{Date: 100}, {Date: 100}, {Date: 2}}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sort.Sort(tt.page) + assert.Equal(t, tt.want, tt.page) + }) + } +} diff --git a/platform/bitcoin/transaction.go b/platform/bitcoin/transaction.go index ee3f509e5..2388dc137 100644 --- a/platform/bitcoin/transaction.go +++ b/platform/bitcoin/transaction.go @@ -7,6 +7,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" "net/http" + "sort" ) // @Summary Get xpub transactions @@ -32,7 +33,7 @@ func (p *Platform) handleAddressRoute(c *gin.Context) { address := c.Param("address") txs, ok := p.getTxsByAddress(address) txPage := blockatlas.TxPage(txs) - txPage.Sort() + sort.Sort(txPage) if ok != nil { c.JSON(http.StatusInternalServerError, ok) return @@ -44,7 +45,7 @@ func (p *Platform) handleXpubRoute(c *gin.Context) { xpub := c.Param("key") txs, ok := p.getTxsByXPub(xpub) txPage := blockatlas.TxPage(txs) - txPage.Sort() + sort.Sort(txPage) if ok != nil { c.JSON(http.StatusInternalServerError, ok) return diff --git a/platform/ethereum/transaction.go b/platform/ethereum/transaction.go index 5b27f1980..882fa834d 100644 --- a/platform/ethereum/transaction.go +++ b/platform/ethereum/transaction.go @@ -8,6 +8,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/logger" "math/big" "net/http" + "sort" ) func (p *Platform) RegisterRoutes(router gin.IRouter) { @@ -38,7 +39,7 @@ func (p *Platform) getTransactions(c *gin.Context) { } page := blockatlas.TxPage(txs) - page.Sort() + sort.Sort(page) c.JSON(http.StatusOK, &page) } From d0cf9fda22d55842a41b5ea18c513473a469f862 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sat, 15 Feb 2020 10:04:20 +0900 Subject: [PATCH 131/506] Add description and description to CoinInfo (#875) --- pkg/blockatlas/marketdata.go | 22 +++++++++------------- services/assets/info.go | 4 ++-- services/assets/info_test.go | 6 +++--- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/pkg/blockatlas/marketdata.go b/pkg/blockatlas/marketdata.go index bb16b86c5..7e6c14f5e 100644 --- a/pkg/blockatlas/marketdata.go +++ b/pkg/blockatlas/marketdata.go @@ -48,14 +48,15 @@ type ChartCoinInfo struct { } type CoinInfo struct { - Name string `json:"name,omitempty"` - Website string `json:"website,omitempty"` - SourceCode string `json:"source_code,omitempty"` - Whitepaper string `json:"whitepaper,omitempty"` - Explorers []Link `json:"explorers,omitempty"` - Socials []SocialLink `json:"socials,omitempty"` - Details []Detail `json:"details,omitempty"` - DataSource string `json:"data_source,omitempty"` + Name string `json:"name,omitempty"` + Website string `json:"website,omitempty"` + SourceCode string `json:"source_code,omitempty"` + WhitePaper string `json:"white_paper,omitempty"` + Description string `json:"description,omitempty"` + ShortDescription string `json:"short_description,omitempty"` + Explorers []Link `json:"explorers,omitempty"` + Socials []SocialLink `json:"socials,omitempty"` + DataSource string `json:"data_source,omitempty"` } type SocialLink struct { @@ -69,11 +70,6 @@ type Link struct { Url string `json:"url"` } -type Detail struct { - Language string `json:"language"` - Description string `json:"description"` -} - func (t *Ticker) SetCoinId(coinId uint) { t.Coin = coinId t.CoinName = "" diff --git a/services/assets/info.go b/services/assets/info.go index 416bed206..ca33c29fb 100644 --- a/services/assets/info.go +++ b/services/assets/info.go @@ -14,13 +14,13 @@ func GetCoinInfo(coinId int, token string) (info *blockatlas.CoinInfo, err error } url := getCoinInfoUrl(c, token) request := blockatlas.InitClient(url) - err = request.GetWithCache(&info, "info/info.json", nil, time.Hour*1) + err = request.GetWithCache(&info, "/info.json", nil, time.Hour*1) return } func getCoinInfoUrl(c coin.Coin, token string) string { if len(token) == 0 { - return AssetsURL + c.Handle + return AssetsURL + c.Handle + "/info" } return AssetsURL + c.Handle + "/assets/" + token } diff --git a/services/assets/info_test.go b/services/assets/info_test.go index 6b5e5f787..bc7a280b5 100644 --- a/services/assets/info_test.go +++ b/services/assets/info_test.go @@ -15,10 +15,10 @@ func Test_getCoinInfoUrl(t *testing.T) { args args want string }{ - {"test Ethereum coin", args{coin.Ethereum(), ""}, AssetsURL + coin.Ethereum().Handle}, + {"test Ethereum coin", args{coin.Ethereum(), ""}, AssetsURL + coin.Ethereum().Handle + "/info"}, {"test Ethereum token", args{coin.Ethereum(), "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, AssetsURL + coin.Ethereum().Handle + "/assets/" + "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, - {"test Binance coin", args{coin.Binance(), ""}, AssetsURL + coin.Binance().Handle}, - {"test Binance token", args{coin.Binance(), "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, AssetsURL + coin.Binance().Handle + "/assets/" + "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, + {"test Binance coin", args{coin.Binance(), ""}, AssetsURL + coin.Binance().Handle + "/info"}, + {"test Binance token", args{coin.Binance(), "BUSD-BD1"}, AssetsURL + coin.Binance().Handle + "/assets/" + "BUSD-BD1"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 225a495b552fa221bbba5983ebb461dc5af1ed4c Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 14 Feb 2020 18:19:21 -0700 Subject: [PATCH 132/506] Small changes with Readme and file cleanup (#877) * Update README.md * Remove useless files and add /scripts directory for future deployment scripts Co-authored-by: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> --- Makefile | 2 +- Procfile | 5 -- README.md | 4 +- app.json | 37 -------------- run_docker_compose.sh | 58 ---------------------- .goreleaser.yml => scripts/.goreleaser.yml | 0 6 files changed, 3 insertions(+), 103 deletions(-) delete mode 100644 Procfile delete mode 100644 app.json delete mode 100755 run_docker_compose.sh rename .goreleaser.yml => scripts/.goreleaser.yml (100%) diff --git a/Makefile b/Makefile index 4e1284e03..c33eea187 100644 --- a/Makefile +++ b/Makefile @@ -233,7 +233,7 @@ go-gen-docs: go-goreleaser: @echo " > Releasing a new version" - GOBIN=$(GOBIN) goreleaser --rm-dist + GOBIN=$(GOBIN) scripts/goreleaser --rm-dist go-vet: @echo " > Running go vet" diff --git a/Procfile b/Procfile deleted file mode 100644 index 4b7f58f1f..000000000 --- a/Procfile +++ /dev/null @@ -1,5 +0,0 @@ -platform_api: bin/platform_api -p $PORT -c config.yml -platform_observer: bin/platform_observer -c config.yml -observer_api: bin/observer_api -p $PORT -c config.yml -market_api: bin/market_api -p $PORT -c config.yml -market_observer: bin/market_observer -c config.yml diff --git a/README.md b/README.md index b608c53f1..df3859fa4 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ Then build: docker-compose build ``` -For run api, observer and markets: +Run all services: ```shell docker-compose up ``` @@ -134,7 +134,7 @@ docker-compose start platform_api # Run only observer for addresses and api for it docker-compose start platform_observer observer_api redis # Run markets with it's api -docker-compose start markets_observer markets_api redis +docker-compose start market_observer market_api redis # Run swagger api docker-compose start swagger_api ``` diff --git a/app.json b/app.json deleted file mode 100644 index 1cf7219a5..000000000 --- a/app.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "Block Atlas", - "description": "Block Atlas blockchain API by Trust Wallet", - "keywords": [ - "blockatlas", - "trustwallet" - ], - "website": "https://github.com/trustwallet/blockatlas", - "repository": "https://github.com/trustwallet/blockatlas", - "logo": "https://avatars0.githubusercontent.com/u/32179889", - "success_url": "/v1/", - "buildpacks": [ - { - "url": "heroku/go" - } - ], - "environments": { - "review": { - "addons": [ - "logentries:le_tryit" - ] - } - }, - "formation": { - "web": { - "quantity": 1, - "size": "Free" - }, - "observer": { - "quantity": 1, - "size": "Free" - }, - "scripts": { - }, - "stack": "heroku-18" - } -} diff --git a/run_docker_compose.sh b/run_docker_compose.sh deleted file mode 100755 index c58b5a447..000000000 --- a/run_docker_compose.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - -# https://github.com/jasperes/bash-yaml - -parse_yaml() { - local yaml_file=$1 - local prefix=$2 - local s - local w - local fs - - s='[[:space:]]*' - w='[a-zA-Z0-9_.-]*' - fs="$(echo @|tr @ '\034')" - - ( - sed -e '/- [^\“]'"[^\']"'.*: /s|\([ ]*\)- \([[:space:]]*\)|\1-\'$'\n'' \1\2|g' | - - sed -ne '/^--/s|--||g; s|\"|\\\"|g; s/[[:space:]]*$//g;' \ - -e "/#.*[\"\']/!s| #.*||g; /^#/s|#.*||g;" \ - -e "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \ - -e "s|^\($s\)\($w\)${s}[:-]$s\(.*\)$s\$|\1$fs\2$fs\3|p" | - - awk -F"$fs" '{ - indent = length($1)/2; - if (length($2) == 0) { conj[indent]="+";} else {conj[indent]="";} - vname[indent] = $2; - for (i in vname) {if (i > indent) {delete vname[i]}} - if (length($3) > 0) { - vn=""; for (i=0; i Date: Fri, 14 Feb 2020 22:27:12 -0300 Subject: [PATCH 133/506] Put back the FIO tests (#876) --- .../functional/testdata/query_fixtures.json | 3 ++- pkg/tests/integration/domains/domains.go | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pkg/tests/functional/testdata/query_fixtures.json b/pkg/tests/functional/testdata/query_fixtures.json index 0e73c21d2..6cf012ee2 100644 --- a/pkg/tests/functional/testdata/query_fixtures.json +++ b/pkg/tests/functional/testdata/query_fixtures.json @@ -11,7 +11,8 @@ "name=vitalik.luxe&coins=60", "name=ourxyzwallet.xyz&coins=60", "name=btc.zil&coins=313", - "name=btc.crypto&coins=313" + "name=btc.crypto&coins=313", + "name=adam@fiotestnet&coins=60" ], "/v1/market/charts": [ "currency=USD&time_start=1574483028&coin=60&token=0xdAC17F958D2ee523a2206206994597C13D831ec7", diff --git a/pkg/tests/integration/domains/domains.go b/pkg/tests/integration/domains/domains.go index 97cbe7ab4..7dcb3f1c8 100644 --- a/pkg/tests/integration/domains/domains.go +++ b/pkg/tests/integration/domains/domains.go @@ -71,15 +71,15 @@ func TestDomains(t *testing.T) { }, false, }, - //{ - // "test @fiotestnet domain", - // "adam@fiotestnet", - // []uint64{coin.ETH}, - // []blockatlas.Resolved{ - // {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, - // }, - // false, - //}, + { + "test @fiotestnet domain", + "adam@fiotestnet", + []uint64{coin.ETH}, + []blockatlas.Resolved{ + {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, + }, + false, + }, { "test batch .crypto domains", "dpantani.crypto", From feb4abda19f915bcf91f1f79bb8cc5579fd4b779 Mon Sep 17 00:00:00 2001 From: Derek Date: Sat, 15 Feb 2020 13:24:03 -0300 Subject: [PATCH 134/506] Minor: fixing small typos (#878) --- Makefile | 8 ++++---- README.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index c33eea187..0c5a5d7e3 100644 --- a/Makefile +++ b/Makefile @@ -158,7 +158,7 @@ endif ## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http//localhost newman: install-newman - @echo " > Runing $(test) tests" + @echo " > Running $(test) tests" ifeq (,$(host)) @echo " > Host parameter is missing. e.g: make newman test=staking host=http://localhost:8420" @exit 1 @@ -208,15 +208,15 @@ go-clean: GOBIN=$(GOBIN) go clean go-test: - @echo " > Runing unit tests" + @echo " > Running unit tests" GOBIN=$(GOBIN) go test -cover -race -v ./... go-functional: - @echo " > Runing functional tests" + @echo " > Running functional tests" GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=functional -v ./pkg/tests/functional go-integration: - @echo " > Runing integration tests" + @echo " > Running integration tests" GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./pkg/tests/integration go-fmt: diff --git a/README.md b/README.md index df3859fa4..63d01b3ac 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas go build -o platform-observer-bin cmd/platform_observer/main.go && ./platform-observer-bin -c config.yml # Start markets_observer with the path to the config.yml ./ -go build -o markets-observer-bin cmd/markets_observer/main.go && ./markets-observer-bin -c config.yml +go build -o market-observer-bin cmd/markets_observer/main.go && ./market-observer-bin -c config.yml # Start Platform API server at port 8420 with the path to the config.yml ./ go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 -c config.yml From 343103353d370a9ebe5c8db78fb47f9ea61ad566 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 17 Feb 2020 17:23:11 -0300 Subject: [PATCH 135/506] Remove sentry call from rpc method --- pkg/blockatlas/jsonrpc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/blockatlas/jsonrpc.go b/pkg/blockatlas/jsonrpc.go index 81f5e0618..bc01f3d0f 100644 --- a/pkg/blockatlas/jsonrpc.go +++ b/pkg/blockatlas/jsonrpc.go @@ -52,7 +52,7 @@ func (r *Request) RpcCall(result interface{}, method string, params interface{}) return errors.E("RPC Call error", errors.Params{ "method": method, "error_code": resp.Error.Code, - "error_message": resp.Error.Message}).PushToSentry() + "error_message": resp.Error.Message}) } return resp.GetObject(result) } From d95e2e76094e041d20cc47502d5e9fbd4114587f Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Mon, 17 Feb 2020 20:30:55 -0300 Subject: [PATCH 136/506] Fix date for pending NIMIQ txs (#884) --- platform/nimiq/transaction.go | 7 ++- platform/nimiq/transaction_test.go | 99 +++++++++++++++++++----------- 2 files changed, 70 insertions(+), 36 deletions(-) diff --git a/platform/nimiq/transaction.go b/platform/nimiq/transaction.go index dc220aa1b..3bfba60c6 100644 --- a/platform/nimiq/transaction.go +++ b/platform/nimiq/transaction.go @@ -3,6 +3,7 @@ package nimiq import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "time" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { @@ -15,7 +16,11 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { // NormalizeTx converts a Nimiq transaction into the generic model func NormalizeTx(srcTx *Tx) blockatlas.Tx { - date, _ := srcTx.Timestamp.Int64() + date, err := srcTx.Timestamp.Int64() + // Pending transaction doesn't have a timestamp, we gonna use the current time + if err != nil || len(srcTx.BlockHash) == 0 { + date = time.Now().Unix() + } return blockatlas.Tx{ ID: srcTx.Hash, Coin: coin.NIM, diff --git a/platform/nimiq/transaction_test.go b/platform/nimiq/transaction_test.go index 8699887b7..edbc3a44a 100644 --- a/platform/nimiq/transaction_test.go +++ b/platform/nimiq/transaction_test.go @@ -1,14 +1,16 @@ package nimiq import ( - "bytes" "encoding/json" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" + "time" ) -const basicSrc = ` +const ( + basicSrc = ` { "hash": "8b219949f4c1dfe9e7a9cdc5dbbc507e40dc16f44a1a5182ed6125c9a6891a50", "blockHash": "ab36a0909c6ed5761a984ef261d9c3456b7c1aea6a52d531c5bf2518526a32e6", @@ -26,44 +28,71 @@ const basicSrc = ` "flags": 0 } ` - -var basicDst = blockatlas.Tx{ - ID: "8b219949f4c1dfe9e7a9cdc5dbbc507e40dc16f44a1a5182ed6125c9a6891a50", - Coin: coin.NIM, - From: "NQ69 9A4A MB83 HXDQ 4J46 BH5R 4JFF QMA9 C3GN", - To: "NQ15 MLJN 23YB 8FBM 61TN 7LYG 2212 LVBG 4V19", - Fee: "138", - Date: 1538924505, - Block: 252575, - Meta: blockatlas.Transfer{ - Value: "10000000000000", - Symbol: "NIM", - Decimals: 5, - }, + pendingSrc = ` +{ + "data": null, + "fee": 300, + "flags": 0, + "from": "d48182276127b149a9710e78c436fb4bc1c4dc0b", + "fromAddress": "NQ74 SJ0Q 49T1 4XQL KABH 1RUC 8DPT 9F0U 9P0B", + "hash": "79719d16f3f347cc98c35cd7a9af708cdce97de578b5135c5ae4393fd7920d61", + "to": "0a17218ffdc42385f45329ba4089919236dd2743", + "toAddress": "NQ97 18BJ 33YV QGHQ BV2K 56V4 12CH J8TD S9S3", + "value": 100000 } +` +) -func TestNormalizeTx(t *testing.T) { - var srcTx Tx - err := json.Unmarshal([]byte(basicSrc), &srcTx) - if err != nil { - t.Error(err) - return +var ( + basicDst = blockatlas.Tx{ + ID: "8b219949f4c1dfe9e7a9cdc5dbbc507e40dc16f44a1a5182ed6125c9a6891a50", + Coin: coin.NIM, + From: "NQ69 9A4A MB83 HXDQ 4J46 BH5R 4JFF QMA9 C3GN", + To: "NQ15 MLJN 23YB 8FBM 61TN 7LYG 2212 LVBG 4V19", + Fee: "138", + Date: 1538924505, + Block: 252575, + Meta: blockatlas.Transfer{ + Value: "10000000000000", + Symbol: "NIM", + Decimals: 5, + }, } - - tx := NormalizeTx(&srcTx) - resJSON, err := json.Marshal(&tx) - if err != nil { - t.Fatal(err) + pendingDst = blockatlas.Tx{ + ID: "79719d16f3f347cc98c35cd7a9af708cdce97de578b5135c5ae4393fd7920d61", + Coin: coin.NIM, + From: "NQ74 SJ0Q 49T1 4XQL KABH 1RUC 8DPT 9F0U 9P0B", + To: "NQ97 18BJ 33YV QGHQ BV2K 56V4 12CH J8TD S9S3", + Fee: "300", + Date: time.Now().Unix(), + Block: 0, + Meta: blockatlas.Transfer{ + Value: "100000", + Symbol: "NIM", + Decimals: 5, + }, } +) - dstJSON, err := json.Marshal(&basicDst) - if err != nil { - t.Fatal(err) +func TestNormalizeTx1(t *testing.T) { + tests := []struct { + name string + srcTx string + want blockatlas.Tx + }{ + {"test transaction", basicSrc, basicDst}, + {"test pending transaction", pendingSrc, pendingDst}, } - - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error("basic: tx don't equal") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx Tx + err := json.Unmarshal([]byte(tt.srcTx), &srcTx) + if err != nil { + t.Error(err) + return + } + got := NormalizeTx(&srcTx) + assert.Equal(t, tt.want, got) + }) } } From c73689113641dea163abb4781ca98428ac0a6946 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Tue, 18 Feb 2020 14:30:50 -0300 Subject: [PATCH 137/506] fix Zilliqa block request and data race (#883) * fix zilliqa block request and data race * Ignore 'TxBlock has no transactions' error * Avoid only the empty tx error --- platform/zilliqa/block.go | 2 +- platform/zilliqa/model.go | 20 ++++++++++ platform/zilliqa/model_test.go | 22 +++++++++++ platform/zilliqa/rpc.go | 70 ++++++++++++++++++++++------------ 4 files changed, 89 insertions(+), 25 deletions(-) diff --git a/platform/zilliqa/block.go b/platform/zilliqa/block.go index dbfb6c2c3..4180c65d1 100644 --- a/platform/zilliqa/block.go +++ b/platform/zilliqa/block.go @@ -30,10 +30,10 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { tx := Normalize(&srcTx) normalized = append(normalized, tx) } + block := blockatlas.Block{ Number: num, Txs: normalized, } - return &block, nil } diff --git a/platform/zilliqa/model.go b/platform/zilliqa/model.go index f4ab3a1e9..77f2357ba 100644 --- a/platform/zilliqa/model.go +++ b/platform/zilliqa/model.go @@ -2,10 +2,23 @@ package zilliqa import ( "encoding/hex" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "math/big" "strconv" ) +type BlockTxs [][]string + +func (b BlockTxs) txs() []string { + txs := make([]string, 0) + for _, ids := range b { + for _, id := range ids { + txs = append(txs, id) + } + } + return txs +} + type Tx struct { Hash string `json:"hash"` BlockHeight uint64 `json:"blockHeight"` @@ -75,3 +88,10 @@ func (t *TxRPC) toTx() Tx { } return tx } + +type BlockTxRpc struct { + JsonRpc string `json:"jsonrpc"` + Error *blockatlas.RpcError `json:"error,omitempty"` + Result BlockTxs `json:"result,omitempty"` + Id string `json:"id,omitempty"` +} diff --git a/platform/zilliqa/model_test.go b/platform/zilliqa/model_test.go index 117819761..737894ce7 100644 --- a/platform/zilliqa/model_test.go +++ b/platform/zilliqa/model_test.go @@ -70,3 +70,25 @@ func TestTx_NonceValue(t *testing.T) { }) } } + +func TestBlockTxs_txs(t *testing.T) { + tests := []struct { + name string + b BlockTxs + want []string + }{ + {"test 1 tx", BlockTxs{{"tx1"}, {}}, []string{"tx1"}}, + {"test 2 txs 1", BlockTxs{{"tx1"}, {"tx2"}}, []string{"tx1", "tx2"}}, + {"test 2 txs 2", BlockTxs{{"tx1", "tx2"}}, []string{"tx1", "tx2"}}, + {"test 3 txs 1", BlockTxs{{"tx1", "tx2"}, {"tx3"}}, []string{"tx1", "tx2", "tx3"}}, + {"test 3 txs 2", BlockTxs{{"tx1"}, {"tx2"}, {"tx3"}}, []string{"tx1", "tx2", "tx3"}}, + {"test 4 txs", BlockTxs{{"tx1", "tx2"}, {"tx3"}, {"tx4"}}, []string{"tx1", "tx2", "tx3", "tx4"}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.b.txs(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("txs() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/platform/zilliqa/rpc.go b/platform/zilliqa/rpc.go index d64a468e2..966dc96e7 100644 --- a/platform/zilliqa/rpc.go +++ b/platform/zilliqa/rpc.go @@ -2,6 +2,7 @@ package zilliqa import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" "strconv" "sync" ) @@ -15,37 +16,58 @@ func (c *RpcClient) GetBlockchainInfo() (info *ChainInfo, err error) { return } -func (c *RpcClient) GetTx(hash string) (tx Tx, err error) { +func (c *RpcClient) GetTx(hash string) (tx TxRPC, err error) { err = c.RpcCall(&tx, "GetTransaction", []string{hash}) return } -func (c *RpcClient) GetTxInBlock(number int64) (txs []Tx, err error) { - strNumber := strconv.FormatInt(number, 10) - var results [][]string - err = c.RpcCall(&results, "GetTransactionsForTxBlock", []string{strNumber}) +func (c *RpcClient) GetBlockByNumber(number int64) ([]string, error) { + strNumber := strconv.Itoa(int(number)) + req := &blockatlas.RpcRequest{ + JsonRpc: blockatlas.JsonRpcVersion, + Method: "GetTransactionsForTxBlock", + Params: []string{strNumber}, + Id: "GetTransactionsForTxBlock_" + strNumber, + } + var resp *BlockTxRpc + err := c.Post(&resp, "", req) + if err != nil { + return nil, err + } + if resp.Error != nil && resp.Error.Code != -1 { + return nil, errors.E("RPC Call error", errors.Params{ + "method": "GetTransactionsForTxBlock", + "error_code": resp.Error.Code, + "error_message": resp.Error.Message}) + } + return resp.Result.txs(), nil +} + +func (c *RpcClient) GetTxInBlock(number int64) ([]Tx, error) { + txs := make([]Tx, 0) + hashes, err := c.GetBlockByNumber(number) + if err != nil { + return txs, err + } var wg sync.WaitGroup - out := make(chan Tx) - for _, ids := range results { - for _, id := range ids { - wg.Add(1) - go func(id string) { - defer wg.Done() - tx, errTx := c.GetTx(id) - if errTx != nil { - return - } - out <- tx - }(id) - } + out := make(chan Tx, len(hashes)) + wg.Add(len(hashes)) + for _, id := range hashes { + go func(hash string, txChan chan Tx, wg *sync.WaitGroup) { + defer wg.Done() + tx, errTx := c.GetTx(hash) + if errTx != nil { + return + } + txChan <- tx.toTx() + }(id, out, &wg) } - go func() { - for tx := range out { - txs = append(txs, tx) - } - }() wg.Wait() close(out) - return + + for tx := range out { + txs = append(txs, tx) + } + return txs, nil } From f5c745994f445c236450e434f22991046e0bbfd9 Mon Sep 17 00:00:00 2001 From: Mykola Date: Tue, 18 Feb 2020 19:32:54 -0800 Subject: [PATCH 138/506] Fix typo [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 63d01b3ac..edef03442 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas go build -o platform-observer-bin cmd/platform_observer/main.go && ./platform-observer-bin -c config.yml # Start markets_observer with the path to the config.yml ./ -go build -o market-observer-bin cmd/markets_observer/main.go && ./market-observer-bin -c config.yml +go build -o market-observer-bin cmd/market_observer/main.go && ./market-observer-bin -c config.yml # Start Platform API server at port 8420 with the path to the config.yml ./ go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 -c config.yml From ff31205bd5a129277b9d9e48d6ce97e83359373e Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 19 Feb 2020 01:07:07 -0300 Subject: [PATCH 139/506] Add support for rpc batch call (#891) --- pkg/blockatlas/jsonrpc.go | 19 +++++++++++++++++++ pkg/blockatlas/jsonrpc_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 pkg/blockatlas/jsonrpc_test.go diff --git a/pkg/blockatlas/jsonrpc.go b/pkg/blockatlas/jsonrpc.go index bc01f3d0f..e250fbd28 100644 --- a/pkg/blockatlas/jsonrpc.go +++ b/pkg/blockatlas/jsonrpc.go @@ -9,6 +9,8 @@ const ( JsonRpcVersion = "2.0" ) +type RpcRequests []*RpcRequest + type RpcRequest struct { JsonRpc string `json:"jsonrpc"` Method string `json:"method"` @@ -56,3 +58,20 @@ func (r *Request) RpcCall(result interface{}, method string, params interface{}) } return resp.GetObject(result) } + +func (r *Request) RpcBatchCall(requests RpcRequests) ([]RpcResponse, error) { + var resp []RpcResponse + err := r.Post(&resp, "", requests.fillDefaultValues()) + if err != nil { + return nil, err + } + return resp, nil +} + +func (rs RpcRequests) fillDefaultValues() RpcRequests { + for _, r := range rs { + r.JsonRpc = JsonRpcVersion + r.Id = r.Method + } + return rs +} diff --git a/pkg/blockatlas/jsonrpc_test.go b/pkg/blockatlas/jsonrpc_test.go new file mode 100644 index 000000000..b95417565 --- /dev/null +++ b/pkg/blockatlas/jsonrpc_test.go @@ -0,0 +1,34 @@ +package blockatlas + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestRpcRequests_fillDefaultValues(t *testing.T) { + tests := []struct { + name string + rs RpcRequests + want RpcRequests + }{ + { + "test 1", + RpcRequests{{Method: "method1", Params: "params1"}}, + RpcRequests{{Method: "method1", Params: "params1", JsonRpc: JsonRpcVersion, Id: "method1"}}, + }, { + "test 2", + RpcRequests{ + {Method: "method1", Params: "params1"}, {Method: "method2", Params: "params2"}}, + RpcRequests{ + {Method: "method1", Params: "params1", JsonRpc: JsonRpcVersion, Id: "method1"}, + {Method: "method2", Params: "params2", JsonRpc: JsonRpcVersion, Id: "method2"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.rs.fillDefaultValues() + assert.Equal(t, tt.want, got) + }) + } +} From 012ffb68247a9bc39a40ffaf0d235c179cb1c53a Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 19 Feb 2020 14:36:38 -0300 Subject: [PATCH 140/506] Add rpc batch call for zilliqa (#892) --- platform/zilliqa/rpc.go | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/platform/zilliqa/rpc.go b/platform/zilliqa/rpc.go index 966dc96e7..8f6dff965 100644 --- a/platform/zilliqa/rpc.go +++ b/platform/zilliqa/rpc.go @@ -1,10 +1,10 @@ package zilliqa import ( + "github.com/mitchellh/mapstructure" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "strconv" - "sync" ) type RpcClient struct { @@ -46,28 +46,27 @@ func (c *RpcClient) GetBlockByNumber(number int64) ([]string, error) { func (c *RpcClient) GetTxInBlock(number int64) ([]Tx, error) { txs := make([]Tx, 0) hashes, err := c.GetBlockByNumber(number) - if err != nil { + if err != nil || len(hashes) == 0 { return txs, err } - var wg sync.WaitGroup - out := make(chan Tx, len(hashes)) - wg.Add(len(hashes)) - for _, id := range hashes { - go func(hash string, txChan chan Tx, wg *sync.WaitGroup) { - defer wg.Done() - tx, errTx := c.GetTx(hash) - if errTx != nil { - return - } - txChan <- tx.toTx() - }(id, out, &wg) + var requests blockatlas.RpcRequests + for _, hashe := range hashes { + requests = append(requests, &blockatlas.RpcRequest{ + Method: "GetTransaction", + Params: []string{hashe}, + }) } - wg.Wait() - close(out) - - for tx := range out { - txs = append(txs, tx) + responses, err := c.RpcBatchCall(requests) + if err != nil { + return nil, err + } + for _, result := range responses { + var txRPC TxRPC + if mapstructure.Decode(result.Result, &txRPC) != nil { + continue + } + txs = append(txs, txRPC.toTx()) } return txs, nil } From d12218b93a51a42bdc533525a0cc1fae6cbd28c5 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 19 Feb 2020 14:39:25 -0300 Subject: [PATCH 141/506] Remove GET ticker route (#888) --- api/maketdata.go | 45 ------------------------------- docs/docs.go | 69 +++++------------------------------------------ docs/swagger.json | 67 +++++---------------------------------------- docs/swagger.yaml | 47 ++++---------------------------- 4 files changed, 18 insertions(+), 210 deletions(-) diff --git a/api/maketdata.go b/api/maketdata.go index d8633e8f5..ae8051e7e 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -36,57 +36,12 @@ type Coin struct { func SetupMarketAPI(router gin.IRouter, db storage.Market) { router.Use(ginutils.TokenAuthMiddleware(viper.GetString("market.auth"))) // Ticker - router.GET("/ticker", getTickerHandler(db)) router.POST("/ticker", getTickersHandler(db)) // Charts router.GET("/charts", gincache.CacheMiddleware(time.Minute*5, getChartsHandler())) router.GET("/info", getCoinInfoHandler()) } -// @Summary Get ticker value for a specific market -// @Id get_ticker -// @Description Get the ticker value from an market and coin/token -// @Accept json -// @Produce json -// @Tags Market -// @Param coin query int true "coin id" -// @Param token query string false "token id" -// @Param currency query string false "the currency to show the quote" default(USD) -// @Success 200 {object} blockatlas.Ticker -// @Router /v1/market/ticker [get] -func getTickerHandler(storage storage.Market) func(c *gin.Context) { - if storage == nil { - return nil - } - return func(c *gin.Context) { - coinQuery := c.Query("coin") - coinId, err := strconv.Atoi(coinQuery) - if err != nil { - ginutils.RenderError(c, http.StatusBadRequest, "Invalid coin") - return - } - token := strings.ToUpper(c.Query("token")) - - currency := c.DefaultQuery("currency", blockatlas.DefaultCurrency) - rate, err := storage.GetRate(strings.ToUpper(currency)) - if err != nil { - logger.Error(err, "Failed to retrieve currency", logger.Params{"coin": coinId, "currency": currency}) - ginutils.RenderError(c, http.StatusInternalServerError, "Failed to retrieve currency") - return - } - - symbol := coin.Coins[uint(coinId)].Symbol - result, err := storage.GetTicker(symbol, token) - if err != nil { - logger.Error(err, "Failed to retrieve ticker", logger.Params{"coin": coinId, "currency": currency}) - ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) - return - } - result.ApplyRate(currency, rate.Rate, rate.PercentChange24h) - ginutils.RenderSuccess(c, result) - } -} - // @Summary Get ticker values for a specific market // @Id get_tickers // @Description Get the ticker values from many market and coin/token diff --git a/docs/docs.go b/docs/docs.go index e52d2c064..a64b11e20 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-14 14:10:03.328765 -0700 MST m=+0.094246342 +// 2020-02-18 21:29:30.368853 -0300 -03 m=+0.159220320 package docs @@ -301,50 +301,6 @@ var doc = `{ } }, "/v1/market/ticker": { - "get": { - "description": "Get the ticker value from an market and coin/token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get ticker value for a specific market", - "operationId": "get_ticker", - "parameters": [ - { - "type": "integer", - "description": "coin id", - "name": "coin", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "token id", - "name": "token", - "in": "query" - }, - { - "type": "string", - "default": "USD", - "description": "the currency to show the quote", - "name": "currency", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.Ticker" - } - } - } - }, "post": { "description": "Get the ticker values from many market and coin/token", "consumes": [ @@ -1141,11 +1097,8 @@ var doc = `{ "data_source": { "type": "string" }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Detail" - } + "description": { + "type": "string" }, "explorers": { "type": "array", @@ -1156,6 +1109,9 @@ var doc = `{ "name": { "type": "string" }, + "short_description": { + "type": "string" + }, "socials": { "type": "array", "items": { @@ -1168,7 +1124,7 @@ var doc = `{ "website": { "type": "string" }, - "whitepaper": { + "white_paper": { "type": "string" } } @@ -1287,17 +1243,6 @@ var doc = `{ "$ref": "#/definitions/blockatlas.Delegation" } }, - "blockatlas.Detail": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "language": { - "type": "string" - } - } - }, "blockatlas.DocsResponse": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index fce62e6b0..983255744 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -280,50 +280,6 @@ } }, "/v1/market/ticker": { - "get": { - "description": "Get the ticker value from an market and coin/token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get ticker value for a specific market", - "operationId": "get_ticker", - "parameters": [ - { - "type": "integer", - "description": "coin id", - "name": "coin", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "token id", - "name": "token", - "in": "query" - }, - { - "type": "string", - "default": "USD", - "description": "the currency to show the quote", - "name": "currency", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.Ticker" - } - } - } - }, "post": { "description": "Get the ticker values from many market and coin/token", "consumes": [ @@ -1120,11 +1076,8 @@ "data_source": { "type": "string" }, - "details": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Detail" - } + "description": { + "type": "string" }, "explorers": { "type": "array", @@ -1135,6 +1088,9 @@ "name": { "type": "string" }, + "short_description": { + "type": "string" + }, "socials": { "type": "array", "items": { @@ -1147,7 +1103,7 @@ "website": { "type": "string" }, - "whitepaper": { + "white_paper": { "type": "string" } } @@ -1266,17 +1222,6 @@ "$ref": "#/definitions/blockatlas.Delegation" } }, - "blockatlas.Detail": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "language": { - "type": "string" - } - } - }, "blockatlas.DocsResponse": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 660b54e0b..be121c2ee 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -62,16 +62,16 @@ definitions: properties: data_source: type: string - details: - items: - $ref: '#/definitions/blockatlas.Detail' - type: array + description: + type: string explorers: items: $ref: '#/definitions/blockatlas.Link' type: array name: type: string + short_description: + type: string socials: items: $ref: '#/definitions/blockatlas.SocialLink' @@ -80,7 +80,7 @@ definitions: type: string website: type: string - whitepaper: + white_paper: type: string type: object blockatlas.CoinStatus: @@ -159,13 +159,6 @@ definitions: items: $ref: '#/definitions/blockatlas.Delegation' type: array - blockatlas.Detail: - properties: - description: - type: string - language: - type: string - type: object blockatlas.DocsResponse: properties: docs: @@ -623,36 +616,6 @@ paths: tags: - Market /v1/market/ticker: - get: - consumes: - - application/json - description: Get the ticker value from an market and coin/token - operationId: get_ticker - parameters: - - description: coin id - in: query - name: coin - required: true - type: integer - - description: token id - in: query - name: token - type: string - - default: USD - description: the currency to show the quote - in: query - name: currency - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.Ticker' - summary: Get ticker value for a specific market - tags: - - Market post: consumes: - application/json From 584bb9297efbfc69be5dcc363fdd2422f5704eba Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 19 Feb 2020 14:40:23 -0300 Subject: [PATCH 142/506] Set Max and Min block time for observer (#881) * Fix observer blocktime and set maximum * Update config file * Fix signature names * Create getInterval method * Change method signature * Use max and min function * Create external method to get interval --- cmd/platform_observer/main.go | 16 +++++------- config.yml | 6 +++-- observer/observer.go | 9 +++++++ observer/observer_test.go | 48 +++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 11 deletions(-) diff --git a/cmd/platform_observer/main.go b/cmd/platform_observer/main.go index 1466238e4..f97ade887 100644 --- a/cmd/platform_observer/main.go +++ b/cmd/platform_observer/main.go @@ -9,7 +9,6 @@ import ( "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/storage" "sync" - "time" ) const ( @@ -32,20 +31,19 @@ func main() { logger.Fatal("No APIs to observe") } - minInterval := viper.GetDuration("observer.min_poll") backlogTime := viper.GetDuration("observer.backlog") + minInterval := viper.GetDuration("observer.block_poll.min") + maxInterval := viper.GetDuration("observer.block_poll.max") + if minInterval >= maxInterval { + logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") + } var wg sync.WaitGroup wg.Add(len(platform.BlockAPIs)) for _, api := range platform.BlockAPIs { coin := api.Coin() - blockTime := time.Duration(coin.BlockTime) * time.Millisecond - pollInterval := blockTime / 4 - - if pollInterval < minInterval { - pollInterval = minInterval - } + pollInterval := observer.GetInterval(coin.BlockTime, minInterval, maxInterval) // Stream incoming blocks var backlogCount int @@ -53,7 +51,7 @@ func main() { backlogCount = 50 logger.Warn("Unknown block time", logger.Params{"coin": coin.ID}) } else { - backlogCount = int(backlogTime / blockTime) + backlogCount = int(backlogTime / pollInterval) } stream := observer.Stream{ diff --git a/config.yml b/config.yml index 39a70f80a..05d5e8c12 100644 --- a/config.yml +++ b/config.yml @@ -21,14 +21,16 @@ observer: auth: test # Redis Subscription Database redis: redis://redis:6379 - # Smallest possible block polling interval - min_poll: 250ms # Don't request blocks older than this backlog: 3h # Don't request more than N blocks at once backlog_max_blocks: 200 # Max connections to open to API stream_conns: 16 + # Block polling interval + block_poll: + min: 3s + max: 30s # The market watcher market: diff --git a/observer/observer.go b/observer/observer.go index 4c6956d86..a9b076e3d 100644 --- a/observer/observer.go +++ b/observer/observer.go @@ -4,8 +4,10 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/blockatlas/platform/bitcoin" "github.com/trustwallet/blockatlas/storage" + "time" ) type Event struct { @@ -106,3 +108,10 @@ func inferUtxoValue(tx *blockatlas.Tx, address string, coinIndex uint) { } } } + +func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duration { + interval := time.Duration(value) * time.Millisecond + pMin := numbers.Max(minInterval.Nanoseconds(), interval.Nanoseconds()) + pMax := numbers.Min(int(maxInterval.Nanoseconds()), int(pMin)) + return time.Duration(pMax) +} diff --git a/observer/observer_test.go b/observer/observer_test.go index bc0f9f247..c01027a8f 100644 --- a/observer/observer_test.go +++ b/observer/observer_test.go @@ -5,6 +5,7 @@ import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" + "time" ) var transferDst1 = blockatlas.Tx{ @@ -247,3 +248,50 @@ func Test_inferUtxoValue(t *testing.T) { }) } } + +func TestGetInterval(t *testing.T) { + min, _ := time.ParseDuration("2s") + max, _ := time.ParseDuration("30s") + type args struct { + blockTime int + minInterval time.Duration + maxInterval time.Duration + } + tests := []struct { + name string + args args + want time.Duration + }{ + { + "test minimum", + args{ + blockTime: 100, + minInterval: min, + maxInterval: max, + }, + min, + }, { + "test maximum", + args{ + blockTime: 600000, + minInterval: min, + maxInterval: max, + }, + max, + }, { + "test right blocktime", + args{ + blockTime: 5000, + minInterval: min, + maxInterval: max, + }, + 5000 * time.Millisecond, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := GetInterval(tt.args.blockTime, tt.args.minInterval, tt.args.maxInterval) + assert.EqualValues(t, tt.want, got) + }) + } +} From 6972a06257a204394f2706d1d9c9aa8be13b994a Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 19 Feb 2020 15:09:59 -0300 Subject: [PATCH 143/506] Fix CoinGecko Market route (#894) --- market/clients/coingecko/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/market/clients/coingecko/client.go b/market/clients/coingecko/client.go index 5d71bee85..d8774fc05 100644 --- a/market/clients/coingecko/client.go +++ b/market/clients/coingecko/client.go @@ -48,7 +48,7 @@ func (c *Client) FetchLatestRates(coins GeckoCoins, currency string) (prices Coi } var cp CoinPrices - err := c.Get(&cp, "v3/coins/market", values) + err := c.Get(&cp, "v3/coins/markets", values) if err != nil { logger.Error(err) return From 16cfcce40b85678865d167097546cf4de9d96fb3 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 19 Feb 2020 19:27:40 -0300 Subject: [PATCH 144/506] Fix typo for Zilliqa Block API --- platform/zilliqa/rpc.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/zilliqa/rpc.go b/platform/zilliqa/rpc.go index 8f6dff965..ad86a2941 100644 --- a/platform/zilliqa/rpc.go +++ b/platform/zilliqa/rpc.go @@ -51,10 +51,10 @@ func (c *RpcClient) GetTxInBlock(number int64) ([]Tx, error) { } var requests blockatlas.RpcRequests - for _, hashe := range hashes { + for _, hash := range hashes { requests = append(requests, &blockatlas.RpcRequest{ Method: "GetTransaction", - Params: []string{hashe}, + Params: []string{hash}, }) } responses, err := c.RpcBatchCall(requests) From aecceff1fc29ad0289f592976472600098ee4504 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 19 Feb 2020 19:41:09 -0300 Subject: [PATCH 145/506] Add config object to access env vars easier (#882) * Add config file to access env vars easier * Remove unused env var * Fix signatures pattern * Add block_pool struct for configuration * Use old values for config.yml --- api/handlers.go | 4 +- api/maketdata.go | 4 +- api/observer.go | 4 +- cmd/market_api/main.go | 4 +- cmd/observer_api/main.go | 4 +- cmd/platform_api/main.go | 7 +- cmd/platform_observer/main.go | 11 ++- cmd/swagger_api/main.go | 4 +- config.yml | 2 - config/config.go | 39 ---------- config/configuration.go | 92 +++++++++++++++++++++++ internal/init.go | 4 +- market/charts.go | 10 +-- market/market.go | 22 +++--- market/rates.go | 24 +++--- observer/stream.go | 6 +- pkg/ginutils/reverse_proxy.go | 4 +- pkg/tests/functional/functional_test.go | 7 +- pkg/tests/integration/integration_test.go | 3 +- 19 files changed, 150 insertions(+), 105 deletions(-) delete mode 100644 config/config.go create mode 100755 config/configuration.go diff --git a/api/handlers.go b/api/handlers.go index 322b21841..6b96ddca5 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -4,7 +4,7 @@ import ( "github.com/chenjiandongx/ginprom" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/metrics" @@ -271,7 +271,7 @@ func makeTokenRoute(router gin.IRouter, api blockatlas.Platform) { func MakeMetricsRoute(router gin.IRouter) { router.Use(metrics.PromMiddleware()) m := router.Group("/metrics") - m.Use(ginutils.TokenAuthMiddleware(viper.GetString("metrics.api_token"))) + m.Use(ginutils.TokenAuthMiddleware(config.Configuration.Metrics.APIToken)) m.GET("/", ginprom.PromHandler(promhttp.Handler())) } diff --git a/api/maketdata.go b/api/maketdata.go index ae8051e7e..aa75953de 100644 --- a/api/maketdata.go +++ b/api/maketdata.go @@ -2,8 +2,8 @@ package api import ( "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/market" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -34,7 +34,7 @@ type Coin struct { } func SetupMarketAPI(router gin.IRouter, db storage.Market) { - router.Use(ginutils.TokenAuthMiddleware(viper.GetString("market.auth"))) + router.Use(ginutils.TokenAuthMiddleware(config.Configuration.Market.Auth)) // Ticker router.POST("/ticker", getTickersHandler(db)) // Charts diff --git a/api/observer.go b/api/observer.go index 4a9fc8477..ca6b22cb7 100644 --- a/api/observer.go +++ b/api/observer.go @@ -2,7 +2,7 @@ package api import ( "github.com/gin-gonic/gin" - "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/platform" @@ -10,7 +10,7 @@ import ( ) func SetupObserverAPI(router gin.IRouter, db *storage.Storage) { - router.Use(ginutils.TokenAuthMiddleware(viper.GetString("observer.auth"))) + router.Use(ginutils.TokenAuthMiddleware(config.Configuration.Observer.Auth)) router.POST("/webhook/register", addCall(db)) router.DELETE("/webhook/register", deleteCall(db)) router.GET("/status", statusCall(db)) diff --git a/cmd/market_api/main.go b/cmd/market_api/main.go index 14017cdfa..fbe183b8a 100644 --- a/cmd/market_api/main.go +++ b/cmd/market_api/main.go @@ -2,8 +2,8 @@ package main import ( "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -27,7 +27,7 @@ func init() { } func main() { - gin.SetMode(viper.GetString("gin.mode")) + gin.SetMode(config.Configuration.Gin.Mode) engine := gin.New() engine.Use(ginutils.CheckReverseProxy, *sg) diff --git a/cmd/observer_api/main.go b/cmd/observer_api/main.go index 72e9c67af..dbaaf3f85 100644 --- a/cmd/observer_api/main.go +++ b/cmd/observer_api/main.go @@ -2,8 +2,8 @@ package main import ( "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -27,7 +27,7 @@ func init() { } func main() { - gin.SetMode(viper.GetString("gin.mode")) + gin.SetMode(config.Configuration.Gin.Mode) engine := gin.New() engine.Use(ginutils.CheckReverseProxy, *sg) diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index 4cb9b79da..73873e4cc 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -2,8 +2,8 @@ package main import ( "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -23,12 +23,11 @@ var ( func init() { port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) - chosenPlatform = viper.GetString("platform") - platform.Init(chosenPlatform) + platform.Init(config.Configuration.Platform) } func main() { - gin.SetMode(viper.GetString("gin.mode")) + gin.SetMode(config.Configuration.Gin.Mode) engine := gin.New() engine.Use(ginutils.CheckReverseProxy, *sg) engine.Use(ginutils.CORSMiddleware()) diff --git a/cmd/platform_observer/main.go b/cmd/platform_observer/main.go index f97ade887..3ec4f8f60 100644 --- a/cmd/platform_observer/main.go +++ b/cmd/platform_observer/main.go @@ -2,7 +2,7 @@ package main import ( "context" - "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/observer" "github.com/trustwallet/blockatlas/pkg/logger" @@ -22,8 +22,7 @@ var ( func init() { _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) - - platform.Init(viper.GetString("platform")) + platform.Init(config.Configuration.Platform) } func main() { @@ -31,9 +30,9 @@ func main() { logger.Fatal("No APIs to observe") } - backlogTime := viper.GetDuration("observer.backlog") - minInterval := viper.GetDuration("observer.block_poll.min") - maxInterval := viper.GetDuration("observer.block_poll.max") + backlogTime := config.Configuration.Observer.Backlog + minInterval := config.Configuration.Observer.BlockPoll.Min + maxInterval := config.Configuration.Observer.BlockPoll.Max if minInterval >= maxInterval { logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") } diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go index 644ee8da7..d3f23596f 100644 --- a/cmd/swagger_api/main.go +++ b/cmd/swagger_api/main.go @@ -2,10 +2,10 @@ package main import ( "github.com/gin-gonic/gin" - "github.com/spf13/viper" ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -27,7 +27,7 @@ func init() { } func main() { - gin.SetMode(viper.GetString("gin.mode")) + gin.SetMode(config.Configuration.Gin.Mode) engine := gin.New() engine.Use(ginutils.CheckReverseProxy, *sg) diff --git a/config.yml b/config.yml index 05d5e8c12..d9986de23 100644 --- a/config.yml +++ b/config.yml @@ -19,8 +19,6 @@ observer: enabled: false # TODO : Add description auth: test - # Redis Subscription Database - redis: redis://redis:6379 # Don't request blocks older than this backlog: 3h # Don't request more than N blocks at once diff --git a/config/config.go b/config/config.go deleted file mode 100644 index 56c11e623..000000000 --- a/config/config.go +++ /dev/null @@ -1,39 +0,0 @@ -package config - -import ( - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/pkg/logger" - "strings" -) - -func LoadConfig(confPath string) { - // Load config from environment - viper.SetEnvPrefix("atlas") // will be uppercased automatically => ATLAS - viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) - viper.AutomaticEnv() - - viper.AddConfigPath(".") - viper.SetConfigName("config") - viper.SetConfigType("yml") - - // Load config file - if confPath == "" { - if err := viper.ReadInConfig(); err != nil { - if _, ok := err.(viper.ConfigFileNotFoundError); ok { - logger.Info("Config file was not supplied") - } else { - logger.Fatal("Issue reading config", err) - } - } - logger.Info("Viper config", logger.Params{"config_file": viper.ConfigFileUsed()}) - } else { - viper.SetConfigFile(confPath) - err := viper.ReadInConfig() - if err != nil { - logger.Error("Failed to read config", err, - logger.Params{"config_file": confPath}) - } else { - logger.Info("Using config file", logger.Params{"config_file": confPath}) - } - } -} diff --git a/config/configuration.go b/config/configuration.go new file mode 100755 index 000000000..4c9f836ff --- /dev/null +++ b/config/configuration.go @@ -0,0 +1,92 @@ +package config + +import ( + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/pkg/logger" + "strings" + "time" +) + +type configuration struct { + Gin struct { + Mode string + ReverseProxy bool `mapstructure:"reverse_proxy"` + } + Platform string + Metrics struct { + APIToken string `mapstructure:"api_token"` + } + Sentry struct { + Dsn string + } + Observer struct { + Enabled bool + Auth string + Backlog time.Duration + BacklogMaxBlocks int64 `mapstructure:"backlog_max_blocks"` + StreamConns int `mapstructure:"stream_conns"` + BlockPoll struct { + Min time.Duration + Max time.Duration + } `mapstructure:"block_poll"` + } + Market struct { + Enabled bool + Auth string + QuoteUpdateTime string `mapstructure:"quote_update_time"` + RateUpdateTime string `mapstructure:"rate_update_time"` + Dex struct { + QuoteUpdateTime string `mapstructure:"quote_update_time"` + API string + } + Cmc struct { + API string + WebAPI string + WidgetAPI string + APIKey string `mapstructure:"api_key"` + MapURL string `mapstructure:"map_url"` + } + Fixer struct { + API string + APIKey string `mapstructure:"api_key"` + RateUpdateTime string `mapstructure:"rate_update_time"` + } + Compound struct { + API string + } + Coingecko struct { + API string + } + } + Storage struct { + Redis string + } +} + +var Configuration configuration + +// LoadConfig reads in config file and ENV variables if set. +func LoadConfig(confPath string) { + viper.SetEnvPrefix("atlas") // will be uppercased automatically => ATLAS + viper.AutomaticEnv() // read in environment variables that match + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.AddConfigPath(".") + viper.SetConfigName("config") + viper.SetConfigType("yml") + + // Load config file + if len(confPath) > 0 { + viper.SetConfigFile(confPath) + } else { + confPath = viper.ConfigFileUsed() + } + err := viper.ReadInConfig() + if err != nil { + logger.Info("Failed to read config", err, logger.Params{"config_file": confPath}) + } + logger.Info("Using config file", logger.Params{"config_file": confPath}) + + if err := viper.Unmarshal(&Configuration); err != nil { + logger.Error(err, "Error Unmarshal Viper Config File") + } +} diff --git a/internal/init.go b/internal/init.go index f2d3c0616..6b9ca41be 100644 --- a/internal/init.go +++ b/internal/init.go @@ -4,7 +4,6 @@ import ( "flag" sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" @@ -56,8 +55,7 @@ func InitAPIWithRedis(defaultPort, defaultConfigPath string) (string, string, *g config.LoadConfig(confPath) logger.InitLogger() - host := viper.GetString("storage.redis") - err = cache.Init(host) + err = cache.Init(config.Configuration.Storage.Redis) if err != nil { logger.Fatal(err) } diff --git a/market/charts.go b/market/charts.go index cab0408b4..3b2835009 100644 --- a/market/charts.go +++ b/market/charts.go @@ -1,7 +1,7 @@ package market import ( - "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/market/chart" "github.com/trustwallet/blockatlas/market/chart/cmc" "github.com/trustwallet/blockatlas/market/chart/coingecko" @@ -23,12 +23,12 @@ type Charts struct { func InitCharts() *Charts { return &Charts{chart.Providers{ 0: cmc.InitChart( - viper.GetString("market.cmc.webapi"), - viper.GetString("market.cmc.widgetapi"), - viper.GetString("market.cmc.map_url"), + config.Configuration.Market.Cmc.WebAPI, + config.Configuration.Market.Cmc.WidgetAPI, + config.Configuration.Market.Cmc.MapURL, ), 1: coingecko.InitChart( - viper.GetString("market.coingecko.api"), + config.Configuration.Market.Coingecko.API, ), }} } diff --git a/market/market.go b/market/market.go index 7e00db258..76daadf26 100644 --- a/market/market.go +++ b/market/market.go @@ -2,7 +2,7 @@ package market import ( "github.com/robfig/cron/v3" - "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/market/market" "github.com/trustwallet/blockatlas/market/market/cmc" "github.com/trustwallet/blockatlas/market/market/coingecko" @@ -19,22 +19,22 @@ func InitMarkets(storage storage.Market) { marketProviders = market.Providers{ // Add Market Quote Providers: 0: dex.InitMarket( - viper.GetString("market.dex.api"), - viper.GetString("market.dex.quote_update_time"), + config.Configuration.Market.Dex.API, + config.Configuration.Market.Dex.QuoteUpdateTime, ), 1: cmc.InitMarket( - viper.GetString("market.cmc.api"), - viper.GetString("market.cmc.api_key"), - viper.GetString("market.cmc.map_url"), - viper.GetString("market.quote_update_time"), + config.Configuration.Market.Cmc.API, + config.Configuration.Market.Cmc.APIKey, + config.Configuration.Market.Cmc.MapURL, + config.Configuration.Market.QuoteUpdateTime, ), 2: compound.InitMarket( - viper.GetString("market.compound.api"), - viper.GetString("market.quote_update_time"), + config.Configuration.Market.Compound.API, + config.Configuration.Market.QuoteUpdateTime, ), 3: coingecko.InitMarket( - viper.GetString("market.coingecko.api"), - viper.GetString("market.quote_update_time"), + config.Configuration.Market.Coingecko.API, + config.Configuration.Market.QuoteUpdateTime, ), } addMarkets(storage, marketProviders) diff --git a/market/rates.go b/market/rates.go index d2b361e01..768f3634e 100644 --- a/market/rates.go +++ b/market/rates.go @@ -2,7 +2,7 @@ package market import ( "github.com/robfig/cron/v3" - "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/market/rate" "github.com/trustwallet/blockatlas/market/rate/cmc" "github.com/trustwallet/blockatlas/market/rate/coingecko" @@ -19,23 +19,23 @@ func InitRates(storage storage.Market) { rateProviders = rate.Providers{ // Add Market Quote Providers: 0: cmc.InitRate( - viper.GetString("market.cmc.api"), - viper.GetString("market.cmc.api_key"), - viper.GetString("market.cmc.map_url"), - viper.GetString("market.rate_update_time"), + config.Configuration.Market.Cmc.API, + config.Configuration.Market.Cmc.APIKey, + config.Configuration.Market.Cmc.MapURL, + config.Configuration.Market.RateUpdateTime, ), 1: fixer.InitRate( - viper.GetString("market.fixer.api"), - viper.GetString("market.fixer.api_key"), - viper.GetString("market.fixer.rate_update_time"), + config.Configuration.Market.Fixer.API, + config.Configuration.Market.Fixer.APIKey, + config.Configuration.Market.Fixer.RateUpdateTime, ), 2: compound.InitRate( - viper.GetString("market.compound.api"), - viper.GetString("market.rate_update_time"), + config.Configuration.Market.Compound.API, + config.Configuration.Market.RateUpdateTime, ), 3: coingecko.InitRate( - viper.GetString("market.coingecko.api"), - viper.GetString("market.rate_update_time"), + config.Configuration.Market.Coingecko.API, + config.Configuration.Market.RateUpdateTime, ), } addRates(storage, rateProviders) diff --git a/observer/stream.go b/observer/stream.go index b86c95af5..d447211c2 100644 --- a/observer/stream.go +++ b/observer/stream.go @@ -2,7 +2,7 @@ package observer import ( "context" - "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/semaphore" @@ -30,7 +30,7 @@ func (s *Stream) Execute(ctx context.Context) <-chan *blockatlas.Block { cn := s.BlockAPI.Coin() s.coin = cn.ID s.logParams = logger.Params{"platform": cn.Handle} - conns := viper.GetInt("observer.stream_conns") + conns := config.Configuration.Observer.StreamConns if conns == 0 { logger.Fatal("observer.stream_conns is 0") } @@ -71,7 +71,7 @@ func (s *Stream) load(c chan<- *blockatlas.Block) { if height-lastHeight > int64(s.BacklogCount) { lastHeight = height - int64(s.BacklogCount) } - backLogMax := viper.GetInt64("observer.backlog_max_blocks") + backLogMax := config.Configuration.Observer.BacklogMaxBlocks if height-lastHeight > backLogMax { lastHeight = height - backLogMax } diff --git a/pkg/ginutils/reverse_proxy.go b/pkg/ginutils/reverse_proxy.go index c828956ed..5840a1b8e 100644 --- a/pkg/ginutils/reverse_proxy.go +++ b/pkg/ginutils/reverse_proxy.go @@ -2,13 +2,13 @@ package ginutils import ( "github.com/gin-gonic/gin" - "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/config" ) // CheckReverseProxy removes untrusted forwarded HTTP headers // if gin.reverse_proxy is defined func CheckReverseProxy(c *gin.Context) { - if !viper.GetBool("gin.reverse_proxy") { + if !config.Configuration.Gin.ReverseProxy { c.Request.Header.Del("Forwarded") c.Request.Header.Del("X-Forwarded-Proto") c.Request.Header.Del("X-Forwarded-Host") diff --git a/pkg/tests/functional/functional_test.go b/pkg/tests/functional/functional_test.go index c7126ec4c..36fc58043 100755 --- a/pkg/tests/functional/functional_test.go +++ b/pkg/tests/functional/functional_test.go @@ -6,7 +6,6 @@ import ( "context" "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" "github.com/trustwallet/blockatlas/api" @@ -30,7 +29,7 @@ func TestApis(t *testing.T) { config.LoadConfig(os.Getenv("TEST_CONFIG")) logger.InitLogger() - platform.Init(viper.GetString("platform")) + platform.Init(config.Configuration.Platform) cache := storage.New() sg := sentrygin.New(sentrygin.Options{}) p := ":8420" @@ -54,12 +53,12 @@ func TestApis(t *testing.T) { api.MakeMetricsRoute(engine) api.LoadPlatforms(engine) - if viper.GetBool("observer.enabled") { + if config.Configuration.Observer.Enabled { logger.Info("Loading observer API") observerAPI := engine.Group("/observer/v1") api.SetupObserverAPI(observerAPI, cache) } - if viper.GetBool("market.enabled") { + if config.Configuration.Market.Enabled { logger.Info("Loading market API") marketAPI := engine.Group("/v1/market") api.SetupMarketAPI(marketAPI, cache) diff --git a/pkg/tests/integration/integration_test.go b/pkg/tests/integration/integration_test.go index 858ccd7fa..7e220322a 100755 --- a/pkg/tests/integration/integration_test.go +++ b/pkg/tests/integration/integration_test.go @@ -3,7 +3,6 @@ package integration import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/tests/integration/bitcoin" "github.com/trustwallet/blockatlas/pkg/tests/integration/domains" @@ -20,7 +19,7 @@ func Test(t *testing.T) { } else { config.LoadConfig(configPath) } - platform.Init(viper.GetString("platform")) + platform.Init(config.Configuration.Platform) // Add your integration tests here ontology.TestOntology(t) From 7c842154b493f5af9029e55b1db3e9a2ff3e1948 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 19 Feb 2020 22:09:56 -0300 Subject: [PATCH 146/506] Avoid error when the config vars is not set (#895) --- config.yml | 8 ++++---- pkg/tests/functional/http.go | 2 ++ pkg/tests/functional/testdata/coin_fixtures.json | 5 ++++- pkg/tests/functional/testdata/exclude.json | 2 ++ services/assets/stake.go | 4 ++-- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/config.yml b/config.yml index d9986de23..dd2b953e3 100644 --- a/config.yml +++ b/config.yml @@ -140,7 +140,7 @@ theta: # [ATOM] Cosmos: https://cosmos.network/ cosmos: - api: http://stargate.cosmos.network + api: https://api.cosmos.network # [ONTOLOGY] ONT: https://ont.io/ ontology: @@ -148,8 +148,8 @@ ontology: # [ZIL] Zilliqa: https://zilliqa.com zilliqa: - # api: https://api.viewblock.io/v1/zilliqa - # key: YOUR_API_KEY + api: https://api.viewblock.io/v1/zilliqa + # key: YOUR_API_KEY rpc: https://api.zilliqa.com lookup: https://unstoppabledomains.com/api/v1 @@ -170,7 +170,7 @@ nebulas: api: https://explorer-backend.nebulas.io/api fio: -# api: https://addresses.fio.foundation + # api: https://addresses.fio.foundation api: http://testnet.fioprotocol.io/v1/chain # [BTC] Bitcoin: https://bitcoin.org/ (Blockbook API https://github.com/trezor/blockbook) diff --git a/pkg/tests/functional/http.go b/pkg/tests/functional/http.go index a00cebe77..b77093480 100644 --- a/pkg/tests/functional/http.go +++ b/pkg/tests/functional/http.go @@ -49,6 +49,7 @@ func (c *Client) testGet(route string, query string) { if response == nil || response.Raw() == nil { logger.Error("Invalid response", logger.Params{"response": response, "route": route, "query": query}) + return } if response.Raw().StatusCode != http.StatusOK { logger.Error("Invalid status code", logger.Params{"code": response.Raw().Status, "route": route, "query": query}) @@ -69,6 +70,7 @@ func (c *Client) testPost(route string, body interface{}) { response := request.Expect() if response == nil || response.Raw() == nil { logger.Error("Invalid response", logger.Params{"code": response.Raw().Status, "route": route}) + return } if response.Raw().StatusCode != http.StatusOK { bodyJson, _ := json.Marshal(body) diff --git a/pkg/tests/functional/testdata/coin_fixtures.json b/pkg/tests/functional/testdata/coin_fixtures.json index 906a63465..9563ed5d8 100644 --- a/pkg/tests/functional/testdata/coin_fixtures.json +++ b/pkg/tests/functional/testdata/coin_fixtures.json @@ -111,7 +111,7 @@ "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" }, "tron": { - "address": "TQZskDJJRGAHifeKoQ7wLC4QDyB2iGvwp2" + "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" }, "vechain": { "address": "0xB5e883349e68aB59307d1604555AC890fAC47128" @@ -154,6 +154,9 @@ }, "waves": { "address": "3P7wz6TXienpw3BHe8eHUEuZWb6WE58kgnQ" + }, + "harmony": { + "address": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv" } } diff --git a/pkg/tests/functional/testdata/exclude.json b/pkg/tests/functional/testdata/exclude.json index 51798c170..1326f2894 100644 --- a/pkg/tests/functional/testdata/exclude.json +++ b/pkg/tests/functional/testdata/exclude.json @@ -1,5 +1,7 @@ [ "/swagger/*any", + "/v1/fio/:address", + "/v2/fio/transactions/:address", "/v1/aeternity/:address", "/v2/aeternity/transactions/:address", "/v2/collectibles/categories", diff --git a/services/assets/stake.go b/services/assets/stake.go index 6c5999d49..01fd35202 100644 --- a/services/assets/stake.go +++ b/services/assets/stake.go @@ -17,7 +17,7 @@ func requestValidatorsInfo(coin coin.Coin) (AssetValidators, error) { request := blockatlas.InitClient(AssetsURL + coin.Handle) err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) if err != nil { - return nil, errors.E(err, errors.Params{"coin": coin.Handle}).PushToSentry() + return nil, errors.E(err, errors.Params{"coin": coin.Handle}) } return results, nil } @@ -43,7 +43,7 @@ func GetActiveValidators(api blockatlas.StakeAPI) (blockatlas.StakeValidators, e func GetValidators(api blockatlas.StakeAPI) (AssetValidators, blockatlas.ValidatorPage, error) { assetsValidators, err := requestValidatorsInfo(api.Coin()) if err != nil { - return nil, 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") } validators, err := api.GetValidators() From 37a103473e996a049026ab92dcbc30085e228285 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 21 Feb 2020 23:30:55 +0300 Subject: [PATCH 147/506] Update PRs from dev branch (#901) * Add version info to binaries (#896) * Move platform init one level higher (#887) * Move init functions to the top lvl * Fix coinindex for generic platforms * Init platform inside the integration tests * Use dinamic api var * Move fetch cg markets functionality to function (#897) * Move fetching CG market ot function * Use plurar naming * fix Ripple * Change postman * Fix ong claim tx (#899) Co-authored-by: Danilo Pantani Co-authored-by: Mykola <3277207+kolya182@users.noreply.github.com> --- Makefile | 4 +- build/build.go | 26 +++ cmd/market_api/main.go | 7 +- cmd/market_observer/main.go | 2 + cmd/observer_api/main.go | 7 +- cmd/platform_api/main.go | 7 +- cmd/platform_observer/main.go | 2 + cmd/swagger_api/main.go | 7 +- go.mod | 1 + market/clients/coingecko/client.go | 22 +- market/market/coingecko/coingecko.go | 6 +- pkg/blockatlas/api.go | 6 - pkg/blockatlas/platform.go | 11 + pkg/blockatlas/platform_test.go | 45 ++++ pkg/tests/integration/bitcoin/block.go | 5 +- pkg/tests/integration/ontology/block.go | 4 +- .../Blockatlas.postman_collection.json | 217 +----------------- pkg/tests/postman/transaction_data.json | 2 +- platform/aeternity/base.go | 8 +- platform/aion/base.go | 8 +- platform/algorand/base.go | 9 +- platform/binance/base.go | 12 +- platform/bitcoin/base.go | 14 +- platform/cosmos/base.go | 14 +- platform/ethereum/base.go | 31 ++- platform/fio/base.go | 8 +- platform/harmony/base.go | 9 +- platform/icon/base.go | 8 +- platform/iotex/base.go | 8 +- platform/nano/base.go | 10 +- platform/nebulas/base.go | 8 +- platform/nimiq/base.go | 8 +- platform/ontology/base.go | 8 +- platform/ontology/model.go | 13 +- platform/ontology/model_test.go | 68 ++++-- platform/ontology/transaction_test.go | 2 +- platform/platform.go | 97 ++++++++ platform/polkadot/base.go | 14 +- platform/registry.go | 188 +-------------- platform/ripple/base.go | 8 +- platform/ripple/client.go | 2 +- platform/stellar/base.go | 12 +- platform/tezos/base.go | 11 +- platform/theta/base.go | 8 +- platform/tron/base.go | 8 +- platform/vechain/base.go | 8 +- platform/waves/base.go | 8 +- platform/zilliqa/base.go | 17 +- 48 files changed, 432 insertions(+), 576 deletions(-) create mode 100644 build/build.go create mode 100644 pkg/blockatlas/platform.go create mode 100644 pkg/blockatlas/platform_test.go create mode 100644 platform/platform.go diff --git a/Makefile b/Makefile index 0c5a5d7e3..cbde91f86 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,10 @@ #! /usr/bin/make -f # Project variables. +PACKAGE := github.com/trustwallet/blockatlas VERSION := $(shell git describe --tags) BUILD := $(shell git rev-parse --short HEAD) +DATETIME := $(shell date +"%Y.%m.%d-%H:%M:%S") PROJECT_NAME := $(shell basename "$(PWD)") API_SERVICE := platform_api OBSERVER_SERVICE := platform_observer @@ -26,7 +28,7 @@ CONFIG_FILE=$(GOBASE)/config.yml GOFMT_FILES?=$$(find . -name '*.go' | grep -v vendor) # Use linker flags to provide version/build settings -LDFLAGS=-ldflags "-X=main.Version=$(VERSION) -X=main.Build=$(BUILD)" +LDFLAGS=-ldflags "-X=$(PACKAGE)/build.Version=$(VERSION) -X=$(PACKAGE)/build.Build=$(BUILD) -X=$(PACKAGE)/build.Date=$(DATETIME)" # Redirect error output to a file, so we can show it in development mode. STDERR := /tmp/.$(PROJECT_NAME)-stderr.txt diff --git a/build/build.go b/build/build.go new file mode 100644 index 000000000..49f78ec67 --- /dev/null +++ b/build/build.go @@ -0,0 +1,26 @@ +package build + +import ( + "fmt" + "runtime" +) + +var ( + Version = "dev" + Build = "dev" + Date = "" +) + +func LogVersionInfo() { + fmt.Printf(` +************************************************ +Version: %v +Build: %v +Date: %v +OS: %s +Arch: %s +Go: %s +************************************************ +`, + Version, Build, Date, runtime.GOOS, runtime.GOARCH, runtime.Version()) +} diff --git a/cmd/market_api/main.go b/cmd/market_api/main.go index fbe183b8a..69310fa66 100644 --- a/cmd/market_api/main.go +++ b/cmd/market_api/main.go @@ -3,6 +3,7 @@ package main import ( "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/build" "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" @@ -23,6 +24,7 @@ var ( ) func init() { + build.LogVersionInfo() port, confPath, sg, cache = internal.InitAPIWithRedis(defaultPort, defaultConfigPath) } @@ -38,7 +40,10 @@ func main() { engine.GET("/", api.GetRoot) engine.GET("/status", func(c *gin.Context) { ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, + "status": true, + "version": build.Version, + "build": build.Build, + "date": build.Date, }) }) diff --git a/cmd/market_observer/main.go b/cmd/market_observer/main.go index 64746140f..152fbaeb5 100644 --- a/cmd/market_observer/main.go +++ b/cmd/market_observer/main.go @@ -1,6 +1,7 @@ package main import ( + "github.com/trustwallet/blockatlas/build" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/market" "github.com/trustwallet/blockatlas/storage" @@ -16,6 +17,7 @@ var ( ) func init() { + build.LogVersionInfo() _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) } diff --git a/cmd/observer_api/main.go b/cmd/observer_api/main.go index dbaaf3f85..997b3901b 100644 --- a/cmd/observer_api/main.go +++ b/cmd/observer_api/main.go @@ -3,6 +3,7 @@ package main import ( "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/build" "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" @@ -23,6 +24,7 @@ var ( ) func init() { + build.LogVersionInfo() port, confPath, sg, cache = internal.InitAPIWithRedis(defaultPort, defaultConfigPath) } @@ -38,7 +40,10 @@ func main() { engine.GET("/", api.GetRoot) engine.GET("/status", func(c *gin.Context) { ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, + "status": true, + "version": build.Version, + "build": build.Build, + "date": build.Date, }) }) diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index 73873e4cc..c3bf9a5c0 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -3,6 +3,7 @@ package main import ( "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/build" "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" @@ -22,6 +23,7 @@ var ( ) func init() { + build.LogVersionInfo() port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) platform.Init(config.Configuration.Platform) } @@ -37,7 +39,10 @@ func main() { engine.GET("/", api.GetRoot) engine.GET("/status", func(c *gin.Context) { ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, + "status": true, + "version": build.Version, + "build": build.Build, + "date": build.Date, }) }) diff --git a/cmd/platform_observer/main.go b/cmd/platform_observer/main.go index 3ec4f8f60..04cdfe1e1 100644 --- a/cmd/platform_observer/main.go +++ b/cmd/platform_observer/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "github.com/trustwallet/blockatlas/build" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/observer" @@ -21,6 +22,7 @@ var ( ) func init() { + build.LogVersionInfo() _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) platform.Init(config.Configuration.Platform) } diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go index d3f23596f..2b4c85115 100644 --- a/cmd/swagger_api/main.go +++ b/cmd/swagger_api/main.go @@ -5,6 +5,7 @@ import ( ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/build" "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" @@ -23,6 +24,7 @@ var ( ) func init() { + build.LogVersionInfo() port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) } @@ -37,7 +39,10 @@ func main() { engine.GET("/", api.GetRoot) engine.GET("/status", func(c *gin.Context) { ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, + "status": true, + "version": build.Version, + "build": build.Build, + "date": build.Date, }) }) diff --git a/go.mod b/go.mod index fddd41ed9..8a81e9d9e 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/go-redis/redis v6.15.6+incompatible github.com/hewigovens/go-coincodec v1.0.4 github.com/jinzhu/gorm v1.9.12 + github.com/mitchellh/mapstructure v1.1.2 github.com/mr-tron/base58 v1.1.3 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/prometheus/client_golang v1.4.0 diff --git a/market/clients/coingecko/client.go b/market/clients/coingecko/client.go index d8774fc05..93a425701 100644 --- a/market/clients/coingecko/client.go +++ b/market/clients/coingecko/client.go @@ -41,14 +41,9 @@ func (c *Client) FetchLatestRates(coins GeckoCoins, currency string) (prices Coi end = i + bucketSize } bucket := ci[i:end] - values := url.Values{ - "vs_currency": {currency}, - "sparkline": {"false"}, - "ids": {strings.Join(bucket[:], ",")}, - } + ids := strings.Join(bucket[:], ",") - var cp CoinPrices - err := c.Get(&cp, "v3/coins/markets", values) + cp, err := c.FetchCoinsMarkets(currency, ids) if err != nil { logger.Error(err) return @@ -71,7 +66,7 @@ func (c *Client) FetchLatestRates(coins GeckoCoins, currency string) (prices Coi return } -func (c *Client) GetChartsData(id string, currency string, timeStart int64, timeEnd int64) (charts Charts, err error) { +func (c *Client) GetChartsData(id, currency string, timeStart, timeEnd int64) (charts Charts, err error) { values := url.Values{ "vs_currency": {currency}, "from": {strconv.FormatInt(timeStart, 10)}, @@ -89,6 +84,17 @@ func (c *Client) FetchCoinsList() (coins GeckoCoins, err error) { return } +func (c *Client) FetchCoinsMarkets(currency, ids string) (cp CoinPrices, err error) { + values := url.Values{ + "vs_currency": {currency}, + "sparkline": {"false"}, + "ids": {ids}, + } + + err = c.Get(&cp, "v3/coins/markets", values) + return +} + func (coins GeckoCoins) coinIds() []string { coinIds := make([]string, 0) for _, coin := range coins { diff --git a/market/market/coingecko/coingecko.go b/market/market/coingecko/coingecko.go index 6729505ff..d16f21dd3 100644 --- a/market/market/coingecko/coingecko.go +++ b/market/market/coingecko/coingecko.go @@ -17,7 +17,7 @@ type Market struct { market.Market } -func InitMarket(api string, updateTime string) market.Provider { +func InitMarket(api, updateTime string) market.Provider { m := &Market{ client: coingecko.NewClient(api), Market: market.Market{ @@ -45,7 +45,7 @@ func (m *Market) normalizeTicker(price coingecko.CoinPrice, provider string) (ti coinName := strings.ToUpper(price.Symbol) coinType := blockatlas.TypeCoin - cgCoin, err := m.cache.GetCoinsById(price.Id) + cgCoins, err := m.cache.GetCoinsById(price.Id) if err != nil { tickers = append(tickers, &blockatlas.Ticker{ CoinName: coinName, @@ -62,7 +62,7 @@ func (m *Market) normalizeTicker(price coingecko.CoinPrice, provider string) (ti return } - for _, cg := range cgCoin { + for _, cg := range cgCoins { coinName = strings.ToUpper(cg.Symbol) if cg.CoinType == blockatlas.TypeCoin { tokenId = "" diff --git a/pkg/blockatlas/api.go b/pkg/blockatlas/api.go index bafbb616d..141637baf 100644 --- a/pkg/blockatlas/api.go +++ b/pkg/blockatlas/api.go @@ -5,14 +5,8 @@ import ( "github.com/trustwallet/blockatlas/coin" ) -// Initer is a service that can be initialized once -type Initer interface { - Init() error -} - // Platform can be used to access a crypto service type Platform interface { - Initer Coin() coin.Coin } diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go new file mode 100644 index 000000000..0dad23195 --- /dev/null +++ b/pkg/blockatlas/platform.go @@ -0,0 +1,11 @@ +package blockatlas + +type Platforms map[string]Platform + +func (ps Platforms) GetPlatformList() []Platform { + platforms := make([]Platform, 0) + for _, p := range ps { + platforms = append(platforms, p) + } + return platforms +} diff --git a/pkg/blockatlas/platform_test.go b/pkg/blockatlas/platform_test.go new file mode 100644 index 000000000..5cafdb6c6 --- /dev/null +++ b/pkg/blockatlas/platform_test.go @@ -0,0 +1,45 @@ +package blockatlas + +import ( + "reflect" + "testing" +) + +func TestPlatforms_GetPlatformList(t *testing.T) { + var p Platform + tests := []struct { + name string + ps Platforms + want []Platform + }{ + { + "test 1", + Platforms{ + "test1": p, + "test2": p, + "test3": p, + }, + []Platform{p, p, p}, + }, { + "test 2", + Platforms{ + "test1": p, + "test2": p, + }, + []Platform{p, p}, + }, { + "test 3", + Platforms{ + "test1": p, + }, + []Platform{p}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.ps.GetPlatformList(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetPlatformList() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/tests/integration/bitcoin/block.go b/pkg/tests/integration/bitcoin/block.go index 26fcddb19..3237b4322 100755 --- a/pkg/tests/integration/bitcoin/block.go +++ b/pkg/tests/integration/bitcoin/block.go @@ -3,6 +3,8 @@ package bitcoin import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/platform/bitcoin" "testing" ) @@ -13,8 +15,7 @@ const ( func TestBitcoin(t *testing.T) { t.Run("test bitcoin", func(t *testing.T) { - p := &bitcoin.Platform{} - _ = p.Init() + p := bitcoin.Init(coin.BTC, platform.GetApiVar(coin.BTC)) testCurrentBlockNumber(p, t) testGetBlockByNumber(p, t) }) diff --git a/pkg/tests/integration/ontology/block.go b/pkg/tests/integration/ontology/block.go index 2238b0a65..d5c01b1ae 100755 --- a/pkg/tests/integration/ontology/block.go +++ b/pkg/tests/integration/ontology/block.go @@ -5,6 +5,7 @@ package ontology import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/platform/ontology" "testing" ) @@ -81,8 +82,7 @@ const ( func TestOntology(t *testing.T) { t.Run("test ontology", func(t *testing.T) { - p := &ontology.Platform{} - _ = p.Init() + p := ontology.Init(platform.GetVar("ontology.api")) testCurrentBlockNumber(p, t) testGetBlockByNumber(p, t) }) diff --git a/pkg/tests/postman/Blockatlas.postman_collection.json b/pkg/tests/postman/Blockatlas.postman_collection.json index ad9a8fea8..d30fd6701 100644 --- a/pkg/tests/postman/Blockatlas.postman_collection.json +++ b/pkg/tests/postman/Blockatlas.postman_collection.json @@ -1,7 +1,7 @@ { "info": { - "_postman_id": "b31e9564-879c-4fb0-ad27-986070bc06a0", - "name": "Blockatlas", + "_postman_id": "4e4d72ba-02c4-4d87-af91-ea42b6225ee4", + "name": "Blockatlas вум", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ @@ -1598,124 +1598,6 @@ { "name": "market", "item": [ - { - "name": "ticker", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "7312c9e7-5330-421a-9ca8-171101050e38", - "exec": [ - "var token_id = pm.environment.get(\"token_id\");", - "if(!token_id) {", - " pm.environment.set(\"token_id\", \"\");", - "}", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "acec8baa-0ef0-4703-ab83-c555260deffa", - "exec": [ - "var Ajv = require('ajv');", - "var ajv = new Ajv({logger: console});", - "let schema = {", - " \"type\": \"object\",", - " \"properties\": {", - " \"coin\": {", - " \"type\": \"integer\"", - " },", - " \"coin_name\": {", - " \"type\": \"string\"", - " },", - " \"token_id\": {", - " \"type\": \"string\"", - " },", - " \"type\": {", - " \"type\": \"string\"", - " },", - " \"price\": {", - " \"type\": \"object\",", - " \"properties\": {", - " \"value\": {", - " \"type\": \"number\"", - " },", - " \"change_24h\": {", - " \"type\": \"number\"", - " },", - " \"currency\": {", - " \"type\": \"string\"", - " },", - " \"provider\": {", - " \"type\": \"string\"", - " }", - " }", - " },", - " \"last_update\": {", - " \"type\": \"string\"", - " }", - " }", - "};", - "", - "var jsonData = pm.response.json();", - "", - "pm.test(\"response must be valid and have a body\", function () {", - " pm.response.to.have.status(200);", - " pm.response.to.be.ok;", - " pm.response.to.not.be.error;", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "", - "pm.test(\"schema is valid\", function() {", - " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{market_auth}}" - } - ], - "url": { - "raw": "{{host}}/v1/market/ticker?currency={{currency}}&coin={{coin}}&token={{token_id}}", - "host": [ - "{{host}}" - ], - "path": [ - "v1", - "market", - "ticker" - ], - "query": [ - { - "key": "currency", - "value": "{{currency}}" - }, - { - "key": "coin", - "value": "{{coin}}" - }, - { - "key": "token", - "value": "{{token_id}}" - } - ] - } - }, - "response": [] - }, { "name": "charts", "event": [ @@ -2275,93 +2157,6 @@ } }, "response": [] - }, - { - "name": "status", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "7312c9e7-5330-421a-9ca8-171101050e38", - "exec": [ - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "acec8baa-0ef0-4703-ab83-c555260deffa", - "exec": [ - "var Ajv = require('ajv');", - "var ajv = new Ajv({logger: console});", - "let schema = {", - " \"type\": \"object\",", - " \"minProperties\": 5,", - " \"uniqueItems\": true,", - " \"items\": {\"type\": \"object\"}", - "};", - "", - "var jsonData = pm.response.json();", - "", - "pm.test(\"response must be valid and have a body\", function () {", - " pm.response.to.have.status(200);", - " pm.response.to.be.ok;", - " pm.response.to.not.be.error;", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "", - "pm.test(\"schema is valid\", function() {", - " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{observer_auth}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{host}}/observer/v1/status", - "host": [ - "{{host}}" - ], - "path": [ - "observer", - "v1", - "status" - ] - } - }, - "response": [] } ], "event": [ @@ -2571,25 +2366,25 @@ ], "variable": [ { - "id": "7e392582-2f75-48a2-a096-ef338490e7f8", + "id": "ad2326b7-fb90-4b11-a1e3-dfe8ea3aae65", "key": "host", "value": "http://localhost:8420", "type": "string" }, { - "id": "39dad5f8-9727-4dda-9f27-b4e29dd0ff18", + "id": "7ae1014f-44e1-4c16-aacd-2be971ee15ef", "key": "observer_auth", "value": "test", "type": "string" }, { - "id": "edc48bc9-0c39-46a1-809a-c6d71874a958", + "id": "0d3dcacb-5b63-409a-8150-9e06d24e1eb4", "key": "market_auth", "value": "", "type": "string" }, { - "id": "2ee77821-80ac-470a-9293-78b361ef27c7", + "id": "c42f8723-ad35-45ea-9dd2-066ced0780bc", "key": "platform_auth", "value": "", "type": "string" diff --git a/pkg/tests/postman/transaction_data.json b/pkg/tests/postman/transaction_data.json index 6818b823e..4c580cac8 100644 --- a/pkg/tests/postman/transaction_data.json +++ b/pkg/tests/postman/transaction_data.json @@ -117,7 +117,7 @@ }, { "handler": "waves", - "address": "3P7wz6TXienpw3BHe8eHUEuZWb6WE58kgnQ" + "address": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD" }, { "handler": "digibyte", diff --git a/platform/aeternity/base.go b/platform/aeternity/base.go index 1f345c83c..bf412ce27 100644 --- a/platform/aeternity/base.go +++ b/platform/aeternity/base.go @@ -1,7 +1,6 @@ package aeternity import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("aeternity.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/aion/base.go b/platform/aion/base.go index 15379aa6e..1e7fa8487 100644 --- a/platform/aion/base.go +++ b/platform/aion/base.go @@ -1,7 +1,6 @@ package aion import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("aion.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/algorand/base.go b/platform/algorand/base.go index 1e121c6ce..3dd9cde67 100644 --- a/platform/algorand/base.go +++ b/platform/algorand/base.go @@ -1,8 +1,6 @@ package algorand import ( - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -11,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("algorand.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/binance/base.go b/platform/binance/base.go index ae15a6ea9..55f9fb345 100644 --- a/platform/binance/base.go +++ b/platform/binance/base.go @@ -1,7 +1,6 @@ package binance import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -11,13 +10,14 @@ type Platform struct { dexClient DexClient } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("binance.api"))} +func Init(api, dex string) *Platform { + p := &Platform{ + client: Client{blockatlas.InitClient(api)}, + dexClient: DexClient{blockatlas.InitClient(dex)}, + } p.client.ErrorHandler = getHTTPError - - p.dexClient = DexClient{blockatlas.InitClient(viper.GetString("binance.dex"))} p.dexClient.ErrorHandler = getHTTPError - return nil + return p } func (p *Platform) Coin() coin.Coin { diff --git a/platform/bitcoin/base.go b/platform/bitcoin/base.go index a8c685b64..ada173e4d 100644 --- a/platform/bitcoin/base.go +++ b/platform/bitcoin/base.go @@ -1,8 +1,6 @@ package bitcoin import ( - "fmt" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -12,19 +10,17 @@ type Platform struct { CoinIndex uint } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString(p.ConfigKey()))} - return nil +func Init(coin uint, api string) *Platform { + return &Platform{ + CoinIndex: coin, + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { return coin.Coins[p.CoinIndex] } -func (p *Platform) ConfigKey() string { - return fmt.Sprintf("%s.api", p.Coin().Handle) -} - func (p *Platform) GetAddressesFromXpub(xpub string) ([]string, error) { tokens, err := p.client.GetAddressesFromXpub(xpub) addresses := make([]string, 0) diff --git a/platform/cosmos/base.go b/platform/cosmos/base.go index 3fea3ceda..3b3b92c50 100644 --- a/platform/cosmos/base.go +++ b/platform/cosmos/base.go @@ -1,8 +1,6 @@ package cosmos import ( - "fmt" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -12,15 +10,13 @@ type Platform struct { CoinIndex uint } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString(p.ConfigKey()))} - return nil +func Init(coin uint, api string) *Platform { + return &Platform{ + CoinIndex: coin, + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { return coin.Coins[p.CoinIndex] } - -func (p *Platform) ConfigKey() string { - return fmt.Sprintf("%s.api", p.Coin().Handle) -} diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index 2d5aadd30..4d78bcd8d 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -1,33 +1,30 @@ package ethereum import ( - "fmt" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) type Platform struct { - client Client - collectionsClient CollectionsClient CoinIndex uint RpcURL string + client Client + collectionsClient CollectionsClient } -func (p *Platform) Init() error { - handle := coin.Coins[p.CoinIndex].Handle - - coinVar := fmt.Sprintf("%s.api", handle) - p.client = Client{blockatlas.InitClient(viper.GetString(coinVar))} - - collectionsApiVar := fmt.Sprintf("%s.collections_api", handle) - p.collectionsClient = CollectionsClient{blockatlas.InitClient(viper.GetString(collectionsApiVar))} - - collectionsApiKeyVar := fmt.Sprintf("%s.collections_api_key", handle) - p.collectionsClient.Headers["X-API-KEY"] = viper.GetString(collectionsApiKeyVar) +func Init(coin uint, api, rpc string) *Platform { + return &Platform{ + CoinIndex: coin, + RpcURL: rpc, + client: Client{blockatlas.InitClient(api)}, + } +} - p.RpcURL = viper.GetString("ethereum.rpc") - return nil +func InitWitCollection(coin uint, api, rpc, collectionApi, collectionKey string) *Platform { + p := Init(coin, api, rpc) + p.collectionsClient = CollectionsClient{blockatlas.InitClient(collectionApi)} + p.collectionsClient.Headers["X-API-KEY"] = collectionKey + return p } func (p *Platform) Coin() coin.Coin { diff --git a/platform/fio/base.go b/platform/fio/base.go index 6db1586a3..5f5641dca 100644 --- a/platform/fio/base.go +++ b/platform/fio/base.go @@ -1,7 +1,6 @@ package fio import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("fio.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/harmony/base.go b/platform/harmony/base.go index 75bce0e88..f9e8c813c 100644 --- a/platform/harmony/base.go +++ b/platform/harmony/base.go @@ -1,7 +1,6 @@ package harmony import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,10 +9,12 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("harmony.api"))} +func Init(api string) *Platform { + p := &Platform{ + client: Client{blockatlas.InitClient(api)}, + } p.client.Headers["Content-Type"] = "application/json" - return nil + return p } func (p *Platform) Coin() coin.Coin { diff --git a/platform/icon/base.go b/platform/icon/base.go index 74c785a8a..d247899cd 100644 --- a/platform/icon/base.go +++ b/platform/icon/base.go @@ -1,7 +1,6 @@ package icon import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("icon.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/iotex/base.go b/platform/iotex/base.go index e9de7daeb..b7880f7d0 100644 --- a/platform/iotex/base.go +++ b/platform/iotex/base.go @@ -1,7 +1,6 @@ package iotex import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("iotex.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/nano/base.go b/platform/nano/base.go index 08cac55ee..8dfde34eb 100644 --- a/platform/nano/base.go +++ b/platform/nano/base.go @@ -3,18 +3,18 @@ package nano import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - - "github.com/spf13/viper" ) type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("nano.api"))} +func Init(api string) *Platform { + p := &Platform{ + client: Client{blockatlas.InitClient(api)}, + } p.client.Headers["Content-Type"] = "application/json" - return nil + return p } func (p *Platform) Coin() coin.Coin { diff --git a/platform/nebulas/base.go b/platform/nebulas/base.go index 2b03679c5..6d41707a4 100644 --- a/platform/nebulas/base.go +++ b/platform/nebulas/base.go @@ -1,7 +1,6 @@ package nebulas import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("nebulas.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/nimiq/base.go b/platform/nimiq/base.go index e64e82297..0772b8534 100644 --- a/platform/nimiq/base.go +++ b/platform/nimiq/base.go @@ -1,7 +1,6 @@ package nimiq import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("nimiq.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/ontology/base.go b/platform/ontology/base.go index dd5ce0480..cd7945c0f 100644 --- a/platform/ontology/base.go +++ b/platform/ontology/base.go @@ -1,7 +1,6 @@ package ontology import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("ontology.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/ontology/model.go b/platform/ontology/model.go index ae54ab78b..a5cd55a3c 100644 --- a/platform/ontology/model.go +++ b/platform/ontology/model.go @@ -134,11 +134,22 @@ func (tfs Transfers) isClaimReward() bool { if tfs[0].AssetName != AssetONG || tfs[1].AssetName != AssetONG { return false } + // Avoid transactions for yourself + if tfs[0].ToAddress == tfs[0].FromAddress || tfs[1].ToAddress == tfs[1].FromAddress { + return false + } // Verify if one of the transfers is a fee transfer. if !tfs.hasFeeTransfer() { return false } - return true + // The user need to pay a fee to get his reward + if tfs[1].isFeeTransfer() && tfs[0].ToAddress == tfs[1].FromAddress && tfs[1].ToAddress == GovernanceContract { + return true + } + if tfs[0].isFeeTransfer() && tfs[1].ToAddress == tfs[0].FromAddress && tfs[0].ToAddress == GovernanceContract { + return false + } + return false } diff --git a/platform/ontology/model_test.go b/platform/ontology/model_test.go index 72b03d390..b67322bf0 100644 --- a/platform/ontology/model_test.go +++ b/platform/ontology/model_test.go @@ -37,6 +37,40 @@ func TestTransfer_isFeeTransfer(t *testing.T) { } var ( + transfersClaims2 = Transfers{{ + Amount: "0.4", + FromAddress: "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", + ToAddress: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + AssetName: "ong", + }, { + Amount: "0.01", + FromAddress: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + ToAddress: "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + AssetName: "ong", + }} + transfersOngYourself = Transfers{{ + Amount: "0.02", + FromAddress: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + ToAddress: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + AssetName: "ong", + }, { + Amount: "0.01", + FromAddress: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + ToAddress: "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + AssetName: "ong", + }} + transfersOng2 = Transfers{{ + Amount: "0.4", + FromAddress: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + ToAddress: "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + AssetName: "ong", + }, { + Amount: "0.01", + FromAddress: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + ToAddress: "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + AssetName: "ong", + }} + transferFee = Transfer{ Amount: "0.01", FromAddress: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", @@ -55,10 +89,10 @@ var ( ToAddress: "ARncJn1rr9hivokUWxzr915vS3usR6xdgJ", AssetName: "ont", } - transfersClaims = Transfers{transferOng, transferFee} - transfersOnt = Transfers{transferOnt, transferFee} - transfersOng = Transfers{transferOng} - transfersFee = Transfers{transferFee} + transfersClaims1 = Transfers{transferOng, transferFee} + transfersOnt = Transfers{transferOnt, transferFee} + transfersOng1 = Transfers{transferOng} + transfersFee = Transfers{transferFee} ) func TestTransfers_getTransfer(t *testing.T) { @@ -68,15 +102,15 @@ func TestTransfers_getTransfer(t *testing.T) { asset AssetType want *Transfer }{ - {"Transfer Claims Asset Ong", transfersClaims, AssetONG, &transferOng}, - {"Transfer Claims Asset Ont", transfersClaims, AssetONT, nil}, - {"Transfer Claims Asset All", transfersClaims, AssetAll, &transferOng}, + {"Transfer Claims Asset Ong", transfersClaims1, AssetONG, &transferOng}, + {"Transfer Claims Asset Ont", transfersClaims1, AssetONT, nil}, + {"Transfer Claims Asset All", transfersClaims1, AssetAll, &transferOng}, {"Transfer Ont Asset Ong", transfersOnt, AssetONG, nil}, {"Transfer Ont Asset Ont", transfersOnt, AssetONT, &transferOnt}, {"Transfer Ont Asset All", transfersOnt, AssetAll, &transferOnt}, - {"Transfer Ong Asset Ong", transfersOng, AssetONG, &transferOng}, - {"Transfer Ong Asset Ont", transfersOng, AssetONT, nil}, - {"Transfer Ong Asset All", transfersOng, AssetAll, &transferOng}, + {"Transfer Ong Asset Ong", transfersOng1, AssetONG, &transferOng}, + {"Transfer Ong Asset Ont", transfersOng1, AssetONT, nil}, + {"Transfer Ong Asset All", transfersOng1, AssetAll, &transferOng}, {"Transfer Fee Asset Ong", transfersFee, AssetONG, nil}, {"Transfer Fee Asset Ont", transfersFee, AssetONT, nil}, {"Transfer Fee Asset All", transfersFee, AssetAll, nil}, @@ -96,9 +130,12 @@ func TestTransfers_hasFeeTransfer(t *testing.T) { tfs Transfers want bool }{ - {"Transfer Claims", transfersClaims, true}, + {"Transfer Claims 1", transfersClaims1, true}, + {"Transfer Calims 2", transfersClaims2, true}, {"Transfer Ont", transfersOnt, true}, - {"Transfer Ong", transfersOng, false}, + {"Transfer Ong 1", transfersOng1, false}, + {"Transfer Ong 2", transfersOng2, true}, + {"Transfer Ong Yourself ", transfersOngYourself, true}, {"Transfer Fee", transfersFee, true}, } for _, tt := range tests { @@ -116,9 +153,12 @@ func TestTransfers_isClaimReward(t *testing.T) { tfs Transfers want bool }{ - {"Transfer Claims", transfersClaims, true}, + {"Transfer Claims 1", transfersClaims1, true}, + {"Transfer Claims 2", transfersClaims2, true}, {"Transfer Ont", transfersOnt, false}, - {"Transfer Ong", transfersOng, false}, + {"Transfer Ong 1", transfersOng1, false}, + {"Transfer Ong 2", transfersOng2, false}, + {"Transfer Ong Yourself", transfersOngYourself, false}, {"Transfer Fee", transfersFee, false}, } for _, tt := range tests { diff --git a/platform/ontology/transaction_test.go b/platform/ontology/transaction_test.go index 2312fc520..fc318228a 100644 --- a/platform/ontology/transaction_test.go +++ b/platform/ontology/transaction_test.go @@ -289,6 +289,6 @@ func TestNormalizeBlock(t *testing.T) { if err != nil { t.Fatal(err) } - want := `[{"id":"266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb","coin":1024,"from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"any_action","memo":"","metadata":{"coin":1024,"title":"Claim Rewards","key":"stake_claim_rewards","token_id":"ong","name":"Ontology Gas","symbol":"ONG","decimals":9,"value":"51000000000000"}},{"id":"2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd","coin":1024,"from":"ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"transfer","memo":"","metadata":{"value":"113.2","symbol":"ONT","decimals":0}},{"id":"40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3","coin":1024,"from":"Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"transfer","memo":"","metadata":{"value":"10949","symbol":"ONT","decimals":0}}]` + want := `[{"id":"266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb","coin":1024,"from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"native_token_transfer","memo":"","metadata":{"name":"Ontology Gas","symbol":"ONG","token_id":"ong","decimals":9,"value":"51000000000000","from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx"}},{"id":"2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd","coin":1024,"from":"ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"transfer","memo":"","metadata":{"value":"113.2","symbol":"ONT","decimals":0}},{"id":"40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3","coin":1024,"from":"Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"transfer","memo":"","metadata":{"value":"10949","symbol":"ONT","decimals":0}}]` assert.Equal(t, want, string(got)) } diff --git a/platform/platform.go b/platform/platform.go new file mode 100644 index 000000000..502ab16ad --- /dev/null +++ b/platform/platform.go @@ -0,0 +1,97 @@ +package platform + +import ( + "fmt" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/aeternity" + "github.com/trustwallet/blockatlas/platform/aion" + "github.com/trustwallet/blockatlas/platform/algorand" + "github.com/trustwallet/blockatlas/platform/binance" + "github.com/trustwallet/blockatlas/platform/bitcoin" + "github.com/trustwallet/blockatlas/platform/cosmos" + "github.com/trustwallet/blockatlas/platform/ethereum" + "github.com/trustwallet/blockatlas/platform/fio" + "github.com/trustwallet/blockatlas/platform/harmony" + "github.com/trustwallet/blockatlas/platform/icon" + "github.com/trustwallet/blockatlas/platform/iotex" + "github.com/trustwallet/blockatlas/platform/nano" + "github.com/trustwallet/blockatlas/platform/nebulas" + "github.com/trustwallet/blockatlas/platform/nimiq" + "github.com/trustwallet/blockatlas/platform/ontology" + "github.com/trustwallet/blockatlas/platform/polkadot" + "github.com/trustwallet/blockatlas/platform/ripple" + "github.com/trustwallet/blockatlas/platform/stellar" + "github.com/trustwallet/blockatlas/platform/tezos" + "github.com/trustwallet/blockatlas/platform/theta" + "github.com/trustwallet/blockatlas/platform/tron" + "github.com/trustwallet/blockatlas/platform/vechain" + "github.com/trustwallet/blockatlas/platform/waves" + "github.com/trustwallet/blockatlas/platform/zilliqa" +) + +func GetVar(name string) string { + return viper.GetString(name) +} + +func GetApiVar(coinId uint) string { + varName := fmt.Sprintf("%s.api", coin.Coins[coinId].Handle) + return GetVar(varName) +} + +func GetRpcVar(coinId uint) string { + varName := fmt.Sprintf("%s.rpc", coin.Coins[coinId].Handle) + return GetVar(varName) +} + +func getPlatformMap() blockatlas.Platforms { + return blockatlas.Platforms{ + coin.Fio().Handle: fio.Init(GetApiVar(coin.FIO)), + coin.Aion().Handle: aion.Init(GetApiVar(coin.AION)), + coin.Icon().Handle: icon.Init(GetApiVar(coin.ICX)), + coin.Tron().Handle: tron.Init(GetApiVar(coin.TRX)), + coin.Nano().Handle: nano.Init(GetApiVar(coin.NANO)), + coin.Nimiq().Handle: nimiq.Init(GetApiVar(coin.NIM)), + coin.Iotex().Handle: iotex.Init(GetApiVar(coin.IOTX)), + coin.Theta().Handle: theta.Init(GetApiVar(coin.THETA)), + coin.Waves().Handle: waves.Init(GetApiVar(coin.WAVES)), + coin.Ripple().Handle: ripple.Init(GetApiVar(coin.XRP)), + coin.Harmony().Handle: harmony.Init(GetApiVar(coin.ONE)), + coin.Vechain().Handle: vechain.Init(GetApiVar(coin.VET)), + coin.Nebulas().Handle: nebulas.Init(GetApiVar(coin.NAS)), + coin.Ontology().Handle: ontology.Init(GetApiVar(coin.ONT)), + coin.Algorand().Handle: algorand.Init(GetApiVar(coin.ALGO)), + coin.Aeternity().Handle: aeternity.Init(GetApiVar(coin.AE)), + coin.Tezos().Handle: tezos.Init(GetApiVar(coin.XTZ), GetRpcVar(coin.XTZ)), + coin.Binance().Handle: binance.Init(GetApiVar(coin.BNB), GetVar("binance.dex")), + coin.Zilliqa().Handle: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL), GetVar("zilliqa.lookup")), + coin.Kusama().Handle: polkadot.Init(coin.KSM, GetApiVar(coin.KSM)), + coin.Stellar().Handle: stellar.Init(coin.XLM, GetApiVar(coin.XLM)), + coin.Kin().Handle: stellar.Init(coin.KIN, GetApiVar(coin.KIN)), + coin.Cosmos().Handle: cosmos.Init(coin.ATOM, GetApiVar(coin.ATOM)), + coin.Kava().Handle: cosmos.Init(coin.KAVA, GetApiVar(coin.KAVA)), + coin.Bitcoin().Handle: bitcoin.Init(coin.BTC, GetApiVar(coin.BTC)), + coin.Litecoin().Handle: bitcoin.Init(coin.LTC, GetApiVar(coin.LTC)), + coin.Bitcoincash().Handle: bitcoin.Init(coin.BCH, GetApiVar(coin.BCH)), + coin.Zcash().Handle: bitcoin.Init(coin.ZEC, GetApiVar(coin.ZEC)), + coin.Zcoin().Handle: bitcoin.Init(coin.XZC, GetApiVar(coin.XZC)), + coin.Viacoin().Handle: bitcoin.Init(coin.VIA, GetApiVar(coin.VIA)), + coin.Ravencoin().Handle: bitcoin.Init(coin.RVN, GetApiVar(coin.RVN)), + coin.Groestlcoin().Handle: bitcoin.Init(coin.GRS, GetApiVar(coin.GRS)), + coin.Zelcash().Handle: bitcoin.Init(coin.ZEL, GetApiVar(coin.ZEL)), + coin.Decred().Handle: bitcoin.Init(coin.DCR, GetApiVar(coin.DCR)), + coin.Digibyte().Handle: bitcoin.Init(coin.DGB, GetApiVar(coin.DGB)), + coin.Dash().Handle: bitcoin.Init(coin.DASH, GetApiVar(coin.DASH)), + coin.Doge().Handle: bitcoin.Init(coin.DOGE, GetApiVar(coin.DOGE)), + coin.Qtum().Handle: bitcoin.Init(coin.QTUM, GetApiVar(coin.QTUM)), + coin.Gochain().Handle: ethereum.Init(coin.GO, GetApiVar(coin.GO), GetRpcVar(coin.GO)), + coin.Thundertoken().Handle: ethereum.Init(coin.TT, GetApiVar(coin.TT), GetRpcVar(coin.TT)), + coin.Classic().Handle: ethereum.Init(coin.ETC, GetApiVar(coin.ETC), GetRpcVar(coin.ETC)), + coin.Poa().Handle: ethereum.Init(coin.POA, GetApiVar(coin.POA), GetRpcVar(coin.POA)), + coin.Callisto().Handle: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO)), + coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN)), + coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), + coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), + } +} diff --git a/platform/polkadot/base.go b/platform/polkadot/base.go index e2342dd47..65d5357ed 100644 --- a/platform/polkadot/base.go +++ b/platform/polkadot/base.go @@ -1,8 +1,6 @@ package polkadot import ( - "fmt" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -12,15 +10,13 @@ type Platform struct { CoinIndex uint } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString(p.ConfigKey()))} - return nil +func Init(coin uint, api string) *Platform { + return &Platform{ + CoinIndex: coin, + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { return coin.Coins[p.CoinIndex] } - -func (p *Platform) ConfigKey() string { - return fmt.Sprintf("%s.api", p.Coin().Handle) -} diff --git a/platform/registry.go b/platform/registry.go index 35a51650b..3c512870b 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -5,84 +5,9 @@ import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform/cosmos" - "github.com/trustwallet/blockatlas/platform/polkadot" - - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/platform/aeternity" - "github.com/trustwallet/blockatlas/platform/aion" - "github.com/trustwallet/blockatlas/platform/algorand" - "github.com/trustwallet/blockatlas/platform/binance" - "github.com/trustwallet/blockatlas/platform/bitcoin" - "github.com/trustwallet/blockatlas/platform/ethereum" - "github.com/trustwallet/blockatlas/platform/fio" - "github.com/trustwallet/blockatlas/platform/harmony" - "github.com/trustwallet/blockatlas/platform/icon" - "github.com/trustwallet/blockatlas/platform/iotex" - "github.com/trustwallet/blockatlas/platform/nano" - "github.com/trustwallet/blockatlas/platform/nebulas" - "github.com/trustwallet/blockatlas/platform/nimiq" - "github.com/trustwallet/blockatlas/platform/ontology" - "github.com/trustwallet/blockatlas/platform/ripple" - "github.com/trustwallet/blockatlas/platform/stellar" - "github.com/trustwallet/blockatlas/platform/tezos" - "github.com/trustwallet/blockatlas/platform/theta" - "github.com/trustwallet/blockatlas/platform/tron" - "github.com/trustwallet/blockatlas/platform/vechain" - "github.com/trustwallet/blockatlas/platform/waves" - "github.com/trustwallet/blockatlas/platform/zilliqa" ) var ( - allPlatformsList = []blockatlas.Platform{ - &binance.Platform{}, - &nimiq.Platform{}, - &ripple.Platform{}, - &stellar.Platform{CoinIndex: coin.XLM}, - &stellar.Platform{CoinIndex: coin.KIN}, - ðereum.Platform{CoinIndex: coin.ETH}, - ðereum.Platform{CoinIndex: coin.ETC}, - ðereum.Platform{CoinIndex: coin.POA}, - ðereum.Platform{CoinIndex: coin.CLO}, - ðereum.Platform{CoinIndex: coin.GO}, - ðereum.Platform{CoinIndex: coin.WAN}, - ðereum.Platform{CoinIndex: coin.TOMO}, - ðereum.Platform{CoinIndex: coin.TT}, - &cosmos.Platform{CoinIndex: coin.ATOM}, - &cosmos.Platform{CoinIndex: coin.KAVA}, - &tezos.Platform{}, - &aion.Platform{}, - &icon.Platform{}, - &iotex.Platform{}, - &ontology.Platform{}, - &theta.Platform{}, - &tron.Platform{}, - &vechain.Platform{}, - &zilliqa.Platform{}, - &waves.Platform{}, - &aeternity.Platform{}, - &bitcoin.Platform{CoinIndex: coin.BTC}, - &bitcoin.Platform{CoinIndex: coin.LTC}, - &bitcoin.Platform{CoinIndex: coin.BCH}, - &bitcoin.Platform{CoinIndex: coin.DASH}, - &bitcoin.Platform{CoinIndex: coin.DOGE}, - &bitcoin.Platform{CoinIndex: coin.ZEC}, - &bitcoin.Platform{CoinIndex: coin.XZC}, - &bitcoin.Platform{CoinIndex: coin.VIA}, - &bitcoin.Platform{CoinIndex: coin.RVN}, - &bitcoin.Platform{CoinIndex: coin.QTUM}, - &bitcoin.Platform{CoinIndex: coin.GRS}, - &bitcoin.Platform{CoinIndex: coin.ZEL}, - &bitcoin.Platform{CoinIndex: coin.DCR}, - &bitcoin.Platform{CoinIndex: coin.DGB}, - &nebulas.Platform{}, - &fio.Platform{}, - &algorand.Platform{}, - &nano.Platform{}, - &harmony.Platform{}, - &polkadot.Platform{CoinIndex: coin.KSM}, - } - // Platforms contains all registered platforms by handle Platforms map[string]blockatlas.Platform @@ -102,113 +27,15 @@ var ( CollectionAPIs map[uint]blockatlas.CollectionAPI ) -func getPlatform(handle string) blockatlas.Platform { - switch handle { - case coin.Binance().Handle: - return &binance.Platform{} - case coin.Nimiq().Handle: - return &nimiq.Platform{} - case coin.Ripple().Handle: - return &ripple.Platform{} - case coin.Stellar().Handle: - return &stellar.Platform{CoinIndex: coin.XLM} - case coin.Kin().Handle: - return &stellar.Platform{CoinIndex: coin.KIN} - case coin.Ethereum().Handle: - return ðereum.Platform{CoinIndex: coin.ETH} - case coin.Classic().Handle: - return ðereum.Platform{CoinIndex: coin.ETC} - case coin.Poa().Handle: - return ðereum.Platform{CoinIndex: coin.POA} - case coin.Callisto().Handle: - return ðereum.Platform{CoinIndex: coin.CLO} - case coin.Gochain().Handle: - return ðereum.Platform{CoinIndex: coin.GO} - case coin.Wanchain().Handle: - return ðereum.Platform{CoinIndex: coin.WAN} - case coin.Tomochain().Handle: - return ðereum.Platform{CoinIndex: coin.TOMO} - case coin.Thundertoken().Handle: - return ðereum.Platform{CoinIndex: coin.TT} - case coin.Cosmos().Handle: - return &cosmos.Platform{CoinIndex: coin.ATOM} - case coin.Kava().Handle: - return &cosmos.Platform{CoinIndex: coin.KAVA} - case coin.Tezos().Handle: - return &tezos.Platform{} - case coin.Aion().Handle: - return &aion.Platform{} - case coin.Icon().Handle: - return &icon.Platform{} - case coin.Iotex().Handle: - return &iotex.Platform{} - case coin.Ontology().Handle: - return &ontology.Platform{} - case coin.Theta().Handle: - return &theta.Platform{} - case coin.Tron().Handle: - return &tron.Platform{} - case coin.Vechain().Handle: - return &vechain.Platform{} - case coin.Zilliqa().Handle: - return &zilliqa.Platform{} - case coin.Waves().Handle: - return &waves.Platform{} - case coin.Aeternity().Handle: - return &aeternity.Platform{} - case coin.Bitcoin().Handle: - return &bitcoin.Platform{CoinIndex: coin.BTC} - case coin.Litecoin().Handle: - return &bitcoin.Platform{CoinIndex: coin.LTC} - case coin.Bitcoincash().Handle: - return &bitcoin.Platform{CoinIndex: coin.BCH} - case coin.Dash().Handle: - return &bitcoin.Platform{CoinIndex: coin.DASH} - case coin.Doge().Handle: - return &bitcoin.Platform{CoinIndex: coin.DOGE} - case coin.Zcash().Handle: - return &bitcoin.Platform{CoinIndex: coin.ZEC} - case coin.Zcoin().Handle: - return &bitcoin.Platform{CoinIndex: coin.XZC} - case coin.Viacoin().Handle: - return &bitcoin.Platform{CoinIndex: coin.VIA} - case coin.Ravencoin().Handle: - return &bitcoin.Platform{CoinIndex: coin.RVN} - case coin.Qtum().Handle: - return &bitcoin.Platform{CoinIndex: coin.QTUM} - case coin.Groestlcoin().Handle: - return &bitcoin.Platform{CoinIndex: coin.GRS} - case coin.Zelcash().Handle: - return &bitcoin.Platform{CoinIndex: coin.ZEL} - case coin.Decred().Handle: - return &bitcoin.Platform{CoinIndex: coin.DCR} - case coin.Digibyte().Handle: - return &bitcoin.Platform{CoinIndex: coin.DGB} - case coin.Nebulas().Handle: - return &nebulas.Platform{} - case coin.Fio().Handle: - return &fio.Platform{} - case coin.Algorand().Handle: - return &algorand.Platform{} - case coin.Nano().Handle: - return &nano.Platform{} - case coin.Harmony().Handle: - return &harmony.Platform{} - case coin.Kusama().Handle: - return &polkadot.Platform{CoinIndex: coin.KSM} - default: - return nil - } -} - func getActivePlatforms(handle string) []blockatlas.Platform { logger.Info("Loaded with: ", logger.Params{"handle": handle}) - platform := getPlatform(handle) - if platform != nil { + platforms := getPlatformMap() + platform, ok := platforms[handle] + if ok { return []blockatlas.Platform{platform} } - return allPlatformsList + return platforms.GetPlatformList() } func Init(platformHandle string) { @@ -240,14 +67,7 @@ func Init(platformHandle string) { if _, exists := Platforms[handle]; exists { logger.Fatal("Duplicate handle", p) } - - err := platform.Init() - if err != nil { - logger.Error("Failed to initialize API", err, p) - } - Platforms[handle] = platform - if blockAPI, ok := platform.(blockatlas.BlockAPI); ok { BlockAPIs[handle] = blockAPI } diff --git a/platform/ripple/base.go b/platform/ripple/base.go index 83be17700..ea0dfc262 100644 --- a/platform/ripple/base.go +++ b/platform/ripple/base.go @@ -1,7 +1,6 @@ package ripple import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("ripple.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/ripple/client.go b/platform/ripple/client.go index 5e8ec7068..b2d080084 100644 --- a/platform/ripple/client.go +++ b/platform/ripple/client.go @@ -13,7 +13,7 @@ type Client struct { func (c *Client) GetTxsOfAddress(address string) ([]Tx, error) { query := url.Values{ "type": {"Payment"}, - "descending": {"true"}, + "descending": {"false"}, "limit": {"200"}, } uri := fmt.Sprintf("accounts/%s/transactions", url.PathEscape(address)) diff --git a/platform/stellar/base.go b/platform/stellar/base.go index 67a7ec704..fe4be7cf2 100644 --- a/platform/stellar/base.go +++ b/platform/stellar/base.go @@ -1,8 +1,6 @@ package stellar import ( - "fmt" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -12,11 +10,11 @@ type Platform struct { CoinIndex uint } -func (p *Platform) Init() error { - handle := coin.Coins[p.CoinIndex].Handle - api := fmt.Sprintf("%s.api", handle) - p.client = Client{blockatlas.InitClient(viper.GetString(api))} - return nil +func Init(coin uint, api string) *Platform { + return &Platform{ + CoinIndex: coin, + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/tezos/base.go b/platform/tezos/base.go index 0aad538cb..bbb3e1c20 100644 --- a/platform/tezos/base.go +++ b/platform/tezos/base.go @@ -1,7 +1,6 @@ package tezos import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -11,11 +10,13 @@ type Platform struct { rpcClient RpcClient } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("tezos.api"))} +func Init(api, rpc string) *Platform { + p := &Platform{ + client: Client{blockatlas.InitClient(api)}, + rpcClient: RpcClient{blockatlas.InitClient(rpc)}, + } p.client.SetTimeout(35) - p.rpcClient = RpcClient{blockatlas.InitClient(viper.GetString("tezos.rpc"))} - return nil + return p } func (p *Platform) Coin() coin.Coin { diff --git a/platform/theta/base.go b/platform/theta/base.go index c7db94c20..317bdcd77 100644 --- a/platform/theta/base.go +++ b/platform/theta/base.go @@ -1,7 +1,6 @@ package theta import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("theta.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/tron/base.go b/platform/tron/base.go index c713d9862..24c15a083 100644 --- a/platform/tron/base.go +++ b/platform/tron/base.go @@ -1,7 +1,6 @@ package tron import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("tron.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/vechain/base.go b/platform/vechain/base.go index 2b6608578..3b5dfa4bb 100644 --- a/platform/vechain/base.go +++ b/platform/vechain/base.go @@ -1,7 +1,6 @@ package vechain import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("vechain.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/waves/base.go b/platform/waves/base.go index 6715d90af..26897e990 100644 --- a/platform/waves/base.go +++ b/platform/waves/base.go @@ -1,7 +1,6 @@ package waves import ( - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -10,9 +9,10 @@ type Platform struct { client Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("waves.api"))} - return nil +func Init(api string) *Platform { + return &Platform{ + client: Client{blockatlas.InitClient(api)}, + } } func (p *Platform) Coin() coin.Coin { diff --git a/platform/zilliqa/base.go b/platform/zilliqa/base.go index 5a0550e07..44602f8f8 100644 --- a/platform/zilliqa/base.go +++ b/platform/zilliqa/base.go @@ -3,8 +3,6 @@ package zilliqa import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - - "github.com/spf13/viper" ) type Platform struct { @@ -13,13 +11,14 @@ type Platform struct { udClient Client } -func (p *Platform) Init() error { - p.client = Client{blockatlas.InitClient(viper.GetString("zilliqa.api"))} - p.client.Headers["X-APIKEY"] = viper.GetString("zilliqa.key") - - p.rpcClient = RpcClient{blockatlas.InitClient(viper.GetString("zilliqa.rpc"))} - p.udClient = Client{blockatlas.InitClient(viper.GetString("zilliqa.lookup"))} - return nil +func Init(api, apiKey, rpc, udClient string) *Platform { + p := &Platform{ + client: Client{blockatlas.InitClient(api)}, + rpcClient: RpcClient{blockatlas.InitClient(rpc)}, + udClient: Client{blockatlas.InitClient(udClient)}, + } + p.client.Headers["X-APIKEY"] = apiKey + return p } func (p *Platform) Coin() coin.Coin { From 3c6d963a6d0ab7281d2438d24697c96c122f81f3 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 22 Feb 2020 00:39:55 +0300 Subject: [PATCH 148/506] Platform init change & postman changes (#902) * Change postman test && currently it will be impossible to ignore platform param * Fix --- cmd/platform_api/main.go | 1 - pkg/tests/postman/transaction_data.json | 2 +- platform/registry.go | 6 +++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index c3bf9a5c0..6f7d69d66 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -14,7 +14,6 @@ import ( const ( defaultPort = "8420" defaultConfigPath = "../../config.yml" - allPlatforms = "all" ) var ( diff --git a/pkg/tests/postman/transaction_data.json b/pkg/tests/postman/transaction_data.json index 4c580cac8..bbc6084d0 100644 --- a/pkg/tests/postman/transaction_data.json +++ b/pkg/tests/postman/transaction_data.json @@ -101,7 +101,7 @@ }, { "handler": "aeternity", - "address": "ak_wTPFpksUJFjjntonTvwK4LJvDw11DPma7kZBneKbumb8yPeFq" + "address": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb" }, { "handler": "aion", diff --git a/platform/registry.go b/platform/registry.go index 3c512870b..b4fb817eb 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -34,8 +34,12 @@ func getActivePlatforms(handle string) []blockatlas.Platform { platform, ok := platforms[handle] if ok { return []blockatlas.Platform{platform} + } else if handle == "all" { + return platforms.GetPlatformList() + } else { + logger.Fatal("Please, use ATLAS_PLATFORM handle with non-empty value", logger.Params{"ATLAS_PLATFORM": handle}) + return nil } - return platforms.GetPlatformList() } func Init(platformHandle string) { From 91640860ef5876c38d543c7db40da28608966647 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 22 Feb 2020 01:30:25 +0300 Subject: [PATCH 149/506] Remove markets (#903) * Remove markets * Update README.md --- Makefile | 29 +- README.md | 20 +- api/maketdata.go | 188 --------- cmd/market_api/main.go | 56 --- cmd/market_observer/main.go | 28 -- config.yml | 23 -- docker-compose.yml | 20 - market/chart/chart.go | 9 - market/chart/cmc/cmc.go | 133 ------- market/chart/cmc/cmc_test.go | 225 ----------- market/chart/coingecko/coingecko.go | 115 ------ market/chart/coingecko/coingecko_test.go | 91 ----- market/chart/provider.go | 22 -- market/charts.go | 83 ---- market/charts_test.go | 168 -------- market/clients/cmc/cache.go | 75 ---- market/clients/cmc/cache_test.go | 89 ----- market/clients/cmc/client.go | 56 --- market/clients/cmc/models.go | 63 --- market/clients/cmc/webclient.go | 32 -- market/clients/cmc/widgetclient.go | 28 -- market/clients/coingecko/cache.go | 120 ------ market/clients/coingecko/cache_test.go | 370 ------------------ market/clients/coingecko/client.go | 104 ----- market/clients/coingecko/client_test.go | 42 -- market/clients/coingecko/models.go | 49 --- market/clients/compound/client.go | 21 - market/clients/compound/models.go | 15 - market/market.go | 67 ---- market/market/cmc/cmc.go | 102 ----- market/market/cmc/cmc_test.go | 93 ----- market/market/coingecko/coingecko.go | 94 ----- market/market/coingecko/coingecko_test.go | 104 ----- market/market/compound/compound.go | 64 --- market/market/compound/compound_test.go | 72 ---- market/market/dex/dex.go | 96 ----- market/market/dex/dex_test.go | 81 ---- market/market/dex/models.go | 8 - market/market/market.go | 46 --- market/market/provider.go | 25 -- market/rate/cmc/cmc.go | 55 --- market/rate/cmc/cmc_test.go | 101 ----- market/rate/coingecko/coingecko.go | 50 --- market/rate/coingecko/coingecko_test.go | 72 ---- market/rate/compound/compound.go | 49 --- market/rate/compound/compound_test.go | 77 ---- market/rate/fixer/fixer.go | 49 --- market/rate/fixer/fixer_test.go | 56 --- market/rate/fixer/models.go | 11 - market/rate/provider.go | 25 -- market/rate/rate.go | 46 --- market/rates.go | 62 --- market/worker.go | 75 ---- .../Blockatlas.postman_collection.json | 4 +- storage/market.go | 83 ---- storage/storage.go | 7 - 56 files changed, 8 insertions(+), 3940 deletions(-) delete mode 100644 api/maketdata.go delete mode 100644 cmd/market_api/main.go delete mode 100644 cmd/market_observer/main.go delete mode 100644 market/chart/chart.go delete mode 100644 market/chart/cmc/cmc.go delete mode 100644 market/chart/cmc/cmc_test.go delete mode 100644 market/chart/coingecko/coingecko.go delete mode 100644 market/chart/coingecko/coingecko_test.go delete mode 100644 market/chart/provider.go delete mode 100644 market/charts.go delete mode 100644 market/charts_test.go delete mode 100644 market/clients/cmc/cache.go delete mode 100644 market/clients/cmc/cache_test.go delete mode 100644 market/clients/cmc/client.go delete mode 100644 market/clients/cmc/models.go delete mode 100644 market/clients/cmc/webclient.go delete mode 100644 market/clients/cmc/widgetclient.go delete mode 100644 market/clients/coingecko/cache.go delete mode 100644 market/clients/coingecko/cache_test.go delete mode 100644 market/clients/coingecko/client.go delete mode 100644 market/clients/coingecko/client_test.go delete mode 100644 market/clients/coingecko/models.go delete mode 100644 market/clients/compound/client.go delete mode 100644 market/clients/compound/models.go delete mode 100644 market/market.go delete mode 100644 market/market/cmc/cmc.go delete mode 100644 market/market/cmc/cmc_test.go delete mode 100644 market/market/coingecko/coingecko.go delete mode 100644 market/market/coingecko/coingecko_test.go delete mode 100644 market/market/compound/compound.go delete mode 100644 market/market/compound/compound_test.go delete mode 100644 market/market/dex/dex.go delete mode 100644 market/market/dex/dex_test.go delete mode 100644 market/market/dex/models.go delete mode 100644 market/market/market.go delete mode 100644 market/market/provider.go delete mode 100644 market/rate/cmc/cmc.go delete mode 100644 market/rate/cmc/cmc_test.go delete mode 100644 market/rate/coingecko/coingecko.go delete mode 100644 market/rate/coingecko/coingecko_test.go delete mode 100644 market/rate/compound/compound.go delete mode 100644 market/rate/compound/compound_test.go delete mode 100644 market/rate/fixer/fixer.go delete mode 100644 market/rate/fixer/fixer_test.go delete mode 100644 market/rate/fixer/models.go delete mode 100644 market/rate/provider.go delete mode 100644 market/rate/rate.go delete mode 100644 market/rates.go delete mode 100644 market/worker.go delete mode 100644 storage/market.go diff --git a/Makefile b/Makefile index cbde91f86..8c9bbd5b5 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,6 @@ PROJECT_NAME := $(shell basename "$(PWD)") API_SERVICE := platform_api OBSERVER_SERVICE := platform_observer OBSERVER_API := observer_api -MARKET_SERVICE := market_observer -MARKET_API := market_api SWAGGER_API := swagger_api COIN_FILE := coin/coins.yml COIN_GO_FILE := coin/coins.go @@ -37,8 +35,6 @@ STDERR := /tmp/.$(PROJECT_NAME)-stderr.txt PID_API := /tmp/.$(PROJECT_NAME).$(API_SERVICE).pid PID_OBSERVER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SERVICE).pid PID_OBSERVER_API := /tmp/.$(PROJECT_NAME).$(OBSERVER_API).pid -PID_MARKET := /tmp/.$(PROJECT_NAME).$(MARKET_SERVICE).pid -PID_MARKET_API := /tmp/.$(PROJECT_NAME).$(MARKET_API).pid PID_SWAGGER_API := /tmp/.$(PROJECT_NAME).$(SWAGGER_API).pid # Make is verbose in Linux. Make it silent. MAKEFLAGS += --silent @@ -71,20 +67,6 @@ start-observer-api: stop @cat $(PID_OBSERVER_API) | sed "/^/s/^/ \> Observer PID: /" @echo " > Error log: $(STDERR)" -## start-sync-market: Start Sync market in development mode. -start-market-observer: stop - @echo " > Starting $(PROJECT_NAME) Sync" - @-$(GOBIN)/$(MARKET_SERVICE)/market_observer -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_MARKET) - @cat $(PID_MARKET) | sed "/^/s/^/ \> Sync PID: /" - @echo " > Error log: $(STDERR)" - -## start-sync-market-api: Start Sync market api in development mode. -start-market-api: stop - @echo " > Starting $(PROJECT_NAME) Sync API" - @-$(GOBIN)/$(MARKET_API)/market_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_MARKET_API) - @cat $(PID_MARKET_API) | sed "/^/s/^/ \> Sync PID: /" - @echo " > Error log: $(STDERR)" - ## start-sync-market-api: Start Sync market api in development mode. start-swagger-api: stop @echo " > Starting $(PROJECT_NAME) Sync API" @@ -94,14 +76,12 @@ start-swagger-api: stop ## stop: Stop development mode. stop: - @-touch $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_API) $(PID_MARKET) $(PID_MARKET_API) $(PID_SWAGGER_API) + @-touch $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_API) $(PID_SWAGGER_API) @-kill `cat $(PID_API)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER_API)` 2> /dev/null || true - @-kill `cat $(PID_MARKET)` 2> /dev/null || true - @-kill `cat $(PID_MARKET_API)` 2> /dev/null || true @-kill `cat $(PID_SWAGGER_API)` 2> /dev/null || true - @-rm $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_API) $(PID_MARKET) $(PID_MARKET_API) $(PID_SWAGGER_API) + @-rm $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_API) $(PID_SWAGGER_API) ## compile: Compile the project. compile: @@ -173,7 +153,6 @@ ifeq (,$(test)) @bash -c "$(MAKE) newman test=domain host=$(host)" @bash -c "$(MAKE) newman test=healthcheck host=$(host)" @bash -c "$(MAKE) newman test=observer host=$(host)" - @bash -c "$(MAKE) newman test=market host=$(host)" else @newman run pkg/tests/postman/Blockatlas.postman_collection.json --folder $(test) -d pkg/tests/postman/$(test)_data.json --env-var "host=$(host)" endif @@ -183,10 +162,6 @@ go-compile: go-get go-build go-build: @echo " > Building platform_api binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API_SERVICE)/platform_api ./cmd/$(API_SERVICE) - @echo " > Building market_observer binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(MARKET_SERVICE)/market_observer ./cmd/$(MARKET_SERVICE) - @echo " > Building market_api binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(MARKET_API)/market_api ./cmd/$(MARKET_API) @echo " > Building platform_observer binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SERVICE)/platform_observer ./cmd/$(OBSERVER_SERVICE) @echo " > Building observer_api binary..." diff --git a/README.md b/README.md index edef03442..de5746f81 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ > BlockAtlas is a clean explorer API and transaction observer for cryptocurrencies. BlockAtlas connects to nodes or explorer APIs of the supported coins and maps transaction data, -account transaction history and market data into a generic, easy to work with JSON format. +account transaction history into a generic, easy to work with JSON format. It is in production use at the [Trust Wallet app](https://trustwallet.com/), the official cryptocurrency wallet of Binance. Also is in production at the [BUTTON Wallet](https://buttonwallet.com), Telegram based non-custodial wallet. The observer API watches the chain for new transactions and generates notifications by webhooks. @@ -52,17 +52,13 @@ There are multiple services: 1. Platform API - to get transactions, staking, tokens, domain lookup for supported coins in common format 2. Observer API - to subscribe several addresses on different supported coins and receive webhook -3. Market API - to get market data from different platforms in common format -4. Swagger API - swagger for all handlers of 1-3 APIs. You need to route requests to them on you own (nginx) +3. Swagger API - swagger for all handlers of 1-3 APIs. You need to route requests to them on you own (nginx) There are workers that are linked with Observer API and Market API: -5. Market Observer - fetching latest rates from multiple external API's and cache it in Redis -6. Platform Observer - fetching latest blocks, parse them to common block specification, check subscribed addresses - send webhook. We use Redis to get information about subscribed addresses per coin with webhooks and caching latest block that was processed by observer - -Market API <-> Redis A <-> Market Observer +5. Platform Observer - fetching latest blocks, parse them to common block specification, check subscribed addresses - send webhook. We use Redis to get information about subscribed addresses per coin with webhooks and caching latest block that was processed by observer -Observer API <-> Redis B <-> Platform Observer +Observer API <-> Redis <-> Platform Observer #### IMPORTANT @@ -83,15 +79,9 @@ cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas # Start platform_observer with the path to the config.yml ./ go build -o platform-observer-bin cmd/platform_observer/main.go && ./platform-observer-bin -c config.yml -# Start markets_observer with the path to the config.yml ./ -go build -o market-observer-bin cmd/market_observer/main.go && ./market-observer-bin -c config.yml - # Start Platform API server at port 8420 with the path to the config.yml ./ go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 -c config.yml -# Start Market API server at port 8421 with the path to the config.yml ./ -go build -o market-api-bin cmd/market_api/main.go && ./market-api-bin -p 8421 -c config.yml - # Start Observer API server at port 8422 with the path to the config.yml ./ go build -o observer-api-bin cmd/observer-api/main.go && ./observer-api-bin -p 8422 -c config.yml @@ -133,8 +123,6 @@ If you need to start one service: docker-compose start platform_api # Run only observer for addresses and api for it docker-compose start platform_observer observer_api redis -# Run markets with it's api -docker-compose start market_observer market_api redis # Run swagger api docker-compose start swagger_api ``` diff --git a/api/maketdata.go b/api/maketdata.go deleted file mode 100644 index aa75953de..000000000 --- a/api/maketdata.go +++ /dev/null @@ -1,188 +0,0 @@ -package api - -import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/market" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/pkg/ginutils/gincache" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/services/assets" - "github.com/trustwallet/blockatlas/storage" - "math/big" - "net/http" - "strconv" - "strings" - "time" -) - -const ( - defaultMaxChartItems = 64 -) - -type TickerRequest struct { - Currency string `json:"currency"` - Assets []Coin `json:"assets"` -} - -type Coin struct { - Coin uint `json:"coin"` - CoinType blockatlas.CoinType `json:"type"` - TokenId string `json:"token_id,omitempty"` -} - -func SetupMarketAPI(router gin.IRouter, db storage.Market) { - router.Use(ginutils.TokenAuthMiddleware(config.Configuration.Market.Auth)) - // Ticker - router.POST("/ticker", getTickersHandler(db)) - // Charts - router.GET("/charts", gincache.CacheMiddleware(time.Minute*5, getChartsHandler())) - router.GET("/info", getCoinInfoHandler()) -} - -// @Summary Get ticker values for a specific market -// @Id get_tickers -// @Description Get the ticker values from many market and coin/token -// @Accept json -// @Produce json -// @Tags Market -// @Param tickers body api.TickerRequest true "Ticker" -// @Success 200 {object} blockatlas.Tickers -// @Router /v1/market/ticker [post] -func getTickersHandler(storage storage.Market) func(c *gin.Context) { - if storage == nil { - return nil - } - return func(c *gin.Context) { - md := TickerRequest{Currency: blockatlas.DefaultCurrency} - if err := c.BindJSON(&md); err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - rate, err := storage.GetRate(strings.ToUpper(md.Currency)) - if err != nil { - logger.Error(err, "Failed to retrieve rate", logger.Params{"currency": md.Currency}) - ginutils.RenderError(c, http.StatusInternalServerError, "Failed to retrieve rate") - return - } - - tickers := make(blockatlas.Tickers, 0) - for _, coinRequest := range md.Assets { - exchangeRate := rate.Rate - percentChange := rate.PercentChange24h - - coinObj, ok := coin.Coins[coinRequest.Coin] - if !ok { - continue - } - r, err := storage.GetTicker(coinObj.Symbol, strings.ToUpper(coinRequest.TokenId)) - if err != nil { - // TODO: either fail the request or signal to requester that ticker for coin couldn't be retrieved - logger.Error(err, "Failed to retrieve ticker", logger.Params{"coin": coinObj.Symbol, "currency": md.Currency}) - continue - } - if r.Price.Currency != blockatlas.DefaultCurrency { - newRate, err := storage.GetRate(strings.ToUpper(r.Price.Currency)) - if err == nil { - exchangeRate *= newRate.Rate - percentChange = newRate.PercentChange24h - } else { - tickerRate, err := storage.GetTicker(strings.ToUpper(r.Price.Currency), "") - if err == nil { - exchangeRate *= tickerRate.Price.Value - percentChange = big.NewFloat(tickerRate.Price.Change24h) - } - } - } - - r.ApplyRate(md.Currency, exchangeRate, percentChange) - r.SetCoinId(coinRequest.Coin) - tickers = append(tickers, r) - } - - ginutils.RenderSuccess(c, blockatlas.TickerResponse{Currency: md.Currency, Docs: tickers}) - } -} - -// @Summary Get charts data for a specific coin -// @Id get_charts_data -// @Description Get the charts data from an market and coin/token -// @Accept json -// @Produce json -// @Tags Market -// @Param coin query int true "Coin ID" default(60) -// @Param token query string false "Token ID" -// @Param time_start query int false "Start timestamp" default(1574483028) -// @Param max_items query int false "Max number of items in result prices array" default(64) -// @Param currency query string false "The currency to show charts" default(USD) -// @Success 200 {object} blockatlas.ChartData -// @Router /v1/market/charts [get] -func getChartsHandler() func(c *gin.Context) { - var charts = market.InitCharts() - return func(c *gin.Context) { - coinQuery := c.Query("coin") - coinId, err := strconv.Atoi(coinQuery) - if err != nil { - ginutils.RenderError(c, http.StatusBadRequest, "Invalid coin") - return - } - token := c.Query("token") - - timeStart, err := strconv.ParseInt(c.Query("time_start"), 10, 64) - if err != nil { - ginutils.RenderError(c, http.StatusBadRequest, "Invalid time_start") - return - } - maxItems, err := strconv.Atoi(c.Query("max_items")) - if err != nil || maxItems <= 0 { - maxItems = defaultMaxChartItems - } - - currency := c.DefaultQuery("currency", blockatlas.DefaultCurrency) - - chart, err := charts.GetChartData(uint(coinId), token, currency, timeStart, maxItems) - if err != nil { - logger.Error(err, "Failed to retrieve chart", logger.Params{"coin": coinId, "currency": currency}) - ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) - return - } - ginutils.RenderSuccess(c, chart) - } -} - -// @Summary Get charts coin info data for a specific coin -// @Id get_charts_coin_info -// @Description Get the charts coin info data from an market and coin/contract -// @Accept json -// @Produce json -// @Tags Market -// @Param coin query int true "Coin ID" default(60) -// @Param token query string false "Token ID" -// @Param time_start query int false "Start timestamp" default(1574483028) -// @Param currency query string false "The currency to show coin info in" default(USD) -// @Success 200 {object} blockatlas.ChartCoinInfo -// @Router /v1/market/info [get] -func getCoinInfoHandler() func(c *gin.Context) { - var charts = market.InitCharts() - return func(c *gin.Context) { - coinQuery := c.Query("coin") - coinId, err := strconv.Atoi(coinQuery) - if err != nil { - ginutils.RenderError(c, http.StatusBadRequest, "Invalid coin") - return - } - - token := c.Query("token") - currency := c.DefaultQuery("currency", blockatlas.DefaultCurrency) - chart, err := charts.GetCoinInfo(uint(coinId), token, currency) - if err != nil { - logger.Error(err, "Failed to retrieve coin info", logger.Params{"coin": coinId, "currency": currency}) - ginutils.RenderError(c, http.StatusInternalServerError, err.Error()) - return - } - chart.Info, _ = assets.GetCoinInfo(coinId, token) - ginutils.RenderSuccess(c, chart) - } -} diff --git a/cmd/market_api/main.go b/cmd/market_api/main.go deleted file mode 100644 index 69310fa66..000000000 --- a/cmd/market_api/main.go +++ /dev/null @@ -1,56 +0,0 @@ -package main - -import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/api" - "github.com/trustwallet/blockatlas/build" - "github.com/trustwallet/blockatlas/config" - _ "github.com/trustwallet/blockatlas/docs" - "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" -) - -const ( - defaultPort = "8421" - defaultConfigPath = "../../config.yml" -) - -var ( - port, confPath string - cache *storage.Storage - sg *gin.HandlerFunc -) - -func init() { - build.LogVersionInfo() - port, confPath, sg, cache = internal.InitAPIWithRedis(defaultPort, defaultConfigPath) -} - -func main() { - gin.SetMode(config.Configuration.Gin.Mode) - - engine := gin.New() - engine.Use(ginutils.CheckReverseProxy, *sg) - engine.Use(ginutils.CORSMiddleware()) - engine.Use(gin.Logger()) - - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) - engine.GET("/", api.GetRoot) - engine.GET("/status", func(c *gin.Context) { - ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, - "version": build.Version, - "build": build.Build, - "date": build.Date, - }) - }) - - logger.Info("Loading market API") - - marketAPI := engine.Group("/v1/market") - - api.SetupMarketAPI(marketAPI, cache) - internal.SetupGracefulShutdown(port, engine) -} diff --git a/cmd/market_observer/main.go b/cmd/market_observer/main.go deleted file mode 100644 index 152fbaeb5..000000000 --- a/cmd/market_observer/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "github.com/trustwallet/blockatlas/build" - "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/market" - "github.com/trustwallet/blockatlas/storage" -) - -const ( - defaultConfigPath = "../../config.yml" -) - -var ( - confPath string - cache *storage.Storage -) - -func init() { - build.LogVersionInfo() - _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) -} - -func main() { - market.InitRates(cache) - market.InitMarkets(cache) - <-make(chan struct{}) -} diff --git a/config.yml b/config.yml index dd2b953e3..7d232e425 100644 --- a/config.yml +++ b/config.yml @@ -30,29 +30,6 @@ observer: min: 3s max: 30s -# The market watcher -market: - enabled: false - quote_update_time: 20m - rate_update_time: 20m - dex: - quote_update_time: 5m - api: https://dex.binance.org/api - cmc: - api: https://pro-api.coinmarketcap.com - webapi: https://web-api.coinmarketcap.com - widgetapi: https://widgets.coinmarketcap.com - api_key: - map_url: https://raw.githubusercontent.com/trustwallet/assets/master/pricing/coinmarketcap - fixer: - rate_update_time: 1h - api: https://data.fixer.io/api - api_key: - compound: - api: https://api.compound.finance/api - coingecko: - api: https://api.coingecko.com/api - storage: redis: redis://redis:6379 diff --git a/docker-compose.yml b/docker-compose.yml index a18c8d61d..6bb3a2dbf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,25 +1,5 @@ version: '3.7' services: - market_api: - container_name: market_api - build: - context: . - args: - - SERVICE=market_api - ports: - - 8421:8421 - links: - - redis - - market_observer: - container_name: market_observer - build: - context: . - args: - - SERVICE=market_observer - links: - - redis - observer_api: container_name: observer_api build: diff --git a/market/chart/chart.go b/market/chart/chart.go deleted file mode 100644 index 922fecf7a..000000000 --- a/market/chart/chart.go +++ /dev/null @@ -1,9 +0,0 @@ -package chart - -type Chart struct { - Id string -} - -func (c *Chart) GetId() string { - return c.Id -} diff --git a/market/chart/cmc/cmc.go b/market/chart/cmc/cmc.go deleted file mode 100644 index e949463a1..000000000 --- a/market/chart/cmc/cmc.go +++ /dev/null @@ -1,133 +0,0 @@ -package cmc - -import ( - "github.com/trustwallet/blockatlas/market/chart" - "github.com/trustwallet/blockatlas/market/clients/cmc" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "time" -) - -const ( - id = "cmc" - chartDataSize = 3 -) - -type Chart struct { - chart.Chart - mapApi string - webClient *cmc.WebClient - widgetClient *cmc.WidgetClient -} - -func InitChart(webApi string, widgetApi string, mapApi string) chart.Provider { - m := &Chart{ - Chart: chart.Chart{ - Id: id, - }, - mapApi: mapApi, - webClient: cmc.NewWebClient(webApi), - widgetClient: cmc.NewWidgetClient(widgetApi), - } - return m -} - -func (c *Chart) GetChartData(coin uint, token string, currency string, timeStart int64) (blockatlas.ChartData, error) { - chartsData := blockatlas.ChartData{} - cmap, err := cmc.GetCoinMap(c.mapApi) - if err != nil { - return chartsData, err - } - coinObj, err := cmap.GetCoinByContract(coin, token) - if err != nil { - return chartsData, err - } - - timeStartDate := time.Unix(timeStart, 0) - days := int(time.Since(timeStartDate).Hours() / 24) - timeEnd := time.Now().Unix() - charts, err := c.webClient.GetChartsData(coinObj.Id, currency, timeStart, timeEnd, getInterval(days)) - if err != nil { - return chartsData, err - } - - return normalizeCharts(currency, charts), nil -} - -func (c *Chart) GetCoinData(coin uint, token string, currency string) (blockatlas.ChartCoinInfo, error) { - info := blockatlas.ChartCoinInfo{} - - cmap, err := cmc.GetCoinMap(c.mapApi) - if err != nil { - return info, err - } - coinObj, err := cmap.GetCoinByContract(coin, token) - if err != nil { - return info, err - } - - data, err := c.widgetClient.GetCoinData(coinObj.Id, currency) - if err != nil { - return info, err - } - - return normalizeInfo(currency, coinObj.Id, data) -} - -func normalizeCharts(currency string, charts cmc.Charts) blockatlas.ChartData { - chartsData := blockatlas.ChartData{} - prices := make([]blockatlas.ChartPrice, 0) - for dateSrt, q := range charts.Data { - date, err := time.Parse(time.RFC3339, dateSrt) - if err != nil { - continue - } - - quote, ok := q[currency] - if !ok { - continue - } - - if len(quote) < chartDataSize { - continue - } - prices = append(prices, blockatlas.ChartPrice{ - Price: quote[0], - Date: date.Unix(), - }) - } - - chartsData.Prices = prices - - return chartsData -} - -func normalizeInfo(currency string, cmcCoin uint, data cmc.ChartInfo) (blockatlas.ChartCoinInfo, error) { - info := blockatlas.ChartCoinInfo{} - quote, ok := data.Data.Quotes[currency] - if !ok { - return info, errors.E("Cant get coin info", errors.Params{"cmcCoin": cmcCoin, "currency": currency}) - } - - return blockatlas.ChartCoinInfo{ - Vol24: quote.Volume24, - MarketCap: quote.MarketCap, - CirculatingSupply: data.Data.CirculatingSupply, - TotalSupply: data.Data.TotalSupply, - }, nil -} - -func getInterval(days int) string { - switch d := days; { - case d >= 360: - return "1d" - case d >= 90: - return "2h" - case d >= 30: - return "1h" - case d >= 7: - return "15m" - default: - return "5m" - } -} diff --git a/market/chart/cmc/cmc_test.go b/market/chart/cmc/cmc_test.go deleted file mode 100644 index e97e0474a..000000000 --- a/market/chart/cmc/cmc_test.go +++ /dev/null @@ -1,225 +0,0 @@ -package cmc - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/market/clients/cmc" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "reflect" - "sort" - "testing" - "time" -) - -func Test_normalizeInfo(t *testing.T) { - type args struct { - currency string - cmcCoin uint - data cmc.ChartInfo - } - tests := []struct { - name string - args args - wantInfo blockatlas.ChartCoinInfo - }{ - { - "test normalize cmc chart info 1", - args{ - currency: "USD", - cmcCoin: 1, - data: cmc.ChartInfo{ - Data: cmc.ChartInfoData{ - Rank: 1, - CirculatingSupply: 111, - TotalSupply: 222, - Quotes: map[string]cmc.ChartInfoQuote{ - "USD": {Price: 333, Volume24: 444, MarketCap: 555}, - }, - }, - }, - }, - blockatlas.ChartCoinInfo{ - Vol24: 444, - MarketCap: 555, - CirculatingSupply: 111, - TotalSupply: 222, - }, - }, - { - "test normalize cmc chart info 2", - args{ - currency: "EUR", - cmcCoin: 2, - data: cmc.ChartInfo{ - Data: cmc.ChartInfoData{ - Rank: 2, - CirculatingSupply: 111, - TotalSupply: 222, - Quotes: map[string]cmc.ChartInfoQuote{ - "EUR": {Price: 333, Volume24: 444, MarketCap: 555}, - }, - }, - }, - }, - blockatlas.ChartCoinInfo{ - Vol24: 444, - MarketCap: 555, - CirculatingSupply: 111, - TotalSupply: 222, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotInfo, err := normalizeInfo(tt.args.currency, tt.args.cmcCoin, tt.args.data) - assert.Nil(t, err) - assert.True(t, reflect.DeepEqual(tt.wantInfo, gotInfo)) - }) - } -} - -func Test_normalizeCharts(t *testing.T) { - type args struct { - currency string - symbol string - charts cmc.Charts - } - - timeStr1 := "2019-12-19T18:27:23.453Z" - d1, _ := time.Parse(time.RFC3339, timeStr1) - timeStr2 := "2019-11-19T18:27:23.453Z" - d2, _ := time.Parse(time.RFC3339, timeStr2) - tests := []struct { - name string - args args - wantInfo blockatlas.ChartData - }{ - { - "test normalize cmc chart 1", - args{ - currency: "USD", - symbol: "BTC", - charts: cmc.Charts{ - Data: cmc.ChartQuotes{ - timeStr1: cmc.ChartQuoteValues{ - "USD": []float64{111, 222, 333}, - }, - }, - }, - }, - blockatlas.ChartData{ - Prices: []blockatlas.ChartPrice{ - { - Price: 111, - Date: d1.Unix(), - }, - }, - }, - }, - { - "test normalize cmc chart 2", - args{ - currency: "EUR", - symbol: "BTC", - charts: cmc.Charts{ - Data: cmc.ChartQuotes{ - timeStr1: cmc.ChartQuoteValues{ - "EUR": []float64{333, 444, 555}, - }, - timeStr2: cmc.ChartQuoteValues{ - "EUR": []float64{555, 666, 777}, - }, - }, - }, - }, - blockatlas.ChartData{ - Prices: []blockatlas.ChartPrice{ - { - Price: 333, - Date: d1.Unix(), - }, - { - Price: 555, - Date: d2.Unix(), - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotInfo := normalizeCharts(tt.args.currency, tt.args.charts) - sort.SliceStable(gotInfo.Prices, func(i, j int) bool { - return gotInfo.Prices[i].Price < gotInfo.Prices[j].Price - }) - if !assert.ObjectsAreEqualValues(tt.wantInfo, gotInfo) { - t.Errorf("normalizeCharts() = %v, want %v", gotInfo, tt.wantInfo) - } - }) - } -} - -func Test_getInterval(t *testing.T) { - tests := []struct { - name string - days int - wantInfo string - }{ - { - "test getInterval 1", - 1, - "5m", - }, - { - "test getInterval 2", - 5, - "5m", - }, - { - "test getInterval 3", - 7, - "15m", - }, - { - "test getInterval 4", - 8, - "15m", - }, - { - "test getInterval 5", - 30, - "1h", - }, - { - "test getInterval 6", - 40, - "1h", - }, - { - "test getInterval 7", - 90, - "2h", - }, - { - "test getInterval 8", - 120, - "2h", - }, - { - "test getInterval 9", - 360, - "1d", - }, - { - "test getInterval 10", - 800, - "1d", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotInfo := getInterval(tt.days) - assert.Equal(t, tt.wantInfo, gotInfo) - }) - } -} diff --git a/market/chart/coingecko/coingecko.go b/market/chart/coingecko/coingecko.go deleted file mode 100644 index cad5d4ddc..000000000 --- a/market/chart/coingecko/coingecko.go +++ /dev/null @@ -1,115 +0,0 @@ -package coingecko - -import ( - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/market/chart" - "github.com/trustwallet/blockatlas/market/clients/coingecko" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "time" -) - -const ( - id = "coingecko" - chartDataSize = 2 -) - -type Chart struct { - chart.Chart - client *coingecko.Client -} - -func InitChart(api string) chart.Provider { - m := &Chart{ - Chart: chart.Chart{ - Id: id, - }, - client: coingecko.NewClient(api), - } - return m -} - -func (c *Chart) GetChartData(coinId uint, token string, currency string, timeStart int64) (blockatlas.ChartData, error) { - chartsData := blockatlas.ChartData{} - coins, err := c.client.FetchCoinsList() - if err != nil { - return chartsData, err - } - cache := coingecko.NewSymbolsCache(coins) - - coinResult, err := getCoinObj(cache, coinId, token) - if err != nil { - return chartsData, err - } - - timeEndDate := time.Now().Unix() - charts, err := c.client.GetChartsData(coinResult.Id, currency, timeStart, timeEndDate) - if err != nil { - return chartsData, err - } - - return normalizeCharts(charts), nil -} - -func (c *Chart) GetCoinData(coinId uint, token string, currency string) (blockatlas.ChartCoinInfo, error) { - coins, err := c.client.FetchCoinsList() - if err != nil { - return blockatlas.ChartCoinInfo{}, err - } - cache := coingecko.NewSymbolsCache(coins) - - coinResult, err := getCoinObj(cache, coinId, token) - if err != nil { - return blockatlas.ChartCoinInfo{}, err - } - - data := c.client.FetchLatestRates(coingecko.GeckoCoins{coinResult}, currency) - if len(data) == 0 { - return blockatlas.ChartCoinInfo{}, errors.E("No rates found", errors.Params{"id": coinResult.Id}) - } - return normalizeInfo(data[0]), nil -} - -func getCoinObj(cache *coingecko.SymbolsCache, coinId uint, token string) (coingecko.GeckoCoin, error) { - c := coingecko.GeckoCoin{} - coinObj, ok := coin.Coins[coinId] - if !ok { - return c, errors.E("Coin not found", errors.Params{"coindId": coinId}) - } - - c, err := cache.GetCoinsBySymbol(coinObj.Symbol, token) - if err != nil { - return c, err - } - - return c, nil -} - -func normalizeCharts(charts coingecko.Charts) blockatlas.ChartData { - chartsData := blockatlas.ChartData{} - prices := make([]blockatlas.ChartPrice, 0) - for _, quote := range charts.Prices { - if len(quote) != chartDataSize { - continue - } - - date := time.Unix(int64(quote[0])/1000, 0) - prices = append(prices, blockatlas.ChartPrice{ - Price: quote[1], - Date: date.Unix(), - }) - } - - chartsData.Prices = prices - - return chartsData -} - -func normalizeInfo(data coingecko.CoinPrice) blockatlas.ChartCoinInfo { - return blockatlas.ChartCoinInfo{ - Vol24: data.TotalVolume, - MarketCap: data.MarketCap, - CirculatingSupply: data.CirculatingSupply, - TotalSupply: data.TotalSupply, - } -} diff --git a/market/chart/coingecko/coingecko_test.go b/market/chart/coingecko/coingecko_test.go deleted file mode 100644 index f7a845fee..000000000 --- a/market/chart/coingecko/coingecko_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package coingecko - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/market/clients/coingecko" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "reflect" - "testing" - "time" -) - -func Test_normalizeInfo(t *testing.T) { - type args struct { - data coingecko.CoinPrice - } - tests := []struct { - name string - args args - wantInfo blockatlas.ChartCoinInfo - }{ - { - "test normalize coingecko chart info 1", - args{ - data: coingecko.CoinPrice{ - MarketCap: 555, - TotalVolume: 444, - CirculatingSupply: 111, - TotalSupply: 222, - }, - }, - blockatlas.ChartCoinInfo{ - Vol24: 444, - MarketCap: 555, - CirculatingSupply: 111, - TotalSupply: 222, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotInfo := normalizeInfo(tt.args.data) - assert.True(t, reflect.DeepEqual(tt.wantInfo, gotInfo)) - }) - } -} - -func Test_normalizeCharts(t *testing.T) { - type args struct { - charts coingecko.Charts - } - - timeStr1 := "2019-12-19T18:27:23.453Z" - d1, _ := time.Parse(time.RFC3339, timeStr1) - timeStr2 := "2019-11-19T18:27:23.453Z" - d2, _ := time.Parse(time.RFC3339, timeStr2) - tests := []struct { - name string - args args - wantInfo blockatlas.ChartData - }{ - { - "test normalize coingecko chart 1", - args{ - charts: coingecko.Charts{ - Prices: []coingecko.ChartVolume{ - []float64{float64(d1.UnixNano() / int64(time.Millisecond)), 222}, - []float64{float64(d2.UnixNano() / int64(time.Millisecond)), 333}, - }, - }, - }, - blockatlas.ChartData{ - Prices: []blockatlas.ChartPrice{ - { - Price: 222, - Date: d1.Unix(), - }, - { - Price: 333, - Date: d2.Unix(), - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotInfo := normalizeCharts(tt.args.charts) - assert.True(t, reflect.DeepEqual(tt.wantInfo, gotInfo)) - }) - } -} diff --git a/market/chart/provider.go b/market/chart/provider.go deleted file mode 100644 index 0ae1bc277..000000000 --- a/market/chart/provider.go +++ /dev/null @@ -1,22 +0,0 @@ -package chart - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) - -type Provider interface { - GetId() string - GetChartData(coin uint, token string, currency string, timeStart int64) (blockatlas.ChartData, error) - GetCoinData(coin uint, token string, currency string) (blockatlas.ChartCoinInfo, error) -} - -type Providers map[int]Provider - -func (ps Providers) GetPriority(providerId string) int { - for priority, provider := range ps { - if provider.GetId() == providerId { - return priority - } - } - return -1 -} diff --git a/market/charts.go b/market/charts.go deleted file mode 100644 index 3b2835009..000000000 --- a/market/charts.go +++ /dev/null @@ -1,83 +0,0 @@ -package market - -import ( - "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/market/chart" - "github.com/trustwallet/blockatlas/market/chart/cmc" - "github.com/trustwallet/blockatlas/market/chart/coingecko" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/numbers" - "math" - "sort" -) - -const ( - minUnixTime = 1000000000 -) - -type Charts struct { - chartProviders chart.Providers -} - -func InitCharts() *Charts { - return &Charts{chart.Providers{ - 0: cmc.InitChart( - config.Configuration.Market.Cmc.WebAPI, - config.Configuration.Market.Cmc.WidgetAPI, - config.Configuration.Market.Cmc.MapURL, - ), - 1: coingecko.InitChart( - config.Configuration.Market.Coingecko.API, - ), - }} -} - -func (c *Charts) GetChartData(coin uint, token string, currency string, timeStart int64, maxItems int) (blockatlas.ChartData, error) { - chartsData := blockatlas.ChartData{} - timeStart = numbers.Max(timeStart, minUnixTime) - for i := 0; i < len(c.chartProviders); i++ { - c := c.chartProviders[i] - charts, err := c.GetChartData(coin, token, currency, timeStart) - if err != nil { - continue - } - charts.Prices = normalizePrices(charts.Prices, maxItems) - return charts, nil - } - return chartsData, errors.E("No chart data found", errors.Params{"coin": coin, "token": token}) -} - -func (c *Charts) GetCoinInfo(coin uint, token string, currency string) (blockatlas.ChartCoinInfo, error) { - coinInfoData := blockatlas.ChartCoinInfo{} - for i := 0; i < len(c.chartProviders); i++ { - c := c.chartProviders[i] - info, err := c.GetCoinData(coin, token, currency) - if err != nil { - continue - } - return info, nil - } - return coinInfoData, errors.E("No chart coin info data found", errors.Params{"coin": coin, "token": token}) -} - -func normalizePrices(prices []blockatlas.ChartPrice, maxItems int) (result []blockatlas.ChartPrice) { - sort.Slice(prices, func(p, q int) bool { - return prices[p].Date < prices[q].Date - }) - if len(prices) > maxItems && maxItems > 0 { - skip := int(math.Ceil(float64(len(prices) / maxItems))) - i := 0 - for i < len(prices) { - result = append(result, prices[i]) - i += skip + 1 - } - lastPrice := prices[len(prices)-1] - if len(result) > 0 && lastPrice.Date != result[len(result)-1].Date { - result = append(result, lastPrice) - } - } else { - result = prices - } - return -} diff --git a/market/charts_test.go b/market/charts_test.go deleted file mode 100644 index f4bdf7a54..000000000 --- a/market/charts_test.go +++ /dev/null @@ -1,168 +0,0 @@ -package market - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "reflect" - "testing" -) - -func Test_normalizeInfo(t *testing.T) { - type args struct { - prices []blockatlas.ChartPrice - maxItems int - } - tests := []struct { - args args - wantInfo []blockatlas.ChartPrice - }{ - { - args{ - prices: []blockatlas.ChartPrice{ - { - Price: 1, - Date: 1578741541, - }, - { - Price: 1, - Date: 1578741542, - }, - { - Price: 1, - Date: 1578741549, - }, - { - Price: 1, - Date: 1578741545, - }, - { - Price: 1, - Date: 1578741547, - }, - { - Price: 1, - Date: 1578741546, - }, - }, - maxItems: 3, - }, - []blockatlas.ChartPrice{ - { - Price: 1, - Date: 1578741541, - }, - { - Price: 1, - Date: 1578741546, - }, - { - Price: 1, - Date: 1578741549, - }, - }, - }, - { - args{ - prices: []blockatlas.ChartPrice{ - { - Price: 1, - Date: 1578741541, - }, - { - Price: 1, - Date: 1578741542, - }, - { - Price: 1, - Date: 1578741549, - }, - { - Price: 1, - Date: 1578741545, - }, - { - Price: 1, - Date: 1578741547, - }, - { - Price: 1, - Date: 1578741546, - }, - }, - maxItems: 20, - }, - []blockatlas.ChartPrice{ - { - Price: 1, - Date: 1578741541, - }, - { - Price: 1, - Date: 1578741542, - }, - { - Price: 1, - Date: 1578741545, - }, - { - Price: 1, - Date: 1578741546, - }, - { - Price: 1, - Date: 1578741547, - }, - { - Price: 1, - Date: 1578741549, - }, - }, - }, - { - args{ - prices: []blockatlas.ChartPrice{ - { - Price: 1, - Date: 1578741541, - }, - { - Price: 1, - Date: 1578741542, - }, - { - Price: 1, - Date: 1578741545, - }, - { - Price: 1, - Date: 1578741547, - }, - { - Price: 1, - Date: 1578741546, - }, - }, - maxItems: 3, - }, - []blockatlas.ChartPrice{ - { - Price: 1, - Date: 1578741541, - }, - { - Price: 1, - Date: 1578741545, - }, - { - Price: 1, - Date: 1578741547, - }, - }, - }, - } - for _, tt := range tests { - t.Run("Test prices normalize", func(t *testing.T) { - assert.True(t, reflect.DeepEqual(normalizePrices(tt.args.prices, tt.args.maxItems), tt.wantInfo)) - }) - } -} diff --git a/market/clients/cmc/cache.go b/market/clients/cmc/cache.go deleted file mode 100644 index 19edd520c..000000000 --- a/market/clients/cmc/cache.go +++ /dev/null @@ -1,75 +0,0 @@ -package cmc - -import ( - "fmt" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" -) - -type CoinMap struct { - Coin uint `json:"coin"` - Id uint `json:"id"` - Type string `json:"type"` - TokenId string `json:"token_id"` -} - -type CoinResult struct { - Id uint - Coin coin.Coin - TokenId string - CoinType blockatlas.CoinType -} - -type CmcSlice []CoinMap -type CoinMapping map[string]CoinMap -type CmcMapping map[uint][]CoinMap - -func (c *CmcSlice) coinToCmcMap() (m CoinMapping) { - m = make(map[string]CoinMap) - for _, cm := range *c { - m[generateId(cm.Coin, cm.TokenId)] = cm - } - return -} - -func (c *CmcSlice) cmcToCoinMap() (m CmcMapping) { - m = make(map[uint][]CoinMap) - for _, cm := range *c { - _, ok := m[cm.Id] - if !ok { - m[cm.Id] = make([]CoinMap, 0) - } - m[cm.Id] = append(m[cm.Id], cm) - } - return -} - -func (cm CmcMapping) GetCoins(coinId uint) ([]CoinResult, error) { - cmcCoin, ok := cm[coinId] - if !ok { - return nil, errors.E("CmcMapping.getCoin: coinId notFound") - } - tokens := make([]CoinResult, 0) - for _, cc := range cmcCoin { - c, ok := coin.Coins[cc.Coin] - if !ok { - continue - } - tokens = append(tokens, CoinResult{Coin: c, Id: cc.Id, TokenId: cc.TokenId, CoinType: blockatlas.CoinType(cc.Type)}) - } - return tokens, nil -} - -func (cm CoinMapping) GetCoinByContract(coinId uint, contract string) (c CoinMap, err error) { - c, ok := cm[generateId(coinId, contract)] - if !ok { - err = errors.E("No coin found", errors.Params{"coin": coinId, "token": contract}) - } - - return -} - -func generateId(id uint, token string) string { - return fmt.Sprintf("%d:%s", id, token) -} diff --git a/market/clients/cmc/cache_test.go b/market/clients/cmc/cache_test.go deleted file mode 100644 index 02d2c14d7..000000000 --- a/market/clients/cmc/cache_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package cmc - -import ( - "reflect" - "testing" -) - -func TestCmcMapping_cmcToCoinMap(t *testing.T) { - tests := []struct { - name string - c CmcSlice - wantM CmcMapping - }{ - { - "parse mapping 1", - CmcSlice{{Id: 3}, {Id: 10}, {Id: 44}}, - map[uint][]CoinMap{3: {{Id: 3}}, 10: {{Id: 10}}, 44: {{Id: 44}}}}, - { - "parse mapping 2", - CmcSlice{{Id: 3}, {Id: 10}}, - map[uint][]CoinMap{3: {{Id: 3}}, 10: {{Id: 10}}}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if gotM := tt.c.cmcToCoinMap(); !reflect.DeepEqual(gotM, tt.wantM) { - t.Errorf("cmcToCoinMap() = %v, want %v", gotM, tt.wantM) - } - }) - } -} - -func TestCmcMapping_coinToCmcMap(t *testing.T) { - tests := []struct { - name string - c CmcSlice - wantM CoinMapping - }{ - { - "parse mapping 1", - CmcSlice{{Coin: 60, Id: 3, TokenId: "3211"}, {Coin: 60, Id: 10}, {Coin: 61, Id: 44}}, - CoinMapping{generateId(60, "3211"): {Id: 3, Coin: 60, TokenId: "3211"}, generateId(60, ""): {Coin: 60, Id: 10}, generateId(61, ""): {Coin: 61, Id: 44}}}, - { - "parse mapping 2", - CmcSlice{{Coin: 60, Id: 3}, {Coin: 61, Id: 10}}, - CoinMapping{generateId(60, ""): {Coin: 60, Id: 3, TokenId: ""}, generateId(61, ""): {Coin: 61, Id: 10}}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if gotM := tt.c.coinToCmcMap(); !reflect.DeepEqual(gotM, tt.wantM) { - t.Errorf("coinToCmcMap() = %v, want %v", gotM, tt.wantM) - } - }) - } -} - -func Test_generateId(t *testing.T) { - type args struct { - coin uint - token string - } - tests := []struct { - name string - args args - want string - }{ - { - "generate id 1", - args{coin: 60, token: ""}, - "60:", - }, - { - "generate id 2", - args{coin: 60, token: "12"}, - "60:12", - }, - { - "generate id 2", - args{coin: 185, token: "12"}, - "185:12", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := generateId(tt.args.coin, tt.args.token); !reflect.DeepEqual(got, tt.want) { - t.Errorf("generateId() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/market/clients/cmc/client.go b/market/clients/cmc/client.go deleted file mode 100644 index f10829f8e..000000000 --- a/market/clients/cmc/client.go +++ /dev/null @@ -1,56 +0,0 @@ -package cmc - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "net/url" - "time" -) - -type Client struct { - apiKey string - blockatlas.Request -} - -func NewClient(api string, key string) *Client { - c := Client{ - Request: blockatlas.InitClient(api), - apiKey: key, - } - c.Headers["X-CMC_PRO_API_KEY"] = key - return &c -} - -func (c *Client) GetData() (prices CoinPrices, err error) { - err = c.Get(&prices, "v1/cryptocurrency/listings/latest", - url.Values{"limit": {"5000"}, "convert": {blockatlas.DefaultCurrency}}) - return -} - -func GetCmcMap(mapApi string) (CmcMapping, error) { - var results CmcSlice - request := blockatlas.Request{ - BaseUrl: mapApi, - HttpClient: blockatlas.DefaultClient, - ErrorHandler: blockatlas.DefaultErrorHandler, - } - err := request.GetWithCache(&results, "mapping.json", nil, time.Hour*1) - if err != nil { - return nil, errors.E(err).PushToSentry() - } - return results.cmcToCoinMap(), nil -} - -func GetCoinMap(mapApi string) (CoinMapping, error) { - var results CmcSlice - request := blockatlas.Request{ - BaseUrl: mapApi, - HttpClient: blockatlas.DefaultClient, - ErrorHandler: blockatlas.DefaultErrorHandler, - } - err := request.GetWithCache(&results, "mapping.json", nil, time.Hour*1) - if err != nil { - return nil, errors.E(err).PushToSentry() - } - return results.coinToCmcMap(), nil -} diff --git a/market/clients/cmc/models.go b/market/clients/cmc/models.go deleted file mode 100644 index d4b3bd5f7..000000000 --- a/market/clients/cmc/models.go +++ /dev/null @@ -1,63 +0,0 @@ -package cmc - -import "time" - -type Charts struct { - Data ChartQuotes `json:"data"` -} - -type ChartQuotes map[string]ChartQuoteValues - -type ChartQuoteValues map[string][]float64 - -type ChartInfo struct { - Data ChartInfoData `json:"data"` -} - -type ChartInfoData struct { - Rank uint32 `json:"rank"` - CirculatingSupply float64 `json:"circulating_supply"` - TotalSupply float64 `json:"total_supply"` - Quotes map[string]ChartInfoQuote `json:"quotes"` -} - -type ChartInfoQuote struct { - Price float64 `json:"price"` - Volume24 float64 `json:"volume_24h"` - MarketCap float64 `json:"market_cap"` -} - -type CoinPrices struct { - Status struct { - Timestamp time.Time `json:"timestamp"` - ErrorCode int `json:"error_code"` - ErrorMessage interface{} `json:"error_message"` - } `json:"status"` - Data []Data `json:"data"` -} - -type Coin struct { - Id uint `json:"id"` - Symbol string `json:"symbol"` -} - -type Data struct { - Coin - LastUpdated time.Time `json:"last_updated"` - Platform *Platform `json:"platform"` - Quote Quote `json:"quote"` -} - -type Platform struct { - Coin - TokenAddress string `json:"token_address"` -} - -type Quote struct { - USD USD `json:"USD"` -} - -type USD struct { - Price float64 `json:"price"` - PercentChange24h float64 `json:"percent_change_24h"` -} diff --git a/market/clients/cmc/webclient.go b/market/clients/cmc/webclient.go deleted file mode 100644 index 7abd4a55e..000000000 --- a/market/clients/cmc/webclient.go +++ /dev/null @@ -1,32 +0,0 @@ -package cmc - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "net/url" - "strconv" - "time" -) - -type WebClient struct { - blockatlas.Request -} - -func NewWebClient(api string) *WebClient { - c := WebClient{ - Request: blockatlas.InitClient(api), - } - return &c -} - -func (c *WebClient) GetChartsData(id uint, currency string, timeStart int64, timeEnd int64, interval string) (charts Charts, err error) { - values := url.Values{ - "convert": {currency}, - "format": {"chart_crypto_details"}, - "id": {strconv.FormatInt(int64(id), 10)}, - "time_start": {strconv.FormatInt(timeStart, 10)}, - "time_end": {strconv.FormatInt(timeEnd, 10)}, - "interval": {interval}, - } - err = c.GetWithCache(&charts, "v1/cryptocurrency/quotes/historical", values, time.Minute*5) - return -} diff --git a/market/clients/cmc/widgetclient.go b/market/clients/cmc/widgetclient.go deleted file mode 100644 index 6bbbf158c..000000000 --- a/market/clients/cmc/widgetclient.go +++ /dev/null @@ -1,28 +0,0 @@ -package cmc - -import ( - "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "net/url" - "time" -) - -type WidgetClient struct { - blockatlas.Request -} - -func NewWidgetClient(api string) *WidgetClient { - c := WidgetClient{ - Request: blockatlas.InitClient(api), - } - return &c -} - -func (c *WidgetClient) GetCoinData(id uint, currency string) (charts ChartInfo, err error) { - values := url.Values{ - "convert": {currency}, - "ref": {"widget"}, - } - err = c.GetWithCache(&charts, fmt.Sprintf("v2/ticker/%d", id), values, time.Minute*5) - return -} diff --git a/market/clients/coingecko/cache.go b/market/clients/coingecko/cache.go deleted file mode 100644 index d343ce61c..000000000 --- a/market/clients/coingecko/cache.go +++ /dev/null @@ -1,120 +0,0 @@ -package coingecko - -import ( - "fmt" - "github.com/trustwallet/blockatlas/pkg/address" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "strings" -) - -type Cache map[string][]CoinResult -type SymbolsCache map[string]GeckoCoin - -const ( - PlatformEthereum = "ethereum" - PlatformClassic = "ethereum-classic" -) - -func (c Cache) GetCoinsById(id string) (coins []CoinResult, err error) { - coins, ok := c[id] - if !ok { - err = errors.E("No coin found by id", errors.Params{"id": id}) - } - return -} - -func (c SymbolsCache) generateId(symbol, token string) string { - if len(token) > 0 { - return fmt.Sprintf("%s:%s", strings.ToUpper(symbol), address.EIP55Checksum(token)) - } - return strings.ToUpper(symbol) -} - -func (c SymbolsCache) GetCoinsBySymbol(symbol, token string) (coin GeckoCoin, err error) { - coin, ok := c[c.generateId(symbol, token)] - if !ok { - err = errors.E("No coin found by symbol", errors.Params{"symbol": symbol, "token": token}) - } - return -} - -func NewSymbolsCache(coins GeckoCoins) *SymbolsCache { - m := SymbolsCache{} - coinsMap := getCoinsMap(coins) - - for _, coin := range coins { - if len(coin.Platforms) == 0 { - m[m.generateId(coin.Symbol, "")] = coin - } - for platform, address := range coin.Platforms { - if len(platform) == 0 || len(address) == 0 { - continue - } - platformCoin, ok := coinsMap[platform] - if !ok { - continue - } - m[m.generateId(platformCoin.Symbol, address)] = coin - } - } - - return &m -} - -func NewCache(coins GeckoCoins) *Cache { - m := Cache{} - coinsMap := getCoinsMap(coins) - - for _, coin := range coins { - for platform, address := range coin.Platforms { - if len(platform) == 0 || len(address) == 0 { - continue - } - platformCoin, ok := coinsMap[platform] - if !ok { - continue - } - - _, ok = m[coin.Id] - if !ok { - m[coin.Id] = make([]CoinResult, 0) - } - - tokenId := normalizeTokenId(platform, address) - if tokenId == "" { - continue - } - - m[coin.Id] = append(m[coin.Id], CoinResult{ - Symbol: platformCoin.Symbol, - TokenId: tokenId, - CoinType: blockatlas.TypeToken, - }) - } - } - return &m -} - -func getCoinsMap(coins GeckoCoins) map[string]GeckoCoin { - coinsMap := make(map[string]GeckoCoin) - for _, coin := range coins { - coinsMap[coin.Id] = coin - } - return coinsMap -} - -func normalizeTokenId(platform, addr string) string { - if platform == "" || addr == "" { - return "" - } - switch platform { - case PlatformEthereum, PlatformClassic: - if len(addr) == 42 && strings.HasPrefix(addr, "0x") { - return address.EIP55Checksum(addr) - } - return "" - default: - return addr - } -} diff --git a/market/clients/coingecko/cache_test.go b/market/clients/coingecko/cache_test.go deleted file mode 100644 index 4936a7351..000000000 --- a/market/clients/coingecko/cache_test.go +++ /dev/null @@ -1,370 +0,0 @@ -package coingecko - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func Test_NewCache(t *testing.T) { - tests := []struct { - name string - coins GeckoCoins - expected *Cache - }{ - { - name: "test prepare cache map", - coins: GeckoCoins{ - GeckoCoin{ - Id: "ethereum", - Symbol: "eth", - Name: "eth", - Platforms: nil, - }, - GeckoCoin{ - Id: "bitcoin", - Symbol: "btc", - Name: "btc", - Platforms: nil, - }, - GeckoCoin{ - Id: "0x", - Symbol: "0x", - Name: "0x", - Platforms: Platforms{ - "ethereum": "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", - }, - }, - GeckoCoin{ - Id: "usdt", - Symbol: "usdt", - Name: "usdt", - Platforms: Platforms{ - "ethereum": "0xdac17f958d2ee523a2206206994597c13d831ec7", - }, - }, - }, - expected: &Cache{ - "0x": { - CoinResult{ - Symbol: "eth", - TokenId: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", - CoinType: "token", - }, - }, - "usdt": { - CoinResult{ - Symbol: "eth", - TokenId: "0xdAC17F958D2ee523a2206206994597C13D831ec7", - CoinType: "token", - }, - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.expected, NewCache(tt.coins)) - }) - } -} - -func TestClient_GetCoinsById(t *testing.T) { - coins := GeckoCoins{ - GeckoCoin{ - Id: "ethereum", - Symbol: "eth", - Name: "eth", - Platforms: nil, - }, - GeckoCoin{ - Id: "bitcoin", - Symbol: "btc", - Name: "btc", - Platforms: nil, - }, - GeckoCoin{ - Id: "0x", - Symbol: "0x", - Name: "0x", - Platforms: Platforms{ - "ethereum": "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", - }, - }, - GeckoCoin{ - Id: "usdt", - Symbol: "usdt", - Name: "usdt", - Platforms: Platforms{ - "ethereum": "0xdac17f958d2ee523a2206206994597c13d831ec7", - }, - }, - } - tests := []struct { - name string - id string - expected []CoinResult - }{ - { - name: "test fetching 0x", - id: "0x", - expected: []CoinResult{ - { - Symbol: "eth", - TokenId: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", - CoinType: "token", - }, - }, - }, - { - name: "test fetching usdt", - id: "usdt", - expected: []CoinResult{ - { - Symbol: "eth", - TokenId: "0xdAC17F958D2ee523a2206206994597C13D831ec7", - CoinType: "token", - }, - }, - }, - } - cache := NewCache(coins) - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - res, err := cache.GetCoinsById(tt.id) - assert.Nil(t, err) - assert.Equal(t, tt.expected, res) - }) - } -} - -func Test_NewSymbolsCache(t *testing.T) { - tests := []struct { - name string - coins GeckoCoins - expected *SymbolsCache - }{ - { - name: "test prepare cache map", - coins: GeckoCoins{ - GeckoCoin{ - Id: "ethereum", - Symbol: "eth", - Name: "eth", - Platforms: nil, - }, - GeckoCoin{ - Id: "bitcoin", - Symbol: "btc", - Name: "btc", - Platforms: nil, - }, - GeckoCoin{ - Id: "0x", - Symbol: "0x", - Name: "0x", - Platforms: Platforms{ - "ethereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", - }, - }, - GeckoCoin{ - Id: "usdt", - Symbol: "usdt", - Name: "usdt", - Platforms: Platforms{ - "ethereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", - }, - }, - }, - expected: &SymbolsCache{ - "ETH:0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6": GeckoCoin{ - Id: "0x", - Symbol: "0x", - Name: "0x", - Platforms: Platforms{ - "ethereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", - }, - }, - "ETH:0xdAC17F958D2ee523a2206206994597C13D831ec7": GeckoCoin{ - Id: "usdt", - Symbol: "usdt", - Name: "usdt", - Platforms: Platforms{ - "ethereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", - }, - }, - "BTC": GeckoCoin{Id: "bitcoin", Symbol: "btc", Name: "btc", Platforms: nil}, - "ETH": GeckoCoin{Id: "ethereum", Symbol: "eth", Name: "eth", Platforms: nil}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.expected, NewSymbolsCache(tt.coins)) - }) - } -} - -func TestClient_GetCoinsBySymbol(t *testing.T) { - coins := GeckoCoins{ - GeckoCoin{ - Id: "ethereum", - Symbol: "eth", - Name: "eth", - Platforms: nil, - }, - GeckoCoin{ - Id: "bitcoin", - Symbol: "btc", - Name: "btc", - Platforms: nil, - }, - GeckoCoin{ - Id: "0x", - Symbol: "0x", - Name: "0x", - Platforms: Platforms{ - "ethereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", - }, - }, - GeckoCoin{ - Id: "usdt", - Symbol: "usdt", - Name: "usdt", - Platforms: Platforms{ - "ethereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", - }, - }, - } - tests := []struct { - name string - symbol string - address string - expected GeckoCoin - }{ - { - name: "test fetching 0x", - symbol: "eth", - address: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", - expected: GeckoCoin{ - Id: "0x", - Symbol: "0x", - Name: "0x", - Platforms: Platforms{ - "ethereum": "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", - }, - }, - }, { - name: "test fetching usdt", - symbol: "eth", - address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", - expected: GeckoCoin{ - Id: "usdt", - Symbol: "usdt", - Name: "usdt", - Platforms: Platforms{ - "ethereum": "0xdAC17F958D2ee523a2206206994597C13D831ec7", - }, - }, - }, - { - name: "test fetching btc", - symbol: "btc", - expected: GeckoCoin{ - Id: "bitcoin", - Symbol: "btc", - Name: "btc", - Platforms: nil, - }, - }, - { - name: "test fetching eth", - symbol: "eth", - expected: GeckoCoin{ - Id: "ethereum", - Symbol: "eth", - Name: "eth", - Platforms: nil, - }, - }, - } - cache := NewSymbolsCache(coins) - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - res, err := cache.GetCoinsBySymbol(tt.symbol, tt.address) - assert.Nil(t, err) - assert.Equal(t, tt.expected, res) - }) - } -} - -func Test_NormalizeTokenIDs(t *testing.T) { - tests := []struct { - name string - platform string - address string - expected string - }{ - { - name: "Should checksum Ethereum lowercase address", - platform: PlatformEthereum, - address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", - expected: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", - }, - { - name: "Should checksum Classic lowercase address", - platform: PlatformClassic, - address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", - expected: "0x812f35b66Ec9EEe26CD7Fdf07Fbc1c9c0ac3C4D6", - }, - { - name: "Check if one of the input empty - 1", - platform: PlatformEthereum, - address: "", - expected: "", - }, - { - name: "Check if one of the input empty - 2", - platform: PlatformClassic, - address: "", - expected: "", - }, - { - name: "Check if one of the input empty - 3", - platform: "", - address: "0x812f35b66ec9eee26cd7fdf07fbc1c9c0ac3c4d6", - expected: "", - }, - { - name: "Should not process if address malformed", - platform: PlatformEthereum, - address: "https://etherscan.io/address/0x8Ddc86DbA7ad728012eFc460b8A168Aba60B403B", - expected: "", - }, - { - name: "Return empty string if input empty", - platform: "", - address: "", - expected: "", - }, - { - name: "Should return same Stellar address", - platform: "stellar", - address: "SIX-GDMS6EECOH6MBMCP3FYRYEVRBIV3TQGLOFQIPVAITBRJUMTI6V7A2X6Z", - expected: "SIX-GDMS6EECOH6MBMCP3FYRYEVRBIV3TQGLOFQIPVAITBRJUMTI6V7A2X6Z", - }, - { - name: "Should return same Neo address", - platform: "neo", - address: "ab38352559b8b203bde5fddfa0b07d8b2525e132", - expected: "ab38352559b8b203bde5fddfa0b07d8b2525e132", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.expected, normalizeTokenId(tt.platform, tt.address)) - }) - } -} diff --git a/market/clients/coingecko/client.go b/market/clients/coingecko/client.go deleted file mode 100644 index 93a425701..000000000 --- a/market/clients/coingecko/client.go +++ /dev/null @@ -1,104 +0,0 @@ -package coingecko - -import ( - "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" - "net/url" - "strconv" - "strings" - "sync" - "time" -) - -const ( - bucketSize = 500 -) - -type Client struct { - blockatlas.Request -} - -func NewClient(api string) *Client { - c := Client{ - Request: blockatlas.InitClient(api), - } - return &c -} - -func (c *Client) FetchLatestRates(coins GeckoCoins, currency string) (prices CoinPrices) { - ci := coins.coinIds() - - i := 0 - prChan := make(chan CoinPrices) - var wg sync.WaitGroup - for i < len(ci) { - wg.Add(1) - go func(i int) { - defer wg.Done() - var end = len(ci) - if len(ci) > i+bucketSize { - end = i + bucketSize - } - bucket := ci[i:end] - ids := strings.Join(bucket[:], ",") - - cp, err := c.FetchCoinsMarkets(currency, ids) - if err != nil { - logger.Error(err) - return - } - prChan <- cp - }(i) - - i += bucketSize - } - - go func() { - wg.Wait() - close(prChan) - }() - - for bucket := range prChan { - prices = append(prices, bucket...) - } - - return -} - -func (c *Client) GetChartsData(id, currency string, timeStart, timeEnd int64) (charts Charts, err error) { - values := url.Values{ - "vs_currency": {currency}, - "from": {strconv.FormatInt(timeStart, 10)}, - "to": {strconv.FormatInt(timeEnd, 10)}, - } - err = c.GetWithCache(&charts, fmt.Sprintf("v3/coins/%s/market_chart/range", id), values, time.Minute*5) - return -} - -func (c *Client) FetchCoinsList() (coins GeckoCoins, err error) { - values := url.Values{ - "include_platform": {"true"}, - } - err = c.GetWithCache(&coins, "v3/coins/list", values, time.Hour) - return -} - -func (c *Client) FetchCoinsMarkets(currency, ids string) (cp CoinPrices, err error) { - values := url.Values{ - "vs_currency": {currency}, - "sparkline": {"false"}, - "ids": {ids}, - } - - err = c.Get(&cp, "v3/coins/markets", values) - return -} - -func (coins GeckoCoins) coinIds() []string { - coinIds := make([]string, 0) - for _, coin := range coins { - coinIds = append(coinIds, coin.Id) - } - return coinIds -} diff --git a/market/clients/coingecko/client_test.go b/market/clients/coingecko/client_test.go deleted file mode 100644 index c4dd29347..000000000 --- a/market/clients/coingecko/client_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package coingecko - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func Test_coinIds(t *testing.T) { - tests := []struct { - name string - coins GeckoCoins - expected []string - }{ - { - name: "test construct coin Ids", - coins: GeckoCoins{ - GeckoCoin{ - Id: "ethtereum", - Symbol: "eth", - Name: "eth", - Platforms: nil, - }, - GeckoCoin{ - Id: "bitcoin", - Symbol: "btc", - Name: "btc", - Platforms: nil, - }, - }, - expected: []string{ - "ethtereum", - "bitcoin", - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.expected, tt.coins.coinIds()) - }) - } -} diff --git a/market/clients/coingecko/models.go b/market/clients/coingecko/models.go deleted file mode 100644 index f1821f6ef..000000000 --- a/market/clients/coingecko/models.go +++ /dev/null @@ -1,49 +0,0 @@ -package coingecko - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "time" -) - -type Charts struct { - Prices []ChartVolume `json:"prices"` - MarketCaps []ChartVolume `json:"market_caps"` - Volumes []ChartVolume `json:"total_volumes"` -} - -type ChartVolume []float64 - -type CoinResult struct { - Symbol string - TokenId string - CoinType blockatlas.CoinType -} - -type CoinPrices []CoinPrice - -type CoinPrice struct { - Id string `json:"id"` - Symbol string `json:"symbol"` - Name string `json:"name"` - CurrentPrice float64 `json:"current_price"` - PriceChange24h float64 `json:"price_change_24h"` - PriceChangePercentage24h float64 `json:"price_change_percentage_24h"` - MarketCapChange24h float64 `json:"market_cap_change_24h"` - MarketCapChangePercentage24h float64 `json:"market_cap_change_percentage_24h"` - MarketCap float64 `json:"market_cap"` - TotalVolume float64 `json:"total_volume"` - CirculatingSupply float64 `json:"circulating_supply"` - TotalSupply float64 `json:"total_supply"` - LastUpdated time.Time `json:"last_updated"` -} - -type GeckoCoins []GeckoCoin - -type GeckoCoin struct { - Id string `json:"id"` - Symbol string `json:"symbol"` - Name string `json:"name"` - Platforms Platforms `json:"platforms"` -} - -type Platforms map[string]string diff --git a/market/clients/compound/client.go b/market/clients/compound/client.go deleted file mode 100644 index 52083a569..000000000 --- a/market/clients/compound/client.go +++ /dev/null @@ -1,21 +0,0 @@ -package compound - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) - -type Client struct { - blockatlas.Request -} - -func NewClient(api string) *Client { - c := Client{ - Request: blockatlas.InitClient(api), - } - return &c -} - -func (c *Client) GetData() (prices CoinPrices, err error) { - err = c.Get(&prices, "v2/ctoken", nil) - return -} diff --git a/market/clients/compound/models.go b/market/clients/compound/models.go deleted file mode 100644 index 5a159c4f6..000000000 --- a/market/clients/compound/models.go +++ /dev/null @@ -1,15 +0,0 @@ -package compound - -type CoinPrices struct { - Data []CToken `json:"cToken"` -} - -type CToken struct { - UnderlyingPrice Amount `json:"underlying_price"` - Symbol string `json:"symbol"` - TokenAddress string `json:"token_address"` -} - -type Amount struct { - Value float64 `json:"value,string"` -} diff --git a/market/market.go b/market/market.go deleted file mode 100644 index 76daadf26..000000000 --- a/market/market.go +++ /dev/null @@ -1,67 +0,0 @@ -package market - -import ( - "github.com/robfig/cron/v3" - "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/market/market" - "github.com/trustwallet/blockatlas/market/market/cmc" - "github.com/trustwallet/blockatlas/market/market/coingecko" - "github.com/trustwallet/blockatlas/market/market/compound" - "github.com/trustwallet/blockatlas/market/market/dex" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" -) - -var marketProviders market.Providers - -func InitMarkets(storage storage.Market) { - marketProviders = market.Providers{ - // Add Market Quote Providers: - 0: dex.InitMarket( - config.Configuration.Market.Dex.API, - config.Configuration.Market.Dex.QuoteUpdateTime, - ), - 1: cmc.InitMarket( - config.Configuration.Market.Cmc.API, - config.Configuration.Market.Cmc.APIKey, - config.Configuration.Market.Cmc.MapURL, - config.Configuration.Market.QuoteUpdateTime, - ), - 2: compound.InitMarket( - config.Configuration.Market.Compound.API, - config.Configuration.Market.QuoteUpdateTime, - ), - 3: coingecko.InitMarket( - config.Configuration.Market.Coingecko.API, - config.Configuration.Market.QuoteUpdateTime, - ), - } - addMarkets(storage, marketProviders) -} - -func addMarkets(storage storage.Market, ps market.Providers) { - c := cron.New() - for _, p := range ps { - scheduleTasks(storage, p, c) - } - c.Start() -} - -func runMarket(storage storage.Market, p market.Provider) error { - data, err := p.GetData() - if err != nil { - return errors.E(err, "GetData") - } - var saveErrs = 0 - for _, result := range data { - err = storage.SaveTicker(result, marketProviders) - if err != nil { - saveErrs++ - logger.Error(errors.E(err, "SaveTicker", - errors.Params{"result": result})) - } - } - logger.Info("Market data result", logger.Params{"markets": len(data), "provider": p.GetId(), "failed": saveErrs}) - return nil -} diff --git a/market/market/cmc/cmc.go b/market/market/cmc/cmc.go deleted file mode 100644 index 214c44716..000000000 --- a/market/market/cmc/cmc.go +++ /dev/null @@ -1,102 +0,0 @@ -package cmc - -import ( - "github.com/trustwallet/blockatlas/market/clients/cmc" - "github.com/trustwallet/blockatlas/market/market" - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) - -const ( - id = "cmc" -) - -type Market struct { - market.Market - mapApi string - client *cmc.Client -} - -func InitMarket(api string, apiKey string, mapApi string, updateTime string) market.Provider { - m := &Market{ - Market: market.Market{ - Id: id, - UpdateTime: updateTime, - }, - mapApi: mapApi, - client: cmc.NewClient(api, apiKey), - } - return m -} - -func (m *Market) GetData() (blockatlas.Tickers, error) { - cmap, err := cmc.GetCmcMap(m.mapApi) - if err != nil { - return nil, err - } - prices, err := m.client.GetData() - if err != nil { - return nil, err - } - return normalizeTickers(prices, m.GetId(), cmap), nil -} - -func normalizeTicker(price cmc.Data, provider string, cmap cmc.CmcMapping) (tickers blockatlas.Tickers) { - tokenId := "" - coinName := price.Symbol - coinType := blockatlas.TypeCoin - if price.Platform != nil { - coinType = blockatlas.TypeToken - coinName = price.Platform.Symbol - tokenId = price.Platform.TokenAddress - if len(tokenId) == 0 { - tokenId = price.Symbol - } - } - - cmcCoin, err := cmap.GetCoins(price.Id) - if err != nil { - tickers = append(tickers, &blockatlas.Ticker{ - CoinName: coinName, - CoinType: coinType, - TokenId: tokenId, - Price: blockatlas.TickerPrice{ - Value: price.Quote.USD.Price, - Change24h: price.Quote.USD.PercentChange24h, - Currency: blockatlas.DefaultCurrency, - Provider: provider, - }, - LastUpdate: price.LastUpdated, - }) - return - } - - for _, cmc := range cmcCoin { - coinName = cmc.Coin.Symbol - if cmc.CoinType == blockatlas.TypeCoin { - tokenId = "" - } else if len(cmc.TokenId) > 0 { - tokenId = cmc.TokenId - } - tickers = append(tickers, &blockatlas.Ticker{ - CoinName: coinName, - CoinType: cmc.CoinType, - TokenId: tokenId, - Price: blockatlas.TickerPrice{ - Value: price.Quote.USD.Price, - Change24h: price.Quote.USD.PercentChange24h, - Currency: blockatlas.DefaultCurrency, - Provider: provider, - }, - LastUpdate: price.LastUpdated, - }) - } - return -} - -func normalizeTickers(prices cmc.CoinPrices, provider string, cmap cmc.CmcMapping) (tickers blockatlas.Tickers) { - for _, price := range prices.Data { - t := normalizeTicker(price, provider, cmap) - tickers = append(tickers, t...) - } - return -} diff --git a/market/market/cmc/cmc_test.go b/market/market/cmc/cmc_test.go deleted file mode 100644 index 1e90b1991..000000000 --- a/market/market/cmc/cmc_test.go +++ /dev/null @@ -1,93 +0,0 @@ -package cmc - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/market/clients/cmc" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "sort" - "testing" - "time" -) - -func Test_normalizeTickers(t *testing.T) { - mapping := cmc.CmcMapping{ - 666: {{ - Coin: 1023, - Id: 666, - Type: "coin", - }}, - } - type args struct { - prices cmc.CoinPrices - provider string - } - tests := []struct { - name string - args args - wantTickers blockatlas.Tickers - }{ - { - "test normalize cmc quote", - args{prices: cmc.CoinPrices{Data: []cmc.Data{ - {Coin: cmc.Coin{Symbol: "BTC", Id: 0}, LastUpdated: time.Unix(111, 0), Quote: cmc.Quote{ - USD: cmc.USD{Price: 223.55, PercentChange24h: 10}}}, - {Coin: cmc.Coin{Symbol: "ETH", Id: 60}, LastUpdated: time.Unix(333, 0), Quote: cmc.Quote{ - USD: cmc.USD{Price: 11.11, PercentChange24h: 20}}}, - {Coin: cmc.Coin{Symbol: "SWP", Id: 6969}, LastUpdated: time.Unix(444, 0), Quote: cmc.Quote{ - USD: cmc.USD{Price: 463.22, PercentChange24h: -3}}, - Platform: &cmc.Platform{Coin: cmc.Coin{Symbol: "ETH"}, TokenAddress: "0x8ce9137d39326ad0cd6491fb5cc0cba0e089b6a9"}}, - {Coin: cmc.Coin{Symbol: "ONE", Id: 666}, LastUpdated: time.Unix(555, 0), Quote: cmc.Quote{ - USD: cmc.USD{Price: 123.09, PercentChange24h: -1.4}}, - Platform: &cmc.Platform{Coin: cmc.Coin{Symbol: "BNB"}, TokenAddress: "0x8ce9137d39326ad0cd6491fb5cc0cba0e089b6a9"}}}}, - provider: "cmc"}, - blockatlas.Tickers{ - &blockatlas.Ticker{CoinName: "BTC", CoinType: blockatlas.TypeCoin, LastUpdate: time.Unix(111, 0), - Price: blockatlas.TickerPrice{ - Value: 223.55, - Change24h: 10, - Currency: blockatlas.DefaultCurrency, - Provider: "cmc", - }, - }, - &blockatlas.Ticker{CoinName: "ETH", CoinType: blockatlas.TypeCoin, LastUpdate: time.Unix(333, 0), - Price: blockatlas.TickerPrice{ - Value: 11.11, - Change24h: 20, - Currency: blockatlas.DefaultCurrency, - Provider: "cmc", - }, - }, - &blockatlas.Ticker{CoinName: "ETH", TokenId: "0x8ce9137d39326ad0cd6491fb5cc0cba0e089b6a9", CoinType: blockatlas.TypeToken, LastUpdate: time.Unix(444, 0), - Price: blockatlas.TickerPrice{ - Value: 463.22, - Change24h: -3, - Currency: blockatlas.DefaultCurrency, - Provider: "cmc", - }, - }, - &blockatlas.Ticker{CoinName: "ONE", CoinType: blockatlas.TypeCoin, LastUpdate: time.Unix(555, 0), - Price: blockatlas.TickerPrice{ - Value: 123.09, - Change24h: -1.4, - Currency: blockatlas.DefaultCurrency, - Provider: "cmc", - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotTickers := normalizeTickers(tt.args.prices, tt.args.provider, mapping) - sort.SliceStable(gotTickers, func(i, j int) bool { - return gotTickers[i].LastUpdate.Unix() < gotTickers[j].LastUpdate.Unix() - }) - if !assert.Equal(t, len(tt.wantTickers), len(gotTickers)) { - t.Fatal("invalid tickers length") - } - for i, obj := range tt.wantTickers { - assert.Equal(t, obj, gotTickers[i]) - } - }) - } -} diff --git a/market/market/coingecko/coingecko.go b/market/market/coingecko/coingecko.go deleted file mode 100644 index d16f21dd3..000000000 --- a/market/market/coingecko/coingecko.go +++ /dev/null @@ -1,94 +0,0 @@ -package coingecko - -import ( - "github.com/trustwallet/blockatlas/market/clients/coingecko" - "github.com/trustwallet/blockatlas/market/market" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "strings" -) - -const ( - id = "coingecko" -) - -type Market struct { - client *coingecko.Client - cache *coingecko.Cache - market.Market -} - -func InitMarket(api, updateTime string) market.Provider { - m := &Market{ - client: coingecko.NewClient(api), - Market: market.Market{ - Id: id, - UpdateTime: updateTime, - }, - } - return m -} - -func (m *Market) GetData() (result blockatlas.Tickers, err error) { - coins, err := m.client.FetchCoinsList() - if err != nil { - return - } - m.cache = coingecko.NewCache(coins) - - rates := m.client.FetchLatestRates(coins, blockatlas.DefaultCurrency) - result = m.normalizeTickers(rates, m.GetId()) - return -} - -func (m *Market) normalizeTicker(price coingecko.CoinPrice, provider string) (tickers blockatlas.Tickers) { - tokenId := "" - coinName := strings.ToUpper(price.Symbol) - coinType := blockatlas.TypeCoin - - cgCoins, err := m.cache.GetCoinsById(price.Id) - if err != nil { - tickers = append(tickers, &blockatlas.Ticker{ - CoinName: coinName, - CoinType: coinType, - TokenId: tokenId, - Price: blockatlas.TickerPrice{ - Value: price.CurrentPrice, - Change24h: price.PriceChangePercentage24h, - Currency: blockatlas.DefaultCurrency, - Provider: provider, - }, - LastUpdate: price.LastUpdated, - }) - return - } - - for _, cg := range cgCoins { - coinName = strings.ToUpper(cg.Symbol) - if cg.CoinType == blockatlas.TypeCoin { - tokenId = "" - } else if len(cg.TokenId) > 0 { - tokenId = cg.TokenId - } - tickers = append(tickers, &blockatlas.Ticker{ - CoinName: coinName, - CoinType: cg.CoinType, - TokenId: tokenId, - Price: blockatlas.TickerPrice{ - Value: price.CurrentPrice, - Change24h: price.PriceChangePercentage24h, - Currency: blockatlas.DefaultCurrency, - Provider: provider, - }, - LastUpdate: price.LastUpdated, - }) - } - return -} - -func (m *Market) normalizeTickers(prices coingecko.CoinPrices, provider string) (tickers blockatlas.Tickers) { - for _, price := range prices { - t := m.normalizeTicker(price, provider) - tickers = append(tickers, t...) - } - return -} diff --git a/market/market/coingecko/coingecko_test.go b/market/market/coingecko/coingecko_test.go deleted file mode 100644 index 3c3a20c3f..000000000 --- a/market/market/coingecko/coingecko_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package coingecko - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/market/clients/coingecko" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "sort" - "testing" - "time" -) - -func Test_normalizeTickers(t *testing.T) { - coins := coingecko.GeckoCoins{ - coingecko.GeckoCoin{ - Id: "ethtereum", - Symbol: "eth", - Name: "eth", - Platforms: nil, - }, - coingecko.GeckoCoin{ - Id: "bitcoin", - Symbol: "btc", - Name: "btc", - Platforms: nil, - }, - coingecko.GeckoCoin{ - Id: "cREP", - Symbol: "cREP", - Name: "cREP", - Platforms: coingecko.Platforms{ - "ethtereum": "0x158079ee67fce2f58472a96584a73c7ab9ac95c1", - }, - }, - coingecko.GeckoCoin{ - Id: "cUSDC", - Symbol: "cUSDC", - Name: "cUSDC", - Platforms: coingecko.Platforms{ - "ethtereum": "0x39aa39c021dfbae8fac545936693ac917d5e7563", - }, - }, - } - - m := Market{} - m.cache = coingecko.NewCache(coins) - type args struct { - prices coingecko.CoinPrices - provider string - } - tests := []struct { - name string - args args - wantTickers blockatlas.Tickers - }{ - { - "test normalize coingecko quote", - args{prices: coingecko.CoinPrices{ - { - Id: "cUSDC", - Symbol: "cUSDC", - CurrentPrice: 0.0021, - }, - { - Id: "cREP", - Symbol: "cREP", - CurrentPrice: 0.02, - }, - }, provider: id}, - blockatlas.Tickers{ - &blockatlas.Ticker{CoinName: "ETH", TokenId: "0x39aa39c021dfbae8fac545936693ac917d5e7563", CoinType: blockatlas.TypeToken, LastUpdate: time.Unix(222, 0), - Price: blockatlas.TickerPrice{ - Value: 0.0021, - Currency: blockatlas.DefaultCurrency, - Provider: id, - }, - }, - &blockatlas.Ticker{CoinName: "ETH", TokenId: "0x158079ee67fce2f58472a96584a73c7ab9ac95c1", CoinType: blockatlas.TypeToken, LastUpdate: time.Unix(444, 0), - Price: blockatlas.TickerPrice{ - Value: 0.02, - Currency: blockatlas.DefaultCurrency, - Provider: id, - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotTickers := m.normalizeTickers(tt.args.prices, tt.args.provider) - now := time.Now() - sort.Slice(gotTickers, func(i, j int) bool { - gotTickers[i].LastUpdate = now - gotTickers[j].LastUpdate = now - return gotTickers[i].Coin > gotTickers[j].Coin - }) - sort.Slice(tt.wantTickers, func(i, j int) bool { - tt.wantTickers[i].LastUpdate = now - tt.wantTickers[j].LastUpdate = now - return tt.wantTickers[i].Coin > tt.wantTickers[j].Coin - }) - assert.Equal(t, tt.wantTickers, gotTickers) - }) - } -} diff --git a/market/market/compound/compound.go b/market/market/compound/compound.go deleted file mode 100644 index 379fa63be..000000000 --- a/market/market/compound/compound.go +++ /dev/null @@ -1,64 +0,0 @@ -package compound - -import ( - "github.com/trustwallet/blockatlas/coin" - c "github.com/trustwallet/blockatlas/market/clients/compound" - "github.com/trustwallet/blockatlas/market/market" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "time" -) - -const ( - id = "compound" -) - -type Market struct { - market.Market - client *c.Client -} - -func InitMarket(api string, updateTime string) market.Provider { - m := &Market{ - Market: market.Market{ - Id: id, - UpdateTime: updateTime, - }, - client: c.NewClient(api), - } - return m -} - -func (m *Market) GetData() (result blockatlas.Tickers, err error) { - coinPrices, err := m.client.GetData() - if err != nil { - return - } - result = normalizeTickers(coinPrices, m.GetId()) - return result, nil -} - -func normalizeTicker(ctoken c.CToken, provider string) (*blockatlas.Ticker, error) { - // TODO: add value24 calculation - return &blockatlas.Ticker{ - CoinName: coin.Ethereum().Symbol, - CoinType: blockatlas.TypeToken, - TokenId: ctoken.TokenAddress, - Price: blockatlas.TickerPrice{ - Value: ctoken.UnderlyingPrice.Value, - Currency: coin.Coins[coin.ETH].Symbol, - Provider: provider, - }, - LastUpdate: time.Now(), - }, nil -} - -func normalizeTickers(prices c.CoinPrices, provider string) (tickers blockatlas.Tickers) { - for _, price := range prices.Data { - t, err := normalizeTicker(price, provider) - if err != nil { - continue - } - tickers = append(tickers, t) - } - return -} diff --git a/market/market/compound/compound_test.go b/market/market/compound/compound_test.go deleted file mode 100644 index 15bc971ea..000000000 --- a/market/market/compound/compound_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package compound - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/market/clients/compound" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "sort" - "testing" - "time" -) - -func Test_normalizeTickers(t *testing.T) { - type args struct { - prices compound.CoinPrices - provider string - } - tests := []struct { - name string - args args - wantTickers blockatlas.Tickers - }{ - { - "test normalize compound quote", - args{prices: compound.CoinPrices{Data: []compound.CToken{ - { - TokenAddress: "0x39aa39c021dfbae8fac545936693ac917d5e7563", - Symbol: "cUSDC", - UnderlyingPrice: compound.Amount{Value: 0.0021}, - }, - { - TokenAddress: "0x158079ee67fce2f58472a96584a73c7ab9ac95c1", - Symbol: "cREP", - UnderlyingPrice: compound.Amount{Value: 0.02}, - }, - }}, provider: id}, - blockatlas.Tickers{ - &blockatlas.Ticker{CoinName: "ETH", TokenId: "0x39aa39c021dfbae8fac545936693ac917d5e7563", CoinType: blockatlas.TypeToken, LastUpdate: time.Unix(222, 0), - Price: blockatlas.TickerPrice{ - Value: 0.0021, - Currency: coin.Coins[coin.ETH].Symbol, - Provider: id, - }, - }, - &blockatlas.Ticker{CoinName: "ETH", TokenId: "0x158079ee67fce2f58472a96584a73c7ab9ac95c1", CoinType: blockatlas.TypeToken, LastUpdate: time.Unix(444, 0), - Price: blockatlas.TickerPrice{ - Value: 0.02, - Currency: coin.Coins[coin.ETH].Symbol, - Provider: id, - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotTickers := normalizeTickers(tt.args.prices, tt.args.provider) - now := time.Now() - sort.Slice(gotTickers, func(i, j int) bool { - gotTickers[i].LastUpdate = now - gotTickers[j].LastUpdate = now - return gotTickers[i].Coin > gotTickers[j].Coin - }) - sort.Slice(tt.wantTickers, func(i, j int) bool { - tt.wantTickers[i].LastUpdate = now - tt.wantTickers[j].LastUpdate = now - return tt.wantTickers[i].Coin > tt.wantTickers[j].Coin - }) - assert.Equal(t, tt.wantTickers, gotTickers) - }) - } -} diff --git a/market/market/dex/dex.go b/market/market/dex/dex.go deleted file mode 100644 index 7b1fc3ec5..000000000 --- a/market/market/dex/dex.go +++ /dev/null @@ -1,96 +0,0 @@ -package dex - -import ( - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/market/market" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "math/big" - "net/url" - "strconv" - "time" -) - -var ( - id = "dex" - BNBAsset = coin.Binance().Symbol -) - -type Market struct { - market.Market - blockatlas.Request -} - -func InitMarket(api string, updateTime string) market.Provider { - m := &Market{ - Market: market.Market{ - Id: id, - UpdateTime: updateTime, - }, - Request: blockatlas.InitClient(api), - } - return m -} - -func (m *Market) GetData() (blockatlas.Tickers, error) { - var prices []*CoinPrice - err := m.Get(&prices, "v1/ticker/24hr", url.Values{"limit": {"1000"}}) - if err != nil { - return nil, err - } - rate, err := m.Storage.GetRate(BNBAsset) - if err != nil { - return nil, errors.E(err, "rate not found", errors.Params{"asset": BNBAsset}) - } - result := normalizeTickers(prices, m.GetId()) - if rate.PercentChange24h != nil { - rate.PercentChange24h.Mul(rate.PercentChange24h, big.NewFloat(-1)) - } - result.ApplyRate(blockatlas.DefaultCurrency, 1/rate.Rate, rate.PercentChange24h) - return result, nil -} - -func normalizeTicker(price *CoinPrice, provider string) (*blockatlas.Ticker, error) { - if price.QuoteAssetName != BNBAsset && price.BaseAssetName != BNBAsset { - return nil, errors.E("invalid quote/base asset", - errors.Params{"Symbol": price.BaseAssetName, "QuoteAsset": price.QuoteAssetName}) - } - value, err := strconv.ParseFloat(price.LastPrice, 64) - if err != nil { - return nil, errors.E(err, "normalizeTicker parse value error", - errors.Params{"LastPrice": price.LastPrice, "Symbol": price.BaseAssetName}) - } - value24h, err := strconv.ParseFloat(price.PriceChangePercent, 64) - if err != nil { - return nil, errors.E(err, "normalizeTicker parse value24h error", - errors.Params{"PriceChange": price.PriceChangePercent, "Symbol": price.BaseAssetName}) - } - tokenId := price.BaseAssetName - if tokenId == BNBAsset { - tokenId = price.QuoteAssetName - value = 1.0 / value - } - return &blockatlas.Ticker{ - CoinName: BNBAsset, - CoinType: blockatlas.TypeToken, - TokenId: tokenId, - Price: blockatlas.TickerPrice{ - Value: value, - Change24h: value24h, - Currency: "BNB", - Provider: provider, - }, - LastUpdate: time.Now(), - }, nil -} - -func normalizeTickers(prices []*CoinPrice, provider string) (tickers blockatlas.Tickers) { - for _, price := range prices { - t, err := normalizeTicker(price, provider) - if err != nil { - continue - } - tickers = append(tickers, t) - } - return -} diff --git a/market/market/dex/dex_test.go b/market/market/dex/dex_test.go deleted file mode 100644 index 14cd5aba9..000000000 --- a/market/market/dex/dex_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package dex - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "sort" - "testing" - "time" -) - -func Test_normalizeTickers(t *testing.T) { - type args struct { - prices []*CoinPrice - provider string - } - tests := []struct { - name string - args args - wantTickers blockatlas.Tickers - }{ - { - "test normalize dex quote", - args{prices: []*CoinPrice{ - { - BaseAssetName: "RAVEN-F66", - QuoteAssetName: "BNB", - LastPrice: "0.00001082", - PriceChangePercent: "-2.2500", - }, - { - BaseAssetName: "SLV-986", - QuoteAssetName: "BNB", - LastPrice: "0.04494510", - PriceChangePercent: "-5.3700", - }, - { - BaseAssetName: "CBIX-3C9", - QuoteAssetName: "TAUD-888", - LastPrice: "0.00100235", - PriceChangePercent: "5.2700", - }, - }, - provider: "dex"}, - blockatlas.Tickers{ - &blockatlas.Ticker{CoinName: "BNB", TokenId: "RAVEN-F66", CoinType: blockatlas.TypeToken, LastUpdate: time.Now(), - Price: blockatlas.TickerPrice{ - Value: 0.00001082, - Change24h: -2.2500, - Currency: "BNB", - Provider: "dex", - }, - }, - &blockatlas.Ticker{CoinName: "BNB", TokenId: "SLV-986", CoinType: blockatlas.TypeToken, LastUpdate: time.Now(), - Price: blockatlas.TickerPrice{ - Value: 0.0449451, - Change24h: -5.3700, - Currency: "BNB", - Provider: "dex", - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotTickers := normalizeTickers(tt.args.prices, tt.args.provider) - now := time.Now() - sort.Slice(gotTickers, func(i, j int) bool { - gotTickers[i].LastUpdate = now - gotTickers[j].LastUpdate = now - return gotTickers[i].Coin > gotTickers[j].Coin - }) - sort.Slice(tt.wantTickers, func(i, j int) bool { - tt.wantTickers[i].LastUpdate = now - tt.wantTickers[j].LastUpdate = now - return tt.wantTickers[i].Coin > tt.wantTickers[j].Coin - }) - assert.Equal(t, tt.wantTickers, gotTickers) - }) - } -} diff --git a/market/market/dex/models.go b/market/market/dex/models.go deleted file mode 100644 index f6ae7d701..000000000 --- a/market/market/dex/models.go +++ /dev/null @@ -1,8 +0,0 @@ -package dex - -type CoinPrice struct { - BaseAssetName string `json:"baseAssetName"` - QuoteAssetName string `json:"quoteAssetName"` - PriceChangePercent string `json:"priceChangePercent"` - LastPrice string `json:"lastPrice"` -} diff --git a/market/market/market.go b/market/market/market.go deleted file mode 100644 index 32a660f7e..000000000 --- a/market/market/market.go +++ /dev/null @@ -1,46 +0,0 @@ -package market - -import ( - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" -) - -const ( - defaultUpdateTime = "5m" -) - -type Market struct { - Id string - UpdateTime string - Storage storage.Market -} - -func (m *Market) GetId() string { - return m.Id -} - -func (m *Market) GetLogType() string { - return "market-data" -} - -func (m *Market) GetUpdateTime() string { - return m.UpdateTime -} - -func (m *Market) Init(storage storage.Market) error { - logger.Info("Init Market Quote Provider", logger.Params{"market": m.GetId()}) - if len(m.Id) == 0 { - return errors.E("Market Quote: Id cannot be empty") - } - - if storage == nil { - return errors.E("Market Quote: Storage cannot be nil") - } - m.Storage = storage - - if len(m.UpdateTime) == 0 { - m.UpdateTime = defaultUpdateTime - } - return nil -} diff --git a/market/market/provider.go b/market/market/provider.go deleted file mode 100644 index 2db249428..000000000 --- a/market/market/provider.go +++ /dev/null @@ -1,25 +0,0 @@ -package market - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/storage" -) - -type Provider interface { - Init(storage.Market) error - GetId() string - GetUpdateTime() string - GetData() (blockatlas.Tickers, error) - GetLogType() string -} - -type Providers map[int]Provider - -func (ps Providers) GetPriority(providerId string) int { - for priority, provider := range ps { - if provider.GetId() == providerId { - return priority - } - } - return -1 -} diff --git a/market/rate/cmc/cmc.go b/market/rate/cmc/cmc.go deleted file mode 100644 index 7f53f2b2d..000000000 --- a/market/rate/cmc/cmc.go +++ /dev/null @@ -1,55 +0,0 @@ -package cmc - -import ( - "github.com/trustwallet/blockatlas/market/clients/cmc" - "github.com/trustwallet/blockatlas/market/rate" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "math/big" -) - -const ( - id = "cmc" -) - -type Cmc struct { - rate.Rate - mapApi string - client *cmc.Client -} - -func InitRate(api string, apiKey string, mapApi string, updateTime string) rate.Provider { - cmc := &Cmc{ - Rate: rate.Rate{ - Id: id, - UpdateTime: updateTime, - }, - mapApi: mapApi, - client: cmc.NewClient(api, apiKey), - } - return cmc -} - -func (c *Cmc) FetchLatestRates() (rates blockatlas.Rates, err error) { - prices, err := c.client.GetData() - if err != nil { - return - } - rates = normalizeRates(prices, c.GetId()) - return -} - -func normalizeRates(prices cmc.CoinPrices, provider string) (rates blockatlas.Rates) { - for _, price := range prices.Data { - if price.Platform != nil { - continue - } - rates = append(rates, blockatlas.Rate{ - Currency: price.Symbol, - Rate: 1.0 / price.Quote.USD.Price, - Timestamp: price.LastUpdated.Unix(), - PercentChange24h: big.NewFloat(price.Quote.USD.PercentChange24h), - Provider: provider, - }) - } - return -} diff --git a/market/rate/cmc/cmc_test.go b/market/rate/cmc/cmc_test.go deleted file mode 100644 index b060caa8c..000000000 --- a/market/rate/cmc/cmc_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package cmc - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/market/clients/cmc" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "math/big" - "sort" - "testing" - "time" -) - -func Test_normalizeRates(t *testing.T) { - provider := "cmc" - tests := []struct { - name string - prices cmc.CoinPrices - wantRates blockatlas.Rates - }{ - { - "test normalize cmc rate 1", - cmc.CoinPrices{ - Data: []cmc.Data{ - { - Coin: cmc.Coin{ - Symbol: "BTC", - }, - Quote: cmc.Quote{ - USD: cmc.USD{ - Price: 223.5, - PercentChange24h: 0.33, - }, - }, - LastUpdated: time.Unix(333, 0), - }, - { - Coin: cmc.Coin{ - Symbol: "ETH", - }, - Quote: cmc.Quote{ - USD: cmc.USD{ - Price: 11.11, - PercentChange24h: -1.22, - }, - }, - LastUpdated: time.Unix(333, 0), - }, - }, - }, - blockatlas.Rates{ - blockatlas.Rate{Currency: "BTC", Rate: 1 / 223.5, Timestamp: 333, Provider: provider, PercentChange24h: big.NewFloat(0.33)}, - blockatlas.Rate{Currency: "ETH", Rate: 1 / 11.11, Timestamp: 333, Provider: provider, PercentChange24h: big.NewFloat(-1.22)}, - }, - }, - { - "test normalize cmc rate 2", - cmc.CoinPrices{ - Data: []cmc.Data{ - { - Coin: cmc.Coin{ - Symbol: "BNB", - }, - Quote: cmc.Quote{ - USD: cmc.USD{ - Price: 30.333, - PercentChange24h: 2.1, - }, - }, - LastUpdated: time.Unix(123, 0), - }, - { - Coin: cmc.Coin{ - Symbol: "XRP", - }, - Quote: cmc.Quote{ - USD: cmc.USD{ - Price: 0.4687, - }, - }, - LastUpdated: time.Unix(123, 0), - }, - }, - }, - blockatlas.Rates{ - blockatlas.Rate{Currency: "BNB", Rate: 1 / 30.333, Timestamp: 123, Provider: provider, PercentChange24h: big.NewFloat(2.1)}, - blockatlas.Rate{Currency: "XRP", Rate: 1 / 0.4687, Timestamp: 123, Provider: provider, PercentChange24h: big.NewFloat(0)}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotRates := normalizeRates(tt.prices, provider) - sort.SliceStable(gotRates, func(i, j int) bool { - return gotRates[i].Rate < gotRates[j].Rate - }) - if !assert.ObjectsAreEqualValues(gotRates, tt.wantRates) { - t.Errorf("normalizeRates() = %v, want %v", gotRates, tt.wantRates) - } - }) - } -} diff --git a/market/rate/coingecko/coingecko.go b/market/rate/coingecko/coingecko.go deleted file mode 100644 index 25cb8f874..000000000 --- a/market/rate/coingecko/coingecko.go +++ /dev/null @@ -1,50 +0,0 @@ -package coingecko - -import ( - "github.com/trustwallet/blockatlas/market/clients/coingecko" - "github.com/trustwallet/blockatlas/market/rate" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "strings" -) - -const ( - id = "coingecko" -) - -type Coingecko struct { - client *coingecko.Client - rate.Rate -} - -func InitRate(api string, updateTime string) rate.Provider { - return &Coingecko{ - client: coingecko.NewClient(api), - Rate: rate.Rate{ - Id: id, - UpdateTime: updateTime, - }, - } -} - -func (c *Coingecko) FetchLatestRates() (rates blockatlas.Rates, err error) { - coins, err := c.client.FetchCoinsList() - if err != nil { - return - } - prices := c.client.FetchLatestRates(coins, blockatlas.DefaultCurrency) - - rates = normalizeRates(prices, c.GetId()) - return -} - -func normalizeRates(coinPrices coingecko.CoinPrices, provider string) (rates blockatlas.Rates) { - for _, price := range coinPrices { - rates = append(rates, blockatlas.Rate{ - Currency: strings.ToUpper(price.Symbol), - Rate: 1.0 / price.CurrentPrice, - Timestamp: price.LastUpdated.Unix(), - Provider: provider, - }) - } - return -} diff --git a/market/rate/coingecko/coingecko_test.go b/market/rate/coingecko/coingecko_test.go deleted file mode 100644 index 3757e2421..000000000 --- a/market/rate/coingecko/coingecko_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package coingecko - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/market/clients/coingecko" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "sort" - "testing" - "time" -) - -func Test_normalizeRates(t *testing.T) { - tests := []struct { - name string - prices coingecko.CoinPrices - wantRates blockatlas.Rates - }{ - { - "test normalize coingecko rate 1", - coingecko.CoinPrices{ - { - Symbol: "cUSDC", - CurrentPrice: 0.0021, - }, - { - Symbol: "cREP", - CurrentPrice: 0.02, - }, - }, - blockatlas.Rates{ - blockatlas.Rate{Currency: "CUSDC", Rate: 1 / 0.0021, Timestamp: 333, Provider: id}, - blockatlas.Rate{Currency: "CREP", Rate: 1 / 0.02, Timestamp: 333, Provider: id}, - }, - }, - { - "test normalize coingecko rate 2", - coingecko.CoinPrices{ - { - Symbol: "cUSDC", - CurrentPrice: 110.0021, - }, - { - Symbol: "cREP", - CurrentPrice: 110.02, - }, - }, - blockatlas.Rates{ - blockatlas.Rate{Currency: "CUSDC", Rate: 1 / 110.0021, Timestamp: 123, Provider: id}, - blockatlas.Rate{Currency: "CREP", Rate: 1 / 110.02, Timestamp: 123, Provider: id}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotRates := normalizeRates(tt.prices, id) - now := time.Now().Unix() - sort.Slice(gotRates, func(i, j int) bool { - gotRates[i].Timestamp = now - gotRates[j].Timestamp = now - return gotRates[i].Rate < gotRates[j].Rate - }) - sort.Slice(tt.wantRates, func(i, j int) bool { - tt.wantRates[i].Timestamp = now - tt.wantRates[j].Timestamp = now - return tt.wantRates[i].Rate < tt.wantRates[j].Rate - }) - if !assert.ObjectsAreEqualValues(gotRates, tt.wantRates) { - t.Errorf("normalizeRates() = %v, want %v", gotRates, tt.wantRates) - } - }) - } -} diff --git a/market/rate/compound/compound.go b/market/rate/compound/compound.go deleted file mode 100644 index a641ea806..000000000 --- a/market/rate/compound/compound.go +++ /dev/null @@ -1,49 +0,0 @@ -package compound - -import ( - c "github.com/trustwallet/blockatlas/market/clients/compound" - "github.com/trustwallet/blockatlas/market/rate" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "strings" - "time" -) - -const ( - compound = "compound" -) - -type Compound struct { - rate.Rate - client *c.Client -} - -func InitRate(api string, updateTime string) rate.Provider { - return &Compound{ - Rate: rate.Rate{ - Id: compound, - UpdateTime: updateTime, - }, - client: c.NewClient(api), - } -} - -func (c *Compound) FetchLatestRates() (rates blockatlas.Rates, err error) { - coinPrices, err := c.client.GetData() - if err != nil { - return - } - rates = normalizeRates(coinPrices, c.GetId()) - return -} - -func normalizeRates(coinPrices c.CoinPrices, provider string) (rates blockatlas.Rates) { - for _, cToken := range coinPrices.Data { - rates = append(rates, blockatlas.Rate{ - Currency: strings.ToUpper(cToken.Symbol), - Rate: 1.0 / cToken.UnderlyingPrice.Value, - Timestamp: time.Now().Unix(), - Provider: provider, - }) - } - return -} diff --git a/market/rate/compound/compound_test.go b/market/rate/compound/compound_test.go deleted file mode 100644 index 430c82322..000000000 --- a/market/rate/compound/compound_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package compound - -import ( - "github.com/stretchr/testify/assert" - c "github.com/trustwallet/blockatlas/market/clients/compound" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "sort" - "testing" - "time" -) - -func Test_normalizeRates(t *testing.T) { - provider := "compound" - tests := []struct { - name string - prices c.CoinPrices - wantRates blockatlas.Rates - }{ - { - "test normalize compound rate 1", - c.CoinPrices{ - Data: []c.CToken{ - { - Symbol: "cUSDC", - UnderlyingPrice: c.Amount{Value: 0.0021}, - }, - { - Symbol: "cREP", - UnderlyingPrice: c.Amount{Value: 0.02}, - }, - }, - }, - blockatlas.Rates{ - blockatlas.Rate{Currency: "CUSDC", Rate: 1 / 0.0021, Timestamp: 333, Provider: provider}, - blockatlas.Rate{Currency: "CREP", Rate: 1 / 0.02, Timestamp: 333, Provider: provider}, - }, - }, - { - "test normalize compound rate 2", - c.CoinPrices{ - Data: []c.CToken{ - { - Symbol: "cUSDC", - UnderlyingPrice: c.Amount{Value: 110.0021}, - }, - { - Symbol: "cREP", - UnderlyingPrice: c.Amount{Value: 110.02}, - }, - }, - }, - blockatlas.Rates{ - blockatlas.Rate{Currency: "CUSDC", Rate: 1 / 110.0021, Timestamp: 123, Provider: provider}, - blockatlas.Rate{Currency: "CREP", Rate: 1 / 110.02, Timestamp: 123, Provider: provider}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotRates := normalizeRates(tt.prices, provider) - now := time.Now().Unix() - sort.Slice(gotRates, func(i, j int) bool { - gotRates[i].Timestamp = now - gotRates[j].Timestamp = now - return gotRates[i].Rate < gotRates[j].Rate - }) - sort.Slice(tt.wantRates, func(i, j int) bool { - tt.wantRates[i].Timestamp = now - tt.wantRates[j].Timestamp = now - return tt.wantRates[i].Rate < tt.wantRates[j].Rate - }) - if !assert.ObjectsAreEqualValues(gotRates, tt.wantRates) { - t.Errorf("normalizeRates() = %v, want %v", gotRates, tt.wantRates) - } - }) - } -} diff --git a/market/rate/fixer/fixer.go b/market/rate/fixer/fixer.go deleted file mode 100644 index 34a2587a8..000000000 --- a/market/rate/fixer/fixer.go +++ /dev/null @@ -1,49 +0,0 @@ -package fixer - -import ( - "github.com/trustwallet/blockatlas/market/rate" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "net/url" -) - -const ( - id = "fixer" -) - -type Fixer struct { - rate.Rate - APIKey string - blockatlas.Request -} - -func InitRate(api string, apiKey string, updateTime string) rate.Provider { - return &Fixer{ - Rate: rate.Rate{ - Id: id, - UpdateTime: updateTime, - }, - Request: blockatlas.InitClient(api), - APIKey: apiKey, - } -} - -func (f *Fixer) FetchLatestRates() (rates blockatlas.Rates, err error) { - values := url.Values{ - "access_key": {f.APIKey}, - "base": {blockatlas.DefaultCurrency}, // Base USD supported only in paid api - } - var latest Latest - err = f.Get(&latest, "latest", values) - if err != nil { - return - } - rates = normalizeRates(latest, f.GetId()) - return -} - -func normalizeRates(latest Latest, provider string) (rates blockatlas.Rates) { - for currency, rate := range latest.Rates { - rates = append(rates, blockatlas.Rate{Currency: currency, Rate: rate, Timestamp: latest.Timestamp, Provider: provider}) - } - return -} diff --git a/market/rate/fixer/fixer_test.go b/market/rate/fixer/fixer_test.go deleted file mode 100644 index b3a6c0a26..000000000 --- a/market/rate/fixer/fixer_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package fixer - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "sort" - "testing" - "time" -) - -func Test_normalizeRates(t *testing.T) { - provider := "dex" - tests := []struct { - name string - latest Latest - wantRates blockatlas.Rates - }{ - { - "test normalize fixer rate 1", - Latest{ - Timestamp: 123, - Rates: map[string]float64{"USD": 22.111, "BRL": 33.2, "BTC": 44.99}, - UpdatedAt: time.Now(), - }, - blockatlas.Rates{ - blockatlas.Rate{Currency: "USD", Rate: 22.111, Timestamp: 123, Provider: provider}, - blockatlas.Rate{Currency: "BRL", Rate: 33.2, Timestamp: 123, Provider: provider}, - blockatlas.Rate{Currency: "BTC", Rate: 44.99, Timestamp: 123, Provider: provider}, - }, - }, - { - "test normalize fixer rate 2", - Latest{ - Timestamp: 333, - Rates: map[string]float64{"LSK": 123.321, "IFC": 34.973, "DUO": 998.3}, - UpdatedAt: time.Now(), - }, - blockatlas.Rates{ - blockatlas.Rate{Currency: "IFC", Rate: 34.973, Timestamp: 333, Provider: provider}, - blockatlas.Rate{Currency: "LSK", Rate: 123.321, Timestamp: 333, Provider: provider}, - blockatlas.Rate{Currency: "DUO", Rate: 998.3, Timestamp: 333, Provider: provider}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotRates := normalizeRates(tt.latest, provider) - sort.SliceStable(gotRates, func(i, j int) bool { - return gotRates[i].Rate < gotRates[j].Rate - }) - if !assert.ObjectsAreEqualValues(gotRates, tt.wantRates) { - t.Errorf("normalizeRates() = %v, want %v", gotRates, tt.wantRates) - } - }) - } -} diff --git a/market/rate/fixer/models.go b/market/rate/fixer/models.go deleted file mode 100644 index 6dff9eecb..000000000 --- a/market/rate/fixer/models.go +++ /dev/null @@ -1,11 +0,0 @@ -package fixer - -import ( - "time" -) - -type Latest struct { - Timestamp int64 `json:"timestamp"` - Rates map[string]float64 `json:"rates"` - UpdatedAt time.Time `json:"updated_at"` -} diff --git a/market/rate/provider.go b/market/rate/provider.go deleted file mode 100644 index 5f7b92dcb..000000000 --- a/market/rate/provider.go +++ /dev/null @@ -1,25 +0,0 @@ -package rate - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/storage" -) - -type Provider interface { - Init(storage.Market) error - FetchLatestRates() (blockatlas.Rates, error) - GetUpdateTime() string - GetId() string - GetLogType() string -} - -type Providers map[int]Provider - -func (ps Providers) GetPriority(providerId string) int { - for priority, provider := range ps { - if provider.GetId() == providerId { - return priority - } - } - return -1 -} diff --git a/market/rate/rate.go b/market/rate/rate.go deleted file mode 100644 index 9879c6ff6..000000000 --- a/market/rate/rate.go +++ /dev/null @@ -1,46 +0,0 @@ -package rate - -import ( - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" -) - -const ( - defaultUpdateTime = "5m" -) - -type Rate struct { - Id string - UpdateTime string - Storage storage.Market -} - -func (r *Rate) GetUpdateTime() string { - return r.UpdateTime -} - -func (r *Rate) GetId() string { - return r.Id -} - -func (r *Rate) GetLogType() string { - return "market-rate" -} - -func (r *Rate) Init(storage storage.Market) error { - logger.Info("Init Market Rate Provider", logger.Params{"rate": r.GetId()}) - if len(r.Id) == 0 { - return errors.E("Market Rate: Id cannot be empty") - } - - if storage == nil { - return errors.E("Market Rate: Storage cannot be nil") - } - r.Storage = storage - - if len(r.UpdateTime) == 0 { - r.UpdateTime = defaultUpdateTime - } - return nil -} diff --git a/market/rates.go b/market/rates.go deleted file mode 100644 index 768f3634e..000000000 --- a/market/rates.go +++ /dev/null @@ -1,62 +0,0 @@ -package market - -import ( - "github.com/robfig/cron/v3" - "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/market/rate" - "github.com/trustwallet/blockatlas/market/rate/cmc" - "github.com/trustwallet/blockatlas/market/rate/coingecko" - "github.com/trustwallet/blockatlas/market/rate/compound" - "github.com/trustwallet/blockatlas/market/rate/fixer" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" -) - -var rateProviders rate.Providers - -func InitRates(storage storage.Market) { - rateProviders = rate.Providers{ - // Add Market Quote Providers: - 0: cmc.InitRate( - config.Configuration.Market.Cmc.API, - config.Configuration.Market.Cmc.APIKey, - config.Configuration.Market.Cmc.MapURL, - config.Configuration.Market.RateUpdateTime, - ), - 1: fixer.InitRate( - config.Configuration.Market.Fixer.API, - config.Configuration.Market.Fixer.APIKey, - config.Configuration.Market.Fixer.RateUpdateTime, - ), - 2: compound.InitRate( - config.Configuration.Market.Compound.API, - config.Configuration.Market.RateUpdateTime, - ), - 3: coingecko.InitRate( - config.Configuration.Market.Coingecko.API, - config.Configuration.Market.RateUpdateTime, - ), - } - addRates(storage, rateProviders) -} - -func addRates(storage storage.Market, rates rate.Providers) { - c := cron.New() - for _, r := range rates { - scheduleTasks(storage, r, c) - } - c.Start() -} - -func runRate(storage storage.Market, p rate.Provider) error { - rates, err := p.FetchLatestRates() - if err != nil { - return errors.E(err, "FetchLatestRates") - } - if len(rates) > 0 { - storage.SaveRates(rates, rateProviders) - logger.Info("Market rates", logger.Params{"rates": len(rates), "provider": p.GetId()}) - } - return nil -} diff --git a/market/worker.go b/market/worker.go deleted file mode 100644 index d14545ebd..000000000 --- a/market/worker.go +++ /dev/null @@ -1,75 +0,0 @@ -package market - -import ( - "fmt" - "github.com/cenkalti/backoff" - "github.com/robfig/cron/v3" - "github.com/trustwallet/blockatlas/market/market" - "github.com/trustwallet/blockatlas/market/rate" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" - "time" -) - -const ( - backoffValue = 2 -) - -type Provider interface { - Init(storage.Market) error - GetId() string - GetLogType() string - GetUpdateTime() string -} - -// processBackoff make a exponential backoff for market run -// errors, increasing the retry in a exponential period for each attempt. -func processBackoff(storage storage.Market, md Provider) { - b := backoff.NewExponentialBackOff() - b.MaxElapsedTime = backoffValue * time.Minute - r := func() error { - return run(storage, md) - } - - n := func(err error, t time.Duration) { - logger.Error(err, "process backoff market", logger.Params{"Duration": t.String()}) - } - err := backoff.RetryNotify(r, b, n) - if err != nil { - logger.Error(err, "Market ProcessBackoff") - } -} - -func scheduleTasks(storage storage.Market, md Provider, c *cron.Cron) { - err := md.Init(storage) - if err != nil { - logger.Error(err, "Init Market Error", logger.Params{"Type": md.GetLogType(), "Market": md.GetId()}) - return - } - t := md.GetUpdateTime() - spec := fmt.Sprintf("@every %s", t) - logger.Info("Scheduling market data task", logger.Params{ - "Type": md.GetLogType(), - "Market": md.GetId(), - "Interval": spec, - }) - _, err = c.AddFunc(spec, func() { - go processBackoff(storage, md) - }) - processBackoff(storage, md) - if err != nil { - logger.Error(err, "AddFunc") - } -} - -func run(storage storage.Market, md Provider) error { - logger.Info("Starting market data task...", logger.Params{"Type": md.GetLogType(), "Market": md.GetId()}) - switch m := md.(type) { - case market.Provider: - return runMarket(storage, m) - case rate.Provider: - return runRate(storage, m) - } - return errors.E("invalid market interface") -} diff --git a/pkg/tests/postman/Blockatlas.postman_collection.json b/pkg/tests/postman/Blockatlas.postman_collection.json index d30fd6701..a642b846e 100644 --- a/pkg/tests/postman/Blockatlas.postman_collection.json +++ b/pkg/tests/postman/Blockatlas.postman_collection.json @@ -1,7 +1,7 @@ { "info": { "_postman_id": "4e4d72ba-02c4-4d87-af91-ea42b6225ee4", - "name": "Blockatlas вум", + "name": "Blockatlas", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ @@ -2391,4 +2391,4 @@ } ], "protocolProfileBehavior": {} -} \ No newline at end of file +} diff --git a/storage/market.go b/storage/market.go deleted file mode 100644 index 92ece7cd0..000000000 --- a/storage/market.go +++ /dev/null @@ -1,83 +0,0 @@ -package storage - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - "strings" -) - -const ( - EntityRates = "ATLAS_MARKET_RATES" - EntityQuotes = "ATLAS_MARKET_QUOTES" -) - -type ProviderList interface { - GetPriority(providerId string) int -} - -func (s *Storage) SaveTicker(coin *blockatlas.Ticker, pl ProviderList) error { - cd, err := s.GetTicker(coin.CoinName, coin.TokenId) - if err == nil { - op := pl.GetPriority(cd.Price.Provider) - np := pl.GetPriority(coin.Price.Provider) - if op != -1 && np > op { - return errors.E("ticker provider with less priority") - } - - if cd.LastUpdate.After(coin.LastUpdate) && op >= np { - return errors.E("ticker is outdated or too low priority", errors.Params{ - "oldTickerTime": cd.LastUpdate, - "newTickerTime": coin.LastUpdate, - "oldTickerPriority": op, - "newTickerPriority": np, - }) - } - } - hm := createHashMap(coin.CoinName, coin.TokenId) - return s.AddHM(EntityQuotes, hm, coin) -} - -func (s *Storage) GetTicker(coin, token string) (*blockatlas.Ticker, error) { - hm := createHashMap(coin, token) - var cd *blockatlas.Ticker - err := s.GetHMValue(EntityQuotes, hm, &cd) - if err != nil { - return nil, err - } - return cd, nil -} - -func (s *Storage) SaveRates(rates blockatlas.Rates, pl ProviderList) { - for _, rate := range rates { - r, err := s.GetRate(rate.Currency) - if err == nil { - op := pl.GetPriority(r.Provider) - np := pl.GetPriority(rate.Provider) - if op != -1 && np > op { - continue - } - - if rate.Timestamp < r.Timestamp && op >= np { - continue - } - } - err = s.AddHM(EntityRates, rate.Currency, &rate) - if err != nil { - logger.Error(err, "SaveRates") - continue - } - } -} - -func (s *Storage) GetRate(currency string) (rate *blockatlas.Rate, err error) { - err = s.GetHMValue(EntityRates, currency, &rate) - return -} - -func createHashMap(coin, token string) string { - if len(token) == 0 { - return strings.ToUpper(coin) - } - return strings.ToUpper(strings.Join([]string{coin, token}, "_")) -} diff --git a/storage/storage.go b/storage/storage.go index dfd510851..40b8afd85 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -26,10 +26,3 @@ type Addresses interface { AddSubscriptions(subscriptions []blockatlas.Subscription) DeleteSubscriptions(subscriptions []blockatlas.Subscription) } - -type Market interface { - SaveTicker(coin *blockatlas.Ticker, pl ProviderList) error - GetTicker(coin, token string) (*blockatlas.Ticker, error) - SaveRates(rates blockatlas.Rates, pl ProviderList) - GetRate(currency string) (*blockatlas.Rate, error) -} From 5017d004706a70665185dfe9ab0fb6a8bc9a7f91 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 22 Feb 2020 01:59:55 +0300 Subject: [PATCH 150/506] Remove markets from tests (#905) * Fix functional_test.go - remove markets setup --- pkg/tests/functional/functional_test.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pkg/tests/functional/functional_test.go b/pkg/tests/functional/functional_test.go index 36fc58043..cfa2230fd 100755 --- a/pkg/tests/functional/functional_test.go +++ b/pkg/tests/functional/functional_test.go @@ -58,11 +58,6 @@ func TestApis(t *testing.T) { observerAPI := engine.Group("/observer/v1") api.SetupObserverAPI(observerAPI, cache) } - if config.Configuration.Market.Enabled { - logger.Info("Loading market API") - marketAPI := engine.Group("/v1/market") - api.SetupMarketAPI(marketAPI, cache) - } signalForExit := make(chan os.Signal, 1) From 80ee2b029f9e210593e25074a1ac02b9569e144e Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 22 Feb 2020 07:51:35 +0300 Subject: [PATCH 151/506] config.yml change for production (#906) --- config.yml | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/config.yml b/config.yml index 7d232e425..ce2d95ed7 100644 --- a/config.yml +++ b/config.yml @@ -40,8 +40,8 @@ binance: dex: https://dex.binance.org/api # [NIM] Nimiq: https://nimiq.com -#nimiq: -# api: http://localhost:8648 +nimiq: + api: http://localhost:8648 # [XRP] Ripple: https://ripple.com ripple: @@ -61,39 +61,39 @@ tezos: rpc: https://mainnet.tezos.org.ua # [ETH] Ethereum: https://ethereum.org (Trust-Ray API) -# ethereum: -# api: https://localhost:4567 -# collections_api: https://api.opensea.io -# collections_api_key: [opensea_api_key] -# rpc: [ethereum rpc] +ethereum: + api: https://localhost:4567 + collections_api: https://api.opensea.io + collections_api_key: [opensea_api_key] + rpc: [ethereum rpc] # [ETC] Ethereum Classic: https://ethereumclassic.org (Trust-Ray API) -# classic: -# api: https://localhost:4567 +classic: + api: https://localhost:4567 # [POA] POA Network: https://poa.network (Trust-Ray API) -# poa: -# api: https://localhost:4567 +poa: + api: https://localhost:4567 -# [CLO] Callisto Network: https://callisto.network (Trust-Ray API) -# callisto: -# api: https://localhost:4567 + # [CLO] Callisto Network: https://callisto.network (Trust-Ray API) + callisto: + api: https://localhost:4567 -# [GO] GoChain: https://gochain.io (Trust-Ray API) -# gochain: -# api: https://localhost:4567 + # [GO] GoChain: https://gochain.io (Trust-Ray API) + gochain: + api: https://localhost:4567 -# [WAN] Wanchain: https://wanchain.org (Trust-Ray API) -# wanchain: -# api: https://localhost:4567 + # [WAN] Wanchain: https://wanchain.org (Trust-Ray API) + wanchain: + api: https://localhost:4567 -# [TOMO] TomoChain: https://tomochain.com (Trust-Ray API) -# tomochain: -# api: https://localhost:4567 + # [TOMO] TomoChain: https://tomochain.com (Trust-Ray API) + tomochain: + api: https://localhost:4567 -# [TT] ThunderCore: https://www.thundercore.com (Trust-Ray API) -# thundertoken: -# api: https://localhost:4567 + # [TT] ThunderCore: https://www.thundercore.com (Trust-Ray API) + thundertoken: + api: https://localhost:4567 # [AION] Aion: https://aion.network aion: From fb04f17d5cfdd9c1e77d1196c36f5bf9e8b167cc Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 22 Feb 2020 08:39:00 +0300 Subject: [PATCH 152/506] Remove useless and dangerous config change that broke everything 3 times (#907) * Remove useless and dangerous config change that broke everything 3 times * Return commented config.yml * Return viper to the tests --- api/handlers.go | 4 +- api/observer.go | 4 +- cmd/observer_api/main.go | 4 +- cmd/platform_api/main.go | 6 +- cmd/platform_observer/main.go | 10 +-- cmd/swagger_api/main.go | 4 +- config.yml | 52 ++++++------- config/configuration.go | 93 +++++------------------ internal/init.go | 3 +- observer/stream.go | 6 +- pkg/ginutils/reverse_proxy.go | 4 +- pkg/tests/functional/functional_test.go | 5 +- pkg/tests/integration/integration_test.go | 4 +- pkg/tests/integration/ontology/block.go | 2 +- 14 files changed, 76 insertions(+), 125 deletions(-) diff --git a/api/handlers.go b/api/handlers.go index 6b96ddca5..322b21841 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -4,7 +4,7 @@ import ( "github.com/chenjiandongx/ginprom" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/trustwallet/blockatlas/config" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/metrics" @@ -271,7 +271,7 @@ func makeTokenRoute(router gin.IRouter, api blockatlas.Platform) { func MakeMetricsRoute(router gin.IRouter) { router.Use(metrics.PromMiddleware()) m := router.Group("/metrics") - m.Use(ginutils.TokenAuthMiddleware(config.Configuration.Metrics.APIToken)) + m.Use(ginutils.TokenAuthMiddleware(viper.GetString("metrics.api_token"))) m.GET("/", ginprom.PromHandler(promhttp.Handler())) } diff --git a/api/observer.go b/api/observer.go index ca6b22cb7..fc230b694 100644 --- a/api/observer.go +++ b/api/observer.go @@ -2,7 +2,7 @@ package api import ( "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/config" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/platform" @@ -10,7 +10,7 @@ import ( ) func SetupObserverAPI(router gin.IRouter, db *storage.Storage) { - router.Use(ginutils.TokenAuthMiddleware(config.Configuration.Observer.Auth)) + router.Use(ginutils.TokenAuthMiddleware(viper.GetString("metrics.api_token"))) router.POST("/webhook/register", addCall(db)) router.DELETE("/webhook/register", deleteCall(db)) router.GET("/status", statusCall(db)) diff --git a/cmd/observer_api/main.go b/cmd/observer_api/main.go index 997b3901b..0eabaa994 100644 --- a/cmd/observer_api/main.go +++ b/cmd/observer_api/main.go @@ -2,9 +2,9 @@ package main import ( "github.com/gin-gonic/gin" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" "github.com/trustwallet/blockatlas/build" - "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -29,7 +29,7 @@ func init() { } func main() { - gin.SetMode(config.Configuration.Gin.Mode) + gin.SetMode(viper.GetString("gin.mode")) engine := gin.New() engine.Use(ginutils.CheckReverseProxy, *sg) diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index 6f7d69d66..fa58fc84f 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -2,9 +2,9 @@ package main import ( "github.com/gin-gonic/gin" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" "github.com/trustwallet/blockatlas/build" - "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -24,11 +24,11 @@ var ( func init() { build.LogVersionInfo() port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) - platform.Init(config.Configuration.Platform) + platform.Init(viper.GetString("platform")) } func main() { - gin.SetMode(config.Configuration.Gin.Mode) + gin.SetMode(viper.GetString("gin.mode")) engine := gin.New() engine.Use(ginutils.CheckReverseProxy, *sg) engine.Use(ginutils.CORSMiddleware()) diff --git a/cmd/platform_observer/main.go b/cmd/platform_observer/main.go index 04cdfe1e1..a1e0a30ff 100644 --- a/cmd/platform_observer/main.go +++ b/cmd/platform_observer/main.go @@ -2,8 +2,8 @@ package main import ( "context" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/build" - "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/observer" "github.com/trustwallet/blockatlas/pkg/logger" @@ -24,7 +24,7 @@ var ( func init() { build.LogVersionInfo() _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) - platform.Init(config.Configuration.Platform) + platform.Init(viper.GetString("platform")) } func main() { @@ -32,9 +32,9 @@ func main() { logger.Fatal("No APIs to observe") } - backlogTime := config.Configuration.Observer.Backlog - minInterval := config.Configuration.Observer.BlockPoll.Min - maxInterval := config.Configuration.Observer.BlockPoll.Max + backlogTime := viper.GetDuration("observer.backlog") + minInterval := viper.GetDuration("observer.block_poll.min") + maxInterval := viper.GetDuration("observer.block_poll.max") if minInterval >= maxInterval { logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") } diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go index 2b4c85115..02c4f431d 100644 --- a/cmd/swagger_api/main.go +++ b/cmd/swagger_api/main.go @@ -2,11 +2,11 @@ package main import ( "github.com/gin-gonic/gin" + "github.com/spf13/viper" ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" "github.com/trustwallet/blockatlas/api" "github.com/trustwallet/blockatlas/build" - "github.com/trustwallet/blockatlas/config" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -29,7 +29,7 @@ func init() { } func main() { - gin.SetMode(config.Configuration.Gin.Mode) + gin.SetMode(viper.GetString("gin.mode")) engine := gin.New() engine.Use(ginutils.CheckReverseProxy, *sg) diff --git a/config.yml b/config.yml index ce2d95ed7..7d232e425 100644 --- a/config.yml +++ b/config.yml @@ -40,8 +40,8 @@ binance: dex: https://dex.binance.org/api # [NIM] Nimiq: https://nimiq.com -nimiq: - api: http://localhost:8648 +#nimiq: +# api: http://localhost:8648 # [XRP] Ripple: https://ripple.com ripple: @@ -61,39 +61,39 @@ tezos: rpc: https://mainnet.tezos.org.ua # [ETH] Ethereum: https://ethereum.org (Trust-Ray API) -ethereum: - api: https://localhost:4567 - collections_api: https://api.opensea.io - collections_api_key: [opensea_api_key] - rpc: [ethereum rpc] +# ethereum: +# api: https://localhost:4567 +# collections_api: https://api.opensea.io +# collections_api_key: [opensea_api_key] +# rpc: [ethereum rpc] # [ETC] Ethereum Classic: https://ethereumclassic.org (Trust-Ray API) -classic: - api: https://localhost:4567 +# classic: +# api: https://localhost:4567 # [POA] POA Network: https://poa.network (Trust-Ray API) -poa: - api: https://localhost:4567 +# poa: +# api: https://localhost:4567 - # [CLO] Callisto Network: https://callisto.network (Trust-Ray API) - callisto: - api: https://localhost:4567 +# [CLO] Callisto Network: https://callisto.network (Trust-Ray API) +# callisto: +# api: https://localhost:4567 - # [GO] GoChain: https://gochain.io (Trust-Ray API) - gochain: - api: https://localhost:4567 +# [GO] GoChain: https://gochain.io (Trust-Ray API) +# gochain: +# api: https://localhost:4567 - # [WAN] Wanchain: https://wanchain.org (Trust-Ray API) - wanchain: - api: https://localhost:4567 +# [WAN] Wanchain: https://wanchain.org (Trust-Ray API) +# wanchain: +# api: https://localhost:4567 - # [TOMO] TomoChain: https://tomochain.com (Trust-Ray API) - tomochain: - api: https://localhost:4567 +# [TOMO] TomoChain: https://tomochain.com (Trust-Ray API) +# tomochain: +# api: https://localhost:4567 - # [TT] ThunderCore: https://www.thundercore.com (Trust-Ray API) - thundertoken: - api: https://localhost:4567 +# [TT] ThunderCore: https://www.thundercore.com (Trust-Ray API) +# thundertoken: +# api: https://localhost:4567 # [AION] Aion: https://aion.network aion: diff --git a/config/configuration.go b/config/configuration.go index 4c9f836ff..56c11e623 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -4,89 +4,36 @@ import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/logger" "strings" - "time" ) -type configuration struct { - Gin struct { - Mode string - ReverseProxy bool `mapstructure:"reverse_proxy"` - } - Platform string - Metrics struct { - APIToken string `mapstructure:"api_token"` - } - Sentry struct { - Dsn string - } - Observer struct { - Enabled bool - Auth string - Backlog time.Duration - BacklogMaxBlocks int64 `mapstructure:"backlog_max_blocks"` - StreamConns int `mapstructure:"stream_conns"` - BlockPoll struct { - Min time.Duration - Max time.Duration - } `mapstructure:"block_poll"` - } - Market struct { - Enabled bool - Auth string - QuoteUpdateTime string `mapstructure:"quote_update_time"` - RateUpdateTime string `mapstructure:"rate_update_time"` - Dex struct { - QuoteUpdateTime string `mapstructure:"quote_update_time"` - API string - } - Cmc struct { - API string - WebAPI string - WidgetAPI string - APIKey string `mapstructure:"api_key"` - MapURL string `mapstructure:"map_url"` - } - Fixer struct { - API string - APIKey string `mapstructure:"api_key"` - RateUpdateTime string `mapstructure:"rate_update_time"` - } - Compound struct { - API string - } - Coingecko struct { - API string - } - } - Storage struct { - Redis string - } -} - -var Configuration configuration - -// LoadConfig reads in config file and ENV variables if set. func LoadConfig(confPath string) { + // Load config from environment viper.SetEnvPrefix("atlas") // will be uppercased automatically => ATLAS - viper.AutomaticEnv() // read in environment variables that match viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.AutomaticEnv() + viper.AddConfigPath(".") viper.SetConfigName("config") viper.SetConfigType("yml") // Load config file - if len(confPath) > 0 { - viper.SetConfigFile(confPath) + if confPath == "" { + if err := viper.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); ok { + logger.Info("Config file was not supplied") + } else { + logger.Fatal("Issue reading config", err) + } + } + logger.Info("Viper config", logger.Params{"config_file": viper.ConfigFileUsed()}) } else { - confPath = viper.ConfigFileUsed() - } - err := viper.ReadInConfig() - if err != nil { - logger.Info("Failed to read config", err, logger.Params{"config_file": confPath}) - } - logger.Info("Using config file", logger.Params{"config_file": confPath}) - - if err := viper.Unmarshal(&Configuration); err != nil { - logger.Error(err, "Error Unmarshal Viper Config File") + viper.SetConfigFile(confPath) + err := viper.ReadInConfig() + if err != nil { + logger.Error("Failed to read config", err, + logger.Params{"config_file": confPath}) + } else { + logger.Info("Using config file", logger.Params{"config_file": confPath}) + } } } diff --git a/internal/init.go b/internal/init.go index 6b9ca41be..319cc6e35 100644 --- a/internal/init.go +++ b/internal/init.go @@ -4,6 +4,7 @@ import ( "flag" sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" @@ -55,7 +56,7 @@ func InitAPIWithRedis(defaultPort, defaultConfigPath string) (string, string, *g config.LoadConfig(confPath) logger.InitLogger() - err = cache.Init(config.Configuration.Storage.Redis) + err = cache.Init(viper.GetString("storage.redis")) if err != nil { logger.Fatal(err) } diff --git a/observer/stream.go b/observer/stream.go index d447211c2..b86c95af5 100644 --- a/observer/stream.go +++ b/observer/stream.go @@ -2,7 +2,7 @@ package observer import ( "context" - "github.com/trustwallet/blockatlas/config" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/semaphore" @@ -30,7 +30,7 @@ func (s *Stream) Execute(ctx context.Context) <-chan *blockatlas.Block { cn := s.BlockAPI.Coin() s.coin = cn.ID s.logParams = logger.Params{"platform": cn.Handle} - conns := config.Configuration.Observer.StreamConns + conns := viper.GetInt("observer.stream_conns") if conns == 0 { logger.Fatal("observer.stream_conns is 0") } @@ -71,7 +71,7 @@ func (s *Stream) load(c chan<- *blockatlas.Block) { if height-lastHeight > int64(s.BacklogCount) { lastHeight = height - int64(s.BacklogCount) } - backLogMax := config.Configuration.Observer.BacklogMaxBlocks + backLogMax := viper.GetInt64("observer.backlog_max_blocks") if height-lastHeight > backLogMax { lastHeight = height - backLogMax } diff --git a/pkg/ginutils/reverse_proxy.go b/pkg/ginutils/reverse_proxy.go index 5840a1b8e..c828956ed 100644 --- a/pkg/ginutils/reverse_proxy.go +++ b/pkg/ginutils/reverse_proxy.go @@ -2,13 +2,13 @@ package ginutils import ( "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/config" + "github.com/spf13/viper" ) // CheckReverseProxy removes untrusted forwarded HTTP headers // if gin.reverse_proxy is defined func CheckReverseProxy(c *gin.Context) { - if !config.Configuration.Gin.ReverseProxy { + if !viper.GetBool("gin.reverse_proxy") { c.Request.Header.Del("Forwarded") c.Request.Header.Del("X-Forwarded-Proto") c.Request.Header.Del("X-Forwarded-Host") diff --git a/pkg/tests/functional/functional_test.go b/pkg/tests/functional/functional_test.go index cfa2230fd..96f7a86dd 100755 --- a/pkg/tests/functional/functional_test.go +++ b/pkg/tests/functional/functional_test.go @@ -6,6 +6,7 @@ import ( "context" "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" + "github.com/spf13/viper" "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" "github.com/trustwallet/blockatlas/api" @@ -29,7 +30,7 @@ func TestApis(t *testing.T) { config.LoadConfig(os.Getenv("TEST_CONFIG")) logger.InitLogger() - platform.Init(config.Configuration.Platform) + platform.Init(viper.GetString("platform")) cache := storage.New() sg := sentrygin.New(sentrygin.Options{}) p := ":8420" @@ -53,7 +54,7 @@ func TestApis(t *testing.T) { api.MakeMetricsRoute(engine) api.LoadPlatforms(engine) - if config.Configuration.Observer.Enabled { + if viper.GetBool("observer.enabled") { logger.Info("Loading observer API") observerAPI := engine.Group("/observer/v1") api.SetupObserverAPI(observerAPI, cache) diff --git a/pkg/tests/integration/integration_test.go b/pkg/tests/integration/integration_test.go index 7e220322a..28b6d6bdd 100755 --- a/pkg/tests/integration/integration_test.go +++ b/pkg/tests/integration/integration_test.go @@ -3,10 +3,12 @@ package integration import ( + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/tests/integration/bitcoin" "github.com/trustwallet/blockatlas/pkg/tests/integration/domains" "github.com/trustwallet/blockatlas/pkg/tests/integration/ontology" + "github.com/trustwallet/blockatlas/platform" "os" "testing" @@ -19,7 +21,7 @@ func Test(t *testing.T) { } else { config.LoadConfig(configPath) } - platform.Init(config.Configuration.Platform) + platform.Init(viper.GetString("platform")) // Add your integration tests here ontology.TestOntology(t) diff --git a/pkg/tests/integration/ontology/block.go b/pkg/tests/integration/ontology/block.go index d5c01b1ae..7ffa7d214 100755 --- a/pkg/tests/integration/ontology/block.go +++ b/pkg/tests/integration/ontology/block.go @@ -1,4 +1,4 @@ -// +build integration +// build integration package ontology From 620b01fb080ce782bb0b1188556f3aee6c1c2e25 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 22 Feb 2020 09:12:00 +0300 Subject: [PATCH 153/506] Remove unstable handle from tests (#908) --- pkg/tests/functional/testdata/exclude.json | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/tests/functional/testdata/exclude.json b/pkg/tests/functional/testdata/exclude.json index 1326f2894..189274cbc 100644 --- a/pkg/tests/functional/testdata/exclude.json +++ b/pkg/tests/functional/testdata/exclude.json @@ -3,6 +3,7 @@ "/v1/fio/:address", "/v2/fio/transactions/:address", "/v1/aeternity/:address", + "/v1/ethereum/:address", "/v2/aeternity/transactions/:address", "/v2/collectibles/categories", "/v3/collectibles/categories", From 96a026a68b03d2f94c46ac34885c3bd5119b286a Mon Sep 17 00:00:00 2001 From: maxUo <20925019+maxUo@users.noreply.github.com> Date: Sun, 23 Feb 2020 14:09:47 +0300 Subject: [PATCH 154/506] Add nginx-proxy for local development (#911) * Add nginx-proxy for local development * ... --- Dockerfile | 15 +++++++++------ docker-compose.yml | 18 +++++++++++++++--- nginx.conf | 15 +++++++++++++++ 3 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 nginx.conf diff --git a/Dockerfile b/Dockerfile index dbb9cfecc..b8267f344 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,19 @@ -FROM golang:latest AS builder +FROM golang:1.13.6-alpine as builder ARG SERVICE +RUN apk add --update --no-cache git build-base musl-dev linux-headers RUN mkdir /build -ADD . /build WORKDIR /build +COPY go.mod . +COPY go.sum . +RUN go mod download +COPY . . RUN go build -o bin/blockatlas ./cmd/$SERVICE -FROM debian:latest -COPY --from=builder /build/bin /app/bin/$SERVICE +FROM alpine:latest +COPY --from=builder /build/bin /bin/ COPY --from=builder /build/config.yml /config/ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -WORKDIR /app/bin/$SERVICE -ENTRYPOINT ["/app/bin/blockatlas", "-c", "/config/config.yml"] +ENTRYPOINT ["/bin/blockatlas", "-c", "/config/config.yml"] diff --git a/docker-compose.yml b/docker-compose.yml index 6bb3a2dbf..c7fcc7778 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,17 @@ version: '3.7' services: + nginx: + container_name: nginx + image: nginx:alpine + volumes: + - ./nginx.conf:/etc/nginx/conf.d/default.conf + ports: + - 8080:80 + links: + - observer_api + - platform_api + - swagger_api + observer_api: container_name: observer_api build: @@ -38,7 +50,7 @@ services: - redis redis: - container_name: redis1 - image: neojt/mredis + container_name: redis + image: redis ports: - - 6379:6379 + - 6379:6379 \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 000000000..77b5be96a --- /dev/null +++ b/nginx.conf @@ -0,0 +1,15 @@ +server { + listen 80; + + location ~* /swagger.* { + proxy_pass http://swagger_api:8423; + } + + location ~* /observer.* { + proxy_pass http://observer_api:8422; + } + + location / { + proxy_pass http://platform_api:8420; + } +} \ No newline at end of file From 524f6b599f188ca324cf7eb3f64546c4df920df0 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 23 Feb 2020 15:19:39 +0300 Subject: [PATCH 155/506] Update postman and fix collections (#910) --- .../Blockatlas.postman_collection.json | 140 +++++++++++++++++- platform/ethereum/base.go | 18 +-- platform/platform.go | 18 ++- 3 files changed, 156 insertions(+), 20 deletions(-) diff --git a/pkg/tests/postman/Blockatlas.postman_collection.json b/pkg/tests/postman/Blockatlas.postman_collection.json index a642b846e..be23b38a3 100644 --- a/pkg/tests/postman/Blockatlas.postman_collection.json +++ b/pkg/tests/postman/Blockatlas.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "4e4d72ba-02c4-4d87-af91-ea42b6225ee4", + "_postman_id": "9cea8a5c-d3e5-40c1-98da-0a7a1742cf6d", "name": "Blockatlas", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -1349,6 +1349,144 @@ } }, "response": [] + }, + { + "name": "collections batch v3 ", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"docs\": {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"symbol\": {", + " \"type\": \"string\"", + " },", + " \"slug\": {", + " \"type\": \"string\"", + " },", + " \"image_url\": {", + " \"type\": \"string\"", + " },", + " \"external_link\": {", + " \"type\": \"string\"", + " },", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"category_address\": {", + " \"type\": \"string\"", + " },", + " \"address\": {", + " \"type\": \"string\"", + " },", + " \"nft_version\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " }", + " }", + " }", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid: \" + address, function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + " console.log(JSON.stringify(jsonData))", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}", + "type": "text" + }, + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"{{coin}}\": [\"{{address}}\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/v3/collectibles/categories", + "host": [ + "{{host}}" + ], + "path": [ + "v3", + "collectibles", + "categories" + ] + } + }, + "response": [] } ], "protocolProfileBehavior": {}, diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index 4d78bcd8d..d83040657 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -12,19 +12,15 @@ type Platform struct { collectionsClient CollectionsClient } -func Init(coin uint, api, rpc string) *Platform { - return &Platform{ - CoinIndex: coin, - RpcURL: rpc, - client: Client{blockatlas.InitClient(api)}, +func Init(coin uint, api, rpc, collectionApi, collectionKey string) *Platform { + p := Platform{ + CoinIndex: coin, + RpcURL: rpc, + client: Client{blockatlas.InitClient(api)}, + collectionsClient: CollectionsClient{blockatlas.InitClient(collectionApi)}, } -} - -func InitWitCollection(coin uint, api, rpc, collectionApi, collectionKey string) *Platform { - p := Init(coin, api, rpc) - p.collectionsClient = CollectionsClient{blockatlas.InitClient(collectionApi)} p.collectionsClient.Headers["X-API-KEY"] = collectionKey - return p + return &p } func (p *Platform) Coin() coin.Coin { diff --git a/platform/platform.go b/platform/platform.go index 502ab16ad..2ef29fb22 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -31,6 +31,8 @@ import ( "github.com/trustwallet/blockatlas/platform/zilliqa" ) +const emptyParam = "" + func GetVar(name string) string { return viper.GetString(name) } @@ -85,13 +87,13 @@ func getPlatformMap() blockatlas.Platforms { coin.Dash().Handle: bitcoin.Init(coin.DASH, GetApiVar(coin.DASH)), coin.Doge().Handle: bitcoin.Init(coin.DOGE, GetApiVar(coin.DOGE)), coin.Qtum().Handle: bitcoin.Init(coin.QTUM, GetApiVar(coin.QTUM)), - coin.Gochain().Handle: ethereum.Init(coin.GO, GetApiVar(coin.GO), GetRpcVar(coin.GO)), - coin.Thundertoken().Handle: ethereum.Init(coin.TT, GetApiVar(coin.TT), GetRpcVar(coin.TT)), - coin.Classic().Handle: ethereum.Init(coin.ETC, GetApiVar(coin.ETC), GetRpcVar(coin.ETC)), - coin.Poa().Handle: ethereum.Init(coin.POA, GetApiVar(coin.POA), GetRpcVar(coin.POA)), - coin.Callisto().Handle: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO)), - coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN)), - coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), - coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), + coin.Gochain().Handle: ethereum.Init(coin.GO, GetApiVar(coin.GO), GetRpcVar(coin.GO), emptyParam, emptyParam), + coin.Thundertoken().Handle: ethereum.Init(coin.TT, GetApiVar(coin.TT), GetRpcVar(coin.TT), emptyParam, emptyParam), + coin.Classic().Handle: ethereum.Init(coin.ETC, GetApiVar(coin.ETC), GetRpcVar(coin.ETC), emptyParam, emptyParam), + coin.Poa().Handle: ethereum.Init(coin.POA, GetApiVar(coin.POA), GetRpcVar(coin.POA), emptyParam, emptyParam), + coin.Callisto().Handle: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO), emptyParam, emptyParam), + coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN), emptyParam, emptyParam), + coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO), emptyParam, emptyParam), + coin.Ethereum().Handle: ethereum.Init(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), } } From 161e9e6ab2ba3b0af8c3f5796149e4ad29958572 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Mon, 24 Feb 2020 02:16:51 +0300 Subject: [PATCH 156/506] Refactor and fixes (Split api routes, remove metrics and build packages, change nano and config.yml) (#916) * Split api routes with proper namings, remove tests from pkg folder, put build package into internal, remove unused code, refactor some code * Remove sentry and metrics, small api refactor + rename storage files * Change config.yml * nano small refactor, return err for normalize tx * add postman run all script * Return init to previous architecture and create whitelist for collections apis * Remove sentry call and refactor whitelist --- Makefile | 6 +- README.md | 2 +- api/batch.go | 179 ---------------- api/{handlers.go => collection.go} | 202 ++++++------------ api/{naming_service.go => domain.go} | 0 api/meta.go | 30 --- api/observer.go | 8 - api/routes.go | 70 ++++-- api/{stake.go => staking.go} | 92 ++++++++ api/transaction.go | 141 ++++++++++++ build/build.go | 26 --- cmd/observer_api/main.go | 19 +- cmd/platform_api/main.go | 20 +- cmd/platform_observer/main.go | 2 - cmd/swagger_api/main.go | 15 +- coin/gen_test.go | 3 + config.yml | 7 +- go.sum | 15 ++ internal/init.go | 24 ++- observer/dispatcher.go | 4 +- pkg/address/address.go | 2 +- pkg/blockatlas/client.go | 3 - pkg/blockatlas/clientcache.go | 4 +- pkg/blockatlas/jsonrpc.go | 4 +- pkg/blockatlas/marshal.go | 6 +- pkg/errors/errors.go | 22 +- pkg/ginutils/gincache/cache.go | 4 +- pkg/metrics/client.go | 35 --- pkg/metrics/metrics.go | 16 -- pkg/metrics/metrics_test.go | 24 --- pkg/metrics/server.go | 89 -------- pkg/numbers/decimal.go | 4 +- platform/binance/block.go | 2 +- platform/binance/client.go | 4 +- platform/cosmos/client.go | 2 +- platform/cosmos/stake.go | 2 +- platform/ethereum/base.go | 18 +- platform/ethereum/collection_client.go | 4 +- platform/harmony/transaction.go | 2 +- platform/icon/transaction.go | 2 +- platform/iotex/client.go | 2 +- platform/nano/transaction.go | 21 +- platform/nano/transaction_test.go | 2 +- platform/platform.go | 27 ++- platform/registry.go | 21 +- platform/stellar/client.go | 2 +- platform/tron/transaction.go | 10 +- platform/vechain/transaction.go | 8 +- scripts/run_tests_postman.sh | 11 + services/assets/info.go | 26 --- services/assets/info_test.go | 30 --- services/assets/model.go | 35 +-- storage/{subscriptions.go => addresses.go} | 0 storage/{block.go => tracker.go} | 0 {pkg/tests => tests}/functional/fixtures.go | 0 .../functional/functional_test.go | 9 +- {pkg/tests => tests}/functional/http.go | 0 .../functional/testdata/body_fixtures.json | 0 .../functional/testdata/coin_fixtures.json | 0 .../functional/testdata/exclude.json | 0 .../functional/testdata/query_fixtures.json | 0 .../integration/bitcoin/block.go | 0 .../integration/domains/domains.go | 0 .../integration/integration_test.go | 6 +- .../integration/ontology/block.go | 0 .../Blockatlas.postman_collection.json | 0 .../postman/collection_data.json | 0 {pkg/tests => tests}/postman/domain_data.json | 0 .../postman/healthcheck_data.json | 0 {pkg/tests => tests}/postman/market_data.json | 0 .../postman/observer_data.json | 0 .../tests => tests}/postman/staking_data.json | 0 {pkg/tests => tests}/postman/token_data.json | 0 .../postman/transaction_data.json | 2 +- 74 files changed, 549 insertions(+), 777 deletions(-) delete mode 100644 api/batch.go rename api/{handlers.go => collection.go} (54%) rename api/{naming_service.go => domain.go} (100%) delete mode 100644 api/meta.go rename api/{stake.go => staking.go} (55%) create mode 100644 api/transaction.go delete mode 100644 build/build.go delete mode 100644 pkg/metrics/client.go delete mode 100644 pkg/metrics/metrics.go delete mode 100644 pkg/metrics/metrics_test.go delete mode 100644 pkg/metrics/server.go create mode 100755 scripts/run_tests_postman.sh delete mode 100644 services/assets/info.go delete mode 100644 services/assets/info_test.go rename storage/{subscriptions.go => addresses.go} (100%) rename storage/{block.go => tracker.go} (100%) rename {pkg/tests => tests}/functional/fixtures.go (100%) rename {pkg/tests => tests}/functional/functional_test.go (89%) rename {pkg/tests => tests}/functional/http.go (100%) rename {pkg/tests => tests}/functional/testdata/body_fixtures.json (100%) rename {pkg/tests => tests}/functional/testdata/coin_fixtures.json (100%) rename {pkg/tests => tests}/functional/testdata/exclude.json (100%) rename {pkg/tests => tests}/functional/testdata/query_fixtures.json (100%) rename {pkg/tests => tests}/integration/bitcoin/block.go (100%) rename {pkg/tests => tests}/integration/domains/domains.go (100%) rename {pkg/tests => tests}/integration/integration_test.go (72%) rename {pkg/tests => tests}/integration/ontology/block.go (100%) rename {pkg/tests => tests}/postman/Blockatlas.postman_collection.json (100%) rename {pkg/tests => tests}/postman/collection_data.json (100%) rename {pkg/tests => tests}/postman/domain_data.json (100%) rename {pkg/tests => tests}/postman/healthcheck_data.json (100%) rename {pkg/tests => tests}/postman/market_data.json (100%) rename {pkg/tests => tests}/postman/observer_data.json (100%) rename {pkg/tests => tests}/postman/staking_data.json (100%) rename {pkg/tests => tests}/postman/token_data.json (100%) rename {pkg/tests => tests}/postman/transaction_data.json (99%) diff --git a/Makefile b/Makefile index 8c9bbd5b5..49451dece 100644 --- a/Makefile +++ b/Makefile @@ -154,7 +154,7 @@ ifeq (,$(test)) @bash -c "$(MAKE) newman test=healthcheck host=$(host)" @bash -c "$(MAKE) newman test=observer host=$(host)" else - @newman run pkg/tests/postman/Blockatlas.postman_collection.json --folder $(test) -d pkg/tests/postman/$(test)_data.json --env-var "host=$(host)" + @newman run tests/postman/Blockatlas.postman_collection.json --folder $(test) -d tests/postman/$(test)_data.json --env-var "host=$(host)" endif go-compile: go-get go-build @@ -190,11 +190,11 @@ go-test: go-functional: @echo " > Running functional tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=functional -v ./pkg/tests/functional + GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=functional -v ./tests/functional go-integration: @echo " > Running integration tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./pkg/tests/integration + GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration go-fmt: @echo " > Format all go files" diff --git a/README.md b/README.md index de5746f81..1a1eab1b1 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ The observer API watches the chain for new transactions and generates notificati ### Requirements * [Go Toolchain](https://golang.org/doc/install) versions 1.13+ - * [Redis](https://redis.io/topics/quickstart) instance (observer and markets) + * [Redis](https://redis.io/topics/quickstart) instance for platform_observer ### From Source diff --git a/api/batch.go b/api/batch.go deleted file mode 100644 index 9f511c8d5..000000000 --- a/api/batch.go +++ /dev/null @@ -1,179 +0,0 @@ -package api - -import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/pkg/ginutils/gincache" - "github.com/trustwallet/blockatlas/platform" - "strconv" - "time" -) - -type AddressBatchRequest struct { - Address string `json:"address"` - CoinBatchRequest -} - -type CoinBatchRequest struct { - Coin uint `json:"coin"` -} - -type ENSBatchRequest struct { - Coins []uint64 `json:"coins"` - Name string `json:"name"` -} - -type AddressesRequest []AddressBatchRequest -type CoinsRequest []CoinBatchRequest - -// @Summary Get Multiple Stake Delegations -// @ID batch_delegations -// @Description Get Stake Delegations for multiple coins -// @Accept json -// @Produce json -// @Tags Staking -// @Param delegations body api.AddressesRequest true "Validators addresses and coins" -// @Success 200 {object} blockatlas.DelegationsBatchPage -// @Router /v2/staking/delegations [post] -func makeStakingDelegationsBatchRoute(router gin.IRouter) { - router.POST("/staking/delegations", func(c *gin.Context) { - var reqs AddressesRequest - if err := c.BindJSON(&reqs); err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - batch := make(blockatlas.DelegationsBatchPage, 0) - for _, r := range reqs { - c, ok := coin.Coins[r.Coin] - if !ok { - continue - } - p, ok := platform.StakeAPIs[c.Handle] - if !ok { - continue - } - delegation, err := getDelegationResponse(p, r.Address) - if err != nil { - continue - } - batch = append(batch, delegation) - } - ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: batch}) - }) -} - -// @Summary Get Multiple Stake Delegations -// @ID batch_delegations -// @Description Get Stake Delegations for multiple coins -// @Accept json -// @Produce json -// @Tags Staking -// @Param delegations body api.AddressesRequest true "Validators addresses and coins" -// @Success 200 {object} blockatlas.DelegationsBatchPage -// @Router /v2/staking/list [post] -func makeStakingDelegationsSimpleBatchRoute(router gin.IRouter) { - router.POST("/staking/list", gincache.CacheMiddleware(time.Hour*24, func(c *gin.Context) { - var reqs CoinsRequest - if err := c.BindJSON(&reqs); err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - batch := make(blockatlas.StakingBatchPage, 0) - for _, r := range reqs { - c, ok := coin.Coins[r.Coin] - if !ok { - continue - } - p, ok := platform.StakeAPIs[c.Handle] - if !ok { - continue - } - staking := getStakingResponse(p) - batch = append(batch, staking) - } - ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: batch}) - })) -} - -// @Description Get collection categories -// @ID collection_categories_v2 -// @Summary Get list of collections from a specific coin and addresses -// @Accept json -// @Produce json -// @Tags Collections -// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) -// @Success 200 {object} blockatlas.DocsResponse -// @Router /v2/collectibles/categories [post] -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func oldMakeCategoriesBatchRoute(router gin.IRouter) { - router.POST("/collectibles/categories", func(c *gin.Context) { - var reqs map[string][]string - if err := c.BindJSON(&reqs); err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - batch := make(blockatlas.CollectionPage, 0) - for key, addresses := range reqs { - coinId, err := strconv.Atoi(key) - if err != nil { - continue - } - p, ok := platform.CollectionAPIs[uint(coinId)] - if !ok { - continue - } - for _, address := range addresses { - collections, err := p.OldGetCollections(address) - if err != nil { - continue - } - batch = append(batch, collections...) - } - } - ginutils.RenderSuccess(c, batch) - }) -} - -// @Description Get collection categories -// @ID collection_categories_v3 -// @Summary Get list of collections from a specific coin and addresses -// @Accept json -// @Produce json -// @Tags Collections -// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) -// @Success 200 {object} blockatlas.DocsResponse -// @Router /v3/collectibles/categories [post] -func makeCategoriesBatchRoute(router gin.IRouter) { - router.POST("/collectibles/categories", func(c *gin.Context) { - var reqs map[string][]string - if err := c.BindJSON(&reqs); err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - batch := make(blockatlas.CollectionPage, 0) - for key, addresses := range reqs { - coinId, err := strconv.Atoi(key) - if err != nil { - continue - } - p, ok := platform.CollectionAPIs[uint(coinId)] - if !ok { - continue - } - for _, address := range addresses { - collections, err := p.GetCollections(address) - if err != nil { - continue - } - batch = append(batch, collections...) - } - } - ginutils.RenderSuccess(c, batch) - }) -} diff --git a/api/handlers.go b/api/collection.go similarity index 54% rename from api/handlers.go rename to api/collection.go index 322b21841..35c57e079 100644 --- a/api/handlers.go +++ b/api/collection.go @@ -1,113 +1,13 @@ package api import ( - "github.com/chenjiandongx/ginprom" "github.com/gin-gonic/gin" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/pkg/metrics" - "net/http" - "sort" + "github.com/trustwallet/blockatlas/platform" + "strconv" ) -// @Summary Get Transactions -// @ID tx_v1 -// @Description Get transactions from the address -// @Accept json -// @Produce json -// @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 -// @Router /v1/{coin}/{address} [get] -func makeTxRouteV1(router gin.IRouter, api blockatlas.Platform) { - makeTxRoute(router, api, "/:address") -} - -// @Summary Get Transactions -// @ID tx_v2 -// @Description Get transactions from the address -// @Accept json -// @Produce json -// @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 -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/{coin}/transactions/{address} [get] -func makeTxRouteV2(router gin.IRouter, api blockatlas.Platform) { - makeTxRoute(router, api, "/transactions/:address") -} - -func makeTxRoute(router gin.IRouter, api blockatlas.Platform, path string) { - var txAPI blockatlas.TxAPI - var tokenTxAPI blockatlas.TokenTxAPI - txAPI, _ = api.(blockatlas.TxAPI) - tokenTxAPI, _ = api.(blockatlas.TokenTxAPI) - - if txAPI == nil && tokenTxAPI == nil { - return - } - - router.GET(path, func(c *gin.Context) { - address := c.Param("address") - if address == "" { - emptyPage(c) - return - } - token := c.Query("token") - - var txs []blockatlas.Tx - var err error - switch { - case token == "" && txAPI != nil: - txs, err = txAPI.GetTxsByAddress(address) - case token != "" && tokenTxAPI != nil: - txs, err = tokenTxAPI.GetTokenTxsByAddress(address, token) - default: - emptyPage(c) - return - } - - if err != nil { - errResp := ginutils.ErrorResponse(c) - switch { - case err == blockatlas.ErrInvalidAddr: - errResp.Params(http.StatusBadRequest, "Invalid address") - case err == blockatlas.ErrNotFound: - errResp.Params(http.StatusNotFound, "No such address") - case err == blockatlas.ErrSourceConn: - errResp.Params(http.StatusServiceUnavailable, "Lost connection to blockchain") - } - errResp.Render() - return - } - - page := make(blockatlas.TxPage, 0) - for _, tx := range txs { - if tx.Direction != "" { - goto AddTx - } - tx.Direction = blockatlas.DirectionOutgoing - if tx.To == address { - tx.Direction = blockatlas.DirectionIncoming - if tx.From == address { - tx.Direction = blockatlas.DirectionSelf - } - } - AddTx: - page = append(page, tx) - } - if len(page) > blockatlas.TxPerPage { - page = page[0:blockatlas.TxPerPage] - } - sort.Sort(page) - ginutils.RenderSuccess(c, &page) - }) -} - // @Summary Get Collections // @ID collections_v2 // @Description Get all collections from the address @@ -232,49 +132,85 @@ func makeCollectionRoute(router gin.IRouter, api blockatlas.Platform) { }) } -// @Summary Get Tokens -// @ID tokens -// @Description Get tokens from the address +// @Description Get collection categories +// @ID collection_categories_v2 +// @Summary Get list of collections from a specific coin and addresses // @Accept json // @Produce json -// @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 -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/{coin}/tokens/{address} [get] -func makeTokenRoute(router gin.IRouter, api blockatlas.Platform) { - var tokenAPI blockatlas.TokenAPI - tokenAPI, _ = api.(blockatlas.TokenAPI) - - if tokenAPI == nil { - return - } - - router.GET("/tokens/:address", func(c *gin.Context) { - address := c.Param("address") - if address == "" { - emptyPage(c) +// @Tags Collections +// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) +// @Success 200 {object} blockatlas.DocsResponse +// @Router /v2/collectibles/categories [post] +//TODO: remove once most of the clients will be updated (deadline: March 17th) +func oldMakeCategoriesBatchRoute(router gin.IRouter) { + router.POST("/collectibles/categories", func(c *gin.Context) { + var reqs map[string][]string + if err := c.BindJSON(&reqs); err != nil { + ginutils.ErrorResponse(c).Message(err.Error()).Render() return } - tl, err := tokenAPI.GetTokenListByAddress(address) - if err != nil { + batch := make(blockatlas.CollectionPage, 0) + for key, addresses := range reqs { + coinId, err := strconv.Atoi(key) + if err != nil { + continue + } + p, ok := platform.CollectionAPIs[uint(coinId)] + if !ok { + continue + } + for _, address := range addresses { + collections, err := p.OldGetCollections(address) + if err != nil { + continue + } + batch = append(batch, collections...) + } + } + ginutils.RenderSuccess(c, batch) + }) +} + +// @Description Get collection categories +// @ID collection_categories_v3 +// @Summary Get list of collections from a specific coin and addresses +// @Accept json +// @Produce json +// @Tags Collections +// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) +// @Success 200 {object} blockatlas.DocsResponse +// @Router /v3/collectibles/categories [post] +func makeCategoriesBatchRoute(router gin.IRouter) { + router.POST("/collectibles/categories", func(c *gin.Context) { + var reqs map[string][]string + if err := c.BindJSON(&reqs); err != nil { ginutils.ErrorResponse(c).Message(err.Error()).Render() return } - ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: tl}) + batch := make(blockatlas.CollectionPage, 0) + for key, addresses := range reqs { + coinId, err := strconv.Atoi(key) + if err != nil { + continue + } + p, ok := platform.CollectionAPIs[uint(coinId)] + if !ok { + continue + } + for _, address := range addresses { + collections, err := p.GetCollections(address) + if err != nil { + continue + } + batch = append(batch, collections...) + } + } + ginutils.RenderSuccess(c, batch) }) } -func MakeMetricsRoute(router gin.IRouter) { - router.Use(metrics.PromMiddleware()) - m := router.Group("/metrics") - m.Use(ginutils.TokenAuthMiddleware(viper.GetString("metrics.api_token"))) - m.GET("/", ginprom.PromHandler(promhttp.Handler())) -} - func emptyPage(c *gin.Context) { var page blockatlas.TxPage ginutils.RenderSuccess(c, &page) diff --git a/api/naming_service.go b/api/domain.go similarity index 100% rename from api/naming_service.go rename to api/domain.go diff --git a/api/meta.go b/api/meta.go deleted file mode 100644 index 2d9a67843..000000000 --- a/api/meta.go +++ /dev/null @@ -1,30 +0,0 @@ -package api - -import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/pkg/ginutils" -) - -func GetRoot(c *gin.Context) { - ginutils.RenderSuccess(c, - `Welcome to the Block Atlas API! - -Don't know how you landed here? -Visit https://trustwallet.com to get back to the main page. - -If you know what you're doing: - - Visit /v1/ to list platforms - - Source: https://github.com/trustwallet/blockatlas - - Any questions? https://t.me/walletcore -`) -} - -func getEnabledEndpoints(c *gin.Context) { - var resp struct { - Endpoints []string `json:"endpoints,omitempty"` - } - for handle := range routers { - resp.Endpoints = append(resp.Endpoints, handle) - } - ginutils.RenderSuccess(c, &resp) -} diff --git a/api/observer.go b/api/observer.go index fc230b694..160832f8a 100644 --- a/api/observer.go +++ b/api/observer.go @@ -2,20 +2,12 @@ package api import ( "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/storage" ) -func SetupObserverAPI(router gin.IRouter, db *storage.Storage) { - router.Use(ginutils.TokenAuthMiddleware(viper.GetString("metrics.api_token"))) - router.POST("/webhook/register", addCall(db)) - router.DELETE("/webhook/register", deleteCall(db)) - router.GET("/status", statusCall(db)) -} - // @Summary Create a webhook // @ID create_webhook // @Description Create a webhook for addresses transactions diff --git a/api/routes.go b/api/routes.go index 9105d6d97..b4e8a9a5b 100644 --- a/api/routes.go +++ b/api/routes.go @@ -3,17 +3,40 @@ package api import ( "fmt" "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/storage" ) var routers = make(map[string]gin.IRouter) -func LoadPlatforms(root gin.IRouter) { +func SetupObserverAPI(router gin.IRouter, db *storage.Storage) { + router.GET("/", GetRoot) + router.GET("/status", GetStatus) + + observerAPI := router.Group("/observer/v1") + observerAPI.Use(ginutils.TokenAuthMiddleware(viper.GetString("observer.auth"))) + observerAPI.POST("/webhook/register", addCall(db)) + observerAPI.DELETE("/webhook/register", deleteCall(db)) + observerAPI.GET("/status", statusCall(db)) + + logger.Info("Routes set up", logger.Params{"routes": len(routers)}) +} + +func SetupPlatformAPI(root gin.IRouter) { + + root.GET("/", GetRoot) + root.GET("/status", GetStatus) + v1 := root.Group("/v1") v2 := root.Group("/v2") v3 := root.Group("/v3") + v1.GET("/", GetSupportedEndpoints) + for _, txAPI := range platform.Platforms { router := getRouter(v1, txAPI.Coin().Handle) makeTxRouteV1(router, txAPI) @@ -34,15 +57,14 @@ func LoadPlatforms(root gin.IRouter) { } for _, collectionAPI := range platform.Platforms { - routerv2 := getRouter(v2, collectionAPI.Coin().Handle) - routerv3 := getRouter(v3, collectionAPI.Coin().Handle) + routerV2 := getRouter(v2, collectionAPI.Coin().Handle) + routerV3 := getRouter(v3, collectionAPI.Coin().Handle) - makeCollectionsRoute(routerv3, collectionAPI) - makeCollectionRoute(routerv3, collectionAPI) + makeCollectionsRoute(routerV3, collectionAPI) + makeCollectionRoute(routerV3, collectionAPI) - //TODO: remove once most of the clients will be updated (deadline: March 17th) - oldMakeCollectionRoute(routerv2, collectionAPI) - oldMakeCollectionsRoute(routerv2, collectionAPI) + oldMakeCollectionRoute(routerV2, collectionAPI) + oldMakeCollectionsRoute(routerV2, collectionAPI) } for _, customAPI := range platform.CustomAPIs { @@ -50,21 +72,17 @@ func LoadPlatforms(root gin.IRouter) { customAPI.RegisterRoutes(router) } - { - ns := root.Group("/ns") - batchNs := v2.Group("/ns") - MakeLookupRoute(ns) - MakeLookupBatchRoute(batchNs) - } + ns := root.Group("/ns") + batchNs := v2.Group("/ns") + MakeLookupRoute(ns) + MakeLookupBatchRoute(batchNs) - //TODO: remove once most of the clients will be updated (deadline: March 17th) oldMakeCategoriesBatchRoute(v2) makeCategoriesBatchRoute(v3) makeStakingDelegationsBatchRoute(v2) makeStakingDelegationsSimpleBatchRoute(v2) logger.Info("Routes set up", logger.Params{"routes": len(routers)}) - v1.GET("/", getEnabledEndpoints) } // getRouter lazy loads routers @@ -80,3 +98,23 @@ func getRouter(router *gin.RouterGroup, handle string) gin.IRouter { return group } } + +func GetSupportedEndpoints(c *gin.Context) { + var resp struct { + Endpoints []string `json:"endpoints,omitempty"` + } + for handle := range routers { + resp.Endpoints = append(resp.Endpoints, handle) + } + ginutils.RenderSuccess(c, &resp) +} + +func GetRoot(c *gin.Context) { ginutils.RenderSuccess(c, "Welcome to the Block Atlas API") } + +func GetStatus(c *gin.Context) { + ginutils.RenderSuccess(c, map[string]interface{}{ + "status": true, + "build": internal.Build, + "date": internal.Date, + }) +} diff --git a/api/stake.go b/api/staking.go similarity index 55% rename from api/stake.go rename to api/staking.go index f691669aa..881d26bc9 100644 --- a/api/stake.go +++ b/api/staking.go @@ -2,15 +2,107 @@ package api import ( "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/ginutils/gincache" "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/platform" services "github.com/trustwallet/blockatlas/services/assets" "time" ) +type ( + AddressBatchRequest struct { + Address string `json:"address"` + CoinBatchRequest + } + + CoinBatchRequest struct { + Coin uint `json:"coin"` + } + + ENSBatchRequest struct { + Coins []uint64 `json:"coins"` + Name string `json:"name"` + } + + AddressesRequest []AddressBatchRequest + CoinsRequest []CoinBatchRequest +) + +// @Summary Get Multiple Stake Delegations +// @ID batch_delegations +// @Description Get Stake Delegations for multiple coins +// @Accept json +// @Produce json +// @Tags Staking +// @Param delegations body api.AddressesRequest true "Validators addresses and coins" +// @Success 200 {object} blockatlas.DelegationsBatchPage +// @Router /v2/staking/delegations [post] +func makeStakingDelegationsBatchRoute(router gin.IRouter) { + router.POST("/staking/delegations", func(c *gin.Context) { + var reqs AddressesRequest + if err := c.BindJSON(&reqs); err != nil { + ginutils.ErrorResponse(c).Message(err.Error()).Render() + return + } + + batch := make(blockatlas.DelegationsBatchPage, 0) + for _, r := range reqs { + c, ok := coin.Coins[r.Coin] + if !ok { + continue + } + p, ok := platform.StakeAPIs[c.Handle] + if !ok { + continue + } + delegation, err := getDelegationResponse(p, r.Address) + if err != nil { + continue + } + batch = append(batch, delegation) + } + ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: batch}) + }) +} + +// @Summary Get Multiple Stake Delegations +// @ID batch_delegations +// @Description Get Stake Delegations for multiple coins +// @Accept json +// @Produce json +// @Tags Staking +// @Param delegations body api.AddressesRequest true "Validators addresses and coins" +// @Success 200 {object} blockatlas.DelegationsBatchPage +// @Router /v2/staking/list [post] +func makeStakingDelegationsSimpleBatchRoute(router gin.IRouter) { + router.POST("/staking/list", gincache.CacheMiddleware(time.Hour*24, func(c *gin.Context) { + var reqs CoinsRequest + if err := c.BindJSON(&reqs); err != nil { + ginutils.ErrorResponse(c).Message(err.Error()).Render() + return + } + + batch := make(blockatlas.StakingBatchPage, 0) + for _, r := range reqs { + c, ok := coin.Coins[r.Coin] + if !ok { + continue + } + p, ok := platform.StakeAPIs[c.Handle] + if !ok { + continue + } + staking := getStakingResponse(p) + batch = append(batch, staking) + } + ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: batch}) + })) +} + // @Summary Get Validators // @ID validators // @Description Get validators from the address diff --git a/api/transaction.go b/api/transaction.go new file mode 100644 index 000000000..002943df0 --- /dev/null +++ b/api/transaction.go @@ -0,0 +1,141 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/ginutils" + "net/http" + "sort" +) + +// @Summary Get Transactions +// @ID tx_v1 +// @Description Get transactions from the address +// @Accept json +// @Produce json +// @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 +// @Router /v1/{coin}/{address} [get] +func makeTxRouteV1(router gin.IRouter, api blockatlas.Platform) { + makeTxRoute(router, api, "/:address") +} + +// @Summary Get Transactions +// @ID tx_v2 +// @Description Get transactions from the address +// @Accept json +// @Produce json +// @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 +// @Failure 500 {object} ginutils.ApiError +// @Router /v2/{coin}/transactions/{address} [get] +func makeTxRouteV2(router gin.IRouter, api blockatlas.Platform) { + makeTxRoute(router, api, "/transactions/:address") +} + +func makeTxRoute(router gin.IRouter, api blockatlas.Platform, path string) { + var txAPI blockatlas.TxAPI + var tokenTxAPI blockatlas.TokenTxAPI + txAPI, _ = api.(blockatlas.TxAPI) + tokenTxAPI, _ = api.(blockatlas.TokenTxAPI) + + if txAPI == nil && tokenTxAPI == nil { + return + } + + router.GET(path, func(c *gin.Context) { + address := c.Param("address") + if address == "" { + emptyPage(c) + return + } + token := c.Query("token") + + var txs []blockatlas.Tx + var err error + switch { + case token == "" && txAPI != nil: + txs, err = txAPI.GetTxsByAddress(address) + case token != "" && tokenTxAPI != nil: + txs, err = tokenTxAPI.GetTokenTxsByAddress(address, token) + default: + emptyPage(c) + return + } + + if err != nil { + errResp := ginutils.ErrorResponse(c) + switch { + case err == blockatlas.ErrInvalidAddr: + errResp.Params(http.StatusBadRequest, "Invalid address") + case err == blockatlas.ErrNotFound: + errResp.Params(http.StatusNotFound, "No such address") + case err == blockatlas.ErrSourceConn: + errResp.Params(http.StatusServiceUnavailable, "Lost connection to blockchain") + } + errResp.Render() + return + } + + page := make(blockatlas.TxPage, 0) + for _, tx := range txs { + if tx.Direction != "" { + goto AddTx + } + tx.Direction = blockatlas.DirectionOutgoing + if tx.To == address { + tx.Direction = blockatlas.DirectionIncoming + if tx.From == address { + tx.Direction = blockatlas.DirectionSelf + } + } + AddTx: + page = append(page, tx) + } + if len(page) > blockatlas.TxPerPage { + page = page[0:blockatlas.TxPerPage] + } + sort.Sort(page) + ginutils.RenderSuccess(c, &page) + }) +} + +// @Summary Get Tokens +// @ID tokens +// @Description Get tokens from the address +// @Accept json +// @Produce json +// @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 +// @Failure 500 {object} ginutils.ApiError +// @Router /v2/{coin}/tokens/{address} [get] +func makeTokenRoute(router gin.IRouter, api blockatlas.Platform) { + var tokenAPI blockatlas.TokenAPI + tokenAPI, _ = api.(blockatlas.TokenAPI) + + if tokenAPI == nil { + return + } + + router.GET("/tokens/:address", func(c *gin.Context) { + address := c.Param("address") + if address == "" { + emptyPage(c) + return + } + + tl, err := tokenAPI.GetTokenListByAddress(address) + if err != nil { + ginutils.ErrorResponse(c).Message(err.Error()).Render() + return + } + + ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: tl}) + }) +} diff --git a/build/build.go b/build/build.go deleted file mode 100644 index 49f78ec67..000000000 --- a/build/build.go +++ /dev/null @@ -1,26 +0,0 @@ -package build - -import ( - "fmt" - "runtime" -) - -var ( - Version = "dev" - Build = "dev" - Date = "" -) - -func LogVersionInfo() { - fmt.Printf(` -************************************************ -Version: %v -Build: %v -Date: %v -OS: %s -Arch: %s -Go: %s -************************************************ -`, - Version, Build, Date, runtime.GOOS, runtime.GOARCH, runtime.Version()) -} diff --git a/cmd/observer_api/main.go b/cmd/observer_api/main.go index 0eabaa994..ce72ea515 100644 --- a/cmd/observer_api/main.go +++ b/cmd/observer_api/main.go @@ -4,11 +4,9 @@ import ( "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" - "github.com/trustwallet/blockatlas/build" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" ) @@ -24,7 +22,6 @@ var ( ) func init() { - build.LogVersionInfo() port, confPath, sg, cache = internal.InitAPIWithRedis(defaultPort, defaultConfigPath) } @@ -35,22 +32,8 @@ func main() { engine.Use(ginutils.CheckReverseProxy, *sg) engine.Use(ginutils.CORSMiddleware()) engine.Use(gin.Logger()) - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) - engine.GET("/", api.GetRoot) - engine.GET("/status", func(c *gin.Context) { - ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, - "version": build.Version, - "build": build.Build, - "date": build.Date, - }) - }) - - logger.Info("Loading observer API") - - observerAPI := engine.Group("/observer/v1") - api.SetupObserverAPI(observerAPI, cache) + api.SetupObserverAPI(engine, cache) internal.SetupGracefulShutdown(port, engine) } diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index fa58fc84f..507220453 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -4,7 +4,6 @@ import ( "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" - "github.com/trustwallet/blockatlas/build" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -17,35 +16,24 @@ const ( ) var ( - port, confPath, chosenPlatform string - sg *gin.HandlerFunc + port, confPath string + sg *gin.HandlerFunc ) func init() { - build.LogVersionInfo() port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) platform.Init(viper.GetString("platform")) } func main() { gin.SetMode(viper.GetString("gin.mode")) + engine := gin.New() engine.Use(ginutils.CheckReverseProxy, *sg) engine.Use(ginutils.CORSMiddleware()) engine.Use(gin.Logger()) - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) - engine.GET("/", api.GetRoot) - engine.GET("/status", func(c *gin.Context) { - ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, - "version": build.Version, - "build": build.Build, - "date": build.Date, - }) - }) - - api.LoadPlatforms(engine) + api.SetupPlatformAPI(engine) internal.SetupGracefulShutdown(port, engine) } diff --git a/cmd/platform_observer/main.go b/cmd/platform_observer/main.go index a1e0a30ff..a04fdb2ab 100644 --- a/cmd/platform_observer/main.go +++ b/cmd/platform_observer/main.go @@ -3,7 +3,6 @@ package main import ( "context" "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/build" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/observer" "github.com/trustwallet/blockatlas/pkg/logger" @@ -22,7 +21,6 @@ var ( ) func init() { - build.LogVersionInfo() _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) platform.Init(viper.GetString("platform")) } diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go index 02c4f431d..660821c51 100644 --- a/cmd/swagger_api/main.go +++ b/cmd/swagger_api/main.go @@ -6,7 +6,6 @@ import ( ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" "github.com/trustwallet/blockatlas/api" - "github.com/trustwallet/blockatlas/build" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" @@ -15,7 +14,6 @@ import ( const ( defaultPort = "8423" defaultConfigPath = "../../config.yml" - allPlatforms = "all" ) var ( @@ -24,28 +22,19 @@ var ( ) func init() { - build.LogVersionInfo() port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) } func main() { gin.SetMode(viper.GetString("gin.mode")) - engine := gin.New() + engine.Use(ginutils.CheckReverseProxy, *sg) engine.Use(ginutils.CORSMiddleware()) engine.OPTIONS("/*path", ginutils.CORSMiddleware()) engine.GET("/", api.GetRoot) - engine.GET("/status", func(c *gin.Context) { - ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, - "version": build.Version, - "build": build.Build, - "date": build.Date, - }) - }) - + engine.GET("/status", api.GetStatus) engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) internal.SetupGracefulShutdown(port, engine) diff --git a/coin/gen_test.go b/coin/gen_test.go index 067bee058..45e8f47da 100644 --- a/coin/gen_test.go +++ b/coin/gen_test.go @@ -34,6 +34,9 @@ func TestFilesExists(t *testing.T) { func TestCoinFile(t *testing.T) { var coinList []TestCoin coin, err := os.Open(coinFile) + if err != nil { + t.Error(err) + } dec := yaml.NewDecoder(coin) err = dec.Decode(&coinList) if err != nil { diff --git a/config.yml b/config.yml index 7d232e425..8f7117282 100644 --- a/config.yml +++ b/config.yml @@ -6,9 +6,10 @@ gin: # If set, HTTP Forwarded headers will be respected reverse_proxy: false +# If all - run all platforms in one binary. You can pick specific coin handle to run binary only with specific coin +# Example: ethereum +# You can see all the coin handles at coins/coins.yml file platform: all -#metrics: -# api_token: xxxxxx # Sentry error tracking #sentry: @@ -16,8 +17,6 @@ platform: all # The transaction watcher observer: - enabled: false - # TODO : Add description auth: test # Don't request blocks older than this backlog: 3h diff --git a/go.sum b/go.sum index f5dc2222d..d9943f83b 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,7 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/Pantani/httpexpect v2.0.0+incompatible h1:P658jo0d3gej0D67KBcSUgpZY76CH1TdxvOfQAmyNu0= github.com/Pantani/httpexpect v2.0.0+incompatible/go.mod h1:+8VdK+EZPV0YorWMMNyakEIYKcDl9OHtde3DdkPqbwQ= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= @@ -33,6 +34,7 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrU github.com/VictoriaMetrics/fastcache v1.5.3 h1:2odJnXLbFZcoV9KYtQ+7TH1UOq3dn3AssMgieaezkR4= github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= @@ -122,6 +124,7 @@ github.com/ethereum/go-ethereum v1.9.10 h1:jooX7tWcscpC7ytufk73t9JMCeJQ7aJF2YmZJ github.com/ethereum/go-ethereum v1.9.10/go.mod h1:lXHkVo/MTvsEXfYsmNzelZ8R1e0DTvdk/wMZJIRpaRw= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= @@ -200,6 +203,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= @@ -229,6 +233,7 @@ github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOo github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= @@ -272,6 +277,7 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -329,6 +335,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= @@ -404,6 +411,7 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 h1:Pm6R878vxWWWR+Sa3ppsLce/Zq+JNTs6aVvRu13jv9A= github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -474,7 +482,9 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= @@ -490,12 +500,17 @@ github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8 github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/internal/init.go b/internal/init.go index 319cc6e35..6ac30c03d 100644 --- a/internal/init.go +++ b/internal/init.go @@ -2,6 +2,7 @@ package internal import ( "flag" + "fmt" sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" "github.com/spf13/viper" @@ -9,6 +10,13 @@ import ( "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" "path/filepath" + "runtime" + "time" +) + +var ( + Build = "dev" + Date = time.Now().String() ) func InitAPI(defaultPort, defaultConfigPath string) (string, string, *gin.HandlerFunc) { @@ -17,6 +25,7 @@ func InitAPI(defaultPort, defaultConfigPath string) (string, string, *gin.Handle sg gin.HandlerFunc ) + LogVersionInfo() sg = sentrygin.New(sentrygin.Options{}) flag.StringVar(&port, "p", defaultPort, "port for api") @@ -40,7 +49,7 @@ func InitAPIWithRedis(defaultPort, defaultConfigPath string) (string, string, *g cache *storage.Storage sg gin.HandlerFunc ) - + LogVersionInfo() cache = storage.New() sg = sentrygin.New(sentrygin.Options{}) @@ -63,3 +72,16 @@ func InitAPIWithRedis(defaultPort, defaultConfigPath string) (string, string, *g return port, confPath, &sg, cache } + +func LogVersionInfo() { + fmt.Printf(` +------------------------------------------------------------------------------- +Build: %v +Start date: %v +OS: %s +Go Arch: %s +Go Version: %s +------------------------------------------------------------------------------- +`, + Build, Date, runtime.GOOS, runtime.GOARCH, runtime.Version()) +} diff --git a/observer/dispatcher.go b/observer/dispatcher.go index 7cb7b5ce2..45b07d0d9 100644 --- a/observer/dispatcher.go +++ b/observer/dispatcher.go @@ -47,8 +47,8 @@ func (d *Dispatcher) dispatch(event Event) { func (d *Dispatcher) postWebhook(hook string, data []byte, logParams logger.Params) { _, err := d.Client.Post(hook, "application/json", bytes.NewReader(data)) if err != nil { - err = errors.E(err, errors.Params{"hook": hook}).PushToSentry() - logger.Error(err, "Failed to dispatch event", logger.Params{"webhook": hook}, logParams) + err = errors.E(err, "Failed to dispatch event", errors.Params{"webhook": hook}, logParams) + logger.Error(err, logger.Params{"webhook": hook}, logParams) } logger.Info("Webhook dispatched", logger.Params{"webhook": hook}, logParams) } diff --git a/pkg/address/address.go b/pkg/address/address.go index a720f8c38..3f4ccc7fe 100644 --- a/pkg/address/address.go +++ b/pkg/address/address.go @@ -48,7 +48,7 @@ func HexToAddress(hexAddr string) (b58 string, err error) { bytes, err := hex.DecodeString(hexAddr) if err != nil { return "", errors.E(err, errors.TypePlatformUnmarshal, - errors.Params{"hexAddr": hexAddr}).PushToSentry() + errors.Params{"hexAddr": hexAddr}) } var checksum [32]byte checksum = sha256.Sum256(bytes) diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go index 19dfaab82..c10c2dc68 100644 --- a/pkg/blockatlas/client.go +++ b/pkg/blockatlas/client.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/metrics" "io" "io/ioutil" "net/http" @@ -62,7 +61,6 @@ func (r *Request) Post(result interface{}, path string, body interface{}) error func (r *Request) Execute(method string, url string, body io.Reader, result interface{}, params errors.Params) error { params["method"] = method - start := time.Now() req, err := http.NewRequest(method, url, body) if err != nil { return errors.E(err, errors.TypePlatformRequest, params) @@ -76,7 +74,6 @@ func (r *Request) Execute(method string, url string, body io.Reader, result inte if err != nil { return errors.E(err, errors.TypePlatformRequest, params) } - go metrics.GetMetrics(res.Status, url, method, start) err = r.ErrorHandler(res, url) if err != nil { diff --git a/pkg/blockatlas/clientcache.go b/pkg/blockatlas/clientcache.go index 847398958..12ace94d8 100644 --- a/pkg/blockatlas/clientcache.go +++ b/pkg/blockatlas/clientcache.go @@ -68,7 +68,7 @@ func (mc *memCache) setCache(key string, value interface{}, duration time.Durati defer mc.RUnlock() b, err := json.Marshal(value) if err != nil { - logger.Error(errors.E(err, "client cache cannot marshal cache object").PushToSentry()) + logger.Error(errors.E(err, "client cache cannot marshal cache object")) return } memoryCache.cache.Set(key, b, duration) @@ -85,7 +85,7 @@ func (mc *memCache) getCache(key string, value interface{}) error { } err := json.Unmarshal(r, value) if err != nil { - return errors.E(err, util.ErrNotFound).PushToSentry() + return errors.E(err, util.ErrNotFound) } return nil } diff --git a/pkg/blockatlas/jsonrpc.go b/pkg/blockatlas/jsonrpc.go index e250fbd28..b9a187dd3 100644 --- a/pkg/blockatlas/jsonrpc.go +++ b/pkg/blockatlas/jsonrpc.go @@ -33,12 +33,12 @@ type RpcError struct { func (r *RpcResponse) GetObject(toType interface{}) error { js, err := json.Marshal(r.Result) if err != nil { - return errors.E(err, "json-rpc GetObject Marshal error", errors.Params{"obj": toType}).PushToSentry() + return errors.E(err, "json-rpc GetObject Marshal error", errors.Params{"obj": toType}) } err = json.Unmarshal(js, toType) if err != nil { - return errors.E(err, "json-rpc GetObject Unmarshal error", errors.Params{"obj": toType, "string": string(js)}).PushToSentry() + return errors.E(err, "json-rpc GetObject Unmarshal error", errors.Params{"obj": toType, "string": string(js)}) } return nil } diff --git a/pkg/blockatlas/marshal.go b/pkg/blockatlas/marshal.go index f2b118301..00f6dd8de 100644 --- a/pkg/blockatlas/marshal.go +++ b/pkg/blockatlas/marshal.go @@ -45,7 +45,7 @@ func (t *Tx) UnmarshalJSON(data []byte) error { case TxAnyAction: t.Meta = new(AnyAction) default: - return errors.E("unsupported tx type", errors.Params{"type": t.Type}).PushToSentry() + return errors.E("unsupported tx type", errors.Params{"type": t.Type}) } if err := json.Unmarshal(raw, t.Meta); err != nil { return err @@ -75,7 +75,7 @@ func (t *Tx) MarshalJSON() ([]byte, error) { case AnyAction, *AnyAction: t.Type = TxAnyAction default: - return nil, errors.E("unsupported tx metadata", errors.Params{"meta": t.Meta}).PushToSentry() + return nil, errors.E("unsupported tx metadata", errors.Params{"meta": t.Meta}) } // Set status to completed by default @@ -97,7 +97,7 @@ func (a *Amount) UnmarshalJSON(data []byte) error { } str := string(n) if !matchNumber.MatchString(str) { - return errors.E("not a regular decimal number", errors.Params{"str": str}).PushToSentry() + return errors.E("not a regular decimal number", errors.Params{"str": str}) } if strings.ContainsRune(str, '.') { str, _ = numbers.DecimalToSatoshis(str) diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index 5a9019cba..d2746cb12 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -8,20 +8,20 @@ import ( "strings" ) -type Params map[string]interface{} +type ( + Params map[string]interface{} -// Error represents a error's specification. -type Error struct { - Err error - Type Type - meta map[string]interface{} - stack []string -} - -var ( - _ error = (*Error)(nil) + // Error represents a error's specification. + Error struct { + Err error + Type Type + meta map[string]interface{} + stack []string + } ) +var _ error = (*Error)(nil) + func (e *Error) isEmpty() bool { return e.meta == nil && e.Type == TypeNone && e.Err == nil } diff --git a/pkg/ginutils/gincache/cache.go b/pkg/ginutils/gincache/cache.go index bbe26706a..1de5fca2f 100644 --- a/pkg/ginutils/gincache/cache.go +++ b/pkg/ginutils/gincache/cache.go @@ -115,7 +115,7 @@ func (mc *memCache) deleteCache(key string) { func (mc *memCache) setCache(k string, x interface{}, d time.Duration) { b, err := json.Marshal(x) if err != nil { - logger.Error(errors.E(err, "client cache cannot marshal cache object").PushToSentry()) + logger.Error(errors.E(err, "client cache cannot marshal cache object")) return } mc.RLock() @@ -135,7 +135,7 @@ func (mc *memCache) getCache(key string) (cacheResponse, error) { } err := json.Unmarshal(r, &result) if err != nil { - return result, errors.E(err, util.ErrNotFound).PushToSentry() + return result, errors.E(err, util.ErrNotFound) } return result, nil } diff --git a/pkg/metrics/client.go b/pkg/metrics/client.go deleted file mode 100644 index e7c5a55fc..000000000 --- a/pkg/metrics/client.go +++ /dev/null @@ -1,35 +0,0 @@ -package metrics - -import ( - "github.com/prometheus/client_golang/prometheus" - "time" -) - -const ( - clientNamespace = "client" -) - -var ( - clientLabels = []string{"status", "endpoint", "method"} - clientReqCount = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Namespace: clientNamespace, - Name: "http_request_count_total", - Help: "Total number of HTTP requests made.", - }, clientLabels, - ) - clientReqDuration = prometheus.NewHistogramVec( - prometheus.HistogramOpts{ - Namespace: clientNamespace, - Name: "http_request_duration_seconds", - Help: "HTTP request latencies in seconds.", - }, clientLabels, - ) -) - -func GetMetrics(status, url, method string, start time.Time) { - endpoint := removeSensitiveInfo(url) - lvs := []string{status, endpoint, method} - clientReqCount.WithLabelValues(lvs...).Inc() - clientReqDuration.WithLabelValues(lvs...).Observe(time.Since(start).Seconds()) -} diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go deleted file mode 100644 index 4c7c2a534..000000000 --- a/pkg/metrics/metrics.go +++ /dev/null @@ -1,16 +0,0 @@ -package metrics - -import ( - "github.com/prometheus/client_golang/prometheus" - "regexp" -) - -// init registers the prometheus metrics -func init() { - prometheus.MustRegister(clientReqCount, clientReqDuration, serverReqCount, serverReqDuration, serverReqSizeBytes, serverRespSizeBytes) -} - -func removeSensitiveInfo(info string) string { - reg := regexp.MustCompile(`([a-zA-Z0-9\s]{30,})|([0-9]{4,})|(=(.*?)[^(&|$)]+)|(--[^$]+)|(&asset_contract_addresses)`) - return reg.ReplaceAllString(info, "") -} diff --git a/pkg/metrics/metrics_test.go b/pkg/metrics/metrics_test.go deleted file mode 100644 index debf02503..000000000 --- a/pkg/metrics/metrics_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package metrics - -import "testing" - -func Test_removeSensitiveInfo(t *testing.T) { - tests := []struct { - name string - info string - want string - }{ - {"Remove Nimiq address", "/v1/nimiq/NQ43 J7G6 K6T8 H5KJ 5CXN Q5JK 2GJ4 6DSB 7PUH", "/v1/nimiq/"}, - {"Remove Tezos address", "/v1/tezos/tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", "/v1/tezos/"}, - {"Remove Tron info", "https://api.trongrid.io/v1/accounts/TPJYCz8ppZNyvw7pTwmjajcx4Kk1MmEUhD/transactions?limit=200&only_confirmed=true&token_id=1000011", "https://api.trongrid.io/v1/accounts//transactions?limit&only_confirmed&token_id"}, - {"Remove asset id", "https://api.trongrid.io/v1/assets/1000570?", "https://api.trongrid.io/v1/assets/?"}, - {"Remove collection id", "/v2/ethereum/collections//collection/---enjin-old", "/v2/ethereum/collections//collection/"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := removeSensitiveInfo(tt.info); got != tt.want { - t.Errorf("removeSensitiveInfo() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/metrics/server.go b/pkg/metrics/server.go deleted file mode 100644 index f95777e2c..000000000 --- a/pkg/metrics/server.go +++ /dev/null @@ -1,89 +0,0 @@ -package metrics - -import ( - "fmt" - "github.com/gin-gonic/gin" - "github.com/prometheus/client_golang/prometheus" - "net/http" - "time" -) - -const ( - serverNamespace = "server" -) - -var ( - serverLabels = []string{"status", "endpoint", "method"} - serverReqCount = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Namespace: serverNamespace, - Name: "http_request_count_total", - Help: "Total number of HTTP requests made.", - }, serverLabels, - ) - serverReqDuration = prometheus.NewHistogramVec( - prometheus.HistogramOpts{ - Namespace: serverNamespace, - Name: "http_request_duration_seconds", - Help: "HTTP request latencies in seconds.", - }, serverLabels, - ) - - serverReqSizeBytes = prometheus.NewSummaryVec( - prometheus.SummaryOpts{ - Namespace: serverNamespace, - Name: "http_request_size_bytes", - Help: "HTTP request sizes in bytes.", - }, serverLabels, - ) - serverRespSizeBytes = prometheus.NewSummaryVec( - prometheus.SummaryOpts{ - Namespace: serverNamespace, - Name: "http_response_size_bytes", - Help: "HTTP request sizes in bytes.", - }, serverLabels, - ) -) - -func PromMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - start := time.Now() - c.Next() - - status := fmt.Sprintf("%d", c.Writer.Status()) - url := c.Request.URL.Path - method := c.Request.Method - - endpoint := removeSensitiveInfo(url) - lvs := []string{status, endpoint, method} - - serverReqCount.WithLabelValues(lvs...).Inc() - serverReqDuration.WithLabelValues(lvs...).Observe(time.Since(start).Seconds()) - serverReqSizeBytes.WithLabelValues(lvs...).Observe(calcRequestSize(c.Request)) - serverRespSizeBytes.WithLabelValues(lvs...).Observe(float64(c.Writer.Size())) - } -} - -func calcRequestSize(r *http.Request) float64 { - size := 0 - if r.URL != nil { - size = len(r.URL.String()) - } - - size += len(r.Method) - size += len(r.Proto) - - for name, values := range r.Header { - size += len(name) - for _, value := range values { - size += len(value) - } - } - size += len(r.Host) - - // r.Form and r.MultipartForm are assumed to be included in r.URL. - if r.ContentLength != -1 { - size += int(r.ContentLength) - } - return float64(size) -} diff --git a/pkg/numbers/decimal.go b/pkg/numbers/decimal.go index 51ce48a94..667470aac 100644 --- a/pkg/numbers/decimal.go +++ b/pkg/numbers/decimal.go @@ -15,7 +15,7 @@ func DecimalToSatoshis(dec string) (string, error) { out = strings.TrimLeft(out, "0") for _, c := range out { if !unicode.IsNumber(c) { - return "", errors.E("not a number", errors.Params{"dec": dec, "c": c}).PushToSentry() + return "", errors.E("not a number", errors.Params{"dec": dec, "c": c}) } } return out, nil @@ -64,7 +64,7 @@ func DecimalExp(dec string, exp int) string { func HexToDecimal(hex string) (string, error) { var i big.Int if _, ok := i.SetString(hex, 0); !ok { - return "", errors.E("invalid hex", errors.Params{"hex": hex}).PushToSentry() + return "", errors.E("invalid hex", errors.Params{"hex": hex}) } return i.String(), nil } diff --git a/platform/binance/block.go b/platform/binance/block.go index 9115c6cdf..1a93421fd 100644 --- a/platform/binance/block.go +++ b/platform/binance/block.go @@ -14,7 +14,7 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { return 0, err } if len(list.BlockArray) == 0 { - return 0, errors.E("no block descriptor found", errors.TypePlatformApi).PushToSentry() + return 0, errors.E("no block descriptor found", errors.TypePlatformApi) } return list.BlockArray[0].BlockHeight, nil } diff --git a/platform/binance/client.go b/platform/binance/client.go index 5a2cb2500..cd1b2f1f0 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -57,7 +57,7 @@ func getHTTPError(res *http.Response, desc string) error { case http.StatusOK: return nil default: - return errors.E("getHTTPError error", errors.Params{"status": res.Status}).PushToSentry() + return errors.E("getHTTPError error", errors.Params{"status": res.Status}) } } @@ -65,7 +65,7 @@ func getAPIError(res *http.Response, desc string) error { var sErr Error err := json.NewDecoder(res.Body).Decode(&sErr) if err != nil { - err = errors.E(err, errors.TypePlatformUnmarshal, errors.Params{"desc": desc}).PushToSentry() + err = errors.E(err, errors.TypePlatformUnmarshal, errors.Params{"desc": desc}) logger.Error(err, "Binance: Failed to decode error response") return blockatlas.ErrSourceConn } diff --git a/platform/cosmos/client.go b/platform/cosmos/client.go index ea59ad1d2..eee6f4b8f 100644 --- a/platform/cosmos/client.go +++ b/platform/cosmos/client.go @@ -51,7 +51,7 @@ func (c *Client) CurrentBlockNumber() (num int64, err error) { num, err = strconv.ParseInt(block.Meta.Header.Height, 10, 64) if err != nil { - return num, errors.E("error to ParseInt", errors.TypePlatformUnmarshal).PushToSentry() + return num, errors.E("error to ParseInt", errors.TypePlatformUnmarshal) } return diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index fe919f000..94795bde6 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -32,7 +32,7 @@ func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { } inflationValue, err := strconv.ParseFloat(inflation.Result, 32) if err != nil { - return nil, errors.E("error to parse inflationValue to float", errors.TypePlatformUnmarshal).PushToSentry() + return nil, errors.E("error to parse inflationValue to float", errors.TypePlatformUnmarshal) } for _, validator := range validators.Result { diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index d83040657..4d78bcd8d 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -12,15 +12,19 @@ type Platform struct { collectionsClient CollectionsClient } -func Init(coin uint, api, rpc, collectionApi, collectionKey string) *Platform { - p := Platform{ - CoinIndex: coin, - RpcURL: rpc, - client: Client{blockatlas.InitClient(api)}, - collectionsClient: CollectionsClient{blockatlas.InitClient(collectionApi)}, +func Init(coin uint, api, rpc string) *Platform { + return &Platform{ + CoinIndex: coin, + RpcURL: rpc, + client: Client{blockatlas.InitClient(api)}, } +} + +func InitWitCollection(coin uint, api, rpc, collectionApi, collectionKey string) *Platform { + p := Init(coin, api, rpc) + p.collectionsClient = CollectionsClient{blockatlas.InitClient(collectionApi)} p.collectionsClient.Headers["X-API-KEY"] = collectionKey - return &p + return p } func (p *Platform) Coin() coin.Coin { diff --git a/platform/ethereum/collection_client.go b/platform/ethereum/collection_client.go index 39cadf664..c41ae633d 100644 --- a/platform/ethereum/collection_client.go +++ b/platform/ethereum/collection_client.go @@ -28,7 +28,7 @@ func (c CollectionsClient) GetCollectibles(owner string, collectibleID string) ( collection := searchCollection(collections, collectibleID) if collection == nil { return nil, nil, errors.E("collectible not found", errors.TypePlatformClient, - errors.Params{"collectibleID": collectibleID}).PushToSentry() + errors.Params{"collectibleID": collectibleID}) } query := url.Values{ @@ -53,7 +53,7 @@ func (c CollectionsClient) OldGetCollectibles(owner string, collectibleID string collection := oldSearchCollection(collections, id) if collection == nil { return nil, nil, errors.E("collectible not found", errors.TypePlatformClient, - errors.Params{"collectibleID": collectibleID}).PushToSentry() + errors.Params{"collectibleID": collectibleID}) } query := url.Values{ diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index a83a6ddce..890b5b436 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -29,7 +29,7 @@ func NormalizeTxs(txs []Transaction) blockatlas.TxPage { } func GetNormalizationError(err error) error { - return errors.E(err, errors.TypePlatformNormalize, errors.Params{"method": "Harmony_NormalizeTx"}).PushToSentry() + return errors.E(err, errors.TypePlatformNormalize, errors.Params{"method": "Harmony_NormalizeTx"}) } func NormalizeTx(trx *Transaction) (tx blockatlas.Tx, b bool, err error) { diff --git a/platform/icon/transaction.go b/platform/icon/transaction.go index 0742e9408..350609284 100644 --- a/platform/icon/transaction.go +++ b/platform/icon/transaction.go @@ -31,7 +31,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { func Normalize(trx *Tx) (tx blockatlas.Tx, b bool) { date, err := time.Parse("2006-01-02T15:04:05.999Z0700", trx.CreateDate) if err != nil { - err = errors.E(err, errors.TypePlatformUnmarshal).PushToSentry() + err = errors.E(err, errors.TypePlatformUnmarshal) logger.Error(err) return tx, false } diff --git a/platform/iotex/client.go b/platform/iotex/client.go index c06b337df..5e86adb50 100644 --- a/platform/iotex/client.go +++ b/platform/iotex/client.go @@ -21,7 +21,7 @@ func (c *Client) GetLatestBlock() (int64, error) { } b, err := strconv.ParseInt(chainMeta.Height, 10, 64) if err != nil { - return 0, errors.E(err, "ParseInt failed", errors.TypePlatformUnmarshal).PushToSentry() + return 0, errors.E(err, "ParseInt failed", errors.TypePlatformUnmarshal) } return b, nil } diff --git a/platform/nano/transaction.go b/platform/nano/transaction.go index 2e9ff1bff..c509b8baf 100644 --- a/platform/nano/transaction.go +++ b/platform/nano/transaction.go @@ -24,14 +24,17 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { } for _, srcTx := range txs { - tx := p.Normalize(&srcTx, history.Account) + tx, err := p.Normalize(&srcTx, history.Account) + if err != nil { + continue + } normalized = append(normalized, tx) } return normalized, nil } -func (p *Platform) Normalize(srcTx *Transaction, account string) (tx blockatlas.Tx) { +func (p *Platform) Normalize(srcTx *Transaction, account string) (blockatlas.Tx, error) { var from string var to string @@ -44,13 +47,19 @@ func (p *Platform) Normalize(srcTx *Transaction, account string) (tx blockatlas. } status := blockatlas.StatusCompleted - height, _ := strconv.ParseUint(srcTx.Height, 10, 64) + height, err := strconv.ParseUint(srcTx.Height, 10, 64) + if err != nil { + return blockatlas.Tx{}, err + } if height == 0 { status = blockatlas.StatusPending } - timestamp, _ := strconv.ParseInt(srcTx.LocalTimestamp, 10, 64) + timestamp, err := strconv.ParseInt(srcTx.LocalTimestamp, 10, 64) + if err != nil { + return blockatlas.Tx{}, err + } - tx = blockatlas.Tx{ + tx := blockatlas.Tx{ ID: srcTx.Hash, Coin: p.Coin().ID, Date: timestamp, @@ -65,5 +74,5 @@ func (p *Platform) Normalize(srcTx *Transaction, account string) (tx blockatlas. Decimals: p.Coin().Decimals, }, } - return tx + return tx, nil } diff --git a/platform/nano/transaction_test.go b/platform/nano/transaction_test.go index db0e92b7e..84c4ce13f 100644 --- a/platform/nano/transaction_test.go +++ b/platform/nano/transaction_test.go @@ -79,7 +79,7 @@ func TestNormalize(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if gotTx := platform.Normalize(tt.args.srcTx, tt.args.account); !reflect.DeepEqual(gotTx, tt.wantTx) { + if gotTx, err := platform.Normalize(tt.args.srcTx, tt.args.account); !reflect.DeepEqual(gotTx, tt.wantTx) && err == nil { t.Errorf("Normalize() = %v, want %v", gotTx, tt.wantTx) } }) diff --git a/platform/platform.go b/platform/platform.go index 2ef29fb22..60267e021 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -31,7 +31,11 @@ import ( "github.com/trustwallet/blockatlas/platform/zilliqa" ) -const emptyParam = "" +const ( + allPlatformsHandle = "all" +) + +var CollectionsWhitelist map[uint]bool func GetVar(name string) string { return viper.GetString(name) @@ -87,13 +91,18 @@ func getPlatformMap() blockatlas.Platforms { coin.Dash().Handle: bitcoin.Init(coin.DASH, GetApiVar(coin.DASH)), coin.Doge().Handle: bitcoin.Init(coin.DOGE, GetApiVar(coin.DOGE)), coin.Qtum().Handle: bitcoin.Init(coin.QTUM, GetApiVar(coin.QTUM)), - coin.Gochain().Handle: ethereum.Init(coin.GO, GetApiVar(coin.GO), GetRpcVar(coin.GO), emptyParam, emptyParam), - coin.Thundertoken().Handle: ethereum.Init(coin.TT, GetApiVar(coin.TT), GetRpcVar(coin.TT), emptyParam, emptyParam), - coin.Classic().Handle: ethereum.Init(coin.ETC, GetApiVar(coin.ETC), GetRpcVar(coin.ETC), emptyParam, emptyParam), - coin.Poa().Handle: ethereum.Init(coin.POA, GetApiVar(coin.POA), GetRpcVar(coin.POA), emptyParam, emptyParam), - coin.Callisto().Handle: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO), emptyParam, emptyParam), - coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN), emptyParam, emptyParam), - coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO), emptyParam, emptyParam), - coin.Ethereum().Handle: ethereum.Init(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), + coin.Gochain().Handle: ethereum.Init(coin.GO, GetApiVar(coin.GO), GetRpcVar(coin.GO)), + coin.Thundertoken().Handle: ethereum.Init(coin.TT, GetApiVar(coin.TT), GetRpcVar(coin.TT)), + coin.Classic().Handle: ethereum.Init(coin.ETC, GetApiVar(coin.ETC), GetRpcVar(coin.ETC)), + coin.Poa().Handle: ethereum.Init(coin.POA, GetApiVar(coin.POA), GetRpcVar(coin.POA)), + coin.Callisto().Handle: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO)), + coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN)), + coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), + coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), } } + +func InitCollectionsWhitelist() { + CollectionsWhitelist = make(map[uint]bool) + CollectionsWhitelist[coin.Ethereum().ID] = true +} diff --git a/platform/registry.go b/platform/registry.go index b4fb817eb..a1018352f 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -28,23 +28,28 @@ var ( ) func getActivePlatforms(handle string) []blockatlas.Platform { - logger.Info("Loaded with: ", logger.Params{"handle": handle}) - platforms := getPlatformMap() + logger.Info("Platform API setup with: ", logger.Params{"handle": handle}) + + if handle == allPlatformsHandle { + return platforms.GetPlatformList() + } + platform, ok := platforms[handle] if ok { return []blockatlas.Platform{platform} - } else if handle == "all" { - return platforms.GetPlatformList() - } else { - logger.Fatal("Please, use ATLAS_PLATFORM handle with non-empty value", logger.Params{"ATLAS_PLATFORM": handle}) - return nil } + + logger.Fatal("Please, use ATLAS_PLATFORM handle with non-empty value, see more at Readme. Example: all", logger.Params{"ATLAS_PLATFORM": handle}) + return nil } func Init(platformHandle string) { platformList := getActivePlatforms(platformHandle) + // white list of collection api coins (only ETH now) + InitCollectionsWhitelist() + Platforms = make(map[string]blockatlas.Platform) BlockAPIs = make(map[string]blockatlas.BlockAPI) StakeAPIs = make(map[string]blockatlas.StakeAPI) @@ -84,7 +89,7 @@ func Init(platformHandle string) { if namingAPI, ok := platform.(blockatlas.NamingServiceAPI); ok { NamingAPIs[uint64(platform.Coin().ID)] = namingAPI } - if collectionAPI, ok := platform.(blockatlas.CollectionAPI); ok { + if collectionAPI, ok := platform.(blockatlas.CollectionAPI); ok && CollectionsWhitelist[platform.Coin().ID] { CollectionAPIs[platform.Coin().ID] = collectionAPI } } diff --git a/platform/stellar/client.go b/platform/stellar/client.go index eb47350fb..58716dd09 100644 --- a/platform/stellar/client.go +++ b/platform/stellar/client.go @@ -49,7 +49,7 @@ func (c *Client) CurrentBlockNumber() (int64, error) { } if len(ledgers.Embedded.Records) == 0 { - return 0, errors.E("CurrentBlockNumber: Records is empty", errors.TypePlatformUnmarshal).PushToSentry() + return 0, errors.E("CurrentBlockNumber: Records is empty", errors.TypePlatformUnmarshal) } return ledgers.Embedded.Records[0].Sequence, nil } diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index d12a25a06..baf200c18 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -35,7 +35,7 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPag tokenTxs, err := p.client.GetTxsOfAddress(address, token) if err != nil { return nil, errors.E(err, "TRON: failed to get token from address", errors.TypePlatformApi, - errors.Params{"address": address, "token": token}).PushToSentry() + errors.Params{"address": address, "token": token}) } txs := make(blockatlas.TxPage, 0) @@ -47,7 +47,7 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPag info, err := p.client.GetTokenInfo(token) if err != nil || len(info.Data) == 0 { return nil, errors.E(err, "TRON: failed to get token info", errors.TypePlatformApi, - errors.Params{"address": address, "token": token}).PushToSentry() + errors.Params{"address": address, "token": token}) } for _, srcTx := range tokenTxs { @@ -80,7 +80,7 @@ func setTokenMeta(tx *blockatlas.Tx, srcTx Tx, tokenInfo AssetInfo) { func Normalize(srcTx Tx) (*blockatlas.Tx, error) { if len(srcTx.Data.Contracts) == 0 { return nil, errors.E("TRON: transfer without contract", errors.TypePlatformApi, - errors.Params{"tx": srcTx}).PushToSentry() + errors.Params{"tx": srcTx}) } contract := srcTx.Data.Contracts[0] @@ -93,12 +93,12 @@ func Normalize(srcTx Tx) (*blockatlas.Tx, error) { from, err := address.HexToAddress(transfer.OwnerAddress) if err != nil { return nil, errors.E(err, "TRON: failed to get from address", errors.TypePlatformApi, - errors.Params{"tx": srcTx}).PushToSentry() + errors.Params{"tx": srcTx}) } to, err := address.HexToAddress(transfer.ToAddress) if err != nil { return nil, errors.E(err, "TRON: failed to get to address", errors.TypePlatformApi, - errors.Params{"tx": srcTx}).PushToSentry() + errors.Params{"tx": srcTx}) } return &blockatlas.Tx{ diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index bdf4a7eed..119049bba 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -54,19 +54,19 @@ func (p *Platform) getTransactionChannel(id string, txChan chan blockatlas.TxPag srcTx, err := p.client.GetTransactionByID(id) if err != nil { return errors.E(err, "Failed to get tx", errors.TypePlatformUnmarshal, - errors.Params{"id": id}).PushToSentry() + errors.Params{"id": id}) } receipt, err := p.client.GetTransactionReceiptByID(id) if err != nil { return errors.E(err, "Failed to get tx id receipt", errors.TypePlatformUnmarshal, - errors.Params{"id": id}).PushToSentry() + errors.Params{"id": id}) } txs, err := p.NormalizeTokenTransaction(srcTx, receipt) if err != nil { return errors.E(err, "Failed to NormalizeBlockTransactions tx", errors.TypePlatformUnmarshal, - errors.Params{"tx": srcTx}).PushToSentry() + errors.Params{"tx": srcTx}) } txChan <- txs return nil @@ -74,7 +74,7 @@ func (p *Platform) getTransactionChannel(id string, txChan chan blockatlas.TxPag func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (blockatlas.TxPage, error) { if receipt.Outputs == nil || len(receipt.Outputs) == 0 { - return blockatlas.TxPage{}, errors.E("NormalizeBlockTransaction: Clauses not found", errors.Params{"tx": srcTx}).PushToSentry() + return blockatlas.TxPage{}, errors.E("NormalizeBlockTransaction: Clauses not found", errors.Params{"tx": srcTx}) } origin := address.EIP55Checksum(blockatlas.GetValidParameter(srcTx.Origin, srcTx.Meta.TxOrigin)) diff --git a/scripts/run_tests_postman.sh b/scripts/run_tests_postman.sh new file mode 100755 index 000000000..0877438be --- /dev/null +++ b/scripts/run_tests_postman.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# blockatlas host +HOST=$1 + +cd .. +make newman test=transaction host=$HOST +make newman test=token host=$1 +make newman test=staking host=$1 +make newman test=collection host=$1 +make newman test=domain host=$1 +make newman test=observer host=$1 diff --git a/services/assets/info.go b/services/assets/info.go deleted file mode 100644 index ca33c29fb..000000000 --- a/services/assets/info.go +++ /dev/null @@ -1,26 +0,0 @@ -package assets - -import ( - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "time" -) - -func GetCoinInfo(coinId int, token string) (info *blockatlas.CoinInfo, err error) { - c, ok := coin.Coins[uint(coinId)] - if !ok { - return info, errors.E("coin not found") - } - url := getCoinInfoUrl(c, token) - request := blockatlas.InitClient(url) - err = request.GetWithCache(&info, "/info.json", nil, time.Hour*1) - return -} - -func getCoinInfoUrl(c coin.Coin, token string) string { - if len(token) == 0 { - return AssetsURL + c.Handle + "/info" - } - return AssetsURL + c.Handle + "/assets/" + token -} diff --git a/services/assets/info_test.go b/services/assets/info_test.go deleted file mode 100644 index bc7a280b5..000000000 --- a/services/assets/info_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package assets - -import ( - "github.com/trustwallet/blockatlas/coin" - "testing" -) - -func Test_getCoinInfoUrl(t *testing.T) { - type args struct { - c coin.Coin - token string - } - tests := []struct { - name string - args args - want string - }{ - {"test Ethereum coin", args{coin.Ethereum(), ""}, AssetsURL + coin.Ethereum().Handle + "/info"}, - {"test Ethereum token", args{coin.Ethereum(), "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, AssetsURL + coin.Ethereum().Handle + "/assets/" + "0x0000000000b3F879cb30FE243b4Dfee438691c04"}, - {"test Binance coin", args{coin.Binance(), ""}, AssetsURL + coin.Binance().Handle + "/info"}, - {"test Binance token", args{coin.Binance(), "BUSD-BD1"}, AssetsURL + coin.Binance().Handle + "/assets/" + "BUSD-BD1"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := getCoinInfoUrl(tt.args.c, tt.args.token); got != tt.want { - t.Errorf("getCoinInfoUrl() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/services/assets/model.go b/services/assets/model.go index 1eed6eed4..6d5ec909b 100644 --- a/services/assets/model.go +++ b/services/assets/model.go @@ -1,24 +1,27 @@ package assets -type AssetValidators []AssetValidator -type AssetValidatorMap map[string]AssetValidator +type ( + AssetValidators []AssetValidator -type AssetValidator struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Website string `json:"website"` - Payout ValidatorPayout `json:"payout,omitempty"` - Status ValidatorStatus `json:"status,omitempty"` -} + AssetValidatorMap map[string]AssetValidator -type ValidatorPayout struct { - Commission float64 `json:"commission"` -} + AssetValidator struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Website string `json:"website"` + Payout ValidatorPayout `json:"payout,omitempty"` + Status ValidatorStatus `json:"status,omitempty"` + } -type ValidatorStatus struct { - Disabled bool `json:"disabled"` -} + ValidatorPayout struct { + Commission float64 `json:"commission"` + } + + ValidatorStatus struct { + Disabled bool `json:"disabled"` + } +) func (av AssetValidators) toMap() AssetValidatorMap { validators := make(AssetValidatorMap) diff --git a/storage/subscriptions.go b/storage/addresses.go similarity index 100% rename from storage/subscriptions.go rename to storage/addresses.go diff --git a/storage/block.go b/storage/tracker.go similarity index 100% rename from storage/block.go rename to storage/tracker.go diff --git a/pkg/tests/functional/fixtures.go b/tests/functional/fixtures.go similarity index 100% rename from pkg/tests/functional/fixtures.go rename to tests/functional/fixtures.go diff --git a/pkg/tests/functional/functional_test.go b/tests/functional/functional_test.go similarity index 89% rename from pkg/tests/functional/functional_test.go rename to tests/functional/functional_test.go index 96f7a86dd..d5b1df9b6 100755 --- a/pkg/tests/functional/functional_test.go +++ b/tests/functional/functional_test.go @@ -51,14 +51,7 @@ func TestApis(t *testing.T) { }) }) - api.MakeMetricsRoute(engine) - api.LoadPlatforms(engine) - - if viper.GetBool("observer.enabled") { - logger.Info("Loading observer API") - observerAPI := engine.Group("/observer/v1") - api.SetupObserverAPI(observerAPI, cache) - } + api.SetupPlatformAPI(engine) signalForExit := make(chan os.Signal, 1) diff --git a/pkg/tests/functional/http.go b/tests/functional/http.go similarity index 100% rename from pkg/tests/functional/http.go rename to tests/functional/http.go diff --git a/pkg/tests/functional/testdata/body_fixtures.json b/tests/functional/testdata/body_fixtures.json similarity index 100% rename from pkg/tests/functional/testdata/body_fixtures.json rename to tests/functional/testdata/body_fixtures.json diff --git a/pkg/tests/functional/testdata/coin_fixtures.json b/tests/functional/testdata/coin_fixtures.json similarity index 100% rename from pkg/tests/functional/testdata/coin_fixtures.json rename to tests/functional/testdata/coin_fixtures.json diff --git a/pkg/tests/functional/testdata/exclude.json b/tests/functional/testdata/exclude.json similarity index 100% rename from pkg/tests/functional/testdata/exclude.json rename to tests/functional/testdata/exclude.json diff --git a/pkg/tests/functional/testdata/query_fixtures.json b/tests/functional/testdata/query_fixtures.json similarity index 100% rename from pkg/tests/functional/testdata/query_fixtures.json rename to tests/functional/testdata/query_fixtures.json diff --git a/pkg/tests/integration/bitcoin/block.go b/tests/integration/bitcoin/block.go similarity index 100% rename from pkg/tests/integration/bitcoin/block.go rename to tests/integration/bitcoin/block.go diff --git a/pkg/tests/integration/domains/domains.go b/tests/integration/domains/domains.go similarity index 100% rename from pkg/tests/integration/domains/domains.go rename to tests/integration/domains/domains.go diff --git a/pkg/tests/integration/integration_test.go b/tests/integration/integration_test.go similarity index 72% rename from pkg/tests/integration/integration_test.go rename to tests/integration/integration_test.go index 28b6d6bdd..218e49061 100755 --- a/pkg/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -5,9 +5,9 @@ package integration import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/pkg/tests/integration/bitcoin" - "github.com/trustwallet/blockatlas/pkg/tests/integration/domains" - "github.com/trustwallet/blockatlas/pkg/tests/integration/ontology" + "github.com/trustwallet/blockatlas/tests/integration/bitcoin" + "github.com/trustwallet/blockatlas/tests/integration/domains" + "github.com/trustwallet/blockatlas/tests/integration/ontology" "github.com/trustwallet/blockatlas/platform" "os" diff --git a/pkg/tests/integration/ontology/block.go b/tests/integration/ontology/block.go similarity index 100% rename from pkg/tests/integration/ontology/block.go rename to tests/integration/ontology/block.go diff --git a/pkg/tests/postman/Blockatlas.postman_collection.json b/tests/postman/Blockatlas.postman_collection.json similarity index 100% rename from pkg/tests/postman/Blockatlas.postman_collection.json rename to tests/postman/Blockatlas.postman_collection.json diff --git a/pkg/tests/postman/collection_data.json b/tests/postman/collection_data.json similarity index 100% rename from pkg/tests/postman/collection_data.json rename to tests/postman/collection_data.json diff --git a/pkg/tests/postman/domain_data.json b/tests/postman/domain_data.json similarity index 100% rename from pkg/tests/postman/domain_data.json rename to tests/postman/domain_data.json diff --git a/pkg/tests/postman/healthcheck_data.json b/tests/postman/healthcheck_data.json similarity index 100% rename from pkg/tests/postman/healthcheck_data.json rename to tests/postman/healthcheck_data.json diff --git a/pkg/tests/postman/market_data.json b/tests/postman/market_data.json similarity index 100% rename from pkg/tests/postman/market_data.json rename to tests/postman/market_data.json diff --git a/pkg/tests/postman/observer_data.json b/tests/postman/observer_data.json similarity index 100% rename from pkg/tests/postman/observer_data.json rename to tests/postman/observer_data.json diff --git a/pkg/tests/postman/staking_data.json b/tests/postman/staking_data.json similarity index 100% rename from pkg/tests/postman/staking_data.json rename to tests/postman/staking_data.json diff --git a/pkg/tests/postman/token_data.json b/tests/postman/token_data.json similarity index 100% rename from pkg/tests/postman/token_data.json rename to tests/postman/token_data.json diff --git a/pkg/tests/postman/transaction_data.json b/tests/postman/transaction_data.json similarity index 99% rename from pkg/tests/postman/transaction_data.json rename to tests/postman/transaction_data.json index bbc6084d0..59945f8f7 100644 --- a/pkg/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -37,7 +37,7 @@ }, { "handler": "poa", - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + "address": "0x59D82a4B6068188ac06605A8416b5C7D40d6Fc43" }, { "handler": "thundertoken", From 530257aadfc3fadccbe652a17b3669de06dc2abf Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Mon, 24 Feb 2020 02:49:49 +0300 Subject: [PATCH 157/506] Fix functional_test.go (#919) * Fix functional_test.go --- tests/functional/functional_test.go | 10 ++-------- tests/functional/testdata/exclude.json | 7 +++++++ tests/functional/testdata/query_fixtures.json | 3 +-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/functional/functional_test.go b/tests/functional/functional_test.go index d5b1df9b6..9d2efb4c7 100755 --- a/tests/functional/functional_test.go +++ b/tests/functional/functional_test.go @@ -22,7 +22,6 @@ import ( "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/storage" ) func TestApis(t *testing.T) { @@ -31,25 +30,20 @@ func TestApis(t *testing.T) { logger.InitLogger() platform.Init(viper.GetString("platform")) - cache := storage.New() + sg := sentrygin.New(sentrygin.Options{}) p := ":8420" engine := gin.New() engine.Use(gin.Recovery()) + engine.Use(ginutils.CheckReverseProxy, sg) engine.Use(ginutils.CORSMiddleware()) engine.OPTIONS("/*path", ginutils.CORSMiddleware()) engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - engine.GET("/", api.GetRoot) - engine.GET("/status", func(c *gin.Context) { - ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, - }) - }) api.SetupPlatformAPI(engine) diff --git a/tests/functional/testdata/exclude.json b/tests/functional/testdata/exclude.json index 189274cbc..87d3f8a44 100644 --- a/tests/functional/testdata/exclude.json +++ b/tests/functional/testdata/exclude.json @@ -2,6 +2,7 @@ "/swagger/*any", "/v1/fio/:address", "/v2/fio/transactions/:address", + "/v1/iotex/:address", "/v1/aeternity/:address", "/v1/ethereum/:address", "/v2/aeternity/transactions/:address", @@ -14,6 +15,12 @@ "/v2/tomochain/collections/:owner", "/v2/gochain/collections/:owner", "/v2/ethereum/collections/:owner", + "/v2/kava/staking/validators/:address", + "/v2/cosmos/staking/validators/:address", + "/v2/cosmos/staking/delegations/:address", + "/v2/iotex/transactions/:address", + "/v2/iotex/staking/validators", + "/v2/iotex/staking/delegations/:address", "/v2/classic/collections/:owner/collection/:collection_id", "/v2/callisto/collections/:owner/collection/:collection_id", "/v2/poa/collections/:owner/collection/:collection_id", diff --git a/tests/functional/testdata/query_fixtures.json b/tests/functional/testdata/query_fixtures.json index 6cf012ee2..0e73c21d2 100644 --- a/tests/functional/testdata/query_fixtures.json +++ b/tests/functional/testdata/query_fixtures.json @@ -11,8 +11,7 @@ "name=vitalik.luxe&coins=60", "name=ourxyzwallet.xyz&coins=60", "name=btc.zil&coins=313", - "name=btc.crypto&coins=313", - "name=adam@fiotestnet&coins=60" + "name=btc.crypto&coins=313" ], "/v1/market/charts": [ "currency=USD&time_start=1574483028&coin=60&token=0xdAC17F958D2ee523a2206206994597C13D831ec7", From d1db19d0cbed1dc0bbdef4307eb1422b257de2ee Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Mon, 24 Feb 2020 08:36:41 +0300 Subject: [PATCH 158/506] [Observer] Add new provider to send dispatched events, add RabbitMQ (#920) * Disptach events and send hooks via amqp / http protocol * Add DispatchProtocol type Co-authored-by: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> --- cmd/platform_observer/main.go | 7 ++++-- config.yml | 4 ++++ docker-compose.yml | 16 ++++++++++++- go.mod | 1 + go.sum | 2 ++ internal/init.go | 21 ++++++++++++++++ mq/mq.go | 41 +++++++++++++++++++++++++++++++ observer/dispatcher.go | 45 +++++++++++++++++++++++++++++------ 8 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 mq/mq.go diff --git a/cmd/platform_observer/main.go b/cmd/platform_observer/main.go index a04fdb2ab..0fdb461be 100644 --- a/cmd/platform_observer/main.go +++ b/cmd/platform_observer/main.go @@ -17,11 +17,13 @@ const ( var ( confPath string - cache *storage.Storage + dispatchProtocol observer.DispatchProtocol + cache *storage.Storage ) func init() { _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) + dispatchProtocol = internal.InitRabbitMQ() platform.Init(viper.GetString("platform")) } @@ -33,6 +35,7 @@ func main() { backlogTime := viper.GetDuration("observer.backlog") minInterval := viper.GetDuration("observer.block_poll.min") maxInterval := viper.GetDuration("observer.block_poll.max") + if minInterval >= maxInterval { logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") } @@ -69,7 +72,7 @@ func main() { events := obs.Execute(blocks) // Dispatch events - dispatcher := observer.Dispatcher{} + dispatcher := observer.Dispatcher{DispatchProtocol: observer.DispatchProtocol(dispatchProtocol)} go func() { dispatcher.Run(events) wg.Done() diff --git a/config.yml b/config.yml index 8f7117282..bde39695b 100644 --- a/config.yml +++ b/config.yml @@ -28,6 +28,10 @@ observer: block_poll: min: 3s max: 30s + rabbitmq: + uri: amqp://user:bitnami@rabbit:5672 + # http or amqp - the way to dispatch ans send events + dispatch_protocol: http storage: redis: redis://redis:6379 diff --git a/docker-compose.yml b/docker-compose.yml index c7fcc7778..915d7461d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,6 +22,7 @@ services: - 8422:8422 links: - redis + restart: on-failure platform_api: container_name: platform_api @@ -48,9 +49,22 @@ services: - SERVICE=platform_observer links: - redis + - rabbit + restart: on-failure + + rabbit: + container_name: rabbit + image: bitnami/rabbitmq + ports: + - 5672:5672 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5672"] + interval: 30s + timeout: 10s + retries: 5 redis: container_name: redis image: redis ports: - - 6379:6379 \ No newline at end of file + - 6379:6379 diff --git a/go.mod b/go.mod index 8a81e9d9e..de0bb6ac8 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/sirupsen/logrus v1.4.2 github.com/spf13/cast v1.3.1 github.com/spf13/viper v1.6.2 + github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 github.com/stretchr/testify v1.4.0 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.5 diff --git a/go.sum b/go.sum index d9943f83b..193793ce6 100644 --- a/go.sum +++ b/go.sum @@ -447,6 +447,8 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1 github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5NYJe/zRYDwOu9ku6YHy+Iw7l5DM= +github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= diff --git a/internal/init.go b/internal/init.go index 6ac30c03d..bfdf55726 100644 --- a/internal/init.go +++ b/internal/init.go @@ -7,6 +7,8 @@ import ( "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/observer" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" "path/filepath" @@ -73,6 +75,25 @@ func InitAPIWithRedis(defaultPort, defaultConfigPath string) (string, string, *g return port, confPath, &sg, cache } +func InitRabbitMQ() observer.DispatchProtocol { + dispatchProtocolStr := viper.GetString("observer.dispatch_protocol") + dispatchProtocol := observer.DispatchProtocol(dispatchProtocolStr) + + if dispatchProtocol != observer.AMQP && dispatchProtocol != observer.HTTP { + logger.Fatal("DispatchProtocol must be amqp (MQ) or http", logger.Params{"protocol": dispatchProtocol}) + } + + url := viper.GetString("observer.rabbitmq.uri") + + if dispatchProtocol == "amqp" { + err := mq.Init(url) + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"url": url}) + } + } + return dispatchProtocol +} + func LogVersionInfo() { fmt.Printf(` ------------------------------------------------------------------------------- diff --git a/mq/mq.go b/mq/mq.go new file mode 100644 index 000000000..353822233 --- /dev/null +++ b/mq/mq.go @@ -0,0 +1,41 @@ +package mq + +import ( + "github.com/streadway/amqp" +) + +var ( + amqpChan *amqp.Channel + conn *amqp.Connection + queue amqp.Queue +) + +type QueueName string + +const Notifications QueueName = "transactions" + +func Init(uri string) (err error) { + conn, err = amqp.Dial(uri) + if err != nil { + return + } + amqpChan, err = conn.Channel() + if err != nil { + return + } + queue, err = amqpChan.QueueDeclare(string(Notifications), true, false, false, false, nil) + return +} + +func Close() { + amqpChan.Close() + conn.Close() +} + +func Publish(body []byte) error { + return amqpChan.Publish("", queue.Name, false, false, amqp.Publishing{ + DeliveryMode: amqp.Persistent, + ContentType: "text/plain", + Body: body, + }) +} diff --git a/observer/dispatcher.go b/observer/dispatcher.go index 45b07d0d9..5d3b25781 100644 --- a/observer/dispatcher.go +++ b/observer/dispatcher.go @@ -3,19 +3,29 @@ package observer import ( "bytes" "encoding/json" + "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "net/http" ) +type DispatchProtocol string + +const ( + HTTP DispatchProtocol = "http" + AMQP DispatchProtocol = "amqp" +) + type Dispatcher struct { Client http.Client + DispatchProtocol DispatchProtocol } type DispatchEvent struct { - Action blockatlas.TransactionType `json:"action"` - Result *blockatlas.Tx `json:"result"` + Action blockatlas.TransactionType `json:"action"` + Result *blockatlas.Tx `json:"result"` + Webhook string `json:"webhook"` } func (d *Dispatcher) Run(events <-chan Event) { @@ -25,25 +35,37 @@ func (d *Dispatcher) Run(events <-chan Event) { } func (d *Dispatcher) dispatch(event Event) { + webhook := event.Subscription.Webhook + action := DispatchEvent{ - Action: event.Tx.Type, - Result: event.Tx, + Action: event.Tx.Type, + Result: event.Tx, + Webhook: webhook, } + txJson, err := json.Marshal(action) if err != nil { logger.Panic(err) } - webhook := event.Subscription.Webhook logParams := logger.Params{ "webhook": webhook, "coin": event.Subscription.Coin, "txID": event.Tx.ID, } - go d.postWebhook(webhook, txJson, logParams) - logger.Info("Dispatching webhooks...", logger.Params{"webhook": webhook}, logParams) + switch d.DispatchProtocol { + case HTTP: + go d.postWebhook(webhook, txJson, logParams) + case AMQP: + go d.postMessageToQueue(webhook, txJson, logParams) + default: + logger.Fatal("DispatchProtocol is incorrect", logger.Params{"protocol": d.DispatchProtocol}) + } + + logger.Info("Dispatching messages...", logParams) } +// use postWebhook if you want to transfer event by http protocol func (d *Dispatcher) postWebhook(hook string, data []byte, logParams logger.Params) { _, err := d.Client.Post(hook, "application/json", bytes.NewReader(data)) if err != nil { @@ -52,3 +74,12 @@ func (d *Dispatcher) postWebhook(hook string, data []byte, logParams logger.Para } logger.Info("Webhook dispatched", logger.Params{"webhook": hook}, logParams) } + +func (d *Dispatcher) postMessageToQueue(message string, rawMessage []byte, logParams logger.Params) { + err := mq.Publish(rawMessage) + if err != nil { + err = errors.E(err, "Failed to dispatch event", errors.Params{"message": message}, logParams) + logger.Error(err, logger.Params{"message": message}, logParams) + } + logger.Info("Message dispatched", logger.Params{"message": message}, logParams) +} From 1924b508099d8160275fbb1bc99894b3dccb7665 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> Date: Mon, 24 Feb 2020 16:20:36 +0300 Subject: [PATCH 159/506] Use only MQ in dispatcher(remove POST webhook method), update config.yml (#921) * Use only MQ in dispatcher(remove POST webhook method) * Remove dispatch_protocol field from config.yml --- cmd/platform_observer/main.go | 10 +++++++--- config.yml | 2 -- internal/init.go | 21 --------------------- observer/dispatcher.go | 29 ++--------------------------- 4 files changed, 9 insertions(+), 53 deletions(-) diff --git a/cmd/platform_observer/main.go b/cmd/platform_observer/main.go index 0fdb461be..a92a72cbf 100644 --- a/cmd/platform_observer/main.go +++ b/cmd/platform_observer/main.go @@ -4,6 +4,7 @@ import ( "context" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/observer" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" @@ -17,13 +18,16 @@ const ( var ( confPath string - dispatchProtocol observer.DispatchProtocol cache *storage.Storage ) func init() { _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) - dispatchProtocol = internal.InitRabbitMQ() + uri := viper.GetString("observer.rabbitmq.uri") + err := mq.Init(uri) + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) + } platform.Init(viper.GetString("platform")) } @@ -72,7 +76,7 @@ func main() { events := obs.Execute(blocks) // Dispatch events - dispatcher := observer.Dispatcher{DispatchProtocol: observer.DispatchProtocol(dispatchProtocol)} + var dispatcher observer.Dispatcher go func() { dispatcher.Run(events) wg.Done() diff --git a/config.yml b/config.yml index bde39695b..6007c378e 100644 --- a/config.yml +++ b/config.yml @@ -30,8 +30,6 @@ observer: max: 30s rabbitmq: uri: amqp://user:bitnami@rabbit:5672 - # http or amqp - the way to dispatch ans send events - dispatch_protocol: http storage: redis: redis://redis:6379 diff --git a/internal/init.go b/internal/init.go index bfdf55726..6ac30c03d 100644 --- a/internal/init.go +++ b/internal/init.go @@ -7,8 +7,6 @@ import ( "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/observer" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" "path/filepath" @@ -75,25 +73,6 @@ func InitAPIWithRedis(defaultPort, defaultConfigPath string) (string, string, *g return port, confPath, &sg, cache } -func InitRabbitMQ() observer.DispatchProtocol { - dispatchProtocolStr := viper.GetString("observer.dispatch_protocol") - dispatchProtocol := observer.DispatchProtocol(dispatchProtocolStr) - - if dispatchProtocol != observer.AMQP && dispatchProtocol != observer.HTTP { - logger.Fatal("DispatchProtocol must be amqp (MQ) or http", logger.Params{"protocol": dispatchProtocol}) - } - - url := viper.GetString("observer.rabbitmq.uri") - - if dispatchProtocol == "amqp" { - err := mq.Init(url) - if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"url": url}) - } - } - return dispatchProtocol -} - func LogVersionInfo() { fmt.Printf(` ------------------------------------------------------------------------------- diff --git a/observer/dispatcher.go b/observer/dispatcher.go index 5d3b25781..397073be3 100644 --- a/observer/dispatcher.go +++ b/observer/dispatcher.go @@ -1,7 +1,6 @@ package observer import ( - "bytes" "encoding/json" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -10,16 +9,8 @@ import ( "net/http" ) -type DispatchProtocol string - -const ( - HTTP DispatchProtocol = "http" - AMQP DispatchProtocol = "amqp" -) - type Dispatcher struct { Client http.Client - DispatchProtocol DispatchProtocol } type DispatchEvent struct { @@ -53,26 +44,10 @@ func (d *Dispatcher) dispatch(event Event) { "coin": event.Subscription.Coin, "txID": event.Tx.ID, } - switch d.DispatchProtocol { - case HTTP: - go d.postWebhook(webhook, txJson, logParams) - case AMQP: - go d.postMessageToQueue(webhook, txJson, logParams) - default: - logger.Fatal("DispatchProtocol is incorrect", logger.Params{"protocol": d.DispatchProtocol}) - } - logger.Info("Dispatching messages...", logParams) -} + go d.postMessageToQueue(webhook, txJson, logParams) -// use postWebhook if you want to transfer event by http protocol -func (d *Dispatcher) postWebhook(hook string, data []byte, logParams logger.Params) { - _, err := d.Client.Post(hook, "application/json", bytes.NewReader(data)) - if err != nil { - err = errors.E(err, "Failed to dispatch event", errors.Params{"webhook": hook}, logParams) - logger.Error(err, logger.Params{"webhook": hook}, logParams) - } - logger.Info("Webhook dispatched", logger.Params{"webhook": hook}, logParams) + logger.Info("Dispatching messages...", logParams) } func (d *Dispatcher) postMessageToQueue(message string, rawMessage []byte, logParams logger.Params) { From 95bfb73b129b9cf2d73f9b9b191f9a761ff3c5f1 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Tue, 25 Feb 2020 04:32:39 +0300 Subject: [PATCH 160/506] [Collections] Add normalizeSupportedContracts (#922) * Add normalize supported contracts logic * Add unit test for NormalizeSupportedContracts --- platform/ethereum/collection.go | 13 +++ platform/ethereum/collection_test.go | 163 +++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) diff --git a/platform/ethereum/collection.go b/platform/ethereum/collection.go index ffd8cf57c..251df61b9 100644 --- a/platform/ethereum/collection.go +++ b/platform/ethereum/collection.go @@ -167,6 +167,7 @@ func OldNormalizeCollectiblePage(c *Collection, srcPage []Collectible, coinIndex } func NormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas.Collection { + normalizeSupportedContracts(&c) if len(c.Contracts) == 0 { return blockatlas.Collection{} } @@ -193,7 +194,19 @@ func NormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas. } } +func normalizeSupportedContracts(c *Collection) { + supportedContracts := make([]PrimaryAssetContract, 0) + for _, contract := range c.Contracts { + if _, ok := supportedTypes[contract.Type]; !ok { + continue + } + supportedContracts = append(supportedContracts, contract) + } + c.Contracts = supportedContracts +} + func NormalizeCollectiblePage(c *Collection, srcPage []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { + normalizeSupportedContracts(c) if len(c.Contracts) == 0 { return } diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/collection_test.go index a3b6be197..1a96c8a15 100644 --- a/platform/ethereum/collection_test.go +++ b/platform/ethereum/collection_test.go @@ -246,3 +246,166 @@ func TestSearchCollection(t *testing.T) { } } + +func TestNormalizeSupportedContracts(t *testing.T) { + var contracts []PrimaryAssetContract + err := json.Unmarshal([]byte(rawAssetContracts), &contracts) + assert.Nil(t, err) + var collection = Collection{} + collection.Contracts = contracts + normalizeSupportedContracts(&collection) + assert.Equal(t, len(collection.Contracts), 2, "normalizeSupportedContracts with incorrect len") + var expectedContracts []PrimaryAssetContract + err = json.Unmarshal([]byte(rawAssetContractsExpected), &expectedContracts) + assert.Nil(t, err) + assert.Equal(t, collection.Contracts, expectedContracts, "normalizeSupportedContracts expectedContracts") +} + +const rawAssetContracts = `[ + { + "address": "0xee85966b4974d3c6f71a2779cc3b6f53afbc2b68", + "asset_contract_type": "fungible", + "created_date": "2019-10-16T07:36:16.102163", + "name": "Rare Chest", + "nft_version": null, + "opensea_version": null, + "owner": 1610615, + "schema_name": "ERC20", + "symbol": "", + "total_supply": "1", + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + { + "address": "0x20d4cec36528e1c4563c1bfbe3de06aba70b22b4", + "asset_contract_type": "fungible", + "created_date": "2019-10-16T08:06:42.727997", + "name": "Legendary Chest", + "nft_version": null, + "opensea_version": null, + "owner": 1610615, + "schema_name": "ERC20", + "symbol": "", + "total_supply": "1", + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + { + "address": "0x0e3a2a1f2146d86a604adc220b4967a898d7fe07", + "asset_contract_type": "non-fungible", + "created_date": "2019-11-01T06:39:04.363034", + "name": "Gods Unchained Cards", + "nft_version": "3.0", + "opensea_version": null, + "owner": 1691695, + "schema_name": "ERC721", + "symbol": "", + "total_supply": "1", + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + { + "address": "0x564cb55c655f727b61d9baf258b547ca04e9e548", + "asset_contract_type": "non-fungible", + "created_date": "2019-10-29T12:28:37.643714", + "name": "Gods Unchained", + "nft_version": "3.0", + "opensea_version": null, + "owner": 1691695, + "schema_name": "ERC721", + "symbol": "", + "total_supply": "205", + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + } +]` + +const rawAssetContractsExpected = `[{ + "address": "0x0e3a2a1f2146d86a604adc220b4967a898d7fe07", + "asset_contract_type": "non-fungible", + "created_date": "2019-11-01T06:39:04.363034", + "name": "Gods Unchained Cards", + "nft_version": "3.0", + "opensea_version": null, + "owner": 1691695, + "schema_name": "ERC721", + "symbol": "", + "total_supply": "1", + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + { + "address": "0x564cb55c655f727b61d9baf258b547ca04e9e548", + "asset_contract_type": "non-fungible", + "created_date": "2019-10-29T12:28:37.643714", + "name": "Gods Unchained", + "nft_version": "3.0", + "opensea_version": null, + "owner": 1691695, + "schema_name": "ERC721", + "symbol": "", + "total_supply": "205", + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + } +]` From f3fd50b098e650a1938aadbbda030611bd586cdb Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Tue, 25 Feb 2020 02:35:55 +0100 Subject: [PATCH 161/506] Fix Nimiq transaction requests (#832) --- .../tests/getTransactionsByAddress_50.json | 62 +++++++++++++++++++ platform/nimiq/transaction.go | 7 +++ platform/nimiq/transaction_test.go | 27 ++++++++ 3 files changed, 96 insertions(+) create mode 100644 platform/nimiq/tests/getTransactionsByAddress_50.json diff --git a/platform/nimiq/tests/getTransactionsByAddress_50.json b/platform/nimiq/tests/getTransactionsByAddress_50.json new file mode 100644 index 000000000..973f15bbe --- /dev/null +++ b/platform/nimiq/tests/getTransactionsByAddress_50.json @@ -0,0 +1,62 @@ +[ + { + "hash": "61454a43916e075f0e0a830888db7a37e9ffc42503fa3cd2d9eb85fe8067e435", + "blockHash": "ec2c6712a977d62e95e0d43eca02bf4161c86197e576073429c0cdc6b9cc1ce1", + "blockNumber": 507486, + "timestamp": 1554283830, + "confirmations": 450839, + "from": "99643a627e867dae6cf10ca73b4aff0345d3b72e", + "fromAddress": "NQ76 K5J3 LQKX GRXS UT7H 1JKK NJPY 0D2V 7DRE", + "to": "0d609a98033b7b85ab5178c6050ef9ef82d9006e", + "toAddress": "NQ64 1MG9 M603 7DVQ BASH F330 A3PR VX1D J03E", + "value": 199400, + "fee": 300, + "data": null, + "flags": 0 + }, + { + "hash": "bc38ac8f4fa67222e38e6120073e327a1cc7c38b8419502f6fd5dc3699853296", + "blockHash": "58c6afb786829419c90bdcdaf0ab01630b36105affc1718e3d2e772d91d73621", + "blockNumber": 952271, + "timestamp": 1581094339, + "confirmations": 6054, + "from": "fdcc85a8e604f23c7d2cd3c13a5d18dc566a6e7c", + "fromAddress": "NQ02 YP68 BA76 0KR3 QY9C SF0K LP8Q THB6 LTKU", + "to": "99643a627e867dae6cf10ca73b4aff0345d3b72e", + "toAddress": "NQ76 K5J3 LQKX GRXS UT7H 1JKK NJPY 0D2V 7DRE", + "value": 100000, + "fee": 138, + "data": null, + "flags": 0 + }, + { + "hash": "54de2a0c420f9c145320c9a020decb106b0b8989fe4be147144af79dc13e8a1c", + "blockHash": "25b73d90dd38ff61f6c8d713671ba576f735fa3f544d0ea9a5f74f00aea082ff", + "blockNumber": 933566, + "timestamp": 1579965313, + "confirmations": 24759, + "from": "fdcc85a8e604f23c7d2cd3c13a5d18dc566a6e7c", + "fromAddress": "NQ02 YP68 BA76 0KR3 QY9C SF0K LP8Q THB6 LTKU", + "to": "99643a627e867dae6cf10ca73b4aff0345d3b72e", + "toAddress": "NQ76 K5J3 LQKX GRXS UT7H 1JKK NJPY 0D2V 7DRE", + "value": 100000, + "fee": 138, + "data": null, + "flags": 0 + }, + { + "hash": "874494dc2640876ad1417822e230304050ef37924b06ee84a8d8584935f2707b", + "blockHash": "c583c5ee1b375d46d07a1289de036b7e10c426184d8d85de7e6d6eec66681167", + "blockNumber": 591542, + "timestamp": 1559352602, + "confirmations": 366783, + "from": "fdcc85a8e604f23c7d2cd3c13a5d18dc566a6e7c", + "fromAddress": "NQ02 YP68 BA76 0KR3 QY9C SF0K LP8Q THB6 LTKU", + "to": "99643a627e867dae6cf10ca73b4aff0345d3b72e", + "toAddress": "NQ76 K5J3 LQKX GRXS UT7H 1JKK NJPY 0D2V 7DRE", + "value": 100000, + "fee": 138, + "data": null, + "flags": 0 + } +] diff --git a/platform/nimiq/transaction.go b/platform/nimiq/transaction.go index 3bfba60c6..e16a14406 100644 --- a/platform/nimiq/transaction.go +++ b/platform/nimiq/transaction.go @@ -3,6 +3,7 @@ package nimiq import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "sort" "time" ) @@ -39,6 +40,12 @@ func NormalizeTx(srcTx *Tx) blockatlas.Tx { // NormalizeTxs converts multiple Nimiq transactions func NormalizeTxs(srcTxs []Tx) []blockatlas.Tx { + sort.SliceStable(srcTxs, func(i, j int) bool { + return srcTxs[i].BlockNumber > srcTxs[j].BlockNumber + }) + if len(srcTxs) > blockatlas.TxPerPage { + srcTxs = srcTxs[:blockatlas.TxPerPage] + } txs := make([]blockatlas.Tx, len(srcTxs)) for i, srcTx := range srcTxs { txs[i] = NormalizeTx(&srcTx) diff --git a/platform/nimiq/transaction_test.go b/platform/nimiq/transaction_test.go index edbc3a44a..8c0a5f0f6 100644 --- a/platform/nimiq/transaction_test.go +++ b/platform/nimiq/transaction_test.go @@ -5,6 +5,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "io/ioutil" + "path/filepath" + "runtime" + "sort" "testing" "time" ) @@ -96,3 +100,26 @@ func TestNormalizeTx1(t *testing.T) { }) } } + +func TestNormalizeTxs_Ordering(t *testing.T) { + _, goFile, _, _ := runtime.Caller(0) + testFilePath := filepath.Join(filepath.Dir(goFile), "tests", "getTransactionsByAddress_50.json") + testFile, err := ioutil.ReadFile(testFilePath) + if err != nil { + t.Fatal(err) + } + var srcTxs []Tx + if err := json.Unmarshal(testFile, &srcTxs); err != nil { + t.Fatal(err) + } + txs := NormalizeTxs(srcTxs) + if len(txs) != 4 { + t.Fatalf("Unexpected count: %d", len(txs)) + } + sorted := sort.SliceIsSorted(txs, func(i, j int) bool { + return txs[i].Block > txs[j].Block + }) + if !sorted { + t.Fatal("Transactions not sorted") + } +} From 75fd3b7b601a402708fbdd06b81f94345f9206de Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Tue, 25 Feb 2020 21:11:01 +0300 Subject: [PATCH 162/506] Change blocklatlas/client Get and Post functions and remove logs (#926) --- api/routes.go | 3 --- pkg/blockatlas/client.go | 17 ++++++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/api/routes.go b/api/routes.go index b4e8a9a5b..2d83d2b4e 100644 --- a/api/routes.go +++ b/api/routes.go @@ -22,12 +22,9 @@ func SetupObserverAPI(router gin.IRouter, db *storage.Storage) { observerAPI.POST("/webhook/register", addCall(db)) observerAPI.DELETE("/webhook/register", deleteCall(db)) observerAPI.GET("/status", statusCall(db)) - - logger.Info("Routes set up", logger.Params{"routes": len(routers)}) } func SetupPlatformAPI(root gin.IRouter) { - root.GET("/", GetRoot) root.GET("/status", GetStatus) diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go index c10c2dc68..3c5f0d08b 100644 --- a/pkg/blockatlas/client.go +++ b/pkg/blockatlas/client.go @@ -47,7 +47,7 @@ func (r *Request) Get(result interface{}, path string, query url.Values) error { queryStr = query.Encode() } uri := strings.Join([]string{r.GetBase(path), queryStr}, "?") - return r.Execute("GET", uri, nil, result, errors.Params{"path": path}) + return r.Execute("GET", uri, nil, result) } func (r *Request) Post(result interface{}, path string, body interface{}) error { @@ -56,14 +56,13 @@ func (r *Request) Post(result interface{}, path string, body interface{}) error return err } uri := r.GetBase(path) - return r.Execute("POST", uri, buf, result, errors.Params{"path": path}) + return r.Execute("POST", uri, buf, result) } -func (r *Request) Execute(method string, url string, body io.Reader, result interface{}, params errors.Params) error { - params["method"] = method +func (r *Request) Execute(method string, url string, body io.Reader, result interface{}) error { req, err := http.NewRequest(method, url, body) if err != nil { - return errors.E(err, errors.TypePlatformRequest, params) + return errors.E(err, errors.TypePlatformRequest) } for key, value := range r.Headers { @@ -72,21 +71,21 @@ func (r *Request) Execute(method string, url string, body io.Reader, result inte res, err := r.HttpClient.Do(req) if err != nil { - return errors.E(err, errors.TypePlatformRequest, params) + return errors.E(err, errors.TypePlatformRequest) } err = r.ErrorHandler(res, url) if err != nil { - return errors.E(err, errors.TypePlatformError, params) + return errors.E(err, errors.TypePlatformError) } defer res.Body.Close() b, err := ioutil.ReadAll(res.Body) if err != nil { - return errors.E(err, errors.TypePlatformUnmarshal, params) + return errors.E(err, errors.TypePlatformUnmarshal) } err = json.Unmarshal(b, result) if err != nil { - return errors.E(err, errors.TypePlatformUnmarshal, params) + return errors.E(err, errors.TypePlatformUnmarshal) } return err } From b9b096a8eca04e23cbeb08cc81a5248fbbffcdcf Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Wed, 26 Feb 2020 07:50:58 +0900 Subject: [PATCH 163/506] Add v4 Collectibles endpoint (#924) * Add v4 collectibles version. - Remove use of primary contracts * Setup v4 route * Rename CollectibleContract to AssetContract * Add support for v4 collectibles * Adjust v4 collectible tests * Add collection v4 and collections v4 batch postman tests Co-authored-by: Nick Kozlov --- api/collection.go | 70 ++++ api/routes.go | 5 + pkg/blockatlas/api.go | 3 + pkg/blockatlas/collectibles.go | 6 +- platform/ethereum/collection_client.go | 12 + platform/ethereum/collection_v4.go | 73 ++++ platform/ethereum/collection_v4_test.go | 337 ++++++++++++++++++ platform/ethereum/model.go | 26 +- .../Blockatlas.postman_collection.json | 271 +++++++++++++- 9 files changed, 790 insertions(+), 13 deletions(-) create mode 100644 platform/ethereum/collection_v4.go create mode 100644 platform/ethereum/collection_v4_test.go diff --git a/api/collection.go b/api/collection.go index 35c57e079..9d1081f1a 100644 --- a/api/collection.go +++ b/api/collection.go @@ -211,6 +211,76 @@ func makeCategoriesBatchRoute(router gin.IRouter) { }) } +// @Description Get collection categories +// @ID collection_categories_v4 +// @Summary Get list of collections from a specific coin and addresses +// @Accept json +// @Produce json +// @Tags Collections +// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) +// @Success 200 {object} blockatlas.DocsResponse +// @Router /v4/collectibles/categories [post] +func makeCategoriesBatchRouteV4(router gin.IRouter) { + router.POST("/collectibles/categories", func(c *gin.Context) { + var reqs map[string][]string + if err := c.BindJSON(&reqs); err != nil { + ginutils.ErrorResponse(c).Message(err.Error()).Render() + return + } + + batch := make(blockatlas.CollectionPage, 0) + for key, addresses := range reqs { + coinId, err := strconv.Atoi(key) + if err != nil { + continue + } + p, ok := platform.CollectionAPIs[uint(coinId)] + if !ok { + continue + } + for _, address := range addresses { + collections, err := p.GetCollectionsV4(address) + if err != nil { + continue + } + batch = append(batch, collections...) + } + } + ginutils.RenderSuccess(c, batch) + }) +} + +// @Summary Get Collection +// @ID collection_v4 +// @Description Get a collection from the address +// @Accept json +// @Produce json +// @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) +// @Success 200 {object} blockatlas.CollectionPage +// @Failure 500 {object} ginutils.ApiError +// @Router /v4/{coin}/collections/{owner}/collection/{collection_id} [get] +func makeCollectionRouteV4(router gin.IRouter, api blockatlas.Platform) { + var collectionAPI blockatlas.CollectionAPI + collectionAPI, _ = api.(blockatlas.CollectionAPI) + + if collectionAPI == nil { + return + } + + router.GET("/collections/:owner/collection/:collection_id", func(c *gin.Context) { + collectibles, err := collectionAPI.GetCollectiblesV4(c.Param("owner"), c.Param("collection_id")) + if err != nil { + ginutils.ErrorResponse(c).Message(err.Error()).Render() + return + } + + ginutils.RenderSuccess(c, collectibles) + }) +} + func emptyPage(c *gin.Context) { var page blockatlas.TxPage ginutils.RenderSuccess(c, &page) diff --git a/api/routes.go b/api/routes.go index 2d83d2b4e..c1ce1ba9c 100644 --- a/api/routes.go +++ b/api/routes.go @@ -31,6 +31,7 @@ func SetupPlatformAPI(root gin.IRouter) { v1 := root.Group("/v1") v2 := root.Group("/v2") v3 := root.Group("/v3") + v4 := root.Group("/v4") v1.GET("/", GetSupportedEndpoints) @@ -56,12 +57,15 @@ func SetupPlatformAPI(root gin.IRouter) { for _, collectionAPI := range platform.Platforms { routerV2 := getRouter(v2, collectionAPI.Coin().Handle) routerV3 := getRouter(v3, collectionAPI.Coin().Handle) + routerV4 := getRouter(v4, collectionAPI.Coin().Handle) makeCollectionsRoute(routerV3, collectionAPI) makeCollectionRoute(routerV3, collectionAPI) oldMakeCollectionRoute(routerV2, collectionAPI) oldMakeCollectionsRoute(routerV2, collectionAPI) + + makeCollectionRouteV4(routerV4, collectionAPI) } for _, customAPI := range platform.CustomAPIs { @@ -76,6 +80,7 @@ func SetupPlatformAPI(root gin.IRouter) { oldMakeCategoriesBatchRoute(v2) makeCategoriesBatchRoute(v3) + makeCategoriesBatchRouteV4(v4) makeStakingDelegationsBatchRoute(v2) makeStakingDelegationsSimpleBatchRoute(v2) diff --git a/pkg/blockatlas/api.go b/pkg/blockatlas/api.go index 141637baf..123d246af 100644 --- a/pkg/blockatlas/api.go +++ b/pkg/blockatlas/api.go @@ -58,6 +58,9 @@ type CollectionAPI interface { //TODO: remove once most of the clients will be updated (deadline: March 17th) OldGetCollections(owner string) (CollectionPage, error) OldGetCollectibles(owner, collectibleID string) (CollectiblePage, error) + + GetCollectionsV4(owner string) (CollectionPage, error) + GetCollectiblesV4(owner, collectibleID string) (CollectiblePage, error) } // CustomAPI provides custom HTTP routes diff --git a/pkg/blockatlas/collectibles.go b/pkg/blockatlas/collectibles.go index ac8cacb9c..d8829b665 100644 --- a/pkg/blockatlas/collectibles.go +++ b/pkg/blockatlas/collectibles.go @@ -11,9 +11,10 @@ type Collection struct { Total int `json:"total"` CategoryAddress string `json:"category_address"` Address string `json:"address"` - Version string `json:"nft_version"` Coin uint `json:"coin"` - Type string `json:"type"` + // Delete in the future version, as it's now part of Collectible + Version string `json:"nft_version"` + Type string `json:"type"` } type CollectionPage []Collection @@ -33,6 +34,7 @@ type Collectible struct { Description string `json:"description"` Coin uint `json:"coin"` Name string `json:"name"` + Version string `json:"nft_version"` } type CollectiblePage []Collectible diff --git a/platform/ethereum/collection_client.go b/platform/ethereum/collection_client.go index c41ae633d..2c4bdeb1d 100644 --- a/platform/ethereum/collection_client.go +++ b/platform/ethereum/collection_client.go @@ -43,6 +43,18 @@ func (c CollectionsClient) GetCollectibles(owner string, collectibleID string) ( return collection, page.Collectibles, err } +func (c CollectionsClient) GetCollectiblesV4(owner string, collectibleID string) ([]Collectible, error) { + query := url.Values{ + "owner": {owner}, + "collection": {collectibleID}, + "limit": {strconv.Itoa(300)}, + } + + var page CollectiblePage + err := c.Get(&page, "api/v1/assets", query) + return page.Collectibles, err +} + //TODO: remove once most of the clients will be updated (deadline: March 17th) func (c CollectionsClient) OldGetCollectibles(owner string, collectibleID string) (*Collection, []Collectible, error) { collections, err := c.GetCollections(owner) diff --git a/platform/ethereum/collection_v4.go b/platform/ethereum/collection_v4.go new file mode 100644 index 000000000..2eed5376a --- /dev/null +++ b/platform/ethereum/collection_v4.go @@ -0,0 +1,73 @@ +package ethereum + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "strings" +) + +func (p *Platform) GetCollectionsV4(owner string) (blockatlas.CollectionPage, error) { + collections, err := p.collectionsClient.GetCollections(owner) + if err != nil { + return nil, err + } + return NormalizeCollectionsV4(collections, p.CoinIndex, owner), nil +} + +func (p *Platform) GetCollectiblesV4(owner, collectibleID string) (blockatlas.CollectiblePage, error) { + items, err := p.collectionsClient.GetCollectiblesV4(owner, collectibleID) + if err != nil { + return nil, err + } + return NormalizeCollectiblePageV4(items, p.CoinIndex), nil +} + +func NormalizeCollectionsV4(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { + for _, collection := range collections { + item := NormalizeCollectionV4(collection, coinIndex, owner) + page = append(page, item) + } + return page +} + +func NormalizeCollectionV4(c Collection, coinIndex uint, owner string) blockatlas.Collection { + return blockatlas.Collection{ + Name: c.Name, + Slug: c.Slug, + ImageUrl: c.ImageUrl, + Description: c.Description, + ExternalLink: c.ExternalUrl, + Total: int(c.Total.Int64()), + Id: c.Slug, + Address: owner, + Coin: coinIndex, + } +} + +func NormalizeCollectiblePageV4(collectibles []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { + for _, collectible := range collectibles { + item := NormalizeCollectibleV4(collectible, coinIndex) + if _, ok := supportedTypes[item.Type]; ok { + page = append(page, item) + } + } + return page +} + +func NormalizeCollectibleV4(a Collectible, coinIndex uint) blockatlas.Collectible { + id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") + return blockatlas.Collectible{ + ID: id, + CollectionID: a.Collection.Slug, + TokenID: a.TokenId, + ContractAddress: a.AssetContract.Address, + Name: a.Name, + Category: a.Collection.Name, + ImageUrl: a.ImagePreviewUrl, + ProviderLink: a.Permalink, + ExternalLink: a.Collection.ExternalLink, + Type: a.AssetContract.Type, + Description: a.Description, + Coin: coinIndex, + Version: a.AssetContract.Version, + } +} diff --git a/platform/ethereum/collection_v4_test.go b/platform/ethereum/collection_v4_test.go new file mode 100644 index 000000000..ed7421610 --- /dev/null +++ b/platform/ethereum/collection_v4_test.go @@ -0,0 +1,337 @@ +package ethereum + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" +) + +const collectionsOwnerV4 = "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + +const collectionsSrcV4 = ` +[ + { + "primary_asset_contracts":[ + { + "address":"0x06012c8cf97bead5deae237070f9587f8e7a266d", + "name":"CryptoKitties", + "symbol":"CKITTY", + "description":"CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + "external_link":"https://www.cryptokitties.co/", + "nft_version":"1.0", + "schema_name":"ERC721", + "display_data":{ + "images":[ + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/564155.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/546630.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/441529.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/552435.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/524748.png", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/540800.svg" + ], + "card_display_style":"padded" + }, + "image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png" + } + ], + "name":"CryptoKitties", + "slug":"cryptokitties", + "image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", + "description":"CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + "external_url":"https://www.cryptokitties.co/", + "featured_image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556589429.png", + "created_date":"2019-04-26T22:13:04.207050", + "owned_asset_count":3 + }, + { + "primary_asset_contracts":[ + { + "address":"0xfaafdc07907ff5120a76b34b731b278c38d6043c", + "name":"Enjin", + "symbol":"", + "description":"", + "external_link":null, + "nft_version":null, + "schema_name":"ERC1155", + "display_data":{ + + }, + "owner":null, + "created_date":"2019-08-02T23:43:14.666153", + "asset_contract_type":"semi-fungible" + } + ], + "name":"Age of Rust", + "slug":"age-of-rust", + "image_url":"https://storage.opensea.io/age-of-rust-1561960816.jpg", + "description":"Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", + "external_url":"https://www.ageofrust.games/", + "featured_image_url":null, + "created_date":"2019-09-03T02:35:56.063685", + "owned_asset_count":1 + }, + { + "primary_asset_contracts":[ + { + "address":"0xee85966b4974d3c6f71a2779cc3b6f53afbc2b68", + "asset_contract_type":"fungible", + "created_date":"2019-10-16T07:36:16.102163", + "name":"Rare Chest", + "nft_version":null, + "opensea_version":null, + "owner":1610615, + "schema_name":"ERC20", + "symbol":"", + "total_supply":"1", + "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat":false, + "dev_buyer_fee_basis_points":0, + "dev_seller_fee_basis_points":0, + "only_proxied_transfers":false, + "opensea_buyer_fee_basis_points":0, + "opensea_seller_fee_basis_points":250, + "buyer_fee_basis_points":0, + "seller_fee_basis_points":250, + "payout_address":null + }, + { + "address":"0x20d4cec36528e1c4563c1bfbe3de06aba70b22b4", + "asset_contract_type":"fungible", + "created_date":"2019-10-16T08:06:42.727997", + "name":"Legendary Chest", + "nft_version":null, + "opensea_version":null, + "owner":1610615, + "schema_name":"ERC20", + "symbol":"", + "total_supply":"1", + "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat":false, + "dev_buyer_fee_basis_points":0, + "dev_seller_fee_basis_points":0, + "only_proxied_transfers":false, + "opensea_buyer_fee_basis_points":0, + "opensea_seller_fee_basis_points":250, + "buyer_fee_basis_points":0, + "seller_fee_basis_points":250, + "payout_address":null + }, + { + "address":"0x0e3a2a1f2146d86a604adc220b4967a898d7fe07", + "asset_contract_type":"non-fungible", + "created_date":"2019-11-01T06:39:04.363034", + "name":"Gods Unchained Cards", + "nft_version":"3.0", + "opensea_version":null, + "owner":1691695, + "schema_name":"ERC721", + "symbol":"", + "total_supply":"1", + "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat":false, + "dev_buyer_fee_basis_points":0, + "dev_seller_fee_basis_points":0, + "only_proxied_transfers":false, + "opensea_buyer_fee_basis_points":0, + "opensea_seller_fee_basis_points":250, + "buyer_fee_basis_points":0, + "seller_fee_basis_points":250, + "payout_address":null + }, + { + "address":"0x564cb55c655f727b61d9baf258b547ca04e9e548", + "asset_contract_type":"non-fungible", + "created_date":"2019-10-29T12:28:37.643714", + "name":"Gods Unchained", + "nft_version":"3.0", + "opensea_version":null, + "owner":1691695, + "schema_name":"ERC721", + "symbol":"", + "total_supply":"205", + "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat":false, + "dev_buyer_fee_basis_points":0, + "dev_seller_fee_basis_points":0, + "only_proxied_transfers":false, + "opensea_buyer_fee_basis_points":0, + "opensea_seller_fee_basis_points":250, + "buyer_fee_basis_points":0, + "seller_fee_basis_points":250, + "payout_address":null + } + ], + "traits":{ + "mana":{ + "min":1, + "max":18 + }, + "health":{ + "min":1, + "max":16 + }, + "attack":{ + "min":1, + "max":16 + } + }, + "stats":{ + "seven_day_volume":270.564697067863, + "seven_day_change":-0.014179906699531201, + "total_volume":11825.0384171324, + "count":6835331, + "num_owners":10791, + "market_cap":150892.14138332763, + "average_price":0.0396514694030496, + "items_sold":298233 + }, + "banner_image_url":null, + "chat_url":null, + "created_date":"2019-11-13T03:01:42.051246", + "default_to_fiat":false, + "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "dev_buyer_fee_basis_points":"0", + "dev_seller_fee_basis_points":"0", + "display_data":{ + "images":[ + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/25233.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/152875.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/25669.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9237.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9228.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9231.png" + ], + "card_display_style":"contain" + }, + "external_url":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "featured":true, + "featured_image_url":"https://storage.opensea.io/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab-featured-1556589419.png", + "hidden":false, + "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "is_subject_to_whitelist":false, + "large_image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ", + "name":"Gods Unchained", + "only_proxied_transfers":false, + "opensea_buyer_fee_basis_points":"0", + "opensea_seller_fee_basis_points":"250", + "payout_address":null, + "require_email":false, + "short_description":null, + "slug":"gods-unchained", + "wiki_url":null, + "owned_asset_count":535 + } +] +` + +var collection1DstV4 = blockatlas.Collection{ + Name: "CryptoKitties", + Symbol: "", + Slug: "cryptokitties", + ImageUrl: "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", + Description: "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + ExternalLink: "https://www.cryptokitties.co/", + Total: 3, + Id: "cryptokitties", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Coin: 60, +} + +var collection2DstV4 = blockatlas.Collection{ + Name: "Age of Rust", + Symbol: "", + Slug: "age-of-rust", + ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", + Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", + ExternalLink: "https://www.ageofrust.games/", + Total: 1, + Id: "age-of-rust", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Coin: 60, +} + +var collection3DstV4 = blockatlas.Collection{ + Name: "Gods Unchained", + Symbol: "", + Slug: "gods-unchained", + ImageUrl: "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + Description: "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + ExternalLink: "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + Total: 535, + Id: "gods-unchained", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Coin: 60, +} + +func TestNormalizeCollectionV4(t *testing.T) { + var collections []Collection + err := json.Unmarshal([]byte(collectionsSrcV4), &collections) + assert.Nil(t, err) + page := NormalizeCollectionsV4(collections, coin.ETH, collectionsOwnerV4) + assert.Equal(t, 3, len(page), "collections could not be normalized") + expected := blockatlas.CollectionPage{collection1DstV4, collection2DstV4, collection3DstV4} + assert.Equal(t, page, expected, "collections don't equal") +} + +const collectibleSrcV4 = ` +[ + { + "token_id": "54277541829991970107421667568590323026590803461896874578610080514640537714688", + "image_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858806.png", + "image_preview_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", + "name": "Rustbits", + "description": "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", + "external_link": "", + "asset_contract": { + "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + "name": "Enjin", + "external_link": null, + "nft_version": null, + "schema_name": "ERC1155", + "display_data": {} + }, + "collection": { + "slug": "age-of-rust", + "name": "Age of Rust", + "external_url": "https://opensea.io/" + }, + "permalink": "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688" + } +] +` + +var collectibleDstV4 = blockatlas.Collectible{ + ID: "0xfaafdc07907ff5120a76b34b731b278c38d6043c-54277541829991970107421667568590323026590803461896874578610080514640537714688", + CollectionID: "age-of-rust", + TokenID: "54277541829991970107421667568590323026590803461896874578610080514640537714688", + CategoryContract: "", + ContractAddress: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + Category: "Age of Rust", + ImageUrl: "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", + ExternalLink: "https://opensea.io/", + ProviderLink: "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688", + Type: "ERC1155", + Description: "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", + Coin: 60, + Name: "Rustbits", +} + +func TestNormalizeCollectibleV4(t *testing.T) { + var collectibles []Collectible + err := json.Unmarshal([]byte(collectibleSrcV4), &collectibles) + assert.Nil(t, err) + page := NormalizeCollectiblePageV4(collectibles, coin.ETH) + assert.Equal(t, len(page), 1, "collectible could not be normalized") + expected := blockatlas.CollectiblePage{collectibleDstV4} + assert.Equal(t, page, expected, "collectible don't equal") +} diff --git a/platform/ethereum/model.go b/platform/ethereum/model.go index df481539b..e4f2e3313 100644 --- a/platform/ethereum/model.go +++ b/platform/ethereum/model.go @@ -91,19 +91,27 @@ type CollectiblePage struct { } type Collectible struct { - TokenId string `json:"token_id"` - AssetContract CollectibleContract `json:"asset_contract"` - ImageUrl string `json:"image_url"` - ImagePreviewUrl string `json:"image_preview_url"` - Name string `json:"name"` - ExternalLink string `json:"external_link"` - Permalink string `json:"permalink"` - Description string `json:"description"` + TokenId string `json:"token_id"` + AssetContract AssetContract `json:"asset_contract"` + ImageUrl string `json:"image_url"` + ImagePreviewUrl string `json:"image_preview_url"` + Name string `json:"name"` + ExternalLink string `json:"external_link"` + Permalink string `json:"permalink"` + Description string `json:"description"` + Collection CollectibleCollections `json:"collection"` } -type CollectibleContract struct { +type CollectibleCollections struct { + Name string `json:"name"` + Slug string `json:"slug"` + ExternalLink string `json:"external_url"` +} + +type AssetContract struct { Address string `json:"address"` Category string `json:"name"` ExternalLink string `json:"external_link"` Type string `json:"schema_name"` + Version string `json:"nft_version"` } diff --git a/tests/postman/Blockatlas.postman_collection.json b/tests/postman/Blockatlas.postman_collection.json index be23b38a3..383850db7 100644 --- a/tests/postman/Blockatlas.postman_collection.json +++ b/tests/postman/Blockatlas.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "9cea8a5c-d3e5-40c1-98da-0a7a1742cf6d", + "_postman_id": "63af4255-85a1-4505-87cb-13f8de0453af", "name": "Blockatlas", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -1088,6 +1088,135 @@ }, "response": [] }, + { + "name": "collection v4", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"docs\": {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"collection_id\": {", + " \"type\": \"string\"", + " },", + " \"token_id\": {", + " \"type\": \"string\"", + " },", + " \"category_contract\": {", + " \"type\": \"string\"", + " },", + " \"contract_address\": {", + " \"type\": \"string\"", + " },", + " \"category\": {", + " \"type\": \"string\"", + " },", + " \"image_url\": {", + " \"type\": \"string\"", + " },", + " \"external_link\": {", + " \"type\": \"string\"", + " },", + " \"provider_link\": {", + " \"type\": \"string\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " },", + " \"description\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"name\": {", + " \"type\": \"string\"", + " }", + " }", + " }", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid: \" + address, function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + " console.log(JSON.stringify(jsonData))", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/v2/{{handler}}/collections/{{address}}/collection/{{collection}}", + "host": [ + "{{host}}" + ], + "path": [ + "v2", + "{{handler}}", + "collections", + "{{address}}", + "collection", + "{{collection}}" + ] + } + }, + "response": [] + }, { "name": "collections", "event": [ @@ -1487,6 +1616,144 @@ } }, "response": [] + }, + { + "name": "collections batch v4", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"docs\": {", + " \"type\": \"array\",", + " \"minItems\": 1,", + " \"uniqueItems\": true,", + " \"items\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"id\": {", + " \"type\": \"string\"", + " },", + " \"name\": {", + " \"type\": \"string\"", + " },", + " \"symbol\": {", + " \"type\": \"string\"", + " },", + " \"slug\": {", + " \"type\": \"string\"", + " },", + " \"image_url\": {", + " \"type\": \"string\"", + " },", + " \"external_link\": {", + " \"type\": \"string\"", + " },", + " \"total\": {", + " \"type\": \"integer\"", + " },", + " \"category_address\": {", + " \"type\": \"string\"", + " },", + " \"address\": {", + " \"type\": \"string\"", + " },", + " \"nft_version\": {", + " \"type\": \"string\"", + " },", + " \"coin\": {", + " \"type\": \"integer\"", + " },", + " \"type\": {", + " \"type\": \"string\"", + " }", + " }", + " }", + " },", + " \"status\": {", + " \"type\": \"boolean\"", + " }", + " }", + "};", + "", + "let handler = pm.variables.get(\"handler\");", + "let address = pm.variables.get(\"address\");", + "var jsonData = pm.response.json();", + "", + "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "pm.test(handler + \" - schema is valid: \" + address, function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + " console.log(JSON.stringify(jsonData))", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{platform_auth}}", + "type": "text" + }, + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"{{coin}}\": [\"{{address}}\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/v3/collectibles/categories", + "host": [ + "{{host}}" + ], + "path": [ + "v3", + "collectibles", + "categories" + ] + } + }, + "response": [] } ], "protocolProfileBehavior": {}, @@ -2529,4 +2796,4 @@ } ], "protocolProfileBehavior": {} -} +} \ No newline at end of file From ad7353dced2bffb507753af2785c3cf2ac02d585 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 26 Feb 2020 03:50:24 +0300 Subject: [PATCH 164/506] Add v4 collectibles functional test and update swagger (#928) Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> --- docs/docs.go | 95 +++++++++++++++++++- docs/swagger.json | 93 +++++++++++++++++++ docs/swagger.yaml | 64 +++++++++++++ tests/functional/testdata/body_fixtures.json | 12 +++ 4 files changed, 263 insertions(+), 1 deletion(-) diff --git a/docs/docs.go b/docs/docs.go index a64b11e20..99b46c3c3 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-18 21:29:30.368853 -0300 -03 m=+0.159220320 +// 2020-02-26 03:37:11.056244 +0300 MSK m=+0.121112696 package docs @@ -997,6 +997,98 @@ var doc = `{ } } } + }, + "/v4/collectibles/categories": { + "post": { + "description": "Get collection categories", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Collections" + ], + "summary": "Get list of collections from a specific coin and addresses", + "operationId": "collection_categories_v4", + "parameters": [ + { + "default": "{\"60\": [\"0xb3624367b1ab37daef42e1a3a2ced012359659b0\"]}", + "description": "Payload", + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/blockatlas.DocsResponse" + } + } + } + } + }, + "/v4/{coin}/collections/{owner}/collection/{collection_id}": { + "get": { + "description": "Get a collection from the address", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Collections" + ], + "summary": "Get Collection", + "operationId": "collection_v4", + "parameters": [ + { + "type": "string", + "default": "ethereum", + "description": "the coin name", + "name": "coin", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "description": "the query address", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "0x06012c8cf97bead5deae237070f9587f8e7a266d", + "description": "the query collection", + "name": "collection_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/blockatlas.CollectionPage" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/ginutils.ApiError" + } + } + } + } } }, "definitions": { @@ -1168,6 +1260,7 @@ var doc = `{ "type": "string" }, "nft_version": { + "description": "Delete in the future version, as it's now part of Collectible", "type": "string" }, "slug": { diff --git a/docs/swagger.json b/docs/swagger.json index 983255744..e34832650 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -976,6 +976,98 @@ } } } + }, + "/v4/collectibles/categories": { + "post": { + "description": "Get collection categories", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Collections" + ], + "summary": "Get list of collections from a specific coin and addresses", + "operationId": "collection_categories_v4", + "parameters": [ + { + "default": "{\"60\": [\"0xb3624367b1ab37daef42e1a3a2ced012359659b0\"]}", + "description": "Payload", + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/blockatlas.DocsResponse" + } + } + } + } + }, + "/v4/{coin}/collections/{owner}/collection/{collection_id}": { + "get": { + "description": "Get a collection from the address", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Collections" + ], + "summary": "Get Collection", + "operationId": "collection_v4", + "parameters": [ + { + "type": "string", + "default": "ethereum", + "description": "the coin name", + "name": "coin", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "description": "the query address", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "0x06012c8cf97bead5deae237070f9587f8e7a266d", + "description": "the query collection", + "name": "collection_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/blockatlas.CollectionPage" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/ginutils.ApiError" + } + } + } + } } }, "definitions": { @@ -1147,6 +1239,7 @@ "type": "string" }, "nft_version": { + "description": "Delete in the future version, as it's now part of Collectible", "type": "string" }, "slug": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index be121c2ee..428a6fada 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -109,6 +109,7 @@ definitions: name: type: string nft_version: + description: Delete in the future version, as it's now part of Collectible type: string slug: type: string @@ -1032,4 +1033,67 @@ paths: summary: Get list of collections from a specific coin and addresses tags: - Collections + /v4/{coin}/collections/{owner}/collection/{collection_id}: + get: + consumes: + - application/json + description: Get a collection from the address + operationId: collection_v4 + parameters: + - default: ethereum + description: the coin name + in: path + name: coin + required: true + type: string + - default: 0x0875BCab22dE3d02402bc38aEe4104e1239374a7 + description: the query address + in: path + name: owner + required: true + type: string + - default: 0x06012c8cf97bead5deae237070f9587f8e7a266d + description: the query collection + in: path + name: collection_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/blockatlas.CollectionPage' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/ginutils.ApiError' + summary: Get Collection + tags: + - Collections + /v4/collectibles/categories: + post: + consumes: + - application/json + description: Get collection categories + operationId: collection_categories_v4 + parameters: + - default: '{"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}' + description: Payload + in: body + name: data + required: true + schema: + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/blockatlas.DocsResponse' + summary: Get list of collections from a specific coin and addresses + tags: + - Collections swagger: "2.0" diff --git a/tests/functional/testdata/body_fixtures.json b/tests/functional/testdata/body_fixtures.json index d054da461..e99f8dc65 100644 --- a/tests/functional/testdata/body_fixtures.json +++ b/tests/functional/testdata/body_fixtures.json @@ -30,6 +30,18 @@ "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" ] } + ], + "/v4/collectibles/categories": [ + { + "60": [ + "0xb3624367b1ab37daef42e1a3a2ced012359659b0" + ] + }, + { + "60": [ + "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + ] + } ] } From b61aded757a87207386fa604bfa1a3c70b4c8a6d Mon Sep 17 00:00:00 2001 From: Mykola <3277207+kolya182@users.noreply.github.com> Date: Wed, 26 Feb 2020 21:13:48 -0800 Subject: [PATCH 165/506] Add transaction direction (#929) * Add transaction direction * format --- platform/vechain/transaction.go | 94 +++++++++++++++++------- platform/vechain/transaction_test.go | 102 +++++++++++++++++++++------ 2 files changed, 147 insertions(+), 49 deletions(-) diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 119049bba..5d3edfa75 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -77,8 +77,6 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (block return blockatlas.TxPage{}, errors.E("NormalizeBlockTransaction: Clauses not found", errors.Params{"tx": srcTx}) } - origin := address.EIP55Checksum(blockatlas.GetValidParameter(srcTx.Origin, srcTx.Meta.TxOrigin)) - fee, err := numbers.HexToDecimal(receipt.Paid) if err != nil { return blockatlas.TxPage{}, err @@ -90,31 +88,40 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (block continue } event := output.Events[0] // TODO add support for multisend - to := address.EIP55Checksum(event.Address) value, err := numbers.HexToDecimal(event.Data) if err != nil { continue } + originSender := address.EIP55Checksum(blockatlas.GetValidParameter(srcTx.Origin, srcTx.Meta.TxOrigin)) + originReceiver := address.EIP55Checksum(event.Address) + topicsFrom := address.EIP55Checksum(getRecipientAddress(event.Topics[1])) + topicsTo := address.EIP55Checksum(getRecipientAddress(event.Topics[2])) + + direction, err := getTokenTransactionDirectory(originSender, topicsFrom, topicsTo) + if err != nil { + continue + } txs = append(txs, blockatlas.Tx{ - ID: srcTx.Id, - Coin: p.Coin().ID, - From: origin, - To: to, - Fee: blockatlas.Amount(fee), - Date: srcTx.Meta.BlockTimestamp, - Type: blockatlas.TxTokenTransfer, - Block: srcTx.Meta.BlockNumber, - Status: blockatlas.StatusCompleted, + ID: srcTx.Id, + Coin: p.Coin().ID, + From: originSender, + To: originReceiver, + Fee: blockatlas.Amount(fee), + Date: srcTx.Meta.BlockTimestamp, + Type: blockatlas.TxTokenTransfer, + Block: srcTx.Meta.BlockNumber, + Status: blockatlas.StatusCompleted, + Direction: direction, Meta: blockatlas.TokenTransfer{ // the only supported Token on VeChain is its Gas token Name: gasTokenName, - TokenID: to, + TokenID: originReceiver, Value: blockatlas.Amount(value), Symbol: gasTokenSymbol, Decimals: gasTokenDecimals, - From: origin, - To: address.EIP55Checksum(getRecipientAddress(event.Topics[2])), + From: originSender, + To: topicsTo, }, }) } @@ -137,7 +144,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { if err != nil { continue } - tx, err := p.NormalizeTransaction(t, trxId) + tx, err := p.NormalizeTransaction(t, trxId, address) if err != nil { continue } @@ -146,24 +153,33 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func (p *Platform) NormalizeTransaction(srcTx LogTransfer, trxId Tx) (blockatlas.Tx, error) { +func (p *Platform) NormalizeTransaction(srcTx LogTransfer, trxId Tx, addr string) (blockatlas.Tx, error) { value, err := numbers.HexToDecimal(srcTx.Amount) if err != nil { return blockatlas.Tx{}, err } fee := strconv.Itoa(trxId.Gas) + sender := address.EIP55Checksum(srcTx.Sender) + recipient := address.EIP55Checksum(srcTx.Recipient) + addrChecksum := address.EIP55Checksum(addr) + + directory, err := getTransferDirectory(sender, recipient, addrChecksum) + if err != nil { + return blockatlas.Tx{}, err + } return blockatlas.Tx{ - ID: srcTx.Meta.TxId, - Coin: p.Coin().ID, - From: address.EIP55Checksum(srcTx.Sender), - To: address.EIP55Checksum(srcTx.Recipient), - Fee: blockatlas.Amount(fee), - Date: srcTx.Meta.BlockTimestamp, - Type: blockatlas.TxTransfer, - Block: srcTx.Meta.BlockNumber, - Status: blockatlas.StatusCompleted, + ID: srcTx.Meta.TxId, + Coin: p.Coin().ID, + From: sender, + To: recipient, + Fee: blockatlas.Amount(fee), + Date: srcTx.Meta.BlockTimestamp, + Type: blockatlas.TxTransfer, + Block: srcTx.Meta.BlockNumber, + Direction: directory, + Status: blockatlas.StatusCompleted, Meta: blockatlas.Transfer{ Value: blockatlas.Amount(value), Symbol: p.Coin().Symbol, @@ -185,3 +201,29 @@ func hexToInt(hex string) (uint64, error) { func getRecipientAddress(hex string) string { return "0x" + hex[len(hex)-40:] } + +func getTokenTransactionDirectory(originSender, topicsFrom, topicsTo string) (dir blockatlas.Direction, err error) { + if originSender == topicsFrom && originSender == topicsTo { + return blockatlas.DirectionSelf, nil + } + if originSender == topicsFrom && originSender != topicsTo { + return blockatlas.DirectionIncoming, nil + } + if originSender == topicsTo && originSender != topicsFrom { + return blockatlas.DirectionOutgoing, nil + } + return "", errors.E("Unknown direction") +} + +func getTransferDirectory(sender, recipient, addr string) (dir blockatlas.Direction, err error) { + if sender == addr && recipient == addr { + return blockatlas.DirectionSelf, nil + } + if sender == addr && recipient != addr { + return blockatlas.DirectionOutgoing, nil + } + if recipient == addr && sender != addr { + return blockatlas.DirectionIncoming, nil + } + return "", errors.E("Unknown direction") +} diff --git a/platform/vechain/transaction_test.go b/platform/vechain/transaction_test.go index 0383c3704..43fd3bb1b 100644 --- a/platform/vechain/transaction_test.go +++ b/platform/vechain/transaction_test.go @@ -27,15 +27,16 @@ const trxId = `{ }` var expectedTransfer = blockatlas.Tx{ - ID: "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", - Coin: coin.VET, - From: "0xB5e883349e68aB59307d1604555AC890fAC47128", - To: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", - Date: 1574410670, - Type: blockatlas.TxTransfer, - Fee: blockatlas.Amount("21000"), - Status: blockatlas.StatusCompleted, - Block: 4395940, + ID: "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", + Coin: coin.VET, + From: "0xB5e883349e68aB59307d1604555AC890fAC47128", + To: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", + Date: 1574410670, + Type: blockatlas.TxTransfer, + Fee: blockatlas.Amount("21000"), + Status: blockatlas.StatusCompleted, + Block: 4395940, + Direction: blockatlas.DirectionOutgoing, Meta: blockatlas.Transfer{ Value: blockatlas.Amount("1347000000000000000"), Decimals: 18, @@ -46,11 +47,12 @@ var expectedTransfer = blockatlas.Tx{ func TestNormalizeTransaction(t *testing.T) { tests := []struct { name string + addr string txData string txId string expected blockatlas.Tx }{ - {"Test normalize VET transfer transaction", transferSrc, trxId, expectedTransfer}, + {"Test normalize VET transfer transaction", "0xb5e883349e68ab59307d1604555ac890fac47128", transferSrc, trxId, expectedTransfer}, } platform := Platform{} @@ -65,7 +67,7 @@ func TestNormalizeTransaction(t *testing.T) { errTrxID := json.Unmarshal([]byte(tt.txId), &tId) assert.Nil(t, errTrxID) - actual, err := platform.NormalizeTransaction(tx, tId) + actual, err := platform.NormalizeTransaction(tx, tId, tt.addr) assert.Nil(t, err) assert.Equal(t, tt.expected, actual, "tx don't equal") @@ -133,15 +135,16 @@ const trxReceipt = `{ var expectedTransferLog = blockatlas.TxPage{ { - ID: "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", - Coin: coin.VET, - From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", - To: "0x0000000000000000000000000000456E65726779", - Date: 1574278180, - Type: blockatlas.TxTokenTransfer, - Fee: blockatlas.Amount("36582000000000000000"), - Status: blockatlas.StatusCompleted, - Block: 4382764, + ID: "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", + Coin: coin.VET, + From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", + To: "0x0000000000000000000000000000456E65726779", + Date: 1574278180, + Type: blockatlas.TxTokenTransfer, + Fee: blockatlas.Amount("36582000000000000000"), + Status: blockatlas.StatusCompleted, + Block: 4382764, + Direction: blockatlas.DirectionIncoming, Meta: blockatlas.TokenTransfer{ Name: gasTokenName, Symbol: gasTokenSymbol, @@ -210,9 +213,6 @@ func Test_hexToInt(t *testing.T) { } func Test_getRecipientAddress(t *testing.T) { - type args struct { - hex string - } tests := []struct { name string hex string @@ -229,3 +229,59 @@ func Test_getRecipientAddress(t *testing.T) { }) } } + +func Test_getTokenTransactionDirectory(t *testing.T) { + addr1 := "0xb5e883349e68ab59307d1604555ac890fac47128" + addr2 := "0eec2bbedbb8b18357dab0b753cd1893bb832284" + tests := []struct { + name string + originSender string + topicsFrom string + topicsTo string + expected blockatlas.Direction + expectErr bool + }{ + {"Self direction", addr1, addr1, addr1, blockatlas.DirectionSelf, false}, + {"In direction", addr1, addr1, addr2, blockatlas.DirectionIncoming, false}, + {"Out direction", addr1, addr2, addr1, blockatlas.DirectionOutgoing, false}, + {"Unknown direction", addr1, addr2, addr2, "", true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual, err := getTokenTransactionDirectory(tt.originSender, tt.topicsFrom, tt.topicsTo) + if tt.expectErr { + assert.NotNil(t, err) + } + assert.Equal(t, tt.expected, actual) + }) + } +} + +func Test_getTransferDirectory(t *testing.T) { + addr1 := "0xb5e883349e68ab59307d1604555ac890fac47128" + addr2 := "0eec2bbedbb8b18357dab0b753cd1893bb832284" + tests := []struct { + name string + sender string + recipient string + address string + expected blockatlas.Direction + expectErr bool + }{ + {"Self direction for addr1", addr1, addr1, addr1, blockatlas.DirectionSelf, false}, + {"Self direction for addr2", addr2, addr2, addr2, blockatlas.DirectionSelf, false}, + {"Out direction", addr1, addr2, addr1, blockatlas.DirectionOutgoing, false}, + {"In direction", addr1, addr2, addr2, blockatlas.DirectionIncoming, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual, err := getTransferDirectory(tt.sender, tt.recipient, tt.address) + if tt.expectErr { + assert.NotNil(t, err) + } + assert.Equal(t, tt.expected, actual) + }) + } +} From 5a2fb18b25a24dd64d96ae0c094475af39c87e13 Mon Sep 17 00:00:00 2001 From: coolcottontail <50373379+coolcottontail@users.noreply.github.com> Date: Thu, 27 Feb 2020 02:05:57 -0800 Subject: [PATCH 166/506] [Harmony] Adding get validators and get delegations #733 (#923) * adding get validators and get delegations * making apr dynamic, fixing variable names and delegation type * removing empty slice creation * Update azure-pipelines.yml for Azure Pipelines * fix azure-pipelines.yml for Azure Pipelines * make some client methods public (#731) * make some client methods public * fix callers * remove useless condition * move observers models to reusable package * [Market] Return pricing elements amount based on the time (#721) * if condition replaced by switch * decimate prices data * review fixes * update swagger * Sort validators by APR in desc by default (#736) * Remove unused and unecessary code * Add validator "Staus" struct * Sort validaotrs by APR in desc by default. Do not return disabled validaotrs * making apr dynamic, fixing variable names and delegation type * small refactoring (#737) * remove xpub for pushes (#735) * remove xpub * remove useless methods * fix unit tests * add unit tests and fix utxo value * fix market API initialization (#723) * follow route pattern * fix market routes * fix swagger file * fix swagger * removing empty slice creation * removed return value true form normalizeValidator Co-authored-by: Ganesha Upadhyaya Co-authored-by: Danilo Pantani Co-authored-by: dpereskokov Co-authored-by: Mykola <3277207+kolya182@users.noreply.github.com> Co-authored-by: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> --- platform/harmony/client.go | 43 +++++++++++++- platform/harmony/model.go | 21 +++++++ platform/harmony/stake.go | 90 ++++++++++++++++++++++++++++ platform/harmony/stake_test.go | 101 ++++++++++++++++++++++++++++++++ platform/harmony/transaction.go | 2 + 5 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 platform/harmony/stake.go create mode 100644 platform/harmony/stake_test.go diff --git a/platform/harmony/client.go b/platform/harmony/client.go index 67f48c6b6..50b0b996b 100644 --- a/platform/harmony/client.go +++ b/platform/harmony/client.go @@ -2,9 +2,11 @@ package harmony import ( "fmt" + "strconv" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" - "strconv" ) type Client struct { @@ -41,6 +43,45 @@ func (c *Client) GetBlockByNumber(num int64) (info BlockInfo, err error) { return } +func (c *Client) GetValidators() (validators Validators, err error) { + err = c.Get(&validators, "hmy_getAllValidatorAddresses", nil) + return +} + +func (c *Client) GetDelegations(address string) (delegations Delegations, err error) { + err = c.RpcCall(&delegations, "hmy_getDelegationsByDelegator", []interface{}{address}) + if err != nil { + logger.Error(err, "Harmony: Failed to get delegations for address") + } + return +} + +func (c *Client) GetBalance(address string) (string, error) { + var result string + err := c.RpcCall(&result, "hmy_getBalance", []interface{}{address, "latest"}) + if err != nil { + return "0", err + } + balance, err := numbers.HexToDecimal(result) + if err != nil { + return "0", err + } + return balance, nil +} + +func (c *Client) GetAPR() (float64, error) { + var aprInfo string + err := c.RpcCall(&aprInfo, "hmy_getAPR", nil) + if err != nil { + return 0, err + } + decimalBlock, err := numbers.HexToDecimal(aprInfo) + if err != nil { + return 0, err + } + return strconv.ParseFloat(decimalBlock, 64) +} + func hexToInt(hex string) (uint64, error) { nonceStr, err := numbers.HexToDecimal(hex) if err != nil { diff --git a/platform/harmony/model.go b/platform/harmony/model.go index a4134e22c..cc2a75fc5 100644 --- a/platform/harmony/model.go +++ b/platform/harmony/model.go @@ -1,5 +1,7 @@ package harmony +import "math/big" + type TxResponse struct { Result TxResult `json:"result"` } @@ -26,3 +28,22 @@ type BlockInfo struct { Number string `json:"number"` Transactions []Transaction `json:"transactions"` } + +type Validator struct { + Address string `json:"one-address"` + Active bool `json:"active"` +} + +type Validators struct { + Validators []Validator `json:"validators"` +} + +type Delegation struct { + DelegatorAddress string `json:"delegator_address"` + ValidatorAddress string `json:"validator_address"` + Amount *big.Int `json:"amount"` +} + +type Delegations struct { + List []Delegation `json:"result"` +} diff --git a/platform/harmony/stake.go b/platform/harmony/stake.go new file mode 100644 index 000000000..162ce5b42 --- /dev/null +++ b/platform/harmony/stake.go @@ -0,0 +1,90 @@ +package harmony + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/logger" + services "github.com/trustwallet/blockatlas/services/assets" +) + +func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { + results := make(blockatlas.ValidatorPage, 0) + validators, err := p.client.GetValidators() + if err != nil { + return results, err + } + + apr, err := p.client.GetAPR() + if err != nil { + apr = Annual + } + + for _, v := range validators.Validators { + results = append(results, normalizeValidator(v, apr)) + } + return results, nil +} + +func (p *Platform) GetDetails() blockatlas.StakingDetails { + apr, err := p.client.GetAPR() + if err != nil { + apr = Annual + } + return getDetails(apr) +} + +func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + delegations, err := p.client.GetDelegations(address) + if err != nil { + return nil, err + } + + validators, err := services.GetValidatorsMap(p) + if err != nil { + return nil, err + } + return NormalizeDelegations(delegations.List, validators), nil +} + +func (p *Platform) UndelegatedBalance(address string) (string, error) { + balance, err := p.client.GetBalance(address) + if err != nil { + return "0", err + } + return balance, nil +} + +func NormalizeDelegations(delegations []Delegation, validators blockatlas.ValidatorMap) []blockatlas.Delegation { + results := make([]blockatlas.Delegation, 0) + for _, v := range delegations { + validator, ok := validators[v.ValidatorAddress] + if !ok { + logger.Error(errors.E("Validator not found", errors.Params{"address": v.ValidatorAddress, "platform": "harmony", "delegation": v.DelegatorAddress})) + continue + } + delegation := blockatlas.Delegation{ + Delegator: validator, + Value: v.Amount.String(), + Status: blockatlas.DelegationStatusActive, + } + results = append(results, delegation) + } + return results +} + +func getDetails(apr float64) blockatlas.StakingDetails { + return blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: apr}, + MinimumAmount: blockatlas.Amount("0"), + LockTime: 0, + Type: blockatlas.DelegationTypeDelegate, + } +} + +func normalizeValidator(v Validator, apr float64) (validator blockatlas.Validator) { + return blockatlas.Validator{ + Status: true, + ID: v.Address, + Details: getDetails(apr), + } +} diff --git a/platform/harmony/stake_test.go b/platform/harmony/stake_test.go new file mode 100644 index 000000000..f193fc565 --- /dev/null +++ b/platform/harmony/stake_test.go @@ -0,0 +1,101 @@ +package harmony + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +const validatorSrc = ` +{ + "one-address": "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", + "bls-public-keys": [ + "65f55eb3052f9e9f632b2923be594ba77c55543f5c58ee1454b9cfd658d25e06373b0f7d42a19c84768139ea294f6204" + ], + "min-self-delegation": 2000000000000000000, + "max-total-delegation": 11553255926290448384, + "active": true, + "commission": { + "rate": "0.100000000000000000", + "max-rate": "0.900000000000000000", + "max-change-rate": "0.050000000000000000" + }, + "description": { + "name": "John", + "identity": "john", + "website": "john@harmony.one", + "security_contact": "Alex", + "details": "John the validator" + }, + "creation-height": 51 +}` + +const delegationsSrc = ` +[ + { + "validator_address": "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", + "delegator_address": "one1pf75h0t4am90z8uv3y0dgunfqp4lj8wr3t5rsp", + "amount": 10000000000000000000, + "reward": 15854399877248931866418, + "Undelegations": [] + } +]` + +func TestNormalizeValidator(t *testing.T) { + var v Validator + _ = json.Unmarshal([]byte(validatorSrc), &v) + expected := blockatlas.Validator{ + Status: v.Active, + ID: v.Address, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 10}, + LockTime: 0, + MinimumAmount: "0", + Type: blockatlas.DelegationTypeDelegate, + }, + } + result := normalizeValidator(v, 10) + assert.Equal(t, expected, result) +} + +var validator1 = blockatlas.StakeValidator{ + ID: "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "Harmony One", + Description: "Stake and earn rewards with the most secure and stable validator. Operated by Harmony One Inc.", + Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/harmony/validators/assets/one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy/logo.png", + Website: "https://harmony.one", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 10, + }, + LockTime: 0, + MinimumAmount: "0", + }, +} + +var validatorMap = blockatlas.ValidatorMap{ + "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy": validator1, +} + +func TestNormalizeDelegations(t *testing.T) { + var delegations []Delegation + err := json.Unmarshal([]byte(delegationsSrc), &delegations) + assert.NoError(t, err) + assert.NotNil(t, delegations) + + expected := []blockatlas.Delegation{ + { + Delegator: validator1, + Value: "10000000000000000000", + Status: blockatlas.DelegationStatusActive, + }, + } + result := NormalizeDelegations(delegations, validatorMap) + assert.Equal(t, expected, result) + +} diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index 890b5b436..920ed2cba 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -8,6 +8,8 @@ import ( "strconv" ) +const Annual = 10 + func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { result, err := p.client.GetTxsOfAddress(address) if err != nil { From c4c0b4a4250f57e75fa832f6d7a344917ce1997e Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Thu, 27 Feb 2020 13:26:51 +0300 Subject: [PATCH 167/506] Revert "[Harmony] Adding get validators and get delegations #733 (#923)" (#931) This reverts commit 5a2fb18b25a24dd64d96ae0c094475af39c87e13. --- platform/harmony/client.go | 43 +------------- platform/harmony/model.go | 21 ------- platform/harmony/stake.go | 90 ---------------------------- platform/harmony/stake_test.go | 101 -------------------------------- platform/harmony/transaction.go | 2 - 5 files changed, 1 insertion(+), 256 deletions(-) delete mode 100644 platform/harmony/stake.go delete mode 100644 platform/harmony/stake_test.go diff --git a/platform/harmony/client.go b/platform/harmony/client.go index 50b0b996b..67f48c6b6 100644 --- a/platform/harmony/client.go +++ b/platform/harmony/client.go @@ -2,11 +2,9 @@ package harmony import ( "fmt" - "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" + "strconv" ) type Client struct { @@ -43,45 +41,6 @@ func (c *Client) GetBlockByNumber(num int64) (info BlockInfo, err error) { return } -func (c *Client) GetValidators() (validators Validators, err error) { - err = c.Get(&validators, "hmy_getAllValidatorAddresses", nil) - return -} - -func (c *Client) GetDelegations(address string) (delegations Delegations, err error) { - err = c.RpcCall(&delegations, "hmy_getDelegationsByDelegator", []interface{}{address}) - if err != nil { - logger.Error(err, "Harmony: Failed to get delegations for address") - } - return -} - -func (c *Client) GetBalance(address string) (string, error) { - var result string - err := c.RpcCall(&result, "hmy_getBalance", []interface{}{address, "latest"}) - if err != nil { - return "0", err - } - balance, err := numbers.HexToDecimal(result) - if err != nil { - return "0", err - } - return balance, nil -} - -func (c *Client) GetAPR() (float64, error) { - var aprInfo string - err := c.RpcCall(&aprInfo, "hmy_getAPR", nil) - if err != nil { - return 0, err - } - decimalBlock, err := numbers.HexToDecimal(aprInfo) - if err != nil { - return 0, err - } - return strconv.ParseFloat(decimalBlock, 64) -} - func hexToInt(hex string) (uint64, error) { nonceStr, err := numbers.HexToDecimal(hex) if err != nil { diff --git a/platform/harmony/model.go b/platform/harmony/model.go index cc2a75fc5..a4134e22c 100644 --- a/platform/harmony/model.go +++ b/platform/harmony/model.go @@ -1,7 +1,5 @@ package harmony -import "math/big" - type TxResponse struct { Result TxResult `json:"result"` } @@ -28,22 +26,3 @@ type BlockInfo struct { Number string `json:"number"` Transactions []Transaction `json:"transactions"` } - -type Validator struct { - Address string `json:"one-address"` - Active bool `json:"active"` -} - -type Validators struct { - Validators []Validator `json:"validators"` -} - -type Delegation struct { - DelegatorAddress string `json:"delegator_address"` - ValidatorAddress string `json:"validator_address"` - Amount *big.Int `json:"amount"` -} - -type Delegations struct { - List []Delegation `json:"result"` -} diff --git a/platform/harmony/stake.go b/platform/harmony/stake.go deleted file mode 100644 index 162ce5b42..000000000 --- a/platform/harmony/stake.go +++ /dev/null @@ -1,90 +0,0 @@ -package harmony - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - services "github.com/trustwallet/blockatlas/services/assets" -) - -func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { - results := make(blockatlas.ValidatorPage, 0) - validators, err := p.client.GetValidators() - if err != nil { - return results, err - } - - apr, err := p.client.GetAPR() - if err != nil { - apr = Annual - } - - for _, v := range validators.Validators { - results = append(results, normalizeValidator(v, apr)) - } - return results, nil -} - -func (p *Platform) GetDetails() blockatlas.StakingDetails { - apr, err := p.client.GetAPR() - if err != nil { - apr = Annual - } - return getDetails(apr) -} - -func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { - delegations, err := p.client.GetDelegations(address) - if err != nil { - return nil, err - } - - validators, err := services.GetValidatorsMap(p) - if err != nil { - return nil, err - } - return NormalizeDelegations(delegations.List, validators), nil -} - -func (p *Platform) UndelegatedBalance(address string) (string, error) { - balance, err := p.client.GetBalance(address) - if err != nil { - return "0", err - } - return balance, nil -} - -func NormalizeDelegations(delegations []Delegation, validators blockatlas.ValidatorMap) []blockatlas.Delegation { - results := make([]blockatlas.Delegation, 0) - for _, v := range delegations { - validator, ok := validators[v.ValidatorAddress] - if !ok { - logger.Error(errors.E("Validator not found", errors.Params{"address": v.ValidatorAddress, "platform": "harmony", "delegation": v.DelegatorAddress})) - continue - } - delegation := blockatlas.Delegation{ - Delegator: validator, - Value: v.Amount.String(), - Status: blockatlas.DelegationStatusActive, - } - results = append(results, delegation) - } - return results -} - -func getDetails(apr float64) blockatlas.StakingDetails { - return blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: apr}, - MinimumAmount: blockatlas.Amount("0"), - LockTime: 0, - Type: blockatlas.DelegationTypeDelegate, - } -} - -func normalizeValidator(v Validator, apr float64) (validator blockatlas.Validator) { - return blockatlas.Validator{ - Status: true, - ID: v.Address, - Details: getDetails(apr), - } -} diff --git a/platform/harmony/stake_test.go b/platform/harmony/stake_test.go deleted file mode 100644 index f193fc565..000000000 --- a/platform/harmony/stake_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package harmony - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) - -const validatorSrc = ` -{ - "one-address": "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", - "bls-public-keys": [ - "65f55eb3052f9e9f632b2923be594ba77c55543f5c58ee1454b9cfd658d25e06373b0f7d42a19c84768139ea294f6204" - ], - "min-self-delegation": 2000000000000000000, - "max-total-delegation": 11553255926290448384, - "active": true, - "commission": { - "rate": "0.100000000000000000", - "max-rate": "0.900000000000000000", - "max-change-rate": "0.050000000000000000" - }, - "description": { - "name": "John", - "identity": "john", - "website": "john@harmony.one", - "security_contact": "Alex", - "details": "John the validator" - }, - "creation-height": 51 -}` - -const delegationsSrc = ` -[ - { - "validator_address": "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", - "delegator_address": "one1pf75h0t4am90z8uv3y0dgunfqp4lj8wr3t5rsp", - "amount": 10000000000000000000, - "reward": 15854399877248931866418, - "Undelegations": [] - } -]` - -func TestNormalizeValidator(t *testing.T) { - var v Validator - _ = json.Unmarshal([]byte(validatorSrc), &v) - expected := blockatlas.Validator{ - Status: v.Active, - ID: v.Address, - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 10}, - LockTime: 0, - MinimumAmount: "0", - Type: blockatlas.DelegationTypeDelegate, - }, - } - result := normalizeValidator(v, 10) - assert.Equal(t, expected, result) -} - -var validator1 = blockatlas.StakeValidator{ - ID: "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", - Status: true, - Info: blockatlas.StakeValidatorInfo{ - Name: "Harmony One", - Description: "Stake and earn rewards with the most secure and stable validator. Operated by Harmony One Inc.", - Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/harmony/validators/assets/one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy/logo.png", - Website: "https://harmony.one", - }, - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{ - Annual: 10, - }, - LockTime: 0, - MinimumAmount: "0", - }, -} - -var validatorMap = blockatlas.ValidatorMap{ - "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy": validator1, -} - -func TestNormalizeDelegations(t *testing.T) { - var delegations []Delegation - err := json.Unmarshal([]byte(delegationsSrc), &delegations) - assert.NoError(t, err) - assert.NotNil(t, delegations) - - expected := []blockatlas.Delegation{ - { - Delegator: validator1, - Value: "10000000000000000000", - Status: blockatlas.DelegationStatusActive, - }, - } - result := NormalizeDelegations(delegations, validatorMap) - assert.Equal(t, expected, result) - -} diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index 920ed2cba..890b5b436 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -8,8 +8,6 @@ import ( "strconv" ) -const Annual = 10 - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { result, err := p.client.GetTxsOfAddress(address) if err != nil { From 46fdba9808ab3929c553fb62d2dc25c11b20c1ad Mon Sep 17 00:00:00 2001 From: Mykola <3277207+kolya182@users.noreply.github.com> Date: Fri, 28 Feb 2020 17:12:31 -0800 Subject: [PATCH 168/506] XRP: Query min needed trx in desc order (#936) --- platform/ripple/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/ripple/client.go b/platform/ripple/client.go index b2d080084..5d6706c95 100644 --- a/platform/ripple/client.go +++ b/platform/ripple/client.go @@ -13,8 +13,8 @@ type Client struct { func (c *Client) GetTxsOfAddress(address string) ([]Tx, error) { query := url.Values{ "type": {"Payment"}, - "descending": {"false"}, - "limit": {"200"}, + "descending": {"true"}, + "limit": {"25"}, } uri := fmt.Sprintf("accounts/%s/transactions", url.PathEscape(address)) From 1354f474958b618285a30080afce0cf3f730ede0 Mon Sep 17 00:00:00 2001 From: Mykola <3277207+kolya182@users.noreply.github.com> Date: Sat, 29 Feb 2020 06:03:27 -0800 Subject: [PATCH 169/506] cosmos/fix: Fix missing transactions (#937) --- platform/cosmos/client.go | 4 ++-- platform/cosmos/model.go | 3 ++- platform/cosmos/transaction.go | 27 +++++++++++++++++++++++---- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/platform/cosmos/client.go b/platform/cosmos/client.go index eee6f4b8f..2378061dd 100644 --- a/platform/cosmos/client.go +++ b/platform/cosmos/client.go @@ -15,10 +15,10 @@ type Client struct { } // GetAddrTxs - get all ATOM transactions for a given address -func (c *Client) GetAddrTxs(address string, tag string) (txs TxPage, err error) { +func (c *Client) GetAddrTxs(address, tag string, page int) (txs TxPage, err error) { query := url.Values{ tag: {address}, - "page": {"1"}, + "page": {strconv.Itoa(page)}, "limit": {"25"}, } err = c.Get(&txs, "txs", query) diff --git a/platform/cosmos/model.go b/platform/cosmos/model.go index 09d7c2e82..9280c75c7 100644 --- a/platform/cosmos/model.go +++ b/platform/cosmos/model.go @@ -48,7 +48,8 @@ type Tx struct { } type TxPage struct { - Txs []Tx `json:"txs"` + PageTotal string `json:"page_total"` + Txs []Tx `json:"txs"` } // Events diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 04f752101..3fac2e2e3 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -12,24 +12,43 @@ import ( func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { tagsList := []string{"transfer.recipient", "message.sender"} var wg sync.WaitGroup - out := make(chan TxPage, len(tagsList)) + out := make(chan []Tx, len(tagsList)) wg.Add(len(tagsList)) for _, t := range tagsList { go func(tag, addr string, wg *sync.WaitGroup) { defer wg.Done() - txs, err := p.client.GetAddrTxs(addr, tag) + page := 1 + txs, err := p.client.GetAddrTxs(addr, tag, page) if err != nil { logger.Error("GetAddrTxs", err, logger.Params{"address": tag, "tag": tag}) return } - out <- txs + // Condition when no more pages to paginate + if txs.PageTotal == "1" { + out <- txs.Txs + return + } + + totalPages, err := strconv.Atoi(txs.PageTotal) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"totalPages": totalPages}) + return + } + // gaia does support sort option, paginate to get latest transactions by passing total pages page + // https://github.com/cosmos/gaia/blob/f61b391aee5d04364d2b5539692bbb187ad9b946/docs/resources/gaiacli.md#query-transactions + txs2, err := p.client.GetAddrTxs(addr, tag, totalPages) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"address": tag, "tag": tag}) + return + } + out <- txs2.Txs }(t, address, &wg) } wg.Wait() close(out) srcTxs := make([]Tx, 0) for r := range out { - srcTxs = append(srcTxs, r.Txs...) + srcTxs = append(srcTxs, r...) } return p.NormalizeTxs(srcTxs), nil } From 0342674155eaa58a90f30d64920404fb411864a1 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 29 Feb 2020 17:35:56 +0300 Subject: [PATCH 170/506] Exculde unstable endpoints from functional testing (#939) --- tests/functional/testdata/exclude.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/functional/testdata/exclude.json b/tests/functional/testdata/exclude.json index 87d3f8a44..714327013 100644 --- a/tests/functional/testdata/exclude.json +++ b/tests/functional/testdata/exclude.json @@ -28,6 +28,8 @@ "/v2/tomochain/collections/:owner/collection/:collection_id", "/v2/gochain/collections/:owner/collection/:collection_id", "/v2/ethereum/collections/:owner/collection/:collection_id", + "/v3/ethereum/collections/:owner/collection/:collection_id", + "/v4/ethereum/collections/:owner/collection/:collection_id", "/v3/classic/collections/:owner", "/v3/callisto/collections/:owner", "/v3/poa/collections/:owner", From 2b98f5aa763e861c9ff1d902dcb393646b8d58ba Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 29 Feb 2020 20:33:08 +0300 Subject: [PATCH 171/506] Change GetTxsOfAddress() ripple client function (#938) * Change GetTxsOfAddress() ripple client function, now we will retry to fetch transactions if descending == true fails * Refactor --- platform/ripple/client.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/platform/ripple/client.go b/platform/ripple/client.go index 5d6706c95..6900f4a04 100644 --- a/platform/ripple/client.go +++ b/platform/ripple/client.go @@ -11,9 +11,25 @@ type Client struct { } func (c *Client) GetTxsOfAddress(address string) ([]Tx, error) { + res, err := c.fetchTransactions(address, "true") + if err != nil { + return nil, err + } + + if res.Result == "error" { + res, err = c.fetchTransactions(address, "false") + if err != nil { + return nil, err + } + } + + return res.Transactions, nil +} + +func (c *Client) fetchTransactions(address, descending string) (Response, error) { query := url.Values{ "type": {"Payment"}, - "descending": {"true"}, + "descending": {descending}, "limit": {"25"}, } uri := fmt.Sprintf("accounts/%s/transactions", url.PathEscape(address)) @@ -21,9 +37,9 @@ func (c *Client) GetTxsOfAddress(address string) ([]Tx, error) { var res Response err := c.Get(&res, uri, query) if err != nil { - return nil, err + return Response{}, err } - return res.Transactions, nil + return res, nil } func (c *Client) GetCurrentBlock() (int64, error) { From 83a2781a190df74ef1aa7161e1ba97a1d8c4f419 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 1 Mar 2020 04:07:56 +0300 Subject: [PATCH 172/506] Change subscription api. Now we will subscribe users by using MQ (#941) * Change obsrver_api to worker. Now using MQ to subcribe for events --- Makefile | 25 ++--- api/observer.go | 106 ------------------ api/routes.go | 13 --- cmd/observer_api/main.go | 39 ------- cmd/observer_subscriber/main.go | 45 ++++++++ .../main.go | 8 +- cmd/platform_api/main.go | 1 - cmd/swagger_api/main.go | 1 - docs/docs.go | 6 +- mq/mq.go | 42 ++++++- observer/dispatcher.go | 2 +- pkg/blockatlas/observer.go | 15 ++- pkg/blockatlas/observer_test.go | 10 +- services/subscription/subscribtion.go | 36 ++++++ services/subscription/subscription_test.go | 32 ++++++ storage/addresses.go | 15 ++- storage/storage.go | 4 +- 17 files changed, 196 insertions(+), 204 deletions(-) delete mode 100644 api/observer.go delete mode 100644 cmd/observer_api/main.go create mode 100644 cmd/observer_subscriber/main.go rename cmd/{platform_observer => observer_worker}/main.go (93%) create mode 100644 services/subscription/subscribtion.go create mode 100644 services/subscription/subscription_test.go diff --git a/Makefile b/Makefile index 49451dece..b05a97f75 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ BUILD := $(shell git rev-parse --short HEAD) DATETIME := $(shell date +"%Y.%m.%d-%H:%M:%S") PROJECT_NAME := $(shell basename "$(PWD)") API_SERVICE := platform_api -OBSERVER_SERVICE := platform_observer -OBSERVER_API := observer_api +OBSERVER_SERVICE := observer_worker +OBSERVER_SUBSCRIBER := observer_subscriber SWAGGER_API := swagger_api COIN_FILE := coin/coins.yml COIN_GO_FILE := coin/coins.go @@ -34,7 +34,7 @@ STDERR := /tmp/.$(PROJECT_NAME)-stderr.txt # PID file will keep the process id of the server PID_API := /tmp/.$(PROJECT_NAME).$(API_SERVICE).pid PID_OBSERVER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SERVICE).pid -PID_OBSERVER_API := /tmp/.$(PROJECT_NAME).$(OBSERVER_API).pid +PID_OBSERVER_SUBSCRIBER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SUBSCRIBER).pid PID_SWAGGER_API := /tmp/.$(PROJECT_NAME).$(SWAGGER_API).pid # Make is verbose in Linux. Make it silent. MAKEFLAGS += --silent @@ -63,8 +63,8 @@ start-platform-observer: stop ## start-observer: Start Observer in development mode. start-observer-api: stop @echo " > Starting $(PROJECT_NAME) Observer" - @-$(GOBIN)/$(OBSERVER_API)/observer_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_API) - @cat $(PID_OBSERVER_API) | sed "/^/s/^/ \> Observer PID: /" + @-$(GOBIN)/$(OBSERVER_SUBSCRIBER)/observer_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_SUBSCRIBER) + @cat $(PID_OBSERVER_SUBSCRIBER) | sed "/^/s/^/ \> Observer PID: /" @echo " > Error log: $(STDERR)" ## start-sync-market-api: Start Sync market api in development mode. @@ -76,12 +76,12 @@ start-swagger-api: stop ## stop: Stop development mode. stop: - @-touch $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_API) $(PID_SWAGGER_API) + @-touch $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) @-kill `cat $(PID_API)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER)` 2> /dev/null || true - @-kill `cat $(PID_OBSERVER_API)` 2> /dev/null || true + @-kill `cat $(PID_OBSERVER_SUBSCRIBER)` 2> /dev/null || true @-kill `cat $(PID_SWAGGER_API)` 2> /dev/null || true - @-rm $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_API) $(PID_SWAGGER_API) + @-rm $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) ## compile: Compile the project. compile: @@ -152,7 +152,6 @@ ifeq (,$(test)) @bash -c "$(MAKE) newman test=collection host=$(host)" @bash -c "$(MAKE) newman test=domain host=$(host)" @bash -c "$(MAKE) newman test=healthcheck host=$(host)" - @bash -c "$(MAKE) newman test=observer host=$(host)" else @newman run tests/postman/Blockatlas.postman_collection.json --folder $(test) -d tests/postman/$(test)_data.json --env-var "host=$(host)" endif @@ -162,10 +161,10 @@ go-compile: go-get go-build go-build: @echo " > Building platform_api binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API_SERVICE)/platform_api ./cmd/$(API_SERVICE) - @echo " > Building platform_observer binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SERVICE)/platform_observer ./cmd/$(OBSERVER_SERVICE) - @echo " > Building observer_api binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_API)/observer_api ./cmd/$(OBSERVER_API) + @echo " > Building observer_worker binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SERVICE)/observer_worker ./cmd/$(OBSERVER_SERVICE) + @echo " > Building observer_subscriber binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(observer_subscriber)/observer_subscriber ./cmd/$(OBSERVER_SUBSCRIBER) @echo " > Building swagger_api binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SWAGGER_API)/swagger_api ./cmd/$(SWAGGER_API) diff --git a/api/observer.go b/api/observer.go deleted file mode 100644 index 160832f8a..000000000 --- a/api/observer.go +++ /dev/null @@ -1,106 +0,0 @@ -package api - -import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/storage" -) - -// @Summary Create a webhook -// @ID create_webhook -// @Description Create a webhook for addresses transactions -// @Accept json -// @Produce json -// @Tags Observer -// @Param subscriptions body blockatlas.Webhook true "Accounts subscriptions" -// @Param Authorization header string true "Bearer authorization header" default(Bearer test) -// @Header 200 {string} Authorization {token} -// @Success 200 {object} blockatlas.Observer -// @Router /observer/v1/webhook/register [post] -func addCall(storage storage.Addresses) func(c *gin.Context) { - if storage == nil { - return nil - } - return func(c *gin.Context) { - var req blockatlas.Webhook - if c.BindJSON(&req) != nil { - return - } - - if len(req.Subscriptions) == 0 { - ginutils.RenderSuccess(c, blockatlas.Observer{Message: "Added", Status: true}) - return - } - subs := req.ParseSubscriptions() - go storage.AddSubscriptions(subs) - - ginutils.RenderSuccess(c, blockatlas.Observer{Message: "Added", Status: true}) - } -} - -// @Summary Delete a webhook -// @ID delete_webhook -// @Description Delete a webhook for addresses transactions -// @Accept json -// @Produce json -// @Tags Observer -// @Param subscriptions body blockatlas.Webhook true "Accounts subscriptions" -// @Param Authorization header string true "Bearer authorization header" default(Bearer test) -// @Header 200 {string} Authorization {token} -// @Success 200 {object} blockatlas.Observer -// @Router /observer/v1/webhook/register [delete] -func deleteCall(storage storage.Addresses) func(c *gin.Context) { - if storage == nil { - return nil - } - return func(c *gin.Context) { - var req blockatlas.Webhook - if c.BindJSON(&req) != nil { - return - } - - if len(req.Subscriptions) == 0 { - ginutils.RenderSuccess(c, blockatlas.Observer{Message: "Deleted", Status: true}) - return - } - - subs := req.ParseSubscriptions() - go storage.DeleteSubscriptions(subs) - ginutils.RenderSuccess(c, blockatlas.Observer{Message: "Deleted", Status: true}) - } -} - -// @Summary Get coin status -// @ID coin_status -// @Description Get coin status -// @Accept json -// @Produce json -// @Tags Observer -// @Param Authorization header string true "Bearer authorization header" default(Bearer test) -// @Header 200 {string} Authorization {token} -// @Success 200 {object} blockatlas.CoinStatus -// @Router /observer/v1/status [get] -func statusCall(storage storage.Tracker) func(c *gin.Context) { - if storage == nil { - return nil - } - return func(c *gin.Context) { - result := make(map[string]blockatlas.CoinStatus) - for _, api := range platform.BlockAPIs { - coin := api.Coin() - num, err := storage.GetBlockNumber(coin.ID) - var status blockatlas.CoinStatus - if err != nil { - status = blockatlas.CoinStatus{Error: err.Error()} - } else if num == 0 { - status = blockatlas.CoinStatus{Error: "no blocks"} - } else { - status = blockatlas.CoinStatus{Height: num} - } - result[coin.Handle] = status - } - ginutils.RenderSuccess(c, result) - } -} diff --git a/api/routes.go b/api/routes.go index c1ce1ba9c..c843a21ab 100644 --- a/api/routes.go +++ b/api/routes.go @@ -3,27 +3,14 @@ package api import ( "fmt" "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/storage" ) var routers = make(map[string]gin.IRouter) -func SetupObserverAPI(router gin.IRouter, db *storage.Storage) { - router.GET("/", GetRoot) - router.GET("/status", GetStatus) - - observerAPI := router.Group("/observer/v1") - observerAPI.Use(ginutils.TokenAuthMiddleware(viper.GetString("observer.auth"))) - observerAPI.POST("/webhook/register", addCall(db)) - observerAPI.DELETE("/webhook/register", deleteCall(db)) - observerAPI.GET("/status", statusCall(db)) -} - func SetupPlatformAPI(root gin.IRouter) { root.GET("/", GetRoot) root.GET("/status", GetStatus) diff --git a/cmd/observer_api/main.go b/cmd/observer_api/main.go deleted file mode 100644 index ce72ea515..000000000 --- a/cmd/observer_api/main.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "github.com/gin-gonic/gin" - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/api" - _ "github.com/trustwallet/blockatlas/docs" - "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/storage" -) - -const ( - defaultPort = "8422" - defaultConfigPath = "../../config.yml" -) - -var ( - port, confPath string - cache *storage.Storage - sg *gin.HandlerFunc -) - -func init() { - port, confPath, sg, cache = internal.InitAPIWithRedis(defaultPort, defaultConfigPath) -} - -func main() { - gin.SetMode(viper.GetString("gin.mode")) - - engine := gin.New() - engine.Use(ginutils.CheckReverseProxy, *sg) - engine.Use(ginutils.CORSMiddleware()) - engine.Use(gin.Logger()) - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) - - api.SetupObserverAPI(engine, cache) - internal.SetupGracefulShutdown(port, engine) -} diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go new file mode 100644 index 000000000..7e32970b6 --- /dev/null +++ b/cmd/observer_subscriber/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + _ "github.com/trustwallet/blockatlas/docs" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/services/subscription" + "github.com/trustwallet/blockatlas/storage" +) + +const ( + defaultConfigPath = "../../config.yml" +) + +var ( + port, confPath string + cache *storage.Storage + sg *gin.HandlerFunc +) + +func init() { + _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) + + uri := viper.GetString("observer.rabbitmq.uri") + err := mq.Init(uri) + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) + } + err = mq.Transactions.Declare() + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) + } + + platform.Init(viper.GetString("platform")) +} + +func main() { + defer mq.Close() + mq.Subscriptions.RunConsumer(subscription.Consume, cache) + <-make(chan struct{}) +} diff --git a/cmd/platform_observer/main.go b/cmd/observer_worker/main.go similarity index 93% rename from cmd/platform_observer/main.go rename to cmd/observer_worker/main.go index a92a72cbf..2809ee84b 100644 --- a/cmd/platform_observer/main.go +++ b/cmd/observer_worker/main.go @@ -18,16 +18,22 @@ const ( var ( confPath string - cache *storage.Storage + cache *storage.Storage ) func init() { _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) + uri := viper.GetString("observer.rabbitmq.uri") err := mq.Init(uri) if err != nil { logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) } + err = mq.Transactions.Declare() + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) + } + platform.Init(viper.GetString("platform")) } diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index 507220453..26ac4396a 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -32,7 +32,6 @@ func main() { engine.Use(ginutils.CheckReverseProxy, *sg) engine.Use(ginutils.CORSMiddleware()) engine.Use(gin.Logger()) - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) api.SetupPlatformAPI(engine) internal.SetupGracefulShutdown(port, engine) diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go index 660821c51..2d2c4b4d9 100644 --- a/cmd/swagger_api/main.go +++ b/cmd/swagger_api/main.go @@ -32,7 +32,6 @@ func main() { engine.Use(ginutils.CheckReverseProxy, *sg) engine.Use(ginutils.CORSMiddleware()) - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) engine.GET("/", api.GetRoot) engine.GET("/status", api.GetStatus) engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) diff --git a/docs/docs.go b/docs/docs.go index 99b46c3c3..b3caf16d2 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -122,7 +122,7 @@ var doc = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/blockatlas.Webhook" + "$ref": "#/definitions/blockatlas.GUID" } }, { @@ -163,7 +163,7 @@ var doc = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/blockatlas.Webhook" + "$ref": "#/definitions/blockatlas.GUID" } }, { @@ -1603,7 +1603,7 @@ var doc = `{ "$ref": "#/definitions/blockatlas.Tx" } }, - "blockatlas.Webhook": { + "blockatlas.GUID": { "type": "object", "properties": { "subscriptions": { diff --git a/mq/mq.go b/mq/mq.go index 353822233..4aa00c6ff 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -2,6 +2,8 @@ package mq import ( "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/storage" ) var ( @@ -10,9 +12,15 @@ var ( queue amqp.Queue ) -type QueueName string +type ( + Queue string + Consumer func(amqp.Delivery, storage.Addresses) +) -const Notifications QueueName = "transactions" +const ( + Transactions Queue = "transactions" + Subscriptions Queue = "subscriptions" +) func Init(uri string) (err error) { conn, err = amqp.Dial(uri) @@ -23,7 +31,6 @@ func Init(uri string) (err error) { if err != nil { return } - queue, err = amqpChan.QueueDeclare(string(Notifications), true, false, false, false, nil) return } @@ -32,10 +39,35 @@ func Close() { conn.Close() } -func Publish(body []byte) error { - return amqpChan.Publish("", queue.Name, false, false, amqp.Publishing{ +func (q Queue) Declare() error { + _, err := amqpChan.QueueDeclare(string(q), true, false, false, false, nil) + return err +} + +func (q Queue) Publish(body []byte) error { + return amqpChan.Publish("", string(q), false, false, amqp.Publishing{ DeliveryMode: amqp.Persistent, ContentType: "text/plain", Body: body, }) } + +func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { + messageChannel, err := amqpChan.Consume( + string(q), + "", + false, + false, + false, + false, + nil, + ) + if err != nil { + logger.Error(err) + return + } + + for data := range messageChannel { + consumer(data, cache) + } +} diff --git a/observer/dispatcher.go b/observer/dispatcher.go index 397073be3..e68c40a11 100644 --- a/observer/dispatcher.go +++ b/observer/dispatcher.go @@ -51,7 +51,7 @@ func (d *Dispatcher) dispatch(event Event) { } func (d *Dispatcher) postMessageToQueue(message string, rawMessage []byte, logParams logger.Params) { - err := mq.Publish(rawMessage) + err := mq.Transactions.Publish(rawMessage) if err != nil { err = errors.E(err, "Failed to dispatch event", errors.Params{"message": message}, logParams) logger.Error(err, logger.Params{"message": message}, logParams) diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go index f46cc1120..abb1f1f9c 100644 --- a/pkg/blockatlas/observer.go +++ b/pkg/blockatlas/observer.go @@ -4,9 +4,12 @@ import "strconv" type Subscriptions map[string][]string -type Webhook struct { - Subscriptions Subscriptions `json:"subscriptions"` - Webhook string `json:"webhook"` +type SubscriptionOperation string + +type SubscriptionEvent struct { + Subscriptions Subscriptions `json:"subscriptions"` + GUID string `json:"guid"` + Operation SubscriptionOperation `json:"operation"` } type CoinStatus struct { @@ -19,9 +22,9 @@ type Observer struct { Message string `json:"message"` } -func (w *Webhook) ParseSubscriptions() []Subscription { +func (e *SubscriptionEvent) ParseSubscriptions() []Subscription { subs := make([]Subscription, 0) - for coinStr, perCoin := range w.Subscriptions { + for coinStr, perCoin := range e.Subscriptions { coin, err := strconv.Atoi(coinStr) if err != nil { continue @@ -30,7 +33,7 @@ func (w *Webhook) ParseSubscriptions() []Subscription { subs = append(subs, Subscription{ Coin: uint(coin), Address: addr, - Webhook: w.Webhook, + Webhook: e.GUID, }) } } diff --git a/pkg/blockatlas/observer_test.go b/pkg/blockatlas/observer_test.go index 00d73b21f..7d488c138 100644 --- a/pkg/blockatlas/observer_test.go +++ b/pkg/blockatlas/observer_test.go @@ -9,13 +9,13 @@ import ( func Test_parseSubscriptions(t *testing.T) { tests := []struct { name string - subscriptions Webhook + subscriptions SubscriptionEvent wantSubs []Subscription }{ { name: "webhook with 1 coin", - subscriptions: Webhook{ - Webhook: "http://127.0.0.1:8080", + subscriptions: SubscriptionEvent{ + GUID: "http://127.0.0.1:8080", Subscriptions: Subscriptions{ "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, }, @@ -33,8 +33,8 @@ func Test_parseSubscriptions(t *testing.T) { }, { name: "webhook with 2 coins", - subscriptions: Webhook{ - Webhook: "http://127.0.0.1:8080", + subscriptions: SubscriptionEvent{ + GUID: "http://127.0.0.1:8080", Subscriptions: Subscriptions{ "2": {"zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc"}, "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, diff --git a/services/subscription/subscribtion.go b/services/subscription/subscribtion.go new file mode 100644 index 000000000..6f79d6c41 --- /dev/null +++ b/services/subscription/subscribtion.go @@ -0,0 +1,36 @@ +package subscription + +import ( + "encoding/json" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/storage" +) + +const ( + addSubscription blockatlas.SubscriptionOperation = "AddSubscription" + deleteSubscription blockatlas.SubscriptionOperation = "DeleteSubscription" +) + +func Consume(delivery amqp.Delivery, storage storage.Addresses) { + var event blockatlas.SubscriptionEvent + err := json.Unmarshal(delivery.Body, &event) + if err != nil { + logger.Fatal(err) + } + subscription := event.ParseSubscriptions() + + switch event.Operation { + case addSubscription: + err := storage.AddSubscriptions(subscription) + if err != nil { + logger.Fatal(err, logger.Params{"operation": event.Operation, "guid": event.GUID}) + } + case deleteSubscription: + err := storage.DeleteSubscriptions(nil) + if err != nil { + logger.Fatal(logger.Params{"operation": event.Operation, "guid": event.GUID}) + } + } +} diff --git a/services/subscription/subscription_test.go b/services/subscription/subscription_test.go new file mode 100644 index 000000000..a52d129bc --- /dev/null +++ b/services/subscription/subscription_test.go @@ -0,0 +1,32 @@ +package subscription + +import ( + "testing" +) + +func TestGetInterval(t *testing.T) { + //cache := storage.New() + //err := cache.Init("redis://localhost:6379") + //if err != nil { + // logger.Fatal(err) + //} + // + //var subscriptions = blockatlas.Subscriptions{ + // "2": {"COINADDRESS 0"}, + // "0": {"ADDRES 1", "aDDRESS 2"}, + //} + // + //var mockedData = blockatlas.SubscriptionEvent{ + // Subscriptions: subscriptions, + // GUID: "EXAMPLE", + // Operation: addSubscription, + //} + + // b, _ := json.Marshal(mockedData) + // + // //success := Consume(b, cache) + // if !success { + // t.Fatal() + // } + //} +} diff --git a/storage/addresses.go b/storage/addresses.go index 760bebc56..cc7e54ff6 100644 --- a/storage/addresses.go +++ b/storage/addresses.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" ) const ( @@ -30,11 +29,11 @@ func (s *Storage) Lookup(coin uint, addresses []string) ([]blockatlas.Subscripti return observers, nil } -func (s *Storage) AddSubscriptions(subscriptions []blockatlas.Subscription) { +func (s *Storage) AddSubscriptions(subscriptions []blockatlas.Subscription) error { for _, sub := range subscriptions { key := getSubscriptionKey(sub.Coin, sub.Address) var webhooks []string - _ = s.GetHMValue(ATLAS_OBSERVER, key, &webhooks) + s.GetHMValue(ATLAS_OBSERVER, key, &webhooks) if webhooks == nil { webhooks = make([]string, 0) } @@ -44,12 +43,13 @@ func (s *Storage) AddSubscriptions(subscriptions []blockatlas.Subscription) { webhooks = append(webhooks, sub.Webhook) err := s.AddHM(ATLAS_OBSERVER, key, webhooks) if err != nil { - logger.Error(err, "AddSubscriptions error", errors.Params{"webhooks": webhooks, "address": sub.Address, "coin": sub.Coin}) + return err } } + return nil } -func (s *Storage) DeleteSubscriptions(subscriptions []blockatlas.Subscription) { +func (s *Storage) DeleteSubscriptions(subscriptions []blockatlas.Subscription) error { for _, sub := range subscriptions { key := getSubscriptionKey(sub.Coin, sub.Address) var webhooks []string @@ -69,10 +69,9 @@ func (s *Storage) DeleteSubscriptions(subscriptions []blockatlas.Subscription) { continue } err = s.AddHM(ATLAS_OBSERVER, key, newHooks) - if err != nil { - logger.Error(err, "DeleteSubscriptions - AddHM", errors.Params{"webhook": newHooks, "address": sub.Address, "coin": sub.Coin}) - } + return err } + return nil } func getSubscriptionKey(coin uint, address string) string { diff --git a/storage/storage.go b/storage/storage.go index 40b8afd85..9182843a7 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -23,6 +23,6 @@ type Tracker interface { type Addresses interface { Lookup(coin uint, addresses []string) ([]blockatlas.Subscription, error) - AddSubscriptions(subscriptions []blockatlas.Subscription) - DeleteSubscriptions(subscriptions []blockatlas.Subscription) + AddSubscriptions(subscriptions []blockatlas.Subscription) error + DeleteSubscriptions(subscriptions []blockatlas.Subscription) error } From 3b1c3ccdb2eb1c7cccfe678e80fcf701d8297c83 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 1 Mar 2020 04:40:59 +0300 Subject: [PATCH 173/506] MQ observer: prepare for mq migration with multiple struct changes (#942) * MQ observer: Update swagger, multiple structures, readme, dispatcher, run linter * Update swagger --- README.md | 6 +- docs/docs.go | 376 ++++-------------- docs/swagger.json | 374 ++++------------- docs/swagger.yaml | 265 +++--------- observer/dispatcher.go | 22 +- pkg/blockatlas/block.go | 2 +- pkg/blockatlas/observer.go | 2 +- pkg/blockatlas/observer_test.go | 14 +- platform/cosmos/model.go | 4 +- platform/cosmos/transaction.go | 2 +- services/subscription/subscribtion.go | 8 +- storage/addresses.go | 32 +- .../Blockatlas.postman_collection.json | 210 +--------- tests/postman/observer_data.json | 72 ---- 14 files changed, 241 insertions(+), 1148 deletions(-) delete mode 100644 tests/postman/observer_data.json diff --git a/README.md b/README.md index 1a1eab1b1..1d772630e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ BlockAtlas connects to nodes or explorer APIs of the supported coins and maps tr account transaction history into a generic, easy to work with JSON format. It is in production use at the [Trust Wallet app](https://trustwallet.com/), the official cryptocurrency wallet of Binance. Also is in production at the [BUTTON Wallet](https://buttonwallet.com), Telegram based non-custodial wallet. -The observer API watches the chain for new transactions and generates notifications by webhooks. +The observer API watches the chain for new transactions and generates notifications by guids. #### Supported Coins @@ -51,12 +51,12 @@ The observer API watches the chain for new transactions and generates notificati There are multiple services: 1. Platform API - to get transactions, staking, tokens, domain lookup for supported coins in common format -2. Observer API - to subscribe several addresses on different supported coins and receive webhook +2. Observer API - to subscribe several addresses on different supported coins and receive message 3. Swagger API - swagger for all handlers of 1-3 APIs. You need to route requests to them on you own (nginx) There are workers that are linked with Observer API and Market API: -5. Platform Observer - fetching latest blocks, parse them to common block specification, check subscribed addresses - send webhook. We use Redis to get information about subscribed addresses per coin with webhooks and caching latest block that was processed by observer +5. Platform Observer - fetching latest blocks, parse them to common block specification, check subscribed addresses - send message to queue. We use Redis to get information about subscribed addresses per coin with webhooks and caching latest block that was processed by observer Observer API <-> Redis <-> Platform Observer diff --git a/docs/docs.go b/docs/docs.go index b3caf16d2..247a2732c 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-26 03:37:11.056244 +0300 MSK m=+0.121112696 +// 2020-03-01 04:39:26.356879 +0300 MSK m=+1.896562991 package docs @@ -67,124 +67,6 @@ var doc = `{ } } }, - "/observer/v1/status": { - "get": { - "description": "Get coin status", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Observer" - ], - "summary": "Get coin status", - "operationId": "coin_status", - "parameters": [ - { - "type": "string", - "default": "Bearer test", - "description": "Bearer authorization header", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.CoinStatus" - } - } - } - } - }, - "/observer/v1/webhook/register": { - "post": { - "description": "Create a webhook for addresses transactions", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Observer" - ], - "summary": "Create a webhook", - "operationId": "create_webhook", - "parameters": [ - { - "description": "Accounts subscriptions", - "name": "subscriptions", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/blockatlas.GUID" - } - }, - { - "type": "string", - "default": "Bearer test", - "description": "Bearer authorization header", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.Observer" - } - } - } - }, - "delete": { - "description": "Delete a webhook for addresses transactions", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Observer" - ], - "summary": "Delete a webhook", - "operationId": "delete_webhook", - "parameters": [ - { - "description": "Accounts subscriptions", - "name": "subscriptions", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/blockatlas.GUID" - } - }, - { - "type": "string", - "default": "Bearer test", - "description": "Bearer authorization header", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.Observer" - } - } - } - } - }, "/v1/market/charts": { "get": { "description": "Get the charts data from an market and coin/token", @@ -240,7 +122,7 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.ChartData" + "$ref": "#/definitions/watchmarket.ChartData" } } } @@ -294,7 +176,7 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.ChartCoinInfo" + "$ref": "#/definitions/watchmarket.ChartCoinInfo" } } } @@ -329,7 +211,7 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.Tickers" + "$ref": "#/definitions/api.Tickers" } } } @@ -1123,113 +1005,68 @@ var doc = `{ } } }, - "api.TickerRequest": { + "api.Ticker": { "type": "object", "properties": { - "assets": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Coin" - } + "coin": { + "type": "integer" }, - "currency": { + "coin_name": { "type": "string" - } - } - }, - "blockatlas.ChartCoinInfo": { - "type": "object", - "properties": { - "circulating_supply": { - "type": "number" }, - "info": { - "type": "object", - "$ref": "#/definitions/blockatlas.CoinInfo" + "error": { + "type": "string" }, - "market_cap": { - "type": "number" + "last_update": { + "type": "string" }, - "total_supply": { - "type": "number" + "price": { + "type": "object", + "$ref": "#/definitions/api.TickerPrice" }, - "volume_24": { - "type": "number" - } - } - }, - "blockatlas.ChartData": { - "type": "object", - "properties": { - "error": { + "token_id": { "type": "string" }, - "prices": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.ChartPrice" - } + "type": { + "type": "string" } } }, - "blockatlas.ChartPrice": { + "api.TickerPrice": { "type": "object", "properties": { - "date": { - "type": "integer" + "change_24h": { + "type": "number" }, - "price": { + "currency": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "value": { "type": "number" } } }, - "blockatlas.CoinInfo": { + "api.TickerRequest": { "type": "object", "properties": { - "data_source": { - "type": "string" - }, - "description": { - "type": "string" - }, - "explorers": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Link" - } - }, - "name": { - "type": "string" - }, - "short_description": { - "type": "string" - }, - "socials": { + "assets": { "type": "array", "items": { - "$ref": "#/definitions/blockatlas.SocialLink" + "$ref": "#/definitions/api.Coin" } }, - "source_code": { - "type": "string" - }, - "website": { - "type": "string" - }, - "white_paper": { + "currency": { "type": "string" } } }, - "blockatlas.CoinStatus": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "height": { - "type": "integer" - } + "api.Tickers": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Ticker" } }, "blockatlas.Collection": { @@ -1344,28 +1181,6 @@ var doc = `{ } } }, - "blockatlas.Link": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "url": { - "type": "string" - } - } - }, - "blockatlas.Observer": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "status": { - "type": "boolean" - } - } - }, "blockatlas.Resolved": { "type": "object", "properties": { @@ -1377,20 +1192,6 @@ var doc = `{ } } }, - "blockatlas.SocialLink": { - "type": "object", - "properties": { - "handle": { - "type": "string" - }, - "name": { - "type": "string" - }, - "url": { - "type": "string" - } - } - }, "blockatlas.StakeValidator": { "type": "object", "properties": { @@ -1453,65 +1254,6 @@ var doc = `{ } } }, - "blockatlas.Subscriptions": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "blockatlas.Ticker": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "coin_name": { - "type": "string" - }, - "error": { - "type": "string" - }, - "last_update": { - "type": "string" - }, - "price": { - "type": "object", - "$ref": "#/definitions/blockatlas.TickerPrice" - }, - "token_id": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "blockatlas.TickerPrice": { - "type": "object", - "properties": { - "change_24h": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "provider": { - "type": "string" - }, - "value": { - "type": "number" - } - } - }, - "blockatlas.Tickers": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Ticker" - } - }, "blockatlas.Tx": { "type": "object", "properties": { @@ -1603,18 +1345,6 @@ var doc = `{ "$ref": "#/definitions/blockatlas.Tx" } }, - "blockatlas.GUID": { - "type": "object", - "properties": { - "subscriptions": { - "type": "object", - "$ref": "#/definitions/blockatlas.Subscriptions" - }, - "webhook": { - "type": "string" - } - } - }, "coin.ExternalCoin": { "type": "object", "properties": { @@ -1642,6 +1372,40 @@ var doc = `{ "type": "string" } } + }, + "watchmarket.ChartCoinInfo": { + "type": "object", + "properties": { + "circulating_supply": { + "type": "number" + }, + "info": { + "type": "CoinInfo" + }, + "market_cap": { + "type": "number" + }, + "total_supply": { + "type": "number" + }, + "volume_24": { + "type": "number" + } + } + }, + "watchmarket.ChartData": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "prices": { + "type": "array", + "items": { + "type": "ChartPrice" + } + } + } } } }` diff --git a/docs/swagger.json b/docs/swagger.json index e34832650..dc8104ce2 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -46,124 +46,6 @@ } } }, - "/observer/v1/status": { - "get": { - "description": "Get coin status", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Observer" - ], - "summary": "Get coin status", - "operationId": "coin_status", - "parameters": [ - { - "type": "string", - "default": "Bearer test", - "description": "Bearer authorization header", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.CoinStatus" - } - } - } - } - }, - "/observer/v1/webhook/register": { - "post": { - "description": "Create a webhook for addresses transactions", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Observer" - ], - "summary": "Create a webhook", - "operationId": "create_webhook", - "parameters": [ - { - "description": "Accounts subscriptions", - "name": "subscriptions", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/blockatlas.Webhook" - } - }, - { - "type": "string", - "default": "Bearer test", - "description": "Bearer authorization header", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.Observer" - } - } - } - }, - "delete": { - "description": "Delete a webhook for addresses transactions", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Observer" - ], - "summary": "Delete a webhook", - "operationId": "delete_webhook", - "parameters": [ - { - "description": "Accounts subscriptions", - "name": "subscriptions", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/blockatlas.Webhook" - } - }, - { - "type": "string", - "default": "Bearer test", - "description": "Bearer authorization header", - "name": "Authorization", - "in": "header", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.Observer" - } - } - } - } - }, "/v1/market/charts": { "get": { "description": "Get the charts data from an market and coin/token", @@ -219,7 +101,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.ChartData" + "$ref": "#/definitions/watchmarket.ChartData" } } } @@ -273,7 +155,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.ChartCoinInfo" + "$ref": "#/definitions/watchmarket.ChartCoinInfo" } } } @@ -308,7 +190,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.Tickers" + "$ref": "#/definitions/api.Tickers" } } } @@ -1102,113 +984,68 @@ } } }, - "api.TickerRequest": { + "api.Ticker": { "type": "object", "properties": { - "assets": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Coin" - } + "coin": { + "type": "integer" }, - "currency": { + "coin_name": { "type": "string" - } - } - }, - "blockatlas.ChartCoinInfo": { - "type": "object", - "properties": { - "circulating_supply": { - "type": "number" }, - "info": { - "type": "object", - "$ref": "#/definitions/blockatlas.CoinInfo" + "error": { + "type": "string" }, - "market_cap": { - "type": "number" + "last_update": { + "type": "string" }, - "total_supply": { - "type": "number" + "price": { + "type": "object", + "$ref": "#/definitions/api.TickerPrice" }, - "volume_24": { - "type": "number" - } - } - }, - "blockatlas.ChartData": { - "type": "object", - "properties": { - "error": { + "token_id": { "type": "string" }, - "prices": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.ChartPrice" - } + "type": { + "type": "string" } } }, - "blockatlas.ChartPrice": { + "api.TickerPrice": { "type": "object", "properties": { - "date": { - "type": "integer" + "change_24h": { + "type": "number" }, - "price": { + "currency": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "value": { "type": "number" } } }, - "blockatlas.CoinInfo": { + "api.TickerRequest": { "type": "object", "properties": { - "data_source": { - "type": "string" - }, - "description": { - "type": "string" - }, - "explorers": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Link" - } - }, - "name": { - "type": "string" - }, - "short_description": { - "type": "string" - }, - "socials": { + "assets": { "type": "array", "items": { - "$ref": "#/definitions/blockatlas.SocialLink" + "$ref": "#/definitions/api.Coin" } }, - "source_code": { - "type": "string" - }, - "website": { - "type": "string" - }, - "white_paper": { + "currency": { "type": "string" } } }, - "blockatlas.CoinStatus": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "height": { - "type": "integer" - } + "api.Tickers": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Ticker" } }, "blockatlas.Collection": { @@ -1323,28 +1160,6 @@ } } }, - "blockatlas.Link": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "url": { - "type": "string" - } - } - }, - "blockatlas.Observer": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "status": { - "type": "boolean" - } - } - }, "blockatlas.Resolved": { "type": "object", "properties": { @@ -1356,20 +1171,6 @@ } } }, - "blockatlas.SocialLink": { - "type": "object", - "properties": { - "handle": { - "type": "string" - }, - "name": { - "type": "string" - }, - "url": { - "type": "string" - } - } - }, "blockatlas.StakeValidator": { "type": "object", "properties": { @@ -1432,65 +1233,6 @@ } } }, - "blockatlas.Subscriptions": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "blockatlas.Ticker": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "coin_name": { - "type": "string" - }, - "error": { - "type": "string" - }, - "last_update": { - "type": "string" - }, - "price": { - "type": "object", - "$ref": "#/definitions/blockatlas.TickerPrice" - }, - "token_id": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "blockatlas.TickerPrice": { - "type": "object", - "properties": { - "change_24h": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "provider": { - "type": "string" - }, - "value": { - "type": "number" - } - } - }, - "blockatlas.Tickers": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Ticker" - } - }, "blockatlas.Tx": { "type": "object", "properties": { @@ -1582,18 +1324,6 @@ "$ref": "#/definitions/blockatlas.Tx" } }, - "blockatlas.Webhook": { - "type": "object", - "properties": { - "subscriptions": { - "type": "object", - "$ref": "#/definitions/blockatlas.Subscriptions" - }, - "webhook": { - "type": "string" - } - } - }, "coin.ExternalCoin": { "type": "object", "properties": { @@ -1621,6 +1351,40 @@ "type": "string" } } + }, + "watchmarket.ChartCoinInfo": { + "type": "object", + "properties": { + "circulating_supply": { + "type": "number" + }, + "info": { + "type": "CoinInfo" + }, + "market_cap": { + "type": "number" + }, + "total_supply": { + "type": "number" + }, + "volume_24": { + "type": "number" + } + } + }, + "watchmarket.ChartData": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "prices": { + "type": "array", + "items": { + "type": "ChartPrice" + } + } + } } } } \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 428a6fada..4ddb42cde 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -19,77 +19,48 @@ definitions: type: type: string type: object - api.TickerRequest: - properties: - assets: - items: - $ref: '#/definitions/api.Coin' - type: array - currency: - type: string - type: object - blockatlas.ChartCoinInfo: + api.Ticker: properties: - circulating_supply: - type: number - info: - $ref: '#/definitions/blockatlas.CoinInfo' - type: object - market_cap: - type: number - total_supply: - type: number - volume_24: - type: number - type: object - blockatlas.ChartData: - properties: - error: - type: string - prices: - items: - $ref: '#/definitions/blockatlas.ChartPrice' - type: array - type: object - blockatlas.ChartPrice: - properties: - date: + coin: type: integer - price: - type: number - type: object - blockatlas.CoinInfo: - properties: - data_source: + coin_name: type: string - description: + error: type: string - explorers: - items: - $ref: '#/definitions/blockatlas.Link' - type: array - name: + last_update: type: string - short_description: + price: + $ref: '#/definitions/api.TickerPrice' + type: object + token_id: type: string - socials: - items: - $ref: '#/definitions/blockatlas.SocialLink' - type: array - source_code: + type: type: string - website: + type: object + api.TickerPrice: + properties: + change_24h: + type: number + currency: type: string - white_paper: + provider: type: string + value: + type: number type: object - blockatlas.CoinStatus: + api.TickerRequest: properties: - error: + assets: + items: + $ref: '#/definitions/api.Coin' + type: array + currency: type: string - height: - type: integer type: object + api.Tickers: + items: + $ref: '#/definitions/api.Ticker' + type: array blockatlas.Collection: properties: address: @@ -165,20 +136,6 @@ definitions: docs: type: object type: object - blockatlas.Link: - properties: - name: - type: string - url: - type: string - type: object - blockatlas.Observer: - properties: - message: - type: string - status: - type: boolean - type: object blockatlas.Resolved: properties: coin: @@ -186,15 +143,6 @@ definitions: result: type: string type: object - blockatlas.SocialLink: - properties: - handle: - type: string - name: - type: string - url: - type: string - type: object blockatlas.StakeValidator: properties: details: @@ -236,45 +184,6 @@ definitions: annual: type: number type: object - blockatlas.Subscriptions: - additionalProperties: - items: - type: string - type: array - type: object - blockatlas.Ticker: - properties: - coin: - type: integer - coin_name: - type: string - error: - type: string - last_update: - type: string - price: - $ref: '#/definitions/blockatlas.TickerPrice' - type: object - token_id: - type: string - type: - type: string - type: object - blockatlas.TickerPrice: - properties: - change_24h: - type: number - currency: - type: string - provider: - type: string - value: - type: number - type: object - blockatlas.Tickers: - items: - $ref: '#/definitions/blockatlas.Ticker' - type: array blockatlas.Tx: properties: block: @@ -342,14 +251,6 @@ definitions: items: $ref: '#/definitions/blockatlas.Tx' type: array - blockatlas.Webhook: - properties: - subscriptions: - $ref: '#/definitions/blockatlas.Subscriptions' - type: object - webhook: - type: string - type: object coin.ExternalCoin: properties: coin: @@ -368,6 +269,28 @@ definitions: status_message: type: string type: object + watchmarket.ChartCoinInfo: + properties: + circulating_supply: + type: number + info: + type: CoinInfo + market_cap: + type: number + total_supply: + type: number + volume_24: + type: number + type: object + watchmarket.ChartData: + properties: + error: + type: string + prices: + items: + type: ChartPrice + type: array + type: object info: contact: {} license: {} @@ -399,86 +322,6 @@ paths: summary: Lookup .eth / .zil addresses tags: - Naming - /observer/v1/status: - get: - consumes: - - application/json - description: Get coin status - operationId: coin_status - parameters: - - default: Bearer test - description: Bearer authorization header - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.CoinStatus' - summary: Get coin status - tags: - - Observer - /observer/v1/webhook/register: - delete: - consumes: - - application/json - description: Delete a webhook for addresses transactions - operationId: delete_webhook - parameters: - - description: Accounts subscriptions - in: body - name: subscriptions - required: true - schema: - $ref: '#/definitions/blockatlas.Webhook' - - default: Bearer test - description: Bearer authorization header - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.Observer' - summary: Delete a webhook - tags: - - Observer - post: - consumes: - - application/json - description: Create a webhook for addresses transactions - operationId: create_webhook - parameters: - - description: Accounts subscriptions - in: body - name: subscriptions - required: true - schema: - $ref: '#/definitions/blockatlas.Webhook' - - default: Bearer test - description: Bearer authorization header - in: header - name: Authorization - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.Observer' - summary: Create a webhook - tags: - - Observer /v1/{coin}/{address}: get: consumes: @@ -575,7 +418,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/blockatlas.ChartData' + $ref: '#/definitions/watchmarket.ChartData' summary: Get charts data for a specific coin tags: - Market @@ -612,7 +455,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/blockatlas.ChartCoinInfo' + $ref: '#/definitions/watchmarket.ChartCoinInfo' summary: Get charts coin info data for a specific coin tags: - Market @@ -635,7 +478,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/blockatlas.Tickers' + $ref: '#/definitions/api.Tickers' summary: Get ticker values for a specific market tags: - Market diff --git a/observer/dispatcher.go b/observer/dispatcher.go index e68c40a11..1e11e67b8 100644 --- a/observer/dispatcher.go +++ b/observer/dispatcher.go @@ -14,9 +14,9 @@ type Dispatcher struct { } type DispatchEvent struct { - Action blockatlas.TransactionType `json:"action"` - Result *blockatlas.Tx `json:"result"` - Webhook string `json:"webhook"` + Action blockatlas.TransactionType `json:"action"` + Result *blockatlas.Tx `json:"result"` + GUID string `json:"guid"` } func (d *Dispatcher) Run(events <-chan Event) { @@ -26,12 +26,12 @@ func (d *Dispatcher) Run(events <-chan Event) { } func (d *Dispatcher) dispatch(event Event) { - webhook := event.Subscription.Webhook + guid := event.Subscription.GUID action := DispatchEvent{ - Action: event.Tx.Type, - Result: event.Tx, - Webhook: webhook, + Action: event.Tx.Type, + Result: event.Tx, + GUID: guid, } txJson, err := json.Marshal(action) @@ -40,12 +40,12 @@ func (d *Dispatcher) dispatch(event Event) { } logParams := logger.Params{ - "webhook": webhook, - "coin": event.Subscription.Coin, - "txID": event.Tx.ID, + "guid": guid, + "coin": event.Subscription.Coin, + "txID": event.Tx.ID, } - go d.postMessageToQueue(webhook, txJson, logParams) + go d.postMessageToQueue(guid, txJson, logParams) logger.Info("Dispatching messages...", logParams) } diff --git a/pkg/blockatlas/block.go b/pkg/blockatlas/block.go index e11e8e2d3..14e54f03a 100644 --- a/pkg/blockatlas/block.go +++ b/pkg/blockatlas/block.go @@ -9,5 +9,5 @@ type Block struct { type Subscription struct { Coin uint `json:"coin"` Address string `json:"address"` - Webhook string `json:"webhook"` + GUID string `json:"guid"` } diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go index abb1f1f9c..dc5909cc8 100644 --- a/pkg/blockatlas/observer.go +++ b/pkg/blockatlas/observer.go @@ -33,7 +33,7 @@ func (e *SubscriptionEvent) ParseSubscriptions() []Subscription { subs = append(subs, Subscription{ Coin: uint(coin), Address: addr, - Webhook: e.GUID, + GUID: e.GUID, }) } } diff --git a/pkg/blockatlas/observer_test.go b/pkg/blockatlas/observer_test.go index 7d488c138..bd56ef656 100644 --- a/pkg/blockatlas/observer_test.go +++ b/pkg/blockatlas/observer_test.go @@ -13,7 +13,7 @@ func Test_parseSubscriptions(t *testing.T) { wantSubs []Subscription }{ { - name: "webhook with 1 coin", + name: "guid with 1 coin", subscriptions: SubscriptionEvent{ GUID: "http://127.0.0.1:8080", Subscriptions: Subscriptions{ @@ -22,17 +22,17 @@ func Test_parseSubscriptions(t *testing.T) { }, wantSubs: []Subscription{ { - Coin: 0, Webhook: "http://127.0.0.1:8080", + Coin: 0, GUID: "http://127.0.0.1:8080", Address: "xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", }, { - Coin: 0, Webhook: "http://127.0.0.1:8080", + Coin: 0, GUID: "http://127.0.0.1:8080", Address: "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL", }, }, }, { - name: "webhook with 2 coins", + name: "guid with 2 coins", subscriptions: SubscriptionEvent{ GUID: "http://127.0.0.1:8080", Subscriptions: Subscriptions{ @@ -42,15 +42,15 @@ func Test_parseSubscriptions(t *testing.T) { }, wantSubs: []Subscription{ { - Coin: 2, Webhook: "http://127.0.0.1:8080", + Coin: 2, GUID: "http://127.0.0.1:8080", Address: "zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc", }, { - Coin: 0, Webhook: "http://127.0.0.1:8080", + Coin: 0, GUID: "http://127.0.0.1:8080", Address: "xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", }, { - Coin: 0, Webhook: "http://127.0.0.1:8080", + Coin: 0, GUID: "http://127.0.0.1:8080", Address: "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL", }, }, diff --git a/platform/cosmos/model.go b/platform/cosmos/model.go index 9280c75c7..c9b1e6ec9 100644 --- a/platform/cosmos/model.go +++ b/platform/cosmos/model.go @@ -48,8 +48,8 @@ type Tx struct { } type TxPage struct { - PageTotal string `json:"page_total"` - Txs []Tx `json:"txs"` + PageTotal string `json:"page_total"` + Txs []Tx `json:"txs"` } // Events diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 3fac2e2e3..3051e7c3d 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -17,7 +17,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { for _, t := range tagsList { go func(tag, addr string, wg *sync.WaitGroup) { defer wg.Done() - page := 1 + page := 1 txs, err := p.client.GetAddrTxs(addr, tag, page) if err != nil { logger.Error("GetAddrTxs", err, logger.Params{"address": tag, "tag": tag}) diff --git a/services/subscription/subscribtion.go b/services/subscription/subscribtion.go index 6f79d6c41..37ac3b37e 100644 --- a/services/subscription/subscribtion.go +++ b/services/subscription/subscribtion.go @@ -19,18 +19,20 @@ func Consume(delivery amqp.Delivery, storage storage.Addresses) { if err != nil { logger.Fatal(err) } - subscription := event.ParseSubscriptions() + subscriptions := event.ParseSubscriptions() switch event.Operation { case addSubscription: - err := storage.AddSubscriptions(subscription) + err := storage.AddSubscriptions(subscriptions) if err != nil { logger.Fatal(err, logger.Params{"operation": event.Operation, "guid": event.GUID}) } + logger.Info("Success", logger.Params{"operation": event.Operation, "guid": event.GUID, "subscriptions_len": len(subscriptions)}) case deleteSubscription: err := storage.DeleteSubscriptions(nil) if err != nil { - logger.Fatal(logger.Params{"operation": event.Operation, "guid": event.GUID}) + logger.Fatal(err, logger.Params{"operation": event.Operation, "guid": event.GUID}) } + logger.Info("Success", logger.Params{"operation": event.Operation, "guid": event.GUID, "subscriptions_len": len(subscriptions)}) } } diff --git a/storage/addresses.go b/storage/addresses.go index cc7e54ff6..c4b6238bb 100644 --- a/storage/addresses.go +++ b/storage/addresses.go @@ -17,13 +17,13 @@ func (s *Storage) Lookup(coin uint, addresses []string) ([]blockatlas.Subscripti observers := make([]blockatlas.Subscription, 0) for _, address := range addresses { key := getSubscriptionKey(coin, address) - var webhooks []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &webhooks) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) if err != nil { continue } - for _, webhook := range webhooks { - observers = append(observers, blockatlas.Subscription{Coin: coin, Address: address, Webhook: webhook}) + for _, guid := range guids { + observers = append(observers, blockatlas.Subscription{Coin: coin, Address: address, GUID: guid}) } } return observers, nil @@ -32,16 +32,16 @@ func (s *Storage) Lookup(coin uint, addresses []string) ([]blockatlas.Subscripti func (s *Storage) AddSubscriptions(subscriptions []blockatlas.Subscription) error { for _, sub := range subscriptions { key := getSubscriptionKey(sub.Coin, sub.Address) - var webhooks []string - s.GetHMValue(ATLAS_OBSERVER, key, &webhooks) - if webhooks == nil { - webhooks = make([]string, 0) + var guids []string + s.GetHMValue(ATLAS_OBSERVER, key, &guids) + if guids == nil { + guids = make([]string, 0) } - if hasObject(webhooks, sub.Webhook) { + if hasObject(guids, sub.GUID) { continue } - webhooks = append(webhooks, sub.Webhook) - err := s.AddHM(ATLAS_OBSERVER, key, webhooks) + guids = append(guids, sub.GUID) + err := s.AddHM(ATLAS_OBSERVER, key, guids) if err != nil { return err } @@ -52,17 +52,17 @@ func (s *Storage) AddSubscriptions(subscriptions []blockatlas.Subscription) erro func (s *Storage) DeleteSubscriptions(subscriptions []blockatlas.Subscription) error { for _, sub := range subscriptions { key := getSubscriptionKey(sub.Coin, sub.Address) - var webhooks []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &webhooks) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) if err != nil { continue } newHooks := make([]string, 0) - for _, webhook := range webhooks { - if webhook == sub.Webhook { + for _, guid := range guids { + if guid == sub.GUID { continue } - newHooks = append(newHooks, webhook) + newHooks = append(newHooks, guid) } if len(newHooks) == 0 { _ = s.DeleteHM(ATLAS_OBSERVER, key) diff --git a/tests/postman/Blockatlas.postman_collection.json b/tests/postman/Blockatlas.postman_collection.json index 383850db7..a0b5f819b 100644 --- a/tests/postman/Blockatlas.postman_collection.json +++ b/tests/postman/Blockatlas.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "63af4255-85a1-4505-87cb-13f8de0453af", + "_postman_id": "60e7e382-2f40-487f-a291-3e62daadadd8", "name": "Blockatlas", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -2380,214 +2380,6 @@ ], "protocolProfileBehavior": {} }, - { - "name": "observer", - "item": [ - { - "name": "add", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "7312c9e7-5330-421a-9ca8-171101050e38", - "exec": [ - "", - "var body = {\"subscriptions\": {}, \"webhook\": \"\"}", - "", - "let subscriptions = pm.variables.get(\"subscriptions\");", - "let webhook = pm.variables.get(\"webhook\");", - "", - "body[\"subscriptions\"] = subscriptions", - "body[\"webhook\"] = webhook", - "", - "pm.environment.set(\"request_body\", JSON.stringify(body));", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "acec8baa-0ef0-4703-ab83-c555260deffa", - "exec": [ - "let result = {", - " \"status\": true,", - " \"message\": \"Added\"", - "};", - "var jsonData = pm.response.json();", - "", - "pm.test(\"response must be valid and have a body\", function () {", - " pm.response.to.have.status(200);", - " pm.response.to.be.ok;", - " pm.response.to.not.be.error;", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "", - "pm.test(\"response is valid\", function() {", - " pm.expect(jsonData).to.eql(result);", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{observer_auth}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/json", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{{request_body}}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{host}}/observer/v1/webhook/register", - "host": [ - "{{host}}" - ], - "path": [ - "observer", - "v1", - "webhook", - "register" - ] - } - }, - "response": [] - }, - { - "name": "delete", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "7312c9e7-5330-421a-9ca8-171101050e38", - "exec": [ - "", - "var body = {\"subscriptions\": {}, \"webhook\": \"\"}", - "", - "let subscriptions = pm.variables.get(\"subscriptions\");", - "let webhook = pm.variables.get(\"webhook\");", - "", - "body[\"subscriptions\"] = subscriptions", - "body[\"webhook\"] = webhook", - "", - "pm.environment.set(\"request_body\", JSON.stringify(body));", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "acec8baa-0ef0-4703-ab83-c555260deffa", - "exec": [ - "let result = {", - " \"status\": true,", - " \"message\": \"Deleted\"", - "};", - "var jsonData = pm.response.json();", - "", - "pm.test(\"response must be valid and have a body\", function () {", - " pm.response.to.have.status(200);", - " pm.response.to.be.ok;", - " pm.response.to.not.be.error;", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "", - "pm.test(\"response is valid\", function() {", - " pm.expect(jsonData).to.eql(result);", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "DELETE", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{observer_auth}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{{request_body}}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{host}}/observer/v1/webhook/register", - "host": [ - "{{host}}" - ], - "path": [ - "observer", - "v1", - "webhook", - "register" - ] - } - }, - "response": [] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "id": "50b8bc65-9acc-4652-8ac7-722f45767478", - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "id": "88a2b78a-643e-449b-9ec0-f7c7a62ad50a", - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ], - "protocolProfileBehavior": {} - }, { "name": "healthcheck", "item": [ diff --git a/tests/postman/observer_data.json b/tests/postman/observer_data.json deleted file mode 100644 index 9c5394ee0..000000000 --- a/tests/postman/observer_data.json +++ /dev/null @@ -1,72 +0,0 @@ -[ - { - "subscriptions": { - "0": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "2": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "60": [ - "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" - ], - "459": [ - "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - ], - "714": [ - "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" - ] - }, - "webhook": "http://localhost" - }, - { - "subscriptions": { - "0": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "2": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "60": [ - "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" - ], - "459": [ - "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - ] - }, - "webhook": "http://localhost" - }, - { - "subscriptions": { - "0": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "2": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "60": [ - "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" - ] - }, - "webhook": "http://localhost" - }, - { - "subscriptions": { - "0": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "2": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ] - }, - "webhook": "http://localhost" - }, - { - "subscriptions": { - "0": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ] - }, - "webhook": "http://localhost" - } -] \ No newline at end of file From 13483f780d20fa5881a7dc31398d87c26634105f Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 1 Mar 2020 04:59:58 +0300 Subject: [PATCH 174/506] Update subscribtion.go --- services/subscription/subscribtion.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/subscription/subscribtion.go b/services/subscription/subscribtion.go index 37ac3b37e..28715118a 100644 --- a/services/subscription/subscribtion.go +++ b/services/subscription/subscribtion.go @@ -9,8 +9,8 @@ import ( ) const ( - addSubscription blockatlas.SubscriptionOperation = "AddSubscription" - deleteSubscription blockatlas.SubscriptionOperation = "DeleteSubscription" + AddSubscription blockatlas.SubscriptionOperation = "AddSubscription" + DeleteSubscription blockatlas.SubscriptionOperation = "DeleteSubscription" ) func Consume(delivery amqp.Delivery, storage storage.Addresses) { @@ -22,13 +22,13 @@ func Consume(delivery amqp.Delivery, storage storage.Addresses) { subscriptions := event.ParseSubscriptions() switch event.Operation { - case addSubscription: + case AddSubscription: err := storage.AddSubscriptions(subscriptions) if err != nil { logger.Fatal(err, logger.Params{"operation": event.Operation, "guid": event.GUID}) } logger.Info("Success", logger.Params{"operation": event.Operation, "guid": event.GUID, "subscriptions_len": len(subscriptions)}) - case deleteSubscription: + case DeleteSubscription: err := storage.DeleteSubscriptions(nil) if err != nil { logger.Fatal(err, logger.Params{"operation": event.Operation, "guid": event.GUID}) From 94ce25c5274394139328cc6310a9f33456c41965 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 1 Mar 2020 06:02:07 +0300 Subject: [PATCH 175/506] Update: consumer logic, nginx, compose Add: update event, Ack (#943) --- cmd/observer_subscriber/main.go | 2 -- docker-compose.yml | 31 +++++++++++---------- nginx.conf | 6 +---- pkg/blockatlas/observer.go | 11 ++++---- pkg/blockatlas/observer_test.go | 6 ++--- services/subscription/subscribtion.go | 39 ++++++++++++++++++++++----- 6 files changed, 57 insertions(+), 38 deletions(-) diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index 7e32970b6..4b93f9119 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -7,7 +7,6 @@ import ( "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/subscription" "github.com/trustwallet/blockatlas/storage" ) @@ -35,7 +34,6 @@ func init() { logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) } - platform.Init(viper.GetString("platform")) } func main() { diff --git a/docker-compose.yml b/docker-compose.yml index 915d7461d..cae42ded5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,18 +11,6 @@ services: - observer_api - platform_api - swagger_api - - observer_api: - container_name: observer_api - build: - context: . - args: - - SERVICE=observer_api - ports: - - 8422:8422 - links: - - redis - restart: on-failure platform_api: container_name: platform_api @@ -31,7 +19,7 @@ services: args: - SERVICE=platform_api ports: - - 8420:8420 + - 8420:8420 swagger_api: container_name: swagger_api @@ -42,11 +30,22 @@ services: ports: - 8423:8423 - platform_observer: + observer_worker: + build: + context: . + args: + - SERVICE=observer_worker + links: + - redis + - rabbit + restart: on-failure + + observer_subscriber: + container_name: observer_subscriber build: context: . args: - - SERVICE=platform_observer + - SERVICE=observer_subscriber links: - redis - rabbit @@ -67,4 +66,4 @@ services: container_name: redis image: redis ports: - - 6379:6379 + - 6379:6379 diff --git a/nginx.conf b/nginx.conf index 77b5be96a..8fd11f920 100644 --- a/nginx.conf +++ b/nginx.conf @@ -5,11 +5,7 @@ server { proxy_pass http://swagger_api:8423; } - location ~* /observer.* { - proxy_pass http://observer_api:8422; - } - location / { proxy_pass http://platform_api:8420; } -} \ No newline at end of file +} diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go index dc5909cc8..7b7e79ed9 100644 --- a/pkg/blockatlas/observer.go +++ b/pkg/blockatlas/observer.go @@ -7,9 +7,10 @@ type Subscriptions map[string][]string type SubscriptionOperation string type SubscriptionEvent struct { - Subscriptions Subscriptions `json:"subscriptions"` - GUID string `json:"guid"` - Operation SubscriptionOperation `json:"operation"` + NewSubscriptions Subscriptions `json:"new_subscriptions"` + OldSubscriptions Subscriptions `json:"old_subscriptions"` + GUID string `json:"guid"` + Operation SubscriptionOperation `json:"operation"` } type CoinStatus struct { @@ -22,9 +23,9 @@ type Observer struct { Message string `json:"message"` } -func (e *SubscriptionEvent) ParseSubscriptions() []Subscription { +func (e *SubscriptionEvent) ParseSubscriptions(s Subscriptions) []Subscription { subs := make([]Subscription, 0) - for coinStr, perCoin := range e.Subscriptions { + for coinStr, perCoin := range s { coin, err := strconv.Atoi(coinStr) if err != nil { continue diff --git a/pkg/blockatlas/observer_test.go b/pkg/blockatlas/observer_test.go index bd56ef656..1f80e0eac 100644 --- a/pkg/blockatlas/observer_test.go +++ b/pkg/blockatlas/observer_test.go @@ -16,7 +16,7 @@ func Test_parseSubscriptions(t *testing.T) { name: "guid with 1 coin", subscriptions: SubscriptionEvent{ GUID: "http://127.0.0.1:8080", - Subscriptions: Subscriptions{ + OldSubscriptions: Subscriptions{ "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, }, }, @@ -35,7 +35,7 @@ func Test_parseSubscriptions(t *testing.T) { name: "guid with 2 coins", subscriptions: SubscriptionEvent{ GUID: "http://127.0.0.1:8080", - Subscriptions: Subscriptions{ + OldSubscriptions: Subscriptions{ "2": {"zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc"}, "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, }, @@ -58,7 +58,7 @@ func Test_parseSubscriptions(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotSubs := tt.subscriptions.ParseSubscriptions() + gotSubs := tt.subscriptions.ParseSubscriptions(tt.subscriptions.OldSubscriptions) sort.Slice(gotSubs, func(i, j int) bool { return gotSubs[i].Coin > gotSubs[j].Coin }) diff --git a/services/subscription/subscribtion.go b/services/subscription/subscribtion.go index 28715118a..518875b89 100644 --- a/services/subscription/subscribtion.go +++ b/services/subscription/subscribtion.go @@ -11,6 +11,7 @@ import ( const ( AddSubscription blockatlas.SubscriptionOperation = "AddSubscription" DeleteSubscription blockatlas.SubscriptionOperation = "DeleteSubscription" + UpdateSubscription blockatlas.SubscriptionOperation = "UpdateSubscription" ) func Consume(delivery amqp.Delivery, storage storage.Addresses) { @@ -19,20 +20,44 @@ func Consume(delivery amqp.Delivery, storage storage.Addresses) { if err != nil { logger.Fatal(err) } - subscriptions := event.ParseSubscriptions() + newSubscriptions := event.ParseSubscriptions(event.NewSubscriptions) + oldSubscriptions := event.ParseSubscriptions(event.OldSubscriptions) + params := logger.Params{"operation": event.Operation, "guid": event.GUID, "new_subscriptions_len": len(newSubscriptions), "old_subscriptions_len": len(oldSubscriptions)} switch event.Operation { + case UpdateSubscription: + err := storage.DeleteSubscriptions(oldSubscriptions) + if err != nil { + logger.Error(err, params) + } + err = storage.AddSubscriptions(newSubscriptions) + if err != nil { + logger.Error(err, params) + } + err = delivery.Ack(false) + if err != nil { + logger.Error(err, params) + } + logger.Info("Updated", params) case AddSubscription: - err := storage.AddSubscriptions(subscriptions) + err = storage.AddSubscriptions(newSubscriptions) + if err != nil { + logger.Error(err, params) + } + err = delivery.Ack(false) if err != nil { - logger.Fatal(err, logger.Params{"operation": event.Operation, "guid": event.GUID}) + logger.Error(err, params) } - logger.Info("Success", logger.Params{"operation": event.Operation, "guid": event.GUID, "subscriptions_len": len(subscriptions)}) + logger.Info("Added", params) case DeleteSubscription: - err := storage.DeleteSubscriptions(nil) + err := storage.DeleteSubscriptions(oldSubscriptions) + if err != nil { + logger.Error(err, params) + } + err = delivery.Ack(false) if err != nil { - logger.Fatal(err, logger.Params{"operation": event.Operation, "guid": event.GUID}) + logger.Error(err, params) } - logger.Info("Success", logger.Params{"operation": event.Operation, "guid": event.GUID, "subscriptions_len": len(subscriptions)}) + logger.Info("Deleted", params) } } From f9a158b762e3cf1a510c6da2f1c5e2cc8223529f Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Sun, 1 Mar 2020 15:17:40 +0800 Subject: [PATCH 176/506] Add ens .kred support (#944) * resolve .kred * lower name in tests --- services/domains/domains.go | 6 ++++-- services/domains/domains_test.go | 6 +++++- tests/integration/domains/domains.go | 10 +++++++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/services/domains/domains.go b/services/domains/domains.go index 05adb51d6..e814230c8 100644 --- a/services/domains/domains.go +++ b/services/domains/domains.go @@ -1,12 +1,13 @@ package domains import ( + "math" + "strings" + CoinType "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/platform" - "math" - "strings" ) // TLDMapping Mapping of name TLD's to coin where they are handled @@ -14,6 +15,7 @@ var TLDMapping = map[string]uint64{ ".eth": CoinType.ETH, ".xyz": CoinType.ETH, ".luxe": CoinType.ETH, + ".kred": CoinType.ETH, ".zil": CoinType.ZIL, ".crypto": CoinType.ZIL, "@fiotestnet": CoinType.FIO, diff --git a/services/domains/domains_test.go b/services/domains/domains_test.go index 3dc2f45af..9786527f8 100644 --- a/services/domains/domains_test.go +++ b/services/domains/domains_test.go @@ -1,12 +1,15 @@ package domains import ( + "strings" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/errors" - "testing" ) func checkGetTLD(t *testing.T, name string, expectedTLD string, expectedError error) { + name = strings.ToLower(name) tld, err := getTLD(name) assert.Equal(t, expectedTLD, tld) if expectedError == nil { @@ -20,6 +23,7 @@ func Test_getTLD(t *testing.T) { checkGetTLD(t, "vitalik.eth", ".eth", nil) checkGetTLD(t, "vitalik.ens", ".ens", nil) checkGetTLD(t, "ourxyzwallet.xyz", ".xyz", nil) + checkGetTLD(t, "Cameron.Kred", ".kred", nil) checkGetTLD(t, "btc.zil", ".zil", nil) checkGetTLD(t, "btc.crypto", ".crypto", nil) checkGetTLD(t, "nick@fiotestnet", "@fiotestnet", nil) diff --git a/tests/integration/domains/domains.go b/tests/integration/domains/domains.go index 7dcb3f1c8..a5dac9e93 100644 --- a/tests/integration/domains/domains.go +++ b/tests/integration/domains/domains.go @@ -3,11 +3,12 @@ package domains import ( + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/domains" - "testing" ) func TestDomains(t *testing.T) { @@ -39,6 +40,13 @@ func TestDomains(t *testing.T) { []blockatlas.Resolved{{Result: "0x0C54eEAd78d555bE3cbCD451424F9A27a7843935", Coin: coin.ETH}}, false, }, + { + "test .kred domain", + "Cameron.Kred", + []uint64{coin.ETH}, + []blockatlas.Resolved{{Result: "0xfc9FB438c456C771c0B38a57Cf0e8A3eaB4704fE", Coin: coin.ETH}}, + false, + }, { "test .zil domain", "dpantani.zil", From 267a2f91bf956861b81811dc3bef885e1a958a6c Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 1 Mar 2020 10:21:16 +0300 Subject: [PATCH 177/506] Add more details to logs (#945) --- services/subscription/subscribtion.go | 3 +- services/subscription/subscription_test.go | 32 ---------------------- 2 files changed, 2 insertions(+), 33 deletions(-) delete mode 100644 services/subscription/subscription_test.go diff --git a/services/subscription/subscribtion.go b/services/subscription/subscribtion.go index 518875b89..007afbf8e 100644 --- a/services/subscription/subscribtion.go +++ b/services/subscription/subscribtion.go @@ -22,7 +22,8 @@ func Consume(delivery amqp.Delivery, storage storage.Addresses) { } newSubscriptions := event.ParseSubscriptions(event.NewSubscriptions) oldSubscriptions := event.ParseSubscriptions(event.OldSubscriptions) - params := logger.Params{"operation": event.Operation, "guid": event.GUID, "new_subscriptions_len": len(newSubscriptions), "old_subscriptions_len": len(oldSubscriptions)} + + params := logger.Params{"operation": event.Operation, "guid": event.GUID, "new_subscriptions_len": len(newSubscriptions), "old_subscriptions_len": len(oldSubscriptions), "subs_old": oldSubscriptions, "subs_new": newSubscriptions} switch event.Operation { case UpdateSubscription: diff --git a/services/subscription/subscription_test.go b/services/subscription/subscription_test.go deleted file mode 100644 index a52d129bc..000000000 --- a/services/subscription/subscription_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package subscription - -import ( - "testing" -) - -func TestGetInterval(t *testing.T) { - //cache := storage.New() - //err := cache.Init("redis://localhost:6379") - //if err != nil { - // logger.Fatal(err) - //} - // - //var subscriptions = blockatlas.Subscriptions{ - // "2": {"COINADDRESS 0"}, - // "0": {"ADDRES 1", "aDDRESS 2"}, - //} - // - //var mockedData = blockatlas.SubscriptionEvent{ - // Subscriptions: subscriptions, - // GUID: "EXAMPLE", - // Operation: addSubscription, - //} - - // b, _ := json.Marshal(mockedData) - // - // //success := Consume(b, cache) - // if !success { - // t.Fatal() - // } - //} -} From f0d8cd7c04939aa260dc7f23c4254dde10e35183 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 1 Mar 2020 10:45:48 +0300 Subject: [PATCH 178/506] Temporary remove ack and clear logs (#946) --- mq/mq.go | 2 +- services/subscription/subscribtion.go | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mq/mq.go b/mq/mq.go index 4aa00c6ff..db96eefb5 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -56,7 +56,7 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { messageChannel, err := amqpChan.Consume( string(q), "", - false, + true, false, false, false, diff --git a/services/subscription/subscribtion.go b/services/subscription/subscribtion.go index 007afbf8e..f561021a4 100644 --- a/services/subscription/subscribtion.go +++ b/services/subscription/subscribtion.go @@ -23,7 +23,7 @@ func Consume(delivery amqp.Delivery, storage storage.Addresses) { newSubscriptions := event.ParseSubscriptions(event.NewSubscriptions) oldSubscriptions := event.ParseSubscriptions(event.OldSubscriptions) - params := logger.Params{"operation": event.Operation, "guid": event.GUID, "new_subscriptions_len": len(newSubscriptions), "old_subscriptions_len": len(oldSubscriptions), "subs_old": oldSubscriptions, "subs_new": newSubscriptions} + params := logger.Params{"operation": event.Operation, "guid": event.GUID, "new_subscriptions_len": len(newSubscriptions), "old_subscriptions_len": len(oldSubscriptions)} switch event.Operation { case UpdateSubscription: @@ -35,30 +35,30 @@ func Consume(delivery amqp.Delivery, storage storage.Addresses) { if err != nil { logger.Error(err, params) } - err = delivery.Ack(false) - if err != nil { - logger.Error(err, params) - } + //err = delivery.Ack(false) + //if err != nil { + // logger.Error(err, params) + //} logger.Info("Updated", params) case AddSubscription: err = storage.AddSubscriptions(newSubscriptions) if err != nil { logger.Error(err, params) } - err = delivery.Ack(false) - if err != nil { - logger.Error(err, params) - } + //err = delivery.Ack(false) + //if err != nil { + // logger.Error(err, params) + //} logger.Info("Added", params) case DeleteSubscription: err := storage.DeleteSubscriptions(oldSubscriptions) if err != nil { logger.Error(err, params) } - err = delivery.Ack(false) - if err != nil { - logger.Error(err, params) - } + //err = delivery.Ack(false) + //if err != nil { + // logger.Error(err, params) + //} logger.Info("Deleted", params) } } From 5470f3ced2f7786fb2263d7dd2da1f47434f5751 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 1 Mar 2020 11:25:06 +0300 Subject: [PATCH 179/506] Fix redis bug (#947) --- storage/addresses.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/storage/addresses.go b/storage/addresses.go index c4b6238bb..97e8cb244 100644 --- a/storage/addresses.go +++ b/storage/addresses.go @@ -69,7 +69,9 @@ func (s *Storage) DeleteSubscriptions(subscriptions []blockatlas.Subscription) e continue } err = s.AddHM(ATLAS_OBSERVER, key, newHooks) - return err + if err != nil { + return err + } } return nil } From ea846a32dbbac9f10f7c2a369d0f7598f9f52a77 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 1 Mar 2020 11:27:40 +0300 Subject: [PATCH 180/506] Return ack for consumer --- mq/mq.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mq/mq.go b/mq/mq.go index db96eefb5..4aa00c6ff 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -56,7 +56,7 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { messageChannel, err := amqpChan.Consume( string(q), "", - true, + false, false, false, false, From 454e8e09fceb1da15b1c3064703ce1c0b9a286ea Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 1 Mar 2020 11:55:24 +0300 Subject: [PATCH 181/506] Update subscribtion.go --- services/subscription/subscribtion.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/services/subscription/subscribtion.go b/services/subscription/subscribtion.go index f561021a4..a381fd59f 100644 --- a/services/subscription/subscribtion.go +++ b/services/subscription/subscribtion.go @@ -35,30 +35,30 @@ func Consume(delivery amqp.Delivery, storage storage.Addresses) { if err != nil { logger.Error(err, params) } - //err = delivery.Ack(false) - //if err != nil { - // logger.Error(err, params) - //} + err = delivery.Ack(false) + if err != nil { + logger.Error(err, params) + } logger.Info("Updated", params) case AddSubscription: err = storage.AddSubscriptions(newSubscriptions) if err != nil { logger.Error(err, params) } - //err = delivery.Ack(false) - //if err != nil { - // logger.Error(err, params) - //} + err = delivery.Ack(false) + if err != nil { + logger.Error(err, params) + } logger.Info("Added", params) case DeleteSubscription: err := storage.DeleteSubscriptions(oldSubscriptions) if err != nil { logger.Error(err, params) } - //err = delivery.Ack(false) - //if err != nil { - // logger.Error(err, params) - //} + err = delivery.Ack(false) + if err != nil { + logger.Error(err, params) + } logger.Info("Deleted", params) } } From 7032f5564fb795a53201f8458545815c2ba03fc3 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sun, 1 Mar 2020 18:12:23 +0900 Subject: [PATCH 182/506] Rename StatusFailed to StatusError (#948) --- pkg/blockatlas/tx.go | 2 +- platform/cosmos/transaction.go | 2 +- platform/cosmos/transaction_test.go | 2 +- platform/ethereum/transaction.go | 2 +- platform/ethereum/transaction_test.go | 2 +- platform/nebulas/transaction.go | 2 +- platform/ontology/transaction.go | 2 +- platform/polkadot/transaction.go | 4 ++-- platform/ripple/transaction.go | 2 +- platform/ripple/transaction_test.go | 2 +- platform/tezos/transaction.go | 2 +- platform/tezos/transaction_test.go | 2 +- platform/zilliqa/transaction.go | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 6e40b645e..7ae77f4f1 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -11,7 +11,7 @@ type KeyTitle string const ( StatusCompleted Status = "completed" StatusPending Status = "pending" - StatusFailed Status = "failed" + StatusError Status = "error" DirectionOutgoing Direction = "outgoing" DirectionIncoming Direction = "incoming" diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 3051e7c3d..5a08c1fc0 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -96,7 +96,7 @@ func (p *Platform) Normalize(srcTx *Tx) (tx blockatlas.Tx, ok bool) { status := blockatlas.StatusCompleted // https://github.com/cosmos/cosmos-sdk/blob/95ddc242ad024ca78a359a13122dade6f14fd676/types/errors/errors.go#L19 if srcTx.Code > 0 { - status = blockatlas.StatusFailed + status = blockatlas.StatusError } tx = blockatlas.Tx{ diff --git a/platform/cosmos/transaction_test.go b/platform/cosmos/transaction_test.go index c571ec9df..32570c79e 100644 --- a/platform/cosmos/transaction_test.go +++ b/platform/cosmos/transaction_test.go @@ -664,7 +664,7 @@ var failedTransferDst = blockatlas.Tx{ Fee: "2000", Date: 1576120902, Block: 5552, - Status: blockatlas.StatusFailed, + Status: blockatlas.StatusError, Type: blockatlas.TxTransfer, Memo: "UniCoins registration rewards", Meta: blockatlas.Transfer{ diff --git a/platform/ethereum/transaction.go b/platform/ethereum/transaction.go index 882fa834d..e3dfbd012 100644 --- a/platform/ethereum/transaction.go +++ b/platform/ethereum/transaction.go @@ -49,7 +49,7 @@ func extractBase(srcTx *Doc, coinIndex uint) (base blockatlas.Tx, ok bool) { if srcTx.Error == "" { status = blockatlas.StatusCompleted } else { - status = blockatlas.StatusFailed + status = blockatlas.StatusError errReason = srcTx.Error } diff --git a/platform/ethereum/transaction_test.go b/platform/ethereum/transaction_test.go index c26a50f4a..eef731398 100644 --- a/platform/ethereum/transaction_test.go +++ b/platform/ethereum/transaction_test.go @@ -172,7 +172,7 @@ var failedDst = blockatlas.Tx{ Date: 1554662399, Block: 7522678, Sequence: 1, - Status: blockatlas.StatusFailed, + Status: blockatlas.StatusError, Error: "Error", Meta: blockatlas.Transfer{ Value: "59859820000000000", diff --git a/platform/nebulas/transaction.go b/platform/nebulas/transaction.go index d31df4d05..c22ce5a2c 100644 --- a/platform/nebulas/transaction.go +++ b/platform/nebulas/transaction.go @@ -41,7 +41,7 @@ func NormalizeTxs(txs []Transaction) []blockatlas.Tx { func NormalizeTx(srcTx Transaction) blockatlas.Tx { var status = blockatlas.StatusCompleted if srcTx.Status == 0 { - status = blockatlas.StatusFailed + status = blockatlas.StatusError } return blockatlas.Tx{ ID: srcTx.Hash, diff --git a/platform/ontology/transaction.go b/platform/ontology/transaction.go index c2fb04856..57216401e 100644 --- a/platform/ontology/transaction.go +++ b/platform/ontology/transaction.go @@ -34,7 +34,7 @@ func Normalize(srcTx *Tx, assetName AssetType) (tx blockatlas.Tx, ok bool) { fee := numbers.DecimalExp(srcTx.Fee, ONGDecimals) status := blockatlas.StatusCompleted if srcTx.ConfirmFlag != 1 { - status = blockatlas.StatusFailed + status = blockatlas.StatusError } tx = blockatlas.Tx{ ID: srcTx.Hash, diff --git a/platform/polkadot/transaction.go b/platform/polkadot/transaction.go index 1685c717d..5a1387c57 100644 --- a/platform/polkadot/transaction.go +++ b/platform/polkadot/transaction.go @@ -35,7 +35,7 @@ func (p *Platform) NormalizeTransfer(srcTx *Transfer) blockatlas.Tx { amount := strings.Split(numbers.DecimalExp(srcTx.Amount, int(decimals)), ".")[0] status := blockatlas.StatusCompleted if !srcTx.Success { - status = blockatlas.StatusFailed + status = blockatlas.StatusError } result := blockatlas.Tx{ ID: srcTx.Hash, @@ -75,7 +75,7 @@ func (p *Platform) NormalizeExtrinsic(srcTx *Extrinsic) *blockatlas.Tx { var status blockatlas.Status if !srcTx.Success { - status = blockatlas.StatusFailed + status = blockatlas.StatusError } else { status = blockatlas.StatusCompleted } diff --git a/platform/ripple/transaction.go b/platform/ripple/transaction.go index 84f0fd871..68e054a6d 100644 --- a/platform/ripple/transaction.go +++ b/platform/ripple/transaction.go @@ -55,7 +55,7 @@ func NormalizeTx(srcTx *Tx) (blockatlas.Tx, bool) { status := blockatlas.StatusCompleted if srcTx.Meta.TransactionResult != transactionResultSuccess { - status = blockatlas.StatusFailed + status = blockatlas.StatusError } result := blockatlas.Tx{ diff --git a/platform/ripple/transaction_test.go b/platform/ripple/transaction_test.go index ef640bee5..8cbc06a19 100644 --- a/platform/ripple/transaction_test.go +++ b/platform/ripple/transaction_test.go @@ -199,7 +199,7 @@ var failedPaymentDst = blockatlas.Tx{ Date: 1581590872, Block: 53401154, Memo: "", - Status: blockatlas.StatusFailed, + Status: blockatlas.StatusError, Meta: blockatlas.Transfer{ Value: "24999750000", Symbol: "XRP", diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index 354c795c3..d2615e4db 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -49,7 +49,7 @@ func NormalizeTx(srcTx Transaction) (blockatlas.Tx, bool) { status := blockatlas.StatusCompleted if srcTx.Status() != TxStatusApplied { errMsg = "transaction failed" - status = blockatlas.StatusFailed + status = blockatlas.StatusError } tx := blockatlas.Tx{ ID: srcTx.Op.OpHash, diff --git a/platform/tezos/transaction_test.go b/platform/tezos/transaction_test.go index 125acb9bf..42e56cad2 100644 --- a/platform/tezos/transaction_test.go +++ b/platform/tezos/transaction_test.go @@ -274,7 +274,7 @@ var transfer3 = blockatlas.Tx{ Symbol: coin.Coins[coin.XTZ].Symbol, Decimals: coin.Coins[coin.XTZ].Decimals, }, - Status: blockatlas.StatusFailed, + Status: blockatlas.StatusError, Error: "transaction failed", } diff --git a/platform/zilliqa/transaction.go b/platform/zilliqa/transaction.go index cb52d1e56..c18bda5d2 100644 --- a/platform/zilliqa/transaction.go +++ b/platform/zilliqa/transaction.go @@ -41,7 +41,7 @@ func Normalize(srcTx *Tx) (tx blockatlas.Tx) { }, } if !srcTx.ReceiptSuccess { - tx.Status = blockatlas.StatusFailed + tx.Status = blockatlas.StatusError } return tx } From cf7f34eff1ae33d015a9f67aa3e7b3081cf28bc5 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 1 Mar 2020 17:07:45 +0300 Subject: [PATCH 183/506] Improve consumer speed up to 100x with concurrency pattern and prefetch (#949) * Improve perfomance up to 100x with concurrent consumer and prefetch restriction * Close mq connection on retry. Setup prefetch perfectly --- cmd/observer_subscriber/main.go | 1 + cmd/observer_worker/main.go | 2 +- mq/mq.go | 11 ++++++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index 4b93f9119..8713bc489 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -40,4 +40,5 @@ func main() { defer mq.Close() mq.Subscriptions.RunConsumer(subscription.Consume, cache) <-make(chan struct{}) + mq.Close() } diff --git a/cmd/observer_worker/main.go b/cmd/observer_worker/main.go index 2809ee84b..e126abecd 100644 --- a/cmd/observer_worker/main.go +++ b/cmd/observer_worker/main.go @@ -96,6 +96,6 @@ func main() { } wg.Wait() - + mq.Close() logger.Info("Exiting cleanly") } diff --git a/mq/mq.go b/mq/mq.go index 4aa00c6ff..3ee3ab8cf 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -67,7 +67,16 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { return } + err = amqpChan.Qos( + 5, + 0, + true, + ) + if err != nil { + logger.Error("no qos limit ", err) + } + for data := range messageChannel { - consumer(data, cache) + go consumer(data, cache) } } From f8adb058158d7837b119287053dc1c96badea06a Mon Sep 17 00:00:00 2001 From: Mykola <3277207+kolya182@users.noreply.github.com> Date: Mon, 2 Mar 2020 17:41:05 -0800 Subject: [PATCH 184/506] Adopt to new trust-ray token response (#932) * Adopt to new trust-ray token response * Fix test --- platform/ethereum/model.go | 10 ++-------- platform/ethereum/token.go | 12 ++++++------ platform/ethereum/token_test.go | 16 ++++++---------- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/platform/ethereum/model.go b/platform/ethereum/model.go index e4f2e3313..d8464d084 100644 --- a/platform/ethereum/model.go +++ b/platform/ethereum/model.go @@ -11,13 +11,8 @@ type Page struct { } type TokenPage struct { - Total uint `json:"total"` - Docs []Token `json:"docs"` -} - -type Token struct { - Balance string `json:"balance"` - Contract Contract `json:"contract"` + Total uint `json:"total"` + Docs []Contract `json:"docs"` } type Doc struct { @@ -54,7 +49,6 @@ type Contract struct { Decimals uint `json:"decimals"` TotalSupply string `json:"totalSupply,omitempty"` Name string `json:"name"` - Contract string `json:"contract,omitempty"` } type NodeInfo struct { diff --git a/platform/ethereum/token.go b/platform/ethereum/token.go index cce551a02..78b15f898 100644 --- a/platform/ethereum/token.go +++ b/platform/ethereum/token.go @@ -13,13 +13,13 @@ func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, } // NormalizeToken converts a Ethereum token into the generic model -func NormalizeToken(srcToken *Token, coinIndex uint) (t blockatlas.Token, ok bool) { +func NormalizeToken(srcToken *Contract, coinIndex uint) (t blockatlas.Token, ok bool) { t = blockatlas.Token{ - Name: srcToken.Contract.Name, - Symbol: srcToken.Contract.Symbol, - TokenID: srcToken.Contract.Contract, + Name: srcToken.Name, + Symbol: srcToken.Symbol, + TokenID: srcToken.Address, Coin: coinIndex, - Decimals: srcToken.Contract.Decimals, + Decimals: srcToken.Decimals, Type: blockatlas.TokenTypeERC20, } @@ -27,7 +27,7 @@ func NormalizeToken(srcToken *Token, coinIndex uint) (t blockatlas.Token, ok boo } // NormalizeTxs converts multiple Ethereum tokens -func NormalizeTokens(srcTokens []Token, p Platform) []blockatlas.Token { +func NormalizeTokens(srcTokens []Contract, p Platform) []blockatlas.Token { tokenPage := make([]blockatlas.Token, 0) for _, srcToken := range srcTokens { token, ok := NormalizeToken(&srcToken, p.CoinIndex) diff --git a/platform/ethereum/token_test.go b/platform/ethereum/token_test.go index 1a87cdfcf..a2e9fdde6 100644 --- a/platform/ethereum/token_test.go +++ b/platform/ethereum/token_test.go @@ -10,21 +10,17 @@ import ( const tokenSrc = ` { - "balance": "0", - "contract": { - "contract": "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", - "address": "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", - "name": "FusChain", - "decimals": 18, - "symbol": "FUS" - } + "address": "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + "name": "FusChain", + "decimals": 18, + "symbol": "FUS" }` var tokenDst = blockatlas.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, - TokenID: "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", + TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.ETH, Type: blockatlas.TokenTypeERC20, } @@ -44,7 +40,7 @@ func TestNormalizeToken(t *testing.T) { } func testNormalizeToken(t *testing.T, _test *testToken) { - var token Token + var token Contract err := json.Unmarshal([]byte(_test.apiResponse), &token) if err != nil { t.Error(err) From 2fce3560a4b2a0df42c36ea66e9adeef294167c6 Mon Sep 17 00:00:00 2001 From: Mykola Date: Mon, 2 Mar 2020 17:48:01 -0800 Subject: [PATCH 185/506] Revert "Adopt to new trust-ray token response (#932)" This reverts commit f8adb058158d7837b119287053dc1c96badea06a. --- platform/ethereum/model.go | 10 ++++++++-- platform/ethereum/token.go | 12 ++++++------ platform/ethereum/token_test.go | 16 ++++++++++------ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/platform/ethereum/model.go b/platform/ethereum/model.go index d8464d084..e4f2e3313 100644 --- a/platform/ethereum/model.go +++ b/platform/ethereum/model.go @@ -11,8 +11,13 @@ type Page struct { } type TokenPage struct { - Total uint `json:"total"` - Docs []Contract `json:"docs"` + Total uint `json:"total"` + Docs []Token `json:"docs"` +} + +type Token struct { + Balance string `json:"balance"` + Contract Contract `json:"contract"` } type Doc struct { @@ -49,6 +54,7 @@ type Contract struct { Decimals uint `json:"decimals"` TotalSupply string `json:"totalSupply,omitempty"` Name string `json:"name"` + Contract string `json:"contract,omitempty"` } type NodeInfo struct { diff --git a/platform/ethereum/token.go b/platform/ethereum/token.go index 78b15f898..cce551a02 100644 --- a/platform/ethereum/token.go +++ b/platform/ethereum/token.go @@ -13,13 +13,13 @@ func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, } // NormalizeToken converts a Ethereum token into the generic model -func NormalizeToken(srcToken *Contract, coinIndex uint) (t blockatlas.Token, ok bool) { +func NormalizeToken(srcToken *Token, coinIndex uint) (t blockatlas.Token, ok bool) { t = blockatlas.Token{ - Name: srcToken.Name, - Symbol: srcToken.Symbol, - TokenID: srcToken.Address, + Name: srcToken.Contract.Name, + Symbol: srcToken.Contract.Symbol, + TokenID: srcToken.Contract.Contract, Coin: coinIndex, - Decimals: srcToken.Decimals, + Decimals: srcToken.Contract.Decimals, Type: blockatlas.TokenTypeERC20, } @@ -27,7 +27,7 @@ func NormalizeToken(srcToken *Contract, coinIndex uint) (t blockatlas.Token, ok } // NormalizeTxs converts multiple Ethereum tokens -func NormalizeTokens(srcTokens []Contract, p Platform) []blockatlas.Token { +func NormalizeTokens(srcTokens []Token, p Platform) []blockatlas.Token { tokenPage := make([]blockatlas.Token, 0) for _, srcToken := range srcTokens { token, ok := NormalizeToken(&srcToken, p.CoinIndex) diff --git a/platform/ethereum/token_test.go b/platform/ethereum/token_test.go index a2e9fdde6..1a87cdfcf 100644 --- a/platform/ethereum/token_test.go +++ b/platform/ethereum/token_test.go @@ -10,17 +10,21 @@ import ( const tokenSrc = ` { - "address": "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - "name": "FusChain", - "decimals": 18, - "symbol": "FUS" + "balance": "0", + "contract": { + "contract": "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", + "address": "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", + "name": "FusChain", + "decimals": 18, + "symbol": "FUS" + } }` var tokenDst = blockatlas.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, - TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + TokenID: "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", Coin: coin.ETH, Type: blockatlas.TokenTypeERC20, } @@ -40,7 +44,7 @@ func TestNormalizeToken(t *testing.T) { } func testNormalizeToken(t *testing.T, _test *testToken) { - var token Contract + var token Token err := json.Unmarshal([]byte(_test.apiResponse), &token) if err != nil { t.Error(err) From e41770ba7023eabcc2dc73273acad44997a1e7ef Mon Sep 17 00:00:00 2001 From: Mykola Date: Mon, 2 Mar 2020 17:59:54 -0800 Subject: [PATCH 186/506] Revert "Revert "Adopt to new trust-ray token response (#932)"" This reverts commit 2fce3560a4b2a0df42c36ea66e9adeef294167c6. --- platform/ethereum/model.go | 10 ++-------- platform/ethereum/token.go | 12 ++++++------ platform/ethereum/token_test.go | 16 ++++++---------- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/platform/ethereum/model.go b/platform/ethereum/model.go index e4f2e3313..d8464d084 100644 --- a/platform/ethereum/model.go +++ b/platform/ethereum/model.go @@ -11,13 +11,8 @@ type Page struct { } type TokenPage struct { - Total uint `json:"total"` - Docs []Token `json:"docs"` -} - -type Token struct { - Balance string `json:"balance"` - Contract Contract `json:"contract"` + Total uint `json:"total"` + Docs []Contract `json:"docs"` } type Doc struct { @@ -54,7 +49,6 @@ type Contract struct { Decimals uint `json:"decimals"` TotalSupply string `json:"totalSupply,omitempty"` Name string `json:"name"` - Contract string `json:"contract,omitempty"` } type NodeInfo struct { diff --git a/platform/ethereum/token.go b/platform/ethereum/token.go index cce551a02..78b15f898 100644 --- a/platform/ethereum/token.go +++ b/platform/ethereum/token.go @@ -13,13 +13,13 @@ func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, } // NormalizeToken converts a Ethereum token into the generic model -func NormalizeToken(srcToken *Token, coinIndex uint) (t blockatlas.Token, ok bool) { +func NormalizeToken(srcToken *Contract, coinIndex uint) (t blockatlas.Token, ok bool) { t = blockatlas.Token{ - Name: srcToken.Contract.Name, - Symbol: srcToken.Contract.Symbol, - TokenID: srcToken.Contract.Contract, + Name: srcToken.Name, + Symbol: srcToken.Symbol, + TokenID: srcToken.Address, Coin: coinIndex, - Decimals: srcToken.Contract.Decimals, + Decimals: srcToken.Decimals, Type: blockatlas.TokenTypeERC20, } @@ -27,7 +27,7 @@ func NormalizeToken(srcToken *Token, coinIndex uint) (t blockatlas.Token, ok boo } // NormalizeTxs converts multiple Ethereum tokens -func NormalizeTokens(srcTokens []Token, p Platform) []blockatlas.Token { +func NormalizeTokens(srcTokens []Contract, p Platform) []blockatlas.Token { tokenPage := make([]blockatlas.Token, 0) for _, srcToken := range srcTokens { token, ok := NormalizeToken(&srcToken, p.CoinIndex) diff --git a/platform/ethereum/token_test.go b/platform/ethereum/token_test.go index 1a87cdfcf..a2e9fdde6 100644 --- a/platform/ethereum/token_test.go +++ b/platform/ethereum/token_test.go @@ -10,21 +10,17 @@ import ( const tokenSrc = ` { - "balance": "0", - "contract": { - "contract": "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", - "address": "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", - "name": "FusChain", - "decimals": 18, - "symbol": "FUS" - } + "address": "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + "name": "FusChain", + "decimals": 18, + "symbol": "FUS" }` var tokenDst = blockatlas.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, - TokenID: "0xa14839c9837657efcde754ebeaf5cbecdd801b2a", + TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.ETH, Type: blockatlas.TokenTypeERC20, } @@ -44,7 +40,7 @@ func TestNormalizeToken(t *testing.T) { } func testNormalizeToken(t *testing.T, _test *testToken) { - var token Token + var token Contract err := json.Unmarshal([]byte(_test.apiResponse), &token) if err != nil { t.Error(err) From 2584114e27ff8c89e9feaec759a41d08cb672460 Mon Sep 17 00:00:00 2001 From: "D. Robin" Date: Tue, 3 Mar 2020 03:21:13 +0100 Subject: [PATCH 187/506] Minor: Update images to use assets repository (#950) Update README.md to use TrustWallet/assets repository instead of tokens repository (archived). --- README.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 1d772630e..f29a0b90b 100644 --- a/README.md +++ b/README.md @@ -17,26 +17,26 @@ The observer API watches the chain for new transactions and generates notificati #### Supported Coins - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + ## Setup From 154698780fdb17aedec456e568260c4077fc42e8 Mon Sep 17 00:00:00 2001 From: Mykola Date: Mon, 2 Mar 2020 18:22:38 -0800 Subject: [PATCH 188/506] fxi typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f29a0b90b..b5dd96099 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The observer API watches the chain for new transactions and generates notificati - + From ee30b346ab4619249c37b1330af1edd30c9c2c09 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> Date: Tue, 3 Mar 2020 05:57:33 +0300 Subject: [PATCH 189/506] [Observer] Fix getDirection bug for TokenTransfer and NativeTokenTransfer (#951) --- observer/observer.go | 15 ++++++++-- observer/observer_test.go | 60 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/observer/observer.go b/observer/observer.go index a9b076e3d..658ec8fb2 100644 --- a/observer/observer.go +++ b/observer/observer.go @@ -88,8 +88,19 @@ func getDirection(tx blockatlas.Tx, address string) blockatlas.Direction { addressSet := mapset.NewSet(address) return bitcoin.InferDirection(&tx, addressSet) } - if address == tx.To { - if tx.From == tx.To { + switch meta := tx.Meta.(type) { + case *blockatlas.TokenTransfer: + return determineDirection(address, meta.From, meta.To) + case *blockatlas.NativeTokenTransfer: + return determineDirection(address, meta.From, meta.To) + default: + return determineDirection(address, tx.From, tx.To) + } +} + +func determineDirection(address, from, to string) blockatlas.Direction { + if address == to { + if from == to { return blockatlas.DirectionSelf } return blockatlas.DirectionIncoming diff --git a/observer/observer_test.go b/observer/observer_test.go index c01027a8f..91c4c3265 100644 --- a/observer/observer_test.go +++ b/observer/observer_test.go @@ -171,6 +171,66 @@ func Test_getDirection(t *testing.T) { }, "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", }, blockatlas.DirectionIncoming, }, + {"Test NativeTokenTransfer Direction Self", + args{ + blockatlas.Tx{ + Meta: &blockatlas.NativeTokenTransfer{ + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, blockatlas.DirectionSelf, + }, + {"Test NativeTokenTransfer Direction Outgoing", + args{ + blockatlas.Tx{ + Meta: &blockatlas.NativeTokenTransfer{ + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, blockatlas.DirectionOutgoing, + }, + {"Test NativeTokenTransfer Direction Incoming", + args{ + blockatlas.Tx{ + Meta: &blockatlas.NativeTokenTransfer{ + From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, blockatlas.DirectionIncoming, + }, + {"Test TokenTransfer Direction Self", + args{ + blockatlas.Tx{ + Meta: &blockatlas.TokenTransfer{ + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, blockatlas.DirectionSelf, + }, + {"Test TokenTransfer Direction Outgoing", + args{ + blockatlas.Tx{ + Meta: &blockatlas.TokenTransfer{ + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, blockatlas.DirectionOutgoing, + }, + {"Test TokenTransfer Direction Incoming", + args{ + blockatlas.Tx{ + Meta: &blockatlas.TokenTransfer{ + From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, blockatlas.DirectionIncoming, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 4945c81cf577a2e39fd4d090ee8b8e4c14df87b8 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> Date: Tue, 3 Mar 2020 10:03:00 +0300 Subject: [PATCH 190/506] [Observer] Delete pointers in getDirection (#952) * [Observer] Delete pointers in getDirection * Fix unit tests --- observer/observer.go | 4 ++-- observer/observer_test.go | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/observer/observer.go b/observer/observer.go index 658ec8fb2..aaf8470f0 100644 --- a/observer/observer.go +++ b/observer/observer.go @@ -89,9 +89,9 @@ func getDirection(tx blockatlas.Tx, address string) blockatlas.Direction { return bitcoin.InferDirection(&tx, addressSet) } switch meta := tx.Meta.(type) { - case *blockatlas.TokenTransfer: + case blockatlas.TokenTransfer: return determineDirection(address, meta.From, meta.To) - case *blockatlas.NativeTokenTransfer: + case blockatlas.NativeTokenTransfer: return determineDirection(address, meta.From, meta.To) default: return determineDirection(address, tx.From, tx.To) diff --git a/observer/observer_test.go b/observer/observer_test.go index 91c4c3265..9c6fa449d 100644 --- a/observer/observer_test.go +++ b/observer/observer_test.go @@ -174,7 +174,7 @@ func Test_getDirection(t *testing.T) { {"Test NativeTokenTransfer Direction Self", args{ blockatlas.Tx{ - Meta: &blockatlas.NativeTokenTransfer{ + Meta: blockatlas.NativeTokenTransfer{ From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, @@ -184,7 +184,7 @@ func Test_getDirection(t *testing.T) { {"Test NativeTokenTransfer Direction Outgoing", args{ blockatlas.Tx{ - Meta: &blockatlas.NativeTokenTransfer{ + Meta: blockatlas.NativeTokenTransfer{ From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", }, @@ -194,7 +194,7 @@ func Test_getDirection(t *testing.T) { {"Test NativeTokenTransfer Direction Incoming", args{ blockatlas.Tx{ - Meta: &blockatlas.NativeTokenTransfer{ + Meta: blockatlas.NativeTokenTransfer{ From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, @@ -204,7 +204,7 @@ func Test_getDirection(t *testing.T) { {"Test TokenTransfer Direction Self", args{ blockatlas.Tx{ - Meta: &blockatlas.TokenTransfer{ + Meta: blockatlas.TokenTransfer{ From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, @@ -214,7 +214,7 @@ func Test_getDirection(t *testing.T) { {"Test TokenTransfer Direction Outgoing", args{ blockatlas.Tx{ - Meta: &blockatlas.TokenTransfer{ + Meta: blockatlas.TokenTransfer{ From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", }, @@ -224,7 +224,7 @@ func Test_getDirection(t *testing.T) { {"Test TokenTransfer Direction Incoming", args{ blockatlas.Tx{ - Meta: &blockatlas.TokenTransfer{ + Meta: blockatlas.TokenTransfer{ From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, From 23453ffb17ed1940770108eade52bad4dd9bc86d Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Thu, 5 Mar 2020 02:01:59 +0100 Subject: [PATCH 191/506] Update mq.go --- mq/mq.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mq/mq.go b/mq/mq.go index 3ee3ab8cf..bcfebb9b1 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -68,7 +68,7 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { } err = amqpChan.Qos( - 5, + 20, 0, true, ) From 32a3fdaf32a2437c1a902dc25881ebef6f2dc056 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 7 Mar 2020 19:10:21 +0300 Subject: [PATCH 192/506] Temporary change tezos api to http api.tezos.id have outdated https certificate --- config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.yml b/config.yml index 6007c378e..65444ad81 100644 --- a/config.yml +++ b/config.yml @@ -58,7 +58,8 @@ kin: # [XTZ] Tezos: https://tezos.com tezos: - api: https://api.tezos.id/mooncake/mainnet + stake_api: https://api.tzstats.com/explorer + api: http://api.tezos.id/mooncake/mainnet rpc: https://mainnet.tezos.org.ua # [ETH] Ethereum: https://ethereum.org (Trust-Ray API) From 491809184e77cc5b73889a5b5f80afeea2874c8c Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 11 Mar 2020 06:06:45 +0300 Subject: [PATCH 193/506] Internal init changes, add optinal MQ prefetch count (#953) * Change init package, init functions for services, add optional prefetch count for MQ * Add docker tests (setup got mq and redis) * Add connection check(mq setup) * Try to fix tests * Use another image for rabbit setup * Update docker-compose and config.yml * Add tests, change default prefetch count at config.yml * Fix integration test build * Remove fio domain integration test Co-authored-by: prazd --- Makefile | 2 +- cmd/observer_subscriber/main.go | 28 ++++---- cmd/observer_worker/main.go | 25 +++---- cmd/platform_api/main.go | 22 +++--- cmd/swagger_api/main.go | 28 ++++---- config.yml | 6 +- docker-compose.yml | 2 +- go.mod | 13 ++++ go.sum | 42 ++++++++++++ internal/init.go | 67 ++++++++++--------- mq/mq.go | 21 ++++-- .../data/given_subscriptions_added.json | 42 ++++++++++++ .../data/wanted_subscriptions_added.json | 22 ++++++ tests/docker_test/environment_run_test.go | 18 +++++ tests/docker_test/observer_test.go | 64 ++++++++++++++++++ tests/docker_test/setup/mq.go | 37 ++++++++++ tests/docker_test/setup/redis.go | 43 ++++++++++++ tests/docker_test/setup/setup.go | 27 ++++++++ tests/integration/domains/domains.go | 18 ++--- 19 files changed, 425 insertions(+), 102 deletions(-) create mode 100644 tests/docker_test/data/given_subscriptions_added.json create mode 100644 tests/docker_test/data/wanted_subscriptions_added.json create mode 100644 tests/docker_test/environment_run_test.go create mode 100644 tests/docker_test/observer_test.go create mode 100644 tests/docker_test/setup/mq.go create mode 100644 tests/docker_test/setup/redis.go create mode 100644 tests/docker_test/setup/setup.go diff --git a/Makefile b/Makefile index b05a97f75..d3e4582ff 100644 --- a/Makefile +++ b/Makefile @@ -193,7 +193,7 @@ go-functional: go-integration: @echo " > Running integration tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration + GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration ./tests/docker_test go-fmt: @echo " > Format all go files" diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index 8713bc489..b6b414b49 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -1,7 +1,6 @@ package main import ( - "github.com/gin-gonic/gin" "github.com/spf13/viper" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" @@ -16,29 +15,26 @@ const ( ) var ( - port, confPath string - cache *storage.Storage - sg *gin.HandlerFunc + confPath string + cache *storage.Storage ) func init() { - _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) - - uri := viper.GetString("observer.rabbitmq.uri") - err := mq.Init(uri) - if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) - } - err = mq.Transactions.Declare() - if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) - } + _, confPath := internal.ParseArgs("", defaultConfigPath) + internal.InitConfig(confPath) + logger.InitLogger() + + redisHost := viper.GetString("storage.redis") + mqHost := viper.GetString("observer.rabbitmq.uri") + prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + + cache = internal.InitRedis(redisHost) + internal.InitRabbitMQ(mqHost, prefetchCount) } func main() { defer mq.Close() mq.Subscriptions.RunConsumer(subscription.Consume, cache) <-make(chan struct{}) - mq.Close() } diff --git a/cmd/observer_worker/main.go b/cmd/observer_worker/main.go index e126abecd..5e2c3d18c 100644 --- a/cmd/observer_worker/main.go +++ b/cmd/observer_worker/main.go @@ -22,22 +22,24 @@ var ( ) func init() { - _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) + _, confPath := internal.ParseArgs("", defaultConfigPath) - uri := viper.GetString("observer.rabbitmq.uri") - err := mq.Init(uri) - if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) - } - err = mq.Transactions.Declare() - if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) - } + internal.InitConfig(confPath) + logger.InitLogger() - platform.Init(viper.GetString("platform")) + redisHost := viper.GetString("storage.redis") + mqHost := viper.GetString("observer.rabbitmq.uri") + prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + platformHandle := viper.GetString("platform") + + cache = internal.InitRedis(redisHost) + internal.InitRabbitMQ(mqHost, prefetchCount) + platform.Init(platformHandle) } func main() { + defer mq.Close() + if len(platform.BlockAPIs) == 0 { logger.Fatal("No APIs to observe") } @@ -96,6 +98,5 @@ func main() { } wg.Wait() - mq.Close() logger.Info("Exiting cleanly") } diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index 26ac4396a..4e293b0a4 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -1,12 +1,13 @@ package main import ( + sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" ) @@ -17,22 +18,23 @@ const ( var ( port, confPath string - sg *gin.HandlerFunc + engine *gin.Engine ) func init() { - port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) + port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) + + internal.InitConfig(confPath) + logger.InitLogger() + tmp := sentrygin.New(sentrygin.Options{}) + sg := &tmp + + engine = internal.InitEngine(sg, viper.GetString("gin.mode")) + platform.Init(viper.GetString("platform")) } func main() { - gin.SetMode(viper.GetString("gin.mode")) - - engine := gin.New() - engine.Use(ginutils.CheckReverseProxy, *sg) - engine.Use(ginutils.CORSMiddleware()) - engine.Use(gin.Logger()) - api.SetupPlatformAPI(engine) internal.SetupGracefulShutdown(port, engine) } diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go index 2d2c4b4d9..ceb9c0d69 100644 --- a/cmd/swagger_api/main.go +++ b/cmd/swagger_api/main.go @@ -1,14 +1,15 @@ package main import ( + sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" "github.com/spf13/viper" ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" - "github.com/trustwallet/blockatlas/api" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/logger" + "net/http" ) const ( @@ -18,23 +19,22 @@ const ( var ( port, confPath string - sg *gin.HandlerFunc + engine *gin.Engine ) func init() { - port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) + port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) + tmp := sentrygin.New(sentrygin.Options{}) + sg := &tmp + internal.InitConfig(confPath) + logger.InitLogger() + engine = internal.InitEngine(sg, viper.GetString("gin.mode")) } func main() { - gin.SetMode(viper.GetString("gin.mode")) - engine := gin.New() - - engine.Use(ginutils.CheckReverseProxy, *sg) - engine.Use(ginutils.CORSMiddleware()) - - engine.GET("/", api.GetRoot) - engine.GET("/status", api.GetStatus) + logger.Info("Loading Swagger API") + engine.GET("/", func(c *gin.Context) { + c.Redirect(http.StatusMovedPermanently, "swagger/index.html") + }) engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - - internal.SetupGracefulShutdown(port, engine) } diff --git a/config.yml b/config.yml index 65444ad81..da4585987 100644 --- a/config.yml +++ b/config.yml @@ -29,10 +29,12 @@ observer: min: 3s max: 30s rabbitmq: - uri: amqp://user:bitnami@rabbit:5672 + uri: amqp://rabbit:5672 + consumer: + prefetch_count: 10 storage: - redis: redis://redis:6379 + redis: redis://localhost:6379 # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org diff --git a/docker-compose.yml b/docker-compose.yml index cae42ded5..9d8562149 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,7 +53,7 @@ services: rabbit: container_name: rabbit - image: bitnami/rabbitmq + image: rabbitmq ports: - 5672:5672 healthcheck: diff --git a/go.mod b/go.mod index de0bb6ac8..b5168b5f4 100644 --- a/go.mod +++ b/go.mod @@ -3,21 +3,32 @@ module github.com/trustwallet/blockatlas go 1.12 require ( + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/Pantani/httpexpect v2.0.0+incompatible github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.1 github.com/cenkalti/backoff v2.2.1+incompatible github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05 + github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c // indirect github.com/deckarep/golang-set v1.7.1 + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.4.0 // indirect github.com/ethereum/go-ethereum v1.9.10 github.com/getsentry/sentry-go v0.4.0 github.com/gin-gonic/gin v1.5.0 github.com/go-redis/redis v6.15.6+incompatible github.com/hewigovens/go-coincodec v1.0.4 github.com/jinzhu/gorm v1.9.12 + github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/mitchellh/mapstructure v1.1.2 github.com/mr-tron/base58 v1.1.3 + github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/runc v0.1.1 // indirect + github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.4.0 github.com/robfig/cron/v3 v3.0.1 github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 @@ -30,5 +41,7 @@ require ( github.com/swaggo/swag v1.6.5 github.com/wealdtech/go-ens/v3 v3.2.0 golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d + golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect + golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index 193793ce6..849be0207 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,11 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= @@ -20,6 +23,10 @@ github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKz github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Pantani/httpexpect v2.0.0+incompatible h1:P658jo0d3gej0D67KBcSUgpZY76CH1TdxvOfQAmyNu0= @@ -84,6 +91,8 @@ github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05/go.mod h1:lI github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c h1:8ahmSVELW1wghbjerVAyuEYD5+Dio66RYvSS0iGfL1M= +github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -109,6 +118,11 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= @@ -280,7 +294,10 @@ github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -354,10 +371,20 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c h1:1RHs3t github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/oschwald/maxminddb-golang v1.3.1/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -369,8 +396,11 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -416,7 +446,9 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 h1:Pm6R878vxWWWR+Sa3ppsLce/Zq+JNTs6aVvRu13jv9A= github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -432,9 +464,11 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= @@ -520,6 +554,7 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -552,6 +587,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -570,6 +607,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -577,6 +615,8 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -599,12 +639,14 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= diff --git a/internal/init.go b/internal/init.go index 6ac30c03d..f6f47cd30 100644 --- a/internal/init.go +++ b/internal/init.go @@ -3,10 +3,10 @@ package internal import ( "flag" "fmt" - sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" "path/filepath" @@ -19,58 +19,63 @@ var ( Date = time.Now().String() ) -func InitAPI(defaultPort, defaultConfigPath string) (string, string, *gin.HandlerFunc) { +func ParseArgs(defaultPort, defaultConfigPath string) (string, string) { var ( port, confPath string - sg gin.HandlerFunc ) - LogVersionInfo() - sg = sentrygin.New(sentrygin.Options{}) - flag.StringVar(&port, "p", defaultPort, "port for api") flag.StringVar(&confPath, "c", defaultConfigPath, "config file for api") flag.Parse() - confPath, err := filepath.Abs(confPath) + return port, confPath +} + +func InitRedis(host string) *storage.Storage { + cache := storage.New() + err := cache.Init(host) if err != nil { logger.Fatal(err) } - - config.LoadConfig(confPath) - logger.InitLogger() - - return port, confPath, &sg + return cache } -func InitAPIWithRedis(defaultPort, defaultConfigPath string) (string, string, *gin.HandlerFunc, *storage.Storage) { - var ( - port, confPath string - cache *storage.Storage - sg gin.HandlerFunc - ) - LogVersionInfo() - cache = storage.New() - sg = sentrygin.New(sentrygin.Options{}) - - flag.StringVar(&port, "p", defaultPort, "port for api") - flag.StringVar(&confPath, "c", defaultConfigPath, "config file for api") - flag.Parse() - +func InitConfig(confPath string) { confPath, err := filepath.Abs(confPath) if err != nil { logger.Fatal(err) } config.LoadConfig(confPath) - logger.InitLogger() +} + +func InitEngine(handler *gin.HandlerFunc, ginMode string) *gin.Engine { + gin.SetMode(ginMode) + engine := gin.New() + engine.Use(ginutils.CheckReverseProxy, *handler) + engine.Use(ginutils.CORSMiddleware()) + engine.Use(gin.Logger()) + + engine.OPTIONS("/*path", ginutils.CORSMiddleware()) + engine.GET("/status", func(c *gin.Context) { + ginutils.RenderSuccess(c, map[string]interface{}{ + "status": true, + }) + }) - err = cache.Init(viper.GetString("storage.redis")) + return engine +} + +func InitRabbitMQ(rabbitURI string, prefetchCount int) { + err := mq.Init(rabbitURI) + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": rabbitURI}) + } + err = mq.Transactions.Declare() if err != nil { logger.Fatal(err) } - - return port, confPath, &sg, cache + mq.PrefetchCount = prefetchCount } func LogVersionInfo() { diff --git a/mq/mq.go b/mq/mq.go index bcfebb9b1..c086fddae 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -7,9 +7,10 @@ import ( ) var ( - amqpChan *amqp.Channel - conn *amqp.Connection - queue amqp.Queue + PrefetchCount int + amqpChan *amqp.Channel + conn *amqp.Connection + queue amqp.Queue ) type ( @@ -18,8 +19,10 @@ type ( ) const ( - Transactions Queue = "transactions" - Subscriptions Queue = "subscriptions" + Transactions Queue = "transactions" + Subscriptions Queue = "subscriptions" + defaultPrefetchCount = 5 + minPrefetchCount = 1 ) func Init(uri string) (err error) { @@ -67,11 +70,17 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { return } + if PrefetchCount < minPrefetchCount { + logger.Info("Change prefetch count to default") + PrefetchCount = defaultPrefetchCount + } + err = amqpChan.Qos( - 20, + PrefetchCount, 0, true, ) + if err != nil { logger.Error("no qos limit ", err) } diff --git a/tests/docker_test/data/given_subscriptions_added.json b/tests/docker_test/data/given_subscriptions_added.json new file mode 100644 index 000000000..6d5efbc84 --- /dev/null +++ b/tests/docker_test/data/given_subscriptions_added.json @@ -0,0 +1,42 @@ +[ + { + "new_subscriptions": { + "60": [ + "0x0000000000000000000000000000000000000000" + ] + }, + "old_subscriptions": null, + "guid": "0", + "operation": "AddSubscription" + }, + { + "new_subscriptions": { + "118": [ + "0x0000000000000000000000000000000000000001" + ] + }, + "old_subscriptions": null, + "guid": "1", + "operation": "AddSubscription" + }, + { + "new_subscriptions": { + "714": [ + "0x0000000000000000000000000000000000000002" + ] + }, + "old_subscriptions": null, + "guid": "2", + "operation": "AddSubscription" + }, + { + "new_subscriptions": { + "144": [ + "0x0000000000000000000000000000000000000003" + ] + }, + "old_subscriptions": null, + "guid": "3", + "operation": "AddSubscription" + } +] diff --git a/tests/docker_test/data/wanted_subscriptions_added.json b/tests/docker_test/data/wanted_subscriptions_added.json new file mode 100644 index 000000000..c89a4b50d --- /dev/null +++ b/tests/docker_test/data/wanted_subscriptions_added.json @@ -0,0 +1,22 @@ +[ + { + "coin": 60, + "address": "0x0000000000000000000000000000000000000000", + "guid": "0" + }, + { + "coin": 118, + "address": "0x0000000000000000000000000000000000000001", + "guid": "1" + }, + { + "coin": 714, + "address": "0x0000000000000000000000000000000000000002", + "guid": "2" + }, + { + "coin": 144, + "address": "0x0000000000000000000000000000000000000003", + "guid": "3" + } +] diff --git a/tests/docker_test/environment_run_test.go b/tests/docker_test/environment_run_test.go new file mode 100644 index 000000000..ca13dd7a1 --- /dev/null +++ b/tests/docker_test/environment_run_test.go @@ -0,0 +1,18 @@ +// +build integration + +package docker_test + +import ( + "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "os" + "testing" +) + +func TestMain(m *testing.M) { + setup.RunMQContainer() + setup.RunRedisContainer() + code := m.Run() + setup.StopMQContainer() + setup.StopRedisContainer() + os.Exit(code) +} diff --git a/tests/docker_test/observer_test.go b/tests/docker_test/observer_test.go new file mode 100644 index 000000000..5bccfff2a --- /dev/null +++ b/tests/docker_test/observer_test.go @@ -0,0 +1,64 @@ +// +build integration + +package docker_test + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/subscription" + "github.com/trustwallet/blockatlas/storage" + "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "io/ioutil" + "path/filepath" + "runtime" + "testing" + "time" +) + +func TestSubscriberAddSubscription(t *testing.T) { + _, goFile, _, _ := runtime.Caller(0) + testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_added.json") + testFileGiven, err := ioutil.ReadFile(testFilePathGiven) + if err != nil { + t.Fatal(err) + } + var givenEvents []blockatlas.SubscriptionEvent + if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { + t.Fatal(err) + } + + testFilePathWanted := filepath.Join(filepath.Dir(goFile), "data", "wanted_subscriptions_added.json") + testFileWanted, err := ioutil.ReadFile(testFilePathWanted) + if err != nil { + t.Fatal(err) + } + var wantedEvents []blockatlas.Subscription + if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { + t.Fatal(err) + } + + assert.Nil(t, mq.Subscriptions.Declare()) + + for _, event := range givenEvents { + body, err := json.Marshal(event) + assert.Nil(t, err) + + err = mq.Subscriptions.Publish(body) + assert.Nil(t, err) + + go mq.Subscriptions.RunConsumer(subscription.Consume, setup.Cache) + time.Sleep(time.Second / 5) + } + + result, err := setup.Cache.GetAllHM(storage.ATLAS_OBSERVER) + assert.Nil(t, err) + assert.NotNil(t, result) + + for _, wanted := range wantedEvents { + result, err := setup.Cache.Lookup(wanted.Coin, []string{wanted.Address}) + assert.Nil(t, err) + assert.Equal(t, result[0], wanted) + } +} diff --git a/tests/docker_test/setup/mq.go b/tests/docker_test/setup/mq.go new file mode 100644 index 000000000..cf7e3ea03 --- /dev/null +++ b/tests/docker_test/setup/mq.go @@ -0,0 +1,37 @@ +package setup + +import ( + "fmt" + "github.com/ory/dockertest" + "github.com/trustwallet/blockatlas/mq" + "log" +) + +var ( + mqResource *dockertest.Resource +) + +func runMQContainer() error { + var err error + pool, err := dockertest.NewPool("") + if err != nil { + log.Fatalf("Could not connect to docker: %s", err) + } + + mqResource, err = pool.Run("rabbitmq", "latest", nil) + if err != nil { + log.Fatalf("Could not start resource: %s", err) + } + + if err = pool.Retry(func() error { + return mq.Init(fmt.Sprintf("amqp://localhost:%s", mqResource.GetPort("5672/tcp"))) + }); err != nil { + return err + } + return nil +} + +func stopMQContainer() error { + mq.Close() + return mqResource.Close() +} \ No newline at end of file diff --git a/tests/docker_test/setup/redis.go b/tests/docker_test/setup/redis.go new file mode 100644 index 000000000..05b6929e2 --- /dev/null +++ b/tests/docker_test/setup/redis.go @@ -0,0 +1,43 @@ +package setup + +import ( + "fmt" + "github.com/ory/dockertest" + "github.com/trustwallet/blockatlas/storage" + "log" +) + +var ( + Cache *storage.Storage + redisResource *dockertest.Resource +) + +func runRedisContainer() error { + var err error + pool, err := dockertest.NewPool("") + if err != nil { + log.Fatalf("Could not connect to docker: %s", err) + } + + redisResource, err = pool.Run("redis", "latest", nil) + if err != nil { + log.Fatalf("Could not start resource: %s", err) + } + + if err = pool.Retry(func() error { + var err error + Cache = storage.New() + err = Cache.Init(fmt.Sprintf("redis://localhost:%s", redisResource.GetPort("6379/tcp"))) + if err != nil { + return err + } + return nil + }); err != nil { + return err + } + return nil +} + +func stopRedisContainer() error { + return redisResource.Close() +} \ No newline at end of file diff --git a/tests/docker_test/setup/setup.go b/tests/docker_test/setup/setup.go new file mode 100644 index 000000000..80daf059c --- /dev/null +++ b/tests/docker_test/setup/setup.go @@ -0,0 +1,27 @@ +package setup + +import "log" + +func RunRedisContainer(){ + if err := runRedisContainer(); err != nil{ + log.Fatal(err) + } +} + +func StopRedisContainer(){ + if err := stopRedisContainer(); err != nil{ + log.Fatal(err) + } +} + +func RunMQContainer(){ + if err := runMQContainer(); err != nil{ + log.Fatal(err) + } +} + +func StopMQContainer(){ + if err := stopMQContainer(); err != nil{ + log.Fatal(err) + } +} \ No newline at end of file diff --git a/tests/integration/domains/domains.go b/tests/integration/domains/domains.go index a5dac9e93..058e0489e 100644 --- a/tests/integration/domains/domains.go +++ b/tests/integration/domains/domains.go @@ -79,15 +79,15 @@ func TestDomains(t *testing.T) { }, false, }, - { - "test @fiotestnet domain", - "adam@fiotestnet", - []uint64{coin.ETH}, - []blockatlas.Resolved{ - {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, - }, - false, - }, + //{ + // "test @fiotestnet domain", + // "adam@fiotestnet", + // []uint64{coin.ETH}, + // []blockatlas.Resolved{ + // {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, + // }, + // false, + //}, { "test batch .crypto domains", "dpantani.crypto", From f02a83f76009e262124dce4fda65fee0601d91ad Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 11 Mar 2020 06:48:19 +0300 Subject: [PATCH 194/506] Revert "Internal init changes, add optinal MQ prefetch count (#953)" (#957) This reverts commit 491809184e77cc5b73889a5b5f80afeea2874c8c. --- Makefile | 2 +- cmd/observer_subscriber/main.go | 28 ++++---- cmd/observer_worker/main.go | 25 ++++--- cmd/platform_api/main.go | 22 +++--- cmd/swagger_api/main.go | 28 ++++---- config.yml | 6 +- docker-compose.yml | 2 +- go.mod | 13 ---- go.sum | 42 ------------ internal/init.go | 67 +++++++++---------- mq/mq.go | 21 ++---- .../data/given_subscriptions_added.json | 42 ------------ .../data/wanted_subscriptions_added.json | 22 ------ tests/docker_test/environment_run_test.go | 18 ----- tests/docker_test/observer_test.go | 64 ------------------ tests/docker_test/setup/mq.go | 37 ---------- tests/docker_test/setup/redis.go | 43 ------------ tests/docker_test/setup/setup.go | 27 -------- tests/integration/domains/domains.go | 18 ++--- 19 files changed, 102 insertions(+), 425 deletions(-) delete mode 100644 tests/docker_test/data/given_subscriptions_added.json delete mode 100644 tests/docker_test/data/wanted_subscriptions_added.json delete mode 100644 tests/docker_test/environment_run_test.go delete mode 100644 tests/docker_test/observer_test.go delete mode 100644 tests/docker_test/setup/mq.go delete mode 100644 tests/docker_test/setup/redis.go delete mode 100644 tests/docker_test/setup/setup.go diff --git a/Makefile b/Makefile index d3e4582ff..b05a97f75 100644 --- a/Makefile +++ b/Makefile @@ -193,7 +193,7 @@ go-functional: go-integration: @echo " > Running integration tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration ./tests/docker_test + GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration go-fmt: @echo " > Format all go files" diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index b6b414b49..8713bc489 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -1,6 +1,7 @@ package main import ( + "github.com/gin-gonic/gin" "github.com/spf13/viper" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" @@ -15,26 +16,29 @@ const ( ) var ( - confPath string - cache *storage.Storage + port, confPath string + cache *storage.Storage + sg *gin.HandlerFunc ) func init() { - _, confPath := internal.ParseArgs("", defaultConfigPath) + _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) + + uri := viper.GetString("observer.rabbitmq.uri") + err := mq.Init(uri) + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) + } + err = mq.Transactions.Declare() + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) + } - internal.InitConfig(confPath) - logger.InitLogger() - - redisHost := viper.GetString("storage.redis") - mqHost := viper.GetString("observer.rabbitmq.uri") - prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") - - cache = internal.InitRedis(redisHost) - internal.InitRabbitMQ(mqHost, prefetchCount) } func main() { defer mq.Close() mq.Subscriptions.RunConsumer(subscription.Consume, cache) <-make(chan struct{}) + mq.Close() } diff --git a/cmd/observer_worker/main.go b/cmd/observer_worker/main.go index 5e2c3d18c..e126abecd 100644 --- a/cmd/observer_worker/main.go +++ b/cmd/observer_worker/main.go @@ -22,24 +22,22 @@ var ( ) func init() { - _, confPath := internal.ParseArgs("", defaultConfigPath) + _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) - internal.InitConfig(confPath) - logger.InitLogger() - - redisHost := viper.GetString("storage.redis") - mqHost := viper.GetString("observer.rabbitmq.uri") - prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") - platformHandle := viper.GetString("platform") + uri := viper.GetString("observer.rabbitmq.uri") + err := mq.Init(uri) + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) + } + err = mq.Transactions.Declare() + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) + } - cache = internal.InitRedis(redisHost) - internal.InitRabbitMQ(mqHost, prefetchCount) - platform.Init(platformHandle) + platform.Init(viper.GetString("platform")) } func main() { - defer mq.Close() - if len(platform.BlockAPIs) == 0 { logger.Fatal("No APIs to observe") } @@ -98,5 +96,6 @@ func main() { } wg.Wait() + mq.Close() logger.Info("Exiting cleanly") } diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index 4e293b0a4..26ac4396a 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -1,13 +1,12 @@ package main import ( - sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/platform" ) @@ -18,23 +17,22 @@ const ( var ( port, confPath string - engine *gin.Engine + sg *gin.HandlerFunc ) func init() { - port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) - - internal.InitConfig(confPath) - logger.InitLogger() - tmp := sentrygin.New(sentrygin.Options{}) - sg := &tmp - - engine = internal.InitEngine(sg, viper.GetString("gin.mode")) - + port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) platform.Init(viper.GetString("platform")) } func main() { + gin.SetMode(viper.GetString("gin.mode")) + + engine := gin.New() + engine.Use(ginutils.CheckReverseProxy, *sg) + engine.Use(ginutils.CORSMiddleware()) + engine.Use(gin.Logger()) + api.SetupPlatformAPI(engine) internal.SetupGracefulShutdown(port, engine) } diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go index ceb9c0d69..2d2c4b4d9 100644 --- a/cmd/swagger_api/main.go +++ b/cmd/swagger_api/main.go @@ -1,15 +1,14 @@ package main import ( - sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" "github.com/spf13/viper" ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" + "github.com/trustwallet/blockatlas/api" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/logger" - "net/http" + "github.com/trustwallet/blockatlas/pkg/ginutils" ) const ( @@ -19,22 +18,23 @@ const ( var ( port, confPath string - engine *gin.Engine + sg *gin.HandlerFunc ) func init() { - port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) - tmp := sentrygin.New(sentrygin.Options{}) - sg := &tmp - internal.InitConfig(confPath) - logger.InitLogger() - engine = internal.InitEngine(sg, viper.GetString("gin.mode")) + port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) } func main() { - logger.Info("Loading Swagger API") - engine.GET("/", func(c *gin.Context) { - c.Redirect(http.StatusMovedPermanently, "swagger/index.html") - }) + gin.SetMode(viper.GetString("gin.mode")) + engine := gin.New() + + engine.Use(ginutils.CheckReverseProxy, *sg) + engine.Use(ginutils.CORSMiddleware()) + + engine.GET("/", api.GetRoot) + engine.GET("/status", api.GetStatus) engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + + internal.SetupGracefulShutdown(port, engine) } diff --git a/config.yml b/config.yml index da4585987..65444ad81 100644 --- a/config.yml +++ b/config.yml @@ -29,12 +29,10 @@ observer: min: 3s max: 30s rabbitmq: - uri: amqp://rabbit:5672 - consumer: - prefetch_count: 10 + uri: amqp://user:bitnami@rabbit:5672 storage: - redis: redis://localhost:6379 + redis: redis://redis:6379 # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org diff --git a/docker-compose.yml b/docker-compose.yml index 9d8562149..cae42ded5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,7 +53,7 @@ services: rabbit: container_name: rabbit - image: rabbitmq + image: bitnami/rabbitmq ports: - 5672:5672 healthcheck: diff --git a/go.mod b/go.mod index b5168b5f4..de0bb6ac8 100644 --- a/go.mod +++ b/go.mod @@ -3,32 +3,21 @@ module github.com/trustwallet/blockatlas go 1.12 require ( - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect - github.com/Microsoft/go-winio v0.4.14 // indirect - github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/Pantani/httpexpect v2.0.0+incompatible github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.1 github.com/cenkalti/backoff v2.2.1+incompatible github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05 - github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c // indirect github.com/deckarep/golang-set v1.7.1 - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.4.0 // indirect github.com/ethereum/go-ethereum v1.9.10 github.com/getsentry/sentry-go v0.4.0 github.com/gin-gonic/gin v1.5.0 github.com/go-redis/redis v6.15.6+incompatible github.com/hewigovens/go-coincodec v1.0.4 github.com/jinzhu/gorm v1.9.12 - github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/mitchellh/mapstructure v1.1.2 github.com/mr-tron/base58 v1.1.3 - github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/opencontainers/runc v0.1.1 // indirect - github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.4.0 github.com/robfig/cron/v3 v3.0.1 github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 @@ -41,7 +30,5 @@ require ( github.com/swaggo/swag v1.6.5 github.com/wealdtech/go-ens/v3 v3.2.0 golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d - golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect - golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index 849be0207..193793ce6 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,8 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= @@ -23,10 +20,6 @@ github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKz github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Pantani/httpexpect v2.0.0+incompatible h1:P658jo0d3gej0D67KBcSUgpZY76CH1TdxvOfQAmyNu0= @@ -91,8 +84,6 @@ github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05/go.mod h1:lI github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= -github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c h1:8ahmSVELW1wghbjerVAyuEYD5+Dio66RYvSS0iGfL1M= -github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -118,11 +109,6 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= @@ -294,10 +280,7 @@ github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -371,20 +354,10 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c h1:1RHs3t github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= -github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/oschwald/maxminddb-golang v1.3.1/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -396,11 +369,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -446,9 +416,7 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 h1:Pm6R878vxWWWR+Sa3ppsLce/Zq+JNTs6aVvRu13jv9A= github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -464,11 +432,9 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= @@ -554,7 +520,6 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -587,8 +552,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -607,7 +570,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -615,8 +577,6 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -639,14 +599,12 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= diff --git a/internal/init.go b/internal/init.go index f6f47cd30..6ac30c03d 100644 --- a/internal/init.go +++ b/internal/init.go @@ -3,10 +3,10 @@ package internal import ( "flag" "fmt" + sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" "path/filepath" @@ -19,63 +19,58 @@ var ( Date = time.Now().String() ) -func ParseArgs(defaultPort, defaultConfigPath string) (string, string) { +func InitAPI(defaultPort, defaultConfigPath string) (string, string, *gin.HandlerFunc) { var ( port, confPath string + sg gin.HandlerFunc ) + LogVersionInfo() + sg = sentrygin.New(sentrygin.Options{}) + flag.StringVar(&port, "p", defaultPort, "port for api") flag.StringVar(&confPath, "c", defaultConfigPath, "config file for api") flag.Parse() - return port, confPath -} - -func InitRedis(host string) *storage.Storage { - cache := storage.New() - err := cache.Init(host) - if err != nil { - logger.Fatal(err) - } - return cache -} - -func InitConfig(confPath string) { confPath, err := filepath.Abs(confPath) if err != nil { logger.Fatal(err) } config.LoadConfig(confPath) -} + logger.InitLogger() -func InitEngine(handler *gin.HandlerFunc, ginMode string) *gin.Engine { - gin.SetMode(ginMode) - engine := gin.New() - engine.Use(ginutils.CheckReverseProxy, *handler) - engine.Use(ginutils.CORSMiddleware()) - engine.Use(gin.Logger()) + return port, confPath, &sg +} - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) - engine.GET("/status", func(c *gin.Context) { - ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, - }) - }) +func InitAPIWithRedis(defaultPort, defaultConfigPath string) (string, string, *gin.HandlerFunc, *storage.Storage) { + var ( + port, confPath string + cache *storage.Storage + sg gin.HandlerFunc + ) + LogVersionInfo() + cache = storage.New() + sg = sentrygin.New(sentrygin.Options{}) - return engine -} + flag.StringVar(&port, "p", defaultPort, "port for api") + flag.StringVar(&confPath, "c", defaultConfigPath, "config file for api") + flag.Parse() -func InitRabbitMQ(rabbitURI string, prefetchCount int) { - err := mq.Init(rabbitURI) + confPath, err := filepath.Abs(confPath) if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": rabbitURI}) + logger.Fatal(err) } - err = mq.Transactions.Declare() + + config.LoadConfig(confPath) + logger.InitLogger() + + err = cache.Init(viper.GetString("storage.redis")) if err != nil { logger.Fatal(err) } - mq.PrefetchCount = prefetchCount + + return port, confPath, &sg, cache } func LogVersionInfo() { diff --git a/mq/mq.go b/mq/mq.go index c086fddae..bcfebb9b1 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -7,10 +7,9 @@ import ( ) var ( - PrefetchCount int - amqpChan *amqp.Channel - conn *amqp.Connection - queue amqp.Queue + amqpChan *amqp.Channel + conn *amqp.Connection + queue amqp.Queue ) type ( @@ -19,10 +18,8 @@ type ( ) const ( - Transactions Queue = "transactions" - Subscriptions Queue = "subscriptions" - defaultPrefetchCount = 5 - minPrefetchCount = 1 + Transactions Queue = "transactions" + Subscriptions Queue = "subscriptions" ) func Init(uri string) (err error) { @@ -70,17 +67,11 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { return } - if PrefetchCount < minPrefetchCount { - logger.Info("Change prefetch count to default") - PrefetchCount = defaultPrefetchCount - } - err = amqpChan.Qos( - PrefetchCount, + 20, 0, true, ) - if err != nil { logger.Error("no qos limit ", err) } diff --git a/tests/docker_test/data/given_subscriptions_added.json b/tests/docker_test/data/given_subscriptions_added.json deleted file mode 100644 index 6d5efbc84..000000000 --- a/tests/docker_test/data/given_subscriptions_added.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "new_subscriptions": { - "60": [ - "0x0000000000000000000000000000000000000000" - ] - }, - "old_subscriptions": null, - "guid": "0", - "operation": "AddSubscription" - }, - { - "new_subscriptions": { - "118": [ - "0x0000000000000000000000000000000000000001" - ] - }, - "old_subscriptions": null, - "guid": "1", - "operation": "AddSubscription" - }, - { - "new_subscriptions": { - "714": [ - "0x0000000000000000000000000000000000000002" - ] - }, - "old_subscriptions": null, - "guid": "2", - "operation": "AddSubscription" - }, - { - "new_subscriptions": { - "144": [ - "0x0000000000000000000000000000000000000003" - ] - }, - "old_subscriptions": null, - "guid": "3", - "operation": "AddSubscription" - } -] diff --git a/tests/docker_test/data/wanted_subscriptions_added.json b/tests/docker_test/data/wanted_subscriptions_added.json deleted file mode 100644 index c89a4b50d..000000000 --- a/tests/docker_test/data/wanted_subscriptions_added.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "coin": 60, - "address": "0x0000000000000000000000000000000000000000", - "guid": "0" - }, - { - "coin": 118, - "address": "0x0000000000000000000000000000000000000001", - "guid": "1" - }, - { - "coin": 714, - "address": "0x0000000000000000000000000000000000000002", - "guid": "2" - }, - { - "coin": 144, - "address": "0x0000000000000000000000000000000000000003", - "guid": "3" - } -] diff --git a/tests/docker_test/environment_run_test.go b/tests/docker_test/environment_run_test.go deleted file mode 100644 index ca13dd7a1..000000000 --- a/tests/docker_test/environment_run_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build integration - -package docker_test - -import ( - "github.com/trustwallet/blockatlas/tests/docker_test/setup" - "os" - "testing" -) - -func TestMain(m *testing.M) { - setup.RunMQContainer() - setup.RunRedisContainer() - code := m.Run() - setup.StopMQContainer() - setup.StopRedisContainer() - os.Exit(code) -} diff --git a/tests/docker_test/observer_test.go b/tests/docker_test/observer_test.go deleted file mode 100644 index 5bccfff2a..000000000 --- a/tests/docker_test/observer_test.go +++ /dev/null @@ -1,64 +0,0 @@ -// +build integration - -package docker_test - -import ( - "encoding/json" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/subscription" - "github.com/trustwallet/blockatlas/storage" - "github.com/trustwallet/blockatlas/tests/docker_test/setup" - "io/ioutil" - "path/filepath" - "runtime" - "testing" - "time" -) - -func TestSubscriberAddSubscription(t *testing.T) { - _, goFile, _, _ := runtime.Caller(0) - testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_added.json") - testFileGiven, err := ioutil.ReadFile(testFilePathGiven) - if err != nil { - t.Fatal(err) - } - var givenEvents []blockatlas.SubscriptionEvent - if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { - t.Fatal(err) - } - - testFilePathWanted := filepath.Join(filepath.Dir(goFile), "data", "wanted_subscriptions_added.json") - testFileWanted, err := ioutil.ReadFile(testFilePathWanted) - if err != nil { - t.Fatal(err) - } - var wantedEvents []blockatlas.Subscription - if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { - t.Fatal(err) - } - - assert.Nil(t, mq.Subscriptions.Declare()) - - for _, event := range givenEvents { - body, err := json.Marshal(event) - assert.Nil(t, err) - - err = mq.Subscriptions.Publish(body) - assert.Nil(t, err) - - go mq.Subscriptions.RunConsumer(subscription.Consume, setup.Cache) - time.Sleep(time.Second / 5) - } - - result, err := setup.Cache.GetAllHM(storage.ATLAS_OBSERVER) - assert.Nil(t, err) - assert.NotNil(t, result) - - for _, wanted := range wantedEvents { - result, err := setup.Cache.Lookup(wanted.Coin, []string{wanted.Address}) - assert.Nil(t, err) - assert.Equal(t, result[0], wanted) - } -} diff --git a/tests/docker_test/setup/mq.go b/tests/docker_test/setup/mq.go deleted file mode 100644 index cf7e3ea03..000000000 --- a/tests/docker_test/setup/mq.go +++ /dev/null @@ -1,37 +0,0 @@ -package setup - -import ( - "fmt" - "github.com/ory/dockertest" - "github.com/trustwallet/blockatlas/mq" - "log" -) - -var ( - mqResource *dockertest.Resource -) - -func runMQContainer() error { - var err error - pool, err := dockertest.NewPool("") - if err != nil { - log.Fatalf("Could not connect to docker: %s", err) - } - - mqResource, err = pool.Run("rabbitmq", "latest", nil) - if err != nil { - log.Fatalf("Could not start resource: %s", err) - } - - if err = pool.Retry(func() error { - return mq.Init(fmt.Sprintf("amqp://localhost:%s", mqResource.GetPort("5672/tcp"))) - }); err != nil { - return err - } - return nil -} - -func stopMQContainer() error { - mq.Close() - return mqResource.Close() -} \ No newline at end of file diff --git a/tests/docker_test/setup/redis.go b/tests/docker_test/setup/redis.go deleted file mode 100644 index 05b6929e2..000000000 --- a/tests/docker_test/setup/redis.go +++ /dev/null @@ -1,43 +0,0 @@ -package setup - -import ( - "fmt" - "github.com/ory/dockertest" - "github.com/trustwallet/blockatlas/storage" - "log" -) - -var ( - Cache *storage.Storage - redisResource *dockertest.Resource -) - -func runRedisContainer() error { - var err error - pool, err := dockertest.NewPool("") - if err != nil { - log.Fatalf("Could not connect to docker: %s", err) - } - - redisResource, err = pool.Run("redis", "latest", nil) - if err != nil { - log.Fatalf("Could not start resource: %s", err) - } - - if err = pool.Retry(func() error { - var err error - Cache = storage.New() - err = Cache.Init(fmt.Sprintf("redis://localhost:%s", redisResource.GetPort("6379/tcp"))) - if err != nil { - return err - } - return nil - }); err != nil { - return err - } - return nil -} - -func stopRedisContainer() error { - return redisResource.Close() -} \ No newline at end of file diff --git a/tests/docker_test/setup/setup.go b/tests/docker_test/setup/setup.go deleted file mode 100644 index 80daf059c..000000000 --- a/tests/docker_test/setup/setup.go +++ /dev/null @@ -1,27 +0,0 @@ -package setup - -import "log" - -func RunRedisContainer(){ - if err := runRedisContainer(); err != nil{ - log.Fatal(err) - } -} - -func StopRedisContainer(){ - if err := stopRedisContainer(); err != nil{ - log.Fatal(err) - } -} - -func RunMQContainer(){ - if err := runMQContainer(); err != nil{ - log.Fatal(err) - } -} - -func StopMQContainer(){ - if err := stopMQContainer(); err != nil{ - log.Fatal(err) - } -} \ No newline at end of file diff --git a/tests/integration/domains/domains.go b/tests/integration/domains/domains.go index 058e0489e..a5dac9e93 100644 --- a/tests/integration/domains/domains.go +++ b/tests/integration/domains/domains.go @@ -79,15 +79,15 @@ func TestDomains(t *testing.T) { }, false, }, - //{ - // "test @fiotestnet domain", - // "adam@fiotestnet", - // []uint64{coin.ETH}, - // []blockatlas.Resolved{ - // {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, - // }, - // false, - //}, + { + "test @fiotestnet domain", + "adam@fiotestnet", + []uint64{coin.ETH}, + []blockatlas.Resolved{ + {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, + }, + false, + }, { "test batch .crypto domains", "dpantani.crypto", From ac3d9c351cdc866d0f02ca1cf344bf0e4f99291b Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 11 Mar 2020 06:55:16 +0300 Subject: [PATCH 195/506] MQ prefetch && refactor (#958) * Change init package, init functions for services, add optional prefetch count for MQ * Add docker tests (setup got mq and redis) * Add connection check(mq setup) * Try to fix tests * Use another image for rabbit setup * Update docker-compose and config.yml * Add tests, change default prefetch count at config.yml * Fix integration test build * Remove fio domain integration test * Fix critical issue with platform Co-authored-by: prazd --- Makefile | 2 +- cmd/observer_subscriber/main.go | 28 ++++---- cmd/observer_worker/main.go | 25 ++++---- cmd/platform_api/main.go | 22 ++++--- cmd/swagger_api/main.go | 28 ++++---- config.yml | 6 +- docker-compose.yml | 2 +- go.mod | 13 ++++ go.sum | 42 ++++++++++++ internal/init.go | 62 +++++++++--------- mq/mq.go | 21 ++++-- .../data/given_subscriptions_added.json | 42 ++++++++++++ .../data/wanted_subscriptions_added.json | 22 +++++++ tests/docker_test/environment_run_test.go | 18 ++++++ tests/docker_test/observer_test.go | 64 +++++++++++++++++++ tests/docker_test/setup/mq.go | 37 +++++++++++ tests/docker_test/setup/redis.go | 43 +++++++++++++ tests/docker_test/setup/setup.go | 27 ++++++++ tests/integration/domains/domains.go | 18 +++--- 19 files changed, 420 insertions(+), 102 deletions(-) create mode 100644 tests/docker_test/data/given_subscriptions_added.json create mode 100644 tests/docker_test/data/wanted_subscriptions_added.json create mode 100644 tests/docker_test/environment_run_test.go create mode 100644 tests/docker_test/observer_test.go create mode 100644 tests/docker_test/setup/mq.go create mode 100644 tests/docker_test/setup/redis.go create mode 100644 tests/docker_test/setup/setup.go diff --git a/Makefile b/Makefile index b05a97f75..d3e4582ff 100644 --- a/Makefile +++ b/Makefile @@ -193,7 +193,7 @@ go-functional: go-integration: @echo " > Running integration tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration + GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration ./tests/docker_test go-fmt: @echo " > Format all go files" diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index 8713bc489..b6b414b49 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -1,7 +1,6 @@ package main import ( - "github.com/gin-gonic/gin" "github.com/spf13/viper" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" @@ -16,29 +15,26 @@ const ( ) var ( - port, confPath string - cache *storage.Storage - sg *gin.HandlerFunc + confPath string + cache *storage.Storage ) func init() { - _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) - - uri := viper.GetString("observer.rabbitmq.uri") - err := mq.Init(uri) - if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) - } - err = mq.Transactions.Declare() - if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) - } + _, confPath := internal.ParseArgs("", defaultConfigPath) + internal.InitConfig(confPath) + logger.InitLogger() + + redisHost := viper.GetString("storage.redis") + mqHost := viper.GetString("observer.rabbitmq.uri") + prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + + cache = internal.InitRedis(redisHost) + internal.InitRabbitMQ(mqHost, prefetchCount) } func main() { defer mq.Close() mq.Subscriptions.RunConsumer(subscription.Consume, cache) <-make(chan struct{}) - mq.Close() } diff --git a/cmd/observer_worker/main.go b/cmd/observer_worker/main.go index e126abecd..5e2c3d18c 100644 --- a/cmd/observer_worker/main.go +++ b/cmd/observer_worker/main.go @@ -22,22 +22,24 @@ var ( ) func init() { - _, confPath, _, cache = internal.InitAPIWithRedis("", defaultConfigPath) + _, confPath := internal.ParseArgs("", defaultConfigPath) - uri := viper.GetString("observer.rabbitmq.uri") - err := mq.Init(uri) - if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) - } - err = mq.Transactions.Declare() - if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": uri}) - } + internal.InitConfig(confPath) + logger.InitLogger() - platform.Init(viper.GetString("platform")) + redisHost := viper.GetString("storage.redis") + mqHost := viper.GetString("observer.rabbitmq.uri") + prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + platformHandle := viper.GetString("platform") + + cache = internal.InitRedis(redisHost) + internal.InitRabbitMQ(mqHost, prefetchCount) + platform.Init(platformHandle) } func main() { + defer mq.Close() + if len(platform.BlockAPIs) == 0 { logger.Fatal("No APIs to observe") } @@ -96,6 +98,5 @@ func main() { } wg.Wait() - mq.Close() logger.Info("Exiting cleanly") } diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index 26ac4396a..4e293b0a4 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -1,12 +1,13 @@ package main import ( + sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" ) @@ -17,22 +18,23 @@ const ( var ( port, confPath string - sg *gin.HandlerFunc + engine *gin.Engine ) func init() { - port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) + port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) + + internal.InitConfig(confPath) + logger.InitLogger() + tmp := sentrygin.New(sentrygin.Options{}) + sg := &tmp + + engine = internal.InitEngine(sg, viper.GetString("gin.mode")) + platform.Init(viper.GetString("platform")) } func main() { - gin.SetMode(viper.GetString("gin.mode")) - - engine := gin.New() - engine.Use(ginutils.CheckReverseProxy, *sg) - engine.Use(ginutils.CORSMiddleware()) - engine.Use(gin.Logger()) - api.SetupPlatformAPI(engine) internal.SetupGracefulShutdown(port, engine) } diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go index 2d2c4b4d9..ceb9c0d69 100644 --- a/cmd/swagger_api/main.go +++ b/cmd/swagger_api/main.go @@ -1,14 +1,15 @@ package main import ( + sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" "github.com/spf13/viper" ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" - "github.com/trustwallet/blockatlas/api" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/ginutils" + "github.com/trustwallet/blockatlas/pkg/logger" + "net/http" ) const ( @@ -18,23 +19,22 @@ const ( var ( port, confPath string - sg *gin.HandlerFunc + engine *gin.Engine ) func init() { - port, confPath, sg = internal.InitAPI(defaultPort, defaultConfigPath) + port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) + tmp := sentrygin.New(sentrygin.Options{}) + sg := &tmp + internal.InitConfig(confPath) + logger.InitLogger() + engine = internal.InitEngine(sg, viper.GetString("gin.mode")) } func main() { - gin.SetMode(viper.GetString("gin.mode")) - engine := gin.New() - - engine.Use(ginutils.CheckReverseProxy, *sg) - engine.Use(ginutils.CORSMiddleware()) - - engine.GET("/", api.GetRoot) - engine.GET("/status", api.GetStatus) + logger.Info("Loading Swagger API") + engine.GET("/", func(c *gin.Context) { + c.Redirect(http.StatusMovedPermanently, "swagger/index.html") + }) engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - - internal.SetupGracefulShutdown(port, engine) } diff --git a/config.yml b/config.yml index 65444ad81..da4585987 100644 --- a/config.yml +++ b/config.yml @@ -29,10 +29,12 @@ observer: min: 3s max: 30s rabbitmq: - uri: amqp://user:bitnami@rabbit:5672 + uri: amqp://rabbit:5672 + consumer: + prefetch_count: 10 storage: - redis: redis://redis:6379 + redis: redis://localhost:6379 # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org diff --git a/docker-compose.yml b/docker-compose.yml index cae42ded5..9d8562149 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,7 +53,7 @@ services: rabbit: container_name: rabbit - image: bitnami/rabbitmq + image: rabbitmq ports: - 5672:5672 healthcheck: diff --git a/go.mod b/go.mod index de0bb6ac8..b5168b5f4 100644 --- a/go.mod +++ b/go.mod @@ -3,21 +3,32 @@ module github.com/trustwallet/blockatlas go 1.12 require ( + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/Pantani/httpexpect v2.0.0+incompatible github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.1 github.com/cenkalti/backoff v2.2.1+incompatible github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05 + github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c // indirect github.com/deckarep/golang-set v1.7.1 + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.4.0 // indirect github.com/ethereum/go-ethereum v1.9.10 github.com/getsentry/sentry-go v0.4.0 github.com/gin-gonic/gin v1.5.0 github.com/go-redis/redis v6.15.6+incompatible github.com/hewigovens/go-coincodec v1.0.4 github.com/jinzhu/gorm v1.9.12 + github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/mitchellh/mapstructure v1.1.2 github.com/mr-tron/base58 v1.1.3 + github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/runc v0.1.1 // indirect + github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.4.0 github.com/robfig/cron/v3 v3.0.1 github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 @@ -30,5 +41,7 @@ require ( github.com/swaggo/swag v1.6.5 github.com/wealdtech/go-ens/v3 v3.2.0 golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d + golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect + golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index 193793ce6..849be0207 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,11 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= @@ -20,6 +23,10 @@ github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKz github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Pantani/httpexpect v2.0.0+incompatible h1:P658jo0d3gej0D67KBcSUgpZY76CH1TdxvOfQAmyNu0= @@ -84,6 +91,8 @@ github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05/go.mod h1:lI github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c h1:8ahmSVELW1wghbjerVAyuEYD5+Dio66RYvSS0iGfL1M= +github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -109,6 +118,11 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= @@ -280,7 +294,10 @@ github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -354,10 +371,20 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c h1:1RHs3t github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/oschwald/maxminddb-golang v1.3.1/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -369,8 +396,11 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -416,7 +446,9 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 h1:Pm6R878vxWWWR+Sa3ppsLce/Zq+JNTs6aVvRu13jv9A= github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -432,9 +464,11 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= @@ -520,6 +554,7 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -552,6 +587,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -570,6 +607,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -577,6 +615,8 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -599,12 +639,14 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= diff --git a/internal/init.go b/internal/init.go index 6ac30c03d..41b058ce5 100644 --- a/internal/init.go +++ b/internal/init.go @@ -3,10 +3,10 @@ package internal import ( "flag" "fmt" - sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" "path/filepath" @@ -19,58 +19,58 @@ var ( Date = time.Now().String() ) -func InitAPI(defaultPort, defaultConfigPath string) (string, string, *gin.HandlerFunc) { +func ParseArgs(defaultPort, defaultConfigPath string) (string, string) { var ( port, confPath string - sg gin.HandlerFunc ) - LogVersionInfo() - sg = sentrygin.New(sentrygin.Options{}) - flag.StringVar(&port, "p", defaultPort, "port for api") flag.StringVar(&confPath, "c", defaultConfigPath, "config file for api") flag.Parse() - confPath, err := filepath.Abs(confPath) + return port, confPath +} + +func InitRedis(host string) *storage.Storage { + cache := storage.New() + err := cache.Init(host) if err != nil { logger.Fatal(err) } - - config.LoadConfig(confPath) - logger.InitLogger() - - return port, confPath, &sg + return cache } -func InitAPIWithRedis(defaultPort, defaultConfigPath string) (string, string, *gin.HandlerFunc, *storage.Storage) { - var ( - port, confPath string - cache *storage.Storage - sg gin.HandlerFunc - ) - LogVersionInfo() - cache = storage.New() - sg = sentrygin.New(sentrygin.Options{}) - - flag.StringVar(&port, "p", defaultPort, "port for api") - flag.StringVar(&confPath, "c", defaultConfigPath, "config file for api") - flag.Parse() - +func InitConfig(confPath string) { confPath, err := filepath.Abs(confPath) if err != nil { logger.Fatal(err) } config.LoadConfig(confPath) - logger.InitLogger() +} + +func InitEngine(handler *gin.HandlerFunc, ginMode string) *gin.Engine { + gin.SetMode(ginMode) + engine := gin.New() + engine.Use(ginutils.CheckReverseProxy, *handler) + engine.Use(ginutils.CORSMiddleware()) + engine.Use(gin.Logger()) + + engine.OPTIONS("/*path", ginutils.CORSMiddleware()) - err = cache.Init(viper.GetString("storage.redis")) + return engine +} + +func InitRabbitMQ(rabbitURI string, prefetchCount int) { + err := mq.Init(rabbitURI) + if err != nil { + logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": rabbitURI}) + } + err = mq.Transactions.Declare() if err != nil { logger.Fatal(err) } - - return port, confPath, &sg, cache + mq.PrefetchCount = prefetchCount } func LogVersionInfo() { diff --git a/mq/mq.go b/mq/mq.go index bcfebb9b1..c086fddae 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -7,9 +7,10 @@ import ( ) var ( - amqpChan *amqp.Channel - conn *amqp.Connection - queue amqp.Queue + PrefetchCount int + amqpChan *amqp.Channel + conn *amqp.Connection + queue amqp.Queue ) type ( @@ -18,8 +19,10 @@ type ( ) const ( - Transactions Queue = "transactions" - Subscriptions Queue = "subscriptions" + Transactions Queue = "transactions" + Subscriptions Queue = "subscriptions" + defaultPrefetchCount = 5 + minPrefetchCount = 1 ) func Init(uri string) (err error) { @@ -67,11 +70,17 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { return } + if PrefetchCount < minPrefetchCount { + logger.Info("Change prefetch count to default") + PrefetchCount = defaultPrefetchCount + } + err = amqpChan.Qos( - 20, + PrefetchCount, 0, true, ) + if err != nil { logger.Error("no qos limit ", err) } diff --git a/tests/docker_test/data/given_subscriptions_added.json b/tests/docker_test/data/given_subscriptions_added.json new file mode 100644 index 000000000..6d5efbc84 --- /dev/null +++ b/tests/docker_test/data/given_subscriptions_added.json @@ -0,0 +1,42 @@ +[ + { + "new_subscriptions": { + "60": [ + "0x0000000000000000000000000000000000000000" + ] + }, + "old_subscriptions": null, + "guid": "0", + "operation": "AddSubscription" + }, + { + "new_subscriptions": { + "118": [ + "0x0000000000000000000000000000000000000001" + ] + }, + "old_subscriptions": null, + "guid": "1", + "operation": "AddSubscription" + }, + { + "new_subscriptions": { + "714": [ + "0x0000000000000000000000000000000000000002" + ] + }, + "old_subscriptions": null, + "guid": "2", + "operation": "AddSubscription" + }, + { + "new_subscriptions": { + "144": [ + "0x0000000000000000000000000000000000000003" + ] + }, + "old_subscriptions": null, + "guid": "3", + "operation": "AddSubscription" + } +] diff --git a/tests/docker_test/data/wanted_subscriptions_added.json b/tests/docker_test/data/wanted_subscriptions_added.json new file mode 100644 index 000000000..c89a4b50d --- /dev/null +++ b/tests/docker_test/data/wanted_subscriptions_added.json @@ -0,0 +1,22 @@ +[ + { + "coin": 60, + "address": "0x0000000000000000000000000000000000000000", + "guid": "0" + }, + { + "coin": 118, + "address": "0x0000000000000000000000000000000000000001", + "guid": "1" + }, + { + "coin": 714, + "address": "0x0000000000000000000000000000000000000002", + "guid": "2" + }, + { + "coin": 144, + "address": "0x0000000000000000000000000000000000000003", + "guid": "3" + } +] diff --git a/tests/docker_test/environment_run_test.go b/tests/docker_test/environment_run_test.go new file mode 100644 index 000000000..ca13dd7a1 --- /dev/null +++ b/tests/docker_test/environment_run_test.go @@ -0,0 +1,18 @@ +// +build integration + +package docker_test + +import ( + "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "os" + "testing" +) + +func TestMain(m *testing.M) { + setup.RunMQContainer() + setup.RunRedisContainer() + code := m.Run() + setup.StopMQContainer() + setup.StopRedisContainer() + os.Exit(code) +} diff --git a/tests/docker_test/observer_test.go b/tests/docker_test/observer_test.go new file mode 100644 index 000000000..5bccfff2a --- /dev/null +++ b/tests/docker_test/observer_test.go @@ -0,0 +1,64 @@ +// +build integration + +package docker_test + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/subscription" + "github.com/trustwallet/blockatlas/storage" + "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "io/ioutil" + "path/filepath" + "runtime" + "testing" + "time" +) + +func TestSubscriberAddSubscription(t *testing.T) { + _, goFile, _, _ := runtime.Caller(0) + testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_added.json") + testFileGiven, err := ioutil.ReadFile(testFilePathGiven) + if err != nil { + t.Fatal(err) + } + var givenEvents []blockatlas.SubscriptionEvent + if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { + t.Fatal(err) + } + + testFilePathWanted := filepath.Join(filepath.Dir(goFile), "data", "wanted_subscriptions_added.json") + testFileWanted, err := ioutil.ReadFile(testFilePathWanted) + if err != nil { + t.Fatal(err) + } + var wantedEvents []blockatlas.Subscription + if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { + t.Fatal(err) + } + + assert.Nil(t, mq.Subscriptions.Declare()) + + for _, event := range givenEvents { + body, err := json.Marshal(event) + assert.Nil(t, err) + + err = mq.Subscriptions.Publish(body) + assert.Nil(t, err) + + go mq.Subscriptions.RunConsumer(subscription.Consume, setup.Cache) + time.Sleep(time.Second / 5) + } + + result, err := setup.Cache.GetAllHM(storage.ATLAS_OBSERVER) + assert.Nil(t, err) + assert.NotNil(t, result) + + for _, wanted := range wantedEvents { + result, err := setup.Cache.Lookup(wanted.Coin, []string{wanted.Address}) + assert.Nil(t, err) + assert.Equal(t, result[0], wanted) + } +} diff --git a/tests/docker_test/setup/mq.go b/tests/docker_test/setup/mq.go new file mode 100644 index 000000000..cf7e3ea03 --- /dev/null +++ b/tests/docker_test/setup/mq.go @@ -0,0 +1,37 @@ +package setup + +import ( + "fmt" + "github.com/ory/dockertest" + "github.com/trustwallet/blockatlas/mq" + "log" +) + +var ( + mqResource *dockertest.Resource +) + +func runMQContainer() error { + var err error + pool, err := dockertest.NewPool("") + if err != nil { + log.Fatalf("Could not connect to docker: %s", err) + } + + mqResource, err = pool.Run("rabbitmq", "latest", nil) + if err != nil { + log.Fatalf("Could not start resource: %s", err) + } + + if err = pool.Retry(func() error { + return mq.Init(fmt.Sprintf("amqp://localhost:%s", mqResource.GetPort("5672/tcp"))) + }); err != nil { + return err + } + return nil +} + +func stopMQContainer() error { + mq.Close() + return mqResource.Close() +} \ No newline at end of file diff --git a/tests/docker_test/setup/redis.go b/tests/docker_test/setup/redis.go new file mode 100644 index 000000000..05b6929e2 --- /dev/null +++ b/tests/docker_test/setup/redis.go @@ -0,0 +1,43 @@ +package setup + +import ( + "fmt" + "github.com/ory/dockertest" + "github.com/trustwallet/blockatlas/storage" + "log" +) + +var ( + Cache *storage.Storage + redisResource *dockertest.Resource +) + +func runRedisContainer() error { + var err error + pool, err := dockertest.NewPool("") + if err != nil { + log.Fatalf("Could not connect to docker: %s", err) + } + + redisResource, err = pool.Run("redis", "latest", nil) + if err != nil { + log.Fatalf("Could not start resource: %s", err) + } + + if err = pool.Retry(func() error { + var err error + Cache = storage.New() + err = Cache.Init(fmt.Sprintf("redis://localhost:%s", redisResource.GetPort("6379/tcp"))) + if err != nil { + return err + } + return nil + }); err != nil { + return err + } + return nil +} + +func stopRedisContainer() error { + return redisResource.Close() +} \ No newline at end of file diff --git a/tests/docker_test/setup/setup.go b/tests/docker_test/setup/setup.go new file mode 100644 index 000000000..80daf059c --- /dev/null +++ b/tests/docker_test/setup/setup.go @@ -0,0 +1,27 @@ +package setup + +import "log" + +func RunRedisContainer(){ + if err := runRedisContainer(); err != nil{ + log.Fatal(err) + } +} + +func StopRedisContainer(){ + if err := stopRedisContainer(); err != nil{ + log.Fatal(err) + } +} + +func RunMQContainer(){ + if err := runMQContainer(); err != nil{ + log.Fatal(err) + } +} + +func StopMQContainer(){ + if err := stopMQContainer(); err != nil{ + log.Fatal(err) + } +} \ No newline at end of file diff --git a/tests/integration/domains/domains.go b/tests/integration/domains/domains.go index a5dac9e93..058e0489e 100644 --- a/tests/integration/domains/domains.go +++ b/tests/integration/domains/domains.go @@ -79,15 +79,15 @@ func TestDomains(t *testing.T) { }, false, }, - { - "test @fiotestnet domain", - "adam@fiotestnet", - []uint64{coin.ETH}, - []blockatlas.Resolved{ - {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, - }, - false, - }, + //{ + // "test @fiotestnet domain", + // "adam@fiotestnet", + // []uint64{coin.ETH}, + // []blockatlas.Resolved{ + // {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, + // }, + // false, + //}, { "test batch .crypto domains", "dpantani.crypto", From 4c9b547903657cde92514a2bda95c37ec04b5707 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 11 Mar 2020 07:50:39 +0300 Subject: [PATCH 196/506] Fmt and swagger fix (#960) --- cmd/swagger_api/main.go | 1 + observer/observer_test.go | 24 ++++++++++++------------ tests/docker_test/setup/mq.go | 4 ++-- tests/docker_test/setup/redis.go | 6 +++--- tests/docker_test/setup/setup.go | 18 +++++++++--------- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go index ceb9c0d69..617a8590d 100644 --- a/cmd/swagger_api/main.go +++ b/cmd/swagger_api/main.go @@ -37,4 +37,5 @@ func main() { c.Redirect(http.StatusMovedPermanently, "swagger/index.html") }) engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + internal.SetupGracefulShutdown(port, engine) } diff --git a/observer/observer_test.go b/observer/observer_test.go index 9c6fa449d..4c5b9fd2d 100644 --- a/observer/observer_test.go +++ b/observer/observer_test.go @@ -175,8 +175,8 @@ func Test_getDirection(t *testing.T) { args{ blockatlas.Tx{ Meta: blockatlas.NativeTokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, blockatlas.DirectionSelf, @@ -185,8 +185,8 @@ func Test_getDirection(t *testing.T) { args{ blockatlas.Tx{ Meta: blockatlas.NativeTokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", }, }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, blockatlas.DirectionOutgoing, @@ -195,8 +195,8 @@ func Test_getDirection(t *testing.T) { args{ blockatlas.Tx{ Meta: blockatlas.NativeTokenTransfer{ - From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, blockatlas.DirectionIncoming, @@ -205,8 +205,8 @@ func Test_getDirection(t *testing.T) { args{ blockatlas.Tx{ Meta: blockatlas.TokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, blockatlas.DirectionSelf, @@ -215,8 +215,8 @@ func Test_getDirection(t *testing.T) { args{ blockatlas.Tx{ Meta: blockatlas.TokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", }, }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, blockatlas.DirectionOutgoing, @@ -225,8 +225,8 @@ func Test_getDirection(t *testing.T) { args{ blockatlas.Tx{ Meta: blockatlas.TokenTransfer{ - From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, blockatlas.DirectionIncoming, diff --git a/tests/docker_test/setup/mq.go b/tests/docker_test/setup/mq.go index cf7e3ea03..dc1cb294b 100644 --- a/tests/docker_test/setup/mq.go +++ b/tests/docker_test/setup/mq.go @@ -8,7 +8,7 @@ import ( ) var ( - mqResource *dockertest.Resource + mqResource *dockertest.Resource ) func runMQContainer() error { @@ -34,4 +34,4 @@ func runMQContainer() error { func stopMQContainer() error { mq.Close() return mqResource.Close() -} \ No newline at end of file +} diff --git a/tests/docker_test/setup/redis.go b/tests/docker_test/setup/redis.go index 05b6929e2..5ae759e71 100644 --- a/tests/docker_test/setup/redis.go +++ b/tests/docker_test/setup/redis.go @@ -8,8 +8,8 @@ import ( ) var ( - Cache *storage.Storage - redisResource *dockertest.Resource + Cache *storage.Storage + redisResource *dockertest.Resource ) func runRedisContainer() error { @@ -40,4 +40,4 @@ func runRedisContainer() error { func stopRedisContainer() error { return redisResource.Close() -} \ No newline at end of file +} diff --git a/tests/docker_test/setup/setup.go b/tests/docker_test/setup/setup.go index 80daf059c..53210ff47 100644 --- a/tests/docker_test/setup/setup.go +++ b/tests/docker_test/setup/setup.go @@ -2,26 +2,26 @@ package setup import "log" -func RunRedisContainer(){ - if err := runRedisContainer(); err != nil{ +func RunRedisContainer() { + if err := runRedisContainer(); err != nil { log.Fatal(err) } } -func StopRedisContainer(){ - if err := stopRedisContainer(); err != nil{ +func StopRedisContainer() { + if err := stopRedisContainer(); err != nil { log.Fatal(err) } } -func RunMQContainer(){ - if err := runMQContainer(); err != nil{ +func RunMQContainer() { + if err := runMQContainer(); err != nil { log.Fatal(err) } } -func StopMQContainer(){ - if err := stopMQContainer(); err != nil{ +func StopMQContainer() { + if err := stopMQContainer(); err != nil { log.Fatal(err) } -} \ No newline at end of file +} From 675ac335857a8c14d5e04733c9a5b20336a70e94 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 11 Mar 2020 23:48:34 +0300 Subject: [PATCH 197/506] MQ now will crash the app if connection is closed for Publisher, also compose fix (#961) --- docker-compose.yml | 1 - mq/mq.go | 2 +- observer/dispatcher.go | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 9d8562149..7601470db 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,6 @@ services: ports: - 8080:80 links: - - observer_api - platform_api - swagger_api diff --git a/mq/mq.go b/mq/mq.go index c086fddae..60b6a3bea 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -66,7 +66,7 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { nil, ) if err != nil { - logger.Error(err) + logger.Fatal("MQ issue " + err.Error()) return } diff --git a/observer/dispatcher.go b/observer/dispatcher.go index 1e11e67b8..4301249ea 100644 --- a/observer/dispatcher.go +++ b/observer/dispatcher.go @@ -54,7 +54,7 @@ func (d *Dispatcher) postMessageToQueue(message string, rawMessage []byte, logPa err := mq.Transactions.Publish(rawMessage) if err != nil { err = errors.E(err, "Failed to dispatch event", errors.Params{"message": message}, logParams) - logger.Error(err, logger.Params{"message": message}, logParams) + logger.Fatal(err, logger.Params{"message": message}, logParams) } logger.Info("Message dispatched", logger.Params{"message": message}, logParams) } From e3ab9c27524fc3ccb0213bc24d4a28f0516ec794 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 14 Mar 2020 06:21:21 +0300 Subject: [PATCH 198/506] Update README.md --- README.md | 56 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index b5dd96099..e4897016b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,9 @@ # Block Atlas by Trust Wallet ![Go Version](https://img.shields.io/github/go-mod/go-version/TrustWallet/blockatlas) -[![GoDoc](https://godoc.org/github.com/TrustWallet/blockatlas?status.svg)](https://godoc.org/github.com/TrustWallet/blockatlas) [![Build Status](https://dev.azure.com/TrustWallet/Trust%20BlockAtlas/_apis/build/status/TrustWallet.blockatlas?branchName=master)](https://dev.azure.com/TrustWallet/Trust%20BlockAtlas/_build/latest?definitionId=27&branchName=master) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/43834b0c94ad4f6088629aa3e3bb5e94)](https://www.codacy.com/app/TrustWallet/blockatlas?utm_source=github.com&utm_medium=referral&utm_content=TrustWallet/blockatlas&utm_campaign=Badge_Grade) [![Go Report Card](https://goreportcard.com/badge/trustwallet/blockatlas)](https://goreportcard.com/report/TrustWallet/blockatlas) -[![Docker](https://img.shields.io/docker/cloud/build/trustwallet/blockatlas.svg)](https://hub.docker.com/r/trustwallet/blockatlas) > BlockAtlas is a clean explorer API and transaction observer for cryptocurrencies. @@ -39,26 +37,42 @@ The observer API watches the chain for new transactions and generates notificati -## Setup +## Architecture -### Requirements +#### NOTE +Currently Blockatlas is under active development and is not well documented. If you still want to run it on your own or help to contribute, **please** pay attention that currenlty integration, nemwan, functional tests are not working locally without all endpoints. We are fixing that issue and soon you will be able to test all the stuff locally - * [Go Toolchain](https://golang.org/doc/install) versions 1.13+ - * [Redis](https://redis.io/topics/quickstart) instance for platform_observer +Blockatlas allows to: +- Get information about transactions, tokens, staking details, collectibles, crypto domains for supported coins. +- Subscribe for price notifications via Rabbit MQ -### From Source +Platform API is independent service and can work with the specific blockchain only (like bitcoin, ethereum, etc) + +Notifications: + +(Sub Producer) - Subscribe to specific coin [Not implemented at Atlas, write it on your own] + +(Sub Consumer) - Save all the subscriptions to the Redis [Implemented, you can see it at cmd/observer_subscriber] + +(Tx Notifier Producer) - Parse the block, check transactions, find addresses in Redis and push the tx details for these addresses [Implemented, you can see it at cmd/observer_worker] + +(Tx Notifier Consumer) - Notify users, get tx informations by GUID from queue [Not implemented at Atlas, write it on your own] -There are multiple services: +``` +Sub Producer --(Rabbit MQ)--> Sub Consumer --(Redis)--> Tx Notifier Producer --(Rabbit MQ)--> Tx Notifier Consumer --> User +``` -1. Platform API - to get transactions, staking, tokens, domain lookup for supported coins in common format -2. Observer API - to subscribe several addresses on different supported coins and receive message -3. Swagger API - swagger for all handlers of 1-3 APIs. You need to route requests to them on you own (nginx) +The whole flow is not availible at Atlas repo. We will have integration tests with it. Also there will be examples of all instances soon. -There are workers that are linked with Observer API and Market API: +## Setup + +### Requirements -5. Platform Observer - fetching latest blocks, parse them to common block specification, check subscribed addresses - send message to queue. We use Redis to get information about subscribed addresses per coin with webhooks and caching latest block that was processed by observer + * [Go Toolchain](https://golang.org/doc/install) versions 1.13+ + * [Redis](https://redis.io/topics/quickstart) instance for platform_observer + * [Rabbit MQ](https://www.rabbitmq.com/#getstarted) using to pass subscriptions and send transaction notifications -Observer API <-> Redis <-> Platform Observer +### From Source #### IMPORTANT @@ -69,22 +83,22 @@ ATLAS_PLATFORM=ethereum go run main.go ``` You will run platform API for Ethereum coin only. You can run 30 coins with 30 binaries for scalability and sustainability. Howevever, you can run all of them at once by using ```ATLAS_PLATFORM=all``` env param -It works the same for platoform_observer - you can run all observer at 1 binary or 30 coins per 30 binaries +It works the same for observer_worker - you can run all observer at 1 binary or 30 coins per 30 binaries ```shell # Download source to $GOPATH go get -u github.com/trustwallet/blockatlas cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas -# Start platform_observer with the path to the config.yml ./ -go build -o platform-observer-bin cmd/platform_observer/main.go && ./platform-observer-bin -c config.yml +# Start observer_worker with the path to the config.yml ./ +go build -o observer_worker-bin cmd/observer_worker/main.go && ./observer_worker-bin -c config.yml + +# Start observer_subscriber with the path to the config.yml ./ +go build -o observer_subscriber-bin cmd/observer_subscriber/main.go && ./observer_subscriber-bin -c config.yml # Start Platform API server at port 8420 with the path to the config.yml ./ go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 -c config.yml -# Start Observer API server at port 8422 with the path to the config.yml ./ -go build -o observer-api-bin cmd/observer-api/main.go && ./observer-api-bin -p 8422 -c config.yml - # Startp Swagger API server at port 8422 with the path to the config.yml ./ go build -o swagger-api-bin cmd/swagger-api/main.go && ./swagger-api-bin -p 8423 ``` @@ -121,8 +135,6 @@ If you need to start one service: ```shell # Run only platform API docker-compose start platform_api -# Run only observer for addresses and api for it -docker-compose start platform_observer observer_api redis # Run swagger api docker-compose start swagger_api ``` From f4eddc3de32d72e13cfba70f9b0296b5f80f0a28 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> Date: Sun, 15 Mar 2020 20:42:43 +0300 Subject: [PATCH 199/506] [MQ & Cache] Add workers for restore connection (#964) --- cmd/observer_subscriber/main.go | 8 +++++++ cmd/observer_worker/main.go | 7 +++++++ internal/init.go | 4 ---- mq/mq.go | 37 +++++++++++++++++++++++++++++++++ storage/storage.go | 23 ++++++++++++++++++++ 5 files changed, 75 insertions(+), 4 deletions(-) diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index b6b414b49..390ade380 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -8,6 +8,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/subscription" "github.com/trustwallet/blockatlas/storage" + "time" ) const ( @@ -30,11 +31,18 @@ func init() { prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") cache = internal.InitRedis(redisHost) + internal.InitRabbitMQ(mqHost, prefetchCount) + + go mq.FatalWorker(time.Second * 10) + go storage.RestoreConnectionWorker(cache, redisHost, time.Second * 10) } func main() { defer mq.Close() + if err := mq.Subscriptions.Declare(); err != nil{ + logger.Fatal(err) + } mq.Subscriptions.RunConsumer(subscription.Consume, cache) <-make(chan struct{}) } diff --git a/cmd/observer_worker/main.go b/cmd/observer_worker/main.go index 5e2c3d18c..4782356fc 100644 --- a/cmd/observer_worker/main.go +++ b/cmd/observer_worker/main.go @@ -10,6 +10,7 @@ import ( "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/storage" "sync" + "time" ) const ( @@ -35,10 +36,16 @@ func init() { cache = internal.InitRedis(redisHost) internal.InitRabbitMQ(mqHost, prefetchCount) platform.Init(platformHandle) + + go mq.RestoreConnectionWorker(mqHost, mq.Transactions, time.Second * 10) + go storage.RestoreConnectionWorker(cache, redisHost, time.Second * 10) } func main() { defer mq.Close() + if err := mq.Transactions.Declare(); err != nil{ + logger.Fatal(err) + } if len(platform.BlockAPIs) == 0 { logger.Fatal("No APIs to observe") diff --git a/internal/init.go b/internal/init.go index 41b058ce5..699a7ac19 100644 --- a/internal/init.go +++ b/internal/init.go @@ -66,10 +66,6 @@ func InitRabbitMQ(rabbitURI string, prefetchCount int) { if err != nil { logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": rabbitURI}) } - err = mq.Transactions.Declare() - if err != nil { - logger.Fatal(err) - } mq.PrefetchCount = prefetchCount } diff --git a/mq/mq.go b/mq/mq.go index 60b6a3bea..756e516a7 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -4,6 +4,7 @@ import ( "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" + "time" ) var ( @@ -89,3 +90,39 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { go consumer(data, cache) } } + +func RestoreConnectionWorker(uri string, queue Queue, timeout time.Duration) { + logger.Info("Run MQ RestoreConnectionWorker") + for { + if conn.IsClosed() { + for { + logger.Warn("MQ is not available now") + logger.Warn("Trying to connect to MQ...") + if err := Init(uri); err != nil { + logger.Warn("MQ is still unavailable") + time.Sleep(timeout) + continue + } + if err := queue.Declare(); err != nil { + logger.Warn("Can't declare queues:", queue) + time.Sleep(timeout) + continue + } else { + logger.Info("MQ connection restored") + break + } + } + } + time.Sleep(timeout) + } +} + +func FatalWorker(timeout time.Duration){ + logger.Info("Run FatalWorker") + for { + if conn.IsClosed() { + logger.Fatal("MQ is not available now") + } + time.Sleep(timeout) + } +} diff --git a/storage/storage.go b/storage/storage.go index 9182843a7..edd55563f 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -2,7 +2,9 @@ package storage import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/storage/redis" + "time" ) type Storage struct { @@ -16,6 +18,27 @@ func New() *Storage { return s } +func RestoreConnectionWorker(storage *Storage, uri string, timeout time.Duration) { + logger.Info("Run Redis RestoreConnectionWorker") + for { + if !storage.IsReady() { + for { + logger.Warn("Redis is not available now") + logger.Warn("Trying to connect to MQ...") + if err := storage.Init(uri); err != nil { + logger.Warn("Redis is still unavailable") + time.Sleep(timeout) + continue + } else { + logger.Info("Redis connection restored") + break + } + } + } + time.Sleep(timeout) + } +} + type Tracker interface { GetBlockNumber(coin uint) (int64, error) SetBlockNumber(coin uint, num int64) error From f6b8b5381db733a3522a2387c84df730f46f3d41 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Mon, 16 Mar 2020 23:08:22 +0800 Subject: [PATCH 200/506] Add NEAR coin definition (#965) --- coin/coins.go | 16 +++++++++++++++- coin/coins.yml | 8 ++++++++ config.yml | 3 +++ platform/near/base.go | 21 +++++++++++++++++++++ platform/near/client.go | 9 +++++++++ platform/near/transaction.go | 10 ++++++++++ platform/platform.go | 3 +++ 7 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 platform/near/base.go create mode 100644 platform/near/client.go create mode 100644 platform/near/transaction.go diff --git a/coin/coins.go b/coin/coins.go index cda0cb6b0..53613fd5a 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2020-02-02 17:57:53.145329 -0300 -03 m=+0.001556851 +// 2020-03-15 10:51:30.879337 +0800 CST m=+0.001247730 // using data from coins.yml package coin @@ -71,6 +71,7 @@ const ( DGB = 20 ONE = 1023 KSM = 434 + NEAR = 397 ) var Coins = map[uint]Coin{ @@ -534,6 +535,16 @@ var Coins = map[uint]Coin{ MinConfirmations: 0, SampleAddr: "HewiDTQv92L2bVtkziZC8ASxrFUxr6ajQ62RXAnwQ8FDVmg", }, + NEAR: { + ID: 397, + Handle: "near", + Symbol: "NEAR", + Name: "NEAR", + Decimals: 18, + BlockTime: 2000, + MinConfirmations: 0, + SampleAddr: "NEAR6Y66fCzeKqWiwxoPox5oGeDN9VhNCu7CEQ9M86iniqoN9vg2X", + }, } func Ethereum() Coin { return Coins[ETH] @@ -673,4 +684,7 @@ func Harmony() Coin { func Kusama() Coin { return Coins[KSM] } +func Near() Coin { + return Coins[NEAR] +} diff --git a/coin/coins.yml b/coin/coins.yml index 8b2a59822..df23ee9e3 100644 --- a/coin/coins.yml +++ b/coin/coins.yml @@ -363,3 +363,11 @@ decimals: 12 blockTime: 6000 sampleAddress: 'HewiDTQv92L2bVtkziZC8ASxrFUxr6ajQ62RXAnwQ8FDVmg' + +- id: 397 + symbol: NEAR + handle: near + name: NEAR + decimals: 18 + blockTime: 2000 + sampleAddress: 'NEAR6Y66fCzeKqWiwxoPox5oGeDN9VhNCu7CEQ9M86iniqoN9vg2X' diff --git a/config.yml b/config.yml index da4585987..462139f2f 100644 --- a/config.yml +++ b/config.yml @@ -211,3 +211,6 @@ kava: kusama: api: https://kusama.subscan.io/api + +near: + api: https://staging-rpc.nearprotocol.com diff --git a/platform/near/base.go b/platform/near/base.go new file mode 100644 index 000000000..53407e774 --- /dev/null +++ b/platform/near/base.go @@ -0,0 +1,21 @@ +package near + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func Init(api string) *Platform { + p := &Platform{ + client: Client{blockatlas.InitClient(api)}, + } + return p +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.NEAR] +} diff --git a/platform/near/client.go b/platform/near/client.go new file mode 100644 index 000000000..f39de7d88 --- /dev/null +++ b/platform/near/client.go @@ -0,0 +1,9 @@ +package near + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Client struct { + blockatlas.Request +} diff --git a/platform/near/transaction.go b/platform/near/transaction.go new file mode 100644 index 000000000..0f9421868 --- /dev/null +++ b/platform/near/transaction.go @@ -0,0 +1,10 @@ +package near + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + normalized := make([]blockatlas.Tx, 0) + return normalized, nil +} diff --git a/platform/platform.go b/platform/platform.go index 60267e021..ce97f1d9e 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -2,6 +2,7 @@ package platform import ( "fmt" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -17,6 +18,7 @@ import ( "github.com/trustwallet/blockatlas/platform/icon" "github.com/trustwallet/blockatlas/platform/iotex" "github.com/trustwallet/blockatlas/platform/nano" + "github.com/trustwallet/blockatlas/platform/near" "github.com/trustwallet/blockatlas/platform/nebulas" "github.com/trustwallet/blockatlas/platform/nimiq" "github.com/trustwallet/blockatlas/platform/ontology" @@ -99,6 +101,7 @@ func getPlatformMap() blockatlas.Platforms { coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN)), coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), + coin.Near().Handle: near.Init(GetApiVar(coin.NEAR)), } } From 8e00b7387c40799e5a3f9654875c2947f6aac881 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Mon, 16 Mar 2020 18:50:55 +0300 Subject: [PATCH 201/506] Remove unused packages, refactor pkg, run fmt (#967) * Remove unused packages, refactor pkg, run fmt * Fix Makefile --- Makefile | 38 ++--- cmd/observer_subscriber/main.go | 8 +- cmd/observer_worker/main.go | 8 +- mq/mq.go | 3 +- pkg/blockatlas/api.go | 117 ++++++------- pkg/blockatlas/block.go | 13 -- pkg/blockatlas/collectibles.go | 72 ++++---- pkg/blockatlas/jsonrpc.go | 36 ++-- pkg/blockatlas/marketdata.go | 115 ------------- pkg/blockatlas/marketdata_test.go | 70 -------- pkg/blockatlas/models.go | 16 +- pkg/blockatlas/observer.go | 46 +++-- pkg/blockatlas/staking.go | 114 +++++++------ pkg/blockatlas/tx.go | 274 +++++++++++++++--------------- pkg/storage/sql/postgres.go | 32 ---- pkg/storage/sql/sql.go | 87 ---------- storage/storage.go | 2 +- 17 files changed, 379 insertions(+), 672 deletions(-) delete mode 100644 pkg/blockatlas/block.go delete mode 100644 pkg/blockatlas/marketdata.go delete mode 100644 pkg/blockatlas/marketdata_test.go delete mode 100644 pkg/storage/sql/postgres.go delete mode 100644 pkg/storage/sql/sql.go diff --git a/Makefile b/Makefile index d3e4582ff..09735b9d2 100644 --- a/Makefile +++ b/Makefile @@ -44,34 +44,34 @@ install: go-get ## start: Start API, Observer and Sync in development mode. start: - @bash -c "$(MAKE) clean compile start-platform-api start-platform-observer start-observer-api start-market-observer start-market-api" + @bash -c "$(MAKE) clean compile start-platform-api start-observer-worker start-observer-subscriber" -## start-api: Start API in development mode. +## start-api: Start platform api in development mode. start-platform-api: stop - @echo " > Starting $(PROJECT_NAME) API" + @echo " > Starting $(PROJECT_NAME)" @-$(GOBIN)/$(API_SERVICE)/platform_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_API) @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" @echo " > Error log: $(STDERR)" -## start-observer: Start Observer in development mode. -start-platform-observer: stop - @echo " > Starting $(PROJECT_NAME) Observer" - @-$(GOBIN)/$(OBSERVER_SERVICE)/platform_observer -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER) - @cat $(PID_OBSERVER) | sed "/^/s/^/ \> Observer PID: /" +## start-swagger-api: Start swagger api in development mode. +start-swagger-api: stop + @echo " > Starting $(PROJECT_NAME)" + @-$(GOBIN)/$(SWAGGER_API)/swagger_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SWAGGER_API) + @cat $(PID_SWAGGER_API) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" -## start-observer: Start Observer in development mode. -start-observer-api: stop - @echo " > Starting $(PROJECT_NAME) Observer" - @-$(GOBIN)/$(OBSERVER_SUBSCRIBER)/observer_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_SUBSCRIBER) - @cat $(PID_OBSERVER_SUBSCRIBER) | sed "/^/s/^/ \> Observer PID: /" +## start-observer-worker: Start swagger api in development mode. +start-observer-worker: stop + @echo " > Starting $(PROJECT_NAME)" + @-$(GOBIN)/$(OBSERVER_SERVICE)/observer_worker -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER) + @cat $(PID_OBSERVER) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" -## start-sync-market-api: Start Sync market api in development mode. -start-swagger-api: stop - @echo " > Starting $(PROJECT_NAME) Sync API" - @-$(GOBIN)/$(SWAGGER_API)/swagger_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SWAGGER_API) - @cat $(PID_SWAGGER_API) | sed "/^/s/^/ \> Sync PID: /" +## start-observer-worker: Start swagger api in development mode. +start-observer-subscriber: stop + @echo " > Starting $(PROJECT_NAME)" + @-$(GOBIN)/$(OBSERVER_SUBSCRIBER)/observer_subscriber -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_SUBSCRIBER) + @cat $(PID_OBSERVER_SUBSCRIBER) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" ## stop: Stop development mode. @@ -164,7 +164,7 @@ go-build: @echo " > Building observer_worker binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SERVICE)/observer_worker ./cmd/$(OBSERVER_SERVICE) @echo " > Building observer_subscriber binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(observer_subscriber)/observer_subscriber ./cmd/$(OBSERVER_SUBSCRIBER) + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SUBSCRIBER)/observer_subscriber ./cmd/$(OBSERVER_SUBSCRIBER) @echo " > Building swagger_api binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SWAGGER_API)/swagger_api ./cmd/$(SWAGGER_API) diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index 390ade380..f3830265f 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -21,7 +21,7 @@ var ( ) func init() { - _, confPath := internal.ParseArgs("", defaultConfigPath) + _, confPath = internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) logger.InitLogger() @@ -33,14 +33,14 @@ func init() { cache = internal.InitRedis(redisHost) internal.InitRabbitMQ(mqHost, prefetchCount) - + go mq.FatalWorker(time.Second * 10) - go storage.RestoreConnectionWorker(cache, redisHost, time.Second * 10) + go storage.RestoreConnectionWorker(cache, redisHost, time.Second*10) } func main() { defer mq.Close() - if err := mq.Subscriptions.Declare(); err != nil{ + if err := mq.Subscriptions.Declare(); err != nil { logger.Fatal(err) } mq.Subscriptions.RunConsumer(subscription.Consume, cache) diff --git a/cmd/observer_worker/main.go b/cmd/observer_worker/main.go index 4782356fc..652117461 100644 --- a/cmd/observer_worker/main.go +++ b/cmd/observer_worker/main.go @@ -23,7 +23,7 @@ var ( ) func init() { - _, confPath := internal.ParseArgs("", defaultConfigPath) + _, confPath = internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) logger.InitLogger() @@ -37,13 +37,13 @@ func init() { internal.InitRabbitMQ(mqHost, prefetchCount) platform.Init(platformHandle) - go mq.RestoreConnectionWorker(mqHost, mq.Transactions, time.Second * 10) - go storage.RestoreConnectionWorker(cache, redisHost, time.Second * 10) + go mq.RestoreConnectionWorker(mqHost, mq.Transactions, time.Second*10) + go storage.RestoreConnectionWorker(cache, redisHost, time.Second*10) } func main() { defer mq.Close() - if err := mq.Transactions.Declare(); err != nil{ + if err := mq.Transactions.Declare(); err != nil { logger.Fatal(err) } diff --git a/mq/mq.go b/mq/mq.go index 756e516a7..5804b8c6d 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -11,7 +11,6 @@ var ( PrefetchCount int amqpChan *amqp.Channel conn *amqp.Connection - queue amqp.Queue ) type ( @@ -117,7 +116,7 @@ func RestoreConnectionWorker(uri string, queue Queue, timeout time.Duration) { } } -func FatalWorker(timeout time.Duration){ +func FatalWorker(timeout time.Duration) { logger.Info("Run FatalWorker") for { if conn.IsClosed() { diff --git a/pkg/blockatlas/api.go b/pkg/blockatlas/api.go index 123d246af..1d4bfb1b4 100644 --- a/pkg/blockatlas/api.go +++ b/pkg/blockatlas/api.go @@ -5,72 +5,73 @@ import ( "github.com/trustwallet/blockatlas/coin" ) -// Platform can be used to access a crypto service -type Platform interface { - Coin() coin.Coin -} +type ( + // Platform can be used to access a crypto service + Platform interface { + Coin() coin.Coin + } -// TxAPI provides transaction lookups -type TxAPI interface { - Platform - GetTxsByAddress(address string) (TxPage, error) -} + // TxAPI provides transaction lookups + TxAPI interface { + Platform + GetTxsByAddress(address string) (TxPage, error) + } -// TokenTxAPI provides token transaction lookups -type TokenTxAPI interface { - Platform - GetTokenTxsByAddress(address, token string) (TxPage, error) -} + // TokenTxAPI provides token transaction lookups + TokenTxAPI interface { + Platform + GetTokenTxsByAddress(address, token string) (TxPage, error) + } -// TokenAPI provides token lookups -type TokenAPI interface { - Platform - GetTokenListByAddress(address string) (TokenPage, error) -} + // TokenAPI provides token lookups + TokenAPI interface { + Platform + GetTokenListByAddress(address string) (TokenPage, error) + } -// BlockAPI provides block information and lookups -type BlockAPI interface { - Platform - CurrentBlockNumber() (int64, error) - GetBlockByNumber(num int64) (*Block, error) -} + // BlockAPI provides block information and lookups + BlockAPI interface { + Platform + CurrentBlockNumber() (int64, error) + GetBlockByNumber(num int64) (*Block, error) + } -// AddressAPI provides address information -type AddressAPI interface { - Platform - GetAddressesFromXpub(xpub string) ([]string, error) -} + // AddressAPI provides address information + AddressAPI interface { + Platform + GetAddressesFromXpub(xpub string) ([]string, error) + } -// StakingAPI provides staking information -type StakeAPI interface { - Platform - UndelegatedBalance(address string) (string, error) - GetDetails() StakingDetails - GetValidators() (ValidatorPage, error) - GetDelegations(address string) (DelegationsPage, error) -} + // StakingAPI provides staking information + StakeAPI interface { + Platform + UndelegatedBalance(address string) (string, error) + GetDetails() StakingDetails + GetValidators() (ValidatorPage, error) + GetDelegations(address string) (DelegationsPage, error) + } -type CollectionAPI interface { - Platform - GetCollections(owner string) (CollectionPage, error) - GetCollectibles(owner, collectibleID string) (CollectiblePage, error) + CollectionAPI interface { + Platform + GetCollections(owner string) (CollectionPage, error) + GetCollectibles(owner, collectibleID string) (CollectiblePage, error) - //TODO: remove once most of the clients will be updated (deadline: March 17th) - OldGetCollections(owner string) (CollectionPage, error) - OldGetCollectibles(owner, collectibleID string) (CollectiblePage, error) + OldGetCollections(owner string) (CollectionPage, error) + OldGetCollectibles(owner, collectibleID string) (CollectiblePage, error) - GetCollectionsV4(owner string) (CollectionPage, error) - GetCollectiblesV4(owner, collectibleID string) (CollectiblePage, error) -} + GetCollectionsV4(owner string) (CollectionPage, error) + GetCollectiblesV4(owner, collectibleID string) (CollectiblePage, error) + } -// CustomAPI provides custom HTTP routes -type CustomAPI interface { - Platform - RegisterRoutes(router gin.IRouter) -} + // CustomAPI provides custom HTTP routes + CustomAPI interface { + Platform + RegisterRoutes(router gin.IRouter) + } -// NamingServiceAPI provides public name service domains HTTP routes -type NamingServiceAPI interface { - Platform - Lookup(coins []uint64, name string) ([]Resolved, error) -} + // NamingServiceAPI provides public name service domains HTTP routes + NamingServiceAPI interface { + Platform + Lookup(coins []uint64, name string) ([]Resolved, error) + } +) diff --git a/pkg/blockatlas/block.go b/pkg/blockatlas/block.go deleted file mode 100644 index 14e54f03a..000000000 --- a/pkg/blockatlas/block.go +++ /dev/null @@ -1,13 +0,0 @@ -package blockatlas - -type Block struct { - Number int64 `json:"number"` - ID string `json:"id,omitempty"` - Txs []Tx `json:"txs"` -} - -type Subscription struct { - Coin uint `json:"coin"` - Address string `json:"address"` - GUID string `json:"guid"` -} diff --git a/pkg/blockatlas/collectibles.go b/pkg/blockatlas/collectibles.go index d8829b665..74a272e35 100644 --- a/pkg/blockatlas/collectibles.go +++ b/pkg/blockatlas/collectibles.go @@ -1,40 +1,42 @@ package blockatlas -type Collection struct { - Id string `json:"id"` - Name string `json:"name"` - Symbol string `json:"symbol"` - Slug string `json:"slug"` - ImageUrl string `json:"image_url"` - Description string `json:"description"` - ExternalLink string `json:"external_link"` - Total int `json:"total"` - CategoryAddress string `json:"category_address"` - Address string `json:"address"` - Coin uint `json:"coin"` - // Delete in the future version, as it's now part of Collectible - Version string `json:"nft_version"` - Type string `json:"type"` -} +type ( + Collection struct { + Id string `json:"id"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Slug string `json:"slug"` + ImageUrl string `json:"image_url"` + Description string `json:"description"` + ExternalLink string `json:"external_link"` + Total int `json:"total"` + CategoryAddress string `json:"category_address"` + Address string `json:"address"` + Coin uint `json:"coin"` + // Delete in the future version, as it's now part of Collectible + Version string `json:"nft_version"` + Type string `json:"type"` + } -type CollectionPage []Collection + CollectionPage []Collection -type Collectible struct { - ID string `json:"id"` - CollectionID string `json:"collection_id"` - TokenID string `json:"token_id"` - CategoryContract string `json:"category_contract"` - // Deprecated: for support old client, ContractAddress eq CollectionID - ContractAddress string `json:"contract_address"` - Category string `json:"category"` - ImageUrl string `json:"image_url"` - ExternalLink string `json:"external_link"` - ProviderLink string `json:"provider_link"` - Type string `json:"type"` - Description string `json:"description"` - Coin uint `json:"coin"` - Name string `json:"name"` - Version string `json:"nft_version"` -} + Collectible struct { + ID string `json:"id"` + CollectionID string `json:"collection_id"` + TokenID string `json:"token_id"` + CategoryContract string `json:"category_contract"` + // Deprecated: for support old client, ContractAddress eq CollectionID + ContractAddress string `json:"contract_address"` + Category string `json:"category"` + ImageUrl string `json:"image_url"` + ExternalLink string `json:"external_link"` + ProviderLink string `json:"provider_link"` + Type string `json:"type"` + Description string `json:"description"` + Coin uint `json:"coin"` + Name string `json:"name"` + Version string `json:"nft_version"` + } -type CollectiblePage []Collectible + CollectiblePage []Collectible +) diff --git a/pkg/blockatlas/jsonrpc.go b/pkg/blockatlas/jsonrpc.go index b9a187dd3..d96d76bb3 100644 --- a/pkg/blockatlas/jsonrpc.go +++ b/pkg/blockatlas/jsonrpc.go @@ -9,26 +9,28 @@ const ( JsonRpcVersion = "2.0" ) -type RpcRequests []*RpcRequest +type ( + RpcRequests []*RpcRequest -type RpcRequest struct { - JsonRpc string `json:"jsonrpc"` - Method string `json:"method"` - Params interface{} `json:"params,omitempty"` - Id string `json:"id,omitempty"` -} + RpcRequest struct { + JsonRpc string `json:"jsonrpc"` + Method string `json:"method"` + Params interface{} `json:"params,omitempty"` + Id string `json:"id,omitempty"` + } -type RpcResponse struct { - JsonRpc string `json:"jsonrpc"` - Error *RpcError `json:"error,omitempty"` - Result interface{} `json:"result,omitempty"` - Id string `json:"id,omitempty"` -} + RpcResponse struct { + JsonRpc string `json:"jsonrpc"` + Error *RpcError `json:"error,omitempty"` + Result interface{} `json:"result,omitempty"` + Id string `json:"id,omitempty"` + } -type RpcError struct { - Code int `json:"code"` - Message string `json:"message"` -} + RpcError struct { + Code int `json:"code"` + Message string `json:"message"` + } +) func (r *RpcResponse) GetObject(toType interface{}) error { js, err := json.Marshal(r.Result) diff --git a/pkg/blockatlas/marketdata.go b/pkg/blockatlas/marketdata.go deleted file mode 100644 index 7e6c14f5e..000000000 --- a/pkg/blockatlas/marketdata.go +++ /dev/null @@ -1,115 +0,0 @@ -package blockatlas - -import ( - "math/big" - "time" -) - -const ( - TypeCoin CoinType = "coin" - TypeToken CoinType = "token" - - DefaultCurrency = "USD" -) - -type CoinType string - -type TickerResponse struct { - Currency string `json:"currency"` - Docs Tickers `json:"docs"` -} - -type Ticker struct { - Coin uint `json:"coin"` - CoinName string `json:"coin_name,omitempty"` - TokenId string `json:"token_id,omitempty"` - CoinType CoinType `json:"type,omitempty"` - Price TickerPrice `json:"price,omitempty"` - LastUpdate time.Time `json:"last_update,omitempty"` - Error string `json:"error,omitempty"` -} - -type ChartData struct { - Prices []ChartPrice `json:"prices,omitempty"` - Error string `json:"error,omitempty"` -} - -type ChartPrice struct { - Price float64 `json:"price"` - Date int64 `json:"date"` -} - -type ChartCoinInfo struct { - Vol24 float64 `json:"volume_24"` - MarketCap float64 `json:"market_cap"` - CirculatingSupply float64 `json:"circulating_supply"` - TotalSupply float64 `json:"total_supply"` - Info *CoinInfo `json:"info,omitempty"` -} - -type CoinInfo struct { - Name string `json:"name,omitempty"` - Website string `json:"website,omitempty"` - SourceCode string `json:"source_code,omitempty"` - WhitePaper string `json:"white_paper,omitempty"` - Description string `json:"description,omitempty"` - ShortDescription string `json:"short_description,omitempty"` - Explorers []Link `json:"explorers,omitempty"` - Socials []SocialLink `json:"socials,omitempty"` - DataSource string `json:"data_source,omitempty"` -} - -type SocialLink struct { - Name string `json:"name"` - Url string `json:"url"` - Handle string `json:"handle"` -} - -type Link struct { - Name string `json:"name"` - Url string `json:"url"` -} - -func (t *Ticker) SetCoinId(coinId uint) { - t.Coin = coinId - t.CoinName = "" - t.Price.Provider = "" - t.Price.Currency = "" -} - -type TickerPrice struct { - Value float64 `json:"value"` - Change24h float64 `json:"change_24h"` - Currency string `json:"currency,omitempty"` - Provider string `json:"provider,omitempty"` -} - -type Rate struct { - Currency string `json:"currency"` - Rate float64 `json:"rate"` - Timestamp int64 `json:"timestamp"` - PercentChange24h *big.Float `json:"percent_change_24h,omitempty"` - Provider string `json:"provider,omitempty"` -} - -type Rates []Rate -type Tickers []*Ticker - -func (ts Tickers) ApplyRate(currency string, rate float64, percentChange24h *big.Float) { - for _, t := range ts { - t.ApplyRate(currency, rate, percentChange24h) - } -} - -func (t *Ticker) ApplyRate(currency string, rate float64, percentChange24h *big.Float) { - if t.Price.Currency == currency { - return - } - t.Price.Value *= rate - t.Price.Currency = currency - - if percentChange24h != nil { - change24h, _ := percentChange24h.Float64() - t.Price.Change24h -= change24h - } -} diff --git a/pkg/blockatlas/marketdata_test.go b/pkg/blockatlas/marketdata_test.go deleted file mode 100644 index f2bd81a43..000000000 --- a/pkg/blockatlas/marketdata_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package blockatlas - -import ( - "github.com/stretchr/testify/assert" - "math/big" - "testing" -) - -func TestTicker_ApplyRate(t *testing.T) { - type args struct { - price float64 - percentChange24h float64 - rate float64 - rateChange24h float64 - currency string - } - type want struct { - price float64 - percentChange24h float64 - } - tests := []struct { - name string - args args - want want - }{ - { - "apply rate 1", - args{443, -0.44, 344, -0.33, "BTC"}, - want{152392, -0.10999999999999999}, - }, { - "apply rate 2", - args{1111.22, 3.04, 0.88, -2.12, "BTC"}, - want{977.8736, 5.16}, - }, { - "apply rate 3", - args{3.33, -1.02, 22.3, 1.02, "BTC"}, - want{74.259, -2.04}, - }, { - "apply rate 4", - args{9.3332, -2, 22, -0.555, "BTC"}, - want{205.3304, -1.4449999999999998}, - }, { - "apply rate 5", - args{0.00000001, 0, 0.2, 1.333, "BTC"}, - want{0.000000002, -1.333}, - }, { - "apply rate 6", - args{0.00000001, -0.0003, 10, -0.0003, "BTC"}, - want{0.0000001, 0}, - }, { - "apply for same currency", - args{0.33333, -0.0003, 10, -0.0003, "USD"}, - want{0.33333, -0.0003}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t1 *testing.T) { - ticker := &Ticker{ - Price: TickerPrice{ - Value: tt.args.price, - Change24h: tt.args.percentChange24h, - Currency: DefaultCurrency, - }, - } - ticker.ApplyRate(tt.args.currency, tt.args.rate, big.NewFloat(tt.args.rateChange24h)) - assert.Equal(t, tt.want.price, ticker.Price.Value) - assert.Equal(t, tt.want.percentChange24h, ticker.Price.Change24h) - }) - } -} diff --git a/pkg/blockatlas/models.go b/pkg/blockatlas/models.go index da366ed3b..1a881bbd8 100644 --- a/pkg/blockatlas/models.go +++ b/pkg/blockatlas/models.go @@ -1,10 +1,12 @@ package blockatlas -type DocsResponse struct { - Docs interface{} `json:"docs"` -} +type ( + DocsResponse struct { + Docs interface{} `json:"docs"` + } -type ResultsResponse struct { - Total int `json:"total"` - Results interface{} `json:"docs"` -} + ResultsResponse struct { + Total int `json:"total"` + Results interface{} `json:"docs"` + } +) diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go index 7b7e79ed9..1c3ba0ffb 100644 --- a/pkg/blockatlas/observer.go +++ b/pkg/blockatlas/observer.go @@ -2,26 +2,40 @@ package blockatlas import "strconv" -type Subscriptions map[string][]string +type ( + Subscriptions map[string][]string -type SubscriptionOperation string + SubscriptionOperation string -type SubscriptionEvent struct { - NewSubscriptions Subscriptions `json:"new_subscriptions"` - OldSubscriptions Subscriptions `json:"old_subscriptions"` - GUID string `json:"guid"` - Operation SubscriptionOperation `json:"operation"` -} + SubscriptionEvent struct { + NewSubscriptions Subscriptions `json:"new_subscriptions"` + OldSubscriptions Subscriptions `json:"old_subscriptions"` + GUID string `json:"guid"` + Operation SubscriptionOperation `json:"operation"` + } -type CoinStatus struct { - Height int64 `json:"height"` - Error string `json:"error,omitempty"` -} + Subscription struct { + Coin uint `json:"coin"` + Address string `json:"address"` + GUID string `json:"guid"` + } -type Observer struct { - Status bool `json:"status"` - Message string `json:"message"` -} + CoinStatus struct { + Height int64 `json:"height"` + Error string `json:"error,omitempty"` + } + + Observer struct { + Status bool `json:"status"` + Message string `json:"message"` + } + + Block struct { + Number int64 `json:"number"` + ID string `json:"id,omitempty"` + Txs []Tx `json:"txs"` + } +) func (e *SubscriptionEvent) ParseSubscriptions(s Subscriptions) []Subscription { subs := make([]Subscription, 0) diff --git a/pkg/blockatlas/staking.go b/pkg/blockatlas/staking.go index 17ef91272..94f315126 100644 --- a/pkg/blockatlas/staking.go +++ b/pkg/blockatlas/staking.go @@ -2,17 +2,6 @@ package blockatlas import "github.com/trustwallet/blockatlas/coin" -type ValidatorPage []Validator -type DelegationsPage []Delegation -type DelegationsBatchPage []DelegationResponse -type StakingBatchPage []StakingResponse -type StakeValidators []StakeValidator - -type DelegationStatus string -type DelegationType string - -type ValidatorMap map[string]StakeValidator - const ( DelegationStatusActive DelegationStatus = "active" DelegationStatusPending DelegationStatus = "pending" @@ -23,59 +12,72 @@ const ( DefaultAnnualReward = 0 ) -type StakingReward struct { - Annual float64 `json:"annual"` -} +type ( + ValidatorPage []Validator + DelegationsPage []Delegation + DelegationsBatchPage []DelegationResponse + StakingBatchPage []StakingResponse + StakeValidators []StakeValidator -type StakingDetails struct { - Reward StakingReward `json:"reward"` - LockTime int `json:"locktime"` - MinimumAmount Amount `json:"minimum_amount"` - Type DelegationType `json:"type"` -} + DelegationStatus string + DelegationType string -type Validator struct { - ID string `json:"id"` - Status bool `json:"status"` - Details StakingDetails `json:"details"` -} + ValidatorMap map[string]StakeValidator -type Delegation struct { - Delegator StakeValidator `json:"delegator"` - Value string `json:"value"` - Status DelegationStatus `json:"status"` - Metadata interface{} `json:"metadata,omitempty"` -} + StakingReward struct { + Annual float64 `json:"annual"` + } -type DelegationMetaDataPending struct { - AvailableDate uint `json:"available_date"` -} + StakingDetails struct { + Reward StakingReward `json:"reward"` + LockTime int `json:"locktime"` + MinimumAmount Amount `json:"minimum_amount"` + Type DelegationType `json:"type"` + } -type StakeValidatorInfo struct { - Name string `json:"name"` - Description string `json:"description"` - Image string `json:"image"` - Website string `json:"website"` -} + Validator struct { + ID string `json:"id"` + Status bool `json:"status"` + Details StakingDetails `json:"details"` + } -type StakeValidator struct { - ID string `json:"id"` - Status bool `json:"status"` - Info StakeValidatorInfo `json:"info,omitempty"` - Details StakingDetails `json:"details,omitempty"` -} + Delegation struct { + Delegator StakeValidator `json:"delegator"` + Value string `json:"value"` + Status DelegationStatus `json:"status"` + Metadata interface{} `json:"metadata,omitempty"` + } -type DelegationResponse struct { - Delegations DelegationsPage `json:"delegations"` - Balance string `json:"balance"` - Address string `json:"address"` - StakingResponse -} + DelegationMetaDataPending struct { + AvailableDate uint `json:"available_date"` + } -type StakingResponse struct { - Coin *coin.ExternalCoin `json:"coin"` - Details StakingDetails `json:"details"` -} + StakeValidatorInfo struct { + Name string `json:"name"` + Description string `json:"description"` + Image string `json:"image"` + Website string `json:"website"` + } + + StakeValidator struct { + ID string `json:"id"` + Status bool `json:"status"` + Info StakeValidatorInfo `json:"info,omitempty"` + Details StakingDetails `json:"details,omitempty"` + } + + DelegationResponse struct { + Delegations DelegationsPage `json:"delegations"` + Balance string `json:"balance"` + Address string `json:"address"` + StakingResponse + } + + StakingResponse struct { + Coin *coin.ExternalCoin `json:"coin"` + Details StakingDetails `json:"details"` + } +) func (sv StakeValidators) ToMap() ValidatorMap { validators := make(ValidatorMap) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 7ae77f4f1..0d46eff1c 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -1,13 +1,5 @@ package blockatlas -type Direction string -type Status string -type TokenType string -type TransactionType string -type KeyType string -type KeyTitle string - -// Types of transaction statuses const ( StatusCompleted Status = "completed" StatusPending Status = "pending" @@ -51,147 +43,157 @@ const ( AnyActionDelegation KeyTitle = "Delegation" AnyActionUndelegation KeyTitle = "Undelegation" AnyActionClaimRewards KeyTitle = "Claim Rewards" + + // TxPerPage says how many transactions to return per page + TxPerPage = 25 ) -// TxPerPage says how many transactions to return per page -const TxPerPage = 25 - -// TxPage is a page of transactions -type TxPage []Tx - -// Amount is a positive decimal integer string. -// It is written in the smallest possible unit (e.g. Wei, Satoshis) -type Amount string - -// Tx describes an on-chain transaction generically -type Tx struct { - // Unique identifier - ID string `json:"id"` - // SLIP-44 coin index of the platform - Coin uint `json:"coin"` - // Address of the transaction sender - From string `json:"from"` - // Address of the transaction recipient - To string `json:"to"` - // Transaction fee (native currency) - Fee Amount `json:"fee"` - // Unix timestamp of the block the transaction was included in - Date int64 `json:"date"` - // Height of the block the transaction was included in - Block uint64 `json:"block"` - // Status of the transaction - Status Status `json:"status"` - // Empty if the transaction was successful, - // else error explaining why the transaction failed (optional) - Error string `json:"error,omitempty"` - // Transaction nonce or sequence - Sequence uint64 `json:"sequence,omitempty"` - // Type of metadata - Type TransactionType `json:"type"` - // Input addresses - Inputs []TxOutput `json:"inputs,omitempty"` - // Output addresses - Outputs []TxOutput `json:"outputs,omitempty"` - // Transaction Direction - Direction Direction `json:"direction,omitempty"` - // Meta data object - Memo string `json:"memo"` - Meta interface{} `json:"metadata"` -} +type ( + // Types of transaction statuses + Direction string + Status string + TokenType string + TransactionType string + KeyType string + KeyTitle string + + // TxPage is a page of transactions + TxPage []Tx + + // Amount is a positive decimal integer string. + // It is written in the smallest possible unit (e.g. Wei, Satoshis) + Amount string + + // Tx describes an on-chain transaction generically + Tx struct { + // Unique identifier + ID string `json:"id"` + // SLIP-44 coin index of the platform + Coin uint `json:"coin"` + // Address of the transaction sender + From string `json:"from"` + // Address of the transaction recipient + To string `json:"to"` + // Transaction fee (native currency) + Fee Amount `json:"fee"` + // Unix timestamp of the block the transaction was included in + Date int64 `json:"date"` + // Height of the block the transaction was included in + Block uint64 `json:"block"` + // Status of the transaction + Status Status `json:"status"` + // Empty if the transaction was successful, + // else error explaining why the transaction failed (optional) + Error string `json:"error,omitempty"` + // Transaction nonce or sequence + Sequence uint64 `json:"sequence,omitempty"` + // Type of metadata + Type TransactionType `json:"type"` + // Input addresses + Inputs []TxOutput `json:"inputs,omitempty"` + // Output addresses + Outputs []TxOutput `json:"outputs,omitempty"` + // Transaction Direction + Direction Direction `json:"direction,omitempty"` + // Meta data object + Memo string `json:"memo"` + Meta interface{} `json:"metadata"` + } -type TxOutput struct { - Address string `json:"address"` - Value Amount `json:"value"` -} + TxOutput struct { + Address string `json:"address"` + Value Amount `json:"value"` + } -// Transfer describes the transfer of currency native to the platform -type Transfer struct { - Value Amount `json:"value"` - Symbol string `json:"symbol"` - Decimals uint `json:"decimals"` -} + // Transfer describes the transfer of currency native to the platform + Transfer struct { + Value Amount `json:"value"` + Symbol string `json:"symbol"` + Decimals uint `json:"decimals"` + } -// NativeTokenTransfer describes the transfer of native tokens. -// Example: Stellar Tokens, TRC10 -type NativeTokenTransfer struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - TokenID string `json:"token_id"` - Decimals uint `json:"decimals"` - Value Amount `json:"value"` - From string `json:"from"` - To string `json:"to"` -} + // NativeTokenTransfer describes the transfer of native tokens. + // Example: Stellar Tokens, TRC10 + NativeTokenTransfer struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + TokenID string `json:"token_id"` + Decimals uint `json:"decimals"` + Value Amount `json:"value"` + From string `json:"from"` + To string `json:"to"` + } -// TokenTransfer describes the transfer of non-native tokens. -// Examples: ERC-20, TRC20 -type TokenTransfer struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - TokenID string `json:"token_id"` - Decimals uint `json:"decimals"` - Value Amount `json:"value"` - From string `json:"from"` - To string `json:"to"` -} + // TokenTransfer describes the transfer of non-native tokens. + // Examples: ERC-20, TRC20 + TokenTransfer struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + TokenID string `json:"token_id"` + Decimals uint `json:"decimals"` + Value Amount `json:"value"` + From string `json:"from"` + To string `json:"to"` + } -// CollectibleTransfer describes the transfer of a -// "collectible", unique token. -type CollectibleTransfer struct { - Name string `json:"name"` - Contract string `json:"contract"` - ImageURL string `json:"image_url"` -} + // CollectibleTransfer describes the transfer of a + // "collectible", unique token. + CollectibleTransfer struct { + Name string `json:"name"` + Contract string `json:"contract"` + ImageURL string `json:"image_url"` + } -// TokenSwap describes the exchange of two different tokens -type TokenSwap struct { - Input TokenTransfer `json:"input"` - Output TokenTransfer `json:"output"` -} + // TokenSwap describes the exchange of two different tokens + TokenSwap struct { + Input TokenTransfer `json:"input"` + Output TokenTransfer `json:"output"` + } -// ContractCall describes a -type ContractCall struct { - Input string `json:"input"` - Value string `json:"value"` -} + // ContractCall describes a + ContractCall struct { + Input string `json:"input"` + Value string `json:"value"` + } -// Currency describes currency information with its amount -type Currency struct { - Token Token `json:"token"` - Value Amount `json:"value"` -} + // Currency describes currency information with its amount + Currency struct { + Token Token `json:"token"` + Value Amount `json:"value"` + } -// MultiCurrencyTransfer describes the transfer of multiple currency native to the platform -type MultiCurrencyTransfer struct { - Currencies []Currency `json:"currencies"` - Fees []Currency `json:"fees"` -} + // MultiCurrencyTransfer describes the transfer of multiple currency native to the platform + MultiCurrencyTransfer struct { + Currencies []Currency `json:"currencies"` + Fees []Currency `json:"fees"` + } -// AnyAction describes all other types -type AnyAction struct { - Coin uint `json:"coin"` - Title KeyTitle `json:"title"` - Key KeyType `json:"key"` - TokenID string `json:"token_id"` - Name string `json:"name"` - Symbol string `json:"symbol"` - Decimals uint `json:"decimals"` - Value Amount `json:"value"` -} + // AnyAction describes all other types + AnyAction struct { + Coin uint `json:"coin"` + Title KeyTitle `json:"title"` + Key KeyType `json:"key"` + TokenID string `json:"token_id"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals uint `json:"decimals"` + Value Amount `json:"value"` + } -// TokenPage is a page of transactions. -type TokenPage []Token - -// Token describes the non-native tokens. -// Examples: ERC-20, TRC-20, BEP-2 -type Token struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - Decimals uint `json:"decimals"` - TokenID string `json:"token_id"` - Coin uint `json:"coin"` - Type TokenType `json:"type"` -} + // TokenPage is a page of transactions. + TokenPage []Token + + // Token describes the non-native tokens. + // Examples: ERC-20, TRC-20, BEP-2 + Token struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals uint `json:"decimals"` + TokenID string `json:"token_id"` + Coin uint `json:"coin"` + Type TokenType `json:"type"` + } +) func (t *Tx) GetUtxoAddresses() (addresses []string) { for _, input := range t.Inputs { diff --git a/pkg/storage/sql/postgres.go b/pkg/storage/sql/postgres.go deleted file mode 100644 index 51b903703..000000000 --- a/pkg/storage/sql/postgres.go +++ /dev/null @@ -1,32 +0,0 @@ -package sql - -import ( - "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/postgres" - "github.com/trustwallet/blockatlas/pkg/logger" - "time" -) - -type PgSql struct { - sql -} - -func (db *PgSql) Init(host string) { - client, err := gorm.Open("postgres", host) - if err != nil { - logger.Fatal(err, "postgress connection failed") - } - client.DB().SetMaxIdleConns(20) - client.DB().SetMaxOpenConns(100) - client.DB().SetConnMaxLifetime(time.Minute) - client.LogMode(true) - db.Client = client -} - -func (db *PgSql) IsReady() bool { - return db.Client != nil -} - -func (db *PgSql) Close() error { - return db.Client.Close() -} diff --git a/pkg/storage/sql/sql.go b/pkg/storage/sql/sql.go deleted file mode 100644 index 899ee643f..000000000 --- a/pkg/storage/sql/sql.go +++ /dev/null @@ -1,87 +0,0 @@ -package sql - -import ( - "github.com/jinzhu/gorm" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/storage/util" -) - -type sql struct { - Client *gorm.DB -} - -type Handler func(db *gorm.DB, value interface{}) error - -func Get(db *gorm.DB, value interface{}) error { - err := db.Where(value).Take(value).Error - if err != nil { - return errors.E(err, util.ErrNotFound, errors.Params{"method": "Get", "value": value}) - } - return nil -} - -func Find(db *gorm.DB, out interface{}, where ...interface{}) error { - err := db.Find(out, where...).Error - if err != nil { - return errors.E(err, util.ErrNotFound, errors.Params{"method": "Find", "out": out, "where": where}) - } - return nil -} - -func Save(db *gorm.DB, value interface{}) error { - err := db.Save(value).Error - if err != nil { - return errors.E(err, util.ErrNotUpdated, errors.Params{"method": "Save", "value": value}) - } - return nil -} - -func Add(db *gorm.DB, value interface{}) error { - err := db.Where(value).FirstOrCreate(value).Error - if err != nil { - return errors.E(err, util.ErrNotStored, errors.Params{"method": "Add", "value": value}) - } - return nil -} - -func (db *sql) AddMany(values ...interface{}) error { - return db.Batch(true, Add, values...) -} - -func (db *sql) MustAddMany(values ...interface{}) error { - return db.Batch(false, Add, values...) -} - -func Delete(db *gorm.DB, value interface{}) error { - err := Get(db, value) - if err != nil { - return err - } - err = db.Delete(value).Error - if err != nil { - return errors.E(err, util.ErrNotDeleted) - } - return nil -} - -func (db *sql) DeleteMany(values ...interface{}) error { - return db.Batch(true, Delete, values...) -} - -func (db *sql) MustDeleteMany(values ...interface{}) error { - return db.Batch(false, Delete, values...) -} - -func (db *sql) Batch(rollback bool, handler Handler, values ...interface{}) error { - tx := db.Client.Begin() - for _, value := range values { - err := handler(tx, value) - if err != nil { - if rollback { - tx.Rollback() - return err - } - } - } - return tx.Commit().Error -} diff --git a/storage/storage.go b/storage/storage.go index edd55563f..0b66d1b60 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -27,7 +27,7 @@ func RestoreConnectionWorker(storage *Storage, uri string, timeout time.Duration logger.Warn("Trying to connect to MQ...") if err := storage.Init(uri); err != nil { logger.Warn("Redis is still unavailable") - time.Sleep(timeout) + time.Sleep(timeout) continue } else { logger.Info("Redis connection restored") From aee38096fe5aee224095df2d40736c86bbf558db Mon Sep 17 00:00:00 2001 From: Mykola <3277207+kolya182@users.noreply.github.com> Date: Tue, 17 Mar 2020 22:54:32 -0700 Subject: [PATCH 202/506] Remove request only_confirmed transactions (#969) --- platform/tron/client.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/tron/client.go b/platform/tron/client.go index 862126ef5..56b654a6b 100644 --- a/platform/tron/client.go +++ b/platform/tron/client.go @@ -31,8 +31,7 @@ func (c *Client) GetTxsOfAddress(address, token string) ([]Tx, error) { var txs Page err := c.Get(&txs, path, url.Values{ - "only_confirmed": {"true"}, - "limit": {"200"}, + "limit": {"25"}, "token_id": {token}, "order_by": {"block_timestamp,desc"}, }) From 3ee6810bd173a5e753ed84ad72c3ec9b087bb7bc Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Fri, 20 Mar 2020 16:49:44 +0100 Subject: [PATCH 203/506] Base infra for mocked external services, mocked functional tests. (#963) * Base infra for mocked external services, mocked functional tests. Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov Co-authored-by: Nick Kozlov --- .gitignore | 3 + Makefile | 71 +++++- configmock.yml | 219 ++++++++++++++++++ .../ext-api-dyson/get/algorand-api-account.js | 41 ++++ mock/ext-api-dyson/get/algorand-api-block.js | 61 +++++ mock/ext-api-dyson/get/binance-api-tx.js | 60 +++++ mock/ext-api-dyson/get/binance-api-txs.js | 64 +++++ .../ext-api-dyson/get/eth-api-transactions.js | 42 ++++ .../get/unstoppabledomains-lookup.js | 38 +++ mock/ext-api-dyson/post/eth-rpc.js | 81 +++++++ .../post/fio-api-get_pub_address.js | 29 +++ mock/ext-api-dyson/post/harmony-api.js | 19 ++ mock/ext-api-dyson/post/nano-api.js | 88 +++++++ platform/fio/client.go | 1 + .../Blockatlas.postman_collection.json | 14 +- tests/postman/transaction_data.json | 176 +++++++++----- 16 files changed, 936 insertions(+), 71 deletions(-) create mode 100644 configmock.yml create mode 100644 mock/ext-api-dyson/get/algorand-api-account.js create mode 100644 mock/ext-api-dyson/get/algorand-api-block.js create mode 100644 mock/ext-api-dyson/get/binance-api-tx.js create mode 100644 mock/ext-api-dyson/get/binance-api-txs.js create mode 100644 mock/ext-api-dyson/get/eth-api-transactions.js create mode 100644 mock/ext-api-dyson/get/unstoppabledomains-lookup.js create mode 100644 mock/ext-api-dyson/post/eth-rpc.js create mode 100644 mock/ext-api-dyson/post/fio-api-get_pub_address.js create mode 100644 mock/ext-api-dyson/post/harmony-api.js create mode 100644 mock/ext-api-dyson/post/nano-api.js diff --git a/.gitignore b/.gitignore index 4ad0ab859..4dd133c32 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,6 @@ _testmain.go # govendor cache .cache + +# npm-installed stuff +node_modules diff --git a/Makefile b/Makefile index 09735b9d2..bc492346d 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ GOPKG := $(.) # Environment variables CONFIG_FILE=$(GOBASE)/config.yml +CONFIG_MOCK_FILE=$(GOBASE)/configmock.yml # Go files GOFMT_FILES?=$$(find . -name '*.go' | grep -v vendor) @@ -36,6 +37,7 @@ PID_API := /tmp/.$(PROJECT_NAME).$(API_SERVICE).pid PID_OBSERVER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SERVICE).pid PID_OBSERVER_SUBSCRIBER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SUBSCRIBER).pid PID_SWAGGER_API := /tmp/.$(PROJECT_NAME).$(SWAGGER_API).pid +PID_DYSON := /tmp/.$(PROJECT_NAME).dyson.pid # Make is verbose in Linux. Make it silent. MAKEFLAGS += --silent @@ -53,6 +55,13 @@ start-platform-api: stop @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" @echo " > Error log: $(STDERR)" +# start-platform-api-mock: Start API in development mode. Similar to start-platform-api, but uses config file with mock URLs +start-platform-api-mock: stop start-mock-dyson + @echo " > Starting $(PROJECT_NAME) API" + @-$(GOBIN)/$(API_SERVICE)/platform_api -c $(CONFIG_MOCK_FILE) 2>&1 & echo $$! > $(PID_API) + @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" + @echo " > Error log: $(STDERR)" + ## start-swagger-api: Start swagger api in development mode. start-swagger-api: stop @echo " > Starting $(PROJECT_NAME)" @@ -81,8 +90,13 @@ stop: @-kill `cat $(PID_OBSERVER)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER_SUBSCRIBER)` 2> /dev/null || true @-kill `cat $(PID_SWAGGER_API)` 2> /dev/null || true + @-kill `cat $(PID_DYSON)` 2> /dev/null || true @-rm $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) +stop-dyson: + @kill `cat $(PID_DYSON)` 2> /dev/null || true + @rm $(PID_DYSON) + ## compile: Compile the project. compile: @-touch $(STDERR) @@ -105,9 +119,15 @@ test: go-test ## functional: Run all functional tests. functional: go-functional -## integration: Run all functional tests. +## integration: Run all integration tests. integration: go-integration +## start-mock-dyson: Start Dyson with mocks of external services +start-mock-dyson: stop-dyson + @echo " > Starting Dyson with mocks" + @-dyson mock/ext-api-dyson & echo $$! > $(PID_DYSON) + @echo " > Dyson started " `cat $(PID_DYSON)` + ## fmt: Run `go fmt` for all go files. fmt: go-fmt @@ -139,21 +159,45 @@ ifeq (,$(shell which newman)) endif ## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http//localhost -newman: install-newman - @echo " > Running $(test) tests" +newman: install-newman start-platform-api +ifeq (,$(test)) + @bash -c "$(MAKE) newman-run test=transaction host=$(host)" + @bash -c "$(MAKE) newman-run test=token host=$(host)" + @bash -c "$(MAKE) newman-run test=staking host=$(host)" + @bash -c "$(MAKE) newman-run test=collection host=$(host)" + @bash -c "$(MAKE) newman-run test=domain host=$(host)" + @bash -c "$(MAKE) newman-run test=healthcheck host=$(host)" +else + @bash -c "$(MAKE) newman-run test=$(test) host=$(host)" +endif + +## newman-mocked: Run mocked Postman Newman tests, after starting platform api. See newman target. +newman-mocked: install-newman install-dyson go-compile start-platform-api-mock +ifeq (,$(test)) + @bash -c "$(MAKE) newman-run test=transaction host=$(host)" + @bash -c "$(MAKE) newman-run test=token host=$(host)" + @bash -c "$(MAKE) newman-run test=staking host=$(host)" + @bash -c "$(MAKE) newman-run test=collection host=$(host)" + @bash -c "$(MAKE) newman-run test=domain host=$(host)" + @bash -c "$(MAKE) newman-run test=healthcheck host=$(host)" +else + @bash -c "$(MAKE) newman-run test=$(test) host=$(host)" +endif + +## newman-run: Run chosen Newman tests. See newman target. +newman-run: ifeq (,$(host)) @echo " > Host parameter is missing. e.g: make newman test=staking host=http://localhost:8420" @exit 1 endif -ifeq (,$(test)) - @bash -c "$(MAKE) newman test=transaction host=$(host)" - @bash -c "$(MAKE) newman test=token host=$(host)" - @bash -c "$(MAKE) newman test=staking host=$(host)" - @bash -c "$(MAKE) newman test=collection host=$(host)" - @bash -c "$(MAKE) newman test=domain host=$(host)" - @bash -c "$(MAKE) newman test=healthcheck host=$(host)" -else + @echo " > Running $(test) tests" @newman run tests/postman/Blockatlas.postman_collection.json --folder $(test) -d tests/postman/$(test)_data.json --env-var "host=$(host)" + +## install-dyson: Install Dyson for mocked tests. +install-dyson: +ifeq (,$(shell which dyson)) + @echo " > Installing Dyson" + @-npm install -g dyson endif go-compile: go-get go-build @@ -191,6 +235,11 @@ go-functional: @echo " > Running functional tests" GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=functional -v ./tests/functional +## go-functional-mock: Run platform-api with mocks, and run functional tests +go-functional-mock: stop install-dyson start-mock-dyson start-platform-api-mock + @echo " > Running functional tests with mocks" + GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=functional -v ./tests/functional + go-integration: @echo " > Running integration tests" GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration ./tests/docker_test diff --git a/configmock.yml b/configmock.yml new file mode 100644 index 000000000..d6e3024cb --- /dev/null +++ b/configmock.yml @@ -0,0 +1,219 @@ +# Gin is the web framework +gin: + # Possible values: "debug", "release" + mode: release + # App running behind a reverse proxy? + # If set, HTTP Forwarded headers will be respected + reverse_proxy: false + +# If all - run all platforms in one binary. You can pick specific coin handle to run binary only with specific coin +# Example: ethereum +# You can see all the coin handles at coins/coins.yml file +platform: all + +# Sentry error tracking +#sentry: +# dsn: https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@sentry.io/xxxxxxx + +# The transaction watcher +observer: + auth: test + # Don't request blocks older than this + backlog: 3h + # Don't request more than N blocks at once + backlog_max_blocks: 200 + # Max connections to open to API + stream_conns: 16 + # Block polling interval + block_poll: + min: 3s + max: 30s + rabbitmq: + uri: amqp://rabbit:5672 + consumer: + prefetch_count: 10 + +storage: + redis: redis://localhost:6379 + +# [BNB] Binance DEX: https://wallet.binance.org +# Binance Chain: https://explorer.binance.org +binance: + #mock api: https://explorer.binance.org/api/v1 + api: http://localhost:3000/binance-api/v1 + dex: https://dex.binance.org/api + +# [NIM] Nimiq: https://nimiq.com +#nimiq: +# api: http://localhost:8648 + +# [XRP] Ripple: https://ripple.com +ripple: + api: https://data.ripple.com/v2 + +# [XLM] Stellar Lumen: https://www.stellar.org +stellar: + api: https://horizon.stellar.org + +# [KIN] Kin: https://www.kin.org +kin: + api: https://horizon-block-explorer.kininfrastructure.com + +# [XTZ] Tezos: https://tezos.com +tezos: + stake_api: https://api.tzstats.com/explorer + api: http://api.tezos.id/mooncake/mainnet + rpc: https://mainnet.tezos.org.ua + +# [ETH] Ethereum: https://ethereum.org (Trust-Ray API) +ethereum: + api: http://localhost:3000/eth-api + collections_api: https://api.opensea.io + collections_api_key: opensea_api_key + rpc: http://localhost:3000/eth-rpc + +# [ETC] Ethereum Classic: https://ethereumclassic.org (Trust-Ray API) +# classic: +# api: https://localhost:4567 + +# [POA] POA Network: https://poa.network (Trust-Ray API) +# poa: +# api: https://localhost:4567 + +# [CLO] Callisto Network: https://callisto.network (Trust-Ray API) +# callisto: +# api: https://localhost:4567 + +# [GO] GoChain: https://gochain.io (Trust-Ray API) +# gochain: +# api: https://localhost:4567 + +# [WAN] Wanchain: https://wanchain.org (Trust-Ray API) +# wanchain: +# api: https://localhost:4567 + +# [TOMO] TomoChain: https://tomochain.com (Trust-Ray API) +# tomochain: +# api: https://localhost:4567 + +# [TT] ThunderCore: https://www.thundercore.com (Trust-Ray API) +# thundertoken: +# api: https://localhost:4567 + +# [AION] Aion: https://aion.network +aion: + api: https://mainnet-api.theoan.com/aion/dashboard + +# [ICX] ICON: https://icon.foundation +icon: + api: https://tracker.icon.foundation/v3 + +# [TRX] Tron: https://tron.network/ +tron: + api: https://api.trongrid.io + +# [VET] VeChain: https://www.vechain.org +vechain: + api: https://vethor-pubnode.digonchain.com + +# [THETA] THETA: https://www.thetatoken.org/ +theta: + api: https://explorer.thetatoken.org:9000/api + +# [ATOM] Cosmos: https://cosmos.network/ +cosmos: + api: https://api.cosmos.network + +# [ONTOLOGY] ONT: https://ont.io/ +ontology: + api: https://explorer.ont.io + +# [ZIL] Zilliqa: https://zilliqa.com +zilliqa: + api: https://api.viewblock.io/v1/zilliqa + # key: YOUR_API_KEY + rpc: https://api.zilliqa.com + #mock lookup: https://unstoppabledomains.com/api/v1 + lookup: http://localhost:3000/unstoppabledomains/api/v1 + +#[IoTeX] IoTeX: https://iotex.io +iotex: + api: https://pharos.iotex.io/v1 + +# [WAVES] Waves: http://wavesplatform.com +waves: + api: https://nodes.wavesnodes.com + +# [AE] Aeternity: https://aeternity.com +aeternity: + api: https://mdw.aepps.com + +# [NAS] Nebulas: https://nebulas.io +nebulas: + api: https://explorer-backend.nebulas.io/api + +fio: + # api: https://addresses.fio.foundation + #mock api: http://testnet.fioprotocol.io/v1/chain + api: http://localhost:3000/fio-api/v1/chain + +# [BTC] Bitcoin: https://bitcoin.org/ (Blockbook API https://github.com/trezor/blockbook) +bitcoin: + api: https://btc1.trezor.io/api + +litecoin: + api: https://ltc1.trezor.io/api + +bitcoincash: + api: https://bch1.trezor.io/api + +doge: + api: https://doge1.trezor.io/api + +dash: + api: https://dash1.trezor.io/api + +zcoin: + api: https://blockbook.zcoin.io/api + +zcash: + api: https://zec1.trezor.io/api + +zelcash: + api: https://blockbook.zel.network/api + +viacoin: + api: https://blockbook.viacoin.org/api + +qtum: + api: https://blockv3.qtum.info/api + +groestlcoin: + api: https://blockbook.groestlcoin.org/api + +ravencoin: + api: https://blockbook.ravencoin.org/api + +decred: + api: https://blockbook.decred.org:9161/api + +algorand: + #mock api: https://mainnet-algorand.api.purestake.io/ps1 + api: http://localhost:3000/algorand-api + +nano: + #mock api: https://nanoverse.io/api/node + api: http://localhost:3000/nano-api + +digibyte: + api: https://dgb1.trezor.io/api + +harmony: + #mock api: https://api.s0.t.hmny.io + api: http://localhost:3000/harmony-api + +kava: + api: https://data.kava.io + +kusama: + api: https://kusama.subscan.io/api diff --git a/mock/ext-api-dyson/get/algorand-api-account.js b/mock/ext-api-dyson/get/algorand-api-account.js new file mode 100644 index 000000000..977f3a83f --- /dev/null +++ b/mock/ext-api-dyson/get/algorand-api-account.js @@ -0,0 +1,41 @@ +/// Mock for external Algorand API +/// curl "http://localhost:3000/algorand-api/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions?" +/// curl "https://algorand-rpc.trustwalletapp.com/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions?" +/// curl http://localhost:8420/v1/algorand/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U + +module.exports = { + path: '/algorand-api/v1/account/:account/transactions?', + template: function(params, query, body) { + //console.log(params) + switch (params.account) { + case '4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U': + return JSON.parse(` + { + "transactions": [ + { + "type": "pay", + "tx": "JZTKP6RRFGUDOZ7DQIR26DQWRDYZVYG2G3WDE4WLBJ77AMAEBFBA", + "from": "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", + "fee": 1000, + "first-round": 5478300, + "last-round": 5478749, + "noteb64": "sHLxsLBrP3o=", + "round": 5478346, + "payment": { + "to": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", + "amount": 1, + "torewards": 2052177, + "closerewards": 0 + }, + "fromrewards": 0, + "genesisID": "mainnet-v1.0", + "genesishashb64": "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=" + } + ] + } + `); + } + // fallback + return {error: "Not implemented"} + } +}; diff --git a/mock/ext-api-dyson/get/algorand-api-block.js b/mock/ext-api-dyson/get/algorand-api-block.js new file mode 100644 index 000000000..27768e026 --- /dev/null +++ b/mock/ext-api-dyson/get/algorand-api-block.js @@ -0,0 +1,61 @@ +/// Mock for external Algorand API +/// curl "http://localhost:3000/algorand-api/v1/block/5478346?" +/// curl "https://algorand-rpc.trustwalletapp.com/v1/block/5478346?" +/// curl http://localhost:8420/v1/algorand/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U + +module.exports = { + path: '/algorand-api/v1/block/:block?', + template: function(params, query, body) { + //console.log(params) + switch (params.block) { + case '5478346': + return JSON.parse(` + { + "hash": "SU4PUD4YK5DPIXUXDLEZOEHVVIIP4SWZORFPJBW2J22QO444NSAA", + "previousBlockHash": "CC4CQRE2U5AC7S7JLJHDVVGIDCHGWTDFIZM3P34TVTC7AP4BA2AQ", + "seed": "NLAQIQXPCZI5QMKMRFFKMIKANNBC4PTFW5QFVAK7U6FE477T2TRA", + "proposer": "WCFKBT4NEPDUCQP7MGLIWV4QGXIBOCXJFVYNTXF3HZHFHGQGHGR5WWA7XA", + "round": 5478346, + "period": 0, + "txnRoot": "KFADZYI64LDUX76VWVVV3MROORV5RXAVNZA7MVTWOP2QTGW6DZ2A", + "reward": 111421, + "rate": 25999967, + "frac": 2639736378, + "txns": { + "transactions": [ + { + "type": "pay", + "tx": "JZTKP6RRFGUDOZ7DQIR26DQWRDYZVYG2G3WDE4WLBJ77AMAEBFBA", + "from": "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", + "fee": 1000, + "first-round": 5478300, + "last-round": 5478749, + "noteb64": "sHLxsLBrP3o=", + "round": 5478346, + "payment": { + "to": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", + "amount": 1, + "torewards": 2052177, + "closerewards": 0 + }, + "fromrewards": 0, + "genesisID": "mainnet-v1.0", + "genesishashb64": "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=" + } + ] + }, + "timestamp": 1584332782, + "currentProtocol": "https://github.com/algorandfoundation/specs/tree/4a9db6a25595c6fd097cf9cc137cc83027787eaa", + "nextProtocol": "", + "nextProtocolApprovals": 0, + "nextProtocolVoteBefore": 0, + "nextProtocolSwitchOn": 0, + "upgradePropose": "", + "upgradeApprove": false + } + `); + } + // fallback + return {error: "Not implemented"} + } +}; diff --git a/mock/ext-api-dyson/get/binance-api-tx.js b/mock/ext-api-dyson/get/binance-api-tx.js new file mode 100644 index 000000000..13ece8742 --- /dev/null +++ b/mock/ext-api-dyson/get/binance-api-tx.js @@ -0,0 +1,60 @@ +/// Binance chain block explorer API Mock, tx +/// Returns: +/// - Multi-transaction transaction for a specific address +/// see http://localhost:3000/binance-api/v1/tx?txHash=F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC +/// see https://explorer.binance.org/api/v1/tx?txHash=F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC +/// see http://localhost:8420/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp +/// see http://localhost:8420/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp?token=BUSD-BD1 +/// - empty response for other txHash'es + +module.exports = { + path: '/binance-api/v1/tx', + template: function(params, query, body) { + if (query['txHash'] == 'F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC') { + return { + txHash: "F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC", + blockHeight: Number.parseFrom('63280715'), + txType: "TRANSFER", + timeStamp: Number.parseFrom('1579688431580'), + txFee: Number.parseFrom('0.00060'), + txAge: Number.parseFrom('2350509'), + code: 0, + log: "Msg 0: ", + confirmBlocks: 5818526, + memo: "Trust Wallet Redeem", + source: 0, + sequence: 175, + hasChildren: 1, + subTxsDto: { + totalNum: 2, + pageSize: 15, + subTxDtoList: [ + { + hash: "F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC", + height: Number.parseFrom('63280715'), + type: "TRANSFER", + value: 0.00375, + asset: "BNB", + fromAddr: "bnb1rhv98jcx2yu26shxedskttjzpkvsrz4nd226yv", + toAddr: "bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp", + fee: Number.parseFrom('0.00060') + }, + { + hash: "F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC", + height: Number.parseFrom('63280715'), + type: "TRANSFER", + value: 10.0, + asset: "BUSD-BD1", + fromAddr: "bnb1rhv98jcx2yu26shxedskttjzpkvsrz4nd226yv", + toAddr: "bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp", + fee: null + } + ] + } + }; + } + + // not found txHash, return empty response + return {} + } +}; diff --git a/mock/ext-api-dyson/get/binance-api-txs.js b/mock/ext-api-dyson/get/binance-api-txs.js new file mode 100644 index 000000000..4dc1615a9 --- /dev/null +++ b/mock/ext-api-dyson/get/binance-api-txs.js @@ -0,0 +1,64 @@ +/// Binance chain block explorer API Mock, txs +/// Return +/// - for address 'bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp' 2 txs, one of them multi +/// - for address 'bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd' 1 tx +/// - empty list for other addresses +/// See: +/// curl "http://localhost:3000/explorer-api/v1/txs?address=bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp&page=1&rows=20&txAsset=BNB&txType=TRANSFER" +/// curl "https://explorer.binance.org/api/v1/txs?address=bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp&page=1&rows=20&txAsset=BNB&txType=TRANSFER" +/// curl "http://localhost:8420/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp" + +module.exports = { + path: '/binance-api/v1/txs', + template: function(params, query, body) { + //console.log(query); + var address = query['address']; + //console.log('address', address); + switch (address) { + case 'bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp': + return { + txNums: 2, + txArray: [ + { + txHash: "4A5E688755E3588B89C5F0325274430AA52786E527313739C542BC69436E18F4", + blockHeight: Number.parseFrom('63282272'), + txType: "TRANSFER", + timeStamp: Number.parseFrom('1579689046296'), + fromAddr: "bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp", + toAddr: "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + value: 0.5541546, + txAsset: "BNB", + txFee: Number.parseFrom('0.000375'), + txAge: 2351199, + code: 0, + log: "Msg 0: ", + confirmBlocks: 0, + memo: "102101832", + source: 0, + hasChildren: 0 + }, + { + txHash: "F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC", + blockHeight: Number.parseFrom('63280715'), + txType: "TRANSFER", + timeStamp: Number.parseFrom('1579688431580'), + txFee: Number.parseFrom('0.00060'), + txAge: 2351814, + code: 0, + log: "Msg 0: ", + confirmBlocks: 0, + memo: "Trust Wallet Redeem", + source: 0, + hasChildren: 1 + } + ] + }; + + case 'bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd': + return JSON.parse('{"txNums":1,"txArray":[{"txHash":"DDA939C475755B2A00123CDA37A5EC442F502EA2983014D04F647C3CB9FB57A0","blockHeight":75110907,"txType":"TRANSFER","timeStamp":1584450870939,"fromAddr":"bnb166fvwtfra2atta5mm8mygt2fyltktqctgpedcg","toAddr":"bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd","value":0.00037500,"txAsset":"BNB","txFee":0.00037500,"txAge":10170,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0}]}'); + } + + // not found, address + return {txNums: 0, txArray: []} + } +}; diff --git a/mock/ext-api-dyson/get/eth-api-transactions.js b/mock/ext-api-dyson/get/eth-api-transactions.js new file mode 100644 index 000000000..c26bf7084 --- /dev/null +++ b/mock/ext-api-dyson/get/eth-api-transactions.js @@ -0,0 +1,42 @@ +/// RPC Mock +/// See: +/// curl "http://localhost:3000/eth-api/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "https://trust-wallet.herokuapp.com/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl http://localhost:8420/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7 + +module.exports = { + path: '/eth-api/transactions', + template: function(params, query, body) { + //console.log(query) + if (query.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { + return JSON.parse(` + { + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", + "blockNumber": 9551915, + "time": 1582624428, + "nonce": 227, + "from": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "to": "0x1717f94202c126ef71d6C562de253Fe95eEbDD5f", + "value": "17635730000000000", + "gas": "21000", + "gasPrice": "4320000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", + "timeStamp": "1582624428" + } + ], + "total": 1 + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/unstoppabledomains-lookup.js b/mock/ext-api-dyson/get/unstoppabledomains-lookup.js new file mode 100644 index 000000000..e03008864 --- /dev/null +++ b/mock/ext-api-dyson/get/unstoppabledomains-lookup.js @@ -0,0 +1,38 @@ + +/// Unstoppabledomains API Mock, lookup +/// Returns: +/// - public address for certain name and coin combinations +/// - public address not found message for other input +/// See: +/// curl "http://localhost:3000/unstoppabledomains/api/v1//dpantani.zil" +/// curl "https://unstoppabledomains.com/api/v1/dpantani.zil" +/// curl "http://localhost:8420/v2/ns/lookup?name=dpantani.zil&coins=313" + +module.exports = { + path: '/unstoppabledomains/api/v1//:name?', + template: function(params, query, body) { return lookup(params, query, body); } +}; + +function lookup(params, query, body) { + var addr = getAddresses(params.name); + if (addr == '') { + return {addresses: {}, meta: {owner: null, type: "ZNS", ttl: 0}, claimed: false}; + } + return addr; +} + +function getAddresses(address) { + if (address !== 'dpantani.zil' && address !== 'dpantani.crypto') { return ''; } + return { + addresses: { + BTC: "bc1qd7eystu9xl53hkyxm4kyg7h5yk4p436sqx6f27", + ETH: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + ZIL: "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64" + }, + meta: { + owner: "0xe4da405976f315ab91ff9a43a51972cc94739aa8", + type: "ZNS", + ttl: 0 + } + } +}; diff --git a/mock/ext-api-dyson/post/eth-rpc.js b/mock/ext-api-dyson/post/eth-rpc.js new file mode 100644 index 000000000..68a603f70 --- /dev/null +++ b/mock/ext-api-dyson/post/eth-rpc.js @@ -0,0 +1,81 @@ +/// ETH RPC API Mock +/// See: +/// curl -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":2,"method":"eth_call","params":[{"data":"0x02571be3ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835","from":"0x0000000000000000000000000000000000000000","to":"0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e"},"latest"]}' http://localhost:3000/eth-rpc +/// curl "http://localhost:8420/v2/ns/lookup?name=vitalik.eth&coins=60" + +module.exports = { + path: '/eth-rpc', + template: function(params, query, body) { + //console.log(body); + var jsonrpc = body.jsonrpc; + var id = body.id; + //console.log('body.method', body.method); + if (body.method === 'net_version') { + return {jsonrpc: jsonrpc, id: id, result: "1"} + } else if (body.method === 'eth_call') { + //console.log('body.params', body.params); + //console.log('body.params[0].data', body.params[0].data); + switch (body.params[0].data) { + case '0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835': + // name lookup, vitalik.eth, part 2 + return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000226159d592e2b063810a10ebf6dcbada94ed68b8"}; + case '0x02571be32337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047': + // name lookup, ourxyzwallet.xyz, part 1 + return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000b30b09da480dd907907d98af5102c2034ed7df60"}; + case '0x02571be3a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4': + // name lookup, vitalik.luxe, part 1 + return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000d8a667312d5260f12a306ae7730c754d938da86c"}; + case '0x02571be3ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835': + // name lookup, vitalik.eth, part 1 + return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045"}; + case '0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047': + // name lookup, ourxyzwallet.xyz, part 2 + return {jsonrpc: jsonrpc, id: id, result: "0x0000000000000000000000001da022710df5002339274aadee8d58218e9d6ab5"}; + case '0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4': + // name lookup, vitalik.luxe, part 2 + return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000bd5f5ec7ed5f19b53726344540296c02584a5237"}; + case '0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047': + // name lookup, ourxyzwallet.xyz, part 5 + return {jsonrpc: jsonrpc, id: id, result: "0x0000000000000000000000000c54eead78d555be3cbcd451424f9a27a7843935"}; + case '0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4': + // name lookup, vitalik.luxe, part 4 + return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000d8a667312d5260f12a306ae7730c754d938da86c"}; + + case '0x3b3b57deeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1': + switch (body.params[0].to) { + case '0x1da022710df5002339274aadee8d58218e9d6ab5': + // name lookup, ourxyzwallet.xyz, part 3 + return {jsonrpc: jsonrpc, id: id, result: "0x0000000000000000000000000000000000000000000000000000000000000000"}; + case '0x226159d592e2b063810a10ebf6dcbada94ed68b8': + // name lookup, vitalik.eth, part 3 + return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000eefb13c7d42efcc655e528da6d6f7bbcf9a2251d"}; + case '0xbd5f5ec7ed5f19b53726344540296c02584a5237': + // name lookup, vitalik.luxe, part 3 + return {jsonrpc: jsonrpc, id: id, result: "0x0000000000000000000000006109dd117aa5486605fc85e040ab00163a75c662"}; + } + + case '0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c': + switch (body.params[0].to) { + case '0x1da022710df5002339274aadee8d58218e9d6ab5': + // name lookup, ourxyzwallet.xyz, part 4 + return {jsonrpc: jsonrpc, id: id, result: "0x"}; + } + + case '0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c': + switch (body.params[0].to) { + case '0x226159d592e2b063810a10ebf6dcbada94ed68b8': + // name lookup, vitalik.eth, part 4 + return {jsonrpc: jsonrpc, id: id, result: "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000"}; + case '0xbd5f5ec7ed5f19b53726344540296c02584a5237': + // name lookup, vitalik.luxe, part 4 + return {jsonrpc: jsonrpc, id: id, result: "0x"}; + } + } + // fallback + return {error: "wrong data"}; + } else { + // fallback + return {error: "wrong method"}; + } + } +}; diff --git a/mock/ext-api-dyson/post/fio-api-get_pub_address.js b/mock/ext-api-dyson/post/fio-api-get_pub_address.js new file mode 100644 index 000000000..ad9257cec --- /dev/null +++ b/mock/ext-api-dyson/post/fio-api-get_pub_address.js @@ -0,0 +1,29 @@ +/// FIO RPC API Mock, get_pub_address +/// Returns: +/// - public address for certain fio name and coin combinations +/// - public address not found message for other input +/// See: +/// curl -H "Content-Type: application/json" -d '{"fio_address":"adam@fiotestnet","token_code":"BTC","chain_code":"BTC"}' "http://localhost:3000/fio-api/v1/chain/get_pub_address" +/// curl -H "Content-Type: application/json" -d '{"fio_address":"adam@fiotestnet","token_code":"BTC","chain_code":"BTC"}' "http://testnet.fioprotocol.io/v1/chain/get_pub_address" +/// curl "http://localhost:8420/v2/ns/lookup?name=adam@fiotestnet&coins=60" + +module.exports = { + path: '/fio-api/v1/chain/get_pub_address', + template: function(params, query, body) { + var addr = getAddress(body.fio_address, body.token_code); + if (addr == '') { + return {message: 'Public address not found'}; + } + return {public_address: addr}; + } +}; + +function getAddress(fio_address, token_code) { + if (fio_address !== 'adam@fiotestnet') { return ''; } + switch (token_code) { + case 'BTC': return 'bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v'; + case 'ETH': return '0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51'; + case 'BNB': return 'bnb1ts3dg54apwlvr9hupv2n0j6e46q54znnusjk9s'; + default: return ''; + } +}; diff --git a/mock/ext-api-dyson/post/harmony-api.js b/mock/ext-api-dyson/post/harmony-api.js new file mode 100644 index 000000000..782b4f21a --- /dev/null +++ b/mock/ext-api-dyson/post/harmony-api.js @@ -0,0 +1,19 @@ +/// Harmony RPC Mock +/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":"hmy_getTransactionsHistory"} ' http://localhost:3000/harmony-api +/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":"hmy_getTransactionsHistory"} ' https://harmony-rpc.trustwalletapp.com +/// curl "http://localhost:8420/v2/harmony/one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv" + +module.exports = { + path: '/harmony-api', + template: function(params, query, body) { + //console.log("curl -H 'Content-Type: application/json' -d '", JSON.stringify(body), "' https://harmony-rpc.trustwalletapp.com"); + if (body.method === 'hmy_getTransactionsHistory') { + //console.log('body.params[0].address', body.params[0].address); + if (body.params[0].address === 'one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv') { + return JSON.parse('{"jsonrpc":"2.0","id":"hmy_getTransactionsHistory","result":{"transactions":[{"blockHash":"0xe6e65f0f9f1e694d93012f1f2b4713cdd253cc6a15e729ff6df23a78d7694013","blockNumber":"0x1b2cd7","from":"one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk","timestamp":"0x5df7cb24","gas":"0x33450","gasPrice":"0x3b9aca00","hash":"0x391af85c5e25ee96cbbc417121b6bacc0ed466c0423467354192c075444e7603","input":"0x","nonce":"0x1f","to":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","transactionIndex":"0x0","value":"0x1bc0ae68df60e000","shardID":0,"toShardID":0,"v":"0x25","r":"0xb65b59fd1c9733977b0689e07a1869713ae2b2f8eabecee0a426c3f7fe62ac6b","s":"0x52b5be00be05173d89ffbf82a47b03f50268e6fe1ccd36a3fa7123a5255d2be2"},{"blockHash":"0x1b45da220f94f41bd42dc0eb89a5e83ce77b37cc78dbc9032bd10a5bbab13674","blockNumber":"0x1b2cdb","from":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","timestamp":"0x5df7cb45","gas":"0x33450","gasPrice":"0x3b9aca00","hash":"0x6bfd003239bf137855342f6266c456ae1b342e886bd1965a47edd4c74dd1a687","input":"0x","nonce":"0x0","to":"one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk","transactionIndex":"0x0","value":"0x1bbfef6a6ff9c000","shardID":0,"toShardID":0,"v":"0x26","r":"0x44c2a7b8c38612a3ce8b51967947c0c9756dda8d82d0f12137451ce33bbef390","s":"0x34234c6c26fe36bda246db845692fd248cb4060cda0d1c6056298b39486ed4f2"},{"blockHash":"0x58cc90d1b9302d0121b426f5fd35014acbc009defe36c5bbff6ac920d6005526","blockNumber":"0x1b2cf2","from":"one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk","timestamp":"0x5df7cc02","gas":"0x33450","gasPrice":"0x3b9aca00","hash":"0xf54f6f86df1624f38fcedf56eb248854a13a733e0b0f92d4b31b9cc7196d90b0","input":"0x","nonce":"0x20","to":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","transactionIndex":"0x0","value":"0x1bc0ae68df60e000","shardID":0,"toShardID":0,"v":"0x25","r":"0x46d14df06948f055e519ac244bcaaa3c3446ed20671d41db01546ddaad32503b","s":"0x50d13aeb94f2e8c760723afa4d892f3ca17690451a57465ea7e39c5d347efe8"},{"blockHash":"0xa84376f0f4d082b76355ccc6ec491660c0062d9ef3f39985ca00986e8dcbacc1","blockNumber":"0x1b2d1b","from":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","timestamp":"0x5df7cd50","gas":"0x33450","gasPrice":"0x3b9aca00","hash":"0x73355f625d0f7ef31512657c0f669e710c8c91a67180cd28bc919cfca0a2af82","input":"0x","nonce":"0x1","to":"one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk","transactionIndex":"0x0","value":"0x1bc09b4f6dd69000","shardID":0,"toShardID":0,"v":"0x26","r":"0xf31271b93e446bce8cc83eb997183146b4da2378a5f2cb1fc4ae64fbd65a93f5","s":"0x77e8e5693a87394204f96693a15f2157459b0329a2ddab97da0bf1cfb6fbce8c"}]}}'); + } + return {jsonrpc:"2.0",id:"hmy_getTransactionsHistory",result:{"transactions":[]}}; + } + return {error: 'Invalid request'}; + } +}; diff --git a/mock/ext-api-dyson/post/nano-api.js b/mock/ext-api-dyson/post/nano-api.js new file mode 100644 index 000000000..8e1de484a --- /dev/null +++ b/mock/ext-api-dyson/post/nano-api.js @@ -0,0 +1,88 @@ +/// Nano RPC Mock +/// curl -H 'Content-Type: application/json' -d ' {"action":"account_history","account":"nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z","count":"25"} ' http://localhost:3000/nano-api +/// curl -H 'Content-Type: application/json' -d ' {"action":"account_history","account":"nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z","count":"25"} ' https://nano-rpc.trustwalletapp.com +/// curl "http://localhost:8420/v1/nano/nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z" + +module.exports = { + path: '/nano-api', + template: function(params, query, body) { + //console.log("curl -H 'Content-Type: application/json' -d '", JSON.stringify(body), "' https://nano-rpc.trustwalletapp.com"); + if (body.action === 'account_history') { + //console.log('body.account', body.account); + if (body.account === 'nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z') { + return JSON.parse(`{ + "account": "nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z", + "history": [ + { + "type": "send", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "1083000821328155744662798729216", + "local_timestamp": "1576911470", + "height": "8", + "hash": "05A23A254272028F349BB7E74115A5101B2048786A5437D1EBBE8807CEFF1E82" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "1047300821328155744662798729216", + "local_timestamp": "1576911457", + "height": "7", + "hash": "13B8146F059C4D5695DCBCEEC750EAEDDDD8F436A6FAD569A107F2FAC0F899D5" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "34700000000000000000000000000", + "local_timestamp": "1576911446", + "height": "6", + "hash": "8A2A5840C9286B35D998F5AD535851750C1AFE7B0C7D3AA61E06A1628EDD0E94" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "1000000000000000000000000000", + "local_timestamp": "1575913533", + "height": "5", + "hash": "6816B5AC0594ED768CEC45F5DE25CBF0420300800B6C3C55E6749102F8B09C81" + }, + { + "type": "send", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "1083000821328155744662798729216", + "local_timestamp": "1575498786", + "height": "4", + "hash": "D9F97A2AB82EDFAA7A23FFA3423B286A8DD361B5B9303C5E0262EB684162DFD6" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "713600821328155744662798729216", + "local_timestamp": "1575498271", + "height": "3", + "hash": "69F4616925EC95DC15D97037BD99E2E782C2D2A557D5CE11E7FBB4BB6FF617F5" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "234700000000000000000000000000", + "local_timestamp": "1575498125", + "height": "2", + "hash": "6CE398F84A6B3F71E41E843C34917DAC408990C8468EFBC36CFC04954B113A43" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "134700000000000000000000000000", + "local_timestamp": "1575498065", + "height": "1", + "hash": "586BB82BADA98D6F8E4639DA6884C6562141AB983D885780FA41F31F7A04EC18" + } + ] + }`); + } + return {error: 'Bad account number'}; + } + var return4Codacy = {error: 'Invalid request'}; + return return4Codacy; + } +}; diff --git a/platform/fio/client.go b/platform/fio/client.go index 56a68c055..db12c9b5a 100644 --- a/platform/fio/client.go +++ b/platform/fio/client.go @@ -12,6 +12,7 @@ type Client struct { func (c *Client) lookupPubAddress(name string, coinSymbol string) (address string, error error) { var res GetPubAddressResponse + c.Headers["Content-Type"] = "application/json" err := c.Post(&res, "get_pub_address", GetPubAddressRequest{FioAddress: name, TokenCode: coinSymbol, ChainCode: coinSymbol}) if err != nil { return "", errors.E(err, "Error looking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": err.Error()}) diff --git a/tests/postman/Blockatlas.postman_collection.json b/tests/postman/Blockatlas.postman_collection.json index a0b5f819b..78ee0f3c4 100644 --- a/tests/postman/Blockatlas.postman_collection.json +++ b/tests/postman/Blockatlas.postman_collection.json @@ -91,6 +91,7 @@ "", "let handler = pm.variables.get(\"handler\");", "let address = pm.variables.get(\"address\");", + "let expectedTxId = pm.variables.get(\"expectedTxId\");", "var jsonData = pm.response.json();", "", "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", @@ -101,13 +102,24 @@ " pm.response.to.be.json;", "});", "", - "pm.test(handler + \" - verify has docs: \" + address, function() {", + "pm.test(handler + \" - verify has docs content: \" + address, function() {", " pm.expect(jsonData.total).to.be.above(0);", "});", "", "pm.test(handler + \" - schema is valid: \" + address, function() {", " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", "});", + "", + "// verify transaction ID in result (only if expected id is present) ", + "if (expectedTxId && expectedTxId.length > 0) {", + " var transactionIdFound = false;", + " for (var d in jsonData.docs) {", + " if (jsonData.docs[d].id === expectedTxId) { transactionIdFound = true; }", + " }", + " pm.test(handler + \" - verify expected txId: \" + expectedTxId, function() {", + " pm.expect(transactionIdFound).to.be.true;", + " });", + "}", "" ], "type": "text/javascript" diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index 59945f8f7..e8c49264b 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -1,234 +1,292 @@ [ { "handler": "harmony", - "address": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv" + "address": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", + "expectedTxId": "0x73355f625d0f7ef31512657c0f669e710c8c91a67180cd28bc919cfca0a2af82" }, { "handler": "nano", - "address": "nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z" + "address": "nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z", + "expectedTxId": "05A23A254272028F349BB7E74115A5101B2048786A5437D1EBBE8807CEFF1E82" }, { "handler": "algorand", - "address": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U" + "address": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", + "expectedTxId": "JZTKP6RRFGUDOZ7DQIR26DQWRDYZVYG2G3WDE4WLBJ77AMAEBFBA" }, { "handler": "kusama", - "address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK" + "address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", + "expectedTxId": "0x9908579abffb409aef95394128f9097f0a21cfdf16675588423e31ab0d3c58e2" }, { "handler": "kava", - "address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + "address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", + "expectedTxId": "30EFE9E830D317F84629F9DC35177577DF6713D78D354C2C469DE633900303BC" }, { "handler": "zilliqa", - "address": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z" + "address": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", + "expectedTxId": "0xa5d0e0cefd6f114e9659f15016f9f4a303a8367eb373beb6909ee44f7f39834d" }, { "handler": "tomochain", - "address": "0x17e4c16605e32adead5fa371bf6117df34ca0200" + "address": "0x17e4c16605e32adead5fa371bf6117df34ca0200", + "expectedTxId": "" }, { "handler": "ethereum", - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "expectedTxId": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47" }, { "handler": "classic", - "address": "0x7d2d0e153026fb428b885d86de50768d4cfeac37" + "address": "0x7d2d0e153026fb428b885d86de50768d4cfeac37", + "expectedTxId": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe" }, { "handler": "poa", - "address": "0x59D82a4B6068188ac06605A8416b5C7D40d6Fc43" + "address": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "expectedTxId": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3" }, { "handler": "thundertoken", - "address": "0x0b230def08139f18a86536d9cfa150f04435414c" + "address": "0x0b230def08139f18a86536d9cfa150f04435414c", + "expectedTxId": "" }, { "handler": "callisto", - "address": "0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" + "address": "0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7", + "expectedTxId": "" }, { "handler": "gochain", - "address": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" + "address": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", + "expectedTxId": "" }, { "handler": "theta", - "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f" + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "expectedTxId": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78" }, { "handler": "binance", - "address": "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" + "address": "bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd", + "expectedTxId": "DDA939C475755B2A00123CDA37A5EC442F502EA2983014D04F647C3CB9FB57A0" }, { "handler": "tezos", - "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" + "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", + "expectedTxId": "ooLrNAP233Qvoz3AGvjRjhk1fjG7z19UfyLEGBm1rwfHn4NSVhd" }, { "handler": "tron", - "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" + "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB", + "expectedTxId": "3ef5e225ce5bdd01333286e4ab4413ae3da8b80c24b26c5811ae78962940a8ca" }, { "handler": "vechain", - "address": "0xB5e883349e68aB59307d1604555AC890fAC47128" + "address": "0xB5e883349e68aB59307d1604555AC890fAC47128", + "expectedTxId": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7" }, { "handler": "ripple", - "address": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + "address": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "expectedTxId": "000BC2AFC047BE45C43886109720F44B6F3F2434D59B1A16A9B2B4FC9B9C5A13" }, { "handler": "cosmos", - "address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + "address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "expectedTxId": "93E43518BAE4BC137605BBB7FD5D31FDAE6427ECE57EC299C43CE786FDAEBC63" }, { "handler": "iotex", - "address": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + "address": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5", + "expectedTxId": "8f40e5e4c9fb4e8e29505a8d0db6428f3d372109c1a96c807d120ae9fe84ff9e" }, { "handler": "icon", - "address": "hxee691e7bccc4eb11fee922896e9f51490e62b12e" + "address": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", + "expectedTxId": "0x3b1a382884091e683350d6285d908406c149a030a7d52eb347f4571c1c904382" }, { "handler": "stellar", - "address": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" + "address": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "expectedTxId": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029" }, { "handler": "nimiq", - "address": "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07" + "address": "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", + "expectedTxId": "8674d985ac1ea2a75fe9b35ed11d629cef8adfed50db6a5eb125351e622bb405" }, { "handler": "nebulas", - "address": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a" + "address": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "expectedTxId": "0d06074b64c37ed24a17162d1e0ef8a8e65122fc7758c90c969e61735bc4396a" }, { "handler": "aeternity", - "address": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb" + "address": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "expectedTxId": "th_WfeoRYXd13MMmDBzMXjBBdaNSSaRXkwUwJ7tFxJ7ZKPQVNXC4" }, { "handler": "aion", - "address": "0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed" + "address": "0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed", + "expectedTxId": "0x511d3a4aafbdd26825a1655b5c7525df5bea8a8ef0f887d5490b490055b53df7" }, { "handler": "kin", - "address": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH" + "address": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "expectedTxId": "847bdd7cfef3fdf2683e846c37d8f8f3f611095e31042f4f7ad48094eab53992" }, { "handler": "ontology", - "address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7" + "address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "expectedTxId": "0ae15301f25a5067c075a25e722f0624a813a1352363197de2dd5f61ebd2998d" }, { "handler": "waves", - "address": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD" + "address": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "expectedTxId": "23JGFzBh65fzZArK6KSeRqjjBG5WnQshJJkUv53hCE1E" }, { "handler": "digibyte", - "address": "address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" + "address": "address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi", + "expectedTxId": "d7efaffeded550697d7385d3eb07e539237615792b29e3639df427ce919c8d6e" }, { "handler": "digibyte", - "address": "xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow" + "address": "xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow", + "expectedTxId": "e13c81f4450e43ef8ef10dea8f4f9d53f357266563462df32a7fd61eb71bd190" }, { "handler": "doge", - "address": "address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + "address": "address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh", + "expectedTxId": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9" }, { "handler": "doge", - "address": "xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN" + "address": "xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN", + "expectedTxId": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9" }, { "handler": "decred", - "address": "address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + "address": "address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", + "expectedTxId": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0" }, { "handler": "decred", - "address": "xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN" + "address": "xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN", + "expectedTxId": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0" }, { "handler": "zelcash", - "address": "address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" + "address": "address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa", + "expectedTxId": "" }, { "handler": "zelcash", - "address": "xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf" + "address": "xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf", + "expectedTxId": "2de19629bbf78af114ff9cf3332229dc336be4758481b72828f1bd786e8cc41e" }, { "handler": "zcoin", - "address": "address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + "address": "address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn", + "expectedTxId": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef" }, { "handler": "zcoin", - "address": "xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK" + "address": "xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK", + "expectedTxId": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef" }, { "handler": "zcash", - "address": "address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" + "address": "address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX", + "expectedTxId": "415888d61d605843fa4e846a84350c46703d6dd75446573770959d3eed71233d" }, { "handler": "zcash", - "address": "xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS" + "address": "xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS", + "expectedTxId": "f2438a93039faf08d39bd3df1f7b5f19a2c29ffe8753127e2956ab4461adab35" }, { "handler": "bitcoin", - "address": "address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + "address": "address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj", + "expectedTxId": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4" }, { "handler": "bitcoin", - "address": "xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC" + "address": "xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", + "expectedTxId": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4" }, { "handler": "bitcoincash", - "address": "address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + "address": "address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme", + "expectedTxId": "0284cb9b8deb0534efa8fc8911db1e8f9b106d00608c712d31c3680f303fbf36" }, { "handler": "bitcoincash", - "address": "xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX" + "address": "xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX", + "expectedTxId": "269d428f01fbe49cd6d2c2ca5e6e2f0ff68aece905313932156078d4341d347a" }, { "handler": "ravencoin", - "address": "address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" + "address": "address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS", + "expectedTxId": "23722d4e47de83f6a7a7f661a7733e4f85205fe733b4aeab1e7eaf9ae975fccc" }, { "handler": "ravencoin", - "address": "xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B" + "address": "xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B", + "expectedTxId": "5d22e5a84b0eb054b623fdc3caf88a60eaa646dc97922f06d325aa8d6f18c564" }, { "handler": "viacoin", - "address": "address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" + "address": "address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A", + "expectedTxId": "45f94473bf1bfda2c47cea9c38238ce86821c3ac301500a281ff45de1772b32c" }, { "handler": "viacoin", - "address": "xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK" + "address": "xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK", + "expectedTxId": "bdff404da14940abd84f7cb741fe8f77ad5de5aefbb74254caee683fe2a9b540" }, { "handler": "litecoin", - "address": "address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + "address": "address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept", + "expectedTxId": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1" }, { "handler": "litecoin", - "address": "xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu" + "address": "xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu", + "expectedTxId": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1" }, { "handler": "qtum", - "address": "address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + "address": "address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", + "expectedTxId": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67" }, { "handler": "qtum", - "address": "xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd" + "address": "xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd", + "expectedTxId": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67" }, { "handler": "groestlcoin", - "address": "address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" + "address": "address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj", + "expectedTxId": "2640aa5de0c9603da1c0d9c16b2fd3fa0a17b1472c3aa02559d3ef5e1defceb5" }, { "handler": "groestlcoin", - "address": "xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf" + "address": "xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf", + "expectedTxId": "686c651223b937b1223560a60631ad79ad17351c88bba67cad8ea0c95fccbb83" }, { "handler": "dash", - "address": "address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" + "address": "address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG", + "expectedTxId": "f47a4929bcd8767819b6969c83893a76d5b26a145c74ace416ce4c454166186e" }, { "handler": "dash", - "address": "xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD" + "address": "xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD", + "expectedTxId": "2b67e2fbe6a212286243bc539cca3c1d877e85ffec7c925e34f2bfb7b6cc498c" } -] +] \ No newline at end of file From 2dbf8f4fbbccd01481fa78c5efdca2bb9f9277a9 Mon Sep 17 00:00:00 2001 From: Mykola <3277207+kolya182@users.noreply.github.com> Date: Sun, 22 Mar 2020 19:43:35 -0700 Subject: [PATCH 204/506] Fix tfuel direction (#972) * Correct struct name * Add test * Adopt test to direction * Run go-fmt * Fix coins.go --- coin/coins.go | 2 +- platform/theta/model.go | 4 +- platform/theta/transaction.go | 46 +++++++++++++++-- platform/theta/transaction_test.go | 80 ++++++++++++++++++++---------- platform/tron/client.go | 6 +-- 5 files changed, 102 insertions(+), 36 deletions(-) diff --git a/coin/coins.go b/coin/coins.go index 53613fd5a..a9a0ba470 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2020-03-15 10:51:30.879337 +0800 CST m=+0.001247730 +// 2020-03-22 19:36:28.030503 -0700 PDT m=+0.019507357 // using data from coins.yml package coin diff --git a/platform/theta/model.go b/platform/theta/model.go index b6dce25a9..0211caee4 100644 --- a/platform/theta/model.go +++ b/platform/theta/model.go @@ -20,7 +20,7 @@ type Tx struct { type Data struct { Fee Fee `json:"fee"` - Inputs []Inputs `json:"inputs"` + Inputs []Input `json:"inputs"` Outputs []Output `json:"outputs"` } @@ -29,7 +29,7 @@ type Fee struct { Tfuelwei string `json:"tfuelwei"` } -type Inputs struct { +type Input struct { Address string `json:"address"` Sequence string `json:"sequence"` } diff --git a/platform/theta/transaction.go b/platform/theta/transaction.go index 72b192da3..d96100f05 100644 --- a/platform/theta/transaction.go +++ b/platform/theta/transaction.go @@ -1,9 +1,11 @@ package theta import ( + "fmt" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "strconv" + "strings" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { @@ -11,7 +13,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return p.GetTokenTxsByAddress(address, "") } -func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { trx, err := p.client.FetchAddressTransactions(address) if err != nil { return nil, err @@ -44,16 +46,28 @@ func Normalize(trx *Tx, address, token string) (tx blockatlas.Tx, ok bool) { Block: block, Sequence: block, } + inputs := trx.Data.Inputs + outputs := trx.Data.Outputs - input := trx.Data.Inputs[0] - output := trx.Data.Outputs[0] + // Doesn't support multisend + if len(inputs) == 0 && len(outputs) == 0 { + return tx, false + } + + input := inputs[0] + output := outputs[0] sequence, _ := strconv.ParseUint(input.Sequence, 10, 64) - // Condition for transfer THETA trnafer + // Condition for transfer THETA transfer if address != "" && token == "" && output.Coins.Tfuelwei == "0" { + direction, err := getDirection(address, input, output) + if err != nil { + return tx, false + } tx.From = input.Address tx.To = output.Address tx.Sequence = sequence + tx.Direction = direction tx.Type = blockatlas.TxTransfer tx.Meta = blockatlas.Transfer{ Value: blockatlas.Amount(output.Coins.Thetawei), @@ -68,9 +82,15 @@ func Normalize(trx *Tx, address, token string) (tx blockatlas.Tx, ok bool) { if address != "" && token == "tfuel" && output.Coins.Thetawei == "0" { from := input.Address to := output.Address + direction, err := getDirection(address, input, output) + if err != nil { + return tx, false + } + tx.From = from tx.To = to tx.Sequence = sequence + tx.Direction = direction tx.Type = blockatlas.TxNativeTokenTransfer tx.Meta = blockatlas.NativeTokenTransfer{ Name: "Theta Fuel", @@ -87,3 +107,21 @@ func Normalize(trx *Tx, address, token string) (tx blockatlas.Tx, ok bool) { return tx, false } + +// Get transaction direction +func getDirection(a string, inputs Input, outputs Output) (dir blockatlas.Direction, err error) { + address := strings.ToLower(a) + inAddr := inputs.Address + outAddr := outputs.Address + + switch { + case inAddr == address && outAddr == address: + return blockatlas.DirectionSelf, nil + case inAddr == address && outAddr != address: + return blockatlas.DirectionOutgoing, nil + case inAddr != address && outAddr == address: + return blockatlas.DirectionIncoming, nil + } + + return "", fmt.Errorf("direction unknown") +} diff --git a/platform/theta/transaction_test.go b/platform/theta/transaction_test.go index 130c177be..956f395cf 100644 --- a/platform/theta/transaction_test.go +++ b/platform/theta/transaction_test.go @@ -5,10 +5,11 @@ import ( "encoding/json" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "gotest.tools/assert" "testing" ) -var transferReceipt = `{ +var thetaTransfer = `{ "hash": "0x413d8423fd1e6df99fc57f425dfd58c791c877657b364c62c15905ade5114a70", "data": { "fee": { @@ -52,7 +53,7 @@ var tFuelTransfer = ` }, "inputs": [ { - "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", "coins": { "thetawei": "0", "tfuelwei": "44326000000000000" @@ -62,7 +63,7 @@ var tFuelTransfer = ` ], "outputs": [ { - "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", "coins": { "thetawei": "0", "tfuelwei": "44324000000000000" @@ -78,16 +79,17 @@ var tFuelTransfer = ` ` var expectedTransferTrx = blockatlas.Tx{ - ID: "0x413d8423fd1e6df99fc57f425dfd58c791c877657b364c62c15905ade5114a70", - Coin: coin.THETA, - From: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - To: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", - Fee: "2000000000000", - Date: 1557136781, - Type: "transfer", - Status: blockatlas.StatusCompleted, - Block: 700321, - Sequence: 43, + ID: "0x413d8423fd1e6df99fc57f425dfd58c791c877657b364c62c15905ade5114a70", + Coin: coin.THETA, + From: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + To: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + Fee: "2000000000000", + Date: 1557136781, + Type: "transfer", + Status: blockatlas.StatusCompleted, + Block: 700321, + Sequence: 43, + Direction: blockatlas.DirectionOutgoing, Meta: blockatlas.Transfer{ Value: "4000000000000000000", Symbol: "THETA", @@ -96,24 +98,25 @@ var expectedTransferTrx = blockatlas.Tx{ } var expectedTfuelTransfer = blockatlas.Tx{ - ID: "0x558cb5ec877119c2c84a677277efb5b3059adb830c6e74971b3dbe93221b7132", - Coin: coin.THETA, - From: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - To: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", - Fee: "2000000000000", - Date: 1557136821, - Type: blockatlas.TxNativeTokenTransfer, - Status: blockatlas.StatusCompleted, - Sequence: 44, - Block: 700327, + ID: "0x558cb5ec877119c2c84a677277efb5b3059adb830c6e74971b3dbe93221b7132", + Coin: coin.THETA, + From: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + To: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + Fee: "2000000000000", + Date: 1557136821, + Type: blockatlas.TxNativeTokenTransfer, + Status: blockatlas.StatusCompleted, + Sequence: 44, + Block: 700327, + Direction: blockatlas.DirectionIncoming, Meta: blockatlas.NativeTokenTransfer{ Name: "Theta Fuel", Symbol: "TFUEL", TokenID: "tfuel", Decimals: 18, Value: "44324000000000000", - From: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - To: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + From: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + To: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", }, } @@ -124,7 +127,7 @@ func TestNormalize(t *testing.T) { Token string Expected blockatlas.Tx }{ - {transferReceipt, "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", "", expectedTransferTrx}, + {thetaTransfer, "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", "", expectedTransferTrx}, {tFuelTransfer, "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", "tfuel", expectedTfuelTransfer}, } @@ -160,3 +163,28 @@ func TestNormalize(t *testing.T) { } } } + +func TestGetDirection(t *testing.T) { + var addrChecksum = "0x42616C88c7076FbE6e1596b734c13356b5A508a4" + var addr = "0x42616c88c7076fbe6e1596b734c13356b5a508a4" + var otherAddr = "0x8665a3cbc02ff17cf9d712e8a20f3d7bb1444517" + + var tests = []struct { + address string + expectedDir blockatlas.Direction + trxInput Input + trxOutput Output + }{ + {address: addrChecksum, expectedDir: blockatlas.DirectionSelf, trxInput: Input{Address: addr}, trxOutput: Output{Address: addr}}, + {address: addrChecksum, expectedDir: blockatlas.DirectionOutgoing, trxInput: Input{Address: addr}, trxOutput: Output{Address: otherAddr}}, + {address: addrChecksum, expectedDir: blockatlas.DirectionIncoming, trxInput: Input{Address: otherAddr}, trxOutput: Output{Address: addr}}, + } + + for _, test := range tests { + actualDir, err := getDirection(test.address, test.trxInput, test.trxOutput) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, test.expectedDir, actualDir, test.expectedDir) + } +} diff --git a/platform/tron/client.go b/platform/tron/client.go index 56b654a6b..e5c5f6548 100644 --- a/platform/tron/client.go +++ b/platform/tron/client.go @@ -31,9 +31,9 @@ func (c *Client) GetTxsOfAddress(address, token string) ([]Tx, error) { var txs Page err := c.Get(&txs, path, url.Values{ - "limit": {"25"}, - "token_id": {token}, - "order_by": {"block_timestamp,desc"}, + "limit": {"25"}, + "token_id": {token}, + "order_by": {"block_timestamp,desc"}, }) return txs.Txs, err From c2378e459a6140fb757b01b892d339c2106f13ec Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Mon, 23 Mar 2020 03:46:54 -0600 Subject: [PATCH 205/506] Add Initial Solana implementation (#962) * Initial Solana implementation * go fmt * Add public endpoint * Review comments * Update coin/coins.yml Co-Authored-By: hewig <360470+hewigovens@users.noreply.github.com> * Return empty tx list * Add content-type header Co-authored-by: Nick Kozlov Co-authored-by: hewig <360470+hewigovens@users.noreply.github.com> --- coin/coins.go | 16 +++- coin/coins.yml | 8 ++ config.yml | 3 + platform/platform.go | 2 + platform/solana/base.go | 22 +++++ platform/solana/client.go | 38 +++++++++ platform/solana/model.go | 62 ++++++++++++++ platform/solana/stake.go | 138 ++++++++++++++++++++++++++++++ platform/solana/stake_test.go | 151 +++++++++++++++++++++++++++++++++ platform/solana/transaction.go | 10 +++ 10 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 platform/solana/base.go create mode 100644 platform/solana/client.go create mode 100644 platform/solana/model.go create mode 100644 platform/solana/stake.go create mode 100644 platform/solana/stake_test.go create mode 100644 platform/solana/transaction.go diff --git a/coin/coins.go b/coin/coins.go index a9a0ba470..6fa1f08a8 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2020-03-22 19:36:28.030503 -0700 PDT m=+0.019507357 +// 2020-03-19 12:32:14.57052 -0600 MDT m=+0.001450289 // using data from coins.yml package coin @@ -71,6 +71,7 @@ const ( DGB = 20 ONE = 1023 KSM = 434 + SOL = 501 NEAR = 397 ) @@ -535,6 +536,16 @@ var Coins = map[uint]Coin{ MinConfirmations: 0, SampleAddr: "HewiDTQv92L2bVtkziZC8ASxrFUxr6ajQ62RXAnwQ8FDVmg", }, + SOL: { + ID: 501, + Handle: "solana", + Symbol: "SOL", + Name: "Solana", + Decimals: 9, + BlockTime: 500, + MinConfirmations: 0, + SampleAddr: "boot1Z6jb15CLqpaMTn2CxktktwZpRAVAgHZEW6SxQ7", + }, NEAR: { ID: 397, Handle: "near", @@ -684,6 +695,9 @@ func Harmony() Coin { func Kusama() Coin { return Coins[KSM] } +func Solana() Coin { + return Coins[SOL] +} func Near() Coin { return Coins[NEAR] } diff --git a/coin/coins.yml b/coin/coins.yml index df23ee9e3..92a442ffc 100644 --- a/coin/coins.yml +++ b/coin/coins.yml @@ -364,6 +364,14 @@ blockTime: 6000 sampleAddress: 'HewiDTQv92L2bVtkziZC8ASxrFUxr6ajQ62RXAnwQ8FDVmg' +- id: 501 + symbol: SOL + handle: solana + name: Solana + decimals: 9 + blockTime: 500 + sampleAddress: 'boot1Z6jb15CLqpaMTn2CxktktwZpRAVAgHZEW6SxQ7' + - id: 397 symbol: NEAR handle: near diff --git a/config.yml b/config.yml index 462139f2f..3b281c32d 100644 --- a/config.yml +++ b/config.yml @@ -212,5 +212,8 @@ kava: kusama: api: https://kusama.subscan.io/api +solana: + api: https://api.mainnet-beta.solana.com + near: api: https://staging-rpc.nearprotocol.com diff --git a/platform/platform.go b/platform/platform.go index ce97f1d9e..b19940f24 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -24,6 +24,7 @@ import ( "github.com/trustwallet/blockatlas/platform/ontology" "github.com/trustwallet/blockatlas/platform/polkadot" "github.com/trustwallet/blockatlas/platform/ripple" + "github.com/trustwallet/blockatlas/platform/solana" "github.com/trustwallet/blockatlas/platform/stellar" "github.com/trustwallet/blockatlas/platform/tezos" "github.com/trustwallet/blockatlas/platform/theta" @@ -71,6 +72,7 @@ func getPlatformMap() blockatlas.Platforms { coin.Ontology().Handle: ontology.Init(GetApiVar(coin.ONT)), coin.Algorand().Handle: algorand.Init(GetApiVar(coin.ALGO)), coin.Aeternity().Handle: aeternity.Init(GetApiVar(coin.AE)), + coin.Solana().Handle: solana.Init(GetApiVar(coin.SOL)), coin.Tezos().Handle: tezos.Init(GetApiVar(coin.XTZ), GetRpcVar(coin.XTZ)), coin.Binance().Handle: binance.Init(GetApiVar(coin.BNB), GetVar("binance.dex")), coin.Zilliqa().Handle: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL), GetVar("zilliqa.lookup")), diff --git a/platform/solana/base.go b/platform/solana/base.go new file mode 100644 index 000000000..f14ad7a45 --- /dev/null +++ b/platform/solana/base.go @@ -0,0 +1,22 @@ +package solana + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client +} + +func Init(api string) *Platform { + p := &Platform{ + client: Client{blockatlas.InitClient(api)}, + } + p.client.Headers["Content-Type"] = "application/json" + return p +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.SOL] +} diff --git a/platform/solana/client.go b/platform/solana/client.go new file mode 100644 index 000000000..94c2bc611 --- /dev/null +++ b/platform/solana/client.go @@ -0,0 +1,38 @@ +package solana + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +const stakeProgramId = "Stake11111111111111111111111111111111111111" + +type Client struct { + blockatlas.Request +} + +func (c *Client) GetCurrentVoteAccounts() (validators []VoteAccount, err error) { + var v VoteAccounts + err = c.RpcCall(&v, "getVoteAccounts", []string{}) + return v.Current, err +} + +func (c *Client) GetStakeAccounts() (accounts []KeyedAccount, err error) { + err = c.RpcCall(&accounts, "getProgramAccounts", []string{stakeProgramId}) + return +} + +func (c *Client) GetAccount(pubkey string) (account Account, err error) { + var r RpcAccount + err = c.RpcCall(&r, "getAccountInfo", []string{pubkey}) + return r.Account, err +} + +func (c *Client) GetEpochInfo() (epochInfo EpochInfo, err error) { + err = c.RpcCall(&epochInfo, "getEpochInfo", []string{}) + return +} + +func (c *Client) GetMinimumBalanceForRentExemption() (minimumBalance uint64, err error) { + err = c.RpcCall(&minimumBalance, "getMinimumBalanceForRentExemption", []uint64{4008}) + return +} diff --git a/platform/solana/model.go b/platform/solana/model.go new file mode 100644 index 000000000..bffac00ac --- /dev/null +++ b/platform/solana/model.go @@ -0,0 +1,62 @@ +package solana + +type VoteAccount struct { + NodePubkey string `json:"nodePubkey"` + VotePubkey string `json:"votePubkey"` + Commission uint64 `json:"commission"` + ActivatedStake uint64 `json:"activatedStake"` + RootSlot uint64 `json:"rootSlot"` + LastVote uint64 `json:"lastVote"` + EpochCredits [][]uint64 `json:"epochCredits"` + EpochVoteAccount bool `json:"epochVoteAccount"` +} + +type VoteAccounts struct { + Current []VoteAccount `json:"current"` + Delinquent []VoteAccount `json:"delinquent"` +} + +type Account struct { + Data string `json:"data"` + Executable bool `json:"executable"` + Lamports uint64 `json:"lamports"` + Owner string `json:"owner"` + RentEpoch uint64 `json:"rentEpoch"` +} + +type KeyedAccount struct { + Account Account `json:"account"` + Pubkey string `json:"pubkey"` +} + +type RpcAccount struct { + Context RpcContext `json:"context"` + Account Account `json:"value"` +} + +type RpcContext struct { + Slot uint64 `json:"slot"` +} + +type StakeState struct { + State uint32 + RentExemptReserve uint64 + AuthorizedStaker [32]byte + AuthorizedWithdrawer [32]byte + UnixTimestamp int64 + LockupEpoch uint64 + Custodian [32]byte + VoterPubkey [32]byte + Stake uint64 + ActivationEpoch uint64 + DeactivationEpoch uint64 + WarmupCooldownRate float64 + CreditsObserved uint64 +} + +type EpochInfo struct { + AbsoluteSlot uint64 `json:"absoluteSlot"` + Epoch uint64 `json:"epoch"` + SlotIndex uint64 `json:"slotIndex"` + SlotsInEpoch uint64 `json:"slotsInEpoch"` +} diff --git a/platform/solana/stake.go b/platform/solana/stake.go new file mode 100644 index 000000000..c69de5f99 --- /dev/null +++ b/platform/solana/stake.go @@ -0,0 +1,138 @@ +package solana + +import ( + "bytes" + "encoding/binary" + "github.com/btcsuite/btcutil/base58" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + services "github.com/trustwallet/blockatlas/services/assets" + "strconv" +) + +func arrayOfPubkey(pubkey string) [32]byte { + var array [32]byte + copy(array[:], base58.Decode(pubkey)) + return array +} + +func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { + results := make(blockatlas.ValidatorPage, 0) + + validators, err := p.client.GetCurrentVoteAccounts() + if err != nil { + return results, err + } + + minimumBalance, err := p.client.GetMinimumBalanceForRentExemption() + if err != nil { + minimumBalance = 0 + } + + for _, v := range validators { + results = append(results, normalizeValidator(v, minimumBalance)) + } + return results, nil +} + +func (p *Platform) GetDetails() blockatlas.StakingDetails { + return getDetails() +} + +func getDetails() blockatlas.StakingDetails { + return blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 0}, + MinimumAmount: "0", + LockTime: 0, + Type: blockatlas.DelegationTypeDelegate, + } +} + +func normalizeValidator(v VoteAccount, minimumBalance uint64) (validator blockatlas.Validator) { + minimumAmount := strconv.FormatUint(minimumBalance+1, 10) // Must stake at least 1 lamport + return blockatlas.Validator{ + Status: true, + ID: v.VotePubkey, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 0}, + MinimumAmount: blockatlas.Amount(minimumAmount), + LockTime: 0, + Type: blockatlas.DelegationTypeDelegate, + }, + } +} + +func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + accounts, err := p.client.GetStakeAccounts() + if err != nil { + return nil, err + } + + stakeAccounts := make([]StakeState, 0) + for _, keyedAccount := range accounts { + account, err := parseStakeData(keyedAccount.Account) + if err != nil { + return nil, err + } + if isAuthorized(account, address) { + stakeAccounts = append(stakeAccounts, account) + } + } + if len(stakeAccounts) == 0 { + return make(blockatlas.DelegationsPage, 0), nil + } + + validators, err := services.GetValidatorsMap(p) + if err != nil { + return nil, err + } + + epochInfo, err := p.client.GetEpochInfo() + if err != nil { + return nil, err + } + + return NormalizeDelegations(stakeAccounts, validators, epochInfo) +} + +func parseStakeData(account Account) (stakeAccount StakeState, err error) { + buffer := base58.Decode(account.Data) + r := bytes.NewReader(buffer) + err = binary.Read(r, binary.LittleEndian, &stakeAccount) + return +} + +func isAuthorized(stakeAccount StakeState, address string) bool { + return stakeAccount.AuthorizedStaker == arrayOfPubkey(address) +} + +func (p *Platform) UndelegatedBalance(address string) (string, error) { + account, err := p.client.GetAccount(address) + if err != nil { + return "0", err + } + return strconv.FormatUint(account.Lamports, 10), nil +} + +func NormalizeDelegations(stakeAccounts []StakeState, validators blockatlas.ValidatorMap, epochInfo EpochInfo) (blockatlas.DelegationsPage, error) { + results := make([]blockatlas.Delegation, 0) + for _, stakeState := range stakeAccounts { + votePubkey := base58.Encode(stakeState.VoterPubkey[:]) + validator, ok := validators[votePubkey] + if !ok { + return nil, errors.E("Validator not found", + errors.Params{"Validator": votePubkey, "Platform": "solana"}) + } + status := blockatlas.DelegationStatusPending + if stakeState.ActivationEpoch > 0 && stakeState.ActivationEpoch <= epochInfo.Epoch { + status = blockatlas.DelegationStatusActive + } + delegation := blockatlas.Delegation{ + Delegator: validator, + Value: strconv.FormatUint(stakeState.Stake, 10), + Status: status, + } + results = append(results, delegation) + } + return results, nil +} diff --git a/platform/solana/stake_test.go b/platform/solana/stake_test.go new file mode 100644 index 000000000..4817d2377 --- /dev/null +++ b/platform/solana/stake_test.go @@ -0,0 +1,151 @@ +package solana + +import ( + "encoding/json" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" + + "github.com/stretchr/testify/assert" +) + +const currentValidators = ` +[ + { + "activatedStake": 3733867423940, + "commission": 100, + "epochCredits": [ + [70,524224,516032],[71,532416,524224],[72,540608,532416],[73,548800,540608],[74,556992,548800],[75,565184,556992],[76,573376,565184],[77,581568,573376],[78,589760,581568],[79,597952,589760],[80,601055,597952] + ], + "epochVoteAccount": true, + "lastVote": 601085, + "nodePubkey": "boot1Z6jb15CLqpaMTn2CxktktwZpRAVAgHZEW6SxQ7", + "rootSlot": 601054, + "votePubkey": "2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW" + }, + { + "activatedStake": 10540011934, + "commission": 100 , + "epochCredits": [ + [78,4760,0],[79,12952,4760],[80,16055,12952] + ], + "epochVoteAccount": true, + "lastVote": 601085, + "nodePubkey": "B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY", + "rootSlot": 601054, + "votePubkey": "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5" + } +]` + +var expectedValidators = []blockatlas.Validator{ + blockatlas.Validator{ + Status: true, + ID: "2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW", + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 0}, + MinimumAmount: blockatlas.Amount("2282881"), + LockTime: 0, + Type: blockatlas.DelegationTypeDelegate, + }, + }, + blockatlas.Validator{ + Status: true, + ID: "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5", + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 0}, + MinimumAmount: blockatlas.Amount("2282881"), + LockTime: 0, + Type: blockatlas.DelegationTypeDelegate, + }, + }, +} + +func TestNormalizeValidator(t *testing.T) { + var validators []VoteAccount + minimumBalanceForRentExemption := uint64(2282880) // Arbitrary value; minimumBalanceForRentExemption is calculated from account data size + err := json.Unmarshal([]byte(currentValidators), &validators) + assert.Nil(t, err) + for i, v := range validators { + result := normalizeValidator(v, minimumBalanceForRentExemption) + assert.Equal(t, expectedValidators[i], result) + } +} + +var keyedStakeAccount = KeyedAccount{ + Account: Account{ + Data: "mrWMHx6j3BkmepJy67XLycC7LVeiq2NBESfV2YNmZvY62xT5jTgKnMzRBQheYtAuajncAniTEmU8QxgkpnytnXynTrMSJN4p6ihefU5cobkyCeSwMKugKGuBbyDLjQoUMu6BUKjDTFvjpJUHFCgz1Vaa8HSVscUqqRcioByf3owMUwHmEYsF8vuouLAqEQmo61wFkKfZELxLrhBbi2PQQZucryrnNDKXV4DY3oegLy9aMnMDZUeoDtDPPiJeM2F1Trh8ZkH1sQL6sQ5V", + Executable: false, + Lamports: 100000000000, + Owner: "Stake11111111111111111111111111111111111111", + RentEpoch: 80, + }, + Pubkey: "EgR17fgGmwQQaMZPsuJdk9oHw2xY8TJQj3Bp44o24mar", +} + +var stakeState = StakeState{ + State: 2, + RentExemptReserve: 2282880, + AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + UnixTimestamp: 0, + LockupEpoch: 0, + Custodian: arrayOfPubkey("11111111111111111111111111111111"), + VoterPubkey: arrayOfPubkey("5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5"), + Stake: 99997717120, + ActivationEpoch: 79, + DeactivationEpoch: ^uint64(0), + WarmupCooldownRate: 0.25, + CreditsObserved: 21143, +} + +func TestParseStakeData(t *testing.T) { + + result, err := parseStakeData(keyedStakeAccount.Account) + assert.Nil(t, err) + assert.Equal(t, result, stakeState) +} + +func TestIsAuthorized(t *testing.T) { + address := "B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY" + account, _ := parseStakeData(keyedStakeAccount.Account) + assert.True(t, isAuthorized(account, address)) + + address = "BADaddresscyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY" + assert.False(t, isAuthorized(account, address)) +} + +var stakeValidator = blockatlas.StakeValidator{ + ID: "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5", + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "Certus One", + Description: "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment.", + Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/solana/validators/assets/2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW/logo.png", + Website: "https://certus.one", + }, + Details: getDetails(), +} + +var validatorMap = blockatlas.ValidatorMap{ + "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5": stakeValidator, +} + +var epochInfo = EpochInfo{ + AbsoluteSlot: 165763, + Epoch: 80, + SlotIndex: 1923, + SlotsInEpoch: 2048, +} + +var delegation = blockatlas.DelegationsPage{ + { + Delegator: stakeValidator, + Value: "99997717120", + Status: blockatlas.DelegationStatusActive, + }, +} + +func TestNormalizeDelegations(t *testing.T) { + result, err := NormalizeDelegations([]StakeState{stakeState}, validatorMap, epochInfo) + assert.NoError(t, err) + assert.Equal(t, delegation, result) +} diff --git a/platform/solana/transaction.go b/platform/solana/transaction.go new file mode 100644 index 000000000..8ded47050 --- /dev/null +++ b/platform/solana/transaction.go @@ -0,0 +1,10 @@ +package solana + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + results := make(blockatlas.TxPage, 0) + return results, nil +} From f24a7f22975415189a28b4cf1da3cd099df96dc6 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> Date: Mon, 23 Mar 2020 21:11:15 +0300 Subject: [PATCH 206/506] [Observer] Start rewriting observer service: separate service - add observer_parser and observer_notifier (#968) * [Observer] Start rewriting observer service: separate service - add observer_parser and observer_notifier * Continue refactoring, speed up some tests * Add unit tests for all functions that can be tested by unit tests * Add observer_notifier service * Continue refactoring the notifier * Remove unused package * Small cleanup * Test & build fixes * Continue refactoring * Fix Unit test * Run fmt and add storage test for lookup * Update miniredis, refactor FindSubscriptions, * Add storage tests * Update notifier and parser * Add Normal logs for parser * Add Normal logs for parser * Fix tests * Fix tests * Add notifier test * Add notifier test fix * Fix integration tests * [Observer parser] Add graceful shutdown * Setup concurrent publishing (not yet finished) * [Observer parser] Update FetchBlocks and PublishBlocks * [Errors & Parser] Update errors package and FetchBlocks/PublishBlocks * Change queue type to Txs * [Observer parser] Update PublishBlocks * Change queue type to Txs * Fix tests * [MQ & Obserer notifier & Observer subscriber] Add RunConsumerWithCancel, add graceful shutdown to observer notifier and subscriber * [Observer healthcheck] Setup observer healthcheck servcie * Add unit tests for all functions that can be tested by unit tests, change parser.go * Small refactoring * Small change to healthcheck.go * [Observer parser] Add getTxsBatches and test, add rand.Seed to getBlockByNumberWithRetry * Add storage test * [Storage] Update deleteSubscriptions and addSubscriptions * [Observer healthcheck] Add exclude param * Refactoring Parser, MQ, add tests * Add txs batch limit to config.yml * [Observer parser] Update graceful shutdown * Fix integration tests Co-authored-by: Nick Kozlov Co-authored-by: Nick Kozlov --- CODE_OF_CONDUCT.md | 2 - Makefile | 38 +- api/observer_healthcheck.go | 12 + api/routes.go | 12 + cmd/observer_healthcheck/main.go | 50 +++ cmd/observer_notifier/main.go | 56 +++ cmd/observer_parser/main.go | 142 +++++++ cmd/observer_subscriber/main.go | 10 +- cmd/observer_worker/main.go | 109 ------ config.yml | 7 +- docker-compose.yml | 2 +- go.mod | 19 +- go.sum | 142 +++++-- internal/shutdown.go | 10 + mq/mq.go | 87 ++++- observer/dispatcher.go | 60 --- observer/observer.go | 128 ------ observer/observer_test.go | 357 ----------------- observer/retry.go | 40 -- observer/retry_test.go | 43 --- observer/stream.go | 107 ----- pkg/blockatlas/api.go | 77 ---- pkg/blockatlas/observer.go | 6 - pkg/blockatlas/platform.go | 76 ++++ pkg/blockatlas/tx.go | 106 +++++ pkg/blockatlas/tx_test.go | 365 ++++++++++++++++++ pkg/blockatlas/txset.go | 27 +- pkg/errors/errors.go | 9 +- pkg/semaphore/semaphore.go | 17 - platform/bitcoin/transaction.go | 44 +-- platform/bitcoin/transaction_test.go | 64 --- scripts/run_tests_postman.sh | 0 services/observer/healthcheck/healthcheck.go | 112 ++++++ services/observer/healthcheck/model.go | 6 + services/observer/notifier/notifier.go | 101 +++++ services/observer/notifier/notifier_test.go | 54 +++ services/observer/parser/parser.go | 297 ++++++++++++++ services/observer/parser/parser_test.go | 240 ++++++++++++ .../subscriber/subscriber.go} | 21 +- storage/addresses.go | 155 +++++--- storage/addresses_test.go | 347 +++++++++++++++++ storage/storage.go | 6 +- storage/tracker.go | 4 +- storage/tracker_test.go | 24 ++ tests/docker_test/environment_run_test.go | 20 + tests/docker_test/notifier_test.go | 108 ++++++ tests/docker_test/observer_test.go | 168 ++++++-- tests/docker_test/parser_test.go | 119 ++++++ tests/docker_test/subscriber_test.go | 66 ++++ 49 files changed, 2845 insertions(+), 1227 deletions(-) delete mode 100644 CODE_OF_CONDUCT.md create mode 100644 api/observer_healthcheck.go create mode 100644 cmd/observer_healthcheck/main.go create mode 100644 cmd/observer_notifier/main.go create mode 100644 cmd/observer_parser/main.go delete mode 100644 cmd/observer_worker/main.go delete mode 100644 observer/dispatcher.go delete mode 100644 observer/observer.go delete mode 100644 observer/observer_test.go delete mode 100644 observer/retry.go delete mode 100644 observer/retry_test.go delete mode 100644 observer/stream.go delete mode 100644 pkg/blockatlas/api.go delete mode 100644 pkg/semaphore/semaphore.go mode change 100755 => 100644 scripts/run_tests_postman.sh create mode 100644 services/observer/healthcheck/healthcheck.go create mode 100644 services/observer/healthcheck/model.go create mode 100644 services/observer/notifier/notifier.go create mode 100644 services/observer/notifier/notifier_test.go create mode 100644 services/observer/parser/parser.go create mode 100644 services/observer/parser/parser_test.go rename services/{subscription/subscribtion.go => observer/subscriber/subscriber.go} (82%) create mode 100644 storage/addresses_test.go create mode 100644 storage/tracker_test.go create mode 100644 tests/docker_test/notifier_test.go create mode 100644 tests/docker_test/parser_test.go create mode 100644 tests/docker_test/subscriber_test.go diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 5624ce360..000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,2 +0,0 @@ -* There are no stupid questions -* Be respectful :) diff --git a/Makefile b/Makefile index bc492346d..95278e9c2 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,8 @@ BUILD := $(shell git rev-parse --short HEAD) DATETIME := $(shell date +"%Y.%m.%d-%H:%M:%S") PROJECT_NAME := $(shell basename "$(PWD)") API_SERVICE := platform_api -OBSERVER_SERVICE := observer_worker +OSERVER_NOTIFIER := observer_notifier +OBSERVER_PARSER := observer_parser OBSERVER_SUBSCRIBER := observer_subscriber SWAGGER_API := swagger_api COIN_FILE := coin/coins.yml @@ -34,7 +35,8 @@ STDERR := /tmp/.$(PROJECT_NAME)-stderr.txt # PID file will keep the process id of the server PID_API := /tmp/.$(PROJECT_NAME).$(API_SERVICE).pid -PID_OBSERVER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SERVICE).pid +PID_OBSERVER_NOTIFIER := /tmp/.$(PROJECT_NAME).$(OBSERVER_NOTIFIER).pid +PID_OBSERVER_PARSER := /tmp/.$(PROJECT_NAME).$(OBSERVER_PARSER).pid PID_OBSERVER_SUBSCRIBER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SUBSCRIBER).pid PID_SWAGGER_API := /tmp/.$(PROJECT_NAME).$(SWAGGER_API).pid PID_DYSON := /tmp/.$(PROJECT_NAME).dyson.pid @@ -46,7 +48,7 @@ install: go-get ## start: Start API, Observer and Sync in development mode. start: - @bash -c "$(MAKE) clean compile start-platform-api start-observer-worker start-observer-subscriber" + @bash -c "$(MAKE) clean compile start-platform-api start-observer-parser start-observer-notifier start-observer-subscriber" ## start-api: Start platform api in development mode. start-platform-api: stop @@ -69,14 +71,21 @@ start-swagger-api: stop @cat $(PID_SWAGGER_API) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" -## start-observer-worker: Start swagger api in development mode. -start-observer-worker: stop +## start-observer-parser: Start observer-parser in development mode. +start-observer-parser: stop @echo " > Starting $(PROJECT_NAME)" - @-$(GOBIN)/$(OBSERVER_SERVICE)/observer_worker -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER) - @cat $(PID_OBSERVER) | sed "/^/s/^/ \> Sync PID: /" + @-$(GOBIN)/$(OBSERVER_PARSER)/observer_parser -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_PARSER) + @cat $(PID_OBSERVER_PARSER) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" -## start-observer-worker: Start swagger api in development mode. +## start-observer-notifier: Start observer-notifier in development mode. +start-observer-notifier: stop + @echo " > Starting $(PROJECT_NAME)" + @-$(GOBIN)/$(OBSERVER_NOTIFIER)/observer_notifier -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_NOTIFIER) + @cat $(PID_OBSERVER_NOTIFIER) | sed "/^/s/^/ \> Sync PID: /" + @echo " > Error log: $(STDERR)" + +## start-observer-subscriber: Start observer-subscriber in development mode. start-observer-subscriber: stop @echo " > Starting $(PROJECT_NAME)" @-$(GOBIN)/$(OBSERVER_SUBSCRIBER)/observer_subscriber -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_SUBSCRIBER) @@ -85,13 +94,14 @@ start-observer-subscriber: stop ## stop: Stop development mode. stop: - @-touch $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) + @-touch $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) @-kill `cat $(PID_API)` 2> /dev/null || true - @-kill `cat $(PID_OBSERVER)` 2> /dev/null || true + @-kill `cat $(OBSERVER_NOTIFIER)` 2> /dev/null || true + @-kill `cat $(OBSERVER_PARSER)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER_SUBSCRIBER)` 2> /dev/null || true @-kill `cat $(PID_SWAGGER_API)` 2> /dev/null || true @-kill `cat $(PID_DYSON)` 2> /dev/null || true - @-rm $(PID_API) $(PID_OBSERVER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) + @-rm $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) stop-dyson: @kill `cat $(PID_DYSON)` 2> /dev/null || true @@ -205,8 +215,10 @@ go-compile: go-get go-build go-build: @echo " > Building platform_api binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API_SERVICE)/platform_api ./cmd/$(API_SERVICE) - @echo " > Building observer_worker binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SERVICE)/observer_worker ./cmd/$(OBSERVER_SERVICE) + @echo " > Building observer_notifier binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OSERVER_NOTIFIER)/observer_notifier ./cmd/$(OSERVER_NOTIFIER) + @echo " > Building observer_parser binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_PARSER)/observer_parser ./cmd/$(OBSERVER_PARSER) @echo " > Building observer_subscriber binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SUBSCRIBER)/observer_subscriber ./cmd/$(OBSERVER_SUBSCRIBER) @echo " > Building swagger_api binary..." diff --git a/api/observer_healthcheck.go b/api/observer_healthcheck.go new file mode 100644 index 000000000..dafe734c6 --- /dev/null +++ b/api/observer_healthcheck.go @@ -0,0 +1,12 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/services/observer/healthcheck" + "net/http" +) + +func GetObserverStatus(c *gin.Context) { + exclude := splitParam(c.Query("exclude")) + c.JSON(http.StatusOK, healthcheck.GetStatus(exclude)) +} diff --git a/api/routes.go b/api/routes.go index c843a21ab..8766293f3 100644 --- a/api/routes.go +++ b/api/routes.go @@ -7,6 +7,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" + "strings" ) var routers = make(map[string]gin.IRouter) @@ -74,6 +75,10 @@ func SetupPlatformAPI(root gin.IRouter) { logger.Info("Routes set up", logger.Params{"routes": len(routers)}) } +func SetupHealthCheckApi(root gin.IRouter) { + root.GET("/", GetObserverStatus) +} + // getRouter lazy loads routers func getRouter(router *gin.RouterGroup, handle string) gin.IRouter { key := fmt.Sprintf("%s/%s", router.BasePath(), handle) @@ -107,3 +112,10 @@ func GetStatus(c *gin.Context) { "date": internal.Date, }) } + +func splitParam(param string) []string { + splitFn := func(c rune) bool { + return c == ',' + } + return strings.FieldsFunc(param, splitFn) +} \ No newline at end of file diff --git a/cmd/observer_healthcheck/main.go b/cmd/observer_healthcheck/main.go new file mode 100644 index 000000000..b7169727f --- /dev/null +++ b/cmd/observer_healthcheck/main.go @@ -0,0 +1,50 @@ +package main + +import ( + sentrygin "github.com/getsentry/sentry-go/gin" + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/services/observer/healthcheck" + "github.com/trustwallet/blockatlas/storage" + "time" +) + +const ( + defaultPort = "3333" + defaultConfigPath = "../../config.yml" +) + +var ( + port, confPath string + engine *gin.Engine + cache *storage.Storage +) + +func init() { + port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) + + internal.InitConfig(confPath) + redisHost := viper.GetString("storage.redis") + cache = internal.InitRedis(redisHost) + logger.InitLogger() + tmp := sentrygin.New(sentrygin.Options{}) + sg := &tmp + + engine = internal.InitEngine(sg, viper.GetString("gin.mode")) + + platform.Init(viper.GetString("platform")) +} + +func main() { + for _, blockAPI := range platform.BlockAPIs { + go healthcheck.Worker(cache, blockAPI) + time.Sleep(time.Millisecond * 200) + } + + api.SetupHealthCheckApi(engine) + internal.SetupGracefulShutdown(port, engine) +} diff --git a/cmd/observer_notifier/main.go b/cmd/observer_notifier/main.go new file mode 100644 index 000000000..d3032ea21 --- /dev/null +++ b/cmd/observer_notifier/main.go @@ -0,0 +1,56 @@ +package main + +import ( + "context" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/services/observer/notifier" + "github.com/trustwallet/blockatlas/storage" + "time" +) + +const ( + defaultConfigPath = "../../config.yml" +) + +var ( + confPath string + cache *storage.Storage +) + +func init() { + _, confPath = internal.ParseArgs("", defaultConfigPath) + + internal.InitConfig(confPath) + logger.InitLogger() + + redisHost := viper.GetString("storage.redis") + mqHost := viper.GetString("observer.rabbitmq.uri") + prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + + cache = internal.InitRedis(redisHost) + internal.InitRabbitMQ(mqHost, prefetchCount) + + if err := mq.RawTransactions.Declare(); err != nil { + logger.Fatal(err) + } + + if err := mq.Transactions.Declare(); err != nil { + logger.Fatal(err) + } + + go storage.RestoreConnectionWorker(cache, redisHost, time.Second*10) + go mq.RestoreConnectionWorker(mqHost, mq.RawTransactions, time.Second*10) +} + +func main() { + defer mq.Close() + + ctx, cancel := context.WithCancel(context.Background()) + + go mq.RawTransactions.RunConsumerWithCancel(notifier.RunNotifier, cache, ctx) + + internal.SetupGracefulShutdownForObserver(cancel) +} diff --git a/cmd/observer_parser/main.go b/cmd/observer_parser/main.go new file mode 100644 index 000000000..978418d00 --- /dev/null +++ b/cmd/observer_parser/main.go @@ -0,0 +1,142 @@ +package main + +import ( + "context" + "fmt" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/services/observer/notifier" + "github.com/trustwallet/blockatlas/services/observer/parser" + "github.com/trustwallet/blockatlas/storage" + "os" + "os/signal" + "sync" + "syscall" + "time" +) + +const ( + defaultConfigPath = "../../config.yml" +) + +var ( + confPath string + cache *storage.Storage + backlogTime, minInterval, maxInterval time.Duration + maxBackLogBlocks int64 + txsBatchLimit uint +) + +func init() { + _, confPath = internal.ParseArgs("", defaultConfigPath) + + internal.InitConfig(confPath) + logger.InitLogger() + + redisHost := viper.GetString("storage.redis") + mqHost := viper.GetString("observer.rabbitmq.uri") + prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + platformHandle := viper.GetString("platform") + + cache = internal.InitRedis(redisHost) + internal.InitRabbitMQ(mqHost, prefetchCount) + platform.Init(platformHandle) + + if err := mq.RawTransactions.Declare(); err != nil { + logger.Fatal(err) + } + + if len(platform.BlockAPIs) == 0 { + logger.Fatal("No APIs to observe") + } + txsBatchLimit = viper.GetUint("observer.txs_batch_limit") + backlogTime = viper.GetDuration("observer.backlog") + minInterval = viper.GetDuration("observer.block_poll.min") + maxInterval = viper.GetDuration("observer.block_poll.max") + maxBackLogBlocks = viper.GetInt64("observer.backlog_max_blocks") + if minInterval >= maxInterval { + logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") + } + + go mq.FatalWorker(time.Second * 10) + time.Sleep(time.Millisecond) + go storage.RestoreConnectionWorker(cache, redisHost, time.Second*10) + time.Sleep(time.Millisecond) +} + +func main() { + defer mq.Close() + var ( + wg sync.WaitGroup + coinCancel = make(map[string]context.CancelFunc) + stopChannel = make(chan<- struct{}, len(platform.BlockAPIs)) + ) + + wg.Add(len(platform.BlockAPIs)) + for _, api := range platform.BlockAPIs { + coin := api.Coin() + pollInterval := notifier.GetInterval(coin.BlockTime, minInterval, maxInterval) + + var backlogCount int + if coin.BlockTime == 0 { + backlogCount = 50 + logger.Warn("Unknown block time", logger.Params{"coin": coin.Handle}) + } else { + backlogCount = int(backlogTime / pollInterval) + } + + // do not allow + if txsBatchLimit < parser.MinTxsBatchLimit { + txsBatchLimit = parser.MinTxsBatchLimit + } + + ctx, cancel := context.WithCancel(context.Background()) + + coinCancel[coin.Handle] = cancel + + params := parser.Params{ + Ctx: ctx, + Api: api, + Storage: cache, + Queue: mq.RawTransactions, + ParsingBlocksInterval: pollInterval, + BacklogCount: backlogCount, + MaxBacklogBlocks: maxBackLogBlocks, + StopChannel: stopChannel, + TxBatchLimit: txsBatchLimit, + } + + go parser.RunParser(params) + + logger.Info("Parser params", logger.Params{ + "interval": pollInterval, + "backlog": backlogCount, + "Max backlog": maxBackLogBlocks, + "Txs Batch limit": txsBatchLimit, + }) + + wg.Done() + } + + wg.Wait() + + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) + <-quit + logger.Info("Shutdown parser ...") + for coin, cancel := range coinCancel { + logger.Info(fmt.Sprintf("Starting to stop %s parser...", coin)) + cancel() + } + for { + if len(stopChannel) == len(platform.BlockAPIs) { + logger.Info("All parsers are stopped") + break + } + } + + logger.Info("Exiting gracefully") +} diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index f3830265f..3a169996c 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -1,12 +1,13 @@ package main import ( + "context" "github.com/spf13/viper" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/services/subscription" + "github.com/trustwallet/blockatlas/services/observer/subscriber" "github.com/trustwallet/blockatlas/storage" "time" ) @@ -43,6 +44,9 @@ func main() { if err := mq.Subscriptions.Declare(); err != nil { logger.Fatal(err) } - mq.Subscriptions.RunConsumer(subscription.Consume, cache) - <-make(chan struct{}) + ctx, cancel := context.WithCancel(context.Background()) + + go mq.Subscriptions.RunConsumerWithCancel(subscriber.RunSubscriber, cache, ctx) + + internal.SetupGracefulShutdownForObserver(cancel) } diff --git a/cmd/observer_worker/main.go b/cmd/observer_worker/main.go deleted file mode 100644 index 652117461..000000000 --- a/cmd/observer_worker/main.go +++ /dev/null @@ -1,109 +0,0 @@ -package main - -import ( - "context" - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/observer" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/storage" - "sync" - "time" -) - -const ( - defaultConfigPath = "../../config.yml" -) - -var ( - confPath string - cache *storage.Storage -) - -func init() { - _, confPath = internal.ParseArgs("", defaultConfigPath) - - internal.InitConfig(confPath) - logger.InitLogger() - - redisHost := viper.GetString("storage.redis") - mqHost := viper.GetString("observer.rabbitmq.uri") - prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") - platformHandle := viper.GetString("platform") - - cache = internal.InitRedis(redisHost) - internal.InitRabbitMQ(mqHost, prefetchCount) - platform.Init(platformHandle) - - go mq.RestoreConnectionWorker(mqHost, mq.Transactions, time.Second*10) - go storage.RestoreConnectionWorker(cache, redisHost, time.Second*10) -} - -func main() { - defer mq.Close() - if err := mq.Transactions.Declare(); err != nil { - logger.Fatal(err) - } - - if len(platform.BlockAPIs) == 0 { - logger.Fatal("No APIs to observe") - } - - backlogTime := viper.GetDuration("observer.backlog") - minInterval := viper.GetDuration("observer.block_poll.min") - maxInterval := viper.GetDuration("observer.block_poll.max") - - if minInterval >= maxInterval { - logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") - } - - var wg sync.WaitGroup - wg.Add(len(platform.BlockAPIs)) - - for _, api := range platform.BlockAPIs { - coin := api.Coin() - pollInterval := observer.GetInterval(coin.BlockTime, minInterval, maxInterval) - - // Stream incoming blocks - var backlogCount int - if coin.BlockTime == 0 { - backlogCount = 50 - logger.Warn("Unknown block time", logger.Params{"coin": coin.ID}) - } else { - backlogCount = int(backlogTime / pollInterval) - } - - stream := observer.Stream{ - BlockAPI: api, - Tracker: cache, - PollInterval: pollInterval, - BacklogCount: backlogCount, - } - blocks := stream.Execute(context.Background()) - - // Check for transaction events - obs := observer.Observer{ - Storage: cache, - Coin: coin.ID, - } - events := obs.Execute(blocks) - - // Dispatch events - var dispatcher observer.Dispatcher - go func() { - dispatcher.Run(events) - wg.Done() - }() - - logger.Info("Observing", logger.Params{ - "coin": coin, - "interval": pollInterval, - "backlog": backlogCount, - }) - } - - wg.Wait() - logger.Info("Exiting cleanly") -} diff --git a/config.yml b/config.yml index 3b281c32d..36d6b991c 100644 --- a/config.yml +++ b/config.yml @@ -17,19 +17,18 @@ platform: all # The transaction watcher observer: - auth: test # Don't request blocks older than this backlog: 3h # Don't request more than N blocks at once backlog_max_blocks: 200 - # Max connections to open to API - stream_conns: 16 + # Limit amount of transactions in batch + txs_batch_limit: 3000 # Block polling interval block_poll: min: 3s max: 30s rabbitmq: - uri: amqp://rabbit:5672 + uri: amqp://localhost:5672 consumer: prefetch_count: 10 diff --git a/docker-compose.yml b/docker-compose.yml index 7601470db..c7513dccf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,7 +33,7 @@ services: build: context: . args: - - SERVICE=observer_worker + - SERVICE=observer_notifier links: - redis - rabbit diff --git a/go.mod b/go.mod index b5168b5f4..5644f85a9 100644 --- a/go.mod +++ b/go.mod @@ -8,9 +8,11 @@ require ( github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/Pantani/httpexpect v2.0.0+incompatible github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 + github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect + github.com/alicebob/miniredis v2.5.0+incompatible + github.com/aristanetworks/goarista v0.0.0-20200310212843-2da4c1f5881b // indirect github.com/btcsuite/btcutil v1.0.1 - github.com/cenkalti/backoff v2.2.1+incompatible - github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05 + github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c // indirect github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect @@ -19,29 +21,30 @@ require ( github.com/getsentry/sentry-go v0.4.0 github.com/gin-gonic/gin v1.5.0 github.com/go-redis/redis v6.15.6+incompatible + github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/hewigovens/go-coincodec v1.0.4 - github.com/jinzhu/gorm v1.9.12 github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/lib/pq v1.1.1 // indirect github.com/mitchellh/mapstructure v1.1.2 github.com/mr-tron/base58 v1.1.3 github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v0.1.1 // indirect github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.4.0 - github.com/robfig/cron/v3 v3.0.1 github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 github.com/sirupsen/logrus v1.4.2 - github.com/spf13/cast v1.3.1 + github.com/spf13/cast v1.3.1 // indirect github.com/spf13/viper v1.6.2 github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 github.com/stretchr/testify v1.4.0 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.5 github.com/wealdtech/go-ens/v3 v3.2.0 - golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d + github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect + go.uber.org/atomic v1.4.0 + golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect + golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect gopkg.in/yaml.v2 v2.2.8 ) diff --git a/go.sum b/go.sum index 849be0207..20543a1b8 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,7 @@ github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxB github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= @@ -37,6 +38,8 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.5.3 h1:2odJnXLbFZcoV9KYtQ+7TH1UOq3dn3AssMgieaezkR4= github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE= @@ -48,19 +51,27 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMwWcqkLzDAQugVEwedisr5nRJ1r+7LYnv0U= +github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI= +github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= github.com/allegro/bigcache v1.2.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/apilayer/freegeoip v3.5.0+incompatible/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU= +github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= +github.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5 h1:L0TwgZQo7Mga9im6FvKEZGIvyLE/VG/HI5loz5LpvC0= github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/aristanetworks/goarista v0.0.0-20200310212843-2da4c1f5881b h1:VBFuX8nQQ57A6OGYGOLugx/Sc488F0nNIdTtcmNq9qE= +github.com/aristanetworks/goarista v0.0.0-20200310212843-2da4c1f5881b/go.mod h1:QZe5Yh80Hp1b6JxQdpfSEEe8X7hTyTEZSosSrFf/oJE= +github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= github.com/btcsuite/btcd v0.0.0-20190418232430-6867ff32788a/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= @@ -79,15 +90,18 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05 h1:2qhpRcnS61pafr2CbHYBr9ZWN7I8txgEOkBUm8Z7NH4= -github.com/chenjiandongx/ginprom v0.0.0-20191227144730-e11ebf56bc05/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= @@ -110,8 +124,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= -github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -124,6 +136,9 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -131,26 +146,33 @@ github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZi github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= github.com/elastic/gosigar v0.10.4 h1:6jfw75dsoflhBMRdO6QPzQUgLqUYTsQQQRkkcsHsuPo= github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= github.com/ethereum/go-ethereum v1.9.10 h1:jooX7tWcscpC7ytufk73t9JMCeJQ7aJF2YmZJQEuvFo= github.com/ethereum/go-ethereum v1.9.10/go.mod h1:lXHkVo/MTvsEXfYsmNzelZ8R1e0DTvdk/wMZJIRpaRw= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a h1:1znxn4+q2MrEdTk1eCk6KIV3muTYVclBIB6CTVR/zBc= github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getsentry/sentry-go v0.4.0 h1:WqRI2/7EiALbdG9qGB47c0Aks1tdznG5DZd6GSQ1y/8= github.com/getsentry/sentry-go v0.4.0/go.mod h1:xkGcb82SipKQloDNa5b7hTV4VdEyc2bhwd1/UczP52k= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= @@ -161,10 +183,13 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/ github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= @@ -190,7 +215,6 @@ github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rm github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-redis/redis v6.15.6+incompatible h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be8FqJQRhdQZ5Sg= github.com/go-redis/redis v6.15.6+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -198,8 +222,6 @@ github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -208,9 +230,12 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38 h1:y0Wmhvml7cGnzPa9nocn/fMraMH/lMDdeG+rkx4VgYY= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -228,11 +253,14 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6/go.mod h1:Au3iQ8DvDis8hZ4q2OzRcaKYlAsPt+fYvib5q4nIqu4= github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= @@ -242,6 +270,7 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/hewigovens/go-coincodec v1.0.4 h1:asF02q8WfDwVQjU1O0VZYbOBer0cPJUmTiZKfAgqBYM= github.com/hewigovens/go-coincodec v1.0.4/go.mod h1:+LTdzScnu782gMt0J3ZccPY9S2uyrGe0R1LUYGWecfc= github.com/howeyc/fsnotify v0.9.0/go.mod h1:41HzSPxBGeFRQKEEwgh49TRw/nKBsYZ2cF1OzPjSJsA= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= @@ -252,6 +281,7 @@ github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/C github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= @@ -259,12 +289,8 @@ github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrO github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= -github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= @@ -273,12 +299,14 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= @@ -293,15 +321,23 @@ github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6 github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= @@ -319,6 +355,7 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= @@ -332,8 +369,6 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= -github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= 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= @@ -348,8 +383,10 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= @@ -372,10 +409,14 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= +github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -394,6 +435,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -406,32 +449,29 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic= github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= +github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= github.com/robertkrimen/otto v0.0.0-20170205013659-6a77b7cbc37d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= @@ -453,6 +493,7 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -501,6 +542,9 @@ github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAy github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= +github.com/tjfoc/gmsm v1.3.0/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= @@ -524,16 +568,18 @@ github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtE github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/wealdtech/go-ens/v3 v3.1.0/go.mod h1:P2OEBvgkhXLrPzPN+eR5z2/wFIGwHyijTDvpuC1xLlo= github.com/wealdtech/go-ens/v3 v3.2.0 h1:bshYk63BUJaIriX3UoAcYKh1tVI85kI1Xbg3jAnM/NM= github.com/wealdtech/go-ens/v3 v3.2.0/go.mod h1:P2OEBvgkhXLrPzPN+eR5z2/wFIGwHyijTDvpuC1xLlo= github.com/wealdtech/go-multicodec v1.2.0 h1:9AHSxcSE9F9r6ZvQLAO0EXCdM08QfYohaXmW3k6sSh4= github.com/wealdtech/go-multicodec v1.2.0/go.mod h1:aedGMaTeYkIqi/KCPre1ho5rTb3hGpu/snBOS3GQLw4= github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= +github.com/wealdtech/go-string2eth v1.0.0 h1:jY6b1MVqU6k2Uw/kvcU1Y9/3dDyXfPzZrOFspt82UJs= github.com/wealdtech/go-string2eth v1.0.0/go.mod h1:UZA/snEybGcD6n+Pl+yoDjmexlEJ6dtoS9myfM83Ol4= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -542,14 +588,20 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0= +github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -558,17 +610,23 @@ golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -576,6 +634,7 @@ golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -587,6 +646,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -594,6 +655,7 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -603,6 +665,7 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -613,54 +676,77 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd h1:hHkvGJK23seRCflePJnVa9IMv8fsuavSCWKd11kDQFs= +golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200218151345-dad8c97a84f5/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190213234257-ec84240a7772/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff h1:uuol9OUzSvZntY1v963NAbVd7A+PHLMz1FlCe3Lorcs= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -669,5 +755,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/shutdown.go b/internal/shutdown.go index 37f958689..234766d9d 100644 --- a/internal/shutdown.go +++ b/internal/shutdown.go @@ -43,3 +43,13 @@ func SetupGracefulShutdown(port string, engine *gin.Engine) { logger.Info("Stop signal Received", stop) logger.Info("Waiting for all jobs to stop") } + +func SetupGracefulShutdownForObserver(cancel context.CancelFunc) { + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) + <-quit + cancel() + logger.Info("Shutdown ...") + time.Sleep(time.Second * 5) + logger.Info("Exiting gracefully") +} diff --git a/mq/mq.go b/mq/mq.go index 5804b8c6d..1ad87c08f 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -1,6 +1,7 @@ package mq import ( + "context" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/storage" @@ -14,13 +15,15 @@ var ( ) type ( - Queue string - Consumer func(amqp.Delivery, storage.Addresses) + Queue string + Consumer func(amqp.Delivery, storage.Addresses) + MessageChannel <-chan amqp.Delivery ) const ( Transactions Queue = "transactions" Subscriptions Queue = "subscriptions" + RawTransactions Queue = "rawTransactions" defaultPrefetchCount = 5 minPrefetchCount = 1 ) @@ -55,6 +58,21 @@ func (q Queue) Publish(body []byte) error { }) } +func (q Queue) RunConsumerForChannelWithCancel(consumer Consumer, messageChannel MessageChannel, cache storage.Addresses, ctx context.Context) { + for { + select { + case <-ctx.Done(): + logger.Info("Consumer stopped") + return + case message := <-messageChannel: + if message.Body == nil { + continue + } + go consumer(message, cache) + } + } +} + func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { messageChannel, err := amqpChan.Consume( string(q), @@ -90,6 +108,71 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { } } +func (q Queue) RunConsumerWithCancel(consumer Consumer, cache storage.Addresses, ctx context.Context) { + messageChannel, err := amqpChan.Consume( + string(q), + "", + false, + false, + false, + false, + nil, + ) + if err != nil { + logger.Fatal("MQ issue " + err.Error()) + return + } + + if PrefetchCount < minPrefetchCount { + logger.Info("Change prefetch count to default") + PrefetchCount = defaultPrefetchCount + } + + err = amqpChan.Qos( + PrefetchCount, + 0, + true, + ) + + if err != nil { + logger.Error("no qos limit ", err) + } + + for { + select { + case <-ctx.Done(): + logger.Info("Consumer stopped") + return + case message := <-messageChannel: + if message.Body == nil { + continue + } + go consumer(message, cache) + } + } +} + +func (q Queue) GetMessageChannel() MessageChannel { + messageChannel, err := amqpChan.Consume( + string(q), + "", + false, + false, + false, + false, + nil, + ) + if err != nil { + logger.Fatal("MQ issue " + err.Error()) + } + + return messageChannel +} + +func (mc MessageChannel) GetMessage() amqp.Delivery { + return <-mc +} + func RestoreConnectionWorker(uri string, queue Queue, timeout time.Duration) { logger.Info("Run MQ RestoreConnectionWorker") for { diff --git a/observer/dispatcher.go b/observer/dispatcher.go deleted file mode 100644 index 4301249ea..000000000 --- a/observer/dispatcher.go +++ /dev/null @@ -1,60 +0,0 @@ -package observer - -import ( - "encoding/json" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - "net/http" -) - -type Dispatcher struct { - Client http.Client -} - -type DispatchEvent struct { - Action blockatlas.TransactionType `json:"action"` - Result *blockatlas.Tx `json:"result"` - GUID string `json:"guid"` -} - -func (d *Dispatcher) Run(events <-chan Event) { - for event := range events { - d.dispatch(event) - } -} - -func (d *Dispatcher) dispatch(event Event) { - guid := event.Subscription.GUID - - action := DispatchEvent{ - Action: event.Tx.Type, - Result: event.Tx, - GUID: guid, - } - - txJson, err := json.Marshal(action) - if err != nil { - logger.Panic(err) - } - - logParams := logger.Params{ - "guid": guid, - "coin": event.Subscription.Coin, - "txID": event.Tx.ID, - } - - go d.postMessageToQueue(guid, txJson, logParams) - - logger.Info("Dispatching messages...", logParams) -} - -func (d *Dispatcher) postMessageToQueue(message string, rawMessage []byte, logParams logger.Params) { - err := mq.Transactions.Publish(rawMessage) - if err != nil { - err = errors.E(err, "Failed to dispatch event", errors.Params{"message": message}, logParams) - logger.Fatal(err, logger.Params{"message": message}, logParams) - } - logger.Info("Message dispatched", logger.Params{"message": message}, logParams) -} diff --git a/observer/observer.go b/observer/observer.go deleted file mode 100644 index aaf8470f0..000000000 --- a/observer/observer.go +++ /dev/null @@ -1,128 +0,0 @@ -package observer - -import ( - mapset "github.com/deckarep/golang-set" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" - "github.com/trustwallet/blockatlas/platform/bitcoin" - "github.com/trustwallet/blockatlas/storage" - "time" -) - -type Event struct { - Subscription blockatlas.Subscription - Tx *blockatlas.Tx -} - -type Observer struct { - Storage storage.Addresses - Coin uint -} - -func (o *Observer) Execute(blocks <-chan *blockatlas.Block) <-chan Event { - events := make(chan Event) - go o.run(events, blocks) - return events -} - -func (o *Observer) run(events chan<- Event, blocks <-chan *blockatlas.Block) { - for block := range blocks { - o.processBlock(events, block) - } -} - -func (o *Observer) processBlock(events chan<- Event, block *blockatlas.Block) { - txMap := GetTxs(block) - if len(txMap) == 0 { - return - } - - // Build list of unique addresses - var addresses []string - for address := range txMap { - if len(address) == 0 { - continue - } - addresses = append(addresses, address) - } - - // Lookup subscriptions - subs, err := o.Storage.Lookup(o.Coin, addresses) - if err != nil || len(subs) == 0 { - return - } - for _, sub := range subs { - tx, ok := txMap[sub.Address] - if !ok { - continue - } - for _, tx := range tx.Txs() { - tx.Direction = getDirection(tx, sub.Address) - inferUtxoValue(&tx, sub.Address, o.Coin) - events <- Event{ - Subscription: sub, - Tx: &tx, - } - } - } -} - -func GetTxs(block *blockatlas.Block) map[string]*blockatlas.TxSet { - txMap := make(map[string]*blockatlas.TxSet) - for i := 0; i < len(block.Txs); i++ { - addresses := block.Txs[i].GetAddresses() - addresses = append(addresses, block.Txs[i].GetUtxoAddresses()...) - for _, address := range addresses { - if txMap[address] == nil { - txMap[address] = new(blockatlas.TxSet) - } - txMap[address].Add(&block.Txs[i]) - } - } - return txMap -} - -func getDirection(tx blockatlas.Tx, address string) blockatlas.Direction { - if len(tx.Inputs) > 0 && len(tx.Outputs) > 0 { - addressSet := mapset.NewSet(address) - return bitcoin.InferDirection(&tx, addressSet) - } - switch meta := tx.Meta.(type) { - case blockatlas.TokenTransfer: - return determineDirection(address, meta.From, meta.To) - case blockatlas.NativeTokenTransfer: - return determineDirection(address, meta.From, meta.To) - default: - return determineDirection(address, tx.From, tx.To) - } -} - -func determineDirection(address, from, to string) blockatlas.Direction { - if address == to { - if from == to { - return blockatlas.DirectionSelf - } - return blockatlas.DirectionIncoming - } - return blockatlas.DirectionOutgoing -} - -func inferUtxoValue(tx *blockatlas.Tx, address string, coinIndex uint) { - if len(tx.Inputs) > 0 && len(tx.Outputs) > 0 { - addressSet := mapset.NewSet(address) - value := bitcoin.InferValue(tx, tx.Direction, addressSet) - tx.Meta = blockatlas.Transfer{ - Value: value, - Symbol: coin.Coins[coinIndex].Symbol, - Decimals: coin.Coins[coinIndex].Decimals, - } - } -} - -func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duration { - interval := time.Duration(value) * time.Millisecond - pMin := numbers.Max(minInterval.Nanoseconds(), interval.Nanoseconds()) - pMax := numbers.Min(int(maxInterval.Nanoseconds()), int(pMin)) - return time.Duration(pMax) -} diff --git a/observer/observer_test.go b/observer/observer_test.go deleted file mode 100644 index 4c5b9fd2d..000000000 --- a/observer/observer_test.go +++ /dev/null @@ -1,357 +0,0 @@ -package observer - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" - "time" -) - -var transferDst1 = blockatlas.Tx{ - ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", - Coin: coin.BNB, - From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - To: "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5", - Fee: "125000", - Date: 1555049867, - Block: 7761368, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: blockatlas.Transfer{ - Value: "10000000000000", - Decimals: 8, - Symbol: "BNB", - }, -} - -var transferDst2 = blockatlas.Tx{ - ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44556", - Coin: coin.BNB, - From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - To: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - Fee: "125000", - Date: 1555049867, - Block: 7761368, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: blockatlas.Transfer{ - Value: "10000000000000", - Decimals: 8, - Symbol: "BNB", - }, -} - -var nativeTransferDst1 = blockatlas.Tx{ - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: blockatlas.NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, -} - -var nativeTransferDst2 = blockatlas.Tx{ - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4D0", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: blockatlas.NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, -} - -var txsBlock = blockatlas.Block{ - Number: 12345, - ID: "12345", - Txs: []blockatlas.Tx{ - transferDst1, - transferDst2, - nativeTransferDst1, - nativeTransferDst2, - }, -} - -func TestGetTxs(t *testing.T) { - txs := GetTxs(&txsBlock) - assert.Equal(t, len(txs), 4) - assert.Equal(t, txs["tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2"].Size(), 2) - assert.Equal(t, txs["tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5"].Size(), 1) - assert.Equal(t, txs["tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"].Size(), 2) - assert.Equal(t, txs["tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex"].Size(), 2) -} - -func Test_getDirection(t *testing.T) { - type args struct { - tx blockatlas.Tx - address string - } - tests := []struct { - name string - args args - want blockatlas.Direction - }{ - {"Test Direction Self", - args{ - blockatlas.Tx{ - From: "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1", To: "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, - "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, blockatlas.DirectionSelf, - }, - {"Test Direction Outgoing", - args{ - blockatlas.Tx{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7"}, - "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB"}, blockatlas.DirectionOutgoing, - }, - {"Test Direction Incoming", - args{ - blockatlas.Tx{ - From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", To: "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, - "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, blockatlas.DirectionIncoming, - }, - {"Test UTXO Direction Self", - args{ - blockatlas.Tx{ - Outputs: []blockatlas.TxOutput{ - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "72934112534"}, - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "500000000"}, - }, - Inputs: []blockatlas.TxOutput{ - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "73196112534"}, - }, - }, "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", - }, blockatlas.DirectionSelf, - }, - {"Test UTXO Direction Outgoing", - args{ - blockatlas.Tx{ - Outputs: []blockatlas.TxOutput{ - {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, - {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, - }, - Inputs: []blockatlas.TxOutput{ - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, - }, - }, "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", - }, blockatlas.DirectionOutgoing, - }, - {"Test UTXO Direction Incoming", - args{ - blockatlas.Tx{ - Outputs: []blockatlas.TxOutput{ - {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, - {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, - }, - Inputs: []blockatlas.TxOutput{ - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, - }, - }, "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", - }, blockatlas.DirectionIncoming, - }, - {"Test NativeTokenTransfer Direction Self", - args{ - blockatlas.Tx{ - Meta: blockatlas.NativeTokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, blockatlas.DirectionSelf, - }, - {"Test NativeTokenTransfer Direction Outgoing", - args{ - blockatlas.Tx{ - Meta: blockatlas.NativeTokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, blockatlas.DirectionOutgoing, - }, - {"Test NativeTokenTransfer Direction Incoming", - args{ - blockatlas.Tx{ - Meta: blockatlas.NativeTokenTransfer{ - From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, blockatlas.DirectionIncoming, - }, - {"Test TokenTransfer Direction Self", - args{ - blockatlas.Tx{ - Meta: blockatlas.TokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, blockatlas.DirectionSelf, - }, - {"Test TokenTransfer Direction Outgoing", - args{ - blockatlas.Tx{ - Meta: blockatlas.TokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, blockatlas.DirectionOutgoing, - }, - {"Test TokenTransfer Direction Incoming", - args{ - blockatlas.Tx{ - Meta: blockatlas.TokenTransfer{ - From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, blockatlas.DirectionIncoming, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := getDirection(tt.args.tx, tt.args.address); got != tt.want { - t.Errorf("getDirection() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_inferUtxoValue(t *testing.T) { - type args struct { - tx blockatlas.Tx - address string - coinIndex uint - } - tests := []struct { - name string - args args - wantAmount blockatlas.Amount - }{ - {"Test UTXO Direction Self", - args{ - blockatlas.Tx{ - Outputs: []blockatlas.TxOutput{ - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "72934112534"}, - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "500000000"}, - }, - Inputs: []blockatlas.TxOutput{ - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "73196112534"}, - }, - }, "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", 3, - }, blockatlas.Amount("72934112534"), - }, - {"Test UTXO Direction Outgoing", - args{ - blockatlas.Tx{ - Outputs: []blockatlas.TxOutput{ - {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, - {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, - }, - Inputs: []blockatlas.TxOutput{ - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, - }, - }, "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", 0, - }, blockatlas.Amount("4471835"), - }, - {"Test UTXO Direction Incoming", - args{ - blockatlas.Tx{ - Outputs: []blockatlas.TxOutput{ - {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, - {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, - }, - Inputs: []blockatlas.TxOutput{ - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, - }, - }, "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", 0, - }, blockatlas.Amount("4471835"), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - expect := blockatlas.Transfer{ - Value: tt.wantAmount, - Symbol: coin.Coins[tt.args.coinIndex].Symbol, - Decimals: coin.Coins[tt.args.coinIndex].Decimals, - } - tt.args.tx.Direction = getDirection(tt.args.tx, tt.args.address) - if inferUtxoValue(&tt.args.tx, tt.args.address, tt.args.coinIndex); tt.args.tx.Meta != expect { - t.Errorf("inferUtxoValue() = %v, want %v", tt.args.tx.Meta, expect) - } - }) - } -} - -func TestGetInterval(t *testing.T) { - min, _ := time.ParseDuration("2s") - max, _ := time.ParseDuration("30s") - type args struct { - blockTime int - minInterval time.Duration - maxInterval time.Duration - } - tests := []struct { - name string - args args - want time.Duration - }{ - { - "test minimum", - args{ - blockTime: 100, - minInterval: min, - maxInterval: max, - }, - min, - }, { - "test maximum", - args{ - blockTime: 600000, - minInterval: min, - maxInterval: max, - }, - max, - }, { - "test right blocktime", - args{ - blockTime: 5000, - minInterval: min, - maxInterval: max, - }, - 5000 * time.Millisecond, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := GetInterval(tt.args.blockTime, tt.args.minInterval, tt.args.maxInterval) - assert.EqualValues(t, tt.want, got) - }) - } -} diff --git a/observer/retry.go b/observer/retry.go deleted file mode 100644 index 7d3b685a8..000000000 --- a/observer/retry.go +++ /dev/null @@ -1,40 +0,0 @@ -package observer - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" - "math/rand" - "time" -) - -type GetBlockByNumber func(num int64) (*blockatlas.Block, error) - -type stop struct { - error -} - -func retry(attempts int, sleep time.Duration, f GetBlockByNumber, n int64) (*blockatlas.Block, error) { - r, err := f(n) - if err != nil { - if s, ok := err.(stop); ok { - return nil, s.error - } - if attempts--; attempts > 0 { - // Add some randomness to prevent creating a Thundering Herd - jitter := time.Duration(rand.Int63n(int64(sleep))) - sleep = sleep + jitter/2 - - logger.Info("GetBlockByNumber retry", - logger.Params{ - "number": n, - "attempts": attempts, - "sleep": sleep.String(), - }, - ) - - time.Sleep(sleep) - return retry(attempts, sleep*2, f, n) - } - } - return r, err -} diff --git a/observer/retry_test.go b/observer/retry_test.go deleted file mode 100644 index 7b4333230..000000000 --- a/observer/retry_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package observer - -import ( - "errors" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" - "time" -) - -func getBlock(num int64) (*blockatlas.Block, error) { - if num == 0 { - return nil, errors.New("teste") - } - return &blockatlas.Block{}, nil -} - -func TestRetry(t *testing.T) { - block, err := retry(3, time.Second*1, getBlock, 1) - if err != nil { - t.Error(err) - } - - if block == nil { - t.Error("block is nil") - } -} - -func TestRetryError(t *testing.T) { - now := time.Now() - block, err := retry(3, time.Second*1, getBlock, 0) - elapsed := time.Since(now) - if err == nil { - t.Error("retry method need fail") - } - - if block != nil { - t.Error("block object need be nil") - } - - if elapsed > time.Second*6 { - t.Error("Thundering Herd prevent doesn't work") - } -} diff --git a/observer/stream.go b/observer/stream.go deleted file mode 100644 index b86c95af5..000000000 --- a/observer/stream.go +++ /dev/null @@ -1,107 +0,0 @@ -package observer - -import ( - "context" - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/pkg/semaphore" - "github.com/trustwallet/blockatlas/storage" - "sync" - "sync/atomic" - "time" -) - -type Stream struct { - BlockAPI blockatlas.BlockAPI - Tracker storage.Tracker - PollInterval time.Duration - BacklogCount int - coin uint - logParams logger.Params - - // Concurrency - blockNumber int64 - semaphore *semaphore.Semaphore - wg sync.WaitGroup -} - -func (s *Stream) Execute(ctx context.Context) <-chan *blockatlas.Block { - cn := s.BlockAPI.Coin() - s.coin = cn.ID - s.logParams = logger.Params{"platform": cn.Handle} - conns := viper.GetInt("observer.stream_conns") - if conns == 0 { - logger.Fatal("observer.stream_conns is 0") - } - s.semaphore = semaphore.NewSemaphore(conns) - c := make(chan *blockatlas.Block) - go s.run(ctx, c) - return c -} - -func (s *Stream) run(ctx context.Context, c chan<- *blockatlas.Block) { - ticker := time.NewTicker(s.PollInterval) - for { - select { - case <-ctx.Done(): - ticker.Stop() - close(c) - return - case <-ticker.C: - s.load(c) - } - } -} - -func (s *Stream) load(c chan<- *blockatlas.Block) { - lastHeight, err := s.Tracker.GetBlockNumber(s.coin) - if err != nil { - logger.Error(err, "Polling failed: tracker didn't return last known block number", s.logParams) - return - } - - height, err := s.BlockAPI.CurrentBlockNumber() - height -= s.BlockAPI.Coin().MinConfirmations - if err != nil { - logger.Error(err, "Polling failed: source didn't return chain head number", s.logParams) - return - } - - if height-lastHeight > int64(s.BacklogCount) { - lastHeight = height - int64(s.BacklogCount) - } - backLogMax := viper.GetInt64("observer.backlog_max_blocks") - if height-lastHeight > backLogMax { - lastHeight = height - backLogMax - } - - atomic.StoreInt64(&s.blockNumber, lastHeight) - for i := lastHeight + 1; i <= height; i++ { - s.wg.Add(1) - go s.loadBlock(c, i) - } - s.wg.Wait() -} - -func (s *Stream) loadBlock(c chan<- *blockatlas.Block, num int64) { - defer s.wg.Done() - s.semaphore.Acquire() - defer s.semaphore.Release() - - block, err := retry(5, time.Second*5, s.BlockAPI.GetBlockByNumber, num) - if err != nil { - logger.Error(err, "Polling failed: could not get block", s.logParams, logger.Params{"block": num}) - return - } - c <- block - logger.Info(err, "Got new block", s.logParams, logger.Params{"block": num, "txs": len(block.Txs)}) - - // Not strictly correct nor avoids race conditions - // But good enough - newNum := atomic.AddInt64(&s.blockNumber, 1) - err = s.Tracker.SetBlockNumber(s.coin, newNum) - if err != nil { - logger.Error(err, "SetBlockNumber failed", s.logParams, logger.Params{"block": num, "coin": s.coin}) - } -} diff --git a/pkg/blockatlas/api.go b/pkg/blockatlas/api.go deleted file mode 100644 index 1d4bfb1b4..000000000 --- a/pkg/blockatlas/api.go +++ /dev/null @@ -1,77 +0,0 @@ -package blockatlas - -import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/coin" -) - -type ( - // Platform can be used to access a crypto service - Platform interface { - Coin() coin.Coin - } - - // TxAPI provides transaction lookups - TxAPI interface { - Platform - GetTxsByAddress(address string) (TxPage, error) - } - - // TokenTxAPI provides token transaction lookups - TokenTxAPI interface { - Platform - GetTokenTxsByAddress(address, token string) (TxPage, error) - } - - // TokenAPI provides token lookups - TokenAPI interface { - Platform - GetTokenListByAddress(address string) (TokenPage, error) - } - - // BlockAPI provides block information and lookups - BlockAPI interface { - Platform - CurrentBlockNumber() (int64, error) - GetBlockByNumber(num int64) (*Block, error) - } - - // AddressAPI provides address information - AddressAPI interface { - Platform - GetAddressesFromXpub(xpub string) ([]string, error) - } - - // StakingAPI provides staking information - StakeAPI interface { - Platform - UndelegatedBalance(address string) (string, error) - GetDetails() StakingDetails - GetValidators() (ValidatorPage, error) - GetDelegations(address string) (DelegationsPage, error) - } - - CollectionAPI interface { - Platform - GetCollections(owner string) (CollectionPage, error) - GetCollectibles(owner, collectibleID string) (CollectiblePage, error) - - OldGetCollections(owner string) (CollectionPage, error) - OldGetCollectibles(owner, collectibleID string) (CollectiblePage, error) - - GetCollectionsV4(owner string) (CollectionPage, error) - GetCollectiblesV4(owner, collectibleID string) (CollectiblePage, error) - } - - // CustomAPI provides custom HTTP routes - CustomAPI interface { - Platform - RegisterRoutes(router gin.IRouter) - } - - // NamingServiceAPI provides public name service domains HTTP routes - NamingServiceAPI interface { - Platform - Lookup(coins []uint64, name string) ([]Resolved, error) - } -) diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go index 1c3ba0ffb..168c94e7a 100644 --- a/pkg/blockatlas/observer.go +++ b/pkg/blockatlas/observer.go @@ -29,12 +29,6 @@ type ( Status bool `json:"status"` Message string `json:"message"` } - - Block struct { - Number int64 `json:"number"` - ID string `json:"id,omitempty"` - Txs []Tx `json:"txs"` - } ) func (e *SubscriptionEvent) ParseSubscriptions(s Subscriptions) []Subscription { diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 0dad23195..28bbbb664 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -1,5 +1,81 @@ package blockatlas +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/coin" +) + +type ( + // Platform can be used to access a crypto service + Platform interface { + Coin() coin.Coin + } + + // TxAPI provides transaction lookups + TxAPI interface { + Platform + GetTxsByAddress(address string) (TxPage, error) + } + + // TokenTxAPI provides token transaction lookups + TokenTxAPI interface { + Platform + GetTokenTxsByAddress(address, token string) (TxPage, error) + } + + // TokenAPI provides token lookups + TokenAPI interface { + Platform + GetTokenListByAddress(address string) (TokenPage, error) + } + + // BlockAPI provides block information and lookups + BlockAPI interface { + Platform + CurrentBlockNumber() (int64, error) + GetBlockByNumber(num int64) (*Block, error) + } + + // AddressAPI provides address information + AddressAPI interface { + Platform + GetAddressesFromXpub(xpub string) ([]string, error) + } + + // StakingAPI provides staking information + StakeAPI interface { + Platform + UndelegatedBalance(address string) (string, error) + GetDetails() StakingDetails + GetValidators() (ValidatorPage, error) + GetDelegations(address string) (DelegationsPage, error) + } + + CollectionAPI interface { + Platform + GetCollections(owner string) (CollectionPage, error) + GetCollectibles(owner, collectibleID string) (CollectiblePage, error) + + OldGetCollections(owner string) (CollectionPage, error) + OldGetCollectibles(owner, collectibleID string) (CollectiblePage, error) + + GetCollectionsV4(owner string) (CollectionPage, error) + GetCollectiblesV4(owner, collectibleID string) (CollectiblePage, error) + } + + // CustomAPI provides custom HTTP routes + CustomAPI interface { + Platform + RegisterRoutes(router gin.IRouter) + } + + // NamingServiceAPI provides public name service domains HTTP routes + NamingServiceAPI interface { + Platform + Lookup(coins []uint64, name string) ([]Resolved, error) + } +) + type Platforms map[string]Platform func (ps Platforms) GetPlatformList() []Platform { diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 0d46eff1c..8a1e1ddd1 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -1,5 +1,11 @@ package blockatlas +import ( + mapset "github.com/deckarep/golang-set" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/numbers" +) + const ( StatusCompleted Status = "completed" StatusPending Status = "pending" @@ -57,6 +63,12 @@ type ( KeyType string KeyTitle string + Block struct { + Number int64 `json:"number"` + ID string `json:"id,omitempty"` + Txs []Tx `json:"txs"` + } + // TxPage is a page of transactions TxPage []Tx @@ -193,8 +205,25 @@ type ( Coin uint `json:"coin"` Type TokenType `json:"type"` } + + Txs []Tx ) +func (t Txs) GetTransactionsMap() TxSetMap { + txSetMap := TxSetMap{Map: make(map[string]*TxSet)} + for i := 0; i < len(t); i++ { + addresses := t[i].GetAddresses() + addresses = append(addresses, t[i].GetUtxoAddresses()...) + for _, address := range addresses { + if txSetMap.Map[address] == nil { + txSetMap.Map[address] = new(TxSet) + } + txSetMap.Map[address].Add(&t[i]) + } + } + return txSetMap +} + func (t *Tx) GetUtxoAddresses() (addresses []string) { for _, input := range t.Inputs { addresses = append(addresses, input.Address) @@ -234,3 +263,80 @@ func (t *Tx) GetAddresses() []string { return addresses } } + +func (t *Tx) GetTransactionDirection(address string) Direction { + if len(t.Inputs) > 0 && len(t.Outputs) > 0 { + addressSet := mapset.NewSet(address) + return InferDirection(t, addressSet) + } + switch meta := t.Meta.(type) { + case TokenTransfer: + return determineTransactionDirection(address, meta.From, meta.To) + case NativeTokenTransfer: + return determineTransactionDirection(address, meta.From, meta.To) + default: + return determineTransactionDirection(address, t.From, t.To) + } +} + +func determineTransactionDirection(address, from, to string) Direction { + if address == to { + if from == to { + return DirectionSelf + } + return DirectionIncoming + } + return DirectionOutgoing +} + +func (t *Tx) InferUtxoValue(address string, coinIndex uint) { + if len(t.Inputs) > 0 && len(t.Outputs) > 0 { + addressSet := mapset.NewSet(address) + value := InferValue(t, t.Direction, addressSet) + t.Meta = Transfer{ + Value: value, + Symbol: coin.Coins[coinIndex].Symbol, + Decimals: coin.Coins[coinIndex].Decimals, + } + } +} + +func InferDirection(tx *Tx, addressSet mapset.Set) Direction { + inputSet := mapset.NewSet() + for _, address := range tx.Inputs { + inputSet.Add(address.Address) + } + outputSet := mapset.NewSet() + for _, address := range tx.Outputs { + outputSet.Add(address.Address) + } + intersect := addressSet.Intersect(inputSet) + if intersect.Cardinality() == 0 { + return DirectionIncoming + } + if outputSet.IsProperSubset(addressSet) || outputSet.Equal(inputSet) { + return DirectionSelf + } + return DirectionOutgoing +} + +func InferValue(tx *Tx, direction Direction, addressSet mapset.Set) Amount { + value := Amount("0") + if len(tx.Outputs) == 0 { + return value + } + if direction == DirectionOutgoing || direction == DirectionSelf { + value = tx.Outputs[0].Value + } else if direction == DirectionIncoming { + amount := value + for _, output := range tx.Outputs { + if !addressSet.Contains(output.Address) { + continue + } + value := numbers.AddAmount(string(amount), string(output.Value)) + amount = Amount(value) + } + value = amount + } + return value +} diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 8c72c8156..f6b77e7a7 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -1,6 +1,7 @@ package blockatlas import ( + mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "testing" @@ -127,3 +128,367 @@ func TestTx_GetUtxoAddresses(t *testing.T) { assert.Equal(t, utxoTransferDst1.GetUtxoAddresses(), []string{"bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh", "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737", "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6"}) assert.Equal(t, utxoTransferDst2.GetUtxoAddresses(), []string{"bc1q6e8sdxlgc7ekqkqyevtrx8wshfv7sg66z3z6ce", "bc1q7nn4txus4g6fc5v7d2tha35ely8mfpd8qvv6eg", "bc1q2fpry7zwqh575huc9urwfdvjtuvz508wez56ff", "bc1qk3yj6h79qw7tnsg4durc9sd5fpd3qt0p0m8u5p", "bc1qm8836plkzft2rhh23z6j8s9s8fxrzd4zag95z8"}) } + +func Test_getDirection(t *testing.T) { + type args struct { + tx Tx + address string + } + tests := []struct { + name string + args args + want Direction + }{ + {"Test Direction Self", + args{ + Tx{ + From: "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1", To: "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, + "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, DirectionSelf, + }, + {"Test Direction Outgoing", + args{ + Tx{ + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7"}, + "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB"}, DirectionOutgoing, + }, + {"Test Direction Incoming", + args{ + Tx{ + From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", To: "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, + "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, DirectionIncoming, + }, + {"Test UTXO Direction Self", + args{ + Tx{ + Outputs: []TxOutput{ + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "72934112534"}, + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "500000000"}, + }, + Inputs: []TxOutput{ + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "73196112534"}, + }, + }, "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", + }, DirectionSelf, + }, + {"Test UTXO Direction Outgoing", + args{ + Tx{ + Outputs: []TxOutput{ + {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, + {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, + }, + Inputs: []TxOutput{ + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, + }, + }, "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", + }, DirectionOutgoing, + }, + {"Test UTXO Direction Incoming", + args{ + Tx{ + Outputs: []TxOutput{ + {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, + {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, + }, + Inputs: []TxOutput{ + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, + }, + }, "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", + }, DirectionIncoming, + }, + {"Test NativeTokenTransfer Direction Self", + args{ + Tx{ + Meta: NativeTokenTransfer{ + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, DirectionSelf, + }, + {"Test NativeTokenTransfer Direction Outgoing", + args{ + Tx{ + Meta: NativeTokenTransfer{ + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, DirectionOutgoing, + }, + {"Test NativeTokenTransfer Direction Incoming", + args{ + Tx{ + Meta: NativeTokenTransfer{ + From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, DirectionIncoming, + }, + {"Test TokenTransfer Direction Self", + args{ + Tx{ + Meta: TokenTransfer{ + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, DirectionSelf, + }, + {"Test TokenTransfer Direction Outgoing", + args{ + Tx{ + Meta: TokenTransfer{ + From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, DirectionOutgoing, + }, + {"Test TokenTransfer Direction Incoming", + args{ + Tx{ + Meta: TokenTransfer{ + From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", + To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, + }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + }, DirectionIncoming, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.args.tx.GetTransactionDirection(tt.args.address); got != tt.want { + t.Errorf("getTransactionDirection() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_inferUtxoValue(t *testing.T) { + type args struct { + tx Tx + address string + coinIndex uint + } + tests := []struct { + name string + args args + wantAmount Amount + }{ + {"Test UTXO Direction Self", + args{ + Tx{ + Outputs: []TxOutput{ + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "72934112534"}, + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "500000000"}, + }, + Inputs: []TxOutput{ + {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "73196112534"}, + }, + }, "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", 3, + }, Amount("72934112534"), + }, + {"Test UTXO Direction Outgoing", + args{ + Tx{ + Outputs: []TxOutput{ + {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, + {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, + }, + Inputs: []TxOutput{ + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, + }, + }, "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", 0, + }, Amount("4471835"), + }, + {"Test UTXO Direction Incoming", + args{ + Tx{ + Outputs: []TxOutput{ + {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, + {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, + }, + Inputs: []TxOutput{ + {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, + }, + }, "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", 0, + }, Amount("4471835"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + expect := Transfer{ + Value: tt.wantAmount, + Symbol: coin.Coins[tt.args.coinIndex].Symbol, + Decimals: coin.Coins[tt.args.coinIndex].Decimals, + } + tt.args.tx.Direction = tt.args.tx.GetTransactionDirection(tt.args.address) + if tt.args.tx.InferUtxoValue(tt.args.address, tt.args.coinIndex); tt.args.tx.Meta != expect { + t.Errorf("inferUtxoValue() = %v, want %v", tt.args.tx.Meta, expect) + } + }) + } +} + +// zpub: zpub6r9CEhEkruYbEcu2yQCaRKQ1qufTa4zLrx6ezs31P627UpAepVNBE2td3d3mHnSaXyRbwksRwDJGzLBWQeZPFMut8N3BvXpcwRwEWGEwAnq +var ( + btcSet = mapset.NewSet("bc1qfrrncxmf7skye2glyef95xlpmrlmf2e8qlav2l", "bc1qxm90n0rxkadhdkvglev56k60qths73luzlnn7a", + "bc1q2sykr9c342mjpm9mwnps8ksk6e35lz75rpdlfe", "bc1qs86ucvr3unce2grvfp77433npy66nzha9w0e3c") + btcInputs1 = []TxOutput{{Address: "bc1q2sykr9c342mjpm9mwnps8ksk6e35lz75rpdlfe"}} + btcOutputs1 = []TxOutput{{Address: "bc1q6wf7tj62f0uwr6almah3666th2ejefdg72ek6t"}} + btcInputs2 = []TxOutput{{ + Address: "3CgvDkzcJ7yMZe75jNBem6Bj6nkMAWwMEf"}, + {Address: "3LyzYcB54pm9EAMmzXpFfb1kzEDAFvqBgT"}, + {Address: "3Q6DYour5q5WdMhyXsyPgBeAqPCXchzCsF"}, + {Address: "3JZZM1rwst7G5izxbFL7KNvy7ZiZ47SVqG"}} + btcOutputs2 = []TxOutput{ + {Address: "139f1CrnLWvVajGzs3ZtpQhbGWxM599sho"}, + {Address: "3LyzYcB54pm9EAMmzXpFfb1kzEDAFvqBgT"}, + {Address: "bc1q9mx5tm66zs7epa4skvyuf2vfuwmtnlttj74cnl"}, + {Address: "3JZZM1rwst7G5izxbFL7KNvy7ZiZ47SVqG"}} + + dogeSet = mapset.NewSet("DB49sNjVdxyREXEBEzUV54TrQYYpvi3Be7") + dogeInputs = []TxOutput{{Address: "DAukM5pPtGdbPxMX1u2LYHoyhbDhEFHbnH"}} + dogeOutputs = []TxOutput{{Address: "DB49sNjVdxyREXEBEzUV54TrQYYpvi3Be7"}, {Address: "DAukM5pPtGdbPxMX1u2LYHoyhbDhEFHbnH"}} +) + +func TestInferDirection(t *testing.T) { + var tests = []struct { + AddressSet mapset.Set + Inputs []TxOutput + Outputs []TxOutput + Expected Direction + Coin uint + }{ + { + btcSet, + btcInputs1, + btcOutputs1, + DirectionOutgoing, + coin.BTC, + }, + { + btcSet, + btcInputs2, + btcOutputs2, + DirectionIncoming, + coin.BTC, + }, + { + dogeSet, + dogeInputs, + dogeOutputs, + DirectionIncoming, + coin.DOGE, + }, + } + + for _, test := range tests { + tx := Tx{ + Inputs: test.Inputs, + Outputs: test.Outputs, + } + + direction := InferDirection(&tx, test.AddressSet) + if direction != test.Expected { + t.Errorf("direction is not %s", test.Expected) + } + } +} + +var ( + transferDstOne = Tx{ + ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", + Coin: coin.BNB, + From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", + To: "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5", + Fee: "125000", + Date: 1555049867, + Block: 7761368, + Status: StatusCompleted, + Memo: "test", + Meta: Transfer{ + Value: "10000000000000", + Decimals: 8, + Symbol: "BNB", + }, + } + + transferDst2 = Tx{ + ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44556", + Coin: coin.BNB, + From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", + To: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", + Fee: "125000", + Date: 1555049867, + Block: 7761368, + Status: StatusCompleted, + Memo: "test", + Meta: Transfer{ + Value: "10000000000000", + Decimals: 8, + Symbol: "BNB", + }, + } + + nativeTransferDstOne = Tx{ + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: StatusCompleted, + Memo: "test", + Meta: NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + }, + } + + nativeTransferDst2 = Tx{ + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4D0", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: StatusCompleted, + Memo: "test", + Meta: NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + }, + } +) + +func TestGetTxsTx(t *testing.T) { + tx := Txs{ + transferDstOne, + transferDst2, + nativeTransferDstOne, + nativeTransferDst2, + } + txs := tx.GetTransactionsMap() + assert.Equal(t, len(txs.Map), 4) + assert.Equal(t, txs.Map["tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2"].Size(), 2) + assert.Equal(t, txs.Map["tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5"].Size(), 1) + assert.Equal(t, txs.Map["tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"].Size(), 2) + assert.Equal(t, txs.Map["tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex"].Size(), 2) +} diff --git a/pkg/blockatlas/txset.go b/pkg/blockatlas/txset.go index a3a27ac81..1819a149f 100644 --- a/pkg/blockatlas/txset.go +++ b/pkg/blockatlas/txset.go @@ -2,12 +2,18 @@ package blockatlas import "sync" -type TxSet struct { - items map[*Tx]bool - lock sync.RWMutex -} +type ( + TxSetMap struct { + Map map[string]*TxSet + } + + TxSet struct { + items map[*Tx]bool + lock sync.RWMutex + } +) -// Add adds a new element to the Set. Returns a pointer to the Set. +// Add adds a new element to the Map. Returns a pointer to the Map. func (s *TxSet) Add(t *Tx) *TxSet { s.lock.Lock() defer s.lock.Unlock() @@ -36,3 +42,14 @@ func (s *TxSet) Size() int { defer s.lock.RUnlock() return len(s.items) } + +func (s TxSetMap) GetUniqueAddresses() []string { + var addresses []string + for address := range s.Map { + if len(address) == 0 { + continue + } + addresses = append(addresses, address) + } + return addresses +} diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index d2746cb12..c0d2f1ad7 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -27,11 +27,7 @@ func (e *Error) isEmpty() bool { } func (e *Error) Error() string { - r, err := e.MarshalJSON() - if err != nil { - return e.Err.Error() - } - return string(r) + return e.String() } func (e *Error) String() string { @@ -39,9 +35,6 @@ func (e *Error) String() string { if e.Type != TypeNone { msg = fmt.Sprintf("%s | Type: %s", msg, e.Type.String()) } - if len(e.Meta()) > 0 { - msg = fmt.Sprintf("%s | Meta: %s", msg, e.Meta()) - } if len(e.stack) > 0 { msg = fmt.Sprintf("%s | Stack: %s", msg, e.stack) } diff --git a/pkg/semaphore/semaphore.go b/pkg/semaphore/semaphore.go deleted file mode 100644 index e46e33262..000000000 --- a/pkg/semaphore/semaphore.go +++ /dev/null @@ -1,17 +0,0 @@ -package semaphore - -type Semaphore struct { - c chan bool -} - -func NewSemaphore(n int) *Semaphore { - return &Semaphore{make(chan bool, n)} -} - -func (s *Semaphore) Acquire() { - s.c <- true -} - -func (s *Semaphore) Release() { - <-s.c -} diff --git a/platform/bitcoin/transaction.go b/platform/bitcoin/transaction.go index 2388dc137..fd4d250ee 100644 --- a/platform/bitcoin/transaction.go +++ b/platform/bitcoin/transaction.go @@ -92,8 +92,8 @@ func normalizeTxs(sourceTxs TransactionsList, coinIndex uint, addressSet mapset. func normalizeTransfer(transaction Transaction, coinIndex uint, addressSet mapset.Set) (tx blockatlas.Tx, ok bool) { tx = normalizeTransaction(transaction, coinIndex) - direction := InferDirection(&tx, addressSet) - value := InferValue(&tx, direction, addressSet) + direction := blockatlas.InferDirection(&tx, addressSet) + value := blockatlas.InferValue(&tx, direction, addressSet) tx.Direction = direction tx.Meta = blockatlas.Transfer{ @@ -105,46 +105,6 @@ func normalizeTransfer(transaction Transaction, coinIndex uint, addressSet mapse return tx, true } -func InferDirection(tx *blockatlas.Tx, addressSet mapset.Set) blockatlas.Direction { - inputSet := mapset.NewSet() - for _, address := range tx.Inputs { - inputSet.Add(address.Address) - } - outputSet := mapset.NewSet() - for _, address := range tx.Outputs { - outputSet.Add(address.Address) - } - intersect := addressSet.Intersect(inputSet) - if intersect.Cardinality() == 0 { - return blockatlas.DirectionIncoming - } - if outputSet.IsProperSubset(addressSet) || outputSet.Equal(inputSet) { - return blockatlas.DirectionSelf - } - return blockatlas.DirectionOutgoing -} - -func InferValue(tx *blockatlas.Tx, direction blockatlas.Direction, addressSet mapset.Set) blockatlas.Amount { - value := blockatlas.Amount("0") - if len(tx.Outputs) == 0 { - return value - } - if direction == blockatlas.DirectionOutgoing || direction == blockatlas.DirectionSelf { - value = tx.Outputs[0].Value - } else if direction == blockatlas.DirectionIncoming { - amount := value - for _, output := range tx.Outputs { - if !addressSet.Contains(output.Address) { - continue - } - value := numbers.AddAmount(string(amount), string(output.Value)) - amount = blockatlas.Amount(value) - } - value = amount - } - return value -} - func normalizeTransaction(tx Transaction, coinIndex uint) blockatlas.Tx { inputs := parseOutputs(tx.Vin) outputs := parseOutputs(tx.Vout) diff --git a/platform/bitcoin/transaction_test.go b/platform/bitcoin/transaction_test.go index e7a18dd0c..fd93c95c7 100644 --- a/platform/bitcoin/transaction_test.go +++ b/platform/bitcoin/transaction_test.go @@ -269,70 +269,6 @@ func TestNormalizeTransfer(t *testing.T) { } } -// zpub: zpub6r9CEhEkruYbEcu2yQCaRKQ1qufTa4zLrx6ezs31P627UpAepVNBE2td3d3mHnSaXyRbwksRwDJGzLBWQeZPFMut8N3BvXpcwRwEWGEwAnq -var btcSet = mapset.NewSet("bc1qfrrncxmf7skye2glyef95xlpmrlmf2e8qlav2l", "bc1qxm90n0rxkadhdkvglev56k60qths73luzlnn7a", - "bc1q2sykr9c342mjpm9mwnps8ksk6e35lz75rpdlfe", "bc1qs86ucvr3unce2grvfp77433npy66nzha9w0e3c") -var btcInputs1 = []blockatlas.TxOutput{{Address: "bc1q2sykr9c342mjpm9mwnps8ksk6e35lz75rpdlfe"}} -var btcOutputs1 = []blockatlas.TxOutput{{Address: "bc1q6wf7tj62f0uwr6almah3666th2ejefdg72ek6t"}} -var btcInputs2 = []blockatlas.TxOutput{{ - Address: "3CgvDkzcJ7yMZe75jNBem6Bj6nkMAWwMEf"}, - {Address: "3LyzYcB54pm9EAMmzXpFfb1kzEDAFvqBgT"}, - {Address: "3Q6DYour5q5WdMhyXsyPgBeAqPCXchzCsF"}, - {Address: "3JZZM1rwst7G5izxbFL7KNvy7ZiZ47SVqG"}} -var btcOutputs2 = []blockatlas.TxOutput{ - {Address: "139f1CrnLWvVajGzs3ZtpQhbGWxM599sho"}, - {Address: "3LyzYcB54pm9EAMmzXpFfb1kzEDAFvqBgT"}, - {Address: "bc1q9mx5tm66zs7epa4skvyuf2vfuwmtnlttj74cnl"}, - {Address: "3JZZM1rwst7G5izxbFL7KNvy7ZiZ47SVqG"}} - -var dogeSet = mapset.NewSet("DB49sNjVdxyREXEBEzUV54TrQYYpvi3Be7") -var dogeInputs = []blockatlas.TxOutput{{Address: "DAukM5pPtGdbPxMX1u2LYHoyhbDhEFHbnH"}} -var dogeOutputs = []blockatlas.TxOutput{{Address: "DB49sNjVdxyREXEBEzUV54TrQYYpvi3Be7"}, {Address: "DAukM5pPtGdbPxMX1u2LYHoyhbDhEFHbnH"}} - -func TestInferDirection(t *testing.T) { - var tests = []struct { - AddressSet mapset.Set - Inputs []blockatlas.TxOutput - Outputs []blockatlas.TxOutput - Expected blockatlas.Direction - Coin uint - }{ - { - btcSet, - btcInputs1, - btcOutputs1, - blockatlas.DirectionOutgoing, - coin.BTC, - }, - { - btcSet, - btcInputs2, - btcOutputs2, - blockatlas.DirectionIncoming, - coin.BTC, - }, - { - dogeSet, - dogeInputs, - dogeOutputs, - blockatlas.DirectionIncoming, - coin.DOGE, - }, - } - - for _, test := range tests { - tx := blockatlas.Tx{ - Inputs: test.Inputs, - Outputs: test.Outputs, - } - - direction := InferDirection(&tx, test.AddressSet) - if direction != test.Expected { - t.Errorf("direction is not %s", test.Expected) - } - } -} - func TestTransactionStatus(t *testing.T) { var tests = []struct { Tx Transaction diff --git a/scripts/run_tests_postman.sh b/scripts/run_tests_postman.sh old mode 100755 new mode 100644 diff --git a/services/observer/healthcheck/healthcheck.go b/services/observer/healthcheck/healthcheck.go new file mode 100644 index 000000000..1fbde8ae5 --- /dev/null +++ b/services/observer/healthcheck/healthcheck.go @@ -0,0 +1,112 @@ +package healthcheck + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/storage" + "sync" + "time" +) + +var observerStatus status + +func init() { + observerStatus = status{ + m: make(map[string]Info), + } +} + +type status struct { + m map[string]Info + sync.RWMutex +} + +func (cr *status) update(coin string, info Info) { + cr.Lock() + cr.m[coin] = info + cr.Unlock() +} + +func (cr *status) get() map[string]Info { + cr.RLock() + defer cr.RUnlock() + return cr.m +} + +func Worker(storage storage.Tracker, api blockatlas.BlockAPI) { + var ( + lastParsedBlock, currentBlock int64 + err error + ) + + lastParsedBlock, err = storage.GetLastParsedBlockNumber(api.Coin().ID) + if err != nil { + logger.Fatal(err) + } + + var duration time.Duration + t := api.Coin().BlockTime / 1000 + + if t > 30 { + duration = time.Duration(int64(time.Second) * int64(t)) + } else { + duration = time.Minute * 11 + } + logger.Info("Setting update duration", logger.Params{"duration": duration}) + + for { + currentBlock, err = storage.GetLastParsedBlockNumber(api.Coin().ID) + if err != nil { + logger.Error(err) + continue + } + + latestBlock, err := api.CurrentBlockNumber() + if err != nil { + logger.Error(err) + continue + } + + logger.Info("fetched", logger.Params{"currentBlock": currentBlock, "lastParsedBlock": lastParsedBlock, "latestBlock": latestBlock, "handle": api.Coin().Handle}) + + if currentBlock > lastParsedBlock || latestBlock == currentBlock { + lastParsedBlock = currentBlock + observerStatus.update(api.Coin().Handle, Info{ + LastParsedBlock: lastParsedBlock, + Healthy: true, + }) + } else { + observerStatus.update(api.Coin().Handle, Info{ + LastParsedBlock: lastParsedBlock, + Healthy: false, + }) + } + + time.Sleep(duration) + } +} + +func GetStatus(exclude []string) map[string]interface{} { + total := true + result := make(map[string]interface{}) + status := observerStatus.get() + for k, v := range status{ + if !contain(k, exclude){ + if v.Healthy == false{ + total = false + } + result[k] = v + } + } + result["total"] = total + return result +} + +func contain(elem string, list []string) bool{ + for _, v := range list{ + if v == elem{ + return true + } + } + return false +} diff --git a/services/observer/healthcheck/model.go b/services/observer/healthcheck/model.go new file mode 100644 index 000000000..6a4fa944c --- /dev/null +++ b/services/observer/healthcheck/model.go @@ -0,0 +1,6 @@ +package healthcheck + +type Info struct { + LastParsedBlock int64 `json:"lastParsedBlock"` + Healthy bool `json:"healthy"` +} diff --git a/services/observer/notifier/notifier.go b/services/observer/notifier/notifier.go new file mode 100644 index 000000000..0f75260b2 --- /dev/null +++ b/services/observer/notifier/notifier.go @@ -0,0 +1,101 @@ +package notifier + +import ( + "encoding/json" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/blockatlas/storage" + "sync" + "time" +) + +type DispatchEvent struct { + Action blockatlas.TransactionType `json:"action"` + Result *blockatlas.Tx `json:"result"` + GUID string `json:"guid"` +} + +func RunNotifier(delivery amqp.Delivery, s storage.Addresses) { + defer func() { + if err := delivery.Ack(false); err != nil { + logger.Error(err) + } + }() + var txs blockatlas.Txs + if err := json.Unmarshal(delivery.Body, &txs); err != nil { + logger.Error(err) + return + } + if len(txs) == 0 { + return + } + + logger.Info("Consumed", logger.Params{"txs": len(txs), "coin": txs[0].Coin}) + + blockTransactions := txs.GetTransactionsMap() + if len(blockTransactions.Map) == 0 { + return + } + + addresses := blockTransactions.GetUniqueAddresses() + subs, err := s.FindSubscriptions(txs[0].Coin, addresses) + if err != nil || len(subs) == 0 { + return + } + + var wg sync.WaitGroup + wg.Add(len(subs)) + for _, sub := range subs { + go buildAndPostMessage(blockTransactions, sub, &wg) + } + wg.Wait() +} + +func buildAndPostMessage(blockTransactions blockatlas.TxSetMap, sub blockatlas.Subscription, wg *sync.WaitGroup) { + defer wg.Done() + tx, ok := blockTransactions.Map[sub.Address] + if !ok { + return + } + for _, tx := range tx.Txs() { + tx.Direction = tx.GetTransactionDirection(sub.Address) + tx.InferUtxoValue(sub.Address, tx.Coin) + action := DispatchEvent{ + Action: tx.Type, + Result: &tx, + GUID: sub.GUID, + } + txJson, err := json.Marshal(action) + if err != nil { + logger.Panic(err) + } + + logParams := logger.Params{ + "guid": sub.GUID, + "coin": sub.Coin, + "txID": tx.ID, + } + + publishTransaction(sub.GUID, txJson, logParams) + } +} + +func publishTransaction(message string, rawMessage []byte, logParams logger.Params) { + err := mq.Transactions.Publish(rawMessage) + if err != nil { + err = errors.E(err, "Failed to dispatch event", errors.Params{"message": message}, logParams) + logger.Fatal(err, logger.Params{"message": message}, logParams) + } + logger.Info("Message dispatched", logger.Params{"message": message}, logParams) +} + +func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duration { + interval := time.Duration(value) * time.Millisecond + pMin := numbers.Max(minInterval.Nanoseconds(), interval.Nanoseconds()) + pMax := numbers.Min(int(maxInterval.Nanoseconds()), int(pMin)) + return time.Duration(pMax) +} diff --git a/services/observer/notifier/notifier_test.go b/services/observer/notifier/notifier_test.go new file mode 100644 index 000000000..882343ede --- /dev/null +++ b/services/observer/notifier/notifier_test.go @@ -0,0 +1,54 @@ +package notifier + +import ( + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +func TestGetInterval(t *testing.T) { + min, _ := time.ParseDuration("2s") + max, _ := time.ParseDuration("30s") + type args struct { + blockTime int + minInterval time.Duration + maxInterval time.Duration + } + tests := []struct { + name string + args args + want time.Duration + }{ + { + "test minimum", + args{ + blockTime: 100, + minInterval: min, + maxInterval: max, + }, + min, + }, { + "test maximum", + args{ + blockTime: 600000, + minInterval: min, + maxInterval: max, + }, + max, + }, { + "test right blocktime", + args{ + blockTime: 5000, + minInterval: min, + maxInterval: max, + }, + 5000 * time.Millisecond, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := GetInterval(tt.args.blockTime, tt.args.minInterval, tt.args.maxInterval) + assert.EqualValues(t, tt.want, got) + }) + } +} diff --git a/services/observer/parser/parser.go b/services/observer/parser/parser.go new file mode 100644 index 000000000..bcec76430 --- /dev/null +++ b/services/observer/parser/parser.go @@ -0,0 +1,297 @@ +package parser + +import ( + "context" + "encoding/json" + "fmt" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "sync/atomic" + + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/storage" + "math/rand" + "sort" + "sync" + "time" +) + +type ( + Params struct { + Ctx context.Context + Api blockatlas.BlockAPI + Storage storage.Tracker + Queue mq.Queue + ParsingBlocksInterval time.Duration + BacklogCount int + MaxBacklogBlocks int64 + StopChannel chan<- struct{} + TxBatchLimit uint + } + + GetBlockByNumber func(num int64) (*blockatlas.Block, error) + + stop struct { + error + } + + transactionsBatch struct { + sync.Mutex + blockatlas.Txs + } +) + +const MinTxsBatchLimit = 500 + +func RunParser(params Params) { + logger.Info("------------------------------------------------------------") + for { + select { + case <-params.Ctx.Done(): + logger.Info(fmt.Sprintf("Parser of %s stopped parsing blocks", params.Api.Coin().Handle)) + params.StopChannel <- struct{}{} + return + default: + lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params) + if err != nil { + logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + time.Sleep(params.ParsingBlocksInterval) + continue + } + + blocks := FetchBlocks(params.Api, lastParsedBlock, currentBlock) + + err = SaveLastParsedBlock(params, blocks) + if err != nil { + logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + time.Sleep(params.ParsingBlocksInterval) + continue + } + + txs := ConvertToBatch(blocks) + + PublishTransactionsBatch(params, txs) + + time.Sleep(params.ParsingBlocksInterval) + } + } +} + +func GetBlocksIntervalToFetch(params Params) (int64, int64, error) { + lastParsedBlock, err := params.Storage.GetLastParsedBlockNumber(params.Api.Coin().ID) + if err != nil { + return 0, 0, errors.E(err, "Polling failed: tracker didn't return last known block number") + } + currentBlock, err := params.Api.CurrentBlockNumber() + currentBlock -= params.Api.Coin().MinConfirmations + if err != nil { + return 0, 0, errors.E(err, "Polling failed: source didn't return chain head number") + } + + if currentBlock-lastParsedBlock > int64(params.BacklogCount) { + lastParsedBlock = currentBlock - int64(params.BacklogCount) + } + + if currentBlock-lastParsedBlock > params.MaxBacklogBlocks { + lastParsedBlock = currentBlock - params.MaxBacklogBlocks + } + + return lastParsedBlock, currentBlock, nil +} + +func FetchBlocks(api blockatlas.BlockAPI, lastParsedBlock, currentBlock int64) []blockatlas.Block { + if lastParsedBlock == currentBlock { + logger.Info("No new blocks", logger.Params{"last": lastParsedBlock, "coin": api.Coin().ID, "time": time.Now().Unix()}) + return nil + } + + blocksCount := currentBlock - lastParsedBlock + if blocksCount < 0 { + logger.Error("Current block is 0", logger.Params{"coin": api.Coin().Handle}) + return nil + } + + var ( + blocksChan = make(chan blockatlas.Block, blocksCount) + errorsChan = make(chan error, blocksCount) + totalCount int32 + wg sync.WaitGroup + ) + + for i := lastParsedBlock + 1; i <= currentBlock; i++ { + wg.Add(1) + go func(i int64, wg *sync.WaitGroup) { + defer wg.Done() + err := fetchBlock(api, i, blocksChan) + if err != nil { + errorsChan <- err + return + } + atomic.AddInt32(&totalCount, 1) + }(i, &wg) + } + + wg.Wait() + close(errorsChan) + close(blocksChan) + + if len(errorsChan) > 0 { + var ( + errorsList = make([]error, 0, len(errorsChan)) + ) + for err := range errorsChan { + errorsList = append(errorsList, err) + } + logger.Error("Fetch blocks errors", logger.Params{"count": len(errorsList), "blocks": errorsList}) + } + + blocksList := make([]blockatlas.Block, 0, len(blocksChan)) + for block := range blocksChan { + blocksList = append(blocksList, block) + } + + logger.Info("Fetched blocks batch", logger.Params{"from": lastParsedBlock, "to": currentBlock, "total": totalCount}) + return blocksList +} + +func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas.Block) error { + block, err := getBlockByNumberWithRetry(5, time.Second*5, api.GetBlockByNumber, num) + if err != nil { + return errors.E(fmt.Sprintf("%d", num)) + } + blocksChan <- *block + return nil +} + +func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { + if len(blocks) == 0 { + return nil + } + + sort.Slice(blocks, func(i, j int) bool { + return blocks[i].Number < blocks[j].Number + }) + + lastBlockNumber := blocks[len(blocks)-1].Number + + err := params.Storage.SetLastParsedBlockNumber(params.Api.Coin().ID, lastBlockNumber) + if err != nil { + return err + } + + logger.Info(err, "Save last parsed block", logger.Params{"block": lastBlockNumber, "coin": params.Api.Coin().Handle}) + return nil +} + +func ConvertToBatch(blocks []blockatlas.Block) blockatlas.Txs { + if len(blocks) == 0 { + return nil + } + + var ( + txsBatch transactionsBatch + wg sync.WaitGroup + ) + + for _, block := range blocks { + wg.Add(1) + go func(block blockatlas.Block, wg *sync.WaitGroup) { + defer wg.Done() + txsBatch.fillBatch(block.Txs) + }(block, &wg) + } + wg.Wait() + + if len(txsBatch.Txs) == 0 { + logger.Info("Blocks converted to transactions batch, there is no transactions", logger.Params{"blocks": len(blocks)}) + return nil + } + + logger.Info("Blocks converted to transactions batch", logger.Params{"blocks": len(blocks), "txs": len(txsBatch.Txs)}) + return txsBatch.Txs +} + +func PublishTransactionsBatch(params Params, txs blockatlas.Txs) { + if len(txs) == 0 { + logger.Info("------------------------------------------------------------") + return + } + + batches := getTxsBatches(txs, params.TxBatchLimit) + + var wg sync.WaitGroup + for _, batch := range batches { + wg.Add(1) + go publish(params, batch, &wg) + } + wg.Wait() + + logger.Info("Published transactions batch", logger.Params{"txs": len(txs), "batchCount": len(batches)}) + logger.Info("------------------------------------------------------------") +} + +func getTxsBatches(txs blockatlas.Txs, sizeUint uint) []blockatlas.Txs { + size := int(sizeUint) + resultLength := (len(txs) + size - 1) / size + result := make([]blockatlas.Txs, resultLength) + lo, hi := 0, size + for i := range result { + if hi > len(txs) { + hi = len(txs) + } + result[i] = txs[lo:hi:hi] + lo, hi = hi, hi+size + } + return result +} + +func publish(params Params, txs blockatlas.Txs, wg *sync.WaitGroup) { + defer wg.Done() + body, err := json.Marshal(txs) + if err != nil { + logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + return + } + err = params.Queue.Publish(body) + if err != nil { + logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + return + } +} + +func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64) (*blockatlas.Block, error) { + r, err := getBlockByNumber(n) + if err != nil { + if s, ok := err.(stop); ok { + return nil, s.error + } + if attempts--; attempts > 0 { + // Add some randomness to prevent creating a Thundering Herd + rand.Seed(time.Now().UnixNano()) + jitter := time.Duration(rand.Int63n(int64(sleep))) + sleep = sleep + jitter/2 + + logger.Info("retry GetBlockByNumber", + logger.Params{ + "number": n, + "attempts": attempts, + "sleep": sleep.String(), + }, + ) + + time.Sleep(sleep) + return getBlockByNumberWithRetry(attempts, sleep*2, getBlockByNumber, n) + } + } + return r, err +} + +func (t *transactionsBatch) fillBatch(transactions blockatlas.Txs) { + t.Lock() + defer t.Unlock() + if len(transactions) == 0 { + return + } + t.Txs = append(t.Txs, transactions...) +} diff --git a/services/observer/parser/parser_test.go b/services/observer/parser/parser_test.go new file mode 100644 index 000000000..38457c659 --- /dev/null +++ b/services/observer/parser/parser_test.go @@ -0,0 +1,240 @@ +package parser + +import ( + "errors" + "fmt" + "github.com/alicebob/miniredis" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/storage" + "sync" + "testing" + "time" +) + +var ( + wantedMockedNumber int64 + + block = blockatlas.Block{ + Number: 110, + ID: "", + Txs: []blockatlas.Tx{ + { + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + }, + }, + }, + } + + txs = blockatlas.Txs{ + { + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + }, + }, + } +) + +func Test_GetBlocksIntervalToFetch(t *testing.T) { + + params := Params{ + ParsingBlocksInterval: time.Minute, + BacklogCount: 10, + MaxBacklogBlocks: 100, + Storage: getMockedRedis(t), + Api: getMockedBlockAPI(), + } + latestParsedBlock := int64(100) + wantedMockedNumber = 110 + lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params) + assert.Nil(t, err) + assert.Equal(t, wantedMockedNumber, currentBlock) + assert.Equal(t, latestParsedBlock, lastParsedBlock) +} + +func TestFetchBlocks(t *testing.T) { + blocks := FetchBlocks(getMockedBlockAPI(), 0, 100) + assert.Equal(t, len(blocks), 100) +} + +func TestSaveLastParsedBlock(t *testing.T) { + blocks := make([]blockatlas.Block, 0) + blocks = append(blocks, block) + s := getMockedRedis(t) + + params := Params{ + ParsingBlocksInterval: time.Minute, + BacklogCount: 10, + MaxBacklogBlocks: 100, + Storage: s, + Api: getMockedBlockAPI(), + } + err := SaveLastParsedBlock(params, blocks) + assert.Nil(t, err) + + lastParsedBlock, err := s.GetLastParsedBlockNumber(getMockedBlockAPI().Coin().ID) + assert.Nil(t, err) + assert.Equal(t, lastParsedBlock, int64(110)) +} + +func TestParser_ConvertToBatch(t *testing.T) { + blocks := []blockatlas.Block{block, block, block, block} + txs := ConvertToBatch(blocks) + assert.Equal(t, 4, len(txs)) + + empty := []blockatlas.Block{} + txsEmpty := ConvertToBatch(empty) + assert.Equal(t, 0, len(txsEmpty)) +} + +func TestParser_add(t *testing.T) { + blocks := []blockatlas.Block{block, block, block, block} + txs := ConvertToBatch(blocks) + + batch := transactionsBatch{ + Mutex: sync.Mutex{}, + Txs: txs, + } + + batch.fillBatch(txs) + assert.Equal(t, 8, len(batch.Txs)) + + batch.fillBatch(nil) + assert.Equal(t, 8, len(batch.Txs)) +} + +func TestParser_getBlockByNumberWithRetry(t *testing.T) { + block, err := getBlockByNumberWithRetry(3, time.Millisecond*1, getBlock, 1) + if err != nil { + t.Error(err) + } + + if block == nil { + t.Error("block is nil") + } +} + +func TestParser_getBlockByNumberWithRetry_Error(t *testing.T) { + now := time.Now() + block, err := getBlockByNumberWithRetry(2, time.Millisecond*2, getBlock, 0) + elapsed := time.Since(now) + if err == nil { + t.Error("getBlockByNumberWithRetry method need fail") + } + + if block != nil { + t.Error("block object need be nil") + } + + if elapsed > time.Millisecond*7 { + t.Error("Thundering Herd prevent doesn't work") + } +} + +func getBlock(num int64) (*blockatlas.Block, error) { + if num == 0 { + return nil, errors.New("test") + } + return &blockatlas.Block{}, nil +} + +func getMockedBlockAPI() blockatlas.BlockAPI { + p := Platform{CoinIndex: 60} + return &p +} + +func getMockedRedis(t *testing.T) *storage.Storage { + s, err := miniredis.Run() + if err != nil { + t.Fatal(err) + } + + cache := storage.New() + err = cache.Init(fmt.Sprintf("redis://%s", s.Addr())) + if err != nil { + logger.Fatal(err) + } + return cache +} + +type Platform struct { + CoinIndex uint +} + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return wantedMockedNumber, nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[p.CoinIndex] +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + return &blockatlas.Block{}, nil +} + +func TestGetTxBatches(t *testing.T) { + txs := make(blockatlas.Txs, 10000) + batches := getTxsBatches(txs, 1000) + assert.Len(t, batches, 10) + batches = getTxsBatches(txs, 100) + assert.Len(t, batches, 100) + batches = getTxsBatches(txs, 500) + assert.Len(t, batches, 20) + + txs = make(blockatlas.Txs, 3800) + batches = getTxsBatches(txs, 100) + assert.Len(t, batches, 38) + batches = getTxsBatches(txs, 1000) + assert.Len(t, batches, 4) + + txs = make(blockatlas.Txs, 5000) + batches = getTxsBatches(txs, 10000) + assert.Len(t, batches, 1) + + txs = make(blockatlas.Txs, 0) + batches = getTxsBatches(txs, 100) + assert.Len(t, batches, 0) + + txs = make(blockatlas.Txs, 0) + batches = getTxsBatches(txs, 100) + assert.Len(t, batches, 0) + + batches = getTxsBatches(nil, 100) + assert.Len(t, batches, 0) + + txs = make(blockatlas.Txs, 1000000) + batches = getTxsBatches(txs, 5000) + assert.Len(t, batches, 200) +} diff --git a/services/subscription/subscribtion.go b/services/observer/subscriber/subscriber.go similarity index 82% rename from services/subscription/subscribtion.go rename to services/observer/subscriber/subscriber.go index a381fd59f..dc9cc4a9a 100644 --- a/services/subscription/subscribtion.go +++ b/services/observer/subscriber/subscriber.go @@ -1,4 +1,4 @@ -package subscription +package subscriber import ( "encoding/json" @@ -14,7 +14,7 @@ const ( UpdateSubscription blockatlas.SubscriptionOperation = "UpdateSubscription" ) -func Consume(delivery amqp.Delivery, storage storage.Addresses) { +func RunSubscriber(delivery amqp.Delivery, storage storage.Addresses) { var event blockatlas.SubscriptionEvent err := json.Unmarshal(delivery.Body, &event) if err != nil { @@ -35,30 +35,23 @@ func Consume(delivery amqp.Delivery, storage storage.Addresses) { if err != nil { logger.Error(err, params) } - err = delivery.Ack(false) - if err != nil { - logger.Error(err, params) - } logger.Info("Updated", params) case AddSubscription: err = storage.AddSubscriptions(newSubscriptions) if err != nil { logger.Error(err, params) } - err = delivery.Ack(false) - if err != nil { - logger.Error(err, params) - } logger.Info("Added", params) case DeleteSubscription: err := storage.DeleteSubscriptions(oldSubscriptions) if err != nil { logger.Error(err, params) } - err = delivery.Ack(false) - if err != nil { - logger.Error(err, params) - } logger.Info("Deleted", params) } + + err = delivery.Ack(false) + if err != nil { + logger.Error(err, params) + } } diff --git a/storage/addresses.go b/storage/addresses.go index 97e8cb244..8a3a1cfda 100644 --- a/storage/addresses.go +++ b/storage/addresses.go @@ -4,76 +4,133 @@ import ( "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "sync" ) const ( ATLAS_OBSERVER = "ATLAS_OBSERVER" ) -func (s *Storage) Lookup(coin uint, addresses []string) ([]blockatlas.Subscription, error) { +type SubscriptionOperation func(sub blockatlas.Subscription, wg *sync.WaitGroup, errorsChan chan<- error) + +func (s *Storage) RunOperation(subscriptions []blockatlas.Subscription, operation SubscriptionOperation) error { + var ( + errorsChan = make(chan error, len(subscriptions)) + wg sync.WaitGroup + ) + + for _, sub := range subscriptions { + wg.Add(1) + go operation(sub, &wg, errorsChan) + } + wg.Wait() + close(errorsChan) + + if len(errorsChan) != 0 { + var errorsStr string + for err := range errorsChan { + errorsStr += err.Error() + " " + } + return errors.E(errorsStr) + } + + return nil +} + +func (s *Storage) DeleteSubscriptions(subscriptions []blockatlas.Subscription) error { + return s.RunOperation(subscriptions, s.deleteSubscriptions) +} + +func (s *Storage) AddSubscriptions(subscriptions []blockatlas.Subscription) error { + return s.RunOperation(subscriptions, s.addSubscriptions) +} + +func (s *Storage) FindSubscriptions(coin uint, addresses []string) ([]blockatlas.Subscription, error) { if len(addresses) == 0 { return nil, errors.E("cannot look up an empty list") } - observers := make([]blockatlas.Subscription, 0) + + observersSliceChan := make(chan []blockatlas.Subscription, len(addresses)) + observers := make([]blockatlas.Subscription, 0, len(addresses)) + + var wg sync.WaitGroup + wg.Add(len(addresses)) + for _, address := range addresses { - key := getSubscriptionKey(coin, address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - if err != nil { - continue - } - for _, guid := range guids { - observers = append(observers, blockatlas.Subscription{Coin: coin, Address: address, GUID: guid}) + go s.findSubscriptionsByAddress(coin, address, observersSliceChan, &wg) + } + wg.Wait() + close(observersSliceChan) + + for slice := range observersSliceChan { + for _, v := range slice { + observers = append(observers, v) } } + return observers, nil } -func (s *Storage) AddSubscriptions(subscriptions []blockatlas.Subscription) error { - for _, sub := range subscriptions { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - s.GetHMValue(ATLAS_OBSERVER, key, &guids) - if guids == nil { - guids = make([]string, 0) - } - if hasObject(guids, sub.GUID) { - continue - } - guids = append(guids, sub.GUID) - err := s.AddHM(ATLAS_OBSERVER, key, guids) - if err != nil { - return err - } +func (s *Storage) findSubscriptionsByAddress(coin uint, address string, sub chan<- []blockatlas.Subscription, wg *sync.WaitGroup) { + defer wg.Done() + key := getSubscriptionKey(coin, address) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + if err != nil { + return } - return nil + + result := make([]blockatlas.Subscription, 0, len(guids)) + + for _, guid := range guids { + result = append(result, blockatlas.Subscription{Coin: coin, Address: address, GUID: guid}) + } + + sub <- result } -func (s *Storage) DeleteSubscriptions(subscriptions []blockatlas.Subscription) error { - for _, sub := range subscriptions { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - if err != nil { - continue - } - newHooks := make([]string, 0) - for _, guid := range guids { - if guid == sub.GUID { - continue - } - newHooks = append(newHooks, guid) - } - if len(newHooks) == 0 { - _ = s.DeleteHM(ATLAS_OBSERVER, key) +func (s *Storage) deleteSubscriptions(sub blockatlas.Subscription, wg *sync.WaitGroup, errorsChan chan<- error) { + defer wg.Done() + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + if err != nil { + errorsChan <- err + return + } + newHooks := make([]string, 0) + for _, guid := range guids { + if guid == sub.GUID { continue } - err = s.AddHM(ATLAS_OBSERVER, key, newHooks) - if err != nil { - return err - } + newHooks = append(newHooks, guid) + } + if len(newHooks) == 0 { + _ = s.DeleteHM(ATLAS_OBSERVER, key) + return + } + err = s.AddHM(ATLAS_OBSERVER, key, newHooks) + if err != nil { + errorsChan <- err + } +} + +func (s *Storage) addSubscriptions(sub blockatlas.Subscription, wg *sync.WaitGroup, errorsChan chan<- error) { + defer wg.Done() + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + s.GetHMValue(ATLAS_OBSERVER, key, &guids) + if guids == nil { + guids = make([]string, 0) + } + if hasObject(guids, sub.GUID) { + return + } + guids = append(guids, sub.GUID) + err := s.AddHM(ATLAS_OBSERVER, key, guids) + if err != nil { + errorsChan <- err } - return nil } func getSubscriptionKey(coin uint, address string) string { diff --git a/storage/addresses_test.go b/storage/addresses_test.go new file mode 100644 index 000000000..52ef3856e --- /dev/null +++ b/storage/addresses_test.go @@ -0,0 +1,347 @@ +package storage + +import ( + "fmt" + "github.com/alicebob/miniredis" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "testing" +) + +func TestStorage_Lookup(t *testing.T) { + s := initStorage(t) + assert.NotNil(t, s) + + type fields struct { + coin int + addresses []string + } + tests := []struct { + name string + fields fields + wantData []blockatlas.Subscription + wantCondition bool + }{ + {"test all guids found", + fields{coin: 60, addresses: []string{"1", "2", "3"}}, + []blockatlas.Subscription{ + {Coin: 60, Address: "1", GUID: "1"}, + {Coin: 60, Address: "2", GUID: "2"}, + {Coin: 60, Address: "3", GUID: "3"}, + }, + true, + }, + {"test not found", + fields{coin: 60, addresses: []string{"1", "4", "3"}}, + []blockatlas.Subscription{ + {Coin: 60, Address: "1", GUID: "1"}, + {Coin: 60, Address: "2", GUID: "2"}, + {Coin: 60, Address: "3", GUID: "3"}, + }, + false, + }, + } + + for _, tt := range tests { + for i, a := range tt.fields.addresses { + key := getSubscriptionKey(uint(tt.fields.coin), a) + err := s.AddHM(ATLAS_OBSERVER, key, []string{tt.wantData[i].GUID}) + if err != nil { + t.Fatal(err) + } + } + + t.Run(tt.name, func(t *testing.T) { + if got, err := s.FindSubscriptions(uint(tt.fields.coin), tt.fields.addresses); !(isEqualSubscriptions(got, tt.wantData) == tt.wantCondition) || err != nil { + t.Fatal(got) + } + }) + } +} + +func TestStorage_Lookup_MultipleGUIDs(t *testing.T) { + s := initStorage(t) + assert.NotNil(t, s) + + want := []blockatlas.Subscription{ + {Coin: 60, Address: "1", GUID: "1"}, + {Coin: 60, Address: "2", GUID: "2"}, + {Coin: 60, Address: "2", GUID: "3"}, + {Coin: 60, Address: "3", GUID: "3"}, + } + + key1 := getSubscriptionKey(uint(60), "1") + err := s.AddHM(ATLAS_OBSERVER, key1, []string{"1"}) + if err != nil { + t.Fatal(err) + } + + key2 := getSubscriptionKey(uint(60), "2") + err = s.AddHM(ATLAS_OBSERVER, key2, []string{"2", "3"}) + if err != nil { + t.Fatal(err) + } + + key3 := getSubscriptionKey(uint(60), "3") + err = s.AddHM(ATLAS_OBSERVER, key3, []string{"3"}) + if err != nil { + t.Fatal(err) + } + + given, err := s.FindSubscriptions(uint(60), []string{"1", "2", "3"}) + assert.Nil(t, err) + assert.True(t, isEqualSubscriptions(given, want)) +} + +func TestStorage_Lookup_NotFoundSeveral(t *testing.T) { + s := initStorage(t) + assert.NotNil(t, s) + + want := []blockatlas.Subscription{ + {Coin: 60, Address: "1", GUID: "1"}, + } + + key1 := getSubscriptionKey(uint(60), "1") + err := s.AddHM(ATLAS_OBSERVER, key1, []string{"1"}) + if err != nil { + t.Fatal(err) + } + + key2 := getSubscriptionKey(uint(60), "2") + err = s.AddHM(ATLAS_OBSERVER, key2, []string{"2", "3"}) + if err != nil { + t.Fatal(err) + } + + key3 := getSubscriptionKey(uint(60), "3") + err = s.AddHM(ATLAS_OBSERVER, key3, []string{"3"}) + if err != nil { + t.Fatal(err) + } + + given, err := s.FindSubscriptions(uint(60), []string{"1", "4", "5"}) + assert.Nil(t, err) + assert.True(t, isEqualSubscriptions(given, want)) +} + +func TestStorage_AddSubscriptions(t *testing.T) { + s := initStorage(t) + assert.NotNil(t, s) + + subs := []blockatlas.Subscription{ + {Coin: 60, Address: "1", GUID: "1"}, + {Coin: 144, Address: "11212", GUID: "112"}, + {Coin: 144, Address: "112121", GUID: "112"}, + } + var want []string + for _, sub := range subs { + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + assert.NotNil(t, err) + assert.Equal(t, want, guids) + } + + err := s.AddSubscriptions(subs) + assert.Nil(t, err) + + for _, sub := range subs { + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + assert.Nil(t, err) + assert.NotNil(t, guids) + + var counter int + for _, g := range guids { + if g == sub.GUID { + counter++ + } + } + assert.True(t, counter == 1) + } + + NewSubs := []blockatlas.Subscription{ + {Coin: 714, Address: "2", GUID: "2"}, + {Coin: 148, Address: "21", GUID: "21"}, + {Coin: 148, Address: "21", GUID: "21"}, + } + + err = s.AddSubscriptions(NewSubs) + assert.Nil(t, err) + + for _, sub := range subs { + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + assert.Nil(t, err) + assert.NotNil(t, guids) + + var counter int + for _, g := range guids { + if g == sub.GUID { + counter++ + } + } + assert.True(t, counter == 1) + } + + for _, sub := range NewSubs { + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + assert.Nil(t, err) + assert.NotNil(t, guids) + + var counter int + for _, g := range guids { + if g == sub.GUID { + counter++ + } + } + assert.True(t, counter == 1) + } + + NotExistingSubs := []blockatlas.Subscription{ + {Coin: 111, Address: "2", GUID: "2"}, + {Coin: 222, Address: "21", GUID: "21"}, + } + + for _, sub := range NotExistingSubs { + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + assert.NotNil(t, err) + assert.Nil(t, guids) + + var counter int + for _, g := range guids { + if g == sub.GUID { + counter++ + } + } + assert.False(t, counter == 1) + } +} + +func TestStorage_DeleteSubscriptions(t *testing.T) { + s := initStorage(t) + assert.NotNil(t, s) + + subs := []blockatlas.Subscription{ + {Coin: 60, Address: "1", GUID: "1"}, + {Coin: 144, Address: "11212", GUID: "112"}, + {Coin: 255, Address: "112121", GUID: "1121"}, + } + var want []string + for _, sub := range subs { + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + assert.NotNil(t, err) + assert.Equal(t, want, guids) + } + + err := s.AddSubscriptions(subs) + assert.Nil(t, err) + + for _, sub := range subs { + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + assert.Nil(t, err) + assert.NotNil(t, guids) + + var counter int + for _, g := range guids { + if g == sub.GUID { + counter++ + } + } + assert.True(t, counter == 1) + } + + deleted_subs := []blockatlas.Subscription{ + {Coin: 60, Address: "1", GUID: "1"}, + {Coin: 144, Address: "11212", GUID: "112"}, + } + + err = s.DeleteSubscriptions(deleted_subs) + assert.Nil(t, err) + + for _, sub := range deleted_subs { + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + assert.NotNil(t, err) + assert.Nil(t, guids) + + var counter int + for _, g := range guids { + if g == sub.GUID { + counter++ + } + } + assert.True(t, counter == 0) + } + + existing_subs := []blockatlas.Subscription{ + {Coin: 255, Address: "112121", GUID: "1121"}, + } + + for _, sub := range existing_subs { + key := getSubscriptionKey(sub.Coin, sub.Address) + var guids []string + err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) + assert.Nil(t, err) + assert.NotNil(t, guids) + + var counter int + for _, g := range guids { + if g == sub.GUID { + counter++ + } + } + assert.True(t, counter == 1) + } +} + +func isEqualSubscriptions(given, want []blockatlas.Subscription) bool { + if len(given) != len(want) { + return false + } + var givenCounter int + for _, g := range given { + var wantCounter int + for _, w := range want { + if w == g { + wantCounter++ + } + } + if wantCounter > 0 { + givenCounter++ + } + } + + if givenCounter == len(want) { + return true + } + return false +} + +func initStorage(t *testing.T) *Storage { + s, err := miniredis.Run() + if err != nil { + t.Fatal(err) + } + + storage := New() + err = storage.Init(fmt.Sprintf("redis://%s", s.Addr())) + if err != nil { + logger.Fatal(err) + } + return storage +} diff --git a/storage/storage.go b/storage/storage.go index 0b66d1b60..284977603 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -40,12 +40,12 @@ func RestoreConnectionWorker(storage *Storage, uri string, timeout time.Duration } type Tracker interface { - GetBlockNumber(coin uint) (int64, error) - SetBlockNumber(coin uint, num int64) error + GetLastParsedBlockNumber(coin uint) (int64, error) + SetLastParsedBlockNumber(coin uint, num int64) error } type Addresses interface { - Lookup(coin uint, addresses []string) ([]blockatlas.Subscription, error) + FindSubscriptions(coin uint, addresses []string) ([]blockatlas.Subscription, error) AddSubscriptions(subscriptions []blockatlas.Subscription) error DeleteSubscriptions(subscriptions []blockatlas.Subscription) error } diff --git a/storage/tracker.go b/storage/tracker.go index 469de1bcc..78ab2b678 100644 --- a/storage/tracker.go +++ b/storage/tracker.go @@ -33,7 +33,7 @@ func (bm *BlockMap) GetHeights() map[uint]int64 { return bm.heights } -func (s *Storage) GetBlockNumber(coin uint) (int64, error) { +func (s *Storage) GetLastParsedBlockNumber(coin uint) (int64, error) { b, ok := s.blockHeights.GetBlock(coin) if ok { return b, nil @@ -46,7 +46,7 @@ func (s *Storage) GetBlockNumber(coin uint) (int64, error) { return b, nil } -func (s *Storage) SetBlockNumber(coin uint, num int64) error { +func (s *Storage) SetLastParsedBlockNumber(coin uint, num int64) error { s.blockHeights.SetBlock(coin, num) return s.Add(getBlockKey(coin), num) } diff --git a/storage/tracker_test.go b/storage/tracker_test.go new file mode 100644 index 000000000..56a7a3072 --- /dev/null +++ b/storage/tracker_test.go @@ -0,0 +1,24 @@ +package storage + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestBlockMap(t *testing.T) { + s := initStorage(t) + assert.NotNil(t, s) + + block, err := s.GetLastParsedBlockNumber(60) + assert.Nil(t, err) + assert.Equal(t, int64(0), block) + + newBlock := int64(1400) + + err = s.SetLastParsedBlockNumber(60, newBlock) + assert.Nil(t, err) + + current, err := s.GetLastParsedBlockNumber(60) + assert.Nil(t, err) + assert.Equal(t, newBlock, current) +} diff --git a/tests/docker_test/environment_run_test.go b/tests/docker_test/environment_run_test.go index ca13dd7a1..35e38f3a7 100644 --- a/tests/docker_test/environment_run_test.go +++ b/tests/docker_test/environment_run_test.go @@ -3,13 +3,33 @@ package docker_test import ( + "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "log" "os" "testing" ) +var ( + rawTransactionsChannel, + transactionsChannel, subscriptionChannel mq.MessageChannel +) + func TestMain(m *testing.M) { setup.RunMQContainer() + if err := mq.RawTransactions.Declare(); err != nil { + log.Fatal(err) + } + if err := mq.Transactions.Declare(); err != nil { + log.Fatal(err) + } + if err := mq.Subscriptions.Declare(); err != nil { + log.Fatal(err) + } + rawTransactionsChannel = mq.RawTransactions.GetMessageChannel() + subscriptionChannel = mq.Subscriptions.GetMessageChannel() + transactionsChannel = mq.Transactions.GetMessageChannel() + setup.RunRedisContainer() code := m.Run() setup.StopMQContainer() diff --git a/tests/docker_test/notifier_test.go b/tests/docker_test/notifier_test.go new file mode 100644 index 000000000..ea9fa9589 --- /dev/null +++ b/tests/docker_test/notifier_test.go @@ -0,0 +1,108 @@ +// +build integration + +package docker_test + +import ( + "context" + "encoding/json" + "github.com/streadway/amqp" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/observer/notifier" + "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "testing" + "time" +) + +var ( + txs = blockatlas.Txs{ + { + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + }, + }, + } +) + +func TestNotifier(t *testing.T) { + err := setup.Cache.AddSubscriptions([]blockatlas.Subscription{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", GUID: "guid_test"}}) + assert.Nil(t, err) + + err = produceTxs(txs) + assert.Nil(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + + go mq.RawTransactions.RunConsumerForChannelWithCancel(notifier.RunNotifier, rawTransactionsChannel, setup.Cache, ctx) + time.Sleep(time.Second * 3) + msg := transactionsChannel.GetMessage() + ConsumerToTestTransactions(msg, t) + cancel() +} + +func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { + var event notifier.DispatchEvent + if err := json.Unmarshal(delivery.Body, &event); err != nil { + assert.Nil(t, err) + return + } + err := delivery.Ack(false) + if err != nil { + assert.Nil(t, err) + } + + memo := blockatlas.NativeTokenTransfer{ + Name: "", + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + } + + assert.Equal(t, notifier.DispatchEvent{ + Action: blockatlas.TxNativeTokenTransfer, + Result: &blockatlas.Tx{ + Type: blockatlas.TxNativeTokenTransfer, + Direction: "outgoing", + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: &memo, + }, + GUID: "guid_test", + }, event) + + return +} + +func produceTxs(txs blockatlas.Txs) error { + body, err := json.Marshal(txs) + if err != nil { + return err + } + return mq.RawTransactions.Publish(body) +} diff --git a/tests/docker_test/observer_test.go b/tests/docker_test/observer_test.go index 5bccfff2a..8c60b2351 100644 --- a/tests/docker_test/observer_test.go +++ b/tests/docker_test/observer_test.go @@ -3,62 +3,158 @@ package docker_test import ( + "context" "encoding/json" + "github.com/streadway/amqp" "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/subscription" - "github.com/trustwallet/blockatlas/storage" + "github.com/trustwallet/blockatlas/services/observer/notifier" + "github.com/trustwallet/blockatlas/services/observer/parser" "github.com/trustwallet/blockatlas/tests/docker_test/setup" - "io/ioutil" - "path/filepath" - "runtime" + "go.uber.org/atomic" "testing" "time" ) -func TestSubscriberAddSubscription(t *testing.T) { - _, goFile, _, _ := runtime.Caller(0) - testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_added.json") - testFileGiven, err := ioutil.ReadFile(testFilePathGiven) - if err != nil { - t.Fatal(err) +var counter atomic.Int32 +var counterBlock atomic.Int32 + +func TestFullFlow(t *testing.T) { + err := setup.Cache.AddSubscriptions([]blockatlas.Subscription{{Coin: 60, Address: "testAddress", GUID: "guid_test"}}) + assert.Nil(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + + stopChan := make(chan struct{}, 1) + + params := setupParserFull(stopChan) + params.Ctx = ctx + params.Queue = mq.RawTransactions + + go parser.RunParser(params) + time.Sleep(time.Second * 2) + + go mq.RawTransactions.RunConsumerForChannelWithCancel(notifier.RunNotifier, rawTransactionsChannel, setup.Cache, ctx) + time.Sleep(time.Second * 5) + + for i := 0; i < 11; i++ { + x := transactionsChannel.GetMessage() + ConsumerToTestTransactionsFull(x, t, cancel, i) } - var givenEvents []blockatlas.SubscriptionEvent - if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { - t.Fatal(err) + <-stopChan +} + +func getMockedBlockAPIFull() blockatlas.BlockAPI { + p := PlatformFullFlow{CoinIndex: 60} + return &p +} + +type PlatformFullFlow struct { + CoinIndex uint +} + +func (p *PlatformFullFlow) CurrentBlockNumber() (int64, error) { + i := counterBlock.Load() + counterBlock.Add(1) + return int64(i), nil +} + +func (p *PlatformFullFlow) Coin() coin.Coin { + return coin.Coins[p.CoinIndex] +} + +func (p *PlatformFullFlow) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + if num < 100 { + return &blockatlas.Block{ + Number: num, + ID: "", + Txs: []blockatlas.Tx{ + { + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.ETH, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "testAddress", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "testAddress", + }, + }, + }, + }, nil } + return &blockatlas.Block{}, nil +} - testFilePathWanted := filepath.Join(filepath.Dir(goFile), "data", "wanted_subscriptions_added.json") - testFileWanted, err := ioutil.ReadFile(testFilePathWanted) +func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel context.CancelFunc, counter int) { + var event notifier.DispatchEvent + if err := json.Unmarshal(delivery.Body, &event); err != nil { + assert.Nil(t, err) + return + } + err := delivery.Ack(false) if err != nil { - t.Fatal(err) + assert.Nil(t, err) } - var wantedEvents []blockatlas.Subscription - if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { - t.Fatal(err) + memo := blockatlas.NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "testAddress", } - assert.Nil(t, mq.Subscriptions.Declare()) + assert.Equal(t, notifier.DispatchEvent{ + Action: blockatlas.TxNativeTokenTransfer, + Result: &blockatlas.Tx{ + Type: blockatlas.TxNativeTokenTransfer, + Direction: "incoming", + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.ETH, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "testAddress", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: &memo, + }, + GUID: "guid_test", + }, event) - for _, event := range givenEvents { - body, err := json.Marshal(event) - assert.Nil(t, err) + if counter == 10 { + cancel() + } +} - err = mq.Subscriptions.Publish(body) - assert.Nil(t, err) +func setupParserFull(stopChan chan<- struct{}) parser.Params { + minTime := time.Second + maxTime := time.Second * 2 + maxBatchBlocksAmount := 1 - go mq.Subscriptions.RunConsumer(subscription.Consume, setup.Cache) - time.Sleep(time.Second / 5) - } + pollInterval := notifier.GetInterval(0, minTime, maxTime) - result, err := setup.Cache.GetAllHM(storage.ATLAS_OBSERVER) - assert.Nil(t, err) - assert.NotNil(t, result) + backlogCount := 1 - for _, wanted := range wantedEvents { - result, err := setup.Cache.Lookup(wanted.Coin, []string{wanted.Address}) - assert.Nil(t, err) - assert.Equal(t, result[0], wanted) + return parser.Params{ + Api: getMockedBlockAPIFull(), + Storage: setup.Cache, + ParsingBlocksInterval: pollInterval, + BacklogCount: backlogCount, + MaxBacklogBlocks: int64(maxBatchBlocksAmount), + TxBatchLimit: 100, + StopChannel: stopChan, } } diff --git a/tests/docker_test/parser_test.go b/tests/docker_test/parser_test.go new file mode 100644 index 000000000..1c1005a04 --- /dev/null +++ b/tests/docker_test/parser_test.go @@ -0,0 +1,119 @@ +// +build integration + +package docker_test + +import ( + "context" + "encoding/json" + "github.com/streadway/amqp" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/services/observer/notifier" + "github.com/trustwallet/blockatlas/services/observer/parser" + "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "testing" + "time" +) + +func TestParserFetchAndPublishBlock_NormalCase(t *testing.T) { + stopChan := make(chan struct{}, 1) + + params := setupParser(stopChan) + + ctx, cancel := context.WithCancel(context.Background()) + + params.Ctx = ctx + params.Queue = mq.RawTransactions + + go parser.RunParser(params) + + time.Sleep(time.Microsecond) + ConsumerToTestAmountOfBlocks(rawTransactionsChannel.GetMessage(), t, cancel) + <-stopChan +} + +func getMockedBlockAPI() blockatlas.BlockAPI { + p := Platform{CoinIndex: 60} + return &p +} + +type Platform struct { + CoinIndex uint +} + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return int64(100), nil +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[p.CoinIndex] +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + if num < 101 { + return &blockatlas.Block{ + Number: num, + ID: "", + Txs: []blockatlas.Tx{ + { + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + }, + }, + }, + }, nil + } + return &blockatlas.Block{}, nil +} + +func ConsumerToTestAmountOfBlocks(delivery amqp.Delivery, t *testing.T, cancelFunc context.CancelFunc) { + var txs blockatlas.Txs + if err := json.Unmarshal(delivery.Body, &txs); err != nil { + logger.Error(err) + return + } + err := delivery.Ack(false) + if err != nil { + logger.Error(err) + } + + assert.Equal(t, len(txs), 50) + cancelFunc() +} + +func setupParser(stopChan chan struct{}) parser.Params { + minTime := time.Second + maxTime := time.Second * 2 + maxBatchBlocksAmount := 100 + + pollInterval := notifier.GetInterval(0, minTime, maxTime) + + backlogCount := 50 + + return parser.Params{ + Api: getMockedBlockAPI(), + Storage: setup.Cache, + ParsingBlocksInterval: pollInterval, + BacklogCount: backlogCount, + MaxBacklogBlocks: int64(maxBatchBlocksAmount), + TxBatchLimit: 100, + StopChannel: stopChan, + } +} diff --git a/tests/docker_test/subscriber_test.go b/tests/docker_test/subscriber_test.go new file mode 100644 index 000000000..ca652763a --- /dev/null +++ b/tests/docker_test/subscriber_test.go @@ -0,0 +1,66 @@ +// +build integration + +package docker_test + +import ( + "context" + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/observer/subscriber" + "github.com/trustwallet/blockatlas/storage" + "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "io/ioutil" + "path/filepath" + "runtime" + "testing" + "time" +) + +func TestSubscriberAddSubscription(t *testing.T) { + _, goFile, _, _ := runtime.Caller(0) + testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_added.json") + testFileGiven, err := ioutil.ReadFile(testFilePathGiven) + if err != nil { + t.Fatal(err) + } + var givenEvents []blockatlas.SubscriptionEvent + if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { + t.Fatal(err) + } + + testFilePathWanted := filepath.Join(filepath.Dir(goFile), "data", "wanted_subscriptions_added.json") + testFileWanted, err := ioutil.ReadFile(testFilePathWanted) + if err != nil { + t.Fatal(err) + } + var wantedEvents []blockatlas.Subscription + if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { + t.Fatal(err) + } + + for _, event := range givenEvents { + body, err := json.Marshal(event) + assert.Nil(t, err) + + err = mq.Subscriptions.Publish(body) + assert.Nil(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + + go mq.Subscriptions.RunConsumerForChannelWithCancel(subscriber.RunSubscriber, subscriptionChannel, setup.Cache, ctx) + time.Sleep(time.Second / 5) + cancel() + } + + result, err := setup.Cache.GetAllHM(storage.ATLAS_OBSERVER) + assert.Nil(t, err) + assert.NotNil(t, result) + + for _, wanted := range wantedEvents { + result, err := setup.Cache.FindSubscriptions(wanted.Coin, []string{wanted.Address}) + assert.Nil(t, err) + assert.Equal(t, result[0], wanted) + } +} From 2190c3b07fa7f5eadbddcba309774c8576e6a693 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov <34573846+prazd@users.noreply.github.com> Date: Thu, 26 Mar 2020 01:39:05 +0300 Subject: [PATCH 207/506] [Observer-TX] Fix issue with wrong transaction direction (#976) * [TX] Fix GetTransactionDirection * Add additional types checking for Memo * Add test Co-authored-by: Nick Kozlov --- pkg/blockatlas/tx.go | 4 ++++ pkg/blockatlas/tx_test.go | 46 ++++++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 8a1e1ddd1..09cbc5797 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -270,6 +270,10 @@ func (t *Tx) GetTransactionDirection(address string) Direction { return InferDirection(t, addressSet) } switch meta := t.Meta.(type) { + case *TokenTransfer: + return determineTransactionDirection(address, meta.From, meta.To) + case *NativeTokenTransfer: + return determineTransactionDirection(address, meta.From, meta.To) case TokenTransfer: return determineTransactionDirection(address, meta.From, meta.To) case NativeTokenTransfer: diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index f6b77e7a7..d268e0ba8 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -201,7 +201,7 @@ func Test_getDirection(t *testing.T) { {"Test NativeTokenTransfer Direction Self", args{ Tx{ - Meta: NativeTokenTransfer{ + Meta: &NativeTokenTransfer{ From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, @@ -211,7 +211,7 @@ func Test_getDirection(t *testing.T) { {"Test NativeTokenTransfer Direction Outgoing", args{ Tx{ - Meta: NativeTokenTransfer{ + Meta: &NativeTokenTransfer{ From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", }, @@ -221,7 +221,7 @@ func Test_getDirection(t *testing.T) { {"Test NativeTokenTransfer Direction Incoming", args{ Tx{ - Meta: NativeTokenTransfer{ + Meta: &NativeTokenTransfer{ From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, @@ -231,7 +231,7 @@ func Test_getDirection(t *testing.T) { {"Test TokenTransfer Direction Self", args{ Tx{ - Meta: TokenTransfer{ + Meta: &TokenTransfer{ From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, @@ -241,7 +241,7 @@ func Test_getDirection(t *testing.T) { {"Test TokenTransfer Direction Outgoing", args{ Tx{ - Meta: TokenTransfer{ + Meta: &TokenTransfer{ From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", }, @@ -251,7 +251,7 @@ func Test_getDirection(t *testing.T) { {"Test TokenTransfer Direction Incoming", args{ Tx{ - Meta: TokenTransfer{ + Meta: &TokenTransfer{ From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", }, @@ -492,3 +492,37 @@ func TestGetTxsTx(t *testing.T) { assert.Equal(t, txs.Map["tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"].Size(), 2) assert.Equal(t, txs.Map["tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex"].Size(), 2) } + +func TestTx_GetTransactionDirection(t *testing.T) { + txMeta := TokenTransfer{ + Name: "Kyber Network Crystal", + Symbol: "KNC", + TokenID: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + Decimals: 18, + Value: "100000000000000", + From: "0x08777CB1e80F45642752662B04886Df2d271E049", + To: "0x38d45371993eEc84f38FEDf93C646aA2D2267CEA", + } + + tx := Tx{ + ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c4", + Coin: 60, + From: "0x08777CB1e80F45642752662B04886Df2d271E049", + To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + Fee: "52473000000000", + Date: 1585169424, + Block: 9742705, + Status: "completed", + Sequence: 149, + Type: "token_transfer", + Meta: txMeta, + } + + tx.Direction = tx.GetTransactionDirection("0x38d45371993eEc84f38FEDf93C646aA2D2267CEA") + assert.Equal(t, Direction("incoming"), tx.Direction) + + tx.Meta = &txMeta + + tx.Direction = tx.GetTransactionDirection("0x38d45371993eEc84f38FEDf93C646aA2D2267CEA") + assert.Equal(t, Direction("incoming"), tx.Direction) +} From e8f3bb5e5fbb909505fb0834f0318b1df1289072 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Thu, 26 Mar 2020 03:18:24 +0300 Subject: [PATCH 208/506] Add transaction direction to eth transaction api (#977) --- platform/ethereum/transaction.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/ethereum/transaction.go b/platform/ethereum/transaction.go index e3dfbd012..d2df6038e 100644 --- a/platform/ethereum/transaction.go +++ b/platform/ethereum/transaction.go @@ -34,8 +34,9 @@ func (p *Platform) getTransactions(c *gin.Context) { } var txs []blockatlas.Tx - for _, srcTx := range srcPage.Docs { + for i, srcTx := range srcPage.Docs { txs = AppendTxs(txs, &srcTx, p.CoinIndex) + txs[i].Direction = txs[i].GetTransactionDirection(address) } page := blockatlas.TxPage(txs) From 9588d07d110b69564cfe54e41ab4872c88473031 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Thu, 26 Mar 2020 08:47:07 +0800 Subject: [PATCH 209/506] remove go-ens / go-ethereum dependency (#973) * remove go-ens / go-ethereum dependency * Fix ens client * move to ens-coincodec * review comments * update fio client --- api/domain.go | 5 +- go.mod | 18 +- go.sum | 244 +------------------------- pkg/blockatlas/client.go | 16 +- platform/ethereum/base.go | 2 + platform/ethereum/domain.go | 35 ++-- platform/ethereum/ens_client.go | 84 +++++++++ platform/ethereum/ens_encoder.go | 86 +++++++++ platform/ethereum/ens_encoder_test.go | 193 ++++++++++++++++++++ platform/ethereum/model.go | 3 +- platform/ethereum/namehash.go | 90 ++++++++++ platform/ethereum/namehash_test.go | 90 ++++++++++ platform/fio/base.go | 2 +- platform/fio/client.go | 1 - platform/harmony/base.go | 3 +- platform/nano/base.go | 3 +- platform/solana/base.go | 3 +- 17 files changed, 600 insertions(+), 278 deletions(-) create mode 100644 platform/ethereum/ens_client.go create mode 100644 platform/ethereum/ens_encoder.go create mode 100644 platform/ethereum/ens_encoder_test.go create mode 100644 platform/ethereum/namehash.go create mode 100644 platform/ethereum/namehash_test.go diff --git a/api/domain.go b/api/domain.go index cd943e650..7c720db36 100644 --- a/api/domain.go +++ b/api/domain.go @@ -1,12 +1,13 @@ package api import ( - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/services/domains" "net/http" "strconv" "strings" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/services/domains" + "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/gin-gonic/gin" diff --git a/go.mod b/go.mod index 5644f85a9..de25d5f8e 100644 --- a/go.mod +++ b/go.mod @@ -10,20 +10,23 @@ require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect github.com/alicebob/miniredis v2.5.0+incompatible - github.com/aristanetworks/goarista v0.0.0-20200310212843-2da4c1f5881b // indirect github.com/btcsuite/btcutil v1.0.1 github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c // indirect github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/ethereum/go-ethereum v1.9.10 github.com/getsentry/sentry-go v0.4.0 github.com/gin-gonic/gin v1.5.0 github.com/go-redis/redis v6.15.6+incompatible + github.com/golang/protobuf v1.3.3 // indirect + github.com/google/go-cmp v0.4.0 // indirect + github.com/gorilla/websocket v1.4.1 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect - github.com/hewigovens/go-coincodec v1.0.4 + github.com/json-iterator/go v1.1.9 // indirect + github.com/klauspost/compress v1.10.1 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/kr/pretty v0.2.0 // indirect github.com/lib/pq v1.1.1 // indirect github.com/mitchellh/mapstructure v1.1.2 github.com/mr-tron/base58 v1.1.3 @@ -31,6 +34,7 @@ require ( github.com/opencontainers/runc v0.1.1 // indirect github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pkg/errors v0.9.1 // indirect github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 github.com/sirupsen/logrus v1.4.2 github.com/spf13/cast v1.3.1 // indirect @@ -39,12 +43,14 @@ require ( github.com/stretchr/testify v1.4.0 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.5 - github.com/wealdtech/go-ens/v3 v3.2.0 + github.com/trustwallet/ens-coincodec v1.0.5 github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect go.uber.org/atomic v1.4.0 golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d - golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect - golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e + golang.org/x/net v0.0.0-20200301022130-244492dfa37a golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect + golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v2 v2.2.8 + gotest.tools v2.2.0+incompatible ) diff --git a/go.sum b/go.sum index 20543a1b8..29bdd1f27 100644 --- a/go.sum +++ b/go.sum @@ -1,21 +1,8 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= -github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= @@ -29,7 +16,6 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Pantani/httpexpect v2.0.0+incompatible h1:P658jo0d3gej0D67KBcSUgpZY76CH1TdxvOfQAmyNu0= github.com/Pantani/httpexpect v2.0.0+incompatible/go.mod h1:+8VdK+EZPV0YorWMMNyakEIYKcDl9OHtde3DdkPqbwQ= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -38,11 +24,6 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/VictoriaMetrics/fastcache v1.5.3 h1:2odJnXLbFZcoV9KYtQ+7TH1UOq3dn3AssMgieaezkR4= -github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= @@ -50,36 +31,18 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMwWcqkLzDAQugVEwedisr5nRJ1r+7LYnv0U= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI= github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= -github.com/allegro/bigcache v1.2.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/apilayer/freegeoip v3.5.0+incompatible/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU= -github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= -github.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= -github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= -github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5 h1:L0TwgZQo7Mga9im6FvKEZGIvyLE/VG/HI5loz5LpvC0= -github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= -github.com/aristanetworks/goarista v0.0.0-20200310212843-2da4c1f5881b h1:VBFuX8nQQ57A6OGYGOLugx/Sc488F0nNIdTtcmNq9qE= -github.com/aristanetworks/goarista v0.0.0-20200310212843-2da4c1f5881b/go.mod h1:QZe5Yh80Hp1b6JxQdpfSEEe8X7hTyTEZSosSrFf/oJE= -github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= -github.com/btcsuite/btcd v0.0.0-20190418232430-6867ff32788a/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.1 h1:GKOz8BnRjYrb/JTKgaOk+zh26NWNdSNvdvv0xoAZMSA= github.com/btcsuite/btcutil v1.0.1/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= @@ -90,20 +53,12 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= -github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c h1:8ahmSVELW1wghbjerVAyuEYD5+Dio66RYvSS0iGfL1M= github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= @@ -121,54 +76,28 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= -github.com/elastic/gosigar v0.10.4 h1:6jfw75dsoflhBMRdO6QPzQUgLqUYTsQQQRkkcsHsuPo= -github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= -github.com/ethereum/go-ethereum v1.9.10 h1:jooX7tWcscpC7ytufk73t9JMCeJQ7aJF2YmZJQEuvFo= -github.com/ethereum/go-ethereum v1.9.10/go.mod h1:lXHkVo/MTvsEXfYsmNzelZ8R1e0DTvdk/wMZJIRpaRw= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a h1:1znxn4+q2MrEdTk1eCk6KIV3muTYVclBIB6CTVR/zBc= -github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getsentry/sentry-go v0.4.0 h1:WqRI2/7EiALbdG9qGB47c0Aks1tdznG5DZd6GSQ1y/8= github.com/getsentry/sentry-go v0.4.0/go.mod h1:xkGcb82SipKQloDNa5b7hTV4VdEyc2bhwd1/UczP52k= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -186,13 +115,10 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= -github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= @@ -227,14 +153,10 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38 h1:y0Wmhvml7cGnzPa9nocn/fMraMH/lMDdeG+rkx4VgYY= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -245,53 +167,29 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= -github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6/go.mod h1:Au3iQ8DvDis8hZ4q2OzRcaKYlAsPt+fYvib5q4nIqu4= -github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hewigovens/go-coincodec v1.0.4 h1:asF02q8WfDwVQjU1O0VZYbOBer0cPJUmTiZKfAgqBYM= -github.com/hewigovens/go-coincodec v1.0.4/go.mod h1:+LTdzScnu782gMt0J3ZccPY9S2uyrGe0R1LUYGWecfc= -github.com/howeyc/fsnotify v0.9.0/go.mod h1:41HzSPxBGeFRQKEEwgh49TRw/nKBsYZ2cF1OzPjSJsA= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= -github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= -github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= -github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= -github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -304,13 +202,9 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= -github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= -github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= @@ -321,11 +215,9 @@ github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6 github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.1 h1:a/QY0o9S6wCi0XhxaMX/QmusicNUqCqFugR6WKPOSoQ= github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= @@ -334,12 +226,12 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= @@ -353,32 +245,19 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= 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/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= -github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5 h1:l16XLUUJ34wIz+RIvLhSwGvLvKyy+W598b135bJN6mg= -github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -388,24 +267,15 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik= -github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c h1:1RHs3tNxjXGHeul8z2t6H2N2TlAqpKe5yryJztRx4Jk= -github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -415,27 +285,18 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= -github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/oschwald/maxminddb-golang v1.3.1/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= -github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= -github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -448,35 +309,14 @@ 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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic= -github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= -github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= -github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= -github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= -github.com/robertkrimen/otto v0.0.0-20170205013659-6a77b7cbc37d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= -github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -497,9 +337,6 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -515,13 +352,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= -github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw= -github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= -github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE= -github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= -github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= -github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5NYJe/zRYDwOu9ku6YHy+Iw7l5DM= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -539,16 +369,9 @@ github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.6.5 h1:2C+t+xyK6p1sujqncYO/VnMvPZcBJjNdKKyxbOdAW8o= github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= -github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= -github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= -github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= -github.com/tjfoc/gmsm v1.3.0/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= -github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= -github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/trustwallet/ens-coincodec v1.0.5 h1:rdebDQYHqNjv+yUdtMf3DXyMgJpEJSI2DSbC1GUFuyk= +github.com/trustwallet/ens-coincodec v1.0.5/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= @@ -559,7 +382,6 @@ github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2t github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -568,18 +390,8 @@ github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtE github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/wealdtech/go-ens/v3 v3.2.0 h1:bshYk63BUJaIriX3UoAcYKh1tVI85kI1Xbg3jAnM/NM= -github.com/wealdtech/go-ens/v3 v3.2.0/go.mod h1:P2OEBvgkhXLrPzPN+eR5z2/wFIGwHyijTDvpuC1xLlo= -github.com/wealdtech/go-multicodec v1.2.0 h1:9AHSxcSE9F9r6ZvQLAO0EXCdM08QfYohaXmW3k6sSh4= -github.com/wealdtech/go-multicodec v1.2.0/go.mod h1:aedGMaTeYkIqi/KCPre1ho5rTb3hGpu/snBOS3GQLw4= github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= -github.com/wealdtech/go-string2eth v1.0.0 h1:jY6b1MVqU6k2Uw/kvcU1Y9/3dDyXfPzZrOFspt82UJs= -github.com/wealdtech/go-string2eth v1.0.0/go.mod h1:UZA/snEybGcD6n+Pl+yoDjmexlEJ6dtoS9myfM83Ol4= -github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= -github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -588,8 +400,6 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= -github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= @@ -610,31 +420,22 @@ golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= -golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -643,11 +444,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -655,12 +453,9 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -674,26 +469,20 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88= @@ -704,18 +493,11 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200218151345-dad8c97a84f5/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= @@ -730,32 +512,16 @@ gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvR gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= -gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= -gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= -gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= -gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190213234257-ec84240a7772/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff h1:uuol9OUzSvZntY1v963NAbVd7A+PHLMz1FlCe3Lorcs= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= -gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go index 3c5f0d08b..b663fa847 100644 --- a/pkg/blockatlas/client.go +++ b/pkg/blockatlas/client.go @@ -4,13 +4,14 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/trustwallet/blockatlas/pkg/errors" "io" "io/ioutil" "net/http" "net/url" "strings" "time" + + "github.com/trustwallet/blockatlas/pkg/errors" ) type Request struct { @@ -33,6 +34,19 @@ func InitClient(baseUrl string) Request { } } +func InitJSONClient(baseUrl string) Request { + headers := map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + } + return Request{ + Headers: headers, + HttpClient: DefaultClient, + ErrorHandler: DefaultErrorHandler, + BaseUrl: baseUrl, + } +} + var DefaultClient = &http.Client{ Timeout: time.Second * 15, } diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index 4d78bcd8d..47bd6d386 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -10,6 +10,7 @@ type Platform struct { RpcURL string client Client collectionsClient CollectionsClient + ens RpcClient } func Init(coin uint, api, rpc string) *Platform { @@ -17,6 +18,7 @@ func Init(coin uint, api, rpc string) *Platform { CoinIndex: coin, RpcURL: rpc, client: Client{blockatlas.InitClient(api)}, + ens: RpcClient{blockatlas.InitJSONClient(rpc)}, } } diff --git a/platform/ethereum/domain.go b/platform/ethereum/domain.go index 354a06d22..7d00f7f8d 100644 --- a/platform/ethereum/domain.go +++ b/platform/ethereum/domain.go @@ -1,29 +1,26 @@ package ethereum import ( - "github.com/ethereum/go-ethereum/ethclient" - cc "github.com/hewigovens/go-coincodec" CoinType "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" - ens "github.com/wealdtech/go-ens/v3" + AddressEncoder "github.com/trustwallet/ens-coincodec" ) func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { var result []blockatlas.Resolved - client, err := ethclient.Dial(p.RpcURL) + node, err := NameHash(name) if err != nil { - return result, errors.E(err, "can't dial to ethereum rpc") - } - defer client.Close() - resolver, err := ens.NewResolver(client, name) - if err != nil { - return result, errors.E(err, "new ens resolver failed") + return result, errors.E(err, "name hash failed") } for _, coin := range coins { + resolver, err := p.ens.Resolver(node[:]) + if err != nil { + return result, errors.E(err, "query resolver failed") + } // try to get multi coin address - address, err := addressForCoin(resolver, coin) + address, err := p.addressForCoin("0x"+resolver, node[:], coin) if err != nil { logger.Error(errors.E(err, errors.Params{"coin": coin, "name": name})) continue @@ -34,12 +31,12 @@ func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, e return result, nil } -func addressForCoin(resolver *ens.Resolver, coin uint64) (string, error) { - address, err := resolver.MultiAddress(coin) +func (p *Platform) addressForCoin(resovler string, node []byte, coin uint64) (string, error) { + result, err := p.ens.Addr(resovler, node, coin) if err != nil { if coin == CoinType.ETH { // user may not set multi coin address - result, err := lookupLegacyETH(resolver) + result, err := p.lookupLegacyETH(resovler, node) if err != nil { return "", errors.E(err, "query legacy address failed") } @@ -47,17 +44,13 @@ func addressForCoin(resolver *ens.Resolver, coin uint64) (string, error) { } return "", errors.E(err, "query multi coin address failed") } - encoded, err := cc.ToString(address, uint32(coin)) + encoded, err := AddressEncoder.ToString(result, uint32(coin)) if err != nil { return "", errors.E(err, "encode to address failed") } return encoded, nil } -func lookupLegacyETH(resolver *ens.Resolver) (string, error) { - address, err := resolver.Address() - if err != nil { - return "", errors.E(err, "query address failed") - } - return address.Hex(), nil +func (p *Platform) lookupLegacyETH(resolver string, node []byte) (string, error) { + return p.ens.LegacyAddr(resolver, node) } diff --git a/platform/ethereum/ens_client.go b/platform/ethereum/ens_client.go new file mode 100644 index 000000000..5229fac5a --- /dev/null +++ b/platform/ethereum/ens_client.go @@ -0,0 +1,84 @@ +package ethereum + +import ( + "encoding/hex" + + "github.com/trustwallet/blockatlas/pkg/address" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" +) + +const ( + registry = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" +) + +type RpcClient struct { + blockatlas.Request +} + +func (c *RpcClient) EthCall(params []interface{}) (string, error) { + var res string + err := c.RpcCall(&res, "eth_call", params) + if err != nil { + return "", err + } + return res, nil +} + +func (c *RpcClient) toParams(to string, data []byte) []interface{} { + return []interface{}{ + map[string]interface{}{ + "to": to, + "data": "0x" + hex.EncodeToString(data), + }, + "latest", + } +} + +func (c *RpcClient) Resolver(node []byte) (string, error) { + data := encodeResolver(node) + params := c.toParams(registry, data) + result, err := c.EthCall(params) + if err != nil { + return "", err + } + if allZero(address.Remove0x(result)) { + return "", errors.E("unregistered name or resolver not set") + } + if len(result) < 40 { + return "", errors.E("invalid address length") + } + return result[len(result)-40:], nil +} + +func (c *RpcClient) Addr(resolver string, node []byte, coin uint64) ([]byte, error) { + data := encodeAddr(node, coin) + params := c.toParams(resolver, data) + result, err := c.EthCall(params) + if err != nil { + return nil, err + } + if len(result) < 32 { + return nil, errors.E("invalid result length") + } + return decodeBytesInHex(result), nil +} + +func (c *RpcClient) LegacyAddr(resolver string, node []byte) (string, error) { + data := encodeLegacyAddr(node) + params := c.toParams(resolver, data) + result, err := c.EthCall(params) + if err != nil || len(result) < 40 { + return "", err + } + return address.EIP55Checksum(result[len(result)-40:]), nil +} + +func allZero(s string) bool { + for _, v := range s { + if v != '0' { + return false + } + } + return true +} diff --git a/platform/ethereum/ens_encoder.go b/platform/ethereum/ens_encoder.go new file mode 100644 index 000000000..79a18dd38 --- /dev/null +++ b/platform/ethereum/ens_encoder.go @@ -0,0 +1,86 @@ +package ethereum + +import ( + "bytes" + "encoding/binary" + "encoding/hex" + "math/big" + "strings" + + "golang.org/x/crypto/sha3" +) + +func encodeResolver(node []byte) []byte { + data := make([]byte, 0, 36) + signature := encodeFunc("resolver(bytes32)") + data = append(data, signature...) + data = append(data, node[:]...) + return data +} + +func encodeAddr(node []byte, coinType uint64) []byte { + data := make([]byte, 0, 68) + signature := encodeFunc("addr(bytes32,uint256)") + data = append(data, signature...) + data = append(data, node...) + data = append(data, encodeCoinType(coinType)...) + return data +} + +func encodeSupportsInterface(id []byte) []byte { + data := make([]byte, 0, 8) + signature := encodeFunc("supportsInterface(bytes4)") + data = append(data, signature...) + data = append(data, id[:4]...) + return data +} + +func encodeLegacyAddr(node []byte) []byte { + data := make([]byte, 0, 36) + signature := encodeFunc("addr(bytes32)") + data = append(data, signature...) + data = append(data, node...) + return data +} + +func encodeFunc(fn string) []byte { + data := make([]byte, 0, 32) + sha := sha3.NewLegacyKeccak256() + if _, err := sha.Write([]byte(fn)); err != nil { + return data + } + sha.Sum(data) + return data[:4] +} + +func encodeCoinType(i uint64) []byte { + data := make([]byte, 24) + buf := new(bytes.Buffer) + err := binary.Write(buf, binary.BigEndian, i) + if err != nil { + return data + } + data = append(data, buf.Bytes()...) + return data +} + +func decodeBytesInHex(s string) []byte { + if strings.HasPrefix(s, "0x") { + s = strings.TrimPrefix(s, "0x") + } + bytes, err := hex.DecodeString(s) + if err != nil || len(bytes) < 32 { + return []byte{} + } + return decodeBytes(bytes) +} + +func decodeBytes(b []byte) []byte { + offset := int64(32) + count := new(big.Int) + count.SetBytes(b[:offset]) + length := new(big.Int) + length.SetBytes(b[offset : offset+count.Int64()]) + offset += count.Int64() + return b[offset : offset+length.Int64()] +} diff --git a/platform/ethereum/ens_encoder_test.go b/platform/ethereum/ens_encoder_test.go new file mode 100644 index 000000000..3b8769458 --- /dev/null +++ b/platform/ethereum/ens_encoder_test.go @@ -0,0 +1,193 @@ +package ethereum + +import ( + "encoding/hex" + "reflect" + "testing" +) + +func Test_encodeResolver(t *testing.T) { + tests := []struct { + name string + node string + want string + }{ + { + "Test ohmyname.eth resolver", + "5ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6", + "0178b8bf5ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + node, _ := hex.DecodeString(tt.node) + want, _ := hex.DecodeString(tt.want) + if got := encodeResolver(node[:]); !reflect.DeepEqual(got, want) { + t.Errorf("encodeResolver() = %v, want %v", hex.EncodeToString(got), tt.want) + } + }) + } +} + +func Test_encodeAddr(t *testing.T) { + type args struct { + node string + coinType uint64 + } + tests := []struct { + name string + args args + want string + }{ + { + "Test encodeAddr", + args{ + "5ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6", + 60, + }, + "f1cb7e065ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6000000000000000000000000000000000000000000000000000000000000003c", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + node, _ := hex.DecodeString(tt.args.node) + want, _ := hex.DecodeString(tt.want) + if got := encodeAddr(node, tt.args.coinType); !reflect.DeepEqual(got, want) { + t.Errorf("encodeAddr() = %v, want %v", hex.EncodeToString(got), tt.want) + } + }) + } +} + +func Test_encodeSupportsInterface(t *testing.T) { + tests := []struct { + name string + id string + want string + }{ + { + "Test encodeSupportsInterface", + "3b3b57de", + "01ffc9a73b3b57de", + }, + { + "Test encodeSupportsInterface", + "f1cb7e06", + "01ffc9a7f1cb7e06", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + id, _ := hex.DecodeString(tt.id) + want, _ := hex.DecodeString(tt.want) + if got := encodeSupportsInterface(id); !reflect.DeepEqual(got, want) { + t.Errorf("encodeSupportsInterface() = %v, want %v", hex.EncodeToString(got), tt.want) + } + }) + } +} + +func Test_encodeLegacyAddr(t *testing.T) { + tests := []struct { + name string + node string + want string + }{ + { + "Test encodeLegacyAddr", + "5ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6", + "3b3b57de5ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + node, _ := hex.DecodeString(tt.node) + want, _ := hex.DecodeString(tt.want) + if got := encodeLegacyAddr(node); !reflect.DeepEqual(got, want) { + t.Errorf("encodeLegacyAddr() = %v, want %v", hex.EncodeToString(got), tt.want) + } + }) + } +} + +func Test_encodeFunc(t *testing.T) { + tests := []struct { + name string + fn string + want string + }{ + { + "Test resolver", + "resolver(bytes32)", + "0178b8bf", + }, + { + "Test addr", + "addr(bytes32,uint256)", + "f1cb7e06", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + want, _ := hex.DecodeString(tt.want) + if got := encodeFunc(tt.fn); !reflect.DeepEqual(got, want) { + t.Errorf("encodeFunc() = %v, want %v", hex.EncodeToString(got), tt.want) + } + }) + } +} + +func Test_encodeCoinType(t *testing.T) { + tests := []struct { + name string + coin uint64 + want string + }{ + { + "Test Ethereum", + uint64(60), + "000000000000000000000000000000000000000000000000000000000000003c", + }, + { + "Test Bitcoin", + uint64(0), + "0000000000000000000000000000000000000000000000000000000000000000", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + want, _ := hex.DecodeString(tt.want) + if got := encodeCoinType(tt.coin); !reflect.DeepEqual(got, want) { + t.Errorf("encodeCoinType() = %v, want %v", hex.EncodeToString(got), tt.want) + } + }) + } +} + +func Test_decodeBytes(t *testing.T) { + tests := []struct { + name string + bytes string + want string + }{ + { + "Test decode bytes", + "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014c36edf48e21cf395b206352a1819de658fd7f988000000000000000000000000", + "c36edf48e21cf395b206352a1819de658fd7f988", + }, + { + "Test decode bytes 2", + "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000160014b3df10c6941f4a949f1183281844c3a210cba1e200000000000000000000", + "0014b3df10c6941f4a949f1183281844c3a210cba1e2", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bytes, _ := hex.DecodeString(tt.bytes) + want, _ := hex.DecodeString(tt.want) + if got := decodeBytes(bytes); !reflect.DeepEqual(got, want) { + t.Errorf("decodeBytes() = %v, want %v", hex.EncodeToString(got), tt.want) + } + }) + } +} diff --git a/platform/ethereum/model.go b/platform/ethereum/model.go index d8464d084..a315ee0ac 100644 --- a/platform/ethereum/model.go +++ b/platform/ethereum/model.go @@ -1,8 +1,9 @@ package ethereum import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "math/big" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) type Page struct { diff --git a/platform/ethereum/namehash.go b/platform/ethereum/namehash.go new file mode 100644 index 000000000..a9ef969f2 --- /dev/null +++ b/platform/ethereum/namehash.go @@ -0,0 +1,90 @@ +// Copyright 2017 Weald Technology Trading +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ethereum + +import ( + "strings" + + "golang.org/x/net/idna" + + "golang.org/x/crypto/sha3" +) + +var p = idna.New(idna.MapForLookup(), idna.StrictDomainName(false), idna.Transitional(false)) +var pStrict = idna.New(idna.MapForLookup(), idna.StrictDomainName(true), idna.Transitional(false)) + +// Normalize normalizes a name according to the ENS rules +func Normalize(input string) (output string, err error) { + output, err = p.ToUnicode(input) + if err != nil { + return + } + // If the name started with a period then ToUnicode() removes it, but we want to keep it + if strings.HasPrefix(input, ".") && !strings.HasPrefix(output, ".") { + output = "." + output + } + return +} + +// LabelHash generates a simple hash for a piece of a name. +func LabelHash(label string) (hash [32]byte, err error) { + normalizedLabel, err := Normalize(label) + if err != nil { + return + } + + sha := sha3.NewLegacyKeccak256() + if _, err = sha.Write([]byte(normalizedLabel)); err != nil { + return + } + sha.Sum(hash[:0]) + return +} + +// NameHash generates a hash from a name that can be used to +// look up the name in ENS +func NameHash(name string) (hash [32]byte, err error) { + if name == "" { + return + } + normalizedName, err := Normalize(name) + if err != nil { + return + } + parts := strings.Split(normalizedName, ".") + for i := len(parts) - 1; i >= 0; i-- { + if hash, err = nameHashPart(hash, parts[i]); err != nil { + return + } + } + return +} + +func nameHashPart(currentHash [32]byte, name string) (hash [32]byte, err error) { + sha := sha3.NewLegacyKeccak256() + if _, err = sha.Write(currentHash[:]); err != nil { + return + } + nameSha := sha3.NewLegacyKeccak256() + if _, err = nameSha.Write([]byte(name)); err != nil { + return + } + nameHash := nameSha.Sum(nil) + if _, err = sha.Write(nameHash); err != nil { + return + } + sha.Sum(hash[:0]) + return +} diff --git a/platform/ethereum/namehash_test.go b/platform/ethereum/namehash_test.go new file mode 100644 index 000000000..4a2ce916a --- /dev/null +++ b/platform/ethereum/namehash_test.go @@ -0,0 +1,90 @@ +// Copyright 2017 Weald Technology Trading +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ethereum + +import ( + "encoding/hex" + "testing" +) + +func TestNameHash(t *testing.T) { + tests := []struct { + input string + output string + err error + }{ + {"", "0000000000000000000000000000000000000000000000000000000000000000", nil}, + {"eth", "93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae", nil}, + {"Eth", "93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae", nil}, + {".eth", "8cc9f31a5e7af6381efc751d98d289e3f3589f1b6f19b9b989ace1788b939cf7", nil}, + {"resolver.eth", "fdd5d5de6dd63db72bbc2d487944ba13bf775b50a80805fe6fcaba9b0fba88f5", nil}, + {"foo.eth", "de9b09fd7c5f901e23a3f19fecc54828e9c848539801e86591bd9801b019f84f", nil}, + {"Foo.eth", "de9b09fd7c5f901e23a3f19fecc54828e9c848539801e86591bd9801b019f84f", nil}, + {"foo..eth", "4143a5b2f547838d3b49982e3f2ec6a26415274e5b9c3ffeb21971bbfdfaa052", nil}, + {"bar.foo.eth", "275ae88e7263cdce5ab6cf296cdd6253f5e385353fe39cfff2dd4a2b14551cf3", nil}, + {"Bar.foo.eth", "275ae88e7263cdce5ab6cf296cdd6253f5e385353fe39cfff2dd4a2b14551cf3", nil}, + {"addr.reverse", "91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2", nil}, + } + + for _, tt := range tests { + result, err := NameHash(tt.input) + if tt.err == nil { + if err != nil { + t.Fatalf("unexpected error %v", err) + } + if tt.output != hex.EncodeToString(result[:]) { + t.Errorf("Failure: %v => %v (expected %v)\n", tt.input, hex.EncodeToString(result[:]), tt.output) + } + } else { + if err == nil { + t.Fatalf("missing expected error") + } + if tt.err.Error() != err.Error() { + t.Errorf("unexpected error value %v", err) + } + } + } +} + +func TestLabelHash(t *testing.T) { + tests := []struct { + input string + output string + err error + }{ + {"", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", nil}, + {"eth", "4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0", nil}, + {"foo", "41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d", nil}, + } + + for _, tt := range tests { + output, err := LabelHash(tt.input) + if tt.err == nil { + if err != nil { + t.Fatalf("unexpected error %v", err) + } + if tt.output != hex.EncodeToString(output[:]) { + t.Errorf("Failure: %v => %v (expected %v)\n", tt.input, hex.EncodeToString(output[:]), tt.output) + } + } else { + if err == nil { + t.Fatalf("missing expected error") + } + if tt.err.Error() != err.Error() { + t.Errorf("unexpected error value %v", err) + } + } + } +} diff --git a/platform/fio/base.go b/platform/fio/base.go index 5f5641dca..0f4ba28dc 100644 --- a/platform/fio/base.go +++ b/platform/fio/base.go @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{blockatlas.InitJSONClient(api)}, } } diff --git a/platform/fio/client.go b/platform/fio/client.go index db12c9b5a..56a68c055 100644 --- a/platform/fio/client.go +++ b/platform/fio/client.go @@ -12,7 +12,6 @@ type Client struct { func (c *Client) lookupPubAddress(name string, coinSymbol string) (address string, error error) { var res GetPubAddressResponse - c.Headers["Content-Type"] = "application/json" err := c.Post(&res, "get_pub_address", GetPubAddressRequest{FioAddress: name, TokenCode: coinSymbol, ChainCode: coinSymbol}) if err != nil { return "", errors.E(err, "Error looking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": err.Error()}) diff --git a/platform/harmony/base.go b/platform/harmony/base.go index f9e8c813c..83b6ceb48 100644 --- a/platform/harmony/base.go +++ b/platform/harmony/base.go @@ -11,9 +11,8 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{blockatlas.InitJSONClient(api)}, } - p.client.Headers["Content-Type"] = "application/json" return p } diff --git a/platform/nano/base.go b/platform/nano/base.go index 8dfde34eb..ed413ca1d 100644 --- a/platform/nano/base.go +++ b/platform/nano/base.go @@ -11,9 +11,8 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{blockatlas.InitJSONClient(api)}, } - p.client.Headers["Content-Type"] = "application/json" return p } diff --git a/platform/solana/base.go b/platform/solana/base.go index f14ad7a45..88bf65bf7 100644 --- a/platform/solana/base.go +++ b/platform/solana/base.go @@ -11,9 +11,8 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{blockatlas.InitJSONClient(api)}, } - p.client.Headers["Content-Type"] = "application/json" return p } From 4053fd90ba09bd4a066ed95b5fead0fdb0958792 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Thu, 26 Mar 2020 17:11:41 +0100 Subject: [PATCH 210/506] Fix for 'make stop' (Makefile, observer pid). (#979) * Fix for 'make stop' (Makefile, observer pid). * Fix newman test at Makefile Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 95278e9c2..d8fbeef14 100644 --- a/Makefile +++ b/Makefile @@ -96,8 +96,8 @@ start-observer-subscriber: stop stop: @-touch $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) @-kill `cat $(PID_API)` 2> /dev/null || true - @-kill `cat $(OBSERVER_NOTIFIER)` 2> /dev/null || true - @-kill `cat $(OBSERVER_PARSER)` 2> /dev/null || true + @-kill `cat $(PID_OBSERVER_NOTIFIER)` 2> /dev/null || true + @-kill `cat $(PID_OBSERVER_PARSER)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER_SUBSCRIBER)` 2> /dev/null || true @-kill `cat $(PID_SWAGGER_API)` 2> /dev/null || true @-kill `cat $(PID_DYSON)` 2> /dev/null || true @@ -169,7 +169,7 @@ ifeq (,$(shell which newman)) endif ## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http//localhost -newman: install-newman start-platform-api +newman: install-newman ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host)" @bash -c "$(MAKE) newman-run test=token host=$(host)" From 6d09675639a1d2df6392c0510ca314e1181f0c64 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 28 Mar 2020 04:27:10 +0300 Subject: [PATCH 211/506] Fix issue with hardcoded token type for any eth like platform (#983) --- platform/ethereum/token.go | 23 +++++- platform/ethereum/token_test.go | 131 ++++++++++++++++++++++++++++---- 2 files changed, 138 insertions(+), 16 deletions(-) diff --git a/platform/ethereum/token.go b/platform/ethereum/token.go index 78b15f898..dbf88c192 100644 --- a/platform/ethereum/token.go +++ b/platform/ethereum/token.go @@ -1,6 +1,7 @@ package ethereum import ( + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -14,13 +15,33 @@ func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, // NormalizeToken converts a Ethereum token into the generic model func NormalizeToken(srcToken *Contract, coinIndex uint) (t blockatlas.Token, ok bool) { + var tokenType blockatlas.TokenType + switch coinIndex { + case coin.Ethereum().ID: + tokenType = blockatlas.TokenTypeERC20 + case coin.Classic().ID: + tokenType = blockatlas.TokenTypeETC20 + case coin.Poa().ID: + tokenType = blockatlas.TokenTypePOA20 + case coin.Callisto().ID: + tokenType = blockatlas.TokenTypeCLO20 + case coin.Wanchain().ID: + tokenType = blockatlas.TokenTypeWAN20 + case coin.Thundertoken().ID: + tokenType = blockatlas.TokenTypeTT20 + case coin.Gochain().ID: + tokenType = blockatlas.TokenTypeGO20 + default: + tokenType = "unknown" + } + t = blockatlas.Token{ Name: srcToken.Name, Symbol: srcToken.Symbol, TokenID: srcToken.Address, Coin: coinIndex, Decimals: srcToken.Decimals, - Type: blockatlas.TokenTypeERC20, + Type: tokenType, } return t, true diff --git a/platform/ethereum/token_test.go b/platform/ethereum/token_test.go index a2e9fdde6..ab7b88f8f 100644 --- a/platform/ethereum/token_test.go +++ b/platform/ethereum/token_test.go @@ -16,27 +16,128 @@ const tokenSrc = ` "symbol": "FUS" }` -var tokenDst = blockatlas.Token{ - Name: "FusChain", - Symbol: "FUS", - Decimals: 18, - TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - Coin: coin.ETH, - Type: blockatlas.TokenTypeERC20, -} - type testToken struct { name string apiResponse string expected *blockatlas.Token + coin int } func TestNormalizeToken(t *testing.T) { - testNormalizeToken(t, &testToken{ - name: "token", - apiResponse: tokenSrc, - expected: &tokenDst, - }) + var tests = []struct { + name string + tokenRaw string + coin int + want blockatlas.Token + }{ + { + "ethereum erc20", + tokenSrc, + coin.ETH, + blockatlas.Token{ + Name: "FusChain", + Symbol: "FUS", + Decimals: 18, + TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + Coin: coin.ETH, + Type: blockatlas.TokenTypeERC20, + }, + }, + {"classic etc20", + tokenSrc, + coin.ETC, + blockatlas.Token{ + Name: "FusChain", + Symbol: "FUS", + Decimals: 18, + TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + Coin: coin.ETC, + Type: blockatlas.TokenTypeETC20, + }, + }, + {"gochain go20", + tokenSrc, + coin.GO, + blockatlas.Token{ + Name: "FusChain", + Symbol: "FUS", + Decimals: 18, + TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + Coin: coin.GO, + Type: blockatlas.TokenTypeGO20, + }, + }, + {"thudertoken tt20", + tokenSrc, + coin.TT, + blockatlas.Token{ + Name: "FusChain", + Symbol: "FUS", + Decimals: 18, + TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + Coin: coin.TT, + Type: blockatlas.TokenTypeTT20, + }, + }, + {"wanchain wan20", + tokenSrc, + coin.WAN, + blockatlas.Token{ + Name: "FusChain", + Symbol: "FUS", + Decimals: 18, + TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + Coin: coin.WAN, + Type: blockatlas.TokenTypeWAN20, + }, + }, + {"poa poa20", + tokenSrc, + coin.POA, + blockatlas.Token{ + Name: "FusChain", + Symbol: "FUS", + Decimals: 18, + TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + Coin: coin.POA, + Type: blockatlas.TokenTypePOA20, + }, + }, + {"callisto clo20", + tokenSrc, + coin.CLO, + blockatlas.Token{ + Name: "FusChain", + Symbol: "FUS", + Decimals: 18, + TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + Coin: coin.CLO, + Type: blockatlas.TokenTypeCLO20, + }, + }, + {"unkown", + tokenSrc, + 1999, + blockatlas.Token{ + Name: "FusChain", + Symbol: "FUS", + Decimals: 18, + TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", + Coin: 1999, + Type: "unknown", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testNormalizeToken(t, &testToken{ + apiResponse: tt.tokenRaw, + expected: &tt.want, + coin: tt.coin, + }) + }) + } + } func testNormalizeToken(t *testing.T, _test *testToken) { @@ -46,7 +147,7 @@ func testNormalizeToken(t *testing.T, _test *testToken) { t.Error(err) return } - tk, ok := NormalizeToken(&token, coin.ETH) + tk, ok := NormalizeToken(&token, uint(_test.coin)) if !ok { t.Errorf("token: token could not be normalized") } From f8c1ccda45e86f69b16f10535978e45fb5b6fa60 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Sun, 29 Mar 2020 22:31:10 +0200 Subject: [PATCH 212/506] Mocked transaction history tests. (#971) * Base infra for mocked external services, mocked functional tests. New ENS lookup mock. New ETH RPC, lookup mock. Rename mocked->mock. Rearrange newman make targets, to run mocked newman tests. Complete mock for domain tests. Change for codacy false alarms. Change for codacy false alarms 2. Small change to Makefile: build bin before running app Makefile: start/stop dyson. Mocked harmony tx test. Mocked nano tx test. Update README.md [MQ & Cache] Add workers for restore connection (#964) Add NEAR coin definition (#965) Remove unused packages, refactor pkg, run fmt (#967) * Remove unused packages, refactor pkg, run fmt * Fix Makefile Extend postman transaction tests with verification of result txId. Mocked eth tx test. Mocked binance tx test. Small rename. Rename mock script files. Mock path adjustments, script renames. Mocked algorand tx test. Codacy pleasing? Codacy 2. Mocked viacoin tx tests. Remove request only_confirmed transactions (#969) Base infra for mocked external services, mocked functional tests. (#963) * Base infra for mocked external services, mocked functional tests. Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov Co-authored-by: Nick Kozlov Mocked zcash tx tests. Mocked Zilliqa tx tests. EthClassic mocked tx test. Poa mocked tx test. Callisto mocked tx test.Callisto mocked tx test. Adjustments to test data. Test data formatting. Rework TX test TxId check rules, for mocked and non-mocked case. Tomochain mocked tx test. Gochain mocked tx test. Thundertoken mocked tx test. Cosmos and Kava mocked tx tests. Theta mocked tx tests. Ripple mocked tx test. Aion mocked tx test. Tron mocked tx test. Iotex mocked tx test. Icon mocked tx test. Stellar mcked tx test. Nebulas mocked tx test. Aeternity mocked tx test. Kin mocked tx test. Ontology mocked tx test. Waves mocked tx test. Bitcoin mocked tx test. Cleanup configmock.yml. Formatting. Digibyte mocked tx test. doge mocked tx test. decred mocked tx test. Zelcash mocked tx test. Zcoin mocked tx test. Bitcoincash mocked tx test. parent 07d7f68440e1384a6fd7de33691fa52c11e24c2f author Catenocrypt 1585129309 +0100 committer Nick Kozlov 1585509791 +0300 Ravencoin mocked tx test. Litecoin mocked tx test. Qtum mocked tx test. Groestlcoin mocked tx test. Dash mocked tx test. Nimiq mocked tx test. Kusama mocked tx test. Vechain mocked tx test. Tezos mocked tx test. Finalize mocked tx tests, Makefile. Makefile: host param optional; codacy. Fix tfuel direction (#972) * Correct struct name * Add test * Adopt test to direction * Run go-fmt * Fix coins.go Add Initial Solana implementation (#962) * Initial Solana implementation * go fmt * Add public endpoint * Review comments * Update coin/coins.yml Co-Authored-By: hewig <360470+hewigovens@users.noreply.github.com> * Return empty tx list * Add content-type header Co-authored-by: Nick Kozlov Co-authored-by: hewig <360470+hewigovens@users.noreply.github.com> [Observer] Start rewriting observer service: separate service - add observer_parser and observer_notifier (#968) * [Observer] Start rewriting observer service: separate service - add observer_parser and observer_notifier * Continue refactoring, speed up some tests * Add unit tests for all functions that can be tested by unit tests * Add observer_notifier service * Continue refactoring the notifier * Remove unused package * Small cleanup * Test & build fixes * Continue refactoring * Fix Unit test * Run fmt and add storage test for lookup * Update miniredis, refactor FindSubscriptions, * Add storage tests * Update notifier and parser * Add Normal logs for parser * Add Normal logs for parser * Fix tests * Fix tests * Add notifier test * Add notifier test fix * Fix integration tests * [Observer parser] Add graceful shutdown * Setup concurrent publishing (not yet finished) * [Observer parser] Update FetchBlocks and PublishBlocks * [Errors & Parser] Update errors package and FetchBlocks/PublishBlocks * Change queue type to Txs * [Observer parser] Update PublishBlocks * Change queue type to Txs * Fix tests * [MQ & Obserer notifier & Observer subscriber] Add RunConsumerWithCancel, add graceful shutdown to observer notifier and subscriber * [Observer healthcheck] Setup observer healthcheck servcie * Add unit tests for all functions that can be tested by unit tests, change parser.go * Small refactoring * Small change to healthcheck.go * [Observer parser] Add getTxsBatches and test, add rand.Seed to getBlockByNumberWithRetry * Add storage test * [Storage] Update deleteSubscriptions and addSubscriptions * [Observer healthcheck] Add exclude param * Refactoring Parser, MQ, add tests * Add txs batch limit to config.yml * [Observer parser] Update graceful shutdown * Fix integration tests Co-authored-by: Nick Kozlov Co-authored-by: Nick Kozlov [Observer-TX] Fix issue with wrong transaction direction (#976) * [TX] Fix GetTransactionDirection * Add additional types checking for Memo * Add test Co-authored-by: Nick Kozlov Add transaction direction to eth transaction api (#977) remove go-ens / go-ethereum dependency (#973) * remove go-ens / go-ethereum dependency * Fix ens client * move to ens-coincodec * review comments * update fio client Merge master, use new InitJSONClient. Fix make stop (Makefile). Small fix for newman test Remove functional tests and change pipeline More fixes for the pipeline More fixes for the pipeline #2 Fix for 'make stop' (Makefile, observer pid). (#979) * Fix for 'make stop' (Makefile, observer pid). * Fix newman test at Makefile Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov More fixes for the pipeline #3 More fixes for the pipeline #5 More fixes for the pipeline #6 Small fixes of api to pass tests Fix issue with hardcoded token type for any eth like platform (#983) * Fix Waves api mock * Fix Waves api mock attempt 2 Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov --- Makefile | 46 +- azure-pipelines.yml | 17 +- configmock.yml | 99 +- mock/ext-api-dyson/dyson.json | 6 + .../get/aeternity-api-transactions.js | 61 + .../get/aion-get-getTransactionsByAddress.js | 76 + .../ext-api-dyson/get/algorand-api-account.js | 2 +- mock/ext-api-dyson/get/algorand-api-block.js | 2 +- mock/ext-api-dyson/get/binance-api-txs.js | 88 +- mock/ext-api-dyson/get/bitcoin-api-address.js | 132 ++ mock/ext-api-dyson/get/bitcoin-api-xpub.js | 168 ++ .../get/bitcoincash-api-address.js | 1621 +++++++++++++++++ .../ext-api-dyson/get/bitcoincash-api-xpub.js | 184 ++ .../get/callisto-api-transactions.js | 60 + mock/ext-api-dyson/get/cosmos-api-txs.js | 524 ++++++ mock/ext-api-dyson/get/dash-api-address.js | 177 ++ mock/ext-api-dyson/get/dash-api-xpub.js | 175 ++ mock/ext-api-dyson/get/decred-api-address.js | 136 ++ mock/ext-api-dyson/get/decred-api-xpub.js | 122 ++ .../ext-api-dyson/get/digibyte-api-address.js | 189 ++ mock/ext-api-dyson/get/digibyte-api-xpub.js | 123 ++ mock/ext-api-dyson/get/doge-api-address.js | 137 ++ mock/ext-api-dyson/get/doge-api-xpub.js | 126 ++ .../ext-api-dyson/get/eth-api-transactions.js | 47 +- .../get/ethclassic-api-transactions.js | 60 + .../get/gochain-api-transactions.js | 58 + .../get/groestlcoin-api-address.js | 139 ++ .../ext-api-dyson/get/groestlcoin-api-xpub.js | 157 ++ mock/ext-api-dyson/get/icon-api-actions.js | 73 + mock/ext-api-dyson/get/iotex-get-accounts.js | 71 + mock/ext-api-dyson/get/kava-api-txs.js | 279 +++ mock/ext-api-dyson/get/kin-api-accounts.js | 97 + .../ext-api-dyson/get/kin-api-transactions.js | 112 ++ .../ext-api-dyson/get/litecoin-api-address.js | 132 ++ mock/ext-api-dyson/get/litecoin-api-xpub.js | 166 ++ mock/ext-api-dyson/get/nebulas-api-tx.js | 133 ++ .../get/ontolotgy-api-v2-addresses.js | 124 ++ .../ext-api-dyson/get/poa-api-transactions.js | 113 ++ mock/ext-api-dyson/get/qtum-api-address.js | 178 ++ mock/ext-api-dyson/get/qtum-api-xpub.js | 164 ++ .../get/ravencoin-api-address.js | 139 ++ mock/ext-api-dyson/get/ravencoin-api-xpub.js | 176 ++ mock/ext-api-dyson/get/ripple-get-accounts.js | 205 +++ .../ext-api-dyson/get/stellar-api-accounts.js | 99 + .../get/stellar-api-transactions.js | 118 ++ .../get/tezos-api-transactions.js | 29 + mock/ext-api-dyson/get/theta-api-accounttx.js | 95 + .../get/thundertoken-api-transactions.js | 75 + .../get/tomochain-api-transactions.js | 58 + mock/ext-api-dyson/get/tron-get-accounts.js | 101 + .../ext-api-dyson/get/vechain-api-entities.js | 107 ++ mock/ext-api-dyson/get/viacoin-api-address.js | 107 ++ mock/ext-api-dyson/get/viacoin-api-xpub.js | 87 + .../get/waves-api-transactions-address.js | 61 + mock/ext-api-dyson/get/zcash-api-address.js | 173 ++ mock/ext-api-dyson/get/zcash-api-xpub.js | 126 ++ mock/ext-api-dyson/get/zcoin-api-address.js | 279 +++ mock/ext-api-dyson/get/zcoin-api-xpub.js | 422 +++++ mock/ext-api-dyson/get/zelcash-api-address.js | 243 +++ mock/ext-api-dyson/get/zelcash-api-xpub.js | 196 ++ .../get/zilliqa-api-addresses-txs.js | 49 + mock/ext-api-dyson/post/harmony-api.js | 66 +- mock/ext-api-dyson/post/kusama-api.js | 65 + mock/ext-api-dyson/post/nano-api.js | 40 - mock/ext-api-dyson/post/nimiq-rpc.js | 66 + mock/ext-api-dyson/post/vechain-api-logs.js | 51 + platform/nimiq/base.go | 2 +- platform/polkadot/base.go | 2 +- platform/vechain/base.go | 2 +- tests/functional/fixtures.go | 111 -- tests/functional/functional_test.go | 89 - tests/functional/http.go | 104 -- tests/functional/testdata/body_fixtures.json | 47 - tests/functional/testdata/coin_fixtures.json | 162 -- tests/functional/testdata/exclude.json | 45 - tests/functional/testdata/query_fixtures.json | 28 - .../Blockatlas.postman_collection.json | 32 +- tests/postman/transaction_data.json | 80 +- 78 files changed, 9526 insertions(+), 785 deletions(-) create mode 100644 mock/ext-api-dyson/dyson.json create mode 100644 mock/ext-api-dyson/get/aeternity-api-transactions.js create mode 100644 mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js create mode 100644 mock/ext-api-dyson/get/bitcoin-api-address.js create mode 100644 mock/ext-api-dyson/get/bitcoin-api-xpub.js create mode 100644 mock/ext-api-dyson/get/bitcoincash-api-address.js create mode 100644 mock/ext-api-dyson/get/bitcoincash-api-xpub.js create mode 100644 mock/ext-api-dyson/get/callisto-api-transactions.js create mode 100644 mock/ext-api-dyson/get/cosmos-api-txs.js create mode 100644 mock/ext-api-dyson/get/dash-api-address.js create mode 100644 mock/ext-api-dyson/get/dash-api-xpub.js create mode 100644 mock/ext-api-dyson/get/decred-api-address.js create mode 100644 mock/ext-api-dyson/get/decred-api-xpub.js create mode 100644 mock/ext-api-dyson/get/digibyte-api-address.js create mode 100644 mock/ext-api-dyson/get/digibyte-api-xpub.js create mode 100644 mock/ext-api-dyson/get/doge-api-address.js create mode 100644 mock/ext-api-dyson/get/doge-api-xpub.js create mode 100644 mock/ext-api-dyson/get/ethclassic-api-transactions.js create mode 100644 mock/ext-api-dyson/get/gochain-api-transactions.js create mode 100644 mock/ext-api-dyson/get/groestlcoin-api-address.js create mode 100644 mock/ext-api-dyson/get/groestlcoin-api-xpub.js create mode 100644 mock/ext-api-dyson/get/icon-api-actions.js create mode 100644 mock/ext-api-dyson/get/iotex-get-accounts.js create mode 100644 mock/ext-api-dyson/get/kava-api-txs.js create mode 100644 mock/ext-api-dyson/get/kin-api-accounts.js create mode 100644 mock/ext-api-dyson/get/kin-api-transactions.js create mode 100644 mock/ext-api-dyson/get/litecoin-api-address.js create mode 100644 mock/ext-api-dyson/get/litecoin-api-xpub.js create mode 100644 mock/ext-api-dyson/get/nebulas-api-tx.js create mode 100644 mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js create mode 100644 mock/ext-api-dyson/get/poa-api-transactions.js create mode 100644 mock/ext-api-dyson/get/qtum-api-address.js create mode 100644 mock/ext-api-dyson/get/qtum-api-xpub.js create mode 100644 mock/ext-api-dyson/get/ravencoin-api-address.js create mode 100644 mock/ext-api-dyson/get/ravencoin-api-xpub.js create mode 100644 mock/ext-api-dyson/get/ripple-get-accounts.js create mode 100644 mock/ext-api-dyson/get/stellar-api-accounts.js create mode 100644 mock/ext-api-dyson/get/stellar-api-transactions.js create mode 100644 mock/ext-api-dyson/get/tezos-api-transactions.js create mode 100644 mock/ext-api-dyson/get/theta-api-accounttx.js create mode 100644 mock/ext-api-dyson/get/thundertoken-api-transactions.js create mode 100644 mock/ext-api-dyson/get/tomochain-api-transactions.js create mode 100644 mock/ext-api-dyson/get/tron-get-accounts.js create mode 100644 mock/ext-api-dyson/get/vechain-api-entities.js create mode 100644 mock/ext-api-dyson/get/viacoin-api-address.js create mode 100644 mock/ext-api-dyson/get/viacoin-api-xpub.js create mode 100644 mock/ext-api-dyson/get/waves-api-transactions-address.js create mode 100644 mock/ext-api-dyson/get/zcash-api-address.js create mode 100644 mock/ext-api-dyson/get/zcash-api-xpub.js create mode 100644 mock/ext-api-dyson/get/zcoin-api-address.js create mode 100644 mock/ext-api-dyson/get/zcoin-api-xpub.js create mode 100644 mock/ext-api-dyson/get/zelcash-api-address.js create mode 100644 mock/ext-api-dyson/get/zelcash-api-xpub.js create mode 100644 mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js create mode 100644 mock/ext-api-dyson/post/kusama-api.js create mode 100644 mock/ext-api-dyson/post/nimiq-rpc.js create mode 100644 mock/ext-api-dyson/post/vechain-api-logs.js delete mode 100644 tests/functional/fixtures.go delete mode 100755 tests/functional/functional_test.go delete mode 100644 tests/functional/http.go delete mode 100644 tests/functional/testdata/body_fixtures.json delete mode 100644 tests/functional/testdata/coin_fixtures.json delete mode 100644 tests/functional/testdata/exclude.json delete mode 100644 tests/functional/testdata/query_fixtures.json diff --git a/Makefile b/Makefile index d8fbeef14..696a1ff82 100644 --- a/Makefile +++ b/Makefile @@ -94,16 +94,17 @@ start-observer-subscriber: stop ## stop: Stop development mode. stop: - @-touch $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) + @-touch $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) $(PID_DYSON) @-kill `cat $(PID_API)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER_NOTIFIER)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER_PARSER)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER_SUBSCRIBER)` 2> /dev/null || true @-kill `cat $(PID_SWAGGER_API)` 2> /dev/null || true @-kill `cat $(PID_DYSON)` 2> /dev/null || true - @-rm $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) + @-rm $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) $(PID_DYSON) stop-dyson: + @-touch $(PID_DYSON) @kill `cat $(PID_DYSON)` 2> /dev/null || true @rm $(PID_DYSON) @@ -126,9 +127,6 @@ clean: ## test: Run all unit tests. test: go-test -## functional: Run all functional tests. -functional: go-functional - ## integration: Run all integration tests. integration: go-integration @@ -165,24 +163,29 @@ docs: go-gen-docs install-newman: ifeq (,$(shell which newman)) @echo " > Installing Postman Newman" - @-npm install -g newman + @-sudo npm install -g newman endif -## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http//localhost -newman: install-newman +## newman-mocked: Run mocked Postman Newman tests. +newman-mocked: install-newman install-dyson go-compile + @bash -c "$(MAKE) newman-mocked-params host=http://localhost:8420" + +## newman-mocked-params: Run mocked Postman Newman tests, after starting platform api. +## The host parameter is required. +## E.g.: $ make newman-mocked-params test=domain host=http://localhost:8420 +newman-mocked-params: start-platform-api-mock ifeq (,$(test)) - @bash -c "$(MAKE) newman-run test=transaction host=$(host)" - @bash -c "$(MAKE) newman-run test=token host=$(host)" - @bash -c "$(MAKE) newman-run test=staking host=$(host)" - @bash -c "$(MAKE) newman-run test=collection host=$(host)" - @bash -c "$(MAKE) newman-run test=domain host=$(host)" - @bash -c "$(MAKE) newman-run test=healthcheck host=$(host)" + @bash -c "$(MAKE) newman-run test=transaction host=$(host) && \ + $(MAKE) newman-run test=domain host=$(host)" + #not-mocked-yet: $(MAKE) newman-run test=token host=$(host) && \ + #not-mocked-yet: $(MAKE) newman-run test=staking host=$(host) && \ + #not-mocked-yet: $(MAKE) newman-run test=collection host=$(host) && else @bash -c "$(MAKE) newman-run test=$(test) host=$(host)" endif -## newman-mocked: Run mocked Postman Newman tests, after starting platform api. See newman target. -newman-mocked: install-newman install-dyson go-compile start-platform-api-mock +## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http//localhost +newman: install-newman ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host)" @bash -c "$(MAKE) newman-run test=token host=$(host)" @@ -207,7 +210,7 @@ endif install-dyson: ifeq (,$(shell which dyson)) @echo " > Installing Dyson" - @-npm install -g dyson + @-sudo npm install -g dyson endif go-compile: go-get go-build @@ -243,15 +246,6 @@ go-test: @echo " > Running unit tests" GOBIN=$(GOBIN) go test -cover -race -v ./... -go-functional: - @echo " > Running functional tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=functional -v ./tests/functional - -## go-functional-mock: Run platform-api with mocks, and run functional tests -go-functional-mock: stop install-dyson start-mock-dyson start-platform-api-mock - @echo " > Running functional tests with mocks" - GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=functional -v ./tests/functional - go-integration: @echo " > Running integration tests" GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration ./tests/docker_test diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 983d963ec..3006f5c67 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -50,23 +50,14 @@ jobs: workingDirectory: '$(System.DefaultWorkingDirectory)' displayName: 'Run unit tests' - - job: functional_tests + - job: mocked_tests dependsOn: environment condition: succeeded() steps: - - script: | - go get github.com/gavv/httpexpect - make functional + - script: sudo make newman-mocked workingDirectory: '$(System.DefaultWorkingDirectory)' - condition: ne(variables['build.sourceBranch'], 'refs/heads/master') - continueOnError: true - displayName: "Run functional tests for new PR's" - - - script: | - make functional - workingDirectory: '$(System.DefaultWorkingDirectory)' - condition: eq(variables['build.sourceBranch'], 'refs/heads/master') - displayName: 'Run functional tests for new releases' + condition: succeeded() + displayName: "Run api tests for new PR's" - job: integration_tests dependsOn: environment diff --git a/configmock.yml b/configmock.yml index d6e3024cb..6796417d9 100644 --- a/configmock.yml +++ b/configmock.yml @@ -39,30 +39,29 @@ storage: # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org binance: - #mock api: https://explorer.binance.org/api/v1 api: http://localhost:3000/binance-api/v1 dex: https://dex.binance.org/api # [NIM] Nimiq: https://nimiq.com -#nimiq: -# api: http://localhost:8648 +nimiq: + api: http://localhost:3000/nimiq-rpc # [XRP] Ripple: https://ripple.com ripple: - api: https://data.ripple.com/v2 + api: http://localhost:3000/ripple-api # [XLM] Stellar Lumen: https://www.stellar.org stellar: - api: https://horizon.stellar.org + api: http://localhost:3000/stellar-api # [KIN] Kin: https://www.kin.org kin: - api: https://horizon-block-explorer.kininfrastructure.com + api: http://localhost:3000/kin-api # [XTZ] Tezos: https://tezos.com tezos: stake_api: https://api.tzstats.com/explorer - api: http://api.tezos.id/mooncake/mainnet + api: http://localhost:3000/tezos-api rpc: https://mainnet.tezos.org.ua # [ETH] Ethereum: https://ethereum.org (Trust-Ray API) @@ -73,147 +72,141 @@ ethereum: rpc: http://localhost:3000/eth-rpc # [ETC] Ethereum Classic: https://ethereumclassic.org (Trust-Ray API) -# classic: -# api: https://localhost:4567 +classic: + api: http://localhost:3000/ethclassic-api # [POA] POA Network: https://poa.network (Trust-Ray API) -# poa: -# api: https://localhost:4567 +poa: + api: http://localhost:3000/poa-api # [CLO] Callisto Network: https://callisto.network (Trust-Ray API) -# callisto: -# api: https://localhost:4567 +callisto: + api: http://localhost:3000/callisto-api # [GO] GoChain: https://gochain.io (Trust-Ray API) -# gochain: -# api: https://localhost:4567 +gochain: + api: http://localhost:3000/gochain-api # [WAN] Wanchain: https://wanchain.org (Trust-Ray API) # wanchain: # api: https://localhost:4567 # [TOMO] TomoChain: https://tomochain.com (Trust-Ray API) -# tomochain: -# api: https://localhost:4567 +tomochain: + api: http://localhost:3000/tomochain-api # [TT] ThunderCore: https://www.thundercore.com (Trust-Ray API) -# thundertoken: -# api: https://localhost:4567 +thundertoken: + api: http://localhost:3000/thundertoken-api # [AION] Aion: https://aion.network aion: - api: https://mainnet-api.theoan.com/aion/dashboard + api: http://localhost:3000/aion-api # [ICX] ICON: https://icon.foundation icon: - api: https://tracker.icon.foundation/v3 + api: http://localhost:3000/icon-api # [TRX] Tron: https://tron.network/ tron: - api: https://api.trongrid.io + api: http://localhost:3000/tron-api # [VET] VeChain: https://www.vechain.org vechain: - api: https://vethor-pubnode.digonchain.com + api: http://localhost:3000/vechain-api # [THETA] THETA: https://www.thetatoken.org/ theta: - api: https://explorer.thetatoken.org:9000/api + api: http://localhost:3000/theta-api # [ATOM] Cosmos: https://cosmos.network/ cosmos: - api: https://api.cosmos.network + api: http://localhost:3000/cosmos-api # [ONTOLOGY] ONT: https://ont.io/ ontology: - api: https://explorer.ont.io + api: http://localhost:3000/ontology-api # [ZIL] Zilliqa: https://zilliqa.com zilliqa: - api: https://api.viewblock.io/v1/zilliqa + api: http://localhost:3000/zilliqa-api # key: YOUR_API_KEY rpc: https://api.zilliqa.com - #mock lookup: https://unstoppabledomains.com/api/v1 lookup: http://localhost:3000/unstoppabledomains/api/v1 #[IoTeX] IoTeX: https://iotex.io iotex: - api: https://pharos.iotex.io/v1 + api: http://localhost:3000/iotex-api # [WAVES] Waves: http://wavesplatform.com waves: - api: https://nodes.wavesnodes.com + api: http://localhost:3000/waves-api # [AE] Aeternity: https://aeternity.com aeternity: - api: https://mdw.aepps.com + api: http://localhost:3000/aeternity-api # [NAS] Nebulas: https://nebulas.io nebulas: - api: https://explorer-backend.nebulas.io/api + api: http://localhost:3000/nebulas-api fio: - # api: https://addresses.fio.foundation - #mock api: http://testnet.fioprotocol.io/v1/chain api: http://localhost:3000/fio-api/v1/chain # [BTC] Bitcoin: https://bitcoin.org/ (Blockbook API https://github.com/trezor/blockbook) bitcoin: - api: https://btc1.trezor.io/api + api: http://localhost:3000/bitcoin-api litecoin: - api: https://ltc1.trezor.io/api + api: http://localhost:3000/litecoin-api bitcoincash: - api: https://bch1.trezor.io/api + api: http://localhost:3000/bitcoincash-api doge: - api: https://doge1.trezor.io/api + api: http://localhost:3000/doge-api dash: - api: https://dash1.trezor.io/api + api: http://localhost:3000/dash-api zcoin: - api: https://blockbook.zcoin.io/api + api: http://localhost:3000/zcoin-api zcash: - api: https://zec1.trezor.io/api + api: http://localhost:3000/zcash-api zelcash: - api: https://blockbook.zel.network/api + api: http://localhost:3000/zelcash-api viacoin: - api: https://blockbook.viacoin.org/api + api: http://localhost:3000/viacoin-api qtum: - api: https://blockv3.qtum.info/api + api: http://localhost:3000/qtum-api groestlcoin: - api: https://blockbook.groestlcoin.org/api + api: http://localhost:3000/groestlcoin-api ravencoin: - api: https://blockbook.ravencoin.org/api + api: http://localhost:3000/ravencoin-api decred: - api: https://blockbook.decred.org:9161/api + api: http://localhost:3000/decred-api algorand: - #mock api: https://mainnet-algorand.api.purestake.io/ps1 api: http://localhost:3000/algorand-api nano: - #mock api: https://nanoverse.io/api/node api: http://localhost:3000/nano-api digibyte: - api: https://dgb1.trezor.io/api + api: http://localhost:3000/digibyte-api harmony: - #mock api: https://api.s0.t.hmny.io api: http://localhost:3000/harmony-api kava: - api: https://data.kava.io + api: http://localhost:3000/kava-api kusama: - api: https://kusama.subscan.io/api + api: http://localhost:3000/kusama-rpc diff --git a/mock/ext-api-dyson/dyson.json b/mock/ext-api-dyson/dyson.json new file mode 100644 index 000000000..a6b63fe8a --- /dev/null +++ b/mock/ext-api-dyson/dyson.json @@ -0,0 +1,6 @@ +{ + "port": 3000, + "proxy": false, + "multiRequest": "+", + "quiet": false +} diff --git a/mock/ext-api-dyson/get/aeternity-api-transactions.js b/mock/ext-api-dyson/get/aeternity-api-transactions.js new file mode 100644 index 000000000..30dd4c219 --- /dev/null +++ b/mock/ext-api-dyson/get/aeternity-api-transactions.js @@ -0,0 +1,61 @@ +/// Aeternity API Mock +/// See: +/// curl "http://localhost:3000/aeternity-api/middleware/transactions/account/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb?" +/// curl "https://mdw.aepps.com/middleware/transactions/account/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb?" +/// curl http://localhost:8420/v1/aeternity/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb +module.exports = { + path: "/aeternity-api/middleware/transactions/:type/:address?", + template: function(params, query, body) { + //console.log(query) + if (params.type === 'account') { + if (params.address === 'ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb') { + return JSON.parse(` + [ + { + "block_hash": "mh_2V2PJ732cTfDqD4CaWr6W1s1fN531PqiVydMiy7gooccQFoGvM", + "block_height": 222994, + "hash": "th_WfeoRYXd13MMmDBzMXjBBdaNSSaRXkwUwJ7tFxJ7ZKPQVNXC4", + "signatures": [ + "sg_MLBxuqnHUD21i747SKnQuyNh1LzLuH7RDHqY1mngZyJMDWL9LFcuMbKdo2XMbwkMmskFsgfsZZBwgyA5w4Xs3ghynF2AF" + ], + "time": 1583633007081, + "tx": { + "amount": 1.99979979992e21, + "fee": 16840000000000, + "nonce": 3, + "payload": "ba_Xfbg4g==", + "recipient_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "sender_id": "ak_26dGJ7S5ba7LhUXPo8vMPe4QuNaQbskWnM5jkopPuim3PGny9Y", + "type": "SpendTx", + "version": 1 + } + }, + { + "block_hash": "mh_Z1a6HSs9vE5XDf8JtSiQMN5UpX49Spgnf9Sn32TiXxKwSbsP6", + "block_height": 186035, + "hash": "th_2wGEGmqwRMPYdv3vz1EE7ueJEveMTzEWzosgUH9ytERjGMv3rX", + "signatures": [ + "sg_66c2LXv4rvYnn4r2fZ4H1wxieDUuVEUF6fLCB3M13MjB9QNfEH4q9YThUWJCo5WzWKxzqjb3RbumhXdUZh8YDq3v8KZ2M" + ], + "time": 1576946253731, + "tx": { + "amount": 1.00079975e21, + "fee": 50000000000000, + "nonce": 3, + "payload": "ba_Xfbg4g==", + "recipient_id": "ak_26dGJ7S5ba7LhUXPo8vMPe4QuNaQbskWnM5jkopPuim3PGny9Y", + "sender_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "ttl": 186135, + "type": "SpendTx", + "version": 1 + } + } + ] + `); + } + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js b/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js new file mode 100644 index 000000000..1c44b14fa --- /dev/null +++ b/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js @@ -0,0 +1,76 @@ +/// Aion API Mock +/// See: +/// curl "http://localhost:3000/aion-api/getTransactionsByAddress?accountAddress=0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed&size=25" +/// curl "https://mainnet-api.theoan.com/aion/dashboard/getTransactionsByAddress?accountAddress=0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed&size=25" +/// curl http://localhost:8420/v1/aion/0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed +module.exports = { + path: "/aion-api/getTransactionsByAddress?", + template: function(params, query, body) { + //console.log(query) + if (query.accountAddress === '0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed') { + return JSON.parse(` + { + "page": { + "number": 0, + "size": 25, + "totalPages": 1, + "start": 1582532306, + "end": 1585037906, + "totalElements": 2 + }, + "content": [ + { + "blockHash": "f9aab3a58f9211d9d37458d8a87e49f2e00d1d242390d4650cd4092897650797", + "nrgPrice": 10000000000, + "toAddr": "a0c00cfc4c53bb6d49f385b91f58a23dd7b1dc024976b391bb8b81eb9e8801ab", + "contractAddr": "", + "data": "", + "year": 2020, + "internalTransactionCount": 0, + "transactionIndex": 0, + "type": "DEFAULT", + "nonce": "1e2f", + "transactionHash": "511d3a4aafbdd26825a1655b5c7525df5bea8a8ef0f887d5490b490055b53df7", + "transactionTimestamp": 1584349754, + "nrgConsumed": 21000, + "month": 3, + "blockNumber": 5619712, + "blockTimestamp": 1584349754, + "transactionLog": "[]", + "fromAddr": "a04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed", + "day": 16, + "value": "1.002217611212000000000000000000000000", + "txError": "" + }, + { + "blockHash": "ed8d3d92da7228c35c363f55383c602b6f5041b37ff165231245cfa83b863ae7", + "nrgPrice": 10000000000, + "toAddr": "a04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed", + "contractAddr": "", + "data": "", + "year": 2020, + "internalTransactionCount": 0, + "transactionIndex": 2, + "type": "DEFAULT", + "nonce": "2b2e55", + "transactionHash": "84789693b108bc3c437f8dccbd517682f611036d54621ec1f4db26f661fde468", + "transactionTimestamp": 1584349550, + "nrgConsumed": 21000, + "month": 3, + "blockNumber": 5619690, + "blockTimestamp": 1584349550, + "transactionLog": "[]", + "fromAddr": "a00983f07c11ee9160a64dd3ba3dc3d1f88332a2869f25725f56cbd0be32ef7a", + "day": 16, + "value": "1.002427611212000000000000000000000000", + "txError": "" + } + ] + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/algorand-api-account.js b/mock/ext-api-dyson/get/algorand-api-account.js index 977f3a83f..c450b711c 100644 --- a/mock/ext-api-dyson/get/algorand-api-account.js +++ b/mock/ext-api-dyson/get/algorand-api-account.js @@ -1,6 +1,6 @@ /// Mock for external Algorand API /// curl "http://localhost:3000/algorand-api/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions?" -/// curl "https://algorand-rpc.trustwalletapp.com/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions?" +/// curl "http://{algorand rpc}/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions?" /// curl http://localhost:8420/v1/algorand/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U module.exports = { diff --git a/mock/ext-api-dyson/get/algorand-api-block.js b/mock/ext-api-dyson/get/algorand-api-block.js index 27768e026..c6ff6f80d 100644 --- a/mock/ext-api-dyson/get/algorand-api-block.js +++ b/mock/ext-api-dyson/get/algorand-api-block.js @@ -1,6 +1,6 @@ /// Mock for external Algorand API /// curl "http://localhost:3000/algorand-api/v1/block/5478346?" -/// curl "https://algorand-rpc.trustwalletapp.com/v1/block/5478346?" +/// curl "http://{algorand rpc}/v1/block/5478346?" /// curl http://localhost:8420/v1/algorand/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U module.exports = { diff --git a/mock/ext-api-dyson/get/binance-api-txs.js b/mock/ext-api-dyson/get/binance-api-txs.js index 4dc1615a9..fafcd41b6 100644 --- a/mock/ext-api-dyson/get/binance-api-txs.js +++ b/mock/ext-api-dyson/get/binance-api-txs.js @@ -16,46 +16,68 @@ module.exports = { //console.log('address', address); switch (address) { case 'bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp': - return { - txNums: 2, - txArray: [ + return JSON.parse(`{ + "txNums": 2, + "txArray": [ { - txHash: "4A5E688755E3588B89C5F0325274430AA52786E527313739C542BC69436E18F4", - blockHeight: Number.parseFrom('63282272'), - txType: "TRANSFER", - timeStamp: Number.parseFrom('1579689046296'), - fromAddr: "bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp", - toAddr: "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - value: 0.5541546, - txAsset: "BNB", - txFee: Number.parseFrom('0.000375'), - txAge: 2351199, - code: 0, - log: "Msg 0: ", - confirmBlocks: 0, - memo: "102101832", - source: 0, - hasChildren: 0 + "txHash": "4A5E688755E3588B89C5F0325274430AA52786E527313739C542BC69436E18F4", + "blockHeight": 63282272, + "txType": "TRANSFER", + "timeStamp": 1579689046296, + "fromAddr": "bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": 0.55415460, + "txAsset": "BNB", + "txFee": 0.00037500, + "txAge": 5273327, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 0, + "memo": "102101832", + "source": 0, + "hasChildren": 0 }, { - txHash: "F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC", - blockHeight: Number.parseFrom('63280715'), - txType: "TRANSFER", - timeStamp: Number.parseFrom('1579688431580'), - txFee: Number.parseFrom('0.00060'), - txAge: 2351814, - code: 0, - log: "Msg 0: ", - confirmBlocks: 0, - memo: "Trust Wallet Redeem", - source: 0, - hasChildren: 1 + "txHash": "F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC", + "blockHeight": 63280715, + "txType": "TRANSFER", + "timeStamp": 1579688431580, + "txFee": 0.00060000, + "txAge": 5273941, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 0, + "memo": "Trust Wallet Redeem", + "source": 0, + "hasChildren": 1 } ] - }; + }`); case 'bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd': - return JSON.parse('{"txNums":1,"txArray":[{"txHash":"DDA939C475755B2A00123CDA37A5EC442F502EA2983014D04F647C3CB9FB57A0","blockHeight":75110907,"txType":"TRANSFER","timeStamp":1584450870939,"fromAddr":"bnb166fvwtfra2atta5mm8mygt2fyltktqctgpedcg","toAddr":"bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd","value":0.00037500,"txAsset":"BNB","txFee":0.00037500,"txAge":10170,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0}]}'); + return JSON.parse(`{ + "txNums": 1, + "txArray": [ + { + "txHash": "DDA939C475755B2A00123CDA37A5EC442F502EA2983014D04F647C3CB9FB57A0", + "blockHeight": 75110907, + "txType": "TRANSFER", + "timeStamp": 1584450870939, + "fromAddr": "bnb166fvwtfra2atta5mm8mygt2fyltktqctgpedcg", + "toAddr": "bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd", + "value": 0.00037500, + "txAsset": "BNB", + "txFee": 0.00037500, + "txAge": 10170, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "hasChildren": 0 + } + ] + }`); } // not found, address diff --git a/mock/ext-api-dyson/get/bitcoin-api-address.js b/mock/ext-api-dyson/get/bitcoin-api-address.js new file mode 100644 index 000000000..26fbe54c3 --- /dev/null +++ b/mock/ext-api-dyson/get/bitcoin-api-address.js @@ -0,0 +1,132 @@ +/// Mock for external Bitcoin API +/// See: +/// curl "http://localhost:3000/bitcoin-api/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" +/// curl "https://btc1.trezor.io/api/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" +/// curl "http://localhost:8420/v1/bitcoin/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + +module.exports = { + path: '/bitcoin-api/address/:address?', + template: function (params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "addrStr": "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj", + "balance": "0.00020074", + "totalReceived": "0.00091089", + "totalSent": "0.00071015", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 2, + "txs": [ + { + "txid": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4", + "version": 1, + "vin": [ + { + "txid": "270a6490cc806d99aa84bb8079b543d9d7a255fc59364890e7a4cb57970daef8", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "scriptSig": {}, + "addresses": [ + "bc1q3230a7cqt2drewuza8qff4c4gpt4muy9qyqknw" + ], + "value": "0.00001699" + } + ], + "vout": [ + { + "value": "0.00000375", + "n": 0, + "scriptPubKey": { + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ] + }, + "spent": false + }, + { + "value": "0.00001098", + "n": 1, + "scriptPubKey": { + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ] + }, + "spent": false + } + ], + "blockhash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", + "blockheight": 622017, + "confirmations": 780, + "time": 1584485709, + "blocktime": 1584485709, + "valueOut": "0.00001473", + "valueIn": "0.00001699", + "fees": "0.00000226", + "hex": "01000000000101f8ae0d9757cba4e790483659fc55a2d7d943b57980bb84aa996d80cc90640a270100000000feffffff0277010000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a4a040000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220683d9c2b40958fd706623783017300ebbc9b73ce1db571963d9bb40679c3079c02207ee68976e225e1e98d20e66d4d8a498cddf3268d0d7b66827a2ed3ac4330f137012102b7f0cb54c2a6a4da3372fe17d7a07475f575777364633e89dacb39eb1fd5a09c00000000" + }, + { + "txid": "c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be", + "version": 1, + "vin": [ + { + "txid": "d39d78838d5a3c870aa5acdc9e518945bd6ad86af093b38f85c714f790f28c76", + "vout": 1, + "n": 0, + "scriptSig": {}, + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "value": "0.00006055" + } + ], + "vout": [ + { + "value": "0.00001", + "n": 0, + "scriptPubKey": { + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ] + }, + "spent": false + }, + { + "value": "0.00004829", + "n": 1, + "scriptPubKey": { + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ] + }, + "spent": false + } + ], + "blockhash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", + "blockheight": 622017, + "confirmations": 780, + "time": 1584485709, + "blocktime": 1584485709, + "valueOut": "0.00005829", + "valueIn": "0.00006055", + "fees": "0.00000226", + "hex": "01000000000101768cf290f714c7858fb393f06ad86abd4589519edcaca50a873c5a8d83789dd301000000000000000002e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169add120000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a02483045022100cb25ac0d9e69ddaaedd49e3a3f9efb218b38bf49c2abf44ff2266bfb941bd3b202206b32cc1337f9a6a176fabadd6aefdf5a95d479e5db856d4e3e8eee7fefc26773012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" + } + ] + } + `); + } + return { error: "Not implemented" }; + } +} diff --git a/mock/ext-api-dyson/get/bitcoin-api-xpub.js b/mock/ext-api-dyson/get/bitcoin-api-xpub.js new file mode 100644 index 000000000..d1bf669da --- /dev/null +++ b/mock/ext-api-dyson/get/bitcoin-api-xpub.js @@ -0,0 +1,168 @@ +/// Mock for external Bitcoin API +/// See: +/// curl "https://btc1.trezor.io/api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs" +/// curl "http://localhost:3000/bitcoin-api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs" +/// curl "http://localhost:8420/v1/bitcoin/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC" + +module.exports = { + path: '/bitcoin-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", + "balance": "37093", + "totalReceived": "4218808", + "totalSent": "4181715", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 92, + "transactions": [ + { + "txid": "c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be", + "version": 1, + "vin": [ + { + "txid": "d39d78838d5a3c870aa5acdc9e518945bd6ad86af093b38f85c714f790f28c76", + "vout": 1, + "n": 0, + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true, + "value": "6055" + } + ], + "vout": [ + { + "value": "1000", + "n": 0, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "4829", + "n": 1, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", + "blockHeight": 622017, + "confirmations": 780, + "blockTime": 1584485709, + "value": "5829", + "valueIn": "6055", + "fees": "226", + "hex": "01000000000101768cf290f714c7858fb393f06ad86abd4589519edcaca50a873c5a8d83789dd301000000000000000002e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169add120000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a02483045022100cb25ac0d9e69ddaaedd49e3a3f9efb218b38bf49c2abf44ff2266bfb941bd3b202206b32cc1337f9a6a176fabadd6aefdf5a95d479e5db856d4e3e8eee7fefc26773012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" + }, + { + "txid": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4", + "version": 1, + "vin": [ + { + "txid": "270a6490cc806d99aa84bb8079b543d9d7a255fc59364890e7a4cb57970daef8", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "bc1q3230a7cqt2drewuza8qff4c4gpt4muy9qyqknw" + ], + "isAddress": true, + "value": "1699" + } + ], + "vout": [ + { + "value": "375", + "n": 0, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "1098", + "n": 1, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", + "blockHeight": 622017, + "confirmations": 780, + "blockTime": 1584485709, + "value": "1473", + "valueIn": "1699", + "fees": "226", + "hex": "01000000000101f8ae0d9757cba4e790483659fc55a2d7d943b57980bb84aa996d80cc90640a270100000000feffffff0277010000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a4a040000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220683d9c2b40958fd706623783017300ebbc9b73ce1db571963d9bb40679c3079c02207ee68976e225e1e98d20e66d4d8a498cddf3268d0d7b66827a2ed3ac4330f137012102b7f0cb54c2a6a4da3372fe17d7a07475f575777364633e89dacb39eb1fd5a09c00000000" + }, + { + "txid": "d39d78838d5a3c870aa5acdc9e518945bd6ad86af093b38f85c714f790f28c76", + "version": 1, + "vin": [ + { + "txid": "c215e9c6f9533d584effc4d31d08736a0ef4f717b7d42563ebba053f5f3bc1d5", + "vout": 1, + "sequence": 4294967287, + "n": 0, + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true, + "value": "8185" + } + ], + "vout": [ + { + "value": "1000", + "n": 0, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "6055", + "n": 1, + "spent": true, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000000ab8b2230f5b63d4d4be1a0aa6b9296cfc09e48c8e42e0", + "blockHeight": 619385, + "confirmations": 3412, + "blockTime": 1582902175, + "value": "7055", + "valueIn": "8185", + "fees": "1130", + "hex": "01000000000101d5c13b5f3f05baeb6325d4b717f7f40e6a73081dd3c4ff4e583d53f9c6e915c20100000000f7ffffff02e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169aa7170000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220158b0d8c5fb6cb9f60d0af05ce8b63abe934dca8eca380013bc7e8463420810f02207d7e6594586ec8196546e2520b6775c2e8659c8f266acb3b861e99f13cf1b380012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/bitcoincash-api-address.js b/mock/ext-api-dyson/get/bitcoincash-api-address.js new file mode 100644 index 000000000..1b096b621 --- /dev/null +++ b/mock/ext-api-dyson/get/bitcoincash-api-address.js @@ -0,0 +1,1621 @@ +/// Mock for external Bitcoincash API +/// See: +/// curl "http://{bch rpc}/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" +/// curl "http://localhost:3000/bitcoincash-api/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" +/// curl "http://localhost:8420/v1/bitcoincash/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + +module.exports = { + path: '/bitcoincash-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme': + return JSON.parse(` + { + "page": 1, + "totalPages": 11, + "itemsOnPage": 1000, + "addrStr": "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme", + "balance": "0", + "totalReceived": "125028.30507987", + "totalSent": "125028.30507987", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 10067, + "txs": [ + { + "txid": "0284cb9b8deb0534efa8fc8911db1e8f9b106d00608c712d31c3680f303fbf36", + "version": 2, + "locktime": 611622, + "vin": [ + { + "txid": "2f150ee63214982edbaf23c85629e920e16093d0506ed284ec3018ebe8746b12", + "vout": 0, + "sequence": 4294967294, + "n": 0, + "scriptSig": { + "hex": "47304402206f992d73dfa7e518b00190f220ad5dc7b7947b1d75a2fcd8251b59f3d29d89af022036c6c44f52f9aeed406dec72a9aab1f82c3b997c36742f4a3504e4f93e6f8557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50119473" + }, + { + "txid": "550ba873216e6690c8ca34992da41ecaa29e74a557943af604537de13fb84838", + "vout": 0, + "sequence": 4294967294, + "n": 1, + "scriptSig": { + "hex": "483045022100db30ebe47536e42115a507f88bb8d5c97b81ad05ce334872235811134c5948bb0220418d77aed78cc4a332b1858c1d2e9ab169828b9c12e8c0d0f8d155964e5d0b8e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50052374" + }, + { + "txid": "ed8d8d9810ca30cd0512a0e0ca87649713a550a015bb0022c16686c2ccb22143", + "vout": 0, + "sequence": 4294967294, + "n": 2, + "scriptSig": { + "hex": "483045022100d30c9fd598613586d8d0460fb6c9ffc1d0c6dff6f647535d2a9f69cf373193d102207fff687aa035910db124adad8b59607a72b3d24aca9096217ec6b90fa132a2ae412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50058021" + }, + { + "txid": "a2d79bacd53918c9ad6b27055eff555130f1af8522f77a09c4d74321dad8a032", + "vout": 0, + "sequence": 4294967294, + "n": 3, + "scriptSig": { + "hex": "47304402207b30e99cb1f6754d227a4511c5b7791f3b896724b170716d6ed238017f191bb102202c1fadc4c572c86288b002a0d6b6d2460a14a6d3c8b49efc17a03e59d2db18e3412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50022804" + }, + { + "txid": "9a0679dc735b7774ab3aa55a01188ce4d70613927b1b0ca9f96784b09479f762", + "vout": 1, + "sequence": 4294967294, + "n": 4, + "scriptSig": { + "hex": "48304502210092b7f176f182936323df8e4359b2a329b0c1e4b48a529d6e32867038a2a453cc02203c24a8bb46b7fea4ef5c78ff116a51fd0a04dee25bfcdffe856fb8988a7a97f64121035b4e75dda9fb0d55d856f54f24fc65da6657939b9559ab2c623c8ef325f14d8d" + }, + "addresses": [ + "bitcoincash:qzqn6xdqhaqa8yykvq4e94td4yg0k9ll9vyjf47x0f" + ], + "value": "0.01620505" + }, + { + "txid": "5d557c0c3331dc1dc4db34776603c01ce24ac8b0adf1f6fc2cc07a88baf5bf5c", + "vout": 0, + "sequence": 4294967294, + "n": 5, + "scriptSig": { + "hex": "47304402202a2bcfdaf12c398ed5372e6b168a786edb8972df1146b705d3cccf2d9601517d022020b90ac89d9141d68817850d1cdffaf6c51f45249a44fd6861b361a6025d8ac4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50096547" + }, + { + "txid": "61dbe706b513c1ee5aa577a07782471cf5c0c13fd7ce31b29cdd1c2362ea0bca", + "vout": 0, + "sequence": 4294967294, + "n": 6, + "scriptSig": { + "hex": "48304502210087ef2709b9fe8e7f136219254229edd45e94c3f6ebd2bb149aadd9b1d44d89e202206ffde3c9491c012832967e4d34e02ece2c08bc4c07967b3b466d4800f9ca0746412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50179897" + }, + { + "txid": "54b28d128142bb03aa60e9cf535fe30d5916089f1e70ac94444572008e9b3b84", + "vout": 0, + "sequence": 4294967294, + "n": 7, + "scriptSig": { + "hex": "483045022100c7dbd1117c57eedc8fc006e818371bfe6399c4d25e8b40482c1f0858a3d98a4b0220426d1196513a87fc7afb5b107b770a90af789536799a11686eab96b04afa6326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50044246" + }, + { + "txid": "750c2e638eb26bd271586fe201f48e21ef7fcef1154a6b6335d2bd4381450123", + "vout": 0, + "sequence": 4294967294, + "n": 8, + "scriptSig": { + "hex": "47304402203604fbb20824443899030d2c1f5cd0dc2b88174929861a708bdca878868e910c02200a607b1da53483bc95d3a5c54e5ad66e459827d4ecf8b4ef9909e9d58b2d329b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.5240491" + }, + { + "txid": "9b6dc387b59e4af25bfa14067e24c399fae3fbb744e97edb670087265ebcecf9", + "vout": 0, + "sequence": 4294967294, + "n": 9, + "scriptSig": { + "hex": "4730440220399c36174173cca01f6d6a234a935d6f776b549e1ea2fc2635193924c4ac2eb002205aea7741fafd95f862588c480aaa282d7a344d32d6318aec1a908cbb939e5d0e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.56320052" + }, + { + "txid": "8f27da29f81ae3ac3ab90f29cd4988d718cd351f965892b073a80b9a9492f49e", + "vout": 1, + "sequence": 4294967294, + "n": 10, + "scriptSig": { + "hex": "483045022100da9075310e7af59456423be99362f2cc686d50571e0f0b016bcfae1f0bc4692802203379b648d47704dba48542b8b6d5e515bf3c4fd7ff8a7be82cd0c8c0c7be56f7412103a344a84dc1a919a64874605fae200861b7af3ecd02dc5d52dd00eb6f8845525a" + }, + "addresses": [ + "bitcoincash:qz8mkaldpk8zk2ge27wpn8ue0uwu28xq5552u5c5my" + ], + "value": "0.01687043" + }, + { + "txid": "109bf48f720a9d05fd7a74b632164ed96db721b00458420595d799b437305f5c", + "vout": 0, + "sequence": 4294967294, + "n": 11, + "scriptSig": { + "hex": "47304402206cbf93634d6a477a571fa2884c19918b19ddfb008ff9fe405954720047efdb88022003e755313436d406dddfe3cfb68719e8f39e43de7c586489cc543dac0347da9f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.51895732" + }, + { + "txid": "d3e570366f647db1f73079b743ec994169875c7af42ff2e9f3cf290fcb3f180b", + "vout": 0, + "sequence": 4294967294, + "n": 12, + "scriptSig": { + "hex": "483045022100f23d4cf11fd0a5ab83dc053ca64066cbdd2fb4107e0977a3a880c68a67636f7d0220220a47c66d3944cfc309c059fe8013c4de742e4d8590003fd56c5e0b3c7da557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50081823" + }, + { + "txid": "6f05f99a402127463db6dc2f8f6b1064109fbfb93bacb258babd2aa861055480", + "vout": 0, + "sequence": 4294967294, + "n": 13, + "scriptSig": { + "hex": "4830450221009f522beef55cbf8c7f10e88739846f78ef1c9d9cbc6959dba6f687a08fec0ef502203a160231733b87c6cfd8afd148994c9b6c5d5db9bb9847aa9e60938a6e79d5b1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50020672" + }, + { + "txid": "3d93b717b0676245a3dc3fb86625d9abffac4f66e2889a81a07733a14e1e4a4a", + "vout": 0, + "sequence": 4294967294, + "n": 14, + "scriptSig": { + "hex": "47304402201f5d29be80192a752fe28ff141ed702640df88083faf3f9573e52405cb4bd79a02202d751649aa600c4fdb8b1d1b21f0d134c2f4e5af9ecbe7d87180d667140f0a11412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50118486" + }, + { + "txid": "c77ac92e646677bf9e59873c5f5036831d5d5597cda469b7e6b30a9563a3419b", + "vout": 0, + "sequence": 4294967294, + "n": 15, + "scriptSig": { + "hex": "47304402203f4bea3816d252cb19d4247f587a146901c74d04e783efddfd5089942f2abcdb022069012613c4ee4b3b0212ae71dbd2071e01665148697011eb03eba25431e679cf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50097156" + }, + { + "txid": "90cba3db7e020c7b8943293ecca7f6a2150082a372972c0ed65646337b0b05ab", + "vout": 0, + "sequence": 4294967294, + "n": 16, + "scriptSig": { + "hex": "4730440220782ba77287116d5d735f67a3738fbecc1a802d2141a1fa544f61a5e8ba682a4402205473d68019cc8895ecb1d87bfced62ddb6dc48b81152f2684ae8530122d5b41f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.5017515" + }, + { + "txid": "e25ec382049a4d8edd530469e5e41d9e056a2081b661f505414b1348e482dd26", + "vout": 1, + "sequence": 4294967294, + "n": 17, + "scriptSig": { + "hex": "473044022044ed9bfa8674d7e83112fa22280797169d45bd971b185da2413e36252637529d0220531eefc480e0911d6ccda42002942883149bc1cdd1f3bbde313751d80bcf98b641210328ac4ed2b30ddc04c778a78b24e7256b08c55758c1465defd997ff4bcefacf10" + }, + "addresses": [ + "bitcoincash:qqnfldeu0yd4wd89c44sujdz2w7hwvvd3y8g9tuech" + ], + "value": "0.01884419" + }, + { + "txid": "13a148dff09d7786a7e0d0929e7ece3c9fb8de532597cbb0d045f5ec531b2e9e", + "vout": 0, + "sequence": 4294967294, + "n": 18, + "scriptSig": { + "hex": "4830450221008cfdfd352e268dba2022e7fbfc37a90401c40fdf6f1d8ba9dcb97d67743eddc302202c0a1b604d34aa174fddef63c9115c95465548855c5f783bb206eb4ff8fda235412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.5002857" + }, + { + "txid": "700dfcfa0847678c56a084b5a75fb8aef1b1a1126512b026ebdb8c45d55efdf9", + "vout": 0, + "sequence": 4294967294, + "n": 19, + "scriptSig": { + "hex": "473044022001b33b610b8d742df2ad98679f1e41f0c647faf272e15e7ea93171ba29c33bcd022061646fbcb81ba30d6e8b030ee12101d1f1bef38ba44a6d5daf40c4ff6d644e6e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50039508" + }, + { + "txid": "6810932357166daa33c2125cf38be6076f7b6f718f199348905459f22ba7f2a6", + "vout": 0, + "sequence": 4294967294, + "n": 20, + "scriptSig": { + "hex": "483045022100ec9b6bbaba90d8902ec8a1ca0e90ea594264bc1add204b756cc89def4d7e9a2a022066b2bc84f94e1a99effe0e929be8de8669631143ca20c73e700d182ad4884e71412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50136993" + }, + { + "txid": "42a98564873f7c888a6a569cb97066b4bc43c5fa41d732573774f996b91980b3", + "vout": 0, + "sequence": 4294967294, + "n": 21, + "scriptSig": { + "hex": "473044022057117591cc465c48da58ebcb8f57fcd56359757d41e1397e45b5e33e034ea5d8022001de1d78ce9e8e73370a0778b4a8595045c6faeb2497ab4296d0cff735711276412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.5005352" + }, + { + "txid": "f7b56e95b5a48a66649fd3e9e9bc94a7a01bd1c4822c4dcc2c40243c8da60bbd", + "vout": 0, + "sequence": 4294967294, + "n": 22, + "scriptSig": { + "hex": "483045022100dace56650d1d9edaef30e8c9ecb4b78499a573984c8a451253295a90c84a3ed702201f4587d4a760cd77a2e21d5f6f2b7aacf668220c8c7c62fc1ae4779f7c0141cd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50111141" + }, + { + "txid": "d58b912c125283ee0249b670a7901bd5a1061d92f7c06627b5e963fb0b2c3d14", + "vout": 0, + "sequence": 4294967294, + "n": 23, + "scriptSig": { + "hex": "47304402200db6b461a0082807f59053bea210d38f5f82f02dd63a57f6e3987339cac23870022064ba927fc11b36318785d4e861a7f94cb3909ef8fe882360e2041f7b4a444692412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50143132" + }, + { + "txid": "530326ce09e8f933a604488e5e2f06845c3e805761c02eced5cc02856be1b7b0", + "vout": 0, + "sequence": 4294967294, + "n": 24, + "scriptSig": { + "hex": "483045022100a3e75a6c7918db32a27be348493b831631856ec8f546ca43d143cdc3c1cd03c802201e6ae036423bfce45c500b0c049f68396deae5cb999038de61e972ccd4cba5e7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50022822" + }, + { + "txid": "ca51412ad37c5e5a49b11dc7858b4013ff68288c56e6026b11a4266e184b286d", + "vout": 0, + "sequence": 4294967294, + "n": 25, + "scriptSig": { + "hex": "483045022100caf952ca1760052cfefe8df283fdd0eccb9e1238eea88eef287df9404c622e8b022072027363fa1070548576fbf9bcbddf2e435fd020662b2d8f0582b52bfa487b31412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50033136" + }, + { + "txid": "c03e268bbb105f171305f7fd994c0e15fbff5ae3d08f3c332c48cacca66bbb38", + "vout": 0, + "sequence": 4294967294, + "n": 26, + "scriptSig": { + "hex": "47304402201a4b4efff2b70a4039b4dc120141da04ae84f63906df10c3cad08838c01b6b8702205a065d025c338547ea07b2095ad31252658e57f1a7a04c7f4eacc0248e611fa2412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50037356" + }, + { + "txid": "46c8b9fca6423412b3d40cf7606b79678807d75b2be1e848765c40f367b326a3", + "vout": 0, + "sequence": 4294967294, + "n": 27, + "scriptSig": { + "hex": "47304402206b0a876d78793710acaa8bbeb58a2d908bd4936f2a88825f944b190041b5e0be0220279560be5009e4a3fab44d08f4748e2dead710a8ccc77e06a03ba8112d728856412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50061192" + }, + { + "txid": "fadc6b6f3225ea8686c7a03cd8362765f91e604c260beaf965c4e7093fb16b74", + "vout": 0, + "sequence": 4294967294, + "n": 28, + "scriptSig": { + "hex": "4730440220799bdb7ac60cdf3314cc1f157299858d353e22c00354707337ab5b497619d626022000e41053afe44fa65227b7dd8498300a2dc89367d9daf0586caba5bffdfde567412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50118669" + }, + { + "txid": "adb5163c2bd4b1c35c1eac2671e6124e6c6b9b6c3e2abdc8372601528600a98d", + "vout": 0, + "sequence": 4294967294, + "n": 29, + "scriptSig": { + "hex": "483045022100a1af33a83edb7fdc289a48a4f77cf286a88b38c21ddf27dd4ec3df007ce11046022074dd56730730f958039efd70edfe7e181060fec306c6df4cf75209600ebebed7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50075561" + }, + { + "txid": "db1a00011dcc02708d6757b7435a3163d4dc384d8490208656229b0780b4a184", + "vout": 0, + "sequence": 4294967294, + "n": 30, + "scriptSig": { + "hex": "483045022100eff445419ec63d1e9f51a5324c3be0315911b39f30657639e84ea7d2f739e0510220218e73140a39542ec8055b6645cbb7989f96b9d9a93c67549c059509de06f0ba412103dd71b53aaa823b09a68aba30c7603c6a397e7c183f708c9dfb0d9d0a9cd1c722" + }, + "addresses": [ + "bitcoincash:qzduecze3gvxk6y7rcjmvnau8c3ncddvvvs05z5gz6" + ], + "value": "0.01400587" + }, + { + "txid": "df69893e75d4acee084666c023822f07196dcae429a07b136fe92a87262f87f8", + "vout": 0, + "sequence": 4294967294, + "n": 31, + "scriptSig": { + "hex": "473044022050b7ed06a6832b8831c08ba86049b3793b5a71fd6d5177c9f268b79c3074bca7022047447c23429de30c361875642d9058bf1b5e0e6c5516d6e71b70b7cfb29827aa412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50118543" + }, + { + "txid": "8432efebc29ead31beb783d5d27cc379fa31cee352cc19a75746768b2fbfbe7e", + "vout": 0, + "sequence": 4294967294, + "n": 32, + "scriptSig": { + "hex": "483045022100fb072bfd399dc11191ac449a9d60119bd191ce6b19a5d92412a805ddc8d4b46f022021e463686560b15ddf272b9943d8e41425ed500f77698aba518ccf546a97aeb4412103e35c58a738805f53af73472ffb671a9bd3556ddef47c62f18ced868bb5033d0d" + }, + "addresses": [ + "bitcoincash:qqfs2vp95prfunn2r9wh5lf2g6k7k6jjr5qld8a37e" + ], + "value": "0.01772743" + }, + { + "txid": "29ff4caeaa127c04ecc8141f49462390a13febd47877abda62a7ebb66658f0ba", + "vout": 0, + "sequence": 4294967294, + "n": 33, + "scriptSig": { + "hex": "483045022100b25e7d4ebaa0e7d8e24498b039e756d568b67316aa14d05abafaec59e216a73d0220010d0b6548a74435907eb0d548dfe8e52a949bbb785eb2be3bce14053953784f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50075582" + }, + { + "txid": "3b46f445ddc1b8acd4fa933fb8d7dba9bd95ce53a579339b32a1e97352323013", + "vout": 0, + "sequence": 4294967294, + "n": 34, + "scriptSig": { + "hex": "473044022007d2baa9a766c120e111a727bfa8e8bc2e01cc285d4d4f67d2323b213525a10c022020f32be2d9935b6d9b5091db27ebf00aaeb54adc7032badc7ad63f20741ff28a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50043307" + }, + { + "txid": "1bd4b1e18be85528e214e16c69f459272ec126ff0dfd1948de6838b5b50e5344", + "vout": 0, + "sequence": 4294967294, + "n": 35, + "scriptSig": { + "hex": "483045022100f98ee28ffb66acd04474a120904ec1be2327d727d8ed8fe99d8b95c174b8f46a022041d21406dd8df10cecc1d6435de68fef3f9db71838c1ca2910895bb184b4a6e4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.51821842" + }, + { + "txid": "067492a2b7fe0787a44ceba7d6ee64da25aa8be08357576e4cef97ef76babf2f", + "vout": 0, + "sequence": 4294967294, + "n": 36, + "scriptSig": { + "hex": "483045022100ee3f7961f0f23137d753affe85b777e94c1db3f656cf41b8f59fcf82d9226eb7022025009482a6c0002e409590075caf7a78023ebc1457f100c8b922a4974ebf86ba412103f1d1dd7685d3781f58f9aa399a16f6bb9ccc7d008cdb7c63a7945cfcaa6ba0e2" + }, + "addresses": [ + "bitcoincash:qr99zjexsl5dtdu38wu8w7jdmsmcxtcr9qw64zjhdk" + ], + "value": "0.01843864" + }, + { + "txid": "bcc168ae5cc9dd70fabab262712036bacea7250db404c0d5af438b0b085c52bf", + "vout": 0, + "sequence": 4294967294, + "n": 37, + "scriptSig": { + "hex": "47304402201fed9da4c0526ac5ce257fce2b7fc995646b5f0d2961396327f93e2dfda3e4a0022035b217adc5a9be2ca34f4361ceafd9f2d09a6fa47d4a767f7001ade40c08fe26412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50034365" + }, + { + "txid": "025d365f0471a48171c3f50ba4e9ee04ee74f72c2e8d0cddca600f3a900b7b32", + "vout": 0, + "sequence": 4294967294, + "n": 38, + "scriptSig": { + "hex": "483045022100fa8ee82d42f524290319fb3ee47a1afa70cb952f8a37325680d6fd651ac3699f02205ac0cd86fece03ca204bd881d67ccce0cccbbc98704d9e955e2f92b5b77121dd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50085848" + }, + { + "txid": "c61c8a5fd411f160bac0e4b4e703e1caf7d3f8218b0ca5f2aa7b762bb9d3ad5f", + "vout": 0, + "sequence": 4294967294, + "n": 39, + "scriptSig": { + "hex": "483045022100f3cb343c4704bebbc78c6492dd72ca19c388b285f44f574dcff25f993add6d5f02200e050dacd78de955cf552f9158beaac5fa64995f5bf7c8a919a231a39425730c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50086233" + }, + { + "txid": "207dd74726483c593b21c180a9467166af7f5b02450fd3613268cea239aed047", + "vout": 0, + "sequence": 4294967294, + "n": 40, + "scriptSig": { + "hex": "47304402203f05a035f5d42fbfe97172b431a613110ad733e356ebfd08886fa11bedaf1faf022061c4a3bc3417390910612bae46f5acf8b6e8a5b008d273a52e483a315bfb950b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50080933" + }, + { + "txid": "facaafec82e7853c85dca5fcecad9c62d830a2421c98e8c5896b793966face46", + "vout": 0, + "sequence": 4294967294, + "n": 41, + "scriptSig": { + "hex": "483045022100bf60fbd4716339bbb42ce150966ad6caf90b14e57f45eb6804756cf8ff36b23a02202f16aaecdb9994f3b683cc7fab45bd0a3f54795c336b5fc224fc51270a7f3f4f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50075132" + }, + { + "txid": "26703badea466dcf8446e1ee49868ed4259ff22e0f13460db9d79819115b5c4e", + "vout": 0, + "sequence": 4294967294, + "n": 42, + "scriptSig": { + "hex": "483045022100bcdcae99c9289b5fc89d3227daaea8df7d0a0f3a8971d841ebe1ab7a1ecf72e202202ca21447a6b3e96540e32529697d523b7b08c65845d6a13f6b1475de94919bb6412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.501188" + }, + { + "txid": "c94103172a643e1ae22c3955749bf7af337a914a48d124fb5cbaae1ab5fa9e48", + "vout": 1, + "sequence": 4294967294, + "n": 43, + "scriptSig": { + "hex": "4830450221009535c27b5bbca0db2bcf1a0d0b3b283a2171df53f0d68f1a138888fcc6ddd996022068af19252ac4376cffdbfaacb2e0f0c216deb7e2478b586abe7c2679501eac34412103a47e5dea4ab8d785f4e00994d0faf1a8f384c41e74ed8e4b776fa6ce136ebc42" + }, + "addresses": [ + "bitcoincash:qzfvx98n9r4yzlvk2h736rn3qftpl2uttuu76kvt5x" + ], + "value": "0.0163143" + }, + { + "txid": "180544709d0cc711566118b48af548a7b199c639185685c7228676725c28ee7e", + "vout": 0, + "sequence": 4294967294, + "n": 44, + "scriptSig": { + "hex": "483045022100b456847e29f8a648730f0fd34cc7edcfb35daba866ab7d800472beaf2836ce4202207db401f0a5e30efc53c7bf58e57d1dec5874d64768ad9eb4895351cc4be9226f412102291b40a9a927dafeb53cdfc7e722ee5c9dfd6eac2d81331678b9ab405bb25d21" + }, + "addresses": [ + "bitcoincash:qrrv55s5ag0dduyjsc83ds7hstqc0m9htqk764mtaq" + ], + "value": "0.01078385" + }, + { + "txid": "67c24b19a0f444541bcbcb15e708f7713f5168f89f3d42df51d1909f6e22b093", + "vout": 0, + "sequence": 4294967294, + "n": 45, + "scriptSig": { + "hex": "47304402205ff244c77726def0e3697a3e546bdf74c7f31479c9d01a7a6f8cd1656482d537022045d78dba8ed4d3777f473736daedbdaca6f5698dd306898d144eb43f96259766412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50191671" + }, + { + "txid": "208d4a8a6afa218a65416286733a5158e7ca393003e30f88dec606e771e384c7", + "vout": 0, + "sequence": 4294967294, + "n": 46, + "scriptSig": { + "hex": "483045022100ec6b35ce6d24889726480d70a31bc0d62800bf7ac49ecf084b98137322606bca0220432d33e2d8b508f26d7d813d18629453c537a4d90f73a104bbf80627f9fe8d62412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50036468" + }, + { + "txid": "60a7eef8d0b9e7cbfe602bedebd75a80121587af1236fcb8ddf00e510cb4caa4", + "vout": 0, + "sequence": 4294967294, + "n": 47, + "scriptSig": { + "hex": "4730440220423ea635717cff512d9262b7c8932c0122ca868251f019ae033101c28771a52302200cd3ae05f2e88d9f64207beb4b715ba480bde9ffdd40ab61a36feff88f2968d54121035530745f3cd4d31532991e460bd2a15e1944e690643f73133a9918edb95da53e" + }, + "addresses": [ + "bitcoincash:qq788skgg7eqc7unt733wahchmx08h87tgn20l2n3l" + ], + "value": "0.01329593" + }, + { + "txid": "7033ed9dcbb1af754c41046bf1ec51c16285336abc235b9485dd9c8829f32b85", + "vout": 0, + "sequence": 4294967294, + "n": 48, + "scriptSig": { + "hex": "473044022055cc4dfa48a79b8584a9352be34ab5fe9cae4132d264dd827d14ae06d35ad4090220652a83c93505f8a8527c5bc0479f37da0593595c1bf18c12b8fa0b41a2e37a64412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50053803" + }, + { + "txid": "929f05541924a6eb7dc7f2e11310037de210718c5896b9d9475ca5724dc13532", + "vout": 0, + "sequence": 4294967294, + "n": 49, + "scriptSig": { + "hex": "4830450221009acc8d0e06d10b0c764a27613bcef41fc75f910875eae3989a7f8725f81814cd02207146ff66f412910ed993fbda4ad6ed48862a02f366dd88a83856a17e7f96d83e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.5017106" + }, + { + "txid": "a7e965c2d147a2bcc7d99f61bada49696703563d7b8225c9e69c29e312aab0a0", + "vout": 0, + "sequence": 4294967294, + "n": 50, + "scriptSig": { + "hex": "47304402202d8cd72290f04063c0ae9bc06d2cae3ac74ef4cb6945c92c3e3ccca210c127ef022030471726cd87ac9d55f3d246095f64ae22b611aa8791922236bbdb19ec273322412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.500305" + }, + { + "txid": "e6897dfc8254d449f61372cb7c4131c4caaf2781fa60cf930a36421d0bc156c8", + "vout": 1, + "sequence": 4294967294, + "n": 51, + "scriptSig": { + "hex": "483045022100ffaa954e5b86d54ece9bcb9e37895047221828ca381b03266de3d9341599c8f902200ea1c5ed36e893df822c698a474b062d4f93005c32f9d2f0d78ecaf5a56e4fbd4121031a00f43cd99e015c72acace20ac47d887a39ef284f89a5aa09abd968d06f5e9d" + }, + "addresses": [ + "bitcoincash:qq64kqwmv0gu5naq8ztaj5ecef3042n3pceymy9fw2" + ], + "value": "0.01746309" + }, + { + "txid": "d69c6ead378471a3f30a9a7b10381a88bd8c5e343b8108a0f189f9f665901269", + "vout": 1, + "sequence": 4294967294, + "n": 52, + "scriptSig": { + "hex": "4730440220457d59caf24eb6e10664d06f3e936f6ee31d9d59f1cc4f6f62788f022bce8c1b02202ce7c37ae6832b078c1cb9a055e3ffcf4674081f0738fd9c3eb4465b52bcc9ca412102fea9ae922223f2c68c68d7672b7656885c3e1321d35cc8f5f445179df6f7d27a" + }, + "addresses": [ + "bitcoincash:qzudxte3pz9qf5gmnpr5yxj97kv3flcs2gv5mct8gm" + ], + "value": "0.01792586" + }, + { + "txid": "212aa8288a75640e62292417bf53dad20d242df7579c38fa10f2f63d8c03d38a", + "vout": 0, + "sequence": 4294967294, + "n": 53, + "scriptSig": { + "hex": "47304402205e0f5cb06f7fd741825c669c87e9db1a433913fb8577adb92b779d3a693b4f080220120648a5f9d2abae83a29cd2c79f5c61b9bc40da8990736ab97ccf6f82c586cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50046573" + }, + { + "txid": "3d6a1aebc3f48b843e408421c9f421d3934670d86a3f5df49a6530152056da4f", + "vout": 0, + "sequence": 4294967294, + "n": 54, + "scriptSig": { + "hex": "483045022100debfb215f94e9d784e91fe0b9d2541d09a4c7591172fad1441506db4a3590fd102200cce728e344933111c9548162e62872fccac624f6f98d92ccdcf98dbed09ac544121039b8a20c23f32f5b14e76fb29e0baade695810aa7b6dac9e9638a8d13b6ad8221" + }, + "addresses": [ + "bitcoincash:qrt6ljgpzzmamr2ukg9a3jxe46ufaa8fr5yp6f9pfy" + ], + "value": "0.01801618" + }, + { + "txid": "91585d5312b1a4c8bca993b6db304a65c7bda601113960cccc978f28c381bfe7", + "vout": 0, + "sequence": 4294967294, + "n": 55, + "scriptSig": { + "hex": "4830450221008110aec39b127143891069590fa0d9e1d8b41bdda70d9807848eba92cb48736b02201bcfdc1a1cedfa4c53efd941482f6157774b2aa80af44e500263be6a3cbcbacb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50046545" + }, + { + "txid": "b9b3d23c90954095289ff5feff55de3cbd7469cbb179e38aa74dc813fd6b684c", + "vout": 0, + "sequence": 4294967294, + "n": 56, + "scriptSig": { + "hex": "4830450221009f76d6838b8fd8bb74f50c67920fda9f28054d093b30fd03b54b3fb888db046f0220307944f3abec07c3570614f418056aeff03c0830173c963bb0b65bd5ef24b4a9412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50022645" + }, + { + "txid": "65f9a63b7bf753423cca4a5ec229f566e61cd1ec8f745683da2a934b1308713f", + "vout": 1, + "sequence": 4294967294, + "n": 57, + "scriptSig": { + "hex": "47304402207b93e2500b189b51fbc3a49a191c4b92ac76e32ce86f6f1b9af4afbb3a91fbe002200b5617cf52095bf882a5129f5477f119c9c565dd582a9f19493cf1bdae6527ac41210323ab0930ba40688e66bef6e08f673bd6bcd3df687e4c503387f48c24bffdc93d" + }, + "addresses": [ + "bitcoincash:qz86ljat9dnhjp2wplpm7ncfm7q69hk58svu9g46ex" + ], + "value": "0.01593178" + }, + { + "txid": "48ddbf6a4cc52b15bb4d2cb7e39fcecae29483bcd3d6471e3543785621f3df7e", + "vout": 0, + "sequence": 4294967294, + "n": 58, + "scriptSig": { + "hex": "4730440220731ab37e71d9c6f63333ba205a318d36e5847706381f571b4b562e5e6f6e403c02200704ca9d9a33843d9a16135f56eced1fd18e227385671a8df5fa41e505e3ba3c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50019587" + }, + { + "txid": "5027ac365cb55b21278f32710703d9ad932912919c58de364e1eb1e9d79412f7", + "vout": 0, + "sequence": 4294967294, + "n": 59, + "scriptSig": { + "hex": "483045022100d1d3565175e1f529124ebba1bcdf8c1704e753c2f91ddcd1a093b5f5403cd0ed02207420ee9d6082356cba6d8075b4fbf310bd84dc770734a8ab30e74741a779bae8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50045268" + }, + { + "txid": "93cc92162ee854259d3b3f9ad1886847eadb2ccc86d03bcc6b89718da9ca23f4", + "vout": 0, + "sequence": 4294967294, + "n": 60, + "scriptSig": { + "hex": "47304402203ddf5c6c5065f03229cdf837d9f8d3d22314834b006e0aba8dacabea206b3b150220417c49c9095372d3dfd954688bcd43fdfd2a121989fde18456a9428b2a8e3c63412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50086952" + }, + { + "txid": "c672af6e97eeecc79e87e708d57e20e2c7d811bf3431eaa928f7efc24b663dce", + "vout": 0, + "sequence": 4294967294, + "n": 61, + "scriptSig": { + "hex": "483045022100a20e6aaca7df2b142b768d3b1cbf8f783f3d4997d155a32f0e066b4255777c9f02206deb15cf53d6b27a973df9aa7080691e5914538d9e97ec7c6e797ce03333238b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50143426" + }, + { + "txid": "5f64a0a07336a2bad8f9611709653146fad9fc796f1e92dbd12afbf0d6dcf5b8", + "vout": 0, + "sequence": 4294967294, + "n": 62, + "scriptSig": { + "hex": "483045022100cc2cf5c6c2d4862dfdf65407138684ba45565bd8ec46594ed4586bfa37b715dd022013255b2eb22f5bb93d2afdd07ec4c3b5efe0aa16134b2fd084c6bc720f8cfd5c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50125454" + }, + { + "txid": "256b18d5861752fb617796cef5ceba05e42de141e48aa2737c77020e8d1f337c", + "vout": 0, + "sequence": 4294967294, + "n": 63, + "scriptSig": { + "hex": "47304402202c9dd98c9a72e5a8df4b01f09d18e2826d8b9871db89c5d3b24ffd673facaa0702207523bfcf3ab80790167a2b1159fe268770371fcc7d770995c19eace3181ec8af412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50058048" + }, + { + "txid": "aeda3cb9ccecf67cabaae458862b2068129297b1b502b862067f578a2201d54c", + "vout": 0, + "sequence": 4294967294, + "n": 64, + "scriptSig": { + "hex": "483045022100bfac8828df10b7911d341c15a532819c429c7185d8883de19de84e71b97d78730220177603a3572908c90dad865770906b5ad228da7ee5da39503ececf60ac735158412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50083898" + }, + { + "txid": "0b11e279a95eaf9241bd55fd7f7b045e2ff047b307b25f3885feb6a71140d6db", + "vout": 0, + "sequence": 4294967294, + "n": 65, + "scriptSig": { + "hex": "483045022100d598e2ccdeecfdfea9d5139a49a94fa39414f9e1ecb13d54efeb34c168e58aec02202a59463710905613844f48dc71d316c0cae54ab9e16dd95beb8902e5940024ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50050928" + }, + { + "txid": "82026eabe17877d3aae729eee2612778389a9246d56b8032706c454223760eb9", + "vout": 0, + "sequence": 4294967294, + "n": 66, + "scriptSig": { + "hex": "4830450221008302d38e9eaccaea812c853047931562417a3665b8b9373cf7f63e58180b002602207ac8fddbbd19560a74333ec92fa077d169b4902a41e0431113f8fdb75b304ecf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.5003979" + }, + { + "txid": "43a94c82abb414437ac13038fa5840a6038733dc156bf160cf30db31a82355e1", + "vout": 0, + "sequence": 4294967294, + "n": 67, + "scriptSig": { + "hex": "483045022100c0d85a1f9146e8ef9efaef8ed9b3ed09c55e51b25e189735610da89b6d212360022003a49114e504741befcdb95d52a3dedd1aadef68b7c48f0a4a8c7dddfb4201b5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.5010516" + }, + { + "txid": "41f835819365a32c2ce1138c131a4039c6dfeb034d922af573d997697b409378", + "vout": 0, + "sequence": 4294967294, + "n": 68, + "scriptSig": { + "hex": "48304502210091ec8402cafd1e7eb11b56ac56a994ac79c435893108d0b7c8cfff87c07ba0a602204fd98efddc1b4e21bd3cb81217579a7b9621f9c3c204f2f5800e75ce1c60b19c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50127067" + }, + { + "txid": "2f8ca9dea380bd026636e2281f1e42e63dd54a04be1c1526574994450ca36f01", + "vout": 0, + "sequence": 4294967294, + "n": 69, + "scriptSig": { + "hex": "483045022100a850bf088a08baac1f1f577da8946befe2e6b0354d6a29f636afd39982569a7e022062652d6b75dee145f741d28d6f1870fde9a7d66b994f0d3162abdc42fbf54458412103ffdeec10b52942b0c46d6578998efdc1d64073de579e92e7c5dfa97fdf3ac391" + }, + "addresses": [ + "bitcoincash:qzzkjplzf0yw2xej4u9he5pr5evgup2snqqxs823e8" + ], + "value": "0.01366913" + }, + { + "txid": "404829243c500005d37a95164bf6610005ccfa19cb7660ac9c1ee0da009465d8", + "vout": 1, + "sequence": 4294967294, + "n": 70, + "scriptSig": { + "hex": "4730440220762f7c017672dfc71d487f3730e26d69d0e53902f579ba348095ca164d27b094022076c7e8045ec9fc57af6dd95f35c0ffad2c0ca8f83f112f60fb9851ba4ba15d92412103a2d2d8251728b11fd4afe7b8c73a8442f76dff9bfa424f5cad9b98083936259d" + }, + "addresses": [ + "bitcoincash:qq4kx2926zmnhfa36xzfswf9p9raqlapmysqvr4ck6" + ], + "value": "0.0129234" + }, + { + "txid": "2624cad28a9b7f55434b68fc8be7aadb87d40003d786f0e414cc1eff74a12b64", + "vout": 0, + "sequence": 4294967294, + "n": 71, + "scriptSig": { + "hex": "47304402200654032c5760f8b94cc089da51773447f19c1cd2108cab89bb53ccfdb6dbee56022015e277622dea4bd1a7913ff934b2bb2d1b3d75f05285b51690160e1197a258c5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50134907" + }, + { + "txid": "893b3cfda77c1371e21df17e45910578fd778958f9b51fcebb24a2e92c604d65", + "vout": 0, + "sequence": 4294967294, + "n": 72, + "scriptSig": { + "hex": "4730440220712877c0dc553096eb0ebf101d1555fda5235db26ad074d2f330163fab63fc7802202c89752dd7645e8a3da7e8af5fb68dc8b177700766b79cf6a35695a0c7c873cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.5003304" + }, + { + "txid": "cd86f3aba8b0553de0041a2173507a34f595a3785dbaeb8c9b2cc1c1c34c61cc", + "vout": 0, + "sequence": 4294967294, + "n": 73, + "scriptSig": { + "hex": "483045022100f3fa1e305666e2a62afaa11fd37025b25c0bdff8709fe1580406615934228cee02204841a7d96f36d3c183f06e22a58175756c3e9a76c93c7cb4e9945f31ddedc902412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50105407" + }, + { + "txid": "ae8ae862b5ddba89e69b42aa8a6ea2693e61f90ad3a5625b5f81605c7aedb226", + "vout": 0, + "sequence": 4294967294, + "n": 74, + "scriptSig": { + "hex": "473044022047c158e3fe3f40de3f39796dcecb7df3cf344f14009de9826b62a43837f2cdcb0220759d823cc145fd5e8b651a7bcc399544692bbf596189b1fc50bba5f4ca02cdd1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.54457185" + }, + { + "txid": "b402b3d23c910e0ed869045671269210f6594f308b6b01a0bed2052f6012b0eb", + "vout": 0, + "sequence": 4294967294, + "n": 75, + "scriptSig": { + "hex": "483045022100bd70744c867943bc3bf578e192c8a87a5ed5126aac4acd98efa06ea2483911fa02207377e11ae2d2bbaab00da86ec73c26e596bfcc680c0b8eddc5d44bda650bc299412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50101109" + }, + { + "txid": "e1deda4073c863ba018bd7334f625f79884854006f27712cd010e57bf59c8087", + "vout": 0, + "sequence": 4294967294, + "n": 76, + "scriptSig": { + "hex": "473044022059ee25066b8a2a4fdfc35f14c5cbb7f22ab181fcfa9702d4f3de7aa4d738c7a402206dff315ad1cd2222cd6ac074bf34241fc22db38a57bf089f7e24542323f1766c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50083658" + }, + { + "txid": "219c39d91c3d5d3d1f81c83ba373df7ccaecb45f5e4a2f7422bb2021afb7338c", + "vout": 0, + "sequence": 4294967294, + "n": 77, + "scriptSig": { + "hex": "473044022039657cdf4fcd5a9e81766ba11db495b8be5664612d3b91f8504bea342c4ecbe702206ca4913e5807cd697d30dbc93e0a9d679eb01ee84b687ab0c642e2f3ebde745b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50032757" + }, + { + "txid": "3a1f594a74bad6de4c762a78a6c06db3900c45408ec0f785c61bf9f29bc34281", + "vout": 0, + "sequence": 4294967294, + "n": 78, + "scriptSig": { + "hex": "47304402200232ee94873317eae275cf715f4c3aca25dd0c8db4800946a45cc1d9c45732fa02203d9ce9c9aedc0a3899dd027df32e683438769d66f33ffe52006454614b77821d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.53061599" + }, + { + "txid": "14cf83e6c8b80366b8651c6b4a0f7d2270290066325d686ba671ab5c4c9a3b50", + "vout": 0, + "sequence": 4294967294, + "n": 79, + "scriptSig": { + "hex": "483045022100900bdc6f705efa56449a65f15a67fc7fbbc102f78e7974ea6ac2849c75d2dfec02203b78de71dad2e3f6ffad2779cb9007217c957c8f5db7abd58fd0537fbabb8c6b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50121784" + }, + { + "txid": "1dd1ec6c4b4ec9bf13aec933506376c77e63254d5573c2584d7515554f14ed8b", + "vout": 0, + "sequence": 4294967294, + "n": 80, + "scriptSig": { + "hex": "483045022100becbb21c7937b9b27ea3cdac5f2048ab9ac314de59c3ee2926a5cfb258ce14e902201c8022bf275c1a761e7715b14e15d74526901363ae5f8bf5489d00908dd758eb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50044721" + }, + { + "txid": "9957066f6fe221a9423b0f54ce1188000e1e9f7bf9085527d9e1edb31d88b7bc", + "vout": 0, + "sequence": 4294967294, + "n": 81, + "scriptSig": { + "hex": "483045022100ad84bcd69a85a0d487fd7cbe4d76b95bffa303e76615a4336419fd182eeae4b902206d21e4f592297e87f1af9e19c80fd978914aaf5a2db2cf499b72cabbbe73c831412102958762ff6c8985dc9656afda59e61afc6c0131a5d8f1d86c87c83c9b37f7bd18" + }, + "addresses": [ + "bitcoincash:qp7zwhgnhhuh4j8644mqg7y3fqejm2jkfvkt6qp4pp" + ], + "value": "0.018763" + }, + { + "txid": "ca467662c89f207dbfc6ec016e126693a204f17d6151987aa748838852aeffb7", + "vout": 0, + "sequence": 4294967294, + "n": 82, + "scriptSig": { + "hex": "483045022100edfd64cf9335d094d5873deb38cda5f4ceda3351df722f1c718993a2dd12c8e302203126b0f9470a4d0867ed4e773518b8ad689ce43a2c9f65a1f297525fc22201dc412103f37089783028c0776f2b8a9d8481ec8d6d0652a31edc03cc274032ae17c63c62" + }, + "addresses": [ + "bitcoincash:qq7fvpnuflq4cq6wc5t4qjuzj8l59puq75h022fyxs" + ], + "value": "0.01114817" + }, + { + "txid": "54fde006c8dbb7a3de68e0609d057a3f2337c99ee2ae70cc715d72f5dc881a80", + "vout": 0, + "sequence": 4294967294, + "n": 83, + "scriptSig": { + "hex": "4730440220448751a749e7cccacab0ae1ad4da948b0e0b5d8e3f41ac2b22c18928e8e67d41022051c107c345c06ea82fe8329a8cf3a96b516fd8750611d8ef438b8545416398ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50175152" + }, + { + "txid": "a08d7c70130d925e33b93e21cf77b5790a2ab5b5dfc4ec2198b9d81a74af06bb", + "vout": 0, + "sequence": 4294967294, + "n": 84, + "scriptSig": { + "hex": "47304402207f9b2802ed1e893168277204b7919ff479efe5c71ad2a255e1738a52bacd758f0220253780485f2e3ee960e058d449c647b147b8f64b49b913e7e9615a6c7114f18e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50056417" + }, + { + "txid": "e2c0a8e67a48286fb8801c0faa3951a268c5f6cc450c445c380e80e09c752778", + "vout": 0, + "sequence": 4294967294, + "n": 85, + "scriptSig": { + "hex": "4730440220778fd8ba1dd9f71df55bbe1c3c4185b8da21dda82198546c2a0c30250f4c1d66022040f17a46187d535c6e943c047942f45159a37b2e171db18c657cd24168c22e2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50043784" + }, + { + "txid": "221971a381aaba4e963d21b54e625b764016e848a5390a0df32a29aadf35f92a", + "vout": 0, + "sequence": 4294967294, + "n": 86, + "scriptSig": { + "hex": "47304402202cd2fd29fa395a5a80893de065c8bbe71e0bfe0e7b2224cfd5684736a086aabc02206720226ba63a3e5d9e2dc67e404625cdf31a7a08da0e8a22717e558f7abc817c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50090058" + }, + { + "txid": "bf6623abb315d54e6b7d9428133d913121ac875dc4c8e3f698477dff8cb7e3e3", + "vout": 0, + "sequence": 4294967294, + "n": 87, + "scriptSig": { + "hex": "483045022100f8769b797386f0bdd662483096f4e0a33c13f6074a4aaba3fd590b9abbca7c2402201eb064869fcd17a59ac028145b08c73b3552544cd7fc62245d1fd1d369ecf765412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.5022994" + }, + { + "txid": "e66b832bf71437eeb367e6cd7818658f960a4845bdf3f5081aa474935c9b31dc", + "vout": 0, + "sequence": 4294967294, + "n": 88, + "scriptSig": { + "hex": "4730440220558e65fd916d9c9616a3e0bd41111dba3914867b1ce5d487df4f77feadc0059502203198566c0d58af8551b65f884db98bde161bac140c7a900cd40df97a40c267de412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50154777" + }, + { + "txid": "452873e0c38438227a2fcf64230973ea8f5868fabf05603b629881a2b46a4069", + "vout": 0, + "sequence": 4294967294, + "n": 89, + "scriptSig": { + "hex": "483045022100ca93287feb58daad47c5388067b219e44f8533a214eb8eea9b5313040579773002201716a6ad2de70eff6721ae7950edaf9230420648bb8ec53173c215cbd12246c0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50103829" + }, + { + "txid": "60b3b027b67f550a0544a539f173066031914f0a49897379b51ffa127117e521", + "vout": 0, + "sequence": 4294967294, + "n": 90, + "scriptSig": { + "hex": "473044022003240fd71510800910b448c62a03178b4ef62299b17d6d2c06ac8f3293684ff50220637e3ba59fc884a8bd16aa2e884b379d85f38ae4ba049a0365f33644febee6df412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50125814" + }, + { + "txid": "6cf9e489432bda9fa9eb865587eb28ff525b5171c38f746c55b85a577ae68854", + "vout": 0, + "sequence": 4294967294, + "n": 91, + "scriptSig": { + "hex": "47304402202e2ac9c8b619b8e2626895c20f6bdd1a24fa27de017d05d5fa2ce120b3421f25022053ef6f82ccf9a132d40ce566d45f4ec18bf30048d415f6ec1c783cda027b6747412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50144563" + }, + { + "txid": "9c9923f0c3366eea9c229233d8828825beb12a2c28ae3bfaf46203dd1fe8ab03", + "vout": 0, + "sequence": 4294967294, + "n": 92, + "scriptSig": { + "hex": "4730440220352bdfe541e9e1ce428ac4eb4c8ba9391a118b7dbe57b4fe3c4ecd30f228fbff02204a0b78ada1d74a7e7b9ae912e6f445d9ce9050855d9c5ecc7d477d2590a68b18412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.5021873" + }, + { + "txid": "5ed23fa46f4db7043e14b845ef13a37712170f7cb25f88ff9acbbd6bc97a9d87", + "vout": 0, + "sequence": 4294967294, + "n": 93, + "scriptSig": { + "hex": "46304302203f767d8f64e3c9e5773d94a325f8029d21d1c9a0f470c9288cd99f70d2d90ec2021f50b395f9329ffe64ff8084c1506e904ffc02dfac7f7e15461c3e8a077f604c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50079095" + }, + { + "txid": "fb09c795e5cf32d174df4efe8b2208de9819ed024511d9fd684556ec8adc00ff", + "vout": 0, + "sequence": 4294967294, + "n": 94, + "scriptSig": { + "hex": "483045022100f17f8045a627bf96fe09d868109063d8040e3e2df8944e05f9b20a15273d0bdb022059c31e2d849abd57e784f1a3903f49f18c7c5a624545bab98649e8a092e12a10412103ee2a3f78cd4930dac8c030ccc93381ec5eab259c1607360d85d1728fc296dacf" + }, + "addresses": [ + "bitcoincash:qr3vdgfvrp77mlhac73ujqgtn78cg6yeeurwnjqylu" + ], + "value": "0.01792434" + }, + { + "txid": "36bf90cf0b6074a361292ec88ef58d76780d301a1e5709bf013808c068af253f", + "vout": 1, + "sequence": 4294967294, + "n": 95, + "scriptSig": { + "hex": "483045022100b58c7dd3fa1f8dc50edc7b5546b8ccef8ffc5c179fee774999c63fa729ae3cef02205eb611cc887e5a62a4e9da33318ce6e216ca353225f452ebca51be1dd10f544941210267f3c9b9bfb6bc5c1f68dd1d18623a9986408202cf232ad1e4089933c83f186b" + }, + "addresses": [ + "bitcoincash:qzjvk52q08wp84x9uelf7k3572fx4z5q4q7vkpaalx" + ], + "value": "0.01713598" + }, + { + "txid": "259bc4abb9f14457e323223bcbbf772afc0a0252556e69c9e13e8c7860e7946a", + "vout": 0, + "sequence": 4294967294, + "n": 96, + "scriptSig": { + "hex": "4730440220097f46c588f37ced4846a45905df1a0ae22709760f8a1bc930a58f5054cbe482022053b418af66d1edcb3887616feb23e5dd4095f29e74ac89853c3b909eb42bac34412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50075778" + }, + { + "txid": "14a32331f78309de6ddad707840b364aace14cbef8694ab16a55305fd44260b2", + "vout": 0, + "sequence": 4294967294, + "n": 97, + "scriptSig": { + "hex": "483045022100cf98e22a2854c7088a0572e1edb4e876aa622ed10dc0376806e1432f5dc1eef90220527845f8dd2522fbdf423b4fc34a4792a7f82e04b314e0d83e2425daa2f92115412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50085059" + }, + { + "txid": "acd836ea3252a7610e6c1d426f2cc739f73fe1a0768048d7431a69d4bff3f0e5", + "vout": 0, + "sequence": 4294967294, + "n": 98, + "scriptSig": { + "hex": "473044022070c7aaa7d7f050b1b520878e55db3ca491fb33211150e2f620b685cb49d7d885022022d9ede63e3b196a1c33c2d211c1eacf2e2411820ecf5155b5e4244f5dfd9f1d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50132855" + }, + { + "txid": "348cdfc73c3172311b972b8c529545591f725b86ad065f88d7a78c2fcc05f9fe", + "vout": 0, + "sequence": 4294967294, + "n": 99, + "scriptSig": { + "hex": "473044022018cd70c3e62563ea92ea12735e2efb4b905df85e6b290d573051f49c63d07c60022037a537ca3514121d5c2b8753833808a5e0432f1a8f277d91495953c8211ad326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50023474" + }, + { + "txid": "af7baa39bec2ba327ff720a7c782f833d18c0677c644080f59996e2270756c55", + "vout": 0, + "sequence": 4294967294, + "n": 100, + "scriptSig": { + "hex": "483045022100a01ad9ec8d24fdf01eb203c2887c1413ae56990d4600a18010959f6df43de08d022056f0f0dccb8f772f29a7835d7dc40f242348805005b5f80ae8f2fbdb600ab2ca412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50249377" + }, + { + "txid": "6ba95cc08cb6849c9599eea8ec3abeb7ba7c7b42399cfc6d807dbc5aa8c1be52", + "vout": 0, + "sequence": 4294967294, + "n": 101, + "scriptSig": { + "hex": "483045022100cdd770159d56ac518ecb0dc916df0da06eed536e540582680f742389f53fa4be022012d372e2c04176bcb82b91b02ea23c9c1464baef7d1dda66066bf84c402c0012412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50192878" + }, + { + "txid": "41ebe9615cb3037d95ed10c37be1fc80d216619086c5cfc256e489ce42042d3b", + "vout": 0, + "sequence": 4294967294, + "n": 102, + "scriptSig": { + "hex": "473044022001dc7db378891c1c5bf07a09d14fcc6675965976e2e3e762786b1b1e0f4a4bb702206db6f284dec835823fb516fad89543edd3bd7af3ed33940fa296939fadb41ba841210393ae47ec2e844378cda3630abe12082401f2e0f98d016dde2b152b42e335630d" + }, + "addresses": [ + "bitcoincash:qp4h56rtxkel7traz24d3ep3jq0yxqm82stgclvks8" + ], + "value": "0.01288555" + }, + { + "txid": "a135747cbd99ace7bf495ba29e49b5595f32259ee7df61d9549cf3d4274880c3", + "vout": 0, + "sequence": 4294967294, + "n": 103, + "scriptSig": { + "hex": "4730440220290a5055313d68f9461ce830f8a7395022d2d55abf28f6b4bd665693b4a13730022035d4cc2a6676ed842027dd4f21d31dd5a956f4b1f5cf771b866cc0d4a6400df0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50118091" + }, + { + "txid": "90095e01bb497ffceeb85366ee1b9603b96c33ee0acb47a64fe3af23911410d6", + "vout": 0, + "sequence": 4294967294, + "n": 104, + "scriptSig": { + "hex": "47304402201fd6be6d72ae75b61a624c13476b538ec2f9e5146f3074c879af57ecfbe1679702200ab10ae612e7fe0f76fe943c1f6a02262008407f86782c1536e92e3bad77d3db412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50028058" + }, + { + "txid": "44b169e5c5414cd335ef67906c0f4425e8b190ab366dd1e16641a34d85ab5f20", + "vout": 0, + "sequence": 4294967294, + "n": 105, + "scriptSig": { + "hex": "483045022100a4132f408b5299dfed6153b7a331f9fe866f1b042e4263bf7574ea0964c450a202203d99cf8dc9a9194269bce400185a4f86f5d35b5be83f6dbc3166b600392f1b00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50132073" + }, + { + "txid": "f7f16d4c8f00cb446063f53a75d2dbb2c54d9d474abc836b92d48ed76a5ead8e", + "vout": 0, + "sequence": 4294967294, + "n": 106, + "scriptSig": { + "hex": "483045022100bbcc2e2d77458abc30898cddc7eda060b23a62f0a53b81c3db47f284cd7b29cf0220705328a29bd30792a7f5a704fd74b771c3c8a099265f5e7c9d70046da5b03ff4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50210684" + }, + { + "txid": "0252408a18fc77479f6e664fab80cbc6d90c1c5e369c34661effa52b9f1f36f2", + "vout": 1, + "sequence": 4294967294, + "n": 107, + "scriptSig": { + "hex": "483045022100d2f40145c4b9a17b3582aabdf7d9ac2d47546b3eea5350c4e2ec1e9c2466343d02203354ce620aa056a749de847f867c49dd121579c9fc50bd6258bff7cfb173c5f24121035bf755e8b075665a85155618f6e9022196a09c486415587dd3af0d25b76e9c27" + }, + "addresses": [ + "bitcoincash:qqe36s4qsvdfjzwrv8whsc0z94unav03agzr35m4d7" + ], + "value": "0.01591983" + }, + { + "txid": "74002fe81a5931658cbde74c28933bb36cdaed62201be1c0e26a53c92d6bf5c8", + "vout": 0, + "sequence": 4294967294, + "n": 108, + "scriptSig": { + "hex": "483045022100cf8c593dec0724644d034f17ccde99feaf0416334219f158f884badf500fc93e022035af1b68574e88ef15e1c05c1b36638401613a31aa7096d97efba6df62695706412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50148696" + }, + { + "txid": "496b4d67e0a734740962920c116d56121c16ca60787812fea76d69b9161f8395", + "vout": 0, + "sequence": 4294967294, + "n": 109, + "scriptSig": { + "hex": "483045022100a669e8918ba68754b84d584f38afdd34be387773449784a6c61ef3f33d0fd99e02204d007ef31f5a3a7c412ac3d2660633fcef137964ef2ff6269c41e933896d918b41210383b6491fd80e1411675d7c8eda9b756c30a814b45fa565b7ac24d7be9dedcaaa" + }, + "addresses": [ + "bitcoincash:qq99u7jj9ujglljvh8nzaqtq0kfl8matf5eldrwhmm" + ], + "value": "0.0185992" + }, + { + "txid": "4a6f608d6ce8efcc0cbd3b55bfa0feef86f5493331564dee943fa554fc84111e", + "vout": 0, + "sequence": 4294967294, + "n": 110, + "scriptSig": { + "hex": "483045022100fc35ed21833c3ea3ff5f832ef02236a08ded0999ea367aa6eaaff364ecac3e5002206e291d7c4fca0485dd8ea22519544ac632909d706741710a6e5f0d472c0b0656412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50058421" + }, + { + "txid": "a9cfa2539cb07c0903e2a01a343c6ea8566bc063b4c301ce2efee45760e36448", + "vout": 0, + "sequence": 4294967294, + "n": 111, + "scriptSig": { + "hex": "4730440220485937c55c67c8eb46b94523cb06f9572ffb55094536d8b1a458c76b67dec75b02204e5007f610e491d043a412696d4fd769bb2f5d8c3e8b3a59e6ec3bb598f775a7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.51645868" + }, + { + "txid": "62466cac8a8cb05584af3ce85d0eb8d4a5edf644a374aa23989bfa2adad2d8ee", + "vout": 0, + "sequence": 4294967294, + "n": 112, + "scriptSig": { + "hex": "483045022100b430528ddfca4431cf5cec08964f7325c036fdee55edc0ea0181d34ed72469bc022074b75bfa66dd4a87fab93da0f2f0def65b785fb0b51fe07355799cbd8b30c39a41210316d35753d58318c06d0faadcb723563316847ae06019984f42f2c75deaf3727d" + }, + "addresses": [ + "bitcoincash:qzl7yg7fxw5ls4jum50st5z7valsu7qa7v63ks2730" + ], + "value": "0.01579507" + }, + { + "txid": "559927367907ed4d3822c2b4c0dca89ba2a4df844daa1033123e9939c9e81743", + "vout": 0, + "sequence": 4294967294, + "n": 113, + "scriptSig": { + "hex": "483045022100c6ccc3891fa3924c7b1e69b855628230c48d85d1e1331f037823ab7c5928610c0220050c9c0e078f34ced537e88f95289863a663b28488880f6ada3f1dbbcb1743a1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50110065" + }, + { + "txid": "7b5bfd94b29844e13c3fce76d9579dc7d20b3fa0ef15309714530152e4d5ae85", + "vout": 0, + "sequence": 4294967294, + "n": 114, + "scriptSig": { + "hex": "4730440220168f31f413d65ce64bccb62390490dae2e4a00f98c2c44bd4fd689cd942da8b1022006f1b2aa4fae9587c688e8b7ca5c07db3b3c3afd6961f9f843099ed30b583369412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.51309649" + } + ], + "vout": [ + { + "value": "0.00032902", + "n": 0, + "scriptPubKey": { + "hex": "76a9149a262d0621819c8c17d34a7feca1b39b39157af988ac", + "addresses": [ + "bitcoincash:qzdzvtgxyxqeerqh6d98lm9pkwdnj9t6lydxqg82t6" + ] + }, + "spent": true + }, + { + "value": "1150.6730235", + "n": 1, + "scriptPubKey": { + "hex": "76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac", + "addresses": [ + "bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7" + ] + }, + "spent": true + } + ], + "blockhash": "0000000000000000023414a6f8ec13dd4f85b3fb1c71b937d5dcaa14e350cd4d", + "blockheight": 611623, + "confirmations": 16330, + "time": 1575319726, + "blocktime": 1575319726, + "valueOut": "1150.67335252", + "valueIn": "1150.6735235", + "fees": "0.00017098", + "hex": "0200000073126b74e8eb1830ec84d26e50d09360e120e92956c823afdb2e981432e60e152f000000006a47304402206f992d73dfa7e518b00190f220ad5dc7b7947b1d75a2fcd8251b59f3d29d89af022036c6c44f52f9aeed406dec72a9aab1f82c3b997c36742f4a3504e4f93e6f8557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3848b83fe17d5304f63a9457a5749ea2ca1ea42d9934cac890666e2173a80b55000000006b483045022100db30ebe47536e42115a507f88bb8d5c97b81ad05ce334872235811134c5948bb0220418d77aed78cc4a332b1858c1d2e9ab169828b9c12e8c0d0f8d155964e5d0b8e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4321b2ccc28666c12200bb15a050a513976487cae0a01205cd30ca10988d8ded000000006b483045022100d30c9fd598613586d8d0460fb6c9ffc1d0c6dff6f647535d2a9f69cf373193d102207fff687aa035910db124adad8b59607a72b3d24aca9096217ec6b90fa132a2ae412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff32a0d8da2143d7c4097af72285aff1305155ff5e05276badc91839d5ac9bd7a2000000006a47304402207b30e99cb1f6754d227a4511c5b7791f3b896724b170716d6ed238017f191bb102202c1fadc4c572c86288b002a0d6b6d2460a14a6d3c8b49efc17a03e59d2db18e3412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff62f77994b08467f9a90c1b7b921306d7e48c18015aa53aab74775b73dc79069a010000006b48304502210092b7f176f182936323df8e4359b2a329b0c1e4b48a529d6e32867038a2a453cc02203c24a8bb46b7fea4ef5c78ff116a51fd0a04dee25bfcdffe856fb8988a7a97f64121035b4e75dda9fb0d55d856f54f24fc65da6657939b9559ab2c623c8ef325f14d8dfeffffff5cbff5ba887ac02cfcf6f1adb0c84ae21cc003667734dbc41ddc31330c7c555d000000006a47304402202a2bcfdaf12c398ed5372e6b168a786edb8972df1146b705d3cccf2d9601517d022020b90ac89d9141d68817850d1cdffaf6c51f45249a44fd6861b361a6025d8ac4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffca0bea62231cdd9cb231ced73fc1c0f51c478277a077a55aeec113b506e7db61000000006b48304502210087ef2709b9fe8e7f136219254229edd45e94c3f6ebd2bb149aadd9b1d44d89e202206ffde3c9491c012832967e4d34e02ece2c08bc4c07967b3b466d4800f9ca0746412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff843b9b8e0072454494ac701e9f0816590de35f53cfe960aa03bb4281128db254000000006b483045022100c7dbd1117c57eedc8fc006e818371bfe6399c4d25e8b40482c1f0858a3d98a4b0220426d1196513a87fc7afb5b107b770a90af789536799a11686eab96b04afa6326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2301458143bdd235636b4a15f1ce7fef218ef401e26f5871d26bb28e632e0c75000000006a47304402203604fbb20824443899030d2c1f5cd0dc2b88174929861a708bdca878868e910c02200a607b1da53483bc95d3a5c54e5ad66e459827d4ecf8b4ef9909e9d58b2d329b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff9ecbc5e26870067db7ee944b7fbe3fa99c3247e0614fa5bf24a9eb587c36d9b000000006a4730440220399c36174173cca01f6d6a234a935d6f776b549e1ea2fc2635193924c4ac2eb002205aea7741fafd95f862588c480aaa282d7a344d32d6318aec1a908cbb939e5d0e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff9ef492949a0ba873b09258961f35cd18d78849cd290fb93aace31af829da278f010000006b483045022100da9075310e7af59456423be99362f2cc686d50571e0f0b016bcfae1f0bc4692802203379b648d47704dba48542b8b6d5e515bf3c4fd7ff8a7be82cd0c8c0c7be56f7412103a344a84dc1a919a64874605fae200861b7af3ecd02dc5d52dd00eb6f8845525afeffffff5c5f3037b499d79505425804b021b76dd94e1632b6747afd059d0a728ff49b10000000006a47304402206cbf93634d6a477a571fa2884c19918b19ddfb008ff9fe405954720047efdb88022003e755313436d406dddfe3cfb68719e8f39e43de7c586489cc543dac0347da9f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0b183fcb0f29cff3e9f22ff47a5c87694199ec43b77930f7b17d646f3670e5d3000000006b483045022100f23d4cf11fd0a5ab83dc053ca64066cbdd2fb4107e0977a3a880c68a67636f7d0220220a47c66d3944cfc309c059fe8013c4de742e4d8590003fd56c5e0b3c7da557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff80540561a82abdba58b2ac3bb9bf9f1064106b8f2fdcb63d462721409af9056f000000006b4830450221009f522beef55cbf8c7f10e88739846f78ef1c9d9cbc6959dba6f687a08fec0ef502203a160231733b87c6cfd8afd148994c9b6c5d5db9bb9847aa9e60938a6e79d5b1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4a4a1e4ea13377a0819a88e2664facffabd92566b83fdca3456267b017b7933d000000006a47304402201f5d29be80192a752fe28ff141ed702640df88083faf3f9573e52405cb4bd79a02202d751649aa600c4fdb8b1d1b21f0d134c2f4e5af9ecbe7d87180d667140f0a11412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff9b41a363950ab3e6b769a4cd97555d1d8336505f3c87599ebf7766642ec97ac7000000006a47304402203f4bea3816d252cb19d4247f587a146901c74d04e783efddfd5089942f2abcdb022069012613c4ee4b3b0212ae71dbd2071e01665148697011eb03eba25431e679cf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffab050b7b334656d60e2c9772a3820015a2f6a7cc3e2943897b0c027edba3cb90000000006a4730440220782ba77287116d5d735f67a3738fbecc1a802d2141a1fa544f61a5e8ba682a4402205473d68019cc8895ecb1d87bfced62ddb6dc48b81152f2684ae8530122d5b41f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff26dd82e448134b4105f561b681206a059e1de4e5690453dd8e4d9a0482c35ee2010000006a473044022044ed9bfa8674d7e83112fa22280797169d45bd971b185da2413e36252637529d0220531eefc480e0911d6ccda42002942883149bc1cdd1f3bbde313751d80bcf98b641210328ac4ed2b30ddc04c778a78b24e7256b08c55758c1465defd997ff4bcefacf10feffffff9e2e1b53ecf545d0b0cb972553deb89f3cce7e9e92d0e0a786779df0df48a113000000006b4830450221008cfdfd352e268dba2022e7fbfc37a90401c40fdf6f1d8ba9dcb97d67743eddc302202c0a1b604d34aa174fddef63c9115c95465548855c5f783bb206eb4ff8fda235412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff9fd5ed5458cdbeb26b0126512a1b1f1aeb85fa7b584a0568c674708fafc0d70000000006a473044022001b33b610b8d742df2ad98679f1e41f0c647faf272e15e7ea93171ba29c33bcd022061646fbcb81ba30d6e8b030ee12101d1f1bef38ba44a6d5daf40c4ff6d644e6e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa6f2a72bf25954904893198f716f7b6f07e68bf35c12c233aa6d165723931068000000006b483045022100ec9b6bbaba90d8902ec8a1ca0e90ea594264bc1add204b756cc89def4d7e9a2a022066b2bc84f94e1a99effe0e929be8de8669631143ca20c73e700d182ad4884e71412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb38019b996f974375732d741fac543bcb46670b99c566a8a887c3f876485a942000000006a473044022057117591cc465c48da58ebcb8f57fcd56359757d41e1397e45b5e33e034ea5d8022001de1d78ce9e8e73370a0778b4a8595045c6faeb2497ab4296d0cff735711276412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbd0ba68d3c24402ccc4d2c82c4d11ba0a794bce9e9d39f64668aa4b5956eb5f7000000006b483045022100dace56650d1d9edaef30e8c9ecb4b78499a573984c8a451253295a90c84a3ed702201f4587d4a760cd77a2e21d5f6f2b7aacf668220c8c7c62fc1ae4779f7c0141cd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff143d2c0bfb63e9b52766c0f7921d06a1d51b90a770b64902ee8352122c918bd5000000006a47304402200db6b461a0082807f59053bea210d38f5f82f02dd63a57f6e3987339cac23870022064ba927fc11b36318785d4e861a7f94cb3909ef8fe882360e2041f7b4a444692412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb0b7e16b8502ccd5ce2ec06157803e5c84062f5e8e4804a633f9e809ce260353000000006b483045022100a3e75a6c7918db32a27be348493b831631856ec8f546ca43d143cdc3c1cd03c802201e6ae036423bfce45c500b0c049f68396deae5cb999038de61e972ccd4cba5e7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff6d284b186e26a4116b02e6568c2868ff13408b85c71db1495a5e7cd32a4151ca000000006b483045022100caf952ca1760052cfefe8df283fdd0eccb9e1238eea88eef287df9404c622e8b022072027363fa1070548576fbf9bcbddf2e435fd020662b2d8f0582b52bfa487b31412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff38bb6ba6ccca482c333c8fd0e35afffb150e4c99fdf70513175f10bb8b263ec0000000006a47304402201a4b4efff2b70a4039b4dc120141da04ae84f63906df10c3cad08838c01b6b8702205a065d025c338547ea07b2095ad31252658e57f1a7a04c7f4eacc0248e611fa2412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa326b367f3405c7648e8e12b5bd7078867796b60f70cd4b3123442a6fcb9c846000000006a47304402206b0a876d78793710acaa8bbeb58a2d908bd4936f2a88825f944b190041b5e0be0220279560be5009e4a3fab44d08f4748e2dead710a8ccc77e06a03ba8112d728856412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff746bb13f09e7c465f9ea0b264c601ef9652736d83ca0c78686ea25326f6bdcfa000000006a4730440220799bdb7ac60cdf3314cc1f157299858d353e22c00354707337ab5b497619d626022000e41053afe44fa65227b7dd8498300a2dc89367d9daf0586caba5bffdfde567412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8da9008652012637c8bd2a3e6c9b6b6c4e12e67126ac1e5cc3b1d42b3c16b5ad000000006b483045022100a1af33a83edb7fdc289a48a4f77cf286a88b38c21ddf27dd4ec3df007ce11046022074dd56730730f958039efd70edfe7e181060fec306c6df4cf75209600ebebed7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff84a1b480079b2256862090844d38dcd463315a43b757678d7002cc1d01001adb000000006b483045022100eff445419ec63d1e9f51a5324c3be0315911b39f30657639e84ea7d2f739e0510220218e73140a39542ec8055b6645cbb7989f96b9d9a93c67549c059509de06f0ba412103dd71b53aaa823b09a68aba30c7603c6a397e7c183f708c9dfb0d9d0a9cd1c722fefffffff8872f26872ae96f137ba029e4ca6d19072f8223c0664608eeacd4753e8969df000000006a473044022050b7ed06a6832b8831c08ba86049b3793b5a71fd6d5177c9f268b79c3074bca7022047447c23429de30c361875642d9058bf1b5e0e6c5516d6e71b70b7cfb29827aa412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7ebebf2f8b764657a719cc52e3ce31fa79c37cd2d583b7be31ad9ec2ebef3284000000006b483045022100fb072bfd399dc11191ac449a9d60119bd191ce6b19a5d92412a805ddc8d4b46f022021e463686560b15ddf272b9943d8e41425ed500f77698aba518ccf546a97aeb4412103e35c58a738805f53af73472ffb671a9bd3556ddef47c62f18ced868bb5033d0dfeffffffbaf05866b6eba762daab7778d4eb3fa1902346491f14c8ec047c12aaae4cff29000000006b483045022100b25e7d4ebaa0e7d8e24498b039e756d568b67316aa14d05abafaec59e216a73d0220010d0b6548a74435907eb0d548dfe8e52a949bbb785eb2be3bce14053953784f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff1330325273e9a1329b3379a553ce95bda9dbd7b83f93fad4acb8c1dd45f4463b000000006a473044022007d2baa9a766c120e111a727bfa8e8bc2e01cc285d4d4f67d2323b213525a10c022020f32be2d9935b6d9b5091db27ebf00aaeb54adc7032badc7ad63f20741ff28a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff44530eb5b53868de4819fd0dff26c12e2759f4696ce114e22855e88be1b1d41b000000006b483045022100f98ee28ffb66acd04474a120904ec1be2327d727d8ed8fe99d8b95c174b8f46a022041d21406dd8df10cecc1d6435de68fef3f9db71838c1ca2910895bb184b4a6e4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2fbfba76ef97ef4c6e575783e08baa25da64eed6a7eb4ca48707feb7a2927406000000006b483045022100ee3f7961f0f23137d753affe85b777e94c1db3f656cf41b8f59fcf82d9226eb7022025009482a6c0002e409590075caf7a78023ebc1457f100c8b922a4974ebf86ba412103f1d1dd7685d3781f58f9aa399a16f6bb9ccc7d008cdb7c63a7945cfcaa6ba0e2feffffffbf525c080b8b43afd5c004b40d25a7ceba36207162b2bafa70ddc95cae68c1bc000000006a47304402201fed9da4c0526ac5ce257fce2b7fc995646b5f0d2961396327f93e2dfda3e4a0022035b217adc5a9be2ca34f4361ceafd9f2d09a6fa47d4a767f7001ade40c08fe26412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff327b0b903a0f60cadd0c8d2e2cf774ee04eee9a40bf5c37181a471045f365d02000000006b483045022100fa8ee82d42f524290319fb3ee47a1afa70cb952f8a37325680d6fd651ac3699f02205ac0cd86fece03ca204bd881d67ccce0cccbbc98704d9e955e2f92b5b77121dd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff5fadd3b92b767baaf2a50c8b21f8d3f7cae103e7b4e4c0ba60f111d45f8a1cc6000000006b483045022100f3cb343c4704bebbc78c6492dd72ca19c388b285f44f574dcff25f993add6d5f02200e050dacd78de955cf552f9158beaac5fa64995f5bf7c8a919a231a39425730c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff47d0ae39a2ce683261d30f45025b7faf667146a980c1213b593c482647d77d20000000006a47304402203f05a035f5d42fbfe97172b431a613110ad733e356ebfd08886fa11bedaf1faf022061c4a3bc3417390910612bae46f5acf8b6e8a5b008d273a52e483a315bfb950b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff46cefa6639796b89c5e8981c42a230d8629cadecfca5dc853c85e782ecafcafa000000006b483045022100bf60fbd4716339bbb42ce150966ad6caf90b14e57f45eb6804756cf8ff36b23a02202f16aaecdb9994f3b683cc7fab45bd0a3f54795c336b5fc224fc51270a7f3f4f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4e5c5b111998d7b90d46130f2ef29f25d48e8649eee14684cf6d46eaad3b7026000000006b483045022100bcdcae99c9289b5fc89d3227daaea8df7d0a0f3a8971d841ebe1ab7a1ecf72e202202ca21447a6b3e96540e32529697d523b7b08c65845d6a13f6b1475de94919bb6412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff489efab51aaeba5cfb24d1484a917a33aff79b7455392ce21a3e642a170341c9010000006b4830450221009535c27b5bbca0db2bcf1a0d0b3b283a2171df53f0d68f1a138888fcc6ddd996022068af19252ac4376cffdbfaacb2e0f0c216deb7e2478b586abe7c2679501eac34412103a47e5dea4ab8d785f4e00994d0faf1a8f384c41e74ed8e4b776fa6ce136ebc42feffffff7eee285c72768622c785561839c699b1a748f58ab418615611c70c9d70440518000000006b483045022100b456847e29f8a648730f0fd34cc7edcfb35daba866ab7d800472beaf2836ce4202207db401f0a5e30efc53c7bf58e57d1dec5874d64768ad9eb4895351cc4be9226f412102291b40a9a927dafeb53cdfc7e722ee5c9dfd6eac2d81331678b9ab405bb25d21feffffff93b0226e9f90d151df423d9ff868513f71f708e715cbcb1b5444f4a0194bc267000000006a47304402205ff244c77726def0e3697a3e546bdf74c7f31479c9d01a7a6f8cd1656482d537022045d78dba8ed4d3777f473736daedbdaca6f5698dd306898d144eb43f96259766412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc784e371e706c6de880fe3033039cae758513a73866241658a21fa6a8a4a8d20000000006b483045022100ec6b35ce6d24889726480d70a31bc0d62800bf7ac49ecf084b98137322606bca0220432d33e2d8b508f26d7d813d18629453c537a4d90f73a104bbf80627f9fe8d62412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa4cab40c510ef0ddb8fc3612af871512805ad7ebed2b60fecbe7b9d0f8eea760000000006a4730440220423ea635717cff512d9262b7c8932c0122ca868251f019ae033101c28771a52302200cd3ae05f2e88d9f64207beb4b715ba480bde9ffdd40ab61a36feff88f2968d54121035530745f3cd4d31532991e460bd2a15e1944e690643f73133a9918edb95da53efeffffff852bf329889cdd85945b23bc6a338562c151ecf16b04414c75afb1cb9ded3370000000006a473044022055cc4dfa48a79b8584a9352be34ab5fe9cae4132d264dd827d14ae06d35ad4090220652a83c93505f8a8527c5bc0479f37da0593595c1bf18c12b8fa0b41a2e37a64412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3235c14d72a55c47d9b996588c7110e27d031013e1f2c77deba6241954059f92000000006b4830450221009acc8d0e06d10b0c764a27613bcef41fc75f910875eae3989a7f8725f81814cd02207146ff66f412910ed993fbda4ad6ed48862a02f366dd88a83856a17e7f96d83e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa0b0aa12e3299ce6c925827b3d5603676949daba619fd9c7bca247d1c265e9a7000000006a47304402202d8cd72290f04063c0ae9bc06d2cae3ac74ef4cb6945c92c3e3ccca210c127ef022030471726cd87ac9d55f3d246095f64ae22b611aa8791922236bbdb19ec273322412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc856c10b1d42360a93cf60fa8127afcac431417ccb7213f649d45482fc7d89e6010000006b483045022100ffaa954e5b86d54ece9bcb9e37895047221828ca381b03266de3d9341599c8f902200ea1c5ed36e893df822c698a474b062d4f93005c32f9d2f0d78ecaf5a56e4fbd4121031a00f43cd99e015c72acace20ac47d887a39ef284f89a5aa09abd968d06f5e9dfeffffff69129065f6f989f1a008813b345e8cbd881a38107b9a0af3a3718437ad6e9cd6010000006a4730440220457d59caf24eb6e10664d06f3e936f6ee31d9d59f1cc4f6f62788f022bce8c1b02202ce7c37ae6832b078c1cb9a055e3ffcf4674081f0738fd9c3eb4465b52bcc9ca412102fea9ae922223f2c68c68d7672b7656885c3e1321d35cc8f5f445179df6f7d27afeffffff8ad3038c3df6f210fa389c57f72d240dd2da53bf172429620e64758a28a82a21000000006a47304402205e0f5cb06f7fd741825c669c87e9db1a433913fb8577adb92b779d3a693b4f080220120648a5f9d2abae83a29cd2c79f5c61b9bc40da8990736ab97ccf6f82c586cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4fda56201530659af45d3f6ad8704693d321f4c92184403e848bf4c3eb1a6a3d000000006b483045022100debfb215f94e9d784e91fe0b9d2541d09a4c7591172fad1441506db4a3590fd102200cce728e344933111c9548162e62872fccac624f6f98d92ccdcf98dbed09ac544121039b8a20c23f32f5b14e76fb29e0baade695810aa7b6dac9e9638a8d13b6ad8221feffffffe7bf81c3288f97cccc60391101a6bdc7654a30dbb693a9bcc8a4b112535d5891000000006b4830450221008110aec39b127143891069590fa0d9e1d8b41bdda70d9807848eba92cb48736b02201bcfdc1a1cedfa4c53efd941482f6157774b2aa80af44e500263be6a3cbcbacb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4c686bfd13c84da78ae379b1cb6974bd3cde55fffef59f28954095903cd2b3b9000000006b4830450221009f76d6838b8fd8bb74f50c67920fda9f28054d093b30fd03b54b3fb888db046f0220307944f3abec07c3570614f418056aeff03c0830173c963bb0b65bd5ef24b4a9412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3f7108134b932ada8356748fecd11ce666f529c25e4aca3c4253f77b3ba6f965010000006a47304402207b93e2500b189b51fbc3a49a191c4b92ac76e32ce86f6f1b9af4afbb3a91fbe002200b5617cf52095bf882a5129f5477f119c9c565dd582a9f19493cf1bdae6527ac41210323ab0930ba40688e66bef6e08f673bd6bcd3df687e4c503387f48c24bffdc93dfeffffff7edff321567843351e47d6d3bc8394e2cace9fe3b72c4dbb152bc54c6abfdd48000000006a4730440220731ab37e71d9c6f63333ba205a318d36e5847706381f571b4b562e5e6f6e403c02200704ca9d9a33843d9a16135f56eced1fd18e227385671a8df5fa41e505e3ba3c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff71294d7e9b11e4e36de589c91122993add9030771328f27215bb55c36ac2750000000006b483045022100d1d3565175e1f529124ebba1bcdf8c1704e753c2f91ddcd1a093b5f5403cd0ed02207420ee9d6082356cba6d8075b4fbf310bd84dc770734a8ab30e74741a779bae8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff423caa98d71896bcc3bd086cc2cdbea476888d19a3f3b9d2554e82e1692cc93000000006a47304402203ddf5c6c5065f03229cdf837d9f8d3d22314834b006e0aba8dacabea206b3b150220417c49c9095372d3dfd954688bcd43fdfd2a121989fde18456a9428b2a8e3c63412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffce3d664bc2eff728a9ea3134bf11d8c7e2207ed508e7879ec7ecee976eaf72c6000000006b483045022100a20e6aaca7df2b142b768d3b1cbf8f783f3d4997d155a32f0e066b4255777c9f02206deb15cf53d6b27a973df9aa7080691e5914538d9e97ec7c6e797ce03333238b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb8f5dcd6f0fb2ad1db921e6f79fcd9fa463165091761f9d8baa23673a0a0645f000000006b483045022100cc2cf5c6c2d4862dfdf65407138684ba45565bd8ec46594ed4586bfa37b715dd022013255b2eb22f5bb93d2afdd07ec4c3b5efe0aa16134b2fd084c6bc720f8cfd5c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7c331f8d0e02777c73a28ae441e12de405bacef5ce967761fb521786d5186b25000000006a47304402202c9dd98c9a72e5a8df4b01f09d18e2826d8b9871db89c5d3b24ffd673facaa0702207523bfcf3ab80790167a2b1159fe268770371fcc7d770995c19eace3181ec8af412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4cd501228a577f0662b802b5b197921268202b8658e4aaab7cf6ecccb93cdaae000000006b483045022100bfac8828df10b7911d341c15a532819c429c7185d8883de19de84e71b97d78730220177603a3572908c90dad865770906b5ad228da7ee5da39503ececf60ac735158412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffdbd64011a7b6fe85385fb207b347f02f5e047b7ffd55bd4192af5ea979e2110b000000006b483045022100d598e2ccdeecfdfea9d5139a49a94fa39414f9e1ecb13d54efeb34c168e58aec02202a59463710905613844f48dc71d316c0cae54ab9e16dd95beb8902e5940024ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb90e762342456c7032806bd546929a38782761e2ee29e7aad37778e1ab6e0282000000006b4830450221008302d38e9eaccaea812c853047931562417a3665b8b9373cf7f63e58180b002602207ac8fddbbd19560a74333ec92fa077d169b4902a41e0431113f8fdb75b304ecf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe15523a831db30cf60f16b15dc338703a64058fa3830c17a4314b4ab824ca943000000006b483045022100c0d85a1f9146e8ef9efaef8ed9b3ed09c55e51b25e189735610da89b6d212360022003a49114e504741befcdb95d52a3dedd1aadef68b7c48f0a4a8c7dddfb4201b5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7893407b6997d973f52a924d03ebdfc639401a138c13e12c2ca365938135f841000000006b48304502210091ec8402cafd1e7eb11b56ac56a994ac79c435893108d0b7c8cfff87c07ba0a602204fd98efddc1b4e21bd3cb81217579a7b9621f9c3c204f2f5800e75ce1c60b19c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff016fa30c4594495726151cbe044ad53de6421e1f28e2366602bd80a3dea98c2f000000006b483045022100a850bf088a08baac1f1f577da8946befe2e6b0354d6a29f636afd39982569a7e022062652d6b75dee145f741d28d6f1870fde9a7d66b994f0d3162abdc42fbf54458412103ffdeec10b52942b0c46d6578998efdc1d64073de579e92e7c5dfa97fdf3ac391feffffffd8659400dae01e9cac6076cb19facc050061f64b16957ad30500503c24294840010000006a4730440220762f7c017672dfc71d487f3730e26d69d0e53902f579ba348095ca164d27b094022076c7e8045ec9fc57af6dd95f35c0ffad2c0ca8f83f112f60fb9851ba4ba15d92412103a2d2d8251728b11fd4afe7b8c73a8442f76dff9bfa424f5cad9b98083936259dfeffffff642ba174ff1ecc14e4f086d70300d487dbaae78bfc684b43557f9b8ad2ca2426000000006a47304402200654032c5760f8b94cc089da51773447f19c1cd2108cab89bb53ccfdb6dbee56022015e277622dea4bd1a7913ff934b2bb2d1b3d75f05285b51690160e1197a258c5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff654d602ce9a224bbce1fb5f9588977fd780591457ef11de271137ca7fd3c3b89000000006a4730440220712877c0dc553096eb0ebf101d1555fda5235db26ad074d2f330163fab63fc7802202c89752dd7645e8a3da7e8af5fb68dc8b177700766b79cf6a35695a0c7c873cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffcc614cc3c1c12c9b8cebba5d78a395f5347a5073211a04e03d55b0a8abf386cd000000006b483045022100f3fa1e305666e2a62afaa11fd37025b25c0bdff8709fe1580406615934228cee02204841a7d96f36d3c183f06e22a58175756c3e9a76c93c7cb4e9945f31ddedc902412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff26b2ed7a5c60815f5b62a5d30af9613e69a26e8aaa429be689baddb562e88aae000000006a473044022047c158e3fe3f40de3f39796dcecb7df3cf344f14009de9826b62a43837f2cdcb0220759d823cc145fd5e8b651a7bcc399544692bbf596189b1fc50bba5f4ca02cdd1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffebb012602f05d2bea0016b8b304f59f610922671560469d80e0e913cd2b302b4000000006b483045022100bd70744c867943bc3bf578e192c8a87a5ed5126aac4acd98efa06ea2483911fa02207377e11ae2d2bbaab00da86ec73c26e596bfcc680c0b8eddc5d44bda650bc299412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff87809cf57be510d02c71276f00544888795f624f33d78b01ba63c87340dadee1000000006a473044022059ee25066b8a2a4fdfc35f14c5cbb7f22ab181fcfa9702d4f3de7aa4d738c7a402206dff315ad1cd2222cd6ac074bf34241fc22db38a57bf089f7e24542323f1766c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8c33b7af2120bb22742f4a5e5fb4ecca7cdf73a33bc8811f3d5d3d1cd9399c21000000006a473044022039657cdf4fcd5a9e81766ba11db495b8be5664612d3b91f8504bea342c4ecbe702206ca4913e5807cd697d30dbc93e0a9d679eb01ee84b687ab0c642e2f3ebde745b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8142c39bf2f91bc685f7c08e40450c90b36dc0a6782a764cded6ba744a591f3a000000006a47304402200232ee94873317eae275cf715f4c3aca25dd0c8db4800946a45cc1d9c45732fa02203d9ce9c9aedc0a3899dd027df32e683438769d66f33ffe52006454614b77821d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff503b9a4c5cab71a66b685d3266002970227d0f4a6b1c65b86603b8c8e683cf14000000006b483045022100900bdc6f705efa56449a65f15a67fc7fbbc102f78e7974ea6ac2849c75d2dfec02203b78de71dad2e3f6ffad2779cb9007217c957c8f5db7abd58fd0537fbabb8c6b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8bed144f5515754d58c273554d25637ec776635033c9ae13bfc94e4b6cecd11d000000006b483045022100becbb21c7937b9b27ea3cdac5f2048ab9ac314de59c3ee2926a5cfb258ce14e902201c8022bf275c1a761e7715b14e15d74526901363ae5f8bf5489d00908dd758eb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbcb7881db3ede1d9275508f97b9f1e0e008811ce540f3b42a921e26f6f065799000000006b483045022100ad84bcd69a85a0d487fd7cbe4d76b95bffa303e76615a4336419fd182eeae4b902206d21e4f592297e87f1af9e19c80fd978914aaf5a2db2cf499b72cabbbe73c831412102958762ff6c8985dc9656afda59e61afc6c0131a5d8f1d86c87c83c9b37f7bd18feffffffb7ffae52888348a77a9851617df104a29366126e01ecc6bf7d209fc8627646ca000000006b483045022100edfd64cf9335d094d5873deb38cda5f4ceda3351df722f1c718993a2dd12c8e302203126b0f9470a4d0867ed4e773518b8ad689ce43a2c9f65a1f297525fc22201dc412103f37089783028c0776f2b8a9d8481ec8d6d0652a31edc03cc274032ae17c63c62feffffff801a88dcf5725d71cc70aee29ec937233f7a059d60e068dea3b7dbc806e0fd54000000006a4730440220448751a749e7cccacab0ae1ad4da948b0e0b5d8e3f41ac2b22c18928e8e67d41022051c107c345c06ea82fe8329a8cf3a96b516fd8750611d8ef438b8545416398ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbb06af741ad8b99821ecc4dfb5b52a0a79b577cf213eb9335e920d13707c8da0000000006a47304402207f9b2802ed1e893168277204b7919ff479efe5c71ad2a255e1738a52bacd758f0220253780485f2e3ee960e058d449c647b147b8f64b49b913e7e9615a6c7114f18e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7827759ce0800e385c440c45ccf6c568a25139aa0f1c80b86f28487ae6a8c0e2000000006a4730440220778fd8ba1dd9f71df55bbe1c3c4185b8da21dda82198546c2a0c30250f4c1d66022040f17a46187d535c6e943c047942f45159a37b2e171db18c657cd24168c22e2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2af935dfaa292af30d0a39a548e81640765b624eb5213d964ebaaa81a3711922000000006a47304402202cd2fd29fa395a5a80893de065c8bbe71e0bfe0e7b2224cfd5684736a086aabc02206720226ba63a3e5d9e2dc67e404625cdf31a7a08da0e8a22717e558f7abc817c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe3e3b78cff7d4798f6e3c8c45d87ac2131913d1328947d6b4ed515b3ab2366bf000000006b483045022100f8769b797386f0bdd662483096f4e0a33c13f6074a4aaba3fd590b9abbca7c2402201eb064869fcd17a59ac028145b08c73b3552544cd7fc62245d1fd1d369ecf765412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffdc319b5c9374a41a08f5f3bd45480a968f651878cde667b3ee3714f72b836be6000000006a4730440220558e65fd916d9c9616a3e0bd41111dba3914867b1ce5d487df4f77feadc0059502203198566c0d58af8551b65f884db98bde161bac140c7a900cd40df97a40c267de412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff69406ab4a28198623b6005bffa68588fea73092364cf2f7a223884c3e0732845000000006b483045022100ca93287feb58daad47c5388067b219e44f8533a214eb8eea9b5313040579773002201716a6ad2de70eff6721ae7950edaf9230420648bb8ec53173c215cbd12246c0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff21e5177112fa1fb5797389490a4f9131600673f139a544050a557fb627b0b360000000006a473044022003240fd71510800910b448c62a03178b4ef62299b17d6d2c06ac8f3293684ff50220637e3ba59fc884a8bd16aa2e884b379d85f38ae4ba049a0365f33644febee6df412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff5488e67a575ab8556c748fc371515b52ff28eb875586eba99fda2b4389e4f96c000000006a47304402202e2ac9c8b619b8e2626895c20f6bdd1a24fa27de017d05d5fa2ce120b3421f25022053ef6f82ccf9a132d40ce566d45f4ec18bf30048d415f6ec1c783cda027b6747412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff03abe81fdd0362f4fa3bae282c2ab1be258882d83392229cea6e36c3f023999c000000006a4730440220352bdfe541e9e1ce428ac4eb4c8ba9391a118b7dbe57b4fe3c4ecd30f228fbff02204a0b78ada1d74a7e7b9ae912e6f445d9ce9050855d9c5ecc7d477d2590a68b18412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff879d7ac96bbdcb9aff885fb27c0f171277a313ef45b8143e04b74d6fa43fd25e000000006946304302203f767d8f64e3c9e5773d94a325f8029d21d1c9a0f470c9288cd99f70d2d90ec2021f50b395f9329ffe64ff8084c1506e904ffc02dfac7f7e15461c3e8a077f604c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffff00dc8aec564568fdd9114502ed1998de08228bfe4edf74d132cfe595c709fb000000006b483045022100f17f8045a627bf96fe09d868109063d8040e3e2df8944e05f9b20a15273d0bdb022059c31e2d849abd57e784f1a3903f49f18c7c5a624545bab98649e8a092e12a10412103ee2a3f78cd4930dac8c030ccc93381ec5eab259c1607360d85d1728fc296dacffeffffff3f25af68c0083801bf09571e1a300d78768df58ec82e2961a374600bcf90bf36010000006b483045022100b58c7dd3fa1f8dc50edc7b5546b8ccef8ffc5c179fee774999c63fa729ae3cef02205eb611cc887e5a62a4e9da33318ce6e216ca353225f452ebca51be1dd10f544941210267f3c9b9bfb6bc5c1f68dd1d18623a9986408202cf232ad1e4089933c83f186bfeffffff6a94e760788c3ee1c9696e5552020afc2a77bfcb3b2223e35744f1b9abc49b25000000006a4730440220097f46c588f37ced4846a45905df1a0ae22709760f8a1bc930a58f5054cbe482022053b418af66d1edcb3887616feb23e5dd4095f29e74ac89853c3b909eb42bac34412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb26042d45f30556ab14a69f8be4ce1ac4a360b8407d7da6dde0983f73123a314000000006b483045022100cf98e22a2854c7088a0572e1edb4e876aa622ed10dc0376806e1432f5dc1eef90220527845f8dd2522fbdf423b4fc34a4792a7f82e04b314e0d83e2425daa2f92115412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe5f0f3bfd4691a43d7488076a0e13ff739c72c6f421d6c0e61a75232ea36d8ac000000006a473044022070c7aaa7d7f050b1b520878e55db3ca491fb33211150e2f620b685cb49d7d885022022d9ede63e3b196a1c33c2d211c1eacf2e2411820ecf5155b5e4244f5dfd9f1d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffffef905cc2f8ca7d7885f06ad865b721f594595528c2b971b3172313cc7df8c34000000006a473044022018cd70c3e62563ea92ea12735e2efb4b905df85e6b290d573051f49c63d07c60022037a537ca3514121d5c2b8753833808a5e0432f1a8f277d91495953c8211ad326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff556c7570226e99590f0844c677068cd133f882c7a720f77f32bac2be39aa7baf000000006b483045022100a01ad9ec8d24fdf01eb203c2887c1413ae56990d4600a18010959f6df43de08d022056f0f0dccb8f772f29a7835d7dc40f242348805005b5f80ae8f2fbdb600ab2ca412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff52bec1a85abc7d806dfc9c39427b7cbab7be3aeca8ee99959c84b68cc05ca96b000000006b483045022100cdd770159d56ac518ecb0dc916df0da06eed536e540582680f742389f53fa4be022012d372e2c04176bcb82b91b02ea23c9c1464baef7d1dda66066bf84c402c0012412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3b2d0442ce89e456c2cfc586906116d280fce17bc310ed957d03b35c61e9eb41000000006a473044022001dc7db378891c1c5bf07a09d14fcc6675965976e2e3e762786b1b1e0f4a4bb702206db6f284dec835823fb516fad89543edd3bd7af3ed33940fa296939fadb41ba841210393ae47ec2e844378cda3630abe12082401f2e0f98d016dde2b152b42e335630dfeffffffc3804827d4f39c54d961dfe79e25325f59b5499ea25b49bfe7ac99bd7c7435a1000000006a4730440220290a5055313d68f9461ce830f8a7395022d2d55abf28f6b4bd665693b4a13730022035d4cc2a6676ed842027dd4f21d31dd5a956f4b1f5cf771b866cc0d4a6400df0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffd610149123afe34fa647cb0aee336cb903961bee6653b8eefc7f49bb015e0990000000006a47304402201fd6be6d72ae75b61a624c13476b538ec2f9e5146f3074c879af57ecfbe1679702200ab10ae612e7fe0f76fe943c1f6a02262008407f86782c1536e92e3bad77d3db412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff205fab854da34166e1d16d36ab90b1e825440f6c9067ef35d34c41c5e569b144000000006b483045022100a4132f408b5299dfed6153b7a331f9fe866f1b042e4263bf7574ea0964c450a202203d99cf8dc9a9194269bce400185a4f86f5d35b5be83f6dbc3166b600392f1b00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8ead5e6ad78ed4926b83bc4a479d4dc5b2dbd2753af5636044cb008f4c6df1f7000000006b483045022100bbcc2e2d77458abc30898cddc7eda060b23a62f0a53b81c3db47f284cd7b29cf0220705328a29bd30792a7f5a704fd74b771c3c8a099265f5e7c9d70046da5b03ff4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff2361f9f2ba5ff1e66349c365e1c0cd9c6cb80ab4f666e9f4777fc188a405202010000006b483045022100d2f40145c4b9a17b3582aabdf7d9ac2d47546b3eea5350c4e2ec1e9c2466343d02203354ce620aa056a749de847f867c49dd121579c9fc50bd6258bff7cfb173c5f24121035bf755e8b075665a85155618f6e9022196a09c486415587dd3af0d25b76e9c27feffffffc8f56b2dc9536ae2c0e11b2062edda6cb33b93284ce7bd8c6531591ae82f0074000000006b483045022100cf8c593dec0724644d034f17ccde99feaf0416334219f158f884badf500fc93e022035af1b68574e88ef15e1c05c1b36638401613a31aa7096d97efba6df62695706412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff95831f16b9696da7fe12787860ca161c12566d110c9262097434a7e0674d6b49000000006b483045022100a669e8918ba68754b84d584f38afdd34be387773449784a6c61ef3f33d0fd99e02204d007ef31f5a3a7c412ac3d2660633fcef137964ef2ff6269c41e933896d918b41210383b6491fd80e1411675d7c8eda9b756c30a814b45fa565b7ac24d7be9dedcaaafeffffff1e1184fc54a53f94ee4d56313349f586effea0bf553bbd0cccefe86c8d606f4a000000006b483045022100fc35ed21833c3ea3ff5f832ef02236a08ded0999ea367aa6eaaff364ecac3e5002206e291d7c4fca0485dd8ea22519544ac632909d706741710a6e5f0d472c0b0656412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4864e36057e4fe2ece01c3b463c06b56a86e3c341aa0e203097cb09c53a2cfa9000000006a4730440220485937c55c67c8eb46b94523cb06f9572ffb55094536d8b1a458c76b67dec75b02204e5007f610e491d043a412696d4fd769bb2f5d8c3e8b3a59e6ec3bb598f775a7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffeed8d2da2afa9b9823aa74a344f6eda5d4b80e5de83caf8455b08c8aac6c4662000000006b483045022100b430528ddfca4431cf5cec08964f7325c036fdee55edc0ea0181d34ed72469bc022074b75bfa66dd4a87fab93da0f2f0def65b785fb0b51fe07355799cbd8b30c39a41210316d35753d58318c06d0faadcb723563316847ae06019984f42f2c75deaf3727dfeffffff4317e8c939993e123310aa4d84dfa4a29ba8dcc0b4c222384ded077936279955000000006b483045022100c6ccc3891fa3924c7b1e69b855628230c48d85d1e1331f037823ab7c5928610c0220050c9c0e078f34ced537e88f95289863a663b28488880f6ada3f1dbbcb1743a1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff85aed5e452015314973015efa03f0bd2c79d57d976ce3f3ce14498b294fd5b7b000000006a4730440220168f31f413d65ce64bccb62390490dae2e4a00f98c2c44bd4fd689cd942da8b1022006f1b2aa4fae9587c688e8b7ca5c07db3b3c3afd6961f9f843099ed30b583369412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0286800000000000001976a9149a262d0621819c8c17d34a7feca1b39b39157af988acceb18bca1a0000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac26550900" + }, + { + "txid": "99300f90ced7d053b3b24ef3a8fdb5774418e616f07971366a63b9938944ab2d", + "version": 2, + "locktime": 609135, + "vin": [ + { + "txid": "f0202389fab209e6975199ec2d8abf76fd4cea5d7d441ea0938ff47a35366c45", + "vout": 0, + "sequence": 4294967294, + "n": 0, + "scriptSig": { + "hex": "473044022001b8ba5dbc580e3bf4419b65892f15423e8b0e48d52479fd0317fe4c03ede0a002204013a50c3914aeb7f59183f9e44c880bc94fe9c23045a6311ae4b07da3c2d209412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "value": "12.50016811" + } + ], + "vout": [ + { + "value": "10", + "n": 0, + "scriptPubKey": { + "hex": "76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac", + "addresses": [ + "bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7" + ] + }, + "spent": true + }, + { + "value": "2.50016585", + "n": 1, + "scriptPubKey": { + "hex": "76a9146932df2f990838523783075db0b985b9bd2330b088ac", + "addresses": [ + "bitcoincash:qp5n9he0nyyrs53hsvr4mv9eskum6geskqthlx9n4d" + ] + }, + "spent": true + } + ], + "blockhash": "000000000000000002132a5e60d7b9de0524eeffb36fc91972a7d68afdf17b65", + "blockheight": 611545, + "confirmations": 16408, + "time": 1575274423, + "blocktime": 1575274423, + "valueOut": "12.50016585", + "valueIn": "12.50016811", + "fees": "0.00000226", + "hex": "0200000001456c36357af48f93a01e447d5dea4cfd76bf8a2dec995197e609b2fa892320f0000000006a473044022001b8ba5dbc580e3bf4419b65892f15423e8b0e48d52479fd0317fe4c03ede0a002204013a50c3914aeb7f59183f9e44c880bc94fe9c23045a6311ae4b07da3c2d209412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0200ca9a3b000000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac49f3e60e000000001976a9146932df2f990838523783075db0b985b9bd2330b088ac6f4b0900" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/bitcoincash-api-xpub.js b/mock/ext-api-dyson/get/bitcoincash-api-xpub.js new file mode 100644 index 000000000..f707df5eb --- /dev/null +++ b/mock/ext-api-dyson/get/bitcoincash-api-xpub.js @@ -0,0 +1,184 @@ +/// Mock for external Bitcoincash API +/// See: +/// curl "http://{bch rpc}/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs" +/// curl "http://localhost:3000/bitcoincash-api/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs" +/// curl "http://localhost:8420/v1/bitcoincash/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX" + +module.exports = { + path: '/bitcoincash-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX", + "balance": "177672", + "totalReceived": "13221795", + "totalSent": "13044123", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 72, + "transactions": [ + { + "txid": "269d428f01fbe49cd6d2c2ca5e6e2f0ff68aece905313932156078d4341d347a", + "version": 1, + "vin": [ + { + "txid": "5536327a38fddb32a92a98582aca4e85b4e50f40b9d3c03db360eaca7b512f97", + "n": 0, + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true, + "value": "188124", + "hex": "473044022057e811d95dfce16c7f1d1da574ab4ca1bf883359da34a1e7a380f5045fcffc960220149c357343f0172301f06b914a2844d3755a3e990a236ae33f71afed52f0849d41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" + } + ], + "vout": [ + { + "value": "10000", + "n": 0, + "hex": "76a9147222fa3e0a256cc45823a641aa4060e66718276288ac", + "addresses": [ + "bitcoincash:qpez9737pgjke3zcywnyr2jqvrnxwxp8vgu3nnxf6x" + ], + "isAddress": true + }, + { + "value": "177672", + "n": 1, + "hex": "76a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac", + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000000e0846c675bda2ea268eaa290287aef83f8877c40f07743", + "blockHeight": 620315, + "confirmations": 7640, + "blockTime": 1580517507, + "value": "187672", + "valueIn": "188124", + "fees": "452", + "hex": "0100000001972f517bcaea60b33dc0d3b9400fe5b4854eca2a58982aa932dbfd387a323655000000006a473044022057e811d95dfce16c7f1d1da574ab4ca1bf883359da34a1e7a380f5045fcffc960220149c357343f0172301f06b914a2844d3755a3e990a236ae33f71afed52f0849d41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5000000000210270000000000001976a9147222fa3e0a256cc45823a641aa4060e66718276288ac08b60200000000001976a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac00000000" + }, + { + "txid": "5536327a38fddb32a92a98582aca4e85b4e50f40b9d3c03db360eaca7b512f97", + "version": 1, + "vin": [ + { + "txid": "feac34105f3f0bd442f75acaff6b2e840b9e2c0e32e897393d9d0fe47fe76ba1", + "vout": 1, + "n": 0, + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true, + "value": "38804", + "hex": "483045022100dbbf18561baf7fdb46c21d27801594209f2067f1d7735e245c56001c4e462d3c0220016e052ebbcf350bd64a257f7cc52ef23730fe50b24355d098f87c528fcd839641210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" + }, + { + "txid": "01b8958ff2a939534269d05af5ac747238eb3a8c91b2a564107af20e4de55680", + "n": 1, + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true, + "value": "150000", + "hex": "47304402202100334789951706405faa9ddc191702b88d9438d5a461d1f008a9bd097bd9b0022062cd93003ad63bfbb16386b90e619c2b32d9caef5229d8943c11309f26b6c19f41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" + } + ], + "vout": [ + { + "value": "188124", + "n": 0, + "spent": true, + "hex": "76a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac", + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000028351f97cd867acbba39b5a81137ce35a1ac18444aaa76", + "blockHeight": 619773, + "confirmations": 8182, + "blockTime": 1580201823, + "value": "188124", + "valueIn": "188804", + "fees": "680", + "hex": "0100000002a16be77fe40f9d3d3997e8320e2c9e0b842e6bffca5af742d40b3f5f1034acfe010000006b483045022100dbbf18561baf7fdb46c21d27801594209f2067f1d7735e245c56001c4e462d3c0220016e052ebbcf350bd64a257f7cc52ef23730fe50b24355d098f87c528fcd839641210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5000000008056e54d0ef27a1064a5b2918c3aeb387274acf55ad069425339a9f28f95b801000000006a47304402202100334789951706405faa9ddc191702b88d9438d5a461d1f008a9bd097bd9b0022062cd93003ad63bfbb16386b90e619c2b32d9caef5229d8943c11309f26b6c19f41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd50000000001dcde0200000000001976a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac00000000" + }, + { + "txid": "feac34105f3f0bd442f75acaff6b2e840b9e2c0e32e897393d9d0fe47fe76ba1", + "version": 1, + "vin": [ + { + "txid": "6f2d6fb46039f192f82cfd9bc85dcf0575fdf5eda9b726643314be883c8c0559", + "vout": 1, + "n": 0, + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true, + "value": "49256", + "hex": "47304402207df4bd44f74e9a077b84f547b29c595e808bfb3ebc23e070e975905e2012044c02206fa66e30f9afe063c5a5c30d0bb20c6d0eece782a9b6211676180c25d745e98c41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" + } + ], + "vout": [ + { + "value": "10000", + "n": 0, + "spent": true, + "hex": "76a914045891bcbb214544c47a8dbc75350584d8042bc288ac", + "addresses": [ + "bitcoincash:qqz93yduhvs523xy02xmcaf4qkzdspptcgq4dscr8c" + ], + "isAddress": true + }, + { + "value": "38804", + "n": 1, + "spent": true, + "hex": "76a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac", + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000015997ed69ac8b1e1d19c006bca7fb08faf3442890b2fed5", + "blockHeight": 619764, + "confirmations": 8191, + "blockTime": 1580198433, + "value": "48804", + "valueIn": "49256", + "fees": "452", + "hex": "010000000159058c3c88be14336426b7a9edf5fd7505cf5dc89bfd2cf892f13960b46f2d6f010000006a47304402207df4bd44f74e9a077b84f547b29c595e808bfb3ebc23e070e975905e2012044c02206fa66e30f9afe063c5a5c30d0bb20c6d0eece782a9b6211676180c25d745e98c41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5000000000210270000000000001976a914045891bcbb214544c47a8dbc75350584d8042bc288ac94970000000000001976a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac00000000" + } + ], + "usedTokens": 71, + "tokens": [ + { + "type": "XPUBAddress", + "name": "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25", + "path": "m/44'/145'/0'/0/0", + "transfers": 11, + "decimals": 8, + "balance": "177672", + "totalReceived": "850002", + "totalSent": "672330" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/callisto-api-transactions.js b/mock/ext-api-dyson/get/callisto-api-transactions.js new file mode 100644 index 000000000..7c8789baf --- /dev/null +++ b/mock/ext-api-dyson/get/callisto-api-transactions.js @@ -0,0 +1,60 @@ +/// Callisto API Mock +/// See: +/// curl "http://localhost:3000/callisto-api/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" +/// curl "http://{callisto rpc}/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" +/// curl http://localhost:8420/v1/callisto/0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7 + +module.exports = { + path: '/callisto-api/transactions', + template: function(params, query, body) { + //console.log(query) + if (query.address === '0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7') { + return JSON.parse(` + { + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x4052f55ee615a783abaa22a62100a45d2eee27ecab3a599e9d6691371336463e", + "blockNumber": 4699868, + "time": 1584952936, + "nonce": 7973, + "from": "0x28D2c7db63a9fC5f0b1eE3Ee2B7c0c350Eb9256A", + "to": "0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7", + "value": "120071054450000000000", + "gas": "21000", + "gasPrice": "50000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x4052f55ee615a783abaa22a62100a45d2eee27ecab3a599e9d6691371336463e", + "timeStamp": "1584952936" + }, + { + "operations": [], + "contract": null, + "_id": "0x8d50f2e48d3616e55c4adf2b579aa4696459714c2777baf01d43333389acf9c5", + "blockNumber": 4699693, + "time": 1584950541, + "nonce": 1466, + "from": "0x1212c7aE2d01E3d174C759EF616c46C9C50bd94f", + "to": "0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7", + "value": "179512617388000000000", + "gas": "21000", + "gasPrice": "50000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x8d50f2e48d3616e55c4adf2b579aa4696459714c2777baf01d43333389acf9c5", + "timeStamp": "1584950541" + } + ], + "total": 2 + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/cosmos-api-txs.js b/mock/ext-api-dyson/get/cosmos-api-txs.js new file mode 100644 index 000000000..6da657330 --- /dev/null +++ b/mock/ext-api-dyson/get/cosmos-api-txs.js @@ -0,0 +1,524 @@ +/// Cosmos API Mock +/// See: +/// curl "http://localhost:3000/cosmos-api/txs?transfer.recipient=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq&page=1&limit=25" +/// curl "http://localhost:3000/cosmos-api/txs?message.sender=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq&page=1&limit=25" +/// curl "http://{cosmos rpc}/txs?transfer.recipient=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq&page=1&limit=25" +/// curl ""http://{cosmos rpc}/txs?message.sender=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq&page=1&limit=25" +/// curl http://localhost:8420/v1/cosmos/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq +module.exports = { + path: "/cosmos-api/txs?", + template: function(params, query, body) { + //console.log(query) + if (query["transfer.recipient"] === 'cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq') { + return JSON.parse(` + { + "total_count": "1", + "count": "1", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "26616", + "txhash": "3FEE8F10FBA5505DE2A8D3EF220D5CE900CA76B96208234BBF89B8075743A230", + "data": "0C0886C1BEF00510E7FFF6F801", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "127111", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgUndelegate", + "value": { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", + "amount": { + "denom": "uatom", + "amount": "2203000" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" + }, + "signature": "fJkOgQX9FZz6UJJo48AA3qxc2v/vFrjxlMgq3iOhDmVUWjA2P6X+pPbPkSB1SHlBFlVbsNF/DDPB0pvP9LRPTg==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-12-13T20:13:58Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + } + ] + } + `); + } + + if (query["message.sender"] === 'cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq') { + return JSON.parse(` + { + "total_count": "2", + "count": "2", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "26616", + "txhash": "3FEE8F10FBA5505DE2A8D3EF220D5CE900CA76B96208234BBF89B8075743A230", + "data": "0C0886C1BEF00510E7FFF6F801", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "127111", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgUndelegate", + "value": { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", + "amount": { + "denom": "uatom", + "amount": "2203000" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" + }, + "signature": "fJkOgQX9FZz6UJJo48AA3qxc2v/vFrjxlMgq3iOhDmVUWjA2P6X+pPbPkSB1SHlBFlVbsNF/DDPB0pvP9LRPTg==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-12-13T20:13:58Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + }, + { + "height": "404179", + "txhash": "93E43518BAE4BC137605BBB7FD5D31FDAE6427ECE57EC299C43CE786FDAEBC63", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "delegate", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh" + }, + { + "key": "amount", + "value": "2211271" + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "delegate" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "93720", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgDelegate", + "value": { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", + "amount": { + "denom": "uatom", + "amount": "2211271" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" + }, + "signature": "X1/NzRdb+HUxE7N9gMk39XI8TyHFobLRQtsX4QxZZbYeKmEYOOZ7FyNSGqgmipCkpuysBeh6fNnbXmo3IFzFEQ==" + } + ], + "memo": "" + } + }, + "timestamp": "2020-01-13T15:23:12Z", + "events": [ + { + "type": "delegate", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh" + }, + { + "key": "amount", + "value": "2211271" + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "delegate" + } + ] + } + ] + } + ] + } + `); + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; + diff --git a/mock/ext-api-dyson/get/dash-api-address.js b/mock/ext-api-dyson/get/dash-api-address.js new file mode 100644 index 000000000..2a7ae47b1 --- /dev/null +++ b/mock/ext-api-dyson/get/dash-api-address.js @@ -0,0 +1,177 @@ +/// Mock for external Dash API +/// See: +/// curl "http://{dash rpc}/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" +/// curl "http://localhost:3000/dash-api/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" +/// curl "http://localhost:8420/v1/dash/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" + +module.exports = { + path: '/dash-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "addrStr": "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG", + "balance": "167.97080211", + "totalReceived": "1302.03239791", + "totalSent": "1134.0615958", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 618, + "txs": [ + { + "txid": "35541e151818606a512bb88acddb449449f46531e97f1ed0a5fcc0d7a8091e41", + "version": 3, + "vin": [ + { + "txid": "", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": {}, + "addresses": null, + "value": "" + } + ], + "vout": [ + { + "value": "1.55334749", + "n": 0, + "scriptPubKey": { + "hex": "76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac", + "addresses": [ + "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" + ] + }, + "spent": false + }, + { + "value": "1.55334763", + "n": 1, + "scriptPubKey": { + "hex": "76a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac", + "addresses": [ + "Xb8cmjtK67y9T2haqrcDicoAMByDesLcAe" + ] + }, + "spent": true + } + ], + "blockhash": "000000000000000f432c35cbd89c013333cf591c72d15959a51100625d263243", + "blockheight": 1239931, + "confirmations": 3276, + "time": 1584614323, + "blocktime": 1584614323, + "valueOut": "3.10669512", + "valueIn": "0", + "fees": "0", + "hex": "03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff27037beb121a4d696e656420627920416e74506f6f6c347c00330120ad45211b6b76000001000000ffffffff025d384209000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac6b384209000000001976a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac000000004602007beb12009d9eb909c943fd6b4aad565dc083dc2b53736359cc678af072352bbf409a942f3b0192d52c43692520241eb04505406f34adf6805fd5ab29113959133e8e1d3d" + }, + { + "txid": "f47a4929bcd8767819b6969c83893a76d5b26a145c74ace416ce4c454166186e", + "version": 3, + "vin": [ + { + "txid": "", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": {}, + "addresses": null, + "value": "" + } + ], + "vout": [ + { + "value": "1.56344682", + "n": 0, + "scriptPubKey": { + "hex": "76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac", + "addresses": [ + "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" + ] + }, + "spent": false + }, + { + "value": "1.56344689", + "n": 1, + "scriptPubKey": { + "hex": "76a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac", + "addresses": [ + "Xb8cmjtK67y9T2haqrcDicoAMByDesLcAe" + ] + }, + "spent": true + } + ], + "blockhash": "000000000000001709a13d55d31782a8d26ea3691c4d3433794b9ff2ee0b0ac7", + "blockheight": 1237951, + "confirmations": 5256, + "time": 1584303664, + "blocktime": 1584303664, + "valueOut": "3.12689371", + "valueIn": "0", + "fees": "0", + "hex": "03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff2703bfe3121a4d696e656420627920416e74506f6f6c357c006502207193bf88753900000d030000ffffffff026aa15109000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac71a15109000000001976a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac00000000460200bfe312006d5f02b8c49b966902195a3b2b581b4a5847901d5c66bf9820a35884c6a91b51b20d38a728281d7ba3a9b3c157593c9121850977cababcba9ab71729684d9723" + }, + { + "txid": "aaceebd8a59a777c8d27ede7d086f605a04e3463bd3465fd3fa02518fcd24abd", + "version": 3, + "vin": [ + { + "txid": "", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": {}, + "addresses": null, + "value": "" + } + ], + "vout": [ + { + "value": "1.55873001", + "n": 0, + "scriptPubKey": { + "hex": "76a9142832b5c571b5686c4a08dae4091d856c4f9b190a88ac", + "addresses": [ + "XeMPcKeVDN9bkECGDC7ggtf9QsX5thgKAx" + ] + }, + "spent": true + }, + { + "value": "1.55872988", + "n": 1, + "scriptPubKey": { + "hex": "76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac", + "addresses": [ + "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" + ] + }, + "spent": false + } + ], + "blockhash": "00000000000000021075e42769f6a1bd6ac477574266102b324197c158bf3a14", + "blockheight": 1237949, + "confirmations": 5258, + "time": 1584302904, + "blocktime": 1584302904, + "valueOut": "3.11745989", + "valueIn": "0", + "fees": "0", + "hex": "03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff1703bde31212563c785f430fb8fa7417000000002f4e614effffffff02e96e4a09000000001976a9142832b5c571b5686c4a08dae4091d856c4f9b190a88acdc6e4a09000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac00000000460200bde312006d5f02b8c49b966902195a3b2b581b4a5847901d5c66bf9820a35884c6a91b51b20d38a728281d7ba3a9b3c157593c9121850977cababcba9ab71729684d9723" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/dash-api-xpub.js b/mock/ext-api-dyson/get/dash-api-xpub.js new file mode 100644 index 000000000..1a187be43 --- /dev/null +++ b/mock/ext-api-dyson/get/dash-api-xpub.js @@ -0,0 +1,175 @@ +/// Mock for external Dash API +/// See: +/// curl "http://{dash rpc}/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs" +/// curl "http://localhost:3000/dash-api/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs" +/// curl "http://localhost:8420/v1/dash/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD" + +module.exports = { + path: '/dash-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD", + "balance": "2597761", + "totalReceived": "27175423", + "totalSent": "24577662", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 52, + "transactions": [ + { + "txid": "2b67e2fbe6a212286243bc539cca3c1d877e85ffec7c925e34f2bfb7b6cc498c", + "version": 1, + "vin": [ + { + "txid": "227f1995f5d0b0adcd4f014159710892fa4b66a02ff7ad1e0fc4c1b84ca27cb2", + "n": 0, + "addresses": [ + "XyPpEePUKruNEVgdp5jWSakfvoQTnkZxhL" + ], + "isAddress": true, + "value": "34508", + "hex": "483045022100bebce18899214200115fbb2e3b16cd7a6b61cca2cf3e1ffc3b26872f66b714f702203316ce9f1cfb7cef751dbba46015ea76d3c409d6b913b6e434553ebe66680713012103f556051304c43ef031a17615fd8b056c1ac7b0a50926137bf918e72be002f606" + } + ], + "vout": [ + { + "value": "10000", + "n": 0, + "hex": "76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac", + "addresses": [ + "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" + ], + "isAddress": true + }, + { + "value": "18858", + "n": 1, + "hex": "76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac", + "addresses": [ + "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000b3e9287157ae29c1c19bbd1e65660a5bbe723261d0fc57737", + "blockHeight": 1226578, + "confirmations": 16630, + "blockTime": 1582509671, + "value": "28858", + "valueIn": "34508", + "fees": "5650", + "hex": "0100000001b27ca24cb8c1c40f1eadf72fa0664bfa9208715941014fcdadb0d0f595197f22000000006b483045022100bebce18899214200115fbb2e3b16cd7a6b61cca2cf3e1ffc3b26872f66b714f702203316ce9f1cfb7cef751dbba46015ea76d3c409d6b913b6e434553ebe66680713012103f556051304c43ef031a17615fd8b056c1ac7b0a50926137bf918e72be002f606000000000210270000000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88acaa490000000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac00000000" + }, + { + "txid": "dc8e1219da91a24c2eca773a6853d7a0602eed509a4b71afd553f8b4c218b309", + "version": 1, + "vin": [ + { + "txid": "501c3c7ecaae272de760e81d284e44644a0475c42e3ee15ae16a125650211c8e", + "vout": 1, + "n": 0, + "addresses": [ + "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" + ], + "isAddress": true, + "value": "768334", + "hex": "483045022100805ae010fb81b3659f687d1f9da9efa27fa220d34c0f9c54dde4f8e8358e7c2e022003c2c89eb0372616ad50b74f627097e3ccf2ecd940bad616b0bf7caaab58615c01210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600" + }, + { + "txid": "501c3c7ecaae272de760e81d284e44644a0475c42e3ee15ae16a125650211c8e", + "n": 1, + "addresses": [ + "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" + ], + "isAddress": true, + "value": "809686", + "hex": "483045022100ff644abb86e4272384e64de00d7ac2b1ed01e6848f59707f1bd93913b0f2ceeb02205ba0be94a02a2af3d7178977d828dda4268da4f83c00d2af1331e4274a5454a201210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac", + "addresses": [ + "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" + ], + "isAddress": true + }, + { + "value": "576150", + "n": 1, + "hex": "76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac", + "addresses": [ + "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000f727266a1a157af489fec0a009938dadeca89bc3edd1bc017", + "blockHeight": 1215128, + "confirmations": 28080, + "blockTime": 1580704472, + "value": "1576150", + "valueIn": "1578020", + "fees": "1870", + "hex": "01000000028e1c215056126ae15ae13e2ec475044a64444e281de860e72d27aeca7e3c1c50010000006b483045022100805ae010fb81b3659f687d1f9da9efa27fa220d34c0f9c54dde4f8e8358e7c2e022003c2c89eb0372616ad50b74f627097e3ccf2ecd940bad616b0bf7caaab58615c01210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600000000008e1c215056126ae15ae13e2ec475044a64444e281de860e72d27aeca7e3c1c50000000006b483045022100ff644abb86e4272384e64de00d7ac2b1ed01e6848f59707f1bd93913b0f2ceeb02205ba0be94a02a2af3d7178977d828dda4268da4f83c00d2af1331e4274a5454a201210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600000000000240420f00000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac96ca0800000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac00000000" + } + ], + "usedTokens": 47, + "tokens": [ + { + "type": "XPUBAddress", + "name": "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq", + "path": "m/44'/5'/0'/0/0", + "transfers": 13, + "decimals": 8, + "balance": "2543095", + "totalReceived": "4275043", + "totalSent": "1731948" + }, + { + "type": "XPUBAddress", + "name": "XezMSYZ3ucD2tNGVME1j3A8tM5q3NvigKu", + "path": "m/44'/5'/0'/0/15", + "transfers": 1, + "decimals": 8, + "balance": "10000", + "totalReceived": "10000", + "totalSent": "0" + }, + { + "type": "XPUBAddress", + "name": "XmM5KX1Zpepji5V6RF7iypCkXBi4hSronS", + "path": "m/44'/5'/0'/0/18", + "transfers": 1, + "decimals": 8, + "balance": "10000", + "totalReceived": "10000", + "totalSent": "0" + }, + { + "type": "XPUBAddress", + "name": "XcLBw1EUz5HPDJ5pZrSbeyXYBWcVCabZ56", + "path": "m/44'/5'/0'/1/24", + "transfers": 1, + "decimals": 8, + "balance": "34666", + "totalReceived": "34666", + "totalSent": "0" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/decred-api-address.js b/mock/ext-api-dyson/get/decred-api-address.js new file mode 100644 index 000000000..ad7fc2648 --- /dev/null +++ b/mock/ext-api-dyson/get/decred-api-address.js @@ -0,0 +1,136 @@ +/// Mock for external Decred API +/// See: +/// curl "http://{decred rpc}/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" +/// curl "http://localhost:3000/decred-api/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" +/// curl "http://localhost:8420/v1/decred/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + +module.exports = { + path: '/decred-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "addrStr": "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", + "balance": "0.19473147", + "totalReceived": "0.7496027", + "totalSent": "0.55487123", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 10, + "txs": [ + { + "txid": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0", + "version": 1, + "vin": [ + { + "txid": "2dc905f525885537310c8ab87f67dc175ca369af1fe7111a49a94451866aa019", + "vout": 0, + "sequence": 4294967291, + "n": 0, + "scriptSig": { + "hex": "473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + }, + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "value": "0.00591955" + } + ], + "vout": [ + { + "value": "0.001", + "n": 0, + "scriptPubKey": { + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ] + }, + "spent": false + }, + { + "value": "0.00489415", + "n": 1, + "scriptPubKey": { + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ] + }, + "spent": false + } + ], + "blockhash": "00000000000000000c12cb497e60470a3cf366d16705eaba303c2c4415cc7567", + "blockheight": 429609, + "confirmations": 5412, + "time": 1583516573, + "blocktime": 1583516573, + "valueOut": "0.00589415", + "valueIn": "0.00591955", + "fees": "0.0000254", + "hex": "010000000119a06a865144a9491a11e71faf69a35c17dc677fb88a0c3137558825f505c92d0000000000fbffffff02a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acc77707000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac0000000000000000015308090000000000dbcc05000b0000006a473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + }, + { + "txid": "025abf340da79c4fc4de29667c08fc22cdafbded24c7c2a994a27f6fb4d5fa17", + "version": 1, + "vin": [ + { + "txid": "5a2a0d01ed8672d6bebd7dee447b2e0342bfc34fd4893bed58a4fa5aa87a4c42", + "vout": 0, + "n": 0, + "scriptSig": { + "hex": "483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" + }, + "addresses": [ + "Dsf6WkLoiTcSGKmkXoSEdukqUfeRJMqUNJV" + ], + "value": "0.1999198" + } + ], + "vout": [ + { + "value": "0.001", + "n": 0, + "scriptPubKey": { + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ] + }, + "spent": false + }, + { + "value": "0.1988944", + "n": 1, + "scriptPubKey": { + "hex": "76a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac", + "addresses": [ + "Dsesp1V6DZDEtcq2behmBVKdYqKMdkh96hL" + ] + }, + "spent": false + } + ], + "blockhash": "0000000000000000264c499f21a7ef95bffb37148fc099514b2407dfa28c3287", + "blockheight": 429186, + "confirmations": 5835, + "time": 1583384838, + "blocktime": 1583384838, + "valueOut": "0.1998944", + "valueIn": "0.1999198", + "fees": "0.0000254", + "hex": "0100000001424c7aa85afaa458ed3b89d44fc3bf42032e7b44ee7dbdbed67286ed010d2a5a00000000000000000002a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac207d2f010000000000001976a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac000000000000000001ac0d31010000000052630600050000006b483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/decred-api-xpub.js b/mock/ext-api-dyson/get/decred-api-xpub.js new file mode 100644 index 000000000..914387609 --- /dev/null +++ b/mock/ext-api-dyson/get/decred-api-xpub.js @@ -0,0 +1,122 @@ +/// Mock for external Decred API +/// See: +/// curl "http://{decred rpc}v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs" +/// curl "http://localhost:3000/decred-api/v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs" +/// curl "http://localhost:8420/v1/decred/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN" + +module.exports = { + path: '/decred-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN", + "balance": "19617042", + "totalReceived": "376432293", + "totalSent": "356815251", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 28, + "transactions": [ + { + "txid": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0", + "version": 1, + "vin": [ + { + "txid": "2dc905f525885537310c8ab87f67dc175ca369af1fe7111a49a94451866aa019", + "sequence": 4294967291, + "n": 0, + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true, + "value": "591955", + "hex": "473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "489415", + "n": 1, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000c12cb497e60470a3cf366d16705eaba303c2c4415cc7567", + "blockHeight": 429609, + "confirmations": 5412, + "blockTime": 1583516573, + "value": "589415", + "valueIn": "591955", + "fees": "2540", + "hex": "010000000119a06a865144a9491a11e71faf69a35c17dc677fb88a0c3137558825f505c92d0000000000fbffffff02a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acc77707000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac0000000000000000015308090000000000dbcc05000b0000006a473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + }, + { + "txid": "025abf340da79c4fc4de29667c08fc22cdafbded24c7c2a994a27f6fb4d5fa17", + "version": 1, + "vin": [ + { + "txid": "5a2a0d01ed8672d6bebd7dee447b2e0342bfc34fd4893bed58a4fa5aa87a4c42", + "n": 0, + "addresses": [ + "Dsf6WkLoiTcSGKmkXoSEdukqUfeRJMqUNJV" + ], + "isAddress": true, + "value": "19991980", + "hex": "483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "19889440", + "n": 1, + "hex": "76a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac", + "addresses": [ + "Dsesp1V6DZDEtcq2behmBVKdYqKMdkh96hL" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000264c499f21a7ef95bffb37148fc099514b2407dfa28c3287", + "blockHeight": 429186, + "confirmations": 5835, + "blockTime": 1583384838, + "value": "19989440", + "valueIn": "19991980", + "fees": "2540", + "hex": "0100000001424c7aa85afaa458ed3b89d44fc3bf42032e7b44ee7dbdbed67286ed010d2a5a00000000000000000002a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac207d2f010000000000001976a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac000000000000000001ac0d31010000000052630600050000006b483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/digibyte-api-address.js b/mock/ext-api-dyson/get/digibyte-api-address.js new file mode 100644 index 000000000..bab0bb9d7 --- /dev/null +++ b/mock/ext-api-dyson/get/digibyte-api-address.js @@ -0,0 +1,189 @@ +/// Mock for external Digibyte API +/// See: +/// curl "http://{digibyte rpc}/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" +/// curl "http://localhost:3000/digibyte-api/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" +/// curl "http://localhost:8420/v1/digibyte/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" + +module.exports = { + path: '/digibyte-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi': + return JSON.parse(` + { + "page": 1, + "totalPages": 4, + "itemsOnPage": 1000, + "addrStr": "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi", + "balance": "0", + "totalReceived": "2317.03950234", + "totalSent": "2317.03950234", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 3428, + "txs": [ + { + "txid": "3ad1035d37f47061599a5055284a8b2acc0facc6039353b1822f0a3c0f1d6906", + "version": 1, + "vin": [ + { + "txid": "14f845047925fb36e5a0c569f2c1d2b7c5be4543e46920b49eb732860bf5b02a", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": { + "hex": "47304402202fc0e7eebec384bcff141800990f80742d2ed97db02784fb383cd4cd42aca71e02202be0f292a8209bff5682e05424170632bb7023a7aaca0dca1faf54af1e8eec16012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057" + }, + "addresses": [ + "DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW" + ], + "value": "0.7988" + } + ], + "vout": [ + { + "value": "0.79879", + "n": 0, + "scriptPubKey": { + "hex": "76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac", + "addresses": [ + "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" + ] + }, + "spent": true + }, + { + "value": "0", + "n": 1, + "scriptPubKey": { + "hex": "6a45524d555453422e41432e544800000000000025aba398bee3241347368c2d4d758575c7fe00138abe258456087c4f640ae3274c452f87d110bc12ee1f77ed9b365a49d6c547", + "addresses": [ + "OP_RETURN 524d555453422e41432e544800000000000025aba398bee3241347368c2d4d758575c7fe00138abe258456087c4f640ae3274c452f87d110bc12ee1f77ed9b365a49d6c547" + ] + }, + "spent": false + } + ], + "blockhash": "0000000000000007fa73216ba848e3d029f91a088f628cc1780f333d7e13311d", + "blockheight": 10510734, + "confirmations": 30461, + "time": 1584668841, + "blocktime": 1584668841, + "valueOut": "0.79879", + "valueIn": "0.7988", + "fees": "0.00001", + "hex": "01000000012ab0f50b8632b79eb42069e44345bec5b7d2c1f269c5a0e536fb25790445f814000000006a47304402202fc0e7eebec384bcff141800990f80742d2ed97db02784fb383cd4cd42aca71e02202be0f292a8209bff5682e05424170632bb7023a7aaca0dca1faf54af1e8eec16012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff0258dbc204000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e544800000000000025aba398bee3241347368c2d4d758575c7fe00138abe258456087c4f640ae3274c452f87d110bc12ee1f77ed9b365a49d6c54700000000" + }, + { + "txid": "d7efaffeded550697d7385d3eb07e539237615792b29e3639df427ce919c8d6e", + "version": 1, + "vin": [ + { + "txid": "a7613f7242b3a24ca6f1de2c15be605411d01f6d86ed1cf0037da9d0e908bf0e", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": { + "hex": "47304402201d09be67618dc89a882c389560e73713302cb3d120adbae814e06ed15b2a17e002204595a11648173fe085a820b034394c1264ddd30b0e2dfdb07d3ebb46067145c10141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48" + }, + "addresses": [ + "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" + ], + "value": "0.71187" + } + ], + "vout": [ + { + "value": "0.71186", + "n": 0, + "scriptPubKey": { + "hex": "76a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac", + "addresses": [ + "DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW" + ] + }, + "spent": true + }, + { + "value": "0", + "n": 1, + "scriptPubKey": { + "hex": "6a45524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f1891", + "addresses": [ + "OP_RETURN 524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f1891" + ] + }, + "spent": false + } + ], + "blockhash": "6518a4fe30d601f87370aca047d1e2bcc3eaf72a194fc05f475bdbf24ca6d36e", + "blockheight": 10493876, + "confirmations": 47319, + "time": 1584416875, + "blocktime": 1584416875, + "valueOut": "0.71186", + "valueIn": "0.71187", + "fees": "0.00001", + "hex": "01000000010ebf08e9d0a97d03f01ced866d1fd0115460be152cdef1a64ca2b342723f61a7000000008a47304402201d09be67618dc89a882c389560e73713302cb3d120adbae814e06ed15b2a17e002204595a11648173fe085a820b034394c1264ddd30b0e2dfdb07d3ebb46067145c10141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48ffffffff0250363e04000000001976a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac0000000000000000476a45524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f189100000000" + }, + { + "txid": "a7613f7242b3a24ca6f1de2c15be605411d01f6d86ed1cf0037da9d0e908bf0e", + "version": 1, + "vin": [ + { + "txid": "3e4e8f95cf76c3a1bb91283e8c55ba5a7c103cc31b1c25c4587916666fbb8263", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": { + "hex": "47304402202560cf31d48b023fb44383c79f1685420af0365d87377589f9fa493f66c6d97f02201724f2c0c41ff384fc53d128fec351093d8f2d54332cc7191153008080c4f9a7012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057" + }, + "addresses": [ + "DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW" + ], + "value": "0.71188" + } + ], + "vout": [ + { + "value": "0.71187", + "n": 0, + "scriptPubKey": { + "hex": "76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac", + "addresses": [ + "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" + ] + }, + "spent": true + }, + { + "value": "0", + "n": 1, + "scriptPubKey": { + "hex": "6a45524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f1891", + "addresses": [ + "OP_RETURN 524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f1891" + ] + }, + "spent": false + } + ], + "blockhash": "6518a4fe30d601f87370aca047d1e2bcc3eaf72a194fc05f475bdbf24ca6d36e", + "blockheight": 10493876, + "confirmations": 47319, + "time": 1584416875, + "blocktime": 1584416875, + "valueOut": "0.71187", + "valueIn": "0.71188", + "fees": "0.00001", + "hex": "01000000016382bb6f66167958c4251c1bc33c107c5aba558c3e2891bba1c376cf958f4e3e000000006a47304402202560cf31d48b023fb44383c79f1685420af0365d87377589f9fa493f66c6d97f02201724f2c0c41ff384fc53d128fec351093d8f2d54332cc7191153008080c4f9a7012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff02383a3e04000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f189100000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/digibyte-api-xpub.js b/mock/ext-api-dyson/get/digibyte-api-xpub.js new file mode 100644 index 000000000..a82b7a7c4 --- /dev/null +++ b/mock/ext-api-dyson/get/digibyte-api-xpub.js @@ -0,0 +1,123 @@ +/// Mock for external Digibyte API +/// See: +/// curl "http://{digibyte rpc}/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs" +/// curl "http://localhost:3000/digibyte-api/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs" +/// curl "http://localhost:8420/v1/digibyte/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow" + +module.exports = { + path: '/digibyte-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow", + "balance": "2599896040", + "totalReceived": "6895667780", + "totalSent": "4295771740", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 7, + "transactions": [ + { + "txid": "e13c81f4450e43ef8ef10dea8f4f9d53f357266563462df32a7fd61eb71bd190", + "version": 1, + "vin": [ + { + "txid": "34fac508c701939ac0fcb62bc436281cc28588d7986c5aa51de99e9835b9217b", + "vout": 1, + "n": 0, + "addresses": [ + "dgb1qxxdszsfkv4uvw8kzzl2wfatts5r9zex69x6076" + ], + "isAddress": true, + "value": "598908696" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "hex": "0014428a3010eb79c4d32478404200dbd41042e61fce", + "addresses": [ + "dgb1qg29rqy8t08zdxfrcgppqpk75zppwv87wknuder" + ], + "isAddress": true + }, + { + "value": "588896040", + "n": 1, + "hex": "00146542b8b7859994b18df4b71c72c4a72ed113662e", + "addresses": [ + "dgb1qv4pt3du9nx2trr05kuw893989mg3xe3w322vy7" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000733a44ab2efd51c9485b05d905d2ba9092f716dcc0083116c", + "blockHeight": 9763292, + "confirmations": 777936, + "blockTime": 1573501957, + "value": "598896040", + "valueIn": "598908696", + "fees": "12656", + "hex": "010000000001017b21b935989ee91da55a6c98d78885c21c2836c42bb6fcc09a9301c708c5fa34010000000000000000028096980000000000160014428a3010eb79c4d32478404200dbd41042e61fce28d71923000000001600146542b8b7859994b18df4b71c72c4a72ed113662e02473044022023b050ed97c4c7e334fec8efa3f27754e65c1e66a60ce142b2f8e2c16a1c847b02204a2e7d8a470a8978735a0b6d0f3649da6489612256f7cacd52e95034cc05365e012102cc9d7c2383e8f7c18e5af1852ddc35c5c4355a262a68b9d499ba173f6200ff9500000000" + }, + { + "txid": "303aa433530cb32762f8068ae14022e9a759b6c40bb69cee7e77abca333db317", + "version": 1, + "vin": [ + { + "txid": "d8d05cee8623257853b90cb1b0ff6c8e4bf5509818e812510f6715015fac1599", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "DTVYvQYvoXQjsiZQdvT9AaBjyQJr8TjAWu" + ], + "isAddress": true, + "value": "48587940518800", + "hex": "483045022100de758903643db73bc56bcd6b3e1e4bdafb3bd9b7a844286f66317de7c90b868702207eba0eeb32c817df9e79df2aad5f192808941ccb5d18430f9ee7ea18b8b1abad0121038f47ad4221aa24dbefe2b439f644b3af71428a7eb9e837517a162710fe631cf7" + } + ], + "vout": [ + { + "value": "48585940500900", + "n": 0, + "spent": true, + "hex": "76a914c30c2dd0e7b7f6506259f11e956d0f1085ca437588ac", + "addresses": [ + "DNvQtshdnrehs8MNRx6Mh9XDPz4UZucfEv" + ], + "isAddress": true + }, + { + "value": "2000000000", + "n": 1, + "hex": "00147ad8c91046724785f78b48d4ae606a3556ddf9b4", + "addresses": [ + "dgb1q0tvvjyzxwfrctautfr22ucr2x4tdm7d5va4lr6" + ], + "isAddress": true + } + ], + "blockHash": "311aa13d66a4cf6be602209601d7b54bc715320d9255d1abc822ad20a7e01a20", + "blockHeight": 9756845, + "confirmations": 784383, + "blockTime": 1573405513, + "value": "48587940500900", + "valueIn": "48587940518800", + "fees": "17900", + "hex": "01000000019915ac5f0115670f5112e8189850f54b8e6cffb0b10cb95378252386ee5cd0d8000000006b483045022100de758903643db73bc56bcd6b3e1e4bdafb3bd9b7a844286f66317de7c90b868702207eba0eeb32c817df9e79df2aad5f192808941ccb5d18430f9ee7ea18b8b1abad0121038f47ad4221aa24dbefe2b439f644b3af71428a7eb9e837517a162710fe631cf7ffffffff02a481b94b302c00001976a914c30c2dd0e7b7f6506259f11e956d0f1085ca437588ac00943577000000001600147ad8c91046724785f78b48d4ae606a3556ddf9b400000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/doge-api-address.js b/mock/ext-api-dyson/get/doge-api-address.js new file mode 100644 index 000000000..02e07026b --- /dev/null +++ b/mock/ext-api-dyson/get/doge-api-address.js @@ -0,0 +1,137 @@ +/// Mock for external Doge API +/// See: +/// curl "http://{doge rpc}/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" +/// curl "http://localhost:3000/doge-api/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" +/// curl "http://localhost:8420/v1/doge/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + +module.exports = { + path: '/doge-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "addrStr": "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh", + "balance": "513.94795942", + "totalReceived": "1602.02987826", + "totalSent": "1088.08191884", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 11, + "txs": [ + { + "txid": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9", + "version": 1, + "vin": [ + { + "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", + "vout": 1, + "sequence": 4294967288, + "n": 0, + "scriptSig": { + "hex": "483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5" + }, + "addresses": [ + "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" + ], + "value": "5.336" + } + ], + "vout": [ + { + "value": "1", + "n": 0, + "scriptPubKey": { + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ] + }, + "spent": false + }, + { + "value": "2.754", + "n": 1, + "scriptPubKey": { + "hex": "76a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac", + "addresses": [ + "DKix6fTygojRpBFbADfkYKDX9nZ2Y7Huqq" + ] + }, + "spent": false + } + ], + "blockhash": "ece2c433edfaf7143ba79f381ea40ac8b7e38ce6c4ff0771ae1e3dda9246824a", + "blockheight": 3099770, + "confirmations": 59971, + "time": 1581351126, + "blocktime": 1581351126, + "valueOut": "3.754", + "valueIn": "5.336", + "fees": "1.582", + "hex": "0100000001987490208464a2b0547cf6fcae4b550be9bb9ca88ce526ef4a0ee5803da50df6010000006b483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5f8ffffff0200e1f505000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac40456a10000000001976a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac00000000" + }, + { + "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", + "version": 1, + "vin": [ + { + "txid": "c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb", + "vout": 1, + "sequence": 4294967291, + "n": 0, + "scriptSig": { + "hex": "483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + }, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "value": "8.418" + } + ], + "vout": [ + { + "value": "1.5", + "n": 0, + "scriptPubKey": { + "hex": "76a914e82178c73b5744342916f6a7a944af4fa37aebff88ac", + "addresses": [ + "DSJVQRY3wyVPrXbEDMSeoFufWNSsMeKEuj" + ] + }, + "spent": false + }, + { + "value": "5.336", + "n": 1, + "scriptPubKey": { + "hex": "76a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac", + "addresses": [ + "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" + ] + }, + "spent": true + } + ], + "blockhash": "d4a57feed1683117d412944fc6581eace1bc3a8be5ebab93cf2dd99f5918374d", + "blockheight": 3088989, + "confirmations": 70752, + "time": 1580673745, + "blocktime": 1580673745, + "valueOut": "6.836", + "valueIn": "8.418", + "fees": "1.582", + "hex": "0100000001fb1d11634e4149776ceb89325044be3f2b14989d65584f323c16bbd4d21ea5c6010000006b483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6cafbffffff0280d1f008000000001976a914e82178c73b5744342916f6a7a944af4fa37aebff88ac0017ce1f000000001976a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac00000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/doge-api-xpub.js b/mock/ext-api-dyson/get/doge-api-xpub.js new file mode 100644 index 000000000..42b709dd4 --- /dev/null +++ b/mock/ext-api-dyson/get/doge-api-xpub.js @@ -0,0 +1,126 @@ +/// Mock for external Doge API +/// See: +/// curl "http://{doge rpc}/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs" +/// curl "http://localhost:3000/doge-api/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs" +/// curl "http://localhost:8420/v1/doge/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN" + +module.exports = { + path: '/doge-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN", + "balance": "53537405232", + "totalReceived": "2701368049752", + "totalSent": "2647830644520", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 2, + "transactions": [ + { + "txid": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9", + "version": 1, + "vin": [ + { + "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", + "vout": 1, + "sequence": 4294967288, + "n": 0, + "addresses": [ + "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" + ], + "isAddress": true, + "value": "533600000", + "hex": "483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + }, + { + "value": "275400000", + "n": 1, + "hex": "76a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac", + "addresses": [ + "DKix6fTygojRpBFbADfkYKDX9nZ2Y7Huqq" + ], + "isAddress": true + } + ], + "blockHash": "ece2c433edfaf7143ba79f381ea40ac8b7e38ce6c4ff0771ae1e3dda9246824a", + "blockHeight": 3099770, + "confirmations": 59977, + "blockTime": 1581351126, + "value": "375400000", + "valueIn": "533600000", + "fees": "158200000", + "hex": "0100000001987490208464a2b0547cf6fcae4b550be9bb9ca88ce526ef4a0ee5803da50df6010000006b483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5f8ffffff0200e1f505000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac40456a10000000001976a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac00000000" + }, + { + "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", + "version": 1, + "vin": [ + { + "txid": "c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb", + "vout": 1, + "sequence": 4294967291, + "n": 0, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true, + "value": "841800000", + "hex": "483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + } + ], + "vout": [ + { + "value": "150000000", + "n": 0, + "hex": "76a914e82178c73b5744342916f6a7a944af4fa37aebff88ac", + "addresses": [ + "DSJVQRY3wyVPrXbEDMSeoFufWNSsMeKEuj" + ], + "isAddress": true + }, + { + "value": "533600000", + "n": 1, + "spent": true, + "hex": "76a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac", + "addresses": [ + "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" + ], + "isAddress": true + } + ], + "blockHash": "d4a57feed1683117d412944fc6581eace1bc3a8be5ebab93cf2dd99f5918374d", + "blockHeight": 3088989, + "confirmations": 70758, + "blockTime": 1580673745, + "value": "683600000", + "valueIn": "841800000", + "fees": "158200000", + "hex": "0100000001fb1d11634e4149776ceb89325044be3f2b14989d65584f323c16bbd4d21ea5c6010000006b483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6cafbffffff0280d1f008000000001976a914e82178c73b5744342916f6a7a944af4fa37aebff88ac0017ce1f000000001976a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac00000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/eth-api-transactions.js b/mock/ext-api-dyson/get/eth-api-transactions.js index c26bf7084..572281a51 100644 --- a/mock/ext-api-dyson/get/eth-api-transactions.js +++ b/mock/ext-api-dyson/get/eth-api-transactions.js @@ -1,7 +1,7 @@ -/// RPC Mock +/// Ethereum API Mock /// See: /// curl "http://localhost:3000/eth-api/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "https://trust-wallet.herokuapp.com/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://{eth rpc}/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" /// curl http://localhost:8420/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7 module.exports = { @@ -9,8 +9,7 @@ module.exports = { template: function(params, query, body) { //console.log(query) if (query.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { - return JSON.parse(` - { + return JSON.parse(`{ "docs": [ { "operations": [], @@ -29,11 +28,45 @@ module.exports = { "error": "", "id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", "timeStamp": "1582624428" + }, + { + "operations": [ + { + "transactionId": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3-0", + "contract": { + "address": "0x0d8775f648430679a709e98d2b0cb6250d2887ef", + "symbol": "BAT", + "decimals": 18, + "totalSupply": "1500000000000000000000000000", + "name": "Basic Attention Token", + "updatedAt": "2020-03-23T06:01:25.975Z" + }, + "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", + "to": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "type": "token_transfer", + "value": "400000000000000000", + "id": null + } + ], + "contract": null, + "_id": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", + "blockNumber": 9519169, + "time": 1582189159, + "nonce": 16, + "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", + "to": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "value": "0", + "gas": "51839", + "gasPrice": "11500000000", + "gasUsed": "37028", + "input": "0xa9059cbb0000000000000000000000000875bcab22de3d02402bc38aee4104e1239374a7000000000000000000000000000000000000000000000000058d15e176280000", + "error": "", + "id": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", + "timeStamp": "1582189159" } ], - "total": 1 - } - `); + "total": 2 + }`); } // fallback var return4Codacy = {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/ethclassic-api-transactions.js b/mock/ext-api-dyson/get/ethclassic-api-transactions.js new file mode 100644 index 000000000..ec6719854 --- /dev/null +++ b/mock/ext-api-dyson/get/ethclassic-api-transactions.js @@ -0,0 +1,60 @@ +/// Ethereum Classic API Mock +/// See: +/// curl "http://localhost:3000/ethclassic-api/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" +/// curl "http://{etc rpc}/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" +/// curl http://localhost:8420/v1/ethereumclassic/0x7d2d0e153026fb428b885d86de50768d4cfeac37 + +module.exports = { + path: '/ethclassic-api/transactions', + template: function(params, query, body) { + //console.log(query) + if (query.address === '0x7d2d0e153026fb428b885d86de50768d4cfeac37') { + return JSON.parse(` + { + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe", + "blockNumber": 9833329, + "time": 1582237362, + "nonce": 7071, + "from": "0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9", + "to": "0x7D2D0E153026fB428B885D86De50768D4cFeaC37", + "value": "18529160000000000", + "gas": "21000", + "gasPrice": "1000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe", + "timeStamp": "1582237362" + }, + { + "operations": [], + "contract": null, + "_id": "0x524fb5fedace7bee35c165ac7f641d689122cb21390db7f7384507473a5ba058", + "blockNumber": 9804290, + "time": 1581854371, + "nonce": 6918, + "from": "0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9", + "to": "0x7D2D0E153026fB428B885D86De50768D4cFeaC37", + "value": "16208400000000000", + "gas": "21000", + "gasPrice": "1000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x524fb5fedace7bee35c165ac7f641d689122cb21390db7f7384507473a5ba058", + "timeStamp": "1581854371" + } + ], + "total": 2 + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/gochain-api-transactions.js b/mock/ext-api-dyson/get/gochain-api-transactions.js new file mode 100644 index 000000000..0b72af854 --- /dev/null +++ b/mock/ext-api-dyson/get/gochain-api-transactions.js @@ -0,0 +1,58 @@ +/// Gochain API Mock +/// See: +/// curl "http://localhost:3000/gochain-api/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" +/// curl "http://{go rpc}/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" +/// curl http://localhost:8420/v1/gochain/0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896 + +module.exports = { + path: '/gochain-api/transactions', + template: function(params, query, body) { + //console.log(query) + if (query.address === '0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896') { + return JSON.parse(`{ + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7", + "blockNumber": 10070535, + "time": 1576793173, + "nonce": 6, + "from": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", + "to": "0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3", + "value": "860000000000000000000000", + "gas": "90000", + "gasPrice": "2000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7", + "timeStamp": "1576793173" + }, + { + "operations": [], + "contract": null, + "_id": "0x472c94385a46072713bb2bf3503fc1610135a70e415046bf61a937789c205f4c", + "blockNumber": 10070520, + "time": 1576793098, + "nonce": 5, + "from": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", + "to": "0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3", + "value": "800000000000000000000", + "gas": "90000", + "gasPrice": "2000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x472c94385a46072713bb2bf3503fc1610135a70e415046bf61a937789c205f4c", + "timeStamp": "1576793098" + } + ], + "total": 2 + }`); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/groestlcoin-api-address.js b/mock/ext-api-dyson/get/groestlcoin-api-address.js new file mode 100644 index 000000000..1feaa2b36 --- /dev/null +++ b/mock/ext-api-dyson/get/groestlcoin-api-address.js @@ -0,0 +1,139 @@ +/// Mock for external Groestlcoin API +/// See: +/// curl "http://{groestlcoin rpc}/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" +/// curl "http://localhost:3000/groestlcoin-api/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" +/// curl "http://localhost:8420/v1/groestlcoin/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" + +module.exports = { + path: '/groestlcoin-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case '33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "addrStr": "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj", + "balance": "0", + "totalReceived": "59.5115306", + "totalSent": "59.5115306", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 2, + "txs": [ + { + "txid": "2640aa5de0c9603da1c0d9c16b2fd3fa0a17b1472c3aa02559d3ef5e1defceb5", + "version": 2, + "locktime": 2959295, + "vin": [ + { + "txid": "d8e0d23dedc2c89e9de317e7a54bdc3d26f514918a9360aa04e271c4d8074c28", + "vout": 0, + "sequence": 4294967294, + "n": 0, + "scriptSig": { + "hex": "160014d6c589125f084df1e3286fcd55446b64dc7de130" + }, + "addresses": [ + "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" + ], + "value": "59.5115306" + } + ], + "vout": [ + { + "value": "11.511497", + "n": 0, + "scriptPubKey": { + "hex": "a91436d64490426cc347a50bdd3f8db2ef20d62949f587", + "addresses": [ + "36gy6VVstfso35mS89pBg1PiUcYY3Gesar" + ] + }, + "spent": true + }, + { + "value": "48", + "n": 1, + "scriptPubKey": { + "hex": "76a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac", + "addresses": [ + "FtCkFSrwrgiJzjQzGRZvjHzrmHp4HJeGYm" + ] + }, + "spent": true + } + ], + "blockhash": "0000000000000a79428395294255704ed877847d93c6d36108dc8184b71c1f0a", + "blockheight": 2959365, + "confirmations": 59348, + "time": 1581386699, + "blocktime": 1581386699, + "valueOut": "59.511497", + "valueIn": "59.5115306", + "fees": "0.0000336", + "hex": "02000000000101284c07d8c471e204aa60938a9114f5263ddc4ba5e717e39d9ec8c2ed3dd2e0d80000000017160014d6c589125f084df1e3286fcd55446b64dc7de130feffffff0284269d440000000017a91436d64490426cc347a50bdd3f8db2ef20d62949f58700301a1e010000001976a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac02473044022034f3f2ab2d021a27ba999aebb40016f921433c39149d6908fe1e96d914c5c96402203d5d12127f64a01429775090abb445b5af2ec90803372c92499a35e12e229adb0121033ca60a0478fee5583e52c3b85c4dacb81faa9c4a10ad8b4f574c1b050f814463bf272d00" + }, + { + "txid": "d8e0d23dedc2c89e9de317e7a54bdc3d26f514918a9360aa04e271c4d8074c28", + "version": 2, + "locktime": 2959360, + "vin": [ + { + "txid": "2ed852f7881270ec108c86482d609f818ee21ae07033796fb77cb8e52fa86ccd", + "vout": 0, + "sequence": 4294967294, + "n": 0, + "scriptSig": { + "hex": "47304402201fe0aff8dd5c35be49f824216adb51d0749878dc2d759d0dd6d4ed6612ca09cd02203ad7d2b2eaa52f341f325934cca2c2758ac4c4b7b8bc279e7748d48ab98b484901210246e7e23df8acf0a305b94009d9b60eca7230ce747493201a9574f7ccb03775e9" + }, + "addresses": [ + "Fg4WGddhNYayAF3mTPDNCFCEqrXydAd6Vu" + ], + "value": "297.5115752" + } + ], + "vout": [ + { + "value": "59.5115306", + "n": 0, + "scriptPubKey": { + "hex": "a914146081496e97dbb864af7df601184f8ec3624aa787", + "addresses": [ + "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" + ] + }, + "spent": true + }, + { + "value": "238", + "n": 1, + "scriptPubKey": { + "hex": "76a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac", + "addresses": [ + "FtCkFSrwrgiJzjQzGRZvjHzrmHp4HJeGYm" + ] + }, + "spent": true + } + ], + "blockhash": "0000000000000a79428395294255704ed877847d93c6d36108dc8184b71c1f0a", + "blockheight": 2959365, + "confirmations": 59348, + "time": 1581386699, + "blocktime": 1581386699, + "valueOut": "297.5115306", + "valueIn": "297.5115752", + "fees": "0.0000446", + "hex": "0200000001cd6ca82fe5b87cb76f793370e01ae28e819f602d48868c10ec701288f752d82e000000006a47304402201fe0aff8dd5c35be49f824216adb51d0749878dc2d759d0dd6d4ed6612ca09cd02203ad7d2b2eaa52f341f325934cca2c2758ac4c4b7b8bc279e7748d48ab98b484901210246e7e23df8acf0a305b94009d9b60eca7230ce747493201a9574f7ccb03775e9feffffff02a463b7620100000017a914146081496e97dbb864af7df601184f8ec3624aa787002e978a050000001976a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac00282d00" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/groestlcoin-api-xpub.js b/mock/ext-api-dyson/get/groestlcoin-api-xpub.js new file mode 100644 index 000000000..4e2160fb4 --- /dev/null +++ b/mock/ext-api-dyson/get/groestlcoin-api-xpub.js @@ -0,0 +1,157 @@ +/// Mock for external Groestlcoin API +/// See: +/// curl "http://{groestlcoin rpc}/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs" +/// curl "http://localhost:3000/groestlcoin-api/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs" +/// curl "http://localhost:8420/v1/groestlcoin/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf" + +module.exports = { + path: '/groestlcoin-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf", + "balance": "412844353", + "totalReceived": "289739972697", + "totalSent": "289327128344", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 98, + "transactions": [ + { + "txid": "686c651223b937b1223560a60631ad79ad17351c88bba67cad8ea0c95fccbb83", + "version": 1, + "vin": [ + { + "txid": "1e3362ef26063cae601362721fcde1c0e856b7d81abc9e541ba38a0b15330689", + "sequence": 2147483644, + "n": 0, + "addresses": [ + "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" + ], + "isAddress": true, + "value": "100000000" + }, + { + "txid": "1e3362ef26063cae601362721fcde1c0e856b7d81abc9e541ba38a0b15330689", + "vout": 1, + "sequence": 2147483645, + "n": 1, + "addresses": [ + "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" + ], + "isAddress": true, + "value": "212864353" + }, + { + "txid": "dd7780ee2529f7030153737c8ee2a16ef32817cbd63b6aba8553c4ccbeac368d", + "sequence": 2147483646, + "n": 2, + "addresses": [ + "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" + ], + "isAddress": true, + "value": "100000000" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "hex": "0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395", + "addresses": [ + "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" + ], + "isAddress": true + }, + { + "value": "402844353", + "n": 1, + "hex": "0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395", + "addresses": [ + "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" + ], + "isAddress": true + } + ], + "blockHash": "00000000000003a48c30ddfaa9c875b902e8372c448413ee65dba418601a5b7e", + "blockHeight": 2998112, + "confirmations": 20605, + "blockTime": 1583831414, + "value": "412844353", + "valueIn": "412864353", + "fees": "20000", + "hex": "01000000000103890633150b8aa31b549ebc1ad8b756e8c0e1cd1f72621360ae3c0626ef62331e0000000000fcffff7f890633150b8aa31b549ebc1ad8b756e8c0e1cd1f72621360ae3c0626ef62331e0100000000fdffff7f8d36acbeccc45385ba6a3bd6cb1728f36ea1e28e7c73530103f72925ee8077dd0000000000feffff7f028096980000000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395c1ea021800000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb423950247304402201b4acd75cb1186fba1405bd604a2e24a960d94a39e14316f4e6ef5289808e4c90220569d652a91ecc149d543d7aab0653a646ce60d8e3bed053d421907432bd7c9bd012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b285024730440220426733a0a12dd1c34142d9814e74987fdbb41438189fb0bbed74ab2cd420a9b4022046dc588c6690b1ecba351b8a981ed3db63df9de95df49d5a8333b087b349b6c3012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b285024730440220291f4932101719b70630233d53503854f456a0a944453a6105f4e2b95fde526b0220617d4dd0b4dd12e8917d15f80dadf617ec584fe650a31ca8f07f4d6869256549012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000" + }, + { + "txid": "1e3362ef26063cae601362721fcde1c0e856b7d81abc9e541ba38a0b15330689", + "version": 1, + "vin": [ + { + "txid": "dd7780ee2529f7030153737c8ee2a16ef32817cbd63b6aba8553c4ccbeac368d", + "vout": 1, + "n": 0, + "addresses": [ + "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" + ], + "isAddress": true, + "value": "312884353" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395", + "addresses": [ + "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" + ], + "isAddress": true + }, + { + "value": "212864353", + "n": 1, + "spent": true, + "hex": "0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395", + "addresses": [ + "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" + ], + "isAddress": true + } + ], + "blockHash": "000000000000034560a3a07b6498c9b937da914a4f683d1575197a02c4b69a83", + "blockHeight": 2989928, + "confirmations": 28789, + "blockTime": 1583315379, + "value": "312864353", + "valueIn": "312884353", + "fees": "20000", + "hex": "010000000001018d36acbeccc45385ba6a3bd6cb1728f36ea1e28e7c73530103f72925ee8077dd0100000000000000000200e1f50500000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395610db00c00000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb4239502483045022100e0e7e5484f9d06120f0e3a63471d353d90b65ba63b0fbf640c714608414ffa5d02204556b0c2554bc33ebfb338d806fa1589df1e25afe251c5a7869cfad6e6ef0a61012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000" + } + ], + "usedTokens": 79, + "tokens": [ + { + "type": "XPUBAddress", + "name": "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04", + "path": "m/84'/17'/0'/0/0", + "transfers": 53, + "decimals": 8, + "balance": "412844353", + "totalReceived": "34760610350", + "totalSent": "34347765997" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/icon-api-actions.js b/mock/ext-api-dyson/get/icon-api-actions.js new file mode 100644 index 000000000..78b72c8dc --- /dev/null +++ b/mock/ext-api-dyson/get/icon-api-actions.js @@ -0,0 +1,73 @@ +/// Icon API Mock +/// See: +/// curl "http://localhost:3000/icon-api/address/txList?address=hxee691e7bccc4eb11fee922896e9f51490e62b12e&count=25" +/// curl "https://tracker.icon.foundation/v3/address/txList?address=hxee691e7bccc4eb11fee922896e9f51490e62b12e&count=25" +/// curl http://localhost:8420/v1/icon/hxee691e7bccc4eb11fee922896e9f51490e62b12e +module.exports = { + path: "/icon-api/address/:action?", + template: function(params, query, body) { + //console.log(query) + if (params.action === 'txList') { + if (query.address === 'hxee691e7bccc4eb11fee922896e9f51490e62b12e') { + return JSON.parse(` + { + "data": [ + { + "txHash": "0x3b1a382884091e683350d6285d908406c149a030a7d52eb347f4571c1c904382", + "height": 7044559, + "createDate": "2019-08-13T06:53:56.000+0000", + "fromAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", + "toAddr": "hx06d5b88bb7089033a2d8a2b61b8a305ecff8774f", + "txType": "0", + "dataType": "icx", + "amount": "0.498", + "fee": "0.001", + "state": 1, + "errorMsg": null, + "targetContractAddr": null, + "id": null + }, + { + "txHash": "0x990b7f289aa465369e638b4f719c99f0d050f9756c19081ba86b2bae5b8e2f0d", + "height": 361987, + "createDate": "2019-04-17T01:16:02.000+0000", + "fromAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", + "toAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", + "txType": "0", + "dataType": "icx", + "amount": "0.00347", + "fee": "0.001", + "state": 1, + "errorMsg": null, + "targetContractAddr": null, + "id": null + }, + { + "txHash": "0x3a455daca1f5e4588adbc6ac5cdfd84126d0617d3ebcf5610eb44b15dfc71402", + "height": 112100, + "createDate": "2018-11-23T21:52:15.000+0000", + "fromAddr": "hx3709f4e615f072158247ca4973218e1d40e0ea35", + "toAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", + "txType": "0", + "dataType": "icx", + "amount": "0.5", + "fee": "0.001", + "state": 1, + "errorMsg": null, + "targetContractAddr": null, + "id": null + } + ], + "listSize": 3, + "totalSize": 3, + "result": "200", + "description": "success" + } + `); + } + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/iotex-get-accounts.js b/mock/ext-api-dyson/get/iotex-get-accounts.js new file mode 100644 index 000000000..9e5912ade --- /dev/null +++ b/mock/ext-api-dyson/get/iotex-get-accounts.js @@ -0,0 +1,71 @@ +/// Iotex API Mock +/// See: +/// curl "http://localhost:3000/iotex-api/actions/addr/io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5?start=0&count=25" +/// curl "https://pharos.iotex.io/v1/actions/addr/io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5?start=0&count=25" +/// curl http://localhost:8420/v1/iotex/io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5 +module.exports = { + path: "/iotex-api/actions/:action/:address?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + if (params.action === 'addr') { + if (params.address === 'io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5') { + return JSON.parse(` + { + "total": "2", + "actionInfo": [ + { + "action": { + "core": { + "version": 1, + "nonce": "40", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "5010000000000000000000", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BHd42w46LIO7qw5+TsTo+QjAUZBhVc3NPwEVh3IHePcFQQeb9rFSPmEV6LhFS7cqRzDBpgSHuQbelY6wnPvMYmw=", + "signature": "CiJdvAO3jNUX7agpE4AvtrBdEzgFsm1MANhXTXeVtdkXxNrDV8xbSiFz6FuFUTd1L5uaFXoe1mxUPIrbTabh4QE=" + }, + "actHash": "7aceeda86535b8dd345e1ab2176a7f12e1907aac3591cf9422a5393feadb6bb6", + "blkHash": "57ca5160cb9aac7a16b4e5006295d93857220de966335a2a453992c824037ebe", + "blkHeight": "3291297", + "sender": "io1r8cwhdec6y3fpv42hv7ak0aqh0cfyc279ladxl", + "gasFee": "10000000000000000", + "timestamp": "2020-02-14T01:44:30Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "1", + "gasLimit": "500000", + "gasPrice": "1000000000000", + "execution": { + "amount": "5000000000000000000000", + "contract": "io1zn9mn4v63jg3047ylqx9nqaqz0ev659777q3xc", + "data": "B8NfwAAAAAAAY29yZWRldgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + } + }, + "senderPubKey": "BKarIa2N7C/tz6r93fnnHXHEXyGC4aG9fiTYSjwSKpUOWl2efDuLb9Fk+NysVn1hEFgFLjRONu/KlM4TnHaIQLQ=", + "signature": "0Pn96CJXbUmNvXsnvx0RgqPYuac7YD699liT/WqmE9Ak4EHYZXhTozu+t+JrM4cHmt37z7M3R4lbzC77gggHdgA=" + }, + "actHash": "7644e425163920f1d5658e12c96d6dfb4961ee35bc9886347fbb339d6b939dd8", + "blkHash": "1f7ab328160d0643b7a6af287a1559a88de70cd8a2068d40dcc814fdcdfba996", + "blkHeight": "3292065", + "sender": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5", + "gasFee": "264146000000000000", + "timestamp": "2020-02-14T02:48:30Z" + } + ] + } + `); + } + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/kava-api-txs.js b/mock/ext-api-dyson/get/kava-api-txs.js new file mode 100644 index 000000000..e701f0ee3 --- /dev/null +++ b/mock/ext-api-dyson/get/kava-api-txs.js @@ -0,0 +1,279 @@ +/// Kava API Mock +/// See: +/// curl "http://localhost:3000/kava-api/txs?transfer.recipient=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" +/// curl "http://localhost:3000/kava-api/txs?message.sender=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" +/// curl "http://{kava rpc}/txs?transfer.recipient=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" +/// curl "http://{kava rpc}/txs?message.sender=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" +/// curl http://localhost:8420/v1/kava/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m +module.exports = { + path: "/kava-api/txs?", + template: function(params, query, body) { + //console.log(query) + if (query["transfer.recipient"] === 'kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m') { + return JSON.parse(` + { + "total_count": "1", + "count": "1", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "793039", + "txhash": "84FFA6CC8428B7A5E82003A7BCA6D1FAB2DF296AD18BE73EE61CBCBF67623880", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "amount", + "value": "9999000ukava" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "70019", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7", + "to_address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", + "amount": [ + { + "denom": "ukava", + "amount": "9999000" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "ukava", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "As3eDIXFkLdMkBep+aV+6q9ccVRkA94snsXq2iL5bCTt" + }, + "signature": "QFx3iARLhLeuCCHRUbFAZTePzq+vGAYd4lB/F4JuCGYw1TrfIbAzJhmUHbXHcB/GC+f7Myv5xNrnlCPfCR53uA==" + } + ], + "memo": "" + } + }, + "timestamp": "2020-01-17T11:17:36Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "amount", + "value": "9999000ukava" + } + ] + } + ] + } + ] + } + `); + } + + if (query["message.sender"] === 'kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m') { + return JSON.parse(` + { + "total_count": "1", + "count": "1", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "1101012", + "txhash": "30EFE9E830D317F84629F9DC35177577DF6713D78D354C2C469DE633900303BC", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" + }, + { + "key": "amount", + "value": "9998000ukava" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "68317", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", + "to_address": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7", + "amount": [ + { + "denom": "ukava", + "amount": "9998000" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "ukava", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "AvgGasyPvRpG68UQ6IGPVKN+HrJix24tgwcYXIcIfsna" + }, + "signature": "iST3iM8TtkR5VHTFFhJE1zi+Nh6Invrg4hKgLEY2HCQ+R6Qj9L3jET4yRtAg6+QxitJab27+etoPjJbK20V/Cw==" + } + ], + "memo": "100009547" + } + }, + "timestamp": "2020-02-11T01:33:46Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" + }, + { + "key": "amount", + "value": "9998000ukava" + } + ] + } + ] + } + ] + } + `); + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; + diff --git a/mock/ext-api-dyson/get/kin-api-accounts.js b/mock/ext-api-dyson/get/kin-api-accounts.js new file mode 100644 index 000000000..8351cd6b8 --- /dev/null +++ b/mock/ext-api-dyson/get/kin-api-accounts.js @@ -0,0 +1,97 @@ +/// Kin API Mock, accounts +/// See: +/// curl "http://localhost:3000/kin-api/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?order=desc&limit=25" +/// curl "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?order=desc&limit=25" +/// curl http://localhost:8420/v1/kin/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH +module.exports = { + path: "/kin-api/accounts/:address/:operation?", + template: function(params, query, body) { + //console.log(query) + if (params.operation === 'payments') { + if (params.address === 'GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH') { + return JSON.parse(` + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?cursor=\u0026limit=25\u0026order=desc" + }, + "next": { + "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?cursor=31839477328764929\u0026limit=25\u0026order=desc" + }, + "prev": { + "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?cursor=32148096498577409\u0026limit=25\u0026order=asc" + } + }, + "_embedded": { + "records": [ + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/32148096498577409" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/32148096498577409/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=32148096498577409" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=32148096498577409" + } + }, + "id": "32148096498577409", + "paging_token": "32148096498577409", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "payment", + "type_i": 1, + "created_at": "2020-03-24T01:43:00Z", + "transaction_hash": "b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a", + "asset_type": "native", + "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "to": "GBWDEMV6IAU6HJP55VK3R7ZZSPL4GWHMCAC4WFBRBTN7TPPPYXFFH4AR", + "amount": "151431.00000" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/32134176509775873" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/32134176509775873/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=32134176509775873" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=32134176509775873" + } + }, + "id": "32134176509775873", + "paging_token": "32134176509775873", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "payment", + "type_i": 1, + "created_at": "2020-03-23T21:12:01Z", + "transaction_hash": "eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed", + "asset_type": "native", + "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "to": "GA5IZMCHFS54NN3I73ZAPQZWI7EKNXU6AP5QIVTEKJMPFW6I2GZVD3JO", + "amount": "4009823.45205" + } + ] + } + } + `); + } + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/kin-api-transactions.js b/mock/ext-api-dyson/get/kin-api-transactions.js new file mode 100644 index 000000000..604d7027a --- /dev/null +++ b/mock/ext-api-dyson/get/kin-api-transactions.js @@ -0,0 +1,112 @@ +/// Kin API Mock, transactions +/// See: +/// curl "http://localhost:3000/kin-api/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a?" +/// curl "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a?" +/// curl http://localhost:8420/v1/kin/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX +module.exports = { + path: "/kin-api/transactions/:txid?", + template: function(params, query, body) { + //console.log(query) + if (params.txid === 'b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a') { + return JSON.parse(` + { + "memo": "Namilak8", + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a" + }, + "account": { + "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH" + }, + "ledger": { + "href": "https://horizon-block-explorer.kininfrastructure.com/ledgers/7485062" + }, + "operations": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a/operations{?cursor,limit,order}", + "templated": true + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a/effects{?cursor,limit,order}", + "templated": true + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=asc\u0026cursor=32148096498577408" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=desc\u0026cursor=32148096498577408" + } + }, + "id": "b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a", + "paging_token": "32148096498577408", + "hash": "b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a", + "ledger": 7485062, + "created_at": "2020-03-24T01:43:00Z", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "source_account_sequence": "3873257342118155", + "fee_paid": 100, + "operation_count": 1, + "envelope_xdr": "AAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAAAAZAANwrUAACkLAAAAAAAAAAEAAAAITmFtaWxhazgAAAABAAAAAQAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAAAEAAAAAbDIyvkAp46X97VW4/zmT18NY7BAFyxQxDNv5ve/FylMAAAAAAAAAA4aZXmAAAAAAAAAAATKoLogAAABAiivAdbjfQvWTMheamksBZp9yBc9oRN2E2OpPhTCeT/bICu6eSr3FJy+WqYlieBlXtdVbBaoCWOlR07Mi4QqjDQ==", + "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", + "result_meta_xdr": "AAAAAAAAAAEAAAAEAAAAAwByNoYAAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHRPE+rKwADcK1AAApCwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByNoYAAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHQWqlTkwADcK1AAApCwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBwLBkAAAAAAAAAAGwyMr5AKeOl/e1VuP85k9fDWOwQBcsUMQzb+b3vxcpTAAAAAzCVZ9QAcAeUAAAAAwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByNoYAAAAAAAAAAGwyMr5AKeOl/e1VuP85k9fDWOwQBcsUMQzb+b3vxcpTAAAABrcuxjQAcAeUAAAAAwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA", + "fee_meta_xdr": "AAAAAgAAAAMAcindAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR0TxPq0QAA3CtQAAKQoAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAcjaGAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR0TxPqysAA3CtQAAKQsAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==", + "memo_type": "text", + "signatures": [ + "iivAdbjfQvWTMheamksBZp9yBc9oRN2E2OpPhTCeT/bICu6eSr3FJy+WqYlieBlXtdVbBaoCWOlR07Mi4QqjDQ==" + ] + } + `); + } + if (params.txid === 'eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed') { + return JSON.parse(` + { + "memo": "", + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed" + }, + "account": { + "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH" + }, + "ledger": { + "href": "https://horizon-block-explorer.kininfrastructure.com/ledgers/7481821" + }, + "operations": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed/operations{?cursor,limit,order}", + "templated": true + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed/effects{?cursor,limit,order}", + "templated": true + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=asc\u0026cursor=32134176509775872" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=desc\u0026cursor=32134176509775872" + } + }, + "id": "eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed", + "paging_token": "32134176509775872", + "hash": "eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed", + "ledger": 7481821, + "created_at": "2020-03-23T21:12:01Z", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "source_account_sequence": "3873257342118154", + "fee_paid": 100, + "operation_count": 1, + "envelope_xdr": "AAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAAAAZAANwrUAACkKAAAAAAAAAAEAAAAAAAAAAQAAAAEAAAAATqpn4tSz1u76l93pz8ttLSIDQbslHppzlH1cgjKoLogAAAABAAAAADqMsEcsu8a3aP7yB8M2R8im3p4D+wRWZFJY8tvI0bNRAAAAAAAAAF1caQX1AAAAAAAAAAEyqC6IAAAAQFsrhOcyOXVWLIFf8aSJh37W1bx4ZP3qKXPejdB2M0z+FG09ggG0uDiV7FAsmRvzPUGoEgI3reEw+eAFByO6dAs=", + "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", + "result_meta_xdr": "AAAAAAAAAAEAAAAEAAAAAwByKaQAAAAAAAAAADqMsEcsu8a3aP7yB8M2R8im3p4D+wRWZFJY8tvI0bNRAAAAdGpUDqAAcik+AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByKd0AAAAAAAAAADqMsEcsu8a3aP7yB8M2R8im3p4D+wRWZFJY8tvI0bNRAAAA0ca9FJUAcik+AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwByKd0AAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHok2nswUADcK1AAApCgAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByKd0AAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHRPE+rRAADcK1AAApCgAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA", + "fee_meta_xdr": "AAAAAgAAAAMAcimkAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR6JNp7NpAA3CtQAAKQkAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAcindAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR6JNp7MFAA3CtQAAKQoAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==", + "memo_type": "text", + "signatures": [ + "WyuE5zI5dVYsgV/xpImHftbVvHhk/eopc96N0HYzTP4UbT2CAbS4OJXsUCyZG/M9QagSAjet4TD54AUHI7p0Cw==" + ] + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/litecoin-api-address.js b/mock/ext-api-dyson/get/litecoin-api-address.js new file mode 100644 index 000000000..03379a122 --- /dev/null +++ b/mock/ext-api-dyson/get/litecoin-api-address.js @@ -0,0 +1,132 @@ +/// Mock for external Litecoin API +/// See: +/// curl "http://{ltc rpc}/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" +/// curl "http://localhost:3000/litecoin-api/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" +/// curl "http://localhost:8420/v1/litecoin/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + +module.exports = { + path: '/litecoin-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "addrStr": "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept", + "balance": "0.01688078", + "totalReceived": "0.25679292", + "totalSent": "0.23991214", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 19, + "txs": [ + { + "txid": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1", + "version": 1, + "vin": [ + { + "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", + "vout": 1, + "n": 0, + "scriptSig": {}, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "value": "0.0078853" + } + ], + "vout": [ + { + "value": "0.001", + "n": 0, + "scriptPubKey": { + "hex": "0014ccf05f3bc453f7f66fb48b124bd79690bc309e22", + "addresses": [ + "ltc1qenc97w7y20mlvma53vfyh4ukjz7rp83zf892wx" + ] + }, + "spent": false + }, + { + "value": "0.00688078", + "n": 1, + "scriptPubKey": { + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ] + }, + "spent": false + } + ], + "blockhash": "ae8df4fb9cbbd07375eef217dd25e8b918a1b2746907c23cf4f2e15cd18fccdd", + "blockheight": 1804076, + "confirmations": 7531, + "time": 1583910871, + "blocktime": 1583910871, + "valueOut": "0.00788078", + "valueIn": "0.0078853", + "fees": "0.00000452", + "hex": "0100000000010167f89bc6125388f252bd770e142e61b9ab23dfb18762ba210f6f162bed92406701000000000000000002a086010000000000160014ccf05f3bc453f7f66fb48b124bd79690bc309e22ce7f0a00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100a40df50e2b419a35001f40d508e911f36d01497ebe5225dc93c81f53a30452fb022034c086517326be293019c2cbf215d6b9a53aa0ab4a0c2b890a9f1b05e8052aac012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", + "version": 1, + "vin": [ + { + "txid": "f8ddc3eca55aa4bffd27b030fc3b35ceb8d503b31a03dafd32df56eec552fe99", + "vout": 1, + "sequence": 4294967290, + "n": 0, + "scriptSig": {}, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "value": "0.01788982" + } + ], + "vout": [ + { + "value": "0.01", + "n": 0, + "scriptPubKey": { + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ] + }, + "spent": false + }, + { + "value": "0.0078853", + "n": 1, + "scriptPubKey": { + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ] + }, + "spent": true + } + ], + "blockhash": "dd92763dcb8477d8f012e5ec0598ebf3c135a15780d7491754fff40d3d24dd9b", + "blockheight": 1803562, + "confirmations": 8045, + "time": 1583831802, + "blocktime": 1583831802, + "valueOut": "0.0178853", + "valueIn": "0.01788982", + "fees": "0.00000452", + "hex": "0100000000010199fe52c5ee56df32fdda031ab303d5b8ce353bfc30b027fdbfa45aa5ecc3ddf80100000000faffffff0240420f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c532080c00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100bbde918ff538468c440424323bbe8ba78eef14d9dde357c8e6496905d540098c02205700d984884edff918f827289898c16ec9ad30344a637ea85dc55f7f836143bd012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/litecoin-api-xpub.js b/mock/ext-api-dyson/get/litecoin-api-xpub.js new file mode 100644 index 000000000..66b83d0f5 --- /dev/null +++ b/mock/ext-api-dyson/get/litecoin-api-xpub.js @@ -0,0 +1,166 @@ +/// Mock for external Litecoin API +/// See: +/// curl "http://{ltc rpc}/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs" +/// curl "http://localhost:3000/litecoin-api/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs" +/// curl "http://localhost:8420/v1/litecoin/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu" + +module.exports = { + path: '/litecoin-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu", + "balance": "1818078", + "totalReceived": "379622767", + "totalSent": "377804689", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 130, + "transactions": [ + { + "txid": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1", + "version": 1, + "vin": [ + { + "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", + "vout": 1, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "788530" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "0014ccf05f3bc453f7f66fb48b124bd79690bc309e22", + "addresses": [ + "ltc1qenc97w7y20mlvma53vfyh4ukjz7rp83zf892wx" + ], + "isAddress": true + }, + { + "value": "688078", + "n": 1, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "ae8df4fb9cbbd07375eef217dd25e8b918a1b2746907c23cf4f2e15cd18fccdd", + "blockHeight": 1804076, + "confirmations": 7532, + "blockTime": 1583910871, + "value": "788078", + "valueIn": "788530", + "fees": "452", + "hex": "0100000000010167f89bc6125388f252bd770e142e61b9ab23dfb18762ba210f6f162bed92406701000000000000000002a086010000000000160014ccf05f3bc453f7f66fb48b124bd79690bc309e22ce7f0a00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100a40df50e2b419a35001f40d508e911f36d01497ebe5225dc93c81f53a30452fb022034c086517326be293019c2cbf215d6b9a53aa0ab4a0c2b890a9f1b05e8052aac012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", + "version": 1, + "vin": [ + { + "txid": "f8ddc3eca55aa4bffd27b030fc3b35ceb8d503b31a03dafd32df56eec552fe99", + "vout": 1, + "sequence": 4294967290, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "1788982" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + }, + { + "value": "788530", + "n": 1, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "dd92763dcb8477d8f012e5ec0598ebf3c135a15780d7491754fff40d3d24dd9b", + "blockHeight": 1803562, + "confirmations": 8046, + "blockTime": 1583831802, + "value": "1788530", + "valueIn": "1788982", + "fees": "452", + "hex": "0100000000010199fe52c5ee56df32fdda031ab303d5b8ce353bfc30b027fdbfa45aa5ecc3ddf80100000000faffffff0240420f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c532080c00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100bbde918ff538468c440424323bbe8ba78eef14d9dde357c8e6496905d540098c02205700d984884edff918f827289898c16ec9ad30344a637ea85dc55f7f836143bd012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + } + ], + "usedTokens": 123, + "tokens": [ + { + "type": "XPUBAddress", + "name": "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept", + "path": "m/84'/2'/0'/0/0", + "transfers": 19, + "decimals": 8, + "balance": "1688078", + "totalReceived": "25679292", + "totalSent": "23991214" + }, + { + "type": "XPUBAddress", + "name": "ltc1q2rs8e2xy7tr7c5e4zugqzwsry5dtt5wcdk4zv9", + "path": "m/84'/2'/0'/0/54", + "transfers": 4, + "decimals": 8, + "balance": "20000", + "totalReceived": "2009886", + "totalSent": "1989886" + }, + { + "type": "XPUBAddress", + "name": "ltc1q2j0k8v7aczdajd42g96h7gy4jef63feh77494u", + "path": "m/84'/2'/0'/0/58", + "transfers": 3, + "decimals": 8, + "balance": "10000", + "totalReceived": "11000", + "totalSent": "1000" + }, + { + "type": "XPUBAddress", + "name": "ltc1qxpa5d35hnj29nr8yn5g5t0zd3m4jwp8mwchc9c", + "path": "m/84'/2'/0'/0/59", + "transfers": 1, + "decimals": 8, + "balance": "100000", + "totalReceived": "100000", + "totalSent": "0" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/nebulas-api-tx.js b/mock/ext-api-dyson/get/nebulas-api-tx.js new file mode 100644 index 000000000..a4913f82e --- /dev/null +++ b/mock/ext-api-dyson/get/nebulas-api-tx.js @@ -0,0 +1,133 @@ +/// Nebulas API Mock +/// See: +/// curl "http://localhost:3000/nebulas-api/tx?a=n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a&p=0" +/// curl "https://explorer-backend.nebulas.io/api/tx?a=n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a&p=0" +/// curl http://localhost:8420/v1/nebulas/n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a +module.exports = { + path: "/nebulas-api/tx?", + template: function(params, query, body) { + //console.log(query) + if (query.a === 'n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a') { + return JSON.parse(` + { + "code": 0, + "msg": "success", + "data": { + "txnList": [ + { + "hash": "3cd98a767d8f5eaa87c8ffa95adbde3a4c08236b49ab0296f04057491e4bd1a3", + "block": { + "hash": "9bb20444ae79a542af44ed64241a440759aa59363641fa1b7594266f6f16109d", + "height": 2659950, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 1, + "timestamp": 1562378850000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20711", + "createdAt": 1562379080000, + "currentTimestamp": 1585045274097, + "timeDiff": 22666424097, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414220000000000" + }, + { + "hash": "0d06074b64c37ed24a17162d1e0ef8a8e65122fc7758c90c969e61735bc4396a", + "block": { + "hash": "faf4eb93b1a571c709bf1871e1c142570d3f5aeb787d325eba9a34a6ca56144b", + "height": 2659949, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1YDRkSbuzjRVYPbmGC9qULchXMeqS451Je", + "alias": "", + "balance": "37962400000000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "status": 1, + "value": "10000000000000000", + "nonce": 210, + "timestamp": 1562378835000, + "type": "binary", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20000", + "createdAt": 1562379063000, + "currentTimestamp": 1585045274097, + "timeDiff": 22666439097, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "400000000000000" + } + ], + "totalPage": 1, + "maxDisplayCnt": 16, + "type": "address", + "currentPage": 0, + "txnCnt": 2 + } + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js b/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js new file mode 100644 index 000000000..9e5bf722d --- /dev/null +++ b/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js @@ -0,0 +1,124 @@ +/// Ontology API Mock +/// See: +/// curl "http://localhost:3000/ontology-api/v2/addresses/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7/transactions?page_size=20&page_number=1" +/// curl "https://explorer.ont.io/v2/addresses/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7/transactions?page_size=20&page_number=1" +/// curl http://localhost:8420/v1/ontology/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7 +module.exports = { + path: "/ontology-api/v2/addresses/:address/:operation?", + template: function(params, query, body) { + //console.log(params) + if (params.address === 'AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7') { + return JSON.parse(` + { + "code": 0, + "msg": "SUCCESS", + "result": [ + { + "tx_hash": "d3be042ae21a313bc70fbfea62d11fb32731126101859a66f523e081c3fd429c", + "tx_type": 209, + "tx_time": 1582189609, + "block_height": 7836941, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.4", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "5c9a5f708953ee6cd13623e9d3fd610530159fafe71a8d207d890ed7b97f3ced", + "tx_type": 209, + "tx_time": 1582188446, + "block_height": 7836832, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.02", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "7e35568117aaed4e041d281087b2f47da91a4ac183c370d40040aa2b496d5878", + "tx_type": 209, + "tx_time": 1582122942, + "block_height": 7832679, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.011074432", + "from_address": "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "0ae15301f25a5067c075a25e722f0624a813a1352363197de2dd5f61ebd2998d", + "tx_type": 209, + "tx_time": 1581924056, + "block_height": 7819845, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + } + ] + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/poa-api-transactions.js b/mock/ext-api-dyson/get/poa-api-transactions.js new file mode 100644 index 000000000..ef3808277 --- /dev/null +++ b/mock/ext-api-dyson/get/poa-api-transactions.js @@ -0,0 +1,113 @@ +/// POA API Mock +/// See: +/// curl "http://localhost:3000/poa-api/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" +/// curl "http://{poa rpc}/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" +/// curl http://localhost:8420/v1/poa/0x55798eCbF17ce1241d543c22dCE46134c13b4bc0 + +module.exports = { + path: '/poa-api/transactions', + template: function(params, query, body) { + //console.log(query) + if (query.address === '0x55798eCbF17ce1241d543c22dCE46134c13b4bc0') { + return JSON.parse(` + { + "docs": [ + { + "operations": [ + { + "transactionId": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d-0", + "contract": { + "address": "0xab2f2dd3120de530d38936ee09a74a6d17e3da44", + "decimals": 18, + "name": "GeonCoin", + "symbol": "GC", + "totalSupply": "100000000000000000000000000", + "updatedAt": "2020-02-26T23:41:29.763Z" + }, + "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "to": "0xE87E46032847e097F5bB51404d19A0449c704EE8", + "type": "token_transfer", + "value": "1000000000000000000", + "id": null + } + ], + "contract": null, + "_id": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d", + "blockNumber": 14115901, + "time": 1584448420, + "nonce": 1, + "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "to": "0xAb2f2Dd3120dE530d38936EE09A74a6d17e3Da44", + "value": "0", + "gas": "120000", + "gasPrice": "1000000000", + "gasUsed": "78484", + "input": "0xb88a3f725e70c38d1d03b5568e2f4d1600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000", + "error": "", + "id": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d", + "timeStamp": "1584448420" + }, + { + "operations": [], + "contract": null, + "_id": "0xcde1f2c3a262012f624065f167616db3160e763f4938ccfa0fcc742d5725eae2", + "blockNumber": 14115900, + "time": 1584448415, + "nonce": 109291, + "from": "0x628cF7150f8242b20B2ADB064D27183D2a026130", + "to": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "value": "600000000000000", + "gas": "120000", + "gasPrice": "1000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0xcde1f2c3a262012f624065f167616db3160e763f4938ccfa0fcc742d5725eae2", + "timeStamp": "1584448415" + }, + { + "operations": [], + "contract": null, + "_id": "0x90ef177d3448d379560218f99657027661a7238fb62c793dc2a7091a0d0d88e8", + "blockNumber": 14115899, + "time": 1584448410, + "nonce": 0, + "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "to": "0xE87E46032847e097F5bB51404d19A0449c704EE8", + "value": "0", + "gas": "120000", + "gasPrice": "1000000000", + "gasUsed": "100890", + "input": "0x1e76c9445e70c38d1d03b5568e2f4d160000000000000000000000000000000000000000", + "error": "", + "id": "0x90ef177d3448d379560218f99657027661a7238fb62c793dc2a7091a0d0d88e8", + "timeStamp": "1584448410" + }, + { + "operations": [], + "contract": null, + "_id": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3", + "blockNumber": 14115898, + "time": 1584448405, + "nonce": 109290, + "from": "0x628cF7150f8242b20B2ADB064D27183D2a026130", + "to": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "value": "600000000000000", + "gas": "120000", + "gasPrice": "1000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3", + "timeStamp": "1584448405" + } + ], + "total": 4 + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/qtum-api-address.js b/mock/ext-api-dyson/get/qtum-api-address.js new file mode 100644 index 000000000..77eaeab2c --- /dev/null +++ b/mock/ext-api-dyson/get/qtum-api-address.js @@ -0,0 +1,178 @@ +/// Mock for external Qtum API +/// See: +/// curl "http://{qtum rpc}/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" +/// curl "http://localhost:3000/qtum-api/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" +/// curl "http://localhost:8420/v1/qtum/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + +module.exports = { + path: '/qtum-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "addrStr": "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", + "balance": "2.3535761", + "totalReceived": "433.3535761", + "totalSent": "431", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 5, + "txs": [ + { + "txid": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67", + "version": 1, + "vin": [ + { + "txid": "782e18a7b1bf612972e773fd6ccdcbe0c4514c661c31a7942f5dcd4807c5ab68", + "vout": 0, + "sequence": 4294967293, + "n": 0, + "scriptSig": { + "hex": "483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1e" + }, + "addresses": [ + "QWLQSMPF5WKAqhXxePJvjUJNjxDHrPCbjB" + ], + "value": "0.001" + }, + { + "txid": "80b7c6bcba625ad4abb69f7e92521a782681e984982408d40ad35a24b3f78297", + "vout": 0, + "sequence": 4294967294, + "n": 1, + "scriptSig": { + "hex": "48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5b" + }, + "addresses": [ + "QgqVXuCCN1m4Hfb9HCkrzbgUSkoodKsrVY" + ], + "value": "0.001" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "vout": 0, + "sequence": 4294967292, + "n": 2, + "scriptSig": { + "hex": "473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbc" + }, + "addresses": [ + "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" + ], + "value": "0.1" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "vout": 1, + "sequence": 4294967291, + "n": 3, + "scriptSig": { + "hex": "483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3" + }, + "addresses": [ + "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" + ], + "value": "2.2549462" + } + ], + "vout": [ + { + "value": "2.3535761", + "n": 0, + "scriptPubKey": { + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ] + }, + "spent": false + } + ], + "blockhash": "6e71fa96ca29a6e4cbd10defaa4fc69ff09adec45fc666d82afade3f75206cc1", + "blockheight": 563426, + "confirmations": 11011, + "time": 1583720608, + "blocktime": 1583720608, + "valueOut": "2.3535761", + "valueIn": "2.3569462", + "fees": "0.0033701", + "hex": "010000000468abc50748cd5d2f94a7311c664c51c4e0cbcd6cfd73e7722961bfb1a7182e78000000006b483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1efdffffff9782f7b3245ad30ad408249884e98126781a52927e9fb6abd45a62babcc6b780000000006b48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5bfeffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c000000006a473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbcfcffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c010000006b483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3fbffffff01aa45070e000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac00000000" + }, + { + "txid": "ef335bef783551cb054acd220555f1588cc4b03c0f47cc0839220c81d3ceb88d", + "version": 1, + "vin": [ + { + "txid": "506d07570d75914d5bd319d591374fb9cd1633f5c8b3cc800387e104298e8a62", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "scriptSig": { + "hex": "4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081e" + }, + "addresses": [ + "QfLtauKWxzF6pDf2ceXJe5oqizNHVMBneH" + ], + "value": "1.98984808" + }, + { + "txid": "e22c3e2ea4d285b71a73c41cdbb51f7c75d80b6f473e7f4aade6df5bf8771942", + "vout": 0, + "sequence": 4294967292, + "n": 1, + "scriptSig": { + "hex": "483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764" + }, + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "value": "430" + } + ], + "vout": [ + { + "value": "430", + "n": 0, + "scriptPubKey": { + "hex": "76a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac", + "addresses": [ + "QURZqPoBfuXXoHDkCHCvhGJa1DP2Ahj1KX" + ] + }, + "spent": true + }, + { + "value": "1.98831468", + "n": 1, + "scriptPubKey": { + "hex": "76a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac", + "addresses": [ + "QdfcTR3TQHjGHcKLiHmiPLRfVPFRWazJPg" + ] + }, + "spent": true + } + ], + "blockhash": "918141389623f4f880b1ba279bb70ee91de6a005e1a9d523d21a66e8c55f0502", + "blockheight": 393505, + "confirmations": 180932, + "time": 1560879520, + "blocktime": 1560879520, + "valueOut": "431.98831468", + "valueIn": "431.98984808", + "fees": "0.0015334", + "hex": "0100000002628a8e2904e1870380ccb3c8f53316cdb94f3791d519d35b4d91750d57076d50010000006b4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081efeffffff421977f85bdfe6ad4a7f3e476f0bd8757c1fb5db1cc4731ab785d2a42e3e2ce2000000006b483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764fcffffff0200eeff020a0000001976a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac6cedd90b000000001976a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac00000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/qtum-api-xpub.js b/mock/ext-api-dyson/get/qtum-api-xpub.js new file mode 100644 index 000000000..3716dbd4a --- /dev/null +++ b/mock/ext-api-dyson/get/qtum-api-xpub.js @@ -0,0 +1,164 @@ +/// Mock for external Qtum API +/// See: +/// curl "http://{qtum rpc}/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs" +/// curl "http://localhost:3000/qtum-api/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs" +/// curl "http://localhost:8420/v1/qtum/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd" + +module.exports = { + path: '/qtum-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd", + "balance": "235357610", + "totalReceived": "78913733296", + "totalSent": "78678375686", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 37, + "transactions": [ + { + "txid": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67", + "version": 1, + "vin": [ + { + "txid": "782e18a7b1bf612972e773fd6ccdcbe0c4514c661c31a7942f5dcd4807c5ab68", + "sequence": 4294967293, + "n": 0, + "addresses": [ + "QWLQSMPF5WKAqhXxePJvjUJNjxDHrPCbjB" + ], + "isAddress": true, + "value": "100000", + "hex": "483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1e" + }, + { + "txid": "80b7c6bcba625ad4abb69f7e92521a782681e984982408d40ad35a24b3f78297", + "sequence": 4294967294, + "n": 1, + "addresses": [ + "QgqVXuCCN1m4Hfb9HCkrzbgUSkoodKsrVY" + ], + "isAddress": true, + "value": "100000", + "hex": "48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5b" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "sequence": 4294967292, + "n": 2, + "addresses": [ + "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" + ], + "isAddress": true, + "value": "10000000", + "hex": "473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbc" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "vout": 1, + "sequence": 4294967291, + "n": 3, + "addresses": [ + "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" + ], + "isAddress": true, + "value": "225494620", + "hex": "483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3" + } + ], + "vout": [ + { + "value": "235357610", + "n": 0, + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true + } + ], + "blockHash": "6e71fa96ca29a6e4cbd10defaa4fc69ff09adec45fc666d82afade3f75206cc1", + "blockHeight": 563426, + "confirmations": 11012, + "blockTime": 1583720608, + "value": "235357610", + "valueIn": "235694620", + "fees": "337010", + "hex": "010000000468abc50748cd5d2f94a7311c664c51c4e0cbcd6cfd73e7722961bfb1a7182e78000000006b483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1efdffffff9782f7b3245ad30ad408249884e98126781a52927e9fb6abd45a62babcc6b780000000006b48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5bfeffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c000000006a473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbcfcffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c010000006b483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3fbffffff01aa45070e000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac00000000" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "version": 1, + "vin": [ + { + "txid": "1d597a91e1810fdbfcb712c11c4776f5384ab4e7bd94a2fdc6538b9afdc1e6d0", + "vout": 1, + "sequence": 4294967292, + "n": 0, + "addresses": [ + "QZsdyvpJnczcDPJoySkNTaSh8VP8XAXeMz" + ], + "isAddress": true, + "value": "235607620", + "hex": "4730440220679ad69958629be2516a0d93457ba24f154fd42e23a4f3f2896272fe97940eed0220395098fa364232f74440e50043d6b2868829cb11faf56057d12f68f4bac82bdc0121036ea9140776d2e6a3ec7dd32b9795b47cf592e90e4159f7db793019b069e78b46" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "76a9143dc1aae7701ab1f7be54fc69808c092ddb5a574088ac", + "addresses": [ + "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" + ], + "isAddress": true + }, + { + "value": "225494620", + "n": 1, + "spent": true, + "hex": "76a914d40a0b271f69b1d2f43f60c540325c9039b4a05588ac", + "addresses": [ + "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" + ], + "isAddress": true + } + ], + "blockHash": "a7a05f41f5f07faa5d3ca2cf5fb7de6a0cf46bc4ee465028ceda72ea5e6b5669", + "blockHeight": 479076, + "confirmations": 95362, + "blockTime": 1572922480, + "value": "235494620", + "valueIn": "235607620", + "fees": "113000", + "hex": "0100000001d0e6c1fd9a8b53c6fda294bde7b44a38f576471cc112b7fcdb0f81e1917a591d010000006a4730440220679ad69958629be2516a0d93457ba24f154fd42e23a4f3f2896272fe97940eed0220395098fa364232f74440e50043d6b2868829cb11faf56057d12f68f4bac82bdc0121036ea9140776d2e6a3ec7dd32b9795b47cf592e90e4159f7db793019b069e78b46fcffffff0280969800000000001976a9143dc1aae7701ab1f7be54fc69808c092ddb5a574088ac5cc6700d000000001976a914d40a0b271f69b1d2f43f60c540325c9039b4a05588ac00000000" + } + ], + "usedTokens": 33, + "tokens": [ + { + "type": "XPUBAddress", + "name": "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", + "path": "m/44'/2301'/0'/0/0", + "transfers": 5, + "decimals": 8, + "balance": "235357610", + "totalReceived": "43335357610", + "totalSent": "43100000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/ravencoin-api-address.js b/mock/ext-api-dyson/get/ravencoin-api-address.js new file mode 100644 index 000000000..ecd6d3ad5 --- /dev/null +++ b/mock/ext-api-dyson/get/ravencoin-api-address.js @@ -0,0 +1,139 @@ +/// Mock for external Ravencoin API +/// See: +/// curl "http://{Ravencoin rpc}/address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS?details=txs" +/// curl "http://localhost:3000/ravencoin-api/address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS?details=txs" +/// curl "http://localhost:8420/v1/ravencoin/address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" + +module.exports = { + path: '/ravencoin-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "addrStr": "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS", + "balance": "0", + "totalReceived": "10.48", + "totalSent": "10.48", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 5, + "txs": [ + { + "txid": "fc6c9e9c6cd0253f05e43a12d64154a689115f0103dc0b64957a8cb92b67f306", + "version": 1, + "vin": [ + { + "txid": "3717b528eb4925461d9de5a596d2eefe175985740b4fda153255e10135f236a6", + "vout": 1, + "sequence": 4294967293, + "n": 0, + "scriptSig": { + "hex": "483045022100b085c0f7d09937eed588f4c18e8ea600382926bcd0467a90436c7d3446ae2aa202206261e0b98c5d4852b17e32bcc04c2d6bc01dad327be0c16776ce9b6f57a44142012102138724e702d25b0fdce73372ccea9734f9349442d5a9681a5f4d831036cd9429" + }, + "addresses": [ + "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" + ], + "value": "0.48" + }, + { + "txid": "128793fa1635c630a3463225515f9aabfa6160ae32028d5ae6f09b04802abebe", + "vout": 0, + "sequence": 4294967294, + "n": 1, + "scriptSig": { + "hex": "47304402202f7f64346ddf51e1304e46407e1a285625b1c8e743b2a8ac919520a924be6ca102206a452426f9a1e105b0ba422b321cf358fe8d357cf985f43caf581ec7275f03ce0121030b22ea9d87e08432c18606849e801462189a45aaa9e158306cd5f26bcea3c61e" + }, + "addresses": [ + "RVtWJKBbG7JN3GQBkgwz4n4GYVPeViNer7" + ], + "value": "5.988166" + } + ], + "vout": [ + { + "value": "6.4679603", + "n": 0, + "scriptPubKey": { + "hex": "76a9148272c538003476df668581ad1336eecc774f274c88ac", + "addresses": [ + "RMAwQqgkYur4un2JbE6vPnZWeyzunXkuWo" + ] + }, + "spent": true + } + ], + "blockhash": "0000000000005cbc77e1a4b921e5de4fc5388fb661065e825877911d2364472a", + "blockheight": 753909, + "confirmations": 405243, + "time": 1560658623, + "blocktime": 1560658623, + "valueOut": "6.4679603", + "valueIn": "6.468166", + "fees": "0.0002057", + "hex": "0100000002a636f23501e1553215da4f0b74855917feeed296a5e59d1d462549eb28b51737010000006b483045022100b085c0f7d09937eed588f4c18e8ea600382926bcd0467a90436c7d3446ae2aa202206261e0b98c5d4852b17e32bcc04c2d6bc01dad327be0c16776ce9b6f57a44142012102138724e702d25b0fdce73372ccea9734f9349442d5a9681a5f4d831036cd9429fdffffffbebe2a80049bf0e65a8d0232ae6061faab9a5f51253246a330c63516fa938712000000006a47304402202f7f64346ddf51e1304e46407e1a285625b1c8e743b2a8ac919520a924be6ca102206a452426f9a1e105b0ba422b321cf358fe8d357cf985f43caf581ec7275f03ce0121030b22ea9d87e08432c18606849e801462189a45aaa9e158306cd5f26bcea3c61efeffffff01fe528d26000000001976a9148272c538003476df668581ad1336eecc774f274c88ac00000000" + }, + { + "txid": "3717b528eb4925461d9de5a596d2eefe175985740b4fda153255e10135f236a6", + "version": 1, + "vin": [ + { + "txid": "0c7e82b44eec71d634c013e2db3cb4fa26f87fbc90eb8734da93807d23605544", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": { + "hex": "483045022100d790bdaa3c44eb5e3a422365ca5fc009c4512625222e3378f2f16e7e6ef1732a0220688c1bb995b7ff2f12729e101d7c24b6314430317e7717911fdc35c0d84f2f0d012102138724e702d25b0fdce73372ccea9734f9349442d5a9681a5f4d831036cd9429" + }, + "addresses": [ + "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" + ], + "value": "1" + } + ], + "vout": [ + { + "value": "0.5", + "n": 0, + "scriptPubKey": { + "hex": "76a9149451f4546e09fc2e49ef9b5303924712ec2b038e88ac", + "addresses": [ + "RNoSGCX8SPFscj8epDaJjqEpuZa2B5in88" + ] + }, + "spent": false + }, + { + "value": "0.48", + "n": 1, + "scriptPubKey": { + "hex": "76a9145d6e33f3a108bbcc586cbbe90994d5baf5a9cce488ac", + "addresses": [ + "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" + ] + }, + "spent": true + } + ], + "blockhash": "0000000000004b942df6b9736c0a4b1a320cadfe46ca10351e43b35cccee7be1", + "blockheight": 734142, + "confirmations": 425010, + "time": 1559464388, + "blocktime": 1559464388, + "valueOut": "0.98", + "valueIn": "1", + "fees": "0.02", + "hex": "0100000001445560237d8093da3487eb90bc7ff826fab43cdbe213c034d671ec4eb4827e0c000000006b483045022100d790bdaa3c44eb5e3a422365ca5fc009c4512625222e3378f2f16e7e6ef1732a0220688c1bb995b7ff2f12729e101d7c24b6314430317e7717911fdc35c0d84f2f0d012102138724e702d25b0fdce73372ccea9734f9349442d5a9681a5f4d831036cd9429ffffffff0280f0fa02000000001976a9149451f4546e09fc2e49ef9b5303924712ec2b038e88ac006cdc02000000001976a9145d6e33f3a108bbcc586cbbe90994d5baf5a9cce488ac00000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/ravencoin-api-xpub.js b/mock/ext-api-dyson/get/ravencoin-api-xpub.js new file mode 100644 index 000000000..207ee7599 --- /dev/null +++ b/mock/ext-api-dyson/get/ravencoin-api-xpub.js @@ -0,0 +1,176 @@ +/// Mock for external Ravencoin API +/// See: +/// curl "http://{Ravencoin rpc}/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs" +/// curl "http://localhost:3000/ravencoin-api/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs" +/// curl "http://localhost:8420/v1/ravencoin/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B" + +module.exports = { + path: '/ravencoin-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B", + "balance": "299445646", + "totalReceived": "2599356720", + "totalSent": "2299911074", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 8, + "transactions": [ + { + "txid": "5d22e5a84b0eb054b623fdc3caf88a60eaa646dc97922f06d325aa8d6f18c564", + "version": 1, + "vin": [ + { + "txid": "baa2ee45ad8b9922a9db3fdcc22f8c3b5257dc81fef609800e7bd138748b6977", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "RHhtrB8eUZuTp8m8HVEyGidEiSkSz5CRdM" + ], + "isAddress": true, + "value": "299456974", + "hex": "47304402204d44f9873e894314746557e4e7ba74e9436d7fa81986d0386684179d8acb77fe02206ff207862b3badbd41cc2ab584ff334410ab2bd089c6c4a1f6ffa59ce2b5d7da012102d34aee6afc67a1b86789beadf0ef2ed7dd5665776b734c0a4dba727bf532bd59" + } + ], + "vout": [ + { + "value": "299445646", + "n": 0, + "hex": "76a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac", + "addresses": [ + "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz" + ], + "isAddress": true + } + ], + "blockHash": "00000000000013c420937088dd9b69e5ef38c2c1e544828d222c1e8998d1358a", + "blockHeight": 843530, + "confirmations": 315623, + "blockTime": 1566071064, + "value": "299445646", + "valueIn": "299456974", + "fees": "11328", + "hex": "010000000177698b7438d17b0e8009f6fe81dc57523b8c2fc2dc3fdba922998bad45eea2ba000000006a47304402204d44f9873e894314746557e4e7ba74e9436d7fa81986d0386684179d8acb77fe02206ff207862b3badbd41cc2ab584ff334410ab2bd089c6c4a1f6ffa59ce2b5d7da012102d34aee6afc67a1b86789beadf0ef2ed7dd5665776b734c0a4dba727bf532bd59feffffff018e2dd911000000001976a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac00000000" + }, + { + "txid": "baa2ee45ad8b9922a9db3fdcc22f8c3b5257dc81fef609800e7bd138748b6977", + "version": 1, + "vin": [ + { + "txid": "0f517fd0d4e86070fdff40e95f5202a1b343f75d3168842feb2e8fd6f1be0ef9", + "n": 0, + "addresses": [ + "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz" + ], + "isAddress": true, + "value": "9990400", + "hex": "483045022100d8e3598c4d8829b39433c43d4a4c3c438754e8fa77284e1de606233b954770f2022034eb8b6ab6ca103f613d14ccc38fc6aea7bc8661dbff87b0c576b4712d202b3a012102ee0d81b0e40adde804683388953c9cef6276703a3d26e65f9f3433dff0b82dba" + }, + { + "txid": "b9db035506eaeb0de0dbc98a277c29f41c08317515538c79cdc542d759918004", + "vout": 1, + "n": 1, + "addresses": [ + "RGG4nwkVgFSpy5wdZVKkKFySUCz8N35B5L" + ], + "isAddress": true, + "value": "89988700", + "hex": "473044022075c8f6c3ce3de19c86bbaa845871e25af82ea40bb3793896e657dccbd350209a022033b983ef8733a74ca8e977e08c4ded3a027a800dedbe8aa65a06bca0dc87d09b012103d66703c2448791bcb6828c060de9c568853aa43a753ed227a1f14d70612d3144" + }, + { + "txid": "44172def2b5f799963adf28f0a3129e6f7910c8bc5ad09ad0e8155da24748d25", + "vout": 1, + "n": 2, + "addresses": [ + "RHj2wiQ8tDhJZKsNKsf48WzxAj2pVnhEnX" + ], + "isAddress": true, + "value": "199965874", + "hex": "4730440220601d4e0d8bc03cf5064dad0316cf61d996ec507aa92105711a0d480a561d9bbb02200acaf5ff2deed01fca255caeaeb63925097bad740adbfd952ab0df66fbfa8552012102eff42496547e74666a392bf8399072dc289ae1d1e835a1c7068650a76be44709" + } + ], + "vout": [ + { + "value": "299456974", + "n": 0, + "spent": true, + "hex": "76a9145c6d05bdca691ab3acfd59ad1a70e55aea1cece388ac", + "addresses": [ + "RHhtrB8eUZuTp8m8HVEyGidEiSkSz5CRdM" + ], + "isAddress": true + } + ], + "blockHash": "0000000000006c4af5eab913f98e03bb3ff45c8b580b88cbeba39b0748ec6f8c", + "blockHeight": 843527, + "confirmations": 315626, + "blockTime": 1566070929, + "value": "299456974", + "valueIn": "299944974", + "fees": "488000", + "hex": "0100000003f90ebef1d68f2eeb2f8468315df743b3a102525fe940fffd7060e8d4d07f510f000000006b483045022100d8e3598c4d8829b39433c43d4a4c3c438754e8fa77284e1de606233b954770f2022034eb8b6ab6ca103f613d14ccc38fc6aea7bc8661dbff87b0c576b4712d202b3a012102ee0d81b0e40adde804683388953c9cef6276703a3d26e65f9f3433dff0b82dba0000000004809159d742c5cd798c53157531081cf4297c278ac9dbe00debea065503dbb9010000006a473044022075c8f6c3ce3de19c86bbaa845871e25af82ea40bb3793896e657dccbd350209a022033b983ef8733a74ca8e977e08c4ded3a027a800dedbe8aa65a06bca0dc87d09b012103d66703c2448791bcb6828c060de9c568853aa43a753ed227a1f14d70612d314400000000258d7424da55810ead09adc58b0c91f7e629310a8ff2ad6399795f2bef2d1744010000006a4730440220601d4e0d8bc03cf5064dad0316cf61d996ec507aa92105711a0d480a561d9bbb02200acaf5ff2deed01fca255caeaeb63925097bad740adbfd952ab0df66fbfa8552012102eff42496547e74666a392bf8399072dc289ae1d1e835a1c7068650a76be447090000000001ce59d911000000001976a9145c6d05bdca691ab3acfd59ad1a70e55aea1cece388ac00000000" + }, + { + "txid": "0f517fd0d4e86070fdff40e95f5202a1b343f75d3168842feb2e8fd6f1be0ef9", + "version": 1, + "vin": [ + { + "txid": "b9db035506eaeb0de0dbc98a277c29f41c08317515538c79cdc542d759918004", + "n": 0, + "addresses": [ + "RArA49JQFoQZPZRUJqbnE6tp8fVRmAp8v7" + ], + "isAddress": true, + "value": "10000000", + "hex": "4830450221009370c852500b17d02ad9cc2f539a7b56fa237ccd108ec39b2e914fa9fdcde95e02203a730d6431a5e4ada7580644f0fc68ec57fc4e3519d8656e70790239bf12e6b501210214632a2120dc88ae7624ccb3e63534ae3c1d84aefe9f1b72ee23ba9876e3cbc6" + } + ], + "vout": [ + { + "value": "9990400", + "n": 0, + "spent": true, + "hex": "76a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac", + "addresses": [ + "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz" + ], + "isAddress": true + } + ], + "blockHash": "00000000000060b0a773ca5f98d4dfdfab1610d62c85f367aee85768852ba5f6", + "blockHeight": 741026, + "confirmations": 418127, + "blockTime": 1559880464, + "value": "9990400", + "valueIn": "10000000", + "fees": "9600", + "hex": "010000000104809159d742c5cd798c53157531081cf4297c278ac9dbe00debea065503dbb9000000006b4830450221009370c852500b17d02ad9cc2f539a7b56fa237ccd108ec39b2e914fa9fdcde95e02203a730d6431a5e4ada7580644f0fc68ec57fc4e3519d8656e70790239bf12e6b501210214632a2120dc88ae7624ccb3e63534ae3c1d84aefe9f1b72ee23ba9876e3cbc6000000000100719800000000001976a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac00000000" + } + ], + "usedTokens": 7, + "tokens": [ + { + "type": "XPUBAddress", + "name": "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz", + "path": "m/44'/175'/0'/0/2", + "transfers": 3, + "decimals": 8, + "balance": "299445646", + "totalReceived": "309436046", + "totalSent": "9990400" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/ripple-get-accounts.js b/mock/ext-api-dyson/get/ripple-get-accounts.js new file mode 100644 index 000000000..545ee1562 --- /dev/null +++ b/mock/ext-api-dyson/get/ripple-get-accounts.js @@ -0,0 +1,205 @@ +/// Ripple API Mock +/// See: +/// curl "http://localhost:3000/ripple-api/accounts/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1/transactions?type=Payment&descending=false&limit=25" +/// curl "https://data.ripple.com/v2/accounts/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1/transactions?type=Payment&descending=false&limit=25" +/// curl http://localhost:8420/v1/ripple/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1 +module.exports = { + path: "/ripple-api/accounts/:address/transactions?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + if (params.address === 'rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1') { + return JSON.parse(` + { + "result": "success", + "count": 2, + "transactions": [ + { + "hash": "20F2F95E4612296B1A82CC72F0DC53C9EAA8DA1557A0D0AD6C1E3BCA7E67E7CE", + "ledger_index": 44734671, + "date": "2019-01-28T19:22:50+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 13, + "LastLedgerSequence": 44913253, + "Amount": "392834642660000", + "Fee": "500", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rUEchj8k8jvVXKGhfVYvrs5ntVEtc5F2hK", + "Signers": [ + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "30440220247A6624588612C73EEC2CD5F8D0A74E7FF7EE36E1ECFFF413703E928654824702205E9F5DB179A9146331935C5B5762AAAE52AE09EFDDEFDA6C596A53AE870464D2", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "029A7A9E7A6175690C6E3D46EBBA33DA9EBF096EB5942E21C4A8C98F5606E6E6B8", + "TxnSignature": "304402201DFB1E6C459753DAAD5AA6D0D44501D5D1B067F18733E2DE23F3DA9E6F4A03E602201BD890DCDDA34E8304C7C29209EAAB3C34DE07C9FD4CF2537848EA4CA02FA1BB", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "304402205E1D7DE31B9E88848E370AD7D5D77FF16CED0807A3514918BA41718040A9721F02207A832DA5575C0B66B9FF0AC6C1C0BFAF15359727221A97D2027A69CFDA953297", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + }, + { + "Signer": { + "SigningPubKey": "0368CFF85FEF68857A445A3F51FFC6119F2A113C9590E898351CE49F61BA71E6E8", + "TxnSignature": "304402204BB844E6102A40079C9616AB888C7332F000353665B4FA972525B261DB3DDED6022018586112E834D6BC3A2A2151A4F39304B1357EB11617EE84ED55D862D7978E7C", + "Account": "rP5xpZ5KzPih69fLhG3NYvZEDfLmSEViUk" + } + } + ] + }, + "meta": { + "TransactionIndex": 2, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44734265, + "PreviousTxnID": "AB83FFE7B46FF4E44BC084DFBEBBCFAA09913770766CCBFC0B1858E8195CE94E", + "LedgerIndex": "459E688FB21500B75D59CBFA49EB4C17C54E81D32A7A69CF1910691AB6AA4DCC", + "PreviousFields": { + "Balance": "392834747660000" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 1, + "OwnerCount": 0, + "Balance": "785669390320000", + "Account": "rUEchj8k8jvVXKGhfVYvrs5ntVEtc5F2hK" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44734265, + "PreviousTxnID": "AB83FFE7B46FF4E44BC084DFBEBBCFAA09913770766CCBFC0B1858E8195CE94E", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 13, + "Balance": "4123164791269591" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 14, + "OwnerCount": 10, + "Balance": "3730330148609091", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "392834642660000" + } + }, + { + "hash": "000BC2AFC047BE45C43886109720F44B6F3F2434D59B1A16A9B2B4FC9B9C5A13", + "ledger_index": 51969362, + "date": "2019-12-11T00:00:01+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 14, + "LastLedgerSequence": 52151515, + "Amount": "220303137120000", + "Fee": "5000", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "r3a8tn1ubcP13np3giaLYzkmVKfnhLP2BL", + "Signers": [ + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100BC1FBB9457B5A8684AACA1E949DB2640CE1D0C9907AA060D334655F4162D27D0022028DD17C6E2AAD9863D2FA7BE7F0D80D4181CB9B9349371959E5DB2D69BF662D3", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "029A7A9E7A6175690C6E3D46EBBA33DA9EBF096EB5942E21C4A8C98F5606E6E6B8", + "TxnSignature": "3044022014FA8252577C836D14D796B59C74F377A23EE1D335AEB68ED21A4BF5D4D05BBE022054361EEC50A8F3C4A4AF4EFE61C83B399F7B5240C42C2FD4BBBCEAB1CFF138B4", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "3045022100B407D26B1A4ABAA6C0BC9C99EDB0DCB280852EF21974D82C8C8E5866FB08187A02207255B8CD26CCEFD8ACA1DD63A767CCC127AE6EA2115CC2F89D1B798EBFA3316C", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + }, + { + "Signer": { + "SigningPubKey": "0368CFF85FEF68857A445A3F51FFC6119F2A113C9590E898351CE49F61BA71E6E8", + "TxnSignature": "3045022100A0A5FD62D9EC81D1F0C5474A7EEB31C45423D647764B352F947617C383CD9E6902201896720DB3B9876FE56DEA05E4F75B3F90A20B3A5EF95E39703F80F5166BD1F6", + "Account": "rP5xpZ5KzPih69fLhG3NYvZEDfLmSEViUk" + } + } + ] + }, + "meta": { + "TransactionIndex": 0, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 51901464, + "PreviousTxnID": "607A53B712B938B1475D194EC4F3318E6EC4BACD430D6C5437AA4018F1754A2A", + "LedgerIndex": "45806910346E5E79AE202994014742DEDA552A6197C19E03C4DC5C5466A00DB2", + "PreviousFields": { + "Balance": "120000000" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 2, + "OwnerCount": 0, + "Balance": "220303257120000", + "Account": "r3a8tn1ubcP13np3giaLYzkmVKfnhLP2BL" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44734671, + "PreviousTxnID": "20F2F95E4612296B1A82CC72F0DC53C9EAA8DA1557A0D0AD6C1E3BCA7E67E7CE", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 14, + "Balance": "3730330148609091" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 15, + "OwnerCount": 10, + "Balance": "3510027011484091", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "220303137120000" + } + } + ] + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/stellar-api-accounts.js b/mock/ext-api-dyson/get/stellar-api-accounts.js new file mode 100644 index 000000000..f0605ed98 --- /dev/null +++ b/mock/ext-api-dyson/get/stellar-api-accounts.js @@ -0,0 +1,99 @@ +/// Stellar API Mock, accounts +/// See: +/// curl "http://localhost:3000/stellar-api/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?order=desc&limit=25" +/// curl "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?order=desc&limit=25" +/// curl http://localhost:8420/v1/stellar/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX +module.exports = { + path: "/stellar-api/accounts/:address/:operation?", + template: function(params, query, body) { + //console.log(query) + if (params.operation === 'payments') { + if (params.address === 'GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX') { + return JSON.parse(` + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?cursor=\u0026limit=25\u0026order=desc" + }, + "next": { + "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?cursor=68651109446586369\u0026limit=25\u0026order=desc" + }, + "prev": { + "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?cursor=118409941953355777\u0026limit=25\u0026order=asc" + } + }, + "_embedded": { + "records": [ + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/118409941953355777" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/118409941953355777/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=118409941953355777" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=118409941953355777" + } + }, + "id": "118409941953355777", + "paging_token": "118409941953355777", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2020-01-03T00:26:37Z", + "transaction_hash": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GDBX63ONLLI372D7FHJYEPKP3KOCH7HZPKJWZPYJMC5RN7L5HB4VFXLM", + "amount": "500000.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/117528387031003137" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/117528387031003137/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=117528387031003137" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=117528387031003137" + } + }, + "id": "117528387031003137", + "paging_token": "117528387031003137", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2019-12-20T23:06:36Z", + "transaction_hash": "23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GCGVWRW5MHZW5OB2IR6RRFYBG5NV4BXUT5GYBRH2E3FD3TVYVINA72KM", + "amount": "3976053.0000000" + } + ] + } + } + `); + } + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/stellar-api-transactions.js b/mock/ext-api-dyson/get/stellar-api-transactions.js new file mode 100644 index 000000000..9d4e7ed43 --- /dev/null +++ b/mock/ext-api-dyson/get/stellar-api-transactions.js @@ -0,0 +1,118 @@ +/// Stellar API Mock, transactions +/// See: +/// curl "http://localhost:3000/stellar-api/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029?" +/// curl "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029?" +/// curl http://localhost:8420/v1/stellar/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX +module.exports = { + path: "/stellar-api/transactions/:txid?", + template: function(params, query, body) { + //console.log(query) + if (params.txid === '2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029') { + return JSON.parse(` + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029" + }, + "account": { + "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" + }, + "ledger": { + "href": "https://horizon.stellar.org/ledgers/27569463" + }, + "operations": { + "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029/operations{?cursor,limit,order}", + "templated": true + }, + "effects": { + "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029/effects{?cursor,limit,order}", + "templated": true + }, + "precedes": { + "href": "https://horizon.stellar.org/transactions?order=asc\u0026cursor=118409941953355776" + }, + "succeeds": { + "href": "https://horizon.stellar.org/transactions?order=desc\u0026cursor=118409941953355776" + } + }, + "id": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029", + "paging_token": "118409941953355776", + "successful": true, + "hash": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029", + "ledger": 27569463, + "created_at": "2020-01-03T00:26:37Z", + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "source_account_sequence": "25002129911447568", + "fee_charged": 100, + "max_fee": 100, + "operation_count": 1, + "envelope_xdr": "AAAAANSEpQq63M02LHthmlMK1zL6lF7mvGyAj9qoryiJWAQrAAAAZABY004AAAAQAAAAAAAAAAAAAAABAAAAAQAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwAAAAEAAAAAw39tzVrRv+h/KdOCPU/anCP8+XqTbL8JYLsW/X04eVIAAAAAAAAEjCc5UAAAAAAAAAAAA4lYBCsAAABAM4j0FWLKI8qMUcJMO3tP4rMAoIDZdbRlFjiFNACVoAd9dCtdgBBpbi6ZnXtimE370ar19q/qrbvOKBJrnYXjC2b459kAAABAtIedy2ER3ep90HE5rEPwh03iyQRp644Sm8/wK0c9sk6qPSTG2VEFEj85Jk0TrXLxDmxvnktEhPyec67ZcdxfDrEQC4sAAABAoabKlFbeUmDTtAiGVOHthzrCZHK8mpyFkKIS7QzjL4a6ASQ6RweWNUKedUBj4uuO5z1vHDr3I5EiLUhK8xceAQ==", + "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", + "result_meta_xdr": "AAAAAQAAAAIAAAADAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYurIvScogBY004AAAAPAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYurIvScogBY004AAAAQAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAAAABAAAAAMBlbvHAAAAAAAAAADDf23NWtG/6H8p04I9T9qcI/z5epNsvwlguxb9fTh5UgAAAAAEBsfCAWsUFwAAAAcAAAADAAAAAQAAAACEPwEuxkVAQXfespLpiilBRPdvqIsEbieyl7rz8ME0FgAAAAAAAAAIbm9kbGUua3kAAgICAAAAAwAAAABZb+AQ1x8C7yRRjZjmrWnGc3IjlX+nHwpN9kmfVrOUgwAAAAEAAAAAa+mvYlV3vvuiNbEFfIwap9J7CAY2vNceKVv68HTkxg8AAAABAAAAAOIt1YAF0nOgEaMoodWZu6F3u9zkCv+ua4tEMcnzooD+AAAAAQAAAAAAAAAAAAAAAQGkrTcAAAAAAAAAAMN/bc1a0b/ofynTgj1P2pwj/Pl6k2y/CWC7Fv19OHlSAAAEjCtAF8IBaxQXAAAABwAAAAMAAAABAAAAAIQ/AS7GRUBBd96ykumKKUFE92+oiwRuJ7KXuvPwwTQWAAAAAAAAAAhub2RsZS5reQACAgIAAAADAAAAAFlv4BDXHwLvJFGNmOatacZzciOVf6cfCk32SZ9Ws5SDAAAAAQAAAABr6a9iVXe++6I1sQV8jBqn0nsIBja81x4pW/rwdOTGDwAAAAEAAAAA4i3VgAXSc6ARoyih1Zm7oXe73OQK/65ri0QxyfOigP4AAAABAAAAAAAAAAAAAAADAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYurIvScogBY004AAAAQAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYce+7tMogBY004AAAAQAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAA=", + "fee_meta_xdr": "AAAAAgAAAAMBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFi6si9J0GAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAAAAAAEBpK03AAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFi6si9JyiAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAA==", + "memo_type": "none", + "signatures": [ + "M4j0FWLKI8qMUcJMO3tP4rMAoIDZdbRlFjiFNACVoAd9dCtdgBBpbi6ZnXtimE370ar19q/qrbvOKBJrnYXjCw==", + "tIedy2ER3ep90HE5rEPwh03iyQRp644Sm8/wK0c9sk6qPSTG2VEFEj85Jk0TrXLxDmxvnktEhPyec67ZcdxfDg==", + "oabKlFbeUmDTtAiGVOHthzrCZHK8mpyFkKIS7QzjL4a6ASQ6RweWNUKedUBj4uuO5z1vHDr3I5EiLUhK8xceAQ==" + ] + } + `); + } + if (params.txid === '23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c') { + return JSON.parse(` + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c" + }, + "account": { + "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" + }, + "ledger": { + "href": "https://horizon.stellar.org/ledgers/27364210" + }, + "operations": { + "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c/operations{?cursor,limit,order}", + "templated": true + }, + "effects": { + "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c/effects{?cursor,limit,order}", + "templated": true + }, + "precedes": { + "href": "https://horizon.stellar.org/transactions?order=asc\u0026cursor=117528387031003136" + }, + "succeeds": { + "href": "https://horizon.stellar.org/transactions?order=desc\u0026cursor=117528387031003136" + } + }, + "id": "23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c", + "paging_token": "117528387031003136", + "successful": true, + "hash": "23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c", + "ledger": 27364210, + "created_at": "2019-12-20T23:06:36Z", + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "source_account_sequence": "25002129911447567", + "fee_charged": 100, + "max_fee": 100, + "operation_count": 1, + "envelope_xdr": "AAAAANSEpQq63M02LHthmlMK1zL6lF7mvGyAj9qoryiJWAQrAAAAZABY004AAAAPAAAAAAAAAAAAAAABAAAAAQAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwAAAAEAAAAAjVtG3WHzbrg6RH0YlwE3W14G9J9NgMT6Jso9zriqGg8AAAAAAAAkKXhESIAAAAAAAAAAA2b459kAAABA5EcZFubvZDa2IytO64bCB85UpjzLqHIS3FBWshoigfice819SwpBYkk7xa3kIWseL/kiQBCnrIAsU7ujYAR3AIlYBCsAAABA1oF6s5NMUEJas97SMRqHgeuXxCdKetSEPBtFGlgzSPTqG6mzAGPuwibKs3HaBjdmfbwh7ffTtjAAesLHIApdCRlL7xoAAABAkADolN0l8llCFxrkqMLbbU4NNKwPsQDrYDoxERo7uvuVJgg18zMBk4t1eqXqQfiYZVeIdAN/q9zcL2SGGYJaBg==", + "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", + "result_meta_xdr": "AAAAAQAAAAIAAAADAaGLcgAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAha/UmzjlhgBY004AAAAOAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAaGLcgAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAha/UmzjlhgBY004AAAAPAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAAAABAAAAAMBoJ96AAAAAAAAAACNW0bdYfNuuDpEfRiXATdbXgb0n02AxPomyj3OuKoaDwAAABwqq724AWpTdAAAABYAAAADAAAAAAAAAAAAAAAAAQMDAwAAAAMAAAAAVMpM+DapT2QOM7rVti7Nu9zC8ZweMu0F3X3WjmI18MwAAAABAAAAALpTQaHLUccK4ssbtsuxFMwYEVe6qosFYprYXIH5kg8bAAAAAQAAAAC6le9TwqPIBkG+/CAt9sGl/SpcdU21B5eJ4qdAhRlyIwAAAAEAAAAAAAAAAAAAAAEBoYtyAAAAAAAAAACNW0bdYfNuuDpEfRiXATdbXgb0n02AxPomyj3OuKoaDwAAJEWi8AY4AWpTdAAAABYAAAADAAAAAAAAAAAAAAAAAQMDAwAAAAMAAAAAVMpM+DapT2QOM7rVti7Nu9zC8ZweMu0F3X3WjmI18MwAAAABAAAAALpTQaHLUccK4ssbtsuxFMwYEVe6qosFYprYXIH5kg8bAAAAAQAAAAC6le9TwqPIBkG+/CAt9sGl/SpcdU21B5eJ4qdAhRlyIwAAAAEAAAAAAAAAAAAAAAMBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFr9SbOOWGAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAAAAAAEBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFi6si9J0GAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAA==", + "fee_meta_xdr": "AAAAAgAAAAMBn66qAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFr9SbOOXqAFjTTgAAAA4AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAAAAAAEBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFr9SbOOWGAFjTTgAAAA4AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAA==", + "memo_type": "none", + "signatures": [ + "5EcZFubvZDa2IytO64bCB85UpjzLqHIS3FBWshoigfice819SwpBYkk7xa3kIWseL/kiQBCnrIAsU7ujYAR3AA==", + "1oF6s5NMUEJas97SMRqHgeuXxCdKetSEPBtFGlgzSPTqG6mzAGPuwibKs3HaBjdmfbwh7ffTtjAAesLHIApdCQ==", + "kADolN0l8llCFxrkqMLbbU4NNKwPsQDrYDoxERo7uvuVJgg18zMBk4t1eqXqQfiYZVeIdAN/q9zcL2SGGYJaBg==" + ] + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/tezos-api-transactions.js b/mock/ext-api-dyson/get/tezos-api-transactions.js new file mode 100644 index 000000000..0a63945cf --- /dev/null +++ b/mock/ext-api-dyson/get/tezos-api-transactions.js @@ -0,0 +1,29 @@ +/// Mock for external Tezos API, transactions +/// See +/// curl "http://api.tezos.id/mooncake/mainnet/v1/transactions?account=tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8&n=50&p=0" +/// curl "http://localhost:3000/tezos-api/v1/transactions?account=tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8&n=50&p=0" +/// curl "http://localhost:8420/v1/tezos/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" + +module.exports = { + path: '/tezos-api/v1/transactions?', + template: function(params, query, body) { + //console.log(query) + if (query.account === 'tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8') { + return JSON.parse(` + [ + { + "tx": { + "kind": "transaction", + "status": "applied" + }, + "op": { + "opHash": "ooLrNAP233Qvoz3AGvjRjhk1fjG7z19UfyLEGBm1rwfHn4NSVhd" + } + } + ] + `) + } + // fallback + return {error: "Not implemented"} + } +}; diff --git a/mock/ext-api-dyson/get/theta-api-accounttx.js b/mock/ext-api-dyson/get/theta-api-accounttx.js new file mode 100644 index 000000000..3cd7f1b85 --- /dev/null +++ b/mock/ext-api-dyson/get/theta-api-accounttx.js @@ -0,0 +1,95 @@ +/// Theta API Mock +/// See: +/// curl "http://localhost:3000/theta-api/accounttx/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f?type=2&pageNumber=1&limitNumber=100&isEqualType=true" +/// curl "https://explorer.thetatoken.org:9000/api/accounttx/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f?type=2&pageNumber=1&limitNumber=100&isEqualType=true" +/// curl http://localhost:8420/v1/theta/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f +module.exports = { + path: "/theta-api/accounttx/:address?", + template: function(params, query, body) { + //console.log(params) + if (params.address === '0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f') { + return JSON.parse(` + { + "type": "account_tx_list", + "body": [ + { + "_id": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78", + "block_height": "4160784", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "1000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "52", + "signature": "0x60ae320a7a0f7f6e72ed5080830d2156f145a191197092df9eb88e7b8c7637ad01894b128b81d33b67a6516e3a6c7dc064576eb40b9516b4dc127e9845ede8c300" + } + ], + "outputs": [ + { + "address": "0x082a2aef39b6473c55ba7e28c122ed3aea0de381", + "coins": { + "thetawei": "1000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78", + "number": 31836666, + "status": "finalized", + "timestamp": "1579009947", + "type": 2 + }, + { + "_id": "0x43804bbc7ff254f5eb3ff0a9bc1feed5788cbbc3eb5b535c52de4c47c8963dfd", + "block_height": "4160736", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "1000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "51", + "signature": "0x23cd4f14859ef6a9cd0bd820591101cd53c74d3421e01b42ca0671501afdd6f73dcf2ec8e35ceba773319ba552c0b170daa3460bf6125992e846f9d0cf839a9700" + } + ], + "outputs": [ + { + "address": "0x082a2aef39b6473c55ba7e28c122ed3aea0de381", + "coins": { + "thetawei": "1000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x43804bbc7ff254f5eb3ff0a9bc1feed5788cbbc3eb5b535c52de4c47c8963dfd", + "number": 31836430, + "status": "finalized", + "timestamp": "1579009642", + "type": 2 + } + ], + "totalPageNumber": 1, + "currentPageNumber": 1 + } + `); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/thundertoken-api-transactions.js b/mock/ext-api-dyson/get/thundertoken-api-transactions.js new file mode 100644 index 000000000..13de512b7 --- /dev/null +++ b/mock/ext-api-dyson/get/thundertoken-api-transactions.js @@ -0,0 +1,75 @@ +/// Thundertoken API Mock +/// See: +/// curl "http://localhost:3000/thundertoken-api/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" +/// curl "http://{Thundertoken rpc}/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" +/// curl http://localhost:8420/v1/thundertoken/0x0b230def08139f18a86536d9cfa150f04435414c + +module.exports = { + path: '/thundertoken-api/transactions', + template: function(params, query, body) { + //console.log(query) + if (query.address === '0x0b230def08139f18a86536d9cfa150f04435414c') { + return JSON.parse(`{ + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x80929a2170969364e06d253d2b853fe0b2ca3a307e61d629946b9b76e2f983cf", + "blockNumber": 33514713, + "time": 1584945288, + "nonce": 312, + "from": "0x0B230dEf08139F18a86536d9CFa150f04435414c", + "to": "0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1", + "value": "0", + "gas": "4700000", + "gasPrice": "4000000000", + "gasUsed": "421569", + "input": "0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800", + "error": "", + "id": "0x80929a2170969364e06d253d2b853fe0b2ca3a307e61d629946b9b76e2f983cf", + "timeStamp": "1584945288" + }, + { + "operations": [ + { + "transactionId": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00-0", + "contract": { + "address": "0x51bca9300d034a7e6ab379399a317bdfa0d4835b", + "decimals": 18, + "name": "The Third Identity", + "symbol": "TTI", + "totalSupply": "10000000000000000000000000000", + "updatedAt": "2020-02-26T21:42:19.178Z" + }, + "from": "0x3270b4e0916B4556BF236B6E5D4377282b3255e5", + "to": "0x0B230dEf08139F18a86536d9CFa150f04435414c", + "type": "token_transfer", + "value": "292820000000000000000", + "id": null + } + ], + "contract": null, + "_id": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00", + "blockNumber": 33514370, + "time": 1584944945, + "nonce": 311, + "from": "0x0B230dEf08139F18a86536d9CFa150f04435414c", + "to": "0x3270b4e0916B4556BF236B6E5D4377282b3255e5", + "value": "0", + "gas": "4700000", + "gasPrice": "2880000000", + "gasUsed": "1511414", + "input": "0x4008d2f3", + "error": "", + "id": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00", + "timeStamp": "1584944945" + } + ], + "total": 2 + }`); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/tomochain-api-transactions.js b/mock/ext-api-dyson/get/tomochain-api-transactions.js new file mode 100644 index 000000000..fcf9da07a --- /dev/null +++ b/mock/ext-api-dyson/get/tomochain-api-transactions.js @@ -0,0 +1,58 @@ +/// Tomochain API Mock +/// See: +/// curl "http://localhost:3000/tomochain-api/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" +/// curl "http://{Tomochain rpc}/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" +/// curl http://localhost:8420/v1/tomochain/0x17e4c16605e32adead5fa371bf6117df34ca0200 + +module.exports = { + path: '/tomochain-api/transactions', + template: function(params, query, body) { + //console.log(query) + if (query.address === '0x17e4c16605e32adead5fa371bf6117df34ca0200') { + return JSON.parse(`{ + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0xb2af5ad5eebaba1da3452e0281f9b6ec9e00a5bb832793a912eb3959b6c2fdd2", + "blockNumber": 18455252, + "time": 1584963130, + "nonce": 892939, + "from": "0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200", + "to": "0x0000000000000000000000000000000000000089", + "value": "0", + "gas": "200000", + "gasPrice": "0", + "gasUsed": "0", + "input": "0xe341eaa40000000000000000000000000000000000000000000000000000000001199ad29a43ad0df08d1ff128de7642208ce68720dc77bbe7e02acb2685951f73efea56", + "error": "", + "id": "0xb2af5ad5eebaba1da3452e0281f9b6ec9e00a5bb832793a912eb3959b6c2fdd2", + "timeStamp": "1584963130" + }, + { + "operations": [], + "contract": null, + "_id": "0x9181d170fb77eb55e1dda42c55080230397702204247e8b242c8f6588f61f41d", + "blockNumber": 18455237, + "time": 1584963100, + "nonce": 892938, + "from": "0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200", + "to": "0x0000000000000000000000000000000000000089", + "value": "0", + "gas": "200000", + "gasPrice": "0", + "gasUsed": "0", + "input": "0xe341eaa40000000000000000000000000000000000000000000000000000000001199ac3f1234069ee58f791cc422978d794e7f3c1e82d580013038badd5493ed854b6e4", + "error": "", + "id": "0x9181d170fb77eb55e1dda42c55080230397702204247e8b242c8f6588f61f41d", + "timeStamp": "1584963100" + } + ], + "total": 2 + }`); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/tron-get-accounts.js b/mock/ext-api-dyson/get/tron-get-accounts.js new file mode 100644 index 000000000..6710c8fa2 --- /dev/null +++ b/mock/ext-api-dyson/get/tron-get-accounts.js @@ -0,0 +1,101 @@ +/// Tron API Mock +/// See: +/// curl "http://localhost:3000/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?token_id=&limit=25&order_by=block_timestamp,desc" +/// curl "http://{Tron rpc}/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?token_id=&limit=25&order_by=block_timestamp,desc" +/// curl http://localhost:8420/v1/tron/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB +module.exports = { + path: "/tron-api/v1/accounts/:address/:operation?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + if (params.operation === 'transactions') { + if (params.address === 'TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB') { + return JSON.parse(` + { + "success": true, + "meta": { + "at": 1585038748264, + "page_size": 2 + }, + "data": [ + { + "block_timestamp": 1553870898000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 10149740000, + "asset_name": "1002000", + "owner_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1553870955000, + "fee_limit": 0, + "ref_block_bytes": "b560", + "ref_block_hash": "2d9026ee979db6b6", + "timestamp": 1553870897024 + }, + "raw_data_hex": "0a02b56022082d9026ee979db6b640f8c3b4cf9c2d5a77080212730a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123d0a07313030323030301215410583a68a3bcd86c25ab1bee482bac04a216b02611a154139fec4d95bb59f45a727f9234020adaf2cec9e2020e0fbe2e7257080ffb0cf9c2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "10c57bda2346f4cc7e287a2b696fcd8dcbec273d84df8b8d41fcf49d13e02fdf1ca539d1b631feabd58e3f0a8c501c8d74595774fd149cfba16770eb8a4bd18100" + ], + "txID": "d9206168ee601935bb19de30a613f735972f1ab59178ba05d078ff1ae19c0602" + }, + { + "block_timestamp": 1553864040000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferContract", + "value": { + "amount": 278720000, + "owner_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferContract" + } + ], + "expiration": 1553864097000, + "fee_limit": 0, + "ref_block_bytes": "ac7f", + "ref_block_hash": "648c4cb65453b4de", + "timestamp": 1553864038710 + }, + "raw_data_hex": "0a02ac7f2208648c4cb65453b4de40e8f991cc9c2d5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a15410583a68a3bcd86c25ab1bee482bac04a216b026112154139fec4d95bb59f45a727f9234020adaf2cec9e201880dcf3840170b6b28ecc9c2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "25052c3c653de8c06dc2294f9078a621179102282799f14f4a6950b805e66ea17c1a894a34922d92b7b14aad27cc07aeb129cb31570d55e9f21a0e3f5dd11ce701" + ], + "txID": "3ef5e225ce5bdd01333286e4ab4413ae3da8b80c24b26c5811ae78962940a8ca" + } + ] + } + `); + } + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/vechain-api-entities.js b/mock/ext-api-dyson/get/vechain-api-entities.js new file mode 100644 index 000000000..6115e70bf --- /dev/null +++ b/mock/ext-api-dyson/get/vechain-api-entities.js @@ -0,0 +1,107 @@ +/// Mock for external coin API, transactions +/// See +/// curl https://vethor-pubnode.digonchain.com/blocks/best +/// curl https://vethor-pubnode.digonchain.com/transactions/0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7 +/// curl http://localhost:3000/vechain-api/blocks/best +/// curl http://localhost:3000/vechain-api/transactions/0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7 +/// curl "http://localhost:8420/v1/vechain/0xB5e883349e68aB59307d1604555AC890fAC47128" + +module.exports = { + path: '/vechain-api/:entity/:id?', + template: function(params, query, body) { + //console.log(params) + if (params.entity === 'blocks') { + if (params.id === 'best') { + return JSON.parse(` + { + "number": 5466405, + "id": "0x00536925d12b64746d8ca1d75db659b0688da13191f709304c88d8372de53519", + "size": 1021, + "parentID": "0x00536924049d49e0f4605b72f313ccac653ee54e2523f515113db3998ac30cc5", + "timestamp": 1585149040, + "gasLimit": 35201963, + "beneficiary": "0x5643143716537c9c86c558091d2a30710f71fec7", + "gasUsed": 184188, + "totalScore": 526861845, + "txsRoot": "0x81c1361fff2a3cb206f6ecd94d644220d11d91dde4295a0a7b9b0f0e549b9008", + "txsFeatures": 1, + "stateRoot": "0xcbf49e247ca8bb1826cf101480c05c1470a54c4fdc10702932ac7613ea297d81", + "receiptsRoot": "0x0e7dfcee0f0e1fcc1b6888e6eb9f767b6f37aaa5614efcee0faf94e6a62bcb6d", + "signer": "0x2da258cae01aac5cd0e4bd876f708081f78b327d", + "isTrunk": true, + "transactions": [ + "0x3985abfc8963bc7adfc54d534f0a89498aa986bb49ff87b4eb3d0aa47aeefa87", + "0xeedebfba7af9d6a99561f1c02509ce792eb6a2b582f0e35ea4dc571f9ae2306c", + "0xbb386e125bfb9bd81e32af6a4b2ef30ff8f89461a94f7be2b3a42135b490562a", + "0x49c295e28b017cf337325ea7d6e112ab11afde0433c65c8e71778e21b5acc7d9" + ] + } + `); + } + } + if (params.entity === 'transactions') { + switch (params.id) { + case '0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7': + return JSON.parse(` + { + "id": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", + "chainTag": 74, + "blockRef": "0x004313a393a18efb", + "expiration": 720, + "clauses": [ + { + "to": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", + "value": "0x12b1815d00738000", + "data": "0x" + } + ], + "gasPriceCoef": 0, + "gas": 21000, + "origin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "delegator": null, + "nonce": "0x8cff29df64a414f8", + "dependsOn": null, + "size": 129, + "meta": { + "blockID": "0x004313a4bd4286e821b684cc1749deb3df12fa2a8114435fbd35baa155e82016", + "blockNumber": 4395940, + "blockTimestamp": 1574410670 + } + } + `); + + case '0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5': + return JSON.parse(` + { + "id": "0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5", + "chainTag": 74, + "blockRef": "0x0042249a647f63e7", + "expiration": 720, + "clauses": [ + { + "to": "0x00bae5ed35736e4ef17af1be0c6f50e0fb73d685", + "value": "0x38f6ea18e810b6f00", + "data": "0x" + } + ], + "gasPriceCoef": 0, + "gas": 21000, + "origin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "delegator": null, + "nonce": "0x6fa76caac4c18bd", + "dependsOn": null, + "size": 130, + "meta": { + "blockID": "0x0042249bee56223e0ed7a9c7fcfffe8e61b9fd95d29d24843c558ff2c46ea094", + "blockNumber": 4334747, + "blockTimestamp": 1573795570 + } + } + `); + } + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/viacoin-api-address.js b/mock/ext-api-dyson/get/viacoin-api-address.js new file mode 100644 index 000000000..beb83f0a5 --- /dev/null +++ b/mock/ext-api-dyson/get/viacoin-api-address.js @@ -0,0 +1,107 @@ +/// Mock for external Viacoin API +/// See: +/// curl "http://{Viacoin rpc}/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" +/// curl "http://localhost:3000/viacoin-api/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" +/// curl "http://localhost:8420/v1/viacoin/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" + +module.exports = { + path: '/viacoin-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 2, + "addrStr": "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A", + "balance": "737.5107688", + "totalReceived": "183234.99094131", + "totalSent": "182497.48017251", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 1523480, + "txs": [ + { + "txid": "dadbe1f13dc5ecd1cfb0d8ae139a4e55493eb9ab2c937cb78b67a5d9c1ded7e8", + "version": 1, + "vin": [ + { + "txid": "", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": {}, + "addresses": null, + "value": "" + } + ], + "vout": [ + { + "value": "0.00976562", + "n": 0, + "scriptPubKey": { + "hex": "76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac", + "addresses": [ + "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" + ] + }, + "spent": false + } + ], + "blockhash": "496ff7e4cf450449ade88fc8bf214fd39a6d4203da8f8256492c589bf28de1a7", + "blockheight": 7423549, + "confirmations": 6, + "time": 1584742971, + "blocktime": 1584742971, + "valueOut": "0.00976562", + "valueIn": "0", + "fees": "0", + "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff09033d4671045e75423bffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000" + }, + { + "txid": "be2a7b573af425f8f309561b3db4631f905626057da94399d7e44f97595c7dbe", + "version": 1, + "vin": [ + { + "txid": "", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": {}, + "addresses": null, + "value": "" + } + ], + "vout": [ + { + "value": "0.00976562", + "n": 0, + "scriptPubKey": { + "hex": "76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac", + "addresses": [ + "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" + ] + }, + "spent": false + } + ], + "blockhash": "36c57ff80410c9c32790b75e566fdf855c6302a6a09f6dc75b362f9c6b3c884c", + "blockheight": 7423545, + "confirmations": 10, + "time": 1584742872, + "blocktime": 1584742872, + "valueOut": "0.00976562", + "valueIn": "0", + "fees": "0", + "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0903394671045e7541d8ffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/viacoin-api-xpub.js b/mock/ext-api-dyson/get/viacoin-api-xpub.js new file mode 100644 index 000000000..4dbcb38cd --- /dev/null +++ b/mock/ext-api-dyson/get/viacoin-api-xpub.js @@ -0,0 +1,87 @@ +/// Mock for external Viacoin API +/// See: +/// curl "http://{Viacoin rpc}/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs" +/// curl "http://localhost:3000/viacoin-api/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs" +/// curl "http://localhost:8420/v1/viacoin/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK" + +module.exports = { + path: '/viacoin-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1, + "address": "zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK", + "balance": "741749040", + "totalReceived": "57216749588", + "totalSent": "56475000548", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 39, + "transactions": [ + { + "txid": "bdff404da14940abd84f7cb741fe8f77ad5de5aefbb74254caee683fe2a9b540", + "version": 1, + "vin": [ + { + "txid": "32790f42de714507b6a1e6001a4a334600ac316937a98489c19821bba0d5c74f", + "vout": 1, + "n": 0, + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ], + "value": "741862718" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ] + }, + { + "value": "641749040", + "n": 1, + "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ] + } + ], + "blockHash": "0853179f0baef807426b977e4a9ae260ba1a3a3726dbb7513ff4150991f5827a", + "blockHeight": 7305935, + "confirmations": 117673, + "blockTime": 1581914336, + "value": "741749040", + "valueIn": "741862718", + "fees": "113678", + "hex": "010000000001014fc7d5a0bb2198c18984a9376931ac0046334a1a00e6a1b6074571de420f79320100000000000000000200e1f505000000001600143379fd40508ec2101e11c3519a31615de6e7b67330504026000000001600143379fd40508ec2101e11c3519a31615de6e7b67302473044022049b1d030bd9ec88ec343a52971d354b470d1357413675e985161bf2d5f8ca8ba02205d393b4d5232ae983faba4237e0c8feace5483493bf4da35313ce62459c87c66012102b5e09e1dbb76a0eeebea67bf80069ce41c26c81d0f06d1dd42e712ebf55de4bc00000000" + } + ], + "usedTokens": 40, + "tokens": [ + { + "type": "XPUBAddress", + "name": "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp", + "path": "m/84'/14'/0'/0/0", + "transfers": 7, + "decimals": 8, + "balance": "741749040", + "totalReceived": "9445588154", + "totalSent": "8703839114" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/waves-api-transactions-address.js b/mock/ext-api-dyson/get/waves-api-transactions-address.js new file mode 100644 index 000000000..062262faa --- /dev/null +++ b/mock/ext-api-dyson/get/waves-api-transactions-address.js @@ -0,0 +1,61 @@ +/// Waves API Mock +/// See: +/// curl "http://localhost:3000/waves-api/transactions/address/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD/limit/25" +/// curl "https://nodes.wavesnodes.com/transactions/address/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD/limit/25" +/// curl http://localhost:8420/v1/waves/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD +module.exports = { + path: "/waves-api/transactions/address/:address/limit/:limit", + template: function (params, query, body) { + //console.log(params) + if (params.address === '3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD') { + return [ + [ + { + senderPublicKey: "2UstBx1nMYQ2mPeaJi6tv9oUFCUHLvU1G7nS8Leazsbw", + amount: parseFloat("369133368000"), + signature: "5Hw5SW7C1EK8hE2YKawFCAWcJoB1Z5NSZFkA65bS3PcDY9w2fi7etPCJDamK2WNb14RWa3BykdT5yFd64SxodjeQ", + fee: parseFloat("100000"), + type: parseFloat("4"), + version: parseFloat("1"), + attachment: "", + sender: "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + feeAssetId: null, + proofs: [ + "5Hw5SW7C1EK8hE2YKawFCAWcJoB1Z5NSZFkA65bS3PcDY9w2fi7etPCJDamK2WNb14RWa3BykdT5yFd64SxodjeQ" + ], + assetId: null, + recipient: "3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", + feeAsset: null, + id: "23JGFzBh65fzZArK6KSeRqjjBG5WnQshJJkUv53hCE1E", + timestamp: parseFloat("1582527770493"), + height: parseFloat("1943922") + }, + { + senderPublicKey: "3uT3a9ceebFf6vEa5DmedD5pK6xa1GY7PnvhWPMVyqxC", + amount: parseFloat("369133468000"), + signature: "3Nrz47KpD3U39Nf7Los23MDoukqXCrCJun1BqnUgjpy9iZLfXc163dTrz4wVvURC2yiULsNYDYA2pxTPGWpBotc5", + fee: parseFloat("100000"), + type: parseFloat("4"), + version: parseFloat("1"), + attachment: "Paribu", + sender: "3PHYYqBA6ZfBsoGsrXP8r7ZptLXYdGDt1Cm", + feeAssetId: null, + proofs: [ + "3Nrz47KpD3U39Nf7Los23MDoukqXCrCJun1BqnUgjpy9iZLfXc163dTrz4wVvURC2yiULsNYDYA2pxTPGWpBotc5" + ], + assetId: null, + recipient: "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + feeAsset: null, + id: "1456haw7zSTKDmVSbY1njrYdskX7xKbv241c5WJjWhCu", + timestamp: parseFloat("1582527244669"), + height: parseFloat("1943911") + } + ] + ] + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +} +; diff --git a/mock/ext-api-dyson/get/zcash-api-address.js b/mock/ext-api-dyson/get/zcash-api-address.js new file mode 100644 index 000000000..463c12a15 --- /dev/null +++ b/mock/ext-api-dyson/get/zcash-api-address.js @@ -0,0 +1,173 @@ +/// Mock for external Zcash API +/// See: +/// curl "http://{Zcash rpc}/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" +/// curl "http://localhost:3000/zcash-api/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" +/// curl "http://localhost:8420/v1/zcash/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" + +module.exports = { + path: '/zcash-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 't1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 2, + "addrStr": "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX", + "balance": "0.12344656", + "totalReceived": "1096.63825939", + "totalSent": "1096.51481283", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 1636, + "txs": [ + { + "txid": "d504755667e0fb61543e16d09aff5f84733f500190a07acb4a6784b4dc4c99e7", + "version": 4, + "vin": [ + { + "txid": "", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": {}, + "addresses": null, + "value": "" + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "scriptPubKey": { + "hex": "76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac", + "addresses": [ + "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" + ] + }, + "spent": false + }, + { + "value": "1.25", + "n": 1, + "scriptPubKey": { + "hex": "a914e445cfa944b6f2bdacefbda904a81d5fdd26d77f87", + "addresses": [ + "t3fNcdBUbycvbCtsD2n9q3LuxG7jVPvFB8L" + ] + }, + "spent": false + }, + { + "value": "0.0625", + "n": 2, + "scriptPubKey": { + "hex": "76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac", + "addresses": [ + "t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv" + ] + }, + "spent": false + }, + { + "value": "4.9375", + "n": 3, + "scriptPubKey": { + "hex": "76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac", + "addresses": [ + "t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2" + ] + }, + "spent": false + } + ], + "blockhash": "000000000259ba5a4b53e1ce8e6828fc780f8858283620aa27418ce80681c1b5", + "blockheight": 768336, + "confirmations": 7, + "time": 1584747959, + "blocktime": 1584747959, + "valueOut": "6.25", + "valueIn": "0", + "fees": "0", + "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff500350b90b0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914e445cfa944b6f2bdacefbda904a81d5fdd26d77f87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000" + }, + { + "txid": "95e12ff1a8ca7a19d5af92c6a480d1c1da4cf998dcba08329d151acb45d78bbb", + "version": 4, + "vin": [ + { + "txid": "", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": {}, + "addresses": null, + "value": "" + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "scriptPubKey": { + "hex": "76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac", + "addresses": [ + "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" + ] + }, + "spent": false + }, + { + "value": "1.25", + "n": 1, + "scriptPubKey": { + "hex": "a914e445cfa944b6f2bdacefbda904a81d5fdd26d77f87", + "addresses": [ + "t3fNcdBUbycvbCtsD2n9q3LuxG7jVPvFB8L" + ] + }, + "spent": false + }, + { + "value": "0.0625", + "n": 2, + "scriptPubKey": { + "hex": "76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac", + "addresses": [ + "t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv" + ] + }, + "spent": false + }, + { + "value": "4.9375", + "n": 3, + "scriptPubKey": { + "hex": "76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac", + "addresses": [ + "t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2" + ] + }, + "spent": false + } + ], + "blockhash": "0000000000f747c6311d3658bad9bab649e21dd365075a1df8b98a88c3871458", + "blockheight": 768281, + "confirmations": 62, + "time": 1584744347, + "blocktime": 1584744347, + "valueOut": "6.25", + "valueIn": "0", + "fees": "0", + "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff500319b90b0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914e445cfa944b6f2bdacefbda904a81d5fdd26d77f87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/zcash-api-xpub.js b/mock/ext-api-dyson/get/zcash-api-xpub.js new file mode 100644 index 000000000..c18f35d5d --- /dev/null +++ b/mock/ext-api-dyson/get/zcash-api-xpub.js @@ -0,0 +1,126 @@ +/// Mock for external Zcash API +/// See: +/// curl "http://{Zcash rpc}/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs" +/// curl "http://localhost:3000/zcash-api/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs" +/// curl "http://localhost:8420/v1/zcash/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS" + +module.exports = { + path: '/zcash-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 2, + "address": "xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS", + "balance": "846466", + "totalReceived": "14304018", + "totalSent": "13457552", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 38, + "transactions": [ + { + "txid": "f2438a93039faf08d39bd3df1f7b5f19a2c29ffe8753127e2956ab4461adab35", + "version": 4, + "vin": [ + { + "txid": "ee120b714991e6166b8ff4b6419cbfee657eca87675245ce8585787be3b07d70", + "vout": 1, + "n": 0, + "addresses": [ + "t1LJWoRDU14zUG4TGumHiobd9WBUjqLE5FU" + ], + "isAddress": true, + "value": "956466", + "hex": "483045022100d2ac7b2b17218572f3dc163063463be5143a8d3c2126b52eb73d49c9c4959da00220057417baaad53c168e82dd44a7f964759c7d584e0770b6284a8e1b0261f1c7e0012102a71eeea42aa1b4e30a409f9186bd88dc84dec5c404964f386c323f557ad268d9" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a914a2511fc37f67f3b5627affce89fb3f7bb186412888ac", + "addresses": [ + "t1Yfrf1dssDLmaMBsq2LFKWPbS5vH3nGpa2" + ], + "isAddress": true + }, + { + "value": "846466", + "n": 1, + "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true + } + ], + "blockHash": "00000000005a238fecd893e55fba7072af65545fd43eaad63402c211cc172a61", + "blockHeight": 750255, + "confirmations": 18102, + "blockTime": 1583385097, + "value": "946466", + "valueIn": "956466", + "fees": "10000", + "hex": "0400008085202f8901707db0e37b788585ce45526787ca7e65eebf9c41b6f48f6b16e69149710b12ee010000006b483045022100d2ac7b2b17218572f3dc163063463be5143a8d3c2126b52eb73d49c9c4959da00220057417baaad53c168e82dd44a7f964759c7d584e0770b6284a8e1b0261f1c7e0012102a71eeea42aa1b4e30a409f9186bd88dc84dec5c404964f386c323f557ad268d90000000002a0860100000000001976a914a2511fc37f67f3b5627affce89fb3f7bb186412888ac82ea0c00000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac00000000000000000000000000000000000000" + }, + { + "txid": "ee120b714991e6166b8ff4b6419cbfee657eca87675245ce8585787be3b07d70", + "version": 4, + "vin": [ + { + "txid": "b49791a277ff137e37f9e163c8a5bc25492f741c275f9d36d5c0c713497c176c", + "vout": 1, + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1fuw3P3r5xbJXFqpaHUWb3TMz6xo9yPXEL" + ], + "isAddress": true, + "value": "996466", + "hex": "483045022100e7ddc39a2b976ee277d71f6130334084f1f21ef4f17cdd81514cf8af2181df1b02201c9a76a45b948c87940dc47525f1660d6c9c1e44ab22e4bcc16af0ce99c4c1890121031a03d4f4982aaa59d4087434907c9578fe77eadc73491b32f7373aaf9c17902e" + } + ], + "vout": [ + { + "value": "30000", + "n": 0, + "spent": true, + "hex": "76a914db49ca3524ee1e99aa097c6c9860ffcb5e5ed94a88ac", + "addresses": [ + "t1ds6PMeHUvAYtASPqCuEXzT1DsteXWwtTv" + ], + "isAddress": true + }, + { + "value": "956466", + "n": 1, + "spent": true, + "hex": "76a9141aa64e287339ad3fa041bc7a429bbcd57ac8a80088ac", + "addresses": [ + "t1LJWoRDU14zUG4TGumHiobd9WBUjqLE5FU" + ], + "isAddress": true + } + ], + "blockHash": "00000000008dcc62d679d7eaf05ac18403198f5f39b3e4e7f36869673855779b", + "blockHeight": 685806, + "confirmations": 82551, + "blockTime": 1578529212, + "value": "986466", + "valueIn": "996466", + "fees": "10000", + "hex": "0400008085202f89016c177c4913c7c0d5369d5f271c742f4925bca5c863e1f9377e13ff77a29197b4010000006b483045022100e7ddc39a2b976ee277d71f6130334084f1f21ef4f17cdd81514cf8af2181df1b02201c9a76a45b948c87940dc47525f1660d6c9c1e44ab22e4bcc16af0ce99c4c1890121031a03d4f4982aaa59d4087434907c9578fe77eadc73491b32f7373aaf9c17902efeffff7f0230750000000000001976a914db49ca3524ee1e99aa097c6c9860ffcb5e5ed94a88ac32980e00000000001976a9141aa64e287339ad3fa041bc7a429bbcd57ac8a80088ac00000000000000000000000000000000000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/zcoin-api-address.js b/mock/ext-api-dyson/get/zcoin-api-address.js new file mode 100644 index 000000000..b1c393f11 --- /dev/null +++ b/mock/ext-api-dyson/get/zcoin-api-address.js @@ -0,0 +1,279 @@ +/// Mock for external Zcoin API +/// See: +/// curl "http://{Zcoin rpc}/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" +/// curl "http://localhost:3000/zcoin-api/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" +/// curl "http://localhost:8420/v1/zcoin/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + +module.exports = { + path: '/zcoin-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "addrStr": "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn", + "balance": "0.6310911", + "totalReceived": "15.65104974", + "totalSent": "15.01995864", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 18, + "txs": [ + { + "txid": "11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45", + "version": 1, + "vin": [ + { + "txid": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", + "vout": 1, + "n": 0, + "scriptSig": { + "hex": "483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" + }, + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "value": "0.63028838" + } + ], + "vout": [ + { + "value": "0.001", + "n": 0, + "scriptPubKey": { + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ] + }, + "spent": false + }, + { + "value": "0.6292477", + "n": 1, + "scriptPubKey": { + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ] + }, + "spent": true, + "spentTxId": "50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd", + "spentHeight": 251156 + } + ], + "blockhash": "5ba0f8c0e58986d1eb5036e766e28ed541d0993cb717fc1aea46d714a89945e7", + "blockheight": 250864, + "confirmations": 1845, + "time": 1584571576, + "blocktime": 1584571576, + "valueOut": "0.6302477", + "valueIn": "0.63028838", + "fees": "0.00004068", + "hex": "0100000001ef273981817358e256ecb5e87a9826056893b8e2672e49a6a8c29b0fe343fb86010000006b483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b150000000002a0860100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ace227c003000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", + "version": 1, + "vin": [ + { + "txid": "5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "scriptSig": { + "hex": "483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" + }, + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "value": "0.64032906" + } + ], + "vout": [ + { + "value": "0.01", + "n": 0, + "scriptPubKey": { + "hex": "76a914cffef031eead7d332c245df1372dcf4980a0127c88ac", + "addresses": [ + "aKgF22yWfjBqekrbkhkFYqenzsw9zfRch8" + ] + }, + "spent": false + }, + { + "value": "0.63028838", + "n": 1, + "scriptPubKey": { + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ] + }, + "spent": true, + "spentTxId": "11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45", + "spentHeight": 250864 + } + ], + "blockhash": "fcfea4d17cde4cfc8d113d923e7e2978513e902448f1087fd448ae4162696f4f", + "blockheight": 244409, + "confirmations": 8300, + "time": 1582620606, + "blocktime": 1582620606, + "valueOut": "0.64028838", + "valueIn": "0.64032906", + "fees": "0.00004068", + "hex": "01000000011e60be361fdabd33a545444bd7c0a6571e6e1fa9d92e65676da700d0aeebf75c010000006b483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15feffffff0240420f00000000001976a914cffef031eead7d332c245df1372dcf4980a0127c88ac66bec103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "4178eb3a84a34a9b508dbb61abbe725de115de2daea619e1cfa68eadf001fe51", + "version": 1, + "vin": [ + { + "txid": "6de60b862ef752e24f1417c255f750e8e2e2b64ce4160eccbcdd82663a36daeb", + "vout": 0, + "n": 0, + "scriptSig": { + "hex": "483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b" + }, + "addresses": [ + "aDVvWiM5PTv3QrUbrWQW3hPVLiFTMmzAHr" + ], + "value": "0.001" + } + ], + "vout": [ + { + "value": "0.00096544", + "n": 0, + "scriptPubKey": { + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ] + }, + "spent": false + } + ], + "blockhash": "e3d64bc33182f0b74b6247c7b37a9f8ff3c6852fe1c08116d460d067919345d1", + "blockheight": 241112, + "confirmations": 11597, + "time": 1581616858, + "blocktime": 1581616858, + "valueOut": "0.00096544", + "valueIn": "0.001", + "fees": "0.00003456", + "hex": "0100000001ebda363a6682ddbccc0e16e44cb6e2e2e850f755c217144fe252f72e860be66d000000006b483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b000000000120790100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e", + "version": 1, + "vin": [ + { + "txid": "5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241", + "vout": 1, + "n": 0, + "scriptSig": { + "hex": "483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8" + }, + "addresses": [ + "aL96Xr2E1pMW3vcsZ5QV6BYLFE9jdCVBJL" + ], + "value": "3.64036974" + } + ], + "vout": [ + { + "value": "3", + "n": 0, + "scriptPubKey": { + "hex": "76a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac", + "addresses": [ + "aB3mWSqhFzszMJ3h8sxTedFYDhZCDBkeQT" + ] + }, + "spent": true, + "spentTxId": "736d2ed9a2398511cc98f30df178db721716c1996fd8ab67970a5ac41a795e72", + "spentIndex": 2, + "spentHeight": 239559 + }, + { + "value": "0.64032906", + "n": 1, + "scriptPubKey": { + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ] + }, + "spent": true, + "spentTxId": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", + "spentHeight": 244409 + } + ], + "blockhash": "07d7c24529ee402be1a94b6b5a70d000c6002f0fa7201c1f5ef4ef7dd87f0117", + "blockheight": 239551, + "confirmations": 13158, + "time": 1581138788, + "blocktime": 1581138788, + "valueOut": "3.64032906", + "valueIn": "3.64036974", + "fees": "0.00004068", + "hex": "010000000141320e1d67dca17a2d7107f1e3b378fbf443347afb21e16d130be718a8ce8254010000006b483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8000000000200a3e111000000001976a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac8a10d103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "c4f897a1d64e6c870184ff26a3ad8f5f4a94a6667f6d3486f21e52530d8ecea2", + "version": 1, + "vin": [ + { + "txid": "3054b05d5f9624264bf7bfbb140749472c58670cc935efa5aab4a96c6430ed19", + "vout": 0, + "sequence": 4294967294, + "n": 0, + "scriptSig": { + "hex": "473044022062705d4b0f266a25646c410e3a735b7665dafb85655bf4b9f3ce89ecde4306f20220702f5fd1f3d6e593c3e3e9a37adf6431b1920b55151872dc9c8f4dc166df1a8f0121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" + }, + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "value": "3.6504511" + } + ], + "vout": [ + { + "value": "3.65041042", + "n": 0, + "scriptPubKey": { + "hex": "76a914e5712d04a22c551a8261aea3f4a8d98ddb057f5988ac", + "addresses": [ + "aMde4RuTWiNzoZN53SWZ7i7tKNbhSwt57U" + ] + }, + "spent": true, + "spentTxId": "5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241", + "spentHeight": 238210 + } + ], + "blockhash": "1afa27baa3146c5ae36cb93612f928b794b306d4d8b552636fb3f35891a7adb8", + "blockheight": 238176, + "confirmations": 14533, + "time": 1580709451, + "blocktime": 1580709451, + "valueOut": "3.65041042", + "valueIn": "3.6504511", + "fees": "0.00004068", + "hex": "010000000119ed30646ca9b4aaa5ef35c90c67582c47490714bbbff74b2624965f5db05430000000006a473044022062705d4b0f266a25646c410e3a735b7665dafb85655bf4b9f3ce89ecde4306f20220702f5fd1f3d6e593c3e3e9a37adf6431b1920b55151872dc9c8f4dc166df1a8f0121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15feffffff019215c215000000001976a914e5712d04a22c551a8261aea3f4a8d98ddb057f5988ac00000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/zcoin-api-xpub.js b/mock/ext-api-dyson/get/zcoin-api-xpub.js new file mode 100644 index 000000000..06dca4723 --- /dev/null +++ b/mock/ext-api-dyson/get/zcoin-api-xpub.js @@ -0,0 +1,422 @@ +/// Mock for external Zcoin API +/// See: +/// curl "http://{Zcoin rpc}/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs" +/// curl "http://localhost:3000/zcoin-api/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs" +/// curl "http://localhost:8420/v1/zcoin/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK" + +module.exports = { + path: '/zcoin-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK", + "balance": "63109110", + "totalReceived": "19765346316", + "totalSent": "19702237206", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 54, + "transactions": [ + { + "txid": "cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564", + "version": 1, + "vin": [ + { + "txid": "50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd", + "vout": 1, + "n": 0, + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true, + "value": "61920702", + "hex": "483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + }, + { + "value": "51916634", + "n": 1, + "spent": true, + "spentTxId": "f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609", + "spentHeight": 251191, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + } + ], + "blockHash": "f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328", + "blockHeight": 251191, + "confirmations": 1518, + "blockTime": 1584663676, + "value": "61916634", + "valueIn": "61920702", + "fees": "4068", + "hex": "0100000001fd296277b76a406837115f9213f3ce6ebfdb8408447c1423281c034e387acb50010000006b483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15000000000280969800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac5a2f1803000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609", + "version": 1, + "vin": [ + { + "txid": "cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564", + "vout": 1, + "n": 0, + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true, + "value": "51916634", + "hex": "483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" + } + ], + "vout": [ + { + "value": "13113178", + "n": 0, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + }, + { + "value": "38799388", + "n": 1, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + } + ], + "blockHash": "f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328", + "blockHeight": 251191, + "confirmations": 1518, + "blockTime": 1584663676, + "value": "51912566", + "valueIn": "51916634", + "fees": "4068", + "hex": "010000000164b574c298c44b23fc6f328494ff306444895262d7f670ebb2a5c48233ac33cd010000006b483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b1500000000025a17c800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac1c085002000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd", + "version": 1, + "vin": [ + { + "txid": "11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45", + "vout": 1, + "n": 0, + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true, + "value": "62924770", + "hex": "4830450221009e0fe641502a598f5f470ff3a5cb4bd46e2906e0e09c7a8c93d80bfd61cfb26e0220199247204747faf99e8605e7c6af4a1a8489c2a133b92f1f547990cef62cc9f60121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + }, + { + "value": "61920702", + "n": 1, + "spent": true, + "spentTxId": "cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564", + "spentHeight": 251191, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + } + ], + "blockHash": "1cb40b2f2d4618cd9606b0f476d2ccfeee4740bb76cd46e2c75df6e783017cb1", + "blockHeight": 251156, + "confirmations": 1553, + "blockTime": 1584656561, + "value": "62920702", + "valueIn": "62924770", + "fees": "4068", + "hex": "010000000145db9ddeddd58b983e4e7aa6909c09aa34fddf13657f512bba0821deeb51a011010000006b4830450221009e0fe641502a598f5f470ff3a5cb4bd46e2906e0e09c7a8c93d80bfd61cfb26e0220199247204747faf99e8605e7c6af4a1a8489c2a133b92f1f547990cef62cc9f60121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15000000000240420f00000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788acbed5b003000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45", + "version": 1, + "vin": [ + { + "txid": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", + "vout": 1, + "n": 0, + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true, + "value": "63028838", + "hex": "483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + }, + { + "value": "62924770", + "n": 1, + "spent": true, + "spentTxId": "50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd", + "spentHeight": 251156, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + } + ], + "blockHash": "5ba0f8c0e58986d1eb5036e766e28ed541d0993cb717fc1aea46d714a89945e7", + "blockHeight": 250864, + "confirmations": 1845, + "blockTime": 1584571576, + "value": "63024770", + "valueIn": "63028838", + "fees": "4068", + "hex": "0100000001ef273981817358e256ecb5e87a9826056893b8e2672e49a6a8c29b0fe343fb86010000006b483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b150000000002a0860100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ace227c003000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", + "version": 1, + "vin": [ + { + "txid": "5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true, + "value": "64032906", + "hex": "483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "76a914cffef031eead7d332c245df1372dcf4980a0127c88ac", + "addresses": [ + "aKgF22yWfjBqekrbkhkFYqenzsw9zfRch8" + ], + "isAddress": true + }, + { + "value": "63028838", + "n": 1, + "spent": true, + "spentTxId": "11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45", + "spentHeight": 250864, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + } + ], + "blockHash": "fcfea4d17cde4cfc8d113d923e7e2978513e902448f1087fd448ae4162696f4f", + "blockHeight": 244409, + "confirmations": 8300, + "blockTime": 1582620606, + "value": "64028838", + "valueIn": "64032906", + "fees": "4068", + "hex": "01000000011e60be361fdabd33a545444bd7c0a6571e6e1fa9d92e65676da700d0aeebf75c010000006b483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15feffffff0240420f00000000001976a914cffef031eead7d332c245df1372dcf4980a0127c88ac66bec103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "4178eb3a84a34a9b508dbb61abbe725de115de2daea619e1cfa68eadf001fe51", + "version": 1, + "vin": [ + { + "txid": "6de60b862ef752e24f1417c255f750e8e2e2b64ce4160eccbcdd82663a36daeb", + "n": 0, + "addresses": [ + "aDVvWiM5PTv3QrUbrWQW3hPVLiFTMmzAHr" + ], + "isAddress": true, + "value": "100000", + "hex": "483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b" + } + ], + "vout": [ + { + "value": "96544", + "n": 0, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + } + ], + "blockHash": "e3d64bc33182f0b74b6247c7b37a9f8ff3c6852fe1c08116d460d067919345d1", + "blockHeight": 241112, + "confirmations": 11597, + "blockTime": 1581616858, + "value": "96544", + "valueIn": "100000", + "fees": "3456", + "hex": "0100000001ebda363a6682ddbccc0e16e44cb6e2e2e850f755c217144fe252f72e860be66d000000006b483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b000000000120790100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e", + "version": 1, + "vin": [ + { + "txid": "5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241", + "vout": 1, + "n": 0, + "addresses": [ + "aL96Xr2E1pMW3vcsZ5QV6BYLFE9jdCVBJL" + ], + "isAddress": true, + "value": "364036974", + "hex": "483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8" + } + ], + "vout": [ + { + "value": "300000000", + "n": 0, + "spent": true, + "spentTxId": "736d2ed9a2398511cc98f30df178db721716c1996fd8ab67970a5ac41a795e72", + "spentIndex": 2, + "spentHeight": 239559, + "hex": "76a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac", + "addresses": [ + "aB3mWSqhFzszMJ3h8sxTedFYDhZCDBkeQT" + ], + "isAddress": true + }, + { + "value": "64032906", + "n": 1, + "spent": true, + "spentTxId": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", + "spentHeight": 244409, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + } + ], + "blockHash": "07d7c24529ee402be1a94b6b5a70d000c6002f0fa7201c1f5ef4ef7dd87f0117", + "blockHeight": 239551, + "confirmations": 13158, + "blockTime": 1581138788, + "value": "364032906", + "valueIn": "364036974", + "fees": "4068", + "hex": "010000000141320e1d67dca17a2d7107f1e3b378fbf443347afb21e16d130be718a8ce8254010000006b483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8000000000200a3e111000000001976a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac8a10d103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241", + "version": 1, + "vin": [ + { + "txid": "c4f897a1d64e6c870184ff26a3ad8f5f4a94a6667f6d3486f21e52530d8ecea2", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "aMde4RuTWiNzoZN53SWZ7i7tKNbhSwt57U" + ], + "isAddress": true, + "value": "365041042", + "hex": "4730440220260b40074ffa84cf4f747433efdc524a347bf9f2b995a212a7c7fafeeb9105180220222edad73b70511698a9dc68ae246b78a7ba9daf3c1b44fb5d7fdd4d8d008d890121035209cb9a9c86a775cb9593b4c6fdde4f23e4bb4193cfeae0706080702189efa3" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "spentTxId": "c70c9d3bf599a9e3553b6235f6468c69c1fa54aa0505e49d81e37aa1a749379a", + "spentHeight": 238297, + "hex": "76a91480be9e18824eae9cc7771291b7a017a458fb48b388ac", + "addresses": [ + "aCTCaoLEy6ZbKQGKjBe1kprQ4foEa2cBVv" + ], + "isAddress": true + }, + { + "value": "364036974", + "n": 1, + "spent": true, + "spentTxId": "5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e", + "spentHeight": 239551, + "hex": "76a914d51315e0d5624c84e9da869bd34735926022ae5888ac", + "addresses": [ + "aL96Xr2E1pMW3vcsZ5QV6BYLFE9jdCVBJL" + ], + "isAddress": true + } + ], + "blockHash": "fc464897e8c6bcbd5bede4109a24075894a61d3a2d7aa06cc0bc1a37b07d1903", + "blockHeight": 238210, + "confirmations": 14499, + "blockTime": 1580718580, + "value": "365036974", + "valueIn": "365041042", + "fees": "4068", + "hex": "0100000001a2ce8e0d53521ef286346d7f66a6944a5f8fada326ff8401876c4ed6a197f8c4000000006a4730440220260b40074ffa84cf4f747433efdc524a347bf9f2b995a212a7c7fafeeb9105180220222edad73b70511698a9dc68ae246b78a7ba9daf3c1b44fb5d7fdd4d8d008d890121035209cb9a9c86a775cb9593b4c6fdde4f23e4bb4193cfeae0706080702189efa3feffffff0240420f00000000001976a91480be9e18824eae9cc7771291b7a017a458fb48b388ac6ec3b215000000001976a914d51315e0d5624c84e9da869bd34735926022ae5888ac00000000" + } + ], + "usedTokens": 52, + "tokens": [ + { + "type": "XPUBAddress", + "name": "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn", + "path": "m/44'/136'/0'/0/0", + "transfers": 18, + "decimals": 8, + "balance": "63109110", + "totalReceived": "1565104974", + "totalSent": "1501995864" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/zelcash-api-address.js b/mock/ext-api-dyson/get/zelcash-api-address.js new file mode 100644 index 000000000..d46f5b8a2 --- /dev/null +++ b/mock/ext-api-dyson/get/zelcash-api-address.js @@ -0,0 +1,243 @@ +/// Mock for external Zelcash API +/// See: +/// curl "http://{Zelcash rpc}/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs&pageSize=25" +/// curl "http://localhost:3000/zelcash-api/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs" +/// curl "http://localhost:8420/v1/zelcash/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" + +module.exports = { + path: '/zelcash-api/address/:address?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 't1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa': + return JSON.parse(` + { + "page": 1, + "totalPages": 4175, + "itemsOnPage": 25, + "addrStr": "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa", + "balance": "6300.00809211", + "totalReceived": "10963952.85564162", + "totalSent": "10957652.84754951", + "unconfirmedBalance": "0", + "unconfirmedTxApperances": 0, + "txApperances": 104369, + "txs": [ + { + "txid": "ca8b3fa115c5eae0f056d9b629680c521f4d9d271abbe86d4c482c54117e15a1", + "version": 4, + "vin": [ + { + "txid": "", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": {}, + "addresses": null, + "value": "" + } + ], + "vout": [ + { + "value": "112.5001", + "n": 0, + "scriptPubKey": { + "hex": "76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac", + "addresses": [ + "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" + ] + }, + "spent": false + }, + { + "value": "5.625", + "n": 1, + "scriptPubKey": { + "hex": "76a91402664e0d583d97b55b71320eea199c20ecbab3a588ac", + "addresses": [ + "t1J6HuzEqw8Aicm1WLL8YX7jo7Syy7zkTjs" + ] + }, + "spent": false + }, + { + "value": "9.375", + "n": 2, + "scriptPubKey": { + "hex": "76a9146096374c8e00616fd777c9497d9fce18eae3948d88ac", + "addresses": [ + "t1SgJpwdmPSgw4j6eAdVVY1duWkbixygptP" + ] + }, + "spent": false + }, + { + "value": "22.5", + "n": 3, + "scriptPubKey": { + "hex": "76a9145a5f63ff65c2b1f4124ed2f5aa6fd9db53ec2f4488ac", + "addresses": [ + "t1S7T6TRuYuodWyAkiRVxRj5XgfFs1G3PWY" + ] + }, + "spent": false + } + ], + "blockhash": "000000351df0a7b2a629657aecc89ce10d07f7c5a9ad7f03fefb3442b1a7a521", + "blockheight": 562387, + "confirmations": 1, + "time": 1585124312, + "blocktime": 1585124312, + "valueOut": "150.0001", + "valueIn": "0", + "fees": "0", + "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003d3940800324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0490878d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a91402664e0d583d97b55b71320eea199c20ecbab3a588ac601de137000000001976a9146096374c8e00616fd777c9497d9fce18eae3948d88ac80461c86000000001976a9145a5f63ff65c2b1f4124ed2f5aa6fd9db53ec2f4488ac00000000000000000000000000000000000000" + }, + { + "txid": "96990e262110a89d8e372df3126cf72023b07643325c9b8b38f4c3651c1931b3", + "version": 4, + "vin": [ + { + "txid": "", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": {}, + "addresses": null, + "value": "" + } + ], + "vout": [ + { + "value": "112.5", + "n": 0, + "scriptPubKey": { + "hex": "76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac", + "addresses": [ + "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" + ] + }, + "spent": false + }, + { + "value": "5.625", + "n": 1, + "scriptPubKey": { + "hex": "76a914361dfb3217992096d4fc8cfac8a076cdc4e9aaf588ac", + "addresses": [ + "t1NokQpvLQo1Ti4MzvqPM24tn5psXEbJAWu" + ] + }, + "spent": false + }, + { + "value": "9.375", + "n": 2, + "scriptPubKey": { + "hex": "76a9142ccfb039f8a3057684832334b2b96f38299d9a9988ac", + "addresses": [ + "t1MxYYDbod3vJNDpmCXPF99SpoFZ8j4k8dZ" + ] + }, + "spent": false + }, + { + "value": "22.5", + "n": 3, + "scriptPubKey": { + "hex": "76a9143d94fc18dd332c386014f9e5b05cce17710a2ce688ac", + "addresses": [ + "t1PVDhgMueDh8vY3JfkZoXcGrwATCfkwaL9" + ] + }, + "spent": false + } + ], + "blockhash": "00000027379c0e0420ab3ebfc88a0f1bf59f10ced3317ce70f64ffa53f6a7775", + "blockheight": 562386, + "confirmations": 2, + "time": 1585124285, + "blocktime": 1585124285, + "valueOut": "150", + "valueIn": "0", + "fees": "0", + "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003d2940800324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0480608d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914361dfb3217992096d4fc8cfac8a076cdc4e9aaf588ac601de137000000001976a9142ccfb039f8a3057684832334b2b96f38299d9a9988ac80461c86000000001976a9143d94fc18dd332c386014f9e5b05cce17710a2ce688ac00000000000000000000000000000000000000" + }, + { + "txid": "aa1012b3cfcc36b0d6e10c25d0550d8ff482462cfc39e2ae93b03e9f7021bc00", + "version": 4, + "vin": [ + { + "txid": "", + "vout": 0, + "sequence": 4294967295, + "n": 0, + "scriptSig": {}, + "addresses": null, + "value": "" + } + ], + "vout": [ + { + "value": "112.5", + "n": 0, + "scriptPubKey": { + "hex": "76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac", + "addresses": [ + "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" + ] + }, + "spent": false + }, + { + "value": "5.625", + "n": 1, + "scriptPubKey": { + "hex": "76a914490683ffa4c8c06eca7f0ede150cf267df5e920988ac", + "addresses": [ + "t1QXj93zU8HVsfTpqJTHCnoZ9QvR2ho1rp7" + ] + }, + "spent": false + }, + { + "value": "9.375", + "n": 2, + "scriptPubKey": { + "hex": "76a91415f6ecf50ff229de0462f7003dcd5c5656f1e56888ac", + "addresses": [ + "t1Ksk14EFS9GqwGUF5kqnyR9zpYnKDAfxA5" + ] + }, + "spent": false + }, + { + "value": "22.5", + "n": 3, + "scriptPubKey": { + "hex": "76a914ee494e77ec55c57b2f5b42b1487a15fb3264227188ac", + "addresses": [ + "t1fbYeRABbZfzuxViLQbJ4d1dBTET48FgnV" + ] + }, + "spent": false + } + ], + "blockhash": "000000938163fab733308a221b50373250c7e8316e1420992abb833208152916", + "blockheight": 562385, + "confirmations": 3, + "time": 1585124162, + "blocktime": 1585124162, + "valueOut": "150", + "valueIn": "0", + "fees": "0", + "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003d1940800324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0480608d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914490683ffa4c8c06eca7f0ede150cf267df5e920988ac601de137000000001976a91415f6ecf50ff229de0462f7003dcd5c5656f1e56888ac80461c86000000001976a914ee494e77ec55c57b2f5b42b1487a15fb3264227188ac00000000000000000000000000000000000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/zelcash-api-xpub.js b/mock/ext-api-dyson/get/zelcash-api-xpub.js new file mode 100644 index 000000000..c1b3e53bd --- /dev/null +++ b/mock/ext-api-dyson/get/zelcash-api-xpub.js @@ -0,0 +1,196 @@ +/// Mock for external Zelcash API +/// See: +/// curl "http://{Zelcash rpc}/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs" +/// curl "http://localhost:3000/zelcash-api/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs" +/// curl "http://localhost:8420/v1/zelcash/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf" + +module.exports = { + path: '/zelcash-api/v2/xpub/:xpubkey?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.xpubkey) { + case 'xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf': + return JSON.parse(` + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf", + "balance": "9209317640", + "totalReceived": "135114824440", + "totalSent": "125905506800", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 29, + "transactions": [ + { + "txid": "640ea080f060fbfcc6722f861c93483551a831020f6731a37ba5383da71b4972", + "version": 4, + "vin": [ + { + "txid": "a3db9e10aa146805477b9012130e6f68d473975095b82c7e6e6ab5f409da9eef", + "n": 0, + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ], + "value": "1000000", + "hex": "47304402205f7e4f5c17f6bf9880bd0afecec581253419a7b94a440fc9d4a4f4c35ee5b69102203a5c1ba8fc40098e9de6d4df71bb364e9028ddf9eb6ec31e42a1293c19170d8d012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + }, + { + "value": "890000", + "n": 1, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + } + ], + "blockHash": "0000004957cd52c4654e44b0a02cd33be907ae3ae47949e44984cccaf0e34e96", + "blockHeight": 560762, + "confirmations": 1627, + "blockTime": 1584928030, + "value": "990000", + "valueIn": "1000000", + "fees": "10000", + "hex": "0400008085202f8901ef9eda09f4b56a6e7e2cb895509773d4686f0e1312907b47056814aa109edba3000000006a47304402205f7e4f5c17f6bf9880bd0afecec581253419a7b94a440fc9d4a4f4c35ee5b69102203a5c1ba8fc40098e9de6d4df71bb364e9028ddf9eb6ec31e42a1293c19170d8d012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e366440000000002a0860100000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac90940d00000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac00000000000000000000000000000000000000" + }, + { + "txid": "a3db9e10aa146805477b9012130e6f68d473975095b82c7e6e6ab5f409da9eef", + "version": 4, + "vin": [ + { + "txid": "2de19629bbf78af114ff9cf3332229dc336be4758481b72828f1bd786e8cc41e", + "vout": 1, + "n": 0, + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ], + "value": "899960000", + "hex": "4830450221008f14795cde861210cbd9a1c3d89a29f0efe5c3cdceb2049795d5a9a84cc2571f02203c4e360575b7e5a45b067382b7d4e3fadbc80382eaa32e08a0bba46ae9bc7cb9012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + }, + { + "value": "898950000", + "n": 1, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + } + ], + "blockHash": "0000008979ea8aac4d45ae6b5db721845d2d909e723b8fbb87d81f528a7ceefe", + "blockHeight": 558864, + "confirmations": 3525, + "blockTime": 1584697832, + "value": "899950000", + "valueIn": "899960000", + "fees": "10000", + "hex": "0400008085202f89011ec48c6e78bdf12828b7818475e46b33dc292233f39cff14f18af7bb2996e12d010000006b4830450221008f14795cde861210cbd9a1c3d89a29f0efe5c3cdceb2049795d5a9a84cc2571f02203c4e360575b7e5a45b067382b7d4e3fadbc80382eaa32e08a0bba46ae9bc7cb9012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644000000000240420f00000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac70e39435000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac00000000000000000000000000000000000000" + }, + { + "txid": "2de19629bbf78af114ff9cf3332229dc336be4758481b72828f1bd786e8cc41e", + "version": 4, + "vin": [ + { + "txid": "7db9135b1dabcecccff9e4d403802d1bf0d7850438233b3091b876331bab551b", + "n": 0, + "addresses": [ + "t1MpHLd2vryyTufEMF3WBHy7VP63YKigi53" + ], + "value": "999970000", + "hex": "473044022040534cefd8cfbe8f2705032a3636067fb8612ec3449f75699fcd894e5f2dc9960220363c26ddbbdb840fc76fbb950aecbfd6fa7d03e64da1c5890c302f0bb6f007a8012103d6bf5faa2c95ae8c4572f0755f45dba20dcd806ef8344a5dc2a54996874661c4" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "76a914a394f62bbe0a47af97171e99bd8ff4fed9cae33188ac", + "addresses": [ + "t1YnYbdwU1ReMUbN46byAQNtnDPqMRYxFPJ" + ] + }, + { + "value": "899960000", + "n": 1, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + } + ], + "blockHash": "0000007f0db0ed2ac5f5747e7746dc5e016e1f2a84df54115e85eee4d7aecb3b", + "blockHeight": 547987, + "confirmations": 14402, + "blockTime": 1583385317, + "value": "999960000", + "valueIn": "999970000", + "fees": "10000", + "hex": "0400008085202f89011b55ab1b3376b891303b23380485d7f01b2d8003d4e4f9cfccceab1d5b13b97d000000006a473044022040534cefd8cfbe8f2705032a3636067fb8612ec3449f75699fcd894e5f2dc9960220363c26ddbbdb840fc76fbb950aecbfd6fa7d03e64da1c5890c302f0bb6f007a8012103d6bf5faa2c95ae8c4572f0755f45dba20dcd806ef8344a5dc2a54996874661c4000000000200e1f505000000001976a914a394f62bbe0a47af97171e99bd8ff4fed9cae33188acc04ca435000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac00000000000000000000000000000000000000" + }, + { + "txid": "7db9135b1dabcecccff9e4d403802d1bf0d7850438233b3091b876331bab551b", + "version": 4, + "vin": [ + { + "txid": "3ce3913910d9aab7ddb308b16abd6d5d66c258737b5f86e829cc741fa317820b", + "n": 0, + "addresses": [ + "t1YnYbdwU1ReMUbN46byAQNtnDPqMRYxFPJ" + ], + "value": "999980000", + "hex": "483045022100fdf9542e8c44a218601d427ac9d8262866083c3ac1312c1448c345ed54782901022077a4c5e1d22657e000a2c76dc6f873fcb70b7298bd627dd3dc7bb24fa6175ab10121033985b538c7c62cd419a5b24e0dd8d322174303f376e025fddd1f19da2cebcc50" + } + ], + "vout": [ + { + "value": "999970000", + "n": 0, + "spent": true, + "hex": "76a9142b3fac242eb3d7e20130082190605a5f7750037788ac", + "addresses": [ + "t1MpHLd2vryyTufEMF3WBHy7VP63YKigi53" + ] + } + ], + "blockHash": "00000021b6af345a3d3010cdf9811fa9ca1f1163841519f2906ababa766b21ec", + "blockHeight": 494906, + "confirmations": 67483, + "blockTime": 1576977235, + "value": "999970000", + "valueIn": "999980000", + "fees": "10000", + "hex": "0400008085202f89010b8217a31f74cc29e8865f7b7358c2665d6dbd6ab108b3ddb7aad9103991e33c000000006b483045022100fdf9542e8c44a218601d427ac9d8262866083c3ac1312c1448c345ed54782901022077a4c5e1d22657e000a2c76dc6f873fcb70b7298bd627dd3dc7bb24fa6175ab10121033985b538c7c62cd419a5b24e0dd8d322174303f376e025fddd1f19da2cebcc500000000001d0549a3b000000001976a9142b3fac242eb3d7e20130082190605a5f7750037788ac00000000000000000000000000000000000000" + } + ] + } + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js b/mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js new file mode 100644 index 000000000..58273206a --- /dev/null +++ b/mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js @@ -0,0 +1,49 @@ +/// Mock for external Zilliqa API +/// See: +/// curl -H "X-APIKEY: YOUR_API_KEY" "https://api.viewblock.io/v1/zilliqa/addresses/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z/txs" +/// curl "http://localhost:3000/zilliqa-api/addresses/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z/txs" +/// curl "http://localhost:8420/v1/zilliqa/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z" + +module.exports = { + path: '/zilliqa-api/addresses/:address/txs', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.address) { + case 'zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z': + return JSON.parse(` + [ + { + "hash": "0xa5d0e0cefd6f114e9659f15016f9f4a303a8367eb373beb6909ee44f7f39834d", + "blockHeight": 459052, + "from": "zil10lx2eurx5hexaca0lshdr75czr025cevqu83uz", + "to": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", + "value": "1000000000000", + "fee": "1000000000", + "timestamp": 1583384813191, + "signature": "0x00AF9733DF8FAEFA0FCC9BBAD21DB30A4815749C19CBFFA5A3BCE75A199E4C84FB4728CB946A2F043B8FCA338C8EEC26855CD7B88D8925E69F87CADF5D072343", + "direction": "in", + "nonce": 25, + "receiptSuccess": true, + "events": [] + }, + { + "hash": "0xe29a7e17402c0c067af4c285dedc79114fe62f23d39843c15756db4641f1a00d", + "blockHeight": 414452, + "from": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", + "to": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", + "value": "10000000000", + "fee": "1000000000", + "timestamp": 1580891803587, + "signature": "0xA5F2C86098A37149CDDD0884009FF1032714DDAC07B2831C87E1FEEB16B8D9B5EB5D310D042003B3AA27A31BE16FD62CD41E5B1F5108475FEB3EB5B8524DA3F4", + "direction": "self", + "nonce": 47, + "receiptSuccess": true, + "events": [] + } + ] + `); + } + return {error: "Not implemented"}; + } +} diff --git a/mock/ext-api-dyson/post/harmony-api.js b/mock/ext-api-dyson/post/harmony-api.js index 782b4f21a..8186560d4 100644 --- a/mock/ext-api-dyson/post/harmony-api.js +++ b/mock/ext-api-dyson/post/harmony-api.js @@ -10,7 +10,71 @@ module.exports = { if (body.method === 'hmy_getTransactionsHistory') { //console.log('body.params[0].address', body.params[0].address); if (body.params[0].address === 'one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv') { - return JSON.parse('{"jsonrpc":"2.0","id":"hmy_getTransactionsHistory","result":{"transactions":[{"blockHash":"0xe6e65f0f9f1e694d93012f1f2b4713cdd253cc6a15e729ff6df23a78d7694013","blockNumber":"0x1b2cd7","from":"one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk","timestamp":"0x5df7cb24","gas":"0x33450","gasPrice":"0x3b9aca00","hash":"0x391af85c5e25ee96cbbc417121b6bacc0ed466c0423467354192c075444e7603","input":"0x","nonce":"0x1f","to":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","transactionIndex":"0x0","value":"0x1bc0ae68df60e000","shardID":0,"toShardID":0,"v":"0x25","r":"0xb65b59fd1c9733977b0689e07a1869713ae2b2f8eabecee0a426c3f7fe62ac6b","s":"0x52b5be00be05173d89ffbf82a47b03f50268e6fe1ccd36a3fa7123a5255d2be2"},{"blockHash":"0x1b45da220f94f41bd42dc0eb89a5e83ce77b37cc78dbc9032bd10a5bbab13674","blockNumber":"0x1b2cdb","from":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","timestamp":"0x5df7cb45","gas":"0x33450","gasPrice":"0x3b9aca00","hash":"0x6bfd003239bf137855342f6266c456ae1b342e886bd1965a47edd4c74dd1a687","input":"0x","nonce":"0x0","to":"one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk","transactionIndex":"0x0","value":"0x1bbfef6a6ff9c000","shardID":0,"toShardID":0,"v":"0x26","r":"0x44c2a7b8c38612a3ce8b51967947c0c9756dda8d82d0f12137451ce33bbef390","s":"0x34234c6c26fe36bda246db845692fd248cb4060cda0d1c6056298b39486ed4f2"},{"blockHash":"0x58cc90d1b9302d0121b426f5fd35014acbc009defe36c5bbff6ac920d6005526","blockNumber":"0x1b2cf2","from":"one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk","timestamp":"0x5df7cc02","gas":"0x33450","gasPrice":"0x3b9aca00","hash":"0xf54f6f86df1624f38fcedf56eb248854a13a733e0b0f92d4b31b9cc7196d90b0","input":"0x","nonce":"0x20","to":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","transactionIndex":"0x0","value":"0x1bc0ae68df60e000","shardID":0,"toShardID":0,"v":"0x25","r":"0x46d14df06948f055e519ac244bcaaa3c3446ed20671d41db01546ddaad32503b","s":"0x50d13aeb94f2e8c760723afa4d892f3ca17690451a57465ea7e39c5d347efe8"},{"blockHash":"0xa84376f0f4d082b76355ccc6ec491660c0062d9ef3f39985ca00986e8dcbacc1","blockNumber":"0x1b2d1b","from":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","timestamp":"0x5df7cd50","gas":"0x33450","gasPrice":"0x3b9aca00","hash":"0x73355f625d0f7ef31512657c0f669e710c8c91a67180cd28bc919cfca0a2af82","input":"0x","nonce":"0x1","to":"one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk","transactionIndex":"0x0","value":"0x1bc09b4f6dd69000","shardID":0,"toShardID":0,"v":"0x26","r":"0xf31271b93e446bce8cc83eb997183146b4da2378a5f2cb1fc4ae64fbd65a93f5","s":"0x77e8e5693a87394204f96693a15f2157459b0329a2ddab97da0bf1cfb6fbce8c"}]}}'); + return JSON.parse(`{ + "jsonrpc": "2.0", + "id": "hmy_getTransactionsHistory", + "result": { + "transactions": [ + { + "blockHash": "0x1b45da220f94f41bd42dc0eb89a5e83ce77b37cc78dbc9032bd10a5bbab13674", + "blockNumber": "0x1b2cdb", + "from": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", + "timestamp": "0x5df7cb45", + "gas": "0x33450", + "gasPrice": "0x3b9aca00", + "hash": "0x6bfd003239bf137855342f6266c456ae1b342e886bd1965a47edd4c74dd1a687", + "input": "0x", + "nonce": "0x0", + "to": "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", + "transactionIndex": "0x0", + "value": "0x1bbfef6a6ff9c000", + "shardID": 0, + "toShardID": 0, + "v": "0x26", + "r": "0x44c2a7b8c38612a3ce8b51967947c0c9756dda8d82d0f12137451ce33bbef390", + "s": "0x34234c6c26fe36bda246db845692fd248cb4060cda0d1c6056298b39486ed4f2" + }, + { + "blockHash": "0x58cc90d1b9302d0121b426f5fd35014acbc009defe36c5bbff6ac920d6005526", + "blockNumber": "0x1b2cf2", + "from": "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", + "timestamp": "0x5df7cc02", + "gas": "0x33450", + "gasPrice": "0x3b9aca00", + "hash": "0xf54f6f86df1624f38fcedf56eb248854a13a733e0b0f92d4b31b9cc7196d90b0", + "input": "0x", + "nonce": "0x20", + "to": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", + "transactionIndex": "0x0", + "value": "0x1bc0ae68df60e000", + "shardID": 0, + "toShardID": 0, + "v": "0x25", + "r": "0x46d14df06948f055e519ac244bcaaa3c3446ed20671d41db01546ddaad32503b", + "s": "0x50d13aeb94f2e8c760723afa4d892f3ca17690451a57465ea7e39c5d347efe8" + }, + { + "blockHash": "0xa84376f0f4d082b76355ccc6ec491660c0062d9ef3f39985ca00986e8dcbacc1", + "blockNumber": "0x1b2d1b", + "from": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", + "timestamp": "0x5df7cd50", + "gas": "0x33450", + "gasPrice": "0x3b9aca00", + "hash": "0x73355f625d0f7ef31512657c0f669e710c8c91a67180cd28bc919cfca0a2af82", + "input": "0x", + "nonce": "0x1", + "to": "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", + "transactionIndex": "0x0", + "value": "0x1bc09b4f6dd69000", + "shardID": 0, + "toShardID": 0, + "v": "0x26", + "r": "0xf31271b93e446bce8cc83eb997183146b4da2378a5f2cb1fc4ae64fbd65a93f5", + "s": "0x77e8e5693a87394204f96693a15f2157459b0329a2ddab97da0bf1cfb6fbce8c" + } + ] + } + }`); } return {jsonrpc:"2.0",id:"hmy_getTransactionsHistory",result:{"transactions":[]}}; } diff --git a/mock/ext-api-dyson/post/kusama-api.js b/mock/ext-api-dyson/post/kusama-api.js new file mode 100644 index 000000000..61fe9d1df --- /dev/null +++ b/mock/ext-api-dyson/post/kusama-api.js @@ -0,0 +1,65 @@ +/// Kusama RPC API Mock +/// See: +/// curl -H "Content-Type: application/json" -d '{"address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", "row": 25}' https://kusama.subscan.io/api/scan/transfers +/// curl -H "Content-Type: application/json" -d '{"address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", "row": 25}' http://localhost:3000/kusama-rpc/scan/transfers +/// curl "http://localhost:8420/v1/kusama/HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK" + +module.exports = { + path: '/kusama-rpc/scan/transfers', + template: function(params, query, body) { + //console.log(body); + switch (body.address) { + case 'HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK': + return JSON.parse(` + { + "code": 0, + "message": "Success", + "ttl": 1, + "data": { + "count": 3, + "transfers": [ + { + "from": "EonK7NScfhd7ZRfgnLhm4cKRFJWK1z59zPximUZRg8VjHQj", + "to": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", + "module": "balances", + "amount": "30", + "hash": "0x9908579abffb409aef95394128f9097f0a21cfdf16675588423e31ab0d3c58e2", + "block_timestamp": 1583243826, + "block_num": 1291387, + "extrinsic_index": "1291387-3", + "success": true, + "fee": "10000000000" + }, + { + "from": "EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X", + "to": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", + "module": "balances", + "amount": "7.333459", + "hash": "0xab5dbf2d38f249785c260c3fca9e19a17df298c5294a99eaec2baab29970eb85", + "block_timestamp": 1581154290, + "block_num": 961987, + "extrinsic_index": "961987-2", + "success": true, + "fee": "10000000000" + }, + { + "from": "EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X", + "to": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", + "module": "balances", + "amount": "233.193373", + "hash": "0x08aad18956058ee385387da2f7d613ed17ac5c98ad23683cfea855b0fd529a63", + "block_timestamp": 1579722240, + "block_num": 738814, + "extrinsic_index": "738814-3", + "success": true, + "fee": "10000000000" + } + ] + } + } + `); + } + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/post/nano-api.js b/mock/ext-api-dyson/post/nano-api.js index 8e1de484a..cc1b306cd 100644 --- a/mock/ext-api-dyson/post/nano-api.js +++ b/mock/ext-api-dyson/post/nano-api.js @@ -36,46 +36,6 @@ module.exports = { "local_timestamp": "1576911446", "height": "6", "hash": "8A2A5840C9286B35D998F5AD535851750C1AFE7B0C7D3AA61E06A1628EDD0E94" - }, - { - "type": "receive", - "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", - "amount": "1000000000000000000000000000", - "local_timestamp": "1575913533", - "height": "5", - "hash": "6816B5AC0594ED768CEC45F5DE25CBF0420300800B6C3C55E6749102F8B09C81" - }, - { - "type": "send", - "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", - "amount": "1083000821328155744662798729216", - "local_timestamp": "1575498786", - "height": "4", - "hash": "D9F97A2AB82EDFAA7A23FFA3423B286A8DD361B5B9303C5E0262EB684162DFD6" - }, - { - "type": "receive", - "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", - "amount": "713600821328155744662798729216", - "local_timestamp": "1575498271", - "height": "3", - "hash": "69F4616925EC95DC15D97037BD99E2E782C2D2A557D5CE11E7FBB4BB6FF617F5" - }, - { - "type": "receive", - "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", - "amount": "234700000000000000000000000000", - "local_timestamp": "1575498125", - "height": "2", - "hash": "6CE398F84A6B3F71E41E843C34917DAC408990C8468EFBC36CFC04954B113A43" - }, - { - "type": "receive", - "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", - "amount": "134700000000000000000000000000", - "local_timestamp": "1575498065", - "height": "1", - "hash": "586BB82BADA98D6F8E4639DA6884C6562141AB983D885780FA41F31F7A04EC18" } ] }`); diff --git a/mock/ext-api-dyson/post/nimiq-rpc.js b/mock/ext-api-dyson/post/nimiq-rpc.js new file mode 100644 index 000000000..6b630112a --- /dev/null +++ b/mock/ext-api-dyson/post/nimiq-rpc.js @@ -0,0 +1,66 @@ +/// Nimiq RPC API Mock +/// See: +/// curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "getTransactionsByAddress", "params": [ "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", "25" ], "id": "getTransactionsByAddress"}' https://nimiq-rpc.trustwalletapp.com +/// curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "getTransactionsByAddress", "params": [ "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", "25" ], "id": "getTransactionsByAddress"}' http://localhost:3000/nimiq-rpc +/// curl "http://localhost:8420/v1/nimiq/NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07" + +module.exports = { + path: '/nimiq-rpc', + template: function(params, query, body) { + //console.log(body); + //console.log('body.method', body.method); + if (body.method === 'getTransactionsByAddress') { + //console.log('body.params', body.params); + if (body.params.length == 0) { + return {error: "missing parameters"}; + } + var address = body.params[0]; + switch (address) { + case 'NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07': + return JSON.parse(` + { + "jsonrpc": "2.0", + "result": [ + { + "hash": "8674d985ac1ea2a75fe9b35ed11d629cef8adfed50db6a5eb125351e622bb405", + "blockHash": "11b0a3aaf64119cfbc66b7fdb8c38d5734a7f50d5bbb0116ee579eb1de513c3f", + "blockNumber": 543545, + "timestamp": 1556458272, + "confirmations": 475868, + "from": "21c7fc976349d39188b3d239b3b86ab66daeafc2", + "fromAddress": "NQ32 473Y R5T3 979R 325K S8UT 7E3A NRNS VBX2", + "to": "8b12a9a5a81bf52a9afb47a16b57d4c81c51fc07", + "toAddress": "NQ94 HC9A K9D8 3FSJ M6PT 8XGN NMXL R0E5 3Y07", + "value": 42839, + "fee": 138, + "data": null, + "flags": 0 + }, + { + "hash": "c3c6e87cba620095a2aeb9898f07077d184e20a68f53798032857cc842dfb0c0", + "blockHash": "9b51f58b8ca881e2b182e1f544d09e4f1fe265b0f478fd41bf0128099013abd8", + "blockNumber": 354736, + "timestamp": 1545080725, + "confirmations": 664677, + "from": "e9a799c4fce6198cfb2eaacdeda5231078227d62", + "fromAddress": "NQ61 V6KR KH7U UQCQ RXRE MB6X T993 21U2 4YB2", + "to": "8b12a9a5a81bf52a9afb47a16b57d4c81c51fc07", + "toAddress": "NQ94 HC9A K9D8 3FSJ M6PT 8XGN NMXL R0E5 3Y07", + "value": 99808, + "fee": 192, + "data": "3c7363726970743e64656275676765723b3c2f7363726970743e", + "flags": 0 + } + ], + "id": "getTransactionsByAddress" + } + `); + } + // fallback + return {error: "wrong data"}; + } else { + // fallback + return {error: "wrong method"}; + } + } +}; diff --git a/mock/ext-api-dyson/post/vechain-api-logs.js b/mock/ext-api-dyson/post/vechain-api-logs.js new file mode 100644 index 000000000..95987d08c --- /dev/null +++ b/mock/ext-api-dyson/post/vechain-api-logs.js @@ -0,0 +1,51 @@ +/// Vechain RPC API Mock +/// See: +/// curl -H "Content-Type: application/json" -d '{"options": {"offset": 0, "limit": 15 }, "criteriaSet": [{"sender": "0xB5e883349e68aB59307d1604555AC890fAC47128"},{"recipient": "0xB5e883349e68aB59307d1604555AC890fAC47128"}], "range": {"unit": "block", "from": 0, "to": 5466405 }, "order": "desc"}' https://vethor-pubnode.digonchain.com/logs/transfer +/// curl -H "Content-Type: application/json" -d '{"options": {"offset": 0, "limit": 15 }, "criteriaSet": [{"sender": "0xB5e883349e68aB59307d1604555AC890fAC47128"},{"recipient": "0xB5e883349e68aB59307d1604555AC890fAC47128"}], "range": {"unit": "block", "from": 0, "to": 5466405 }, "order": "desc"}' http://localhost:3000/vechain-api/logs/transfer +/// curl "http://localhost:8420/v1/vechain/0xB5e883349e68aB59307d1604555AC890fAC47128" + +module.exports = { + path: '/vechain-api/logs/:entity', + template: function(params, query, body) { + //console.log(params); + //console.log(body); + if (params.entity === 'transfer') { + // TODO check sender/recipient + if (body["criteriaSet"][0]["sender"] === '0xB5e883349e68aB59307d1604555AC890fAC47128' || + body["criteriaSet"][1]["recipient"] === '0xB5e883349e68aB59307d1604555AC890fAC47128') { + return JSON.parse(` + [ + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", + "amount": "0x12b1815d00738000", + "meta": { + "blockID": "0x004313a4bd4286e821b684cc1749deb3df12fa2a8114435fbd35baa155e82016", + "blockNumber": 4395940, + "blockTimestamp": 1574410670, + "txID": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0x00bae5ed35736e4ef17af1be0c6f50e0fb73d685", + "amount": "0x38f6ea18e810b6f00", + "meta": { + "blockID": "0x0042249bee56223e0ed7a9c7fcfffe8e61b9fd95d29d24843c558ff2c46ea094", + "blockNumber": 4334747, + "blockTimestamp": 1573795570, + "txID": "0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + } + ] + `); + } + } + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/platform/nimiq/base.go b/platform/nimiq/base.go index 0772b8534..855490a7e 100644 --- a/platform/nimiq/base.go +++ b/platform/nimiq/base.go @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{blockatlas.InitJSONClient(api)}, } } diff --git a/platform/polkadot/base.go b/platform/polkadot/base.go index 65d5357ed..1aa284b27 100644 --- a/platform/polkadot/base.go +++ b/platform/polkadot/base.go @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{blockatlas.InitClient(api)}, + client: Client{blockatlas.InitJSONClient(api)}, } } diff --git a/platform/vechain/base.go b/platform/vechain/base.go index 3b5dfa4bb..19c7d3070 100644 --- a/platform/vechain/base.go +++ b/platform/vechain/base.go @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{blockatlas.InitJSONClient(api)}, } } diff --git a/tests/functional/fixtures.go b/tests/functional/fixtures.go deleted file mode 100644 index 89b90e2b3..000000000 --- a/tests/functional/fixtures.go +++ /dev/null @@ -1,111 +0,0 @@ -// +build functional - -package functional - -import ( - "encoding/json" - "fmt" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/logger" - "io/ioutil" - "path/filepath" - "strings" -) - -const ( - fixturesFolder = "testdata" // Folder contains the JSON fixtures - bodyFixturesFile = "body_fixtures.json" // Body fixtures for POST requests - coinFixturesFile = "coin_fixtures.json" // Coin fixtures for path parameters - queryFixturesFile = "query_fixtures.json" // Query string for GET requests - excludeApisFile = "exclude.json" // API's need to be excluded from functional tests -) - -type BodyFixture map[string][]interface{} -type CoinFixture map[string]map[string]string -type QueryFixture map[string][]string -type ExcludeApis []string - -var bodyFixture BodyFixture -var coinFixture CoinFixture -var queryFixture QueryFixture -var excludeApis ExcludeApis - -func init() { - geFixtures(bodyFixturesFile, &bodyFixture) - geFixtures(coinFixturesFile, &coinFixture) - geFixtures(queryFixturesFile, &queryFixture) - geFixtures(excludeApisFile, &excludeApis) -} - -func geFixtures(f string, r interface{}) { - b, err := getFile(f) - if err != nil { - logger.Panic(err) - } - err = json.Unmarshal(b[:], &r) - if err != nil { - logger.Panic(err) - } -} - -func isExcluded(path string) bool { - return contains(excludeApis, path) -} - -func getFile(file string) ([]byte, error) { - golden := filepath.Join(fixturesFolder, file) - return ioutil.ReadFile(golden) -} - -func getCoin(path string) coin.Coin { - for _, c := range coin.Coins { - if strings.Contains(path, fmt.Sprintf("/%s/", c.Handle)) { - return c - } - } - return coin.Coin{} -} - -func getBodyTests(path string) []interface{} { - fix, ok := bodyFixture[path] - if !ok { - return []interface{}{nil} - } - return fix -} - -func getQueryTests(path string) []string { - fix, ok := queryFixture[path] - if !ok { - return []string{""} - } - return fix -} - -func addCoinFixtures(path string) string { - c := getCoin(path) - if (c == coin.Coin{}) { - return path - } - fix, ok := coinFixture[c.Handle] - if !ok { - return strings.Replace(path, ":address", c.SampleAddr, -1) - } - if _, ok := fix["address"]; !ok { - return strings.Replace(path, ":address", c.SampleAddr, -1) - } - result := path - for key, value := range fix { - result = strings.Replace(result, ":"+key, value, -1) - } - return result -} - -func contains(s []string, e string) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} diff --git a/tests/functional/functional_test.go b/tests/functional/functional_test.go deleted file mode 100755 index 9d2efb4c7..000000000 --- a/tests/functional/functional_test.go +++ /dev/null @@ -1,89 +0,0 @@ -// +build functional - -package functional - -import ( - "context" - "github.com/getsentry/sentry-go/gin" - "github.com/gin-gonic/gin" - "github.com/spf13/viper" - "github.com/swaggo/gin-swagger" - "github.com/swaggo/gin-swagger/swaggerFiles" - "github.com/trustwallet/blockatlas/api" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "net/http" - "os" - "os/signal" - "sync" - "syscall" - "testing" - "time" - - "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform" -) - -func TestApis(t *testing.T) { - _ = os.Setenv("ATLAS_GIN_MODE", "debug") - config.LoadConfig(os.Getenv("TEST_CONFIG")) - - logger.InitLogger() - platform.Init(viper.GetString("platform")) - - sg := sentrygin.New(sentrygin.Options{}) - p := ":8420" - - engine := gin.New() - - engine.Use(gin.Recovery()) - - engine.Use(ginutils.CheckReverseProxy, sg) - engine.Use(ginutils.CORSMiddleware()) - - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) - - engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - - api.SetupPlatformAPI(engine) - - signalForExit := make(chan os.Signal, 1) - - signal.Notify(signalForExit, - syscall.SIGHUP, - syscall.SIGINT, - syscall.SIGTERM, - syscall.SIGQUIT) - - srv := &http.Server{ - Addr: ":8420", - Handler: engine, - } - - go func() { - if err := srv.ListenAndServe(); err != nil { - logger.Info("Application failed", err) - } - }() - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - defer func() { - if err := srv.Shutdown(ctx); err != nil { - logger.Info("Server Shutdown: ", err) - } - }() - - time.Sleep(time.Second * 2) - - var wg sync.WaitGroup - cl := newClient(t, p) - for _, r := range engine.Routes() { - wg.Add(1) - t.Run(r.Path, func(t *testing.T) { - go cl.doTests(r.Method, r.Path, &wg) - }) - } - wg.Wait() -} diff --git a/tests/functional/http.go b/tests/functional/http.go deleted file mode 100644 index b77093480..000000000 --- a/tests/functional/http.go +++ /dev/null @@ -1,104 +0,0 @@ -// +build functional - -package functional - -import ( - "encoding/json" - "fmt" - "github.com/Pantani/httpexpect" - "github.com/trustwallet/blockatlas/pkg/logger" - "net/http" - "sync" - "testing" - "time" -) - -const ( - baseUrl = "http://localhost%s" -) - -type Client struct { - baseUrl string - e *httpexpect.Expect - t *testing.T -} - -func newClient(t *testing.T, port string) *Client { - client := httpexpect.WithConfig(httpexpect.Config{ - BaseURL: getBaseUrl(port), - Client: &http.Client{ - Jar: httpexpect.NewJar(), - Timeout: time.Second * 30, - }, - // use fatal failures - Reporter: httpexpect.NewAssertReporter(t), - // use verbose logging - Printers: []httpexpect.Printer{}, - }) - return &Client{ - baseUrl: getBaseUrl(port), - e: client, - t: t, - } -} - -func (c *Client) testGet(route string, query string) { - request := c.e.GET(route).WithURL(c.baseUrl) - request.WithQueryString(query) - response := request.Expect() - - if response == nil || response.Raw() == nil { - logger.Error("Invalid response", logger.Params{"response": response, "route": route, "query": query}) - return - } - if response.Raw().StatusCode != http.StatusOK { - logger.Error("Invalid status code", logger.Params{"code": response.Raw().Status, "route": route, "query": query}) - } - response.Status(http.StatusOK) -} - -func (c *Client) testPost(route string, body interface{}) { - request := c.e.POST(route).WithURL(c.baseUrl) - if body == nil { - request.WithText("[]") - } else { - b, err := json.Marshal(body) - if err == nil && b != nil { - request.WithText(string(b)) - } - } - response := request.Expect() - if response == nil || response.Raw() == nil { - logger.Error("Invalid response", logger.Params{"code": response.Raw().Status, "route": route}) - return - } - if response.Raw().StatusCode != http.StatusOK { - bodyJson, _ := json.Marshal(body) - logger.Error("Invalid status code", logger.Params{"code": response.Raw().Status, "route": route, "body": bodyJson}) - } - response.Status(http.StatusOK) -} - -func (c *Client) doTests(method, path string, wg *sync.WaitGroup) { - defer wg.Done() - if isExcluded(path) { - return - } - url := addCoinFixtures(path) - switch method { - case "GET": - tests := getQueryTests(path) - for _, query := range tests { - c.testGet(url, query) - } - case "POST": - tests := getBodyTests(path) - for _, body := range tests { - c.testPost(url, body) - } - } -} - -func getBaseUrl(port string) string { - return fmt.Sprintf(baseUrl, port) -} diff --git a/tests/functional/testdata/body_fixtures.json b/tests/functional/testdata/body_fixtures.json deleted file mode 100644 index e99f8dc65..000000000 --- a/tests/functional/testdata/body_fixtures.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "/v2/staking/delegations": [ - [ - { - "coin": 1729, - "address": "tz1eDhCa5PCkomAabH6PG4xdMoNTWKGyBpo1" - } - ] - ], - "/v2/collectibles/categories": [ - { - "60": [ - "0xb3624367b1ab37daef42e1a3a2ced012359659b0" - ] - }, - { - "60": [ - "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" - ] - } - ], - "/v3/collectibles/categories": [ - { - "60": [ - "0xb3624367b1ab37daef42e1a3a2ced012359659b0" - ] - }, - { - "60": [ - "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" - ] - } - ], - "/v4/collectibles/categories": [ - { - "60": [ - "0xb3624367b1ab37daef42e1a3a2ced012359659b0" - ] - }, - { - "60": [ - "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" - ] - } - ] -} - diff --git a/tests/functional/testdata/coin_fixtures.json b/tests/functional/testdata/coin_fixtures.json deleted file mode 100644 index 9563ed5d8..000000000 --- a/tests/functional/testdata/coin_fixtures.json +++ /dev/null @@ -1,162 +0,0 @@ -{ - "bitcoin": { - "address": "bc1quvuarfksewfeuevuc6tn0kfyptgjvwsvrprk9d", - "key": "xpub6CUGRUonZSQ4TWtTMmzXdrXDtypWKiKrhko4egpiMZbpiaQL2jkwSB1icqYh2cfDfVxdx4df189oLKnC5fSwqPfgyP3hooxujYzAu3fDVmz" - }, - "litecoin": { - "address": "ltc1qhd8fxxp2dx3vsmpac43z6ev0kllm4n53t5sk0u", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "bitcoincash": { - "address": "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "viacoin": { - "address": "via1qnmsgjd6cvfprnszdgmyg9kewtjfgqflz67wwhc", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "zcash": { - "address": "t1YYnByMzdGhQv3W3rnjHMrJs6HH4Y231gy", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "zelcash": { - "address": "t1UKbRPzL4WN8Rs8aZ8RNiWoD2ftCMHKGUf", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "zilliqa": { - "address": "zil1anrjcsj2ntklaa3arq4w3s6gw4l4hqrycs9egy", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "dash": { - "address": "XqHiz8EXYbTAtBEYs4pWTHh7ipEDQcNQeT", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "decred": { - "address": "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "doge": { - "address": "DJRFZNg8jkUtjcpo2zJd92FUAzwRjitw6f", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "ravencoin": { - "address": "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "zcoin": { - "address": "aEd5XFChyXobvEics2ppAqgK3Bgusjxtik", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "groestlcoin": { - "address": "grs1qexwmshts5pdpeqglkl39zyl6693tmfwp0cue4j", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "qtum": { - "address": "QhceuaTdeCZtcxmVc6yyEDEJ7Riu5gWFoF", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "digibyte": { - "address": "D8NBg12kfW8uLjzCv7LYnPYCNhqvVtHaMQ", - "key": "xprv9s21ZrQH143K277qXR6NRni1DS7qmSNBs96NmnF5VGdcejgrJtBHzRJYZxqDJZKX1pF5i6gmmDmWDbBCs4DcQ9T1bH65UttBRw2uMaNJnNQ" - }, - "tomochain": { - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "owner": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collections": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collection_id": "0xfaafdc07907ff5120a76b34b731b278c38d6043c" - }, - "ethereum": { - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "owner": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collections": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collection_id": "ens" - }, - "classic": { - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "owner": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collections": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collection_id": "0xfaafdc07907ff5120a76b34b731b278c38d6043c" - }, - "poa": { - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "owner": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collections": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collection_id": "0xfaafdc07907ff5120a76b34b731b278c38d6043c" - }, - "thundertoken": { - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "owner": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collections": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collection_id": "0xfaafdc07907ff5120a76b34b731b278c38d6043c" - }, - "callisto": { - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "owner": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collections": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collection_id": "0xfaafdc07907ff5120a76b34b731b278c38d6043c" - }, - "gochain": { - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "owner": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collections": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "collection_id": "0xfaafdc07907ff5120a76b34b731b278c38d6043c" - }, - "theta": { - "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f" - }, - "binance": { - "address": "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" - }, - "tezos": { - "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" - }, - "tron": { - "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" - }, - "vechain": { - "address": "0xB5e883349e68aB59307d1604555AC890fAC47128" - }, - "ripple": { - "address": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" - }, - "cosmos": { - "address": "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl" - }, - "iotex": { - "address": "io154mvzs09vkgn0hw6gg3ayzw5w39jzp47f8py9v" - }, - "icon": { - "address": "hxee691e7bccc4eb11fee922896e9f51490e62b12e" - }, - "stellar": { - "address": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" - }, - "nimiq": { - "address": "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07" - }, - "nebulas": { - "address": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a" - }, - "aeternity": { - "address": "ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw" - }, - "aion": { - "address": "0000000000000000000000000000000000000000000000000000000000000000" - }, - "fio": { - "address": "FIO5J2xdfWygeNdHZNZRzRws8YGbVxjUXtp4eP8KoGkGKoLFQ7CaU" - }, - "kin": { - "address": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH" - }, - "ontology": { - "address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7" - }, - "waves": { - "address": "3P7wz6TXienpw3BHe8eHUEuZWb6WE58kgnQ" - }, - "harmony": { - "address": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv" - } -} - diff --git a/tests/functional/testdata/exclude.json b/tests/functional/testdata/exclude.json deleted file mode 100644 index 714327013..000000000 --- a/tests/functional/testdata/exclude.json +++ /dev/null @@ -1,45 +0,0 @@ -[ - "/swagger/*any", - "/v1/fio/:address", - "/v2/fio/transactions/:address", - "/v1/iotex/:address", - "/v1/aeternity/:address", - "/v1/ethereum/:address", - "/v2/aeternity/transactions/:address", - "/v2/collectibles/categories", - "/v3/collectibles/categories", - "/v2/classic/collections/:owner", - "/v2/callisto/collections/:owner", - "/v2/poa/collections/:owner", - "/v2/thundertoken/collections/:owner", - "/v2/tomochain/collections/:owner", - "/v2/gochain/collections/:owner", - "/v2/ethereum/collections/:owner", - "/v2/kava/staking/validators/:address", - "/v2/cosmos/staking/validators/:address", - "/v2/cosmos/staking/delegations/:address", - "/v2/iotex/transactions/:address", - "/v2/iotex/staking/validators", - "/v2/iotex/staking/delegations/:address", - "/v2/classic/collections/:owner/collection/:collection_id", - "/v2/callisto/collections/:owner/collection/:collection_id", - "/v2/poa/collections/:owner/collection/:collection_id", - "/v2/thundertoken/collections/:owner/collection/:collection_id", - "/v2/tomochain/collections/:owner/collection/:collection_id", - "/v2/gochain/collections/:owner/collection/:collection_id", - "/v2/ethereum/collections/:owner/collection/:collection_id", - "/v3/ethereum/collections/:owner/collection/:collection_id", - "/v4/ethereum/collections/:owner/collection/:collection_id", - "/v3/classic/collections/:owner", - "/v3/callisto/collections/:owner", - "/v3/poa/collections/:owner", - "/v3/thundertoken/collections/:owner", - "/v3/tomochain/collections/:owner", - "/v3/gochain/collections/:owner", - "/v3/classic/collections/:owner/collection/:collection_id", - "/v3/callisto/collections/:owner/collection/:collection_id", - "/v3/poa/collections/:owner/collection/:collection_id", - "/v3/thundertoken/collections/:owner/collection/:collection_id", - "/v3/tomochain/collections/:owner/collection/:collection_id", - "/v3/gochain/collections/:owner/collection/:collection_id" -] diff --git a/tests/functional/testdata/query_fixtures.json b/tests/functional/testdata/query_fixtures.json deleted file mode 100644 index 0e73c21d2..000000000 --- a/tests/functional/testdata/query_fixtures.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "/ns/lookup": [ - "name=vitalik.eth&coin=60", - "name=vitalik.luxe&coin=60", - "name=ourxyzwallet.xyz&coin=60", - "name=btc.zil&coin=313", - "name=btc.crypto&coin=313" - ], - "/v2/ns/lookup": [ - "name=vitalik.eth&coins=60", - "name=vitalik.luxe&coins=60", - "name=ourxyzwallet.xyz&coins=60", - "name=btc.zil&coins=313", - "name=btc.crypto&coins=313" - ], - "/v1/market/charts": [ - "currency=USD&time_start=1574483028&coin=60&token=0xdAC17F958D2ee523a2206206994597C13D831ec7", - "currency=EUR&time_start=1574483028&coin=60&token=0xdAC17F958D2ee523a2206206994597C13D831ec7", - "currency=USD&time_start=1574483028&coin=0", - "currency=USD&time_start=1574483028&coin=60" - ], - "/v1/market/info": [ - "currency=USD&coin=60&token=0xdAC17F958D2ee523a2206206994597C13D831ec7", - "currency=EUR&coin=60&token=0xdAC17F958D2ee523a2206206994597C13D831ec7", - "currency=USD&coin=0", - "currency=USD&coin=60" - ] -} diff --git a/tests/postman/Blockatlas.postman_collection.json b/tests/postman/Blockatlas.postman_collection.json index 78ee0f3c4..43860435a 100644 --- a/tests/postman/Blockatlas.postman_collection.json +++ b/tests/postman/Blockatlas.postman_collection.json @@ -91,9 +91,16 @@ "", "let handler = pm.variables.get(\"handler\");", "let address = pm.variables.get(\"address\");", + "let expectedTxNum = pm.variables.get(\"expectedTxNum\") || 1;", "let expectedTxId = pm.variables.get(\"expectedTxId\");", "var jsonData = pm.response.json();", "", + "// IMPORTANT Note on verification -- to serve mocked AND non-mocked tests:", + "// - if number of returned TXs is:", + "// -- less then expectedTxNum or zero --> Fail", + "// -- equals expectedTxNum, and expectedTxId is set, expectedTxId MUST be present in result", + "// -- greater than expectedTxNum (likely non-mocked), expectedTxId is NOT checked", + "", "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", " pm.response.to.have.status(200);", " pm.response.to.be.ok;", @@ -103,22 +110,27 @@ "});", "", "pm.test(handler + \" - verify has docs content: \" + address, function() {", - " pm.expect(jsonData.total).to.be.above(0);", + " pm.expect(jsonData.total).to.be.above(expectedTxNum - 1);", "});", "", "pm.test(handler + \" - schema is valid: \" + address, function() {", " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", "});", "", - "// verify transaction ID in result (only if expected id is present) ", - "if (expectedTxId && expectedTxId.length > 0) {", - " var transactionIdFound = false;", - " for (var d in jsonData.docs) {", - " if (jsonData.docs[d].id === expectedTxId) { transactionIdFound = true; }", + "// verify transaction ID in result (only if number of TXs matches and expected id is present) ", + "if (jsonData.total && jsonData.total == expectedTxNum) {", + " if (expectedTxId && expectedTxId.length > 0) {", + " var transactionIdFound = false;", + " for (var d in jsonData.docs) {", + " if (jsonData.docs[d].id === expectedTxId) { transactionIdFound = true; }", + " }", + " pm.test(handler + \" - verify expected txId: \" + expectedTxId, function() {", + " pm.expect(transactionIdFound).to.be.true;", + " });", " }", - " pm.test(handler + \" - verify expected txId: \" + expectedTxId, function() {", - " pm.expect(transactionIdFound).to.be.true;", - " });", + "} else if (jsonData.total && jsonData.total > expectedTxNum) {", + " // more TXs returned, likely real case, not checking TxId", + " console.log('More TXs returned, not checking TxId', jsonData.total, expectedTxNum);", "}", "" ], @@ -2600,4 +2612,4 @@ } ], "protocolProfileBehavior": {} -} \ No newline at end of file +} diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index e8c49264b..c18d45814 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -2,291 +2,349 @@ { "handler": "harmony", "address": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", + "expectedTxNum": 3, "expectedTxId": "0x73355f625d0f7ef31512657c0f669e710c8c91a67180cd28bc919cfca0a2af82" }, { "handler": "nano", "address": "nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z", + "expectedTxNum": 3, "expectedTxId": "05A23A254272028F349BB7E74115A5101B2048786A5437D1EBBE8807CEFF1E82" }, { "handler": "algorand", "address": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", + "expectedTxNum": 1, "expectedTxId": "JZTKP6RRFGUDOZ7DQIR26DQWRDYZVYG2G3WDE4WLBJ77AMAEBFBA" }, { "handler": "kusama", "address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", + "expectedTxNum": 3, "expectedTxId": "0x9908579abffb409aef95394128f9097f0a21cfdf16675588423e31ab0d3c58e2" }, { "handler": "kava", "address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", + "expectedTxNum": 2, "expectedTxId": "30EFE9E830D317F84629F9DC35177577DF6713D78D354C2C469DE633900303BC" }, { "handler": "zilliqa", "address": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", + "expectedTxNum": 2, "expectedTxId": "0xa5d0e0cefd6f114e9659f15016f9f4a303a8367eb373beb6909ee44f7f39834d" }, { "handler": "tomochain", "address": "0x17e4c16605e32adead5fa371bf6117df34ca0200", - "expectedTxId": "" + "expectedTxNum": 2, + "expectedTxId": "0xb2af5ad5eebaba1da3452e0281f9b6ec9e00a5bb832793a912eb3959b6c2fdd2" }, { "handler": "ethereum", "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "expectedTxNum": 2, "expectedTxId": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47" }, { "handler": "classic", "address": "0x7d2d0e153026fb428b885d86de50768d4cfeac37", + "expectedTxNum": 2, "expectedTxId": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe" }, { "handler": "poa", "address": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "expectedTxNum": 4, "expectedTxId": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3" }, { "handler": "thundertoken", "address": "0x0b230def08139f18a86536d9cfa150f04435414c", - "expectedTxId": "" + "expectedTxNum": 2, + "expectedTxId": "0x80929a2170969364e06d253d2b853fe0b2ca3a307e61d629946b9b76e2f983cf" }, { "handler": "callisto", "address": "0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7", - "expectedTxId": "" + "expectedTxNum": 2, + "expectedTxId": "0x4052f55ee615a783abaa22a62100a45d2eee27ecab3a599e9d6691371336463e" }, { "handler": "gochain", "address": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", - "expectedTxId": "" + "expectedTxNum": 2, + "expectedTxId": "0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7" }, { "handler": "theta", "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "expectedTxNum": 2, "expectedTxId": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78" }, { "handler": "binance", "address": "bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd", + "expectedTxNum": 1, "expectedTxId": "DDA939C475755B2A00123CDA37A5EC442F502EA2983014D04F647C3CB9FB57A0" }, { "handler": "tezos", "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", + "expectedTxNum": 1, "expectedTxId": "ooLrNAP233Qvoz3AGvjRjhk1fjG7z19UfyLEGBm1rwfHn4NSVhd" }, { "handler": "tron", "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB", + "expectedTxNum": 1, "expectedTxId": "3ef5e225ce5bdd01333286e4ab4413ae3da8b80c24b26c5811ae78962940a8ca" }, { "handler": "vechain", "address": "0xB5e883349e68aB59307d1604555AC890fAC47128", + "expectedTxNum": 2, "expectedTxId": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7" }, { "handler": "ripple", "address": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "expectedTxNum": 2, "expectedTxId": "000BC2AFC047BE45C43886109720F44B6F3F2434D59B1A16A9B2B4FC9B9C5A13" }, { "handler": "cosmos", "address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "expectedTxNum": 2, "expectedTxId": "93E43518BAE4BC137605BBB7FD5D31FDAE6427ECE57EC299C43CE786FDAEBC63" }, { "handler": "iotex", "address": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5", - "expectedTxId": "8f40e5e4c9fb4e8e29505a8d0db6428f3d372109c1a96c807d120ae9fe84ff9e" + "expectedTxNum": 1, + "expectedTxId": "7aceeda86535b8dd345e1ab2176a7f12e1907aac3591cf9422a5393feadb6bb6" }, { "handler": "icon", "address": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", + "expectedTxNum": 3, "expectedTxId": "0x3b1a382884091e683350d6285d908406c149a030a7d52eb347f4571c1c904382" }, { "handler": "stellar", "address": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "expectedTxNum": 2, "expectedTxId": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029" }, { "handler": "nimiq", "address": "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", + "expectedTxNum": 2, "expectedTxId": "8674d985ac1ea2a75fe9b35ed11d629cef8adfed50db6a5eb125351e622bb405" }, { "handler": "nebulas", "address": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "expectedTxNum": 1, "expectedTxId": "0d06074b64c37ed24a17162d1e0ef8a8e65122fc7758c90c969e61735bc4396a" }, { "handler": "aeternity", "address": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "expectedTxNum": 2, "expectedTxId": "th_WfeoRYXd13MMmDBzMXjBBdaNSSaRXkwUwJ7tFxJ7ZKPQVNXC4" }, { "handler": "aion", "address": "0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed", + "expectedTxNum": 2, "expectedTxId": "0x511d3a4aafbdd26825a1655b5c7525df5bea8a8ef0f887d5490b490055b53df7" }, { "handler": "kin", "address": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", - "expectedTxId": "847bdd7cfef3fdf2683e846c37d8f8f3f611095e31042f4f7ad48094eab53992" + "expectedTxNum": 2, + "expectedTxId": "b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a" }, { "handler": "ontology", "address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "expectedTxNum": 1, "expectedTxId": "0ae15301f25a5067c075a25e722f0624a813a1352363197de2dd5f61ebd2998d" }, { "handler": "waves", "address": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "expectedTxNum": 2, "expectedTxId": "23JGFzBh65fzZArK6KSeRqjjBG5WnQshJJkUv53hCE1E" }, { "handler": "digibyte", "address": "address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi", + "expectedTxNum": 3, "expectedTxId": "d7efaffeded550697d7385d3eb07e539237615792b29e3639df427ce919c8d6e" }, { "handler": "digibyte", "address": "xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow", + "expectedTxNum": 2, "expectedTxId": "e13c81f4450e43ef8ef10dea8f4f9d53f357266563462df32a7fd61eb71bd190" }, { "handler": "doge", "address": "address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh", + "expectedTxNum": 2, "expectedTxId": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9" }, { "handler": "doge", "address": "xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN", + "expectedTxNum": 2, "expectedTxId": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9" }, { "handler": "decred", "address": "address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", + "expectedTxNum": 2, "expectedTxId": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0" }, { "handler": "decred", "address": "xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN", + "expectedTxNum": 2, "expectedTxId": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0" }, { "handler": "zelcash", "address": "address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa", - "expectedTxId": "" + "expectedTxNum": 3, + "expectedTxId": "ca8b3fa115c5eae0f056d9b629680c521f4d9d271abbe86d4c482c54117e15a1" }, { "handler": "zelcash", "address": "xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf", + "expectedTxNum": 4, "expectedTxId": "2de19629bbf78af114ff9cf3332229dc336be4758481b72828f1bd786e8cc41e" }, { "handler": "zcoin", "address": "address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn", + "expectedTxNum": 5, "expectedTxId": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef" }, { "handler": "zcoin", "address": "xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK", + "expectedTxNum": 8, "expectedTxId": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef" }, { "handler": "zcash", "address": "address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX", - "expectedTxId": "415888d61d605843fa4e846a84350c46703d6dd75446573770959d3eed71233d" + "expectedTxNum": 2, + "expectedTxId": "d504755667e0fb61543e16d09aff5f84733f500190a07acb4a6784b4dc4c99e7" }, { "handler": "zcash", "address": "xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS", + "expectedTxNum": 2, "expectedTxId": "f2438a93039faf08d39bd3df1f7b5f19a2c29ffe8753127e2956ab4461adab35" }, { "handler": "bitcoin", "address": "address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj", + "expectedTxNum": 2, "expectedTxId": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4" }, { "handler": "bitcoin", "address": "xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", + "expectedTxNum": 3, "expectedTxId": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4" }, { "handler": "bitcoincash", "address": "address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme", + "expectedTxNum": 2, "expectedTxId": "0284cb9b8deb0534efa8fc8911db1e8f9b106d00608c712d31c3680f303fbf36" }, { "handler": "bitcoincash", "address": "xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX", + "expectedTxNum": 3, "expectedTxId": "269d428f01fbe49cd6d2c2ca5e6e2f0ff68aece905313932156078d4341d347a" }, { "handler": "ravencoin", "address": "address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS", - "expectedTxId": "23722d4e47de83f6a7a7f661a7733e4f85205fe733b4aeab1e7eaf9ae975fccc" + "expectedTxNum": 2, + "expectedTxId": "fc6c9e9c6cd0253f05e43a12d64154a689115f0103dc0b64957a8cb92b67f306" }, { "handler": "ravencoin", "address": "xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B", + "expectedTxNum": 3, "expectedTxId": "5d22e5a84b0eb054b623fdc3caf88a60eaa646dc97922f06d325aa8d6f18c564" }, { "handler": "viacoin", "address": "address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A", - "expectedTxId": "45f94473bf1bfda2c47cea9c38238ce86821c3ac301500a281ff45de1772b32c" + "expectedTxNum": 2, + "expectedTxId": "dadbe1f13dc5ecd1cfb0d8ae139a4e55493eb9ab2c937cb78b67a5d9c1ded7e8" }, { "handler": "viacoin", "address": "xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK", + "expectedTxNum": 1, "expectedTxId": "bdff404da14940abd84f7cb741fe8f77ad5de5aefbb74254caee683fe2a9b540" }, { "handler": "litecoin", "address": "address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept", + "expectedTxNum": 2, "expectedTxId": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1" }, { "handler": "litecoin", "address": "xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu", + "expectedTxNum": 2, "expectedTxId": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1" }, { "handler": "qtum", "address": "address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", + "expectedTxNum": 2, "expectedTxId": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67" }, { "handler": "qtum", "address": "xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd", + "expectedTxNum": 2, "expectedTxId": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67" }, { "handler": "groestlcoin", "address": "address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj", + "expectedTxNum": 2, "expectedTxId": "2640aa5de0c9603da1c0d9c16b2fd3fa0a17b1472c3aa02559d3ef5e1defceb5" }, { "handler": "groestlcoin", "address": "xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf", + "expectedTxNum": 2, "expectedTxId": "686c651223b937b1223560a60631ad79ad17351c88bba67cad8ea0c95fccbb83" }, { "handler": "dash", "address": "address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG", + "expectedTxNum": 3, "expectedTxId": "f47a4929bcd8767819b6969c83893a76d5b26a145c74ace416ce4c454166186e" }, { "handler": "dash", "address": "xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD", + "expectedTxNum": 2, "expectedTxId": "2b67e2fbe6a212286243bc539cca3c1d877e85ffec7c925e34f2bfb7b6cc498c" } -] \ No newline at end of file +] From 415affc53979c69ca09d6de8babcabfce52539e7 Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Mon, 30 Mar 2020 18:11:26 -0700 Subject: [PATCH 213/506] Replace current Tezos explorer with TxStats (#980) * Remoe extra spacing * Update config * Add Float64toString func * Standardize tests initialization * Adopt client * WIP * Remove redundant test in favore improved unit tests * Pass address needed to determine trx direction * IMprove tests * Update test * Simplify block trx fetching * Adjust test * Fix issue with hardcoded token type for any eth like platform (#983) * Do not use var * Rewrite ErrorMsg to if else * Mocked transaction history tests. (#971) * Base infra for mocked external services, mocked functional tests. New ENS lookup mock. New ETH RPC, lookup mock. Rename mocked->mock. Rearrange newman make targets, to run mocked newman tests. Complete mock for domain tests. Change for codacy false alarms. Change for codacy false alarms 2. Small change to Makefile: build bin before running app Makefile: start/stop dyson. Mocked harmony tx test. Mocked nano tx test. Update README.md [MQ & Cache] Add workers for restore connection (#964) Add NEAR coin definition (#965) Remove unused packages, refactor pkg, run fmt (#967) * Remove unused packages, refactor pkg, run fmt * Fix Makefile Extend postman transaction tests with verification of result txId. Mocked eth tx test. Mocked binance tx test. Small rename. Rename mock script files. Mock path adjustments, script renames. Mocked algorand tx test. Codacy pleasing? Codacy 2. Mocked viacoin tx tests. Remove request only_confirmed transactions (#969) Base infra for mocked external services, mocked functional tests. (#963) * Base infra for mocked external services, mocked functional tests. Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov Co-authored-by: Nick Kozlov Mocked zcash tx tests. Mocked Zilliqa tx tests. EthClassic mocked tx test. Poa mocked tx test. Callisto mocked tx test.Callisto mocked tx test. Adjustments to test data. Test data formatting. Rework TX test TxId check rules, for mocked and non-mocked case. Tomochain mocked tx test. Gochain mocked tx test. Thundertoken mocked tx test. Cosmos and Kava mocked tx tests. Theta mocked tx tests. Ripple mocked tx test. Aion mocked tx test. Tron mocked tx test. Iotex mocked tx test. Icon mocked tx test. Stellar mcked tx test. Nebulas mocked tx test. Aeternity mocked tx test. Kin mocked tx test. Ontology mocked tx test. Waves mocked tx test. Bitcoin mocked tx test. Cleanup configmock.yml. Formatting. Digibyte mocked tx test. doge mocked tx test. decred mocked tx test. Zelcash mocked tx test. Zcoin mocked tx test. Bitcoincash mocked tx test. parent 07d7f68440e1384a6fd7de33691fa52c11e24c2f author Catenocrypt 1585129309 +0100 committer Nick Kozlov 1585509791 +0300 Ravencoin mocked tx test. Litecoin mocked tx test. Qtum mocked tx test. Groestlcoin mocked tx test. Dash mocked tx test. Nimiq mocked tx test. Kusama mocked tx test. Vechain mocked tx test. Tezos mocked tx test. Finalize mocked tx tests, Makefile. Makefile: host param optional; codacy. Fix tfuel direction (#972) * Correct struct name * Add test * Adopt test to direction * Run go-fmt * Fix coins.go Add Initial Solana implementation (#962) * Initial Solana implementation * go fmt * Add public endpoint * Review comments * Update coin/coins.yml Co-Authored-By: hewig <360470+hewigovens@users.noreply.github.com> * Return empty tx list * Add content-type header Co-authored-by: Nick Kozlov Co-authored-by: hewig <360470+hewigovens@users.noreply.github.com> [Observer] Start rewriting observer service: separate service - add observer_parser and observer_notifier (#968) * [Observer] Start rewriting observer service: separate service - add observer_parser and observer_notifier * Continue refactoring, speed up some tests * Add unit tests for all functions that can be tested by unit tests * Add observer_notifier service * Continue refactoring the notifier * Remove unused package * Small cleanup * Test & build fixes * Continue refactoring * Fix Unit test * Run fmt and add storage test for lookup * Update miniredis, refactor FindSubscriptions, * Add storage tests * Update notifier and parser * Add Normal logs for parser * Add Normal logs for parser * Fix tests * Fix tests * Add notifier test * Add notifier test fix * Fix integration tests * [Observer parser] Add graceful shutdown * Setup concurrent publishing (not yet finished) * [Observer parser] Update FetchBlocks and PublishBlocks * [Errors & Parser] Update errors package and FetchBlocks/PublishBlocks * Change queue type to Txs * [Observer parser] Update PublishBlocks * Change queue type to Txs * Fix tests * [MQ & Obserer notifier & Observer subscriber] Add RunConsumerWithCancel, add graceful shutdown to observer notifier and subscriber * [Observer healthcheck] Setup observer healthcheck servcie * Add unit tests for all functions that can be tested by unit tests, change parser.go * Small refactoring * Small change to healthcheck.go * [Observer parser] Add getTxsBatches and test, add rand.Seed to getBlockByNumberWithRetry * Add storage test * [Storage] Update deleteSubscriptions and addSubscriptions * [Observer healthcheck] Add exclude param * Refactoring Parser, MQ, add tests * Add txs batch limit to config.yml * [Observer parser] Update graceful shutdown * Fix integration tests Co-authored-by: Nick Kozlov Co-authored-by: Nick Kozlov [Observer-TX] Fix issue with wrong transaction direction (#976) * [TX] Fix GetTransactionDirection * Add additional types checking for Memo * Add test Co-authored-by: Nick Kozlov Add transaction direction to eth transaction api (#977) remove go-ens / go-ethereum dependency (#973) * remove go-ens / go-ethereum dependency * Fix ens client * move to ens-coincodec * review comments * update fio client Merge master, use new InitJSONClient. Fix make stop (Makefile). Small fix for newman test Remove functional tests and change pipeline More fixes for the pipeline More fixes for the pipeline #2 Fix for 'make stop' (Makefile, observer pid). (#979) * Fix for 'make stop' (Makefile, observer pid). * Fix newman test at Makefile Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov More fixes for the pipeline #3 More fixes for the pipeline #5 More fixes for the pipeline #6 Small fixes of api to pass tests Fix issue with hardcoded token type for any eth like platform (#983) * Fix Waves api mock * Fix Waves api mock attempt 2 Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov * Adjust ErrorMsg func and test * Remoe extra spacing * Update config * Add Float64toString func * Standardize tests initialization * Adopt client * WIP * Remove redundant test in favore improved unit tests * Pass address needed to determine trx direction * IMprove tests * Update test * Simplify block trx fetching * Adjust test * Do not use var * Rewrite ErrorMsg to if else * Adjust ErrorMsg func and test * New Tezos API: Update mocked unit test. * Add test for Float64toString and reuse in binance package * Fix test Co-authored-by: Nick Kozlov Co-authored-by: Adam R <13562139+catenocrypt@users.noreply.github.com> Co-authored-by: Catenocrypt --- README.md | 4 +- config.yml | 3 +- configmock.yml | 1 - .../get/tezos-api-transactions.js | 181 +++++++- pkg/blockatlas/string_test.go | 2 +- pkg/blockatlas/tx.go | 12 +- pkg/blockatlas/tx_test.go | 2 +- pkg/errors/helper_test.go | 4 +- pkg/numbers/number.go | 4 + pkg/numbers/number_test.go | 11 + platform/binance/model.go | 2 +- platform/bitcoin/transaction_test.go | 4 +- platform/ethereum/collection_test.go | 2 +- platform/ontology/transaction_test.go | 2 +- platform/tezos/block.go | 28 +- platform/tezos/client.go | 36 +- platform/tezos/model.go | 143 ++++--- platform/tezos/model_test.go | 172 +++++--- platform/tezos/transaction.go | 78 ++-- platform/tezos/transaction_test.go | 387 ++---------------- platform/theta/transaction_test.go | 4 +- tests/integration/domains/domains.go | 2 +- tests/postman/transaction_data.json | 2 +- 23 files changed, 497 insertions(+), 589 deletions(-) diff --git a/README.md b/README.md index e4897016b..5f7089bd7 100644 --- a/README.md +++ b/README.md @@ -97,10 +97,10 @@ go build -o observer_worker-bin cmd/observer_worker/main.go && ./observer_worker go build -o observer_subscriber-bin cmd/observer_subscriber/main.go && ./observer_subscriber-bin -c config.yml # Start Platform API server at port 8420 with the path to the config.yml ./ -go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 -c config.yml +go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 -c config.yml # Startp Swagger API server at port 8422 with the path to the config.yml ./ -go build -o swagger-api-bin cmd/swagger-api/main.go && ./swagger-api-bin -p 8423 +go build -o swagger-api-bin cmd/swagger-api/main.go && ./swagger-api-bin -p 8423 ``` OR diff --git a/config.yml b/config.yml index 36d6b991c..9456cc02c 100644 --- a/config.yml +++ b/config.yml @@ -59,8 +59,7 @@ kin: # [XTZ] Tezos: https://tezos.com tezos: - stake_api: https://api.tzstats.com/explorer - api: http://api.tezos.id/mooncake/mainnet + api: https://api.tzstats.com/explorer # https://tzstats.com/docs/api/index.html#introduction rpc: https://mainnet.tezos.org.ua # [ETH] Ethereum: https://ethereum.org (Trust-Ray API) diff --git a/configmock.yml b/configmock.yml index 6796417d9..9d6575c7d 100644 --- a/configmock.yml +++ b/configmock.yml @@ -60,7 +60,6 @@ kin: # [XTZ] Tezos: https://tezos.com tezos: - stake_api: https://api.tzstats.com/explorer api: http://localhost:3000/tezos-api rpc: https://mainnet.tezos.org.ua diff --git a/mock/ext-api-dyson/get/tezos-api-transactions.js b/mock/ext-api-dyson/get/tezos-api-transactions.js index 0a63945cf..08093d95a 100644 --- a/mock/ext-api-dyson/get/tezos-api-transactions.js +++ b/mock/ext-api-dyson/get/tezos-api-transactions.js @@ -1,27 +1,180 @@ /// Mock for external Tezos API, transactions /// See -/// curl "http://api.tezos.id/mooncake/mainnet/v1/transactions?account=tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8&n=50&p=0" -/// curl "http://localhost:3000/tezos-api/v1/transactions?account=tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8&n=50&p=0" +/// curl "https://api.tzstats.com/explorer/account/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8/op?limit=25&order=desc&type=transaction%2Cdelegation" +/// curl "http://localhost:3000/tezos-api/account/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8/op?limit=25&order=desc&type=transaction%2Cdelegation" /// curl "http://localhost:8420/v1/tezos/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" module.exports = { - path: '/tezos-api/v1/transactions?', + path: '/tezos-api/account/:account/:op?', template: function(params, query, body) { + //console.log(params) //console.log(query) - if (query.account === 'tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8') { + if (params.account === 'tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8') { return JSON.parse(` - [ - { - "tx": { - "kind": "transaction", - "status": "applied" + { + "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", + "address_type": "ed25519", + "delegate": "", + "manager": "", + "pubkey": "edpkvKiFTVXxttCcDa2N6QfwgsnWHoEQdYRsVfUDBWPXJbhBPQpLVk", + "first_in": 797595, + "first_out": 797612, + "last_in": 797595, + "last_out": 797612, + "first_seen": 797595, + "last_seen": 797612, + "delegated_since": 0, + "delegate_since": 0, + "first_in_time": "2020-01-26T23:49:01Z", + "first_out_time": "2020-01-27T00:06:01Z", + "last_in_time": "2020-01-26T23:49:01Z", + "last_out_time": "2020-01-27T00:06:01Z", + "first_seen_time": "2020-01-26T23:49:01Z", + "last_seen_time": "2020-01-27T00:06:01Z", + "delegated_since_time": "0001-01-01T00:00:00Z", + "delegate_since_time": "0001-01-01T00:00:00Z", + "total_received": 0.01, + "total_sent": 0.007, + "total_burned": 0, + "total_fees_paid": 0.003, + "total_rewards_earned": 0, + "total_fees_earned": 0, + "total_lost": 0, + "frozen_deposits": 0, + "frozen_rewards": 0, + "frozen_fees": 0, + "unclaimed_balance": 0, + "spendable_balance": 0, + "total_balance": 0, + "delegated_balance": 0, + "total_delegations": 0, + "active_delegations": 0, + "is_funded": false, + "is_activated": false, + "is_vesting": false, + "is_spendable": true, + "is_delegatable": false, + "is_delegated": false, + "is_revealed": false, + "is_delegate": false, + "is_active_delegate": false, + "is_contract": false, + "blocks_baked": 0, + "blocks_missed": 0, + "blocks_stolen": 0, + "blocks_endorsed": 0, + "slots_endorsed": 0, + "slots_missed": 0, + "n_ops": 3, + "n_ops_failed": 0, + "n_tx": 2, + "n_delegation": 0, + "n_origination": 0, + "n_proposal": 0, + "n_ballot": 0, + "token_gen_min": 0, + "token_gen_max": 0, + "grace_period": 0, + "staking_balance": 0, + "rolls": 0, + "rich_rank": 0, + "traffic_rank": 0, + "flow_rank": 0, + "last_bake_height": 0, + "last_bake_block": "", + "last_bake_time": "0001-01-01T00:00:00Z", + "last_endorse_height": 0, + "last_endorse_block": "", + "last_endorse_time": "0001-01-01T00:00:00Z", + "next_bake_height": 0, + "next_bake_priority": 0, + "next_bake_time": "0001-01-01T00:00:00Z", + "next_endorse_height": 0, + "next_endorse_time": "0001-01-01T00:00:00Z", + "ops": [ + { + "row_id": 20862164, + "hash": "ooLrNAP233Qvoz3AGvjRjhk1fjG7z19UfyLEGBm1rwfHn4NSVhd", + "type": "transaction", + "block": "BMRy3L1EEkPrmv4UwTUsFNnD3Q25hVB36VyN5Tx5G96vUpfkiR1", + "time": "2020-01-27T00:06:01Z", + "height": 797612, + "cycle": 194, + "counter": 2946274, + "op_n": 50, + "op_l": 3, + "op_p": 2, + "op_c": 1, + "op_i": 0, + "status": "applied", + "is_success": true, + "is_contract": false, + "gas_limit": 10600, + "gas_used": 10209, + "gas_price": 0.14693, + "storage_limit": 257, + "storage_size": 0, + "storage_paid": 0, + "volume": 0.007, + "fee": 0.0015, + "reward": 0, + "deposit": 0, + "burned": 0, + "is_internal": false, + "has_data": false, + "days_destroyed": 0.000083, + "sender": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", + "receiver": "tz1KqtebPYZopqj65E6qPseW2GDGVgUs82wK", + "branch_id": 797612, + "branch_height": 797611, + "branch_depth": 1, + "branch": "BMEPJ9BA41LZKuS9ywVQAvdtV7SHqiKU6vmFsxPSEUzCLZ2pG5D", + "is_implicit": false, + "entrypoint_id": 0 }, - "op": { - "opHash": "ooLrNAP233Qvoz3AGvjRjhk1fjG7z19UfyLEGBm1rwfHn4NSVhd" + { + "row_id": 20861661, + "hash": "op2f6FPSKhzKcN6o2uUNETUrgF4vX8pAEyRJb4k9uPnAFEoJjYq", + "type": "transaction", + "block": "BMJtDFTTaWABiv8ye1qALB5Jss2wQz3CFYjrMVhTX8yBWA8dttt", + "time": "2020-01-26T23:49:01Z", + "height": 797595, + "cycle": 194, + "counter": 2555733, + "op_n": 19, + "op_l": 3, + "op_p": 0, + "op_c": 0, + "op_i": 0, + "status": "applied", + "is_success": true, + "is_contract": false, + "gas_limit": 10307, + "gas_used": 10207, + "gas_price": 0.1258, + "storage_limit": 277, + "storage_size": 0, + "storage_paid": 0, + "volume": 0.01, + "fee": 0.001284, + "reward": 0, + "deposit": 0, + "burned": 0.257, + "is_internal": false, + "has_data": false, + "days_destroyed": 0.019403, + "sender": "tz1VwmmesDxud2BJEyDKUTV5T5VEP8tGBKGD", + "receiver": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", + "branch_id": 797595, + "branch_height": 797594, + "branch_depth": 1, + "branch": "BLcdWDBAN4N38tnsEGMT8vorsKeMgAbCN154AM93eZ348uhZGWy", + "is_implicit": false, + "entrypoint_id": 0 } - } - ] - `) + ] + } + `) } // fallback return {error: "Not implemented"} diff --git a/pkg/blockatlas/string_test.go b/pkg/blockatlas/string_test.go index 77d3f5b1f..babf707a6 100644 --- a/pkg/blockatlas/string_test.go +++ b/pkg/blockatlas/string_test.go @@ -6,7 +6,7 @@ import ( ) func TestGetValidParameter(t *testing.T) { - var tests = []struct { + tests := []struct { first string second string result string diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 09cbc5797..49f435c64 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -56,12 +56,12 @@ const ( type ( // Types of transaction statuses - Direction string - Status string - TokenType string - TransactionType string - KeyType string - KeyTitle string + Direction string + Status string + TokenType string + TransactionType string + KeyType string + KeyTitle string Block struct { Number int64 `json:"number"` diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index d268e0ba8..787e770bc 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -359,7 +359,7 @@ var ( ) func TestInferDirection(t *testing.T) { - var tests = []struct { + tests := []struct { AddressSet mapset.Set Inputs []TxOutput Outputs []TxOutput diff --git a/pkg/errors/helper_test.go b/pkg/errors/helper_test.go index 0be276b72..f9a317513 100644 --- a/pkg/errors/helper_test.go +++ b/pkg/errors/helper_test.go @@ -6,7 +6,7 @@ import ( ) func TestIsType(t *testing.T) { - var tests = []struct { + tests := []struct { error error errorType Type result bool @@ -26,7 +26,7 @@ func TestIsType(t *testing.T) { } func TestEqual(t *testing.T) { - var tests = []struct { + tests := []struct { err1 error err2 error result bool diff --git a/pkg/numbers/number.go b/pkg/numbers/number.go index 916f219af..c36be11b9 100644 --- a/pkg/numbers/number.go +++ b/pkg/numbers/number.go @@ -32,6 +32,10 @@ func Float64toPrecision(num float64, precision int) float64 { return float64(Round(num*output)) / output } +func Float64toString(num float64) string { + return strconv.FormatFloat(num, 'f', -1, 64) +} + func FromDecimal(dec string) string { v, err := DecimalToSatoshis(dec) if err != nil { diff --git a/pkg/numbers/number_test.go b/pkg/numbers/number_test.go index 522f39f17..23d0ce429 100644 --- a/pkg/numbers/number_test.go +++ b/pkg/numbers/number_test.go @@ -54,3 +54,14 @@ func TestFloat64toPrecision(t *testing.T) { assert.Equal(t, Float64toPrecision(26.5, 4), 26.5) assert.Equal(t, Float64toPrecision(3374, 4), 3374.0) } + +func TestFloat64toString(t *testing.T) { + assert.Equal(t, Float64toString(0), "0") + assert.Equal(t, Float64toString(0.0), "0") + assert.Equal(t, Float64toString(0.1), "0.1") + assert.Equal(t, Float64toString(0.1010), "0.101") + assert.Equal(t, Float64toString(0.015), "0.015") + assert.Equal(t, Float64toString(1), "1") + assert.Equal(t, Float64toString(1.1), "1.1") + assert.Equal(t, Float64toString(1.015), "1.015") +} diff --git a/platform/binance/model.go b/platform/binance/model.go index 15df6c3ef..d54d9e5e6 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -104,7 +104,7 @@ func (subTxs *SubTxs) getTxs() (txs []Tx) { if err != nil { subTxValue = 0 } - value := strconv.FormatFloat(txValue+subTxValue, 'f', -1, 64) + value := numbers.Float64toString(txValue+subTxValue) tx.Value = json.Number(value) mapTx[key] = tx } diff --git a/platform/bitcoin/transaction_test.go b/platform/bitcoin/transaction_test.go index fd93c95c7..8a11c33ba 100644 --- a/platform/bitcoin/transaction_test.go +++ b/platform/bitcoin/transaction_test.go @@ -226,7 +226,7 @@ func TestNormalizeTransfer(t *testing.T) { incomingTxSet.Add("t1ZBs9xvRypkjXmci2SS6zbNWVhuWH1h93L") incomingTxSet.Add("t1VZp67AK9zgdXwa35kwYrJ1Mh4NWjUENrM") - var tests = []struct { + tests := []struct { RawTx string Expected blockatlas.Tx AddressSet mapset.Set @@ -270,7 +270,7 @@ func TestNormalizeTransfer(t *testing.T) { } func TestTransactionStatus(t *testing.T) { - var tests = []struct { + tests := []struct { Tx Transaction Expected blockatlas.Status }{ diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/collection_test.go index 1a96c8a15..056743e97 100644 --- a/platform/ethereum/collection_test.go +++ b/platform/ethereum/collection_test.go @@ -225,7 +225,7 @@ var c3 = Collection{ } func TestSearchCollection(t *testing.T) { - var tests = []struct { + tests := []struct { collections []Collection collectibleID string result *Collection diff --git a/platform/ontology/transaction_test.go b/platform/ontology/transaction_test.go index fc318228a..3cc7dbe59 100644 --- a/platform/ontology/transaction_test.go +++ b/platform/ontology/transaction_test.go @@ -164,7 +164,7 @@ var ( ) func TestNormalize(t *testing.T) { - var tests = []struct { + tests := []struct { name string Transaction string AssetName AssetType diff --git a/platform/tezos/block.go b/platform/tezos/block.go index 2a219b5ae..8b5e596a3 100644 --- a/platform/tezos/block.go +++ b/platform/tezos/block.go @@ -3,7 +3,6 @@ package tezos import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" - "sync" ) func (p *Platform) CurrentBlockNumber() (int64, error) { @@ -11,28 +10,13 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { } func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - txTypes := []TxType{TxTransactions, TxDelegations} - var wg sync.WaitGroup - out := make(chan []Transaction, len(txTypes)) - wg.Add(len(txTypes)) - for _, t := range txTypes { - go func(txType TxType, num int64, wg *sync.WaitGroup) { - defer wg.Done() - txs, err := p.client.GetBlockByNumber(num, txType) - if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"txType": txType, "num": num}) - return - } - out <- txs - }(t, num, &wg) + txTypes := []string{TxTypeTransaction, TxTypeDelegation} + srcTxs, err := p.client.GetBlockByNumber(num, txTypes) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"txType": txTypes, "num": num}) + return nil, err } - wg.Wait() - close(out) - srcTxs := make([]Transaction, 0) - for r := range out { - srcTxs = append(srcTxs, r...) - } - txs := NormalizeTxs(srcTxs) + txs := NormalizeTxs(srcTxs, "") return &blockatlas.Block{ Number: num, Txs: txs, diff --git a/platform/tezos/client.go b/platform/tezos/client.go index cacd741e2..d47564454 100644 --- a/platform/tezos/client.go +++ b/platform/tezos/client.go @@ -1,27 +1,41 @@ package tezos import ( - "net/url" - "strconv" - + "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "net/url" + "strings" ) type Client struct { blockatlas.Request } -func (c *Client) GetTxsOfAddress(address string, txType TxType) (txs []Transaction, err error) { - err = c.Get(&txs, "v1/"+string(txType), url.Values{"n": {"50"}, "p": {"0"}, "account": {address}}) +func (c *Client) GetTxsOfAddress(address string, txType []string) (txs ExplorerAccount, err error) { + path := fmt.Sprintf("account/%s/op", address) + err = c.Get(&txs, path, url.Values{ + "order": {"desc"}, + "type": {strings.Join(txType, ",")}, + "limit": {"25"}, + }) return } -func (c *Client) GetCurrentBlock() (height int64, err error) { - err = c.Get(&height, "v1/blocks_num", nil) - return +// Get last indexed block by explorer +func (c *Client) GetCurrentBlock() (int64, error) { + var status Status + err := c.Get(&status, "status", nil) + return status.Indexed, err } -func (c *Client) GetBlockByNumber(num int64, txType TxType) (txs []Transaction, err error) { - err = c.Get(&txs, "v1/"+string(txType), url.Values{"n": {"50"}, "p": {"0"}, "block": {strconv.Itoa(int(num))}}) - return +func (c *Client) GetBlockByNumber(num int64, txType []string) ([]Transaction, error) { + var blockOps ExplorerAccount + path := fmt.Sprintf("account/%d/op", num) + types := strings.Join(txType, ",") + + err := c.Get(&blockOps, path, url.Values{ + "limit": {"5000"}, // https://github.com/blockwatch-cc/tzindex/issues/17#issuecomment-604967761 + "type": {types}, + }) + return blockOps.Transactions, err } diff --git a/platform/tezos/model.go b/platform/tezos/model.go index da720f1f5..970c08ca9 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -1,94 +1,111 @@ package tezos -import "time" - -type TxType string -type TxKind string -type TxStatus string +import ( + "fmt" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "time" +) const ( - TxTransactions TxType = "transactions" - TxDelegations TxType = "delegations" + TxTypeTransaction string = "transaction" + TxTypeDelegation string = "delegation" - TxKindTransaction TxKind = "transaction" - TxKindDelegation TxKind = "delegation" - - TxStatusApplied TxStatus = "applied" - TxStatusSkipped TxStatus = "skipped" + TxStatusApplied string = "applied" ) -type Op struct { - OpHash string `json:"opHash"` - BlockLevel uint64 `json:"blockLevel"` - BlockTimestamp time.Time `json:"blockTimestamp"` +type Account struct { + Balance string `json:"balance"` + Delegate string `json:"delegate"` +} + +type ExplorerAccount struct { + Transactions []Transaction `json:"ops"` } type Transaction struct { - Tx Tx `json:"tx"` - Op Op `json:"op"` - Delegation Delegation `json:"delegation"` + Delegate string `json:"delegate"` // Current delegate (may be self when registered as delegate). + Errors []Error `json:"errors"` // Operation status applied, failed, backtracked, skipped. + Fee float64 `json:"fee"` // Total fee paid (and frozen) by all operations. + Hash string `json:"hash"` // Operation hash. + Height uint64 `json:"height"` + IsSuccess bool `json:"is_success"` // Flag indicating operation was successfully applied. + Receiver string `json:"receiver"` + Sender string `json:"sender"` + Stat string `json:"status"` // Operation status applied, failed, backtracked, skipped. + Time string `json:"time"` // Block time at which the operation was included on-chain e.g: 2019-09-28T13:10:51Z + Type string `json:"type"` // Operation type, one of activate_account, double_baking_evidence, double_endorsement_evidence, seed_nonce_revelation, transaction, origination, delegation, reveal, endorsement, proposals, ballot. + Volume float64 `json:"volume"` } -func (t *Transaction) Status() TxStatus { - if len(t.Tx.Status) > 0 { - return t.Tx.Status - } - return t.Delegation.Status +type Error struct { + ID string `json:"id"` + Kind string `json:"kind"` } -func (t *Transaction) Kind() TxKind { - if len(t.Tx.Kind) > 0 { - return t.Tx.Kind - } - return t.Delegation.Kind +type Status struct { + Indexed int64 `json:"indexed"` } -func (t *Transaction) Source() string { - if len(t.Tx.Source) > 0 { - return t.Tx.Source - } - return t.Delegation.Source +type Validator struct { + Address string `json:"pkh"` } -func (t *Transaction) Destination() string { - if len(t.Tx.Destination) > 0 { - return t.Tx.Destination +func (t *Transaction) Status() blockatlas.Status { + switch t.Stat { + case TxStatusApplied: + return blockatlas.StatusCompleted + default: + return blockatlas.StatusError } - return t.Delegation.Delegate } -func (t *Transaction) Fee() string { - if len(t.Tx.Fee) > 0 { - return t.Tx.Fee +func (t *Transaction) ErrorMsg() string { + if !t.IsSuccess && len(t.Errors) > 0 { + return fmt.Sprintf("%s %s", t.Errors[0].ID, t.Errors[0].Kind) + } else { + return "" } - return t.Delegation.Fee } -type Tx struct { - Destination string `json:"destination"` - Amount string `json:"amount"` - GasLimit string `json:"gasLimit"` - Kind TxKind `json:"kind"` - BlockHash string `json:"blockHash"` - Fee string `json:"fee"` - Source string `json:"source"` - Status TxStatus `json:"operationResultStatus"` +func (t *Transaction) Title() blockatlas.KeyTitle { + if t.Delegate == "" && t.Receiver != "" { + return blockatlas.AnyActionDelegation + } + + if t.Delegate != "" && t.Receiver == "" { + return blockatlas.AnyActionUndelegation + } + + return blockatlas.AnyActionDelegation } -type Delegation struct { - Delegate string `json:"delegate"` - GasLimit string `json:"gasLimit"` - Kind TxKind `json:"kind"` - Status TxStatus `json:"operationResultStatus"` - Fee string `json:"fee"` - Source string `json:"source"` +func (t *Transaction) BlockTimestamp() int64 { + unix := int64(0) + date, err := time.Parse(time.RFC3339, t.Time) + if err == nil { + unix = date.Unix() + } + return unix } -type Validator struct { - Address string `json:"pkh"` +func (t *Transaction) TransferType() blockatlas.TransactionType { + switch t.Type { + case TxTypeTransaction: + return blockatlas.TxTransfer + case TxTypeDelegation: + return blockatlas.TxAnyAction + default: + return "" + } } -type Account struct { - Balance string `json:"balance"` - Delegate string `json:"delegate"` +func (t *Transaction) Direction(address string) blockatlas.Direction { + if t.Sender == address && t.Receiver == address { + return blockatlas.DirectionSelf + } + if t.Sender == address && t.Receiver != address { + return blockatlas.DirectionOutgoing + } + + return blockatlas.DirectionIncoming } diff --git a/platform/tezos/model_test.go b/platform/tezos/model_test.go index a3e95c526..773b11dd5 100644 --- a/platform/tezos/model_test.go +++ b/platform/tezos/model_test.go @@ -2,82 +2,130 @@ package tezos import ( "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" - "time" ) var ( - transaction = Tx{ - Destination: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - Amount: "1751", - GasLimit: "15385", - Kind: TxKindTransaction, - BlockHash: "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", - Fee: "0", - Source: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - Status: TxStatusApplied, + addr1 = "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK" + addr2 = "tz1egbN6RK2bM5vt4aAZw6r9j4nL8z49bPdS" +) + +func TestTransaction_Status(t *testing.T) { + testStatus := []struct { + name string + in Transaction + out blockatlas.Status + }{ + {"Status completed", Transaction{Stat: "applied"}, blockatlas.StatusCompleted}, + {"Status error", Transaction{Stat: "failed"}, blockatlas.StatusError}, + {"Status error", Transaction{Stat: ""}, blockatlas.StatusError}, + {"Status error", Transaction{Stat: "something else"}, blockatlas.StatusError}, } - del = Delegation{ - Delegate: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - GasLimit: "10600", - Kind: TxKindDelegation, - Status: TxStatusApplied, - Fee: "1500", - Source: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", + + for _, tt := range testStatus { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.out, tt.in.Status()) + }) } - op = Op{ - OpHash: "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", - BlockLevel: 788568, - BlockTimestamp: time.Time{}, + + testsError := []struct { + name string + in Transaction + out string + }{ + {"Error present", Transaction{IsSuccess: false, Errors: []Error{{"unchanged", "temporary"}}}, "unchanged temporary"}, + {"Error no", Transaction{IsSuccess: true}, ""}, } -) -func TestTransaction_Status(t *testing.T) { - type fields struct { - Op Op - Tx Tx - Delegation Delegation + for _, tt := range testsError { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.out, tt.in.ErrorMsg()) + }) } - type want struct { - Status TxStatus - Kind TxKind - Source string - Destination string - Fee string + + testsTitle := []struct { + name string + in Transaction + out blockatlas.KeyTitle + }{ + {"Delegation", Transaction{Delegate: "", Receiver: addr1}, blockatlas.AnyActionDelegation}, + {"Undelegation", Transaction{Delegate: addr1, Receiver: ""}, blockatlas.AnyActionUndelegation}, + {"Delegation", Transaction{Delegate: "", Receiver: ""}, blockatlas.AnyActionDelegation}, + {"Delegation", Transaction{Delegate: addr1, Receiver: addr1}, blockatlas.AnyActionDelegation}, } - tests := []struct { - name string - fields fields - want want + + for _, tt := range testsTitle { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.out, tt.in.Title()) + }) + } + + testsBlockTimestamp := []struct { + name string + in Transaction + out int64 }{ - { - "transaction", - fields{op, transaction, Delegation{}}, - want{TxStatusApplied, TxKindTransaction, "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", "0"}, - }, - { - "delegation", - fields{op, Tx{}, del}, - want{TxStatusApplied, TxKindDelegation, "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", "1500"}, - }, - { - "transaction and delegation", - fields{op, transaction, del}, - want{TxStatusApplied, TxKindTransaction, "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", "0"}, - }, + {"Delegation", Transaction{Time: "2020-02-04T12:27:59Z",}, 1580819279}, } - for _, tt := range tests { + + for _, tt := range testsBlockTimestamp { t.Run(tt.name, func(t *testing.T) { - tx := &Transaction{ - Tx: tt.fields.Tx, - Op: tt.fields.Op, - Delegation: tt.fields.Delegation, + assert.Equal(t, tt.out, tt.in.BlockTimestamp()) + }) + } + + testsKind := []struct { + name string + in Transaction + out blockatlas.TransactionType + }{ + {"Type should be transaction", Transaction{Type: "transaction",}, blockatlas.TxTransfer}, + {"Type should be delegation", Transaction{Type: "delegation",}, blockatlas.TxAnyAction}, + {"Type unsupported", Transaction{Type: "bake",}, ""}, + {"Type endorsement", Transaction{Type: "endorsement",}, ""}, + } + + for _, tt := range testsKind { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.out, tt.in.TransferType()) + }) + } + + testsDirection := []struct { + name string + in Transaction + out blockatlas.Direction + address string + }{ + {"Direction self", Transaction{Sender: addr1, Receiver: addr1}, blockatlas.DirectionSelf, addr1}, + {"Direction outgoing", Transaction{Sender: addr1, Receiver: addr2}, blockatlas.DirectionOutgoing, addr1}, + {"Direction incoming", Transaction{Sender: addr2, Receiver: addr1}, blockatlas.DirectionIncoming, addr1}, + } + + for _, tt := range testsDirection { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.out, tt.in.Direction(tt.address)) + }) + } + + testsNormalize := []struct { + name string + in Transaction + out blockatlas.Tx + address string + }{ + {"Normalize XTZ transfer", tezosTransfer, normalizedTezosTransfer, addr1}, + } + + for _, tt := range testsNormalize { + t.Run(tt.name, func(t *testing.T) { + normalized, ok := NormalizeTx(tt.in, tt.address) + if !ok { + assert.False(t, ok, "issue to normalize") } - assert.Equal(t, tt.want.Status, tx.Status()) - assert.Equal(t, tt.want.Kind, tx.Kind()) - assert.Equal(t, tt.want.Source, tx.Source()) - assert.Equal(t, tt.want.Destination, tx.Destination()) - assert.Equal(t, tt.want.Fee, tx.Fee()) + assert.Equal(t, tt.out, normalized) }) } + } diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index d2615e4db..415b77135 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -4,37 +4,23 @@ import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" - "sync" + "github.com/trustwallet/blockatlas/pkg/numbers" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - txTypes := []TxType{TxTransactions} - var wg sync.WaitGroup - out := make(chan []Transaction, len(txTypes)) - wg.Add(len(txTypes)) - for _, t := range txTypes { - go func(txType TxType, addr string, wg *sync.WaitGroup) { - defer wg.Done() - txs, err := p.client.GetTxsOfAddress(address, txType) - if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"txType": txType, "addr": addr}) - return - } - out <- txs - }(t, address, &wg) + txTypes := []string{TxTypeTransaction, TxTypeDelegation} + txs, err := p.client.GetTxsOfAddress(address, txTypes) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"txType": txTypes, "addr": address}) + return nil, err } - wg.Wait() - close(out) - srcTxs := make([]Transaction, 0) - for r := range out { - srcTxs = append(srcTxs, r...) - } - return NormalizeTxs(srcTxs), nil + + return NormalizeTxs(txs.Transactions, address), nil } -func NormalizeTxs(srcTxs []Transaction) (txs []blockatlas.Tx) { +func NormalizeTxs(srcTxs []Transaction, address string) (txs []blockatlas.Tx) { for _, srcTx := range srcTxs { - tx, ok := NormalizeTx(srcTx) + tx, ok := NormalizeTx(srcTx, address) if !ok { continue } @@ -44,42 +30,36 @@ func NormalizeTxs(srcTxs []Transaction) (txs []blockatlas.Tx) { } // NormalizeTx converts a Tezos transaction into the generic model -func NormalizeTx(srcTx Transaction) (blockatlas.Tx, bool) { - errMsg := "" - status := blockatlas.StatusCompleted - if srcTx.Status() != TxStatusApplied { - errMsg = "transaction failed" - status = blockatlas.StatusError - } - tx := blockatlas.Tx{ - ID: srcTx.Op.OpHash, +func NormalizeTx(srcTx Transaction, address string) (blockatlas.Tx, bool) { + var tx = blockatlas.Tx{ + Block: srcTx.Height, Coin: coin.XTZ, - Date: srcTx.Op.BlockTimestamp.Unix(), - From: srcTx.Source(), - To: srcTx.Destination(), - Fee: blockatlas.Amount(srcTx.Fee()), - Block: srcTx.Op.BlockLevel, - Status: status, - Error: errMsg, + Date: srcTx.BlockTimestamp(), + Error: srcTx.ErrorMsg(), + Fee: blockatlas.Amount(numbers.Float64toString(srcTx.Fee)), + From: srcTx.Sender, + ID: srcTx.Hash, + Status: srcTx.Status(), + To: srcTx.Receiver, + Type: srcTx.TransferType(), + } + if address != "" { + tx.Direction = srcTx.Direction(address) } - switch srcTx.Kind() { - case TxKindDelegation: - title := blockatlas.AnyActionDelegation - if len(srcTx.Delegation.Delegate) == 0 { - title = blockatlas.AnyActionUndelegation - } + switch srcTx.TransferType() { + case blockatlas.TxAnyAction: tx.Meta = blockatlas.AnyAction{ Coin: coin.Tezos().ID, - Title: title, + Title: srcTx.Title(), Key: blockatlas.KeyStakeDelegate, Name: coin.Tezos().Name, Symbol: coin.Tezos().Symbol, Decimals: coin.Tezos().Decimals, } - case TxKindTransaction: + case blockatlas.TxTransfer: tx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(srcTx.Tx.Amount), + Value: blockatlas.Amount(numbers.Float64toString(srcTx.Volume)), Symbol: coin.Coins[coin.XTZ].Symbol, Decimals: coin.Coins[coin.XTZ].Decimals, } diff --git a/platform/tezos/transaction_test.go b/platform/tezos/transaction_test.go index 42e56cad2..cc8febf65 100644 --- a/platform/tezos/transaction_test.go +++ b/platform/tezos/transaction_test.go @@ -1,363 +1,62 @@ package tezos import ( - "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" ) -const transferSrc1 = ` -{ - "tx": { - "destination": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - "amount": "1560", - "gasLimit": "15385", - "kind": "transaction", - "operationResultStatus": "applied", - "blockHash": "BMJYDJk9wRpxQuuqcFS7MZivqShtrgG18eY5K6rSDBpx5vcJLB2", - "fee": "0", - "operationResultConsumedGas": "10207", - "counter": "1383819", - "blockLevel": 791441, - "operationResultErrors": null, - "blockTimestamp": "2020-01-22T16:34:22Z", - "parameters": null, - "source": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - "insertedTimestamp": "2020-01-22 16:34:56.015281 UTC" - }, - "op": { - "opHash": "ooBAC2ynR5LfU9L2KEon8Z3ujmwEVyB9si1rrppBCmmEn4Mr3bJ", - "chainId": "NetXdQprcVkpaWU", - "blockHash": "BMJYDJk9wRpxQuuqcFS7MZivqShtrgG18eY5K6rSDBpx5vcJLB2", - "blockLevel": 791441, - "blockTimestamp": "2020-01-22T16:34:22Z", - "insertedTimestamp": "2020-01-22 16:34:49.405793 UTC" - } -}` - -const transferSrc2 = ` -{ - "tx": { - "destination": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - "amount": "1751", - "gasLimit": "15385", - "kind": "transaction", - "operationResultStatus": "applied", - "blockHash": "BLJKc6f6SpFs3Jr7WMp2ekx5jQQyzHWN6SWHDo2AJ41HJoPKTF2", - "fee": "0", - "operationResultConsumedGas": "10207", - "counter": "1383094", - "blockLevel": 788725, - "operationResultErrors": null, - "blockTimestamp": "2020-01-20T18:54:52Z", - "parameters": null, - "source": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - "insertedTimestamp": "2020-01-20 18:56:34.828193 UTC" - }, - "op": { - "opHash": "ookuQhVYopxrg8FtnfNASxpMhmnNhBqYaK3PJQXDpP7sDCJAZwf", - "chainId": "NetXdQprcVkpaWU", - "blockHash": "BLJKc6f6SpFs3Jr7WMp2ekx5jQQyzHWN6SWHDo2AJ41HJoPKTF2", - "blockLevel": 788725, - "blockTimestamp": "2020-01-20T18:54:52Z", - "insertedTimestamp": "2020-01-20 18:56:28.193751 UTC" - } -}` - -const transferSrc3 = ` -{ - "tx": { - "destination": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - "amount": "1751", - "gasLimit": "15385", - "kind": "transaction", - "operationResultStatus": "backtracked", - "blockHash": "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", - "fee": "0", - "operationResultConsumedGas": "10207", - "counter": "1382930", - "blockLevel": 788568, - "operationResultErrors": null, - "blockTimestamp": "2020-01-20T16:16:32Z", - "parameters": null, - "source": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - "insertedTimestamp": "2020-01-20 16:19:06.938114 UTC" - }, - "op": { - "opHash": "ooXN845juCMcQuqeodwBJWNhY17A5HKyWRxbcwS1m6TfqCqjM8q", - "chainId": "NetXdQprcVkpaWU", - "blockHash": "BMDYrXJ7GSwztzsy3ykJb43VXciNk1WY8EAaSoGbcUE7mA7HUzj", - "blockLevel": 788568, - "blockTimestamp": "2020-01-20T16:16:32Z", - "insertedTimestamp": "2020-01-20 16:18:59.855515 UTC" - } -}` - -const transferSrc4 = ` -{ - "op": { - "signature": "sigjQxDjvom9zqhNbi4cbwPLXn4fnVHiYSwsxDyXdPiFCjDqgS2ukHeWqmq61jkboiXTE3UJUqiXGqtmDVDXTRr5EKhaAeWF", - "blockUuid": "0ce492ed-ea9e-43c2-bf14-f17c44f099a4", - "opHash": "opUx5394wcy8BdoaYCM32kVyLB27F9ruT4vnKQccgQ463KsFPy3", - "uuid": "d5e2df82-9149-4d3e-9cac-16a425c79f67", - "chainId": "NetXdQprcVkpaWU", - "blockHash": "BMCkZ9NM5v3LnRPgfXYd4F9DHQ3bdTmmE8KjWhA5X982Bfz7ueC", - "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", - "branch": "BKybkjYtw3Cv7zdECiQd9W9WmWkoa25eJLwFiVQ4S3wB5mdcw4i", - "blockLevel": 809102, - "blockTimestamp": "2020-02-04T00:29:14Z", - "insertedTimestamp": "2020-02-04 00:29:28.291063 UTC" - }, - "endor": { - "slots": [ - 1 - ], - "delegate": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", - "opUuid": "d5e2df82-9149-4d3e-9cac-16a425c79f67", - "uuid": "7e1d6f45-b148-4e24-9c36-d7a0deb6ff72", - "kind": "endorsement", - "blockHash": "BMCkZ9NM5v3LnRPgfXYd4F9DHQ3bdTmmE8KjWhA5X982Bfz7ueC", - "blockLevel": 809102, - "blockTimestamp": "2020-02-04T00:29:14Z", - "insertedTimestamp": "2020-02-04 00:29:31.168224 UTC", - "metadataUuid": "36380127-30af-4bd0-88dd-18b49860d43c", - "level": 809101 - } -}` - -const delegationsSrc1 = ` -{ - "op": { - "signature": "sigvHd2YBByFXU8nL4CZKSTYXNdMapMsJw1f239YRRjgz9NvrTyA6iGnpBDhi9kCB4zMHysrg9H4jxcpPH975WiQtEmkMjb5", - "blockUuid": "4b292c55-41ba-4383-a1d6-03fb71b88f41", - "opHash": "opGphHGNEZZN5rF78yxwe9BJydxYA2yqxECnZR6s6HcxXtCg8Sj", - "uuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", - "chainId": "NetXdQprcVkpaWU", - "blockHash": "BLkscXpE63gajVzmgBS7fQx63hERKQRCZFGtMXdYY6WPThHyji7", - "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", - "branch": "BKqtLegZfdPR3USyYYcMpedB59W5eUBuFZAVpVMPpFgEvMcZjr1", - "blockLevel": 791778, - "blockTimestamp": "2020-01-22T22:13:38Z", - "insertedTimestamp": "2020-01-22 22:14:05.937406 UTC" - }, - "delegation": { - "storageLimit": "257", - "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - "opUuid": "e4ec0e07-1601-4da3-bd92-090a820ed369", - "uuid": "6459fcd9-5eee-4999-ac4d-92330b9eaab3", - "gasLimit": "10600", - "kind": "delegation", - "operationResultStatus": "applied", - "fee": "1500", - "operationResultUuid": "791f6ec7-ecec-43d5-82ca-a1497be0188c", - "operationResultConsumedGas": "10000", - "counter": "2409130", - "operationResultErrors": null, - "source": "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - "insertedTimestamp": "2020-01-22 22:15:12.038586 UTC", - "metadataUuid": "85b42f50-1a89-421c-bcb0-a06926941bc4" - } -}` - -const delegationsSrc2 = ` -{ - "op": { - "signature": "sigbhvzA37wDGhfYT21LQyoYfzU4KvhbaTwrLMXMDMDUJt69HNAxSK44wv8S1576ZADcEwMLNUbSXyBEFgFkikbNRn51ozhg", - "blockUuid": "785389b9-356d-4a98-9202-39f9c94b5b73", - "opHash": "onfvhheWth5GCbKKAc9KLZoqQ9AFzAS27vfPCN2DGcGuPA31jmc", - "uuid": "766932d0-fc9b-451d-834d-5feb48178580", - "chainId": "NetXdQprcVkpaWU", - "blockHash": "BMQShgncuUDtY2WbXz9aEqebKfztSL3VxVzgVRoMweb72fzS9MD", - "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", - "branch": "BLzBVG42EMvipNaWEPPTW9G6otFqwAEhSjsgmDMSNrVKComW4Tb", - "blockLevel": 809061, - "blockTimestamp": "2020-02-03T23:48:14Z", - "insertedTimestamp": "2020-02-03 23:48:43.650483 UTC" - }, - "delegation": { - "storageLimit": "257", - "delegate": "tz1V3yg82mcrPJbegqVCPn6bC8w1CSTRp3f8", - "opUuid": "766932d0-fc9b-451d-834d-5feb48178580", - "uuid": "ad5b8aca-86ae-4463-82b1-a05350c6899b", - "gasLimit": "10600", - "kind": "delegation", - "operationResultStatus": "applied", - "fee": "1500", - "operationResultUuid": "a87226fd-4983-49d7-b65f-93378056fda7", - "operationResultConsumedGas": "10000", - "counter": "3032194", - "operationResultErrors": null, - "source": "tz1hpUTmafsAEH8vQTirnZsvPWZ3wZ6oEkUw", - "insertedTimestamp": "2020-02-03 23:49:59.947433 UTC", - "metadataUuid": "325bfab8-6db3-4f6e-beb3-783031c556de" - } -}` - -const delegationsSrc3 = ` -{ - "op": { - "signature": "signaVwXLttpBqZVKUwbdUN92TevU26CRUWvYBx5areFAb4uAaeKDVFacWPfLc2WwfpMhXgbC4PpwgMuZd1RfXNJF7w7T7Fn", - "blockUuid": "ac319dd4-78ee-44c4-8652-6bf5be68a666", - "opHash": "oneqVXTkJqDvCDfxqggnzveo6U28Bp5sByguaqSZ7seBgQgzZSG", - "uuid": "c3bab716-ed01-4357-8f41-b75df6ea1708", - "chainId": "NetXdQprcVkpaWU", - "blockHash": "BLSN7G7UBSUys7njxo8Xm699L4U3xhhbkZyYYr5e8jJrDtnqfj8", - "protocol": "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS", - "branch": "BLAWNqLHLQWfSLwgQE8gqUWFPx3DPzxN2jrUxtz9q1zvisaCUwi", - "blockLevel": 809007, - "blockTimestamp": "2020-02-03T22:53:34Z", - "insertedTimestamp": "2020-02-03 22:53:48.734959 UTC" - }, - "delegation": { - "storageLimit": "257", - "delegate": null, - "opUuid": "c3bab716-ed01-4357-8f41-b75df6ea1708", - "uuid": "979e75b2-a64c-4844-a187-d5e59a3c7728", - "gasLimit": "10600", - "kind": "delegation", - "operationResultStatus": "applied", - "fee": "1500", - "operationResultUuid": "a4c26049-8169-4804-b074-d201fac4bfd2", - "operationResultConsumedGas": "10000", - "counter": "3032193", - "operationResultErrors": null, - "source": "tz1hpUTmafsAEH8vQTirnZsvPWZ3wZ6oEkUw", - "insertedTimestamp": "2020-02-03 22:54:50.993844 UTC", - "metadataUuid": "edd476c1-88e0-40d0-ac29-2c32e6d16feb" - } -}` - -var transfer1 = blockatlas.Tx{ - ID: "ooBAC2ynR5LfU9L2KEon8Z3ujmwEVyB9si1rrppBCmmEn4Mr3bJ", - Coin: coin.XTZ, - Date: 1579710862, - From: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - To: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - Fee: "0", - Block: 791441, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1560"), - Symbol: coin.Coins[coin.XTZ].Symbol, - Decimals: coin.Coins[coin.XTZ].Decimals, - }, - Status: blockatlas.StatusCompleted, -} - -var transfer2 = blockatlas.Tx{ - ID: "ookuQhVYopxrg8FtnfNASxpMhmnNhBqYaK3PJQXDpP7sDCJAZwf", - Coin: coin.XTZ, - Date: 1579546492, - From: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - To: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - Fee: "0", - Block: 788725, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1751"), - Symbol: coin.Coins[coin.XTZ].Symbol, - Decimals: coin.Coins[coin.XTZ].Decimals, - }, - Status: blockatlas.StatusCompleted, -} - -var transfer3 = blockatlas.Tx{ - ID: "ooXN845juCMcQuqeodwBJWNhY17A5HKyWRxbcwS1m6TfqCqjM8q", - Coin: coin.XTZ, - Date: 1579536992, - From: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - To: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - Fee: "0", - Block: 788568, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1751"), - Symbol: coin.Coins[coin.XTZ].Symbol, - Decimals: coin.Coins[coin.XTZ].Decimals, - }, - Status: blockatlas.StatusError, - Error: "transaction failed", -} - -var delegation1 = blockatlas.Tx{ - ID: "opGphHGNEZZN5rF78yxwe9BJydxYA2yqxECnZR6s6HcxXtCg8Sj", - Coin: coin.XTZ, - Date: 1579731218, - From: "tz1WDujRWCYjLBDfZieXW6insg5EUbg1rCRK", - To: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - Fee: "1500", - Block: 791778, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.AnyAction{ - Coin: coin.Tezos().ID, - Title: blockatlas.AnyActionDelegation, - Key: blockatlas.KeyStakeDelegate, - Name: coin.Tezos().Name, - Symbol: coin.Tezos().Symbol, - Decimals: coin.Tezos().Decimals, - }, -} - -var delegation2 = blockatlas.Tx{ - ID: "onfvhheWth5GCbKKAc9KLZoqQ9AFzAS27vfPCN2DGcGuPA31jmc", - Coin: coin.XTZ, - Date: 1580773694, - From: "tz1hpUTmafsAEH8vQTirnZsvPWZ3wZ6oEkUw", - To: "tz1V3yg82mcrPJbegqVCPn6bC8w1CSTRp3f8", - Fee: "1500", - Block: 809061, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.AnyAction{ - Coin: coin.Tezos().ID, - Title: blockatlas.AnyActionDelegation, - Key: blockatlas.KeyStakeDelegate, - Name: coin.Tezos().Name, - Symbol: coin.Tezos().Symbol, - Decimals: coin.Tezos().Decimals, - }, -} +var ( + tezosTransfer = Transaction{ + Hash: "op6GzJ3a3wGJTu4KuD2WNCVJdwEU5WKDXV6EyjsBYMEjyPQWozF", + Type: "transaction", + Time: "2020-02-28T12:59:06Z", + Height: 843988, + Stat: "applied", + IsSuccess: true, + Volume: 0.000001, + Fee: 0.0015, + Sender: addr1, + Receiver: addr1, + //Errors: {{ID: "proto.005-PsBabyM1.delegate.unchanged"}, Kind: "temporary"} + } -var delegation3 = blockatlas.Tx{ - ID: "oneqVXTkJqDvCDfxqggnzveo6U28Bp5sByguaqSZ7seBgQgzZSG", - Coin: coin.XTZ, - Date: 1580770414, - From: "tz1hpUTmafsAEH8vQTirnZsvPWZ3wZ6oEkUw", - To: "", - Fee: "1500", - Block: 809007, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.AnyAction{ - Coin: coin.Tezos().ID, - Title: blockatlas.AnyActionUndelegation, - Key: blockatlas.KeyStakeDelegate, - Name: coin.Tezos().Name, - Symbol: coin.Tezos().Symbol, - Decimals: coin.Tezos().Decimals, - }, -} + normalizedTezosTransfer = blockatlas.Tx{ + ID: "op6GzJ3a3wGJTu4KuD2WNCVJdwEU5WKDXV6EyjsBYMEjyPQWozF", + Coin: 1729, + From: addr1, + To: addr1, + Fee: "0.0015", + Date: 1582894746, + Block: 843988, + Status: "completed", + Type: "transfer", + Direction: "yourself", + Memo: "", + Meta: blockatlas.Transfer{ + Value: "0.000001", + Symbol: "XTZ", + Decimals: 6, + }, + } +) func TestNormalizeTx(t *testing.T) { tests := []struct { - name string - srcTx string - wantTx blockatlas.Tx - wantOk bool + name string + in Transaction + out blockatlas.Tx + address string }{ - {"transfer 1", transferSrc1, transfer1, true}, - {"transfer 2", transferSrc2, transfer2, true}, - {"transfer 3", transferSrc3, transfer3, true}, - {"delegation 1", delegationsSrc1, delegation1, true}, - {"delegation 2", delegationsSrc2, delegation2, true}, - {"delegation 3", delegationsSrc3, delegation3, true}, - {"transfer 4", transferSrc4, blockatlas.Tx{}, false}, + {"Normalize XTZ transfer", tezosTransfer, normalizedTezosTransfer, addr1}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var transaction Transaction - err := json.Unmarshal([]byte(tt.srcTx), &transaction) - assert.Nil(t, err) - gotTx, gotOk := NormalizeTx(transaction) - assert.Equal(t, tt.wantOk, gotOk, "transfer ok result don't equal") - assert.Equal(t, tt.wantTx, gotTx, "transfer don't equal") + normalized, ok := NormalizeTx(tt.in, tt.address) + if !ok { + assert.False(t, ok, "issue to normalize") + } + assert.Equal(t, tt.out, normalized) }) } } diff --git a/platform/theta/transaction_test.go b/platform/theta/transaction_test.go index 956f395cf..1b894685c 100644 --- a/platform/theta/transaction_test.go +++ b/platform/theta/transaction_test.go @@ -121,7 +121,7 @@ var expectedTfuelTransfer = blockatlas.Tx{ } func TestNormalize(t *testing.T) { - var tests = []struct { + tests := []struct { Transaction string Address string Token string @@ -169,7 +169,7 @@ func TestGetDirection(t *testing.T) { var addr = "0x42616c88c7076fbe6e1596b734c13356b5a508a4" var otherAddr = "0x8665a3cbc02ff17cf9d712e8a20f3d7bb1444517" - var tests = []struct { + tests := []struct { address string expectedDir blockatlas.Direction trxInput Input diff --git a/tests/integration/domains/domains.go b/tests/integration/domains/domains.go index 058e0489e..a4568b07b 100644 --- a/tests/integration/domains/domains.go +++ b/tests/integration/domains/domains.go @@ -12,7 +12,7 @@ import ( ) func TestDomains(t *testing.T) { - var tests = []struct { + tests := []struct { name string domain string coins []uint64 diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index c18d45814..2011df49a 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -92,7 +92,7 @@ { "handler": "tezos", "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", - "expectedTxNum": 1, + "expectedTxNum": 2, "expectedTxId": "ooLrNAP233Qvoz3AGvjRjhk1fjG7z19UfyLEGBm1rwfHn4NSVhd" }, { From eac73404903af108fa55305caa389a3b9d3ea865 Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Mon, 30 Mar 2020 19:41:58 -0700 Subject: [PATCH 214/506] fix: Get receiver for delegate transfer (#985) --- platform/tezos/model.go | 8 ++++++++ platform/tezos/model_test.go | 15 +++++++++++++++ platform/tezos/transaction.go | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/platform/tezos/model.go b/platform/tezos/model.go index 970c08ca9..451b39c07 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -109,3 +109,11 @@ func (t *Transaction) Direction(address string) blockatlas.Direction { return blockatlas.DirectionIncoming } + +func (t *Transaction) GetReceiver() string { + if t.Receiver != "" { + return t.Receiver + } else { + return t.Delegate + } +} diff --git a/platform/tezos/model_test.go b/platform/tezos/model_test.go index 773b11dd5..9d8151648 100644 --- a/platform/tezos/model_test.go +++ b/platform/tezos/model_test.go @@ -128,4 +128,19 @@ func TestTransaction_Status(t *testing.T) { }) } + testsGetReceiver := []struct { + name string + in Transaction + out string + }{ + {"Should get receiver when no delegate", Transaction{Receiver: addr1, Delegate: ""}, addr1}, + {"Should get receiver when delegate", Transaction{Receiver: "", Delegate: addr1}, addr1}, + } + + for _, tt := range testsGetReceiver { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.out, tt.in.GetReceiver()) + }) + } + } diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index 415b77135..5e1d76c10 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -40,7 +40,7 @@ func NormalizeTx(srcTx Transaction, address string) (blockatlas.Tx, bool) { From: srcTx.Sender, ID: srcTx.Hash, Status: srcTx.Status(), - To: srcTx.Receiver, + To: srcTx.GetReceiver(), Type: srcTx.TransferType(), } if address != "" { From 85cd1bac718fbf4b7aaa18fd1dedf619cc3c227d Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Mon, 30 Mar 2020 20:10:58 -0700 Subject: [PATCH 215/506] Fix tezos volume for delegation type transfers (#986) --- platform/tezos/transaction.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index 5e1d76c10..930fab63e 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -46,7 +46,7 @@ func NormalizeTx(srcTx Transaction, address string) (blockatlas.Tx, bool) { if address != "" { tx.Direction = srcTx.Direction(address) } - + value := blockatlas.Amount(numbers.Float64toString(srcTx.Volume)) switch srcTx.TransferType() { case blockatlas.TxAnyAction: tx.Meta = blockatlas.AnyAction{ @@ -56,10 +56,11 @@ func NormalizeTx(srcTx Transaction, address string) (blockatlas.Tx, bool) { Name: coin.Tezos().Name, Symbol: coin.Tezos().Symbol, Decimals: coin.Tezos().Decimals, + Value: value, } case blockatlas.TxTransfer: tx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(numbers.Float64toString(srcTx.Volume)), + Value: value, Symbol: coin.Coins[coin.XTZ].Symbol, Decimals: coin.Coins[coin.XTZ].Decimals, } From 64d793b9186d5cacc3530cb30a94dc8c473b26b4 Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Mon, 30 Mar 2020 20:55:02 -0700 Subject: [PATCH 216/506] Fix decimal value (#987) * Fix decimal vlaue * Fix test --- platform/tezos/transaction.go | 3 ++- platform/tezos/transaction_test.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index 930fab63e..87f27acf5 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -46,7 +46,8 @@ func NormalizeTx(srcTx Transaction, address string) (blockatlas.Tx, bool) { if address != "" { tx.Direction = srcTx.Direction(address) } - value := blockatlas.Amount(numbers.Float64toString(srcTx.Volume)) + + value := blockatlas.Amount(numbers.DecimalExp(numbers.Float64toString(srcTx.Volume), 6)) switch srcTx.TransferType() { case blockatlas.TxAnyAction: tx.Meta = blockatlas.AnyAction{ diff --git a/platform/tezos/transaction_test.go b/platform/tezos/transaction_test.go index cc8febf65..5bf0a9d0e 100644 --- a/platform/tezos/transaction_test.go +++ b/platform/tezos/transaction_test.go @@ -34,7 +34,7 @@ var ( Direction: "yourself", Memo: "", Meta: blockatlas.Transfer{ - Value: "0.000001", + Value: "1", Symbol: "XTZ", Decimals: 6, }, From e078561cfffd0252b1eb1bcc67fc5ccc452b442b Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Mon, 30 Mar 2020 21:11:07 -0700 Subject: [PATCH 217/506] Fix fee decimal (#990) --- platform/tezos/transaction.go | 2 +- platform/tezos/transaction_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index 87f27acf5..73347a0c7 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -36,7 +36,7 @@ func NormalizeTx(srcTx Transaction, address string) (blockatlas.Tx, bool) { Coin: coin.XTZ, Date: srcTx.BlockTimestamp(), Error: srcTx.ErrorMsg(), - Fee: blockatlas.Amount(numbers.Float64toString(srcTx.Fee)), + Fee: blockatlas.Amount(numbers.DecimalExp(numbers.Float64toString(srcTx.Fee), 6)), From: srcTx.Sender, ID: srcTx.Hash, Status: srcTx.Status(), diff --git a/platform/tezos/transaction_test.go b/platform/tezos/transaction_test.go index 5bf0a9d0e..aa98ce7f2 100644 --- a/platform/tezos/transaction_test.go +++ b/platform/tezos/transaction_test.go @@ -26,7 +26,7 @@ var ( Coin: 1729, From: addr1, To: addr1, - Fee: "0.0015", + Fee: "1500", Date: 1582894746, Block: 843988, Status: "completed", From 8fe9fb2abd948eadc02e20006823989a3f5958b0 Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Mon, 30 Mar 2020 21:31:44 -0700 Subject: [PATCH 218/506] Create Maintance template (#988) --- .github/ISSUE_TEMPLATE/MAINTANCE_TEMPLATE | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/MAINTANCE_TEMPLATE diff --git a/.github/ISSUE_TEMPLATE/MAINTANCE_TEMPLATE b/.github/ISSUE_TEMPLATE/MAINTANCE_TEMPLATE new file mode 100644 index 000000000..38e8634d4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/MAINTANCE_TEMPLATE @@ -0,0 +1,16 @@ +--- +name: Maintance +about: Deprecate old functionality or routes +title: '' +labels: 'Type: Maintance' +assignees: '' + +--- + + + From 9a33e588e4922d6d47904a986bec160122bfa7bf Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Tue, 31 Mar 2020 00:10:31 -0700 Subject: [PATCH 219/506] Add Enhancement template (#991) --- .github/ISSUE_TEMPLATE/IMPROVEMENT_TEMPLATE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/IMPROVEMENT_TEMPLATE diff --git a/.github/ISSUE_TEMPLATE/IMPROVEMENT_TEMPLATE b/.github/ISSUE_TEMPLATE/IMPROVEMENT_TEMPLATE new file mode 100644 index 000000000..f1e0f329a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/IMPROVEMENT_TEMPLATE @@ -0,0 +1,21 @@ +--- +name: Enhancement +about: Improve existing architecture +title: '' +labels: 'Type: Enhancement' +assignees: '' + +--- + + + +## Current Functionality + + +## Possible Improvement + From 3eeb1d248527e110a7b1a7ea08b965ff3c880b2e Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 1 Apr 2020 02:52:42 +0300 Subject: [PATCH 220/506] Migration from Redis to Postgres DB (#975) * Init PG * Step 2: rewrite package, add tests; Didn't rewrite old tests some updates Update Add/Find/Delete Add update test Add new test Update tests Update AddSubscription Fix integration tests Fix tests Fix tests Requested changes [Observer-TX] Fix issue with wrong transaction direction (#976) * [TX] Fix GetTransactionDirection * Add additional types checking for Memo * Add test Co-authored-by: Nick Kozlov Add transaction direction to eth transaction api (#977) remove go-ens / go-ethereum dependency (#973) * remove go-ens / go-ethereum dependency * Fix ens client * move to ens-coincodec * review comments * update fio client Fix for 'make stop' (Makefile, observer pid). (#979) * Fix for 'make stop' (Makefile, observer pid). * Fix newman test at Makefile Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov Fix issue with hardcoded token type for any eth like platform (#983) Update SubscriptionData/Subscription/Tracker Add TestDb_DuplicateEntries Small refactoring Finish to refactor db package Fix tests Add UpdateSub test Update AddSubscriptions logic Fix db_test Update Subscription model, fix test, removeSubscriptionDuplicates Fix test Update add/delete/update subscription and integration tests * Fix Makefile * Fixes for main.go and new test * Small changes * Update Subscriptions model * New tests fixes after guid change * Additional fixes * Add Bulk Delete for DeleteOperation * Init PG Step 2: rewrite package, add tests; Didn't rewrite old tests some updates Update Add/Find/Delete Add update test Add new test Update tests Update AddSubscription Fix integration tests Fix tests Fix tests Requested changes [Observer-TX] Fix issue with wrong transaction direction (#976) * [TX] Fix GetTransactionDirection * Add additional types checking for Memo * Add test Co-authored-by: Nick Kozlov Add transaction direction to eth transaction api (#977) remove go-ens / go-ethereum dependency (#973) * remove go-ens / go-ethereum dependency * Fix ens client * move to ens-coincodec * review comments * update fio client Fix for 'make stop' (Makefile, observer pid). (#979) * Fix for 'make stop' (Makefile, observer pid). * Fix newman test at Makefile Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov Fix issue with hardcoded token type for any eth like platform (#983) Update SubscriptionData/Subscription/Tracker Add TestDb_DuplicateEntries Small refactoring Finish to refactor db package Fix tests Add UpdateSub test Update AddSubscriptions logic Fix db_test Update Subscription model, fix test, removeSubscriptionDuplicates Fix test Update add/delete/update subscription and integration tests Fix Makefile Update Subscriptions model Fixes for main.go and new test Small changes New tests fixes after guid change Additional fixes Add Bulk Delete for DeleteOperation Cleanup Tests fixes * Add PG restore connection worker * Update Subscription model * Update DeleteAllSubscriptions, add integration test * Add test that expose bug * Fix issue (hope so) * Remove doubled tests which use real endpoints * Init PG * Step 2: rewrite package, add tests; Didn't rewrite old tests some updates Update Add/Find/Delete Add update test Add new test Update tests Update AddSubscription Fix integration tests Fix tests Fix tests Requested changes [Observer-TX] Fix issue with wrong transaction direction (#976) * [TX] Fix GetTransactionDirection * Add additional types checking for Memo * Add test Co-authored-by: Nick Kozlov Add transaction direction to eth transaction api (#977) remove go-ens / go-ethereum dependency (#973) * remove go-ens / go-ethereum dependency * Fix ens client * move to ens-coincodec * review comments * update fio client Fix for 'make stop' (Makefile, observer pid). (#979) * Fix for 'make stop' (Makefile, observer pid). * Fix newman test at Makefile Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov Fix issue with hardcoded token type for any eth like platform (#983) Update SubscriptionData/Subscription/Tracker Add TestDb_DuplicateEntries Small refactoring Finish to refactor db package Fix tests Add UpdateSub test Update AddSubscriptions logic Fix db_test Update Subscription model, fix test, removeSubscriptionDuplicates Fix test Update add/delete/update subscription and integration tests * Fix Makefile * Update Subscriptions model * Fixes for main.go and new test * Small changes * New tests fixes after guid change * Additional fixes * Add Bulk Delete for DeleteOperation * Update Subscription model * Init PG Step 2: rewrite package, add tests; Didn't rewrite old tests some updates Update Add/Find/Delete Add update test Add new test Update tests Update AddSubscription Fix integration tests Fix tests Fix tests Requested changes [Observer-TX] Fix issue with wrong transaction direction (#976) * [TX] Fix GetTransactionDirection * Add additional types checking for Memo * Add test Co-authored-by: Nick Kozlov Add transaction direction to eth transaction api (#977) remove go-ens / go-ethereum dependency (#973) * remove go-ens / go-ethereum dependency * Fix ens client * move to ens-coincodec * review comments * update fio client Fix for 'make stop' (Makefile, observer pid). (#979) * Fix for 'make stop' (Makefile, observer pid). * Fix newman test at Makefile Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov Fix issue with hardcoded token type for any eth like platform (#983) Update SubscriptionData/Subscription/Tracker Add TestDb_DuplicateEntries Small refactoring Finish to refactor db package Fix tests Add UpdateSub test Update AddSubscriptions logic Fix db_test Update Subscription model, fix test, removeSubscriptionDuplicates Fix test Update add/delete/update subscription and integration tests Fix Makefile Update Subscriptions model Fixes for main.go and new test Small changes New tests fixes after guid change Additional fixes Add Bulk Delete for DeleteOperation Cleanup Tests fixes * Add PG restore connection worker * Fix issue (hope so) * Remove doubled tests which use real endpoints * Add more logs to notifier.go * Update db package (delete global gorm.DB instance) * Call of db functions change Now we inject db as instance and use methods * Add more logs to notifier.go * Add tx to AddSubscriptions * Add more logs to notifier.go * Small fixes for db and notifier init * Small cleanup * Rename dbInstance to database Co-authored-by: Alexey Prazdnikov --- Makefile | 2 +- api/observer_healthcheck.go | 12 - api/routes.go | 6 +- cmd/observer_healthcheck/main.go | 50 -- cmd/observer_notifier/main.go | 18 +- cmd/observer_parser/main.go | 19 +- cmd/observer_subscriber/main.go | 20 +- config.yml | 6 +- db/db.go | 52 ++ db/models/subscriptions.go | 24 + db/models/tracker.go | 6 + db/subscriptions.go | 152 ++++++ db/subscritions_test.go | 91 ++++ db/tracker.go | 55 +++ go.mod | 3 +- go.sum | 71 +-- internal/init.go | 11 +- mq/mq.go | 109 ++--- pkg/blockatlas/clientcache.go | 3 +- pkg/blockatlas/observer.go | 11 +- pkg/blockatlas/observer_test.go | 20 +- pkg/blockatlas/tx.go | 12 +- pkg/ginutils/gincache/cache.go | 3 +- pkg/storage/redis/hmap.go | 51 -- pkg/storage/redis/redis.go | 64 --- pkg/storage/util/errors.go | 14 - platform/binance/model.go | 2 +- platform/binance/transaction.go | 2 +- platform/tezos/model_test.go | 10 +- scripts/.goreleaser.yml | 6 +- scripts/run_tests_postman.sh | 2 +- services/observer/healthcheck/healthcheck.go | 112 ----- services/observer/healthcheck/model.go | 6 - services/observer/notifier/notifier.go | 35 +- services/observer/parser/parser.go | 9 +- services/observer/parser/parser_test.go | 55 --- services/observer/subscriber/subscriber.go | 31 +- storage/addresses.go | 147 ------ storage/addresses_test.go | 347 -------------- storage/storage.go | 51 -- storage/tracker.go | 56 --- storage/tracker_test.go | 24 - tests/docker_test/setup/redis.go | 43 -- tests/docker_test/setup/setup.go | 27 -- tests/docker_test/subscriber_test.go | 66 --- tests/integration/bitcoin/block.go | 44 -- tests/integration/db_test/db_run_test.go | 25 + .../integration/db_test/subscriptions_test.go | 448 ++++++++++++++++++ tests/integration/db_test/tracker_test.go | 25 + tests/integration/domains/domains.go | 129 ----- tests/integration/integration_test.go | 30 -- .../data/given_subscriptions_added.json | 20 +- .../data/given_subscriptions_deleted.json | 38 ++ .../data/wanted_subscriptions_added.json | 8 +- .../observer_test/full_flow_test.go} | 23 +- .../observer_test}/notifier_test.go | 13 +- .../observer_test/observer_test.go} | 14 +- .../observer_test}/parser_test.go | 7 +- .../observer_test/subscriber_test.go | 146 ++++++ tests/integration/ontology/block.go | 128 ----- .../{docker_test => integration}/setup/mq.go | 0 tests/integration/setup/postgres.go | 81 ++++ tests/integration/setup/setup.go | 32 ++ 63 files changed, 1394 insertions(+), 1733 deletions(-) delete mode 100644 api/observer_healthcheck.go delete mode 100644 cmd/observer_healthcheck/main.go create mode 100644 db/db.go create mode 100644 db/models/subscriptions.go create mode 100644 db/models/tracker.go create mode 100644 db/subscriptions.go create mode 100644 db/subscritions_test.go create mode 100644 db/tracker.go delete mode 100644 pkg/storage/redis/hmap.go delete mode 100644 pkg/storage/redis/redis.go delete mode 100644 pkg/storage/util/errors.go delete mode 100644 services/observer/healthcheck/healthcheck.go delete mode 100644 services/observer/healthcheck/model.go delete mode 100644 storage/addresses.go delete mode 100644 storage/addresses_test.go delete mode 100644 storage/storage.go delete mode 100644 storage/tracker.go delete mode 100644 storage/tracker_test.go delete mode 100644 tests/docker_test/setup/redis.go delete mode 100644 tests/docker_test/setup/setup.go delete mode 100644 tests/docker_test/subscriber_test.go delete mode 100755 tests/integration/bitcoin/block.go create mode 100644 tests/integration/db_test/db_run_test.go create mode 100644 tests/integration/db_test/subscriptions_test.go create mode 100644 tests/integration/db_test/tracker_test.go delete mode 100644 tests/integration/domains/domains.go delete mode 100755 tests/integration/integration_test.go rename tests/{docker_test => integration/observer_test}/data/given_subscriptions_added.json (62%) create mode 100644 tests/integration/observer_test/data/given_subscriptions_deleted.json rename tests/{docker_test => integration/observer_test}/data/wanted_subscriptions_added.json (84%) rename tests/{docker_test/observer_test.go => integration/observer_test/full_flow_test.go} (86%) rename tests/{docker_test => integration/observer_test}/notifier_test.go (87%) rename tests/{docker_test/environment_run_test.go => integration/observer_test/observer_test.go} (64%) rename tests/{docker_test => integration/observer_test}/parser_test.go (95%) create mode 100644 tests/integration/observer_test/subscriber_test.go delete mode 100755 tests/integration/ontology/block.go rename tests/{docker_test => integration}/setup/mq.go (100%) create mode 100644 tests/integration/setup/postgres.go create mode 100644 tests/integration/setup/setup.go diff --git a/Makefile b/Makefile index 696a1ff82..0c9280556 100644 --- a/Makefile +++ b/Makefile @@ -248,7 +248,7 @@ go-test: go-integration: @echo " > Running integration tests" - GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration ./tests/docker_test + GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration/... go-fmt: @echo " > Format all go files" diff --git a/api/observer_healthcheck.go b/api/observer_healthcheck.go deleted file mode 100644 index dafe734c6..000000000 --- a/api/observer_healthcheck.go +++ /dev/null @@ -1,12 +0,0 @@ -package api - -import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/services/observer/healthcheck" - "net/http" -) - -func GetObserverStatus(c *gin.Context) { - exclude := splitParam(c.Query("exclude")) - c.JSON(http.StatusOK, healthcheck.GetStatus(exclude)) -} diff --git a/api/routes.go b/api/routes.go index 8766293f3..e029d5ab6 100644 --- a/api/routes.go +++ b/api/routes.go @@ -75,10 +75,6 @@ func SetupPlatformAPI(root gin.IRouter) { logger.Info("Routes set up", logger.Params{"routes": len(routers)}) } -func SetupHealthCheckApi(root gin.IRouter) { - root.GET("/", GetObserverStatus) -} - // getRouter lazy loads routers func getRouter(router *gin.RouterGroup, handle string) gin.IRouter { key := fmt.Sprintf("%s/%s", router.BasePath(), handle) @@ -118,4 +114,4 @@ func splitParam(param string) []string { return c == ',' } return strings.FieldsFunc(param, splitFn) -} \ No newline at end of file +} diff --git a/cmd/observer_healthcheck/main.go b/cmd/observer_healthcheck/main.go deleted file mode 100644 index b7169727f..000000000 --- a/cmd/observer_healthcheck/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - sentrygin "github.com/getsentry/sentry-go/gin" - "github.com/gin-gonic/gin" - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/api" - "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/services/observer/healthcheck" - "github.com/trustwallet/blockatlas/storage" - "time" -) - -const ( - defaultPort = "3333" - defaultConfigPath = "../../config.yml" -) - -var ( - port, confPath string - engine *gin.Engine - cache *storage.Storage -) - -func init() { - port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) - - internal.InitConfig(confPath) - redisHost := viper.GetString("storage.redis") - cache = internal.InitRedis(redisHost) - logger.InitLogger() - tmp := sentrygin.New(sentrygin.Options{}) - sg := &tmp - - engine = internal.InitEngine(sg, viper.GetString("gin.mode")) - - platform.Init(viper.GetString("platform")) -} - -func main() { - for _, blockAPI := range platform.BlockAPIs { - go healthcheck.Worker(cache, blockAPI) - time.Sleep(time.Millisecond * 200) - } - - api.SetupHealthCheckApi(engine) - internal.SetupGracefulShutdown(port, engine) -} diff --git a/cmd/observer_notifier/main.go b/cmd/observer_notifier/main.go index d3032ea21..6acfc2e24 100644 --- a/cmd/observer_notifier/main.go +++ b/cmd/observer_notifier/main.go @@ -3,11 +3,11 @@ package main import ( "context" "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/observer/notifier" - "github.com/trustwallet/blockatlas/storage" "time" ) @@ -17,7 +17,7 @@ const ( var ( confPath string - cache *storage.Storage + database *db.Instance ) func init() { @@ -26,11 +26,10 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() - redisHost := viper.GetString("storage.redis") mqHost := viper.GetString("observer.rabbitmq.uri") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + pgUri := viper.GetString("postgres.uri") - cache = internal.InitRedis(redisHost) internal.InitRabbitMQ(mqHost, prefetchCount) if err := mq.RawTransactions.Declare(); err != nil { @@ -41,8 +40,15 @@ func init() { logger.Fatal(err) } - go storage.RestoreConnectionWorker(cache, redisHost, time.Second*10) + var err error + database, err = db.New(pgUri) + if err != nil { + logger.Fatal(err) + } + go mq.RestoreConnectionWorker(mqHost, mq.RawTransactions, time.Second*10) + go db.RestoreConnectionWorker(database.DB, time.Second*10, pgUri) + time.Sleep(time.Millisecond) } func main() { @@ -50,7 +56,7 @@ func main() { ctx, cancel := context.WithCancel(context.Background()) - go mq.RawTransactions.RunConsumerWithCancel(notifier.RunNotifier, cache, ctx) + go mq.RawTransactions.RunConsumerWithCancelAndDbConn(notifier.RunNotifier, database, ctx) internal.SetupGracefulShutdownForObserver(cancel) } diff --git a/cmd/observer_parser/main.go b/cmd/observer_parser/main.go index 978418d00..6aed48645 100644 --- a/cmd/observer_parser/main.go +++ b/cmd/observer_parser/main.go @@ -4,13 +4,13 @@ import ( "context" "fmt" "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/observer/notifier" "github.com/trustwallet/blockatlas/services/observer/parser" - "github.com/trustwallet/blockatlas/storage" "os" "os/signal" "sync" @@ -24,10 +24,10 @@ const ( var ( confPath string - cache *storage.Storage backlogTime, minInterval, maxInterval time.Duration maxBackLogBlocks int64 txsBatchLimit uint + database *db.Instance ) func init() { @@ -36,12 +36,10 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() - redisHost := viper.GetString("storage.redis") mqHost := viper.GetString("observer.rabbitmq.uri") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") platformHandle := viper.GetString("platform") - cache = internal.InitRedis(redisHost) internal.InitRabbitMQ(mqHost, prefetchCount) platform.Init(platformHandle) @@ -52,6 +50,9 @@ func init() { if len(platform.BlockAPIs) == 0 { logger.Fatal("No APIs to observe") } + + pgUri := viper.GetString("postgres.uri") + txsBatchLimit = viper.GetUint("observer.txs_batch_limit") backlogTime = viper.GetDuration("observer.backlog") minInterval = viper.GetDuration("observer.block_poll.min") @@ -60,10 +61,14 @@ func init() { if minInterval >= maxInterval { logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") } + var err error + database, err = db.New(pgUri) + if err != nil { + logger.Fatal(err) + } go mq.FatalWorker(time.Second * 10) - time.Sleep(time.Millisecond) - go storage.RestoreConnectionWorker(cache, redisHost, time.Second*10) + go db.RestoreConnectionWorker(database.DB, time.Second*10, pgUri) time.Sleep(time.Millisecond) } @@ -100,13 +105,13 @@ func main() { params := parser.Params{ Ctx: ctx, Api: api, - Storage: cache, Queue: mq.RawTransactions, ParsingBlocksInterval: pollInterval, BacklogCount: backlogCount, MaxBacklogBlocks: maxBackLogBlocks, StopChannel: stopChannel, TxBatchLimit: txsBatchLimit, + Database: database, } go parser.RunParser(params) diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index 3a169996c..9c9bf9f36 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -3,12 +3,12 @@ package main import ( "context" "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/db" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/observer/subscriber" - "github.com/trustwallet/blockatlas/storage" "time" ) @@ -18,7 +18,7 @@ const ( var ( confPath string - cache *storage.Storage + database *db.Instance ) func init() { @@ -27,16 +27,22 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() - redisHost := viper.GetString("storage.redis") + pgUri := viper.GetString("postgres.uri") + mqHost := viper.GetString("observer.rabbitmq.uri") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") - cache = internal.InitRedis(redisHost) - internal.InitRabbitMQ(mqHost, prefetchCount) + var err error + database, err = db.New(pgUri) + if err != nil { + logger.Fatal(err) + } + go mq.FatalWorker(time.Second * 10) - go storage.RestoreConnectionWorker(cache, redisHost, time.Second*10) + go db.RestoreConnectionWorker(database.DB, time.Second*10, pgUri) + time.Sleep(time.Millisecond) } func main() { @@ -46,7 +52,7 @@ func main() { } ctx, cancel := context.WithCancel(context.Background()) - go mq.Subscriptions.RunConsumerWithCancel(subscriber.RunSubscriber, cache, ctx) + go mq.Subscriptions.RunConsumerWithCancelAndDbConn(subscriber.RunSubscriber, database, ctx) internal.SetupGracefulShutdownForObserver(cancel) } diff --git a/config.yml b/config.yml index 9456cc02c..6430bb651 100644 --- a/config.yml +++ b/config.yml @@ -9,7 +9,7 @@ gin: # If all - run all platforms in one binary. You can pick specific coin handle to run binary only with specific coin # Example: ethereum # You can see all the coin handles at coins/coins.yml file -platform: all +platform: binance # Sentry error tracking #sentry: @@ -32,8 +32,8 @@ observer: consumer: prefetch_count: 10 -storage: - redis: redis://localhost:6379 +postgres: + uri: postgresql://user:pass@localhost/my_db?sslmode=disable # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org diff --git a/db/db.go b/db/db.go new file mode 100644 index 000000000..98b4f41f0 --- /dev/null +++ b/db/db.go @@ -0,0 +1,52 @@ +package db + +import ( + "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/postgres" + "github.com/trustwallet/blockatlas/db/models" + + "github.com/trustwallet/blockatlas/pkg/logger" + "time" +) + +type Instance struct { + DB *gorm.DB +} + +func New(uri string) (*Instance, error) { + dbConn, err := gorm.Open("postgres", uri) + if err != nil { + return nil, err + } + + dbConn.AutoMigrate( + &models.Subscription{}, + &models.SubscriptionData{}, + &models.Tracker{}, + ) + i := &Instance{DB: dbConn} + + return i, nil +} + +func RestoreConnectionWorker(dbConn *gorm.DB, timeout time.Duration, uri string) { + logger.Info("Run PG RestoreConnectionWorker") + for { + if err := dbConn.DB().Ping(); err != nil { + for { + logger.Warn("PG is not available now") + logger.Warn("Trying to connect to PG...") + dbConn, err = gorm.Open("postgres", uri) + if err != nil { + logger.Warn("PG is still unavailable:", err.Error()) + time.Sleep(timeout) + continue + } else { + logger.Info("PG connection restored") + break + } + } + } + time.Sleep(timeout) + } +} diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go new file mode 100644 index 000000000..a98ab609d --- /dev/null +++ b/db/models/subscriptions.go @@ -0,0 +1,24 @@ +package models + +import ( + "time" +) + +type TimeModel struct { + CreatedAt time.Time + UpdatedAt time.Time +} + +type Subscription struct { + TimeModel + SubscriptionId uint `gorm:"primary_key:true"` + Data []SubscriptionData `gorm:"foreignkey:SubscriptionId"` +} + +type SubscriptionData struct { + TimeModel + ID uint `gorm:"primary_key:true"` + SubscriptionId uint `sql:"index"` + Coin uint `sql:"index"` + Address string `sql:"index"` +} diff --git a/db/models/tracker.go b/db/models/tracker.go new file mode 100644 index 000000000..10e62a234 --- /dev/null +++ b/db/models/tracker.go @@ -0,0 +1,6 @@ +package models + +type Tracker struct { + Coin uint `gorm:"primary_key:true"` + Height int64 +} diff --git a/db/subscriptions.go b/db/subscriptions.go new file mode 100644 index 000000000..8ef21dc44 --- /dev/null +++ b/db/subscriptions.go @@ -0,0 +1,152 @@ +package db + +import ( + "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/pkg/errors" +) + +func (i *Instance) GetSubscriptionData(coin uint, addresses []string) ([]models.SubscriptionData, error) { + if len(addresses) == 0 { + return nil, errors.E("Empty addresses") + } + + var subscriptionsDataList []models.SubscriptionData + err := i.DB. + Model(&models.SubscriptionData{}). + Where("address in (?) AND coin = ?", addresses, coin). + Find(&subscriptionsDataList).Error + + if err != nil { + return nil, err + } + return subscriptionsDataList, nil +} + +func (i *Instance) AddSubscriptions(id uint, subscriptions []models.SubscriptionData) error { + txInstance := Instance{DB: i.DB.Begin()} + defer func() { + if r := recover(); r != nil { + txInstance.DB.Rollback() + } + }() + + if err := txInstance.DB.Error; err != nil { + return err + } + if len(subscriptions) == 0 { + return errors.E("Empty subscriptions") + } + var ( + existingSub models.Subscription + err error + ) + + recordNotFound := txInstance.DB. + Where(models.Subscription{SubscriptionId: id}). + First(&existingSub). + RecordNotFound() + + subscriptions = removeSubscriptionDuplicates(subscriptions) + if recordNotFound { + err = txInstance.AddSubscription(id, subscriptions) + } else { + err = txInstance.AddToExistingSubscription(id, subscriptions) + } + if err != nil { + txInstance.DB.Rollback() + return err + } + return txInstance.DB.Commit().Error +} + +func (i *Instance) AddSubscription(id uint, data []models.SubscriptionData) error { + return i.DB.Create(&models.Subscription{SubscriptionId: id, Data: data}).Error +} + +func (i *Instance) AddToExistingSubscription(id uint, subscriptions []models.SubscriptionData) error { + var ( + existingData []models.SubscriptionData + association = i.DB.Model(&models.Subscription{SubscriptionId: id}).Association("Data") + ) + if err := association.Error; err != nil { + return err + } + if err := association.Find(&existingData).Error; err != nil { + return err + } + + updateList, deleteList := getSubscriptionsToDeleteAndUpdate(existingData, subscriptions) + if len(updateList) > 0 { + if err := association.Append(updateList).Error; err != nil { + return err + } + } + if len(deleteList) > 0 { + if err := i.DeleteSubscriptions(deleteList); err != nil { + return err + } + } + return nil +} + +func (i *Instance) DeleteAllSubscriptions(id uint) error { + request := i.DB.Where("subscription_id = ?", id) + if err := request.Error; err != nil { + return err + } + return request.Delete(&models.SubscriptionData{}).Error +} + +func (i *Instance) DeleteSubscriptions(subscriptions []models.SubscriptionData) error { + var ( + errorsList = make([]error, 0) + errDetails string + ) + for _, sub := range subscriptions { + if err := i.DB.Delete(&models.SubscriptionData{}, sub).Error; err != nil { + errorsList = append(errorsList, err) + } + } + if len(errorsList) != 0 { + for _, err := range errorsList { + errDetails += err.Error() + " " + } + return errors.E(errDetails) + } + return nil +} + +func getSubscriptionsToDeleteAndUpdate(existing, new []models.SubscriptionData) (subToUpdate, subToDelete []models.SubscriptionData) { + for _, n := range new { + if !containSubscription(n, existing) { + subToUpdate = append(subToUpdate, n) + } + } + for _, e := range existing { + if !containSubscription(e, new) { + subToDelete = append(subToDelete, e) + } + } + return subToUpdate, subToDelete +} + +func containSubscription(sub models.SubscriptionData, list []models.SubscriptionData) bool { + for _, s := range list { + if s.Address == sub.Address && sub.Coin == s.Coin && s.SubscriptionId == sub.SubscriptionId { + return true + } + } + return false +} + +func removeSubscriptionDuplicates(sub []models.SubscriptionData) []models.SubscriptionData { + keys := make(map[models.SubscriptionData]bool) + result := make([]models.SubscriptionData, 0) + for _, entry := range sub { + if _, value := keys[entry]; !value { + keys[entry] = true + result = append(result, entry) + } + } + return result +} diff --git a/db/subscritions_test.go b/db/subscritions_test.go new file mode 100644 index 000000000..274ceec5a --- /dev/null +++ b/db/subscritions_test.go @@ -0,0 +1,91 @@ +package db + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/db/models" + "testing" +) + +func TestGetSubscriptionsToDeleteAndUpdate(t *testing.T) { + oldSubscriptions := []models.SubscriptionData{{ + SubscriptionId: 1, + Coin: 60, + Address: "A", + }, { + SubscriptionId: 1, + Coin: 60, + Address: "B", + }, { + SubscriptionId: 1, + Coin: 60, + Address: "C", + }} + + newSubscription := []models.SubscriptionData{{ + SubscriptionId: 1, + Coin: 60, + Address: "B", + }, { + SubscriptionId: 1, + Coin: 60, + Address: "C", + }} + + update, delete := getSubscriptionsToDeleteAndUpdate(oldSubscriptions, newSubscription) + assert.Len(t, update, 0) + assert.Len(t, delete, 1) + assert.Equal(t, "A", delete[0].Address) + + oldSubscriptions = []models.SubscriptionData{{ + SubscriptionId: 1, + Coin: 60, + Address: "A", + }, { + SubscriptionId: 1, + Coin: 60, + Address: "B", + }, { + SubscriptionId: 1, + Coin: 60, + Address: "C", + }, { + SubscriptionId: 1, + Coin: 60, + Address: "D", + }} + + newSubscription = []models.SubscriptionData{{ + SubscriptionId: 1, + Coin: 60, + Address: "E", + }} + + update, delete = getSubscriptionsToDeleteAndUpdate(oldSubscriptions, newSubscription) + assert.Len(t, update, 1) + assert.Len(t, delete, 4) + + oldSubscriptions = []models.SubscriptionData{{ + SubscriptionId: 1, + Coin: 60, + Address: "A", + }, { + SubscriptionId: 1, + Coin: 60, + Address: "B", + }} + + newSubscription = []models.SubscriptionData{{ + SubscriptionId: 1, + Coin: 60, + Address: "A", + }, { + SubscriptionId: 1, + Coin: 60, + Address: "B", + }} + + update, delete = getSubscriptionsToDeleteAndUpdate(oldSubscriptions, newSubscription) + assert.Len(t, update, 0) + assert.Len(t, delete, 0) + +} diff --git a/db/tracker.go b/db/tracker.go new file mode 100644 index 000000000..60098a0d3 --- /dev/null +++ b/db/tracker.go @@ -0,0 +1,55 @@ +package db + +import ( + "github.com/trustwallet/blockatlas/db/models" + "sync" +) + +var memoryCache heightBlockMap + +func init() { + memoryCache.m = make(map[uint]int64) +} + +type heightBlockMap struct { + m map[uint]int64 + sync.RWMutex +} + +func (hbm *heightBlockMap) SetHeight(coin uint, b int64) { + hbm.Lock() + defer hbm.Unlock() + hbm.m[coin] = b +} + +func (hbm *heightBlockMap) GetHeight(coin uint) (int64, bool) { + hbm.RLock() + defer hbm.RUnlock() + b, ok := hbm.m[coin] + return b, ok +} + +func (i *Instance) GetLastParsedBlockNumber(coin uint) (int64, error) { + height, ok := memoryCache.GetHeight(coin) + if ok { + return height, nil + } + var tracker models.Tracker + if err := i.DB.Where(models.Tracker{Coin: coin}).Find(&tracker).Error; err != nil { + return 0, nil + } + return tracker.Height, nil +} + +func (i *Instance) SetLastParsedBlockNumber(coin uint, num int64) error { + memoryCache.SetHeight(coin, num) + tracker := models.Tracker{ + Coin: coin, + Height: num, + } + + return i.DB. + Set("gorm:insert_option", "ON CONFLICT (coin) DO UPDATE SET height = excluded.height"). + Where(models.Tracker{Coin: coin}). + Create(&tracker).Error +} diff --git a/go.mod b/go.mod index de25d5f8e..a91e3f674 100644 --- a/go.mod +++ b/go.mod @@ -23,11 +23,12 @@ require ( github.com/google/go-cmp v0.4.0 // indirect github.com/gorilla/websocket v1.4.1 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect + github.com/hewigovens/go-coincodec v1.0.4 + github.com/jinzhu/gorm v1.9.12 github.com/json-iterator/go v1.1.9 // indirect github.com/klauspost/compress v1.10.1 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/kr/pretty v0.2.0 // indirect - github.com/lib/pq v1.1.1 // indirect github.com/mitchellh/mapstructure v1.1.2 github.com/mr-tron/base58 v1.1.3 github.com/opencontainers/image-spec v1.0.1 // indirect diff --git a/go.sum b/go.sum index 29bdd1f27..8b9d371bc 100644 --- a/go.sum +++ b/go.sum @@ -78,6 +78,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -89,10 +90,9 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= @@ -101,7 +101,6 @@ github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv github.com/getsentry/sentry-go v0.4.0 h1:WqRI2/7EiALbdG9qGB47c0Aks1tdznG5DZd6GSQ1y/8= github.com/getsentry/sentry-go v0.4.0/go.mod h1:xkGcb82SipKQloDNa5b7hTV4VdEyc2bhwd1/UczP52k= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= @@ -112,11 +111,9 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/ github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= @@ -139,40 +136,34 @@ github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotf github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= -github.com/go-redis/redis v6.15.6+incompatible h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be8FqJQRhdQZ5Sg= github.com/go-redis/redis v6.15.6+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38 h1:y0Wmhvml7cGnzPa9nocn/fMraMH/lMDdeG+rkx4VgYY= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -180,9 +171,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hewigovens/go-coincodec v1.0.4/go.mod h1:+LTdzScnu782gMt0J3ZccPY9S2uyrGe0R1LUYGWecfc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= @@ -190,20 +180,22 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/ github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= +github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= @@ -213,24 +205,16 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.10.1 h1:a/QY0o9S6wCi0XhxaMX/QmusicNUqCqFugR6WKPOSoQ= github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= @@ -245,15 +229,14 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= -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/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= @@ -262,12 +245,9 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -279,11 +259,9 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -297,11 +275,9 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -321,7 +297,6 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 h1:Pm6R878vxWWWR+Sa3ppsLce/Zq+JNTs6aVvRu13jv9A= github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -331,9 +306,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -384,31 +357,21 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0= github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= @@ -420,17 +383,19 @@ golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -444,7 +409,6 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -485,14 +449,13 @@ golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd h1:hHkvGJK23seRCflePJnVa9IMv8fsuavSCWKd11kDQFs= golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -500,12 +463,9 @@ gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= @@ -514,7 +474,6 @@ gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/init.go b/internal/init.go index 699a7ac19..bce427039 100644 --- a/internal/init.go +++ b/internal/init.go @@ -8,7 +8,7 @@ import ( "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" + "path/filepath" "runtime" "time" @@ -31,15 +31,6 @@ func ParseArgs(defaultPort, defaultConfigPath string) (string, string) { return port, confPath } -func InitRedis(host string) *storage.Storage { - cache := storage.New() - err := cache.Init(host) - if err != nil { - logger.Fatal(err) - } - return cache -} - func InitConfig(confPath string) { confPath, err := filepath.Abs(confPath) if err != nil { diff --git a/mq/mq.go b/mq/mq.go index 1ad87c08f..812fd9041 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -3,8 +3,8 @@ package mq import ( "context" "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" "time" ) @@ -15,9 +15,10 @@ var ( ) type ( - Queue string - Consumer func(amqp.Delivery, storage.Addresses) - MessageChannel <-chan amqp.Delivery + Queue string + Consumer func(amqp.Delivery) + ConsumerWithDbConn func(*db.Instance, amqp.Delivery) + MessageChannel <-chan amqp.Delivery ) const ( @@ -31,13 +32,10 @@ const ( func Init(uri string) (err error) { conn, err = amqp.Dial(uri) if err != nil { - return + return err } amqpChan, err = conn.Channel() - if err != nil { - return - } - return + return err } func Close() { @@ -45,6 +43,10 @@ func Close() { conn.Close() } +func (mc MessageChannel) GetMessage() amqp.Delivery { + return <-mc +} + func (q Queue) Declare() error { _, err := amqpChan.QueueDeclare(string(q), true, false, false, false, nil) return err @@ -58,7 +60,7 @@ func (q Queue) Publish(body []byte) error { }) } -func (q Queue) RunConsumerForChannelWithCancel(consumer Consumer, messageChannel MessageChannel, cache storage.Addresses, ctx context.Context) { +func RunConsumerForChannelWithCancelAndDbConn(consumer ConsumerWithDbConn, messageChannel MessageChannel, database *db.Instance, ctx context.Context) { for { select { case <-ctx.Done(): @@ -68,12 +70,12 @@ func (q Queue) RunConsumerForChannelWithCancel(consumer Consumer, messageChannel if message.Body == nil { continue } - go consumer(message, cache) + go consumer(database, message) } } } -func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { +func (q Queue) GetMessageChannel() MessageChannel { messageChannel, err := amqpChan.Consume( string(q), "", @@ -85,12 +87,6 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { ) if err != nil { logger.Fatal("MQ issue " + err.Error()) - return - } - - if PrefetchCount < minPrefetchCount { - logger.Info("Change prefetch count to default") - PrefetchCount = defaultPrefetchCount } err = amqpChan.Qos( @@ -98,46 +94,22 @@ func (q Queue) RunConsumer(consumer Consumer, cache storage.Addresses) { 0, true, ) - if err != nil { - logger.Error("no qos limit ", err) + logger.Fatal("No qos limit ", err) } - for data := range messageChannel { - go consumer(data, cache) - } + return messageChannel } -func (q Queue) RunConsumerWithCancel(consumer Consumer, cache storage.Addresses, ctx context.Context) { - messageChannel, err := amqpChan.Consume( - string(q), - "", - false, - false, - false, - false, - nil, - ) - if err != nil { - logger.Fatal("MQ issue " + err.Error()) - return - } - - if PrefetchCount < minPrefetchCount { - logger.Info("Change prefetch count to default") - PrefetchCount = defaultPrefetchCount - } - - err = amqpChan.Qos( - PrefetchCount, - 0, - true, - ) - - if err != nil { - logger.Error("no qos limit ", err) +func (q Queue) RunConsumer(consumer Consumer) { + messageChannel := q.GetMessageChannel() + for data := range messageChannel { + go consumer(data) } +} +func (q Queue) RunConsumerWithCancel(consumer Consumer, ctx context.Context) { + messageChannel := q.GetMessageChannel() for { select { case <-ctx.Done(): @@ -147,30 +119,25 @@ func (q Queue) RunConsumerWithCancel(consumer Consumer, cache storage.Addresses, if message.Body == nil { continue } - go consumer(message, cache) + go consumer(message) } } } -func (q Queue) GetMessageChannel() MessageChannel { - messageChannel, err := amqpChan.Consume( - string(q), - "", - false, - false, - false, - false, - nil, - ) - if err != nil { - logger.Fatal("MQ issue " + err.Error()) +func (q Queue) RunConsumerWithCancelAndDbConn(consumer ConsumerWithDbConn, database *db.Instance, ctx context.Context) { + messageChannel := q.GetMessageChannel() + for { + select { + case <-ctx.Done(): + logger.Info("Consumer stopped") + return + case message := <-messageChannel: + if message.Body == nil { + continue + } + go consumer(database, message) + } } - - return messageChannel -} - -func (mc MessageChannel) GetMessage() amqp.Delivery { - return <-mc } func RestoreConnectionWorker(uri string, queue Queue, timeout time.Duration) { @@ -200,7 +167,7 @@ func RestoreConnectionWorker(uri string, queue Queue, timeout time.Duration) { } func FatalWorker(timeout time.Duration) { - logger.Info("Run FatalWorker") + logger.Info("Run MQ FatalWorker") for { if conn.IsClosed() { logger.Fatal("MQ is not available now") diff --git a/pkg/blockatlas/clientcache.go b/pkg/blockatlas/clientcache.go index 12ace94d8..6c376f4c5 100644 --- a/pkg/blockatlas/clientcache.go +++ b/pkg/blockatlas/clientcache.go @@ -7,7 +7,6 @@ import ( "github.com/patrickmn/go-cache" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/pkg/storage/util" "net/url" "strings" "sync" @@ -85,7 +84,7 @@ func (mc *memCache) getCache(key string, value interface{}) error { } err := json.Unmarshal(r, value) if err != nil { - return errors.E(err, util.ErrNotFound) + return errors.E(err, "not found") } return nil } diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go index 168c94e7a..da61b1b7a 100644 --- a/pkg/blockatlas/observer.go +++ b/pkg/blockatlas/observer.go @@ -8,16 +8,15 @@ type ( SubscriptionOperation string SubscriptionEvent struct { - NewSubscriptions Subscriptions `json:"new_subscriptions"` - OldSubscriptions Subscriptions `json:"old_subscriptions"` - GUID string `json:"guid"` - Operation SubscriptionOperation `json:"operation"` + Subscriptions Subscriptions `json:"subscriptions"` + Id uint `json:"id"` + Operation SubscriptionOperation `json:"operation"` } Subscription struct { Coin uint `json:"coin"` Address string `json:"address"` - GUID string `json:"guid"` + Id uint `json:"id"` } CoinStatus struct { @@ -42,7 +41,7 @@ func (e *SubscriptionEvent) ParseSubscriptions(s Subscriptions) []Subscription { subs = append(subs, Subscription{ Coin: uint(coin), Address: addr, - GUID: e.GUID, + Id: e.Id, }) } } diff --git a/pkg/blockatlas/observer_test.go b/pkg/blockatlas/observer_test.go index 1f80e0eac..1cd29b123 100644 --- a/pkg/blockatlas/observer_test.go +++ b/pkg/blockatlas/observer_test.go @@ -15,18 +15,18 @@ func Test_parseSubscriptions(t *testing.T) { { name: "guid with 1 coin", subscriptions: SubscriptionEvent{ - GUID: "http://127.0.0.1:8080", - OldSubscriptions: Subscriptions{ + Id: 1, + Subscriptions: Subscriptions{ "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, }, }, wantSubs: []Subscription{ { - Coin: 0, GUID: "http://127.0.0.1:8080", + Coin: 0, Id: 1, Address: "xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", }, { - Coin: 0, GUID: "http://127.0.0.1:8080", + Coin: 0, Id: 1, Address: "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL", }, }, @@ -34,23 +34,23 @@ func Test_parseSubscriptions(t *testing.T) { { name: "guid with 2 coins", subscriptions: SubscriptionEvent{ - GUID: "http://127.0.0.1:8080", - OldSubscriptions: Subscriptions{ + Id: 1, + Subscriptions: Subscriptions{ "2": {"zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc"}, "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, }, }, wantSubs: []Subscription{ { - Coin: 2, GUID: "http://127.0.0.1:8080", + Coin: 2, Id: 1, Address: "zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc", }, { - Coin: 0, GUID: "http://127.0.0.1:8080", + Coin: 0, Id: 1, Address: "xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", }, { - Coin: 0, GUID: "http://127.0.0.1:8080", + Coin: 0, Id: 1, Address: "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL", }, }, @@ -58,7 +58,7 @@ func Test_parseSubscriptions(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotSubs := tt.subscriptions.ParseSubscriptions(tt.subscriptions.OldSubscriptions) + gotSubs := tt.subscriptions.ParseSubscriptions(tt.subscriptions.Subscriptions) sort.Slice(gotSubs, func(i, j int) bool { return gotSubs[i].Coin > gotSubs[j].Coin }) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 49f435c64..09cbc5797 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -56,12 +56,12 @@ const ( type ( // Types of transaction statuses - Direction string - Status string - TokenType string - TransactionType string - KeyType string - KeyTitle string + Direction string + Status string + TokenType string + TransactionType string + KeyType string + KeyTitle string Block struct { Number int64 `json:"number"` diff --git a/pkg/ginutils/gincache/cache.go b/pkg/ginutils/gincache/cache.go index 1de5fca2f..43474e167 100644 --- a/pkg/ginutils/gincache/cache.go +++ b/pkg/ginutils/gincache/cache.go @@ -10,7 +10,6 @@ import ( "github.com/patrickmn/go-cache" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/pkg/storage/util" "io/ioutil" "net/http" "sync" @@ -135,7 +134,7 @@ func (mc *memCache) getCache(key string) (cacheResponse, error) { } err := json.Unmarshal(r, &result) if err != nil { - return result, errors.E(err, util.ErrNotFound) + return result, errors.E(err, "not found") } return result, nil } diff --git a/pkg/storage/redis/hmap.go b/pkg/storage/redis/hmap.go deleted file mode 100644 index a5c469132..000000000 --- a/pkg/storage/redis/hmap.go +++ /dev/null @@ -1,51 +0,0 @@ -package redis - -import ( - "encoding/json" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/storage/util" -) - -func (db *Redis) GetAllHM(entity string) (map[string]string, error) { - cmd := db.client.HGetAll(entity) - if cmd.Err() != nil { - return nil, errors.E(cmd.Err(), util.ErrNotFound) - } - return cmd.Val(), nil -} - -func (db *Redis) GetHMValue(entity, key string, value interface{}) error { - cmd := db.client.HMGet(entity, key) - if cmd.Err() != nil { - return errors.E(cmd.Err(), util.ErrNotFound) - } - val, ok := cmd.Val()[0].(string) - if !ok { - return errors.E(util.ErrNotFound) - } - err := json.Unmarshal([]byte(val), value) - if err != nil { - return errors.E(err, util.ErrNotFound) - } - return nil -} - -func (db *Redis) AddHM(entity, key string, value interface{}) error { - j, err := json.Marshal(value) - if err != nil { - return errors.E(err, errors.Params{"key": key}) - } - cmd := db.client.HMSet(entity, map[string]interface{}{key: j}) - if cmd.Err() != nil { - return errors.E(cmd.Err(), util.ErrNotStored) - } - return nil -} - -func (db *Redis) DeleteHM(entity, key string) error { - cmd := db.client.HDel(entity, key) - if cmd.Err() != nil { - return errors.E(cmd.Err(), util.ErrNotDeleted) - } - return nil -} diff --git a/pkg/storage/redis/redis.go b/pkg/storage/redis/redis.go deleted file mode 100644 index 979ae2a23..000000000 --- a/pkg/storage/redis/redis.go +++ /dev/null @@ -1,64 +0,0 @@ -package redis - -import ( - "encoding/json" - "github.com/go-redis/redis" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/storage/util" -) - -type Redis struct { - client *redis.Client -} - -func (db *Redis) Init(host string) error { - options, err := redis.ParseURL(host) - if err != nil { - return errors.E(err, "Cannot connect to Redis") - } - client := redis.NewClient(options) - if err := client.Ping().Err(); err != nil { - return errors.E(err, "Redis connection test failed") - } - db.client = client - return nil -} - -func (db *Redis) GetValue(key string, value interface{}) error { - cmd := db.client.Get(key) - if cmd.Err() != nil { - return errors.E(cmd.Err(), util.ErrNotFound) - } - err := json.Unmarshal([]byte(cmd.Val()), value) - if err != nil { - return errors.E(err, util.ErrNotFound) - } - return nil -} - -func (db *Redis) Add(key string, value interface{}) error { - j, err := json.Marshal(value) - if err != nil { - return errors.E(err, errors.Params{"key": key}) - } - cmd := db.client.Set(key, j, 0) - if cmd.Err() != nil { - return errors.E(cmd.Err(), util.ErrNotStored) - } - return nil -} - -func (db *Redis) Delete(key string) error { - cmd := db.client.Del(key) - if cmd.Err() != nil { - return errors.E(cmd.Err(), util.ErrNotDeleted) - } - return nil -} - -func (db *Redis) IsReady() bool { - if db.client == nil { - return false - } - return db.client.Ping().Err() == nil -} diff --git a/pkg/storage/util/errors.go b/pkg/storage/util/errors.go deleted file mode 100644 index 162401f98..000000000 --- a/pkg/storage/util/errors.go +++ /dev/null @@ -1,14 +0,0 @@ -package util - -import ( - "github.com/trustwallet/blockatlas/pkg/errors" -) - -var ( - ErrNotFound = errors.E("storage: obj not found") - ErrNotStored = errors.E("storage: not stored") - ErrNotUpdated = errors.E("storage: not updated") - ErrNotDeleted = errors.E("storage: not deleted") - ErrInvalidType = errors.E("storage: invalid type") - ErrAlreadyExist = errors.E("storage: object already exist") -) diff --git a/platform/binance/model.go b/platform/binance/model.go index d54d9e5e6..8523d0968 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -104,7 +104,7 @@ func (subTxs *SubTxs) getTxs() (txs []Tx) { if err != nil { subTxValue = 0 } - value := numbers.Float64toString(txValue+subTxValue) + value := numbers.Float64toString(txValue + subTxValue) tx.Value = json.Number(value) mapTx[key] = tx } diff --git a/platform/binance/transaction.go b/platform/binance/transaction.go index 289fe6fc6..ba8ab2111 100644 --- a/platform/binance/transaction.go +++ b/platform/binance/transaction.go @@ -65,7 +65,7 @@ func normalizeTransfer(tx blockatlas.Tx, srcTx Tx, token, address string) (block txs := make(blockatlas.TxPage, 0) // Parse all assets as a transaction for _, subTx := range srcTx.SubTxsDto.SubTxDtoList.getTxs() { - // If this is not called from a block observer, only get the user txs/assets + // If this is not called from a block observer_test, only get the user txs/assets if !subTx.containAddress(address) { continue } diff --git a/platform/tezos/model_test.go b/platform/tezos/model_test.go index 9d8151648..7243c1a95 100644 --- a/platform/tezos/model_test.go +++ b/platform/tezos/model_test.go @@ -66,7 +66,7 @@ func TestTransaction_Status(t *testing.T) { in Transaction out int64 }{ - {"Delegation", Transaction{Time: "2020-02-04T12:27:59Z",}, 1580819279}, + {"Delegation", Transaction{Time: "2020-02-04T12:27:59Z"}, 1580819279}, } for _, tt := range testsBlockTimestamp { @@ -80,10 +80,10 @@ func TestTransaction_Status(t *testing.T) { in Transaction out blockatlas.TransactionType }{ - {"Type should be transaction", Transaction{Type: "transaction",}, blockatlas.TxTransfer}, - {"Type should be delegation", Transaction{Type: "delegation",}, blockatlas.TxAnyAction}, - {"Type unsupported", Transaction{Type: "bake",}, ""}, - {"Type endorsement", Transaction{Type: "endorsement",}, ""}, + {"Type should be transaction", Transaction{Type: "transaction"}, blockatlas.TxTransfer}, + {"Type should be delegation", Transaction{Type: "delegation"}, blockatlas.TxAnyAction}, + {"Type unsupported", Transaction{Type: "bake"}, ""}, + {"Type endorsement", Transaction{Type: "endorsement"}, ""}, } for _, tt := range testsKind { diff --git a/scripts/.goreleaser.yml b/scripts/.goreleaser.yml index a9ea72828..f183aab9b 100644 --- a/scripts/.goreleaser.yml +++ b/scripts/.goreleaser.yml @@ -12,9 +12,9 @@ builds: - amd64 env: - CGO_ENABLED=0 - - id: observer - binary: observer - main: "./cmd/observer/main.go" + - id: observer_test + binary: observer_test + main: "./cmd/observer_test/main.go" goos: - linux goarch: diff --git a/scripts/run_tests_postman.sh b/scripts/run_tests_postman.sh index 0877438be..e18f11401 100644 --- a/scripts/run_tests_postman.sh +++ b/scripts/run_tests_postman.sh @@ -8,4 +8,4 @@ make newman test=token host=$1 make newman test=staking host=$1 make newman test=collection host=$1 make newman test=domain host=$1 -make newman test=observer host=$1 +make newman test=observer_test host=$1 diff --git a/services/observer/healthcheck/healthcheck.go b/services/observer/healthcheck/healthcheck.go deleted file mode 100644 index 1fbde8ae5..000000000 --- a/services/observer/healthcheck/healthcheck.go +++ /dev/null @@ -1,112 +0,0 @@ -package healthcheck - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" - "sync" - "time" -) - -var observerStatus status - -func init() { - observerStatus = status{ - m: make(map[string]Info), - } -} - -type status struct { - m map[string]Info - sync.RWMutex -} - -func (cr *status) update(coin string, info Info) { - cr.Lock() - cr.m[coin] = info - cr.Unlock() -} - -func (cr *status) get() map[string]Info { - cr.RLock() - defer cr.RUnlock() - return cr.m -} - -func Worker(storage storage.Tracker, api blockatlas.BlockAPI) { - var ( - lastParsedBlock, currentBlock int64 - err error - ) - - lastParsedBlock, err = storage.GetLastParsedBlockNumber(api.Coin().ID) - if err != nil { - logger.Fatal(err) - } - - var duration time.Duration - t := api.Coin().BlockTime / 1000 - - if t > 30 { - duration = time.Duration(int64(time.Second) * int64(t)) - } else { - duration = time.Minute * 11 - } - logger.Info("Setting update duration", logger.Params{"duration": duration}) - - for { - currentBlock, err = storage.GetLastParsedBlockNumber(api.Coin().ID) - if err != nil { - logger.Error(err) - continue - } - - latestBlock, err := api.CurrentBlockNumber() - if err != nil { - logger.Error(err) - continue - } - - logger.Info("fetched", logger.Params{"currentBlock": currentBlock, "lastParsedBlock": lastParsedBlock, "latestBlock": latestBlock, "handle": api.Coin().Handle}) - - if currentBlock > lastParsedBlock || latestBlock == currentBlock { - lastParsedBlock = currentBlock - observerStatus.update(api.Coin().Handle, Info{ - LastParsedBlock: lastParsedBlock, - Healthy: true, - }) - } else { - observerStatus.update(api.Coin().Handle, Info{ - LastParsedBlock: lastParsedBlock, - Healthy: false, - }) - } - - time.Sleep(duration) - } -} - -func GetStatus(exclude []string) map[string]interface{} { - total := true - result := make(map[string]interface{}) - status := observerStatus.get() - for k, v := range status{ - if !contain(k, exclude){ - if v.Healthy == false{ - total = false - } - result[k] = v - } - } - result["total"] = total - return result -} - -func contain(elem string, list []string) bool{ - for _, v := range list{ - if v == elem{ - return true - } - } - return false -} diff --git a/services/observer/healthcheck/model.go b/services/observer/healthcheck/model.go deleted file mode 100644 index 6a4fa944c..000000000 --- a/services/observer/healthcheck/model.go +++ /dev/null @@ -1,6 +0,0 @@ -package healthcheck - -type Info struct { - LastParsedBlock int64 `json:"lastParsedBlock"` - Healthy bool `json:"healthy"` -} diff --git a/services/observer/notifier/notifier.go b/services/observer/notifier/notifier.go index 0f75260b2..16e97ffbc 100644 --- a/services/observer/notifier/notifier.go +++ b/services/observer/notifier/notifier.go @@ -3,12 +3,12 @@ package notifier import ( "encoding/json" "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" - "github.com/trustwallet/blockatlas/storage" "sync" "time" ) @@ -16,10 +16,10 @@ import ( type DispatchEvent struct { Action blockatlas.TransactionType `json:"action"` Result *blockatlas.Tx `json:"result"` - GUID string `json:"guid"` + Id uint `json:"id"` } -func RunNotifier(delivery amqp.Delivery, s storage.Addresses) { +func RunNotifier(database *db.Instance, delivery amqp.Delivery) { defer func() { if err := delivery.Ack(false); err != nil { logger.Error(err) @@ -42,15 +42,18 @@ func RunNotifier(delivery amqp.Delivery, s storage.Addresses) { } addresses := blockTransactions.GetUniqueAddresses() - subs, err := s.FindSubscriptions(txs[0].Coin, addresses) - if err != nil || len(subs) == 0 { + subscriptionsDataList, err := database.GetSubscriptionData(txs[0].Coin, addresses) + if err != nil || len(subscriptionsDataList) == 0 { return } var wg sync.WaitGroup - wg.Add(len(subs)) - for _, sub := range subs { - go buildAndPostMessage(blockTransactions, sub, &wg) + wg.Add(len(subscriptionsDataList)) + for _, data := range subscriptionsDataList { + go buildAndPostMessage( + blockTransactions, + blockatlas.Subscription{Coin: data.Coin, Address: data.Address, Id: data.SubscriptionId}, + &wg) } wg.Wait() } @@ -67,30 +70,30 @@ func buildAndPostMessage(blockTransactions blockatlas.TxSetMap, sub blockatlas.S action := DispatchEvent{ Action: tx.Type, Result: &tx, - GUID: sub.GUID, + Id: sub.Id, } txJson, err := json.Marshal(action) if err != nil { - logger.Panic(err) + logger.Panic(err, logger.Params{"coin": tx.Coin}) } logParams := logger.Params{ - "guid": sub.GUID, + "Id": sub.Id, "coin": sub.Coin, "txID": tx.ID, } - publishTransaction(sub.GUID, txJson, logParams) + publishTransaction(sub.Id, txJson, logParams) } } -func publishTransaction(message string, rawMessage []byte, logParams logger.Params) { +func publishTransaction(id uint, rawMessage []byte, logParams logger.Params) { err := mq.Transactions.Publish(rawMessage) if err != nil { - err = errors.E(err, "Failed to dispatch event", errors.Params{"message": message}, logParams) - logger.Fatal(err, logger.Params{"message": message}, logParams) + err = errors.E(err, "Failed to dispatch event", errors.Params{"id": id}, logParams) + logger.Fatal(err, logger.Params{"id": id}, logParams) } - logger.Info("Message dispatched", logger.Params{"message": message}, logParams) + logger.Info("Message dispatched", logger.Params{"id": id}, logParams) } func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duration { diff --git a/services/observer/parser/parser.go b/services/observer/parser/parser.go index bcec76430..10d71a2f8 100644 --- a/services/observer/parser/parser.go +++ b/services/observer/parser/parser.go @@ -4,13 +4,13 @@ import ( "context" "encoding/json" "fmt" + "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "sync/atomic" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" "math/rand" "sort" "sync" @@ -21,13 +21,13 @@ type ( Params struct { Ctx context.Context Api blockatlas.BlockAPI - Storage storage.Tracker Queue mq.Queue ParsingBlocksInterval time.Duration BacklogCount int MaxBacklogBlocks int64 StopChannel chan<- struct{} TxBatchLimit uint + Database *db.Instance } GetBlockByNumber func(num int64) (*blockatlas.Block, error) @@ -79,7 +79,7 @@ func RunParser(params Params) { } func GetBlocksIntervalToFetch(params Params) (int64, int64, error) { - lastParsedBlock, err := params.Storage.GetLastParsedBlockNumber(params.Api.Coin().ID) + lastParsedBlock, err := params.Database.GetLastParsedBlockNumber(params.Api.Coin().ID) if err != nil { return 0, 0, errors.E(err, "Polling failed: tracker didn't return last known block number") } @@ -174,8 +174,7 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { }) lastBlockNumber := blocks[len(blocks)-1].Number - - err := params.Storage.SetLastParsedBlockNumber(params.Api.Coin().ID, lastBlockNumber) + err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().ID, lastBlockNumber) if err != nil { return err } diff --git a/services/observer/parser/parser_test.go b/services/observer/parser/parser_test.go index 38457c659..6b6d36966 100644 --- a/services/observer/parser/parser_test.go +++ b/services/observer/parser/parser_test.go @@ -2,13 +2,9 @@ package parser import ( "errors" - "fmt" - "github.com/alicebob/miniredis" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" "sync" "testing" "time" @@ -66,48 +62,11 @@ var ( } ) -func Test_GetBlocksIntervalToFetch(t *testing.T) { - - params := Params{ - ParsingBlocksInterval: time.Minute, - BacklogCount: 10, - MaxBacklogBlocks: 100, - Storage: getMockedRedis(t), - Api: getMockedBlockAPI(), - } - latestParsedBlock := int64(100) - wantedMockedNumber = 110 - lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params) - assert.Nil(t, err) - assert.Equal(t, wantedMockedNumber, currentBlock) - assert.Equal(t, latestParsedBlock, lastParsedBlock) -} - func TestFetchBlocks(t *testing.T) { blocks := FetchBlocks(getMockedBlockAPI(), 0, 100) assert.Equal(t, len(blocks), 100) } -func TestSaveLastParsedBlock(t *testing.T) { - blocks := make([]blockatlas.Block, 0) - blocks = append(blocks, block) - s := getMockedRedis(t) - - params := Params{ - ParsingBlocksInterval: time.Minute, - BacklogCount: 10, - MaxBacklogBlocks: 100, - Storage: s, - Api: getMockedBlockAPI(), - } - err := SaveLastParsedBlock(params, blocks) - assert.Nil(t, err) - - lastParsedBlock, err := s.GetLastParsedBlockNumber(getMockedBlockAPI().Coin().ID) - assert.Nil(t, err) - assert.Equal(t, lastParsedBlock, int64(110)) -} - func TestParser_ConvertToBatch(t *testing.T) { blocks := []blockatlas.Block{block, block, block, block} txs := ConvertToBatch(blocks) @@ -174,20 +133,6 @@ func getMockedBlockAPI() blockatlas.BlockAPI { return &p } -func getMockedRedis(t *testing.T) *storage.Storage { - s, err := miniredis.Run() - if err != nil { - t.Fatal(err) - } - - cache := storage.New() - err = cache.Init(fmt.Sprintf("redis://%s", s.Addr())) - if err != nil { - logger.Fatal(err) - } - return cache -} - type Platform struct { CoinIndex uint } diff --git a/services/observer/subscriber/subscriber.go b/services/observer/subscriber/subscriber.go index dc9cc4a9a..40ab2905f 100644 --- a/services/observer/subscriber/subscriber.go +++ b/services/observer/subscriber/subscriber.go @@ -3,9 +3,10 @@ package subscriber import ( "encoding/json" "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/storage" ) const ( @@ -14,36 +15,34 @@ const ( UpdateSubscription blockatlas.SubscriptionOperation = "UpdateSubscription" ) -func RunSubscriber(delivery amqp.Delivery, storage storage.Addresses) { +func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { var event blockatlas.SubscriptionEvent err := json.Unmarshal(delivery.Body, &event) if err != nil { logger.Fatal(err) } - newSubscriptions := event.ParseSubscriptions(event.NewSubscriptions) - oldSubscriptions := event.ParseSubscriptions(event.OldSubscriptions) - params := logger.Params{"operation": event.Operation, "guid": event.GUID, "new_subscriptions_len": len(newSubscriptions), "old_subscriptions_len": len(oldSubscriptions)} + subscriptions := event.ParseSubscriptions(event.Subscriptions) + + params := logger.Params{"operation": event.Operation, "id": event.Id, "subscriptions_len": len(subscriptions)} + + id := event.Id switch event.Operation { case UpdateSubscription: - err := storage.DeleteSubscriptions(oldSubscriptions) - if err != nil { - logger.Error(err, params) - } - err = storage.AddSubscriptions(newSubscriptions) + err := database.AddToExistingSubscription(id, ToSubscriptionData(subscriptions)) if err != nil { logger.Error(err, params) } logger.Info("Updated", params) case AddSubscription: - err = storage.AddSubscriptions(newSubscriptions) + err = database.AddSubscriptions(id, ToSubscriptionData(subscriptions)) if err != nil { logger.Error(err, params) } logger.Info("Added", params) case DeleteSubscription: - err := storage.DeleteSubscriptions(oldSubscriptions) + err := database.DeleteAllSubscriptions(id) if err != nil { logger.Error(err, params) } @@ -55,3 +54,11 @@ func RunSubscriber(delivery amqp.Delivery, storage storage.Addresses) { logger.Error(err, params) } } + +func ToSubscriptionData(sub []blockatlas.Subscription) []models.SubscriptionData { + data := make([]models.SubscriptionData, 0, len(sub)) + for _, s := range sub { + data = append(data, models.SubscriptionData{Coin: s.Coin, Address: s.Address, SubscriptionId: s.Id}) + } + return data +} diff --git a/storage/addresses.go b/storage/addresses.go deleted file mode 100644 index 8a3a1cfda..000000000 --- a/storage/addresses.go +++ /dev/null @@ -1,147 +0,0 @@ -package storage - -import ( - "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "sync" -) - -const ( - ATLAS_OBSERVER = "ATLAS_OBSERVER" -) - -type SubscriptionOperation func(sub blockatlas.Subscription, wg *sync.WaitGroup, errorsChan chan<- error) - -func (s *Storage) RunOperation(subscriptions []blockatlas.Subscription, operation SubscriptionOperation) error { - var ( - errorsChan = make(chan error, len(subscriptions)) - wg sync.WaitGroup - ) - - for _, sub := range subscriptions { - wg.Add(1) - go operation(sub, &wg, errorsChan) - } - wg.Wait() - close(errorsChan) - - if len(errorsChan) != 0 { - var errorsStr string - for err := range errorsChan { - errorsStr += err.Error() + " " - } - return errors.E(errorsStr) - } - - return nil -} - -func (s *Storage) DeleteSubscriptions(subscriptions []blockatlas.Subscription) error { - return s.RunOperation(subscriptions, s.deleteSubscriptions) -} - -func (s *Storage) AddSubscriptions(subscriptions []blockatlas.Subscription) error { - return s.RunOperation(subscriptions, s.addSubscriptions) -} - -func (s *Storage) FindSubscriptions(coin uint, addresses []string) ([]blockatlas.Subscription, error) { - if len(addresses) == 0 { - return nil, errors.E("cannot look up an empty list") - } - - observersSliceChan := make(chan []blockatlas.Subscription, len(addresses)) - observers := make([]blockatlas.Subscription, 0, len(addresses)) - - var wg sync.WaitGroup - wg.Add(len(addresses)) - - for _, address := range addresses { - go s.findSubscriptionsByAddress(coin, address, observersSliceChan, &wg) - } - wg.Wait() - close(observersSliceChan) - - for slice := range observersSliceChan { - for _, v := range slice { - observers = append(observers, v) - } - } - - return observers, nil -} - -func (s *Storage) findSubscriptionsByAddress(coin uint, address string, sub chan<- []blockatlas.Subscription, wg *sync.WaitGroup) { - defer wg.Done() - key := getSubscriptionKey(coin, address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - if err != nil { - return - } - - result := make([]blockatlas.Subscription, 0, len(guids)) - - for _, guid := range guids { - result = append(result, blockatlas.Subscription{Coin: coin, Address: address, GUID: guid}) - } - - sub <- result -} - -func (s *Storage) deleteSubscriptions(sub blockatlas.Subscription, wg *sync.WaitGroup, errorsChan chan<- error) { - defer wg.Done() - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - if err != nil { - errorsChan <- err - return - } - newHooks := make([]string, 0) - for _, guid := range guids { - if guid == sub.GUID { - continue - } - newHooks = append(newHooks, guid) - } - if len(newHooks) == 0 { - _ = s.DeleteHM(ATLAS_OBSERVER, key) - return - } - err = s.AddHM(ATLAS_OBSERVER, key, newHooks) - if err != nil { - errorsChan <- err - } -} - -func (s *Storage) addSubscriptions(sub blockatlas.Subscription, wg *sync.WaitGroup, errorsChan chan<- error) { - defer wg.Done() - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - s.GetHMValue(ATLAS_OBSERVER, key, &guids) - if guids == nil { - guids = make([]string, 0) - } - if hasObject(guids, sub.GUID) { - return - } - guids = append(guids, sub.GUID) - err := s.AddHM(ATLAS_OBSERVER, key, guids) - if err != nil { - errorsChan <- err - } -} - -func getSubscriptionKey(coin uint, address string) string { - return fmt.Sprintf("%d-%s", coin, address) -} - -func hasObject(array []string, obj string) bool { - for _, temp := range array { - if temp == obj { - return true - } - } - return false -} diff --git a/storage/addresses_test.go b/storage/addresses_test.go deleted file mode 100644 index 52ef3856e..000000000 --- a/storage/addresses_test.go +++ /dev/null @@ -1,347 +0,0 @@ -package storage - -import ( - "fmt" - "github.com/alicebob/miniredis" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" - "testing" -) - -func TestStorage_Lookup(t *testing.T) { - s := initStorage(t) - assert.NotNil(t, s) - - type fields struct { - coin int - addresses []string - } - tests := []struct { - name string - fields fields - wantData []blockatlas.Subscription - wantCondition bool - }{ - {"test all guids found", - fields{coin: 60, addresses: []string{"1", "2", "3"}}, - []blockatlas.Subscription{ - {Coin: 60, Address: "1", GUID: "1"}, - {Coin: 60, Address: "2", GUID: "2"}, - {Coin: 60, Address: "3", GUID: "3"}, - }, - true, - }, - {"test not found", - fields{coin: 60, addresses: []string{"1", "4", "3"}}, - []blockatlas.Subscription{ - {Coin: 60, Address: "1", GUID: "1"}, - {Coin: 60, Address: "2", GUID: "2"}, - {Coin: 60, Address: "3", GUID: "3"}, - }, - false, - }, - } - - for _, tt := range tests { - for i, a := range tt.fields.addresses { - key := getSubscriptionKey(uint(tt.fields.coin), a) - err := s.AddHM(ATLAS_OBSERVER, key, []string{tt.wantData[i].GUID}) - if err != nil { - t.Fatal(err) - } - } - - t.Run(tt.name, func(t *testing.T) { - if got, err := s.FindSubscriptions(uint(tt.fields.coin), tt.fields.addresses); !(isEqualSubscriptions(got, tt.wantData) == tt.wantCondition) || err != nil { - t.Fatal(got) - } - }) - } -} - -func TestStorage_Lookup_MultipleGUIDs(t *testing.T) { - s := initStorage(t) - assert.NotNil(t, s) - - want := []blockatlas.Subscription{ - {Coin: 60, Address: "1", GUID: "1"}, - {Coin: 60, Address: "2", GUID: "2"}, - {Coin: 60, Address: "2", GUID: "3"}, - {Coin: 60, Address: "3", GUID: "3"}, - } - - key1 := getSubscriptionKey(uint(60), "1") - err := s.AddHM(ATLAS_OBSERVER, key1, []string{"1"}) - if err != nil { - t.Fatal(err) - } - - key2 := getSubscriptionKey(uint(60), "2") - err = s.AddHM(ATLAS_OBSERVER, key2, []string{"2", "3"}) - if err != nil { - t.Fatal(err) - } - - key3 := getSubscriptionKey(uint(60), "3") - err = s.AddHM(ATLAS_OBSERVER, key3, []string{"3"}) - if err != nil { - t.Fatal(err) - } - - given, err := s.FindSubscriptions(uint(60), []string{"1", "2", "3"}) - assert.Nil(t, err) - assert.True(t, isEqualSubscriptions(given, want)) -} - -func TestStorage_Lookup_NotFoundSeveral(t *testing.T) { - s := initStorage(t) - assert.NotNil(t, s) - - want := []blockatlas.Subscription{ - {Coin: 60, Address: "1", GUID: "1"}, - } - - key1 := getSubscriptionKey(uint(60), "1") - err := s.AddHM(ATLAS_OBSERVER, key1, []string{"1"}) - if err != nil { - t.Fatal(err) - } - - key2 := getSubscriptionKey(uint(60), "2") - err = s.AddHM(ATLAS_OBSERVER, key2, []string{"2", "3"}) - if err != nil { - t.Fatal(err) - } - - key3 := getSubscriptionKey(uint(60), "3") - err = s.AddHM(ATLAS_OBSERVER, key3, []string{"3"}) - if err != nil { - t.Fatal(err) - } - - given, err := s.FindSubscriptions(uint(60), []string{"1", "4", "5"}) - assert.Nil(t, err) - assert.True(t, isEqualSubscriptions(given, want)) -} - -func TestStorage_AddSubscriptions(t *testing.T) { - s := initStorage(t) - assert.NotNil(t, s) - - subs := []blockatlas.Subscription{ - {Coin: 60, Address: "1", GUID: "1"}, - {Coin: 144, Address: "11212", GUID: "112"}, - {Coin: 144, Address: "112121", GUID: "112"}, - } - var want []string - for _, sub := range subs { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - assert.NotNil(t, err) - assert.Equal(t, want, guids) - } - - err := s.AddSubscriptions(subs) - assert.Nil(t, err) - - for _, sub := range subs { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - assert.Nil(t, err) - assert.NotNil(t, guids) - - var counter int - for _, g := range guids { - if g == sub.GUID { - counter++ - } - } - assert.True(t, counter == 1) - } - - NewSubs := []blockatlas.Subscription{ - {Coin: 714, Address: "2", GUID: "2"}, - {Coin: 148, Address: "21", GUID: "21"}, - {Coin: 148, Address: "21", GUID: "21"}, - } - - err = s.AddSubscriptions(NewSubs) - assert.Nil(t, err) - - for _, sub := range subs { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - assert.Nil(t, err) - assert.NotNil(t, guids) - - var counter int - for _, g := range guids { - if g == sub.GUID { - counter++ - } - } - assert.True(t, counter == 1) - } - - for _, sub := range NewSubs { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - assert.Nil(t, err) - assert.NotNil(t, guids) - - var counter int - for _, g := range guids { - if g == sub.GUID { - counter++ - } - } - assert.True(t, counter == 1) - } - - NotExistingSubs := []blockatlas.Subscription{ - {Coin: 111, Address: "2", GUID: "2"}, - {Coin: 222, Address: "21", GUID: "21"}, - } - - for _, sub := range NotExistingSubs { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - assert.NotNil(t, err) - assert.Nil(t, guids) - - var counter int - for _, g := range guids { - if g == sub.GUID { - counter++ - } - } - assert.False(t, counter == 1) - } -} - -func TestStorage_DeleteSubscriptions(t *testing.T) { - s := initStorage(t) - assert.NotNil(t, s) - - subs := []blockatlas.Subscription{ - {Coin: 60, Address: "1", GUID: "1"}, - {Coin: 144, Address: "11212", GUID: "112"}, - {Coin: 255, Address: "112121", GUID: "1121"}, - } - var want []string - for _, sub := range subs { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - assert.NotNil(t, err) - assert.Equal(t, want, guids) - } - - err := s.AddSubscriptions(subs) - assert.Nil(t, err) - - for _, sub := range subs { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - assert.Nil(t, err) - assert.NotNil(t, guids) - - var counter int - for _, g := range guids { - if g == sub.GUID { - counter++ - } - } - assert.True(t, counter == 1) - } - - deleted_subs := []blockatlas.Subscription{ - {Coin: 60, Address: "1", GUID: "1"}, - {Coin: 144, Address: "11212", GUID: "112"}, - } - - err = s.DeleteSubscriptions(deleted_subs) - assert.Nil(t, err) - - for _, sub := range deleted_subs { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - assert.NotNil(t, err) - assert.Nil(t, guids) - - var counter int - for _, g := range guids { - if g == sub.GUID { - counter++ - } - } - assert.True(t, counter == 0) - } - - existing_subs := []blockatlas.Subscription{ - {Coin: 255, Address: "112121", GUID: "1121"}, - } - - for _, sub := range existing_subs { - key := getSubscriptionKey(sub.Coin, sub.Address) - var guids []string - err := s.GetHMValue(ATLAS_OBSERVER, key, &guids) - assert.Nil(t, err) - assert.NotNil(t, guids) - - var counter int - for _, g := range guids { - if g == sub.GUID { - counter++ - } - } - assert.True(t, counter == 1) - } -} - -func isEqualSubscriptions(given, want []blockatlas.Subscription) bool { - if len(given) != len(want) { - return false - } - var givenCounter int - for _, g := range given { - var wantCounter int - for _, w := range want { - if w == g { - wantCounter++ - } - } - if wantCounter > 0 { - givenCounter++ - } - } - - if givenCounter == len(want) { - return true - } - return false -} - -func initStorage(t *testing.T) *Storage { - s, err := miniredis.Run() - if err != nil { - t.Fatal(err) - } - - storage := New() - err = storage.Init(fmt.Sprintf("redis://%s", s.Addr())) - if err != nil { - logger.Fatal(err) - } - return storage -} diff --git a/storage/storage.go b/storage/storage.go deleted file mode 100644 index 284977603..000000000 --- a/storage/storage.go +++ /dev/null @@ -1,51 +0,0 @@ -package storage - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/pkg/storage/redis" - "time" -) - -type Storage struct { - redis.Redis - blockHeights BlockMap -} - -func New() *Storage { - s := new(Storage) - s.blockHeights.heights = make(map[uint]int64) - return s -} - -func RestoreConnectionWorker(storage *Storage, uri string, timeout time.Duration) { - logger.Info("Run Redis RestoreConnectionWorker") - for { - if !storage.IsReady() { - for { - logger.Warn("Redis is not available now") - logger.Warn("Trying to connect to MQ...") - if err := storage.Init(uri); err != nil { - logger.Warn("Redis is still unavailable") - time.Sleep(timeout) - continue - } else { - logger.Info("Redis connection restored") - break - } - } - } - time.Sleep(timeout) - } -} - -type Tracker interface { - GetLastParsedBlockNumber(coin uint) (int64, error) - SetLastParsedBlockNumber(coin uint, num int64) error -} - -type Addresses interface { - FindSubscriptions(coin uint, addresses []string) ([]blockatlas.Subscription, error) - AddSubscriptions(subscriptions []blockatlas.Subscription) error - DeleteSubscriptions(subscriptions []blockatlas.Subscription) error -} diff --git a/storage/tracker.go b/storage/tracker.go deleted file mode 100644 index 78ab2b678..000000000 --- a/storage/tracker.go +++ /dev/null @@ -1,56 +0,0 @@ -package storage - -import ( - "fmt" - "sync" -) - -const ( - ATLAS_BLOCK_NUMBER = "ATLAS_BLOCK_NUMBER_%d" -) - -type BlockMap struct { - heights map[uint]int64 - lock sync.RWMutex -} - -func (bm *BlockMap) SetBlock(coin uint, b int64) { - bm.lock.Lock() - defer bm.lock.Unlock() - bm.heights[coin] = b -} - -func (bm *BlockMap) GetBlock(coin uint) (int64, bool) { - bm.lock.RLock() - defer bm.lock.RUnlock() - b, ok := bm.heights[coin] - return b, ok -} - -func (bm *BlockMap) GetHeights() map[uint]int64 { - bm.lock.RLock() - defer bm.lock.RUnlock() - return bm.heights -} - -func (s *Storage) GetLastParsedBlockNumber(coin uint) (int64, error) { - b, ok := s.blockHeights.GetBlock(coin) - if ok { - return b, nil - } - - err := s.GetValue(getBlockKey(coin), &b) - if err != nil { - return 0, nil - } - return b, nil -} - -func (s *Storage) SetLastParsedBlockNumber(coin uint, num int64) error { - s.blockHeights.SetBlock(coin, num) - return s.Add(getBlockKey(coin), num) -} - -func getBlockKey(coin uint) string { - return fmt.Sprintf(ATLAS_BLOCK_NUMBER, coin) -} diff --git a/storage/tracker_test.go b/storage/tracker_test.go deleted file mode 100644 index 56a7a3072..000000000 --- a/storage/tracker_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package storage - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestBlockMap(t *testing.T) { - s := initStorage(t) - assert.NotNil(t, s) - - block, err := s.GetLastParsedBlockNumber(60) - assert.Nil(t, err) - assert.Equal(t, int64(0), block) - - newBlock := int64(1400) - - err = s.SetLastParsedBlockNumber(60, newBlock) - assert.Nil(t, err) - - current, err := s.GetLastParsedBlockNumber(60) - assert.Nil(t, err) - assert.Equal(t, newBlock, current) -} diff --git a/tests/docker_test/setup/redis.go b/tests/docker_test/setup/redis.go deleted file mode 100644 index 5ae759e71..000000000 --- a/tests/docker_test/setup/redis.go +++ /dev/null @@ -1,43 +0,0 @@ -package setup - -import ( - "fmt" - "github.com/ory/dockertest" - "github.com/trustwallet/blockatlas/storage" - "log" -) - -var ( - Cache *storage.Storage - redisResource *dockertest.Resource -) - -func runRedisContainer() error { - var err error - pool, err := dockertest.NewPool("") - if err != nil { - log.Fatalf("Could not connect to docker: %s", err) - } - - redisResource, err = pool.Run("redis", "latest", nil) - if err != nil { - log.Fatalf("Could not start resource: %s", err) - } - - if err = pool.Retry(func() error { - var err error - Cache = storage.New() - err = Cache.Init(fmt.Sprintf("redis://localhost:%s", redisResource.GetPort("6379/tcp"))) - if err != nil { - return err - } - return nil - }); err != nil { - return err - } - return nil -} - -func stopRedisContainer() error { - return redisResource.Close() -} diff --git a/tests/docker_test/setup/setup.go b/tests/docker_test/setup/setup.go deleted file mode 100644 index 53210ff47..000000000 --- a/tests/docker_test/setup/setup.go +++ /dev/null @@ -1,27 +0,0 @@ -package setup - -import "log" - -func RunRedisContainer() { - if err := runRedisContainer(); err != nil { - log.Fatal(err) - } -} - -func StopRedisContainer() { - if err := stopRedisContainer(); err != nil { - log.Fatal(err) - } -} - -func RunMQContainer() { - if err := runMQContainer(); err != nil { - log.Fatal(err) - } -} - -func StopMQContainer() { - if err := stopMQContainer(); err != nil { - log.Fatal(err) - } -} diff --git a/tests/docker_test/subscriber_test.go b/tests/docker_test/subscriber_test.go deleted file mode 100644 index ca652763a..000000000 --- a/tests/docker_test/subscriber_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// +build integration - -package docker_test - -import ( - "context" - "encoding/json" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/observer/subscriber" - "github.com/trustwallet/blockatlas/storage" - "github.com/trustwallet/blockatlas/tests/docker_test/setup" - "io/ioutil" - "path/filepath" - "runtime" - "testing" - "time" -) - -func TestSubscriberAddSubscription(t *testing.T) { - _, goFile, _, _ := runtime.Caller(0) - testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_added.json") - testFileGiven, err := ioutil.ReadFile(testFilePathGiven) - if err != nil { - t.Fatal(err) - } - var givenEvents []blockatlas.SubscriptionEvent - if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { - t.Fatal(err) - } - - testFilePathWanted := filepath.Join(filepath.Dir(goFile), "data", "wanted_subscriptions_added.json") - testFileWanted, err := ioutil.ReadFile(testFilePathWanted) - if err != nil { - t.Fatal(err) - } - var wantedEvents []blockatlas.Subscription - if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { - t.Fatal(err) - } - - for _, event := range givenEvents { - body, err := json.Marshal(event) - assert.Nil(t, err) - - err = mq.Subscriptions.Publish(body) - assert.Nil(t, err) - - ctx, cancel := context.WithCancel(context.Background()) - - go mq.Subscriptions.RunConsumerForChannelWithCancel(subscriber.RunSubscriber, subscriptionChannel, setup.Cache, ctx) - time.Sleep(time.Second / 5) - cancel() - } - - result, err := setup.Cache.GetAllHM(storage.ATLAS_OBSERVER) - assert.Nil(t, err) - assert.NotNil(t, result) - - for _, wanted := range wantedEvents { - result, err := setup.Cache.FindSubscriptions(wanted.Coin, []string{wanted.Address}) - assert.Nil(t, err) - assert.Equal(t, result[0], wanted) - } -} diff --git a/tests/integration/bitcoin/block.go b/tests/integration/bitcoin/block.go deleted file mode 100755 index 3237b4322..000000000 --- a/tests/integration/bitcoin/block.go +++ /dev/null @@ -1,44 +0,0 @@ -// +build integration - -package bitcoin - -import ( - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/platform/bitcoin" - "testing" -) - -const ( - blockNum = 616070 -) - -func TestBitcoin(t *testing.T) { - t.Run("test bitcoin", func(t *testing.T) { - p := bitcoin.Init(coin.BTC, platform.GetApiVar(coin.BTC)) - testCurrentBlockNumber(p, t) - testGetBlockByNumber(p, t) - }) -} - -func testCurrentBlockNumber(p *bitcoin.Platform, t *testing.T) { - resp, err := p.CurrentBlockNumber() - if err != nil { - t.Error(err) - } - if resp < 0 { - t.Error("block is < 0") - } -} - -func testGetBlockByNumber(p *bitcoin.Platform, t *testing.T) { - resp, err := p.GetBlockByNumber(int64(blockNum)) - if err != nil { - t.Error(err) - } - - expectedTxs := 2129 - if len(resp.Txs) != expectedTxs { - t.Errorf("invalid tx count for block %d, expected %d", len(resp.Txs), expectedTxs) - } -} diff --git a/tests/integration/db_test/db_run_test.go b/tests/integration/db_test/db_run_test.go new file mode 100644 index 000000000..061c11bb0 --- /dev/null +++ b/tests/integration/db_test/db_run_test.go @@ -0,0 +1,25 @@ +// +build integration + +package db_test + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/tests/integration/setup" + "os" + "testing" +) + +var database *db.Instance + +func TestMain(m *testing.M) { + database = setup.RunPgContainer() + code := m.Run() + setup.StopPgContainer() + os.Exit(code) +} + +func TestPgSetup(t *testing.T) { + assert.NotNil(t, database) + assert.NotNil(t, database.DB) +} diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go new file mode 100644 index 000000000..97e66c665 --- /dev/null +++ b/tests/integration/db_test/subscriptions_test.go @@ -0,0 +1,448 @@ +// +build integration + +package db_test + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/observer/subscriber" + "github.com/trustwallet/blockatlas/tests/integration/setup" + "testing" +) + +func TestDb_AddSubscriptions(t *testing.T) { + setup.CleanupPgContainer(database.DB) + var subscriptions []models.SubscriptionData + + id := uint(1) + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 60, + Address: "testAddr", + }) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 61, + Address: "testAddr2", + }) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 62, + Address: "testAddr3", + }) + + assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + + subs, err := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.NotNil(t, subs) + assert.Equal(t, 1, len(subs)) + assert.Equal(t, subscriptions[0].SubscriptionId, subs[0].SubscriptionId) + assert.Equal(t, subscriptions[0].Coin, subs[0].Coin) + assert.Equal(t, subscriptions[0].Address, subs[0].Address) + + subs, err = database.GetSubscriptionData(61, []string{"testAddr2"}) + assert.Nil(t, err) + assert.NotNil(t, subs) + assert.Equal(t, 1, len(subs)) + assert.Equal(t, subscriptions[1].SubscriptionId, subs[0].SubscriptionId) + assert.Equal(t, subscriptions[1].Coin, subs[0].Coin) + assert.Equal(t, subscriptions[1].Address, subs[0].Address) + + subs, err = database.GetSubscriptionData(62, []string{"testAddr3"}) + assert.Nil(t, err) + assert.NotNil(t, subs) + assert.Equal(t, 1, len(subs)) + assert.Equal(t, subscriptions[2].SubscriptionId, subs[0].SubscriptionId) + assert.Equal(t, subscriptions[2].Coin, subs[0].Coin) + assert.Equal(t, subscriptions[2].Address, subs[0].Address) +} + +func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { + setup.CleanupPgContainer(database.DB) + id := uint(1) + + var subscriptions []models.SubscriptionData + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 60, + Address: "testAddr", + }) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 714, + Address: "testAddr", + }) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 144, + Address: "testAddr", + }) + + assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + + subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.NotNil(t, subs60) + assert.Equal(t, 1, len(subs60)) + assert.Equal(t, subscriptions[0].SubscriptionId, subs60[0].SubscriptionId) + assert.Equal(t, subscriptions[0].Coin, subs60[0].Coin) + assert.Equal(t, subscriptions[0].Address, subs60[0].Address) + + subs714, err := database.GetSubscriptionData(714, []string{"testAddr"}) + assert.Nil(t, err) + assert.NotNil(t, subs714) + assert.Equal(t, 1, len(subs714)) + assert.Equal(t, subscriptions[1].SubscriptionId, subs714[0].SubscriptionId) + assert.Equal(t, subscriptions[1].Coin, subs714[0].Coin) + assert.Equal(t, subscriptions[1].Address, subs714[0].Address) + + subs144, err := database.GetSubscriptionData(144, []string{"testAddr"}) + assert.Nil(t, err) + assert.NotNil(t, subs144) + assert.Equal(t, 1, len(subs144)) + assert.Equal(t, subscriptions[2].SubscriptionId, subs144[0].SubscriptionId) + assert.Equal(t, subscriptions[2].Coin, subs144[0].Coin) + assert.Equal(t, subscriptions[2].Address, subs144[0].Address) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 60, + Address: "testAddr2", + }) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 714, + Address: "testAddr2", + }) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 144, + Address: "testAddr2", + }) + + assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + + subs2N60, err := database.GetSubscriptionData(60, []string{"testAddr2"}) + assert.Nil(t, err) + assert.Nil(t, err) + assert.NotNil(t, subs2N60) + assert.Equal(t, 1, len(subs2N60)) + assert.Equal(t, subscriptions[3].SubscriptionId, subs2N60[0].SubscriptionId) + assert.Equal(t, subscriptions[3].Coin, subs2N60[0].Coin) + assert.Equal(t, subscriptions[3].Address, subs2N60[0].Address) + + subs2N714, err := database.GetSubscriptionData(714, []string{"testAddr2"}) + assert.Nil(t, err) + assert.Nil(t, err) + assert.NotNil(t, subs2N714) + assert.Equal(t, 1, len(subs2N714)) + assert.Equal(t, subscriptions[4].SubscriptionId, subs2N714[0].SubscriptionId) + assert.Equal(t, subscriptions[4].Coin, subs2N714[0].Coin) + assert.Equal(t, subscriptions[4].Address, subs2N714[0].Address) + + subs2N114, err := database.GetSubscriptionData(144, []string{"testAddr2"}) + assert.Nil(t, err) + assert.Nil(t, err) + assert.NotNil(t, subs2N114) + assert.Equal(t, 1, len(subs2N114)) + assert.Equal(t, subscriptions[5].SubscriptionId, subs2N114[0].SubscriptionId) + assert.Equal(t, subscriptions[5].Coin, subs2N114[0].Coin) + assert.Equal(t, subscriptions[5].Address, subs2N114[0].Address) +} + +func TestDb_FindSubscriptions(t *testing.T) { + setup.CleanupPgContainer(database.DB) + + var subscriptionsA []blockatlas.Subscription + id := uint(1) + subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ + Id: id, + Coin: 60, + Address: "etherAddress", + }) + + subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ + Id: id, + Coin: 714, + Address: "binanceAddress", + }) + + subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ + Id: id, + Coin: 148, + Address: "AtomAddress", + }) + + subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ + Id: id, + Coin: 144, + Address: "XLMAddress", + }) + + subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ + Id: id, + Coin: 61, + Address: "ETCAddress", + }) + + assert.Nil(t, database.AddSubscriptions(id, subscriber.ToSubscriptionData(subscriptionsA))) + + var subscriptionsB []blockatlas.Subscription + + for _, sub := range subscriptionsA { + sub.Id = uint(2) + subscriptionsB = append(subscriptionsB, sub) + } + assert.Nil(t, database.AddSubscriptions(2, subscriber.ToSubscriptionData(subscriptionsB))) + + returnedSubs, err := database.GetSubscriptionData(60, []string{"etherAddress"}) + assert.Nil(t, err) + assert.Equal(t, 2, len(returnedSubs)) + + returnedSubs, err = database.GetSubscriptionData(714, []string{"binanceAddress"}) + assert.Nil(t, err) + assert.Equal(t, 2, len(returnedSubs)) + + returnedSubs, err = database.GetSubscriptionData(144, []string{"XLMAddress"}) + assert.Nil(t, err) + assert.Equal(t, 2, len(returnedSubs)) + + returnedSubs, err = database.GetSubscriptionData(148, []string{"AtomAddress"}) + assert.Nil(t, err) + assert.Equal(t, 2, len(returnedSubs)) + + returnedSubs, err = database.GetSubscriptionData(61, []string{"ETCAddress"}) + assert.Nil(t, err) + assert.Equal(t, 2, len(returnedSubs)) +} + +func TestDb_DeleteSubscriptions(t *testing.T) { + setup.CleanupPgContainer(database.DB) + var subscriptions []models.SubscriptionData + + id := uint(1) + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 60, + Address: "testAddr", + }) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 714, + Address: "testAddr2", + }) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 144, + Address: "testAddr3", + }) + + assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + + subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.NotNil(t, subs60) + assert.Equal(t, 1, len(subs60)) + assert.Equal(t, subscriptions[0].SubscriptionId, subs60[0].SubscriptionId) + assert.Equal(t, subscriptions[0].Coin, subs60[0].Coin) + assert.Equal(t, subscriptions[0].Address, subs60[0].Address) + + subs714, err := database.GetSubscriptionData(714, []string{"testAddr2"}) + assert.Nil(t, err) + assert.NotNil(t, subs714) + assert.Equal(t, 1, len(subs714)) + assert.Equal(t, subscriptions[1].SubscriptionId, subs714[0].SubscriptionId) + assert.Equal(t, subscriptions[1].Coin, subs714[0].Coin) + assert.Equal(t, subscriptions[1].Address, subs714[0].Address) + + subs144, err := database.GetSubscriptionData(144, []string{"testAddr3"}) + assert.Nil(t, err) + assert.NotNil(t, subs144) + assert.Equal(t, 1, len(subs144)) + assert.Equal(t, subscriptions[2].SubscriptionId, subs144[0].SubscriptionId) + assert.Equal(t, subscriptions[2].Coin, subs144[0].Coin) + assert.Equal(t, subscriptions[2].Address, subs144[0].Address) + + subsToDel := []models.SubscriptionData{subscriptions[0]} + + assert.Nil(t, database.DeleteSubscriptions(subsToDel)) + + subs714N2, err := database.GetSubscriptionData(714, []string{"testAddr2"}) + assert.Nil(t, err) + assert.NotNil(t, subs714N2) + assert.Equal(t, 1, len(subs714N2)) + assert.Equal(t, subscriptions[1].SubscriptionId, subs714N2[0].SubscriptionId) + assert.Equal(t, subscriptions[1].Coin, subs714N2[0].Coin) + assert.Equal(t, subscriptions[1].Address, subs714N2[0].Address) + + subs144N2, err := database.GetSubscriptionData(144, []string{"testAddr3"}) + assert.Nil(t, err) + assert.NotNil(t, subs144N2) + assert.Equal(t, 1, len(subs144N2)) + assert.Equal(t, subscriptions[2].SubscriptionId, subs144N2[0].SubscriptionId) + assert.Equal(t, subscriptions[2].Coin, subs144N2[0].Coin) + assert.Equal(t, subscriptions[2].Address, subs144N2[0].Address) + + subs60N2, err := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.Len(t, subs60N2, 0) +} + +func TestDeleteAll(t *testing.T) { + setup.CleanupPgContainer(database.DB) + var subscriptions []models.SubscriptionData + + id := uint(1) + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 60, + Address: "testAddr", + }) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 714, + Address: "testAddr2", + }) + + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 144, + Address: "testAddr3", + }) + assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + + subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.Len(t, subs60, 1) + + subs714, err := database.GetSubscriptionData(714, []string{"testAddr2"}) + assert.Nil(t, err) + assert.Len(t, subs714, 1) + + subs144, err := database.GetSubscriptionData(144, []string{"testAddr3"}) + assert.Nil(t, err) + assert.Len(t, subs144, 1) + + assert.Nil(t, database.DeleteAllSubscriptions(1)) + + subs60, err = database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.Len(t, subs60, 0) + + subs714, err = database.GetSubscriptionData(714, []string{"testAddr2"}) + assert.Nil(t, err) + assert.Len(t, subs714, 0) + + subs144, err = database.GetSubscriptionData(144, []string{"testAddr3"}) + assert.Nil(t, err) + assert.Len(t, subs144, 0) + + assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + + subs60, err = database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.Len(t, subs60, 1) +} + +func TestDb_DuplicateEntries(t *testing.T) { + setup.CleanupPgContainer(database.DB) + var subscriptions []models.SubscriptionData + + id := uint(1) + + for i := 0; i < 10; i++ { + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: 60, + Address: "testAddr", + }) + } + + assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + + subs, err := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.NotNil(t, subs) + assert.Equal(t, 1, len(subs)) + assert.True(t, containSub(subscriptions[0], subs)) +} + +func TestDb_FindSubscriptions_Multiple(t *testing.T) { + setup.CleanupPgContainer(database.DB) + var subscriptions []models.SubscriptionData + subscriptions = append(subscriptions, models.SubscriptionData{ + Coin: 60, + Address: "testAddr", + }) + + for i := 1; i < 6; i++ { + subscriptions[0].SubscriptionId = uint(i) + assert.Nil(t, database.AddSubscriptions(uint(i), subscriptions)) + } + + subscriptions[0].SubscriptionId = uint(1) + assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions)) + + subs, err := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.Equal(t, 5, len(subs)) + + for i := 0; i < 5; i++ { + assert.Equal(t, uint(i)+1, subs[i].SubscriptionId) + } +} + +func TestDb_AddToExisting(t *testing.T) { + setup.CleanupPgContainer(database.DB) + var subscriptions []models.SubscriptionData + subscriptions = append(subscriptions, models.SubscriptionData{ + Coin: 60, + Address: "testAddr", + }) + + subscriptions[0].SubscriptionId = uint(1) + assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions)) + + subs, err := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.Equal(t, 1, len(subs)) + + assert.Equal(t, uint(1), subs[0].SubscriptionId) + + assert.Nil(t, database.AddToExistingSubscription(uint(1), subscriptions)) + + subs2, err2 := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err2) + assert.Equal(t, 1, len(subs2)) + + assert.Equal(t, uint(1), subs2[0].SubscriptionId) + + assert.Nil(t, database.AddToExistingSubscription(uint(2), subscriptions)) + assert.Nil(t, database.AddToExistingSubscription(uint(1), subscriptions)) + + for i := 1; i < 2; i++ { + assert.Nil(t, database.AddToExistingSubscription(uint(i), subscriptions)) + } + assert.NotNil(t, database.AddToExistingSubscription(uint(0), subscriptions)) + +} + +func containSub(sub models.SubscriptionData, list []models.SubscriptionData) bool { + for _, s := range list { + if sub.Address == s.Address && sub.Coin == s.Coin && sub.SubscriptionId == s.SubscriptionId { + return true + } + } + return false +} diff --git a/tests/integration/db_test/tracker_test.go b/tests/integration/db_test/tracker_test.go new file mode 100644 index 000000000..a05f1c3ab --- /dev/null +++ b/tests/integration/db_test/tracker_test.go @@ -0,0 +1,25 @@ +// +build integration + +package db_test + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/tests/integration/setup" + "testing" +) + +func TestDb_SetBlock(t *testing.T) { + setup.CleanupPgContainer(database.DB) + + assert.Nil(t, database.SetLastParsedBlockNumber(60, 0)) + + block, err := database.GetLastParsedBlockNumber(60) + assert.Nil(t, err) + assert.Equal(t, block, int64(0)) + + assert.Nil(t, database.SetLastParsedBlockNumber(60, 110)) + + newBlock, err := database.GetLastParsedBlockNumber(60) + assert.Nil(t, err) + assert.Equal(t, newBlock, int64(110)) +} diff --git a/tests/integration/domains/domains.go b/tests/integration/domains/domains.go deleted file mode 100644 index a4568b07b..000000000 --- a/tests/integration/domains/domains.go +++ /dev/null @@ -1,129 +0,0 @@ -// +build integration - -package domains - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/domains" -) - -func TestDomains(t *testing.T) { - tests := []struct { - name string - domain string - coins []uint64 - Expected []blockatlas.Resolved - wantErr bool - }{ - { - "test .eth domain", - "vitalik.eth", - []uint64{coin.ETH}, - []blockatlas.Resolved{{Result: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", Coin: coin.ETH}}, - false, - }, - { - "test .luxe domain", - "vitalik.luxe", - []uint64{coin.ETH}, - []blockatlas.Resolved{{Result: "0xD8A667312D5260F12a306Ae7730C754d938da86c", Coin: coin.ETH}}, - false, - }, - { - "test .xyz domain", - "ourxyzwallet.xyz", - []uint64{coin.ETH}, - []blockatlas.Resolved{{Result: "0x0C54eEAd78d555bE3cbCD451424F9A27a7843935", Coin: coin.ETH}}, - false, - }, - { - "test .kred domain", - "Cameron.Kred", - []uint64{coin.ETH}, - []blockatlas.Resolved{{Result: "0xfc9FB438c456C771c0B38a57Cf0e8A3eaB4704fE", Coin: coin.ETH}}, - false, - }, - { - "test .zil domain", - "dpantani.zil", - []uint64{coin.ZIL}, - []blockatlas.Resolved{{Result: "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64", Coin: coin.ZIL}}, - false, - }, - { - "test batch .zil domains", - "dpantani.zil", - []uint64{coin.BTC, coin.ETH, coin.ZIL, coin.LTC, coin.BNB, coin.BCH, coin.DOGE, coin.XRP}, - []blockatlas.Resolved{ - {Result: "bc1qd7eystu9xl53hkyxm4kyg7h5yk4p436sqx6f27", Coin: coin.BTC}, - {Result: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", Coin: coin.ETH}, - {Result: "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64", Coin: coin.ZIL}, - {Result: "ltc1qz6nd472gx5gl3urfeldkrhg3h83c8tp2m7m6sd", Coin: coin.LTC}, - {Result: "bnb1h4vyuuytu4rm86ust29wwlevt95du52383cctm", Coin: coin.BNB}, - {Result: "qzpjlfnzudeu83krv0yk0r2kys67qptj6ys6eg6dms", Coin: coin.BCH}, - {Result: "DP9VmQyDMyB1TWwgXkyRpBa7rTfPYgMvjy", Coin: coin.DOGE}, - {Result: "rUvXBttEXhdwaKjEM2MxbtswHU6AMhUTgJ", Coin: coin.XRP}, - }, - false, - }, - { - "test .crypto domain", - "dpantani.crypto", - []uint64{coin.ZIL}, - []blockatlas.Resolved{ - {Result: "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64", Coin: coin.ZIL}, - }, - false, - }, - //{ - // "test @fiotestnet domain", - // "adam@fiotestnet", - // []uint64{coin.ETH}, - // []blockatlas.Resolved{ - // {Result: "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51", Coin: coin.ETH}, - // }, - // false, - //}, - { - "test batch .crypto domains", - "dpantani.crypto", - []uint64{coin.BTC, coin.ETH, coin.ZIL, coin.LTC, coin.BNB, coin.BCH, coin.DOGE, coin.XRP}, - []blockatlas.Resolved{ - {Result: "bc1qd7eystu9xl53hkyxm4kyg7h5yk4p436sqx6f27", Coin: coin.BTC}, - {Result: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", Coin: coin.ETH}, - {Result: "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64", Coin: coin.ZIL}, - {Result: "ltc1qz6nd472gx5gl3urfeldkrhg3h83c8tp2m7m6sd", Coin: coin.LTC}, - {Result: "bnb1h4vyuuytu4rm86ust29wwlevt95du52383cctm", Coin: coin.BNB}, - {Result: "qzpjlfnzudeu83krv0yk0r2kys67qptj6ys6eg6dms", Coin: coin.BCH}, - {Result: "DP9VmQyDMyB1TWwgXkyRpBa7rTfPYgMvjy", Coin: coin.DOGE}, - {Result: "rUvXBttEXhdwaKjEM2MxbtswHU6AMhUTgJ", Coin: coin.XRP}, - }, - false, - }, - { - "test batch with invalid coin", - "vitalik.eth", - []uint64{44, coin.ETH}, - []blockatlas.Resolved{{Result: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", Coin: coin.ETH}}, - false, - }, - {"test invalid coin", "vitalik.eth", []uint64{44}, nil, false}, - {"test invalid name", "z9z9z900s982jidhwallet.eth", []uint64{coin.ALGO}, nil, true}, - {"test invalid domain", "vitalik.blabla", []uint64{coin.ALGO}, nil, true}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got, err := domains.HandleLookup(test.domain, test.coins) - if test.wantErr { - assert.NotNil(t, err) - return - } - assert.Nil(t, err) - assert.EqualValues(t, test.Expected, got) - }) - } -} diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go deleted file mode 100755 index 218e49061..000000000 --- a/tests/integration/integration_test.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build integration - -package integration - -import ( - "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/tests/integration/bitcoin" - "github.com/trustwallet/blockatlas/tests/integration/domains" - "github.com/trustwallet/blockatlas/tests/integration/ontology" - - "github.com/trustwallet/blockatlas/platform" - "os" - "testing" -) - -func Test(t *testing.T) { - configPath := os.Getenv("TEST_CONFIG") - if configPath == "" { - config.LoadConfig("../../../config.yml") - } else { - config.LoadConfig(configPath) - } - platform.Init(viper.GetString("platform")) - - // Add your integration tests here - ontology.TestOntology(t) - bitcoin.TestBitcoin(t) - domains.TestDomains(t) -} diff --git a/tests/docker_test/data/given_subscriptions_added.json b/tests/integration/observer_test/data/given_subscriptions_added.json similarity index 62% rename from tests/docker_test/data/given_subscriptions_added.json rename to tests/integration/observer_test/data/given_subscriptions_added.json index 6d5efbc84..87fdbc915 100644 --- a/tests/docker_test/data/given_subscriptions_added.json +++ b/tests/integration/observer_test/data/given_subscriptions_added.json @@ -1,42 +1,38 @@ [ { - "new_subscriptions": { + "subscriptions": { "60": [ "0x0000000000000000000000000000000000000000" ] }, - "old_subscriptions": null, - "guid": "0", + "id": 10, "operation": "AddSubscription" }, { - "new_subscriptions": { + "subscriptions": { "118": [ "0x0000000000000000000000000000000000000001" ] }, - "old_subscriptions": null, - "guid": "1", + "id": 1, "operation": "AddSubscription" }, { - "new_subscriptions": { + "subscriptions": { "714": [ "0x0000000000000000000000000000000000000002" ] }, - "old_subscriptions": null, - "guid": "2", + "id": 2, "operation": "AddSubscription" }, { - "new_subscriptions": { + "subscriptions": { "144": [ "0x0000000000000000000000000000000000000003" ] }, - "old_subscriptions": null, - "guid": "3", + "id": 3, "operation": "AddSubscription" } ] diff --git a/tests/integration/observer_test/data/given_subscriptions_deleted.json b/tests/integration/observer_test/data/given_subscriptions_deleted.json new file mode 100644 index 000000000..7c887378b --- /dev/null +++ b/tests/integration/observer_test/data/given_subscriptions_deleted.json @@ -0,0 +1,38 @@ +[ + { + "subscriptions": { + "60": [ + "0x0000000000000000000000000000000000000000" + ] + }, + "id": 10, + "operation": "UpdateSubscription" + }, + { + "subscriptions": { + "118": [ + "0x0000000000000000000000000000000000000001" + ] + }, + "id": 1, + "operation": "UpdateSubscription" + }, + { + "subscriptions": { + "714": [ + "0x0000000000000000000000000000000000000002" + ] + }, + "id": 2, + "operation": "UpdateSubscription" + }, + { + "subscriptions": { + "144": [ + "0x0000000000000000000000000000000000000003" + ] + }, + "id": 3, + "operation": "UpdateSubscription" + } +] diff --git a/tests/docker_test/data/wanted_subscriptions_added.json b/tests/integration/observer_test/data/wanted_subscriptions_added.json similarity index 84% rename from tests/docker_test/data/wanted_subscriptions_added.json rename to tests/integration/observer_test/data/wanted_subscriptions_added.json index c89a4b50d..7007019a0 100644 --- a/tests/docker_test/data/wanted_subscriptions_added.json +++ b/tests/integration/observer_test/data/wanted_subscriptions_added.json @@ -2,21 +2,21 @@ { "coin": 60, "address": "0x0000000000000000000000000000000000000000", - "guid": "0" + "id": 10 }, { "coin": 118, "address": "0x0000000000000000000000000000000000000001", - "guid": "1" + "id": 1 }, { "coin": 714, "address": "0x0000000000000000000000000000000000000002", - "guid": "2" + "id": 2 }, { "coin": 144, "address": "0x0000000000000000000000000000000000000003", - "guid": "3" + "id": 3 } ] diff --git a/tests/docker_test/observer_test.go b/tests/integration/observer_test/full_flow_test.go similarity index 86% rename from tests/docker_test/observer_test.go rename to tests/integration/observer_test/full_flow_test.go index 8c60b2351..0dbe86339 100644 --- a/tests/docker_test/observer_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -1,6 +1,6 @@ // +build integration -package docker_test +package observer_test import ( "context" @@ -8,21 +8,24 @@ import ( "github.com/streadway/amqp" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/observer/notifier" "github.com/trustwallet/blockatlas/services/observer/parser" - "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "github.com/trustwallet/blockatlas/tests/integration/setup" "go.uber.org/atomic" "testing" "time" ) -var counter atomic.Int32 -var counterBlock atomic.Int32 +var ( + currentBlockNumberCounter atomic.Int32 +) func TestFullFlow(t *testing.T) { - err := setup.Cache.AddSubscriptions([]blockatlas.Subscription{{Coin: 60, Address: "testAddress", GUID: "guid_test"}}) + setup.CleanupPgContainer(database.DB) + err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 60, Address: "testAddress", SubscriptionId: 1}}) assert.Nil(t, err) ctx, cancel := context.WithCancel(context.Background()) @@ -30,13 +33,14 @@ func TestFullFlow(t *testing.T) { stopChan := make(chan struct{}, 1) params := setupParserFull(stopChan) + params.Database = database params.Ctx = ctx params.Queue = mq.RawTransactions go parser.RunParser(params) time.Sleep(time.Second * 2) - go mq.RawTransactions.RunConsumerForChannelWithCancel(notifier.RunNotifier, rawTransactionsChannel, setup.Cache, ctx) + go mq.RunConsumerForChannelWithCancelAndDbConn(notifier.RunNotifier, rawTransactionsChannel, database, ctx) time.Sleep(time.Second * 5) for i := 0; i < 11; i++ { @@ -56,8 +60,8 @@ type PlatformFullFlow struct { } func (p *PlatformFullFlow) CurrentBlockNumber() (int64, error) { - i := counterBlock.Load() - counterBlock.Add(1) + i := currentBlockNumberCounter.Load() + currentBlockNumberCounter.Add(1) return int64(i), nil } @@ -131,7 +135,7 @@ func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel Memo: "test", Meta: &memo, }, - GUID: "guid_test", + Id: 1, }, event) if counter == 10 { @@ -150,7 +154,6 @@ func setupParserFull(stopChan chan<- struct{}) parser.Params { return parser.Params{ Api: getMockedBlockAPIFull(), - Storage: setup.Cache, ParsingBlocksInterval: pollInterval, BacklogCount: backlogCount, MaxBacklogBlocks: int64(maxBatchBlocksAmount), diff --git a/tests/docker_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go similarity index 87% rename from tests/docker_test/notifier_test.go rename to tests/integration/observer_test/notifier_test.go index ea9fa9589..31510474a 100644 --- a/tests/docker_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -1,6 +1,6 @@ // +build integration -package docker_test +package observer_test import ( "context" @@ -8,10 +8,11 @@ import ( "github.com/streadway/amqp" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/observer/notifier" - "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "github.com/trustwallet/blockatlas/tests/integration/setup" "testing" "time" ) @@ -41,7 +42,9 @@ var ( ) func TestNotifier(t *testing.T) { - err := setup.Cache.AddSubscriptions([]blockatlas.Subscription{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", GUID: "guid_test"}}) + setup.CleanupPgContainer(database.DB) + + err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", SubscriptionId: 1}}) assert.Nil(t, err) err = produceTxs(txs) @@ -49,7 +52,7 @@ func TestNotifier(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) - go mq.RawTransactions.RunConsumerForChannelWithCancel(notifier.RunNotifier, rawTransactionsChannel, setup.Cache, ctx) + go mq.RunConsumerForChannelWithCancelAndDbConn(notifier.RunNotifier, rawTransactionsChannel, database, ctx) time.Sleep(time.Second * 3) msg := transactionsChannel.GetMessage() ConsumerToTestTransactions(msg, t) @@ -93,7 +96,7 @@ func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { Memo: "test", Meta: &memo, }, - GUID: "guid_test", + Id: 1, }, event) return diff --git a/tests/docker_test/environment_run_test.go b/tests/integration/observer_test/observer_test.go similarity index 64% rename from tests/docker_test/environment_run_test.go rename to tests/integration/observer_test/observer_test.go index 35e38f3a7..dc75b91e1 100644 --- a/tests/docker_test/environment_run_test.go +++ b/tests/integration/observer_test/observer_test.go @@ -1,21 +1,23 @@ // +build integration -package docker_test +package observer_test import ( + "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "github.com/trustwallet/blockatlas/tests/integration/setup" "log" "os" "testing" ) var ( - rawTransactionsChannel, - transactionsChannel, subscriptionChannel mq.MessageChannel + rawTransactionsChannel, transactionsChannel, subscriptionChannel mq.MessageChannel + database *db.Instance ) func TestMain(m *testing.M) { + database = setup.RunPgContainer() setup.RunMQContainer() if err := mq.RawTransactions.Declare(); err != nil { log.Fatal(err) @@ -30,9 +32,9 @@ func TestMain(m *testing.M) { subscriptionChannel = mq.Subscriptions.GetMessageChannel() transactionsChannel = mq.Transactions.GetMessageChannel() - setup.RunRedisContainer() code := m.Run() + setup.StopMQContainer() - setup.StopRedisContainer() + setup.StopPgContainer() os.Exit(code) } diff --git a/tests/docker_test/parser_test.go b/tests/integration/observer_test/parser_test.go similarity index 95% rename from tests/docker_test/parser_test.go rename to tests/integration/observer_test/parser_test.go index 1c1005a04..59e7a85be 100644 --- a/tests/docker_test/parser_test.go +++ b/tests/integration/observer_test/parser_test.go @@ -1,6 +1,6 @@ // +build integration -package docker_test +package observer_test import ( "context" @@ -13,15 +13,17 @@ import ( "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/observer/notifier" "github.com/trustwallet/blockatlas/services/observer/parser" - "github.com/trustwallet/blockatlas/tests/docker_test/setup" + "github.com/trustwallet/blockatlas/tests/integration/setup" "testing" "time" ) func TestParserFetchAndPublishBlock_NormalCase(t *testing.T) { + setup.CleanupPgContainer(database.DB) stopChan := make(chan struct{}, 1) params := setupParser(stopChan) + params.Database = database ctx, cancel := context.WithCancel(context.Background()) @@ -109,7 +111,6 @@ func setupParser(stopChan chan struct{}) parser.Params { return parser.Params{ Api: getMockedBlockAPI(), - Storage: setup.Cache, ParsingBlocksInterval: pollInterval, BacklogCount: backlogCount, MaxBacklogBlocks: int64(maxBatchBlocksAmount), diff --git a/tests/integration/observer_test/subscriber_test.go b/tests/integration/observer_test/subscriber_test.go new file mode 100644 index 000000000..ef52c74b3 --- /dev/null +++ b/tests/integration/observer_test/subscriber_test.go @@ -0,0 +1,146 @@ +// +build integration + +package observer_test + +import ( + "context" + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/observer/subscriber" + "github.com/trustwallet/blockatlas/tests/integration/setup" + "io/ioutil" + "path/filepath" + "runtime" + "testing" + "time" +) + +func TestSubscriberAddSubscription(t *testing.T) { + setup.CleanupPgContainer(database.DB) + + _, goFile, _, _ := runtime.Caller(0) + testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_added.json") + testFileGiven, err := ioutil.ReadFile(testFilePathGiven) + if err != nil { + t.Fatal(err) + } + var givenEvents []blockatlas.SubscriptionEvent + if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { + t.Fatal(err) + } + + testFilePathWanted := filepath.Join(filepath.Dir(goFile), "data", "wanted_subscriptions_added.json") + testFileWanted, err := ioutil.ReadFile(testFilePathWanted) + if err != nil { + t.Fatal(err) + } + var wantedEvents []blockatlas.Subscription + if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { + t.Fatal(err) + } + + for _, event := range givenEvents { + body, err := json.Marshal(event) + assert.Nil(t, err) + + err = mq.Subscriptions.Publish(body) + assert.Nil(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + + go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunSubscriber, subscriptionChannel, database, ctx) + time.Sleep(time.Second * 2) + cancel() + } + + for _, wanted := range wantedEvents { + result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}) + assert.Nil(t, err) + assert.Equal(t, result[0].SubscriptionId, wanted.Id) + assert.Equal(t, result[0].Coin, wanted.Coin) + assert.Equal(t, result[0].Address, wanted.Address) + } +} + +func TestSubscriber_UpdateSubscription(t *testing.T) { + setup.CleanupPgContainer(database.DB) + _, goFile, _, _ := runtime.Caller(0) + testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_deleted.json") + testFileGiven, err := ioutil.ReadFile(testFilePathGiven) + if err != nil { + t.Fatal(err) + } + var givenEvents []blockatlas.SubscriptionEvent + if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { + t.Fatal(err) + } + + if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { + t.Fatal(err) + } + + testFilePathWanted := filepath.Join(filepath.Dir(goFile), "data", "wanted_subscriptions_added.json") + testFileWanted, err := ioutil.ReadFile(testFilePathWanted) + if err != nil { + t.Fatal(err) + } + var wantedEvents []blockatlas.Subscription + if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { + t.Fatal(err) + } + + database.AddSubscriptions(10, []models.SubscriptionData{ + {Coin: 61, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 10}, + }) + database.AddSubscriptions(1, []models.SubscriptionData{ + {Coin: 62, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 1}, + }) + database.AddSubscriptions(2, []models.SubscriptionData{ + {Coin: 63, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 2}, + }) + database.AddSubscriptions(3, []models.SubscriptionData{ + {Coin: 64, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 3}, + }) + + for _, event := range givenEvents { + body, err := json.Marshal(event) + assert.Nil(t, err) + + err = mq.Subscriptions.Publish(body) + assert.Nil(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + + go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunSubscriber, subscriptionChannel, database, ctx) + time.Sleep(time.Second) + cancel() + } + + for _, wanted := range wantedEvents { + result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}) + assert.Nil(t, err) + assert.Equal(t, result[0].SubscriptionId, wanted.Id) + assert.Equal(t, result[0].Coin, wanted.Coin) + assert.Equal(t, result[0].Address, wanted.Address) + + } + + abs61, err := database.GetSubscriptionData(61, []string{"0x0000000000000000000000000000000000000000"}) + assert.Nil(t, err) + assert.Len(t, abs61, 0) + + abs62, err := database.GetSubscriptionData(62, []string{"0x0000000000000000000000000000000000000000"}) + assert.Nil(t, err) + assert.Len(t, abs62, 0) + + abs63, err := database.GetSubscriptionData(63, []string{"0x0000000000000000000000000000000000000000"}) + assert.Nil(t, err) + assert.Len(t, abs63, 0) + + abs64, err := database.GetSubscriptionData(64, []string{"0x0000000000000000000000000000000000000000"}) + assert.Nil(t, err) + assert.Len(t, abs64, 0) +} diff --git a/tests/integration/ontology/block.go b/tests/integration/ontology/block.go deleted file mode 100755 index 7ffa7d214..000000000 --- a/tests/integration/ontology/block.go +++ /dev/null @@ -1,128 +0,0 @@ -// build integration - -package ontology - -import ( - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/platform/ontology" - "testing" -) - -var ( - testBlock = blockatlas.Block{ - Number: 7707834, - Txs: []blockatlas.Tx{ - { - From: "AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE", - To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", - ID: "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb", - Fee: "10000000", - Block: 7707834, - Status: blockatlas.StatusCompleted, - Date: 1580481541, - Coin: coin.Ontology().ID, - Type: blockatlas.TxNativeTokenTransfer, - Meta: blockatlas.AnyAction{ - Name: "Claim Rewards", - Symbol: "ONG", - TokenID: "ong", - Decimals: 9, - Value: "51000000000000", - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, - }, - }, { - From: "ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz", - To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", - ID: "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd", - Fee: "10000000", - Block: 7707834, - Status: blockatlas.StatusCompleted, - Date: 1580481541, - Coin: coin.Ontology().ID, - Type: blockatlas.TxNativeTokenTransfer, - Meta: blockatlas.AnyAction{ - Name: "Claim Rewards", - Symbol: "ONG", - TokenID: "ong", - Decimals: 9, - Value: "113200000000", - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, - }, - }, { - From: "Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS", - To: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", - ID: "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3", - Fee: "10000000", - Block: 7707834, - Status: blockatlas.StatusCompleted, - Date: 1580481541, - Coin: coin.Ontology().ID, - Type: blockatlas.TxNativeTokenTransfer, - Meta: blockatlas.AnyAction{ - Name: "Claim Rewards", - Symbol: "ONG", - TokenID: "ong", - Decimals: 9, - Value: "10949000000000", - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, - }, - }, - }, - } -) - -const ( - blockNum = 7707834 -) - -func TestOntology(t *testing.T) { - t.Run("test ontology", func(t *testing.T) { - p := ontology.Init(platform.GetVar("ontology.api")) - testCurrentBlockNumber(p, t) - testGetBlockByNumber(p, t) - }) -} - -func testCurrentBlockNumber(p *ontology.Platform, t *testing.T) { - resp, err := p.CurrentBlockNumber() - if err != nil { - t.Error(err) - } - if resp < 0 { - t.Error("block is < 0") - } -} - -func testGetBlockByNumber(p *ontology.Platform, t *testing.T) { - resp, err := p.GetBlockByNumber(int64(blockNum)) - if err != nil { - t.Error(err) - } - - isSame := resp.Number == testBlock.Number && - resp.Txs[0].Block == testBlock.Txs[0].Block && - resp.Txs[0].Status == testBlock.Txs[0].Status && - resp.Txs[0].Date == testBlock.Txs[0].Date && - resp.Txs[0].Coin == testBlock.Txs[0].Coin - if !isSame { - t.Errorf("Block is not the same") - } - - // check that we have tx hashes of parsed block - txMap := map[string]bool{} - for _, tx := range resp.Txs { - txMap[tx.ID] = true - } - delete(txMap, "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3") - delete(txMap, "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb") - delete(txMap, "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd") - - if len(txMap) > 0 { - t.Errorf("Block is not the same: %v", txMap) - } -} diff --git a/tests/docker_test/setup/mq.go b/tests/integration/setup/mq.go similarity index 100% rename from tests/docker_test/setup/mq.go rename to tests/integration/setup/mq.go diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go new file mode 100644 index 000000000..739043724 --- /dev/null +++ b/tests/integration/setup/postgres.go @@ -0,0 +1,81 @@ +package setup + +import ( + "fmt" + "github.com/jinzhu/gorm" + "github.com/ory/dockertest" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/db/models" + "log" +) + +const ( + pgUser = "user" + pgPass = "pass" + pgDB = "my_db" +) + +var ( + pgResource *dockertest.Resource + pgContainerENV = []string{ + "POSTGRES_USER=" + pgUser, + "POSTGRES_PASSWORD=" + pgPass, + "POSTGRES_DB=" + pgDB, + } + + tables = []interface{}{ + &models.Subscription{}, + &models.SubscriptionData{}, + &models.Tracker{}, + } + + uri string +) + +func runPgContainerAndInitConnection() (*db.Instance, error) { + pool := runPgContainer() + var ( + dbConn *db.Instance + err error + ) + if err := pool.Retry(func() error { + dbConn, err = db.New(uri) + return err + }); err != nil { + return nil, err + } + autoMigrate(dbConn.DB) + + return dbConn, nil +} + +func CleanupPgContainer(dbConn *gorm.DB) { + dbConn.DropTable(tables...) + autoMigrate(dbConn) +} + +func autoMigrate(dbConn *gorm.DB) { + dbConn.AutoMigrate(tables...) +} + +func stopPgContainer() error { + return pgResource.Close() +} + +func runPgContainer() *dockertest.Pool { + var err error + pool, err := dockertest.NewPool("") + if err != nil { + log.Fatalf("Could not connect to docker: %s", err) + } + + pgResource, err = pool.Run("postgres", "latest", pgContainerENV) + if err != nil { + log.Fatalf("Could not start resource: %s", err) + } + + uri = fmt.Sprintf("postgres://%s:%s@localhost:%s/%s?sslmode=disable", + pgUser, pgPass, pgResource.GetPort("5432/tcp"), pgDB, + ) + return pool +} diff --git a/tests/integration/setup/setup.go b/tests/integration/setup/setup.go new file mode 100644 index 000000000..0e916c8d8 --- /dev/null +++ b/tests/integration/setup/setup.go @@ -0,0 +1,32 @@ +package setup + +import ( + "github.com/trustwallet/blockatlas/db" + "log" +) + +func RunMQContainer() { + if err := runMQContainer(); err != nil { + log.Fatal(err) + } +} + +func StopMQContainer() { + if err := stopMQContainer(); err != nil { + log.Fatal(err) + } +} + +func RunPgContainer() *db.Instance { + dbConn, err := runPgContainerAndInitConnection() + if err != nil { + log.Fatal(err) + } + return dbConn +} + +func StopPgContainer() { + if err := stopPgContainer(); err != nil { + log.Fatal(err) + } +} From e2e9c1e6f3698a445df2447412ae0a93da7621dc Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Tue, 31 Mar 2020 18:33:38 -0700 Subject: [PATCH 221/506] Give templates correct naming (#993) --- .github/ISSUE_TEMPLATE/{IMPROVEMENT_TEMPLATE => improvement.md} | 0 .github/ISSUE_TEMPLATE/{MAINTANCE_TEMPLATE => maintance.md} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename .github/ISSUE_TEMPLATE/{IMPROVEMENT_TEMPLATE => improvement.md} (100%) rename .github/ISSUE_TEMPLATE/{MAINTANCE_TEMPLATE => maintance.md} (100%) diff --git a/.github/ISSUE_TEMPLATE/IMPROVEMENT_TEMPLATE b/.github/ISSUE_TEMPLATE/improvement.md similarity index 100% rename from .github/ISSUE_TEMPLATE/IMPROVEMENT_TEMPLATE rename to .github/ISSUE_TEMPLATE/improvement.md diff --git a/.github/ISSUE_TEMPLATE/MAINTANCE_TEMPLATE b/.github/ISSUE_TEMPLATE/maintance.md similarity index 100% rename from .github/ISSUE_TEMPLATE/MAINTANCE_TEMPLATE rename to .github/ISSUE_TEMPLATE/maintance.md From b505956dd1129297d6c94fbc73d3121178bca330 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 1 Apr 2020 08:13:22 +0300 Subject: [PATCH 222/506] Postgres perfomance fixes (#996) * Update subscriber.go * Use raw sql request to create / add subscriptions * Add bulk delete * Fix tests * Fix db.go --- cmd/observer_notifier/main.go | 2 +- cmd/observer_parser/main.go | 2 +- cmd/observer_subscriber/main.go | 2 +- db/db.go | 15 ++-- db/models/subscriptions.go | 11 --- db/subscriptions.go | 89 +++++++++++++------ db/tracker.go | 4 +- services/observer/subscriber/subscriber.go | 8 +- tests/integration/db_test/db_run_test.go | 2 +- .../integration/db_test/subscriptions_test.go | 41 +++++++-- tests/integration/db_test/tracker_test.go | 2 +- .../observer_test/full_flow_test.go | 2 +- .../observer_test/notifier_test.go | 2 +- .../integration/observer_test/parser_test.go | 2 +- .../observer_test/subscriber_test.go | 4 +- tests/integration/setup/postgres.go | 2 +- 16 files changed, 113 insertions(+), 77 deletions(-) diff --git a/cmd/observer_notifier/main.go b/cmd/observer_notifier/main.go index 6acfc2e24..293357c8d 100644 --- a/cmd/observer_notifier/main.go +++ b/cmd/observer_notifier/main.go @@ -47,7 +47,7 @@ func init() { } go mq.RestoreConnectionWorker(mqHost, mq.RawTransactions, time.Second*10) - go db.RestoreConnectionWorker(database.DB, time.Second*10, pgUri) + go db.RestoreConnectionWorker(database, time.Second*10, pgUri) time.Sleep(time.Millisecond) } diff --git a/cmd/observer_parser/main.go b/cmd/observer_parser/main.go index 6aed48645..41190a988 100644 --- a/cmd/observer_parser/main.go +++ b/cmd/observer_parser/main.go @@ -68,7 +68,7 @@ func init() { } go mq.FatalWorker(time.Second * 10) - go db.RestoreConnectionWorker(database.DB, time.Second*10, pgUri) + go db.RestoreConnectionWorker(database, time.Second*10, pgUri) time.Sleep(time.Millisecond) } diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index 9c9bf9f36..77225cbea 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -41,7 +41,7 @@ func init() { } go mq.FatalWorker(time.Second * 10) - go db.RestoreConnectionWorker(database.DB, time.Second*10, pgUri) + go db.RestoreConnectionWorker(database, time.Second*10, pgUri) time.Sleep(time.Millisecond) } diff --git a/db/db.go b/db/db.go index 98b4f41f0..f62d16c0e 100644 --- a/db/db.go +++ b/db/db.go @@ -4,39 +4,38 @@ import ( "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/postgres" "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/logger" "time" ) type Instance struct { - DB *gorm.DB + Gorm *gorm.DB } func New(uri string) (*Instance, error) { - dbConn, err := gorm.Open("postgres", uri) + g, err := gorm.Open("postgres", uri) if err != nil { return nil, err } - dbConn.AutoMigrate( + g.AutoMigrate( &models.Subscription{}, &models.SubscriptionData{}, &models.Tracker{}, ) - i := &Instance{DB: dbConn} + i := &Instance{Gorm: g} return i, nil } -func RestoreConnectionWorker(dbConn *gorm.DB, timeout time.Duration, uri string) { +func RestoreConnectionWorker(database *Instance, timeout time.Duration, uri string) { logger.Info("Run PG RestoreConnectionWorker") for { - if err := dbConn.DB().Ping(); err != nil { + if err := database.Gorm.DB().Ping(); err != nil { for { logger.Warn("PG is not available now") logger.Warn("Trying to connect to PG...") - dbConn, err = gorm.Open("postgres", uri) + database.Gorm, err = gorm.Open("postgres", uri) if err != nil { logger.Warn("PG is still unavailable:", err.Error()) time.Sleep(timeout) diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index a98ab609d..df8e972c1 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -1,22 +1,11 @@ package models -import ( - "time" -) - -type TimeModel struct { - CreatedAt time.Time - UpdatedAt time.Time -} - type Subscription struct { - TimeModel SubscriptionId uint `gorm:"primary_key:true"` Data []SubscriptionData `gorm:"foreignkey:SubscriptionId"` } type SubscriptionData struct { - TimeModel ID uint `gorm:"primary_key:true"` SubscriptionId uint `sql:"index"` Coin uint `sql:"index"` diff --git a/db/subscriptions.go b/db/subscriptions.go index 8ef21dc44..73173976a 100644 --- a/db/subscriptions.go +++ b/db/subscriptions.go @@ -1,8 +1,11 @@ package db import ( + "fmt" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/errors" + "strconv" + "strings" ) func (i *Instance) GetSubscriptionData(coin uint, addresses []string) ([]models.SubscriptionData, error) { @@ -11,7 +14,7 @@ func (i *Instance) GetSubscriptionData(coin uint, addresses []string) ([]models. } var subscriptionsDataList []models.SubscriptionData - err := i.DB. + err := i.Gorm. Model(&models.SubscriptionData{}). Where("address in (?) AND coin = ?", addresses, coin). Find(&subscriptionsDataList).Error @@ -23,50 +26,53 @@ func (i *Instance) GetSubscriptionData(coin uint, addresses []string) ([]models. } func (i *Instance) AddSubscriptions(id uint, subscriptions []models.SubscriptionData) error { - txInstance := Instance{DB: i.DB.Begin()} + if len(subscriptions) == 0 { + return errors.E("Empty subscriptions") + } + + txInstance := Instance{Gorm: i.Gorm.Begin()} defer func() { if r := recover(); r != nil { - txInstance.DB.Rollback() + txInstance.Gorm.Rollback() } }() - if err := txInstance.DB.Error; err != nil { + if err := txInstance.Gorm.Error; err != nil { return err } - if len(subscriptions) == 0 { - return errors.E("Empty subscriptions") - } + var ( existingSub models.Subscription err error ) - recordNotFound := txInstance.DB. + recordNotFound := txInstance.Gorm. Where(models.Subscription{SubscriptionId: id}). First(&existingSub). RecordNotFound() subscriptions = removeSubscriptionDuplicates(subscriptions) if recordNotFound { - err = txInstance.AddSubscription(id, subscriptions) + if err = txInstance.Gorm.Create(&models.Subscription{SubscriptionId: id}).Error; err != nil { + txInstance.Gorm.Rollback() + return err + } + err = txInstance.BulkCreate(subscriptions) } else { err = txInstance.AddToExistingSubscription(id, subscriptions) } + if err != nil { - txInstance.DB.Rollback() + txInstance.Gorm.Rollback() return err } - return txInstance.DB.Commit().Error -} - -func (i *Instance) AddSubscription(id uint, data []models.SubscriptionData) error { - return i.DB.Create(&models.Subscription{SubscriptionId: id, Data: data}).Error + return txInstance.Gorm.Commit().Error } func (i *Instance) AddToExistingSubscription(id uint, subscriptions []models.SubscriptionData) error { var ( existingData []models.SubscriptionData - association = i.DB.Model(&models.Subscription{SubscriptionId: id}).Association("Data") + association = i.Gorm.Model(&models.Subscription{SubscriptionId: id}).Association("Data") ) if err := association.Error; err != nil { return err @@ -77,7 +83,7 @@ func (i *Instance) AddToExistingSubscription(id uint, subscriptions []models.Sub updateList, deleteList := getSubscriptionsToDeleteAndUpdate(existingData, subscriptions) if len(updateList) > 0 { - if err := association.Append(updateList).Error; err != nil { + if err := i.BulkCreate(updateList); err != nil { return err } } @@ -90,7 +96,7 @@ func (i *Instance) AddToExistingSubscription(id uint, subscriptions []models.Sub } func (i *Instance) DeleteAllSubscriptions(id uint) error { - request := i.DB.Where("subscription_id = ?", id) + request := i.Gorm.Where("subscription_id = ?", id) if err := request.Error; err != nil { return err } @@ -98,21 +104,46 @@ func (i *Instance) DeleteAllSubscriptions(id uint) error { } func (i *Instance) DeleteSubscriptions(subscriptions []models.SubscriptionData) error { + var idList = make([]string, 0, len(subscriptions)) + + for _, sub := range subscriptions { + idList = append(idList, strconv.Itoa(int(sub.ID))) + } + + request := i.Gorm.Where("id in (?)", idList) + + if err := request.Error; err != nil { + return err + } + if err := request.Delete(&models.SubscriptionData{}).Error; err != nil { + return err + } + + return nil +} + +func (i *Instance) BulkCreate(dataList []models.SubscriptionData) error { var ( - errorsList = make([]error, 0) - errDetails string + valueStrings []string + valueArgs []interface{} ) - for _, sub := range subscriptions { - if err := i.DB.Delete(&models.SubscriptionData{}, sub).Error; err != nil { - errorsList = append(errorsList, err) - } + + for _, d := range dataList { + valueStrings = append(valueStrings, "(?, ?, ?)") + + valueArgs = append(valueArgs, d.SubscriptionId) + valueArgs = append(valueArgs, d.Coin) + valueArgs = append(valueArgs, d.Address) } - if len(errorsList) != 0 { - for _, err := range errorsList { - errDetails += err.Error() + " " - } - return errors.E(errDetails) + + smt := `INSERT INTO subscription_data(subscription_id, coin, address) VALUES %s` + + smt = fmt.Sprintf(smt, strings.Join(valueStrings, ",")) + + if err := i.Gorm.Exec(smt, valueArgs...).Error; err != nil { + return err } + return nil } diff --git a/db/tracker.go b/db/tracker.go index 60098a0d3..269e46792 100644 --- a/db/tracker.go +++ b/db/tracker.go @@ -35,7 +35,7 @@ func (i *Instance) GetLastParsedBlockNumber(coin uint) (int64, error) { return height, nil } var tracker models.Tracker - if err := i.DB.Where(models.Tracker{Coin: coin}).Find(&tracker).Error; err != nil { + if err := i.Gorm.Where(models.Tracker{Coin: coin}).Find(&tracker).Error; err != nil { return 0, nil } return tracker.Height, nil @@ -48,7 +48,7 @@ func (i *Instance) SetLastParsedBlockNumber(coin uint, num int64) error { Height: num, } - return i.DB. + return i.Gorm. Set("gorm:insert_option", "ON CONFLICT (coin) DO UPDATE SET height = excluded.height"). Where(models.Tracker{Coin: coin}). Create(&tracker).Error diff --git a/services/observer/subscriber/subscriber.go b/services/observer/subscriber/subscriber.go index 40ab2905f..713781749 100644 --- a/services/observer/subscriber/subscriber.go +++ b/services/observer/subscriber/subscriber.go @@ -29,13 +29,7 @@ func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { id := event.Id switch event.Operation { - case UpdateSubscription: - err := database.AddToExistingSubscription(id, ToSubscriptionData(subscriptions)) - if err != nil { - logger.Error(err, params) - } - logger.Info("Updated", params) - case AddSubscription: + case AddSubscription, UpdateSubscription: err = database.AddSubscriptions(id, ToSubscriptionData(subscriptions)) if err != nil { logger.Error(err, params) diff --git a/tests/integration/db_test/db_run_test.go b/tests/integration/db_test/db_run_test.go index 061c11bb0..86847e667 100644 --- a/tests/integration/db_test/db_run_test.go +++ b/tests/integration/db_test/db_run_test.go @@ -21,5 +21,5 @@ func TestMain(m *testing.M) { func TestPgSetup(t *testing.T) { assert.NotNil(t, database) - assert.NotNil(t, database.DB) + assert.NotNil(t, database.Gorm) } diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go index 97e66c665..3d405f284 100644 --- a/tests/integration/db_test/subscriptions_test.go +++ b/tests/integration/db_test/subscriptions_test.go @@ -11,8 +11,31 @@ import ( "testing" ) +func TestDb_AddSubscriptionsBulk(t *testing.T) { + setup.CleanupPgContainer(database.Gorm) + var subscriptions []models.SubscriptionData + + id := uint(1) + + for i := 0; i < 100; i++ { + subscriptions = append(subscriptions, models.SubscriptionData{ + SubscriptionId: id, + Coin: uint(i), + Address: "testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr", + }) + } + + assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + for i := 0; i < 100; i++ { + s, err := database.GetSubscriptionData(uint(i), []string{"testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr"}) + assert.Nil(t, err) + assert.Equal(t, id, s[0].SubscriptionId) + } + +} + func TestDb_AddSubscriptions(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData id := uint(1) @@ -62,7 +85,7 @@ func TestDb_AddSubscriptions(t *testing.T) { } func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) id := uint(1) var subscriptions []models.SubscriptionData @@ -159,7 +182,7 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { } func TestDb_FindSubscriptions(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) var subscriptionsA []blockatlas.Subscription id := uint(1) @@ -225,7 +248,7 @@ func TestDb_FindSubscriptions(t *testing.T) { } func TestDb_DeleteSubscriptions(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData id := uint(1) @@ -273,6 +296,7 @@ func TestDb_DeleteSubscriptions(t *testing.T) { assert.Equal(t, subscriptions[2].Coin, subs144[0].Coin) assert.Equal(t, subscriptions[2].Address, subs144[0].Address) + subscriptions[0].ID = subs60[0].ID subsToDel := []models.SubscriptionData{subscriptions[0]} assert.Nil(t, database.DeleteSubscriptions(subsToDel)) @@ -299,7 +323,7 @@ func TestDb_DeleteSubscriptions(t *testing.T) { } func TestDeleteAll(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData id := uint(1) @@ -356,7 +380,7 @@ func TestDeleteAll(t *testing.T) { } func TestDb_DuplicateEntries(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData id := uint(1) @@ -379,7 +403,7 @@ func TestDb_DuplicateEntries(t *testing.T) { } func TestDb_FindSubscriptions_Multiple(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData subscriptions = append(subscriptions, models.SubscriptionData{ Coin: 60, @@ -404,7 +428,7 @@ func TestDb_FindSubscriptions_Multiple(t *testing.T) { } func TestDb_AddToExisting(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData subscriptions = append(subscriptions, models.SubscriptionData{ Coin: 60, @@ -419,7 +443,6 @@ func TestDb_AddToExisting(t *testing.T) { assert.Equal(t, 1, len(subs)) assert.Equal(t, uint(1), subs[0].SubscriptionId) - assert.Nil(t, database.AddToExistingSubscription(uint(1), subscriptions)) subs2, err2 := database.GetSubscriptionData(60, []string{"testAddr"}) diff --git a/tests/integration/db_test/tracker_test.go b/tests/integration/db_test/tracker_test.go index a05f1c3ab..de443a5d0 100644 --- a/tests/integration/db_test/tracker_test.go +++ b/tests/integration/db_test/tracker_test.go @@ -9,7 +9,7 @@ import ( ) func TestDb_SetBlock(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) assert.Nil(t, database.SetLastParsedBlockNumber(60, 0)) diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 0dbe86339..3b4df80de 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -24,7 +24,7 @@ var ( ) func TestFullFlow(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 60, Address: "testAddress", SubscriptionId: 1}}) assert.Nil(t, err) diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index 31510474a..8bb5b4d67 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -42,7 +42,7 @@ var ( ) func TestNotifier(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", SubscriptionId: 1}}) assert.Nil(t, err) diff --git a/tests/integration/observer_test/parser_test.go b/tests/integration/observer_test/parser_test.go index 59e7a85be..a4f9a2979 100644 --- a/tests/integration/observer_test/parser_test.go +++ b/tests/integration/observer_test/parser_test.go @@ -19,7 +19,7 @@ import ( ) func TestParserFetchAndPublishBlock_NormalCase(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) stopChan := make(chan struct{}, 1) params := setupParser(stopChan) diff --git a/tests/integration/observer_test/subscriber_test.go b/tests/integration/observer_test/subscriber_test.go index ef52c74b3..94cd29db0 100644 --- a/tests/integration/observer_test/subscriber_test.go +++ b/tests/integration/observer_test/subscriber_test.go @@ -19,7 +19,7 @@ import ( ) func TestSubscriberAddSubscription(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) _, goFile, _, _ := runtime.Caller(0) testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_added.json") @@ -66,7 +66,7 @@ func TestSubscriberAddSubscription(t *testing.T) { } func TestSubscriber_UpdateSubscription(t *testing.T) { - setup.CleanupPgContainer(database.DB) + setup.CleanupPgContainer(database.Gorm) _, goFile, _, _ := runtime.Caller(0) testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_deleted.json") testFileGiven, err := ioutil.ReadFile(testFilePathGiven) diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go index 739043724..c52eb76bc 100644 --- a/tests/integration/setup/postgres.go +++ b/tests/integration/setup/postgres.go @@ -44,7 +44,7 @@ func runPgContainerAndInitConnection() (*db.Instance, error) { }); err != nil { return nil, err } - autoMigrate(dbConn.DB) + autoMigrate(dbConn.Gorm) return dbConn, nil } From f007d022dbd9968c78c56a3a2deef77d5f60e3be Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Wed, 1 Apr 2020 17:43:17 +0200 Subject: [PATCH 223/506] FIO transaction history (#984) * FIO mock script: more generic. * Update FIO API endpoint. * FIO transaction history. * Fill all fields. * Minor review finding. * Formatting. * FIO history, use actor as input to API. * Also accept actors, not only public keys. * FIO history: add tests (mocked). * Minor, remove console logs. * Additional test. * Small cleanup * Review comments, code cleanup. * Review comments, error handling. Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov --- config.yml | 4 +- configmock.yml | 2 +- ...pi-get_pub_address.js => fio-api-chain.js} | 15 +- mock/ext-api-dyson/post/fio-api-history.js | 1498 +++++++++++++++++ platform/fio/actor.go | 101 ++ platform/fio/actor_test.go | 67 + platform/fio/client.go | 14 +- platform/fio/model.go | 41 +- platform/fio/transaction.go | 71 +- tests/postman/transaction_data.json | 18 + 10 files changed, 1819 insertions(+), 12 deletions(-) rename mock/ext-api-dyson/post/{fio-api-get_pub_address.js => fio-api-chain.js} (73%) create mode 100644 mock/ext-api-dyson/post/fio-api-history.js create mode 100644 platform/fio/actor.go create mode 100644 platform/fio/actor_test.go diff --git a/config.yml b/config.yml index 6430bb651..057ece881 100644 --- a/config.yml +++ b/config.yml @@ -148,9 +148,9 @@ aeternity: nebulas: api: https://explorer-backend.nebulas.io/api +# [FIO] FIO: https://fioprotocol.io fio: - # api: https://addresses.fio.foundation - api: http://testnet.fioprotocol.io/v1/chain + api: https://fio.eosphere.io # [BTC] Bitcoin: https://bitcoin.org/ (Blockbook API https://github.com/trezor/blockbook) bitcoin: diff --git a/configmock.yml b/configmock.yml index 9d6575c7d..57d7f7c23 100644 --- a/configmock.yml +++ b/configmock.yml @@ -150,7 +150,7 @@ nebulas: api: http://localhost:3000/nebulas-api fio: - api: http://localhost:3000/fio-api/v1/chain + api: http://localhost:3000/fio-api # [BTC] Bitcoin: https://bitcoin.org/ (Blockbook API https://github.com/trezor/blockbook) bitcoin: diff --git a/mock/ext-api-dyson/post/fio-api-get_pub_address.js b/mock/ext-api-dyson/post/fio-api-chain.js similarity index 73% rename from mock/ext-api-dyson/post/fio-api-get_pub_address.js rename to mock/ext-api-dyson/post/fio-api-chain.js index ad9257cec..480e1194e 100644 --- a/mock/ext-api-dyson/post/fio-api-get_pub_address.js +++ b/mock/ext-api-dyson/post/fio-api-chain.js @@ -1,4 +1,4 @@ -/// FIO RPC API Mock, get_pub_address +/// FIO RPC API Mock, chain API /// Returns: /// - public address for certain fio name and coin combinations /// - public address not found message for other input @@ -8,13 +8,16 @@ /// curl "http://localhost:8420/v2/ns/lookup?name=adam@fiotestnet&coins=60" module.exports = { - path: '/fio-api/v1/chain/get_pub_address', + path: '/fio-api/v1/chain/:action', template: function(params, query, body) { - var addr = getAddress(body.fio_address, body.token_code); - if (addr == '') { - return {message: 'Public address not found'}; + if (params.action === 'get_pub_address') { + var addr = getAddress(body.fio_address, body.token_code); + if (addr == '') { + return {message: 'Public address not found'}; + } + return {public_address: addr}; } - return {public_address: addr}; + return {error: 'Not implemented'}; } }; diff --git a/mock/ext-api-dyson/post/fio-api-history.js b/mock/ext-api-dyson/post/fio-api-history.js new file mode 100644 index 000000000..9c829f7e1 --- /dev/null +++ b/mock/ext-api-dyson/post/fio-api-history.js @@ -0,0 +1,1498 @@ +/// FIO RPC API Mock, history API +/// curl -H "Content-Type: application/json" -d '{"account_name": "ezsmbcy2opod"}' https://fio.eosphere.io/v1/history/get_actions +/// curl -H "Content-Type: application/json" -d '{"account_name": "ezsmbcy2opod"}' http://localhost:3000/fio-api/v1/history/get_actions +/// curl "http://localhost:8420/v1/fio/FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt" + +module.exports = { + path: '/fio-api/v1/history/:action', + template: function(params, query, body) { + //console.log(params); + //console.log(body); + if (params.action === 'get_actions') { + switch (body.account_name) { + case 'ezsmbcy2opod': // FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt + return JSON.parse(` + { + "actions": [ + { + "global_action_seq": 507874, + "account_action_seq": 0, + "block_num": 358689, + "block_time": "2020-03-27T01:54:24.500", + "action_trace": { + "receipt": { + "receiver": "ezsmbcy2opod", + "response": "{'status': 'OK','fee_collected':2000000000}", + "act_digest": "6ef1d997fd449b6fefb8df19401c71425d366a24aab4613ca2059478fef7915f", + "global_sequence": 507874, + "recv_sequence": 1, + "auth_sequence": [ + [ + "f5axfpgffiqz", + 125 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "ezsmbcy2opod", + "act": { + "account": "fio.token", + "name": "trnsfiopubky", + "authorization": [ + { + "actor": "f5axfpgffiqz", + "permission": "active" + } + ], + "data": { + "payee_public_key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "amount": 700000000000, + "max_fee": 2000000000, + "actor": "f5axfpgffiqz", + "tpid": "" + }, + "hex_data": "3546494f375133586651326f634750317a5973743653667835717273695a383635437538536f326174727562394a4e3934736f376774005840fba20000000094357700000000f0ad5b8bd5d54d5900" + }, + "context_free": false, + "elapsed": 6, + "console": "", + "trx_id": "2e0a7dc3640768e1d644cee871734dd2efa23e65a54c438c1ba03801d7386fb7", + "block_num": 358689, + "block_time": "2020-03-27T01:54:24.500", + "producer_block_id": "00057921b2a5f55fba29f7f08cd49dd095a18f0de2e4e06ba0833ca771ad699b", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 508968, + "account_action_seq": 1, + "block_num": 359762, + "block_time": "2020-03-27T02:03:21.000", + "action_trace": { + "receipt": { + "receiver": "fio.address", + "response": "{'status': 'OK','expiration':'2021-03-27T02:03:21','fee_collected':40000000000}", + "act_digest": "e054494384148e58122a10c3398d9e01a09a79cd6c22da0203653906afd79b3b", + "global_sequence": 508968, + "recv_sequence": 34025, + "auth_sequence": [ + [ + "ezsmbcy2opod", + 1 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.address", + "act": { + "account": "fio.address", + "name": "regaddress", + "authorization": [ + { + "actor": "ezsmbcy2opod", + "permission": "active" + } + ], + "data": { + "fio_address": "bp@eosph", + "owner_fio_public_key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "max_fee": 40000000000, + "actor": "ezsmbcy2opod", + "tpid": "" + }, + "hex_data": "08627040656f7370683546494f375133586651326f634750317a5973743653667835717273695a383635437538536f326174727562394a4e3934736f37677400902f50090000009068a5c2a323f15700" + }, + "context_free": false, + "elapsed": 2834, + "console": "", + "trx_id": "b7dd60839ccce11cd175fce6816da04bbce9b70825661005d2ea5d3572408c04", + "block_num": 359762, + "block_time": "2020-03-27T02:03:21.000", + "producer_block_id": "00057d5209ad0141445b3ee2eb1ba7265ab4c7093f7bc4c2142e2eac4c8e5d10", + "account_ram_deltas": [ + { + "account": "ezsmbcy2opod", + "delta": 798 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 508970, + "account_action_seq": 2, + "block_num": 359762, + "block_time": "2020-03-27T02:03:21.000", + "action_trace": { + "receipt": { + "receiver": "ezsmbcy2opod", + "response": "", + "act_digest": "e6774ab921eabe540049667756efb5567b83b291b8a21c5bec81c8b5dc98c366", + "global_sequence": 508970, + "recv_sequence": 2, + "auth_sequence": [ + [ + "eosio", + 430085 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "ezsmbcy2opod", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "ezsmbcy2opod", + "to": "fio.treasury", + "quantity": "40.000000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "9068a5c2a323f157e0afc646dd0ca85b00902f50090000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 6, + "console": "", + "trx_id": "b7dd60839ccce11cd175fce6816da04bbce9b70825661005d2ea5d3572408c04", + "block_num": 359762, + "block_time": "2020-03-27T02:03:21.000", + "producer_block_id": "00057d5209ad0141445b3ee2eb1ba7265ab4c7093f7bc4c2142e2eac4c8e5d10", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 510503, + "account_action_seq": 3, + "block_num": 361281, + "block_time": "2020-03-27T02:16:00.500", + "action_trace": { + "receipt": { + "receiver": "eosio", + "response": "{'status': 'OK','fee_collected':200000000000}", + "act_digest": "52b1631c84896baaebd4b81a80c2cfab4f9741e0323d2845d1b3df5683ad7c3c", + "global_sequence": 510503, + "recv_sequence": 404854, + "auth_sequence": [ + [ + "ezsmbcy2opod", + 2 + ] + ], + "code_sequence": 2, + "abi_sequence": 2 + }, + "receiver": "eosio", + "act": { + "account": "eosio", + "name": "regproducer", + "authorization": [ + { + "actor": "ezsmbcy2opod", + "permission": "active" + } + ], + "data": { + "fio_address": "bp@eosph", + "fio_pub_key": "FIO5hZB8REVEirigba4N7TKa67MYm4HFwtiKz6GZJ2eRi5Paxwixz", + "url": "https://www.eosph.io", + "location": 10, + "actor": "ezsmbcy2opod", + "max_fee": 400000000000 + }, + "hex_data": "08627040656f7370683546494f35685a423852455645697269676261344e37544b6136374d596d3448467774694b7a36475a4a32655269355061787769787a1468747470733a2f2f7777772e656f7370682e696f0a009068a5c2a323f15700a0db215d000000" + }, + "context_free": false, + "elapsed": 2207, + "console": "", + "trx_id": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8", + "block_num": 361281, + "block_time": "2020-03-27T02:16:00.500", + "producer_block_id": "00058341700331f78adea1eec39e7150b743f171c9fd9dfff8ea7310f5e6b515", + "account_ram_deltas": [ + { + "account": "ezsmbcy2opod", + "delta": 635 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 510505, + "account_action_seq": 4, + "block_num": 361281, + "block_time": "2020-03-27T02:16:00.500", + "action_trace": { + "receipt": { + "receiver": "ezsmbcy2opod", + "response": "", + "act_digest": "a8dd1a5cfe8db5fb3ca38eed9e348acd73150d88211f93e0d37e332289fe76a3", + "global_sequence": 510505, + "recv_sequence": 3, + "auth_sequence": [ + [ + "eosio", + 431614 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "ezsmbcy2opod", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "ezsmbcy2opod", + "to": "fio.treasury", + "quantity": "200.000000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "9068a5c2a323f157e0afc646dd0ca85b00d0ed902e0000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 6, + "console": "", + "trx_id": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8", + "block_num": 361281, + "block_time": "2020-03-27T02:16:00.500", + "producer_block_id": "00058341700331f78adea1eec39e7150b743f171c9fd9dfff8ea7310f5e6b515", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + } + ], + "last_irreversible_block": 928886 + } + `); + + case 'gmdncuvoqxfn': // FIO6gZthsHigy7wXeev4MKS4MuoygkxQ1yirmmUqpoubDWLJTASa2 + return JSON.parse(` + { + "actions": [ + { + "global_action_seq": 1158276, + "account_action_seq": 0, + "block_num": 1008911, + "block_time": "2020-03-30T20:12:55.500", + "action_trace": { + "receipt": { + "receiver": "gmdncuvoqxfn", + "response": "{'status': 'OK','fee_collected':2000000000}", + "act_digest": "dcff7e3441ac0e2ce3677fca269d04c4a6ee81a10c830a22fa37dcdc7595f1c1", + "global_sequence": 1158276, + "recv_sequence": 1, + "auth_sequence": [ + [ + "f5axfpgffiqz", + 129 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "gmdncuvoqxfn", + "act": { + "account": "fio.token", + "name": "trnsfiopubky", + "authorization": [ + { + "actor": "f5axfpgffiqz", + "permission": "active" + } + ], + "data": { + "payee_public_key": "FIO6gZthsHigy7wXeev4MKS4MuoygkxQ1yirmmUqpoubDWLJTASa2", + "amount": 700000000000, + "max_fee": 2000000000, + "actor": "f5axfpgffiqz", + "tpid": "" + }, + "hex_data": "3546494f36675a74687348696779377758656576344d4b53344d756f79676b7851317969726d6d5571706f756244574c4a5441536132005840fba20000000094357700000000f0ad5b8bd5d54d5900" + }, + "context_free": false, + "elapsed": 8, + "console": "", + "trx_id": "d2dd588ac5e46cb072d0a2673ea59b88187f0331b26906fabbafddbcea291450", + "block_num": 1008911, + "block_time": "2020-03-30T20:12:55.500", + "producer_block_id": "000f650fae073cc3a5c4eaf40a68051dab80e642d815345fca490f66067bfe8d", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 1247174, + "account_action_seq": 1, + "block_num": 1097674, + "block_time": "2020-03-31T08:32:37.000", + "action_trace": { + "receipt": { + "receiver": "fio.address", + "response": "{'status': 'OK','expiration':'2021-03-31T08:32:37','fee_collected':40000000000}", + "act_digest": "4a17b4b8b5f8c318d0a08b9766a793f9a60063acf98a0acaf2177c880e852855", + "global_sequence": 1247174, + "recv_sequence": 34050, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 1 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.address", + "act": { + "account": "fio.address", + "name": "regaddress", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "active" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "owner_fio_public_key": "FIO6gZthsHigy7wXeev4MKS4MuoygkxQ1yirmmUqpoubDWLJTASa2", + "max_fee": 40000000000, + "actor": "gmdncuvoqxfn", + "tpid": "" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3546494f36675a74687348696779377758656576344d4b53344d756f79676b7851317969726d6d5571706f756244574c4a544153613200902f50090000003057b7746b34936400" + }, + "context_free": false, + "elapsed": 3142, + "console": "", + "trx_id": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a", + "block_num": 1097674, + "block_time": "2020-03-31T08:32:37.000", + "producer_block_id": "0010bfca1e5c31bb4b4af9ec59df5c3f92b7adc33aa3f0967ae8a4538c78c982", + "account_ram_deltas": [ + { + "account": "gmdncuvoqxfn", + "delta": 818 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 1247176, + "account_action_seq": 2, + "block_num": 1097674, + "block_time": "2020-03-31T08:32:37.000", + "action_trace": { + "receipt": { + "receiver": "gmdncuvoqxfn", + "response": "", + "act_digest": "601cd0faa0fca3e16359d623dbf5c0906fdbc41e6c494a0fd58c0f836ac89793", + "global_sequence": 1247176, + "recv_sequence": 2, + "auth_sequence": [ + [ + "eosio", + 1168156 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "gmdncuvoqxfn", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "gmdncuvoqxfn", + "to": "fio.treasury", + "quantity": "40.000000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "3057b7746b349364e0afc646dd0ca85b00902f50090000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 4, + "console": "", + "trx_id": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a", + "block_num": 1097674, + "block_time": "2020-03-31T08:32:37.000", + "producer_block_id": "0010bfca1e5c31bb4b4af9ec59df5c3f92b7adc33aa3f0967ae8a4538c78c982", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + } + ], + "last_irreversible_block": 1104980 + } + `); + + case 'fio.treasury': + return JSON.parse(` + { + "actions": [ + { + "global_action_seq": 1205798, + "account_action_seq": 69910, + "block_num": 1056340, + "block_time": "2020-03-31T02:48:10.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "7523d7353879acaf9d41d6078cebd956a5ad6980ce1ada7a840f90ba275851d9", + "global_sequence": 1205798, + "recv_sequence": 69907, + "auth_sequence": [ + [ + "fio.fee", + 1643 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "fdtnrwdupdat", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "002d310100000000" + }, + "context_free": false, + "elapsed": 56, + "console": "", + "trx_id": "7fc2be4379b1cbb2ac95a1ef00149a2cbf559cc1e563cb2d237bb829001cf298", + "block_num": 1056340, + "block_time": "2020-03-31T02:48:10.000", + "producer_block_id": "00101e54f8bc28902f8fcd26eb3dba2a96278ad3380bfba98dcffef5d220bd4c", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1205796, + "account_action_seq": 69911, + "block_num": 1056340, + "block_time": "2020-03-31T02:48:10.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "902802357ab59f73547676540fb71244591e71819a763429e562091ffca4b324", + "global_sequence": 1205796, + "recv_sequence": 69905, + "auth_sequence": [ + [ + "eosio", + 1126799 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "c1dlj1dcjzno", + "to": "fio.treasury", + "quantity": "0.400000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "40e77f2885175340e0afc646dd0ca85b0084d717000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 21, + "console": "", + "trx_id": "7fc2be4379b1cbb2ac95a1ef00149a2cbf559cc1e563cb2d237bb829001cf298", + "block_num": 1056340, + "block_time": "2020-03-31T02:48:10.000", + "producer_block_id": "00101e54f8bc28902f8fcd26eb3dba2a96278ad3380bfba98dcffef5d220bd4c", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 8, + "creator_action_ordinal": 4, + "closest_unnotified_ancestor_action_ordinal": 4 + } + }, + { + "global_action_seq": 1216171, + "account_action_seq": 69912, + "block_num": 1066706, + "block_time": "2020-03-31T04:14:33.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "b93c4648862a6a184d38af9f078f1c352a7bf07cddb8f6d457148847cbfa479a", + "global_sequence": 1216171, + "recv_sequence": 69909, + "auth_sequence": [ + [ + "fio.fee", + 1644 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bprewdupdate", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "80d99f3800000000" + }, + "context_free": false, + "elapsed": 42, + "console": "", + "trx_id": "b088bf3b4663118a177bb48da45374f29e3988141d4fed81f92124880318f88d", + "block_num": 1066706, + "block_time": "2020-03-31T04:14:33.000", + "producer_block_id": "001046d219e699f20c31ff0fed77bd361bf2323cb06a46a9417a1c908294c29a", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 5, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1216172, + "account_action_seq": 69913, + "block_num": 1066706, + "block_time": "2020-03-31T04:14:33.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "fefe089e3efc8a4b18d94b377e52b2d688e3d9321eef5c8f7d1fa6b060f2b687", + "global_sequence": 1216172, + "recv_sequence": 69910, + "auth_sequence": [ + [ + "fio.fee", + 1645 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "fdtnrwdupdat", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "80f0fa0200000000" + }, + "context_free": false, + "elapsed": 32, + "console": "", + "trx_id": "b088bf3b4663118a177bb48da45374f29e3988141d4fed81f92124880318f88d", + "block_num": 1066706, + "block_time": "2020-03-31T04:14:33.000", + "producer_block_id": "001046d219e699f20c31ff0fed77bd361bf2323cb06a46a9417a1c908294c29a", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1216170, + "account_action_seq": 69914, + "block_num": 1066706, + "block_time": "2020-03-31T04:14:33.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "facd8187719c8282812a04b487e67cc2202c472183b4e4ee114fcfa492c05573", + "global_sequence": 1216170, + "recv_sequence": 69908, + "auth_sequence": [ + [ + "eosio", + 1137169 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "aloha3joooqd", + "to": "fio.treasury", + "quantity": "1.000000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "902ca5f40dd36834e0afc646dd0ca85b00ca9a3b000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 12, + "console": "", + "trx_id": "b088bf3b4663118a177bb48da45374f29e3988141d4fed81f92124880318f88d", + "block_num": 1066706, + "block_time": "2020-03-31T04:14:33.000", + "producer_block_id": "001046d219e699f20c31ff0fed77bd361bf2323cb06a46a9417a1c908294c29a", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 8, + "creator_action_ordinal": 4, + "closest_unnotified_ancestor_action_ordinal": 4 + } + }, + { + "global_action_seq": 1216854, + "account_action_seq": 69915, + "block_num": 1067381, + "block_time": "2020-03-31T04:20:10.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "088307ffafcae045997b5ce895a1208f845b47cb363ac9bff52df318f23b257d", + "global_sequence": 1216854, + "recv_sequence": 69912, + "auth_sequence": [ + [ + "fio.fee", + 1646 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bprewdupdate", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "0057a61600000000" + }, + "context_free": false, + "elapsed": 56, + "console": "", + "trx_id": "2c755be0cd59e443b5e1fc33443594a0770b7a6dcfdef4709c98145a2e36bf1b", + "block_num": 1067381, + "block_time": "2020-03-31T04:20:10.500", + "producer_block_id": "001049757562cbc8bb5db955d8c7ee14689c7383bd9a6211ea9a5cb5d024827a", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 5, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1216855, + "account_action_seq": 69916, + "block_num": 1067381, + "block_time": "2020-03-31T04:20:10.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "7523d7353879acaf9d41d6078cebd956a5ad6980ce1ada7a840f90ba275851d9", + "global_sequence": 1216855, + "recv_sequence": 69913, + "auth_sequence": [ + [ + "fio.fee", + 1647 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "fdtnrwdupdat", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "002d310100000000" + }, + "context_free": false, + "elapsed": 41, + "console": "", + "trx_id": "2c755be0cd59e443b5e1fc33443594a0770b7a6dcfdef4709c98145a2e36bf1b", + "block_num": 1067381, + "block_time": "2020-03-31T04:20:10.500", + "producer_block_id": "001049757562cbc8bb5db955d8c7ee14689c7383bd9a6211ea9a5cb5d024827a", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1216853, + "account_action_seq": 69917, + "block_num": 1067381, + "block_time": "2020-03-31T04:20:10.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "a5180fd568f15f4722641a839c5f2b9d9fcf7597464d1e9e5b84ffdf63a48fb1", + "global_sequence": 1216853, + "recv_sequence": 69911, + "auth_sequence": [ + [ + "eosio", + 1137848 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "wwgwvaijiuag", + "to": "fio.treasury", + "quantity": "0.400000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "c08c76cf99cd19e7e0afc646dd0ca85b0084d717000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 16, + "console": "", + "trx_id": "2c755be0cd59e443b5e1fc33443594a0770b7a6dcfdef4709c98145a2e36bf1b", + "block_num": 1067381, + "block_time": "2020-03-31T04:20:10.500", + "producer_block_id": "001049757562cbc8bb5db955d8c7ee14689c7383bd9a6211ea9a5cb5d024827a", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 8, + "creator_action_ordinal": 4, + "closest_unnotified_ancestor_action_ordinal": 4 + } + }, + { + "global_action_seq": 1216978, + "account_action_seq": 69918, + "block_num": 1067497, + "block_time": "2020-03-31T04:21:08.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "088307ffafcae045997b5ce895a1208f845b47cb363ac9bff52df318f23b257d", + "global_sequence": 1216978, + "recv_sequence": 69915, + "auth_sequence": [ + [ + "fio.fee", + 1648 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bprewdupdate", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "0057a61600000000" + }, + "context_free": false, + "elapsed": 44, + "console": "", + "trx_id": "7535cb0a48298e8d8c636dcdfc7742af43a35fccf9fdd7d8d8e5ee80a253ce48", + "block_num": 1067497, + "block_time": "2020-03-31T04:21:08.500", + "producer_block_id": "001049e9f3572dde8f852624dd489c884309a27c277bfb251bc353ce7a80a05f", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 5, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1216979, + "account_action_seq": 69919, + "block_num": 1067497, + "block_time": "2020-03-31T04:21:08.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "7523d7353879acaf9d41d6078cebd956a5ad6980ce1ada7a840f90ba275851d9", + "global_sequence": 1216979, + "recv_sequence": 69916, + "auth_sequence": [ + [ + "fio.fee", + 1649 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "fdtnrwdupdat", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "002d310100000000" + }, + "context_free": false, + "elapsed": 45, + "console": "", + "trx_id": "7535cb0a48298e8d8c636dcdfc7742af43a35fccf9fdd7d8d8e5ee80a253ce48", + "block_num": 1067497, + "block_time": "2020-03-31T04:21:08.500", + "producer_block_id": "001049e9f3572dde8f852624dd489c884309a27c277bfb251bc353ce7a80a05f", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1216977, + "account_action_seq": 69920, + "block_num": 1067497, + "block_time": "2020-03-31T04:21:08.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "a5180fd568f15f4722641a839c5f2b9d9fcf7597464d1e9e5b84ffdf63a48fb1", + "global_sequence": 1216977, + "recv_sequence": 69914, + "auth_sequence": [ + [ + "eosio", + 1137968 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "wwgwvaijiuag", + "to": "fio.treasury", + "quantity": "0.400000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "c08c76cf99cd19e7e0afc646dd0ca85b0084d717000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 12, + "console": "", + "trx_id": "7535cb0a48298e8d8c636dcdfc7742af43a35fccf9fdd7d8d8e5ee80a253ce48", + "block_num": 1067497, + "block_time": "2020-03-31T04:21:08.500", + "producer_block_id": "001049e9f3572dde8f852624dd489c884309a27c277bfb251bc353ce7a80a05f", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 8, + "creator_action_ordinal": 4, + "closest_unnotified_ancestor_action_ordinal": 4 + } + }, + { + "global_action_seq": 1241641, + "account_action_seq": 69921, + "block_num": 1092152, + "block_time": "2020-03-31T07:46:36.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "088307ffafcae045997b5ce895a1208f845b47cb363ac9bff52df318f23b257d", + "global_sequence": 1241641, + "recv_sequence": 69918, + "auth_sequence": [ + [ + "fio.fee", + 1650 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bprewdupdate", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "0057a61600000000" + }, + "context_free": false, + "elapsed": 66, + "console": "", + "trx_id": "9429e1dccf6e50e00c6f03c51d2ae37cb936bc7593b8719a89b13fff40574218", + "block_num": 1092152, + "block_time": "2020-03-31T07:46:36.000", + "producer_block_id": "0010aa38918e0b7ca42cf76a59cfdac5bcc06cdbcc6e83f8b2e4959ba222da90", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 5, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1241642, + "account_action_seq": 69922, + "block_num": 1092152, + "block_time": "2020-03-31T07:46:36.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "7523d7353879acaf9d41d6078cebd956a5ad6980ce1ada7a840f90ba275851d9", + "global_sequence": 1241642, + "recv_sequence": 69919, + "auth_sequence": [ + [ + "fio.fee", + 1651 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "fdtnrwdupdat", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "002d310100000000" + }, + "context_free": false, + "elapsed": 66, + "console": "", + "trx_id": "9429e1dccf6e50e00c6f03c51d2ae37cb936bc7593b8719a89b13fff40574218", + "block_num": 1092152, + "block_time": "2020-03-31T07:46:36.000", + "producer_block_id": "0010aa38918e0b7ca42cf76a59cfdac5bcc06cdbcc6e83f8b2e4959ba222da90", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1241640, + "account_action_seq": 69923, + "block_num": 1092152, + "block_time": "2020-03-31T07:46:36.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "e780fffd69aa5812e49e034ad42f6ae16d639562eaf9476c974dc8cb8db88919", + "global_sequence": 1241640, + "recv_sequence": 69917, + "auth_sequence": [ + [ + "eosio", + 1162627 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "u2rwmaqfxtvs", + "to": "fio.treasury", + "quantity": "0.400000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "8077eecb1ac9afd0e0afc646dd0ca85b0084d717000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 21, + "console": "", + "trx_id": "9429e1dccf6e50e00c6f03c51d2ae37cb936bc7593b8719a89b13fff40574218", + "block_num": 1092152, + "block_time": "2020-03-31T07:46:36.000", + "producer_block_id": "0010aa38918e0b7ca42cf76a59cfdac5bcc06cdbcc6e83f8b2e4959ba222da90", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 8, + "creator_action_ordinal": 4, + "closest_unnotified_ancestor_action_ordinal": 4 + } + }, + { + "global_action_seq": 1241684, + "account_action_seq": 69924, + "block_num": 1092187, + "block_time": "2020-03-31T07:46:53.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "088307ffafcae045997b5ce895a1208f845b47cb363ac9bff52df318f23b257d", + "global_sequence": 1241684, + "recv_sequence": 69921, + "auth_sequence": [ + [ + "fio.fee", + 1652 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bprewdupdate", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "0057a61600000000" + }, + "context_free": false, + "elapsed": 47, + "console": "", + "trx_id": "6d67c62ac8c778963972064b3aaf302cf6f7b8d3625ef40cebcebda92276bed2", + "block_num": 1092187, + "block_time": "2020-03-31T07:46:53.500", + "producer_block_id": "0010aa5b487b38bb00a45860ac534767e302a285994ad9b5fd6aa671e37e1551", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 5, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1241685, + "account_action_seq": 69925, + "block_num": 1092187, + "block_time": "2020-03-31T07:46:53.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "7523d7353879acaf9d41d6078cebd956a5ad6980ce1ada7a840f90ba275851d9", + "global_sequence": 1241685, + "recv_sequence": 69922, + "auth_sequence": [ + [ + "fio.fee", + 1653 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "fdtnrwdupdat", + "authorization": [ + { + "actor": "fio.fee", + "permission": "active" + } + ], + "data": "002d310100000000" + }, + "context_free": false, + "elapsed": 32, + "console": "", + "trx_id": "6d67c62ac8c778963972064b3aaf302cf6f7b8d3625ef40cebcebda92276bed2", + "block_num": 1092187, + "block_time": "2020-03-31T07:46:53.500", + "producer_block_id": "0010aa5b487b38bb00a45860ac534767e302a285994ad9b5fd6aa671e37e1551", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 1241683, + "account_action_seq": 69926, + "block_num": 1092187, + "block_time": "2020-03-31T07:46:53.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "e780fffd69aa5812e49e034ad42f6ae16d639562eaf9476c974dc8cb8db88919", + "global_sequence": 1241683, + "recv_sequence": 69920, + "auth_sequence": [ + [ + "eosio", + 1162666 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "u2rwmaqfxtvs", + "to": "fio.treasury", + "quantity": "0.400000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "8077eecb1ac9afd0e0afc646dd0ca85b0084d717000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 19, + "console": "", + "trx_id": "6d67c62ac8c778963972064b3aaf302cf6f7b8d3625ef40cebcebda92276bed2", + "block_num": 1092187, + "block_time": "2020-03-31T07:46:53.500", + "producer_block_id": "0010aa5b487b38bb00a45860ac534767e302a285994ad9b5fd6aa671e37e1551", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 8, + "creator_action_ordinal": 4, + "closest_unnotified_ancestor_action_ordinal": 4 + } + }, + { + "global_action_seq": 1247178, + "account_action_seq": 69927, + "block_num": 1097674, + "block_time": "2020-03-31T08:32:37.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "d86fcb99d2b33d23d674f18ae83a278b6ad4dae408eba0a125b4978c534ce715", + "global_sequence": 1247178, + "recv_sequence": 69924, + "auth_sequence": [ + [ + "fio.address", + 72535 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "fdtnrwdupdat", + "authorization": [ + { + "actor": "fio.address", + "permission": "active" + } + ], + "data": "0094357700000000" + }, + "context_free": false, + "elapsed": 46, + "console": "", + "trx_id": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a", + "block_num": 1097674, + "block_time": "2020-03-31T08:32:37.000", + "producer_block_id": "0010bfca1e5c31bb4b4af9ec59df5c3f92b7adc33aa3f0967ae8a4538c78c982", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 3, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 1247179, + "account_action_seq": 69928, + "block_num": 1097674, + "block_time": "2020-03-31T08:32:37.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "5bceab55ed2ffde8ba5cbf5b9b309c48a75e181f8d13ea981f856c1f66699682", + "global_sequence": 1247179, + "recv_sequence": 69925, + "auth_sequence": [ + [ + "fio.address", + 72536 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bppoolupdate", + "authorization": [ + { + "actor": "fio.address", + "permission": "active" + } + ], + "data": "00fcf9d808000000" + }, + "context_free": false, + "elapsed": 31, + "console": "", + "trx_id": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a", + "block_num": 1097674, + "block_time": "2020-03-31T08:32:37.000", + "producer_block_id": "0010bfca1e5c31bb4b4af9ec59df5c3f92b7adc33aa3f0967ae8a4538c78c982", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 4, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 1247177, + "account_action_seq": 69929, + "block_num": 1097674, + "block_time": "2020-03-31T08:32:37.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "601cd0faa0fca3e16359d623dbf5c0906fdbc41e6c494a0fd58c0f836ac89793", + "global_sequence": 1247177, + "recv_sequence": 69923, + "auth_sequence": [ + [ + "eosio", + 1168157 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "gmdncuvoqxfn", + "to": "fio.treasury", + "quantity": "40.000000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "3057b7746b349364e0afc646dd0ca85b00902f50090000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 15, + "console": "", + "trx_id": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a", + "block_num": 1097674, + "block_time": "2020-03-31T08:32:37.000", + "producer_block_id": "0010bfca1e5c31bb4b4af9ec59df5c3f92b7adc33aa3f0967ae8a4538c78c982", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 7, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + } + ], + "last_irreversible_block": 1104241 + } + `); + } + } + return {error: 'Not implemented'}; + } +}; diff --git a/platform/fio/actor.go b/platform/fio/actor.go new file mode 100644 index 000000000..4fc0a805d --- /dev/null +++ b/platform/fio/actor.go @@ -0,0 +1,101 @@ +package fio + +import ( + "github.com/btcsuite/btcutil/base58" + "github.com/trustwallet/blockatlas/pkg/errors" +) + +func actorFromPublicKeyOrActor(addressOrActor string) string { + l := len(addressOrActor) + if l >= 51 && l <= 55 && addressOrActor[:3] == "FIO" { + // assume public key string + return actorFromPublicKey(addressOrActor) + } + if l <= 13 { + // assume actor + return addressOrActor + } + return "" +} + +func actorFromPublicKey(address string) string { + pkBytes, err := bytesFromPublicKeyString(address) + if err != nil { + return "" + } + return actorFromPublicKeyBytes(pkBytes) +} + +func actorFromPublicKeyBytes(pkBytes []byte) string { + shortenedKey := shortenKey(pkBytes) + name13 := getName(shortenedKey) + // trim to 12 characters + return name13[:12] +} + +func bytesFromPublicKeyString(address string) ([]byte, error) { + if address[:3] != "FIO" { + return nil, errors.E("Invalid FIO public key prefix") + } + array := base58.Decode(address[3:]) + if len(array) != 37 { + return nil, errors.E("Invalid FIO public key length") + } + return array, nil +} + +func mask12(len int) byte { + if len == 12 { + return 0x0f + } + return 0x1f +} + +func mask0(len int) byte { + if len == 0 { + return 0x0f + } + return 0x1f +} + +func shortenKey(addrKey []byte) uint64 { + var ( + res uint64 = 0 + i = 1 // Ignore key head + l = 0 + ) + for l <= 12 { + //assert(i < 33) + trimmedChar := uint64(addrKey[i] & mask12(l)) + if trimmedChar == 0 { + i++ + continue + } // Skip a zero and move to next + var shuffle byte = 0 + if l < 12 { + shuffle = byte(5*(12-l) - 1) + } + res = res | (trimmedChar << shuffle) + l++ + i++ + } + return res +} + +func getName(shortKey uint64) string { + var ( + charmap = ".12345abcdefghijklmnopqrstuvwxyz" + str [13]byte + tmp = shortKey + ) + for i := 0; i <= 12; i++ { + c := charmap[tmp&uint64(mask0(i))] + str[12-i] = c + if i == 0 { + tmp = tmp >> 4 + } else { + tmp = tmp >> 5 + } + } + return string(str[:]) +} diff --git a/platform/fio/actor_test.go b/platform/fio/actor_test.go new file mode 100644 index 000000000..df2db0fcc --- /dev/null +++ b/platform/fio/actor_test.go @@ -0,0 +1,67 @@ +package fio + +import ( + "encoding/hex" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestActorFromPublicKey(t *testing.T) { + addrArr := []string{ + "FIO6cDpi7vPnvRwMEdXtLnAmFwygaQ8CzD7vqKLBJ2GfgtHBQ4PPy", + "FIO7uMZoeei5HtXAD24C4yCkpWWbf24bjYtrRNjWdmGCXHZccwuiE", + "FIO7bxrQUTbQ4mqcoefhWPz1aFieN4fA9RQAiozRz7FrUChHZ7Rb8", + "FIO6m1fMdTpRkRBnedvYshXCxLFiC5suRU8KDfx8xxtXp2hntxpnf", + "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o", + "2odzomo2v4pe", // actor + "hhq2g4qgycfb", // actor + "FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575", // invalid length + "FIO5kJKNHwctcfUM5XZyiWSqSTM5H", // invalid length + "FIO5kJKNHwct", // assume actor + } + actorArr := []string{ + "2odzomo2v4pe", + "hhq2g4qgycfb", + "5kmx4qbqlpld", + "qdfejz2a5wpl", + "ezsmbcy2opod", + "ltwagbt4qpuk", + "2odzomo2v4pe", + "hhq2g4qgycfb", + "", + "", + "FIO5kJKNHwct", + } + for i := range addrArr { + assert.Equal(t, actorArr[i], actorFromPublicKeyOrActor(actorArr[i])) + } +} + +func TestBytesFromPublicKeyString(t *testing.T) { + { + pkBytes, err := bytesFromPublicKeyString("FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o") + assert.Equal(t, nil, err) + assert.Equal(t, 37, len(pkBytes)) + assert.Equal(t, "0271195c66ec2799e436757a70cd8431d4b17733a097b18a5f7f1b6b085978ff0f343fc54e", hex.EncodeToString(pkBytes)) + } + { + pkBytes, err := bytesFromPublicKeyString("FIO6cDpi7vPnvRwMEdXtLnAmFwygaQ8CzD7vqKLBJ2GfgtHBQ4PPy") + assert.Equal(t, nil, err) + assert.Equal(t, "02e274495ff4d2f4027bc4d5ead805b0197f19efe526ba2c1c5545ba916d6088a7248a8bf4", hex.EncodeToString(pkBytes)) + } + { + pkBytes, err := bytesFromPublicKeyString("FIO6cDpi7vPnvRwMEdXtLnAmFwygaQ8CzD7vqKLBJ2GfgtHBQ4P") + assert.True(t, err != nil) + assert.Equal(t, 0, len(pkBytes)) + } +} + +func TestShortenKey(t *testing.T) { + pkBytes, _ := hex.DecodeString("02e274495ff4d2f4027bc4d5ead805b0197f19efe526ba2c1c5545ba916d6088a7248a8bf4") + assert.Equal(t, uint64(1518832697283783336), shortenKey(pkBytes)) +} + +func TestGetName(t *testing.T) { + assert.Equal(t, "2odzomo2v4pec", getName(uint64(1518832697283783336))) +} diff --git a/platform/fio/client.go b/platform/fio/client.go index 56a68c055..4a573bf0d 100644 --- a/platform/fio/client.go +++ b/platform/fio/client.go @@ -10,9 +10,21 @@ type Client struct { blockatlas.Request } +func (c *Client) getTransactions(account string) (actions []Action, error error) { + var res GetActionsResponse + err := c.Post(&res, "v1/history/get_actions", GetActionsRequest{ + AccountName: account, + Sort: "desc", + }) + if err != nil { + return nil, errors.E(err, "Error from get_actions", errors.Params{"account_name": account, "inner_error": err.Error()}) + } + return res.Actions, nil +} + func (c *Client) lookupPubAddress(name string, coinSymbol string) (address string, error error) { var res GetPubAddressResponse - err := c.Post(&res, "get_pub_address", GetPubAddressRequest{FioAddress: name, TokenCode: coinSymbol, ChainCode: coinSymbol}) + err := c.Post(&res, "v1/chain/get_pub_address", GetPubAddressRequest{FioAddress: name, TokenCode: coinSymbol, ChainCode: coinSymbol}) if err != nil { return "", errors.E(err, "Error looking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": err.Error()}) } diff --git a/platform/fio/model.go b/platform/fio/model.go index 404a05b3f..61d3cc93a 100644 --- a/platform/fio/model.go +++ b/platform/fio/model.go @@ -1,5 +1,45 @@ package fio +// ActionData (from get_actions) +type ActionData struct { + From string `json:"from"` + To string `json:"to"` + Quantity string `json:"quantity"` + Memo string `json:"memo"` +} + +// ActionAct (from get_actions) +type ActionAct struct { + Account string `json:"account"` + Name string `json:"name"` + Data interface{} `json:"data"` // Structure of data is action-specific +} + +// ActionTrace +type ActionTrace struct { + Act ActionAct `json:"act"` + TrxID string `json:"trx_id"` +} + +// Action (from get_actions) +type Action struct { + BlockNum uint64 `json:"block_num"` + BlockTime string `json:"block_time"` + ActionTrace ActionTrace `json:"action_trace"` +} + +// GetActionsRequest request struct for get_actions +type GetActionsRequest struct { + AccountName string `json:"account_name"` + // pos, offset + Sort string `json:"sort"` // desc +} + +// GetActionsResponse request struct for get_actions +type GetActionsResponse struct { + Actions []Action `json:"actions"` +} + // GetPubAddressRequest request struct for get_pub_address type GetPubAddressRequest struct { FioAddress string `json:"fio_address"` @@ -10,6 +50,5 @@ type GetPubAddressRequest struct { // GetPubAddressResponse response struct for get_pub_address type GetPubAddressResponse struct { PublicAddress string `json:"public_address"` - BlockNum int `json:"block_num"` Message string `json:"message"` } diff --git a/platform/fio/transaction.go b/platform/fio/transaction.go index 11f87aef5..df2d5e22b 100644 --- a/platform/fio/transaction.go +++ b/platform/fio/transaction.go @@ -1,9 +1,78 @@ package fio import ( + "encoding/json" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "strconv" + "strings" + "time" ) func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err error) { - return page, err + // take actor from address + account := actorFromPublicKeyOrActor(address) + actions, err := p.client.getTransactions(account) + if err != nil { + return nil, err + } + txs := make([]blockatlas.Tx, 0) + for _, a := range actions { + tx, err := p.Normalize(&a, account) + if err != nil { + continue + } + txs = append(txs, tx) + } + txPage := blockatlas.TxPage(txs) + return txPage, nil +} + +func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, error) { + var ( + to, from string + amount blockatlas.Amount + ) + const dateFormat string = "2006-01-02T15:04:05" + + // Action type "transfer" handled (trnsfiopubky not) + if action.ActionTrace.Act.Account == "fio.token" && + action.ActionTrace.Act.Name == "transfer" { + // convert to action-specific data + var actionData ActionData + dataJSON, err := json.Marshal(action.ActionTrace.Act.Data) + if err != nil { + return blockatlas.Tx{}, errors.E("Unparseable Data field") + } + if json.Unmarshal(dataJSON, &actionData) != nil { + return blockatlas.Tx{}, errors.E("Unparseable Data field") + } + from = actionData.From + to = actionData.To + amountNum, err := strconv.ParseFloat(strings.Split(actionData.Quantity, " ")[0], 64) + if err == nil { + amount = blockatlas.Amount(strconv.Itoa(int(amountNum * 1000000000))) + } + date, _ := time.Parse(dateFormat, action.BlockTime) + tx := blockatlas.Tx{ + ID: action.ActionTrace.TrxID, + Coin: p.Coin().ID, + Date: date.Unix(), + From: from, + To: to, + Block: action.BlockNum, + Status: blockatlas.StatusCompleted, + Fee: "0", // trnsfiopubky: actionData.Fee + Meta: blockatlas.Transfer{ + Value: amount, + Symbol: p.Coin().Symbol, + Decimals: p.Coin().Decimals, + }, + Memo: actionData.Memo, + Type: blockatlas.TxTransfer, + } + tx.Direction = tx.GetTransactionDirection(account) + return tx, nil + } + return blockatlas.Tx{}, errors.E("Unknown action") } diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index 2011df49a..27aab3ac5 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -346,5 +346,23 @@ "address": "xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD", "expectedTxNum": 2, "expectedTxId": "2b67e2fbe6a212286243bc539cca3c1d877e85ffec7c925e34f2bfb7b6cc498c" + }, + { + "handler": "fio", + "address": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "expectedTxNum": 2, + "expectedTxId": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8" + }, + { + "handler": "fio", + "address": "ezsmbcy2opod", + "expectedTxNum": 2, + "expectedTxId": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8" + }, + { + "handler": "fio", + "address": "FIO6gZthsHigy7wXeev4MKS4MuoygkxQ1yirmmUqpoubDWLJTASa2", + "expectedTxNum": 1, + "expectedTxId": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a" } ] From e15458235eb46ceb6c7b8833bfc730ad01156dcc Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Wed, 1 Apr 2020 19:12:54 -0700 Subject: [PATCH 224/506] Fix Tezos Delegation direction (#995) * Fix Tezos Delegation direciton * Handle if some transaction types unsuported --- platform/tezos/model.go | 26 ++++++++++++++------------ platform/tezos/model_test.go | 34 +++++++++++++++++++--------------- platform/tezos/transaction.go | 18 ++++++++++++++---- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/platform/tezos/model.go b/platform/tezos/model.go index 451b39c07..836b4fbb1 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -67,16 +67,18 @@ func (t *Transaction) ErrorMsg() string { } } -func (t *Transaction) Title() blockatlas.KeyTitle { - if t.Delegate == "" && t.Receiver != "" { - return blockatlas.AnyActionDelegation +func (t *Transaction) Title(address string) (blockatlas.KeyTitle, bool) { + if t.Type == TxTypeDelegation { + if address == t.Sender && t.Delegate != "" && t.Receiver == "" { + return blockatlas.AnyActionDelegation, true + } + + if address == t.Sender && t.Delegate == "" && t.Receiver != "" { + return blockatlas.AnyActionUndelegation, true + } } - if t.Delegate != "" && t.Receiver == "" { - return blockatlas.AnyActionUndelegation - } - - return blockatlas.AnyActionDelegation + return "unsupported title", false } func (t *Transaction) BlockTimestamp() int64 { @@ -88,14 +90,14 @@ func (t *Transaction) BlockTimestamp() int64 { return unix } -func (t *Transaction) TransferType() blockatlas.TransactionType { +func (t *Transaction) TransferType() (blockatlas.TransactionType, bool) { switch t.Type { case TxTypeTransaction: - return blockatlas.TxTransfer + return blockatlas.TxTransfer, true case TxTypeDelegation: - return blockatlas.TxAnyAction + return blockatlas.TxAnyAction, true default: - return "" + return "unsupported type", false } } diff --git a/platform/tezos/model_test.go b/platform/tezos/model_test.go index 7243c1a95..153adfce8 100644 --- a/platform/tezos/model_test.go +++ b/platform/tezos/model_test.go @@ -45,19 +45,23 @@ func TestTransaction_Status(t *testing.T) { } testsTitle := []struct { - name string - in Transaction - out blockatlas.KeyTitle + name string + address string + in Transaction + out blockatlas.KeyTitle }{ - {"Delegation", Transaction{Delegate: "", Receiver: addr1}, blockatlas.AnyActionDelegation}, - {"Undelegation", Transaction{Delegate: addr1, Receiver: ""}, blockatlas.AnyActionUndelegation}, - {"Delegation", Transaction{Delegate: "", Receiver: ""}, blockatlas.AnyActionDelegation}, - {"Delegation", Transaction{Delegate: addr1, Receiver: addr1}, blockatlas.AnyActionDelegation}, + {"Delegation title", addr1, Transaction{Sender: addr1, Delegate: addr2, Receiver: "", Type: TxTypeDelegation}, blockatlas.AnyActionDelegation}, + {"Undelegation title", addr1, Transaction{Sender: addr1, Delegate: "", Receiver: addr2, Type: TxTypeDelegation}, blockatlas.AnyActionUndelegation}, + {"Unsupported title", addr1, Transaction{Sender: addr1, Delegate: addr1, Receiver: addr1}, "unsupported title"}, + {"Unsupported title", addr1, Transaction{Sender: addr1, Delegate: addr2, Receiver: addr1}, "unsupported title"}, + {"Unsupported title", addr1, Transaction{Sender: addr1, Delegate: addr1, Receiver: addr2}, "unsupported title"}, + {"Unsupported title", addr1, Transaction{Sender: addr1, Delegate: addr2, Receiver: addr2}, "unsupported title"}, } for _, tt := range testsTitle { t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.out, tt.in.Title()) + title, _ := tt.in.Title(tt.address) + assert.Equal(t, tt.out, title) }) } @@ -75,20 +79,20 @@ func TestTransaction_Status(t *testing.T) { }) } - testsKind := []struct { + testsTransferType := []struct { name string in Transaction out blockatlas.TransactionType }{ - {"Type should be transaction", Transaction{Type: "transaction"}, blockatlas.TxTransfer}, - {"Type should be delegation", Transaction{Type: "delegation"}, blockatlas.TxAnyAction}, - {"Type unsupported", Transaction{Type: "bake"}, ""}, - {"Type endorsement", Transaction{Type: "endorsement"}, ""}, + {"Type should be transaction", Transaction{Type: "transaction",}, blockatlas.TxTransfer}, + {"Type should be delegation", Transaction{Type: "delegation",}, blockatlas.TxAnyAction}, + {"Type unsupported", Transaction{Type: "bake"}, "unsupported type"}, } - for _, tt := range testsKind { + for _, tt := range testsTransferType { t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.out, tt.in.TransferType()) + transferType, _ := tt.in.TransferType() + assert.Equal(t, tt.out, transferType) }) } diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index 73347a0c7..023e84e65 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -31,7 +31,13 @@ func NormalizeTxs(srcTxs []Transaction, address string) (txs []blockatlas.Tx) { // NormalizeTx converts a Tezos transaction into the generic model func NormalizeTx(srcTx Transaction, address string) (blockatlas.Tx, bool) { - var tx = blockatlas.Tx{ + var tx blockatlas.Tx + tt, ok := srcTx.TransferType() + if !ok { + return tx, false + } + + tx = blockatlas.Tx{ Block: srcTx.Height, Coin: coin.XTZ, Date: srcTx.BlockTimestamp(), @@ -41,18 +47,22 @@ func NormalizeTx(srcTx Transaction, address string) (blockatlas.Tx, bool) { ID: srcTx.Hash, Status: srcTx.Status(), To: srcTx.GetReceiver(), - Type: srcTx.TransferType(), + Type: tt, } if address != "" { tx.Direction = srcTx.Direction(address) } value := blockatlas.Amount(numbers.DecimalExp(numbers.Float64toString(srcTx.Volume), 6)) - switch srcTx.TransferType() { + switch tt { case blockatlas.TxAnyAction: + title, ok := srcTx.Title(address) + if !ok { + return tx, false + } tx.Meta = blockatlas.AnyAction{ Coin: coin.Tezos().ID, - Title: srcTx.Title(), + Title: title, Key: blockatlas.KeyStakeDelegate, Name: coin.Tezos().Name, Symbol: coin.Tezos().Symbol, From 92a973fcc68f1bb7d394bfe30f43bd2c85c83563 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 3 Apr 2020 03:00:11 +0300 Subject: [PATCH 225/506] Update README.md --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5f7089bd7..71f0b92d0 100644 --- a/README.md +++ b/README.md @@ -50,16 +50,21 @@ Platform API is independent service and can work with the specific blockchain on Notifications: -(Sub Producer) - Subscribe to specific coin [Not implemented at Atlas, write it on your own] +(Observer Subscriber Producer) - Create new blockatlas.SubscriptionEvent [Not implemented at Atlas, write it on your own] -(Sub Consumer) - Save all the subscriptions to the Redis [Implemented, you can see it at cmd/observer_subscriber] +(Observer Subscriber) - Get subscriptions from queue, set them to the DB -(Tx Notifier Producer) - Parse the block, check transactions, find addresses in Redis and push the tx details for these addresses [Implemented, you can see it at cmd/observer_worker] +(Observer Parser) - Parse the block, convert block to the transactions batch, send to queue -(Tx Notifier Consumer) - Notify users, get tx informations by GUID from queue [Not implemented at Atlas, write it on your own] +(Observer Notifier) - Check each transaction for having the same address as stored at DB, if so - send tx data and id to the next queue + +(Observer Notifier Consumer) - Notify the user [Not implemented at Atlas, write it on your own] ``` -Sub Producer --(Rabbit MQ)--> Sub Consumer --(Redis)--> Tx Notifier Producer --(Rabbit MQ)--> Tx Notifier Consumer --> User +New Subscriptions --(Rabbit MQ)--> Subscriber --> DB + | + Parser --(Rabbit MQ)--> Notifier --(Rabbit MQ)--> Notifier Consumer --> User + ``` The whole flow is not availible at Atlas repo. We will have integration tests with it. Also there will be examples of all instances soon. @@ -69,7 +74,7 @@ The whole flow is not availible at Atlas repo. We will have integration tests wi ### Requirements * [Go Toolchain](https://golang.org/doc/install) versions 1.13+ - * [Redis](https://redis.io/topics/quickstart) instance for platform_observer + * [Postgres](https://www.postgresql.org/download) storing user subscriptions and latest parsed block number * [Rabbit MQ](https://www.rabbitmq.com/#getstarted) using to pass subscriptions and send transaction notifications ### From Source From 03618767054600721daa695f51b3ead813e2dcf4 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 3 Apr 2020 11:41:29 +0300 Subject: [PATCH 226/506] Update README.md --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 71f0b92d0..a0f5a6678 100644 --- a/README.md +++ b/README.md @@ -95,8 +95,11 @@ It works the same for observer_worker - you can run all observer at 1 binary or go get -u github.com/trustwallet/blockatlas cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas -# Start observer_worker with the path to the config.yml ./ -go build -o observer_worker-bin cmd/observer_worker/main.go && ./observer_worker-bin -c config.yml +# Start observer_parser with the path to the config.yml ./ +go build -o observer_parser-bin cmd/observer_parser/main.go && ./observer_parser-bin -c config.yml + +# Start observer_notifier with the path to the config.yml ./ +go build -o observer_notifier-bin cmd/observer_notifier/main.go && ./observer_notifier-bin -c config.yml # Start observer_subscriber with the path to the config.yml ./ go build -o observer_subscriber-bin cmd/observer_subscriber/main.go && ./observer_subscriber-bin -c config.yml From 6609d09e79e91273df6cebc6e5dc4132554bc4ed Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 3 Apr 2020 11:42:08 +0300 Subject: [PATCH 227/506] Update README.md --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index a0f5a6678..5c674aa4a 100644 --- a/README.md +++ b/README.md @@ -125,10 +125,6 @@ make start Build and run from local Dockerfile: -You should change `config.yml`: -```yaml -redis: redis://redis:6379 -``` Then build: ```shell docker-compose build From dd1dea3515226397430eb091487b76ad760c4166 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Fri, 3 Apr 2020 13:04:54 +0200 Subject: [PATCH 228/506] [WIP] Adapt FIO lookup to mainnet FIO domains (@trust, ...). (#1001) * Adapt FIO lookup to mainnet FIO domains (@trust, ...). Co-authored-by: Catenocrypt --- mock/ext-api-dyson/post/fio-api-chain.js | 27 ++++++++++++++++-------- services/domains/domains.go | 27 +++++++++++++++++------- tests/postman/domain_data.json | 16 +++++++++++++- 3 files changed, 52 insertions(+), 18 deletions(-) diff --git a/mock/ext-api-dyson/post/fio-api-chain.js b/mock/ext-api-dyson/post/fio-api-chain.js index 480e1194e..3a9903962 100644 --- a/mock/ext-api-dyson/post/fio-api-chain.js +++ b/mock/ext-api-dyson/post/fio-api-chain.js @@ -3,9 +3,9 @@ /// - public address for certain fio name and coin combinations /// - public address not found message for other input /// See: -/// curl -H "Content-Type: application/json" -d '{"fio_address":"adam@fiotestnet","token_code":"BTC","chain_code":"BTC"}' "http://localhost:3000/fio-api/v1/chain/get_pub_address" -/// curl -H "Content-Type: application/json" -d '{"fio_address":"adam@fiotestnet","token_code":"BTC","chain_code":"BTC"}' "http://testnet.fioprotocol.io/v1/chain/get_pub_address" -/// curl "http://localhost:8420/v2/ns/lookup?name=adam@fiotestnet&coins=60" +/// curl -H "Content-Type: application/json" -d '{"fio_address":"trust@trust","token_code":"BTC","chain_code":"BTC"}' "http://localhost:3000/fio-api/v1/chain/get_pub_address" +/// curl -H "Content-Type: application/json" -d '{"fio_address":"trust@trust","token_code":"BTC","chain_code":"BTC"}' "http://testnet.fioprotocol.io/v1/chain/get_pub_address" +/// curl "http://localhost:8420/v2/ns/lookup?name=trust@trust&coins=60" module.exports = { path: '/fio-api/v1/chain/:action', @@ -22,11 +22,20 @@ module.exports = { }; function getAddress(fio_address, token_code) { - if (fio_address !== 'adam@fiotestnet') { return ''; } - switch (token_code) { - case 'BTC': return 'bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v'; - case 'ETH': return '0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51'; - case 'BNB': return 'bnb1ts3dg54apwlvr9hupv2n0j6e46q54znnusjk9s'; - default: return ''; + switch (fio_address) { + case 'trust@trust': + switch (token_code) { + case 'BTC': return 'bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v'; + case 'ETH': return '0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51'; + case 'BNB': return 'bnb1ts3dg54apwlvr9hupv2n0j6e46q54znnusjk9s'; + default: return ''; + } + + case 'trust@trustwallet': + return '0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a0001'; + + case 'name@somefiodomain': + return '0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a0002'; } + return ''; }; diff --git a/services/domains/domains.go b/services/domains/domains.go index e814230c8..1ba1a5a05 100644 --- a/services/domains/domains.go +++ b/services/domains/domains.go @@ -12,13 +12,17 @@ import ( // TLDMapping Mapping of name TLD's to coin where they are handled var TLDMapping = map[string]uint64{ - ".eth": CoinType.ETH, - ".xyz": CoinType.ETH, - ".luxe": CoinType.ETH, - ".kred": CoinType.ETH, - ".zil": CoinType.ZIL, - ".crypto": CoinType.ZIL, - "@fiotestnet": CoinType.FIO, + ".eth": CoinType.ETH, + ".xyz": CoinType.ETH, + ".luxe": CoinType.ETH, + ".kred": CoinType.ETH, + ".zil": CoinType.ZIL, + ".crypto": CoinType.ZIL, + "@trust": CoinType.FIO, + "@trustwallet": CoinType.FIO, + "@binance": CoinType.FIO, + "@fiomembers": CoinType.FIO, + "@": CoinType.FIO, // any FIO domain } func HandleLookup(name string, coins []uint64) ([]blockatlas.Resolved, error) { @@ -30,7 +34,14 @@ func HandleLookup(name string, coins []uint64) ([]blockatlas.Resolved, error) { } id, ok := TLDMapping[tld] if !ok { - return nil, errors.E("name not found", errors.Params{"name": name, "coins": coins, "tld": tld}) + // special handling for FIO, any fio domain + if len(tld) >= 2 && tld[0] == '@' { + tld = string("@") + id, ok = TLDMapping[tld] + if !ok { + return nil, errors.E("name not found", errors.Params{"name": name, "coins": coins, "tld": tld}) + } + } } api, ok := platform.NamingAPIs[id] if !ok { diff --git a/tests/postman/domain_data.json b/tests/postman/domain_data.json index 52db7664b..85b7ee26b 100644 --- a/tests/postman/domain_data.json +++ b/tests/postman/domain_data.json @@ -35,10 +35,24 @@ "address": "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64" }, { - "domain": "adam@fiotestnet", + "domain": "trust@trust", "coins": [ 60 ], "address": "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51" + }, + { + "domain": "trust@trustwallet", + "coins": [ + 60 + ], + "address": "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a0001" + }, + { + "domain": "name@somefiodomain", + "coins": [ + 60 + ], + "address": "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a0002" } ] \ No newline at end of file From a70c50cc73b0ac1bae73aafe473d589cd51cbf64 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Fri, 3 Apr 2020 15:52:00 +0200 Subject: [PATCH 229/506] FIO tx history fixes (#1002) * Adapt FIO lookup to mainnet FIO domains (@trust, ...). * FIO history: limit API query to 100 actions. * FIO API: switch to fio.greymass.com. * FIO history: handle "trnsfiopubky" transfer. --- config.yml | 2 +- mock/ext-api-dyson/post/fio-api-history.js | 2 +- platform/fio/client.go | 2 + platform/fio/model.go | 19 +++++++-- platform/fio/transaction.go | 47 +++++++++++++++------- tests/postman/transaction_data.json | 6 +-- 6 files changed, 55 insertions(+), 23 deletions(-) diff --git a/config.yml b/config.yml index 057ece881..9ae5439e4 100644 --- a/config.yml +++ b/config.yml @@ -150,7 +150,7 @@ nebulas: # [FIO] FIO: https://fioprotocol.io fio: - api: https://fio.eosphere.io + api: https://fio.greymass.com # [BTC] Bitcoin: https://bitcoin.org/ (Blockbook API https://github.com/trezor/blockbook) bitcoin: diff --git a/mock/ext-api-dyson/post/fio-api-history.js b/mock/ext-api-dyson/post/fio-api-history.js index 9c829f7e1..a96cae5fd 100644 --- a/mock/ext-api-dyson/post/fio-api-history.js +++ b/mock/ext-api-dyson/post/fio-api-history.js @@ -1,5 +1,5 @@ /// FIO RPC API Mock, history API -/// curl -H "Content-Type: application/json" -d '{"account_name": "ezsmbcy2opod"}' https://fio.eosphere.io/v1/history/get_actions +/// curl -H "Content-Type: application/json" -d '{"account_name": "ezsmbcy2opod"}' https://fio.greymass.com/v1/history/get_actions /// curl -H "Content-Type: application/json" -d '{"account_name": "ezsmbcy2opod"}' http://localhost:3000/fio-api/v1/history/get_actions /// curl "http://localhost:8420/v1/fio/FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt" diff --git a/platform/fio/client.go b/platform/fio/client.go index 4a573bf0d..3a0299a9a 100644 --- a/platform/fio/client.go +++ b/platform/fio/client.go @@ -14,6 +14,8 @@ func (c *Client) getTransactions(account string) (actions []Action, error error) var res GetActionsResponse err := c.Post(&res, "v1/history/get_actions", GetActionsRequest{ AccountName: account, + Pos: -1, // latest + Offset: -100, // 100 before last; use 100 because not all actions are transfers Sort: "desc", }) if err != nil { diff --git a/platform/fio/model.go b/platform/fio/model.go index 61d3cc93a..5eb91f16b 100644 --- a/platform/fio/model.go +++ b/platform/fio/model.go @@ -1,13 +1,22 @@ package fio -// ActionData (from get_actions) -type ActionData struct { +// ActionDataTransfer (from get_actions) +type ActionDataTransfer struct { From string `json:"from"` To string `json:"to"` Quantity string `json:"quantity"` Memo string `json:"memo"` } +// ActionDataTrnsfiopubky (from get_actions) +type ActionDataTrnsfiopubky struct { + PayeePublicKey string `json:"payee_public_key"` + Amount int64 `json:"amount"` + MaxFee int64 `json:"max_fee"` + Actor string `json:"actor"` + TpID string `json:"tpid"` +} + // ActionAct (from get_actions) type ActionAct struct { Account string `json:"account"` @@ -29,10 +38,12 @@ type Action struct { } // GetActionsRequest request struct for get_actions +// see https://github.com/EOSIO/eos/blob/master/plugins/history_plugin/include/eosio/history_plugin/history_plugin.hpp type GetActionsRequest struct { AccountName string `json:"account_name"` - // pos, offset - Sort string `json:"sort"` // desc + Pos int32 `json:"pos"` + Offset int32 `json:"offset"` + Sort string `json:"sort"` // desc } // GetActionsResponse request struct for get_actions diff --git a/platform/fio/transaction.go b/platform/fio/transaction.go index df2d5e22b..67a76657d 100644 --- a/platform/fio/transaction.go +++ b/platform/fio/transaction.go @@ -30,28 +30,47 @@ func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, error) { var ( - to, from string - amount blockatlas.Amount + to, from string + amount, fee blockatlas.Amount + memo string ) const dateFormat string = "2006-01-02T15:04:05" // Action type "transfer" handled (trnsfiopubky not) if action.ActionTrace.Act.Account == "fio.token" && - action.ActionTrace.Act.Name == "transfer" { + (action.ActionTrace.Act.Name == "transfer" || action.ActionTrace.Act.Name == "trnsfiopubky") { // convert to action-specific data - var actionData ActionData dataJSON, err := json.Marshal(action.ActionTrace.Act.Data) if err != nil { return blockatlas.Tx{}, errors.E("Unparseable Data field") } - if json.Unmarshal(dataJSON, &actionData) != nil { - return blockatlas.Tx{}, errors.E("Unparseable Data field") - } - from = actionData.From - to = actionData.To - amountNum, err := strconv.ParseFloat(strings.Split(actionData.Quantity, " ")[0], 64) - if err == nil { - amount = blockatlas.Amount(strconv.Itoa(int(amountNum * 1000000000))) + switch action.ActionTrace.Act.Name { + case "transfer": + var actionData ActionDataTransfer + if json.Unmarshal(dataJSON, &actionData) != nil { + return blockatlas.Tx{}, errors.E("Unparseable Data field") + } + from = actionData.From + to = actionData.To + amountNum, err := strconv.ParseFloat(strings.Split(actionData.Quantity, " ")[0], 64) + if err == nil { + amount = blockatlas.Amount(strconv.Itoa(int(amountNum * 1000000000))) + } + // fee unknown + memo = actionData.Memo + break + + case "trnsfiopubky": + var actionData ActionDataTrnsfiopubky + if json.Unmarshal(dataJSON, &actionData) != nil { + return blockatlas.Tx{}, errors.E("Unparseable Data field") + } + from = actionData.Actor + to = actorFromPublicKeyOrActor(actionData.PayeePublicKey) + amount = blockatlas.Amount(strconv.FormatInt(actionData.Amount, 10)) + fee = blockatlas.Amount(strconv.FormatInt(actionData.MaxFee, 10)) + // no memo + break } date, _ := time.Parse(dateFormat, action.BlockTime) tx := blockatlas.Tx{ @@ -62,13 +81,13 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err To: to, Block: action.BlockNum, Status: blockatlas.StatusCompleted, - Fee: "0", // trnsfiopubky: actionData.Fee + Fee: fee, Meta: blockatlas.Transfer{ Value: amount, Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, }, - Memo: actionData.Memo, + Memo: memo, Type: blockatlas.TxTransfer, } tx.Direction = tx.GetTransactionDirection(account) diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index 27aab3ac5..32f8f3a3f 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -350,19 +350,19 @@ { "handler": "fio", "address": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", - "expectedTxNum": 2, + "expectedTxNum": 3, "expectedTxId": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8" }, { "handler": "fio", "address": "ezsmbcy2opod", - "expectedTxNum": 2, + "expectedTxNum": 3, "expectedTxId": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8" }, { "handler": "fio", "address": "FIO6gZthsHigy7wXeev4MKS4MuoygkxQ1yirmmUqpoubDWLJTASa2", - "expectedTxNum": 1, + "expectedTxNum": 2, "expectedTxId": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a" } ] From 17901cfa242d4eb9b611f532f1899e0541d9b0b4 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Sat, 4 Apr 2020 21:10:39 +0800 Subject: [PATCH 230/506] return action sequence (#1007) --- platform/fio/model.go | 1 + platform/fio/transaction.go | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/platform/fio/model.go b/platform/fio/model.go index 5eb91f16b..ee5ef15bb 100644 --- a/platform/fio/model.go +++ b/platform/fio/model.go @@ -32,6 +32,7 @@ type ActionTrace struct { // Action (from get_actions) type Action struct { + ActionSeq uint64 `json:"account_action_seq"` BlockNum uint64 `json:"block_num"` BlockTime string `json:"block_time"` ActionTrace ActionTrace `json:"action_trace"` diff --git a/platform/fio/transaction.go b/platform/fio/transaction.go index 67a76657d..c70a0cead 100644 --- a/platform/fio/transaction.go +++ b/platform/fio/transaction.go @@ -2,11 +2,12 @@ package fio import ( "encoding/json" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "strconv" "strings" "time" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" ) func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err error) { @@ -58,8 +59,6 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err } // fee unknown memo = actionData.Memo - break - case "trnsfiopubky": var actionData ActionDataTrnsfiopubky if json.Unmarshal(dataJSON, &actionData) != nil { @@ -70,18 +69,18 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err amount = blockatlas.Amount(strconv.FormatInt(actionData.Amount, 10)) fee = blockatlas.Amount(strconv.FormatInt(actionData.MaxFee, 10)) // no memo - break } date, _ := time.Parse(dateFormat, action.BlockTime) tx := blockatlas.Tx{ - ID: action.ActionTrace.TrxID, - Coin: p.Coin().ID, - Date: date.Unix(), - From: from, - To: to, - Block: action.BlockNum, - Status: blockatlas.StatusCompleted, - Fee: fee, + ID: action.ActionTrace.TrxID, + Coin: p.Coin().ID, + Date: date.Unix(), + From: from, + To: to, + Block: action.BlockNum, + Sequence: action.ActionSeq, + Status: blockatlas.StatusCompleted, + Fee: fee, Meta: blockatlas.Transfer{ Value: amount, Symbol: p.Coin().Symbol, From 597f596a700e87b9a4aa784240034661dd8a60dd Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Sun, 5 Apr 2020 08:12:36 +0800 Subject: [PATCH 231/506] Fix duplicated trnsfiopubky items, skip meaningless fee action (#1008) * Fix duplicated trnsfiopubky items, skip meaningless fee action * update mock data * Fix expectedTxId --- platform/fio/transaction.go | 34 ++++++++++++++++++++++++----- tests/postman/transaction_data.json | 12 +++++----- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/platform/fio/transaction.go b/platform/fio/transaction.go index c70a0cead..758be6752 100644 --- a/platform/fio/transaction.go +++ b/platform/fio/transaction.go @@ -2,6 +2,8 @@ package fio import ( "encoding/json" + "fmt" + "sort" "strconv" "strings" "time" @@ -25,19 +27,20 @@ func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err } txs = append(txs, tx) } + txs = unique(txs) txPage := blockatlas.TxPage(txs) + sort.Sort(txPage) return txPage, nil } func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, error) { var ( - to, from string - amount, fee blockatlas.Amount - memo string + to, from, memo string + amount, fee blockatlas.Amount + sequence uint64 ) const dateFormat string = "2006-01-02T15:04:05" - // Action type "transfer" handled (trnsfiopubky not) if action.ActionTrace.Act.Account == "fio.token" && (action.ActionTrace.Act.Name == "transfer" || action.ActionTrace.Act.Name == "trnsfiopubky") { // convert to action-specific data @@ -51,6 +54,9 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err if json.Unmarshal(dataJSON, &actionData) != nil { return blockatlas.Tx{}, errors.E("Unparseable Data field") } + if actionData.Memo == "FIO API fees. Thank you." { + return blockatlas.Tx{}, errors.E("Skip meaningless hardcoded fee action") + } from = actionData.From to = actionData.To amountNum, err := strconv.ParseFloat(strings.Split(actionData.Quantity, " ")[0], 64) @@ -59,6 +65,7 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err } // fee unknown memo = actionData.Memo + sequence = action.ActionSeq case "trnsfiopubky": var actionData ActionDataTrnsfiopubky if json.Unmarshal(dataJSON, &actionData) != nil { @@ -68,7 +75,7 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err to = actorFromPublicKeyOrActor(actionData.PayeePublicKey) amount = blockatlas.Amount(strconv.FormatInt(actionData.Amount, 10)) fee = blockatlas.Amount(strconv.FormatInt(actionData.MaxFee, 10)) - // no memo + // not set sequence because it might be duplicated } date, _ := time.Parse(dateFormat, action.BlockTime) tx := blockatlas.Tx{ @@ -78,7 +85,7 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err From: from, To: to, Block: action.BlockNum, - Sequence: action.ActionSeq, + Sequence: sequence, Status: blockatlas.StatusCompleted, Fee: fee, Meta: blockatlas.Transfer{ @@ -94,3 +101,18 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err } return blockatlas.Tx{}, errors.E("Unknown action") } + +func unique(txs []blockatlas.Tx) []blockatlas.Tx { + set := make(map[string]struct{}) + var result []blockatlas.Tx + for _, tx := range txs { + id := fmt.Sprintf("%s-%d", tx.ID, tx.Sequence) + if _, ok := set[id]; ok { + continue + } else { + set[id] = struct{}{} + result = append(result, tx) + } + } + return result +} diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index 32f8f3a3f..7e3468453 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -350,19 +350,19 @@ { "handler": "fio", "address": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", - "expectedTxNum": 3, - "expectedTxId": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8" + "expectedTxNum": 1, + "expectedTxId": "2e0a7dc3640768e1d644cee871734dd2efa23e65a54c438c1ba03801d7386fb7" }, { "handler": "fio", "address": "ezsmbcy2opod", - "expectedTxNum": 3, - "expectedTxId": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8" + "expectedTxNum": 1, + "expectedTxId": "2e0a7dc3640768e1d644cee871734dd2efa23e65a54c438c1ba03801d7386fb7" }, { "handler": "fio", "address": "FIO6gZthsHigy7wXeev4MKS4MuoygkxQ1yirmmUqpoubDWLJTASa2", - "expectedTxNum": 2, - "expectedTxId": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a" + "expectedTxNum": 1, + "expectedTxId": "d2dd588ac5e46cb072d0a2673ea59b88187f0331b26906fabbafddbcea291450" } ] From 3c3aac7c93bc0bd54174363bd3ddc63eecb67476 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 5 Apr 2020 07:54:21 +0300 Subject: [PATCH 232/506] [Postgres fixes] and new field, add tests (#999) * PG fixes and new field, add tests Add updated_at field, fix issue with conflct, add test * Update dockerfile and go.mod * Update configmock.yml * Change test pkg for theta * Update go.mod * Add composite private key * Resolve on conflict issue * Requested changes and remove log mode --- configmock.yml | 6 +- db/db.go | 1 + db/models/subscriptions.go | 13 +- db/subscriptions.go | 17 +- docker-compose.yml | 33 ++- go.mod | 56 ++-- go.sum | 274 +++++++++++++----- platform/theta/transaction_test.go | 2 +- .../integration/db_test/subscriptions_test.go | 40 +++ 9 files changed, 324 insertions(+), 118 deletions(-) diff --git a/configmock.yml b/configmock.yml index 57d7f7c23..032ad773e 100644 --- a/configmock.yml +++ b/configmock.yml @@ -17,8 +17,6 @@ platform: all # The transaction watcher observer: - auth: test - # Don't request blocks older than this backlog: 3h # Don't request more than N blocks at once backlog_max_blocks: 200 @@ -33,8 +31,8 @@ observer: consumer: prefetch_count: 10 -storage: - redis: redis://localhost:6379 +postgres: + uri: postgresql://user:pass@localhost/my_db?sslmode=disable # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org diff --git a/db/db.go b/db/db.go index f62d16c0e..c20036ec1 100644 --- a/db/db.go +++ b/db/db.go @@ -23,6 +23,7 @@ func New(uri string) (*Instance, error) { &models.SubscriptionData{}, &models.Tracker{}, ) + i := &Instance{Gorm: g} return i, nil diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index df8e972c1..016e8624a 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -1,13 +1,16 @@ package models +import "time" + type Subscription struct { - SubscriptionId uint `gorm:"primary_key:true"` + SubscriptionId uint `gorm:"primary_key:true"` + UpdatedAt time.Time Data []SubscriptionData `gorm:"foreignkey:SubscriptionId"` } type SubscriptionData struct { - ID uint `gorm:"primary_key:true"` - SubscriptionId uint `sql:"index"` - Coin uint `sql:"index"` - Address string `sql:"index"` + ID uint `gorm:"primary_key;"` + SubscriptionId uint `gorm:"primary_key; column:subscription_id; auto_increment:false"` + Coin uint `gorm:"primary_key; column:coin; auto_increment:false"` + Address string `gorm:"primary_key; column:address; type:varchar(128)"` } diff --git a/db/subscriptions.go b/db/subscriptions.go index 73173976a..35bb2d2ec 100644 --- a/db/subscriptions.go +++ b/db/subscriptions.go @@ -6,8 +6,11 @@ import ( "github.com/trustwallet/blockatlas/pkg/errors" "strconv" "strings" + "time" ) +const rawBulkInsert = `INSERT INTO subscription_data(subscription_id, coin, address) VALUES %s ON CONFLICT DO NOTHING` + func (i *Instance) GetSubscriptionData(coin uint, addresses []string) ([]models.SubscriptionData, error) { if len(addresses) == 0 { return nil, errors.E("Empty addresses") @@ -53,7 +56,10 @@ func (i *Instance) AddSubscriptions(id uint, subscriptions []models.Subscription subscriptions = removeSubscriptionDuplicates(subscriptions) if recordNotFound { - if err = txInstance.Gorm.Create(&models.Subscription{SubscriptionId: id}).Error; err != nil { + err = txInstance.Gorm.Set("gorm:insert_option", + "ON CONFLICT (subscription_id) DO UPDATE SET subscription_id = excluded.subscription_id"). + Create(&models.Subscription{SubscriptionId: id, UpdatedAt: time.Now()}).Error + if err != nil { txInstance.Gorm.Rollback() return err } @@ -92,6 +98,11 @@ func (i *Instance) AddToExistingSubscription(id uint, subscriptions []models.Sub return err } } + + if err := i.Gorm.Model(&models.Subscription{SubscriptionId: id}).Update("updated_at", time.Now()).Error; err != nil { + return err + } + return nil } @@ -136,9 +147,7 @@ func (i *Instance) BulkCreate(dataList []models.SubscriptionData) error { valueArgs = append(valueArgs, d.Address) } - smt := `INSERT INTO subscription_data(subscription_id, coin, address) VALUES %s` - - smt = fmt.Sprintf(smt, strings.Join(valueStrings, ",")) + smt := fmt.Sprintf(rawBulkInsert, strings.Join(valueStrings, ",")) if err := i.Gorm.Exec(smt, valueArgs...).Error; err != nil { return err diff --git a/docker-compose.yml b/docker-compose.yml index c7513dccf..1a9faed94 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,14 +29,24 @@ services: ports: - 8423:8423 - observer_worker: + observer_notifier: build: context: . args: - SERVICE=observer_notifier links: - - redis - rabbit + - postgres + restart: on-failure + + observer_parser: + build: + context: . + args: + - SERVICE=observer_parser + links: + - rabbit + - postgres restart: on-failure observer_subscriber: @@ -46,8 +56,8 @@ services: args: - SERVICE=observer_subscriber links: - - redis - rabbit + - postgres restart: on-failure rabbit: @@ -61,8 +71,17 @@ services: timeout: 10s retries: 5 - redis: - container_name: redis - image: redis + postgres: + container_name: postgres + image: postgres + environment: + - POSTGRES_USER=user + - POSTGRES_PASSWORD=pass + - POSTGRES_DB=my_db ports: - - 6379:6379 + - 5432:5432 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5432"] + interval: 30s + timeout: 10s + retries: 5 diff --git a/go.mod b/go.mod index a91e3f674..951e0f820 100644 --- a/go.mod +++ b/go.mod @@ -1,57 +1,49 @@ module github.com/trustwallet/blockatlas -go 1.12 +go 1.14 require ( - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect - github.com/Microsoft/go-winio v0.4.14 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect - github.com/Pantani/httpexpect v2.0.0+incompatible github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 - github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect - github.com/alicebob/miniredis v2.5.0+incompatible + github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61 // indirect github.com/btcsuite/btcutil v1.0.1 github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c // indirect + github.com/dancannon/gorethink v3.0.5+incompatible // indirect github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/getsentry/sentry-go v0.4.0 - github.com/gin-gonic/gin v1.5.0 - github.com/go-redis/redis v6.15.6+incompatible - github.com/golang/protobuf v1.3.3 // indirect - github.com/google/go-cmp v0.4.0 // indirect - github.com/gorilla/websocket v1.4.1 // indirect - github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect - github.com/hewigovens/go-coincodec v1.0.4 + github.com/garyburd/redigo v1.6.0 // indirect + github.com/getsentry/sentry-go v0.5.1 + github.com/gin-gonic/gin v1.6.2 + github.com/go-stomp/stomp v2.0.5+incompatible // indirect + github.com/gocql/gocql v0.0.0-20200324094621-6d895e38b0a5 // indirect + github.com/gotestyourself/gotestyourself v1.4.0 // indirect + github.com/hashicorp/consul/api v1.4.0 // indirect github.com/jinzhu/gorm v1.9.12 - github.com/json-iterator/go v1.1.9 // indirect - github.com/klauspost/compress v1.10.1 // indirect - github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect - github.com/kr/pretty v0.2.0 // indirect - github.com/mitchellh/mapstructure v1.1.2 + github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b // indirect + github.com/mitchellh/mapstructure v1.2.2 github.com/mr-tron/base58 v1.1.3 github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v0.1.1 // indirect + github.com/ory-am/common v0.4.0 // indirect github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/errors v0.9.1 // indirect - github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 - github.com/sirupsen/logrus v1.4.2 - github.com/spf13/cast v1.3.1 // indirect + github.com/pborman/uuid v1.2.0 // indirect + github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da // indirect + github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc + github.com/sirupsen/logrus v1.5.0 github.com/spf13/viper v1.6.2 github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 - github.com/stretchr/testify v1.4.0 + github.com/stretchr/testify v1.5.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.5 github.com/trustwallet/ens-coincodec v1.0.5 - github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect - go.uber.org/atomic v1.4.0 - golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d - golang.org/x/net v0.0.0-20200301022130-244492dfa37a - golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect - golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd // indirect - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + go.uber.org/atomic v1.6.0 + golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 + golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e + gopkg.in/fatih/pool.v2 v2.0.0 // indirect + gopkg.in/gorethink/gorethink.v3 v3.0.5 // indirect gopkg.in/yaml.v2 v2.2.8 - gotest.tools v2.2.0+incompatible + gotest.tools v1.4.0 ) diff --git a/go.sum b/go.sum index 8b9d371bc..287aef217 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,6 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= @@ -11,13 +9,9 @@ github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKz github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/Pantani/httpexpect v2.0.0+incompatible h1:P658jo0d3gej0D67KBcSUgpZY76CH1TdxvOfQAmyNu0= -github.com/Pantani/httpexpect v2.0.0+incompatible/go.mod h1:+8VdK+EZPV0YorWMMNyakEIYKcDl9OHtde3DdkPqbwQ= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -25,20 +19,27 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMwWcqkLzDAQugVEwedisr5nRJ1r+7LYnv0U= -github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI= -github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= +github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61 h1:Xz25cuW4REGC5W5UtpMU3QItMIImag615HiQcRbxqKQ= +github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61/go.mod h1:ikc1XA58M+Rx7SEbf0bLJCfBkwayZ8T5jBo5FXK8Uz8= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= +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/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= 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/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= +github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= @@ -53,33 +54,38 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c h1:8ahmSVELW1wghbjerVAyuEYD5+Dio66RYvSS0iGfL1M= github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= +github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c h1:4e6Zsb6LFd3kadoMiut2zcd3hCb4zywpJnQa8+NV2Cs= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c/go.mod h1:k5D13LCXSsMrQyfdW0yGYs4GWUvirqoxHht8qwtqyRY= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/dancannon/gorethink v3.0.5+incompatible h1:AenyUfDNo7CUhNsA9qGVDIO/b5GzrnwjBRLZvlkb7jk= +github.com/dancannon/gorethink v3.0.5+incompatible/go.mod h1:BLvkat9KmZc1efyYwhz3WnybhRZtgF1K929FD8z1avU= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -90,17 +96,25 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/getsentry/sentry-go v0.4.0 h1:WqRI2/7EiALbdG9qGB47c0Aks1tdznG5DZd6GSQ1y/8= -github.com/getsentry/sentry-go v0.4.0/go.mod h1:xkGcb82SipKQloDNa5b7hTV4VdEyc2bhwd1/UczP52k= +github.com/getsentry/sentry-go v0.5.1 h1:MIPe7ScHADsrK2vznqmhksIUFxq7m0JfTh+ZIMkI+VQ= +github.com/getsentry/sentry-go v0.5.1/go.mod h1:B8H7x8TYDPkeWPRzGpIiFO97LZP6rL8A3hEt8lUItMw= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= @@ -108,9 +122,10 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc= -github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= +github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM= +github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -132,46 +147,101 @@ github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= -github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= -github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= -github.com/go-redis/redis v6.15.6+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stomp/stomp v2.0.5+incompatible h1:EqEAa4yeAh6GG+ODG6fXzI3ZIa9ARoX+Gq+KSWwlWn4= +github.com/go-stomp/stomp v2.0.5+incompatible/go.mod h1:VqCtqNZv1226A1/79yh+rMiFUcfY3R109np+7ke4n0c= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gocql/gocql v0.0.0-20200324094621-6d895e38b0a5 h1:LbX3qY8XXiD8kUJLvEsm3Hm2tjG3gQxThdmv9tW3cyI= +github.com/gocql/gocql v0.0.0-20200324094621-6d895e38b0a5/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049 h1:K9KHZbXKpGydfDN0aZrsoHpLJlZsBrGMFWbgLDGnPZk= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/gotestyourself/gotestyourself v1.4.0 h1:CDSlSIuRL/Fsc72Ln5lMybtrCvSRDddsHsDRG/nP7Rg= +github.com/gotestyourself/gotestyourself v1.4.0/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hashicorp/consul/api v1.4.0 h1:jfESivXnO5uLdH650JU/6AnjRoHrLhULq0FnC3Kp9EY= +github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU= +github.com/hashicorp/consul/sdk v0.4.0 h1:zBtCfKJZcJDBvSCkQJch4ulp59m1rATFLKwNo/LYY30= +github.com/hashicorp/consul/sdk v0.4.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hewigovens/go-coincodec v1.0.4/go.mod h1:+LTdzScnu782gMt0J3ZccPY9S2uyrGe0R1LUYGWecfc= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -184,13 +254,16 @@ github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= @@ -206,20 +279,22 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= -github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -229,24 +304,47 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b h1:v29yPGHhOqw7VHEnTeQFAth3SsBrmwc8JfuhNY0G34k= +github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b/go.mod h1:5MWrJXKRQyhQdUCF+vu6U5c4nQpg70vW3eHaU0/AYbU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +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/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= +github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= @@ -269,52 +367,71 @@ github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVo github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/ory-am/common v0.4.0 h1:edGPoxYX4hno0IJHXh9TCMUPR6ZcJp+y6aClFYxeuUE= +github.com/ory-am/common v0.4.0/go.mod h1:oCYGuwwM8FyYMKqh9vrhBaeUoyz/edx0bgJN6uS6/+k= +github.com/ory/dockertest v2.2.3+incompatible h1:eo4lG4wxzqGFObKl4C6ST7AjiLztTGojcQoFa6b8/cY= +github.com/ory/dockertest v2.2.3+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da h1:p3Vo3i64TCLY7gIfzeQaUJ+kppEO5WQG3cL8iE8tGHU= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 h1:Pm6R878vxWWWR+Sa3ppsLce/Zq+JNTs6aVvRu13jv9A= -github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY= +github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= +github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= @@ -332,8 +449,9 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= @@ -342,6 +460,7 @@ github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.6.5 h1:2C+t+xyK6p1sujqncYO/VnMvPZcBJjNdKKyxbOdAW8o= github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/ens-coincodec v1.0.5 h1:rdebDQYHqNjv+yUdtMf3DXyMgJpEJSI2DSbC1GUFuyk= github.com/trustwallet/ens-coincodec v1.0.5/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= @@ -366,40 +485,48 @@ github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= +go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d h1:2+ZP7EfsZV7Vvmx3TIqSlSzATMkTAKqM14YGFPoSKjI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -410,35 +537,41 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -450,28 +583,39 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd h1:hHkvGJK23seRCflePJnVa9IMv8fsuavSCWKd11kDQFs= -golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg= +gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= -gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU= +gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -481,6 +625,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools v1.4.0 h1:BjtEgfuw8Qyd+jPvQz8CfoxiO/UjFEidWinwEXZiWv0= +gotest.tools v1.4.0/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/platform/theta/transaction_test.go b/platform/theta/transaction_test.go index 1b894685c..ce9a95113 100644 --- a/platform/theta/transaction_test.go +++ b/platform/theta/transaction_test.go @@ -3,9 +3,9 @@ package theta import ( "bytes" "encoding/json" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "gotest.tools/assert" "testing" ) diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go index 3d405f284..49a5e03b1 100644 --- a/tests/integration/db_test/subscriptions_test.go +++ b/tests/integration/db_test/subscriptions_test.go @@ -9,6 +9,7 @@ import ( "github.com/trustwallet/blockatlas/services/observer/subscriber" "github.com/trustwallet/blockatlas/tests/integration/setup" "testing" + "time" ) func TestDb_AddSubscriptionsBulk(t *testing.T) { @@ -461,6 +462,45 @@ func TestDb_AddToExisting(t *testing.T) { } +func TestDb_UpdatedAt(t *testing.T) { + setup.CleanupPgContainer(database.Gorm) + var subscriptions []models.SubscriptionData + subscriptions = append(subscriptions, models.SubscriptionData{ + Coin: 60, + Address: "testAddr", + }) + + subscriptions[0].SubscriptionId = uint(1) + assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions)) + subs, err := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, err) + assert.Equal(t, 1, len(subs)) + + time.Sleep(time.Second) + + var existingSub models.Subscription + assert.False(t, database.Gorm.Where(models.Subscription{SubscriptionId: uint(1)}).First(&existingSub).RecordNotFound()) + assert.Greater(t, time.Now().Unix(), existingSub.UpdatedAt.Unix()) + assert.Greater(t, existingSub.UpdatedAt.Unix(), time.Now().Unix()-120) + + subscriptions = append(subscriptions, models.SubscriptionData{ + Coin: 714, + Address: "newtestAddr", + }) + + assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions)) + + time.Sleep(time.Second) + + var existingSub2 models.Subscription + assert.False(t, database.Gorm.Where(models.Subscription{SubscriptionId: uint(1)}).First(&existingSub2).RecordNotFound()) + + assert.Greater(t, time.Now().Unix(), existingSub2.UpdatedAt.Unix()) + assert.Greater(t, existingSub2.UpdatedAt.Unix(), time.Now().Unix()-120) + assert.Greater(t, existingSub2.UpdatedAt.Unix(), existingSub.UpdatedAt.Unix()) + +} + func containSub(sub models.SubscriptionData, list []models.SubscriptionData) bool { for _, s := range list { if sub.Address == s.Address && sub.Coin == s.Coin && sub.SubscriptionId == s.SubscriptionId { From fffb66f8cc92948c8cc9b10561d140acefc1b9d5 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 5 Apr 2020 15:40:46 +0300 Subject: [PATCH 233/506] Additional fixes for observer, add batch notifications for mq (#1011) * Additional fixes for parser * Send notifications as a batch * Add getNotificationBatches * Now notifications batch limit can be changed via config.yml * Fix of broken test * Add fetch interval for blocks * Fix tests Co-authored-by: Alexey Prazdnikov --- cmd/observer_notifier/main.go | 11 +++- cmd/observer_parser/main.go | 21 ++++--- config.yml | 4 ++ db/models/tracker.go | 2 +- mq/mq.go | 19 +++--- services/observer/notifier/notifier.go | 60 +++++++++++++------ services/observer/parser/parser.go | 34 ++++++----- services/observer/parser/parser_test.go | 14 ++++- .../observer_test/full_flow_test.go | 8 +-- .../observer_test/notifier_test.go | 8 +-- .../observer_test/observer_test.go | 4 +- 11 files changed, 124 insertions(+), 61 deletions(-) diff --git a/cmd/observer_notifier/main.go b/cmd/observer_notifier/main.go index 293357c8d..623676cd8 100644 --- a/cmd/observer_notifier/main.go +++ b/cmd/observer_notifier/main.go @@ -28,6 +28,7 @@ func init() { mqHost := viper.GetString("observer.rabbitmq.uri") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") pgUri := viper.GetString("postgres.uri") internal.InitRabbitMQ(mqHost, prefetchCount) @@ -36,7 +37,7 @@ func init() { logger.Fatal(err) } - if err := mq.Transactions.Declare(); err != nil { + if err := mq.TxNotifications.Declare(); err != nil { logger.Fatal(err) } @@ -46,6 +47,14 @@ func init() { logger.Fatal(err) } + if maxPushNotificationsBatchLimit == 0 { + notifier.MaxPushNotificationsBatchLimit = notifier.DefaultPushNotificationsBatchLimit + } else { + notifier.MaxPushNotificationsBatchLimit = maxPushNotificationsBatchLimit + } + + logger.Info("maxPushNotificationsBatchLimit ", logger.Params{"limit": maxPushNotificationsBatchLimit}) + go mq.RestoreConnectionWorker(mqHost, mq.RawTransactions, time.Second*10) go db.RestoreConnectionWorker(database, time.Second*10, pgUri) time.Sleep(time.Millisecond) diff --git a/cmd/observer_parser/main.go b/cmd/observer_parser/main.go index 41190a988..83e59f3d9 100644 --- a/cmd/observer_parser/main.go +++ b/cmd/observer_parser/main.go @@ -23,11 +23,11 @@ const ( ) var ( - confPath string - backlogTime, minInterval, maxInterval time.Duration - maxBackLogBlocks int64 - txsBatchLimit uint - database *db.Instance + confPath string + backlogTime, minInterval, maxInterval, fetchBlocksInterval time.Duration + maxBackLogBlocks int64 + txsBatchLimit uint + database *db.Instance ) func init() { @@ -57,6 +57,7 @@ func init() { backlogTime = viper.GetDuration("observer.backlog") minInterval = viper.GetDuration("observer.block_poll.min") maxInterval = viper.GetDuration("observer.block_poll.max") + fetchBlocksInterval = viper.GetDuration("observer.fetch_blocks_interval") maxBackLogBlocks = viper.GetInt64("observer.backlog_max_blocks") if minInterval >= maxInterval { logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") @@ -107,6 +108,7 @@ func main() { Api: api, Queue: mq.RawTransactions, ParsingBlocksInterval: pollInterval, + FetchBlocksTimeout: fetchBlocksInterval, BacklogCount: backlogCount, MaxBacklogBlocks: maxBackLogBlocks, StopChannel: stopChannel, @@ -117,10 +119,11 @@ func main() { go parser.RunParser(params) logger.Info("Parser params", logger.Params{ - "interval": pollInterval, - "backlog": backlogCount, - "Max backlog": maxBackLogBlocks, - "Txs Batch limit": txsBatchLimit, + "interval": pollInterval, + "backlog": backlogCount, + "Max backlog": maxBackLogBlocks, + "Txs Batch limit": txsBatchLimit, + "Fetching blocks interval": fetchBlocksInterval, }) wg.Done() diff --git a/config.yml b/config.yml index 9ae5439e4..426a9be52 100644 --- a/config.yml +++ b/config.yml @@ -19,10 +19,14 @@ platform: binance observer: # Don't request blocks older than this backlog: 3h + # Amount of time between fetching blocks concurrently + fetch_blocks_interval: 1ms # Don't request more than N blocks at once backlog_max_blocks: 200 # Limit amount of transactions in batch txs_batch_limit: 3000 + # Limit of push notifications in batch + push_notifications_batch_limit: 50 # Block polling interval block_poll: min: 3s diff --git a/db/models/tracker.go b/db/models/tracker.go index 10e62a234..c5a03554f 100644 --- a/db/models/tracker.go +++ b/db/models/tracker.go @@ -1,6 +1,6 @@ package models type Tracker struct { - Coin uint `gorm:"primary_key:true"` + Coin uint `gorm:"primary_key:true; auto_increment:false"` Height int64 } diff --git a/mq/mq.go b/mq/mq.go index 812fd9041..e2c2a6016 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -22,11 +22,9 @@ type ( ) const ( - Transactions Queue = "transactions" - Subscriptions Queue = "subscriptions" - RawTransactions Queue = "rawTransactions" - defaultPrefetchCount = 5 - minPrefetchCount = 1 + TxNotifications Queue = "txNotifications" + Subscriptions Queue = "subscriptions" + RawTransactions Queue = "rawTransactions" ) func Init(uri string) (err error) { @@ -39,8 +37,15 @@ func Init(uri string) (err error) { } func Close() { - amqpChan.Close() - conn.Close() + err := amqpChan.Close() + if err != nil { + logger.Error(err) + } + + err = conn.Close() + if err != nil { + logger.Error(err) + } } func (mc MessageChannel) GetMessage() amqp.Delivery { diff --git a/services/observer/notifier/notifier.go b/services/observer/notifier/notifier.go index 16e97ffbc..35e1b0951 100644 --- a/services/observer/notifier/notifier.go +++ b/services/observer/notifier/notifier.go @@ -13,7 +13,11 @@ import ( "time" ) -type DispatchEvent struct { +const DefaultPushNotificationsBatchLimit = 50 + +var MaxPushNotificationsBatchLimit uint = DefaultPushNotificationsBatchLimit + +type TransactionNotification struct { Action blockatlas.TransactionType `json:"action"` Result *blockatlas.Tx `json:"result"` Id uint `json:"id"` @@ -60,40 +64,47 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { func buildAndPostMessage(blockTransactions blockatlas.TxSetMap, sub blockatlas.Subscription, wg *sync.WaitGroup) { defer wg.Done() + tx, ok := blockTransactions.Map[sub.Address] if !ok { return } + notifications := make([]TransactionNotification, 0, len(tx.Txs())) for _, tx := range tx.Txs() { tx.Direction = tx.GetTransactionDirection(sub.Address) tx.InferUtxoValue(sub.Address, tx.Coin) - action := DispatchEvent{ + notification := TransactionNotification{ Action: tx.Type, Result: &tx, Id: sub.Id, } - txJson, err := json.Marshal(action) - if err != nil { - logger.Panic(err, logger.Params{"coin": tx.Coin}) - } - logParams := logger.Params{ - "Id": sub.Id, - "coin": sub.Coin, - "txID": tx.ID, - } + logger.Info("Notification ready", logger.Params{"Id": sub.Id, "coin": sub.Coin, "txID": tx.ID}) + + notifications = append(notifications, notification) + } + + batches := getNotificationBatches(notifications, MaxPushNotificationsBatchLimit) - publishTransaction(sub.Id, txJson, logParams) + for _, batch := range batches { + publishNotificationBatch(batch) } } -func publishTransaction(id uint, rawMessage []byte, logParams logger.Params) { - err := mq.Transactions.Publish(rawMessage) +func publishNotificationBatch(batch []TransactionNotification) { + raw, err := json.Marshal(batch) if err != nil { - err = errors.E(err, "Failed to dispatch event", errors.Params{"id": id}, logParams) - logger.Fatal(err, logger.Params{"id": id}, logParams) + err = errors.E(err, " failed to dispatch event") + logger.Fatal(err) } - logger.Info("Message dispatched", logger.Params{"id": id}, logParams) + + err = mq.TxNotifications.Publish(raw) + if err != nil { + err = errors.E(err, " failed to dispatch event") + logger.Fatal(err) + } + + logger.Info("Txs batch dispatched", logger.Params{"txs": len(batch)}) } func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duration { @@ -102,3 +113,18 @@ func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duratio pMax := numbers.Min(int(maxInterval.Nanoseconds()), int(pMin)) return time.Duration(pMax) } + +func getNotificationBatches(notifications []TransactionNotification, sizeUint uint) [][]TransactionNotification { + size := int(sizeUint) + resultLength := (len(notifications) + size - 1) / size + result := make([][]TransactionNotification, resultLength) + lo, hi := 0, size + for i := range result { + if hi > len(notifications) { + hi = len(notifications) + } + result[i] = notifications[lo:hi:hi] + lo, hi = hi, hi+size + } + return result +} diff --git a/services/observer/parser/parser.go b/services/observer/parser/parser.go index 10d71a2f8..86e6f6762 100644 --- a/services/observer/parser/parser.go +++ b/services/observer/parser/parser.go @@ -19,15 +19,15 @@ import ( type ( Params struct { - Ctx context.Context - Api blockatlas.BlockAPI - Queue mq.Queue - ParsingBlocksInterval time.Duration - BacklogCount int - MaxBacklogBlocks int64 - StopChannel chan<- struct{} - TxBatchLimit uint - Database *db.Instance + Ctx context.Context + Api blockatlas.BlockAPI + Queue mq.Queue + ParsingBlocksInterval, FetchBlocksTimeout time.Duration + BacklogCount int + MaxBacklogBlocks int64 + StopChannel chan<- struct{} + TxBatchLimit uint + Database *db.Instance } GetBlockByNumber func(num int64) (*blockatlas.Block, error) @@ -54,13 +54,13 @@ func RunParser(params Params) { return default: lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params) - if err != nil { + if err != nil || lastParsedBlock > currentBlock { logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) time.Sleep(params.ParsingBlocksInterval) continue } - blocks := FetchBlocks(params.Api, lastParsedBlock, currentBlock) + blocks := FetchBlocks(params, lastParsedBlock, currentBlock) err = SaveLastParsedBlock(params, blocks) if err != nil { @@ -100,15 +100,15 @@ func GetBlocksIntervalToFetch(params Params) (int64, int64, error) { return lastParsedBlock, currentBlock, nil } -func FetchBlocks(api blockatlas.BlockAPI, lastParsedBlock, currentBlock int64) []blockatlas.Block { +func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatlas.Block { if lastParsedBlock == currentBlock { - logger.Info("No new blocks", logger.Params{"last": lastParsedBlock, "coin": api.Coin().ID, "time": time.Now().Unix()}) + logger.Info("No new blocks", logger.Params{"last": lastParsedBlock, "coin": params.Api.Coin().ID, "time": time.Now().Unix()}) return nil } blocksCount := currentBlock - lastParsedBlock if blocksCount < 0 { - logger.Error("Current block is 0", logger.Params{"coin": api.Coin().Handle}) + logger.Error("Current block is 0", logger.Params{"coin": params.Api.Coin().Handle}) return nil } @@ -121,9 +121,10 @@ func FetchBlocks(api blockatlas.BlockAPI, lastParsedBlock, currentBlock int64) [ for i := lastParsedBlock + 1; i <= currentBlock; i++ { wg.Add(1) + time.Sleep(params.FetchBlocksTimeout) go func(i int64, wg *sync.WaitGroup) { defer wg.Done() - err := fetchBlock(api, i, blocksChan) + err := fetchBlock(params.Api, i, blocksChan) if err != nil { errorsChan <- err return @@ -174,6 +175,9 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { }) lastBlockNumber := blocks[len(blocks)-1].Number + if lastBlockNumber <= 0 { + return errors.E(fmt.Sprintf("Parser of %s failed to save last block, lastBlockNumber <= 0", params.Api.Coin().Handle)) + } err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().ID, lastBlockNumber) if err != nil { return err diff --git a/services/observer/parser/parser_test.go b/services/observer/parser/parser_test.go index 6b6d36966..d5b88ae57 100644 --- a/services/observer/parser/parser_test.go +++ b/services/observer/parser/parser_test.go @@ -63,7 +63,19 @@ var ( ) func TestFetchBlocks(t *testing.T) { - blocks := FetchBlocks(getMockedBlockAPI(), 0, 100) + params := Params{ + Ctx: nil, + Api: getMockedBlockAPI(), + Queue: "", + ParsingBlocksInterval: 0, + FetchBlocksTimeout: 0, + BacklogCount: 0, + MaxBacklogBlocks: 0, + StopChannel: nil, + TxBatchLimit: 0, + Database: nil, + } + blocks := FetchBlocks(params, 0, 100) assert.Equal(t, len(blocks), 100) } diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 3b4df80de..aeaf88fd7 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -101,8 +101,8 @@ func (p *PlatformFullFlow) GetBlockByNumber(num int64) (*blockatlas.Block, error } func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel context.CancelFunc, counter int) { - var event notifier.DispatchEvent - if err := json.Unmarshal(delivery.Body, &event); err != nil { + var notifications []notifier.TransactionNotification + if err := json.Unmarshal(delivery.Body, ¬ifications); err != nil { assert.Nil(t, err) return } @@ -119,7 +119,7 @@ func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel To: "testAddress", } - assert.Equal(t, notifier.DispatchEvent{ + assert.Equal(t, notifier.TransactionNotification{ Action: blockatlas.TxNativeTokenTransfer, Result: &blockatlas.Tx{ Type: blockatlas.TxNativeTokenTransfer, @@ -136,7 +136,7 @@ func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel Meta: &memo, }, Id: 1, - }, event) + }, notifications[0]) if counter == 10 { cancel() diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index 8bb5b4d67..4737b8b32 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -60,8 +60,8 @@ func TestNotifier(t *testing.T) { } func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { - var event notifier.DispatchEvent - if err := json.Unmarshal(delivery.Body, &event); err != nil { + var notifications []notifier.TransactionNotification + if err := json.Unmarshal(delivery.Body, ¬ifications); err != nil { assert.Nil(t, err) return } @@ -80,7 +80,7 @@ func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", } - assert.Equal(t, notifier.DispatchEvent{ + assert.Equal(t, notifier.TransactionNotification{ Action: blockatlas.TxNativeTokenTransfer, Result: &blockatlas.Tx{ Type: blockatlas.TxNativeTokenTransfer, @@ -97,7 +97,7 @@ func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { Meta: &memo, }, Id: 1, - }, event) + }, notifications[0]) return } diff --git a/tests/integration/observer_test/observer_test.go b/tests/integration/observer_test/observer_test.go index dc75b91e1..cdaba9d39 100644 --- a/tests/integration/observer_test/observer_test.go +++ b/tests/integration/observer_test/observer_test.go @@ -22,7 +22,7 @@ func TestMain(m *testing.M) { if err := mq.RawTransactions.Declare(); err != nil { log.Fatal(err) } - if err := mq.Transactions.Declare(); err != nil { + if err := mq.TxNotifications.Declare(); err != nil { log.Fatal(err) } if err := mq.Subscriptions.Declare(); err != nil { @@ -30,7 +30,7 @@ func TestMain(m *testing.M) { } rawTransactionsChannel = mq.RawTransactions.GetMessageChannel() subscriptionChannel = mq.Subscriptions.GetMessageChannel() - transactionsChannel = mq.Transactions.GetMessageChannel() + transactionsChannel = mq.TxNotifications.GetMessageChannel() code := m.Run() From d63d510fe9765c42c18948847b20e3bc7048a184 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 5 Apr 2020 21:41:09 +0300 Subject: [PATCH 234/506] Change the pipeline: add golangcli-lint, fix errors with it (#1012) * Change the pipeline: add golangcli-lint * Add fix to Makefile * Fix #2 * Requested changes --- Makefile | 11 ++-- api/routes.go | 8 --- azure-pipelines.yml | 6 +- pkg/address/address.go | 8 ++- pkg/blockatlas/client.go | 2 +- pkg/blockatlas/clientcache.go | 1 + pkg/errors/errors.go | 4 -- pkg/ginutils/gincache/cache_test.go | 2 +- pkg/logger/logger.go | 2 +- platform/aeternity/client.go | 11 ++-- platform/binance/block.go | 2 +- platform/binance/transaction_test.go | 75 ------------------------- platform/ethereum/namehash.go | 1 - platform/ethereum/token_test.go | 1 - platform/ontology/client.go | 2 +- platform/tron/model.go | 4 +- platform/zilliqa/model.go | 4 +- services/observer/parser/parser_test.go | 22 -------- 18 files changed, 27 insertions(+), 139 deletions(-) diff --git a/Makefile b/Makefile index 0c9280556..75d43e3da 100644 --- a/Makefile +++ b/Makefile @@ -154,7 +154,7 @@ goreleaser: go-goreleaser govet: go-vet ## golint: Run golint. -golint: go-lint +lint: go-lint-install go-lint ## docs: Generate swagger docs. docs: go-gen-docs @@ -177,9 +177,6 @@ newman-mocked-params: start-platform-api-mock ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host) && \ $(MAKE) newman-run test=domain host=$(host)" - #not-mocked-yet: $(MAKE) newman-run test=token host=$(host) && \ - #not-mocked-yet: $(MAKE) newman-run test=staking host=$(host) && \ - #not-mocked-yet: $(MAKE) newman-run test=collection host=$(host) && else @bash -c "$(MAKE) newman-run test=$(test) host=$(host)" endif @@ -270,9 +267,13 @@ go-vet: @echo " > Running go vet" GOBIN=$(GOBIN) go vet ./... +go-lint-install: + @echo " > Installing golint" + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s + go-lint: @echo " > Running golint" - GOBIN=$(GOBIN) golint ./... + bin/golangci-lint run .PHONY: help all: help diff --git a/api/routes.go b/api/routes.go index e029d5ab6..c843a21ab 100644 --- a/api/routes.go +++ b/api/routes.go @@ -7,7 +7,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" - "strings" ) var routers = make(map[string]gin.IRouter) @@ -108,10 +107,3 @@ func GetStatus(c *gin.Context) { "date": internal.Date, }) } - -func splitParam(param string) []string { - splitFn := func(c rune) bool { - return c == ',' - } - return strings.FieldsFunc(param, splitFn) -} diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3006f5c67..f359b9082 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -34,13 +34,13 @@ jobs: workingDirectory: '$(System.DefaultWorkingDirectory)' displayName: 'Get dependencies' - - job: go_vet + - job: go_lint dependsOn: environment condition: succeeded() steps: - - script: make govet + - script: sudo make lint workingDirectory: '$(System.DefaultWorkingDirectory)' - displayName: 'Run go vet' + displayName: 'Run go lint' - job: unit_tests dependsOn: environment diff --git a/pkg/address/address.go b/pkg/address/address.go index 3f4ccc7fe..e26b5d9bf 100644 --- a/pkg/address/address.go +++ b/pkg/address/address.go @@ -5,12 +5,11 @@ import ( "encoding/hex" "github.com/mr-tron/base58" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/logger" "golang.org/x/crypto/sha3" "strings" ) -const ethereumAddressLength = 40 - // Decode decodes a hex string with 0x prefix. func Remove0x(input string) string { if strings.HasPrefix(input, "0x") { @@ -23,7 +22,10 @@ func Remove0x(input string) string { func EIP55Checksum(unchecksummed string) string { v := []byte(Remove0x(strings.ToLower(unchecksummed))) sha := sha3.NewLegacyKeccak256() - sha.Write(v) + _, err := sha.Write(v) + if err != nil { + logger.Error(err) + } hash := sha.Sum(nil) result := v diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go index b663fa847..fd285e758 100644 --- a/pkg/blockatlas/client.go +++ b/pkg/blockatlas/client.go @@ -106,7 +106,7 @@ func (r *Request) Execute(method string, url string, body io.Reader, result inte func (r *Request) GetBase(path string) string { if path == "" { - return fmt.Sprintf("%s", r.BaseUrl) + return r.BaseUrl } return fmt.Sprintf("%s/%s", r.BaseUrl, path) } diff --git a/pkg/blockatlas/clientcache.go b/pkg/blockatlas/clientcache.go index 6c376f4c5..a6e511609 100644 --- a/pkg/blockatlas/clientcache.go +++ b/pkg/blockatlas/clientcache.go @@ -56,6 +56,7 @@ func (r *Request) GetWithCache(result interface{}, path string, query url.Values return err } +//nolint func (mc *memCache) deleteCache(key string) { mc.RLock() defer mc.RUnlock() diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index c0d2f1ad7..751f64f82 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -22,10 +22,6 @@ type ( var _ error = (*Error)(nil) -func (e *Error) isEmpty() bool { - return e.meta == nil && e.Type == TypeNone && e.Err == nil -} - func (e *Error) Error() string { return e.String() } diff --git a/pkg/ginutils/gincache/cache_test.go b/pkg/ginutils/gincache/cache_test.go index 3742dec84..9467aca28 100644 --- a/pkg/ginutils/gincache/cache_test.go +++ b/pkg/ginutils/gincache/cache_test.go @@ -30,7 +30,7 @@ func TestWrite(t *testing.T) { c.Writer.WriteHeader(204) c.Writer.WriteHeaderNow() - c.Writer.Write([]byte("foo")) + c.Writer.Write([]byte("foo")) // nolint assert.Equal(t, 204, c.Writer.Status()) assert.Equal(t, "foo", w.Body.String()) assert.True(t, c.Writer.Written()) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 92e6130bd..76bd485bb 100755 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -28,7 +28,7 @@ func (msg *message) String() string { if len(msg.params) > 0 { return fmt.Sprintf("%s - %v", msg.message, msg.params) } - return fmt.Sprintf("%s", msg.message) + return msg.message } func Info(args ...interface{}) { diff --git a/platform/aeternity/client.go b/platform/aeternity/client.go index 71a5f48e5..89dbc0a77 100644 --- a/platform/aeternity/client.go +++ b/platform/aeternity/client.go @@ -11,15 +11,14 @@ type Client struct { blockatlas.Request } -func (c *Client) GetTxs(address string, limit int) (transactions []Transaction, err error) { +func (c *Client) GetTxs(address string, limit int) ([]Transaction, error) { query := url.Values{ "limit": {strconv.Itoa(limit)}, } uri := fmt.Sprintf("middleware/transactions/account/%s", address) - - err = c.Get(&transactions, uri, query) - if err != nil { - return + var transactions []Transaction + if err := c.Get(&transactions, uri, query); err != nil { + return nil, err } var result []Transaction @@ -28,5 +27,5 @@ func (c *Client) GetTxs(address string, limit int) (transactions []Transaction, result = append(result, tx) } } - return + return result, nil } diff --git a/platform/binance/block.go b/platform/binance/block.go index 1a93421fd..c4647d8bb 100644 --- a/platform/binance/block.go +++ b/platform/binance/block.go @@ -25,7 +25,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { return nil, err } - txs := make(blockatlas.TxPage, 0) + var txs blockatlas.TxPage childTxs, err := p.getTxChildChan(srcTxs.Txs) if err == nil { txs = NormalizeTxs(childTxs, "", "") diff --git a/platform/binance/transaction_test.go b/platform/binance/transaction_test.go index e770f59b7..cbe80c777 100644 --- a/platform/binance/transaction_test.go +++ b/platform/binance/transaction_test.go @@ -407,81 +407,6 @@ func TestNormalizeTx(t *testing.T) { } } -const AllTransfersType = ` -[ - { - "blockHeight": 7761368, - "code": 0, - "confirmBlocks": 2089441, - "fromAddr": "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - "hasChildren": 0, - "log": "Msg 0: ", - "timeStamp": 1555049867552, - "toAddr": "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5", - "txAge": 836729, - "txAsset": "BNB", - "txFee": 0.00125, - "txHash": "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", - "txType": "TRANSFER", - "value": 100000, - "memo": "test" - }, - { - "blockHeight": 7928667, - "code": 0, - "confirmBlocks": 1922024, - "fromAddr": "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - "hasChildren": 0, - "log": "Msg 0: ", - "timeStamp": 1555117625829, - "toAddr": "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - "txAge": 768924, - "txAsset": "YLC-D8B", - "txFee": 0.00125, - "txHash": "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - "txType": "TRANSFER", - "value": 2.10572645, - "memo": "test" - }, - { - "txHash": "B0677F3436C1B1661E94D192B84B98AA42AC2485D9808357796EE501CBF794F7", - "blockHeight": 10815565, - "txType": "NEW_ORDER", - "timeStamp": 1559689901929, - "fromAddr": "bnb16ya67j7kvw8682kka09qujlw5u7lf4geqef0ku", - "value": 0.00649878, - "txAsset": "BNB", - "txQuoteAsset": "AWC-986", - "txFee": 0, - "txAge": 14346340, - "orderId": "D13BAF4BD6638FA3AAD6EBCA0E4BEEA73DF4D519-30", - "data": "{\"orderData\":{\"symbol\":\"BNB_AWC-986\",\"orderType\":\"limit\",\"side\":\"buy\",\"price\":0.00324939,\"quantity\":2.00000000,\"timeInForce\":\"GTE\",\"orderId\":\"D13BAF4BD6638FA3AAD6EBCA0E4BEEA73DF4D519-30\"}}", - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "", - "source": 0, - "hasChildren": 0 - }, - { - "txHash": "F48DE755170C10F4A4C0E6836A708C33EEF9A7144800F25187D5F2349FD15A34", - "blockHeight": 10815539, - "txType": "CANCEL_ORDER", - "timeStamp": 1559689892180, - "fromAddr": "bnb16ya67j7kvw8682kka09qujlw5u7lf4geqef0ku", - "txFee": 0, - "txAge": 14346349, - "data": "{\"orderData\":{\"symbol\":\"BNB_GTO-908\",\"orderType\":\"limit\",\"side\":\"buy\",\"price\":0.00104716,\"quantity\":1.00000000,\"timeInForce\":\"GTE\",\"orderId\":\"D13BAF4BD6638FA3AAD6EBCA0E4BEEA73DF4D519-28\"}}", - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "", - "source": 0, - "hasChildren": 0 - } -] -` - type testTxs struct { name string apiResponse string diff --git a/platform/ethereum/namehash.go b/platform/ethereum/namehash.go index a9ef969f2..963896147 100644 --- a/platform/ethereum/namehash.go +++ b/platform/ethereum/namehash.go @@ -23,7 +23,6 @@ import ( ) var p = idna.New(idna.MapForLookup(), idna.StrictDomainName(false), idna.Transitional(false)) -var pStrict = idna.New(idna.MapForLookup(), idna.StrictDomainName(true), idna.Transitional(false)) // Normalize normalizes a name according to the ENS rules func Normalize(input string) (output string, err error) { diff --git a/platform/ethereum/token_test.go b/platform/ethereum/token_test.go index ab7b88f8f..fa5470b22 100644 --- a/platform/ethereum/token_test.go +++ b/platform/ethereum/token_test.go @@ -17,7 +17,6 @@ const tokenSrc = ` }` type testToken struct { - name string apiResponse string expected *blockatlas.Token coin int diff --git a/platform/ontology/client.go b/platform/ontology/client.go index 73cb5cc58..3844cfbcb 100644 --- a/platform/ontology/client.go +++ b/platform/ontology/client.go @@ -32,7 +32,7 @@ func (c *Client) GetTxsOfAddress(address string) (txPage TxsResult, err error) { func (c *Client) CurrentBlockNumber() (blocks BlockResult, err error) { query := url.Values{"page_size": {"1"}, "page_number": {"1"}} - path := fmt.Sprintf("v2/blocks") + path := "v2/blocks" err = c.Get(&blocks, path, query) if err != nil || blocks.Msg != MsgSuccess { return blocks, errors.E(err, "explorer client CurrentBlockNumber", errors.Params{"platform": "ONT"}) diff --git a/platform/tron/model.go b/platform/tron/model.go index 54eac7576..38e90ed06 100644 --- a/platform/tron/model.go +++ b/platform/tron/model.go @@ -48,8 +48,6 @@ type ContractType string const ( TransferContract ContractType = "TransferContract" TransferAssetContract ContractType = "TransferAssetContract" - CreateSmartContract ContractType = "CreateSmartContract" - TriggerSmartContract ContractType = "TriggerSmartContract" ) type Contract struct { @@ -88,7 +86,7 @@ type Votes struct { type Frozen struct { ExpireTime int64 `json:"expire_time"` - FrozenBalance interface{} `json:"frozen_balance,string"` + FrozenBalance interface{} `json:"frozen_balance,string"` // nolint } type Asset struct { diff --git a/platform/zilliqa/model.go b/platform/zilliqa/model.go index 77f2357ba..8bc611b87 100644 --- a/platform/zilliqa/model.go +++ b/platform/zilliqa/model.go @@ -12,9 +12,7 @@ type BlockTxs [][]string func (b BlockTxs) txs() []string { txs := make([]string, 0) for _, ids := range b { - for _, id := range ids { - txs = append(txs, id) - } + txs = append(txs, ids...) } return txs } diff --git a/services/observer/parser/parser_test.go b/services/observer/parser/parser_test.go index d5b88ae57..5f0e6a015 100644 --- a/services/observer/parser/parser_test.go +++ b/services/observer/parser/parser_test.go @@ -38,28 +38,6 @@ var ( }, }, } - - txs = blockatlas.Txs{ - { - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: blockatlas.NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, - }, - } ) func TestFetchBlocks(t *testing.T) { From 08cb51578775ac010ea163571fabc7a3dc8f3e3d Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 5 Apr 2020 22:09:11 +0300 Subject: [PATCH 235/506] Now mocked api stopped after running (#1013) --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 75d43e3da..e4dcf75c1 100644 --- a/Makefile +++ b/Makefile @@ -177,8 +177,10 @@ newman-mocked-params: start-platform-api-mock ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host) && \ $(MAKE) newman-run test=domain host=$(host)" + @bash -c "$(MAKE) stop" else @bash -c "$(MAKE) newman-run test=$(test) host=$(host)" + @bash -c "$(MAKE) stop" endif ## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http//localhost From dffc35bf1afca4b31a1ecb30275d9609635e533a Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Tue, 7 Apr 2020 07:14:33 -0700 Subject: [PATCH 236/506] =?UTF-8?q?Remove=20v2,=20=D1=81ollections=20route?= =?UTF-8?q?=20(#989)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * REmove v2 collections route * New swagger and postman * Fix swagger, remove v2, v3 collections also * Remove outdated fields, collection methods, change collection interface, update postman tests * Bring back v3 for android * Bring back v3 for android client Co-authored-by: Nick Kozlov --- api/collection.go | 115 +--- api/routes.go | 16 +- docs/docs.go | 303 +-------- docs/swagger.json | 301 +-------- docs/swagger.yaml | 207 +----- pkg/blockatlas/collectibles.go | 43 +- pkg/blockatlas/marshal.go | 32 + pkg/blockatlas/platform.go | 7 +- platform/ethereum/collection.go | 263 +------ platform/ethereum/collectionV3.go | 114 ++++ platform/ethereum/collection_client.go | 49 +- platform/ethereum/collection_test.go | 639 ++++++++---------- platform/ethereum/collection_v4.go | 73 -- platform/ethereum/collection_v4_test.go | 337 --------- .../Blockatlas.postman_collection.json | 567 +--------------- tests/postman/collection_data.json | 4 +- 16 files changed, 577 insertions(+), 2493 deletions(-) create mode 100644 platform/ethereum/collectionV3.go delete mode 100644 platform/ethereum/collection_v4.go delete mode 100644 platform/ethereum/collection_v4_test.go diff --git a/api/collection.go b/api/collection.go index 9d1081f1a..4c5816477 100644 --- a/api/collection.go +++ b/api/collection.go @@ -8,37 +8,6 @@ import ( "strconv" ) -// @Summary Get Collections -// @ID collections_v2 -// @Description Get all collections from the address -// @Accept json -// @Produce json -// @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 -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/{coin}/collections/{address} [get] -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func oldMakeCollectionsRoute(router gin.IRouter, api blockatlas.Platform) { - var collectionAPI blockatlas.CollectionAPI - collectionAPI, _ = api.(blockatlas.CollectionAPI) - - if collectionAPI == nil { - return - } - - router.GET("/collections/:owner", func(c *gin.Context) { - collections, err := collectionAPI.OldGetCollections(c.Param("owner")) - if err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - ginutils.RenderSuccess(c, collections) - }) -} - // @Summary Get Collections // @ID collections_v3 // @Description Get all collections from the address @@ -59,7 +28,7 @@ func makeCollectionsRoute(router gin.IRouter, api blockatlas.Platform) { } router.GET("/collections/:owner", func(c *gin.Context) { - collections, err := collectionAPI.GetCollections(c.Param("owner")) + collections, err := collectionAPI.GetCollectionsV3(c.Param("owner")) if err != nil { ginutils.ErrorResponse(c).Message(err.Error()).Render() return @@ -69,38 +38,6 @@ func makeCollectionsRoute(router gin.IRouter, api blockatlas.Platform) { }) } -// @Summary Get Collection -// @ID collection_v2 -// @Description Get a collection from the address -// @Accept json -// @Produce json -// @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) -// @Success 200 {object} blockatlas.CollectionPage -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/{coin}/collections/{owner}/collection/{collection_id} [get] -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func oldMakeCollectionRoute(router gin.IRouter, api blockatlas.Platform) { - var collectionAPI blockatlas.CollectionAPI - collectionAPI, _ = api.(blockatlas.CollectionAPI) - - if collectionAPI == nil { - return - } - - router.GET("/collections/:owner/collection/:collection_id", func(c *gin.Context) { - collectibles, err := collectionAPI.OldGetCollectibles(c.Param("owner"), c.Param("collection_id")) - if err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - ginutils.RenderSuccess(c, collectibles) - }) -} - // @Summary Get Collection // @ID collection_v3 // @Description Get a collection from the address @@ -122,7 +59,7 @@ func makeCollectionRoute(router gin.IRouter, api blockatlas.Platform) { } router.GET("/collections/:owner/collection/:collection_id", func(c *gin.Context) { - collectibles, err := collectionAPI.GetCollectibles(c.Param("owner"), c.Param("collection_id")) + collectibles, err := collectionAPI.GetCollectiblesV3(c.Param("owner"), c.Param("collection_id")) if err != nil { ginutils.ErrorResponse(c).Message(err.Error()).Render() return @@ -132,46 +69,6 @@ func makeCollectionRoute(router gin.IRouter, api blockatlas.Platform) { }) } -// @Description Get collection categories -// @ID collection_categories_v2 -// @Summary Get list of collections from a specific coin and addresses -// @Accept json -// @Produce json -// @Tags Collections -// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) -// @Success 200 {object} blockatlas.DocsResponse -// @Router /v2/collectibles/categories [post] -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func oldMakeCategoriesBatchRoute(router gin.IRouter) { - router.POST("/collectibles/categories", func(c *gin.Context) { - var reqs map[string][]string - if err := c.BindJSON(&reqs); err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - batch := make(blockatlas.CollectionPage, 0) - for key, addresses := range reqs { - coinId, err := strconv.Atoi(key) - if err != nil { - continue - } - p, ok := platform.CollectionAPIs[uint(coinId)] - if !ok { - continue - } - for _, address := range addresses { - collections, err := p.OldGetCollections(address) - if err != nil { - continue - } - batch = append(batch, collections...) - } - } - ginutils.RenderSuccess(c, batch) - }) -} - // @Description Get collection categories // @ID collection_categories_v3 // @Summary Get list of collections from a specific coin and addresses @@ -189,7 +86,7 @@ func makeCategoriesBatchRoute(router gin.IRouter) { return } - batch := make(blockatlas.CollectionPage, 0) + batch := make(blockatlas.CollectionPageV3, 0) for key, addresses := range reqs { coinId, err := strconv.Atoi(key) if err != nil { @@ -200,7 +97,7 @@ func makeCategoriesBatchRoute(router gin.IRouter) { continue } for _, address := range addresses { - collections, err := p.GetCollections(address) + collections, err := p.GetCollectionsV3(address) if err != nil { continue } @@ -239,7 +136,7 @@ func makeCategoriesBatchRouteV4(router gin.IRouter) { continue } for _, address := range addresses { - collections, err := p.GetCollectionsV4(address) + collections, err := p.GetCollections(address) if err != nil { continue } @@ -271,7 +168,7 @@ func makeCollectionRouteV4(router gin.IRouter, api blockatlas.Platform) { } router.GET("/collections/:owner/collection/:collection_id", func(c *gin.Context) { - collectibles, err := collectionAPI.GetCollectiblesV4(c.Param("owner"), c.Param("collection_id")) + collectibles, err := collectionAPI.GetCollectibles(c.Param("owner"), c.Param("collection_id")) if err != nil { ginutils.ErrorResponse(c).Message(err.Error()).Render() return diff --git a/api/routes.go b/api/routes.go index c843a21ab..b1f19b108 100644 --- a/api/routes.go +++ b/api/routes.go @@ -16,8 +16,8 @@ func SetupPlatformAPI(root gin.IRouter) { root.GET("/status", GetStatus) v1 := root.Group("/v1") - v2 := root.Group("/v2") v3 := root.Group("/v3") + v2 := root.Group("/v2") v4 := root.Group("/v4") v1.GET("/", GetSupportedEndpoints) @@ -42,16 +42,12 @@ func SetupPlatformAPI(root gin.IRouter) { } for _, collectionAPI := range platform.Platforms { - routerV2 := getRouter(v2, collectionAPI.Coin().Handle) - routerV3 := getRouter(v3, collectionAPI.Coin().Handle) - routerV4 := getRouter(v4, collectionAPI.Coin().Handle) + routerV3 := getRouter(v3, collectionAPI.Coin().Handle) makeCollectionsRoute(routerV3, collectionAPI) makeCollectionRoute(routerV3, collectionAPI) - oldMakeCollectionRoute(routerV2, collectionAPI) - oldMakeCollectionsRoute(routerV2, collectionAPI) - + routerV4 := getRouter(v4, collectionAPI.Coin().Handle) makeCollectionRouteV4(routerV4, collectionAPI) } @@ -65,12 +61,12 @@ func SetupPlatformAPI(root gin.IRouter) { MakeLookupRoute(ns) MakeLookupBatchRoute(batchNs) - oldMakeCategoriesBatchRoute(v2) - makeCategoriesBatchRoute(v3) - makeCategoriesBatchRouteV4(v4) makeStakingDelegationsBatchRoute(v2) makeStakingDelegationsSimpleBatchRoute(v2) + makeCategoriesBatchRoute(v3) + makeCategoriesBatchRouteV4(v4) + logger.Info("Routes set up", logger.Params{"routes": len(routers)}) } diff --git a/docs/docs.go b/docs/docs.go index 247a2732c..99f65030c 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-03-01 04:39:26.356879 +0300 MSK m=+1.896562991 +// 2020-04-06 16:53:26.62462 +0300 MSK m=+1.619745776 package docs @@ -157,13 +157,6 @@ var doc = `{ "name": "token", "in": "query" }, - { - "type": "integer", - "default": 1574483028, - "description": "Start timestamp", - "name": "time_start", - "in": "query" - }, { "type": "string", "default": "USD", @@ -301,42 +294,6 @@ var doc = `{ } } }, - "/v2/collectibles/categories": { - "post": { - "description": "Get collection categories", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get list of collections from a specific coin and addresses", - "operationId": "collection_categories_v2", - "parameters": [ - { - "default": "{\"60\": [\"0xb3624367b1ab37daef42e1a3a2ced012359659b0\"]}", - "description": "Payload", - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.DocsResponse" - } - } - } - } - }, "/v2/ns/lookup": { "get": { "description": "Lookup ENS/ZNS to find registered addresses for multiple coins", @@ -452,110 +409,6 @@ var doc = `{ } } }, - "/v2/{coin}/collections/{address}": { - "get": { - "description": "Get all collections from the address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get Collections", - "operationId": "collections_v2", - "parameters": [ - { - "type": "string", - "default": "ethereum", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - "description": "the query address", - "name": "address", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } - } - } - } - }, - "/v2/{coin}/collections/{owner}/collection/{collection_id}": { - "get": { - "description": "Get a collection from the address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get Collection", - "operationId": "collection_v2", - "parameters": [ - { - "type": "string", - "default": "ethereum", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "description": "the query address", - "name": "owner", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x06012c8cf97bead5deae237070f9587f8e7a266d", - "description": "the query collection", - "name": "collection_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } - } - } - } - }, "/v2/{coin}/staking/delegations/{address}": { "get": { "description": "Get stake delegations from the address", @@ -740,146 +593,6 @@ var doc = `{ } } }, - "/v3/collectibles/categories": { - "post": { - "description": "Get collection categories", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get list of collections from a specific coin and addresses", - "operationId": "collection_categories_v3", - "parameters": [ - { - "default": "{\"60\": [\"0xb3624367b1ab37daef42e1a3a2ced012359659b0\"]}", - "description": "Payload", - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.DocsResponse" - } - } - } - } - }, - "/v3/{coin}/collections/{address}": { - "get": { - "description": "Get all collections from the address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get Collections", - "operationId": "collections_v3", - "parameters": [ - { - "type": "string", - "default": "ethereum", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - "description": "the query address", - "name": "address", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } - } - } - } - }, - "/v3/{coin}/collections/{owner}/collection/{collection_id}": { - "get": { - "description": "Get a collection from the address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get Collection", - "operationId": "collection_v3", - "parameters": [ - { - "type": "string", - "default": "ethereum", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "description": "the query address", - "name": "owner", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x06012c8cf97bead5deae237070f9587f8e7a266d", - "description": "the query collection", - "name": "collection_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } - } - } - } - }, "/v4/collectibles/categories": { "post": { "description": "Get collection categories", @@ -1001,7 +714,8 @@ var doc = `{ "type": "string" }, "type": { - "type": "string" + "type": "object", + "$ref": "#/definitions/blockatlas.CoinStatus" } } }, @@ -1069,6 +783,17 @@ var doc = `{ "$ref": "#/definitions/api.Ticker" } }, + "blockatlas.CoinStatus": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "height": { + "type": "integer" + } + } + }, "blockatlas.Collection": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index dc8104ce2..52096ec8c 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -136,13 +136,6 @@ "name": "token", "in": "query" }, - { - "type": "integer", - "default": 1574483028, - "description": "Start timestamp", - "name": "time_start", - "in": "query" - }, { "type": "string", "default": "USD", @@ -280,42 +273,6 @@ } } }, - "/v2/collectibles/categories": { - "post": { - "description": "Get collection categories", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get list of collections from a specific coin and addresses", - "operationId": "collection_categories_v2", - "parameters": [ - { - "default": "{\"60\": [\"0xb3624367b1ab37daef42e1a3a2ced012359659b0\"]}", - "description": "Payload", - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.DocsResponse" - } - } - } - } - }, "/v2/ns/lookup": { "get": { "description": "Lookup ENS/ZNS to find registered addresses for multiple coins", @@ -431,110 +388,6 @@ } } }, - "/v2/{coin}/collections/{address}": { - "get": { - "description": "Get all collections from the address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get Collections", - "operationId": "collections_v2", - "parameters": [ - { - "type": "string", - "default": "ethereum", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - "description": "the query address", - "name": "address", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } - } - } - } - }, - "/v2/{coin}/collections/{owner}/collection/{collection_id}": { - "get": { - "description": "Get a collection from the address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get Collection", - "operationId": "collection_v2", - "parameters": [ - { - "type": "string", - "default": "ethereum", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "description": "the query address", - "name": "owner", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x06012c8cf97bead5deae237070f9587f8e7a266d", - "description": "the query collection", - "name": "collection_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } - } - } - } - }, "/v2/{coin}/staking/delegations/{address}": { "get": { "description": "Get stake delegations from the address", @@ -719,146 +572,6 @@ } } }, - "/v3/collectibles/categories": { - "post": { - "description": "Get collection categories", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get list of collections from a specific coin and addresses", - "operationId": "collection_categories_v3", - "parameters": [ - { - "default": "{\"60\": [\"0xb3624367b1ab37daef42e1a3a2ced012359659b0\"]}", - "description": "Payload", - "name": "data", - "in": "body", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.DocsResponse" - } - } - } - } - }, - "/v3/{coin}/collections/{address}": { - "get": { - "description": "Get all collections from the address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get Collections", - "operationId": "collections_v3", - "parameters": [ - { - "type": "string", - "default": "ethereum", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - "description": "the query address", - "name": "address", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } - } - } - } - }, - "/v3/{coin}/collections/{owner}/collection/{collection_id}": { - "get": { - "description": "Get a collection from the address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Collections" - ], - "summary": "Get Collection", - "operationId": "collection_v3", - "parameters": [ - { - "type": "string", - "default": "ethereum", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "description": "the query address", - "name": "owner", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "0x06012c8cf97bead5deae237070f9587f8e7a266d", - "description": "the query collection", - "name": "collection_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } - } - } - } - }, "/v4/collectibles/categories": { "post": { "description": "Get collection categories", @@ -980,7 +693,8 @@ "type": "string" }, "type": { - "type": "string" + "type": "object", + "$ref": "#/definitions/blockatlas.CoinStatus" } } }, @@ -1048,6 +762,17 @@ "$ref": "#/definitions/api.Ticker" } }, + "blockatlas.CoinStatus": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "height": { + "type": "integer" + } + } + }, "blockatlas.Collection": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4ddb42cde..0656a0ebf 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -17,7 +17,8 @@ definitions: token_id: type: string type: - type: string + $ref: '#/definitions/blockatlas.CoinStatus' + type: object type: object api.Ticker: properties: @@ -61,6 +62,13 @@ definitions: items: $ref: '#/definitions/api.Ticker' type: array + blockatlas.CoinStatus: + properties: + error: + type: string + height: + type: integer + type: object blockatlas.Collection: properties: address: @@ -439,11 +447,6 @@ paths: in: query name: token type: string - - default: 1574483028 - description: Start timestamp - in: query - name: time_start - type: integer - default: USD description: The currency to show coin info in in: query @@ -482,78 +485,6 @@ paths: summary: Get ticker values for a specific market tags: - Market - /v2/{coin}/collections/{address}: - get: - consumes: - - application/json - description: Get all collections from the address - operationId: collections_v2 - parameters: - - default: ethereum - description: the coin name - in: path - name: coin - required: true - type: string - - default: 0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB - description: the query address - in: path - name: address - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.CollectionPage' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/ginutils.ApiError' - summary: Get Collections - tags: - - Collections - /v2/{coin}/collections/{owner}/collection/{collection_id}: - get: - consumes: - - application/json - description: Get a collection from the address - operationId: collection_v2 - parameters: - - default: ethereum - description: the coin name - in: path - name: coin - required: true - type: string - - default: 0x0875BCab22dE3d02402bc38aEe4104e1239374a7 - description: the query address - in: path - name: owner - required: true - type: string - - default: 0x06012c8cf97bead5deae237070f9587f8e7a266d - description: the query collection - in: path - name: collection_id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.CollectionPage' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/ginutils.ApiError' - summary: Get Collection - tags: - - Collections /v2/{coin}/staking/delegations/{address}: get: consumes: @@ -680,30 +611,6 @@ paths: summary: Get Transactions tags: - Transactions - /v2/collectibles/categories: - post: - consumes: - - application/json - description: Get collection categories - operationId: collection_categories_v2 - parameters: - - default: '{"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}' - description: Payload - in: body - name: data - required: true - schema: - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.DocsResponse' - summary: Get list of collections from a specific coin and addresses - tags: - - Collections /v2/ns/lookup: get: description: Lookup ENS/ZNS to find registered addresses for multiple coins @@ -780,102 +687,6 @@ paths: summary: Get Multiple Stake Delegations tags: - Staking - /v3/{coin}/collections/{address}: - get: - consumes: - - application/json - description: Get all collections from the address - operationId: collections_v3 - parameters: - - default: ethereum - description: the coin name - in: path - name: coin - required: true - type: string - - default: 0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB - description: the query address - in: path - name: address - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.CollectionPage' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/ginutils.ApiError' - summary: Get Collections - tags: - - Collections - /v3/{coin}/collections/{owner}/collection/{collection_id}: - get: - consumes: - - application/json - description: Get a collection from the address - operationId: collection_v3 - parameters: - - default: ethereum - description: the coin name - in: path - name: coin - required: true - type: string - - default: 0x0875BCab22dE3d02402bc38aEe4104e1239374a7 - description: the query address - in: path - name: owner - required: true - type: string - - default: 0x06012c8cf97bead5deae237070f9587f8e7a266d - description: the query collection - in: path - name: collection_id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.CollectionPage' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/ginutils.ApiError' - summary: Get Collection - tags: - - Collections - /v3/collectibles/categories: - post: - consumes: - - application/json - description: Get collection categories - operationId: collection_categories_v3 - parameters: - - default: '{"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}' - description: Payload - in: body - name: data - required: true - schema: - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.DocsResponse' - summary: Get list of collections from a specific coin and addresses - tags: - - Collections /v4/{coin}/collections/{owner}/collection/{collection_id}: get: consumes: diff --git a/pkg/blockatlas/collectibles.go b/pkg/blockatlas/collectibles.go index 74a272e35..bad081526 100644 --- a/pkg/blockatlas/collectibles.go +++ b/pkg/blockatlas/collectibles.go @@ -1,7 +1,7 @@ package blockatlas type ( - Collection struct { + CollectionV3 struct { Id string `json:"id"` Name string `json:"name"` Symbol string `json:"symbol"` @@ -18,14 +18,26 @@ type ( Type string `json:"type"` } + Collection struct { + Id string `json:"id"` + Name string `json:"name"` + ImageUrl string `json:"image_url"` + Description string `json:"description"` + ExternalLink string `json:"external_link"` + Total int `json:"total"` + Address string `json:"address"` + Coin uint `json:"coin"` + Type string `json:"-"` + } + + CollectionPageV3 []CollectionV3 + CollectionPage []Collection Collectible struct { - ID string `json:"id"` - CollectionID string `json:"collection_id"` - TokenID string `json:"token_id"` - CategoryContract string `json:"category_contract"` - // Deprecated: for support old client, ContractAddress eq CollectionID + ID string `json:"id"` + CollectionID string `json:"collection_id"` + TokenID string `json:"token_id"` ContractAddress string `json:"contract_address"` Category string `json:"category"` ImageUrl string `json:"image_url"` @@ -39,4 +51,23 @@ type ( } CollectiblePage []Collectible + + CollectibleV3 struct { + ID string `json:"id"` + CollectionID string `json:"collection_id"` + TokenID string `json:"token_id"` + CategoryContract string `json:"category_contract"` + ContractAddress string `json:"contract_address"` + Category string `json:"category"` + ImageUrl string `json:"image_url"` + ExternalLink string `json:"external_link"` + ProviderLink string `json:"provider_link"` + Type string `json:"type"` + Description string `json:"description"` + Coin uint `json:"coin"` + Name string `json:"name"` + Version string `json:"nft_version"` + } + + CollectiblePageV3 []CollectibleV3 ) diff --git a/pkg/blockatlas/marshal.go b/pkg/blockatlas/marshal.go index 00f6dd8de..91b9a543f 100644 --- a/pkg/blockatlas/marshal.go +++ b/pkg/blockatlas/marshal.go @@ -163,3 +163,35 @@ func (r CollectiblePage) MarshalJSON() ([]byte, error) { page.Status = true return json.Marshal(page) } + +// MarshalJSON returns a wrapped list of collections in JSON +func (r CollectionPageV3) MarshalJSON() ([]byte, error) { + var page struct { + Total int `json:"total"` + Docs []CollectionV3 `json:"docs"` + Status bool `json:"status"` + } + page.Docs = []CollectionV3(r) + if page.Docs == nil { + page.Docs = make([]CollectionV3, 0) + } + page.Total = len(page.Docs) + page.Status = true + return json.Marshal(page) +} + +// MarshalJSON returns a wrapped list of collectibles in JSON +func (r CollectiblePageV3) MarshalJSON() ([]byte, error) { + var page struct { + Total int `json:"total"` + Docs []CollectibleV3 `json:"docs"` + Status bool `json:"status"` + } + page.Docs = []CollectibleV3(r) + if page.Docs == nil { + page.Docs = make([]CollectibleV3, 0) + } + page.Total = len(page.Docs) + page.Status = true + return json.Marshal(page) +} diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 28bbbb664..43c23e84b 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -56,11 +56,8 @@ type ( GetCollections(owner string) (CollectionPage, error) GetCollectibles(owner, collectibleID string) (CollectiblePage, error) - OldGetCollections(owner string) (CollectionPage, error) - OldGetCollectibles(owner, collectibleID string) (CollectiblePage, error) - - GetCollectionsV4(owner string) (CollectionPage, error) - GetCollectiblesV4(owner, collectibleID string) (CollectiblePage, error) + GetCollectionsV3(owner string) (CollectionPageV3, error) + GetCollectiblesV3(owner, collectibleID string) (CollectiblePageV3, error) } // CustomAPI provides custom HTTP routes diff --git a/platform/ethereum/collection.go b/platform/ethereum/collection.go index 251df61b9..7cb836c4f 100644 --- a/platform/ethereum/collection.go +++ b/platform/ethereum/collection.go @@ -1,14 +1,12 @@ package ethereum import ( - "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" "strings" ) var ( supportedTypes = map[string]bool{"ERC721": true, "ERC1155": true} - slugTokens = map[string]bool{"ERC1155": true} ) func (p *Platform) GetCollections(owner string) (blockatlas.CollectionPage, error) { @@ -16,252 +14,63 @@ func (p *Platform) GetCollections(owner string) (blockatlas.CollectionPage, erro if err != nil { return nil, err } - page := NormalizeCollectionPage(collections, p.CoinIndex, owner) - return page, nil -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func (p *Platform) OldGetCollections(owner string) (blockatlas.CollectionPage, error) { - collections, err := p.collectionsClient.GetCollections(owner) - if err != nil { - return nil, err - } - page := OldNormalizeCollectionPage(collections, p.CoinIndex, owner) - return page, nil + return NormalizeCollections(collections, p.CoinIndex, owner), nil } func (p *Platform) GetCollectibles(owner, collectibleID string) (blockatlas.CollectiblePage, error) { - collection, items, err := p.collectionsClient.GetCollectibles(owner, collectibleID) + items, err := p.collectionsClient.GetCollectibles(owner, collectibleID) if err != nil { return nil, err } - page := NormalizeCollectiblePage(collection, items, p.CoinIndex) - return page, nil + return NormalizeCollectiblePage(items, p.CoinIndex), nil } -func NormalizeCollectionPage(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { +func NormalizeCollections(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { for _, collection := range collections { - if len(collection.Contracts) == 0 { - continue - } item := NormalizeCollection(collection, coinIndex, owner) - if _, ok := supportedTypes[item.Type]; !ok { - continue - } page = append(page, item) } - return -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func (p *Platform) OldGetCollectibles(owner, collectibleID string) (blockatlas.CollectiblePage, error) { - collection, items, err := p.collectionsClient.OldGetCollectibles(owner, collectibleID) - if err != nil { - return nil, err - } - page := OldNormalizeCollectiblePage(collection, items, p.CoinIndex) - return page, nil -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func OldNormalizeCollectionPage(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { - for _, collection := range collections { - if len(collection.Contracts) == 0 { - continue - } - item := OldNormalizeCollection(collection, coinIndex, owner) - if _, ok := supportedTypes[item.Type]; !ok { - continue - } - page = append(page, item) - } - return -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func OldNormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas.Collection { - if len(c.Contracts) == 0 { - return blockatlas.Collection{} - } - - description := blockatlas.GetValidParameter(c.Description, c.Contracts[0].Description) - symbol := blockatlas.GetValidParameter(c.Contracts[0].Symbol, "") - collectionId := blockatlas.GetValidParameter(c.Contracts[0].Address, "") - version := blockatlas.GetValidParameter(c.Contracts[0].NftVersion, "") - collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") - if _, ok := slugTokens[collectionType]; ok { - collectionId = createCollectionId(collectionId, c.Slug) - } - - return blockatlas.Collection{ - Name: c.Name, - Symbol: symbol, - Slug: c.Slug, - ImageUrl: c.ImageUrl, - Description: description, - ExternalLink: c.ExternalUrl, - Total: int(c.Total.Int64()), - Id: collectionId, - CategoryAddress: collectionId, - Address: owner, - Version: version, - Coin: coinIndex, - Type: collectionType, - } -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func OldNormalizeCollectible(c *Collection, a Collectible, coinIndex uint) blockatlas.Collectible { - address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") - collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") - collectionID := address - if _, ok := slugTokens[collectionType]; ok { - collectionID = createCollectionId(address, c.Slug) - } - externalLink := blockatlas.GetValidParameter(a.ExternalLink, a.AssetContract.ExternalLink) - id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") - return blockatlas.Collectible{ - ID: id, - CollectionID: collectionID, - ContractAddress: address, - TokenID: a.TokenId, - CategoryContract: a.AssetContract.Address, - Name: a.Name, - Category: c.Name, - ImageUrl: a.ImagePreviewUrl, - ProviderLink: a.Permalink, - ExternalLink: externalLink, - Type: collectionType, - Description: a.Description, - Coin: coinIndex, - } -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func createCollectionId(address, slug string) string { - return fmt.Sprintf("%s---%s", address, slug) -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func getCollectionId(collectionId string) string { - s := strings.Split(collectionId, "---") - if len(s) != 2 { - return collectionId - } - return s[1] -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func OldNormalizeCollectiblePage(c *Collection, srcPage []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { - if len(c.Contracts) == 0 { - return - } - for _, src := range srcPage { - item := OldNormalizeCollectible(c, src, coinIndex) - if _, ok := supportedTypes[item.Type]; !ok { - continue - } - page = append(page, item) - } - return + return page } func NormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas.Collection { - normalizeSupportedContracts(&c) - if len(c.Contracts) == 0 { - return blockatlas.Collection{} - } - - description := blockatlas.GetValidParameter(c.Description, c.Contracts[0].Description) - symbol := blockatlas.GetValidParameter(c.Contracts[0].Symbol, "") - version := blockatlas.GetValidParameter(c.Contracts[0].NftVersion, "") - collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") - return blockatlas.Collection{ - Name: c.Name, - Symbol: symbol, - Slug: c.Slug, - ImageUrl: c.ImageUrl, - Description: description, - ExternalLink: c.ExternalUrl, - Total: int(c.Total.Int64()), - Id: c.Slug, - CategoryAddress: c.Slug, - Address: owner, - Version: version, - Coin: coinIndex, - Type: collectionType, - } -} - -func normalizeSupportedContracts(c *Collection) { - supportedContracts := make([]PrimaryAssetContract, 0) - for _, contract := range c.Contracts { - if _, ok := supportedTypes[contract.Type]; !ok { - continue + Name: c.Name, + ImageUrl: c.ImageUrl, + Description: c.Description, + ExternalLink: c.ExternalUrl, + Total: int(c.Total.Int64()), + Id: c.Slug, + Address: owner, + Coin: coinIndex, + } +} + +func NormalizeCollectiblePage(collectibles []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { + for _, collectible := range collectibles { + item := NormalizeCollectible(collectible, coinIndex) + if _, ok := supportedTypes[item.Type]; ok { + page = append(page, item) } - supportedContracts = append(supportedContracts, contract) } - c.Contracts = supportedContracts + return page } -func NormalizeCollectiblePage(c *Collection, srcPage []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { - normalizeSupportedContracts(c) - if len(c.Contracts) == 0 { - return - } - for _, src := range srcPage { - item := NormalizeCollectible(c, src, coinIndex) - if _, ok := supportedTypes[item.Type]; !ok { - continue - } - page = append(page, item) - } - return -} - -func NormalizeCollectible(c *Collection, a Collectible, coinIndex uint) blockatlas.Collectible { - address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") - collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") - externalLink := blockatlas.GetValidParameter(a.ExternalLink, a.AssetContract.ExternalLink) +func NormalizeCollectible(a Collectible, coinIndex uint) blockatlas.Collectible { id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") return blockatlas.Collectible{ - ID: id, - CollectionID: c.Slug, - ContractAddress: address, - TokenID: a.TokenId, - CategoryContract: a.AssetContract.Address, - Name: a.Name, - Category: c.Name, - ImageUrl: a.ImagePreviewUrl, - ProviderLink: a.Permalink, - ExternalLink: externalLink, - Type: collectionType, - Description: a.Description, - Coin: coinIndex, - } -} - -func searchCollection(collections []Collection, collectibleID string) *Collection { - for _, i := range collections { - if strings.EqualFold(i.Slug, collectibleID) { - return &i - } - } - return nil -} - -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func oldSearchCollection(collections []Collection, collectibleID string) *Collection { - for _, i := range collections { - if strings.EqualFold(i.Slug, collectibleID) { - return &i - } - for _, contract := range i.Contracts { - if strings.EqualFold(contract.Address, collectibleID) { - return &i - } - } + ID: id, + CollectionID: a.Collection.Slug, + TokenID: a.TokenId, + ContractAddress: a.AssetContract.Address, + Name: a.Name, + Category: a.Collection.Name, + ImageUrl: a.ImagePreviewUrl, + ProviderLink: a.Permalink, + ExternalLink: a.Collection.ExternalLink, + Type: a.AssetContract.Type, + Description: a.Description, + Coin: coinIndex, + Version: a.AssetContract.Version, } - return nil } diff --git a/platform/ethereum/collectionV3.go b/platform/ethereum/collectionV3.go new file mode 100644 index 000000000..dc35a5afe --- /dev/null +++ b/platform/ethereum/collectionV3.go @@ -0,0 +1,114 @@ +package ethereum + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "strings" +) + +func (p *Platform) GetCollectionsV3(owner string) (blockatlas.CollectionPageV3, error) { + collections, err := p.collectionsClient.GetCollections(owner) + if err != nil { + return nil, err + } + page := NormalizeCollectionPageV3(collections, p.CoinIndex, owner) + return page, nil +} + +func (p *Platform) GetCollectiblesV3(owner, collectibleID string) (blockatlas.CollectiblePageV3, error) { + collection, items, err := p.collectionsClient.GetCollectiblesV3(owner, collectibleID) + if err != nil { + return nil, err + } + page := NormalizeCollectiblePageV3(collection, items, p.CoinIndex) + return page, nil +} + +func NormalizeCollectionPageV3(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPageV3) { + for _, collection := range collections { + if len(collection.Contracts) == 0 { + continue + } + item := NormalizeCollectionV3(collection, coinIndex, owner) + if _, ok := supportedTypes[item.Type]; !ok { + continue + } + page = append(page, item) + } + return +} + +func NormalizeCollectionV3(c Collection, coinIndex uint, owner string) blockatlas.CollectionV3 { + normalizeSupportedContracts(&c) + if len(c.Contracts) == 0 { + return blockatlas.CollectionV3{} + } + + description := blockatlas.GetValidParameter(c.Description, c.Contracts[0].Description) + symbol := blockatlas.GetValidParameter(c.Contracts[0].Symbol, "") + version := blockatlas.GetValidParameter(c.Contracts[0].NftVersion, "") + collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") + + return blockatlas.CollectionV3{ + Name: c.Name, + Symbol: symbol, + Slug: c.Slug, + ImageUrl: c.ImageUrl, + Description: description, + ExternalLink: c.ExternalUrl, + Total: int(c.Total.Int64()), + Id: c.Slug, + CategoryAddress: c.Slug, + Address: owner, + Version: version, + Coin: coinIndex, + Type: collectionType, + } +} + +func normalizeSupportedContracts(c *Collection) { + supportedContracts := make([]PrimaryAssetContract, 0) + for _, contract := range c.Contracts { + if _, ok := supportedTypes[contract.Type]; !ok { + continue + } + supportedContracts = append(supportedContracts, contract) + } + c.Contracts = supportedContracts +} + +func NormalizeCollectiblePageV3(c *Collection, srcPage []Collectible, coinIndex uint) (page blockatlas.CollectiblePageV3) { + normalizeSupportedContracts(c) + if len(c.Contracts) == 0 { + return + } + for _, src := range srcPage { + item := NormalizeCollectibleV3(c, src, coinIndex) + if _, ok := supportedTypes[item.Type]; !ok { + continue + } + page = append(page, item) + } + return +} + +func NormalizeCollectibleV3(c *Collection, a Collectible, coinIndex uint) blockatlas.CollectibleV3 { + address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") + collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") + externalLink := blockatlas.GetValidParameter(a.ExternalLink, a.AssetContract.ExternalLink) + id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") + return blockatlas.CollectibleV3{ + ID: id, + CollectionID: c.Slug, + ContractAddress: address, + TokenID: a.TokenId, + CategoryContract: a.AssetContract.Address, + Name: a.Name, + Category: c.Name, + ImageUrl: a.ImagePreviewUrl, + ProviderLink: a.Permalink, + ExternalLink: externalLink, + Type: collectionType, + Description: a.Description, + Coin: coinIndex, + } +} diff --git a/platform/ethereum/collection_client.go b/platform/ethereum/collection_client.go index 2c4bdeb1d..5a049e708 100644 --- a/platform/ethereum/collection_client.go +++ b/platform/ethereum/collection_client.go @@ -5,6 +5,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/errors" "net/url" "strconv" + "strings" ) type CollectionsClient struct { @@ -20,30 +21,7 @@ func (c CollectionsClient) GetCollections(owner string) (page []Collection, err return } -func (c CollectionsClient) GetCollectibles(owner string, collectibleID string) (*Collection, []Collectible, error) { - collections, err := c.GetCollections(owner) - if err != nil { - return nil, nil, err - } - collection := searchCollection(collections, collectibleID) - if collection == nil { - return nil, nil, errors.E("collectible not found", errors.TypePlatformClient, - errors.Params{"collectibleID": collectibleID}) - } - - query := url.Values{ - "owner": {owner}, - "limit": {strconv.Itoa(300)}, - } - - query.Set("collection", collection.Slug) - - var page CollectiblePage - err = c.Get(&page, "api/v1/assets", query) - return collection, page.Collectibles, err -} - -func (c CollectionsClient) GetCollectiblesV4(owner string, collectibleID string) ([]Collectible, error) { +func (c CollectionsClient) GetCollectibles(owner string, collectibleID string) ([]Collectible, error) { query := url.Values{ "owner": {owner}, "collection": {collectibleID}, @@ -55,14 +33,12 @@ func (c CollectionsClient) GetCollectiblesV4(owner string, collectibleID string) return page.Collectibles, err } -//TODO: remove once most of the clients will be updated (deadline: March 17th) -func (c CollectionsClient) OldGetCollectibles(owner string, collectibleID string) (*Collection, []Collectible, error) { +func (c CollectionsClient) GetCollectiblesV3(owner string, collectibleID string) (*Collection, []Collectible, error) { collections, err := c.GetCollections(owner) if err != nil { return nil, nil, err } - id := getCollectionId(collectibleID) - collection := oldSearchCollection(collections, id) + collection := searchCollection(collections, collectibleID) if collection == nil { return nil, nil, errors.E("collectible not found", errors.TypePlatformClient, errors.Params{"collectibleID": collectibleID}) @@ -73,15 +49,18 @@ func (c CollectionsClient) OldGetCollectibles(owner string, collectibleID string "limit": {strconv.Itoa(300)}, } - for _, i := range collection.Contracts { - if _, ok := slugTokens[i.Type]; ok { - query.Set("collection", collection.Slug) - break - } - query.Add("asset_contract_addresses", i.Address) - } + query.Set("collection", collection.Slug) var page CollectiblePage err = c.Get(&page, "api/v1/assets", query) return collection, page.Collectibles, err } + +func searchCollection(collections []Collection, collectibleID string) *Collection { + for _, i := range collections { + if strings.EqualFold(i.Slug, collectibleID) { + return &i + } + } + return nil +} diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/collection_test.go index 056743e97..771baa5ac 100644 --- a/platform/ethereum/collection_test.go +++ b/platform/ethereum/collection_test.go @@ -2,142 +2,282 @@ package ethereum import ( "encoding/json" - "fmt" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "math/big" "testing" ) -const collectionsOwner = "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +const collectionsOwnerV4 = "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -const collectionsSrc = ` +const collectionsSrcV4 = ` [ - { - "primary_asset_contracts": [ - { - "address": "0x06012c8cf97bead5deae237070f9587f8e7a266d", - "name": "CryptoKitties", - "symbol": "CKITTY", - "description": "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - "external_link": "https://www.cryptokitties.co/", - "nft_version": "1.0", - "schema_name": "ERC721", - "display_data": { - "images": [ - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/564155.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/546630.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/441529.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/552435.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/524748.png", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/540800.svg" - ], - "card_display_style": "padded" - }, - "image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png" - } - ], - "name": "CryptoKitties", - "slug": "cryptokitties", - "image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", - "description": "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - "external_url": "https://www.cryptokitties.co/", - "featured_image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556589429.png", - "created_date": "2019-04-26T22:13:04.207050", - "owned_asset_count": 3 - }, - { - "primary_asset_contracts": [ - { - "address": "0xf629cbd94d3791c9250152bd8dfbdf380e2a3b9c", - "name": "Coin", - "symbol": "", - "description": null, - "external_link": null, - "nft_version": null, - "schema_name": "ERC20", - "display_data": {} - } - ], - "name": "Enjin Token", - "slug": "enjin-token", - "image_url": "https://storage.googleapis.com/opensea-static/tokens-high-res/ENJ.png", - "description": "This is the collection of owners of EnjinCoin", - "external_url": null, - "owned_asset_count": 20000000000000000000 - }, - { - "primary_asset_contracts": [ - { - "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - "name": "Enjin", - "symbol": "", - "description": "", - "external_link": null, - "nft_version": null, - "schema_name": "ERC1155", - "display_data": {}, - "owner": null, - "created_date": "2019-08-02T23:43:14.666153", - "asset_contract_type": "semi-fungible" - } - ], - "name": "Age of Rust", - "slug": "age-of-rust", - "image_url": "https://storage.opensea.io/age-of-rust-1561960816.jpg", - "description": "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", - "external_url": "https://www.ageofrust.games/", - "featured_image_url": null, - "created_date": "2019-09-03T02:35:56.063685", - "owned_asset_count": 1 - } + { + "primary_asset_contracts":[ + { + "address":"0x06012c8cf97bead5deae237070f9587f8e7a266d", + "name":"CryptoKitties", + "symbol":"CKITTY", + "description":"CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + "external_link":"https://www.cryptokitties.co/", + "nft_version":"1.0", + "schema_name":"ERC721", + "display_data":{ + "images":[ + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/564155.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/546630.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/441529.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/552435.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/524748.png", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/540800.svg" + ], + "card_display_style":"padded" + }, + "image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png" + } + ], + "name":"CryptoKitties", + "slug":"cryptokitties", + "image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", + "description":"CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + "external_url":"https://www.cryptokitties.co/", + "featured_image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556589429.png", + "created_date":"2019-04-26T22:13:04.207050", + "owned_asset_count":3 + }, + { + "primary_asset_contracts":[ + { + "address":"0xfaafdc07907ff5120a76b34b731b278c38d6043c", + "name":"Enjin", + "symbol":"", + "description":"", + "external_link":null, + "nft_version":null, + "schema_name":"ERC1155", + "display_data":{ + + }, + "owner":null, + "created_date":"2019-08-02T23:43:14.666153", + "asset_contract_type":"semi-fungible" + } + ], + "name":"Age of Rust", + "slug":"age-of-rust", + "image_url":"https://storage.opensea.io/age-of-rust-1561960816.jpg", + "description":"Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", + "external_url":"https://www.ageofrust.games/", + "featured_image_url":null, + "created_date":"2019-09-03T02:35:56.063685", + "owned_asset_count":1 + }, + { + "primary_asset_contracts":[ + { + "address":"0xee85966b4974d3c6f71a2779cc3b6f53afbc2b68", + "asset_contract_type":"fungible", + "created_date":"2019-10-16T07:36:16.102163", + "name":"Rare Chest", + "nft_version":null, + "opensea_version":null, + "owner":1610615, + "schema_name":"ERC20", + "symbol":"", + "total_supply":"1", + "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat":false, + "dev_buyer_fee_basis_points":0, + "dev_seller_fee_basis_points":0, + "only_proxied_transfers":false, + "opensea_buyer_fee_basis_points":0, + "opensea_seller_fee_basis_points":250, + "buyer_fee_basis_points":0, + "seller_fee_basis_points":250, + "payout_address":null + }, + { + "address":"0x20d4cec36528e1c4563c1bfbe3de06aba70b22b4", + "asset_contract_type":"fungible", + "created_date":"2019-10-16T08:06:42.727997", + "name":"Legendary Chest", + "nft_version":null, + "opensea_version":null, + "owner":1610615, + "schema_name":"ERC20", + "symbol":"", + "total_supply":"1", + "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat":false, + "dev_buyer_fee_basis_points":0, + "dev_seller_fee_basis_points":0, + "only_proxied_transfers":false, + "opensea_buyer_fee_basis_points":0, + "opensea_seller_fee_basis_points":250, + "buyer_fee_basis_points":0, + "seller_fee_basis_points":250, + "payout_address":null + }, + { + "address":"0x0e3a2a1f2146d86a604adc220b4967a898d7fe07", + "asset_contract_type":"non-fungible", + "created_date":"2019-11-01T06:39:04.363034", + "name":"Gods Unchained Cards", + "nft_version":"3.0", + "opensea_version":null, + "owner":1691695, + "schema_name":"ERC721", + "symbol":"", + "total_supply":"1", + "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat":false, + "dev_buyer_fee_basis_points":0, + "dev_seller_fee_basis_points":0, + "only_proxied_transfers":false, + "opensea_buyer_fee_basis_points":0, + "opensea_seller_fee_basis_points":250, + "buyer_fee_basis_points":0, + "seller_fee_basis_points":250, + "payout_address":null + }, + { + "address":"0x564cb55c655f727b61d9baf258b547ca04e9e548", + "asset_contract_type":"non-fungible", + "created_date":"2019-10-29T12:28:37.643714", + "name":"Gods Unchained", + "nft_version":"3.0", + "opensea_version":null, + "owner":1691695, + "schema_name":"ERC721", + "symbol":"", + "total_supply":"205", + "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat":false, + "dev_buyer_fee_basis_points":0, + "dev_seller_fee_basis_points":0, + "only_proxied_transfers":false, + "opensea_buyer_fee_basis_points":0, + "opensea_seller_fee_basis_points":250, + "buyer_fee_basis_points":0, + "seller_fee_basis_points":250, + "payout_address":null + } + ], + "traits":{ + "mana":{ + "min":1, + "max":18 + }, + "health":{ + "min":1, + "max":16 + }, + "attack":{ + "min":1, + "max":16 + } + }, + "stats":{ + "seven_day_volume":270.564697067863, + "seven_day_change":-0.014179906699531201, + "total_volume":11825.0384171324, + "count":6835331, + "num_owners":10791, + "market_cap":150892.14138332763, + "average_price":0.0396514694030496, + "items_sold":298233 + }, + "banner_image_url":null, + "chat_url":null, + "created_date":"2019-11-13T03:01:42.051246", + "default_to_fiat":false, + "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "dev_buyer_fee_basis_points":"0", + "dev_seller_fee_basis_points":"0", + "display_data":{ + "images":[ + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/25233.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/152875.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/25669.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9237.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9228.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9231.png" + ], + "card_display_style":"contain" + }, + "external_url":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "featured":true, + "featured_image_url":"https://storage.opensea.io/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab-featured-1556589419.png", + "hidden":false, + "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "is_subject_to_whitelist":false, + "large_image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ", + "name":"Gods Unchained", + "only_proxied_transfers":false, + "opensea_buyer_fee_basis_points":"0", + "opensea_seller_fee_basis_points":"250", + "payout_address":null, + "require_email":false, + "short_description":null, + "slug":"gods-unchained", + "wiki_url":null, + "owned_asset_count":535 + } ] ` -var collection1Dst = blockatlas.Collection{ - Name: "CryptoKitties", - Symbol: "CKITTY", - Slug: "cryptokitties", - ImageUrl: "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", - Description: "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - ExternalLink: "https://www.cryptokitties.co/", - Total: 3, - CategoryAddress: "cryptokitties", - Id: "cryptokitties", - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - Version: "1.0", - Coin: 60, - Type: "ERC721", +var collection1DstV4 = blockatlas.Collection{ + Name: "CryptoKitties", + ImageUrl: "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", + Description: "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + ExternalLink: "https://www.cryptokitties.co/", + Total: 3, + Id: "cryptokitties", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Coin: 60, } -var collection2Dst = blockatlas.Collection{ - Name: "Age of Rust", - Symbol: "", - Slug: "age-of-rust", - ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", - Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", - ExternalLink: "https://www.ageofrust.games/", - Total: 1, - CategoryAddress: "age-of-rust", - Id: "age-of-rust", - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - Version: "", - Coin: 60, - Type: "ERC1155", +var collection2DstV4 = blockatlas.Collection{ + Name: "Age of Rust", + ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", + Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", + ExternalLink: "https://www.ageofrust.games/", + Total: 1, + Id: "age-of-rust", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Coin: 60, } -func TestNormalizeCollection(t *testing.T) { +var collection3DstV4 = blockatlas.Collection{ + Name: "Gods Unchained", + ImageUrl: "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + Description: "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + ExternalLink: "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + Total: 535, + Id: "gods-unchained", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Coin: 60, +} + +func TestNormalizeCollectionV4(t *testing.T) { var collections []Collection - err := json.Unmarshal([]byte(collectionsSrc), &collections) + err := json.Unmarshal([]byte(collectionsSrcV4), &collections) assert.Nil(t, err) - page := NormalizeCollectionPage(collections, coin.ETH, collectionsOwner) - assert.Equal(t, len(page), 2, "collections could not be normalized") - expected := blockatlas.CollectionPage{collection1Dst, collection2Dst} + page := NormalizeCollections(collections, coin.ETH, collectionsOwnerV4) + assert.Equal(t, 3, len(page), "collections could not be normalized") + expected := blockatlas.CollectionPage{collection1DstV4, collection2DstV4, collection3DstV4} assert.Equal(t, page, expected, "collections don't equal") } -const collectibleSrc = ` +const collectibleSrcV4 = ` [ { "token_id": "54277541829991970107421667568590323026590803461896874578610080514640537714688", @@ -153,259 +293,38 @@ const collectibleSrc = ` "nft_version": null, "schema_name": "ERC1155", "display_data": {} + }, + "collection": { + "slug": "age-of-rust", + "name": "Age of Rust", + "external_url": "https://opensea.io/" }, "permalink": "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688" } ] ` -var collectibleCollectionDst = Collection{ - Name: "Age of Rust", - ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", - Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", - ExternalUrl: "https://www.ageofrust.games/", - Total: big.NewInt(1), - Slug: "age-of-rust", - Contracts: []PrimaryAssetContract{ - { - Name: "Age of Rust", - Address: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - NftVersion: "", - Symbol: "", - Description: "", - Type: "ERC1155", - Url: "", - }, - }, -} - -var collectibleDst = blockatlas.Collectible{ - ID: "0xfaafdc07907ff5120a76b34b731b278c38d6043c-54277541829991970107421667568590323026590803461896874578610080514640537714688", - CollectionID: "age-of-rust", - TokenID: "54277541829991970107421667568590323026590803461896874578610080514640537714688", - CategoryContract: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - ContractAddress: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - Category: "Age of Rust", - ImageUrl: "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", - ExternalLink: "", - ProviderLink: "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688", - Type: "ERC1155", - Description: "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", - Coin: 60, - Name: "Rustbits", +var collectibleDstV4 = blockatlas.Collectible{ + ID: "0xfaafdc07907ff5120a76b34b731b278c38d6043c-54277541829991970107421667568590323026590803461896874578610080514640537714688", + CollectionID: "age-of-rust", + TokenID: "54277541829991970107421667568590323026590803461896874578610080514640537714688", + ContractAddress: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + Category: "Age of Rust", + ImageUrl: "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", + ExternalLink: "https://opensea.io/", + ProviderLink: "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688", + Type: "ERC1155", + Description: "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", + Coin: 60, + Name: "Rustbits", } -func TestNormalizeCollectible(t *testing.T) { - var collectible []Collectible - err := json.Unmarshal([]byte(collectibleSrc), &collectible) +func TestNormalizeCollectibleV4(t *testing.T) { + var collectibles []Collectible + err := json.Unmarshal([]byte(collectibleSrcV4), &collectibles) assert.Nil(t, err) - page := NormalizeCollectiblePage(&collectibleCollectionDst, collectible, coin.ETH) + page := NormalizeCollectiblePage(collectibles, coin.ETH) assert.Equal(t, len(page), 1, "collectible could not be normalized") - expected := blockatlas.CollectiblePage{collectibleDst} + expected := blockatlas.CollectiblePage{collectibleDstV4} assert.Equal(t, page, expected, "collectible don't equal") } - -var c1 = Collection{ - Slug: "enjin", - Contracts: []PrimaryAssetContract{{ - Address: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - }}, -} -var c2 = Collection{ - Slug: "cryptokitties", - Contracts: []PrimaryAssetContract{{ - Address: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }}, -} -var c3 = Collection{ - Slug: "age-of-rust", - Contracts: []PrimaryAssetContract{{ - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - }}, -} - -func TestSearchCollection(t *testing.T) { - tests := []struct { - collections []Collection - collectibleID string - result *Collection - }{ - {[]Collection{c1, c2, c3}, "enjin", &c1}, - {[]Collection{c1, c2, c3}, "cryptokitties", &c2}, - {[]Collection{c1, c2}, "age-of-rust", nil}, - {[]Collection{c1, c2, c3}, "age-of-rust", &c3}, - {[]Collection{c1, c2}, "cryptokitties", &c2}, - {[]Collection{c1}, "age-of-rust", nil}, - {[]Collection{c1, c3}, "enjin", &c1}, - } - for i, tt := range tests { - t.Run(fmt.Sprintf("searchCollection %d", i), func(t *testing.T) { - s := searchCollection(tt.collections, tt.collectibleID) - assert.EqualValues(t, s, tt.result) - }) - } - -} - -func TestNormalizeSupportedContracts(t *testing.T) { - var contracts []PrimaryAssetContract - err := json.Unmarshal([]byte(rawAssetContracts), &contracts) - assert.Nil(t, err) - var collection = Collection{} - collection.Contracts = contracts - normalizeSupportedContracts(&collection) - assert.Equal(t, len(collection.Contracts), 2, "normalizeSupportedContracts with incorrect len") - var expectedContracts []PrimaryAssetContract - err = json.Unmarshal([]byte(rawAssetContractsExpected), &expectedContracts) - assert.Nil(t, err) - assert.Equal(t, collection.Contracts, expectedContracts, "normalizeSupportedContracts expectedContracts") -} - -const rawAssetContracts = `[ - { - "address": "0xee85966b4974d3c6f71a2779cc3b6f53afbc2b68", - "asset_contract_type": "fungible", - "created_date": "2019-10-16T07:36:16.102163", - "name": "Rare Chest", - "nft_version": null, - "opensea_version": null, - "owner": 1610615, - "schema_name": "ERC20", - "symbol": "", - "total_supply": "1", - "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - }, - { - "address": "0x20d4cec36528e1c4563c1bfbe3de06aba70b22b4", - "asset_contract_type": "fungible", - "created_date": "2019-10-16T08:06:42.727997", - "name": "Legendary Chest", - "nft_version": null, - "opensea_version": null, - "owner": 1610615, - "schema_name": "ERC20", - "symbol": "", - "total_supply": "1", - "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - }, - { - "address": "0x0e3a2a1f2146d86a604adc220b4967a898d7fe07", - "asset_contract_type": "non-fungible", - "created_date": "2019-11-01T06:39:04.363034", - "name": "Gods Unchained Cards", - "nft_version": "3.0", - "opensea_version": null, - "owner": 1691695, - "schema_name": "ERC721", - "symbol": "", - "total_supply": "1", - "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - }, - { - "address": "0x564cb55c655f727b61d9baf258b547ca04e9e548", - "asset_contract_type": "non-fungible", - "created_date": "2019-10-29T12:28:37.643714", - "name": "Gods Unchained", - "nft_version": "3.0", - "opensea_version": null, - "owner": 1691695, - "schema_name": "ERC721", - "symbol": "", - "total_supply": "205", - "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - } -]` - -const rawAssetContractsExpected = `[{ - "address": "0x0e3a2a1f2146d86a604adc220b4967a898d7fe07", - "asset_contract_type": "non-fungible", - "created_date": "2019-11-01T06:39:04.363034", - "name": "Gods Unchained Cards", - "nft_version": "3.0", - "opensea_version": null, - "owner": 1691695, - "schema_name": "ERC721", - "symbol": "", - "total_supply": "1", - "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - }, - { - "address": "0x564cb55c655f727b61d9baf258b547ca04e9e548", - "asset_contract_type": "non-fungible", - "created_date": "2019-10-29T12:28:37.643714", - "name": "Gods Unchained", - "nft_version": "3.0", - "opensea_version": null, - "owner": 1691695, - "schema_name": "ERC721", - "symbol": "", - "total_supply": "205", - "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - } -]` diff --git a/platform/ethereum/collection_v4.go b/platform/ethereum/collection_v4.go deleted file mode 100644 index 2eed5376a..000000000 --- a/platform/ethereum/collection_v4.go +++ /dev/null @@ -1,73 +0,0 @@ -package ethereum - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "strings" -) - -func (p *Platform) GetCollectionsV4(owner string) (blockatlas.CollectionPage, error) { - collections, err := p.collectionsClient.GetCollections(owner) - if err != nil { - return nil, err - } - return NormalizeCollectionsV4(collections, p.CoinIndex, owner), nil -} - -func (p *Platform) GetCollectiblesV4(owner, collectibleID string) (blockatlas.CollectiblePage, error) { - items, err := p.collectionsClient.GetCollectiblesV4(owner, collectibleID) - if err != nil { - return nil, err - } - return NormalizeCollectiblePageV4(items, p.CoinIndex), nil -} - -func NormalizeCollectionsV4(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { - for _, collection := range collections { - item := NormalizeCollectionV4(collection, coinIndex, owner) - page = append(page, item) - } - return page -} - -func NormalizeCollectionV4(c Collection, coinIndex uint, owner string) blockatlas.Collection { - return blockatlas.Collection{ - Name: c.Name, - Slug: c.Slug, - ImageUrl: c.ImageUrl, - Description: c.Description, - ExternalLink: c.ExternalUrl, - Total: int(c.Total.Int64()), - Id: c.Slug, - Address: owner, - Coin: coinIndex, - } -} - -func NormalizeCollectiblePageV4(collectibles []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { - for _, collectible := range collectibles { - item := NormalizeCollectibleV4(collectible, coinIndex) - if _, ok := supportedTypes[item.Type]; ok { - page = append(page, item) - } - } - return page -} - -func NormalizeCollectibleV4(a Collectible, coinIndex uint) blockatlas.Collectible { - id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") - return blockatlas.Collectible{ - ID: id, - CollectionID: a.Collection.Slug, - TokenID: a.TokenId, - ContractAddress: a.AssetContract.Address, - Name: a.Name, - Category: a.Collection.Name, - ImageUrl: a.ImagePreviewUrl, - ProviderLink: a.Permalink, - ExternalLink: a.Collection.ExternalLink, - Type: a.AssetContract.Type, - Description: a.Description, - Coin: coinIndex, - Version: a.AssetContract.Version, - } -} diff --git a/platform/ethereum/collection_v4_test.go b/platform/ethereum/collection_v4_test.go deleted file mode 100644 index ed7421610..000000000 --- a/platform/ethereum/collection_v4_test.go +++ /dev/null @@ -1,337 +0,0 @@ -package ethereum - -import ( - "encoding/json" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" -) - -const collectionsOwnerV4 = "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" - -const collectionsSrcV4 = ` -[ - { - "primary_asset_contracts":[ - { - "address":"0x06012c8cf97bead5deae237070f9587f8e7a266d", - "name":"CryptoKitties", - "symbol":"CKITTY", - "description":"CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - "external_link":"https://www.cryptokitties.co/", - "nft_version":"1.0", - "schema_name":"ERC721", - "display_data":{ - "images":[ - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/564155.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/546630.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/441529.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/552435.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/524748.png", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/540800.svg" - ], - "card_display_style":"padded" - }, - "image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png" - } - ], - "name":"CryptoKitties", - "slug":"cryptokitties", - "image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", - "description":"CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - "external_url":"https://www.cryptokitties.co/", - "featured_image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556589429.png", - "created_date":"2019-04-26T22:13:04.207050", - "owned_asset_count":3 - }, - { - "primary_asset_contracts":[ - { - "address":"0xfaafdc07907ff5120a76b34b731b278c38d6043c", - "name":"Enjin", - "symbol":"", - "description":"", - "external_link":null, - "nft_version":null, - "schema_name":"ERC1155", - "display_data":{ - - }, - "owner":null, - "created_date":"2019-08-02T23:43:14.666153", - "asset_contract_type":"semi-fungible" - } - ], - "name":"Age of Rust", - "slug":"age-of-rust", - "image_url":"https://storage.opensea.io/age-of-rust-1561960816.jpg", - "description":"Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", - "external_url":"https://www.ageofrust.games/", - "featured_image_url":null, - "created_date":"2019-09-03T02:35:56.063685", - "owned_asset_count":1 - }, - { - "primary_asset_contracts":[ - { - "address":"0xee85966b4974d3c6f71a2779cc3b6f53afbc2b68", - "asset_contract_type":"fungible", - "created_date":"2019-10-16T07:36:16.102163", - "name":"Rare Chest", - "nft_version":null, - "opensea_version":null, - "owner":1610615, - "schema_name":"ERC20", - "symbol":"", - "total_supply":"1", - "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat":false, - "dev_buyer_fee_basis_points":0, - "dev_seller_fee_basis_points":0, - "only_proxied_transfers":false, - "opensea_buyer_fee_basis_points":0, - "opensea_seller_fee_basis_points":250, - "buyer_fee_basis_points":0, - "seller_fee_basis_points":250, - "payout_address":null - }, - { - "address":"0x20d4cec36528e1c4563c1bfbe3de06aba70b22b4", - "asset_contract_type":"fungible", - "created_date":"2019-10-16T08:06:42.727997", - "name":"Legendary Chest", - "nft_version":null, - "opensea_version":null, - "owner":1610615, - "schema_name":"ERC20", - "symbol":"", - "total_supply":"1", - "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat":false, - "dev_buyer_fee_basis_points":0, - "dev_seller_fee_basis_points":0, - "only_proxied_transfers":false, - "opensea_buyer_fee_basis_points":0, - "opensea_seller_fee_basis_points":250, - "buyer_fee_basis_points":0, - "seller_fee_basis_points":250, - "payout_address":null - }, - { - "address":"0x0e3a2a1f2146d86a604adc220b4967a898d7fe07", - "asset_contract_type":"non-fungible", - "created_date":"2019-11-01T06:39:04.363034", - "name":"Gods Unchained Cards", - "nft_version":"3.0", - "opensea_version":null, - "owner":1691695, - "schema_name":"ERC721", - "symbol":"", - "total_supply":"1", - "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat":false, - "dev_buyer_fee_basis_points":0, - "dev_seller_fee_basis_points":0, - "only_proxied_transfers":false, - "opensea_buyer_fee_basis_points":0, - "opensea_seller_fee_basis_points":250, - "buyer_fee_basis_points":0, - "seller_fee_basis_points":250, - "payout_address":null - }, - { - "address":"0x564cb55c655f727b61d9baf258b547ca04e9e548", - "asset_contract_type":"non-fungible", - "created_date":"2019-10-29T12:28:37.643714", - "name":"Gods Unchained", - "nft_version":"3.0", - "opensea_version":null, - "owner":1691695, - "schema_name":"ERC721", - "symbol":"", - "total_supply":"205", - "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat":false, - "dev_buyer_fee_basis_points":0, - "dev_seller_fee_basis_points":0, - "only_proxied_transfers":false, - "opensea_buyer_fee_basis_points":0, - "opensea_seller_fee_basis_points":250, - "buyer_fee_basis_points":0, - "seller_fee_basis_points":250, - "payout_address":null - } - ], - "traits":{ - "mana":{ - "min":1, - "max":18 - }, - "health":{ - "min":1, - "max":16 - }, - "attack":{ - "min":1, - "max":16 - } - }, - "stats":{ - "seven_day_volume":270.564697067863, - "seven_day_change":-0.014179906699531201, - "total_volume":11825.0384171324, - "count":6835331, - "num_owners":10791, - "market_cap":150892.14138332763, - "average_price":0.0396514694030496, - "items_sold":298233 - }, - "banner_image_url":null, - "chat_url":null, - "created_date":"2019-11-13T03:01:42.051246", - "default_to_fiat":false, - "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "dev_buyer_fee_basis_points":"0", - "dev_seller_fee_basis_points":"0", - "display_data":{ - "images":[ - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/25233.png", - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/152875.png", - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/25669.png", - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9237.png", - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9228.png", - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9231.png" - ], - "card_display_style":"contain" - }, - "external_url":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "featured":true, - "featured_image_url":"https://storage.opensea.io/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab-featured-1556589419.png", - "hidden":false, - "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "is_subject_to_whitelist":false, - "large_image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ", - "name":"Gods Unchained", - "only_proxied_transfers":false, - "opensea_buyer_fee_basis_points":"0", - "opensea_seller_fee_basis_points":"250", - "payout_address":null, - "require_email":false, - "short_description":null, - "slug":"gods-unchained", - "wiki_url":null, - "owned_asset_count":535 - } -] -` - -var collection1DstV4 = blockatlas.Collection{ - Name: "CryptoKitties", - Symbol: "", - Slug: "cryptokitties", - ImageUrl: "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", - Description: "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - ExternalLink: "https://www.cryptokitties.co/", - Total: 3, - Id: "cryptokitties", - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - Coin: 60, -} - -var collection2DstV4 = blockatlas.Collection{ - Name: "Age of Rust", - Symbol: "", - Slug: "age-of-rust", - ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", - Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", - ExternalLink: "https://www.ageofrust.games/", - Total: 1, - Id: "age-of-rust", - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - Coin: 60, -} - -var collection3DstV4 = blockatlas.Collection{ - Name: "Gods Unchained", - Symbol: "", - Slug: "gods-unchained", - ImageUrl: "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - Description: "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - ExternalLink: "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - Total: 535, - Id: "gods-unchained", - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - Coin: 60, -} - -func TestNormalizeCollectionV4(t *testing.T) { - var collections []Collection - err := json.Unmarshal([]byte(collectionsSrcV4), &collections) - assert.Nil(t, err) - page := NormalizeCollectionsV4(collections, coin.ETH, collectionsOwnerV4) - assert.Equal(t, 3, len(page), "collections could not be normalized") - expected := blockatlas.CollectionPage{collection1DstV4, collection2DstV4, collection3DstV4} - assert.Equal(t, page, expected, "collections don't equal") -} - -const collectibleSrcV4 = ` -[ - { - "token_id": "54277541829991970107421667568590323026590803461896874578610080514640537714688", - "image_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858806.png", - "image_preview_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", - "name": "Rustbits", - "description": "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", - "external_link": "", - "asset_contract": { - "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - "name": "Enjin", - "external_link": null, - "nft_version": null, - "schema_name": "ERC1155", - "display_data": {} - }, - "collection": { - "slug": "age-of-rust", - "name": "Age of Rust", - "external_url": "https://opensea.io/" - }, - "permalink": "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688" - } -] -` - -var collectibleDstV4 = blockatlas.Collectible{ - ID: "0xfaafdc07907ff5120a76b34b731b278c38d6043c-54277541829991970107421667568590323026590803461896874578610080514640537714688", - CollectionID: "age-of-rust", - TokenID: "54277541829991970107421667568590323026590803461896874578610080514640537714688", - CategoryContract: "", - ContractAddress: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - Category: "Age of Rust", - ImageUrl: "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", - ExternalLink: "https://opensea.io/", - ProviderLink: "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688", - Type: "ERC1155", - Description: "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", - Coin: 60, - Name: "Rustbits", -} - -func TestNormalizeCollectibleV4(t *testing.T) { - var collectibles []Collectible - err := json.Unmarshal([]byte(collectibleSrcV4), &collectibles) - assert.Nil(t, err) - page := NormalizeCollectiblePageV4(collectibles, coin.ETH) - assert.Equal(t, len(page), 1, "collectible could not be normalized") - expected := blockatlas.CollectiblePage{collectibleDstV4} - assert.Equal(t, page, expected, "collectible don't equal") -} diff --git a/tests/postman/Blockatlas.postman_collection.json b/tests/postman/Blockatlas.postman_collection.json index 43860435a..884eb883d 100644 --- a/tests/postman/Blockatlas.postman_collection.json +++ b/tests/postman/Blockatlas.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "60e7e382-2f40-487f-a291-3e62daadadd8", + "_postman_id": "7c16faaa-629e-4a75-a8bc-2ccaacb540ff", "name": "Blockatlas", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -984,7 +984,7 @@ "name": "collection", "item": [ { - "name": "collection", + "name": "collection v4", "event": [ { "listen": "prerequest", @@ -1025,9 +1025,6 @@ " \"token_id\": {", " \"type\": \"string\"", " },", - " \"category_contract\": {", - " \"type\": \"string\"", - " },", " \"contract_address\": {", " \"type\": \"string\"", " },", @@ -1054,134 +1051,8 @@ " },", " \"name\": {", " \"type\": \"string\"", - " }", - " }", - " }", - " },", - " \"status\": {", - " \"type\": \"boolean\"", - " }", - " }", - "};", - "", - "let handler = pm.variables.get(\"handler\");", - "let address = pm.variables.get(\"address\");", - "var jsonData = pm.response.json();", - "", - "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", - " pm.response.to.have.status(200);", - " pm.response.to.be.ok;", - " pm.response.to.not.be.error;", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "", - "pm.test(handler + \" - schema is valid: \" + address, function() {", - " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", - " console.log(JSON.stringify(jsonData))", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{platform_auth}}", - "type": "text" - } - ], - "url": { - "raw": "{{host}}/v2/{{handler}}/collections/{{address}}/collection/{{collection}}", - "host": [ - "{{host}}" - ], - "path": [ - "v2", - "{{handler}}", - "collections", - "{{address}}", - "collection", - "{{collection}}" - ] - } - }, - "response": [] - }, - { - "name": "collection v4", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "7312c9e7-5330-421a-9ca8-171101050e38", - "exec": [ - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "acec8baa-0ef0-4703-ab83-c555260deffa", - "exec": [ - "var Ajv = require('ajv');", - "var ajv = new Ajv({logger: console});", - "let schema = {", - " \"type\": \"object\",", - " \"properties\": {", - " \"total\": {", - " \"type\": \"integer\"", - " },", - " \"docs\": {", - " \"type\": \"array\",", - " \"minItems\": 1,", - " \"uniqueItems\": true,", - " \"items\": {", - " \"type\": \"object\",", - " \"properties\": {", - " \"id\": {", - " \"type\": \"string\"", - " },", - " \"collection_id\": {", - " \"type\": \"string\"", - " },", - " \"token_id\": {", - " \"type\": \"string\"", - " },", - " \"category_contract\": {", - " \"type\": \"string\"", - " },", - " \"contract_address\": {", - " \"type\": \"string\"", - " },", - " \"category\": {", - " \"type\": \"string\"", - " },", - " \"image_url\": {", - " \"type\": \"string\"", " },", - " \"external_link\": {", - " \"type\": \"string\"", - " },", - " \"provider_link\": {", - " \"type\": \"string\"", - " },", - " \"type\": {", - " \"type\": \"string\"", - " },", - " \"description\": {", - " \"type\": \"string\"", - " },", - " \"coin\": {", - " \"type\": \"integer\"", - " },", - " \"name\": {", + " \"nft_version\": {", " \"type\": \"string\"", " }", " }", @@ -1225,12 +1096,12 @@ } ], "url": { - "raw": "{{host}}/v2/{{handler}}/collections/{{address}}/collection/{{collection}}", + "raw": "{{host}}/v4/{{handler}}/collections/{{address}}/collection/{{collection}}", "host": [ "{{host}}" ], "path": [ - "v2", + "v4", "{{handler}}", "collections", "{{address}}", @@ -1242,7 +1113,7 @@ "response": [] }, { - "name": "collections", + "name": "collections batch v4", "event": [ { "listen": "prerequest", @@ -1280,12 +1151,6 @@ " \"name\": {", " \"type\": \"string\"", " },", - " \"symbol\": {", - " \"type\": \"string\"", - " },", - " \"slug\": {", - " \"type\": \"string\"", - " },", " \"image_url\": {", " \"type\": \"string\"", " },", @@ -1295,415 +1160,9 @@ " \"total\": {", " \"type\": \"integer\"", " },", - " \"category_address\": {", - " \"type\": \"string\"", - " },", " \"address\": {", " \"type\": \"string\"", " },", - " \"nft_version\": {", - " \"type\": \"string\"", - " },", - " \"coin\": {", - " \"type\": \"integer\"", - " },", - " \"type\": {", - " \"type\": \"string\"", - " }", - " }", - " }", - " },", - " \"status\": {", - " \"type\": \"boolean\"", - " }", - " }", - "};", - "", - "let handler = pm.variables.get(\"handler\");", - "let address = pm.variables.get(\"address\");", - "var jsonData = pm.response.json();", - "", - "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", - " pm.response.to.have.status(200);", - " pm.response.to.be.ok;", - " pm.response.to.not.be.error;", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "", - "pm.test(handler + \" - schema is valid: \" + address, function() {", - " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", - " console.log(JSON.stringify(jsonData))", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{platform_auth}}", - "type": "text" - } - ], - "url": { - "raw": "{{host}}/v2/{{handler}}/collections/{{address}}", - "host": [ - "{{host}}" - ], - "path": [ - "v2", - "{{handler}}", - "collections", - "{{address}}" - ] - } - }, - "response": [] - }, - { - "name": "collections batch", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "7312c9e7-5330-421a-9ca8-171101050e38", - "exec": [ - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "acec8baa-0ef0-4703-ab83-c555260deffa", - "exec": [ - "var Ajv = require('ajv');", - "var ajv = new Ajv({logger: console});", - "let schema = {", - " \"type\": \"object\",", - " \"properties\": {", - " \"total\": {", - " \"type\": \"integer\"", - " },", - " \"docs\": {", - " \"type\": \"array\",", - " \"minItems\": 1,", - " \"uniqueItems\": true,", - " \"items\": {", - " \"type\": \"object\",", - " \"properties\": {", - " \"id\": {", - " \"type\": \"string\"", - " },", - " \"name\": {", - " \"type\": \"string\"", - " },", - " \"symbol\": {", - " \"type\": \"string\"", - " },", - " \"slug\": {", - " \"type\": \"string\"", - " },", - " \"image_url\": {", - " \"type\": \"string\"", - " },", - " \"external_link\": {", - " \"type\": \"string\"", - " },", - " \"total\": {", - " \"type\": \"integer\"", - " },", - " \"category_address\": {", - " \"type\": \"string\"", - " },", - " \"address\": {", - " \"type\": \"string\"", - " },", - " \"nft_version\": {", - " \"type\": \"string\"", - " },", - " \"coin\": {", - " \"type\": \"integer\"", - " },", - " \"type\": {", - " \"type\": \"string\"", - " }", - " }", - " }", - " },", - " \"status\": {", - " \"type\": \"boolean\"", - " }", - " }", - "};", - "", - "let handler = pm.variables.get(\"handler\");", - "let address = pm.variables.get(\"address\");", - "var jsonData = pm.response.json();", - "", - "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", - " pm.response.to.have.status(200);", - " pm.response.to.be.ok;", - " pm.response.to.not.be.error;", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "", - "pm.test(handler + \" - schema is valid: \" + address, function() {", - " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", - " console.log(JSON.stringify(jsonData))", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{platform_auth}}", - "type": "text" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/json", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n\t\"{{coin}}\": [\"{{address}}\"]\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{host}}/v2/collectibles/categories", - "host": [ - "{{host}}" - ], - "path": [ - "v2", - "collectibles", - "categories" - ] - } - }, - "response": [] - }, - { - "name": "collections batch v3 ", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "7312c9e7-5330-421a-9ca8-171101050e38", - "exec": [ - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "acec8baa-0ef0-4703-ab83-c555260deffa", - "exec": [ - "var Ajv = require('ajv');", - "var ajv = new Ajv({logger: console});", - "let schema = {", - " \"type\": \"object\",", - " \"properties\": {", - " \"total\": {", - " \"type\": \"integer\"", - " },", - " \"docs\": {", - " \"type\": \"array\",", - " \"minItems\": 1,", - " \"uniqueItems\": true,", - " \"items\": {", - " \"type\": \"object\",", - " \"properties\": {", - " \"id\": {", - " \"type\": \"string\"", - " },", - " \"name\": {", - " \"type\": \"string\"", - " },", - " \"symbol\": {", - " \"type\": \"string\"", - " },", - " \"slug\": {", - " \"type\": \"string\"", - " },", - " \"image_url\": {", - " \"type\": \"string\"", - " },", - " \"external_link\": {", - " \"type\": \"string\"", - " },", - " \"total\": {", - " \"type\": \"integer\"", - " },", - " \"category_address\": {", - " \"type\": \"string\"", - " },", - " \"address\": {", - " \"type\": \"string\"", - " },", - " \"nft_version\": {", - " \"type\": \"string\"", - " },", - " \"coin\": {", - " \"type\": \"integer\"", - " },", - " \"type\": {", - " \"type\": \"string\"", - " }", - " }", - " }", - " },", - " \"status\": {", - " \"type\": \"boolean\"", - " }", - " }", - "};", - "", - "let handler = pm.variables.get(\"handler\");", - "let address = pm.variables.get(\"address\");", - "var jsonData = pm.response.json();", - "", - "pm.test(handler + \" - response must be valid and have a body: \" + address, function () {", - " pm.response.to.have.status(200);", - " pm.response.to.be.ok;", - " pm.response.to.not.be.error;", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "", - "pm.test(handler + \" - schema is valid: \" + address, function() {", - " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", - " console.log(JSON.stringify(jsonData))", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{platform_auth}}", - "type": "text" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/json", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n\t\"{{coin}}\": [\"{{address}}\"]\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{host}}/v3/collectibles/categories", - "host": [ - "{{host}}" - ], - "path": [ - "v3", - "collectibles", - "categories" - ] - } - }, - "response": [] - }, - { - "name": "collections batch v4", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "7312c9e7-5330-421a-9ca8-171101050e38", - "exec": [ - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "acec8baa-0ef0-4703-ab83-c555260deffa", - "exec": [ - "var Ajv = require('ajv');", - "var ajv = new Ajv({logger: console});", - "let schema = {", - " \"type\": \"object\",", - " \"properties\": {", - " \"total\": {", - " \"type\": \"integer\"", - " },", - " \"docs\": {", - " \"type\": \"array\",", - " \"minItems\": 1,", - " \"uniqueItems\": true,", - " \"items\": {", - " \"type\": \"object\",", - " \"properties\": {", - " \"id\": {", - " \"type\": \"string\"", - " },", - " \"name\": {", - " \"type\": \"string\"", - " },", - " \"symbol\": {", - " \"type\": \"string\"", - " },", - " \"slug\": {", - " \"type\": \"string\"", - " },", - " \"image_url\": {", - " \"type\": \"string\"", - " },", - " \"external_link\": {", - " \"type\": \"string\"", - " },", - " \"total\": {", - " \"type\": \"integer\"", - " },", - " \"category_address\": {", - " \"type\": \"string\"", - " },", - " \"address\": {", - " \"type\": \"string\"", - " },", - " \"nft_version\": {", - " \"type\": \"string\"", - " },", " \"coin\": {", " \"type\": \"integer\"", " },", @@ -1766,12 +1225,12 @@ } }, "url": { - "raw": "{{host}}/v3/collectibles/categories", + "raw": "{{host}}/v4/collectibles/categories", "host": [ "{{host}}" ], "path": [ - "v3", + "v4", "collectibles", "categories" ] @@ -2587,29 +2046,29 @@ ], "variable": [ { - "id": "ad2326b7-fb90-4b11-a1e3-dfe8ea3aae65", + "id": "c6d3b134-d68f-4747-b5c5-a687412f2166", "key": "host", "value": "http://localhost:8420", "type": "string" }, { - "id": "7ae1014f-44e1-4c16-aacd-2be971ee15ef", + "id": "cfde5bdb-eecf-472c-b1bf-d944a63befff", "key": "observer_auth", "value": "test", "type": "string" }, { - "id": "0d3dcacb-5b63-409a-8150-9e06d24e1eb4", + "id": "1455449b-6372-4c16-81d9-ed93ab4aafd7", "key": "market_auth", "value": "", "type": "string" }, { - "id": "c42f8723-ad35-45ea-9dd2-066ced0780bc", + "id": "4180368d-8afe-4432-8ecb-48db2f778a72", "key": "platform_auth", "value": "", "type": "string" } ], "protocolProfileBehavior": {} -} +} \ No newline at end of file diff --git a/tests/postman/collection_data.json b/tests/postman/collection_data.json index 0213e2d11..4e09b0163 100644 --- a/tests/postman/collection_data.json +++ b/tests/postman/collection_data.json @@ -2,7 +2,7 @@ { "coin": 60, "handler": "ethereum", - "address": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "collection": "0x35b7838dd7507ada69610397a85310ae0abd5034" + "address": "0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d", + "collection": "unstoppable-domains" } ] From dfef17044071ecec47ed8ec1585635ef46022233 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 8 Apr 2020 06:33:26 +0300 Subject: [PATCH 237/506] Refactor API and define error response (#1015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Init * Remove v2, сollections route (#989) * REmove v2 collections route * New swagger and postman * Fix swagger, remove v2, v3 collections also * Remove outdated fields, collection methods, change collection interface, update postman tests * Bring back v3 for android * Bring back v3 for android client Co-authored-by: Nick Kozlov * Define Error Response * Refactor http api * Init * Define Error Response * Refactor http api * Rebase with master * Cleanup * Requested changes Co-authored-by: mykola.eth <3277207+kolya182@users.noreply.github.com> --- api/api.go | 20 + api/collection.go | 184 -------- api/domain.go | 95 ---- api/endpoint/basic.go | 23 + api/endpoint/collection.go | 114 +++++ api/endpoint/domain.go | 82 ++++ api/endpoint/staking.go | 168 +++++++ api/endpoint/token.go | 34 ++ api/endpoint/transaction.go | 89 ++++ .../gincache => api/middleware}/cache.go | 6 +- .../gincache => api/middleware}/cache_test.go | 22 +- .../middleware.go => api/middleware/cors.go | 29 +- .../middleware}/reverse_proxy.go | 2 +- api/model/model.go | 31 ++ api/registry.go | 141 ++++++ api/routes.go | 105 ----- api/staking.go | 192 -------- api/transaction.go | 141 ------ docs/swagger.yaml | 418 +++++++++--------- internal/init.go | 8 +- pkg/ginutils/response.go | 66 --- 21 files changed, 930 insertions(+), 1040 deletions(-) create mode 100644 api/api.go delete mode 100644 api/collection.go delete mode 100644 api/domain.go create mode 100644 api/endpoint/basic.go create mode 100644 api/endpoint/collection.go create mode 100644 api/endpoint/domain.go create mode 100644 api/endpoint/staking.go create mode 100644 api/endpoint/token.go create mode 100644 api/endpoint/transaction.go rename {pkg/ginutils/gincache => api/middleware}/cache.go (97%) rename {pkg/ginutils/gincache => api/middleware}/cache_test.go (73%) rename pkg/ginutils/middleware.go => api/middleware/cors.go (51%) rename {pkg/ginutils => api/middleware}/reverse_proxy.go (95%) create mode 100644 api/model/model.go create mode 100644 api/registry.go delete mode 100644 api/routes.go delete mode 100644 api/staking.go delete mode 100644 api/transaction.go delete mode 100644 pkg/ginutils/response.go diff --git a/api/api.go b/api/api.go new file mode 100644 index 000000000..22c4ea912 --- /dev/null +++ b/api/api.go @@ -0,0 +1,20 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/platform" +) + +func SetupPlatformAPI(root gin.IRouter) { + for _, api := range platform.Platforms { + RegisterCollectionsAPI(root, api) + RegisterTransactionsAPI(root, api) + RegisterCustomAPI(root, api) + RegisterTokensAPI(root, api) + RegisterStakeAPI(root, api) + } + + RegisterBatchAPI(root) + RegisterDomainAPI(root) + RegisterBasicAPI(root) +} diff --git a/api/collection.go b/api/collection.go deleted file mode 100644 index 4c5816477..000000000 --- a/api/collection.go +++ /dev/null @@ -1,184 +0,0 @@ -package api - -import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/platform" - "strconv" -) - -// @Summary Get Collections -// @ID collections_v3 -// @Description Get all collections from the address -// @Accept json -// @Produce json -// @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 -// @Failure 500 {object} ginutils.ApiError -// @Router /v3/{coin}/collections/{address} [get] -func makeCollectionsRoute(router gin.IRouter, api blockatlas.Platform) { - var collectionAPI blockatlas.CollectionAPI - collectionAPI, _ = api.(blockatlas.CollectionAPI) - - if collectionAPI == nil { - return - } - - router.GET("/collections/:owner", func(c *gin.Context) { - collections, err := collectionAPI.GetCollectionsV3(c.Param("owner")) - if err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - ginutils.RenderSuccess(c, collections) - }) -} - -// @Summary Get Collection -// @ID collection_v3 -// @Description Get a collection from the address -// @Accept json -// @Produce json -// @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) -// @Success 200 {object} blockatlas.CollectionPage -// @Failure 500 {object} ginutils.ApiError -// @Router /v3/{coin}/collections/{owner}/collection/{collection_id} [get] -func makeCollectionRoute(router gin.IRouter, api blockatlas.Platform) { - var collectionAPI blockatlas.CollectionAPI - collectionAPI, _ = api.(blockatlas.CollectionAPI) - - if collectionAPI == nil { - return - } - - router.GET("/collections/:owner/collection/:collection_id", func(c *gin.Context) { - collectibles, err := collectionAPI.GetCollectiblesV3(c.Param("owner"), c.Param("collection_id")) - if err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - ginutils.RenderSuccess(c, collectibles) - }) -} - -// @Description Get collection categories -// @ID collection_categories_v3 -// @Summary Get list of collections from a specific coin and addresses -// @Accept json -// @Produce json -// @Tags Collections -// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) -// @Success 200 {object} blockatlas.DocsResponse -// @Router /v3/collectibles/categories [post] -func makeCategoriesBatchRoute(router gin.IRouter) { - router.POST("/collectibles/categories", func(c *gin.Context) { - var reqs map[string][]string - if err := c.BindJSON(&reqs); err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - batch := make(blockatlas.CollectionPageV3, 0) - for key, addresses := range reqs { - coinId, err := strconv.Atoi(key) - if err != nil { - continue - } - p, ok := platform.CollectionAPIs[uint(coinId)] - if !ok { - continue - } - for _, address := range addresses { - collections, err := p.GetCollectionsV3(address) - if err != nil { - continue - } - batch = append(batch, collections...) - } - } - ginutils.RenderSuccess(c, batch) - }) -} - -// @Description Get collection categories -// @ID collection_categories_v4 -// @Summary Get list of collections from a specific coin and addresses -// @Accept json -// @Produce json -// @Tags Collections -// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) -// @Success 200 {object} blockatlas.DocsResponse -// @Router /v4/collectibles/categories [post] -func makeCategoriesBatchRouteV4(router gin.IRouter) { - router.POST("/collectibles/categories", func(c *gin.Context) { - var reqs map[string][]string - if err := c.BindJSON(&reqs); err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - batch := make(blockatlas.CollectionPage, 0) - for key, addresses := range reqs { - coinId, err := strconv.Atoi(key) - if err != nil { - continue - } - p, ok := platform.CollectionAPIs[uint(coinId)] - if !ok { - continue - } - for _, address := range addresses { - collections, err := p.GetCollections(address) - if err != nil { - continue - } - batch = append(batch, collections...) - } - } - ginutils.RenderSuccess(c, batch) - }) -} - -// @Summary Get Collection -// @ID collection_v4 -// @Description Get a collection from the address -// @Accept json -// @Produce json -// @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) -// @Success 200 {object} blockatlas.CollectionPage -// @Failure 500 {object} ginutils.ApiError -// @Router /v4/{coin}/collections/{owner}/collection/{collection_id} [get] -func makeCollectionRouteV4(router gin.IRouter, api blockatlas.Platform) { - var collectionAPI blockatlas.CollectionAPI - collectionAPI, _ = api.(blockatlas.CollectionAPI) - - if collectionAPI == nil { - return - } - - router.GET("/collections/:owner/collection/:collection_id", func(c *gin.Context) { - collectibles, err := collectionAPI.GetCollectibles(c.Param("owner"), c.Param("collection_id")) - if err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - ginutils.RenderSuccess(c, collectibles) - }) -} - -func emptyPage(c *gin.Context) { - var page blockatlas.TxPage - ginutils.RenderSuccess(c, &page) -} diff --git a/api/domain.go b/api/domain.go deleted file mode 100644 index 7c720db36..000000000 --- a/api/domain.go +++ /dev/null @@ -1,95 +0,0 @@ -package api - -import ( - "net/http" - "strconv" - "strings" - - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/services/domains" - - "github.com/trustwallet/blockatlas/pkg/ginutils" - - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) - -type LookupBatchPage []blockatlas.Resolved - -// @Summary Lookup .eth / .zil addresses -// @ID lookup -// @Description Lookup ENS/ZNS to find registered addresses -// @Produce json -// @Tags Naming -// @Param name query string empty "string name" -// @Param coin query string 60 "string coin" -// @Success 200 {object} blockatlas.Resolved -// @Failure 500 {object} ginutils.ApiError -// @Router /ns/lookup [get] -func MakeLookupRoute(router gin.IRouter) { - router.GET("/lookup", func(c *gin.Context) { - name := c.Query("name") - coinQuery := c.Query("coin") - coin, err := strconv.ParseUint(coinQuery, 10, 64) - if err != nil { - ginutils.RenderError(c, http.StatusBadRequest, "coin query is invalid") - return - } - - result, err := domains.HandleLookup(name, []uint64{coin}) - if err != nil { - ginutils.RenderError(c, http.StatusBadRequest, err.Error()) - return - } - if len(result) == 0 { - ginutils.RenderError(c, http.StatusBadRequest, errors.E("name not found", errors.Params{"coin": coin, "name": name}).Error()) - return - } - ginutils.RenderSuccess(c, result[0]) - }) -} - -// @Summary Lookup .eth / .zil addresses -// @ID lookup -// @Description Lookup ENS/ZNS to find registered addresses for multiple coins -// @Produce json -// @Tags Naming -// @Param name query string empty "string name" -// @Param coins query string true "List of coins" -// @Success 200 {array} blockatlas.Resolved -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/ns/lookup [get] -func MakeLookupBatchRoute(router gin.IRouter) { - router.GET("/lookup", func(c *gin.Context) { - name := c.Query("name") - coinsRaw := strings.Split(c.Query("coins"), ",") - coins, err := sliceAtoi(coinsRaw) - if err != nil { - ginutils.RenderError(c, http.StatusBadRequest, "coin query is invalid") - return - } - - result, err := domains.HandleLookup(name, coins) - if err != nil { - ginutils.RenderError(c, http.StatusBadRequest, err.Error()) - return - } - if len(result) == 0 { - ginutils.RenderError(c, http.StatusBadRequest, errors.E("name not found", errors.Params{"name": name}).Error()) - return - } - ginutils.RenderSuccess(c, result) - }) -} - -func sliceAtoi(sa []string) ([]uint64, error) { - si := make([]uint64, 0, len(sa)) - for _, a := range sa { - i, err := strconv.ParseUint(a, 10, 64) - if err != nil { - return si, err - } - si = append(si, i) - } - return si, nil -} diff --git a/api/endpoint/basic.go b/api/endpoint/basic.go new file mode 100644 index 000000000..dbf68d6de --- /dev/null +++ b/api/endpoint/basic.go @@ -0,0 +1,23 @@ +package endpoint + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "net/http" +) + +func GetRoot(c *gin.Context) { c.JSON(http.StatusOK, "Welcome to the Block Atlas API") } + +func GetStatus(c *gin.Context) { + c.JSON(http.StatusOK, map[string]interface{}{ + "status": true, + "build": internal.Build, + "date": internal.Date, + }) +} + +func EmptyPage(c *gin.Context) { + var page blockatlas.TxPage + c.JSON(http.StatusOK, &page) +} diff --git a/api/endpoint/collection.go b/api/endpoint/collection.go new file mode 100644 index 000000000..a7fc3851d --- /dev/null +++ b/api/endpoint/collection.go @@ -0,0 +1,114 @@ +package endpoint + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/api/model" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "net/http" + "strconv" +) + +// @Summary Get Collection +// @ID collection_v4 +// @Description Get a collection from the address +// @Accept json +// @Produce json +// @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) +// @Success 200 {object} blockatlas.CollectionPage +// @Failure 500 {object} middleware.ApiError +// @Router /v4/{coin}/collections/{owner}/collection/{collection_id} [get] +func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas.CollectionAPI) { + collectibles, err := api.GetCollectibles(c.Param("owner"), c.Param("collection_id")) + if err != nil { + c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + return + } + c.JSON(http.StatusOK, &collectibles) +} + +// @Description Get collection categories +// @ID collection_categories_v4 +// @Summary Get list of collections from a specific coin and addresses +// @Accept json +// @Produce json +// @Tags Collections +// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) +// @Success 200 {object} blockatlas.DocsResponse +// @Router /v4/collectibles/categories [post] +func GetCollectionCategoriesFromList(c *gin.Context, apis map[uint]blockatlas.CollectionAPI) { + var reqs map[string][]string + if err := c.BindJSON(&reqs); err != nil { + c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.Default, err)) + return + } + + batch := make(blockatlas.CollectionPage, 0) + for key, addresses := range reqs { + coinId, err := strconv.Atoi(key) + if err != nil { + continue + } + p, ok := apis[uint(coinId)] + if !ok { + continue + } + for _, address := range addresses { + collections, err := p.GetCollections(address) + if err != nil { + continue + } + batch = append(batch, collections...) + } + } + c.JSON(http.StatusOK, &batch) +} + +func GetCollectiblesForOwnerV3(c *gin.Context, api blockatlas.CollectionAPI) { + collections, err := api.GetCollectionsV3(c.Param("owner")) + if err != nil { + c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + return + } + + c.JSON(http.StatusOK, &collections) +} + +func GetCollectiblesForSpecificCollectionAndOwnerV3(c *gin.Context, api blockatlas.CollectionAPI) { + collectibles, err := api.GetCollectiblesV3(c.Param("owner"), c.Param("collection_id")) + if err != nil { + c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + return + } + c.JSON(http.StatusOK, &collectibles) +} + +func GetCollectionCategoriesFromListV3(c *gin.Context, apis map[uint]blockatlas.CollectionAPI) { + var reqs map[string][]string + if err := c.BindJSON(&reqs); err != nil { + c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.Default, err)) + return + } + + batch := make(blockatlas.CollectionPageV3, 0) + for key, addresses := range reqs { + coinId, err := strconv.Atoi(key) + if err != nil { + continue + } + p, ok := apis[uint(coinId)] + if !ok { + continue + } + for _, address := range addresses { + collections, err := p.GetCollectionsV3(address) + if err != nil { + continue + } + batch = append(batch, collections...) + } + } + c.JSON(http.StatusOK, &batch) +} diff --git a/api/endpoint/domain.go b/api/endpoint/domain.go new file mode 100644 index 000000000..9c4cf4b28 --- /dev/null +++ b/api/endpoint/domain.go @@ -0,0 +1,82 @@ +package endpoint + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/api/model" + "github.com/trustwallet/blockatlas/services/domains" + "net/http" + "strconv" + "strings" +) + +// @Summary Lookup .eth / .zil addresses +// @ID lookup +// @Description Lookup ENS/ZNS to find registered addresses +// @Produce json +// @Tags Naming +// @Param name query string empty "string name" +// @Param coin query string 60 "string coin" +// @Success 200 {object} blockatlas.Resolved +// @Failure 500 {object} middleware.ApiError +// @Router /ns/lookup [get] +func GetAddressByCoinAndDomain(c *gin.Context) { + name := c.Query("name") + coinQuery := c.Query("coin") + coin, err := strconv.ParseUint(coinQuery, 10, 64) + if err != nil { + c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, err)) + return + } + result, err := domains.HandleLookup(name, []uint64{coin}) + if err != nil { + c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + return + } + if len(result) == 0 { + c.JSON(http.StatusNotFound, model.CreateErrorResponse(model.RequestedDataNotFound, err)) + return + } + c.JSON(http.StatusOK, result[0]) +} + +// @Summary Lookup .eth / .zil addresses +// @ID lookup +// @Description Lookup ENS/ZNS to find registered addresses for multiple coins +// @Produce json +// @Tags Naming +// @Param name query string empty "string name" +// @Param coins query string true "List of coins" +// @Success 200 {array} blockatlas.Resolved +// @Failure 500 {object} middleware.ApiError +// @Router /v2/ns/lookup [get] +func GetAddressByCoinAndDomainBatch(c *gin.Context) { + name := c.Query("name") + coinsRaw := strings.Split(c.Query("coins"), ",") + coins, err := sliceAtoi(coinsRaw) + if err != nil { + c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, err)) + return + } + result, err := domains.HandleLookup(name, coins) + if err != nil { + c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + return + } + if len(result) == 0 { + c.JSON(http.StatusNotFound, model.CreateErrorResponse(model.RequestedDataNotFound, err)) + return + } + c.JSON(http.StatusOK, &result) +} + +func sliceAtoi(sa []string) ([]uint64, error) { + si := make([]uint64, 0, len(sa)) + for _, a := range sa { + i, err := strconv.ParseUint(a, 10, 64) + if err != nil { + return si, err + } + si = append(si, i) + } + return si, nil +} diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go new file mode 100644 index 000000000..fb0acef0e --- /dev/null +++ b/api/endpoint/staking.go @@ -0,0 +1,168 @@ +package endpoint + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/api/model" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + services "github.com/trustwallet/blockatlas/services/assets" + "net/http" +) + +type ( + AddressBatchRequest struct { + Address string `json:"address"` + CoinBatchRequest + } + + CoinBatchRequest struct { + Coin uint `json:"coin"` + } + + ENSBatchRequest struct { + Coins []uint64 `json:"coins"` + Name string `json:"name"` + } + + AddressesRequest []AddressBatchRequest + CoinsRequest []CoinBatchRequest +) + +// @Summary Get Multiple Stake Delegations +// @ID batch_delegations +// @Description Get Stake Delegations for multiple coins +// @Accept json +// @Produce json +// @Tags Staking +// @Param delegations body api.AddressesRequest true "Validators addresses and coins" +// @Success 200 {object} blockatlas.DelegationsBatchPage +// @Router /v2/staking/delegations [post] +func GetStakeDelegationsWithAllInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { + var reqs AddressesRequest + if err := c.BindJSON(&reqs); err != nil { + c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, err)) + return + } + + batch := make(blockatlas.DelegationsBatchPage, 0) + for _, r := range reqs { + requestCoin, ok := coin.Coins[r.Coin] + if !ok { + continue + } + p, ok := apis[requestCoin.Handle] + if !ok { + continue + } + delegation, err := getDelegationResponse(p, r.Address) + if err != nil { + continue + } + batch = append(batch, delegation) + } + c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &batch}) +} + +// @Summary Get Multiple Stake Delegations +// @ID batch_delegations +// @Description Get Stake Delegations for multiple coins +// @Accept json +// @Produce json +// @Tags Staking +// @Param delegations body api.AddressesRequest true "Validators addresses and coins" +// @Success 200 {object} blockatlas.DelegationsBatchPage +// @Router /v2/staking/list [post] +func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { + var reqs CoinsRequest + if err := c.BindJSON(&reqs); err != nil { + c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, err)) + return + } + + batch := make(blockatlas.StakingBatchPage, 0) + for _, r := range reqs { + requestCoin, ok := coin.Coins[r.Coin] + if !ok { + continue + } + p, ok := apis[requestCoin.Handle] + if !ok { + continue + } + staking := getStakingResponse(p) + batch = append(batch, staking) + } + c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &batch}) +} + +// @Summary Get Validators +// @ID validators +// @Description Get validators from the address +// @Accept json +// @Produce json +// @Tags Staking +// @Param coin path string true "the coin name" default(cosmos) +// @Success 200 {object} blockatlas.DocsResponse +// @Failure 500 {object} middleware.ApiError +// @Router /v2/{coin}/staking/validators [get] +func GetValidators(c *gin.Context, api blockatlas.StakeAPI) { + results, err := services.GetActiveValidators(api) + if err != nil { + c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + return + } + c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &results}) +} + +// @Summary Get Stake Delegations +// @ID delegations +// @Description Get stake delegations from the address +// @Accept json +// @Produce json +// @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 +// @Failure 500 {object} middleware.ApiError +// @Router /v2/{coin}/staking/delegations/{address} [get] +func GetStakingDelegationsForSpecificCoin(c *gin.Context, api blockatlas.StakeAPI) { + result, err := getDelegationResponse(api, c.Param("address")) + if err != nil { + c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + return + } + c.JSON(http.StatusOK, &result) +} + +func getDelegationResponse(api blockatlas.StakeAPI, address string) (blockatlas.DelegationResponse, error) { + delegations, err := api.GetDelegations(address) + if err != nil { + return blockatlas.DelegationResponse{ + StakingResponse: getStakingResponse(api), + Address: address, + }, errors.E("Unable to fetch delegations list", err) + } + balance, err := api.UndelegatedBalance(address) + if err != nil { + return blockatlas.DelegationResponse{ + Delegations: delegations, + Address: address, + StakingResponse: getStakingResponse(api), + }, errors.E("Unable to fetch undelegated balance", err) + } + return blockatlas.DelegationResponse{ + Balance: balance, + Delegations: delegations, + Address: address, + StakingResponse: getStakingResponse(api), + }, nil +} + +func getStakingResponse(api blockatlas.StakeAPI) blockatlas.StakingResponse { + stakingCoin := api.Coin() + return blockatlas.StakingResponse{ + Coin: stakingCoin.External(), + Details: api.GetDetails(), + } +} diff --git a/api/endpoint/token.go b/api/endpoint/token.go new file mode 100644 index 000000000..4111c542f --- /dev/null +++ b/api/endpoint/token.go @@ -0,0 +1,34 @@ +package endpoint + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/api/model" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "net/http" +) + +// @Summary Get Tokens +// @ID tokens +// @Description Get tokens from the address +// @Accept json +// @Produce json +// @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 +// @Failure 500 {object} middleware.ApiError +// @Router /v2/{coin}/tokens/{address} [get] +func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokenAPI) { + address := c.Param("address") + if address == "" { + EmptyPage(c) + return + } + + result, err := tokenAPI.GetTokenListByAddress(address) + if err != nil { + c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + return + } + c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &result}) +} diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go new file mode 100644 index 000000000..52ba41963 --- /dev/null +++ b/api/endpoint/transaction.go @@ -0,0 +1,89 @@ +package endpoint + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/api/model" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "net/http" + "sort" +) + +// @Summary Get Transactions +// @ID tx_v2 +// @Description Get transactions from the address +// @Accept json +// @Produce json +// @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 +// @Failure 500 {object} middleware.ApiError +// @Router /v2/{coin}/transactions/{address} [get] + +// @Summary Get Transactions +// @ID tx_v1 +// @Description Get transactions from the address +// @Accept json +// @Produce json +// @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} middleware.ApiError +// @Router /v1/{coin}/{address} [get] +func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI blockatlas.TokenTxAPI) { + address := c.Param("address") + if address == "" { + c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, blockatlas.ErrInvalidAddr)) + return + } + token := c.Query("token") + + var ( + txs []blockatlas.Tx + err error + ) + + switch { + case token == "" && txAPI != nil: + txs, err = txAPI.GetTxsByAddress(address) + case token != "" && tokenTxAPI != nil: + txs, err = tokenTxAPI.GetTokenTxsByAddress(address, token) + default: + c.JSON(http.StatusInternalServerError, + model.CreateErrorResponse(model.InternalFail, errors.E("Failed to find api for that coin"))) + return + } + + if err != nil { + switch err { + case blockatlas.ErrInvalidAddr: + c.JSON(http.StatusBadRequest, + model.CreateErrorResponse(model.InvalidQuery, blockatlas.ErrInvalidAddr)) + return + case blockatlas.ErrNotFound: + c.JSON(http.StatusNotFound, + model.CreateErrorResponse(model.RequestedDataNotFound, blockatlas.ErrNotFound)) + return + case blockatlas.ErrSourceConn: + c.JSON(http.StatusServiceUnavailable, + model.CreateErrorResponse(model.InternalFail, blockatlas.ErrSourceConn)) + return + default: + c.JSON(http.StatusInternalServerError, + model.CreateErrorResponse(model.Default, err)) + return + } + } + + page := make(blockatlas.TxPage, 0) + for _, tx := range txs { + tx.Direction = tx.GetTransactionDirection(address) + page = append(page, tx) + } + if len(page) > blockatlas.TxPerPage { + page = page[0:blockatlas.TxPerPage] + } + sort.Sort(&page) + c.JSON(http.StatusOK, &page) +} diff --git a/pkg/ginutils/gincache/cache.go b/api/middleware/cache.go similarity index 97% rename from pkg/ginutils/gincache/cache.go rename to api/middleware/cache.go index 43474e167..efba3bbaf 100644 --- a/pkg/ginutils/gincache/cache.go +++ b/api/middleware/cache.go @@ -1,4 +1,4 @@ -package gincache +package middleware import ( "bytes" @@ -43,8 +43,6 @@ type cachedWriter struct { key string } -var _ gin.ResponseWriter = &cachedWriter{} - func newCachedWriter(expire time.Duration, writer gin.ResponseWriter, key string) *cachedWriter { return &cachedWriter{writer, 0, false, expire, key} } @@ -151,7 +149,7 @@ func generateKey(c *gin.Context) string { return base64.URLEncoding.EncodeToString(hash[:]) } -// CacheMiddleware encapsulates a gin handler function and caches the response with an expiration time. +// CacheMiddleware encapsulates a gin handler function and caches the model with an expiration time. func CacheMiddleware(expiration time.Duration, handle gin.HandlerFunc) gin.HandlerFunc { return func(c *gin.Context) { defer c.Next() diff --git a/pkg/ginutils/gincache/cache_test.go b/api/middleware/cache_test.go similarity index 73% rename from pkg/ginutils/gincache/cache_test.go rename to api/middleware/cache_test.go index 9467aca28..c2cda6ae5 100644 --- a/pkg/ginutils/gincache/cache_test.go +++ b/api/middleware/cache_test.go @@ -1,10 +1,10 @@ -package gincache +package middleware import ( "fmt" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/ginutils" + "net/http" "net/http/httptest" "testing" "time" @@ -28,10 +28,10 @@ func TestWrite(t *testing.T) { writer := newCachedWriter(time.Second*3, c.Writer, "mykey") c.Writer = writer - c.Writer.WriteHeader(204) + c.Writer.WriteHeader(http.StatusNoContent) c.Writer.WriteHeaderNow() - c.Writer.Write([]byte("foo")) // nolint - assert.Equal(t, 204, c.Writer.Status()) + _, _ = c.Writer.Write([]byte("foo")) // nolint + assert.Equal(t, http.StatusNoContent, c.Writer.Status()) assert.Equal(t, "foo", w.Body.String()) assert.True(t, c.Writer.Written()) } @@ -39,28 +39,28 @@ func TestWrite(t *testing.T) { func TestCachePage(t *testing.T) { router := gin.New() router.GET("/cache_ping", CacheMiddleware(time.Second*3, func(c *gin.Context) { - ginutils.RenderSuccess(c, "pong "+fmt.Sprint(time.Now().UnixNano())) + c.JSON(http.StatusOK, "pong "+fmt.Sprint(time.Now().UnixNano())) })) w1 := performRequest("GET", "/cache_ping", router) w2 := performRequest("GET", "/cache_ping", router) - assert.Equal(t, 200, w1.Code) - assert.Equal(t, 200, w2.Code) + assert.Equal(t, http.StatusOK, w1.Code) + assert.Equal(t, http.StatusOK, w2.Code) assert.Equal(t, w1.Body.String(), w2.Body.String()) } func TestCachePageExpire(t *testing.T) { router := gin.New() router.GET("/cache_ping", CacheMiddleware(time.Second, func(c *gin.Context) { - ginutils.RenderSuccess(c, "pong "+fmt.Sprint(time.Now().UnixNano())) + c.JSON(http.StatusOK, "pong "+fmt.Sprint(time.Now().UnixNano())) })) w1 := performRequest("GET", "/cache_ping", router) time.Sleep(time.Second * 3) w2 := performRequest("GET", "/cache_ping", router) - assert.Equal(t, 200, w1.Code) - assert.Equal(t, 200, w2.Code) + assert.Equal(t, http.StatusOK, w1.Code) + assert.Equal(t, http.StatusOK, w2.Code) assert.NotEqual(t, w1.Body.String(), w2.Body.String()) } diff --git a/pkg/ginutils/middleware.go b/api/middleware/cors.go similarity index 51% rename from pkg/ginutils/middleware.go rename to api/middleware/cors.go index 0cc162377..58f48fbc5 100644 --- a/pkg/ginutils/middleware.go +++ b/api/middleware/cors.go @@ -1,36 +1,9 @@ -package ginutils +package middleware import ( "github.com/gin-gonic/gin" - "net/http" - "strings" ) -var DefaultMiddleware = func(c *gin.Context) { - c.Next() -} - -func TokenAuthMiddleware(requiredToken string) gin.HandlerFunc { - if requiredToken == "" { - return DefaultMiddleware - } - - return func(c *gin.Context) { - token := c.Request.Header.Get("Authorization") - token = strings.Replace(token, "Bearer ", "", 1) - if token == "" { - RenderError(c, http.StatusUnauthorized, "API token required") - return - } - - if token != requiredToken { - RenderError(c, http.StatusUnauthorized, "Invalid API token") - return - } - c.Next() - } -} - func CORSMiddleware() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set("Access-Control-Allow-Origin", "*") diff --git a/pkg/ginutils/reverse_proxy.go b/api/middleware/reverse_proxy.go similarity index 95% rename from pkg/ginutils/reverse_proxy.go rename to api/middleware/reverse_proxy.go index c828956ed..868be6b1d 100644 --- a/pkg/ginutils/reverse_proxy.go +++ b/api/middleware/reverse_proxy.go @@ -1,4 +1,4 @@ -package ginutils +package middleware import ( "github.com/gin-gonic/gin" diff --git a/api/model/model.go b/api/model/model.go new file mode 100644 index 000000000..e7708e475 --- /dev/null +++ b/api/model/model.go @@ -0,0 +1,31 @@ +package model + +const ( + Default ErrorCode = iota + InvalidQuery + RequestedDataNotFound + InternalFail +) + +type ( + ErrorResponse struct { + Error ErrorDetails `json:"error"` + } + ErrorDetails struct { + Message string `json:"message"` + Code ErrorCode `json:"code"` + } + + ErrorCode int +) + +func CreateErrorResponse(code ErrorCode, err error) ErrorResponse { + var message string + if err != nil { + message = err.Error() + } + return ErrorResponse{Error: ErrorDetails{ + Message: message, + Code: code, + }} +} diff --git a/api/registry.go b/api/registry.go new file mode 100644 index 000000000..aabe4169c --- /dev/null +++ b/api/registry.go @@ -0,0 +1,141 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/api/endpoint" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform" +) + +func RegisterCollectionsAPI(root gin.IRouter, api blockatlas.Platform) { + collectionAPI, ok := api.(blockatlas.CollectionAPI) + if !ok { + return + } + + handle := collectionAPI.Coin().Handle + + root.GET("/v3/"+handle+"/collections/:owner/collection/:collection_id", func(c *gin.Context) { + endpoint.GetCollectiblesForSpecificCollectionAndOwnerV3(c, collectionAPI) + }) + root.GET("/v3/"+handle+"/collections/:owner", func(c *gin.Context) { + endpoint.GetCollectiblesForOwnerV3(c, collectionAPI) + }) + root.GET("/v4/"+handle+"/collections/:owner/collection/:collection_id", func(c *gin.Context) { + endpoint.GetCollectiblesForSpecificCollectionAndOwner(c, collectionAPI) + }) +} + +func RegisterTokensAPI(root gin.IRouter, api blockatlas.Platform) { + tokenAPI, ok := api.(blockatlas.TokenAPI) + if !ok { + return + } + + handle := api.Coin().Handle + + root.GET("/v2/"+handle+"/tokens/:address", func(c *gin.Context) { + endpoint.GetTokensByAddress(c, tokenAPI) + }) +} + +func RegisterTransactionsAPI(root gin.IRouter, api blockatlas.Platform) { + txAPI, _ := api.(blockatlas.TxAPI) + tokenTxAPI, _ := api.(blockatlas.TokenTxAPI) + + handle := api.Coin().Handle + + if IsForCustomAPI(handle) { + return + } + + root.GET("/v1/"+handle+"/:address", func(c *gin.Context) { + endpoint.GetTransactionsHistory(c, txAPI, tokenTxAPI) + }) + root.GET("/v2/"+handle+"/transactions/:address", func(c *gin.Context) { + endpoint.GetTransactionsHistory(c, txAPI, tokenTxAPI) + }) +} + +func RegisterStakeAPI(root gin.IRouter, api blockatlas.Platform) { + stakingAPI, ok := api.(blockatlas.StakeAPI) + if !ok { + return + } + handle := api.Coin().Handle + + root.GET("/v2/"+handle+"/staking/validators", func(c *gin.Context) { + endpoint.GetValidators(c, stakingAPI) + }) + root.GET("/v2/"+handle+"/staking/delegations/:address", func(c *gin.Context) { + endpoint.GetStakingDelegationsForSpecificCoin(c, stakingAPI) + }) +} + +func RegisterBatchAPI(root gin.IRouter) { + root.POST("v2/staking/delegations", func(c *gin.Context) { + endpoint.GetStakeDelegationsWithAllInfoForBatch(c, platform.StakeAPIs) + }) + root.POST("v2/staking/list", func(c *gin.Context) { + endpoint.GetStakeInfoForBatch(c, platform.StakeAPIs) + }) + root.POST("/v3/collectibles/categories", func(c *gin.Context) { + endpoint.GetCollectionCategoriesFromListV3(c, platform.CollectionAPIs) + }) + root.POST("/v4/collectibles/categories", func(c *gin.Context) { + endpoint.GetCollectionCategoriesFromList(c, platform.CollectionAPIs) + }) +} + +// CustomAPI must be removed and all handlers needs to be migrated to the transactions, tokens api +func RegisterCustomAPI(root gin.IRouter, api blockatlas.Platform) { + customAPI, ok := api.(blockatlas.CustomAPI) + if !ok { + return + } + handle := api.Coin().Handle + + customRouter := root.Group("/v1/" + handle) + customAPI.RegisterRoutes(customRouter) +} + +func RegisterDomainAPI(root gin.IRouter) { + root.GET("/ns/lookup", endpoint.GetAddressByCoinAndDomain) + root.GET("v2/ns/lookup", endpoint.GetAddressByCoinAndDomainBatch) +} + +func RegisterBasicAPI(root gin.IRouter) { + root.GET("/", endpoint.GetRoot) + root.GET("/status", endpoint.GetStatus) +} + +func IsForCustomAPI(handle string) bool { + switch handle { + case coin.Gochain().Handle, + coin.Thundertoken().Handle, + coin.Classic().Handle, + coin.Poa().Handle, + coin.Callisto().Handle, + coin.Wanchain().Handle, + coin.Tomochain().Handle, + coin.Ethereum().Handle, + coin.Bitcoin().Handle, + coin.Litecoin().Handle, + coin.Bitcoincash().Handle, + coin.Zcash().Handle, + coin.Zcoin().Handle, + coin.Viacoin().Handle, + coin.Ravencoin().Handle, + coin.Groestlcoin().Handle, + coin.Zelcash().Handle, + coin.Decred().Handle, + coin.Digibyte().Handle, + coin.Dash().Handle, + coin.Doge().Handle, + coin.Qtum().Handle: + return true + default: + return false + } +} diff --git a/api/routes.go b/api/routes.go deleted file mode 100644 index b1f19b108..000000000 --- a/api/routes.go +++ /dev/null @@ -1,105 +0,0 @@ -package api - -import ( - "fmt" - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform" -) - -var routers = make(map[string]gin.IRouter) - -func SetupPlatformAPI(root gin.IRouter) { - root.GET("/", GetRoot) - root.GET("/status", GetStatus) - - v1 := root.Group("/v1") - v3 := root.Group("/v3") - v2 := root.Group("/v2") - v4 := root.Group("/v4") - - v1.GET("/", GetSupportedEndpoints) - - for _, txAPI := range platform.Platforms { - router := getRouter(v1, txAPI.Coin().Handle) - makeTxRouteV1(router, txAPI) - - routerV2 := getRouter(v2, txAPI.Coin().Handle) - makeTxRouteV2(routerV2, txAPI) - } - - for _, tokenAPI := range platform.Platforms { - router := getRouter(v2, tokenAPI.Coin().Handle) - makeTokenRoute(router, tokenAPI) - } - - for _, stakeAPI := range platform.Platforms { - router := getRouter(v2, stakeAPI.Coin().Handle) - makeStakingValidatorsRoute(router, stakeAPI) - makeStakingDelegationsRoute(router, stakeAPI) - } - - for _, collectionAPI := range platform.Platforms { - - routerV3 := getRouter(v3, collectionAPI.Coin().Handle) - makeCollectionsRoute(routerV3, collectionAPI) - makeCollectionRoute(routerV3, collectionAPI) - - routerV4 := getRouter(v4, collectionAPI.Coin().Handle) - makeCollectionRouteV4(routerV4, collectionAPI) - } - - for _, customAPI := range platform.CustomAPIs { - router := getRouter(v1, customAPI.Coin().Handle) - customAPI.RegisterRoutes(router) - } - - ns := root.Group("/ns") - batchNs := v2.Group("/ns") - MakeLookupRoute(ns) - MakeLookupBatchRoute(batchNs) - - makeStakingDelegationsBatchRoute(v2) - makeStakingDelegationsSimpleBatchRoute(v2) - - makeCategoriesBatchRoute(v3) - makeCategoriesBatchRouteV4(v4) - - logger.Info("Routes set up", logger.Params{"routes": len(routers)}) -} - -// getRouter lazy loads routers -func getRouter(router *gin.RouterGroup, handle string) gin.IRouter { - key := fmt.Sprintf("%s/%s", router.BasePath(), handle) - if group, ok := routers[key]; ok { - return group - } else { - path := fmt.Sprintf("/%s", handle) - logger.Debug("Registering route", logger.Params{"path": len(path)}) - group := router.Group(path) - routers[key] = group - return group - } -} - -func GetSupportedEndpoints(c *gin.Context) { - var resp struct { - Endpoints []string `json:"endpoints,omitempty"` - } - for handle := range routers { - resp.Endpoints = append(resp.Endpoints, handle) - } - ginutils.RenderSuccess(c, &resp) -} - -func GetRoot(c *gin.Context) { ginutils.RenderSuccess(c, "Welcome to the Block Atlas API") } - -func GetStatus(c *gin.Context) { - ginutils.RenderSuccess(c, map[string]interface{}{ - "status": true, - "build": internal.Build, - "date": internal.Date, - }) -} diff --git a/api/staking.go b/api/staking.go deleted file mode 100644 index 881d26bc9..000000000 --- a/api/staking.go +++ /dev/null @@ -1,192 +0,0 @@ -package api - -import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "github.com/trustwallet/blockatlas/pkg/ginutils/gincache" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/platform" - services "github.com/trustwallet/blockatlas/services/assets" - "time" -) - -type ( - AddressBatchRequest struct { - Address string `json:"address"` - CoinBatchRequest - } - - CoinBatchRequest struct { - Coin uint `json:"coin"` - } - - ENSBatchRequest struct { - Coins []uint64 `json:"coins"` - Name string `json:"name"` - } - - AddressesRequest []AddressBatchRequest - CoinsRequest []CoinBatchRequest -) - -// @Summary Get Multiple Stake Delegations -// @ID batch_delegations -// @Description Get Stake Delegations for multiple coins -// @Accept json -// @Produce json -// @Tags Staking -// @Param delegations body api.AddressesRequest true "Validators addresses and coins" -// @Success 200 {object} blockatlas.DelegationsBatchPage -// @Router /v2/staking/delegations [post] -func makeStakingDelegationsBatchRoute(router gin.IRouter) { - router.POST("/staking/delegations", func(c *gin.Context) { - var reqs AddressesRequest - if err := c.BindJSON(&reqs); err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - batch := make(blockatlas.DelegationsBatchPage, 0) - for _, r := range reqs { - c, ok := coin.Coins[r.Coin] - if !ok { - continue - } - p, ok := platform.StakeAPIs[c.Handle] - if !ok { - continue - } - delegation, err := getDelegationResponse(p, r.Address) - if err != nil { - continue - } - batch = append(batch, delegation) - } - ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: batch}) - }) -} - -// @Summary Get Multiple Stake Delegations -// @ID batch_delegations -// @Description Get Stake Delegations for multiple coins -// @Accept json -// @Produce json -// @Tags Staking -// @Param delegations body api.AddressesRequest true "Validators addresses and coins" -// @Success 200 {object} blockatlas.DelegationsBatchPage -// @Router /v2/staking/list [post] -func makeStakingDelegationsSimpleBatchRoute(router gin.IRouter) { - router.POST("/staking/list", gincache.CacheMiddleware(time.Hour*24, func(c *gin.Context) { - var reqs CoinsRequest - if err := c.BindJSON(&reqs); err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - batch := make(blockatlas.StakingBatchPage, 0) - for _, r := range reqs { - c, ok := coin.Coins[r.Coin] - if !ok { - continue - } - p, ok := platform.StakeAPIs[c.Handle] - if !ok { - continue - } - staking := getStakingResponse(p) - batch = append(batch, staking) - } - ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: batch}) - })) -} - -// @Summary Get Validators -// @ID validators -// @Description Get validators from the address -// @Accept json -// @Produce json -// @Tags Staking -// @Param coin path string true "the coin name" default(cosmos) -// @Success 200 {object} blockatlas.DocsResponse -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/{coin}/staking/validators [get] -func makeStakingValidatorsRoute(router gin.IRouter, api blockatlas.Platform) { - var stakingAPI blockatlas.StakeAPI - stakingAPI, _ = api.(blockatlas.StakeAPI) - - if stakingAPI == nil { - return - } - - router.GET("/staking/validators", gincache.CacheMiddleware(time.Hour, func(c *gin.Context) { - results, err := services.GetActiveValidators(stakingAPI) - if err != nil { - logger.Error(err) - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: results}) - })) -} - -// @Summary Get Stake Delegations -// @ID delegations -// @Description Get stake delegations from the address -// @Accept json -// @Produce json -// @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 -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/{coin}/staking/delegations/{address} [get] -func makeStakingDelegationsRoute(router gin.IRouter, api blockatlas.Platform) { - var stakingAPI blockatlas.StakeAPI - stakingAPI, _ = api.(blockatlas.StakeAPI) - - if stakingAPI == nil { - return - } - - router.GET("/staking/delegations/:address", func(c *gin.Context) { - response, err := getDelegationResponse(stakingAPI, c.Param("address")) - if err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - ginutils.RenderSuccess(c, response) - }) -} - -func getDelegationResponse(p blockatlas.StakeAPI, address string) (blockatlas.DelegationResponse, error) { - delegations, err := p.GetDelegations(address) - if err != nil { - return blockatlas.DelegationResponse{ - StakingResponse: getStakingResponse(p), - }, errors.E("Unable to fetch delegations list", err) - } - balance, err := p.UndelegatedBalance(address) - if err != nil { - return blockatlas.DelegationResponse{ - StakingResponse: getStakingResponse(p), - }, errors.E("Unable to fetch undelegated balance", err) - } - return blockatlas.DelegationResponse{ - Balance: balance, - Delegations: delegations, - Address: address, - StakingResponse: getStakingResponse(p), - }, nil -} - -func getStakingResponse(p blockatlas.StakeAPI) blockatlas.StakingResponse { - c := p.Coin() - return blockatlas.StakingResponse{ - Coin: c.External(), - Details: p.GetDetails(), - } -} diff --git a/api/transaction.go b/api/transaction.go deleted file mode 100644 index 002943df0..000000000 --- a/api/transaction.go +++ /dev/null @@ -1,141 +0,0 @@ -package api - -import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/ginutils" - "net/http" - "sort" -) - -// @Summary Get Transactions -// @ID tx_v1 -// @Description Get transactions from the address -// @Accept json -// @Produce json -// @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 -// @Router /v1/{coin}/{address} [get] -func makeTxRouteV1(router gin.IRouter, api blockatlas.Platform) { - makeTxRoute(router, api, "/:address") -} - -// @Summary Get Transactions -// @ID tx_v2 -// @Description Get transactions from the address -// @Accept json -// @Produce json -// @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 -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/{coin}/transactions/{address} [get] -func makeTxRouteV2(router gin.IRouter, api blockatlas.Platform) { - makeTxRoute(router, api, "/transactions/:address") -} - -func makeTxRoute(router gin.IRouter, api blockatlas.Platform, path string) { - var txAPI blockatlas.TxAPI - var tokenTxAPI blockatlas.TokenTxAPI - txAPI, _ = api.(blockatlas.TxAPI) - tokenTxAPI, _ = api.(blockatlas.TokenTxAPI) - - if txAPI == nil && tokenTxAPI == nil { - return - } - - router.GET(path, func(c *gin.Context) { - address := c.Param("address") - if address == "" { - emptyPage(c) - return - } - token := c.Query("token") - - var txs []blockatlas.Tx - var err error - switch { - case token == "" && txAPI != nil: - txs, err = txAPI.GetTxsByAddress(address) - case token != "" && tokenTxAPI != nil: - txs, err = tokenTxAPI.GetTokenTxsByAddress(address, token) - default: - emptyPage(c) - return - } - - if err != nil { - errResp := ginutils.ErrorResponse(c) - switch { - case err == blockatlas.ErrInvalidAddr: - errResp.Params(http.StatusBadRequest, "Invalid address") - case err == blockatlas.ErrNotFound: - errResp.Params(http.StatusNotFound, "No such address") - case err == blockatlas.ErrSourceConn: - errResp.Params(http.StatusServiceUnavailable, "Lost connection to blockchain") - } - errResp.Render() - return - } - - page := make(blockatlas.TxPage, 0) - for _, tx := range txs { - if tx.Direction != "" { - goto AddTx - } - tx.Direction = blockatlas.DirectionOutgoing - if tx.To == address { - tx.Direction = blockatlas.DirectionIncoming - if tx.From == address { - tx.Direction = blockatlas.DirectionSelf - } - } - AddTx: - page = append(page, tx) - } - if len(page) > blockatlas.TxPerPage { - page = page[0:blockatlas.TxPerPage] - } - sort.Sort(page) - ginutils.RenderSuccess(c, &page) - }) -} - -// @Summary Get Tokens -// @ID tokens -// @Description Get tokens from the address -// @Accept json -// @Produce json -// @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 -// @Failure 500 {object} ginutils.ApiError -// @Router /v2/{coin}/tokens/{address} [get] -func makeTokenRoute(router gin.IRouter, api blockatlas.Platform) { - var tokenAPI blockatlas.TokenAPI - tokenAPI, _ = api.(blockatlas.TokenAPI) - - if tokenAPI == nil { - return - } - - router.GET("/tokens/:address", func(c *gin.Context) { - address := c.Param("address") - if address == "" { - emptyPage(c) - return - } - - tl, err := tokenAPI.GetTokenListByAddress(address) - if err != nil { - ginutils.ErrorResponse(c).Message(err.Error()).Render() - return - } - - ginutils.RenderSuccess(c, blockatlas.DocsResponse{Docs: tl}) - }) -} diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 0656a0ebf..d91e4c537 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -308,16 +308,16 @@ paths: description: Lookup ENS/ZNS to find registered addresses operationId: lookup parameters: - - description: string name - in: query - name: name - type: string - - description: string coin - in: query - name: coin - type: string + - description: string name + in: query + name: name + type: string + - description: string coin + in: query + name: coin + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -329,28 +329,28 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Lookup .eth / .zil addresses tags: - - Naming + - Naming /v1/{coin}/{address}: get: consumes: - - application/json + - application/json description: Get transactions from the address operationId: tx_v1 parameters: - - default: tezos - description: the coin name - in: path - name: coin - required: true - type: string - - default: tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q - description: the query address - in: path - name: address - required: true - type: string + - default: tezos + description: the coin name + in: path + name: coin + required: true + type: string + - default: tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q + description: the query address + in: path + name: address + required: true + type: string produces: - - application/json + - application/json responses: "500": description: Internal Server Error @@ -358,28 +358,28 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Transactions tags: - - Transactions + - Transactions /v1/{coin}/xpub/{xpub}: get: consumes: - - application/json + - application/json description: Get transactions from xpub address operationId: xpub parameters: - - default: bitcoin - description: the coin name - in: path - name: coin - required: true - type: string - - default: zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC - description: the xpub address - in: path - name: xpub - required: true - type: string + - default: bitcoin + description: the coin name + in: path + name: coin + required: true + type: string + - default: zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC + description: the xpub address + in: path + name: xpub + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -387,41 +387,41 @@ paths: $ref: '#/definitions/blockatlas.TxPage' summary: Get xpub transactions tags: - - Transactions + - Transactions /v1/market/charts: get: consumes: - - application/json + - application/json description: Get the charts data from an market and coin/token operationId: get_charts_data parameters: - - default: 60 - description: Coin ID - in: query - name: coin - required: true - type: integer - - description: Token ID - in: query - name: token - type: string - - default: 1574483028 - description: Start timestamp - in: query - name: time_start - type: integer - - default: 64 - description: Max number of items in result prices array - in: query - name: max_items - type: integer - - default: USD - description: The currency to show charts - in: query - name: currency - type: string + - default: 60 + description: Coin ID + in: query + name: coin + required: true + type: integer + - description: Token ID + in: query + name: token + type: string + - default: 1574483028 + description: Start timestamp + in: query + name: time_start + type: integer + - default: 64 + description: Max number of items in result prices array + in: query + name: max_items + type: integer + - default: USD + description: The currency to show charts + in: query + name: currency + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -429,31 +429,31 @@ paths: $ref: '#/definitions/watchmarket.ChartData' summary: Get charts data for a specific coin tags: - - Market + - Market /v1/market/info: get: consumes: - - application/json + - application/json description: Get the charts coin info data from an market and coin/contract operationId: get_charts_coin_info parameters: - - default: 60 - description: Coin ID - in: query - name: coin - required: true - type: integer - - description: Token ID - in: query - name: token - type: string - - default: USD - description: The currency to show coin info in - in: query - name: currency - type: string + - default: 60 + description: Coin ID + in: query + name: coin + required: true + type: integer + - description: Token ID + in: query + name: token + type: string + - default: USD + description: The currency to show coin info in + in: query + name: currency + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -461,22 +461,22 @@ paths: $ref: '#/definitions/watchmarket.ChartCoinInfo' summary: Get charts coin info data for a specific coin tags: - - Market + - Market /v1/market/ticker: post: consumes: - - application/json + - application/json description: Get the ticker values from many market and coin/token operationId: get_tickers parameters: - - description: Ticker - in: body - name: tickers - required: true - schema: - $ref: '#/definitions/api.TickerRequest' + - description: Ticker + in: body + name: tickers + required: true + schema: + $ref: '#/definitions/api.TickerRequest' produces: - - application/json + - application/json responses: "200": description: OK @@ -484,28 +484,28 @@ paths: $ref: '#/definitions/api.Tickers' summary: Get ticker values for a specific market tags: - - Market + - Market /v2/{coin}/staking/delegations/{address}: get: consumes: - - application/json + - application/json description: Get stake delegations from the address operationId: delegations parameters: - - default: tron - description: the coin name - in: path - name: coin - required: true - type: string - - default: TPJYCz8ppZNyvw7pTwmjajcx4Kk1MmEUhD - description: the query address - in: path - name: address - required: true - type: string + - default: tron + description: the coin name + in: path + name: coin + required: true + type: string + - default: TPJYCz8ppZNyvw7pTwmjajcx4Kk1MmEUhD + description: the query address + in: path + name: address + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -517,22 +517,22 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Stake Delegations tags: - - Staking + - Staking /v2/{coin}/staking/validators: get: consumes: - - application/json + - application/json description: Get validators from the address operationId: validators parameters: - - default: cosmos - description: the coin name - in: path - name: coin - required: true - type: string + - default: cosmos + description: the coin name + in: path + name: coin + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -544,28 +544,28 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Validators tags: - - Staking + - Staking /v2/{coin}/tokens/{address}: get: consumes: - - application/json + - application/json description: Get tokens from the address operationId: tokens parameters: - - default: ethereum - description: the coin name - in: path - name: coin - required: true - type: string - - default: 0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB - description: the query address - in: path - name: address - required: true - type: string + - default: ethereum + description: the coin name + in: path + name: coin + required: true + type: string + - default: 0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB + description: the query address + in: path + name: address + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -577,28 +577,28 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Tokens tags: - - Transactions + - Transactions /v2/{coin}/transactions/{address}: get: consumes: - - application/json + - application/json description: Get transactions from the address operationId: tx_v2 parameters: - - default: tezos - description: the coin name - in: path - name: coin - required: true - type: string - - default: tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q - description: the query address - in: path - name: address - required: true - type: string + - default: tezos + description: the coin name + in: path + name: coin + required: true + type: string + - default: tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q + description: the query address + in: path + name: address + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -610,23 +610,23 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Transactions tags: - - Transactions + - Transactions /v2/ns/lookup: get: description: Lookup ENS/ZNS to find registered addresses for multiple coins operationId: lookup parameters: - - description: string name - in: query - name: name - type: string - - description: List of coins - in: query - name: coins - required: true - type: string + - description: string name + in: query + name: name + type: string + - description: List of coins + in: query + name: coins + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -640,22 +640,22 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Lookup .eth / .zil addresses tags: - - Naming + - Naming /v2/staking/delegations: post: consumes: - - application/json + - application/json description: Get Stake Delegations for multiple coins operationId: batch_delegations parameters: - - description: Validators addresses and coins - in: body - name: delegations - required: true - schema: - $ref: '#/definitions/api.AddressesRequest' + - description: Validators addresses and coins + in: body + name: delegations + required: true + schema: + $ref: '#/definitions/api.AddressesRequest' produces: - - application/json + - application/json responses: "200": description: OK @@ -663,22 +663,22 @@ paths: $ref: '#/definitions/blockatlas.DelegationsBatchPage' summary: Get Multiple Stake Delegations tags: - - Staking + - Staking /v2/staking/list: post: consumes: - - application/json + - application/json description: Get Stake Delegations for multiple coins operationId: batch_delegations parameters: - - description: Validators addresses and coins - in: body - name: delegations - required: true - schema: - $ref: '#/definitions/api.AddressesRequest' + - description: Validators addresses and coins + in: body + name: delegations + required: true + schema: + $ref: '#/definitions/api.AddressesRequest' produces: - - application/json + - application/json responses: "200": description: OK @@ -686,34 +686,34 @@ paths: $ref: '#/definitions/blockatlas.DelegationsBatchPage' summary: Get Multiple Stake Delegations tags: - - Staking + - Staking /v4/{coin}/collections/{owner}/collection/{collection_id}: get: consumes: - - application/json + - application/json description: Get a collection from the address operationId: collection_v4 parameters: - - default: ethereum - description: the coin name - in: path - name: coin - required: true - type: string - - default: 0x0875BCab22dE3d02402bc38aEe4104e1239374a7 - description: the query address - in: path - name: owner - required: true - type: string - - default: 0x06012c8cf97bead5deae237070f9587f8e7a266d - description: the query collection - in: path - name: collection_id - required: true - type: string + - default: ethereum + description: the coin name + in: path + name: coin + required: true + type: string + - default: 0x0875BCab22dE3d02402bc38aEe4104e1239374a7 + description: the query address + in: path + name: owner + required: true + type: string + - default: 0x06012c8cf97bead5deae237070f9587f8e7a266d + description: the query collection + in: path + name: collection_id + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -725,23 +725,23 @@ paths: $ref: '#/definitions/ginutils.ApiError' summary: Get Collection tags: - - Collections + - Collections /v4/collectibles/categories: post: consumes: - - application/json + - application/json description: Get collection categories operationId: collection_categories_v4 parameters: - - default: '{"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}' - description: Payload - in: body - name: data - required: true - schema: - type: string + - default: '{"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}' + description: Payload + in: body + name: data + required: true + schema: + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -749,5 +749,5 @@ paths: $ref: '#/definitions/blockatlas.DocsResponse' summary: Get list of collections from a specific coin and addresses tags: - - Collections + - Collections swagger: "2.0" diff --git a/internal/init.go b/internal/init.go index bce427039..5011df165 100644 --- a/internal/init.go +++ b/internal/init.go @@ -4,9 +4,9 @@ import ( "flag" "fmt" "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/api/middleware" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/ginutils" "github.com/trustwallet/blockatlas/pkg/logger" "path/filepath" @@ -43,11 +43,11 @@ func InitConfig(confPath string) { func InitEngine(handler *gin.HandlerFunc, ginMode string) *gin.Engine { gin.SetMode(ginMode) engine := gin.New() - engine.Use(ginutils.CheckReverseProxy, *handler) - engine.Use(ginutils.CORSMiddleware()) + engine.Use(middleware.CheckReverseProxy, *handler) + engine.Use(middleware.CORSMiddleware()) engine.Use(gin.Logger()) - engine.OPTIONS("/*path", ginutils.CORSMiddleware()) + engine.OPTIONS("/*path", middleware.CORSMiddleware()) return engine } diff --git a/pkg/ginutils/response.go b/pkg/ginutils/response.go deleted file mode 100644 index 83efac655..000000000 --- a/pkg/ginutils/response.go +++ /dev/null @@ -1,66 +0,0 @@ -package ginutils - -import ( - "encoding/json" - "github.com/gin-gonic/gin" - "net/http" -) - -type ApiError struct { - *gin.Context `json:"-"` - StatusCode int `json:"status_code"` - StatusMessage string `json:"status_message"` -} - -func RenderSuccess(c *gin.Context, result interface{}) { - c.JSON(http.StatusOK, result) -} - -func RenderError(c *gin.Context, code int, msg string) { - err := &ApiError{ - StatusCode: code, - StatusMessage: msg, - Context: c, - } - err.Render() -} - -func ErrorResponse(c *gin.Context) *ApiError { - return &ApiError{ - StatusCode: http.StatusInternalServerError, - StatusMessage: "Internal server error", - Context: c, - } -} - -func (e *ApiError) Code(code int) *ApiError { - e.StatusCode = code - return e -} - -func (e *ApiError) Message(msg string) *ApiError { - e.StatusMessage = msg - return e -} - -func (e *ApiError) Params(code int, msg string) *ApiError { - e.StatusCode = code - e.StatusMessage = msg - return e -} - -func (e *ApiError) Render() { - var msg map[string]interface{} - err := json.Unmarshal([]byte(e.StatusMessage), &msg) - if err == nil { - e.AbortWithStatusJSON(e.StatusCode, map[string]interface{}{ - "error": msg, - "code": e.StatusCode, - }) - return - } - e.AbortWithStatusJSON(e.StatusCode, map[string]interface{}{ - "error": e.StatusMessage, - "code": e.StatusCode, - }) -} From fa750f1a9a2ab9c535e0f19ed996cf6c5aae1b69 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 8 Apr 2020 14:37:09 +0300 Subject: [PATCH 238/506] Fix wrong tx direction for txs with pre-defined direction (#1017) --- api/endpoint/transaction.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 52ba41963..6769021a9 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -78,6 +78,11 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b page := make(blockatlas.TxPage, 0) for _, tx := range txs { + if tx.Direction != "" { + page = append(page, tx) + continue + } + tx.Direction = tx.GetTransactionDirection(address) page = append(page, tx) } From a9032a5f75a56198db843f1cf99c2fe9bb1f7f3e Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov Date: Wed, 8 Apr 2020 22:20:56 +0300 Subject: [PATCH 239/506] [Gincache] Add Cache-Control headers for CacheMiddleware (#1016) * [Gincache] Add Cache-Control headers for CacheMiddleware * Add test * Fix test after rebase * Fixes after review * Update Makefile * Fixes after review --- Makefile | 2 +- api/middleware/cache.go | 28 ++++++++++++++++++++-------- api/middleware/cache_test.go | 21 +++++++++++++++++++++ 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index e4dcf75c1..18f743f53 100644 --- a/Makefile +++ b/Makefile @@ -275,7 +275,7 @@ go-lint-install: go-lint: @echo " > Running golint" - bin/golangci-lint run + bin/golangci-lint run --timeout=2m .PHONY: help all: help diff --git a/api/middleware/cache.go b/api/middleware/cache.go index efba3bbaf..8d87aa0b9 100644 --- a/api/middleware/cache.go +++ b/api/middleware/cache.go @@ -120,21 +120,21 @@ func (mc *memCache) setCache(k string, x interface{}, d time.Duration) { memoryCache.cache.Set(k, b, d) } -func (mc *memCache) getCache(key string) (cacheResponse, error) { +func (mc *memCache) getCache(key string) (cacheResponse, time.Time, error) { var result cacheResponse - c, ok := mc.cache.Get(key) + c, exp, ok := mc.cache.GetWithExpiration(key) if !ok { - return result, fmt.Errorf("gin-cache: invalid cache key %s", key) + return result, time.Time{}, fmt.Errorf("gin-cache: invalid cache key %s", key) } r, ok := c.([]byte) if !ok { - return result, errors.E("validator cache: failed to cast cache to bytes") + return result, time.Time{}, errors.E("validator cache: failed to cast cache to bytes") } err := json.Unmarshal(r, &result) if err != nil { - return result, errors.E(err, "not found") + return result, time.Time{}, errors.E(err, "not found") } - return result, nil + return result, exp, nil } func generateKey(c *gin.Context) string { @@ -154,12 +154,15 @@ func CacheMiddleware(expiration time.Duration, handle gin.HandlerFunc) gin.Handl return func(c *gin.Context) { defer c.Next() key := generateKey(c) - mc, err := memoryCache.getCache(key) + mc, exp, err := memoryCache.getCache(key) if err != nil || mc.Data == nil { writer := newCachedWriter(expiration, c.Writer, key) + + expForSet := uint(expiration.Seconds()) + writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", expForSet)) + c.Writer = writer handle(c) - if c.IsAborted() { memoryCache.deleteCache(key) } @@ -172,6 +175,15 @@ func CacheMiddleware(expiration time.Duration, handle gin.HandlerFunc) gin.Handl c.Writer.Header().Set(k, v) } } + + expCacheTime := (exp.UnixNano() - time.Now().UnixNano()) / int64(time.Second) + + if expCacheTime < 0 { + logger.Error("Invalid expiration time") + } else { + c.Writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", expCacheTime)) + } + _, err = c.Writer.Write(mc.Data) if err != nil { memoryCache.deleteCache(key) diff --git a/api/middleware/cache_test.go b/api/middleware/cache_test.go index c2cda6ae5..72d0aafcd 100644 --- a/api/middleware/cache_test.go +++ b/api/middleware/cache_test.go @@ -64,3 +64,24 @@ func TestCachePageExpire(t *testing.T) { assert.Equal(t, http.StatusOK, w2.Code) assert.NotEqual(t, w1.Body.String(), w2.Body.String()) } + +func TestCacheControl(t *testing.T) { + router := gin.New() + router.GET("/cache_ping_control", CacheMiddleware(time.Second*30, func(c *gin.Context) { + c.JSON(http.StatusOK, "pong "+fmt.Sprint(time.Now().UnixNano())) + })) + + w1 := performRequest("GET", "/cache_ping_control", router) + w1CacheControl := w1.Header().Get("Cache-Control") + assert.NotEqual(t, "no-cache", w1CacheControl) + time.Sleep(time.Second * 1) + w2 := performRequest("GET", "/cache_ping_control", router) + w2CacheControl := w2.Header().Get("Cache-Control") + + assert.NotEqual(t, w1CacheControl, w2CacheControl) + assert.Equal(t, w1.Body.String(), w2.Body.String()) + + assert.Equal(t, http.StatusOK, w1.Code) + assert.Equal(t, http.StatusOK, w2.Code) + +} From f2e476ea9dda2620b245d2ed9727268a89268b41 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov Date: Wed, 8 Apr 2020 23:59:39 +0300 Subject: [PATCH 240/506] [Gincache] Update Cache-Control logic in CacheMiddleware (#1022) --- api/middleware/cache.go | 26 ++++++++++---------------- api/middleware/cache_test.go | 2 +- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/api/middleware/cache.go b/api/middleware/cache.go index 8d87aa0b9..916483a87 100644 --- a/api/middleware/cache.go +++ b/api/middleware/cache.go @@ -120,21 +120,21 @@ func (mc *memCache) setCache(k string, x interface{}, d time.Duration) { memoryCache.cache.Set(k, b, d) } -func (mc *memCache) getCache(key string) (cacheResponse, time.Time, error) { +func (mc *memCache) getCache(key string) (cacheResponse, error) { var result cacheResponse - c, exp, ok := mc.cache.GetWithExpiration(key) + c, ok := mc.cache.Get(key) if !ok { - return result, time.Time{}, fmt.Errorf("gin-cache: invalid cache key %s", key) + return result, fmt.Errorf("gin-cache: invalid cache key %s", key) } r, ok := c.([]byte) if !ok { - return result, time.Time{}, errors.E("validator cache: failed to cast cache to bytes") + return result, errors.E("validator cache: failed to cast cache to bytes") } err := json.Unmarshal(r, &result) if err != nil { - return result, time.Time{}, errors.E(err, "not found") + return result, errors.E(err, "not found") } - return result, exp, nil + return result, nil } func generateKey(c *gin.Context) string { @@ -154,12 +154,12 @@ func CacheMiddleware(expiration time.Duration, handle gin.HandlerFunc) gin.Handl return func(c *gin.Context) { defer c.Next() key := generateKey(c) - mc, exp, err := memoryCache.getCache(key) + cacheControlValue := uint(expiration.Seconds()) + mc, err := memoryCache.getCache(key) if err != nil || mc.Data == nil { writer := newCachedWriter(expiration, c.Writer, key) - expForSet := uint(expiration.Seconds()) - writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", expForSet)) + writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", cacheControlValue)) c.Writer = writer handle(c) @@ -176,13 +176,7 @@ func CacheMiddleware(expiration time.Duration, handle gin.HandlerFunc) gin.Handl } } - expCacheTime := (exp.UnixNano() - time.Now().UnixNano()) / int64(time.Second) - - if expCacheTime < 0 { - logger.Error("Invalid expiration time") - } else { - c.Writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", expCacheTime)) - } + c.Writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", cacheControlValue)) _, err = c.Writer.Write(mc.Data) if err != nil { diff --git a/api/middleware/cache_test.go b/api/middleware/cache_test.go index 72d0aafcd..70b680b30 100644 --- a/api/middleware/cache_test.go +++ b/api/middleware/cache_test.go @@ -78,7 +78,7 @@ func TestCacheControl(t *testing.T) { w2 := performRequest("GET", "/cache_ping_control", router) w2CacheControl := w2.Header().Get("Cache-Control") - assert.NotEqual(t, w1CacheControl, w2CacheControl) + assert.Equal(t, w1CacheControl, w2CacheControl) assert.Equal(t, w1.Body.String(), w2.Body.String()) assert.Equal(t, http.StatusOK, w1.Code) From 480234e77b878af3e1a07dfec68b9b6e041fb69d Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Thu, 9 Apr 2020 00:47:32 +0300 Subject: [PATCH 241/506] Refactor tx direction and add caching for staking endpoints (#1023) --- api/endpoint/transaction.go | 5 ----- api/registry.go | 10 ++++++---- pkg/blockatlas/tx.go | 3 +++ pkg/blockatlas/tx_test.go | 4 ++++ 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 6769021a9..52ba41963 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -78,11 +78,6 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b page := make(blockatlas.TxPage, 0) for _, tx := range txs { - if tx.Direction != "" { - page = append(page, tx) - continue - } - tx.Direction = tx.GetTransactionDirection(address) page = append(page, tx) } diff --git a/api/registry.go b/api/registry.go index aabe4169c..8d1518eaa 100644 --- a/api/registry.go +++ b/api/registry.go @@ -3,9 +3,11 @@ package api import ( "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/api/endpoint" + "github.com/trustwallet/blockatlas/api/middleware" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform" + "time" ) func RegisterCollectionsAPI(root gin.IRouter, api blockatlas.Platform) { @@ -65,9 +67,9 @@ func RegisterStakeAPI(root gin.IRouter, api blockatlas.Platform) { } handle := api.Coin().Handle - root.GET("/v2/"+handle+"/staking/validators", func(c *gin.Context) { + root.GET("/v2/"+handle+"/staking/validators", middleware.CacheMiddleware(time.Hour, func(c *gin.Context) { endpoint.GetValidators(c, stakingAPI) - }) + })) root.GET("/v2/"+handle+"/staking/delegations/:address", func(c *gin.Context) { endpoint.GetStakingDelegationsForSpecificCoin(c, stakingAPI) }) @@ -77,9 +79,9 @@ func RegisterBatchAPI(root gin.IRouter) { root.POST("v2/staking/delegations", func(c *gin.Context) { endpoint.GetStakeDelegationsWithAllInfoForBatch(c, platform.StakeAPIs) }) - root.POST("v2/staking/list", func(c *gin.Context) { + root.POST("v2/staking/list", middleware.CacheMiddleware(time.Hour, func(c *gin.Context) { endpoint.GetStakeInfoForBatch(c, platform.StakeAPIs) - }) + })) root.POST("/v3/collectibles/categories", func(c *gin.Context) { endpoint.GetCollectionCategoriesFromListV3(c, platform.CollectionAPIs) }) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 09cbc5797..1f5bc6e2c 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -265,6 +265,9 @@ func (t *Tx) GetAddresses() []string { } func (t *Tx) GetTransactionDirection(address string) Direction { + if t.Direction != "" { + return t.Direction + } if len(t.Inputs) > 0 && len(t.Outputs) > 0 { addressSet := mapset.NewSet(address) return InferDirection(t, addressSet) diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 787e770bc..5c1462c8a 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -525,4 +525,8 @@ func TestTx_GetTransactionDirection(t *testing.T) { tx.Direction = tx.GetTransactionDirection("0x38d45371993eEc84f38FEDf93C646aA2D2267CEA") assert.Equal(t, Direction("incoming"), tx.Direction) + + tx.Direction = DirectionSelf + tx.Direction = tx.GetTransactionDirection("0x38d45371993eEc84f38FEDf93C646aA2D2267CEA") + assert.Equal(t, Direction("yourself"), tx.Direction) } From ba7cb85d1acd6c41b6a31360036dc88bc25ef0fd Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Thu, 9 Apr 2020 22:12:16 +0300 Subject: [PATCH 242/506] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c674aa4a..2940eb471 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![Go Version](https://img.shields.io/github/go-mod/go-version/TrustWallet/blockatlas) [![Build Status](https://dev.azure.com/TrustWallet/Trust%20BlockAtlas/_apis/build/status/TrustWallet.blockatlas?branchName=master)](https://dev.azure.com/TrustWallet/Trust%20BlockAtlas/_build/latest?definitionId=27&branchName=master) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/43834b0c94ad4f6088629aa3e3bb5e94)](https://www.codacy.com/app/TrustWallet/blockatlas?utm_source=github.com&utm_medium=referral&utm_content=TrustWallet/blockatlas&utm_campaign=Badge_Grade) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f11889e08c604dd08c28b76c350a6c4f)](https://www.codacy.com/gh/trustwallet/blockatlas?utm_source=github.com&utm_medium=referral&utm_content=trustwallet/blockatlas&utm_campaign=Badge_Grade) [![Go Report Card](https://goreportcard.com/badge/trustwallet/blockatlas)](https://goreportcard.com/report/TrustWallet/blockatlas) > BlockAtlas is a clean explorer API and transaction observer for cryptocurrencies. From d9a29fa17b56ef989c953981306a431b817f9ba8 Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Thu, 9 Apr 2020 13:00:20 -0700 Subject: [PATCH 243/506] Add codecov (#1021) * Base * Add codecov yml --- .codecov.yml | 12 ++++++++++++ .gitignore | 1 + Makefile | 2 +- azure-pipelines.yml | 3 +++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 .codecov.yml diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 000000000..aab63c6f1 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,12 @@ +coverage: + range: 70..100 + round: down + precision: 0 + + status: + project: + default: + # basic + target: 30% + + diff --git a/.gitignore b/.gitignore index 4dd133c32..5cf4f5ab7 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ cmd/__debug_bin config_*.yml *.orig *~ +coverage.txt ### macOS ### *.DS_Store diff --git a/Makefile b/Makefile index 18f743f53..889154808 100644 --- a/Makefile +++ b/Makefile @@ -243,7 +243,7 @@ go-clean: go-test: @echo " > Running unit tests" - GOBIN=$(GOBIN) go test -cover -race -v ./... + GOBIN=$(GOBIN) go test -cover -race -coverprofile=coverage.txt -covermode=atomic -v ./... go-integration: @echo " > Running integration tests" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f359b9082..fcde072f0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -49,6 +49,9 @@ jobs: - script: make test workingDirectory: '$(System.DefaultWorkingDirectory)' displayName: 'Run unit tests' + - script: bash <(curl -s https://codecov.io/bash) -f coverage.txt + workingDirectory: '$(System.DefaultWorkingDirectory)' + displayName: 'Upload coverage to codecov.io' - job: mocked_tests dependsOn: environment From 464b11a0f4b5944ebd338cfb694d1fe2531a6125 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Thu, 9 Apr 2020 23:29:24 +0300 Subject: [PATCH 244/506] Add codecov badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2940eb471..d20093252 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ ![Go Version](https://img.shields.io/github/go-mod/go-version/TrustWallet/blockatlas) [![Build Status](https://dev.azure.com/TrustWallet/Trust%20BlockAtlas/_apis/build/status/TrustWallet.blockatlas?branchName=master)](https://dev.azure.com/TrustWallet/Trust%20BlockAtlas/_build/latest?definitionId=27&branchName=master) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f11889e08c604dd08c28b76c350a6c4f)](https://www.codacy.com/gh/trustwallet/blockatlas?utm_source=github.com&utm_medium=referral&utm_content=trustwallet/blockatlas&utm_campaign=Badge_Grade) +[![codecov](https://codecov.io/gh/trustwallet/blockatlas/branch/master/graph/badge.svg)](https://codecov.io/gh/trustwallet/blockatlas) [![Go Report Card](https://goreportcard.com/badge/trustwallet/blockatlas)](https://goreportcard.com/report/TrustWallet/blockatlas) > BlockAtlas is a clean explorer API and transaction observer for cryptocurrencies. From b856a6e11be9adbc2859aca0e7a165586d256920 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 10 Apr 2020 03:30:21 +0300 Subject: [PATCH 245/506] Ignore some directories for codecov (#1025) --- .codecov.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.codecov.yml b/.codecov.yml index aab63c6f1..ba09b162d 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -9,4 +9,10 @@ coverage: # basic target: 30% - + ignore: + - "mock" + - "config" + - "tests" + - "services" + - "scripts" + - "docs" From fbb99c7a6d08826a56495b1a5154730ada298182 Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Fri, 10 Apr 2020 02:20:47 -0700 Subject: [PATCH 246/506] Fix typos in Makerfile, break down go-build by separate targets (#1024) * Fix typos in Makefile, break down go-build by separate targets * Add missing go-build --- Makefile | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 889154808..e11e968d2 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ BUILD := $(shell git rev-parse --short HEAD) DATETIME := $(shell date +"%Y.%m.%d-%H:%M:%S") PROJECT_NAME := $(shell basename "$(PWD)") API_SERVICE := platform_api -OSERVER_NOTIFIER := observer_notifier +OBSERVER_NOTIFIER := observer_notifier OBSERVER_PARSER := observer_parser OBSERVER_SUBSCRIBER := observer_subscriber SWAGGER_API := swagger_api @@ -134,7 +134,7 @@ integration: go-integration start-mock-dyson: stop-dyson @echo " > Starting Dyson with mocks" @-dyson mock/ext-api-dyson & echo $$! > $(PID_DYSON) - @echo " > Dyson started " `cat $(PID_DYSON)` + @echo " > Dyson started with PID: " `cat $(PID_DYSON)` ## fmt: Run `go fmt` for all go files. fmt: go-fmt @@ -183,7 +183,7 @@ else @bash -c "$(MAKE) stop" endif -## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http//localhost +## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http://localhost:8420 newman: install-newman ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host)" @@ -214,15 +214,25 @@ endif go-compile: go-get go-build -go-build: +go-build: go-build-platform-api go-build-observer-notifier go-build-observer-parser go-build-observer-subscriber go-build-swagger-api + +go-build-platform-api: @echo " > Building platform_api binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API_SERVICE)/platform_api ./cmd/$(API_SERVICE) + +go-build-observer-notifier: @echo " > Building observer_notifier binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OSERVER_NOTIFIER)/observer_notifier ./cmd/$(OSERVER_NOTIFIER) + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_NOTIFIER)/observer_notifier ./cmd/$(OBSERVER_NOTIFIER) + +go-build-observer-parser: @echo " > Building observer_parser binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_PARSER)/observer_parser ./cmd/$(OBSERVER_PARSER) + +go-build-observer-subscriber: @echo " > Building observer_subscriber binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SUBSCRIBER)/observer_subscriber ./cmd/$(OBSERVER_SUBSCRIBER) + +go-build-swagger-api: @echo " > Building swagger_api binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SWAGGER_API)/swagger_api ./cmd/$(SWAGGER_API) From 371a83b5292a57bbe4012654f33acb8a99ec9a26 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 10 Apr 2020 20:39:32 +0300 Subject: [PATCH 247/506] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d20093252..2e8154995 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ ![Go Version](https://img.shields.io/github/go-mod/go-version/TrustWallet/blockatlas) [![Build Status](https://dev.azure.com/TrustWallet/Trust%20BlockAtlas/_apis/build/status/TrustWallet.blockatlas?branchName=master)](https://dev.azure.com/TrustWallet/Trust%20BlockAtlas/_build/latest?definitionId=27&branchName=master) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f11889e08c604dd08c28b76c350a6c4f)](https://www.codacy.com/gh/trustwallet/blockatlas?utm_source=github.com&utm_medium=referral&utm_content=trustwallet/blockatlas&utm_campaign=Badge_Grade) [![codecov](https://codecov.io/gh/trustwallet/blockatlas/branch/master/graph/badge.svg)](https://codecov.io/gh/trustwallet/blockatlas) [![Go Report Card](https://goreportcard.com/badge/trustwallet/blockatlas)](https://goreportcard.com/report/TrustWallet/blockatlas) From c0a8a3f1ff8256d29e0267b8cce2af14bf7f971f Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 11 Apr 2020 20:35:56 +0300 Subject: [PATCH 248/506] Fix releaser (#1028) --- scripts/.goreleaser.yml | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/scripts/.goreleaser.yml b/scripts/.goreleaser.yml index f183aab9b..573ad2bdf 100644 --- a/scripts/.goreleaser.yml +++ b/scripts/.goreleaser.yml @@ -3,33 +3,51 @@ before: - git reset --hard - git checkout . builds: - - id: api - binary: api - main: "./cmd/api/main.go" + - id: platform_api + binary: platform_api + main: "./cmd/platform_api/main.go" goos: - linux goarch: - amd64 env: - CGO_ENABLED=0 - - id: observer_test - binary: observer_test - main: "./cmd/observer_test/main.go" + - id: swagger_api + binary: swagger_api + main: "./cmd/swagger_api/main.go" + goos: + - linux + goarch: + - amd64 + env: + - CGO_ENABLED=0 + - id: observer_parser + binary: observer_parser + main: "./cmd/observer_parser/main.go" goos: - linux goarch: - amd64 env: - CGO_ENABLED=0 - - id: market - binary: market - main: "./cmd/market/main.go" + - id: observer_subscriber + binary: observer_subscriber + main: "./cmd/observer_subscriber/main.go" goos: - linux goarch: - amd64 env: - CGO_ENABLED=0 + - id: observer_notifier + binary: observer_notifier + main: "./cmd/observer_notifier/main.go" + goos: + - linux + goarch: + - amd64 + env: + - CGO_ENABLED=0 archives: - replacements: amd64: 64-bit From b71933b83a91eb4f8ed57df5bcf28cd9315919d8 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 11 Apr 2020 23:34:46 +0300 Subject: [PATCH 249/506] Add prometheus for internal monitoring (#1029) * Add basic metrics with prometheus * Finish with prometheus using old versions of it at this repo * Add test * Remove indirect deps --- api/middleware/prometheus.go | 38 ++++++ api/middleware/prometheus_test.go | 42 +++++++ api/registry.go | 3 + go.mod | 23 +--- go.sum | 193 +++++++++++++----------------- internal/init.go | 2 +- 6 files changed, 171 insertions(+), 130 deletions(-) create mode 100644 api/middleware/prometheus.go create mode 100644 api/middleware/prometheus_test.go diff --git a/api/middleware/prometheus.go b/api/middleware/prometheus.go new file mode 100644 index 000000000..0ca1d15cf --- /dev/null +++ b/api/middleware/prometheus.go @@ -0,0 +1,38 @@ +package middleware + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/prometheus/client_golang/prometheus" + "regexp" +) + +var labels = []string{"status", "endpoint", "method"} + +func Prometheus() gin.HandlerFunc { + serverReqCount := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: "atlas", + Name: "http_request_count_total", + Help: "Total number of HTTP requests made.", + }, labels, + ) + prometheus.MustRegister(serverReqCount) + + return func(c *gin.Context) { + c.Next() + + status := fmt.Sprintf("%d", c.Writer.Status()) + url := c.Request.URL.Path + method := c.Request.Method + + lvs := []string{status, removeAddress(url), method} + + serverReqCount.WithLabelValues(lvs...).Inc() + } +} + +func removeAddress(info string) string { + reg := regexp.MustCompile(`([a-zA-Z0-9\s]{30,})|([0-9]{4,})|(=(.*?)[^(&|$)]+)|(--[^$]+)|(&asset_contract_addresses)`) + return reg.ReplaceAllString(info, "") +} diff --git a/api/middleware/prometheus_test.go b/api/middleware/prometheus_test.go new file mode 100644 index 000000000..a3c952f9d --- /dev/null +++ b/api/middleware/prometheus_test.go @@ -0,0 +1,42 @@ +package middleware + +import ( + "github.com/chenjiandongx/ginprom" + "github.com/gin-gonic/gin" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/stretchr/testify/assert" + "net/http" + "testing" +) + +func TestPrometheus(t *testing.T) { + router := gin.New() + router.Use(Prometheus()) + router.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) + + w1 := performRequest("GET", "/metrics", router) + + assert.Equal(t, http.StatusOK, w1.Code) + assert.NotNil(t, w1.Body.String()) +} + +func Test_removeAddress(t *testing.T) { + tests := []struct { + name string + info string + want string + }{ + {"Remove Nimiq address", "/v1/nimiq/NQ43 J7G6 K6T8 H5KJ 5CXN Q5JK 2GJ4 6DSB 7PUH", "/v1/nimiq/"}, + {"Remove Tezos address", "/v1/tezos/tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", "/v1/tezos/"}, + {"Remove Tron info", "https://api.trongrid.io/v1/accounts/TPJYCz8ppZNyvw7pTwmjajcx4Kk1MmEUhD/transactions?limit=200&only_confirmed=true&token_id=1000011", "https://api.trongrid.io/v1/accounts//transactions?limit&only_confirmed&token_id"}, + {"Remove asset id", "https://api.trongrid.io/v1/assets/1000570?", "https://api.trongrid.io/v1/assets/?"}, + {"Remove collection id", "/v2/ethereum/collections//collection/---enjin-old", "/v2/ethereum/collections//collection/"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := removeAddress(tt.info); got != tt.want { + t.Errorf("removeSensitiveInfo() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/api/registry.go b/api/registry.go index 8d1518eaa..d2b1bce77 100644 --- a/api/registry.go +++ b/api/registry.go @@ -1,7 +1,9 @@ package api import ( + "github.com/chenjiandongx/ginprom" "github.com/gin-gonic/gin" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/trustwallet/blockatlas/api/endpoint" "github.com/trustwallet/blockatlas/api/middleware" "github.com/trustwallet/blockatlas/coin" @@ -110,6 +112,7 @@ func RegisterDomainAPI(root gin.IRouter) { func RegisterBasicAPI(root gin.IRouter) { root.GET("/", endpoint.GetRoot) root.GET("/status", endpoint.GetStatus) + root.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) } func IsForCustomAPI(handle string) bool { diff --git a/go.mod b/go.mod index 951e0f820..d9864f7c4 100644 --- a/go.mod +++ b/go.mod @@ -3,34 +3,18 @@ module github.com/trustwallet/blockatlas go 1.14 require ( - github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 - github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61 // indirect github.com/btcsuite/btcutil v1.0.1 - github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c // indirect - github.com/dancannon/gorethink v3.0.5+incompatible // indirect + github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 github.com/deckarep/golang-set v1.7.1 - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.4.0 // indirect - github.com/garyburd/redigo v1.6.0 // indirect github.com/getsentry/sentry-go v0.5.1 github.com/gin-gonic/gin v1.6.2 - github.com/go-stomp/stomp v2.0.5+incompatible // indirect - github.com/gocql/gocql v0.0.0-20200324094621-6d895e38b0a5 // indirect - github.com/gotestyourself/gotestyourself v1.4.0 // indirect - github.com/hashicorp/consul/api v1.4.0 // indirect github.com/jinzhu/gorm v1.9.12 - github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b // indirect github.com/mitchellh/mapstructure v1.2.2 github.com/mr-tron/base58 v1.1.3 - github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/opencontainers/runc v0.1.1 // indirect - github.com/ory-am/common v0.4.0 // indirect github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pborman/uuid v1.2.0 // indirect - github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da // indirect + github.com/prometheus/client_golang v1.5.1 github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc github.com/sirupsen/logrus v1.5.0 github.com/spf13/viper v1.6.2 @@ -42,8 +26,5 @@ require ( go.uber.org/atomic v1.6.0 golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e - gopkg.in/fatih/pool.v2 v2.0.0 // indirect - gopkg.in/gorethink/gorethink.v3 v3.0.5 // indirect gopkg.in/yaml.v2 v2.2.8 - gotest.tools v1.4.0 ) diff --git a/go.sum b/go.sum index 287aef217..b77b97796 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,22 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a h1:3SgJcK9l5uPdBC/X17wanyJAMxM33+4ZhEIV96MIH8U= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= +github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7 h1:mreN1m/5VJ/Zc3b4pzj9qU6D9SRQ6Vm+3KfI328t3S8= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -17,29 +25,24 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61 h1:Xz25cuW4REGC5W5UtpMU3QItMIImag615HiQcRbxqKQ= -github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61/go.mod h1:ikc1XA58M+Rx7SEbf0bLJCfBkwayZ8T5jBo5FXK8Uz8= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= -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/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= 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/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= -github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= @@ -54,7 +57,12 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 h1:3Wv1E0CqL45hBs4bykb586wvZMRGKfFITHrN3ilm4FE= +github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c h1:8ahmSVELW1wghbjerVAyuEYD5+Dio66RYvSS0iGfL1M= @@ -74,8 +82,6 @@ github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c h1:4e6Zsb6LFd3kadoM github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c/go.mod h1:k5D13LCXSsMrQyfdW0yGYs4GWUvirqoxHht8qwtqyRY= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/dancannon/gorethink v3.0.5+incompatible h1:AenyUfDNo7CUhNsA9qGVDIO/b5GzrnwjBRLZvlkb7jk= -github.com/dancannon/gorethink v3.0.5+incompatible/go.mod h1:BLvkat9KmZc1efyYwhz3WnybhRZtgF1K929FD8z1avU= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -95,20 +101,20 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= -github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/getsentry/sentry-go v0.5.1 h1:MIPe7ScHADsrK2vznqmhksIUFxq7m0JfTh+ZIMkI+VQ= github.com/getsentry/sentry-go v0.5.1/go.mod h1:B8H7x8TYDPkeWPRzGpIiFO97LZP6rL8A3hEt8lUItMw= @@ -124,10 +130,12 @@ github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6 github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM= github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= @@ -158,13 +166,9 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stomp/stomp v2.0.5+incompatible h1:EqEAa4yeAh6GG+ODG6fXzI3ZIa9ARoX+Gq+KSWwlWn4= -github.com/go-stomp/stomp v2.0.5+incompatible/go.mod h1:VqCtqNZv1226A1/79yh+rMiFUcfY3R109np+7ke4n0c= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/gocql/gocql v0.0.0-20200324094621-6d895e38b0a5 h1:LbX3qY8XXiD8kUJLvEsm3Hm2tjG3gQxThdmv9tW3cyI= -github.com/gocql/gocql v0.0.0-20200324094621-6d895e38b0a5/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -177,21 +181,21 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/snappy v0.0.0-20170215233205-553a64147049 h1:K9KHZbXKpGydfDN0aZrsoHpLJlZsBrGMFWbgLDGnPZk= -github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= @@ -204,50 +208,19 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92Bcuy github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= -github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= -github.com/hashicorp/consul/api v1.4.0 h1:jfESivXnO5uLdH650JU/6AnjRoHrLhULq0FnC3Kp9EY= -github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU= -github.com/hashicorp/consul/sdk v0.4.0 h1:zBtCfKJZcJDBvSCkQJch4ulp59m1rATFLKwNo/LYY30= -github.com/hashicorp/consul/sdk v0.4.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/schema v0.0.1 h1:10g/WnoRR+U+XXHWKBHeNy/+tZmM2kcAVGLOsz+yaDA= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= @@ -265,23 +238,33 @@ github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGn github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618 h1:MK144iBQF9hTSwBW/9eJm034bVoG30IshVm688T2hi8= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 h1:WQM1NildKThwdP7qWrNAFGzp4ijNLw8RlgENkaI4MJs= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/kataras/golog v0.0.9 h1:J7Dl82843nbKQDrQM/abbNJZvQjS6PfmkkffhOTXEpM= github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/iris/v12 v12.0.1 h1:Wo5S7GMWv5OAzJmvFTvss/C4TS1W0uo6LkDlSymT4rM= github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao= github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -304,19 +287,12 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b h1:v29yPGHhOqw7VHEnTeQFAth3SsBrmwc8JfuhNY0G34k= -github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b/go.mod h1:5MWrJXKRQyhQdUCF+vu6U5c4nQpg70vW3eHaU0/AYbU= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= @@ -326,17 +302,10 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= -github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -346,6 +315,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -357,9 +327,11 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -367,18 +339,10 @@ github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVo github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/ory-am/common v0.4.0 h1:edGPoxYX4hno0IJHXh9TCMUPR6ZcJp+y6aClFYxeuUE= -github.com/ory-am/common v0.4.0/go.mod h1:oCYGuwwM8FyYMKqh9vrhBaeUoyz/edx0bgJN6uS6/+k= -github.com/ory/dockertest v2.2.3+incompatible h1:eo4lG4wxzqGFObKl4C6ST7AjiLztTGojcQoFa6b8/cY= -github.com/ory/dockertest v2.2.3+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= @@ -389,36 +353,47 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA= +github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= 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/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/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/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= 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/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 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= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da h1:p3Vo3i64TCLY7gIfzeQaUJ+kppEO5WQG3cL8iE8tGHU= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -476,21 +451,30 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -504,7 +488,6 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -524,9 +507,7 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -545,11 +526,10 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -558,16 +538,18 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= +golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -603,28 +585,23 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg= -gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU= -gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v1.4.0 h1:BjtEgfuw8Qyd+jPvQz8CfoxiO/UjFEidWinwEXZiWv0= -gotest.tools v1.4.0/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/init.go b/internal/init.go index 5011df165..80b43872e 100644 --- a/internal/init.go +++ b/internal/init.go @@ -46,7 +46,7 @@ func InitEngine(handler *gin.HandlerFunc, ginMode string) *gin.Engine { engine.Use(middleware.CheckReverseProxy, *handler) engine.Use(middleware.CORSMiddleware()) engine.Use(gin.Logger()) - + engine.Use(middleware.Prometheus()) engine.OPTIONS("/*path", middleware.CORSMiddleware()) return engine From 49a24d0b514a55536bd716ca2afb797f6c398b05 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 12 Apr 2020 02:53:02 +0300 Subject: [PATCH 250/506] [Observer-Parser] Change tracker model to handle, not ID of coin (#1030) * Change tracker model to handle, not ID of coin * Remove models from codecov * Add tracker_test.go test * Add type for coin --- .codecov.yml | 1 + db/models/tracker.go | 2 +- db/tracker.go | 12 ++--- db/tracker_test.go | 64 +++++++++++++++++++++++ go.mod | 1 + go.sum | 14 ++--- services/observer/parser/parser.go | 4 +- tests/integration/db_test/tracker_test.go | 8 +-- 8 files changed, 82 insertions(+), 24 deletions(-) create mode 100644 db/tracker_test.go diff --git a/.codecov.yml b/.codecov.yml index ba09b162d..2eca65d92 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -16,3 +16,4 @@ coverage: - "services" - "scripts" - "docs" + - "db/models" diff --git a/db/models/tracker.go b/db/models/tracker.go index c5a03554f..723531df6 100644 --- a/db/models/tracker.go +++ b/db/models/tracker.go @@ -1,6 +1,6 @@ package models type Tracker struct { - Coin uint `gorm:"primary_key:true; auto_increment:false"` + Coin string `gorm:"primary_key:true; type:varchar(64)"` Height int64 } diff --git a/db/tracker.go b/db/tracker.go index 269e46792..1007e0b1f 100644 --- a/db/tracker.go +++ b/db/tracker.go @@ -8,28 +8,28 @@ import ( var memoryCache heightBlockMap func init() { - memoryCache.m = make(map[uint]int64) + memoryCache.m = make(map[string]int64) } type heightBlockMap struct { - m map[uint]int64 + m map[string]int64 sync.RWMutex } -func (hbm *heightBlockMap) SetHeight(coin uint, b int64) { +func (hbm *heightBlockMap) SetHeight(coin string, b int64) { hbm.Lock() defer hbm.Unlock() hbm.m[coin] = b } -func (hbm *heightBlockMap) GetHeight(coin uint) (int64, bool) { +func (hbm *heightBlockMap) GetHeight(coin string) (int64, bool) { hbm.RLock() defer hbm.RUnlock() b, ok := hbm.m[coin] return b, ok } -func (i *Instance) GetLastParsedBlockNumber(coin uint) (int64, error) { +func (i *Instance) GetLastParsedBlockNumber(coin string) (int64, error) { height, ok := memoryCache.GetHeight(coin) if ok { return height, nil @@ -41,7 +41,7 @@ func (i *Instance) GetLastParsedBlockNumber(coin uint) (int64, error) { return tracker.Height, nil } -func (i *Instance) SetLastParsedBlockNumber(coin uint, num int64) error { +func (i *Instance) SetLastParsedBlockNumber(coin string, num int64) error { memoryCache.SetHeight(coin, num) tracker := models.Tracker{ Coin: coin, diff --git a/db/tracker_test.go b/db/tracker_test.go new file mode 100644 index 000000000..a25121650 --- /dev/null +++ b/db/tracker_test.go @@ -0,0 +1,64 @@ +package db + +import ( + "github.com/DATA-DOG/go-sqlmock" + "github.com/jinzhu/gorm" + "github.com/stretchr/testify/assert" + "regexp" + "testing" +) + +func TestHeightBlockMap_SetHeight(t *testing.T) { + db, mock := setupDB(t) + defer db.Close() + mock.ExpectBegin() + mock.ExpectQuery( + regexp.QuoteMeta( + `INSERT INTO "trackers" ("coin","height") VALUES ($1,$2) ON CONFLICT (coin) DO UPDATE SET height = excluded.height RETURNING "trackers"."coin"`)).WithArgs("bitcoin", 1).WillReturnRows(sqlmock.NewRows([]string{"id"}). + AddRow("id")) + mock.ExpectCommit() + i := Instance{Gorm: db} + + assert.Nil(t, i.SetLastParsedBlockNumber("bitcoin", 1)) +} + +func TestHeightBlockMap_GetHeight(t *testing.T) { + db, mock := setupDB(t) + defer db.Close() + mock.ExpectBegin() + mock.ExpectQuery( + regexp.QuoteMeta( + `INSERT INTO "trackers" ("coin","height") VALUES ($1,$2) ON CONFLICT (coin) DO UPDATE SET height = excluded.height RETURNING "trackers"."coin"`)).WithArgs("bitcoin", 1).WillReturnRows(sqlmock.NewRows([]string{"id"}). + AddRow("id")) + mock.ExpectCommit() + i := Instance{Gorm: db} + + assert.Nil(t, i.SetLastParsedBlockNumber("bitcoin", 1)) + block, err := i.GetLastParsedBlockNumber("bitcoin") + assert.Nil(t, err) + assert.Equal(t, int64(1), block) + + mock.ExpectQuery( + regexp.QuoteMeta( + `SELECT * FROM "trackers" WHERE ("trackers"."coin" = $1`)).WithArgs("ethereum").WillReturnRows(sqlmock.NewRows([]string{"coin", "height"}). + AddRow("ethereum", 1)) + + b, err := i.GetLastParsedBlockNumber("ethereum") + assert.Nil(t, err) + assert.Equal(t, int64(1), b) + +} + +func setupDB(t *testing.T) (*gorm.DB, sqlmock.Sqlmock) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when sqlmock", err) + } + + d, err := gorm.Open("postgres", db) + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + d.LogMode(true) + return d, mock +} diff --git a/go.mod b/go.mod index d9864f7c4..62d4cb0c8 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/trustwallet/blockatlas go 1.14 require ( + github.com/DATA-DOG/go-sqlmock v1.4.1 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.1 github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 diff --git a/go.sum b/go.sum index b77b97796..ecb30a18b 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a h1:3SgJcK9l5 github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= +github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= +github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7 h1:mreN1m/5VJ/Zc3b4pzj9qU6D9SRQ6Vm+3KfI328t3S8= @@ -184,8 +186,6 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -263,13 +263,9 @@ github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= @@ -374,9 +370,8 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R 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/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 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= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -543,13 +538,10 @@ golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= -golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/services/observer/parser/parser.go b/services/observer/parser/parser.go index 86e6f6762..58195f013 100644 --- a/services/observer/parser/parser.go +++ b/services/observer/parser/parser.go @@ -79,7 +79,7 @@ func RunParser(params Params) { } func GetBlocksIntervalToFetch(params Params) (int64, int64, error) { - lastParsedBlock, err := params.Database.GetLastParsedBlockNumber(params.Api.Coin().ID) + lastParsedBlock, err := params.Database.GetLastParsedBlockNumber(params.Api.Coin().Handle) if err != nil { return 0, 0, errors.E(err, "Polling failed: tracker didn't return last known block number") } @@ -178,7 +178,7 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { if lastBlockNumber <= 0 { return errors.E(fmt.Sprintf("Parser of %s failed to save last block, lastBlockNumber <= 0", params.Api.Coin().Handle)) } - err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().ID, lastBlockNumber) + err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().Handle, lastBlockNumber) if err != nil { return err } diff --git a/tests/integration/db_test/tracker_test.go b/tests/integration/db_test/tracker_test.go index de443a5d0..4e63587a9 100644 --- a/tests/integration/db_test/tracker_test.go +++ b/tests/integration/db_test/tracker_test.go @@ -11,15 +11,15 @@ import ( func TestDb_SetBlock(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - assert.Nil(t, database.SetLastParsedBlockNumber(60, 0)) + assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 0)) - block, err := database.GetLastParsedBlockNumber(60) + block, err := database.GetLastParsedBlockNumber("ethereum") assert.Nil(t, err) assert.Equal(t, block, int64(0)) - assert.Nil(t, database.SetLastParsedBlockNumber(60, 110)) + assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 110)) - newBlock, err := database.GetLastParsedBlockNumber(60) + newBlock, err := database.GetLastParsedBlockNumber("ethereum") assert.Nil(t, err) assert.Equal(t, newBlock, int64(110)) } From b14ce93925b8b8c21b4bce0aab9d366dccabe0e5 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Mon, 13 Apr 2020 02:47:32 +0200 Subject: [PATCH 251/506] Mocked tests (#998) * Mocked tron staking tests: first 2 TCs. * Complete mocked Tron staking test. * Mocked Kava staking test. * Update RPC endpoints. * Cosmos Kava staking test. * Iotex staking test. * Fix cosmos tx test (merge 2 js files). * Fix kava tx test, merge 2 js files. * Fix iotex tx test, merge 2 js. * Enable staking tests in mocked newman tests. * Minor formatting, codacy. * Add mocked Tron token test. * Mocked ETC token test. * Remove console.log. * Mocked ETH token test. * Codacy: exclude all dyson mock JS files. Co-authored-by: Catenocrypt --- .codacy.yml | 3 + Makefile | 5 +- .../ext-api-dyson/get/cosmos-api-commands2.js | 3688 +++++++++++++++++ .../ext-api-dyson/get/cosmos-api-commands4.js | 44 + mock/ext-api-dyson/get/cosmos-api-txs.js | 524 --- mock/ext-api-dyson/get/eth-api-commands1.js | 196 + .../ext-api-dyson/get/eth-api-transactions.js | 75 - .../get/ethclassic-api-commands1.js | 91 + .../get/ethclassic-api-transactions.js | 60 - mock/ext-api-dyson/get/iotex-api-commands2.js | 823 ++++ mock/ext-api-dyson/get/iotex-api-commands4.js | 110 + mock/ext-api-dyson/get/iotex-get-accounts.js | 71 - mock/ext-api-dyson/get/kava-api-commands2.js | 2630 ++++++++++++ mock/ext-api-dyson/get/kava-api-commands4.js | 32 + ...et-accounts.js => tron-api-v1-accounts.js} | 91 +- mock/ext-api-dyson/get/tron-api-v1-assets.js | 103 + mock/ext-api-dyson/get/tron-api-wallet.js | 89 + mock/ext-api-dyson/post/harmony-api.js | 4 +- mock/ext-api-dyson/post/nano-api.js | 4 +- mock/ext-api-dyson/post/nimiq-rpc.js | 2 +- mock/ext-api-dyson/post/tron-api-wallet.js | 18 + 21 files changed, 7926 insertions(+), 737 deletions(-) create mode 100644 .codacy.yml create mode 100644 mock/ext-api-dyson/get/cosmos-api-commands2.js create mode 100644 mock/ext-api-dyson/get/cosmos-api-commands4.js delete mode 100644 mock/ext-api-dyson/get/cosmos-api-txs.js create mode 100644 mock/ext-api-dyson/get/eth-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/eth-api-transactions.js create mode 100644 mock/ext-api-dyson/get/ethclassic-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/ethclassic-api-transactions.js create mode 100644 mock/ext-api-dyson/get/iotex-api-commands2.js create mode 100644 mock/ext-api-dyson/get/iotex-api-commands4.js delete mode 100644 mock/ext-api-dyson/get/iotex-get-accounts.js create mode 100644 mock/ext-api-dyson/get/kava-api-commands2.js create mode 100644 mock/ext-api-dyson/get/kava-api-commands4.js rename mock/ext-api-dyson/get/{tron-get-accounts.js => tron-api-v1-accounts.js} (57%) create mode 100644 mock/ext-api-dyson/get/tron-api-v1-assets.js create mode 100644 mock/ext-api-dyson/get/tron-api-wallet.js create mode 100644 mock/ext-api-dyson/post/tron-api-wallet.js diff --git a/.codacy.yml b/.codacy.yml new file mode 100644 index 000000000..4b6a06df4 --- /dev/null +++ b/.codacy.yml @@ -0,0 +1,3 @@ +--- +exclude_paths: + - 'mock/ext-api-dyson/**' diff --git a/Makefile b/Makefile index e11e968d2..1169f6056 100644 --- a/Makefile +++ b/Makefile @@ -176,7 +176,10 @@ newman-mocked: install-newman install-dyson go-compile newman-mocked-params: start-platform-api-mock ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host) && \ - $(MAKE) newman-run test=domain host=$(host)" + $(MAKE) newman-run test=domain host=$(host) && \ + $(MAKE) newman-run test=staking host=$(host)" + #not-mocked-yet: $(MAKE) newman-run test=token host=$(host) && \ + #not-mocked-yet: $(MAKE) newman-run test=collection host=$(host) && @bash -c "$(MAKE) stop" else @bash -c "$(MAKE) newman-run test=$(test) host=$(host)" diff --git a/mock/ext-api-dyson/get/cosmos-api-commands2.js b/mock/ext-api-dyson/get/cosmos-api-commands2.js new file mode 100644 index 000000000..886ba5d4f --- /dev/null +++ b/mock/ext-api-dyson/get/cosmos-api-commands2.js @@ -0,0 +1,3688 @@ +/// Cosmos API Mock +/// See: +/// curl "http://localhost:3000/cosmos-api/staking/validators?status=bonded" +/// curl "http://localhost:3000/cosmos-api/staking/pool" +/// curl "http://localhost:3000/cosmos-api/minting/inflation" +/// curl "https://{cosmos_rpc}/staking/validators?status=bonded" +/// curl "https://{cosmos_rpc}/staking/pool" +/// curl "https://{cosmos_rpc}/minting/inflation" +/// curl "http://localhost:8420/v2/cosmos/staking/validators" +/// curl "http://localhost:8420/v2/cosmos/staking/delegations/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq?Authorization=Bearer" + +module.exports = { + path: "/cosmos-api/:command1/:command2?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch(params.command1) { + case 'minting': + switch(params.command2) { + case 'inflation': + // status=bonded + return JSON.parse(`{"height":"1419036","result":"0.070000000000000000"}`); + } + + case 'txs': { + if (query["transfer.recipient"] === 'cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq') { + return JSON.parse(` + { + "total_count": "1", + "count": "1", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "26616", + "txhash": "3FEE8F10FBA5505DE2A8D3EF220D5CE900CA76B96208234BBF89B8075743A230", + "data": "0C0886C1BEF00510E7FFF6F801", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "127111", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgUndelegate", + "value": { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", + "amount": { + "denom": "uatom", + "amount": "2203000" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" + }, + "signature": "fJkOgQX9FZz6UJJo48AA3qxc2v/vFrjxlMgq3iOhDmVUWjA2P6X+pPbPkSB1SHlBFlVbsNF/DDPB0pvP9LRPTg==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-12-13T20:13:58Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + } + ] + } + `); + } + + if (query["message.sender"] === 'cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq') { + return JSON.parse(` + { + "total_count": "2", + "count": "2", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "26616", + "txhash": "3FEE8F10FBA5505DE2A8D3EF220D5CE900CA76B96208234BBF89B8075743A230", + "data": "0C0886C1BEF00510E7FFF6F801", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "127111", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgUndelegate", + "value": { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", + "amount": { + "denom": "uatom", + "amount": "2203000" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" + }, + "signature": "fJkOgQX9FZz6UJJo48AA3qxc2v/vFrjxlMgq3iOhDmVUWjA2P6X+pPbPkSB1SHlBFlVbsNF/DDPB0pvP9LRPTg==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-12-13T20:13:58Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + }, + { + "height": "404179", + "txhash": "93E43518BAE4BC137605BBB7FD5D31FDAE6427ECE57EC299C43CE786FDAEBC63", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "delegate", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh" + }, + { + "key": "amount", + "value": "2211271" + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "delegate" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "93720", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgDelegate", + "value": { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", + "amount": { + "denom": "uatom", + "amount": "2211271" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" + }, + "signature": "X1/NzRdb+HUxE7N9gMk39XI8TyHFobLRQtsX4QxZZbYeKmEYOOZ7FyNSGqgmipCkpuysBeh6fNnbXmo3IFzFEQ==" + } + ], + "memo": "" + } + }, + "timestamp": "2020-01-13T15:23:12Z", + "events": [ + { + "type": "delegate", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh" + }, + { + "key": "amount", + "value": "2211271" + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "delegate" + } + ] + } + ] + } + ] + } + `); + } + } + + case 'staking': + switch(params.command2) { + case 'pool': + return JSON.parse(` + { + "height":"1419019", + "result": { + "not_bonded_tokens": "2422309183727", + "bonded_tokens": "182732778407119" + } + } + `); + + case 'validators': + return JSON.parse(` + { + "height": "1418977", + "result": [ + { + "operator_address": "cosmosvaloper1qdxmyqkvt8jsxpn5pp45a38ngs36mn2604cqk9", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmq2l5ehgl3rxwjgzgr6sgzp69qwjl5ufvtyvacc9ms8p3phazl2qh3ulfw", + "jailed": false, + "status": 2, + "tokens": "94117413314", + "delegator_shares": "94117413314.000000000000000000", + "description": { + "moniker": "真本聪\u0026IOSG", + "identity": "8A79F44CC25D26DF", + "website": "realsatoshi.net", + "details": "To The Moon Then Cosmos. We are a crypto community and venture capital combined staking service provider" + }, + "unbonding_height": "0", + "unbonding_time": "2019-06-24T19:55:42.604341211Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-08-05T07:24:32.572614545Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", + "consensus_pubkey": "cosmosvalconspub1zcjduepqwrjpn0slu86e32zfu5xxg8l42uk40guuw6er44vw2yl6s7wc38est6l0ux", + "jailed": false, + "status": 2, + "tokens": "5289222663449", + "delegator_shares": "5289222663449.000000000000000000", + "description": { + "moniker": "Certus One", + "identity": "ABD51DF68C0D1ECF", + "website": "https://certus.one", + "details": "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.125000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1qs8tnw2t8l6amtzvdemnnsq9dzk0ag0z52uzay", + "consensus_pubkey": "cosmosvalconspub1zcjduepqsszd2gzte82dzt0xpa3w0ky8lxhjs6zpd5ft8akmkscwujpftymsnt83qc", + "jailed": false, + "status": 2, + "tokens": "1605450345336", + "delegator_shares": "1605450345336.000000000000000000", + "description": { + "moniker": "Castlenode", + "identity": "F685CC35D748424C", + "website": "https://www.castlenode.com/cosmos", + "details": "Castlenode is a validator operator focused on security and run by experienced professionals. Please read our Terms and Conditions on our website before delegating" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.090000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1pz0lfq40sa63n0wany3v95x3yvznc5gyf8u28w", + "consensus_pubkey": "cosmosvalconspub1zcjduepqv03r9c26w884sqw0zdqg9cdx4xxwgn3dd2s6wa3x346tm83nxudqwhm3jl", + "jailed": false, + "status": 2, + "tokens": "296744671239", + "delegator_shares": "296744671239.000000000000000000", + "description": { + "moniker": "Cobo", + "identity": "3B7C85200D5B57A9", + "website": "https://cobo.com/", + "details": "Cobo is the first leading company in the world to offer Proof-of-Stake (PoS) and masternode rewards on user holdings, making it easy for users to grow their digital assets effortlessly." + }, + "unbonding_height": "0", + "unbonding_time": "2019-05-18T11:34:21.668987388Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-06-15T05:45:23.950986198Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1pgsjyvkg3y2m7qas534zzdhsqsxqyph2jh3uck", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5tycuhznpjuwlr93ypflreaddk0r66hdryzgmfvmlj2ekdd5sqrqnxclgg", + "jailed": false, + "status": 2, + "tokens": "228520445065", + "delegator_shares": "228520445065.000000000000000000", + "description": { + "moniker": "OneSixtyTwo", + "identity": "1C136F82A18BB2E2", + "website": "", + "details": "OneSixtyTwo" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-20T16:43:30.502949835Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", + "consensus_pubkey": "cosmosvalconspub1zcjduepqtcsm8lp7n6ph98vd59qa9esgyuysuntww9juz5wynxrhzpspmuuq6g5pzg", + "jailed": false, + "status": 2, + "tokens": "1125811000585", + "delegator_shares": "1125811000585.000000000000000000", + "description": { + "moniker": "WeStaking", + "identity": "DA9C5AD3E308E426", + "website": "https://www.westaking.io", + "details": "Delegate your atom to us for the staking rewards. We will do our best as secure and stable validator." + }, + "unbonding_height": "0", + "unbonding_time": "2019-09-07T12:24:58.270714195Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-29T00:37:22.163935678Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1pjmngrwcsatsuyy8m3qrunaun67sr9x7z5r2qs", + "consensus_pubkey": "cosmosvalconspub1zcjduepqcdav5ylt2zst90qmuh8e5w07xmxv9y6wufp5k9ngzmx7v9qewqtqkcq4z8", + "jailed": false, + "status": 2, + "tokens": "654800077136", + "delegator_shares": "654800077136.000000000000000000", + "description": { + "moniker": "Cypher Core", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1p650epkdwj0jte6sjc3ep0n3wz6jc9ehh8jutg", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmy5ja8dee3sprtmxkekcuvwz20y2x9d6llcsjl6p6553rpqev0eql6qccf", + "jailed": false, + "status": 2, + "tokens": "111582433714", + "delegator_shares": "111615914997.731210796675788592", + "description": { + "moniker": "Cosmos Suisse", + "identity": "2D875495A911A943", + "website": "https://cosmos-suisse.com", + "details": "An awesome Validator based in Crypto Valley, Switzerland." + }, + "unbonding_height": "970101", + "unbonding_time": "2020-03-21T06:33:36.130547135Z", + "commission": { + "commission_rates": { + "rate": "0.295000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-05T06:40:17.027131003Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1zqgheeawp7cmqk27dgyctd80rd8ryhqs6la9wc", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5tm478lhn4du7l46yp6fgu9e8fcfks0j4kf87pk4z8vc3clckxzqvh2q72", + "jailed": false, + "status": 2, + "tokens": "685457015651", + "delegator_shares": "685457015651.000000000000000000", + "description": { + "moniker": "melea-◮👁◭", + "identity": "4BE49EABAA41B8BF", + "website": "https://meleatrust.com/", + "details": "Validator service secure and trusted, awarded in Game Of Steaks" + }, + "unbonding_height": "0", + "unbonding_time": "2019-06-26T23:50:09.38840326Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-27T05:18:46.405341672Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1rpgtz9pskr5geavkjz02caqmeep7cwwpv73axj", + "consensus_pubkey": "cosmosvalconspub1zcjduepq04y0dtylyed2f8drc9t78dmptfuta7l6xyujwmsgrqefs0sxpgjsnzpsj6", + "jailed": false, + "status": 2, + "tokens": "3995820273418", + "delegator_shares": "3996619557261.806706040418750517", + "description": { + "moniker": "Blockpower", + "identity": "C374865C7ADE710B", + "website": "http://blockpower.capital/cosmos", + "details": "We self-bond 1m atoms and will keep our fee low till transfer enabled. We are top-ten validator in Tezos and operate professional staking services for multiple PoS platforms. Twitter: https://twitter.com/blockpowercap and TG: https://t.me/blockpowercosmos" + }, + "unbonding_height": "0", + "unbonding_time": "2019-11-04T04:14:24.222468286Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-31T19:58:53.172697095Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1r8kyvg4me2upnvlk26n2ay0zd5t4jktna8hhxp", + "consensus_pubkey": "cosmosvalconspub1zcjduepqsl29jhapyxf4fa5a947dmnlvrt266fm959hfg2c657ju80hq0ljs3qejr7", + "jailed": false, + "status": 2, + "tokens": "250002000000", + "delegator_shares": "250002000000.000000000000000000", + "description": { + "moniker": "noma", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-03-14T03:50:13.123302789Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1rwh0cxa72d3yle3r4l8gd7vyphrmjy2kpe4x72", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5kg8xls9l35ftulkm2rt70hexeeyr5cqqkcv4h7936z5uasvvazqla8eck", + "jailed": false, + "status": 2, + "tokens": "5699344397878", + "delegator_shares": "5699344397878.000000000000000000", + "description": { + "moniker": "SparkPool", + "identity": "DE8E37240061B04E", + "website": "https://cosmos.sparkpool.com/", + "details": "The biggest Ethereum mining pool, we can be a reliable validator with our 3 years" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.040000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-09-26T06:05:19.676181518Z" + }, + "min_self_delegation": "100000000000" + }, + { + "operator_address": "cosmosvaloper1rcp29q3hpd246n6qak7jluqep4v006cdsc2kkl", + "consensus_pubkey": "cosmosvalconspub1zcjduepq7mft6gfls57a0a42d7uhx656cckhfvtrlmw744jv4q0mvlv0dypskehfk8", + "jailed": false, + "status": 2, + "tokens": "243735228951", + "delegator_shares": "243735228951.000000000000000000", + "description": { + "moniker": "2nd only to Certus One in GoS: in3s.com", + "identity": "0CE19EE3E4BA48E5", + "website": "https://in3s.com/Services#CosmosValidator", + "details": "https://in3s.com/Delegate#Delegate" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-03-18T20:31:50.23335594Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1y0us8xvsvfvqkk9c6nt5cfyu5au5tww2ztve7q", + "consensus_pubkey": "cosmosvalconspub1zcjduepqqhkzzgfc876q287ny2v9lqwmjpenuzkzlsnstrmg7krwrrf0pfqs9fxvs0", + "jailed": false, + "status": 2, + "tokens": "12973804826", + "delegator_shares": "12973804826.000000000000000000", + "description": { + "moniker": "Swiss Staking", + "identity": "165F85FC0194320D", + "website": "https://swiss-staking.ch", + "details": "Experienced PoS Validator. We refund downtime slashing to 100%." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-12-11T18:25:42.711862818Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper19yy989ka5usws6gsd8vl94y7l6ssgdwsrnscjc", + "consensus_pubkey": "cosmosvalconspub1zcjduepqf22yaz9nsxlh043qm0tmupw8pnpver2n8lm3mwz6jzmsql76fkmqa482y8", + "jailed": false, + "status": 2, + "tokens": "500001550260", + "delegator_shares": "500001550260.000000000000000000", + "description": { + "moniker": "OKEx Pool", + "identity": "406C257E090E70AA", + "website": "http://www.okpool.top", + "details": "An innovative mining pool with higher yield" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-09-26T10:31:26.722694911Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1998928nfs697ep5d825y5jah0nq9zrtd00yyj7", + "consensus_pubkey": "cosmosvalconspub1zcjduepqlecm0rrfrr0vfgl624s7su9xvd3ycsaetndeuw2c7us0v8vfyfsq7cqz80", + "jailed": false, + "status": 2, + "tokens": "105880988262", + "delegator_shares": "105902167539.392512073112670643", + "description": { + "moniker": "HLT", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "2019-12-22T20:58:53.786852369Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-06-17T11:29:36.731435956Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper199mlc7fr6ll5t54w7tts7f4s0cvnqgc59nmuxf", + "consensus_pubkey": "cosmosvalconspub1zcjduepqajqpmv4j70a08ahs8lyjt8qk28ffa77zjegd7yajghchy8au575qmmxuyt", + "jailed": false, + "status": 2, + "tokens": "571392869594", + "delegator_shares": "571392869594.000000000000000000", + "description": { + "moniker": "Velocity V1", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-30T20:41:10.689796224Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "cosmosvaloper19v9ej55ataqrfl39v83pf4e0dm69u89rngf928", + "consensus_pubkey": "cosmosvalconspub1zcjduepqa32xgy8y5s69j6dynjmr3rlpv5dv35whz2tyaedwtjeqckm5gg4s2hj8ss", + "jailed": false, + "status": 2, + "tokens": "14356837431", + "delegator_shares": "14356837431.000000000000000000", + "description": { + "moniker": "blockscape", + "identity": "C46C8329BB5F48D8", + "website": "https://blockscape.network/", + "details": "By delegating, you confirm that you are aware of the risk of slashing and that M-Way Solutions GmbH is not liable for any potential damages to your investment." + }, + "unbonding_height": "483", + "unbonding_time": "2020-01-01T17:32:11.54021567Z", + "commission": { + "commission_rates": { + "rate": "0.099900000000000000", + "max_rate": "0.399900000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-02T09:18:02.304119479Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper19j2hd230c3hw6ds843yu8akc0xgvdvyuz9v02v", + "consensus_pubkey": "cosmosvalconspub1zcjduepq9ge7uqrfp9qkdapzd29tjtwrqpt2mm9meptx395ygxgm40tdc8ysrzj40a", + "jailed": false, + "status": 2, + "tokens": "441435636408", + "delegator_shares": "441435636408.000000000000000000", + "description": { + "moniker": "syncnode", + "identity": "F422F328C14AFBFA", + "website": "wallet.syncnode.ro", + "details": "email: g@ysncnode.ro || Operator's LinkedIn: https://www.linkedin.com/in/gbunea/ || Telegram Channel: https://t.me/syncnodeValidator || Blog: https://medium.com/syncnode-validator" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-15T11:41:35.747062104Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper19kwwdw0j64xhrmgkz49l0lmu5uyujjayxakwsn", + "consensus_pubkey": "cosmosvalconspub1zcjduepq668g4epaumjtx35rk3ucz2nlm7l7zuewkt0kzutg9hha859zjxmsvl2v67", + "jailed": false, + "status": 2, + "tokens": "630448698935", + "delegator_shares": "630448698935.000000000000000000", + "description": { + "moniker": "Firmamint", + "identity": "2FE4BC7A59E09FD0", + "website": "https://www.firmamint.io/", + "details": "The FUTURE is at STAKE - Proudly Canadian - Tier 1 WINNER of Game of Stakes Adversarial Testnet" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.030000000000000000" + }, + "update_time": "2019-03-18T22:02:43.333950761Z" + }, + "min_self_delegation": "1500000000" + }, + { + "operator_address": "cosmosvaloper1xym2qygmr9vanpa0m7ndk3n0qxgey3ffzcyd5c", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5evf9e4qhkxym6lx0ur2mwuz5e09u2v7u54yz3wcfanqwvhkc7rqcgpmlw", + "jailed": false, + "status": 2, + "tokens": "100726900000", + "delegator_shares": "100726900000.000000000000000000", + "description": { + "moniker": "🐡grant.fish", + "identity": "BE328F9A089F50C9", + "website": "http://grant.fish", + "details": "Providing grants to projects contributing to the Cosmos ecosystem." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-12-11T17:14:13.747872899Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1x8rr4hcf54nz6hfckyy2n05sxss54h8wz9puzg", + "consensus_pubkey": "cosmosvalconspub1zcjduepq8xpk5nh78lmgg0s0qqdyh4xtcw66xemt8anjsr6hrvlhauq252kstq7zr7", + "jailed": false, + "status": 2, + "tokens": "876463600211", + "delegator_shares": "876463600211.000000000000000000", + "description": { + "moniker": "cosmosgbt", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-10-18T04:22:16.555340871Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1x88j7vp2xnw3zec8ur3g4waxycyz7m0mahdv3p", + "consensus_pubkey": "cosmosvalconspub1zcjduepqhm6gjjkwecqyfrgey96s5up7drnspnl4t3rdr79grklkg9ff6zaqnfl2dg", + "jailed": false, + "status": 2, + "tokens": "2025689252407", + "delegator_shares": "2025689252407.000000000000000000", + "description": { + "moniker": "Staking Facilities", + "identity": "6B0DF6793DE1FB1F", + "website": "stakingfacilities.com", + "details": "Earn rewards with one of the most experienced and secure validators. More than 150k USD in customer rewards paid out. We exclude liability for any financial damage resulting from delegating." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-23T22:11:43.172644866Z" + }, + "min_self_delegation": "100000000000" + }, + { + "operator_address": "cosmosvaloper1x065cjlgejk2p2la0029akfvdy52gtq9mm58ta", + "consensus_pubkey": "cosmosvalconspub1zcjduepqny59kv2elgh89tq9qr4jje2n0my4gyvh2hlnydzljtt542a5plwswtas48", + "jailed": false, + "status": 2, + "tokens": "150298393037", + "delegator_shares": "150298393037.000000000000000000", + "description": { + "moniker": "MathWallet麦子钱包", + "identity": "58320327FF6C928C", + "website": "https://mathwallet.org", + "details": "Math Wallet is a powerful and secure universal crypto wallet that enables storage of all BTC, ETH/ERC20, NEO/NEP5, EOS/ENU/Telos, TRON, ONT, BinanceChain, Cosmos/IRISnet tokens, supports cross-chain token exchange and a multi-chain dApp store." + }, + "unbonding_height": "0", + "unbonding_time": "2019-07-21T13:52:13.251185336Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-09-09T03:44:27.230973438Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03xfytvz7", + "consensus_pubkey": "cosmosvalconspub1zcjduepqdgvppnyr5c9pulsrmzr9e9rp7qpgm9jwp5yu8g3aumekgjugxacq8a9p2c", + "jailed": false, + "status": 2, + "tokens": "5364854020103", + "delegator_shares": "5364854020103.000000000000000000", + "description": { + "moniker": "iqlusion", + "identity": "DCB176E79AE7D51F", + "website": "iqlusion.io", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "100000000000" + }, + { + "operator_address": "cosmosvaloper1gdg6qqe5a3u483unqlqsnullja23g0xvqkxtk0", + "consensus_pubkey": "cosmosvalconspub1zcjduepqlsvqw4vacnv2qtwxmm8tq32lrcdhau3szqxevrrzy8u0jvwz69pqphnkzk", + "jailed": false, + "status": 2, + "tokens": "76705740036", + "delegator_shares": "76705740036.000000000000000000", + "description": { + "moniker": "zugerselfdelegation", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-02-21T16:46:55.500729256Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1fqzqejwkk898fcslw4z4eeqjzesynvrdfr5hte", + "consensus_pubkey": "cosmosvalconspub1zcjduepqd4hvh0rwfkhtwrj4ly3ptyxs8pyfaser57wx2tcnzzp0rlref90sxm5kwr", + "jailed": false, + "status": 2, + "tokens": "412308417647", + "delegator_shares": "412308417647.000000000000000000", + "description": { + "moniker": "commercio.network", + "identity": "ADBDB0178E4441BE", + "website": "https://commercio.network", + "details": "The Documents Blockchain" + }, + "unbonding_height": "0", + "unbonding_time": "2019-06-23T11:25:09.272949514Z", + "commission": { + "commission_rates": { + "rate": "0.090000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-25T10:53:14.835657659Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ff0dw8kawsnxkrgj7p65kvw7jxxakyf8n583gx", + "consensus_pubkey": "cosmosvalconspub1zcjduepqu08f7tuce8k88tgewhwer69kfvk5az3cn5lz3v8phl8gvu9nxu8qhrjxfj", + "jailed": false, + "status": 2, + "tokens": "685381971996", + "delegator_shares": "685450516977.642009537883274736", + "description": { + "moniker": "Compass", + "identity": "72CB5AAAAFB1CE69", + "website": "http://val.network/", + "details": "EasyZone is a decentralized light client, which means users can access account, stake and earn rewords with local key store. For the time being we focus on Tendermint ecosystem, including Cosmos, QOS and Irisnet etc. Winner of the Game of Stakes." + }, + "unbonding_height": "0", + "unbonding_time": "2019-10-14T04:10:07.163539573Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2", + "consensus_pubkey": "cosmosvalconspub1zcjduepqzu34dgs2p6ysz52hpdycls4jcfwgnf2pvxv0eh539ypmadkjfmes6mwaa3", + "jailed": false, + "status": 2, + "tokens": "717001927145", + "delegator_shares": "717001927145.000000000000000000", + "description": { + "moniker": "POS Bakerz", + "identity": "3AFAE7268F4DFD10", + "website": "https://posbakerz.com/", + "details": "Secure, Reliable and Efficient Staking-as-a-Service" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-02T09:39:28.188566867Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", + "consensus_pubkey": "cosmosvalconspub1zcjduepquuc5k7egx8ymejamr27c3sgw6tyhmt0eq0ak4qvflvhxx56nvjzsx9etmd", + "jailed": false, + "status": 2, + "tokens": "3596427902503", + "delegator_shares": "3596427902503.000000000000000000", + "description": { + "moniker": "Huobi Wallet", + "identity": "CF01514DBF6583FE", + "website": "https://www.huobiwallet.com", + "details": "Huobi Wallet is a leading multi-chain wallet from Huobi Group and also offering competitive Proof-of-Stake (PoS) rewards for users to grow their digital assets. As a Cosmos validator, Huobi Wallet offers the one and only hard slashing insurance fund to our delegators" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-06T02:06:36.387455308Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper125umsz3fws7gepn5ccsh0sv4gre9r6a3tccz4r", + "consensus_pubkey": "cosmosvalconspub1zcjduepqkzserh5aetg6m33vrfcsuz60qpkgkpkpzkh8gp9lsd7cxffgph4qjzkxft", + "jailed": false, + "status": 2, + "tokens": "6281466956", + "delegator_shares": "6281466956.000000000000000000", + "description": { + "moniker": "Moonstake", + "identity": "742F7B64C32DF7A6", + "website": "https://www.moonstake.io/", + "details": "Shoot For The Moon" + }, + "unbonding_height": "950642", + "unbonding_time": "2020-03-19T15:59:10.375998429Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-03-03T10:05:22.79594206Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper124maqmcqv8tquy764ktz7cu0gxnzfw54n3vww8", + "consensus_pubkey": "cosmosvalconspub1zcjduepq279zs0zgd53ujngs6v2hus2le9rk2a2rs66j4yvv6ewvvxn29yqqk95h8x", + "jailed": false, + "status": 2, + "tokens": "636354488555", + "delegator_shares": "636354488555.000000000000000000", + "description": { + "moniker": "Simply Staking", + "identity": "F74595D6D5D568A2", + "website": "https://www.simply-vc.com.mt", + "details": "Simply VC runs highly reliable and secure infrastructure in our own datacentre in Malta, built with the aim of supporting the growth of the blockchain ecosystem." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-11T17:29:59.537654017Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "cosmosvaloper1tflk30mq5vgqjdly92kkhhq3raev2hnz6eete3", + "consensus_pubkey": "cosmosvalconspub1zcjduepqwcvy8hyw2phdp080ggj7prxv972rvqc9gwyjnl0uwf7uxn63s8vqdctdcw", + "jailed": false, + "status": 2, + "tokens": "164930806828", + "delegator_shares": "164930806828.000000000000000000", + "description": { + "moniker": "Everstake", + "identity": "", + "website": "https://everstake.one", + "details": "Reliable and experienced staking service provider from Ukraine. Visit our website for more details." + }, + "unbonding_height": "0", + "unbonding_time": "2019-12-07T19:10:59.878559804Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-07-14T19:56:46.186760169Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ttfytaf43nkytzp8hkfjfgjc693ky4t3y2n2ku", + "consensus_pubkey": "cosmosvalconspub1zcjduepq2nfs6lcwu6ksq54yf0ptgrmjjrnm5p5ywng3x0t0767m777hvctq30rwcs", + "jailed": false, + "status": 2, + "tokens": "68002415747", + "delegator_shares": "68009216666.737140135826986143", + "description": { + "moniker": "StarCluster", + "identity": "F97B6EF4FD82202F", + "website": "https://starcluster.tech", + "details": "With decades of passion invested in tech, we provide a team of top security and infrastructure engineers as a service. With extensive knowledge in the blockchain space and having run a successful ICO, we are confident that providing our experience \u0026 skills could benefit many." + }, + "unbonding_height": "0", + "unbonding_time": "2019-12-24T15:27:58.293852371Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.150000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-10-26T21:50:11.42045872Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v", + "consensus_pubkey": "cosmosvalconspub1zcjduepqjg26g27dtvjqstyqktmp4jsn98473vfz0mek2eyklfp0yqapav5szdrvpd", + "jailed": false, + "status": 2, + "tokens": "3519949961612", + "delegator_shares": "3519949961612.000000000000000000", + "description": { + "moniker": "CoinoneNode", + "identity": "F4E86EE9BD73A11F", + "website": "https://node.coinone.co.kr", + "details": "The more, the easier. Coinone Node manages your assets securely." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-14T09:22:28.276013718Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1vrg6ruw00lhszl4sjgwt5ldvl8z0f7pfp5va85", + "consensus_pubkey": "cosmosvalconspub1zcjduepq2hfnf0rvk6nksvtzkqly4vy362sencfkt7tgsrvx30krj5vxw0asa7hmjh", + "jailed": false, + "status": 2, + "tokens": "342783139733", + "delegator_shares": "342783139733.000000000000000000", + "description": { + "moniker": "SSSnodes", + "identity": "C5B68615F8828EC0", + "website": "http://sssnodes.com/cosmos", + "details": "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by SSSnodes, a Corp. focused on delegation service for multiple Proof of Stake networks, such as COSMOS, ChainX, IOST, CyberMiles, Lambda, ONT, etc." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.018000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-28T08:09:59.47667909Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1vf44d85es37hwl9f4h9gv0e064m0lla60j9luj", + "consensus_pubkey": "cosmosvalconspub1zcjduepqtj2urav4g9wex3hku588au0x4sucrc9lpky46zp5u8w4mvd584sqmcxxhs", + "jailed": false, + "status": 2, + "tokens": "7246081767965", + "delegator_shares": "7246081767965.000000000000000000", + "description": { + "moniker": "MultiChain Ventures", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-08-21T08:01:01.670548948Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1v5y0tg0jllvxf5c3afml8s3awue0ymju89frut", + "consensus_pubkey": "cosmosvalconspub1zcjduepq9kun5ty55rl3lnmf46tfxhj06as8h7zpxcdhujm6d708ffn6kgss43q6u9", + "jailed": false, + "status": 2, + "tokens": "5856792267830", + "delegator_shares": "5856792267830.000000000000000000", + "description": { + "moniker": "Zero Knowledge Validator (ZKV)", + "identity": "3E38E52A12F94561", + "website": "https://zkvalidator.com/", + "details": "Zero Knowledge Validator: Stake \u0026 Support ZKP Research \u0026 Privacy Tech" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-11T15:48:18.737920871Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1vk706z2tfnqhdg6jrkngyx7f463jq58nj0x7p7", + "consensus_pubkey": "cosmosvalconspub1zcjduepq0qdudwaluzpy5ptluu5umck5fp2ns2qf2kjp367qlr7yf65agx5s0n8h7f", + "jailed": false, + "status": 2, + "tokens": "26192977888", + "delegator_shares": "26192977888.000000000000000000", + "description": { + "moniker": "Public Payments", + "identity": "1850627141D54797", + "website": "https://www.publicpayments.io", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-02T12:25:53.791107872Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1d0aup392g3enru7eash83sedqclaxvp7fzh6gk", + "consensus_pubkey": "cosmosvalconspub1zcjduepql9j7qpwvfl0pspymhesj48t3t0aazjx0m2jwjuyxd7zw53hqnkss4hmasl", + "jailed": false, + "status": 2, + "tokens": "194657773848", + "delegator_shares": "194677241406.157421240224999535", + "description": { + "moniker": "Stir", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "2019-06-21T20:37:09.115641759Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-14T13:03:10.437070061Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1dse76yk5jmj85jsd77ewsczc4k3u4s7a870wtj", + "consensus_pubkey": "cosmosvalconspub1zcjduepqjdc9grwq5mxdtg26hv9t75y3ltsau3rtmg6p72p0dh8343nj4s6qr6xymd", + "jailed": false, + "status": 2, + "tokens": "399992036873", + "delegator_shares": "400032040000.820061751426683457", + "description": { + "moniker": "gf.network", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "10001", + "unbonding_time": "2020-01-02T11:58:18.459331455Z", + "commission": { + "commission_rates": { + "rate": "0.080000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-27T12:23:08.242833465Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1de7qx00pz2j6gn9k88ntxxylelkazfk3g8fgh9", + "consensus_pubkey": "cosmosvalconspub1zcjduepqwr5p8j076mfydn7wckqz748lr0j50zwgsftnfpvgz6rz0rkvvqwqg5fyaf", + "jailed": false, + "status": 2, + "tokens": "222020931706", + "delegator_shares": "222020931706.000000000000000000", + "description": { + "moniker": "Cosmic Validator", + "identity": "FF4B91B50B71CEDA", + "website": "", + "details": "A reliable, passionate and service oriented Cosmos, Polkadot and Sentinel validator. We are long term trusted community members and have received delegation from the Interchain Foundation (ICF) as a reward for our continuous support and effort." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-10-07T05:35:40.25581859Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1d7ufwp2rgfj7s7pfw2q7vm2lc9txmr8vh77ztr", + "consensus_pubkey": "cosmosvalconspub1zcjduepq2x456pyef8jdnjgk8j62fuug24xfg9cnnjl66ewtgttwr00phz8sdzatkj", + "jailed": false, + "status": 2, + "tokens": "117924360855", + "delegator_shares": "117924360855.000000000000000000", + "description": { + "moniker": "Cybernetic Destiny", + "identity": "", + "website": "", + "details": "The future you’ve always wanted." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-02-07T23:19:03.834895518Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1wp9jne5t3e4au7u8gfep90g59j0qdhpeqvlg7n", + "consensus_pubkey": "cosmosvalconspub1zcjduepq6740f8r23xr74w94l5ew9fh6n8wquutgm22pw6yyrydq507mgdkqghsjtd", + "jailed": false, + "status": 2, + "tokens": "92787621513", + "delegator_shares": "92787621513.000000000000000000", + "description": { + "moniker": "Newroad Network", + "identity": "F898ACE263EC1C4E", + "website": "https://newroad.network/cosmos/", + "details": "We provide a professional delegation service for multiple Proof of Stake networks. We use a secure and redundant setup. Visit our website for more information." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-02-26T08:44:32.038638755Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1wtv0kp6ydt03edd8kyr5arr4f3yc52vp3u2x3u", + "consensus_pubkey": "cosmosvalconspub1zcjduepq0zyaquh6c8vmjfzft43uqylf2ejjpjcvup2zrtsk40uyz8xsq29s0k4eaw", + "jailed": false, + "status": 2, + "tokens": "353202000001", + "delegator_shares": "353202000001.000000000000000000", + "description": { + "moniker": "kytzu", + "identity": "909A480D5643CCC5", + "website": "https://www.linkedin.com/in/calinchitu", + "details": "Blockchain consultant, running on IPSX infrastructure (calin@ip.sx)" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-07-13T04:46:58.395203387Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "cosmosvaloper1wdrypwex63geqswmcy5qynv4w3z3dyef2qmyna", + "consensus_pubkey": "cosmosvalconspub1zcjduepqs0et7kpf82glsw5j9jnppekrpa7kl6gr6xk67ztqg9ynmhgj82ks9edcrw", + "jailed": false, + "status": 2, + "tokens": "457217580134", + "delegator_shares": "457217580134.000000000000000000", + "description": { + "moniker": "Genesis Lab", + "identity": "C1A123F2723041F0", + "website": "https://genesislab.net", + "details": "Genesis Lab is a blockchain-focused development company and validation nodes operator in PoS networks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-15T17:32:00.387570437Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1wd8vquxza6svsvvnh489tdvg9vdjjfpepcfvf9", + "consensus_pubkey": "cosmosvalconspub1zcjduepqf4qptg2va4frg7g35c4plnlq0ngny64qv34a9vzhy39vuv8jwjfsexun5p", + "jailed": false, + "status": 2, + "tokens": "6427445224", + "delegator_shares": "6427445224.000000000000000000", + "description": { + "moniker": "DeBank", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-12-25T08:04:37.22829156Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1wwspfe7whh3zu4ql5rvpg044lyk6cuu7fpnd9e", + "consensus_pubkey": "cosmosvalconspub1zcjduepqz7ylkz6wapcwa5k3gn7vh6efd0qk7cqwp2rxh5lf0l7lhvsh4m8qhgp2zf", + "jailed": false, + "status": 2, + "tokens": "5699129041", + "delegator_shares": "5699129041.000000000000000000", + "description": { + "moniker": "Bit Cat🐱", + "identity": "FAB46CEEAEAB9FA1", + "website": "https://www.bitcat365.com", + "details": "Secure and stable validator service from China team" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-07-30T09:12:32.806551501Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1w0494h0l4mneaq7ajkrcjvn73m2n04l87j2nst", + "consensus_pubkey": "cosmosvalconspub1zcjduepquxeuhp0gj88u5mrukuazzrxc4rnjjuakls4fr2gzxlwj4f9p8lfs965r7z", + "jailed": false, + "status": 2, + "tokens": "96449451062", + "delegator_shares": "96478391551.647848054450574736", + "description": { + "moniker": "Angel", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "804087", + "unbonding_time": "2020-03-07T13:08:49.834368524Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.500000000000000000" + }, + "update_time": "2019-03-18T15:40:26.600089741Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1w42lm7zv55jrh5ggpecg0v643qeatfkd9aqf3f", + "consensus_pubkey": "cosmosvalconspub1zcjduepqz679nxu2dkfd6y9hytqwvf2z4yuevraqykkm2464ag4e6z278h3qdq92xu", + "jailed": false, + "status": 2, + "tokens": "761888512720", + "delegator_shares": "761888512720.000000000000000000", + "description": { + "moniker": "Mythos", + "identity": "2E9FDF34351A5112", + "website": "https://mythos.services", + "details": "Staking and validator services for crypto networks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw", + "consensus_pubkey": "cosmosvalconspub1zcjduepq6adydsk7nw3d63qtn30t5rexhfg56pq44sw4l9ld0tcj6jvnx30s5xw9ar", + "jailed": false, + "status": 2, + "tokens": "1817891090486", + "delegator_shares": "1817891090486.000000000000000000", + "description": { + "moniker": "Staked", + "identity": "E7BFA6515FB02B3B", + "website": "https://staked.us/", + "details": "Staked operates highly available and highly secure, institutional grade staking infrastructure for leading proof-of-stake (PoS) protocols." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.020000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1wauge4px27c257nfn4k3329wteddqw7gs3n66u", + "consensus_pubkey": "cosmosvalconspub1zcjduepqqaffdhuhdtr0d6nl8twpraxps74q3mxn68qknrex465yd9cc9l0qeh6lkk", + "jailed": false, + "status": 2, + "tokens": "166849428224", + "delegator_shares": "166849428224.000000000000000000", + "description": { + "moniker": "DappPub", + "identity": "BB2D113EFC6DFDC4", + "website": "https://dapp.pub", + "details": "DappPub, Unleashing the Power of DApps" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-05-15T10:37:35.020580984Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper102ruvpv2srmunfffxavttxnhezln6fnc54at8c", + "consensus_pubkey": "cosmosvalconspub1zcjduepq9weu2v0za8fdcvx0w3ps972k5v7sm6h5as9qaznc437vwpfxu37q0f3lyg", + "jailed": false, + "status": 2, + "tokens": "419722382279", + "delegator_shares": "419722382279.000000000000000000", + "description": { + "moniker": "Ztake.org", + "identity": "09A303A2C724C591", + "website": "https://ztake.org/", + "details": "Support reliable independent validator" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-08-14T05:12:52.848294105Z" + }, + "min_self_delegation": "10" + }, + { + "operator_address": "cosmosvaloper1000ya26q2cmh399q4c5aaacd9lmmdqp90kw2jn", + "consensus_pubkey": "cosmosvalconspub1zcjduepqe93asg05nlnj30ej2pe3r8rkeryyuflhtfw3clqjphxn4j3u27msrr63nk", + "jailed": false, + "status": 2, + "tokens": "457608104422", + "delegator_shares": "457608104422.000000000000000000", + "description": { + "moniker": "Staking Fund", + "identity": "805F39B20E881861", + "website": "https://www.staking.fund", + "details": "Staking Fund has been participating in the validating role since early 2018 and is a proud member of the Never Jailed Crew of Game of Stakes." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "0.334000000000000000", + "max_change_rate": "0.012019031323000000" + }, + "update_time": "2020-02-02T00:47:46.138000758Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper10nzaaeh2kq28t3nqsh5m8kmyv90vx7ym5mpakx", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmuspsp8739l0lgn2qz0arargk6ccfy2p82mwflsrsqzwpvhuh5usuwykf6", + "jailed": false, + "status": 2, + "tokens": "73145988986", + "delegator_shares": "73145988986.000000000000000000", + "description": { + "moniker": "Blockdaemon", + "identity": "8F898657DE26D645", + "website": "https://blockdaemon.com/node-marketplace/#staking", + "details": "Blockdaemon provides maximum uptime for the Cosmos network so that you can be confident your node will be there, ready and secure, for optimal reward generation. Contact us to stake on Cosmos today." + }, + "unbonding_height": "0", + "unbonding_time": "2019-12-19T03:19:44.114438899Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-10-29T19:55:36.41178089Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper10e4vsut6suau8tk9m6dnrm0slgd6npe3jx5xpv", + "consensus_pubkey": "cosmosvalconspub1zcjduepqteacnywz7urnac46wtrcy34myyj82j250ny7866yffypdgavae5s0lf4a0", + "jailed": false, + "status": 2, + "tokens": "3607499246627", + "delegator_shares": "3607499246627.000000000000000000", + "description": { + "moniker": "B-Harvest", + "identity": "8957C5091FBF4192", + "website": "https://bharvest.io", + "details": "B-Harvest focus on the value of high standard security \u0026 stability, active community participation on Cosmos Network, and real world practical use-case of blockchain technology." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-24T11:21:51.694254562Z" + }, + "min_self_delegation": "9000000000" + }, + { + "operator_address": "cosmosvaloper1sxx9mszve0gaedz5ld7qdkjkfv8z992ax69k08", + "consensus_pubkey": "cosmosvalconspub1zcjduepqjnnwe2jsywv0kfc97pz04zkm7tc9k2437cde2my3y5js9t7cw9mstfg3sa", + "jailed": false, + "status": 2, + "tokens": "2545294437814", + "delegator_shares": "2545294437814.000000000000000000", + "description": { + "moniker": "validator.network | Security first. Highly available.", + "identity": "357F80896B3311B4", + "website": "https://validator.network", + "details": "Highly resilient and secure validator operating out of Northern Europe. See website for terms of service." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-06-30T08:32:22.562118158Z" + }, + "min_self_delegation": "100000000" + }, + { + "operator_address": "cosmosvaloper1sd4tl9aljmmezzudugs7zlaya7pg2895ws8tfs", + "consensus_pubkey": "cosmosvalconspub1zcjduepq8y846wm58fmmuctxp7csqmaz3594xnykcean0lp722ntf6u5ycaqss4prd", + "jailed": false, + "status": 2, + "tokens": "1080650483982", + "delegator_shares": "1080650483982.000000000000000000", + "description": { + "moniker": "InfStones (Infinity Stones)", + "identity": "39A41C2FDE0AD040", + "website": "https://infstones.io", + "details": "Fueling Blockchain Beyond Infinity!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-05-10T06:56:55.530159974Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1s05va5d09xlq3et8mapsesqh6r5lqy7mkhwshm", + "consensus_pubkey": "cosmosvalconspub1zcjduepqgx5xdrx0xktl5r8e3w7vj329fgh3fnep8ahgx8027nd5nkjxzuqs5us5en", + "jailed": false, + "status": 2, + "tokens": "557166703758", + "delegator_shares": "557166703758.000000000000000000", + "description": { + "moniker": "Wetez", + "identity": "26FA2B24F46A98EF", + "website": "https://www.wetez.io", + "details": "Wetez is the most professional team in the POS ( Proof of Stake) field.Wetez是POS领域最专业的团队,为POS带来的权益做更多赋能。" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-03-25T02:35:12.908955321Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ssm0d433seakyak8kcf93yefhknjleeds4y3em", + "consensus_pubkey": "cosmosvalconspub1zcjduepqrgyyjxpe0ujefxwnkpmqz9m0hj03y09tdz9lwc0s7mvy469hulfq69f8sd", + "jailed": false, + "status": 2, + "tokens": "1548438266517", + "delegator_shares": "1548438266517.000000000000000000", + "description": { + "moniker": "IRISnet-Bianjie", + "identity": "DB667A6F239969F5", + "website": "https://irisnet.org/irisnet-bianjie", + "details": "Interchain Service Hub for NextGen Distributed Applications." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.020000000000000000" + }, + "update_time": "2019-06-21T04:33:57.044358454Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9u2lcnj0", + "consensus_pubkey": "cosmosvalconspub1zcjduepq6fpkt3qn9xd7u44478ypkhrvtx45uhfj3uhdny420hzgsssrvh3qnzwdpe", + "jailed": false, + "status": 2, + "tokens": "12598748851227", + "delegator_shares": "12598748851227.000000000000000000", + "description": { + "moniker": "🐠stake.fish", + "identity": "90B597A673FC950E", + "website": "stake.fish", + "details": "We are the leading staking service provider for blockchain projects. Join our community to help secure networks and earn rewards. We know staking." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.040000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1s6x9fy4wc49wj9jx4jv6czredqsmp46h7vnk2q", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfkkyuexns2l7rw2mx2ms988heah0rjv42e9q88scc3ms5hzg45psycrvr4", + "jailed": false, + "status": 2, + "tokens": "735675714417", + "delegator_shares": "735675714417.000000000000000000", + "description": { + "moniker": "SNZPool", + "identity": "FF2019D4CF1F3185", + "website": "https://snzholding.com", + "details": "SNZ is a crypto assets capital, consulting agency, community builder and professional \u0026 reliable POS validator for a dozen of projects like Cosmos, IRISnet, EOS, ONT, Loom, etc." + }, + "unbonding_height": "0", + "unbonding_time": "2019-05-31T14:02:51.669843605Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1s6t3wzx6mcv3pjg5fp2ddzplm3gj4pg6d330wg", + "consensus_pubkey": "cosmosvalconspub1zcjduepqncdd6lvm4r42eke822e5eg0alentpvlxjwzat7nvpynlp0vcu55sl5z96g", + "jailed": false, + "status": 2, + "tokens": "245002260000", + "delegator_shares": "245002260000.000000000000000000", + "description": { + "moniker": "omega3", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-03-22T01:22:56.42711479Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1s65zmn32zugl57ysj47s7vmfcek0rtd7he7wde", + "consensus_pubkey": "cosmosvalconspub1zcjduepqrc6g9m2eyy4zs7kyeph8vk5ldpgnceveelc39zf7lc32j8k3shqssevdlg", + "jailed": false, + "status": 2, + "tokens": "194202250000", + "delegator_shares": "194202250000.000000000000000000", + "description": { + "moniker": "firstblock", + "identity": "23D9B8528FC93D58", + "website": "https://firstblock.io", + "details": "You Delegate. We Validate." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-09T03:45:47.112144406Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1s7jnk7t6yqzensdgpvkvkag022udk842qdjdtd", + "consensus_pubkey": "cosmosvalconspub1zcjduepqnnh28nlj55sc329ppnhcr0xx7kuc9vnsp3dpwc28wdhhxtjc7jfs9k57f7", + "jailed": false, + "status": 2, + "tokens": "336505666793", + "delegator_shares": "336505666793.000000000000000000", + "description": { + "moniker": "Blockscale", + "identity": "F38EDEA063FD446C", + "website": "https://blockscale.net", + "details": "Planet-scale blockchain infrastructure." + }, + "unbonding_height": "0", + "unbonding_time": "2019-06-14T07:33:07.032714186Z", + "commission": { + "commission_rates": { + "rate": "0.250000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-09-21T01:23:56.63727699Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper132juzk0gdmwuxvx4phug7m3ymyatxlh9734g4w", + "consensus_pubkey": "cosmosvalconspub1zcjduepq9xu9z6ky3nz3k544ar4zhupjehkxdlpmt2l90kekxkrvuu7hxfgslcdqwy", + "jailed": false, + "status": 2, + "tokens": "2451022343872", + "delegator_shares": "2451022343872.000000000000000000", + "description": { + "moniker": "P2P.ORG - P2P Validator", + "identity": "E12F4695036D8072", + "website": "https://p2p.org", + "details": "One of the winners of Cosmos Game of Stakes. We provide a simple, secure and intelligent staking service to help you generate rewards on your blockchain assets across 9+ networks within a single interface. Let’s stake together - p2p.org." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-11T17:13:40.302520375Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper130mdu9a0etmeuw52qfxk73pn0ga6gawkxsrlwf", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfahazsjeru5wqulfuzklmkh272ggss2ru6fk00zq2fmlfzcq773sqlqe42", + "jailed": false, + "status": 2, + "tokens": "1127978319378", + "delegator_shares": "1127978319378.000000000000000000", + "description": { + "moniker": "jackzampolin", + "identity": "0979483D4F669CFF", + "website": "https://pylonvalidator.com", + "details": "'You must construct additional pylons' -StarCraft" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.150000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-03-25T15:28:01.171914203Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper13sduv92y3xdhy3rpmhakrc3v7t37e7ps9l0kpv", + "consensus_pubkey": "cosmosvalconspub1zcjduepqqddwwkhkfrsd66u49kg3h6q36t4kv557vlszqaed4c3y936ncq9s0r0tm2", + "jailed": false, + "status": 2, + "tokens": "1647613576303", + "delegator_shares": "1647613576303.000000000000000000", + "description": { + "moniker": "nylira.net", + "identity": "6A0D65E29A4CBC8E", + "website": "https://nylira.net", + "details": "Stake and earn with security and peace of mind. Operated by Peng Zhong." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-14T21:33:23.86382871Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper13ce7hhqa0z3tpc2l7jm0lcvwe073hdkkpp2nst", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmx0dcpmd9uq7ueck8d880lrt8tp9kvkfmaz0mtv0arye2cda2zrsrlla3n", + "jailed": false, + "status": 2, + "tokens": "61552309043", + "delegator_shares": "61552309043.000000000000000000", + "description": { + "moniker": "RockX", + "identity": "A15B586AB203F14E", + "website": "www.rockx.com", + "details": "Unlocking the full value of digital assets and decentralized governance" + }, + "unbonding_height": "0", + "unbonding_time": "2019-12-24T17:24:12.507160243Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-09-05T08:00:55.144718017Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1jxv0u20scum4trha72c7ltfgfqef6nsch7q6cu", + "consensus_pubkey": "cosmosvalconspub1zcjduepqnru7aa6ayyuwddd5qsa6tvutzs7xl9jk6pfx4ka5dr4y9d3q6eesgz9rz7", + "jailed": false, + "status": 2, + "tokens": "302293155457", + "delegator_shares": "302293155457.000000000000000000", + "description": { + "moniker": "Ping.pub", + "identity": "6EA723DA332200B2", + "website": "https://ping.pub", + "details": "We are one of the most secure and stable validator, welcome to delegate to us. 我们是最安全,最稳定,性价比最高的验证人节点,欢迎委托给我们!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.200000000000000000" + }, + "update_time": "2019-11-18T12:14:35.328556Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1j0vaeh27t4rll7zhmarwcuq8xtrmvqhudrgcky", + "consensus_pubkey": "cosmosvalconspub1zcjduepqvn4a4skwj88c8e0jvns3qjrhyy0whvnuwmth3k8kexvqk5vupw4qsdje47", + "jailed": false, + "status": 2, + "tokens": "1071888285988", + "delegator_shares": "1071888285988.000000000000000000", + "description": { + "moniker": "chainflow-cosmos-prodval-01", + "identity": "81D443FA08A4A926", + "website": "https://chainflow.io/cosmos", + "details": "Operated by Chris Remus (Twitter @cjremus) / Validating since the Validator Working Group formed in October 2017" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-04-01T15:19:20.666364183Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1jlr62guqwrwkdt4m3y00zh2rrsamhjf9num5xr", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5e8w7t7k9pwfewgrwy8vn6cghk0x49chx64vt0054yl4wwsmjgrqfackxm", + "jailed": false, + "status": 2, + "tokens": "723622196447", + "delegator_shares": "723622196447.000000000000000000", + "description": { + "moniker": "StakeWith.Us", + "identity": "609F83752053AD57", + "website": "https://stakewith.us", + "details": "Secured Staking Made Easy. Put Your Crypto to Work - Hassle Free. Disclaimer: Delegators should understand that delegation comes with slashing risk. By delegating to StakeWithUs Pte Ltd, you acknowledge that StakeWithUs Pte Ltd is not liable for any losses on your investment." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-04-22T12:01:25.715205208Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1n5pu2rtz4e2skaeatcmlexza7kheedzh8a2680", + "consensus_pubkey": "cosmosvalconspub1zcjduepqnd9kzfhhvuv5k2cq62yu0e5v73ymsgxa0wlen9c7999ucwg7hg6qdm34pm", + "jailed": false, + "status": 2, + "tokens": "576060849627", + "delegator_shares": "576060849627.000000000000000000", + "description": { + "moniker": "BlockMatrix 🚀", + "identity": "DA33F58EC17769B4", + "website": "https://blockmatrix.network", + "details": "Experienced validator across multiple PoS and DPoS networks. Winners in the Game of Stakes. Cosmos FTW!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "10" + }, + { + "operator_address": "cosmosvaloper1nm0rrq86ucezaf8uj35pq9fpwr5r82clzyvtd8", + "consensus_pubkey": "cosmosvalconspub1zcjduepqsnngsdda53d9aqwezvpsx4uh2nkwkn4nra5lw4tyl9n3m02q4kvsrqq0pw", + "jailed": false, + "status": 2, + "tokens": "145001000000", + "delegator_shares": "145001000000.000000000000000000", + "description": { + "moniker": "Cthulhu", + "identity": "Cthulhu", + "website": "Cthul.hu", + "details": "Cthulhu" + }, + "unbonding_height": "644758", + "unbonding_time": "2020-02-23T10:33:51.593569686Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-01-22T08:27:20.214359212Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper15r4tc0m6hc7z8drq3dzlrtcs6rq2q9l2nvwher", + "consensus_pubkey": "cosmosvalconspub1zcjduepqjcp9ez3dzmvsdfcw2h5kllmqvjgqnhtlvhad4q9wzcqf34gf6ewq6zl5mm", + "jailed": false, + "status": 2, + "tokens": "730533169795", + "delegator_shares": "730533169795.000000000000000000", + "description": { + "moniker": "DragonStake", + "identity": "EA61A46F31742B22", + "website": "https://dragonstake.io", + "details": "Forking the Banks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-24T18:52:31.67294751Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper159eexl76jlygrxnfreehl3j9tt70d8wfnn39fw", + "consensus_pubkey": "cosmosvalconspub1zcjduepq0jhujmf2ur4uk7al8pht6rpxwf7a24gqmhggeche0w09fglj9tmss4a0ql", + "jailed": false, + "status": 2, + "tokens": "8594550000", + "delegator_shares": "8594550000.000000000000000000", + "description": { + "moniker": "fishegg.net", + "identity": "", + "website": "http://www.fishegg.net", + "details": "welcome to join staking" + }, + "unbonding_height": "7949", + "unbonding_time": "2020-01-02T07:58:37.125916904Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-13T14:17:35.977287639Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf", + "consensus_pubkey": "cosmosvalconspub1zcjduepqtw8862dhw8uty58d6t2szfd6kqram2t234zjteaaeem6l45wclaq8l60gn", + "jailed": false, + "status": 2, + "tokens": "9408964703954", + "delegator_shares": "9408964703954.000000000000000000", + "description": { + "moniker": "Binance Staking", + "identity": "", + "website": "https://binance.com", + "details": "Exchange the world" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.025000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-06T07:47:39.033746293Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper15urq2dtp9qce4fyc85m6upwm9xul3049e02707", + "consensus_pubkey": "cosmosvalconspub1zcjduepqjc07nu2ya8tyzl8m385rnc382pkulwt2gh8yary73f3a96jak7pqsf63xf", + "jailed": false, + "status": 2, + "tokens": "4800643669275", + "delegator_shares": "4800643669275.000000000000000000", + "description": { + "moniker": "Chorus One", + "identity": "00B79D689B7DC1CE", + "website": "https://chorus.one/", + "details": "Secure Cosmos and shape its future by delegating to Chorus One, a highly secure and stable validator. By delegating, you agree to the terms of service at: https://chorus.one/cosmos/tos" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.075000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.020000000000000000" + }, + "update_time": "2019-08-13T17:43:26.871706216Z" + }, + "min_self_delegation": "10" + }, + { + "operator_address": "cosmosvaloper1402ggxz5u6vm29sqztwqq8vxs3ke6dmwl2z5dk", + "consensus_pubkey": "cosmosvalconspub1zcjduepqd4qh9dqgyce948kn48r2aqk7qlgtuwdmfeewj0z9aj4dr30v33cq6pmlql", + "jailed": false, + "status": 2, + "tokens": "9831948191", + "delegator_shares": "9832931400.858711612156228525", + "description": { + "moniker": "Cosmoon", + "identity": "8935A6F323FA0881", + "website": "https://cosmoon.org/", + "details": " Professional Stake Rewards Service " + }, + "unbonding_height": "1126591", + "unbonding_time": "2020-04-03T05:56:12.40115085Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2020-01-27T22:18:16.158833459Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper14kn0kk33szpwus9nh8n87fjel8djx0y070ymmj", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmfxl36td7rcdzszzrk6c7kzp5l3jlw4lnxz8zms3py7qcsa9xlns7zxfd6", + "jailed": false, + "status": 2, + "tokens": "2279800547152", + "delegator_shares": "2279800547152.000000000000000000", + "description": { + "moniker": "Forbole", + "identity": "2861F5EE06627224", + "website": "https://www.forbole.com/cosmos-hub-validator/", + "details": "As a prominent validator and contributor in Cosmos since 2017, Forbole is devoted to build a stronger Cosmos ecosystem. We are award winners in Game of Stakes and HackAtom. Please join our [community](https://t.me/forbole) or visit [our website](https://www.forbole.com/)." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.095000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-10T16:52:29.417872059Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper14k4pzckkre6uxxyd2lnhnpp8sngys9m6hl6ml7", + "consensus_pubkey": "cosmosvalconspub1zcjduepquhlqdhjw4qp2c2t6qh5z7tfk52qc72623f0etc8f3n7hy8uuh25ql34fvu", + "jailed": false, + "status": 2, + "tokens": "11370687848139", + "delegator_shares": "11370687848139.000000000000000000", + "description": { + "moniker": "Polychain Labs", + "identity": "A51CE3B9CD649C3F", + "website": "https://cosmos.polychainlabs.com", + "details": "Secure staking with Polychain Labs, the most experienced institutional grade staking team." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-04-22T04:57:29.717811274Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper146kwpzhmleafmhtaxulfptyhnvwxzlvm87hwnm", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfc7vnpgls3an0w2pv60pu4vr30p2dxqlmhmlrdv0m38y3tg689vs5qg4u5", + "jailed": false, + "status": 2, + "tokens": "85928911865", + "delegator_shares": "85928911865.000000000000000000", + "description": { + "moniker": "🌐 KysenPool.io", + "identity": "2474A8FCC4426BC5", + "website": "https://www.kysenpool.io", + "details": "Based in Silicon Valley. Help secure Cosmos by delegating to Kysen. Validators are backed by HSMs in Tier 3 enterprise-grade data centers." + }, + "unbonding_height": "0", + "unbonding_time": "2019-09-06T03:47:00.801583378Z", + "commission": { + "commission_rates": { + "rate": "0.079000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-23T06:10:09.194879379Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper14az9dmutwtz4vuycvae8csm4wwwtm0aumtlppe", + "consensus_pubkey": "cosmosvalconspub1zcjduepq59t2nm3ph5k6uc804w0n7ey69ul8ntee2dy47d7u53q248ud822sunv93j", + "jailed": false, + "status": 2, + "tokens": "1745806120297", + "delegator_shares": "1745980718357.935064116083909306", + "description": { + "moniker": "F4RM", + "identity": "181FAE6C0E4FA498", + "website": "http://www.f4rm.io", + "details": "F4RM - secure network validation \u0026 pooled digital asset staking" + }, + "unbonding_height": "546055", + "unbonding_time": "2020-02-15T08:28:57.815140271Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-15T10:36:44.571237954Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper14l0fp639yudfl46zauvv8rkzjgd4u0zk2aseys", + "consensus_pubkey": "cosmosvalconspub1zcjduepq7jsrkl9fgqk0wj3ahmfr8pgxj6vakj2wzn656s8pehh0zhv2w5as5gd80a", + "jailed": false, + "status": 2, + "tokens": "1970826215820", + "delegator_shares": "1970826215820.000000000000000000", + "description": { + "moniker": "ATEAM", + "identity": "0CB9A4E7643FF992", + "website": "nodeateam.com", + "details": "[GOS Never Jailed crew \u0026 Top-Tier] Node A-Team promises to provide validator node operation services at the highest quality" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.099000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-03-15T00:18:37.289241198Z" + }, + "min_self_delegation": "5000" + }, + { + "operator_address": "cosmosvaloper14lultfckehtszvzw4ehu0apvsr77afvyju5zzy", + "consensus_pubkey": "cosmosvalconspub1zcjduepqp0j4vum7ryt6nl6zsgq9ar347afmq2c5z6jmzeavv2p2ns6m0dgs5zmg4z", + "jailed": false, + "status": 2, + "tokens": "11215950232520", + "delegator_shares": "11215950232520.000000000000000000", + "description": { + "moniker": "DokiaCapital", + "identity": "25422F4ADF3F6765", + "website": "https://staking.dokia.cloud", + "details": "Downtime is not an option for Dokia Capital. We operate an enterprise-grade infrastructure that is robust and secure." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.150000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1k9a0cs97vul8w2vwknlfmpez6prv8klv03lv3d", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfgpyq4xk4s96ksmkfrr7juea9kmdxkl5ht94xgpxe240743u9cvsht489p", + "jailed": false, + "status": 2, + "tokens": "900772962204", + "delegator_shares": "900772962204.000000000000000000", + "description": { + "moniker": "Stake Capital", + "identity": "1DD9A932591FA928", + "website": "https://stake.capital", + "details": "'Trustless Digital Asset Management', Twitter: @StakeCapital, operated by @bneiluj @leopoldjoy" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.080000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.030000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1kgddca7qj96z0qcxr2c45z73cfl0c75p7f3s2e", + "consensus_pubkey": "cosmosvalconspub1zcjduepqay5ldqdmyzy9qfr93enxmm7cwsd5aafz6huqvczytqahpw4twa8qvtrwhv", + "jailed": false, + "status": 2, + "tokens": "599883677526", + "delegator_shares": "599883677526.000000000000000000", + "description": { + "moniker": "ChainLayer", + "identity": "AD3CDBC91802F94A", + "website": "https://www.chainlayer.io", + "details": "Secure and reliable validator. TG: https://t.me/chainlayer" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-04-01T18:02:13.514368678Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ktecz4dr56j9tsfh7nwg8s9suvhfu70qykhu5s", + "consensus_pubkey": "cosmosvalconspub1zcjduepq4euv7ertqhgvxrla583fg9g6z2v2dzrkl9spche4j4r23vukmx2q8gqvev", + "jailed": false, + "status": 2, + "tokens": "5766932920", + "delegator_shares": "5766932920.000000000000000000", + "description": { + "moniker": "Dawns.World", + "identity": "AA70E5B206F952A3", + "website": "https://dawns.world", + "details": "To discover token's intrinsic real value and enhance its liquidity" + }, + "unbonding_height": "1282180", + "unbonding_time": "2020-04-16T04:36:32.319738894Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-17T15:57:42.95929171Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1kj0h4kn4z5xvedu2nd9c4a9a559wvpuvu0h6qn", + "consensus_pubkey": "cosmosvalconspub1zcjduepqvc5xdrpvduse3fc084s56n4a6dhzudyzjmywjx25fkgw2fhsj70searwgy", + "jailed": false, + "status": 2, + "tokens": "1564634211770", + "delegator_shares": "1564634211770.000000000000000000", + "description": { + "moniker": "Cryptium Labs", + "identity": "5A309B5CA189D8B3", + "website": "https://cryptium.ch", + "details": "Secure and available validation from the Swiss Alps" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.110000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-27T11:16:35.284063151Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1kn3wugetjuy4zetlq6wadchfhvu3x740ae6z6x", + "consensus_pubkey": "cosmosvalconspub1zcjduepqc8slfqdszcd85wzzweuanv0em4h4gdc5wkh3et6e7t8z93z24u0s0rdlx2", + "jailed": false, + "status": 2, + "tokens": "3445647543790", + "delegator_shares": "3445647543790.000000000000000000", + "description": { + "moniker": "HuobiPool", + "identity": "23536C5BDE3EB949", + "website": "https://www.huobipool.com/", + "details": "Huobi Pool is a sub-brand of Huobi Group, which is an important part of the global ecological strategy of Huobi.Huobi Pool has become one of the largest POS communities in the Asia- Pacific region, the leading POW pool and nodes of a number of public chains." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-05T10:43:26.93220487Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1hvsdf03tl6w5pnfvfv5g8uphjd4wfw2h4gvnl7", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5l63vgd8m9chc3c32wn5lthzsax6xxdylpzmhqmjwrgfhd3m2swsj2wc2d", + "jailed": false, + "status": 2, + "tokens": "100005087848", + "delegator_shares": "100015089026.194888154307376423", + "description": { + "moniker": "Atom.Bi23", + "identity": "EB3470949B3E89E2", + "website": "https://atom.bi23.com", + "details": "Bi23 focuses on the Crypto-Assets, providing customers with Staking and DeFi services." + }, + "unbonding_height": "0", + "unbonding_time": "2019-08-16T15:34:04.702756371Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-11T04:30:32.134491966Z" + }, + "min_self_delegation": "2" + }, + { + "operator_address": "cosmosvaloper1hjct6q7npsspsg3dgvzk3sdf89spmlpfdn6m9d", + "consensus_pubkey": "cosmosvalconspub1zcjduepqnltddase4lqjcfhup8ymg0qex3srakg54ppv06pstvwdjxkm6tmq08znvs", + "jailed": false, + "status": 2, + "tokens": "4653603791655", + "delegator_shares": "4653603791655.000000000000000000", + "description": { + "moniker": "Figment Networks", + "identity": "E5F274B870BDA01D", + "website": "https://figment.network", + "details": "Makers of Hubble and Canada’s largest Cosmos validator, Figment is the easiest and most secure way to stake your Atoms." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.090000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-06T12:17:54.693866931Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1crqm3598z6qmyn2kkcl9dz7uqs4qdqnr6s8jdn", + "consensus_pubkey": "cosmosvalconspub1zcjduepqt0fpxxufuuhavfqh8zg3pjnnwdvvzw9huemzxe59kpjt5e3xprhs7d8khn", + "jailed": false, + "status": 2, + "tokens": "447018398440", + "delegator_shares": "447018398440.000000000000000000", + "description": { + "moniker": "Bison Trails", + "identity": "A296556FF603197C", + "website": "bisontrails.co", + "details": "Bison Trails is the easiest way to run infrastructure on multiple blockchains." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.080000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-10-30T20:21:03.030621767Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1cgh5ksjwy2sd407lyre4l3uj2fdrqhpkzp06e6", + "consensus_pubkey": "cosmosvalconspub1zcjduepq3f6wnsk6k6qu6g8n5vly4z7ajw7q930wh3qx6zkxhktnh49l40kszf5lry", + "jailed": false, + "status": 2, + "tokens": "932859245807", + "delegator_shares": "932859245807.000000000000000000", + "description": { + "moniker": "HashQuark", + "identity": "31AFBBE0A52FA1ED", + "website": "https://www.hashquark.io", + "details": "Staking made easier!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-10-23T02:48:39.22540691Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1clpqr4nrk4khgkxj78fcwwh6dl3uw4epsluffn", + "consensus_pubkey": "cosmosvalconspub1zcjduepq0dc9apn3pz2x2qyujcnl2heqq4aceput2uaucuvhrjts75q0rv5smjjn7v", + "jailed": false, + "status": 2, + "tokens": "6103920214139", + "delegator_shares": "6103920214139.000000000000000000", + "description": { + "moniker": "Cosmostation", + "identity": "AE4C403A6E7AA1AC", + "website": "https://www.cosmostation.io", + "details": "CØSMOSTATION Validator. Delegate your atoms and Start Earning Staking Rewards" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "10" + }, + { + "operator_address": "cosmosvaloper1ey69r37gfxvxg62sh4r0ktpuc46pzjrm873ae8", + "consensus_pubkey": "cosmosvalconspub1zcjduepqg6y8magedjwr9p6s2c28zp28jdjtecxhn97ew6tnuzqklg63zgfspp9y3n", + "jailed": false, + "status": 2, + "tokens": "10361463918660", + "delegator_shares": "10361463917414.465324179280152398", + "description": { + "moniker": "Sikka", + "identity": "https://keybase.io/team/sikka", + "website": "sikka.tech", + "details": "Sunny Aggarwal (@sunnya97) and Dev Ojha (@ValarDragon)" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-01T04:08:08.548659287Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1e859xaue4k2jzqw20cv6l7p3tmc378pc3k8g2u", + "consensus_pubkey": "cosmosvalconspub1zcjduepql9gmstvlcyxpa7ndyl08y694xxc8r03e8nn0zfvl3x255ev6q7rq9hevuz", + "jailed": false, + "status": 2, + "tokens": "2164966230", + "delegator_shares": "2164966230.000000000000000000", + "description": { + "moniker": "#fuckgoogle", + "identity": "", + "website": "https://github.com/cybercongress", + "details": "" + }, + "unbonding_height": "1357109", + "unbonding_time": "2020-04-22T09:09:26.8630982Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-12T12:34:44.598269429Z" + }, + "min_self_delegation": "10" + }, + { + "operator_address": "cosmosvaloper1et77usu8q2hargvyusl4qzryev8x8t9wwqkxfs", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfx0p8s3gmxmaftkkazw5wag4sfau3vgcn20ut4dn5rv2nr8ddq2s59rnvq", + "jailed": false, + "status": 2, + "tokens": "6938017012", + "delegator_shares": "6938017012.000000000000000000", + "description": { + "moniker": "👾replicator.network", + "identity": "9203983F91296B66", + "website": "https://replicator.network", + "details": "" + }, + "unbonding_height": "8201", + "unbonding_time": "2020-01-02T08:27:54.43078638Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-12-12T04:01:41.501864578Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1e0plfg475phrsvrlzw8gwppeva0zk5yg9fgg8c", + "consensus_pubkey": "cosmosvalconspub1zcjduepqz83dmnt4g6w0w6syrf433mwpk86zejxnq6e336xtxd8pg9jtxkgq732tpu", + "jailed": false, + "status": 2, + "tokens": "331202100073", + "delegator_shares": "331202100073.000000000000000000", + "description": { + "moniker": "Easy 2 Stake", + "identity": "2C877AC873132C91", + "website": "www.easy2stake.com", + "details": "Easy.Stake.Trust. as easy and as simple as you would click next. Complete transparency and trust with a secure and stable validator. GoS winner, Never Jailed Crew" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-09-27T08:35:53.771679331Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1e0jnq2sun3dzjh8p2xq95kk0expwmd7sj6x59m", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfndze9l7th79g0m4fguf5cueksmywl6sw2xhuz7gp6jatr39ffuqn3exk9", + "jailed": false, + "status": 2, + "tokens": "116267146692", + "delegator_shares": "116267146692.000000000000000000", + "description": { + "moniker": "Fission Labs", + "identity": "7DAC30FBD99879B0", + "website": "https://fissionlabs.io/", + "details": "Fission Labs - Blockchain infrastructure and development services" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-10-27T15:17:00.635446897Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fz4sdg3", + "consensus_pubkey": "cosmosvalconspub1zcjduepq8hu49qdl5594rzxmdsww3hleu8phxrajjfsseqjere9mjrrrv9tq35mll4", + "jailed": false, + "status": 2, + "tokens": "2135806970012", + "delegator_shares": "2135806970012.000000000000000000", + "description": { + "moniker": "BouBouNode", + "identity": "", + "website": "https://boubounode.com", + "details": "AI-based Validator. #1 AI Validator on Game of Stakes. Fairly priced. Don't trust (humans), verify. Made with BouBou love." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.061000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ehkfl7palwrh6w2hhr2yfrgrq8jetgucudztfe", + "consensus_pubkey": "cosmosvalconspub1zcjduepqvmmhug9hcmm26ce7we0n3esavn4c6tfcfd6zgnuj732ls7khjq4srpg0ft", + "jailed": false, + "status": 2, + "tokens": "1138068194456", + "delegator_shares": "1138068194456.000000000000000000", + "description": { + "moniker": "KalpaTech", + "identity": "B4AD06F0EB355573", + "website": "http://kalpatech.co", + "details": "KalpaTech | Genesis Validator | Game of Stakes winner | Services dedicated exclusively for Cosmos Hub | All resources put in one network" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-28T22:00:22.763748595Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ec3p6a75mqwkv33zt543n6cnxqwun37rr5xlqv", + "consensus_pubkey": "cosmosvalconspub1zcjduepqd85nu5nelvcyyzcsrr0yaglh8rfvn6cv9pp3p0hgmwtk8hf3cazqc7vz5c", + "jailed": false, + "status": 2, + "tokens": "1049353149259", + "delegator_shares": "1049353149259.000000000000000000", + "description": { + "moniker": "lunamint", + "identity": "4F26823468DD7518", + "website": "https://lunamint.com", + "details": "Always adding value to Cosmos. Check out Lunagram, the Cosmos wallet built into Telegram." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1emaa7mwgpnpmc7yptm728ytp9quamsvu837nc0", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfuxvufupnsm7v5anpwd7z8ec70z2k209j7xclnm25zz7vauhyc5qjgxx3h", + "jailed": false, + "status": 2, + "tokens": "525602853385", + "delegator_shares": "525602853385.000000000000000000", + "description": { + "moniker": "kochacolaj", + "identity": "1E9CE94FD0BA5CFEB901F90BC658D64D85B134D2", + "website": "https://blog.cosmos.network/game-of-stakes-closing-ceremonies-eddb71d3b114#147d", + "details": "Top 5 Game Of Stakes winner" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-02-29T17:40:11.439163513Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1eup5t8pp8jq354heck53qtama7vss9l354kh6r", + "consensus_pubkey": "cosmosvalconspub1zcjduepqxh4s2zj52uhfssu7u2xyhmnk5f7g9ty368twxkkcfllsq3fqaw9sdl6rj9", + "jailed": false, + "status": 2, + "tokens": "8452580358", + "delegator_shares": "8452580358.000000000000000000", + "description": { + "moniker": "IZ0", + "identity": "BF964D76855711CC", + "website": "www.izo.ro", + "details": "Izo Data Network ! Commission is 0% . Please join our [community](https://t.me/IzoData) or visit [website](https://www.izo.ro/)! " + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.100000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-12-26T08:56:10.399933806Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper16qme5yxucnaj6snx35nmwze0wyxr8wfgqxsqfw", + "consensus_pubkey": "cosmosvalconspub1zcjduepqwnhw3azrlhnx9kaujvn0es9u26e4a3af6hye6e9j0pl2tlpx9k3s59zwh0", + "jailed": false, + "status": 2, + "tokens": "260865453794", + "delegator_shares": "260865453794.000000000000000000", + "description": { + "moniker": "KIRA Staking", + "identity": "C86C8FF08A5269DC", + "website": "https://kiraex.com", + "details": "Kira Core Staking Services - Sentry, KMS, HSM, High Availability \u0026 Double Sign Protection" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-04-01T21:07:55.105865438Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper16v3f95amtvpewuajjcdsvaekuuy4yyzups85ec", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmgwzcm3aqmc8nln9u4q5ydsjwx6rzqrch6p243x2gtzetnx5l3ls432euv", + "jailed": false, + "status": 2, + "tokens": "147885388389", + "delegator_shares": "147885388389.000000000000000000", + "description": { + "moniker": "BlockPool", + "identity": "", + "website": "www.blockpool.com", + "details": "Power the staking economy" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "0.030000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-06-22T05:19:17.897735561Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1648ynlpdw7fqa2axt0w2yp3fk542junl7rsvq6", + "consensus_pubkey": "cosmosvalconspub1zcjduepqf8llkc4p43lksktsqzr5nmgmw4ln9pzym2vp4kqfrny8xrgnqrsq76djjc", + "jailed": false, + "status": 2, + "tokens": "797707710682", + "delegator_shares": "797787489383.461009934458905148", + "description": { + "moniker": "Any Labs", + "identity": "B2D07CA3CCC907CE", + "website": "https://anylabs.io", + "details": "Blockchain staking and consultancy based in Japan." + }, + "unbonding_height": "25880", + "unbonding_time": "2020-01-03T18:48:44.276425288Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-08T11:30:02.004384504Z" + }, + "min_self_delegation": "100" + }, + { + "operator_address": "cosmosvaloper16k579jk6yt2cwmqx9dz5xvq9fug2tekvlu9qdv", + "consensus_pubkey": "cosmosvalconspub1zcjduepq55mjplg9gy979ua9r5qmk2wr5nysmputt28j0zsgadn933lyh32sh20cmm", + "jailed": false, + "status": 2, + "tokens": "928458345391", + "delegator_shares": "928551200492.966284028096640587", + "description": { + "moniker": "Cephalopod Equipment", + "identity": "6408AA029ADBE364", + "website": "https://cephalopod.equipment", + "details": "Cephalopod Equipment - infrastructure for decentralized intelligence" + }, + "unbonding_height": "0", + "unbonding_time": "2019-12-01T09:34:39.548038382Z", + "commission": { + "commission_rates": { + "rate": "0.081100000000000000", + "max_rate": "0.420000000000000000", + "max_change_rate": "0.011800000000000000" + }, + "update_time": "2019-09-19T12:26:43.48042061Z" + }, + "min_self_delegation": "100000" + }, + { + "operator_address": "cosmosvaloper1mykn77lkynl8fkwvl9tqg369u0zajzzcdhkptq", + "consensus_pubkey": "cosmosvalconspub1zcjduepqft6uxfmfjjce0p7ke4h0zc38x4d9d38wlmrgcc47flru92qq3ydq76mrsf", + "jailed": false, + "status": 2, + "tokens": "89943764382", + "delegator_shares": "89943764382.000000000000000000", + "description": { + "moniker": "Nodeasy.com", + "identity": "AB006A79DBD8FC57", + "website": "https://www.nodeasy.com", + "details": "Nodeasy.com,助你进入Staking时代!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-10-28T13:02:55.182998044Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1m83cwjucw9nt8xm66u8xavvy6v9m7xfspcszc5", + "consensus_pubkey": "cosmosvalconspub1zcjduepq7qnf5r40z7esjc2utrjrvzxg9sfd683hw0805ek85ddchdcptthqjnzxxu", + "jailed": false, + "status": 2, + "tokens": "159214462425", + "delegator_shares": "159214462425.000000000000000000", + "description": { + "moniker": "Fenbushi US - Staked", + "identity": "CC4B238C8F9FB2BE", + "website": "https://fenbushi.vc", + "details": "Fenbushi Capital is the first and most active blockchain-focused venture capital firm in Asia. Staked is the leading provider of validation technology and services. We're bringing our combined skills to Cosmos." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T18:07:08.897219336Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ma02nlc7lchu7caufyrrqt4r6v2mpsj90y9wzd", + "consensus_pubkey": "cosmosvalconspub1zcjduepqxtu8am2qmf0qnglqtvkar9gaclhccfn29tsp7n82vasrtnc8m2fsulp4h2", + "jailed": false, + "status": 2, + "tokens": "3464569661466", + "delegator_shares": "3464569661466.000000000000000000", + "description": { + "moniker": "hashtower", + "identity": "0BBBAE1FD11AEBAF", + "website": "http://hashtower.com", + "details": "Hashtower Actwo COSMOS Validator" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.200000000000000000" + }, + "update_time": "2019-07-16T08:46:06.560077744Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1uxh465053nq3at4dn0jywgwq3s9sme3la3drx6", + "consensus_pubkey": "cosmosvalconspub1zcjduepqc5y2du793cjut0cn6v7thp3xlvphggk6rt2dhw9ekjla5wtkm7nstmv5vy", + "jailed": false, + "status": 2, + "tokens": "520672159921", + "delegator_shares": "520672159921.000000000000000000", + "description": { + "moniker": "Bison Trails", + "identity": "A296556FF603197C", + "website": "https://bisontrails.co", + "details": "Bison Trails is the easiest way to run infrastructure on multiple blockchains." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1udpsgkgyutgsglauk9vk9rs03a3skc62gup9ny", + "consensus_pubkey": "cosmosvalconspub1zcjduepq38tmpw8wujah8nhvkkd26tskx4p7l0qx2kqwfkp3hj8644e9kevqxe5zl2", + "jailed": false, + "status": 2, + "tokens": "5000000000", + "delegator_shares": "5000000000.000000000000000000", + "description": { + "moniker": "TEST_NODE", + "identity": "", + "website": "", + "details": "Test Node." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.075000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-30T11:04:05.791970925Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1uhnsxv6m83jj3328mhrql7yax3nge5svrv6t6c", + "consensus_pubkey": "cosmosvalconspub1zcjduepql42t7mstnewp5rgweteuw95hawzystll7mq8dl24n5yh0th7q2jqetcy07", + "jailed": false, + "status": 2, + "tokens": "720793765456", + "delegator_shares": "720865851960.598464555143928151", + "description": { + "moniker": "Skystar Capital", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "1168707", + "unbonding_time": "2020-04-06T17:50:47.447745873Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1u6ddcsjueax884l3tfrs66497c7g86skn7pa0u", + "consensus_pubkey": "cosmosvalconspub1zcjduepq87zcnf8sm4ewacjafqujfevt8rhwj5qk9uwtx4ef89ctuqmndkeq446ahw", + "jailed": false, + "status": 2, + "tokens": "809489002763", + "delegator_shares": "809489002763.000000000000000000", + "description": { + "moniker": "Sentinel", + "identity": "D54C8032CF19C407", + "website": "https://sentinel.co", + "details": "We are team Sentinel, developer of infrastructure tools on Cosmos \u0026 other networks.Winner in the Uptime category during GOS.Developed the first working version of the dVPN which runs on Ethereum \u0026 Sentinel's own Tendermint TestNet" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "cosmosvaloper1uutuwrwt3z2a5z8z3uasml3rftlpmu25aga5c6", + "consensus_pubkey": "cosmosvalconspub1zcjduepqarrl0ppddzyczwvcqwf3jwd9qwkhxfy6lcv8ep4msk293mlxg39qgf77y3", + "jailed": false, + "status": 2, + "tokens": "894288539493", + "delegator_shares": "894288539493.000000000000000000", + "description": { + "moniker": "Delega Networks♾ ", + "identity": "1BED7C08416A619F", + "website": "https://delega.io", + "details": "Nodes managed by wimel" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.180000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-05T00:45:01.073794845Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ul2me6vukg2vac2p6ltxmqlaa7jywdgt8q76ag", + "consensus_pubkey": "cosmosvalconspub1zcjduepq0cet8ez89wj4yz8uencych7aldc5wyyrpx6jvh6n6kxxslumln5sxkq922", + "jailed": false, + "status": 2, + "tokens": "1208359862997", + "delegator_shares": "1208359862997.000000000000000000", + "description": { + "moniker": "HyperblocksPro", + "identity": "B073FA5BAD230585", + "website": "https://hyperblocks.pro/", + "details": "Secure the network and earn rewards with Hyperblocks.pro, one of the first companies in the world fully focused on Proof Of Stake protocols" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-04-05T23:57:19.320271237Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1a3yjj7d3qnx4spgvjcwjq9cw9snrrrhu5h6jll", + "consensus_pubkey": "cosmosvalconspub1zcjduepqxjkll4nxla8gtekx2ueq3tc8vv4e6rn79jmdead30jeqlm3kc7eqqx7hs8", + "jailed": false, + "status": 2, + "tokens": "10041185315", + "delegator_shares": "10041185315.000000000000000000", + "description": { + "moniker": "Coinbase Custody", + "identity": "Coinbase Custody", + "website": "https://custody.coinbase.com", + "details": "Coinbase Custody Cosmos Validator" + }, + "unbonding_height": "676534", + "unbonding_time": "2020-02-26T01:41:46.759697123Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-02-05T00:29:51.081896503Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", + "consensus_pubkey": "cosmosvalconspub1zcjduepqc9ppxzktam9v39d9q07h6n98cdm7cgg4l65vq5yvtgruxp5h0yhs8tup68", + "jailed": false, + "status": 2, + "tokens": "202801407477", + "delegator_shares": "202801407477.000000000000000000", + "description": { + "moniker": "FRESHATOMS", + "identity": "63575EE3F0F9FAFC", + "website": "https://freshatoms.com", + "details": "FreshAtoms runs on bare metal in a SSAE16 SOC2 certified Tier 3 datacenter with geographically distributed private sentry nodes, YubiHSM2 hardware protected keys, with 24/7 monitoring, alerting, and analytics." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-09-23T20:29:05.781322875Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper17mggn4znyeyg25wd7498qxl7r2jhgue8u4qjcq", + "consensus_pubkey": "cosmosvalconspub1zcjduepqlzmd0spn9m0m3eq9zp93d4w6e5tugamv44yqjzyacelnvra634fqnfec0r", + "jailed": false, + "status": 2, + "tokens": "1079608204356", + "delegator_shares": "1079608204356.000000000000000000", + "description": { + "moniker": "01node", + "identity": "22823CD59617B8E3", + "website": "https://01node.com", + "details": "01node Professional Staking Services for Cosmos, Iris, Terra, Solana, Kava, Polkadot, Skale" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1l9fwl9c77zx850htsr20pq3ltc379xt86ndelm", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfjgjrj4heptaw6h9nhtkng8hw2zsq5c6e9xzwvnjjx2n6pc7x6yq4ny2qc", + "jailed": false, + "status": 2, + "tokens": "5057317038", + "delegator_shares": "5057317038.000000000000000000", + "description": { + "moniker": "CosmosLink", + "identity": "3F7807C66CE770B0", + "website": "cosmoslink.network", + "details": "Based on Cosmos network digital asset security value-added service provider" + }, + "unbonding_height": "1276519", + "unbonding_time": "2020-04-15T17:26:54.325724353Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-18T16:46:59.079404223Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1lktjhnzkpkz3ehrg8psvmwhafg56kfss3q3t8m", + "consensus_pubkey": "cosmosvalconspub1zcjduepqelcwpat987h9yq0ck6g9fsc8t0mththk547gwvk0w4wnkpl0stnspr3hdc", + "jailed": false, + "status": 2, + "tokens": "1720474496626", + "delegator_shares": "1720474496626.000000000000000000", + "description": { + "moniker": "Umbrella ☔", + "identity": "A530AC4D75991FE2", + "website": "https://umbrellavalidator.com", + "details": "One of the winners of Cosmos Game of Stakes, and HackAtom3." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070400000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-08-05T07:10:23.689753607Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1lcwxu50rvvgf9v6jy6q5mrzyhlszwtjxhtscmp", + "consensus_pubkey": "cosmosvalconspub1zcjduepqh3jg5ld5xg5q5mcxrzn6fcuq696qqa3ut3azskphpdrty37ervjqcn8mfj", + "jailed": false, + "status": 2, + "tokens": "9713509339", + "delegator_shares": "9713509339.000000000000000000", + "description": { + "moniker": "stake.zone", + "identity": "0A888728046018EC", + "website": "http://stake.zone", + "details": "operated by nuevax" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2020-02-13T02:20:41.320594366Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1l6udzyaz8xaxv4hpagwauacm95jlcec3xlht2u", + "consensus_pubkey": "cosmosvalconspub1zcjduepq9t4r8jgr09rsscgacnaklxuf55pg0wq5zfwzw8ycawms5x0hrfhqks3dpe", + "jailed": false, + "status": 2, + "tokens": "10802365900", + "delegator_shares": "10802365900.000000000000000000", + "description": { + "moniker": "StakeHouse", + "identity": "A1AAB1D6D0E8F976", + "website": "stakehouse.org", + "details": "Low fees. No hassle. Enjoy your meal." + }, + "unbonding_height": "701066", + "unbonding_time": "2020-02-28T02:04:00.114690756Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-02-11T07:24:35.723449554Z" + }, + "min_self_delegation": "1" + } + ] + } + `); + } + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; + diff --git a/mock/ext-api-dyson/get/cosmos-api-commands4.js b/mock/ext-api-dyson/get/cosmos-api-commands4.js new file mode 100644 index 000000000..eba2be0a0 --- /dev/null +++ b/mock/ext-api-dyson/get/cosmos-api-commands4.js @@ -0,0 +1,44 @@ +/// Cosmos API Mock +/// See: +/// curl "http://localhost:3000/cosmos-api/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/delegations" +/// curl "https://{cosmos_rpc}/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/delegations" +/// curl "http://localhost:8420/v2/cosmos/staking/delegations/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq?Authorization=Bearer" + +module.exports = { + path: "/cosmos-api/:command1/:command2/:arg3/:arg4?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch(params.command1) { + case 'staking': + switch(params.command2) { + case 'delegators': + switch (params.arg3) { + case 'cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq': + switch (params.arg4) { + case 'delegations': + case 'unbonding_delegations': + return JSON.parse(` + { + "height": "1419065", + "result": [ + { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", + "shares": "2211271.000000000000000000", + "balance": "2211271" + } + ] + } + `); + } + } + } + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; + diff --git a/mock/ext-api-dyson/get/cosmos-api-txs.js b/mock/ext-api-dyson/get/cosmos-api-txs.js deleted file mode 100644 index 6da657330..000000000 --- a/mock/ext-api-dyson/get/cosmos-api-txs.js +++ /dev/null @@ -1,524 +0,0 @@ -/// Cosmos API Mock -/// See: -/// curl "http://localhost:3000/cosmos-api/txs?transfer.recipient=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq&page=1&limit=25" -/// curl "http://localhost:3000/cosmos-api/txs?message.sender=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq&page=1&limit=25" -/// curl "http://{cosmos rpc}/txs?transfer.recipient=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq&page=1&limit=25" -/// curl ""http://{cosmos rpc}/txs?message.sender=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq&page=1&limit=25" -/// curl http://localhost:8420/v1/cosmos/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq -module.exports = { - path: "/cosmos-api/txs?", - template: function(params, query, body) { - //console.log(query) - if (query["transfer.recipient"] === 'cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq') { - return JSON.parse(` - { - "total_count": "1", - "count": "1", - "page_number": "1", - "page_total": "1", - "limit": "25", - "txs": [ - { - "height": "26616", - "txhash": "3FEE8F10FBA5505DE2A8D3EF220D5CE900CA76B96208234BBF89B8075743A230", - "data": "0C0886C1BEF00510E7FFF6F801", - "logs": [ - { - "msg_index": 0, - "success": true, - "log": "", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "sender", - "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" - }, - { - "key": "sender", - "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" - }, - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "begin_unbonding" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "amount", - "value": "1147uatom" - }, - { - "key": "recipient", - "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" - }, - { - "key": "amount", - "value": "2203000uatom" - } - ] - }, - { - "type": "unbond", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - }, - { - "key": "amount", - "value": "2203000" - }, - { - "key": "completion_time", - "value": "2020-01-03T20:13:58Z" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "127111", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgUndelegate", - "value": { - "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", - "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", - "amount": { - "denom": "uatom", - "amount": "2203000" - } - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "1000" - } - ], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" - }, - "signature": "fJkOgQX9FZz6UJJo48AA3qxc2v/vFrjxlMgq3iOhDmVUWjA2P6X+pPbPkSB1SHlBFlVbsNF/DDPB0pvP9LRPTg==" - } - ], - "memo": "" - } - }, - "timestamp": "2019-12-13T20:13:58Z", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "sender", - "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" - }, - { - "key": "sender", - "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" - }, - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "begin_unbonding" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "amount", - "value": "1147uatom" - }, - { - "key": "recipient", - "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" - }, - { - "key": "amount", - "value": "2203000uatom" - } - ] - }, - { - "type": "unbond", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - }, - { - "key": "amount", - "value": "2203000" - }, - { - "key": "completion_time", - "value": "2020-01-03T20:13:58Z" - } - ] - } - ] - } - ] - } - `); - } - - if (query["message.sender"] === 'cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq') { - return JSON.parse(` - { - "total_count": "2", - "count": "2", - "page_number": "1", - "page_total": "1", - "limit": "25", - "txs": [ - { - "height": "26616", - "txhash": "3FEE8F10FBA5505DE2A8D3EF220D5CE900CA76B96208234BBF89B8075743A230", - "data": "0C0886C1BEF00510E7FFF6F801", - "logs": [ - { - "msg_index": 0, - "success": true, - "log": "", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "sender", - "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" - }, - { - "key": "sender", - "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" - }, - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "begin_unbonding" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "amount", - "value": "1147uatom" - }, - { - "key": "recipient", - "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" - }, - { - "key": "amount", - "value": "2203000uatom" - } - ] - }, - { - "type": "unbond", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - }, - { - "key": "amount", - "value": "2203000" - }, - { - "key": "completion_time", - "value": "2020-01-03T20:13:58Z" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "127111", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgUndelegate", - "value": { - "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", - "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", - "amount": { - "denom": "uatom", - "amount": "2203000" - } - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "1000" - } - ], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" - }, - "signature": "fJkOgQX9FZz6UJJo48AA3qxc2v/vFrjxlMgq3iOhDmVUWjA2P6X+pPbPkSB1SHlBFlVbsNF/DDPB0pvP9LRPTg==" - } - ], - "memo": "" - } - }, - "timestamp": "2019-12-13T20:13:58Z", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "sender", - "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" - }, - { - "key": "sender", - "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" - }, - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "begin_unbonding" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "amount", - "value": "1147uatom" - }, - { - "key": "recipient", - "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" - }, - { - "key": "amount", - "value": "2203000uatom" - } - ] - }, - { - "type": "unbond", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - }, - { - "key": "amount", - "value": "2203000" - }, - { - "key": "completion_time", - "value": "2020-01-03T20:13:58Z" - } - ] - } - ] - }, - { - "height": "404179", - "txhash": "93E43518BAE4BC137605BBB7FD5D31FDAE6427ECE57EC299C43CE786FDAEBC63", - "logs": [ - { - "msg_index": 0, - "success": true, - "log": "", - "events": [ - { - "type": "delegate", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh" - }, - { - "key": "amount", - "value": "2211271" - } - ] - }, - { - "type": "message", - "attributes": [ - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "delegate" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "93720", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgDelegate", - "value": { - "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", - "validator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", - "amount": { - "denom": "uatom", - "amount": "2211271" - } - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "1000" - } - ], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" - }, - "signature": "X1/NzRdb+HUxE7N9gMk39XI8TyHFobLRQtsX4QxZZbYeKmEYOOZ7FyNSGqgmipCkpuysBeh6fNnbXmo3IFzFEQ==" - } - ], - "memo": "" - } - }, - "timestamp": "2020-01-13T15:23:12Z", - "events": [ - { - "type": "delegate", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh" - }, - { - "key": "amount", - "value": "2211271" - } - ] - }, - { - "type": "message", - "attributes": [ - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "delegate" - } - ] - } - ] - } - ] - } - `); - } - - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; - } -}; - diff --git a/mock/ext-api-dyson/get/eth-api-commands1.js b/mock/ext-api-dyson/get/eth-api-commands1.js new file mode 100644 index 000000000..54b798084 --- /dev/null +++ b/mock/ext-api-dyson/get/eth-api-commands1.js @@ -0,0 +1,196 @@ +/// Ethereum API Mock +/// See: +/// curl "http://localhost:3000/eth-api/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://localhost:3000/eth-api/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "https://{eth rpc}/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "https://{eth rpc}/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://localhost:8420/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://localhost:8420/v2/ethereum/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" + +module.exports = { + path: '/eth-api/:command1?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.command1) { + case 'transactions': + if (query.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { + return JSON.parse(`{ + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", + "blockNumber": 9551915, + "time": 1582624428, + "nonce": 227, + "from": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "to": "0x1717f94202c126ef71d6C562de253Fe95eEbDD5f", + "value": "17635730000000000", + "gas": "21000", + "gasPrice": "4320000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", + "timeStamp": "1582624428" + }, + { + "operations": [ + { + "transactionId": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3-0", + "contract": { + "address": "0x0d8775f648430679a709e98d2b0cb6250d2887ef", + "symbol": "BAT", + "decimals": 18, + "totalSupply": "1500000000000000000000000000", + "name": "Basic Attention Token", + "updatedAt": "2020-03-23T06:01:25.975Z" + }, + "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", + "to": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "type": "token_transfer", + "value": "400000000000000000", + "id": null + } + ], + "contract": null, + "_id": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", + "blockNumber": 9519169, + "time": 1582189159, + "nonce": 16, + "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", + "to": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "value": "0", + "gas": "51839", + "gasPrice": "11500000000", + "gasUsed": "37028", + "input": "0xa9059cbb0000000000000000000000000875bcab22de3d02402bc38aee4104e1239374a7000000000000000000000000000000000000000000000000058d15e176280000", + "error": "", + "id": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", + "timeStamp": "1582189159" + } + ], + "total": 2 + }`); + } + + case 'tokens': + if (query.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { + return JSON.parse(` + { + "total": 17, + "docs": [ + { + "address": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + "name": "Kyber Network Crystal", + "decimals": 18, + "symbol": "KNC" + }, + { + "address": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", + "name": "BNB", + "decimals": 18, + "symbol": "BNB" + }, + { + "address": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "name": "Basic Attention Token", + "decimals": 18, + "symbol": "BAT" + }, + { + "address": "0x226bb599a12C826476e3A771454697EA52E9E220", + "name": "Propy", + "decimals": 8, + "symbol": "PRO" + }, + { + "address": "0xf3Db5Fa2C66B7aF3Eb0C0b782510816cbe4813b8", + "name": "Everex", + "decimals": 4, + "symbol": "EVX" + }, + { + "address": "0x85e076361cc813A908Ff672F9BAd1541474402b2", + "name": "Telcoin", + "decimals": 2, + "symbol": "TEL" + }, + { + "address": "0xD73bE539d6B2076BaB83CA6Ba62DfE189aBC6Bbe", + "name": "BlockchainCuties", + "decimals": 0, + "symbol": "BC" + }, + { + "address": "0x0000000000085d4780B73119b644AE5ecd22b376", + "name": "TrueUSD", + "decimals": 18, + "symbol": "TUSD" + }, + { + "address": "0xFBeef911Dc5821886e1dda71586d90eD28174B7d", + "name": "KnownOriginDigitalAsset", + "decimals": 0, + "symbol": "KODA" + }, + { + "address": "0xc3761EB917CD790B30dAD99f6Cc5b4Ff93C4F9eA", + "name": "ERC20", + "decimals": 18, + "symbol": "ERC20" + }, + { + "address": "0x77FE30b2cf39245267C0a5084B66a560f1cF9E1f", + "name": "Azbit", + "decimals": 18, + "symbol": "AZ" + }, + { + "address": "0x7f3EaB3491Ed282197038F1B89CA33D7e5ADffBa", + "name": "Coin-coin coinslot.com", + "decimals": 8, + "symbol": "CC coinslot.com" + }, + { + "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "name": "Tether USD", + "decimals": 6, + "symbol": "USDT" + }, + { + "address": "0xE1Ac9Eb7cDDAbfd9e5CA49c23bd521aFcDF8BE49", + "name": "Mycion", + "decimals": 18, + "symbol": "MYC" + }, + { + "address": "0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c", + "name": "Enjin Coin", + "decimals": 18, + "symbol": "ENJ" + }, + { + "address": "0x467Bccd9d29f223BcE8043b84E8C8B282827790F", + "name": "Telcoin", + "decimals": 2, + "symbol": "TEL" + }, + { + "address": "0xC12D1c73eE7DC3615BA4e37E4ABFdbDDFA38907E", + "name": "KickToken", + "decimals": 8, + "symbol": "KICK" + } + ] + } + `); + } + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/eth-api-transactions.js b/mock/ext-api-dyson/get/eth-api-transactions.js deleted file mode 100644 index 572281a51..000000000 --- a/mock/ext-api-dyson/get/eth-api-transactions.js +++ /dev/null @@ -1,75 +0,0 @@ -/// Ethereum API Mock -/// See: -/// curl "http://localhost:3000/eth-api/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://{eth rpc}/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl http://localhost:8420/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7 - -module.exports = { - path: '/eth-api/transactions', - template: function(params, query, body) { - //console.log(query) - if (query.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { - return JSON.parse(`{ - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", - "blockNumber": 9551915, - "time": 1582624428, - "nonce": 227, - "from": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "to": "0x1717f94202c126ef71d6C562de253Fe95eEbDD5f", - "value": "17635730000000000", - "gas": "21000", - "gasPrice": "4320000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", - "timeStamp": "1582624428" - }, - { - "operations": [ - { - "transactionId": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3-0", - "contract": { - "address": "0x0d8775f648430679a709e98d2b0cb6250d2887ef", - "symbol": "BAT", - "decimals": 18, - "totalSupply": "1500000000000000000000000000", - "name": "Basic Attention Token", - "updatedAt": "2020-03-23T06:01:25.975Z" - }, - "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", - "to": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "type": "token_transfer", - "value": "400000000000000000", - "id": null - } - ], - "contract": null, - "_id": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", - "blockNumber": 9519169, - "time": 1582189159, - "nonce": 16, - "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", - "to": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", - "value": "0", - "gas": "51839", - "gasPrice": "11500000000", - "gasUsed": "37028", - "input": "0xa9059cbb0000000000000000000000000875bcab22de3d02402bc38aee4104e1239374a7000000000000000000000000000000000000000000000000058d15e176280000", - "error": "", - "id": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", - "timeStamp": "1582189159" - } - ], - "total": 2 - }`); - } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; - } -}; diff --git a/mock/ext-api-dyson/get/ethclassic-api-commands1.js b/mock/ext-api-dyson/get/ethclassic-api-commands1.js new file mode 100644 index 000000000..44b3b2ace --- /dev/null +++ b/mock/ext-api-dyson/get/ethclassic-api-commands1.js @@ -0,0 +1,91 @@ +/// Ethereum Classic API Mock +/// See: +/// curl "http://localhost:3000/ethclassic-api/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" +/// curl "http://localhost:3000/ethclassic-api/tokens?address=0xa12105efa0663147bddee178f6a741ac15676b79" +/// curl "https://{etc rpc}/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" +/// curl "https://{etc rpc}/tokens?address=0xa12105efa0663147bddee178f6a741ac15676b79" +/// curl "http://localhost:8420/v1/ethereumclassic/0x7d2d0e153026fb428b885d86de50768d4cfeac37" +/// curl "http://localhost:8420/v2/classic/tokens/0xa12105efa0663147bddee178f6a741ac15676b79?Authorization=Bearer" + +module.exports = { + path: '/ethclassic-api/:command1?', + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.command1) { + case 'transactions': + if (query.address === '0x7d2d0e153026fb428b885d86de50768d4cfeac37') { + return JSON.parse(` + { + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe", + "blockNumber": 9833329, + "time": 1582237362, + "nonce": 7071, + "from": "0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9", + "to": "0x7D2D0E153026fB428B885D86De50768D4cFeaC37", + "value": "18529160000000000", + "gas": "21000", + "gasPrice": "1000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe", + "timeStamp": "1582237362" + }, + { + "operations": [], + "contract": null, + "_id": "0x524fb5fedace7bee35c165ac7f641d689122cb21390db7f7384507473a5ba058", + "blockNumber": 9804290, + "time": 1581854371, + "nonce": 6918, + "from": "0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9", + "to": "0x7D2D0E153026fB428B885D86De50768D4cFeaC37", + "value": "16208400000000000", + "gas": "21000", + "gasPrice": "1000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x524fb5fedace7bee35c165ac7f641d689122cb21390db7f7384507473a5ba058", + "timeStamp": "1581854371" + } + ], + "total": 2 + } + `); + } + + case 'tokens': + if (query.address === '0xa12105efa0663147bddee178f6a741ac15676b79') { + return JSON.parse(` + { + "total": 2, + "docs": [ + { + "address": "0xCA68fE57A0E9987F940Ebcc65fe5F96E7bC30128", + "name": "Litecoin Classic Token", + "decimals": 8, + "symbol": "LCT" + }, + { + "address": "0x2B682bd9d5c31E67a95cbdF0292017C02E51923C", + "name": "Ether Klown", + "decimals": 6, + "symbol": "KLOWN2" + } + ] + } + `); + } + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/ethclassic-api-transactions.js b/mock/ext-api-dyson/get/ethclassic-api-transactions.js deleted file mode 100644 index ec6719854..000000000 --- a/mock/ext-api-dyson/get/ethclassic-api-transactions.js +++ /dev/null @@ -1,60 +0,0 @@ -/// Ethereum Classic API Mock -/// See: -/// curl "http://localhost:3000/ethclassic-api/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" -/// curl "http://{etc rpc}/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" -/// curl http://localhost:8420/v1/ethereumclassic/0x7d2d0e153026fb428b885d86de50768d4cfeac37 - -module.exports = { - path: '/ethclassic-api/transactions', - template: function(params, query, body) { - //console.log(query) - if (query.address === '0x7d2d0e153026fb428b885d86de50768d4cfeac37') { - return JSON.parse(` - { - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe", - "blockNumber": 9833329, - "time": 1582237362, - "nonce": 7071, - "from": "0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9", - "to": "0x7D2D0E153026fB428B885D86De50768D4cFeaC37", - "value": "18529160000000000", - "gas": "21000", - "gasPrice": "1000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe", - "timeStamp": "1582237362" - }, - { - "operations": [], - "contract": null, - "_id": "0x524fb5fedace7bee35c165ac7f641d689122cb21390db7f7384507473a5ba058", - "blockNumber": 9804290, - "time": 1581854371, - "nonce": 6918, - "from": "0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9", - "to": "0x7D2D0E153026fB428B885D86De50768D4cFeaC37", - "value": "16208400000000000", - "gas": "21000", - "gasPrice": "1000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x524fb5fedace7bee35c165ac7f641d689122cb21390db7f7384507473a5ba058", - "timeStamp": "1581854371" - } - ], - "total": 2 - } - `); - } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; - } -}; diff --git a/mock/ext-api-dyson/get/iotex-api-commands2.js b/mock/ext-api-dyson/get/iotex-api-commands2.js new file mode 100644 index 000000000..7f5159777 --- /dev/null +++ b/mock/ext-api-dyson/get/iotex-api-commands2.js @@ -0,0 +1,823 @@ +/// Iotex API Mock +/// See: +/// curl "http://localhost:3000/iotex-api/staking/validators?status=bonded" +/// curl "http://localhost:3000/iotex-api/accounts/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" +/// curl "https://{iotex_rpc}/v1/staking/validators?status=bonded" +/// curl "https://{iotex_rpc}/v1/accounts/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" +/// curl "http://localhost:8420/v2/iotex/staking/validators" +/// curl "http://localhost:8420/v2/iotex/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m?Authorization=Bearer" + +module.exports = { + path: "/iotex-api/:command1/:command2?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch(params.command1) { + case 'accounts': + switch(params.command2) { + case 'io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m': + // status=bonded + return JSON.parse(`{"accountMeta":{"address":"io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m","balance":"15578806681028832609262","nonce":"583","pendingNonce":"584","numActions":"647"}}`); + + case 'io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5': + return JSON.parse(`{"accountMeta":{"address":"io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5","balance":"33829692159741946535","nonce":"4","pendingNonce":"5","numActions":"57"}}`); + } + + case 'staking': + switch(params.command2) { + case 'validators': + // status=bonded + return JSON.parse(` + [ + { + "id": "huobiwallet", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexcore", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "pubxpayments", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "droute", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "coredev", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "enlightiv", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iosg", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "royalland", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "gamefantasy#", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "laomao", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "cpc", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "hashbuy", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "hotbit", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotxplorerio", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexteam", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "airfoil", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "capitmu", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "ducapital", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "pnp", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "longz", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexlab", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "hofancrypto", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "draperdragon", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "yvalidator", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "satoshi", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "hashquark", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "mrtrump", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "elitex", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "ratels", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "rockx", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "blockfolio", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "preangel", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "consensusnet", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "blockboost", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "metanyx", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "coingecko", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "thebottoken#", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "cobo", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "zhcapital", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "infstones", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "tgb", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexgeeks", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotask", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "cryptolionsx", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "bittaker", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "keys", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "snzholding", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexunion", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "raketat8", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "wannodes", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "citex2018", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "wetez", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "eon", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "whales", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "eatliverun", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexicu", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "everstake", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "nodeasy", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "slowmist", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "alphacoin", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexhub", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "blackpool", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "superiotex", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "link", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexmainnet", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "lanhu", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "piexgo", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexbgogo", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "meter", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "bitwires", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "elink", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + } + ] + `); + } + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; + diff --git a/mock/ext-api-dyson/get/iotex-api-commands4.js b/mock/ext-api-dyson/get/iotex-api-commands4.js new file mode 100644 index 000000000..44dfe10c0 --- /dev/null +++ b/mock/ext-api-dyson/get/iotex-api-commands4.js @@ -0,0 +1,110 @@ +/// Iotex API Mock +/// See: +/// curl "http://localhost:3000/iotex-api/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" +/// curl "https://{iotex_rpc}/v1/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" +/// curl "http://localhost:8420/v2/iotex/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m?Authorization=Bearer" + +module.exports = { + path: "/iotex-api/:command1/:command2/:arg3/:arg4?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch(params.command1) { + case 'actions': + switch(params.command2) { + case 'addr': + switch(params.arg3) { + case 'io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5': + return JSON.parse(` + { + "total": "2", + "actionInfo": [ + { + "action": { + "core": { + "version": 1, + "nonce": "40", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "5010000000000000000000", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BHd42w46LIO7qw5+TsTo+QjAUZBhVc3NPwEVh3IHePcFQQeb9rFSPmEV6LhFS7cqRzDBpgSHuQbelY6wnPvMYmw=", + "signature": "CiJdvAO3jNUX7agpE4AvtrBdEzgFsm1MANhXTXeVtdkXxNrDV8xbSiFz6FuFUTd1L5uaFXoe1mxUPIrbTabh4QE=" + }, + "actHash": "7aceeda86535b8dd345e1ab2176a7f12e1907aac3591cf9422a5393feadb6bb6", + "blkHash": "57ca5160cb9aac7a16b4e5006295d93857220de966335a2a453992c824037ebe", + "blkHeight": "3291297", + "sender": "io1r8cwhdec6y3fpv42hv7ak0aqh0cfyc279ladxl", + "gasFee": "10000000000000000", + "timestamp": "2020-02-14T01:44:30Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "1", + "gasLimit": "500000", + "gasPrice": "1000000000000", + "execution": { + "amount": "5000000000000000000000", + "contract": "io1zn9mn4v63jg3047ylqx9nqaqz0ev659777q3xc", + "data": "B8NfwAAAAAAAY29yZWRldgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + } + }, + "senderPubKey": "BKarIa2N7C/tz6r93fnnHXHEXyGC4aG9fiTYSjwSKpUOWl2efDuLb9Fk+NysVn1hEFgFLjRONu/KlM4TnHaIQLQ=", + "signature": "0Pn96CJXbUmNvXsnvx0RgqPYuac7YD699liT/WqmE9Ak4EHYZXhTozu+t+JrM4cHmt37z7M3R4lbzC77gggHdgA=" + }, + "actHash": "7644e425163920f1d5658e12c96d6dfb4961ee35bc9886347fbb339d6b939dd8", + "blkHash": "1f7ab328160d0643b7a6af287a1559a88de70cd8a2068d40dcc814fdcdfba996", + "blkHeight": "3292065", + "sender": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5", + "gasFee": "264146000000000000", + "timestamp": "2020-02-14T02:48:30Z" + } + ] + } + `); + } + } + + case 'staking': + switch(params.command2) { + case 'delegations': + switch (params.arg3) { + case 'io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m': + return JSON.parse(` + [ + { + "delegator": { + "id": "iotxplorerio", + "status": true, + "info": { + "name": "iotxplorer", + "description": "", + "image": "https://imgc.iotex.io/dokc3pa1x/image/upload/v1551121446/delegates/iotxplorer/Group_2.png", + "website": "https://twitter.com/iotxplorer" + }, + "details": { + "reward": {"annual": 0}, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + "value": "100000000000000000000", + "status": "active" + } + ] + `); + } + } + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; + diff --git a/mock/ext-api-dyson/get/iotex-get-accounts.js b/mock/ext-api-dyson/get/iotex-get-accounts.js deleted file mode 100644 index 9e5912ade..000000000 --- a/mock/ext-api-dyson/get/iotex-get-accounts.js +++ /dev/null @@ -1,71 +0,0 @@ -/// Iotex API Mock -/// See: -/// curl "http://localhost:3000/iotex-api/actions/addr/io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5?start=0&count=25" -/// curl "https://pharos.iotex.io/v1/actions/addr/io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5?start=0&count=25" -/// curl http://localhost:8420/v1/iotex/io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5 -module.exports = { - path: "/iotex-api/actions/:action/:address?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - if (params.action === 'addr') { - if (params.address === 'io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5') { - return JSON.parse(` - { - "total": "2", - "actionInfo": [ - { - "action": { - "core": { - "version": 1, - "nonce": "40", - "gasLimit": "10000", - "gasPrice": "1000000000000", - "transfer": { - "amount": "5010000000000000000000", - "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" - } - }, - "senderPubKey": "BHd42w46LIO7qw5+TsTo+QjAUZBhVc3NPwEVh3IHePcFQQeb9rFSPmEV6LhFS7cqRzDBpgSHuQbelY6wnPvMYmw=", - "signature": "CiJdvAO3jNUX7agpE4AvtrBdEzgFsm1MANhXTXeVtdkXxNrDV8xbSiFz6FuFUTd1L5uaFXoe1mxUPIrbTabh4QE=" - }, - "actHash": "7aceeda86535b8dd345e1ab2176a7f12e1907aac3591cf9422a5393feadb6bb6", - "blkHash": "57ca5160cb9aac7a16b4e5006295d93857220de966335a2a453992c824037ebe", - "blkHeight": "3291297", - "sender": "io1r8cwhdec6y3fpv42hv7ak0aqh0cfyc279ladxl", - "gasFee": "10000000000000000", - "timestamp": "2020-02-14T01:44:30Z" - }, - { - "action": { - "core": { - "version": 1, - "nonce": "1", - "gasLimit": "500000", - "gasPrice": "1000000000000", - "execution": { - "amount": "5000000000000000000000", - "contract": "io1zn9mn4v63jg3047ylqx9nqaqz0ev659777q3xc", - "data": "B8NfwAAAAAAAY29yZWRldgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" - } - }, - "senderPubKey": "BKarIa2N7C/tz6r93fnnHXHEXyGC4aG9fiTYSjwSKpUOWl2efDuLb9Fk+NysVn1hEFgFLjRONu/KlM4TnHaIQLQ=", - "signature": "0Pn96CJXbUmNvXsnvx0RgqPYuac7YD699liT/WqmE9Ak4EHYZXhTozu+t+JrM4cHmt37z7M3R4lbzC77gggHdgA=" - }, - "actHash": "7644e425163920f1d5658e12c96d6dfb4961ee35bc9886347fbb339d6b939dd8", - "blkHash": "1f7ab328160d0643b7a6af287a1559a88de70cd8a2068d40dcc814fdcdfba996", - "blkHeight": "3292065", - "sender": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5", - "gasFee": "264146000000000000", - "timestamp": "2020-02-14T02:48:30Z" - } - ] - } - `); - } - } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; - } -}; diff --git a/mock/ext-api-dyson/get/kava-api-commands2.js b/mock/ext-api-dyson/get/kava-api-commands2.js new file mode 100644 index 000000000..815843c11 --- /dev/null +++ b/mock/ext-api-dyson/get/kava-api-commands2.js @@ -0,0 +1,2630 @@ +/// Kava API Mock +/// See: +/// curl "http://localhost:3000/kava-api/staking/validators?status=bonded" +/// curl "http://localhost:3000/kava-api/staking/pool" +/// curl "http://localhost:3000/kava-api/minting/inflation" +/// curl "https://{kava_rpc}/staking/validators?status=bonded" +/// curl "https://{kava_rpc}/staking/pool" +/// curl "https://{kava_rpc}/minting/inflation" +/// curl "http://localhost:8420/v2/kava/staking/validators" +/// curl "http://localhost:8420/v2/kava/staking/delegations/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m?Authorization=Bearer" + +module.exports = { + path: "/kava-api/:command1/:command2?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch(params.command1) { + case 'minting': + switch(params.command2) { + case 'inflation': + // status=bonded + return JSON.parse(`{"height":"1793129","result":"0.060343307052455856"}`); + } + + case 'txs': { + if (query["transfer.recipient"] === 'kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m') { + return JSON.parse(` + { + "total_count": "1", + "count": "1", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "793039", + "txhash": "84FFA6CC8428B7A5E82003A7BCA6D1FAB2DF296AD18BE73EE61CBCBF67623880", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "amount", + "value": "9999000ukava" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "70019", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7", + "to_address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", + "amount": [ + { + "denom": "ukava", + "amount": "9999000" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "ukava", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "As3eDIXFkLdMkBep+aV+6q9ccVRkA94snsXq2iL5bCTt" + }, + "signature": "QFx3iARLhLeuCCHRUbFAZTePzq+vGAYd4lB/F4JuCGYw1TrfIbAzJhmUHbXHcB/GC+f7Myv5xNrnlCPfCR53uA==" + } + ], + "memo": "" + } + }, + "timestamp": "2020-01-17T11:17:36Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "amount", + "value": "9999000ukava" + } + ] + } + ] + } + ] + } + `); + } + + if (query["message.sender"] === 'kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m') { + return JSON.parse(` + { + "total_count": "1", + "count": "1", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "1101012", + "txhash": "30EFE9E830D317F84629F9DC35177577DF6713D78D354C2C469DE633900303BC", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" + }, + { + "key": "amount", + "value": "9998000ukava" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "68317", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", + "to_address": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7", + "amount": [ + { + "denom": "ukava", + "amount": "9998000" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "ukava", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "AvgGasyPvRpG68UQ6IGPVKN+HrJix24tgwcYXIcIfsna" + }, + "signature": "iST3iM8TtkR5VHTFFhJE1zi+Nh6Invrg4hKgLEY2HCQ+R6Qj9L3jET4yRtAg6+QxitJab27+etoPjJbK20V/Cw==" + } + ], + "memo": "100009547" + } + }, + "timestamp": "2020-02-11T01:33:46Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" + }, + { + "key": "amount", + "value": "9998000ukava" + } + ] + } + ] + } + ] + } + `); + } + } + + case 'staking': + switch(params.command2) { + case 'pool': + return JSON.parse(` + { + "height":"1793093", + "result": { + "not_bonded_tokens": "1664170404961", + "bonded_tokens": "86469758994132" + } + } + `); + + case 'validators': + // status=bonded + return JSON.parse(` + {"height":"1793067","result":[ + { + "operator_address": "kavavaloper1qyc2cfl0nw8r95dsdw534x99wq0xcj9rmxpl7z", + "consensus_pubkey": "kavavalconspub1zcjduepqyj4j29k7hn58g7n6ert7mm4m7d0kllrx6h5rzzgpvjdt69r80zsq3az2xq", + "jailed": false, + "status": 2, + "tokens": "23006899100", + "delegator_shares": "23009200000.000000000000000000", + "description": { + "moniker": "Stake Capital", + "identity": "", + "website": "", + "security_contact": "", + "details": "'Trustless Digital Asset Management', Twitter: @StakeCapital, operated by @bneiluj @leopoldjoy" + }, + "unbonding_height": "1415519", + "unbonding_time": "2020-03-28T07:43:47.102756457Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.500000000000000000" + }, + "update_time": "2020-02-05T09:55:51.495267155Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1qfy0e2w62g6j4jg5djcqd4py3zsaeqexjplj2d", + "consensus_pubkey": "kavavalconspub1zcjduepqftv90yrm4g4w4mq47rdx9f384yxegfx7qfpkft89x2nlzafv36pq47wgls", + "jailed": false, + "status": 2, + "tokens": "20069063571", + "delegator_shares": "20069063571.000000000000000000", + "description": { + "moniker": "DragonStake", + "identity": "EA61A46F31742B22", + "website": "https://dragonstake.io", + "security_contact": "dragonstake@protonmail.com", + "details": "Forking the Banks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-20T18:38:18.607985797Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1q3y9qga5hf360dmzta67vp54qz25tmv4hhkk4t", + "consensus_pubkey": "kavavalconspub1zcjduepquu3m094f3j9jnklursgngn667tt3rz0ahpt4f7406qzqclc42mnqxlrn7e", + "jailed": false, + "status": 2, + "tokens": "20004700000", + "delegator_shares": "20004700000.000000000000000000", + "description": { + "moniker": "funky", + "identity": "1EBAA06E87B6DD60", + "website": "https://kava-funkyvalidator.nl", + "security_contact": "", + "details": "Validating with love in Holland for the world :)" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.110000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-21T00:42:13.651988876Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvl7z9xh", + "consensus_pubkey": "kavavalconspub1zcjduepqfkq6kfq6v3avvrc6qvh0tr6h97qhqxcxw6yhmsgwrclpm3qdqwwq4zl4kc", + "jailed": false, + "status": 2, + "tokens": "106190067334", + "delegator_shares": "106190067334.000000000000000000", + "description": { + "moniker": "WeStaking", + "identity": "DA9C5AD3E308E426", + "website": "https://westaking.io", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-03-17T04:24:29.070264845Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1pn5k9c5pxmg5f0rycpl9rrx6k6mk85scxf06zx", + "consensus_pubkey": "kavavalconspub1zcjduepq5gqsp02excuz03zequ5xkygsj8t0su4g46p00q9p0se5kkhr2fmsusw7w7", + "jailed": false, + "status": 2, + "tokens": "22999900000", + "delegator_shares": "22999900000.000000000000000000", + "description": { + "moniker": "Stir", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:45:39.203670522Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1phd8jz25lumudc7ac7rhmupvcqcv7lg3c8dprc", + "consensus_pubkey": "kavavalconspub1zcjduepquugppwhq0s4t5q8vh6n3j0t4t3susfasdfapa0zp8a8c36tpgj6qpqvs3s", + "jailed": false, + "status": 2, + "tokens": "2675001000000", + "delegator_shares": "2675001000000.000000000000000000", + "description": { + "moniker": "the_valiator", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-13T08:47:32.032003423Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1pceqe8we7drpfqrutchwy3f99800hhzuw6cc84", + "consensus_pubkey": "kavavalconspub1zcjduepqypw0nlaweu77hnlmy37gy82d0cn57g07yy9qrkm36tx5zhp6rjzqzfqta0", + "jailed": false, + "status": 2, + "tokens": "23459640449", + "delegator_shares": "23459640449.000000000000000000", + "description": { + "moniker": "Galaxy", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-25T09:53:43.24669958Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1rgcgqmnkeffks7enrv6hk5u4wg3nzfkmqlzjqd", + "consensus_pubkey": "kavavalconspub1zcjduepqv3f0m888swgzamf2mh3vh2gaehredz9uktv9rjcyfdjzvzvsthks4e5f4t", + "jailed": false, + "status": 2, + "tokens": "21000000000", + "delegator_shares": "21000000000.000000000000000000", + "description": { + "moniker": "syncnode", + "identity": "F422F328C14AFBFA", + "website": "wallet.syncnode.ro", + "security_contact": "", + "details": "https://www.linkedin.com/in/gbunea/" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.190000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-26T09:09:30.282258822Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1yrm63pqvld8uyzkavz55p2cktpm2gm8jd8xxlu", + "consensus_pubkey": "kavavalconspub1zcjduepq6nje57k4x0n0uua5dl26ufpgj9jw2n945hkrv066fv54924vnmeq60d92r", + "jailed": false, + "status": 2, + "tokens": "200010000000", + "delegator_shares": "200010000000.000000000000000000", + "description": { + "moniker": "Nodeasy.com", + "identity": "F7BABF2C95B02A9F", + "website": "https://www.nodeasy.com", + "security_contact": "", + "details": "Nodeasy.com,助你进入Staking时代!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-12-04T03:53:57.870109232Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1yjj2wfers947l6n5pynpgsqlz7svc5n8ssl6ye", + "consensus_pubkey": "kavavalconspub1zcjduepqftnrqaely46s7tzfkczuqfecuk3664wks5www53x6cj7rtl90zhqq6pacf", + "jailed": false, + "status": 2, + "tokens": "20410000001", + "delegator_shares": "20410000001.000000000000000000", + "description": { + "moniker": "StakingHub", + "identity": "25D7A4013B5C2A8F", + "website": "http://www.stakinghub.net/", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-14T23:30:14.565194467Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1yna6lete8nwwwctsalzdg04ldqaz73gtn33ydq", + "consensus_pubkey": "kavavalconspub1zcjduepqzwu26st99545k4qp79vuuslynk5qaxne9z4ucjfzs5g6646klwrqg5dxfa", + "jailed": false, + "status": 2, + "tokens": "23163160000", + "delegator_shares": "23163160000.000000000000000000", + "description": { + "moniker": "ChainodeTech", + "identity": "E34BF744FF5BA8A9", + "website": "https://chainode.tech/", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:35:31.864391537Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper196anr2ycsalg806dz29afklnecuaupvkh5qz6c", + "consensus_pubkey": "kavavalconspub1zcjduepqh525w7mx9apyra8jqeclcs90e6u9p22jrqaw8ymuf7mug2m5cg6sw7v7yu", + "jailed": false, + "status": 2, + "tokens": "47900816757", + "delegator_shares": "47900816757.000000000000000000", + "description": { + "moniker": "Phorest 🌲", + "identity": "A5281CA10EBCDCB5", + "website": "http://phorest.xyz/kava", + "security_contact": "", + "details": "Secure and stable PoS validator" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2020-01-20T14:02:20.813362703Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1x9hq3rjc48t5upcsr3c209ycgekfasne3l5nkc", + "consensus_pubkey": "kavavalconspub1zcjduepqvrf8r43ymaj39x73luu4qsp9sn4sw4t2lh77799mau2739xtrlnsqxyqju", + "jailed": false, + "status": 2, + "tokens": "23114805000", + "delegator_shares": "23114805000.000000000000000000", + "description": { + "moniker": "Masternode24.de", + "identity": "7EBA7730A85C865C", + "website": "https://masternode24.de/", + "security_contact": "", + "details": "Investieren Sie mit uns zusammen in die besten Blockchain Projekte" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-02-20T16:21:56.085890332Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1xftqdxvq0xkv2mu8c5y0jrsc578tak4m9u0s44", + "consensus_pubkey": "kavavalconspub1zcjduepqngw3s4hpzj8xscq6dfg4m8a6qeh5xwau0sjrknmlvg2lqdlgp0zszj7ewc", + "jailed": false, + "status": 2, + "tokens": "28160800000", + "delegator_shares": "28160800000.000000000000000000", + "description": { + "moniker": "Ping.pub", + "identity": "6EA723DA332200B2", + "website": "", + "security_contact": "", + "details": "We are one of the most secure and stable validator, welcome to delegate to us. 我们是最安全,最稳定,性价比最高的验证人节点,欢迎委托给我们!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-21T09:12:17.124698721Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1xka27j0jvmq97yunj5wp8fv242lycmax8ejlaf", + "consensus_pubkey": "kavavalconspub1zcjduepqx4zjl7vsh8pg4l3ndceu88h3027q0vvmpf7anv5c4xxq0htng5kqf24q07", + "jailed": false, + "status": 2, + "tokens": "3047139316200", + "delegator_shares": "3047139316200.000000000000000000", + "description": { + "moniker": "page2", + "identity": "", + "website": "https://coinmarketcap.com/2/", + "security_contact": "", + "details": "Lorem Ipsum" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1xhxzmj8fvkqn76knay9x2chfra826369dhdu2c", + "consensus_pubkey": "kavavalconspub1zcjduepqwsmxfu5vdulvnrwej06v4jj5hvdxxqqk82flvznhxkh5whrdnxms2z2kjx", + "jailed": false, + "status": 2, + "tokens": "1050206000000", + "delegator_shares": "1050206000000.000000000000000000", + "description": { + "moniker": "Figment Networks", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper18zksjhrefqew0zahmts894p8asscufxvdfq702", + "consensus_pubkey": "kavavalconspub1zcjduepq7qm0l9hy8m8a4my03x7rfvcy3vru0y0kv29n2fwcpmrvjda8n23skzza6m", + "jailed": false, + "status": 2, + "tokens": "14040219", + "delegator_shares": "14040219.000000000000000000", + "description": { + "moniker": "Consulnode", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-04T19:27:58.259245834Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper18s9m5d5cjf0humjv7mkq8pm47kchwm0r0369cx", + "consensus_pubkey": "kavavalconspub1zcjduepqphfe0vnahkpurcc6jn3kesfch6c0afnph8qv9ryx29gpec7rtf3q968vu3", + "jailed": false, + "status": 2, + "tokens": "20010000000", + "delegator_shares": "20010000000.000000000000000000", + "description": { + "moniker": "Stake5 Labs", + "identity": "C7595F18CC5D4FA6", + "website": "https://www.stake5labs.com", + "security_contact": "", + "details": "Professional PoS node contributor" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:01:13.609429004Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper18cf35l7req0k6ulqapeyv830mrrucn9xj87plr", + "consensus_pubkey": "kavavalconspub1zcjduepq7rr7drhvr6d67nydvwxtcqv3k0uv6krfn9ktm23l77eqrra9af9s828zrk", + "jailed": false, + "status": 2, + "tokens": "1171728959900", + "delegator_shares": "1171846144514.451445144514451445", + "description": { + "moniker": "mxcpospool", + "identity": "", + "website": "https://www.mxc.co", + "security_contact": "", + "details": "" + }, + "unbonding_height": "1433843", + "unbonding_time": "2020-03-29T19:11:06.277346205Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-13T10:05:51.300009009Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1g20mhvcpjxp6gzlwhtfcphjehwcl2njqydgu7q", + "consensus_pubkey": "kavavalconspub1zcjduepqcg7v7vpgw7tj2f4z6yle5vpwutm3n5zjmlx2dpypphxd0cdvyaeqyeyteg", + "jailed": false, + "status": 2, + "tokens": "23142100000", + "delegator_shares": "23142100000.000000000000000000", + "description": { + "moniker": "pi-londoner", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-02-10T23:44:11.226734593Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1gtd040dmljyaty9tkhq0mlqz7saer48v4d608x", + "consensus_pubkey": "kavavalconspub1zcjduepqqy2kzt636d5ak6l6gxsxexgtadcm8d59qh3wumgtswpa8hau7apsk4ecma", + "jailed": false, + "status": 2, + "tokens": "2391603214", + "delegator_shares": "2391603214.000000000000000000", + "description": { + "moniker": "kava.bi23", + "identity": "EB3470949B3E89E2", + "website": "https://kava.bi23.com", + "security_contact": "", + "details": "Bi23 focuses on the Crypto-Assets, providing customers with Staking and DeFi services." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-12-04T23:42:01.494010426Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1g4qpetrj59a29e4wxpe74x93q4df2czjh8r9ak", + "consensus_pubkey": "kavavalconspub1zcjduepqe3evdke2eyzv7ngkwj0w4qarpqad47s6eqsqavesmzhz664ewmzsre8fkj", + "jailed": false, + "status": 2, + "tokens": "978579000000", + "delegator_shares": "978579000000.000000000000000000", + "description": { + "moniker": "IOSG", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1ffcujj05v6220ccxa6qdnpz3j48ng024ykh2df", + "consensus_pubkey": "kavavalconspub1zcjduepqxzqld0trat9nu9j53rzxwvpnpjekxf02eeg8mw3xewjky2qgy69sgh0tcw", + "jailed": false, + "status": 2, + "tokens": "2207656905814", + "delegator_shares": "2207656905814.000000000000000000", + "description": { + "moniker": "🐠stake.fish", + "identity": "90B597A673FC950E", + "website": "http://stake.fish", + "security_contact": "", + "details": "stake.fish is a reliable validator for PoS blockchains. Stake with us. We know staking." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-12-03T18:59:42.821933888Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1fw7vjc3fphahqxpdjypddlulnltxws8g0mrds7", + "consensus_pubkey": "kavavalconspub1zcjduepq0hlydw7ztc5fp7e6k3snlafkz4h45tyaqzxxw5j87g4trdy826yskkmmgc", + "jailed": false, + "status": 2, + "tokens": "20090000000", + "delegator_shares": "20090000000.000000000000000000", + "description": { + "moniker": "BasBlock", + "identity": "E0A6A3980E464A66", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "1318309", + "unbonding_time": "2020-03-20T12:28:42.433079809Z", + "commission": { + "commission_rates": { + "rate": "0.130000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-02-01T11:28:28.795491395Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1fmas0qlsucg4qwf8mqyrylcg3uluz2ffg8952q", + "consensus_pubkey": "kavavalconspub1zcjduepqkv4fkh6u8l068xusy5dhz2jpz969nzszntuavsc0uu6sxxr9wafqewxkac", + "jailed": false, + "status": 2, + "tokens": "22612704810", + "delegator_shares": "22612704810.000000000000000000", + "description": { + "moniker": "mintonium", + "identity": "0FF7C542EF9422AB", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-15T14:00:18.218278987Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper12qn7y04wzr5s3h4dmdtre4q9f4nvc03a9a9qsz", + "consensus_pubkey": "kavavalconspub1zcjduepqsnl9ahysm5hypmpfuwyqkha280aa9ushdlvvqza4u7rfmf0pvdxqlla0wj", + "jailed": false, + "status": 2, + "tokens": "22996800100", + "delegator_shares": "22999100000.000000000000000000", + "description": { + "moniker": "dexhybrid", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "1321471", + "unbonding_time": "2020-03-20T18:38:12.071818929Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.020000000000000000" + }, + "update_time": "2019-11-16T14:33:31.092253347Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper12r77hhj6ylvvl4etjm0fmpzh07jum8u7qqd695", + "consensus_pubkey": "kavavalconspub1zcjduepq3ndp4jxqsvxlp5crspvu6tcra7zg7cnnxzm3hx6sxhcd409ytzyskcadfv", + "jailed": false, + "status": 2, + "tokens": "10000000", + "delegator_shares": "10000000.000000000000000000", + "description": { + "moniker": "stefansky", + "identity": "878AB3284CD8CBED", + "website": "http://stefancondurachi.com", + "security_contact": "", + "details": "Software Architect" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-02-03T05:32:50.725944775Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "kavavaloper129kkennsm7na34lu6sn4kwxp7ewes58y4fx6y9", + "consensus_pubkey": "kavavalconspub1zcjduepqz354kpmk0970fpvhw6va6ufhasrnh4sgzh82cfd5egm9ggl5gy6qlgwqjt", + "jailed": false, + "status": 2, + "tokens": "23011000000", + "delegator_shares": "23011000000.000000000000000000", + "description": { + "moniker": "stake.zone", + "identity": "0A888728046018EC", + "website": "http://stake.zone", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.040000000000000000" + }, + "update_time": "2019-11-15T14:01:07.22222101Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper12g40q2parn5z9ewh5xpltmayv6y0q3zs6ddmdg", + "consensus_pubkey": "kavavalconspub1zcjduepq0plta99ns8ec5h5sj8x4ufzkdpsz6xu7ckp62hkagfxey242qzgstm0ldw", + "jailed": false, + "status": 2, + "tokens": "5085834241836", + "delegator_shares": "5085834241836.000000000000000000", + "description": { + "moniker": "P2P.ORG - P2P Validator", + "identity": "E12F4695036D8072", + "website": "https://p2p.org", + "security_contact": "vladimir.m@p2p.org", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper12et238paeqxyhvk2pfs20ygfj6ct0dx2ccsdz5", + "consensus_pubkey": "kavavalconspub1zcjduepqzmls593jxfkz8unn306c8nh757n24ztxhnzwzvpuadalk0skuvfsaamxwx", + "jailed": false, + "status": 2, + "tokens": "3000000", + "delegator_shares": "3000000.000000000000000000", + "description": { + "moniker": "hippo", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-03-10T14:45:34.603416711Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1t5l8ht0wxpd4lpe4cweftrpg5kyn3qp437yvnr", + "consensus_pubkey": "kavavalconspub1zcjduepqe58zj7f5zjqu023l3sd96qwurtzy7ayv2549z6mca8zmalvtlxfs80qsja", + "jailed": false, + "status": 2, + "tokens": "20517050000", + "delegator_shares": "20517050000.000000000000000000", + "description": { + "moniker": "DelegaNetworks", + "identity": "1BED7C08416A619F", + "website": "https://delega.io", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-24T20:37:25.840600387Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1vyx7wt8s8dwcspdt7dy49sq4l3jwyhxyndakmm", + "consensus_pubkey": "kavavalconspub1zcjduepq2v03gwaywadc7ar423rxmy7k7ev3y3tkvsetq7w30j0whymjkacsxjg9lt", + "jailed": false, + "status": 2, + "tokens": "2999557167252", + "delegator_shares": "2999557167252.000000000000000000", + "description": { + "moniker": "InfStones", + "identity": "39A41C2FDE0AD040", + "website": "https://infstones.io", + "security_contact": "", + "details": "Fueling Blockchain Beyond Infinity" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1vfawvtzvmcjkpqzhezvhk9q5tv5t7x8smz95uu", + "consensus_pubkey": "kavavalconspub1zcjduepq2yhf7ntk9dkkqpg07ead9nzjmldf2ar6tx6uz8jeaqjedrj9keqsq0hn02", + "jailed": false, + "status": 2, + "tokens": "23079000000", + "delegator_shares": "23079000000.000000000000000000", + "description": { + "moniker": "Newroad Network", + "identity": "91FAC10CA3718A17", + "website": "https://newroad.network/kava/", + "security_contact": "", + "details": "We provide a professional delegation service for multiple Proof of Stake networks. We use a secure and redundant setup. Visit our website for more information." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.350000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-02-03T04:21:51.013448233Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1vw35vclatlrcmzuaxf2fleyuk38xa7xf4vdaq2", + "consensus_pubkey": "kavavalconspub1zcjduepqnrpursauds6wjnqht0979kjr0pvk5jp4c0cv46feazqv4qappqsqn5rd22", + "jailed": false, + "status": 2, + "tokens": "875050100000", + "delegator_shares": "875050100000.000000000000000000", + "description": { + "moniker": "hashquark", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1vw4t8ge2ephu0wuhcmclcw04ag2vzj9rpdme2x", + "consensus_pubkey": "kavavalconspub1zcjduepq0fjxw9wq8swcrk26j2vk8qm90d0vn94c2c7cs0ru5rgy2zlyv5eq8q5kvc", + "jailed": false, + "status": 2, + "tokens": "20153000000", + "delegator_shares": "20153000000.000000000000000000", + "description": { + "moniker": "UbikCapital", + "identity": "8265DEAF50B61DF7", + "website": "https://ubik.capital", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-12-25T21:46:08.338409716Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1vuylvflgy75d8zr07ta8x0gcqynvkvw70et853", + "consensus_pubkey": "kavavalconspub1zcjduepqvk6tye9w7399g7xys6j5ycw5rly8wz92mp0pevgmrv30qc4nva5sc2u25u", + "jailed": false, + "status": 2, + "tokens": "1874980100000", + "delegator_shares": "1874980100000.000000000000000000", + "description": { + "moniker": "Lemniscap", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1dwae0ny4uuvacucakm9v8r8mxhw82zack4cn7y", + "consensus_pubkey": "kavavalconspub1zcjduepq3rfkl40umrfy0wq9u9m5mc5zv30x4lmj08vup2u5d90t4fu3qe7qvq5scl", + "jailed": false, + "status": 2, + "tokens": "3317768400000", + "delegator_shares": "3317768400000.000000000000000000", + "description": { + "moniker": "OKExPool", + "identity": "", + "website": "www.okex.com/pool", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-20T02:25:09.919481267Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1dj63l3z0smqa8au5yek37nmj0xd60zs9dwmdh0", + "consensus_pubkey": "kavavalconspub1zcjduepqq0hj2jx5x7p65t56c7s750e85yp0u6xvydk6eh5m45xq755rjqlsthzygr", + "jailed": false, + "status": 2, + "tokens": "20100000782", + "delegator_shares": "20100000782.000000000000000000", + "description": { + "moniker": "Yn", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:04:52.626128649Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1dntlhrw3jrej6ssdp64yfmkkz08ykyx4n7hphh", + "consensus_pubkey": "kavavalconspub1zcjduepqxd9wm06lw0p6nrysw2ecmusgrmsq6438ht4wh7gx64a0m6vnu4qs7jhyjk", + "jailed": false, + "status": 2, + "tokens": "4001049500000", + "delegator_shares": "4001049500000.000000000000000000", + "description": { + "moniker": "Staked", + "identity": "E7BFA6515FB02B3B", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-03T16:23:23.639110694Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1dede4flaq24j2g9u8f83vkqrqxe6cwzrxt5zsu", + "consensus_pubkey": "kavavalconspub1zcjduepqstxrft39yrg5hgalcnjqurms5tj2yqpw9y85axv9gsxyld62cneqg6k7nk", + "jailed": false, + "status": 2, + "tokens": "104328140934", + "delegator_shares": "104328140934.000000000000000000", + "description": { + "moniker": "POS Bakerz", + "identity": "3AFAE7268F4DFD10", + "website": "https://posbakerz.com/", + "security_contact": "", + "details": "Secure, Reliable and Efficient Staking-as-a-Service" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.098500000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-20T12:29:19.763049675Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1davtd9w5yadvlg5x7aw0kpkyhckk5m5ecrmnyl", + "consensus_pubkey": "kavavalconspub1zcjduepq9x39e7g3m2hv8v6nxcx2lmy6fzaeqmvdz4uqtpm8qaxtr6527yrsh3fkgl", + "jailed": false, + "status": 2, + "tokens": "23000000000", + "delegator_shares": "23000000000.000000000000000000", + "description": { + "moniker": "Cyberili", + "identity": "3554F49719B1BF6F", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:55:31.701406451Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1wtcn3ylrsp4qp4urlhkf78kkt8f2ch7p0f0p98", + "consensus_pubkey": "kavavalconspub1zcjduepqjffmrcy39vaecs9rjaju3hzq97nggr2l0zg96k2u3c54mfx20hks43wvdy", + "jailed": false, + "status": 2, + "tokens": "23124628440", + "delegator_shares": "23124628440.000000000000000000", + "description": { + "moniker": "007", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-03-20T19:41:53.352622226Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1wu8m65vqazssv2rh8rthv532hzggfr3h9azwz9", + "consensus_pubkey": "kavavalconspub1zcjduepqqg29usle4d3hgt4eadn3epppa2h6dsga9mj6sxvyj5prchufgr5qmrneka", + "jailed": false, + "status": 2, + "tokens": "5005157202698", + "delegator_shares": "5005157202698.000000000000000000", + "description": { + "moniker": "Binance Staking", + "identity": "", + "website": "https://binance.com", + "security_contact": "", + "details": "Exchange the world!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1spkjjtwks5zt0dqexj8rv8ljwmwxe8ufkraukq", + "consensus_pubkey": "kavavalconspub1zcjduepq9gppak7hsjrwvyxz2y9hy830gzsx2r4nax43vh2lprj0wj3rvghsyu6xev", + "jailed": false, + "status": 2, + "tokens": "22950000000", + "delegator_shares": "22950000000.000000000000000000", + "description": { + "moniker": "Jupiter.IAM", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-17T11:35:54.989770823Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1srhded4xw0krcwlvddtcyycuh70fp5ry9yvp86", + "consensus_pubkey": "kavavalconspub1zcjduepq64ugztwcunjrpema5pqwherkfznms8ykc4jx7syc6tm5ztv58keqxlc6fv", + "jailed": false, + "status": 2, + "tokens": "2402020264361", + "delegator_shares": "2402020264361.000000000000000000", + "description": { + "moniker": "TRGCapital", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-12-12T17:38:19.894601876Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1s8akp0nq7z7vuf5g9agdswcwq7vm9uwudk0han", + "consensus_pubkey": "kavavalconspub1zcjduepqpgz29c6efzyj96y0kkjrxns67nsm5t3rae0ra2nmrx4fm5j33nkqn066rz", + "jailed": false, + "status": 2, + "tokens": "22950000000", + "delegator_shares": "22950000000.000000000000000000", + "description": { + "moniker": "IvoryTower", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-17T02:12:20.831453541Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper13fxkk4730cqglgdv7w0mdelyx07myyq76uf9f3", + "consensus_pubkey": "kavavalconspub1zcjduepquwqhhvst3t6pg7rzutmvr3dma46ux6nggfxrju4f6u2dza9n3l7s54jgu7", + "jailed": false, + "status": 2, + "tokens": "23213610000", + "delegator_shares": "23215931593.159315931593159315", + "description": { + "moniker": "Finantra.com", + "identity": "", + "website": "http://finantra.com", + "security_contact": "", + "details": "" + }, + "unbonding_height": "1122467", + "unbonding_time": "2020-03-04T18:59:03.214161979Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-03-14T19:38:24.407313925Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper13vstf6ecmfe4p0gaufumk569sdawhtrf8gu56h", + "consensus_pubkey": "kavavalconspub1zcjduepq2ye3234dt2jes9g49mf5sdy7f7xfshekg5xyjm7vq7m07s9uq82qger9yk", + "jailed": false, + "status": 2, + "tokens": "23081092090", + "delegator_shares": "23081092090.000000000000000000", + "description": { + "moniker": "QuantaFrontier.com", + "identity": "", + "website": "https://QuantaFrontier.com", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-03-10T19:08:38.751434231Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper13dfu6et0m8zm4hachudvn62w0c2zvcmrqn8cs3", + "consensus_pubkey": "kavavalconspub1zcjduepqcctrta82mcm79j0e6ttgguekmljvud0y4rlggrm9uw9t49qemujsd69h59", + "jailed": false, + "status": 2, + "tokens": "23144338847", + "delegator_shares": "23144338847.000000000000000000", + "description": { + "moniker": "Sunshine", + "identity": "24DB71E8B5076192", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.300000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-04-05T16:35:57.63239062Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1jyuv7z9at27elvmnmzh2v39dc06r9kjcy59xkr", + "consensus_pubkey": "kavavalconspub1zcjduepqcznteuyudn9zmfzyu6cksgh9qv3e9sc9fkyu32djy9d29ertyjrqfwcnvj", + "jailed": false, + "status": 2, + "tokens": "2799950000000", + "delegator_shares": "2799950000000.000000000000000000", + "description": { + "moniker": "DAF", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1j26c4k2jj9tv95whdhva3e8v2fcm4s3dsgstd2", + "consensus_pubkey": "kavavalconspub1zcjduepq3ra0zhkgeyqzksspztcx475dtlra5lckdpzwht29mk9fuepnkjqsw2rly7", + "jailed": false, + "status": 2, + "tokens": "3269187409856", + "delegator_shares": "3269187409856.000000000000000000", + "description": { + "moniker": "DokiaCapital", + "identity": "", + "website": "https://staking.dokia.cloud", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "0.120000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1jhraz4ftxl2pd37knmeua7wjxghmlskwf7x8pf", + "consensus_pubkey": "kavavalconspub1zcjduepq6rxswfd9puq5t7jlp52cetv5s7cqm4l4n5tx4gqsclg9ngswe45qwhz2dm", + "jailed": false, + "status": 2, + "tokens": "23443000000", + "delegator_shares": "23443000000.000000000000000000", + "description": { + "moniker": "mariposa2", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-12-26T13:44:37.328086675Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1jlzx4js09d9zzyuhuz8sfdweklrapzacuhsxq5", + "consensus_pubkey": "kavavalconspub1zcjduepqg94y638yaj7es28zdktmar4jn9wu0v2l4h8mr40gerr2rek8q3rq9d3gh6", + "jailed": false, + "status": 2, + "tokens": "3099479960136", + "delegator_shares": "3099479960136.000000000000000000", + "description": { + "moniker": "shiprekt", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1jl42l225565y3hm9dm4my33hjgdzleucqryhlx", + "consensus_pubkey": "kavavalconspub1zcjduepqtlmej0vprfmun69nsnmuv56j3dctzw90tmk0f805lqxcqn9sr77s4nzkx0", + "jailed": false, + "status": 2, + "tokens": "34047476004", + "delegator_shares": "34047476004.000000000000000000", + "description": { + "moniker": "melea-◮👁◭", + "identity": "4BE49EABAA41B8BF", + "website": "https://meleatrust.com/kava/", + "security_contact": "meleacrypto@gmail.com", + "details": "Validator service secure and trusted, awarded in Game Of Steaks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-12-27T14:23:19.174760869Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1nxgg4grsc0fwh893mks62d3x3r6uazgpj3m3cr", + "consensus_pubkey": "kavavalconspub1zcjduepqkk7jeymtt9rk3jlhxtxu95akmxfusj44mqq2wuq8c2hckulpga0q4yrauv", + "jailed": false, + "status": 2, + "tokens": "23085863116", + "delegator_shares": "23085863116.000000000000000000", + "description": { + "moniker": "Easy 2 Stake", + "identity": "2C877AC873132C91", + "website": "www.easy2stake.com", + "security_contact": "", + "details": "Easy.Stake.Trust. As easy and as simple as you would click next. Complete transparency and trust with a secure and stable validator." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:00:10.631092707Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1njvaku4qg9pxmx9jgjks36xrxfd6fyqs3tgs4d", + "consensus_pubkey": "kavavalconspub1zcjduepqsxtm3s99l58x9e3sqfxx4z88v6t4pyhku6fnu60drwmq8zm4jwjqx257u9", + "jailed": false, + "status": 2, + "tokens": "1000002000000", + "delegator_shares": "1000002000000.000000000000000000", + "description": { + "moniker": "BitMax Staking", + "identity": "", + "website": "https://bitmax.io/", + "security_contact": "", + "details": "Trading Platform Industry Leader driven by Product Innovation" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-15T09:09:05.545733701Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1nnwwu4km0alut2q8vhg7zjt45wyehddpwlfrmj", + "consensus_pubkey": "kavavalconspub1zcjduepqey9flxqkdw5ewlskac3wltu4yl93asdamt66prm393zc8g93dcuszezutf", + "jailed": false, + "status": 2, + "tokens": "5681499001", + "delegator_shares": "5682067150.013579192799429688", + "description": { + "moniker": "Wetez", + "identity": "26FA2B24F46A98EF", + "website": "https://www.wetez.io", + "security_contact": "", + "details": "Wetez is the most professional team in the POS ( Proof of Stake) field.Wetez是POS领域最专业的团队,为POS带来的权益做更多赋能。" + }, + "unbonding_height": "448243", + "unbonding_time": "2020-01-11T04:03:40.112446434Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-17T01:33:27.008856884Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper15kwwzz908wl0qv4w66a5ee70kytpmfc9khvah6", + "consensus_pubkey": "kavavalconspub1zcjduepq8ylkkt83ktmljrmmk7evkj600j3p9xjnm4kf44z33hyr3cum448sqw2a6j", + "jailed": false, + "status": 2, + "tokens": "6118996081", + "delegator_shares": "6118996081.000000000000000000", + "description": { + "moniker": "Staking4All", + "identity": "", + "website": "https://www.staking4all.org", + "security_contact": "", + "details": "Validator for Proof of Stake blockchains. Delegate to us for a easy staking experience" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-25T15:53:47.321864774Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper15urq2dtp9qce4fyc85m6upwm9xul3049dcs7da", + "consensus_pubkey": "kavavalconspub1zcjduepqsglrgfudcqw4la7e54lfdu2va9z5gd4r8z6wrwe8m5rtz3d2vtsq55njyr", + "jailed": false, + "status": 2, + "tokens": "2475995760455", + "delegator_shares": "2475995760455.000000000000000000", + "description": { + "moniker": "Chorus One", + "identity": "00B79D689B7DC1CE", + "website": "https://chorus.one", + "security_contact": "security@chorus.one", + "details": "Secure Kava and shape its future by delegating to Chorus One, a highly secure and stable validator. By delegating, you agree to the terms of service." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.075000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper14fkp35j5nkvtztmxmsxh88jks6p3w8u7p76zs9", + "consensus_pubkey": "kavavalconspub1zcjduepqlgrd20pqzw4dmkdkg3nd65mra077pjne8l0d43wsvw93y9dw450smyh79n", + "jailed": false, + "status": 2, + "tokens": "23654500000", + "delegator_shares": "23654500000.000000000000000000", + "description": { + "moniker": "Bit Cat🐱", + "identity": "FAB46CEEAEAB9FA1", + "website": "https://www.bitcat365.com", + "security_contact": "", + "details": "Secure and stable KAVA validator service from China team" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:01:37.718892109Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper140g8fnnl46mlvfhygj3zvjqlku6x0fwu6lgey7", + "consensus_pubkey": "kavavalconspub1zcjduepqvtvkhh22hgfvp865tj4uwltv0hu7fs3vwmxwrl0n2mdpfuzj0p0qes2k9e", + "jailed": false, + "status": 2, + "tokens": "4051502234537", + "delegator_shares": "4051502234537.000000000000000000", + "description": { + "moniker": "Cosmostation", + "identity": "AE4C403A6E7AA1AC", + "website": "https://www.cosmostation.io", + "security_contact": "", + "details": "Delegate your Kava and start earning your staking rewards." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-18T01:27:53.436530462Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper14kn0kk33szpwus9nh8n87fjel8djx0y02c7me3", + "consensus_pubkey": "kavavalconspub1zcjduepqk8fq7ssjps5r40j32lmhxrdzfg72k8dknc3xndljjtlghc9u9nrshrlf3r", + "jailed": false, + "status": 2, + "tokens": "2883221903903", + "delegator_shares": "2883221903903.000000000000000000", + "description": { + "moniker": "Forbole", + "identity": "2861F5EE06627224", + "website": "https://www.forbole.com", + "security_contact": "info@forbole.com", + "details": "Professional PoS validator based in Hong Kong" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.095000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1kgddca7qj96z0qcxr2c45z73cfl0c75p27tsg6", + "consensus_pubkey": "kavavalconspub1zcjduepqzah30dnsz855gnufkqlqnq50ksyc4jetprhz4ugg2rmuzhh3gvwsfxan38", + "jailed": false, + "status": 2, + "tokens": "2156193000000", + "delegator_shares": "2156193000000.000000000000000000", + "description": { + "moniker": "ChainLayer", + "identity": "AD3CDBC91802F94A", + "website": "https://www.chainlayer.io", + "security_contact": "", + "details": "Secure and reliable validator. TG: https://t.me/chainlayer" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.100000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1kwj4l5putuymgxw9kx8emh3e5dpaca0hnf3zdy", + "consensus_pubkey": "kavavalconspub1zcjduepqmqwfzwnmjdnkmt9k75k3q7rez3lr08m9fqev06rh6m2sdke8kmusjhywm9", + "jailed": false, + "status": 2, + "tokens": "23173000000", + "delegator_shares": "23173000000.000000000000000000", + "description": { + "moniker": "InChainWorks", + "identity": "BE448F9ECAB40ABE", + "website": "https://inchain.works", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-06T10:37:03.352901001Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1k4kxxfkhhwvyzxxxgksefkzpxahp9wfc572esl", + "consensus_pubkey": "kavavalconspub1zcjduepqt0k39t3zmz460are7rf9n97u20qhfmukp8ujeqhe0jg2q7ye99cqprr8nr", + "jailed": false, + "status": 2, + "tokens": "23215000000", + "delegator_shares": "23215000000.000000000000000000", + "description": { + "moniker": "Mr.K", + "identity": "74D3AF53635231D9", + "website": "", + "security_contact": "", + "details": "Validator on Tendermint base project" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-29T03:49:52.013497324Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1kc6vzheht92jwf0gtzhjk6jjht67rxhal9z04v", + "consensus_pubkey": "kavavalconspub1zcjduepqt8065r783whzn3w47uuhm0t8rw2ke0zda6awa4j5lemlhw029mtqs79pcs", + "jailed": false, + "status": 2, + "tokens": "20028000000", + "delegator_shares": "20028000000.000000000000000000", + "description": { + "moniker": "moonli.me", + "identity": "662AEC27BD90D036", + "website": "https://moonli.me", + "security_contact": "", + "details": "How to Delegete: https://go.moonli.me/kava" + }, + "unbonding_height": "972523", + "unbonding_time": "2020-02-21T16:44:26.247476886Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:03:28.153247409Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1k760ypy9tzhp6l2rmg06sq4n74z0d3rejwwaa0", + "consensus_pubkey": "kavavalconspub1zcjduepqqnxh5k4mhggtdx2u9j9xgq0etpkxpevg333sm954efqema6mn5yqqyf0gw", + "jailed": false, + "status": 2, + "tokens": "25190876386", + "delegator_shares": "25190876386.000000000000000000", + "description": { + "moniker": "novy", + "identity": "5422BE13389B2B4D", + "website": "https://novy.pw", + "security_contact": "", + "details": "Let's validate this network!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-29T20:44:00.222304348Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1h9ulmhqv5e2373khk6s9n0wtrfc5qavre09fxl", + "consensus_pubkey": "kavavalconspub1zcjduepqjqsd0jkhftta7fuc9e45f3yat25ja9xknzrdqye6zk9kyx40wkaq50hcdv", + "jailed": false, + "status": 2, + "tokens": "23182088934", + "delegator_shares": "23182088934.000000000000000000", + "description": { + "moniker": "alexDcrypto", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.190000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-02T22:54:47.953329027Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1hezl6xwva28xt0hk204dllalagenmfsnuu50j6", + "consensus_pubkey": "kavavalconspub1zcjduepqwf05tj86hm83n55lha6zgeyf9jyyz053cwq957nhhv933v9z9sgqdcmt5s", + "jailed": false, + "status": 2, + "tokens": "169401100000", + "delegator_shares": "169401100000.000000000000000000", + "description": { + "moniker": "01node.com", + "identity": "22823CD59617B8E3", + "website": "https://01node.com", + "security_contact": "", + "details": "01node Staking Services" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.150000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:00:18.218278987Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1c9ye54e3pzwm3e0zpdlel6pnavrj9qqvh0atdq", + "consensus_pubkey": "kavavalconspub1zcjduepqc8585309s34yq92calayzy4xc4hu8rrx4pkrymewdy5qyjkx5tjqjgp7tq", + "jailed": false, + "status": 2, + "tokens": "4116869613316", + "delegator_shares": "4116869613316.000000000000000000", + "description": { + "moniker": "StakeWith.Us", + "identity": "609F83752053AD57", + "website": "https://stakewith.us", + "security_contact": "node@stakewith.us", + "details": "Secured Staking Made Easy. Put Your Crypto to Work - Hassle Free. Disclaimer: Delegators should understand that delegation comes with slashing risk. By delegating to StakeWithUs Pte Ltd, you acknowledge that StakeWithUs Pte Ltd is not liable for any losses on your investment." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1cj9cdx9mg95lhvpquym08ncgzpjvhmnwdvm5kc", + "consensus_pubkey": "kavavalconspub1zcjduepq3w00ypwl5652c8unvwhn4urpkpcpztkusgqsdztdsq8fhycw224qwlcd33", + "jailed": false, + "status": 2, + "tokens": "868075391", + "delegator_shares": "868075391.000000000000000000", + "description": { + "moniker": "Sifu Ventures", + "identity": "", + "website": "http://sifu.ventures", + "security_contact": "", + "details": "dPos Tokens Investment Fund" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-24T08:49:40.805033852Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1ceun2qqw65qce5la33j8zv8ltyyaqqfctl35n4", + "consensus_pubkey": "kavavalconspub1zcjduepqsqtuf26ph4szcxutxscz5eq0g9tnqvedhdf203cha77m8xlnuy0sy3nky9", + "jailed": false, + "status": 2, + "tokens": "3266752395198", + "delegator_shares": "3266752395198.000000000000000000", + "description": { + "moniker": "sikka", + "identity": "", + "website": "https://sikka.tech", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper168g9nn9vnamhsnjkm7uqqee9f3v07flgwwddf9", + "consensus_pubkey": "kavavalconspub1zcjduepq29lrp34q3dveyt8r2mnc3kd82y5a5dsq39laj6yhkwans0ay2u9smmru3r", + "jailed": false, + "status": 2, + "tokens": "23164473513", + "delegator_shares": "23164473513.000000000000000000", + "description": { + "moniker": "sebytza05", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.140000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:00:18.218278987Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1645czvg787l0jr6mawhs9dm3mljnggj003yed9", + "consensus_pubkey": "kavavalconspub1zcjduepqws4aku5x2z0806kpyd750yzdpwrergpj82akyj0zz4ft6t38c4esdztwm8", + "jailed": false, + "status": 2, + "tokens": "23138575200", + "delegator_shares": "23143203500.319736666961944921", + "description": { + "moniker": "Mike Pocket", + "identity": "C57B29418AE33CC0", + "website": "", + "security_contact": "", + "details": "GO KAVA GO" + }, + "unbonding_height": "1426431", + "unbonding_time": "2020-03-29T04:47:39.676931865Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-08T11:13:06.439174757Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper16lnfpgn6llvn4fstg5nfrljj6aaxyee9z59jqd", + "consensus_pubkey": "kavavalconspub1zcjduepquwh8pq39pwddp3etxk82d3u57kdfnvftgxamx4kcqduk8q02c3xqsyfaaa", + "jailed": false, + "status": 2, + "tokens": "2833230807310", + "delegator_shares": "2833230807310.000000000000000000", + "description": { + "moniker": "pylonvalidator", + "identity": "0979483D4F669CFF", + "website": "https://pylonvalidator.com", + "security_contact": "security@pylonvalidator.com", + "details": "'It doesn't matter whether the cat is black or white, as long as it catches mice.' --Deng Xiaoping" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1m9y0c7j7wxyu3nqtmeevyfzzpga8jhdyqw42wx", + "consensus_pubkey": "kavavalconspub1zcjduepqqpq85gztxdvheh48pugwp624mm6ey6u3464pj80c6s2epa8m9uwq4xr44m", + "jailed": false, + "status": 2, + "tokens": "1255000300000", + "delegator_shares": "1255000300000.000000000000000000", + "description": { + "moniker": "B-Harvest", + "identity": "8957C5091FBF4192", + "website": "https://bharvest.io", + "security_contact": "contact@bharvest.io", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-20T04:34:50.0221158Z" + }, + "min_self_delegation": "1000" + }, + { + "operator_address": "kavavaloper1mu78xhlr705mzgwqykcafp4xy3kgatvwzrww8z", + "consensus_pubkey": "kavavalconspub1zcjduepqhux83t9q55l0em60vq5a0p22zpf6kcqk3qs7cyzcc5huhycp6qnsutwsz3", + "jailed": false, + "status": 2, + "tokens": "21000000000", + "delegator_shares": "21000000000.000000000000000000", + "description": { + "moniker": "joesatri", + "identity": "649DD29EE41766EB", + "website": "", + "security_contact": "", + "details": "Game of Stakes Never Been Jailed Crew | Kava Founder Badge" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.110000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T15:01:47.310662882Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1uvz0vus7ktxt47cermscwe3k9gs7h9ag05sh6g", + "consensus_pubkey": "kavavalconspub1zcjduepq06xpflh9qkvgax8avl4wen49z48svsv4vplxk2jp2p4qx2htckzsfe2mwq", + "jailed": false, + "status": 2, + "tokens": "32995000000", + "delegator_shares": "32995000000.000000000000000000", + "description": { + "moniker": "Genesis Lab", + "identity": "C1A123F2723041F0", + "website": "https://genesislab.net", + "security_contact": "", + "details": "Genesis Lab is a blockchain-focused development company and validation nodes operator in PoS networks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:15:12.174174763Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1udg4pal8c9gffv4l7zhvza027z0y345gd6esa6", + "consensus_pubkey": "kavavalconspub1zcjduepqpdjehvuwljjjp5se8t9xselu0hlneh2np3vrxwd0f4v6csdahclqktmkdp", + "jailed": false, + "status": 2, + "tokens": "1739934640784", + "delegator_shares": "1739934640784.000000000000000000", + "description": { + "moniker": "ATEAM", + "identity": "0CB9A4E7643FF992", + "website": "", + "security_contact": "", + "details": "Kava_Founding member | Cosmos_GOS: Never Jailed \u0026 Top-Tier | Terra_Validator Drill: Top 3 | IOV_Validator candidates score for mainnet: Top 5 | Lino_Founding Validator Prize Winners: Top 7 | IRISnet_Nyancat: Perfect score" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-19T01:30:06.727558554Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1u0kfndes0pf8dstaunsgumv7scsnmy09p3ln9r", + "consensus_pubkey": "kavavalconspub1zcjduepqxzxd363ej2v0kljvfvy5ff4dka90gnkkfemej9p6rkqv3zac9qhsy8p567", + "jailed": false, + "status": 2, + "tokens": "4800705821800", + "delegator_shares": "4800705821800.000000000000000000", + "description": { + "moniker": "SNZPool", + "identity": "FF2019D4CF1F3185", + "website": "https://snzholding.com", + "security_contact": "", + "details": "SNZ Pool is a professional \u0026 reliable POS validator for a dozen of projects like Cosmos, IRISnet, EOS, ONT, Loom, etc." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-15T14:18:22.510513847Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1u3jf6c2f85kmjldxsncnhsdp44nac7v5j7vzpc", + "consensus_pubkey": "kavavalconspub1zcjduepqvd3xz6346n447pvl3s3s73ee3zwwn54f4ejwjfue3ppvpjgdfxwqu95mqu", + "jailed": false, + "status": 2, + "tokens": "3314184935364", + "delegator_shares": "3314184935364.000000000000000000", + "description": { + "moniker": "HuobiPool", + "identity": "23536C5BDE3EB949", + "website": "https://www.huobipool.com/", + "security_contact": "", + "details": "Huobi Pool is a sub-brand of Huobi Group, which is an important part of the global ecological strategy of Huobi.Huobi Pool has become one of the largest POS communities in the Asia- Pacific region, the leading POW pool and nodes of a number of public chains." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-12T15:50:40.940881395Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1u3hqe2m7vm59l30tyaqd3zurz864dlsg7nq83f", + "consensus_pubkey": "kavavalconspub1zcjduepqrtnnezp4g67f7hh8fs7gtx23pmdfjwu37uqguq4hsrglqkfmyensl4xvdt", + "jailed": false, + "status": 2, + "tokens": "4039881397431", + "delegator_shares": "4040285425961.491814603996529363", + "description": { + "moniker": "Delchain", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "388052", + "unbonding_time": "2020-01-06T09:05:10.544078799Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1uu9zguynwjyyyq57jnm3j2q47d5c362wafgsmf", + "consensus_pubkey": "kavavalconspub1zcjduepqn5uazvr3ew6ktstgshs9pfmh3vh9f9m36e76era3hxffxk8pr5asux5v9a", + "jailed": false, + "status": 2, + "tokens": "1000000", + "delegator_shares": "1000000.000000000000000000", + "description": { + "moniker": "sentry_lab", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-13T08:30:36.49152285Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1u7vsaanwt4e5mdzmxuqurmccxjka3h0ns2n3f5", + "consensus_pubkey": "kavavalconspub1zcjduepq7uy7ln7afmgrfutfpzhyy0llcndntx9q55nl5puqxcq5dqdzrnqswahrha", + "jailed": false, + "status": 2, + "tokens": "1000009950010", + "delegator_shares": "1000009950010.000000000000000000", + "description": { + "moniker": "BiKi Pool", + "identity": "", + "website": "https://www.biki.com", + "security_contact": "", + "details": "Popular Token's Choice" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-04T12:26:32.258743177Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1atelyappg8x4ndgtj6h2jng532a5hvuke2cajr", + "consensus_pubkey": "kavavalconspub1zcjduepqrwah2t8gezgv79stgnzju9ank4rpe85juf6xf4zzfhwgfawc5jpse287y0", + "jailed": false, + "status": 2, + "tokens": "567000000", + "delegator_shares": "567000000.000000000000000000", + "description": { + "moniker": "Nosce", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.007000000000000000", + "max_rate": "0.007700000000000000", + "max_change_rate": "0.000100000000000000" + }, + "update_time": "2020-02-19T04:09:38.903736876Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1aj9r9ll8m72xr5pmxr9fmum88k864tqg39nkfu", + "consensus_pubkey": "kavavalconspub1zcjduepq9nq9gdnvtl5as9sgl92exde7hju797hl20c9htje2chgwnlkwluq8hmtu0", + "jailed": false, + "status": 2, + "tokens": "21000000000", + "delegator_shares": "21000000000.000000000000000000", + "description": { + "moniker": "kytzu", + "identity": "909A480D5643CCC5", + "website": "https://www.linkedin.com/in/calinchitu", + "security_contact": "", + "details": "Blockchain consultant and developer" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.190000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T16:04:53.477387115Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "kavavaloper1ajwfalplxnhkwhsycfax36yyyxpxz3450s800x", + "consensus_pubkey": "kavavalconspub1zcjduepq33ekkklqez4tdd37mrvptrkawejnj0p5caa0a6c7efqs8n7eg37qa2vega", + "jailed": false, + "status": 2, + "tokens": "42770134655", + "delegator_shares": "42770134655.000000000000000000", + "description": { + "moniker": "Ryabina.io - Staking provider in awesome networks", + "identity": "6B1C8FDD84CF4ACD", + "website": "https://ryabina.io", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-02-24T18:08:47.865265697Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper17wcggpjx007uc09s8y4hwrj8f228mlwez945ey", + "consensus_pubkey": "kavavalconspub1zcjduepq5jtcd7kxpft40l65gm5p2ecg8rcxp59nml424u88lxkpxu6yl9cq6hxvzd", + "jailed": false, + "status": 2, + "tokens": "23092086042", + "delegator_shares": "23092086042.000000000000000000", + "description": { + "moniker": "Inotel", + "identity": "975D494265B1AC25", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:04:03.245058425Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper17498ffqdj49zca4jm7mdf3eevq7uhcsgjvm0uk", + "consensus_pubkey": "kavavalconspub1zcjduepq0mk39ccslman3ame4s3dn5exml8upqearp089sa5tae6pchdyrcsmvwmhn", + "jailed": false, + "status": 2, + "tokens": "23699000000", + "delegator_shares": "23699000000.000000000000000000", + "description": { + "moniker": "kaval", + "identity": "5281C9C7BE5C2646", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.550000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-07T10:24:27.851934685Z" + }, + "min_self_delegation": "1" + } + ]} + `); + } + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; + diff --git a/mock/ext-api-dyson/get/kava-api-commands4.js b/mock/ext-api-dyson/get/kava-api-commands4.js new file mode 100644 index 000000000..34c0e641a --- /dev/null +++ b/mock/ext-api-dyson/get/kava-api-commands4.js @@ -0,0 +1,32 @@ +/// Kava API Mock +/// See: +/// curl "http://localhost:3000/kava-api/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/delegations" +/// curl "https://{kava_rpc}/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/delegations" +/// curl "http://localhost:8420/v2/kava/staking/delegations/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m?Authorization=Bearer" + +module.exports = { + path: "/kava-api/:command1/:command2/:arg3/:arg4?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch(params.command1) { + case 'staking': + switch(params.command2) { + case 'delegators': + switch (params.arg3) { + case 'kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m': + switch (params.arg4) { + case 'delegations': + case 'unbonding_delegations': + return {height: "1793219", result: []}; + } + } + } + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; + diff --git a/mock/ext-api-dyson/get/tron-get-accounts.js b/mock/ext-api-dyson/get/tron-api-v1-accounts.js similarity index 57% rename from mock/ext-api-dyson/get/tron-get-accounts.js rename to mock/ext-api-dyson/get/tron-api-v1-accounts.js index 6710c8fa2..f2e76ab46 100644 --- a/mock/ext-api-dyson/get/tron-get-accounts.js +++ b/mock/ext-api-dyson/get/tron-api-v1-accounts.js @@ -1,8 +1,12 @@ /// Tron API Mock /// See: /// curl "http://localhost:3000/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?token_id=&limit=25&order_by=block_timestamp,desc" +/// curl "http://localhost:3000/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" /// curl "http://{Tron rpc}/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?token_id=&limit=25&order_by=block_timestamp,desc" -/// curl http://localhost:8420/v1/tron/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB +/// curl "http://{Tron rpc}/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" +/// curl "http://localhost:8420/v1/tron/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" +/// curl "http://localhost:8420/v2/tron/tokens/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB?Authorization=Bearer" + module.exports = { path: "/tron-api/v1/accounts/:address/:operation?", template: function(params, query, body) { @@ -94,6 +98,91 @@ module.exports = { `); } } + + if (typeof params.operation === 'undefined') { + if (params.address === 'TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB') { + return JSON.parse(` + { + "success": true, + "meta": { + "at": 1586264949424, + "page_size": 1 + }, + "data": [ + { + "account_resource": {}, + "active_permission": [ + { + "id": 2, + "keys": [ + { + "address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", + "weight": 1 + } + ], + "operations": "7fff1fc0033e0000000000000000000000000000000000000000000000000000", + "permission_name": "active", + "threshold": 1, + "type": "Active" + } + ], + "address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", + "allowance": 848829, + "assetV2": [ + { + "key": "1002000", + "value": 10183240058 + }, + { + "key": "1002798", + "value": 10000000 + }, + { + "key": "1002814", + "value": 10000000 + } + ], + "balance": 278720000, + "create_time": 1553864037000, + "free_asset_net_usageV2": [ + { + "key": "1002000", + "value": 0 + }, + { + "key": "1002798", + "value": 0 + }, + { + "key": "1002814", + "value": 0 + } + ], + "latest_consume_free_time": 1575142326000, + "latest_consume_time": 1576767612000, + "latest_opration_time": 1576767612000, + "owner_permission": { + "keys": [ + { + "address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", + "weight": 1 + } + ], + "permission_name": "owner", + "threshold": 1 + }, + "trc20": [ + { + "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7": "50356946" + } + ] + } + ] + } + `); + } + } + // fallback var return4Codacy = {error: "Not implemented"}; return return4Codacy; diff --git a/mock/ext-api-dyson/get/tron-api-v1-assets.js b/mock/ext-api-dyson/get/tron-api-v1-assets.js new file mode 100644 index 000000000..224e76006 --- /dev/null +++ b/mock/ext-api-dyson/get/tron-api-v1-assets.js @@ -0,0 +1,103 @@ +/// Tron API Mock +/// See: +/// curl "http://localhost:3000/tron-api/v1/assets/1002798" +/// curl "https://{tron_rpc}/v1/assets/1002798" +/// curl "http://localhost:8420/v2/tron/tokens/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB?Authorization=Bearer" + +module.exports = { + path: "/tron-api/v1/assets/:arg2?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + switch (params.arg2) { + case '1002000': + return JSON.parse(` + { + "success": true, + "meta": { + "at": 1586265512148, + "page_size": 1 + }, + "data": [ + { + "id": "1002000", + "abbr": "BTT", + "description": "Official Token of BitTorrent Protocol", + "name": "BitTorrent", + "num": 1, + "precision": 6, + "total_supply": "990000000000000000", + "trx_num": 1, + "url": "www.bittorrent.com", + "owner_address": "4137fa1a56eb8c503624701d776d95f6dae1d9f0d6", + "start_time": 1548000000000, + "end_time": 1548000001000 + } + ] + } + `); + + case '1002798': + return JSON.parse(` + { + "success": true, + "meta": { + "at": 1586265317378, + "page_size": 1 + }, + "data": [ + { + "id": "1002798", + "abbr": "EPICAL", + "description": "The token of the game Builder III", + "name": "EPICAL", + "num": 1000000000, + "precision": 6, + "total_supply": "10000000000000000", + "trx_num": 1000000000, + "url": "https://builder3.fun", + "vote_score": 0, + "owner_address": "41133b084f5225a9112f4e8527db26b381a32babd0", + "start_time": 1574966426578, + "end_time": 1574966486578 + } + ] + } + `); + + + + case '1002814': + return JSON.parse(` + { + "success": true, + "meta": { + "at": 1586265542289, + "page_size": 1 + }, + "data": [ + { + "id": "1002814", + "abbr": "AX", + "description": "The token of the game TrainX", + "name": "AX", + "num": 1000000000, + "precision": 6, + "total_supply": "10000000000000000", + "trx_num": 1000000000, + "url": "https://trainx.fun", + "vote_score": 0, + "owner_address": "418e267ead411aaaf671be100a7afe587d4eab0d71", + "start_time": 1576483805985, + "end_time": 1576483865985 + } + ] + } + `); + } + + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/get/tron-api-wallet.js b/mock/ext-api-dyson/get/tron-api-wallet.js new file mode 100644 index 000000000..2c8dc00cc --- /dev/null +++ b/mock/ext-api-dyson/get/tron-api-wallet.js @@ -0,0 +1,89 @@ +/// Tron API Mock +/// See: +/// curl http://localhost:3000/tron-api/wallet/listwitnesses +/// curl http://localhost:8420/v2/tron/staking/validators + +module.exports = { + path: "/tron-api/wallet/:operation?", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + if (params.operation === 'listwitnesses') { + return JSON.parse(` + { + "witnesses": [ + + { + "address": "4178c842ee63b253f8f0d2955bbc582c661a078c9d", + "voteCount": 13546358416, + "url": "https://www.binance.com/en/staking", + "totalProduced": 197868, + "totalMissed": 68, + "latestBlockNum": 18523838, + "latestSlotNum": 528611454, + "isJobs": true + }, + { + "address": "41d25855804e4e65de904faf3ac74b0bdfc53fac76", + "voteCount": 698985941, + "url": "https://www.bitguild.com", + "totalProduced": 594077, + "totalMissed": 2605, + "latestBlockNum": 18523841, + "latestSlotNum": 528611457, + "isJobs": true + }, + { + "address": "41d376d829440505ea13c9d1c455317d51b62e4ab6", + "voteCount": 317223159, + "url": "http://blockchain.org", + "totalProduced": 439090, + "totalMissed": 2650, + "latestBlockNum": 18523376, + "latestSlotNum": 528610983, + "isJobs": true + }, + { + "address": "4192c5d96c3b847268f4cb3e33b87ecfc67b5ce3de", + "voteCount": 331299971, + "url": "https://infstones.io/", + "totalProduced": 528971, + "totalMissed": 2232, + "latestBlockNum": 18523824, + "latestSlotNum": 528611440, + "isJobs": true + }, + { + "address": "417bdd2efb4401c50b6ad255e6428ba688e0b83f81", + "voteCount": 292566620, + "url": "https://minergate.com", + "totalProduced": 365859, + "totalMissed": 798, + "latestBlockNum": 18523360, + "latestSlotNum": 528610967, + "isJobs": true + }, + { + "address": "414d1ef8673f916debb7e2515a8f3ecaf2611034aa", + "voteCount": 392387821, + "url": "https://www.sesameseed.org", + "totalProduced": 667595, + "totalMissed": 5738, + "latestBlockNum": 18523844, + "latestSlotNum": 528611460, + "isJobs": true + }, + { + "address": "41de9c3c2276abe2da70a7cdb34a205ecf7750d063", + "voteCount": 4575746, + "url": "https://www.tron-family.de" + } + ] + } + `) + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/mock/ext-api-dyson/post/harmony-api.js b/mock/ext-api-dyson/post/harmony-api.js index 8186560d4..065918fa4 100644 --- a/mock/ext-api-dyson/post/harmony-api.js +++ b/mock/ext-api-dyson/post/harmony-api.js @@ -1,12 +1,12 @@ /// Harmony RPC Mock /// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":"hmy_getTransactionsHistory"} ' http://localhost:3000/harmony-api -/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":"hmy_getTransactionsHistory"} ' https://harmony-rpc.trustwalletapp.com +/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":"hmy_getTransactionsHistory"} ' https://{harmony_rpc} /// curl "http://localhost:8420/v2/harmony/one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv" module.exports = { path: '/harmony-api', template: function(params, query, body) { - //console.log("curl -H 'Content-Type: application/json' -d '", JSON.stringify(body), "' https://harmony-rpc.trustwalletapp.com"); + //console.log("curl -H 'Content-Type: application/json' -d '", JSON.stringify(body), "' https://{harmony_rpc}"); if (body.method === 'hmy_getTransactionsHistory') { //console.log('body.params[0].address', body.params[0].address); if (body.params[0].address === 'one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv') { diff --git a/mock/ext-api-dyson/post/nano-api.js b/mock/ext-api-dyson/post/nano-api.js index cc1b306cd..c161b417c 100644 --- a/mock/ext-api-dyson/post/nano-api.js +++ b/mock/ext-api-dyson/post/nano-api.js @@ -1,12 +1,12 @@ /// Nano RPC Mock /// curl -H 'Content-Type: application/json' -d ' {"action":"account_history","account":"nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z","count":"25"} ' http://localhost:3000/nano-api -/// curl -H 'Content-Type: application/json' -d ' {"action":"account_history","account":"nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z","count":"25"} ' https://nano-rpc.trustwalletapp.com +/// curl -H 'Content-Type: application/json' -d ' {"action":"account_history","account":"nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z","count":"25"} ' https://{nano_rpc} /// curl "http://localhost:8420/v1/nano/nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z" module.exports = { path: '/nano-api', template: function(params, query, body) { - //console.log("curl -H 'Content-Type: application/json' -d '", JSON.stringify(body), "' https://nano-rpc.trustwalletapp.com"); + //console.log("curl -H 'Content-Type: application/json' -d '", JSON.stringify(body), "' https://{nano_rpc}"); if (body.action === 'account_history') { //console.log('body.account', body.account); if (body.account === 'nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z') { diff --git a/mock/ext-api-dyson/post/nimiq-rpc.js b/mock/ext-api-dyson/post/nimiq-rpc.js index 6b630112a..c854f7e75 100644 --- a/mock/ext-api-dyson/post/nimiq-rpc.js +++ b/mock/ext-api-dyson/post/nimiq-rpc.js @@ -1,6 +1,6 @@ /// Nimiq RPC API Mock /// See: -/// curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "getTransactionsByAddress", "params": [ "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", "25" ], "id": "getTransactionsByAddress"}' https://nimiq-rpc.trustwalletapp.com +/// curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "getTransactionsByAddress", "params": [ "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", "25" ], "id": "getTransactionsByAddress"}' https://{nimiq_rpc} /// curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "getTransactionsByAddress", "params": [ "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", "25" ], "id": "getTransactionsByAddress"}' http://localhost:3000/nimiq-rpc /// curl "http://localhost:8420/v1/nimiq/NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07" diff --git a/mock/ext-api-dyson/post/tron-api-wallet.js b/mock/ext-api-dyson/post/tron-api-wallet.js new file mode 100644 index 000000000..08ffc3547 --- /dev/null +++ b/mock/ext-api-dyson/post/tron-api-wallet.js @@ -0,0 +1,18 @@ +/// Tron API Mock +/// See: +/// curl http://localhost:3000/tron-api/wallet/listwitnesses +/// curl http://localhost:8420/v2/tron/staking/validators + +module.exports = { + path: "/tron-api/wallet/:operation", + template: function(params, query, body) { + //console.log(params) + //console.log(query) + if (params.operation === 'getaccount') { + return {balance: 1, assetV2: [], votes: [], frozen: []} + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; From 89653a77567d676394f46478502835a97e269846 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Mon, 13 Apr 2020 20:27:38 +0300 Subject: [PATCH 252/506] Change /status route to / (#1032) --- api/endpoint/basic.go | 2 -- api/registry.go | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/api/endpoint/basic.go b/api/endpoint/basic.go index dbf68d6de..5d912be9c 100644 --- a/api/endpoint/basic.go +++ b/api/endpoint/basic.go @@ -7,8 +7,6 @@ import ( "net/http" ) -func GetRoot(c *gin.Context) { c.JSON(http.StatusOK, "Welcome to the Block Atlas API") } - func GetStatus(c *gin.Context) { c.JSON(http.StatusOK, map[string]interface{}{ "status": true, diff --git a/api/registry.go b/api/registry.go index d2b1bce77..9c3495214 100644 --- a/api/registry.go +++ b/api/registry.go @@ -110,8 +110,7 @@ func RegisterDomainAPI(root gin.IRouter) { } func RegisterBasicAPI(root gin.IRouter) { - root.GET("/", endpoint.GetRoot) - root.GET("/status", endpoint.GetStatus) + root.GET("/", endpoint.GetStatus) root.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) } From 8945d612f282e56c46d303670e9bb0f0bcc30b16 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Wed, 15 Apr 2020 09:03:00 +0800 Subject: [PATCH 253/506] Migrate from Trust Ray to blockbook (#992) * Use public rpc for eth, etc * Add blockbook models * Move dublcate logic to func * Blockbook client * Blockbook token normalization * Add Blockbook base * Blockbook transaction, draft * :art: add sub packages * Add generic EthereumClient interface * Fix collection tests * Fix txs and models * Fix go vet warning * Indicate ethereum api is trust-ray * cleanup get token list * Add ut and mock tests * Src.Tx.To can be empty * Add check of addresses len for From also * address review comments * normalize query address/token * Use public rpc for eth, etc * Add blockbook models * Move dublcate logic to func * Blockbook client * Blockbook token normalization * Add Blockbook base * Blockbook transaction, draft * :art: add sub packages * Add generic EthereumClient interface * Fix collection tests * Fix txs and models * Fix go vet warning * Indicate ethereum api is trust-ray * cleanup get token list * Add ut and mock tests * Src.Tx.To can be empty * Add check of addresses len for From also * address review comments * normalize query address/token * Small changes (renaming, remove unused) * remove not used variable * Remove address check to match token transfer in trust ray * handle pending txs * coding style fix * skip pending tx and other naming changes Co-authored-by: Mykola Co-authored-by: Nick Kozlov --- config.yml | 11 +- configmock.yml | 1 + .../get/eth-blockbook-api-transactions.js | 114 +++++++++++++ platform/ethereum/base.go | 41 +++-- platform/ethereum/block.go | 26 --- platform/ethereum/blockbook/block.go | 25 +++ platform/ethereum/blockbook/client.go | 55 +++++++ platform/ethereum/blockbook/model.go | 75 +++++++++ .../ethereum/blockbook/model_extension.go | 42 +++++ platform/ethereum/blockbook/token.go | 34 ++++ platform/ethereum/blockbook/token_test.go | 49 ++++++ platform/ethereum/blockbook/transaction.go | 154 ++++++++++++++++++ .../ethereum/blockbook/transaction_test.go | 138 ++++++++++++++++ platform/ethereum/client.go | 46 ++---- platform/ethereum/collection.go | 40 ++--- .../client.go} | 19 ++- platform/ethereum/{ => collection}/model.go | 54 +----- platform/ethereum/collectionV3.go | 17 +- platform/ethereum/collection_test.go | 5 +- platform/ethereum/domain.go | 3 +- platform/ethereum/{ => ens}/ens_client.go | 2 +- platform/ethereum/{ => ens}/ens_encoder.go | 2 +- .../ethereum/{ => ens}/ens_encoder_test.go | 2 +- platform/ethereum/{ => ens}/namehash.go | 2 +- platform/ethereum/{ => ens}/namehash_test.go | 2 +- platform/ethereum/transaction.go | 109 +------------ platform/ethereum/trustray/block.go | 23 +++ platform/ethereum/trustray/client.go | 46 ++++++ platform/ethereum/trustray/model.go | 55 +++++++ platform/ethereum/{ => trustray}/token.go | 28 ++-- .../ethereum/{ => trustray}/token_test.go | 10 +- platform/ethereum/trustray/transaction.go | 125 ++++++++++++++ .../{ => trustray}/transaction_test.go | 5 +- platform/platform.go | 10 +- 34 files changed, 1066 insertions(+), 304 deletions(-) create mode 100644 mock/ext-api-dyson/get/eth-blockbook-api-transactions.js delete mode 100644 platform/ethereum/block.go create mode 100644 platform/ethereum/blockbook/block.go create mode 100644 platform/ethereum/blockbook/client.go create mode 100644 platform/ethereum/blockbook/model.go create mode 100644 platform/ethereum/blockbook/model_extension.go create mode 100644 platform/ethereum/blockbook/token.go create mode 100644 platform/ethereum/blockbook/token_test.go create mode 100644 platform/ethereum/blockbook/transaction.go create mode 100644 platform/ethereum/blockbook/transaction_test.go rename platform/ethereum/{collection_client.go => collection/client.go} (70%) rename platform/ethereum/{ => collection}/model.go (56%) rename platform/ethereum/{ => ens}/ens_client.go (99%) rename platform/ethereum/{ => ens}/ens_encoder.go (99%) rename platform/ethereum/{ => ens}/ens_encoder_test.go (99%) rename platform/ethereum/{ => ens}/namehash.go (99%) rename platform/ethereum/{ => ens}/namehash_test.go (99%) create mode 100644 platform/ethereum/trustray/block.go create mode 100644 platform/ethereum/trustray/client.go create mode 100644 platform/ethereum/trustray/model.go rename platform/ethereum/{ => trustray}/token.go (66%) rename platform/ethereum/{ => trustray}/token_test.go (96%) create mode 100644 platform/ethereum/trustray/transaction.go rename platform/ethereum/{ => trustray}/transaction_test.go (99%) diff --git a/config.yml b/config.yml index 426a9be52..5a591a312 100644 --- a/config.yml +++ b/config.yml @@ -66,12 +66,13 @@ tezos: api: https://api.tzstats.com/explorer # https://tzstats.com/docs/api/index.html#introduction rpc: https://mainnet.tezos.org.ua -# [ETH] Ethereum: https://ethereum.org (Trust-Ray API) +# [ETH] Ethereum: https://ethereum.org # ethereum: -# api: https://localhost:4567 -# collections_api: https://api.opensea.io -# collections_api_key: [opensea_api_key] -# rpc: [ethereum rpc] +# api: https://localhost:4567 (Trust-Ray API) +# blockbook_api: [blockbook api] +# collections_api: https://api.opensea.io +# collections_api_key: [opensea_api_key] +# rpc: [ethereum rpc] # [ETC] Ethereum Classic: https://ethereumclassic.org (Trust-Ray API) # classic: diff --git a/configmock.yml b/configmock.yml index 032ad773e..16dcfd17e 100644 --- a/configmock.yml +++ b/configmock.yml @@ -64,6 +64,7 @@ tezos: # [ETH] Ethereum: https://ethereum.org (Trust-Ray API) ethereum: api: http://localhost:3000/eth-api + blockbook_api: http://localhost:3000/eth-blockbook-api collections_api: https://api.opensea.io collections_api_key: opensea_api_key rpc: http://localhost:3000/eth-rpc diff --git a/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js b/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js new file mode 100644 index 000000000..9d4d268e2 --- /dev/null +++ b/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js @@ -0,0 +1,114 @@ +/// Ethereum Blockbook API Mock +/// See: +/// curl "http://localhost:3000/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7&details=txs" +/// curl http://localhost:8420/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7 + +module.exports = { + path: '/eth-blockbook-api/v2/address/:address', + template: function(params, query, body) { + //console.log(query) + if (params.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { + return JSON.parse(`{ + "page": 1, + "totalPages": 11, + "itemsOnPage": 25, + "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "balance": "185659745674589722", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 259, + "nonTokenTxs": 240, + "transactions": [ + { + "txid": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", + "vin": [ + { + "n": 0, + "addresses": [ + "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "17635730000000000", + "n": 0, + "addresses": [ + "0x1717f94202c126ef71d6C562de253Fe95eEbDD5f" + ], + "isAddress": true + } + ], + "blockHash": "0x5b8b39099d025a8feeed7575ebff6d0b2508e0542d6279c1b3b4f8b893e74296", + "blockHeight": 9551915, + "confirmations": 231227, + "blockTime": 1582624428, + "value": "17635730000000000", + "fees": "90720000000000", + "ethereumSpecific": { + "status": 1, + "nonce": 227, + "gasLimit": 21000, + "gasUsed": 21000, + "gasPrice": "4320000000" + } + }, + { + "txid": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", + "vin": [ + { + "n": 0, + "addresses": [ + "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "addresses": [ + "0x0D8775F648430679A709E98d2b0Cb6250d2887EF" + ], + "isAddress": true + } + ], + "blockHash": "0x770332c9b4ea42e518f8c5a0178ca5732fd5edfe5e8e011e1362e6598de262d5", + "blockHeight": 9519169, + "confirmations": 263973, + "blockTime": 1582189159, + "value": "0", + "fees": "425822000000000", + "tokenTransfers": [ + { + "type": "ERC20", + "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", + "to": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "token": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "name": "Basic Attention Token", + "symbol": "BAT", + "decimals": 18, + "value": "400000000000000000" + } + ], + "ethereumSpecific": { + "status": 1, + "nonce": 16, + "gasLimit": 51839, + "gasUsed": 37028, + "gasPrice": "11500000000" + } + } + ], + "nonce": "228", + "tokens": [] + }`); + } + // fallback + var return4Codacy = {error: "Not implemented"}; + return return4Codacy; + } +}; diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index 47bd6d386..f26fa94cb 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -3,30 +3,43 @@ package ethereum import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/ethereum/blockbook" + "github.com/trustwallet/blockatlas/platform/ethereum/collection" + "github.com/trustwallet/blockatlas/platform/ethereum/ens" + "github.com/trustwallet/blockatlas/platform/ethereum/trustray" ) type Platform struct { - CoinIndex uint - RpcURL string - client Client - collectionsClient CollectionsClient - ens RpcClient + CoinIndex uint + RpcURL string + client EthereumClient + collectible collection.Client + ens ens.RpcClient } -func Init(coin uint, api, rpc string) *Platform { +func Init(coinType uint, api, rpc string) *Platform { return &Platform{ - CoinIndex: coin, + CoinIndex: coinType, RpcURL: rpc, - client: Client{blockatlas.InitClient(api)}, - ens: RpcClient{blockatlas.InitJSONClient(rpc)}, + ens: ens.RpcClient{Request: blockatlas.InitJSONClient(rpc)}, + client: &trustray.Client{Request: blockatlas.InitClient(api)}, } } -func InitWitCollection(coin uint, api, rpc, collectionApi, collectionKey string) *Platform { - p := Init(coin, api, rpc) - p.collectionsClient = CollectionsClient{blockatlas.InitClient(collectionApi)} - p.collectionsClient.Headers["X-API-KEY"] = collectionKey - return p +func InitWithBlockbook(coinType uint, blockbookApi, rpc string) *Platform { + return &Platform{ + CoinIndex: coinType, + RpcURL: rpc, + ens: ens.RpcClient{Request: blockatlas.InitJSONClient(rpc)}, + client: &blockbook.Client{Request: blockatlas.InitClient(blockbookApi)}, + } +} + +func InitWitCollection(coinType uint, api, rpc, blockbookApi, collectionApi, collectionKey string) *Platform { + platform := InitWithBlockbook(coinType, blockbookApi, rpc) + platform.collectible = collection.Client{Request: blockatlas.InitClient(collectionApi)} + platform.collectible.Headers["X-API-KEY"] = collectionKey + return platform } func (p *Platform) Coin() coin.Coin { diff --git a/platform/ethereum/block.go b/platform/ethereum/block.go deleted file mode 100644 index 6d6620b63..000000000 --- a/platform/ethereum/block.go +++ /dev/null @@ -1,26 +0,0 @@ -package ethereum - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "strconv" -) - -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.CurrentBlockNumber() -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - if srcPage, err := p.client.GetBlockByNumber(num); err == nil { - var txs []blockatlas.Tx - for _, srcTx := range srcPage { - txs = AppendTxs(txs, &srcTx, p.CoinIndex) - } - return &blockatlas.Block{ - Number: num, - ID: strconv.FormatInt(num, 10), - Txs: txs, - }, nil - } else { - return nil, err - } -} diff --git a/platform/ethereum/blockbook/block.go b/platform/ethereum/blockbook/block.go new file mode 100644 index 000000000..e630b9d8d --- /dev/null +++ b/platform/ethereum/blockbook/block.go @@ -0,0 +1,25 @@ +package blockbook + +import ( + "strconv" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (c *Client) GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, error) { + block, err := c.GetBlock(num) + if err != nil { + return nil, err + } + + txs := make([]blockatlas.Tx, 0, len(block.Transactions)) + for _, srcTx := range block.Transactions { + tx := normalizeTx(&srcTx, coinIndex) + txs = append(txs, tx) + } + return &blockatlas.Block{ + Number: num, + ID: strconv.FormatInt(num, 10), + Txs: txs, + }, nil +} diff --git a/platform/ethereum/blockbook/client.go b/platform/ethereum/blockbook/client.go new file mode 100644 index 000000000..2de84016e --- /dev/null +++ b/platform/ethereum/blockbook/client.go @@ -0,0 +1,55 @@ +package blockbook + +import ( + "fmt" + "net/url" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Client struct { + blockatlas.Request +} + +func (c *Client) GetTxs(address string) (*Page, error) { + return c.getTransactions(address, "") +} + +func (c *Client) GetTxsWithContract(address, contract string) (*Page, error) { + return c.getTransactions(address, contract) +} + +func (c *Client) GetTokens(address string) ([]Token, error) { + return c.getTokens(address) +} + +func (c *Client) GetCurrentBlockNumber() (int64, error) { + var nodeInfo NodeInfo + err := c.Get(&nodeInfo, "", nil) + if err != nil { + return 0, err + } + return nodeInfo.Blockbook.BestHeight, nil +} + +func (c *Client) GetBlock(num int64) (block Block, err error) { + path := fmt.Sprintf("v2/block/%d", num) + err = c.Get(&block, path, nil) + return +} + +func (c *Client) getTransactions(address, contract string) (page *Page, err error) { + path := fmt.Sprintf("v2/address/%s", address) + query := url.Values{"page": {"1"}, "pageSize": {"25"}, "details": {"txs"}, "contract": {contract}} + err = c.Get(&page, path, query) + return +} + +func (c *Client) getTokens(address string) ([]Token, error) { + var res Page + path := fmt.Sprintf("v2/address/%s", address) + query := url.Values{"details": {"tokens"}} + err := c.Get(&res, path, query) + + return res.Tokens, err +} diff --git a/platform/ethereum/blockbook/model.go b/platform/ethereum/blockbook/model.go new file mode 100644 index 000000000..338dcecd0 --- /dev/null +++ b/platform/ethereum/blockbook/model.go @@ -0,0 +1,75 @@ +package blockbook + +import ( + "math/big" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Page struct { + Transactions []Transaction `json:"transactions,omitempty"` + Tokens []Token `json:"tokens,omitempty"` +} + +type NodeInfo struct { + Blockbook *Blockbook `json:"blockbook"` + Backend *Backend `json:"backend"` +} + +type Blockbook struct { + BestHeight int64 `json:"bestHeight"` +} + +type Backend struct { + Blocks int64 `json:"blocks"` +} + +type Block struct { + Transactions []Transaction `json:"txs"` +} + +type Transaction struct { + TxID string `json:"txid"` + Vin []Output `json:"vin"` + Vout []Output `json:"vout"` + BlockHeight int64 `json:"blockHeight"` + BlockTime int64 `json:"blockTime"` + Value string `json:"value"` + Fees string `json:"fees"` + TokenTransfers []TokenTransfer `json:"tokenTransfers,omitempty"` + EthereumSpecific *EthereumSpecific `json:"ethereumSpecific,omitempty"` +} + +type Output struct { + Value string `json:"value,omitempty"` + Addresses []string `json:"addresses"` +} + +type TokenTransfer struct { + Decimals uint `json:"decimals"` + From string `json:"from"` + Name string `json:"name"` + Symbol string `json:"symbol"` + To string `json:"to"` + Token string `json:"token"` + Type string `json:"type"` + Value string `json:"value"` +} + +// Token contains info about tokens held by an address +type Token struct { + Contract string `json:"contract"` + Decimals uint `json:"decimals"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Type blockatlas.TokenType `json:"type"` +} + +// EthereumSpecific contains ethereum specific transaction data +type EthereumSpecific struct { + Status int `json:"status"` // -1 pending, 0 Fail, 1 OK + Nonce uint64 `json:"nonce"` + GasLimit *big.Int `json:"gasLimit"` + GasUsed *big.Int `json:"gasUsed"` + GasPrice string `json:"gasPrice"` +} diff --git a/platform/ethereum/blockbook/model_extension.go b/platform/ethereum/blockbook/model_extension.go new file mode 100644 index 000000000..611b2905f --- /dev/null +++ b/platform/ethereum/blockbook/model_extension.go @@ -0,0 +1,42 @@ +package blockbook + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (s *EthereumSpecific) GetStatus() (blockatlas.Status, string) { + switch s.Status { + case -1: + return blockatlas.StatusPending, "" + case 0: + return blockatlas.StatusError, "Error" + case 1: + return blockatlas.StatusCompleted, "" + default: + return blockatlas.StatusError, "Unable to define transaction status" + } +} + +func (t *Transaction) FromAddress() string { + if len(t.Vin) > 0 && len(t.Vin[0].Addresses) > 0 { + return t.Vin[0].Addresses[0] + } + return "" +} + +func (t *Transaction) ToAddress() string { + if len(t.Vout) > 0 && len(t.Vout[0].Addresses) > 0 { + return t.Vout[0].Addresses[0] + } + return "" +} + +func GetDirection(address, from, to string) blockatlas.Direction { + if address == from && address == to { + return blockatlas.DirectionSelf + } + if address == from { + return blockatlas.DirectionOutgoing + } + return blockatlas.DirectionIncoming +} diff --git a/platform/ethereum/blockbook/token.go b/platform/ethereum/blockbook/token.go new file mode 100644 index 000000000..9360092b3 --- /dev/null +++ b/platform/ethereum/blockbook/token.go @@ -0,0 +1,34 @@ +package blockbook + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/ethereum/trustray" +) + +func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) { + tokens, err := c.GetTokens(address) + if err != nil { + return nil, err + } + return NormalizeTokens(tokens, coinIndex), nil +} + +func NormalizeTokens(srcTokens []Token, coinIndex uint) []blockatlas.Token { + tokenPage := make([]blockatlas.Token, 0, len(srcTokens)) + for _, srcToken := range srcTokens { + token := NormalizeToken(&srcToken, coinIndex) + tokenPage = append(tokenPage, token) + } + return tokenPage +} + +func NormalizeToken(srcToken *Token, coinIndex uint) blockatlas.Token { + return blockatlas.Token{ + Name: srcToken.Name, + Symbol: srcToken.Symbol, + TokenID: srcToken.Contract, + Coin: coinIndex, + Decimals: srcToken.Decimals, + Type: trustray.GetTokenTypeByIndex(coinIndex), + } +} diff --git a/platform/ethereum/blockbook/token_test.go b/platform/ethereum/blockbook/token_test.go new file mode 100644 index 000000000..8c1982a1e --- /dev/null +++ b/platform/ethereum/blockbook/token_test.go @@ -0,0 +1,49 @@ +package blockbook + +import ( + "reflect" + "testing" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func TestNormalizeToken(t *testing.T) { + type args struct { + srcToken *Token + coinIndex uint + } + tests := []struct { + name string + args args + want blockatlas.Token + }{ + { + name: "Test Normalize Token", + args: args{ + srcToken: &Token{ + Type: "ERC20", + Name: "USD//C", + Contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + Symbol: "USDC", + Decimals: 6, + }, + coinIndex: 60, + }, + want: blockatlas.Token{ + Name: "USD//C", + Symbol: "USDC", + Decimals: 6, + TokenID: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + Type: "ERC20", + Coin: 60, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := NormalizeToken(tt.args.srcToken, tt.args.coinIndex); !reflect.DeepEqual(got, tt.want) { + t.Errorf("NormalizeToken() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/platform/ethereum/blockbook/transaction.go b/platform/ethereum/blockbook/transaction.go new file mode 100644 index 000000000..47d19265b --- /dev/null +++ b/platform/ethereum/blockbook/transaction.go @@ -0,0 +1,154 @@ +package blockbook + +import ( + "github.com/trustwallet/blockatlas/coin" + Address "github.com/trustwallet/blockatlas/pkg/address" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (c *Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) { + page, err := c.GetTxs(address) + if err != nil { + return nil, err + } + return NormalizePage(page, address, "", coinIndex), nil +} + +func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas.TxPage, error) { + page, err := c.GetTxsWithContract(address, token) + if err != nil { + return nil, err + } + return NormalizePage(page, address, token, coinIndex), nil +} + +func NormalizePage(srcPage *Page, address, token string, coinIndex uint) blockatlas.TxPage { + var txs []blockatlas.Tx + normalizedAddr := Address.EIP55Checksum(address) + var normalizedToken string + if token != "" { + normalizedToken = Address.EIP55Checksum(token) + } + for _, srcTx := range srcPage.Transactions { + if srcTx.BlockHeight < 0 { + continue // Skip pending tx + } + tx := normalizeTxWithAddress(&srcTx, normalizedAddr, normalizedToken, coinIndex) + txs = append(txs, tx) + } + return txs +} + +func normalizeTx(srcTx *Transaction, coinIndex uint) blockatlas.Tx { + status, errReason := srcTx.EthereumSpecific.GetStatus() + normalized := blockatlas.Tx{ + ID: srcTx.TxID, + Coin: coinIndex, + From: srcTx.FromAddress(), + To: srcTx.ToAddress(), + Fee: blockatlas.Amount(srcTx.Fees), + Date: srcTx.BlockTime, + Block: normalizeBlockHeight(srcTx.BlockHeight), + Status: status, + Error: errReason, + Sequence: srcTx.EthereumSpecific.Nonce, + } + fillMeta(&normalized, srcTx, coinIndex) + return normalized +} + +func normalizeTxWithAddress(srcTx *Transaction, address, token string, coinIndex uint) blockatlas.Tx { + normalized := normalizeTx(srcTx, coinIndex) + normalized.Direction = GetDirection(address, normalized.From, normalized.To) + fillMetaWithAddress(&normalized, srcTx, address, token, coinIndex) + return normalized +} + +func normalizeBlockHeight(height int64) uint64 { + if height < 0 { + return uint64(0) + } + return uint64(height) +} + +func fillMeta(final *blockatlas.Tx, tx *Transaction, coinIndex uint) { + if ok := fillTokenTransfer(final, tx, coinIndex); !ok { + fillTransferOrContract(final, tx, coinIndex) + } +} + +func fillMetaWithAddress(final *blockatlas.Tx, tx *Transaction, address, token string, coinIndex uint) { + if ok := fillTokenTransferWithAddress(final, tx, address, token, coinIndex); !ok { + fillTransferOrContract(final, tx, coinIndex) + } +} + +func fillTokenTransfer(final *blockatlas.Tx, tx *Transaction, coinIndex uint) bool { + if len(tx.TokenTransfers) == 1 { + transfer := tx.TokenTransfers[0] + final.Meta = blockatlas.TokenTransfer{ + Name: transfer.Name, + Symbol: transfer.Symbol, + TokenID: transfer.Token, + Decimals: transfer.Decimals, + Value: blockatlas.Amount(transfer.Value), + From: transfer.From, + To: transfer.To, + } + return true + } + return false +} + +func fillTokenTransferWithAddress(final *blockatlas.Tx, tx *Transaction, address, token string, coinIndex uint) bool { + if len(tx.TokenTransfers) > 0 { + for _, transfer := range tx.TokenTransfers { + if transfer.To == address || transfer.From == address { + // filter token if specified + if token != "" { + if token != transfer.Token { + continue + } + } + direction := GetDirection(address, transfer.From, transfer.To) + metadata := blockatlas.TokenTransfer{ + Name: transfer.Name, + Symbol: transfer.Symbol, + TokenID: transfer.Token, + Decimals: transfer.Decimals, + Value: blockatlas.Amount(transfer.Value), + } + if direction == blockatlas.DirectionSelf { + metadata.From = address + metadata.To = address + } else if direction == blockatlas.DirectionOutgoing { + metadata.From = address + metadata.To = transfer.To + } else { + metadata.From = transfer.From + metadata.To = address + } + final.Direction = direction + final.Meta = metadata + return true + } + } + } + return false +} + +func fillTransferOrContract(final *blockatlas.Tx, tx *Transaction, coinIndex uint) { + gasUsed := tx.EthereumSpecific.GasUsed + if gasUsed != nil && gasUsed.Int64() == 21000 { + final.Meta = blockatlas.Transfer{ + Value: blockatlas.Amount(tx.Value), + Symbol: coin.Coins[coinIndex].Symbol, + Decimals: coin.Coins[coinIndex].Decimals, + } + return + } + final.Meta = blockatlas.ContractCall{ + Input: "0x", // FIXME blockbook api doesn't return tx data field + Value: tx.Value, + } +} diff --git a/platform/ethereum/blockbook/transaction_test.go b/platform/ethereum/blockbook/transaction_test.go new file mode 100644 index 000000000..147ef00a0 --- /dev/null +++ b/platform/ethereum/blockbook/transaction_test.go @@ -0,0 +1,138 @@ +package blockbook + +import ( + "encoding/json" + "testing" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func TestNormalizePage(t *testing.T) { + type args struct { + srcPage string + address string + token string + coinIndex uint + } + tests := []struct { + name string + args args + want string + }{ + { + name: "Test normalize blockbook txs", + args: args{ + srcPage: `{ + "transactions": [ + { + "txid": "0xb1a32935f9b015bcfdda1b2e3d281b3780d1a6f7a2d4406e05ec2b826b2349cb", + "vin": [ + { + "n": 0, + "addresses": [ + "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "addresses": [ + "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849" + ], + "isAddress": true + } + ], + "blockHash": "0x90d6b2e0fb0f983a15738206c8e9951db53624f5e9b29628fd8b71c5400430cb", + "blockHeight": 8958320, + "confirmations": 825021, + "blockTime": 1574107019, + "value": "0", + "fees": "227056700000000", + "tokenTransfers": [ + { + "type": "ERC20", + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849", + "token": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "name": "Dai Stablecoin v1.0", + "symbol": "DAI", + "decimals": 18, + "value": "2255656573089233195" + }, + { + "type": "ERC20", + "from": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849", + "to": "0xad37fd42185Ba63009177058208dd1be4b136e6b", + "token": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "name": "Dai Stablecoin v1.0", + "symbol": "DAI", + "decimals": 18, + "value": "2255656573089233195" + }, + { + "type": "ERC20", + "from": "0x0000000000000000000000000000000000000000", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "token": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "name": "Dai Stablecoin", + "symbol": "DAI", + "decimals": 18, + "value": "2255656573089233195" + } + ], + "ethereumSpecific": { + "status": 1, + "nonce": 378, + "gasLimit": 3703313, + "gasUsed": 174659, + "gasPrice": "1300000000" + } + } + ]}`, + address: "0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1", + token: "0x6b175474e89094c44da98b954eedeac495271d0f", + coinIndex: 60, + }, + want: `[{ + "id": "0xb1a32935f9b015bcfdda1b2e3d281b3780d1a6f7a2d4406e05ec2b826b2349cb", + "coin": 60, + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849", + "fee": "227056700000000", + "date": 1574107019, + "block": 8958320, + "status": "completed", + "sequence": 378, + "type": "token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "Dai Stablecoin", + "symbol": "DAI", + "token_id": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "decimals": 18, + "value": "2255656573089233195", + "from": "0x0000000000000000000000000000000000000000", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + } + }]`, + }, + } + for _, tt := range tests { + var page Page + var txPage blockatlas.TxPage + _ = json.Unmarshal([]byte(tt.args.srcPage), &page) + _ = json.Unmarshal([]byte(tt.want), &txPage) + t.Run(tt.name, func(t *testing.T) { + got := NormalizePage(&page, tt.args.address, tt.args.token, tt.args.coinIndex) + gotJson, _ := json.Marshal(got) + gotTxPage, _ := json.Marshal(txPage) + if string(gotJson) != string(gotTxPage) { + t.Errorf("NormalizePage() = %v, want %v", string(gotJson), string(gotTxPage)) + } + }) + } +} diff --git a/platform/ethereum/client.go b/platform/ethereum/client.go index 7393c990a..c095eb793 100644 --- a/platform/ethereum/client.go +++ b/platform/ethereum/client.go @@ -1,47 +1,25 @@ package ethereum import ( - "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "net/url" ) -type Client struct { - blockatlas.Request +type EthereumClient interface { + GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) + GetTokenTxs(address, token string, coinIndex uint) (blockatlas.TxPage, error) + GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) + GetCurrentBlockNumber() (int64, error) + GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, error) } -func (c *Client) GetTxs(address string) (*Page, error) { - return c.getTxs(url.Values{"address": {address}}) +func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { + return p.client.GetTokenList(address, p.CoinIndex) } -func (c *Client) GetTxsWithContract(address, contract string) (*Page, error) { - return c.getTxs(url.Values{"address": {address}, "contract": {contract}}) +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.GetCurrentBlockNumber() } -func (c *Client) getTxs(query url.Values) (page *Page, err error) { - err = c.Get(&page, "transactions", query) - return -} - -func (c *Client) GetBlockByNumber(num int64) (page []Doc, err error) { - path := fmt.Sprintf("transactions/block/%d", num) - err = c.Get(&page, path, nil) - return -} - -func (c *Client) CurrentBlockNumber() (int64, error) { - var nodeInfo NodeInfo - err := c.Get(&nodeInfo, "node_info", nil) - if err != nil { - return 0, err - } - return nodeInfo.LatestBlock, nil -} - -func (c *Client) GetTokens(address string) (tp *TokenPage, err error) { - query := url.Values{ - "address": {address}, - } - err = c.Get(&tp, "tokens", query) - return +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + return p.client.GetBlockByNumber(num, p.CoinIndex) } diff --git a/platform/ethereum/collection.go b/platform/ethereum/collection.go index 7cb836c4f..2ef0bd1d6 100644 --- a/platform/ethereum/collection.go +++ b/platform/ethereum/collection.go @@ -1,8 +1,10 @@ package ethereum import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "strings" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/ethereum/collection" ) var ( @@ -10,7 +12,7 @@ var ( ) func (p *Platform) GetCollections(owner string) (blockatlas.CollectionPage, error) { - collections, err := p.collectionsClient.GetCollections(owner) + collections, err := p.collectible.GetCollections(owner) if err != nil { return nil, err } @@ -18,14 +20,14 @@ func (p *Platform) GetCollections(owner string) (blockatlas.CollectionPage, erro } func (p *Platform) GetCollectibles(owner, collectibleID string) (blockatlas.CollectiblePage, error) { - items, err := p.collectionsClient.GetCollectibles(owner, collectibleID) + items, err := p.collectible.GetCollectibles(owner, collectibleID) if err != nil { return nil, err } return NormalizeCollectiblePage(items, p.CoinIndex), nil } -func NormalizeCollections(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { +func NormalizeCollections(collections []collection.Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { for _, collection := range collections { item := NormalizeCollection(collection, coinIndex, owner) page = append(page, item) @@ -33,7 +35,7 @@ func NormalizeCollections(collections []Collection, coinIndex uint, owner string return page } -func NormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas.Collection { +func NormalizeCollection(c collection.Collection, coinIndex uint, owner string) blockatlas.Collection { return blockatlas.Collection{ Name: c.Name, ImageUrl: c.ImageUrl, @@ -46,7 +48,7 @@ func NormalizeCollection(c Collection, coinIndex uint, owner string) blockatlas. } } -func NormalizeCollectiblePage(collectibles []Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { +func NormalizeCollectiblePage(collectibles []collection.Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { for _, collectible := range collectibles { item := NormalizeCollectible(collectible, coinIndex) if _, ok := supportedTypes[item.Type]; ok { @@ -56,21 +58,21 @@ func NormalizeCollectiblePage(collectibles []Collectible, coinIndex uint) (page return page } -func NormalizeCollectible(a Collectible, coinIndex uint) blockatlas.Collectible { - id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") +func NormalizeCollectible(c collection.Collectible, coinIndex uint) blockatlas.Collectible { + id := strings.Join([]string{c.AssetContract.Address, c.TokenId}, "-") return blockatlas.Collectible{ ID: id, - CollectionID: a.Collection.Slug, - TokenID: a.TokenId, - ContractAddress: a.AssetContract.Address, - Name: a.Name, - Category: a.Collection.Name, - ImageUrl: a.ImagePreviewUrl, - ProviderLink: a.Permalink, - ExternalLink: a.Collection.ExternalLink, - Type: a.AssetContract.Type, - Description: a.Description, + CollectionID: c.Collection.Slug, + TokenID: c.TokenId, + ContractAddress: c.AssetContract.Address, + Name: c.Name, + Category: c.Collection.Name, + ImageUrl: c.ImagePreviewUrl, + ProviderLink: c.Permalink, + ExternalLink: c.Collection.ExternalLink, + Type: c.AssetContract.Type, + Description: c.Description, Coin: coinIndex, - Version: a.AssetContract.Version, + Version: c.AssetContract.Version, } } diff --git a/platform/ethereum/collection_client.go b/platform/ethereum/collection/client.go similarity index 70% rename from platform/ethereum/collection_client.go rename to platform/ethereum/collection/client.go index 5a049e708..3d82c6a2e 100644 --- a/platform/ethereum/collection_client.go +++ b/platform/ethereum/collection/client.go @@ -1,18 +1,19 @@ -package ethereum +package collection import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "net/url" "strconv" "strings" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" ) -type CollectionsClient struct { +type Client struct { blockatlas.Request } -func (c CollectionsClient) GetCollections(owner string) (page []Collection, err error) { +func (c Client) GetCollections(owner string) (page []Collection, err error) { query := url.Values{ "asset_owner": {owner}, "limit": {"1000"}, @@ -21,7 +22,7 @@ func (c CollectionsClient) GetCollections(owner string) (page []Collection, err return } -func (c CollectionsClient) GetCollectibles(owner string, collectibleID string) ([]Collectible, error) { +func (c Client) GetCollectibles(owner string, collectibleID string) ([]Collectible, error) { query := url.Values{ "owner": {owner}, "collection": {collectibleID}, @@ -33,12 +34,12 @@ func (c CollectionsClient) GetCollectibles(owner string, collectibleID string) ( return page.Collectibles, err } -func (c CollectionsClient) GetCollectiblesV3(owner string, collectibleID string) (*Collection, []Collectible, error) { +func (c Client) GetCollectiblesV3(owner string, collectibleID string) (*Collection, []Collectible, error) { collections, err := c.GetCollections(owner) if err != nil { return nil, nil, err } - collection := searchCollection(collections, collectibleID) + collection := SearchCollection(collections, collectibleID) if collection == nil { return nil, nil, errors.E("collectible not found", errors.TypePlatformClient, errors.Params{"collectibleID": collectibleID}) @@ -56,7 +57,7 @@ func (c CollectionsClient) GetCollectiblesV3(owner string, collectibleID string) return collection, page.Collectibles, err } -func searchCollection(collections []Collection, collectibleID string) *Collection { +func SearchCollection(collections []Collection, collectibleID string) *Collection { for _, i := range collections { if strings.EqualFold(i.Slug, collectibleID) { return &i diff --git a/platform/ethereum/model.go b/platform/ethereum/collection/model.go similarity index 56% rename from platform/ethereum/model.go rename to platform/ethereum/collection/model.go index a315ee0ac..706529544 100644 --- a/platform/ethereum/model.go +++ b/platform/ethereum/collection/model.go @@ -1,61 +1,9 @@ -package ethereum +package collection import ( "math/big" - - "github.com/trustwallet/blockatlas/pkg/blockatlas" ) -type Page struct { - Total uint `json:"total"` - Docs []Doc `json:"docs"` -} - -type TokenPage struct { - Total uint `json:"total"` - Docs []Contract `json:"docs"` -} - -type Doc struct { - Ops []Op `json:"operations"` - Contract string `json:"contract"` - ID string `json:"id"` - BlockNumber uint64 `json:"blockNumber"` - Timestamp int64 `json:"time"` - Nonce uint64 `json:"nonce"` - From string `json:"from"` - To string `json:"to"` - Value string `json:"value"` - Gas string `json:"gas"` - GasPrice string `json:"gasPrice"` - GasUsed string `json:"gasUsed"` - Input string `json:"input"` - Error string `json:"error"` - Coin uint `json:"coin"` -} - -type Op struct { - TxID string `json:"transactionId"` - Contract *Contract `json:"contract"` - From string `json:"from"` - To string `json:"to"` - Type blockatlas.TransactionType `json:"type"` - Value string `json:"value"` - Coin uint `json:"coin"` -} - -type Contract struct { - Address string `json:"address"` - Symbol string `json:"symbol"` - Decimals uint `json:"decimals"` - TotalSupply string `json:"totalSupply,omitempty"` - Name string `json:"name"` -} - -type NodeInfo struct { - LatestBlock int64 `json:"latest_block"` -} - type Collection struct { Name string `json:"name"` ImageUrl string `json:"image_url"` diff --git a/platform/ethereum/collectionV3.go b/platform/ethereum/collectionV3.go index dc35a5afe..a049d5cd9 100644 --- a/platform/ethereum/collectionV3.go +++ b/platform/ethereum/collectionV3.go @@ -2,11 +2,12 @@ package ethereum import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/ethereum/collection" "strings" ) func (p *Platform) GetCollectionsV3(owner string) (blockatlas.CollectionPageV3, error) { - collections, err := p.collectionsClient.GetCollections(owner) + collections, err := p.collectible.GetCollections(owner) if err != nil { return nil, err } @@ -15,7 +16,7 @@ func (p *Platform) GetCollectionsV3(owner string) (blockatlas.CollectionPageV3, } func (p *Platform) GetCollectiblesV3(owner, collectibleID string) (blockatlas.CollectiblePageV3, error) { - collection, items, err := p.collectionsClient.GetCollectiblesV3(owner, collectibleID) + collection, items, err := p.collectible.GetCollectiblesV3(owner, collectibleID) if err != nil { return nil, err } @@ -23,7 +24,7 @@ func (p *Platform) GetCollectiblesV3(owner, collectibleID string) (blockatlas.Co return page, nil } -func NormalizeCollectionPageV3(collections []Collection, coinIndex uint, owner string) (page blockatlas.CollectionPageV3) { +func NormalizeCollectionPageV3(collections []collection.Collection, coinIndex uint, owner string) (page blockatlas.CollectionPageV3) { for _, collection := range collections { if len(collection.Contracts) == 0 { continue @@ -37,7 +38,7 @@ func NormalizeCollectionPageV3(collections []Collection, coinIndex uint, owner s return } -func NormalizeCollectionV3(c Collection, coinIndex uint, owner string) blockatlas.CollectionV3 { +func NormalizeCollectionV3(c collection.Collection, coinIndex uint, owner string) blockatlas.CollectionV3 { normalizeSupportedContracts(&c) if len(c.Contracts) == 0 { return blockatlas.CollectionV3{} @@ -65,8 +66,8 @@ func NormalizeCollectionV3(c Collection, coinIndex uint, owner string) blockatla } } -func normalizeSupportedContracts(c *Collection) { - supportedContracts := make([]PrimaryAssetContract, 0) +func normalizeSupportedContracts(c *collection.Collection) { + supportedContracts := make([]collection.PrimaryAssetContract, 0) for _, contract := range c.Contracts { if _, ok := supportedTypes[contract.Type]; !ok { continue @@ -76,7 +77,7 @@ func normalizeSupportedContracts(c *Collection) { c.Contracts = supportedContracts } -func NormalizeCollectiblePageV3(c *Collection, srcPage []Collectible, coinIndex uint) (page blockatlas.CollectiblePageV3) { +func NormalizeCollectiblePageV3(c *collection.Collection, srcPage []collection.Collectible, coinIndex uint) (page blockatlas.CollectiblePageV3) { normalizeSupportedContracts(c) if len(c.Contracts) == 0 { return @@ -91,7 +92,7 @@ func NormalizeCollectiblePageV3(c *Collection, srcPage []Collectible, coinIndex return } -func NormalizeCollectibleV3(c *Collection, a Collectible, coinIndex uint) blockatlas.CollectibleV3 { +func NormalizeCollectibleV3(c *collection.Collection, a collection.Collectible, coinIndex uint) blockatlas.CollectibleV3 { address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") externalLink := blockatlas.GetValidParameter(a.ExternalLink, a.AssetContract.ExternalLink) diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/collection_test.go index 771baa5ac..661d3bc2e 100644 --- a/platform/ethereum/collection_test.go +++ b/platform/ethereum/collection_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/ethereum/collection" "testing" ) @@ -268,7 +269,7 @@ var collection3DstV4 = blockatlas.Collection{ } func TestNormalizeCollectionV4(t *testing.T) { - var collections []Collection + var collections []collection.Collection err := json.Unmarshal([]byte(collectionsSrcV4), &collections) assert.Nil(t, err) page := NormalizeCollections(collections, coin.ETH, collectionsOwnerV4) @@ -320,7 +321,7 @@ var collectibleDstV4 = blockatlas.Collectible{ } func TestNormalizeCollectibleV4(t *testing.T) { - var collectibles []Collectible + var collectibles []collection.Collectible err := json.Unmarshal([]byte(collectibleSrcV4), &collectibles) assert.Nil(t, err) page := NormalizeCollectiblePage(collectibles, coin.ETH) diff --git a/platform/ethereum/domain.go b/platform/ethereum/domain.go index 7d00f7f8d..c7ebeaedd 100644 --- a/platform/ethereum/domain.go +++ b/platform/ethereum/domain.go @@ -5,12 +5,13 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/platform/ethereum/ens" AddressEncoder "github.com/trustwallet/ens-coincodec" ) func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { var result []blockatlas.Resolved - node, err := NameHash(name) + node, err := ens.NameHash(name) if err != nil { return result, errors.E(err, "name hash failed") } diff --git a/platform/ethereum/ens_client.go b/platform/ethereum/ens/ens_client.go similarity index 99% rename from platform/ethereum/ens_client.go rename to platform/ethereum/ens/ens_client.go index 5229fac5a..3b50cf951 100644 --- a/platform/ethereum/ens_client.go +++ b/platform/ethereum/ens/ens_client.go @@ -1,4 +1,4 @@ -package ethereum +package ens import ( "encoding/hex" diff --git a/platform/ethereum/ens_encoder.go b/platform/ethereum/ens/ens_encoder.go similarity index 99% rename from platform/ethereum/ens_encoder.go rename to platform/ethereum/ens/ens_encoder.go index 79a18dd38..e3be9aa3f 100644 --- a/platform/ethereum/ens_encoder.go +++ b/platform/ethereum/ens/ens_encoder.go @@ -1,4 +1,4 @@ -package ethereum +package ens import ( "bytes" diff --git a/platform/ethereum/ens_encoder_test.go b/platform/ethereum/ens/ens_encoder_test.go similarity index 99% rename from platform/ethereum/ens_encoder_test.go rename to platform/ethereum/ens/ens_encoder_test.go index 3b8769458..0fade67dd 100644 --- a/platform/ethereum/ens_encoder_test.go +++ b/platform/ethereum/ens/ens_encoder_test.go @@ -1,4 +1,4 @@ -package ethereum +package ens import ( "encoding/hex" diff --git a/platform/ethereum/namehash.go b/platform/ethereum/ens/namehash.go similarity index 99% rename from platform/ethereum/namehash.go rename to platform/ethereum/ens/namehash.go index 963896147..ff6abc6cc 100644 --- a/platform/ethereum/namehash.go +++ b/platform/ethereum/ens/namehash.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ethereum +package ens import ( "strings" diff --git a/platform/ethereum/namehash_test.go b/platform/ethereum/ens/namehash_test.go similarity index 99% rename from platform/ethereum/namehash_test.go rename to platform/ethereum/ens/namehash_test.go index 4a2ce916a..8012c3a7e 100644 --- a/platform/ethereum/namehash_test.go +++ b/platform/ethereum/ens/namehash_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ethereum +package ens import ( "encoding/hex" diff --git a/platform/ethereum/transaction.go b/platform/ethereum/transaction.go index d2df6038e..1be749ca0 100644 --- a/platform/ethereum/transaction.go +++ b/platform/ethereum/transaction.go @@ -1,14 +1,12 @@ package ethereum import ( + "net/http" + "sort" + "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" - "math/big" - "net/http" - "sort" ) func (p *Platform) RegisterRoutes(router gin.IRouter) { @@ -20,118 +18,23 @@ func (p *Platform) RegisterRoutes(router gin.IRouter) { func (p *Platform) getTransactions(c *gin.Context) { token := c.Query("token") address := c.Param("address") - var srcPage *Page + var page blockatlas.TxPage var err error if token != "" { - srcPage, err = p.client.GetTxsWithContract(address, token) + page, err = p.client.GetTokenTxs(address, token, p.CoinIndex) } else { - srcPage, err = p.client.GetTxs(address) + page, err = p.client.GetTransactions(address, p.CoinIndex) } if apiError(c, err) { return } - var txs []blockatlas.Tx - for i, srcTx := range srcPage.Docs { - txs = AppendTxs(txs, &srcTx, p.CoinIndex) - txs[i].Direction = txs[i].GetTransactionDirection(address) - } - - page := blockatlas.TxPage(txs) sort.Sort(page) c.JSON(http.StatusOK, &page) } -func extractBase(srcTx *Doc, coinIndex uint) (base blockatlas.Tx, ok bool) { - var status blockatlas.Status - var errReason string - if srcTx.Error == "" { - status = blockatlas.StatusCompleted - } else { - status = blockatlas.StatusError - errReason = srcTx.Error - } - - fee := calcFee(srcTx.GasPrice, srcTx.GasUsed) - - base = blockatlas.Tx{ - ID: srcTx.ID, - Coin: coinIndex, - From: srcTx.From, - To: srcTx.To, - Fee: blockatlas.Amount(fee), - Date: srcTx.Timestamp, - Block: srcTx.BlockNumber, - Status: status, - Error: errReason, - Sequence: srcTx.Nonce, - } - return base, true -} - -func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas.Tx) { - out = in - baseTx, ok := extractBase(srcTx, coinIndex) - if !ok { - return - } - - // Native ETH transaction - if len(srcTx.Ops) == 0 && srcTx.Input == "0x" { - transferTx := baseTx - transferTx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(srcTx.Value), - Symbol: coin.Coins[coinIndex].Symbol, - Decimals: coin.Coins[coinIndex].Decimals, - } - out = append(out, transferTx) - } - - // Smart Contract Call - if len(srcTx.Ops) == 0 && srcTx.Input != "0x" { - contractTx := baseTx - contractTx.Meta = blockatlas.ContractCall{ - Input: srcTx.Input, - Value: srcTx.Value, - } - out = append(out, contractTx) - } - - if len(srcTx.Ops) == 0 { - return - } - op := &srcTx.Ops[0] - - if op.Type == blockatlas.TxTokenTransfer && op.Contract != nil { - tokenTx := baseTx - - tokenTx.Meta = blockatlas.TokenTransfer{ - Name: op.Contract.Name, - Symbol: op.Contract.Symbol, - TokenID: address.EIP55Checksum(op.Contract.Address), - Decimals: op.Contract.Decimals, - Value: blockatlas.Amount(op.Value), - From: op.From, - To: op.To, - } - out = append(out, tokenTx) - } - return -} - -func calcFee(gasPrice string, gasUsed string) string { - var gasPriceBig, gasUsedBig, feeBig big.Int - - gasPriceBig.SetString(gasPrice, 10) - gasUsedBig.SetString(gasUsed, 10) - - feeBig.Mul(&gasPriceBig, &gasUsedBig) - - return feeBig.String() -} - func apiError(c *gin.Context, err error) bool { if err != nil { logger.Error(err, "Unhandled error") diff --git a/platform/ethereum/trustray/block.go b/platform/ethereum/trustray/block.go new file mode 100644 index 000000000..208432ea7 --- /dev/null +++ b/platform/ethereum/trustray/block.go @@ -0,0 +1,23 @@ +package trustray + +import ( + "strconv" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (c *Client) GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, error) { + srcPage, err := c.GetBlock(num) + if err != nil { + return nil, err + } + var txs []blockatlas.Tx + for _, srcTx := range srcPage { + txs = AppendTxs(txs, &srcTx, coinIndex) + } + return &blockatlas.Block{ + Number: num, + ID: strconv.FormatInt(num, 10), + Txs: txs, + }, nil +} diff --git a/platform/ethereum/trustray/client.go b/platform/ethereum/trustray/client.go new file mode 100644 index 000000000..fa117deb5 --- /dev/null +++ b/platform/ethereum/trustray/client.go @@ -0,0 +1,46 @@ +package trustray + +import ( + "fmt" + "net/url" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Client struct { + blockatlas.Request +} + +func (c *Client) GetTxs(address string) (*Page, error) { + return c.getTxs(url.Values{"address": {address}}) +} + +func (c *Client) GetTxsWithContract(address, contract string) (*Page, error) { + return c.getTxs(url.Values{"address": {address}, "contract": {contract}}) +} + +func (c *Client) getTxs(query url.Values) (page *Page, err error) { + err = c.Get(&page, "transactions", query) + return +} + +func (c *Client) GetBlock(num int64) (page []Doc, err error) { + path := fmt.Sprintf("transactions/block/%d", num) + err = c.Get(&page, path, nil) + return +} + +func (c *Client) GetCurrentBlockNumber() (int64, error) { + var nodeInfo NodeInfo + err := c.Get(&nodeInfo, "node_info", nil) + if err != nil { + return 0, err + } + return nodeInfo.LatestBlock, nil +} + +func (c *Client) GetTokens(address string) (tp *TokenPage, err error) { + query := url.Values{"address": {address}} + err = c.Get(&tp, "tokens", query) + return +} diff --git a/platform/ethereum/trustray/model.go b/platform/ethereum/trustray/model.go new file mode 100644 index 000000000..3e97715cc --- /dev/null +++ b/platform/ethereum/trustray/model.go @@ -0,0 +1,55 @@ +package trustray + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Page struct { + Total uint `json:"total"` + Docs []Doc `json:"docs"` +} + +type TokenPage struct { + Total uint `json:"total"` + Docs []Contract `json:"docs"` +} + +type Doc struct { + Ops []Op `json:"operations"` + Contract string `json:"contract"` + ID string `json:"id"` + BlockNumber uint64 `json:"blockNumber"` + Timestamp int64 `json:"time"` + Nonce uint64 `json:"nonce"` + From string `json:"from"` + To string `json:"to"` + Value string `json:"value"` + Gas string `json:"gas"` + GasPrice string `json:"gasPrice"` + GasUsed string `json:"gasUsed"` + Input string `json:"input"` + Error string `json:"error"` + Coin uint `json:"coin"` +} + +type Op struct { + TxID string `json:"transactionId"` + Contract *Contract `json:"contract"` + From string `json:"from"` + To string `json:"to"` + Type blockatlas.TransactionType `json:"type"` + Value string `json:"value"` + Coin uint `json:"coin"` +} + +type Contract struct { + Address string `json:"address"` + Symbol string `json:"symbol"` + Decimals uint `json:"decimals"` + TotalSupply string `json:"totalSupply,omitempty"` + Name string `json:"name"` +} + +type NodeInfo struct { + LatestBlock int64 `json:"latest_block"` +} diff --git a/platform/ethereum/token.go b/platform/ethereum/trustray/token.go similarity index 66% rename from platform/ethereum/token.go rename to platform/ethereum/trustray/token.go index dbf88c192..fe68a920e 100644 --- a/platform/ethereum/token.go +++ b/platform/ethereum/trustray/token.go @@ -1,20 +1,19 @@ -package ethereum +package trustray import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) -func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { - account, err := p.client.GetTokens(address) +func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) { + account, err := c.GetTokens(address) if err != nil { return nil, err } - return NormalizeTokens(account.Docs, *p), nil + return NormalizeTokens(account.Docs, coinIndex), nil } -// NormalizeToken converts a Ethereum token into the generic model -func NormalizeToken(srcToken *Contract, coinIndex uint) (t blockatlas.Token, ok bool) { +func GetTokenTypeByIndex(coinIndex uint) blockatlas.TokenType { var tokenType blockatlas.TokenType switch coinIndex { case coin.Ethereum().ID: @@ -34,8 +33,14 @@ func NormalizeToken(srcToken *Contract, coinIndex uint) (t blockatlas.Token, ok default: tokenType = "unknown" } + return tokenType +} - t = blockatlas.Token{ +// NormalizeToken converts a Ethereum token into the generic model +func NormalizeToken(srcToken *Contract, coinIndex uint) blockatlas.Token { + tokenType := GetTokenTypeByIndex(coinIndex) + + return blockatlas.Token{ Name: srcToken.Name, Symbol: srcToken.Symbol, TokenID: srcToken.Address, @@ -43,18 +48,13 @@ func NormalizeToken(srcToken *Contract, coinIndex uint) (t blockatlas.Token, ok Decimals: srcToken.Decimals, Type: tokenType, } - - return t, true } // NormalizeTxs converts multiple Ethereum tokens -func NormalizeTokens(srcTokens []Contract, p Platform) []blockatlas.Token { +func NormalizeTokens(srcTokens []Contract, coinIndex uint) []blockatlas.Token { tokenPage := make([]blockatlas.Token, 0) for _, srcToken := range srcTokens { - token, ok := NormalizeToken(&srcToken, p.CoinIndex) - if !ok { - continue - } + token := NormalizeToken(&srcToken, coinIndex) tokenPage = append(tokenPage, token) } return tokenPage diff --git a/platform/ethereum/token_test.go b/platform/ethereum/trustray/token_test.go similarity index 96% rename from platform/ethereum/token_test.go rename to platform/ethereum/trustray/token_test.go index fa5470b22..c2d134175 100644 --- a/platform/ethereum/token_test.go +++ b/platform/ethereum/trustray/token_test.go @@ -1,11 +1,12 @@ -package ethereum +package trustray import ( "bytes" "encoding/json" + "testing" + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" ) const tokenSrc = ` @@ -146,10 +147,7 @@ func testNormalizeToken(t *testing.T, _test *testToken) { t.Error(err) return } - tk, ok := NormalizeToken(&token, uint(_test.coin)) - if !ok { - t.Errorf("token: token could not be normalized") - } + tk := NormalizeToken(&token, uint(_test.coin)) resJSON, err := json.Marshal(&tk) if err != nil { diff --git a/platform/ethereum/trustray/transaction.go b/platform/ethereum/trustray/transaction.go new file mode 100644 index 000000000..a939e1b99 --- /dev/null +++ b/platform/ethereum/trustray/transaction.go @@ -0,0 +1,125 @@ +package trustray + +import ( + "math/big" + + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/address" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (c *Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) { + page, err := c.GetTxs(address) + if err != nil { + return nil, err + } + return normalizePage(page, address, coinIndex), nil +} + +func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas.TxPage, error) { + page, err := c.GetTxsWithContract(address, token) + if err != nil { + return nil, err + } + return normalizePage(page, address, coinIndex), nil +} + +func normalizePage(srcPage *Page, address string, coinIndex uint) blockatlas.TxPage { + var txs []blockatlas.Tx + for i, srcTx := range srcPage.Docs { + txs = AppendTxs(txs, &srcTx, coinIndex) + txs[i].Direction = txs[i].GetTransactionDirection(address) + } + return blockatlas.TxPage(txs) +} + +func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas.Tx) { + out = in + baseTx, ok := extractBase(srcTx, coinIndex) + if !ok { + return + } + + // Native ETH transaction + if len(srcTx.Ops) == 0 && srcTx.Input == "0x" { + transferTx := baseTx + transferTx.Meta = blockatlas.Transfer{ + Value: blockatlas.Amount(srcTx.Value), + Symbol: coin.Coins[coinIndex].Symbol, + Decimals: coin.Coins[coinIndex].Decimals, + } + out = append(out, transferTx) + } + + // Smart Contract Call + if len(srcTx.Ops) == 0 && srcTx.Input != "0x" { + contractTx := baseTx + contractTx.Meta = blockatlas.ContractCall{ + Input: srcTx.Input, + Value: srcTx.Value, + } + out = append(out, contractTx) + } + + if len(srcTx.Ops) == 0 { + return + } + op := &srcTx.Ops[0] + + if op.Type == blockatlas.TxTokenTransfer && op.Contract != nil { + tokenTx := baseTx + + tokenTx.Meta = blockatlas.TokenTransfer{ + Name: op.Contract.Name, + Symbol: op.Contract.Symbol, + TokenID: address.EIP55Checksum(op.Contract.Address), + Decimals: op.Contract.Decimals, + Value: blockatlas.Amount(op.Value), + From: op.From, + To: op.To, + } + out = append(out, tokenTx) + } + return +} + +func extractBase(srcTx *Doc, coinIndex uint) (base blockatlas.Tx, ok bool) { + var ( + status blockatlas.Status + errReason string + ) + + if srcTx.Error == "" { + status = blockatlas.StatusCompleted + } else { + status = blockatlas.StatusError + errReason = srcTx.Error + } + + fee := calcFee(srcTx.GasPrice, srcTx.GasUsed) + + base = blockatlas.Tx{ + ID: srcTx.ID, + Coin: coinIndex, + From: srcTx.From, + To: srcTx.To, + Fee: blockatlas.Amount(fee), + Date: srcTx.Timestamp, + Block: srcTx.BlockNumber, + Status: status, + Error: errReason, + Sequence: srcTx.Nonce, + } + return base, true +} + +func calcFee(gasPrice string, gasUsed string) string { + var gasPriceBig, gasUsedBig, feeBig big.Int + + gasPriceBig.SetString(gasPrice, 10) + gasUsedBig.SetString(gasUsed, 10) + + feeBig.Mul(&gasPriceBig, &gasUsedBig) + + return feeBig.String() +} diff --git a/platform/ethereum/transaction_test.go b/platform/ethereum/trustray/transaction_test.go similarity index 99% rename from platform/ethereum/transaction_test.go rename to platform/ethereum/trustray/transaction_test.go index eef731398..4063fc02d 100644 --- a/platform/ethereum/transaction_test.go +++ b/platform/ethereum/trustray/transaction_test.go @@ -1,11 +1,12 @@ -package ethereum +package trustray import ( "bytes" "encoding/json" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/coin" ) diff --git a/platform/platform.go b/platform/platform.go index b19940f24..b60a96850 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -45,15 +45,19 @@ func GetVar(name string) string { } func GetApiVar(coinId uint) string { - varName := fmt.Sprintf("%s.api", coin.Coins[coinId].Handle) + varName := fmt.Sprintf("%s.api", GetHandle(coinId)) return GetVar(varName) } func GetRpcVar(coinId uint) string { - varName := fmt.Sprintf("%s.rpc", coin.Coins[coinId].Handle) + varName := fmt.Sprintf("%s.rpc", GetHandle(coinId)) return GetVar(varName) } +func GetHandle(coinId uint) string { + return coin.Coins[coinId].Handle +} + func getPlatformMap() blockatlas.Platforms { return blockatlas.Platforms{ coin.Fio().Handle: fio.Init(GetApiVar(coin.FIO)), @@ -102,7 +106,7 @@ func getPlatformMap() blockatlas.Platforms { coin.Callisto().Handle: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO)), coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN)), coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), - coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), + coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), coin.Near().Handle: near.Init(GetApiVar(coin.NEAR)), } } From acfd8e87c9216db62a971a84231a6e61a02aa363 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov Date: Wed, 15 Apr 2020 09:25:54 +0300 Subject: [PATCH 254/506] [Cache] Fix Write method in cache middleware (#1036) --- api/middleware/cache.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/middleware/cache.go b/api/middleware/cache.go index 916483a87..ccc500bf1 100644 --- a/api/middleware/cache.go +++ b/api/middleware/cache.go @@ -64,10 +64,10 @@ func (w *cachedWriter) Written() bool { func (w *cachedWriter) Write(data []byte) (int, error) { ret, err := w.ResponseWriter.Write(data) if err != nil { - return 0, errors.E(err, "fail to cache write string", errors.Params{"data": data}) + return 0, nil } if w.Status() != 200 { - return 0, errors.E("Write: invalid cache status", errors.Params{"data": data}) + return 0, nil } val := cacheResponse{ w.Status(), From d7b19a855039ed04790b2218aa206e60bb4975a4 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Thu, 16 Apr 2020 23:04:15 +0200 Subject: [PATCH 255/506] Mocked token tests. (#1035) * Mocked tron staking tests: first 2 TCs. * Complete mocked Tron staking test. * Mocked Kava staking test. * Update RPC endpoints. * Cosmos Kava staking test. * Iotex staking test. * Fix cosmos tx test (merge 2 js files). * Fix kava tx test, merge 2 js files. * Fix iotex tx test, merge 2 js. * Enable staking tests in mocked newman tests. * Minor formatting, codacy. * Add mocked Tron token test. * Mocked ETC token test. * Remove console.log. * Mocked ETH token test. * Codacy: exclude all dyson mock JS files. * Rename. * Mocked Poa token test. * Rename. * Mocked Gochain token test. * Renames. * Mocked callisto token test. * Mocked tomochain token test. * Mocked thundertoken token test. * Mocked binance token tests, mocked binance dex. * Enable mocked token tests. * Add mocked test descriptions to Readme. * Remove codacy workaround. * Comment cleanup. * Eth-blockbook fix. Co-authored-by: Catenocrypt --- Makefile | 4 +- README.md | 19 + configmock.yml | 2 +- .../get/aeternity-api-transactions.js | 5 +- .../get/aion-get-getTransactionsByAddress.js | 5 +- .../ext-api-dyson/get/algorand-api-account.js | 2 +- mock/ext-api-dyson/get/algorand-api-block.js | 2 +- .../get/binance-dex-commands2.js | 543 ++++++++++++++++++ .../get/callisto-api-commands1.js | 84 +++ .../get/callisto-api-transactions.js | 60 -- .../ext-api-dyson/get/cosmos-api-commands2.js | 4 +- .../ext-api-dyson/get/cosmos-api-commands4.js | 4 +- mock/ext-api-dyson/get/eth-api-commands1.js | 4 +- .../get/eth-blockbook-api-transactions.js | 386 +++++++++---- .../get/ethclassic-api-commands1.js | 4 +- .../get/gochain-api-commands1.js | 83 +++ .../get/gochain-api-transactions.js | 58 -- mock/ext-api-dyson/get/icon-api-actions.js | 5 +- mock/ext-api-dyson/get/iotex-api-commands2.js | 4 +- mock/ext-api-dyson/get/iotex-api-commands4.js | 4 +- mock/ext-api-dyson/get/kava-api-commands2.js | 4 +- mock/ext-api-dyson/get/kava-api-commands4.js | 4 +- mock/ext-api-dyson/get/kava-api-txs.js | 4 +- mock/ext-api-dyson/get/kin-api-accounts.js | 5 +- .../ext-api-dyson/get/kin-api-transactions.js | 5 +- mock/ext-api-dyson/get/nebulas-api-tx.js | 5 +- .../get/ontolotgy-api-v2-addresses.js | 5 +- mock/ext-api-dyson/get/poa-api-commands1.js | 138 +++++ .../ext-api-dyson/get/poa-api-transactions.js | 113 ---- mock/ext-api-dyson/get/ripple-get-accounts.js | 5 +- .../ext-api-dyson/get/stellar-api-accounts.js | 5 +- .../get/stellar-api-transactions.js | 5 +- .../get/tezos-api-transactions.js | 2 +- mock/ext-api-dyson/get/theta-api-accounttx.js | 5 +- .../get/thundertoken-api-commands1.js | 100 ++++ .../get/thundertoken-api-transactions.js | 75 --- .../get/tomochain-api-commands1.js | 89 +++ .../get/tomochain-api-transactions.js | 58 -- .../ext-api-dyson/get/tron-api-v1-accounts.js | 4 +- mock/ext-api-dyson/get/tron-api-v1-assets.js | 4 +- mock/ext-api-dyson/get/tron-api-wallet.js | 5 +- .../ext-api-dyson/get/vechain-api-entities.js | 5 +- .../get/waves-api-transactions-address.js | 5 +- mock/ext-api-dyson/post/kusama-api.js | 3 +- mock/ext-api-dyson/post/nano-api.js | 4 +- mock/ext-api-dyson/post/tron-api-wallet.js | 5 +- mock/ext-api-dyson/post/vechain-api-logs.js | 3 +- 47 files changed, 1390 insertions(+), 557 deletions(-) create mode 100644 mock/ext-api-dyson/get/binance-dex-commands2.js create mode 100644 mock/ext-api-dyson/get/callisto-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/callisto-api-transactions.js create mode 100644 mock/ext-api-dyson/get/gochain-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/gochain-api-transactions.js create mode 100644 mock/ext-api-dyson/get/poa-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/poa-api-transactions.js create mode 100644 mock/ext-api-dyson/get/thundertoken-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/thundertoken-api-transactions.js create mode 100644 mock/ext-api-dyson/get/tomochain-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/tomochain-api-transactions.js diff --git a/Makefile b/Makefile index 1169f6056..2130cdadf 100644 --- a/Makefile +++ b/Makefile @@ -177,8 +177,8 @@ newman-mocked-params: start-platform-api-mock ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host) && \ $(MAKE) newman-run test=domain host=$(host) && \ - $(MAKE) newman-run test=staking host=$(host)" - #not-mocked-yet: $(MAKE) newman-run test=token host=$(host) && \ + $(MAKE) newman-run test=staking host=$(host) && \ + $(MAKE) newman-run test=token host=$(host)" #not-mocked-yet: $(MAKE) newman-run test=collection host=$(host) && @bash -c "$(MAKE) stop" else diff --git a/README.md b/README.md index 2e8154995..455d57f82 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,25 @@ Example: ATLAS_NIMIQ_API=http://localhost:8648 ``` +## Tests + +### Unit tests + +### Mocked tests + +End-to-end tests with calls to external APIs has great value, but is not suitable for regular CI verification, as any external reasons could break the tests. + +Therefore mocked API-level tests are used, whereby external APIs are replaced by mocks. + +* External mocks are implemented using *dyson*, as javascript files. They generally return constant, pre-canned responses to the reuests that occur during tests. +* Mocks are 'turned on' by corresponging API endpoints in the configmock.yml config file (localhost:3000). +* Tests invoke into blockatlas through public APIs only, and are executed using *newman* (Postman cli -- `make newman-mocked`). +* Product code, and even test code should not be aware whether it runs with mocks or the real external endpoints. +* See Makefile for targets with 'mock'; platform can be started locally with mocks using `make start-platform-api-mock`. +* When dyson is started (e.g. with `make start-platform-api-mock`), it outputs requests, which helps debugging +* The newman tests can be executed with unmocked external APIs as well, but verifications may fail, because some APIs return variable responses. Unmocked tests are not intended for regular CI execution, but as ad-hoc development tests. +* General steps for creating new mocked tests: replace endpoint to localhost:3000, observer incoming calls (dyson output), obtain real response from external API (with exact same parameters), enhance dsyon script to return the same output, verify that blockatlas provides correct output. Also, add verifications of results to the tests. + ## Docs Swagger API docs provided at path `/swagger/index.html` diff --git a/configmock.yml b/configmock.yml index 16dcfd17e..2e7f40de2 100644 --- a/configmock.yml +++ b/configmock.yml @@ -38,7 +38,7 @@ postgres: # Binance Chain: https://explorer.binance.org binance: api: http://localhost:3000/binance-api/v1 - dex: https://dex.binance.org/api + dex: http://localhost:3000/binance-dex # [NIM] Nimiq: https://nimiq.com nimiq: diff --git a/mock/ext-api-dyson/get/aeternity-api-transactions.js b/mock/ext-api-dyson/get/aeternity-api-transactions.js index 30dd4c219..9b36c79db 100644 --- a/mock/ext-api-dyson/get/aeternity-api-transactions.js +++ b/mock/ext-api-dyson/get/aeternity-api-transactions.js @@ -54,8 +54,7 @@ module.exports = { `); } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js b/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js index 1c44b14fa..78867abba 100644 --- a/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js +++ b/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js @@ -69,8 +69,7 @@ module.exports = { } `); } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/algorand-api-account.js b/mock/ext-api-dyson/get/algorand-api-account.js index c450b711c..ceac2cbd3 100644 --- a/mock/ext-api-dyson/get/algorand-api-account.js +++ b/mock/ext-api-dyson/get/algorand-api-account.js @@ -35,7 +35,7 @@ module.exports = { } `); } - // fallback + return {error: "Not implemented"} } }; diff --git a/mock/ext-api-dyson/get/algorand-api-block.js b/mock/ext-api-dyson/get/algorand-api-block.js index c6ff6f80d..fe67d4016 100644 --- a/mock/ext-api-dyson/get/algorand-api-block.js +++ b/mock/ext-api-dyson/get/algorand-api-block.js @@ -55,7 +55,7 @@ module.exports = { } `); } - // fallback + return {error: "Not implemented"} } }; diff --git a/mock/ext-api-dyson/get/binance-dex-commands2.js b/mock/ext-api-dyson/get/binance-dex-commands2.js new file mode 100644 index 000000000..c60466506 --- /dev/null +++ b/mock/ext-api-dyson/get/binance-dex-commands2.js @@ -0,0 +1,543 @@ +/// Binance chain block explorer API Mock, Dex +/// See: +/// curl "http://localhost:3000/binance-dex/v1/account/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" +/// curl "http://localhost:3000/binance-dex/v1/tokens?limit=1000&offset=0" +/// curl "https://dex.binance.org/api/v1/account/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" +/// curl "https://dex.binance.org/api/v1/tokens?limit=1000&offset=0" +/// curl "http://localhost:8420/v2/binance/tokens/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m?Authorization=Bearer" + +module.exports = { + path: '/binance-dex/:version/:command1/:command2?', + template: function(params, query, body) { + //console.log(params); + //console.log(query); + switch (params.version) { + case 'v1': + switch (params.command1) { + case 'account': + switch (params.command2) { + case 'bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m': + return JSON.parse(` + { + "account_number": 51, + "address": "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m", + "balances": [ + { + "free": "1732627268.91580163", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "CHZ-ECD" + }, + { + "free": "927279.98843502", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "GTO-908" + }, + { + "free": "22990392.97970594", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "LBA-340" + }, + { + "free": "13504.20603578", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "LTC-F07" + }, + { + "free": "1.00000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "SLV-986" + }, + { + "free": "3400.00000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "TWT-8C2" + }, + { + "free": "417595410.39908617", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "COS-2E4" + }, + { + "free": "8859448.20434497", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "XRP-BF2" + }, + { + "free": "66199647.50538896", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "VRAB-B56" + }, + { + "free": "565.32000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "AERGO-46B" + }, + { + "free": "145.00000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ART-3C9" + }, + { + "free": "483312.47553546", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BOLT-4C6" + }, + { + "free": "85668472.69714541", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ERD-D06" + }, + { + "free": "372741.55000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "MDAB-D42" + }, + { + "free": "56343499.10367935", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ONE-5F9" + }, + { + "free": "2000000.00000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BCPT-95A" + }, + { + "free": "5.00110000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BEAR-14C" + }, + { + "free": "2000.00000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "GIV-94E" + }, + { + "free": "9.44356120", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "NEXO-A84" + }, + { + "free": "193182441.20916349", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "UND-EBC" + }, + { + "free": "569871.98092216", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "TUSDB-888" + }, + { + "free": "316344310.00000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BKRW-AB7" + }, + { + "free": "0.00091449", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "EOSBEAR-721" + }, + { + "free": "10918.75299816", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "EOSBULL-F0D" + }, + { + "free": "296751584.10699693", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "TROY-9B8" + }, + { + "free": "450587749.03659246", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "WINB-41F" + }, + { + "free": "1438139.59497068", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ARN-71B" + }, + { + "free": "19597996.48343213", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "COTI-CBB" + }, + { + "free": "3572612.16675809", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "LTO-BDF" + }, + { + "free": "1.22227000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "XRPBEAR-00B" + }, + { + "free": "8619272.37637807", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "CAN-677" + }, + { + "free": "338507.95870700", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "HNST-3C9" + }, + { + "free": "173741504.28850373", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BTTB-D31" + }, + { + "free": "65500.72562560", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BUSD-BD1" + }, + { + "free": "8549.17210965", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ETH-1C9" + }, + { + "free": "1654100.82380293", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "TOMOB-4BC" + }, + { + "free": "5.00455774", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "XRPBULL-E7C" + }, + { + "free": "35.00000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "AWC-986" + }, + { + "free": "1587996.65265528", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BNB" + }, + { + "free": "45605.00637205", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "QARK-FCE" + }, + { + "free": "1406863.84448749", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ARPA-575" + }, + { + "free": "1619733.62576473", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ENTRP-C8D" + }, + { + "free": "0.01392000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "MTXLT-286" + }, + { + "free": "2340.58605759", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BCH-1FD" + }, + { + "free": "3.49158551", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BULL-BE4" + }, + { + "free": "1.00000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ECO-083" + }, + { + "free": "0.50000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "WICC-01D" + }, + { + "free": "4235575.51194174", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "KAVA-10C" + }, + { + "free": "10.00000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "PVT-554" + }, + { + "free": "9772.00009772", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "UPX-F3E" + }, + { + "free": "221000.60154058", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "USDSB-1AC" + }, + { + "free": "4372695.27174854", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "WRX-ED1" + }, + { + "free": "19906076.03857030", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "PHB-2DF" + }, + { + "free": "12696933.52213685", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "TRXB-2E6" + }, + { + "free": "267793524.10892121", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BLINK-9C6" + }, + { + "free": "3370.02600563", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BTCB-1DE" + }, + { + "free": "103467039.59858401", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "CBM-4B2" + }, + { + "free": "4095309.32370000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "DUSK-45E" + }, + { + "free": "82964636.96725382", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "FTM-A64" + }, + { + "free": "182686435.86912742", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ANKR-E97" + }, + { + "free": "5.00100000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ETHBEAR-B2B" + }, + { + "free": "0.00872511", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "ETHBULL-D33" + }, + { + "free": "39286407.28666093", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "MATIC-84A" + }, + { + "free": "20813555.86251786", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "MITH-C76" + } + ], + "flags": 0, + "public_key": [ + 3, + 86, + 224, + 165, + 128, + 56, + 154, + 111, + 210, + 204, + 145, + 205, + 82, + 92, + 109, + 90, + 77, + 128, + 84, + 175, + 112, + 223, + 23, + 72, + 78, + 88, + 103, + 143, + 159, + 87, + 74, + 11, + 77 + ], + "sequence": 547072 + } + `); + } + break; + + case 'tokens': + return JSON.parse(` + [ + { + "mintable": true, + "name": "Africa Stable-Coin", + "original_symbol": "ABCD", + "owner": "bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms", + "symbol": "ABCD-5D8", + "total_supply": "3000000.00000000" + }, + { + "mintable": false, + "name": "Aditus", + "original_symbol": "ADI", + "owner": "bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps", + "symbol": "ADI-6BB", + "total_supply": "750000000.00000000" + }, + { + "mintable": false, + "name": "Aergo", + "original_symbol": "AERGO", + "owner": "bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl", + "symbol": "AERGO-46B", + "total_supply": "500000000.00000000" + }, + { + "mintable": false, + "name": "Alaris", + "original_symbol": "ALA", + "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", + "symbol": "ALA-DCD", + "total_supply": "60000000.00000000" + }, + { + "mintable": false, + "name": "ANKR", + "original_symbol": "ANKR", + "owner": "bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn", + "symbol": "ANKR-E97", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Aeron", + "original_symbol": "ARN", + "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", + "symbol": "ARN-71B", + "total_supply": "20000000.00000000" + }, + { + "mintable": true, + "name": "ARPA", + "original_symbol": "ARPA", + "owner": "bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c", + "symbol": "ARPA-575", + "total_supply": "12000000.00000000" + }, + { + "mintable": false, + "name": "Maecenas ART Token", + "original_symbol": "ART", + "owner": "bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l", + "symbol": "ART-3C9", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "Atlas Protocol", + "original_symbol": "ATP", + "owner": "bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf", + "symbol": "ATP-38C", + "total_supply": "40000000.00000000" + }, + { + "mintable": false, + "name": "Travala.com Token", + "original_symbol": "AVA", + "owner": "bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c", + "symbol": "AVA-645", + "total_supply": "61383832.00000000" + } + ] + `); + } + } + + // not found, address + return {txNums: 0, txArray: []} + } +}; diff --git a/mock/ext-api-dyson/get/callisto-api-commands1.js b/mock/ext-api-dyson/get/callisto-api-commands1.js new file mode 100644 index 000000000..af630eea6 --- /dev/null +++ b/mock/ext-api-dyson/get/callisto-api-commands1.js @@ -0,0 +1,84 @@ +/// Callisto API Mock +/// See: +/// curl "http://localhost:3000/callisto-api/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" +/// curl "http://localhost:3000/callisto-api/tokens?address=0xc3d5b69f65027ddf48f894e6e90121293a2f6615" +/// curl "https://{callisto rpc}/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" +/// curl "https://{callisto rpc}/tokens?address=0xc3d5b69f65027ddf48f894e6e90121293a2f6615" +/// curl "http://localhost:8420/v1/callisto/0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" +/// curl "http://localhost:8420/v2/callisto/tokens/0xc3d5b69f65027ddf48f894e6e90121293a2f6615?Authorization=Bearer" + +module.exports = { + path: '/callisto-api/:command1?', + template: function(params, query, body) { + //console.log(query); + switch (params.command1) { + case 'transactions': + if (query.address === '0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7') { + return JSON.parse(` + { + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x4052f55ee615a783abaa22a62100a45d2eee27ecab3a599e9d6691371336463e", + "blockNumber": 4699868, + "time": 1584952936, + "nonce": 7973, + "from": "0x28D2c7db63a9fC5f0b1eE3Ee2B7c0c350Eb9256A", + "to": "0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7", + "value": "120071054450000000000", + "gas": "21000", + "gasPrice": "50000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x4052f55ee615a783abaa22a62100a45d2eee27ecab3a599e9d6691371336463e", + "timeStamp": "1584952936" + }, + { + "operations": [], + "contract": null, + "_id": "0x8d50f2e48d3616e55c4adf2b579aa4696459714c2777baf01d43333389acf9c5", + "blockNumber": 4699693, + "time": 1584950541, + "nonce": 1466, + "from": "0x1212c7aE2d01E3d174C759EF616c46C9C50bd94f", + "to": "0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7", + "value": "179512617388000000000", + "gas": "21000", + "gasPrice": "50000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x8d50f2e48d3616e55c4adf2b579aa4696459714c2777baf01d43333389acf9c5", + "timeStamp": "1584950541" + } + ], + "total": 2 + } + `); + } + break; + + case 'tokens': + if (query.address === '0xc3d5b69f65027ddf48f894e6e90121293a2f6615') { + return JSON.parse(` + { + "total": 1, + "docs": [ + { + "address": "0xc3d5B69F65027dDF48f894E6e90121293a2F6615", + "name": "The Hitchhikers Guide to the Galaxy", + "decimals": 18, + "symbol": "H2G2" + } + ] + } + `); + } + break; + } + + return {error: "Not implemented"}; + } +}; diff --git a/mock/ext-api-dyson/get/callisto-api-transactions.js b/mock/ext-api-dyson/get/callisto-api-transactions.js deleted file mode 100644 index 7c8789baf..000000000 --- a/mock/ext-api-dyson/get/callisto-api-transactions.js +++ /dev/null @@ -1,60 +0,0 @@ -/// Callisto API Mock -/// See: -/// curl "http://localhost:3000/callisto-api/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" -/// curl "http://{callisto rpc}/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" -/// curl http://localhost:8420/v1/callisto/0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7 - -module.exports = { - path: '/callisto-api/transactions', - template: function(params, query, body) { - //console.log(query) - if (query.address === '0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7') { - return JSON.parse(` - { - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0x4052f55ee615a783abaa22a62100a45d2eee27ecab3a599e9d6691371336463e", - "blockNumber": 4699868, - "time": 1584952936, - "nonce": 7973, - "from": "0x28D2c7db63a9fC5f0b1eE3Ee2B7c0c350Eb9256A", - "to": "0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7", - "value": "120071054450000000000", - "gas": "21000", - "gasPrice": "50000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x4052f55ee615a783abaa22a62100a45d2eee27ecab3a599e9d6691371336463e", - "timeStamp": "1584952936" - }, - { - "operations": [], - "contract": null, - "_id": "0x8d50f2e48d3616e55c4adf2b579aa4696459714c2777baf01d43333389acf9c5", - "blockNumber": 4699693, - "time": 1584950541, - "nonce": 1466, - "from": "0x1212c7aE2d01E3d174C759EF616c46C9C50bd94f", - "to": "0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7", - "value": "179512617388000000000", - "gas": "21000", - "gasPrice": "50000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x8d50f2e48d3616e55c4adf2b579aa4696459714c2777baf01d43333389acf9c5", - "timeStamp": "1584950541" - } - ], - "total": 2 - } - `); - } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; - } -}; diff --git a/mock/ext-api-dyson/get/cosmos-api-commands2.js b/mock/ext-api-dyson/get/cosmos-api-commands2.js index 886ba5d4f..4b3517811 100644 --- a/mock/ext-api-dyson/get/cosmos-api-commands2.js +++ b/mock/ext-api-dyson/get/cosmos-api-commands2.js @@ -3680,9 +3680,7 @@ module.exports = { } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/cosmos-api-commands4.js b/mock/ext-api-dyson/get/cosmos-api-commands4.js index eba2be0a0..82c3dfbdf 100644 --- a/mock/ext-api-dyson/get/cosmos-api-commands4.js +++ b/mock/ext-api-dyson/get/cosmos-api-commands4.js @@ -36,9 +36,7 @@ module.exports = { } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/eth-api-commands1.js b/mock/ext-api-dyson/get/eth-api-commands1.js index 54b798084..a97e0f9d9 100644 --- a/mock/ext-api-dyson/get/eth-api-commands1.js +++ b/mock/ext-api-dyson/get/eth-api-commands1.js @@ -189,8 +189,6 @@ module.exports = { } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js b/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js index 9d4d268e2..e387c192f 100644 --- a/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js +++ b/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js @@ -1,114 +1,294 @@ /// Ethereum Blockbook API Mock /// See: -/// curl "http://localhost:3000/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7&details=txs" -/// curl http://localhost:8420/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7 +/// curl "http://localhost:3000/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs" +/// curl "http://localhost:3000/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokens" +/// curl "https://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs" +/// curl "https://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokens" +/// curl "http://localhost:8420/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://localhost:8420/v2/ethereum/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" module.exports = { - path: '/eth-blockbook-api/v2/address/:address', + path: '/eth-blockbook-api/v2/address/:address?', template: function(params, query, body) { - //console.log(query) + //console.log(params); + //console.log(query); if (params.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { - return JSON.parse(`{ - "page": 1, - "totalPages": 11, - "itemsOnPage": 25, - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "balance": "185659745674589722", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 259, - "nonTokenTxs": 240, - "transactions": [ - { - "txid": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", - "vin": [ - { - "n": 0, - "addresses": [ - "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" - ], - "isAddress": true - } - ], - "vout": [ - { - "value": "17635730000000000", - "n": 0, - "addresses": [ - "0x1717f94202c126ef71d6C562de253Fe95eEbDD5f" - ], - "isAddress": true - } - ], - "blockHash": "0x5b8b39099d025a8feeed7575ebff6d0b2508e0542d6279c1b3b4f8b893e74296", - "blockHeight": 9551915, - "confirmations": 231227, - "blockTime": 1582624428, - "value": "17635730000000000", - "fees": "90720000000000", - "ethereumSpecific": { - "status": 1, - "nonce": 227, - "gasLimit": 21000, - "gasUsed": 21000, - "gasPrice": "4320000000" + if (query.details === 'tokens') { + return JSON.parse(` + { + "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "balance": "182976771756327797", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 263, + "nonTokenTxs": 243, + "nonce": "231", + "tokens": [ + { + "type": "ERC20", + "name": "Kyber Network Crystal", + "contract": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + "transfers": 13, + "symbol": "KNC", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "BNB", + "contract": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", + "transfers": 4, + "symbol": "BNB", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "Basic Attention Token", + "contract": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "transfers": 40, + "symbol": "BAT", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "Propy", + "contract": "0x226bb599a12C826476e3A771454697EA52E9E220", + "transfers": 1, + "symbol": "PRO", + "decimals": 8 + }, + { + "type": "ERC20", + "name": "Everex", + "contract": "0xf3Db5Fa2C66B7aF3Eb0C0b782510816cbe4813b8", + "transfers": 2, + "symbol": "EVX", + "decimals": 4 + }, + { + "type": "ERC20", + "name": "Telcoin", + "contract": "0x85e076361cc813A908Ff672F9BAd1541474402b2", + "transfers": 61, + "symbol": "TEL", + "decimals": 2 + }, + { + "type": "ERC20", + "name": "blockwell.ai KYC Casper Token", + "contract": "0x212D95FcCdF0366343350f486bda1ceAfC0C2d63", + "transfers": 1, + "symbol": "blockwell.ai KYC Casper Token", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "VeChain Token", + "contract": "0xD850942eF8811f2A866692A623011bDE52a462C1", + "transfers": 1, + "symbol": "VEN", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "BlockchainCuties", + "contract": "0xD73bE539d6B2076BaB83CA6Ba62DfE189aBC6Bbe", + "transfers": 2, + "symbol": "BC", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "TrueUSD", + "contract": "0x0000000000085d4780B73119b644AE5ecd22b376", + "transfers": 5, + "symbol": "TUSD", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "ERC20", + "contract": "0xc3761EB917CD790B30dAD99f6Cc5b4Ff93C4F9eA", + "transfers": 1, + "symbol": "ERC20", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "Azbit", + "contract": "0x77FE30b2cf39245267C0a5084B66a560f1cF9E1f", + "transfers": 1, + "symbol": "AZ", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "Coin-coin coinslot.com", + "contract": "0x7f3EaB3491Ed282197038F1B89CA33D7e5ADffBa", + "transfers": 1, + "symbol": "CC coinslot.com", + "decimals": 8 + }, + { + "type": "ERC20", + "name": "Tether USD", + "contract": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "transfers": 2, + "symbol": "USDT", + "decimals": 6 + }, + { + "type": "ERC20", + "name": "Mycion", + "contract": "0xE1Ac9Eb7cDDAbfd9e5CA49c23bd521aFcDF8BE49", + "transfers": 1, + "symbol": "MYC", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "Enjin Coin", + "contract": "0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c", + "transfers": 1, + "symbol": "ENJ", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "Telcoin", + "contract": "0x467Bccd9d29f223BcE8043b84E8C8B282827790F", + "transfers": 1, + "symbol": "TEL", + "decimals": 2 + }, + { + "type": "ERC20", + "name": "KickToken", + "contract": "0xC12D1c73eE7DC3615BA4e37E4ABFdbDDFA38907E", + "transfers": 1, + "symbol": "KICK", + "decimals": 8 + }, + { + "type": "ERC20", + "name": "OMGToken", + "contract": "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07", + "transfers": 2, + "symbol": "OMG", + "decimals": 18 + }, + { + "type": "ERC20", + "name": "Minereum", + "contract": "0xc92e74b131D7b1D46E60e07F3FaE5d8877Dd03F0", + "transfers": 1, + "symbol": "MNE", + "decimals": 8 + } + ] } - }, - { - "txid": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", - "vin": [ - { - "n": 0, - "addresses": [ - "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8" - ], - "isAddress": true - } - ], - "vout": [ - { - "value": "0", - "n": 0, - "addresses": [ - "0x0D8775F648430679A709E98d2b0Cb6250d2887EF" - ], - "isAddress": true - } + `); + } + return JSON.parse(` + { + "page": 1, + "totalPages": 11, + "itemsOnPage": 25, + "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "balance": "185659745674589722", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 259, + "nonTokenTxs": 240, + "transactions": [ + { + "txid": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", + "vin": [ + { + "n": 0, + "addresses": [ + "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "17635730000000000", + "n": 0, + "addresses": [ + "0x1717f94202c126ef71d6C562de253Fe95eEbDD5f" + ], + "isAddress": true + } + ], + "blockHash": "0x5b8b39099d025a8feeed7575ebff6d0b2508e0542d6279c1b3b4f8b893e74296", + "blockHeight": 9551915, + "confirmations": 231227, + "blockTime": 1582624428, + "value": "17635730000000000", + "fees": "90720000000000", + "ethereumSpecific": { + "status": 1, + "nonce": 227, + "gasLimit": 21000, + "gasUsed": 21000, + "gasPrice": "4320000000" + } + }, + { + "txid": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", + "vin": [ + { + "n": 0, + "addresses": [ + "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "addresses": [ + "0x0D8775F648430679A709E98d2b0Cb6250d2887EF" + ], + "isAddress": true + } + ], + "blockHash": "0x770332c9b4ea42e518f8c5a0178ca5732fd5edfe5e8e011e1362e6598de262d5", + "blockHeight": 9519169, + "confirmations": 263973, + "blockTime": 1582189159, + "value": "0", + "fees": "425822000000000", + "tokenTransfers": [ + { + "type": "ERC20", + "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", + "to": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "token": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "name": "Basic Attention Token", + "symbol": "BAT", + "decimals": 18, + "value": "400000000000000000" + } + ], + "ethereumSpecific": { + "status": 1, + "nonce": 16, + "gasLimit": 51839, + "gasUsed": 37028, + "gasPrice": "11500000000" + } + } ], - "blockHash": "0x770332c9b4ea42e518f8c5a0178ca5732fd5edfe5e8e011e1362e6598de262d5", - "blockHeight": 9519169, - "confirmations": 263973, - "blockTime": 1582189159, - "value": "0", - "fees": "425822000000000", - "tokenTransfers": [ - { - "type": "ERC20", - "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", - "to": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "token": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", - "name": "Basic Attention Token", - "symbol": "BAT", - "decimals": 18, - "value": "400000000000000000" - } - ], - "ethereumSpecific": { - "status": 1, - "nonce": 16, - "gasLimit": 51839, - "gasUsed": 37028, - "gasPrice": "11500000000" - } - } - ], - "nonce": "228", - "tokens": [] - }`); + "nonce": "228", + "tokens": [] + } + `); } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/ethclassic-api-commands1.js b/mock/ext-api-dyson/get/ethclassic-api-commands1.js index 44b3b2ace..901719f59 100644 --- a/mock/ext-api-dyson/get/ethclassic-api-commands1.js +++ b/mock/ext-api-dyson/get/ethclassic-api-commands1.js @@ -84,8 +84,6 @@ module.exports = { } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/gochain-api-commands1.js b/mock/ext-api-dyson/get/gochain-api-commands1.js new file mode 100644 index 000000000..aa4070fad --- /dev/null +++ b/mock/ext-api-dyson/get/gochain-api-commands1.js @@ -0,0 +1,83 @@ +/// Gochain API Mock +/// See: +/// curl "http://localhost:3000/gochain-api/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" +/// curl "http://localhost:3000/gochain-api/tokens?address=0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628" +/// curl "https://{go rpc}/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" +/// curl "https://{go rpc}/ +/// curl "http://localhost:8420/v1/gochain/0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" +/// curl "http://localhost:8420/v2/gochain/tokens/0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628?Authorization=Bearer" + +module.exports = { + path: '/gochain-api/:command1?', + template: function(params, query, body) { + //console.log(params); + //console.log(query); + switch (params.command1) { + case 'transactions': + if (query.address === '0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896') { + return JSON.parse(`{ + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7", + "blockNumber": 10070535, + "time": 1576793173, + "nonce": 6, + "from": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", + "to": "0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3", + "value": "860000000000000000000000", + "gas": "90000", + "gasPrice": "2000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7", + "timeStamp": "1576793173" + }, + { + "operations": [], + "contract": null, + "_id": "0x472c94385a46072713bb2bf3503fc1610135a70e415046bf61a937789c205f4c", + "blockNumber": 10070520, + "time": 1576793098, + "nonce": 5, + "from": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", + "to": "0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3", + "value": "800000000000000000000", + "gas": "90000", + "gasPrice": "2000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x472c94385a46072713bb2bf3503fc1610135a70e415046bf61a937789c205f4c", + "timeStamp": "1576793098" + } + ], + "total": 2 + }`); + } + break; + + case 'tokens': + if (query.address === '0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628') { + return JSON.parse(` + { + "total": 1, + "docs": [ + { + "address": "0x5f16Fa0B5c9d779a3C8d46859a27973Ff3511188", + "name": "pukkamex", + "decimals": 18, + "symbol": "PUX" + } + ] + } + `); + } + break; + } + + return {error: "Not implemented"}; + } +}; diff --git a/mock/ext-api-dyson/get/gochain-api-transactions.js b/mock/ext-api-dyson/get/gochain-api-transactions.js deleted file mode 100644 index 0b72af854..000000000 --- a/mock/ext-api-dyson/get/gochain-api-transactions.js +++ /dev/null @@ -1,58 +0,0 @@ -/// Gochain API Mock -/// See: -/// curl "http://localhost:3000/gochain-api/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" -/// curl "http://{go rpc}/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" -/// curl http://localhost:8420/v1/gochain/0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896 - -module.exports = { - path: '/gochain-api/transactions', - template: function(params, query, body) { - //console.log(query) - if (query.address === '0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896') { - return JSON.parse(`{ - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7", - "blockNumber": 10070535, - "time": 1576793173, - "nonce": 6, - "from": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", - "to": "0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3", - "value": "860000000000000000000000", - "gas": "90000", - "gasPrice": "2000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7", - "timeStamp": "1576793173" - }, - { - "operations": [], - "contract": null, - "_id": "0x472c94385a46072713bb2bf3503fc1610135a70e415046bf61a937789c205f4c", - "blockNumber": 10070520, - "time": 1576793098, - "nonce": 5, - "from": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", - "to": "0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3", - "value": "800000000000000000000", - "gas": "90000", - "gasPrice": "2000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x472c94385a46072713bb2bf3503fc1610135a70e415046bf61a937789c205f4c", - "timeStamp": "1576793098" - } - ], - "total": 2 - }`); - } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; - } -}; diff --git a/mock/ext-api-dyson/get/icon-api-actions.js b/mock/ext-api-dyson/get/icon-api-actions.js index 78b72c8dc..4f57cb401 100644 --- a/mock/ext-api-dyson/get/icon-api-actions.js +++ b/mock/ext-api-dyson/get/icon-api-actions.js @@ -66,8 +66,7 @@ module.exports = { `); } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/iotex-api-commands2.js b/mock/ext-api-dyson/get/iotex-api-commands2.js index 7f5159777..95c31a92d 100644 --- a/mock/ext-api-dyson/get/iotex-api-commands2.js +++ b/mock/ext-api-dyson/get/iotex-api-commands2.js @@ -815,9 +815,7 @@ module.exports = { } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/iotex-api-commands4.js b/mock/ext-api-dyson/get/iotex-api-commands4.js index 44dfe10c0..e8086329c 100644 --- a/mock/ext-api-dyson/get/iotex-api-commands4.js +++ b/mock/ext-api-dyson/get/iotex-api-commands4.js @@ -102,9 +102,7 @@ module.exports = { } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/kava-api-commands2.js b/mock/ext-api-dyson/get/kava-api-commands2.js index 815843c11..a55e7c993 100644 --- a/mock/ext-api-dyson/get/kava-api-commands2.js +++ b/mock/ext-api-dyson/get/kava-api-commands2.js @@ -2622,9 +2622,7 @@ module.exports = { } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/kava-api-commands4.js b/mock/ext-api-dyson/get/kava-api-commands4.js index 34c0e641a..54c47c963 100644 --- a/mock/ext-api-dyson/get/kava-api-commands4.js +++ b/mock/ext-api-dyson/get/kava-api-commands4.js @@ -24,9 +24,7 @@ module.exports = { } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/kava-api-txs.js b/mock/ext-api-dyson/get/kava-api-txs.js index e701f0ee3..fb901a3f1 100644 --- a/mock/ext-api-dyson/get/kava-api-txs.js +++ b/mock/ext-api-dyson/get/kava-api-txs.js @@ -271,9 +271,7 @@ module.exports = { `); } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/kin-api-accounts.js b/mock/ext-api-dyson/get/kin-api-accounts.js index 8351cd6b8..0ab2d6c1b 100644 --- a/mock/ext-api-dyson/get/kin-api-accounts.js +++ b/mock/ext-api-dyson/get/kin-api-accounts.js @@ -90,8 +90,7 @@ module.exports = { `); } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/kin-api-transactions.js b/mock/ext-api-dyson/get/kin-api-transactions.js index 604d7027a..7c989a2b1 100644 --- a/mock/ext-api-dyson/get/kin-api-transactions.js +++ b/mock/ext-api-dyson/get/kin-api-transactions.js @@ -105,8 +105,7 @@ module.exports = { } `); } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/nebulas-api-tx.js b/mock/ext-api-dyson/get/nebulas-api-tx.js index a4913f82e..98b539205 100644 --- a/mock/ext-api-dyson/get/nebulas-api-tx.js +++ b/mock/ext-api-dyson/get/nebulas-api-tx.js @@ -126,8 +126,7 @@ module.exports = { } `); } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js b/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js index 9e5bf722d..6770b91b7 100644 --- a/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js +++ b/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js @@ -117,8 +117,7 @@ module.exports = { } `); } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/poa-api-commands1.js b/mock/ext-api-dyson/get/poa-api-commands1.js new file mode 100644 index 000000000..773957999 --- /dev/null +++ b/mock/ext-api-dyson/get/poa-api-commands1.js @@ -0,0 +1,138 @@ +/// POA API Mock +/// See: +/// curl "http://localhost:3000/poa-api/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" +/// curl "http://localhost:3000/poa-api/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "https://{poa rpc}/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" +/// curl "https://{poa rpc}/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://localhost:8420/v1/poa/0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" +/// curl "http://localhost:8420/v2/poa/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" + +module.exports = { + path: '/poa-api/:command1?', + template: function(params, query, body) { + //console.log(params); + //console.log(query); + switch (params.command1) { + case 'tokens': + if (query.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { + return JSON.parse(` + { + "total": 1, + "docs": [ + { + "address": "0xADFE00d92e5A16e773891F59780e6e54f40B532e", + "name": "Viktor Coin", + "decimals": 0, + "symbol": "VIK" + } + ] + } + `); + } + break; + + case 'transactions': + if (query.address === '0x55798eCbF17ce1241d543c22dCE46134c13b4bc0') { + return JSON.parse(` + { + "docs": [ + { + "operations": [ + { + "transactionId": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d-0", + "contract": { + "address": "0xab2f2dd3120de530d38936ee09a74a6d17e3da44", + "decimals": 18, + "name": "GeonCoin", + "symbol": "GC", + "totalSupply": "100000000000000000000000000", + "updatedAt": "2020-02-26T23:41:29.763Z" + }, + "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "to": "0xE87E46032847e097F5bB51404d19A0449c704EE8", + "type": "token_transfer", + "value": "1000000000000000000", + "id": null + } + ], + "contract": null, + "_id": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d", + "blockNumber": 14115901, + "time": 1584448420, + "nonce": 1, + "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "to": "0xAb2f2Dd3120dE530d38936EE09A74a6d17e3Da44", + "value": "0", + "gas": "120000", + "gasPrice": "1000000000", + "gasUsed": "78484", + "input": "0xb88a3f725e70c38d1d03b5568e2f4d1600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000", + "error": "", + "id": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d", + "timeStamp": "1584448420" + }, + { + "operations": [], + "contract": null, + "_id": "0xcde1f2c3a262012f624065f167616db3160e763f4938ccfa0fcc742d5725eae2", + "blockNumber": 14115900, + "time": 1584448415, + "nonce": 109291, + "from": "0x628cF7150f8242b20B2ADB064D27183D2a026130", + "to": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "value": "600000000000000", + "gas": "120000", + "gasPrice": "1000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0xcde1f2c3a262012f624065f167616db3160e763f4938ccfa0fcc742d5725eae2", + "timeStamp": "1584448415" + }, + { + "operations": [], + "contract": null, + "_id": "0x90ef177d3448d379560218f99657027661a7238fb62c793dc2a7091a0d0d88e8", + "blockNumber": 14115899, + "time": 1584448410, + "nonce": 0, + "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "to": "0xE87E46032847e097F5bB51404d19A0449c704EE8", + "value": "0", + "gas": "120000", + "gasPrice": "1000000000", + "gasUsed": "100890", + "input": "0x1e76c9445e70c38d1d03b5568e2f4d160000000000000000000000000000000000000000", + "error": "", + "id": "0x90ef177d3448d379560218f99657027661a7238fb62c793dc2a7091a0d0d88e8", + "timeStamp": "1584448410" + }, + { + "operations": [], + "contract": null, + "_id": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3", + "blockNumber": 14115898, + "time": 1584448405, + "nonce": 109290, + "from": "0x628cF7150f8242b20B2ADB064D27183D2a026130", + "to": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", + "value": "600000000000000", + "gas": "120000", + "gasPrice": "1000000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3", + "timeStamp": "1584448405" + } + ], + "total": 4 + } + `); + } + break; + } + + return {error: "Not implemented"}; + } +}; diff --git a/mock/ext-api-dyson/get/poa-api-transactions.js b/mock/ext-api-dyson/get/poa-api-transactions.js deleted file mode 100644 index ef3808277..000000000 --- a/mock/ext-api-dyson/get/poa-api-transactions.js +++ /dev/null @@ -1,113 +0,0 @@ -/// POA API Mock -/// See: -/// curl "http://localhost:3000/poa-api/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" -/// curl "http://{poa rpc}/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" -/// curl http://localhost:8420/v1/poa/0x55798eCbF17ce1241d543c22dCE46134c13b4bc0 - -module.exports = { - path: '/poa-api/transactions', - template: function(params, query, body) { - //console.log(query) - if (query.address === '0x55798eCbF17ce1241d543c22dCE46134c13b4bc0') { - return JSON.parse(` - { - "docs": [ - { - "operations": [ - { - "transactionId": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d-0", - "contract": { - "address": "0xab2f2dd3120de530d38936ee09a74a6d17e3da44", - "decimals": 18, - "name": "GeonCoin", - "symbol": "GC", - "totalSupply": "100000000000000000000000000", - "updatedAt": "2020-02-26T23:41:29.763Z" - }, - "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "to": "0xE87E46032847e097F5bB51404d19A0449c704EE8", - "type": "token_transfer", - "value": "1000000000000000000", - "id": null - } - ], - "contract": null, - "_id": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d", - "blockNumber": 14115901, - "time": 1584448420, - "nonce": 1, - "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "to": "0xAb2f2Dd3120dE530d38936EE09A74a6d17e3Da44", - "value": "0", - "gas": "120000", - "gasPrice": "1000000000", - "gasUsed": "78484", - "input": "0xb88a3f725e70c38d1d03b5568e2f4d1600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000", - "error": "", - "id": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d", - "timeStamp": "1584448420" - }, - { - "operations": [], - "contract": null, - "_id": "0xcde1f2c3a262012f624065f167616db3160e763f4938ccfa0fcc742d5725eae2", - "blockNumber": 14115900, - "time": 1584448415, - "nonce": 109291, - "from": "0x628cF7150f8242b20B2ADB064D27183D2a026130", - "to": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "value": "600000000000000", - "gas": "120000", - "gasPrice": "1000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0xcde1f2c3a262012f624065f167616db3160e763f4938ccfa0fcc742d5725eae2", - "timeStamp": "1584448415" - }, - { - "operations": [], - "contract": null, - "_id": "0x90ef177d3448d379560218f99657027661a7238fb62c793dc2a7091a0d0d88e8", - "blockNumber": 14115899, - "time": 1584448410, - "nonce": 0, - "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "to": "0xE87E46032847e097F5bB51404d19A0449c704EE8", - "value": "0", - "gas": "120000", - "gasPrice": "1000000000", - "gasUsed": "100890", - "input": "0x1e76c9445e70c38d1d03b5568e2f4d160000000000000000000000000000000000000000", - "error": "", - "id": "0x90ef177d3448d379560218f99657027661a7238fb62c793dc2a7091a0d0d88e8", - "timeStamp": "1584448410" - }, - { - "operations": [], - "contract": null, - "_id": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3", - "blockNumber": 14115898, - "time": 1584448405, - "nonce": 109290, - "from": "0x628cF7150f8242b20B2ADB064D27183D2a026130", - "to": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "value": "600000000000000", - "gas": "120000", - "gasPrice": "1000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3", - "timeStamp": "1584448405" - } - ], - "total": 4 - } - `); - } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; - } -}; diff --git a/mock/ext-api-dyson/get/ripple-get-accounts.js b/mock/ext-api-dyson/get/ripple-get-accounts.js index 545ee1562..ba5680618 100644 --- a/mock/ext-api-dyson/get/ripple-get-accounts.js +++ b/mock/ext-api-dyson/get/ripple-get-accounts.js @@ -198,8 +198,7 @@ module.exports = { } `); } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/stellar-api-accounts.js b/mock/ext-api-dyson/get/stellar-api-accounts.js index f0605ed98..b8e5543cc 100644 --- a/mock/ext-api-dyson/get/stellar-api-accounts.js +++ b/mock/ext-api-dyson/get/stellar-api-accounts.js @@ -92,8 +92,7 @@ module.exports = { `); } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/stellar-api-transactions.js b/mock/ext-api-dyson/get/stellar-api-transactions.js index 9d4e7ed43..90b1f5036 100644 --- a/mock/ext-api-dyson/get/stellar-api-transactions.js +++ b/mock/ext-api-dyson/get/stellar-api-transactions.js @@ -111,8 +111,7 @@ module.exports = { } `); } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/tezos-api-transactions.js b/mock/ext-api-dyson/get/tezos-api-transactions.js index 08093d95a..dd7889358 100644 --- a/mock/ext-api-dyson/get/tezos-api-transactions.js +++ b/mock/ext-api-dyson/get/tezos-api-transactions.js @@ -176,7 +176,7 @@ module.exports = { } `) } - // fallback + return {error: "Not implemented"} } }; diff --git a/mock/ext-api-dyson/get/theta-api-accounttx.js b/mock/ext-api-dyson/get/theta-api-accounttx.js index 3cd7f1b85..13df717fb 100644 --- a/mock/ext-api-dyson/get/theta-api-accounttx.js +++ b/mock/ext-api-dyson/get/theta-api-accounttx.js @@ -88,8 +88,7 @@ module.exports = { } `); } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/thundertoken-api-commands1.js b/mock/ext-api-dyson/get/thundertoken-api-commands1.js new file mode 100644 index 000000000..bf81b3656 --- /dev/null +++ b/mock/ext-api-dyson/get/thundertoken-api-commands1.js @@ -0,0 +1,100 @@ +/// Thundertoken API Mock +/// See: +/// curl "http://localhost:3000/thundertoken-api/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" +/// curl "http://localhost:3000/thundertoken-api/tokens?address=0x0b230def08139f18a86536d9cfa150f04435414c" +/// curl "https://{Thundertoken rpc}/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" +/// curl "https://{Thundertoken rpc}/tokens?address=0x0b230def08139f18a86536d9cfa150f04435414c" +/// curl "http://localhost:8420/v1/thundertoken/0x0b230def08139f18a86536d9cfa150f04435414c" +/// curl "http://localhost:8420/v2/thundertoken/tokens/0x0b230def08139f18a86536d9cfa150f04435414c?Authorization=Bearer" + +module.exports = { + path: '/thundertoken-api/:command1?', + template: function(params, query, body) { + //console.log(params); + //console.log(query); + switch (params.command1) { + case 'transactions': + if (query.address === '0x0b230def08139f18a86536d9cfa150f04435414c') { + return JSON.parse(`{ + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x80929a2170969364e06d253d2b853fe0b2ca3a307e61d629946b9b76e2f983cf", + "blockNumber": 33514713, + "time": 1584945288, + "nonce": 312, + "from": "0x0B230dEf08139F18a86536d9CFa150f04435414c", + "to": "0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1", + "value": "0", + "gas": "4700000", + "gasPrice": "4000000000", + "gasUsed": "421569", + "input": "0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800", + "error": "", + "id": "0x80929a2170969364e06d253d2b853fe0b2ca3a307e61d629946b9b76e2f983cf", + "timeStamp": "1584945288" + }, + { + "operations": [ + { + "transactionId": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00-0", + "contract": { + "address": "0x51bca9300d034a7e6ab379399a317bdfa0d4835b", + "decimals": 18, + "name": "The Third Identity", + "symbol": "TTI", + "totalSupply": "10000000000000000000000000000", + "updatedAt": "2020-02-26T21:42:19.178Z" + }, + "from": "0x3270b4e0916B4556BF236B6E5D4377282b3255e5", + "to": "0x0B230dEf08139F18a86536d9CFa150f04435414c", + "type": "token_transfer", + "value": "292820000000000000000", + "id": null + } + ], + "contract": null, + "_id": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00", + "blockNumber": 33514370, + "time": 1584944945, + "nonce": 311, + "from": "0x0B230dEf08139F18a86536d9CFa150f04435414c", + "to": "0x3270b4e0916B4556BF236B6E5D4377282b3255e5", + "value": "0", + "gas": "4700000", + "gasPrice": "2880000000", + "gasUsed": "1511414", + "input": "0x4008d2f3", + "error": "", + "id": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00", + "timeStamp": "1584944945" + } + ], + "total": 2 + }`); + } + break; + + case 'tokens': + if (query.address === '0x0b230def08139f18a86536d9cfa150f04435414c') { + return JSON.parse(` + { + "total": 1, + "docs": [ + { + "address": "0x51BcA9300d034A7e6aB379399a317bDfA0D4835b", + "name": "The Third Identity", + "decimals": 18, + "symbol": "TTI" + } + ] + } + `); + } + break; + } + + return {error: "Not implemented"}; + } +}; diff --git a/mock/ext-api-dyson/get/thundertoken-api-transactions.js b/mock/ext-api-dyson/get/thundertoken-api-transactions.js deleted file mode 100644 index 13de512b7..000000000 --- a/mock/ext-api-dyson/get/thundertoken-api-transactions.js +++ /dev/null @@ -1,75 +0,0 @@ -/// Thundertoken API Mock -/// See: -/// curl "http://localhost:3000/thundertoken-api/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" -/// curl "http://{Thundertoken rpc}/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" -/// curl http://localhost:8420/v1/thundertoken/0x0b230def08139f18a86536d9cfa150f04435414c - -module.exports = { - path: '/thundertoken-api/transactions', - template: function(params, query, body) { - //console.log(query) - if (query.address === '0x0b230def08139f18a86536d9cfa150f04435414c') { - return JSON.parse(`{ - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0x80929a2170969364e06d253d2b853fe0b2ca3a307e61d629946b9b76e2f983cf", - "blockNumber": 33514713, - "time": 1584945288, - "nonce": 312, - "from": "0x0B230dEf08139F18a86536d9CFa150f04435414c", - "to": "0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1", - "value": "0", - "gas": "4700000", - "gasPrice": "4000000000", - "gasUsed": "421569", - "input": "0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800", - "error": "", - "id": "0x80929a2170969364e06d253d2b853fe0b2ca3a307e61d629946b9b76e2f983cf", - "timeStamp": "1584945288" - }, - { - "operations": [ - { - "transactionId": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00-0", - "contract": { - "address": "0x51bca9300d034a7e6ab379399a317bdfa0d4835b", - "decimals": 18, - "name": "The Third Identity", - "symbol": "TTI", - "totalSupply": "10000000000000000000000000000", - "updatedAt": "2020-02-26T21:42:19.178Z" - }, - "from": "0x3270b4e0916B4556BF236B6E5D4377282b3255e5", - "to": "0x0B230dEf08139F18a86536d9CFa150f04435414c", - "type": "token_transfer", - "value": "292820000000000000000", - "id": null - } - ], - "contract": null, - "_id": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00", - "blockNumber": 33514370, - "time": 1584944945, - "nonce": 311, - "from": "0x0B230dEf08139F18a86536d9CFa150f04435414c", - "to": "0x3270b4e0916B4556BF236B6E5D4377282b3255e5", - "value": "0", - "gas": "4700000", - "gasPrice": "2880000000", - "gasUsed": "1511414", - "input": "0x4008d2f3", - "error": "", - "id": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00", - "timeStamp": "1584944945" - } - ], - "total": 2 - }`); - } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; - } -}; diff --git a/mock/ext-api-dyson/get/tomochain-api-commands1.js b/mock/ext-api-dyson/get/tomochain-api-commands1.js new file mode 100644 index 000000000..c1526c87e --- /dev/null +++ b/mock/ext-api-dyson/get/tomochain-api-commands1.js @@ -0,0 +1,89 @@ +/// Tomochain API Mock +/// See: +/// curl "http://localhost:3000/tomochain-api/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" +/// curl "http://localhost:3000/tomochain-api/tokens?address=0x8b353021189375591723e7384262f45709a3c3dc" +/// curl "https://{Tomochain rpc}/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" +/// curl "https://{Tomochain rpc}/tokens?address=0x8b353021189375591723e7384262f45709a3c3dc" +/// curl "http://localhost:8420/v1/tomochain/0x17e4c16605e32adead5fa371bf6117df34ca0200" +/// curl "http://localhost:8420/v2/tomochain/tokens/0x8b353021189375591723e7384262f45709a3c3dc?Authorization=Bearer" + +module.exports = { + path: '/tomochain-api/:command1?', + template: function(params, query, body) { + //console.log(params); + //console.log(query); + switch (params.command1) { + case 'transactions': + if (query.address === '0x17e4c16605e32adead5fa371bf6117df34ca0200') { + return JSON.parse(`{ + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0xb2af5ad5eebaba1da3452e0281f9b6ec9e00a5bb832793a912eb3959b6c2fdd2", + "blockNumber": 18455252, + "time": 1584963130, + "nonce": 892939, + "from": "0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200", + "to": "0x0000000000000000000000000000000000000089", + "value": "0", + "gas": "200000", + "gasPrice": "0", + "gasUsed": "0", + "input": "0xe341eaa40000000000000000000000000000000000000000000000000000000001199ad29a43ad0df08d1ff128de7642208ce68720dc77bbe7e02acb2685951f73efea56", + "error": "", + "id": "0xb2af5ad5eebaba1da3452e0281f9b6ec9e00a5bb832793a912eb3959b6c2fdd2", + "timeStamp": "1584963130" + }, + { + "operations": [], + "contract": null, + "_id": "0x9181d170fb77eb55e1dda42c55080230397702204247e8b242c8f6588f61f41d", + "blockNumber": 18455237, + "time": 1584963100, + "nonce": 892938, + "from": "0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200", + "to": "0x0000000000000000000000000000000000000089", + "value": "0", + "gas": "200000", + "gasPrice": "0", + "gasUsed": "0", + "input": "0xe341eaa40000000000000000000000000000000000000000000000000000000001199ac3f1234069ee58f791cc422978d794e7f3c1e82d580013038badd5493ed854b6e4", + "error": "", + "id": "0x9181d170fb77eb55e1dda42c55080230397702204247e8b242c8f6588f61f41d", + "timeStamp": "1584963100" + } + ], + "total": 2 + }`); + } + break; + + case 'tokens': + if (query.address === '0x8b353021189375591723e7384262f45709a3c3dc') { + return JSON.parse(` + { + "total": 2, + "docs": [ + { + "address": "0xaB7e4aE99D7bfff4de8322aB915e9066857227F0", + "name": "KONG", + "decimals": 18, + "symbol": "KONG" + }, + { + "address": "0xc7BdF5D257fF4EC078e12A3ABD34dFc329E55130", + "name": "AIS Token", + "decimals": 18, + "symbol": "AIS" + } + ] + } + `); + } + break; + } + + return {error: "Not implemented"}; + } +}; diff --git a/mock/ext-api-dyson/get/tomochain-api-transactions.js b/mock/ext-api-dyson/get/tomochain-api-transactions.js deleted file mode 100644 index fcf9da07a..000000000 --- a/mock/ext-api-dyson/get/tomochain-api-transactions.js +++ /dev/null @@ -1,58 +0,0 @@ -/// Tomochain API Mock -/// See: -/// curl "http://localhost:3000/tomochain-api/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" -/// curl "http://{Tomochain rpc}/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" -/// curl http://localhost:8420/v1/tomochain/0x17e4c16605e32adead5fa371bf6117df34ca0200 - -module.exports = { - path: '/tomochain-api/transactions', - template: function(params, query, body) { - //console.log(query) - if (query.address === '0x17e4c16605e32adead5fa371bf6117df34ca0200') { - return JSON.parse(`{ - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0xb2af5ad5eebaba1da3452e0281f9b6ec9e00a5bb832793a912eb3959b6c2fdd2", - "blockNumber": 18455252, - "time": 1584963130, - "nonce": 892939, - "from": "0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200", - "to": "0x0000000000000000000000000000000000000089", - "value": "0", - "gas": "200000", - "gasPrice": "0", - "gasUsed": "0", - "input": "0xe341eaa40000000000000000000000000000000000000000000000000000000001199ad29a43ad0df08d1ff128de7642208ce68720dc77bbe7e02acb2685951f73efea56", - "error": "", - "id": "0xb2af5ad5eebaba1da3452e0281f9b6ec9e00a5bb832793a912eb3959b6c2fdd2", - "timeStamp": "1584963130" - }, - { - "operations": [], - "contract": null, - "_id": "0x9181d170fb77eb55e1dda42c55080230397702204247e8b242c8f6588f61f41d", - "blockNumber": 18455237, - "time": 1584963100, - "nonce": 892938, - "from": "0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200", - "to": "0x0000000000000000000000000000000000000089", - "value": "0", - "gas": "200000", - "gasPrice": "0", - "gasUsed": "0", - "input": "0xe341eaa40000000000000000000000000000000000000000000000000000000001199ac3f1234069ee58f791cc422978d794e7f3c1e82d580013038badd5493ed854b6e4", - "error": "", - "id": "0x9181d170fb77eb55e1dda42c55080230397702204247e8b242c8f6588f61f41d", - "timeStamp": "1584963100" - } - ], - "total": 2 - }`); - } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; - } -}; diff --git a/mock/ext-api-dyson/get/tron-api-v1-accounts.js b/mock/ext-api-dyson/get/tron-api-v1-accounts.js index f2e76ab46..dd814ff7c 100644 --- a/mock/ext-api-dyson/get/tron-api-v1-accounts.js +++ b/mock/ext-api-dyson/get/tron-api-v1-accounts.js @@ -183,8 +183,6 @@ module.exports = { } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/tron-api-v1-assets.js b/mock/ext-api-dyson/get/tron-api-v1-assets.js index 224e76006..8bcfa706c 100644 --- a/mock/ext-api-dyson/get/tron-api-v1-assets.js +++ b/mock/ext-api-dyson/get/tron-api-v1-assets.js @@ -96,8 +96,6 @@ module.exports = { `); } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/tron-api-wallet.js b/mock/ext-api-dyson/get/tron-api-wallet.js index 2c8dc00cc..ca58d75d9 100644 --- a/mock/ext-api-dyson/get/tron-api-wallet.js +++ b/mock/ext-api-dyson/get/tron-api-wallet.js @@ -82,8 +82,7 @@ module.exports = { } `) } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/vechain-api-entities.js b/mock/ext-api-dyson/get/vechain-api-entities.js index 6115e70bf..531a260fa 100644 --- a/mock/ext-api-dyson/get/vechain-api-entities.js +++ b/mock/ext-api-dyson/get/vechain-api-entities.js @@ -100,8 +100,7 @@ module.exports = { `); } } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/get/waves-api-transactions-address.js b/mock/ext-api-dyson/get/waves-api-transactions-address.js index 062262faa..e797120fd 100644 --- a/mock/ext-api-dyson/get/waves-api-transactions-address.js +++ b/mock/ext-api-dyson/get/waves-api-transactions-address.js @@ -53,9 +53,8 @@ module.exports = { ] ] } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } } ; diff --git a/mock/ext-api-dyson/post/kusama-api.js b/mock/ext-api-dyson/post/kusama-api.js index 61fe9d1df..426f7f74b 100644 --- a/mock/ext-api-dyson/post/kusama-api.js +++ b/mock/ext-api-dyson/post/kusama-api.js @@ -59,7 +59,6 @@ module.exports = { } `); } - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/post/nano-api.js b/mock/ext-api-dyson/post/nano-api.js index c161b417c..a65af1bd5 100644 --- a/mock/ext-api-dyson/post/nano-api.js +++ b/mock/ext-api-dyson/post/nano-api.js @@ -42,7 +42,7 @@ module.exports = { } return {error: 'Bad account number'}; } - var return4Codacy = {error: 'Invalid request'}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/post/tron-api-wallet.js b/mock/ext-api-dyson/post/tron-api-wallet.js index 08ffc3547..bc2a8a533 100644 --- a/mock/ext-api-dyson/post/tron-api-wallet.js +++ b/mock/ext-api-dyson/post/tron-api-wallet.js @@ -11,8 +11,7 @@ module.exports = { if (params.operation === 'getaccount') { return {balance: 1, assetV2: [], votes: [], frozen: []} } - // fallback - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + + return {error: "Not implemented"}; } }; diff --git a/mock/ext-api-dyson/post/vechain-api-logs.js b/mock/ext-api-dyson/post/vechain-api-logs.js index 95987d08c..2f4ca51ce 100644 --- a/mock/ext-api-dyson/post/vechain-api-logs.js +++ b/mock/ext-api-dyson/post/vechain-api-logs.js @@ -45,7 +45,6 @@ module.exports = { `); } } - var return4Codacy = {error: "Not implemented"}; - return return4Codacy; + return {error: "Not implemented"}; } }; From cc48fc0f5faea2bf5c1d8ea45b556ddfd9a18597 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Mon, 20 Apr 2020 13:14:13 +0800 Subject: [PATCH 256/506] exclude mocked js from linguist (#1039) --- vendor.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 vendor.yml diff --git a/vendor.yml b/vendor.yml new file mode 100644 index 000000000..b9dfc5ff1 --- /dev/null +++ b/vendor.yml @@ -0,0 +1,3 @@ +# test data + +- mock/ext-api-dyson/ From f9fb629d78f49effafcdb672ef33c17499bc6887 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Wed, 22 Apr 2020 17:59:40 +0800 Subject: [PATCH 257/506] [Ethereum] return contract_type if token transfers > 1 (#1044) * only check 1 token transfer case * add token transfer test --- platform/ethereum/blockbook/transaction.go | 57 ++++++------ .../ethereum/blockbook/transaction_test.go | 86 ++++++++++++++++--- 2 files changed, 103 insertions(+), 40 deletions(-) diff --git a/platform/ethereum/blockbook/transaction.go b/platform/ethereum/blockbook/transaction.go index 47d19265b..b5d109002 100644 --- a/platform/ethereum/blockbook/transaction.go +++ b/platform/ethereum/blockbook/transaction.go @@ -101,37 +101,36 @@ func fillTokenTransfer(final *blockatlas.Tx, tx *Transaction, coinIndex uint) bo } func fillTokenTransferWithAddress(final *blockatlas.Tx, tx *Transaction, address, token string, coinIndex uint) bool { - if len(tx.TokenTransfers) > 0 { - for _, transfer := range tx.TokenTransfers { - if transfer.To == address || transfer.From == address { - // filter token if specified - if token != "" { - if token != transfer.Token { - continue - } - } - direction := GetDirection(address, transfer.From, transfer.To) - metadata := blockatlas.TokenTransfer{ - Name: transfer.Name, - Symbol: transfer.Symbol, - TokenID: transfer.Token, - Decimals: transfer.Decimals, - Value: blockatlas.Amount(transfer.Value), - } - if direction == blockatlas.DirectionSelf { - metadata.From = address - metadata.To = address - } else if direction == blockatlas.DirectionOutgoing { - metadata.From = address - metadata.To = transfer.To - } else { - metadata.From = transfer.From - metadata.To = address + if len(tx.TokenTransfers) == 1 { + transfer := tx.TokenTransfers[0] + if transfer.To == address || transfer.From == address { + // filter token if specified + if token != "" { + if token != transfer.Token { + return false } - final.Direction = direction - final.Meta = metadata - return true } + direction := GetDirection(address, transfer.From, transfer.To) + metadata := blockatlas.TokenTransfer{ + Name: transfer.Name, + Symbol: transfer.Symbol, + TokenID: transfer.Token, + Decimals: transfer.Decimals, + Value: blockatlas.Amount(transfer.Value), + } + if direction == blockatlas.DirectionSelf { + metadata.From = address + metadata.To = address + } else if direction == blockatlas.DirectionOutgoing { + metadata.From = address + metadata.To = transfer.To + } else { + metadata.From = transfer.From + metadata.To = address + } + final.Direction = direction + final.Meta = metadata + return true } } return false diff --git a/platform/ethereum/blockbook/transaction_test.go b/platform/ethereum/blockbook/transaction_test.go index 147ef00a0..1710deada 100644 --- a/platform/ethereum/blockbook/transaction_test.go +++ b/platform/ethereum/blockbook/transaction_test.go @@ -90,10 +90,57 @@ func TestNormalizePage(t *testing.T) { "gasUsed": 174659, "gasPrice": "1300000000" } - } + }, + { + "txid": "0x17bb2b5e61f34119d4d4fbfae406ad3d854f0a00f13013d77de9aab7179f183f", + "vin": [ + { + "n": 0, + "addresses": [ + "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "addresses": [ + "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359" + ], + "isAddress": true + } + ], + "blockHash": "0xcee3a57858e3629785fb6e7ca34e68605fe3d2f149b73138f38314a3ef935723", + "blockHeight": 9852430, + "confirmations": 67071, + "blockTime": 1586627561, + "value": "0", + "fees": "87378000000000", + "tokenTransfers": [ + { + "type": "ERC20", + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "token": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "name": "Dai Stablecoin v1.0", + "symbol": "DAI", + "decimals": 18, + "value": "100000000000000" + } + ], + "ethereumSpecific": { + "status": 1, + "nonce": 523, + "gasLimit": 43323, + "gasUsed": 29126, + "gasPrice": "3000000000" + } + } ]}`, address: "0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1", - token: "0x6b175474e89094c44da98b954eedeac495271d0f", + token: "", coinIndex: 60, }, want: `[{ @@ -106,19 +153,36 @@ func TestNormalizePage(t *testing.T) { "block": 8958320, "status": "completed", "sequence": 378, + "type": "contract_call", + "direction": "outgoing", + "memo": "", + "metadata": { + "input": "0x", + "value": "0" + } + },{ + "id": "0x17bb2b5e61f34119d4d4fbfae406ad3d854f0a00f13013d77de9aab7179f183f", + "coin": 60, + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "fee": "87378000000000", + "date": 1586627561, + "block": 9852430, + "status": "completed", + "sequence": 523, "type": "token_transfer", - "direction": "incoming", + "direction": "yourself", "memo": "", "metadata": { - "name": "Dai Stablecoin", - "symbol": "DAI", - "token_id": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "decimals": 18, - "value": "2255656573089233195", - "from": "0x0000000000000000000000000000000000000000", - "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + "name": "Dai Stablecoin v1.0", + "symbol": "DAI", + "token_id": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "decimals": 18, + "value": "100000000000000", + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" } - }]`, + }]`, }, } for _, tt := range tests { From 2d394772077d5855f854cb79fb3e554b83a19026 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Wed, 22 Apr 2020 18:14:16 +0800 Subject: [PATCH 258/506] Check err in zilliqa model (#1043) --- go.mod | 2 +- go.sum | 2 +- platform/zilliqa/model.go | 33 ++++++++++++++++++++++++--------- platform/zilliqa/model_test.go | 4 ++-- platform/zilliqa/rpc.go | 7 +++++-- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 62d4cb0c8..abc960dfa 100644 --- a/go.mod +++ b/go.mod @@ -28,4 +28,4 @@ require ( golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e gopkg.in/yaml.v2 v2.2.8 -) +) \ No newline at end of file diff --git a/go.sum b/go.sum index ecb30a18b..24aba8add 100644 --- a/go.sum +++ b/go.sum @@ -596,4 +596,4 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= \ No newline at end of file diff --git a/platform/zilliqa/model.go b/platform/zilliqa/model.go index 8bc611b87..8f932866b 100644 --- a/platform/zilliqa/model.go +++ b/platform/zilliqa/model.go @@ -2,9 +2,10 @@ package zilliqa import ( "encoding/hex" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "math/big" "strconv" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) type BlockTxs [][]string @@ -33,7 +34,10 @@ type Tx struct { func (tx Tx) NonceValue() uint64 { switch n := tx.Nonce.(type) { case string: - r, _ := strconv.Atoi(n) + r, err := strconv.Atoi(n) + if err != nil { + break + } return uint64(r) case int: return uint64(n) @@ -66,14 +70,26 @@ type TxRPC struct { Version string `json:"version"` } -func (t *TxRPC) toTx() Tx { - to, _ := hex.DecodeString(t.ToAddr) - height, _ := strconv.ParseUint(t.Receipt.EpochNum, 10, 64) - gasLimt, _ := new(big.Int).SetString(t.GasLimit, 10) - gasPrice, _ := new(big.Int).SetString(t.GasPrice, 10) +func (t *TxRPC) toTx() *Tx { + to, err := hex.DecodeString(t.ToAddr) + if err != nil { + return nil + } + height, err := strconv.ParseUint(t.Receipt.EpochNum, 10, 64) + if err != nil { + return nil + } + gasLimt, ok := new(big.Int).SetString(t.GasLimit, 10) + if !ok { + return nil + } + gasPrice, ok := new(big.Int).SetString(t.GasPrice, 10) + if !ok { + return nil + } fee := new(big.Int).Mul(gasLimt, gasPrice) - tx := Tx{ + return &Tx{ Hash: "0x" + t.ID, BlockHeight: height, From: EncodePublicKeyToAddress(t.SenderPubKey), @@ -84,7 +100,6 @@ func (t *TxRPC) toTx() Tx { Nonce: t.Nonce, ReceiptSuccess: t.Receipt.Success, } - return tx } type BlockTxRpc struct { diff --git a/platform/zilliqa/model_test.go b/platform/zilliqa/model_test.go index 737894ce7..bd9668d4a 100644 --- a/platform/zilliqa/model_test.go +++ b/platform/zilliqa/model_test.go @@ -43,8 +43,8 @@ func TestTxRPC_toTx(t *testing.T) { return } - if got := txRPC.toTx(); !reflect.DeepEqual(got, tx) { - t.Errorf("TxRPC.toTx() = %v, want %v", got, tx) + if got := txRPC.toTx(); !reflect.DeepEqual(*got, tx) { + t.Errorf("TxRPC.toTx() = %v, want %v", *got, tx) } } diff --git a/platform/zilliqa/rpc.go b/platform/zilliqa/rpc.go index ad86a2941..687e2a184 100644 --- a/platform/zilliqa/rpc.go +++ b/platform/zilliqa/rpc.go @@ -1,10 +1,11 @@ package zilliqa import ( + "strconv" + "github.com/mitchellh/mapstructure" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" - "strconv" ) type RpcClient struct { @@ -66,7 +67,9 @@ func (c *RpcClient) GetTxInBlock(number int64) ([]Tx, error) { if mapstructure.Decode(result.Result, &txRPC) != nil { continue } - txs = append(txs, txRPC.toTx()) + if tx := txRPC.toTx(); tx != nil { + txs = append(txs, *tx) + } } return txs, nil } From 1890c1fd915c327757ddd241a3184d2120a87fe5 Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Thu, 23 Apr 2020 13:20:17 -0700 Subject: [PATCH 259/506] Do not return ERC20 tokens with zero balance (#1045) * Add publicly avalible endpoint to ethereum config * flatten test and add test zero balance token * filter out tokens with zero balance from new endpoint * Add test when balance = "" * Fix typos * Adjust mock test * Fix test --- Makefile | 2 +- README.md | 4 +- config.yml | 12 +- .../get/eth-blockbook-api-transactions.js | 163 ++---------------- platform/ethereum/blockbook/client.go | 2 +- platform/ethereum/blockbook/model.go | 1 + platform/ethereum/blockbook/token.go | 3 + platform/ethereum/blockbook/token_test.go | 57 ++++-- ...son => blockatlas.postman_collection.json} | 4 +- 9 files changed, 68 insertions(+), 180 deletions(-) rename tests/postman/{Blockatlas.postman_collection.json => blockatlas.postman_collection.json} (99%) diff --git a/Makefile b/Makefile index 2130cdadf..404c5c3c6 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,7 @@ ifeq (,$(host)) @exit 1 endif @echo " > Running $(test) tests" - @newman run tests/postman/Blockatlas.postman_collection.json --folder $(test) -d tests/postman/$(test)_data.json --env-var "host=$(host)" + @newman run tests/postman/blockatlas.postman_collection.json --folder $(test) -d tests/postman/$(test)_data.json --env-var "host=$(host)" ## install-dyson: Install Dyson for mocked tests. install-dyson: diff --git a/README.md b/README.md index 455d57f82..f0555085a 100644 --- a/README.md +++ b/README.md @@ -186,8 +186,8 @@ End-to-end tests with calls to external APIs has great value, but is not suitabl Therefore mocked API-level tests are used, whereby external APIs are replaced by mocks. -* External mocks are implemented using *dyson*, as javascript files. They generally return constant, pre-canned responses to the reuests that occur during tests. -* Mocks are 'turned on' by corresponging API endpoints in the configmock.yml config file (localhost:3000). +* External mocks are implemented using *dyson*, as javascript files. They generally return constant, pre-canned responses to the requests that occur during tests. +* Mocks are 'turned on' by corresponding API endpoints in the configmock.yml config file (localhost:3000). * Tests invoke into blockatlas through public APIs only, and are executed using *newman* (Postman cli -- `make newman-mocked`). * Product code, and even test code should not be aware whether it runs with mocks or the real external endpoints. * See Makefile for targets with 'mock'; platform can be started locally with mocks using `make start-platform-api-mock`. diff --git a/config.yml b/config.yml index 5a591a312..fb89281c5 100644 --- a/config.yml +++ b/config.yml @@ -67,12 +67,12 @@ tezos: rpc: https://mainnet.tezos.org.ua # [ETH] Ethereum: https://ethereum.org -# ethereum: -# api: https://localhost:4567 (Trust-Ray API) -# blockbook_api: [blockbook api] -# collections_api: https://api.opensea.io -# collections_api_key: [opensea_api_key] -# rpc: [ethereum rpc] +ethereum: + api: https://localhost:4567 #(Trust-Ray API) + blockbook_api: https://eth1.trezor.io/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: diff --git a/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js b/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js index e387c192f..04d4c66a6 100644 --- a/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js +++ b/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js @@ -1,19 +1,17 @@ /// Ethereum Blockbook API Mock /// See: /// curl "http://localhost:3000/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs" -/// curl "http://localhost:3000/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokens" +/// curl "http://localhost:3000/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances" /// curl "https://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs" -/// curl "https://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokens" +/// curl "https://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances" /// curl "http://localhost:8420/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" /// curl "http://localhost:8420/v2/ethereum/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" module.exports = { path: '/eth-blockbook-api/v2/address/:address?', - template: function(params, query, body) { - //console.log(params); - //console.log(query); + template: function(params, query) { if (params.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { - if (query.details === 'tokens') { + if (query.details === 'tokenBalances') { return JSON.parse(` { "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", @@ -30,7 +28,8 @@ module.exports = { "contract": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", "transfers": 13, "symbol": "KNC", - "decimals": 18 + "decimals": 18, + "balance": "41100" }, { "type": "ERC20", @@ -38,151 +37,17 @@ module.exports = { "contract": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", "transfers": 4, "symbol": "BNB", - "decimals": 18 + "decimals": 18, + "balance": "100500" }, { "type": "ERC20", - "name": "Basic Attention Token", - "contract": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", - "transfers": 40, - "symbol": "BAT", - "decimals": 18 - }, - { - "type": "ERC20", - "name": "Propy", - "contract": "0x226bb599a12C826476e3A771454697EA52E9E220", - "transfers": 1, - "symbol": "PRO", - "decimals": 8 - }, - { - "type": "ERC20", - "name": "Everex", - "contract": "0xf3Db5Fa2C66B7aF3Eb0C0b782510816cbe4813b8", - "transfers": 2, - "symbol": "EVX", - "decimals": 4 - }, - { - "type": "ERC20", - "name": "Telcoin", - "contract": "0x85e076361cc813A908Ff672F9BAd1541474402b2", - "transfers": 61, - "symbol": "TEL", - "decimals": 2 - }, - { - "type": "ERC20", - "name": "blockwell.ai KYC Casper Token", - "contract": "0x212D95FcCdF0366343350f486bda1ceAfC0C2d63", - "transfers": 1, - "symbol": "blockwell.ai KYC Casper Token", - "decimals": 18 - }, - { - "type": "ERC20", - "name": "VeChain Token", - "contract": "0xD850942eF8811f2A866692A623011bDE52a462C1", - "transfers": 1, - "symbol": "VEN", - "decimals": 18 - }, - { - "type": "ERC20", - "name": "BlockchainCuties", - "contract": "0xD73bE539d6B2076BaB83CA6Ba62DfE189aBC6Bbe", - "transfers": 2, - "symbol": "BC", - "decimals": 18 - }, - { - "type": "ERC20", - "name": "TrueUSD", - "contract": "0x0000000000085d4780B73119b644AE5ecd22b376", - "transfers": 5, - "symbol": "TUSD", - "decimals": 18 - }, - { - "type": "ERC20", - "name": "ERC20", - "contract": "0xc3761EB917CD790B30dAD99f6Cc5b4Ff93C4F9eA", - "transfers": 1, - "symbol": "ERC20", - "decimals": 18 - }, - { - "type": "ERC20", - "name": "Azbit", - "contract": "0x77FE30b2cf39245267C0a5084B66a560f1cF9E1f", - "transfers": 1, - "symbol": "AZ", - "decimals": 18 - }, - { - "type": "ERC20", - "name": "Coin-coin coinslot.com", - "contract": "0x7f3EaB3491Ed282197038F1B89CA33D7e5ADffBa", - "transfers": 1, - "symbol": "CC coinslot.com", - "decimals": 8 - }, - { - "type": "ERC20", - "name": "Tether USD", - "contract": "0xdAC17F958D2ee523a2206206994597C13D831ec7", - "transfers": 2, - "symbol": "USDT", - "decimals": 6 - }, - { - "type": "ERC20", - "name": "Mycion", - "contract": "0xE1Ac9Eb7cDDAbfd9e5CA49c23bd521aFcDF8BE49", - "transfers": 1, - "symbol": "MYC", - "decimals": 18 - }, - { - "type": "ERC20", - "name": "Enjin Coin", - "contract": "0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c", - "transfers": 1, - "symbol": "ENJ", - "decimals": 18 - }, - { - "type": "ERC20", - "name": "Telcoin", - "contract": "0x467Bccd9d29f223BcE8043b84E8C8B282827790F", - "transfers": 1, - "symbol": "TEL", - "decimals": 2 - }, - { - "type": "ERC20", - "name": "KickToken", - "contract": "0xC12D1c73eE7DC3615BA4e37E4ABFdbDDFA38907E", - "transfers": 1, - "symbol": "KICK", - "decimals": 8 - }, - { - "type": "ERC20", - "name": "OMGToken", - "contract": "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07", - "transfers": 2, - "symbol": "OMG", - "decimals": 18 - }, - { - "type": "ERC20", - "name": "Minereum", - "contract": "0xc92e74b131D7b1D46E60e07F3FaE5d8877Dd03F0", - "transfers": 1, - "symbol": "MNE", - "decimals": 8 + "name": "BNB", + "contract": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", + "transfers": 4, + "symbol": "BNB", + "decimals": 18, + "balance": "0" } ] } diff --git a/platform/ethereum/blockbook/client.go b/platform/ethereum/blockbook/client.go index 2de84016e..1fd894cdc 100644 --- a/platform/ethereum/blockbook/client.go +++ b/platform/ethereum/blockbook/client.go @@ -48,7 +48,7 @@ func (c *Client) getTransactions(address, contract string) (page *Page, err erro func (c *Client) getTokens(address string) ([]Token, error) { var res Page path := fmt.Sprintf("v2/address/%s", address) - query := url.Values{"details": {"tokens"}} + query := url.Values{"details": {"tokenBalances"}} err := c.Get(&res, path, query) return res.Tokens, err diff --git a/platform/ethereum/blockbook/model.go b/platform/ethereum/blockbook/model.go index 338dcecd0..64d800f06 100644 --- a/platform/ethereum/blockbook/model.go +++ b/platform/ethereum/blockbook/model.go @@ -58,6 +58,7 @@ type TokenTransfer struct { // Token contains info about tokens held by an address type Token struct { + Balance string `json:"balance,omitempty"` Contract string `json:"contract"` Decimals uint `json:"decimals"` Name string `json:"name"` diff --git a/platform/ethereum/blockbook/token.go b/platform/ethereum/blockbook/token.go index 9360092b3..2e8e2b03e 100644 --- a/platform/ethereum/blockbook/token.go +++ b/platform/ethereum/blockbook/token.go @@ -16,6 +16,9 @@ func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenP func NormalizeTokens(srcTokens []Token, coinIndex uint) []blockatlas.Token { tokenPage := make([]blockatlas.Token, 0, len(srcTokens)) for _, srcToken := range srcTokens { + if srcToken.Balance == "0" || srcToken.Balance == "" { + continue + } token := NormalizeToken(&srcToken, coinIndex) tokenPage = append(tokenPage, token) } diff --git a/platform/ethereum/blockbook/token_test.go b/platform/ethereum/blockbook/token_test.go index 8c1982a1e..72beaa855 100644 --- a/platform/ethereum/blockbook/token_test.go +++ b/platform/ethereum/blockbook/token_test.go @@ -9,39 +9,58 @@ import ( func TestNormalizeToken(t *testing.T) { type args struct { - srcToken *Token + srcToken Token coinIndex uint } tests := []struct { name string args args - want blockatlas.Token + want []blockatlas.Token }{ { - name: "Test Normalize Token", - args: args{ - srcToken: &Token{ - Type: "ERC20", - Name: "USD//C", - Contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - Symbol: "USDC", - Decimals: 6, - }, - coinIndex: 60, - }, - want: blockatlas.Token{ + name: "Should normalize and return token with balance", + args: args{srcToken: Token{ + Balance: "100", + Type: "ERC20", + Name: "USD//C", + Contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + Symbol: "USDC", + Decimals: 6}, + coinIndex: 60}, + want: []blockatlas.Token{ + { + Type: "ERC20", + Name: "USD//C", + TokenID: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + Symbol: "USDC", Decimals: 6, Coin: 60}}, + }, + { + name: "Should not return token with zero balance", + args: args{srcToken: Token{ + Balance: "0", + Type: "ERC20", Name: "USD//C", + Contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", Symbol: "USDC", - Decimals: 6, - TokenID: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + Decimals: 6}, + coinIndex: 60}, + want: []blockatlas.Token{}, + }, { + name: "Should not return token with zero balance", + args: args{srcToken: Token{ + Balance: "", Type: "ERC20", - Coin: 60, - }, + Name: "USD//C", + Contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + Symbol: "USDC", + Decimals: 6}, + coinIndex: 60}, + want: []blockatlas.Token{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := NormalizeToken(tt.args.srcToken, tt.args.coinIndex); !reflect.DeepEqual(got, tt.want) { + if got := NormalizeTokens([]Token{tt.args.srcToken}, tt.args.coinIndex); !reflect.DeepEqual(got, tt.want) { t.Errorf("NormalizeToken() = %v, want %v", got, tt.want) } }) diff --git a/tests/postman/Blockatlas.postman_collection.json b/tests/postman/blockatlas.postman_collection.json similarity index 99% rename from tests/postman/Blockatlas.postman_collection.json rename to tests/postman/blockatlas.postman_collection.json index 884eb883d..48af4a341 100644 --- a/tests/postman/Blockatlas.postman_collection.json +++ b/tests/postman/blockatlas.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "7c16faaa-629e-4a75-a8bc-2ccaacb540ff", + "_postman_id": "57634a03-7dfa-4b5b-b48e-f6321ea4ba1e", "name": "Blockatlas", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -188,7 +188,7 @@ "_postman_isSubFolder": true }, { - "name": "tokens", + "name": "token", "item": [ { "name": "token", From dc060c4b71af14891943157baa5c2e327236f0cb Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Thu, 23 Apr 2020 13:54:02 -0700 Subject: [PATCH 260/506] Add CODEOWNERS (#1049) * Add auto assign * Use CODEOWNWRS insted of auto assign action --- .github/CODEOWNERS | 5 +++++ go.mod | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..5f280417a --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,5 @@ +* @EnoRage +* @catenocrypt +* @hewigovens +* @kolya182 +* @prazd diff --git a/go.mod b/go.mod index abc960dfa..62d4cb0c8 100644 --- a/go.mod +++ b/go.mod @@ -28,4 +28,4 @@ require ( golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e gopkg.in/yaml.v2 v2.2.8 -) \ No newline at end of file +) From 34f8956893095046a72b7dfb883930bf2a137145 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Fri, 24 Apr 2020 20:11:34 +0800 Subject: [PATCH 261/506] Fix doge inputs value (#1051) * 1. upgrade bitcoin address api to v2 2. fix balance accumulation * update mock data * Mocked test fix. --- .gitattribute | 1 + coin/coins.go | 4 +- coin/coins.yml | 2 +- mock/ext-api-dyson/get/bitcoin-api-address.js | 205 +- .../get/bitcoincash-api-address.js | 2984 ++++++++--------- mock/ext-api-dyson/get/dash-api-address.js | 261 +- mock/ext-api-dyson/get/decred-api-address.js | 228 +- .../ext-api-dyson/get/digibyte-api-address.js | 284 +- mock/ext-api-dyson/get/doge-api-address.js | 230 +- .../get/groestlcoin-api-address.js | 238 +- .../ext-api-dyson/get/litecoin-api-address.js | 225 +- mock/ext-api-dyson/get/qtum-api-address.js | 310 +- .../get/ravencoin-api-address.js | 238 +- mock/ext-api-dyson/get/viacoin-api-address.js | 168 +- mock/ext-api-dyson/get/zcash-api-address.js | 294 +- mock/ext-api-dyson/get/zcoin-api-address.js | 375 +-- mock/ext-api-dyson/get/zelcash-api-address.js | 352 +- platform/bitcoin/client.go | 5 +- platform/bitcoin/transaction.go | 11 +- platform/bitcoin/transaction_test.go | 97 +- tests/postman/transaction_data.json | 28 +- vendor.yml | 3 - 22 files changed, 2933 insertions(+), 3610 deletions(-) create mode 100644 .gitattribute delete mode 100644 vendor.yml diff --git a/.gitattribute b/.gitattribute new file mode 100644 index 000000000..a6594a4dc --- /dev/null +++ b/.gitattribute @@ -0,0 +1 @@ +mock/ext-api-dyson/* linguist-vendored \ No newline at end of file diff --git a/coin/coins.go b/coin/coins.go index 6fa1f08a8..dcebc47bf 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -454,7 +454,7 @@ var Coins = map[uint]Coin{ Decimals: 8, BlockTime: 60000, MinConfirmations: 0, - SampleAddr: "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS", + SampleAddr: "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo", }, QTUM: { ID: 2301, @@ -557,6 +557,7 @@ var Coins = map[uint]Coin{ SampleAddr: "NEAR6Y66fCzeKqWiwxoPox5oGeDN9VhNCu7CEQ9M86iniqoN9vg2X", }, } + func Ethereum() Coin { return Coins[ETH] } @@ -701,4 +702,3 @@ func Solana() Coin { func Near() Coin { return Coins[NEAR] } - diff --git a/coin/coins.yml b/coin/coins.yml index 92a442ffc..4379fd1bd 100644 --- a/coin/coins.yml +++ b/coin/coins.yml @@ -299,7 +299,7 @@ name: Raven decimals: 8 blockTime: 60000 - sampleAddress: 'RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS' + sampleAddress: 'RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo' - id: 2301 symbol: QTUM diff --git a/mock/ext-api-dyson/get/bitcoin-api-address.js b/mock/ext-api-dyson/get/bitcoin-api-address.js index 26fbe54c3..16ef2ab65 100644 --- a/mock/ext-api-dyson/get/bitcoin-api-address.js +++ b/mock/ext-api-dyson/get/bitcoin-api-address.js @@ -1,130 +1,111 @@ /// Mock for external Bitcoin API /// See: -/// curl "http://localhost:3000/bitcoin-api/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" -/// curl "https://btc1.trezor.io/api/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" +/// curl "http://localhost:3000/bitcoin-api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" +/// curl "https://btc1.trezor.io/api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" /// curl "http://localhost:8420/v1/bitcoin/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" module.exports = { - path: '/bitcoin-api/address/:address?', + path: '/bitcoin-api/v2/address/:address?', template: function (params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 'bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj': return JSON.parse(` { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "addrStr": "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj", - "balance": "0.00020074", - "totalReceived": "0.00091089", - "totalSent": "0.00071015", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 2, - "txs": [ - { - "txid": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4", - "version": 1, - "vin": [ - { - "txid": "270a6490cc806d99aa84bb8079b543d9d7a255fc59364890e7a4cb57970daef8", - "vout": 1, - "sequence": 4294967294, - "n": 0, - "scriptSig": {}, - "addresses": [ - "bc1q3230a7cqt2drewuza8qff4c4gpt4muy9qyqknw" - ], - "value": "0.00001699" - } - ], - "vout": [ - { - "value": "0.00000375", - "n": 0, - "scriptPubKey": { - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ] - }, - "spent": false - }, - { - "value": "0.00001098", - "n": 1, - "scriptPubKey": { - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj", + "balance": "15245", + "totalReceived": "91089", + "totalSent": "75844", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 12, + "transactions": [{ + "txid": "36b1e721a25ea3ac2fcc09a92d4ff1e2ae4ed70d593e276806d9a9fd2a901132", + "version": 1, + "vin": [{ + "txid": "c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be", + "vout": 1, + "n": 0, "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ] - }, - "spent": false - } - ], - "blockhash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", - "blockheight": 622017, - "confirmations": 780, - "time": 1584485709, - "blocktime": 1584485709, - "valueOut": "0.00001473", - "valueIn": "0.00001699", - "fees": "0.00000226", - "hex": "01000000000101f8ae0d9757cba4e790483659fc55a2d7d943b57980bb84aa996d80cc90640a270100000000feffffff0277010000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a4a040000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220683d9c2b40958fd706623783017300ebbc9b73ce1db571963d9bb40679c3079c02207ee68976e225e1e98d20e66d4d8a498cddf3268d0d7b66827a2ed3ac4330f137012102b7f0cb54c2a6a4da3372fe17d7a07475f575777364633e89dacb39eb1fd5a09c00000000" + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true, + "value": "4829" + }], + "vout": [{ + "value": "1000", + "n": 0, + "hex": "a9141ba5187259ae22520f99ec3522d320279066aafd87", + "addresses": [ + "34DBwkzPz6yeqU1LoZLVzdCm91oeyxq37T" + ], + "isAddress": true + }, + { + "value": "2699", + "n": 1, + "hex": "00148f347b3ea1ce113b09e096125a3ad3310dd0a947", + "addresses": [ + "bc1q3u68k04pecgnkz0qjcf95wknxyxap2287gyzrg" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000000fccc2c78e235d6ea3da4013ea98c8376c7c41f7f71938", + "blockHeight": 624894, + "confirmations": 2494, + "blockTime": 1586299624, + "value": "3699", + "valueIn": "4829", + "fees": "1130", + "hex": "01000000000101be328cc2ca0135e640bc1e795f20d3189939ab3712d8e79627347a5c2dc8a4c601000000000000000002e80300000000000017a9141ba5187259ae22520f99ec3522d320279066aafd878b0a0000000000001600148f347b3ea1ce113b09e096125a3ad3310dd0a94702483045022100c251d7e2497b42d57ff00c92eeb8a6faa86a3d5d77a9d257b7e464400306fa5502204f532ab553ba711779cf1f93cab47c4f5e0f11dbc6017781c79b76caa6ea322b012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" }, { - "txid": "c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be", - "version": 1, - "vin": [ - { - "txid": "d39d78838d5a3c870aa5acdc9e518945bd6ad86af093b38f85c714f790f28c76", - "vout": 1, - "n": 0, - "scriptSig": {}, - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "value": "0.00006055" - } - ], - "vout": [ - { - "value": "0.00001", - "n": 0, - "scriptPubKey": { - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ] - }, - "spent": false - }, - { - "value": "0.00004829", - "n": 1, - "scriptPubKey": { - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "txid": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4", + "version": 1, + "vin": [{ + "txid": "270a6490cc806d99aa84bb8079b543d9d7a255fc59364890e7a4cb57970daef8", + "vout": 1, + "sequence": 4294967294, + "n": 0, "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ] - }, - "spent": false - } - ], - "blockhash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", - "blockheight": 622017, - "confirmations": 780, - "time": 1584485709, - "blocktime": 1584485709, - "valueOut": "0.00005829", - "valueIn": "0.00006055", - "fees": "0.00000226", - "hex": "01000000000101768cf290f714c7858fb393f06ad86abd4589519edcaca50a873c5a8d83789dd301000000000000000002e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169add120000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a02483045022100cb25ac0d9e69ddaaedd49e3a3f9efb218b38bf49c2abf44ff2266bfb941bd3b202206b32cc1337f9a6a176fabadd6aefdf5a95d479e5db856d4e3e8eee7fefc26773012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" + "bc1q3230a7cqt2drewuza8qff4c4gpt4muy9qyqknw" + ], + "isAddress": true, + "value": "1699" + }], + "vout": [{ + "value": "375", + "n": 0, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "1098", + "n": 1, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", + "blockHeight": 622017, + "confirmations": 5371, + "blockTime": 1584485709, + "value": "1473", + "valueIn": "1699", + "fees": "226", + "hex": "01000000000101f8ae0d9757cba4e790483659fc55a2d7d943b57980bb84aa996d80cc90640a270100000000feffffff0277010000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a4a040000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220683d9c2b40958fd706623783017300ebbc9b73ce1db571963d9bb40679c3079c02207ee68976e225e1e98d20e66d4d8a498cddf3268d0d7b66827a2ed3ac4330f137012102b7f0cb54c2a6a4da3372fe17d7a07475f575777364633e89dacb39eb1fd5a09c00000000" } - ] - } + ] + } `); } return { error: "Not implemented" }; diff --git a/mock/ext-api-dyson/get/bitcoincash-api-address.js b/mock/ext-api-dyson/get/bitcoincash-api-address.js index 1b096b621..9534c9bba 100644 --- a/mock/ext-api-dyson/get/bitcoincash-api-address.js +++ b/mock/ext-api-dyson/get/bitcoincash-api-address.js @@ -1,1619 +1,1389 @@ /// Mock for external Bitcoincash API /// See: -/// curl "http://{bch rpc}/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" -/// curl "http://localhost:3000/bitcoincash-api/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" +/// curl "http://{bch rpc}/api/v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" +/// curl "http://localhost:3000/bitcoincash-api/v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" /// curl "http://localhost:8420/v1/bitcoincash/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" module.exports = { - path: '/bitcoincash-api/address/:address?', + path: '/bitcoincash-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 'bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme': return JSON.parse(` - { - "page": 1, - "totalPages": 11, - "itemsOnPage": 1000, - "addrStr": "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme", - "balance": "0", - "totalReceived": "125028.30507987", - "totalSent": "125028.30507987", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 10067, - "txs": [ - { - "txid": "0284cb9b8deb0534efa8fc8911db1e8f9b106d00608c712d31c3680f303fbf36", - "version": 2, - "locktime": 611622, - "vin": [ - { - "txid": "2f150ee63214982edbaf23c85629e920e16093d0506ed284ec3018ebe8746b12", - "vout": 0, - "sequence": 4294967294, - "n": 0, - "scriptSig": { - "hex": "47304402206f992d73dfa7e518b00190f220ad5dc7b7947b1d75a2fcd8251b59f3d29d89af022036c6c44f52f9aeed406dec72a9aab1f82c3b997c36742f4a3504e4f93e6f8557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50119473" - }, - { - "txid": "550ba873216e6690c8ca34992da41ecaa29e74a557943af604537de13fb84838", - "vout": 0, - "sequence": 4294967294, - "n": 1, - "scriptSig": { - "hex": "483045022100db30ebe47536e42115a507f88bb8d5c97b81ad05ce334872235811134c5948bb0220418d77aed78cc4a332b1858c1d2e9ab169828b9c12e8c0d0f8d155964e5d0b8e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50052374" - }, - { - "txid": "ed8d8d9810ca30cd0512a0e0ca87649713a550a015bb0022c16686c2ccb22143", - "vout": 0, - "sequence": 4294967294, - "n": 2, - "scriptSig": { - "hex": "483045022100d30c9fd598613586d8d0460fb6c9ffc1d0c6dff6f647535d2a9f69cf373193d102207fff687aa035910db124adad8b59607a72b3d24aca9096217ec6b90fa132a2ae412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50058021" - }, - { - "txid": "a2d79bacd53918c9ad6b27055eff555130f1af8522f77a09c4d74321dad8a032", - "vout": 0, - "sequence": 4294967294, - "n": 3, - "scriptSig": { - "hex": "47304402207b30e99cb1f6754d227a4511c5b7791f3b896724b170716d6ed238017f191bb102202c1fadc4c572c86288b002a0d6b6d2460a14a6d3c8b49efc17a03e59d2db18e3412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50022804" - }, - { - "txid": "9a0679dc735b7774ab3aa55a01188ce4d70613927b1b0ca9f96784b09479f762", - "vout": 1, - "sequence": 4294967294, - "n": 4, - "scriptSig": { - "hex": "48304502210092b7f176f182936323df8e4359b2a329b0c1e4b48a529d6e32867038a2a453cc02203c24a8bb46b7fea4ef5c78ff116a51fd0a04dee25bfcdffe856fb8988a7a97f64121035b4e75dda9fb0d55d856f54f24fc65da6657939b9559ab2c623c8ef325f14d8d" - }, - "addresses": [ - "bitcoincash:qzqn6xdqhaqa8yykvq4e94td4yg0k9ll9vyjf47x0f" - ], - "value": "0.01620505" - }, - { - "txid": "5d557c0c3331dc1dc4db34776603c01ce24ac8b0adf1f6fc2cc07a88baf5bf5c", - "vout": 0, - "sequence": 4294967294, - "n": 5, - "scriptSig": { - "hex": "47304402202a2bcfdaf12c398ed5372e6b168a786edb8972df1146b705d3cccf2d9601517d022020b90ac89d9141d68817850d1cdffaf6c51f45249a44fd6861b361a6025d8ac4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50096547" - }, - { - "txid": "61dbe706b513c1ee5aa577a07782471cf5c0c13fd7ce31b29cdd1c2362ea0bca", - "vout": 0, - "sequence": 4294967294, - "n": 6, - "scriptSig": { - "hex": "48304502210087ef2709b9fe8e7f136219254229edd45e94c3f6ebd2bb149aadd9b1d44d89e202206ffde3c9491c012832967e4d34e02ece2c08bc4c07967b3b466d4800f9ca0746412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50179897" - }, - { - "txid": "54b28d128142bb03aa60e9cf535fe30d5916089f1e70ac94444572008e9b3b84", - "vout": 0, - "sequence": 4294967294, - "n": 7, - "scriptSig": { - "hex": "483045022100c7dbd1117c57eedc8fc006e818371bfe6399c4d25e8b40482c1f0858a3d98a4b0220426d1196513a87fc7afb5b107b770a90af789536799a11686eab96b04afa6326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50044246" - }, - { - "txid": "750c2e638eb26bd271586fe201f48e21ef7fcef1154a6b6335d2bd4381450123", - "vout": 0, - "sequence": 4294967294, - "n": 8, - "scriptSig": { - "hex": "47304402203604fbb20824443899030d2c1f5cd0dc2b88174929861a708bdca878868e910c02200a607b1da53483bc95d3a5c54e5ad66e459827d4ecf8b4ef9909e9d58b2d329b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.5240491" - }, - { - "txid": "9b6dc387b59e4af25bfa14067e24c399fae3fbb744e97edb670087265ebcecf9", - "vout": 0, - "sequence": 4294967294, - "n": 9, - "scriptSig": { - "hex": "4730440220399c36174173cca01f6d6a234a935d6f776b549e1ea2fc2635193924c4ac2eb002205aea7741fafd95f862588c480aaa282d7a344d32d6318aec1a908cbb939e5d0e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.56320052" - }, - { - "txid": "8f27da29f81ae3ac3ab90f29cd4988d718cd351f965892b073a80b9a9492f49e", - "vout": 1, - "sequence": 4294967294, - "n": 10, - "scriptSig": { - "hex": "483045022100da9075310e7af59456423be99362f2cc686d50571e0f0b016bcfae1f0bc4692802203379b648d47704dba48542b8b6d5e515bf3c4fd7ff8a7be82cd0c8c0c7be56f7412103a344a84dc1a919a64874605fae200861b7af3ecd02dc5d52dd00eb6f8845525a" - }, - "addresses": [ - "bitcoincash:qz8mkaldpk8zk2ge27wpn8ue0uwu28xq5552u5c5my" - ], - "value": "0.01687043" - }, - { - "txid": "109bf48f720a9d05fd7a74b632164ed96db721b00458420595d799b437305f5c", - "vout": 0, - "sequence": 4294967294, - "n": 11, - "scriptSig": { - "hex": "47304402206cbf93634d6a477a571fa2884c19918b19ddfb008ff9fe405954720047efdb88022003e755313436d406dddfe3cfb68719e8f39e43de7c586489cc543dac0347da9f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.51895732" - }, - { - "txid": "d3e570366f647db1f73079b743ec994169875c7af42ff2e9f3cf290fcb3f180b", - "vout": 0, - "sequence": 4294967294, - "n": 12, - "scriptSig": { - "hex": "483045022100f23d4cf11fd0a5ab83dc053ca64066cbdd2fb4107e0977a3a880c68a67636f7d0220220a47c66d3944cfc309c059fe8013c4de742e4d8590003fd56c5e0b3c7da557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50081823" - }, - { - "txid": "6f05f99a402127463db6dc2f8f6b1064109fbfb93bacb258babd2aa861055480", - "vout": 0, - "sequence": 4294967294, - "n": 13, - "scriptSig": { - "hex": "4830450221009f522beef55cbf8c7f10e88739846f78ef1c9d9cbc6959dba6f687a08fec0ef502203a160231733b87c6cfd8afd148994c9b6c5d5db9bb9847aa9e60938a6e79d5b1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50020672" - }, - { - "txid": "3d93b717b0676245a3dc3fb86625d9abffac4f66e2889a81a07733a14e1e4a4a", - "vout": 0, - "sequence": 4294967294, - "n": 14, - "scriptSig": { - "hex": "47304402201f5d29be80192a752fe28ff141ed702640df88083faf3f9573e52405cb4bd79a02202d751649aa600c4fdb8b1d1b21f0d134c2f4e5af9ecbe7d87180d667140f0a11412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50118486" - }, - { - "txid": "c77ac92e646677bf9e59873c5f5036831d5d5597cda469b7e6b30a9563a3419b", - "vout": 0, - "sequence": 4294967294, - "n": 15, - "scriptSig": { - "hex": "47304402203f4bea3816d252cb19d4247f587a146901c74d04e783efddfd5089942f2abcdb022069012613c4ee4b3b0212ae71dbd2071e01665148697011eb03eba25431e679cf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50097156" - }, - { - "txid": "90cba3db7e020c7b8943293ecca7f6a2150082a372972c0ed65646337b0b05ab", - "vout": 0, - "sequence": 4294967294, - "n": 16, - "scriptSig": { - "hex": "4730440220782ba77287116d5d735f67a3738fbecc1a802d2141a1fa544f61a5e8ba682a4402205473d68019cc8895ecb1d87bfced62ddb6dc48b81152f2684ae8530122d5b41f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.5017515" - }, - { - "txid": "e25ec382049a4d8edd530469e5e41d9e056a2081b661f505414b1348e482dd26", - "vout": 1, - "sequence": 4294967294, - "n": 17, - "scriptSig": { - "hex": "473044022044ed9bfa8674d7e83112fa22280797169d45bd971b185da2413e36252637529d0220531eefc480e0911d6ccda42002942883149bc1cdd1f3bbde313751d80bcf98b641210328ac4ed2b30ddc04c778a78b24e7256b08c55758c1465defd997ff4bcefacf10" - }, - "addresses": [ - "bitcoincash:qqnfldeu0yd4wd89c44sujdz2w7hwvvd3y8g9tuech" - ], - "value": "0.01884419" - }, - { - "txid": "13a148dff09d7786a7e0d0929e7ece3c9fb8de532597cbb0d045f5ec531b2e9e", - "vout": 0, - "sequence": 4294967294, - "n": 18, - "scriptSig": { - "hex": "4830450221008cfdfd352e268dba2022e7fbfc37a90401c40fdf6f1d8ba9dcb97d67743eddc302202c0a1b604d34aa174fddef63c9115c95465548855c5f783bb206eb4ff8fda235412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.5002857" - }, - { - "txid": "700dfcfa0847678c56a084b5a75fb8aef1b1a1126512b026ebdb8c45d55efdf9", - "vout": 0, - "sequence": 4294967294, - "n": 19, - "scriptSig": { - "hex": "473044022001b33b610b8d742df2ad98679f1e41f0c647faf272e15e7ea93171ba29c33bcd022061646fbcb81ba30d6e8b030ee12101d1f1bef38ba44a6d5daf40c4ff6d644e6e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50039508" - }, - { - "txid": "6810932357166daa33c2125cf38be6076f7b6f718f199348905459f22ba7f2a6", - "vout": 0, - "sequence": 4294967294, - "n": 20, - "scriptSig": { - "hex": "483045022100ec9b6bbaba90d8902ec8a1ca0e90ea594264bc1add204b756cc89def4d7e9a2a022066b2bc84f94e1a99effe0e929be8de8669631143ca20c73e700d182ad4884e71412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50136993" - }, - { - "txid": "42a98564873f7c888a6a569cb97066b4bc43c5fa41d732573774f996b91980b3", - "vout": 0, - "sequence": 4294967294, - "n": 21, - "scriptSig": { - "hex": "473044022057117591cc465c48da58ebcb8f57fcd56359757d41e1397e45b5e33e034ea5d8022001de1d78ce9e8e73370a0778b4a8595045c6faeb2497ab4296d0cff735711276412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.5005352" - }, - { - "txid": "f7b56e95b5a48a66649fd3e9e9bc94a7a01bd1c4822c4dcc2c40243c8da60bbd", - "vout": 0, - "sequence": 4294967294, - "n": 22, - "scriptSig": { - "hex": "483045022100dace56650d1d9edaef30e8c9ecb4b78499a573984c8a451253295a90c84a3ed702201f4587d4a760cd77a2e21d5f6f2b7aacf668220c8c7c62fc1ae4779f7c0141cd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50111141" - }, - { - "txid": "d58b912c125283ee0249b670a7901bd5a1061d92f7c06627b5e963fb0b2c3d14", - "vout": 0, - "sequence": 4294967294, - "n": 23, - "scriptSig": { - "hex": "47304402200db6b461a0082807f59053bea210d38f5f82f02dd63a57f6e3987339cac23870022064ba927fc11b36318785d4e861a7f94cb3909ef8fe882360e2041f7b4a444692412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50143132" - }, - { - "txid": "530326ce09e8f933a604488e5e2f06845c3e805761c02eced5cc02856be1b7b0", - "vout": 0, - "sequence": 4294967294, - "n": 24, - "scriptSig": { - "hex": "483045022100a3e75a6c7918db32a27be348493b831631856ec8f546ca43d143cdc3c1cd03c802201e6ae036423bfce45c500b0c049f68396deae5cb999038de61e972ccd4cba5e7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50022822" - }, - { - "txid": "ca51412ad37c5e5a49b11dc7858b4013ff68288c56e6026b11a4266e184b286d", - "vout": 0, - "sequence": 4294967294, - "n": 25, - "scriptSig": { - "hex": "483045022100caf952ca1760052cfefe8df283fdd0eccb9e1238eea88eef287df9404c622e8b022072027363fa1070548576fbf9bcbddf2e435fd020662b2d8f0582b52bfa487b31412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50033136" - }, - { - "txid": "c03e268bbb105f171305f7fd994c0e15fbff5ae3d08f3c332c48cacca66bbb38", - "vout": 0, - "sequence": 4294967294, - "n": 26, - "scriptSig": { - "hex": "47304402201a4b4efff2b70a4039b4dc120141da04ae84f63906df10c3cad08838c01b6b8702205a065d025c338547ea07b2095ad31252658e57f1a7a04c7f4eacc0248e611fa2412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50037356" - }, - { - "txid": "46c8b9fca6423412b3d40cf7606b79678807d75b2be1e848765c40f367b326a3", - "vout": 0, - "sequence": 4294967294, - "n": 27, - "scriptSig": { - "hex": "47304402206b0a876d78793710acaa8bbeb58a2d908bd4936f2a88825f944b190041b5e0be0220279560be5009e4a3fab44d08f4748e2dead710a8ccc77e06a03ba8112d728856412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50061192" - }, - { - "txid": "fadc6b6f3225ea8686c7a03cd8362765f91e604c260beaf965c4e7093fb16b74", - "vout": 0, - "sequence": 4294967294, - "n": 28, - "scriptSig": { - "hex": "4730440220799bdb7ac60cdf3314cc1f157299858d353e22c00354707337ab5b497619d626022000e41053afe44fa65227b7dd8498300a2dc89367d9daf0586caba5bffdfde567412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50118669" - }, - { - "txid": "adb5163c2bd4b1c35c1eac2671e6124e6c6b9b6c3e2abdc8372601528600a98d", - "vout": 0, - "sequence": 4294967294, - "n": 29, - "scriptSig": { - "hex": "483045022100a1af33a83edb7fdc289a48a4f77cf286a88b38c21ddf27dd4ec3df007ce11046022074dd56730730f958039efd70edfe7e181060fec306c6df4cf75209600ebebed7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50075561" - }, - { - "txid": "db1a00011dcc02708d6757b7435a3163d4dc384d8490208656229b0780b4a184", - "vout": 0, - "sequence": 4294967294, - "n": 30, - "scriptSig": { - "hex": "483045022100eff445419ec63d1e9f51a5324c3be0315911b39f30657639e84ea7d2f739e0510220218e73140a39542ec8055b6645cbb7989f96b9d9a93c67549c059509de06f0ba412103dd71b53aaa823b09a68aba30c7603c6a397e7c183f708c9dfb0d9d0a9cd1c722" - }, - "addresses": [ - "bitcoincash:qzduecze3gvxk6y7rcjmvnau8c3ncddvvvs05z5gz6" - ], - "value": "0.01400587" - }, - { - "txid": "df69893e75d4acee084666c023822f07196dcae429a07b136fe92a87262f87f8", - "vout": 0, - "sequence": 4294967294, - "n": 31, - "scriptSig": { - "hex": "473044022050b7ed06a6832b8831c08ba86049b3793b5a71fd6d5177c9f268b79c3074bca7022047447c23429de30c361875642d9058bf1b5e0e6c5516d6e71b70b7cfb29827aa412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50118543" - }, - { - "txid": "8432efebc29ead31beb783d5d27cc379fa31cee352cc19a75746768b2fbfbe7e", - "vout": 0, - "sequence": 4294967294, - "n": 32, - "scriptSig": { - "hex": "483045022100fb072bfd399dc11191ac449a9d60119bd191ce6b19a5d92412a805ddc8d4b46f022021e463686560b15ddf272b9943d8e41425ed500f77698aba518ccf546a97aeb4412103e35c58a738805f53af73472ffb671a9bd3556ddef47c62f18ced868bb5033d0d" - }, - "addresses": [ - "bitcoincash:qqfs2vp95prfunn2r9wh5lf2g6k7k6jjr5qld8a37e" - ], - "value": "0.01772743" - }, - { - "txid": "29ff4caeaa127c04ecc8141f49462390a13febd47877abda62a7ebb66658f0ba", - "vout": 0, - "sequence": 4294967294, - "n": 33, - "scriptSig": { - "hex": "483045022100b25e7d4ebaa0e7d8e24498b039e756d568b67316aa14d05abafaec59e216a73d0220010d0b6548a74435907eb0d548dfe8e52a949bbb785eb2be3bce14053953784f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50075582" - }, - { - "txid": "3b46f445ddc1b8acd4fa933fb8d7dba9bd95ce53a579339b32a1e97352323013", - "vout": 0, - "sequence": 4294967294, - "n": 34, - "scriptSig": { - "hex": "473044022007d2baa9a766c120e111a727bfa8e8bc2e01cc285d4d4f67d2323b213525a10c022020f32be2d9935b6d9b5091db27ebf00aaeb54adc7032badc7ad63f20741ff28a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50043307" - }, - { - "txid": "1bd4b1e18be85528e214e16c69f459272ec126ff0dfd1948de6838b5b50e5344", - "vout": 0, - "sequence": 4294967294, - "n": 35, - "scriptSig": { - "hex": "483045022100f98ee28ffb66acd04474a120904ec1be2327d727d8ed8fe99d8b95c174b8f46a022041d21406dd8df10cecc1d6435de68fef3f9db71838c1ca2910895bb184b4a6e4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.51821842" - }, - { - "txid": "067492a2b7fe0787a44ceba7d6ee64da25aa8be08357576e4cef97ef76babf2f", - "vout": 0, - "sequence": 4294967294, - "n": 36, - "scriptSig": { - "hex": "483045022100ee3f7961f0f23137d753affe85b777e94c1db3f656cf41b8f59fcf82d9226eb7022025009482a6c0002e409590075caf7a78023ebc1457f100c8b922a4974ebf86ba412103f1d1dd7685d3781f58f9aa399a16f6bb9ccc7d008cdb7c63a7945cfcaa6ba0e2" - }, - "addresses": [ - "bitcoincash:qr99zjexsl5dtdu38wu8w7jdmsmcxtcr9qw64zjhdk" - ], - "value": "0.01843864" - }, - { - "txid": "bcc168ae5cc9dd70fabab262712036bacea7250db404c0d5af438b0b085c52bf", - "vout": 0, - "sequence": 4294967294, - "n": 37, - "scriptSig": { - "hex": "47304402201fed9da4c0526ac5ce257fce2b7fc995646b5f0d2961396327f93e2dfda3e4a0022035b217adc5a9be2ca34f4361ceafd9f2d09a6fa47d4a767f7001ade40c08fe26412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50034365" - }, - { - "txid": "025d365f0471a48171c3f50ba4e9ee04ee74f72c2e8d0cddca600f3a900b7b32", - "vout": 0, - "sequence": 4294967294, - "n": 38, - "scriptSig": { - "hex": "483045022100fa8ee82d42f524290319fb3ee47a1afa70cb952f8a37325680d6fd651ac3699f02205ac0cd86fece03ca204bd881d67ccce0cccbbc98704d9e955e2f92b5b77121dd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50085848" - }, - { - "txid": "c61c8a5fd411f160bac0e4b4e703e1caf7d3f8218b0ca5f2aa7b762bb9d3ad5f", - "vout": 0, - "sequence": 4294967294, - "n": 39, - "scriptSig": { - "hex": "483045022100f3cb343c4704bebbc78c6492dd72ca19c388b285f44f574dcff25f993add6d5f02200e050dacd78de955cf552f9158beaac5fa64995f5bf7c8a919a231a39425730c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50086233" - }, - { - "txid": "207dd74726483c593b21c180a9467166af7f5b02450fd3613268cea239aed047", - "vout": 0, - "sequence": 4294967294, - "n": 40, - "scriptSig": { - "hex": "47304402203f05a035f5d42fbfe97172b431a613110ad733e356ebfd08886fa11bedaf1faf022061c4a3bc3417390910612bae46f5acf8b6e8a5b008d273a52e483a315bfb950b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50080933" - }, - { - "txid": "facaafec82e7853c85dca5fcecad9c62d830a2421c98e8c5896b793966face46", - "vout": 0, - "sequence": 4294967294, - "n": 41, - "scriptSig": { - "hex": "483045022100bf60fbd4716339bbb42ce150966ad6caf90b14e57f45eb6804756cf8ff36b23a02202f16aaecdb9994f3b683cc7fab45bd0a3f54795c336b5fc224fc51270a7f3f4f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50075132" - }, - { - "txid": "26703badea466dcf8446e1ee49868ed4259ff22e0f13460db9d79819115b5c4e", - "vout": 0, - "sequence": 4294967294, - "n": 42, - "scriptSig": { - "hex": "483045022100bcdcae99c9289b5fc89d3227daaea8df7d0a0f3a8971d841ebe1ab7a1ecf72e202202ca21447a6b3e96540e32529697d523b7b08c65845d6a13f6b1475de94919bb6412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.501188" - }, - { - "txid": "c94103172a643e1ae22c3955749bf7af337a914a48d124fb5cbaae1ab5fa9e48", - "vout": 1, - "sequence": 4294967294, - "n": 43, - "scriptSig": { - "hex": "4830450221009535c27b5bbca0db2bcf1a0d0b3b283a2171df53f0d68f1a138888fcc6ddd996022068af19252ac4376cffdbfaacb2e0f0c216deb7e2478b586abe7c2679501eac34412103a47e5dea4ab8d785f4e00994d0faf1a8f384c41e74ed8e4b776fa6ce136ebc42" - }, - "addresses": [ - "bitcoincash:qzfvx98n9r4yzlvk2h736rn3qftpl2uttuu76kvt5x" - ], - "value": "0.0163143" - }, - { - "txid": "180544709d0cc711566118b48af548a7b199c639185685c7228676725c28ee7e", - "vout": 0, - "sequence": 4294967294, - "n": 44, - "scriptSig": { - "hex": "483045022100b456847e29f8a648730f0fd34cc7edcfb35daba866ab7d800472beaf2836ce4202207db401f0a5e30efc53c7bf58e57d1dec5874d64768ad9eb4895351cc4be9226f412102291b40a9a927dafeb53cdfc7e722ee5c9dfd6eac2d81331678b9ab405bb25d21" - }, - "addresses": [ - "bitcoincash:qrrv55s5ag0dduyjsc83ds7hstqc0m9htqk764mtaq" - ], - "value": "0.01078385" - }, - { - "txid": "67c24b19a0f444541bcbcb15e708f7713f5168f89f3d42df51d1909f6e22b093", - "vout": 0, - "sequence": 4294967294, - "n": 45, - "scriptSig": { - "hex": "47304402205ff244c77726def0e3697a3e546bdf74c7f31479c9d01a7a6f8cd1656482d537022045d78dba8ed4d3777f473736daedbdaca6f5698dd306898d144eb43f96259766412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50191671" - }, - { - "txid": "208d4a8a6afa218a65416286733a5158e7ca393003e30f88dec606e771e384c7", - "vout": 0, - "sequence": 4294967294, - "n": 46, - "scriptSig": { - "hex": "483045022100ec6b35ce6d24889726480d70a31bc0d62800bf7ac49ecf084b98137322606bca0220432d33e2d8b508f26d7d813d18629453c537a4d90f73a104bbf80627f9fe8d62412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50036468" - }, - { - "txid": "60a7eef8d0b9e7cbfe602bedebd75a80121587af1236fcb8ddf00e510cb4caa4", - "vout": 0, - "sequence": 4294967294, - "n": 47, - "scriptSig": { - "hex": "4730440220423ea635717cff512d9262b7c8932c0122ca868251f019ae033101c28771a52302200cd3ae05f2e88d9f64207beb4b715ba480bde9ffdd40ab61a36feff88f2968d54121035530745f3cd4d31532991e460bd2a15e1944e690643f73133a9918edb95da53e" - }, - "addresses": [ - "bitcoincash:qq788skgg7eqc7unt733wahchmx08h87tgn20l2n3l" - ], - "value": "0.01329593" - }, - { - "txid": "7033ed9dcbb1af754c41046bf1ec51c16285336abc235b9485dd9c8829f32b85", - "vout": 0, - "sequence": 4294967294, - "n": 48, - "scriptSig": { - "hex": "473044022055cc4dfa48a79b8584a9352be34ab5fe9cae4132d264dd827d14ae06d35ad4090220652a83c93505f8a8527c5bc0479f37da0593595c1bf18c12b8fa0b41a2e37a64412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50053803" - }, - { - "txid": "929f05541924a6eb7dc7f2e11310037de210718c5896b9d9475ca5724dc13532", - "vout": 0, - "sequence": 4294967294, - "n": 49, - "scriptSig": { - "hex": "4830450221009acc8d0e06d10b0c764a27613bcef41fc75f910875eae3989a7f8725f81814cd02207146ff66f412910ed993fbda4ad6ed48862a02f366dd88a83856a17e7f96d83e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.5017106" - }, - { - "txid": "a7e965c2d147a2bcc7d99f61bada49696703563d7b8225c9e69c29e312aab0a0", - "vout": 0, - "sequence": 4294967294, - "n": 50, - "scriptSig": { - "hex": "47304402202d8cd72290f04063c0ae9bc06d2cae3ac74ef4cb6945c92c3e3ccca210c127ef022030471726cd87ac9d55f3d246095f64ae22b611aa8791922236bbdb19ec273322412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.500305" - }, - { - "txid": "e6897dfc8254d449f61372cb7c4131c4caaf2781fa60cf930a36421d0bc156c8", - "vout": 1, - "sequence": 4294967294, - "n": 51, - "scriptSig": { - "hex": "483045022100ffaa954e5b86d54ece9bcb9e37895047221828ca381b03266de3d9341599c8f902200ea1c5ed36e893df822c698a474b062d4f93005c32f9d2f0d78ecaf5a56e4fbd4121031a00f43cd99e015c72acace20ac47d887a39ef284f89a5aa09abd968d06f5e9d" - }, - "addresses": [ - "bitcoincash:qq64kqwmv0gu5naq8ztaj5ecef3042n3pceymy9fw2" - ], - "value": "0.01746309" - }, - { - "txid": "d69c6ead378471a3f30a9a7b10381a88bd8c5e343b8108a0f189f9f665901269", - "vout": 1, - "sequence": 4294967294, - "n": 52, - "scriptSig": { - "hex": "4730440220457d59caf24eb6e10664d06f3e936f6ee31d9d59f1cc4f6f62788f022bce8c1b02202ce7c37ae6832b078c1cb9a055e3ffcf4674081f0738fd9c3eb4465b52bcc9ca412102fea9ae922223f2c68c68d7672b7656885c3e1321d35cc8f5f445179df6f7d27a" - }, - "addresses": [ - "bitcoincash:qzudxte3pz9qf5gmnpr5yxj97kv3flcs2gv5mct8gm" - ], - "value": "0.01792586" - }, - { - "txid": "212aa8288a75640e62292417bf53dad20d242df7579c38fa10f2f63d8c03d38a", - "vout": 0, - "sequence": 4294967294, - "n": 53, - "scriptSig": { - "hex": "47304402205e0f5cb06f7fd741825c669c87e9db1a433913fb8577adb92b779d3a693b4f080220120648a5f9d2abae83a29cd2c79f5c61b9bc40da8990736ab97ccf6f82c586cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50046573" - }, - { - "txid": "3d6a1aebc3f48b843e408421c9f421d3934670d86a3f5df49a6530152056da4f", - "vout": 0, - "sequence": 4294967294, - "n": 54, - "scriptSig": { - "hex": "483045022100debfb215f94e9d784e91fe0b9d2541d09a4c7591172fad1441506db4a3590fd102200cce728e344933111c9548162e62872fccac624f6f98d92ccdcf98dbed09ac544121039b8a20c23f32f5b14e76fb29e0baade695810aa7b6dac9e9638a8d13b6ad8221" - }, - "addresses": [ - "bitcoincash:qrt6ljgpzzmamr2ukg9a3jxe46ufaa8fr5yp6f9pfy" - ], - "value": "0.01801618" - }, - { - "txid": "91585d5312b1a4c8bca993b6db304a65c7bda601113960cccc978f28c381bfe7", - "vout": 0, - "sequence": 4294967294, - "n": 55, - "scriptSig": { - "hex": "4830450221008110aec39b127143891069590fa0d9e1d8b41bdda70d9807848eba92cb48736b02201bcfdc1a1cedfa4c53efd941482f6157774b2aa80af44e500263be6a3cbcbacb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50046545" - }, - { - "txid": "b9b3d23c90954095289ff5feff55de3cbd7469cbb179e38aa74dc813fd6b684c", - "vout": 0, - "sequence": 4294967294, - "n": 56, - "scriptSig": { - "hex": "4830450221009f76d6838b8fd8bb74f50c67920fda9f28054d093b30fd03b54b3fb888db046f0220307944f3abec07c3570614f418056aeff03c0830173c963bb0b65bd5ef24b4a9412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50022645" - }, - { - "txid": "65f9a63b7bf753423cca4a5ec229f566e61cd1ec8f745683da2a934b1308713f", - "vout": 1, - "sequence": 4294967294, - "n": 57, - "scriptSig": { - "hex": "47304402207b93e2500b189b51fbc3a49a191c4b92ac76e32ce86f6f1b9af4afbb3a91fbe002200b5617cf52095bf882a5129f5477f119c9c565dd582a9f19493cf1bdae6527ac41210323ab0930ba40688e66bef6e08f673bd6bcd3df687e4c503387f48c24bffdc93d" - }, - "addresses": [ - "bitcoincash:qz86ljat9dnhjp2wplpm7ncfm7q69hk58svu9g46ex" - ], - "value": "0.01593178" - }, - { - "txid": "48ddbf6a4cc52b15bb4d2cb7e39fcecae29483bcd3d6471e3543785621f3df7e", - "vout": 0, - "sequence": 4294967294, - "n": 58, - "scriptSig": { - "hex": "4730440220731ab37e71d9c6f63333ba205a318d36e5847706381f571b4b562e5e6f6e403c02200704ca9d9a33843d9a16135f56eced1fd18e227385671a8df5fa41e505e3ba3c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50019587" - }, - { - "txid": "5027ac365cb55b21278f32710703d9ad932912919c58de364e1eb1e9d79412f7", - "vout": 0, - "sequence": 4294967294, - "n": 59, - "scriptSig": { - "hex": "483045022100d1d3565175e1f529124ebba1bcdf8c1704e753c2f91ddcd1a093b5f5403cd0ed02207420ee9d6082356cba6d8075b4fbf310bd84dc770734a8ab30e74741a779bae8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50045268" - }, - { - "txid": "93cc92162ee854259d3b3f9ad1886847eadb2ccc86d03bcc6b89718da9ca23f4", - "vout": 0, - "sequence": 4294967294, - "n": 60, - "scriptSig": { - "hex": "47304402203ddf5c6c5065f03229cdf837d9f8d3d22314834b006e0aba8dacabea206b3b150220417c49c9095372d3dfd954688bcd43fdfd2a121989fde18456a9428b2a8e3c63412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50086952" - }, - { - "txid": "c672af6e97eeecc79e87e708d57e20e2c7d811bf3431eaa928f7efc24b663dce", - "vout": 0, - "sequence": 4294967294, - "n": 61, - "scriptSig": { - "hex": "483045022100a20e6aaca7df2b142b768d3b1cbf8f783f3d4997d155a32f0e066b4255777c9f02206deb15cf53d6b27a973df9aa7080691e5914538d9e97ec7c6e797ce03333238b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50143426" - }, - { - "txid": "5f64a0a07336a2bad8f9611709653146fad9fc796f1e92dbd12afbf0d6dcf5b8", - "vout": 0, - "sequence": 4294967294, - "n": 62, - "scriptSig": { - "hex": "483045022100cc2cf5c6c2d4862dfdf65407138684ba45565bd8ec46594ed4586bfa37b715dd022013255b2eb22f5bb93d2afdd07ec4c3b5efe0aa16134b2fd084c6bc720f8cfd5c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50125454" - }, - { - "txid": "256b18d5861752fb617796cef5ceba05e42de141e48aa2737c77020e8d1f337c", - "vout": 0, - "sequence": 4294967294, - "n": 63, - "scriptSig": { - "hex": "47304402202c9dd98c9a72e5a8df4b01f09d18e2826d8b9871db89c5d3b24ffd673facaa0702207523bfcf3ab80790167a2b1159fe268770371fcc7d770995c19eace3181ec8af412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50058048" - }, - { - "txid": "aeda3cb9ccecf67cabaae458862b2068129297b1b502b862067f578a2201d54c", - "vout": 0, - "sequence": 4294967294, - "n": 64, - "scriptSig": { - "hex": "483045022100bfac8828df10b7911d341c15a532819c429c7185d8883de19de84e71b97d78730220177603a3572908c90dad865770906b5ad228da7ee5da39503ececf60ac735158412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50083898" - }, - { - "txid": "0b11e279a95eaf9241bd55fd7f7b045e2ff047b307b25f3885feb6a71140d6db", - "vout": 0, - "sequence": 4294967294, - "n": 65, - "scriptSig": { - "hex": "483045022100d598e2ccdeecfdfea9d5139a49a94fa39414f9e1ecb13d54efeb34c168e58aec02202a59463710905613844f48dc71d316c0cae54ab9e16dd95beb8902e5940024ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50050928" - }, - { - "txid": "82026eabe17877d3aae729eee2612778389a9246d56b8032706c454223760eb9", - "vout": 0, - "sequence": 4294967294, - "n": 66, - "scriptSig": { - "hex": "4830450221008302d38e9eaccaea812c853047931562417a3665b8b9373cf7f63e58180b002602207ac8fddbbd19560a74333ec92fa077d169b4902a41e0431113f8fdb75b304ecf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.5003979" - }, - { - "txid": "43a94c82abb414437ac13038fa5840a6038733dc156bf160cf30db31a82355e1", - "vout": 0, - "sequence": 4294967294, - "n": 67, - "scriptSig": { - "hex": "483045022100c0d85a1f9146e8ef9efaef8ed9b3ed09c55e51b25e189735610da89b6d212360022003a49114e504741befcdb95d52a3dedd1aadef68b7c48f0a4a8c7dddfb4201b5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.5010516" - }, - { - "txid": "41f835819365a32c2ce1138c131a4039c6dfeb034d922af573d997697b409378", - "vout": 0, - "sequence": 4294967294, - "n": 68, - "scriptSig": { - "hex": "48304502210091ec8402cafd1e7eb11b56ac56a994ac79c435893108d0b7c8cfff87c07ba0a602204fd98efddc1b4e21bd3cb81217579a7b9621f9c3c204f2f5800e75ce1c60b19c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50127067" - }, - { - "txid": "2f8ca9dea380bd026636e2281f1e42e63dd54a04be1c1526574994450ca36f01", - "vout": 0, - "sequence": 4294967294, - "n": 69, - "scriptSig": { - "hex": "483045022100a850bf088a08baac1f1f577da8946befe2e6b0354d6a29f636afd39982569a7e022062652d6b75dee145f741d28d6f1870fde9a7d66b994f0d3162abdc42fbf54458412103ffdeec10b52942b0c46d6578998efdc1d64073de579e92e7c5dfa97fdf3ac391" - }, - "addresses": [ - "bitcoincash:qzzkjplzf0yw2xej4u9he5pr5evgup2snqqxs823e8" - ], - "value": "0.01366913" - }, - { - "txid": "404829243c500005d37a95164bf6610005ccfa19cb7660ac9c1ee0da009465d8", - "vout": 1, - "sequence": 4294967294, - "n": 70, - "scriptSig": { - "hex": "4730440220762f7c017672dfc71d487f3730e26d69d0e53902f579ba348095ca164d27b094022076c7e8045ec9fc57af6dd95f35c0ffad2c0ca8f83f112f60fb9851ba4ba15d92412103a2d2d8251728b11fd4afe7b8c73a8442f76dff9bfa424f5cad9b98083936259d" - }, - "addresses": [ - "bitcoincash:qq4kx2926zmnhfa36xzfswf9p9raqlapmysqvr4ck6" - ], - "value": "0.0129234" - }, - { - "txid": "2624cad28a9b7f55434b68fc8be7aadb87d40003d786f0e414cc1eff74a12b64", - "vout": 0, - "sequence": 4294967294, - "n": 71, - "scriptSig": { - "hex": "47304402200654032c5760f8b94cc089da51773447f19c1cd2108cab89bb53ccfdb6dbee56022015e277622dea4bd1a7913ff934b2bb2d1b3d75f05285b51690160e1197a258c5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50134907" - }, - { - "txid": "893b3cfda77c1371e21df17e45910578fd778958f9b51fcebb24a2e92c604d65", - "vout": 0, - "sequence": 4294967294, - "n": 72, - "scriptSig": { - "hex": "4730440220712877c0dc553096eb0ebf101d1555fda5235db26ad074d2f330163fab63fc7802202c89752dd7645e8a3da7e8af5fb68dc8b177700766b79cf6a35695a0c7c873cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.5003304" - }, - { - "txid": "cd86f3aba8b0553de0041a2173507a34f595a3785dbaeb8c9b2cc1c1c34c61cc", - "vout": 0, - "sequence": 4294967294, - "n": 73, - "scriptSig": { - "hex": "483045022100f3fa1e305666e2a62afaa11fd37025b25c0bdff8709fe1580406615934228cee02204841a7d96f36d3c183f06e22a58175756c3e9a76c93c7cb4e9945f31ddedc902412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50105407" - }, - { - "txid": "ae8ae862b5ddba89e69b42aa8a6ea2693e61f90ad3a5625b5f81605c7aedb226", - "vout": 0, - "sequence": 4294967294, - "n": 74, - "scriptSig": { - "hex": "473044022047c158e3fe3f40de3f39796dcecb7df3cf344f14009de9826b62a43837f2cdcb0220759d823cc145fd5e8b651a7bcc399544692bbf596189b1fc50bba5f4ca02cdd1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.54457185" - }, - { - "txid": "b402b3d23c910e0ed869045671269210f6594f308b6b01a0bed2052f6012b0eb", - "vout": 0, - "sequence": 4294967294, - "n": 75, - "scriptSig": { - "hex": "483045022100bd70744c867943bc3bf578e192c8a87a5ed5126aac4acd98efa06ea2483911fa02207377e11ae2d2bbaab00da86ec73c26e596bfcc680c0b8eddc5d44bda650bc299412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50101109" - }, - { - "txid": "e1deda4073c863ba018bd7334f625f79884854006f27712cd010e57bf59c8087", - "vout": 0, - "sequence": 4294967294, - "n": 76, - "scriptSig": { - "hex": "473044022059ee25066b8a2a4fdfc35f14c5cbb7f22ab181fcfa9702d4f3de7aa4d738c7a402206dff315ad1cd2222cd6ac074bf34241fc22db38a57bf089f7e24542323f1766c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50083658" - }, - { - "txid": "219c39d91c3d5d3d1f81c83ba373df7ccaecb45f5e4a2f7422bb2021afb7338c", - "vout": 0, - "sequence": 4294967294, - "n": 77, - "scriptSig": { - "hex": "473044022039657cdf4fcd5a9e81766ba11db495b8be5664612d3b91f8504bea342c4ecbe702206ca4913e5807cd697d30dbc93e0a9d679eb01ee84b687ab0c642e2f3ebde745b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50032757" - }, - { - "txid": "3a1f594a74bad6de4c762a78a6c06db3900c45408ec0f785c61bf9f29bc34281", - "vout": 0, - "sequence": 4294967294, - "n": 78, - "scriptSig": { - "hex": "47304402200232ee94873317eae275cf715f4c3aca25dd0c8db4800946a45cc1d9c45732fa02203d9ce9c9aedc0a3899dd027df32e683438769d66f33ffe52006454614b77821d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.53061599" - }, - { - "txid": "14cf83e6c8b80366b8651c6b4a0f7d2270290066325d686ba671ab5c4c9a3b50", - "vout": 0, - "sequence": 4294967294, - "n": 79, - "scriptSig": { - "hex": "483045022100900bdc6f705efa56449a65f15a67fc7fbbc102f78e7974ea6ac2849c75d2dfec02203b78de71dad2e3f6ffad2779cb9007217c957c8f5db7abd58fd0537fbabb8c6b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50121784" - }, - { - "txid": "1dd1ec6c4b4ec9bf13aec933506376c77e63254d5573c2584d7515554f14ed8b", - "vout": 0, - "sequence": 4294967294, - "n": 80, - "scriptSig": { - "hex": "483045022100becbb21c7937b9b27ea3cdac5f2048ab9ac314de59c3ee2926a5cfb258ce14e902201c8022bf275c1a761e7715b14e15d74526901363ae5f8bf5489d00908dd758eb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50044721" - }, - { - "txid": "9957066f6fe221a9423b0f54ce1188000e1e9f7bf9085527d9e1edb31d88b7bc", - "vout": 0, - "sequence": 4294967294, - "n": 81, - "scriptSig": { - "hex": "483045022100ad84bcd69a85a0d487fd7cbe4d76b95bffa303e76615a4336419fd182eeae4b902206d21e4f592297e87f1af9e19c80fd978914aaf5a2db2cf499b72cabbbe73c831412102958762ff6c8985dc9656afda59e61afc6c0131a5d8f1d86c87c83c9b37f7bd18" - }, - "addresses": [ - "bitcoincash:qp7zwhgnhhuh4j8644mqg7y3fqejm2jkfvkt6qp4pp" - ], - "value": "0.018763" - }, - { - "txid": "ca467662c89f207dbfc6ec016e126693a204f17d6151987aa748838852aeffb7", - "vout": 0, - "sequence": 4294967294, - "n": 82, - "scriptSig": { - "hex": "483045022100edfd64cf9335d094d5873deb38cda5f4ceda3351df722f1c718993a2dd12c8e302203126b0f9470a4d0867ed4e773518b8ad689ce43a2c9f65a1f297525fc22201dc412103f37089783028c0776f2b8a9d8481ec8d6d0652a31edc03cc274032ae17c63c62" - }, - "addresses": [ - "bitcoincash:qq7fvpnuflq4cq6wc5t4qjuzj8l59puq75h022fyxs" - ], - "value": "0.01114817" - }, - { - "txid": "54fde006c8dbb7a3de68e0609d057a3f2337c99ee2ae70cc715d72f5dc881a80", - "vout": 0, - "sequence": 4294967294, - "n": 83, - "scriptSig": { - "hex": "4730440220448751a749e7cccacab0ae1ad4da948b0e0b5d8e3f41ac2b22c18928e8e67d41022051c107c345c06ea82fe8329a8cf3a96b516fd8750611d8ef438b8545416398ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50175152" - }, - { - "txid": "a08d7c70130d925e33b93e21cf77b5790a2ab5b5dfc4ec2198b9d81a74af06bb", - "vout": 0, - "sequence": 4294967294, - "n": 84, - "scriptSig": { - "hex": "47304402207f9b2802ed1e893168277204b7919ff479efe5c71ad2a255e1738a52bacd758f0220253780485f2e3ee960e058d449c647b147b8f64b49b913e7e9615a6c7114f18e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50056417" - }, - { - "txid": "e2c0a8e67a48286fb8801c0faa3951a268c5f6cc450c445c380e80e09c752778", - "vout": 0, - "sequence": 4294967294, - "n": 85, - "scriptSig": { - "hex": "4730440220778fd8ba1dd9f71df55bbe1c3c4185b8da21dda82198546c2a0c30250f4c1d66022040f17a46187d535c6e943c047942f45159a37b2e171db18c657cd24168c22e2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50043784" - }, - { - "txid": "221971a381aaba4e963d21b54e625b764016e848a5390a0df32a29aadf35f92a", - "vout": 0, - "sequence": 4294967294, - "n": 86, - "scriptSig": { - "hex": "47304402202cd2fd29fa395a5a80893de065c8bbe71e0bfe0e7b2224cfd5684736a086aabc02206720226ba63a3e5d9e2dc67e404625cdf31a7a08da0e8a22717e558f7abc817c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50090058" - }, - { - "txid": "bf6623abb315d54e6b7d9428133d913121ac875dc4c8e3f698477dff8cb7e3e3", - "vout": 0, - "sequence": 4294967294, - "n": 87, - "scriptSig": { - "hex": "483045022100f8769b797386f0bdd662483096f4e0a33c13f6074a4aaba3fd590b9abbca7c2402201eb064869fcd17a59ac028145b08c73b3552544cd7fc62245d1fd1d369ecf765412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.5022994" - }, - { - "txid": "e66b832bf71437eeb367e6cd7818658f960a4845bdf3f5081aa474935c9b31dc", - "vout": 0, - "sequence": 4294967294, - "n": 88, - "scriptSig": { - "hex": "4730440220558e65fd916d9c9616a3e0bd41111dba3914867b1ce5d487df4f77feadc0059502203198566c0d58af8551b65f884db98bde161bac140c7a900cd40df97a40c267de412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50154777" - }, - { - "txid": "452873e0c38438227a2fcf64230973ea8f5868fabf05603b629881a2b46a4069", - "vout": 0, - "sequence": 4294967294, - "n": 89, - "scriptSig": { - "hex": "483045022100ca93287feb58daad47c5388067b219e44f8533a214eb8eea9b5313040579773002201716a6ad2de70eff6721ae7950edaf9230420648bb8ec53173c215cbd12246c0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50103829" - }, - { - "txid": "60b3b027b67f550a0544a539f173066031914f0a49897379b51ffa127117e521", - "vout": 0, - "sequence": 4294967294, - "n": 90, - "scriptSig": { - "hex": "473044022003240fd71510800910b448c62a03178b4ef62299b17d6d2c06ac8f3293684ff50220637e3ba59fc884a8bd16aa2e884b379d85f38ae4ba049a0365f33644febee6df412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50125814" - }, - { - "txid": "6cf9e489432bda9fa9eb865587eb28ff525b5171c38f746c55b85a577ae68854", - "vout": 0, - "sequence": 4294967294, - "n": 91, - "scriptSig": { - "hex": "47304402202e2ac9c8b619b8e2626895c20f6bdd1a24fa27de017d05d5fa2ce120b3421f25022053ef6f82ccf9a132d40ce566d45f4ec18bf30048d415f6ec1c783cda027b6747412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50144563" - }, - { - "txid": "9c9923f0c3366eea9c229233d8828825beb12a2c28ae3bfaf46203dd1fe8ab03", - "vout": 0, - "sequence": 4294967294, - "n": 92, - "scriptSig": { - "hex": "4730440220352bdfe541e9e1ce428ac4eb4c8ba9391a118b7dbe57b4fe3c4ecd30f228fbff02204a0b78ada1d74a7e7b9ae912e6f445d9ce9050855d9c5ecc7d477d2590a68b18412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.5021873" - }, - { - "txid": "5ed23fa46f4db7043e14b845ef13a37712170f7cb25f88ff9acbbd6bc97a9d87", - "vout": 0, - "sequence": 4294967294, - "n": 93, - "scriptSig": { - "hex": "46304302203f767d8f64e3c9e5773d94a325f8029d21d1c9a0f470c9288cd99f70d2d90ec2021f50b395f9329ffe64ff8084c1506e904ffc02dfac7f7e15461c3e8a077f604c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50079095" - }, - { - "txid": "fb09c795e5cf32d174df4efe8b2208de9819ed024511d9fd684556ec8adc00ff", - "vout": 0, - "sequence": 4294967294, - "n": 94, - "scriptSig": { - "hex": "483045022100f17f8045a627bf96fe09d868109063d8040e3e2df8944e05f9b20a15273d0bdb022059c31e2d849abd57e784f1a3903f49f18c7c5a624545bab98649e8a092e12a10412103ee2a3f78cd4930dac8c030ccc93381ec5eab259c1607360d85d1728fc296dacf" - }, - "addresses": [ - "bitcoincash:qr3vdgfvrp77mlhac73ujqgtn78cg6yeeurwnjqylu" - ], - "value": "0.01792434" - }, - { - "txid": "36bf90cf0b6074a361292ec88ef58d76780d301a1e5709bf013808c068af253f", - "vout": 1, - "sequence": 4294967294, - "n": 95, - "scriptSig": { - "hex": "483045022100b58c7dd3fa1f8dc50edc7b5546b8ccef8ffc5c179fee774999c63fa729ae3cef02205eb611cc887e5a62a4e9da33318ce6e216ca353225f452ebca51be1dd10f544941210267f3c9b9bfb6bc5c1f68dd1d18623a9986408202cf232ad1e4089933c83f186b" - }, - "addresses": [ - "bitcoincash:qzjvk52q08wp84x9uelf7k3572fx4z5q4q7vkpaalx" - ], - "value": "0.01713598" - }, - { - "txid": "259bc4abb9f14457e323223bcbbf772afc0a0252556e69c9e13e8c7860e7946a", - "vout": 0, - "sequence": 4294967294, - "n": 96, - "scriptSig": { - "hex": "4730440220097f46c588f37ced4846a45905df1a0ae22709760f8a1bc930a58f5054cbe482022053b418af66d1edcb3887616feb23e5dd4095f29e74ac89853c3b909eb42bac34412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50075778" - }, - { - "txid": "14a32331f78309de6ddad707840b364aace14cbef8694ab16a55305fd44260b2", - "vout": 0, - "sequence": 4294967294, - "n": 97, - "scriptSig": { - "hex": "483045022100cf98e22a2854c7088a0572e1edb4e876aa622ed10dc0376806e1432f5dc1eef90220527845f8dd2522fbdf423b4fc34a4792a7f82e04b314e0d83e2425daa2f92115412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50085059" - }, - { - "txid": "acd836ea3252a7610e6c1d426f2cc739f73fe1a0768048d7431a69d4bff3f0e5", - "vout": 0, - "sequence": 4294967294, - "n": 98, - "scriptSig": { - "hex": "473044022070c7aaa7d7f050b1b520878e55db3ca491fb33211150e2f620b685cb49d7d885022022d9ede63e3b196a1c33c2d211c1eacf2e2411820ecf5155b5e4244f5dfd9f1d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50132855" - }, - { - "txid": "348cdfc73c3172311b972b8c529545591f725b86ad065f88d7a78c2fcc05f9fe", - "vout": 0, - "sequence": 4294967294, - "n": 99, - "scriptSig": { - "hex": "473044022018cd70c3e62563ea92ea12735e2efb4b905df85e6b290d573051f49c63d07c60022037a537ca3514121d5c2b8753833808a5e0432f1a8f277d91495953c8211ad326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50023474" - }, - { - "txid": "af7baa39bec2ba327ff720a7c782f833d18c0677c644080f59996e2270756c55", - "vout": 0, - "sequence": 4294967294, - "n": 100, - "scriptSig": { - "hex": "483045022100a01ad9ec8d24fdf01eb203c2887c1413ae56990d4600a18010959f6df43de08d022056f0f0dccb8f772f29a7835d7dc40f242348805005b5f80ae8f2fbdb600ab2ca412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50249377" - }, - { - "txid": "6ba95cc08cb6849c9599eea8ec3abeb7ba7c7b42399cfc6d807dbc5aa8c1be52", - "vout": 0, - "sequence": 4294967294, - "n": 101, - "scriptSig": { - "hex": "483045022100cdd770159d56ac518ecb0dc916df0da06eed536e540582680f742389f53fa4be022012d372e2c04176bcb82b91b02ea23c9c1464baef7d1dda66066bf84c402c0012412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50192878" - }, - { - "txid": "41ebe9615cb3037d95ed10c37be1fc80d216619086c5cfc256e489ce42042d3b", - "vout": 0, - "sequence": 4294967294, - "n": 102, - "scriptSig": { - "hex": "473044022001dc7db378891c1c5bf07a09d14fcc6675965976e2e3e762786b1b1e0f4a4bb702206db6f284dec835823fb516fad89543edd3bd7af3ed33940fa296939fadb41ba841210393ae47ec2e844378cda3630abe12082401f2e0f98d016dde2b152b42e335630d" - }, - "addresses": [ - "bitcoincash:qp4h56rtxkel7traz24d3ep3jq0yxqm82stgclvks8" - ], - "value": "0.01288555" - }, - { - "txid": "a135747cbd99ace7bf495ba29e49b5595f32259ee7df61d9549cf3d4274880c3", - "vout": 0, - "sequence": 4294967294, - "n": 103, - "scriptSig": { - "hex": "4730440220290a5055313d68f9461ce830f8a7395022d2d55abf28f6b4bd665693b4a13730022035d4cc2a6676ed842027dd4f21d31dd5a956f4b1f5cf771b866cc0d4a6400df0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50118091" - }, - { - "txid": "90095e01bb497ffceeb85366ee1b9603b96c33ee0acb47a64fe3af23911410d6", - "vout": 0, - "sequence": 4294967294, - "n": 104, - "scriptSig": { - "hex": "47304402201fd6be6d72ae75b61a624c13476b538ec2f9e5146f3074c879af57ecfbe1679702200ab10ae612e7fe0f76fe943c1f6a02262008407f86782c1536e92e3bad77d3db412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50028058" - }, - { - "txid": "44b169e5c5414cd335ef67906c0f4425e8b190ab366dd1e16641a34d85ab5f20", - "vout": 0, - "sequence": 4294967294, - "n": 105, - "scriptSig": { - "hex": "483045022100a4132f408b5299dfed6153b7a331f9fe866f1b042e4263bf7574ea0964c450a202203d99cf8dc9a9194269bce400185a4f86f5d35b5be83f6dbc3166b600392f1b00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50132073" - }, - { - "txid": "f7f16d4c8f00cb446063f53a75d2dbb2c54d9d474abc836b92d48ed76a5ead8e", - "vout": 0, - "sequence": 4294967294, - "n": 106, - "scriptSig": { - "hex": "483045022100bbcc2e2d77458abc30898cddc7eda060b23a62f0a53b81c3db47f284cd7b29cf0220705328a29bd30792a7f5a704fd74b771c3c8a099265f5e7c9d70046da5b03ff4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50210684" - }, - { - "txid": "0252408a18fc77479f6e664fab80cbc6d90c1c5e369c34661effa52b9f1f36f2", - "vout": 1, - "sequence": 4294967294, - "n": 107, - "scriptSig": { - "hex": "483045022100d2f40145c4b9a17b3582aabdf7d9ac2d47546b3eea5350c4e2ec1e9c2466343d02203354ce620aa056a749de847f867c49dd121579c9fc50bd6258bff7cfb173c5f24121035bf755e8b075665a85155618f6e9022196a09c486415587dd3af0d25b76e9c27" - }, - "addresses": [ - "bitcoincash:qqe36s4qsvdfjzwrv8whsc0z94unav03agzr35m4d7" - ], - "value": "0.01591983" - }, - { - "txid": "74002fe81a5931658cbde74c28933bb36cdaed62201be1c0e26a53c92d6bf5c8", - "vout": 0, - "sequence": 4294967294, - "n": 108, - "scriptSig": { - "hex": "483045022100cf8c593dec0724644d034f17ccde99feaf0416334219f158f884badf500fc93e022035af1b68574e88ef15e1c05c1b36638401613a31aa7096d97efba6df62695706412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50148696" - }, - { - "txid": "496b4d67e0a734740962920c116d56121c16ca60787812fea76d69b9161f8395", - "vout": 0, - "sequence": 4294967294, - "n": 109, - "scriptSig": { - "hex": "483045022100a669e8918ba68754b84d584f38afdd34be387773449784a6c61ef3f33d0fd99e02204d007ef31f5a3a7c412ac3d2660633fcef137964ef2ff6269c41e933896d918b41210383b6491fd80e1411675d7c8eda9b756c30a814b45fa565b7ac24d7be9dedcaaa" - }, - "addresses": [ - "bitcoincash:qq99u7jj9ujglljvh8nzaqtq0kfl8matf5eldrwhmm" - ], - "value": "0.0185992" - }, - { - "txid": "4a6f608d6ce8efcc0cbd3b55bfa0feef86f5493331564dee943fa554fc84111e", - "vout": 0, - "sequence": 4294967294, - "n": 110, - "scriptSig": { - "hex": "483045022100fc35ed21833c3ea3ff5f832ef02236a08ded0999ea367aa6eaaff364ecac3e5002206e291d7c4fca0485dd8ea22519544ac632909d706741710a6e5f0d472c0b0656412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50058421" - }, - { - "txid": "a9cfa2539cb07c0903e2a01a343c6ea8566bc063b4c301ce2efee45760e36448", - "vout": 0, - "sequence": 4294967294, - "n": 111, - "scriptSig": { - "hex": "4730440220485937c55c67c8eb46b94523cb06f9572ffb55094536d8b1a458c76b67dec75b02204e5007f610e491d043a412696d4fd769bb2f5d8c3e8b3a59e6ec3bb598f775a7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.51645868" - }, - { - "txid": "62466cac8a8cb05584af3ce85d0eb8d4a5edf644a374aa23989bfa2adad2d8ee", - "vout": 0, - "sequence": 4294967294, - "n": 112, - "scriptSig": { - "hex": "483045022100b430528ddfca4431cf5cec08964f7325c036fdee55edc0ea0181d34ed72469bc022074b75bfa66dd4a87fab93da0f2f0def65b785fb0b51fe07355799cbd8b30c39a41210316d35753d58318c06d0faadcb723563316847ae06019984f42f2c75deaf3727d" - }, - "addresses": [ - "bitcoincash:qzl7yg7fxw5ls4jum50st5z7valsu7qa7v63ks2730" - ], - "value": "0.01579507" - }, - { - "txid": "559927367907ed4d3822c2b4c0dca89ba2a4df844daa1033123e9939c9e81743", - "vout": 0, - "sequence": 4294967294, - "n": 113, - "scriptSig": { - "hex": "483045022100c6ccc3891fa3924c7b1e69b855628230c48d85d1e1331f037823ab7c5928610c0220050c9c0e078f34ced537e88f95289863a663b28488880f6ada3f1dbbcb1743a1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50110065" - }, - { - "txid": "7b5bfd94b29844e13c3fce76d9579dc7d20b3fa0ef15309714530152e4d5ae85", - "vout": 0, - "sequence": 4294967294, - "n": 114, - "scriptSig": { - "hex": "4730440220168f31f413d65ce64bccb62390490dae2e4a00f98c2c44bd4fd689cd942da8b1022006f1b2aa4fae9587c688e8b7ca5c07db3b3c3afd6961f9f843099ed30b583369412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.51309649" - } - ], - "vout": [ - { - "value": "0.00032902", - "n": 0, - "scriptPubKey": { - "hex": "76a9149a262d0621819c8c17d34a7feca1b39b39157af988ac", - "addresses": [ - "bitcoincash:qzdzvtgxyxqeerqh6d98lm9pkwdnj9t6lydxqg82t6" - ] - }, - "spent": true - }, - { - "value": "1150.6730235", - "n": 1, - "scriptPubKey": { - "hex": "76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac", - "addresses": [ - "bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7" - ] - }, - "spent": true - } - ], - "blockhash": "0000000000000000023414a6f8ec13dd4f85b3fb1c71b937d5dcaa14e350cd4d", - "blockheight": 611623, - "confirmations": 16330, - "time": 1575319726, - "blocktime": 1575319726, - "valueOut": "1150.67335252", - "valueIn": "1150.6735235", - "fees": "0.00017098", - "hex": "0200000073126b74e8eb1830ec84d26e50d09360e120e92956c823afdb2e981432e60e152f000000006a47304402206f992d73dfa7e518b00190f220ad5dc7b7947b1d75a2fcd8251b59f3d29d89af022036c6c44f52f9aeed406dec72a9aab1f82c3b997c36742f4a3504e4f93e6f8557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3848b83fe17d5304f63a9457a5749ea2ca1ea42d9934cac890666e2173a80b55000000006b483045022100db30ebe47536e42115a507f88bb8d5c97b81ad05ce334872235811134c5948bb0220418d77aed78cc4a332b1858c1d2e9ab169828b9c12e8c0d0f8d155964e5d0b8e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4321b2ccc28666c12200bb15a050a513976487cae0a01205cd30ca10988d8ded000000006b483045022100d30c9fd598613586d8d0460fb6c9ffc1d0c6dff6f647535d2a9f69cf373193d102207fff687aa035910db124adad8b59607a72b3d24aca9096217ec6b90fa132a2ae412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff32a0d8da2143d7c4097af72285aff1305155ff5e05276badc91839d5ac9bd7a2000000006a47304402207b30e99cb1f6754d227a4511c5b7791f3b896724b170716d6ed238017f191bb102202c1fadc4c572c86288b002a0d6b6d2460a14a6d3c8b49efc17a03e59d2db18e3412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff62f77994b08467f9a90c1b7b921306d7e48c18015aa53aab74775b73dc79069a010000006b48304502210092b7f176f182936323df8e4359b2a329b0c1e4b48a529d6e32867038a2a453cc02203c24a8bb46b7fea4ef5c78ff116a51fd0a04dee25bfcdffe856fb8988a7a97f64121035b4e75dda9fb0d55d856f54f24fc65da6657939b9559ab2c623c8ef325f14d8dfeffffff5cbff5ba887ac02cfcf6f1adb0c84ae21cc003667734dbc41ddc31330c7c555d000000006a47304402202a2bcfdaf12c398ed5372e6b168a786edb8972df1146b705d3cccf2d9601517d022020b90ac89d9141d68817850d1cdffaf6c51f45249a44fd6861b361a6025d8ac4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffca0bea62231cdd9cb231ced73fc1c0f51c478277a077a55aeec113b506e7db61000000006b48304502210087ef2709b9fe8e7f136219254229edd45e94c3f6ebd2bb149aadd9b1d44d89e202206ffde3c9491c012832967e4d34e02ece2c08bc4c07967b3b466d4800f9ca0746412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff843b9b8e0072454494ac701e9f0816590de35f53cfe960aa03bb4281128db254000000006b483045022100c7dbd1117c57eedc8fc006e818371bfe6399c4d25e8b40482c1f0858a3d98a4b0220426d1196513a87fc7afb5b107b770a90af789536799a11686eab96b04afa6326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2301458143bdd235636b4a15f1ce7fef218ef401e26f5871d26bb28e632e0c75000000006a47304402203604fbb20824443899030d2c1f5cd0dc2b88174929861a708bdca878868e910c02200a607b1da53483bc95d3a5c54e5ad66e459827d4ecf8b4ef9909e9d58b2d329b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff9ecbc5e26870067db7ee944b7fbe3fa99c3247e0614fa5bf24a9eb587c36d9b000000006a4730440220399c36174173cca01f6d6a234a935d6f776b549e1ea2fc2635193924c4ac2eb002205aea7741fafd95f862588c480aaa282d7a344d32d6318aec1a908cbb939e5d0e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff9ef492949a0ba873b09258961f35cd18d78849cd290fb93aace31af829da278f010000006b483045022100da9075310e7af59456423be99362f2cc686d50571e0f0b016bcfae1f0bc4692802203379b648d47704dba48542b8b6d5e515bf3c4fd7ff8a7be82cd0c8c0c7be56f7412103a344a84dc1a919a64874605fae200861b7af3ecd02dc5d52dd00eb6f8845525afeffffff5c5f3037b499d79505425804b021b76dd94e1632b6747afd059d0a728ff49b10000000006a47304402206cbf93634d6a477a571fa2884c19918b19ddfb008ff9fe405954720047efdb88022003e755313436d406dddfe3cfb68719e8f39e43de7c586489cc543dac0347da9f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0b183fcb0f29cff3e9f22ff47a5c87694199ec43b77930f7b17d646f3670e5d3000000006b483045022100f23d4cf11fd0a5ab83dc053ca64066cbdd2fb4107e0977a3a880c68a67636f7d0220220a47c66d3944cfc309c059fe8013c4de742e4d8590003fd56c5e0b3c7da557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff80540561a82abdba58b2ac3bb9bf9f1064106b8f2fdcb63d462721409af9056f000000006b4830450221009f522beef55cbf8c7f10e88739846f78ef1c9d9cbc6959dba6f687a08fec0ef502203a160231733b87c6cfd8afd148994c9b6c5d5db9bb9847aa9e60938a6e79d5b1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4a4a1e4ea13377a0819a88e2664facffabd92566b83fdca3456267b017b7933d000000006a47304402201f5d29be80192a752fe28ff141ed702640df88083faf3f9573e52405cb4bd79a02202d751649aa600c4fdb8b1d1b21f0d134c2f4e5af9ecbe7d87180d667140f0a11412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff9b41a363950ab3e6b769a4cd97555d1d8336505f3c87599ebf7766642ec97ac7000000006a47304402203f4bea3816d252cb19d4247f587a146901c74d04e783efddfd5089942f2abcdb022069012613c4ee4b3b0212ae71dbd2071e01665148697011eb03eba25431e679cf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffab050b7b334656d60e2c9772a3820015a2f6a7cc3e2943897b0c027edba3cb90000000006a4730440220782ba77287116d5d735f67a3738fbecc1a802d2141a1fa544f61a5e8ba682a4402205473d68019cc8895ecb1d87bfced62ddb6dc48b81152f2684ae8530122d5b41f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff26dd82e448134b4105f561b681206a059e1de4e5690453dd8e4d9a0482c35ee2010000006a473044022044ed9bfa8674d7e83112fa22280797169d45bd971b185da2413e36252637529d0220531eefc480e0911d6ccda42002942883149bc1cdd1f3bbde313751d80bcf98b641210328ac4ed2b30ddc04c778a78b24e7256b08c55758c1465defd997ff4bcefacf10feffffff9e2e1b53ecf545d0b0cb972553deb89f3cce7e9e92d0e0a786779df0df48a113000000006b4830450221008cfdfd352e268dba2022e7fbfc37a90401c40fdf6f1d8ba9dcb97d67743eddc302202c0a1b604d34aa174fddef63c9115c95465548855c5f783bb206eb4ff8fda235412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff9fd5ed5458cdbeb26b0126512a1b1f1aeb85fa7b584a0568c674708fafc0d70000000006a473044022001b33b610b8d742df2ad98679f1e41f0c647faf272e15e7ea93171ba29c33bcd022061646fbcb81ba30d6e8b030ee12101d1f1bef38ba44a6d5daf40c4ff6d644e6e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa6f2a72bf25954904893198f716f7b6f07e68bf35c12c233aa6d165723931068000000006b483045022100ec9b6bbaba90d8902ec8a1ca0e90ea594264bc1add204b756cc89def4d7e9a2a022066b2bc84f94e1a99effe0e929be8de8669631143ca20c73e700d182ad4884e71412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb38019b996f974375732d741fac543bcb46670b99c566a8a887c3f876485a942000000006a473044022057117591cc465c48da58ebcb8f57fcd56359757d41e1397e45b5e33e034ea5d8022001de1d78ce9e8e73370a0778b4a8595045c6faeb2497ab4296d0cff735711276412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbd0ba68d3c24402ccc4d2c82c4d11ba0a794bce9e9d39f64668aa4b5956eb5f7000000006b483045022100dace56650d1d9edaef30e8c9ecb4b78499a573984c8a451253295a90c84a3ed702201f4587d4a760cd77a2e21d5f6f2b7aacf668220c8c7c62fc1ae4779f7c0141cd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff143d2c0bfb63e9b52766c0f7921d06a1d51b90a770b64902ee8352122c918bd5000000006a47304402200db6b461a0082807f59053bea210d38f5f82f02dd63a57f6e3987339cac23870022064ba927fc11b36318785d4e861a7f94cb3909ef8fe882360e2041f7b4a444692412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb0b7e16b8502ccd5ce2ec06157803e5c84062f5e8e4804a633f9e809ce260353000000006b483045022100a3e75a6c7918db32a27be348493b831631856ec8f546ca43d143cdc3c1cd03c802201e6ae036423bfce45c500b0c049f68396deae5cb999038de61e972ccd4cba5e7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff6d284b186e26a4116b02e6568c2868ff13408b85c71db1495a5e7cd32a4151ca000000006b483045022100caf952ca1760052cfefe8df283fdd0eccb9e1238eea88eef287df9404c622e8b022072027363fa1070548576fbf9bcbddf2e435fd020662b2d8f0582b52bfa487b31412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff38bb6ba6ccca482c333c8fd0e35afffb150e4c99fdf70513175f10bb8b263ec0000000006a47304402201a4b4efff2b70a4039b4dc120141da04ae84f63906df10c3cad08838c01b6b8702205a065d025c338547ea07b2095ad31252658e57f1a7a04c7f4eacc0248e611fa2412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa326b367f3405c7648e8e12b5bd7078867796b60f70cd4b3123442a6fcb9c846000000006a47304402206b0a876d78793710acaa8bbeb58a2d908bd4936f2a88825f944b190041b5e0be0220279560be5009e4a3fab44d08f4748e2dead710a8ccc77e06a03ba8112d728856412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff746bb13f09e7c465f9ea0b264c601ef9652736d83ca0c78686ea25326f6bdcfa000000006a4730440220799bdb7ac60cdf3314cc1f157299858d353e22c00354707337ab5b497619d626022000e41053afe44fa65227b7dd8498300a2dc89367d9daf0586caba5bffdfde567412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8da9008652012637c8bd2a3e6c9b6b6c4e12e67126ac1e5cc3b1d42b3c16b5ad000000006b483045022100a1af33a83edb7fdc289a48a4f77cf286a88b38c21ddf27dd4ec3df007ce11046022074dd56730730f958039efd70edfe7e181060fec306c6df4cf75209600ebebed7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff84a1b480079b2256862090844d38dcd463315a43b757678d7002cc1d01001adb000000006b483045022100eff445419ec63d1e9f51a5324c3be0315911b39f30657639e84ea7d2f739e0510220218e73140a39542ec8055b6645cbb7989f96b9d9a93c67549c059509de06f0ba412103dd71b53aaa823b09a68aba30c7603c6a397e7c183f708c9dfb0d9d0a9cd1c722fefffffff8872f26872ae96f137ba029e4ca6d19072f8223c0664608eeacd4753e8969df000000006a473044022050b7ed06a6832b8831c08ba86049b3793b5a71fd6d5177c9f268b79c3074bca7022047447c23429de30c361875642d9058bf1b5e0e6c5516d6e71b70b7cfb29827aa412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7ebebf2f8b764657a719cc52e3ce31fa79c37cd2d583b7be31ad9ec2ebef3284000000006b483045022100fb072bfd399dc11191ac449a9d60119bd191ce6b19a5d92412a805ddc8d4b46f022021e463686560b15ddf272b9943d8e41425ed500f77698aba518ccf546a97aeb4412103e35c58a738805f53af73472ffb671a9bd3556ddef47c62f18ced868bb5033d0dfeffffffbaf05866b6eba762daab7778d4eb3fa1902346491f14c8ec047c12aaae4cff29000000006b483045022100b25e7d4ebaa0e7d8e24498b039e756d568b67316aa14d05abafaec59e216a73d0220010d0b6548a74435907eb0d548dfe8e52a949bbb785eb2be3bce14053953784f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff1330325273e9a1329b3379a553ce95bda9dbd7b83f93fad4acb8c1dd45f4463b000000006a473044022007d2baa9a766c120e111a727bfa8e8bc2e01cc285d4d4f67d2323b213525a10c022020f32be2d9935b6d9b5091db27ebf00aaeb54adc7032badc7ad63f20741ff28a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff44530eb5b53868de4819fd0dff26c12e2759f4696ce114e22855e88be1b1d41b000000006b483045022100f98ee28ffb66acd04474a120904ec1be2327d727d8ed8fe99d8b95c174b8f46a022041d21406dd8df10cecc1d6435de68fef3f9db71838c1ca2910895bb184b4a6e4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2fbfba76ef97ef4c6e575783e08baa25da64eed6a7eb4ca48707feb7a2927406000000006b483045022100ee3f7961f0f23137d753affe85b777e94c1db3f656cf41b8f59fcf82d9226eb7022025009482a6c0002e409590075caf7a78023ebc1457f100c8b922a4974ebf86ba412103f1d1dd7685d3781f58f9aa399a16f6bb9ccc7d008cdb7c63a7945cfcaa6ba0e2feffffffbf525c080b8b43afd5c004b40d25a7ceba36207162b2bafa70ddc95cae68c1bc000000006a47304402201fed9da4c0526ac5ce257fce2b7fc995646b5f0d2961396327f93e2dfda3e4a0022035b217adc5a9be2ca34f4361ceafd9f2d09a6fa47d4a767f7001ade40c08fe26412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff327b0b903a0f60cadd0c8d2e2cf774ee04eee9a40bf5c37181a471045f365d02000000006b483045022100fa8ee82d42f524290319fb3ee47a1afa70cb952f8a37325680d6fd651ac3699f02205ac0cd86fece03ca204bd881d67ccce0cccbbc98704d9e955e2f92b5b77121dd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff5fadd3b92b767baaf2a50c8b21f8d3f7cae103e7b4e4c0ba60f111d45f8a1cc6000000006b483045022100f3cb343c4704bebbc78c6492dd72ca19c388b285f44f574dcff25f993add6d5f02200e050dacd78de955cf552f9158beaac5fa64995f5bf7c8a919a231a39425730c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff47d0ae39a2ce683261d30f45025b7faf667146a980c1213b593c482647d77d20000000006a47304402203f05a035f5d42fbfe97172b431a613110ad733e356ebfd08886fa11bedaf1faf022061c4a3bc3417390910612bae46f5acf8b6e8a5b008d273a52e483a315bfb950b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff46cefa6639796b89c5e8981c42a230d8629cadecfca5dc853c85e782ecafcafa000000006b483045022100bf60fbd4716339bbb42ce150966ad6caf90b14e57f45eb6804756cf8ff36b23a02202f16aaecdb9994f3b683cc7fab45bd0a3f54795c336b5fc224fc51270a7f3f4f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4e5c5b111998d7b90d46130f2ef29f25d48e8649eee14684cf6d46eaad3b7026000000006b483045022100bcdcae99c9289b5fc89d3227daaea8df7d0a0f3a8971d841ebe1ab7a1ecf72e202202ca21447a6b3e96540e32529697d523b7b08c65845d6a13f6b1475de94919bb6412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff489efab51aaeba5cfb24d1484a917a33aff79b7455392ce21a3e642a170341c9010000006b4830450221009535c27b5bbca0db2bcf1a0d0b3b283a2171df53f0d68f1a138888fcc6ddd996022068af19252ac4376cffdbfaacb2e0f0c216deb7e2478b586abe7c2679501eac34412103a47e5dea4ab8d785f4e00994d0faf1a8f384c41e74ed8e4b776fa6ce136ebc42feffffff7eee285c72768622c785561839c699b1a748f58ab418615611c70c9d70440518000000006b483045022100b456847e29f8a648730f0fd34cc7edcfb35daba866ab7d800472beaf2836ce4202207db401f0a5e30efc53c7bf58e57d1dec5874d64768ad9eb4895351cc4be9226f412102291b40a9a927dafeb53cdfc7e722ee5c9dfd6eac2d81331678b9ab405bb25d21feffffff93b0226e9f90d151df423d9ff868513f71f708e715cbcb1b5444f4a0194bc267000000006a47304402205ff244c77726def0e3697a3e546bdf74c7f31479c9d01a7a6f8cd1656482d537022045d78dba8ed4d3777f473736daedbdaca6f5698dd306898d144eb43f96259766412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc784e371e706c6de880fe3033039cae758513a73866241658a21fa6a8a4a8d20000000006b483045022100ec6b35ce6d24889726480d70a31bc0d62800bf7ac49ecf084b98137322606bca0220432d33e2d8b508f26d7d813d18629453c537a4d90f73a104bbf80627f9fe8d62412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa4cab40c510ef0ddb8fc3612af871512805ad7ebed2b60fecbe7b9d0f8eea760000000006a4730440220423ea635717cff512d9262b7c8932c0122ca868251f019ae033101c28771a52302200cd3ae05f2e88d9f64207beb4b715ba480bde9ffdd40ab61a36feff88f2968d54121035530745f3cd4d31532991e460bd2a15e1944e690643f73133a9918edb95da53efeffffff852bf329889cdd85945b23bc6a338562c151ecf16b04414c75afb1cb9ded3370000000006a473044022055cc4dfa48a79b8584a9352be34ab5fe9cae4132d264dd827d14ae06d35ad4090220652a83c93505f8a8527c5bc0479f37da0593595c1bf18c12b8fa0b41a2e37a64412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3235c14d72a55c47d9b996588c7110e27d031013e1f2c77deba6241954059f92000000006b4830450221009acc8d0e06d10b0c764a27613bcef41fc75f910875eae3989a7f8725f81814cd02207146ff66f412910ed993fbda4ad6ed48862a02f366dd88a83856a17e7f96d83e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa0b0aa12e3299ce6c925827b3d5603676949daba619fd9c7bca247d1c265e9a7000000006a47304402202d8cd72290f04063c0ae9bc06d2cae3ac74ef4cb6945c92c3e3ccca210c127ef022030471726cd87ac9d55f3d246095f64ae22b611aa8791922236bbdb19ec273322412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc856c10b1d42360a93cf60fa8127afcac431417ccb7213f649d45482fc7d89e6010000006b483045022100ffaa954e5b86d54ece9bcb9e37895047221828ca381b03266de3d9341599c8f902200ea1c5ed36e893df822c698a474b062d4f93005c32f9d2f0d78ecaf5a56e4fbd4121031a00f43cd99e015c72acace20ac47d887a39ef284f89a5aa09abd968d06f5e9dfeffffff69129065f6f989f1a008813b345e8cbd881a38107b9a0af3a3718437ad6e9cd6010000006a4730440220457d59caf24eb6e10664d06f3e936f6ee31d9d59f1cc4f6f62788f022bce8c1b02202ce7c37ae6832b078c1cb9a055e3ffcf4674081f0738fd9c3eb4465b52bcc9ca412102fea9ae922223f2c68c68d7672b7656885c3e1321d35cc8f5f445179df6f7d27afeffffff8ad3038c3df6f210fa389c57f72d240dd2da53bf172429620e64758a28a82a21000000006a47304402205e0f5cb06f7fd741825c669c87e9db1a433913fb8577adb92b779d3a693b4f080220120648a5f9d2abae83a29cd2c79f5c61b9bc40da8990736ab97ccf6f82c586cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4fda56201530659af45d3f6ad8704693d321f4c92184403e848bf4c3eb1a6a3d000000006b483045022100debfb215f94e9d784e91fe0b9d2541d09a4c7591172fad1441506db4a3590fd102200cce728e344933111c9548162e62872fccac624f6f98d92ccdcf98dbed09ac544121039b8a20c23f32f5b14e76fb29e0baade695810aa7b6dac9e9638a8d13b6ad8221feffffffe7bf81c3288f97cccc60391101a6bdc7654a30dbb693a9bcc8a4b112535d5891000000006b4830450221008110aec39b127143891069590fa0d9e1d8b41bdda70d9807848eba92cb48736b02201bcfdc1a1cedfa4c53efd941482f6157774b2aa80af44e500263be6a3cbcbacb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4c686bfd13c84da78ae379b1cb6974bd3cde55fffef59f28954095903cd2b3b9000000006b4830450221009f76d6838b8fd8bb74f50c67920fda9f28054d093b30fd03b54b3fb888db046f0220307944f3abec07c3570614f418056aeff03c0830173c963bb0b65bd5ef24b4a9412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3f7108134b932ada8356748fecd11ce666f529c25e4aca3c4253f77b3ba6f965010000006a47304402207b93e2500b189b51fbc3a49a191c4b92ac76e32ce86f6f1b9af4afbb3a91fbe002200b5617cf52095bf882a5129f5477f119c9c565dd582a9f19493cf1bdae6527ac41210323ab0930ba40688e66bef6e08f673bd6bcd3df687e4c503387f48c24bffdc93dfeffffff7edff321567843351e47d6d3bc8394e2cace9fe3b72c4dbb152bc54c6abfdd48000000006a4730440220731ab37e71d9c6f63333ba205a318d36e5847706381f571b4b562e5e6f6e403c02200704ca9d9a33843d9a16135f56eced1fd18e227385671a8df5fa41e505e3ba3c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff71294d7e9b11e4e36de589c91122993add9030771328f27215bb55c36ac2750000000006b483045022100d1d3565175e1f529124ebba1bcdf8c1704e753c2f91ddcd1a093b5f5403cd0ed02207420ee9d6082356cba6d8075b4fbf310bd84dc770734a8ab30e74741a779bae8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff423caa98d71896bcc3bd086cc2cdbea476888d19a3f3b9d2554e82e1692cc93000000006a47304402203ddf5c6c5065f03229cdf837d9f8d3d22314834b006e0aba8dacabea206b3b150220417c49c9095372d3dfd954688bcd43fdfd2a121989fde18456a9428b2a8e3c63412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffce3d664bc2eff728a9ea3134bf11d8c7e2207ed508e7879ec7ecee976eaf72c6000000006b483045022100a20e6aaca7df2b142b768d3b1cbf8f783f3d4997d155a32f0e066b4255777c9f02206deb15cf53d6b27a973df9aa7080691e5914538d9e97ec7c6e797ce03333238b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb8f5dcd6f0fb2ad1db921e6f79fcd9fa463165091761f9d8baa23673a0a0645f000000006b483045022100cc2cf5c6c2d4862dfdf65407138684ba45565bd8ec46594ed4586bfa37b715dd022013255b2eb22f5bb93d2afdd07ec4c3b5efe0aa16134b2fd084c6bc720f8cfd5c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7c331f8d0e02777c73a28ae441e12de405bacef5ce967761fb521786d5186b25000000006a47304402202c9dd98c9a72e5a8df4b01f09d18e2826d8b9871db89c5d3b24ffd673facaa0702207523bfcf3ab80790167a2b1159fe268770371fcc7d770995c19eace3181ec8af412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4cd501228a577f0662b802b5b197921268202b8658e4aaab7cf6ecccb93cdaae000000006b483045022100bfac8828df10b7911d341c15a532819c429c7185d8883de19de84e71b97d78730220177603a3572908c90dad865770906b5ad228da7ee5da39503ececf60ac735158412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffdbd64011a7b6fe85385fb207b347f02f5e047b7ffd55bd4192af5ea979e2110b000000006b483045022100d598e2ccdeecfdfea9d5139a49a94fa39414f9e1ecb13d54efeb34c168e58aec02202a59463710905613844f48dc71d316c0cae54ab9e16dd95beb8902e5940024ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb90e762342456c7032806bd546929a38782761e2ee29e7aad37778e1ab6e0282000000006b4830450221008302d38e9eaccaea812c853047931562417a3665b8b9373cf7f63e58180b002602207ac8fddbbd19560a74333ec92fa077d169b4902a41e0431113f8fdb75b304ecf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe15523a831db30cf60f16b15dc338703a64058fa3830c17a4314b4ab824ca943000000006b483045022100c0d85a1f9146e8ef9efaef8ed9b3ed09c55e51b25e189735610da89b6d212360022003a49114e504741befcdb95d52a3dedd1aadef68b7c48f0a4a8c7dddfb4201b5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7893407b6997d973f52a924d03ebdfc639401a138c13e12c2ca365938135f841000000006b48304502210091ec8402cafd1e7eb11b56ac56a994ac79c435893108d0b7c8cfff87c07ba0a602204fd98efddc1b4e21bd3cb81217579a7b9621f9c3c204f2f5800e75ce1c60b19c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff016fa30c4594495726151cbe044ad53de6421e1f28e2366602bd80a3dea98c2f000000006b483045022100a850bf088a08baac1f1f577da8946befe2e6b0354d6a29f636afd39982569a7e022062652d6b75dee145f741d28d6f1870fde9a7d66b994f0d3162abdc42fbf54458412103ffdeec10b52942b0c46d6578998efdc1d64073de579e92e7c5dfa97fdf3ac391feffffffd8659400dae01e9cac6076cb19facc050061f64b16957ad30500503c24294840010000006a4730440220762f7c017672dfc71d487f3730e26d69d0e53902f579ba348095ca164d27b094022076c7e8045ec9fc57af6dd95f35c0ffad2c0ca8f83f112f60fb9851ba4ba15d92412103a2d2d8251728b11fd4afe7b8c73a8442f76dff9bfa424f5cad9b98083936259dfeffffff642ba174ff1ecc14e4f086d70300d487dbaae78bfc684b43557f9b8ad2ca2426000000006a47304402200654032c5760f8b94cc089da51773447f19c1cd2108cab89bb53ccfdb6dbee56022015e277622dea4bd1a7913ff934b2bb2d1b3d75f05285b51690160e1197a258c5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff654d602ce9a224bbce1fb5f9588977fd780591457ef11de271137ca7fd3c3b89000000006a4730440220712877c0dc553096eb0ebf101d1555fda5235db26ad074d2f330163fab63fc7802202c89752dd7645e8a3da7e8af5fb68dc8b177700766b79cf6a35695a0c7c873cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffcc614cc3c1c12c9b8cebba5d78a395f5347a5073211a04e03d55b0a8abf386cd000000006b483045022100f3fa1e305666e2a62afaa11fd37025b25c0bdff8709fe1580406615934228cee02204841a7d96f36d3c183f06e22a58175756c3e9a76c93c7cb4e9945f31ddedc902412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff26b2ed7a5c60815f5b62a5d30af9613e69a26e8aaa429be689baddb562e88aae000000006a473044022047c158e3fe3f40de3f39796dcecb7df3cf344f14009de9826b62a43837f2cdcb0220759d823cc145fd5e8b651a7bcc399544692bbf596189b1fc50bba5f4ca02cdd1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffebb012602f05d2bea0016b8b304f59f610922671560469d80e0e913cd2b302b4000000006b483045022100bd70744c867943bc3bf578e192c8a87a5ed5126aac4acd98efa06ea2483911fa02207377e11ae2d2bbaab00da86ec73c26e596bfcc680c0b8eddc5d44bda650bc299412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff87809cf57be510d02c71276f00544888795f624f33d78b01ba63c87340dadee1000000006a473044022059ee25066b8a2a4fdfc35f14c5cbb7f22ab181fcfa9702d4f3de7aa4d738c7a402206dff315ad1cd2222cd6ac074bf34241fc22db38a57bf089f7e24542323f1766c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8c33b7af2120bb22742f4a5e5fb4ecca7cdf73a33bc8811f3d5d3d1cd9399c21000000006a473044022039657cdf4fcd5a9e81766ba11db495b8be5664612d3b91f8504bea342c4ecbe702206ca4913e5807cd697d30dbc93e0a9d679eb01ee84b687ab0c642e2f3ebde745b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8142c39bf2f91bc685f7c08e40450c90b36dc0a6782a764cded6ba744a591f3a000000006a47304402200232ee94873317eae275cf715f4c3aca25dd0c8db4800946a45cc1d9c45732fa02203d9ce9c9aedc0a3899dd027df32e683438769d66f33ffe52006454614b77821d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff503b9a4c5cab71a66b685d3266002970227d0f4a6b1c65b86603b8c8e683cf14000000006b483045022100900bdc6f705efa56449a65f15a67fc7fbbc102f78e7974ea6ac2849c75d2dfec02203b78de71dad2e3f6ffad2779cb9007217c957c8f5db7abd58fd0537fbabb8c6b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8bed144f5515754d58c273554d25637ec776635033c9ae13bfc94e4b6cecd11d000000006b483045022100becbb21c7937b9b27ea3cdac5f2048ab9ac314de59c3ee2926a5cfb258ce14e902201c8022bf275c1a761e7715b14e15d74526901363ae5f8bf5489d00908dd758eb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbcb7881db3ede1d9275508f97b9f1e0e008811ce540f3b42a921e26f6f065799000000006b483045022100ad84bcd69a85a0d487fd7cbe4d76b95bffa303e76615a4336419fd182eeae4b902206d21e4f592297e87f1af9e19c80fd978914aaf5a2db2cf499b72cabbbe73c831412102958762ff6c8985dc9656afda59e61afc6c0131a5d8f1d86c87c83c9b37f7bd18feffffffb7ffae52888348a77a9851617df104a29366126e01ecc6bf7d209fc8627646ca000000006b483045022100edfd64cf9335d094d5873deb38cda5f4ceda3351df722f1c718993a2dd12c8e302203126b0f9470a4d0867ed4e773518b8ad689ce43a2c9f65a1f297525fc22201dc412103f37089783028c0776f2b8a9d8481ec8d6d0652a31edc03cc274032ae17c63c62feffffff801a88dcf5725d71cc70aee29ec937233f7a059d60e068dea3b7dbc806e0fd54000000006a4730440220448751a749e7cccacab0ae1ad4da948b0e0b5d8e3f41ac2b22c18928e8e67d41022051c107c345c06ea82fe8329a8cf3a96b516fd8750611d8ef438b8545416398ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbb06af741ad8b99821ecc4dfb5b52a0a79b577cf213eb9335e920d13707c8da0000000006a47304402207f9b2802ed1e893168277204b7919ff479efe5c71ad2a255e1738a52bacd758f0220253780485f2e3ee960e058d449c647b147b8f64b49b913e7e9615a6c7114f18e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7827759ce0800e385c440c45ccf6c568a25139aa0f1c80b86f28487ae6a8c0e2000000006a4730440220778fd8ba1dd9f71df55bbe1c3c4185b8da21dda82198546c2a0c30250f4c1d66022040f17a46187d535c6e943c047942f45159a37b2e171db18c657cd24168c22e2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2af935dfaa292af30d0a39a548e81640765b624eb5213d964ebaaa81a3711922000000006a47304402202cd2fd29fa395a5a80893de065c8bbe71e0bfe0e7b2224cfd5684736a086aabc02206720226ba63a3e5d9e2dc67e404625cdf31a7a08da0e8a22717e558f7abc817c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe3e3b78cff7d4798f6e3c8c45d87ac2131913d1328947d6b4ed515b3ab2366bf000000006b483045022100f8769b797386f0bdd662483096f4e0a33c13f6074a4aaba3fd590b9abbca7c2402201eb064869fcd17a59ac028145b08c73b3552544cd7fc62245d1fd1d369ecf765412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffdc319b5c9374a41a08f5f3bd45480a968f651878cde667b3ee3714f72b836be6000000006a4730440220558e65fd916d9c9616a3e0bd41111dba3914867b1ce5d487df4f77feadc0059502203198566c0d58af8551b65f884db98bde161bac140c7a900cd40df97a40c267de412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff69406ab4a28198623b6005bffa68588fea73092364cf2f7a223884c3e0732845000000006b483045022100ca93287feb58daad47c5388067b219e44f8533a214eb8eea9b5313040579773002201716a6ad2de70eff6721ae7950edaf9230420648bb8ec53173c215cbd12246c0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff21e5177112fa1fb5797389490a4f9131600673f139a544050a557fb627b0b360000000006a473044022003240fd71510800910b448c62a03178b4ef62299b17d6d2c06ac8f3293684ff50220637e3ba59fc884a8bd16aa2e884b379d85f38ae4ba049a0365f33644febee6df412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff5488e67a575ab8556c748fc371515b52ff28eb875586eba99fda2b4389e4f96c000000006a47304402202e2ac9c8b619b8e2626895c20f6bdd1a24fa27de017d05d5fa2ce120b3421f25022053ef6f82ccf9a132d40ce566d45f4ec18bf30048d415f6ec1c783cda027b6747412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff03abe81fdd0362f4fa3bae282c2ab1be258882d83392229cea6e36c3f023999c000000006a4730440220352bdfe541e9e1ce428ac4eb4c8ba9391a118b7dbe57b4fe3c4ecd30f228fbff02204a0b78ada1d74a7e7b9ae912e6f445d9ce9050855d9c5ecc7d477d2590a68b18412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff879d7ac96bbdcb9aff885fb27c0f171277a313ef45b8143e04b74d6fa43fd25e000000006946304302203f767d8f64e3c9e5773d94a325f8029d21d1c9a0f470c9288cd99f70d2d90ec2021f50b395f9329ffe64ff8084c1506e904ffc02dfac7f7e15461c3e8a077f604c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffff00dc8aec564568fdd9114502ed1998de08228bfe4edf74d132cfe595c709fb000000006b483045022100f17f8045a627bf96fe09d868109063d8040e3e2df8944e05f9b20a15273d0bdb022059c31e2d849abd57e784f1a3903f49f18c7c5a624545bab98649e8a092e12a10412103ee2a3f78cd4930dac8c030ccc93381ec5eab259c1607360d85d1728fc296dacffeffffff3f25af68c0083801bf09571e1a300d78768df58ec82e2961a374600bcf90bf36010000006b483045022100b58c7dd3fa1f8dc50edc7b5546b8ccef8ffc5c179fee774999c63fa729ae3cef02205eb611cc887e5a62a4e9da33318ce6e216ca353225f452ebca51be1dd10f544941210267f3c9b9bfb6bc5c1f68dd1d18623a9986408202cf232ad1e4089933c83f186bfeffffff6a94e760788c3ee1c9696e5552020afc2a77bfcb3b2223e35744f1b9abc49b25000000006a4730440220097f46c588f37ced4846a45905df1a0ae22709760f8a1bc930a58f5054cbe482022053b418af66d1edcb3887616feb23e5dd4095f29e74ac89853c3b909eb42bac34412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb26042d45f30556ab14a69f8be4ce1ac4a360b8407d7da6dde0983f73123a314000000006b483045022100cf98e22a2854c7088a0572e1edb4e876aa622ed10dc0376806e1432f5dc1eef90220527845f8dd2522fbdf423b4fc34a4792a7f82e04b314e0d83e2425daa2f92115412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe5f0f3bfd4691a43d7488076a0e13ff739c72c6f421d6c0e61a75232ea36d8ac000000006a473044022070c7aaa7d7f050b1b520878e55db3ca491fb33211150e2f620b685cb49d7d885022022d9ede63e3b196a1c33c2d211c1eacf2e2411820ecf5155b5e4244f5dfd9f1d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffffef905cc2f8ca7d7885f06ad865b721f594595528c2b971b3172313cc7df8c34000000006a473044022018cd70c3e62563ea92ea12735e2efb4b905df85e6b290d573051f49c63d07c60022037a537ca3514121d5c2b8753833808a5e0432f1a8f277d91495953c8211ad326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff556c7570226e99590f0844c677068cd133f882c7a720f77f32bac2be39aa7baf000000006b483045022100a01ad9ec8d24fdf01eb203c2887c1413ae56990d4600a18010959f6df43de08d022056f0f0dccb8f772f29a7835d7dc40f242348805005b5f80ae8f2fbdb600ab2ca412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff52bec1a85abc7d806dfc9c39427b7cbab7be3aeca8ee99959c84b68cc05ca96b000000006b483045022100cdd770159d56ac518ecb0dc916df0da06eed536e540582680f742389f53fa4be022012d372e2c04176bcb82b91b02ea23c9c1464baef7d1dda66066bf84c402c0012412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3b2d0442ce89e456c2cfc586906116d280fce17bc310ed957d03b35c61e9eb41000000006a473044022001dc7db378891c1c5bf07a09d14fcc6675965976e2e3e762786b1b1e0f4a4bb702206db6f284dec835823fb516fad89543edd3bd7af3ed33940fa296939fadb41ba841210393ae47ec2e844378cda3630abe12082401f2e0f98d016dde2b152b42e335630dfeffffffc3804827d4f39c54d961dfe79e25325f59b5499ea25b49bfe7ac99bd7c7435a1000000006a4730440220290a5055313d68f9461ce830f8a7395022d2d55abf28f6b4bd665693b4a13730022035d4cc2a6676ed842027dd4f21d31dd5a956f4b1f5cf771b866cc0d4a6400df0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffd610149123afe34fa647cb0aee336cb903961bee6653b8eefc7f49bb015e0990000000006a47304402201fd6be6d72ae75b61a624c13476b538ec2f9e5146f3074c879af57ecfbe1679702200ab10ae612e7fe0f76fe943c1f6a02262008407f86782c1536e92e3bad77d3db412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff205fab854da34166e1d16d36ab90b1e825440f6c9067ef35d34c41c5e569b144000000006b483045022100a4132f408b5299dfed6153b7a331f9fe866f1b042e4263bf7574ea0964c450a202203d99cf8dc9a9194269bce400185a4f86f5d35b5be83f6dbc3166b600392f1b00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8ead5e6ad78ed4926b83bc4a479d4dc5b2dbd2753af5636044cb008f4c6df1f7000000006b483045022100bbcc2e2d77458abc30898cddc7eda060b23a62f0a53b81c3db47f284cd7b29cf0220705328a29bd30792a7f5a704fd74b771c3c8a099265f5e7c9d70046da5b03ff4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff2361f9f2ba5ff1e66349c365e1c0cd9c6cb80ab4f666e9f4777fc188a405202010000006b483045022100d2f40145c4b9a17b3582aabdf7d9ac2d47546b3eea5350c4e2ec1e9c2466343d02203354ce620aa056a749de847f867c49dd121579c9fc50bd6258bff7cfb173c5f24121035bf755e8b075665a85155618f6e9022196a09c486415587dd3af0d25b76e9c27feffffffc8f56b2dc9536ae2c0e11b2062edda6cb33b93284ce7bd8c6531591ae82f0074000000006b483045022100cf8c593dec0724644d034f17ccde99feaf0416334219f158f884badf500fc93e022035af1b68574e88ef15e1c05c1b36638401613a31aa7096d97efba6df62695706412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff95831f16b9696da7fe12787860ca161c12566d110c9262097434a7e0674d6b49000000006b483045022100a669e8918ba68754b84d584f38afdd34be387773449784a6c61ef3f33d0fd99e02204d007ef31f5a3a7c412ac3d2660633fcef137964ef2ff6269c41e933896d918b41210383b6491fd80e1411675d7c8eda9b756c30a814b45fa565b7ac24d7be9dedcaaafeffffff1e1184fc54a53f94ee4d56313349f586effea0bf553bbd0cccefe86c8d606f4a000000006b483045022100fc35ed21833c3ea3ff5f832ef02236a08ded0999ea367aa6eaaff364ecac3e5002206e291d7c4fca0485dd8ea22519544ac632909d706741710a6e5f0d472c0b0656412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4864e36057e4fe2ece01c3b463c06b56a86e3c341aa0e203097cb09c53a2cfa9000000006a4730440220485937c55c67c8eb46b94523cb06f9572ffb55094536d8b1a458c76b67dec75b02204e5007f610e491d043a412696d4fd769bb2f5d8c3e8b3a59e6ec3bb598f775a7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffeed8d2da2afa9b9823aa74a344f6eda5d4b80e5de83caf8455b08c8aac6c4662000000006b483045022100b430528ddfca4431cf5cec08964f7325c036fdee55edc0ea0181d34ed72469bc022074b75bfa66dd4a87fab93da0f2f0def65b785fb0b51fe07355799cbd8b30c39a41210316d35753d58318c06d0faadcb723563316847ae06019984f42f2c75deaf3727dfeffffff4317e8c939993e123310aa4d84dfa4a29ba8dcc0b4c222384ded077936279955000000006b483045022100c6ccc3891fa3924c7b1e69b855628230c48d85d1e1331f037823ab7c5928610c0220050c9c0e078f34ced537e88f95289863a663b28488880f6ada3f1dbbcb1743a1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff85aed5e452015314973015efa03f0bd2c79d57d976ce3f3ce14498b294fd5b7b000000006a4730440220168f31f413d65ce64bccb62390490dae2e4a00f98c2c44bd4fd689cd942da8b1022006f1b2aa4fae9587c688e8b7ca5c07db3b3c3afd6961f9f843099ed30b583369412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0286800000000000001976a9149a262d0621819c8c17d34a7feca1b39b39157af988acceb18bca1a0000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac26550900" - }, - { - "txid": "99300f90ced7d053b3b24ef3a8fdb5774418e616f07971366a63b9938944ab2d", - "version": 2, - "locktime": 609135, - "vin": [ - { - "txid": "f0202389fab209e6975199ec2d8abf76fd4cea5d7d441ea0938ff47a35366c45", - "vout": 0, - "sequence": 4294967294, - "n": 0, - "scriptSig": { - "hex": "473044022001b8ba5dbc580e3bf4419b65892f15423e8b0e48d52479fd0317fe4c03ede0a002204013a50c3914aeb7f59183f9e44c880bc94fe9c23045a6311ae4b07da3c2d209412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "value": "12.50016811" - } - ], - "vout": [ - { - "value": "10", - "n": 0, - "scriptPubKey": { - "hex": "76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac", - "addresses": [ - "bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7" - ] - }, - "spent": true - }, - { - "value": "2.50016585", - "n": 1, - "scriptPubKey": { - "hex": "76a9146932df2f990838523783075db0b985b9bd2330b088ac", - "addresses": [ - "bitcoincash:qp5n9he0nyyrs53hsvr4mv9eskum6geskqthlx9n4d" - ] - }, - "spent": true - } - ], - "blockhash": "000000000000000002132a5e60d7b9de0524eeffb36fc91972a7d68afdf17b65", - "blockheight": 611545, - "confirmations": 16408, - "time": 1575274423, - "blocktime": 1575274423, - "valueOut": "12.50016585", - "valueIn": "12.50016811", - "fees": "0.00000226", - "hex": "0200000001456c36357af48f93a01e447d5dea4cfd76bf8a2dec995197e609b2fa892320f0000000006a473044022001b8ba5dbc580e3bf4419b65892f15423e8b0e48d52479fd0317fe4c03ede0a002204013a50c3914aeb7f59183f9e44c880bc94fe9c23045a6311ae4b07da3c2d209412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0200ca9a3b000000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac49f3e60e000000001976a9146932df2f990838523783075db0b985b9bd2330b088ac6f4b0900" - } - ] - } + { + "page": 1, + "totalPages": 5034, + "itemsOnPage": 2, + "address": "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme", + "balance": "0", + "totalReceived": "12502830507987", + "totalSent": "12502830507987", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 10067, + "transactions": [ + { + "txid": "0284cb9b8deb0534efa8fc8911db1e8f9b106d00608c712d31c3680f303fbf36", + "version": 2, + "lockTime": 611622, + "vin": [ + { + "txid": "2f150ee63214982edbaf23c85629e920e16093d0506ed284ec3018ebe8746b12", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250119473", + "hex": "47304402206f992d73dfa7e518b00190f220ad5dc7b7947b1d75a2fcd8251b59f3d29d89af022036c6c44f52f9aeed406dec72a9aab1f82c3b997c36742f4a3504e4f93e6f8557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "550ba873216e6690c8ca34992da41ecaa29e74a557943af604537de13fb84838", + "sequence": 4294967294, + "n": 1, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250052374", + "hex": "483045022100db30ebe47536e42115a507f88bb8d5c97b81ad05ce334872235811134c5948bb0220418d77aed78cc4a332b1858c1d2e9ab169828b9c12e8c0d0f8d155964e5d0b8e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "ed8d8d9810ca30cd0512a0e0ca87649713a550a015bb0022c16686c2ccb22143", + "sequence": 4294967294, + "n": 2, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250058021", + "hex": "483045022100d30c9fd598613586d8d0460fb6c9ffc1d0c6dff6f647535d2a9f69cf373193d102207fff687aa035910db124adad8b59607a72b3d24aca9096217ec6b90fa132a2ae412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "a2d79bacd53918c9ad6b27055eff555130f1af8522f77a09c4d74321dad8a032", + "sequence": 4294967294, + "n": 3, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250022804", + "hex": "47304402207b30e99cb1f6754d227a4511c5b7791f3b896724b170716d6ed238017f191bb102202c1fadc4c572c86288b002a0d6b6d2460a14a6d3c8b49efc17a03e59d2db18e3412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "9a0679dc735b7774ab3aa55a01188ce4d70613927b1b0ca9f96784b09479f762", + "vout": 1, + "sequence": 4294967294, + "n": 4, + "addresses": [ + "bitcoincash:qzqn6xdqhaqa8yykvq4e94td4yg0k9ll9vyjf47x0f" + ], + "isAddress": true, + "value": "1620505", + "hex": "48304502210092b7f176f182936323df8e4359b2a329b0c1e4b48a529d6e32867038a2a453cc02203c24a8bb46b7fea4ef5c78ff116a51fd0a04dee25bfcdffe856fb8988a7a97f64121035b4e75dda9fb0d55d856f54f24fc65da6657939b9559ab2c623c8ef325f14d8d" + }, + { + "txid": "5d557c0c3331dc1dc4db34776603c01ce24ac8b0adf1f6fc2cc07a88baf5bf5c", + "sequence": 4294967294, + "n": 5, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250096547", + "hex": "47304402202a2bcfdaf12c398ed5372e6b168a786edb8972df1146b705d3cccf2d9601517d022020b90ac89d9141d68817850d1cdffaf6c51f45249a44fd6861b361a6025d8ac4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "61dbe706b513c1ee5aa577a07782471cf5c0c13fd7ce31b29cdd1c2362ea0bca", + "sequence": 4294967294, + "n": 6, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250179897", + "hex": "48304502210087ef2709b9fe8e7f136219254229edd45e94c3f6ebd2bb149aadd9b1d44d89e202206ffde3c9491c012832967e4d34e02ece2c08bc4c07967b3b466d4800f9ca0746412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "54b28d128142bb03aa60e9cf535fe30d5916089f1e70ac94444572008e9b3b84", + "sequence": 4294967294, + "n": 7, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250044246", + "hex": "483045022100c7dbd1117c57eedc8fc006e818371bfe6399c4d25e8b40482c1f0858a3d98a4b0220426d1196513a87fc7afb5b107b770a90af789536799a11686eab96b04afa6326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "750c2e638eb26bd271586fe201f48e21ef7fcef1154a6b6335d2bd4381450123", + "sequence": 4294967294, + "n": 8, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1252404910", + "hex": "47304402203604fbb20824443899030d2c1f5cd0dc2b88174929861a708bdca878868e910c02200a607b1da53483bc95d3a5c54e5ad66e459827d4ecf8b4ef9909e9d58b2d329b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "9b6dc387b59e4af25bfa14067e24c399fae3fbb744e97edb670087265ebcecf9", + "sequence": 4294967294, + "n": 9, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1256320052", + "hex": "4730440220399c36174173cca01f6d6a234a935d6f776b549e1ea2fc2635193924c4ac2eb002205aea7741fafd95f862588c480aaa282d7a344d32d6318aec1a908cbb939e5d0e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "8f27da29f81ae3ac3ab90f29cd4988d718cd351f965892b073a80b9a9492f49e", + "vout": 1, + "sequence": 4294967294, + "n": 10, + "addresses": [ + "bitcoincash:qz8mkaldpk8zk2ge27wpn8ue0uwu28xq5552u5c5my" + ], + "isAddress": true, + "value": "1687043", + "hex": "483045022100da9075310e7af59456423be99362f2cc686d50571e0f0b016bcfae1f0bc4692802203379b648d47704dba48542b8b6d5e515bf3c4fd7ff8a7be82cd0c8c0c7be56f7412103a344a84dc1a919a64874605fae200861b7af3ecd02dc5d52dd00eb6f8845525a" + }, + { + "txid": "109bf48f720a9d05fd7a74b632164ed96db721b00458420595d799b437305f5c", + "sequence": 4294967294, + "n": 11, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1251895732", + "hex": "47304402206cbf93634d6a477a571fa2884c19918b19ddfb008ff9fe405954720047efdb88022003e755313436d406dddfe3cfb68719e8f39e43de7c586489cc543dac0347da9f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "d3e570366f647db1f73079b743ec994169875c7af42ff2e9f3cf290fcb3f180b", + "sequence": 4294967294, + "n": 12, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250081823", + "hex": "483045022100f23d4cf11fd0a5ab83dc053ca64066cbdd2fb4107e0977a3a880c68a67636f7d0220220a47c66d3944cfc309c059fe8013c4de742e4d8590003fd56c5e0b3c7da557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "6f05f99a402127463db6dc2f8f6b1064109fbfb93bacb258babd2aa861055480", + "sequence": 4294967294, + "n": 13, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250020672", + "hex": "4830450221009f522beef55cbf8c7f10e88739846f78ef1c9d9cbc6959dba6f687a08fec0ef502203a160231733b87c6cfd8afd148994c9b6c5d5db9bb9847aa9e60938a6e79d5b1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "3d93b717b0676245a3dc3fb86625d9abffac4f66e2889a81a07733a14e1e4a4a", + "sequence": 4294967294, + "n": 14, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250118486", + "hex": "47304402201f5d29be80192a752fe28ff141ed702640df88083faf3f9573e52405cb4bd79a02202d751649aa600c4fdb8b1d1b21f0d134c2f4e5af9ecbe7d87180d667140f0a11412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "c77ac92e646677bf9e59873c5f5036831d5d5597cda469b7e6b30a9563a3419b", + "sequence": 4294967294, + "n": 15, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250097156", + "hex": "47304402203f4bea3816d252cb19d4247f587a146901c74d04e783efddfd5089942f2abcdb022069012613c4ee4b3b0212ae71dbd2071e01665148697011eb03eba25431e679cf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "90cba3db7e020c7b8943293ecca7f6a2150082a372972c0ed65646337b0b05ab", + "sequence": 4294967294, + "n": 16, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250175150", + "hex": "4730440220782ba77287116d5d735f67a3738fbecc1a802d2141a1fa544f61a5e8ba682a4402205473d68019cc8895ecb1d87bfced62ddb6dc48b81152f2684ae8530122d5b41f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "e25ec382049a4d8edd530469e5e41d9e056a2081b661f505414b1348e482dd26", + "vout": 1, + "sequence": 4294967294, + "n": 17, + "addresses": [ + "bitcoincash:qqnfldeu0yd4wd89c44sujdz2w7hwvvd3y8g9tuech" + ], + "isAddress": true, + "value": "1884419", + "hex": "473044022044ed9bfa8674d7e83112fa22280797169d45bd971b185da2413e36252637529d0220531eefc480e0911d6ccda42002942883149bc1cdd1f3bbde313751d80bcf98b641210328ac4ed2b30ddc04c778a78b24e7256b08c55758c1465defd997ff4bcefacf10" + }, + { + "txid": "13a148dff09d7786a7e0d0929e7ece3c9fb8de532597cbb0d045f5ec531b2e9e", + "sequence": 4294967294, + "n": 18, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250028570", + "hex": "4830450221008cfdfd352e268dba2022e7fbfc37a90401c40fdf6f1d8ba9dcb97d67743eddc302202c0a1b604d34aa174fddef63c9115c95465548855c5f783bb206eb4ff8fda235412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "700dfcfa0847678c56a084b5a75fb8aef1b1a1126512b026ebdb8c45d55efdf9", + "sequence": 4294967294, + "n": 19, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250039508", + "hex": "473044022001b33b610b8d742df2ad98679f1e41f0c647faf272e15e7ea93171ba29c33bcd022061646fbcb81ba30d6e8b030ee12101d1f1bef38ba44a6d5daf40c4ff6d644e6e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "6810932357166daa33c2125cf38be6076f7b6f718f199348905459f22ba7f2a6", + "sequence": 4294967294, + "n": 20, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250136993", + "hex": "483045022100ec9b6bbaba90d8902ec8a1ca0e90ea594264bc1add204b756cc89def4d7e9a2a022066b2bc84f94e1a99effe0e929be8de8669631143ca20c73e700d182ad4884e71412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "42a98564873f7c888a6a569cb97066b4bc43c5fa41d732573774f996b91980b3", + "sequence": 4294967294, + "n": 21, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250053520", + "hex": "473044022057117591cc465c48da58ebcb8f57fcd56359757d41e1397e45b5e33e034ea5d8022001de1d78ce9e8e73370a0778b4a8595045c6faeb2497ab4296d0cff735711276412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "f7b56e95b5a48a66649fd3e9e9bc94a7a01bd1c4822c4dcc2c40243c8da60bbd", + "sequence": 4294967294, + "n": 22, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250111141", + "hex": "483045022100dace56650d1d9edaef30e8c9ecb4b78499a573984c8a451253295a90c84a3ed702201f4587d4a760cd77a2e21d5f6f2b7aacf668220c8c7c62fc1ae4779f7c0141cd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "d58b912c125283ee0249b670a7901bd5a1061d92f7c06627b5e963fb0b2c3d14", + "sequence": 4294967294, + "n": 23, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250143132", + "hex": "47304402200db6b461a0082807f59053bea210d38f5f82f02dd63a57f6e3987339cac23870022064ba927fc11b36318785d4e861a7f94cb3909ef8fe882360e2041f7b4a444692412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "530326ce09e8f933a604488e5e2f06845c3e805761c02eced5cc02856be1b7b0", + "sequence": 4294967294, + "n": 24, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250022822", + "hex": "483045022100a3e75a6c7918db32a27be348493b831631856ec8f546ca43d143cdc3c1cd03c802201e6ae036423bfce45c500b0c049f68396deae5cb999038de61e972ccd4cba5e7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "ca51412ad37c5e5a49b11dc7858b4013ff68288c56e6026b11a4266e184b286d", + "sequence": 4294967294, + "n": 25, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250033136", + "hex": "483045022100caf952ca1760052cfefe8df283fdd0eccb9e1238eea88eef287df9404c622e8b022072027363fa1070548576fbf9bcbddf2e435fd020662b2d8f0582b52bfa487b31412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "c03e268bbb105f171305f7fd994c0e15fbff5ae3d08f3c332c48cacca66bbb38", + "sequence": 4294967294, + "n": 26, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250037356", + "hex": "47304402201a4b4efff2b70a4039b4dc120141da04ae84f63906df10c3cad08838c01b6b8702205a065d025c338547ea07b2095ad31252658e57f1a7a04c7f4eacc0248e611fa2412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "46c8b9fca6423412b3d40cf7606b79678807d75b2be1e848765c40f367b326a3", + "sequence": 4294967294, + "n": 27, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250061192", + "hex": "47304402206b0a876d78793710acaa8bbeb58a2d908bd4936f2a88825f944b190041b5e0be0220279560be5009e4a3fab44d08f4748e2dead710a8ccc77e06a03ba8112d728856412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "fadc6b6f3225ea8686c7a03cd8362765f91e604c260beaf965c4e7093fb16b74", + "sequence": 4294967294, + "n": 28, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250118669", + "hex": "4730440220799bdb7ac60cdf3314cc1f157299858d353e22c00354707337ab5b497619d626022000e41053afe44fa65227b7dd8498300a2dc89367d9daf0586caba5bffdfde567412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "adb5163c2bd4b1c35c1eac2671e6124e6c6b9b6c3e2abdc8372601528600a98d", + "sequence": 4294967294, + "n": 29, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250075561", + "hex": "483045022100a1af33a83edb7fdc289a48a4f77cf286a88b38c21ddf27dd4ec3df007ce11046022074dd56730730f958039efd70edfe7e181060fec306c6df4cf75209600ebebed7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "db1a00011dcc02708d6757b7435a3163d4dc384d8490208656229b0780b4a184", + "sequence": 4294967294, + "n": 30, + "addresses": [ + "bitcoincash:qzduecze3gvxk6y7rcjmvnau8c3ncddvvvs05z5gz6" + ], + "isAddress": true, + "value": "1400587", + "hex": "483045022100eff445419ec63d1e9f51a5324c3be0315911b39f30657639e84ea7d2f739e0510220218e73140a39542ec8055b6645cbb7989f96b9d9a93c67549c059509de06f0ba412103dd71b53aaa823b09a68aba30c7603c6a397e7c183f708c9dfb0d9d0a9cd1c722" + }, + { + "txid": "df69893e75d4acee084666c023822f07196dcae429a07b136fe92a87262f87f8", + "sequence": 4294967294, + "n": 31, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250118543", + "hex": "473044022050b7ed06a6832b8831c08ba86049b3793b5a71fd6d5177c9f268b79c3074bca7022047447c23429de30c361875642d9058bf1b5e0e6c5516d6e71b70b7cfb29827aa412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "8432efebc29ead31beb783d5d27cc379fa31cee352cc19a75746768b2fbfbe7e", + "sequence": 4294967294, + "n": 32, + "addresses": [ + "bitcoincash:qqfs2vp95prfunn2r9wh5lf2g6k7k6jjr5qld8a37e" + ], + "isAddress": true, + "value": "1772743", + "hex": "483045022100fb072bfd399dc11191ac449a9d60119bd191ce6b19a5d92412a805ddc8d4b46f022021e463686560b15ddf272b9943d8e41425ed500f77698aba518ccf546a97aeb4412103e35c58a738805f53af73472ffb671a9bd3556ddef47c62f18ced868bb5033d0d" + }, + { + "txid": "29ff4caeaa127c04ecc8141f49462390a13febd47877abda62a7ebb66658f0ba", + "sequence": 4294967294, + "n": 33, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250075582", + "hex": "483045022100b25e7d4ebaa0e7d8e24498b039e756d568b67316aa14d05abafaec59e216a73d0220010d0b6548a74435907eb0d548dfe8e52a949bbb785eb2be3bce14053953784f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "3b46f445ddc1b8acd4fa933fb8d7dba9bd95ce53a579339b32a1e97352323013", + "sequence": 4294967294, + "n": 34, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250043307", + "hex": "473044022007d2baa9a766c120e111a727bfa8e8bc2e01cc285d4d4f67d2323b213525a10c022020f32be2d9935b6d9b5091db27ebf00aaeb54adc7032badc7ad63f20741ff28a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "1bd4b1e18be85528e214e16c69f459272ec126ff0dfd1948de6838b5b50e5344", + "sequence": 4294967294, + "n": 35, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1251821842", + "hex": "483045022100f98ee28ffb66acd04474a120904ec1be2327d727d8ed8fe99d8b95c174b8f46a022041d21406dd8df10cecc1d6435de68fef3f9db71838c1ca2910895bb184b4a6e4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "067492a2b7fe0787a44ceba7d6ee64da25aa8be08357576e4cef97ef76babf2f", + "sequence": 4294967294, + "n": 36, + "addresses": [ + "bitcoincash:qr99zjexsl5dtdu38wu8w7jdmsmcxtcr9qw64zjhdk" + ], + "isAddress": true, + "value": "1843864", + "hex": "483045022100ee3f7961f0f23137d753affe85b777e94c1db3f656cf41b8f59fcf82d9226eb7022025009482a6c0002e409590075caf7a78023ebc1457f100c8b922a4974ebf86ba412103f1d1dd7685d3781f58f9aa399a16f6bb9ccc7d008cdb7c63a7945cfcaa6ba0e2" + }, + { + "txid": "bcc168ae5cc9dd70fabab262712036bacea7250db404c0d5af438b0b085c52bf", + "sequence": 4294967294, + "n": 37, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250034365", + "hex": "47304402201fed9da4c0526ac5ce257fce2b7fc995646b5f0d2961396327f93e2dfda3e4a0022035b217adc5a9be2ca34f4361ceafd9f2d09a6fa47d4a767f7001ade40c08fe26412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "025d365f0471a48171c3f50ba4e9ee04ee74f72c2e8d0cddca600f3a900b7b32", + "sequence": 4294967294, + "n": 38, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250085848", + "hex": "483045022100fa8ee82d42f524290319fb3ee47a1afa70cb952f8a37325680d6fd651ac3699f02205ac0cd86fece03ca204bd881d67ccce0cccbbc98704d9e955e2f92b5b77121dd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "c61c8a5fd411f160bac0e4b4e703e1caf7d3f8218b0ca5f2aa7b762bb9d3ad5f", + "sequence": 4294967294, + "n": 39, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250086233", + "hex": "483045022100f3cb343c4704bebbc78c6492dd72ca19c388b285f44f574dcff25f993add6d5f02200e050dacd78de955cf552f9158beaac5fa64995f5bf7c8a919a231a39425730c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "207dd74726483c593b21c180a9467166af7f5b02450fd3613268cea239aed047", + "sequence": 4294967294, + "n": 40, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250080933", + "hex": "47304402203f05a035f5d42fbfe97172b431a613110ad733e356ebfd08886fa11bedaf1faf022061c4a3bc3417390910612bae46f5acf8b6e8a5b008d273a52e483a315bfb950b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "facaafec82e7853c85dca5fcecad9c62d830a2421c98e8c5896b793966face46", + "sequence": 4294967294, + "n": 41, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250075132", + "hex": "483045022100bf60fbd4716339bbb42ce150966ad6caf90b14e57f45eb6804756cf8ff36b23a02202f16aaecdb9994f3b683cc7fab45bd0a3f54795c336b5fc224fc51270a7f3f4f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "26703badea466dcf8446e1ee49868ed4259ff22e0f13460db9d79819115b5c4e", + "sequence": 4294967294, + "n": 42, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250118800", + "hex": "483045022100bcdcae99c9289b5fc89d3227daaea8df7d0a0f3a8971d841ebe1ab7a1ecf72e202202ca21447a6b3e96540e32529697d523b7b08c65845d6a13f6b1475de94919bb6412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "c94103172a643e1ae22c3955749bf7af337a914a48d124fb5cbaae1ab5fa9e48", + "vout": 1, + "sequence": 4294967294, + "n": 43, + "addresses": [ + "bitcoincash:qzfvx98n9r4yzlvk2h736rn3qftpl2uttuu76kvt5x" + ], + "isAddress": true, + "value": "1631430", + "hex": "4830450221009535c27b5bbca0db2bcf1a0d0b3b283a2171df53f0d68f1a138888fcc6ddd996022068af19252ac4376cffdbfaacb2e0f0c216deb7e2478b586abe7c2679501eac34412103a47e5dea4ab8d785f4e00994d0faf1a8f384c41e74ed8e4b776fa6ce136ebc42" + }, + { + "txid": "180544709d0cc711566118b48af548a7b199c639185685c7228676725c28ee7e", + "sequence": 4294967294, + "n": 44, + "addresses": [ + "bitcoincash:qrrv55s5ag0dduyjsc83ds7hstqc0m9htqk764mtaq" + ], + "isAddress": true, + "value": "1078385", + "hex": "483045022100b456847e29f8a648730f0fd34cc7edcfb35daba866ab7d800472beaf2836ce4202207db401f0a5e30efc53c7bf58e57d1dec5874d64768ad9eb4895351cc4be9226f412102291b40a9a927dafeb53cdfc7e722ee5c9dfd6eac2d81331678b9ab405bb25d21" + }, + { + "txid": "67c24b19a0f444541bcbcb15e708f7713f5168f89f3d42df51d1909f6e22b093", + "sequence": 4294967294, + "n": 45, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250191671", + "hex": "47304402205ff244c77726def0e3697a3e546bdf74c7f31479c9d01a7a6f8cd1656482d537022045d78dba8ed4d3777f473736daedbdaca6f5698dd306898d144eb43f96259766412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "208d4a8a6afa218a65416286733a5158e7ca393003e30f88dec606e771e384c7", + "sequence": 4294967294, + "n": 46, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250036468", + "hex": "483045022100ec6b35ce6d24889726480d70a31bc0d62800bf7ac49ecf084b98137322606bca0220432d33e2d8b508f26d7d813d18629453c537a4d90f73a104bbf80627f9fe8d62412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "60a7eef8d0b9e7cbfe602bedebd75a80121587af1236fcb8ddf00e510cb4caa4", + "sequence": 4294967294, + "n": 47, + "addresses": [ + "bitcoincash:qq788skgg7eqc7unt733wahchmx08h87tgn20l2n3l" + ], + "isAddress": true, + "value": "1329593", + "hex": "4730440220423ea635717cff512d9262b7c8932c0122ca868251f019ae033101c28771a52302200cd3ae05f2e88d9f64207beb4b715ba480bde9ffdd40ab61a36feff88f2968d54121035530745f3cd4d31532991e460bd2a15e1944e690643f73133a9918edb95da53e" + }, + { + "txid": "7033ed9dcbb1af754c41046bf1ec51c16285336abc235b9485dd9c8829f32b85", + "sequence": 4294967294, + "n": 48, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250053803", + "hex": "473044022055cc4dfa48a79b8584a9352be34ab5fe9cae4132d264dd827d14ae06d35ad4090220652a83c93505f8a8527c5bc0479f37da0593595c1bf18c12b8fa0b41a2e37a64412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "929f05541924a6eb7dc7f2e11310037de210718c5896b9d9475ca5724dc13532", + "sequence": 4294967294, + "n": 49, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250171060", + "hex": "4830450221009acc8d0e06d10b0c764a27613bcef41fc75f910875eae3989a7f8725f81814cd02207146ff66f412910ed993fbda4ad6ed48862a02f366dd88a83856a17e7f96d83e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "a7e965c2d147a2bcc7d99f61bada49696703563d7b8225c9e69c29e312aab0a0", + "sequence": 4294967294, + "n": 50, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250030500", + "hex": "47304402202d8cd72290f04063c0ae9bc06d2cae3ac74ef4cb6945c92c3e3ccca210c127ef022030471726cd87ac9d55f3d246095f64ae22b611aa8791922236bbdb19ec273322412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "e6897dfc8254d449f61372cb7c4131c4caaf2781fa60cf930a36421d0bc156c8", + "vout": 1, + "sequence": 4294967294, + "n": 51, + "addresses": [ + "bitcoincash:qq64kqwmv0gu5naq8ztaj5ecef3042n3pceymy9fw2" + ], + "isAddress": true, + "value": "1746309", + "hex": "483045022100ffaa954e5b86d54ece9bcb9e37895047221828ca381b03266de3d9341599c8f902200ea1c5ed36e893df822c698a474b062d4f93005c32f9d2f0d78ecaf5a56e4fbd4121031a00f43cd99e015c72acace20ac47d887a39ef284f89a5aa09abd968d06f5e9d" + }, + { + "txid": "d69c6ead378471a3f30a9a7b10381a88bd8c5e343b8108a0f189f9f665901269", + "vout": 1, + "sequence": 4294967294, + "n": 52, + "addresses": [ + "bitcoincash:qzudxte3pz9qf5gmnpr5yxj97kv3flcs2gv5mct8gm" + ], + "isAddress": true, + "value": "1792586", + "hex": "4730440220457d59caf24eb6e10664d06f3e936f6ee31d9d59f1cc4f6f62788f022bce8c1b02202ce7c37ae6832b078c1cb9a055e3ffcf4674081f0738fd9c3eb4465b52bcc9ca412102fea9ae922223f2c68c68d7672b7656885c3e1321d35cc8f5f445179df6f7d27a" + }, + { + "txid": "212aa8288a75640e62292417bf53dad20d242df7579c38fa10f2f63d8c03d38a", + "sequence": 4294967294, + "n": 53, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250046573", + "hex": "47304402205e0f5cb06f7fd741825c669c87e9db1a433913fb8577adb92b779d3a693b4f080220120648a5f9d2abae83a29cd2c79f5c61b9bc40da8990736ab97ccf6f82c586cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "3d6a1aebc3f48b843e408421c9f421d3934670d86a3f5df49a6530152056da4f", + "sequence": 4294967294, + "n": 54, + "addresses": [ + "bitcoincash:qrt6ljgpzzmamr2ukg9a3jxe46ufaa8fr5yp6f9pfy" + ], + "isAddress": true, + "value": "1801618", + "hex": "483045022100debfb215f94e9d784e91fe0b9d2541d09a4c7591172fad1441506db4a3590fd102200cce728e344933111c9548162e62872fccac624f6f98d92ccdcf98dbed09ac544121039b8a20c23f32f5b14e76fb29e0baade695810aa7b6dac9e9638a8d13b6ad8221" + }, + { + "txid": "91585d5312b1a4c8bca993b6db304a65c7bda601113960cccc978f28c381bfe7", + "sequence": 4294967294, + "n": 55, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250046545", + "hex": "4830450221008110aec39b127143891069590fa0d9e1d8b41bdda70d9807848eba92cb48736b02201bcfdc1a1cedfa4c53efd941482f6157774b2aa80af44e500263be6a3cbcbacb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "b9b3d23c90954095289ff5feff55de3cbd7469cbb179e38aa74dc813fd6b684c", + "sequence": 4294967294, + "n": 56, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250022645", + "hex": "4830450221009f76d6838b8fd8bb74f50c67920fda9f28054d093b30fd03b54b3fb888db046f0220307944f3abec07c3570614f418056aeff03c0830173c963bb0b65bd5ef24b4a9412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "65f9a63b7bf753423cca4a5ec229f566e61cd1ec8f745683da2a934b1308713f", + "vout": 1, + "sequence": 4294967294, + "n": 57, + "addresses": [ + "bitcoincash:qz86ljat9dnhjp2wplpm7ncfm7q69hk58svu9g46ex" + ], + "isAddress": true, + "value": "1593178", + "hex": "47304402207b93e2500b189b51fbc3a49a191c4b92ac76e32ce86f6f1b9af4afbb3a91fbe002200b5617cf52095bf882a5129f5477f119c9c565dd582a9f19493cf1bdae6527ac41210323ab0930ba40688e66bef6e08f673bd6bcd3df687e4c503387f48c24bffdc93d" + }, + { + "txid": "48ddbf6a4cc52b15bb4d2cb7e39fcecae29483bcd3d6471e3543785621f3df7e", + "sequence": 4294967294, + "n": 58, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250019587", + "hex": "4730440220731ab37e71d9c6f63333ba205a318d36e5847706381f571b4b562e5e6f6e403c02200704ca9d9a33843d9a16135f56eced1fd18e227385671a8df5fa41e505e3ba3c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "5027ac365cb55b21278f32710703d9ad932912919c58de364e1eb1e9d79412f7", + "sequence": 4294967294, + "n": 59, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250045268", + "hex": "483045022100d1d3565175e1f529124ebba1bcdf8c1704e753c2f91ddcd1a093b5f5403cd0ed02207420ee9d6082356cba6d8075b4fbf310bd84dc770734a8ab30e74741a779bae8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "93cc92162ee854259d3b3f9ad1886847eadb2ccc86d03bcc6b89718da9ca23f4", + "sequence": 4294967294, + "n": 60, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250086952", + "hex": "47304402203ddf5c6c5065f03229cdf837d9f8d3d22314834b006e0aba8dacabea206b3b150220417c49c9095372d3dfd954688bcd43fdfd2a121989fde18456a9428b2a8e3c63412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "c672af6e97eeecc79e87e708d57e20e2c7d811bf3431eaa928f7efc24b663dce", + "sequence": 4294967294, + "n": 61, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250143426", + "hex": "483045022100a20e6aaca7df2b142b768d3b1cbf8f783f3d4997d155a32f0e066b4255777c9f02206deb15cf53d6b27a973df9aa7080691e5914538d9e97ec7c6e797ce03333238b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "5f64a0a07336a2bad8f9611709653146fad9fc796f1e92dbd12afbf0d6dcf5b8", + "sequence": 4294967294, + "n": 62, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250125454", + "hex": "483045022100cc2cf5c6c2d4862dfdf65407138684ba45565bd8ec46594ed4586bfa37b715dd022013255b2eb22f5bb93d2afdd07ec4c3b5efe0aa16134b2fd084c6bc720f8cfd5c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "256b18d5861752fb617796cef5ceba05e42de141e48aa2737c77020e8d1f337c", + "sequence": 4294967294, + "n": 63, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250058048", + "hex": "47304402202c9dd98c9a72e5a8df4b01f09d18e2826d8b9871db89c5d3b24ffd673facaa0702207523bfcf3ab80790167a2b1159fe268770371fcc7d770995c19eace3181ec8af412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "aeda3cb9ccecf67cabaae458862b2068129297b1b502b862067f578a2201d54c", + "sequence": 4294967294, + "n": 64, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250083898", + "hex": "483045022100bfac8828df10b7911d341c15a532819c429c7185d8883de19de84e71b97d78730220177603a3572908c90dad865770906b5ad228da7ee5da39503ececf60ac735158412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "0b11e279a95eaf9241bd55fd7f7b045e2ff047b307b25f3885feb6a71140d6db", + "sequence": 4294967294, + "n": 65, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250050928", + "hex": "483045022100d598e2ccdeecfdfea9d5139a49a94fa39414f9e1ecb13d54efeb34c168e58aec02202a59463710905613844f48dc71d316c0cae54ab9e16dd95beb8902e5940024ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "82026eabe17877d3aae729eee2612778389a9246d56b8032706c454223760eb9", + "sequence": 4294967294, + "n": 66, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250039790", + "hex": "4830450221008302d38e9eaccaea812c853047931562417a3665b8b9373cf7f63e58180b002602207ac8fddbbd19560a74333ec92fa077d169b4902a41e0431113f8fdb75b304ecf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "43a94c82abb414437ac13038fa5840a6038733dc156bf160cf30db31a82355e1", + "sequence": 4294967294, + "n": 67, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250105160", + "hex": "483045022100c0d85a1f9146e8ef9efaef8ed9b3ed09c55e51b25e189735610da89b6d212360022003a49114e504741befcdb95d52a3dedd1aadef68b7c48f0a4a8c7dddfb4201b5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "41f835819365a32c2ce1138c131a4039c6dfeb034d922af573d997697b409378", + "sequence": 4294967294, + "n": 68, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250127067", + "hex": "48304502210091ec8402cafd1e7eb11b56ac56a994ac79c435893108d0b7c8cfff87c07ba0a602204fd98efddc1b4e21bd3cb81217579a7b9621f9c3c204f2f5800e75ce1c60b19c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "2f8ca9dea380bd026636e2281f1e42e63dd54a04be1c1526574994450ca36f01", + "sequence": 4294967294, + "n": 69, + "addresses": [ + "bitcoincash:qzzkjplzf0yw2xej4u9he5pr5evgup2snqqxs823e8" + ], + "isAddress": true, + "value": "1366913", + "hex": "483045022100a850bf088a08baac1f1f577da8946befe2e6b0354d6a29f636afd39982569a7e022062652d6b75dee145f741d28d6f1870fde9a7d66b994f0d3162abdc42fbf54458412103ffdeec10b52942b0c46d6578998efdc1d64073de579e92e7c5dfa97fdf3ac391" + }, + { + "txid": "404829243c500005d37a95164bf6610005ccfa19cb7660ac9c1ee0da009465d8", + "vout": 1, + "sequence": 4294967294, + "n": 70, + "addresses": [ + "bitcoincash:qq4kx2926zmnhfa36xzfswf9p9raqlapmysqvr4ck6" + ], + "isAddress": true, + "value": "1292340", + "hex": "4730440220762f7c017672dfc71d487f3730e26d69d0e53902f579ba348095ca164d27b094022076c7e8045ec9fc57af6dd95f35c0ffad2c0ca8f83f112f60fb9851ba4ba15d92412103a2d2d8251728b11fd4afe7b8c73a8442f76dff9bfa424f5cad9b98083936259d" + }, + { + "txid": "2624cad28a9b7f55434b68fc8be7aadb87d40003d786f0e414cc1eff74a12b64", + "sequence": 4294967294, + "n": 71, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250134907", + "hex": "47304402200654032c5760f8b94cc089da51773447f19c1cd2108cab89bb53ccfdb6dbee56022015e277622dea4bd1a7913ff934b2bb2d1b3d75f05285b51690160e1197a258c5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "893b3cfda77c1371e21df17e45910578fd778958f9b51fcebb24a2e92c604d65", + "sequence": 4294967294, + "n": 72, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250033040", + "hex": "4730440220712877c0dc553096eb0ebf101d1555fda5235db26ad074d2f330163fab63fc7802202c89752dd7645e8a3da7e8af5fb68dc8b177700766b79cf6a35695a0c7c873cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "cd86f3aba8b0553de0041a2173507a34f595a3785dbaeb8c9b2cc1c1c34c61cc", + "sequence": 4294967294, + "n": 73, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250105407", + "hex": "483045022100f3fa1e305666e2a62afaa11fd37025b25c0bdff8709fe1580406615934228cee02204841a7d96f36d3c183f06e22a58175756c3e9a76c93c7cb4e9945f31ddedc902412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "ae8ae862b5ddba89e69b42aa8a6ea2693e61f90ad3a5625b5f81605c7aedb226", + "sequence": 4294967294, + "n": 74, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1254457185", + "hex": "473044022047c158e3fe3f40de3f39796dcecb7df3cf344f14009de9826b62a43837f2cdcb0220759d823cc145fd5e8b651a7bcc399544692bbf596189b1fc50bba5f4ca02cdd1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "b402b3d23c910e0ed869045671269210f6594f308b6b01a0bed2052f6012b0eb", + "sequence": 4294967294, + "n": 75, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250101109", + "hex": "483045022100bd70744c867943bc3bf578e192c8a87a5ed5126aac4acd98efa06ea2483911fa02207377e11ae2d2bbaab00da86ec73c26e596bfcc680c0b8eddc5d44bda650bc299412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "e1deda4073c863ba018bd7334f625f79884854006f27712cd010e57bf59c8087", + "sequence": 4294967294, + "n": 76, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250083658", + "hex": "473044022059ee25066b8a2a4fdfc35f14c5cbb7f22ab181fcfa9702d4f3de7aa4d738c7a402206dff315ad1cd2222cd6ac074bf34241fc22db38a57bf089f7e24542323f1766c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "219c39d91c3d5d3d1f81c83ba373df7ccaecb45f5e4a2f7422bb2021afb7338c", + "sequence": 4294967294, + "n": 77, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250032757", + "hex": "473044022039657cdf4fcd5a9e81766ba11db495b8be5664612d3b91f8504bea342c4ecbe702206ca4913e5807cd697d30dbc93e0a9d679eb01ee84b687ab0c642e2f3ebde745b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "3a1f594a74bad6de4c762a78a6c06db3900c45408ec0f785c61bf9f29bc34281", + "sequence": 4294967294, + "n": 78, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1253061599", + "hex": "47304402200232ee94873317eae275cf715f4c3aca25dd0c8db4800946a45cc1d9c45732fa02203d9ce9c9aedc0a3899dd027df32e683438769d66f33ffe52006454614b77821d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "14cf83e6c8b80366b8651c6b4a0f7d2270290066325d686ba671ab5c4c9a3b50", + "sequence": 4294967294, + "n": 79, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250121784", + "hex": "483045022100900bdc6f705efa56449a65f15a67fc7fbbc102f78e7974ea6ac2849c75d2dfec02203b78de71dad2e3f6ffad2779cb9007217c957c8f5db7abd58fd0537fbabb8c6b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "1dd1ec6c4b4ec9bf13aec933506376c77e63254d5573c2584d7515554f14ed8b", + "sequence": 4294967294, + "n": 80, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250044721", + "hex": "483045022100becbb21c7937b9b27ea3cdac5f2048ab9ac314de59c3ee2926a5cfb258ce14e902201c8022bf275c1a761e7715b14e15d74526901363ae5f8bf5489d00908dd758eb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "9957066f6fe221a9423b0f54ce1188000e1e9f7bf9085527d9e1edb31d88b7bc", + "sequence": 4294967294, + "n": 81, + "addresses": [ + "bitcoincash:qp7zwhgnhhuh4j8644mqg7y3fqejm2jkfvkt6qp4pp" + ], + "isAddress": true, + "value": "1876300", + "hex": "483045022100ad84bcd69a85a0d487fd7cbe4d76b95bffa303e76615a4336419fd182eeae4b902206d21e4f592297e87f1af9e19c80fd978914aaf5a2db2cf499b72cabbbe73c831412102958762ff6c8985dc9656afda59e61afc6c0131a5d8f1d86c87c83c9b37f7bd18" + }, + { + "txid": "ca467662c89f207dbfc6ec016e126693a204f17d6151987aa748838852aeffb7", + "sequence": 4294967294, + "n": 82, + "addresses": [ + "bitcoincash:qq7fvpnuflq4cq6wc5t4qjuzj8l59puq75h022fyxs" + ], + "isAddress": true, + "value": "1114817", + "hex": "483045022100edfd64cf9335d094d5873deb38cda5f4ceda3351df722f1c718993a2dd12c8e302203126b0f9470a4d0867ed4e773518b8ad689ce43a2c9f65a1f297525fc22201dc412103f37089783028c0776f2b8a9d8481ec8d6d0652a31edc03cc274032ae17c63c62" + }, + { + "txid": "54fde006c8dbb7a3de68e0609d057a3f2337c99ee2ae70cc715d72f5dc881a80", + "sequence": 4294967294, + "n": 83, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250175152", + "hex": "4730440220448751a749e7cccacab0ae1ad4da948b0e0b5d8e3f41ac2b22c18928e8e67d41022051c107c345c06ea82fe8329a8cf3a96b516fd8750611d8ef438b8545416398ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "a08d7c70130d925e33b93e21cf77b5790a2ab5b5dfc4ec2198b9d81a74af06bb", + "sequence": 4294967294, + "n": 84, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250056417", + "hex": "47304402207f9b2802ed1e893168277204b7919ff479efe5c71ad2a255e1738a52bacd758f0220253780485f2e3ee960e058d449c647b147b8f64b49b913e7e9615a6c7114f18e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "e2c0a8e67a48286fb8801c0faa3951a268c5f6cc450c445c380e80e09c752778", + "sequence": 4294967294, + "n": 85, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250043784", + "hex": "4730440220778fd8ba1dd9f71df55bbe1c3c4185b8da21dda82198546c2a0c30250f4c1d66022040f17a46187d535c6e943c047942f45159a37b2e171db18c657cd24168c22e2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "221971a381aaba4e963d21b54e625b764016e848a5390a0df32a29aadf35f92a", + "sequence": 4294967294, + "n": 86, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250090058", + "hex": "47304402202cd2fd29fa395a5a80893de065c8bbe71e0bfe0e7b2224cfd5684736a086aabc02206720226ba63a3e5d9e2dc67e404625cdf31a7a08da0e8a22717e558f7abc817c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "bf6623abb315d54e6b7d9428133d913121ac875dc4c8e3f698477dff8cb7e3e3", + "sequence": 4294967294, + "n": 87, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250229940", + "hex": "483045022100f8769b797386f0bdd662483096f4e0a33c13f6074a4aaba3fd590b9abbca7c2402201eb064869fcd17a59ac028145b08c73b3552544cd7fc62245d1fd1d369ecf765412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "e66b832bf71437eeb367e6cd7818658f960a4845bdf3f5081aa474935c9b31dc", + "sequence": 4294967294, + "n": 88, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250154777", + "hex": "4730440220558e65fd916d9c9616a3e0bd41111dba3914867b1ce5d487df4f77feadc0059502203198566c0d58af8551b65f884db98bde161bac140c7a900cd40df97a40c267de412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "452873e0c38438227a2fcf64230973ea8f5868fabf05603b629881a2b46a4069", + "sequence": 4294967294, + "n": 89, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250103829", + "hex": "483045022100ca93287feb58daad47c5388067b219e44f8533a214eb8eea9b5313040579773002201716a6ad2de70eff6721ae7950edaf9230420648bb8ec53173c215cbd12246c0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "60b3b027b67f550a0544a539f173066031914f0a49897379b51ffa127117e521", + "sequence": 4294967294, + "n": 90, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250125814", + "hex": "473044022003240fd71510800910b448c62a03178b4ef62299b17d6d2c06ac8f3293684ff50220637e3ba59fc884a8bd16aa2e884b379d85f38ae4ba049a0365f33644febee6df412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "6cf9e489432bda9fa9eb865587eb28ff525b5171c38f746c55b85a577ae68854", + "sequence": 4294967294, + "n": 91, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250144563", + "hex": "47304402202e2ac9c8b619b8e2626895c20f6bdd1a24fa27de017d05d5fa2ce120b3421f25022053ef6f82ccf9a132d40ce566d45f4ec18bf30048d415f6ec1c783cda027b6747412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "9c9923f0c3366eea9c229233d8828825beb12a2c28ae3bfaf46203dd1fe8ab03", + "sequence": 4294967294, + "n": 92, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250218730", + "hex": "4730440220352bdfe541e9e1ce428ac4eb4c8ba9391a118b7dbe57b4fe3c4ecd30f228fbff02204a0b78ada1d74a7e7b9ae912e6f445d9ce9050855d9c5ecc7d477d2590a68b18412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "5ed23fa46f4db7043e14b845ef13a37712170f7cb25f88ff9acbbd6bc97a9d87", + "sequence": 4294967294, + "n": 93, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250079095", + "hex": "46304302203f767d8f64e3c9e5773d94a325f8029d21d1c9a0f470c9288cd99f70d2d90ec2021f50b395f9329ffe64ff8084c1506e904ffc02dfac7f7e15461c3e8a077f604c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "fb09c795e5cf32d174df4efe8b2208de9819ed024511d9fd684556ec8adc00ff", + "sequence": 4294967294, + "n": 94, + "addresses": [ + "bitcoincash:qr3vdgfvrp77mlhac73ujqgtn78cg6yeeurwnjqylu" + ], + "isAddress": true, + "value": "1792434", + "hex": "483045022100f17f8045a627bf96fe09d868109063d8040e3e2df8944e05f9b20a15273d0bdb022059c31e2d849abd57e784f1a3903f49f18c7c5a624545bab98649e8a092e12a10412103ee2a3f78cd4930dac8c030ccc93381ec5eab259c1607360d85d1728fc296dacf" + }, + { + "txid": "36bf90cf0b6074a361292ec88ef58d76780d301a1e5709bf013808c068af253f", + "vout": 1, + "sequence": 4294967294, + "n": 95, + "addresses": [ + "bitcoincash:qzjvk52q08wp84x9uelf7k3572fx4z5q4q7vkpaalx" + ], + "isAddress": true, + "value": "1713598", + "hex": "483045022100b58c7dd3fa1f8dc50edc7b5546b8ccef8ffc5c179fee774999c63fa729ae3cef02205eb611cc887e5a62a4e9da33318ce6e216ca353225f452ebca51be1dd10f544941210267f3c9b9bfb6bc5c1f68dd1d18623a9986408202cf232ad1e4089933c83f186b" + }, + { + "txid": "259bc4abb9f14457e323223bcbbf772afc0a0252556e69c9e13e8c7860e7946a", + "sequence": 4294967294, + "n": 96, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250075778", + "hex": "4730440220097f46c588f37ced4846a45905df1a0ae22709760f8a1bc930a58f5054cbe482022053b418af66d1edcb3887616feb23e5dd4095f29e74ac89853c3b909eb42bac34412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "14a32331f78309de6ddad707840b364aace14cbef8694ab16a55305fd44260b2", + "sequence": 4294967294, + "n": 97, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250085059", + "hex": "483045022100cf98e22a2854c7088a0572e1edb4e876aa622ed10dc0376806e1432f5dc1eef90220527845f8dd2522fbdf423b4fc34a4792a7f82e04b314e0d83e2425daa2f92115412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "acd836ea3252a7610e6c1d426f2cc739f73fe1a0768048d7431a69d4bff3f0e5", + "sequence": 4294967294, + "n": 98, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250132855", + "hex": "473044022070c7aaa7d7f050b1b520878e55db3ca491fb33211150e2f620b685cb49d7d885022022d9ede63e3b196a1c33c2d211c1eacf2e2411820ecf5155b5e4244f5dfd9f1d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "348cdfc73c3172311b972b8c529545591f725b86ad065f88d7a78c2fcc05f9fe", + "sequence": 4294967294, + "n": 99, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250023474", + "hex": "473044022018cd70c3e62563ea92ea12735e2efb4b905df85e6b290d573051f49c63d07c60022037a537ca3514121d5c2b8753833808a5e0432f1a8f277d91495953c8211ad326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "af7baa39bec2ba327ff720a7c782f833d18c0677c644080f59996e2270756c55", + "sequence": 4294967294, + "n": 100, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250249377", + "hex": "483045022100a01ad9ec8d24fdf01eb203c2887c1413ae56990d4600a18010959f6df43de08d022056f0f0dccb8f772f29a7835d7dc40f242348805005b5f80ae8f2fbdb600ab2ca412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "6ba95cc08cb6849c9599eea8ec3abeb7ba7c7b42399cfc6d807dbc5aa8c1be52", + "sequence": 4294967294, + "n": 101, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250192878", + "hex": "483045022100cdd770159d56ac518ecb0dc916df0da06eed536e540582680f742389f53fa4be022012d372e2c04176bcb82b91b02ea23c9c1464baef7d1dda66066bf84c402c0012412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "41ebe9615cb3037d95ed10c37be1fc80d216619086c5cfc256e489ce42042d3b", + "sequence": 4294967294, + "n": 102, + "addresses": [ + "bitcoincash:qp4h56rtxkel7traz24d3ep3jq0yxqm82stgclvks8" + ], + "isAddress": true, + "value": "1288555", + "hex": "473044022001dc7db378891c1c5bf07a09d14fcc6675965976e2e3e762786b1b1e0f4a4bb702206db6f284dec835823fb516fad89543edd3bd7af3ed33940fa296939fadb41ba841210393ae47ec2e844378cda3630abe12082401f2e0f98d016dde2b152b42e335630d" + }, + { + "txid": "a135747cbd99ace7bf495ba29e49b5595f32259ee7df61d9549cf3d4274880c3", + "sequence": 4294967294, + "n": 103, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250118091", + "hex": "4730440220290a5055313d68f9461ce830f8a7395022d2d55abf28f6b4bd665693b4a13730022035d4cc2a6676ed842027dd4f21d31dd5a956f4b1f5cf771b866cc0d4a6400df0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "90095e01bb497ffceeb85366ee1b9603b96c33ee0acb47a64fe3af23911410d6", + "sequence": 4294967294, + "n": 104, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250028058", + "hex": "47304402201fd6be6d72ae75b61a624c13476b538ec2f9e5146f3074c879af57ecfbe1679702200ab10ae612e7fe0f76fe943c1f6a02262008407f86782c1536e92e3bad77d3db412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "44b169e5c5414cd335ef67906c0f4425e8b190ab366dd1e16641a34d85ab5f20", + "sequence": 4294967294, + "n": 105, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250132073", + "hex": "483045022100a4132f408b5299dfed6153b7a331f9fe866f1b042e4263bf7574ea0964c450a202203d99cf8dc9a9194269bce400185a4f86f5d35b5be83f6dbc3166b600392f1b00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "f7f16d4c8f00cb446063f53a75d2dbb2c54d9d474abc836b92d48ed76a5ead8e", + "sequence": 4294967294, + "n": 106, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250210684", + "hex": "483045022100bbcc2e2d77458abc30898cddc7eda060b23a62f0a53b81c3db47f284cd7b29cf0220705328a29bd30792a7f5a704fd74b771c3c8a099265f5e7c9d70046da5b03ff4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "0252408a18fc77479f6e664fab80cbc6d90c1c5e369c34661effa52b9f1f36f2", + "vout": 1, + "sequence": 4294967294, + "n": 107, + "addresses": [ + "bitcoincash:qqe36s4qsvdfjzwrv8whsc0z94unav03agzr35m4d7" + ], + "isAddress": true, + "value": "1591983", + "hex": "483045022100d2f40145c4b9a17b3582aabdf7d9ac2d47546b3eea5350c4e2ec1e9c2466343d02203354ce620aa056a749de847f867c49dd121579c9fc50bd6258bff7cfb173c5f24121035bf755e8b075665a85155618f6e9022196a09c486415587dd3af0d25b76e9c27" + }, + { + "txid": "74002fe81a5931658cbde74c28933bb36cdaed62201be1c0e26a53c92d6bf5c8", + "sequence": 4294967294, + "n": 108, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250148696", + "hex": "483045022100cf8c593dec0724644d034f17ccde99feaf0416334219f158f884badf500fc93e022035af1b68574e88ef15e1c05c1b36638401613a31aa7096d97efba6df62695706412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "496b4d67e0a734740962920c116d56121c16ca60787812fea76d69b9161f8395", + "sequence": 4294967294, + "n": 109, + "addresses": [ + "bitcoincash:qq99u7jj9ujglljvh8nzaqtq0kfl8matf5eldrwhmm" + ], + "isAddress": true, + "value": "1859920", + "hex": "483045022100a669e8918ba68754b84d584f38afdd34be387773449784a6c61ef3f33d0fd99e02204d007ef31f5a3a7c412ac3d2660633fcef137964ef2ff6269c41e933896d918b41210383b6491fd80e1411675d7c8eda9b756c30a814b45fa565b7ac24d7be9dedcaaa" + }, + { + "txid": "4a6f608d6ce8efcc0cbd3b55bfa0feef86f5493331564dee943fa554fc84111e", + "sequence": 4294967294, + "n": 110, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250058421", + "hex": "483045022100fc35ed21833c3ea3ff5f832ef02236a08ded0999ea367aa6eaaff364ecac3e5002206e291d7c4fca0485dd8ea22519544ac632909d706741710a6e5f0d472c0b0656412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "a9cfa2539cb07c0903e2a01a343c6ea8566bc063b4c301ce2efee45760e36448", + "sequence": 4294967294, + "n": 111, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1251645868", + "hex": "4730440220485937c55c67c8eb46b94523cb06f9572ffb55094536d8b1a458c76b67dec75b02204e5007f610e491d043a412696d4fd769bb2f5d8c3e8b3a59e6ec3bb598f775a7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "62466cac8a8cb05584af3ce85d0eb8d4a5edf644a374aa23989bfa2adad2d8ee", + "sequence": 4294967294, + "n": 112, + "addresses": [ + "bitcoincash:qzl7yg7fxw5ls4jum50st5z7valsu7qa7v63ks2730" + ], + "isAddress": true, + "value": "1579507", + "hex": "483045022100b430528ddfca4431cf5cec08964f7325c036fdee55edc0ea0181d34ed72469bc022074b75bfa66dd4a87fab93da0f2f0def65b785fb0b51fe07355799cbd8b30c39a41210316d35753d58318c06d0faadcb723563316847ae06019984f42f2c75deaf3727d" + }, + { + "txid": "559927367907ed4d3822c2b4c0dca89ba2a4df844daa1033123e9939c9e81743", + "sequence": 4294967294, + "n": 113, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250110065", + "hex": "483045022100c6ccc3891fa3924c7b1e69b855628230c48d85d1e1331f037823ab7c5928610c0220050c9c0e078f34ced537e88f95289863a663b28488880f6ada3f1dbbcb1743a1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + }, + { + "txid": "7b5bfd94b29844e13c3fce76d9579dc7d20b3fa0ef15309714530152e4d5ae85", + "sequence": 4294967294, + "n": 114, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1251309649", + "hex": "4730440220168f31f413d65ce64bccb62390490dae2e4a00f98c2c44bd4fd689cd942da8b1022006f1b2aa4fae9587c688e8b7ca5c07db3b3c3afd6961f9f843099ed30b583369412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + } + ], + "vout": [ + { + "value": "32902", + "n": 0, + "spent": true, + "hex": "76a9149a262d0621819c8c17d34a7feca1b39b39157af988ac", + "addresses": [ + "bitcoincash:qzdzvtgxyxqeerqh6d98lm9pkwdnj9t6lydxqg82t6" + ], + "isAddress": true + }, + { + "value": "115067302350", + "n": 1, + "spent": true, + "hex": "76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac", + "addresses": [ + "bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000023414a6f8ec13dd4f85b3fb1c71b937d5dcaa14e350cd4d", + "blockHeight": 611623, + "confirmations": 20560, + "blockTime": 1575319726, + "value": "115067335252", + "valueIn": "115067352350", + "fees": "17098", + "hex": "0200000073126b74e8eb1830ec84d26e50d09360e120e92956c823afdb2e981432e60e152f000000006a47304402206f992d73dfa7e518b00190f220ad5dc7b7947b1d75a2fcd8251b59f3d29d89af022036c6c44f52f9aeed406dec72a9aab1f82c3b997c36742f4a3504e4f93e6f8557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3848b83fe17d5304f63a9457a5749ea2ca1ea42d9934cac890666e2173a80b55000000006b483045022100db30ebe47536e42115a507f88bb8d5c97b81ad05ce334872235811134c5948bb0220418d77aed78cc4a332b1858c1d2e9ab169828b9c12e8c0d0f8d155964e5d0b8e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4321b2ccc28666c12200bb15a050a513976487cae0a01205cd30ca10988d8ded000000006b483045022100d30c9fd598613586d8d0460fb6c9ffc1d0c6dff6f647535d2a9f69cf373193d102207fff687aa035910db124adad8b59607a72b3d24aca9096217ec6b90fa132a2ae412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff32a0d8da2143d7c4097af72285aff1305155ff5e05276badc91839d5ac9bd7a2000000006a47304402207b30e99cb1f6754d227a4511c5b7791f3b896724b170716d6ed238017f191bb102202c1fadc4c572c86288b002a0d6b6d2460a14a6d3c8b49efc17a03e59d2db18e3412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff62f77994b08467f9a90c1b7b921306d7e48c18015aa53aab74775b73dc79069a010000006b48304502210092b7f176f182936323df8e4359b2a329b0c1e4b48a529d6e32867038a2a453cc02203c24a8bb46b7fea4ef5c78ff116a51fd0a04dee25bfcdffe856fb8988a7a97f64121035b4e75dda9fb0d55d856f54f24fc65da6657939b9559ab2c623c8ef325f14d8dfeffffff5cbff5ba887ac02cfcf6f1adb0c84ae21cc003667734dbc41ddc31330c7c555d000000006a47304402202a2bcfdaf12c398ed5372e6b168a786edb8972df1146b705d3cccf2d9601517d022020b90ac89d9141d68817850d1cdffaf6c51f45249a44fd6861b361a6025d8ac4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffca0bea62231cdd9cb231ced73fc1c0f51c478277a077a55aeec113b506e7db61000000006b48304502210087ef2709b9fe8e7f136219254229edd45e94c3f6ebd2bb149aadd9b1d44d89e202206ffde3c9491c012832967e4d34e02ece2c08bc4c07967b3b466d4800f9ca0746412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff843b9b8e0072454494ac701e9f0816590de35f53cfe960aa03bb4281128db254000000006b483045022100c7dbd1117c57eedc8fc006e818371bfe6399c4d25e8b40482c1f0858a3d98a4b0220426d1196513a87fc7afb5b107b770a90af789536799a11686eab96b04afa6326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2301458143bdd235636b4a15f1ce7fef218ef401e26f5871d26bb28e632e0c75000000006a47304402203604fbb20824443899030d2c1f5cd0dc2b88174929861a708bdca878868e910c02200a607b1da53483bc95d3a5c54e5ad66e459827d4ecf8b4ef9909e9d58b2d329b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff9ecbc5e26870067db7ee944b7fbe3fa99c3247e0614fa5bf24a9eb587c36d9b000000006a4730440220399c36174173cca01f6d6a234a935d6f776b549e1ea2fc2635193924c4ac2eb002205aea7741fafd95f862588c480aaa282d7a344d32d6318aec1a908cbb939e5d0e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff9ef492949a0ba873b09258961f35cd18d78849cd290fb93aace31af829da278f010000006b483045022100da9075310e7af59456423be99362f2cc686d50571e0f0b016bcfae1f0bc4692802203379b648d47704dba48542b8b6d5e515bf3c4fd7ff8a7be82cd0c8c0c7be56f7412103a344a84dc1a919a64874605fae200861b7af3ecd02dc5d52dd00eb6f8845525afeffffff5c5f3037b499d79505425804b021b76dd94e1632b6747afd059d0a728ff49b10000000006a47304402206cbf93634d6a477a571fa2884c19918b19ddfb008ff9fe405954720047efdb88022003e755313436d406dddfe3cfb68719e8f39e43de7c586489cc543dac0347da9f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0b183fcb0f29cff3e9f22ff47a5c87694199ec43b77930f7b17d646f3670e5d3000000006b483045022100f23d4cf11fd0a5ab83dc053ca64066cbdd2fb4107e0977a3a880c68a67636f7d0220220a47c66d3944cfc309c059fe8013c4de742e4d8590003fd56c5e0b3c7da557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff80540561a82abdba58b2ac3bb9bf9f1064106b8f2fdcb63d462721409af9056f000000006b4830450221009f522beef55cbf8c7f10e88739846f78ef1c9d9cbc6959dba6f687a08fec0ef502203a160231733b87c6cfd8afd148994c9b6c5d5db9bb9847aa9e60938a6e79d5b1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4a4a1e4ea13377a0819a88e2664facffabd92566b83fdca3456267b017b7933d000000006a47304402201f5d29be80192a752fe28ff141ed702640df88083faf3f9573e52405cb4bd79a02202d751649aa600c4fdb8b1d1b21f0d134c2f4e5af9ecbe7d87180d667140f0a11412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff9b41a363950ab3e6b769a4cd97555d1d8336505f3c87599ebf7766642ec97ac7000000006a47304402203f4bea3816d252cb19d4247f587a146901c74d04e783efddfd5089942f2abcdb022069012613c4ee4b3b0212ae71dbd2071e01665148697011eb03eba25431e679cf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffab050b7b334656d60e2c9772a3820015a2f6a7cc3e2943897b0c027edba3cb90000000006a4730440220782ba77287116d5d735f67a3738fbecc1a802d2141a1fa544f61a5e8ba682a4402205473d68019cc8895ecb1d87bfced62ddb6dc48b81152f2684ae8530122d5b41f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff26dd82e448134b4105f561b681206a059e1de4e5690453dd8e4d9a0482c35ee2010000006a473044022044ed9bfa8674d7e83112fa22280797169d45bd971b185da2413e36252637529d0220531eefc480e0911d6ccda42002942883149bc1cdd1f3bbde313751d80bcf98b641210328ac4ed2b30ddc04c778a78b24e7256b08c55758c1465defd997ff4bcefacf10feffffff9e2e1b53ecf545d0b0cb972553deb89f3cce7e9e92d0e0a786779df0df48a113000000006b4830450221008cfdfd352e268dba2022e7fbfc37a90401c40fdf6f1d8ba9dcb97d67743eddc302202c0a1b604d34aa174fddef63c9115c95465548855c5f783bb206eb4ff8fda235412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff9fd5ed5458cdbeb26b0126512a1b1f1aeb85fa7b584a0568c674708fafc0d70000000006a473044022001b33b610b8d742df2ad98679f1e41f0c647faf272e15e7ea93171ba29c33bcd022061646fbcb81ba30d6e8b030ee12101d1f1bef38ba44a6d5daf40c4ff6d644e6e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa6f2a72bf25954904893198f716f7b6f07e68bf35c12c233aa6d165723931068000000006b483045022100ec9b6bbaba90d8902ec8a1ca0e90ea594264bc1add204b756cc89def4d7e9a2a022066b2bc84f94e1a99effe0e929be8de8669631143ca20c73e700d182ad4884e71412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb38019b996f974375732d741fac543bcb46670b99c566a8a887c3f876485a942000000006a473044022057117591cc465c48da58ebcb8f57fcd56359757d41e1397e45b5e33e034ea5d8022001de1d78ce9e8e73370a0778b4a8595045c6faeb2497ab4296d0cff735711276412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbd0ba68d3c24402ccc4d2c82c4d11ba0a794bce9e9d39f64668aa4b5956eb5f7000000006b483045022100dace56650d1d9edaef30e8c9ecb4b78499a573984c8a451253295a90c84a3ed702201f4587d4a760cd77a2e21d5f6f2b7aacf668220c8c7c62fc1ae4779f7c0141cd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff143d2c0bfb63e9b52766c0f7921d06a1d51b90a770b64902ee8352122c918bd5000000006a47304402200db6b461a0082807f59053bea210d38f5f82f02dd63a57f6e3987339cac23870022064ba927fc11b36318785d4e861a7f94cb3909ef8fe882360e2041f7b4a444692412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb0b7e16b8502ccd5ce2ec06157803e5c84062f5e8e4804a633f9e809ce260353000000006b483045022100a3e75a6c7918db32a27be348493b831631856ec8f546ca43d143cdc3c1cd03c802201e6ae036423bfce45c500b0c049f68396deae5cb999038de61e972ccd4cba5e7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff6d284b186e26a4116b02e6568c2868ff13408b85c71db1495a5e7cd32a4151ca000000006b483045022100caf952ca1760052cfefe8df283fdd0eccb9e1238eea88eef287df9404c622e8b022072027363fa1070548576fbf9bcbddf2e435fd020662b2d8f0582b52bfa487b31412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff38bb6ba6ccca482c333c8fd0e35afffb150e4c99fdf70513175f10bb8b263ec0000000006a47304402201a4b4efff2b70a4039b4dc120141da04ae84f63906df10c3cad08838c01b6b8702205a065d025c338547ea07b2095ad31252658e57f1a7a04c7f4eacc0248e611fa2412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa326b367f3405c7648e8e12b5bd7078867796b60f70cd4b3123442a6fcb9c846000000006a47304402206b0a876d78793710acaa8bbeb58a2d908bd4936f2a88825f944b190041b5e0be0220279560be5009e4a3fab44d08f4748e2dead710a8ccc77e06a03ba8112d728856412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff746bb13f09e7c465f9ea0b264c601ef9652736d83ca0c78686ea25326f6bdcfa000000006a4730440220799bdb7ac60cdf3314cc1f157299858d353e22c00354707337ab5b497619d626022000e41053afe44fa65227b7dd8498300a2dc89367d9daf0586caba5bffdfde567412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8da9008652012637c8bd2a3e6c9b6b6c4e12e67126ac1e5cc3b1d42b3c16b5ad000000006b483045022100a1af33a83edb7fdc289a48a4f77cf286a88b38c21ddf27dd4ec3df007ce11046022074dd56730730f958039efd70edfe7e181060fec306c6df4cf75209600ebebed7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff84a1b480079b2256862090844d38dcd463315a43b757678d7002cc1d01001adb000000006b483045022100eff445419ec63d1e9f51a5324c3be0315911b39f30657639e84ea7d2f739e0510220218e73140a39542ec8055b6645cbb7989f96b9d9a93c67549c059509de06f0ba412103dd71b53aaa823b09a68aba30c7603c6a397e7c183f708c9dfb0d9d0a9cd1c722fefffffff8872f26872ae96f137ba029e4ca6d19072f8223c0664608eeacd4753e8969df000000006a473044022050b7ed06a6832b8831c08ba86049b3793b5a71fd6d5177c9f268b79c3074bca7022047447c23429de30c361875642d9058bf1b5e0e6c5516d6e71b70b7cfb29827aa412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7ebebf2f8b764657a719cc52e3ce31fa79c37cd2d583b7be31ad9ec2ebef3284000000006b483045022100fb072bfd399dc11191ac449a9d60119bd191ce6b19a5d92412a805ddc8d4b46f022021e463686560b15ddf272b9943d8e41425ed500f77698aba518ccf546a97aeb4412103e35c58a738805f53af73472ffb671a9bd3556ddef47c62f18ced868bb5033d0dfeffffffbaf05866b6eba762daab7778d4eb3fa1902346491f14c8ec047c12aaae4cff29000000006b483045022100b25e7d4ebaa0e7d8e24498b039e756d568b67316aa14d05abafaec59e216a73d0220010d0b6548a74435907eb0d548dfe8e52a949bbb785eb2be3bce14053953784f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff1330325273e9a1329b3379a553ce95bda9dbd7b83f93fad4acb8c1dd45f4463b000000006a473044022007d2baa9a766c120e111a727bfa8e8bc2e01cc285d4d4f67d2323b213525a10c022020f32be2d9935b6d9b5091db27ebf00aaeb54adc7032badc7ad63f20741ff28a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff44530eb5b53868de4819fd0dff26c12e2759f4696ce114e22855e88be1b1d41b000000006b483045022100f98ee28ffb66acd04474a120904ec1be2327d727d8ed8fe99d8b95c174b8f46a022041d21406dd8df10cecc1d6435de68fef3f9db71838c1ca2910895bb184b4a6e4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2fbfba76ef97ef4c6e575783e08baa25da64eed6a7eb4ca48707feb7a2927406000000006b483045022100ee3f7961f0f23137d753affe85b777e94c1db3f656cf41b8f59fcf82d9226eb7022025009482a6c0002e409590075caf7a78023ebc1457f100c8b922a4974ebf86ba412103f1d1dd7685d3781f58f9aa399a16f6bb9ccc7d008cdb7c63a7945cfcaa6ba0e2feffffffbf525c080b8b43afd5c004b40d25a7ceba36207162b2bafa70ddc95cae68c1bc000000006a47304402201fed9da4c0526ac5ce257fce2b7fc995646b5f0d2961396327f93e2dfda3e4a0022035b217adc5a9be2ca34f4361ceafd9f2d09a6fa47d4a767f7001ade40c08fe26412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff327b0b903a0f60cadd0c8d2e2cf774ee04eee9a40bf5c37181a471045f365d02000000006b483045022100fa8ee82d42f524290319fb3ee47a1afa70cb952f8a37325680d6fd651ac3699f02205ac0cd86fece03ca204bd881d67ccce0cccbbc98704d9e955e2f92b5b77121dd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff5fadd3b92b767baaf2a50c8b21f8d3f7cae103e7b4e4c0ba60f111d45f8a1cc6000000006b483045022100f3cb343c4704bebbc78c6492dd72ca19c388b285f44f574dcff25f993add6d5f02200e050dacd78de955cf552f9158beaac5fa64995f5bf7c8a919a231a39425730c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff47d0ae39a2ce683261d30f45025b7faf667146a980c1213b593c482647d77d20000000006a47304402203f05a035f5d42fbfe97172b431a613110ad733e356ebfd08886fa11bedaf1faf022061c4a3bc3417390910612bae46f5acf8b6e8a5b008d273a52e483a315bfb950b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff46cefa6639796b89c5e8981c42a230d8629cadecfca5dc853c85e782ecafcafa000000006b483045022100bf60fbd4716339bbb42ce150966ad6caf90b14e57f45eb6804756cf8ff36b23a02202f16aaecdb9994f3b683cc7fab45bd0a3f54795c336b5fc224fc51270a7f3f4f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4e5c5b111998d7b90d46130f2ef29f25d48e8649eee14684cf6d46eaad3b7026000000006b483045022100bcdcae99c9289b5fc89d3227daaea8df7d0a0f3a8971d841ebe1ab7a1ecf72e202202ca21447a6b3e96540e32529697d523b7b08c65845d6a13f6b1475de94919bb6412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff489efab51aaeba5cfb24d1484a917a33aff79b7455392ce21a3e642a170341c9010000006b4830450221009535c27b5bbca0db2bcf1a0d0b3b283a2171df53f0d68f1a138888fcc6ddd996022068af19252ac4376cffdbfaacb2e0f0c216deb7e2478b586abe7c2679501eac34412103a47e5dea4ab8d785f4e00994d0faf1a8f384c41e74ed8e4b776fa6ce136ebc42feffffff7eee285c72768622c785561839c699b1a748f58ab418615611c70c9d70440518000000006b483045022100b456847e29f8a648730f0fd34cc7edcfb35daba866ab7d800472beaf2836ce4202207db401f0a5e30efc53c7bf58e57d1dec5874d64768ad9eb4895351cc4be9226f412102291b40a9a927dafeb53cdfc7e722ee5c9dfd6eac2d81331678b9ab405bb25d21feffffff93b0226e9f90d151df423d9ff868513f71f708e715cbcb1b5444f4a0194bc267000000006a47304402205ff244c77726def0e3697a3e546bdf74c7f31479c9d01a7a6f8cd1656482d537022045d78dba8ed4d3777f473736daedbdaca6f5698dd306898d144eb43f96259766412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc784e371e706c6de880fe3033039cae758513a73866241658a21fa6a8a4a8d20000000006b483045022100ec6b35ce6d24889726480d70a31bc0d62800bf7ac49ecf084b98137322606bca0220432d33e2d8b508f26d7d813d18629453c537a4d90f73a104bbf80627f9fe8d62412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa4cab40c510ef0ddb8fc3612af871512805ad7ebed2b60fecbe7b9d0f8eea760000000006a4730440220423ea635717cff512d9262b7c8932c0122ca868251f019ae033101c28771a52302200cd3ae05f2e88d9f64207beb4b715ba480bde9ffdd40ab61a36feff88f2968d54121035530745f3cd4d31532991e460bd2a15e1944e690643f73133a9918edb95da53efeffffff852bf329889cdd85945b23bc6a338562c151ecf16b04414c75afb1cb9ded3370000000006a473044022055cc4dfa48a79b8584a9352be34ab5fe9cae4132d264dd827d14ae06d35ad4090220652a83c93505f8a8527c5bc0479f37da0593595c1bf18c12b8fa0b41a2e37a64412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3235c14d72a55c47d9b996588c7110e27d031013e1f2c77deba6241954059f92000000006b4830450221009acc8d0e06d10b0c764a27613bcef41fc75f910875eae3989a7f8725f81814cd02207146ff66f412910ed993fbda4ad6ed48862a02f366dd88a83856a17e7f96d83e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa0b0aa12e3299ce6c925827b3d5603676949daba619fd9c7bca247d1c265e9a7000000006a47304402202d8cd72290f04063c0ae9bc06d2cae3ac74ef4cb6945c92c3e3ccca210c127ef022030471726cd87ac9d55f3d246095f64ae22b611aa8791922236bbdb19ec273322412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc856c10b1d42360a93cf60fa8127afcac431417ccb7213f649d45482fc7d89e6010000006b483045022100ffaa954e5b86d54ece9bcb9e37895047221828ca381b03266de3d9341599c8f902200ea1c5ed36e893df822c698a474b062d4f93005c32f9d2f0d78ecaf5a56e4fbd4121031a00f43cd99e015c72acace20ac47d887a39ef284f89a5aa09abd968d06f5e9dfeffffff69129065f6f989f1a008813b345e8cbd881a38107b9a0af3a3718437ad6e9cd6010000006a4730440220457d59caf24eb6e10664d06f3e936f6ee31d9d59f1cc4f6f62788f022bce8c1b02202ce7c37ae6832b078c1cb9a055e3ffcf4674081f0738fd9c3eb4465b52bcc9ca412102fea9ae922223f2c68c68d7672b7656885c3e1321d35cc8f5f445179df6f7d27afeffffff8ad3038c3df6f210fa389c57f72d240dd2da53bf172429620e64758a28a82a21000000006a47304402205e0f5cb06f7fd741825c669c87e9db1a433913fb8577adb92b779d3a693b4f080220120648a5f9d2abae83a29cd2c79f5c61b9bc40da8990736ab97ccf6f82c586cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4fda56201530659af45d3f6ad8704693d321f4c92184403e848bf4c3eb1a6a3d000000006b483045022100debfb215f94e9d784e91fe0b9d2541d09a4c7591172fad1441506db4a3590fd102200cce728e344933111c9548162e62872fccac624f6f98d92ccdcf98dbed09ac544121039b8a20c23f32f5b14e76fb29e0baade695810aa7b6dac9e9638a8d13b6ad8221feffffffe7bf81c3288f97cccc60391101a6bdc7654a30dbb693a9bcc8a4b112535d5891000000006b4830450221008110aec39b127143891069590fa0d9e1d8b41bdda70d9807848eba92cb48736b02201bcfdc1a1cedfa4c53efd941482f6157774b2aa80af44e500263be6a3cbcbacb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4c686bfd13c84da78ae379b1cb6974bd3cde55fffef59f28954095903cd2b3b9000000006b4830450221009f76d6838b8fd8bb74f50c67920fda9f28054d093b30fd03b54b3fb888db046f0220307944f3abec07c3570614f418056aeff03c0830173c963bb0b65bd5ef24b4a9412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3f7108134b932ada8356748fecd11ce666f529c25e4aca3c4253f77b3ba6f965010000006a47304402207b93e2500b189b51fbc3a49a191c4b92ac76e32ce86f6f1b9af4afbb3a91fbe002200b5617cf52095bf882a5129f5477f119c9c565dd582a9f19493cf1bdae6527ac41210323ab0930ba40688e66bef6e08f673bd6bcd3df687e4c503387f48c24bffdc93dfeffffff7edff321567843351e47d6d3bc8394e2cace9fe3b72c4dbb152bc54c6abfdd48000000006a4730440220731ab37e71d9c6f63333ba205a318d36e5847706381f571b4b562e5e6f6e403c02200704ca9d9a33843d9a16135f56eced1fd18e227385671a8df5fa41e505e3ba3c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff71294d7e9b11e4e36de589c91122993add9030771328f27215bb55c36ac2750000000006b483045022100d1d3565175e1f529124ebba1bcdf8c1704e753c2f91ddcd1a093b5f5403cd0ed02207420ee9d6082356cba6d8075b4fbf310bd84dc770734a8ab30e74741a779bae8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff423caa98d71896bcc3bd086cc2cdbea476888d19a3f3b9d2554e82e1692cc93000000006a47304402203ddf5c6c5065f03229cdf837d9f8d3d22314834b006e0aba8dacabea206b3b150220417c49c9095372d3dfd954688bcd43fdfd2a121989fde18456a9428b2a8e3c63412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffce3d664bc2eff728a9ea3134bf11d8c7e2207ed508e7879ec7ecee976eaf72c6000000006b483045022100a20e6aaca7df2b142b768d3b1cbf8f783f3d4997d155a32f0e066b4255777c9f02206deb15cf53d6b27a973df9aa7080691e5914538d9e97ec7c6e797ce03333238b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb8f5dcd6f0fb2ad1db921e6f79fcd9fa463165091761f9d8baa23673a0a0645f000000006b483045022100cc2cf5c6c2d4862dfdf65407138684ba45565bd8ec46594ed4586bfa37b715dd022013255b2eb22f5bb93d2afdd07ec4c3b5efe0aa16134b2fd084c6bc720f8cfd5c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7c331f8d0e02777c73a28ae441e12de405bacef5ce967761fb521786d5186b25000000006a47304402202c9dd98c9a72e5a8df4b01f09d18e2826d8b9871db89c5d3b24ffd673facaa0702207523bfcf3ab80790167a2b1159fe268770371fcc7d770995c19eace3181ec8af412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4cd501228a577f0662b802b5b197921268202b8658e4aaab7cf6ecccb93cdaae000000006b483045022100bfac8828df10b7911d341c15a532819c429c7185d8883de19de84e71b97d78730220177603a3572908c90dad865770906b5ad228da7ee5da39503ececf60ac735158412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffdbd64011a7b6fe85385fb207b347f02f5e047b7ffd55bd4192af5ea979e2110b000000006b483045022100d598e2ccdeecfdfea9d5139a49a94fa39414f9e1ecb13d54efeb34c168e58aec02202a59463710905613844f48dc71d316c0cae54ab9e16dd95beb8902e5940024ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb90e762342456c7032806bd546929a38782761e2ee29e7aad37778e1ab6e0282000000006b4830450221008302d38e9eaccaea812c853047931562417a3665b8b9373cf7f63e58180b002602207ac8fddbbd19560a74333ec92fa077d169b4902a41e0431113f8fdb75b304ecf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe15523a831db30cf60f16b15dc338703a64058fa3830c17a4314b4ab824ca943000000006b483045022100c0d85a1f9146e8ef9efaef8ed9b3ed09c55e51b25e189735610da89b6d212360022003a49114e504741befcdb95d52a3dedd1aadef68b7c48f0a4a8c7dddfb4201b5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7893407b6997d973f52a924d03ebdfc639401a138c13e12c2ca365938135f841000000006b48304502210091ec8402cafd1e7eb11b56ac56a994ac79c435893108d0b7c8cfff87c07ba0a602204fd98efddc1b4e21bd3cb81217579a7b9621f9c3c204f2f5800e75ce1c60b19c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff016fa30c4594495726151cbe044ad53de6421e1f28e2366602bd80a3dea98c2f000000006b483045022100a850bf088a08baac1f1f577da8946befe2e6b0354d6a29f636afd39982569a7e022062652d6b75dee145f741d28d6f1870fde9a7d66b994f0d3162abdc42fbf54458412103ffdeec10b52942b0c46d6578998efdc1d64073de579e92e7c5dfa97fdf3ac391feffffffd8659400dae01e9cac6076cb19facc050061f64b16957ad30500503c24294840010000006a4730440220762f7c017672dfc71d487f3730e26d69d0e53902f579ba348095ca164d27b094022076c7e8045ec9fc57af6dd95f35c0ffad2c0ca8f83f112f60fb9851ba4ba15d92412103a2d2d8251728b11fd4afe7b8c73a8442f76dff9bfa424f5cad9b98083936259dfeffffff642ba174ff1ecc14e4f086d70300d487dbaae78bfc684b43557f9b8ad2ca2426000000006a47304402200654032c5760f8b94cc089da51773447f19c1cd2108cab89bb53ccfdb6dbee56022015e277622dea4bd1a7913ff934b2bb2d1b3d75f05285b51690160e1197a258c5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff654d602ce9a224bbce1fb5f9588977fd780591457ef11de271137ca7fd3c3b89000000006a4730440220712877c0dc553096eb0ebf101d1555fda5235db26ad074d2f330163fab63fc7802202c89752dd7645e8a3da7e8af5fb68dc8b177700766b79cf6a35695a0c7c873cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffcc614cc3c1c12c9b8cebba5d78a395f5347a5073211a04e03d55b0a8abf386cd000000006b483045022100f3fa1e305666e2a62afaa11fd37025b25c0bdff8709fe1580406615934228cee02204841a7d96f36d3c183f06e22a58175756c3e9a76c93c7cb4e9945f31ddedc902412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff26b2ed7a5c60815f5b62a5d30af9613e69a26e8aaa429be689baddb562e88aae000000006a473044022047c158e3fe3f40de3f39796dcecb7df3cf344f14009de9826b62a43837f2cdcb0220759d823cc145fd5e8b651a7bcc399544692bbf596189b1fc50bba5f4ca02cdd1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffebb012602f05d2bea0016b8b304f59f610922671560469d80e0e913cd2b302b4000000006b483045022100bd70744c867943bc3bf578e192c8a87a5ed5126aac4acd98efa06ea2483911fa02207377e11ae2d2bbaab00da86ec73c26e596bfcc680c0b8eddc5d44bda650bc299412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff87809cf57be510d02c71276f00544888795f624f33d78b01ba63c87340dadee1000000006a473044022059ee25066b8a2a4fdfc35f14c5cbb7f22ab181fcfa9702d4f3de7aa4d738c7a402206dff315ad1cd2222cd6ac074bf34241fc22db38a57bf089f7e24542323f1766c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8c33b7af2120bb22742f4a5e5fb4ecca7cdf73a33bc8811f3d5d3d1cd9399c21000000006a473044022039657cdf4fcd5a9e81766ba11db495b8be5664612d3b91f8504bea342c4ecbe702206ca4913e5807cd697d30dbc93e0a9d679eb01ee84b687ab0c642e2f3ebde745b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8142c39bf2f91bc685f7c08e40450c90b36dc0a6782a764cded6ba744a591f3a000000006a47304402200232ee94873317eae275cf715f4c3aca25dd0c8db4800946a45cc1d9c45732fa02203d9ce9c9aedc0a3899dd027df32e683438769d66f33ffe52006454614b77821d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff503b9a4c5cab71a66b685d3266002970227d0f4a6b1c65b86603b8c8e683cf14000000006b483045022100900bdc6f705efa56449a65f15a67fc7fbbc102f78e7974ea6ac2849c75d2dfec02203b78de71dad2e3f6ffad2779cb9007217c957c8f5db7abd58fd0537fbabb8c6b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8bed144f5515754d58c273554d25637ec776635033c9ae13bfc94e4b6cecd11d000000006b483045022100becbb21c7937b9b27ea3cdac5f2048ab9ac314de59c3ee2926a5cfb258ce14e902201c8022bf275c1a761e7715b14e15d74526901363ae5f8bf5489d00908dd758eb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbcb7881db3ede1d9275508f97b9f1e0e008811ce540f3b42a921e26f6f065799000000006b483045022100ad84bcd69a85a0d487fd7cbe4d76b95bffa303e76615a4336419fd182eeae4b902206d21e4f592297e87f1af9e19c80fd978914aaf5a2db2cf499b72cabbbe73c831412102958762ff6c8985dc9656afda59e61afc6c0131a5d8f1d86c87c83c9b37f7bd18feffffffb7ffae52888348a77a9851617df104a29366126e01ecc6bf7d209fc8627646ca000000006b483045022100edfd64cf9335d094d5873deb38cda5f4ceda3351df722f1c718993a2dd12c8e302203126b0f9470a4d0867ed4e773518b8ad689ce43a2c9f65a1f297525fc22201dc412103f37089783028c0776f2b8a9d8481ec8d6d0652a31edc03cc274032ae17c63c62feffffff801a88dcf5725d71cc70aee29ec937233f7a059d60e068dea3b7dbc806e0fd54000000006a4730440220448751a749e7cccacab0ae1ad4da948b0e0b5d8e3f41ac2b22c18928e8e67d41022051c107c345c06ea82fe8329a8cf3a96b516fd8750611d8ef438b8545416398ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbb06af741ad8b99821ecc4dfb5b52a0a79b577cf213eb9335e920d13707c8da0000000006a47304402207f9b2802ed1e893168277204b7919ff479efe5c71ad2a255e1738a52bacd758f0220253780485f2e3ee960e058d449c647b147b8f64b49b913e7e9615a6c7114f18e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7827759ce0800e385c440c45ccf6c568a25139aa0f1c80b86f28487ae6a8c0e2000000006a4730440220778fd8ba1dd9f71df55bbe1c3c4185b8da21dda82198546c2a0c30250f4c1d66022040f17a46187d535c6e943c047942f45159a37b2e171db18c657cd24168c22e2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2af935dfaa292af30d0a39a548e81640765b624eb5213d964ebaaa81a3711922000000006a47304402202cd2fd29fa395a5a80893de065c8bbe71e0bfe0e7b2224cfd5684736a086aabc02206720226ba63a3e5d9e2dc67e404625cdf31a7a08da0e8a22717e558f7abc817c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe3e3b78cff7d4798f6e3c8c45d87ac2131913d1328947d6b4ed515b3ab2366bf000000006b483045022100f8769b797386f0bdd662483096f4e0a33c13f6074a4aaba3fd590b9abbca7c2402201eb064869fcd17a59ac028145b08c73b3552544cd7fc62245d1fd1d369ecf765412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffdc319b5c9374a41a08f5f3bd45480a968f651878cde667b3ee3714f72b836be6000000006a4730440220558e65fd916d9c9616a3e0bd41111dba3914867b1ce5d487df4f77feadc0059502203198566c0d58af8551b65f884db98bde161bac140c7a900cd40df97a40c267de412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff69406ab4a28198623b6005bffa68588fea73092364cf2f7a223884c3e0732845000000006b483045022100ca93287feb58daad47c5388067b219e44f8533a214eb8eea9b5313040579773002201716a6ad2de70eff6721ae7950edaf9230420648bb8ec53173c215cbd12246c0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff21e5177112fa1fb5797389490a4f9131600673f139a544050a557fb627b0b360000000006a473044022003240fd71510800910b448c62a03178b4ef62299b17d6d2c06ac8f3293684ff50220637e3ba59fc884a8bd16aa2e884b379d85f38ae4ba049a0365f33644febee6df412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff5488e67a575ab8556c748fc371515b52ff28eb875586eba99fda2b4389e4f96c000000006a47304402202e2ac9c8b619b8e2626895c20f6bdd1a24fa27de017d05d5fa2ce120b3421f25022053ef6f82ccf9a132d40ce566d45f4ec18bf30048d415f6ec1c783cda027b6747412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff03abe81fdd0362f4fa3bae282c2ab1be258882d83392229cea6e36c3f023999c000000006a4730440220352bdfe541e9e1ce428ac4eb4c8ba9391a118b7dbe57b4fe3c4ecd30f228fbff02204a0b78ada1d74a7e7b9ae912e6f445d9ce9050855d9c5ecc7d477d2590a68b18412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff879d7ac96bbdcb9aff885fb27c0f171277a313ef45b8143e04b74d6fa43fd25e000000006946304302203f767d8f64e3c9e5773d94a325f8029d21d1c9a0f470c9288cd99f70d2d90ec2021f50b395f9329ffe64ff8084c1506e904ffc02dfac7f7e15461c3e8a077f604c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffff00dc8aec564568fdd9114502ed1998de08228bfe4edf74d132cfe595c709fb000000006b483045022100f17f8045a627bf96fe09d868109063d8040e3e2df8944e05f9b20a15273d0bdb022059c31e2d849abd57e784f1a3903f49f18c7c5a624545bab98649e8a092e12a10412103ee2a3f78cd4930dac8c030ccc93381ec5eab259c1607360d85d1728fc296dacffeffffff3f25af68c0083801bf09571e1a300d78768df58ec82e2961a374600bcf90bf36010000006b483045022100b58c7dd3fa1f8dc50edc7b5546b8ccef8ffc5c179fee774999c63fa729ae3cef02205eb611cc887e5a62a4e9da33318ce6e216ca353225f452ebca51be1dd10f544941210267f3c9b9bfb6bc5c1f68dd1d18623a9986408202cf232ad1e4089933c83f186bfeffffff6a94e760788c3ee1c9696e5552020afc2a77bfcb3b2223e35744f1b9abc49b25000000006a4730440220097f46c588f37ced4846a45905df1a0ae22709760f8a1bc930a58f5054cbe482022053b418af66d1edcb3887616feb23e5dd4095f29e74ac89853c3b909eb42bac34412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb26042d45f30556ab14a69f8be4ce1ac4a360b8407d7da6dde0983f73123a314000000006b483045022100cf98e22a2854c7088a0572e1edb4e876aa622ed10dc0376806e1432f5dc1eef90220527845f8dd2522fbdf423b4fc34a4792a7f82e04b314e0d83e2425daa2f92115412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe5f0f3bfd4691a43d7488076a0e13ff739c72c6f421d6c0e61a75232ea36d8ac000000006a473044022070c7aaa7d7f050b1b520878e55db3ca491fb33211150e2f620b685cb49d7d885022022d9ede63e3b196a1c33c2d211c1eacf2e2411820ecf5155b5e4244f5dfd9f1d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffffef905cc2f8ca7d7885f06ad865b721f594595528c2b971b3172313cc7df8c34000000006a473044022018cd70c3e62563ea92ea12735e2efb4b905df85e6b290d573051f49c63d07c60022037a537ca3514121d5c2b8753833808a5e0432f1a8f277d91495953c8211ad326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff556c7570226e99590f0844c677068cd133f882c7a720f77f32bac2be39aa7baf000000006b483045022100a01ad9ec8d24fdf01eb203c2887c1413ae56990d4600a18010959f6df43de08d022056f0f0dccb8f772f29a7835d7dc40f242348805005b5f80ae8f2fbdb600ab2ca412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff52bec1a85abc7d806dfc9c39427b7cbab7be3aeca8ee99959c84b68cc05ca96b000000006b483045022100cdd770159d56ac518ecb0dc916df0da06eed536e540582680f742389f53fa4be022012d372e2c04176bcb82b91b02ea23c9c1464baef7d1dda66066bf84c402c0012412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3b2d0442ce89e456c2cfc586906116d280fce17bc310ed957d03b35c61e9eb41000000006a473044022001dc7db378891c1c5bf07a09d14fcc6675965976e2e3e762786b1b1e0f4a4bb702206db6f284dec835823fb516fad89543edd3bd7af3ed33940fa296939fadb41ba841210393ae47ec2e844378cda3630abe12082401f2e0f98d016dde2b152b42e335630dfeffffffc3804827d4f39c54d961dfe79e25325f59b5499ea25b49bfe7ac99bd7c7435a1000000006a4730440220290a5055313d68f9461ce830f8a7395022d2d55abf28f6b4bd665693b4a13730022035d4cc2a6676ed842027dd4f21d31dd5a956f4b1f5cf771b866cc0d4a6400df0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffd610149123afe34fa647cb0aee336cb903961bee6653b8eefc7f49bb015e0990000000006a47304402201fd6be6d72ae75b61a624c13476b538ec2f9e5146f3074c879af57ecfbe1679702200ab10ae612e7fe0f76fe943c1f6a02262008407f86782c1536e92e3bad77d3db412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff205fab854da34166e1d16d36ab90b1e825440f6c9067ef35d34c41c5e569b144000000006b483045022100a4132f408b5299dfed6153b7a331f9fe866f1b042e4263bf7574ea0964c450a202203d99cf8dc9a9194269bce400185a4f86f5d35b5be83f6dbc3166b600392f1b00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8ead5e6ad78ed4926b83bc4a479d4dc5b2dbd2753af5636044cb008f4c6df1f7000000006b483045022100bbcc2e2d77458abc30898cddc7eda060b23a62f0a53b81c3db47f284cd7b29cf0220705328a29bd30792a7f5a704fd74b771c3c8a099265f5e7c9d70046da5b03ff4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff2361f9f2ba5ff1e66349c365e1c0cd9c6cb80ab4f666e9f4777fc188a405202010000006b483045022100d2f40145c4b9a17b3582aabdf7d9ac2d47546b3eea5350c4e2ec1e9c2466343d02203354ce620aa056a749de847f867c49dd121579c9fc50bd6258bff7cfb173c5f24121035bf755e8b075665a85155618f6e9022196a09c486415587dd3af0d25b76e9c27feffffffc8f56b2dc9536ae2c0e11b2062edda6cb33b93284ce7bd8c6531591ae82f0074000000006b483045022100cf8c593dec0724644d034f17ccde99feaf0416334219f158f884badf500fc93e022035af1b68574e88ef15e1c05c1b36638401613a31aa7096d97efba6df62695706412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff95831f16b9696da7fe12787860ca161c12566d110c9262097434a7e0674d6b49000000006b483045022100a669e8918ba68754b84d584f38afdd34be387773449784a6c61ef3f33d0fd99e02204d007ef31f5a3a7c412ac3d2660633fcef137964ef2ff6269c41e933896d918b41210383b6491fd80e1411675d7c8eda9b756c30a814b45fa565b7ac24d7be9dedcaaafeffffff1e1184fc54a53f94ee4d56313349f586effea0bf553bbd0cccefe86c8d606f4a000000006b483045022100fc35ed21833c3ea3ff5f832ef02236a08ded0999ea367aa6eaaff364ecac3e5002206e291d7c4fca0485dd8ea22519544ac632909d706741710a6e5f0d472c0b0656412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4864e36057e4fe2ece01c3b463c06b56a86e3c341aa0e203097cb09c53a2cfa9000000006a4730440220485937c55c67c8eb46b94523cb06f9572ffb55094536d8b1a458c76b67dec75b02204e5007f610e491d043a412696d4fd769bb2f5d8c3e8b3a59e6ec3bb598f775a7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffeed8d2da2afa9b9823aa74a344f6eda5d4b80e5de83caf8455b08c8aac6c4662000000006b483045022100b430528ddfca4431cf5cec08964f7325c036fdee55edc0ea0181d34ed72469bc022074b75bfa66dd4a87fab93da0f2f0def65b785fb0b51fe07355799cbd8b30c39a41210316d35753d58318c06d0faadcb723563316847ae06019984f42f2c75deaf3727dfeffffff4317e8c939993e123310aa4d84dfa4a29ba8dcc0b4c222384ded077936279955000000006b483045022100c6ccc3891fa3924c7b1e69b855628230c48d85d1e1331f037823ab7c5928610c0220050c9c0e078f34ced537e88f95289863a663b28488880f6ada3f1dbbcb1743a1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff85aed5e452015314973015efa03f0bd2c79d57d976ce3f3ce14498b294fd5b7b000000006a4730440220168f31f413d65ce64bccb62390490dae2e4a00f98c2c44bd4fd689cd942da8b1022006f1b2aa4fae9587c688e8b7ca5c07db3b3c3afd6961f9f843099ed30b583369412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0286800000000000001976a9149a262d0621819c8c17d34a7feca1b39b39157af988acceb18bca1a0000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac26550900" + }, + { + "txid": "99300f90ced7d053b3b24ef3a8fdb5774418e616f07971366a63b9938944ab2d", + "version": 2, + "lockTime": 609135, + "vin": [ + { + "txid": "f0202389fab209e6975199ec2d8abf76fd4cea5d7d441ea0938ff47a35366c45", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" + ], + "isAddress": true, + "value": "1250016811", + "hex": "473044022001b8ba5dbc580e3bf4419b65892f15423e8b0e48d52479fd0317fe4c03ede0a002204013a50c3914aeb7f59183f9e44c880bc94fe9c23045a6311ae4b07da3c2d209412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" + } + ], + "vout": [ + { + "value": "1000000000", + "n": 0, + "spent": true, + "hex": "76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac", + "addresses": [ + "bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7" + ], + "isAddress": true + }, + { + "value": "250016585", + "n": 1, + "spent": true, + "hex": "76a9146932df2f990838523783075db0b985b9bd2330b088ac", + "addresses": [ + "bitcoincash:qp5n9he0nyyrs53hsvr4mv9eskum6geskqthlx9n4d" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000002132a5e60d7b9de0524eeffb36fc91972a7d68afdf17b65", + "blockHeight": 611545, + "confirmations": 20638, + "blockTime": 1575274423, + "value": "1250016585", + "valueIn": "1250016811", + "fees": "226", + "hex": "0200000001456c36357af48f93a01e447d5dea4cfd76bf8a2dec995197e609b2fa892320f0000000006a473044022001b8ba5dbc580e3bf4419b65892f15423e8b0e48d52479fd0317fe4c03ede0a002204013a50c3914aeb7f59183f9e44c880bc94fe9c23045a6311ae4b07da3c2d209412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0200ca9a3b000000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac49f3e60e000000001976a9146932df2f990838523783075db0b985b9bd2330b088ac6f4b0900" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/dash-api-address.js b/mock/ext-api-dyson/get/dash-api-address.js index 2a7ae47b1..74e0dda54 100644 --- a/mock/ext-api-dyson/get/dash-api-address.js +++ b/mock/ext-api-dyson/get/dash-api-address.js @@ -1,175 +1,110 @@ /// Mock for external Dash API /// See: -/// curl "http://{dash rpc}/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" -/// curl "http://localhost:3000/dash-api/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" +/// curl "http://{dash rpc}/api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" +/// curl "http://localhost:3000/dash-api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" /// curl "http://localhost:8420/v1/dash/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" module.exports = { - path: '/dash-api/address/:address?', + path: '/dash-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 'XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG': return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "addrStr": "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG", - "balance": "167.97080211", - "totalReceived": "1302.03239791", - "totalSent": "1134.0615958", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 618, - "txs": [ - { - "txid": "35541e151818606a512bb88acddb449449f46531e97f1ed0a5fcc0d7a8091e41", - "version": 3, - "vin": [ - { - "txid": "", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": {}, - "addresses": null, - "value": "" - } - ], - "vout": [ - { - "value": "1.55334749", - "n": 0, - "scriptPubKey": { - "hex": "76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac", - "addresses": [ - "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" - ] - }, - "spent": false - }, - { - "value": "1.55334763", - "n": 1, - "scriptPubKey": { - "hex": "76a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac", - "addresses": [ - "Xb8cmjtK67y9T2haqrcDicoAMByDesLcAe" - ] - }, - "spent": true - } - ], - "blockhash": "000000000000000f432c35cbd89c013333cf591c72d15959a51100625d263243", - "blockheight": 1239931, - "confirmations": 3276, - "time": 1584614323, - "blocktime": 1584614323, - "valueOut": "3.10669512", - "valueIn": "0", - "fees": "0", - "hex": "03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff27037beb121a4d696e656420627920416e74506f6f6c347c00330120ad45211b6b76000001000000ffffffff025d384209000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac6b384209000000001976a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac000000004602007beb12009d9eb909c943fd6b4aad565dc083dc2b53736359cc678af072352bbf409a942f3b0192d52c43692520241eb04505406f34adf6805fd5ab29113959133e8e1d3d" - }, - { - "txid": "f47a4929bcd8767819b6969c83893a76d5b26a145c74ace416ce4c454166186e", - "version": 3, - "vin": [ - { - "txid": "", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": {}, - "addresses": null, - "value": "" - } - ], - "vout": [ - { - "value": "1.56344682", - "n": 0, - "scriptPubKey": { - "hex": "76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac", - "addresses": [ - "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" - ] - }, - "spent": false - }, - { - "value": "1.56344689", - "n": 1, - "scriptPubKey": { - "hex": "76a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac", - "addresses": [ - "Xb8cmjtK67y9T2haqrcDicoAMByDesLcAe" - ] - }, - "spent": true - } - ], - "blockhash": "000000000000001709a13d55d31782a8d26ea3691c4d3433794b9ff2ee0b0ac7", - "blockheight": 1237951, - "confirmations": 5256, - "time": 1584303664, - "blocktime": 1584303664, - "valueOut": "3.12689371", - "valueIn": "0", - "fees": "0", - "hex": "03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff2703bfe3121a4d696e656420627920416e74506f6f6c357c006502207193bf88753900000d030000ffffffff026aa15109000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac71a15109000000001976a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac00000000460200bfe312006d5f02b8c49b966902195a3b2b581b4a5847901d5c66bf9820a35884c6a91b51b20d38a728281d7ba3a9b3c157593c9121850977cababcba9ab71729684d9723" - }, - { - "txid": "aaceebd8a59a777c8d27ede7d086f605a04e3463bd3465fd3fa02518fcd24abd", - "version": 3, - "vin": [ - { - "txid": "", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": {}, - "addresses": null, - "value": "" - } - ], - "vout": [ - { - "value": "1.55873001", - "n": 0, - "scriptPubKey": { - "hex": "76a9142832b5c571b5686c4a08dae4091d856c4f9b190a88ac", - "addresses": [ - "XeMPcKeVDN9bkECGDC7ggtf9QsX5thgKAx" - ] - }, - "spent": true - }, - { - "value": "1.55872988", - "n": 1, - "scriptPubKey": { - "hex": "76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac", - "addresses": [ - "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" - ] - }, - "spent": false - } - ], - "blockhash": "00000000000000021075e42769f6a1bd6ac477574266102b324197c158bf3a14", - "blockheight": 1237949, - "confirmations": 5258, - "time": 1584302904, - "blocktime": 1584302904, - "valueOut": "3.11745989", - "valueIn": "0", - "fees": "0", - "hex": "03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff1703bde31212563c785f430fb8fa7417000000002f4e614effffffff02e96e4a09000000001976a9142832b5c571b5686c4a08dae4091d856c4f9b190a88acdc6e4a09000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac00000000460200bde312006d5f02b8c49b966902195a3b2b581b4a5847901d5c66bf9820a35884c6a91b51b20d38a728281d7ba3a9b3c157593c9121850977cababcba9ab71729684d9723" - } - ] - } + { + "page": 1, + "totalPages": 333, + "itemsOnPage": 2, + "address": "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG", + "balance": "24107591472", + "totalReceived": "137513751052", + "totalSent": "113406159580", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 665, + "transactions": [ + { + "txid": "8a1859bb849e207b7771c0301a6109a039eec955234b7848715b150f20fabeca", + "version": 3, + "vin": [ + { + "sequence": 4294967295, + "n": 0, + "isAddress": false, + "coinbase": "035c33131a4d696e656420627920416e74506f6f6c347c000b02203c94a613416a0000be010000" + } + ], + "vout": [ + { + "value": "155331342", + "n": 0, + "hex": "76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac", + "addresses": [ + "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" + ], + "isAddress": true + }, + { + "value": "155331350", + "n": 1, + "hex": "76a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac", + "addresses": [ + "Xb8cmjtK67y9T2haqrcDicoAMByDesLcAe" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000f2a4362c05fd3aeca12640061c9c119862cf20b2cc95560a8", + "blockHeight": 1258332, + "confirmations": 1181, + "blockTime": 1587515977, + "value": "310662692", + "valueIn": "0", + "fees": "0", + "hex": "03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff27035c33131a4d696e656420627920416e74506f6f6c347c000b02203c94a613416a0000be010000ffffffff020e2b4209000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac162b4209000000001976a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac000000004602005c3313008c104ddcb4ef489cb517b4ae6aeec851ab8010748b00d20c7bb10b2a86c9ed6478777117ab77017feac02c03ef31f19a0ddfa3e1039f8d364a79cb22052233e3" + }, + { + "txid": "bc017866f1eb2118c59d3c7b6127b96ecce595062abc626f468345782f0bba9f", + "version": 3, + "vin": [ + { + "sequence": 4294967295, + "n": 0, + "isAddress": false, + "coinbase": "03033313042c599f5e0100048e1c1d000000000000" + } + ], + "vout": [ + { + "value": "155462330", + "n": 0, + "hex": "76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac", + "addresses": [ + "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" + ], + "isAddress": true + }, + { + "value": "155462346", + "n": 1, + "spent": true, + "hex": "76a91417158751f496276811c148495b28915314dd9fc088ac", + "addresses": [ + "XcnuAVsG4pRCqxQmQB6PeTX8FJo2ssYPyB" + ], + "isAddress": true + } + ], + "blockHash": "000000000000001c141317365929a3d7937f21be525873142bdaebbdcebe7a1d", + "blockHeight": 1258243, + "confirmations": 1270, + "blockTime": 1587501361, + "value": "310924676", + "valueIn": "0", + "fees": "0", + "hex": "03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff1503033313042c599f5e0100048e1c1d000000000000ffffffff02ba2a4409000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188acca2a4409000000001976a91417158751f496276811c148495b28915314dd9fc088ac000000004602000333130024b54c2354b15fb05d02604e811682ea82b3e81abf3610a4019a9fde7963be6ef022b80b9ef1524c1629323e53296cebee22b80dde230ed8eaee578d5a0f4457" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/decred-api-address.js b/mock/ext-api-dyson/get/decred-api-address.js index ad7fc2648..7696c573a 100644 --- a/mock/ext-api-dyson/get/decred-api-address.js +++ b/mock/ext-api-dyson/get/decred-api-address.js @@ -1,134 +1,118 @@ /// Mock for external Decred API /// See: -/// curl "http://{decred rpc}/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" -/// curl "http://localhost:3000/decred-api/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" +/// curl "http://{decred rpc}/api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" +/// curl "http://localhost:3000/decred-api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" /// curl "http://localhost:8420/v1/decred/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" module.exports = { - path: '/decred-api/address/:address?', + path: '/decred-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 'DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY': return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "addrStr": "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", - "balance": "0.19473147", - "totalReceived": "0.7496027", - "totalSent": "0.55487123", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 10, - "txs": [ - { - "txid": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0", - "version": 1, - "vin": [ - { - "txid": "2dc905f525885537310c8ab87f67dc175ca369af1fe7111a49a94451866aa019", - "vout": 0, - "sequence": 4294967291, - "n": 0, - "scriptSig": { - "hex": "473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" - }, - "addresses": [ - "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" - ], - "value": "0.00591955" - } - ], - "vout": [ - { - "value": "0.001", - "n": 0, - "scriptPubKey": { - "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", - "addresses": [ - "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" - ] - }, - "spent": false - }, - { - "value": "0.00489415", - "n": 1, - "scriptPubKey": { - "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", - "addresses": [ - "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" - ] - }, - "spent": false - } - ], - "blockhash": "00000000000000000c12cb497e60470a3cf366d16705eaba303c2c4415cc7567", - "blockheight": 429609, - "confirmations": 5412, - "time": 1583516573, - "blocktime": 1583516573, - "valueOut": "0.00589415", - "valueIn": "0.00591955", - "fees": "0.0000254", - "hex": "010000000119a06a865144a9491a11e71faf69a35c17dc677fb88a0c3137558825f505c92d0000000000fbffffff02a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acc77707000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac0000000000000000015308090000000000dbcc05000b0000006a473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" - }, - { - "txid": "025abf340da79c4fc4de29667c08fc22cdafbded24c7c2a994a27f6fb4d5fa17", - "version": 1, - "vin": [ - { - "txid": "5a2a0d01ed8672d6bebd7dee447b2e0342bfc34fd4893bed58a4fa5aa87a4c42", - "vout": 0, - "n": 0, - "scriptSig": { - "hex": "483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" - }, - "addresses": [ - "Dsf6WkLoiTcSGKmkXoSEdukqUfeRJMqUNJV" - ], - "value": "0.1999198" - } - ], - "vout": [ - { - "value": "0.001", - "n": 0, - "scriptPubKey": { - "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", - "addresses": [ - "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" - ] - }, - "spent": false - }, - { - "value": "0.1988944", - "n": 1, - "scriptPubKey": { - "hex": "76a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac", - "addresses": [ - "Dsesp1V6DZDEtcq2behmBVKdYqKMdkh96hL" - ] - }, - "spent": false - } - ], - "blockhash": "0000000000000000264c499f21a7ef95bffb37148fc099514b2407dfa28c3287", - "blockheight": 429186, - "confirmations": 5835, - "time": 1583384838, - "blocktime": 1583384838, - "valueOut": "0.1998944", - "valueIn": "0.1999198", - "fees": "0.0000254", - "hex": "0100000001424c7aa85afaa458ed3b89d44fc3bf42032e7b44ee7dbdbed67286ed010d2a5a00000000000000000002a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac207d2f010000000000001976a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac000000000000000001ac0d31010000000052630600050000006b483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" - } - ] - } + { + "page": 1, + "totalPages": 5, + "itemsOnPage": 2, + "address": "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", + "balance": "19473147", + "totalReceived": "74960270", + "totalSent": "55487123", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 10, + "transactions": [ + { + "txid": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0", + "version": 1, + "vin": [ + { + "txid": "2dc905f525885537310c8ab87f67dc175ca369af1fe7111a49a94451866aa019", + "sequence": 4294967291, + "n": 0, + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true, + "value": "591955", + "hex": "473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "489415", + "n": 1, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000c12cb497e60470a3cf366d16705eaba303c2c4415cc7567", + "blockHeight": 429609, + "confirmations": 13942, + "blockTime": 1583516573, + "value": "589415", + "valueIn": "591955", + "fees": "2540", + "hex": "010000000119a06a865144a9491a11e71faf69a35c17dc677fb88a0c3137558825f505c92d0000000000fbffffff02a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acc77707000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac0000000000000000015308090000000000dbcc05000b0000006a473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + }, + { + "txid": "025abf340da79c4fc4de29667c08fc22cdafbded24c7c2a994a27f6fb4d5fa17", + "version": 1, + "vin": [ + { + "txid": "5a2a0d01ed8672d6bebd7dee447b2e0342bfc34fd4893bed58a4fa5aa87a4c42", + "n": 0, + "addresses": [ + "Dsf6WkLoiTcSGKmkXoSEdukqUfeRJMqUNJV" + ], + "isAddress": true, + "value": "19991980", + "hex": "483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "19889440", + "n": 1, + "hex": "76a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac", + "addresses": [ + "Dsesp1V6DZDEtcq2behmBVKdYqKMdkh96hL" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000264c499f21a7ef95bffb37148fc099514b2407dfa28c3287", + "blockHeight": 429186, + "confirmations": 14365, + "blockTime": 1583384838, + "value": "19989440", + "valueIn": "19991980", + "fees": "2540", + "hex": "0100000001424c7aa85afaa458ed3b89d44fc3bf42032e7b44ee7dbdbed67286ed010d2a5a00000000000000000002a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac207d2f010000000000001976a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac000000000000000001ac0d31010000000052630600050000006b483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/digibyte-api-address.js b/mock/ext-api-dyson/get/digibyte-api-address.js index bab0bb9d7..fab82b546 100644 --- a/mock/ext-api-dyson/get/digibyte-api-address.js +++ b/mock/ext-api-dyson/get/digibyte-api-address.js @@ -1,187 +1,121 @@ /// Mock for external Digibyte API /// See: -/// curl "http://{digibyte rpc}/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" -/// curl "http://localhost:3000/digibyte-api/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" +/// curl "http://{digibyte rpc}/api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" +/// curl "http://localhost:3000/digibyte-api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" /// curl "http://localhost:8420/v1/digibyte/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" module.exports = { - path: '/digibyte-api/address/:address?', + path: '/digibyte-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 'DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi': return JSON.parse(` - { - "page": 1, - "totalPages": 4, - "itemsOnPage": 1000, - "addrStr": "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi", - "balance": "0", - "totalReceived": "2317.03950234", - "totalSent": "2317.03950234", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 3428, - "txs": [ - { - "txid": "3ad1035d37f47061599a5055284a8b2acc0facc6039353b1822f0a3c0f1d6906", - "version": 1, - "vin": [ - { - "txid": "14f845047925fb36e5a0c569f2c1d2b7c5be4543e46920b49eb732860bf5b02a", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": { - "hex": "47304402202fc0e7eebec384bcff141800990f80742d2ed97db02784fb383cd4cd42aca71e02202be0f292a8209bff5682e05424170632bb7023a7aaca0dca1faf54af1e8eec16012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057" - }, - "addresses": [ - "DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW" - ], - "value": "0.7988" - } - ], - "vout": [ - { - "value": "0.79879", - "n": 0, - "scriptPubKey": { - "hex": "76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac", - "addresses": [ - "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" - ] - }, - "spent": true - }, - { - "value": "0", - "n": 1, - "scriptPubKey": { - "hex": "6a45524d555453422e41432e544800000000000025aba398bee3241347368c2d4d758575c7fe00138abe258456087c4f640ae3274c452f87d110bc12ee1f77ed9b365a49d6c547", - "addresses": [ - "OP_RETURN 524d555453422e41432e544800000000000025aba398bee3241347368c2d4d758575c7fe00138abe258456087c4f640ae3274c452f87d110bc12ee1f77ed9b365a49d6c547" - ] - }, - "spent": false - } - ], - "blockhash": "0000000000000007fa73216ba848e3d029f91a088f628cc1780f333d7e13311d", - "blockheight": 10510734, - "confirmations": 30461, - "time": 1584668841, - "blocktime": 1584668841, - "valueOut": "0.79879", - "valueIn": "0.7988", - "fees": "0.00001", - "hex": "01000000012ab0f50b8632b79eb42069e44345bec5b7d2c1f269c5a0e536fb25790445f814000000006a47304402202fc0e7eebec384bcff141800990f80742d2ed97db02784fb383cd4cd42aca71e02202be0f292a8209bff5682e05424170632bb7023a7aaca0dca1faf54af1e8eec16012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff0258dbc204000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e544800000000000025aba398bee3241347368c2d4d758575c7fe00138abe258456087c4f640ae3274c452f87d110bc12ee1f77ed9b365a49d6c54700000000" - }, - { - "txid": "d7efaffeded550697d7385d3eb07e539237615792b29e3639df427ce919c8d6e", - "version": 1, - "vin": [ - { - "txid": "a7613f7242b3a24ca6f1de2c15be605411d01f6d86ed1cf0037da9d0e908bf0e", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": { - "hex": "47304402201d09be67618dc89a882c389560e73713302cb3d120adbae814e06ed15b2a17e002204595a11648173fe085a820b034394c1264ddd30b0e2dfdb07d3ebb46067145c10141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48" - }, - "addresses": [ - "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" - ], - "value": "0.71187" - } - ], - "vout": [ - { - "value": "0.71186", - "n": 0, - "scriptPubKey": { - "hex": "76a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac", - "addresses": [ - "DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW" - ] - }, - "spent": true - }, - { - "value": "0", - "n": 1, - "scriptPubKey": { - "hex": "6a45524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f1891", - "addresses": [ - "OP_RETURN 524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f1891" - ] - }, - "spent": false - } - ], - "blockhash": "6518a4fe30d601f87370aca047d1e2bcc3eaf72a194fc05f475bdbf24ca6d36e", - "blockheight": 10493876, - "confirmations": 47319, - "time": 1584416875, - "blocktime": 1584416875, - "valueOut": "0.71186", - "valueIn": "0.71187", - "fees": "0.00001", - "hex": "01000000010ebf08e9d0a97d03f01ced866d1fd0115460be152cdef1a64ca2b342723f61a7000000008a47304402201d09be67618dc89a882c389560e73713302cb3d120adbae814e06ed15b2a17e002204595a11648173fe085a820b034394c1264ddd30b0e2dfdb07d3ebb46067145c10141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48ffffffff0250363e04000000001976a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac0000000000000000476a45524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f189100000000" - }, - { - "txid": "a7613f7242b3a24ca6f1de2c15be605411d01f6d86ed1cf0037da9d0e908bf0e", - "version": 1, - "vin": [ - { - "txid": "3e4e8f95cf76c3a1bb91283e8c55ba5a7c103cc31b1c25c4587916666fbb8263", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": { - "hex": "47304402202560cf31d48b023fb44383c79f1685420af0365d87377589f9fa493f66c6d97f02201724f2c0c41ff384fc53d128fec351093d8f2d54332cc7191153008080c4f9a7012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057" - }, - "addresses": [ - "DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW" - ], - "value": "0.71188" - } - ], - "vout": [ - { - "value": "0.71187", - "n": 0, - "scriptPubKey": { - "hex": "76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac", - "addresses": [ - "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" - ] - }, - "spent": true - }, - { - "value": "0", - "n": 1, - "scriptPubKey": { - "hex": "6a45524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f1891", - "addresses": [ - "OP_RETURN 524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f1891" - ] - }, - "spent": false - } - ], - "blockhash": "6518a4fe30d601f87370aca047d1e2bcc3eaf72a194fc05f475bdbf24ca6d36e", - "blockheight": 10493876, - "confirmations": 47319, - "time": 1584416875, - "blocktime": 1584416875, - "valueOut": "0.71187", - "valueIn": "0.71188", - "fees": "0.00001", - "hex": "01000000016382bb6f66167958c4251c1bc33c107c5aba558c3e2891bba1c376cf958f4e3e000000006a47304402202560cf31d48b023fb44383c79f1685420af0365d87377589f9fa493f66c6d97f02201724f2c0c41ff384fc53d128fec351093d8f2d54332cc7191153008080c4f9a7012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff02383a3e04000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e544800000000000025a8a398bee3241347368c2d4d758575c7fe00f810517db039aa4a3055e73c5eca51dccdad9a31ff0deccfa3ab44611f3f189100000000" - } - ] - } + { + "page": 1, + "totalPages": 1821, + "itemsOnPage": 2, + "address": "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi", + "balance": "0", + "totalReceived": "238524073234", + "totalSent": "238524073234", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 3642, + "transactions": [ + { + "txid": "2b7ba9b43d615fe03bc14bc18201d1bd73c7a0f8aad428accf51725743f9073a", + "version": 1, + "vin": [ + { + "txid": "cba15c1782f15d1f3a5dfd6f06bad6ee03183d4d2bb3699bf72b9a423f4a97a3", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" + ], + "isAddress": true, + "value": "47451000", + "hex": "473044022015642218d196b2bf010e10eb0eff952e0a6bd5bcb8aecd09751599bef8ca5df802205d277e3f6ac47ad360785df4462ffd2092618a58bcb0c8ae94751f26e5918fa30141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48" + } + ], + "vout": [ + { + "value": "47450000", + "n": 0, + "spent": true, + "hex": "76a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac", + "addresses": [ + "DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW" + ], + "isAddress": true + }, + { + "value": "0", + "n": 1, + "hex": "6a45524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de", + "addresses": [ + "OP_RETURN 524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de" + ], + "isAddress": false + } + ], + "blockHash": "00000000000000018af4a98ade5bb1d29d65871fd99b3cbaa8ea6266ea2c16a5", + "blockHeight": 10712917, + "confirmations": 1047, + "blockTime": 1587685950, + "value": "47450000", + "valueIn": "47451000", + "fees": "1000", + "hex": "0100000001a3974a3f429a2bf79b69b32b4d3d1803eed6ba066ffd5d3a1f5df182175ca1cb000000008a473044022015642218d196b2bf010e10eb0eff952e0a6bd5bcb8aecd09751599bef8ca5df802205d277e3f6ac47ad360785df4462ffd2092618a58bcb0c8ae94751f26e5918fa30141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48ffffffff029007d402000000001976a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac0000000000000000476a45524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de00000000" + }, + { + "txid": "cba15c1782f15d1f3a5dfd6f06bad6ee03183d4d2bb3699bf72b9a423f4a97a3", + "version": 1, + "vin": [ + { + "txid": "fae67ad84a3f6a7e7648f12122d649bb711178f0fd129286e2566df1f31fa08f", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW" + ], + "isAddress": true, + "value": "47452000", + "hex": "46304302205da10139f9ff5f0c0579237108634edce8dafa82feb7f63f0104b4596c5d0c98021f75ca71439e45a274b8953fa383d51938403043d961b59e9b078ef50a6fba01012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057" + } + ], + "vout": [ + { + "value": "47451000", + "n": 0, + "spent": true, + "hex": "76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac", + "addresses": [ + "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" + ], + "isAddress": true + }, + { + "value": "0", + "n": 1, + "hex": "6a45524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de", + "addresses": [ + "OP_RETURN 524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de" + ], + "isAddress": false + } + ], + "blockHash": "00000000000000018af4a98ade5bb1d29d65871fd99b3cbaa8ea6266ea2c16a5", + "blockHeight": 10712917, + "confirmations": 1047, + "blockTime": 1587685950, + "value": "47451000", + "valueIn": "47452000", + "fees": "1000", + "hex": "01000000018fa01ff3f16d56e2869212fdf0781171bb49d62221f148767e6a3f4ad87ae6fa000000006946304302205da10139f9ff5f0c0579237108634edce8dafa82feb7f63f0104b4596c5d0c98021f75ca71439e45a274b8953fa383d51938403043d961b59e9b078ef50a6fba01012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff02780bd402000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de00000000" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/doge-api-address.js b/mock/ext-api-dyson/get/doge-api-address.js index 02e07026b..0ee6732c8 100644 --- a/mock/ext-api-dyson/get/doge-api-address.js +++ b/mock/ext-api-dyson/get/doge-api-address.js @@ -1,135 +1,119 @@ /// Mock for external Doge API /// See: -/// curl "http://{doge rpc}/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" -/// curl "http://localhost:3000/doge-api/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" +/// curl "http://{doge rpc}/api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" +/// curl "http://localhost:3000/doge-api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" /// curl "http://localhost:8420/v1/doge/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" module.exports = { - path: '/doge-api/address/:address?', + path: '/doge-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 'D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh': return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "addrStr": "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh", - "balance": "513.94795942", - "totalReceived": "1602.02987826", - "totalSent": "1088.08191884", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 11, - "txs": [ - { - "txid": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9", - "version": 1, - "vin": [ - { - "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", - "vout": 1, - "sequence": 4294967288, - "n": 0, - "scriptSig": { - "hex": "483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5" - }, - "addresses": [ - "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" - ], - "value": "5.336" - } - ], - "vout": [ - { - "value": "1", - "n": 0, - "scriptPubKey": { - "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", - "addresses": [ - "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" - ] - }, - "spent": false - }, - { - "value": "2.754", - "n": 1, - "scriptPubKey": { - "hex": "76a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac", - "addresses": [ - "DKix6fTygojRpBFbADfkYKDX9nZ2Y7Huqq" - ] - }, - "spent": false - } - ], - "blockhash": "ece2c433edfaf7143ba79f381ea40ac8b7e38ce6c4ff0771ae1e3dda9246824a", - "blockheight": 3099770, - "confirmations": 59971, - "time": 1581351126, - "blocktime": 1581351126, - "valueOut": "3.754", - "valueIn": "5.336", - "fees": "1.582", - "hex": "0100000001987490208464a2b0547cf6fcae4b550be9bb9ca88ce526ef4a0ee5803da50df6010000006b483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5f8ffffff0200e1f505000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac40456a10000000001976a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac00000000" - }, - { - "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", - "version": 1, - "vin": [ - { - "txid": "c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb", - "vout": 1, - "sequence": 4294967291, - "n": 0, - "scriptSig": { - "hex": "483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" - }, - "addresses": [ - "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" - ], - "value": "8.418" - } - ], - "vout": [ - { - "value": "1.5", - "n": 0, - "scriptPubKey": { - "hex": "76a914e82178c73b5744342916f6a7a944af4fa37aebff88ac", - "addresses": [ - "DSJVQRY3wyVPrXbEDMSeoFufWNSsMeKEuj" - ] - }, - "spent": false - }, - { - "value": "5.336", - "n": 1, - "scriptPubKey": { - "hex": "76a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac", - "addresses": [ - "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" - ] - }, - "spent": true - } - ], - "blockhash": "d4a57feed1683117d412944fc6581eace1bc3a8be5ebab93cf2dd99f5918374d", - "blockheight": 3088989, - "confirmations": 70752, - "time": 1580673745, - "blocktime": 1580673745, - "valueOut": "6.836", - "valueIn": "8.418", - "fees": "1.582", - "hex": "0100000001fb1d11634e4149776ceb89325044be3f2b14989d65584f323c16bbd4d21ea5c6010000006b483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6cafbffffff0280d1f008000000001976a914e82178c73b5744342916f6a7a944af4fa37aebff88ac0017ce1f000000001976a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac00000000" - } - ] - } + { + "page": 1, + "totalPages": 6, + "itemsOnPage": 2, + "address": "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh", + "balance": "50394795942", + "totalReceived": "160202987826", + "totalSent": "109808191884", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 12, + "transactions": [ + { + "txid": "fee8381fed7406a48a8ea9e62328a3134064210626e81489ed8906e18c433bdf", + "version": 1, + "vin": [ + { + "txid": "c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb", + "n": 0, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true, + "value": "1000000000", + "hex": "47304402200833c3184e768e5b6da836d9824f98b65704a24229a02e572ac760bb304ab9fb022068d102da9400afaeee3a6b42930a966ff107f5c68affde4a0239dab9fa21123d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + } + ], + "vout": [ + { + "value": "134700000", + "n": 0, + "hex": "76a9142ba977acdb30bc18d350df32f38a777313ae86b088ac", + "addresses": [ + "D97xcKB9EAPmgNExbB5nAXDAQ9s5ZJ91J4" + ], + "isAddress": true + }, + { + "value": "707100000", + "n": 1, + "hex": "76a914b358390833fd8371733c1d11477bdb2d185e61e988ac", + "addresses": [ + "DMVPBRTD6bgqr3fk2yTdz97hS4AA2gzj8g" + ], + "isAddress": true + } + ], + "blockHash": "b94fd58d99710000ff0991ebf82c85330ed706ea18bcd4265e1f22747b91ddfe", + "blockHeight": 3170421, + "confirmations": 30293, + "blockTime": 1585794154, + "value": "841800000", + "valueIn": "1000000000", + "fees": "158200000", + "hex": "0100000001fb1d11634e4149776ceb89325044be3f2b14989d65584f323c16bbd4d21ea5c6000000006a47304402200833c3184e768e5b6da836d9824f98b65704a24229a02e572ac760bb304ab9fb022068d102da9400afaeee3a6b42930a966ff107f5c68affde4a0239dab9fa21123d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca0000000002e05b0708000000001976a9142ba977acdb30bc18d350df32f38a777313ae86b088ac607d252a000000001976a914b358390833fd8371733c1d11477bdb2d185e61e988ac00000000" + }, + { + "txid": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9", + "version": 1, + "vin": [ + { + "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", + "vout": 1, + "sequence": 4294967288, + "n": 0, + "addresses": [ + "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" + ], + "isAddress": true, + "value": "533600000", + "hex": "483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + }, + { + "value": "275400000", + "n": 1, + "hex": "76a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac", + "addresses": [ + "DKix6fTygojRpBFbADfkYKDX9nZ2Y7Huqq" + ], + "isAddress": true + } + ], + "blockHash": "ece2c433edfaf7143ba79f381ea40ac8b7e38ce6c4ff0771ae1e3dda9246824a", + "blockHeight": 3099770, + "confirmations": 100944, + "blockTime": 1581351126, + "value": "375400000", + "valueIn": "533600000", + "fees": "158200000", + "hex": "0100000001987490208464a2b0547cf6fcae4b550be9bb9ca88ce526ef4a0ee5803da50df6010000006b483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5f8ffffff0200e1f505000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac40456a10000000001976a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac00000000" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/groestlcoin-api-address.js b/mock/ext-api-dyson/get/groestlcoin-api-address.js index 1feaa2b36..b552240c0 100644 --- a/mock/ext-api-dyson/get/groestlcoin-api-address.js +++ b/mock/ext-api-dyson/get/groestlcoin-api-address.js @@ -1,137 +1,125 @@ /// Mock for external Groestlcoin API /// See: -/// curl "http://{groestlcoin rpc}/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" -/// curl "http://localhost:3000/groestlcoin-api/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" +/// curl "http://{groestlcoin rpc}/api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" +/// curl "http://localhost:3000/groestlcoin-api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" /// curl "http://localhost:8420/v1/groestlcoin/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" module.exports = { - path: '/groestlcoin-api/address/:address?', + path: '/groestlcoin-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case '33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj': return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "addrStr": "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj", - "balance": "0", - "totalReceived": "59.5115306", - "totalSent": "59.5115306", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 2, - "txs": [ - { - "txid": "2640aa5de0c9603da1c0d9c16b2fd3fa0a17b1472c3aa02559d3ef5e1defceb5", - "version": 2, - "locktime": 2959295, - "vin": [ - { - "txid": "d8e0d23dedc2c89e9de317e7a54bdc3d26f514918a9360aa04e271c4d8074c28", - "vout": 0, - "sequence": 4294967294, - "n": 0, - "scriptSig": { - "hex": "160014d6c589125f084df1e3286fcd55446b64dc7de130" - }, - "addresses": [ - "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" - ], - "value": "59.5115306" - } - ], - "vout": [ - { - "value": "11.511497", - "n": 0, - "scriptPubKey": { - "hex": "a91436d64490426cc347a50bdd3f8db2ef20d62949f587", - "addresses": [ - "36gy6VVstfso35mS89pBg1PiUcYY3Gesar" - ] - }, - "spent": true - }, - { - "value": "48", - "n": 1, - "scriptPubKey": { - "hex": "76a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac", - "addresses": [ - "FtCkFSrwrgiJzjQzGRZvjHzrmHp4HJeGYm" - ] - }, - "spent": true - } - ], - "blockhash": "0000000000000a79428395294255704ed877847d93c6d36108dc8184b71c1f0a", - "blockheight": 2959365, - "confirmations": 59348, - "time": 1581386699, - "blocktime": 1581386699, - "valueOut": "59.511497", - "valueIn": "59.5115306", - "fees": "0.0000336", - "hex": "02000000000101284c07d8c471e204aa60938a9114f5263ddc4ba5e717e39d9ec8c2ed3dd2e0d80000000017160014d6c589125f084df1e3286fcd55446b64dc7de130feffffff0284269d440000000017a91436d64490426cc347a50bdd3f8db2ef20d62949f58700301a1e010000001976a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac02473044022034f3f2ab2d021a27ba999aebb40016f921433c39149d6908fe1e96d914c5c96402203d5d12127f64a01429775090abb445b5af2ec90803372c92499a35e12e229adb0121033ca60a0478fee5583e52c3b85c4dacb81faa9c4a10ad8b4f574c1b050f814463bf272d00" - }, - { - "txid": "d8e0d23dedc2c89e9de317e7a54bdc3d26f514918a9360aa04e271c4d8074c28", - "version": 2, - "locktime": 2959360, - "vin": [ - { - "txid": "2ed852f7881270ec108c86482d609f818ee21ae07033796fb77cb8e52fa86ccd", - "vout": 0, - "sequence": 4294967294, - "n": 0, - "scriptSig": { - "hex": "47304402201fe0aff8dd5c35be49f824216adb51d0749878dc2d759d0dd6d4ed6612ca09cd02203ad7d2b2eaa52f341f325934cca2c2758ac4c4b7b8bc279e7748d48ab98b484901210246e7e23df8acf0a305b94009d9b60eca7230ce747493201a9574f7ccb03775e9" - }, - "addresses": [ - "Fg4WGddhNYayAF3mTPDNCFCEqrXydAd6Vu" - ], - "value": "297.5115752" - } - ], - "vout": [ - { - "value": "59.5115306", - "n": 0, - "scriptPubKey": { - "hex": "a914146081496e97dbb864af7df601184f8ec3624aa787", - "addresses": [ - "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" - ] - }, - "spent": true - }, - { - "value": "238", - "n": 1, - "scriptPubKey": { - "hex": "76a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac", - "addresses": [ - "FtCkFSrwrgiJzjQzGRZvjHzrmHp4HJeGYm" - ] - }, - "spent": true - } - ], - "blockhash": "0000000000000a79428395294255704ed877847d93c6d36108dc8184b71c1f0a", - "blockheight": 2959365, - "confirmations": 59348, - "time": 1581386699, - "blocktime": 1581386699, - "valueOut": "297.5115306", - "valueIn": "297.5115752", - "fees": "0.0000446", - "hex": "0200000001cd6ca82fe5b87cb76f793370e01ae28e819f602d48868c10ec701288f752d82e000000006a47304402201fe0aff8dd5c35be49f824216adb51d0749878dc2d759d0dd6d4ed6612ca09cd02203ad7d2b2eaa52f341f325934cca2c2758ac4c4b7b8bc279e7748d48ab98b484901210246e7e23df8acf0a305b94009d9b60eca7230ce747493201a9574f7ccb03775e9feffffff02a463b7620100000017a914146081496e97dbb864af7df601184f8ec3624aa787002e978a050000001976a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac00282d00" - } - ] - } + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 2, + "address": "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj", + "balance": "0", + "totalReceived": "5951153060", + "totalSent": "5951153060", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 2, + "transactions": [ + { + "txid": "2640aa5de0c9603da1c0d9c16b2fd3fa0a17b1472c3aa02559d3ef5e1defceb5", + "version": 2, + "lockTime": 2959295, + "vin": [ + { + "txid": "d8e0d23dedc2c89e9de317e7a54bdc3d26f514918a9360aa04e271c4d8074c28", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" + ], + "isAddress": true, + "value": "5951153060", + "hex": "160014d6c589125f084df1e3286fcd55446b64dc7de130" + } + ], + "vout": [ + { + "value": "1151149700", + "n": 0, + "spent": true, + "hex": "a91436d64490426cc347a50bdd3f8db2ef20d62949f587", + "addresses": [ + "36gy6VVstfso35mS89pBg1PiUcYY3Gesar" + ], + "isAddress": true + }, + { + "value": "4800000000", + "n": 1, + "spent": true, + "hex": "76a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac", + "addresses": [ + "FtCkFSrwrgiJzjQzGRZvjHzrmHp4HJeGYm" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000a79428395294255704ed877847d93c6d36108dc8184b71c1f0a", + "blockHeight": 2959365, + "confirmations": 100119, + "blockTime": 1581386699, + "value": "5951149700", + "valueIn": "5951153060", + "fees": "3360", + "hex": "02000000000101284c07d8c471e204aa60938a9114f5263ddc4ba5e717e39d9ec8c2ed3dd2e0d80000000017160014d6c589125f084df1e3286fcd55446b64dc7de130feffffff0284269d440000000017a91436d64490426cc347a50bdd3f8db2ef20d62949f58700301a1e010000001976a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac02473044022034f3f2ab2d021a27ba999aebb40016f921433c39149d6908fe1e96d914c5c96402203d5d12127f64a01429775090abb445b5af2ec90803372c92499a35e12e229adb0121033ca60a0478fee5583e52c3b85c4dacb81faa9c4a10ad8b4f574c1b050f814463bf272d00" + }, + { + "txid": "d8e0d23dedc2c89e9de317e7a54bdc3d26f514918a9360aa04e271c4d8074c28", + "version": 2, + "lockTime": 2959360, + "vin": [ + { + "txid": "2ed852f7881270ec108c86482d609f818ee21ae07033796fb77cb8e52fa86ccd", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "Fg4WGddhNYayAF3mTPDNCFCEqrXydAd6Vu" + ], + "isAddress": true, + "value": "29751157520", + "hex": "47304402201fe0aff8dd5c35be49f824216adb51d0749878dc2d759d0dd6d4ed6612ca09cd02203ad7d2b2eaa52f341f325934cca2c2758ac4c4b7b8bc279e7748d48ab98b484901210246e7e23df8acf0a305b94009d9b60eca7230ce747493201a9574f7ccb03775e9" + } + ], + "vout": [ + { + "value": "5951153060", + "n": 0, + "spent": true, + "hex": "a914146081496e97dbb864af7df601184f8ec3624aa787", + "addresses": [ + "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" + ], + "isAddress": true + }, + { + "value": "23800000000", + "n": 1, + "spent": true, + "hex": "76a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac", + "addresses": [ + "FtCkFSrwrgiJzjQzGRZvjHzrmHp4HJeGYm" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000a79428395294255704ed877847d93c6d36108dc8184b71c1f0a", + "blockHeight": 2959365, + "confirmations": 100119, + "blockTime": 1581386699, + "value": "29751153060", + "valueIn": "29751157520", + "fees": "4460", + "hex": "0200000001cd6ca82fe5b87cb76f793370e01ae28e819f602d48868c10ec701288f752d82e000000006a47304402201fe0aff8dd5c35be49f824216adb51d0749878dc2d759d0dd6d4ed6612ca09cd02203ad7d2b2eaa52f341f325934cca2c2758ac4c4b7b8bc279e7748d48ab98b484901210246e7e23df8acf0a305b94009d9b60eca7230ce747493201a9574f7ccb03775e9feffffff02a463b7620100000017a914146081496e97dbb864af7df601184f8ec3624aa787002e978a050000001976a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac00282d00" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/litecoin-api-address.js b/mock/ext-api-dyson/get/litecoin-api-address.js index 03379a122..5b2fb0734 100644 --- a/mock/ext-api-dyson/get/litecoin-api-address.js +++ b/mock/ext-api-dyson/get/litecoin-api-address.js @@ -1,130 +1,119 @@ /// Mock for external Litecoin API /// See: -/// curl "http://{ltc rpc}/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" -/// curl "http://localhost:3000/litecoin-api/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" +/// curl "http://{ltc rpc}/api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" +/// curl "http://localhost:3000/litecoin-api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" /// curl "http://localhost:8420/v1/litecoin/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" module.exports = { - path: '/litecoin-api/address/:address?', + path: '/litecoin-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 'ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept': return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "addrStr": "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept", - "balance": "0.01688078", - "totalReceived": "0.25679292", - "totalSent": "0.23991214", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 19, - "txs": [ - { - "txid": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1", - "version": 1, - "vin": [ - { - "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", - "vout": 1, - "n": 0, - "scriptSig": {}, - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "value": "0.0078853" - } - ], - "vout": [ - { - "value": "0.001", - "n": 0, - "scriptPubKey": { - "hex": "0014ccf05f3bc453f7f66fb48b124bd79690bc309e22", - "addresses": [ - "ltc1qenc97w7y20mlvma53vfyh4ukjz7rp83zf892wx" - ] - }, - "spent": false - }, - { - "value": "0.00688078", - "n": 1, - "scriptPubKey": { - "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ] - }, - "spent": false - } - ], - "blockhash": "ae8df4fb9cbbd07375eef217dd25e8b918a1b2746907c23cf4f2e15cd18fccdd", - "blockheight": 1804076, - "confirmations": 7531, - "time": 1583910871, - "blocktime": 1583910871, - "valueOut": "0.00788078", - "valueIn": "0.0078853", - "fees": "0.00000452", - "hex": "0100000000010167f89bc6125388f252bd770e142e61b9ab23dfb18762ba210f6f162bed92406701000000000000000002a086010000000000160014ccf05f3bc453f7f66fb48b124bd79690bc309e22ce7f0a00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100a40df50e2b419a35001f40d508e911f36d01497ebe5225dc93c81f53a30452fb022034c086517326be293019c2cbf215d6b9a53aa0ab4a0c2b890a9f1b05e8052aac012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" - }, - { - "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", - "version": 1, - "vin": [ - { - "txid": "f8ddc3eca55aa4bffd27b030fc3b35ceb8d503b31a03dafd32df56eec552fe99", - "vout": 1, - "sequence": 4294967290, - "n": 0, - "scriptSig": {}, - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "value": "0.01788982" - } - ], - "vout": [ - { - "value": "0.01", - "n": 0, - "scriptPubKey": { - "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ] - }, - "spent": false - }, - { - "value": "0.0078853", - "n": 1, - "scriptPubKey": { - "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ] - }, - "spent": true - } - ], - "blockhash": "dd92763dcb8477d8f012e5ec0598ebf3c135a15780d7491754fff40d3d24dd9b", - "blockheight": 1803562, - "confirmations": 8045, - "time": 1583831802, - "blocktime": 1583831802, - "valueOut": "0.0178853", - "valueIn": "0.01788982", - "fees": "0.00000452", - "hex": "0100000000010199fe52c5ee56df32fdda031ab303d5b8ce353bfc30b027fdbfa45aa5ecc3ddf80100000000faffffff0240420f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c532080c00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100bbde918ff538468c440424323bbe8ba78eef14d9dde357c8e6496905d540098c02205700d984884edff918f827289898c16ec9ad30344a637ea85dc55f7f836143bd012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" - } - ] - } + { + "page": 1, + "totalPages": 10, + "itemsOnPage": 2, + "address": "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept", + "balance": "1688078", + "totalReceived": "25679292", + "totalSent": "23991214", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 19, + "transactions": [ + { + "txid": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1", + "version": 1, + "vin": [ + { + "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", + "vout": 1, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "788530" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "0014ccf05f3bc453f7f66fb48b124bd79690bc309e22", + "addresses": [ + "ltc1qenc97w7y20mlvma53vfyh4ukjz7rp83zf892wx" + ], + "isAddress": true + }, + { + "value": "688078", + "n": 1, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "ae8df4fb9cbbd07375eef217dd25e8b918a1b2746907c23cf4f2e15cd18fccdd", + "blockHeight": 1804076, + "confirmations": 25056, + "blockTime": 1583910871, + "value": "788078", + "valueIn": "788530", + "fees": "452", + "hex": "0100000000010167f89bc6125388f252bd770e142e61b9ab23dfb18762ba210f6f162bed92406701000000000000000002a086010000000000160014ccf05f3bc453f7f66fb48b124bd79690bc309e22ce7f0a00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100a40df50e2b419a35001f40d508e911f36d01497ebe5225dc93c81f53a30452fb022034c086517326be293019c2cbf215d6b9a53aa0ab4a0c2b890a9f1b05e8052aac012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", + "version": 1, + "vin": [ + { + "txid": "f8ddc3eca55aa4bffd27b030fc3b35ceb8d503b31a03dafd32df56eec552fe99", + "vout": 1, + "sequence": 4294967290, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "1788982" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + }, + { + "value": "788530", + "n": 1, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "dd92763dcb8477d8f012e5ec0598ebf3c135a15780d7491754fff40d3d24dd9b", + "blockHeight": 1803562, + "confirmations": 25570, + "blockTime": 1583831802, + "value": "1788530", + "valueIn": "1788982", + "fees": "452", + "hex": "0100000000010199fe52c5ee56df32fdda031ab303d5b8ce353bfc30b027fdbfa45aa5ecc3ddf80100000000faffffff0240420f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c532080c00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100bbde918ff538468c440424323bbe8ba78eef14d9dde357c8e6496905d540098c02205700d984884edff918f827289898c16ec9ad30344a637ea85dc55f7f836143bd012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/qtum-api-address.js b/mock/ext-api-dyson/get/qtum-api-address.js index 77eaeab2c..80ddb9c15 100644 --- a/mock/ext-api-dyson/get/qtum-api-address.js +++ b/mock/ext-api-dyson/get/qtum-api-address.js @@ -1,176 +1,158 @@ /// Mock for external Qtum API /// See: -/// curl "http://{qtum rpc}/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" -/// curl "http://localhost:3000/qtum-api/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" +/// curl "http://{qtum rpc}/api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" +/// curl "http://localhost:3000/qtum-api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" /// curl "http://localhost:8420/v1/qtum/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" module.exports = { - path: '/qtum-api/address/:address?', + path: '/qtum-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 'QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ': return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "addrStr": "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", - "balance": "2.3535761", - "totalReceived": "433.3535761", - "totalSent": "431", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 5, - "txs": [ - { - "txid": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67", - "version": 1, - "vin": [ - { - "txid": "782e18a7b1bf612972e773fd6ccdcbe0c4514c661c31a7942f5dcd4807c5ab68", - "vout": 0, - "sequence": 4294967293, - "n": 0, - "scriptSig": { - "hex": "483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1e" - }, - "addresses": [ - "QWLQSMPF5WKAqhXxePJvjUJNjxDHrPCbjB" - ], - "value": "0.001" - }, - { - "txid": "80b7c6bcba625ad4abb69f7e92521a782681e984982408d40ad35a24b3f78297", - "vout": 0, - "sequence": 4294967294, - "n": 1, - "scriptSig": { - "hex": "48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5b" - }, - "addresses": [ - "QgqVXuCCN1m4Hfb9HCkrzbgUSkoodKsrVY" - ], - "value": "0.001" - }, - { - "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", - "vout": 0, - "sequence": 4294967292, - "n": 2, - "scriptSig": { - "hex": "473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbc" - }, - "addresses": [ - "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" - ], - "value": "0.1" - }, - { - "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", - "vout": 1, - "sequence": 4294967291, - "n": 3, - "scriptSig": { - "hex": "483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3" - }, - "addresses": [ - "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" - ], - "value": "2.2549462" - } - ], - "vout": [ - { - "value": "2.3535761", - "n": 0, - "scriptPubKey": { - "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", - "addresses": [ - "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" - ] - }, - "spent": false - } - ], - "blockhash": "6e71fa96ca29a6e4cbd10defaa4fc69ff09adec45fc666d82afade3f75206cc1", - "blockheight": 563426, - "confirmations": 11011, - "time": 1583720608, - "blocktime": 1583720608, - "valueOut": "2.3535761", - "valueIn": "2.3569462", - "fees": "0.0033701", - "hex": "010000000468abc50748cd5d2f94a7311c664c51c4e0cbcd6cfd73e7722961bfb1a7182e78000000006b483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1efdffffff9782f7b3245ad30ad408249884e98126781a52927e9fb6abd45a62babcc6b780000000006b48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5bfeffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c000000006a473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbcfcffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c010000006b483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3fbffffff01aa45070e000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac00000000" - }, - { - "txid": "ef335bef783551cb054acd220555f1588cc4b03c0f47cc0839220c81d3ceb88d", - "version": 1, - "vin": [ - { - "txid": "506d07570d75914d5bd319d591374fb9cd1633f5c8b3cc800387e104298e8a62", - "vout": 1, - "sequence": 4294967294, - "n": 0, - "scriptSig": { - "hex": "4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081e" - }, - "addresses": [ - "QfLtauKWxzF6pDf2ceXJe5oqizNHVMBneH" - ], - "value": "1.98984808" - }, - { - "txid": "e22c3e2ea4d285b71a73c41cdbb51f7c75d80b6f473e7f4aade6df5bf8771942", - "vout": 0, - "sequence": 4294967292, - "n": 1, - "scriptSig": { - "hex": "483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764" - }, - "addresses": [ - "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" - ], - "value": "430" - } - ], - "vout": [ - { - "value": "430", - "n": 0, - "scriptPubKey": { - "hex": "76a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac", - "addresses": [ - "QURZqPoBfuXXoHDkCHCvhGJa1DP2Ahj1KX" - ] - }, - "spent": true - }, - { - "value": "1.98831468", - "n": 1, - "scriptPubKey": { - "hex": "76a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac", - "addresses": [ - "QdfcTR3TQHjGHcKLiHmiPLRfVPFRWazJPg" - ] - }, - "spent": true - } - ], - "blockhash": "918141389623f4f880b1ba279bb70ee91de6a005e1a9d523d21a66e8c55f0502", - "blockheight": 393505, - "confirmations": 180932, - "time": 1560879520, - "blocktime": 1560879520, - "valueOut": "431.98831468", - "valueIn": "431.98984808", - "fees": "0.0015334", - "hex": "0100000002628a8e2904e1870380ccb3c8f53316cdb94f3791d519d35b4d91750d57076d50010000006b4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081efeffffff421977f85bdfe6ad4a7f3e476f0bd8757c1fb5db1cc4731ab785d2a42e3e2ce2000000006b483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764fcffffff0200eeff020a0000001976a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac6cedd90b000000001976a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac00000000" - } - ] - } + { + "page": 1, + "totalPages": 3, + "itemsOnPage": 2, + "address": "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", + "balance": "235357610", + "totalReceived": "43335357610", + "totalSent": "43100000000", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 5, + "transactions": [ + { + "txid": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67", + "version": 1, + "vin": [ + { + "txid": "782e18a7b1bf612972e773fd6ccdcbe0c4514c661c31a7942f5dcd4807c5ab68", + "sequence": 4294967293, + "n": 0, + "addresses": [ + "QWLQSMPF5WKAqhXxePJvjUJNjxDHrPCbjB" + ], + "isAddress": true, + "value": "100000", + "hex": "483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1e" + }, + { + "txid": "80b7c6bcba625ad4abb69f7e92521a782681e984982408d40ad35a24b3f78297", + "sequence": 4294967294, + "n": 1, + "addresses": [ + "QgqVXuCCN1m4Hfb9HCkrzbgUSkoodKsrVY" + ], + "isAddress": true, + "value": "100000", + "hex": "48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5b" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "sequence": 4294967292, + "n": 2, + "addresses": [ + "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" + ], + "isAddress": true, + "value": "10000000", + "hex": "473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbc" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "vout": 1, + "sequence": 4294967291, + "n": 3, + "addresses": [ + "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" + ], + "isAddress": true, + "value": "225494620", + "hex": "483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3" + } + ], + "vout": [ + { + "value": "235357610", + "n": 0, + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true + } + ], + "blockHash": "6e71fa96ca29a6e4cbd10defaa4fc69ff09adec45fc666d82afade3f75206cc1", + "blockHeight": 563426, + "confirmations": 31109, + "blockTime": 1583720608, + "value": "235357610", + "valueIn": "235694620", + "fees": "337010", + "hex": "010000000468abc50748cd5d2f94a7311c664c51c4e0cbcd6cfd73e7722961bfb1a7182e78000000006b483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1efdffffff9782f7b3245ad30ad408249884e98126781a52927e9fb6abd45a62babcc6b780000000006b48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5bfeffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c000000006a473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbcfcffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c010000006b483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3fbffffff01aa45070e000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac00000000" + }, + { + "txid": "ef335bef783551cb054acd220555f1588cc4b03c0f47cc0839220c81d3ceb88d", + "version": 1, + "vin": [ + { + "txid": "506d07570d75914d5bd319d591374fb9cd1633f5c8b3cc800387e104298e8a62", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QfLtauKWxzF6pDf2ceXJe5oqizNHVMBneH" + ], + "isAddress": true, + "value": "198984808", + "hex": "4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081e" + }, + { + "txid": "e22c3e2ea4d285b71a73c41cdbb51f7c75d80b6f473e7f4aade6df5bf8771942", + "sequence": 4294967292, + "n": 1, + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true, + "value": "43000000000", + "hex": "483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764" + } + ], + "vout": [ + { + "value": "43000000000", + "n": 0, + "spent": true, + "hex": "76a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac", + "addresses": [ + "QURZqPoBfuXXoHDkCHCvhGJa1DP2Ahj1KX" + ], + "isAddress": true + }, + { + "value": "198831468", + "n": 1, + "spent": true, + "hex": "76a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac", + "addresses": [ + "QdfcTR3TQHjGHcKLiHmiPLRfVPFRWazJPg" + ], + "isAddress": true + } + ], + "blockHash": "918141389623f4f880b1ba279bb70ee91de6a005e1a9d523d21a66e8c55f0502", + "blockHeight": 393505, + "confirmations": 201030, + "blockTime": 1560879520, + "value": "43198831468", + "valueIn": "43198984808", + "fees": "153340", + "hex": "0100000002628a8e2904e1870380ccb3c8f53316cdb94f3791d519d35b4d91750d57076d50010000006b4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081efeffffff421977f85bdfe6ad4a7f3e476f0bd8757c1fb5db1cc4731ab785d2a42e3e2ce2000000006b483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764fcffffff0200eeff020a0000001976a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac6cedd90b000000001976a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac00000000" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/ravencoin-api-address.js b/mock/ext-api-dyson/get/ravencoin-api-address.js index ecd6d3ad5..cff216ec1 100644 --- a/mock/ext-api-dyson/get/ravencoin-api-address.js +++ b/mock/ext-api-dyson/get/ravencoin-api-address.js @@ -1,137 +1,121 @@ /// Mock for external Ravencoin API /// See: -/// curl "http://{Ravencoin rpc}/address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS?details=txs" -/// curl "http://localhost:3000/ravencoin-api/address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS?details=txs" -/// curl "http://localhost:8420/v1/ravencoin/address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" +/// curl "http://{Ravencoin rpc}/api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs" +/// curl "http://localhost:3000/ravencoin-api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs" +/// curl "http://localhost:8420/v1/ravencoin/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo" module.exports = { - path: '/ravencoin-api/address/:address?', + path: '/ravencoin-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { - case 'RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS': + case 'RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo': return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "addrStr": "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS", - "balance": "0", - "totalReceived": "10.48", - "totalSent": "10.48", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 5, - "txs": [ - { - "txid": "fc6c9e9c6cd0253f05e43a12d64154a689115f0103dc0b64957a8cb92b67f306", - "version": 1, - "vin": [ - { - "txid": "3717b528eb4925461d9de5a596d2eefe175985740b4fda153255e10135f236a6", - "vout": 1, - "sequence": 4294967293, - "n": 0, - "scriptSig": { - "hex": "483045022100b085c0f7d09937eed588f4c18e8ea600382926bcd0467a90436c7d3446ae2aa202206261e0b98c5d4852b17e32bcc04c2d6bc01dad327be0c16776ce9b6f57a44142012102138724e702d25b0fdce73372ccea9734f9349442d5a9681a5f4d831036cd9429" - }, - "addresses": [ - "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" - ], - "value": "0.48" - }, - { - "txid": "128793fa1635c630a3463225515f9aabfa6160ae32028d5ae6f09b04802abebe", - "vout": 0, - "sequence": 4294967294, - "n": 1, - "scriptSig": { - "hex": "47304402202f7f64346ddf51e1304e46407e1a285625b1c8e743b2a8ac919520a924be6ca102206a452426f9a1e105b0ba422b321cf358fe8d357cf985f43caf581ec7275f03ce0121030b22ea9d87e08432c18606849e801462189a45aaa9e158306cd5f26bcea3c61e" - }, - "addresses": [ - "RVtWJKBbG7JN3GQBkgwz4n4GYVPeViNer7" - ], - "value": "5.988166" - } - ], - "vout": [ - { - "value": "6.4679603", - "n": 0, - "scriptPubKey": { - "hex": "76a9148272c538003476df668581ad1336eecc774f274c88ac", - "addresses": [ - "RMAwQqgkYur4un2JbE6vPnZWeyzunXkuWo" - ] - }, - "spent": true - } - ], - "blockhash": "0000000000005cbc77e1a4b921e5de4fc5388fb661065e825877911d2364472a", - "blockheight": 753909, - "confirmations": 405243, - "time": 1560658623, - "blocktime": 1560658623, - "valueOut": "6.4679603", - "valueIn": "6.468166", - "fees": "0.0002057", - "hex": "0100000002a636f23501e1553215da4f0b74855917feeed296a5e59d1d462549eb28b51737010000006b483045022100b085c0f7d09937eed588f4c18e8ea600382926bcd0467a90436c7d3446ae2aa202206261e0b98c5d4852b17e32bcc04c2d6bc01dad327be0c16776ce9b6f57a44142012102138724e702d25b0fdce73372ccea9734f9349442d5a9681a5f4d831036cd9429fdffffffbebe2a80049bf0e65a8d0232ae6061faab9a5f51253246a330c63516fa938712000000006a47304402202f7f64346ddf51e1304e46407e1a285625b1c8e743b2a8ac919520a924be6ca102206a452426f9a1e105b0ba422b321cf358fe8d357cf985f43caf581ec7275f03ce0121030b22ea9d87e08432c18606849e801462189a45aaa9e158306cd5f26bcea3c61efeffffff01fe528d26000000001976a9148272c538003476df668581ad1336eecc774f274c88ac00000000" - }, - { - "txid": "3717b528eb4925461d9de5a596d2eefe175985740b4fda153255e10135f236a6", - "version": 1, - "vin": [ - { - "txid": "0c7e82b44eec71d634c013e2db3cb4fa26f87fbc90eb8734da93807d23605544", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": { - "hex": "483045022100d790bdaa3c44eb5e3a422365ca5fc009c4512625222e3378f2f16e7e6ef1732a0220688c1bb995b7ff2f12729e101d7c24b6314430317e7717911fdc35c0d84f2f0d012102138724e702d25b0fdce73372ccea9734f9349442d5a9681a5f4d831036cd9429" - }, - "addresses": [ - "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" - ], - "value": "1" - } - ], - "vout": [ - { - "value": "0.5", - "n": 0, - "scriptPubKey": { - "hex": "76a9149451f4546e09fc2e49ef9b5303924712ec2b038e88ac", - "addresses": [ - "RNoSGCX8SPFscj8epDaJjqEpuZa2B5in88" - ] - }, - "spent": false - }, - { - "value": "0.48", - "n": 1, - "scriptPubKey": { - "hex": "76a9145d6e33f3a108bbcc586cbbe90994d5baf5a9cce488ac", - "addresses": [ - "RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS" - ] - }, - "spent": true - } - ], - "blockhash": "0000000000004b942df6b9736c0a4b1a320cadfe46ca10351e43b35cccee7be1", - "blockheight": 734142, - "confirmations": 425010, - "time": 1559464388, - "blocktime": 1559464388, - "valueOut": "0.98", - "valueIn": "1", - "fees": "0.02", - "hex": "0100000001445560237d8093da3487eb90bc7ff826fab43cdbe213c034d671ec4eb4827e0c000000006b483045022100d790bdaa3c44eb5e3a422365ca5fc009c4512625222e3378f2f16e7e6ef1732a0220688c1bb995b7ff2f12729e101d7c24b6314430317e7717911fdc35c0d84f2f0d012102138724e702d25b0fdce73372ccea9734f9349442d5a9681a5f4d831036cd9429ffffffff0280f0fa02000000001976a9149451f4546e09fc2e49ef9b5303924712ec2b038e88ac006cdc02000000001976a9145d6e33f3a108bbcc586cbbe90994d5baf5a9cce488ac00000000" - } - ] - } + { + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo", + "balance": "8525568094", + "totalReceived": "8525568094", + "totalSent": "0", + "unconfirmedBalance": "-8525568094", + "unconfirmedTxs": 1, + "txs": 1, + "transactions": [ + { + "txid": "fc226aad6fc28e1204b747042e8c8b25f5d28424b9669bd162ba6a0149df2f71", + "version": 2, + "lockTime": 1201754, + "vin": [ + { + "txid": "1222cb57d31bfb439e94080266c33ebb0134cdb90999a9fad99455d09a15159b", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo" + ], + "isAddress": true, + "value": "8525568094", + "hex": "483045022100dc56832c815e7294dd51c7bb1ba342af80f5d25c3bc44c9689a55ccd94d18d01022063d3420930736fb1c1ab9a851ec0d1ff01dc906c66685b35972e3ab26b2d5d040121032dd4ba9d193e1912a6b48bd5642cb3579415ebabfc61e9fec9690fcd466dea15" + } + ], + "vout": [ + { + "value": "78460623", + "n": 0, + "hex": "76a9141657456724a83ca9e4c4cc0b65c98b6ffdba5bae88ac", + "addresses": [ + "RBKKVSR79YjBSGBE5pymUCaa871qogE5aY" + ], + "isAddress": true + }, + { + "value": "8446853390", + "n": 1, + "hex": "76a9142e664ae2c04d6292d50bcd65b644553eea7d7f1388ac", + "addresses": [ + "RDWXhkQyUkgmumGbzdR6JetLChVzUbStRq" + ], + "isAddress": true + } + ], + "blockHeight": -1, + "confirmations": 0, + "blockTime": 1587702074, + "value": "8525314013", + "valueIn": "8525568094", + "fees": "254081", + "hex": "02000000019b15159ad05594d9faa99909b9cd3401bb3ec3660208949e43fb1bd357cb2212000000006b483045022100dc56832c815e7294dd51c7bb1ba342af80f5d25c3bc44c9689a55ccd94d18d01022063d3420930736fb1c1ab9a851ec0d1ff01dc906c66685b35972e3ab26b2d5d040121032dd4ba9d193e1912a6b48bd5642cb3579415ebabfc61e9fec9690fcd466dea15feffffff02cf36ad04000000001976a9141657456724a83ca9e4c4cc0b65c98b6ffdba5bae88ac0ec178f7010000001976a9142e664ae2c04d6292d50bcd65b644553eea7d7f1388ac5a561200" + }, + { + "txid": "1222cb57d31bfb439e94080266c33ebb0134cdb90999a9fad99455d09a15159b", + "version": 2, + "lockTime": 1201750, + "vin": [ + { + "txid": "003d748c2c3541535093e840b4c5e54b966915eb522bac06028bc8d1376e1e63", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "R9kyoRBmiF89o5ACFXF4EY7GawGjURP1Z5" + ], + "isAddress": true, + "value": "8530842427", + "hex": "47304402207ea927cfb1c7d8e14b067aa5b892cfde8b7b96b8bd95866b906c13e168581fd20220423bee1c4e25f66cc5ac27d94a33540307edb2a9a8874e800a1e1f875194dabf012103ded5613a24b22a8dc0c416f3ac4b436372a5b581b42e2d45f00fbd042cb066f1" + } + ], + "vout": [ + { + "value": "8525568094", + "n": 0, + "hex": "76a9145208b754b23169797a19e0ffaa9041ab5e29b9ef88ac", + "addresses": [ + "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo" + ], + "isAddress": true + }, + { + "value": "5020252", + "n": 1, + "spent": true, + "hex": "76a914bb7590eef377d63adcda0d080073035ad9a86bfc88ac", + "addresses": [ + "RSNPH2YPN69PNRj6BYq4V3orCyC7nahG9R" + ], + "isAddress": true + } + ], + "blockHash": "00000000000003efc9fb9dd4d5deb4e6ca393266191771d5d2e2426a191e69b3", + "blockHeight": 1201752, + "confirmations": 3, + "blockTime": 1587701825, + "value": "8530588346", + "valueIn": "8530842427", + "fees": "254081", + "hex": "0200000001631e6e37d1c88b0206ac2b52eb1569964be5c5b440e893505341352c8c743d00000000006a47304402207ea927cfb1c7d8e14b067aa5b892cfde8b7b96b8bd95866b906c13e168581fd20220423bee1c4e25f66cc5ac27d94a33540307edb2a9a8874e800a1e1f875194dabf012103ded5613a24b22a8dc0c416f3ac4b436372a5b581b42e2d45f00fbd042cb066f1feffffff025ed829fc010000001976a9145208b754b23169797a19e0ffaa9041ab5e29b9ef88ac5c9a4c00000000001976a914bb7590eef377d63adcda0d080073035ad9a86bfc88ac56561200" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/viacoin-api-address.js b/mock/ext-api-dyson/get/viacoin-api-address.js index beb83f0a5..2c0d736bb 100644 --- a/mock/ext-api-dyson/get/viacoin-api-address.js +++ b/mock/ext-api-dyson/get/viacoin-api-address.js @@ -1,105 +1,87 @@ /// Mock for external Viacoin API /// See: -/// curl "http://{Viacoin rpc}/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" -/// curl "http://localhost:3000/viacoin-api/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" +/// curl "http://{Viacoin rpc}/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" +/// curl "http://localhost:3000/viacoin-api/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" /// curl "http://localhost:8420/v1/viacoin/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" module.exports = { - path: '/viacoin-api/address/:address?', + path: '/viacoin-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 'VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A': return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 2, - "addrStr": "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A", - "balance": "737.5107688", - "totalReceived": "183234.99094131", - "totalSent": "182497.48017251", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 1523480, - "txs": [ - { - "txid": "dadbe1f13dc5ecd1cfb0d8ae139a4e55493eb9ab2c937cb78b67a5d9c1ded7e8", - "version": 1, - "vin": [ - { - "txid": "", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": {}, - "addresses": null, - "value": "" - } - ], - "vout": [ - { - "value": "0.00976562", - "n": 0, - "scriptPubKey": { - "hex": "76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac", - "addresses": [ - "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" - ] - }, - "spent": false - } - ], - "blockhash": "496ff7e4cf450449ade88fc8bf214fd39a6d4203da8f8256492c589bf28de1a7", - "blockheight": 7423549, - "confirmations": 6, - "time": 1584742971, - "blocktime": 1584742971, - "valueOut": "0.00976562", - "valueIn": "0", - "fees": "0", - "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff09033d4671045e75423bffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000" - }, - { - "txid": "be2a7b573af425f8f309561b3db4631f905626057da94399d7e44f97595c7dbe", - "version": 1, - "vin": [ - { - "txid": "", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": {}, - "addresses": null, - "value": "" - } - ], - "vout": [ - { - "value": "0.00976562", - "n": 0, - "scriptPubKey": { - "hex": "76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac", - "addresses": [ - "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" - ] - }, - "spent": false - } - ], - "blockhash": "36c57ff80410c9c32790b75e566fdf855c6302a6a09f6dc75b362f9c6b3c884c", - "blockheight": 7423545, - "confirmations": 10, - "time": 1584742872, - "blocktime": 1584742872, - "valueOut": "0.00976562", - "valueIn": "0", - "fees": "0", - "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0903394671045e7541d8ffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000" - } - ] - } + { + "page": 1, + "totalPages": 785695, + "itemsOnPage": 2, + "address": "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A", + "balance": "120312392935", + "totalReceived": "18370512600313", + "totalSent": "18250200207378", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 1571390, + "transactions": [ + { + "txid": "1b311427cd4749cbebd5c1fc70896b9e92a58d6935ba75bb40ed4a9e22e4a6cb", + "version": 1, + "vin": [ + { + "sequence": 4294967295, + "n": 0, + "coinbase": "03a02873045ea2915d" + } + ], + "vout": [ + { + "value": "976562", + "n": 0, + "hex": "76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac", + "addresses": [ + "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" + ] + } + ], + "blockHash": "c590a4a7357d308917c6d3d8a8bd75b27968db346b965f2cd6e2be639e792f24", + "blockHeight": 7547040, + "confirmations": 3, + "blockTime": 1587712349, + "value": "976562", + "valueIn": "0", + "fees": "0", + "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0903a02873045ea2915dffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000" + }, + { + "txid": "e7393042e4b7755ba320a80ee734b0f0bd496a46fa3c9e9982c1a8176b6815b4", + "version": 1, + "vin": [ + { + "sequence": 4294967295, + "n": 0, + "coinbase": "039e2873045ea29101" + } + ], + "vout": [ + { + "value": "976562", + "n": 0, + "hex": "76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac", + "addresses": [ + "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" + ] + } + ], + "blockHash": "87f245b6882d8d1a0a2122c5dd5e00a8a6ea0e811d8bc53cde5ba00a1a7b63ce", + "blockHeight": 7547038, + "confirmations": 5, + "blockTime": 1587712257, + "value": "976562", + "valueIn": "0", + "fees": "0", + "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff09039e2873045ea29101ffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/zcash-api-address.js b/mock/ext-api-dyson/get/zcash-api-address.js index 463c12a15..1c9109039 100644 --- a/mock/ext-api-dyson/get/zcash-api-address.js +++ b/mock/ext-api-dyson/get/zcash-api-address.js @@ -1,171 +1,147 @@ /// Mock for external Zcash API /// See: -/// curl "http://{Zcash rpc}/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" -/// curl "http://localhost:3000/zcash-api/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" +/// curl "http://{Zcash rpc}/api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" +/// curl "http://localhost:3000/zcash-api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" /// curl "http://localhost:8420/v1/zcash/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" module.exports = { - path: '/zcash-api/address/:address?', + path: '/zcash-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 't1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX': return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 2, - "addrStr": "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX", - "balance": "0.12344656", - "totalReceived": "1096.63825939", - "totalSent": "1096.51481283", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 1636, - "txs": [ - { - "txid": "d504755667e0fb61543e16d09aff5f84733f500190a07acb4a6784b4dc4c99e7", - "version": 4, - "vin": [ - { - "txid": "", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": {}, - "addresses": null, - "value": "" - } - ], - "vout": [ - { - "value": "0", - "n": 0, - "scriptPubKey": { - "hex": "76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac", - "addresses": [ - "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" - ] - }, - "spent": false - }, - { - "value": "1.25", - "n": 1, - "scriptPubKey": { - "hex": "a914e445cfa944b6f2bdacefbda904a81d5fdd26d77f87", - "addresses": [ - "t3fNcdBUbycvbCtsD2n9q3LuxG7jVPvFB8L" - ] - }, - "spent": false - }, - { - "value": "0.0625", - "n": 2, - "scriptPubKey": { - "hex": "76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac", - "addresses": [ - "t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv" - ] - }, - "spent": false - }, - { - "value": "4.9375", - "n": 3, - "scriptPubKey": { - "hex": "76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac", - "addresses": [ - "t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2" - ] - }, - "spent": false - } - ], - "blockhash": "000000000259ba5a4b53e1ce8e6828fc780f8858283620aa27418ce80681c1b5", - "blockheight": 768336, - "confirmations": 7, - "time": 1584747959, - "blocktime": 1584747959, - "valueOut": "6.25", - "valueIn": "0", - "fees": "0", - "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff500350b90b0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914e445cfa944b6f2bdacefbda904a81d5fdd26d77f87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000" - }, - { - "txid": "95e12ff1a8ca7a19d5af92c6a480d1c1da4cf998dcba08329d151acb45d78bbb", - "version": 4, - "vin": [ - { - "txid": "", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": {}, - "addresses": null, - "value": "" - } - ], - "vout": [ - { - "value": "0", - "n": 0, - "scriptPubKey": { - "hex": "76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac", - "addresses": [ - "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" - ] - }, - "spent": false - }, - { - "value": "1.25", - "n": 1, - "scriptPubKey": { - "hex": "a914e445cfa944b6f2bdacefbda904a81d5fdd26d77f87", - "addresses": [ - "t3fNcdBUbycvbCtsD2n9q3LuxG7jVPvFB8L" - ] - }, - "spent": false - }, - { - "value": "0.0625", - "n": 2, - "scriptPubKey": { - "hex": "76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac", - "addresses": [ - "t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv" - ] - }, - "spent": false - }, - { - "value": "4.9375", - "n": 3, - "scriptPubKey": { - "hex": "76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac", - "addresses": [ - "t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2" - ] - }, - "spent": false - } - ], - "blockhash": "0000000000f747c6311d3658bad9bab649e21dd365075a1df8b98a88c3871458", - "blockheight": 768281, - "confirmations": 62, - "time": 1584744347, - "blocktime": 1584744347, - "valueOut": "6.25", - "valueIn": "0", - "fees": "0", - "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff500319b90b0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914e445cfa944b6f2bdacefbda904a81d5fdd26d77f87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000" - } - ] - } + { + "page": 1, + "totalPages": 917, + "itemsOnPage": 2, + "address": "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX", + "balance": "12344656", + "totalReceived": "109663825939", + "totalSent": "109651481283", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 1833, + "transactions": [ + { + "txid": "ca640e5215e141a4f9c235dd91e4b99fd1e0defdd5da27d78ec2cee02d3493dc", + "version": 4, + "vin": [ + { + "sequence": 4294967295, + "n": 0, + "isAddress": false, + "coinbase": "0323520c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b" + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "hex": "76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac", + "addresses": [ + "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" + ], + "isAddress": true + }, + { + "value": "125000000", + "n": 1, + "hex": "a914cdcd95aa6892db5fc849ac15804d2b9dd035a3b787", + "addresses": [ + "t3dKojUU2EMjs28nHV84TvkVEUDu1M1FaEx" + ], + "isAddress": true + }, + { + "value": "6250000", + "n": 2, + "hex": "76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac", + "addresses": [ + "t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv" + ], + "isAddress": true + }, + { + "value": "493750000", + "n": 3, + "hex": "76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac", + "addresses": [ + "t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2" + ], + "isAddress": true + } + ], + "blockHash": "000000000031b763658a48c735fa02d9e5181b12683cc66a93d79caf5f66e9b0", + "blockHeight": 807459, + "confirmations": 89, + "blockTime": 1587696399, + "value": "625000000", + "valueIn": "0", + "fees": "0", + "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff500323520c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914cdcd95aa6892db5fc849ac15804d2b9dd035a3b787105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000" + }, + { + "txid": "7bbf19b071907f23bd3d124d8f28a2aa8445a38d9f8a915487e9a36686c9094f", + "version": 4, + "vin": [ + { + "sequence": 4294967295, + "n": 0, + "isAddress": false, + "coinbase": "03a2510c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b" + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "hex": "76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac", + "addresses": [ + "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" + ], + "isAddress": true + }, + { + "value": "125000000", + "n": 1, + "hex": "a914cdcd95aa6892db5fc849ac15804d2b9dd035a3b787", + "addresses": [ + "t3dKojUU2EMjs28nHV84TvkVEUDu1M1FaEx" + ], + "isAddress": true + }, + { + "value": "6250000", + "n": 2, + "spent": true, + "hex": "76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac", + "addresses": [ + "t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv" + ], + "isAddress": true + }, + { + "value": "493750000", + "n": 3, + "spent": true, + "hex": "76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac", + "addresses": [ + "t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2" + ], + "isAddress": true + } + ], + "blockHash": "00000000030219218c61edcf72dcd6c3512bbf9d3e5ffc34b607625d476dc558", + "blockHeight": 807330, + "confirmations": 218, + "blockTime": 1587686790, + "value": "625000000", + "valueIn": "0", + "fees": "0", + "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff5003a2510c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914cdcd95aa6892db5fc849ac15804d2b9dd035a3b787105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/zcoin-api-address.js b/mock/ext-api-dyson/get/zcoin-api-address.js index b1c393f11..27af44520 100644 --- a/mock/ext-api-dyson/get/zcoin-api-address.js +++ b/mock/ext-api-dyson/get/zcoin-api-address.js @@ -1,277 +1,122 @@ /// Mock for external Zcoin API /// See: -/// curl "http://{Zcoin rpc}/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" -/// curl "http://localhost:3000/zcoin-api/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" +/// curl "http://{Zcoin rpc}/api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" +/// curl "http://localhost:3000/zcoin-api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" /// curl "http://localhost:8420/v1/zcoin/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" module.exports = { - path: '/zcoin-api/address/:address?', + path: '/zcoin-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 'a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn': return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "addrStr": "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn", - "balance": "0.6310911", - "totalReceived": "15.65104974", - "totalSent": "15.01995864", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 18, - "txs": [ - { - "txid": "11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45", - "version": 1, - "vin": [ - { - "txid": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", - "vout": 1, - "n": 0, - "scriptSig": { - "hex": "483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" - }, - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "value": "0.63028838" - } - ], - "vout": [ - { - "value": "0.001", - "n": 0, - "scriptPubKey": { - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ] - }, - "spent": false - }, - { - "value": "0.6292477", - "n": 1, - "scriptPubKey": { - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ] - }, - "spent": true, - "spentTxId": "50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd", - "spentHeight": 251156 - } - ], - "blockhash": "5ba0f8c0e58986d1eb5036e766e28ed541d0993cb717fc1aea46d714a89945e7", - "blockheight": 250864, - "confirmations": 1845, - "time": 1584571576, - "blocktime": 1584571576, - "valueOut": "0.6302477", - "valueIn": "0.63028838", - "fees": "0.00004068", - "hex": "0100000001ef273981817358e256ecb5e87a9826056893b8e2672e49a6a8c29b0fe343fb86010000006b483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b150000000002a0860100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ace227c003000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", - "version": 1, - "vin": [ - { - "txid": "5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e", - "vout": 1, - "sequence": 4294967294, - "n": 0, - "scriptSig": { - "hex": "483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" - }, - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "value": "0.64032906" - } - ], - "vout": [ - { - "value": "0.01", - "n": 0, - "scriptPubKey": { - "hex": "76a914cffef031eead7d332c245df1372dcf4980a0127c88ac", - "addresses": [ - "aKgF22yWfjBqekrbkhkFYqenzsw9zfRch8" - ] - }, - "spent": false - }, - { - "value": "0.63028838", - "n": 1, - "scriptPubKey": { - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ] - }, - "spent": true, - "spentTxId": "11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45", - "spentHeight": 250864 - } - ], - "blockhash": "fcfea4d17cde4cfc8d113d923e7e2978513e902448f1087fd448ae4162696f4f", - "blockheight": 244409, - "confirmations": 8300, - "time": 1582620606, - "blocktime": 1582620606, - "valueOut": "0.64028838", - "valueIn": "0.64032906", - "fees": "0.00004068", - "hex": "01000000011e60be361fdabd33a545444bd7c0a6571e6e1fa9d92e65676da700d0aeebf75c010000006b483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15feffffff0240420f00000000001976a914cffef031eead7d332c245df1372dcf4980a0127c88ac66bec103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "4178eb3a84a34a9b508dbb61abbe725de115de2daea619e1cfa68eadf001fe51", - "version": 1, - "vin": [ - { - "txid": "6de60b862ef752e24f1417c255f750e8e2e2b64ce4160eccbcdd82663a36daeb", - "vout": 0, - "n": 0, - "scriptSig": { - "hex": "483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b" - }, - "addresses": [ - "aDVvWiM5PTv3QrUbrWQW3hPVLiFTMmzAHr" - ], - "value": "0.001" - } - ], - "vout": [ - { - "value": "0.00096544", - "n": 0, - "scriptPubKey": { - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ] - }, - "spent": false - } - ], - "blockhash": "e3d64bc33182f0b74b6247c7b37a9f8ff3c6852fe1c08116d460d067919345d1", - "blockheight": 241112, - "confirmations": 11597, - "time": 1581616858, - "blocktime": 1581616858, - "valueOut": "0.00096544", - "valueIn": "0.001", - "fees": "0.00003456", - "hex": "0100000001ebda363a6682ddbccc0e16e44cb6e2e2e850f755c217144fe252f72e860be66d000000006b483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b000000000120790100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e", - "version": 1, - "vin": [ - { - "txid": "5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241", - "vout": 1, - "n": 0, - "scriptSig": { - "hex": "483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8" - }, - "addresses": [ - "aL96Xr2E1pMW3vcsZ5QV6BYLFE9jdCVBJL" - ], - "value": "3.64036974" - } - ], - "vout": [ - { - "value": "3", - "n": 0, - "scriptPubKey": { - "hex": "76a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac", - "addresses": [ - "aB3mWSqhFzszMJ3h8sxTedFYDhZCDBkeQT" - ] - }, - "spent": true, - "spentTxId": "736d2ed9a2398511cc98f30df178db721716c1996fd8ab67970a5ac41a795e72", - "spentIndex": 2, - "spentHeight": 239559 - }, - { - "value": "0.64032906", - "n": 1, - "scriptPubKey": { - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ] - }, - "spent": true, - "spentTxId": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", - "spentHeight": 244409 - } - ], - "blockhash": "07d7c24529ee402be1a94b6b5a70d000c6002f0fa7201c1f5ef4ef7dd87f0117", - "blockheight": 239551, - "confirmations": 13158, - "time": 1581138788, - "blocktime": 1581138788, - "valueOut": "3.64032906", - "valueIn": "3.64036974", - "fees": "0.00004068", - "hex": "010000000141320e1d67dca17a2d7107f1e3b378fbf443347afb21e16d130be718a8ce8254010000006b483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8000000000200a3e111000000001976a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac8a10d103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "c4f897a1d64e6c870184ff26a3ad8f5f4a94a6667f6d3486f21e52530d8ecea2", - "version": 1, - "vin": [ - { - "txid": "3054b05d5f9624264bf7bfbb140749472c58670cc935efa5aab4a96c6430ed19", - "vout": 0, - "sequence": 4294967294, - "n": 0, - "scriptSig": { - "hex": "473044022062705d4b0f266a25646c410e3a735b7665dafb85655bf4b9f3ce89ecde4306f20220702f5fd1f3d6e593c3e3e9a37adf6431b1920b55151872dc9c8f4dc166df1a8f0121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" - }, - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "value": "3.6504511" - } - ], - "vout": [ - { - "value": "3.65041042", - "n": 0, - "scriptPubKey": { - "hex": "76a914e5712d04a22c551a8261aea3f4a8d98ddb057f5988ac", - "addresses": [ - "aMde4RuTWiNzoZN53SWZ7i7tKNbhSwt57U" - ] - }, - "spent": true, - "spentTxId": "5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241", - "spentHeight": 238210 - } - ], - "blockhash": "1afa27baa3146c5ae36cb93612f928b794b306d4d8b552636fb3f35891a7adb8", - "blockheight": 238176, - "confirmations": 14533, - "time": 1580709451, - "blocktime": 1580709451, - "valueOut": "3.65041042", - "valueIn": "3.6504511", - "fees": "0.00004068", - "hex": "010000000119ed30646ca9b4aaa5ef35c90c67582c47490714bbbff74b2624965f5db05430000000006a473044022062705d4b0f266a25646c410e3a735b7665dafb85655bf4b9f3ce89ecde4306f20220702f5fd1f3d6e593c3e3e9a37adf6431b1920b55151872dc9c8f4dc166df1a8f0121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15feffffff019215c215000000001976a914e5712d04a22c551a8261aea3f4a8d98ddb057f5988ac00000000" - } - ] - } + { + "page": 1, + "totalPages": 9, + "itemsOnPage": 2, + "address": "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn", + "balance": "63109110", + "totalReceived": "1565104974", + "totalSent": "1501995864", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 18, + "transactions": [ + { + "txid": "f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609", + "version": 1, + "vin": [ + { + "txid": "cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564", + "vout": 1, + "n": 0, + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true, + "value": "51916634", + "hex": "483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" + } + ], + "vout": [ + { + "value": "13113178", + "n": 0, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + }, + { + "value": "38799388", + "n": 1, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + } + ], + "blockHash": "f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328", + "blockHeight": 251191, + "confirmations": 10102, + "blockTime": 1584663676, + "value": "51912566", + "valueIn": "51916634", + "fees": "4068", + "hex": "010000000164b574c298c44b23fc6f328494ff306444895262d7f670ebb2a5c48233ac33cd010000006b483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b1500000000025a17c800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac1c085002000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + }, + { + "txid": "cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564", + "version": 1, + "vin": [ + { + "txid": "50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd", + "vout": 1, + "n": 0, + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true, + "value": "61920702", + "hex": "483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + }, + { + "value": "51916634", + "n": 1, + "spent": true, + "spentTxId": "f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609", + "spentHeight": 251191, + "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", + "addresses": [ + "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" + ], + "isAddress": true + } + ], + "blockHash": "f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328", + "blockHeight": 251191, + "confirmations": 10102, + "blockTime": 1584663676, + "value": "61916634", + "valueIn": "61920702", + "fees": "4068", + "hex": "0100000001fd296277b76a406837115f9213f3ce6ebfdb8408447c1423281c034e387acb50010000006b483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15000000000280969800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac5a2f1803000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/mock/ext-api-dyson/get/zelcash-api-address.js b/mock/ext-api-dyson/get/zelcash-api-address.js index d46f5b8a2..ae21ca2f3 100644 --- a/mock/ext-api-dyson/get/zelcash-api-address.js +++ b/mock/ext-api-dyson/get/zelcash-api-address.js @@ -1,241 +1,135 @@ /// Mock for external Zelcash API /// See: -/// curl "http://{Zelcash rpc}/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs&pageSize=25" -/// curl "http://localhost:3000/zelcash-api/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs" +/// curl "http://{Zelcash rpc}/api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs&pageSize=25" +/// curl "http://localhost:3000/zelcash-api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs" /// curl "http://localhost:8420/v1/zelcash/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" module.exports = { - path: '/zelcash-api/address/:address?', + path: '/zelcash-api/v2/address/:address?', template: function(params, query, body) { - //console.log(params) - //console.log(query) switch (params.address) { case 't1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa': return JSON.parse(` - { - "page": 1, - "totalPages": 4175, - "itemsOnPage": 25, - "addrStr": "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa", - "balance": "6300.00809211", - "totalReceived": "10963952.85564162", - "totalSent": "10957652.84754951", - "unconfirmedBalance": "0", - "unconfirmedTxApperances": 0, - "txApperances": 104369, - "txs": [ - { - "txid": "ca8b3fa115c5eae0f056d9b629680c521f4d9d271abbe86d4c482c54117e15a1", - "version": 4, - "vin": [ - { - "txid": "", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": {}, - "addresses": null, - "value": "" - } - ], - "vout": [ - { - "value": "112.5001", - "n": 0, - "scriptPubKey": { - "hex": "76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac", - "addresses": [ - "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" - ] - }, - "spent": false - }, - { - "value": "5.625", - "n": 1, - "scriptPubKey": { - "hex": "76a91402664e0d583d97b55b71320eea199c20ecbab3a588ac", - "addresses": [ - "t1J6HuzEqw8Aicm1WLL8YX7jo7Syy7zkTjs" - ] - }, - "spent": false - }, - { - "value": "9.375", - "n": 2, - "scriptPubKey": { - "hex": "76a9146096374c8e00616fd777c9497d9fce18eae3948d88ac", - "addresses": [ - "t1SgJpwdmPSgw4j6eAdVVY1duWkbixygptP" - ] - }, - "spent": false - }, - { - "value": "22.5", - "n": 3, - "scriptPubKey": { - "hex": "76a9145a5f63ff65c2b1f4124ed2f5aa6fd9db53ec2f4488ac", - "addresses": [ - "t1S7T6TRuYuodWyAkiRVxRj5XgfFs1G3PWY" - ] - }, - "spent": false - } - ], - "blockhash": "000000351df0a7b2a629657aecc89ce10d07f7c5a9ad7f03fefb3442b1a7a521", - "blockheight": 562387, - "confirmations": 1, - "time": 1585124312, - "blocktime": 1585124312, - "valueOut": "150.0001", - "valueIn": "0", - "fees": "0", - "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003d3940800324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0490878d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a91402664e0d583d97b55b71320eea199c20ecbab3a588ac601de137000000001976a9146096374c8e00616fd777c9497d9fce18eae3948d88ac80461c86000000001976a9145a5f63ff65c2b1f4124ed2f5aa6fd9db53ec2f4488ac00000000000000000000000000000000000000" - }, - { - "txid": "96990e262110a89d8e372df3126cf72023b07643325c9b8b38f4c3651c1931b3", - "version": 4, - "vin": [ - { - "txid": "", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": {}, - "addresses": null, - "value": "" - } - ], - "vout": [ - { - "value": "112.5", - "n": 0, - "scriptPubKey": { - "hex": "76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac", - "addresses": [ - "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" - ] - }, - "spent": false - }, - { - "value": "5.625", - "n": 1, - "scriptPubKey": { - "hex": "76a914361dfb3217992096d4fc8cfac8a076cdc4e9aaf588ac", - "addresses": [ - "t1NokQpvLQo1Ti4MzvqPM24tn5psXEbJAWu" - ] - }, - "spent": false - }, - { - "value": "9.375", - "n": 2, - "scriptPubKey": { - "hex": "76a9142ccfb039f8a3057684832334b2b96f38299d9a9988ac", - "addresses": [ - "t1MxYYDbod3vJNDpmCXPF99SpoFZ8j4k8dZ" - ] - }, - "spent": false - }, - { - "value": "22.5", - "n": 3, - "scriptPubKey": { - "hex": "76a9143d94fc18dd332c386014f9e5b05cce17710a2ce688ac", - "addresses": [ - "t1PVDhgMueDh8vY3JfkZoXcGrwATCfkwaL9" - ] - }, - "spent": false - } - ], - "blockhash": "00000027379c0e0420ab3ebfc88a0f1bf59f10ced3317ce70f64ffa53f6a7775", - "blockheight": 562386, - "confirmations": 2, - "time": 1585124285, - "blocktime": 1585124285, - "valueOut": "150", - "valueIn": "0", - "fees": "0", - "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003d2940800324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0480608d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914361dfb3217992096d4fc8cfac8a076cdc4e9aaf588ac601de137000000001976a9142ccfb039f8a3057684832334b2b96f38299d9a9988ac80461c86000000001976a9143d94fc18dd332c386014f9e5b05cce17710a2ce688ac00000000000000000000000000000000000000" - }, - { - "txid": "aa1012b3cfcc36b0d6e10c25d0550d8ff482462cfc39e2ae93b03e9f7021bc00", - "version": 4, - "vin": [ - { - "txid": "", - "vout": 0, - "sequence": 4294967295, - "n": 0, - "scriptSig": {}, - "addresses": null, - "value": "" - } - ], - "vout": [ - { - "value": "112.5", - "n": 0, - "scriptPubKey": { - "hex": "76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac", - "addresses": [ - "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" - ] - }, - "spent": false - }, - { - "value": "5.625", - "n": 1, - "scriptPubKey": { - "hex": "76a914490683ffa4c8c06eca7f0ede150cf267df5e920988ac", - "addresses": [ - "t1QXj93zU8HVsfTpqJTHCnoZ9QvR2ho1rp7" - ] - }, - "spent": false - }, - { - "value": "9.375", - "n": 2, - "scriptPubKey": { - "hex": "76a91415f6ecf50ff229de0462f7003dcd5c5656f1e56888ac", - "addresses": [ - "t1Ksk14EFS9GqwGUF5kqnyR9zpYnKDAfxA5" - ] - }, - "spent": false - }, - { - "value": "22.5", - "n": 3, - "scriptPubKey": { - "hex": "76a914ee494e77ec55c57b2f5b42b1487a15fb3264227188ac", - "addresses": [ - "t1fbYeRABbZfzuxViLQbJ4d1dBTET48FgnV" - ] - }, - "spent": false - } - ], - "blockhash": "000000938163fab733308a221b50373250c7e8316e1420992abb833208152916", - "blockheight": 562385, - "confirmations": 3, - "time": 1585124162, - "blocktime": 1585124162, - "valueOut": "150", - "valueIn": "0", - "fees": "0", - "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003d1940800324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0480608d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914490683ffa4c8c06eca7f0ede150cf267df5e920988ac601de137000000001976a91415f6ecf50ff229de0462f7003dcd5c5656f1e56888ac80461c86000000001976a914ee494e77ec55c57b2f5b42b1487a15fb3264227188ac00000000000000000000000000000000000000" - } - ] - } + { + "page": 1, + "totalPages": 58223, + "itemsOnPage": 2, + "address": "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa", + "balance": "787501194898", + "totalReceived": "1224870418723238", + "totalSent": "1224082917528340", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 116445, + "transactions": [ + { + "txid": "58b5ce7d497d95e21ad9ebe2f2a3fb480483f77ca4de3ce1bc9a95eb9c0d18e1", + "version": 4, + "vin": [ + { + "sequence": 4294967295, + "n": 0, + "coinbase": "0322e80800324d696e6572732068747470733a2f2f326d696e6572732e636f6d" + } + ], + "vout": [ + { + "value": "11250000000", + "n": 0, + "hex": "76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac", + "addresses": [ + "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" + ] + }, + { + "value": "562500000", + "n": 1, + "hex": "76a914cc069c2af44790f67f6d1a26fa4668cd18ae3cee88ac", + "addresses": [ + "t1cUPmjzAv1UHmVDbdhwJTXQWER1Y9RXrab" + ] + }, + { + "value": "937500000", + "n": 2, + "hex": "76a9147e89c1c8a911588d4dd2df5ee0906de9b367631c88ac", + "addresses": [ + "t1VQgB2axkuPhYQfsbvUG7Wfhfm7WBEYiEb" + ] + }, + { + "value": "2250000000", + "n": 3, + "hex": "76a914c33faabb9d5162c37c0b29dcdb357a39738637b888ac", + "addresses": [ + "t1bfz3Q3E1adjroiPrGXaWsWNJ7u3WJHBgS" + ] + } + ], + "blockHash": "0000009f069aa63aef11ed375763532f3863bb2f03135827e1d6dfc5af3c4746", + "blockHeight": 583714, + "confirmations": 2, + "blockTime": 1587702257, + "value": "15000000000", + "valueIn": "0", + "fees": "0", + "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff200322e80800324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0480608d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914cc069c2af44790f67f6d1a26fa4668cd18ae3cee88ac601de137000000001976a9147e89c1c8a911588d4dd2df5ee0906de9b367631c88ac80461c86000000001976a914c33faabb9d5162c37c0b29dcdb357a39738637b888ac00000000000000000000000000000000000000" + }, + { + "txid": "eaddfc88f931b67c3046b8046fa96831fdeb590db9be4b1e59e706479b0f3012", + "version": 4, + "vin": [ + { + "sequence": 4294967295, + "n": 0, + "coinbase": "031fe80800324d696e6572732068747470733a2f2f326d696e6572732e636f6d" + } + ], + "vout": [ + { + "value": "11250011000", + "n": 0, + "hex": "76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac", + "addresses": [ + "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" + ] + }, + { + "value": "562500000", + "n": 1, + "hex": "76a9148a8b9570ece58cfce36487fe68da103964f2ff4288ac", + "addresses": [ + "t1WWAUFtKyytFzuXpn3Rzc6fGFndzD6xWLK" + ] + }, + { + "value": "937500000", + "n": 2, + "hex": "76a914c6e488b6eaa3becba6a1f439d3a5c05a41b6b77f88ac", + "addresses": [ + "t1c1Fa9ARp7KvHgEi3SKefpkLzy2yBTZvZc" + ] + }, + { + "value": "2250000000", + "n": 3, + "hex": "76a91446f4a65996b3689d296445f2a1170f9f87c2f82e88ac", + "addresses": [ + "t1QLnPL6ozQjArqX4QSDesMNkXTFWUUhbeF" + ] + } + ], + "blockHash": "0000006926830de74fa8629389bb21802ecbfe254ab52198678de133ed6c3b22", + "blockHeight": 583711, + "confirmations": 5, + "blockTime": 1587701924, + "value": "15000011000", + "valueIn": "0", + "fees": "0", + "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff20031fe80800324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff04788b8d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a9148a8b9570ece58cfce36487fe68da103964f2ff4288ac601de137000000001976a914c6e488b6eaa3becba6a1f439d3a5c05a41b6b77f88ac80461c86000000001976a91446f4a65996b3689d296445f2a1170f9f87c2f82e88ac00000000000000000000000000000000000000" + } + ] + } `); } return {error: "Not implemented"}; diff --git a/platform/bitcoin/client.go b/platform/bitcoin/client.go index 0e19ab85d..a1c400602 100644 --- a/platform/bitcoin/client.go +++ b/platform/bitcoin/client.go @@ -2,9 +2,10 @@ package bitcoin import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" "strconv" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) type Client struct { @@ -12,7 +13,7 @@ type Client struct { } func (c *Client) GetTransactions(address string) (transactions TransactionsList, err error) { - path := fmt.Sprintf("address/%s", address) + path := fmt.Sprintf("v2/address/%s", address) err = c.Get(&transactions, path, url.Values{ "details": {"txs"}, "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, diff --git a/platform/bitcoin/transaction.go b/platform/bitcoin/transaction.go index fd4d250ee..577cdc553 100644 --- a/platform/bitcoin/transaction.go +++ b/platform/bitcoin/transaction.go @@ -1,13 +1,14 @@ package bitcoin import ( + "net/http" + "sort" + mapset "github.com/deckarep/golang-set" "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" - "net/http" - "sort" ) // @Summary Get xpub transactions @@ -142,7 +143,7 @@ func normalizeTransaction(tx Transaction, coinIndex uint) blockatlas.Tx { } func parseOutputs(outputs []Output) (addresses []blockatlas.TxOutput) { - set := make(map[string]blockatlas.TxOutput) + set := make(map[string]*blockatlas.TxOutput) var ordered []string for _, output := range outputs { for _, address := range output.OutputAddress() { @@ -151,7 +152,7 @@ func parseOutputs(outputs []Output) (addresses []blockatlas.TxOutput) { val.Value = blockatlas.Amount(value) } else { amount := numbers.GetAmountValue(output.Value) - set[address] = blockatlas.TxOutput{ + set[address] = &blockatlas.TxOutput{ Address: address, Value: blockatlas.Amount(amount), } @@ -160,7 +161,7 @@ func parseOutputs(outputs []Output) (addresses []blockatlas.TxOutput) { } } for _, val := range ordered { - addresses = append(addresses, set[val]) + addresses = append(addresses, *set[val]) } return addresses } diff --git a/platform/bitcoin/transaction_test.go b/platform/bitcoin/transaction_test.go index 8a11c33ba..4fe8065f3 100644 --- a/platform/bitcoin/transaction_test.go +++ b/platform/bitcoin/transaction_test.go @@ -3,11 +3,13 @@ package bitcoin import ( "bytes" "encoding/json" + "reflect" + "testing" + mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" ) const outgoingTx = `{ @@ -282,3 +284,96 @@ func TestTransactionStatus(t *testing.T) { assert.Equal(t, test.Expected, test.Tx.getStatus()) } } + +func TestParseOutputs(t *testing.T) { + tests := []struct { + name string + outputs string + want []blockatlas.TxOutput + }{ + { + name: "Test Doge inputs from 0xb02977b96e5c65fd807e28230375c1267ded1de7c2c43292bf36552283bc5696", + outputs: `[{ + "txid": "6f59c4d96566c84aecb8399884d781766fe39d3ec76c609e6c11b01192c07341", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "DPoYGk1wGQ3uWs5G3exd9WKvVyu8weKYVA" + ], + "isAddress": true, + "value": "10000000", + "hex": "47304402207bb4fe5709874e5bc82c88945f8abb9aebdab996a1a619b0f01ec9a2ca3f862702204c02f986653bbf322ff5813322b72a7f7ac6cedfabf32d8e576be5eeee4acfc4012103565519e77659aae844889ae12609309f85a8d22bf815c4daa418e457c7cb01eb" + }, + { + "txid": "b476736ec08dc16942941103806ec16ce71ddde4d5422dcf6f05b4381c23b8b0", + "sequence": 4294967295, + "n": 1, + "addresses": [ + "DPoYGk1wGQ3uWs5G3exd9WKvVyu8weKYVA" + ], + "isAddress": true, + "value": "500000000", + "hex": "48304502210085426a63df0fa1343a3f7aa8903804a8e49815006f9ed65494b68a81588e605c02207a487df90dcc76e4cbe70358054084b97d407529912762fb784aac825c120125012103565519e77659aae844889ae12609309f85a8d22bf815c4daa418e457c7cb01eb" + }, + { + "txid": "239582019ca4dd5e4ba4441cdd949d67eb2461b6f0600d77245355f751bf9fb4", + "sequence": 4294967295, + "n": 2, + "addresses": [ + "DPoYGk1wGQ3uWs5G3exd9WKvVyu8weKYVA" + ], + "isAddress": true, + "value": "500000000", + "hex": "473044022047cad0afd2aa4ff9b3fc45a6afb40b9745c1b39499a96df803f899d189f3822c0220267464d2954de54825717b93e3597a0915c71aecf1215ed33021bef376813b9a012103565519e77659aae844889ae12609309f85a8d22bf815c4daa418e457c7cb01eb" + }]`, + want: []blockatlas.TxOutput{ + { + Address: "DPoYGk1wGQ3uWs5G3exd9WKvVyu8weKYVA", + Value: "1010000000", + }, + }, + }, + { + name: "Test Doge outputs from 0xb02977b96e5c65fd807e28230375c1267ded1de7c2c43292bf36552283bc5696", + outputs: `[{ + "value": "1000000000", + "n": 0, + "spent": true, + "hex": "76a914e34df4959b71f9a06af1eeb4f836e521067b777988ac", + "addresses": [ + "DRryKEukopEDv7cm6Y1Li6232VHEjnXptA" + ], + "isAddress": true + }, + { + "value": "9973378", + "n": 1, + "hex": "76a914ccb78d11b3850ac3252c1cbda0a2ceeaa833feaf88ac", + "addresses": [ + "DPoYGk1wGQ3uWs5G3exd9WKvVyu8weKYVA" + ], + "isAddress": true + }]`, + want: []blockatlas.TxOutput{ + { + Address: "DRryKEukopEDv7cm6Y1Li6232VHEjnXptA", + Value: "1000000000", + }, + { + Address: "DPoYGk1wGQ3uWs5G3exd9WKvVyu8weKYVA", + Value: "9973378", + }, + }, + }, + } + for _, tt := range tests { + var outputs []Output + _ = json.Unmarshal([]byte(tt.outputs), &outputs) + want := parseOutputs(outputs) + t.Run(tt.name, func(t *testing.T) { + if !reflect.DeepEqual(want, tt.want) { + t.Errorf("parseOutputs() = %v, want %v", want, tt.want) + } + }) + } +} diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index 7e3468453..35682bd2b 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -182,8 +182,8 @@ { "handler": "digibyte", "address": "address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi", - "expectedTxNum": 3, - "expectedTxId": "d7efaffeded550697d7385d3eb07e539237615792b29e3639df427ce919c8d6e" + "expectedTxNum": 2, + "expectedTxId": "2b7ba9b43d615fe03bc14bc18201d1bd73c7a0f8aad428accf51725743f9073a" }, { "handler": "digibyte", @@ -218,8 +218,8 @@ { "handler": "zelcash", "address": "address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa", - "expectedTxNum": 3, - "expectedTxId": "ca8b3fa115c5eae0f056d9b629680c521f4d9d271abbe86d4c482c54117e15a1" + "expectedTxNum": 2, + "expectedTxId": "58b5ce7d497d95e21ad9ebe2f2a3fb480483f77ca4de3ce1bc9a95eb9c0d18e1" }, { "handler": "zelcash", @@ -230,8 +230,8 @@ { "handler": "zcoin", "address": "address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn", - "expectedTxNum": 5, - "expectedTxId": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef" + "expectedTxNum": 2, + "expectedTxId": "f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609" }, { "handler": "zcoin", @@ -243,7 +243,7 @@ "handler": "zcash", "address": "address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX", "expectedTxNum": 2, - "expectedTxId": "d504755667e0fb61543e16d09aff5f84733f500190a07acb4a6784b4dc4c99e7" + "expectedTxId": "ca640e5215e141a4f9c235dd91e4b99fd1e0defdd5da27d78ec2cee02d3493dc" }, { "handler": "zcash", @@ -255,13 +255,13 @@ "handler": "bitcoin", "address": "address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj", "expectedTxNum": 2, - "expectedTxId": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4" + "expectedTxId": "36b1e721a25ea3ac2fcc09a92d4ff1e2ae4ed70d593e276806d9a9fd2a901132" }, { "handler": "bitcoin", "address": "xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", "expectedTxNum": 3, - "expectedTxId": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4" + "expectedTxId": "c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be" }, { "handler": "bitcoincash", @@ -277,9 +277,9 @@ }, { "handler": "ravencoin", - "address": "address/RHoCwPc2FCQqwToYnSiAb3SrCET4zEHsbS", + "address": "address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo", "expectedTxNum": 2, - "expectedTxId": "fc6c9e9c6cd0253f05e43a12d64154a689115f0103dc0b64957a8cb92b67f306" + "expectedTxId": "fc226aad6fc28e1204b747042e8c8b25f5d28424b9669bd162ba6a0149df2f71" }, { "handler": "ravencoin", @@ -291,7 +291,7 @@ "handler": "viacoin", "address": "address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A", "expectedTxNum": 2, - "expectedTxId": "dadbe1f13dc5ecd1cfb0d8ae139a4e55493eb9ab2c937cb78b67a5d9c1ded7e8" + "expectedTxId": "1b311427cd4749cbebd5c1fc70896b9e92a58d6935ba75bb40ed4a9e22e4a6cb" }, { "handler": "viacoin", @@ -338,8 +338,8 @@ { "handler": "dash", "address": "address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG", - "expectedTxNum": 3, - "expectedTxId": "f47a4929bcd8767819b6969c83893a76d5b26a145c74ace416ce4c454166186e" + "expectedTxNum": 2, + "expectedTxId": "8a1859bb849e207b7771c0301a6109a039eec955234b7848715b150f20fabeca" }, { "handler": "dash", diff --git a/vendor.yml b/vendor.yml deleted file mode 100644 index b9dfc5ff1..000000000 --- a/vendor.yml +++ /dev/null @@ -1,3 +0,0 @@ -# test data - -- mock/ext-api-dyson/ From 36fb65c46592e9367c0c37dce395170e06490f2c Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Fri, 24 Apr 2020 11:18:22 -0700 Subject: [PATCH 262/506] Fix CODEOWNERS format --- .github/CODEOWNERS | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5f280417a..4aafad044 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1 @@ -* @EnoRage -* @catenocrypt -* @hewigovens -* @kolya182 -* @prazd +* @EnoRage @catenocrypt @hewigovens @kolya182 @prazd From f52c636894d76fb7e23b124a59c642fdf3c2d109 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 24 Apr 2020 12:19:30 -0600 Subject: [PATCH 263/506] Filter delegations by state (#1053) * Filter delegations by state * Improve test coverage --- platform/solana/model.go | 13 ++++++++++-- platform/solana/stake.go | 20 +++++++++++-------- platform/solana/stake_test.go | 37 +++++++++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/platform/solana/model.go b/platform/solana/model.go index bffac00ac..d9c89fc0a 100644 --- a/platform/solana/model.go +++ b/platform/solana/model.go @@ -1,5 +1,14 @@ package solana +const ( + StakeStateUninitialized StakeState = 0 + StakeStateInitialized StakeState = 1 + StakeStateDelegated StakeState = 2 + StakeStateRewardsPool StakeState = 3 +) + +type StakeState uint32 + type VoteAccount struct { NodePubkey string `json:"nodePubkey"` VotePubkey string `json:"votePubkey"` @@ -38,8 +47,8 @@ type RpcContext struct { Slot uint64 `json:"slot"` } -type StakeState struct { - State uint32 +type StakeData struct { + State StakeState RentExemptReserve uint64 AuthorizedStaker [32]byte AuthorizedWithdrawer [32]byte diff --git a/platform/solana/stake.go b/platform/solana/stake.go index c69de5f99..6babc8ef3 100644 --- a/platform/solana/stake.go +++ b/platform/solana/stake.go @@ -3,9 +3,10 @@ package solana import ( "bytes" "encoding/binary" + "fmt" "github.com/btcsuite/btcutil/base58" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/logger" services "github.com/trustwallet/blockatlas/services/assets" "strconv" ) @@ -68,13 +69,13 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e return nil, err } - stakeAccounts := make([]StakeState, 0) + stakeAccounts := make([]StakeData, 0) for _, keyedAccount := range accounts { account, err := parseStakeData(keyedAccount.Account) if err != nil { return nil, err } - if isAuthorized(account, address) { + if account.State == StakeStateDelegated && isAuthorized(account, address) { stakeAccounts = append(stakeAccounts, account) } } @@ -95,14 +96,14 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e return NormalizeDelegations(stakeAccounts, validators, epochInfo) } -func parseStakeData(account Account) (stakeAccount StakeState, err error) { +func parseStakeData(account Account) (stakeAccount StakeData, err error) { buffer := base58.Decode(account.Data) r := bytes.NewReader(buffer) err = binary.Read(r, binary.LittleEndian, &stakeAccount) return } -func isAuthorized(stakeAccount StakeState, address string) bool { +func isAuthorized(stakeAccount StakeData, address string) bool { return stakeAccount.AuthorizedStaker == arrayOfPubkey(address) } @@ -114,19 +115,22 @@ func (p *Platform) UndelegatedBalance(address string) (string, error) { return strconv.FormatUint(account.Lamports, 10), nil } -func NormalizeDelegations(stakeAccounts []StakeState, validators blockatlas.ValidatorMap, epochInfo EpochInfo) (blockatlas.DelegationsPage, error) { +func NormalizeDelegations(stakeAccounts []StakeData, validators blockatlas.ValidatorMap, epochInfo EpochInfo) (blockatlas.DelegationsPage, error) { results := make([]blockatlas.Delegation, 0) for _, stakeState := range stakeAccounts { votePubkey := base58.Encode(stakeState.VoterPubkey[:]) validator, ok := validators[votePubkey] if !ok { - return nil, errors.E("Validator not found", - errors.Params{"Validator": votePubkey, "Platform": "solana"}) + logger.Debug(fmt.Sprintf("Unpublished solana validator: %s", votePubkey)) + continue } status := blockatlas.DelegationStatusPending if stakeState.ActivationEpoch > 0 && stakeState.ActivationEpoch <= epochInfo.Epoch { status = blockatlas.DelegationStatusActive } + if epochInfo.Epoch > stakeState.DeactivationEpoch { + continue + } delegation := blockatlas.Delegation{ Delegator: validator, Value: strconv.FormatUint(stakeState.Stake, 10), diff --git a/platform/solana/stake_test.go b/platform/solana/stake_test.go index 4817d2377..405360bd0 100644 --- a/platform/solana/stake_test.go +++ b/platform/solana/stake_test.go @@ -81,7 +81,7 @@ var keyedStakeAccount = KeyedAccount{ Pubkey: "EgR17fgGmwQQaMZPsuJdk9oHw2xY8TJQj3Bp44o24mar", } -var stakeState = StakeState{ +var stakeState = StakeData{ State: 2, RentExemptReserve: 2282880, AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), @@ -97,6 +97,38 @@ var stakeState = StakeState{ CreditsObserved: 21143, } +var deactivatedStakeState = StakeData{ + State: 2, + RentExemptReserve: 2282880, + AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + UnixTimestamp: 0, + LockupEpoch: 0, + Custodian: arrayOfPubkey("11111111111111111111111111111111"), + VoterPubkey: arrayOfPubkey("5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5"), + Stake: 99997717120, + ActivationEpoch: 70, + DeactivationEpoch: 78, + WarmupCooldownRate: 0.25, + CreditsObserved: 21143, +} + +var unpublishedValidatorStakeState = StakeData{ + State: 2, + RentExemptReserve: 2282880, + AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + UnixTimestamp: 0, + LockupEpoch: 0, + Custodian: arrayOfPubkey("11111111111111111111111111111111"), + VoterPubkey: arrayOfPubkey("BNTmegvdXzNVyc3UMTWSMSfJUryjr3fXEVErtdqrfs6y"), + Stake: 99997717120, + ActivationEpoch: 70, + DeactivationEpoch: 78, + WarmupCooldownRate: 0.25, + CreditsObserved: 21143, +} + func TestParseStakeData(t *testing.T) { result, err := parseStakeData(keyedStakeAccount.Account) @@ -145,7 +177,8 @@ var delegation = blockatlas.DelegationsPage{ } func TestNormalizeDelegations(t *testing.T) { - result, err := NormalizeDelegations([]StakeState{stakeState}, validatorMap, epochInfo) + stakeAccounts := []StakeData{stakeState, deactivatedStakeState, unpublishedValidatorStakeState} + result, err := NormalizeDelegations(stakeAccounts, validatorMap, epochInfo) assert.NoError(t, err) assert.Equal(t, delegation, result) } From af161d518723eec2bcf81efd7b77e343fbff7791 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov Date: Sat, 25 Apr 2020 00:06:22 +0300 Subject: [PATCH 264/506] [Platform] Update NormalizeDelegations and NormalizeUnbondingDelegations for cosmos and tron, add types package (#1048) * [Cosmos] Update NormalizeDelegations and NormalizeUnbondingDelegations * Fixes after review * Fixes after review * Fixes after review * Add ToDecommissioned * Fixes after review * Fixes after review * Fixes after review --- platform/cosmos/stake.go | 28 ++++++++++++++++++++++++---- platform/tron/stake.go | 3 +-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index 94795bde6..4d9ad5a3c 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -112,8 +112,9 @@ func NormalizeDelegations(delegations []Delegation, validators blockatlas.Valida for _, v := range delegations { validator, ok := validators[v.ValidatorAddress] if !ok { - logger.Error(errors.E("Validator not found", errors.Params{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress})) - continue + logger.Warn("Validator not found", logger.Params{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}) + validator = getUnknownValidator(v.ValidatorAddress) + } delegation := blockatlas.Delegation{ Delegator: validator, @@ -131,8 +132,8 @@ func NormalizeUnbondingDelegations(delegations []UnbondingDelegation, validators for _, entry := range v.Entries { validator, ok := validators[v.ValidatorAddress] if !ok { - logger.Error(errors.E("Validator not found", errors.Params{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress})) - continue + logger.Warn("Validator not found", logger.Params{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}) + validator = getUnknownValidator(v.ValidatorAddress) } t, _ := time.Parse(time.RFC3339, entry.CompletionTime) delegation := blockatlas.Delegation{ @@ -192,3 +193,22 @@ func (p *Platform) Denom() DenomType { return DenomAtom } } + +func getUnknownValidator(address string) blockatlas.StakeValidator { + return blockatlas.StakeValidator{ + ID: address, + Status: false, + Info: blockatlas.StakeValidatorInfo{ + Name: "Decommissioned", + Description: "Decommissioned", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 0, + }, + LockTime: lockTime, + MinimumAmount: minimumAmount, + Type: blockatlas.DelegationTypeDelegate, + }, + } +} diff --git a/platform/tron/stake.go b/platform/tron/stake.go index c3886dd2e..340660123 100644 --- a/platform/tron/stake.go +++ b/platform/tron/stake.go @@ -3,7 +3,6 @@ package tron import ( "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" services "github.com/trustwallet/blockatlas/services/assets" "strconv" @@ -87,7 +86,7 @@ func NormalizeDelegations(data *AccountData, validators blockatlas.ValidatorMap) for _, v := range data.Votes { validator, ok := validators[v.VoteAddress] if !ok { - logger.Error(errors.E("Validator not found", errors.Params{"address": v.VoteAddress, "platform": "tron"})) + logger.Warn("Validator not found", logger.Params{"address": v.VoteAddress, "platform": "tron"}) continue } delegation := blockatlas.Delegation{ From f45016ee6520b5c5a9503f64a4eb85997ae453e1 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov Date: Sun, 26 Apr 2020 22:51:20 +0300 Subject: [PATCH 265/506] [API] Add GetTokens handler (#1056) * [API] Add GetTokens handler * Rename param * Fixes after review * Add timeout * Update getTokens --- api/endpoint/token.go | 82 +++++++++++++++++++++++++++++++++++++++++++ api/registry.go | 3 ++ platform/registry.go | 7 ++++ 3 files changed, 92 insertions(+) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index 4111c542f..da739a2f6 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -5,6 +5,9 @@ import ( "github.com/trustwallet/blockatlas/api/model" "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/http" + "strconv" + "sync" + "time" ) // @Summary Get Tokens @@ -32,3 +35,82 @@ func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokenAPI) { } c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &result}) } + +// @Description Get tokens +// @ID tokens_v3 +// @Summary Get list of tokens by map: coin -> [addresses] +// @Accept json +// @Produce json +// @Tags Transactions +// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) +// @Success 200 {object} blockatlas.ResultsResponse +// @Router /v2/tokens [post] +func GetTokens(c *gin.Context, apis map[uint]blockatlas.TokenAPI) { + var query map[string][]string + if err := c.Bind(&query); err != nil { + c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + return + } + result := make(blockatlas.TokenPage, 0) + for coinStr, addresses := range query { + coinNum, err := strconv.ParseUint(coinStr, 10, 32) + if err != nil { + continue + } + api, ok := apis[uint(coinNum)] + if !ok { + continue + } + + tokens := getTokens(api, addresses) + result = append(result, tokens...) + } + c.JSON(http.StatusOK, blockatlas.ResultsResponse{Total: len(result), Results: &result}) +} + +func getTokens(tokenAPI blockatlas.TokenAPI, addresses []string) blockatlas.TokenPage { + var ( + tokenPagesChan = make(chan blockatlas.TokenPage, len(addresses)) + wg sync.WaitGroup + result blockatlas.TokenPage + timeout = time.Second * 3 + ) + + for _, address := range addresses { + wg.Add(1) + go func(address string, wg *sync.WaitGroup) { + defer wg.Done() + + stopChan := make(chan struct{}) + pageChan := make(chan blockatlas.TokenPage) + + go func() { + defer close(stopChan) + defer close(pageChan) + tokenPage, err := tokenAPI.GetTokenListByAddress(address) + if err != nil { + stopChan <- struct{}{} + return + } + pageChan <- tokenPage + }() + + select { + case <-time.After(timeout): + return + case <-stopChan: + return + case p := <-pageChan: + tokenPagesChan <- p + } + }(address, &wg) + } + wg.Wait() + close(tokenPagesChan) + + for page := range tokenPagesChan { + result = append(result, page...) + } + + return result +} diff --git a/api/registry.go b/api/registry.go index 9c3495214..4a42b17f7 100644 --- a/api/registry.go +++ b/api/registry.go @@ -90,6 +90,9 @@ func RegisterBatchAPI(root gin.IRouter) { root.POST("/v4/collectibles/categories", func(c *gin.Context) { endpoint.GetCollectionCategoriesFromList(c, platform.CollectionAPIs) }) + root.POST("/v2/tokens", func(c *gin.Context) { + endpoint.GetTokens(c, platform.TokensAPIs) + }) } // CustomAPI must be removed and all handlers needs to be migrated to the transactions, tokens api diff --git a/platform/registry.go b/platform/registry.go index a1018352f..4c6cecbfb 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -25,6 +25,9 @@ var ( // CollectionAPIs contain platforms which collections services CollectionAPIs map[uint]blockatlas.CollectionAPI + + // TokensAPIs contain platforms with token services + TokensAPIs map[uint]blockatlas.TokenAPI ) func getActivePlatforms(handle string) []blockatlas.Platform { @@ -56,6 +59,7 @@ func Init(platformHandle string) { CustomAPIs = make(map[string]blockatlas.CustomAPI) NamingAPIs = make(map[uint64]blockatlas.NamingServiceAPI) CollectionAPIs = make(map[uint]blockatlas.CollectionAPI) + TokensAPIs = make(map[uint]blockatlas.TokenAPI) for _, platform := range platformList { handle := platform.Coin().Handle @@ -92,5 +96,8 @@ func Init(platformHandle string) { if collectionAPI, ok := platform.(blockatlas.CollectionAPI); ok && CollectionsWhitelist[platform.Coin().ID] { CollectionAPIs[platform.Coin().ID] = collectionAPI } + if tokenAPI, ok := platform.(blockatlas.TokenAPI); ok { + TokensAPIs[platform.Coin().ID] = tokenAPI + } } } From 38fd09e7b84230b6c83cfb6c21d580fdfddc7889 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Mon, 27 Apr 2020 19:11:24 +0800 Subject: [PATCH 266/506] Incremental jsonrpc request id (#1062) * incremental id * Fix tests --- mock/ext-api-dyson/post/harmony-api.js | 8 ++++---- mock/ext-api-dyson/post/nimiq-rpc.js | 2 +- pkg/blockatlas/jsonrpc.go | 19 +++++++++++++++---- pkg/blockatlas/jsonrpc_test.go | 9 +++++---- platform/zilliqa/rpc.go | 4 ++-- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/mock/ext-api-dyson/post/harmony-api.js b/mock/ext-api-dyson/post/harmony-api.js index 065918fa4..149b827aa 100644 --- a/mock/ext-api-dyson/post/harmony-api.js +++ b/mock/ext-api-dyson/post/harmony-api.js @@ -1,6 +1,6 @@ /// Harmony RPC Mock -/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":"hmy_getTransactionsHistory"} ' http://localhost:3000/harmony-api -/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":"hmy_getTransactionsHistory"} ' https://{harmony_rpc} +/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":1} ' http://localhost:3000/harmony-api +/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":1} ' https://{harmony_rpc} /// curl "http://localhost:8420/v2/harmony/one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv" module.exports = { @@ -12,7 +12,7 @@ module.exports = { if (body.params[0].address === 'one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv') { return JSON.parse(`{ "jsonrpc": "2.0", - "id": "hmy_getTransactionsHistory", + "id": 1, "result": { "transactions": [ { @@ -76,7 +76,7 @@ module.exports = { } }`); } - return {jsonrpc:"2.0",id:"hmy_getTransactionsHistory",result:{"transactions":[]}}; + return {jsonrpc:"2.0",id:1,result:{"transactions":[]}}; } return {error: 'Invalid request'}; } diff --git a/mock/ext-api-dyson/post/nimiq-rpc.js b/mock/ext-api-dyson/post/nimiq-rpc.js index c854f7e75..08e70f00e 100644 --- a/mock/ext-api-dyson/post/nimiq-rpc.js +++ b/mock/ext-api-dyson/post/nimiq-rpc.js @@ -52,7 +52,7 @@ module.exports = { "flags": 0 } ], - "id": "getTransactionsByAddress" + "id": 2 } `); } diff --git a/pkg/blockatlas/jsonrpc.go b/pkg/blockatlas/jsonrpc.go index d96d76bb3..fd5968d13 100644 --- a/pkg/blockatlas/jsonrpc.go +++ b/pkg/blockatlas/jsonrpc.go @@ -2,9 +2,14 @@ package blockatlas import ( "encoding/json" + "github.com/trustwallet/blockatlas/pkg/errors" ) +var ( + requestId = int64(0) +) + const ( JsonRpcVersion = "2.0" ) @@ -16,14 +21,14 @@ type ( JsonRpc string `json:"jsonrpc"` Method string `json:"method"` Params interface{} `json:"params,omitempty"` - Id string `json:"id,omitempty"` + Id int64 `json:"id,omitempty"` } RpcResponse struct { JsonRpc string `json:"jsonrpc"` Error *RpcError `json:"error,omitempty"` Result interface{} `json:"result,omitempty"` - Id string `json:"id,omitempty"` + Id int64 `json:"id,omitempty"` } RpcError struct { @@ -46,7 +51,8 @@ func (r *RpcResponse) GetObject(toType interface{}) error { } func (r *Request) RpcCall(result interface{}, method string, params interface{}) error { - req := &RpcRequest{JsonRpc: JsonRpcVersion, Method: method, Params: params, Id: method} + + req := &RpcRequest{JsonRpc: JsonRpcVersion, Method: method, Params: params, Id: genId()} var resp *RpcResponse err := r.Post(&resp, "", req) if err != nil { @@ -73,7 +79,12 @@ func (r *Request) RpcBatchCall(requests RpcRequests) ([]RpcResponse, error) { func (rs RpcRequests) fillDefaultValues() RpcRequests { for _, r := range rs { r.JsonRpc = JsonRpcVersion - r.Id = r.Method + r.Id = genId() } return rs } + +func genId() int64 { + requestId += 1 + return requestId +} diff --git a/pkg/blockatlas/jsonrpc_test.go b/pkg/blockatlas/jsonrpc_test.go index b95417565..0ee82a211 100644 --- a/pkg/blockatlas/jsonrpc_test.go +++ b/pkg/blockatlas/jsonrpc_test.go @@ -1,8 +1,9 @@ package blockatlas import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestRpcRequests_fillDefaultValues(t *testing.T) { @@ -14,14 +15,14 @@ func TestRpcRequests_fillDefaultValues(t *testing.T) { { "test 1", RpcRequests{{Method: "method1", Params: "params1"}}, - RpcRequests{{Method: "method1", Params: "params1", JsonRpc: JsonRpcVersion, Id: "method1"}}, + RpcRequests{{Method: "method1", Params: "params1", JsonRpc: JsonRpcVersion, Id: 1}}, }, { "test 2", RpcRequests{ {Method: "method1", Params: "params1"}, {Method: "method2", Params: "params2"}}, RpcRequests{ - {Method: "method1", Params: "params1", JsonRpc: JsonRpcVersion, Id: "method1"}, - {Method: "method2", Params: "params2", JsonRpc: JsonRpcVersion, Id: "method2"}, + {Method: "method1", Params: "params1", JsonRpc: JsonRpcVersion, Id: 2}, + {Method: "method2", Params: "params2", JsonRpc: JsonRpcVersion, Id: 3}, }, }, } diff --git a/platform/zilliqa/rpc.go b/platform/zilliqa/rpc.go index 687e2a184..533823a9c 100644 --- a/platform/zilliqa/rpc.go +++ b/platform/zilliqa/rpc.go @@ -23,12 +23,12 @@ func (c *RpcClient) GetTx(hash string) (tx TxRPC, err error) { } func (c *RpcClient) GetBlockByNumber(number int64) ([]string, error) { - strNumber := strconv.Itoa(int(number)) + strNumber := strconv.FormatInt(number, 10) req := &blockatlas.RpcRequest{ JsonRpc: blockatlas.JsonRpcVersion, Method: "GetTransactionsForTxBlock", Params: []string{strNumber}, - Id: "GetTransactionsForTxBlock_" + strNumber, + Id: number, } var resp *BlockTxRpc err := c.Post(&resp, "", req) From 24f2fd966a511a21a1e69b27ef412bd6471f370a Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Mon, 27 Apr 2020 19:12:09 +0800 Subject: [PATCH 267/506] Return 404 instead of 500 if not found names (#1059) * return 404 and log error * skip empty string in zns --- api/endpoint/domain.go | 14 +++++++++----- platform/zilliqa/domain.go | 6 +++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/api/endpoint/domain.go b/api/endpoint/domain.go index 9c4cf4b28..ec4b6f824 100644 --- a/api/endpoint/domain.go +++ b/api/endpoint/domain.go @@ -1,12 +1,14 @@ package endpoint import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/api/model" - "github.com/trustwallet/blockatlas/services/domains" "net/http" "strconv" "strings" + + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/api/model" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/services/domains" ) // @Summary Lookup .eth / .zil addresses @@ -29,7 +31,8 @@ func GetAddressByCoinAndDomain(c *gin.Context) { } result, err := domains.HandleLookup(name, []uint64{coin}) if err != nil { - c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + logger.Warn(err) + c.JSON(http.StatusNotFound, model.CreateErrorResponse(model.InternalFail, err)) return } if len(result) == 0 { @@ -59,7 +62,8 @@ func GetAddressByCoinAndDomainBatch(c *gin.Context) { } result, err := domains.HandleLookup(name, coins) if err != nil { - c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + logger.Warn(err) + c.JSON(http.StatusNotFound, model.CreateErrorResponse(model.InternalFail, err)) return } if len(result) == 0 { diff --git a/platform/zilliqa/domain.go b/platform/zilliqa/domain.go index d104614e9..d31cd3e54 100644 --- a/platform/zilliqa/domain.go +++ b/platform/zilliqa/domain.go @@ -17,7 +17,11 @@ func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, e } for _, coin := range coins { symbol := CoinType.Coins[uint(coin)].Symbol - result = append(result, blockatlas.Resolved{Coin: coin, Result: resp.Addresses[symbol]}) + address := resp.Addresses[symbol] + if len(address) == 0 { + continue + } + result = append(result, blockatlas.Resolved{Coin: coin, Result: address}) } return result, nil } From c864f096d40e592023b53a78f15caffcab4429c2 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Tue, 28 Apr 2020 01:26:59 +0200 Subject: [PATCH 268/506] Mocked tests: Better error handling in case port is taken (3000) (#1047) * Mocked tests: Better error handling in case port is taken (3000). * Add health check for dyson, do check if it has started. * Change Dyson port to 3347 (from 3000). * Dyson start: Change Mocked API port to 8421 (from 8420). * Revert master merge errors. Co-authored-by: Catenocrypt --- Makefile | 14 +-- README.md | 13 ++- configmock.yml | 98 +++++++++---------- docker-compose.yml | 1 + mock/ext-api-dyson/dyson.json | 2 +- .../get/aeternity-api-transactions.js | 4 +- .../get/aion-get-getTransactionsByAddress.js | 4 +- .../ext-api-dyson/get/algorand-api-account.js | 4 +- mock/ext-api-dyson/get/algorand-api-block.js | 4 +- mock/ext-api-dyson/get/binance-api-tx.js | 6 +- mock/ext-api-dyson/get/binance-api-txs.js | 4 +- .../get/binance-dex-commands2.js | 8 +- mock/ext-api-dyson/get/bitcoin-api-address.js | 4 +- mock/ext-api-dyson/get/bitcoin-api-xpub.js | 4 +- .../get/bitcoincash-api-address.js | 4 +- .../ext-api-dyson/get/bitcoincash-api-xpub.js | 4 +- .../get/callisto-api-commands1.js | 8 +- .../ext-api-dyson/get/cosmos-api-commands2.js | 10 +- .../ext-api-dyson/get/cosmos-api-commands4.js | 4 +- mock/ext-api-dyson/get/dash-api-address.js | 4 +- mock/ext-api-dyson/get/dash-api-xpub.js | 4 +- mock/ext-api-dyson/get/decred-api-address.js | 4 +- mock/ext-api-dyson/get/decred-api-xpub.js | 4 +- .../ext-api-dyson/get/digibyte-api-address.js | 4 +- mock/ext-api-dyson/get/digibyte-api-xpub.js | 4 +- mock/ext-api-dyson/get/doge-api-address.js | 4 +- mock/ext-api-dyson/get/doge-api-xpub.js | 4 +- mock/ext-api-dyson/get/dyson-ping.js | 11 +++ mock/ext-api-dyson/get/eth-api-commands1.js | 8 +- .../get/eth-blockbook-api-transactions.js | 8 +- .../get/ethclassic-api-commands1.js | 8 +- .../get/gochain-api-commands1.js | 8 +- .../get/groestlcoin-api-address.js | 4 +- .../ext-api-dyson/get/groestlcoin-api-xpub.js | 4 +- mock/ext-api-dyson/get/icon-api-actions.js | 4 +- mock/ext-api-dyson/get/iotex-api-commands2.js | 8 +- mock/ext-api-dyson/get/iotex-api-commands4.js | 4 +- mock/ext-api-dyson/get/kava-api-commands2.js | 10 +- mock/ext-api-dyson/get/kava-api-commands4.js | 4 +- mock/ext-api-dyson/get/kava-api-txs.js | 6 +- mock/ext-api-dyson/get/kin-api-accounts.js | 4 +- .../ext-api-dyson/get/kin-api-transactions.js | 4 +- .../ext-api-dyson/get/litecoin-api-address.js | 4 +- mock/ext-api-dyson/get/litecoin-api-xpub.js | 4 +- mock/ext-api-dyson/get/nebulas-api-tx.js | 4 +- .../get/ontolotgy-api-v2-addresses.js | 4 +- mock/ext-api-dyson/get/poa-api-commands1.js | 8 +- mock/ext-api-dyson/get/qtum-api-address.js | 4 +- mock/ext-api-dyson/get/qtum-api-xpub.js | 4 +- .../get/ravencoin-api-address.js | 4 +- mock/ext-api-dyson/get/ravencoin-api-xpub.js | 4 +- mock/ext-api-dyson/get/ripple-get-accounts.js | 4 +- .../ext-api-dyson/get/stellar-api-accounts.js | 4 +- .../get/stellar-api-transactions.js | 4 +- .../get/tezos-api-transactions.js | 4 +- mock/ext-api-dyson/get/theta-api-accounttx.js | 4 +- .../get/thundertoken-api-commands1.js | 8 +- .../get/tomochain-api-commands1.js | 8 +- .../ext-api-dyson/get/tron-api-v1-accounts.js | 8 +- mock/ext-api-dyson/get/tron-api-v1-assets.js | 4 +- mock/ext-api-dyson/get/tron-api-wallet.js | 4 +- .../get/unstoppabledomains-lookup.js | 4 +- .../ext-api-dyson/get/vechain-api-entities.js | 6 +- mock/ext-api-dyson/get/viacoin-api-address.js | 4 +- mock/ext-api-dyson/get/viacoin-api-xpub.js | 4 +- .../get/waves-api-transactions-address.js | 4 +- mock/ext-api-dyson/get/zcash-api-address.js | 4 +- mock/ext-api-dyson/get/zcash-api-xpub.js | 4 +- mock/ext-api-dyson/get/zcoin-api-address.js | 4 +- mock/ext-api-dyson/get/zcoin-api-xpub.js | 4 +- mock/ext-api-dyson/get/zelcash-api-address.js | 4 +- mock/ext-api-dyson/get/zelcash-api-xpub.js | 4 +- .../get/zilliqa-api-addresses-txs.js | 4 +- mock/ext-api-dyson/post/eth-rpc.js | 4 +- mock/ext-api-dyson/post/fio-api-chain.js | 4 +- mock/ext-api-dyson/post/fio-api-history.js | 4 +- mock/ext-api-dyson/post/harmony-api.js | 4 +- mock/ext-api-dyson/post/kusama-api.js | 4 +- mock/ext-api-dyson/post/nano-api.js | 4 +- mock/ext-api-dyson/post/nimiq-rpc.js | 4 +- mock/ext-api-dyson/post/tron-api-wallet.js | 4 +- mock/ext-api-dyson/post/vechain-api-logs.js | 4 +- .../blockatlas.postman_collection.json | 91 +++++++++++++++++ tests/postman/mock-healthcheck_data.json | 4 + 84 files changed, 356 insertions(+), 244 deletions(-) create mode 100644 mock/ext-api-dyson/get/dyson-ping.js create mode 100644 tests/postman/mock-healthcheck_data.json diff --git a/Makefile b/Makefile index 404c5c3c6..9465dddd7 100644 --- a/Makefile +++ b/Makefile @@ -57,10 +57,10 @@ start-platform-api: stop @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" @echo " > Error log: $(STDERR)" -# start-platform-api-mock: Start API in development mode. Similar to start-platform-api, but uses config file with mock URLs +# start-platform-api-mock: Start API. Similar to start-platform-api, but uses config file with mock URLs, and port 8437. start-platform-api-mock: stop start-mock-dyson @echo " > Starting $(PROJECT_NAME) API" - @-$(GOBIN)/$(API_SERVICE)/platform_api -c $(CONFIG_MOCK_FILE) 2>&1 & echo $$! > $(PID_API) + @-$(GOBIN)/$(API_SERVICE)/platform_api -p 8437 -c $(CONFIG_MOCK_FILE) 2>&1 & echo $$! > $(PID_API) @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" @echo " > Error log: $(STDERR)" @@ -130,11 +130,13 @@ test: go-test ## integration: Run all integration tests. integration: go-integration -## start-mock-dyson: Start Dyson with mocks of external services +## start-mock-dyson: Start Dyson with mocks of external services. Make sure not to swallow error code in case port is taken. start-mock-dyson: stop-dyson @echo " > Starting Dyson with mocks" @-dyson mock/ext-api-dyson & echo $$! > $(PID_DYSON) @echo " > Dyson started with PID: " `cat $(PID_DYSON)` + # Check that it is running (e.g. may fail due to unavailable port) + @$(MAKE) newman-run test=mock-healthcheck host=http://localhost:8437 ## fmt: Run `go fmt` for all go files. fmt: go-fmt @@ -168,11 +170,11 @@ endif ## newman-mocked: Run mocked Postman Newman tests. newman-mocked: install-newman install-dyson go-compile - @bash -c "$(MAKE) newman-mocked-params host=http://localhost:8420" + @bash -c "$(MAKE) newman-mocked-params host=http://localhost:8437" ## newman-mocked-params: Run mocked Postman Newman tests, after starting platform api. ## The host parameter is required. -## E.g.: $ make newman-mocked-params test=domain host=http://localhost:8420 +## E.g.: $ make newman-mocked-params test=domain host=http://localhost:8437 newman-mocked-params: start-platform-api-mock ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host) && \ @@ -202,7 +204,7 @@ endif ## newman-run: Run chosen Newman tests. See newman target. newman-run: ifeq (,$(host)) - @echo " > Host parameter is missing. e.g: make newman test=staking host=http://localhost:8420" + @echo " > Host parameter is missing. e.g: make newman test=staking host=http://localhost:8437" @exit 1 endif @echo " > Running $(test) tests" diff --git a/README.md b/README.md index f0555085a..2d9dd7f82 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,9 @@ It works the same for observer_worker - you can run all observer at 1 binary or go get -u github.com/trustwallet/blockatlas cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas +# Start Platform API server at port 8420 with the path to the config.yml ./ +go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 -c config.yml + # Start observer_parser with the path to the config.yml ./ go build -o observer_parser-bin cmd/observer_parser/main.go && ./observer_parser-bin -c config.yml @@ -104,11 +107,11 @@ go build -o observer_notifier-bin cmd/observer_notifier/main.go && ./observer_no # Start observer_subscriber with the path to the config.yml ./ go build -o observer_subscriber-bin cmd/observer_subscriber/main.go && ./observer_subscriber-bin -c config.yml -# Start Platform API server at port 8420 with the path to the config.yml ./ -go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 -c config.yml - # Startp Swagger API server at port 8422 with the path to the config.yml ./ go build -o swagger-api-bin cmd/swagger-api/main.go && ./swagger-api-bin -p 8423 + +# Start Platform API server with mocked config, at port 8437 ./ +go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8437 -c configmock.yml ``` OR @@ -187,13 +190,13 @@ End-to-end tests with calls to external APIs has great value, but is not suitabl Therefore mocked API-level tests are used, whereby external APIs are replaced by mocks. * External mocks are implemented using *dyson*, as javascript files. They generally return constant, pre-canned responses to the requests that occur during tests. -* Mocks are 'turned on' by corresponding API endpoints in the configmock.yml config file (localhost:3000). +* Mocks are 'turned on' by corresponding API endpoints in the configmock.yml config file (localhost:3347). * Tests invoke into blockatlas through public APIs only, and are executed using *newman* (Postman cli -- `make newman-mocked`). * Product code, and even test code should not be aware whether it runs with mocks or the real external endpoints. * See Makefile for targets with 'mock'; platform can be started locally with mocks using `make start-platform-api-mock`. * When dyson is started (e.g. with `make start-platform-api-mock`), it outputs requests, which helps debugging * The newman tests can be executed with unmocked external APIs as well, but verifications may fail, because some APIs return variable responses. Unmocked tests are not intended for regular CI execution, but as ad-hoc development tests. -* General steps for creating new mocked tests: replace endpoint to localhost:3000, observer incoming calls (dyson output), obtain real response from external API (with exact same parameters), enhance dsyon script to return the same output, verify that blockatlas provides correct output. Also, add verifications of results to the tests. +* General steps for creating new mocked tests: replace endpoint to localhost:3347, observer incoming calls (dyson output), obtain real response from external API (with exact same parameters), enhance dsyon script to return the same output, verify that blockatlas provides correct output. Also, add verifications of results to the tests. ## Docs diff --git a/configmock.yml b/configmock.yml index 2e7f40de2..153560d0c 100644 --- a/configmock.yml +++ b/configmock.yml @@ -37,53 +37,53 @@ postgres: # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org binance: - api: http://localhost:3000/binance-api/v1 - dex: http://localhost:3000/binance-dex + api: http://localhost:3347/binance-api/v1 + dex: http://localhost:3347/binance-dex # [NIM] Nimiq: https://nimiq.com nimiq: - api: http://localhost:3000/nimiq-rpc + api: http://localhost:3347/nimiq-rpc # [XRP] Ripple: https://ripple.com ripple: - api: http://localhost:3000/ripple-api + api: http://localhost:3347/ripple-api # [XLM] Stellar Lumen: https://www.stellar.org stellar: - api: http://localhost:3000/stellar-api + api: http://localhost:3347/stellar-api # [KIN] Kin: https://www.kin.org kin: - api: http://localhost:3000/kin-api + api: http://localhost:3347/kin-api # [XTZ] Tezos: https://tezos.com tezos: - api: http://localhost:3000/tezos-api + api: http://localhost:3347/tezos-api rpc: https://mainnet.tezos.org.ua # [ETH] Ethereum: https://ethereum.org (Trust-Ray API) ethereum: - api: http://localhost:3000/eth-api - blockbook_api: http://localhost:3000/eth-blockbook-api + api: http://localhost:3347/eth-api + blockbook_api: http://localhost:3347/eth-blockbook-api collections_api: https://api.opensea.io collections_api_key: opensea_api_key - rpc: http://localhost:3000/eth-rpc + rpc: http://localhost:3347/eth-rpc # [ETC] Ethereum Classic: https://ethereumclassic.org (Trust-Ray API) classic: - api: http://localhost:3000/ethclassic-api + api: http://localhost:3347/ethclassic-api # [POA] POA Network: https://poa.network (Trust-Ray API) poa: - api: http://localhost:3000/poa-api + api: http://localhost:3347/poa-api # [CLO] Callisto Network: https://callisto.network (Trust-Ray API) callisto: - api: http://localhost:3000/callisto-api + api: http://localhost:3347/callisto-api # [GO] GoChain: https://gochain.io (Trust-Ray API) gochain: - api: http://localhost:3000/gochain-api + api: http://localhost:3347/gochain-api # [WAN] Wanchain: https://wanchain.org (Trust-Ray API) # wanchain: @@ -91,120 +91,120 @@ gochain: # [TOMO] TomoChain: https://tomochain.com (Trust-Ray API) tomochain: - api: http://localhost:3000/tomochain-api + api: http://localhost:3347/tomochain-api # [TT] ThunderCore: https://www.thundercore.com (Trust-Ray API) thundertoken: - api: http://localhost:3000/thundertoken-api + api: http://localhost:3347/thundertoken-api # [AION] Aion: https://aion.network aion: - api: http://localhost:3000/aion-api + api: http://localhost:3347/aion-api # [ICX] ICON: https://icon.foundation icon: - api: http://localhost:3000/icon-api + api: http://localhost:3347/icon-api # [TRX] Tron: https://tron.network/ tron: - api: http://localhost:3000/tron-api + api: http://localhost:3347/tron-api # [VET] VeChain: https://www.vechain.org vechain: - api: http://localhost:3000/vechain-api + api: http://localhost:3347/vechain-api # [THETA] THETA: https://www.thetatoken.org/ theta: - api: http://localhost:3000/theta-api + api: http://localhost:3347/theta-api # [ATOM] Cosmos: https://cosmos.network/ cosmos: - api: http://localhost:3000/cosmos-api + api: http://localhost:3347/cosmos-api # [ONTOLOGY] ONT: https://ont.io/ ontology: - api: http://localhost:3000/ontology-api + api: http://localhost:3347/ontology-api # [ZIL] Zilliqa: https://zilliqa.com zilliqa: - api: http://localhost:3000/zilliqa-api + api: http://localhost:3347/zilliqa-api # key: YOUR_API_KEY rpc: https://api.zilliqa.com - lookup: http://localhost:3000/unstoppabledomains/api/v1 + lookup: http://localhost:3347/unstoppabledomains/api/v1 #[IoTeX] IoTeX: https://iotex.io iotex: - api: http://localhost:3000/iotex-api + api: http://localhost:3347/iotex-api # [WAVES] Waves: http://wavesplatform.com waves: - api: http://localhost:3000/waves-api + api: http://localhost:3347/waves-api # [AE] Aeternity: https://aeternity.com aeternity: - api: http://localhost:3000/aeternity-api + api: http://localhost:3347/aeternity-api # [NAS] Nebulas: https://nebulas.io nebulas: - api: http://localhost:3000/nebulas-api + api: http://localhost:3347/nebulas-api fio: - api: http://localhost:3000/fio-api + api: http://localhost:3347/fio-api # [BTC] Bitcoin: https://bitcoin.org/ (Blockbook API https://github.com/trezor/blockbook) bitcoin: - api: http://localhost:3000/bitcoin-api + api: http://localhost:3347/bitcoin-api litecoin: - api: http://localhost:3000/litecoin-api + api: http://localhost:3347/litecoin-api bitcoincash: - api: http://localhost:3000/bitcoincash-api + api: http://localhost:3347/bitcoincash-api doge: - api: http://localhost:3000/doge-api + api: http://localhost:3347/doge-api dash: - api: http://localhost:3000/dash-api + api: http://localhost:3347/dash-api zcoin: - api: http://localhost:3000/zcoin-api + api: http://localhost:3347/zcoin-api zcash: - api: http://localhost:3000/zcash-api + api: http://localhost:3347/zcash-api zelcash: - api: http://localhost:3000/zelcash-api + api: http://localhost:3347/zelcash-api viacoin: - api: http://localhost:3000/viacoin-api + api: http://localhost:3347/viacoin-api qtum: - api: http://localhost:3000/qtum-api + api: http://localhost:3347/qtum-api groestlcoin: - api: http://localhost:3000/groestlcoin-api + api: http://localhost:3347/groestlcoin-api ravencoin: - api: http://localhost:3000/ravencoin-api + api: http://localhost:3347/ravencoin-api decred: - api: http://localhost:3000/decred-api + api: http://localhost:3347/decred-api algorand: - api: http://localhost:3000/algorand-api + api: http://localhost:3347/algorand-api nano: - api: http://localhost:3000/nano-api + api: http://localhost:3347/nano-api digibyte: - api: http://localhost:3000/digibyte-api + api: http://localhost:3347/digibyte-api harmony: - api: http://localhost:3000/harmony-api + api: http://localhost:3347/harmony-api kava: - api: http://localhost:3000/kava-api + api: http://localhost:3347/kava-api kusama: - api: http://localhost:3000/kusama-rpc + api: http://localhost:3347/kusama-rpc diff --git a/docker-compose.yml b/docker-compose.yml index 1a9faed94..e744b50c1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,6 +19,7 @@ services: - SERVICE=platform_api ports: - 8420:8420 + - 8437:8437 swagger_api: container_name: swagger_api diff --git a/mock/ext-api-dyson/dyson.json b/mock/ext-api-dyson/dyson.json index a6b63fe8a..897ddd5f2 100644 --- a/mock/ext-api-dyson/dyson.json +++ b/mock/ext-api-dyson/dyson.json @@ -1,5 +1,5 @@ { - "port": 3000, + "port": 3347, "proxy": false, "multiRequest": "+", "quiet": false diff --git a/mock/ext-api-dyson/get/aeternity-api-transactions.js b/mock/ext-api-dyson/get/aeternity-api-transactions.js index 9b36c79db..3f7eb9c40 100644 --- a/mock/ext-api-dyson/get/aeternity-api-transactions.js +++ b/mock/ext-api-dyson/get/aeternity-api-transactions.js @@ -1,8 +1,8 @@ /// Aeternity API Mock /// See: -/// curl "http://localhost:3000/aeternity-api/middleware/transactions/account/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb?" +/// curl "http://localhost:3347/aeternity-api/middleware/transactions/account/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb?" /// curl "https://mdw.aepps.com/middleware/transactions/account/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb?" -/// curl http://localhost:8420/v1/aeternity/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb +/// curl http://localhost:8437/v1/aeternity/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb module.exports = { path: "/aeternity-api/middleware/transactions/:type/:address?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js b/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js index 78867abba..a9af61863 100644 --- a/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js +++ b/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js @@ -1,8 +1,8 @@ /// Aion API Mock /// See: -/// curl "http://localhost:3000/aion-api/getTransactionsByAddress?accountAddress=0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed&size=25" +/// curl "http://localhost:3347/aion-api/getTransactionsByAddress?accountAddress=0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed&size=25" /// curl "https://mainnet-api.theoan.com/aion/dashboard/getTransactionsByAddress?accountAddress=0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed&size=25" -/// curl http://localhost:8420/v1/aion/0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed +/// curl http://localhost:8437/v1/aion/0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed module.exports = { path: "/aion-api/getTransactionsByAddress?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/algorand-api-account.js b/mock/ext-api-dyson/get/algorand-api-account.js index ceac2cbd3..f923d29ac 100644 --- a/mock/ext-api-dyson/get/algorand-api-account.js +++ b/mock/ext-api-dyson/get/algorand-api-account.js @@ -1,7 +1,7 @@ /// Mock for external Algorand API -/// curl "http://localhost:3000/algorand-api/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions?" +/// curl "http://localhost:3347/algorand-api/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions?" /// curl "http://{algorand rpc}/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions?" -/// curl http://localhost:8420/v1/algorand/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U +/// curl http://localhost:8437/v1/algorand/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U module.exports = { path: '/algorand-api/v1/account/:account/transactions?', diff --git a/mock/ext-api-dyson/get/algorand-api-block.js b/mock/ext-api-dyson/get/algorand-api-block.js index fe67d4016..2b28a1490 100644 --- a/mock/ext-api-dyson/get/algorand-api-block.js +++ b/mock/ext-api-dyson/get/algorand-api-block.js @@ -1,7 +1,7 @@ /// Mock for external Algorand API -/// curl "http://localhost:3000/algorand-api/v1/block/5478346?" +/// curl "http://localhost:3347/algorand-api/v1/block/5478346?" /// curl "http://{algorand rpc}/v1/block/5478346?" -/// curl http://localhost:8420/v1/algorand/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U +/// curl http://localhost:8437/v1/algorand/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U module.exports = { path: '/algorand-api/v1/block/:block?', diff --git a/mock/ext-api-dyson/get/binance-api-tx.js b/mock/ext-api-dyson/get/binance-api-tx.js index 13ece8742..63b0e1f75 100644 --- a/mock/ext-api-dyson/get/binance-api-tx.js +++ b/mock/ext-api-dyson/get/binance-api-tx.js @@ -1,10 +1,10 @@ /// Binance chain block explorer API Mock, tx /// Returns: /// - Multi-transaction transaction for a specific address -/// see http://localhost:3000/binance-api/v1/tx?txHash=F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC +/// see http://localhost:3347/binance-api/v1/tx?txHash=F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC /// see https://explorer.binance.org/api/v1/tx?txHash=F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC -/// see http://localhost:8420/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp -/// see http://localhost:8420/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp?token=BUSD-BD1 +/// see http://localhost:8437/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp +/// see http://localhost:8437/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp?token=BUSD-BD1 /// - empty response for other txHash'es module.exports = { diff --git a/mock/ext-api-dyson/get/binance-api-txs.js b/mock/ext-api-dyson/get/binance-api-txs.js index fafcd41b6..3c0591db0 100644 --- a/mock/ext-api-dyson/get/binance-api-txs.js +++ b/mock/ext-api-dyson/get/binance-api-txs.js @@ -4,9 +4,9 @@ /// - for address 'bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd' 1 tx /// - empty list for other addresses /// See: -/// curl "http://localhost:3000/explorer-api/v1/txs?address=bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp&page=1&rows=20&txAsset=BNB&txType=TRANSFER" +/// curl "http://localhost:3347/explorer-api/v1/txs?address=bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp&page=1&rows=20&txAsset=BNB&txType=TRANSFER" /// curl "https://explorer.binance.org/api/v1/txs?address=bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp&page=1&rows=20&txAsset=BNB&txType=TRANSFER" -/// curl "http://localhost:8420/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp" +/// curl "http://localhost:8437/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp" module.exports = { path: '/binance-api/v1/txs', diff --git a/mock/ext-api-dyson/get/binance-dex-commands2.js b/mock/ext-api-dyson/get/binance-dex-commands2.js index c60466506..6a7299f78 100644 --- a/mock/ext-api-dyson/get/binance-dex-commands2.js +++ b/mock/ext-api-dyson/get/binance-dex-commands2.js @@ -1,10 +1,10 @@ /// Binance chain block explorer API Mock, Dex /// See: -/// curl "http://localhost:3000/binance-dex/v1/account/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" -/// curl "http://localhost:3000/binance-dex/v1/tokens?limit=1000&offset=0" +/// curl "http://localhost:3347/binance-dex/v1/account/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" +/// curl "http://localhost:3347/binance-dex/v1/tokens?limit=1000&offset=0" /// curl "https://dex.binance.org/api/v1/account/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" /// curl "https://dex.binance.org/api/v1/tokens?limit=1000&offset=0" -/// curl "http://localhost:8420/v2/binance/tokens/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m?Authorization=Bearer" +/// curl "http://localhost:8437/v2/binance/tokens/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m?Authorization=Bearer" module.exports = { path: '/binance-dex/:version/:command1/:command2?', @@ -458,7 +458,7 @@ module.exports = { "original_symbol": "ABCD", "owner": "bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms", "symbol": "ABCD-5D8", - "total_supply": "3000000.00000000" + "total_supply": "3347000.00000000" }, { "mintable": false, diff --git a/mock/ext-api-dyson/get/bitcoin-api-address.js b/mock/ext-api-dyson/get/bitcoin-api-address.js index 16ef2ab65..a8e8f7529 100644 --- a/mock/ext-api-dyson/get/bitcoin-api-address.js +++ b/mock/ext-api-dyson/get/bitcoin-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Bitcoin API /// See: -/// curl "http://localhost:3000/bitcoin-api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" +/// curl "http://localhost:3347/bitcoin-api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" /// curl "https://btc1.trezor.io/api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" -/// curl "http://localhost:8420/v1/bitcoin/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" +/// curl "http://localhost:8437/v1/bitcoin/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" module.exports = { path: '/bitcoin-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/bitcoin-api-xpub.js b/mock/ext-api-dyson/get/bitcoin-api-xpub.js index d1bf669da..c5a5a12b5 100644 --- a/mock/ext-api-dyson/get/bitcoin-api-xpub.js +++ b/mock/ext-api-dyson/get/bitcoin-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Bitcoin API /// See: /// curl "https://btc1.trezor.io/api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs" -/// curl "http://localhost:3000/bitcoin-api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs" -/// curl "http://localhost:8420/v1/bitcoin/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC" +/// curl "http://localhost:3347/bitcoin-api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs" +/// curl "http://localhost:8437/v1/bitcoin/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC" module.exports = { path: '/bitcoin-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/bitcoincash-api-address.js b/mock/ext-api-dyson/get/bitcoincash-api-address.js index 9534c9bba..c92626142 100644 --- a/mock/ext-api-dyson/get/bitcoincash-api-address.js +++ b/mock/ext-api-dyson/get/bitcoincash-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Bitcoincash API /// See: /// curl "http://{bch rpc}/api/v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" -/// curl "http://localhost:3000/bitcoincash-api/v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" -/// curl "http://localhost:8420/v1/bitcoincash/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" +/// curl "http://localhost:3347/bitcoincash-api/v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" +/// curl "http://localhost:8437/v1/bitcoincash/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" module.exports = { path: '/bitcoincash-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/bitcoincash-api-xpub.js b/mock/ext-api-dyson/get/bitcoincash-api-xpub.js index f707df5eb..9a8abeb55 100644 --- a/mock/ext-api-dyson/get/bitcoincash-api-xpub.js +++ b/mock/ext-api-dyson/get/bitcoincash-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Bitcoincash API /// See: /// curl "http://{bch rpc}/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs" -/// curl "http://localhost:3000/bitcoincash-api/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs" -/// curl "http://localhost:8420/v1/bitcoincash/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX" +/// curl "http://localhost:3347/bitcoincash-api/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs" +/// curl "http://localhost:8437/v1/bitcoincash/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX" module.exports = { path: '/bitcoincash-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/callisto-api-commands1.js b/mock/ext-api-dyson/get/callisto-api-commands1.js index af630eea6..01d4a9452 100644 --- a/mock/ext-api-dyson/get/callisto-api-commands1.js +++ b/mock/ext-api-dyson/get/callisto-api-commands1.js @@ -1,11 +1,11 @@ /// Callisto API Mock /// See: -/// curl "http://localhost:3000/callisto-api/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" -/// curl "http://localhost:3000/callisto-api/tokens?address=0xc3d5b69f65027ddf48f894e6e90121293a2f6615" +/// curl "http://localhost:3347/callisto-api/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" +/// curl "http://localhost:3347/callisto-api/tokens?address=0xc3d5b69f65027ddf48f894e6e90121293a2f6615" /// curl "https://{callisto rpc}/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" /// curl "https://{callisto rpc}/tokens?address=0xc3d5b69f65027ddf48f894e6e90121293a2f6615" -/// curl "http://localhost:8420/v1/callisto/0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" -/// curl "http://localhost:8420/v2/callisto/tokens/0xc3d5b69f65027ddf48f894e6e90121293a2f6615?Authorization=Bearer" +/// curl "http://localhost:8437/v1/callisto/0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" +/// curl "http://localhost:8437/v2/callisto/tokens/0xc3d5b69f65027ddf48f894e6e90121293a2f6615?Authorization=Bearer" module.exports = { path: '/callisto-api/:command1?', diff --git a/mock/ext-api-dyson/get/cosmos-api-commands2.js b/mock/ext-api-dyson/get/cosmos-api-commands2.js index 4b3517811..4a5de1ffc 100644 --- a/mock/ext-api-dyson/get/cosmos-api-commands2.js +++ b/mock/ext-api-dyson/get/cosmos-api-commands2.js @@ -1,13 +1,13 @@ /// Cosmos API Mock /// See: -/// curl "http://localhost:3000/cosmos-api/staking/validators?status=bonded" -/// curl "http://localhost:3000/cosmos-api/staking/pool" -/// curl "http://localhost:3000/cosmos-api/minting/inflation" +/// curl "http://localhost:3347/cosmos-api/staking/validators?status=bonded" +/// curl "http://localhost:3347/cosmos-api/staking/pool" +/// curl "http://localhost:3347/cosmos-api/minting/inflation" /// curl "https://{cosmos_rpc}/staking/validators?status=bonded" /// curl "https://{cosmos_rpc}/staking/pool" /// curl "https://{cosmos_rpc}/minting/inflation" -/// curl "http://localhost:8420/v2/cosmos/staking/validators" -/// curl "http://localhost:8420/v2/cosmos/staking/delegations/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq?Authorization=Bearer" +/// curl "http://localhost:8437/v2/cosmos/staking/validators" +/// curl "http://localhost:8437/v2/cosmos/staking/delegations/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq?Authorization=Bearer" module.exports = { path: "/cosmos-api/:command1/:command2?", diff --git a/mock/ext-api-dyson/get/cosmos-api-commands4.js b/mock/ext-api-dyson/get/cosmos-api-commands4.js index 82c3dfbdf..f59cea546 100644 --- a/mock/ext-api-dyson/get/cosmos-api-commands4.js +++ b/mock/ext-api-dyson/get/cosmos-api-commands4.js @@ -1,8 +1,8 @@ /// Cosmos API Mock /// See: -/// curl "http://localhost:3000/cosmos-api/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/delegations" +/// curl "http://localhost:3347/cosmos-api/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/delegations" /// curl "https://{cosmos_rpc}/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/delegations" -/// curl "http://localhost:8420/v2/cosmos/staking/delegations/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq?Authorization=Bearer" +/// curl "http://localhost:8437/v2/cosmos/staking/delegations/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq?Authorization=Bearer" module.exports = { path: "/cosmos-api/:command1/:command2/:arg3/:arg4?", diff --git a/mock/ext-api-dyson/get/dash-api-address.js b/mock/ext-api-dyson/get/dash-api-address.js index 74e0dda54..68f5bb930 100644 --- a/mock/ext-api-dyson/get/dash-api-address.js +++ b/mock/ext-api-dyson/get/dash-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Dash API /// See: /// curl "http://{dash rpc}/api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" -/// curl "http://localhost:3000/dash-api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" -/// curl "http://localhost:8420/v1/dash/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" +/// curl "http://localhost:3347/dash-api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" +/// curl "http://localhost:8437/v1/dash/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" module.exports = { path: '/dash-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/dash-api-xpub.js b/mock/ext-api-dyson/get/dash-api-xpub.js index 1a187be43..300246007 100644 --- a/mock/ext-api-dyson/get/dash-api-xpub.js +++ b/mock/ext-api-dyson/get/dash-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Dash API /// See: /// curl "http://{dash rpc}/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs" -/// curl "http://localhost:3000/dash-api/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs" -/// curl "http://localhost:8420/v1/dash/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD" +/// curl "http://localhost:3347/dash-api/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs" +/// curl "http://localhost:8437/v1/dash/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD" module.exports = { path: '/dash-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/decred-api-address.js b/mock/ext-api-dyson/get/decred-api-address.js index 7696c573a..92301c2fb 100644 --- a/mock/ext-api-dyson/get/decred-api-address.js +++ b/mock/ext-api-dyson/get/decred-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Decred API /// See: /// curl "http://{decred rpc}/api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" -/// curl "http://localhost:3000/decred-api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" -/// curl "http://localhost:8420/v1/decred/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" +/// curl "http://localhost:3347/decred-api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" +/// curl "http://localhost:8437/v1/decred/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" module.exports = { path: '/decred-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/decred-api-xpub.js b/mock/ext-api-dyson/get/decred-api-xpub.js index 914387609..399cdf7cd 100644 --- a/mock/ext-api-dyson/get/decred-api-xpub.js +++ b/mock/ext-api-dyson/get/decred-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Decred API /// See: /// curl "http://{decred rpc}v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs" -/// curl "http://localhost:3000/decred-api/v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs" -/// curl "http://localhost:8420/v1/decred/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN" +/// curl "http://localhost:3347/decred-api/v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs" +/// curl "http://localhost:8437/v1/decred/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN" module.exports = { path: '/decred-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/digibyte-api-address.js b/mock/ext-api-dyson/get/digibyte-api-address.js index fab82b546..b010065d7 100644 --- a/mock/ext-api-dyson/get/digibyte-api-address.js +++ b/mock/ext-api-dyson/get/digibyte-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Digibyte API /// See: /// curl "http://{digibyte rpc}/api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" -/// curl "http://localhost:3000/digibyte-api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" -/// curl "http://localhost:8420/v1/digibyte/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" +/// curl "http://localhost:3347/digibyte-api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" +/// curl "http://localhost:8437/v1/digibyte/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" module.exports = { path: '/digibyte-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/digibyte-api-xpub.js b/mock/ext-api-dyson/get/digibyte-api-xpub.js index a82b7a7c4..fea8f1f4c 100644 --- a/mock/ext-api-dyson/get/digibyte-api-xpub.js +++ b/mock/ext-api-dyson/get/digibyte-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Digibyte API /// See: /// curl "http://{digibyte rpc}/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs" -/// curl "http://localhost:3000/digibyte-api/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs" -/// curl "http://localhost:8420/v1/digibyte/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow" +/// curl "http://localhost:3347/digibyte-api/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs" +/// curl "http://localhost:8437/v1/digibyte/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow" module.exports = { path: '/digibyte-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/doge-api-address.js b/mock/ext-api-dyson/get/doge-api-address.js index 0ee6732c8..cbb40e34f 100644 --- a/mock/ext-api-dyson/get/doge-api-address.js +++ b/mock/ext-api-dyson/get/doge-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Doge API /// See: /// curl "http://{doge rpc}/api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" -/// curl "http://localhost:3000/doge-api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" -/// curl "http://localhost:8420/v1/doge/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" +/// curl "http://localhost:3347/doge-api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" +/// curl "http://localhost:8437/v1/doge/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" module.exports = { path: '/doge-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/doge-api-xpub.js b/mock/ext-api-dyson/get/doge-api-xpub.js index 42b709dd4..c9fd225fb 100644 --- a/mock/ext-api-dyson/get/doge-api-xpub.js +++ b/mock/ext-api-dyson/get/doge-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Doge API /// See: /// curl "http://{doge rpc}/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs" -/// curl "http://localhost:3000/doge-api/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs" -/// curl "http://localhost:8420/v1/doge/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN" +/// curl "http://localhost:3347/doge-api/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs" +/// curl "http://localhost:8437/v1/doge/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN" module.exports = { path: '/doge-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/dyson-ping.js b/mock/ext-api-dyson/get/dyson-ping.js new file mode 100644 index 000000000..604711052 --- /dev/null +++ b/mock/ext-api-dyson/get/dyson-ping.js @@ -0,0 +1,11 @@ +/// Health-check for Dyson + +module.exports = { + path: '/dyson-ping/ping', + template: function(params, query) { + return { + status: true, + msg: 'Dyson is alive' + }; + } +} diff --git a/mock/ext-api-dyson/get/eth-api-commands1.js b/mock/ext-api-dyson/get/eth-api-commands1.js index a97e0f9d9..38a844c6f 100644 --- a/mock/ext-api-dyson/get/eth-api-commands1.js +++ b/mock/ext-api-dyson/get/eth-api-commands1.js @@ -1,11 +1,11 @@ /// Ethereum API Mock /// See: -/// curl "http://localhost:3000/eth-api/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://localhost:3000/eth-api/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://localhost:3347/eth-api/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://localhost:3347/eth-api/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" /// curl "https://{eth rpc}/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" /// curl "https://{eth rpc}/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://localhost:8420/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://localhost:8420/v2/ethereum/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" +/// curl "http://localhost:8437/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://localhost:8437/v2/ethereum/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" module.exports = { path: '/eth-api/:command1?', diff --git a/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js b/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js index 04d4c66a6..4ff105f0a 100644 --- a/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js +++ b/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js @@ -1,11 +1,11 @@ /// Ethereum Blockbook API Mock /// See: -/// curl "http://localhost:3000/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs" -/// curl "http://localhost:3000/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances" +/// curl "http://localhost:3347/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs" +/// curl "http://localhost:3347/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances" /// curl "https://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs" /// curl "https://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances" -/// curl "http://localhost:8420/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://localhost:8420/v2/ethereum/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" +/// curl "http://localhost:8437/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://localhost:8437/v2/ethereum/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" module.exports = { path: '/eth-blockbook-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/ethclassic-api-commands1.js b/mock/ext-api-dyson/get/ethclassic-api-commands1.js index 901719f59..482e00725 100644 --- a/mock/ext-api-dyson/get/ethclassic-api-commands1.js +++ b/mock/ext-api-dyson/get/ethclassic-api-commands1.js @@ -1,11 +1,11 @@ /// Ethereum Classic API Mock /// See: -/// curl "http://localhost:3000/ethclassic-api/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" -/// curl "http://localhost:3000/ethclassic-api/tokens?address=0xa12105efa0663147bddee178f6a741ac15676b79" +/// curl "http://localhost:3347/ethclassic-api/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" +/// curl "http://localhost:3347/ethclassic-api/tokens?address=0xa12105efa0663147bddee178f6a741ac15676b79" /// curl "https://{etc rpc}/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" /// curl "https://{etc rpc}/tokens?address=0xa12105efa0663147bddee178f6a741ac15676b79" -/// curl "http://localhost:8420/v1/ethereumclassic/0x7d2d0e153026fb428b885d86de50768d4cfeac37" -/// curl "http://localhost:8420/v2/classic/tokens/0xa12105efa0663147bddee178f6a741ac15676b79?Authorization=Bearer" +/// curl "http://localhost:8437/v1/ethereumclassic/0x7d2d0e153026fb428b885d86de50768d4cfeac37" +/// curl "http://localhost:8437/v2/classic/tokens/0xa12105efa0663147bddee178f6a741ac15676b79?Authorization=Bearer" module.exports = { path: '/ethclassic-api/:command1?', diff --git a/mock/ext-api-dyson/get/gochain-api-commands1.js b/mock/ext-api-dyson/get/gochain-api-commands1.js index aa4070fad..268fab6a2 100644 --- a/mock/ext-api-dyson/get/gochain-api-commands1.js +++ b/mock/ext-api-dyson/get/gochain-api-commands1.js @@ -1,11 +1,11 @@ /// Gochain API Mock /// See: -/// curl "http://localhost:3000/gochain-api/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" -/// curl "http://localhost:3000/gochain-api/tokens?address=0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628" +/// curl "http://localhost:3347/gochain-api/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" +/// curl "http://localhost:3347/gochain-api/tokens?address=0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628" /// curl "https://{go rpc}/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" /// curl "https://{go rpc}/ -/// curl "http://localhost:8420/v1/gochain/0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" -/// curl "http://localhost:8420/v2/gochain/tokens/0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628?Authorization=Bearer" +/// curl "http://localhost:8437/v1/gochain/0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" +/// curl "http://localhost:8437/v2/gochain/tokens/0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628?Authorization=Bearer" module.exports = { path: '/gochain-api/:command1?', diff --git a/mock/ext-api-dyson/get/groestlcoin-api-address.js b/mock/ext-api-dyson/get/groestlcoin-api-address.js index b552240c0..c82622302 100644 --- a/mock/ext-api-dyson/get/groestlcoin-api-address.js +++ b/mock/ext-api-dyson/get/groestlcoin-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Groestlcoin API /// See: /// curl "http://{groestlcoin rpc}/api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" -/// curl "http://localhost:3000/groestlcoin-api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" -/// curl "http://localhost:8420/v1/groestlcoin/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" +/// curl "http://localhost:3347/groestlcoin-api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" +/// curl "http://localhost:8437/v1/groestlcoin/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" module.exports = { path: '/groestlcoin-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/groestlcoin-api-xpub.js b/mock/ext-api-dyson/get/groestlcoin-api-xpub.js index 4e2160fb4..de299f7c6 100644 --- a/mock/ext-api-dyson/get/groestlcoin-api-xpub.js +++ b/mock/ext-api-dyson/get/groestlcoin-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Groestlcoin API /// See: /// curl "http://{groestlcoin rpc}/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs" -/// curl "http://localhost:3000/groestlcoin-api/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs" -/// curl "http://localhost:8420/v1/groestlcoin/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf" +/// curl "http://localhost:3347/groestlcoin-api/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs" +/// curl "http://localhost:8437/v1/groestlcoin/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf" module.exports = { path: '/groestlcoin-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/icon-api-actions.js b/mock/ext-api-dyson/get/icon-api-actions.js index 4f57cb401..58494d90d 100644 --- a/mock/ext-api-dyson/get/icon-api-actions.js +++ b/mock/ext-api-dyson/get/icon-api-actions.js @@ -1,8 +1,8 @@ /// Icon API Mock /// See: -/// curl "http://localhost:3000/icon-api/address/txList?address=hxee691e7bccc4eb11fee922896e9f51490e62b12e&count=25" +/// curl "http://localhost:3347/icon-api/address/txList?address=hxee691e7bccc4eb11fee922896e9f51490e62b12e&count=25" /// curl "https://tracker.icon.foundation/v3/address/txList?address=hxee691e7bccc4eb11fee922896e9f51490e62b12e&count=25" -/// curl http://localhost:8420/v1/icon/hxee691e7bccc4eb11fee922896e9f51490e62b12e +/// curl http://localhost:8437/v1/icon/hxee691e7bccc4eb11fee922896e9f51490e62b12e module.exports = { path: "/icon-api/address/:action?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/iotex-api-commands2.js b/mock/ext-api-dyson/get/iotex-api-commands2.js index 95c31a92d..2172af297 100644 --- a/mock/ext-api-dyson/get/iotex-api-commands2.js +++ b/mock/ext-api-dyson/get/iotex-api-commands2.js @@ -1,11 +1,11 @@ /// Iotex API Mock /// See: -/// curl "http://localhost:3000/iotex-api/staking/validators?status=bonded" -/// curl "http://localhost:3000/iotex-api/accounts/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" +/// curl "http://localhost:3347/iotex-api/staking/validators?status=bonded" +/// curl "http://localhost:3347/iotex-api/accounts/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" /// curl "https://{iotex_rpc}/v1/staking/validators?status=bonded" /// curl "https://{iotex_rpc}/v1/accounts/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" -/// curl "http://localhost:8420/v2/iotex/staking/validators" -/// curl "http://localhost:8420/v2/iotex/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m?Authorization=Bearer" +/// curl "http://localhost:8437/v2/iotex/staking/validators" +/// curl "http://localhost:8437/v2/iotex/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m?Authorization=Bearer" module.exports = { path: "/iotex-api/:command1/:command2?", diff --git a/mock/ext-api-dyson/get/iotex-api-commands4.js b/mock/ext-api-dyson/get/iotex-api-commands4.js index e8086329c..5aba7f53e 100644 --- a/mock/ext-api-dyson/get/iotex-api-commands4.js +++ b/mock/ext-api-dyson/get/iotex-api-commands4.js @@ -1,8 +1,8 @@ /// Iotex API Mock /// See: -/// curl "http://localhost:3000/iotex-api/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" +/// curl "http://localhost:3347/iotex-api/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" /// curl "https://{iotex_rpc}/v1/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" -/// curl "http://localhost:8420/v2/iotex/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m?Authorization=Bearer" +/// curl "http://localhost:8437/v2/iotex/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m?Authorization=Bearer" module.exports = { path: "/iotex-api/:command1/:command2/:arg3/:arg4?", diff --git a/mock/ext-api-dyson/get/kava-api-commands2.js b/mock/ext-api-dyson/get/kava-api-commands2.js index a55e7c993..3a3f61485 100644 --- a/mock/ext-api-dyson/get/kava-api-commands2.js +++ b/mock/ext-api-dyson/get/kava-api-commands2.js @@ -1,13 +1,13 @@ /// Kava API Mock /// See: -/// curl "http://localhost:3000/kava-api/staking/validators?status=bonded" -/// curl "http://localhost:3000/kava-api/staking/pool" -/// curl "http://localhost:3000/kava-api/minting/inflation" +/// curl "http://localhost:3347/kava-api/staking/validators?status=bonded" +/// curl "http://localhost:3347/kava-api/staking/pool" +/// curl "http://localhost:3347/kava-api/minting/inflation" /// curl "https://{kava_rpc}/staking/validators?status=bonded" /// curl "https://{kava_rpc}/staking/pool" /// curl "https://{kava_rpc}/minting/inflation" -/// curl "http://localhost:8420/v2/kava/staking/validators" -/// curl "http://localhost:8420/v2/kava/staking/delegations/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m?Authorization=Bearer" +/// curl "http://localhost:8437/v2/kava/staking/validators" +/// curl "http://localhost:8437/v2/kava/staking/delegations/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m?Authorization=Bearer" module.exports = { path: "/kava-api/:command1/:command2?", diff --git a/mock/ext-api-dyson/get/kava-api-commands4.js b/mock/ext-api-dyson/get/kava-api-commands4.js index 54c47c963..09a878064 100644 --- a/mock/ext-api-dyson/get/kava-api-commands4.js +++ b/mock/ext-api-dyson/get/kava-api-commands4.js @@ -1,8 +1,8 @@ /// Kava API Mock /// See: -/// curl "http://localhost:3000/kava-api/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/delegations" +/// curl "http://localhost:3347/kava-api/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/delegations" /// curl "https://{kava_rpc}/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/delegations" -/// curl "http://localhost:8420/v2/kava/staking/delegations/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m?Authorization=Bearer" +/// curl "http://localhost:8437/v2/kava/staking/delegations/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m?Authorization=Bearer" module.exports = { path: "/kava-api/:command1/:command2/:arg3/:arg4?", diff --git a/mock/ext-api-dyson/get/kava-api-txs.js b/mock/ext-api-dyson/get/kava-api-txs.js index fb901a3f1..2fc327c9c 100644 --- a/mock/ext-api-dyson/get/kava-api-txs.js +++ b/mock/ext-api-dyson/get/kava-api-txs.js @@ -1,10 +1,10 @@ /// Kava API Mock /// See: -/// curl "http://localhost:3000/kava-api/txs?transfer.recipient=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" -/// curl "http://localhost:3000/kava-api/txs?message.sender=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" +/// curl "http://localhost:3347/kava-api/txs?transfer.recipient=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" +/// curl "http://localhost:3347/kava-api/txs?message.sender=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" /// curl "http://{kava rpc}/txs?transfer.recipient=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" /// curl "http://{kava rpc}/txs?message.sender=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" -/// curl http://localhost:8420/v1/kava/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m +/// curl http://localhost:8437/v1/kava/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m module.exports = { path: "/kava-api/txs?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/kin-api-accounts.js b/mock/ext-api-dyson/get/kin-api-accounts.js index 0ab2d6c1b..8ed0c808b 100644 --- a/mock/ext-api-dyson/get/kin-api-accounts.js +++ b/mock/ext-api-dyson/get/kin-api-accounts.js @@ -1,8 +1,8 @@ /// Kin API Mock, accounts /// See: -/// curl "http://localhost:3000/kin-api/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?order=desc&limit=25" +/// curl "http://localhost:3347/kin-api/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?order=desc&limit=25" /// curl "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?order=desc&limit=25" -/// curl http://localhost:8420/v1/kin/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH +/// curl http://localhost:8437/v1/kin/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH module.exports = { path: "/kin-api/accounts/:address/:operation?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/kin-api-transactions.js b/mock/ext-api-dyson/get/kin-api-transactions.js index 7c989a2b1..34b3d37ad 100644 --- a/mock/ext-api-dyson/get/kin-api-transactions.js +++ b/mock/ext-api-dyson/get/kin-api-transactions.js @@ -1,8 +1,8 @@ /// Kin API Mock, transactions /// See: -/// curl "http://localhost:3000/kin-api/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a?" +/// curl "http://localhost:3347/kin-api/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a?" /// curl "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a?" -/// curl http://localhost:8420/v1/kin/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX +/// curl http://localhost:8437/v1/kin/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX module.exports = { path: "/kin-api/transactions/:txid?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/litecoin-api-address.js b/mock/ext-api-dyson/get/litecoin-api-address.js index 5b2fb0734..63a900e43 100644 --- a/mock/ext-api-dyson/get/litecoin-api-address.js +++ b/mock/ext-api-dyson/get/litecoin-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Litecoin API /// See: /// curl "http://{ltc rpc}/api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" -/// curl "http://localhost:3000/litecoin-api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" -/// curl "http://localhost:8420/v1/litecoin/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" +/// curl "http://localhost:3347/litecoin-api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" +/// curl "http://localhost:8437/v1/litecoin/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" module.exports = { path: '/litecoin-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/litecoin-api-xpub.js b/mock/ext-api-dyson/get/litecoin-api-xpub.js index 66b83d0f5..cbe27e8e3 100644 --- a/mock/ext-api-dyson/get/litecoin-api-xpub.js +++ b/mock/ext-api-dyson/get/litecoin-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Litecoin API /// See: /// curl "http://{ltc rpc}/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs" -/// curl "http://localhost:3000/litecoin-api/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs" -/// curl "http://localhost:8420/v1/litecoin/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu" +/// curl "http://localhost:3347/litecoin-api/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs" +/// curl "http://localhost:8437/v1/litecoin/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu" module.exports = { path: '/litecoin-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/nebulas-api-tx.js b/mock/ext-api-dyson/get/nebulas-api-tx.js index 98b539205..3a990801b 100644 --- a/mock/ext-api-dyson/get/nebulas-api-tx.js +++ b/mock/ext-api-dyson/get/nebulas-api-tx.js @@ -1,8 +1,8 @@ /// Nebulas API Mock /// See: -/// curl "http://localhost:3000/nebulas-api/tx?a=n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a&p=0" +/// curl "http://localhost:3347/nebulas-api/tx?a=n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a&p=0" /// curl "https://explorer-backend.nebulas.io/api/tx?a=n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a&p=0" -/// curl http://localhost:8420/v1/nebulas/n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a +/// curl http://localhost:8437/v1/nebulas/n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a module.exports = { path: "/nebulas-api/tx?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js b/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js index 6770b91b7..59ff4a8f3 100644 --- a/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js +++ b/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js @@ -1,8 +1,8 @@ /// Ontology API Mock /// See: -/// curl "http://localhost:3000/ontology-api/v2/addresses/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7/transactions?page_size=20&page_number=1" +/// curl "http://localhost:3347/ontology-api/v2/addresses/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7/transactions?page_size=20&page_number=1" /// curl "https://explorer.ont.io/v2/addresses/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7/transactions?page_size=20&page_number=1" -/// curl http://localhost:8420/v1/ontology/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7 +/// curl http://localhost:8437/v1/ontology/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7 module.exports = { path: "/ontology-api/v2/addresses/:address/:operation?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/poa-api-commands1.js b/mock/ext-api-dyson/get/poa-api-commands1.js index 773957999..2bb424218 100644 --- a/mock/ext-api-dyson/get/poa-api-commands1.js +++ b/mock/ext-api-dyson/get/poa-api-commands1.js @@ -1,11 +1,11 @@ /// POA API Mock /// See: -/// curl "http://localhost:3000/poa-api/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" -/// curl "http://localhost:3000/poa-api/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +/// curl "http://localhost:3347/poa-api/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" +/// curl "http://localhost:3347/poa-api/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" /// curl "https://{poa rpc}/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" /// curl "https://{poa rpc}/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://localhost:8420/v1/poa/0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" -/// curl "http://localhost:8420/v2/poa/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" +/// curl "http://localhost:8437/v1/poa/0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" +/// curl "http://localhost:8437/v2/poa/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" module.exports = { path: '/poa-api/:command1?', diff --git a/mock/ext-api-dyson/get/qtum-api-address.js b/mock/ext-api-dyson/get/qtum-api-address.js index 80ddb9c15..1ee20d3e2 100644 --- a/mock/ext-api-dyson/get/qtum-api-address.js +++ b/mock/ext-api-dyson/get/qtum-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Qtum API /// See: /// curl "http://{qtum rpc}/api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" -/// curl "http://localhost:3000/qtum-api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" -/// curl "http://localhost:8420/v1/qtum/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" +/// curl "http://localhost:3347/qtum-api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" +/// curl "http://localhost:8437/v1/qtum/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" module.exports = { path: '/qtum-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/qtum-api-xpub.js b/mock/ext-api-dyson/get/qtum-api-xpub.js index 3716dbd4a..8893d2a03 100644 --- a/mock/ext-api-dyson/get/qtum-api-xpub.js +++ b/mock/ext-api-dyson/get/qtum-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Qtum API /// See: /// curl "http://{qtum rpc}/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs" -/// curl "http://localhost:3000/qtum-api/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs" -/// curl "http://localhost:8420/v1/qtum/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd" +/// curl "http://localhost:3347/qtum-api/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs" +/// curl "http://localhost:8437/v1/qtum/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd" module.exports = { path: '/qtum-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/ravencoin-api-address.js b/mock/ext-api-dyson/get/ravencoin-api-address.js index cff216ec1..b6bd59d37 100644 --- a/mock/ext-api-dyson/get/ravencoin-api-address.js +++ b/mock/ext-api-dyson/get/ravencoin-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Ravencoin API /// See: /// curl "http://{Ravencoin rpc}/api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs" -/// curl "http://localhost:3000/ravencoin-api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs" -/// curl "http://localhost:8420/v1/ravencoin/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo" +/// curl "http://localhost:3347/ravencoin-api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs" +/// curl "http://localhost:8437/v1/ravencoin/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo" module.exports = { path: '/ravencoin-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/ravencoin-api-xpub.js b/mock/ext-api-dyson/get/ravencoin-api-xpub.js index 207ee7599..f7ef19629 100644 --- a/mock/ext-api-dyson/get/ravencoin-api-xpub.js +++ b/mock/ext-api-dyson/get/ravencoin-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Ravencoin API /// See: /// curl "http://{Ravencoin rpc}/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs" -/// curl "http://localhost:3000/ravencoin-api/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs" -/// curl "http://localhost:8420/v1/ravencoin/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B" +/// curl "http://localhost:3347/ravencoin-api/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs" +/// curl "http://localhost:8437/v1/ravencoin/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B" module.exports = { path: '/ravencoin-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/ripple-get-accounts.js b/mock/ext-api-dyson/get/ripple-get-accounts.js index ba5680618..11ec2dc72 100644 --- a/mock/ext-api-dyson/get/ripple-get-accounts.js +++ b/mock/ext-api-dyson/get/ripple-get-accounts.js @@ -1,8 +1,8 @@ /// Ripple API Mock /// See: -/// curl "http://localhost:3000/ripple-api/accounts/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1/transactions?type=Payment&descending=false&limit=25" +/// curl "http://localhost:3347/ripple-api/accounts/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1/transactions?type=Payment&descending=false&limit=25" /// curl "https://data.ripple.com/v2/accounts/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1/transactions?type=Payment&descending=false&limit=25" -/// curl http://localhost:8420/v1/ripple/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1 +/// curl http://localhost:8437/v1/ripple/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1 module.exports = { path: "/ripple-api/accounts/:address/transactions?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/stellar-api-accounts.js b/mock/ext-api-dyson/get/stellar-api-accounts.js index b8e5543cc..6432dd67e 100644 --- a/mock/ext-api-dyson/get/stellar-api-accounts.js +++ b/mock/ext-api-dyson/get/stellar-api-accounts.js @@ -1,8 +1,8 @@ /// Stellar API Mock, accounts /// See: -/// curl "http://localhost:3000/stellar-api/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?order=desc&limit=25" +/// curl "http://localhost:3347/stellar-api/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?order=desc&limit=25" /// curl "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?order=desc&limit=25" -/// curl http://localhost:8420/v1/stellar/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX +/// curl http://localhost:8437/v1/stellar/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX module.exports = { path: "/stellar-api/accounts/:address/:operation?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/stellar-api-transactions.js b/mock/ext-api-dyson/get/stellar-api-transactions.js index 90b1f5036..3597a7864 100644 --- a/mock/ext-api-dyson/get/stellar-api-transactions.js +++ b/mock/ext-api-dyson/get/stellar-api-transactions.js @@ -1,8 +1,8 @@ /// Stellar API Mock, transactions /// See: -/// curl "http://localhost:3000/stellar-api/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029?" +/// curl "http://localhost:3347/stellar-api/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029?" /// curl "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029?" -/// curl http://localhost:8420/v1/stellar/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX +/// curl http://localhost:8437/v1/stellar/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX module.exports = { path: "/stellar-api/transactions/:txid?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/tezos-api-transactions.js b/mock/ext-api-dyson/get/tezos-api-transactions.js index dd7889358..2d7c25bc4 100644 --- a/mock/ext-api-dyson/get/tezos-api-transactions.js +++ b/mock/ext-api-dyson/get/tezos-api-transactions.js @@ -1,8 +1,8 @@ /// Mock for external Tezos API, transactions /// See /// curl "https://api.tzstats.com/explorer/account/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8/op?limit=25&order=desc&type=transaction%2Cdelegation" -/// curl "http://localhost:3000/tezos-api/account/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8/op?limit=25&order=desc&type=transaction%2Cdelegation" -/// curl "http://localhost:8420/v1/tezos/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" +/// curl "http://localhost:3347/tezos-api/account/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8/op?limit=25&order=desc&type=transaction%2Cdelegation" +/// curl "http://localhost:8437/v1/tezos/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" module.exports = { path: '/tezos-api/account/:account/:op?', diff --git a/mock/ext-api-dyson/get/theta-api-accounttx.js b/mock/ext-api-dyson/get/theta-api-accounttx.js index 13df717fb..633266650 100644 --- a/mock/ext-api-dyson/get/theta-api-accounttx.js +++ b/mock/ext-api-dyson/get/theta-api-accounttx.js @@ -1,8 +1,8 @@ /// Theta API Mock /// See: -/// curl "http://localhost:3000/theta-api/accounttx/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f?type=2&pageNumber=1&limitNumber=100&isEqualType=true" +/// curl "http://localhost:3347/theta-api/accounttx/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f?type=2&pageNumber=1&limitNumber=100&isEqualType=true" /// curl "https://explorer.thetatoken.org:9000/api/accounttx/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f?type=2&pageNumber=1&limitNumber=100&isEqualType=true" -/// curl http://localhost:8420/v1/theta/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f +/// curl http://localhost:8437/v1/theta/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f module.exports = { path: "/theta-api/accounttx/:address?", template: function(params, query, body) { diff --git a/mock/ext-api-dyson/get/thundertoken-api-commands1.js b/mock/ext-api-dyson/get/thundertoken-api-commands1.js index bf81b3656..b6cdbb654 100644 --- a/mock/ext-api-dyson/get/thundertoken-api-commands1.js +++ b/mock/ext-api-dyson/get/thundertoken-api-commands1.js @@ -1,11 +1,11 @@ /// Thundertoken API Mock /// See: -/// curl "http://localhost:3000/thundertoken-api/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" -/// curl "http://localhost:3000/thundertoken-api/tokens?address=0x0b230def08139f18a86536d9cfa150f04435414c" +/// curl "http://localhost:3347/thundertoken-api/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" +/// curl "http://localhost:3347/thundertoken-api/tokens?address=0x0b230def08139f18a86536d9cfa150f04435414c" /// curl "https://{Thundertoken rpc}/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" /// curl "https://{Thundertoken rpc}/tokens?address=0x0b230def08139f18a86536d9cfa150f04435414c" -/// curl "http://localhost:8420/v1/thundertoken/0x0b230def08139f18a86536d9cfa150f04435414c" -/// curl "http://localhost:8420/v2/thundertoken/tokens/0x0b230def08139f18a86536d9cfa150f04435414c?Authorization=Bearer" +/// curl "http://localhost:8437/v1/thundertoken/0x0b230def08139f18a86536d9cfa150f04435414c" +/// curl "http://localhost:8437/v2/thundertoken/tokens/0x0b230def08139f18a86536d9cfa150f04435414c?Authorization=Bearer" module.exports = { path: '/thundertoken-api/:command1?', diff --git a/mock/ext-api-dyson/get/tomochain-api-commands1.js b/mock/ext-api-dyson/get/tomochain-api-commands1.js index c1526c87e..3f5054b2c 100644 --- a/mock/ext-api-dyson/get/tomochain-api-commands1.js +++ b/mock/ext-api-dyson/get/tomochain-api-commands1.js @@ -1,11 +1,11 @@ /// Tomochain API Mock /// See: -/// curl "http://localhost:3000/tomochain-api/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" -/// curl "http://localhost:3000/tomochain-api/tokens?address=0x8b353021189375591723e7384262f45709a3c3dc" +/// curl "http://localhost:3347/tomochain-api/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" +/// curl "http://localhost:3347/tomochain-api/tokens?address=0x8b353021189375591723e7384262f45709a3c3dc" /// curl "https://{Tomochain rpc}/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" /// curl "https://{Tomochain rpc}/tokens?address=0x8b353021189375591723e7384262f45709a3c3dc" -/// curl "http://localhost:8420/v1/tomochain/0x17e4c16605e32adead5fa371bf6117df34ca0200" -/// curl "http://localhost:8420/v2/tomochain/tokens/0x8b353021189375591723e7384262f45709a3c3dc?Authorization=Bearer" +/// curl "http://localhost:8437/v1/tomochain/0x17e4c16605e32adead5fa371bf6117df34ca0200" +/// curl "http://localhost:8437/v2/tomochain/tokens/0x8b353021189375591723e7384262f45709a3c3dc?Authorization=Bearer" module.exports = { path: '/tomochain-api/:command1?', diff --git a/mock/ext-api-dyson/get/tron-api-v1-accounts.js b/mock/ext-api-dyson/get/tron-api-v1-accounts.js index dd814ff7c..d57d81719 100644 --- a/mock/ext-api-dyson/get/tron-api-v1-accounts.js +++ b/mock/ext-api-dyson/get/tron-api-v1-accounts.js @@ -1,11 +1,11 @@ /// Tron API Mock /// See: -/// curl "http://localhost:3000/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?token_id=&limit=25&order_by=block_timestamp,desc" -/// curl "http://localhost:3000/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" +/// curl "http://localhost:3347/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?token_id=&limit=25&order_by=block_timestamp,desc" +/// curl "http://localhost:3347/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" /// curl "http://{Tron rpc}/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?token_id=&limit=25&order_by=block_timestamp,desc" /// curl "http://{Tron rpc}/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" -/// curl "http://localhost:8420/v1/tron/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" -/// curl "http://localhost:8420/v2/tron/tokens/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB?Authorization=Bearer" +/// curl "http://localhost:8437/v1/tron/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" +/// curl "http://localhost:8437/v2/tron/tokens/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB?Authorization=Bearer" module.exports = { path: "/tron-api/v1/accounts/:address/:operation?", diff --git a/mock/ext-api-dyson/get/tron-api-v1-assets.js b/mock/ext-api-dyson/get/tron-api-v1-assets.js index 8bcfa706c..e476c4ae7 100644 --- a/mock/ext-api-dyson/get/tron-api-v1-assets.js +++ b/mock/ext-api-dyson/get/tron-api-v1-assets.js @@ -1,8 +1,8 @@ /// Tron API Mock /// See: -/// curl "http://localhost:3000/tron-api/v1/assets/1002798" +/// curl "http://localhost:3347/tron-api/v1/assets/1002798" /// curl "https://{tron_rpc}/v1/assets/1002798" -/// curl "http://localhost:8420/v2/tron/tokens/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB?Authorization=Bearer" +/// curl "http://localhost:8437/v2/tron/tokens/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB?Authorization=Bearer" module.exports = { path: "/tron-api/v1/assets/:arg2?", diff --git a/mock/ext-api-dyson/get/tron-api-wallet.js b/mock/ext-api-dyson/get/tron-api-wallet.js index ca58d75d9..099836d9c 100644 --- a/mock/ext-api-dyson/get/tron-api-wallet.js +++ b/mock/ext-api-dyson/get/tron-api-wallet.js @@ -1,7 +1,7 @@ /// Tron API Mock /// See: -/// curl http://localhost:3000/tron-api/wallet/listwitnesses -/// curl http://localhost:8420/v2/tron/staking/validators +/// curl http://localhost:3347/tron-api/wallet/listwitnesses +/// curl http://localhost:8437/v2/tron/staking/validators module.exports = { path: "/tron-api/wallet/:operation?", diff --git a/mock/ext-api-dyson/get/unstoppabledomains-lookup.js b/mock/ext-api-dyson/get/unstoppabledomains-lookup.js index e03008864..e0168f642 100644 --- a/mock/ext-api-dyson/get/unstoppabledomains-lookup.js +++ b/mock/ext-api-dyson/get/unstoppabledomains-lookup.js @@ -4,9 +4,9 @@ /// - public address for certain name and coin combinations /// - public address not found message for other input /// See: -/// curl "http://localhost:3000/unstoppabledomains/api/v1//dpantani.zil" +/// curl "http://localhost:3347/unstoppabledomains/api/v1//dpantani.zil" /// curl "https://unstoppabledomains.com/api/v1/dpantani.zil" -/// curl "http://localhost:8420/v2/ns/lookup?name=dpantani.zil&coins=313" +/// curl "http://localhost:8437/v2/ns/lookup?name=dpantani.zil&coins=313" module.exports = { path: '/unstoppabledomains/api/v1//:name?', diff --git a/mock/ext-api-dyson/get/vechain-api-entities.js b/mock/ext-api-dyson/get/vechain-api-entities.js index 531a260fa..691a5ff00 100644 --- a/mock/ext-api-dyson/get/vechain-api-entities.js +++ b/mock/ext-api-dyson/get/vechain-api-entities.js @@ -2,9 +2,9 @@ /// See /// curl https://vethor-pubnode.digonchain.com/blocks/best /// curl https://vethor-pubnode.digonchain.com/transactions/0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7 -/// curl http://localhost:3000/vechain-api/blocks/best -/// curl http://localhost:3000/vechain-api/transactions/0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7 -/// curl "http://localhost:8420/v1/vechain/0xB5e883349e68aB59307d1604555AC890fAC47128" +/// curl http://localhost:3347/vechain-api/blocks/best +/// curl http://localhost:3347/vechain-api/transactions/0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7 +/// curl "http://localhost:8437/v1/vechain/0xB5e883349e68aB59307d1604555AC890fAC47128" module.exports = { path: '/vechain-api/:entity/:id?', diff --git a/mock/ext-api-dyson/get/viacoin-api-address.js b/mock/ext-api-dyson/get/viacoin-api-address.js index 2c0d736bb..be045dc72 100644 --- a/mock/ext-api-dyson/get/viacoin-api-address.js +++ b/mock/ext-api-dyson/get/viacoin-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Viacoin API /// See: /// curl "http://{Viacoin rpc}/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" -/// curl "http://localhost:3000/viacoin-api/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" -/// curl "http://localhost:8420/v1/viacoin/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" +/// curl "http://localhost:3347/viacoin-api/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" +/// curl "http://localhost:8437/v1/viacoin/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" module.exports = { path: '/viacoin-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/viacoin-api-xpub.js b/mock/ext-api-dyson/get/viacoin-api-xpub.js index 4dbcb38cd..81906bf00 100644 --- a/mock/ext-api-dyson/get/viacoin-api-xpub.js +++ b/mock/ext-api-dyson/get/viacoin-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Viacoin API /// See: /// curl "http://{Viacoin rpc}/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs" -/// curl "http://localhost:3000/viacoin-api/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs" -/// curl "http://localhost:8420/v1/viacoin/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK" +/// curl "http://localhost:3347/viacoin-api/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs" +/// curl "http://localhost:8437/v1/viacoin/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK" module.exports = { path: '/viacoin-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/waves-api-transactions-address.js b/mock/ext-api-dyson/get/waves-api-transactions-address.js index e797120fd..c2756b7c3 100644 --- a/mock/ext-api-dyson/get/waves-api-transactions-address.js +++ b/mock/ext-api-dyson/get/waves-api-transactions-address.js @@ -1,8 +1,8 @@ /// Waves API Mock /// See: -/// curl "http://localhost:3000/waves-api/transactions/address/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD/limit/25" +/// curl "http://localhost:3347/waves-api/transactions/address/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD/limit/25" /// curl "https://nodes.wavesnodes.com/transactions/address/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD/limit/25" -/// curl http://localhost:8420/v1/waves/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD +/// curl http://localhost:8437/v1/waves/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD module.exports = { path: "/waves-api/transactions/address/:address/limit/:limit", template: function (params, query, body) { diff --git a/mock/ext-api-dyson/get/zcash-api-address.js b/mock/ext-api-dyson/get/zcash-api-address.js index 1c9109039..637c6d853 100644 --- a/mock/ext-api-dyson/get/zcash-api-address.js +++ b/mock/ext-api-dyson/get/zcash-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Zcash API /// See: /// curl "http://{Zcash rpc}/api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" -/// curl "http://localhost:3000/zcash-api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" -/// curl "http://localhost:8420/v1/zcash/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" +/// curl "http://localhost:3347/zcash-api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" +/// curl "http://localhost:8437/v1/zcash/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" module.exports = { path: '/zcash-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/zcash-api-xpub.js b/mock/ext-api-dyson/get/zcash-api-xpub.js index c18f35d5d..84612673a 100644 --- a/mock/ext-api-dyson/get/zcash-api-xpub.js +++ b/mock/ext-api-dyson/get/zcash-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Zcash API /// See: /// curl "http://{Zcash rpc}/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs" -/// curl "http://localhost:3000/zcash-api/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs" -/// curl "http://localhost:8420/v1/zcash/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS" +/// curl "http://localhost:3347/zcash-api/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs" +/// curl "http://localhost:8437/v1/zcash/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS" module.exports = { path: '/zcash-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/zcoin-api-address.js b/mock/ext-api-dyson/get/zcoin-api-address.js index 27af44520..9257ac3b8 100644 --- a/mock/ext-api-dyson/get/zcoin-api-address.js +++ b/mock/ext-api-dyson/get/zcoin-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Zcoin API /// See: /// curl "http://{Zcoin rpc}/api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" -/// curl "http://localhost:3000/zcoin-api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" -/// curl "http://localhost:8420/v1/zcoin/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" +/// curl "http://localhost:3347/zcoin-api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" +/// curl "http://localhost:8437/v1/zcoin/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" module.exports = { path: '/zcoin-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/zcoin-api-xpub.js b/mock/ext-api-dyson/get/zcoin-api-xpub.js index 06dca4723..0fe98efda 100644 --- a/mock/ext-api-dyson/get/zcoin-api-xpub.js +++ b/mock/ext-api-dyson/get/zcoin-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Zcoin API /// See: /// curl "http://{Zcoin rpc}/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs" -/// curl "http://localhost:3000/zcoin-api/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs" -/// curl "http://localhost:8420/v1/zcoin/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK" +/// curl "http://localhost:3347/zcoin-api/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs" +/// curl "http://localhost:8437/v1/zcoin/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK" module.exports = { path: '/zcoin-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/zelcash-api-address.js b/mock/ext-api-dyson/get/zelcash-api-address.js index ae21ca2f3..a8e3bd4bd 100644 --- a/mock/ext-api-dyson/get/zelcash-api-address.js +++ b/mock/ext-api-dyson/get/zelcash-api-address.js @@ -1,8 +1,8 @@ /// Mock for external Zelcash API /// See: /// curl "http://{Zelcash rpc}/api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs&pageSize=25" -/// curl "http://localhost:3000/zelcash-api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs" -/// curl "http://localhost:8420/v1/zelcash/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" +/// curl "http://localhost:3347/zelcash-api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs" +/// curl "http://localhost:8437/v1/zelcash/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" module.exports = { path: '/zelcash-api/v2/address/:address?', diff --git a/mock/ext-api-dyson/get/zelcash-api-xpub.js b/mock/ext-api-dyson/get/zelcash-api-xpub.js index c1b3e53bd..62f932ce7 100644 --- a/mock/ext-api-dyson/get/zelcash-api-xpub.js +++ b/mock/ext-api-dyson/get/zelcash-api-xpub.js @@ -1,8 +1,8 @@ /// Mock for external Zelcash API /// See: /// curl "http://{Zelcash rpc}/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs" -/// curl "http://localhost:3000/zelcash-api/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs" -/// curl "http://localhost:8420/v1/zelcash/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf" +/// curl "http://localhost:3347/zelcash-api/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs" +/// curl "http://localhost:8437/v1/zelcash/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf" module.exports = { path: '/zelcash-api/v2/xpub/:xpubkey?', diff --git a/mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js b/mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js index 58273206a..ae84e9283 100644 --- a/mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js +++ b/mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js @@ -1,8 +1,8 @@ /// Mock for external Zilliqa API /// See: /// curl -H "X-APIKEY: YOUR_API_KEY" "https://api.viewblock.io/v1/zilliqa/addresses/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z/txs" -/// curl "http://localhost:3000/zilliqa-api/addresses/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z/txs" -/// curl "http://localhost:8420/v1/zilliqa/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z" +/// curl "http://localhost:3347/zilliqa-api/addresses/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z/txs" +/// curl "http://localhost:8437/v1/zilliqa/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z" module.exports = { path: '/zilliqa-api/addresses/:address/txs', diff --git a/mock/ext-api-dyson/post/eth-rpc.js b/mock/ext-api-dyson/post/eth-rpc.js index 68a603f70..62ba4a0be 100644 --- a/mock/ext-api-dyson/post/eth-rpc.js +++ b/mock/ext-api-dyson/post/eth-rpc.js @@ -1,7 +1,7 @@ /// ETH RPC API Mock /// See: -/// curl -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":2,"method":"eth_call","params":[{"data":"0x02571be3ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835","from":"0x0000000000000000000000000000000000000000","to":"0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e"},"latest"]}' http://localhost:3000/eth-rpc -/// curl "http://localhost:8420/v2/ns/lookup?name=vitalik.eth&coins=60" +/// curl -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":2,"method":"eth_call","params":[{"data":"0x02571be3ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835","from":"0x0000000000000000000000000000000000000000","to":"0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e"},"latest"]}' http://localhost:3347/eth-rpc +/// curl "http://localhost:8437/v2/ns/lookup?name=vitalik.eth&coins=60" module.exports = { path: '/eth-rpc', diff --git a/mock/ext-api-dyson/post/fio-api-chain.js b/mock/ext-api-dyson/post/fio-api-chain.js index 3a9903962..7f0c32cd5 100644 --- a/mock/ext-api-dyson/post/fio-api-chain.js +++ b/mock/ext-api-dyson/post/fio-api-chain.js @@ -3,9 +3,9 @@ /// - public address for certain fio name and coin combinations /// - public address not found message for other input /// See: -/// curl -H "Content-Type: application/json" -d '{"fio_address":"trust@trust","token_code":"BTC","chain_code":"BTC"}' "http://localhost:3000/fio-api/v1/chain/get_pub_address" +/// curl -H "Content-Type: application/json" -d '{"fio_address":"trust@trust","token_code":"BTC","chain_code":"BTC"}' "http://localhost:3347/fio-api/v1/chain/get_pub_address" /// curl -H "Content-Type: application/json" -d '{"fio_address":"trust@trust","token_code":"BTC","chain_code":"BTC"}' "http://testnet.fioprotocol.io/v1/chain/get_pub_address" -/// curl "http://localhost:8420/v2/ns/lookup?name=trust@trust&coins=60" +/// curl "http://localhost:8437/v2/ns/lookup?name=trust@trust&coins=60" module.exports = { path: '/fio-api/v1/chain/:action', diff --git a/mock/ext-api-dyson/post/fio-api-history.js b/mock/ext-api-dyson/post/fio-api-history.js index a96cae5fd..fdbbb0b05 100644 --- a/mock/ext-api-dyson/post/fio-api-history.js +++ b/mock/ext-api-dyson/post/fio-api-history.js @@ -1,7 +1,7 @@ /// FIO RPC API Mock, history API /// curl -H "Content-Type: application/json" -d '{"account_name": "ezsmbcy2opod"}' https://fio.greymass.com/v1/history/get_actions -/// curl -H "Content-Type: application/json" -d '{"account_name": "ezsmbcy2opod"}' http://localhost:3000/fio-api/v1/history/get_actions -/// curl "http://localhost:8420/v1/fio/FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt" +/// curl -H "Content-Type: application/json" -d '{"account_name": "ezsmbcy2opod"}' http://localhost:3347/fio-api/v1/history/get_actions +/// curl "http://localhost:8437/v1/fio/FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt" module.exports = { path: '/fio-api/v1/history/:action', diff --git a/mock/ext-api-dyson/post/harmony-api.js b/mock/ext-api-dyson/post/harmony-api.js index 149b827aa..d61797ef4 100644 --- a/mock/ext-api-dyson/post/harmony-api.js +++ b/mock/ext-api-dyson/post/harmony-api.js @@ -1,7 +1,7 @@ /// Harmony RPC Mock -/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":1} ' http://localhost:3000/harmony-api +/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":1} ' http://localhost:3347/harmony-api /// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":1} ' https://{harmony_rpc} -/// curl "http://localhost:8420/v2/harmony/one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv" +/// curl "http://localhost:8437/v2/harmony/one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv" module.exports = { path: '/harmony-api', diff --git a/mock/ext-api-dyson/post/kusama-api.js b/mock/ext-api-dyson/post/kusama-api.js index 426f7f74b..6d3112ddd 100644 --- a/mock/ext-api-dyson/post/kusama-api.js +++ b/mock/ext-api-dyson/post/kusama-api.js @@ -1,8 +1,8 @@ /// Kusama RPC API Mock /// See: /// curl -H "Content-Type: application/json" -d '{"address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", "row": 25}' https://kusama.subscan.io/api/scan/transfers -/// curl -H "Content-Type: application/json" -d '{"address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", "row": 25}' http://localhost:3000/kusama-rpc/scan/transfers -/// curl "http://localhost:8420/v1/kusama/HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK" +/// curl -H "Content-Type: application/json" -d '{"address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", "row": 25}' http://localhost:3347/kusama-rpc/scan/transfers +/// curl "http://localhost:8437/v1/kusama/HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK" module.exports = { path: '/kusama-rpc/scan/transfers', diff --git a/mock/ext-api-dyson/post/nano-api.js b/mock/ext-api-dyson/post/nano-api.js index a65af1bd5..cc36cb391 100644 --- a/mock/ext-api-dyson/post/nano-api.js +++ b/mock/ext-api-dyson/post/nano-api.js @@ -1,7 +1,7 @@ /// Nano RPC Mock -/// curl -H 'Content-Type: application/json' -d ' {"action":"account_history","account":"nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z","count":"25"} ' http://localhost:3000/nano-api +/// curl -H 'Content-Type: application/json' -d ' {"action":"account_history","account":"nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z","count":"25"} ' http://localhost:3347/nano-api /// curl -H 'Content-Type: application/json' -d ' {"action":"account_history","account":"nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z","count":"25"} ' https://{nano_rpc} -/// curl "http://localhost:8420/v1/nano/nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z" +/// curl "http://localhost:8437/v1/nano/nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z" module.exports = { path: '/nano-api', diff --git a/mock/ext-api-dyson/post/nimiq-rpc.js b/mock/ext-api-dyson/post/nimiq-rpc.js index 08e70f00e..18a42afb8 100644 --- a/mock/ext-api-dyson/post/nimiq-rpc.js +++ b/mock/ext-api-dyson/post/nimiq-rpc.js @@ -1,8 +1,8 @@ /// Nimiq RPC API Mock /// See: /// curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "getTransactionsByAddress", "params": [ "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", "25" ], "id": "getTransactionsByAddress"}' https://{nimiq_rpc} -/// curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "getTransactionsByAddress", "params": [ "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", "25" ], "id": "getTransactionsByAddress"}' http://localhost:3000/nimiq-rpc -/// curl "http://localhost:8420/v1/nimiq/NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07" +/// curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "getTransactionsByAddress", "params": [ "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", "25" ], "id": "getTransactionsByAddress"}' http://localhost:3347/nimiq-rpc +/// curl "http://localhost:8437/v1/nimiq/NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07" module.exports = { path: '/nimiq-rpc', diff --git a/mock/ext-api-dyson/post/tron-api-wallet.js b/mock/ext-api-dyson/post/tron-api-wallet.js index bc2a8a533..d897760d9 100644 --- a/mock/ext-api-dyson/post/tron-api-wallet.js +++ b/mock/ext-api-dyson/post/tron-api-wallet.js @@ -1,7 +1,7 @@ /// Tron API Mock /// See: -/// curl http://localhost:3000/tron-api/wallet/listwitnesses -/// curl http://localhost:8420/v2/tron/staking/validators +/// curl http://localhost:3347/tron-api/wallet/listwitnesses +/// curl http://localhost:8437/v2/tron/staking/validators module.exports = { path: "/tron-api/wallet/:operation", diff --git a/mock/ext-api-dyson/post/vechain-api-logs.js b/mock/ext-api-dyson/post/vechain-api-logs.js index 2f4ca51ce..0be3129d2 100644 --- a/mock/ext-api-dyson/post/vechain-api-logs.js +++ b/mock/ext-api-dyson/post/vechain-api-logs.js @@ -1,8 +1,8 @@ /// Vechain RPC API Mock /// See: /// curl -H "Content-Type: application/json" -d '{"options": {"offset": 0, "limit": 15 }, "criteriaSet": [{"sender": "0xB5e883349e68aB59307d1604555AC890fAC47128"},{"recipient": "0xB5e883349e68aB59307d1604555AC890fAC47128"}], "range": {"unit": "block", "from": 0, "to": 5466405 }, "order": "desc"}' https://vethor-pubnode.digonchain.com/logs/transfer -/// curl -H "Content-Type: application/json" -d '{"options": {"offset": 0, "limit": 15 }, "criteriaSet": [{"sender": "0xB5e883349e68aB59307d1604555AC890fAC47128"},{"recipient": "0xB5e883349e68aB59307d1604555AC890fAC47128"}], "range": {"unit": "block", "from": 0, "to": 5466405 }, "order": "desc"}' http://localhost:3000/vechain-api/logs/transfer -/// curl "http://localhost:8420/v1/vechain/0xB5e883349e68aB59307d1604555AC890fAC47128" +/// curl -H "Content-Type: application/json" -d '{"options": {"offset": 0, "limit": 15 }, "criteriaSet": [{"sender": "0xB5e883349e68aB59307d1604555AC890fAC47128"},{"recipient": "0xB5e883349e68aB59307d1604555AC890fAC47128"}], "range": {"unit": "block", "from": 0, "to": 5466405 }, "order": "desc"}' http://localhost:3347/vechain-api/logs/transfer +/// curl "http://localhost:8437/v1/vechain/0xB5e883349e68aB59307d1604555AC890fAC47128" module.exports = { path: '/vechain-api/logs/:entity', diff --git a/tests/postman/blockatlas.postman_collection.json b/tests/postman/blockatlas.postman_collection.json index 48af4a341..c023db8f2 100644 --- a/tests/postman/blockatlas.postman_collection.json +++ b/tests/postman/blockatlas.postman_collection.json @@ -2020,6 +2020,97 @@ } ], "protocolProfileBehavior": {} + }, + { + "name": "mock-healthcheck", + "item": [ + { + "name": "status", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "7312c9e7-5330-421a-9ca8-171101050e38", + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "acec8baa-0ef0-4703-ab83-c555260deffa", + "exec": [ + "var Ajv = require('ajv');", + "var ajv = new Ajv({logger: console});", + "let schema = {", + " \"status\": \"boolean\",", + " \"msg\": \"string\"", + "};", + "", + "pm.test(\"response must be valid and have a body -- HAS MOCK STARTED?\", function () {", + " pm.response.to.have.status(200);", + " pm.response.to.be.ok;", + " pm.response.to.not.be.error;", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "", + "var jsonData = pm.response.json();", + "", + "pm.test(\"verify the status\", function() {", + " pm.expect(jsonData.status).to.equal(true);", + "});", + "", + "pm.test(\"schema is valid\", function() {", + " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "localhost:3347/dyson-ping/ping", + "host": [ + "localhost:3347" + ], + "path": [ + "dyson-ping/ping" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "2f430d33-58dd-4df5-b3bb-2826e76b89b2", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "727ab826-5939-45a7-96be-d8382192a69e", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "protocolProfileBehavior": {} } ], "event": [ diff --git a/tests/postman/mock-healthcheck_data.json b/tests/postman/mock-healthcheck_data.json new file mode 100644 index 000000000..da1a058a9 --- /dev/null +++ b/tests/postman/mock-healthcheck_data.json @@ -0,0 +1,4 @@ +[ + { + } +] From 3166b3c5dcda62792f24f61f2424ece67eda7fe5 Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Wed, 29 Apr 2020 12:19:29 -0700 Subject: [PATCH 269/506] WIP Change platform default (#1064) * Change platform default * Init readme update * Update readme, fix typos. * remove tips --- README.md | 95 ++++++++++++++++++++++++++---------------------------- config.yml | 2 +- 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 2d9dd7f82..f1681f0fa 100644 --- a/README.md +++ b/README.md @@ -40,13 +40,13 @@ The observer API watches the chain for new transactions and generates notificati ## Architecture #### NOTE -Currently Blockatlas is under active development and is not well documented. If you still want to run it on your own or help to contribute, **please** pay attention that currenlty integration, nemwan, functional tests are not working locally without all endpoints. We are fixing that issue and soon you will be able to test all the stuff locally +Currently Block Atlas is under active development and is not well documented. If you still want to run it on your own or help to contribute, **please** pay attention that currently integration, nemwan, functional tests are not working locally without all endpoints. We are fixing that issue and soon you will be able to test all the stuff locally Blockatlas allows to: - Get information about transactions, tokens, staking details, collectibles, crypto domains for supported coins. - Subscribe for price notifications via Rabbit MQ -Platform API is independent service and can work with the specific blockchain only (like bitcoin, ethereum, etc) +Platform API is independent service and can work with the specific blockchain only (like Bitcoin, Ethereum, etc) Notifications: @@ -67,45 +67,43 @@ New Subscriptions --(Rabbit MQ)--> Subscriber --> DB ``` -The whole flow is not availible at Atlas repo. We will have integration tests with it. Also there will be examples of all instances soon. +The whole flow is not available at Atlas repo. We will have integration tests with it. Also there will be examples of all instances soon. ## Setup -### Requirements +### Prerequisite + * [Go Toolchain](https://golang.org/doc/install) versions 1.14+ + + Depends on what type of Blockatlas service you would like to run will also be needed. + * [Postgres](https://www.postgresql.org/download) to store user subscriptions and latest parsed block number + * [Rabbit MQ](https://www.rabbitmq.com/#getstarted) to pass subscriptions and send transaction notifications - * [Go Toolchain](https://golang.org/doc/install) versions 1.13+ - * [Postgres](https://www.postgresql.org/download) storing user subscriptions and latest parsed block number - * [Rabbit MQ](https://www.rabbitmq.com/#getstarted) using to pass subscriptions and send transaction notifications +### Quick Start -### From Source +#### Get source code -#### IMPORTANT - -You can run platform API for specific coin only! +Download source to `GOPATH` ```shell -cd cmd/platform_api -ATLAS_PLATFORM=ethereum go run main.go +go get -u github.com/trustwallet/blockatlas +cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas ``` -You will run platform API for Ethereum coin only. You can run 30 coins with 30 binaries for scalability and sustainability. Howevever, you can run all of them at once by using ```ATLAS_PLATFORM=all``` env param -It works the same for observer_worker - you can run all observer at 1 binary or 30 coins per 30 binaries +#### Build and run -```shell -# Download source to $GOPATH -go get -u github.com/trustwallet/blockatlas -cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas +Read [configuration](#configuration) info -# Start Platform API server at port 8420 with the path to the config.yml ./ -go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 -c config.yml +```shell +# Start Platform API server at port 8420 with the path to the config.yml ./ +go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 # Start observer_parser with the path to the config.yml ./ -go build -o observer_parser-bin cmd/observer_parser/main.go && ./observer_parser-bin -c config.yml +go build -o observer_parser-bin cmd/observer_parser/main.go && ./observer_parser-bin # Start observer_notifier with the path to the config.yml ./ -go build -o observer_notifier-bin cmd/observer_notifier/main.go && ./observer_notifier-bin -c config.yml +go build -o observer_notifier-bin cmd/observer_notifier/main.go && ./observer_notifier-bin # Start observer_subscriber with the path to the config.yml ./ -go build -o observer_subscriber-bin cmd/observer_subscriber/main.go && ./observer_subscriber-bin -c config.yml +go build -o observer_subscriber-bin cmd/observer_subscriber/main.go && ./observer_subscriber-bin # Startp Swagger API server at port 8422 with the path to the config.yml ./ go build -o swagger-api-bin cmd/swagger-api/main.go && ./swagger-api-bin -p 8423 @@ -114,64 +112,63 @@ go build -o swagger-api-bin cmd/swagger-api/main.go && ./swagger-api-bin -p 8423 go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8437 -c configmock.yml ``` -OR +### make command +Build and start all services: ```shell make go-build +make start ``` -Then + +Build and start individual service: ```shell +make go-build-platform-api make start ``` ### Docker -Build and run from local Dockerfile: +Build and run all services: -Then build: ```shell docker-compose build -``` - -Run all services: -```shell docker-compose up ``` -If you need to start one service: +Build and run individual service: ```shell -# Run only platform API -docker-compose start platform_api -# Run swagger api +docker-compose build swagger_api docker-compose start swagger_api ``` ## Configuration +When any of Block Atlas services started they look up inside [default configuration](./config.yml). +Most coins offering public RPC/explorer APIs are enabled, thus Block Atlas can be started and used right away, no additional configuration needed. +By default starting any of the [services](#architecture) will enable all platforms -Block Atlas can run just fine without configuration. -By default, all coins offering public RPC/explorer APIs are enabled. - -If you want to use custom RPC endpoints, or enable coins without public RPC (like Nimiq), -you can configure Block Atlas over `config.yml` or environment variables. - -#### Config File +To run a specific service only by passing environmental variable, e.g: `platfrom_api` : +```shell +ATLAS_PLATFORM=ethereum go run cmd/platform_api/main.go +``` -Config is loaded from `config.yml` if it exists in the working directory. -The repository includes a [default config](./config.yml) for reference with all available config options. +or change in config file +```yaml +platform: ethereum +``` -Example (`config.yml`): +This way you can one platform per binary, for scalability and sustainability. +To enable use of private endpoint: ```yaml nimiq: api: http://localhost:8648 -#... ``` +It works the same for observer_worker - you can run all observer at 1 binary or 30 coins per 30 binaries #### Environment The rest gets loaded from environment variables. -Every config option is available under the `ATLAS_` prefix. -Nested keys are joined via `_` (Example `nimiq.api` => `NIMIQ_API`) +Every config option is available under the `ATLAS_` prefix. Nested keys are joined via `_`. Example: diff --git a/config.yml b/config.yml index fb89281c5..49cdd6913 100644 --- a/config.yml +++ b/config.yml @@ -9,7 +9,7 @@ gin: # If all - run all platforms in one binary. You can pick specific coin handle to run binary only with specific coin # Example: ethereum # You can see all the coin handles at coins/coins.yml file -platform: binance +platform: all # Sentry error tracking #sentry: From 3fe642c4336c57531dee11c3daa6c1aa1f632d3d Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Wed, 29 Apr 2020 13:09:59 -0700 Subject: [PATCH 270/506] Add Tezos unknown validator (#1063) * Add Tezos unknown validator * Pas correct delegate address --- platform/cosmos/stake.go | 2 +- platform/tezos/stake.go | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index 4d9ad5a3c..5b8bf46ea 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -11,7 +11,7 @@ import ( ) const ( - lockTime = 1814400 + lockTime = 1814400 // in seconds (21 days) minimumAmount = "1" ) diff --git a/platform/tezos/stake.go b/platform/tezos/stake.go index bd46c6d84..e83a9c8ae 100644 --- a/platform/tezos/stake.go +++ b/platform/tezos/stake.go @@ -2,11 +2,15 @@ package tezos import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - services "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/services/assets" ) -const Annual = 6.09 +const ( + Annual = 6.09 + LockTime = 0 + MinimumStakeAmount = "0" +) func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { account, err := p.rpcClient.GetAccount(address) @@ -17,7 +21,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e return make(blockatlas.DelegationsPage, 0), nil } - validators, err := services.GetValidatorsMap(p) + validators, err := assets.GetValidatorsMap(p) if err != nil { return nil, err } @@ -27,8 +31,8 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e func NormalizeDelegation(account Account, validators blockatlas.ValidatorMap) (blockatlas.DelegationsPage, error) { validator, ok := validators[account.Delegate] if !ok { - return nil, errors.E("Validator not found", - errors.Params{"Delegate": account.Delegate, "Balance": account.Balance}) + logger.Warn("Validator not found", logger.Params{"platform": "tezos", "delegation": account.Delegate}) + validator = getUnknownValidator(account.Delegate) } return blockatlas.DelegationsPage{ { @@ -82,8 +86,8 @@ func (p *Platform) UndelegatedBalance(address string) (string, error) { func getDetails() blockatlas.StakingDetails { return blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: Annual}, - MinimumAmount: "0", - LockTime: 0, + MinimumAmount: MinimumStakeAmount, + LockTime: LockTime, Type: blockatlas.DelegationTypeDelegate, } } @@ -97,3 +101,22 @@ func normalizeValidator(v Validator) (validator blockatlas.Validator) { Details: getDetails(), } } + +func getUnknownValidator(address string) blockatlas.StakeValidator { + return blockatlas.StakeValidator{ + ID: address, + Status: false, + Info: blockatlas.StakeValidatorInfo{ + Name: "Decommissioned", + Description: "Decommissioned", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: Annual, + }, + LockTime: LockTime, + MinimumAmount: MinimumStakeAmount, + Type: blockatlas.DelegationTypeDelegate, + }, + } +} From fbaebae4d8806289d1bcb77a6c2cf37784f1464a Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Thu, 30 Apr 2020 13:28:54 +0200 Subject: [PATCH 271/506] Mock tests: add collections test. (#1066) * Mock tests: add collections test. * Adjust .gitattributes. Co-authored-by: Catenocrypt --- .gitattribute | 1 - .gitattributes | 1 + Makefile | 4 +- configmock.yml | 2 +- .../ext-api-dyson/get/opensea-api-command1.js | 862 ++++++++++++++++++ 5 files changed, 866 insertions(+), 4 deletions(-) delete mode 100644 .gitattribute create mode 100644 .gitattributes create mode 100644 mock/ext-api-dyson/get/opensea-api-command1.js diff --git a/.gitattribute b/.gitattribute deleted file mode 100644 index a6594a4dc..000000000 --- a/.gitattribute +++ /dev/null @@ -1 +0,0 @@ -mock/ext-api-dyson/* linguist-vendored \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..385a3fa58 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +mock/ext-api-dyson/* linguist-vendored diff --git a/Makefile b/Makefile index 9465dddd7..53ddca7fa 100644 --- a/Makefile +++ b/Makefile @@ -180,8 +180,8 @@ ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host) && \ $(MAKE) newman-run test=domain host=$(host) && \ $(MAKE) newman-run test=staking host=$(host) && \ - $(MAKE) newman-run test=token host=$(host)" - #not-mocked-yet: $(MAKE) newman-run test=collection host=$(host) && + $(MAKE) newman-run test=token host=$(host) && \ + $(MAKE) newman-run test=collection host=$(host)" @bash -c "$(MAKE) stop" else @bash -c "$(MAKE) newman-run test=$(test) host=$(host)" diff --git a/configmock.yml b/configmock.yml index 153560d0c..e8347768c 100644 --- a/configmock.yml +++ b/configmock.yml @@ -65,7 +65,7 @@ tezos: ethereum: api: http://localhost:3347/eth-api blockbook_api: http://localhost:3347/eth-blockbook-api - collections_api: https://api.opensea.io + collections_api: http://localhost:3347/opensea-api collections_api_key: opensea_api_key rpc: http://localhost:3347/eth-rpc diff --git a/mock/ext-api-dyson/get/opensea-api-command1.js b/mock/ext-api-dyson/get/opensea-api-command1.js new file mode 100644 index 000000000..1aef38cdc --- /dev/null +++ b/mock/ext-api-dyson/get/opensea-api-command1.js @@ -0,0 +1,862 @@ +/// OpenSea API Mock +/// See: + +/// curl "http://localhost:3347/opensea-api/api/v1/assets/?collection=unstoppable-domains&limit=300&owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d" +/// curl "https://api.opensea.io/api/v1/assets/?collection=unstoppable-domains&limit=300&owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d" +/// curl "http://localhost:8437/v4/ethereum/collections/0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d/collection/unstoppable-domains" + +/// curl "http://localhost:3347/opensea-api/api/v1/collections/?asset_owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d&limit=1000" +/// curl "https://api.opensea.io/api/v1/collections?asset_owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d&limit=1000" +/// curl -d '{"60":["0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d"]}' http://localhost:8437/v4/collectibles/categories + +module.exports = { + path: "/opensea-api/api/v1/:command1/?", + template: function(params, query) { + switch (params.command1) { + case 'assets': + if (query.owner == '0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d' && + query.collection == 'unstoppable-domains') { + return JSON.parse(` + { + "assets": [ + { + "token_id": "107221826727469155718680588460379721284635325845036369130032935095484960793482", + "num_sales": 0, + "background_color": "4C47F7", + "image_url": "https://storage.opensea.io/files/fec912a0664aecaa908ee888177ebfc6.svg", + "image_preview_url": "https://lh3.googleusercontent.com/cqCHmaBgbAtaE5i-jRKLGbJy2C-AUnDXN8zpkw8JPKnqRNGXdMJme_ThTFL30mDN9u9piJ4ACcfHmmDAyaXfIocN=s250", + "image_thumbnail_url": "https://lh3.googleusercontent.com/cqCHmaBgbAtaE5i-jRKLGbJy2C-AUnDXN8zpkw8JPKnqRNGXdMJme_ThTFL30mDN9u9piJ4ACcfHmmDAyaXfIocN=s128", + "image_original_url": null, + "animation_url": null, + "animation_original_url": null, + "name": "sloth", + "description": "A .crypto blockchain domain. Use it to resolve your cryptocurrency addresses and decentralized websites.", + "external_link": "https://unstoppabledomains.com/search?searchTerm=sloth.crypto", + "asset_contract": { + "address": "0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe", + "asset_contract_type": "non-fungible", + "created_date": "2019-12-10T08:55:01.176657", + "name": ".crypto", + "nft_version": "3.0", + "opensea_version": null, + "owner": null, + "schema_name": "ERC721", + "symbol": "", + "total_supply": null, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "external_link": "https://unstoppabledomains.com/", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + "owner": { + "user": null, + "profile_img_url": "https://storage.googleapis.com/opensea-static/opensea-profile/6.png", + "address": "0x84e79d544b4b13bc3560069cfd56a9d5bbe7521d", + "config": "", + "discord_id": "" + }, + "permalink": "https://opensea.io/assets/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/107221826727469155718680588460379721284635325845036369130032935095484960793482", + "collection": { + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-12-10T08:55:01.591598", + "default_to_fiat": false, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "display_data": { + "card_display_style": "padded", + "images": [ + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" + ] + }, + "external_url": "https://unstoppabledomains.com/", + "featured": false, + "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", + "name": "Unstoppable Domains", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "unstoppable-domains", + "wiki_url": null + }, + "decimals": 0, + "auctions": null, + "sell_orders": [], + "traits": [ + { + "trait_type": "level", + "value": 2, + "display_type": null, + "max_value": null, + "trait_count": 0, + "order": null + }, + { + "trait_type": "domain", + "value": "sloth.crypto", + "display_type": null, + "max_value": null, + "trait_count": 1, + "order": null + }, + { + "trait_type": "type", + "value": "standard", + "display_type": null, + "max_value": null, + "trait_count": 52377, + "order": null + } + ], + "last_sale": null, + "top_bid": null, + "current_price": null, + "current_escrow_price": null, + "listing_date": null, + "is_presale": false, + "transfer_fee_payment_token": null, + "transfer_fee": null + }, + { + "token_id": "39602885785430968515488172908991286516392379555774938600072517130912304722435", + "num_sales": 0, + "background_color": "4C47F7", + "image_url": "https://storage.opensea.io/files/a9d70320f34fb5fb5183d1a9913d2267.svg", + "image_preview_url": "https://lh3.googleusercontent.com/vbjIXUNL8ghOTEn7W6j_ALfwbFl4EOaYdqZjIwmtgdPQ92kzTd3jJjk7fsjJuW2IKkCT80JPuJ6PX_dChnOKI0yK=s250", + "image_thumbnail_url": "https://lh3.googleusercontent.com/vbjIXUNL8ghOTEn7W6j_ALfwbFl4EOaYdqZjIwmtgdPQ92kzTd3jJjk7fsjJuW2IKkCT80JPuJ6PX_dChnOKI0yK=s128", + "image_original_url": null, + "animation_url": null, + "animation_original_url": null, + "name": "vikmeup", + "description": "A .crypto blockchain domain. Use it to resolve your cryptocurrency addresses and decentralized websites.", + "external_link": "https://unstoppabledomains.com/search?searchTerm=vikmeup.crypto", + "asset_contract": { + "address": "0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe", + "asset_contract_type": "non-fungible", + "created_date": "2019-12-10T08:55:01.176657", + "name": ".crypto", + "nft_version": "3.0", + "opensea_version": null, + "owner": null, + "schema_name": "ERC721", + "symbol": "", + "total_supply": null, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "external_link": "https://unstoppabledomains.com/", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + "owner": { + "user": null, + "profile_img_url": "https://storage.googleapis.com/opensea-static/opensea-profile/6.png", + "address": "0x84e79d544b4b13bc3560069cfd56a9d5bbe7521d", + "config": "", + "discord_id": "" + }, + "permalink": "https://opensea.io/assets/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/39602885785430968515488172908991286516392379555774938600072517130912304722435", + "collection": { + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-12-10T08:55:01.591598", + "default_to_fiat": false, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "display_data": { + "card_display_style": "padded", + "images": [ + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" + ] + }, + "external_url": "https://unstoppabledomains.com/", + "featured": false, + "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", + "name": "Unstoppable Domains", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "unstoppable-domains", + "wiki_url": null + }, + "decimals": 0, + "auctions": null, + "sell_orders": [], + "traits": [ + { + "trait_type": "level", + "value": 2, + "display_type": null, + "max_value": null, + "trait_count": 0, + "order": null + }, + { + "trait_type": "domain", + "value": "vikmeup.crypto", + "display_type": null, + "max_value": null, + "trait_count": 1, + "order": null + }, + { + "trait_type": "type", + "value": "standard", + "display_type": null, + "max_value": null, + "trait_count": 52377, + "order": null + } + ], + "last_sale": null, + "top_bid": null, + "current_price": null, + "current_escrow_price": null, + "listing_date": null, + "is_presale": false, + "transfer_fee_payment_token": null, + "transfer_fee": null + } + ] + } + `); + } + break; + + case 'collections': + if (query.asset_owner == '0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d') { + return JSON.parse(` + [ + { + "primary_asset_contracts": [ + { + "address": "0x1d963688fe2209a98db35c67a041524822cf04ff", + "asset_contract_type": "non-fungible", + "created_date": "2019-01-23T02:17:28.643618", + "name": "MarbleCards", + "nft_version": "3.0", + "opensea_version": null, + "owner": 204604, + "schema_name": "ERC721", + "symbol": "MRBLNFT", + "total_supply": null, + "description": "Claim the most amazing web pages. Remember that every web page can only be marbled once and by one person only. Once a card is created, that URL is claimed forever. Now go create some classics!", + "external_link": "https://marble.cards", + "image_url": "https://lh3.googleusercontent.com/JHs53JRA6f3VcBqqORnoL4_q4kLDeZkDgZkmbY3iziyQQ14IRtP3mQglePCmHpXE_fit88FH8cAFMUA3j54mivAA=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 250, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 500, + "payout_address": "0xee68e4c594b96efc19a9d7d2a33901651ce967a2" + } + ], + "traits": { + "Collection ID": { + "min": 1, + "max": 5865 + }, + "level": { + "min": 1, + "max": 100 + }, + "collection_id": { + "min": 1, + "max": 4033 + } + }, + "stats": { + "seven_day_volume": 1.01145277777778, + "seven_day_change": 4.163107594577744, + "total_volume": 350.909262241233, + "count": 57728, + "num_owners": 1091, + "market_cap": 3029.695577899588, + "average_price": 0.164129682994029, + "items_sold": 2026 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-04-26T22:13:21.421079", + "default_to_fiat": false, + "description": "Claim the most amazing web pages. Remember that every web page can only be marbled once and by one person only. Once a card is created, that URL is claimed forever. Now go create some classics!", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "250", + "display_data": { + "card_display_style": "contain", + "images": [ + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18612-1552667321.png", + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18905-1552770831.png", + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18704-1552750420.png", + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/8829-1550886013.png", + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18951-1552772148.png", + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18950-1552772146.png" + ] + }, + "external_url": "https://marble.cards", + "featured": false, + "featured_image_url": "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff-featured-1556589463.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/JHs53JRA6f3VcBqqORnoL4_q4kLDeZkDgZkmbY3iziyQQ14IRtP3mQglePCmHpXE_fit88FH8cAFMUA3j54mivAA=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/JHs53JRA6f3VcBqqORnoL4_q4kLDeZkDgZkmbY3iziyQQ14IRtP3mQglePCmHpXE_fit88FH8cAFMUA3j54mivAA", + "name": "MarbleCards", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": "0xee68e4c594b96efc19a9d7d2a33901651ce967a2", + "require_email": false, + "short_description": "Claim websites as unique crypto collectibles", + "slug": "marblecards", + "wiki_url": null, + "owned_asset_count": 1 + }, + { + "primary_asset_contracts": [ + { + "address": "0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85", + "asset_contract_type": "non-fungible", + "created_date": "2019-05-08T21:59:29.327544", + "name": "ENS", + "nft_version": "3.0", + "opensea_version": null, + "owner": 279872, + "schema_name": "ERC721", + "symbol": "ENS", + "total_supply": null, + "description": "Ethereum Name Service (ENS) domains are secure domain names for the decentralized world. ENS domains provide a way for users to map human readable names to blockchain and non-blockchain resources, like Ethereum addresses, IPFS hashes, or website URLs. ENS domains can be bought and sold on secondary markets.", + "external_link": "https://ens.domains", + "image_url": "https://lh3.googleusercontent.com/0cOqWoYA7xL9CkUjGlxsjreSYBdrUBE0c6EO1COG4XE8UeP-Z30ckqUNiL872zHQHQU5MUNMNhfDpyXIP17hRSC5HQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": "" + } + ], + "traits": { + "Length": { + "min": 3, + "max": 70 + } + }, + "stats": { + "seven_day_volume": 61.5400674228928, + "seven_day_change": 24.471538567710834, + "total_volume": 6330.17513707834, + "count": 352132, + "num_owners": 30272, + "market_cap": 349849.79099535465, + "average_price": 0.713098472127782, + "items_sold": 8868 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-05-08T21:59:36.282454", + "default_to_fiat": false, + "description": "Ethereum Name Service (ENS) domains are secure domain names for the decentralized world. ENS domains provide a way for users to map human readable names to blockchain and non-blockchain resources, like Ethereum addresses, IPFS hashes, or website URLs. ENS domains can be bought and sold on secondary markets.", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "display_data": { + "card_display_style": "cover", + "images": [ + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/26693679858283927161893791132395207263838168762475401800426021835398462679008-1565293871.png", + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/14216961695379335495094368768338390872453914418325715259759390099828279953313-1565293758.png", + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/28032727276679833339346855127845420552876278365164540739421161968857583632995-1565293757.png", + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/5939065732706496924433039736405736608461463576171087944642507927497598723058-1565293758.png", + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/8268680357553423178495517182551079885250260646681574205692425339615070583014-1565293756.png", + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/96156505551778134260224136134970011352406026760333505247707872912354314952431-1565293756.png" + ] + }, + "external_url": "https://ens.domains", + "featured": false, + "featured_image_url": "https://storage.googleapis.com/opensea-static/official-ens-logo.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/0cOqWoYA7xL9CkUjGlxsjreSYBdrUBE0c6EO1COG4XE8UeP-Z30ckqUNiL872zHQHQU5MUNMNhfDpyXIP17hRSC5HQ=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/0cOqWoYA7xL9CkUjGlxsjreSYBdrUBE0c6EO1COG4XE8UeP-Z30ckqUNiL872zHQHQU5MUNMNhfDpyXIP17hRSC5HQ", + "name": "Ethereum Name Service (ENS)", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": "", + "require_email": false, + "short_description": null, + "slug": "ens", + "wiki_url": null, + "owned_asset_count": 2 + }, + { + "primary_asset_contracts": [ + { + "address": "0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c", + "asset_contract_type": "non-fungible", + "created_date": "2019-10-24T11:06:57.511707", + "name": "KnightStory Item", + "nft_version": "3.0", + "opensea_version": null, + "owner": 1672886, + "schema_name": "ERC721", + "symbol": "", + "total_supply": "1", + "description": "Knight Story is an innovative mobile RPG powered by blockchain. The game is the second title of Biscuit; developed EOS Knights, the legendary blockchain game.", + "external_link": "https://knightstory.io", + "image_url": "https://lh3.googleusercontent.com/Hwr0JNz9lHdTeu3mZTawVun-BdKRf-zSpi5ZUDxirBbPs_-hW92qHfh25QcTzeGCPy0FRULooZyTJ6MlRh8qaq4=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": "0x9702a479115788294232c384a5c1f42c881789fe" + } + ], + "traits": { + "hp": { + "min": 2, + "max": 5502 + }, + "defense (set)": { + "min": 70, + "max": 288 + }, + "attack (set)": { + "min": 60, + "max": 714 + }, + "score": { + "min": 28, + "max": 100 + }, + "luck": { + "min": 2, + "max": 1079 + }, + "magic_bean_purchase_bonus": { + "min": 2, + "max": 128 + }, + "luck (set)": { + "min": 40, + "max": 294 + }, + "defense": { + "min": 2, + "max": 2242 + }, + "hp (set)": { + "min": 60, + "max": 756 + }, + "None": { + "min": 0, + "max": 0 + }, + "attack": { + "min": 7, + "max": 5502 + } + }, + "stats": { + "seven_day_volume": 16.6826531170265, + "seven_day_change": -0.42001600555972113, + "total_volume": 555.213393323626, + "count": 39491, + "num_owners": 5650, + "market_cap": 1592.9963396829778, + "average_price": 0.0318228574152362, + "items_sold": 17443 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-10-24T11:06:58.609791", + "default_to_fiat": false, + "description": "Knight Story is an innovative mobile RPG powered by blockchain. The game is the second title of Biscuit; developed EOS Knights, the legendary blockchain game.", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "display_data": { + "card_display_style": "padded", + "images": [ + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/1-1571915237.svg", + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/2-1571982585.svg", + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/6-1571984918.svg", + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/5-1571984898.svg", + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/4-1571984887.svg", + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/3-1571984879.svg" + ] + }, + "external_url": "https://knightstory.io", + "featured": false, + "featured_image_url": null, + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/Hwr0JNz9lHdTeu3mZTawVun-BdKRf-zSpi5ZUDxirBbPs_-hW92qHfh25QcTzeGCPy0FRULooZyTJ6MlRh8qaq4=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/Hwr0JNz9lHdTeu3mZTawVun-BdKRf-zSpi5ZUDxirBbPs_-hW92qHfh25QcTzeGCPy0FRULooZyTJ6MlRh8qaq4", + "name": "KnightStory", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": "0x9702a479115788294232c384a5c1f42c881789fe", + "require_email": false, + "short_description": null, + "slug": "knightstory", + "wiki_url": null, + "owned_asset_count": 1 + }, + { + "primary_asset_contracts": [ + { + "address": "0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe", + "asset_contract_type": "non-fungible", + "created_date": "2019-12-10T08:55:01.176657", + "name": ".crypto", + "nft_version": "3.0", + "opensea_version": null, + "owner": null, + "schema_name": "ERC721", + "symbol": "", + "total_supply": null, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "external_link": "https://unstoppabledomains.com/", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + } + ], + "traits": { + "level": { + "min": 1, + "max": 3 + } + }, + "stats": { + "seven_day_volume": 8.232, + "seven_day_change": -0.43929053087580205, + "total_volume": 46.0238785864631, + "count": 56375, + "num_owners": 4213, + "market_cap": 8820.628142903694, + "average_price": 0.104362536477241, + "items_sold": 441 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-12-10T08:55:01.591598", + "default_to_fiat": false, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "display_data": { + "card_display_style": "padded", + "images": [ + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" + ] + }, + "external_url": "https://unstoppabledomains.com/", + "featured": false, + "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", + "name": "Unstoppable Domains", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "unstoppable-domains", + "wiki_url": null, + "owned_asset_count": 2 + }, + { + "primary_asset_contracts": [ + { + "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + "asset_contract_type": "semi-fungible", + "created_date": "2019-08-02T23:43:14.666153", + "name": "Enjin", + "nft_version": null, + "opensea_version": null, + "owner": null, + "schema_name": "ERC1155", + "symbol": "", + "total_supply": null, + "description": "Enjin assets are unique digital ERC1155 assets used in a variety of games in the Enjin multiverse.", + "external_link": "https://enjinx.io/", + "image_url": "https://lh3.googleusercontent.com/pz9RPxNoHxFTJNNySYV5bXjsWlajAiDiI1A5m5OvUaS1fd8N64yViclbRQqM8HViBTIUPrYgQ-w49h36NHL0D1Y=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + } + ], + "traits": {}, + "stats": { + "seven_day_volume": 0.6148, + "seven_day_change": 3.6330067822155234, + "total_volume": 284.785297517294, + "count": 34146, + "num_owners": 29430, + "market_cap": 907.2470250000015, + "average_price": 0.21673158106339, + "items_sold": 1306 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-12-15T03:51:34.864843", + "default_to_fiat": false, + "description": "The season of giving is upon us, and we come bearing gifts! Join us in the spirit of giving to receive one of our first-ever Binance Collectibles! “HO HO HODL: Binance Collectibles Series 1.”", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "display_data": { + "card_display_style": "contain", + "images": [ + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727762-1576342335.jpg", + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420726407-1576341423.jpg", + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727252-1576342120.jpg", + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727146-1576342000.jpg", + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727063-1576341986.jpg", + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727778-1576342346.jpg" + ] + }, + "external_url": "https://www.binance.com/en/blog/411120468693135360/Earn-a-Guaranteed-Binance-NFT--HO-HO-HODL-Binance-Collectibles-Series-1", + "featured": false, + "featured_image_url": null, + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/vbRXgbAGZVvBQw5q-qmV0tF3HHKCJeomBz5oHFTehsv2q6xuY7UyndXSWgCWqj2GGJM77DLFP-vLNVnaKYnVoD8=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/vbRXgbAGZVvBQw5q-qmV0tF3HHKCJeomBz5oHFTehsv2q6xuY7UyndXSWgCWqj2GGJM77DLFP-vLNVnaKYnVoD8", + "name": "Binance", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "binance", + "wiki_url": null, + "owned_asset_count": 4 + }, + { + "primary_asset_contracts": [ + { + "address": "0x3eea5bf894236f4b7a6f1451bca89a9c91f49719", + "asset_contract_type": "non-fungible", + "created_date": "2019-12-24T15:08:28.581742", + "name": "Trust Collectible", + "nft_version": "3.0", + "opensea_version": null, + "owner": 1982280, + "schema_name": "ERC721", + "symbol": "", + "total_supply": "25", + "description": "Your friendly talkative crypto app.", + "external_link": "https://trustwallet.com", + "image_url": "https://storage.opensea.io/trust-collectible-1577200601.png", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + } + ], + "traits": { + "level": { + "min": 2, + "max": 2 + }, + "generation": { + "min": 1, + "max": 1 + } + }, + "stats": { + "seven_day_volume": 0, + "seven_day_change": 0, + "total_volume": 1.12550814873532, + "count": 50, + "num_owners": 22, + "market_cap": 0, + "average_price": 0.0229695540558228, + "items_sold": 47 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-12-24T15:08:28.833176", + "default_to_fiat": false, + "description": "Your friendly talkative crypto app.", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "display_data": { + "card_display_style": "cover", + "images": [ + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/1-1577200113.png", + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/25-1577200136.png", + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/24-1577200136.png", + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/21-1577200135.png", + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/23-1577200135.png", + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/22-1577200133.png" + ] + }, + "external_url": "https://trustwallet.com", + "featured": false, + "featured_image_url": null, + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://storage.opensea.io/trust-collectible-1577200601.png", + "is_subject_to_whitelist": false, + "large_image_url": "https://storage.opensea.io/trust-collectible-large-1577200602.png", + "name": "Trust Collectibles", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "trust-collectible", + "wiki_url": null, + "owned_asset_count": 1 + }, + { + "primary_asset_contracts": [], + "traits": { + "level": { + "min": 2, + "max": 2 + } + }, + "stats": { + "seven_day_volume": 2.11109527819312, + "seven_day_change": 2.279116617261758, + "total_volume": 2.78059527819312, + "count": 14085, + "num_owners": 8511, + "market_cap": 126.33769191403255, + "average_price": 0.00896966218771974, + "items_sold": 310 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2020-04-13T20:06:38.168795", + "default_to_fiat": false, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "display_data": { + "card_display_style": "padded", + "images": [ + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" + ] + }, + "external_url": "https://unstoppabledomains.com/", + "featured": false, + "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", + "name": "Unstoppable Domains Animals", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "unstoppable-domains-animals", + "wiki_url": null, + "owned_asset_count": 1 + } + ] + `); + } + break; + } + + return {error: "Not implemented"}; + } +}; From 50168e9e39338d7db085d8750947e5793f55e0a2 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 2 May 2020 03:25:29 +0300 Subject: [PATCH 272/506] Add /v2/xpub endpoint (#1070) * Add new /v2 router for custom api as @vikmeup requested * Update swagger * Fix router conflicts --- api/endpoint/collection.go | 2 +- api/endpoint/domain.go | 4 +- api/endpoint/staking.go | 8 +- api/endpoint/token.go | 2 +- api/endpoint/transaction.go | 4 +- api/registry.go | 32 +- docs/docs.go | 401 ++++++------------------- docs/swagger.json | 399 ++++++------------------- docs/swagger.yaml | 580 +++++++++++++----------------------- 9 files changed, 419 insertions(+), 1013 deletions(-) diff --git a/api/endpoint/collection.go b/api/endpoint/collection.go index a7fc3851d..d69141164 100644 --- a/api/endpoint/collection.go +++ b/api/endpoint/collection.go @@ -18,7 +18,7 @@ import ( // @Param owner path string true "the query address" default(0x0875BCab22dE3d02402bc38aEe4104e1239374a7) // @Param collection_id path string true "the query collection" default(0x06012c8cf97bead5deae237070f9587f8e7a266d) // @Success 200 {object} blockatlas.CollectionPage -// @Failure 500 {object} middleware.ApiError +// @Failure 500 {object} model.ErrorResponse // @Router /v4/{coin}/collections/{owner}/collection/{collection_id} [get] func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas.CollectionAPI) { collectibles, err := api.GetCollectibles(c.Param("owner"), c.Param("collection_id")) diff --git a/api/endpoint/domain.go b/api/endpoint/domain.go index ec4b6f824..b83baebef 100644 --- a/api/endpoint/domain.go +++ b/api/endpoint/domain.go @@ -19,7 +19,7 @@ import ( // @Param name query string empty "string name" // @Param coin query string 60 "string coin" // @Success 200 {object} blockatlas.Resolved -// @Failure 500 {object} middleware.ApiError +// @Failure 500 {object} model.ErrorResponse // @Router /ns/lookup [get] func GetAddressByCoinAndDomain(c *gin.Context) { name := c.Query("name") @@ -50,7 +50,7 @@ func GetAddressByCoinAndDomain(c *gin.Context) { // @Param name query string empty "string name" // @Param coins query string true "List of coins" // @Success 200 {array} blockatlas.Resolved -// @Failure 500 {object} middleware.ApiError +// @Failure 500 {object} model.ErrorResponse // @Router /v2/ns/lookup [get] func GetAddressByCoinAndDomainBatch(c *gin.Context) { name := c.Query("name") diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index fb0acef0e..906a63341 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -35,7 +35,7 @@ type ( // @Accept json // @Produce json // @Tags Staking -// @Param delegations body api.AddressesRequest true "Validators addresses and coins" +// @Param delegations body AddressesRequest true "Validators addresses and coins" // @Success 200 {object} blockatlas.DelegationsBatchPage // @Router /v2/staking/delegations [post] func GetStakeDelegationsWithAllInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { @@ -70,7 +70,7 @@ func GetStakeDelegationsWithAllInfoForBatch(c *gin.Context, apis map[string]bloc // @Accept json // @Produce json // @Tags Staking -// @Param delegations body api.AddressesRequest true "Validators addresses and coins" +// @Param delegations body AddressesRequest true "Validators addresses and coins" // @Success 200 {object} blockatlas.DelegationsBatchPage // @Router /v2/staking/list [post] func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { @@ -104,7 +104,7 @@ func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { // @Tags Staking // @Param coin path string true "the coin name" default(cosmos) // @Success 200 {object} blockatlas.DocsResponse -// @Failure 500 {object} middleware.ApiError +// @Failure 500 {object} model.ErrorResponse // @Router /v2/{coin}/staking/validators [get] func GetValidators(c *gin.Context, api blockatlas.StakeAPI) { results, err := services.GetActiveValidators(api) @@ -124,7 +124,7 @@ func GetValidators(c *gin.Context, api blockatlas.StakeAPI) { // @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 -// @Failure 500 {object} middleware.ApiError +// @Failure 500 {object} model.ErrorResponse // @Router /v2/{coin}/staking/delegations/{address} [get] func GetStakingDelegationsForSpecificCoin(c *gin.Context, api blockatlas.StakeAPI) { result, err := getDelegationResponse(api, c.Param("address")) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index da739a2f6..2227f8d16 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -19,7 +19,7 @@ import ( // @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 -// @Failure 500 {object} middleware.ApiError +// @Failure 500 {object} model.ErrorResponse // @Router /v2/{coin}/tokens/{address} [get] func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokenAPI) { address := c.Param("address") diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 52ba41963..b21b5c933 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -18,7 +18,7 @@ import ( // @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 -// @Failure 500 {object} middleware.ApiError +// @Failure 500 {object} model.ErrorResponse // @Router /v2/{coin}/transactions/{address} [get] // @Summary Get Transactions @@ -29,7 +29,7 @@ import ( // @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} middleware.ApiError +// @Failure 500 {object} model.ErrorResponse // @Router /v1/{coin}/{address} [get] func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI blockatlas.TokenTxAPI) { address := c.Param("address") diff --git a/api/registry.go b/api/registry.go index 4a42b17f7..27f0d5483 100644 --- a/api/registry.go +++ b/api/registry.go @@ -103,8 +103,14 @@ func RegisterCustomAPI(root gin.IRouter, api blockatlas.Platform) { } handle := api.Coin().Handle - customRouter := root.Group("/v1/" + handle) - customAPI.RegisterRoutes(customRouter) + customRouterV1 := root.Group("/v1/" + handle) + customRouterV2 := root.Group("/v2/" + handle) + customAPI.RegisterRoutes(customRouterV1) + + if isForUtxoAPI(handle) { + customAPI.RegisterRoutes(customRouterV2) + } + } func RegisterDomainAPI(root gin.IRouter) { @@ -146,3 +152,25 @@ func IsForCustomAPI(handle string) bool { return false } } + +func isForUtxoAPI(handle string) bool { + switch handle { + case coin.Bitcoin().Handle, + coin.Litecoin().Handle, + coin.Bitcoincash().Handle, + coin.Zcash().Handle, + coin.Zcoin().Handle, + coin.Viacoin().Handle, + coin.Ravencoin().Handle, + coin.Groestlcoin().Handle, + coin.Zelcash().Handle, + coin.Decred().Handle, + coin.Digibyte().Handle, + coin.Dash().Handle, + coin.Doge().Handle, + coin.Qtum().Handle: + return true + default: + return false + } +} diff --git a/docs/docs.go b/docs/docs.go index 99f65030c..74f870fe6 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-04-06 16:53:26.62462 +0300 MSK m=+1.619745776 +// 2020-05-02 02:25:06.652414 +0300 MSK m=+0.185285183 package docs @@ -61,150 +61,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } - } - } - } - }, - "/v1/market/charts": { - "get": { - "description": "Get the charts data from an market and coin/token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get charts data for a specific coin", - "operationId": "get_charts_data", - "parameters": [ - { - "type": "integer", - "default": 60, - "description": "Coin ID", - "name": "coin", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Token ID", - "name": "token", - "in": "query" - }, - { - "type": "integer", - "default": 1574483028, - "description": "Start timestamp", - "name": "time_start", - "in": "query" - }, - { - "type": "integer", - "default": 64, - "description": "Max number of items in result prices array", - "name": "max_items", - "in": "query" - }, - { - "type": "string", - "default": "USD", - "description": "The currency to show charts", - "name": "currency", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/watchmarket.ChartData" - } - } - } - } - }, - "/v1/market/info": { - "get": { - "description": "Get the charts coin info data from an market and coin/contract", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get charts coin info data for a specific coin", - "operationId": "get_charts_coin_info", - "parameters": [ - { - "type": "integer", - "default": 60, - "description": "Coin ID", - "name": "coin", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Token ID", - "name": "token", - "in": "query" - }, - { - "type": "string", - "default": "USD", - "description": "The currency to show coin info in", - "name": "currency", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/watchmarket.ChartCoinInfo" - } - } - } - } - }, - "/v1/market/ticker": { - "post": { - "description": "Get the ticker values from many market and coin/token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get ticker values for a specific market", - "operationId": "get_tickers", - "parameters": [ - { - "description": "Ticker", - "name": "tickers", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/api.TickerRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.Tickers" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -288,7 +145,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -333,7 +190,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -360,7 +217,7 @@ var doc = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/api.AddressesRequest" + "$ref": "#/definitions/endpoint.AddressesRequest" } } ], @@ -395,7 +252,7 @@ var doc = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/api.AddressesRequest" + "$ref": "#/definitions/endpoint.AddressesRequest" } } ], @@ -409,6 +266,42 @@ var doc = `{ } } }, + "/v2/tokens": { + "post": { + "description": "Get tokens", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Transactions" + ], + "summary": "Get list of tokens by map: coin -\u003e [addresses]", + "operationId": "tokens_v3", + "parameters": [ + { + "default": "{\"60\": [\"0xb3624367b1ab37daef42e1a3a2ced012359659b0\"]}", + "description": "Payload", + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/blockatlas.ResultsResponse" + } + } + } + } + }, "/v2/{coin}/staking/delegations/{address}": { "get": { "description": "Get stake delegations from the address", @@ -451,7 +344,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -491,7 +384,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -539,15 +432,15 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } } }, - "/v2/{coin}/transactions/{address}": { + "/v2/{coin}/xpub/{xpub}": { "get": { - "description": "Get transactions from the address", + "description": "Get transactions from xpub address", "consumes": [ "application/json" ], @@ -557,12 +450,12 @@ var doc = `{ "tags": [ "Transactions" ], - "summary": "Get Transactions", - "operationId": "tx_v2", + "summary": "Get xpub transactions", + "operationId": "xpub", "parameters": [ { "type": "string", - "default": "tezos", + "default": "bitcoin", "description": "the coin name", "name": "coin", "in": "path", @@ -570,9 +463,9 @@ var doc = `{ }, { "type": "string", - "default": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", - "description": "the query address", - "name": "address", + "default": "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", + "description": "the xpub address", + "name": "xpub", "in": "path", "required": true } @@ -583,12 +476,6 @@ var doc = `{ "schema": { "$ref": "#/definitions/blockatlas.TxPage" } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } } } } @@ -679,7 +566,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -687,122 +574,12 @@ var doc = `{ } }, "definitions": { - "api.AddressBatchRequest": { - "type": "object", - "properties": { - "address": { - "type": "string" - }, - "coin": { - "type": "integer" - } - } - }, - "api.AddressesRequest": { - "type": "array", - "items": { - "$ref": "#/definitions/api.AddressBatchRequest" - } - }, - "api.Coin": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "token_id": { - "type": "string" - }, - "type": { - "type": "object", - "$ref": "#/definitions/blockatlas.CoinStatus" - } - } - }, - "api.Ticker": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "coin_name": { - "type": "string" - }, - "error": { - "type": "string" - }, - "last_update": { - "type": "string" - }, - "price": { - "type": "object", - "$ref": "#/definitions/api.TickerPrice" - }, - "token_id": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "api.TickerPrice": { - "type": "object", - "properties": { - "change_24h": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "provider": { - "type": "string" - }, - "value": { - "type": "number" - } - } - }, - "api.TickerRequest": { - "type": "object", - "properties": { - "assets": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Coin" - } - }, - "currency": { - "type": "string" - } - } - }, - "api.Tickers": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Ticker" - } - }, - "blockatlas.CoinStatus": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "height": { - "type": "integer" - } - } - }, "blockatlas.Collection": { "type": "object", "properties": { "address": { "type": "string" }, - "category_address": { - "type": "string" - }, "coin": { "type": "integer" }, @@ -821,21 +598,8 @@ var doc = `{ "name": { "type": "string" }, - "nft_version": { - "description": "Delete in the future version, as it's now part of Collectible", - "type": "string" - }, - "slug": { - "type": "string" - }, - "symbol": { - "type": "string" - }, "total": { "type": "integer" - }, - "type": { - "type": "string" } } }, @@ -917,6 +681,17 @@ var doc = `{ } } }, + "blockatlas.ResultsResponse": { + "type": "object", + "properties": { + "docs": { + "type": "object" + }, + "total": { + "type": "integer" + } + } + }, "blockatlas.StakeValidator": { "type": "object", "properties": { @@ -1087,48 +862,40 @@ var doc = `{ } } }, - "ginutils.ApiError": { + "endpoint.AddressBatchRequest": { "type": "object", "properties": { - "status_code": { - "type": "integer" - }, - "status_message": { + "address": { "type": "string" + }, + "coin": { + "type": "integer" } } }, - "watchmarket.ChartCoinInfo": { + "endpoint.AddressesRequest": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.AddressBatchRequest" + } + }, + "model.ErrorDetails": { "type": "object", "properties": { - "circulating_supply": { - "type": "number" - }, - "info": { - "type": "CoinInfo" - }, - "market_cap": { - "type": "number" - }, - "total_supply": { - "type": "number" + "code": { + "type": "integer" }, - "volume_24": { - "type": "number" + "message": { + "type": "string" } } }, - "watchmarket.ChartData": { + "model.ErrorResponse": { "type": "object", "properties": { "error": { - "type": "string" - }, - "prices": { - "type": "array", - "items": { - "type": "ChartPrice" - } + "type": "object", + "$ref": "#/definitions/model.ErrorDetails" } } } diff --git a/docs/swagger.json b/docs/swagger.json index 52096ec8c..99526cd97 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -40,150 +40,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } - } - } - } - }, - "/v1/market/charts": { - "get": { - "description": "Get the charts data from an market and coin/token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get charts data for a specific coin", - "operationId": "get_charts_data", - "parameters": [ - { - "type": "integer", - "default": 60, - "description": "Coin ID", - "name": "coin", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Token ID", - "name": "token", - "in": "query" - }, - { - "type": "integer", - "default": 1574483028, - "description": "Start timestamp", - "name": "time_start", - "in": "query" - }, - { - "type": "integer", - "default": 64, - "description": "Max number of items in result prices array", - "name": "max_items", - "in": "query" - }, - { - "type": "string", - "default": "USD", - "description": "The currency to show charts", - "name": "currency", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/watchmarket.ChartData" - } - } - } - } - }, - "/v1/market/info": { - "get": { - "description": "Get the charts coin info data from an market and coin/contract", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get charts coin info data for a specific coin", - "operationId": "get_charts_coin_info", - "parameters": [ - { - "type": "integer", - "default": 60, - "description": "Coin ID", - "name": "coin", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Token ID", - "name": "token", - "in": "query" - }, - { - "type": "string", - "default": "USD", - "description": "The currency to show coin info in", - "name": "currency", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/watchmarket.ChartCoinInfo" - } - } - } - } - }, - "/v1/market/ticker": { - "post": { - "description": "Get the ticker values from many market and coin/token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get ticker values for a specific market", - "operationId": "get_tickers", - "parameters": [ - { - "description": "Ticker", - "name": "tickers", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/api.TickerRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/api.Tickers" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -267,7 +124,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -312,7 +169,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -339,7 +196,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/api.AddressesRequest" + "$ref": "#/definitions/endpoint.AddressesRequest" } } ], @@ -374,7 +231,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/api.AddressesRequest" + "$ref": "#/definitions/endpoint.AddressesRequest" } } ], @@ -388,6 +245,42 @@ } } }, + "/v2/tokens": { + "post": { + "description": "Get tokens", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Transactions" + ], + "summary": "Get list of tokens by map: coin -\u003e [addresses]", + "operationId": "tokens_v3", + "parameters": [ + { + "default": "{\"60\": [\"0xb3624367b1ab37daef42e1a3a2ced012359659b0\"]}", + "description": "Payload", + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/blockatlas.ResultsResponse" + } + } + } + } + }, "/v2/{coin}/staking/delegations/{address}": { "get": { "description": "Get stake delegations from the address", @@ -430,7 +323,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -470,7 +363,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -518,15 +411,15 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } } }, - "/v2/{coin}/transactions/{address}": { + "/v2/{coin}/xpub/{xpub}": { "get": { - "description": "Get transactions from the address", + "description": "Get transactions from xpub address", "consumes": [ "application/json" ], @@ -536,12 +429,12 @@ "tags": [ "Transactions" ], - "summary": "Get Transactions", - "operationId": "tx_v2", + "summary": "Get xpub transactions", + "operationId": "xpub", "parameters": [ { "type": "string", - "default": "tezos", + "default": "bitcoin", "description": "the coin name", "name": "coin", "in": "path", @@ -549,9 +442,9 @@ }, { "type": "string", - "default": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", - "description": "the query address", - "name": "address", + "default": "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", + "description": "the xpub address", + "name": "xpub", "in": "path", "required": true } @@ -562,12 +455,6 @@ "schema": { "$ref": "#/definitions/blockatlas.TxPage" } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/ginutils.ApiError" - } } } } @@ -658,7 +545,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/ginutils.ApiError" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -666,122 +553,12 @@ } }, "definitions": { - "api.AddressBatchRequest": { - "type": "object", - "properties": { - "address": { - "type": "string" - }, - "coin": { - "type": "integer" - } - } - }, - "api.AddressesRequest": { - "type": "array", - "items": { - "$ref": "#/definitions/api.AddressBatchRequest" - } - }, - "api.Coin": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "token_id": { - "type": "string" - }, - "type": { - "type": "object", - "$ref": "#/definitions/blockatlas.CoinStatus" - } - } - }, - "api.Ticker": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "coin_name": { - "type": "string" - }, - "error": { - "type": "string" - }, - "last_update": { - "type": "string" - }, - "price": { - "type": "object", - "$ref": "#/definitions/api.TickerPrice" - }, - "token_id": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "api.TickerPrice": { - "type": "object", - "properties": { - "change_24h": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "provider": { - "type": "string" - }, - "value": { - "type": "number" - } - } - }, - "api.TickerRequest": { - "type": "object", - "properties": { - "assets": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Coin" - } - }, - "currency": { - "type": "string" - } - } - }, - "api.Tickers": { - "type": "array", - "items": { - "$ref": "#/definitions/api.Ticker" - } - }, - "blockatlas.CoinStatus": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "height": { - "type": "integer" - } - } - }, "blockatlas.Collection": { "type": "object", "properties": { "address": { "type": "string" }, - "category_address": { - "type": "string" - }, "coin": { "type": "integer" }, @@ -800,21 +577,8 @@ "name": { "type": "string" }, - "nft_version": { - "description": "Delete in the future version, as it's now part of Collectible", - "type": "string" - }, - "slug": { - "type": "string" - }, - "symbol": { - "type": "string" - }, "total": { "type": "integer" - }, - "type": { - "type": "string" } } }, @@ -896,6 +660,17 @@ } } }, + "blockatlas.ResultsResponse": { + "type": "object", + "properties": { + "docs": { + "type": "object" + }, + "total": { + "type": "integer" + } + } + }, "blockatlas.StakeValidator": { "type": "object", "properties": { @@ -1066,48 +841,40 @@ } } }, - "ginutils.ApiError": { + "endpoint.AddressBatchRequest": { "type": "object", "properties": { - "status_code": { - "type": "integer" - }, - "status_message": { + "address": { "type": "string" + }, + "coin": { + "type": "integer" } } }, - "watchmarket.ChartCoinInfo": { + "endpoint.AddressesRequest": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.AddressBatchRequest" + } + }, + "model.ErrorDetails": { "type": "object", "properties": { - "circulating_supply": { - "type": "number" - }, - "info": { - "type": "CoinInfo" - }, - "market_cap": { - "type": "number" - }, - "total_supply": { - "type": "number" + "code": { + "type": "integer" }, - "volume_24": { - "type": "number" + "message": { + "type": "string" } } }, - "watchmarket.ChartData": { + "model.ErrorResponse": { "type": "object", "properties": { "error": { - "type": "string" - }, - "prices": { - "type": "array", - "items": { - "type": "ChartPrice" - } + "type": "object", + "$ref": "#/definitions/model.ErrorDetails" } } } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index d91e4c537..c6c53647c 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,80 +1,8 @@ definitions: - api.AddressBatchRequest: - properties: - address: - type: string - coin: - type: integer - type: object - api.AddressesRequest: - items: - $ref: '#/definitions/api.AddressBatchRequest' - type: array - api.Coin: - properties: - coin: - type: integer - token_id: - type: string - type: - $ref: '#/definitions/blockatlas.CoinStatus' - type: object - type: object - api.Ticker: - properties: - coin: - type: integer - coin_name: - type: string - error: - type: string - last_update: - type: string - price: - $ref: '#/definitions/api.TickerPrice' - type: object - token_id: - type: string - type: - type: string - type: object - api.TickerPrice: - properties: - change_24h: - type: number - currency: - type: string - provider: - type: string - value: - type: number - type: object - api.TickerRequest: - properties: - assets: - items: - $ref: '#/definitions/api.Coin' - type: array - currency: - type: string - type: object - api.Tickers: - items: - $ref: '#/definitions/api.Ticker' - type: array - blockatlas.CoinStatus: - properties: - error: - type: string - height: - type: integer - type: object blockatlas.Collection: properties: address: type: string - category_address: - type: string coin: type: integer description: @@ -87,17 +15,8 @@ definitions: type: string name: type: string - nft_version: - description: Delete in the future version, as it's now part of Collectible - type: string - slug: - type: string - symbol: - type: string total: type: integer - type: - type: string type: object blockatlas.CollectionPage: items: @@ -151,6 +70,13 @@ definitions: result: type: string type: object + blockatlas.ResultsResponse: + properties: + docs: + type: object + total: + type: integer + type: object blockatlas.StakeValidator: properties: details: @@ -270,34 +196,29 @@ definitions: symbol: type: string type: object - ginutils.ApiError: + endpoint.AddressBatchRequest: properties: - status_code: - type: integer - status_message: + address: type: string + coin: + type: integer type: object - watchmarket.ChartCoinInfo: + endpoint.AddressesRequest: + items: + $ref: '#/definitions/endpoint.AddressBatchRequest' + type: array + model.ErrorDetails: properties: - circulating_supply: - type: number - info: - type: CoinInfo - market_cap: - type: number - total_supply: - type: number - volume_24: - type: number + code: + type: integer + message: + type: string type: object - watchmarket.ChartData: + model.ErrorResponse: properties: error: - type: string - prices: - items: - type: ChartPrice - type: array + $ref: '#/definitions/model.ErrorDetails' + type: object type: object info: contact: {} @@ -308,16 +229,16 @@ paths: description: Lookup ENS/ZNS to find registered addresses operationId: lookup parameters: - - description: string name - in: query - name: name - type: string - - description: string coin - in: query - name: coin - type: string + - description: string name + in: query + name: name + type: string + - description: string coin + in: query + name: coin + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -326,60 +247,60 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/ginutils.ApiError' + $ref: '#/definitions/model.ErrorResponse' summary: Lookup .eth / .zil addresses tags: - - Naming + - Naming /v1/{coin}/{address}: get: consumes: - - application/json + - application/json description: Get transactions from the address operationId: tx_v1 parameters: - - default: tezos - description: the coin name - in: path - name: coin - required: true - type: string - - default: tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q - description: the query address - in: path - name: address - required: true - type: string + - default: tezos + description: the coin name + in: path + name: coin + required: true + type: string + - default: tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q + description: the query address + in: path + name: address + required: true + type: string produces: - - application/json + - application/json responses: "500": description: Internal Server Error schema: - $ref: '#/definitions/ginutils.ApiError' + $ref: '#/definitions/model.ErrorResponse' summary: Get Transactions tags: - - Transactions + - Transactions /v1/{coin}/xpub/{xpub}: get: consumes: - - application/json + - application/json description: Get transactions from xpub address operationId: xpub parameters: - - default: bitcoin - description: the coin name - in: path - name: coin - required: true - type: string - - default: zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC - description: the xpub address - in: path - name: xpub - required: true - type: string + - default: bitcoin + description: the coin name + in: path + name: coin + required: true + type: string + - default: zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC + description: the xpub address + in: path + name: xpub + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -387,125 +308,28 @@ paths: $ref: '#/definitions/blockatlas.TxPage' summary: Get xpub transactions tags: - - Transactions - /v1/market/charts: - get: - consumes: - - application/json - description: Get the charts data from an market and coin/token - operationId: get_charts_data - parameters: - - default: 60 - description: Coin ID - in: query - name: coin - required: true - type: integer - - description: Token ID - in: query - name: token - type: string - - default: 1574483028 - description: Start timestamp - in: query - name: time_start - type: integer - - default: 64 - description: Max number of items in result prices array - in: query - name: max_items - type: integer - - default: USD - description: The currency to show charts - in: query - name: currency - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/watchmarket.ChartData' - summary: Get charts data for a specific coin - tags: - - Market - /v1/market/info: - get: - consumes: - - application/json - description: Get the charts coin info data from an market and coin/contract - operationId: get_charts_coin_info - parameters: - - default: 60 - description: Coin ID - in: query - name: coin - required: true - type: integer - - description: Token ID - in: query - name: token - type: string - - default: USD - description: The currency to show coin info in - in: query - name: currency - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/watchmarket.ChartCoinInfo' - summary: Get charts coin info data for a specific coin - tags: - - Market - /v1/market/ticker: - post: - consumes: - - application/json - description: Get the ticker values from many market and coin/token - operationId: get_tickers - parameters: - - description: Ticker - in: body - name: tickers - required: true - schema: - $ref: '#/definitions/api.TickerRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/api.Tickers' - summary: Get ticker values for a specific market - tags: - - Market + - Transactions /v2/{coin}/staking/delegations/{address}: get: consumes: - - application/json + - application/json description: Get stake delegations from the address operationId: delegations parameters: - - default: tron - description: the coin name - in: path - name: coin - required: true - type: string - - default: TPJYCz8ppZNyvw7pTwmjajcx4Kk1MmEUhD - description: the query address - in: path - name: address - required: true - type: string + - default: tron + description: the coin name + in: path + name: coin + required: true + type: string + - default: TPJYCz8ppZNyvw7pTwmjajcx4Kk1MmEUhD + description: the query address + in: path + name: address + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -514,25 +338,25 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/ginutils.ApiError' + $ref: '#/definitions/model.ErrorResponse' summary: Get Stake Delegations tags: - - Staking + - Staking /v2/{coin}/staking/validators: get: consumes: - - application/json + - application/json description: Get validators from the address operationId: validators parameters: - - default: cosmos - description: the coin name - in: path - name: coin - required: true - type: string + - default: cosmos + description: the coin name + in: path + name: coin + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -541,31 +365,31 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/ginutils.ApiError' + $ref: '#/definitions/model.ErrorResponse' summary: Get Validators tags: - - Staking + - Staking /v2/{coin}/tokens/{address}: get: consumes: - - application/json + - application/json description: Get tokens from the address operationId: tokens parameters: - - default: ethereum - description: the coin name - in: path - name: coin - required: true - type: string - - default: 0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB - description: the query address - in: path - name: address - required: true - type: string + - default: ethereum + description: the coin name + in: path + name: coin + required: true + type: string + - default: 0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB + description: the query address + in: path + name: address + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -574,59 +398,55 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/ginutils.ApiError' + $ref: '#/definitions/model.ErrorResponse' summary: Get Tokens tags: - - Transactions - /v2/{coin}/transactions/{address}: + - Transactions + /v2/{coin}/xpub/{xpub}: get: consumes: - - application/json - description: Get transactions from the address - operationId: tx_v2 + - application/json + description: Get transactions from xpub address + operationId: xpub parameters: - - default: tezos - description: the coin name - in: path - name: coin - required: true - type: string - - default: tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q - description: the query address - in: path - name: address - required: true - type: string + - default: bitcoin + description: the coin name + in: path + name: coin + required: true + type: string + - default: zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC + description: the xpub address + in: path + name: xpub + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK schema: $ref: '#/definitions/blockatlas.TxPage' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/ginutils.ApiError' - summary: Get Transactions + summary: Get xpub transactions tags: - - Transactions + - Transactions /v2/ns/lookup: get: description: Lookup ENS/ZNS to find registered addresses for multiple coins operationId: lookup parameters: - - description: string name - in: query - name: name - type: string - - description: List of coins - in: query - name: coins - required: true - type: string + - description: string name + in: query + name: name + type: string + - description: List of coins + in: query + name: coins + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -637,25 +457,25 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/ginutils.ApiError' + $ref: '#/definitions/model.ErrorResponse' summary: Lookup .eth / .zil addresses tags: - - Naming + - Naming /v2/staking/delegations: post: consumes: - - application/json + - application/json description: Get Stake Delegations for multiple coins operationId: batch_delegations parameters: - - description: Validators addresses and coins - in: body - name: delegations - required: true - schema: - $ref: '#/definitions/api.AddressesRequest' + - description: Validators addresses and coins + in: body + name: delegations + required: true + schema: + $ref: '#/definitions/endpoint.AddressesRequest' produces: - - application/json + - application/json responses: "200": description: OK @@ -663,22 +483,22 @@ paths: $ref: '#/definitions/blockatlas.DelegationsBatchPage' summary: Get Multiple Stake Delegations tags: - - Staking + - Staking /v2/staking/list: post: consumes: - - application/json + - application/json description: Get Stake Delegations for multiple coins operationId: batch_delegations parameters: - - description: Validators addresses and coins - in: body - name: delegations - required: true - schema: - $ref: '#/definitions/api.AddressesRequest' + - description: Validators addresses and coins + in: body + name: delegations + required: true + schema: + $ref: '#/definitions/endpoint.AddressesRequest' produces: - - application/json + - application/json responses: "200": description: OK @@ -686,34 +506,58 @@ paths: $ref: '#/definitions/blockatlas.DelegationsBatchPage' summary: Get Multiple Stake Delegations tags: - - Staking + - Staking + /v2/tokens: + post: + consumes: + - application/json + description: Get tokens + operationId: tokens_v3 + parameters: + - default: '{"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}' + description: Payload + in: body + name: data + required: true + schema: + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/blockatlas.ResultsResponse' + summary: 'Get list of tokens by map: coin -> [addresses]' + tags: + - Transactions /v4/{coin}/collections/{owner}/collection/{collection_id}: get: consumes: - - application/json + - application/json description: Get a collection from the address operationId: collection_v4 parameters: - - default: ethereum - description: the coin name - in: path - name: coin - required: true - type: string - - default: 0x0875BCab22dE3d02402bc38aEe4104e1239374a7 - description: the query address - in: path - name: owner - required: true - type: string - - default: 0x06012c8cf97bead5deae237070f9587f8e7a266d - description: the query collection - in: path - name: collection_id - required: true - type: string + - default: ethereum + description: the coin name + in: path + name: coin + required: true + type: string + - default: 0x0875BCab22dE3d02402bc38aEe4104e1239374a7 + description: the query address + in: path + name: owner + required: true + type: string + - default: 0x06012c8cf97bead5deae237070f9587f8e7a266d + description: the query collection + in: path + name: collection_id + required: true + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -722,26 +566,26 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/ginutils.ApiError' + $ref: '#/definitions/model.ErrorResponse' summary: Get Collection tags: - - Collections + - Collections /v4/collectibles/categories: post: consumes: - - application/json + - application/json description: Get collection categories operationId: collection_categories_v4 parameters: - - default: '{"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}' - description: Payload - in: body - name: data - required: true - schema: - type: string + - default: '{"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}' + description: Payload + in: body + name: data + required: true + schema: + type: string produces: - - application/json + - application/json responses: "200": description: OK @@ -749,5 +593,5 @@ paths: $ref: '#/definitions/blockatlas.DocsResponse' summary: Get list of collections from a specific coin and addresses tags: - - Collections + - Collections swagger: "2.0" From f45276b6246ba6de6e476b3a10f0c899426c3e12 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 2 May 2020 05:22:06 +0300 Subject: [PATCH 273/506] Change /v2/{coin}/xpub to /v2/{coin}/transactions/xpub (#1071) * Update swagger and change xpub endpoint * Update swagger and fix previous mistake with endpoint --- docs/docs.go | 54 +++++++++++++++++++++++++++++++-- docs/swagger.json | 52 +++++++++++++++++++++++++++++-- docs/swagger.yaml | 37 ++++++++++++++++++++-- platform/bitcoin/transaction.go | 5 +++ 4 files changed, 141 insertions(+), 7 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 74f870fe6..41f83f6ee 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-05-02 02:25:06.652414 +0300 MSK m=+0.185285183 +// 2020-05-02 05:07:02.305717 +0300 MSK m=+0.083111694 package docs @@ -438,7 +438,7 @@ var doc = `{ } } }, - "/v2/{coin}/xpub/{xpub}": { + "/v2/{coin}/transactions/xpub/{xpub}": { "get": { "description": "Get transactions from xpub address", "consumes": [ @@ -451,7 +451,7 @@ var doc = `{ "Transactions" ], "summary": "Get xpub transactions", - "operationId": "xpub", + "operationId": "xpubV2", "parameters": [ { "type": "string", @@ -480,6 +480,54 @@ var doc = `{ } } }, + "/v2/{coin}/transactions/{address}": { + "get": { + "description": "Get transactions from the address", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Transactions" + ], + "summary": "Get Transactions", + "operationId": "tx_v2", + "parameters": [ + { + "type": "string", + "default": "tezos", + "description": "the coin name", + "name": "coin", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", + "description": "the query address", + "name": "address", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/blockatlas.TxPage" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.ErrorResponse" + } + } + } + } + }, "/v4/collectibles/categories": { "post": { "description": "Get collection categories", diff --git a/docs/swagger.json b/docs/swagger.json index 99526cd97..a3f3b20ed 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -417,7 +417,7 @@ } } }, - "/v2/{coin}/xpub/{xpub}": { + "/v2/{coin}/transactions/xpub/{xpub}": { "get": { "description": "Get transactions from xpub address", "consumes": [ @@ -430,7 +430,7 @@ "Transactions" ], "summary": "Get xpub transactions", - "operationId": "xpub", + "operationId": "xpubV2", "parameters": [ { "type": "string", @@ -459,6 +459,54 @@ } } }, + "/v2/{coin}/transactions/{address}": { + "get": { + "description": "Get transactions from the address", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Transactions" + ], + "summary": "Get Transactions", + "operationId": "tx_v2", + "parameters": [ + { + "type": "string", + "default": "tezos", + "description": "the coin name", + "name": "coin", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", + "description": "the query address", + "name": "address", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/blockatlas.TxPage" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/model.ErrorResponse" + } + } + } + } + }, "/v4/collectibles/categories": { "post": { "description": "Get collection categories", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index c6c53647c..55ffb2eb0 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -402,12 +402,45 @@ paths: summary: Get Tokens tags: - Transactions - /v2/{coin}/xpub/{xpub}: + /v2/{coin}/transactions/{address}: + get: + consumes: + - application/json + description: Get transactions from the address + operationId: tx_v2 + parameters: + - default: tezos + description: the coin name + in: path + name: coin + required: true + type: string + - default: tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q + description: the query address + in: path + name: address + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/blockatlas.TxPage' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.ErrorResponse' + summary: Get Transactions + tags: + - Transactions + /v2/{coin}/transactions/xpub/{xpub}: get: consumes: - application/json description: Get transactions from xpub address - operationId: xpub + operationId: xpubV2 parameters: - default: bitcoin description: the coin name diff --git a/platform/bitcoin/transaction.go b/platform/bitcoin/transaction.go index 577cdc553..7301e4721 100644 --- a/platform/bitcoin/transaction.go +++ b/platform/bitcoin/transaction.go @@ -25,6 +25,11 @@ func (p *Platform) RegisterRoutes(router gin.IRouter) { router.GET("/xpub/:key", func(c *gin.Context) { p.handleXpubRoute(c) }) + + router.GET("/transactions/xpub/:key", func(c *gin.Context) { + p.handleXpubRoute(c) + }) + router.GET("/address/:address", func(c *gin.Context) { p.handleAddressRoute(c) }) From 074de1ac4a29baa462142cbcba234a4622644925 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 2 May 2020 05:23:40 +0300 Subject: [PATCH 274/506] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f1681f0fa..f9d7a1bd7 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,9 @@ ATLAS_NIMIQ_API=http://localhost:8648 ## Tests ### Unit tests - +``` +make test +``` ### Mocked tests End-to-end tests with calls to external APIs has great value, but is not suitable for regular CI verification, as any external reasons could break the tests. From 182fdbe6ee6c55a72e21eddfdb7c815c36ff202d Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Mon, 4 May 2020 16:07:21 +0200 Subject: [PATCH 275/506] Refactor: Remove CustomAPI routes for BTC and ETH (#1068) * Rename root->router. * Merge ethereum address CustomAPI with generic address API. * Generic handling of BTC-style Xpub+Addr-based tx query, instead of Custom. * Remove CustomAPI handling. * Register routes based on typed lists. * Collections and Naming handlers in separate lists. * Rename XPub --> Xpub * Review comments, minor rearrangements. * Add starting slash to API routes that missed it. * Add /v2/xpub endpoint (logical merge from master). * Change /v2/{coin}/xpub to /v2/{coin}/transactions/xpub (logical merge). * Revert some of the route-discrimination logic. * Change API to TxUtxoAPI, add tests for ethereum * Add tests and change GetTokenTxsByAddress Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov --- api/api.go | 19 +-- api/endpoint/collection.go | 10 +- api/endpoint/token.go | 6 +- api/endpoint/transaction.go | 47 +++++++ api/registry.go | 189 ++++++++------------------ pkg/blockatlas/errors.go | 17 ++- pkg/blockatlas/platform.go | 45 +++--- platform/bitcoin/transaction.go | 56 ++------ platform/ethereum/transaction.go | 40 +----- platform/ethereum/transaction_test.go | 77 +++++++++++ platform/platform.go | 25 +++- platform/registry.go | 43 ++---- services/domains/domains.go | 2 +- 13 files changed, 283 insertions(+), 293 deletions(-) create mode 100644 platform/ethereum/transaction_test.go diff --git a/api/api.go b/api/api.go index 22c4ea912..be6f0b742 100644 --- a/api/api.go +++ b/api/api.go @@ -5,16 +5,17 @@ import ( "github.com/trustwallet/blockatlas/platform" ) -func SetupPlatformAPI(root gin.IRouter) { +func SetupPlatformAPI(router gin.IRouter) { for _, api := range platform.Platforms { - RegisterCollectionsAPI(root, api) - RegisterTransactionsAPI(root, api) - RegisterCustomAPI(root, api) - RegisterTokensAPI(root, api) - RegisterStakeAPI(root, api) + RegisterTransactionsAPI(router, api) + RegisterTokensAPI(router, api) + RegisterStakeAPI(router, api) + } + for _, api := range platform.CollectionsAPIs { + RegisterCollectionsAPI(router, api) } - RegisterBatchAPI(root) - RegisterDomainAPI(root) - RegisterBasicAPI(root) + RegisterBatchAPI(router) + RegisterDomainAPI(router) + RegisterBasicAPI(router) } diff --git a/api/endpoint/collection.go b/api/endpoint/collection.go index d69141164..76052ddf8 100644 --- a/api/endpoint/collection.go +++ b/api/endpoint/collection.go @@ -20,7 +20,7 @@ import ( // @Success 200 {object} blockatlas.CollectionPage // @Failure 500 {object} model.ErrorResponse // @Router /v4/{coin}/collections/{owner}/collection/{collection_id} [get] -func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas.CollectionAPI) { +func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas.CollectionsAPI) { collectibles, err := api.GetCollectibles(c.Param("owner"), c.Param("collection_id")) if err != nil { c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) @@ -38,7 +38,7 @@ func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas // @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) // @Success 200 {object} blockatlas.DocsResponse // @Router /v4/collectibles/categories [post] -func GetCollectionCategoriesFromList(c *gin.Context, apis map[uint]blockatlas.CollectionAPI) { +func GetCollectionCategoriesFromList(c *gin.Context, apis blockatlas.CollectionsAPIs) { var reqs map[string][]string if err := c.BindJSON(&reqs); err != nil { c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.Default, err)) @@ -66,7 +66,7 @@ func GetCollectionCategoriesFromList(c *gin.Context, apis map[uint]blockatlas.Co c.JSON(http.StatusOK, &batch) } -func GetCollectiblesForOwnerV3(c *gin.Context, api blockatlas.CollectionAPI) { +func GetCollectiblesForOwnerV3(c *gin.Context, api blockatlas.CollectionsAPI) { collections, err := api.GetCollectionsV3(c.Param("owner")) if err != nil { c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) @@ -76,7 +76,7 @@ func GetCollectiblesForOwnerV3(c *gin.Context, api blockatlas.CollectionAPI) { c.JSON(http.StatusOK, &collections) } -func GetCollectiblesForSpecificCollectionAndOwnerV3(c *gin.Context, api blockatlas.CollectionAPI) { +func GetCollectiblesForSpecificCollectionAndOwnerV3(c *gin.Context, api blockatlas.CollectionsAPI) { collectibles, err := api.GetCollectiblesV3(c.Param("owner"), c.Param("collection_id")) if err != nil { c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) @@ -85,7 +85,7 @@ func GetCollectiblesForSpecificCollectionAndOwnerV3(c *gin.Context, api blockatl c.JSON(http.StatusOK, &collectibles) } -func GetCollectionCategoriesFromListV3(c *gin.Context, apis map[uint]blockatlas.CollectionAPI) { +func GetCollectionCategoriesFromListV3(c *gin.Context, apis blockatlas.CollectionsAPIs) { var reqs map[string][]string if err := c.BindJSON(&reqs); err != nil { c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.Default, err)) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index 2227f8d16..c065fa51e 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -21,7 +21,7 @@ import ( // @Success 200 {object} blockatlas.CollectionPage // @Failure 500 {object} model.ErrorResponse // @Router /v2/{coin}/tokens/{address} [get] -func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokenAPI) { +func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { address := c.Param("address") if address == "" { EmptyPage(c) @@ -45,7 +45,7 @@ func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokenAPI) { // @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) // @Success 200 {object} blockatlas.ResultsResponse // @Router /v2/tokens [post] -func GetTokens(c *gin.Context, apis map[uint]blockatlas.TokenAPI) { +func GetTokens(c *gin.Context, apis map[uint]blockatlas.TokensAPI) { var query map[string][]string if err := c.Bind(&query); err != nil { c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) @@ -68,7 +68,7 @@ func GetTokens(c *gin.Context, apis map[uint]blockatlas.TokenAPI) { c.JSON(http.StatusOK, blockatlas.ResultsResponse{Total: len(result), Results: &result}) } -func getTokens(tokenAPI blockatlas.TokenAPI, addresses []string) blockatlas.TokenPage { +func getTokens(tokenAPI blockatlas.TokensAPI, addresses []string) blockatlas.TokenPage { var ( tokenPagesChan = make(chan blockatlas.TokenPage, len(addresses)) wg sync.WaitGroup diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index b21b5c933..87b02166a 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -87,3 +87,50 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b sort.Sort(&page) c.JSON(http.StatusOK, &page) } + +// @Summary Get Transactions by XPUB +// @ID txxpub_v1 +// @Description Get transactions from XPUB address +// @Accept json +// @Produce json +// @Tags Transactions +// @Param coin path string true "the coin name" default(bitcoin) +// @Param xpub path string true "the xpub key" default(zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC) +// @Failure 500 {object} middleware.ApiError +// @Router /v1/{coin}/xpub/{xpub} [get] +func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { + xPubKey := c.Param("xpub") + if xPubKey == "" { + c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, blockatlas.ErrInvalidKey)) + return + } + + txs, err := api.GetTxsByXpub(xPubKey) + if err != nil { + switch err { + case blockatlas.ErrInvalidKey: + c.JSON(http.StatusBadRequest, + model.CreateErrorResponse(model.InvalidQuery, blockatlas.ErrInvalidKey)) + return + case blockatlas.ErrNotFound: + c.JSON(http.StatusNotFound, + model.CreateErrorResponse(model.RequestedDataNotFound, blockatlas.ErrNotFound)) + return + case blockatlas.ErrSourceConn: + c.JSON(http.StatusServiceUnavailable, + model.CreateErrorResponse(model.InternalFail, blockatlas.ErrSourceConn)) + return + default: + c.JSON(http.StatusInternalServerError, + model.CreateErrorResponse(model.Default, err)) + return + } + } + + page := blockatlas.TxPage(txs) + if len(page) > blockatlas.TxPerPage { + page = page[0:blockatlas.TxPerPage] + } + sort.Sort(&page) + c.JSON(http.StatusOK, &page) +} diff --git a/api/registry.go b/api/registry.go index 27f0d5483..17bd5ba89 100644 --- a/api/registry.go +++ b/api/registry.go @@ -6,171 +6,100 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/trustwallet/blockatlas/api/endpoint" "github.com/trustwallet/blockatlas/api/middleware" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform" "time" ) -func RegisterCollectionsAPI(root gin.IRouter, api blockatlas.Platform) { - collectionAPI, ok := api.(blockatlas.CollectionAPI) - if !ok { +func RegisterTransactionsAPI(router gin.IRouter, api blockatlas.Platform) { + handle := api.Coin().Handle + txUtxoAPI, ok := api.(blockatlas.TxUtxoAPI) + if ok { + router.GET("/v1/"+handle+"/address/:address", func(c *gin.Context) { + endpoint.GetTransactionsHistory(c, txUtxoAPI, nil) + }) + router.GET("/v1/"+handle+"/xpub/:xpub", func(c *gin.Context) { + endpoint.GetTransactionsByXpub(c, txUtxoAPI) + }) + router.GET("/v2/"+handle+"/transactions/xpub/:xpub", func(c *gin.Context) { + endpoint.GetTransactionsByXpub(c, txUtxoAPI) + }) return } - - handle := collectionAPI.Coin().Handle - - root.GET("/v3/"+handle+"/collections/:owner/collection/:collection_id", func(c *gin.Context) { - endpoint.GetCollectiblesForSpecificCollectionAndOwnerV3(c, collectionAPI) - }) - root.GET("/v3/"+handle+"/collections/:owner", func(c *gin.Context) { - endpoint.GetCollectiblesForOwnerV3(c, collectionAPI) - }) - root.GET("/v4/"+handle+"/collections/:owner/collection/:collection_id", func(c *gin.Context) { - endpoint.GetCollectiblesForSpecificCollectionAndOwner(c, collectionAPI) - }) + txAPI, okTxApi := api.(blockatlas.TxAPI) + tokenTxAPI, okTokenTxApi := api.(blockatlas.TokenTxAPI) + if okTxApi || okTokenTxApi { + router.GET("/v1/"+handle+"/:address", func(c *gin.Context) { + endpoint.GetTransactionsHistory(c, txAPI, tokenTxAPI) + }) + router.GET("/v2/"+handle+"/transactions/:address", func(c *gin.Context) { + endpoint.GetTransactionsHistory(c, txAPI, tokenTxAPI) + }) + } } -func RegisterTokensAPI(root gin.IRouter, api blockatlas.Platform) { - tokenAPI, ok := api.(blockatlas.TokenAPI) +func RegisterTokensAPI(router gin.IRouter, api blockatlas.Platform) { + tokenAPI, ok := api.(blockatlas.TokensAPI) if !ok { return } - - handle := api.Coin().Handle - - root.GET("/v2/"+handle+"/tokens/:address", func(c *gin.Context) { + handle := tokenAPI.Coin().Handle + router.GET("/v2/"+handle+"/tokens/:address", func(c *gin.Context) { endpoint.GetTokensByAddress(c, tokenAPI) }) } -func RegisterTransactionsAPI(root gin.IRouter, api blockatlas.Platform) { - txAPI, _ := api.(blockatlas.TxAPI) - tokenTxAPI, _ := api.(blockatlas.TokenTxAPI) - - handle := api.Coin().Handle - - if IsForCustomAPI(handle) { +func RegisterStakeAPI(router gin.IRouter, api blockatlas.Platform) { + stakeAPI, ok := api.(blockatlas.StakeAPI) + if !ok { return } - - root.GET("/v1/"+handle+"/:address", func(c *gin.Context) { - endpoint.GetTransactionsHistory(c, txAPI, tokenTxAPI) - }) - root.GET("/v2/"+handle+"/transactions/:address", func(c *gin.Context) { - endpoint.GetTransactionsHistory(c, txAPI, tokenTxAPI) + handle := api.Coin().Handle + router.GET("/v2/"+handle+"/staking/validators", middleware.CacheMiddleware(time.Hour, func(c *gin.Context) { + endpoint.GetValidators(c, stakeAPI) + })) + router.GET("/v2/"+handle+"/staking/delegations/:address", func(c *gin.Context) { + endpoint.GetStakingDelegationsForSpecificCoin(c, stakeAPI) }) } -func RegisterStakeAPI(root gin.IRouter, api blockatlas.Platform) { - stakingAPI, ok := api.(blockatlas.StakeAPI) - if !ok { - return - } +func RegisterCollectionsAPI(router gin.IRouter, api blockatlas.CollectionsAPI) { handle := api.Coin().Handle - - root.GET("/v2/"+handle+"/staking/validators", middleware.CacheMiddleware(time.Hour, func(c *gin.Context) { - endpoint.GetValidators(c, stakingAPI) - })) - root.GET("/v2/"+handle+"/staking/delegations/:address", func(c *gin.Context) { - endpoint.GetStakingDelegationsForSpecificCoin(c, stakingAPI) + router.GET("/v3/"+handle+"/collections/:owner/collection/:collection_id", func(c *gin.Context) { + endpoint.GetCollectiblesForSpecificCollectionAndOwnerV3(c, api) + }) + router.GET("/v3/"+handle+"/collections/:owner", func(c *gin.Context) { + endpoint.GetCollectiblesForOwnerV3(c, api) + }) + router.GET("/v4/"+handle+"/collections/:owner/collection/:collection_id", func(c *gin.Context) { + endpoint.GetCollectiblesForSpecificCollectionAndOwner(c, api) }) } -func RegisterBatchAPI(root gin.IRouter) { - root.POST("v2/staking/delegations", func(c *gin.Context) { +func RegisterBatchAPI(router gin.IRouter) { + router.POST("/v2/staking/delegations", func(c *gin.Context) { endpoint.GetStakeDelegationsWithAllInfoForBatch(c, platform.StakeAPIs) }) - root.POST("v2/staking/list", middleware.CacheMiddleware(time.Hour, func(c *gin.Context) { + router.POST("/v2/staking/list", middleware.CacheMiddleware(time.Hour, func(c *gin.Context) { endpoint.GetStakeInfoForBatch(c, platform.StakeAPIs) })) - root.POST("/v3/collectibles/categories", func(c *gin.Context) { - endpoint.GetCollectionCategoriesFromListV3(c, platform.CollectionAPIs) + router.POST("/v3/collectibles/categories", func(c *gin.Context) { + endpoint.GetCollectionCategoriesFromListV3(c, platform.CollectionsAPIs) }) - root.POST("/v4/collectibles/categories", func(c *gin.Context) { - endpoint.GetCollectionCategoriesFromList(c, platform.CollectionAPIs) + router.POST("/v4/collectibles/categories", func(c *gin.Context) { + endpoint.GetCollectionCategoriesFromList(c, platform.CollectionsAPIs) }) - root.POST("/v2/tokens", func(c *gin.Context) { + router.POST("/v2/tokens", func(c *gin.Context) { endpoint.GetTokens(c, platform.TokensAPIs) }) } -// CustomAPI must be removed and all handlers needs to be migrated to the transactions, tokens api -func RegisterCustomAPI(root gin.IRouter, api blockatlas.Platform) { - customAPI, ok := api.(blockatlas.CustomAPI) - if !ok { - return - } - handle := api.Coin().Handle - - customRouterV1 := root.Group("/v1/" + handle) - customRouterV2 := root.Group("/v2/" + handle) - customAPI.RegisterRoutes(customRouterV1) - - if isForUtxoAPI(handle) { - customAPI.RegisterRoutes(customRouterV2) - } - -} - -func RegisterDomainAPI(root gin.IRouter) { - root.GET("/ns/lookup", endpoint.GetAddressByCoinAndDomain) - root.GET("v2/ns/lookup", endpoint.GetAddressByCoinAndDomainBatch) -} - -func RegisterBasicAPI(root gin.IRouter) { - root.GET("/", endpoint.GetStatus) - root.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) +func RegisterDomainAPI(router gin.IRouter) { + router.GET("/ns/lookup", endpoint.GetAddressByCoinAndDomain) + router.GET("/v2/ns/lookup", endpoint.GetAddressByCoinAndDomainBatch) } -func IsForCustomAPI(handle string) bool { - switch handle { - case coin.Gochain().Handle, - coin.Thundertoken().Handle, - coin.Classic().Handle, - coin.Poa().Handle, - coin.Callisto().Handle, - coin.Wanchain().Handle, - coin.Tomochain().Handle, - coin.Ethereum().Handle, - coin.Bitcoin().Handle, - coin.Litecoin().Handle, - coin.Bitcoincash().Handle, - coin.Zcash().Handle, - coin.Zcoin().Handle, - coin.Viacoin().Handle, - coin.Ravencoin().Handle, - coin.Groestlcoin().Handle, - coin.Zelcash().Handle, - coin.Decred().Handle, - coin.Digibyte().Handle, - coin.Dash().Handle, - coin.Doge().Handle, - coin.Qtum().Handle: - return true - default: - return false - } -} - -func isForUtxoAPI(handle string) bool { - switch handle { - case coin.Bitcoin().Handle, - coin.Litecoin().Handle, - coin.Bitcoincash().Handle, - coin.Zcash().Handle, - coin.Zcoin().Handle, - coin.Viacoin().Handle, - coin.Ravencoin().Handle, - coin.Groestlcoin().Handle, - coin.Zelcash().Handle, - coin.Decred().Handle, - coin.Digibyte().Handle, - coin.Dash().Handle, - coin.Doge().Handle, - coin.Qtum().Handle: - return true - default: - return false - } +func RegisterBasicAPI(router gin.IRouter) { + router.GET("/", endpoint.GetStatus) + router.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) } diff --git a/pkg/blockatlas/errors.go b/pkg/blockatlas/errors.go index 6eafa7d3b..46dd6d354 100644 --- a/pkg/blockatlas/errors.go +++ b/pkg/blockatlas/errors.go @@ -2,11 +2,16 @@ package blockatlas import "errors" -// ErrSourceConn signals that the connection to the source API failed -var ErrSourceConn = errors.New("connection to servers failed") +var ( + // ErrSourceConn signals that the connection to the source API failed + ErrSourceConn = errors.New("connection to servers failed") -// ErrInvalidAddr signals that the requested address is invalid -var ErrInvalidAddr = errors.New("invalid address") + // ErrInvalidAddr signals that the requested address is invalid + ErrInvalidAddr = errors.New("invalid address") -// ErrNotFound signals that the resource has not been found -var ErrNotFound = errors.New("not found") + // ErrNotFound signals that the resource has not been found + ErrNotFound = errors.New("not found") + + // ErrInvalidKey signals that the requested key is invalid + ErrInvalidKey = errors.New("invalid key") +) diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 43c23e84b..1ddf2c9e9 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -1,7 +1,6 @@ package blockatlas import ( - "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/coin" ) @@ -11,7 +10,14 @@ type ( Coin() coin.Coin } - // TxAPI provides transaction lookups + // BlockAPI provides block information and lookups + BlockAPI interface { + Platform + CurrentBlockNumber() (int64, error) + GetBlockByNumber(num int64) (*Block, error) + } + + // TxAPI provides transaction lookups based on address TxAPI interface { Platform GetTxsByAddress(address string) (TxPage, error) @@ -23,23 +29,16 @@ type ( GetTokenTxsByAddress(address, token string) (TxPage, error) } - // TokenAPI provides token lookups - TokenAPI interface { - Platform - GetTokenListByAddress(address string) (TokenPage, error) + // TxUtxoAPI provides transaction lookup based on address and XPUB (Bitcoin-style) + TxUtxoAPI interface { + TxAPI + GetTxsByXpub(xpub string) (TxPage, error) } - // BlockAPI provides block information and lookups - BlockAPI interface { + // TokensAPI provides token lookups + TokensAPI interface { Platform - CurrentBlockNumber() (int64, error) - GetBlockByNumber(num int64) (*Block, error) - } - - // AddressAPI provides address information - AddressAPI interface { - Platform - GetAddressesFromXpub(xpub string) ([]string, error) + GetTokenListByAddress(address string) (TokenPage, error) } // StakingAPI provides staking information @@ -51,7 +50,7 @@ type ( GetDelegations(address string) (DelegationsPage, error) } - CollectionAPI interface { + CollectionsAPI interface { Platform GetCollections(owner string) (CollectionPage, error) GetCollectibles(owner, collectibleID string) (CollectiblePage, error) @@ -60,20 +59,16 @@ type ( GetCollectiblesV3(owner, collectibleID string) (CollectiblePageV3, error) } - // CustomAPI provides custom HTTP routes - CustomAPI interface { - Platform - RegisterRoutes(router gin.IRouter) - } - // NamingServiceAPI provides public name service domains HTTP routes NamingServiceAPI interface { Platform Lookup(coins []uint64, name string) ([]Resolved, error) } -) -type Platforms map[string]Platform + Platforms map[string]Platform + + CollectionsAPIs map[uint]CollectionsAPI +) func (ps Platforms) GetPlatformList() []Platform { platforms := make([]Platform, 0) diff --git a/platform/bitcoin/transaction.go b/platform/bitcoin/transaction.go index 7301e4721..25b98ec21 100644 --- a/platform/bitcoin/transaction.go +++ b/platform/bitcoin/transaction.go @@ -1,65 +1,35 @@ package bitcoin import ( - "net/http" "sort" mapset "github.com/deckarep/golang-set" - "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" ) -// @Summary Get xpub transactions -// @ID xpub -// @Description Get transactions from xpub address -// @Accept json -// @Produce json -// @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 -// @Router /v1/{coin}/xpub/{xpub} [get] -func (p *Platform) RegisterRoutes(router gin.IRouter) { - router.GET("/xpub/:key", func(c *gin.Context) { - p.handleXpubRoute(c) - }) - - router.GET("/transactions/xpub/:key", func(c *gin.Context) { - p.handleXpubRoute(c) - }) - - router.GET("/address/:address", func(c *gin.Context) { - p.handleAddressRoute(c) - }) -} - -func (p *Platform) handleAddressRoute(c *gin.Context) { - address := c.Param("address") - txs, ok := p.getTxsByAddress(address) +func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + txs, err := p.getTxsByAddress(address) + if err != nil { + return nil, err + } txPage := blockatlas.TxPage(txs) sort.Sort(txPage) - if ok != nil { - c.JSON(http.StatusInternalServerError, ok) - return - } - c.JSON(http.StatusOK, &txPage) + return txPage, nil } -func (p *Platform) handleXpubRoute(c *gin.Context) { - xpub := c.Param("key") - txs, ok := p.getTxsByXPub(xpub) +func (p *Platform) GetTxsByXpub(xpub string) (blockatlas.TxPage, error) { + txs, err := p.getTxsByXpub(xpub) + if err != nil { + return nil, err + } txPage := blockatlas.TxPage(txs) sort.Sort(txPage) - if ok != nil { - c.JSON(http.StatusInternalServerError, ok) - return - } - c.JSON(http.StatusOK, &txPage) + return txPage, nil } -func (p *Platform) getTxsByXPub(xpub string) ([]blockatlas.Tx, error) { +func (p *Platform) getTxsByXpub(xpub string) ([]blockatlas.Tx, error) { sourceTxs, err := p.client.GetTransactionsByXpub(xpub) if err != nil { diff --git a/platform/ethereum/transaction.go b/platform/ethereum/transaction.go index 1be749ca0..997a60181 100644 --- a/platform/ethereum/transaction.go +++ b/platform/ethereum/transaction.go @@ -1,45 +1,13 @@ package ethereum import ( - "net/http" - "sort" - - "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" ) -func (p *Platform) RegisterRoutes(router gin.IRouter) { - router.GET("/:address", func(c *gin.Context) { - p.getTransactions(c) - }) -} - -func (p *Platform) getTransactions(c *gin.Context) { - token := c.Query("token") - address := c.Param("address") - var page blockatlas.TxPage - var err error - - if token != "" { - page, err = p.client.GetTokenTxs(address, token, p.CoinIndex) - } else { - page, err = p.client.GetTransactions(address, p.CoinIndex) - } - - if apiError(c, err) { - return - } - - sort.Sort(page) - c.JSON(http.StatusOK, &page) +func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + return p.client.GetTransactions(address, p.CoinIndex) } -func apiError(c *gin.Context, err error) bool { - if err != nil { - logger.Error(err, "Unhandled error") - c.AbortWithStatus(http.StatusInternalServerError) - return true - } - return false +func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { + return p.client.GetTokenTxs(address, token, p.CoinIndex) } diff --git a/platform/ethereum/transaction_test.go b/platform/ethereum/transaction_test.go new file mode 100644 index 000000000..abf0c312b --- /dev/null +++ b/platform/ethereum/transaction_test.go @@ -0,0 +1,77 @@ +package ethereum + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" +) + +func TestPlatform_GetTokenTxsByAddress(t *testing.T) { + p := Platform{ + client: getTxClientMock(), + } + + resp, err := p.GetTxsByAddress("A") + assert.Nil(t, err) + assert.Equal(t, page, resp) +} + +func TestPlatform_GetTxsByAddress(t *testing.T) { + p := Platform{ + client: getTxClientMock(), + } + + resp, err := p.GetTokenTxsByAddress("A", "") + assert.Nil(t, err) + assert.Equal(t, page, resp) +} + +func getTxClientMock() EthereumClient { + return &c +} + +var tx = blockatlas.Tx{ + ID: "1", + Coin: 60, + From: "A", + To: "B", + Fee: "", + Date: 0, + Block: 0, + Status: "", + Error: "", + Sequence: 0, + Type: "", + Inputs: nil, + Outputs: nil, + Direction: "", + Memo: "", + Meta: nil, +} + +var page = blockatlas.TxPage([]blockatlas.Tx{tx}) + +type Client string + +var c Client + +func (c Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) { + txs := make([]blockatlas.Tx, 0) + txs = append(txs, tx) + return txs, nil +} + +func (c Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas.TxPage, error) { + txs := make([]blockatlas.Tx, 0) + txs = append(txs, tx) + return txs, nil +} +func (c Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) { + return blockatlas.TokenPage{}, nil +} +func (c Client) GetCurrentBlockNumber() (int64, error) { + return 0, nil +} +func (c Client) GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, error) { + return nil, nil +} diff --git a/platform/platform.go b/platform/platform.go index b60a96850..287eaa269 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -38,8 +38,6 @@ const ( allPlatformsHandle = "all" ) -var CollectionsWhitelist map[uint]bool - func GetVar(name string) string { return viper.GetString(name) } @@ -58,7 +56,7 @@ func GetHandle(coinId uint) string { return coin.Coins[coinId].Handle } -func getPlatformMap() blockatlas.Platforms { +func getAllHandlers() blockatlas.Platforms { return blockatlas.Platforms{ coin.Fio().Handle: fio.Init(GetApiVar(coin.FIO)), coin.Aion().Handle: aion.Init(GetApiVar(coin.AION)), @@ -111,7 +109,22 @@ func getPlatformMap() blockatlas.Platforms { } } -func InitCollectionsWhitelist() { - CollectionsWhitelist = make(map[uint]bool) - CollectionsWhitelist[coin.Ethereum().ID] = true +func getCollectionsHandlers() blockatlas.CollectionsAPIs { + return blockatlas.CollectionsAPIs { + coin.ETH: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), + } +} + +func getNamingHandlers() map[uint]blockatlas.NamingServiceAPI { + return map[uint]blockatlas.NamingServiceAPI { + coin.ETH: ethereum.Init(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH)), + coin.CLO: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO)), + coin.TOMO: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), + coin.GO: ethereum.Init(coin.GO, GetApiVar(coin.GO), GetRpcVar(coin.GO)), + coin.ETC: ethereum.Init(coin.ETC, GetApiVar(coin.ETC), GetRpcVar(coin.ETC)), + coin.POA: ethereum.Init(coin.POA, GetApiVar(coin.POA), GetRpcVar(coin.POA)), + coin.TT: ethereum.Init(coin.TT, GetApiVar(coin.TT), GetRpcVar(coin.TT)), + coin.FIO: fio.Init(GetApiVar(coin.FIO)), + coin.ZIL: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL), GetVar("zilliqa.lookup")), + } } diff --git a/platform/registry.go b/platform/registry.go index 4c6cecbfb..b7bc91a20 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -14,24 +14,21 @@ var ( // BlockAPIs contain platforms with block services BlockAPIs map[string]blockatlas.BlockAPI + // TokensAPIs contain platforms with token services + TokensAPIs map[uint]blockatlas.TokensAPI + // StakeAPIs contain platforms with staking services StakeAPIs map[string]blockatlas.StakeAPI - // CustomAPIs contain platforms with custom HTTP services - CustomAPIs map[string]blockatlas.CustomAPI + // CollectionsAPIs contain platforms which collections services + CollectionsAPIs blockatlas.CollectionsAPIs // NamingAPIs contain platforms which support naming services - NamingAPIs map[uint64]blockatlas.NamingServiceAPI - - // CollectionAPIs contain platforms which collections services - CollectionAPIs map[uint]blockatlas.CollectionAPI - - // TokensAPIs contain platforms with token services - TokensAPIs map[uint]blockatlas.TokenAPI + NamingAPIs map[uint]blockatlas.NamingServiceAPI ) func getActivePlatforms(handle string) []blockatlas.Platform { - platforms := getPlatformMap() + platforms := getAllHandlers() logger.Info("Platform API setup with: ", logger.Params{"handle": handle}) if handle == allPlatformsHandle { @@ -50,16 +47,10 @@ func getActivePlatforms(handle string) []blockatlas.Platform { func Init(platformHandle string) { platformList := getActivePlatforms(platformHandle) - // white list of collection api coins (only ETH now) - InitCollectionsWhitelist() - Platforms = make(map[string]blockatlas.Platform) BlockAPIs = make(map[string]blockatlas.BlockAPI) + TokensAPIs = make(map[uint]blockatlas.TokensAPI) StakeAPIs = make(map[string]blockatlas.StakeAPI) - CustomAPIs = make(map[string]blockatlas.CustomAPI) - NamingAPIs = make(map[uint64]blockatlas.NamingServiceAPI) - CollectionAPIs = make(map[uint]blockatlas.CollectionAPI) - TokensAPIs = make(map[uint]blockatlas.TokenAPI) for _, platform := range platformList { handle := platform.Coin().Handle @@ -84,20 +75,14 @@ func Init(platformHandle string) { if blockAPI, ok := platform.(blockatlas.BlockAPI); ok { BlockAPIs[handle] = blockAPI } + if tokenAPI, ok := platform.(blockatlas.TokensAPI); ok { + TokensAPIs[platform.Coin().ID] = tokenAPI + } if stakeAPI, ok := platform.(blockatlas.StakeAPI); ok { StakeAPIs[handle] = stakeAPI } - if customAPI, ok := platform.(blockatlas.CustomAPI); ok { - CustomAPIs[handle] = customAPI - } - if namingAPI, ok := platform.(blockatlas.NamingServiceAPI); ok { - NamingAPIs[uint64(platform.Coin().ID)] = namingAPI - } - if collectionAPI, ok := platform.(blockatlas.CollectionAPI); ok && CollectionsWhitelist[platform.Coin().ID] { - CollectionAPIs[platform.Coin().ID] = collectionAPI - } - if tokenAPI, ok := platform.(blockatlas.TokenAPI); ok { - TokensAPIs[platform.Coin().ID] = tokenAPI - } } + + CollectionsAPIs = getCollectionsHandlers() + NamingAPIs = getNamingHandlers() } diff --git a/services/domains/domains.go b/services/domains/domains.go index 1ba1a5a05..38dfe642f 100644 --- a/services/domains/domains.go +++ b/services/domains/domains.go @@ -11,7 +11,7 @@ import ( ) // TLDMapping Mapping of name TLD's to coin where they are handled -var TLDMapping = map[string]uint64{ +var TLDMapping = map[string]uint{ ".eth": CoinType.ETH, ".xyz": CoinType.ETH, ".luxe": CoinType.ETH, From a1f63d0d421afda51c269618ad41bd258f8b3c86 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Tue, 5 May 2020 17:30:49 +0300 Subject: [PATCH 276/506] Add new router with cache & update swaggger docs (#1074) --- api/endpoint/staking.go | 46 +++++ api/endpoint/transaction.go | 14 +- api/registry.go | 3 + docs/docs.go | 388 ++++++++++++++++++++++++++++++++++-- docs/swagger.json | 386 +++++++++++++++++++++++++++++++++-- docs/swagger.yaml | 264 ++++++++++++++++++++++-- 6 files changed, 1046 insertions(+), 55 deletions(-) diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index 906a63341..c5c9a7104 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -8,6 +8,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/errors" services "github.com/trustwallet/blockatlas/services/assets" "net/http" + "strings" ) type ( @@ -96,6 +97,51 @@ func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &batch}) } +// @Summary Get staking info by coin ID +// @ID batch_info +// @Description Get staking info by coin ID +// @Produce json +// @Tags Staking +// @Param coins query string true "List of coins" +// @Success 200 {array} blockatlas.DelegationsBatchPage +// @Failure 400 {object} model.ErrorResponse +// @Router /v3/staking/list [get] +func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { + coinsRequest := c.Query("coins") + if coinsRequest == "" { + c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, errors.E("empty coins list"))) + return + } + + coinsRaw := strings.Split(coinsRequest, ",") + + coins, err := sliceAtoi(coinsRaw) + if err != nil { + c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, err)) + return + } + + var reqs CoinsRequest + for _, c := range coins { + reqs = append(reqs, CoinBatchRequest{Coin: uint(c)}) + } + + batch := make(blockatlas.StakingBatchPage, 0) + for _, r := range reqs { + requestCoin, ok := coin.Coins[r.Coin] + if !ok { + continue + } + p, ok := apis[requestCoin.Handle] + if !ok { + continue + } + staking := getStakingResponse(p) + batch = append(batch, staking) + } + c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &batch}) +} + // @Summary Get Validators // @ID validators // @Description Get validators from the address diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 87b02166a..530b1488e 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -9,18 +9,6 @@ import ( "sort" ) -// @Summary Get Transactions -// @ID tx_v2 -// @Description Get transactions from the address -// @Accept json -// @Produce json -// @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 -// @Failure 500 {object} model.ErrorResponse -// @Router /v2/{coin}/transactions/{address} [get] - // @Summary Get Transactions // @ID tx_v1 // @Description Get transactions from the address @@ -96,7 +84,7 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b // @Tags Transactions // @Param coin path string true "the coin name" default(bitcoin) // @Param xpub path string true "the xpub key" default(zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC) -// @Failure 500 {object} middleware.ApiError +// @Failure 500 {object} model.ErrorResponse // @Router /v1/{coin}/xpub/{xpub} [get] func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { xPubKey := c.Param("xpub") diff --git a/api/registry.go b/api/registry.go index 17bd5ba89..2346249c3 100644 --- a/api/registry.go +++ b/api/registry.go @@ -77,6 +77,9 @@ func RegisterCollectionsAPI(router gin.IRouter, api blockatlas.CollectionsAPI) { } func RegisterBatchAPI(router gin.IRouter) { + router.GET("/v3/staking/list", middleware.CacheMiddleware(time.Hour*10, func(c *gin.Context) { + endpoint.GetStakeInfoForCoins(c, platform.StakeAPIs) + })) router.POST("/v2/staking/delegations", func(c *gin.Context) { endpoint.GetStakeDelegationsWithAllInfoForBatch(c, platform.StakeAPIs) }) diff --git a/docs/docs.go b/docs/docs.go index 41f83f6ee..45ca2468c 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-05-02 05:07:02.305717 +0300 MSK m=+0.083111694 +// 2020-05-05 16:09:19.422499 +0300 MSK m=+0.199865137 package docs @@ -67,9 +67,152 @@ var doc = `{ } } }, + "/v1/market/charts": { + "get": { + "description": "Get the charts data from an market and coin/token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Market" + ], + "summary": "Get charts data for a specific coin", + "operationId": "get_charts_data", + "parameters": [ + { + "type": "integer", + "default": 60, + "description": "Coin ID", + "name": "coin", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Token ID", + "name": "token", + "in": "query" + }, + { + "type": "integer", + "default": 1574483028, + "description": "Start timestamp", + "name": "time_start", + "in": "query" + }, + { + "type": "integer", + "default": 64, + "description": "Max number of items in result prices array", + "name": "max_items", + "in": "query" + }, + { + "type": "string", + "default": "USD", + "description": "The currency to show charts", + "name": "currency", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoint.ChartData" + } + } + } + } + }, + "/v1/market/info": { + "get": { + "description": "Get the charts coin info data from an market and coin/contract", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Market" + ], + "summary": "Get charts coin info data for a specific coin", + "operationId": "get_charts_coin_info", + "parameters": [ + { + "type": "integer", + "default": 60, + "description": "Coin ID", + "name": "coin", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Token ID", + "name": "token", + "in": "query" + }, + { + "type": "string", + "default": "USD", + "description": "The currency to show coin info in", + "name": "currency", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoint.ChartCoinInfo" + } + } + } + } + }, + "/v1/market/ticker": { + "post": { + "description": "Get the ticker values from many market and coin/token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Market" + ], + "summary": "Get ticker values for a specific market", + "operationId": "get_tickers", + "parameters": [ + { + "description": "Ticker", + "name": "tickers", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/endpoint.TickerRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoint.Tickers" + } + } + } + } + }, "/v1/{coin}/xpub/{xpub}": { "get": { - "description": "Get transactions from xpub address", + "description": "Get transactions from XPUB address", "consumes": [ "application/json" ], @@ -79,8 +222,8 @@ var doc = `{ "tags": [ "Transactions" ], - "summary": "Get xpub transactions", - "operationId": "xpub", + "summary": "Get Transactions by XPUB", + "operationId": "txxpub_v1", "parameters": [ { "type": "string", @@ -93,17 +236,17 @@ var doc = `{ { "type": "string", "default": "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - "description": "the xpub address", + "description": "the xpub key", "name": "xpub", "in": "path", "required": true } ], "responses": { - "200": { - "description": "OK", + "500": { + "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/blockatlas.TxPage" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -440,7 +583,7 @@ var doc = `{ }, "/v2/{coin}/transactions/xpub/{xpub}": { "get": { - "description": "Get transactions from xpub address", + "description": "Get transactions from XPUB address", "consumes": [ "application/json" ], @@ -450,8 +593,8 @@ var doc = `{ "tags": [ "Transactions" ], - "summary": "Get xpub transactions", - "operationId": "xpubV2", + "summary": "Get Transactions by XPUB", + "operationId": "txxpub_v2", "parameters": [ { "type": "string", @@ -464,17 +607,17 @@ var doc = `{ { "type": "string", "default": "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - "description": "the xpub address", + "description": "the xpub key", "name": "xpub", "in": "path", "required": true } ], "responses": { - "200": { - "description": "OK", + "500": { + "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/blockatlas.TxPage" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -528,6 +671,45 @@ var doc = `{ } } }, + "/v3/staking/list": { + "get": { + "description": "Get staking info by coin ID", + "produces": [ + "application/json" + ], + "tags": [ + "Staking" + ], + "summary": "Get staking info by coin ID", + "operationId": "batch_info", + "parameters": [ + { + "type": "string", + "description": "List of coins", + "name": "coins", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.DelegationsBatchPage" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.ErrorResponse" + } + } + } + } + }, "/v4/collectibles/categories": { "post": { "description": "Get collection categories", @@ -927,6 +1109,182 @@ var doc = `{ "$ref": "#/definitions/endpoint.AddressBatchRequest" } }, + "endpoint.ChartCoinInfo": { + "type": "object", + "properties": { + "circulating_supply": { + "type": "number" + }, + "info": { + "type": "object", + "$ref": "#/definitions/endpoint.CoinInfo" + }, + "market_cap": { + "type": "number" + }, + "provider": { + "type": "string" + }, + "total_supply": { + "type": "number" + }, + "volume_24": { + "type": "number" + } + } + }, + "endpoint.ChartData": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "prices": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.ChartPrice" + } + }, + "provider": { + "type": "string" + } + } + }, + "endpoint.ChartPrice": { + "type": "object", + "properties": { + "date": { + "type": "integer" + }, + "price": { + "type": "number" + } + } + }, + "endpoint.Coin": { + "type": "object", + "properties": { + "coin": { + "type": "integer" + }, + "token_id": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "endpoint.CoinInfo": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "explorer": { + "type": "string" + }, + "name": { + "type": "string" + }, + "short_description": { + "type": "string" + }, + "socials": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.SocialLink" + } + }, + "source_code": { + "type": "string" + }, + "website": { + "type": "string" + }, + "white_paper": { + "type": "string" + } + } + }, + "endpoint.SocialLink": { + "type": "object", + "properties": { + "handle": { + "type": "string" + }, + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "endpoint.Ticker": { + "type": "object", + "properties": { + "coin": { + "type": "integer" + }, + "coin_name": { + "type": "string" + }, + "error": { + "type": "string" + }, + "last_update": { + "type": "string" + }, + "price": { + "type": "object", + "$ref": "#/definitions/endpoint.TickerPrice" + }, + "token_id": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "endpoint.TickerPrice": { + "type": "object", + "properties": { + "change_24h": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "value": { + "type": "number" + } + } + }, + "endpoint.TickerRequest": { + "type": "object", + "properties": { + "assets": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.Coin" + } + }, + "currency": { + "type": "string" + } + } + }, + "endpoint.Tickers": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.Ticker" + } + }, "model.ErrorDetails": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index a3f3b20ed..9689467c0 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -46,9 +46,152 @@ } } }, + "/v1/market/charts": { + "get": { + "description": "Get the charts data from an market and coin/token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Market" + ], + "summary": "Get charts data for a specific coin", + "operationId": "get_charts_data", + "parameters": [ + { + "type": "integer", + "default": 60, + "description": "Coin ID", + "name": "coin", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Token ID", + "name": "token", + "in": "query" + }, + { + "type": "integer", + "default": 1574483028, + "description": "Start timestamp", + "name": "time_start", + "in": "query" + }, + { + "type": "integer", + "default": 64, + "description": "Max number of items in result prices array", + "name": "max_items", + "in": "query" + }, + { + "type": "string", + "default": "USD", + "description": "The currency to show charts", + "name": "currency", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoint.ChartData" + } + } + } + } + }, + "/v1/market/info": { + "get": { + "description": "Get the charts coin info data from an market and coin/contract", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Market" + ], + "summary": "Get charts coin info data for a specific coin", + "operationId": "get_charts_coin_info", + "parameters": [ + { + "type": "integer", + "default": 60, + "description": "Coin ID", + "name": "coin", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Token ID", + "name": "token", + "in": "query" + }, + { + "type": "string", + "default": "USD", + "description": "The currency to show coin info in", + "name": "currency", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoint.ChartCoinInfo" + } + } + } + } + }, + "/v1/market/ticker": { + "post": { + "description": "Get the ticker values from many market and coin/token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Market" + ], + "summary": "Get ticker values for a specific market", + "operationId": "get_tickers", + "parameters": [ + { + "description": "Ticker", + "name": "tickers", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/endpoint.TickerRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoint.Tickers" + } + } + } + } + }, "/v1/{coin}/xpub/{xpub}": { "get": { - "description": "Get transactions from xpub address", + "description": "Get transactions from XPUB address", "consumes": [ "application/json" ], @@ -58,8 +201,8 @@ "tags": [ "Transactions" ], - "summary": "Get xpub transactions", - "operationId": "xpub", + "summary": "Get Transactions by XPUB", + "operationId": "txxpub_v1", "parameters": [ { "type": "string", @@ -72,17 +215,17 @@ { "type": "string", "default": "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - "description": "the xpub address", + "description": "the xpub key", "name": "xpub", "in": "path", "required": true } ], "responses": { - "200": { - "description": "OK", + "500": { + "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/blockatlas.TxPage" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -419,7 +562,7 @@ }, "/v2/{coin}/transactions/xpub/{xpub}": { "get": { - "description": "Get transactions from xpub address", + "description": "Get transactions from XPUB address", "consumes": [ "application/json" ], @@ -429,8 +572,8 @@ "tags": [ "Transactions" ], - "summary": "Get xpub transactions", - "operationId": "xpubV2", + "summary": "Get Transactions by XPUB", + "operationId": "txxpub_v2", "parameters": [ { "type": "string", @@ -443,17 +586,17 @@ { "type": "string", "default": "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - "description": "the xpub address", + "description": "the xpub key", "name": "xpub", "in": "path", "required": true } ], "responses": { - "200": { - "description": "OK", + "500": { + "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/blockatlas.TxPage" + "$ref": "#/definitions/model.ErrorResponse" } } } @@ -507,6 +650,45 @@ } } }, + "/v3/staking/list": { + "get": { + "description": "Get staking info by coin ID", + "produces": [ + "application/json" + ], + "tags": [ + "Staking" + ], + "summary": "Get staking info by coin ID", + "operationId": "batch_info", + "parameters": [ + { + "type": "string", + "description": "List of coins", + "name": "coins", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.DelegationsBatchPage" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/model.ErrorResponse" + } + } + } + } + }, "/v4/collectibles/categories": { "post": { "description": "Get collection categories", @@ -906,6 +1088,182 @@ "$ref": "#/definitions/endpoint.AddressBatchRequest" } }, + "endpoint.ChartCoinInfo": { + "type": "object", + "properties": { + "circulating_supply": { + "type": "number" + }, + "info": { + "type": "object", + "$ref": "#/definitions/endpoint.CoinInfo" + }, + "market_cap": { + "type": "number" + }, + "provider": { + "type": "string" + }, + "total_supply": { + "type": "number" + }, + "volume_24": { + "type": "number" + } + } + }, + "endpoint.ChartData": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "prices": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.ChartPrice" + } + }, + "provider": { + "type": "string" + } + } + }, + "endpoint.ChartPrice": { + "type": "object", + "properties": { + "date": { + "type": "integer" + }, + "price": { + "type": "number" + } + } + }, + "endpoint.Coin": { + "type": "object", + "properties": { + "coin": { + "type": "integer" + }, + "token_id": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "endpoint.CoinInfo": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "explorer": { + "type": "string" + }, + "name": { + "type": "string" + }, + "short_description": { + "type": "string" + }, + "socials": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.SocialLink" + } + }, + "source_code": { + "type": "string" + }, + "website": { + "type": "string" + }, + "white_paper": { + "type": "string" + } + } + }, + "endpoint.SocialLink": { + "type": "object", + "properties": { + "handle": { + "type": "string" + }, + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "endpoint.Ticker": { + "type": "object", + "properties": { + "coin": { + "type": "integer" + }, + "coin_name": { + "type": "string" + }, + "error": { + "type": "string" + }, + "last_update": { + "type": "string" + }, + "price": { + "type": "object", + "$ref": "#/definitions/endpoint.TickerPrice" + }, + "token_id": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "endpoint.TickerPrice": { + "type": "object", + "properties": { + "change_24h": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "value": { + "type": "number" + } + } + }, + "endpoint.TickerRequest": { + "type": "object", + "properties": { + "assets": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.Coin" + } + }, + "currency": { + "type": "string" + } + } + }, + "endpoint.Tickers": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.Ticker" + } + }, "model.ErrorDetails": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 55ffb2eb0..986373a42 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -207,6 +207,121 @@ definitions: items: $ref: '#/definitions/endpoint.AddressBatchRequest' type: array + endpoint.ChartCoinInfo: + properties: + circulating_supply: + type: number + info: + $ref: '#/definitions/endpoint.CoinInfo' + type: object + market_cap: + type: number + provider: + type: string + total_supply: + type: number + volume_24: + type: number + type: object + endpoint.ChartData: + properties: + error: + type: string + prices: + items: + $ref: '#/definitions/endpoint.ChartPrice' + type: array + provider: + type: string + type: object + endpoint.ChartPrice: + properties: + date: + type: integer + price: + type: number + type: object + endpoint.Coin: + properties: + coin: + type: integer + token_id: + type: string + type: + type: string + type: object + endpoint.CoinInfo: + properties: + description: + type: string + explorer: + type: string + name: + type: string + short_description: + type: string + socials: + items: + $ref: '#/definitions/endpoint.SocialLink' + type: array + source_code: + type: string + website: + type: string + white_paper: + type: string + type: object + endpoint.SocialLink: + properties: + handle: + type: string + name: + type: string + url: + type: string + type: object + endpoint.Ticker: + properties: + coin: + type: integer + coin_name: + type: string + error: + type: string + last_update: + type: string + price: + $ref: '#/definitions/endpoint.TickerPrice' + type: object + token_id: + type: string + type: + type: string + type: object + endpoint.TickerPrice: + properties: + change_24h: + type: number + currency: + type: string + provider: + type: string + value: + type: number + type: object + endpoint.TickerRequest: + properties: + assets: + items: + $ref: '#/definitions/endpoint.Coin' + type: array + currency: + type: string + type: object + endpoint.Tickers: + items: + $ref: '#/definitions/endpoint.Ticker' + type: array model.ErrorDetails: properties: code: @@ -284,8 +399,8 @@ paths: get: consumes: - application/json - description: Get transactions from xpub address - operationId: xpub + description: Get transactions from XPUB address + operationId: txxpub_v1 parameters: - default: bitcoin description: the coin name @@ -294,21 +409,118 @@ paths: required: true type: string - default: zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC - description: the xpub address + description: the xpub key in: path name: xpub required: true type: string produces: - application/json + responses: + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/model.ErrorResponse' + summary: Get Transactions by XPUB + tags: + - Transactions + /v1/market/charts: + get: + consumes: + - application/json + description: Get the charts data from an market and coin/token + operationId: get_charts_data + parameters: + - default: 60 + description: Coin ID + in: query + name: coin + required: true + type: integer + - description: Token ID + in: query + name: token + type: string + - default: 1574483028 + description: Start timestamp + in: query + name: time_start + type: integer + - default: 64 + description: Max number of items in result prices array + in: query + name: max_items + type: integer + - default: USD + description: The currency to show charts + in: query + name: currency + type: string + produces: + - application/json responses: "200": description: OK schema: - $ref: '#/definitions/blockatlas.TxPage' - summary: Get xpub transactions + $ref: '#/definitions/endpoint.ChartData' + summary: Get charts data for a specific coin tags: - - Transactions + - Market + /v1/market/info: + get: + consumes: + - application/json + description: Get the charts coin info data from an market and coin/contract + operationId: get_charts_coin_info + parameters: + - default: 60 + description: Coin ID + in: query + name: coin + required: true + type: integer + - description: Token ID + in: query + name: token + type: string + - default: USD + description: The currency to show coin info in + in: query + name: currency + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/endpoint.ChartCoinInfo' + summary: Get charts coin info data for a specific coin + tags: + - Market + /v1/market/ticker: + post: + consumes: + - application/json + description: Get the ticker values from many market and coin/token + operationId: get_tickers + parameters: + - description: Ticker + in: body + name: tickers + required: true + schema: + $ref: '#/definitions/endpoint.TickerRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/endpoint.Tickers' + summary: Get ticker values for a specific market + tags: + - Market /v2/{coin}/staking/delegations/{address}: get: consumes: @@ -439,8 +651,8 @@ paths: get: consumes: - application/json - description: Get transactions from xpub address - operationId: xpubV2 + description: Get transactions from XPUB address + operationId: txxpub_v2 parameters: - default: bitcoin description: the coin name @@ -449,7 +661,7 @@ paths: required: true type: string - default: zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC - description: the xpub address + description: the xpub key in: path name: xpub required: true @@ -457,11 +669,11 @@ paths: produces: - application/json responses: - "200": - description: OK + "500": + description: Internal Server Error schema: - $ref: '#/definitions/blockatlas.TxPage' - summary: Get xpub transactions + $ref: '#/definitions/model.ErrorResponse' + summary: Get Transactions by XPUB tags: - Transactions /v2/ns/lookup: @@ -564,6 +776,32 @@ paths: summary: 'Get list of tokens by map: coin -> [addresses]' tags: - Transactions + /v3/staking/list: + get: + description: Get staking info by coin ID + operationId: batch_info + parameters: + - description: List of coins + in: query + name: coins + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/blockatlas.DelegationsBatchPage' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/model.ErrorResponse' + summary: Get staking info by coin ID + tags: + - Staking /v4/{coin}/collections/{owner}/collection/{collection_id}: get: consumes: From 053032dc8b5f965c8cac6453b5b7c823f847765d Mon Sep 17 00:00:00 2001 From: Tezos Ukraine <58071967+tezukr@users.noreply.github.com> Date: Wed, 6 May 2020 09:08:47 +0300 Subject: [PATCH 277/506] Switch from tezos.org.ua api to giganode.io (#1073) --- config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.yml b/config.yml index 49cdd6913..0f8bf4ec3 100644 --- a/config.yml +++ b/config.yml @@ -64,7 +64,7 @@ kin: # [XTZ] Tezos: https://tezos.com tezos: api: https://api.tzstats.com/explorer # https://tzstats.com/docs/api/index.html#introduction - rpc: https://mainnet.tezos.org.ua + rpc: https://mainnet-tezos.giganode.io # [ETH] Ethereum: https://ethereum.org ethereum: From 262edda39bc3e5509a4b73f06267f6c4f5b5ca9c Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Thu, 7 May 2020 16:05:28 -0700 Subject: [PATCH 278/506] Add min delegation (#1075) --- services/assets/model.go | 5 +++ services/assets/stake.go | 28 +++++++++------- services/assets/stake_test.go | 60 +++++++++++++++++++++++++++++------ 3 files changed, 72 insertions(+), 21 deletions(-) diff --git a/services/assets/model.go b/services/assets/model.go index 6d5ec909b..28ad72a16 100644 --- a/services/assets/model.go +++ b/services/assets/model.go @@ -12,6 +12,7 @@ type ( Website string `json:"website"` Payout ValidatorPayout `json:"payout,omitempty"` Status ValidatorStatus `json:"status,omitempty"` + Staking StakingInfo `json:"staking,omitempty"` } ValidatorPayout struct { @@ -21,6 +22,10 @@ type ( ValidatorStatus struct { Disabled bool `json:"disabled"` } + + StakingInfo struct { + MinDelegation float64 `json:"minDelegation"` + } ) func (av AssetValidators) toMap() AssetValidatorMap { diff --git a/services/assets/stake.go b/services/assets/stake.go index 01fd35202..5abac0507 100644 --- a/services/assets/stake.go +++ b/services/assets/stake.go @@ -4,6 +4,7 @@ import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/numbers" "sort" "time" ) @@ -40,6 +41,7 @@ func GetActiveValidators(api blockatlas.StakeAPI) (blockatlas.StakeValidators, e return results, nil } +// Get validators from assets repository and RPC func GetValidators(api blockatlas.StakeAPI) (AssetValidators, blockatlas.ValidatorPage, error) { assetsValidators, err := requestValidatorsInfo(api.Coin()) if err != nil { @@ -53,10 +55,10 @@ func GetValidators(api blockatlas.StakeAPI) (AssetValidators, blockatlas.Validat return assetsValidators, validators, nil } -func normalizeValidators(assets AssetValidators, validators []blockatlas.Validator, coin coin.Coin) blockatlas.StakeValidators { +func normalizeValidators(assetsValidators AssetValidators, rpcValidators []blockatlas.Validator, coin coin.Coin) blockatlas.StakeValidators { results := make(blockatlas.StakeValidators, 0) - assetsMap := assets.toMap() - for _, v := range validators { + assetsMap := assetsValidators.toMap() + for _, v := range rpcValidators { asset, ok := assetsMap[v.ID] if !ok { continue @@ -70,17 +72,19 @@ func normalizeValidators(assets AssetValidators, validators []blockatlas.Validat return results } -func normalizeValidator(plainValidator blockatlas.Validator, validator AssetValidator, coin coin.Coin) blockatlas.StakeValidator { - details := plainValidator.Details - details.Reward.Annual = calculateAnnual(details.Reward.Annual, validator.Payout.Commission) +func normalizeValidator(rpcValidator blockatlas.Validator, assetValidator AssetValidator, coin coin.Coin) blockatlas.StakeValidator { + details := rpcValidator.Details + details.MinimumAmount = blockatlas.Amount(numbers.Float64toString(assetValidator.Staking.MinDelegation)) + details.Reward.Annual = calculateAnnual(details.Reward.Annual, assetValidator.Payout.Commission) + return blockatlas.StakeValidator{ - ID: validator.ID, - Status: plainValidator.Status && !validator.Status.Disabled, + ID: assetValidator.ID, + Status: rpcValidator.Status && !assetValidator.Status.Disabled, Info: blockatlas.StakeValidatorInfo{ - Name: validator.Name, - Description: validator.Description, - Image: getImage(coin, plainValidator.ID), - Website: validator.Website, + Name: assetValidator.Name, + Description: assetValidator.Description, + Image: getImage(coin, rpcValidator.ID), + Website: assetValidator.Website, }, Details: details, } diff --git a/services/assets/stake_test.go b/services/assets/stake_test.go index 40ca40aaa..84f635772 100644 --- a/services/assets/stake_test.go +++ b/services/assets/stake_test.go @@ -9,6 +9,8 @@ import ( var ( cosmosCoin = coin.Coin{Handle: "cosmos"} + tezosCoin = coin.Coin{Handle: "tezos"} + validators = []blockatlas.Validator{ { ID: "test1", @@ -51,32 +53,71 @@ var ( Status: ValidatorStatus{Disabled: true}, }, } - expectedStakeValidator = blockatlas.StakeValidator{ + + tezosValidators = []blockatlas.Validator{ + { + ID: "test1", + Status: true, + }, + } + + tezosAssets1 = []AssetValidator{ + { + ID: "test1", + Name: "🐠stake.fish", + Description: "Leading validator for Proof of Stake blockchains.", + Website: "https://stake.fish/", + Status: ValidatorStatus{Disabled: false}, + Staking: StakingInfo{MinDelegation: 10}, + }, + } + expectTezosVal1 = blockatlas.StakeValidator{ + ID: "test1", Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "🐠stake.fish", + Description: "Leading validator for Proof of Stake blockchains.", + Image: getImage(tezosCoin, "test1"), + Website: "https://stake.fish/", + }, + Details: blockatlas.StakingDetails{ + MinimumAmount: blockatlas.Amount("10"), + }, + } + expectedCosmosStakeValidator = 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", + Image: getImage(cosmosCoin, "test1"), Website: "https://tw.com", }, + Details: blockatlas.StakingDetails{ + MinimumAmount: blockatlas.Amount("0"), + }, } - expectedStakeValidatorDisabled1 = blockatlas.StakeValidator{ + expectedCosmosStakeValidatorDisabled1 = 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", + Image: getImage(cosmosCoin, "test1"), Website: "https://tw.com", }, + Details: blockatlas.StakingDetails{ + MinimumAmount: blockatlas.Amount("0"), + }, } - expectedStakeValidatorDisabled2 = blockatlas.StakeValidator{ + expectedCosmosStakeValidatorDisabled2 = 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", + Image: getImage(cosmosCoin, "test2"), Website: "https://tw.com", }, + Details: blockatlas.StakingDetails{ + MinimumAmount: blockatlas.Amount("0"), + }, } ) @@ -141,7 +182,7 @@ func TestCalcAnnual(t *testing.T) { func TestNormalizeValidator(t *testing.T) { result := normalizeValidator(validators[0], assets1[0], cosmosCoin) - assert.Equal(t, expectedStakeValidator, result) + assert.Equal(t, expectedCosmosStakeValidator, result) } func Test_normalizeValidators(t *testing.T) { @@ -155,8 +196,9 @@ func Test_normalizeValidators(t *testing.T) { 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}}, + {"normalize validator 1", args{assets1, validators, cosmosCoin}, blockatlas.StakeValidators{expectedCosmosStakeValidator, expectedCosmosStakeValidatorDisabled2}}, + {"normalize validator 2", args{assets2, validators, cosmosCoin}, blockatlas.StakeValidators{expectedCosmosStakeValidatorDisabled1, expectedCosmosStakeValidatorDisabled2}}, + {"normalize tezos validator", args{tezosAssets1, tezosValidators, tezosCoin}, blockatlas.StakeValidators{expectTezosVal1}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 99daaa4d710e997d247b4d06574d3f23d06f5d28 Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Sat, 9 May 2020 16:36:49 -0700 Subject: [PATCH 279/506] Sort Harmony trx (#1078) Fixes https://github.com/trustwallet/rpc-services/issues/309 --- platform/harmony/transaction.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index 890b5b436..1be81b015 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -5,6 +5,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" + "sort" "strconv" ) @@ -25,6 +26,9 @@ func NormalizeTxs(txs []Transaction) blockatlas.TxPage { } normalizeTxs = append(normalizeTxs, normalized) } + sort.Slice(normalizeTxs, func(i, j int) bool { + return normalizeTxs[i].Date > normalizeTxs[j].Date + }) return normalizeTxs } From bade3528effc8ecfda5c4c13bc06e1e20b67944d Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 10 May 2020 03:28:26 +0300 Subject: [PATCH 280/506] Remove omitmpty for sequence json field at blockatlas.tx (#1080) * Remove omitempty for sequence json field at blockatlas.tx There are seqeunce numbers = 0 * Remove prinln --- pkg/blockatlas/tx.go | 2 +- platform/ontology/transaction_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 1f5bc6e2c..3444a9ab7 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -98,7 +98,7 @@ type ( // else error explaining why the transaction failed (optional) Error string `json:"error,omitempty"` // Transaction nonce or sequence - Sequence uint64 `json:"sequence,omitempty"` + Sequence uint64 `json:"sequence"` // Type of metadata Type TransactionType `json:"type"` // Input addresses diff --git a/platform/ontology/transaction_test.go b/platform/ontology/transaction_test.go index 3cc7dbe59..4e505018a 100644 --- a/platform/ontology/transaction_test.go +++ b/platform/ontology/transaction_test.go @@ -289,6 +289,6 @@ func TestNormalizeBlock(t *testing.T) { if err != nil { t.Fatal(err) } - want := `[{"id":"266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb","coin":1024,"from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"native_token_transfer","memo":"","metadata":{"name":"Ontology Gas","symbol":"ONG","token_id":"ong","decimals":9,"value":"51000000000000","from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx"}},{"id":"2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd","coin":1024,"from":"ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"transfer","memo":"","metadata":{"value":"113.2","symbol":"ONT","decimals":0}},{"id":"40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3","coin":1024,"from":"Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","type":"transfer","memo":"","metadata":{"value":"10949","symbol":"ONT","decimals":0}}]` + want := `[{"id":"266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb","coin":1024,"from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","sequence":0,"type":"native_token_transfer","memo":"","metadata":{"name":"Ontology Gas","symbol":"ONG","token_id":"ong","decimals":9,"value":"51000000000000","from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx"}},{"id":"2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd","coin":1024,"from":"ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"113.2","symbol":"ONT","decimals":0}},{"id":"40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3","coin":1024,"from":"Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"10949","symbol":"ONT","decimals":0}}]` assert.Equal(t, want, string(got)) } From 07daa0ed2a4b3e7a59e66b8dc30706f1e252936a Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Sat, 9 May 2020 17:32:02 -0700 Subject: [PATCH 281/506] Remove duplicate txs (#1079) --- platform/harmony/transaction.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index 1be81b015..df19854bc 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -19,7 +19,8 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { func NormalizeTxs(txs []Transaction) blockatlas.TxPage { normalizeTxs := make([]blockatlas.Tx, 0) - for _, srcTx := range txs { + filteredTxs := unique(txs) + for _, srcTx := range filteredTxs { normalized, isCorrect, err := NormalizeTx(&srcTx) if !isCorrect || err != nil { return []blockatlas.Tx{} @@ -86,3 +87,16 @@ func NormalizeTx(trx *Transaction) (tx blockatlas.Tx, b bool, err error) { }, }, true, nil } + +// Remove duplicate transaction with same hash +func unique(intSlice []Transaction) []Transaction { + keys := make(map[string]bool) + list := make([]Transaction, 0) + for _, entry := range intSlice { + if _, value := keys[entry.Hash]; !value { + keys[entry.Hash] = true + list = append(list, entry) + } + } + return list +} From d125d199125ace70e38c396631fd9c7b112a6eb2 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 10 May 2020 05:18:44 +0300 Subject: [PATCH 282/506] Sort Txs on api level now. Remove bad prev solution (#1081) --- api/endpoint/transaction.go | 16 +++--- pkg/blockatlas/tx.go | 20 +++++++ pkg/blockatlas/tx_test.go | 93 +++++++++++++++++++++++++++++++++ platform/harmony/transaction.go | 20 +------ 4 files changed, 123 insertions(+), 26 deletions(-) diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 530b1488e..78136f8a4 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -6,7 +6,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "net/http" - "sort" ) // @Summary Get Transactions @@ -63,16 +62,17 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b return } } - - page := make(blockatlas.TxPage, 0) - for _, tx := range txs { + var ( + page = make(blockatlas.TxPage, 0) + filteredTxs = blockatlas.Txs(txs).FilterUniqueID().SortByDate() + ) + for _, tx := range filteredTxs { tx.Direction = tx.GetTransactionDirection(address) page = append(page, tx) } if len(page) > blockatlas.TxPerPage { page = page[0:blockatlas.TxPerPage] } - sort.Sort(&page) c.JSON(http.StatusOK, &page) } @@ -114,11 +114,13 @@ func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { return } } + var ( + filteredTxs = blockatlas.Txs(txs).FilterUniqueID().SortByDate() + page = blockatlas.TxPage(filteredTxs) + ) - page := blockatlas.TxPage(txs) if len(page) > blockatlas.TxPerPage { page = page[0:blockatlas.TxPerPage] } - sort.Sort(&page) c.JSON(http.StatusOK, &page) } diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 3444a9ab7..e36e14165 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -4,6 +4,7 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/numbers" + "sort" ) const ( @@ -209,6 +210,25 @@ type ( Txs []Tx ) +func (t Txs) FilterUniqueID() Txs { + keys := make(map[string]bool) + list := make(Txs, 0) + for _, entry := range t { + if _, value := keys[entry.ID]; !value { + keys[entry.ID] = true + list = append(list, entry) + } + } + return list +} + +func (t Txs) SortByDate() Txs { + sort.Slice(t, func(i, j int) bool { + return t[i].Date > t[j].Date + }) + return t +} + func (t Txs) GetTransactionsMap() TxSetMap { txSetMap := TxSetMap{Map: make(map[string]*TxSet)} for i := 0; i < len(t); i++ { diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 5c1462c8a..688f73355 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -4,6 +4,7 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" + "sort" "testing" ) @@ -530,3 +531,95 @@ func TestTx_GetTransactionDirection(t *testing.T) { tx.Direction = tx.GetTransactionDirection("0x38d45371993eEc84f38FEDf93C646aA2D2267CEA") assert.Equal(t, Direction("yourself"), tx.Direction) } + +func TestTxs_FilterUniqueID(t *testing.T) { + tx := Tx{ + ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c4", + Coin: 60, + From: "0x08777CB1e80F45642752662B04886Df2d271E049", + To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + Fee: "52473000000000", + Date: 1585169424, + Block: 9742705, + Status: "completed", + Sequence: 149, + Type: "token_transfer", + } + tx2 := Tx{ + ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c4", + Coin: 60, + From: "0x08777CB1e80F45642752662B04886Df2d271E049", + To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + Fee: "52473000000000", + Date: 1585169424, + Block: 9742705, + Status: "completed", + Sequence: 149, + Type: "token_transfer", + } + + txs := make([]Tx, 0) + txs = append(txs, tx) + txs = append(txs, tx2) + + entry := Txs(txs) + + result := entry.FilterUniqueID() + + assert.Equal(t, entry[:1], result) +} + +func TestTxs_SortByDate(t *testing.T) { + tx := Tx{ + ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c4", + Coin: 60, + From: "0x08777CB1e80F45642752662B04886Df2d271E049", + To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + Fee: "52473000000000", + Date: 1585169423, + Block: 9742705, + Status: "completed", + Sequence: 149, + Type: "token_transfer", + } + tx2 := Tx{ + ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c5", + Coin: 60, + From: "0x08777CB1e80F45642752662B04886Df2d271E049", + To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + Fee: "52473000000000", + Date: 1585169424, + Block: 9742705, + Status: "completed", + Sequence: 149, + Type: "token_transfer", + } + tx3 := Tx{ + ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c6", + Coin: 60, + From: "0x08777CB1e80F45642752662B04886Df2d271E049", + To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + Fee: "52473000000000", + Date: 1585169425, + Block: 9742705, + Status: "completed", + Sequence: 149, + Type: "token_transfer", + } + + txs := make([]Tx, 0) + txs = append(txs, tx) + txs = append(txs, tx2) + txs = append(txs, tx3) + + entry := Txs(txs) + isNotSorted := sort.SliceIsSorted(entry, func(i, j int) bool { + return entry[i].Date > entry[j].Date + }) + assert.True(t, !isNotSorted) + result := entry.SortByDate() + isSorted := sort.SliceIsSorted(result, func(i, j int) bool { + return result[i].Date > result[j].Date + }) + assert.True(t, isSorted) +} diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index df19854bc..890b5b436 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -5,7 +5,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" - "sort" "strconv" ) @@ -19,17 +18,13 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { func NormalizeTxs(txs []Transaction) blockatlas.TxPage { normalizeTxs := make([]blockatlas.Tx, 0) - filteredTxs := unique(txs) - for _, srcTx := range filteredTxs { + for _, srcTx := range txs { normalized, isCorrect, err := NormalizeTx(&srcTx) if !isCorrect || err != nil { return []blockatlas.Tx{} } normalizeTxs = append(normalizeTxs, normalized) } - sort.Slice(normalizeTxs, func(i, j int) bool { - return normalizeTxs[i].Date > normalizeTxs[j].Date - }) return normalizeTxs } @@ -87,16 +82,3 @@ func NormalizeTx(trx *Transaction) (tx blockatlas.Tx, b bool, err error) { }, }, true, nil } - -// Remove duplicate transaction with same hash -func unique(intSlice []Transaction) []Transaction { - keys := make(map[string]bool) - list := make([]Transaction, 0) - for _, entry := range intSlice { - if _, value := keys[entry.Hash]; !value { - keys[entry.Hash] = true - list = append(list, entry) - } - } - return list -} From f87576ce70bfe0a4e45a2ce9ecb99941aff612f9 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sat, 9 May 2020 23:26:26 -0700 Subject: [PATCH 283/506] [Tron] Add caching for fetching an asset endpoint (#1085) --- platform/tron/client.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/tron/client.go b/platform/tron/client.go index e5c5f6548..dfa484ac2 100644 --- a/platform/tron/client.go +++ b/platform/tron/client.go @@ -5,6 +5,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "net/url" + "time" ) type Client struct { @@ -52,7 +53,7 @@ func (c *Client) GetAccountVotes(address string) (account *AccountData, err erro func (c *Client) GetTokenInfo(id string) (asset Asset, err error) { path := fmt.Sprintf("v1/assets/%s", id) - err = c.Get(&asset, path, nil) + err = c.GetWithCache(&asset, path, nil, time.Hour*24) return } From 97f7b890b45e2666d68838cdf99889c7009aa7f8 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sat, 9 May 2020 23:39:13 -0700 Subject: [PATCH 284/506] [BNB] Add cache for fetching tokens list (#1086) --- platform/binance/dex_client.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/binance/dex_client.go b/platform/binance/dex_client.go index 4de3efa61..094fcdeac 100644 --- a/platform/binance/dex_client.go +++ b/platform/binance/dex_client.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" + "time" ) // TODO Headers + rate limiting @@ -21,6 +22,6 @@ func (c *DexClient) GetAccountMetadata(address string) (account *Account, err er func (c *DexClient) GetTokens() (*TokenPage, error) { stp := new(TokenPage) query := url.Values{"limit": {"1000"}, "offset": {"0"}} - err := c.Get(stp, "v1/tokens", query) + err := c.GetWithCache(stp, "v1/tokens", query, time.Hour*1) return stp, err } From 80b419333943171d279d1e2cf33dadede0f19552 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sun, 10 May 2020 13:00:07 -0700 Subject: [PATCH 285/506] [Transactions] Improve fetching logic for transactions (#1087) * [Transactions] Improve fetching logic for transactions In current implementation now we have ability to include transactions details to avoid calling /transactions endpoint for each transaction that is being parsed from the block or list of transactions * Fix block number for stellar chain it will present 0 for kin blockchain, which is better than a wrong number * Update transaction.go --- platform/stellar/client.go | 13 ++------ platform/stellar/model.go | 37 ++++++++++----------- platform/stellar/transaction.go | 49 +++++----------------------- platform/stellar/transaction_test.go | 32 +++++++----------- 4 files changed, 40 insertions(+), 91 deletions(-) diff --git a/platform/stellar/client.go b/platform/stellar/client.go index 58716dd09..1c5a06758 100644 --- a/platform/stellar/client.go +++ b/platform/stellar/client.go @@ -15,6 +15,7 @@ func (c *Client) GetTxsOfAddress(address string) ([]Payment, error) { query := url.Values{ "order": {"desc"}, "limit": {"25"}, + "join": {"transactions"}, } path := fmt.Sprintf("accounts/%s/payments", url.PathEscape(address)) @@ -26,17 +27,6 @@ func (c *Client) GetTxsOfAddress(address string) ([]Payment, error) { return payments.Embedded.Records, nil } -func (c *Client) GetTxHash(id string) (TxHash, error) { - path := fmt.Sprintf("transactions/%s", id) - - var hash TxHash - err := c.Get(&hash, path, nil) - if err != nil { - return hash, err - } - return hash, nil -} - func (c *Client) CurrentBlockNumber() (int64, error) { query := url.Values{ "order": {"desc"}, @@ -63,6 +53,7 @@ func (c *Client) GetBlockByNumber(num int64) (*Block, error) { query := url.Values{ "order": {"desc"}, "limit": {"100"}, + "join": {"transactions"}, } path := fmt.Sprintf("ledgers/%d/payments", num) diff --git a/platform/stellar/model.go b/platform/stellar/model.go index 0d78d4785..af8d75f20 100644 --- a/platform/stellar/model.go +++ b/platform/stellar/model.go @@ -38,26 +38,23 @@ type Block struct { // Payment model returned by Horizon type Payment struct { - ID string `json:"id"` - Type string `json:"type"` - SourceAccount string `json:"source_account"` - CreatedAt string `json:"created_at"` - Account string `json:"account"` - Funder string `json:"funder"` - StartingBalance string `json:"starting_balance"` - Into string `json:"into"` - From string `json:"from"` - To string `json:"to"` - AssetType string `json:"asset_type"` - Amount string `json:"amount"` - TransactionHash string `json:"transaction_hash"` + ID string `json:"id"` + Type string `json:"type"` + SourceAccount string `json:"source_account"` + CreatedAt string `json:"created_at"` + Account string `json:"account"` + Funder string `json:"funder"` + StartingBalance string `json:"starting_balance"` + Into string `json:"into"` + From string `json:"from"` + To string `json:"to"` + AssetType string `json:"asset_type"` + Amount string `json:"amount"` + TransactionHash string `json:"transaction_hash"` + Transaction Transaction `json:"transaction"` } -type TxHash struct { - Memo string `json:"memo"` -} - -type Tuple struct { - Payment - TxHash +type Transaction struct { + Memo string `json:"memo"` + Ledger uint64 `json:"ledger"` } diff --git a/platform/stellar/transaction.go b/platform/stellar/transaction.go index 53cd01cdf..001ee6fe2 100644 --- a/platform/stellar/transaction.go +++ b/platform/stellar/transaction.go @@ -4,8 +4,6 @@ import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" - "strconv" - "sync" "time" ) @@ -18,43 +16,18 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return p.NormalizePayments(payments), nil } -func (p *Platform) NormalizePayments(payments []Payment) (txs []blockatlas.Tx) { - var ( - wg sync.WaitGroup - txsChan = make(chan blockatlas.Tx, len(payments)) - ) - +func (p *Platform) NormalizePayments(payments []Payment) []blockatlas.Tx { + txs := make([]blockatlas.Tx, 0, len(payments)) for _, payment := range payments { - wg.Add(1) - go func(pay Payment) { - defer wg.Done() - - txHash, err := p.client.GetTxHash(pay.TransactionHash) - if err != nil { - return - } - - tx, ok := Normalize(&pay, p.CoinIndex, txHash) - if !ok { - return - } - - txsChan <- tx - - }(payment) - } - wg.Wait() - close(txsChan) - - for tx := range txsChan { - txs = append(txs, tx) + if tx, ok := Normalize(&payment, p.CoinIndex); ok { + txs = append(txs, tx) + } } - - return + return txs } // Normalize converts a Stellar-based transaction into the generic model -func Normalize(payment *Payment, nativeCoinIndex uint, hash TxHash) (tx blockatlas.Tx, ok bool) { +func Normalize(payment *Payment, nativeCoinIndex uint) (tx blockatlas.Tx, ok bool) { switch payment.Type { case PaymentType: if payment.AssetType != Native { @@ -65,10 +38,6 @@ func Normalize(payment *Payment, nativeCoinIndex uint, hash TxHash) (tx blockatl default: return tx, false } - id, err := strconv.ParseUint(payment.ID, 10, 64) - if err != nil { - return tx, false - } date, err := time.Parse("2006-01-02T15:04:05Z", payment.CreatedAt) if err != nil { return tx, false @@ -95,8 +64,8 @@ func Normalize(payment *Payment, nativeCoinIndex uint, hash TxHash) (tx blockatl To: to, Fee: FixedFee, Date: date.Unix(), - Memo: hash.Memo, - Block: id, + Memo: payment.Transaction.Memo, + Block: payment.Transaction.Ledger, Meta: blockatlas.Transfer{ Value: blockatlas.Amount(value), Symbol: coin.Coins[nativeCoinIndex].Symbol, diff --git a/platform/stellar/transaction_test.go b/platform/stellar/transaction_test.go index 40feddee2..f08661258 100644 --- a/platform/stellar/transaction_test.go +++ b/platform/stellar/transaction_test.go @@ -1,8 +1,8 @@ package stellar import ( - "bytes" "encoding/json" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" @@ -31,8 +31,7 @@ var createDst = blockatlas.Tx{ To: "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", Fee: "100", Date: 1470850220, - Memo: "testing", - Block: 25002129911451649, + Block: 0, Meta: blockatlas.Transfer{ Value: "473269393700000000", Symbol: "XLM", @@ -53,7 +52,11 @@ const transferSrc = ` "asset_type": "native", "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", "to": "GAX3BRBNB5WTJ2GNEFFH7A4CZKT2FORYABDDBZR5FIIT3P7FLS2EFOZZ", - "amount": "100000000.0000000" + "amount": "100000000.0000000", + "transaction": { + "memo": "testing", + "ledger": 123 + } } ` @@ -65,7 +68,7 @@ var transferDst = blockatlas.Tx{ Fee: "100", Date: 1470857941, Memo: "testing", - Block: 25008572362395649, + Block: 123, Meta: blockatlas.Transfer{ Value: blockatlas.Amount("1000000000000000"), Symbol: "XLM", @@ -73,14 +76,9 @@ var transferDst = blockatlas.Tx{ }, } -var hash = TxHash{ - Memo: "testing", -} - type test struct { name string apiResponse string - hash TxHash expected *blockatlas.Tx } @@ -88,13 +86,11 @@ func TestNormalize(t *testing.T) { testNormalize(t, &test{ name: "create account", apiResponse: createSrc, - hash: hash, expected: &createDst, }) testNormalize(t, &test{ name: "transfer", apiResponse: transferSrc, - hash: hash, expected: &transferDst, }) } @@ -106,24 +102,20 @@ func testNormalize(t *testing.T, _test *test) { t.Error(err) return } - tx, ok := Normalize(&payment, coin.XLM, _test.hash) + tx, ok := Normalize(&payment, coin.XLM) if !ok { t.Errorf("%s: tx could not be normalized", _test.name) } - resJSON, err := json.Marshal(&tx) + _, err = json.Marshal(&tx) if err != nil { t.Fatal(err) } - dstJSON, err := json.Marshal(&_test.expected) + _, err = json.Marshal(&_test.expected) if err != nil { t.Fatal(err) } - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error(_test.name + ": tx don't equal") - } + assert.Equal(t, tx, *_test.expected) } From d64d583720769c77bba18d138f815376562f2b7a Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Mon, 11 May 2020 10:42:54 +0200 Subject: [PATCH 286/506] Remove empty test iteration file for mock startup. (#1090) * Remove empty test iteration file for mock startup. * Why does codecov complains if only Makefile was modified? Co-authored-by: Catenocrypt --- .codecov.yml | 1 + Makefile | 4 ++-- tests/postman/mock-healthcheck_data.json | 4 ---- 3 files changed, 3 insertions(+), 6 deletions(-) delete mode 100644 tests/postman/mock-healthcheck_data.json diff --git a/.codecov.yml b/.codecov.yml index 2eca65d92..aac5fb868 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -17,3 +17,4 @@ coverage: - "scripts" - "docs" - "db/models" + - "Makefile" diff --git a/Makefile b/Makefile index 53ddca7fa..0255cf008 100644 --- a/Makefile +++ b/Makefile @@ -135,8 +135,8 @@ start-mock-dyson: stop-dyson @echo " > Starting Dyson with mocks" @-dyson mock/ext-api-dyson & echo $$! > $(PID_DYSON) @echo " > Dyson started with PID: " `cat $(PID_DYSON)` - # Check that it is running (e.g. may fail due to unavailable port) - @$(MAKE) newman-run test=mock-healthcheck host=http://localhost:8437 + # Check that mock is running, by making a test with simple call (e.g. may fail due to unavailable port) + @newman run tests/postman/blockatlas.postman_collection.json --folder mock-healthcheck --env-var "host=http://localhost:8437" ## fmt: Run `go fmt` for all go files. fmt: go-fmt diff --git a/tests/postman/mock-healthcheck_data.json b/tests/postman/mock-healthcheck_data.json deleted file mode 100644 index da1a058a9..000000000 --- a/tests/postman/mock-healthcheck_data.json +++ /dev/null @@ -1,4 +0,0 @@ -[ - { - } -] From e3c3f01c3cf4af339b97dc6f62f88514bc763673 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Tue, 12 May 2020 00:46:24 +0800 Subject: [PATCH 287/506] Move CI to actions (#1083) * Create ci.yml * Update readme and remove pipelines * move lint and build to UT job * Add CD Trigger Co-authored-by: maxUo --- .github/workflows/ci.yml | 69 +++++++ .github/workflows/goreleaser.yml | 30 --- Makefile | 2 +- README.md | 2 +- azure-pipelines.yml | 79 -------- go.mod | 31 +++- go.sum | 301 +++++++++++++++++++------------ 7 files changed, 278 insertions(+), 236 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/goreleaser.yml delete mode 100644 azure-pipelines.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..654074aff --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,69 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + test: + name: Unit Test + runs-on: ubuntu-latest + steps: + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + go get -v -t -d ./... + + - name: Lint + run: make lint + + - name: Build + run: make go-build + + - name: Unit Test + run: make test + + - name: Upload coverage + run: bash <(curl -s https://codecov.io/bash) -f coverage.txt + + integration: + name: Integration Test + runs-on: ubuntu-latest + steps: + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + go get -v -t -d ./... + + - name: Integration Test + run: make integration + + - name: Mock Test + run: make newman-mocked + + deploy: + - name: CD Trigger + if: github.ref == 'refs/heads/master' + uses: Azure/pipelines@releases/v1 + with: + azure-devops-project-url: 'https://dev.azure.com/TrustWallet/Trust%20BlockAtlas' + azure-pipeline-name: 'AutomaticCD' + azure-devops-token: '${{ secrets.AZURE_DEVOPS_TOKEN }}' \ No newline at end of file diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml deleted file mode 100644 index 259b4f284..000000000 --- a/.github/workflows/goreleaser.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: goreleaser -on: - push: - tags: - - '*' - -jobs: - goreleaser: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Unshallow - run: git fetch --prune --unshallow - - - name: Set up Go - uses: actions/setup-go@v1 - with: - go-version: 1.13.x - - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v1 - with: - version: latest - args: release --rm-dist - key: ${{ secrets.YOUR_PRIVATE_KEY }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index 0255cf008..6a70a5604 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # Project variables. PACKAGE := github.com/trustwallet/blockatlas -VERSION := $(shell git describe --tags) +VERSION := $(shell git describe --tags 2>/dev/null || git describe --all) BUILD := $(shell git rev-parse --short HEAD) DATETIME := $(shell date +"%Y.%m.%d-%H:%M:%S") PROJECT_NAME := $(shell basename "$(PWD)") diff --git a/README.md b/README.md index f9d7a1bd7..aca802ef5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Block Atlas by Trust Wallet ![Go Version](https://img.shields.io/github/go-mod/go-version/TrustWallet/blockatlas) -[![Build Status](https://dev.azure.com/TrustWallet/Trust%20BlockAtlas/_apis/build/status/TrustWallet.blockatlas?branchName=master)](https://dev.azure.com/TrustWallet/Trust%20BlockAtlas/_build/latest?definitionId=27&branchName=master) +![CI](https://github.com/trustwallet/blockatlas/workflows/CI/badge.svg) [![codecov](https://codecov.io/gh/trustwallet/blockatlas/branch/master/graph/badge.svg)](https://codecov.io/gh/trustwallet/blockatlas) [![Go Report Card](https://goreportcard.com/badge/trustwallet/blockatlas)](https://goreportcard.com/report/TrustWallet/blockatlas) diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index fcde072f0..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,79 +0,0 @@ -trigger: - branches: - include: - - master - - dev - tags: - include: - - '*' - -pr: - branches: - include: - - master - - dev - -pool: - vmImage: 'Ubuntu 16.04' - -variables: - GOVERSION: '1.13' - -jobs: - - job: environment - steps: - - task: GoTool@0 - inputs: - version: '$(GOVERSION)' - displayName: 'Go Tool' - - - task: Go@0 - inputs: - command: 'get' - arguments: '-v -t -d ./...' - workingDirectory: '$(System.DefaultWorkingDirectory)' - displayName: 'Get dependencies' - - - job: go_lint - dependsOn: environment - condition: succeeded() - steps: - - script: sudo make lint - workingDirectory: '$(System.DefaultWorkingDirectory)' - displayName: 'Run go lint' - - - job: unit_tests - dependsOn: environment - condition: succeeded() - steps: - - script: make test - workingDirectory: '$(System.DefaultWorkingDirectory)' - displayName: 'Run unit tests' - - script: bash <(curl -s https://codecov.io/bash) -f coverage.txt - workingDirectory: '$(System.DefaultWorkingDirectory)' - displayName: 'Upload coverage to codecov.io' - - - job: mocked_tests - dependsOn: environment - condition: succeeded() - steps: - - script: sudo make newman-mocked - workingDirectory: '$(System.DefaultWorkingDirectory)' - condition: succeeded() - displayName: "Run api tests for new PR's" - - - job: integration_tests - dependsOn: environment - condition: succeeded() - steps: - - script: make integration - workingDirectory: '$(System.DefaultWorkingDirectory)' - displayName: 'Run integration tests' - - - job: build - dependsOn: environment - condition: succeeded() - steps: - - script: make go-build - workingDirectory: '$(System.DefaultWorkingDirectory)' - displayName: 'Build' diff --git a/go.mod b/go.mod index 62d4cb0c8..c6fff5614 100644 --- a/go.mod +++ b/go.mod @@ -3,29 +3,40 @@ module github.com/trustwallet/blockatlas go 1.14 require ( + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/DATA-DOG/go-sqlmock v1.4.1 + github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 - github.com/btcsuite/btcutil v1.0.1 + github.com/btcsuite/btcutil v1.0.2 + github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 + github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb // indirect github.com/deckarep/golang-set v1.7.1 - github.com/getsentry/sentry-go v0.5.1 - github.com/gin-gonic/gin v1.6.2 + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/getsentry/sentry-go v0.6.0 + github.com/gin-gonic/gin v1.6.3 + github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/jinzhu/gorm v1.9.12 - github.com/mitchellh/mapstructure v1.2.2 + github.com/mitchellh/mapstructure v1.3.0 github.com/mr-tron/base58 v1.1.3 + github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/runc v0.1.1 // indirect github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/prometheus/client_golang v1.5.1 - github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc - github.com/sirupsen/logrus v1.5.0 - github.com/spf13/viper v1.6.2 + github.com/prometheus/client_golang v1.6.0 + github.com/shopspring/decimal v1.2.0 + github.com/sirupsen/logrus v1.6.0 + github.com/spf13/viper v1.7.0 github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 github.com/stretchr/testify v1.5.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.5 github.com/trustwallet/ens-coincodec v1.0.5 go.uber.org/atomic v1.6.0 - golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 - golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e + golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 + golang.org/x/net v0.0.0-20200506145744-7e3656a0809f gopkg.in/yaml.v2 v2.2.8 + gotest.tools v2.2.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index 24aba8add..feca575b4 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,28 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a h1:3SgJcK9l5uPdBC/X17wanyJAMxM33+4ZhEIV96MIH8U= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= -github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7 h1:mreN1m/5VJ/Zc3b4pzj9qU6D9SRQ6Vm+3KfI328t3S8= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= @@ -27,31 +36,32 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns= +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/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +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= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcutil v1.0.1 h1:GKOz8BnRjYrb/JTKgaOk+zh26NWNdSNvdvv0xoAZMSA= -github.com/btcsuite/btcutil v1.0.1/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= @@ -67,18 +77,15 @@ github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 h1:3Wv1E0CqL github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= -github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c h1:8ahmSVELW1wghbjerVAyuEYD5+Dio66RYvSS0iGfL1M= -github.com/containerd/continuity v0.0.0-20200228182428-0f16d7a0959c/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= -github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= +github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb h1:nXPkFq8X1a9ycY3GYQpFNxHh3j2JgY7zDZfq2EXMIzk= +github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c h1:4e6Zsb6LFd3kadoMiut2zcd3hCb4zywpJnQa8+NV2Cs= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c/go.mod h1:k5D13LCXSsMrQyfdW0yGYs4GWUvirqoxHht8qwtqyRY= @@ -93,7 +100,6 @@ github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14y github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -103,24 +109,19 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/getsentry/sentry-go v0.5.1 h1:MIPe7ScHADsrK2vznqmhksIUFxq7m0JfTh+ZIMkI+VQ= -github.com/getsentry/sentry-go v0.5.1/go.mod h1:B8H7x8TYDPkeWPRzGpIiFO97LZP6rL8A3hEt8lUItMw= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/getsentry/sentry-go v0.6.0 h1:kPd+nr+dlXmaarUBg7xlC/qn+7wyMJL6PMsSn5fA+RM= +github.com/getsentry/sentry-go v0.6.0/go.mod h1:0yZBuzSvbZwBnvaF9VwZIMen3kXscY8/uasKtAX1qG8= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= @@ -130,12 +131,12 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM= -github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -172,55 +173,77 @@ github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22 github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gotestyourself/gotestyourself v1.4.0 h1:CDSlSIuRL/Fsc72Ln5lMybtrCvSRDddsHsDRG/nP7Rg= -github.com/gotestyourself/gotestyourself v1.4.0/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= -github.com/iris-contrib/schema v0.0.1 h1:10g/WnoRR+U+XXHWKBHeNy/+tZmM2kcAVGLOsz+yaDA= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= @@ -229,40 +252,33 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20180524022052-584905176618 h1:MK144iBQF9hTSwBW/9eJm034bVoG30IshVm688T2hi8= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 h1:WQM1NildKThwdP7qWrNAFGzp4ijNLw8RlgENkaI4MJs= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kataras/golog v0.0.9 h1:J7Dl82843nbKQDrQM/abbNJZvQjS6PfmkkffhOTXEpM= github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= -github.com/kataras/iris/v12 v12.0.1 h1:Wo5S7GMWv5OAzJmvFTvss/C4TS1W0uo6LkDlSymT4rM= github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= -github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao= github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -283,8 +299,9 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -298,20 +315,24 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= -github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= -github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.0 h1:iDwIio/3gk2QtLLEsqU5lInaMzos0hDTz8a6lazSFVw= +github.com/mitchellh/mapstructure v1.3.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -323,11 +344,9 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -337,6 +356,7 @@ github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJ github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= @@ -349,53 +369,49 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA= -github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= +github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= 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/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/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/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= 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/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 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= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY= -github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= -github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= @@ -410,8 +426,8 @@ github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bd github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= -github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5NYJe/zRYDwOu9ku6YHy+Iw7l5DM= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -430,7 +446,6 @@ github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.6.5 h1:2C+t+xyK6p1sujqncYO/VnMvPZcBJjNdKKyxbOdAW8o= github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/ens-coincodec v1.0.5 h1:rdebDQYHqNjv+yUdtMf3DXyMgJpEJSI2DSbC1GUFuyk= github.com/trustwallet/ens-coincodec v1.0.5/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= @@ -446,148 +461,198 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d h1:2+ZP7EfsZV7Vvmx3TIqSlSzATMkTAKqM14YGFPoSKjI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88= +golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -596,4 +661,10 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= \ No newline at end of file +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= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 1c2b77a1f8c92499ed7f87ab174e153632a12e8a Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Mon, 11 May 2020 19:57:29 +0300 Subject: [PATCH 288/506] CI fix --- .github/workflows/ci.yml | 81 +++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 654074aff..ff684bb98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,59 +11,62 @@ jobs: name: Unit Test runs-on: ubuntu-latest steps: - - name: Set up Go 1.x - uses: actions/setup-go@v2 - with: - go-version: ^1.13 - id: go + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go - - name: Check out code - uses: actions/checkout@v2 + - name: Check out code + uses: actions/checkout@v2 - - name: Get dependencies - run: | - go get -v -t -d ./... + - name: Get dependencies + run: | + go get -v -t -d ./... - - name: Lint - run: make lint + - name: Lint + run: make lint - - name: Build - run: make go-build + - name: Build + run: make go-build - - name: Unit Test - run: make test + - name: Unit Test + run: make test - - name: Upload coverage - run: bash <(curl -s https://codecov.io/bash) -f coverage.txt + - name: Upload coverage + run: bash <(curl -s https://codecov.io/bash) -f coverage.txt integration: name: Integration Test runs-on: ubuntu-latest steps: - - name: Set up Go 1.x - uses: actions/setup-go@v2 - with: - go-version: ^1.13 - id: go + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go - - name: Check out code - uses: actions/checkout@v2 + - name: Check out code + uses: actions/checkout@v2 - - name: Get dependencies - run: | - go get -v -t -d ./... + - name: Get dependencies + run: | + go get -v -t -d ./... - - name: Integration Test - run: make integration + - name: Integration Test + run: make integration - - name: Mock Test - run: make newman-mocked + - name: Mock Test + run: make newman-mocked deploy: - - name: CD Trigger - if: github.ref == 'refs/heads/master' - uses: Azure/pipelines@releases/v1 - with: - azure-devops-project-url: 'https://dev.azure.com/TrustWallet/Trust%20BlockAtlas' - azure-pipeline-name: 'AutomaticCD' - azure-devops-token: '${{ secrets.AZURE_DEVOPS_TOKEN }}' \ No newline at end of file + name: CD + runs-on: ubuntu-latest + steps: + - name: CD Trigger + if: github.ref == 'refs/heads/master' + uses: Azure/pipelines@releases/v1 + with: + azure-devops-project-url: 'https://dev.azure.com/TrustWallet/Trust%20BlockAtlas' + azure-pipeline-name: 'AutomaticCD' + azure-devops-token: '${{ secrets.AZURE_DEVOPS_TOKEN }}' From 024bd444442bd518faf52a409231ae75da7f735d Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Mon, 11 May 2020 20:06:19 +0300 Subject: [PATCH 289/506] CI - Now CD will be triggered after all actions only --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff684bb98..4cfc01ce6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,6 +62,7 @@ jobs: deploy: name: CD runs-on: ubuntu-latest + needs: [test, integration] steps: - name: CD Trigger if: github.ref == 'refs/heads/master' From 9f6107b0b0383a701a4dab345bf4f16f60223d2a Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov Date: Tue, 12 May 2020 18:18:05 +0300 Subject: [PATCH 290/506] [Observer notifier] Use FatalWorker instead of RestoreConnectionWorker (#1092) --- cmd/observer_notifier/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/observer_notifier/main.go b/cmd/observer_notifier/main.go index 623676cd8..850d712f4 100644 --- a/cmd/observer_notifier/main.go +++ b/cmd/observer_notifier/main.go @@ -55,8 +55,9 @@ func init() { logger.Info("maxPushNotificationsBatchLimit ", logger.Params{"limit": maxPushNotificationsBatchLimit}) - go mq.RestoreConnectionWorker(mqHost, mq.RawTransactions, time.Second*10) + go mq.FatalWorker(time.Second * 10) go db.RestoreConnectionWorker(database, time.Second*10, pgUri) + time.Sleep(time.Millisecond) } From 0fa0780885d98126fbdfbc606d5a32bb053ed87a Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 12 May 2020 12:33:01 -0700 Subject: [PATCH 291/506] Only keep one code owner [skip ci] --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4aafad044..91d2b9989 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @EnoRage @catenocrypt @hewigovens @kolya182 @prazd +* @EnoRage From 22c9a1dc1de1c35a4bedefc495ff900a774768f0 Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Wed, 13 May 2020 15:17:50 +0800 Subject: [PATCH 292/506] Enable ethereum pending txs (#1091) * enable pending eth tx * Add pending tx test * 1. check data field when fill meta 2. fix fee for pending tx 3. add more tx tests --- platform/ethereum/blockbook/model.go | 1 + .../ethereum/blockbook/model_extension.go | 17 ++ platform/ethereum/blockbook/transaction.go | 30 ++- .../ethereum/blockbook/transaction_test.go | 195 +++++++++++++++++- 4 files changed, 230 insertions(+), 13 deletions(-) diff --git a/platform/ethereum/blockbook/model.go b/platform/ethereum/blockbook/model.go index 64d800f06..415b5294e 100644 --- a/platform/ethereum/blockbook/model.go +++ b/platform/ethereum/blockbook/model.go @@ -73,4 +73,5 @@ type EthereumSpecific struct { GasLimit *big.Int `json:"gasLimit"` GasUsed *big.Int `json:"gasUsed"` GasPrice string `json:"gasPrice"` + Data string `json:"data,omitempty"` } diff --git a/platform/ethereum/blockbook/model_extension.go b/platform/ethereum/blockbook/model_extension.go index 611b2905f..40d96deda 100644 --- a/platform/ethereum/blockbook/model_extension.go +++ b/platform/ethereum/blockbook/model_extension.go @@ -1,6 +1,8 @@ package blockbook import ( + "math/big" + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -24,6 +26,21 @@ func (t *Transaction) FromAddress() string { return "" } +func (t *Transaction) GetFee() string { + status, _ := t.EthereumSpecific.GetStatus() + if status != blockatlas.StatusPending { + return t.Fees + } + + gasLimit := t.EthereumSpecific.GasLimit + gasPrice, ok := new(big.Int).SetString(t.EthereumSpecific.GasPrice, 10) + if gasLimit == nil || !ok { + return "0" + } + fee := new(big.Int).Mul(gasLimit, gasPrice) + return fee.String() +} + func (t *Transaction) ToAddress() string { if len(t.Vout) > 0 && len(t.Vout[0].Addresses) > 0 { return t.Vout[0].Addresses[0] diff --git a/platform/ethereum/blockbook/transaction.go b/platform/ethereum/blockbook/transaction.go index b5d109002..e539d54b5 100644 --- a/platform/ethereum/blockbook/transaction.go +++ b/platform/ethereum/blockbook/transaction.go @@ -1,6 +1,8 @@ package blockbook import ( + "strings" + "github.com/trustwallet/blockatlas/coin" Address "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -30,9 +32,6 @@ func NormalizePage(srcPage *Page, address, token string, coinIndex uint) blockat normalizedToken = Address.EIP55Checksum(token) } for _, srcTx := range srcPage.Transactions { - if srcTx.BlockHeight < 0 { - continue // Skip pending tx - } tx := normalizeTxWithAddress(&srcTx, normalizedAddr, normalizedToken, coinIndex) txs = append(txs, tx) } @@ -46,7 +45,7 @@ func normalizeTx(srcTx *Transaction, coinIndex uint) blockatlas.Tx { Coin: coinIndex, From: srcTx.FromAddress(), To: srcTx.ToAddress(), - Fee: blockatlas.Amount(srcTx.Fees), + Fee: blockatlas.Amount(srcTx.GetFee()), Date: srcTx.BlockTime, Block: normalizeBlockHeight(srcTx.BlockHeight), Status: status, @@ -146,8 +145,25 @@ func fillTransferOrContract(final *blockatlas.Tx, tx *Transaction, coinIndex uin } return } - final.Meta = blockatlas.ContractCall{ - Input: "0x", // FIXME blockbook api doesn't return tx data field - Value: tx.Value, + data := tx.EthereumSpecific.Data + if data == "" { + // old node doesn't have data field + final.Meta = blockatlas.ContractCall{ + Input: "0x", + Value: tx.Value, + } + } else { + if len(strings.TrimPrefix(data, "0x")) > 0 { + final.Meta = blockatlas.ContractCall{ + Input: data, + Value: tx.Value, + } + } else { + final.Meta = blockatlas.Transfer{ + Value: blockatlas.Amount(tx.Value), + Symbol: coin.Coins[coinIndex].Symbol, + Decimals: coin.Coins[coinIndex].Decimals, + } + } } } diff --git a/platform/ethereum/blockbook/transaction_test.go b/platform/ethereum/blockbook/transaction_test.go index 1710deada..859358934 100644 --- a/platform/ethereum/blockbook/transaction_test.go +++ b/platform/ethereum/blockbook/transaction_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -137,7 +138,127 @@ func TestNormalizePage(t *testing.T) { "gasUsed": 29126, "gasPrice": "3000000000" } - } + }, + { + "txid": "0x7a3929f2fad5e61f535ed5c1317f34e739655d582bc1b0161b9869b0957df6af", + "vin": [ + { + "n": 0, + "addresses": [ + "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "567000000000000", + "n": 0, + "addresses": [ + "0x47331175b23C2f067204B506CA1501c26731C990" + ], + "isAddress": true + } + ], + "blockHash": "0xf08fd4b1d6ace92bf9516bbed37de100025f8b0879a80a92359a08f37e788b95", + "blockHeight": 10050786, + "confirmations": 43, + "blockTime": 1589278824, + "value": "567000000000000", + "fees": "407799043328112", + "ethereumSpecific": { + "status": 1, + "nonce": 535, + "gasLimit": 33000, + "gasUsed": 21064, + "gasPrice": "19360000158", + "data": "0xdeadbeef" + } + }, + { + "txid": "0xb1a56570bcb072d376630b987bd1f44ecc8f2c20ece52f02c9245296d3e3da39", + "vin": [ + { + "n": 0, + "addresses": [ + "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "addresses": [ + "0xdAC17F958D2ee523a2206206994597C13D831ec7" + ], + "isAddress": true + } + ], + "blockHeight": -1, + "confirmations": 0, + "blockTime": 1589279659, + "value": "0", + "fees": "0", + "rbf": true, + "tokenTransfers": [ + { + "type": "ERC20", + "from": "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "token": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "value": "23000000" + } + ], + "ethereumSpecific": { + "status": -1, + "nonce": 15647, + "gasLimit": 100000, + "gasUsed": null, + "gasPrice": "28560000000", + "data": "0xa9059cbb000000000000000000000000595031ff9bf6e0c1de20349e1377f43934f8951400000000000000000000000000000000000000000000000000000000015ef3c0" + } + }, + { + "txid": "0xfe7cce9928450e356f3332485e611781e407425b5888b8b2c7c66afaa4787cb1", + "vin": [ + { + "n": 0, + "addresses": [ + "0x267be1C1D684F78cb4F6a176C4911b741E4Ffdc0" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "295000000000000000", + "n": 0, + "addresses": [ + "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + ], + "isAddress": true + } + ], + "blockHeight": -1, + "confirmations": 0, + "blockTime": 1589287339, + "value": "295000000000000000", + "fees": "0", + "rbf": true, + "ethereumSpecific": { + "status": -1, + "nonce": 1282636, + "gasLimit": 30000, + "gasUsed": null, + "gasPrice": "24255000245", + "data": "0x" + } + } ]}`, address: "0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1", token: "", @@ -182,18 +303,80 @@ func TestNormalizePage(t *testing.T) { "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" } - }]`, + },{ + "id": "0x7a3929f2fad5e61f535ed5c1317f34e739655d582bc1b0161b9869b0957df6af", + "coin": 60, + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0x47331175b23C2f067204B506CA1501c26731C990", + "fee": "407799043328112", + "date": 1589278824, + "block": 10050786, + "status": "completed", + "sequence": 535, + "type": "contract_call", + "direction": "outgoing", + "memo": "", + "metadata": { + "input": "0xdeadbeef", + "value": "567000000000000" + } + },{ + "id": "0xb1a56570bcb072d376630b987bd1f44ecc8f2c20ece52f02c9245296d3e3da39", + "coin": 60, + "from": "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218", + "to": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "fee": "2856000000000000", + "date": 1589279659, + "block": 0, + "status": "pending", + "sequence": 15647, + "type": "token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "decimals": 6, + "value": "23000000", + "from": "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + } + },{ + "id": "0xfe7cce9928450e356f3332485e611781e407425b5888b8b2c7c66afaa4787cb1", + "coin": 60, + "from": "0x267be1C1D684F78cb4F6a176C4911b741E4Ffdc0", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "fee": "727650007350000", + "date": 1589287339, + "block": 0, + "status": "pending", + "sequence": 1282636, + "type": "transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "value": "295000000000000000", + "symbol": "ETH", + "decimals": 18 + } + } + ]`, }, } for _, tt := range tests { var page Page var txPage blockatlas.TxPage - _ = json.Unmarshal([]byte(tt.args.srcPage), &page) - _ = json.Unmarshal([]byte(tt.want), &txPage) + err := json.Unmarshal([]byte(tt.args.srcPage), &page) + assert.Nil(t, err) + err = json.Unmarshal([]byte(tt.want), &txPage) + assert.Nil(t, err) t.Run(tt.name, func(t *testing.T) { got := NormalizePage(&page, tt.args.address, tt.args.token, tt.args.coinIndex) - gotJson, _ := json.Marshal(got) - gotTxPage, _ := json.Marshal(txPage) + gotJson, err := json.Marshal(got) + assert.Nil(t, err) + gotTxPage, err := json.Marshal(txPage) + assert.Nil(t, err) if string(gotJson) != string(gotTxPage) { t.Errorf("NormalizePage() = %v, want %v", string(gotJson), string(gotTxPage)) } From 55208a7c0ff718fe12b7f1c3d9ea8fbfcb3c8bab Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 13 May 2020 21:21:25 +0300 Subject: [PATCH 293/506] Cosmos staking info will be cached in client level (#1095) --- platform/cosmos/client.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/cosmos/client.go b/platform/cosmos/client.go index 2378061dd..fd810dda7 100644 --- a/platform/cosmos/client.go +++ b/platform/cosmos/client.go @@ -7,6 +7,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/logger" "net/url" "strconv" + "time" ) // Client - the HTTP client @@ -32,7 +33,7 @@ func (c *Client) GetValidators() (validators Validators, err error) { query := url.Values{ "status": {"bonded"}, } - err = c.Get(&validators, "staking/validators", query) + err = c.GetWithCache(&validators, "staking/validators", query, time.Minute*10) return } @@ -58,11 +59,11 @@ func (c *Client) CurrentBlockNumber() (num int64, err error) { } func (c *Client) GetPool() (result StakingPool, err error) { - return result, c.Get(&result, "staking/pool", nil) + return result, c.GetWithCache(&result, "staking/pool", nil, time.Minute*20) } func (c *Client) GetInflation() (inflation Inflation, err error) { - err = c.Get(&inflation, "minting/inflation", nil) + err = c.GetWithCache(&inflation, "minting/inflation", nil, time.Minute*20) return } From b3bae43e64347cbfbff7ff0a52faf7729f12e102 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Thu, 14 May 2020 02:21:27 +0300 Subject: [PATCH 294/506] WIP Remove sentry and small cleanup (#1096) * Remove sentry and small cleanup * Change swagger api to login with pass --- CONTRIBUTING.md | 5 +- cmd/platform_api/main.go | 5 +- cmd/swagger_api/main.go | 14 ++--- config.yml | 6 +-- configmock.yml | 4 -- go.mod | 4 +- go.sum | 108 ++++----------------------------------- internal/init.go | 18 +------ pkg/errors/errors.go | 5 -- pkg/errors/sentry.go | 31 ----------- pkg/logger/error.go | 2 - pkg/logger/logger.go | 5 -- 12 files changed, 22 insertions(+), 185 deletions(-) delete mode 100755 pkg/errors/sentry.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index af68667c6..4d765fc7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,11 +64,8 @@ errors.E(err, errors.TypePlatformRequest, errors.Params{ ``` - Any other combinations above -You can send the errors to sentry using `.PushToSentry()` -`errors.E(err, errors.TypePlatformRequest).PushToSentry()` - -*All fatal errors emitted by logger package already send the error to Sentry* +*All fatal errors emitted by logger package already send the error to * __[List of error types](https://godoc.org/github.com/trustwallet/blockatlas/pkg/errors#Type)__ diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index 4e293b0a4..5bc8bc28c 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -1,7 +1,6 @@ package main import ( - sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" @@ -26,10 +25,8 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() - tmp := sentrygin.New(sentrygin.Options{}) - sg := &tmp - engine = internal.InitEngine(sg, viper.GetString("gin.mode")) + engine = internal.InitEngine(viper.GetString("gin.mode")) platform.Init(viper.GetString("platform")) } diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go index 617a8590d..dc2ad7802 100644 --- a/cmd/swagger_api/main.go +++ b/cmd/swagger_api/main.go @@ -1,7 +1,6 @@ package main import ( - sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" "github.com/spf13/viper" ginSwagger "github.com/swaggo/gin-swagger" @@ -9,7 +8,6 @@ import ( _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/pkg/logger" - "net/http" ) const ( @@ -24,18 +22,16 @@ var ( func init() { port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) - tmp := sentrygin.New(sentrygin.Options{}) - sg := &tmp internal.InitConfig(confPath) logger.InitLogger() - engine = internal.InitEngine(sg, viper.GetString("gin.mode")) + engine = internal.InitEngine(viper.GetString("gin.mode")) } func main() { logger.Info("Loading Swagger API") - engine.GET("/", func(c *gin.Context) { - c.Redirect(http.StatusMovedPermanently, "swagger/index.html") - }) - engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + admin := engine.Group("/admin", gin.BasicAuth(gin.Accounts{ + viper.GetString("gin.login"): viper.GetString("gin.pass"), + })) + admin.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) internal.SetupGracefulShutdown(port, engine) } diff --git a/config.yml b/config.yml index 0f8bf4ec3..0cef73168 100644 --- a/config.yml +++ b/config.yml @@ -1,6 +1,8 @@ # Gin is the web framework gin: # Possible values: "debug", "release" + login: admin + pass: pass mode: release # App running behind a reverse proxy? # If set, HTTP Forwarded headers will be respected @@ -11,10 +13,6 @@ gin: # You can see all the coin handles at coins/coins.yml file platform: all -# Sentry error tracking -#sentry: -# dsn: https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@sentry.io/xxxxxxx - # The transaction watcher observer: # Don't request blocks older than this diff --git a/configmock.yml b/configmock.yml index e8347768c..757655fdc 100644 --- a/configmock.yml +++ b/configmock.yml @@ -11,10 +11,6 @@ gin: # You can see all the coin handles at coins/coins.yml file platform: all -# Sentry error tracking -#sentry: -# dsn: https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@sentry.io/xxxxxxx - # The transaction watcher observer: backlog: 3h diff --git a/go.mod b/go.mod index c6fff5614..c1415e7a1 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,6 @@ require ( github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/getsentry/sentry-go v0.6.0 github.com/gin-gonic/gin v1.6.3 github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/jinzhu/gorm v1.9.12 @@ -35,8 +34,9 @@ require ( github.com/swaggo/swag v1.6.5 github.com/trustwallet/ens-coincodec v1.0.5 go.uber.org/atomic v1.6.0 - golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 + golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f + golang.org/x/tools v0.0.0-20200513175351-0951661448da // indirect gopkg.in/yaml.v2 v2.2.8 gotest.tools v2.2.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index feca575b4..fa19a1e17 100644 --- a/go.sum +++ b/go.sum @@ -12,18 +12,13 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= -github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= @@ -36,19 +31,15 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 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/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -76,20 +67,15 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 h1:3Wv1E0CqL45hBs4bykb586wvZMRGKfFITHrN3ilm4FE= github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb h1:nXPkFq8X1a9ycY3GYQpFNxHh3j2JgY7zDZfq2EXMIzk= github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c h1:4e6Zsb6LFd3kadoMiut2zcd3hCb4zywpJnQa8+NV2Cs= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c/go.mod h1:k5D13LCXSsMrQyfdW0yGYs4GWUvirqoxHht8qwtqyRY= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -99,29 +85,18 @@ github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9r github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/getsentry/sentry-go v0.6.0 h1:kPd+nr+dlXmaarUBg7xlC/qn+7wyMJL6PMsSn5fA+RM= -github.com/getsentry/sentry-go v0.6.0/go.mod h1:0yZBuzSvbZwBnvaF9VwZIMen3kXscY8/uasKtAX1qG8= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= @@ -133,15 +108,11 @@ github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6 github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= @@ -169,9 +140,6 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= @@ -191,7 +159,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -199,7 +166,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -209,7 +175,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= @@ -228,7 +193,6 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -239,12 +203,7 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= -github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= -github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= -github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= @@ -261,21 +220,10 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= -github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= -github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= -github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -286,13 +234,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -300,26 +245,19 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -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/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= 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/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= -github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= -github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= @@ -333,21 +271,15 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= -github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -361,8 +293,6 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= -github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= @@ -392,13 +322,10 @@ github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4 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= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -419,13 +346,11 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5NYJe/zRYDwOu9ku6YHy+Iw7l5DM= @@ -454,28 +379,15 @@ github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/o github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -488,18 +400,19 @@ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88= golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -519,6 +432,7 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -530,7 +444,6 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -539,6 +452,7 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -557,7 +471,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -570,8 +483,6 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -585,13 +496,11 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -607,7 +516,11 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200513175351-0951661448da h1:ZR1ivkcQoKXKtux9Rx3Em7iiSViMxQ5suNd5PZMUkPc= +golang.org/x/tools v0.0.0-20200513175351-0951661448da/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -651,7 +564,6 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= diff --git a/internal/init.go b/internal/init.go index 80b43872e..e61222cd7 100644 --- a/internal/init.go +++ b/internal/init.go @@ -2,7 +2,6 @@ package internal import ( "flag" - "fmt" "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/api/middleware" "github.com/trustwallet/blockatlas/config" @@ -10,7 +9,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/logger" "path/filepath" - "runtime" "time" ) @@ -40,10 +38,9 @@ func InitConfig(confPath string) { config.LoadConfig(confPath) } -func InitEngine(handler *gin.HandlerFunc, ginMode string) *gin.Engine { +func InitEngine(ginMode string) *gin.Engine { gin.SetMode(ginMode) engine := gin.New() - engine.Use(middleware.CheckReverseProxy, *handler) engine.Use(middleware.CORSMiddleware()) engine.Use(gin.Logger()) engine.Use(middleware.Prometheus()) @@ -59,16 +56,3 @@ func InitRabbitMQ(rabbitURI string, prefetchCount int) { } mq.PrefetchCount = prefetchCount } - -func LogVersionInfo() { - fmt.Printf(` -------------------------------------------------------------------------------- -Build: %v -Start date: %v -OS: %s -Go Arch: %s -Go Version: %s -------------------------------------------------------------------------------- -`, - Build, Date, runtime.GOOS, runtime.GOARCH, runtime.Version()) -} diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index 751f64f82..e82f718d5 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -74,11 +74,6 @@ func (e *Error) MarshalJSON() ([]byte, error) { return json.Marshal(e.JSON()) } -func (e *Error) PushToSentry() *Error { - SendError(e) - return e -} - // T create a new error with runtime stack trace. func T(args ...interface{}) *Error { e := E(args...) diff --git a/pkg/errors/sentry.go b/pkg/errors/sentry.go deleted file mode 100755 index b11c84865..000000000 --- a/pkg/errors/sentry.go +++ /dev/null @@ -1,31 +0,0 @@ -package errors - -import ( - "github.com/getsentry/sentry-go" - "github.com/spf13/viper" - "time" -) - -func InitSentry() error { - err := sentry.Init(sentry.ClientOptions{ - Dsn: viper.GetString("sentry.dsn"), - AttachStacktrace: true, - }) - if err != nil { - return E(err, "InitSentry failed") - } - return nil -} - -func SendError(err error) { - sentry.CaptureException(err) -} - -func SendFatal(err error) { - sentry.CaptureException(err) - sentry.Flush(time.Second * 5) -} - -func SendMessage(msg string) { - sentry.CaptureMessage(msg) -} diff --git a/pkg/logger/error.go b/pkg/logger/error.go index 5e7a37bf8..0a6411e33 100755 --- a/pkg/logger/error.go +++ b/pkg/logger/error.go @@ -23,7 +23,6 @@ func Fatal(args ...interface{}) { Panic("call to logger.Fatal with no arguments") } e := getError(args...) - errors.SendFatal(e.err) log.WithFields(e.params).Fatal(e.err) } @@ -32,7 +31,6 @@ func Panic(args ...interface{}) { Panic("call to logger.Panic with no arguments") } e := getError(args...) - errors.SendFatal(e.err) log.WithFields(e.params).Panic(e.err) } diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 76bd485bb..0540af00c 100755 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -3,7 +3,6 @@ package logger import ( "fmt" log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/errors" "os" "strings" ) @@ -13,10 +12,6 @@ type Params map[string]interface{} func InitLogger() { log.SetFormatter(&log.TextFormatter{}) log.SetOutput(os.Stdout) - err := errors.InitSentry() - if err != nil { - Error(err) - } } type message struct { From 033efb7c12972d3d4df424d6236ec2788cfc8bdb Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Thu, 14 May 2020 12:10:35 -0700 Subject: [PATCH 295/506] Checksum address according to Wanchain EIP55 spec (#1097) * Checksum address acording to Wanchain speck * Fix wrong ref passed to func * Add return to better indicate logic * Add ToEIP55ByCoinID and test * Fix test * remove unsued test param * remove redundant test --- pkg/address/address.go | 39 ++++++ pkg/address/address_test.go | 62 ++++++++- platform/ethereum/trustray/transaction.go | 15 +- .../ethereum/trustray/transaction_test.go | 128 ++++++++---------- 4 files changed, 168 insertions(+), 76 deletions(-) diff --git a/pkg/address/address.go b/pkg/address/address.go index e26b5d9bf..50610e8e7 100644 --- a/pkg/address/address.go +++ b/pkg/address/address.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "encoding/hex" "github.com/mr-tron/base58" + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "golang.org/x/crypto/sha3" @@ -59,3 +60,41 @@ func HexToAddress(hexAddr string) (b58 string, err error) { b58 = base58.EncodeAlphabet(bytes, base58.BTCAlphabet) return } + +// Returns an EIP55 Wanchain compliant hex string representation of the address. +// See https://wandevs.org/docs/difference-between-wanchain-and-ethereum/ +// https://github.com/wanchain/go-wanchain/blob/b238c203ca7dc6a578d57c0c473bec0fcf2431bd/common/types.go#L173 +func EIP55ChecksumWanchain(address string) string { + v := []byte(Remove0x(strings.ToLower(address))) + sha := sha3.NewLegacyKeccak256() + _, err := sha.Write(v) + if err != nil { + logger.Error(err) + } + hash := sha.Sum(nil) + + result := v + for i := 0; i < len(result); i++ { + hashByte := hash[i/2] + if i%2 == 0 { + hashByte = hashByte >> 4 + } else { + hashByte &= 0xf + } + if result[i] > '9' && hashByte <= 7 { + result[i] -= 32 + } + } + return "0x" + string(result) +} + +func ToEIP55ByCoinID(str string, coinID uint) string { + switch coinID { + case coin.ETH, coin.POA, coin.ETC, coin.TOMO, coin.CLO, coin.TT, coin.GO: + return EIP55Checksum(str) + case coin.WAN: + return EIP55ChecksumWanchain(str) + default: + return str + } +} diff --git a/pkg/address/address_test.go b/pkg/address/address_test.go index 1cae85506..9e9b74a2f 100644 --- a/pkg/address/address_test.go +++ b/pkg/address/address_test.go @@ -1,10 +1,12 @@ package address import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" "testing" ) -func TestChecksum(t *testing.T) { +func TestEIP55Checksum(t *testing.T) { tests := []struct { name string unchecksummed string @@ -16,6 +18,7 @@ func TestChecksum(t *testing.T) { {"test checksum hex", "fffdefefed", "0xFfFDEfeFeD"}, {"test checksum 3", "0x0000000000000000003731342d4f4e452d354639", "0x0000000000000000003731342d4f4E452d354639"}, {"test checksum 4", "0000000000000000003731342d4f4e452d354639", "0x0000000000000000003731342d4f4E452d354639"}, + {"test checksum Ethereum address", "0x84a0d77c693adabe0ebc48f88b3ffff010577051", "0x84A0d77c693aDAbE0ebc48F88b3fFFF010577051"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -26,6 +29,29 @@ func TestChecksum(t *testing.T) { } } +func TestEIP55ChecksumWanchain(t *testing.T) { + var ( + addr1Wan = "0xae96137e0e05681ed2f5d1af272c3ee512939d0f" + addr1WANEIP55 = "0xaE96137e0E05681Ed2f5d1af272c3EE512939d0f" + tests = []struct { + name string + unchecksummed string + want string + }{ + {"test 1", addr1Wan, addr1WANEIP55}, + {"test 2", addr1WANEIP55, addr1WANEIP55}, + } + ) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := EIP55ChecksumWanchain(tt.unchecksummed); got != tt.want { + t.Errorf("EIP55ChecksumWanchain() = %v, want %v", got, tt.want) + } + }) + } +} + func TestRemove0x(t *testing.T) { tests := []struct { name string @@ -59,3 +85,37 @@ func TestHexToAddress(t *testing.T) { t.Fatalf("expected %s, got %s", expected, got) } } + +func TestToEIP55ByCoinID(t *testing.T) { + var ( + addr1 = "0xea674fdde714fd979de3edf0f56aa9716b898ec8" + addr1EIP55 = "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8" + wanAddrLowercase = "0xae96137e0e05681ed2f5d1af272c3ee512939d0f" + wanAddrEIP55Checksum = "0xAe96137E0e05681eD2F5D1AF272C3ee512939D0F" + wanAddrEIP55ChecksumWanchain = "0xaE96137e0E05681Ed2f5d1af272c3EE512939d0f" + tests = []struct { + name, address, expectedAddress string + coinID uint + }{ + {"Ethereum", addr1, addr1EIP55, coin.ETH}, + {"Ethereum Classic", addr1, addr1EIP55, coin.ETC}, + {"POA", addr1, addr1EIP55, coin.POA}, + {"Callisto", addr1, addr1EIP55, coin.CLO}, + {"Tomochain", addr1, addr1EIP55, coin.TOMO}, + {"Thunder", addr1, addr1EIP55, coin.TT}, + {"Thunder", addr1, addr1EIP55, coin.TT}, + {"GoChain", addr1, addr1EIP55, coin.GO}, + {"Wanchain 1", wanAddrLowercase, wanAddrEIP55ChecksumWanchain, coin.WAN}, + {"Wanchain 2", wanAddrEIP55Checksum, wanAddrEIP55ChecksumWanchain, coin.WAN}, + {"Non Ethereum like chain 1", "", "", coin.TRX}, + {"Non Ethereum like chain 2", addr1, addr1, coin.BNB}, + } + ) + + t.Run("Test TestToEIP55ByCoinID", func(t *testing.T) { + for _, tt := range tests { + actual := ToEIP55ByCoinID(tt.address, tt.coinID) + assert.Equal(t, tt.expectedAddress, actual) + } + }) +} diff --git a/platform/ethereum/trustray/transaction.go b/platform/ethereum/trustray/transaction.go index a939e1b99..4e63361a6 100644 --- a/platform/ethereum/trustray/transaction.go +++ b/platform/ethereum/trustray/transaction.go @@ -30,7 +30,7 @@ func normalizePage(srcPage *Page, address string, coinIndex uint) blockatlas.TxP txs = AppendTxs(txs, &srcTx, coinIndex) txs[i].Direction = txs[i].GetTransactionDirection(address) } - return blockatlas.TxPage(txs) + return txs } func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas.Tx) { @@ -49,6 +49,7 @@ func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas Decimals: coin.Coins[coinIndex].Decimals, } out = append(out, transferTx) + return } // Smart Contract Call @@ -59,26 +60,27 @@ func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas Value: srcTx.Value, } out = append(out, contractTx) + return } if len(srcTx.Ops) == 0 { return } op := &srcTx.Ops[0] - + // Token transfer transaction if op.Type == blockatlas.TxTokenTransfer && op.Contract != nil { tokenTx := baseTx - tokenTx.Meta = blockatlas.TokenTransfer{ Name: op.Contract.Name, Symbol: op.Contract.Symbol, - TokenID: address.EIP55Checksum(op.Contract.Address), + TokenID: address.ToEIP55ByCoinID(op.Contract.Address, coinIndex), Decimals: op.Contract.Decimals, Value: blockatlas.Amount(op.Value), From: op.From, To: op.To, } out = append(out, tokenTx) + return } return } @@ -101,15 +103,16 @@ func extractBase(srcTx *Doc, coinIndex uint) (base blockatlas.Tx, ok bool) { base = blockatlas.Tx{ ID: srcTx.ID, Coin: coinIndex, - From: srcTx.From, - To: srcTx.To, Fee: blockatlas.Amount(fee), + From: address.ToEIP55ByCoinID(srcTx.From, coinIndex), + To: address.ToEIP55ByCoinID(srcTx.To, coinIndex), Date: srcTx.Timestamp, Block: srcTx.BlockNumber, Status: status, Error: errReason, Sequence: srcTx.Nonce, } + return base, true } diff --git a/platform/ethereum/trustray/transaction_test.go b/platform/ethereum/trustray/transaction_test.go index 4063fc02d..f723eeb33 100644 --- a/platform/ethereum/trustray/transaction_test.go +++ b/platform/ethereum/trustray/transaction_test.go @@ -3,11 +3,9 @@ package trustray import ( "bytes" "encoding/json" - "testing" - - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" ) const tokenTransferSrc = ` @@ -22,8 +20,8 @@ const tokenTransferSrc = ` "totalSupply": "120000000000000000", "name": "KaratBank Coin" }, - "from": "0xd35f30d194684a391c63a6deced7d3dd5207c265", - "to": "0xaa4d790076f1bf7511a0a0ac498c89e13e1efe17", + "from": "0xd35F30D194684a391C63A6decEd7d3dd5207c265", + "to": "0xaA4D790076f1Bf7511a0A0AC498C89e13e1eFE17", "type": "token_transfer", "value": "4291000000", "coin": 60 @@ -110,11 +108,16 @@ const failedSrc = ` "coin": 60 }` +var ( + addr1 = "0xd35F30D194684a391C63A6decEd7d3dd5207c265" + addr2 = "0xaA4D790076f1Bf7511a0A0AC498C89e13e1eFE17" + contract1 = "0xf3586684107CE0859c44aa2b2E0fB8cd8731a15a" +) var tokenTransferDst = blockatlas.Tx{ ID: "0x7777854580f273df61e0162e1a41b3e1e05ab8b9f553036fa9329a90dd7e9ab2", Coin: coin.ETH, - From: "0xd35f30d194684a391c63a6deced7d3dd5207c265", - To: "0xf3586684107ce0859c44aa2b2e0fb8cd8731a15a", + From: addr1, + To: contract1, Fee: "358254913291776", Date: 1554248437, Block: 7491945, @@ -123,19 +126,19 @@ var tokenTransferDst = blockatlas.Tx{ Meta: blockatlas.TokenTransfer{ Name: "KaratBank Coin", Symbol: "KBC", - TokenID: "0xf3586684107CE0859c44aa2b2E0fB8cd8731a15a", + TokenID: contract1, Decimals: 7, Value: "4291000000", - From: "0xd35f30d194684a391c63a6deced7d3dd5207c265", - To: "0xaa4d790076f1bf7511a0a0ac498c89e13e1efe17", + From: addr1, + To: addr2, }, } var contractCallDst = blockatlas.Tx{ ID: "0x34ab0028a9aa794d5cc12887e7b813cec17889948276b301028f24a408da6da4", Coin: coin.ETH, - From: "0xc9a16a82c284efc3cb0fe8c891ab85d6eba0eefb", - To: "0xc67f9c909c4d185e4a5d21d642c27d05a145a76c", + From: "0xc9a16a82c284EFC3cB0fE8C891ab85d6EBa0EeFB", + To: "0xc67f9C909C4d185E4A5d21D642c27D05A145a76c", Fee: "42680000000000", Date: 1554661737, Block: 7522627, @@ -150,8 +153,8 @@ var contractCallDst = blockatlas.Tx{ var transferDst = blockatlas.Tx{ ID: "0x77f8a3b2203933493d103a1637de814b4853410b1fb2981c4d2cff4d7a3071ab", Coin: coin.ETH, - From: "0xf5aea47e57c058881b31ee8fce1002c409188f06", - To: "0x0ae933a89d9e249d0873cfc7ca022fcb3f1280ce", + From: "0xf5AeA47E57c058881B31EE8fcE1002C409188F06", + To: "0x0Ae933A89D9E249D0873cfc7CA022fCB3F1280Ce", Fee: "105000000000000", Date: 1554663642, Block: 7522781, @@ -167,8 +170,8 @@ var transferDst = blockatlas.Tx{ var failedDst = blockatlas.Tx{ ID: "0x8dfe7e859f7bdcea4e6f4ada18567d96a51c3aa29e618ef09b80ae99385e191e", Coin: coin.ETH, - From: "0x4b55af7ce28a113d794f9a9940fe1506f37aa619", - To: "0xe65f787c8561a4b15771111bb427274dedfe85d7", + From: "0x4b55af7cE28A113D794F9A9940fe1506f37aA619", + To: "0xE65f787c8561A4b15771111bb427274deDfe85D7", Fee: "63000000000000", Date: 1554662399, Block: 7522678, @@ -182,59 +185,46 @@ var failedDst = blockatlas.Tx{ }, } -type test struct { - name string - apiResponse string - expected *blockatlas.Tx - token bool -} - func TestNormalize(t *testing.T) { - testNormalize(t, &test{ - name: "transfer", - apiResponse: transferSrc, - expected: &transferDst, - }) - testNormalize(t, &test{ - name: "token transfer", - apiResponse: tokenTransferSrc, - expected: &tokenTransferDst, - token: true, - }) - testNormalize(t, &test{ - name: "contract call", - apiResponse: contractCallSrc, - expected: &contractCallDst, - }) - testNormalize(t, &test{ - name: "failed transaction", - apiResponse: failedSrc, - expected: &failedDst, + var ( + doc Doc + tests = []struct { + name, apiResponse string + expected *blockatlas.Tx + }{ + {"transfer", transferSrc, &transferDst}, + {"token transfer", tokenTransferSrc, &tokenTransferDst}, + {"contract call", contractCallSrc, &contractCallDst}, + {"failed transaction", failedSrc, &failedDst}, + } + ) + + t.Run("TestNormalize", func(t *testing.T) { + for _, tt := range tests { + err := json.Unmarshal([]byte(tt.apiResponse), &doc) + if err != nil { + t.Error(err) + return + } + res := AppendTxs(nil, &doc, coin.ETH) + + resJSON, err := json.Marshal(res) + if err != nil { + t.Fatal(err) + } + + dstJSON, err := json.Marshal([]blockatlas.Tx{*tt.expected}) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(resJSON, dstJSON) { + println("\n", "Test failed ", tt.name) + println("resJSON", string(resJSON)) + println("dstJSON", string(dstJSON)) + t.Error(tt.name + ": tx don't equal") + } + } }) } -func testNormalize(t *testing.T, _test *test) { - var doc Doc - err := json.Unmarshal([]byte(_test.apiResponse), &doc) - if err != nil { - t.Error(err) - return - } - res := AppendTxs(nil, &doc, coin.ETH) - - resJSON, err := json.Marshal(res) - if err != nil { - t.Fatal(err) - } - - dstJSON, err := json.Marshal([]blockatlas.Tx{*_test.expected}) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error(_test.name + ": tx don't equal") - } -} From 255830288fc7b967230a87c5deaa5e131cc1b983 Mon Sep 17 00:00:00 2001 From: "mykola.eth" <3277207+kolya182@users.noreply.github.com> Date: Fri, 15 May 2020 16:51:53 -0700 Subject: [PATCH 296/506] Migrate Binance platform to use only DEX Explorer API for transactions and RPC fo the rest calls (#1010) * Init migration * Progress * Use rpc in config [skip ci] * Use rpc in config [skip ci] * Organize Tx structs and test * Update config * Update config * Squash tests * Squash tests * Comment out test and func related to non supported by client transfer types * Comment out test and func related to non supported by client transfer types * Clean up * Clean up * Update test * Sort in alphabetic order * Sort in alphabetic order * Remove unused/redundant code and test and replace with better tests * Set query tokens with cache, add and remove tests * rename func * Update platform/binance/transaction.go Co-Authored-By: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> * Make suggested changes * Make suggested changes * Fix tx,go and rewrite mocked test * Fix tx,go and rewrite mocked test * Remove outdated TODOs * Remove outdated TODOs * Add codacy ignore file * Add codacy ignore file * Code cleanup * Code cleanup * USe global tx per page amount value [skip ci] * Tokens limit to int * Use strconv.Itoa * Update block.go * Fix issue happened before with merge * Rebase with master #2 * Change mocked tests * fix binance mock * remove useless mock data * WIP use DEX as source of transactions * Mock test update. * Almost done - Add test - Convert types better * Adopt transfer to rpc transaction hash * Fix cleints path * Add func StringNumberToFloat64 and test * Update transaction and test * Update block and test * Update model and test * Fix lint * Add suggested changes * Try fix mock * Add dex to mock config * Fix test * Try Fix mock * Fix mock * Rename dex to explorer * Improve TxV2 conversion * Remove unused func in favor of explorer * Fix go lint * Remove / * remove print skip ci * Small naming changes * Remove redundant conversion * Start doing cleanup * Fix of normalization * Add and adjust test * Add tests for normalizeTxsToExplorer * Change marshal and coins * Change marshal again * Fix tx direction * Add test case for empty * Change marshal and normalization * Remove debug change * Requested changes and cleanup * Small change for normalizeTokens * Fix issues with invalid response for explorer for BNB only. Add filter for BNB only transactions * Remove unused code * Cleanup Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Co-authored-by: Nick Kozlov Co-authored-by: Catenocrypt --- .codacy.yml | 3 - coin/coins.go | 6 +- coin/coins.yml | 1 + config.yml | 7 +- configmock.yml | 4 +- mock/ext-api-dyson/get/binance-api-tx.js | 60 -- mock/ext-api-dyson/get/binance-api-txs.js | 86 --- .../get/binance-dex-commands2.js | 543 --------------- .../get/binance-rpc-commands2.js | 143 ++++ mock/ext-api-dyson/get/binance-rpc-txs.js | 69 ++ pkg/blockatlas/marshal.go | 4 +- pkg/blockatlas/tx.go | 5 +- pkg/numbers/decimal_test.go | 2 + pkg/numbers/number.go | 11 + pkg/numbers/number_test.go | 28 + platform/binance/base.go | 18 +- platform/binance/block.go | 76 ++- platform/binance/block_test.go | 124 ++++ platform/binance/client.go | 79 +-- platform/binance/dex_client.go | 27 - platform/binance/explorer_client.go | 32 + platform/binance/model.go | 402 +++++------ platform/binance/model_test.go | 408 ++++------- platform/binance/token.go | 56 +- platform/binance/token_test.go | 4 +- platform/binance/transaction.go | 288 ++++---- platform/binance/transaction_test.go | 642 ++++-------------- platform/platform.go | 2 +- services/observer/parser/parser.go | 2 +- tests/postman/token_data.json | 4 +- tests/postman/transaction_data.json | 4 +- 31 files changed, 1181 insertions(+), 1959 deletions(-) delete mode 100644 .codacy.yml delete mode 100644 mock/ext-api-dyson/get/binance-api-tx.js delete mode 100644 mock/ext-api-dyson/get/binance-api-txs.js delete mode 100644 mock/ext-api-dyson/get/binance-dex-commands2.js create mode 100644 mock/ext-api-dyson/get/binance-rpc-commands2.js create mode 100644 mock/ext-api-dyson/get/binance-rpc-txs.js create mode 100644 platform/binance/block_test.go delete mode 100644 platform/binance/dex_client.go create mode 100644 platform/binance/explorer_client.go diff --git a/.codacy.yml b/.codacy.yml deleted file mode 100644 index 4b6a06df4..000000000 --- a/.codacy.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -exclude_paths: - - 'mock/ext-api-dyson/**' diff --git a/coin/coins.go b/coin/coins.go index dcebc47bf..88e22e63b 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2020-03-19 12:32:14.57052 -0600 MDT m=+0.001450289 +// 2020-05-15 00:06:57.247245 +0300 MSK m=+0.001827650 // using data from coins.yml package coin @@ -243,7 +243,7 @@ var Coins = map[uint]Coin{ Name: "BNB", Decimals: 8, BlockTime: 4000, - MinConfirmations: 0, + MinConfirmations: 2, SampleAddr: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", }, VET: { @@ -557,7 +557,6 @@ var Coins = map[uint]Coin{ SampleAddr: "NEAR6Y66fCzeKqWiwxoPox5oGeDN9VhNCu7CEQ9M86iniqoN9vg2X", }, } - func Ethereum() Coin { return Coins[ETH] } @@ -702,3 +701,4 @@ func Solana() Coin { func Near() Coin { return Coins[NEAR] } + diff --git a/coin/coins.yml b/coin/coins.yml index 4379fd1bd..f1bc5b992 100644 --- a/coin/coins.yml +++ b/coin/coins.yml @@ -130,6 +130,7 @@ name: BNB decimals: 8 blockTime: 4000 + minConfirmations: 2 sampleAddress: 'tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2' - id: 818 diff --git a/config.yml b/config.yml index 0cef73168..4b4ef8cdb 100644 --- a/config.yml +++ b/config.yml @@ -37,11 +37,10 @@ observer: postgres: uri: postgresql://user:pass@localhost/my_db?sslmode=disable -# [BNB] Binance DEX: https://wallet.binance.org -# Binance Chain: https://explorer.binance.org +# [BNB] Binance DEX: https://www.binance.org/ binance: - api: https://explorer.binance.org/api/v1 - dex: https://dex.binance.org/api + api: https://dex.binance.org/api + explorer: https://explorer.binance.org/api # [NIM] Nimiq: https://nimiq.com #nimiq: diff --git a/configmock.yml b/configmock.yml index 757655fdc..95b934cc0 100644 --- a/configmock.yml +++ b/configmock.yml @@ -33,8 +33,8 @@ postgres: # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org binance: - api: http://localhost:3347/binance-api/v1 - dex: http://localhost:3347/binance-dex + api: https://dex.binance.org/api + explorer: http://localhost:3347/binance-explorer/api # [NIM] Nimiq: https://nimiq.com nimiq: diff --git a/mock/ext-api-dyson/get/binance-api-tx.js b/mock/ext-api-dyson/get/binance-api-tx.js deleted file mode 100644 index 63b0e1f75..000000000 --- a/mock/ext-api-dyson/get/binance-api-tx.js +++ /dev/null @@ -1,60 +0,0 @@ -/// Binance chain block explorer API Mock, tx -/// Returns: -/// - Multi-transaction transaction for a specific address -/// see http://localhost:3347/binance-api/v1/tx?txHash=F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC -/// see https://explorer.binance.org/api/v1/tx?txHash=F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC -/// see http://localhost:8437/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp -/// see http://localhost:8437/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp?token=BUSD-BD1 -/// - empty response for other txHash'es - -module.exports = { - path: '/binance-api/v1/tx', - template: function(params, query, body) { - if (query['txHash'] == 'F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC') { - return { - txHash: "F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC", - blockHeight: Number.parseFrom('63280715'), - txType: "TRANSFER", - timeStamp: Number.parseFrom('1579688431580'), - txFee: Number.parseFrom('0.00060'), - txAge: Number.parseFrom('2350509'), - code: 0, - log: "Msg 0: ", - confirmBlocks: 5818526, - memo: "Trust Wallet Redeem", - source: 0, - sequence: 175, - hasChildren: 1, - subTxsDto: { - totalNum: 2, - pageSize: 15, - subTxDtoList: [ - { - hash: "F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC", - height: Number.parseFrom('63280715'), - type: "TRANSFER", - value: 0.00375, - asset: "BNB", - fromAddr: "bnb1rhv98jcx2yu26shxedskttjzpkvsrz4nd226yv", - toAddr: "bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp", - fee: Number.parseFrom('0.00060') - }, - { - hash: "F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC", - height: Number.parseFrom('63280715'), - type: "TRANSFER", - value: 10.0, - asset: "BUSD-BD1", - fromAddr: "bnb1rhv98jcx2yu26shxedskttjzpkvsrz4nd226yv", - toAddr: "bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp", - fee: null - } - ] - } - }; - } - - // not found txHash, return empty response - return {} - } -}; diff --git a/mock/ext-api-dyson/get/binance-api-txs.js b/mock/ext-api-dyson/get/binance-api-txs.js deleted file mode 100644 index 3c0591db0..000000000 --- a/mock/ext-api-dyson/get/binance-api-txs.js +++ /dev/null @@ -1,86 +0,0 @@ -/// Binance chain block explorer API Mock, txs -/// Return -/// - for address 'bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp' 2 txs, one of them multi -/// - for address 'bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd' 1 tx -/// - empty list for other addresses -/// See: -/// curl "http://localhost:3347/explorer-api/v1/txs?address=bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp&page=1&rows=20&txAsset=BNB&txType=TRANSFER" -/// curl "https://explorer.binance.org/api/v1/txs?address=bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp&page=1&rows=20&txAsset=BNB&txType=TRANSFER" -/// curl "http://localhost:8437/v1/binance/bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp" - -module.exports = { - path: '/binance-api/v1/txs', - template: function(params, query, body) { - //console.log(query); - var address = query['address']; - //console.log('address', address); - switch (address) { - case 'bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp': - return JSON.parse(`{ - "txNums": 2, - "txArray": [ - { - "txHash": "4A5E688755E3588B89C5F0325274430AA52786E527313739C542BC69436E18F4", - "blockHeight": 63282272, - "txType": "TRANSFER", - "timeStamp": 1579689046296, - "fromAddr": "bnb1563k58pc3keeuwkhlrxwz7sdsetyn9l7gdnznp", - "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "value": 0.55415460, - "txAsset": "BNB", - "txFee": 0.00037500, - "txAge": 5273327, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "102101832", - "source": 0, - "hasChildren": 0 - }, - { - "txHash": "F53BB470A3B6B83977CFFE5D5F9937FB1CBB8785FBE818D9B38AD43F3ECD82BC", - "blockHeight": 63280715, - "txType": "TRANSFER", - "timeStamp": 1579688431580, - "txFee": 0.00060000, - "txAge": 5273941, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "Trust Wallet Redeem", - "source": 0, - "hasChildren": 1 - } - ] - }`); - - case 'bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd': - return JSON.parse(`{ - "txNums": 1, - "txArray": [ - { - "txHash": "DDA939C475755B2A00123CDA37A5EC442F502EA2983014D04F647C3CB9FB57A0", - "blockHeight": 75110907, - "txType": "TRANSFER", - "timeStamp": 1584450870939, - "fromAddr": "bnb166fvwtfra2atta5mm8mygt2fyltktqctgpedcg", - "toAddr": "bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd", - "value": 0.00037500, - "txAsset": "BNB", - "txFee": 0.00037500, - "txAge": 10170, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "", - "source": 0, - "hasChildren": 0 - } - ] - }`); - } - - // not found, address - return {txNums: 0, txArray: []} - } -}; diff --git a/mock/ext-api-dyson/get/binance-dex-commands2.js b/mock/ext-api-dyson/get/binance-dex-commands2.js deleted file mode 100644 index 6a7299f78..000000000 --- a/mock/ext-api-dyson/get/binance-dex-commands2.js +++ /dev/null @@ -1,543 +0,0 @@ -/// Binance chain block explorer API Mock, Dex -/// See: -/// curl "http://localhost:3347/binance-dex/v1/account/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" -/// curl "http://localhost:3347/binance-dex/v1/tokens?limit=1000&offset=0" -/// curl "https://dex.binance.org/api/v1/account/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" -/// curl "https://dex.binance.org/api/v1/tokens?limit=1000&offset=0" -/// curl "http://localhost:8437/v2/binance/tokens/bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m?Authorization=Bearer" - -module.exports = { - path: '/binance-dex/:version/:command1/:command2?', - template: function(params, query, body) { - //console.log(params); - //console.log(query); - switch (params.version) { - case 'v1': - switch (params.command1) { - case 'account': - switch (params.command2) { - case 'bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m': - return JSON.parse(` - { - "account_number": 51, - "address": "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m", - "balances": [ - { - "free": "1732627268.91580163", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "CHZ-ECD" - }, - { - "free": "927279.98843502", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "GTO-908" - }, - { - "free": "22990392.97970594", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "LBA-340" - }, - { - "free": "13504.20603578", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "LTC-F07" - }, - { - "free": "1.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "SLV-986" - }, - { - "free": "3400.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "TWT-8C2" - }, - { - "free": "417595410.39908617", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "COS-2E4" - }, - { - "free": "8859448.20434497", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "XRP-BF2" - }, - { - "free": "66199647.50538896", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "VRAB-B56" - }, - { - "free": "565.32000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "AERGO-46B" - }, - { - "free": "145.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ART-3C9" - }, - { - "free": "483312.47553546", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BOLT-4C6" - }, - { - "free": "85668472.69714541", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ERD-D06" - }, - { - "free": "372741.55000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "MDAB-D42" - }, - { - "free": "56343499.10367935", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ONE-5F9" - }, - { - "free": "2000000.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BCPT-95A" - }, - { - "free": "5.00110000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BEAR-14C" - }, - { - "free": "2000.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "GIV-94E" - }, - { - "free": "9.44356120", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "NEXO-A84" - }, - { - "free": "193182441.20916349", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "UND-EBC" - }, - { - "free": "569871.98092216", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "TUSDB-888" - }, - { - "free": "316344310.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BKRW-AB7" - }, - { - "free": "0.00091449", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "EOSBEAR-721" - }, - { - "free": "10918.75299816", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "EOSBULL-F0D" - }, - { - "free": "296751584.10699693", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "TROY-9B8" - }, - { - "free": "450587749.03659246", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "WINB-41F" - }, - { - "free": "1438139.59497068", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ARN-71B" - }, - { - "free": "19597996.48343213", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "COTI-CBB" - }, - { - "free": "3572612.16675809", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "LTO-BDF" - }, - { - "free": "1.22227000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "XRPBEAR-00B" - }, - { - "free": "8619272.37637807", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "CAN-677" - }, - { - "free": "338507.95870700", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "HNST-3C9" - }, - { - "free": "173741504.28850373", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BTTB-D31" - }, - { - "free": "65500.72562560", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BUSD-BD1" - }, - { - "free": "8549.17210965", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ETH-1C9" - }, - { - "free": "1654100.82380293", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "TOMOB-4BC" - }, - { - "free": "5.00455774", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "XRPBULL-E7C" - }, - { - "free": "35.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "AWC-986" - }, - { - "free": "1587996.65265528", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BNB" - }, - { - "free": "45605.00637205", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "QARK-FCE" - }, - { - "free": "1406863.84448749", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ARPA-575" - }, - { - "free": "1619733.62576473", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ENTRP-C8D" - }, - { - "free": "0.01392000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "MTXLT-286" - }, - { - "free": "2340.58605759", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BCH-1FD" - }, - { - "free": "3.49158551", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BULL-BE4" - }, - { - "free": "1.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ECO-083" - }, - { - "free": "0.50000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "WICC-01D" - }, - { - "free": "4235575.51194174", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "KAVA-10C" - }, - { - "free": "10.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "PVT-554" - }, - { - "free": "9772.00009772", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "UPX-F3E" - }, - { - "free": "221000.60154058", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "USDSB-1AC" - }, - { - "free": "4372695.27174854", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "WRX-ED1" - }, - { - "free": "19906076.03857030", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "PHB-2DF" - }, - { - "free": "12696933.52213685", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "TRXB-2E6" - }, - { - "free": "267793524.10892121", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BLINK-9C6" - }, - { - "free": "3370.02600563", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BTCB-1DE" - }, - { - "free": "103467039.59858401", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "CBM-4B2" - }, - { - "free": "4095309.32370000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "DUSK-45E" - }, - { - "free": "82964636.96725382", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "FTM-A64" - }, - { - "free": "182686435.86912742", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ANKR-E97" - }, - { - "free": "5.00100000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ETHBEAR-B2B" - }, - { - "free": "0.00872511", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ETHBULL-D33" - }, - { - "free": "39286407.28666093", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "MATIC-84A" - }, - { - "free": "20813555.86251786", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "MITH-C76" - } - ], - "flags": 0, - "public_key": [ - 3, - 86, - 224, - 165, - 128, - 56, - 154, - 111, - 210, - 204, - 145, - 205, - 82, - 92, - 109, - 90, - 77, - 128, - 84, - 175, - 112, - 223, - 23, - 72, - 78, - 88, - 103, - 143, - 159, - 87, - 74, - 11, - 77 - ], - "sequence": 547072 - } - `); - } - break; - - case 'tokens': - return JSON.parse(` - [ - { - "mintable": true, - "name": "Africa Stable-Coin", - "original_symbol": "ABCD", - "owner": "bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms", - "symbol": "ABCD-5D8", - "total_supply": "3347000.00000000" - }, - { - "mintable": false, - "name": "Aditus", - "original_symbol": "ADI", - "owner": "bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps", - "symbol": "ADI-6BB", - "total_supply": "750000000.00000000" - }, - { - "mintable": false, - "name": "Aergo", - "original_symbol": "AERGO", - "owner": "bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl", - "symbol": "AERGO-46B", - "total_supply": "500000000.00000000" - }, - { - "mintable": false, - "name": "Alaris", - "original_symbol": "ALA", - "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", - "symbol": "ALA-DCD", - "total_supply": "60000000.00000000" - }, - { - "mintable": false, - "name": "ANKR", - "original_symbol": "ANKR", - "owner": "bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn", - "symbol": "ANKR-E97", - "total_supply": "10000000000.00000000" - }, - { - "mintable": false, - "name": "Aeron", - "original_symbol": "ARN", - "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", - "symbol": "ARN-71B", - "total_supply": "20000000.00000000" - }, - { - "mintable": true, - "name": "ARPA", - "original_symbol": "ARPA", - "owner": "bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c", - "symbol": "ARPA-575", - "total_supply": "12000000.00000000" - }, - { - "mintable": false, - "name": "Maecenas ART Token", - "original_symbol": "ART", - "owner": "bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l", - "symbol": "ART-3C9", - "total_supply": "100000000.00000000" - }, - { - "mintable": true, - "name": "Atlas Protocol", - "original_symbol": "ATP", - "owner": "bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf", - "symbol": "ATP-38C", - "total_supply": "40000000.00000000" - }, - { - "mintable": false, - "name": "Travala.com Token", - "original_symbol": "AVA", - "owner": "bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c", - "symbol": "AVA-645", - "total_supply": "61383832.00000000" - } - ] - `); - } - } - - // not found, address - return {txNums: 0, txArray: []} - } -}; diff --git a/mock/ext-api-dyson/get/binance-rpc-commands2.js b/mock/ext-api-dyson/get/binance-rpc-commands2.js new file mode 100644 index 000000000..a20a7f4fd --- /dev/null +++ b/mock/ext-api-dyson/get/binance-rpc-commands2.js @@ -0,0 +1,143 @@ +/// Binance chain RPC Mock +/// See: +/// curl "http://localhost:3347/binance-rpc/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q" +/// curl "http://localhost:3347/binance-rpc/v1/tokens?limit=1000&offset=0" +/// curl "https://{binance_rpc}/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q" +/// curl "https://{binance_rpc}/v1/tokens?limit=1000&offset=0" +/// curl "http://localhost:8437/v2/binance/tokens/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q?Authorization=Bearer" + +module.exports = { + path: '/binance-rpc/:version/:command1/:command2?', + template: function(params, query, body) { + switch (params.version) { + case 'v1': + switch (params.command1) { + case 'account': + switch (params.command2) { + case 'bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q': + return JSON.parse(` + { + "account_number": 273171, + "address": "bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q", + "balances": [ + { + "free": "226.53110295", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BNB" + }, + { + "free": "2623.96917801", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BUSD-BD1" + }, + { + "free": "0.05000000", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "TWT-8C2" + } + ], + "flags": 0, + "public_key": [ + 2, 142, 117 + ], + "sequence": 75 + } + `); + } + break; + + case 'tokens': + return JSON.parse(` + [ + { + "mintable": true, + "name": "Africa Stable-Coin", + "original_symbol": "ABCD", + "owner": "bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms", + "symbol": "ABCD-5D8", + "total_supply": "3347000.00000000" + }, + { + "mintable": false, + "name": "Aditus", + "original_symbol": "ADI", + "owner": "bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps", + "symbol": "ADI-6BB", + "total_supply": "750000000.00000000" + }, + { + "mintable": false, + "name": "Aergo", + "original_symbol": "AERGO", + "owner": "bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl", + "symbol": "AERGO-46B", + "total_supply": "500000000.00000000" + }, + { + "mintable": false, + "name": "Alaris", + "original_symbol": "ALA", + "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", + "symbol": "ALA-DCD", + "total_supply": "60000000.00000000" + }, + { + "mintable": false, + "name": "ANKR", + "original_symbol": "ANKR", + "owner": "bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn", + "symbol": "ANKR-E97", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Aeron", + "original_symbol": "ARN", + "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", + "symbol": "ARN-71B", + "total_supply": "20000000.00000000" + }, + { + "mintable": true, + "name": "ARPA", + "original_symbol": "ARPA", + "owner": "bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c", + "symbol": "ARPA-575", + "total_supply": "12000000.00000000" + }, + { + "mintable": false, + "name": "Maecenas ART Token", + "original_symbol": "ART", + "owner": "bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l", + "symbol": "ART-3C9", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "Atlas Protocol", + "original_symbol": "ATP", + "owner": "bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf", + "symbol": "ATP-38C", + "total_supply": "40000000.00000000" + }, + { + "mintable": false, + "name": "Travala.com Token", + "original_symbol": "AVA", + "owner": "bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c", + "symbol": "AVA-645", + "total_supply": "61383832.00000000" + } + ] + `); + } + } + + // not found, address + return {txNums: 0, txArray: []} + } +}; diff --git a/mock/ext-api-dyson/get/binance-rpc-txs.js b/mock/ext-api-dyson/get/binance-rpc-txs.js new file mode 100644 index 000000000..5813d3dc9 --- /dev/null +++ b/mock/ext-api-dyson/get/binance-rpc-txs.js @@ -0,0 +1,69 @@ +/// Binance chain block explorer mock transaction +/// Returns: +/// - Multi-transaction transaction for a specific address +/// 1. newman calls: http://localhost:8437/v1/binance/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q +/// 2. Block Atlas calls internally : https://{binance_explorer}/api/v1/txs?address=bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q&page=1&rows=25&txType=TRANSFER +/// 3. Dyson response mock data: http://localhost:3347/binance-explorer/api/v1/txs?address=bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q&page=1&rows=25&txType=TRANSFER +/// - empty response for other txHash'es + +// Example contains each type, BNB transfer, BEP2 transfer, BEP2 transfer as multisend transaction +module.exports = { + path: '/binance-explorer/api/v1/txs', + template: function (params, query, body) { + return JSON.parse(`{ + "txNums": 3, + "txArray": [ + { + "txHash": "963D8C627DE1E739845C0AC0C0EAC3387B53806C77289ACB8C1653CD6D62C9CC", + "blockHeight": 84191249, + "txType": "TRANSFER", + "timeStamp": 1588086370574, + "fromAddr": "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", + "toAddr": "bnb1mr5f97rx5wnkfcakx9fcpvljmx2s6kwqc08yur", + "value": 2800.00000000, + "txAsset": "TWT-8C2", + "txFee": 0.00037500, + "txAge": 446701, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "hasChildren": 0 + }, + { + "txHash": "4577CB3B5B202696E9E0B093A6DA973C7DD9CBC6808DA1326872745C35F3C089", + "blockHeight": 84191216, + "txType": "TRANSFER", + "timeStamp": 1588086357686, + "fromAddr": "bnb1mr5f97rx5wnkfcakx9fcpvljmx2s6kwqc08yur", + "toAddr": "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", + "value": 0.00040000, + "txAsset": "BNB", + "txFee": 0.00037500, + "txAge": 446714, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "hasChildren": 0 + }, + { + "txHash": "FAD8C1C5E450BE5E0913B12007AAEACC307F8CFFAFFB0844A9F83155E1235C25", + "blockHeight": 80167666, + "txType": "TRANSFER", + "timeStamp": 1586464452922, + "txFee": 0.29970000, + "txAge": 2068619, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "hasChildren": 1 + } + ] +}`) + } +}; diff --git a/pkg/blockatlas/marshal.go b/pkg/blockatlas/marshal.go index 91b9a543f..8be4e22fb 100644 --- a/pkg/blockatlas/marshal.go +++ b/pkg/blockatlas/marshal.go @@ -47,7 +47,9 @@ func (t *Tx) UnmarshalJSON(data []byte) error { default: return errors.E("unsupported tx type", errors.Params{"type": t.Type}) } - if err := json.Unmarshal(raw, t.Meta); err != nil { + + err := json.Unmarshal(raw, t.Meta) + if err != nil { return err } return nil diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index e36e14165..d0ec8a63a 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -93,10 +93,9 @@ type ( Date int64 `json:"date"` // Height of the block the transaction was included in Block uint64 `json:"block"` - // Status of the transaction + // Status of the transaction e.g: "completed", "pending", "error" Status Status `json:"status"` - // Empty if the transaction was successful, - // else error explaining why the transaction failed (optional) + // Empty if the transaction "completed" or "pending", else error explaining why the transaction failed (optional) Error string `json:"error,omitempty"` // Transaction nonce or sequence Sequence uint64 `json:"sequence"` diff --git a/pkg/numbers/decimal_test.go b/pkg/numbers/decimal_test.go index b32ed8977..2cfcc29e7 100644 --- a/pkg/numbers/decimal_test.go +++ b/pkg/numbers/decimal_test.go @@ -30,6 +30,7 @@ func TestDecimalExp(t *testing.T) { // No-Op assertEquals("0", 300, "0") + assertEquals("0", 8, "0") assertEquals("123", 0, "123") assertEquals("0.456", 0, "0.456") assertEquals("123.456", 0, "123.456") @@ -57,6 +58,7 @@ func TestDecimalExp(t *testing.T) { // Tiny assertEquals("0.001234", -1, "0.0001234") assertEquals("0.001234", 1, "0.01234") + assertEquals("0.000375", 8, "37500") } func TestCutZeroFractional(t *testing.T) { diff --git a/pkg/numbers/number.go b/pkg/numbers/number.go index c36be11b9..7ac3208fa 100644 --- a/pkg/numbers/number.go +++ b/pkg/numbers/number.go @@ -32,10 +32,21 @@ func Float64toPrecision(num float64, precision int) float64 { return float64(Round(num*output)) / output } +// 0.1010 => "0.101" func Float64toString(num float64) string { return strconv.FormatFloat(num, 'f', -1, 64) } +// "0.00037500" => 0.000375, "non-string-number" => 0 +func StringNumberToFloat64(str string) (float64, error) { + value, err := strconv.ParseFloat(str, 64) + if err != nil { + return 0, err + } else { + return value, nil + } +} + func FromDecimal(dec string) string { v, err := DecimalToSatoshis(dec) if err != nil { diff --git a/pkg/numbers/number_test.go b/pkg/numbers/number_test.go index 23d0ce429..5af1964ff 100644 --- a/pkg/numbers/number_test.go +++ b/pkg/numbers/number_test.go @@ -64,4 +64,32 @@ func TestFloat64toString(t *testing.T) { assert.Equal(t, Float64toString(1), "1") assert.Equal(t, Float64toString(1.1), "1.1") assert.Equal(t, Float64toString(1.015), "1.015") + assert.Equal(t, Float64toString(2800.00000000), "2800") + assert.Equal(t, Float64toString(0.00037500), "0.000375") +} + +func TestStringNumberToFloat64(t *testing.T) { + var tests = []struct { + stringNumber string + expect float64 + ecpectErr bool + }{ + {"0.29970000", 0.2997, false}, + {"0.00037500", 0.000375, false}, + {"1.0", 1, false}, + {"1", 1, false}, + {"0", 0, false}, + {"23.12", 23.120, true}, + } + + for _, tt := range tests { + t.Run("", func(t *testing.T) { + actual, err := StringNumberToFloat64(tt.stringNumber) + if tt.ecpectErr { + assert.Nil(t, err) + } else { + assert.Equal(t, tt.expect, actual) + } + }) + } } diff --git a/platform/binance/base.go b/platform/binance/base.go index 55f9fb345..678bf0f81 100644 --- a/platform/binance/base.go +++ b/platform/binance/base.go @@ -6,18 +6,18 @@ import ( ) type Platform struct { - client Client - dexClient DexClient + rpcClient Client + explorerClient ExplorerClient } -func Init(api, dex string) *Platform { - p := &Platform{ - client: Client{blockatlas.InitClient(api)}, - dexClient: DexClient{blockatlas.InitClient(dex)}, +func Init(rpcApi, explorerApi string) *Platform { + p := Platform{ + rpcClient: Client{blockatlas.InitClient(rpcApi)}, + explorerClient: ExplorerClient{blockatlas.InitClient(explorerApi)}, } - p.client.ErrorHandler = getHTTPError - p.dexClient.ErrorHandler = getHTTPError - return p + p.rpcClient.ErrorHandler = handleHTTPError + p.explorerClient.ErrorHandler = handleHTTPError + return &p } func (p *Platform) Coin() coin.Coin { diff --git a/platform/binance/block.go b/platform/binance/block.go index c4647d8bb..90b931d90 100644 --- a/platform/binance/block.go +++ b/platform/binance/block.go @@ -2,38 +2,74 @@ package binance import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/numbers" + "time" ) func (p *Platform) CurrentBlockNumber() (int64, error) { - // No native function to get height in explorer API - // Workaround: Request list of blocks - // and return number of the newest one - list, err := p.client.GetBlockList(1) + info, err := p.rpcClient.fetchNodeInfo() if err != nil { return 0, err } - if len(list.BlockArray) == 0 { - return 0, errors.E("no block descriptor found", errors.TypePlatformApi) - } - return list.BlockArray[0].BlockHeight, nil + + return info.SyncInfo.LatestBlockHeight, nil } func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - srcTxs, err := p.client.GetBlockByNumber(num) + blockTransactions, err := p.rpcClient.fetchBlockTransactions(num) if err != nil { return nil, err } - var txs blockatlas.TxPage - childTxs, err := p.getTxChildChan(srcTxs.Txs) - if err == nil { - txs = NormalizeTxs(childTxs, "", "") - } else { - txs = NormalizeTxs(srcTxs.Txs, "", "") + explorerTransactions := make([]ExplorerTxs, 0, len(blockTransactions)) + for _, tx := range blockTransactions { + explorerTransactions = append(explorerTransactions, normalizeTxsToExplorer(tx)) + } + + var normalizedTxs []blockatlas.Tx + for _, tx := range explorerTransactions { + normalizedTx := normalizeTx(tx, "") + if normalizedTx == nil { + continue + } + normalizedTxs = append(normalizedTxs, normalizedTx...) + } + + return &blockatlas.Block{Number: num, Txs: normalizedTxs}, nil +} + +func normalizeTxsToExplorer(txV2 TxV2) ExplorerTxs { + tx := ExplorerTxs{ + TxAsset: txV2.Asset, + Code: txV2.Code, + FromAddr: txV2.FromAddr, + TxHash: txV2.TxHash, + Memo: txV2.Memo, + ToAddr: txV2.ToAddr, + TxType: txV2.Type, + BlockHeight: txV2.BlockHeight, + } + + if value, err := numbers.StringNumberToFloat64(txV2.Value); err == nil { + tx.Value = value + } + if txV2.Fee == "" && len(txV2.SubTransactions) > 1 { + txV2.Fee = txV2.SubTransactions[0].Fee + } + if fee, err := numbers.StringNumberToFloat64(txV2.Fee); err == nil { + tx.TxFee = fee + } + if len(txV2.SubTransactions) > 0 { + tx.HasChildren = 1 + } + if t, err := time.Parse(time.RFC3339, txV2.Timestamp); err == nil { + tx.Timestamp = t.Unix() + } + + mts := make([]MultiTransfer, len(txV2.SubTransactions)) + for i, st := range txV2.SubTransactions { + mts[i] = MultiTransfer{Amount: st.Value, Asset: st.Asset, From: st.FromAddr, To: st.ToAddr} } - return &blockatlas.Block{ - Number: num, - Txs: txs, - }, nil + tx.MultisendTransfers = mts + return tx } diff --git a/platform/binance/block_test.go b/platform/binance/block_test.go new file mode 100644 index 000000000..6baaf37df --- /dev/null +++ b/platform/binance/block_test.go @@ -0,0 +1,124 @@ +package binance + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "testing" +) + +const ( + bnbSingleTransfer = ` +{ + "blockHeight": 84191216, + "tx": [ + { + "txHash": "4577CB3B5B202696E9E0B093A6DA973C7DD9CBC6808DA1326872745C35F3C089", + "blockHeight": 84191216, + "txType": "TRANSFER", + "timeStamp": "2020-04-28T15:05:57.686Z", + "fromAddr": "bnb1mr5f97rx5wnkfcakx9fcpvljmx2s6kwqc08yur", + "toAddr": "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", + "value": "0.00040000", + "txAsset": "BNB", + "txFee": "0.00037500", + "code": 0, + "data": null, + "memo": "", + "source": 0, + "sequence": 95 + } + ] +}` + bep2MultiTransfer = ` +{ + "blockHeight": 80167666, + "tx": [ + { + "txHash": "FAD8C1C5E450BE5E0913B12007AAEACC307F8CFFAFFB0844A9F83155E1235C25", + "blockHeight": 80167666, + "txType": "TRANSFER", + "timeStamp": "2020-04-09T20:34:12.922Z", + "fromAddr": null, + "toAddr": null, + "value": null, + "txAsset": null, + "txFee": null, + "code": 0, + "data": null, + "memo": "multisend", + "source": 1, + "sequence": 72, + "subTransactions": [ + { + "txHash": "FAD8C1C5E450BE5E0913B12007AAEACC307F8CFFAFFB0844A9F83155E1235C25", + "blockHeight": 80167666, + "txType": "TRANSFER", + "fromAddr": "bnb1ds83nt2tz2s9m7kkdcu53t3ccjc07un4xvdld7", + "toAddr": "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", + "txAsset": "TWT-8C2", + "txFee": "0.29970000", + "value": "2800.00000000" + } + ] + } + ] +} +` +) + +var ( + expectBnbSingleRPCV2TransferResponse = ExplorerTxs{ + BlockHeight: 84191216, + Code: 0, + FromAddr: "bnb1mr5f97rx5wnkfcakx9fcpvljmx2s6kwqc08yur", + HasChildren: 0, + Memo: "", + MultisendTransfers: []MultiTransfer{}, + Timestamp: 1588086357, + ToAddr: "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", + TxFee: 0.000375, + TxHash: "4577CB3B5B202696E9E0B093A6DA973C7DD9CBC6808DA1326872745C35F3C089", + TxType: "TRANSFER", + Value: 0.0004, + TxAsset: "BNB", + } + + expectBEP2MultiRPCV2TransferResponse = ExplorerTxs{ + BlockHeight: 80167666, + Code: 0, + HasChildren: 1, + Memo: "multisend", + MultisendTransfers: bep2MultisendTransfer, + Timestamp: 1586464452, + TxHash: "FAD8C1C5E450BE5E0913B12007AAEACC307F8CFFAFFB0844A9F83155E1235C25", + TxType: "TRANSFER", + Value: 0, + } + + sender = "bnb1ds83nt2tz2s9m7kkdcu53t3ccjc07un4xvdld7" + receiver = "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl" + + bep2MultisendTransfer = []MultiTransfer{ + {Amount: "2800.00000000", Asset: "TWT-8C2", From: sender, To: receiver}, + } +) + +func Test_normalizeBlockSubTx(t *testing.T) { + tests := []struct { + name string + V2Response string + expected ExplorerTxs + }{ + {name: "Normalize single BNB transfer", V2Response: bnbSingleTransfer, expected: expectBnbSingleRPCV2TransferResponse}, + {name: "Normalize multiple BEP2 transfer", V2Response: bep2MultiTransfer, expected: expectBEP2MultiRPCV2TransferResponse}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var blockTxs BlockTransactions + err := json.Unmarshal([]byte(tt.V2Response), &blockTxs) + assert.Nil(t, err) + assert.Equal(t, tt.expected, normalizeTxsToExplorer(blockTxs.Txs[0]), "tx don't equal") + }) + } +} diff --git a/platform/binance/client.go b/platform/binance/client.go index cd1b2f1f0..b920034f0 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -2,83 +2,70 @@ package binance import ( "encoding/json" + "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "net/http" "net/url" - "strconv" + "time" ) -// TODO Headers + rate limiting - type Client struct { blockatlas.Request } -func (c *Client) GetBlockList(count int) (*BlockList, error) { - result := new(BlockList) - query := url.Values{"rows": {strconv.Itoa(count)}, "page": {"1"}} - err := c.Get(result, "blocks", query) +const tokensLimit = "1000" + +func (c *Client) fetchNodeInfo() (*NodeInfo, error) { + result := new(NodeInfo) + err := c.Get(result, "v1/node-info", nil) return result, err } -func (c *Client) GetBlockByNumber(num int64) (*TxPage, error) { - stx := new(TxPage) - query := url.Values{ - "blockHeight": {strconv.FormatInt(num, 10)}, - // Only first 100 transactions of block returned - // Shouldn't be a problem at the current transaction rate - "rows": {"100"}, - "page": {"1"}, - } - err := c.Get(stx, "txs", query) - return stx, err +func (c *Client) fetchBlockTransactions(num int64) ([]TxV2, error) { + stx := new(BlockTransactions) + err := c.Get(stx, fmt.Sprintf("v2/transactions-in-block/%d", num), nil) + return stx.Txs, err +} + +func (c *Client) fetchAccountMetadata(address string) (*Account, error) { + var result Account + err := c.Get(&result, fmt.Sprintf("v1/account/%s", address), nil) + return &result, err } -func (c *Client) GetTxsOfAddress(address string, token string) (*TxPage, error) { - stx := new(TxPage) - query := url.Values{"address": {address}, "rows": {"20"}, "page": {"1"}, "txAsset": {token}, "txType": {"TRANSFER"}} - err := c.Get(stx, "txs", query) - return stx, err +func (c *Client) fetchTokens() (*TokenList, error) { + stp := new(TokenList) + query := url.Values{"limit": {tokensLimit}} + err := c.GetWithCache(stp, "v1/tokens", query, time.Minute*1) + return stp, err } -func (c *Client) GetTx(hash string) (stx Tx, err error) { - err = c.Get(&stx, "tx", url.Values{"txHash": {hash}}) - return +func (c *Client) fetchTransactionHash(hash string) (*TxHashRPC, error) { + var result TxHashRPC + err := c.Get(&result, fmt.Sprintf("v1/tx/%s", hash), url.Values{"format": {"json"}}) + return &result, err } -func getHTTPError(res *http.Response, desc string) error { +func handleHTTPError(res *http.Response, desc string) error { switch res.StatusCode { case http.StatusBadRequest: - return getAPIError(res, desc) + return handleAPIError(res, desc) case http.StatusNotFound: return blockatlas.ErrNotFound case http.StatusOK: return nil default: - return errors.E("getHTTPError error", errors.Params{"status": res.Status}) + return errors.E("handleHTTPError error", errors.Params{"status": res.Status}) } } -func getAPIError(res *http.Response, desc string) error { - var sErr Error - err := json.NewDecoder(res.Body).Decode(&sErr) - if err != nil { - err = errors.E(err, errors.TypePlatformUnmarshal, errors.Params{"desc": desc}) - logger.Error(err, "Binance: Failed to decode error response") - return blockatlas.ErrSourceConn - } - - switch sErr.Message { - case "address is not valid": +func handleAPIError(res *http.Response, desc string) error { + var e Error + if json.NewDecoder(res.Body).Decode(&e) == nil && e.Message == "address is not valid" { return blockatlas.ErrInvalidAddr } - - logger.Error("Binance: Failed", desc, err, logger.Params{ - "status": res.StatusCode, - "code": sErr.Code, - "message": sErr.Message, - }) + logger.Error(desc, logger.Params{"status": res.StatusCode, "code": e.Code, "message": e.Message}) return blockatlas.ErrSourceConn } diff --git a/platform/binance/dex_client.go b/platform/binance/dex_client.go deleted file mode 100644 index 094fcdeac..000000000 --- a/platform/binance/dex_client.go +++ /dev/null @@ -1,27 +0,0 @@ -package binance - -import ( - "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "net/url" - "time" -) - -// TODO Headers + rate limiting - -type DexClient struct { - blockatlas.Request -} - -func (c *DexClient) GetAccountMetadata(address string) (account *Account, err error) { - path := fmt.Sprintf("v1/account/%s", address) - err = c.Get(&account, path, nil) - return account, err -} - -func (c *DexClient) GetTokens() (*TokenPage, error) { - stp := new(TokenPage) - query := url.Values{"limit": {"1000"}, "offset": {"0"}} - err := c.GetWithCache(stp, "v1/tokens", query, time.Hour*1) - return stp, err -} diff --git a/platform/binance/explorer_client.go b/platform/binance/explorer_client.go new file mode 100644 index 000000000..1c9bce492 --- /dev/null +++ b/platform/binance/explorer_client.go @@ -0,0 +1,32 @@ +package binance + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "net/url" +) + +type ExplorerClient struct { + blockatlas.Request +} + +const ( + explorerRows = "25" + explorerPage = "1" +) + +func (c *ExplorerClient) getTxsOfAddress(address, token string) (ExplorerResponse, error) { + result := new(ExplorerResponse) + if token == "" { + token = coin.Binance().Symbol + } + query := url.Values{ + "address": {address}, + "rows": {explorerRows}, + "page": {explorerPage}, + "txType": {string(TxTransfer)}, + "txAsset": {token}, + } + err := c.Get(result, "v1/txs", query) + return *result, err +} diff --git a/platform/binance/model.go b/platform/binance/model.go index 8523d0968..e41446bb2 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -1,229 +1,247 @@ package binance import ( - "encoding/json" "fmt" "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" - "math" "strconv" - "strings" ) -type Account struct { - AccountNumber int `json:"account_number"` - Address string `json:"address"` - Balances []Balance `json:"balances"` - PublicKey []byte `json:"public_key"` - Sequence uint64 `json:"sequence"` -} +const ( + TxTransfer TxType = "TRANSFER" // e.g: BNB, TWT-8C2 + SingleTransferOperation ExplorerTransactionType = "singleTransfer" // e.g: BNB, TWT-8C2 + MultiTransferOperation ExplorerTransactionType = "multiTransfer" // e.g [BNB, BNB], [TWT-8C2, TWT-8C2] +) -type Balance struct { - Free string `json:"free"` - Frozen string `json:"frozen"` - Locked string `json:"locked"` - Symbol string `json:"symbol"` -} +type ( + TxType string + ExplorerTransactionType string -type Error struct { - Code int64 `json:"code"` - Message string `json:"message"` -} + Account struct { + AccountNumber int `json:"account_number"` + Address string `json:"address"` + Balances []Balance `json:"balances"` + PublicKey []byte `json:"public_key"` + Sequence uint64 `json:"sequence"` + } -type BlockDescriptor struct { - BlockHeight int64 `json:"blockHeight"` - BlockHash string `json:"blockHash"` - TxNum int `json:"txNum"` -} + Balance struct { + Free string `json:"free"` + Frozen string `json:"frozen"` + Locked string `json:"locked"` + Symbol string `json:"symbol"` + } -type BlockList struct { - BlockArray []BlockDescriptor `json:"blockArray"` -} + Error struct { + Code int64 `json:"code"` + Message string `json:"message"` + } -type TxType string + NodeInfo struct { + SyncInfo SyncInfo `json:"sync_info"` + } -const ( - TxTransfer TxType = "TRANSFER" - TxNewOrder TxType = "NEW_ORDER" - TxCancelOrder TxType = "CANCEL_ORDER" -) + SyncInfo struct { + LatestBlockHeight int64 `json:"latest_block_height"` + } -type Tx struct { - BlockHeight uint64 `json:"blockHeight"` - Type TxType `json:"txType"` - Code int `json:"code"` - ConfirmBlocks int `json:"confirmBlocks"` - Data string `json:"data"` - FromAddr string `json:"fromAddr"` - OrderID string `json:"orderId"` - Timestamp int64 `json:"timeStamp"` - ToAddr string `json:"toAddr"` - Age int64 `json:"txAge"` - Asset string `json:"txAsset"` - Fee json.Number `json:"txFee"` - Hash string `json:"txHash"` - Value json.Number `json:"value"` - Memo string `json:"memo"` - HasChildren int `json:"hasChildren"` - SubTxsDto SubTxsDto `json:"subTxsDto"` -} + Transactions struct { + Total int `json:"total"` + Txs []Tx `json:"tx"` + } -type SubTxsDto struct { - TotalNum uint `json:"totalNum"` - SubTxDtoList SubTxs `json:"subTxDtoList"` -} + Tx struct { + Asset string `json:"txAsset"` + BlockHeight uint64 `json:"blockHeight"` + Code int `json:"code"` + Data string `json:"data"` + Fee string `json:"txFee"` + FromAddr string `json:"fromAddr"` + Memo string `json:"memo"` + OrderID string `json:"orderId"` + Sequence uint64 `json:"sequence"` + Source int `json:"source"` + Timestamp string `json:"timeStamp"` + ToAddr string `json:"toAddr"` + TxHash string `json:"txHash"` + Type TxType `json:"txType"` + Value string `json:"value"` + } -type SubTx struct { - Hash string `json:"hash"` - Height uint64 `json:"height"` - Type TxType `json:"type"` - Value json.Number `json:"value"` - Asset string `json:"asset"` - FromAddr string `json:"fromAddr"` - ToAddr string `json:"toAddr"` - Fee json.Number `json:"fee"` -} + BlockTransactions struct { + BlockHeight int64 `json:"blockHeight"` + Txs []TxV2 `json:"tx"` + } -type SubTxs []SubTx + TxV2 struct { + Tx + OrderID string `json:"orderId"` // Optional. Available when the transaction type is NEW_ORDER + SubTransactions []SubTx `json:"subTransactions"` // Optional. Available when the transaction has sub-transactions, such as multi-send transaction or a transaction have multiple assets + } -func (subTxs *SubTxs) getTxs() (txs []Tx) { - mapTx := map[string]Tx{} - for _, subTx := range *subTxs { - key := subTx.ToAddr + subTx.Asset - tx, ok := mapTx[key] - if !ok { - mapTx[key] = subTx.toTx() - continue - } - txValue, err := tx.Value.Float64() - if err != nil { - txValue = 0 - } - subTxValue, err := subTx.Value.Float64() - if err != nil { - subTxValue = 0 - } - value := numbers.Float64toString(txValue + subTxValue) - tx.Value = json.Number(value) - mapTx[key] = tx + SubTx struct { + Asset string `json:"txAsset"` + Height uint64 `json:"blockHeight"` + Fee string `json:"txFee"` + FromAddr string `json:"fromAddr"` + Hash string `json:"txHash"` + ToAddr string `json:"toAddr"` + Type TxType `json:"txType"` + Value string `json:"value"` } - for _, tx := range mapTx { - txs = append(txs, tx) + + TokenList []Token + + Token struct { + Name string `json:"name"` + OriginalSymbol string `json:"original_symbol"` + Owner string `json:"owner"` + Symbol string `json:"symbol"` + TotalSupply string `json:"total_supply"` } - return -} -func (subTx *SubTx) toTx() Tx { - return Tx{ - Hash: subTx.Hash, - BlockHeight: subTx.Height, - Type: TxTransfer, - FromAddr: subTx.FromAddr, - ToAddr: subTx.ToAddr, - Asset: subTx.Asset, - Fee: subTx.Fee, - Value: subTx.Value, - HasChildren: 0, + // Transaction response from Explorer + ExplorerResponse struct { + Nums int `json:"txNums"` + Txs []ExplorerTxs `json:"txArray"` } -} -func (tx *Tx) containAddress(address string) bool { - if len(address) == 0 { - return true + ExplorerTxs struct { + BlockHeight uint64 `json:"blockHeight"` + Code int `json:"code"` + FromAddr string `json:"fromAddr"` + HasChildren int `json:"hasChildren"` + Memo string `json:"memo"` + MultisendTransfers []MultiTransfer `json:"subTxsDto"` // Not part of response, added from hash info tx for simplifying logic + Timestamp int64 `json:"timeStamp"` + ToAddr string `json:"toAddr"` + TxFee float64 `json:"txFee"` + TxHash string `json:"txHash"` + TxType TxType `json:"txType"` + Value float64 `json:"value"` + TxAsset string `json:"txAsset"` } - if tx.FromAddr == address { - return true + + TxHashRPC struct { + Hash string `json:"hash"` + Tx TxHashTx `json:"tx"` } - if tx.ToAddr == address { - return true + + TxHashTx struct { + Value Value `json:"value"` } - return false -} -func (tx *Tx) getFee() string { - fee := "0" - feeNumber, err := tx.Fee.Float64() - if err == nil && feeNumber > 0 { - fee = numbers.DecimalExp(string(tx.Fee), 8) + Value struct { + Msg []Msg `json:"msg"` } - return fee -} -func (tx *Tx) getData() (Data, error) { - rawIn := json.RawMessage(tx.Data) - b, err := rawIn.MarshalJSON() - if err != nil { - return Data{}, errors.E(err, "getData MarshalJSON", errors.Params{"data": tx.Data}) + Msg struct { + Value MsgValue `json:"value"` } - var data Data - err = json.Unmarshal(b, &data) - if err != nil { - return Data{}, errors.E(err, "getData Unmarshal", errors.Params{"data": string(b)}) + MsgValue struct { + Inputs []Input `json:"inputs"` + Outputs []Output `json:"outputs"` } - symbols := strings.Split(data.OrderData.Symbol, "_") - if len(symbols) < 2 { - return data, nil + Input struct { + Address string `json:"address"` } - data.OrderData.Base = symbols[0] - data.OrderData.Quote = symbols[1] - return data, nil -} + Output struct { + Address string `json:"address"` + Coins []struct { + Amount string `json:"amount"` + Denom string `json:"denom"` + } `json:"coins"` + } -type Data struct { - OrderData OrderData `json:"orderData"` -} + MultiTransfer struct { + Amount string `json:"amount"` // Float string ind decimal point + Asset string `json:"asset"` + From string `json:"from"` + To string `json:"to"` + } +) -type OrderData struct { - Symbol string `json:"symbol"` - Base string `json:"-"` - Quote string `json:"-"` - Quantity interface{} `json:"quantity"` - Price interface{} `json:"price"` +func extractMultiTransfers(messages Value) (extracted []MultiTransfer) { + for _, msg := range messages.Msg { + var tr MultiTransfer + tr.From = msg.Value.Inputs[0].Address // Assumed multisend transfer has one input, never seen multiple + for _, output := range msg.Value.Outputs { + tr.Amount = output.Coins[0].Amount + tr.Asset = output.Coins[0].Denom + tr.To = output.Address + + extracted = append(extracted, tr) + } + } + return } -func (od OrderData) GetVolume() (int64, bool) { - price, ok := od.GetPrice() - if !ok { - return 0, false +// Get explorer transfer fee converted to decimal expression +func (tx *Tx) getFee() string { + if _, err := strconv.ParseFloat(tx.Fee, 64); err == nil { + return numbers.DecimalExp(tx.Fee, int(coin.Binance().Decimals)) } - quantity, ok := od.GetQuantity() - if !ok { - return 0, false + return "0" +} + +// Converts explorer transfer fee to amount in decimal expression +func (tx *ExplorerTxs) getDexFee() blockatlas.Amount { + if tx.TxFee > 0 { + return blockatlas.Amount(numbers.DecimalExp(numbers.Float64toString(tx.TxFee), int(coin.Binance().Decimals))) + } else { + return blockatlas.Amount(0) } - return removeFloatPoint(price * quantity), true } -func (od OrderData) GetPrice() (float64, bool) { - return convertValue(od.Price) +// Get Explorer transfer status based on transfer code +func (tx *ExplorerTxs) getStatus() blockatlas.Status { + switch tx.Code { + case 0: + return blockatlas.StatusCompleted + default: + return blockatlas.StatusError + } } -func (od OrderData) GetQuantity() (float64, bool) { - return convertValue(od.Quantity) +func (tx *ExplorerTxs) getDexValue() blockatlas.Amount { + val := numbers.DecimalExp(numbers.Float64toString(tx.Value), int(coin.Binance().Decimals)) + return blockatlas.Amount(val) } -type TxPage struct { - Nums int `json:"txNums"` - Txs []Tx `json:"txArray"` +// Determines transaction status +func (tx *Tx) getStatus() blockatlas.Status { + switch tx.Code { + case 0: + return blockatlas.StatusCompleted + default: + return blockatlas.StatusError + } } -type Token struct { - Mintable bool `json:"mintable"` - Name string `json:"name"` - OriginalSymbol string `json:"original_symbol"` - Owner string `json:"owner"` - Symbol string `json:"symbol"` - TotalSupply string `json:"total_supply"` +// Get explorer transfer error message if transaction failed +func (tx *ExplorerTxs) getError() string { + switch tx.getStatus() { + case blockatlas.StatusCompleted: + return "" + default: + return "error" + } } -type TokenPage []Token +func (tx *Tx) containAddress(address string) bool { + if len(address) == 0 || tx.FromAddr == address || tx.ToAddr == address { + return true + } + return false +} // findToken find a token into a token list -func (a TokenPage) findToken(symbol string) *Token { - for _, t := range a { +func (page TokenList) findToken(symbol string) *Token { + for _, t := range page { if t.Symbol == symbol { return &t } @@ -240,33 +258,35 @@ func (balance *Balance) isAllZeroBalance() bool { } } return true - } func (e *Error) Error() string { return fmt.Sprintf("%d: %s", e.Code, e.Message) } -func removeFloatPoint(value float64) int64 { - bnbCoin := coin.Coins[coin.BNB] - pow := math.Pow(10, float64(bnbCoin.Decimals)) - return int64(value * pow) +// Determines Explorer transaction direction relatively to address +func (tx *ExplorerTxs) getDirection(address string) blockatlas.Direction { + if address == "" { + return "" + } + + if tx.FromAddr == address && tx.ToAddr == address { + return blockatlas.DirectionSelf + } + if tx.FromAddr == address && tx.ToAddr != address { + return blockatlas.DirectionOutgoing + } + + return blockatlas.DirectionIncoming } -func convertValue(value interface{}) (float64, bool) { - result := 0.0 - switch v := value.(type) { - case float64: - result = v - case int: - result = float64(v) - case string: - f, err := strconv.ParseFloat(v, 64) - if err == nil { - result = f - } - default: - return result, false +// Determines Explorer transaction type +func (tx *ExplorerTxs) getTransactionType() ExplorerTransactionType { + var txType ExplorerTransactionType + if tx.HasChildren == 1 { + txType = MultiTransferOperation + } else { + txType = SingleTransferOperation } - return result, true + return txType } diff --git a/platform/binance/model_test.go b/platform/binance/model_test.go index fabaa16a5..24df6b4f0 100644 --- a/platform/binance/model_test.go +++ b/platform/binance/model_test.go @@ -1,353 +1,205 @@ package binance import ( - "encoding/json" "github.com/stretchr/testify/assert" - "sort" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "strconv" "testing" - "time" ) -var newOrderDataDst = Data{OrderData: OrderData{ - Symbol: "AWC-986_BNB", - Base: "AWC-986", - Quote: "BNB", - Quantity: 2.0, - Price: 0.00324939, -}} - -var cancelOrderDataDst = Data{OrderData: OrderData{ - Symbol: "GTO-908_BNB", - Base: "GTO-908", - Quote: "BNB", - Quantity: 1.0, - Price: 0.00104716, -}} - -func TestTx_getData(t *testing.T) { - tests := []struct { - name string - Data string - want Data - }{ - { - "new order", - "{\"orderData\":{\"symbol\":\"AWC-986_BNB\",\"orderType\":\"limit\",\"side\":\"buy\",\"price\":0.00324939,\"quantity\":2.00000000,\"timeInForce\":\"GTE\",\"orderId\":\"D13BAF4BD6638FA3AAD6EBCA0E4BEEA73DF4D519-30\"}}", - newOrderDataDst, - }, - { - "cancel order", - "{\"orderData\":{\"symbol\":\"GTO-908_BNB\",\"orderType\":\"limit\",\"side\":\"buy\",\"price\":0.00104716,\"quantity\":1.00000000,\"timeInForce\":\"GTE\",\"orderId\":\"D13BAF4BD6638FA3AAD6EBCA0E4BEEA73DF4D519-28\"}}", - cancelOrderDataDst, - }, +func Test_isZeroBalance(t *testing.T) { + type testZeroStruct struct { + name string + balance Balance + want bool + } + // all combinations of 3 variables with 2 possible value 0 or 1 is 2^3 = 8 + tests := []testZeroStruct{ + {"1", Balance{"0.00000000", "0.00000000", "0.00000000", "BNB"}, true}, + {"2", Balance{"0.00000000", "0", "0.00000001", "BNB"}, false}, + {"3", Balance{"0.00000000", "0.00000001", "0.00000000", "BNB"}, false}, + {"4", Balance{"0.00000000", "0.00000001", "0.00000001", "BNB"}, false}, + {"5", Balance{"0.00000001", "0.00000000", "0.00000000", "BNB"}, false}, + {"6", Balance{"0.00000001", "0.00000000", "0.00000001", "BNB"}, false}, + {"7", Balance{"0.00000001", "0.00000001", "0.00000000", "BNB"}, false}, + {"8", Balance{"0.00000001", "0.00000001", "0.00000001", "BNB"}, false}, + {"Negative", Balance{"-0.00000001", "0.00000001", "0.00000001", "BNB"}, false}, + {"Bad others are 0", Balance{"f", "0.0000000", "0.0000000", "BNB"}, false}, + {"Bad others are not 0", Balance{"f", "0.0000001", "0.0000000", "BNB"}, false}, + {"Empty others are not 0", Balance{"", "0.00000001", "0.00000001", "BNB"}, false}, + {"Empty others are 0", Balance{"", "0.00000000", "0.00000000", "BNB"}, false}, + {"Big", Balance{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "0.00000000", "0.00000000", "BNB"}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tx := &Tx{Data: tt.Data} - got, _ := tx.getData() - assert.Equal(t, tt.want, got) + if got := tt.balance.isAllZeroBalance(); got != tt.want { + t.Errorf("isAllZeroBalance() = %v, want %v, name %v", got, tt.want, tt.name) + } }) } } -func TestConvertValue(t *testing.T) { +// + +func TestTx_containAddress(t *testing.T) { + type fields struct { + FromAddr string + ToAddr string + } tests := []struct { - name string - value interface{} - wantResult float64 - wantError bool + name string + fields fields + address string + want bool }{ - {"test string 1", "9", 9, false}, - {"test number 1", 9, 9, false}, - {"test string 2", "9380938973", 9380938973, false}, - {"test number 2", 9380938973, 9380938973, false}, - {"test string 3", "0.0000003", 0.0000003, false}, - {"test number 3", 0.0000003, 0.0000003, false}, - {"test string 4", "0.44", 0.44, false}, - {"test number 4", 0.44, 0.44, false}, - {"test string 5", "3334", 3334, false}, - {"test number 5", 3334, 3334, false}, - {"test error", time.Time{}, 3334, true}, + {"test from address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", true}, + {"test to address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", true}, + {"test no address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "tbnb1qxm48ndhmh7su0r7zgwmwkltuqgly57jdf8yf8", false}, + {"test empty address", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "", true}, + {"test empty address without from", fields{FromAddr: "", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "", true}, + {"test empty address without to", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: ""}, "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, ok := convertValue(tt.value) - if tt.wantError { - assert.False(t, ok) - return + tx := &Tx{ + FromAddr: tt.fields.FromAddr, + ToAddr: tt.fields.ToAddr, + } + if got := tx.containAddress(tt.address); got != tt.want { + t.Errorf("containAddress() = %v, want %v", got, tt.want) } - assert.True(t, ok) - assert.Equal(t, tt.wantResult, got) }) } } -func Test_removeFloatPoint(t *testing.T) { +func Test_getFee(t *testing.T) { tests := []struct { - name string - value float64 - want int64 + name string + fee string + want string }{ - {"test float 1", 0.0034, 340000}, - {"test float 2", 0.00000013, 13}, - {"test float 3", 0.938984, 93898400}, - {"test float 4", 0.1, 10000000}, - {"test int 1", 12, 1200000000}, - {"test int 2", 2333333333, 233333333300000000}, + {"test empty", "", "0"}, + {"test error", "test", "0"}, + {"test float 1", "444.5", "44450000000"}, + {"test float 2", "0.00000001", "1"}, + {"test float 3", "0.00037500", "37500"}, // standard transfer fee + {"test int", "3", "300000000"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := removeFloatPoint(tt.value); got != tt.want { - t.Errorf("removeFloatPoint() = %v, want %v", got, tt.want) + tx := &Tx{Fee: tt.fee} + if got := tx.getFee(); got != tt.want { + t.Errorf("getFee() = %v, want %v", got, tt.want) } }) } } -func Test_isZeroBalance(t *testing.T) { - type testZeroStruct struct { - name string - balance Balance - want bool - } - // all combinations of 3 variables with 2 possible value 0 or 1 is 2^3 = 8 - tests := []testZeroStruct{ - {"1", - Balance{"0.00000000", "0.00000000", "0.00000000", "BNB"}, - true, - }, - {"2", - Balance{"0.00000000", "0", "0.00000001", "BNB"}, - false, - }, - {"3", - Balance{"0.00000000", "0.00000001", "0.00000000", "BNB"}, - false, - }, - {"4", - Balance{"0.00000000", "0.00000001", "0.00000001", "BNB"}, - false, - }, - {"5", - Balance{"0.00000001", "0.00000000", "0.00000000", "BNB"}, - false, - }, - {"6", - Balance{"0.00000001", "0.00000000", "0.00000001", "BNB"}, - false, - }, - {"7", - Balance{"0.00000001", "0.00000001", "0.00000000", "BNB"}, - false, - }, - {"8", - Balance{"0.00000001", "0.00000001", "0.00000001", "BNB"}, - false, - }, - {"Negative", - Balance{"-0.00000001", "0.00000001", "0.00000001", "BNB"}, - false, - }, - {"Bad others are 0", - Balance{"f", - "0.0000000", "0.0000000", "BNB"}, - false, - }, - {"Bad others are not 0", - Balance{"f", - "0.0000001", "0.0000000", "BNB"}, - false, - }, - {"Empty others are not 0", - Balance{"", - "0.00000001", "0.00000001", "BNB"}, - false, - }, - {"Empty others are 0", - Balance{"", - "0.00000000", "0.00000000", "BNB"}, - false, - }, - {"Big", - Balance{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", - "0.00000000", "0.00000000", "BNB"}, - false, - }, +func Test_getStatus(t *testing.T) { + tests := []struct { + name string + trx Tx + expect blockatlas.Status + }{ + {"Should have status completed", Tx{Code: 0}, blockatlas.StatusCompleted}, + {"Should have status error", Tx{Code: 1}, blockatlas.StatusError}, + {"Should have status error", Tx{Code: -1}, blockatlas.StatusError}, } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.balance.isAllZeroBalance(); got != tt.want { - t.Errorf("isAllZeroBalance() = %v, want %v, name %v", got, tt.want, tt.name) - } + t.Run("", func(t *testing.T) { + assert.Equal(t, tt.trx.getStatus(), tt.expect) }) } } -var ( - subTxDst = SubTx{ - Hash: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", - Height: 63591484, - Type: "TRANSFER", - Value: "0.00000001", - Asset: "BNB", - FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - Fee: "0.0006", - } - subTxTokenDst = SubTx{ - Hash: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", - Height: 63591485, - Type: "TRANSFER", - Value: "0.000064", - Asset: "AERGO-46B", - FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - Fee: "0.0006", - } - txDst = Tx{ - Hash: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", - BlockHeight: 63591484, - Type: "TRANSFER", - Value: "0.00000001", - Asset: "BNB", - FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - Fee: "0.0006", - } - txTokenDst = Tx{ - Hash: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", - BlockHeight: 63591485, - Type: "TRANSFER", - Value: "0.000064", - Asset: "AERGO-46B", - FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - Fee: "0.0006", - } -) - -func TestSubTx_toTx(t *testing.T) { +func Test_getError(t *testing.T) { tests := []struct { - name string - subTx SubTx - want Tx + name string + trx ExplorerTxs + expect string }{ - {"test conversion subTx to Tx", subTxTokenDst, - Tx{ - Hash: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", - BlockHeight: 63591485, - Type: TxTransfer, - FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - Asset: "AERGO-46B", - Fee: "0.0006", - Value: "0.000064", - SubTxsDto: SubTxsDto{}, - }, - }, + {"Should not have error message", ExplorerTxs{Code: 0}, ""}, + {"Should have error message", ExplorerTxs{Code: 1}, "error"}, + {"Should have error message", ExplorerTxs{Code: -1}, "error"}, } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := tt.subTx.toTx() - assert.Equal(t, tt.want, got, "conversion failed") + t.Run("", func(t *testing.T) { + assert.Equal(t, tt.trx.getError(), tt.expect) }) } } -func TestSubTxs_getTxs(t *testing.T) { - txDuplicatedTokenDst := txTokenDst - txDuplicatedTokenDst.Value = "0.000128" - txDuplicatedDst := txDst - txDuplicatedDst.Value = "0.00000002" +func Test_QuantityTransferType(t *testing.T) { tests := []struct { - name string - subTxs SubTxs - wantTxs []Tx + name string + trx ExplorerTxs + expect ExplorerTransactionType }{ - {"test empty", SubTxs{}, nil}, - {"test subTx transfer", SubTxs{subTxDst}, []Tx{txDst}}, - {"test subTx token transfer", SubTxs{subTxTokenDst}, []Tx{txTokenDst}}, - {"test subTx and token transfer", SubTxs{subTxDst, subTxTokenDst}, []Tx{txDst, txTokenDst}}, - {"test duplicate subTx token transfer", SubTxs{subTxTokenDst, subTxTokenDst}, []Tx{txDuplicatedTokenDst}}, - {"test duplicate subTx", SubTxs{subTxDst, subTxDst}, []Tx{txDuplicatedDst}}, + {"Should be multi transfer", ExplorerTxs{HasChildren: 1}, MultiTransferOperation}, + {"Should be single transfer", ExplorerTxs{HasChildren: 0}, SingleTransferOperation}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotTxs := tt.subTxs.getTxs() - sort.Slice(gotTxs, func(i, j int) bool { - return gotTxs[i].BlockHeight < gotTxs[j].BlockHeight - }) - assert.Equal(t, tt.wantTxs, gotTxs, "get txs from subTxs failed") + assert.Equal(t, tt.trx.getTransactionType(), tt.expect) }) } } -func TestTx_containAddress(t *testing.T) { - type fields struct { - FromAddr string - ToAddr string - } +func TestExplorerTxs_getDirection(t *testing.T) { + const ( + addr1 = "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl" + addr2 = "bnb1mr5f97rx5wnkfcakx9fcpvljmx2s6kwqc08yur" + ) + tests := []struct { name string - fields fields address string - want bool + trx ExplorerTxs + expect blockatlas.Direction }{ - {"test from address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", true}, - {"test to address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", true}, - {"test no address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "tbnb1qxm48ndhmh7su0r7zgwmwkltuqgly57jdf8yf8", false}, - {"test empty address", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "", true}, - {"test empty address without from", fields{FromAddr: "", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "", true}, - {"test empty address without to", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: ""}, "", true}, + {"getDirection should be self send", addr1, ExplorerTxs{FromAddr: addr1, ToAddr: addr1}, blockatlas.DirectionSelf}, + {"getDirection should be incoming", addr1, ExplorerTxs{FromAddr: addr2, ToAddr: addr1}, blockatlas.DirectionIncoming}, + {"getDirection should be outgoing", addr1, ExplorerTxs{FromAddr: addr1, ToAddr: addr2}, blockatlas.DirectionOutgoing}, + {"getDirection should be empty", "", ExplorerTxs{FromAddr: addr1, ToAddr: addr2}, blockatlas.Direction("")}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tx := &Tx{ - FromAddr: tt.fields.FromAddr, - ToAddr: tt.fields.ToAddr, - } - if got := tx.containAddress(tt.address); got != tt.want { - t.Errorf("containAddress() = %v, want %v", got, tt.want) - } + assert.Equal(t, tt.trx.getDirection(tt.address), tt.expect) }) } } -func TestTx_getFee(t *testing.T) { +func Test_getDexFee(t *testing.T) { tests := []struct { - name string - fee json.Number - want string + name string + trx ExplorerTxs + expectFee blockatlas.Amount }{ - {"test empty", json.Number(""), "0"}, - {"test error", json.Number("test"), "0"}, - {"test float 1", json.Number("444.5"), "44450000000"}, - {"test float 2", json.Number("0.00000001"), "1"}, - {"test int", json.Number("3"), "300000000"}, + {"Should have zero fee", ExplorerTxs{TxFee: 0}, blockatlas.Amount(0)}, + {"Should have zero fee", ExplorerTxs{TxFee: 0.0}, blockatlas.Amount(0)}, + {"Should have standard fee", ExplorerTxs{TxFee: 0.00037500}, blockatlas.Amount(strconv.Itoa(37500))}, } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tx := &Tx{Fee: tt.fee} - if got := tx.getFee(); got != tt.want { - t.Errorf("getFee() = %v, want %v", got, tt.want) - } + t.Run("", func(t *testing.T) { + fee := tt.trx.getDexFee() + assert.Equal(t, fee, tt.expectFee) }) } } diff --git a/platform/binance/token.go b/platform/binance/token.go index 0e633340c..425d40fa2 100644 --- a/platform/binance/token.go +++ b/platform/binance/token.go @@ -7,50 +7,52 @@ import ( ) func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { - account, err := p.dexClient.GetAccountMetadata(address) + account, err := p.rpcClient.fetchAccountMetadata(address) if err != nil || len(account.Balances) == 0 { return []blockatlas.Token{}, nil } - tokens, err := p.dexClient.GetTokens() + tokens, err := p.rpcClient.fetchTokens() if err != nil { return nil, err } - return NormalizeTokens(account.Balances, tokens), nil + return normalizeTokens(account.Balances, tokens), nil } -// NormalizeToken converts a Binance token into the generic model -func NormalizeToken(srcToken *Balance, tokens *TokenPage) (t blockatlas.Token, ok bool) { +// NormalizeTxs converts multiple Binance tokens +func normalizeTokens(srcBalance []Balance, tokens *TokenList) []blockatlas.Token { + tokensList := make([]blockatlas.Token, 0, len(srcBalance)) + for _, srcToken := range srcBalance { + token, ok := normalizeToken(&srcToken, tokens) + if !ok { + continue + } + tokensList = append(tokensList, token) + } + return tokensList +} + +// normalizeToken converts a Binance token into the generic model +func normalizeToken(srcToken *Balance, tokens *TokenList) (blockatlas.Token, bool) { + var result blockatlas.Token if srcToken.isAllZeroBalance() { - return t, false + return result, false } - tk := tokens.findToken(srcToken.Symbol) - if tk == nil { - return t, false + token := tokens.findToken(srcToken.Symbol) + if token == nil { + return result, false } - t = blockatlas.Token{ - Name: tk.Name, - Symbol: tk.OriginalSymbol, - TokenID: tk.Symbol, + result = blockatlas.Token{ + Name: token.Name, + Symbol: token.OriginalSymbol, + TokenID: token.Symbol, Coin: coin.BNB, - Decimals: uint(decimalPlaces(tk.TotalSupply)), + Decimals: uint(decimalPlaces(token.TotalSupply)), Type: blockatlas.TokenTypeBEP2, } - return t, true -} - -// NormalizeTxs converts multiple Binance tokens -func NormalizeTokens(srcBalance []Balance, tokens *TokenPage) (tokenPage []blockatlas.Token) { - for _, srcToken := range srcBalance { - token, ok := NormalizeToken(&srcToken, tokens) - if !ok { - continue - } - tokenPage = append(tokenPage, token) - } - return + return result, true } // decimalPlaces count the decimals places. diff --git a/platform/binance/token_test.go b/platform/binance/token_test.go index 99106ac9d..33734c07e 100644 --- a/platform/binance/token_test.go +++ b/platform/binance/token_test.go @@ -120,11 +120,11 @@ func TestNormalizeToken(t *testing.T) { err := json.Unmarshal([]byte(testToken.apiResponse), &srcToken) assert.Nil(t, err) - var srcTokens TokenPage + var srcTokens TokenList err = json.Unmarshal([]byte(testToken.tokens), &srcTokens) assert.Nil(t, err) - tk, ok := NormalizeToken(&srcToken, &srcTokens) + tk, ok := normalizeToken(&srcToken, &srcTokens) assert.Equal(t, testToken.ok, ok, "token: token could not be normalized") assert.Equal(t, testToken.expected, tk, "token: token don't equal") }) diff --git a/platform/binance/transaction.go b/platform/binance/transaction.go index ba8ab2111..84581cbce 100644 --- a/platform/binance/transaction.go +++ b/platform/binance/transaction.go @@ -1,190 +1,200 @@ package binance import ( + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" + "strconv" "strings" "sync" - - "github.com/trustwallet/blockatlas/coin" ) +const emptyToken = "" + func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - // Endpoint supports queries without token query parameter - return p.GetTokenTxsByAddress(address, p.Coin().Symbol) + explorerResponse, err := p.GetTokenTxsByAddress(address, emptyToken) + if err != nil { + return nil, err + } + return filterTxsByType(explorerResponse, blockatlas.TxTransfer), nil } -func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { - srcTxs, err := p.client.GetTxsOfAddress(address, token) +func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { + explorerResponse, err := p.explorerClient.getTxsOfAddress(address, token) if err != nil { return nil, err } - txs, err := p.getTxChildChan(srcTxs.Txs) + + explorerTxs, err := p.addTxDetails(explorerResponse.Txs) if err != nil { return nil, err } - return NormalizeTxs(txs, token, address), nil + + return normalizeTxs(explorerTxs, address), nil } -// getTxChildChan get all child assets from a tx -func (p *Platform) getTxChildChan(srcTxs []Tx) ([]Tx, error) { - txs := make([]Tx, 0) - var wg sync.WaitGroup - out := make(chan Tx, len(srcTxs)) - for _, srcTx := range srcTxs { - if srcTx.HasChildren != 1 { - // Return the same transaction if doesn't have a child - txs = append(txs, srcTx) +func normalizeTxs(explorerTxs []ExplorerTxs, address string) []blockatlas.Tx { + var txs []blockatlas.Tx + for _, tx := range explorerTxs { + normalizedTxs := normalizeTx(tx, address) + if normalizedTxs == nil { continue } + txs = append(txs, normalizedTxs...) + } + return txs +} + +func filterTxsByType(txs []blockatlas.Tx, txType blockatlas.TransactionType) []blockatlas.Tx { + var result = make([]blockatlas.Tx, 0, len(txs)) + for _, tx := range txs { + if tx.Type == txType { + result = append(result, tx) + } + } + return result +} + +func normalizeTx(srcTx ExplorerTxs, address string) []blockatlas.Tx { + explorerTxType := srcTx.getTransactionType() + switch explorerTxType { + case SingleTransferOperation: + return normalizeSingleTransfer(srcTx, address) + case MultiTransferOperation: + return normalizeMultiTransfer(srcTx, address) + default: + return nil + } +} + +func normalizeSingleTransfer(srcTx ExplorerTxs, address string) blockatlas.TxPage { + if srcTx.TxType != TxTransfer { + return nil + } + tx := getBase(srcTx) + tx.Direction = srcTx.getDirection(address) + bnbCoin := coin.Coins[coin.BNB] + + if srcTx.TxAsset == bnbCoin.Symbol { + tx.Type = blockatlas.TxTransfer + tx.Meta = blockatlas.Transfer{ + Decimals: bnbCoin.Decimals, + Symbol: bnbCoin.Symbol, + Value: srcTx.getDexValue(), + } + return blockatlas.TxPage{tx} + } + + if srcTx.TxAsset != "" { + tx.Type = blockatlas.TxNativeTokenTransfer + tx.Meta = blockatlas.NativeTokenTransfer{ + Decimals: bnbCoin.Decimals, + From: srcTx.FromAddr, + Symbol: tokenSymbol(srcTx.TxAsset), + To: srcTx.ToAddr, + TokenID: srcTx.TxAsset, + Value: srcTx.getDexValue(), + } + return blockatlas.TxPage{tx} + } + return nil +} + +func normalizeMultiTransfer(srcTx ExplorerTxs, address string) []blockatlas.Tx { + var txs blockatlas.TxPage + for _, t := range srcTx.MultisendTransfers { + if t.From == address || t.To == address { + srcTx.FromAddr = t.From + srcTx.ToAddr = t.To + srcTx.TxAsset = t.Asset + + if value, err := strconv.ParseFloat(numbers.ToDecimal(t.Amount, 8), 64); err == nil { + srcTx.Value = value + } + + if single := normalizeSingleTransfer(srcTx, address); single != nil { + txs = append(txs, single...) + } + } + } + return txs +} + +func (p *Platform) addTxDetails(txs []ExplorerTxs) ([]ExplorerTxs, error) { + var ( + wg sync.WaitGroup + txsWithDetails = make([]ExplorerTxs, 0, len(txs)) + txHashChan = make(chan TxHashRPC, len(txs)) + multiSendTxsMap = make(map[string]ExplorerTxs, len(txs)) + ) + + for _, tx := range txs { + multiSendTxsMap[tx.TxHash] = tx + + if tx.HasChildren != 1 { + continue + } + wg.Add(1) - go func(srcTx Tx, out chan Tx, wg *sync.WaitGroup) { + + go func(srcTx ExplorerTxs, txHashChan chan TxHashRPC, wg *sync.WaitGroup) { defer wg.Done() - tx, err := p.client.GetTx(srcTx.Hash) + txHash, err := p.rpcClient.fetchTransactionHash(srcTx.TxHash) if err != nil { - // Return the same transaction if an error occurs - out <- srcTx - logger.Error("GetTransactionsByBlockChan", err, logger.Params{"hash": srcTx.Hash}) return } - out <- tx - }(srcTx, out, &wg) + txHashChan <- *txHash + }(tx, txHashChan, &wg) } + wg.Wait() - close(out) - for r := range out { - txs = append(txs, r) - } - return txs, nil -} + close(txHashChan) -func normalizeTransfer(tx blockatlas.Tx, srcTx Tx, token, address string) (blockatlas.TxPage, bool) { - // Verify if the tx has more them one asset - if srcTx.HasChildren == 1 { - txs := make(blockatlas.TxPage, 0) - // Parse all assets as a transaction - for _, subTx := range srcTx.SubTxsDto.SubTxDtoList.getTxs() { - // If this is not called from a block observer_test, only get the user txs/assets - if !subTx.containAddress(address) { - continue - } - // Recursive call to normalize the tx - newTxs, ok := normalizeTransfer(tx, subTx, token, address) + for res := range txHashChan { + if len(res.Tx.Value.Msg) > 0 { + a, ok := multiSendTxsMap[res.Hash] if !ok { continue } - txs = append(txs, newTxs...) - } - if len(txs) == 0 { - return txs, false + a.MultisendTransfers = extractMultiTransfers(res.Tx.Value) + multiSendTxsMap[res.Hash] = a } - return txs, true } - // Verify if this is the same asset we are looking for - if len(token) > 0 && srcTx.Asset != token { - return blockatlas.TxPage{tx}, false + for _, tx := range multiSendTxsMap { + txsWithDetails = append(txsWithDetails, tx) } - tx.From = srcTx.FromAddr - tx.To = srcTx.ToAddr + return txsWithDetails, nil +} - bnbCoin := coin.Coins[coin.BNB] - value := numbers.DecimalExp(string(srcTx.Value), 8) - if srcTx.Asset == bnbCoin.Symbol { - // Condition for native transfer (BNB) - tx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(value), - Symbol: bnbCoin.Symbol, - Decimals: bnbCoin.Decimals, - } - return blockatlas.TxPage{tx}, true +// Construct base Tx out of explorer transfer using common fields for all type of Blockatlas transfers +func getBase(srcTx ExplorerTxs) blockatlas.Tx { + base := blockatlas.Tx{ + ID: srcTx.TxHash, + Coin: coin.BNB, + From: srcTx.FromAddr, + Fee: srcTx.getDexFee(), + Date: srcTx.Timestamp / 1000, + Block: srcTx.BlockHeight, + Memo: srcTx.Memo, + To: srcTx.ToAddr, } - // Condition for native token transfer - tx.Meta = blockatlas.NativeTokenTransfer{ - TokenID: srcTx.Asset, - Symbol: TokenSymbol(srcTx.Asset), - Value: blockatlas.Amount(value), - Decimals: bnbCoin.Decimals, - From: srcTx.FromAddr, - To: srcTx.ToAddr, + status := srcTx.getStatus() + base.Status = status + if status == blockatlas.StatusError { + base.Error = srcTx.getError() } - return blockatlas.TxPage{tx}, true -} -// NormalizeTx converts a Binance transaction into the generic model -func NormalizeTx(srcTx Tx, token, address string) (blockatlas.TxPage, bool) { - tx := blockatlas.Tx{ - ID: srcTx.Hash, - Coin: coin.BNB, - From: srcTx.FromAddr, - To: srcTx.ToAddr, - Fee: blockatlas.Amount(srcTx.getFee()), - Date: srcTx.Timestamp / 1000, - Block: srcTx.BlockHeight, - Status: blockatlas.StatusCompleted, - Memo: srcTx.Memo, - } - - switch srcTx.Type { - case TxTransfer: - return normalizeTransfer(tx, srcTx, token, address) - } - //case TxCancelOrder, TxNewOrder: - // return tx, false - // dt, err := srcTx.getData() - // if err != nil { - // return tx, false - // } - // - // symbol := dt.OrderData.Quote - // if len(token) > 0 && symbol != token { - // return tx, false - // } - // - // key := blockatlas.KeyPlaceOrder - // title := blockatlas.KeyTitlePlaceOrder - // if srcTx.Type == TxCancelOrder { - // key = blockatlas.KeyCancelOrder - // title = blockatlas.KeyTitleCancelOrder - // } - // volume, ok := dt.OrderData.GetVolume() - // if ok { - // value = strconv.Itoa(int(volume)) - // } - // - // tx.Meta = blockatlas.AnyAction{ - // Coin: coin.BNB, - // TokenID: dt.OrderData.Symbol, - // Symbol: TokenSymbol(symbol), - // Name: symbol, - // Value: blockatlas.Amount(value), - // Decimals: coin.Coins[coin.BNB].Decimals, - // Title: title, - // Key: key, - // } - //} - return blockatlas.TxPage{tx}, false + return base } -func TokenSymbol(asset string) string { +// Extract BEP2 token symbol from asset name e.g: TWT-8C2 => TWT +func tokenSymbol(asset string) string { s := strings.Split(asset, "-") if len(s) > 1 { return s[0] } return asset } - -// NormalizeTxs converts multiple Binance transactions -func NormalizeTxs(srcTxs []Tx, token, adress string) (txs []blockatlas.Tx) { - for _, srcTx := range srcTxs { - tx, ok := NormalizeTx(srcTx, token, adress) - if !ok { - continue - } - txs = append(txs, tx...) - } - return -} diff --git a/platform/binance/transaction_test.go b/platform/binance/transaction_test.go index cbe80c777..eb4a8a394 100644 --- a/platform/binance/transaction_test.go +++ b/platform/binance/transaction_test.go @@ -3,550 +3,174 @@ package binance import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" ) const ( - transferTransaction = ` -{ - "blockHeight": 7761368, - "code": 0, - "confirmBlocks": 2089441, - "fromAddr": "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - "hasChildren": 0, - "log": "Msg 0: ", - "timeStamp": 1555049867552, - "toAddr": "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5", - "txAge": 836729, - "txAsset": "BNB", - "txFee": 0.00125, - "txHash": "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", - "txType": "TRANSFER", - "value": 100000, - "memo": "test" -}` - tokenTransferTransaction = ` -{ - "blockHeight": 7928667, - "code": 0, - "confirmBlocks": 1922024, - "fromAddr": "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - "hasChildren": 0, - "log": "Msg 0: ", - "timeStamp": 1555117625829, - "toAddr": "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - "txAge": 768924, - "txAsset": "YLC-D8B", - "txFee": 0.00125, - "txHash": "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - "txType": "TRANSFER", - "value": 2.10572645, - "memo": "test" -}` - newOrderTransaction = ` -{ - "txHash": "B0677F3436C1B1661E94D192B84B98AA42AC2485D9808357796EE501CBF794F7", - "blockHeight": 10815565, - "txType": "NEW_ORDER", - "timeStamp": 1559689901929, - "fromAddr": "bnb16ya67j7kvw8682kka09qujlw5u7lf4geqef0ku", - "value": 0.00649878, - "txAsset": "BNB", - "txQuoteAsset": "AWC-986", - "txFee": 0, - "txAge": 14346340, - "orderId": "D13BAF4BD6638FA3AAD6EBCA0E4BEEA73DF4D519-30", - "data": "{\"orderData\":{\"symbol\":\"BNB_AWC-986\",\"orderType\":\"limit\",\"side\":\"buy\",\"price\":0.00324939,\"quantity\":2.00000000,\"timeInForce\":\"GTE\",\"orderId\":\"D13BAF4BD6638FA3AAD6EBCA0E4BEEA73DF4D519-30\"}}", - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "", - "source": 0, - "hasChildren": 0 -}` - cancelOrderTransaction = ` -{ - "txHash": "F48DE755170C10F4A4C0E6836A708C33EEF9A7144800F25187D5F2349FD15A34", - "blockHeight": 10815539, - "txType": "CANCEL_ORDER", - "timeStamp": 1559689892180, - "fromAddr": "bnb16ya67j7kvw8682kka09qujlw5u7lf4geqef0ku", - "txFee": 0, - "txAge": 14346349, - "data": "{\"orderData\":{\"symbol\":\"BNB_GTO-908\",\"orderType\":\"limit\",\"side\":\"buy\",\"price\":0.00104716,\"quantity\":1.00000000,\"timeInForce\":\"GTE\",\"orderId\":\"D13BAF4BD6638FA3AAD6EBCA0E4BEEA73DF4D519-28\"}}", - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "", - "source": 0, - "hasChildren": 0 -}` - multipleTx = ` -{ - "txHash": "0C954A46D5AE90EBF9CB7E6F2EAC0E7C3E8DA2DA94B868962164A3AF9D54BEE8", - "blockHeight": 64374278, - "txType": "TRANSFER", - "timeStamp": 1580128370826, - "txFee": 0.0006, - "txAge": 222591, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 553829, - "memo": "", - "source": 0, - "sequence": 154231, - "hasChildren": 1, - "subTxsDto": { - "totalNum": 2, - "pageSize": 15, - "subTxDtoList": [ - { - "hash": "0C954A46D5AE90EBF9CB7E6F2EAC0E7C3E8DA2DA94B868962164A3AF9D54BEE8", - "height": 64374278, - "type": "TRANSFER", - "value": 3269, - "asset": "AERGO-46B", - "fromAddr": "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - "toAddr": "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - "fee": 0.0006 - }, - { - "hash": "0C954A46D5AE90EBF9CB7E6F2EAC0E7C3E8DA2DA94B868962164A3AF9D54BEE8", - "height": 64374278, - "type": "TRANSFER", - "value": 1, - "asset": "BNB", - "fromAddr": "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - "toAddr": "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - "fee": null - } - ] - } -}` - multipleTwiceTx = ` -{ - "txHash": "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", - "blockHeight": 63591484, - "txType": "TRANSFER", - "timeStamp": 1580421001269, - "txFee": 0.0006, - "txAge": 18773, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 38965, - "memo": "Trust Wallet Redeem", - "source": 0, - "sequence": 33, - "hasChildren": 1, - "subTxsDto": { - "totalNum": 2, - "pageSize": 15, - "subTxDtoList": [ - { - "hash": "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", - "height": 63591484, - "type": "TRANSFER", - "value": 1e-8, - "asset": "BNB", - "fromAddr": "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - "toAddr": "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - "fee": 0.0006 - }, - { - "hash": "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", - "height": 63591484, - "type": "TRANSFER", - "value": 1e-8, - "asset": "BNB", - "fromAddr": "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - "toAddr": "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - "fee": null - } - ] - } -}` + addr1 = "bnb13a7gyv5zl57c0rzeu0henx6d0tzspvrrakxxtv" + addr2 = "bnb1t6tnm2rckd3pfptngj6u8466v3ah4fcdu78n5y" +) + +const ( + bnbSingleExplorerTransferResponse = ` + { + "txHash": "73176E5BFA5856AEAB9BAB1F3030E6F2B2F274324052E84562BE9BE70E1AAEE7", + "blockHeight": 74821444, + "txType": "TRANSFER", + "timeStamp": 1588086370574, + "fromAddr": "bnb13a7gyv5zl57c0rzeu0henx6d0tzspvrrakxxtv", + "toAddr": "bnb1t6tnm2rckd3pfptngj6u8466v3ah4fcdu78n5y", + "value": 10.00000000, + "txAsset": "BNB", + "txFee": 0.00037500, + "txAge": 1868055, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 0, + "memo": "bnb-transfer", + "source": 1, + "hasChildren": 0 + }` + + bep2SingleExplorerTransferResponse = ` + { + "txHash": "73176E5BFA5856AEAB9BAB1F3030E6F2B2F274324052E84562BE9BE70E1AAEE7", + "blockHeight": 74821444, + "txType": "TRANSFER", + "timeStamp": 1588086357686, + "fromAddr": "bnb13a7gyv5zl57c0rzeu0henx6d0tzspvrrakxxtv", + "toAddr": "bnb1t6tnm2rckd3pfptngj6u8466v3ah4fcdu78n5y", + "value": 2800.00000000, + "txAsset": "TWT-8C2", + "txFee": 0.00037500, + "txAge": 276251, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 0, + "memo": "bep2-transfer", + "source": 0, + "hasChildren": 0 + }` + bep2MultipleExplorerTransferResponse = ` + { + "txHash": "73176E5BFA5856AEAB9BAB1F3030E6F2B2F274324052E84562BE9BE70E1AAEE7", + "blockHeight": 74821444, + "txType": "TRANSFER", + "timeStamp": 1588086357686, + "txFee": 0.00037500, + "txAge": 2068619, + "code": 0, + "log": "Msg 0: ", + "confirmBlocks": 0, + "memo": "bep2-transfer", + "source": 0, + "hasChildren": 1, + "subTxsDto": [ + { + "amount": "280000000000", + "asset": "TWT-8C2", + "from": "bnb13a7gyv5zl57c0rzeu0henx6d0tzspvrrakxxtv", + "to": "bnb1t6tnm2rckd3pfptngj6u8466v3ah4fcdu78n5y" + } + ] + }` ) var ( - transferDst = blockatlas.Tx{ - ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", - Coin: coin.BNB, - From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - To: "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5", - Fee: "125000", - Date: 1555049867, - Block: 7761368, - Status: blockatlas.StatusCompleted, - Memo: "test", + expectBnbSingleExplorerTransfer = blockatlas.Tx{ + ID: "73176E5BFA5856AEAB9BAB1F3030E6F2B2F274324052E84562BE9BE70E1AAEE7", + Coin: 714, + From: addr1, + To: addr2, + Fee: "37500", + Date: 1588086370, + Block: 74821444, + Status: blockatlas.StatusCompleted, + Error: "", + Sequence: 0, + Type: blockatlas.TxTransfer, + Direction: blockatlas.DirectionOutgoing, + Memo: "bnb-transfer", Meta: blockatlas.Transfer{ - Value: "10000000000000", - Decimals: 8, + Value: "1000000000", Symbol: "BNB", - }, - } - tokenTransferDst = blockatlas.Tx{ - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: blockatlas.NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", }, } - newOrderTransferDst = blockatlas.Tx{ - ID: "B0677F3436C1B1661E94D192B84B98AA42AC2485D9808357796EE501CBF794F7", - Coin: coin.BNB, - From: "bnb16ya67j7kvw8682kka09qujlw5u7lf4geqef0ku", - Fee: "0", - Date: 1559689901, - Block: 10815565, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.AnyAction{ - Coin: coin.BNB, - Title: blockatlas.KeyTitlePlaceOrder, - Key: blockatlas.KeyPlaceOrder, - TokenID: "BNB_AWC-986", - Name: "AWC-986", - Symbol: "AWC", - Value: "649878", - Decimals: 8, - }, - } - //TODO: temp test dst - metaFreeNewOrderTransferDst = blockatlas.Tx{ - ID: "B0677F3436C1B1661E94D192B84B98AA42AC2485D9808357796EE501CBF794F7", - Coin: coin.BNB, - From: "bnb16ya67j7kvw8682kka09qujlw5u7lf4geqef0ku", - Fee: "0", - Date: 1559689901, - Block: 10815565, - Status: blockatlas.StatusCompleted, - Meta: nil, - } - cancelOrdeTransferDst = blockatlas.Tx{ - ID: "F48DE755170C10F4A4C0E6836A708C33EEF9A7144800F25187D5F2349FD15A34", - Coin: coin.BNB, - From: "bnb16ya67j7kvw8682kka09qujlw5u7lf4geqef0ku", - Fee: "0", - Date: 1559689892, - Block: 10815539, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.AnyAction{ - Coin: coin.BNB, - Title: blockatlas.KeyTitleCancelOrder, - Key: blockatlas.KeyCancelOrder, - TokenID: "BNB_GTO-908", - Name: "GTO-908", - Symbol: "GTO", - Value: "104716", - Decimals: 8, - }, - } - multipleTxDst = blockatlas.Tx{ - ID: "0C954A46D5AE90EBF9CB7E6F2EAC0E7C3E8DA2DA94B868962164A3AF9D54BEE8", - Coin: coin.BNB, - From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - Fee: "60000", - Date: 1580128370, - Block: 64374278, - Status: blockatlas.StatusCompleted, + + expectBEP2SingleExplorerTransfer = blockatlas.Tx{ + ID: "73176E5BFA5856AEAB9BAB1F3030E6F2B2F274324052E84562BE9BE70E1AAEE7", + Coin: 714, + From: addr1, + To: addr2, + Fee: "37500", + Date: 1588086357, + Block: 74821444, + Status: blockatlas.StatusCompleted, + Error: "", + Sequence: 0, + Type: blockatlas.TxNativeTokenTransfer, + Direction: blockatlas.DirectionIncoming, + Memo: "bep2-transfer", Meta: blockatlas.NativeTokenTransfer{ - From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - TokenID: "AERGO-46B", - Symbol: "AERGO", - Value: "326900000000", - Decimals: 8, - }, - } - multipleTwiceTxDst = blockatlas.Tx{ - ID: "C29D822EFBC0C91656D1C5870BA55922F3A72A25BC8415B32D1D1AD0C85142F5", - Coin: coin.BNB, - From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - Fee: "60000", - Date: 1580421001, - Block: 63591484, - Status: blockatlas.StatusCompleted, - Memo: "Trust Wallet Redeem", - Meta: blockatlas.Transfer{ - Value: "2", - Decimals: 8, - Symbol: "BNB", - }, - } - //TODO: temp test dst - metaFreeCancelOrdeTransferDst = blockatlas.Tx{ - ID: "F48DE755170C10F4A4C0E6836A708C33EEF9A7144800F25187D5F2349FD15A34", - Coin: coin.BNB, - From: "bnb16ya67j7kvw8682kka09qujlw5u7lf4geqef0ku", - Fee: "0", - Date: 1559689892, - Block: 10815539, - Status: blockatlas.StatusCompleted, - Meta: nil, - } - baseTransferTx = blockatlas.Tx{ - ID: "0C954A46D5AE90EBF9CB7E6F2EAC0E7C3E8DA2DA94B868962164A3AF9D54BEE8", - Coin: coin.BNB, - From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - Fee: "60000", - Date: 1580128370, - Block: 63591484, - Status: blockatlas.StatusCompleted, - Memo: "Trust Wallet Redeem", - Meta: blockatlas.Transfer{ - Value: "2", Decimals: 8, - Symbol: "BNB", + From: addr1, + Name: "", + Symbol: "TWT", + To: addr2, + TokenID: "TWT-8C2", + Value: "280000000000", }, } ) -type testTx struct { - name string - apiResponse string - expected blockatlas.Tx - token string - wantError bool -} - -func TestNormalizeTx(t *testing.T) { - testTxList := []testTx{ - { - name: "bnb transfer", - apiResponse: transferTransaction, - expected: transferDst, - token: "BNB", - wantError: false, - }, - { - name: "native token transfer", - apiResponse: tokenTransferTransaction, - expected: tokenTransferDst, - token: "YLC-D8B", - wantError: false, - }, - { - name: "multiple addresses token transfer", - apiResponse: multipleTx, - expected: multipleTxDst, - token: "AERGO-46B", - wantError: false, - }, - { - name: "multiple addresses with two transfers", - apiResponse: multipleTwiceTx, - expected: multipleTwiceTxDst, - token: "BNB", - wantError: false, - }, - { - name: "new order transfer", - apiResponse: newOrderTransaction, - expected: newOrderTransferDst, - token: "AWC-986", - wantError: true, - }, - { - name: "cancel order transfer", - apiResponse: cancelOrderTransaction, - expected: cancelOrdeTransferDst, - token: "GTO-908", - wantError: true, - }, - { - name: "new order transfer", - apiResponse: newOrderTransaction, - expected: metaFreeNewOrderTransferDst, - token: "AWC-986", - wantError: true, - }, - { - name: "cancel order transfer", - apiResponse: cancelOrderTransaction, - expected: metaFreeCancelOrdeTransferDst, - token: "GTO-908", - wantError: true, - }, - { - name: "normalize error transfer", - apiResponse: tokenTransferTransaction, - token: "GTO-908", - wantError: true, - }, - } - - for _, testTxInstance := range testTxList { - t.Run(testTxInstance.name, func(t *testing.T) { - var srcTx Tx - err := json.Unmarshal([]byte(testTxInstance.apiResponse), &srcTx) - assert.Nil(t, err) - tx, ok := NormalizeTx(srcTx, testTxInstance.token, "") - if testTxInstance.wantError { - assert.False(t, ok, "transfer: tx could be normalized") - return - } - assert.True(t, ok, "transfer: tx could not be normalized") - assert.Equal(t, blockatlas.TxPage{testTxInstance.expected}, tx, "transfer: tx don't equal") - }) - } -} - -type testTxs struct { - name string - apiResponse string - expected []blockatlas.Tx - token string -} - -func convertJsonToArray(jsonString string) string { - return "[" + jsonString + "]" -} - func TestNormalizeTxs(t *testing.T) { - testTxsList := []testTxs{ - { - name: "bnb transfer", - apiResponse: convertJsonToArray(transferTransaction), - expected: []blockatlas.Tx{transferDst}, - token: "BNB", - }, - { - name: "native token transfer", - apiResponse: convertJsonToArray(tokenTransferTransaction), - expected: []blockatlas.Tx{tokenTransferDst}, - token: "YLC-D8B", - }, - //{ - // name: "all transfers", - // apiResponse: AllTransfersType, - // expected: []blockatlas.Tx{transferDst, tokenTransferDst, newOrderTransferDst, cancelOrdeTransferDst}, - // token: "", - //}, - //{ - // name: "new order transfer", - // apiResponse: convertJsonToArray(newOrderTransaction), - // expected: []blockatlas.Tx{newOrderTransferDst}, - // token: "AWC-986", - //}, - //{ - // name: "cancel order transfer", - // apiResponse: convertJsonToArray(cancelOrderTransaction), - // expected: []blockatlas.Tx{cancelOrdeTransferDst}, - // token: "GTO-908", - //} + type test struct { + name, address, dexTxResponse string + expected []blockatlas.Tx + } + tests := []test{ + {name: "BNB single transfer", dexTxResponse: bnbSingleExplorerTransferResponse, expected: []blockatlas.Tx{expectBnbSingleExplorerTransfer}, address: addr1}, + {name: "BEP2 single transfer", dexTxResponse: bep2SingleExplorerTransferResponse, expected: []blockatlas.Tx{expectBEP2SingleExplorerTransfer}, address: addr2}, + {name: "BEP2 multiple transfer", dexTxResponse: bep2MultipleExplorerTransferResponse, expected: []blockatlas.Tx{expectBEP2SingleExplorerTransfer}, address: addr2}, } - for _, testTxsInstance := range testTxsList { - t.Run(testTxsInstance.name, func(t *testing.T) { - var srcTxs []Tx - err := json.Unmarshal([]byte(testTxsInstance.apiResponse), &srcTxs) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx ExplorerTxs + err := json.Unmarshal([]byte(tt.dexTxResponse), &srcTx) assert.Nil(t, err) - txs := NormalizeTxs(srcTxs, testTxsInstance.token, "") - assert.Equal(t, testTxsInstance.expected, txs, "transfer: tx don't equal") + actual := normalizeTx(srcTx, tt.address) + assert.Equal(t, tt.expected, actual, "tx don't equal") }) } } func TestTokenSymbol(t *testing.T) { - assert.Equal(t, "UGAS", TokenSymbol("UGAS")) - assert.Equal(t, "UGAS", TokenSymbol("UGAS-B0C")) + assert.Equal(t, "UGAS", tokenSymbol("UGAS")) + assert.Equal(t, "UGAS", tokenSymbol("UGAS-B0C")) + assert.Equal(t, "cargabe", tokenSymbol("cargabe")) + assert.Equal(t, "CARBAGE", tokenSymbol("CARBAGE")) + assert.Equal(t, "", tokenSymbol("")) } -var ( - metaTx = blockatlas.Transfer{ - Value: "100000000", - Symbol: "BNB", - Decimals: 8, - } - metaTx2 = blockatlas.Transfer{ - Value: "2", - Symbol: "BNB", - Decimals: 8, - } - metaTokenTx = blockatlas.NativeTokenTransfer{ - Value: "326900000000", - TokenID: "AERGO-46B", - Symbol: "AERGO", - From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - Decimals: 8, - } -) - -func Test_normalizeTransfer(t *testing.T) { - testTx := baseTransferTx - testTx.Meta = metaTx - testTx2 := baseTransferTx - testTx2.Meta = metaTx2 - testTokenTx := baseTransferTx - testTokenTx.Meta = metaTokenTx - type args struct { - tx blockatlas.Tx - srcTx string - token string - address string - } +func Test_getBase(t *testing.T) { tests := []struct { - name string - args args - want blockatlas.TxPage - want1 bool + name string + srcTx ExplorerTxs + expectStatus blockatlas.Status + expectErrorMsg string }{ - {"test multiple tx 1", args{ - tx: baseTransferTx, - srcTx: multipleTx, - token: "BNB", - address: "", - }, blockatlas.TxPage{testTx}, true}, - {"test multiple tx 2", args{ - tx: baseTransferTx, - srcTx: multipleTwiceTx, - token: "BNB", - address: "", - }, blockatlas.TxPage{testTx2}, true}, - {"tx multiple token tx", args{ - tx: baseTransferTx, - srcTx: multipleTx, - token: "AERGO-46B", - address: "", - }, blockatlas.TxPage{testTokenTx}, true}, - {"test multiple tx fail", args{ - tx: baseTransferTx, - srcTx: multipleTwiceTx, - token: "AERGO-46B", - address: "", - }, blockatlas.TxPage{}, false}, - {"test multiple tx address fail", args{ - tx: baseTransferTx, - srcTx: multipleTwiceTx, - token: "AERGO-46B", - address: "tbnb1qxm48ndhmh7su0r7zgwmwkltuqgly57jdf8yf8", - }, blockatlas.TxPage{}, false}, + {"Should have status completed", ExplorerTxs{Code: 0}, blockatlas.StatusCompleted, ""}, + {"Should have status error and error message", ExplorerTxs{Code: 1}, blockatlas.StatusError, "error"}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var srcTx Tx - err := json.Unmarshal([]byte(tt.args.srcTx), &srcTx) - assert.Nil(t, err) - got, got1 := normalizeTransfer(tt.args.tx, srcTx, tt.args.token, tt.args.address) - assert.Equal(t, tt.want, got) - assert.Equal(t, tt.want1, got1) + base := getBase(tt.srcTx) + assert.Equal(t, base.Status, tt.expectStatus) + assert.Equal(t, base.Error, tt.expectErrorMsg) }) } } diff --git a/platform/platform.go b/platform/platform.go index 287eaa269..7790401a2 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -76,7 +76,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Aeternity().Handle: aeternity.Init(GetApiVar(coin.AE)), coin.Solana().Handle: solana.Init(GetApiVar(coin.SOL)), coin.Tezos().Handle: tezos.Init(GetApiVar(coin.XTZ), GetRpcVar(coin.XTZ)), - coin.Binance().Handle: binance.Init(GetApiVar(coin.BNB), GetVar("binance.dex")), + coin.Binance().Handle: binance.Init(GetApiVar(coin.BNB), GetVar("binance.explorer")), coin.Zilliqa().Handle: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL), GetVar("zilliqa.lookup")), coin.Kusama().Handle: polkadot.Init(coin.KSM, GetApiVar(coin.KSM)), coin.Stellar().Handle: stellar.Init(coin.XLM, GetApiVar(coin.XLM)), diff --git a/services/observer/parser/parser.go b/services/observer/parser/parser.go index 58195f013..634356512 100644 --- a/services/observer/parser/parser.go +++ b/services/observer/parser/parser.go @@ -290,7 +290,7 @@ func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumb return r, err } -func (t *transactionsBatch) fillBatch(transactions blockatlas.Txs) { +func (t *transactionsBatch) fillBatch(transactions []blockatlas.Tx) { t.Lock() defer t.Unlock() if len(transactions) == 0 { diff --git a/tests/postman/token_data.json b/tests/postman/token_data.json index da7a2870f..f53b1c75e 100644 --- a/tests/postman/token_data.json +++ b/tests/postman/token_data.json @@ -29,10 +29,10 @@ }, { "handler": "binance", - "address": "bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m" + "address": "bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q" }, { "handler": "classic", "address": "0xa12105efa0663147bddee178f6a741ac15676b79" } -] \ No newline at end of file +] diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index 35682bd2b..5cf4224b7 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -85,9 +85,9 @@ }, { "handler": "binance", - "address": "bnb1mnf0g6zhy2rpy63w8ryc6yp77s0fmqfyzjtkvd", + "address": "bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q", "expectedTxNum": 1, - "expectedTxId": "DDA939C475755B2A00123CDA37A5EC442F502EA2983014D04F647C3CB9FB57A0" + "expectedTxId": "4577CB3B5B202696E9E0B093A6DA973C7DD9CBC6808DA1326872745C35F3C089" }, { "handler": "tezos", From 5782d76ef53e720ac54faedcadb3ffbf1d252277 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 17 May 2020 00:41:05 +0300 Subject: [PATCH 297/506] Fix extract multi transfers + add test (#1103) --- platform/binance/model.go | 25 +++++++++++--------- platform/binance/model_test.go | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/platform/binance/model.go b/platform/binance/model.go index e41446bb2..1a350fd35 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -150,11 +150,12 @@ type ( } Output struct { - Address string `json:"address"` - Coins []struct { - Amount string `json:"amount"` - Denom string `json:"denom"` - } `json:"coins"` + Address string `json:"address"` + Coins []Coins `json:"coins"` + } + Coins struct { + Amount string `json:"amount"` + Denom string `json:"denom"` } MultiTransfer struct { @@ -165,19 +166,21 @@ type ( } ) -func extractMultiTransfers(messages Value) (extracted []MultiTransfer) { +func extractMultiTransfers(messages Value) []MultiTransfer { + var extracted = make([]MultiTransfer, 0) for _, msg := range messages.Msg { var tr MultiTransfer tr.From = msg.Value.Inputs[0].Address // Assumed multisend transfer has one input, never seen multiple for _, output := range msg.Value.Outputs { - tr.Amount = output.Coins[0].Amount - tr.Asset = output.Coins[0].Denom tr.To = output.Address - - extracted = append(extracted, tr) + for _, c := range output.Coins { + tr.Amount = c.Amount + tr.Asset = c.Denom + extracted = append(extracted, tr) + } } } - return + return extracted } // Get explorer transfer fee converted to decimal expression diff --git a/platform/binance/model_test.go b/platform/binance/model_test.go index 24df6b4f0..36b61f149 100644 --- a/platform/binance/model_test.go +++ b/platform/binance/model_test.go @@ -203,3 +203,46 @@ func Test_getDexFee(t *testing.T) { }) } } + +func Test_extractMultiTransfers(t *testing.T) { + multiAssetTransfer := Value{ + Msg: []Msg{ + { + MsgValue{ + Inputs: []Input{ + {Address: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8"}, + }, + Outputs: []Output{ + {Address: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", Coins: []Coins{ + {Amount: "3068900000000", Denom: "AERGO-46B"}, + {Amount: "4100000000", Denom: "BNB"}, + }, + }, + }, + }, + }, + }, + } + + wantedAssetMultiTransfers := []MultiTransfer{ + { + Amount: "3068900000000", + Asset: "AERGO-46B", + From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + }, + { + Amount: "4100000000", + Asset: "BNB", + From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", + To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", + }, + } + + res := extractMultiTransfers(multiAssetTransfer) + assert.NotNil(t, res) + + assert.Equal(t, 2, len(res)) + assert.Equal(t, res[0], wantedAssetMultiTransfers[0]) + assert.Equal(t, res[1], wantedAssetMultiTransfers[1]) +} From 7d52cc7afbb433979df5dab699a66fc49f44a9fc Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 17 May 2020 02:22:20 +0300 Subject: [PATCH 298/506] Now it is possible to setup multiple platforms in on service [specially for shitcoins] (#1101) * Now it is possible to setup multiple platforms in on service [specially for shitcoins] * Fixes for parser to have normal logs for multicoins --- cmd/observer_parser/main.go | 5 ++-- cmd/platform_api/main.go | 2 +- config.yml | 2 +- platform/registry.go | 34 +++++++++++++++---------- services/observer/parser/parser.go | 7 ++--- services/observer/parser/parser_test.go | 4 +-- 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/cmd/observer_parser/main.go b/cmd/observer_parser/main.go index 83e59f3d9..402e5d81f 100644 --- a/cmd/observer_parser/main.go +++ b/cmd/observer_parser/main.go @@ -38,10 +38,10 @@ func init() { mqHost := viper.GetString("observer.rabbitmq.uri") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") - platformHandle := viper.GetString("platform") + platformHandles := viper.GetStringSlice("platform") internal.InitRabbitMQ(mqHost, prefetchCount) - platform.Init(platformHandle) + platform.Init(platformHandles) if err := mq.RawTransactions.Declare(); err != nil { logger.Fatal(err) @@ -83,6 +83,7 @@ func main() { wg.Add(len(platform.BlockAPIs)) for _, api := range platform.BlockAPIs { + time.Sleep(time.Millisecond * 5) coin := api.Coin() pollInterval := notifier.GetInterval(coin.BlockTime, minInterval, maxInterval) diff --git a/cmd/platform_api/main.go b/cmd/platform_api/main.go index 5bc8bc28c..40c971d3c 100644 --- a/cmd/platform_api/main.go +++ b/cmd/platform_api/main.go @@ -28,7 +28,7 @@ func init() { engine = internal.InitEngine(viper.GetString("gin.mode")) - platform.Init(viper.GetString("platform")) + platform.Init(viper.GetStringSlice("platform")) } func main() { diff --git a/config.yml b/config.yml index 4b4ef8cdb..70cb67372 100644 --- a/config.yml +++ b/config.yml @@ -11,7 +11,7 @@ gin: # If all - run all platforms in one binary. You can pick specific coin handle to run binary only with specific coin # Example: ethereum # You can see all the coin handles at coins/coins.yml file -platform: all +platform: [ethereum, binance] # The transaction watcher observer: diff --git a/platform/registry.go b/platform/registry.go index b7bc91a20..9dc4280c7 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -27,25 +27,31 @@ var ( NamingAPIs map[uint]blockatlas.NamingServiceAPI ) -func getActivePlatforms(handle string) []blockatlas.Platform { - platforms := getAllHandlers() - logger.Info("Platform API setup with: ", logger.Params{"handle": handle}) - - if handle == allPlatformsHandle { - return platforms.GetPlatformList() +func getActivePlatforms(handles []string) []blockatlas.Platform { + if len(handles) == 0 { + logger.Fatal("Please, use ATLAS_PLATFORM handle with non-empty value, see more at Readme. Example: all", logger.Params{"ATLAS_PLATFORM": handles}) + return nil } - platform, ok := platforms[handle] - if ok { - return []blockatlas.Platform{platform} - } + allPlatforms := getAllHandlers() + logger.Info("Platform API setup with: ", logger.Params{"handles": handles}) + + platforms := make([]blockatlas.Platform, 0, len(handles)) - logger.Fatal("Please, use ATLAS_PLATFORM handle with non-empty value, see more at Readme. Example: all", logger.Params{"ATLAS_PLATFORM": handle}) - return nil + for _, handle := range handles { + if handle == allPlatformsHandle { + return allPlatforms.GetPlatformList() + } + p, ok := allPlatforms[handle] + if ok { + platforms = append(platforms, p) + } + } + return platforms } -func Init(platformHandle string) { - platformList := getActivePlatforms(platformHandle) +func Init(platformHandles []string) { + platformList := getActivePlatforms(platformHandles) Platforms = make(map[string]blockatlas.Platform) BlockAPIs = make(map[string]blockatlas.BlockAPI) diff --git a/services/observer/parser/parser.go b/services/observer/parser/parser.go index 634356512..ce3b5b5eb 100644 --- a/services/observer/parser/parser.go +++ b/services/observer/parser/parser.go @@ -157,7 +157,7 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatla } func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas.Block) error { - block, err := getBlockByNumberWithRetry(5, time.Second*5, api.GetBlockByNumber, num) + block, err := getBlockByNumberWithRetry(5, time.Second*5, api.GetBlockByNumber, num, api.Coin().Symbol) if err != nil { return errors.E(fmt.Sprintf("%d", num)) } @@ -263,7 +263,7 @@ func publish(params Params, txs blockatlas.Txs, wg *sync.WaitGroup) { } } -func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64) (*blockatlas.Block, error) { +func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64, symbol string) (*blockatlas.Block, error) { r, err := getBlockByNumber(n) if err != nil { if s, ok := err.(stop); ok { @@ -280,11 +280,12 @@ func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumb "number": n, "attempts": attempts, "sleep": sleep.String(), + "symbol": symbol, }, ) time.Sleep(sleep) - return getBlockByNumberWithRetry(attempts, sleep*2, getBlockByNumber, n) + return getBlockByNumberWithRetry(attempts, sleep*2, getBlockByNumber, n, symbol) } } return r, err diff --git a/services/observer/parser/parser_test.go b/services/observer/parser/parser_test.go index 5f0e6a015..8662316dd 100644 --- a/services/observer/parser/parser_test.go +++ b/services/observer/parser/parser_test.go @@ -84,7 +84,7 @@ func TestParser_add(t *testing.T) { } func TestParser_getBlockByNumberWithRetry(t *testing.T) { - block, err := getBlockByNumberWithRetry(3, time.Millisecond*1, getBlock, 1) + block, err := getBlockByNumberWithRetry(3, time.Millisecond*1, getBlock, 1, "") if err != nil { t.Error(err) } @@ -96,7 +96,7 @@ func TestParser_getBlockByNumberWithRetry(t *testing.T) { func TestParser_getBlockByNumberWithRetry_Error(t *testing.T) { now := time.Now() - block, err := getBlockByNumberWithRetry(2, time.Millisecond*2, getBlock, 0) + block, err := getBlockByNumberWithRetry(2, time.Millisecond*2, getBlock, 0, "") elapsed := time.Since(now) if err == nil { t.Error("getBlockByNumberWithRetry method need fail") From 4c385674ccd61c3fabe75128e819a7fef83bf9ae Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 17 May 2020 09:50:57 +0300 Subject: [PATCH 299/506] WIP Setup APM (#1104) * Setup APM for gin * Add APM for logger * Add APM form Gorm * Add APM for parser, notifier, subscriber with details * Tests and logs changes * go.mod changes * Solve gorm issue with race --- cmd/observer_notifier/main.go | 3 +- cmd/observer_parser/main.go | 3 +- cmd/observer_subscriber/main.go | 3 +- config.yml | 4 +- db/db.go | 16 ++- db/subscriptions.go | 19 +-- db/tracker.go | 13 ++- db/tracker_test.go | 9 +- go.mod | 13 ++- go.sum | 93 ++++++++++++++- internal/init.go | 2 + pkg/logger/logger.go | 2 + services/observer/notifier/notifier.go | 26 +++-- services/observer/parser/parser.go | 110 ++++++++++++------ services/observer/parser/parser_test.go | 37 +++--- services/observer/subscriber/subscriber.go | 9 +- .../observer/subscriber/subscriber_test.go | 37 ++++++ .../integration/db_test/subscriptions_test.go | 99 ++++++++-------- tests/integration/db_test/tracker_test.go | 9 +- .../observer_test/full_flow_test.go | 2 +- .../observer_test/notifier_test.go | 2 +- .../observer_test/subscriber_test.go | 20 ++-- tests/integration/setup/postgres.go | 2 +- 23 files changed, 377 insertions(+), 156 deletions(-) create mode 100644 services/observer/subscriber/subscriber_test.go diff --git a/cmd/observer_notifier/main.go b/cmd/observer_notifier/main.go index 850d712f4..b71fe186e 100644 --- a/cmd/observer_notifier/main.go +++ b/cmd/observer_notifier/main.go @@ -13,6 +13,7 @@ import ( const ( defaultConfigPath = "../../config.yml" + prod = "prod" ) var ( @@ -42,7 +43,7 @@ func init() { } var err error - database, err = db.New(pgUri) + database, err = db.New(pgUri, prod) if err != nil { logger.Fatal(err) } diff --git a/cmd/observer_parser/main.go b/cmd/observer_parser/main.go index 402e5d81f..e8282835e 100644 --- a/cmd/observer_parser/main.go +++ b/cmd/observer_parser/main.go @@ -20,6 +20,7 @@ import ( const ( defaultConfigPath = "../../config.yml" + prod = "prod" ) var ( @@ -63,7 +64,7 @@ func init() { logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") } var err error - database, err = db.New(pgUri) + database, err = db.New(pgUri, prod) if err != nil { logger.Fatal(err) } diff --git a/cmd/observer_subscriber/main.go b/cmd/observer_subscriber/main.go index 77225cbea..38d8dfdc5 100644 --- a/cmd/observer_subscriber/main.go +++ b/cmd/observer_subscriber/main.go @@ -14,6 +14,7 @@ import ( const ( defaultConfigPath = "../../config.yml" + prod = "prod" ) var ( @@ -35,7 +36,7 @@ func init() { internal.InitRabbitMQ(mqHost, prefetchCount) var err error - database, err = db.New(pgUri) + database, err = db.New(pgUri, prod) if err != nil { logger.Fatal(err) } diff --git a/config.yml b/config.yml index 70cb67372..f0f6a875b 100644 --- a/config.yml +++ b/config.yml @@ -11,7 +11,7 @@ gin: # If all - run all platforms in one binary. You can pick specific coin handle to run binary only with specific coin # Example: ethereum # You can see all the coin handles at coins/coins.yml file -platform: [ethereum, binance] +platform: [ethereum] # The transaction watcher observer: @@ -66,7 +66,7 @@ tezos: # [ETH] Ethereum: https://ethereum.org ethereum: api: https://localhost:4567 #(Trust-Ray API) - blockbook_api: https://eth1.trezor.io/api/ + blockbook_api: https://eth1.trezor.io/api collections_api: https://api.opensea.io # collections_api_key: [opensea_api_key] rpc: https://main-rpc.linkpool.io diff --git a/db/db.go b/db/db.go index c20036ec1..fe79c9638 100644 --- a/db/db.go +++ b/db/db.go @@ -2,9 +2,10 @@ package db import ( "github.com/jinzhu/gorm" - _ "github.com/jinzhu/gorm/dialects/postgres" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/logger" + "go.elastic.co/apm/module/apmgorm" + _ "go.elastic.co/apm/module/apmgorm/dialects/postgres" "time" ) @@ -12,8 +13,17 @@ type Instance struct { Gorm *gorm.DB } -func New(uri string) (*Instance, error) { - g, err := gorm.Open("postgres", uri) +func New(uri, env string) (*Instance, error) { + var ( + g *gorm.DB + err error + ) + if env == "prod" { + g, err = apmgorm.Open("postgres", uri) + } else { + g, err = gorm.Open("postgres", uri) + } + if err != nil { return nil, err } diff --git a/db/subscriptions.go b/db/subscriptions.go index 35bb2d2ec..917fc4021 100644 --- a/db/subscriptions.go +++ b/db/subscriptions.go @@ -1,9 +1,11 @@ package db import ( + "context" "fmt" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/errors" + "go.elastic.co/apm/module/apmgorm" "strconv" "strings" "time" @@ -11,13 +13,13 @@ import ( const rawBulkInsert = `INSERT INTO subscription_data(subscription_id, coin, address) VALUES %s ON CONFLICT DO NOTHING` -func (i *Instance) GetSubscriptionData(coin uint, addresses []string) ([]models.SubscriptionData, error) { +func (i *Instance) GetSubscriptionData(coin uint, addresses []string, ctx context.Context) ([]models.SubscriptionData, error) { if len(addresses) == 0 { return nil, errors.E("Empty addresses") } - + g := apmgorm.WithContext(ctx, i.Gorm) var subscriptionsDataList []models.SubscriptionData - err := i.Gorm. + err := g. Model(&models.SubscriptionData{}). Where("address in (?) AND coin = ?", addresses, coin). Find(&subscriptionsDataList).Error @@ -28,12 +30,12 @@ func (i *Instance) GetSubscriptionData(coin uint, addresses []string) ([]models. return subscriptionsDataList, nil } -func (i *Instance) AddSubscriptions(id uint, subscriptions []models.SubscriptionData) error { +func (i *Instance) AddSubscriptions(id uint, subscriptions []models.SubscriptionData, ctx context.Context) error { if len(subscriptions) == 0 { return errors.E("Empty subscriptions") } - - txInstance := Instance{Gorm: i.Gorm.Begin()} + g := apmgorm.WithContext(ctx, i.Gorm) + txInstance := Instance{Gorm: g.Begin()} defer func() { if r := recover(); r != nil { txInstance.Gorm.Rollback() @@ -106,8 +108,9 @@ func (i *Instance) AddToExistingSubscription(id uint, subscriptions []models.Sub return nil } -func (i *Instance) DeleteAllSubscriptions(id uint) error { - request := i.Gorm.Where("subscription_id = ?", id) +func (i *Instance) DeleteAllSubscriptions(id uint, ctx context.Context) error { + g := apmgorm.WithContext(ctx, i.Gorm) + request := g.Where("subscription_id = ?", id) if err := request.Error; err != nil { return err } diff --git a/db/tracker.go b/db/tracker.go index 1007e0b1f..86c8ba69f 100644 --- a/db/tracker.go +++ b/db/tracker.go @@ -1,7 +1,9 @@ package db import ( + "context" "github.com/trustwallet/blockatlas/db/models" + "go.elastic.co/apm/module/apmgorm" "sync" ) @@ -29,26 +31,27 @@ func (hbm *heightBlockMap) GetHeight(coin string) (int64, bool) { return b, ok } -func (i *Instance) GetLastParsedBlockNumber(coin string) (int64, error) { +func (i *Instance) GetLastParsedBlockNumber(coin string, ctx context.Context) (int64, error) { height, ok := memoryCache.GetHeight(coin) if ok { return height, nil } var tracker models.Tracker - if err := i.Gorm.Where(models.Tracker{Coin: coin}).Find(&tracker).Error; err != nil { + g := apmgorm.WithContext(ctx, i.Gorm) + if err := g.Where(models.Tracker{Coin: coin}).Find(&tracker).Error; err != nil { return 0, nil } return tracker.Height, nil } -func (i *Instance) SetLastParsedBlockNumber(coin string, num int64) error { +func (i *Instance) SetLastParsedBlockNumber(coin string, num int64, ctx context.Context) error { memoryCache.SetHeight(coin, num) tracker := models.Tracker{ Coin: coin, Height: num, } - - return i.Gorm. + g := apmgorm.WithContext(ctx, i.Gorm) + return g. Set("gorm:insert_option", "ON CONFLICT (coin) DO UPDATE SET height = excluded.height"). Where(models.Tracker{Coin: coin}). Create(&tracker).Error diff --git a/db/tracker_test.go b/db/tracker_test.go index a25121650..502c4a867 100644 --- a/db/tracker_test.go +++ b/db/tracker_test.go @@ -1,6 +1,7 @@ package db import ( + "context" "github.com/DATA-DOG/go-sqlmock" "github.com/jinzhu/gorm" "github.com/stretchr/testify/assert" @@ -19,7 +20,7 @@ func TestHeightBlockMap_SetHeight(t *testing.T) { mock.ExpectCommit() i := Instance{Gorm: db} - assert.Nil(t, i.SetLastParsedBlockNumber("bitcoin", 1)) + assert.Nil(t, i.SetLastParsedBlockNumber("bitcoin", 1, context.Background())) } func TestHeightBlockMap_GetHeight(t *testing.T) { @@ -33,8 +34,8 @@ func TestHeightBlockMap_GetHeight(t *testing.T) { mock.ExpectCommit() i := Instance{Gorm: db} - assert.Nil(t, i.SetLastParsedBlockNumber("bitcoin", 1)) - block, err := i.GetLastParsedBlockNumber("bitcoin") + assert.Nil(t, i.SetLastParsedBlockNumber("bitcoin", 1, context.Background())) + block, err := i.GetLastParsedBlockNumber("bitcoin", context.Background()) assert.Nil(t, err) assert.Equal(t, int64(1), block) @@ -43,7 +44,7 @@ func TestHeightBlockMap_GetHeight(t *testing.T) { `SELECT * FROM "trackers" WHERE ("trackers"."coin" = $1`)).WithArgs("ethereum").WillReturnRows(sqlmock.NewRows([]string{"coin", "height"}). AddRow("ethereum", 1)) - b, err := i.GetLastParsedBlockNumber("ethereum") + b, err := i.GetLastParsedBlockNumber("ethereum", context.Background()) assert.Nil(t, err) assert.Equal(t, int64(1), b) diff --git a/go.mod b/go.mod index c1415e7a1..20b1ccd59 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,10 @@ require ( github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect + github.com/elastic/go-sysinfo v1.3.0 // indirect + github.com/elastic/go-windows v1.0.1 // indirect github.com/gin-gonic/gin v1.6.3 + github.com/golang/protobuf v1.4.2 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/jinzhu/gorm v1.9.12 github.com/mitchellh/mapstructure v1.3.0 @@ -24,6 +27,7 @@ require ( github.com/opencontainers/runc v0.1.1 // indirect github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.6.0 github.com/shopspring/decimal v1.2.0 github.com/sirupsen/logrus v1.6.0 @@ -33,10 +37,17 @@ require ( github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.5 github.com/trustwallet/ens-coincodec v1.0.5 + go.elastic.co/apm v1.8.0 + go.elastic.co/apm/module/apmgin v1.8.0 + go.elastic.co/apm/module/apmgorm v1.8.0 + go.elastic.co/apm/module/apmlogrus v1.8.0 + go.elastic.co/fastjson v1.1.0 // indirect go.uber.org/atomic v1.6.0 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f + golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect golang.org/x/tools v0.0.0-20200513175351-0951661448da // indirect - gopkg.in/yaml.v2 v2.2.8 + gopkg.in/yaml.v2 v2.3.0 gotest.tools v2.2.0+incompatible // indirect + howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 // indirect ) diff --git a/go.sum b/go.sum index fa19a1e17..4d2b75351 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,9 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= @@ -31,15 +33,20 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 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/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/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/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -77,12 +84,15 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c h1:4e6Zsb6LFd3kadoMiut2zcd3hCb4zywpJnQa8+NV2Cs= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c/go.mod h1:k5D13LCXSsMrQyfdW0yGYs4GWUvirqoxHht8qwtqyRY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cucumber/godog v0.8.1 h1:lVb+X41I4YDreE+ibZ50bdXmySxgRviYFgKY6Aw4XE8= +github.com/cucumber/godog v0.8.1/go.mod h1:vSh3r/lM+psC1BPXvdkSEuNjmXfpVqrMGYAElF6hxnA= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -92,6 +102,17 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/elastic/go-sysinfo v1.1.1 h1:ZVlaLDyhVkDfjwPGU55CQRCRolNpc7P0BbyhhQZQmMI= +github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= +github.com/elastic/go-sysinfo v1.3.0 h1:eb2XFGTMlSwG/yyU9Y8jVAYLIzU2sFzWXwo2gmetyrE= +github.com/elastic/go-sysinfo v1.3.0/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= +github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= +github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= +github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= +github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -139,8 +160,11 @@ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1 github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -159,6 +183,9 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -175,6 +202,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= @@ -205,12 +234,16 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -236,6 +269,7 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= @@ -251,6 +285,7 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -286,6 +321,7 @@ github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVo github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -293,37 +329,49 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= +github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= @@ -388,7 +436,24 @@ github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.elastic.co/apm v1.8.0 h1:AWEKpHwRal0yCMd4K8Oxy1HAa7xid+xq1yy+XjgoVU0= +go.elastic.co/apm v1.8.0/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= +go.elastic.co/apm/module/apmgin v1.8.0 h1:QcXVtFhqAcSGqC/ywzqZBHdWzJG3wyrBxgvCvAZ98do= +go.elastic.co/apm/module/apmgin v1.8.0/go.mod h1:heH2rXaOluBb+ucwlG3FBCGrx56qHqoxb1KI7uBLlAk= +go.elastic.co/apm/module/apmgorm v1.8.0 h1:1vKuD8hsbJcChcUQTBb1N8Zy1tILR5pGTExLtijyhko= +go.elastic.co/apm/module/apmgorm v1.8.0/go.mod h1:18ttEKPQr0cvRSeG95WMXoPUy2BT8Jp1EzhPU5NQYTY= +go.elastic.co/apm/module/apmhttp v1.8.0 h1:5AJPefWJzWDLX/47XIDfaloGiYWkkOQEULvlrI6Ieaw= +go.elastic.co/apm/module/apmhttp v1.8.0/go.mod h1:9LPFlEON51/lRbnWDfqAWErihIiAFDUMfMV27YjoWQ8= +go.elastic.co/apm/module/apmlogrus v1.8.0 h1:HSz+gNSa88zLvoX36OaCSgbqTTCn7u3GrR6WqRu8RiU= +go.elastic.co/apm/module/apmlogrus v1.8.0/go.mod h1:0TsyfBEaY5FaGS2p9UlSRhmf1T1zhmf9vcwgQTlI064= +go.elastic.co/apm/module/apmsql v1.8.0 h1:YMGTshRcC9SI8p+hJNI7OzNnk7Dn9RjwuwO0MRcbvvE= +go.elastic.co/apm/module/apmsql v1.8.0/go.mod h1:pX+PSxIcEv5BvIYJjQnODzNwJ6+DJDeLb0fzrhSOIhE= +go.elastic.co/fastjson v1.0.0 h1:ooXV/ABvf+tBul26jcVViPT3sBir0PvXgibYB1IQQzg= +go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs= +go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4= +go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -408,9 +473,8 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88= -golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -432,6 +496,7 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -442,6 +507,7 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -451,6 +517,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y= @@ -471,6 +538,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -483,11 +551,16 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= @@ -495,6 +568,7 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -517,13 +591,16 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200513175351-0951661448da h1:ZR1ivkcQoKXKtux9Rx3Em7iiSViMxQ5suNd5PZMUkPc= golang.org/x/tools v0.0.0-20200513175351-0951661448da/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -535,13 +612,16 @@ google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -551,6 +631,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -573,10 +655,17 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= +howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= +howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 h1:AQkaJpH+/FmqRjmXZPELom5zIERYZfwTjnHpfoVMQEc= +howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/internal/init.go b/internal/init.go index e61222cd7..d2da34fe1 100644 --- a/internal/init.go +++ b/internal/init.go @@ -7,6 +7,7 @@ import ( "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" + "go.elastic.co/apm/module/apmgin" "path/filepath" "time" @@ -42,6 +43,7 @@ func InitEngine(ginMode string) *gin.Engine { gin.SetMode(ginMode) engine := gin.New() engine.Use(middleware.CORSMiddleware()) + engine.Use(apmgin.Middleware(engine)) engine.Use(gin.Logger()) engine.Use(middleware.Prometheus()) engine.OPTIONS("/*path", middleware.CORSMiddleware()) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 0540af00c..221f40798 100755 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -3,6 +3,7 @@ package logger import ( "fmt" log "github.com/sirupsen/logrus" + "go.elastic.co/apm/module/apmlogrus" "os" "strings" ) @@ -12,6 +13,7 @@ type Params map[string]interface{} func InitLogger() { log.SetFormatter(&log.TextFormatter{}) log.SetOutput(os.Stdout) + log.AddHook(&apmlogrus.Hook{}) } type message struct { diff --git a/services/observer/notifier/notifier.go b/services/observer/notifier/notifier.go index 35e1b0951..898242bb6 100644 --- a/services/observer/notifier/notifier.go +++ b/services/observer/notifier/notifier.go @@ -1,6 +1,7 @@ package notifier import ( + "context" "encoding/json" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" @@ -9,6 +10,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" + "go.elastic.co/apm" "sync" "time" ) @@ -24,6 +26,9 @@ type TransactionNotification struct { } func RunNotifier(database *db.Instance, delivery amqp.Delivery) { + tx := apm.DefaultTracer.StartTransaction("RunNotifier", "app") + defer tx.End() + ctx := apm.ContextWithTransaction(context.Background(), tx) defer func() { if err := delivery.Ack(false); err != nil { logger.Error(err) @@ -46,7 +51,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { } addresses := blockTransactions.GetUniqueAddresses() - subscriptionsDataList, err := database.GetSubscriptionData(txs[0].Coin, addresses) + subscriptionsDataList, err := database.GetSubscriptionData(txs[0].Coin, addresses, ctx) if err != nil || len(subscriptionsDataList) == 0 { return } @@ -57,14 +62,17 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { go buildAndPostMessage( blockTransactions, blockatlas.Subscription{Coin: data.Coin, Address: data.Address, Id: data.SubscriptionId}, - &wg) + &wg, ctx) } wg.Wait() } -func buildAndPostMessage(blockTransactions blockatlas.TxSetMap, sub blockatlas.Subscription, wg *sync.WaitGroup) { +func buildAndPostMessage(blockTransactions blockatlas.TxSetMap, sub blockatlas.Subscription, wg *sync.WaitGroup, ctx context.Context) { defer wg.Done() + span, ctx := apm.StartSpan(ctx, "buildAndPostMessage", "app") + defer span.End() + tx, ok := blockTransactions.Map[sub.Address] if !ok { return @@ -84,14 +92,16 @@ func buildAndPostMessage(blockTransactions blockatlas.TxSetMap, sub blockatlas.S notifications = append(notifications, notification) } - batches := getNotificationBatches(notifications, MaxPushNotificationsBatchLimit) + batches := getNotificationBatches(notifications, MaxPushNotificationsBatchLimit, ctx) for _, batch := range batches { - publishNotificationBatch(batch) + publishNotificationBatch(batch, ctx) } } -func publishNotificationBatch(batch []TransactionNotification) { +func publishNotificationBatch(batch []TransactionNotification, ctx context.Context) { + span, _ := apm.StartSpan(ctx, "getNotificationBatches", "app") + defer span.End() raw, err := json.Marshal(batch) if err != nil { err = errors.E(err, " failed to dispatch event") @@ -114,7 +124,9 @@ func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duratio return time.Duration(pMax) } -func getNotificationBatches(notifications []TransactionNotification, sizeUint uint) [][]TransactionNotification { +func getNotificationBatches(notifications []TransactionNotification, sizeUint uint, ctx context.Context) [][]TransactionNotification { + span, _ := apm.StartSpan(ctx, "getNotificationBatches", "app") + defer span.End() size := int(sizeUint) resultLength := (len(notifications) + size - 1) / size result := make([][]TransactionNotification, resultLength) diff --git a/services/observer/parser/parser.go b/services/observer/parser/parser.go index ce3b5b5eb..e5e103c2d 100644 --- a/services/observer/parser/parser.go +++ b/services/observer/parser/parser.go @@ -8,6 +8,8 @@ import ( "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "go.elastic.co/apm" + "strconv" "sync/atomic" "github.com/trustwallet/blockatlas/pkg/logger" @@ -53,33 +55,51 @@ func RunParser(params Params) { params.StopChannel <- struct{}{} return default: - lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params) - if err != nil || lastParsedBlock > currentBlock { - logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) - time.Sleep(params.ParsingBlocksInterval) - continue - } + parse(params) + time.Sleep(params.ParsingBlocksInterval) + } + } +} - blocks := FetchBlocks(params, lastParsedBlock, currentBlock) +func parse(params Params) { + tx := apm.DefaultTracer.StartTransaction("parse", "app") + ctx := apm.ContextWithTransaction(context.Background(), tx) - err = SaveLastParsedBlock(params, blocks) - if err != nil { - logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) - time.Sleep(params.ParsingBlocksInterval) - continue - } + defer tx.End() + + lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params, ctx) + if err != nil || lastParsedBlock > currentBlock { + logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + time.Sleep(params.ParsingBlocksInterval) + tx.Result = "failed" + return + } + tx.Context.SetTag("lastParsedBlock", strconv.Itoa(int(lastParsedBlock))) + tx.Context.SetTag("lastParsedBlock", strconv.Itoa(int(lastParsedBlock))) - txs := ConvertToBatch(blocks) + blocks := FetchBlocks(params, lastParsedBlock, currentBlock, ctx) - PublishTransactionsBatch(params, txs) + tx.Context.SetTag("blocks len", strconv.Itoa(len(blocks))) - time.Sleep(params.ParsingBlocksInterval) - } + err = SaveLastParsedBlock(params, blocks, ctx) + if err != nil { + logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + time.Sleep(params.ParsingBlocksInterval) + tx.Result = "failed" + return } + + txs := ConvertToBatch(blocks, ctx) + tx.Result = "success" + tx.Context.SetTag("txs", strconv.Itoa(len(txs))) + PublishTransactionsBatch(params, txs, ctx) } -func GetBlocksIntervalToFetch(params Params) (int64, int64, error) { - lastParsedBlock, err := params.Database.GetLastParsedBlockNumber(params.Api.Coin().Handle) +func GetBlocksIntervalToFetch(params Params, ctx context.Context) (int64, int64, error) { + span, ctx := apm.StartSpan(ctx, "GetBlocksIntervalToFetch", "app") + defer span.End() + + lastParsedBlock, err := params.Database.GetLastParsedBlockNumber(params.Api.Coin().Handle, ctx) if err != nil { return 0, 0, errors.E(err, "Polling failed: tracker didn't return last known block number") } @@ -100,7 +120,10 @@ func GetBlocksIntervalToFetch(params Params) (int64, int64, error) { return lastParsedBlock, currentBlock, nil } -func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatlas.Block { +func FetchBlocks(params Params, lastParsedBlock, currentBlock int64, ctx context.Context) []blockatlas.Block { + span, ctx := apm.StartSpan(ctx, "FetchBlocks", "app") + defer span.End() + if lastParsedBlock == currentBlock { logger.Info("No new blocks", logger.Params{"last": lastParsedBlock, "coin": params.Api.Coin().ID, "time": time.Now().Unix()}) return nil @@ -124,7 +147,7 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatla time.Sleep(params.FetchBlocksTimeout) go func(i int64, wg *sync.WaitGroup) { defer wg.Done() - err := fetchBlock(params.Api, i, blocksChan) + err := fetchBlock(params.Api, i, blocksChan, ctx) if err != nil { errorsChan <- err return @@ -156,8 +179,10 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatla return blocksList } -func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas.Block) error { - block, err := getBlockByNumberWithRetry(5, time.Second*5, api.GetBlockByNumber, num, api.Coin().Symbol) +func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas.Block, ctx context.Context) error { + span, ctx := apm.StartSpan(ctx, "fetchBlock", "app") + defer span.End() + block, err := getBlockByNumberWithRetry(5, time.Second*5, api.GetBlockByNumber, num, api.Coin().Symbol, ctx) if err != nil { return errors.E(fmt.Sprintf("%d", num)) } @@ -165,7 +190,10 @@ func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas return nil } -func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { +func SaveLastParsedBlock(params Params, blocks []blockatlas.Block, ctx context.Context) error { + span, ctx := apm.StartSpan(ctx, "SaveLastParsedBlock", "app") + defer span.End() + if len(blocks) == 0 { return nil } @@ -178,7 +206,7 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { if lastBlockNumber <= 0 { return errors.E(fmt.Sprintf("Parser of %s failed to save last block, lastBlockNumber <= 0", params.Api.Coin().Handle)) } - err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().Handle, lastBlockNumber) + err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().Handle, lastBlockNumber, ctx) if err != nil { return err } @@ -187,7 +215,9 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { return nil } -func ConvertToBatch(blocks []blockatlas.Block) blockatlas.Txs { +func ConvertToBatch(blocks []blockatlas.Block, ctx context.Context) blockatlas.Txs { + span, ctx := apm.StartSpan(ctx, "ConvertToBatch", "app") + defer span.End() if len(blocks) == 0 { return nil } @@ -201,7 +231,7 @@ func ConvertToBatch(blocks []blockatlas.Block) blockatlas.Txs { wg.Add(1) go func(block blockatlas.Block, wg *sync.WaitGroup) { defer wg.Done() - txsBatch.fillBatch(block.Txs) + txsBatch.fillBatch(block.Txs, ctx) }(block, &wg) } wg.Wait() @@ -215,18 +245,20 @@ func ConvertToBatch(blocks []blockatlas.Block) blockatlas.Txs { return txsBatch.Txs } -func PublishTransactionsBatch(params Params, txs blockatlas.Txs) { +func PublishTransactionsBatch(params Params, txs blockatlas.Txs, ctx context.Context) { + span, ctx := apm.StartSpan(ctx, "PublishTransactionsBatch", "app") + defer span.End() if len(txs) == 0 { logger.Info("------------------------------------------------------------") return } - batches := getTxsBatches(txs, params.TxBatchLimit) + batches := getTxsBatches(txs, params.TxBatchLimit, ctx) var wg sync.WaitGroup for _, batch := range batches { wg.Add(1) - go publish(params, batch, &wg) + go publish(params, batch, &wg, ctx) } wg.Wait() @@ -234,7 +266,9 @@ func PublishTransactionsBatch(params Params, txs blockatlas.Txs) { logger.Info("------------------------------------------------------------") } -func getTxsBatches(txs blockatlas.Txs, sizeUint uint) []blockatlas.Txs { +func getTxsBatches(txs blockatlas.Txs, sizeUint uint, ctx context.Context) []blockatlas.Txs { + span, _ := apm.StartSpan(ctx, "getTxsBatches", "app") + defer span.End() size := int(sizeUint) resultLength := (len(txs) + size - 1) / size result := make([]blockatlas.Txs, resultLength) @@ -249,7 +283,9 @@ func getTxsBatches(txs blockatlas.Txs, sizeUint uint) []blockatlas.Txs { return result } -func publish(params Params, txs blockatlas.Txs, wg *sync.WaitGroup) { +func publish(params Params, txs blockatlas.Txs, wg *sync.WaitGroup, ctx context.Context) { + span, _ := apm.StartSpan(ctx, "publish", "app") + defer span.End() defer wg.Done() body, err := json.Marshal(txs) if err != nil { @@ -263,7 +299,9 @@ func publish(params Params, txs blockatlas.Txs, wg *sync.WaitGroup) { } } -func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64, symbol string) (*blockatlas.Block, error) { +func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64, symbol string, ctx context.Context) (*blockatlas.Block, error) { + span, ctx := apm.StartSpan(ctx, "getBlockByNumberWithRetry", "app") + defer span.End() r, err := getBlockByNumber(n) if err != nil { if s, ok := err.(stop); ok { @@ -285,13 +323,15 @@ func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumb ) time.Sleep(sleep) - return getBlockByNumberWithRetry(attempts, sleep*2, getBlockByNumber, n, symbol) + return getBlockByNumberWithRetry(attempts, sleep*2, getBlockByNumber, n, symbol, ctx) } } return r, err } -func (t *transactionsBatch) fillBatch(transactions []blockatlas.Tx) { +func (t *transactionsBatch) fillBatch(transactions []blockatlas.Tx, ctx context.Context) { + span, _ := apm.StartSpan(ctx, "fillBatch", "app") + defer span.End() t.Lock() defer t.Unlock() if len(transactions) == 0 { diff --git a/services/observer/parser/parser_test.go b/services/observer/parser/parser_test.go index 8662316dd..a6e87a394 100644 --- a/services/observer/parser/parser_test.go +++ b/services/observer/parser/parser_test.go @@ -1,6 +1,7 @@ package parser import ( + "context" "errors" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" @@ -53,38 +54,38 @@ func TestFetchBlocks(t *testing.T) { TxBatchLimit: 0, Database: nil, } - blocks := FetchBlocks(params, 0, 100) + blocks := FetchBlocks(params, 0, 100, context.Background()) assert.Equal(t, len(blocks), 100) } func TestParser_ConvertToBatch(t *testing.T) { blocks := []blockatlas.Block{block, block, block, block} - txs := ConvertToBatch(blocks) + txs := ConvertToBatch(blocks, context.Background()) assert.Equal(t, 4, len(txs)) empty := []blockatlas.Block{} - txsEmpty := ConvertToBatch(empty) + txsEmpty := ConvertToBatch(empty, context.Background()) assert.Equal(t, 0, len(txsEmpty)) } func TestParser_add(t *testing.T) { blocks := []blockatlas.Block{block, block, block, block} - txs := ConvertToBatch(blocks) + txs := ConvertToBatch(blocks, context.Background()) batch := transactionsBatch{ Mutex: sync.Mutex{}, Txs: txs, } - batch.fillBatch(txs) + batch.fillBatch(txs, context.Background()) assert.Equal(t, 8, len(batch.Txs)) - batch.fillBatch(nil) + batch.fillBatch(nil, context.Background()) assert.Equal(t, 8, len(batch.Txs)) } func TestParser_getBlockByNumberWithRetry(t *testing.T) { - block, err := getBlockByNumberWithRetry(3, time.Millisecond*1, getBlock, 1, "") + block, err := getBlockByNumberWithRetry(3, time.Millisecond*1, getBlock, 1, "", context.Background()) if err != nil { t.Error(err) } @@ -96,7 +97,7 @@ func TestParser_getBlockByNumberWithRetry(t *testing.T) { func TestParser_getBlockByNumberWithRetry_Error(t *testing.T) { now := time.Now() - block, err := getBlockByNumberWithRetry(2, time.Millisecond*2, getBlock, 0, "") + block, err := getBlockByNumberWithRetry(2, time.Millisecond*2, getBlock, 0, "", context.Background()) elapsed := time.Since(now) if err == nil { t.Error("getBlockByNumberWithRetry method need fail") @@ -141,35 +142,35 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { func TestGetTxBatches(t *testing.T) { txs := make(blockatlas.Txs, 10000) - batches := getTxsBatches(txs, 1000) + batches := getTxsBatches(txs, 1000, context.Background()) assert.Len(t, batches, 10) - batches = getTxsBatches(txs, 100) + batches = getTxsBatches(txs, 100, context.Background()) assert.Len(t, batches, 100) - batches = getTxsBatches(txs, 500) + batches = getTxsBatches(txs, 500, context.Background()) assert.Len(t, batches, 20) txs = make(blockatlas.Txs, 3800) - batches = getTxsBatches(txs, 100) + batches = getTxsBatches(txs, 100, context.Background()) assert.Len(t, batches, 38) - batches = getTxsBatches(txs, 1000) + batches = getTxsBatches(txs, 1000, context.Background()) assert.Len(t, batches, 4) txs = make(blockatlas.Txs, 5000) - batches = getTxsBatches(txs, 10000) + batches = getTxsBatches(txs, 10000, context.Background()) assert.Len(t, batches, 1) txs = make(blockatlas.Txs, 0) - batches = getTxsBatches(txs, 100) + batches = getTxsBatches(txs, 100, context.Background()) assert.Len(t, batches, 0) txs = make(blockatlas.Txs, 0) - batches = getTxsBatches(txs, 100) + batches = getTxsBatches(txs, 100, context.Background()) assert.Len(t, batches, 0) - batches = getTxsBatches(nil, 100) + batches = getTxsBatches(nil, 100, context.Background()) assert.Len(t, batches, 0) txs = make(blockatlas.Txs, 1000000) - batches = getTxsBatches(txs, 5000) + batches = getTxsBatches(txs, 5000, context.Background()) assert.Len(t, batches, 200) } diff --git a/services/observer/subscriber/subscriber.go b/services/observer/subscriber/subscriber.go index 713781749..1100b4361 100644 --- a/services/observer/subscriber/subscriber.go +++ b/services/observer/subscriber/subscriber.go @@ -1,12 +1,14 @@ package subscriber import ( + "context" "encoding/json" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" + "go.elastic.co/apm" ) const ( @@ -16,6 +18,9 @@ const ( ) func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { + tx := apm.DefaultTracer.StartTransaction("RunSubscriber", "app") + defer tx.End() + ctx := apm.ContextWithTransaction(context.Background(), tx) var event blockatlas.SubscriptionEvent err := json.Unmarshal(delivery.Body, &event) if err != nil { @@ -30,13 +35,13 @@ func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { switch event.Operation { case AddSubscription, UpdateSubscription: - err = database.AddSubscriptions(id, ToSubscriptionData(subscriptions)) + err = database.AddSubscriptions(id, ToSubscriptionData(subscriptions), ctx) if err != nil { logger.Error(err, params) } logger.Info("Added", params) case DeleteSubscription: - err := database.DeleteAllSubscriptions(id) + err := database.DeleteAllSubscriptions(id, ctx) if err != nil { logger.Error(err, params) } diff --git a/services/observer/subscriber/subscriber_test.go b/services/observer/subscriber/subscriber_test.go new file mode 100644 index 000000000..713b879e8 --- /dev/null +++ b/services/observer/subscriber/subscriber_test.go @@ -0,0 +1,37 @@ +package subscriber + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" +) + +func TestToSubscriptionData(t *testing.T) { + sub := blockatlas.Subscription{ + Coin: 60, + Address: "A", + Id: 1, + } + sub2 := blockatlas.Subscription{ + Coin: 60, + Address: "B", + Id: 2, + } + + expectedModel := models.SubscriptionData{ + SubscriptionId: 1, + Coin: 60, + Address: "A", + } + expectedModel1 := models.SubscriptionData{ + SubscriptionId: 2, + Coin: 60, + Address: "B", + } + + res := ToSubscriptionData([]blockatlas.Subscription{sub, sub2}) + assert.Equal(t, 2, len(res)) + assert.Equal(t, expectedModel, res[0]) + assert.Equal(t, expectedModel1, res[1]) +} diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go index 49a5e03b1..0cafda6dd 100644 --- a/tests/integration/db_test/subscriptions_test.go +++ b/tests/integration/db_test/subscriptions_test.go @@ -3,6 +3,7 @@ package db_test import ( + "context" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -26,9 +27,9 @@ func TestDb_AddSubscriptionsBulk(t *testing.T) { }) } - assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) for i := 0; i < 100; i++ { - s, err := database.GetSubscriptionData(uint(i), []string{"testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr"}) + s, err := database.GetSubscriptionData(uint(i), []string{"testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr"}, context.Background()) assert.Nil(t, err) assert.Equal(t, id, s[0].SubscriptionId) } @@ -58,9 +59,9 @@ func TestDb_AddSubscriptions(t *testing.T) { Address: "testAddr3", }) - assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) - subs, err := database.GetSubscriptionData(60, []string{"testAddr"}) + subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) @@ -68,7 +69,7 @@ func TestDb_AddSubscriptions(t *testing.T) { assert.Equal(t, subscriptions[0].Coin, subs[0].Coin) assert.Equal(t, subscriptions[0].Address, subs[0].Address) - subs, err = database.GetSubscriptionData(61, []string{"testAddr2"}) + subs, err = database.GetSubscriptionData(61, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) @@ -76,7 +77,7 @@ func TestDb_AddSubscriptions(t *testing.T) { assert.Equal(t, subscriptions[1].Coin, subs[0].Coin) assert.Equal(t, subscriptions[1].Address, subs[0].Address) - subs, err = database.GetSubscriptionData(62, []string{"testAddr3"}) + subs, err = database.GetSubscriptionData(62, []string{"testAddr3"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) @@ -108,9 +109,9 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { Address: "testAddr", }) - assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) - subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}) + subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs60) assert.Equal(t, 1, len(subs60)) @@ -118,7 +119,7 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { assert.Equal(t, subscriptions[0].Coin, subs60[0].Coin) assert.Equal(t, subscriptions[0].Address, subs60[0].Address) - subs714, err := database.GetSubscriptionData(714, []string{"testAddr"}) + subs714, err := database.GetSubscriptionData(714, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs714) assert.Equal(t, 1, len(subs714)) @@ -126,7 +127,7 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { assert.Equal(t, subscriptions[1].Coin, subs714[0].Coin) assert.Equal(t, subscriptions[1].Address, subs714[0].Address) - subs144, err := database.GetSubscriptionData(144, []string{"testAddr"}) + subs144, err := database.GetSubscriptionData(144, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs144) assert.Equal(t, 1, len(subs144)) @@ -152,9 +153,9 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { Address: "testAddr2", }) - assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) - subs2N60, err := database.GetSubscriptionData(60, []string{"testAddr2"}) + subs2N60, err := database.GetSubscriptionData(60, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.Nil(t, err) assert.NotNil(t, subs2N60) @@ -163,7 +164,7 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { assert.Equal(t, subscriptions[3].Coin, subs2N60[0].Coin) assert.Equal(t, subscriptions[3].Address, subs2N60[0].Address) - subs2N714, err := database.GetSubscriptionData(714, []string{"testAddr2"}) + subs2N714, err := database.GetSubscriptionData(714, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.Nil(t, err) assert.NotNil(t, subs2N714) @@ -172,7 +173,7 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { assert.Equal(t, subscriptions[4].Coin, subs2N714[0].Coin) assert.Equal(t, subscriptions[4].Address, subs2N714[0].Address) - subs2N114, err := database.GetSubscriptionData(144, []string{"testAddr2"}) + subs2N114, err := database.GetSubscriptionData(144, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.Nil(t, err) assert.NotNil(t, subs2N114) @@ -217,7 +218,7 @@ func TestDb_FindSubscriptions(t *testing.T) { Address: "ETCAddress", }) - assert.Nil(t, database.AddSubscriptions(id, subscriber.ToSubscriptionData(subscriptionsA))) + assert.Nil(t, database.AddSubscriptions(id, subscriber.ToSubscriptionData(subscriptionsA), context.Background())) var subscriptionsB []blockatlas.Subscription @@ -225,25 +226,25 @@ func TestDb_FindSubscriptions(t *testing.T) { sub.Id = uint(2) subscriptionsB = append(subscriptionsB, sub) } - assert.Nil(t, database.AddSubscriptions(2, subscriber.ToSubscriptionData(subscriptionsB))) + assert.Nil(t, database.AddSubscriptions(2, subscriber.ToSubscriptionData(subscriptionsB), context.Background())) - returnedSubs, err := database.GetSubscriptionData(60, []string{"etherAddress"}) + returnedSubs, err := database.GetSubscriptionData(60, []string{"etherAddress"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 2, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionData(714, []string{"binanceAddress"}) + returnedSubs, err = database.GetSubscriptionData(714, []string{"binanceAddress"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 2, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionData(144, []string{"XLMAddress"}) + returnedSubs, err = database.GetSubscriptionData(144, []string{"XLMAddress"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 2, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionData(148, []string{"AtomAddress"}) + returnedSubs, err = database.GetSubscriptionData(148, []string{"AtomAddress"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 2, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionData(61, []string{"ETCAddress"}) + returnedSubs, err = database.GetSubscriptionData(61, []string{"ETCAddress"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 2, len(returnedSubs)) } @@ -271,9 +272,9 @@ func TestDb_DeleteSubscriptions(t *testing.T) { Address: "testAddr3", }) - assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) - subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}) + subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs60) assert.Equal(t, 1, len(subs60)) @@ -281,7 +282,7 @@ func TestDb_DeleteSubscriptions(t *testing.T) { assert.Equal(t, subscriptions[0].Coin, subs60[0].Coin) assert.Equal(t, subscriptions[0].Address, subs60[0].Address) - subs714, err := database.GetSubscriptionData(714, []string{"testAddr2"}) + subs714, err := database.GetSubscriptionData(714, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs714) assert.Equal(t, 1, len(subs714)) @@ -289,7 +290,7 @@ func TestDb_DeleteSubscriptions(t *testing.T) { assert.Equal(t, subscriptions[1].Coin, subs714[0].Coin) assert.Equal(t, subscriptions[1].Address, subs714[0].Address) - subs144, err := database.GetSubscriptionData(144, []string{"testAddr3"}) + subs144, err := database.GetSubscriptionData(144, []string{"testAddr3"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs144) assert.Equal(t, 1, len(subs144)) @@ -302,7 +303,7 @@ func TestDb_DeleteSubscriptions(t *testing.T) { assert.Nil(t, database.DeleteSubscriptions(subsToDel)) - subs714N2, err := database.GetSubscriptionData(714, []string{"testAddr2"}) + subs714N2, err := database.GetSubscriptionData(714, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs714N2) assert.Equal(t, 1, len(subs714N2)) @@ -310,7 +311,7 @@ func TestDb_DeleteSubscriptions(t *testing.T) { assert.Equal(t, subscriptions[1].Coin, subs714N2[0].Coin) assert.Equal(t, subscriptions[1].Address, subs714N2[0].Address) - subs144N2, err := database.GetSubscriptionData(144, []string{"testAddr3"}) + subs144N2, err := database.GetSubscriptionData(144, []string{"testAddr3"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs144N2) assert.Equal(t, 1, len(subs144N2)) @@ -318,7 +319,7 @@ func TestDb_DeleteSubscriptions(t *testing.T) { assert.Equal(t, subscriptions[2].Coin, subs144N2[0].Coin) assert.Equal(t, subscriptions[2].Address, subs144N2[0].Address) - subs60N2, err := database.GetSubscriptionData(60, []string{"testAddr"}) + subs60N2, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs60N2, 0) } @@ -345,37 +346,37 @@ func TestDeleteAll(t *testing.T) { Coin: 144, Address: "testAddr3", }) - assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) - subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}) + subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs60, 1) - subs714, err := database.GetSubscriptionData(714, []string{"testAddr2"}) + subs714, err := database.GetSubscriptionData(714, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs714, 1) - subs144, err := database.GetSubscriptionData(144, []string{"testAddr3"}) + subs144, err := database.GetSubscriptionData(144, []string{"testAddr3"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs144, 1) - assert.Nil(t, database.DeleteAllSubscriptions(1)) + assert.Nil(t, database.DeleteAllSubscriptions(1, context.Background())) - subs60, err = database.GetSubscriptionData(60, []string{"testAddr"}) + subs60, err = database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs60, 0) - subs714, err = database.GetSubscriptionData(714, []string{"testAddr2"}) + subs714, err = database.GetSubscriptionData(714, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs714, 0) - subs144, err = database.GetSubscriptionData(144, []string{"testAddr3"}) + subs144, err = database.GetSubscriptionData(144, []string{"testAddr3"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs144, 0) - assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) - subs60, err = database.GetSubscriptionData(60, []string{"testAddr"}) + subs60, err = database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs60, 1) } @@ -394,9 +395,9 @@ func TestDb_DuplicateEntries(t *testing.T) { }) } - assert.Nil(t, database.AddSubscriptions(id, subscriptions)) + assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) - subs, err := database.GetSubscriptionData(60, []string{"testAddr"}) + subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) @@ -413,13 +414,13 @@ func TestDb_FindSubscriptions_Multiple(t *testing.T) { for i := 1; i < 6; i++ { subscriptions[0].SubscriptionId = uint(i) - assert.Nil(t, database.AddSubscriptions(uint(i), subscriptions)) + assert.Nil(t, database.AddSubscriptions(uint(i), subscriptions, context.Background())) } subscriptions[0].SubscriptionId = uint(1) - assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions)) + assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) - subs, err := database.GetSubscriptionData(60, []string{"testAddr"}) + subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 5, len(subs)) @@ -437,16 +438,16 @@ func TestDb_AddToExisting(t *testing.T) { }) subscriptions[0].SubscriptionId = uint(1) - assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions)) + assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) - subs, err := database.GetSubscriptionData(60, []string{"testAddr"}) + subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(subs)) assert.Equal(t, uint(1), subs[0].SubscriptionId) assert.Nil(t, database.AddToExistingSubscription(uint(1), subscriptions)) - subs2, err2 := database.GetSubscriptionData(60, []string{"testAddr"}) + subs2, err2 := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err2) assert.Equal(t, 1, len(subs2)) @@ -471,8 +472,8 @@ func TestDb_UpdatedAt(t *testing.T) { }) subscriptions[0].SubscriptionId = uint(1) - assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions)) - subs, err := database.GetSubscriptionData(60, []string{"testAddr"}) + assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) + subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(subs)) @@ -488,7 +489,7 @@ func TestDb_UpdatedAt(t *testing.T) { Address: "newtestAddr", }) - assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions)) + assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) time.Sleep(time.Second) diff --git a/tests/integration/db_test/tracker_test.go b/tests/integration/db_test/tracker_test.go index 4e63587a9..5ba03bcda 100644 --- a/tests/integration/db_test/tracker_test.go +++ b/tests/integration/db_test/tracker_test.go @@ -3,6 +3,7 @@ package db_test import ( + "context" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/tests/integration/setup" "testing" @@ -11,15 +12,15 @@ import ( func TestDb_SetBlock(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 0)) + assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 0, context.Background())) - block, err := database.GetLastParsedBlockNumber("ethereum") + block, err := database.GetLastParsedBlockNumber("ethereum", context.Background()) assert.Nil(t, err) assert.Equal(t, block, int64(0)) - assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 110)) + assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 110, context.Background())) - newBlock, err := database.GetLastParsedBlockNumber("ethereum") + newBlock, err := database.GetLastParsedBlockNumber("ethereum", context.Background()) assert.Nil(t, err) assert.Equal(t, newBlock, int64(110)) } diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index aeaf88fd7..29cce3ab3 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -25,7 +25,7 @@ var ( func TestFullFlow(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 60, Address: "testAddress", SubscriptionId: 1}}) + err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 60, Address: "testAddress", SubscriptionId: 1}}, context.Background()) assert.Nil(t, err) ctx, cancel := context.WithCancel(context.Background()) diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index 4737b8b32..0f6a1abe9 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -44,7 +44,7 @@ var ( func TestNotifier(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", SubscriptionId: 1}}) + err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", SubscriptionId: 1}}, context.Background()) assert.Nil(t, err) err = produceTxs(txs) diff --git a/tests/integration/observer_test/subscriber_test.go b/tests/integration/observer_test/subscriber_test.go index 94cd29db0..b7e9ac166 100644 --- a/tests/integration/observer_test/subscriber_test.go +++ b/tests/integration/observer_test/subscriber_test.go @@ -57,7 +57,7 @@ func TestSubscriberAddSubscription(t *testing.T) { } for _, wanted := range wantedEvents { - result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}) + result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}, context.Background()) assert.Nil(t, err) assert.Equal(t, result[0].SubscriptionId, wanted.Id) assert.Equal(t, result[0].Coin, wanted.Coin) @@ -94,16 +94,16 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { database.AddSubscriptions(10, []models.SubscriptionData{ {Coin: 61, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 10}, - }) + }, context.Background()) database.AddSubscriptions(1, []models.SubscriptionData{ {Coin: 62, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 1}, - }) + }, context.Background()) database.AddSubscriptions(2, []models.SubscriptionData{ {Coin: 63, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 2}, - }) + }, context.Background()) database.AddSubscriptions(3, []models.SubscriptionData{ {Coin: 64, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 3}, - }) + }, context.Background()) for _, event := range givenEvents { body, err := json.Marshal(event) @@ -120,7 +120,7 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { } for _, wanted := range wantedEvents { - result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}) + result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}, context.Background()) assert.Nil(t, err) assert.Equal(t, result[0].SubscriptionId, wanted.Id) assert.Equal(t, result[0].Coin, wanted.Coin) @@ -128,19 +128,19 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { } - abs61, err := database.GetSubscriptionData(61, []string{"0x0000000000000000000000000000000000000000"}) + abs61, err := database.GetSubscriptionData(61, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) assert.Len(t, abs61, 0) - abs62, err := database.GetSubscriptionData(62, []string{"0x0000000000000000000000000000000000000000"}) + abs62, err := database.GetSubscriptionData(62, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) assert.Len(t, abs62, 0) - abs63, err := database.GetSubscriptionData(63, []string{"0x0000000000000000000000000000000000000000"}) + abs63, err := database.GetSubscriptionData(63, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) assert.Len(t, abs63, 0) - abs64, err := database.GetSubscriptionData(64, []string{"0x0000000000000000000000000000000000000000"}) + abs64, err := database.GetSubscriptionData(64, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) assert.Len(t, abs64, 0) } diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go index c52eb76bc..63ee3aa68 100644 --- a/tests/integration/setup/postgres.go +++ b/tests/integration/setup/postgres.go @@ -39,7 +39,7 @@ func runPgContainerAndInitConnection() (*db.Instance, error) { err error ) if err := pool.Retry(func() error { - dbConn, err = db.New(uri) + dbConn, err = db.New(uri, "test") return err }); err != nil { return nil, err From b57a4b0de31a598372a6f0f566840d08d973ed87 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sun, 17 May 2020 09:53:09 +0300 Subject: [PATCH 300/506] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aca802ef5..ebe256e94 100644 --- a/README.md +++ b/README.md @@ -149,11 +149,16 @@ By default starting any of the [services](#architecture) will enable all platfor To run a specific service only by passing environmental variable, e.g: `platfrom_api` : ```shell ATLAS_PLATFORM=ethereum go run cmd/platform_api/main.go + +ATLAS_PLATFORM=ethereum binance bitcoin go run cmd/platform_api/main.go # for multiple platforms ``` or change in config file ```yaml -platform: ethereum +# Single +platform: [ethereum] +# Multiple +platform: [ethereum, binance, bitcoin] ``` This way you can one platform per binary, for scalability and sustainability. From 7495506f457ca99737e94fa365a529443ff58128 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Tue, 19 May 2020 02:23:37 +0300 Subject: [PATCH 301/506] Add apm http for requests (#1105) --- go.mod | 1 + pkg/blockatlas/client.go | 30 ++++++++++++++++++++++++++---- pkg/blockatlas/clientcache.go | 31 +++++++++++++++++++++++++++++++ pkg/blockatlas/jsonrpc.go | 27 +++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 20b1ccd59..443ac6020 100644 --- a/go.mod +++ b/go.mod @@ -40,6 +40,7 @@ require ( go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmgorm v1.8.0 + go.elastic.co/apm/module/apmhttp v1.8.0 go.elastic.co/apm/module/apmlogrus v1.8.0 go.elastic.co/fastjson v1.1.0 // indirect go.uber.org/atomic v1.6.0 diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go index fd285e758..f3b3e2c3f 100644 --- a/pkg/blockatlas/client.go +++ b/pkg/blockatlas/client.go @@ -2,8 +2,10 @@ package blockatlas import ( "bytes" + "context" "encoding/json" "fmt" + "go.elastic.co/apm/module/apmhttp" "io" "io/ioutil" "net/http" @@ -55,13 +57,22 @@ var DefaultErrorHandler = func(res *http.Response, uri string) error { return nil } +func (r *Request) GetWithContext(result interface{}, path string, query url.Values, ctx context.Context) error { + var queryStr = "" + if query != nil { + queryStr = query.Encode() + } + uri := strings.Join([]string{r.GetBase(path), queryStr}, "?") + return r.Execute("GET", uri, nil, result, ctx) +} + func (r *Request) Get(result interface{}, path string, query url.Values) error { var queryStr = "" if query != nil { queryStr = query.Encode() } uri := strings.Join([]string{r.GetBase(path), queryStr}, "?") - return r.Execute("GET", uri, nil, result) + return r.Execute("GET", uri, nil, result, context.Background()) } func (r *Request) Post(result interface{}, path string, body interface{}) error { @@ -70,10 +81,19 @@ func (r *Request) Post(result interface{}, path string, body interface{}) error return err } uri := r.GetBase(path) - return r.Execute("POST", uri, buf, result) + return r.Execute("POST", uri, buf, result, context.Background()) } -func (r *Request) Execute(method string, url string, body io.Reader, result interface{}) error { +func (r *Request) PostWithContext(result interface{}, path string, body interface{}, ctx context.Context) error { + buf, err := GetBody(body) + if err != nil { + return err + } + uri := r.GetBase(path) + return r.Execute("POST", uri, buf, result, ctx) +} + +func (r *Request) Execute(method string, url string, body io.Reader, result interface{}, ctx context.Context) error { req, err := http.NewRequest(method, url, body) if err != nil { return errors.E(err, errors.TypePlatformRequest) @@ -83,7 +103,9 @@ func (r *Request) Execute(method string, url string, body io.Reader, result inte req.Header.Set(key, value) } - res, err := r.HttpClient.Do(req) + c := apmhttp.WrapClient(r.HttpClient) + + res, err := c.Do(req.WithContext(ctx)) if err != nil { return errors.E(err, errors.TypePlatformRequest) } diff --git a/pkg/blockatlas/clientcache.go b/pkg/blockatlas/clientcache.go index a6e511609..670196dd0 100644 --- a/pkg/blockatlas/clientcache.go +++ b/pkg/blockatlas/clientcache.go @@ -1,6 +1,7 @@ package blockatlas import ( + "context" "crypto/sha1" "encoding/base64" "encoding/json" @@ -41,6 +42,21 @@ func (r *Request) PostWithCache(result interface{}, path string, body interface{ return err } +func (r *Request) PostWithCacheAndContext(result interface{}, path string, body interface{}, cache time.Duration, ctx context.Context) error { + key := r.generateKey(path, nil, body) + err := memoryCache.getCache(key, result) + if err == nil { + return nil + } + + err = r.PostWithContext(result, path, body, ctx) + if err != nil { + return err + } + memoryCache.setCache(key, result, cache) + return err +} + func (r *Request) GetWithCache(result interface{}, path string, query url.Values, cache time.Duration) error { key := r.generateKey(path, query, nil) err := memoryCache.getCache(key, result) @@ -56,6 +72,21 @@ func (r *Request) GetWithCache(result interface{}, path string, query url.Values return err } +func (r *Request) GetWithCacheAndContext(result interface{}, path string, query url.Values, cache time.Duration, ctx context.Context) error { + key := r.generateKey(path, query, nil) + err := memoryCache.getCache(key, result) + if err == nil { + return nil + } + + err = r.Get(result, path, query) + if err != nil { + return err + } + memoryCache.setCache(key, result, cache) + return err +} + //nolint func (mc *memCache) deleteCache(key string) { mc.RLock() diff --git a/pkg/blockatlas/jsonrpc.go b/pkg/blockatlas/jsonrpc.go index fd5968d13..0f2d79e7d 100644 --- a/pkg/blockatlas/jsonrpc.go +++ b/pkg/blockatlas/jsonrpc.go @@ -1,6 +1,7 @@ package blockatlas import ( + "context" "encoding/json" "github.com/trustwallet/blockatlas/pkg/errors" @@ -67,6 +68,32 @@ func (r *Request) RpcCall(result interface{}, method string, params interface{}) return resp.GetObject(result) } +func (r *Request) RpcCallWithContext(result interface{}, method string, params interface{}, ctx context.Context) error { + + req := &RpcRequest{JsonRpc: JsonRpcVersion, Method: method, Params: params, Id: genId()} + var resp *RpcResponse + err := r.PostWithContext(&resp, "", req, ctx) + if err != nil { + return err + } + if resp.Error != nil { + return errors.E("RPC Call error", errors.Params{ + "method": method, + "error_code": resp.Error.Code, + "error_message": resp.Error.Message}) + } + return resp.GetObject(result) +} + +func (r *Request) RpcBatchCallWithContext(requests RpcRequests, ctx context.Context) ([]RpcResponse, error) { + var resp []RpcResponse + err := r.PostWithContext(&resp, "", requests.fillDefaultValues(), ctx) + if err != nil { + return nil, err + } + return resp, nil +} + func (r *Request) RpcBatchCall(requests RpcRequests) ([]RpcResponse, error) { var resp []RpcResponse err := r.Post(&resp, "", requests.fillDefaultValues()) From 0834e4d71555e685f27ffa21892c722c9f9d7ca3 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Wed, 20 May 2020 00:40:50 +0200 Subject: [PATCH 302/506] Fix DecimalToSatoshis for 0 input. (#1110) * Fix DecimalToSatoshis for 0 input. * Fix sporadic Nimiq unit test, issue #1111. * Handle empty string input as error. * Cosmos delegator can have empty value, allow it. Co-authored-by: Catenocrypt --- pkg/numbers/amount_test.go | 4 ++-- pkg/numbers/decimal.go | 12 ++++++++++-- pkg/numbers/decimal_test.go | 23 ++++++++++++++++++++++- platform/cosmos/transaction.go | 10 +++++++--- platform/nimiq/transaction_test.go | 8 +++++++- 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/pkg/numbers/amount_test.go b/pkg/numbers/amount_test.go index 5b95462d5..8db856bcb 100644 --- a/pkg/numbers/amount_test.go +++ b/pkg/numbers/amount_test.go @@ -33,7 +33,7 @@ func Test_addAmount(t *testing.T) { } } -func Test_decimalToSatoshis(t *testing.T) { +func Test_ToSatoshi(t *testing.T) { tests := []struct { name string amount string @@ -47,7 +47,7 @@ func Test_decimalToSatoshis(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := ToSatoshi(tt.amount); got != tt.want { - t.Errorf("decimalToSatoshis() = %v, want %v", got, tt.want) + t.Errorf("ToSatoshi() = %v, want %v", got, tt.want) } }) } diff --git a/pkg/numbers/decimal.go b/pkg/numbers/decimal.go index 667470aac..72e40ef4f 100644 --- a/pkg/numbers/decimal.go +++ b/pkg/numbers/decimal.go @@ -11,8 +11,16 @@ import ( // "12.345" => "12345" // "0.0230" => "230" func DecimalToSatoshis(dec string) (string, error) { - out := strings.Replace(dec, ".", "", 1) - out = strings.TrimLeft(out, "0") + out := strings.TrimLeft(dec, " ") + out = strings.TrimRight(out, " ") + out = strings.Replace(out, ".", "", 1) + // trim left 0's but keep last + if l := len(out); l >= 2 { + out = strings.TrimLeft(out[:l-1], "0") + out[l-1:l] + } + if len(out) == 0 { + return "", errors.E("Invalid empty input", errors.Params{"dec": dec, "dec_trimmed": out}) + } for _, c := range out { if !unicode.IsNumber(c) { return "", errors.E("not a number", errors.Params{"dec": dec, "c": c}) diff --git a/pkg/numbers/decimal_test.go b/pkg/numbers/decimal_test.go index 2cfcc29e7..89c3c3765 100644 --- a/pkg/numbers/decimal_test.go +++ b/pkg/numbers/decimal_test.go @@ -9,14 +9,35 @@ func TestDecimalToSatoshis(t *testing.T) { t.Error(err) } if expected != actual { - t.Errorf("expected: %s, got %s", expected, actual) + t.Errorf("expected %s, got %s, input %s", expected, actual, input) + } + } + + assertSatError := func(input string) { + actual, err := DecimalToSatoshis(input) + if err == nil { + t.Errorf("Expected error but no error: got %s, input %s", actual, input) } } assertSatEquals("10", "1.0") assertSatEquals("1", "0.1") assertSatEquals("13602", "136.02") + assertSatEquals("13602", "0136.02") assertSatEquals("1500000", "0.01500000") + assertSatEquals("0", "0") + assertSatEquals("2030", "0.002030") + assertSatEquals("101010", "0101010") + assertSatEquals("11001100", "0011001100") + assertSatEquals("376", " 376") + assertSatEquals("376", "376 ") + + assertSatError("12NotNumber34") + assertSatError("12,34") + assertSatError("") + assertSatError(" ") + assertSatError("37 6") + assertSatError("37,6") } func TestDecimalExp(t *testing.T) { diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 5a08c1fc0..3de7d5ffb 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -146,9 +146,13 @@ func (p *Platform) fillTransfer(tx *blockatlas.Tx, transfer MessageValueTransfer } func (p *Platform) fillDelegate(tx *blockatlas.Tx, delegate MessageValueDelegate, events Events, msgType TxType) { - value, err := numbers.DecimalToSatoshis(delegate.Amount.Quantity) - if err != nil { - return + value := "" + if len(delegate.Amount.Quantity) > 0 { + var err error + value, err = numbers.DecimalToSatoshis(delegate.Amount.Quantity) + if err != nil { + return + } } tx.From = delegate.DelegatorAddr tx.To = delegate.ValidatorAddr diff --git a/platform/nimiq/transaction_test.go b/platform/nimiq/transaction_test.go index 8c0a5f0f6..f936434ce 100644 --- a/platform/nimiq/transaction_test.go +++ b/platform/nimiq/transaction_test.go @@ -6,6 +6,7 @@ import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "io/ioutil" + "math" "path/filepath" "runtime" "sort" @@ -68,7 +69,7 @@ var ( From: "NQ74 SJ0Q 49T1 4XQL KABH 1RUC 8DPT 9F0U 9P0B", To: "NQ97 18BJ 33YV QGHQ BV2K 56V4 12CH J8TD S9S3", Fee: "300", - Date: time.Now().Unix(), + Date: 666666, // special placholder value Block: 0, Meta: blockatlas.Transfer{ Value: "100000", @@ -79,6 +80,7 @@ var ( ) func TestNormalizeTx1(t *testing.T) { + now := time.Now().Unix() tests := []struct { name string srcTx string @@ -96,6 +98,10 @@ func TestNormalizeTx1(t *testing.T) { return } got := NormalizeTx(&srcTx) + // special handling for current date, if around now, replace with special value + if math.Abs(float64(got.Date - now)) < 30 { + got.Date = 666666 + } assert.Equal(t, tt.want, got) }) } From c8bd8fbff78de2abf04dd19a4d478cb93d73fea3 Mon Sep 17 00:00:00 2001 From: coolcottontail <50373379+coolcottontail@users.noreply.github.com> Date: Wed, 20 May 2020 02:57:25 -0700 Subject: [PATCH 303/506] Add harmony staking support in mainnet (#1099) * updated all staking using mainnet * udpated staking test to use 7 epochs for lock time * updated the minimal staking to 1000 * updated the minimal staking to 1000 * added more staking tests * added more staking tests * added getValidator and getDelegator tests * increase test coverage --- platform/harmony/client.go | 43 +++++- platform/harmony/model.go | 28 ++++ platform/harmony/stake.go | 123 +++++++++++++++ platform/harmony/stake_test.go | 257 ++++++++++++++++++++++++++++++++ platform/harmony/transaction.go | 2 + 5 files changed, 452 insertions(+), 1 deletion(-) create mode 100644 platform/harmony/stake.go create mode 100644 platform/harmony/stake_test.go diff --git a/platform/harmony/client.go b/platform/harmony/client.go index 67f48c6b6..70de06a87 100644 --- a/platform/harmony/client.go +++ b/platform/harmony/client.go @@ -2,9 +2,11 @@ package harmony import ( "fmt" + "strconv" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" - "strconv" ) type Client struct { @@ -41,6 +43,40 @@ func (c *Client) GetBlockByNumber(num int64) (info BlockInfo, err error) { return } + +func (c *Client) GetValidators() (validators Validators, err error) { + err = rpcCallStub(c, &validators.Validators, "hmy_getAllValidatorInformation", []interface{}{-1}) + + if err != nil { + logger.Error(err, "Harmony: Failed to get all validator addresses") + } + + return +} + +func (c *Client) GetDelegations(address string) (delegations Delegations, err error) { + err = rpcCallStub(c, &delegations.List, "hmy_getDelegationsByDelegator", []interface{}{address}) + + if err != nil { + logger.Error(err, "Harmony: Failed to get delegations for address") + } + return +} + +func (c *Client) GetBalance(address string) (string, error) { + var result string + err := rpcCallStub(c, &result, "hmy_getBalance", []interface{}{address, "latest"}) + + if err != nil { + return "0", err + } + balance, err := numbers.HexToDecimal(result) + if err != nil { + return "0", err + } + return balance, nil +} + func hexToInt(hex string) (uint64, error) { nonceStr, err := numbers.HexToDecimal(hex) if err != nil { @@ -48,3 +84,8 @@ func hexToInt(hex string) (uint64, error) { } return strconv.ParseUint(nonceStr, 10, 64) } + +// rpcCallStub is can be overwritten by the unit test +var rpcCallStub = func (c *Client, result interface{}, method string, params interface{}) error { + return c.RpcCall(result, method, params) +} diff --git a/platform/harmony/model.go b/platform/harmony/model.go index a4134e22c..698465edb 100644 --- a/platform/harmony/model.go +++ b/platform/harmony/model.go @@ -26,3 +26,31 @@ type BlockInfo struct { Number string `json:"number"` Transactions []Transaction `json:"transactions"` } + +type ValidatorInfo struct { + Address string `json:"address"` +} + +type LifetimeInfo struct { + Apr string `json:"apr"` +} + +type Validator struct { + Info ValidatorInfo `json:"validator"` + Active bool `json:"currently-in-committee"` + Lifetime LifetimeInfo `json:"lifetime"` +} + +type Validators struct { + Validators []Validator `json:"result"` +} + +type Delegation struct { + DelegatorAddress string `json:"delegator_address"` + ValidatorAddress string `json:"validator_address"` + Amount float64 `json:"amount"` +} + +type Delegations struct { + List []Delegation `json:"result"` +} diff --git a/platform/harmony/stake.go b/platform/harmony/stake.go new file mode 100644 index 000000000..706465465 --- /dev/null +++ b/platform/harmony/stake.go @@ -0,0 +1,123 @@ +package harmony + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/logger" + services "github.com/trustwallet/blockatlas/services/assets" + "math/big" + "strconv" +) + +const ( + lockTime = 604800 // in seconds (7 epochs or 7 days) +) + +func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { + results := make(blockatlas.ValidatorPage, 0) + validators, err := p.client.GetValidators() + if err != nil { + return results, err + } + + for _, v := range validators.Validators { + var apr float64 + if apr, err = strconv.ParseFloat(v.Lifetime.Apr, 64); err != nil { + apr = 0 + } + results = append(results, normalizeValidator(v, apr)) + } + + return results, nil +} + +func (p *Platform) GetDetails() blockatlas.StakingDetails { + apr := p.GetMaxAPR() + return getDetails(apr) +} + +func (p *Platform) GetMaxAPR() float64 { + validators, err := p.client.GetValidators() + if err != nil { + logger.Error("GetMaxAPR", logger.Params{"details": err, "platform": p.Coin().Symbol}) + return Annual + } + + var max = 0.0 + for _, e := range validators.Validators { + var apr float64 + if apr, err = strconv.ParseFloat(e.Lifetime.Apr, 64); err != nil { + apr = 0.0 + } + + if apr > max { + max = apr + } + } + + return max +} + +func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + delegations, err := p.client.GetDelegations(address) + if err != nil { + return nil, err + } + + validators, err := services.GetValidatorsMap(p) + if err != nil { + return nil, err + } + + return NormalizeDelegations(delegations.List, validators), nil +} + +func (p *Platform) UndelegatedBalance(address string) (string, error) { + balance, err := p.client.GetBalance(address) + if err != nil { + return "0", err + } + return balance, nil +} + +func NormalizeDelegations(delegations []Delegation, validators blockatlas.ValidatorMap) []blockatlas.Delegation { + results := make([]blockatlas.Delegation, 0) + for _, v := range delegations { + validator, ok := validators[v.ValidatorAddress] + if !ok { + logger.Error(errors.E("Validator not found", errors.Params{"address": v.ValidatorAddress, "platform": "harmony", "delegation": v.DelegatorAddress})) + continue + } + + bigval := new(big.Float) + bigval.SetFloat64(v.Amount) + + result := new(big.Int) + bigval.Int(result) // store converted number in result + + delegation := blockatlas.Delegation{ + Delegator: validator, + Value: result.String(), // v.Amount.String(), + Status: blockatlas.DelegationStatusActive, + } + results = append(results, delegation) + } + return results +} + +func getDetails(apr float64) blockatlas.StakingDetails { + return blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: apr}, + MinimumAmount: blockatlas.Amount("1000"), + LockTime: lockTime, + Type: blockatlas.DelegationTypeDelegate, + } +} + +func normalizeValidator(v Validator, apr float64) (validator blockatlas.Validator) { + return blockatlas.Validator{ + Status: v.Active, + ID: v.Info.Address, + Details: getDetails(apr), + } +} diff --git a/platform/harmony/stake_test.go b/platform/harmony/stake_test.go new file mode 100644 index 000000000..202672be9 --- /dev/null +++ b/platform/harmony/stake_test.go @@ -0,0 +1,257 @@ +package harmony + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "strconv" + "testing" +) + +const validatorSrc = ` + { + "validator": { + "bls-public-keys": [ + "29fb5d202e2f6f7955b425dc706fc0b29047067e51ba583fbb017c0f51186d5e1eaf6dd4059848be311ab5a49d625309" + ], + "last-epoch-in-committee": 18, + "min-self-delegation": 10999000000000000000000, + "max-total-delegation": 100000000000000000000000000, + "rate": "0.100000000000000000", + "max-rate": "0.100000000000000000", + "max-change-rate": "0.100000000000000000", + "update-height": 88, + "name": "sieemma node", + "identity": "sieemma node by ankr", + "website": "www.ankr.com", + "security-contact": "info@ankr.com", + "details": "This validator is launched from app.ankr.com", + "creation-height": 88, + "address": "one1v8pukmelacy3xdap773rpg5pax3tmu40wmwr2j", + "delegations": [ + { + "delegator-address": "one1v8pukmelacy3xdap773rpg5pax3tmu40wmwr2j", + "amount": 10999000000000000000000, + "reward": 2328233463148225437028, + "undelegations": [] + } + ] + }, + "current-epoch-performance": { + "current-epoch-signing-percent": { + "current-epoch-signed": 3, + "current-epoch-to-sign": 3, + "num-beacon-blocks-until-next-epoch": 37, + "current-epoch-signing-percentage": "1.000000000000000000" + } + }, + "metrics": { + "by-bls-key": [ + { + "key": { + "bls-public-key": "29fb5d202e2f6f7955b425dc706fc0b29047067e51ba583fbb017c0f51186d5e1eaf6dd4059848be311ab5a49d625309", + "group-percent": "0.056856187290969900", + "effective-stake": "85000000000000000000000.000000000000000000", + "earning-account": "one1v8pukmelacy3xdap773rpg5pax3tmu40wmwr2j", + "overall-percent": "0.018193979933110368", + "shard-id": 1 + }, + "earned-reward": 4478494623655913952 + } + ] + }, + "total-delegation": 10999000000000000000000, + "currently-in-committee": true, + "epos-status": "currently elected", + "epos-winning-stake": "85000000000000000000000.000000000000000000", + "booted-status": null, + "lifetime": { + "reward-accumulated": 2328233463148225437028, + "blocks": { + "to-sign": 525, + "signed": 504 + }, + "apr": "12.345" + } +}` + +const delegationsSrc = ` +[ + { + "validator_address": "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", + "delegator_address": "one1pf75h0t4am90z8uv3y0dgunfqp4lj8wr3t5rsp", + "amount": 12345678900000000000, + "reward": 15854399877248931866418, + "Undelegations": [] + } +]` + +func TestNormalizeValidator(t *testing.T) { + var v Validator + _ = json.Unmarshal([]byte(validatorSrc), &v) + expected := blockatlas.Validator{ + Status: v.Active, + ID: v.Info.Address, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 12.345}, + LockTime: lockTime, + MinimumAmount: "1000", + Type: blockatlas.DelegationTypeDelegate, + }, + } + + var apr float64 + var err error + if apr, err = strconv.ParseFloat(v.Lifetime.Apr,64); err != nil { + apr = 0 + } + + result := normalizeValidator(v, apr) + assert.Equal(t, expected, result) +} + +var validator1 = blockatlas.StakeValidator{ + ID: "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "Harmony One", + Description: "Stake and earn rewards with the most secure and stable validator. Operated by Harmony One Inc.", + Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/harmony/validators/assets/one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy/logo.png", + Website: "https://harmony.one", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 10, + }, + LockTime: 0, + MinimumAmount: "0", + }, +} + +var validatorMap = blockatlas.ValidatorMap{ + "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy": validator1, +} + +func TestNormalizeDelegations(t *testing.T) { + var delegations []Delegation + err := json.Unmarshal([]byte(delegationsSrc), &delegations) + assert.NoError(t, err) + assert.NotNil(t, delegations) + + expected := []blockatlas.Delegation{ + { + Delegator: validator1, + Value: "12345678900000000000", + Status: blockatlas.DelegationStatusActive, + }, + } + result := NormalizeDelegations(delegations, validatorMap) + assert.Equal(t, expected, result) +} + +func TestHexToInt(t *testing.T) { + result, _ := hexToInt("0x604800") + + assert.Equal(t,uint64(6309888), result) +} + +func TestGetDetails(t *testing.T) { + var expected = blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 10}, + LockTime: lockTime, + MinimumAmount: "1000", + Type: blockatlas.DelegationTypeDelegate, + } + + result := getDetails(10) + assert.Equal(t,expected, result) +} + + +func TestGetValidators(t *testing.T) { + var c Client + + p := Platform{ + client: c, + } + + var validators = []Validator{ + Validator{ + Info: ValidatorInfo{ + Address: "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", + }, + Active: true, + Lifetime: LifetimeInfo{Apr: "10"}, + }, + } + + rpcCallStub = func (c *Client, result interface{}, method string, params interface{}) error { + jsonData, _ := json.Marshal(validators) + _ = json.Unmarshal(jsonData, result) + return nil + } + + result, _ := p.GetValidators() + assert.Equal(t, lockTime, result[0].Details.LockTime) + assert.Equal(t, float64(10), result[0].Details.Reward.Annual) +} + +func TestGetDelegation(t *testing.T) { + var c Client + + p := Platform{ + client: c, + } + + var delegations = []Delegation{ + Delegation{ + DelegatorAddress: "one1a0au0p33zrns49h3qw7prn02s4wphu0ggcqrhm", + ValidatorAddress: "one1a0au0p33zrns49h3qw7prn02s4wphu0ggcqrhm", + Amount: 100, + }, + } + + var validators = []Validator{ + Validator{ + Info: ValidatorInfo{ + Address: "one1a0au0p33zrns49h3qw7prn02s4wphu0ggcqrhm", + }, + Active: true, + Lifetime: LifetimeInfo{Apr: "10"}, + }, + } + + rpcCallStub = func (c *Client, result interface{}, method string, params interface{}) error { + if (method == "hmy_getAllValidatorInformation") { + jsonData, _ := json.Marshal(validators) + _ = json.Unmarshal(jsonData, result) + } else { + jsonData, _ := json.Marshal(delegations) + _ = json.Unmarshal(jsonData, result) + } + return nil + } + + result, _ := p.GetDelegations("one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy") + assert.Equal(t, delegations[0].DelegatorAddress, result[0].Delegator.ID) +} + + +func TestGeBalance(t *testing.T) { + var c Client + + p := Platform{ + client: c, + } + + var balance = "0x100" + + rpcCallStub = func (c *Client, result interface{}, method string, params interface{}) error { + jsonData, _ := json.Marshal(balance) + _ = json.Unmarshal(jsonData, result) + return nil + } + + result, _ := p.UndelegatedBalance("one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy") + assert.Equal(t, "256",result) +} diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index 890b5b436..920ed2cba 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -8,6 +8,8 @@ import ( "strconv" ) +const Annual = 10 + func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { result, err := p.client.GetTxsOfAddress(address) if err != nil { From 2e15e3296d76bee454a1a10a77155d3cfd326a4f Mon Sep 17 00:00:00 2001 From: Iuga Mihai <50499646+miiu96@users.noreply.github.com> Date: Wed, 20 May 2020 13:11:23 +0300 Subject: [PATCH 304/506] Elrond initial implementation (#1109) * integrate elrond * increase code coverage --- README.md | 1 + coin/coins.go | 16 ++- coin/coins.yml | 8 ++ config.yml | 3 + platform/elrond/base.go | 22 ++++ platform/elrond/block.go | 11 ++ platform/elrond/client.go | 58 ++++++++++ platform/elrond/model.go | 69 ++++++++++++ platform/elrond/transaction.go | 54 +++++++++ platform/elrond/transaction_test.go | 169 ++++++++++++++++++++++++++++ platform/platform.go | 2 + 11 files changed, 412 insertions(+), 1 deletion(-) create mode 100644 platform/elrond/base.go create mode 100644 platform/elrond/block.go create mode 100644 platform/elrond/client.go create mode 100644 platform/elrond/model.go create mode 100644 platform/elrond/transaction.go create mode 100644 platform/elrond/transaction_test.go diff --git a/README.md b/README.md index ebe256e94..c255a8eea 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ The observer API watches the chain for new transactions and generates notificati + ## Architecture diff --git a/coin/coins.go b/coin/coins.go index 88e22e63b..9fa098e0e 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2020-05-15 00:06:57.247245 +0300 MSK m=+0.001827650 +// 2020-05-18 14:17:38.050930018 +0300 EEST m=+0.001659149 // using data from coins.yml package coin @@ -73,6 +73,7 @@ const ( KSM = 434 SOL = 501 NEAR = 397 + ERD = 508 ) var Coins = map[uint]Coin{ @@ -556,6 +557,16 @@ var Coins = map[uint]Coin{ MinConfirmations: 0, SampleAddr: "NEAR6Y66fCzeKqWiwxoPox5oGeDN9VhNCu7CEQ9M86iniqoN9vg2X", }, + ERD: { + ID: 508, + Handle: "elrond", + Symbol: "ERD", + Name: "Elrond", + Decimals: 18, + BlockTime: 6000, + MinConfirmations: 0, + SampleAddr: "erd12tqtt5zcg6vpw65y4hkanvt49kzq695sr3ctuszjy92xw0ppzcssy2xd5r", + }, } func Ethereum() Coin { return Coins[ETH] @@ -701,4 +712,7 @@ func Solana() Coin { func Near() Coin { return Coins[NEAR] } +func Elrond() Coin { + return Coins[ERD] +} diff --git a/coin/coins.yml b/coin/coins.yml index f1bc5b992..05c583b12 100644 --- a/coin/coins.yml +++ b/coin/coins.yml @@ -380,3 +380,11 @@ decimals: 18 blockTime: 2000 sampleAddress: 'NEAR6Y66fCzeKqWiwxoPox5oGeDN9VhNCu7CEQ9M86iniqoN9vg2X' + +- id: 508 + symbol: ERD + handle: elrond + name: Elrond + decimals: 18 + blockTime: 6000 + sampleAddress: 'erd12tqtt5zcg6vpw65y4hkanvt49kzq695sr3ctuszjy92xw0ppzcssy2xd5r' diff --git a/config.yml b/config.yml index f0f6a875b..61a8b41c8 100644 --- a/config.yml +++ b/config.yml @@ -217,3 +217,6 @@ solana: near: api: https://staging-rpc.nearprotocol.com + +elrond: + api: https://api.elrond.com diff --git a/platform/elrond/base.go b/platform/elrond/base.go new file mode 100644 index 000000000..ac154eba1 --- /dev/null +++ b/platform/elrond/base.go @@ -0,0 +1,22 @@ +package elrond + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client + CoinIndex uint +} + +func Init(coin uint, api string) *Platform { + return &Platform{ + CoinIndex: coin, + client: Client{blockatlas.InitJSONClient(api)}, + } +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[p.CoinIndex] +} diff --git a/platform/elrond/block.go b/platform/elrond/block.go new file mode 100644 index 000000000..65ed53ff3 --- /dev/null +++ b/platform/elrond/block.go @@ -0,0 +1,11 @@ +package elrond + +import "github.com/trustwallet/blockatlas/pkg/blockatlas" + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.CurrentBlockNumber() +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + return p.client.GetBlockByNumber(num) +} diff --git a/platform/elrond/client.go b/platform/elrond/client.go new file mode 100644 index 000000000..10405557b --- /dev/null +++ b/platform/elrond/client.go @@ -0,0 +1,58 @@ +package elrond + +import ( + "fmt" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Client struct { + blockatlas.Request +} + +func (c *Client) CurrentBlockNumber() (num int64, err error) { + var networkStatus NetworkStatus + path := fmt.Sprintf("network/status/%s", metachainID) + err = c.Get(&networkStatus, path, nil) + if err != nil { + return 0, err + } + + latestNonce := networkStatus.NetworkStatus.Status.Nonce + + return int64(latestNonce), nil +} + +func (c *Client) GetBlockByNumber(height int64) (*blockatlas.Block, error) { + var blockRes BlockResponse + + path := fmt.Sprintf("block/%s/%d", metachainID, uint64(height)) + err := c.Get(&blockRes, path, nil) + if err != nil { + return nil, err + } + + block := blockRes.Block + txs := NormalizeTxs(block.Transactions, "") + + return &blockatlas.Block{ + Number: int64(block.Nonce), + ID: block.Hash, + Txs: txs, + }, nil +} + +func (c *Client) GetTxsOfAddress(address string) (blockatlas.TxPage, error) { + var txPage TransactionsPage + // TODO: enable pagination of Elrond transactions in the future. + // TODO: currently Elrond only fetches the most recent 20 transactions. + path := fmt.Sprintf("address/%s/transactions", address) + err := c.Get(&txPage, path, nil) + if err != nil { + return nil, err + } + + txs := NormalizeTxs(txPage.Transactions, address) + + return txs, nil +} diff --git a/platform/elrond/model.go b/platform/elrond/model.go new file mode 100644 index 000000000..98fbddab3 --- /dev/null +++ b/platform/elrond/model.go @@ -0,0 +1,69 @@ +package elrond + +import ( + "time" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type NetworkStatus struct { + NetworkStatus Status `json:"message"` +} + +type Status struct { + Status StatusDetails `json:"status"` +} + +type StatusDetails struct { + Round float64 `json:"erd_current_round"` + Epoch float64 `json:"erd_epoch_number"` + Nonce float64 `json:"erd_nonce"` +} + +type BlockResponse struct { + Block Block `json:"block"` +} + +type Block struct { + Nonce uint64 `json:"nonce"` + Hash string `json:"hash"` + Transactions []Transaction `json:"transactions"` +} + +type TransactionsPage struct { + Transactions []Transaction `json:"transactions"` +} + +type Transaction struct { + Hash string `json:"hash"` + Nonce uint64 `json:"nonce"` + Value string `json:"value"` + Receiver string `json:"receiver"` + Sender string `json:"sender"` + Data string `json:"data"` + Timestamp time.Duration `json:"timestamp"` + Status string `json:"status"` + Fee string `json:"fee"` +} + +func (tx *Transaction) TxStatus() blockatlas.Status { + switch tx.Status { + case "Success": + return blockatlas.StatusCompleted + case "Pending": + return blockatlas.StatusPending + default: + return blockatlas.StatusError + } +} + +func (tx *Transaction) Direction(address string) blockatlas.Direction { + switch { + case tx.Sender == address && tx.Receiver == address: + return blockatlas.DirectionSelf + case tx.Sender == address && tx.Receiver != address: + return blockatlas.DirectionOutgoing + default: + return blockatlas.DirectionIncoming + } +} diff --git a/platform/elrond/transaction.go b/platform/elrond/transaction.go new file mode 100644 index 000000000..f56ffb995 --- /dev/null +++ b/platform/elrond/transaction.go @@ -0,0 +1,54 @@ +package elrond + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +const metachainID = "4294967295" + +func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + return p.client.GetTxsOfAddress(address) +} + +// NormalizeTx converts an slice of Elrond transaction info a slice of generic model transaction +func NormalizeTxs(srcTxs []Transaction, address string) (txs []blockatlas.Tx) { + for _, srcTx := range srcTxs { + tx, ok := NormalizeTx(srcTx, address) + if !ok { + continue + } + txs = append(txs, tx) + } + return txs +} + +// NormalizeTx converts an Elrond transaction into the generic model +func NormalizeTx(srcTx Transaction, address string) (tx blockatlas.Tx, ok bool) { + tx = blockatlas.Tx{ + ID: srcTx.Hash, + Coin: coin.Elrond().ID, + Date: int64(srcTx.Timestamp), + From: srcTx.Sender, + To: srcTx.Receiver, + Fee: blockatlas.Amount(srcTx.Fee), + Status: srcTx.TxStatus(), + Sequence: srcTx.Nonce, + Memo: srcTx.Data, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount(srcTx.Value), + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + } + if address != "" { + tx.Direction = srcTx.Direction(address) + } + + // check if transaction sender is metachain shard (protocol transaction) + if srcTx.Sender == metachainID { + tx.From = "metachain" + } + + return tx, true +} diff --git a/platform/elrond/transaction_test.go b/platform/elrond/transaction_test.go new file mode 100644 index 000000000..04c11a27c --- /dev/null +++ b/platform/elrond/transaction_test.go @@ -0,0 +1,169 @@ +package elrond + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +const userAddress = `erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0` + +const txTransferSrc1 = ` +{ + "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce":0, + "round":35462, + "value":"82516976060558456822", + "receiver":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "sender":"4294967295", + "data":"ok", + "signature":"", + "timestamp":1587715632, + "status":"Success", + "fee": "1000" +}` + +const txTransferSrc2 = ` +{ + "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce":1, + "round":100, + "value":"2000", + "receiver":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "data":"money", + "signature":"", + "timestamp":1588757256, + "status":"Pending", + "fee": "1500" +}` + +const txTransferSrc3 = ` +{ + "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce":19, + "round":200, + "value":"2", + "receiver":"erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "data":"bla bla bla", + "signature":"", + "timestamp":1588757256, + "status":"Not executed", + "fee": "5000" +}` + +var txTransfer1Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.ERD, + Date: int64(1587715632), + From: "metachain", + To: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + Fee: "1000", + Status: blockatlas.StatusCompleted, + Memo: "ok", + Sequence: 0, + Meta: blockatlas.Transfer{ + Value: "82516976060558456822", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionOutgoing, +} + +var txTransfer2Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.ERD, + Date: int64(1588757256), + From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + To: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + Fee: "1500", + Status: blockatlas.StatusPending, + Memo: "money", + Sequence: 1, + Meta: blockatlas.Transfer{ + Value: "2000", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionSelf, +} + +var txTransfer3Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.ERD, + Date: int64(1588757256), + From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + Fee: "5000", + Status: blockatlas.StatusError, + Memo: "bla bla bla", + Sequence: 19, + Meta: blockatlas.Transfer{ + Value: "2", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionOutgoing, +} + +type test struct { + name string + apiResponse string + expected *blockatlas.Tx +} + +func TestNormalize(t *testing.T) { + testNormalize(t, &test{ + name: "transferSuccess", + apiResponse: txTransferSrc1, + expected: &txTransfer1Normalized, + }) + + testNormalize(t, &test{ + name: "transferPending", + apiResponse: txTransferSrc2, + expected: &txTransfer2Normalized, + }) + + testNormalize(t, &test{ + name: "transferNotExecuted", + apiResponse: txTransferSrc3, + expected: &txTransfer3Normalized, + }) +} + +func TestNormalizeTxs(t *testing.T) { + var tx1, tx2, tx3 Transaction + + _ = json.Unmarshal([]byte(txTransferSrc1), &tx1) + _ = json.Unmarshal([]byte(txTransferSrc1), &tx2) + _ = json.Unmarshal([]byte(txTransferSrc1), &tx3) + + txs := []Transaction{tx1, tx2, tx3} + normalizedTxs := NormalizeTxs(txs, userAddress) + require.Equal(t, len(txs), len(normalizedTxs)) +} + +func testNormalize(t *testing.T, _test *test) { + var tx Transaction + err := json.Unmarshal([]byte(_test.apiResponse), &tx) + if err != nil { + t.Error(err) + return + } + + normalizedTx, ok := NormalizeTx(tx, tx.Sender) + require.True(t, ok, _test.name+": cannot normalize tx") + + resJSON, err := json.Marshal(&normalizedTx) + require.Nil(t, err) + + dstJSON, err := json.Marshal(&_test.expected) + require.Nil(t, err) + + require.Equal(t, string(dstJSON), string(resJSON)) +} diff --git a/platform/platform.go b/platform/platform.go index 7790401a2..b85fe7b7b 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -12,6 +12,7 @@ import ( "github.com/trustwallet/blockatlas/platform/binance" "github.com/trustwallet/blockatlas/platform/bitcoin" "github.com/trustwallet/blockatlas/platform/cosmos" + "github.com/trustwallet/blockatlas/platform/elrond" "github.com/trustwallet/blockatlas/platform/ethereum" "github.com/trustwallet/blockatlas/platform/fio" "github.com/trustwallet/blockatlas/platform/harmony" @@ -106,6 +107,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), coin.Near().Handle: near.Init(GetApiVar(coin.NEAR)), + coin.Elrond().Handle: elrond.Init(coin.ERD, GetApiVar(coin.ERD)), } } From ddf10ba4817d794c8fdc68a800c8976554c4c489 Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov Date: Wed, 20 May 2020 15:16:51 +0300 Subject: [PATCH 305/506] [BulkInsert] Use gorm-bulk-insert instead of BulkCreate (#1113) --- db/db.go | 50 +++++++++++++++ db/models/subscriptions.go | 2 +- db/subscriptions.go | 35 ++-------- db/subscritions_test.go | 29 +++++---- go.mod | 1 + go.sum | 4 ++ services/observer/notifier/notifier.go | 2 +- services/observer/subscriber/subscriber.go | 3 +- .../observer/subscriber/subscriber_test.go | 9 +-- .../integration/db_test/subscriptions_test.go | 64 +++++++++++-------- .../observer_test/full_flow_test.go | 4 +- .../observer_test/notifier_test.go | 3 +- .../observer_test/subscriber_test.go | 17 +++-- tests/integration/setup/testdata/coins.go | 9 +++ 14 files changed, 147 insertions(+), 85 deletions(-) create mode 100644 tests/integration/setup/testdata/coins.go diff --git a/db/db.go b/db/db.go index fe79c9638..6d626782e 100644 --- a/db/db.go +++ b/db/db.go @@ -1,11 +1,14 @@ package db import ( + "errors" "github.com/jinzhu/gorm" + gormbulk "github.com/t-tiger/gorm-bulk-insert" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/logger" "go.elastic.co/apm/module/apmgorm" _ "go.elastic.co/apm/module/apmgorm/dialects/postgres" + "reflect" "time" ) @@ -13,6 +16,8 @@ type Instance struct { Gorm *gorm.DB } +const batchCount = 3000 + func New(uri, env string) (*Instance, error) { var ( g *gorm.DB @@ -60,3 +65,48 @@ func RestoreConnectionWorker(database *Instance, timeout time.Duration, uri stri time.Sleep(timeout) } } + +func bulkInsert(db *gorm.DB, dbModels interface{}) error { + interfaceSlice, err := getInterfaceSlice(dbModels) + if err != nil { + return err + } + batchList := getInterfaceSliceBatch(interfaceSlice, batchCount) + for _, batch := range batchList { + err := gormbulk.BulkInsert(db, batch, len(batch)) + if err != nil { + return err + } + } + return nil +} + +func getInterfaceSlice(slice interface{}) ([]interface{}, error) { + s := reflect.ValueOf(slice) + if s.Kind() != reflect.Slice { + return nil, errors.New("InterfaceSlice() given a non-slice type") + } + + ret := make([]interface{}, s.Len()) + + for i := 0; i < s.Len(); i++ { + ret[i] = s.Index(i).Interface() + } + + return ret, nil +} + +func getInterfaceSliceBatch(values []interface{}, sizeUint uint) [][]interface{} { + size := int(sizeUint) + resultLength := (len(values) + size - 1) / size + result := make([][]interface{}, resultLength) + lo, hi := 0, size + for i := range result { + if hi > len(values) { + hi = len(values) + } + result[i] = values[lo:hi:hi] + lo, hi = hi, hi+size + } + return result +} diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index 016e8624a..56eafb1a4 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -11,6 +11,6 @@ type Subscription struct { type SubscriptionData struct { ID uint `gorm:"primary_key;"` SubscriptionId uint `gorm:"primary_key; column:subscription_id; auto_increment:false"` - Coin uint `gorm:"primary_key; column:coin; auto_increment:false"` + Coin *uint `gorm:"primary_key; column:coin; auto_increment:false"` Address string `gorm:"primary_key; column:address; type:varchar(128)"` } diff --git a/db/subscriptions.go b/db/subscriptions.go index 917fc4021..e5c0c539d 100644 --- a/db/subscriptions.go +++ b/db/subscriptions.go @@ -2,17 +2,13 @@ package db import ( "context" - "fmt" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/errors" "go.elastic.co/apm/module/apmgorm" "strconv" - "strings" "time" ) -const rawBulkInsert = `INSERT INTO subscription_data(subscription_id, coin, address) VALUES %s ON CONFLICT DO NOTHING` - func (i *Instance) GetSubscriptionData(coin uint, addresses []string, ctx context.Context) ([]models.SubscriptionData, error) { if len(addresses) == 0 { return nil, errors.E("Empty addresses") @@ -65,7 +61,10 @@ func (i *Instance) AddSubscriptions(id uint, subscriptions []models.Subscription txInstance.Gorm.Rollback() return err } - err = txInstance.BulkCreate(subscriptions) + + db := txInstance.Gorm.Set("gorm:insert_option", "ON CONFLICT DO NOTHING") + err = bulkInsert(db, subscriptions) + } else { err = txInstance.AddToExistingSubscription(id, subscriptions) } @@ -91,7 +90,8 @@ func (i *Instance) AddToExistingSubscription(id uint, subscriptions []models.Sub updateList, deleteList := getSubscriptionsToDeleteAndUpdate(existingData, subscriptions) if len(updateList) > 0 { - if err := i.BulkCreate(updateList); err != nil { + db := i.Gorm.Set("gorm:insert_option", "ON CONFLICT DO NOTHING") + if err := bulkInsert(db, updateList); err != nil { return err } } @@ -136,29 +136,6 @@ func (i *Instance) DeleteSubscriptions(subscriptions []models.SubscriptionData) return nil } -func (i *Instance) BulkCreate(dataList []models.SubscriptionData) error { - var ( - valueStrings []string - valueArgs []interface{} - ) - - for _, d := range dataList { - valueStrings = append(valueStrings, "(?, ?, ?)") - - valueArgs = append(valueArgs, d.SubscriptionId) - valueArgs = append(valueArgs, d.Coin) - valueArgs = append(valueArgs, d.Address) - } - - smt := fmt.Sprintf(rawBulkInsert, strings.Join(valueStrings, ",")) - - if err := i.Gorm.Exec(smt, valueArgs...).Error; err != nil { - return err - } - - return nil -} - func getSubscriptionsToDeleteAndUpdate(existing, new []models.SubscriptionData) (subToUpdate, subToDelete []models.SubscriptionData) { for _, n := range new { if !containSubscription(n, existing) { diff --git a/db/subscritions_test.go b/db/subscritions_test.go index 274ceec5a..8f1500857 100644 --- a/db/subscritions_test.go +++ b/db/subscritions_test.go @@ -3,31 +3,32 @@ package db import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/tests/integration/setup/testdata" "testing" ) func TestGetSubscriptionsToDeleteAndUpdate(t *testing.T) { oldSubscriptions := []models.SubscriptionData{{ SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "A", }, { SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "B", }, { SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "C", }} newSubscription := []models.SubscriptionData{{ SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "B", }, { SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "C", }} @@ -38,25 +39,25 @@ func TestGetSubscriptionsToDeleteAndUpdate(t *testing.T) { oldSubscriptions = []models.SubscriptionData{{ SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "A", }, { SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "B", }, { SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "C", }, { SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "D", }} newSubscription = []models.SubscriptionData{{ SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "E", }} @@ -66,21 +67,21 @@ func TestGetSubscriptionsToDeleteAndUpdate(t *testing.T) { oldSubscriptions = []models.SubscriptionData{{ SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "A", }, { SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "B", }} newSubscription = []models.SubscriptionData{{ SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "A", }, { SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "B", }} diff --git a/go.mod b/go.mod index 443ac6020..c00f0deaf 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require ( github.com/stretchr/testify v1.5.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.5 + github.com/t-tiger/gorm-bulk-insert v1.3.0 github.com/trustwallet/ens-coincodec v1.0.5 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 diff --git a/go.sum b/go.sum index 4d2b75351..287d794e5 100644 --- a/go.sum +++ b/go.sum @@ -236,6 +236,7 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= +github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -286,6 +287,7 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -419,6 +421,8 @@ github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.6.5 h1:2C+t+xyK6p1sujqncYO/VnMvPZcBJjNdKKyxbOdAW8o= github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= +github.com/t-tiger/gorm-bulk-insert v1.3.0 h1:9k7BaVEhw/3fsvh6GTOBwJ2RXk3asc5xs5m6hwozq20= +github.com/t-tiger/gorm-bulk-insert v1.3.0/go.mod h1:ruDlk8xDl+8sX4bA7PQuYly9YEb3pbp1eP2LCyeRrFY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/ens-coincodec v1.0.5 h1:rdebDQYHqNjv+yUdtMf3DXyMgJpEJSI2DSbC1GUFuyk= github.com/trustwallet/ens-coincodec v1.0.5/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= diff --git a/services/observer/notifier/notifier.go b/services/observer/notifier/notifier.go index 898242bb6..be4834d85 100644 --- a/services/observer/notifier/notifier.go +++ b/services/observer/notifier/notifier.go @@ -61,7 +61,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { for _, data := range subscriptionsDataList { go buildAndPostMessage( blockTransactions, - blockatlas.Subscription{Coin: data.Coin, Address: data.Address, Id: data.SubscriptionId}, + blockatlas.Subscription{Coin: *data.Coin, Address: data.Address, Id: data.SubscriptionId}, &wg, ctx) } wg.Wait() diff --git a/services/observer/subscriber/subscriber.go b/services/observer/subscriber/subscriber.go index 1100b4361..d5f9e885b 100644 --- a/services/observer/subscriber/subscriber.go +++ b/services/observer/subscriber/subscriber.go @@ -57,7 +57,8 @@ func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { func ToSubscriptionData(sub []blockatlas.Subscription) []models.SubscriptionData { data := make([]models.SubscriptionData, 0, len(sub)) for _, s := range sub { - data = append(data, models.SubscriptionData{Coin: s.Coin, Address: s.Address, SubscriptionId: s.Id}) + coin := s.Coin + data = append(data, models.SubscriptionData{Coin: &coin, Address: s.Address, SubscriptionId: s.Id}) } return data } diff --git a/services/observer/subscriber/subscriber_test.go b/services/observer/subscriber/subscriber_test.go index 713b879e8..b8aefe52a 100644 --- a/services/observer/subscriber/subscriber_test.go +++ b/services/observer/subscriber/subscriber_test.go @@ -4,29 +4,30 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/tests/integration/setup/testdata" "testing" ) func TestToSubscriptionData(t *testing.T) { sub := blockatlas.Subscription{ - Coin: 60, + Coin: testdata.EthCoin.ID, Address: "A", Id: 1, } sub2 := blockatlas.Subscription{ - Coin: 60, + Coin: testdata.EthCoin.ID, Address: "B", Id: 2, } expectedModel := models.SubscriptionData{ SubscriptionId: 1, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "A", } expectedModel1 := models.SubscriptionData{ SubscriptionId: 2, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "B", } diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go index 0cafda6dd..27ef7dbe2 100644 --- a/tests/integration/db_test/subscriptions_test.go +++ b/tests/integration/db_test/subscriptions_test.go @@ -9,6 +9,8 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/observer/subscriber" "github.com/trustwallet/blockatlas/tests/integration/setup" + "github.com/trustwallet/blockatlas/tests/integration/setup/testdata" + "sort" "testing" "time" ) @@ -20,9 +22,10 @@ func TestDb_AddSubscriptionsBulk(t *testing.T) { id := uint(1) for i := 0; i < 100; i++ { + coin := uint(i) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: uint(i), + Coin: &coin, Address: "testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr", }) } @@ -41,21 +44,25 @@ func TestDb_AddSubscriptions(t *testing.T) { var subscriptions []models.SubscriptionData id := uint(1) + + c1 := uint(60) + c2 := uint(61) + c3 := uint(62) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 60, + Coin: &c1, Address: "testAddr", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 61, + Coin: &c2, Address: "testAddr2", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 62, + Coin: &c3, Address: "testAddr3", }) @@ -93,19 +100,19 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { var subscriptions []models.SubscriptionData subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "testAddr", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 714, + Coin: &testdata.BnbCoin.ID, Address: "testAddr", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 144, + Coin: &testdata.XrpCoin.ID, Address: "testAddr", }) @@ -137,19 +144,19 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "testAddr2", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 714, + Coin: &testdata.BnbCoin.ID, Address: "testAddr2", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 144, + Coin: &testdata.XrpCoin.ID, Address: "testAddr2", }) @@ -256,19 +263,19 @@ func TestDb_DeleteSubscriptions(t *testing.T) { id := uint(1) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "testAddr", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 714, + Coin: &testdata.BnbCoin.ID, Address: "testAddr2", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 144, + Coin: &testdata.XrpCoin.ID, Address: "testAddr3", }) @@ -331,19 +338,19 @@ func TestDeleteAll(t *testing.T) { id := uint(1) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "testAddr", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 714, + Coin: &testdata.BnbCoin.ID, Address: "testAddr2", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 144, + Coin: &testdata.XrpCoin.ID, Address: "testAddr3", }) assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) @@ -390,7 +397,7 @@ func TestDb_DuplicateEntries(t *testing.T) { for i := 0; i < 10; i++ { subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "testAddr", }) } @@ -407,8 +414,9 @@ func TestDb_DuplicateEntries(t *testing.T) { func TestDb_FindSubscriptions_Multiple(t *testing.T) { setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData + subscriptions = append(subscriptions, models.SubscriptionData{ - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "testAddr", }) @@ -424,6 +432,10 @@ func TestDb_FindSubscriptions_Multiple(t *testing.T) { assert.Nil(t, err) assert.Equal(t, 5, len(subs)) + sort.Slice(subs, func(i, j int) bool { + return subs[i].SubscriptionId < subs[j].SubscriptionId + }) + for i := 0; i < 5; i++ { assert.Equal(t, uint(i)+1, subs[i].SubscriptionId) } @@ -433,7 +445,7 @@ func TestDb_AddToExisting(t *testing.T) { setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData subscriptions = append(subscriptions, models.SubscriptionData{ - Coin: 60, + Coin: &testdata.EthCoin.ID, Address: "testAddr", }) @@ -467,11 +479,11 @@ func TestDb_UpdatedAt(t *testing.T) { setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData subscriptions = append(subscriptions, models.SubscriptionData{ - Coin: 60, - Address: "testAddr", + SubscriptionId: 1, + Coin: &testdata.EthCoin.ID, + Address: "testAddr", }) - subscriptions[0].SubscriptionId = uint(1) assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) @@ -485,8 +497,9 @@ func TestDb_UpdatedAt(t *testing.T) { assert.Greater(t, existingSub.UpdatedAt.Unix(), time.Now().Unix()-120) subscriptions = append(subscriptions, models.SubscriptionData{ - Coin: 714, - Address: "newtestAddr", + SubscriptionId: 1, + Coin: &testdata.BnbCoin.ID, + Address: "newtestAddr", }) assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) @@ -499,12 +512,11 @@ func TestDb_UpdatedAt(t *testing.T) { assert.Greater(t, time.Now().Unix(), existingSub2.UpdatedAt.Unix()) assert.Greater(t, existingSub2.UpdatedAt.Unix(), time.Now().Unix()-120) assert.Greater(t, existingSub2.UpdatedAt.Unix(), existingSub.UpdatedAt.Unix()) - } func containSub(sub models.SubscriptionData, list []models.SubscriptionData) bool { for _, s := range list { - if sub.Address == s.Address && sub.Coin == s.Coin && sub.SubscriptionId == s.SubscriptionId { + if sub.Address == s.Address && *sub.Coin == *s.Coin && sub.SubscriptionId == s.SubscriptionId { return true } } diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 29cce3ab3..24b41733d 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -14,6 +14,7 @@ import ( "github.com/trustwallet/blockatlas/services/observer/notifier" "github.com/trustwallet/blockatlas/services/observer/parser" "github.com/trustwallet/blockatlas/tests/integration/setup" + "github.com/trustwallet/blockatlas/tests/integration/setup/testdata" "go.uber.org/atomic" "testing" "time" @@ -25,7 +26,8 @@ var ( func TestFullFlow(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 60, Address: "testAddress", SubscriptionId: 1}}, context.Background()) + + err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: &testdata.EthCoin.ID, Address: "testAddress", SubscriptionId: 1}}, context.Background()) assert.Nil(t, err) ctx, cancel := context.WithCancel(context.Background()) diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index 0f6a1abe9..92035445c 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -13,6 +13,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/observer/notifier" "github.com/trustwallet/blockatlas/tests/integration/setup" + "github.com/trustwallet/blockatlas/tests/integration/setup/testdata" "testing" "time" ) @@ -44,7 +45,7 @@ var ( func TestNotifier(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", SubscriptionId: 1}}, context.Background()) + err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: &testdata.BnbCoin.ID, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", SubscriptionId: 1}}, context.Background()) assert.Nil(t, err) err = produceTxs(txs) diff --git a/tests/integration/observer_test/subscriber_test.go b/tests/integration/observer_test/subscriber_test.go index b7e9ac166..80eb6674f 100644 --- a/tests/integration/observer_test/subscriber_test.go +++ b/tests/integration/observer_test/subscriber_test.go @@ -60,7 +60,7 @@ func TestSubscriberAddSubscription(t *testing.T) { result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}, context.Background()) assert.Nil(t, err) assert.Equal(t, result[0].SubscriptionId, wanted.Id) - assert.Equal(t, result[0].Coin, wanted.Coin) + assert.Equal(t, wanted.Coin, *result[0].Coin) assert.Equal(t, result[0].Address, wanted.Address) } } @@ -91,18 +91,21 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { t.Fatal(err) } - + c1 := uint(61) + c2 := uint(62) + c3 := uint(63) + c4 := uint(64) database.AddSubscriptions(10, []models.SubscriptionData{ - {Coin: 61, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 10}, + {Coin: &c1, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 10}, }, context.Background()) database.AddSubscriptions(1, []models.SubscriptionData{ - {Coin: 62, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 1}, + {Coin: &c2, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 1}, }, context.Background()) database.AddSubscriptions(2, []models.SubscriptionData{ - {Coin: 63, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 2}, + {Coin: &c3, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 2}, }, context.Background()) database.AddSubscriptions(3, []models.SubscriptionData{ - {Coin: 64, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 3}, + {Coin: &c4, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 3}, }, context.Background()) for _, event := range givenEvents { @@ -123,7 +126,7 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}, context.Background()) assert.Nil(t, err) assert.Equal(t, result[0].SubscriptionId, wanted.Id) - assert.Equal(t, result[0].Coin, wanted.Coin) + assert.Equal(t, wanted.Coin, *result[0].Coin) assert.Equal(t, result[0].Address, wanted.Address) } diff --git a/tests/integration/setup/testdata/coins.go b/tests/integration/setup/testdata/coins.go new file mode 100644 index 000000000..610fd160b --- /dev/null +++ b/tests/integration/setup/testdata/coins.go @@ -0,0 +1,9 @@ +package testdata + +import "github.com/trustwallet/blockatlas/coin" + +var ( + EthCoin = coin.Ethereum() + BnbCoin = coin.Binance() + XrpCoin = coin.Ripple() +) From 5dbc479ac012a1705be783a4d7027056f9771bd9 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 20 May 2020 16:27:05 +0300 Subject: [PATCH 306/506] Revert "[BulkInsert] Use gorm-bulk-insert instead of BulkCreate (#1113)" (#1114) This reverts commit ddf10ba4817d794c8fdc68a800c8976554c4c489. --- db/db.go | 50 --------------- db/models/subscriptions.go | 2 +- db/subscriptions.go | 35 ++++++++-- db/subscritions_test.go | 29 ++++----- go.mod | 1 - go.sum | 4 -- services/observer/notifier/notifier.go | 2 +- services/observer/subscriber/subscriber.go | 3 +- .../observer/subscriber/subscriber_test.go | 9 ++- .../integration/db_test/subscriptions_test.go | 64 ++++++++----------- .../observer_test/full_flow_test.go | 4 +- .../observer_test/notifier_test.go | 3 +- .../observer_test/subscriber_test.go | 17 ++--- tests/integration/setup/testdata/coins.go | 9 --- 14 files changed, 85 insertions(+), 147 deletions(-) delete mode 100644 tests/integration/setup/testdata/coins.go diff --git a/db/db.go b/db/db.go index 6d626782e..fe79c9638 100644 --- a/db/db.go +++ b/db/db.go @@ -1,14 +1,11 @@ package db import ( - "errors" "github.com/jinzhu/gorm" - gormbulk "github.com/t-tiger/gorm-bulk-insert" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/logger" "go.elastic.co/apm/module/apmgorm" _ "go.elastic.co/apm/module/apmgorm/dialects/postgres" - "reflect" "time" ) @@ -16,8 +13,6 @@ type Instance struct { Gorm *gorm.DB } -const batchCount = 3000 - func New(uri, env string) (*Instance, error) { var ( g *gorm.DB @@ -65,48 +60,3 @@ func RestoreConnectionWorker(database *Instance, timeout time.Duration, uri stri time.Sleep(timeout) } } - -func bulkInsert(db *gorm.DB, dbModels interface{}) error { - interfaceSlice, err := getInterfaceSlice(dbModels) - if err != nil { - return err - } - batchList := getInterfaceSliceBatch(interfaceSlice, batchCount) - for _, batch := range batchList { - err := gormbulk.BulkInsert(db, batch, len(batch)) - if err != nil { - return err - } - } - return nil -} - -func getInterfaceSlice(slice interface{}) ([]interface{}, error) { - s := reflect.ValueOf(slice) - if s.Kind() != reflect.Slice { - return nil, errors.New("InterfaceSlice() given a non-slice type") - } - - ret := make([]interface{}, s.Len()) - - for i := 0; i < s.Len(); i++ { - ret[i] = s.Index(i).Interface() - } - - return ret, nil -} - -func getInterfaceSliceBatch(values []interface{}, sizeUint uint) [][]interface{} { - size := int(sizeUint) - resultLength := (len(values) + size - 1) / size - result := make([][]interface{}, resultLength) - lo, hi := 0, size - for i := range result { - if hi > len(values) { - hi = len(values) - } - result[i] = values[lo:hi:hi] - lo, hi = hi, hi+size - } - return result -} diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index 56eafb1a4..016e8624a 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -11,6 +11,6 @@ type Subscription struct { type SubscriptionData struct { ID uint `gorm:"primary_key;"` SubscriptionId uint `gorm:"primary_key; column:subscription_id; auto_increment:false"` - Coin *uint `gorm:"primary_key; column:coin; auto_increment:false"` + Coin uint `gorm:"primary_key; column:coin; auto_increment:false"` Address string `gorm:"primary_key; column:address; type:varchar(128)"` } diff --git a/db/subscriptions.go b/db/subscriptions.go index e5c0c539d..917fc4021 100644 --- a/db/subscriptions.go +++ b/db/subscriptions.go @@ -2,13 +2,17 @@ package db import ( "context" + "fmt" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/errors" "go.elastic.co/apm/module/apmgorm" "strconv" + "strings" "time" ) +const rawBulkInsert = `INSERT INTO subscription_data(subscription_id, coin, address) VALUES %s ON CONFLICT DO NOTHING` + func (i *Instance) GetSubscriptionData(coin uint, addresses []string, ctx context.Context) ([]models.SubscriptionData, error) { if len(addresses) == 0 { return nil, errors.E("Empty addresses") @@ -61,10 +65,7 @@ func (i *Instance) AddSubscriptions(id uint, subscriptions []models.Subscription txInstance.Gorm.Rollback() return err } - - db := txInstance.Gorm.Set("gorm:insert_option", "ON CONFLICT DO NOTHING") - err = bulkInsert(db, subscriptions) - + err = txInstance.BulkCreate(subscriptions) } else { err = txInstance.AddToExistingSubscription(id, subscriptions) } @@ -90,8 +91,7 @@ func (i *Instance) AddToExistingSubscription(id uint, subscriptions []models.Sub updateList, deleteList := getSubscriptionsToDeleteAndUpdate(existingData, subscriptions) if len(updateList) > 0 { - db := i.Gorm.Set("gorm:insert_option", "ON CONFLICT DO NOTHING") - if err := bulkInsert(db, updateList); err != nil { + if err := i.BulkCreate(updateList); err != nil { return err } } @@ -136,6 +136,29 @@ func (i *Instance) DeleteSubscriptions(subscriptions []models.SubscriptionData) return nil } +func (i *Instance) BulkCreate(dataList []models.SubscriptionData) error { + var ( + valueStrings []string + valueArgs []interface{} + ) + + for _, d := range dataList { + valueStrings = append(valueStrings, "(?, ?, ?)") + + valueArgs = append(valueArgs, d.SubscriptionId) + valueArgs = append(valueArgs, d.Coin) + valueArgs = append(valueArgs, d.Address) + } + + smt := fmt.Sprintf(rawBulkInsert, strings.Join(valueStrings, ",")) + + if err := i.Gorm.Exec(smt, valueArgs...).Error; err != nil { + return err + } + + return nil +} + func getSubscriptionsToDeleteAndUpdate(existing, new []models.SubscriptionData) (subToUpdate, subToDelete []models.SubscriptionData) { for _, n := range new { if !containSubscription(n, existing) { diff --git a/db/subscritions_test.go b/db/subscritions_test.go index 8f1500857..274ceec5a 100644 --- a/db/subscritions_test.go +++ b/db/subscritions_test.go @@ -3,32 +3,31 @@ package db import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/tests/integration/setup/testdata" "testing" ) func TestGetSubscriptionsToDeleteAndUpdate(t *testing.T) { oldSubscriptions := []models.SubscriptionData{{ SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "A", }, { SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "B", }, { SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "C", }} newSubscription := []models.SubscriptionData{{ SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "B", }, { SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "C", }} @@ -39,25 +38,25 @@ func TestGetSubscriptionsToDeleteAndUpdate(t *testing.T) { oldSubscriptions = []models.SubscriptionData{{ SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "A", }, { SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "B", }, { SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "C", }, { SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "D", }} newSubscription = []models.SubscriptionData{{ SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "E", }} @@ -67,21 +66,21 @@ func TestGetSubscriptionsToDeleteAndUpdate(t *testing.T) { oldSubscriptions = []models.SubscriptionData{{ SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "A", }, { SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "B", }} newSubscription = []models.SubscriptionData{{ SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "A", }, { SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "B", }} diff --git a/go.mod b/go.mod index c00f0deaf..443ac6020 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,6 @@ require ( github.com/stretchr/testify v1.5.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.5 - github.com/t-tiger/gorm-bulk-insert v1.3.0 github.com/trustwallet/ens-coincodec v1.0.5 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 diff --git a/go.sum b/go.sum index 287d794e5..4d2b75351 100644 --- a/go.sum +++ b/go.sum @@ -236,7 +236,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= -github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -287,7 +286,6 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -421,8 +419,6 @@ github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.6.5 h1:2C+t+xyK6p1sujqncYO/VnMvPZcBJjNdKKyxbOdAW8o= github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= -github.com/t-tiger/gorm-bulk-insert v1.3.0 h1:9k7BaVEhw/3fsvh6GTOBwJ2RXk3asc5xs5m6hwozq20= -github.com/t-tiger/gorm-bulk-insert v1.3.0/go.mod h1:ruDlk8xDl+8sX4bA7PQuYly9YEb3pbp1eP2LCyeRrFY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/ens-coincodec v1.0.5 h1:rdebDQYHqNjv+yUdtMf3DXyMgJpEJSI2DSbC1GUFuyk= github.com/trustwallet/ens-coincodec v1.0.5/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= diff --git a/services/observer/notifier/notifier.go b/services/observer/notifier/notifier.go index be4834d85..898242bb6 100644 --- a/services/observer/notifier/notifier.go +++ b/services/observer/notifier/notifier.go @@ -61,7 +61,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { for _, data := range subscriptionsDataList { go buildAndPostMessage( blockTransactions, - blockatlas.Subscription{Coin: *data.Coin, Address: data.Address, Id: data.SubscriptionId}, + blockatlas.Subscription{Coin: data.Coin, Address: data.Address, Id: data.SubscriptionId}, &wg, ctx) } wg.Wait() diff --git a/services/observer/subscriber/subscriber.go b/services/observer/subscriber/subscriber.go index d5f9e885b..1100b4361 100644 --- a/services/observer/subscriber/subscriber.go +++ b/services/observer/subscriber/subscriber.go @@ -57,8 +57,7 @@ func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { func ToSubscriptionData(sub []blockatlas.Subscription) []models.SubscriptionData { data := make([]models.SubscriptionData, 0, len(sub)) for _, s := range sub { - coin := s.Coin - data = append(data, models.SubscriptionData{Coin: &coin, Address: s.Address, SubscriptionId: s.Id}) + data = append(data, models.SubscriptionData{Coin: s.Coin, Address: s.Address, SubscriptionId: s.Id}) } return data } diff --git a/services/observer/subscriber/subscriber_test.go b/services/observer/subscriber/subscriber_test.go index b8aefe52a..713b879e8 100644 --- a/services/observer/subscriber/subscriber_test.go +++ b/services/observer/subscriber/subscriber_test.go @@ -4,30 +4,29 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/tests/integration/setup/testdata" "testing" ) func TestToSubscriptionData(t *testing.T) { sub := blockatlas.Subscription{ - Coin: testdata.EthCoin.ID, + Coin: 60, Address: "A", Id: 1, } sub2 := blockatlas.Subscription{ - Coin: testdata.EthCoin.ID, + Coin: 60, Address: "B", Id: 2, } expectedModel := models.SubscriptionData{ SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "A", } expectedModel1 := models.SubscriptionData{ SubscriptionId: 2, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "B", } diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go index 27ef7dbe2..0cafda6dd 100644 --- a/tests/integration/db_test/subscriptions_test.go +++ b/tests/integration/db_test/subscriptions_test.go @@ -9,8 +9,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/observer/subscriber" "github.com/trustwallet/blockatlas/tests/integration/setup" - "github.com/trustwallet/blockatlas/tests/integration/setup/testdata" - "sort" "testing" "time" ) @@ -22,10 +20,9 @@ func TestDb_AddSubscriptionsBulk(t *testing.T) { id := uint(1) for i := 0; i < 100; i++ { - coin := uint(i) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &coin, + Coin: uint(i), Address: "testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr", }) } @@ -44,25 +41,21 @@ func TestDb_AddSubscriptions(t *testing.T) { var subscriptions []models.SubscriptionData id := uint(1) - - c1 := uint(60) - c2 := uint(61) - c3 := uint(62) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &c1, + Coin: 60, Address: "testAddr", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &c2, + Coin: 61, Address: "testAddr2", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &c3, + Coin: 62, Address: "testAddr3", }) @@ -100,19 +93,19 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { var subscriptions []models.SubscriptionData subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "testAddr", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.BnbCoin.ID, + Coin: 714, Address: "testAddr", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.XrpCoin.ID, + Coin: 144, Address: "testAddr", }) @@ -144,19 +137,19 @@ func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "testAddr2", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.BnbCoin.ID, + Coin: 714, Address: "testAddr2", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.XrpCoin.ID, + Coin: 144, Address: "testAddr2", }) @@ -263,19 +256,19 @@ func TestDb_DeleteSubscriptions(t *testing.T) { id := uint(1) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "testAddr", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.BnbCoin.ID, + Coin: 714, Address: "testAddr2", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.XrpCoin.ID, + Coin: 144, Address: "testAddr3", }) @@ -338,19 +331,19 @@ func TestDeleteAll(t *testing.T) { id := uint(1) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "testAddr", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.BnbCoin.ID, + Coin: 714, Address: "testAddr2", }) subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.XrpCoin.ID, + Coin: 144, Address: "testAddr3", }) assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) @@ -397,7 +390,7 @@ func TestDb_DuplicateEntries(t *testing.T) { for i := 0; i < 10; i++ { subscriptions = append(subscriptions, models.SubscriptionData{ SubscriptionId: id, - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "testAddr", }) } @@ -414,9 +407,8 @@ func TestDb_DuplicateEntries(t *testing.T) { func TestDb_FindSubscriptions_Multiple(t *testing.T) { setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData - subscriptions = append(subscriptions, models.SubscriptionData{ - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "testAddr", }) @@ -432,10 +424,6 @@ func TestDb_FindSubscriptions_Multiple(t *testing.T) { assert.Nil(t, err) assert.Equal(t, 5, len(subs)) - sort.Slice(subs, func(i, j int) bool { - return subs[i].SubscriptionId < subs[j].SubscriptionId - }) - for i := 0; i < 5; i++ { assert.Equal(t, uint(i)+1, subs[i].SubscriptionId) } @@ -445,7 +433,7 @@ func TestDb_AddToExisting(t *testing.T) { setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData subscriptions = append(subscriptions, models.SubscriptionData{ - Coin: &testdata.EthCoin.ID, + Coin: 60, Address: "testAddr", }) @@ -479,11 +467,11 @@ func TestDb_UpdatedAt(t *testing.T) { setup.CleanupPgContainer(database.Gorm) var subscriptions []models.SubscriptionData subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: 1, - Coin: &testdata.EthCoin.ID, - Address: "testAddr", + Coin: 60, + Address: "testAddr", }) + subscriptions[0].SubscriptionId = uint(1) assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) @@ -497,9 +485,8 @@ func TestDb_UpdatedAt(t *testing.T) { assert.Greater(t, existingSub.UpdatedAt.Unix(), time.Now().Unix()-120) subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: 1, - Coin: &testdata.BnbCoin.ID, - Address: "newtestAddr", + Coin: 714, + Address: "newtestAddr", }) assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) @@ -512,11 +499,12 @@ func TestDb_UpdatedAt(t *testing.T) { assert.Greater(t, time.Now().Unix(), existingSub2.UpdatedAt.Unix()) assert.Greater(t, existingSub2.UpdatedAt.Unix(), time.Now().Unix()-120) assert.Greater(t, existingSub2.UpdatedAt.Unix(), existingSub.UpdatedAt.Unix()) + } func containSub(sub models.SubscriptionData, list []models.SubscriptionData) bool { for _, s := range list { - if sub.Address == s.Address && *sub.Coin == *s.Coin && sub.SubscriptionId == s.SubscriptionId { + if sub.Address == s.Address && sub.Coin == s.Coin && sub.SubscriptionId == s.SubscriptionId { return true } } diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 24b41733d..29cce3ab3 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -14,7 +14,6 @@ import ( "github.com/trustwallet/blockatlas/services/observer/notifier" "github.com/trustwallet/blockatlas/services/observer/parser" "github.com/trustwallet/blockatlas/tests/integration/setup" - "github.com/trustwallet/blockatlas/tests/integration/setup/testdata" "go.uber.org/atomic" "testing" "time" @@ -26,8 +25,7 @@ var ( func TestFullFlow(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - - err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: &testdata.EthCoin.ID, Address: "testAddress", SubscriptionId: 1}}, context.Background()) + err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 60, Address: "testAddress", SubscriptionId: 1}}, context.Background()) assert.Nil(t, err) ctx, cancel := context.WithCancel(context.Background()) diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index 92035445c..0f6a1abe9 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -13,7 +13,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/observer/notifier" "github.com/trustwallet/blockatlas/tests/integration/setup" - "github.com/trustwallet/blockatlas/tests/integration/setup/testdata" "testing" "time" ) @@ -45,7 +44,7 @@ var ( func TestNotifier(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: &testdata.BnbCoin.ID, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", SubscriptionId: 1}}, context.Background()) + err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", SubscriptionId: 1}}, context.Background()) assert.Nil(t, err) err = produceTxs(txs) diff --git a/tests/integration/observer_test/subscriber_test.go b/tests/integration/observer_test/subscriber_test.go index 80eb6674f..b7e9ac166 100644 --- a/tests/integration/observer_test/subscriber_test.go +++ b/tests/integration/observer_test/subscriber_test.go @@ -60,7 +60,7 @@ func TestSubscriberAddSubscription(t *testing.T) { result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}, context.Background()) assert.Nil(t, err) assert.Equal(t, result[0].SubscriptionId, wanted.Id) - assert.Equal(t, wanted.Coin, *result[0].Coin) + assert.Equal(t, result[0].Coin, wanted.Coin) assert.Equal(t, result[0].Address, wanted.Address) } } @@ -91,21 +91,18 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { t.Fatal(err) } - c1 := uint(61) - c2 := uint(62) - c3 := uint(63) - c4 := uint(64) + database.AddSubscriptions(10, []models.SubscriptionData{ - {Coin: &c1, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 10}, + {Coin: 61, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 10}, }, context.Background()) database.AddSubscriptions(1, []models.SubscriptionData{ - {Coin: &c2, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 1}, + {Coin: 62, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 1}, }, context.Background()) database.AddSubscriptions(2, []models.SubscriptionData{ - {Coin: &c3, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 2}, + {Coin: 63, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 2}, }, context.Background()) database.AddSubscriptions(3, []models.SubscriptionData{ - {Coin: &c4, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 3}, + {Coin: 64, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 3}, }, context.Background()) for _, event := range givenEvents { @@ -126,7 +123,7 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}, context.Background()) assert.Nil(t, err) assert.Equal(t, result[0].SubscriptionId, wanted.Id) - assert.Equal(t, wanted.Coin, *result[0].Coin) + assert.Equal(t, result[0].Coin, wanted.Coin) assert.Equal(t, result[0].Address, wanted.Address) } diff --git a/tests/integration/setup/testdata/coins.go b/tests/integration/setup/testdata/coins.go deleted file mode 100644 index 610fd160b..000000000 --- a/tests/integration/setup/testdata/coins.go +++ /dev/null @@ -1,9 +0,0 @@ -package testdata - -import "github.com/trustwallet/blockatlas/coin" - -var ( - EthCoin = coin.Ethereum() - BnbCoin = coin.Binance() - XrpCoin = coin.Ripple() -) From ffe2e8bddf5e3aeeeea1f5a6ba9404a064f4737e Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Thu, 21 May 2020 16:38:13 +0200 Subject: [PATCH 307/506] Mock data in files, own mockserver (#1100) * Move mock test data files to separate json files, PR #1094 Squashed commit of the following: commit 3e67cdc2f5cad77bd0f9c1becace8074cb5ff869 Merge: ba32ec7 033efb7 Author: Catenocrypt Date: Fri May 15 06:56:08 2020 +0200 Merge branch 'master' into ar/mocktestdata commit ba32ec792aeb71a81f0a5a69adf37a31a607d9df Author: Catenocrypt Date: Thu May 14 16:25:21 2020 +0200 Bogus commit for CI. commit 4ca5fbaed2e0e5a55bd4f3fa63a5f027b38ac4bc Author: Catenocrypt Date: Thu May 14 16:06:06 2020 +0200 Remove one BAK file. commit 77389b0c3ce7daccd68f1f8e4ff2e23f5bcb0c58 Author: Catenocrypt Date: Thu May 14 15:56:23 2020 +0200 Extend README. commit 240f908d38ca656b9d70b02c416cdc44ddd7d2a9 Author: Catenocrypt Date: Thu May 14 15:40:57 2020 +0200 Lint fix. commit 37e8bbf5a370139199f1d5f4f95e1e01ddb61181 Author: Catenocrypt Date: Thu May 14 15:38:01 2020 +0200 FIO not to be updated automatically. commit e76a6bedd5fedcb541d2cb194ffbf506235369a3 Author: Catenocrypt Date: Thu May 14 15:36:44 2020 +0200 FIO lookup responses from files. commit 5bf963d94ae3ae5a8191002c7f3f4e13054882c5 Author: Catenocrypt Date: Thu May 14 14:58:49 2020 +0200 Tron and FIO scripts. commit 0f6898a2c6cc002f21d8ccc5597438d8a01de2da Author: Catenocrypt Date: Thu May 14 14:28:20 2020 +0200 Go fmt. commit 639ab12758e2943bf8c5bfd8e0202b0f12f1fec8 Author: Catenocrypt Date: Thu May 14 14:27:24 2020 +0200 Extend possibility of counter on filename; update FIO script. commit de2a4d269c6b1632a9e5153c2a7c929cfc8def3a Author: Catenocrypt Date: Thu May 14 11:38:14 2020 +0200 Update some post scripts (4). commit e0cea762185578c01f89a9bd79f2cbeb9c879243 Author: Catenocrypt Date: Thu May 14 00:52:00 2020 +0200 Lint fix. commit c4ec4a18b53a202f68c04a52058e25e48f52441b Author: Catenocrypt Date: Thu May 14 00:44:40 2020 +0200 Support for POST requests, first post data+script. commit 43cebc3a93991291036ec6d1e24d15dc3ddcac9b Author: Catenocrypt Date: Wed May 13 23:29:32 2020 +0200 2 more cases (were missed, did not use json.parse). commit 690dfe87868a209dbf71f61ad27008254978fc6a Author: Catenocrypt Date: Wed May 13 23:21:59 2020 +0200 Update scripts, all Get scripts are done. commit 4a4daec9da916144afd977f1ea8dd01fb0d1ca3b Author: Catenocrypt Date: Wed May 13 18:32:19 2020 +0200 More mock update scripts, almost all get scripts. commit d89c54e6b8ee1fed30d2dbecf48c059718fada4a Author: Catenocrypt Date: Wed May 13 15:32:46 2020 +0200 More scripts updated. commit 325eb9301fe8273ebdb489ab8509afefa21af981 Author: Catenocrypt Date: Wed May 13 15:08:31 2020 +0200 Update mock scripts. commit a2bf9e3f49cce1da1421644788268ed73b04715f Author: Catenocrypt Date: Wed May 13 14:18:04 2020 +0200 Lint fix. commit 0e396894f2b535728cb9419c092f75ccbca6632e Author: Catenocrypt Date: Wed May 13 12:50:21 2020 +0200 Remove BAK files. Signed-off-by: Catenocrypt commit 7ee2e071157c3393329102de0b5fd692ee117604 Author: Catenocrypt Date: Wed May 13 12:49:07 2020 +0200 Pretty-print JSON test data files. commit b482e5b942ebe843a9996d92e746f9a48c7e4c5a Author: Catenocrypt Date: Wed May 13 12:45:24 2020 +0200 Pretty-print JSON files. commit 0910aa8d9d427c68f1eb45c54bb3130e4c83df1e Author: Catenocrypt Date: Wed May 13 12:29:43 2020 +0200 Extend testdatatool with add option. commit feb4ddb99076819412b466957da9fa6157d96c49 Author: Catenocrypt Date: Wed May 13 11:48:26 2020 +0200 Add README and testdatatool.go. commit a2bd1a72efc991523bfd09ca44e6e44506ccf4c4 Author: Catenocrypt Date: Wed May 13 10:20:35 2020 +0200 Rename testdatatool.go. commit 1e40c7e854654d7a3ec7fdae1d4b51281f1ee2a0 Author: Catenocrypt Date: Tue May 12 23:56:14 2020 +0200 A missing data file. commit 47710e675a1a6ba0ac9a0aef19883cf0d980997e Author: Catenocrypt Date: Tue May 12 23:50:30 2020 +0200 Update few more test to use test files. commit e8c989eebc8077999c8288606a2ec9281eacf182 Author: Catenocrypt Date: Tue May 12 23:32:42 2020 +0200 Rename 2, update binance script. commit 554cd5a3cc5eae8c02c206f0e1c6d2d89a2c48a6 Author: Catenocrypt Date: Tue May 12 23:27:55 2020 +0200 Dir rename mock/ext-api-data. commit e18e1c583c3a7a2211647d0f33466a5a39fd048e Author: Catenocrypt Date: Tue May 12 23:24:59 2020 +0200 Add test data files (many not yet used). commit fcc72b6a70a5350fad3181d946fc85f75d5ef772 Author: Catenocrypt Date: Tue May 12 21:58:21 2020 +0200 Update mock API paths to start with mock universally. commit 59e4f85742c7e22e74d9a57514e00b759c393f60 Author: Catenocrypt Date: Tue May 12 21:49:44 2020 +0200 Process a few more coins (test data separation). commit 9012ea401a986f46e4bafd909875af1cf3e8ce8f Author: Catenocrypt Date: Tue May 12 15:30:14 2020 +0200 WIP Move mock test data files to separate json files. * Mockserver, first prototype. * Extend data file list with extURLs. * Extend data file list with reqfiles. * Rename data files to readable names. * Move mockserver files out of data dir. * Remove obsolete files. * Fix some query matching. * Get rid of Dyson, small fixes. * Makefile: first compile, then run mockserver. * Support for POST request with non-exact request data (discriminator field). * URL match fix. * Data file fixes. * Add 2 missing data files, fix for handling % character. * Handling of mock URLs absolutre. * Remove all Dyson scripts. * Go fmt; trigger CI. * Add Method to datafiles.yaml. * Lint fix, remove unused line. * Binance test fix (rework of modified tests). * Binance test fix2 (rework of modified tests). * Move mock-healthcheck in file, for transparency. * Missing healthcheck data file. * Update READMEs. * Reduce the largest data files. Co-authored-by: Catenocrypt Co-authored-by: hewig <360470+hewigovens@users.noreply.github.com> --- Makefile | 39 +- README.md | 9 +- configmock.yml | 100 +- mock/README.md | 29 + mock/datafiles.yaml | 507 +++ ...xgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb.json | 139 + ...84d72356c8a362025d31b855ed6ed_size_25.json | 58 + ...EFTVH77ROG4ZGREC6Y7V5T2U_transactions.json | 23 + .../algorand-api_v1_block_5478346.json | 43 + ...bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q | 1 + ...ce-api_v1_tokens__limit_1000_offset_0.json | 1466 +++++++ ...zevgcmf0q_txAsset_BNB_txType_TRANSFER.json | 1 + ...9txwlnw0yj2h82x9566fglqj__details_txs.json | 700 ++++ ...Vq8qhk9veozrA2W9QaWtihrC__details_txs.json | 1 + ...xw80ku2ex0tj76vvsxpvmgme__details_txs.json | 1 + ...88ZaUQxXciBcZ1soSi1d8xtX__details_txs.json | 165 + ...5b69f65027ddf48f894e6e90121293a2f6615.json | 1 + ...3a7ec44ca2b038d4be4b0798152f948f0f3d7.json | 1 + ...x27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json | 1 + .../cosmos-api_minting_inflation.json | 4 + ...ekcf2k9hsktcxnmpl7fcehcvq_delegations.json | 11 + .../ext-api-data/cosmos-api_staking_pool.json | 7 + ...api_staking_validators__status_bonded.json | 3130 ++++++++++++++ ...hwej0ekcf2k9hsktcxnmpl7fcehcvq_page_1.json | 308 ++ ...x27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json | 192 + ...EzbqA9nCJi8zDtnRZzNKkCtG__details_txs.json | 1 + ...WpwPDbJjfxREHC848sxNrUkD__details_txs.json | 1 + ...Ngu5fzozr4mTR4tqqMaKcvpY__details_txs.json | 523 +++ ...opomXRnr5Gt43rjpNEfeuJLN__details_txs.json | 1447 +++++++ ...SjfphFJdxX9eidrjWewMZgAi__details_txs.json | 1 + ...VnpYD2Lawjtb3wowbFdwmjow__details_txs.json | 389 ++ ...g1q4dRgzKTBsxp4VJietWkDh__details_txs.json | 568 +++ ...aYNupUqVAZcweqGhfsudUELN__details_txs.json | 1 + ...5BCab22dE3d02402bc38aEe4104e1239374a7.json | 107 + ...5BCab22dE3d02402bc38aEe4104e1239374a7.json | 58 + ...4104e1239374a7__details_tokenBalances.json | 38 + ...402bc38aEe4104e1239374a7__details_txs.json | 97 + ...a9e6da5a6b004b5a192a0f55d2d9fab4f1047.json | 1 + ...6b004b5a192a0f55d2d9fab4f1047.request_json | 1 + ...0a7ceb56aca81b12e6f5afc46f5a429999aa4.json | 1 + ...aca81b12e6f5afc46f5a429999aa4.request_json | 1 + ...f439055fd2577951148c14b6cea9a53475835.json | 1 + ...d2577951148c14b6cea9a53475835.request_json | 1 + ...a9e6da5a6b004b5a192a0f55d2d9fab4f1047.json | 1 + ...6b004b5a192a0f55d2d9fab4f1047.request_json | 1 + ...0a7ceb56aca81b12e6f5afc46f5a429999aa4.json | 1 + ...aca81b12e6f5afc46f5a429999aa4.request_json | 1 + ...000000000000000000000000000000000003c.json | 1 + ...0000000000000000000000000003c.request_json | 1 + ...000000000000000000000000000000000003c.json | 1 + ...0000000000000000000000000003c.request_json | 1 + ...000000000000000000000000000000000003c.json | 1 + ...0000000000000000000000000003c.request_json | 1 + ...105efa0663147bddee178f6a741ac15676b79.json | 1 + ...d0e153026fb428b885d86de50768d4cfeac37.json | 1 + ...fio-api_v1_chain_get_pub_address.0001.json | 1 + ...v1_chain_get_pub_address.0001.request_json | 5 + ...fio-api_v1_chain_get_pub_address.0002.json | 1 + ...v1_chain_get_pub_address.0002.request_json | 5 + .../fio-api_v1_chain_get_pub_address.json | 1 + ...-api_v1_chain_get_pub_address.request_json | 1 + .../fio-api_v1_history_get_actions.0001.json | 1100 +++++ ...i_v1_history_get_actions.0001.request_json | 3 + .../fio-api_v1_history_get_actions.0002.json | 1029 +++++ ...i_v1_history_get_actions.0002.request_json | 3 + .../fio-api_v1_history_get_actions.json | 547 +++ ...io-api_v1_history_get_actions.request_json | 3 + ...98FB42C439E5F6484f7E71Caa6661d81d0628.json | 1 + ...F2e81B0264177e0df8f275f97Fd74Fa51A896.json | 1 + ...aHD19jymYt6fGd9TqSDQFfQj__details_txs.json | 110 + ...rWk4Fpaev1N6QSp1aNnP5JPf__details_txs.json | 1 + mock/ext-api-data/harmony-api.json | 84 + mock/ext-api-data/harmony-api.request_json | 11 + ...eb11fee922896e9f51490e62b12e_count_25.json | 53 + ...wekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json | 9 + ...g808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5.json | 9 + ...mkc9j0xhzu6vdaw6g5__count_25_start_32.json | 555 +++ ...wekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json | 23 + ...api_staking_validators__status_bonded.json | 794 ++++ ...8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json | 1 + .../kava-api_minting_inflation.json | 4 + ...v447c694k3jndelc9ygtfll2m_delegations.json | 4 + mock/ext-api-data/kava-api_staking_pool.json | 7 + ...api_staking_validators__status_bonded.json | 2371 +++++++++++ ...50cpzv447c694k3jndelc9ygtfll2m_page_1.json | 127 + ...8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json | 127 + ...AXIQNGH_payments__limit_25_order_desc.json | 750 ++++ ...ac4e094c51dc918087171150dd5b996076a__.json | 45 + ...9f19b7690b9dc50535cc135f67ea046e70bed.json | 45 + .../kusama-api_scan_transfers.json | 1 + .../kusama-api_scan_transfers.request_json | 4 + ...ngf6t9td2dxtey9d7985eept__details_txs.json | 1081 +++++ ...8kR3WPtGPn8Lrg677MQ8YeKu__details_txs.json | 1 + mock/ext-api-data/nano-api.json | 69 + mock/ext-api-data/nano-api.request_json | 5 + ...RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a_p_0.json | 845 ++++ mock/ext-api-data/nimiq-rpc.json | 51 + mock/ext-api-data/nimiq-rpc.request_json | 9 + ...nsactions__page_number_1_page_size_20.json | 478 +++ ...79D544B4b13bC3560069cfD56A9D5bbE7521d.json | 252 ++ ...bC3560069cfD56A9D5bbE7521d_limit_1000.json | 620 +++ ...5BCab22dE3d02402bc38aEe4104e1239374a7.json | 1 + ...98eCbF17ce1241d543c22dCE46134c13b4bc0.json | 1 + ...Z1J1AEHtgH3JWM7uLBNAejLZ__details_txs.json | 330 ++ ...42w6xTL2UjKyh2W9V88sXoNd__details_txs.json | 1842 ++++++++ ...8DtmhKy5bddFwRCTZaunjpvo__details_txs.json | 110 + ...5arxekekGpNyVLsWihYAfC5B__details_txs.json | 393 ++ ...escending_false_limit_25_type_Payment.json | 1977 +++++++++ ...ACCWNMX_payments__limit_25_order_desc.json | 792 ++++ ...61ffba516ec4f2e039440ec02a5522b388f2c.json | 52 + ...3ed14820228913142f8c6a5cd360783c029__.json | 52 + ...rder_desc_type_transaction_delegation.json | 163 + ...e_limitNumber_100_pageNumber_1_type_2.json | 2527 +++++++++++ ...30def08139f18a86536d9cfa150f04435414c.json | 1 + ...30def08139f18a86536d9cfa150f04435414c.json | 1 + ...53021189375591723e7384262f45709a3c3dc.json | 1 + ...4c16605e32adead5fa371bf6117df34ca0200.json | 1 + ...ts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB.json | 77 + ...der_by_block_timestamp_desc_token_id_.json | 795 ++++ .../tron-api_v1_assets_1002000.json | 23 + .../tron-api_v1_assets_1002798.json | 24 + .../tron-api_v1_assets_1002814.json | 24 + .../tron-api_wallet_getaccount.json | 1 + .../tron-api_wallet_getaccount.request_json | 1 + .../tron-api_wallet_listwitnesses.json | 1617 ++++++++ ...ppabledomains_api_v1__dpantani.crypto.json | 23 + ...stoppabledomains_api_v1__dpantani.zil.json | 23 + .../ext-api-data/vechain-api_blocks_best.json | 20 + .../vechain-api_logs_transfer.json | 197 + .../vechain-api_logs_transfer.request_json | 20 + ...4a1d54ab95451bee488869f417b351857c3c5.json | 25 + ...dfa52f7150173945103d203fae26b8e3d2ed7.json | 25 + ...SzbYjiMDs1jku9wAh1Ri2Y1A__details_txs.json | 1 + ...nVJ8ECCtwmKqCo6TJm2ZsFJK__details_txs.json | 1814 ++++++++ ...qriJs2y7Z45wmbLrbmV9MDecbPxD_limit_25.json | 183 + ...s4RPtUpeyUD1eYd47inL3bwX__details_txs.json | 1 + ...n6ynHnXW3jczPcJcenThfFeS__details_txs.json | 1770 ++++++++ ...gEn9hm2NL5KfFK1UmSZZaQVn__details_txs.json | 1 + ...kLQQyRxeEBmWHaETS2btF5fK__details_txs.json | 1 + ...GfPV1z48rvoLyabk31z3xwHa__details_txs.json | 1 + ...J56cEaTJGCba5GKv55wPNZNf__details_txs.json | 1463 +++++++ ...vejeam70qang54wnqkgtmlu5mwlgzy64z_txs.json | 30 + mock/ext-api-dyson/dyson.json | 6 - .../get/aeternity-api-transactions.js | 60 - .../get/aion-get-getTransactionsByAddress.js | 75 - .../ext-api-dyson/get/algorand-api-account.js | 41 - mock/ext-api-dyson/get/algorand-api-block.js | 61 - .../get/binance-rpc-commands2.js | 143 - mock/ext-api-dyson/get/binance-rpc-txs.js | 69 - mock/ext-api-dyson/get/bitcoin-api-address.js | 113 - mock/ext-api-dyson/get/bitcoin-api-xpub.js | 168 - .../get/bitcoincash-api-address.js | 1391 ------- .../ext-api-dyson/get/bitcoincash-api-xpub.js | 184 - .../get/callisto-api-commands1.js | 84 - .../ext-api-dyson/get/cosmos-api-commands2.js | 3686 ----------------- .../ext-api-dyson/get/cosmos-api-commands4.js | 42 - mock/ext-api-dyson/get/dash-api-address.js | 112 - mock/ext-api-dyson/get/dash-api-xpub.js | 175 - mock/ext-api-dyson/get/decred-api-address.js | 120 - mock/ext-api-dyson/get/decred-api-xpub.js | 122 - .../ext-api-dyson/get/digibyte-api-address.js | 123 - mock/ext-api-dyson/get/digibyte-api-xpub.js | 123 - mock/ext-api-dyson/get/doge-api-address.js | 121 - mock/ext-api-dyson/get/doge-api-xpub.js | 126 - mock/ext-api-dyson/get/dyson-ping.js | 11 - mock/ext-api-dyson/get/eth-api-commands1.js | 194 - .../get/eth-blockbook-api-transactions.js | 159 - .../get/ethclassic-api-commands1.js | 89 - .../get/gochain-api-commands1.js | 83 - .../get/groestlcoin-api-address.js | 127 - .../ext-api-dyson/get/groestlcoin-api-xpub.js | 157 - mock/ext-api-dyson/get/icon-api-actions.js | 72 - mock/ext-api-dyson/get/iotex-api-commands2.js | 821 ---- mock/ext-api-dyson/get/iotex-api-commands4.js | 108 - mock/ext-api-dyson/get/kava-api-commands2.js | 2628 ------------ mock/ext-api-dyson/get/kava-api-commands4.js | 30 - mock/ext-api-dyson/get/kava-api-txs.js | 277 -- mock/ext-api-dyson/get/kin-api-accounts.js | 96 - .../ext-api-dyson/get/kin-api-transactions.js | 111 - .../ext-api-dyson/get/litecoin-api-address.js | 121 - mock/ext-api-dyson/get/litecoin-api-xpub.js | 166 - mock/ext-api-dyson/get/nebulas-api-tx.js | 132 - .../get/ontolotgy-api-v2-addresses.js | 123 - .../ext-api-dyson/get/opensea-api-command1.js | 862 ---- mock/ext-api-dyson/get/poa-api-commands1.js | 138 - mock/ext-api-dyson/get/qtum-api-address.js | 160 - mock/ext-api-dyson/get/qtum-api-xpub.js | 164 - .../get/ravencoin-api-address.js | 123 - mock/ext-api-dyson/get/ravencoin-api-xpub.js | 176 - mock/ext-api-dyson/get/ripple-get-accounts.js | 204 - .../ext-api-dyson/get/stellar-api-accounts.js | 98 - .../get/stellar-api-transactions.js | 117 - .../get/tezos-api-transactions.js | 182 - mock/ext-api-dyson/get/theta-api-accounttx.js | 94 - .../get/thundertoken-api-commands1.js | 100 - .../get/tomochain-api-commands1.js | 89 - .../ext-api-dyson/get/tron-api-v1-accounts.js | 188 - mock/ext-api-dyson/get/tron-api-v1-assets.js | 101 - mock/ext-api-dyson/get/tron-api-wallet.js | 88 - .../get/unstoppabledomains-lookup.js | 38 - .../ext-api-dyson/get/vechain-api-entities.js | 106 - mock/ext-api-dyson/get/viacoin-api-address.js | 89 - mock/ext-api-dyson/get/viacoin-api-xpub.js | 87 - .../get/waves-api-transactions-address.js | 60 - mock/ext-api-dyson/get/zcash-api-address.js | 149 - mock/ext-api-dyson/get/zcash-api-xpub.js | 126 - mock/ext-api-dyson/get/zcoin-api-address.js | 124 - mock/ext-api-dyson/get/zcoin-api-xpub.js | 422 -- mock/ext-api-dyson/get/zelcash-api-address.js | 137 - mock/ext-api-dyson/get/zelcash-api-xpub.js | 196 - .../get/zilliqa-api-addresses-txs.js | 49 - mock/ext-api-dyson/post/eth-rpc.js | 81 - mock/ext-api-dyson/post/fio-api-chain.js | 41 - mock/ext-api-dyson/post/fio-api-history.js | 1498 ------- mock/ext-api-dyson/post/harmony-api.js | 83 - mock/ext-api-dyson/post/kusama-api.js | 64 - mock/ext-api-dyson/post/nano-api.js | 48 - mock/ext-api-dyson/post/nimiq-rpc.js | 66 - mock/ext-api-dyson/post/tron-api-wallet.js | 17 - mock/ext-api-dyson/post/vechain-api-logs.js | 50 - mock/mockserver/mock-healthcheck.json | 4 + mock/mockserver/mockserver.go | 232 ++ mock/mockserver/mockserver_test.go | 67 + .../blockatlas.postman_collection.json | 4 +- 224 files changed, 38065 insertions(+), 19144 deletions(-) create mode 100644 mock/README.md create mode 100644 mock/datafiles.yaml create mode 100644 mock/ext-api-data/aeternity-api_middleware_transactions_account_ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb.json create mode 100644 mock/ext-api-data/aion-api_getTransactionsByAddress__accountAddress_0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed_size_25.json create mode 100644 mock/ext-api-data/algorand-api_v1_account_4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U_transactions.json create mode 100644 mock/ext-api-data/algorand-api_v1_block_5478346.json create mode 100644 mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q create mode 100644 mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json create mode 100644 mock/ext-api-data/binance-explorer_v1_txs__address_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q_txAsset_BNB_txType_TRANSFER.json create mode 100644 mock/ext-api-data/bitcoin-api_v2_address_bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj__details_txs.json create mode 100644 mock/ext-api-data/bitcoin-api_v2_xpub_zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC__details_txs.json create mode 100644 mock/ext-api-data/bitcoincash-api_v2_address_bitcoincash_qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme__details_txs.json create mode 100644 mock/ext-api-data/bitcoincash-api_v2_xpub_xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX__details_txs.json create mode 100644 mock/ext-api-data/callisto-api_tokens__address_0xc3d5b69f65027ddf48f894e6e90121293a2f6615.json create mode 100644 mock/ext-api-data/callisto-api_transactions__address_0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7.json create mode 100644 mock/ext-api-data/cosmos-api_auth_accounts_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json create mode 100644 mock/ext-api-data/cosmos-api_minting_inflation.json create mode 100644 mock/ext-api-data/cosmos-api_staking_delegators_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_delegations.json create mode 100644 mock/ext-api-data/cosmos-api_staking_pool.json create mode 100644 mock/ext-api-data/cosmos-api_staking_validators__status_bonded.json create mode 100644 mock/ext-api-data/cosmos-api_txs__limit_25_message.sender_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_page_1.json create mode 100644 mock/ext-api-data/cosmos-api_txs__limit_25_page_1_transfer.recipient_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json create mode 100644 mock/ext-api-data/dash-api_v2_address_XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG__details_txs.json create mode 100644 mock/ext-api-data/dash-api_v2_xpub_xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD__details_txs.json create mode 100644 mock/ext-api-data/decred-api_v2_address_DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY__details_txs.json create mode 100644 mock/ext-api-data/decred-api_v2_xpub_dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN__details_txs.json create mode 100644 mock/ext-api-data/digibyte-api_v2_address_DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi__details_txs.json create mode 100644 mock/ext-api-data/digibyte-api_v2_xpub_zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow__details_txs.json create mode 100644 mock/ext-api-data/doge-api_v2_address_D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh__details_txs.json create mode 100644 mock/ext-api-data/doge-api_v2_xpub_dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN__details_txs.json create mode 100644 mock/ext-api-data/eth-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json create mode 100644 mock/ext-api-data/eth-api_transactions__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json create mode 100644 mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_tokenBalances.json create mode 100644 mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_txs.json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.request_json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.request_json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835.json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835.request_json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.request_json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.request_json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c.json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c.request_json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c.json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c.request_json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c.json create mode 100644 mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c.request_json create mode 100644 mock/ext-api-data/ethclassic-api_tokens__address_0xa12105efa0663147bddee178f6a741ac15676b79.json create mode 100644 mock/ext-api-data/ethclassic-api_transactions__address_0x7d2d0e153026fb428b885d86de50768d4cfeac37.json create mode 100644 mock/ext-api-data/fio-api_v1_chain_get_pub_address.0001.json create mode 100644 mock/ext-api-data/fio-api_v1_chain_get_pub_address.0001.request_json create mode 100644 mock/ext-api-data/fio-api_v1_chain_get_pub_address.0002.json create mode 100644 mock/ext-api-data/fio-api_v1_chain_get_pub_address.0002.request_json create mode 100644 mock/ext-api-data/fio-api_v1_chain_get_pub_address.json create mode 100644 mock/ext-api-data/fio-api_v1_chain_get_pub_address.request_json create mode 100644 mock/ext-api-data/fio-api_v1_history_get_actions.0001.json create mode 100644 mock/ext-api-data/fio-api_v1_history_get_actions.0001.request_json create mode 100644 mock/ext-api-data/fio-api_v1_history_get_actions.0002.json create mode 100644 mock/ext-api-data/fio-api_v1_history_get_actions.0002.request_json create mode 100644 mock/ext-api-data/fio-api_v1_history_get_actions.json create mode 100644 mock/ext-api-data/fio-api_v1_history_get_actions.request_json create mode 100644 mock/ext-api-data/gochain-api_tokens__address_0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628.json create mode 100644 mock/ext-api-data/gochain-api_transactions__address_0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896.json create mode 100644 mock/ext-api-data/groestlcoin-api_v2_address_33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj__details_txs.json create mode 100644 mock/ext-api-data/groestlcoin-api_v2_xpub_zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf__details_txs.json create mode 100644 mock/ext-api-data/harmony-api.json create mode 100644 mock/ext-api-data/harmony-api.request_json create mode 100644 mock/ext-api-data/icon-api_address_txList__address_hxee691e7bccc4eb11fee922896e9f51490e62b12e_count_25.json create mode 100644 mock/ext-api-data/iotex-api_accounts_io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json create mode 100644 mock/ext-api-data/iotex-api_accounts_io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5.json create mode 100644 mock/ext-api-data/iotex-api_actions_addr_io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5__count_25_start_32.json create mode 100644 mock/ext-api-data/iotex-api_staking_delegations_io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json create mode 100644 mock/ext-api-data/iotex-api_staking_validators__status_bonded.json create mode 100644 mock/ext-api-data/kava-api_auth_accounts_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json create mode 100644 mock/ext-api-data/kava-api_minting_inflation.json create mode 100644 mock/ext-api-data/kava-api_staking_delegators_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_delegations.json create mode 100644 mock/ext-api-data/kava-api_staking_pool.json create mode 100644 mock/ext-api-data/kava-api_staking_validators__status_bonded.json create mode 100644 mock/ext-api-data/kava-api_txs__limit_25_message.sender_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_page_1.json create mode 100644 mock/ext-api-data/kava-api_txs__limit_25_page_1_transfer.recipient_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json create mode 100644 mock/ext-api-data/kin-api_accounts_GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH_payments__limit_25_order_desc.json create mode 100644 mock/ext-api-data/kin-api_transactions_b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a__.json create mode 100644 mock/ext-api-data/kin-api_transactions_eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed.json create mode 100644 mock/ext-api-data/kusama-api_scan_transfers.json create mode 100644 mock/ext-api-data/kusama-api_scan_transfers.request_json create mode 100644 mock/ext-api-data/litecoin-api_v2_address_ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept__details_txs.json create mode 100644 mock/ext-api-data/litecoin-api_v2_xpub_zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu__details_txs.json create mode 100644 mock/ext-api-data/nano-api.json create mode 100644 mock/ext-api-data/nano-api.request_json create mode 100644 mock/ext-api-data/nebulas-api_tx__a_n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a_p_0.json create mode 100644 mock/ext-api-data/nimiq-rpc.json create mode 100644 mock/ext-api-data/nimiq-rpc.request_json create mode 100644 mock/ext-api-data/ontology-api_v2_addresses_AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7_transactions__page_number_1_page_size_20.json create mode 100644 mock/ext-api-data/opensea-api_api_v1_assets___collection_unstoppable-domains_limit_300_owner_0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d.json create mode 100644 mock/ext-api-data/opensea-api_api_v1_collections___asset_owner_0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d_limit_1000.json create mode 100644 mock/ext-api-data/poa-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json create mode 100644 mock/ext-api-data/poa-api_transactions__address_0x55798eCbF17ce1241d543c22dCE46134c13b4bc0.json create mode 100644 mock/ext-api-data/qtum-api_v2_address_QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ__details_txs.json create mode 100644 mock/ext-api-data/qtum-api_v2_xpub_xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd__details_txs.json create mode 100644 mock/ext-api-data/ravencoin-api_v2_address_RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo__details_txs.json create mode 100644 mock/ext-api-data/ravencoin-api_v2_xpub_xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B__details_txs.json create mode 100644 mock/ext-api-data/ripple-api_accounts_rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1_transactions__descending_false_limit_25_type_Payment.json create mode 100644 mock/ext-api-data/stellar-api_accounts_GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX_payments__limit_25_order_desc.json create mode 100644 mock/ext-api-data/stellar-api_transactions_23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c.json create mode 100644 mock/ext-api-data/stellar-api_transactions_2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029__.json create mode 100644 mock/ext-api-data/tezos-api_account_tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8_op__limit_25_order_desc_type_transaction_delegation.json create mode 100644 mock/ext-api-data/theta-api_accounttx_0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f__isEqualType_true_limitNumber_100_pageNumber_1_type_2.json create mode 100644 mock/ext-api-data/thundertoken-api_tokens__address_0x0b230def08139f18a86536d9cfa150f04435414c.json create mode 100644 mock/ext-api-data/thundertoken-api_transactions__address_0x0b230def08139f18a86536d9cfa150f04435414c.json create mode 100644 mock/ext-api-data/tomochain-api_tokens__address_0x8b353021189375591723e7384262f45709a3c3dc.json create mode 100644 mock/ext-api-data/tomochain-api_transactions__address_0x17e4c16605e32adead5fa371bf6117df34ca0200.json create mode 100644 mock/ext-api-data/tron-api_v1_accounts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB.json create mode 100644 mock/ext-api-data/tron-api_v1_accounts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB_transactions__limit_25_order_by_block_timestamp_desc_token_id_.json create mode 100644 mock/ext-api-data/tron-api_v1_assets_1002000.json create mode 100644 mock/ext-api-data/tron-api_v1_assets_1002798.json create mode 100644 mock/ext-api-data/tron-api_v1_assets_1002814.json create mode 100644 mock/ext-api-data/tron-api_wallet_getaccount.json create mode 100644 mock/ext-api-data/tron-api_wallet_getaccount.request_json create mode 100644 mock/ext-api-data/tron-api_wallet_listwitnesses.json create mode 100644 mock/ext-api-data/unstoppabledomains_api_v1__dpantani.crypto.json create mode 100644 mock/ext-api-data/unstoppabledomains_api_v1__dpantani.zil.json create mode 100644 mock/ext-api-data/vechain-api_blocks_best.json create mode 100644 mock/ext-api-data/vechain-api_logs_transfer.json create mode 100644 mock/ext-api-data/vechain-api_logs_transfer.request_json create mode 100644 mock/ext-api-data/vechain-api_transactions_0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5.json create mode 100644 mock/ext-api-data/vechain-api_transactions_0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7.json create mode 100644 mock/ext-api-data/viacoin-api_v2_address_VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A__details_txs.json create mode 100644 mock/ext-api-data/viacoin-api_v2_xpub_zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK__details_txs.json create mode 100644 mock/ext-api-data/waves-api_transactions_address_3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD_limit_25.json create mode 100644 mock/ext-api-data/zcash-api_v2_address_t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX__details_txs.json create mode 100644 mock/ext-api-data/zcash-api_v2_xpub_xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS__details_txs.json create mode 100644 mock/ext-api-data/zcoin-api_v2_address_a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn__details_txs.json create mode 100644 mock/ext-api-data/zcoin-api_v2_xpub_xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK__details_txs.json create mode 100644 mock/ext-api-data/zelcash-api_v2_address_t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa__details_txs.json create mode 100644 mock/ext-api-data/zelcash-api_v2_xpub_xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf__details_txs.json create mode 100644 mock/ext-api-data/zilliqa-api_addresses_zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z_txs.json delete mode 100644 mock/ext-api-dyson/dyson.json delete mode 100644 mock/ext-api-dyson/get/aeternity-api-transactions.js delete mode 100644 mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js delete mode 100644 mock/ext-api-dyson/get/algorand-api-account.js delete mode 100644 mock/ext-api-dyson/get/algorand-api-block.js delete mode 100644 mock/ext-api-dyson/get/binance-rpc-commands2.js delete mode 100644 mock/ext-api-dyson/get/binance-rpc-txs.js delete mode 100644 mock/ext-api-dyson/get/bitcoin-api-address.js delete mode 100644 mock/ext-api-dyson/get/bitcoin-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/bitcoincash-api-address.js delete mode 100644 mock/ext-api-dyson/get/bitcoincash-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/callisto-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/cosmos-api-commands2.js delete mode 100644 mock/ext-api-dyson/get/cosmos-api-commands4.js delete mode 100644 mock/ext-api-dyson/get/dash-api-address.js delete mode 100644 mock/ext-api-dyson/get/dash-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/decred-api-address.js delete mode 100644 mock/ext-api-dyson/get/decred-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/digibyte-api-address.js delete mode 100644 mock/ext-api-dyson/get/digibyte-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/doge-api-address.js delete mode 100644 mock/ext-api-dyson/get/doge-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/dyson-ping.js delete mode 100644 mock/ext-api-dyson/get/eth-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/eth-blockbook-api-transactions.js delete mode 100644 mock/ext-api-dyson/get/ethclassic-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/gochain-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/groestlcoin-api-address.js delete mode 100644 mock/ext-api-dyson/get/groestlcoin-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/icon-api-actions.js delete mode 100644 mock/ext-api-dyson/get/iotex-api-commands2.js delete mode 100644 mock/ext-api-dyson/get/iotex-api-commands4.js delete mode 100644 mock/ext-api-dyson/get/kava-api-commands2.js delete mode 100644 mock/ext-api-dyson/get/kava-api-commands4.js delete mode 100644 mock/ext-api-dyson/get/kava-api-txs.js delete mode 100644 mock/ext-api-dyson/get/kin-api-accounts.js delete mode 100644 mock/ext-api-dyson/get/kin-api-transactions.js delete mode 100644 mock/ext-api-dyson/get/litecoin-api-address.js delete mode 100644 mock/ext-api-dyson/get/litecoin-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/nebulas-api-tx.js delete mode 100644 mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js delete mode 100644 mock/ext-api-dyson/get/opensea-api-command1.js delete mode 100644 mock/ext-api-dyson/get/poa-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/qtum-api-address.js delete mode 100644 mock/ext-api-dyson/get/qtum-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/ravencoin-api-address.js delete mode 100644 mock/ext-api-dyson/get/ravencoin-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/ripple-get-accounts.js delete mode 100644 mock/ext-api-dyson/get/stellar-api-accounts.js delete mode 100644 mock/ext-api-dyson/get/stellar-api-transactions.js delete mode 100644 mock/ext-api-dyson/get/tezos-api-transactions.js delete mode 100644 mock/ext-api-dyson/get/theta-api-accounttx.js delete mode 100644 mock/ext-api-dyson/get/thundertoken-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/tomochain-api-commands1.js delete mode 100644 mock/ext-api-dyson/get/tron-api-v1-accounts.js delete mode 100644 mock/ext-api-dyson/get/tron-api-v1-assets.js delete mode 100644 mock/ext-api-dyson/get/tron-api-wallet.js delete mode 100644 mock/ext-api-dyson/get/unstoppabledomains-lookup.js delete mode 100644 mock/ext-api-dyson/get/vechain-api-entities.js delete mode 100644 mock/ext-api-dyson/get/viacoin-api-address.js delete mode 100644 mock/ext-api-dyson/get/viacoin-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/waves-api-transactions-address.js delete mode 100644 mock/ext-api-dyson/get/zcash-api-address.js delete mode 100644 mock/ext-api-dyson/get/zcash-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/zcoin-api-address.js delete mode 100644 mock/ext-api-dyson/get/zcoin-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/zelcash-api-address.js delete mode 100644 mock/ext-api-dyson/get/zelcash-api-xpub.js delete mode 100644 mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js delete mode 100644 mock/ext-api-dyson/post/eth-rpc.js delete mode 100644 mock/ext-api-dyson/post/fio-api-chain.js delete mode 100644 mock/ext-api-dyson/post/fio-api-history.js delete mode 100644 mock/ext-api-dyson/post/harmony-api.js delete mode 100644 mock/ext-api-dyson/post/kusama-api.js delete mode 100644 mock/ext-api-dyson/post/nano-api.js delete mode 100644 mock/ext-api-dyson/post/nimiq-rpc.js delete mode 100644 mock/ext-api-dyson/post/tron-api-wallet.js delete mode 100644 mock/ext-api-dyson/post/vechain-api-logs.js create mode 100644 mock/mockserver/mock-healthcheck.json create mode 100644 mock/mockserver/mockserver.go create mode 100644 mock/mockserver/mockserver_test.go diff --git a/Makefile b/Makefile index 6a70a5604..0342a453c 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ PID_OBSERVER_NOTIFIER := /tmp/.$(PROJECT_NAME).$(OBSERVER_NOTIFIER).pid PID_OBSERVER_PARSER := /tmp/.$(PROJECT_NAME).$(OBSERVER_PARSER).pid PID_OBSERVER_SUBSCRIBER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SUBSCRIBER).pid PID_SWAGGER_API := /tmp/.$(PROJECT_NAME).$(SWAGGER_API).pid -PID_DYSON := /tmp/.$(PROJECT_NAME).dyson.pid +PID_MOCKSERVER := /tmp/.$(PROJECT_NAME).mockserver.pid # Make is verbose in Linux. Make it silent. MAKEFLAGS += --silent @@ -58,7 +58,7 @@ start-platform-api: stop @echo " > Error log: $(STDERR)" # start-platform-api-mock: Start API. Similar to start-platform-api, but uses config file with mock URLs, and port 8437. -start-platform-api-mock: stop start-mock-dyson +start-platform-api-mock: stop start-mockserver @echo " > Starting $(PROJECT_NAME) API" @-$(GOBIN)/$(API_SERVICE)/platform_api -p 8437 -c $(CONFIG_MOCK_FILE) 2>&1 & echo $$! > $(PID_API) @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" @@ -94,19 +94,19 @@ start-observer-subscriber: stop ## stop: Stop development mode. stop: - @-touch $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) $(PID_DYSON) + @-touch $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) $(PID_MOCKSERVER) @-kill `cat $(PID_API)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER_NOTIFIER)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER_PARSER)` 2> /dev/null || true @-kill `cat $(PID_OBSERVER_SUBSCRIBER)` 2> /dev/null || true @-kill `cat $(PID_SWAGGER_API)` 2> /dev/null || true - @-kill `cat $(PID_DYSON)` 2> /dev/null || true - @-rm $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) $(PID_DYSON) + @-kill `cat $(PID_MOCKSERVER)` 2> /dev/null || true + @-rm $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) $(PID_MOCKSERVER) -stop-dyson: - @-touch $(PID_DYSON) - @kill `cat $(PID_DYSON)` 2> /dev/null || true - @rm $(PID_DYSON) +stop-mockserver: + @-touch $(PID_MOCKSERVER) + @kill `cat $(PID_MOCKSERVER)` 2> /dev/null || true + @rm $(PID_MOCKSERVER) ## compile: Compile the project. compile: @@ -130,11 +130,13 @@ test: go-test ## integration: Run all integration tests. integration: go-integration -## start-mock-dyson: Start Dyson with mocks of external services. Make sure not to swallow error code in case port is taken. -start-mock-dyson: stop-dyson - @echo " > Starting Dyson with mocks" - @-dyson mock/ext-api-dyson & echo $$! > $(PID_DYSON) - @echo " > Dyson started with PID: " `cat $(PID_DYSON)` +## start-mockserver: Start Mockserver with mocks of external services. Test that it is operational (nasty case if port is taken). +start-mockserver: stop-mockserver + @echo " > Starting Mockserver" + GOBIN=$(GOBIN) go build -o $(GOBIN)/mockserver/mockserver ./mock/mockserver + @-./bin/mockserver/mockserver & echo $$! > $(PID_MOCKSERVER) + @echo " > Mockserver started with PID: " `cat $(PID_MOCKSERVER)` + @sleep 1 # Check that mock is running, by making a test with simple call (e.g. may fail due to unavailable port) @newman run tests/postman/blockatlas.postman_collection.json --folder mock-healthcheck --env-var "host=http://localhost:8437" @@ -169,7 +171,7 @@ ifeq (,$(shell which newman)) endif ## newman-mocked: Run mocked Postman Newman tests. -newman-mocked: install-newman install-dyson go-compile +newman-mocked: install-newman go-compile @bash -c "$(MAKE) newman-mocked-params host=http://localhost:8437" ## newman-mocked-params: Run mocked Postman Newman tests, after starting platform api. @@ -210,13 +212,6 @@ endif @echo " > Running $(test) tests" @newman run tests/postman/blockatlas.postman_collection.json --folder $(test) -d tests/postman/$(test)_data.json --env-var "host=$(host)" -## install-dyson: Install Dyson for mocked tests. -install-dyson: -ifeq (,$(shell which dyson)) - @echo " > Installing Dyson" - @-sudo npm install -g dyson -endif - go-compile: go-get go-build go-build: go-build-platform-api go-build-observer-notifier go-build-observer-parser go-build-observer-subscriber go-build-swagger-api diff --git a/README.md b/README.md index c255a8eea..83af69774 100644 --- a/README.md +++ b/README.md @@ -190,18 +190,17 @@ make test ``` ### Mocked tests -End-to-end tests with calls to external APIs has great value, but is not suitable for regular CI verification, as any external reasons could break the tests. +End-to-end tests with calls to external APIs has great value, but they are not suitable for regular CI verification, beacuse any external reason could break the tests. Therefore mocked API-level tests are used, whereby external APIs are replaced by mocks. -* External mocks are implemented using *dyson*, as javascript files. They generally return constant, pre-canned responses to the requests that occur during tests. -* Mocks are 'turned on' by corresponding API endpoints in the configmock.yml config file (localhost:3347). +* External mocks are implemented as a simple, own, golang `mockserver`. It listens locally, and returns responses to specific API paths, taken from json data files. +* There is a file where API paths and corresponding data files are listed. * Tests invoke into blockatlas through public APIs only, and are executed using *newman* (Postman cli -- `make newman-mocked`). * Product code, and even test code should not be aware whether it runs with mocks or the real external endpoints. * See Makefile for targets with 'mock'; platform can be started locally with mocks using `make start-platform-api-mock`. -* When dyson is started (e.g. with `make start-platform-api-mock`), it outputs requests, which helps debugging * The newman tests can be executed with unmocked external APIs as well, but verifications may fail, because some APIs return variable responses. Unmocked tests are not intended for regular CI execution, but as ad-hoc development tests. -* General steps for creating new mocked tests: replace endpoint to localhost:3347, observer incoming calls (dyson output), obtain real response from external API (with exact same parameters), enhance dsyon script to return the same output, verify that blockatlas provides correct output. Also, add verifications of results to the tests. +* General steps for creating new mocked tests: replace endpoint to localhost:3347, observe incoming calls (visible in mockserver's output), obtain real response from external API (with exact same parameters), place response in a file, add path + file to data file list. Restart mock, and verify that blockatlas provides correct output. Also, add verifications of results to the tests. ## Docs diff --git a/configmock.yml b/configmock.yml index 95b934cc0..54476ca9e 100644 --- a/configmock.yml +++ b/configmock.yml @@ -33,53 +33,53 @@ postgres: # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org binance: - api: https://dex.binance.org/api - explorer: http://localhost:3347/binance-explorer/api + api: http://localhost:3347/mock/binance-api + explorer: http://localhost:3347/mock/binance-explorer # [NIM] Nimiq: https://nimiq.com nimiq: - api: http://localhost:3347/nimiq-rpc + api: http://localhost:3347/mock/nimiq-rpc # [XRP] Ripple: https://ripple.com ripple: - api: http://localhost:3347/ripple-api + api: http://localhost:3347/mock/ripple-api # [XLM] Stellar Lumen: https://www.stellar.org stellar: - api: http://localhost:3347/stellar-api + api: http://localhost:3347/mock/stellar-api # [KIN] Kin: https://www.kin.org kin: - api: http://localhost:3347/kin-api + api: http://localhost:3347/mock/kin-api # [XTZ] Tezos: https://tezos.com tezos: - api: http://localhost:3347/tezos-api + api: http://localhost:3347/mock/tezos-api rpc: https://mainnet.tezos.org.ua # [ETH] Ethereum: https://ethereum.org (Trust-Ray API) ethereum: - api: http://localhost:3347/eth-api - blockbook_api: http://localhost:3347/eth-blockbook-api - collections_api: http://localhost:3347/opensea-api + api: http://localhost:3347/mock/eth-api + blockbook_api: http://localhost:3347/mock/eth-blockbook-api + collections_api: http://localhost:3347/mock/opensea-api collections_api_key: opensea_api_key - rpc: http://localhost:3347/eth-rpc + rpc: http://localhost:3347/mock/eth-rpc # [ETC] Ethereum Classic: https://ethereumclassic.org (Trust-Ray API) classic: - api: http://localhost:3347/ethclassic-api + api: http://localhost:3347/mock/ethclassic-api # [POA] POA Network: https://poa.network (Trust-Ray API) poa: - api: http://localhost:3347/poa-api + api: http://localhost:3347/mock/poa-api # [CLO] Callisto Network: https://callisto.network (Trust-Ray API) callisto: - api: http://localhost:3347/callisto-api + api: http://localhost:3347/mock/callisto-api # [GO] GoChain: https://gochain.io (Trust-Ray API) gochain: - api: http://localhost:3347/gochain-api + api: http://localhost:3347/mock/gochain-api # [WAN] Wanchain: https://wanchain.org (Trust-Ray API) # wanchain: @@ -87,120 +87,120 @@ gochain: # [TOMO] TomoChain: https://tomochain.com (Trust-Ray API) tomochain: - api: http://localhost:3347/tomochain-api + api: http://localhost:3347/mock/tomochain-api # [TT] ThunderCore: https://www.thundercore.com (Trust-Ray API) thundertoken: - api: http://localhost:3347/thundertoken-api + api: http://localhost:3347/mock/thundertoken-api # [AION] Aion: https://aion.network aion: - api: http://localhost:3347/aion-api + api: http://localhost:3347/mock/aion-api # [ICX] ICON: https://icon.foundation icon: - api: http://localhost:3347/icon-api + api: http://localhost:3347/mock/icon-api # [TRX] Tron: https://tron.network/ tron: - api: http://localhost:3347/tron-api + api: http://localhost:3347/mock/tron-api # [VET] VeChain: https://www.vechain.org vechain: - api: http://localhost:3347/vechain-api + api: http://localhost:3347/mock/vechain-api # [THETA] THETA: https://www.thetatoken.org/ theta: - api: http://localhost:3347/theta-api + api: http://localhost:3347/mock/theta-api # [ATOM] Cosmos: https://cosmos.network/ cosmos: - api: http://localhost:3347/cosmos-api + api: http://localhost:3347/mock/cosmos-api # [ONTOLOGY] ONT: https://ont.io/ ontology: - api: http://localhost:3347/ontology-api + api: http://localhost:3347/mock/ontology-api # [ZIL] Zilliqa: https://zilliqa.com zilliqa: - api: http://localhost:3347/zilliqa-api + api: http://localhost:3347/mock/zilliqa-api # key: YOUR_API_KEY rpc: https://api.zilliqa.com - lookup: http://localhost:3347/unstoppabledomains/api/v1 + lookup: http://localhost:3347/mock/unstoppabledomains/api/v1 #[IoTeX] IoTeX: https://iotex.io iotex: - api: http://localhost:3347/iotex-api + api: http://localhost:3347/mock/iotex-api # [WAVES] Waves: http://wavesplatform.com waves: - api: http://localhost:3347/waves-api + api: http://localhost:3347/mock/waves-api # [AE] Aeternity: https://aeternity.com aeternity: - api: http://localhost:3347/aeternity-api + api: http://localhost:3347/mock/aeternity-api # [NAS] Nebulas: https://nebulas.io nebulas: - api: http://localhost:3347/nebulas-api + api: http://localhost:3347/mock/nebulas-api fio: - api: http://localhost:3347/fio-api + api: http://localhost:3347/mock/fio-api # [BTC] Bitcoin: https://bitcoin.org/ (Blockbook API https://github.com/trezor/blockbook) bitcoin: - api: http://localhost:3347/bitcoin-api + api: http://localhost:3347/mock/bitcoin-api litecoin: - api: http://localhost:3347/litecoin-api + api: http://localhost:3347/mock/litecoin-api bitcoincash: - api: http://localhost:3347/bitcoincash-api + api: http://localhost:3347/mock/bitcoincash-api doge: - api: http://localhost:3347/doge-api + api: http://localhost:3347/mock/doge-api dash: - api: http://localhost:3347/dash-api + api: http://localhost:3347/mock/dash-api zcoin: - api: http://localhost:3347/zcoin-api + api: http://localhost:3347/mock/zcoin-api zcash: - api: http://localhost:3347/zcash-api + api: http://localhost:3347/mock/zcash-api zelcash: - api: http://localhost:3347/zelcash-api + api: http://localhost:3347/mock/zelcash-api viacoin: - api: http://localhost:3347/viacoin-api + api: http://localhost:3347/mock/viacoin-api qtum: - api: http://localhost:3347/qtum-api + api: http://localhost:3347/mock/qtum-api groestlcoin: - api: http://localhost:3347/groestlcoin-api + api: http://localhost:3347/mock/groestlcoin-api ravencoin: - api: http://localhost:3347/ravencoin-api + api: http://localhost:3347/mock/ravencoin-api decred: - api: http://localhost:3347/decred-api + api: http://localhost:3347/mock/decred-api algorand: - api: http://localhost:3347/algorand-api + api: http://localhost:3347/mock/algorand-api nano: - api: http://localhost:3347/nano-api + api: http://localhost:3347/mock/nano-api digibyte: - api: http://localhost:3347/digibyte-api + api: http://localhost:3347/mock/digibyte-api harmony: - api: http://localhost:3347/harmony-api + api: http://localhost:3347/mock/harmony-api kava: - api: http://localhost:3347/kava-api + api: http://localhost:3347/mock/kava-api kusama: - api: http://localhost:3347/kusama-rpc + api: http://localhost:3347/mock/kusama-rpc diff --git a/mock/README.md b/mock/README.md new file mode 100644 index 000000000..6ce727122 --- /dev/null +++ b/mock/README.md @@ -0,0 +1,29 @@ +# Test data files + +Responses for mock tests are stored in data files. +The mock uses these files to return canned responses. + +The data files can be updated, by reading and storing responses from the real external APIs. + +## File list + +There is a file `mock/datafiles.yaml` containing API paths and corresponding data files. + +Example: + +``` +- file: mock/ext-api-data/tron-api_v1_assets_1002814.json + mockURL: /mock/tron-api/v1/assets/1002814 + method: GET + extURL: https://api.trongrid.io/v1/assets/1002814 +``` + +Fields: + +* file: name of response data json file (relative to repository root). +* mockURL: the API path for this call, in the mock server. Usually starts with '/mock/'. +* method: GET or POST +* extURL: Optional. The full URL of the external reap API. Used to refresh the data file, manually during development, or automatically. +* reqFile: In case of POST requests, the json file containing POST request. Used to select which resposne to return, and when invoking external API. +* reqField: Optional. Some POST requests cannot be matched by full request json matching, because they contain a changing field, typically call id. In this case one field can be selected (.e.g 'address'), and input is matched by the field only. + diff --git a/mock/datafiles.yaml b/mock/datafiles.yaml new file mode 100644 index 000000000..4f9f4a3ff --- /dev/null +++ b/mock/datafiles.yaml @@ -0,0 +1,507 @@ +- file: mock/mockserver/mock-healthcheck.json + mockURL: /mock/mock-healthcheck + method: GET +- file: mock/ext-api-data/aeternity-api_middleware_transactions_account_ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb.json + mockURL: /mock/aeternity-api/middleware/transactions/account/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb + method: GET + extURL: https://mdw.aepps.com/middleware/transactions/account/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb +- file: mock/ext-api-data/aion-api_getTransactionsByAddress__accountAddress_0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed_size_25.json + mockURL: /mock/aion-api/getTransactionsByAddress?accountAddress=0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed&size=25 + method: GET + extURL: https://mainnet-api.theoan.com/aion/dashboard/getTransactionsByAddress?accountAddress=0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed&size=25 +- file: mock/ext-api-data/algorand-api_v1_account_4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U_transactions.json + mockURL: /mock/algorand-api/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions + method: GET + extURL: https://mainnet-algorand.api.purestake.io/ps1/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions +- file: mock/ext-api-data/algorand-api_v1_block_5478346.json + mockURL: /mock/algorand-api/v1/block/5478346 + method: GET + extURL: https://mainnet-algorand.api.purestake.io/ps1/v1/block/5478346 +- file: mock/ext-api-data/binance-explorer_v1_txs__address_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q_txAsset_BNB_txType_TRANSFER.json + mockURL: /mock/binance-explorer/v1/txs?address=bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q&txAsset=BNB&txType=TRANSFER + method: GET + extURL: https://explorer.binance.org/api/v1/txs?address=bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q&page=1&rows=20&txAsset=BNB&txType=TRANSFER +- file: mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q + mockURL: /mock/binance-api/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q + method: GET + extURL: https://dex.binance.org/api/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q +- file: mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json + mockURL: /mock/binance-api/v1/tokens?limit=1000 + method: GET + extURL: https://dex.binance.org/api/v1/tokens?limit=1000&offset=0 +- file: mock/ext-api-data/bitcoin-api_v2_address_bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj__details_txs.json + mockURL: /mock/bitcoin-api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs + method: GET + extURL: https://btc1.trezor.io/api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs&pageSize=10 +- file: mock/ext-api-data/bitcoin-api_v2_xpub_zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC__details_txs.json + mockURL: /mock/bitcoin-api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs + method: GET + extURL: https://btc1.trezor.io/api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs&pageSize=10 +- file: mock/ext-api-data/bitcoincash-api_v2_address_bitcoincash_qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme__details_txs.json + mockURL: /mock/bitcoincash-api/v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs + method: GET + extURL: https:///v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs&pageSize=5 +- file: mock/ext-api-data/bitcoincash-api_v2_xpub_xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX__details_txs.json + mockURL: /mock/bitcoincash-api/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs + method: GET + extURL: https:///api/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs&pageSize=10 +- file: mock/ext-api-data/callisto-api_tokens__address_0xc3d5b69f65027ddf48f894e6e90121293a2f6615.json + mockURL: /mock/callisto-api/tokens?address=0xc3d5b69f65027ddf48f894e6e90121293a2f6615 + method: GET + extURL: https:///tokens?address=0xc3d5b69f65027ddf48f894e6e90121293a2f6615 +- file: mock/ext-api-data/callisto-api_transactions__address_0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7.json + mockURL: /mock/callisto-api/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7 + method: GET + extURL: https:///transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7 +- file: mock/ext-api-data/cosmos-api_minting_inflation.json + mockURL: /mock/cosmos-api/minting/inflation + method: GET + extURL: https://api.cosmos.network/minting/inflation +- file: mock/ext-api-data/cosmos-api_staking_delegators_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_delegations.json + mockURL: /mock/cosmos-api/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/delegations + method: GET + extURL: https://api.cosmos.network/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/delegations +- file: mock/ext-api-data/cosmos-api_staking_delegators_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_delegations.json + mockURL: /mock/cosmos-api/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/unbonding_delegations + method: GET + extURL: https://api.cosmos.network/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/unbonding_delegations +- file: mock/ext-api-data/cosmos-api_staking_pool.json + mockURL: /mock/cosmos-api/staking/pool + method: GET + extURL: https://api.cosmos.network/staking/pool +- file: mock/ext-api-data/cosmos-api_staking_validators__status_bonded.json + mockURL: /mock/cosmos-api/staking/validators?status=bonded + method: GET + extURL: https://api.cosmos.network/staking/validators?status=bonded +- file: mock/ext-api-data/cosmos-api_txs__limit_25_message.sender_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_page_1.json + mockURL: /mock/cosmos-api/txs?limit=25&message.sender=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq&page=1 + method: GET + extURL: https://api.cosmos.network/txs?limit=25&message.sender=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq&page=1 +- file: mock/ext-api-data/cosmos-api_txs__limit_25_page_1_transfer.recipient_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json + mockURL: /mock/cosmos-api/txs?limit=25&page=1&transfer.recipient=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq + method: GET + extURL: https://api.cosmos.network/txs?limit=25&page=1&transfer.recipient=cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq +- file: mock/ext-api-data/cosmos-api_auth_accounts_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json + mockURL: /mock/cosmos-api/auth/accounts/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq + method: GET + extURL: https://api.cosmos.network/auth/accounts/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq +- file: mock/ext-api-data/dash-api_v2_address_XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG__details_txs.json + mockURL: /mock/dash-api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs + method: GET + extURL: https://dash1.trezor.io/api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs&pageSize=10 +- file: mock/ext-api-data/dash-api_v2_xpub_xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD__details_txs.json + mockURL: /mock/dash-api/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs + method: GET + extURL: https://dash1.trezor.io/api/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs&pageSize=10 +- file: mock/ext-api-data/decred-api_v2_address_DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY__details_txs.json + mockURL: /mock/decred-api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs + method: GET + extURL: https://blockbook.decred.org:9161/api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs&pageSize=10 +- file: mock/ext-api-data/decred-api_v2_xpub_dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN__details_txs.json + mockURL: /mock/decred-api/v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs + method: GET + extURL: https://blockbook.decred.org:9161/api/v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs&pageSize=10 +- file: mock/ext-api-data/digibyte-api_v2_address_DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi__details_txs.json + mockURL: /mock/digibyte-api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs + method: GET + extURL: https://dgb1.trezor.io/api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs&pageSize=10 +- file: mock/ext-api-data/digibyte-api_v2_xpub_zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow__details_txs.json + mockURL: /mock/digibyte-api/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs + method: GET + extURL: https://dgb1.trezor.io/api/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs&pageSize=10 +- file: mock/ext-api-data/doge-api_v2_address_D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh__details_txs.json + mockURL: /mock/doge-api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs + method: GET + extURL: https://doge1.trezor.io/api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs&pageSize=10 +- file: mock/ext-api-data/doge-api_v2_xpub_dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN__details_txs.json + mockURL: /mock/doge-api/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs + method: GET + extURL: https://doge1.trezor.io/api/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs&pageSize=10 +- file: mock/ext-api-data/eth-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json + mockURL: /mock/eth-api/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7 + method: GET + extURL: https://localhost:4567/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7 +- file: mock/ext-api-data/eth-api_transactions__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json + mockURL: /mock/eth-api/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7 + method: GET + extURL: https://localhost:4567/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7 +- file: mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_tokenBalances.json + mockURL: /mock/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances + method: GET + extURL: https:///api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances +- file: mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_txs.json + mockURL: /mock/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs + method: GET + extURL: https:///api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs&pageSize=10 +- file: mock/ext-api-data/ethclassic-api_tokens__address_0xa12105efa0663147bddee178f6a741ac15676b79.json + mockURL: /mock/ethclassic-api/tokens?address=0xa12105efa0663147bddee178f6a741ac15676b79 + method: GET + extURL: https:///tokens?address=0xa12105efa0663147bddee178f6a741ac15676b79 +- file: mock/ext-api-data/ethclassic-api_transactions__address_0x7d2d0e153026fb428b885d86de50768d4cfeac37.json + mockURL: /mock/ethclassic-api/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37 + method: GET + extURL: https:///transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37 +- file: mock/ext-api-data/gochain-api_tokens__address_0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628.json + mockURL: /mock/gochain-api/tokens?address=0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628 + method: GET + extURL: https:///tokens?address=0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628 +- file: mock/ext-api-data/gochain-api_transactions__address_0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896.json + mockURL: /mock/gochain-api/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896 + method: GET + extURL: https:///transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896 +- file: mock/ext-api-data/groestlcoin-api_v2_address_33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj__details_txs.json + mockURL: /mock/groestlcoin-api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs + method: GET + extURL: https://blockbook.groestlcoin.org/api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs&pageSize=10 +- file: mock/ext-api-data/groestlcoin-api_v2_xpub_zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf__details_txs.json + mockURL: /mock/groestlcoin-api/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs + method: GET + extURL: https://blockbook.groestlcoin.org/api/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs&pageSize=10 +- file: mock/ext-api-data/icon-api_address_txList__address_hxee691e7bccc4eb11fee922896e9f51490e62b12e_count_25.json + mockURL: /mock/icon-api/address/txList?address=hxee691e7bccc4eb11fee922896e9f51490e62b12e&count=25 + method: GET + extURL: https://tracker.icon.foundation/v3/address/txList?address=hxee691e7bccc4eb11fee922896e9f51490e62b12e&count=25 +- file: mock/ext-api-data/iotex-api_accounts_io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json + mockURL: /mock/iotex-api/accounts/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m + method: GET + extURL: https://pharos.iotex.io/v1/accounts/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m +- file: mock/ext-api-data/iotex-api_accounts_io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5.json + mockURL: /mock/iotex-api/accounts/io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5 + method: GET + extURL: https://pharos.iotex.io/v1/accounts/io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5 +- file: mock/ext-api-data/iotex-api_actions_addr_io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5__count_25_start_32.json + mockURL: /mock/iotex-api/actions/addr/io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5?count=25 + method: GET + extURL: https://pharos.iotex.io/v1/actions/addr/io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5?count=25&start=32 +- file: mock/ext-api-data/iotex-api_staking_delegations_io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json + mockURL: /mock/iotex-api/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m + method: GET + extURL: https://pharos.iotex.io/v1/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m +- file: mock/ext-api-data/iotex-api_staking_validators__status_bonded.json + mockURL: /mock/iotex-api/staking/validators?status=bonded + method: GET + extURL: https://pharos.iotex.io/v1/staking/validators?status=bonded +- file: mock/ext-api-data/kava-api_minting_inflation.json + mockURL: /mock/kava-api/minting/inflation + method: GET + extURL: https://data.kava.io/minting/inflation +- file: mock/ext-api-data/kava-api_staking_delegators_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_delegations.json + mockURL: /mock/kava-api/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/delegations + method: GET + extURL: https://data.kava.io/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/delegations +- file: mock/ext-api-data/kava-api_staking_delegators_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_delegations.json + mockURL: /mock/kava-api/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/unbonding_delegations + method: GET + extURL: https://data.kava.io/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/unbonding_delegations +- file: mock/ext-api-data/kava-api_staking_pool.json + mockURL: /mock/kava-api/staking/pool + method: GET + extURL: https://data.kava.io/staking/pool +- file: mock/ext-api-data/kava-api_staking_validators__status_bonded.json + mockURL: /mock/kava-api/staking/validators?status=bonded + method: GET + extURL: https://data.kava.io/staking/validators?status=bonded +- file: mock/ext-api-data/kava-api_txs__limit_25_message.sender_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_page_1.json + mockURL: /mock/kava-api/txs?limit=25&message.sender=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1 + method: GET + extURL: https://data.kava.io/txs?limit=25&message.sender=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1 +- file: mock/ext-api-data/kava-api_txs__limit_25_page_1_transfer.recipient_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json + mockURL: /mock/kava-api/txs?limit=25&page=1&transfer.recipient=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m + method: GET + extURL: https://data.kava.io/txs?limit=25&page=1&transfer.recipient=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m +- file: mock/ext-api-data/kava-api_auth_accounts_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json + mockURL: /mock/kava-api/auth/accounts/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m + method: GET + extURL: https://data.kava.io/auth/accounts/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m +- file: mock/ext-api-data/kin-api_accounts_GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH_payments__limit_25_order_desc.json + mockURL: /mock/kin-api/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?limit=25&order=desc + method: GET + extURL: https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?limit=25&order=desc +- file: mock/ext-api-data/kin-api_transactions_b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a__.json + mockURL: /mock/kin-api/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a? + method: GET + extURL: https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a? +- file: mock/ext-api-data/kin-api_transactions_eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed.json + mockURL: /mock/kin-api/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed + method: GET + extURL: https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed +- file: mock/ext-api-data/litecoin-api_v2_address_ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept__details_txs.json + mockURL: /mock/litecoin-api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs + method: GET + extURL: https://ltc1.trezor.io/api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs&pageSize=10 +- file: mock/ext-api-data/litecoin-api_v2_xpub_zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu__details_txs.json + mockURL: /mock/litecoin-api/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs + method: GET + extURL: https://ltc1.trezor.io/api/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs&pageSize=10 +- file: mock/ext-api-data/nebulas-api_tx__a_n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a_p_0.json + mockURL: /mock/nebulas-api/tx?a=n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a + method: GET + extURL: https://explorer-backend.nebulas.io/api/tx?a=n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a&p=0 +- file: mock/ext-api-data/ontology-api_v2_addresses_AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7_transactions__page_number_1_page_size_20.json + mockURL: /mock/ontology-api/v2/addresses/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7/transactions?page_number=1&page_size=20 + method: GET + extURL: https://explorer.ont.io/v2/addresses/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7/transactions?page_number=1&page_size=20 +- file: mock/ext-api-data/opensea-api_api_v1_assets___collection_unstoppable-domains_limit_300_owner_0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d.json + mockURL: /mock/opensea-api/api/v1/assets?collection=unstoppable-domains&owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d + method: GET + extURL: https://api.opensea.io/api/v1/assets/?collection=unstoppable-domains&limit=300&owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d +- file: mock/ext-api-data/opensea-api_api_v1_collections___asset_owner_0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d_limit_1000.json + mockURL: /mock/opensea-api/api/v1/collections?asset_owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d + method: GET + extURL: https://api.opensea.io/api/v1/collections/?asset_owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d&limit=1000 +- file: mock/ext-api-data/poa-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json + mockURL: /mock/poa-api/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7 + method: GET + extURL: https:///tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7 +- file: mock/ext-api-data/poa-api_transactions__address_0x55798eCbF17ce1241d543c22dCE46134c13b4bc0.json + mockURL: /mock/poa-api/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0 + method: GET + extURL: https:///transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0 +- file: mock/ext-api-data/qtum-api_v2_address_QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ__details_txs.json + mockURL: /mock/qtum-api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs + method: GET + extURL: https://blockv3.qtum.info/api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs&pageSize=10 +- file: mock/ext-api-data/qtum-api_v2_xpub_xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd__details_txs.json + mockURL: /mock/qtum-api/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs + method: GET + extURL: https://blockv3.qtum.info/api/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs&pageSize=10 +- file: mock/ext-api-data/ravencoin-api_v2_address_RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo__details_txs.json + mockURL: /mock/ravencoin-api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs + method: GET + extURL: https://blockbook.ravencoin.org/api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs&pageSize=10 +- file: mock/ext-api-data/ravencoin-api_v2_xpub_xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B__details_txs.json + mockURL: /mock/ravencoin-api/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs + method: GET + extURL: https://blockbook.ravencoin.org/api/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs&pageSize=10 +- file: mock/ext-api-data/ripple-api_accounts_rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1_transactions__descending_false_limit_25_type_Payment.json + mockURL: /mock/ripple-api/accounts/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1/transactions?limit=25&type=Payment + method: GET + extURL: https://data.ripple.com/v2/accounts/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1/transactions?descending=false&limit=25&type=Payment +- file: mock/ext-api-data/stellar-api_accounts_GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX_payments__limit_25_order_desc.json + mockURL: /mock/stellar-api/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?limit=25&order=desc + method: GET + extURL: https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?limit=25&order=desc +- file: mock/ext-api-data/stellar-api_transactions_23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c.json + mockURL: /mock/stellar-api/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c + method: GET + extURL: https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c +- file: mock/ext-api-data/stellar-api_transactions_2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029__.json + mockURL: /mock/stellar-api/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029? + method: GET + extURL: https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029? +- file: mock/ext-api-data/tezos-api_account_tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8_op__limit_25_order_desc_type_transaction_delegation.json + mockURL: /mock/tezos-api/account/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8/op?limit=25&order=desc&type=transaction,delegation + method: GET + extURL: https://api.tzstats.com/explorer/account/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8/op?limit=25&order=desc&type=transaction,delegation +- file: mock/ext-api-data/theta-api_accounttx_0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f__isEqualType_true_limitNumber_100_pageNumber_1_type_2.json + mockURL: /mock/theta-api/accounttx/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f?isEqualType=true&limitNumber=100&pageNumber=1&type=2 + method: GET + extURL: https://explorer.thetatoken.org:9000/api/accounttx/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f?isEqualType=true&limitNumber=100&pageNumber=1&type=2 +- file: mock/ext-api-data/thundertoken-api_tokens__address_0x0b230def08139f18a86536d9cfa150f04435414c.json + mockURL: /mock/thundertoken-api/tokens?address=0x0b230def08139f18a86536d9cfa150f04435414c + method: GET + extURL: https:///tokens?address=0x0b230def08139f18a86536d9cfa150f04435414c +- file: mock/ext-api-data/thundertoken-api_transactions__address_0x0b230def08139f18a86536d9cfa150f04435414c.json + mockURL: /mock/thundertoken-api/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c + method: GET + extURL: https:///transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c +- file: mock/ext-api-data/tomochain-api_tokens__address_0x8b353021189375591723e7384262f45709a3c3dc.json + mockURL: /mock/tomochain-api/tokens?address=0x8b353021189375591723e7384262f45709a3c3dc + method: GET + extURL: https:///tokens?address=0x8b353021189375591723e7384262f45709a3c3dc +- file: mock/ext-api-data/tomochain-api_transactions__address_0x17e4c16605e32adead5fa371bf6117df34ca0200.json + mockURL: /mock/tomochain-api/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200 + method: GET + extURL: https:///transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200 +- file: mock/ext-api-data/tron-api_v1_accounts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB_transactions__limit_25_order_by_block_timestamp_desc_token_id_.json + mockURL: /mock/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?limit=25&order_by=block_timestamp,desc&token_id= + method: GET + extURL: https://api.trongrid.io/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?limit=25&order_by=block_timestamp,desc&token_id= +- file: mock/ext-api-data/tron-api_v1_accounts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB.json + mockURL: /mock/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB + method: GET + extURL: https://api.trongrid.io/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB +- file: mock/ext-api-data/tron-api_v1_assets_1002000.json + mockURL: /mock/tron-api/v1/assets/1002000 + method: GET + extURL: https://api.trongrid.io/v1/assets/1002000 +- file: mock/ext-api-data/tron-api_v1_assets_1002798.json + mockURL: /mock/tron-api/v1/assets/1002798 + method: GET + extURL: https://api.trongrid.io/v1/assets/1002798 +- file: mock/ext-api-data/tron-api_v1_assets_1002814.json + mockURL: /mock/tron-api/v1/assets/1002814 + method: GET + extURL: https://api.trongrid.io/v1/assets/1002814 +- file: mock/ext-api-data/tron-api_wallet_listwitnesses.json + mockURL: /mock/tron-api/wallet/listwitnesses + method: GET + extURL: https://api.trongrid.io/wallet/listwitnesses +- file: mock/ext-api-data/unstoppabledomains_api_v1__dpantani.zil.json + mockURL: /mock/unstoppabledomains/api/v1/dpantani.zil + method: GET + extURL: https://unstoppabledomains.com/api/v1/dpantani.zil +- file: mock/ext-api-data/unstoppabledomains_api_v1__dpantani.crypto.json + mockURL: /mock/unstoppabledomains/api/v1/dpantani.crypto + method: GET + extURL: https://unstoppabledomains.com/api/v1/dpantani.crypto +- file: mock/ext-api-data/vechain-api_blocks_best.json + mockURL: /mock/vechain-api/blocks/best + method: GET + extURL: https://vethor-pubnode.digonchain.com/blocks/best +- file: mock/ext-api-data/vechain-api_transactions_0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5.json + mockURL: /mock/vechain-api/transactions/0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5 + method: GET + extURL: https://vethor-pubnode.digonchain.com/transactions/0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5 +- file: mock/ext-api-data/vechain-api_transactions_0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7.json + mockURL: /mock/vechain-api/transactions/0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7 + method: GET + extURL: https://vethor-pubnode.digonchain.com/transactions/0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7 +- file: mock/ext-api-data/viacoin-api_v2_address_VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A__details_txs.json + mockURL: /mock/viacoin-api/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs + method: GET + extURL: https://blockbook.viacoin.org/api/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs&pageSize=10 +- file: mock/ext-api-data/viacoin-api_v2_xpub_zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK__details_txs.json + mockURL: /mock/viacoin-api/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs + method: GET + extURL: https://blockbook.viacoin.org/api/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs&pageSize=10 +- file: mock/ext-api-data/waves-api_transactions_address_3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD_limit_25.json + mockURL: /mock/waves-api/transactions/address/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD/limit/25 + method: GET + extURL: https://nodes.wavesnodes.com/transactions/address/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD/limit/25 +- file: mock/ext-api-data/zcash-api_v2_address_t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX__details_txs.json + mockURL: /mock/zcash-api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs + method: GET + extURL: https://zec1.trezor.io/api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs&pageSize=10 +- file: mock/ext-api-data/zcash-api_v2_xpub_xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS__details_txs.json + mockURL: /mock/zcash-api/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs + method: GET + extURL: https://zec1.trezor.io/api/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs&pageSize=10 +- file: mock/ext-api-data/zcoin-api_v2_address_a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn__details_txs.json + mockURL: /mock/zcoin-api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs + method: GET + extURL: https://blockbook.zcoin.io/api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs&pageSize=10 +- file: mock/ext-api-data/zcoin-api_v2_xpub_xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK__details_txs.json + mockURL: /mock/zcoin-api/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs + method: GET + extURL: https://blockbook.zcoin.io/api/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs&pageSize=10 +- file: mock/ext-api-data/zelcash-api_v2_address_t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa__details_txs.json + mockURL: /mock/zelcash-api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs + method: GET + extURL: https://blockbook.zel.network/api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs&&pageSize=10 +- file: mock/ext-api-data/zelcash-api_v2_xpub_xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf__details_txs.json + mockURL: /mock/zelcash-api/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs + method: GET + extURL: https://blockbook.zel.network/api/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs&pageSize=10 +- file: mock/ext-api-data/zilliqa-api_addresses_zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z_txs.json + mockURL: /mock/zilliqa-api/addresses/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z/txs + method: GET + extURL: https://api.viewblock.io/v1/zilliqa/addresses/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z/txs +- file: mock/ext-api-data/fio-api_v1_chain_get_pub_address.0001.json + mockURL: /mock/fio-api/v1/chain/get_pub_address + method: POST + reqFile: mock/ext-api-data/fio-api_v1_chain_get_pub_address.0001.request_json +- file: mock/ext-api-data/fio-api_v1_chain_get_pub_address.0002.json + mockURL: /mock/fio-api/v1/chain/get_pub_address + method: POST + reqFile: mock/ext-api-data/fio-api_v1_chain_get_pub_address.0002.request_json +- file: mock/ext-api-data/fio-api_v1_chain_get_pub_address.json + mockURL: /mock/fio-api/v1/chain/get_pub_address + method: POST + reqFile: mock/ext-api-data/fio-api_v1_chain_get_pub_address.request_json +- file: mock/ext-api-data/fio-api_v1_history_get_actions.0001.json + mockURL: /mock/fio-api/v1/history/get_actions + method: POST + reqFile: mock/ext-api-data/fio-api_v1_history_get_actions.0001.request_json + reqField: account_name +- file: mock/ext-api-data/fio-api_v1_history_get_actions.0002.json + mockURL: /mock/fio-api/v1/history/get_actions + method: POST + reqFile: mock/ext-api-data/fio-api_v1_history_get_actions.0002.request_json + reqField: account_name +- file: mock/ext-api-data/fio-api_v1_history_get_actions.json + mockURL: /mock/fio-api/v1/history/get_actions + method: POST + reqFile: mock/ext-api-data/fio-api_v1_history_get_actions.request_json + reqField: account_name +- file: mock/ext-api-data/harmony-api.json + mockURL: /mock/harmony-api + method: POST + extURL: https://api.s0.t.hmny.io + reqFile: mock/ext-api-data/harmony-api.request_json + reqField: address +- file: mock/ext-api-data/kusama-api_scan_transfers.json + mockURL: /mock/kusama-rpc/scan/transfers + method: POST + extURL: https://kusama.subscan.io/api/scan/transfers + reqFile: mock/ext-api-data/kusama-api_scan_transfers.request_json +- file: mock/ext-api-data/nano-api.json + mockURL: /mock/nano-api + method: POST + extURL: https://nanoverse.io/api/node + reqFile: mock/ext-api-data/nano-api.request_json +- file: mock/ext-api-data/nimiq-rpc.json + mockURL: /mock/nimiq-rpc + method: POST + extURL: https:// + reqFile: mock/ext-api-data/nimiq-rpc.request_json + reqField: params +- file: mock/ext-api-data/tron-api_wallet_getaccount.json + mockURL: /mock/tron-api/wallet/getaccount + method: POST + extURL: https://api.trongrid.io/wallet/getaccount + reqFile: mock/ext-api-data/tron-api_wallet_getaccount.request_json +- file: mock/ext-api-data/vechain-api_logs_transfer.json + mockURL: /mock/vechain-api/logs/transfer + method: POST + extURL: https://vethor-pubnode.digonchain.com/logs/transfer + reqFile: mock/ext-api-data/vechain-api_logs_transfer.request_json + reqField: sender +- file: mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.json + mockURL: /mock/eth-rpc + method: POST + extURL: https:// + reqFile: mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.request_json + reqField: data +- file: mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835.json + mockURL: /mock/eth-rpc + method: POST + extURL: https:// + reqFile: mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835.request_json + reqField: data +- file: mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.json + mockURL: /mock/eth-rpc + method: POST + extURL: https:// + reqFile: mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.request_json + reqField: data +- file: mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.json + mockURL: /mock/eth-rpc + method: POST + extURL: https:// + reqFile: mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.request_json + reqField: data +- file: mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c.json + mockURL: /mock/eth-rpc + method: POST + extURL: https:// + reqFile: mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c.request_json + reqField: data +- file: mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c.json + mockURL: /mock/eth-rpc + method: POST + extURL: https:// + reqFile: mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c.request_json + reqField: data +- file: mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c.json + mockURL: /mock/eth-rpc + method: POST + extURL: https:// + reqFile: mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c.request_json + reqField: data +- file: mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.json + mockURL: /mock/eth-rpc + method: POST + extURL: https:// + reqFile: mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.request_json + reqField: data diff --git a/mock/ext-api-data/aeternity-api_middleware_transactions_account_ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb.json b/mock/ext-api-data/aeternity-api_middleware_transactions_account_ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb.json new file mode 100644 index 000000000..8a2d5deea --- /dev/null +++ b/mock/ext-api-data/aeternity-api_middleware_transactions_account_ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb.json @@ -0,0 +1,139 @@ +[ + { + "block_hash": "mh_9n1WhZB39ppe4hrw1mW5RTz2xLGPBNopC94EvENTz5uN6FgPx", + "block_height": 253953, + "hash": "th_JHJDW5N9HDJQkChm9dzXJfmQMujsYKYtDzh6oAv4UqdMnyRmb", + "signatures": [ + "sg_2F1uswNURBVAkaib5X8YRtqQAZEEHD4y5aSGD8DkGHkZy7EMsWwf63rtZRYLQoVs2i1HrYg3uBkmhVEJJ29bz9KKUYFQV" + ], + "time": 1589238828576, + "tx": { + "amount": 1.99979974992e21, + "fee": 50000000000000, + "nonce": 4, + "payload": "ba_Xfbg4g==", + "recipient_id": "ak_eCBjzjUpjA6uqhj1unF5VC2bvd8yEC9tFArUDTwor21CYaTNZ", + "sender_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "ttl": 254053, + "type": "SpendTx", + "version": 1 + } + }, + { + "block_hash": "mh_2V2PJ732cTfDqD4CaWr6W1s1fN531PqiVydMiy7gooccQFoGvM", + "block_height": 222994, + "hash": "th_WfeoRYXd13MMmDBzMXjBBdaNSSaRXkwUwJ7tFxJ7ZKPQVNXC4", + "signatures": [ + "sg_MLBxuqnHUD21i747SKnQuyNh1LzLuH7RDHqY1mngZyJMDWL9LFcuMbKdo2XMbwkMmskFsgfsZZBwgyA5w4Xs3ghynF2AF" + ], + "time": 1583633007081, + "tx": { + "amount": 1.99979979992e21, + "fee": 16840000000000, + "nonce": 3, + "payload": "ba_Xfbg4g==", + "recipient_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "sender_id": "ak_26dGJ7S5ba7LhUXPo8vMPe4QuNaQbskWnM5jkopPuim3PGny9Y", + "type": "SpendTx", + "version": 1 + } + }, + { + "block_hash": "mh_Z1a6HSs9vE5XDf8JtSiQMN5UpX49Spgnf9Sn32TiXxKwSbsP6", + "block_height": 186035, + "hash": "th_2wGEGmqwRMPYdv3vz1EE7ueJEveMTzEWzosgUH9ytERjGMv3rX", + "signatures": [ + "sg_66c2LXv4rvYnn4r2fZ4H1wxieDUuVEUF6fLCB3M13MjB9QNfEH4q9YThUWJCo5WzWKxzqjb3RbumhXdUZh8YDq3v8KZ2M" + ], + "time": 1576946253731, + "tx": { + "amount": 1.00079975e21, + "fee": 50000000000000, + "nonce": 3, + "payload": "ba_Xfbg4g==", + "recipient_id": "ak_26dGJ7S5ba7LhUXPo8vMPe4QuNaQbskWnM5jkopPuim3PGny9Y", + "sender_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "ttl": 186135, + "type": "SpendTx", + "version": 1 + } + }, + { + "block_hash": "mh_23SfEMQHUqJoDzGjdYHFh2Fw9zUa1LAR6JxstKxpzW51vZSTBG", + "block_height": 186034, + "hash": "th_2CvMDQGNU21Dq9241hjoeDfwcz7FnBE2DhMXUd5rRMCbjG117H", + "signatures": [ + "sg_Y6dTsjGnmCJG6nVRoLVtoXr6QWyk3kYHvJ97QvXKGumjEFvZcnNtVAUZ2oc6fCYBf36PMHRcxKwF8Z4UWqPEj8mz8CCBB" + ], + "time": 1576946179344, + "tx": { + "amount": 9.9800005e20, + "fee": 50000000000000, + "nonce": 2, + "payload": "ba_Xfbg4g==", + "recipient_id": "ak_26dGJ7S5ba7LhUXPo8vMPe4QuNaQbskWnM5jkopPuim3PGny9Y", + "sender_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "ttl": 186134, + "type": "SpendTx", + "version": 1 + } + }, + { + "block_hash": "mh_2UkBD3ZsjQTjqhqLGqWAERy313ravnLczGjTE3F3Qyzdmikv9q", + "block_height": 185934, + "hash": "th_859Ja4tucJHqjHGmvNibeRVDty2YzGhzKtpz7UDYJVWuW5tGG", + "signatures": [ + "sg_oEsmi674Lqu5K1aJDZ353v48D3UZYUXtkoSoVX5xs6VxDDcKRxg5btnHUJQaFcXC1TFP3eZ6rKSnyeQwNdz11gmAooAg" + ], + "time": 1576928530320, + "tx": { + "amount": 1000050000000000000, + "fee": 50000000000000, + "nonce": 1, + "payload": "ba_Xfbg4g==", + "recipient_id": "ak_26dGJ7S5ba7LhUXPo8vMPe4QuNaQbskWnM5jkopPuim3PGny9Y", + "sender_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "ttl": 186034, + "type": "SpendTx", + "version": 1 + } + }, + { + "block_hash": "mh_2EnVyYu67Ej9VmAhHAEeVp41NKGQvy13jy6t2wppyuvzRRWhLM", + "block_height": 185931, + "hash": "th_7QM8aAVD299io7VoxEQSfRqmJ9SZqpycupZFUHCy7Whe6NhTJ", + "signatures": [ + "sg_DvkxctVXTnzhs1YJeAtgwbA7uPKKULu5chMoZRpJTjMGKjkhTjcQhGawnyfWfhwdrcrrZs2rzUg1S21MMF71qSLSBttRQ" + ], + "time": 1576927729850, + "tx": { + "amount": 1.9898e21, + "fee": 16880000000000, + "nonce": 5256, + "payload": "ba_Xfbg4g==", + "recipient_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "sender_id": "ak_dnzaNnchT7f3YT3CtrQ7GUjqGT6VaHzPxpf2efHWPuEAWKcht", + "type": "SpendTx", + "version": 1 + } + }, + { + "block_hash": "mh_2q93r4jZY77kxQsKMGGS4AqXh97spDydfR61MpbSPs3GWXrmWA", + "block_height": 185618, + "hash": "th_2JTC4fK8aHQLywigJCCNYC5wmAWYHSG5fjG6yDzZQM9YPmee5a", + "signatures": [ + "sg_15yUH8Gi9K59WizVVtShzYBcahXgDgiZsuXfUthSkqw4a5QWyeRzr28kxnv6qYrzePhG4RDMVLDtMmQMfjmXemnynR5fy" + ], + "time": 1576872187562, + "tx": { + "amount": 10000000000000000000, + "fee": 16860000000000, + "nonce": 5241, + "payload": "ba_Xfbg4g==", + "recipient_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", + "sender_id": "ak_dnzaNnchT7f3YT3CtrQ7GUjqGT6VaHzPxpf2efHWPuEAWKcht", + "type": "SpendTx", + "version": 1 + } + } +] \ No newline at end of file diff --git a/mock/ext-api-data/aion-api_getTransactionsByAddress__accountAddress_0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed_size_25.json b/mock/ext-api-data/aion-api_getTransactionsByAddress__accountAddress_0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed_size_25.json new file mode 100644 index 000000000..1f51fa373 --- /dev/null +++ b/mock/ext-api-data/aion-api_getTransactionsByAddress__accountAddress_0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed_size_25.json @@ -0,0 +1,58 @@ +{ + "page": { + "number": 0, + "size": 25, + "totalPages": 1, + "start": 1582532306, + "end": 1585037906, + "totalElements": 2 + }, + "content": [ + { + "blockHash": "f9aab3a58f9211d9d37458d8a87e49f2e00d1d242390d4650cd4092897650797", + "nrgPrice": 10000000000, + "toAddr": "a0c00cfc4c53bb6d49f385b91f58a23dd7b1dc024976b391bb8b81eb9e8801ab", + "contractAddr": "", + "data": "", + "year": 2020, + "internalTransactionCount": 0, + "transactionIndex": 0, + "type": "DEFAULT", + "nonce": "1e2f", + "transactionHash": "511d3a4aafbdd26825a1655b5c7525df5bea8a8ef0f887d5490b490055b53df7", + "transactionTimestamp": 1584349754, + "nrgConsumed": 21000, + "month": 3, + "blockNumber": 5619712, + "blockTimestamp": 1584349754, + "transactionLog": "[]", + "fromAddr": "a04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed", + "day": 16, + "value": "1.002217611212000000000000000000000000", + "txError": "" + }, + { + "blockHash": "ed8d3d92da7228c35c363f55383c602b6f5041b37ff165231245cfa83b863ae7", + "nrgPrice": 10000000000, + "toAddr": "a04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed", + "contractAddr": "", + "data": "", + "year": 2020, + "internalTransactionCount": 0, + "transactionIndex": 2, + "type": "DEFAULT", + "nonce": "2b2e55", + "transactionHash": "84789693b108bc3c437f8dccbd517682f611036d54621ec1f4db26f661fde468", + "transactionTimestamp": 1584349550, + "nrgConsumed": 21000, + "month": 3, + "blockNumber": 5619690, + "blockTimestamp": 1584349550, + "transactionLog": "[]", + "fromAddr": "a00983f07c11ee9160a64dd3ba3dc3d1f88332a2869f25725f56cbd0be32ef7a", + "day": 16, + "value": "1.002427611212000000000000000000000000", + "txError": "" + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/algorand-api_v1_account_4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U_transactions.json b/mock/ext-api-data/algorand-api_v1_account_4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U_transactions.json new file mode 100644 index 000000000..0f4be8eed --- /dev/null +++ b/mock/ext-api-data/algorand-api_v1_account_4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U_transactions.json @@ -0,0 +1,23 @@ +{ + "transactions": [ + { + "type": "pay", + "tx": "JZTKP6RRFGUDOZ7DQIR26DQWRDYZVYG2G3WDE4WLBJ77AMAEBFBA", + "from": "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", + "fee": 1000, + "first-round": 5478300, + "last-round": 5478749, + "noteb64": "sHLxsLBrP3o=", + "round": 5478346, + "payment": { + "to": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", + "amount": 1, + "torewards": 2052177, + "closerewards": 0 + }, + "fromrewards": 0, + "genesisID": "mainnet-v1.0", + "genesishashb64": "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=" + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/algorand-api_v1_block_5478346.json b/mock/ext-api-data/algorand-api_v1_block_5478346.json new file mode 100644 index 000000000..2705c6448 --- /dev/null +++ b/mock/ext-api-data/algorand-api_v1_block_5478346.json @@ -0,0 +1,43 @@ +{ + "hash": "SU4PUD4YK5DPIXUXDLEZOEHVVIIP4SWZORFPJBW2J22QO444NSAA", + "previousBlockHash": "CC4CQRE2U5AC7S7JLJHDVVGIDCHGWTDFIZM3P34TVTC7AP4BA2AQ", + "seed": "NLAQIQXPCZI5QMKMRFFKMIKANNBC4PTFW5QFVAK7U6FE477T2TRA", + "proposer": "WCFKBT4NEPDUCQP7MGLIWV4QGXIBOCXJFVYNTXF3HZHFHGQGHGR5WWA7XA", + "round": 5478346, + "period": 0, + "txnRoot": "KFADZYI64LDUX76VWVVV3MROORV5RXAVNZA7MVTWOP2QTGW6DZ2A", + "reward": 111421, + "rate": 25999967, + "frac": 2639736378, + "txns": { + "transactions": [ + { + "type": "pay", + "tx": "JZTKP6RRFGUDOZ7DQIR26DQWRDYZVYG2G3WDE4WLBJ77AMAEBFBA", + "from": "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", + "fee": 1000, + "first-round": 5478300, + "last-round": 5478749, + "noteb64": "sHLxsLBrP3o=", + "round": 5478346, + "payment": { + "to": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", + "amount": 1, + "torewards": 2052177, + "closerewards": 0 + }, + "fromrewards": 0, + "genesisID": "mainnet-v1.0", + "genesishashb64": "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=" + } + ] + }, + "timestamp": 1584332782, + "currentProtocol": "https://github.com/algorandfoundation/specs/tree/4a9db6a25595c6fd097cf9cc137cc83027787eaa", + "nextProtocol": "", + "nextProtocolApprovals": 0, + "nextProtocolVoteBefore": 0, + "nextProtocolSwitchOn": 0, + "upgradePropose": "", + "upgradeApprove": false +} \ No newline at end of file diff --git a/mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q b/mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q new file mode 100644 index 000000000..ff8e44b50 --- /dev/null +++ b/mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q @@ -0,0 +1 @@ +{"account_number":273171,"address":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","balances":[{"free":"226.52883965","frozen":"0.00000000","locked":"0.00000000","symbol":"BNB"},{"free":"3649.96917801","frozen":"0.00000000","locked":"0.00000000","symbol":"BUSD-BD1"},{"free":"0.05000000","frozen":"0.00000000","locked":"0.00000000","symbol":"TWT-8C2"}],"flags":0,"public_key":[2,142,117,1,132,202,113,77,165,176,46,204,240,131,18,251,120,168,140,204,43,27,32,135,157,30,25,86,154,105,108,64,211],"sequence":82} diff --git a/mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json b/mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json new file mode 100644 index 000000000..ef085c1eb --- /dev/null +++ b/mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json @@ -0,0 +1,1466 @@ +[ + { + "mintable": true, + "name": "Africa Stable-Coin", + "original_symbol": "ABCD", + "owner": "bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms", + "symbol": "ABCD-5D8", + "total_supply": "3000000.00000000" + }, + { + "mintable": false, + "name": "Aditus", + "original_symbol": "ADI", + "owner": "bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps", + "symbol": "ADI-6BB", + "total_supply": "750000000.00000000" + }, + { + "mintable": false, + "name": "Aergo", + "original_symbol": "AERGO", + "owner": "bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl", + "symbol": "AERGO-46B", + "total_supply": "500000000.00000000" + }, + { + "mintable": false, + "name": "Alaris", + "original_symbol": "ALA", + "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", + "symbol": "ALA-DCD", + "total_supply": "60000000.00000000" + }, + { + "mintable": false, + "name": "ANKR", + "original_symbol": "ANKR", + "owner": "bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn", + "symbol": "ANKR-E97", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Aeron", + "original_symbol": "ARN", + "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", + "symbol": "ARN-71B", + "total_supply": "20000000.00000000" + }, + { + "mintable": true, + "name": "ARPA", + "original_symbol": "ARPA", + "owner": "bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c", + "symbol": "ARPA-575", + "total_supply": "12000000.00000000" + }, + { + "mintable": false, + "name": "Maecenas ART Token", + "original_symbol": "ART", + "owner": "bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l", + "symbol": "ART-3C9", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "Atlas Protocol", + "original_symbol": "ATP", + "owner": "bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf", + "symbol": "ATP-38C", + "total_supply": "40000000.00000000" + }, + { + "mintable": false, + "name": "Travala.com Token", + "original_symbol": "AVA", + "owner": "bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c", + "symbol": "AVA-645", + "total_supply": "61242960.00000000" + }, + { + "mintable": true, + "name": "“Atomic", + "original_symbol": "AWC", + "owner": "bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw", + "symbol": "AWC-8B2", + "total_supply": "147.00000000" + }, + { + "mintable": false, + "name": "Atomic Wallet Token", + "original_symbol": "AWC", + "owner": "bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw", + "symbol": "AWC-986", + "total_supply": "50000000.00000000" + }, + { + "mintable": false, + "name": "AXPR.B", + "original_symbol": "AXPR", + "owner": "bnb1zpnmet0vhfupn9ysu26gukzj7a2xkkcry22n9t", + "symbol": "AXPR-777", + "total_supply": "347955111.02000000" + }, + { + "mintable": true, + "name": "BAWnetwork", + "original_symbol": "BAW", + "owner": "bnb1umdp5z4hugur26tcgf48fhr0548fv0q0fga84u", + "symbol": "BAW-DFB", + "total_supply": "25000000000.00000000" + }, + { + "mintable": true, + "name": "BCH BEP2", + "original_symbol": "BCH", + "owner": "bnb15tjhzw85wyywwp7zvc4l3ux3j0393rzp9exl0p", + "symbol": "BCH-1FD", + "total_supply": "5000.00000000" + }, + { + "mintable": false, + "name": "Blockmason Credit Protocol", + "original_symbol": "BCPT", + "owner": "bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew", + "symbol": "BCPT-95A", + "total_supply": "116158667.00000000" + }, + { + "mintable": true, + "name": "3X Short Bitcoin Token", + "original_symbol": "BEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "BEAR-14C", + "total_supply": "50301.00000000" + }, + { + "mintable": false, + "name": "EOSBet Token", + "original_symbol": "BET", + "owner": "bnb1rgylg0f3ka24a63rnq926quvet438fxrz3320c", + "symbol": "BET-844", + "total_supply": "88000000.00000000" + }, + { + "mintable": false, + "name": "BETX Token", + "original_symbol": "BETX", + "owner": "bnb15v9e3c4wy8vpex0c5fj702lexjesh30v2203f2", + "symbol": "BETX-A0C", + "total_supply": "200000000.00000000" + }, + { + "mintable": true, + "name": "Binance GBP Stable Coin", + "original_symbol": "BGBP", + "owner": "bnb1r4ag7kd90rptlhcuuc8trh60v4m4vvzrfyecta", + "symbol": "BGBP-CF3", + "total_supply": "200.00000000" + }, + { + "mintable": true, + "name": "Humanity First Token", + "original_symbol": "BHFT", + "owner": "bnb148t3u8zxa44vhydes5qa8xnxuzuq6zgyxmzt6d", + "symbol": "BHFT-BBE", + "total_supply": "636425000.00000000" + }, + { + "mintable": false, + "name": "Bitwires Token", + "original_symbol": "BKBT", + "owner": "bnb104p50kz2uvep5s5u6j0lr6vkl6rp5g4653d7w4", + "symbol": "BKBT-3A6", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Binance KRW", + "original_symbol": "BKRW", + "owner": "bnb18kha55gvsxl7gkdh8y329hu3p6wndh6jkwqnxn", + "symbol": "BKRW-AB7", + "total_supply": "1418984074.00000000" + }, + { + "mintable": false, + "name": "Blockmason Link", + "original_symbol": "BLINK", + "owner": "bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew", + "symbol": "BLINK-9C6", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "Binance Chain Native Token", + "original_symbol": "BNB", + "owner": "bnb1ultyhpw2p2ktvr68swz56570lgj2rdsadq3ym2", + "symbol": "BNB", + "total_supply": "179883948.90000000" + }, + { + "mintable": false, + "name": "BOLT Token", + "original_symbol": "BOLT", + "owner": "bnb177ujwmshxu8r9za4vy9ztqn65tmr54ddw958rt", + "symbol": "BOLT-4C6", + "total_supply": "980230000.00000000" + }, + { + "mintable": false, + "name": "Bitcloud Pro", + "original_symbol": "BPRO", + "owner": "bnb1482svhhrffpga5wmqw8068af4c9u2q9dp3hg4m", + "symbol": "BPRO-5A6", + "total_supply": "5000000000.00000000" + }, + { + "mintable": true, + "name": "BQTX", + "original_symbol": "BQTX", + "owner": "bnb1j42h6j40htujnjmtp4ckw4zx27vp0f93cvmua8", + "symbol": "BQTX-235", + "total_supply": "1000000.00000000" + }, + { + "mintable": false, + "name": "BOOSTO", + "original_symbol": "BST2", + "owner": "bnb19k2av7cmdvp9f0qkeu5vfl59yp8ftqv2s55dzs", + "symbol": "BST2-2F2", + "total_supply": "500000000.00000000" + }, + { + "mintable": true, + "name": "Bitcoin BEP2", + "original_symbol": "BTCB", + "owner": "bnb1akey87kt0r8y3fmhu2l8eyzdjvt9ptl5cppz0v", + "symbol": "BTCB-1DE", + "total_supply": "9001.00000000" + }, + { + "mintable": true, + "name": "BTTB", + "original_symbol": "BTTB", + "owner": "bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq", + "symbol": "BTTB-D31", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "3x Long Bitcoin Token", + "original_symbol": "BULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "BULL-BE4", + "total_supply": "604.80000000" + }, + { + "mintable": true, + "name": "Binance USD", + "original_symbol": "BUSD", + "owner": "bnb19v2ayq6k6e5x6ny3jdutdm6kpqn3n6mxheegvj", + "symbol": "BUSD-BD1", + "total_supply": "13000000.00000000" + }, + { + "mintable": false, + "name": "Bezant Token", + "original_symbol": "BZNT", + "owner": "bnb1w5a5jywe3cu20uq6n6x3vmzcq342s6st4cz73s", + "symbol": "BZNT-464", + "total_supply": "964511442.00000000" + }, + { + "mintable": false, + "name": "CanYaCoin", + "original_symbol": "CAN", + "owner": "bnb16w59lfh4y2cqvu8f7yr000ll37ldh4w6hnz7l0", + "symbol": "CAN-677", + "total_supply": "95827000.00000000" + }, + { + "mintable": false, + "name": "CASHAA", + "original_symbol": "CAS", + "owner": "bnb1xkw2sagpx6t0cmwzapxpv94tupvqk7tpgy72ku", + "symbol": "CAS-167", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "Cubiex", + "original_symbol": "CBIX", + "owner": "bnb1jlm66w38gpfuqr4s2jcfwlcrlx46p05thdnv7g", + "symbol": "CBIX-3C9", + "total_supply": "150000000.00000000" + }, + { + "mintable": false, + "name": "CryptoBonusMiles", + "original_symbol": "CBM", + "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", + "symbol": "CBM-4B2", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "Clipper Coin", + "original_symbol": "CCCX", + "owner": "bnb1ry99rte8gfnn9c6at9mlmrrq6p2k4u7732j9h7", + "symbol": "CCCX-10D", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "Chiliz", + "original_symbol": "CHZ", + "owner": "bnb1cghr4z8ag440tv4wnk3l6wzynytlpvfqltm9ph", + "symbol": "CHZ-ECD", + "total_supply": "8888888888.00000000" + }, + { + "mintable": false, + "name": "Crypto Neo-value Neural System", + "original_symbol": "CNNS", + "owner": "bnb193wdp4gdnm58urnsjf8nv57lxt58sckt2k50ss", + "symbol": "CNNS-E16", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Contentos", + "original_symbol": "COS", + "owner": "bnb1u9j9hkst6gf09dkdvxlj7puk8c7vh68a0kkmht", + "symbol": "COS-2E4", + "total_supply": "9400000000.00000000" + }, + { + "mintable": true, + "name": "COTI", + "original_symbol": "COTI", + "owner": "bnb1kn733gkku9xsqkuk6wcz86gftqtl4qvthvrj5m", + "symbol": "COTI-CBB", + "total_supply": "80000000.00000000" + }, + { + "mintable": false, + "name": "Covalent Token", + "original_symbol": "COVA", + "owner": "bnb1pucvxaf3l9rslupza75r9fca9h5892ntumszfm", + "symbol": "COVA-218", + "total_supply": "6500000000.00000000" + }, + { + "mintable": false, + "name": "CPChain", + "original_symbol": "CPC", + "owner": "bnb1wq4rlwrmvvltlarvypql8wrr4vlh0dczd8uksg", + "symbol": "CPC-FED", + "total_supply": "150000000.00000000" + }, + { + "mintable": false, + "name": "Crypterium Token", + "original_symbol": "CRPT", + "owner": "bnb17fk3uvagucxzpvmdvd373fapqsahxvzevdard9", + "symbol": "CRPT-8C9", + "total_supply": "99968575.14285720" + }, + { + "mintable": false, + "name": "“Consentium”", + "original_symbol": "CSM", + "owner": "bnb1gguz7vcrlf7a87et8u5gt40f0890qvkpkn9y79", + "symbol": "CSM-734", + "total_supply": "84000000.00000000" + }, + { + "mintable": true, + "name": "Carbon Dollar", + "original_symbol": "CUSD", + "owner": "bnb1y9797dtklkm3haajsfnevm9ruuxs5fyf5rpj67", + "symbol": "CUSD-24B", + "total_supply": "9999999999.00000000" + }, + { + "mintable": false, + "name": "Konstellation Network", + "original_symbol": "DARC", + "owner": "bnb1gyhnhdns4vf63nfzfq7g25czj8swjgrz3rhah8", + "symbol": "DARC-24B", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "DeepCloud", + "original_symbol": "DEEP", + "owner": "bnb1t0ws9gvnjm7j7qssk8te7m2dt5hmm8s3amqk2d", + "symbol": "DEEP-9D3", + "total_supply": "200000000.00000000" + }, + { + "mintable": false, + "name": "DeFi Token", + "original_symbol": "DEFI", + "owner": "bnb1q5xefr07503pqtfrl5sfyyhlghxwc80d4vpas2", + "symbol": "DEFI-FA5", + "total_supply": "2500000000.00000000" + }, + { + "mintable": true, + "name": "DOS Network Token", + "original_symbol": "DOS", + "owner": "bnb13gse9n7mvrjg5w2cymnt4nmxkgj200k9k2l2nh", + "symbol": "DOS-120", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "DREP", + "original_symbol": "DREP", + "owner": "bnb1ez5s9v4rcgsmhwr4fkrnlv6zwsukjnh4y754kn", + "symbol": "DREP-7D2", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Dusk Network", + "original_symbol": "DUSK", + "owner": "bnb1dfls6c8y39l7qq4gj2479wkehg85pt5m07y94g", + "symbol": "DUSK-45E", + "total_supply": "50000000.00000000" + }, + { + "mintable": false, + "name": "eBoost", + "original_symbol": "EBST", + "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", + "symbol": "EBST-783", + "total_supply": "80838159.07000000" + }, + { + "mintable": true, + "name": "Ormeus Ecosystem", + "original_symbol": "ECO", + "owner": "bnb1tr49nv08k828n2lqfw0vrgvwj7xtep5kg8wr4c", + "symbol": "ECO-083", + "total_supply": "2200000000.00000000" + }, + { + "mintable": false, + "name": "Energy Eco Token", + "original_symbol": "EET", + "owner": "bnb1pt353m8ygvvgy4f2ud9xx85tl7fqewkrksh6r5", + "symbol": "EET-45C", + "total_supply": "600000000.00000000" + }, + { + "mintable": false, + "name": "Hut34 Entropy", + "original_symbol": "ENTRP", + "owner": "bnb1wu0hu9pelx3yvplysx0je7d93htcandpj86aev", + "symbol": "ENTRP-C8D", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "EOS BEP2", + "original_symbol": "EOS", + "owner": "bnb1la8alalwjzkchd67wza3r75lj5rm7m9e85ffqr", + "symbol": "EOS-CDD", + "total_supply": "500000.00000000" + }, + { + "mintable": true, + "name": "3X Short EOS Token", + "original_symbol": "EOSBEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "EOSBEAR-721", + "total_supply": "32301.00000000" + }, + { + "mintable": true, + "name": "3X Long EOS Token", + "original_symbol": "EOSBULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "EOSBULL-F0D", + "total_supply": "456191.00000000" + }, + { + "mintable": false, + "name": "EQUAL", + "original_symbol": "EQL", + "owner": "bnb1uz0s54rzv022dh66l7atwk83wqcet9qstgg358", + "symbol": "EQL-586", + "total_supply": "675259060.00000000" + }, + { + "mintable": true, + "name": "Elrond", + "original_symbol": "ERD", + "owner": "bnb1m5uzzfxs7x05sl28gg96zyecn9jwgtkpyeftyn", + "symbol": "ERD-D06", + "total_supply": "14500000000.00000000" + }, + { + "mintable": true, + "name": "ETH BEP2", + "original_symbol": "ETH", + "owner": "bnb1yss2345dphss8c823dh2jzje2w8k8x4jguuxhf", + "symbol": "ETH-1C9", + "total_supply": "10000.00000000" + }, + { + "mintable": true, + "name": "3X Short Ethereum Token", + "original_symbol": "ETHBEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "ETHBEAR-B2B", + "total_supply": "61821.00000000" + }, + { + "mintable": true, + "name": "3X Long Ethereum Token", + "original_symbol": "ETHBULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "ETHBULL-D33", + "total_supply": "33684.00000000" + }, + { + "mintable": true, + "name": "everiToken", + "original_symbol": "EVT", + "owner": "bnb1v3fl4kuwuhzf3g7ghscsq7uzmu5dw50waseptd", + "symbol": "EVT-49B", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "The Force Token", + "original_symbol": "FOR", + "owner": "bnb1c46nhwdwm3u2mlfhx6t07fls25shnvktpr9w9m", + "symbol": "FOR-997", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "Ferrum Network Token", + "original_symbol": "FRM", + "owner": "bnb1um8ntkgwle8yrdk0yn5hwdf7hckjpyjjg29k2p", + "symbol": "FRM-DE7", + "total_supply": "164609374.50000000" + }, + { + "mintable": false, + "name": "Fusion", + "original_symbol": "FSN", + "owner": "bnb17mnutyduat9fe02r2dawp3kn4rnaqamp5kpg0c", + "symbol": "FSN-E14", + "total_supply": "57344000.00000000" + }, + { + "mintable": true, + "name": "Fantom", + "original_symbol": "FTM", + "owner": "bnb1f6sxnf3nhn9fcfwkuccrzvl2pgu3sq0m8pyjhw", + "symbol": "FTM-A64", + "total_supply": "952500000.00000000" + }, + { + "mintable": true, + "name": "FTX Token", + "original_symbol": "FTT", + "owner": "bnb1msxdh7e7smpg68gxxhs0p3fhuj9tzhrxa4c2x2", + "symbol": "FTT-F11", + "total_supply": "10000000.00000000" + }, + { + "mintable": true, + "name": "Givly Coin", + "original_symbol": "GIV", + "owner": "bnb13jzr6sqz72fl0edg2tpqp8tddyzvyt4su2490m", + "symbol": "GIV-94E", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "GoWithMi", + "original_symbol": "GMAT", + "owner": "bnb1yltla9mnk8999ygmjjn3kwmmz2zs94a9v20sca", + "symbol": "GMAT-FC8", + "total_supply": "14900000000.00000000" + }, + { + "mintable": false, + "name": "Global Gaming", + "original_symbol": "GMNG", + "owner": "bnb1qe6zxqptfxw0kh38t8pg6c3qa527n2x2a87qvm", + "symbol": "GMNG-F3E", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "GTEX", + "original_symbol": "GTEX", + "owner": "bnb1nksrzfl24he9xtvdvpypsl6r5jnh5x2uf9s82z", + "symbol": "GTEX-71B", + "total_supply": "4000000000.00000000" + }, + { + "mintable": false, + "name": "Gifto", + "original_symbol": "GTO", + "owner": "bnb1lvp8k3zenlfp2pl2nyaf428xjgh385m258gzvq", + "symbol": "GTO-908", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "“Hermes", + "original_symbol": "HEC", + "owner": "bnb1dfyydqkmsv5m0rs0pa4uut2gwrcsahppktns2t", + "symbol": "HEC-1A9", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "Honest", + "original_symbol": "HNST", + "owner": "bnb1k9fv2hz0w3l9v9z4g9samg3gtc7nc2xgyqw5u0", + "symbol": "HNST-3C9", + "total_supply": "400000000.00000000" + }, + { + "mintable": true, + "name": "Hyperion Token", + "original_symbol": "HYN", + "owner": "bnb1q5cqecuy2g7syl8fssp9a7v2sjamtrzlr3pa0n", + "symbol": "HYN-F21", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Rupiah Token", + "original_symbol": "IDRTB", + "owner": "bnb1wc44duax6pygh23psx0u945skvs3eh7w59e4sp", + "symbol": "IDRTB-178", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "IKU", + "original_symbol": "IKU", + "owner": "bnb1f52tc9l0qg337qtgu4n024ayllc78wxpc5xhvd", + "symbol": "IKU-416", + "total_supply": "300000000.00000000" + }, + { + "mintable": true, + "name": "IRIS Network", + "original_symbol": "IRIS", + "owner": "bnb1dcpm0jjj8el8g6ekr3mvjxa8kptgu4e5xzvqv8", + "symbol": "IRIS-D88", + "total_supply": "2000000000.00000000" + }, + { + "mintable": false, + "name": "JDXUCoin", + "original_symbol": "JDXU", + "owner": "bnb1dwcsg0t86g7935zpxc054n97styzgdtnu2kzg6", + "symbol": "JDXU-706", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "Kambria Token", + "original_symbol": "KAT", + "owner": "bnb1l68n6equtr925lhnentyq54zfrzqyj45lg8uwj", + "symbol": "KAT-7BB", + "total_supply": "3700000000.00000000" + }, + { + "mintable": true, + "name": "Kava BEP2 Token", + "original_symbol": "KAVA", + "owner": "bnb1uyekdn62yur9zuctzqyd9ckasfvqttjz9c33me", + "symbol": "KAVA-10C", + "total_supply": "6071200.72181900" + }, + { + "mintable": false, + "name": "Sessia Kicks", + "original_symbol": "KICKS", + "owner": "bnb130tmwjd3fc79eh6f5ezl2326ur8rqpsxeeq30x", + "symbol": "KICKS-162", + "total_supply": "5000000.00000000" + }, + { + "mintable": true, + "name": "Lambda", + "original_symbol": "LAMB", + "owner": "bnb19vnwdjwthm9unxe9hxdxmgm6qw0d42d2lmcesw", + "symbol": "LAMB-46C", + "total_supply": "5000000.00000000" + }, + { + "mintable": false, + "name": "Lend-Borrow-Asset", + "original_symbol": "LBA", + "owner": "bnb1m8r74hr532lfwtaf5e88cxeakd36ut0ufpd4yu", + "symbol": "LBA-340", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "LITION", + "original_symbol": "LIT", + "owner": "bnb1fhlxwqlwd7cm5fmurg0wmsaalshnp7lwu46nk9", + "symbol": "LIT-099", + "total_supply": "145061313.45061312" + }, + { + "mintable": true, + "name": "Loki", + "original_symbol": "LOKI", + "owner": "bnb1j5sft8wp7tktjwauy30x79f3tqa53fycmgxxs0", + "symbol": "LOKI-6A9", + "total_supply": "3000000.00000000" + }, + { + "mintable": true, + "name": "LTC BEP2", + "original_symbol": "LTC", + "owner": "bnb1cn4sqm79wqmr8rey923r34cp2wrtyhlr9easpg", + "symbol": "LTC-F07", + "total_supply": "18500.00000000" + }, + { + "mintable": false, + "name": "LTO Network", + "original_symbol": "LTO", + "owner": "bnb1ac6p45m00pv36y9mu48e5xr73fyxke3zv2rhmq", + "symbol": "LTO-BDF", + "total_supply": "500000000.00000000" + }, + { + "mintable": false, + "name": "Matic Token", + "original_symbol": "MATIC", + "owner": "bnb1a6nkf3g7c2z0jcrqhp8c9upcwmme0y49qx58nz", + "symbol": "MATIC-84A", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Moviebloc", + "original_symbol": "MBL", + "owner": "bnb17p8rc0z5vlysff2wc7xehff464dm0v7nhl27xq", + "symbol": "MBL-2D2", + "total_supply": "30000000000.00000000" + }, + { + "mintable": true, + "name": "Mcashchain", + "original_symbol": "MCASH", + "owner": "bnb1q420q7qpyv7tghfp6aac7vnjq74dhkeutdhqsg", + "symbol": "MCASH-869", + "total_supply": "200000000.00000000" + }, + { + "mintable": false, + "name": "Magic Cube Token", + "original_symbol": "MCC", + "owner": "bnb14nt79d6hzhjefkys2cgrc9nrzugdjwwtggfmu4", + "symbol": "MCC-33B", + "total_supply": "20000000000.00000000" + }, + { + "mintable": false, + "name": "MDAB", + "original_symbol": "MDAB", + "owner": "bnb1m3edd4q4nd3wxg9vm3xe8pnfnetu5yjmhtnrqz", + "symbol": "MDAB-D42", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "MediBloc", + "original_symbol": "MEDB", + "owner": "bnb1za3ytyh55wprmn4ew8gat657lpjdzhafwrded3", + "symbol": "MEDB-87E", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "MEET.ONE", + "original_symbol": "MEETONE", + "owner": "bnb1zquk6usn03xnnht6ws6p0h4ylgk8jkhch6c6ck", + "symbol": "MEETONE-031", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "SyncFab Smart Manufacturing", + "original_symbol": "MFGB", + "owner": "bnb104qhlkx4fu6nvm32v4k7zzgtt4eqtyzvh9yq48", + "symbol": "MFGB-0A0", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "Mithril", + "original_symbol": "MITH", + "owner": "bnb15krsh6x2343qskf86cw0hazchl5pkfw53zllut", + "symbol": "MITH-C76", + "total_supply": "988855068.00409432" + }, + { + "mintable": false, + "name": "Morpheus Infrastructure Token", + "original_symbol": "MITX", + "owner": "bnb17e2n869fp6zvdyfaqkq3tgfmj8pskq20mdaz7e", + "symbol": "MITX-CAA", + "total_supply": "400000000.00000000" + }, + { + "mintable": false, + "name": "MultiVAC", + "original_symbol": "MTV", + "owner": "bnb18cjgqwpj2sxdxf7u84hgzh76cmqvthw7fgtr7z", + "symbol": "MTV-4C6", + "total_supply": "8000000000.00000000" + }, + { + "mintable": false, + "name": "Tixl", + "original_symbol": "MTXLT", + "owner": "bnb1pwcluc3a2lswrdd8v3uq43qrgfdl6kv2ahrz43", + "symbol": "MTXLT-286", + "total_supply": "900000.00000000" + }, + { + "mintable": true, + "name": "Mass Vehicle Ledger", + "original_symbol": "MVL", + "owner": "bnb1mqdkp0ujngm58sus3fh5x9c0j59madqxej9q75", + "symbol": "MVL-7B0", + "total_supply": "8000000000.00000000" + }, + { + "mintable": false, + "name": "Muzika", + "original_symbol": "MZK", + "owner": "bnb1dkqsj76yr6nlegs3433m3c59mm0j7vy72nn275", + "symbol": "MZK-2C7", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "NEWTON", + "original_symbol": "NEW", + "owner": "bnb1ud4ak7pj5kg5kqddhx9yacdu6sf7sxhqdv30k0", + "symbol": "NEW-09E", + "total_supply": "90000000000.00000000" + }, + { + "mintable": true, + "name": "Nexo", + "original_symbol": "NEXO", + "owner": "bnb15ngukylwcleljegx32ykefqxw8jz42szar6vf5", + "symbol": "NEXO-A84", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "NODE", + "original_symbol": "NODE", + "owner": "bnb1xljnjk7msm5t5lwp4zv2ua80rrxzn2s2afce4j", + "symbol": "NODE-F3A", + "total_supply": "2000000000.00000000" + }, + { + "mintable": false, + "name": "NOIZ Token", + "original_symbol": "NOIZB", + "owner": "bnb1fa9xgszkn57zq0aulfgk5hct09yx5heepum3x7", + "symbol": "NOIZB-878", + "total_supply": "400000000.00000000" + }, + { + "mintable": true, + "name": "NOW Token", + "original_symbol": "NOW", + "owner": "bnb1nug8ls9f0et0t558m4chmm46mf85ehpq0u8gwv", + "symbol": "NOW-E68", + "total_supply": "99939495.70000000" + }, + { + "mintable": false, + "name": "NPX Binance token", + "original_symbol": "NPXB", + "owner": "bnb1wf7z3e8wvcu7gs74stmfmktsa2m5738rd0znae", + "symbol": "NPXB-1E8", + "total_supply": "29800000.00000000" + }, + { + "mintable": false, + "name": "Pundi X NEM", + "original_symbol": "NPXSXEM", + "owner": "bnb1wuww3cqy6wn5jdp6emv0eqwd5khlc3qyy0ympp", + "symbol": "NPXSXEM-89C", + "total_supply": "44815631324.40000000" + }, + { + "mintable": true, + "name": "Harmony.One", + "original_symbol": "ONE", + "owner": "bnb1a03uvqmnqzl85csnxnsx2xy28m76gkkht46f2l", + "symbol": "ONE-5F9", + "total_supply": "12600000000.00000000" + }, + { + "mintable": true, + "name": "ONTBEP2", + "original_symbol": "ONT", + "owner": "bnb1lxlxzanvg5ud02vjcvuxqrdystcehvtj6a05s2", + "symbol": "ONT-33D", + "total_supply": "1500000.00000000" + }, + { + "mintable": false, + "name": "OpenWeb Token", + "original_symbol": "OWTX", + "owner": "bnb1qnzqrxpek5dy6hh4fjywjv60x806yv2kpwt64y", + "symbol": "OWTX-A6B", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "Pink Care Token", + "original_symbol": "PCAT", + "owner": "bnb1xx54pavpran2c36ugvnxnrfszwn36cryqfzufa", + "symbol": "PCAT-4BB", + "total_supply": "50000.00000000" + }, + { + "mintable": true, + "name": "Red Pulse Phoenix Binance", + "original_symbol": "PHB", + "owner": "bnb1vvvm62cezjy35xa46lghjs2jthzzdlpfyqg90a", + "symbol": "PHB-2DF", + "total_supply": "1598758851.80873855" + }, + { + "mintable": true, + "name": "PathHive Network", + "original_symbol": "PHV", + "owner": "bnb13nltf0vw66kw737dej6kc0fy85u3a38avr0xmf", + "symbol": "PHV-4A1", + "total_supply": "350000000.00000000" + }, + { + "mintable": false, + "name": "PCHAIN Token", + "original_symbol": "PIBNB", + "owner": "bnb1lvq8c3ul472aqrsknnvqumjszt2v60s0zagw6r", + "symbol": "PIBNB-43C", + "total_supply": "1071000000.00000000" + }, + { + "mintable": false, + "name": "Pledge Coin", + "original_symbol": "PLG", + "owner": "bnb1wjxhqa6ud4ucxayjqd9necfq0n954ztncsn7zn", + "symbol": "PLG-D8D", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "PPE Token", + "original_symbol": "PPE", + "owner": "bnb1ry96fn3gl3wskha86lhgx8ckrgt3vgrnwq8quz", + "symbol": "PPE-942", + "total_supply": "200000.00000000" + }, + { + "mintable": false, + "name": "Pivot Token", + "original_symbol": "PVT", + "owner": "bnb1vgzzktw8j46hd87npsrukxhzxecq8knnt96tyf", + "symbol": "PVT-554", + "total_supply": "6283185307.00000000" + }, + { + "mintable": false, + "name": "paycentos", + "original_symbol": "PYN", + "owner": "bnb190acfwshh899eylweut9xarls2ma953rvkdlhf", + "symbol": "PYN-C37", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "QARK", + "original_symbol": "QARK", + "owner": "bnb1wnwrnmc6y9pl6ve9g7mahd4wkactaldyx3hsmu", + "symbol": "QARK-FCE", + "total_supply": "77000000.00000000" + }, + { + "mintable": true, + "name": "qiibeeToken", + "original_symbol": "QBX", + "owner": "bnb1eq8cytar7a3rer3ms7dpatd3cuhpfhaw3ts6tr", + "symbol": "QBX-38C", + "total_supply": "138039216.00000000" + }, + { + "mintable": false, + "name": "Raven Protocol", + "original_symbol": "RAVEN", + "owner": "bnb1vdjhrkgvt4y76ykyvrvh68pzqg3lvv0y5yfxyf", + "symbol": "RAVEN-F66", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Reporter News Agency Token", + "original_symbol": "RNA", + "owner": "bnb1m033d9a5fuf6r8wxqcguhwrnnk7sffcljzrc83", + "symbol": "RNA-23B", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "Rasputin Party Mansion Phase2", + "original_symbol": "ROCP2", + "owner": "bnb16fyhf2hw8d5raxtympp48nzt2ezw6dqvfv5cd3", + "symbol": "ROCP2-F01", + "total_supply": "27000000.00000000" + }, + { + "mintable": false, + "name": "Rapids", + "original_symbol": "RPD", + "owner": "bnb1vtpy8dly2jfsn6v3t0qnyfxrex9sdy0entp5zs", + "symbol": "RPD-9E0", + "total_supply": "1500000000.00000000" + }, + { + "mintable": false, + "name": "Rune", + "original_symbol": "RUNE", + "owner": "bnb1e4q8whcufp6d72w8nwmpuhxd96r4n0fstegyuy", + "symbol": "RUNE-B1A", + "total_supply": "500000000.00000000" + }, + { + "mintable": false, + "name": "ShareToken", + "original_symbol": "SHR", + "owner": "bnb12c94hfu5vm77a9xkwfyl2ztgwgk503a06zl70e", + "symbol": "SHR-DB6", + "total_supply": "4396000000.00000000" + }, + { + "mintable": false, + "name": "Silverway", + "original_symbol": "SLV", + "owner": "bnb15nhdv2m09uwgnmmhx73dcguag7n363fdzdsg23", + "symbol": "SLV-986", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "SPIN Protocol", + "original_symbol": "SPIN", + "owner": "bnb12n8fqjp8vh00s5u89paewv0wk8avr3nyvhsl4j", + "symbol": "SPIN-9DD", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "Spendcoin", + "original_symbol": "SPNDB", + "owner": "bnb105n32ugq55kzlyz3tuug35d3t0ul37lx9aksah", + "symbol": "SPNDB-916", + "total_supply": "2000000000.00000000" + }, + { + "mintable": false, + "name": "STIPS Token", + "original_symbol": "STIPS", + "owner": "bnb1tug8sgfcuh0rdyr697k5pnwz9expj7v5zr3qs5", + "symbol": "STIPS-14F", + "total_supply": "128806335.86000000" + }, + { + "mintable": false, + "name": "STIPS", + "original_symbol": "STIPS", + "owner": "bnb1tug8sgfcuh0rdyr697k5pnwz9expj7v5zr3qs5", + "symbol": "STIPS-770", + "total_supply": "243585434.00000000" + }, + { + "mintable": false, + "name": "Yin Lang Music IP Token", + "original_symbol": "STYL", + "owner": "bnb1j2dgknw9l4jny8crjdn6vcjsnu23ejxhchrumg", + "symbol": "STYL-65B", + "total_supply": "100000.00000000" + }, + { + "mintable": false, + "name": "Swingby Token", + "original_symbol": "SWINGBY", + "owner": "bnb1thagrtfude74x2j2wuknhj2savucy2tx0k58y9", + "symbol": "SWINGBY-888", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "SWIPE Token", + "original_symbol": "SWIPE.B", + "owner": "bnb17pwyw202w7fssznnnv8f2gukau49uc4m4chz4m", + "symbol": "SWIPE.B-DC0", + "total_supply": "1500000000.00000000" + }, + { + "mintable": true, + "name": "TrueAUD", + "original_symbol": "TAUDB", + "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", + "symbol": "TAUDB-888", + "total_supply": "90000000000.00000000" + }, + { + "mintable": true, + "name": "TBCC Coin", + "original_symbol": "TBC", + "owner": "bnb18hvknjyd73dx3ud02zp3z8v6du50vw7jxp06xt", + "symbol": "TBC-3A7", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "TrueCAD", + "original_symbol": "TCADB", + "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", + "symbol": "TCADB-888", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "TrustED Token", + "original_symbol": "TED", + "owner": "bnb1zwg63xvmn02u8lv8v2sq0ypaejehhv3fceeu8a", + "symbol": "TED-A85", + "total_supply": "1720000000.00000000" + }, + { + "mintable": true, + "name": "TrueGBP", + "original_symbol": "TGBPB", + "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", + "symbol": "TGBPB-888", + "total_supply": "90000000000.00000000" + }, + { + "mintable": true, + "name": "TrueHKD", + "original_symbol": "THKDB", + "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", + "symbol": "THKDB-888", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "Traxia 2", + "original_symbol": "TM2", + "owner": "bnb1pdeggk7lgch37ks7e3l5x3n5y245krl3zmrl8e", + "symbol": "TM2-0C4", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "TomoChain", + "original_symbol": "TOMOB", + "owner": "bnb1jmgew0xvtkfjhnqsglm50tynxgps3xkx0xqffy", + "symbol": "TOMOB-4BC", + "total_supply": "5000000.00000000" + }, + { + "mintable": false, + "name": "TOP Network", + "original_symbol": "TOP", + "owner": "bnb1lqc7vjrag9sdaqeuv22jccr4rxtdxdtq6ve2w6", + "symbol": "TOP-491", + "total_supply": "20000000000.00000000" + }, + { + "mintable": false, + "name": "TROY", + "original_symbol": "TROY", + "owner": "bnb1scrark2sv6fpngyqxrryw9hw7y05euwntz45ae", + "symbol": "TROY-9B8", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "TrueChain", + "original_symbol": "TRUE", + "owner": "bnb1m0llwxe0nwtw98m7knpz3g7r0c98mwn7tfwjcc", + "symbol": "TRUE-D84", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "TRXB", + "original_symbol": "TRXB", + "owner": "bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq", + "symbol": "TRXB-2E6", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "TrueUSD", + "original_symbol": "TUSDB", + "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", + "symbol": "TUSDB-888", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "Trust Wallet", + "original_symbol": "TWT", + "owner": "bnb1fkyxlq9kz5368ux29aeeztslclgf8e7tja345x", + "symbol": "TWT-8C2", + "total_supply": "90000000000.00000000" + }, + { + "mintable": true, + "name": "“Ubet", + "original_symbol": "UBETS", + "owner": "bnb1gcpctmgmf0am0ft85ttswy2epd9d6vvvxu2ly6", + "symbol": "UBETS-068", + "total_supply": "4000000000.00000000" + }, + { + "mintable": false, + "name": "Ultrain Coin", + "original_symbol": "UGAS", + "owner": "bnb1mj2nncwkmrw9pr6d0spkfmewz5eynz63w67f6e", + "symbol": "UGAS-B0C", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "United Network Distribution", + "original_symbol": "UND", + "owner": "bnb1q5tr6ggvg0h38axzw2dc4606j3edg58qug9ajr", + "symbol": "UND-EBC", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "UPX", + "original_symbol": "UPX", + "owner": "bnb1588jx9ylvfpfhdzy672lk3pulleq8md0a4wcjl", + "symbol": "UPX-F3E", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "HonestCoin", + "original_symbol": "USDH", + "owner": "bnb1kel6x8nl37j2w6963c3gxnwzplvkwkphrkdmx9", + "symbol": "USDH-5B5", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "USDS", + "original_symbol": "USDSB", + "owner": "bnb1nf5qjthrmxwxnfct4j0w4ct03fghthq24qt990", + "symbol": "USDSB-1AC", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "UTU Coin", + "original_symbol": "UTU", + "owner": "bnb1r7whkqt8q2efn3c2ynsshrvxkg07cu8etuxkwr", + "symbol": "UTU-159", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "UNetwork Token", + "original_symbol": "UUU", + "owner": "bnb17mkwwvzxaxa792rggvcmrpe6d7la4j9tjhdaql", + "symbol": "UUU-35C", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Vodi X", + "original_symbol": "VDX", + "owner": "bnb1pk6umuhxjcd3ggyztw7a7lfggwgyyx2w5h8j59", + "symbol": "VDX-A17", + "total_supply": "300000000.00000000" + }, + { + "mintable": false, + "name": "V-ID Token", + "original_symbol": "VIDT", + "owner": "bnb1k8870xayp29jug2lw9ujcqnjv6q6nu92enkg8v", + "symbol": "VIDT-F53", + "total_supply": "36800171.30000000" + }, + { + "mintable": true, + "name": "VNDC", + "original_symbol": "VNDC", + "owner": "bnb1zxt4xh4xxdnv5aagh77a4zp2kflg6a2c22hp73", + "symbol": "VNDC-DB9", + "total_supply": "2050000000.00000000" + }, + { + "mintable": false, + "name": "Vote", + "original_symbol": "VOTE", + "owner": "bnb1px34z7hw3hjtcf4ul664azxl4jwmkvgdnfep5e", + "symbol": "VOTE-FD4", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "VERA", + "original_symbol": "VRAB", + "owner": "bnb1ucrwnsvjetufca3u6hnqskz0jfrwascwzg5tyf", + "symbol": "VRAB-B56", + "total_supply": "10839985784.00000000" + }, + { + "mintable": true, + "name": "Wagerr", + "original_symbol": "WGR", + "owner": "bnb194yuu322fqk69g2el8c874np5hjc8fykft3wv3", + "symbol": "WGR-D3D", + "total_supply": "205000000.00000000" + }, + { + "mintable": true, + "name": "WaykiChain Coin", + "original_symbol": "WICC", + "owner": "bnb1cw6kw5q0xcaxvpqravfewrcca9jgkdmd3zpc5n", + "symbol": "WICC-01D", + "total_supply": "210000000.00000000" + }, + { + "mintable": true, + "name": "WINB", + "original_symbol": "WINB", + "owner": "bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq", + "symbol": "WINB-41F", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "MyWish", + "original_symbol": "WISH", + "owner": "bnb1tawge8u97slduhhtumm03l4xl4c46dwv5m9yzk", + "symbol": "WISH-2D5", + "total_supply": "9546650.62357825" + }, + { + "mintable": false, + "name": "WazirX Token", + "original_symbol": "WRX", + "owner": "bnb19cvhgyrxmkw30hlqs9c5lp966drjzyylytl74z", + "symbol": "WRX-ED1", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "Eterbase Coin", + "original_symbol": "XBASE", + "owner": "bnb177v0mn59lmuxu90uph5mg065n9l4f3r4zqllvd", + "symbol": "XBASE-CD2", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "XIO", + "original_symbol": "XIO", + "owner": "bnb1egwrlcwqkluqpujfwc5r2d27ggg7kv0lteyez9", + "symbol": "XIO-B05", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "Xeonbit Token", + "original_symbol": "XNS", + "owner": "bnb17az2n3ll3wjgf3gnn2chqxawzgrv9xv9vrkc79", + "symbol": "XNS-760", + "total_supply": "300000000.00000000" + }, + { + "mintable": true, + "name": "XRP BEP2", + "original_symbol": "XRP", + "owner": "bnb1x0vv5l6u5c7vpl7c947uxmm0gfstpdhg93gxpt", + "symbol": "XRP-BF2", + "total_supply": "10000000.00000000" + }, + { + "mintable": true, + "name": "3X Short XRP Token", + "original_symbol": "XRPBEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "XRPBEAR-00B", + "total_supply": "1348.00000000" + }, + { + "mintable": true, + "name": "3X Long XRP Token", + "original_symbol": "XRPBULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "XRPBULL-E7C", + "total_supply": "121291.00000000" + }, + { + "mintable": true, + "name": "XTZ BEP2", + "original_symbol": "XTZ", + "owner": "bnb12twkcedchmx3xn09jcf28u7xrg0mqsyluf56g4", + "symbol": "XTZ-F7A", + "total_supply": "250000.00000000" + }, + { + "mintable": false, + "name": "XWG", + "original_symbol": "XWG", + "owner": "bnb10s02g69vhym56ke23nkacmuf9038e8rr7dm8e8", + "symbol": "XWG-478", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "“YeeCo”", + "original_symbol": "YEE", + "owner": "bnb1ykzzc0zevzsade3urq4t27rfz98xgquphm8ucs", + "symbol": "YEE-EAE", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "ZEBI", + "original_symbol": "ZEBI", + "owner": "bnb1gca96lw9zlr8fct47wznsae67pc5wjwsjzamaf", + "symbol": "ZEBI-84F", + "total_supply": "1000000000.00000000" + } +] diff --git a/mock/ext-api-data/binance-explorer_v1_txs__address_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q_txAsset_BNB_txType_TRANSFER.json b/mock/ext-api-data/binance-explorer_v1_txs__address_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q_txAsset_BNB_txType_TRANSFER.json new file mode 100644 index 000000000..980f8e988 --- /dev/null +++ b/mock/ext-api-data/binance-explorer_v1_txs__address_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q_txAsset_BNB_txType_TRANSFER.json @@ -0,0 +1 @@ +{"txNums":169,"txArray":[{"txHash":"CC11034825A1BB932D608F36BAA0655E6216C9BBA4769BC87FF0139609035650","blockHeight":87897954,"txType":"TRANSFER","timeStamp":1589571344220,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":219373,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"7DAD217B37B177538F60286E1ACAE0A739FA3EDC365F92C9A8BCA1EB9D1C466B","blockHeight":87897869,"txType":"TRANSFER","timeStamp":1589571308616,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":219409,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"3235A163F37B0F99C7570BDA9A2621CC115087FF8C6252B4FC340DF9C10C64EE","blockHeight":87897753,"txType":"TRANSFER","timeStamp":1589571259838,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00010000,"txAsset":"BNB","txFee":0.00037500,"txAge":219458,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"A0ED9785BAB44DE6D9F5311CE04E667E0107664B9E27C3ACA05AF4DBFE509474","blockHeight":87897702,"txType":"TRANSFER","timeStamp":1589571238493,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000100,"txAsset":"BNB","txFee":0.00037500,"txAge":219479,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"67B40FD9BD380D8BDB6ED0DF213690658A5B9FE1275FEE360A31E7D9D56D3156","blockHeight":87897594,"txType":"TRANSFER","timeStamp":1589571193162,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00010000,"txAsset":"BNB","txFee":0.00037500,"txAge":219524,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"A6603647F2DCC653A2A11FB5F3D2B82EF503860CECE7A5127BD9E3FA678CA4C8","blockHeight":87891198,"txType":"TRANSFER","timeStamp":1589568627146,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":222090,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"32080C2367C103C6B70EF8179BEA07803BA1A8A478897DE9EC99D95D5B6DBFA9","blockHeight":87890837,"txType":"TRANSFER","timeStamp":1589568487902,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":222230,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"AF6B71DA568D561E6DC450DE15FC9A77C58917323F67536AEB9EBC459D414000","blockHeight":87888079,"txType":"TRANSFER","timeStamp":1589567383565,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":223334,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"ACC83ACD8D8F9073B25DD0A504EAA936882DA5305EA805622A34E725AABB8B73","blockHeight":87769136,"txType":"TRANSFER","timeStamp":1589519763058,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":270955,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"CED98241EE857C699FCCA5FBEC16F6604F93FA2943AD281A366AEF771B4F6081","blockHeight":87764491,"txType":"TRANSFER","timeStamp":1589517890608,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":272827,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"4A254FDDC8C3FAEE0E2BDF58370DD27055CA4D6C298730397D9702AC4FE676B0","blockHeight":87764293,"txType":"TRANSFER","timeStamp":1589517808749,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000100,"txAsset":"BNB","txFee":0.00037500,"txAge":272909,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"568B67B0B264031E6F712C31A2B81D86F74D839F131D1E562B20AE06A61252A5","blockHeight":87709527,"txType":"TRANSFER","timeStamp":1589495866706,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000001,"txAsset":"BNB","txFee":0.00037500,"txAge":294851,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"A5F25D0CA39CFC42C901E61E610C3D791E26D4F0401A74F7249B69029CC953E9","blockHeight":87709081,"txType":"TRANSFER","timeStamp":1589495676493,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":295041,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"B915CE3D9B0C92EB44A4197455A8A27A94566A20A2384E05F20A31C4276EAE54","blockHeight":87708586,"txType":"TRANSFER","timeStamp":1589495469184,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":295248,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"F105829EF7E0828CDADA00B0E0CD84443D219ED475EF452E685DD0FD74A9CA96","blockHeight":86779776,"txType":"TRANSFER","timeStamp":1589124863044,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":665855,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"2DD72EAEDAD575F956BAF5C0EE86A2BEF322715FB9D831959BF8D82A992D41DF","blockHeight":86779508,"txType":"TRANSFER","timeStamp":1589124756232,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00010000,"txAsset":"BNB","txFee":0.00037500,"txAge":665961,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"395F3450AF823D472C9F6DD626B50F2B0875E8BAEE9CE4EEF98C76640B25BFBE","blockHeight":86779356,"txType":"TRANSFER","timeStamp":1589124695388,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":666022,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"EB52141321642002C91551C4511C522F10887F338699E9C4D5821C879F73A669","blockHeight":85915186,"txType":"TRANSFER","timeStamp":1588777143568,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":1013574,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"F15B711FA2F6DCCDC3D28FB74138B037E9B3840FFDB87F0E322DA4544982B65C","blockHeight":80642308,"txType":"TRANSFER","timeStamp":1586654422855,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":3136295,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"D6E00221A466618281A82B053C0C0C89FC99AB637343079C89F0184611263BBD","blockHeight":80636397,"txType":"TRANSFER","timeStamp":1586652053921,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000100,"txAsset":"BNB","txFee":0.00037500,"txAge":3138664,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0}]} \ No newline at end of file diff --git a/mock/ext-api-data/bitcoin-api_v2_address_bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj__details_txs.json b/mock/ext-api-data/bitcoin-api_v2_address_bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj__details_txs.json new file mode 100644 index 000000000..c4811b317 --- /dev/null +++ b/mock/ext-api-data/bitcoin-api_v2_address_bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj__details_txs.json @@ -0,0 +1,700 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj", + "balance": "16245", + "totalReceived": "92089", + "totalSent": "75844", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 13, + "transactions": [ + { + "txid": "48554ab85af888894d3f247088fdb8b7fff412612b54f0069f89dda3bd80f0ce", + "version": 1, + "vin": [ + { + "txid": "ffd5f12382137dfc62866694f77405ecb6d4cf2cc286ac66d192f7e842787c0f", + "sequence": 4294967293, + "n": 0, + "addresses": [ + "bc1qhddmnwdqwuvt6zl7auu976scg7rmtpx6amumsd" + ], + "isAddress": true, + "value": "3220" + } + ], + "vout": [ + { + "value": "1000", + "n": 0, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "1994", + "n": 1, + "hex": "0014bb5bb9b9a07718bd0bfeef385f6a184787b584da", + "addresses": [ + "bc1qhddmnwdqwuvt6zl7auu976scg7rmtpx6amumsd" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000000005e0a9278dcf1a18390c78c27d5f47dc0777772b1e54b", + "blockHeight": 627865, + "confirmations": 2356, + "blockTime": 1587999059, + "value": "2994", + "valueIn": "3220", + "fees": "226", + "hex": "010000000001010f7c7842e8f792d166ac86c22ccfd4b6ec0574f794668662fc7d138223f1d5ff0000000000fdffffff02e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169aca07000000000000160014bb5bb9b9a07718bd0bfeef385f6a184787b584da0247304402203285e50928e3d4f67093bb457fe51b60a9e1981868666d8f79bf272868484f1d02200e7093af7d2d7cb68bc0801587b619c2022f02084fac3902fe93e47977aed6c30121034df96f5dacf5e22fb8611e6863e48f6777c7e96064c81196e23dcefd35017d0e00000000" + }, + { + "txid": "36b1e721a25ea3ac2fcc09a92d4ff1e2ae4ed70d593e276806d9a9fd2a901132", + "version": 1, + "vin": [ + { + "txid": "c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be", + "vout": 1, + "n": 0, + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true, + "value": "4829" + } + ], + "vout": [ + { + "value": "1000", + "n": 0, + "spent": true, + "hex": "a9141ba5187259ae22520f99ec3522d320279066aafd87", + "addresses": [ + "34DBwkzPz6yeqU1LoZLVzdCm91oeyxq37T" + ], + "isAddress": true + }, + { + "value": "2699", + "n": 1, + "hex": "00148f347b3ea1ce113b09e096125a3ad3310dd0a947", + "addresses": [ + "bc1q3u68k04pecgnkz0qjcf95wknxyxap2287gyzrg" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000000fccc2c78e235d6ea3da4013ea98c8376c7c41f7f71938", + "blockHeight": 624894, + "confirmations": 5327, + "blockTime": 1586299624, + "value": "3699", + "valueIn": "4829", + "fees": "1130", + "hex": "01000000000101be328cc2ca0135e640bc1e795f20d3189939ab3712d8e79627347a5c2dc8a4c601000000000000000002e80300000000000017a9141ba5187259ae22520f99ec3522d320279066aafd878b0a0000000000001600148f347b3ea1ce113b09e096125a3ad3310dd0a94702483045022100c251d7e2497b42d57ff00c92eeb8a6faa86a3d5d77a9d257b7e464400306fa5502204f532ab553ba711779cf1f93cab47c4f5e0f11dbc6017781c79b76caa6ea322b012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" + }, + { + "txid": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4", + "version": 1, + "vin": [ + { + "txid": "270a6490cc806d99aa84bb8079b543d9d7a255fc59364890e7a4cb57970daef8", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "bc1q3230a7cqt2drewuza8qff4c4gpt4muy9qyqknw" + ], + "isAddress": true, + "value": "1699" + } + ], + "vout": [ + { + "value": "375", + "n": 0, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "1098", + "n": 1, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", + "blockHeight": 622017, + "confirmations": 8204, + "blockTime": 1584485709, + "value": "1473", + "valueIn": "1699", + "fees": "226", + "hex": "01000000000101f8ae0d9757cba4e790483659fc55a2d7d943b57980bb84aa996d80cc90640a270100000000feffffff0277010000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a4a040000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220683d9c2b40958fd706623783017300ebbc9b73ce1db571963d9bb40679c3079c02207ee68976e225e1e98d20e66d4d8a498cddf3268d0d7b66827a2ed3ac4330f137012102b7f0cb54c2a6a4da3372fe17d7a07475f575777364633e89dacb39eb1fd5a09c00000000" + }, + { + "txid": "c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be", + "version": 1, + "vin": [ + { + "txid": "d39d78838d5a3c870aa5acdc9e518945bd6ad86af093b38f85c714f790f28c76", + "vout": 1, + "n": 0, + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true, + "value": "6055" + } + ], + "vout": [ + { + "value": "1000", + "n": 0, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "4829", + "n": 1, + "spent": true, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", + "blockHeight": 622017, + "confirmations": 8204, + "blockTime": 1584485709, + "value": "5829", + "valueIn": "6055", + "fees": "226", + "hex": "01000000000101768cf290f714c7858fb393f06ad86abd4589519edcaca50a873c5a8d83789dd301000000000000000002e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169add120000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a02483045022100cb25ac0d9e69ddaaedd49e3a3f9efb218b38bf49c2abf44ff2266bfb941bd3b202206b32cc1337f9a6a176fabadd6aefdf5a95d479e5db856d4e3e8eee7fefc26773012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" + }, + { + "txid": "d39d78838d5a3c870aa5acdc9e518945bd6ad86af093b38f85c714f790f28c76", + "version": 1, + "vin": [ + { + "txid": "c215e9c6f9533d584effc4d31d08736a0ef4f717b7d42563ebba053f5f3bc1d5", + "vout": 1, + "sequence": 4294967287, + "n": 0, + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true, + "value": "8185" + } + ], + "vout": [ + { + "value": "1000", + "n": 0, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "6055", + "n": 1, + "spent": true, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000000ab8b2230f5b63d4d4be1a0aa6b9296cfc09e48c8e42e0", + "blockHeight": 619385, + "confirmations": 10836, + "blockTime": 1582902175, + "value": "7055", + "valueIn": "8185", + "fees": "1130", + "hex": "01000000000101d5c13b5f3f05baeb6325d4b717f7f40e6a73081dd3c4ff4e583d53f9c6e915c20100000000f7ffffff02e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169aa7170000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220158b0d8c5fb6cb9f60d0af05ce8b63abe934dca8eca380013bc7e8463420810f02207d7e6594586ec8196546e2520b6775c2e8659c8f266acb3b861e99f13cf1b380012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" + }, + { + "txid": "c215e9c6f9533d584effc4d31d08736a0ef4f717b7d42563ebba053f5f3bc1d5", + "version": 1, + "vin": [ + { + "txid": "1fb8f63b044160a7f918b5db85fa7bed3415848bd733f5827d7ae10cf738b387", + "sequence": 4294967287, + "n": 0, + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true, + "value": "10315" + } + ], + "vout": [ + { + "value": "1000", + "n": 0, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "8185", + "n": 1, + "spent": true, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000000fc5707f9351bdefada8c42267c9d63baf404268d65ca0", + "blockHeight": 619383, + "confirmations": 10838, + "blockTime": 1582901173, + "value": "9185", + "valueIn": "10315", + "fees": "1130", + "hex": "0100000000010187b338f70ce17a7d82f533d78b841534ed7bfa85dbb518f9a76041043bf6b81f0000000000f7ffffff02e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169af91f0000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024830450221008e721f8e1ec8c22e2cec8fb2744d451cb11decabd0ed6b8080b5949f8c34ad3c022070815d97c02a3befae53dfceae504bd4495f034afba9e8e1e84595d07d933a60012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" + }, + { + "txid": "1fb8f63b044160a7f918b5db85fa7bed3415848bd733f5827d7ae10cf738b387", + "version": 1, + "vin": [ + { + "txid": "3eb38e946261c8c7312f02cf72a72ac8d93ede94aa21520fbf06dd9b1f3f4392", + "vout": 1, + "n": 0, + "addresses": [ + "bc1qjar8852c43h73ud79xjluy2e7qce58peymsts8" + ], + "isAddress": true, + "value": "194390" + } + ], + "vout": [ + { + "value": "10315", + "n": 0, + "spent": true, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "179781", + "n": 1, + "spent": true, + "hex": "0014974673d158ac6fe8f1be29a5fe1159f0319a1c39", + "addresses": [ + "bc1qjar8852c43h73ud79xjluy2e7qce58peymsts8" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000000099b3509cf7d55c3c1894f814ab45bdccb32aa2b5e3e46", + "blockHeight": 616239, + "confirmations": 13982, + "blockTime": 1580992887, + "value": "190096", + "valueIn": "194390", + "fees": "4294", + "hex": "0100000000010192433f1f9bdd06bf0f5221aa94de3ed9c82aa772cf022f31c7c86162948eb33e010000000000000000024b280000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a45be020000000000160014974673d158ac6fe8f1be29a5fe1159f0319a1c3902483045022100a2cb51287dd8fd1e7eb9c48be73cba46ddf75287617c38f68618062c945ecbc802206f357933216b63a4530687223e60900c29d1d0869461d6707d7fa202a3c09d9301210289f9d29f5e11c87d2cdbc213d05b7f2aef0291b89b87e7a6f747461d2f75fd9a00000000" + }, + { + "txid": "35caac179d1a85f7c495d9a716d85bb02ed925170fc4716e8b04791acd487419", + "version": 1, + "vin": [ + { + "txid": "45cd3053d5393b2959646d023e1f2fa272d950903ed8b44502db88c9a04325fe", + "vout": 1, + "n": 0, + "addresses": [ + "bc1qs6q3tdsa09dtrwn0ml7d6ser4zdagja23rks6a" + ], + "isAddress": true, + "value": "2470973" + } + ], + "vout": [ + { + "value": "10772", + "n": 0, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "2455681", + "n": 1, + "spent": true, + "hex": "0014974673d158ac6fe8f1be29a5fe1159f0319a1c39", + "addresses": [ + "bc1qjar8852c43h73ud79xjluy2e7qce58peymsts8" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000000fcc2170ca9e17fd26747dd40bbf0388324cb872cd7a72", + "blockHeight": 615391, + "confirmations": 14830, + "blockTime": 1580495311, + "value": "2466453", + "valueIn": "2470973", + "fees": "4520", + "hex": "01000000000101fe2543a0c988db0245b4d83e9050d972a22f1f3e026d6459293b39d55330cd4501000000000000000002142a0000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a8178250000000000160014974673d158ac6fe8f1be29a5fe1159f0319a1c390247304402207fd1c5f4e69845d67696f6dd3f9160fba8e66edb959742b3836f9d6b51b7ef3e022066940b74c238971d0f826648a2bc4806b88be512b6c2bbb08f95e32bbd1ad52f0121020201a3d7f2d6e0e63a7f73e6dfad80d47acaba509585fb40c3c0f54ed9e2478700000000" + }, + { + "txid": "f294afc59e9cf67b50485747c595fcced86d80a3b2783e1df7c0e6189e8a9ecc", + "version": 1, + "vin": [ + { + "txid": "cc6a3c78152df7f1d8976bd1eab82b225e71753f7e0070b387ad39d0da405eb2", + "vout": 1, + "sequence": 4294967289, + "n": 0, + "addresses": [ + "bc1q37qr7p2swx4d034htxwfps0sp7lsyztxw7wuqz" + ], + "isAddress": true, + "value": "3015" + }, + { + "txid": "f8a3a4d6a1c6e9d3450330aa69531fa5d4fbbc6756321e535e55019f276d4de1", + "sequence": 4294967294, + "n": 1, + "addresses": [ + "bc1q0gypp968wfjwjll7p5gfpfgtzu5sjezqgqn6df" + ], + "isAddress": true, + "value": "3644" + }, + { + "txid": "6cb59213f5465c2f8f25fad9c4196291135576c3431dbf1bafffd2d8ae11150b", + "vout": 1, + "sequence": 4294967286, + "n": 2, + "addresses": [ + "bc1qa64vqxuws7tystf6ssqrmc4qplx6ertk0t5g4n" + ], + "isAddress": true, + "value": "3976" + }, + { + "txid": "270a6490cc806d99aa84bb8079b543d9d7a255fc59364890e7a4cb57970daef8", + "sequence": 4294967290, + "n": 3, + "addresses": [ + "bc1q08ujs8m9v73hvkgf6ad09r35t8e403creglz2r" + ], + "isAddress": true, + "value": "4000" + }, + { + "txid": "5c532521086fea144904ecac58fc871fb6e153234434347740c5bd100f5d147a", + "sequence": 4294967292, + "n": 4, + "addresses": [ + "bc1q2lk3mssjhcpde3u0mnj76yqlrf579me7fjt3aq" + ], + "isAddress": true, + "value": "5000" + }, + { + "txid": "a456760ad81c5ee66919a64f45aa27c089023586da1866a37c062a2f255a492a", + "sequence": 4294967288, + "n": 5, + "addresses": [ + "bc1qt3wcz3w2rmhhuvr34zsf4f07yfnuctasu7cw6f" + ], + "isAddress": true, + "value": "5274" + }, + { + "txid": "9581050eaba641ff256ec5d9f9bacc22912a1348188e75998f528a3430f69c13", + "sequence": 4294967285, + "n": 6, + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true, + "value": "6460" + }, + { + "txid": "650dbe3adc3ab3a73a5ce16db694dcd39d755fdd235cb486a7f4168bfaa56e8c", + "sequence": 4294967291, + "n": 7, + "addresses": [ + "bc1q0cgg82lx3dd0u99lrfruwqavdprfkv8kg2gadt" + ], + "isAddress": true, + "value": "7000" + }, + { + "txid": "88873dc6a720a5652290bf50e526ad8677668039b8912f0f215a1d020ca707a4", + "sequence": 4294967293, + "n": 8, + "addresses": [ + "bc1q2xx9q6rvjfak33rqxe6xefgdeslzdtmgqd3xg5" + ], + "isAddress": true, + "value": "7032" + }, + { + "txid": "6cb59213f5465c2f8f25fad9c4196291135576c3431dbf1bafffd2d8ae11150b", + "sequence": 4294967287, + "n": 9, + "addresses": [ + "bc1qvcmvtu590a0tchdczqvdswcc6phz2r900u6wa9" + ], + "isAddress": true, + "value": "7769" + } + ], + "vout": [ + { + "value": "24214", + "n": 0, + "spent": true, + "hex": "00149fae2063427349e00e0dc0e7e0f31f783ba4aedb", + "addresses": [ + "bc1qn7hzqc6zwdy7qrsdcrn7pucl0qa6ftkmezxxvx" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000000a1c05a115781b118c7f0e004b5ea369546bed01b977f8", + "blockHeight": 594666, + "confirmations": 35555, + "blockTime": 1568371428, + "value": "24214", + "valueIn": "53170", + "fees": "28956", + "hex": "0100000000010ab25e40dad039ad87b370007e3f75715e222bb8ead16b97d8f1f72d15783c6acc0100000000f9ffffffe14d6d279f01555e531e325667bcfbd4a51f5369aa300345d3e9c6a1d6a4a3f80000000000feffffff0b1511aed8d2ffaf1bbf1d43c3765513916219c4d9fa258f2f5c46f51392b56c0100000000f6fffffff8ae0d9757cba4e790483659fc55a2d7d943b57980bb84aa996d80cc90640a270000000000faffffff7a145d0f10bdc540773434442353e1b61f87fc58acec044914ea6f082125535c0000000000fcffffff2a495a252f2a067ca36618da86350289c027aa454fa61969e65e1cd80a7656a40000000000f8ffffff139cf630348a528f99758e1848132a9122ccbaf9d9c56e25ff41a6ab0e0581950000000000f5ffffff8c6ea5fa8b16f4a786b45c23dd5f759dd3dc94b66de15c3aa7b33adc3abe0d650000000000fbffffffa407a70c021d5a210f2f91b83980667786ad26e550bf902265a520a7c63d87880000000000fdffffff0b1511aed8d2ffaf1bbf1d43c3765513916219c4d9fa258f2f5c46f51392b56c0000000000f7ffffff01965e0000000000001600149fae2063427349e00e0dc0e7e0f31f783ba4aedb02473044022061d7db5dbbf9f1f754cd0d0e907b63f5304c400c5acf651fe027ddcbec75d2af022029062c9c03f8763ddda455182a72a5caf55b9bc9995b269681eb72f98f953ce5012103972e1fd42a252e79be06cf3b92f91cad5a95d13109f5f6dd424d76dd315aa59302483045022100dcf1041cbdc17cf50829d7c844f1ce75beb4afcf2c5c3811455ae236fb97ee3502201b172291110dc4eebe42f269f0c1d87653bfdae36f906e77578d923a31197bb7012102cac4dcf0eccebb3b8e5b10a0e10c5e2350a7e2b2c2591f05b0f85511dab482fc02483045022100ae38ed7d6562f76bbd3a235126b4c6d699f79ae1c58c2d8a74df274b30ea36c80220154234175104f61c4784492025a2039ac2425dbf057fa5a6bda35ef6a5c8c92f0121029261525063905ff3ae58f5497c9e4d90c6d54cf68d46e01877a8119691cc399402483045022100ecb8f58190b1b9e899a6bc93ea72e2567bc0068ed611ba52c99fdc6ed99845520220515dc894804fe1ec4f72b521b3574f9e6fc7033a276f4ebe97a7fec36edc042701210261cf39d7fb7f3ab145f553b654164b86917a64078e558d47c30a7a99f3b7212d0247304402203ced2182ffe96eb616722a74fcfd9d764a8be6dc0cac0d6c92a434b4b05efacc0220473c2d8f827c77f112ef1c54f71775a830a96eae2e3312951cb8c5a2eafb972a0121028f029b2c38409e68873ebf07431ffa9e71f9a21104c6cddd694dab3607bcfdd6024730440220439a7dc1dc8c8e1e4cbf5faa8cc3fbfee7dd1f0cb7fe5bd6b92affb5fc36c72602200683851cf073f99714cb261b4303a9b20d7f90ea34ecbbbca941a92e9bf0ad7a01210308c0793b4f8fa2c3c98047003d52b21dcce8be18bb99d0f5576cd60504ac544c024830450221009350786cccc44be8386de5f3742467577264cd0e64972be0932cdcdf9da95c3402206e6b594cea10c829ca84591a32844e8b20db273720f750ee7e0476f5d3ab507f012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf6250247304402205bd49cb94b76d43c77b8d3cd737b5cba931b6c1a788456a1e4c15d3506a5c666022011af4e58f9aba52856df9a6a3b6ee5e8b2e0471801da126d1c06a88fcef6eff2012102bc7a575c577e7a5d1abae2d2755b07e027008b8f15ebf2f43db23a4d49c49bf802473044022003f9353abc8190b0eeb5919e89fa24e365ef53c5f324a5d27a03d2e0f676737502206504198edc4ceeb4303b64d2eef7080c43a8fdad4d4e92382ad1f12930ad563f0121033910ba10b8cb78b3fce0ce1a3810869a25151bd162f1b0d20d54bca5c5e8ceb8024830450221008571e0c9314b2fd6689efc895b34f4c2d127e47c6d73fa9a0a1cebf29088030602205eac86149055d2ade3114cc360c784a9f8be273f04b23668481f31d9e0e2660b01210271b8cf7b1845bb4615c40d9049ecac0ef06e86e9806640743ee1a4dd31f96dd300000000" + }, + { + "txid": "9581050eaba641ff256ec5d9f9bacc22912a1348188e75998f528a3430f69c13", + "version": 1, + "vin": [ + { + "txid": "35834d8661b4843a2ba211b436fb7c4286f1128a17a15b09fbb8383b08c88fa3", + "vout": 1, + "sequence": 4294967284, + "n": 0, + "addresses": [ + "bc1q3gnextg4u9lm9rcctnx8jxdmpdz0wde6hlgtnf" + ], + "isAddress": true, + "value": "9194" + } + ], + "vout": [ + { + "value": "6460", + "n": 0, + "spent": true, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "2508", + "n": 1, + "spent": true, + "hex": "00141e20cc5c2865017212ce488e765a598d9362ec8c", + "addresses": [ + "bc1qrcsvchpgv5qhyykwfz88vkje3kfk9myv4tpxqz" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000000789219c989d256be1405088da839989d7ef9eb3b0bfa3", + "blockHeight": 594062, + "confirmations": 36159, + "blockTime": 1568068608, + "value": "8968", + "valueIn": "9194", + "fees": "226", + "hex": "01000000000101a38fc8083b38b8fb095ba1178a12f186427cfb36b411a22b3a84b461864d83350100000000f4ffffff023c190000000000001600141a475acd52ae04da60ab33bf373c9255cea3169acc090000000000001600141e20cc5c2865017212ce488e765a598d9362ec8c02483045022100ef9d266fa275b8bccd3aeb5613c853644c73862e4a58f956ccada4804e34f44c02203a4ccf9562b5dc0fb4f6519c4b54d3c2e0b8da6965ca9356bae06285441e34c701210221a110c08c9ba07f547bcad9b9860b804fe1115490a81478b2bd0fe52d90118d00000000" + }, + { + "txid": "a696d7eeffe8cb6469182ed02aa15cb2ca2720c870bd7074cb1fe688c2bda13a", + "version": 1, + "vin": [ + { + "txid": "e6e04f7537399ef74be5522168746ede370f6ffceb44a0fb490fa52462de5e64", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true, + "value": "10000" + }, + { + "txid": "2d0cbc42a2724f3b315e196e6b31ab2188d02e7aaa774e5bb77a1e7c9e70e9fb", + "sequence": 4294967295, + "n": 1, + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true, + "value": "30000" + }, + { + "txid": "274a5dafacd7290d5b17cafe6e5c4241eaba208f454649b183cf4161a141e56f", + "sequence": 4294967295, + "n": 2, + "addresses": [ + "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h" + ], + "isAddress": true, + "value": "47433" + } + ], + "vout": [ + { + "value": "78649", + "n": 0, + "spent": true, + "hex": "00147bef09cdf93be69ab9d6c32d37691972592dabdd", + "addresses": [ + "bc1q00hsnn0e80nf4wwkcvknw6gewfvjm27aadnngl" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000009636519364378c1db859d41f20f476bca69702360a1fe", + "blockHeight": 549442, + "confirmations": 80779, + "blockTime": 1541806207, + "value": "78649", + "valueIn": "87433", + "fees": "8784", + "hex": "01000000000103645ede6224a50f49fba044ebfc6f0f37de6e74682152e54bf79e3937754fe0e60000000000fffffffffbe9709e7c1e7ab75b4e77aa7a2ed08821ab316b6e195e313b4f72a242bc0c2d0000000000ffffffff6fe541a16141cf83b14946458f20baea41425c6efeca175b0d29d7acaf5d4a270000000000ffffffff0139330100000000001600147bef09cdf93be69ab9d6c32d37691972592dabdd02473044022043e5606e519fa1ce40b0681c16431221f50385577afb94c464b0e9d6c1d7396b0220584db57b6beb051f574e50ad1517a744aceccb987caec202a144d6a21158e4c9012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf625024830450221009ed7c4fa473f673daed2f593af66fcf00f5ccd5de65e5d9a099ed01dff9fa30b022021a6d12c8098e94284cb9c65ca773facc0d4847ae7dcbc33b4aecc9eb0248e5a012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf6250247304402205f5f0499cb74b68284276c78930856f50aef1abeb3d6bdc5ab7868cdc8bdc9b20220266b52935959c5d9d039f92d5cc6f1cbf88d5fa8c901bdbc33e8f73b9b1ef7be01210250cf3a4de6e4f2aae2c1aba4ea8e3ce32e3f6135e5809b8224fbd112fbe88a5b00000000" + }, + { + "txid": "2d0cbc42a2724f3b315e196e6b31ab2188d02e7aaa774e5bb77a1e7c9e70e9fb", + "version": 1, + "vin": [ + { + "txid": "40c5c15eb495b674fefa2f4be74e155ad0b39de4e4189ee10c1322e8013fdfd9", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "18kdgiYf3iMkB12hSp8Vz2u9RAv4342xFd" + ], + "isAddress": true, + "value": "50447", + "hex": "47304402201d17cd9abecee131ddbbdf6c7f7ef13709fdab9c3305a2a05121009821ca4cd10220366192ba41a808f76508abb923aa0914b59dc142ef7fb587e86efd4c13c6a710012103078ee784ae3d00d202ddfcf560137440071a258ee0d5cf5e4e54f91821eed447" + } + ], + "vout": [ + { + "value": "30000", + "n": 0, + "spent": true, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "19047", + "n": 1, + "spent": true, + "hex": "76a9140a8992dfaa275cbca952ec529427cfe90ccf52cb88ac", + "addresses": [ + "1xiZi5nSPtTfKczArfkqPQfhidt1CHqMu" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000001bd897b449e61933380ea70285a92027c8d9d801e0f3e0", + "blockHeight": 549191, + "confirmations": 81030, + "blockTime": 1541630955, + "value": "49047", + "valueIn": "50447", + "fees": "1400", + "hex": "0100000001d9df3f01e822130ce19e18e4e49db3d05a154ee74b2ffafe74b695b45ec1c540000000006a47304402201d17cd9abecee131ddbbdf6c7f7ef13709fdab9c3305a2a05121009821ca4cd10220366192ba41a808f76508abb923aa0914b59dc142ef7fb587e86efd4c13c6a710012103078ee784ae3d00d202ddfcf560137440071a258ee0d5cf5e4e54f91821eed447ffffffff0230750000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a674a0000000000001976a9140a8992dfaa275cbca952ec529427cfe90ccf52cb88ac00000000" + }, + { + "txid": "e6e04f7537399ef74be5522168746ede370f6ffceb44a0fb490fa52462de5e64", + "version": 1, + "vin": [ + { + "txid": "b9a34283e300080e7db25153c7fd22514eda0a0af70acde096a1da9ccc7d2d7c", + "vout": 1, + "sequence": 4294967295, + "n": 0, + "addresses": [ + "bc1quzz2sfdghyhu5g9plm2uz9damh6n5k2dr434q8" + ], + "isAddress": true, + "value": "50000" + } + ], + "vout": [ + { + "value": "10000", + "n": 0, + "spent": true, + "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", + "addresses": [ + "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" + ], + "isAddress": true + }, + { + "value": "36384", + "n": 1, + "spent": true, + "hex": "0014a059d7120d076e2ac132281c21b070b6ec7261a0", + "addresses": [ + "bc1q5pvawysdqahz4sfj9qwzrvrskmk8ycdqmu35w5" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000000f2f0f5e24ce5fda01fd2a5d7545a1cd909850951f96f", + "blockHeight": 549183, + "confirmations": 81038, + "blockTime": 1541624396, + "value": "46384", + "valueIn": "50000", + "fees": "3616", + "hex": "010000000001017c2d7dcc9cdaa196e0cd0af70a0ada4e5122fdc75351b27d0e0800e38342a3b90100000000ffffffff0210270000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a208e000000000000160014a059d7120d076e2ac132281c21b070b6ec7261a0024730440220743b4f5c217b3429101b6213d4aa92922e2960977b3d5e633bb016dada6273a302204e7d588d787845c51bf97cc0a52abaa663a5fb609c275bafbb2cfcd607b1829d01210203389a9e645d4e53a38e449b196b60dfe14ce6e57f814a150d60e912962653bf00000000" + } + ] +} diff --git a/mock/ext-api-data/bitcoin-api_v2_xpub_zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC__details_txs.json b/mock/ext-api-data/bitcoin-api_v2_xpub_zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC__details_txs.json new file mode 100644 index 000000000..bdbfb7803 --- /dev/null +++ b/mock/ext-api-data/bitcoin-api_v2_xpub_zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":10,"itemsOnPage":10,"address":"zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC","balance":"35963","totalReceived":"4222507","totalSent":"4186544","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":94,"transactions":[{"txid":"48554ab85af888894d3f247088fdb8b7fff412612b54f0069f89dda3bd80f0ce","version":1,"vin":[{"txid":"ffd5f12382137dfc62866694f77405ecb6d4cf2cc286ac66d192f7e842787c0f","sequence":4294967293,"n":0,"addresses":["bc1qhddmnwdqwuvt6zl7auu976scg7rmtpx6amumsd"],"isAddress":true,"value":"3220"}],"vout":[{"value":"1000","n":0,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true},{"value":"1994","n":1,"hex":"0014bb5bb9b9a07718bd0bfeef385f6a184787b584da","addresses":["bc1qhddmnwdqwuvt6zl7auu976scg7rmtpx6amumsd"],"isAddress":true}],"blockHash":"000000000000000000005e0a9278dcf1a18390c78c27d5f47dc0777772b1e54b","blockHeight":627865,"confirmations":3322,"blockTime":1587999059,"value":"2994","valueIn":"3220","fees":"226","hex":"010000000001010f7c7842e8f792d166ac86c22ccfd4b6ec0574f794668662fc7d138223f1d5ff0000000000fdffffff02e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169aca07000000000000160014bb5bb9b9a07718bd0bfeef385f6a184787b584da0247304402203285e50928e3d4f67093bb457fe51b60a9e1981868666d8f79bf272868484f1d02200e7093af7d2d7cb68bc0801587b619c2022f02084fac3902fe93e47977aed6c30121034df96f5dacf5e22fb8611e6863e48f6777c7e96064c81196e23dcefd35017d0e00000000"},{"txid":"36b1e721a25ea3ac2fcc09a92d4ff1e2ae4ed70d593e276806d9a9fd2a901132","version":1,"vin":[{"txid":"c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be","vout":1,"n":0,"addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true,"value":"4829"}],"vout":[{"value":"1000","n":0,"spent":true,"hex":"a9141ba5187259ae22520f99ec3522d320279066aafd87","addresses":["34DBwkzPz6yeqU1LoZLVzdCm91oeyxq37T"],"isAddress":true},{"value":"2699","n":1,"hex":"00148f347b3ea1ce113b09e096125a3ad3310dd0a947","addresses":["bc1q3u68k04pecgnkz0qjcf95wknxyxap2287gyzrg"],"isAddress":true}],"blockHash":"0000000000000000000fccc2c78e235d6ea3da4013ea98c8376c7c41f7f71938","blockHeight":624894,"confirmations":6293,"blockTime":1586299624,"value":"3699","valueIn":"4829","fees":"1130","hex":"01000000000101be328cc2ca0135e640bc1e795f20d3189939ab3712d8e79627347a5c2dc8a4c601000000000000000002e80300000000000017a9141ba5187259ae22520f99ec3522d320279066aafd878b0a0000000000001600148f347b3ea1ce113b09e096125a3ad3310dd0a94702483045022100c251d7e2497b42d57ff00c92eeb8a6faa86a3d5d77a9d257b7e464400306fa5502204f532ab553ba711779cf1f93cab47c4f5e0f11dbc6017781c79b76caa6ea322b012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000"},{"txid":"c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be","version":1,"vin":[{"txid":"d39d78838d5a3c870aa5acdc9e518945bd6ad86af093b38f85c714f790f28c76","vout":1,"n":0,"addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true,"value":"6055"}],"vout":[{"value":"1000","n":0,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true},{"value":"4829","n":1,"spent":true,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true}],"blockHash":"00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e","blockHeight":622017,"confirmations":9170,"blockTime":1584485709,"value":"5829","valueIn":"6055","fees":"226","hex":"01000000000101768cf290f714c7858fb393f06ad86abd4589519edcaca50a873c5a8d83789dd301000000000000000002e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169add120000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a02483045022100cb25ac0d9e69ddaaedd49e3a3f9efb218b38bf49c2abf44ff2266bfb941bd3b202206b32cc1337f9a6a176fabadd6aefdf5a95d479e5db856d4e3e8eee7fefc26773012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000"},{"txid":"8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4","version":1,"vin":[{"txid":"270a6490cc806d99aa84bb8079b543d9d7a255fc59364890e7a4cb57970daef8","vout":1,"sequence":4294967294,"n":0,"addresses":["bc1q3230a7cqt2drewuza8qff4c4gpt4muy9qyqknw"],"isAddress":true,"value":"1699"}],"vout":[{"value":"375","n":0,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true},{"value":"1098","n":1,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true}],"blockHash":"00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e","blockHeight":622017,"confirmations":9170,"blockTime":1584485709,"value":"1473","valueIn":"1699","fees":"226","hex":"01000000000101f8ae0d9757cba4e790483659fc55a2d7d943b57980bb84aa996d80cc90640a270100000000feffffff0277010000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a4a040000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220683d9c2b40958fd706623783017300ebbc9b73ce1db571963d9bb40679c3079c02207ee68976e225e1e98d20e66d4d8a498cddf3268d0d7b66827a2ed3ac4330f137012102b7f0cb54c2a6a4da3372fe17d7a07475f575777364633e89dacb39eb1fd5a09c00000000"},{"txid":"d39d78838d5a3c870aa5acdc9e518945bd6ad86af093b38f85c714f790f28c76","version":1,"vin":[{"txid":"c215e9c6f9533d584effc4d31d08736a0ef4f717b7d42563ebba053f5f3bc1d5","vout":1,"sequence":4294967287,"n":0,"addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true,"value":"8185"}],"vout":[{"value":"1000","n":0,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true},{"value":"6055","n":1,"spent":true,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true}],"blockHash":"0000000000000000000ab8b2230f5b63d4d4be1a0aa6b9296cfc09e48c8e42e0","blockHeight":619385,"confirmations":11802,"blockTime":1582902175,"value":"7055","valueIn":"8185","fees":"1130","hex":"01000000000101d5c13b5f3f05baeb6325d4b717f7f40e6a73081dd3c4ff4e583d53f9c6e915c20100000000f7ffffff02e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169aa7170000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220158b0d8c5fb6cb9f60d0af05ce8b63abe934dca8eca380013bc7e8463420810f02207d7e6594586ec8196546e2520b6775c2e8659c8f266acb3b861e99f13cf1b380012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000"},{"txid":"c215e9c6f9533d584effc4d31d08736a0ef4f717b7d42563ebba053f5f3bc1d5","version":1,"vin":[{"txid":"1fb8f63b044160a7f918b5db85fa7bed3415848bd733f5827d7ae10cf738b387","sequence":4294967287,"n":0,"addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true,"value":"10315"}],"vout":[{"value":"1000","n":0,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true},{"value":"8185","n":1,"spent":true,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true}],"blockHash":"0000000000000000000fc5707f9351bdefada8c42267c9d63baf404268d65ca0","blockHeight":619383,"confirmations":11804,"blockTime":1582901173,"value":"9185","valueIn":"10315","fees":"1130","hex":"0100000000010187b338f70ce17a7d82f533d78b841534ed7bfa85dbb518f9a76041043bf6b81f0000000000f7ffffff02e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169af91f0000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024830450221008e721f8e1ec8c22e2cec8fb2744d451cb11decabd0ed6b8080b5949f8c34ad3c022070815d97c02a3befae53dfceae504bd4495f034afba9e8e1e84595d07d933a60012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000"},{"txid":"1fb8f63b044160a7f918b5db85fa7bed3415848bd733f5827d7ae10cf738b387","version":1,"vin":[{"txid":"3eb38e946261c8c7312f02cf72a72ac8d93ede94aa21520fbf06dd9b1f3f4392","vout":1,"n":0,"addresses":["bc1qjar8852c43h73ud79xjluy2e7qce58peymsts8"],"isAddress":true,"value":"194390"}],"vout":[{"value":"10315","n":0,"spent":true,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true},{"value":"179781","n":1,"spent":true,"hex":"0014974673d158ac6fe8f1be29a5fe1159f0319a1c39","addresses":["bc1qjar8852c43h73ud79xjluy2e7qce58peymsts8"],"isAddress":true}],"blockHash":"000000000000000000099b3509cf7d55c3c1894f814ab45bdccb32aa2b5e3e46","blockHeight":616239,"confirmations":14948,"blockTime":1580992887,"value":"190096","valueIn":"194390","fees":"4294","hex":"0100000000010192433f1f9bdd06bf0f5221aa94de3ed9c82aa772cf022f31c7c86162948eb33e010000000000000000024b280000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a45be020000000000160014974673d158ac6fe8f1be29a5fe1159f0319a1c3902483045022100a2cb51287dd8fd1e7eb9c48be73cba46ddf75287617c38f68618062c945ecbc802206f357933216b63a4530687223e60900c29d1d0869461d6707d7fa202a3c09d9301210289f9d29f5e11c87d2cdbc213d05b7f2aef0291b89b87e7a6f747461d2f75fd9a00000000"},{"txid":"35caac179d1a85f7c495d9a716d85bb02ed925170fc4716e8b04791acd487419","version":1,"vin":[{"txid":"45cd3053d5393b2959646d023e1f2fa272d950903ed8b44502db88c9a04325fe","vout":1,"n":0,"addresses":["bc1qs6q3tdsa09dtrwn0ml7d6ser4zdagja23rks6a"],"isAddress":true,"value":"2470973"}],"vout":[{"value":"10772","n":0,"hex":"00141a475acd52ae04da60ab33bf373c9255cea3169a","addresses":["bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj"],"isAddress":true},{"value":"2455681","n":1,"spent":true,"hex":"0014974673d158ac6fe8f1be29a5fe1159f0319a1c39","addresses":["bc1qjar8852c43h73ud79xjluy2e7qce58peymsts8"],"isAddress":true}],"blockHash":"0000000000000000000fcc2170ca9e17fd26747dd40bbf0388324cb872cd7a72","blockHeight":615391,"confirmations":15796,"blockTime":1580495311,"value":"2466453","valueIn":"2470973","fees":"4520","hex":"01000000000101fe2543a0c988db0245b4d83e9050d972a22f1f3e026d6459293b39d55330cd4501000000000000000002142a0000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a8178250000000000160014974673d158ac6fe8f1be29a5fe1159f0319a1c390247304402207fd1c5f4e69845d67696f6dd3f9160fba8e66edb959742b3836f9d6b51b7ef3e022066940b74c238971d0f826648a2bc4806b88be512b6c2bbb08f95e32bbd1ad52f0121020201a3d7f2d6e0e63a7f73e6dfad80d47acaba509585fb40c3c0f54ed9e2478700000000"},{"txid":"7e9a4659d3ad09889595c36f3a533f7dcd2e8c7cd429a8da8129544e961f5540","version":2,"vin":[{"txid":"56246da72d3f56d151adeb34c76c58d229ea0ddcfdc40f17d9b31033fc8789ad","sequence":4294967295,"n":0,"addresses":["33nzF46dHjjuxX61JCnFqirQoxs6VgHRmC"],"isAddress":true,"value":"13482","hex":"160014f9dc6ee2a72c21e6f2a9638dd28a7ea89c79ac62"}],"vout":[{"value":"12257","n":0,"hex":"0014494d0f8f18046f3774ed234a89cb1c37c82ad194","addresses":["bc1qf9xslrccq3hnwa8dyd9gnjcuxlyz45v5dku5t9"],"isAddress":true}],"blockHash":"000000000000000000112771bad60c0245409ff41f8f853f2688bde7194abceb","blockHeight":613673,"confirmations":17514,"blockTime":1579512534,"value":"12257","valueIn":"13482","fees":"1225","hex":"02000000000101ad8987fc3310b3d9170fc4fddc0dea29d2586cc734ebad51d1563f2da76d24560000000017160014f9dc6ee2a72c21e6f2a9638dd28a7ea89c79ac62ffffffff01e12f000000000000160014494d0f8f18046f3774ed234a89cb1c37c82ad194024730440220346da175f0e165a994897ad2eeb117609e2c36f5f1d0d8c40237ef172c88cc00022071fcdc6adebd73a6627e3ce011dff47634796c3b7371e751f5b6258e308674f6012102b708bb3855591cc04d74a65c67be028fd48ae0911e4a82aed92c1c479eb4cce500000000"},{"txid":"56246da72d3f56d151adeb34c76c58d229ea0ddcfdc40f17d9b31033fc8789ad","version":1,"vin":[{"txid":"2054069427b587c84ec43902eb8a400c932567104cd666eb8db514a60170dc15","vout":1,"n":0,"addresses":["bc1qtrk05l53jdflggp0c9hy32ejq4gs6zrf2jjplj"],"isAddress":true,"value":"6530"},{"txid":"45cd3053d5393b2959646d023e1f2fa272d950903ed8b44502db88c9a04325fe","n":1,"addresses":["bc1qlrfxv4v2fkljgylytypxdnr6cdw3jhlcz3xmrs"],"isAddress":true,"value":"11032"}],"vout":[{"value":"13482","n":0,"spent":true,"hex":"a9141711581f950d42881c52adf5c92f64aed4b27a5187","addresses":["33nzF46dHjjuxX61JCnFqirQoxs6VgHRmC"],"isAddress":true}],"blockHash":"00000000000000000002d1d74426c36e5f97541ab039fcfe617425db12bbcfa3","blockHeight":613671,"confirmations":17516,"blockTime":1579512101,"value":"13482","valueIn":"17562","fees":"4080","hex":"0100000000010215dc7001a614b58deb66d64c106725930c408aeb0239c44ec887b52794065420010000000000000000fe2543a0c988db0245b4d83e9050d972a22f1f3e026d6459293b39d55330cd4500000000000000000001aa3400000000000017a9141711581f950d42881c52adf5c92f64aed4b27a518702483045022100cda0a6afa6263f966095400decdf6c73ee4c0889c8eed5bcf5c4bfc85627978b02203beba56e1ee50371a8ffe1ee27be2f2259ad48881808f5d0e63818ccd367a4100121032c5789121a12483272dbd6e42abf59171896aae32c3354ce4ff0ed34635e6b1802483045022100b724e2ecbd7d76b78930cc11af73ad4981ea0d78e90fc5d0860975e7cc3e1c170220695f053d4f4c059954959822bfb80f9d7d7651176ca99522e6ff5b19d4bae11d0121036c203dd0b21843fc2a1f84aca1ca39d45034dd55ef4030adbc663510df4e454b00000000"}],"usedTokens":100,"tokens":[{"type":"XPUBAddress","name":"bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj","path":"m/84'/0'/0'/0/0","transfers":13,"decimals":8,"balance":"16245","totalReceived":"92089","totalSent":"75844"},{"type":"XPUBAddress","name":"bc1qh24nwfr75yt5xuh0ejt6jwme6lg6rgy3nkxscp","path":"m/84'/0'/0'/0/40","transfers":1,"decimals":8,"balance":"643","totalReceived":"643","totalSent":"0"},{"type":"XPUBAddress","name":"bc1q7hhmfl8qlpmcjuq6crm4cu70kzqfm2pj8gp6y0","path":"m/84'/0'/0'/0/42","transfers":1,"decimals":8,"balance":"1000","totalReceived":"1000","totalSent":"0"},{"type":"XPUBAddress","name":"bc1qf9xslrccq3hnwa8dyd9gnjcuxlyz45v5dku5t9","path":"m/84'/0'/0'/0/44","transfers":1,"decimals":8,"balance":"12257","totalReceived":"12257","totalSent":"0"},{"type":"XPUBAddress","name":"bc1q2h0cce60v3cf48lq4ucnk4l998z3c0n7ccd27f","path":"m/84'/0'/0'/0/130","transfers":1,"decimals":8,"balance":"1000","totalReceived":"1000","totalSent":"0"},{"type":"XPUBAddress","name":"bc1qqs8mr36kttyuh3wjzk34dpha9d0gjt7q7vdvhy","path":"m/84'/0'/0'/1/36","transfers":1,"decimals":8,"balance":"1063","totalReceived":"1063","totalSent":"0"},{"type":"XPUBAddress","name":"bc1q8y3g8d0ltmwatqzuh5vq7aqymvq36s6ncn5jv5","path":"m/84'/0'/0'/1/38","transfers":1,"decimals":8,"balance":"1056","totalReceived":"1056","totalSent":"0"},{"type":"XPUBAddress","name":"bc1q3u68k04pecgnkz0qjcf95wknxyxap2287gyzrg","path":"m/84'/0'/0'/1/40","transfers":1,"decimals":8,"balance":"2699","totalReceived":"2699","totalSent":"0"}]} diff --git a/mock/ext-api-data/bitcoincash-api_v2_address_bitcoincash_qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme__details_txs.json b/mock/ext-api-data/bitcoincash-api_v2_address_bitcoincash_qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme__details_txs.json new file mode 100644 index 000000000..2ed2ac728 --- /dev/null +++ b/mock/ext-api-data/bitcoincash-api_v2_address_bitcoincash_qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":2014,"itemsOnPage":5,"address":"bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme","balance":"0","totalReceived":"12502830507987","totalSent":"12502830507987","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":10067,"transactions":[{"txid":"0284cb9b8deb0534efa8fc8911db1e8f9b106d00608c712d31c3680f303fbf36","version":2,"lockTime":611622,"vin":[{"txid":"2f150ee63214982edbaf23c85629e920e16093d0506ed284ec3018ebe8746b12","sequence":4294967294,"n":0,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250119473","hex":"47304402206f992d73dfa7e518b00190f220ad5dc7b7947b1d75a2fcd8251b59f3d29d89af022036c6c44f52f9aeed406dec72a9aab1f82c3b997c36742f4a3504e4f93e6f8557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"550ba873216e6690c8ca34992da41ecaa29e74a557943af604537de13fb84838","sequence":4294967294,"n":1,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250052374","hex":"483045022100db30ebe47536e42115a507f88bb8d5c97b81ad05ce334872235811134c5948bb0220418d77aed78cc4a332b1858c1d2e9ab169828b9c12e8c0d0f8d155964e5d0b8e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"ed8d8d9810ca30cd0512a0e0ca87649713a550a015bb0022c16686c2ccb22143","sequence":4294967294,"n":2,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250058021","hex":"483045022100d30c9fd598613586d8d0460fb6c9ffc1d0c6dff6f647535d2a9f69cf373193d102207fff687aa035910db124adad8b59607a72b3d24aca9096217ec6b90fa132a2ae412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"a2d79bacd53918c9ad6b27055eff555130f1af8522f77a09c4d74321dad8a032","sequence":4294967294,"n":3,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250022804","hex":"47304402207b30e99cb1f6754d227a4511c5b7791f3b896724b170716d6ed238017f191bb102202c1fadc4c572c86288b002a0d6b6d2460a14a6d3c8b49efc17a03e59d2db18e3412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"9a0679dc735b7774ab3aa55a01188ce4d70613927b1b0ca9f96784b09479f762","vout":1,"sequence":4294967294,"n":4,"addresses":["bitcoincash:qzqn6xdqhaqa8yykvq4e94td4yg0k9ll9vyjf47x0f"],"isAddress":true,"value":"1620505","hex":"48304502210092b7f176f182936323df8e4359b2a329b0c1e4b48a529d6e32867038a2a453cc02203c24a8bb46b7fea4ef5c78ff116a51fd0a04dee25bfcdffe856fb8988a7a97f64121035b4e75dda9fb0d55d856f54f24fc65da6657939b9559ab2c623c8ef325f14d8d"},{"txid":"5d557c0c3331dc1dc4db34776603c01ce24ac8b0adf1f6fc2cc07a88baf5bf5c","sequence":4294967294,"n":5,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250096547","hex":"47304402202a2bcfdaf12c398ed5372e6b168a786edb8972df1146b705d3cccf2d9601517d022020b90ac89d9141d68817850d1cdffaf6c51f45249a44fd6861b361a6025d8ac4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"61dbe706b513c1ee5aa577a07782471cf5c0c13fd7ce31b29cdd1c2362ea0bca","sequence":4294967294,"n":6,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250179897","hex":"48304502210087ef2709b9fe8e7f136219254229edd45e94c3f6ebd2bb149aadd9b1d44d89e202206ffde3c9491c012832967e4d34e02ece2c08bc4c07967b3b466d4800f9ca0746412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"54b28d128142bb03aa60e9cf535fe30d5916089f1e70ac94444572008e9b3b84","sequence":4294967294,"n":7,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250044246","hex":"483045022100c7dbd1117c57eedc8fc006e818371bfe6399c4d25e8b40482c1f0858a3d98a4b0220426d1196513a87fc7afb5b107b770a90af789536799a11686eab96b04afa6326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"750c2e638eb26bd271586fe201f48e21ef7fcef1154a6b6335d2bd4381450123","sequence":4294967294,"n":8,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1252404910","hex":"47304402203604fbb20824443899030d2c1f5cd0dc2b88174929861a708bdca878868e910c02200a607b1da53483bc95d3a5c54e5ad66e459827d4ecf8b4ef9909e9d58b2d329b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"9b6dc387b59e4af25bfa14067e24c399fae3fbb744e97edb670087265ebcecf9","sequence":4294967294,"n":9,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1256320052","hex":"4730440220399c36174173cca01f6d6a234a935d6f776b549e1ea2fc2635193924c4ac2eb002205aea7741fafd95f862588c480aaa282d7a344d32d6318aec1a908cbb939e5d0e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"8f27da29f81ae3ac3ab90f29cd4988d718cd351f965892b073a80b9a9492f49e","vout":1,"sequence":4294967294,"n":10,"addresses":["bitcoincash:qz8mkaldpk8zk2ge27wpn8ue0uwu28xq5552u5c5my"],"isAddress":true,"value":"1687043","hex":"483045022100da9075310e7af59456423be99362f2cc686d50571e0f0b016bcfae1f0bc4692802203379b648d47704dba48542b8b6d5e515bf3c4fd7ff8a7be82cd0c8c0c7be56f7412103a344a84dc1a919a64874605fae200861b7af3ecd02dc5d52dd00eb6f8845525a"},{"txid":"109bf48f720a9d05fd7a74b632164ed96db721b00458420595d799b437305f5c","sequence":4294967294,"n":11,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1251895732","hex":"47304402206cbf93634d6a477a571fa2884c19918b19ddfb008ff9fe405954720047efdb88022003e755313436d406dddfe3cfb68719e8f39e43de7c586489cc543dac0347da9f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"d3e570366f647db1f73079b743ec994169875c7af42ff2e9f3cf290fcb3f180b","sequence":4294967294,"n":12,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250081823","hex":"483045022100f23d4cf11fd0a5ab83dc053ca64066cbdd2fb4107e0977a3a880c68a67636f7d0220220a47c66d3944cfc309c059fe8013c4de742e4d8590003fd56c5e0b3c7da557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"6f05f99a402127463db6dc2f8f6b1064109fbfb93bacb258babd2aa861055480","sequence":4294967294,"n":13,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250020672","hex":"4830450221009f522beef55cbf8c7f10e88739846f78ef1c9d9cbc6959dba6f687a08fec0ef502203a160231733b87c6cfd8afd148994c9b6c5d5db9bb9847aa9e60938a6e79d5b1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"3d93b717b0676245a3dc3fb86625d9abffac4f66e2889a81a07733a14e1e4a4a","sequence":4294967294,"n":14,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250118486","hex":"47304402201f5d29be80192a752fe28ff141ed702640df88083faf3f9573e52405cb4bd79a02202d751649aa600c4fdb8b1d1b21f0d134c2f4e5af9ecbe7d87180d667140f0a11412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"c77ac92e646677bf9e59873c5f5036831d5d5597cda469b7e6b30a9563a3419b","sequence":4294967294,"n":15,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250097156","hex":"47304402203f4bea3816d252cb19d4247f587a146901c74d04e783efddfd5089942f2abcdb022069012613c4ee4b3b0212ae71dbd2071e01665148697011eb03eba25431e679cf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"90cba3db7e020c7b8943293ecca7f6a2150082a372972c0ed65646337b0b05ab","sequence":4294967294,"n":16,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250175150","hex":"4730440220782ba77287116d5d735f67a3738fbecc1a802d2141a1fa544f61a5e8ba682a4402205473d68019cc8895ecb1d87bfced62ddb6dc48b81152f2684ae8530122d5b41f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"e25ec382049a4d8edd530469e5e41d9e056a2081b661f505414b1348e482dd26","vout":1,"sequence":4294967294,"n":17,"addresses":["bitcoincash:qqnfldeu0yd4wd89c44sujdz2w7hwvvd3y8g9tuech"],"isAddress":true,"value":"1884419","hex":"473044022044ed9bfa8674d7e83112fa22280797169d45bd971b185da2413e36252637529d0220531eefc480e0911d6ccda42002942883149bc1cdd1f3bbde313751d80bcf98b641210328ac4ed2b30ddc04c778a78b24e7256b08c55758c1465defd997ff4bcefacf10"},{"txid":"13a148dff09d7786a7e0d0929e7ece3c9fb8de532597cbb0d045f5ec531b2e9e","sequence":4294967294,"n":18,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250028570","hex":"4830450221008cfdfd352e268dba2022e7fbfc37a90401c40fdf6f1d8ba9dcb97d67743eddc302202c0a1b604d34aa174fddef63c9115c95465548855c5f783bb206eb4ff8fda235412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"700dfcfa0847678c56a084b5a75fb8aef1b1a1126512b026ebdb8c45d55efdf9","sequence":4294967294,"n":19,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250039508","hex":"473044022001b33b610b8d742df2ad98679f1e41f0c647faf272e15e7ea93171ba29c33bcd022061646fbcb81ba30d6e8b030ee12101d1f1bef38ba44a6d5daf40c4ff6d644e6e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"6810932357166daa33c2125cf38be6076f7b6f718f199348905459f22ba7f2a6","sequence":4294967294,"n":20,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250136993","hex":"483045022100ec9b6bbaba90d8902ec8a1ca0e90ea594264bc1add204b756cc89def4d7e9a2a022066b2bc84f94e1a99effe0e929be8de8669631143ca20c73e700d182ad4884e71412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"42a98564873f7c888a6a569cb97066b4bc43c5fa41d732573774f996b91980b3","sequence":4294967294,"n":21,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250053520","hex":"473044022057117591cc465c48da58ebcb8f57fcd56359757d41e1397e45b5e33e034ea5d8022001de1d78ce9e8e73370a0778b4a8595045c6faeb2497ab4296d0cff735711276412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"f7b56e95b5a48a66649fd3e9e9bc94a7a01bd1c4822c4dcc2c40243c8da60bbd","sequence":4294967294,"n":22,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250111141","hex":"483045022100dace56650d1d9edaef30e8c9ecb4b78499a573984c8a451253295a90c84a3ed702201f4587d4a760cd77a2e21d5f6f2b7aacf668220c8c7c62fc1ae4779f7c0141cd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"d58b912c125283ee0249b670a7901bd5a1061d92f7c06627b5e963fb0b2c3d14","sequence":4294967294,"n":23,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250143132","hex":"47304402200db6b461a0082807f59053bea210d38f5f82f02dd63a57f6e3987339cac23870022064ba927fc11b36318785d4e861a7f94cb3909ef8fe882360e2041f7b4a444692412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"530326ce09e8f933a604488e5e2f06845c3e805761c02eced5cc02856be1b7b0","sequence":4294967294,"n":24,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250022822","hex":"483045022100a3e75a6c7918db32a27be348493b831631856ec8f546ca43d143cdc3c1cd03c802201e6ae036423bfce45c500b0c049f68396deae5cb999038de61e972ccd4cba5e7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"ca51412ad37c5e5a49b11dc7858b4013ff68288c56e6026b11a4266e184b286d","sequence":4294967294,"n":25,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250033136","hex":"483045022100caf952ca1760052cfefe8df283fdd0eccb9e1238eea88eef287df9404c622e8b022072027363fa1070548576fbf9bcbddf2e435fd020662b2d8f0582b52bfa487b31412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"c03e268bbb105f171305f7fd994c0e15fbff5ae3d08f3c332c48cacca66bbb38","sequence":4294967294,"n":26,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250037356","hex":"47304402201a4b4efff2b70a4039b4dc120141da04ae84f63906df10c3cad08838c01b6b8702205a065d025c338547ea07b2095ad31252658e57f1a7a04c7f4eacc0248e611fa2412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"46c8b9fca6423412b3d40cf7606b79678807d75b2be1e848765c40f367b326a3","sequence":4294967294,"n":27,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250061192","hex":"47304402206b0a876d78793710acaa8bbeb58a2d908bd4936f2a88825f944b190041b5e0be0220279560be5009e4a3fab44d08f4748e2dead710a8ccc77e06a03ba8112d728856412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"fadc6b6f3225ea8686c7a03cd8362765f91e604c260beaf965c4e7093fb16b74","sequence":4294967294,"n":28,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250118669","hex":"4730440220799bdb7ac60cdf3314cc1f157299858d353e22c00354707337ab5b497619d626022000e41053afe44fa65227b7dd8498300a2dc89367d9daf0586caba5bffdfde567412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"adb5163c2bd4b1c35c1eac2671e6124e6c6b9b6c3e2abdc8372601528600a98d","sequence":4294967294,"n":29,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250075561","hex":"483045022100a1af33a83edb7fdc289a48a4f77cf286a88b38c21ddf27dd4ec3df007ce11046022074dd56730730f958039efd70edfe7e181060fec306c6df4cf75209600ebebed7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"db1a00011dcc02708d6757b7435a3163d4dc384d8490208656229b0780b4a184","sequence":4294967294,"n":30,"addresses":["bitcoincash:qzduecze3gvxk6y7rcjmvnau8c3ncddvvvs05z5gz6"],"isAddress":true,"value":"1400587","hex":"483045022100eff445419ec63d1e9f51a5324c3be0315911b39f30657639e84ea7d2f739e0510220218e73140a39542ec8055b6645cbb7989f96b9d9a93c67549c059509de06f0ba412103dd71b53aaa823b09a68aba30c7603c6a397e7c183f708c9dfb0d9d0a9cd1c722"},{"txid":"df69893e75d4acee084666c023822f07196dcae429a07b136fe92a87262f87f8","sequence":4294967294,"n":31,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250118543","hex":"473044022050b7ed06a6832b8831c08ba86049b3793b5a71fd6d5177c9f268b79c3074bca7022047447c23429de30c361875642d9058bf1b5e0e6c5516d6e71b70b7cfb29827aa412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"8432efebc29ead31beb783d5d27cc379fa31cee352cc19a75746768b2fbfbe7e","sequence":4294967294,"n":32,"addresses":["bitcoincash:qqfs2vp95prfunn2r9wh5lf2g6k7k6jjr5qld8a37e"],"isAddress":true,"value":"1772743","hex":"483045022100fb072bfd399dc11191ac449a9d60119bd191ce6b19a5d92412a805ddc8d4b46f022021e463686560b15ddf272b9943d8e41425ed500f77698aba518ccf546a97aeb4412103e35c58a738805f53af73472ffb671a9bd3556ddef47c62f18ced868bb5033d0d"},{"txid":"29ff4caeaa127c04ecc8141f49462390a13febd47877abda62a7ebb66658f0ba","sequence":4294967294,"n":33,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250075582","hex":"483045022100b25e7d4ebaa0e7d8e24498b039e756d568b67316aa14d05abafaec59e216a73d0220010d0b6548a74435907eb0d548dfe8e52a949bbb785eb2be3bce14053953784f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"3b46f445ddc1b8acd4fa933fb8d7dba9bd95ce53a579339b32a1e97352323013","sequence":4294967294,"n":34,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250043307","hex":"473044022007d2baa9a766c120e111a727bfa8e8bc2e01cc285d4d4f67d2323b213525a10c022020f32be2d9935b6d9b5091db27ebf00aaeb54adc7032badc7ad63f20741ff28a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"1bd4b1e18be85528e214e16c69f459272ec126ff0dfd1948de6838b5b50e5344","sequence":4294967294,"n":35,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1251821842","hex":"483045022100f98ee28ffb66acd04474a120904ec1be2327d727d8ed8fe99d8b95c174b8f46a022041d21406dd8df10cecc1d6435de68fef3f9db71838c1ca2910895bb184b4a6e4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"067492a2b7fe0787a44ceba7d6ee64da25aa8be08357576e4cef97ef76babf2f","sequence":4294967294,"n":36,"addresses":["bitcoincash:qr99zjexsl5dtdu38wu8w7jdmsmcxtcr9qw64zjhdk"],"isAddress":true,"value":"1843864","hex":"483045022100ee3f7961f0f23137d753affe85b777e94c1db3f656cf41b8f59fcf82d9226eb7022025009482a6c0002e409590075caf7a78023ebc1457f100c8b922a4974ebf86ba412103f1d1dd7685d3781f58f9aa399a16f6bb9ccc7d008cdb7c63a7945cfcaa6ba0e2"},{"txid":"bcc168ae5cc9dd70fabab262712036bacea7250db404c0d5af438b0b085c52bf","sequence":4294967294,"n":37,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250034365","hex":"47304402201fed9da4c0526ac5ce257fce2b7fc995646b5f0d2961396327f93e2dfda3e4a0022035b217adc5a9be2ca34f4361ceafd9f2d09a6fa47d4a767f7001ade40c08fe26412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"025d365f0471a48171c3f50ba4e9ee04ee74f72c2e8d0cddca600f3a900b7b32","sequence":4294967294,"n":38,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250085848","hex":"483045022100fa8ee82d42f524290319fb3ee47a1afa70cb952f8a37325680d6fd651ac3699f02205ac0cd86fece03ca204bd881d67ccce0cccbbc98704d9e955e2f92b5b77121dd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"c61c8a5fd411f160bac0e4b4e703e1caf7d3f8218b0ca5f2aa7b762bb9d3ad5f","sequence":4294967294,"n":39,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250086233","hex":"483045022100f3cb343c4704bebbc78c6492dd72ca19c388b285f44f574dcff25f993add6d5f02200e050dacd78de955cf552f9158beaac5fa64995f5bf7c8a919a231a39425730c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"207dd74726483c593b21c180a9467166af7f5b02450fd3613268cea239aed047","sequence":4294967294,"n":40,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250080933","hex":"47304402203f05a035f5d42fbfe97172b431a613110ad733e356ebfd08886fa11bedaf1faf022061c4a3bc3417390910612bae46f5acf8b6e8a5b008d273a52e483a315bfb950b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"facaafec82e7853c85dca5fcecad9c62d830a2421c98e8c5896b793966face46","sequence":4294967294,"n":41,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250075132","hex":"483045022100bf60fbd4716339bbb42ce150966ad6caf90b14e57f45eb6804756cf8ff36b23a02202f16aaecdb9994f3b683cc7fab45bd0a3f54795c336b5fc224fc51270a7f3f4f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"26703badea466dcf8446e1ee49868ed4259ff22e0f13460db9d79819115b5c4e","sequence":4294967294,"n":42,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250118800","hex":"483045022100bcdcae99c9289b5fc89d3227daaea8df7d0a0f3a8971d841ebe1ab7a1ecf72e202202ca21447a6b3e96540e32529697d523b7b08c65845d6a13f6b1475de94919bb6412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"c94103172a643e1ae22c3955749bf7af337a914a48d124fb5cbaae1ab5fa9e48","vout":1,"sequence":4294967294,"n":43,"addresses":["bitcoincash:qzfvx98n9r4yzlvk2h736rn3qftpl2uttuu76kvt5x"],"isAddress":true,"value":"1631430","hex":"4830450221009535c27b5bbca0db2bcf1a0d0b3b283a2171df53f0d68f1a138888fcc6ddd996022068af19252ac4376cffdbfaacb2e0f0c216deb7e2478b586abe7c2679501eac34412103a47e5dea4ab8d785f4e00994d0faf1a8f384c41e74ed8e4b776fa6ce136ebc42"},{"txid":"180544709d0cc711566118b48af548a7b199c639185685c7228676725c28ee7e","sequence":4294967294,"n":44,"addresses":["bitcoincash:qrrv55s5ag0dduyjsc83ds7hstqc0m9htqk764mtaq"],"isAddress":true,"value":"1078385","hex":"483045022100b456847e29f8a648730f0fd34cc7edcfb35daba866ab7d800472beaf2836ce4202207db401f0a5e30efc53c7bf58e57d1dec5874d64768ad9eb4895351cc4be9226f412102291b40a9a927dafeb53cdfc7e722ee5c9dfd6eac2d81331678b9ab405bb25d21"},{"txid":"67c24b19a0f444541bcbcb15e708f7713f5168f89f3d42df51d1909f6e22b093","sequence":4294967294,"n":45,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250191671","hex":"47304402205ff244c77726def0e3697a3e546bdf74c7f31479c9d01a7a6f8cd1656482d537022045d78dba8ed4d3777f473736daedbdaca6f5698dd306898d144eb43f96259766412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"208d4a8a6afa218a65416286733a5158e7ca393003e30f88dec606e771e384c7","sequence":4294967294,"n":46,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250036468","hex":"483045022100ec6b35ce6d24889726480d70a31bc0d62800bf7ac49ecf084b98137322606bca0220432d33e2d8b508f26d7d813d18629453c537a4d90f73a104bbf80627f9fe8d62412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"60a7eef8d0b9e7cbfe602bedebd75a80121587af1236fcb8ddf00e510cb4caa4","sequence":4294967294,"n":47,"addresses":["bitcoincash:qq788skgg7eqc7unt733wahchmx08h87tgn20l2n3l"],"isAddress":true,"value":"1329593","hex":"4730440220423ea635717cff512d9262b7c8932c0122ca868251f019ae033101c28771a52302200cd3ae05f2e88d9f64207beb4b715ba480bde9ffdd40ab61a36feff88f2968d54121035530745f3cd4d31532991e460bd2a15e1944e690643f73133a9918edb95da53e"},{"txid":"7033ed9dcbb1af754c41046bf1ec51c16285336abc235b9485dd9c8829f32b85","sequence":4294967294,"n":48,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250053803","hex":"473044022055cc4dfa48a79b8584a9352be34ab5fe9cae4132d264dd827d14ae06d35ad4090220652a83c93505f8a8527c5bc0479f37da0593595c1bf18c12b8fa0b41a2e37a64412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"929f05541924a6eb7dc7f2e11310037de210718c5896b9d9475ca5724dc13532","sequence":4294967294,"n":49,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250171060","hex":"4830450221009acc8d0e06d10b0c764a27613bcef41fc75f910875eae3989a7f8725f81814cd02207146ff66f412910ed993fbda4ad6ed48862a02f366dd88a83856a17e7f96d83e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"a7e965c2d147a2bcc7d99f61bada49696703563d7b8225c9e69c29e312aab0a0","sequence":4294967294,"n":50,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250030500","hex":"47304402202d8cd72290f04063c0ae9bc06d2cae3ac74ef4cb6945c92c3e3ccca210c127ef022030471726cd87ac9d55f3d246095f64ae22b611aa8791922236bbdb19ec273322412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"e6897dfc8254d449f61372cb7c4131c4caaf2781fa60cf930a36421d0bc156c8","vout":1,"sequence":4294967294,"n":51,"addresses":["bitcoincash:qq64kqwmv0gu5naq8ztaj5ecef3042n3pceymy9fw2"],"isAddress":true,"value":"1746309","hex":"483045022100ffaa954e5b86d54ece9bcb9e37895047221828ca381b03266de3d9341599c8f902200ea1c5ed36e893df822c698a474b062d4f93005c32f9d2f0d78ecaf5a56e4fbd4121031a00f43cd99e015c72acace20ac47d887a39ef284f89a5aa09abd968d06f5e9d"},{"txid":"d69c6ead378471a3f30a9a7b10381a88bd8c5e343b8108a0f189f9f665901269","vout":1,"sequence":4294967294,"n":52,"addresses":["bitcoincash:qzudxte3pz9qf5gmnpr5yxj97kv3flcs2gv5mct8gm"],"isAddress":true,"value":"1792586","hex":"4730440220457d59caf24eb6e10664d06f3e936f6ee31d9d59f1cc4f6f62788f022bce8c1b02202ce7c37ae6832b078c1cb9a055e3ffcf4674081f0738fd9c3eb4465b52bcc9ca412102fea9ae922223f2c68c68d7672b7656885c3e1321d35cc8f5f445179df6f7d27a"},{"txid":"212aa8288a75640e62292417bf53dad20d242df7579c38fa10f2f63d8c03d38a","sequence":4294967294,"n":53,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250046573","hex":"47304402205e0f5cb06f7fd741825c669c87e9db1a433913fb8577adb92b779d3a693b4f080220120648a5f9d2abae83a29cd2c79f5c61b9bc40da8990736ab97ccf6f82c586cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"3d6a1aebc3f48b843e408421c9f421d3934670d86a3f5df49a6530152056da4f","sequence":4294967294,"n":54,"addresses":["bitcoincash:qrt6ljgpzzmamr2ukg9a3jxe46ufaa8fr5yp6f9pfy"],"isAddress":true,"value":"1801618","hex":"483045022100debfb215f94e9d784e91fe0b9d2541d09a4c7591172fad1441506db4a3590fd102200cce728e344933111c9548162e62872fccac624f6f98d92ccdcf98dbed09ac544121039b8a20c23f32f5b14e76fb29e0baade695810aa7b6dac9e9638a8d13b6ad8221"},{"txid":"91585d5312b1a4c8bca993b6db304a65c7bda601113960cccc978f28c381bfe7","sequence":4294967294,"n":55,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250046545","hex":"4830450221008110aec39b127143891069590fa0d9e1d8b41bdda70d9807848eba92cb48736b02201bcfdc1a1cedfa4c53efd941482f6157774b2aa80af44e500263be6a3cbcbacb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"b9b3d23c90954095289ff5feff55de3cbd7469cbb179e38aa74dc813fd6b684c","sequence":4294967294,"n":56,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250022645","hex":"4830450221009f76d6838b8fd8bb74f50c67920fda9f28054d093b30fd03b54b3fb888db046f0220307944f3abec07c3570614f418056aeff03c0830173c963bb0b65bd5ef24b4a9412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"65f9a63b7bf753423cca4a5ec229f566e61cd1ec8f745683da2a934b1308713f","vout":1,"sequence":4294967294,"n":57,"addresses":["bitcoincash:qz86ljat9dnhjp2wplpm7ncfm7q69hk58svu9g46ex"],"isAddress":true,"value":"1593178","hex":"47304402207b93e2500b189b51fbc3a49a191c4b92ac76e32ce86f6f1b9af4afbb3a91fbe002200b5617cf52095bf882a5129f5477f119c9c565dd582a9f19493cf1bdae6527ac41210323ab0930ba40688e66bef6e08f673bd6bcd3df687e4c503387f48c24bffdc93d"},{"txid":"48ddbf6a4cc52b15bb4d2cb7e39fcecae29483bcd3d6471e3543785621f3df7e","sequence":4294967294,"n":58,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250019587","hex":"4730440220731ab37e71d9c6f63333ba205a318d36e5847706381f571b4b562e5e6f6e403c02200704ca9d9a33843d9a16135f56eced1fd18e227385671a8df5fa41e505e3ba3c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"5027ac365cb55b21278f32710703d9ad932912919c58de364e1eb1e9d79412f7","sequence":4294967294,"n":59,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250045268","hex":"483045022100d1d3565175e1f529124ebba1bcdf8c1704e753c2f91ddcd1a093b5f5403cd0ed02207420ee9d6082356cba6d8075b4fbf310bd84dc770734a8ab30e74741a779bae8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"93cc92162ee854259d3b3f9ad1886847eadb2ccc86d03bcc6b89718da9ca23f4","sequence":4294967294,"n":60,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250086952","hex":"47304402203ddf5c6c5065f03229cdf837d9f8d3d22314834b006e0aba8dacabea206b3b150220417c49c9095372d3dfd954688bcd43fdfd2a121989fde18456a9428b2a8e3c63412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"c672af6e97eeecc79e87e708d57e20e2c7d811bf3431eaa928f7efc24b663dce","sequence":4294967294,"n":61,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250143426","hex":"483045022100a20e6aaca7df2b142b768d3b1cbf8f783f3d4997d155a32f0e066b4255777c9f02206deb15cf53d6b27a973df9aa7080691e5914538d9e97ec7c6e797ce03333238b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"5f64a0a07336a2bad8f9611709653146fad9fc796f1e92dbd12afbf0d6dcf5b8","sequence":4294967294,"n":62,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250125454","hex":"483045022100cc2cf5c6c2d4862dfdf65407138684ba45565bd8ec46594ed4586bfa37b715dd022013255b2eb22f5bb93d2afdd07ec4c3b5efe0aa16134b2fd084c6bc720f8cfd5c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"256b18d5861752fb617796cef5ceba05e42de141e48aa2737c77020e8d1f337c","sequence":4294967294,"n":63,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250058048","hex":"47304402202c9dd98c9a72e5a8df4b01f09d18e2826d8b9871db89c5d3b24ffd673facaa0702207523bfcf3ab80790167a2b1159fe268770371fcc7d770995c19eace3181ec8af412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"aeda3cb9ccecf67cabaae458862b2068129297b1b502b862067f578a2201d54c","sequence":4294967294,"n":64,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250083898","hex":"483045022100bfac8828df10b7911d341c15a532819c429c7185d8883de19de84e71b97d78730220177603a3572908c90dad865770906b5ad228da7ee5da39503ececf60ac735158412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"0b11e279a95eaf9241bd55fd7f7b045e2ff047b307b25f3885feb6a71140d6db","sequence":4294967294,"n":65,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250050928","hex":"483045022100d598e2ccdeecfdfea9d5139a49a94fa39414f9e1ecb13d54efeb34c168e58aec02202a59463710905613844f48dc71d316c0cae54ab9e16dd95beb8902e5940024ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"82026eabe17877d3aae729eee2612778389a9246d56b8032706c454223760eb9","sequence":4294967294,"n":66,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250039790","hex":"4830450221008302d38e9eaccaea812c853047931562417a3665b8b9373cf7f63e58180b002602207ac8fddbbd19560a74333ec92fa077d169b4902a41e0431113f8fdb75b304ecf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"43a94c82abb414437ac13038fa5840a6038733dc156bf160cf30db31a82355e1","sequence":4294967294,"n":67,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250105160","hex":"483045022100c0d85a1f9146e8ef9efaef8ed9b3ed09c55e51b25e189735610da89b6d212360022003a49114e504741befcdb95d52a3dedd1aadef68b7c48f0a4a8c7dddfb4201b5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"41f835819365a32c2ce1138c131a4039c6dfeb034d922af573d997697b409378","sequence":4294967294,"n":68,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250127067","hex":"48304502210091ec8402cafd1e7eb11b56ac56a994ac79c435893108d0b7c8cfff87c07ba0a602204fd98efddc1b4e21bd3cb81217579a7b9621f9c3c204f2f5800e75ce1c60b19c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"2f8ca9dea380bd026636e2281f1e42e63dd54a04be1c1526574994450ca36f01","sequence":4294967294,"n":69,"addresses":["bitcoincash:qzzkjplzf0yw2xej4u9he5pr5evgup2snqqxs823e8"],"isAddress":true,"value":"1366913","hex":"483045022100a850bf088a08baac1f1f577da8946befe2e6b0354d6a29f636afd39982569a7e022062652d6b75dee145f741d28d6f1870fde9a7d66b994f0d3162abdc42fbf54458412103ffdeec10b52942b0c46d6578998efdc1d64073de579e92e7c5dfa97fdf3ac391"},{"txid":"404829243c500005d37a95164bf6610005ccfa19cb7660ac9c1ee0da009465d8","vout":1,"sequence":4294967294,"n":70,"addresses":["bitcoincash:qq4kx2926zmnhfa36xzfswf9p9raqlapmysqvr4ck6"],"isAddress":true,"value":"1292340","hex":"4730440220762f7c017672dfc71d487f3730e26d69d0e53902f579ba348095ca164d27b094022076c7e8045ec9fc57af6dd95f35c0ffad2c0ca8f83f112f60fb9851ba4ba15d92412103a2d2d8251728b11fd4afe7b8c73a8442f76dff9bfa424f5cad9b98083936259d"},{"txid":"2624cad28a9b7f55434b68fc8be7aadb87d40003d786f0e414cc1eff74a12b64","sequence":4294967294,"n":71,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250134907","hex":"47304402200654032c5760f8b94cc089da51773447f19c1cd2108cab89bb53ccfdb6dbee56022015e277622dea4bd1a7913ff934b2bb2d1b3d75f05285b51690160e1197a258c5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"893b3cfda77c1371e21df17e45910578fd778958f9b51fcebb24a2e92c604d65","sequence":4294967294,"n":72,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250033040","hex":"4730440220712877c0dc553096eb0ebf101d1555fda5235db26ad074d2f330163fab63fc7802202c89752dd7645e8a3da7e8af5fb68dc8b177700766b79cf6a35695a0c7c873cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"cd86f3aba8b0553de0041a2173507a34f595a3785dbaeb8c9b2cc1c1c34c61cc","sequence":4294967294,"n":73,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250105407","hex":"483045022100f3fa1e305666e2a62afaa11fd37025b25c0bdff8709fe1580406615934228cee02204841a7d96f36d3c183f06e22a58175756c3e9a76c93c7cb4e9945f31ddedc902412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"ae8ae862b5ddba89e69b42aa8a6ea2693e61f90ad3a5625b5f81605c7aedb226","sequence":4294967294,"n":74,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1254457185","hex":"473044022047c158e3fe3f40de3f39796dcecb7df3cf344f14009de9826b62a43837f2cdcb0220759d823cc145fd5e8b651a7bcc399544692bbf596189b1fc50bba5f4ca02cdd1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"b402b3d23c910e0ed869045671269210f6594f308b6b01a0bed2052f6012b0eb","sequence":4294967294,"n":75,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250101109","hex":"483045022100bd70744c867943bc3bf578e192c8a87a5ed5126aac4acd98efa06ea2483911fa02207377e11ae2d2bbaab00da86ec73c26e596bfcc680c0b8eddc5d44bda650bc299412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"e1deda4073c863ba018bd7334f625f79884854006f27712cd010e57bf59c8087","sequence":4294967294,"n":76,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250083658","hex":"473044022059ee25066b8a2a4fdfc35f14c5cbb7f22ab181fcfa9702d4f3de7aa4d738c7a402206dff315ad1cd2222cd6ac074bf34241fc22db38a57bf089f7e24542323f1766c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"219c39d91c3d5d3d1f81c83ba373df7ccaecb45f5e4a2f7422bb2021afb7338c","sequence":4294967294,"n":77,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250032757","hex":"473044022039657cdf4fcd5a9e81766ba11db495b8be5664612d3b91f8504bea342c4ecbe702206ca4913e5807cd697d30dbc93e0a9d679eb01ee84b687ab0c642e2f3ebde745b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"3a1f594a74bad6de4c762a78a6c06db3900c45408ec0f785c61bf9f29bc34281","sequence":4294967294,"n":78,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1253061599","hex":"47304402200232ee94873317eae275cf715f4c3aca25dd0c8db4800946a45cc1d9c45732fa02203d9ce9c9aedc0a3899dd027df32e683438769d66f33ffe52006454614b77821d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"14cf83e6c8b80366b8651c6b4a0f7d2270290066325d686ba671ab5c4c9a3b50","sequence":4294967294,"n":79,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250121784","hex":"483045022100900bdc6f705efa56449a65f15a67fc7fbbc102f78e7974ea6ac2849c75d2dfec02203b78de71dad2e3f6ffad2779cb9007217c957c8f5db7abd58fd0537fbabb8c6b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"1dd1ec6c4b4ec9bf13aec933506376c77e63254d5573c2584d7515554f14ed8b","sequence":4294967294,"n":80,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250044721","hex":"483045022100becbb21c7937b9b27ea3cdac5f2048ab9ac314de59c3ee2926a5cfb258ce14e902201c8022bf275c1a761e7715b14e15d74526901363ae5f8bf5489d00908dd758eb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"9957066f6fe221a9423b0f54ce1188000e1e9f7bf9085527d9e1edb31d88b7bc","sequence":4294967294,"n":81,"addresses":["bitcoincash:qp7zwhgnhhuh4j8644mqg7y3fqejm2jkfvkt6qp4pp"],"isAddress":true,"value":"1876300","hex":"483045022100ad84bcd69a85a0d487fd7cbe4d76b95bffa303e76615a4336419fd182eeae4b902206d21e4f592297e87f1af9e19c80fd978914aaf5a2db2cf499b72cabbbe73c831412102958762ff6c8985dc9656afda59e61afc6c0131a5d8f1d86c87c83c9b37f7bd18"},{"txid":"ca467662c89f207dbfc6ec016e126693a204f17d6151987aa748838852aeffb7","sequence":4294967294,"n":82,"addresses":["bitcoincash:qq7fvpnuflq4cq6wc5t4qjuzj8l59puq75h022fyxs"],"isAddress":true,"value":"1114817","hex":"483045022100edfd64cf9335d094d5873deb38cda5f4ceda3351df722f1c718993a2dd12c8e302203126b0f9470a4d0867ed4e773518b8ad689ce43a2c9f65a1f297525fc22201dc412103f37089783028c0776f2b8a9d8481ec8d6d0652a31edc03cc274032ae17c63c62"},{"txid":"54fde006c8dbb7a3de68e0609d057a3f2337c99ee2ae70cc715d72f5dc881a80","sequence":4294967294,"n":83,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250175152","hex":"4730440220448751a749e7cccacab0ae1ad4da948b0e0b5d8e3f41ac2b22c18928e8e67d41022051c107c345c06ea82fe8329a8cf3a96b516fd8750611d8ef438b8545416398ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"a08d7c70130d925e33b93e21cf77b5790a2ab5b5dfc4ec2198b9d81a74af06bb","sequence":4294967294,"n":84,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250056417","hex":"47304402207f9b2802ed1e893168277204b7919ff479efe5c71ad2a255e1738a52bacd758f0220253780485f2e3ee960e058d449c647b147b8f64b49b913e7e9615a6c7114f18e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"e2c0a8e67a48286fb8801c0faa3951a268c5f6cc450c445c380e80e09c752778","sequence":4294967294,"n":85,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250043784","hex":"4730440220778fd8ba1dd9f71df55bbe1c3c4185b8da21dda82198546c2a0c30250f4c1d66022040f17a46187d535c6e943c047942f45159a37b2e171db18c657cd24168c22e2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"221971a381aaba4e963d21b54e625b764016e848a5390a0df32a29aadf35f92a","sequence":4294967294,"n":86,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250090058","hex":"47304402202cd2fd29fa395a5a80893de065c8bbe71e0bfe0e7b2224cfd5684736a086aabc02206720226ba63a3e5d9e2dc67e404625cdf31a7a08da0e8a22717e558f7abc817c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"bf6623abb315d54e6b7d9428133d913121ac875dc4c8e3f698477dff8cb7e3e3","sequence":4294967294,"n":87,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250229940","hex":"483045022100f8769b797386f0bdd662483096f4e0a33c13f6074a4aaba3fd590b9abbca7c2402201eb064869fcd17a59ac028145b08c73b3552544cd7fc62245d1fd1d369ecf765412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"e66b832bf71437eeb367e6cd7818658f960a4845bdf3f5081aa474935c9b31dc","sequence":4294967294,"n":88,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250154777","hex":"4730440220558e65fd916d9c9616a3e0bd41111dba3914867b1ce5d487df4f77feadc0059502203198566c0d58af8551b65f884db98bde161bac140c7a900cd40df97a40c267de412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"452873e0c38438227a2fcf64230973ea8f5868fabf05603b629881a2b46a4069","sequence":4294967294,"n":89,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250103829","hex":"483045022100ca93287feb58daad47c5388067b219e44f8533a214eb8eea9b5313040579773002201716a6ad2de70eff6721ae7950edaf9230420648bb8ec53173c215cbd12246c0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"60b3b027b67f550a0544a539f173066031914f0a49897379b51ffa127117e521","sequence":4294967294,"n":90,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250125814","hex":"473044022003240fd71510800910b448c62a03178b4ef62299b17d6d2c06ac8f3293684ff50220637e3ba59fc884a8bd16aa2e884b379d85f38ae4ba049a0365f33644febee6df412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"6cf9e489432bda9fa9eb865587eb28ff525b5171c38f746c55b85a577ae68854","sequence":4294967294,"n":91,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250144563","hex":"47304402202e2ac9c8b619b8e2626895c20f6bdd1a24fa27de017d05d5fa2ce120b3421f25022053ef6f82ccf9a132d40ce566d45f4ec18bf30048d415f6ec1c783cda027b6747412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"9c9923f0c3366eea9c229233d8828825beb12a2c28ae3bfaf46203dd1fe8ab03","sequence":4294967294,"n":92,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250218730","hex":"4730440220352bdfe541e9e1ce428ac4eb4c8ba9391a118b7dbe57b4fe3c4ecd30f228fbff02204a0b78ada1d74a7e7b9ae912e6f445d9ce9050855d9c5ecc7d477d2590a68b18412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"5ed23fa46f4db7043e14b845ef13a37712170f7cb25f88ff9acbbd6bc97a9d87","sequence":4294967294,"n":93,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250079095","hex":"46304302203f767d8f64e3c9e5773d94a325f8029d21d1c9a0f470c9288cd99f70d2d90ec2021f50b395f9329ffe64ff8084c1506e904ffc02dfac7f7e15461c3e8a077f604c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"fb09c795e5cf32d174df4efe8b2208de9819ed024511d9fd684556ec8adc00ff","sequence":4294967294,"n":94,"addresses":["bitcoincash:qr3vdgfvrp77mlhac73ujqgtn78cg6yeeurwnjqylu"],"isAddress":true,"value":"1792434","hex":"483045022100f17f8045a627bf96fe09d868109063d8040e3e2df8944e05f9b20a15273d0bdb022059c31e2d849abd57e784f1a3903f49f18c7c5a624545bab98649e8a092e12a10412103ee2a3f78cd4930dac8c030ccc93381ec5eab259c1607360d85d1728fc296dacf"},{"txid":"36bf90cf0b6074a361292ec88ef58d76780d301a1e5709bf013808c068af253f","vout":1,"sequence":4294967294,"n":95,"addresses":["bitcoincash:qzjvk52q08wp84x9uelf7k3572fx4z5q4q7vkpaalx"],"isAddress":true,"value":"1713598","hex":"483045022100b58c7dd3fa1f8dc50edc7b5546b8ccef8ffc5c179fee774999c63fa729ae3cef02205eb611cc887e5a62a4e9da33318ce6e216ca353225f452ebca51be1dd10f544941210267f3c9b9bfb6bc5c1f68dd1d18623a9986408202cf232ad1e4089933c83f186b"},{"txid":"259bc4abb9f14457e323223bcbbf772afc0a0252556e69c9e13e8c7860e7946a","sequence":4294967294,"n":96,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250075778","hex":"4730440220097f46c588f37ced4846a45905df1a0ae22709760f8a1bc930a58f5054cbe482022053b418af66d1edcb3887616feb23e5dd4095f29e74ac89853c3b909eb42bac34412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"14a32331f78309de6ddad707840b364aace14cbef8694ab16a55305fd44260b2","sequence":4294967294,"n":97,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250085059","hex":"483045022100cf98e22a2854c7088a0572e1edb4e876aa622ed10dc0376806e1432f5dc1eef90220527845f8dd2522fbdf423b4fc34a4792a7f82e04b314e0d83e2425daa2f92115412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"acd836ea3252a7610e6c1d426f2cc739f73fe1a0768048d7431a69d4bff3f0e5","sequence":4294967294,"n":98,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250132855","hex":"473044022070c7aaa7d7f050b1b520878e55db3ca491fb33211150e2f620b685cb49d7d885022022d9ede63e3b196a1c33c2d211c1eacf2e2411820ecf5155b5e4244f5dfd9f1d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"348cdfc73c3172311b972b8c529545591f725b86ad065f88d7a78c2fcc05f9fe","sequence":4294967294,"n":99,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250023474","hex":"473044022018cd70c3e62563ea92ea12735e2efb4b905df85e6b290d573051f49c63d07c60022037a537ca3514121d5c2b8753833808a5e0432f1a8f277d91495953c8211ad326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"af7baa39bec2ba327ff720a7c782f833d18c0677c644080f59996e2270756c55","sequence":4294967294,"n":100,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250249377","hex":"483045022100a01ad9ec8d24fdf01eb203c2887c1413ae56990d4600a18010959f6df43de08d022056f0f0dccb8f772f29a7835d7dc40f242348805005b5f80ae8f2fbdb600ab2ca412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"6ba95cc08cb6849c9599eea8ec3abeb7ba7c7b42399cfc6d807dbc5aa8c1be52","sequence":4294967294,"n":101,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250192878","hex":"483045022100cdd770159d56ac518ecb0dc916df0da06eed536e540582680f742389f53fa4be022012d372e2c04176bcb82b91b02ea23c9c1464baef7d1dda66066bf84c402c0012412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"41ebe9615cb3037d95ed10c37be1fc80d216619086c5cfc256e489ce42042d3b","sequence":4294967294,"n":102,"addresses":["bitcoincash:qp4h56rtxkel7traz24d3ep3jq0yxqm82stgclvks8"],"isAddress":true,"value":"1288555","hex":"473044022001dc7db378891c1c5bf07a09d14fcc6675965976e2e3e762786b1b1e0f4a4bb702206db6f284dec835823fb516fad89543edd3bd7af3ed33940fa296939fadb41ba841210393ae47ec2e844378cda3630abe12082401f2e0f98d016dde2b152b42e335630d"},{"txid":"a135747cbd99ace7bf495ba29e49b5595f32259ee7df61d9549cf3d4274880c3","sequence":4294967294,"n":103,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250118091","hex":"4730440220290a5055313d68f9461ce830f8a7395022d2d55abf28f6b4bd665693b4a13730022035d4cc2a6676ed842027dd4f21d31dd5a956f4b1f5cf771b866cc0d4a6400df0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"90095e01bb497ffceeb85366ee1b9603b96c33ee0acb47a64fe3af23911410d6","sequence":4294967294,"n":104,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250028058","hex":"47304402201fd6be6d72ae75b61a624c13476b538ec2f9e5146f3074c879af57ecfbe1679702200ab10ae612e7fe0f76fe943c1f6a02262008407f86782c1536e92e3bad77d3db412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"44b169e5c5414cd335ef67906c0f4425e8b190ab366dd1e16641a34d85ab5f20","sequence":4294967294,"n":105,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250132073","hex":"483045022100a4132f408b5299dfed6153b7a331f9fe866f1b042e4263bf7574ea0964c450a202203d99cf8dc9a9194269bce400185a4f86f5d35b5be83f6dbc3166b600392f1b00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"f7f16d4c8f00cb446063f53a75d2dbb2c54d9d474abc836b92d48ed76a5ead8e","sequence":4294967294,"n":106,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250210684","hex":"483045022100bbcc2e2d77458abc30898cddc7eda060b23a62f0a53b81c3db47f284cd7b29cf0220705328a29bd30792a7f5a704fd74b771c3c8a099265f5e7c9d70046da5b03ff4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"0252408a18fc77479f6e664fab80cbc6d90c1c5e369c34661effa52b9f1f36f2","vout":1,"sequence":4294967294,"n":107,"addresses":["bitcoincash:qqe36s4qsvdfjzwrv8whsc0z94unav03agzr35m4d7"],"isAddress":true,"value":"1591983","hex":"483045022100d2f40145c4b9a17b3582aabdf7d9ac2d47546b3eea5350c4e2ec1e9c2466343d02203354ce620aa056a749de847f867c49dd121579c9fc50bd6258bff7cfb173c5f24121035bf755e8b075665a85155618f6e9022196a09c486415587dd3af0d25b76e9c27"},{"txid":"74002fe81a5931658cbde74c28933bb36cdaed62201be1c0e26a53c92d6bf5c8","sequence":4294967294,"n":108,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250148696","hex":"483045022100cf8c593dec0724644d034f17ccde99feaf0416334219f158f884badf500fc93e022035af1b68574e88ef15e1c05c1b36638401613a31aa7096d97efba6df62695706412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"496b4d67e0a734740962920c116d56121c16ca60787812fea76d69b9161f8395","sequence":4294967294,"n":109,"addresses":["bitcoincash:qq99u7jj9ujglljvh8nzaqtq0kfl8matf5eldrwhmm"],"isAddress":true,"value":"1859920","hex":"483045022100a669e8918ba68754b84d584f38afdd34be387773449784a6c61ef3f33d0fd99e02204d007ef31f5a3a7c412ac3d2660633fcef137964ef2ff6269c41e933896d918b41210383b6491fd80e1411675d7c8eda9b756c30a814b45fa565b7ac24d7be9dedcaaa"},{"txid":"4a6f608d6ce8efcc0cbd3b55bfa0feef86f5493331564dee943fa554fc84111e","sequence":4294967294,"n":110,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250058421","hex":"483045022100fc35ed21833c3ea3ff5f832ef02236a08ded0999ea367aa6eaaff364ecac3e5002206e291d7c4fca0485dd8ea22519544ac632909d706741710a6e5f0d472c0b0656412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"a9cfa2539cb07c0903e2a01a343c6ea8566bc063b4c301ce2efee45760e36448","sequence":4294967294,"n":111,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1251645868","hex":"4730440220485937c55c67c8eb46b94523cb06f9572ffb55094536d8b1a458c76b67dec75b02204e5007f610e491d043a412696d4fd769bb2f5d8c3e8b3a59e6ec3bb598f775a7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"62466cac8a8cb05584af3ce85d0eb8d4a5edf644a374aa23989bfa2adad2d8ee","sequence":4294967294,"n":112,"addresses":["bitcoincash:qzl7yg7fxw5ls4jum50st5z7valsu7qa7v63ks2730"],"isAddress":true,"value":"1579507","hex":"483045022100b430528ddfca4431cf5cec08964f7325c036fdee55edc0ea0181d34ed72469bc022074b75bfa66dd4a87fab93da0f2f0def65b785fb0b51fe07355799cbd8b30c39a41210316d35753d58318c06d0faadcb723563316847ae06019984f42f2c75deaf3727d"},{"txid":"559927367907ed4d3822c2b4c0dca89ba2a4df844daa1033123e9939c9e81743","sequence":4294967294,"n":113,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250110065","hex":"483045022100c6ccc3891fa3924c7b1e69b855628230c48d85d1e1331f037823ab7c5928610c0220050c9c0e078f34ced537e88f95289863a663b28488880f6ada3f1dbbcb1743a1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"7b5bfd94b29844e13c3fce76d9579dc7d20b3fa0ef15309714530152e4d5ae85","sequence":4294967294,"n":114,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1251309649","hex":"4730440220168f31f413d65ce64bccb62390490dae2e4a00f98c2c44bd4fd689cd942da8b1022006f1b2aa4fae9587c688e8b7ca5c07db3b3c3afd6961f9f843099ed30b583369412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"}],"vout":[{"value":"32902","n":0,"spent":true,"hex":"76a9149a262d0621819c8c17d34a7feca1b39b39157af988ac","addresses":["bitcoincash:qzdzvtgxyxqeerqh6d98lm9pkwdnj9t6lydxqg82t6"],"isAddress":true},{"value":"115067302350","n":1,"spent":true,"hex":"76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac","addresses":["bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7"],"isAddress":true}],"blockHash":"0000000000000000023414a6f8ec13dd4f85b3fb1c71b937d5dcaa14e350cd4d","blockHeight":611623,"confirmations":24477,"blockTime":1575319726,"value":"115067335252","valueIn":"115067352350","fees":"17098","hex":"0200000073126b74e8eb1830ec84d26e50d09360e120e92956c823afdb2e981432e60e152f000000006a47304402206f992d73dfa7e518b00190f220ad5dc7b7947b1d75a2fcd8251b59f3d29d89af022036c6c44f52f9aeed406dec72a9aab1f82c3b997c36742f4a3504e4f93e6f8557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3848b83fe17d5304f63a9457a5749ea2ca1ea42d9934cac890666e2173a80b55000000006b483045022100db30ebe47536e42115a507f88bb8d5c97b81ad05ce334872235811134c5948bb0220418d77aed78cc4a332b1858c1d2e9ab169828b9c12e8c0d0f8d155964e5d0b8e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4321b2ccc28666c12200bb15a050a513976487cae0a01205cd30ca10988d8ded000000006b483045022100d30c9fd598613586d8d0460fb6c9ffc1d0c6dff6f647535d2a9f69cf373193d102207fff687aa035910db124adad8b59607a72b3d24aca9096217ec6b90fa132a2ae412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff32a0d8da2143d7c4097af72285aff1305155ff5e05276badc91839d5ac9bd7a2000000006a47304402207b30e99cb1f6754d227a4511c5b7791f3b896724b170716d6ed238017f191bb102202c1fadc4c572c86288b002a0d6b6d2460a14a6d3c8b49efc17a03e59d2db18e3412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff62f77994b08467f9a90c1b7b921306d7e48c18015aa53aab74775b73dc79069a010000006b48304502210092b7f176f182936323df8e4359b2a329b0c1e4b48a529d6e32867038a2a453cc02203c24a8bb46b7fea4ef5c78ff116a51fd0a04dee25bfcdffe856fb8988a7a97f64121035b4e75dda9fb0d55d856f54f24fc65da6657939b9559ab2c623c8ef325f14d8dfeffffff5cbff5ba887ac02cfcf6f1adb0c84ae21cc003667734dbc41ddc31330c7c555d000000006a47304402202a2bcfdaf12c398ed5372e6b168a786edb8972df1146b705d3cccf2d9601517d022020b90ac89d9141d68817850d1cdffaf6c51f45249a44fd6861b361a6025d8ac4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffca0bea62231cdd9cb231ced73fc1c0f51c478277a077a55aeec113b506e7db61000000006b48304502210087ef2709b9fe8e7f136219254229edd45e94c3f6ebd2bb149aadd9b1d44d89e202206ffde3c9491c012832967e4d34e02ece2c08bc4c07967b3b466d4800f9ca0746412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff843b9b8e0072454494ac701e9f0816590de35f53cfe960aa03bb4281128db254000000006b483045022100c7dbd1117c57eedc8fc006e818371bfe6399c4d25e8b40482c1f0858a3d98a4b0220426d1196513a87fc7afb5b107b770a90af789536799a11686eab96b04afa6326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2301458143bdd235636b4a15f1ce7fef218ef401e26f5871d26bb28e632e0c75000000006a47304402203604fbb20824443899030d2c1f5cd0dc2b88174929861a708bdca878868e910c02200a607b1da53483bc95d3a5c54e5ad66e459827d4ecf8b4ef9909e9d58b2d329b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff9ecbc5e26870067db7ee944b7fbe3fa99c3247e0614fa5bf24a9eb587c36d9b000000006a4730440220399c36174173cca01f6d6a234a935d6f776b549e1ea2fc2635193924c4ac2eb002205aea7741fafd95f862588c480aaa282d7a344d32d6318aec1a908cbb939e5d0e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff9ef492949a0ba873b09258961f35cd18d78849cd290fb93aace31af829da278f010000006b483045022100da9075310e7af59456423be99362f2cc686d50571e0f0b016bcfae1f0bc4692802203379b648d47704dba48542b8b6d5e515bf3c4fd7ff8a7be82cd0c8c0c7be56f7412103a344a84dc1a919a64874605fae200861b7af3ecd02dc5d52dd00eb6f8845525afeffffff5c5f3037b499d79505425804b021b76dd94e1632b6747afd059d0a728ff49b10000000006a47304402206cbf93634d6a477a571fa2884c19918b19ddfb008ff9fe405954720047efdb88022003e755313436d406dddfe3cfb68719e8f39e43de7c586489cc543dac0347da9f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0b183fcb0f29cff3e9f22ff47a5c87694199ec43b77930f7b17d646f3670e5d3000000006b483045022100f23d4cf11fd0a5ab83dc053ca64066cbdd2fb4107e0977a3a880c68a67636f7d0220220a47c66d3944cfc309c059fe8013c4de742e4d8590003fd56c5e0b3c7da557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff80540561a82abdba58b2ac3bb9bf9f1064106b8f2fdcb63d462721409af9056f000000006b4830450221009f522beef55cbf8c7f10e88739846f78ef1c9d9cbc6959dba6f687a08fec0ef502203a160231733b87c6cfd8afd148994c9b6c5d5db9bb9847aa9e60938a6e79d5b1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4a4a1e4ea13377a0819a88e2664facffabd92566b83fdca3456267b017b7933d000000006a47304402201f5d29be80192a752fe28ff141ed702640df88083faf3f9573e52405cb4bd79a02202d751649aa600c4fdb8b1d1b21f0d134c2f4e5af9ecbe7d87180d667140f0a11412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff9b41a363950ab3e6b769a4cd97555d1d8336505f3c87599ebf7766642ec97ac7000000006a47304402203f4bea3816d252cb19d4247f587a146901c74d04e783efddfd5089942f2abcdb022069012613c4ee4b3b0212ae71dbd2071e01665148697011eb03eba25431e679cf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffab050b7b334656d60e2c9772a3820015a2f6a7cc3e2943897b0c027edba3cb90000000006a4730440220782ba77287116d5d735f67a3738fbecc1a802d2141a1fa544f61a5e8ba682a4402205473d68019cc8895ecb1d87bfced62ddb6dc48b81152f2684ae8530122d5b41f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff26dd82e448134b4105f561b681206a059e1de4e5690453dd8e4d9a0482c35ee2010000006a473044022044ed9bfa8674d7e83112fa22280797169d45bd971b185da2413e36252637529d0220531eefc480e0911d6ccda42002942883149bc1cdd1f3bbde313751d80bcf98b641210328ac4ed2b30ddc04c778a78b24e7256b08c55758c1465defd997ff4bcefacf10feffffff9e2e1b53ecf545d0b0cb972553deb89f3cce7e9e92d0e0a786779df0df48a113000000006b4830450221008cfdfd352e268dba2022e7fbfc37a90401c40fdf6f1d8ba9dcb97d67743eddc302202c0a1b604d34aa174fddef63c9115c95465548855c5f783bb206eb4ff8fda235412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff9fd5ed5458cdbeb26b0126512a1b1f1aeb85fa7b584a0568c674708fafc0d70000000006a473044022001b33b610b8d742df2ad98679f1e41f0c647faf272e15e7ea93171ba29c33bcd022061646fbcb81ba30d6e8b030ee12101d1f1bef38ba44a6d5daf40c4ff6d644e6e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa6f2a72bf25954904893198f716f7b6f07e68bf35c12c233aa6d165723931068000000006b483045022100ec9b6bbaba90d8902ec8a1ca0e90ea594264bc1add204b756cc89def4d7e9a2a022066b2bc84f94e1a99effe0e929be8de8669631143ca20c73e700d182ad4884e71412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb38019b996f974375732d741fac543bcb46670b99c566a8a887c3f876485a942000000006a473044022057117591cc465c48da58ebcb8f57fcd56359757d41e1397e45b5e33e034ea5d8022001de1d78ce9e8e73370a0778b4a8595045c6faeb2497ab4296d0cff735711276412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbd0ba68d3c24402ccc4d2c82c4d11ba0a794bce9e9d39f64668aa4b5956eb5f7000000006b483045022100dace56650d1d9edaef30e8c9ecb4b78499a573984c8a451253295a90c84a3ed702201f4587d4a760cd77a2e21d5f6f2b7aacf668220c8c7c62fc1ae4779f7c0141cd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff143d2c0bfb63e9b52766c0f7921d06a1d51b90a770b64902ee8352122c918bd5000000006a47304402200db6b461a0082807f59053bea210d38f5f82f02dd63a57f6e3987339cac23870022064ba927fc11b36318785d4e861a7f94cb3909ef8fe882360e2041f7b4a444692412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb0b7e16b8502ccd5ce2ec06157803e5c84062f5e8e4804a633f9e809ce260353000000006b483045022100a3e75a6c7918db32a27be348493b831631856ec8f546ca43d143cdc3c1cd03c802201e6ae036423bfce45c500b0c049f68396deae5cb999038de61e972ccd4cba5e7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff6d284b186e26a4116b02e6568c2868ff13408b85c71db1495a5e7cd32a4151ca000000006b483045022100caf952ca1760052cfefe8df283fdd0eccb9e1238eea88eef287df9404c622e8b022072027363fa1070548576fbf9bcbddf2e435fd020662b2d8f0582b52bfa487b31412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff38bb6ba6ccca482c333c8fd0e35afffb150e4c99fdf70513175f10bb8b263ec0000000006a47304402201a4b4efff2b70a4039b4dc120141da04ae84f63906df10c3cad08838c01b6b8702205a065d025c338547ea07b2095ad31252658e57f1a7a04c7f4eacc0248e611fa2412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa326b367f3405c7648e8e12b5bd7078867796b60f70cd4b3123442a6fcb9c846000000006a47304402206b0a876d78793710acaa8bbeb58a2d908bd4936f2a88825f944b190041b5e0be0220279560be5009e4a3fab44d08f4748e2dead710a8ccc77e06a03ba8112d728856412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff746bb13f09e7c465f9ea0b264c601ef9652736d83ca0c78686ea25326f6bdcfa000000006a4730440220799bdb7ac60cdf3314cc1f157299858d353e22c00354707337ab5b497619d626022000e41053afe44fa65227b7dd8498300a2dc89367d9daf0586caba5bffdfde567412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8da9008652012637c8bd2a3e6c9b6b6c4e12e67126ac1e5cc3b1d42b3c16b5ad000000006b483045022100a1af33a83edb7fdc289a48a4f77cf286a88b38c21ddf27dd4ec3df007ce11046022074dd56730730f958039efd70edfe7e181060fec306c6df4cf75209600ebebed7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff84a1b480079b2256862090844d38dcd463315a43b757678d7002cc1d01001adb000000006b483045022100eff445419ec63d1e9f51a5324c3be0315911b39f30657639e84ea7d2f739e0510220218e73140a39542ec8055b6645cbb7989f96b9d9a93c67549c059509de06f0ba412103dd71b53aaa823b09a68aba30c7603c6a397e7c183f708c9dfb0d9d0a9cd1c722fefffffff8872f26872ae96f137ba029e4ca6d19072f8223c0664608eeacd4753e8969df000000006a473044022050b7ed06a6832b8831c08ba86049b3793b5a71fd6d5177c9f268b79c3074bca7022047447c23429de30c361875642d9058bf1b5e0e6c5516d6e71b70b7cfb29827aa412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7ebebf2f8b764657a719cc52e3ce31fa79c37cd2d583b7be31ad9ec2ebef3284000000006b483045022100fb072bfd399dc11191ac449a9d60119bd191ce6b19a5d92412a805ddc8d4b46f022021e463686560b15ddf272b9943d8e41425ed500f77698aba518ccf546a97aeb4412103e35c58a738805f53af73472ffb671a9bd3556ddef47c62f18ced868bb5033d0dfeffffffbaf05866b6eba762daab7778d4eb3fa1902346491f14c8ec047c12aaae4cff29000000006b483045022100b25e7d4ebaa0e7d8e24498b039e756d568b67316aa14d05abafaec59e216a73d0220010d0b6548a74435907eb0d548dfe8e52a949bbb785eb2be3bce14053953784f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff1330325273e9a1329b3379a553ce95bda9dbd7b83f93fad4acb8c1dd45f4463b000000006a473044022007d2baa9a766c120e111a727bfa8e8bc2e01cc285d4d4f67d2323b213525a10c022020f32be2d9935b6d9b5091db27ebf00aaeb54adc7032badc7ad63f20741ff28a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff44530eb5b53868de4819fd0dff26c12e2759f4696ce114e22855e88be1b1d41b000000006b483045022100f98ee28ffb66acd04474a120904ec1be2327d727d8ed8fe99d8b95c174b8f46a022041d21406dd8df10cecc1d6435de68fef3f9db71838c1ca2910895bb184b4a6e4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2fbfba76ef97ef4c6e575783e08baa25da64eed6a7eb4ca48707feb7a2927406000000006b483045022100ee3f7961f0f23137d753affe85b777e94c1db3f656cf41b8f59fcf82d9226eb7022025009482a6c0002e409590075caf7a78023ebc1457f100c8b922a4974ebf86ba412103f1d1dd7685d3781f58f9aa399a16f6bb9ccc7d008cdb7c63a7945cfcaa6ba0e2feffffffbf525c080b8b43afd5c004b40d25a7ceba36207162b2bafa70ddc95cae68c1bc000000006a47304402201fed9da4c0526ac5ce257fce2b7fc995646b5f0d2961396327f93e2dfda3e4a0022035b217adc5a9be2ca34f4361ceafd9f2d09a6fa47d4a767f7001ade40c08fe26412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff327b0b903a0f60cadd0c8d2e2cf774ee04eee9a40bf5c37181a471045f365d02000000006b483045022100fa8ee82d42f524290319fb3ee47a1afa70cb952f8a37325680d6fd651ac3699f02205ac0cd86fece03ca204bd881d67ccce0cccbbc98704d9e955e2f92b5b77121dd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff5fadd3b92b767baaf2a50c8b21f8d3f7cae103e7b4e4c0ba60f111d45f8a1cc6000000006b483045022100f3cb343c4704bebbc78c6492dd72ca19c388b285f44f574dcff25f993add6d5f02200e050dacd78de955cf552f9158beaac5fa64995f5bf7c8a919a231a39425730c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff47d0ae39a2ce683261d30f45025b7faf667146a980c1213b593c482647d77d20000000006a47304402203f05a035f5d42fbfe97172b431a613110ad733e356ebfd08886fa11bedaf1faf022061c4a3bc3417390910612bae46f5acf8b6e8a5b008d273a52e483a315bfb950b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff46cefa6639796b89c5e8981c42a230d8629cadecfca5dc853c85e782ecafcafa000000006b483045022100bf60fbd4716339bbb42ce150966ad6caf90b14e57f45eb6804756cf8ff36b23a02202f16aaecdb9994f3b683cc7fab45bd0a3f54795c336b5fc224fc51270a7f3f4f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4e5c5b111998d7b90d46130f2ef29f25d48e8649eee14684cf6d46eaad3b7026000000006b483045022100bcdcae99c9289b5fc89d3227daaea8df7d0a0f3a8971d841ebe1ab7a1ecf72e202202ca21447a6b3e96540e32529697d523b7b08c65845d6a13f6b1475de94919bb6412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff489efab51aaeba5cfb24d1484a917a33aff79b7455392ce21a3e642a170341c9010000006b4830450221009535c27b5bbca0db2bcf1a0d0b3b283a2171df53f0d68f1a138888fcc6ddd996022068af19252ac4376cffdbfaacb2e0f0c216deb7e2478b586abe7c2679501eac34412103a47e5dea4ab8d785f4e00994d0faf1a8f384c41e74ed8e4b776fa6ce136ebc42feffffff7eee285c72768622c785561839c699b1a748f58ab418615611c70c9d70440518000000006b483045022100b456847e29f8a648730f0fd34cc7edcfb35daba866ab7d800472beaf2836ce4202207db401f0a5e30efc53c7bf58e57d1dec5874d64768ad9eb4895351cc4be9226f412102291b40a9a927dafeb53cdfc7e722ee5c9dfd6eac2d81331678b9ab405bb25d21feffffff93b0226e9f90d151df423d9ff868513f71f708e715cbcb1b5444f4a0194bc267000000006a47304402205ff244c77726def0e3697a3e546bdf74c7f31479c9d01a7a6f8cd1656482d537022045d78dba8ed4d3777f473736daedbdaca6f5698dd306898d144eb43f96259766412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc784e371e706c6de880fe3033039cae758513a73866241658a21fa6a8a4a8d20000000006b483045022100ec6b35ce6d24889726480d70a31bc0d62800bf7ac49ecf084b98137322606bca0220432d33e2d8b508f26d7d813d18629453c537a4d90f73a104bbf80627f9fe8d62412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa4cab40c510ef0ddb8fc3612af871512805ad7ebed2b60fecbe7b9d0f8eea760000000006a4730440220423ea635717cff512d9262b7c8932c0122ca868251f019ae033101c28771a52302200cd3ae05f2e88d9f64207beb4b715ba480bde9ffdd40ab61a36feff88f2968d54121035530745f3cd4d31532991e460bd2a15e1944e690643f73133a9918edb95da53efeffffff852bf329889cdd85945b23bc6a338562c151ecf16b04414c75afb1cb9ded3370000000006a473044022055cc4dfa48a79b8584a9352be34ab5fe9cae4132d264dd827d14ae06d35ad4090220652a83c93505f8a8527c5bc0479f37da0593595c1bf18c12b8fa0b41a2e37a64412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3235c14d72a55c47d9b996588c7110e27d031013e1f2c77deba6241954059f92000000006b4830450221009acc8d0e06d10b0c764a27613bcef41fc75f910875eae3989a7f8725f81814cd02207146ff66f412910ed993fbda4ad6ed48862a02f366dd88a83856a17e7f96d83e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa0b0aa12e3299ce6c925827b3d5603676949daba619fd9c7bca247d1c265e9a7000000006a47304402202d8cd72290f04063c0ae9bc06d2cae3ac74ef4cb6945c92c3e3ccca210c127ef022030471726cd87ac9d55f3d246095f64ae22b611aa8791922236bbdb19ec273322412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc856c10b1d42360a93cf60fa8127afcac431417ccb7213f649d45482fc7d89e6010000006b483045022100ffaa954e5b86d54ece9bcb9e37895047221828ca381b03266de3d9341599c8f902200ea1c5ed36e893df822c698a474b062d4f93005c32f9d2f0d78ecaf5a56e4fbd4121031a00f43cd99e015c72acace20ac47d887a39ef284f89a5aa09abd968d06f5e9dfeffffff69129065f6f989f1a008813b345e8cbd881a38107b9a0af3a3718437ad6e9cd6010000006a4730440220457d59caf24eb6e10664d06f3e936f6ee31d9d59f1cc4f6f62788f022bce8c1b02202ce7c37ae6832b078c1cb9a055e3ffcf4674081f0738fd9c3eb4465b52bcc9ca412102fea9ae922223f2c68c68d7672b7656885c3e1321d35cc8f5f445179df6f7d27afeffffff8ad3038c3df6f210fa389c57f72d240dd2da53bf172429620e64758a28a82a21000000006a47304402205e0f5cb06f7fd741825c669c87e9db1a433913fb8577adb92b779d3a693b4f080220120648a5f9d2abae83a29cd2c79f5c61b9bc40da8990736ab97ccf6f82c586cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4fda56201530659af45d3f6ad8704693d321f4c92184403e848bf4c3eb1a6a3d000000006b483045022100debfb215f94e9d784e91fe0b9d2541d09a4c7591172fad1441506db4a3590fd102200cce728e344933111c9548162e62872fccac624f6f98d92ccdcf98dbed09ac544121039b8a20c23f32f5b14e76fb29e0baade695810aa7b6dac9e9638a8d13b6ad8221feffffffe7bf81c3288f97cccc60391101a6bdc7654a30dbb693a9bcc8a4b112535d5891000000006b4830450221008110aec39b127143891069590fa0d9e1d8b41bdda70d9807848eba92cb48736b02201bcfdc1a1cedfa4c53efd941482f6157774b2aa80af44e500263be6a3cbcbacb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4c686bfd13c84da78ae379b1cb6974bd3cde55fffef59f28954095903cd2b3b9000000006b4830450221009f76d6838b8fd8bb74f50c67920fda9f28054d093b30fd03b54b3fb888db046f0220307944f3abec07c3570614f418056aeff03c0830173c963bb0b65bd5ef24b4a9412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3f7108134b932ada8356748fecd11ce666f529c25e4aca3c4253f77b3ba6f965010000006a47304402207b93e2500b189b51fbc3a49a191c4b92ac76e32ce86f6f1b9af4afbb3a91fbe002200b5617cf52095bf882a5129f5477f119c9c565dd582a9f19493cf1bdae6527ac41210323ab0930ba40688e66bef6e08f673bd6bcd3df687e4c503387f48c24bffdc93dfeffffff7edff321567843351e47d6d3bc8394e2cace9fe3b72c4dbb152bc54c6abfdd48000000006a4730440220731ab37e71d9c6f63333ba205a318d36e5847706381f571b4b562e5e6f6e403c02200704ca9d9a33843d9a16135f56eced1fd18e227385671a8df5fa41e505e3ba3c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff71294d7e9b11e4e36de589c91122993add9030771328f27215bb55c36ac2750000000006b483045022100d1d3565175e1f529124ebba1bcdf8c1704e753c2f91ddcd1a093b5f5403cd0ed02207420ee9d6082356cba6d8075b4fbf310bd84dc770734a8ab30e74741a779bae8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff423caa98d71896bcc3bd086cc2cdbea476888d19a3f3b9d2554e82e1692cc93000000006a47304402203ddf5c6c5065f03229cdf837d9f8d3d22314834b006e0aba8dacabea206b3b150220417c49c9095372d3dfd954688bcd43fdfd2a121989fde18456a9428b2a8e3c63412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffce3d664bc2eff728a9ea3134bf11d8c7e2207ed508e7879ec7ecee976eaf72c6000000006b483045022100a20e6aaca7df2b142b768d3b1cbf8f783f3d4997d155a32f0e066b4255777c9f02206deb15cf53d6b27a973df9aa7080691e5914538d9e97ec7c6e797ce03333238b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb8f5dcd6f0fb2ad1db921e6f79fcd9fa463165091761f9d8baa23673a0a0645f000000006b483045022100cc2cf5c6c2d4862dfdf65407138684ba45565bd8ec46594ed4586bfa37b715dd022013255b2eb22f5bb93d2afdd07ec4c3b5efe0aa16134b2fd084c6bc720f8cfd5c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7c331f8d0e02777c73a28ae441e12de405bacef5ce967761fb521786d5186b25000000006a47304402202c9dd98c9a72e5a8df4b01f09d18e2826d8b9871db89c5d3b24ffd673facaa0702207523bfcf3ab80790167a2b1159fe268770371fcc7d770995c19eace3181ec8af412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4cd501228a577f0662b802b5b197921268202b8658e4aaab7cf6ecccb93cdaae000000006b483045022100bfac8828df10b7911d341c15a532819c429c7185d8883de19de84e71b97d78730220177603a3572908c90dad865770906b5ad228da7ee5da39503ececf60ac735158412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffdbd64011a7b6fe85385fb207b347f02f5e047b7ffd55bd4192af5ea979e2110b000000006b483045022100d598e2ccdeecfdfea9d5139a49a94fa39414f9e1ecb13d54efeb34c168e58aec02202a59463710905613844f48dc71d316c0cae54ab9e16dd95beb8902e5940024ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb90e762342456c7032806bd546929a38782761e2ee29e7aad37778e1ab6e0282000000006b4830450221008302d38e9eaccaea812c853047931562417a3665b8b9373cf7f63e58180b002602207ac8fddbbd19560a74333ec92fa077d169b4902a41e0431113f8fdb75b304ecf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe15523a831db30cf60f16b15dc338703a64058fa3830c17a4314b4ab824ca943000000006b483045022100c0d85a1f9146e8ef9efaef8ed9b3ed09c55e51b25e189735610da89b6d212360022003a49114e504741befcdb95d52a3dedd1aadef68b7c48f0a4a8c7dddfb4201b5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7893407b6997d973f52a924d03ebdfc639401a138c13e12c2ca365938135f841000000006b48304502210091ec8402cafd1e7eb11b56ac56a994ac79c435893108d0b7c8cfff87c07ba0a602204fd98efddc1b4e21bd3cb81217579a7b9621f9c3c204f2f5800e75ce1c60b19c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff016fa30c4594495726151cbe044ad53de6421e1f28e2366602bd80a3dea98c2f000000006b483045022100a850bf088a08baac1f1f577da8946befe2e6b0354d6a29f636afd39982569a7e022062652d6b75dee145f741d28d6f1870fde9a7d66b994f0d3162abdc42fbf54458412103ffdeec10b52942b0c46d6578998efdc1d64073de579e92e7c5dfa97fdf3ac391feffffffd8659400dae01e9cac6076cb19facc050061f64b16957ad30500503c24294840010000006a4730440220762f7c017672dfc71d487f3730e26d69d0e53902f579ba348095ca164d27b094022076c7e8045ec9fc57af6dd95f35c0ffad2c0ca8f83f112f60fb9851ba4ba15d92412103a2d2d8251728b11fd4afe7b8c73a8442f76dff9bfa424f5cad9b98083936259dfeffffff642ba174ff1ecc14e4f086d70300d487dbaae78bfc684b43557f9b8ad2ca2426000000006a47304402200654032c5760f8b94cc089da51773447f19c1cd2108cab89bb53ccfdb6dbee56022015e277622dea4bd1a7913ff934b2bb2d1b3d75f05285b51690160e1197a258c5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff654d602ce9a224bbce1fb5f9588977fd780591457ef11de271137ca7fd3c3b89000000006a4730440220712877c0dc553096eb0ebf101d1555fda5235db26ad074d2f330163fab63fc7802202c89752dd7645e8a3da7e8af5fb68dc8b177700766b79cf6a35695a0c7c873cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffcc614cc3c1c12c9b8cebba5d78a395f5347a5073211a04e03d55b0a8abf386cd000000006b483045022100f3fa1e305666e2a62afaa11fd37025b25c0bdff8709fe1580406615934228cee02204841a7d96f36d3c183f06e22a58175756c3e9a76c93c7cb4e9945f31ddedc902412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff26b2ed7a5c60815f5b62a5d30af9613e69a26e8aaa429be689baddb562e88aae000000006a473044022047c158e3fe3f40de3f39796dcecb7df3cf344f14009de9826b62a43837f2cdcb0220759d823cc145fd5e8b651a7bcc399544692bbf596189b1fc50bba5f4ca02cdd1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffebb012602f05d2bea0016b8b304f59f610922671560469d80e0e913cd2b302b4000000006b483045022100bd70744c867943bc3bf578e192c8a87a5ed5126aac4acd98efa06ea2483911fa02207377e11ae2d2bbaab00da86ec73c26e596bfcc680c0b8eddc5d44bda650bc299412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff87809cf57be510d02c71276f00544888795f624f33d78b01ba63c87340dadee1000000006a473044022059ee25066b8a2a4fdfc35f14c5cbb7f22ab181fcfa9702d4f3de7aa4d738c7a402206dff315ad1cd2222cd6ac074bf34241fc22db38a57bf089f7e24542323f1766c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8c33b7af2120bb22742f4a5e5fb4ecca7cdf73a33bc8811f3d5d3d1cd9399c21000000006a473044022039657cdf4fcd5a9e81766ba11db495b8be5664612d3b91f8504bea342c4ecbe702206ca4913e5807cd697d30dbc93e0a9d679eb01ee84b687ab0c642e2f3ebde745b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8142c39bf2f91bc685f7c08e40450c90b36dc0a6782a764cded6ba744a591f3a000000006a47304402200232ee94873317eae275cf715f4c3aca25dd0c8db4800946a45cc1d9c45732fa02203d9ce9c9aedc0a3899dd027df32e683438769d66f33ffe52006454614b77821d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff503b9a4c5cab71a66b685d3266002970227d0f4a6b1c65b86603b8c8e683cf14000000006b483045022100900bdc6f705efa56449a65f15a67fc7fbbc102f78e7974ea6ac2849c75d2dfec02203b78de71dad2e3f6ffad2779cb9007217c957c8f5db7abd58fd0537fbabb8c6b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8bed144f5515754d58c273554d25637ec776635033c9ae13bfc94e4b6cecd11d000000006b483045022100becbb21c7937b9b27ea3cdac5f2048ab9ac314de59c3ee2926a5cfb258ce14e902201c8022bf275c1a761e7715b14e15d74526901363ae5f8bf5489d00908dd758eb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbcb7881db3ede1d9275508f97b9f1e0e008811ce540f3b42a921e26f6f065799000000006b483045022100ad84bcd69a85a0d487fd7cbe4d76b95bffa303e76615a4336419fd182eeae4b902206d21e4f592297e87f1af9e19c80fd978914aaf5a2db2cf499b72cabbbe73c831412102958762ff6c8985dc9656afda59e61afc6c0131a5d8f1d86c87c83c9b37f7bd18feffffffb7ffae52888348a77a9851617df104a29366126e01ecc6bf7d209fc8627646ca000000006b483045022100edfd64cf9335d094d5873deb38cda5f4ceda3351df722f1c718993a2dd12c8e302203126b0f9470a4d0867ed4e773518b8ad689ce43a2c9f65a1f297525fc22201dc412103f37089783028c0776f2b8a9d8481ec8d6d0652a31edc03cc274032ae17c63c62feffffff801a88dcf5725d71cc70aee29ec937233f7a059d60e068dea3b7dbc806e0fd54000000006a4730440220448751a749e7cccacab0ae1ad4da948b0e0b5d8e3f41ac2b22c18928e8e67d41022051c107c345c06ea82fe8329a8cf3a96b516fd8750611d8ef438b8545416398ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbb06af741ad8b99821ecc4dfb5b52a0a79b577cf213eb9335e920d13707c8da0000000006a47304402207f9b2802ed1e893168277204b7919ff479efe5c71ad2a255e1738a52bacd758f0220253780485f2e3ee960e058d449c647b147b8f64b49b913e7e9615a6c7114f18e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7827759ce0800e385c440c45ccf6c568a25139aa0f1c80b86f28487ae6a8c0e2000000006a4730440220778fd8ba1dd9f71df55bbe1c3c4185b8da21dda82198546c2a0c30250f4c1d66022040f17a46187d535c6e943c047942f45159a37b2e171db18c657cd24168c22e2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2af935dfaa292af30d0a39a548e81640765b624eb5213d964ebaaa81a3711922000000006a47304402202cd2fd29fa395a5a80893de065c8bbe71e0bfe0e7b2224cfd5684736a086aabc02206720226ba63a3e5d9e2dc67e404625cdf31a7a08da0e8a22717e558f7abc817c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe3e3b78cff7d4798f6e3c8c45d87ac2131913d1328947d6b4ed515b3ab2366bf000000006b483045022100f8769b797386f0bdd662483096f4e0a33c13f6074a4aaba3fd590b9abbca7c2402201eb064869fcd17a59ac028145b08c73b3552544cd7fc62245d1fd1d369ecf765412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffdc319b5c9374a41a08f5f3bd45480a968f651878cde667b3ee3714f72b836be6000000006a4730440220558e65fd916d9c9616a3e0bd41111dba3914867b1ce5d487df4f77feadc0059502203198566c0d58af8551b65f884db98bde161bac140c7a900cd40df97a40c267de412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff69406ab4a28198623b6005bffa68588fea73092364cf2f7a223884c3e0732845000000006b483045022100ca93287feb58daad47c5388067b219e44f8533a214eb8eea9b5313040579773002201716a6ad2de70eff6721ae7950edaf9230420648bb8ec53173c215cbd12246c0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff21e5177112fa1fb5797389490a4f9131600673f139a544050a557fb627b0b360000000006a473044022003240fd71510800910b448c62a03178b4ef62299b17d6d2c06ac8f3293684ff50220637e3ba59fc884a8bd16aa2e884b379d85f38ae4ba049a0365f33644febee6df412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff5488e67a575ab8556c748fc371515b52ff28eb875586eba99fda2b4389e4f96c000000006a47304402202e2ac9c8b619b8e2626895c20f6bdd1a24fa27de017d05d5fa2ce120b3421f25022053ef6f82ccf9a132d40ce566d45f4ec18bf30048d415f6ec1c783cda027b6747412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff03abe81fdd0362f4fa3bae282c2ab1be258882d83392229cea6e36c3f023999c000000006a4730440220352bdfe541e9e1ce428ac4eb4c8ba9391a118b7dbe57b4fe3c4ecd30f228fbff02204a0b78ada1d74a7e7b9ae912e6f445d9ce9050855d9c5ecc7d477d2590a68b18412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff879d7ac96bbdcb9aff885fb27c0f171277a313ef45b8143e04b74d6fa43fd25e000000006946304302203f767d8f64e3c9e5773d94a325f8029d21d1c9a0f470c9288cd99f70d2d90ec2021f50b395f9329ffe64ff8084c1506e904ffc02dfac7f7e15461c3e8a077f604c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffff00dc8aec564568fdd9114502ed1998de08228bfe4edf74d132cfe595c709fb000000006b483045022100f17f8045a627bf96fe09d868109063d8040e3e2df8944e05f9b20a15273d0bdb022059c31e2d849abd57e784f1a3903f49f18c7c5a624545bab98649e8a092e12a10412103ee2a3f78cd4930dac8c030ccc93381ec5eab259c1607360d85d1728fc296dacffeffffff3f25af68c0083801bf09571e1a300d78768df58ec82e2961a374600bcf90bf36010000006b483045022100b58c7dd3fa1f8dc50edc7b5546b8ccef8ffc5c179fee774999c63fa729ae3cef02205eb611cc887e5a62a4e9da33318ce6e216ca353225f452ebca51be1dd10f544941210267f3c9b9bfb6bc5c1f68dd1d18623a9986408202cf232ad1e4089933c83f186bfeffffff6a94e760788c3ee1c9696e5552020afc2a77bfcb3b2223e35744f1b9abc49b25000000006a4730440220097f46c588f37ced4846a45905df1a0ae22709760f8a1bc930a58f5054cbe482022053b418af66d1edcb3887616feb23e5dd4095f29e74ac89853c3b909eb42bac34412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb26042d45f30556ab14a69f8be4ce1ac4a360b8407d7da6dde0983f73123a314000000006b483045022100cf98e22a2854c7088a0572e1edb4e876aa622ed10dc0376806e1432f5dc1eef90220527845f8dd2522fbdf423b4fc34a4792a7f82e04b314e0d83e2425daa2f92115412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe5f0f3bfd4691a43d7488076a0e13ff739c72c6f421d6c0e61a75232ea36d8ac000000006a473044022070c7aaa7d7f050b1b520878e55db3ca491fb33211150e2f620b685cb49d7d885022022d9ede63e3b196a1c33c2d211c1eacf2e2411820ecf5155b5e4244f5dfd9f1d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffffef905cc2f8ca7d7885f06ad865b721f594595528c2b971b3172313cc7df8c34000000006a473044022018cd70c3e62563ea92ea12735e2efb4b905df85e6b290d573051f49c63d07c60022037a537ca3514121d5c2b8753833808a5e0432f1a8f277d91495953c8211ad326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff556c7570226e99590f0844c677068cd133f882c7a720f77f32bac2be39aa7baf000000006b483045022100a01ad9ec8d24fdf01eb203c2887c1413ae56990d4600a18010959f6df43de08d022056f0f0dccb8f772f29a7835d7dc40f242348805005b5f80ae8f2fbdb600ab2ca412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff52bec1a85abc7d806dfc9c39427b7cbab7be3aeca8ee99959c84b68cc05ca96b000000006b483045022100cdd770159d56ac518ecb0dc916df0da06eed536e540582680f742389f53fa4be022012d372e2c04176bcb82b91b02ea23c9c1464baef7d1dda66066bf84c402c0012412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3b2d0442ce89e456c2cfc586906116d280fce17bc310ed957d03b35c61e9eb41000000006a473044022001dc7db378891c1c5bf07a09d14fcc6675965976e2e3e762786b1b1e0f4a4bb702206db6f284dec835823fb516fad89543edd3bd7af3ed33940fa296939fadb41ba841210393ae47ec2e844378cda3630abe12082401f2e0f98d016dde2b152b42e335630dfeffffffc3804827d4f39c54d961dfe79e25325f59b5499ea25b49bfe7ac99bd7c7435a1000000006a4730440220290a5055313d68f9461ce830f8a7395022d2d55abf28f6b4bd665693b4a13730022035d4cc2a6676ed842027dd4f21d31dd5a956f4b1f5cf771b866cc0d4a6400df0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffd610149123afe34fa647cb0aee336cb903961bee6653b8eefc7f49bb015e0990000000006a47304402201fd6be6d72ae75b61a624c13476b538ec2f9e5146f3074c879af57ecfbe1679702200ab10ae612e7fe0f76fe943c1f6a02262008407f86782c1536e92e3bad77d3db412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff205fab854da34166e1d16d36ab90b1e825440f6c9067ef35d34c41c5e569b144000000006b483045022100a4132f408b5299dfed6153b7a331f9fe866f1b042e4263bf7574ea0964c450a202203d99cf8dc9a9194269bce400185a4f86f5d35b5be83f6dbc3166b600392f1b00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8ead5e6ad78ed4926b83bc4a479d4dc5b2dbd2753af5636044cb008f4c6df1f7000000006b483045022100bbcc2e2d77458abc30898cddc7eda060b23a62f0a53b81c3db47f284cd7b29cf0220705328a29bd30792a7f5a704fd74b771c3c8a099265f5e7c9d70046da5b03ff4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff2361f9f2ba5ff1e66349c365e1c0cd9c6cb80ab4f666e9f4777fc188a405202010000006b483045022100d2f40145c4b9a17b3582aabdf7d9ac2d47546b3eea5350c4e2ec1e9c2466343d02203354ce620aa056a749de847f867c49dd121579c9fc50bd6258bff7cfb173c5f24121035bf755e8b075665a85155618f6e9022196a09c486415587dd3af0d25b76e9c27feffffffc8f56b2dc9536ae2c0e11b2062edda6cb33b93284ce7bd8c6531591ae82f0074000000006b483045022100cf8c593dec0724644d034f17ccde99feaf0416334219f158f884badf500fc93e022035af1b68574e88ef15e1c05c1b36638401613a31aa7096d97efba6df62695706412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff95831f16b9696da7fe12787860ca161c12566d110c9262097434a7e0674d6b49000000006b483045022100a669e8918ba68754b84d584f38afdd34be387773449784a6c61ef3f33d0fd99e02204d007ef31f5a3a7c412ac3d2660633fcef137964ef2ff6269c41e933896d918b41210383b6491fd80e1411675d7c8eda9b756c30a814b45fa565b7ac24d7be9dedcaaafeffffff1e1184fc54a53f94ee4d56313349f586effea0bf553bbd0cccefe86c8d606f4a000000006b483045022100fc35ed21833c3ea3ff5f832ef02236a08ded0999ea367aa6eaaff364ecac3e5002206e291d7c4fca0485dd8ea22519544ac632909d706741710a6e5f0d472c0b0656412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4864e36057e4fe2ece01c3b463c06b56a86e3c341aa0e203097cb09c53a2cfa9000000006a4730440220485937c55c67c8eb46b94523cb06f9572ffb55094536d8b1a458c76b67dec75b02204e5007f610e491d043a412696d4fd769bb2f5d8c3e8b3a59e6ec3bb598f775a7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffeed8d2da2afa9b9823aa74a344f6eda5d4b80e5de83caf8455b08c8aac6c4662000000006b483045022100b430528ddfca4431cf5cec08964f7325c036fdee55edc0ea0181d34ed72469bc022074b75bfa66dd4a87fab93da0f2f0def65b785fb0b51fe07355799cbd8b30c39a41210316d35753d58318c06d0faadcb723563316847ae06019984f42f2c75deaf3727dfeffffff4317e8c939993e123310aa4d84dfa4a29ba8dcc0b4c222384ded077936279955000000006b483045022100c6ccc3891fa3924c7b1e69b855628230c48d85d1e1331f037823ab7c5928610c0220050c9c0e078f34ced537e88f95289863a663b28488880f6ada3f1dbbcb1743a1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff85aed5e452015314973015efa03f0bd2c79d57d976ce3f3ce14498b294fd5b7b000000006a4730440220168f31f413d65ce64bccb62390490dae2e4a00f98c2c44bd4fd689cd942da8b1022006f1b2aa4fae9587c688e8b7ca5c07db3b3c3afd6961f9f843099ed30b583369412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0286800000000000001976a9149a262d0621819c8c17d34a7feca1b39b39157af988acceb18bca1a0000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac26550900"},{"txid":"99300f90ced7d053b3b24ef3a8fdb5774418e616f07971366a63b9938944ab2d","version":2,"lockTime":609135,"vin":[{"txid":"f0202389fab209e6975199ec2d8abf76fd4cea5d7d441ea0938ff47a35366c45","sequence":4294967294,"n":0,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250016811","hex":"473044022001b8ba5dbc580e3bf4419b65892f15423e8b0e48d52479fd0317fe4c03ede0a002204013a50c3914aeb7f59183f9e44c880bc94fe9c23045a6311ae4b07da3c2d209412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"}],"vout":[{"value":"1000000000","n":0,"spent":true,"hex":"76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac","addresses":["bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7"],"isAddress":true},{"value":"250016585","n":1,"spent":true,"hex":"76a9146932df2f990838523783075db0b985b9bd2330b088ac","addresses":["bitcoincash:qp5n9he0nyyrs53hsvr4mv9eskum6geskqthlx9n4d"],"isAddress":true}],"blockHash":"000000000000000002132a5e60d7b9de0524eeffb36fc91972a7d68afdf17b65","blockHeight":611545,"confirmations":24555,"blockTime":1575274423,"value":"1250016585","valueIn":"1250016811","fees":"226","hex":"0200000001456c36357af48f93a01e447d5dea4cfd76bf8a2dec995197e609b2fa892320f0000000006a473044022001b8ba5dbc580e3bf4419b65892f15423e8b0e48d52479fd0317fe4c03ede0a002204013a50c3914aeb7f59183f9e44c880bc94fe9c23045a6311ae4b07da3c2d209412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0200ca9a3b000000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac49f3e60e000000001976a9146932df2f990838523783075db0b985b9bd2330b088ac6f4b0900"},{"txid":"637d7e47d7de2d9da6aa081dd8534ea3f907e8bfcbbaf46dd528f15a71897ab8","version":2,"lockTime":609135,"vin":[{"txid":"62b7b059c7970576e7105dba731a668cc56d8df6e0a683caf69ca6f0b0443a69","sequence":4294967294,"n":0,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250018032","hex":"483045022100f2a03dcbea54b74d1a9db4a97e9e4fac3618f7b90eacefc8bb364d6fe3001e99022075b6ad6ac445dceab967fef530bfeafbe7b0b66bb484ceab492a857354f631fd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"}],"vout":[{"value":"1000000000","n":0,"spent":true,"hex":"76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac","addresses":["bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7"],"isAddress":true},{"value":"250017806","n":1,"spent":true,"hex":"76a914b27503ce07faeb2e71e1b937d871c1e5abc33ce188ac","addresses":["bitcoincash:qze82q7wqlawktn3uxun0kr3c8j6hseuuyz7t4eh7x"],"isAddress":true}],"blockHash":"000000000000000002132a5e60d7b9de0524eeffb36fc91972a7d68afdf17b65","blockHeight":611545,"confirmations":24555,"blockTime":1575274423,"value":"1250017806","valueIn":"1250018032","fees":"226","hex":"0200000001693a44b0f0a69cf6ca83a6e0f68d6dc58c661a73ba5d10e7760597c759b0b762000000006b483045022100f2a03dcbea54b74d1a9db4a97e9e4fac3618f7b90eacefc8bb364d6fe3001e99022075b6ad6ac445dceab967fef530bfeafbe7b0b66bb484ceab492a857354f631fd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0200ca9a3b000000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac0ef8e60e000000001976a914b27503ce07faeb2e71e1b937d871c1e5abc33ce188ac6f4b0900"},{"txid":"fbd9cfbe97c857b2a03b431d8e28faa324ccf4122b769701d3cd013ffa197fe3","version":2,"lockTime":598145,"vin":[{"txid":"58f0bd01660fe9c835929b684134319aae65d11564bfc00071b5457463554d9d","sequence":4294967294,"n":0,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1251118684","hex":"483045022100eee97aebf4fec547551a14929ca063d7d6a679044470e0168f4205396cff4410022047aa3e87d09229e6530ce1545729c2954fda1c7cd037464ec366552098879f00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"5d2c2e1e37a2aa835c757869c28e5b81e51c2caeacf913955a960ffe7a26d3b2","sequence":4294967294,"n":1,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250470637","hex":"483045022100e9c68ab8bbf083eb282c449b7eb697b8d7e86d925447c49927cd0a68267c63cb0220526670fc9ca852ae8da916e3a7fd5afcb57731502014f25365bd30ddf1ed98e1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"67192afdc712d878a5cfb7a2318bcbccec4ad4bf6f6b45009719d341a383f045","sequence":4294967294,"n":2,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250720617","hex":"483045022100f65bd8daf7c1dcfa07190e4262058e30aa09a2f05e64c36988ffdb0114babc5902205d7dd1c0432c0d0f87965c1de3ae43313fc8e23fd03dea69de98e9b21049beda412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"8b798be5bcec847ca23f0a0cc567542187eb70a11db721e7fe2954c48b83a6ea","sequence":4294967294,"n":3,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250575364","hex":"47304402201b9827502c66a65e5d218abf666dbc6857164d64753ba4dcd211ad12dfe42ea202206b48300b4ed1d6501201732b70ad22172c12d2a971fb5253caa86c94b43c482a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"9dd2f09a34aad4c512d4d26a082d37866ab6b1061d2a66cd33e7681b6c9ee038","sequence":4294967294,"n":4,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1251194095","hex":"483045022100ba98ff0f91e60be7d22516d2bd101599ddfd8a901daa4ddb3114e6d2b1b595fc02204cfde2b51fbeff3548744118518889825597882ffc6d7a4284907adb041f9dba412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"a96814c561344ea7a19b57836dfa62e0c86a49e10087436fbce4336031c26d95","sequence":4294967294,"n":5,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250008334","hex":"483045022100e3b2fe47a20658f8e1eeff6d27467ad7dd1523f4269a9a61817144ca885af74a02200d265761767b129aebdd39a7958a79994204b2ae40b08a85f08bba21dc91223a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"cac688b6f4345668588abcdf9d89b5541c552855d9a8f2f4918df53d17ab6218","sequence":4294967294,"n":6,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250451164","hex":"48304502210091e7b82967a71a2f98b14080444868dbc98b1bd77d15158fbc0b40591c5cd85f022005ed9e017b417a261f9f33dec1845858f19c210540ae4b6c8f67845c24bf135b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"e499e4f058684ef3569ee0bd0306404c4f8a047fe34689f36909e5c83dd976d7","sequence":4294967294,"n":7,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1252046891","hex":"47304402207058f613922e647c29f9d4508cd4b1b834d2c51972d98c44c80e79ac90747b4102201b0aa0081a8b045b1ce01aa0b7a34ec138015aac9c0961891be043975887dc9e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"}],"vout":[{"value":"6584524","n":0,"spent":true,"hex":"76a914ed64792c4a5cbc13e7ada63de24d004a928a05a788ac","addresses":["bitcoincash:qrkkg7fvffwtcyl84knrmcjdqp9f9zs95uecncksuh"],"isAddress":true},{"value":"10000000000","n":1,"spent":true,"hex":"76a9149a31ab0abf1974a97c7da6fb6d0921710db6bc7c88ac","addresses":["bitcoincash:qzdrr2c2huvhf2tu0kn0kmgfy9csmd4u0szcc8tvkl"],"isAddress":true}],"blockHash":"00000000000000000162f226fdfaa36a83255640d78976086153bb3b96cbc3c9","blockHeight":598147,"confirmations":37953,"blockTime":1567227161,"value":"10006584524","valueIn":"10006585786","fees":"1262","hex":"02000000089d4d55637445b57100c0bf6415d165ae9a313441689b9235c8e90f6601bdf058000000006b483045022100eee97aebf4fec547551a14929ca063d7d6a679044470e0168f4205396cff4410022047aa3e87d09229e6530ce1545729c2954fda1c7cd037464ec366552098879f00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb2d3267afe0f965a9513f9acae2c1ce5815b8ec26978755c83aaa2371e2e2c5d000000006b483045022100e9c68ab8bbf083eb282c449b7eb697b8d7e86d925447c49927cd0a68267c63cb0220526670fc9ca852ae8da916e3a7fd5afcb57731502014f25365bd30ddf1ed98e1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff45f083a341d3199700456b6fbfd44aeccccb8b31a2b7cfa578d812c7fd2a1967000000006b483045022100f65bd8daf7c1dcfa07190e4262058e30aa09a2f05e64c36988ffdb0114babc5902205d7dd1c0432c0d0f87965c1de3ae43313fc8e23fd03dea69de98e9b21049beda412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffeaa6838bc45429fee721b71da170eb87215467c50c0a3fa27c84ecbce58b798b000000006a47304402201b9827502c66a65e5d218abf666dbc6857164d64753ba4dcd211ad12dfe42ea202206b48300b4ed1d6501201732b70ad22172c12d2a971fb5253caa86c94b43c482a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff38e09e6c1b68e733cd662a1d06b1b66a86372d086ad2d412c5d4aa349af0d29d000000006b483045022100ba98ff0f91e60be7d22516d2bd101599ddfd8a901daa4ddb3114e6d2b1b595fc02204cfde2b51fbeff3548744118518889825597882ffc6d7a4284907adb041f9dba412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff956dc2316033e4bc6f438700e1496ac8e062fa6d83579ba1a74e3461c51468a9000000006b483045022100e3b2fe47a20658f8e1eeff6d27467ad7dd1523f4269a9a61817144ca885af74a02200d265761767b129aebdd39a7958a79994204b2ae40b08a85f08bba21dc91223a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff1862ab173df58d91f4f2a8d95528551c54b5899ddfbc8a58685634f4b688c6ca000000006b48304502210091e7b82967a71a2f98b14080444868dbc98b1bd77d15158fbc0b40591c5cd85f022005ed9e017b417a261f9f33dec1845858f19c210540ae4b6c8f67845c24bf135b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffd776d93dc8e50969f38946e37f048a4f4c400603bde09e56f34e6858f0e499e4000000006a47304402207058f613922e647c29f9d4508cd4b1b834d2c51972d98c44c80e79ac90747b4102201b0aa0081a8b045b1ce01aa0b7a34ec138015aac9c0961891be043975887dc9e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff02cc786400000000001976a914ed64792c4a5cbc13e7ada63de24d004a928a05a788ac00e40b54020000001976a9149a31ab0abf1974a97c7da6fb6d0921710db6bc7c88ac81200900"},{"txid":"e0edb9635d9174d59934abf31cfd54da916423949b5d2dcdbb1f8f5e6723dca6","version":2,"lockTime":598089,"vin":[{"txid":"04f378ab91b96625368f786f7a0452773e36a3e7e6732a737a68f66348763c3a","sequence":4294967294,"n":0,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250313984","hex":"4830450221008a92cb387e315443cd96cd2add24816d0bb8f671aae99e52cd58654a60b0554f022007bdbbdd2565782c6987bda716a8f0eb4d12a8e28b1332a418b25d031253ca36412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"42fde1dcb31533906c694dcfd9141f7c099c8ba58176fddc9b6532dc9afc2ea6","sequence":4294967294,"n":1,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250272096","hex":"47304402207b9f6131318c0fdc3dab08e3a6c6a00279714058fc19ed056674ef28a5cf8d240220791bff750505d7febe7e0bc702508925be6e03344056c91bb904d4170dfff67f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"606f9f8c03c66824612cfd2aca07d75f2f063dc7b5b7989298a4a4dbdd156314","sequence":4294967294,"n":2,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250333923","hex":"483045022100cd449fcf73e96bb49571f35f41a23765f4c473a1aebdeb25ea7c10718544ff6802206069e40e484e2ee6e7fe626698dc82d9b0839e80461ed940131d55bb5c7d1dc1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"80370d88df2f654a47f9c278499ae8cd4e591e03dbb45dd205b14939cd771844","sequence":4294967294,"n":3,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250308273","hex":"47304402206629f28dfb75786ac40f3c93957f2658b823b682037ee61fe6ad5e223f0ef962022073975b7cbfe40f9749ba96b097aa7126d26aa9c7623b2c640f707b20e9a86c99412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"a24c25d181abdb21e408b764e7201b090bdc35b653d121717f132a19423800b3","sequence":4294967294,"n":4,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250358384","hex":"47304402206abb92b77747fd651b6d44ad2200d787fbd47f4ae64301295174522c5308bad1022033b86a6734e68c4f553b4e83dec37e722ca1c62ae2062bc52c7e23a1a0104985412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"a5fa2ae52bb352a42588a97b98a294386c777c86dcaf5f708f3656bc844e9c84","sequence":4294967294,"n":5,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250329832","hex":"483045022100aa7c5cdab10928dceb54ae9e57de784b33a2a6059353760ec0a5a6fbbedcd1b302202d1241bfd163f8085a55ce3ccdacbe9ef9c785d4ef821bd26d81c0d12cccca2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"a7a24f2a96fdcb3e58f11c6e288aca7fe44d611769226bceebc94de70fb7c372","sequence":4294967294,"n":6,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250416002","hex":"47304402207701d283a3d166f92b45f58c739921ba08ce9ae367a80b7f4f8d2224e628f46002206e7d08a6f17edda81c182930df7d8272a3c8b821246ec71def6911778382f7f8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"},{"txid":"f84ba6248b511a24cf393e9c46ef0d87bf141d4a6a98cfa696da9d0ccc23a8c3","sequence":4294967294,"n":7,"addresses":["bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme"],"isAddress":true,"value":"1250012299","hex":"483045022100853a8d9536e224198b5fe594cd76427a299531335fd085000efd91133c4940a6022033af175997096234143c07493c8611c1ab5be145d2c8c60a3d762a2743d1a20e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806"}],"vout":[{"value":"2343531","n":0,"spent":true,"hex":"76a9145e0a0344a13ededc2e256b7de017dc50fea0985388ac","addresses":["bitcoincash:qp0q5q6y5yldahpwy44hmcqhm3g0agyc2vwxyyqf3r"],"isAddress":true},{"value":"10000000000","n":1,"spent":true,"hex":"76a9149a31ab0abf1974a97c7da6fb6d0921710db6bc7c88ac","addresses":["bitcoincash:qzdrr2c2huvhf2tu0kn0kmgfy9csmd4u0szcc8tvkl"],"isAddress":true}],"blockHash":"00000000000000000162f226fdfaa36a83255640d78976086153bb3b96cbc3c9","blockHeight":598147,"confirmations":37953,"blockTime":1567227161,"value":"10002343531","valueIn":"10002344793","fees":"1262","hex":"02000000083a3c764863f6687a732a73e6e7a3363e7752047a6f788f362566b991ab78f304000000006b4830450221008a92cb387e315443cd96cd2add24816d0bb8f671aae99e52cd58654a60b0554f022007bdbbdd2565782c6987bda716a8f0eb4d12a8e28b1332a418b25d031253ca36412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa62efc9adc32659bdcfd7681a58b9c097c1f14d9cf4d696c903315b3dce1fd42000000006a47304402207b9f6131318c0fdc3dab08e3a6c6a00279714058fc19ed056674ef28a5cf8d240220791bff750505d7febe7e0bc702508925be6e03344056c91bb904d4170dfff67f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff146315dddba4a4989298b7b5c73d062f5fd707ca2afd2c612468c6038c9f6f60000000006b483045022100cd449fcf73e96bb49571f35f41a23765f4c473a1aebdeb25ea7c10718544ff6802206069e40e484e2ee6e7fe626698dc82d9b0839e80461ed940131d55bb5c7d1dc1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff441877cd3949b105d25db4db031e594ecde89a4978c2f9474a652fdf880d3780000000006a47304402206629f28dfb75786ac40f3c93957f2658b823b682037ee61fe6ad5e223f0ef962022073975b7cbfe40f9749ba96b097aa7126d26aa9c7623b2c640f707b20e9a86c99412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb3003842192a137f7121d153b635dc0b091b20e764b708e421dbab81d1254ca2000000006a47304402206abb92b77747fd651b6d44ad2200d787fbd47f4ae64301295174522c5308bad1022033b86a6734e68c4f553b4e83dec37e722ca1c62ae2062bc52c7e23a1a0104985412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff849c4e84bc56368f705fafdc867c776c3894a2987ba98825a452b32be52afaa5000000006b483045022100aa7c5cdab10928dceb54ae9e57de784b33a2a6059353760ec0a5a6fbbedcd1b302202d1241bfd163f8085a55ce3ccdacbe9ef9c785d4ef821bd26d81c0d12cccca2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff72c3b70fe74dc9ebce6b226917614de47fca8a286e1cf1583ecbfd962a4fa2a7000000006a47304402207701d283a3d166f92b45f58c739921ba08ce9ae367a80b7f4f8d2224e628f46002206e7d08a6f17edda81c182930df7d8272a3c8b821246ec71def6911778382f7f8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc3a823cc0c9dda96a6cf986a4a1d14bf870def469c3e39cf241a518b24a64bf8000000006b483045022100853a8d9536e224198b5fe594cd76427a299531335fd085000efd91133c4940a6022033af175997096234143c07493c8611c1ab5be145d2c8c60a3d762a2743d1a20e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff026bc22300000000001976a9145e0a0344a13ededc2e256b7de017dc50fea0985388ac00e40b54020000001976a9149a31ab0abf1974a97c7da6fb6d0921710db6bc7c88ac49200900"}]} diff --git a/mock/ext-api-data/bitcoincash-api_v2_xpub_xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX__details_txs.json b/mock/ext-api-data/bitcoincash-api_v2_xpub_xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX__details_txs.json new file mode 100644 index 000000000..35b323e6b --- /dev/null +++ b/mock/ext-api-data/bitcoincash-api_v2_xpub_xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX__details_txs.json @@ -0,0 +1,165 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX", + "balance": "177672", + "totalReceived": "13221795", + "totalSent": "13044123", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 72, + "transactions": [ + { + "txid": "269d428f01fbe49cd6d2c2ca5e6e2f0ff68aece905313932156078d4341d347a", + "version": 1, + "vin": [ + { + "txid": "5536327a38fddb32a92a98582aca4e85b4e50f40b9d3c03db360eaca7b512f97", + "n": 0, + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true, + "value": "188124", + "hex": "473044022057e811d95dfce16c7f1d1da574ab4ca1bf883359da34a1e7a380f5045fcffc960220149c357343f0172301f06b914a2844d3755a3e990a236ae33f71afed52f0849d41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" + } + ], + "vout": [ + { + "value": "10000", + "n": 0, + "hex": "76a9147222fa3e0a256cc45823a641aa4060e66718276288ac", + "addresses": [ + "bitcoincash:qpez9737pgjke3zcywnyr2jqvrnxwxp8vgu3nnxf6x" + ], + "isAddress": true + }, + { + "value": "177672", + "n": 1, + "hex": "76a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac", + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000000e0846c675bda2ea268eaa290287aef83f8877c40f07743", + "blockHeight": 620315, + "confirmations": 7640, + "blockTime": 1580517507, + "value": "187672", + "valueIn": "188124", + "fees": "452", + "hex": "0100000001972f517bcaea60b33dc0d3b9400fe5b4854eca2a58982aa932dbfd387a323655000000006a473044022057e811d95dfce16c7f1d1da574ab4ca1bf883359da34a1e7a380f5045fcffc960220149c357343f0172301f06b914a2844d3755a3e990a236ae33f71afed52f0849d41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5000000000210270000000000001976a9147222fa3e0a256cc45823a641aa4060e66718276288ac08b60200000000001976a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac00000000" + }, + { + "txid": "5536327a38fddb32a92a98582aca4e85b4e50f40b9d3c03db360eaca7b512f97", + "version": 1, + "vin": [ + { + "txid": "feac34105f3f0bd442f75acaff6b2e840b9e2c0e32e897393d9d0fe47fe76ba1", + "vout": 1, + "n": 0, + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true, + "value": "38804", + "hex": "483045022100dbbf18561baf7fdb46c21d27801594209f2067f1d7735e245c56001c4e462d3c0220016e052ebbcf350bd64a257f7cc52ef23730fe50b24355d098f87c528fcd839641210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" + }, + { + "txid": "01b8958ff2a939534269d05af5ac747238eb3a8c91b2a564107af20e4de55680", + "n": 1, + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true, + "value": "150000", + "hex": "47304402202100334789951706405faa9ddc191702b88d9438d5a461d1f008a9bd097bd9b0022062cd93003ad63bfbb16386b90e619c2b32d9caef5229d8943c11309f26b6c19f41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" + } + ], + "vout": [ + { + "value": "188124", + "n": 0, + "spent": true, + "hex": "76a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac", + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000028351f97cd867acbba39b5a81137ce35a1ac18444aaa76", + "blockHeight": 619773, + "confirmations": 8182, + "blockTime": 1580201823, + "value": "188124", + "valueIn": "188804", + "fees": "680", + "hex": "0100000002a16be77fe40f9d3d3997e8320e2c9e0b842e6bffca5af742d40b3f5f1034acfe010000006b483045022100dbbf18561baf7fdb46c21d27801594209f2067f1d7735e245c56001c4e462d3c0220016e052ebbcf350bd64a257f7cc52ef23730fe50b24355d098f87c528fcd839641210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5000000008056e54d0ef27a1064a5b2918c3aeb387274acf55ad069425339a9f28f95b801000000006a47304402202100334789951706405faa9ddc191702b88d9438d5a461d1f008a9bd097bd9b0022062cd93003ad63bfbb16386b90e619c2b32d9caef5229d8943c11309f26b6c19f41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd50000000001dcde0200000000001976a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac00000000" + }, + { + "txid": "feac34105f3f0bd442f75acaff6b2e840b9e2c0e32e897393d9d0fe47fe76ba1", + "version": 1, + "vin": [ + { + "txid": "6f2d6fb46039f192f82cfd9bc85dcf0575fdf5eda9b726643314be883c8c0559", + "vout": 1, + "n": 0, + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true, + "value": "49256", + "hex": "47304402207df4bd44f74e9a077b84f547b29c595e808bfb3ebc23e070e975905e2012044c02206fa66e30f9afe063c5a5c30d0bb20c6d0eece782a9b6211676180c25d745e98c41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" + } + ], + "vout": [ + { + "value": "10000", + "n": 0, + "spent": true, + "hex": "76a914045891bcbb214544c47a8dbc75350584d8042bc288ac", + "addresses": [ + "bitcoincash:qqz93yduhvs523xy02xmcaf4qkzdspptcgq4dscr8c" + ], + "isAddress": true + }, + { + "value": "38804", + "n": 1, + "spent": true, + "hex": "76a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac", + "addresses": [ + "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000015997ed69ac8b1e1d19c006bca7fb08faf3442890b2fed5", + "blockHeight": 619764, + "confirmations": 8191, + "blockTime": 1580198433, + "value": "48804", + "valueIn": "49256", + "fees": "452", + "hex": "010000000159058c3c88be14336426b7a9edf5fd7505cf5dc89bfd2cf892f13960b46f2d6f010000006a47304402207df4bd44f74e9a077b84f547b29c595e808bfb3ebc23e070e975905e2012044c02206fa66e30f9afe063c5a5c30d0bb20c6d0eece782a9b6211676180c25d745e98c41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5000000000210270000000000001976a914045891bcbb214544c47a8dbc75350584d8042bc288ac94970000000000001976a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac00000000" + } + ], + "usedTokens": 71, + "tokens": [ + { + "type": "XPUBAddress", + "name": "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25", + "path": "m/44'/145'/0'/0/0", + "transfers": 11, + "decimals": 8, + "balance": "177672", + "totalReceived": "850002", + "totalSent": "672330" + } + ] +} diff --git a/mock/ext-api-data/callisto-api_tokens__address_0xc3d5b69f65027ddf48f894e6e90121293a2f6615.json b/mock/ext-api-data/callisto-api_tokens__address_0xc3d5b69f65027ddf48f894e6e90121293a2f6615.json new file mode 100644 index 000000000..e87b48373 --- /dev/null +++ b/mock/ext-api-data/callisto-api_tokens__address_0xc3d5b69f65027ddf48f894e6e90121293a2f6615.json @@ -0,0 +1 @@ +{"total":1,"docs":[{"address":"0xc3d5B69F65027dDF48f894E6e90121293a2F6615","name":"The Hitchhikers Guide to the Galaxy","decimals":18,"symbol":"H2G2"}]} \ No newline at end of file diff --git a/mock/ext-api-data/callisto-api_transactions__address_0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7.json b/mock/ext-api-data/callisto-api_transactions__address_0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7.json new file mode 100644 index 000000000..6a10f16b3 --- /dev/null +++ b/mock/ext-api-data/callisto-api_transactions__address_0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7.json @@ -0,0 +1 @@ +{"docs":[{"operations":[],"contract":null,"_id":"0x82b5678e0ba3b46b0102d5ff433a9f115eaf91402d613ffbca0dd5338a51c44f","blockNumber":5035151,"time":1589316023,"nonce":1723,"from":"0xbb120a8195ebD3EA66C1C6dfF45c18D38d786E06","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"129028387687000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x82b5678e0ba3b46b0102d5ff433a9f115eaf91402d613ffbca0dd5338a51c44f","timeStamp":"1589316023"},{"operations":[],"contract":null,"_id":"0x90b487c9db0efd161f8e1a88150002cc5cf9f8b9e697aaf55495d5fa69d80a71","blockNumber":5035135,"time":1589315810,"nonce":276,"from":"0xe91406762704Cdbf495f3bdE76cD400C970d2aDE","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"342351173250000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x90b487c9db0efd161f8e1a88150002cc5cf9f8b9e697aaf55495d5fa69d80a71","timeStamp":"1589315810"},{"operations":[],"contract":null,"_id":"0x8e64dcd6de7e37596d51af0583ec6dc2f2638d9f8e23166962e9bdb4a8866352","blockNumber":5035134,"time":1589315799,"nonce":2914,"from":"0xCd82593B48E9a58c9b09ee6C3dED7C3036835871","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"231388157710000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x8e64dcd6de7e37596d51af0583ec6dc2f2638d9f8e23166962e9bdb4a8866352","timeStamp":"1589315799"},{"operations":[],"contract":null,"_id":"0xab22889ab91804259cf0495a79b13e85f137c64303653c5b3b244410b5924ca3","blockNumber":5035134,"time":1589315799,"nonce":4358,"from":"0xCDAe1A9880Fcc52733b087c2a415e294371F009e","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"153244647883000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0xab22889ab91804259cf0495a79b13e85f137c64303653c5b3b244410b5924ca3","timeStamp":"1589315799"},{"operations":[],"contract":null,"_id":"0x54b3afa576a7f7eb7d2d60903e70d1768012dfe213b11ced6ea07f3ccf886c75","blockNumber":5035134,"time":1589315799,"nonce":5051,"from":"0x1c48A9E67AFA9Ddf2DEDA4139D60030d1B999D4A","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"378400830789000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x54b3afa576a7f7eb7d2d60903e70d1768012dfe213b11ced6ea07f3ccf886c75","timeStamp":"1589315799"},{"operations":[],"contract":null,"_id":"0xae126b8e6ab2717537f0d54849c6d4ba52f1ca1832ebf3fce270589459e9a4cf","blockNumber":5035133,"time":1589315778,"nonce":2048,"from":"0x5e641A17913fdE89c4CE07aFf26411B10aB784DB","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"111733740240000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0xae126b8e6ab2717537f0d54849c6d4ba52f1ca1832ebf3fce270589459e9a4cf","timeStamp":"1589315778"},{"operations":[],"contract":null,"_id":"0xc3915ee14aea901db1500117ba949250c72a491506da8d604e052ae231911646","blockNumber":5035133,"time":1589315778,"nonce":3836,"from":"0x2D926778faa368EBAF115C7Cd2a9789A66c65C06","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"169969278070000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0xc3915ee14aea901db1500117ba949250c72a491506da8d604e052ae231911646","timeStamp":"1589315778"},{"operations":[],"contract":null,"_id":"0xb5a4b98bf365e2fced0de8e9628631d1b3833426da20db7ccb7a36d41d00a1d7","blockNumber":5035133,"time":1589315778,"nonce":2975,"from":"0xBabb1E29027edde95ac20cd1d2938e9c579bAa65","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"207855558241000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0xb5a4b98bf365e2fced0de8e9628631d1b3833426da20db7ccb7a36d41d00a1d7","timeStamp":"1589315778"},{"operations":[],"contract":null,"_id":"0x881b0f9a3774f500cf0587e6a4933a70945311478545607d566cdb4299909e08","blockNumber":5035133,"time":1589315778,"nonce":3358,"from":"0xE0bfc2658C7b1b297327a4BCf4C41ae1e6aD6f7b","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"131733221089000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x881b0f9a3774f500cf0587e6a4933a70945311478545607d566cdb4299909e08","timeStamp":"1589315778"},{"operations":[],"contract":null,"_id":"0x70196354cfd0ec5e228cb1ac677de3f416179ba43e1c12cb890f8d0185e8a88a","blockNumber":5035133,"time":1589315778,"nonce":5402,"from":"0x1434f888964A9BB48ce1499dDC07e62dB3696098","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"532374455895000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x70196354cfd0ec5e228cb1ac677de3f416179ba43e1c12cb890f8d0185e8a88a","timeStamp":"1589315778"},{"operations":[],"contract":null,"_id":"0x02ffc6e44d59e0af56c8fbd00f4ab3b5f6894731f2c17f140933fa2dc3c28e15","blockNumber":5035133,"time":1589315778,"nonce":336,"from":"0xab5F56365c2C1CAc4cC880cc99F9E13834B49116","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"183175717108000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x02ffc6e44d59e0af56c8fbd00f4ab3b5f6894731f2c17f140933fa2dc3c28e15","timeStamp":"1589315778"},{"operations":[],"contract":null,"_id":"0x5bfab15fa70c0db470bd3a9be14eafdfd09ff54d73649ed8878135d35b0b9707","blockNumber":5035131,"time":1589315758,"nonce":3108,"from":"0xB346eeBdAd639777DD49773339CA64369D11b354","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"140432086672000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x5bfab15fa70c0db470bd3a9be14eafdfd09ff54d73649ed8878135d35b0b9707","timeStamp":"1589315758"},{"operations":[],"contract":null,"_id":"0xda1351efecec883529d10f180436405d711e2ba048508a3f91fbdcc6ea8a7694","blockNumber":5035128,"time":1589315724,"nonce":2862,"from":"0xd3324d82bce0AD0957AFe71Ea20200A7Cf9B271f","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"168228497950000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0xda1351efecec883529d10f180436405d711e2ba048508a3f91fbdcc6ea8a7694","timeStamp":"1589315724"},{"operations":[],"contract":null,"_id":"0x26428836a77ccd7693ecd8cb1758ca526f5dcc7c4ad87fcb79f1bd9053a3b4eb","blockNumber":5035128,"time":1589315724,"nonce":5138,"from":"0xa60ca31a47F35471D5679a19E8f8c873f6373A4C","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"141750177027000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x26428836a77ccd7693ecd8cb1758ca526f5dcc7c4ad87fcb79f1bd9053a3b4eb","timeStamp":"1589315724"},{"operations":[],"contract":null,"_id":"0x88b7213a7eeb8cd2682b0b1893796b9fe6e655013aa1e4c175666574498e0fe6","blockNumber":5035127,"time":1589315620,"nonce":6031,"from":"0x85D382a464cbFE155f1cd2e51Cdf70e1848e0B30","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"234799792180000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x88b7213a7eeb8cd2682b0b1893796b9fe6e655013aa1e4c175666574498e0fe6","timeStamp":"1589315620"},{"operations":[],"contract":null,"_id":"0x7b2e66adb872dc5145f2ae906b8f3708623598d8a43defa230d12300e6d24167","blockNumber":5035127,"time":1589315620,"nonce":1501,"from":"0x037EE208fbedB2aB659da61bE5D3d7d59a680450","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"114044051373000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x7b2e66adb872dc5145f2ae906b8f3708623598d8a43defa230d12300e6d24167","timeStamp":"1589315620"},{"operations":[],"contract":null,"_id":"0xd40fda506a9c4ec79bdfb9849b22bb2783ff0fd90677de17fe83542b3171267e","blockNumber":5035127,"time":1589315620,"nonce":4209,"from":"0x80CAE9A0F67Ece88917a0dFdebeAA796A8Ad6baB","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"267270750139000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0xd40fda506a9c4ec79bdfb9849b22bb2783ff0fd90677de17fe83542b3171267e","timeStamp":"1589315620"},{"operations":[],"contract":null,"_id":"0x95e2b3ffb9ea38f7a12929c56a083ff1e218abe3a6ee4a496e93d192ed7349ba","blockNumber":5035127,"time":1589315620,"nonce":5729,"from":"0x9246E7498358b8E48b7B4fCfB6b6B288a32CF88c","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"110097850354000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x95e2b3ffb9ea38f7a12929c56a083ff1e218abe3a6ee4a496e93d192ed7349ba","timeStamp":"1589315620"},{"operations":[],"contract":null,"_id":"0x52c30c78b9babab02a49bed0b372027995e8770520a3f5e7731ce15530f926ed","blockNumber":5035127,"time":1589315620,"nonce":1821,"from":"0x866c5c04B9F76bf3937E8ba6D55296766f4AA68e","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"154521636030000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x52c30c78b9babab02a49bed0b372027995e8770520a3f5e7731ce15530f926ed","timeStamp":"1589315620"},{"operations":[],"contract":null,"_id":"0x7b044c4e2554436812d6f4e47e6061b9c781077b3249465a11650d96a1386903","blockNumber":5035124,"time":1589315584,"nonce":4707,"from":"0x84dDF97c4500c2eDDAeE8965170Ba15843830Ca6","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"348242860332000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x7b044c4e2554436812d6f4e47e6061b9c781077b3249465a11650d96a1386903","timeStamp":"1589315584"},{"operations":[],"contract":null,"_id":"0x9bc139292a22ceee805c1aa2e4f04d949987e7e8db2ec977ad68718e754a2501","blockNumber":5035020,"time":1589314043,"nonce":1249,"from":"0x3EBe5E81f99F8711C29872059197C776875A6d39","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"169702326013000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x9bc139292a22ceee805c1aa2e4f04d949987e7e8db2ec977ad68718e754a2501","timeStamp":"1589314043"},{"operations":[],"contract":null,"_id":"0x85486da3117d18fd789eb83974f8e050e19a7c382eb950a5a9a6d0509fb9b4e8","blockNumber":5035005,"time":1589313889,"nonce":1825,"from":"0x1212c7aE2d01E3d174C759EF616c46C9C50bd94f","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"205825126533000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x85486da3117d18fd789eb83974f8e050e19a7c382eb950a5a9a6d0509fb9b4e8","timeStamp":"1589313889"},{"operations":[],"contract":null,"_id":"0xbf01f666ed9b94b8ad5f6ee364e501fbf449faf9bc9f3024b610d961d575ecad","blockNumber":5035004,"time":1589313876,"nonce":5168,"from":"0xdb9EdDA5E1473D6D893418B95B93DC6abCa03449","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"117070306775000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0xbf01f666ed9b94b8ad5f6ee364e501fbf449faf9bc9f3024b610d961d575ecad","timeStamp":"1589313876"},{"operations":[],"contract":null,"_id":"0xe640264a9fc8ba3688be9cb4ec9af4b955689315d84a1c85113348242a45e1c2","blockNumber":5035004,"time":1589313876,"nonce":3348,"from":"0xC345943EEE93D60FA2A8A33A8D6D0015Ca16A4Fe","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"118206180675000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0xe640264a9fc8ba3688be9cb4ec9af4b955689315d84a1c85113348242a45e1c2","timeStamp":"1589313876"},{"operations":[],"contract":null,"_id":"0x3dc87c1cbab90500c956976465e08de6e10cc7d27dfbacc3e6b0fa9023930a7e","blockNumber":5035004,"time":1589313876,"nonce":440,"from":"0x8d1A02bf0b94DaeFC38fA47Be37B76Bab818cD65","to":"0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7","value":"339711659473000000000","gas":"21000","gasPrice":"30000000000","gasUsed":"21000","input":"0x","error":"","id":"0x3dc87c1cbab90500c956976465e08de6e10cc7d27dfbacc3e6b0fa9023930a7e","timeStamp":"1589313876"}],"total":25} \ No newline at end of file diff --git a/mock/ext-api-data/cosmos-api_auth_accounts_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json b/mock/ext-api-data/cosmos-api_auth_accounts_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json new file mode 100644 index 000000000..03520a934 --- /dev/null +++ b/mock/ext-api-data/cosmos-api_auth_accounts_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json @@ -0,0 +1 @@ +{"height":"1900975","result":{"type":"cosmos-sdk/Account","value":{"address":"cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq","coins":[],"public_key":{"type":"tendermint/PubKeySecp256k1","value":"A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt"},"account_number":"10373","sequence":"3"}}} \ No newline at end of file diff --git a/mock/ext-api-data/cosmos-api_minting_inflation.json b/mock/ext-api-data/cosmos-api_minting_inflation.json new file mode 100644 index 000000000..0fe813926 --- /dev/null +++ b/mock/ext-api-data/cosmos-api_minting_inflation.json @@ -0,0 +1,4 @@ +{ + "height": "1869960", + "result": "0.070000000000000000" +} \ No newline at end of file diff --git a/mock/ext-api-data/cosmos-api_staking_delegators_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_delegations.json b/mock/ext-api-data/cosmos-api_staking_delegators_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_delegations.json new file mode 100644 index 000000000..523cda5f1 --- /dev/null +++ b/mock/ext-api-data/cosmos-api_staking_delegators_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_delegations.json @@ -0,0 +1,11 @@ +{ + "height": "1869960", + "result": [ + { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", + "shares": "2211271.000000000000000000", + "balance": "2211271" + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/cosmos-api_staking_pool.json b/mock/ext-api-data/cosmos-api_staking_pool.json new file mode 100644 index 000000000..6275f5280 --- /dev/null +++ b/mock/ext-api-data/cosmos-api_staking_pool.json @@ -0,0 +1,7 @@ +{ + "height": "1869960", + "result": { + "not_bonded_tokens": "4596456385348", + "bonded_tokens": "182417010067615" + } +} \ No newline at end of file diff --git a/mock/ext-api-data/cosmos-api_staking_validators__status_bonded.json b/mock/ext-api-data/cosmos-api_staking_validators__status_bonded.json new file mode 100644 index 000000000..b107e93f5 --- /dev/null +++ b/mock/ext-api-data/cosmos-api_staking_validators__status_bonded.json @@ -0,0 +1,3130 @@ +{ + "height": "1863094", + "result": [ + { + "operator_address": "cosmosvaloper1qdxmyqkvt8jsxpn5pp45a38ngs36mn2604cqk9", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmq2l5ehgl3rxwjgzgr6sgzp69qwjl5ufvtyvacc9ms8p3phazl2qh3ulfw", + "jailed": false, + "status": 2, + "tokens": "74844486443", + "delegator_shares": "74844486443.000000000000000000", + "description": { + "moniker": "真本聪\u0026IOSG", + "identity": "8A79F44CC25D26DF", + "website": "realsatoshi.net", + "details": "To The Moon Then Cosmos. We are a crypto community and venture capital combined staking service provider" + }, + "unbonding_height": "0", + "unbonding_time": "2019-06-24T19:55:42.604341211Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-08-05T07:24:32.572614545Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", + "consensus_pubkey": "cosmosvalconspub1zcjduepqwrjpn0slu86e32zfu5xxg8l42uk40guuw6er44vw2yl6s7wc38est6l0ux", + "jailed": false, + "status": 2, + "tokens": "5603064313542", + "delegator_shares": "5603064313542.000000000000000000", + "description": { + "moniker": "Certus One", + "identity": "ABD51DF68C0D1ECF", + "website": "https://certus.one", + "details": "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.125000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1qs8tnw2t8l6amtzvdemnnsq9dzk0ag0z52uzay", + "consensus_pubkey": "cosmosvalconspub1zcjduepqsszd2gzte82dzt0xpa3w0ky8lxhjs6zpd5ft8akmkscwujpftymsnt83qc", + "jailed": false, + "status": 2, + "tokens": "1604777219007", + "delegator_shares": "1604777219007.000000000000000000", + "description": { + "moniker": "Castlenode", + "identity": "F685CC35D748424C", + "website": "https://www.castlenode.com/cosmos", + "details": "Castlenode is a validator operator focused on security and run by experienced professionals. Please read our Terms and Conditions on our website before delegating" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.090000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1qaa9zej9a0ge3ugpx3pxyx602lxh3ztqgfnp42", + "consensus_pubkey": "cosmosvalconspub1zcjduepqgx5wxl6eygqf6rx4gura2dy5vzelthjgqntk7q9l2hnpjqam6atsq8u0lx", + "jailed": false, + "status": 2, + "tokens": "69345300547", + "delegator_shares": "69345300547.000000000000000000", + "description": { + "moniker": "CCN", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-04-06T14:37:22.97012847Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1pz0lfq40sa63n0wany3v95x3yvznc5gyf8u28w", + "consensus_pubkey": "cosmosvalconspub1zcjduepqv03r9c26w884sqw0zdqg9cdx4xxwgn3dd2s6wa3x346tm83nxudqwhm3jl", + "jailed": false, + "status": 2, + "tokens": "252842798220", + "delegator_shares": "252842798220.000000000000000000", + "description": { + "moniker": "Cobo", + "identity": "3B7C85200D5B57A9", + "website": "https://cobo.com/", + "details": "Cobo is the first leading company in the world to offer Proof-of-Stake (PoS) and masternode rewards on user holdings, making it easy for users to grow their digital assets effortlessly." + }, + "unbonding_height": "0", + "unbonding_time": "2019-05-18T11:34:21.668987388Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-06-15T05:45:23.950986198Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1pgsjyvkg3y2m7qas534zzdhsqsxqyph2jh3uck", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5tycuhznpjuwlr93ypflreaddk0r66hdryzgmfvmlj2ekdd5sqrqnxclgg", + "jailed": false, + "status": 2, + "tokens": "460520445065", + "delegator_shares": "460520445065.000000000000000000", + "description": { + "moniker": "OneSixtyTwo", + "identity": "1C136F82A18BB2E2", + "website": "", + "details": "OneSixtyTwo" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.130000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-05-12T13:45:02.654424038Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", + "consensus_pubkey": "cosmosvalconspub1zcjduepqtcsm8lp7n6ph98vd59qa9esgyuysuntww9juz5wynxrhzpspmuuq6g5pzg", + "jailed": false, + "status": 2, + "tokens": "925719899399", + "delegator_shares": "925719899399.000000000000000000", + "description": { + "moniker": "WeStaking", + "identity": "DA9C5AD3E308E426", + "website": "https://www.westaking.io", + "details": "Delegate your atom to us for the staking rewards. We will do our best as secure and stable validator." + }, + "unbonding_height": "0", + "unbonding_time": "2019-09-07T12:24:58.270714195Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-29T00:37:22.163935678Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1pjmngrwcsatsuyy8m3qrunaun67sr9x7z5r2qs", + "consensus_pubkey": "cosmosvalconspub1zcjduepqcdav5ylt2zst90qmuh8e5w07xmxv9y6wufp5k9ngzmx7v9qewqtqkcq4z8", + "jailed": false, + "status": 2, + "tokens": "654800077136", + "delegator_shares": "654800077136.000000000000000000", + "description": { + "moniker": "Cypher Core", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1p650epkdwj0jte6sjc3ep0n3wz6jc9ehh8jutg", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmy5ja8dee3sprtmxkekcuvwz20y2x9d6llcsjl6p6553rpqev0eql6qccf", + "jailed": false, + "status": 2, + "tokens": "109356501526", + "delegator_shares": "109389314898.340406887282218010", + "description": { + "moniker": "Cosmos Suisse", + "identity": "2D875495A911A943", + "website": "https://cosmos-suisse.com", + "details": "An awesome Validator based in Crypto Valley, Switzerland." + }, + "unbonding_height": "970101", + "unbonding_time": "2020-03-21T06:33:36.130547135Z", + "commission": { + "commission_rates": { + "rate": "0.295000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-05T06:40:17.027131003Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1zqgheeawp7cmqk27dgyctd80rd8ryhqs6la9wc", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5tm478lhn4du7l46yp6fgu9e8fcfks0j4kf87pk4z8vc3clckxzqvh2q72", + "jailed": false, + "status": 2, + "tokens": "685457020651", + "delegator_shares": "685457020651.000000000000000000", + "description": { + "moniker": "melea-◮👁◭", + "identity": "4BE49EABAA41B8BF", + "website": "https://meleatrust.com/", + "details": "Validator service secure and trusted, awarded in Game Of Steaks" + }, + "unbonding_height": "0", + "unbonding_time": "2019-06-26T23:50:09.38840326Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-27T05:18:46.405341672Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1rpgtz9pskr5geavkjz02caqmeep7cwwpv73axj", + "consensus_pubkey": "cosmosvalconspub1zcjduepq04y0dtylyed2f8drc9t78dmptfuta7l6xyujwmsgrqefs0sxpgjsnzpsj6", + "jailed": false, + "status": 2, + "tokens": "4009701343250", + "delegator_shares": "4010503403720.896323597221447607", + "description": { + "moniker": "Blockpower", + "identity": "C374865C7ADE710B", + "website": "http://blockpower.capital/cosmos", + "details": "We self-bond 1m atoms and will keep our fee low till transfer enabled. We are top-ten validator in Tezos and operate professional staking services for multiple PoS platforms. Twitter: https://twitter.com/blockpowercap and TG: https://t.me/blockpowercosmos" + }, + "unbonding_height": "0", + "unbonding_time": "2019-11-04T04:14:24.222468286Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-31T19:58:53.172697095Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1r8kyvg4me2upnvlk26n2ay0zd5t4jktna8hhxp", + "consensus_pubkey": "cosmosvalconspub1zcjduepqsl29jhapyxf4fa5a947dmnlvrt266fm959hfg2c657ju80hq0ljs3qejr7", + "jailed": false, + "status": 2, + "tokens": "250002000000", + "delegator_shares": "250002000000.000000000000000000", + "description": { + "moniker": "noma", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-03-14T03:50:13.123302789Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1rwh0cxa72d3yle3r4l8gd7vyphrmjy2kpe4x72", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5kg8xls9l35ftulkm2rt70hexeeyr5cqqkcv4h7936z5uasvvazqla8eck", + "jailed": false, + "status": 2, + "tokens": "5176992318281", + "delegator_shares": "5176992318281.000000000000000000", + "description": { + "moniker": "SparkPool", + "identity": "DE8E37240061B04E", + "website": "https://cosmos.sparkpool.com/", + "details": "The biggest Ethereum mining pool, we can be a reliable validator with our 3 years" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.060000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2020-05-09T08:01:06.223552512Z" + }, + "min_self_delegation": "100000000000" + }, + { + "operator_address": "cosmosvaloper1rcp29q3hpd246n6qak7jluqep4v006cdsc2kkl", + "consensus_pubkey": "cosmosvalconspub1zcjduepq7mft6gfls57a0a42d7uhx656cckhfvtrlmw744jv4q0mvlv0dypskehfk8", + "jailed": false, + "status": 2, + "tokens": "244367809379", + "delegator_shares": "244367809379.000000000000000000", + "description": { + "moniker": "2nd only to Certus One in GoS: in3s.com", + "identity": "0CE19EE3E4BA48E5", + "website": "https://in3s.com/Services#CosmosValidator", + "details": "https://in3s.com/Delegate#Delegate" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-03-18T20:31:50.23335594Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1y0us8xvsvfvqkk9c6nt5cfyu5au5tww2ztve7q", + "consensus_pubkey": "cosmosvalconspub1zcjduepqqhkzzgfc876q287ny2v9lqwmjpenuzkzlsnstrmg7krwrrf0pfqs9fxvs0", + "jailed": false, + "status": 2, + "tokens": "21746516100", + "delegator_shares": "21746516100.000000000000000000", + "description": { + "moniker": "Swiss Staking", + "identity": "165F85FC0194320D", + "website": "https://swiss-staking.ch", + "details": "Experienced PoS Validator. We refund downtime slashing to 100%." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-12-11T18:25:42.711862818Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper19yy989ka5usws6gsd8vl94y7l6ssgdwsrnscjc", + "consensus_pubkey": "cosmosvalconspub1zcjduepqf22yaz9nsxlh043qm0tmupw8pnpver2n8lm3mwz6jzmsql76fkmqa482y8", + "jailed": false, + "status": 2, + "tokens": "500001550260", + "delegator_shares": "500001550260.000000000000000000", + "description": { + "moniker": "OKEx Pool", + "identity": "406C257E090E70AA", + "website": "http://www.okpool.top", + "details": "An innovative mining pool with higher yield" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-09-26T10:31:26.722694911Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1998928nfs697ep5d825y5jah0nq9zrtd00yyj7", + "consensus_pubkey": "cosmosvalconspub1zcjduepqlecm0rrfrr0vfgl624s7su9xvd3ycsaetndeuw2c7us0v8vfyfsq7cqz80", + "jailed": false, + "status": 2, + "tokens": "106659805308", + "delegator_shares": "106691809472.979562886817139796", + "description": { + "moniker": "HLT", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "1500089", + "unbonding_time": "2020-05-04T04:00:49.545065159Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-06-17T11:29:36.731435956Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper199mlc7fr6ll5t54w7tts7f4s0cvnqgc59nmuxf", + "consensus_pubkey": "cosmosvalconspub1zcjduepqajqpmv4j70a08ahs8lyjt8qk28ffa77zjegd7yajghchy8au575qmmxuyt", + "jailed": false, + "status": 2, + "tokens": "573776259593", + "delegator_shares": "573776259593.000000000000000000", + "description": { + "moniker": "Velocity V1", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-30T20:41:10.689796224Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "cosmosvaloper19v9ej55ataqrfl39v83pf4e0dm69u89rngf928", + "consensus_pubkey": "cosmosvalconspub1zcjduepqa32xgy8y5s69j6dynjmr3rlpv5dv35whz2tyaedwtjeqckm5gg4s2hj8ss", + "jailed": false, + "status": 2, + "tokens": "14371186654", + "delegator_shares": "14371186654.000000000000000000", + "description": { + "moniker": "blockscape", + "identity": "C46C8329BB5F48D8", + "website": "https://blockscape.network/", + "details": "By delegating, you confirm that you are aware of the risk of slashing and that M-Way Solutions GmbH is not liable for any potential damages to your investment." + }, + "unbonding_height": "483", + "unbonding_time": "2020-01-01T17:32:11.54021567Z", + "commission": { + "commission_rates": { + "rate": "0.099900000000000000", + "max_rate": "0.399900000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-02T09:18:02.304119479Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper19j2hd230c3hw6ds843yu8akc0xgvdvyuz9v02v", + "consensus_pubkey": "cosmosvalconspub1zcjduepq9ge7uqrfp9qkdapzd29tjtwrqpt2mm9meptx395ygxgm40tdc8ysrzj40a", + "jailed": false, + "status": 2, + "tokens": "441636806408", + "delegator_shares": "441636806408.000000000000000000", + "description": { + "moniker": "syncnode", + "identity": "F422F328C14AFBFA", + "website": "wallet.syncnode.ro", + "details": "email: g@ysncnode.ro || Operator's LinkedIn: https://www.linkedin.com/in/gbunea/ || Telegram Channel: https://t.me/syncnodeValidator || Blog: https://medium.com/syncnode-validator" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-15T11:41:35.747062104Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper19kwwdw0j64xhrmgkz49l0lmu5uyujjayxakwsn", + "consensus_pubkey": "cosmosvalconspub1zcjduepq668g4epaumjtx35rk3ucz2nlm7l7zuewkt0kzutg9hha859zjxmsvl2v67", + "jailed": false, + "status": 2, + "tokens": "631012799749", + "delegator_shares": "631012799749.000000000000000000", + "description": { + "moniker": "Firmamint", + "identity": "2FE4BC7A59E09FD0", + "website": "https://www.firmamint.io/", + "details": "The FUTURE is at STAKE - Proudly Canadian - Tier 1 WINNER of Game of Stakes Adversarial Testnet" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.030000000000000000" + }, + "update_time": "2019-03-18T22:02:43.333950761Z" + }, + "min_self_delegation": "1500000000" + }, + { + "operator_address": "cosmosvaloper1xym2qygmr9vanpa0m7ndk3n0qxgey3ffzcyd5c", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5evf9e4qhkxym6lx0ur2mwuz5e09u2v7u54yz3wcfanqwvhkc7rqcgpmlw", + "jailed": false, + "status": 2, + "tokens": "100686973548", + "delegator_shares": "100686973548.000000000000000000", + "description": { + "moniker": "🐡grant.fish", + "identity": "BE328F9A089F50C9", + "website": "http://grant.fish", + "details": "Providing grants to projects contributing to the Cosmos ecosystem." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-12-11T17:14:13.747872899Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1x8rr4hcf54nz6hfckyy2n05sxss54h8wz9puzg", + "consensus_pubkey": "cosmosvalconspub1zcjduepq8xpk5nh78lmgg0s0qqdyh4xtcw66xemt8anjsr6hrvlhauq252kstq7zr7", + "jailed": false, + "status": 2, + "tokens": "945088518708", + "delegator_shares": "945088518708.000000000000000000", + "description": { + "moniker": "cosmosgbt", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-10-18T04:22:16.555340871Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1x88j7vp2xnw3zec8ur3g4waxycyz7m0mahdv3p", + "consensus_pubkey": "cosmosvalconspub1zcjduepqhm6gjjkwecqyfrgey96s5up7drnspnl4t3rdr79grklkg9ff6zaqnfl2dg", + "jailed": false, + "status": 2, + "tokens": "2069213291905", + "delegator_shares": "2069213291905.000000000000000000", + "description": { + "moniker": "Staking Facilities", + "identity": "6B0DF6793DE1FB1F", + "website": "stakingfacilities.com", + "details": "Earn rewards with one of the most experienced and secure validators. More than 150k USD in customer rewards paid out. We exclude liability for any financial damage resulting from delegating." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-23T22:11:43.172644866Z" + }, + "min_self_delegation": "100000000000" + }, + { + "operator_address": "cosmosvaloper1x065cjlgejk2p2la0029akfvdy52gtq9mm58ta", + "consensus_pubkey": "cosmosvalconspub1zcjduepqny59kv2elgh89tq9qr4jje2n0my4gyvh2hlnydzljtt542a5plwswtas48", + "jailed": false, + "status": 2, + "tokens": "141325143037", + "delegator_shares": "141325143037.000000000000000000", + "description": { + "moniker": "MathWallet麦子钱包", + "identity": "58320327FF6C928C", + "website": "https://mathwallet.org", + "details": "Math Wallet is a powerful and secure universal crypto wallet that enables storage of all BTC, ETH/ERC20, NEO/NEP5, EOS/ENU/Telos, TRON, ONT, BinanceChain, Cosmos/IRISnet tokens, supports cross-chain token exchange and a multi-chain dApp store." + }, + "unbonding_height": "0", + "unbonding_time": "2019-07-21T13:52:13.251185336Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-09-09T03:44:27.230973438Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03xfytvz7", + "consensus_pubkey": "cosmosvalconspub1zcjduepqdgvppnyr5c9pulsrmzr9e9rp7qpgm9jwp5yu8g3aumekgjugxacq8a9p2c", + "jailed": false, + "status": 2, + "tokens": "5356417408061", + "delegator_shares": "5356417408061.000000000000000000", + "description": { + "moniker": "iqlusion", + "identity": "DCB176E79AE7D51F", + "website": "iqlusion.io", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "100000000000" + }, + { + "operator_address": "cosmosvaloper1gdg6qqe5a3u483unqlqsnullja23g0xvqkxtk0", + "consensus_pubkey": "cosmosvalconspub1zcjduepqlsvqw4vacnv2qtwxmm8tq32lrcdhau3szqxevrrzy8u0jvwz69pqphnkzk", + "jailed": false, + "status": 2, + "tokens": "103362106837", + "delegator_shares": "103362106837.000000000000000000", + "description": { + "moniker": "zugerselfdelegation", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-02-21T16:46:55.500729256Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1fqzqejwkk898fcslw4z4eeqjzesynvrdfr5hte", + "consensus_pubkey": "cosmosvalconspub1zcjduepqd4hvh0rwfkhtwrj4ly3ptyxs8pyfaser57wx2tcnzzp0rlref90sxm5kwr", + "jailed": false, + "status": 2, + "tokens": "412391812468", + "delegator_shares": "412391812468.000000000000000000", + "description": { + "moniker": "commercio.network", + "identity": "ADBDB0178E4441BE", + "website": "https://commercio.network", + "details": "The Documents Blockchain" + }, + "unbonding_height": "0", + "unbonding_time": "2019-06-23T11:25:09.272949514Z", + "commission": { + "commission_rates": { + "rate": "0.090000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-25T10:53:14.835657659Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ff0dw8kawsnxkrgj7p65kvw7jxxakyf8n583gx", + "consensus_pubkey": "cosmosvalconspub1zcjduepqu08f7tuce8k88tgewhwer69kfvk5az3cn5lz3v8phl8gvu9nxu8qhrjxfj", + "jailed": false, + "status": 2, + "tokens": "686014025437", + "delegator_shares": "686082633630.242664780687029960", + "description": { + "moniker": "Compass", + "identity": "72CB5AAAAFB1CE69", + "website": "http://val.network/", + "details": "EasyZone is a decentralized light client, which means users can access account, stake and earn rewords with local key store. For the time being we focus on Tendermint ecosystem, including Cosmos, QOS and Irisnet etc. Winner of the Game of Stakes." + }, + "unbonding_height": "0", + "unbonding_time": "2019-10-14T04:10:07.163539573Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2", + "consensus_pubkey": "cosmosvalconspub1zcjduepqzu34dgs2p6ysz52hpdycls4jcfwgnf2pvxv0eh539ypmadkjfmes6mwaa3", + "jailed": false, + "status": 2, + "tokens": "1341410982718", + "delegator_shares": "1341410982718.000000000000000000", + "description": { + "moniker": "Stakin by POS Bakerz", + "identity": "83D300CB42D06962", + "website": "http://stakin.com/", + "details": "Your Trusted Crypto Rewards" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-02T09:39:28.188566867Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", + "consensus_pubkey": "cosmosvalconspub1zcjduepquuc5k7egx8ymejamr27c3sgw6tyhmt0eq0ak4qvflvhxx56nvjzsx9etmd", + "jailed": false, + "status": 2, + "tokens": "3480806611496", + "delegator_shares": "3480806611496.000000000000000000", + "description": { + "moniker": "Huobi Wallet", + "identity": "CF01514DBF6583FE", + "website": "https://www.huobiwallet.com", + "details": "Huobi Wallet is a leading multi-chain wallet from Huobi Group and also offering competitive Proof-of-Stake (PoS) rewards for users to grow their digital assets. As a Cosmos validator, Huobi Wallet offers the one and only hard slashing insurance fund to our delegators" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-06T02:06:36.387455308Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper125umsz3fws7gepn5ccsh0sv4gre9r6a3tccz4r", + "consensus_pubkey": "cosmosvalconspub1zcjduepqkzserh5aetg6m33vrfcsuz60qpkgkpkpzkh8gp9lsd7cxffgph4qjzkxft", + "jailed": false, + "status": 2, + "tokens": "10670148807", + "delegator_shares": "10671215847.540238522991345421", + "description": { + "moniker": "Moonstake", + "identity": "742F7B64C32DF7A6", + "website": "https://www.moonstake.io/", + "details": "Shoot For The Moon" + }, + "unbonding_height": "1592315", + "unbonding_time": "2020-05-11T16:50:24.308799306Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-03-03T10:05:22.79594206Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper124maqmcqv8tquy764ktz7cu0gxnzfw54n3vww8", + "consensus_pubkey": "cosmosvalconspub1zcjduepq279zs0zgd53ujngs6v2hus2le9rk2a2rs66j4yvv6ewvvxn29yqqk95h8x", + "jailed": false, + "status": 2, + "tokens": "606545418213", + "delegator_shares": "606545418213.000000000000000000", + "description": { + "moniker": "Simply Staking", + "identity": "F74595D6D5D568A2", + "website": "https://www.simply-vc.com.mt", + "details": "Simply VC runs highly reliable and secure infrastructure in our own datacentre in Malta, built with the aim of supporting the growth of the blockchain ecosystem." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-11T17:29:59.537654017Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "cosmosvaloper1tflk30mq5vgqjdly92kkhhq3raev2hnz6eete3", + "consensus_pubkey": "cosmosvalconspub1zcjduepqwcvy8hyw2phdp080ggj7prxv972rvqc9gwyjnl0uwf7uxn63s8vqdctdcw", + "jailed": false, + "status": 2, + "tokens": "166014730256", + "delegator_shares": "166014730256.000000000000000000", + "description": { + "moniker": "Everstake", + "identity": "", + "website": "https://everstake.one", + "details": "Reliable and experienced staking service provider from Ukraine. Visit our website for more details." + }, + "unbonding_height": "0", + "unbonding_time": "2019-12-07T19:10:59.878559804Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-07-14T19:56:46.186760169Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ttfytaf43nkytzp8hkfjfgjc693ky4t3y2n2ku", + "consensus_pubkey": "cosmosvalconspub1zcjduepq2nfs6lcwu6ksq54yf0ptgrmjjrnm5p5ywng3x0t0767m777hvctq30rwcs", + "jailed": false, + "status": 2, + "tokens": "67995376247", + "delegator_shares": "68002176461.716837847819163406", + "description": { + "moniker": "StarCluster", + "identity": "F97B6EF4FD82202F", + "website": "https://starcluster.tech", + "details": "With decades of passion invested in tech, we provide a team of top security and infrastructure engineers as a service. With extensive knowledge in the blockchain space and having run a successful ICO, we are confident that providing our experience \u0026 skills could benefit many." + }, + "unbonding_height": "0", + "unbonding_time": "2019-12-24T15:27:58.293852371Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.150000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-10-26T21:50:11.42045872Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v", + "consensus_pubkey": "cosmosvalconspub1zcjduepqjg26g27dtvjqstyqktmp4jsn98473vfz0mek2eyklfp0yqapav5szdrvpd", + "jailed": false, + "status": 2, + "tokens": "3368758736271", + "delegator_shares": "3368758736271.000000000000000000", + "description": { + "moniker": "CoinoneNode", + "identity": "F4E86EE9BD73A11F", + "website": "https://node.coinone.co.kr", + "details": "The more, the easier. Coinone Node manages your assets securely." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-14T09:22:28.276013718Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1vrg6ruw00lhszl4sjgwt5ldvl8z0f7pfp5va85", + "consensus_pubkey": "cosmosvalconspub1zcjduepq2hfnf0rvk6nksvtzkqly4vy362sencfkt7tgsrvx30krj5vxw0asa7hmjh", + "jailed": false, + "status": 2, + "tokens": "371297506211", + "delegator_shares": "371297506211.000000000000000000", + "description": { + "moniker": "SSSnodes", + "identity": "C5B68615F8828EC0", + "website": "http://sssnodes.com/cosmos", + "details": "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by SSSnodes, a Corp. focused on delegation service for multiple Proof of Stake networks, such as COSMOS, ChainX, IOST, CyberMiles, Lambda, ONT, etc." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.018000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-28T08:09:59.47667909Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1vf44d85es37hwl9f4h9gv0e064m0lla60j9luj", + "consensus_pubkey": "cosmosvalconspub1zcjduepqtj2urav4g9wex3hku588au0x4sucrc9lpky46zp5u8w4mvd584sqmcxxhs", + "jailed": false, + "status": 2, + "tokens": "7276799410408", + "delegator_shares": "7276799410408.000000000000000000", + "description": { + "moniker": "MultiChain Ventures", + "identity": "06E24C7678282B53", + "website": "https://www.multichain-ventures.com", + "details": "Secure stake and earn rewards with MultiCahin ventures" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-08-21T08:01:01.670548948Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1v5y0tg0jllvxf5c3afml8s3awue0ymju89frut", + "consensus_pubkey": "cosmosvalconspub1zcjduepq9kun5ty55rl3lnmf46tfxhj06as8h7zpxcdhujm6d708ffn6kgss43q6u9", + "jailed": false, + "status": 2, + "tokens": "5856297267830", + "delegator_shares": "5856297267830.000000000000000000", + "description": { + "moniker": "Zero Knowledge Validator (ZKV)", + "identity": "3E38E52A12F94561", + "website": "https://zkvalidator.com/", + "details": "Zero Knowledge Validator: Stake \u0026 Support ZKP Research \u0026 Privacy Tech" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-11T15:48:18.737920871Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1vk706z2tfnqhdg6jrkngyx7f463jq58nj0x7p7", + "consensus_pubkey": "cosmosvalconspub1zcjduepq0qdudwaluzpy5ptluu5umck5fp2ns2qf2kjp367qlr7yf65agx5s0n8h7f", + "jailed": false, + "status": 2, + "tokens": "29009856874", + "delegator_shares": "29009856874.000000000000000000", + "description": { + "moniker": "Public Payments", + "identity": "1850627141D54797", + "website": "https://www.publicpayments.io", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-02T12:25:53.791107872Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1d0aup392g3enru7eash83sedqclaxvp7fzh6gk", + "consensus_pubkey": "cosmosvalconspub1zcjduepql9j7qpwvfl0pspymhesj48t3t0aazjx0m2jwjuyxd7zw53hqnkss4hmasl", + "jailed": false, + "status": 2, + "tokens": "190898805499", + "delegator_shares": "190917897121.968489215822622695", + "description": { + "moniker": "Stir", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "2019-06-21T20:37:09.115641759Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-14T13:03:10.437070061Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1dse76yk5jmj85jsd77ewsczc4k3u4s7a870wtj", + "consensus_pubkey": "cosmosvalconspub1zcjduepqjdc9grwq5mxdtg26hv9t75y3ltsau3rtmg6p72p0dh8343nj4s6qr6xymd", + "jailed": false, + "status": 2, + "tokens": "399992036873", + "delegator_shares": "400032040000.820061751426683457", + "description": { + "moniker": "gf.network", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "10001", + "unbonding_time": "2020-01-02T11:58:18.459331455Z", + "commission": { + "commission_rates": { + "rate": "0.080000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-27T12:23:08.242833465Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1de7qx00pz2j6gn9k88ntxxylelkazfk3g8fgh9", + "consensus_pubkey": "cosmosvalconspub1zcjduepqwr5p8j076mfydn7wckqz748lr0j50zwgsftnfpvgz6rz0rkvvqwqg5fyaf", + "jailed": false, + "status": 2, + "tokens": "365449381771", + "delegator_shares": "365449381771.000000000000000000", + "description": { + "moniker": "Cosmic Validator", + "identity": "FF4B91B50B71CEDA", + "website": "", + "details": "A reliable, passionate and service oriented Cosmos, Polkadot and Sentinel validator. We are long term trusted community members and have received delegation from the Interchain Foundation (ICF) as a reward for our continuous support and effort." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-10-07T05:35:40.25581859Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1d7ufwp2rgfj7s7pfw2q7vm2lc9txmr8vh77ztr", + "consensus_pubkey": "cosmosvalconspub1zcjduepq2x456pyef8jdnjgk8j62fuug24xfg9cnnjl66ewtgttwr00phz8sdzatkj", + "jailed": false, + "status": 2, + "tokens": "117924360855", + "delegator_shares": "117924360855.000000000000000000", + "description": { + "moniker": "Cybernetic Destiny", + "identity": "", + "website": "", + "details": "The future you’ve always wanted." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-02-07T23:19:03.834895518Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1wp9jne5t3e4au7u8gfep90g59j0qdhpeqvlg7n", + "consensus_pubkey": "cosmosvalconspub1zcjduepq6740f8r23xr74w94l5ew9fh6n8wquutgm22pw6yyrydq507mgdkqghsjtd", + "jailed": false, + "status": 2, + "tokens": "89466618968", + "delegator_shares": "89466618968.000000000000000000", + "description": { + "moniker": "Newroad Network", + "identity": "F898ACE263EC1C4E", + "website": "https://newroad.network/cosmos/", + "details": "We provide a professional delegation service for multiple Proof of Stake networks. We use a secure and redundant setup. Visit our website for more information." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.080000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-04-26T18:30:05.33496777Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1wtv0kp6ydt03edd8kyr5arr4f3yc52vp3u2x3u", + "consensus_pubkey": "cosmosvalconspub1zcjduepq0zyaquh6c8vmjfzft43uqylf2ejjpjcvup2zrtsk40uyz8xsq29s0k4eaw", + "jailed": false, + "status": 2, + "tokens": "353702000001", + "delegator_shares": "353702000001.000000000000000000", + "description": { + "moniker": "kytzu", + "identity": "909A480D5643CCC5", + "website": "https://www.linkedin.com/in/calinchitu", + "details": "Blockchain consultant, running on IPSX infrastructure (calin@ip.sx)" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-07-13T04:46:58.395203387Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "cosmosvaloper1wdrypwex63geqswmcy5qynv4w3z3dyef2qmyna", + "consensus_pubkey": "cosmosvalconspub1zcjduepqs0et7kpf82glsw5j9jnppekrpa7kl6gr6xk67ztqg9ynmhgj82ks9edcrw", + "jailed": false, + "status": 2, + "tokens": "457220203123", + "delegator_shares": "457220203123.000000000000000000", + "description": { + "moniker": "Genesis Lab", + "identity": "C1A123F2723041F0", + "website": "https://genesislab.net", + "details": "Genesis Lab is a blockchain-focused development company and validation nodes operator in PoS networks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-15T17:32:00.387570437Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1w0494h0l4mneaq7ajkrcjvn73m2n04l87j2nst", + "consensus_pubkey": "cosmosvalconspub1zcjduepquxeuhp0gj88u5mrukuazzrxc4rnjjuakls4fr2gzxlwj4f9p8lfs965r7z", + "jailed": false, + "status": 2, + "tokens": "96455451062", + "delegator_shares": "96484393351.999596821444782714", + "description": { + "moniker": "Angel", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "804087", + "unbonding_time": "2020-03-07T13:08:49.834368524Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.500000000000000000" + }, + "update_time": "2019-03-18T15:40:26.600089741Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1w42lm7zv55jrh5ggpecg0v643qeatfkd9aqf3f", + "consensus_pubkey": "cosmosvalconspub1zcjduepqz679nxu2dkfd6y9hytqwvf2z4yuevraqykkm2464ag4e6z278h3qdq92xu", + "jailed": false, + "status": 2, + "tokens": "758514561374", + "delegator_shares": "758514561374.000000000000000000", + "description": { + "moniker": "Mythos", + "identity": "2E9FDF34351A5112", + "website": "https://mythos.services", + "details": "Staking and validator services for crypto networks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw", + "consensus_pubkey": "cosmosvalconspub1zcjduepq6adydsk7nw3d63qtn30t5rexhfg56pq44sw4l9ld0tcj6jvnx30s5xw9ar", + "jailed": false, + "status": 2, + "tokens": "1873921877156", + "delegator_shares": "1873921877156.000000000000000000", + "description": { + "moniker": "Staked", + "identity": "E7BFA6515FB02B3B", + "website": "https://staked.us/", + "details": "Staked operates highly available and highly secure, institutional grade staking infrastructure for leading proof-of-stake (PoS) protocols." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.020000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1wauge4px27c257nfn4k3329wteddqw7gs3n66u", + "consensus_pubkey": "cosmosvalconspub1zcjduepqqaffdhuhdtr0d6nl8twpraxps74q3mxn68qknrex465yd9cc9l0qeh6lkk", + "jailed": false, + "status": 2, + "tokens": "169436163344", + "delegator_shares": "169436163344.000000000000000000", + "description": { + "moniker": "DappPub", + "identity": "BB2D113EFC6DFDC4", + "website": "https://dapp.pub", + "details": "DappPub, Unleashing the Power of DApps" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-05-15T10:37:35.020580984Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper102ruvpv2srmunfffxavttxnhezln6fnc54at8c", + "consensus_pubkey": "cosmosvalconspub1zcjduepq9weu2v0za8fdcvx0w3ps972k5v7sm6h5as9qaznc437vwpfxu37q0f3lyg", + "jailed": false, + "status": 2, + "tokens": "419077200660", + "delegator_shares": "419077200660.000000000000000000", + "description": { + "moniker": "Ztake.org", + "identity": "09A303A2C724C591", + "website": "https://ztake.org/", + "details": "Support reliable independent validator" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-08-14T05:12:52.848294105Z" + }, + "min_self_delegation": "10" + }, + { + "operator_address": "cosmosvaloper10wz6lfhmqfw6egg0062ytnawaj6vr89ly5g4yg", + "consensus_pubkey": "cosmosvalconspub1zcjduepqtm62lxg8hm4tcnqvgk69xs6egltfsq9w6ed3cmq73jjgd3avslvq9d0sy9", + "jailed": false, + "status": 2, + "tokens": "95001650000", + "delegator_shares": "95001650000.000000000000000000", + "description": { + "moniker": "BitMax Staking", + "identity": "", + "website": "https://bitmax.io/", + "details": "Trading Platform Industry Leader driven by Product Innovation" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-19T12:21:32.956535488Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1000ya26q2cmh399q4c5aaacd9lmmdqp90kw2jn", + "consensus_pubkey": "cosmosvalconspub1zcjduepqe93asg05nlnj30ej2pe3r8rkeryyuflhtfw3clqjphxn4j3u27msrr63nk", + "jailed": false, + "status": 2, + "tokens": "457347172083", + "delegator_shares": "457347172083.000000000000000000", + "description": { + "moniker": "Staking Fund", + "identity": "805F39B20E881861", + "website": "https://www.staking.fund", + "details": "Staking Fund has been participating in the validating role since early 2018 and is a proud member of the Never Jailed Crew of Game of Stakes." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "0.334000000000000000", + "max_change_rate": "0.012019031323000000" + }, + "update_time": "2020-02-02T00:47:46.138000758Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper10nzaaeh2kq28t3nqsh5m8kmyv90vx7ym5mpakx", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmuspsp8739l0lgn2qz0arargk6ccfy2p82mwflsrsqzwpvhuh5usuwykf6", + "jailed": false, + "status": 2, + "tokens": "73145988986", + "delegator_shares": "73145988986.000000000000000000", + "description": { + "moniker": "Blockdaemon", + "identity": "8F898657DE26D645", + "website": "https://blockdaemon.com/node-marketplace/#staking", + "details": "Blockdaemon provides maximum uptime for the Cosmos network so that you can be confident your node will be there, ready and secure, for optimal reward generation. Contact us to stake on Cosmos today." + }, + "unbonding_height": "0", + "unbonding_time": "2019-12-19T03:19:44.114438899Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-10-29T19:55:36.41178089Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper10e4vsut6suau8tk9m6dnrm0slgd6npe3jx5xpv", + "consensus_pubkey": "cosmosvalconspub1zcjduepqteacnywz7urnac46wtrcy34myyj82j250ny7866yffypdgavae5s0lf4a0", + "jailed": false, + "status": 2, + "tokens": "3679445632111", + "delegator_shares": "3679445632111.000000000000000000", + "description": { + "moniker": "B-Harvest", + "identity": "8957C5091FBF4192", + "website": "https://bharvest.io", + "details": "B-Harvest focus on the value of high standard security \u0026 stability, active community participation on Cosmos Network, and real world practical use-case of blockchain technology." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-24T11:21:51.694254562Z" + }, + "min_self_delegation": "9000000000" + }, + { + "operator_address": "cosmosvaloper1sxx9mszve0gaedz5ld7qdkjkfv8z992ax69k08", + "consensus_pubkey": "cosmosvalconspub1zcjduepqjnnwe2jsywv0kfc97pz04zkm7tc9k2437cde2my3y5js9t7cw9mstfg3sa", + "jailed": false, + "status": 2, + "tokens": "2268794946053", + "delegator_shares": "2268794946053.000000000000000000", + "description": { + "moniker": "validator.network | Security first. Highly available.", + "identity": "357F80896B3311B4", + "website": "https://validator.network", + "details": "Highly resilient and secure validator operating out of Northern Europe. See website for terms of service." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-06-30T08:32:22.562118158Z" + }, + "min_self_delegation": "100000000" + }, + { + "operator_address": "cosmosvaloper1sd4tl9aljmmezzudugs7zlaya7pg2895ws8tfs", + "consensus_pubkey": "cosmosvalconspub1zcjduepq8y846wm58fmmuctxp7csqmaz3594xnykcean0lp722ntf6u5ycaqss4prd", + "jailed": false, + "status": 2, + "tokens": "1246459015415", + "delegator_shares": "1246459015415.000000000000000000", + "description": { + "moniker": "InfStones (Infinity Stones)", + "identity": "39A41C2FDE0AD040", + "website": "https://infstones.io", + "details": "Fueling Blockchain Beyond Infinity!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-05-10T06:56:55.530159974Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1s05va5d09xlq3et8mapsesqh6r5lqy7mkhwshm", + "consensus_pubkey": "cosmosvalconspub1zcjduepqgx5xdrx0xktl5r8e3w7vj329fgh3fnep8ahgx8027nd5nkjxzuqs5us5en", + "jailed": false, + "status": 2, + "tokens": "556817046823", + "delegator_shares": "556817046823.000000000000000000", + "description": { + "moniker": "Wetez", + "identity": "26FA2B24F46A98EF", + "website": "https://www.wetez.io", + "details": "Wetez is the most professional team in the POS ( Proof of Stake) field.Wetez是POS领域最专业的团队,为POS带来的权益做更多赋能。" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-03-25T02:35:12.908955321Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ssm0d433seakyak8kcf93yefhknjleeds4y3em", + "consensus_pubkey": "cosmosvalconspub1zcjduepqrgyyjxpe0ujefxwnkpmqz9m0hj03y09tdz9lwc0s7mvy469hulfq69f8sd", + "jailed": false, + "status": 2, + "tokens": "1516027838065", + "delegator_shares": "1516027838065.000000000000000000", + "description": { + "moniker": "IRISnet-Bianjie", + "identity": "DB667A6F239969F5", + "website": "https://irisnet.org/irisnet-bianjie", + "details": "Interchain Service Hub for NextGen Distributed Applications." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.020000000000000000" + }, + "update_time": "2019-06-21T04:33:57.044358454Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9u2lcnj0", + "consensus_pubkey": "cosmosvalconspub1zcjduepq6fpkt3qn9xd7u44478ypkhrvtx45uhfj3uhdny420hzgsssrvh3qnzwdpe", + "jailed": false, + "status": 2, + "tokens": "12683713751295", + "delegator_shares": "12683713751295.000000000000000000", + "description": { + "moniker": "🐠stake.fish", + "identity": "90B597A673FC950E", + "website": "stake.fish", + "details": "We are the leading staking service provider for blockchain projects. Join our community to help secure networks and earn rewards. We know staking." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.040000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1s6x9fy4wc49wj9jx4jv6czredqsmp46h7vnk2q", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfkkyuexns2l7rw2mx2ms988heah0rjv42e9q88scc3ms5hzg45psycrvr4", + "jailed": false, + "status": 2, + "tokens": "727981844212", + "delegator_shares": "727981844212.000000000000000000", + "description": { + "moniker": "SNZPool", + "identity": "FF2019D4CF1F3185", + "website": "https://snzholding.com", + "details": "SNZ is a crypto assets capital, consulting agency, community builder and professional \u0026 reliable POS validator for a dozen of projects like Cosmos, IRISnet, EOS, ONT, Loom, etc." + }, + "unbonding_height": "0", + "unbonding_time": "2019-05-31T14:02:51.669843605Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1s6t3wzx6mcv3pjg5fp2ddzplm3gj4pg6d330wg", + "consensus_pubkey": "cosmosvalconspub1zcjduepqncdd6lvm4r42eke822e5eg0alentpvlxjwzat7nvpynlp0vcu55sl5z96g", + "jailed": false, + "status": 2, + "tokens": "245002260000", + "delegator_shares": "245002260000.000000000000000000", + "description": { + "moniker": "omega3", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-03-22T01:22:56.42711479Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1s65zmn32zugl57ysj47s7vmfcek0rtd7he7wde", + "consensus_pubkey": "cosmosvalconspub1zcjduepqrc6g9m2eyy4zs7kyeph8vk5ldpgnceveelc39zf7lc32j8k3shqssevdlg", + "jailed": false, + "status": 2, + "tokens": "194202250000", + "delegator_shares": "194202250000.000000000000000000", + "description": { + "moniker": "firstblock", + "identity": "23D9B8528FC93D58", + "website": "https://firstblock.io", + "details": "You Delegate. We Validate." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-09T03:45:47.112144406Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1s7jnk7t6yqzensdgpvkvkag022udk842qdjdtd", + "consensus_pubkey": "cosmosvalconspub1zcjduepqnnh28nlj55sc329ppnhcr0xx7kuc9vnsp3dpwc28wdhhxtjc7jfs9k57f7", + "jailed": false, + "status": 2, + "tokens": "337881031694", + "delegator_shares": "337881031694.000000000000000000", + "description": { + "moniker": "Blockscale", + "identity": "F38EDEA063FD446C", + "website": "https://blockscale.net", + "details": "Planet-scale blockchain infrastructure." + }, + "unbonding_height": "0", + "unbonding_time": "2019-06-14T07:33:07.032714186Z", + "commission": { + "commission_rates": { + "rate": "0.250000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-09-21T01:23:56.63727699Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper132juzk0gdmwuxvx4phug7m3ymyatxlh9734g4w", + "consensus_pubkey": "cosmosvalconspub1zcjduepq9xu9z6ky3nz3k544ar4zhupjehkxdlpmt2l90kekxkrvuu7hxfgslcdqwy", + "jailed": false, + "status": 2, + "tokens": "2917176802437", + "delegator_shares": "2917176802437.000000000000000000", + "description": { + "moniker": "P2P.ORG - P2P Validator", + "identity": "E12F4695036D8072", + "website": "https://p2p.org", + "details": "One of the winners of Cosmos Game of Stakes. We provide a simple, secure and intelligent staking service to help you generate rewards on your blockchain assets across 9+ networks within a single interface. Let’s stake together - p2p.org." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-11T17:13:40.302520375Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper130mdu9a0etmeuw52qfxk73pn0ga6gawkxsrlwf", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfahazsjeru5wqulfuzklmkh272ggss2ru6fk00zq2fmlfzcq773sqlqe42", + "jailed": false, + "status": 2, + "tokens": "1128473573419", + "delegator_shares": "1128473573419.000000000000000000", + "description": { + "moniker": "jackzampolin", + "identity": "0979483D4F669CFF", + "website": "https://pylonvalidator.com", + "details": "'You must construct additional pylons' -StarCraft" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.150000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-03-25T15:28:01.171914203Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper13sduv92y3xdhy3rpmhakrc3v7t37e7ps9l0kpv", + "consensus_pubkey": "cosmosvalconspub1zcjduepqqddwwkhkfrsd66u49kg3h6q36t4kv557vlszqaed4c3y936ncq9s0r0tm2", + "jailed": false, + "status": 2, + "tokens": "1574051576303", + "delegator_shares": "1574051576303.000000000000000000", + "description": { + "moniker": "nylira.net", + "identity": "6A0D65E29A4CBC8E", + "website": "https://nylira.net", + "details": "Stake and earn with security and peace of mind. Operated by Peng Zhong." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-14T21:33:23.86382871Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper13ce7hhqa0z3tpc2l7jm0lcvwe073hdkkpp2nst", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmx0dcpmd9uq7ueck8d880lrt8tp9kvkfmaz0mtv0arye2cda2zrsrlla3n", + "jailed": false, + "status": 2, + "tokens": "10101347732", + "delegator_shares": "10101347732.000000000000000000", + "description": { + "moniker": "RockX", + "identity": "A15B586AB203F14E", + "website": "www.rockx.com", + "details": "Unlocking the full value of digital assets and decentralized governance" + }, + "unbonding_height": "1813403", + "unbonding_time": "2020-05-29T19:33:46.045420571Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-09-05T08:00:55.144718017Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1jxv0u20scum4trha72c7ltfgfqef6nsch7q6cu", + "consensus_pubkey": "cosmosvalconspub1zcjduepqnru7aa6ayyuwddd5qsa6tvutzs7xl9jk6pfx4ka5dr4y9d3q6eesgz9rz7", + "jailed": false, + "status": 2, + "tokens": "302793155457", + "delegator_shares": "302793155457.000000000000000000", + "description": { + "moniker": "Ping.pub", + "identity": "6EA723DA332200B2", + "website": "https://ping.pub", + "details": "We are one of the most secure and stable validator, welcome to delegate to us. 我们是最安全,最稳定,性价比最高的验证人节点,欢迎委托给我们!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.200000000000000000" + }, + "update_time": "2019-11-18T12:14:35.328556Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1j0vaeh27t4rll7zhmarwcuq8xtrmvqhudrgcky", + "consensus_pubkey": "cosmosvalconspub1zcjduepqvn4a4skwj88c8e0jvns3qjrhyy0whvnuwmth3k8kexvqk5vupw4qsdje47", + "jailed": false, + "status": 2, + "tokens": "1081673849444", + "delegator_shares": "1081673849444.000000000000000000", + "description": { + "moniker": "chainflow-cosmos-prodval-01", + "identity": "81D443FA08A4A926", + "website": "https://chainflow.io/cosmos", + "details": "Operated by Chris Remus (Twitter @cjremus) / Validating since the Validator Working Group formed in October 2017" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-04-01T15:19:20.666364183Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1jlr62guqwrwkdt4m3y00zh2rrsamhjf9num5xr", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5e8w7t7k9pwfewgrwy8vn6cghk0x49chx64vt0054yl4wwsmjgrqfackxm", + "jailed": false, + "status": 2, + "tokens": "691322889269", + "delegator_shares": "691322889269.000000000000000000", + "description": { + "moniker": "StakeWith.Us", + "identity": "609F83752053AD57", + "website": "https://stakewith.us", + "details": "Secured Staking Made Easy. Put Your Crypto to Work - Hassle Free. Disclaimer: Delegators should understand that delegation comes with slashing risk. By delegating to StakeWithUs Pte Ltd, you acknowledge that StakeWithUs Pte Ltd is not liable for any losses on your investment." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-04-22T12:01:25.715205208Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1n3f5lm7xtlrp05z9ud2xk2cnvk2xnzkm2he6er", + "consensus_pubkey": "cosmosvalconspub1zcjduepqghz45rfwczrvwl7u2xsm8dpamqg8gtzej66dtn57ax99g59klpfsm3yxyu", + "jailed": false, + "status": 2, + "tokens": "16071388577", + "delegator_shares": "16072995876.587658765876587650", + "description": { + "moniker": "AirGap 🛡", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "882174", + "unbonding_time": "2020-03-14T00:03:41.116898617Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2020-02-13T08:38:50.239783489Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1n5pu2rtz4e2skaeatcmlexza7kheedzh8a2680", + "consensus_pubkey": "cosmosvalconspub1zcjduepqnd9kzfhhvuv5k2cq62yu0e5v73ymsgxa0wlen9c7999ucwg7hg6qdm34pm", + "jailed": false, + "status": 2, + "tokens": "576087977754", + "delegator_shares": "576087977754.000000000000000000", + "description": { + "moniker": "BlockMatrix 🚀", + "identity": "DA33F58EC17769B4", + "website": "https://blockmatrix.network", + "details": "Experienced validator across multiple PoS and DPoS networks. Winners in the Game of Stakes. Cosmos FTW!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "10" + }, + { + "operator_address": "cosmosvaloper1nm0rrq86ucezaf8uj35pq9fpwr5r82clzyvtd8", + "consensus_pubkey": "cosmosvalconspub1zcjduepqsnngsdda53d9aqwezvpsx4uh2nkwkn4nra5lw4tyl9n3m02q4kvsrqq0pw", + "jailed": false, + "status": 2, + "tokens": "145001000000", + "delegator_shares": "145001000000.000000000000000000", + "description": { + "moniker": "Cthulhu", + "identity": "Cthulhu", + "website": "Cthul.hu", + "details": "Cthulhu" + }, + "unbonding_height": "644758", + "unbonding_time": "2020-02-23T10:33:51.593569686Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-01-22T08:27:20.214359212Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper15r4tc0m6hc7z8drq3dzlrtcs6rq2q9l2nvwher", + "consensus_pubkey": "cosmosvalconspub1zcjduepqjcp9ez3dzmvsdfcw2h5kllmqvjgqnhtlvhad4q9wzcqf34gf6ewq6zl5mm", + "jailed": false, + "status": 2, + "tokens": "731466206153", + "delegator_shares": "731466206153.000000000000000000", + "description": { + "moniker": "DragonStake", + "identity": "EA61A46F31742B22", + "website": "https://dragonstake.io", + "details": "Forking the Banks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-24T18:52:31.67294751Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper159eexl76jlygrxnfreehl3j9tt70d8wfnn39fw", + "consensus_pubkey": "cosmosvalconspub1zcjduepq0jhujmf2ur4uk7al8pht6rpxwf7a24gqmhggeche0w09fglj9tmss4a0ql", + "jailed": false, + "status": 2, + "tokens": "12181850000", + "delegator_shares": "12181850000.000000000000000000", + "description": { + "moniker": "fishegg.net", + "identity": "", + "website": "http://www.fishegg.net", + "details": "welcome to join staking" + }, + "unbonding_height": "7949", + "unbonding_time": "2020-01-02T07:58:37.125916904Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-13T14:17:35.977287639Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf", + "consensus_pubkey": "cosmosvalconspub1zcjduepqtw8862dhw8uty58d6t2szfd6kqram2t234zjteaaeem6l45wclaq8l60gn", + "jailed": false, + "status": 2, + "tokens": "9838730453054", + "delegator_shares": "9838730453054.000000000000000000", + "description": { + "moniker": "Binance Staking", + "identity": "", + "website": "https://binance.com", + "details": "Exchange the world" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.025000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-06T07:47:39.033746293Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper15urq2dtp9qce4fyc85m6upwm9xul3049e02707", + "consensus_pubkey": "cosmosvalconspub1zcjduepqjc07nu2ya8tyzl8m385rnc382pkulwt2gh8yary73f3a96jak7pqsf63xf", + "jailed": false, + "status": 2, + "tokens": "4747063386985", + "delegator_shares": "4747063386985.000000000000000000", + "description": { + "moniker": "Chorus One", + "identity": "00B79D689B7DC1CE", + "website": "https://chorus.one/", + "details": "Secure Cosmos and shape its future by delegating to Chorus One, a highly secure and stable validator. By delegating, you agree to the terms of service at: https://chorus.one/cosmos/tos" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.075000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.020000000000000000" + }, + "update_time": "2019-08-13T17:43:26.871706216Z" + }, + "min_self_delegation": "10" + }, + { + "operator_address": "cosmosvaloper1402ggxz5u6vm29sqztwqq8vxs3ke6dmwl2z5dk", + "consensus_pubkey": "cosmosvalconspub1zcjduepqd4qh9dqgyce948kn48r2aqk7qlgtuwdmfeewj0z9aj4dr30v33cq6pmlql", + "jailed": false, + "status": 2, + "tokens": "10136799592", + "delegator_shares": "10137813287.465132892679104584", + "description": { + "moniker": "Cosmoon", + "identity": "8935A6F323FA0881", + "website": "https://cosmoon.org/", + "details": " Professional Stake Rewards Service " + }, + "unbonding_height": "1795893", + "unbonding_time": "2020-05-28T09:10:59.90142555Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2020-01-27T22:18:16.158833459Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper14kn0kk33szpwus9nh8n87fjel8djx0y070ymmj", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmfxl36td7rcdzszzrk6c7kzp5l3jlw4lnxz8zms3py7qcsa9xlns7zxfd6", + "jailed": false, + "status": 2, + "tokens": "2268966311115", + "delegator_shares": "2268966311115.000000000000000000", + "description": { + "moniker": "Forbole", + "identity": "2861F5EE06627224", + "website": "https://www.forbole.com/cosmos-hub-validator/", + "details": "As a prominent validator and contributor in Cosmos since 2017, Forbole is devoted to build a stronger Cosmos ecosystem. We are award winners in Game of Stakes and HackAtom. Please join our [community](https://t.me/forbole) or visit [our website](https://www.forbole.com/)." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.095000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-10T16:52:29.417872059Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper14k4pzckkre6uxxyd2lnhnpp8sngys9m6hl6ml7", + "consensus_pubkey": "cosmosvalconspub1zcjduepquhlqdhjw4qp2c2t6qh5z7tfk52qc72623f0etc8f3n7hy8uuh25ql34fvu", + "jailed": false, + "status": 2, + "tokens": "9676167562461", + "delegator_shares": "9676167562461.000000000000000000", + "description": { + "moniker": "Polychain Labs", + "identity": "A51CE3B9CD649C3F", + "website": "https://cosmos.polychainlabs.com", + "details": "Secure staking with Polychain Labs, the most experienced institutional grade staking team." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-04-22T04:57:29.717811274Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper146kwpzhmleafmhtaxulfptyhnvwxzlvm87hwnm", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfc7vnpgls3an0w2pv60pu4vr30p2dxqlmhmlrdv0m38y3tg689vs5qg4u5", + "jailed": false, + "status": 2, + "tokens": "85907400798", + "delegator_shares": "85907400798.000000000000000000", + "description": { + "moniker": "🌐 KysenPool.io", + "identity": "2474A8FCC4426BC5", + "website": "https://www.kysenpool.io", + "details": "Based in Silicon Valley. Help secure Cosmos by delegating to Kysen. Validators are backed by HSMs in Tier 3 enterprise-grade data centers." + }, + "unbonding_height": "0", + "unbonding_time": "2019-09-06T03:47:00.801583378Z", + "commission": { + "commission_rates": { + "rate": "0.079000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-23T06:10:09.194879379Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper14az9dmutwtz4vuycvae8csm4wwwtm0aumtlppe", + "consensus_pubkey": "cosmosvalconspub1zcjduepq59t2nm3ph5k6uc804w0n7ey69ul8ntee2dy47d7u53q248ud822sunv93j", + "jailed": false, + "status": 2, + "tokens": "1662093108440", + "delegator_shares": "1662259334359.167802676016861987", + "description": { + "moniker": "F4RM", + "identity": "181FAE6C0E4FA498", + "website": "http://www.f4rm.io", + "details": "F4RM - secure network validation \u0026 pooled digital asset staking" + }, + "unbonding_height": "546055", + "unbonding_time": "2020-02-15T08:28:57.815140271Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-15T10:36:44.571237954Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper14l0fp639yudfl46zauvv8rkzjgd4u0zk2aseys", + "consensus_pubkey": "cosmosvalconspub1zcjduepq7jsrkl9fgqk0wj3ahmfr8pgxj6vakj2wzn656s8pehh0zhv2w5as5gd80a", + "jailed": false, + "status": 2, + "tokens": "2123604959964", + "delegator_shares": "2123604959964.000000000000000000", + "description": { + "moniker": "ATEAM", + "identity": "0CB9A4E7643FF992", + "website": "nodeateam.com", + "details": "[GOS Never Jailed crew \u0026 Top-Tier] Node A-Team promises to provide validator node operation services at the highest quality" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.099000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-03-15T00:18:37.289241198Z" + }, + "min_self_delegation": "5000" + }, + { + "operator_address": "cosmosvaloper14lultfckehtszvzw4ehu0apvsr77afvyju5zzy", + "consensus_pubkey": "cosmosvalconspub1zcjduepqp0j4vum7ryt6nl6zsgq9ar347afmq2c5z6jmzeavv2p2ns6m0dgs5zmg4z", + "jailed": false, + "status": 2, + "tokens": "11307847355414", + "delegator_shares": "11307847355414.000000000000000000", + "description": { + "moniker": "DokiaCapital", + "identity": "25422F4ADF3F6765", + "website": "https://staking.dokia.cloud", + "details": "Downtime is not an option for Dokia Capital. We operate an enterprise-grade infrastructure that is robust and secure." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.150000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1k9a0cs97vul8w2vwknlfmpez6prv8klv03lv3d", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfgpyq4xk4s96ksmkfrr7juea9kmdxkl5ht94xgpxe240743u9cvsht489p", + "jailed": false, + "status": 2, + "tokens": "900489276086", + "delegator_shares": "900489276086.000000000000000000", + "description": { + "moniker": "Stake Capital", + "identity": "1DD9A932591FA928", + "website": "https://stake.capital", + "details": "\"Trustless Digital Asset Management\", Twitter: @StakeCapital, operated by @bneiluj @leopoldjoy" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.080000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.030000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1kgquh04ffqvadekf6e47070gskm0s0h28cl7ht", + "consensus_pubkey": "cosmosvalconspub1zcjduepqz76h035hfdt8tka2k4ra3cwkqn8rs6qqmjytgrnzte70qemvnzhsy7gfdu", + "jailed": false, + "status": 2, + "tokens": "25536940606", + "delegator_shares": "25536940606.000000000000000000", + "description": { + "moniker": "tokenweb.io", + "identity": "AD74AC2CC498CD7A", + "website": "https://tokenweb.io", + "details": "put your tokens to work" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-23T10:08:28.783704301Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1kgddca7qj96z0qcxr2c45z73cfl0c75p7f3s2e", + "consensus_pubkey": "cosmosvalconspub1zcjduepqay5ldqdmyzy9qfr93enxmm7cwsd5aafz6huqvczytqahpw4twa8qvtrwhv", + "jailed": false, + "status": 2, + "tokens": "568604464471", + "delegator_shares": "568604464471.000000000000000000", + "description": { + "moniker": "ChainLayer", + "identity": "AD3CDBC91802F94A", + "website": "https://www.chainlayer.io", + "details": "Secure and reliable validator. TG: https://t.me/chainlayer" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-04-01T18:02:13.514368678Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ktecz4dr56j9tsfh7nwg8s9suvhfu70qykhu5s", + "consensus_pubkey": "cosmosvalconspub1zcjduepq4euv7ertqhgvxrla583fg9g6z2v2dzrkl9spche4j4r23vukmx2q8gqvev", + "jailed": false, + "status": 2, + "tokens": "10244999999", + "delegator_shares": "10244999999.000000000000000000", + "description": { + "moniker": "Dawns.World", + "identity": "AA70E5B206F952A3", + "website": "https://dawns.world", + "details": "To discover token's intrinsic real value and enhance its liquidity" + }, + "unbonding_height": "1690790", + "unbonding_time": "2020-05-19T18:55:51.96148342Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-17T15:57:42.95929171Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1kj0h4kn4z5xvedu2nd9c4a9a559wvpuvu0h6qn", + "consensus_pubkey": "cosmosvalconspub1zcjduepqvc5xdrpvduse3fc084s56n4a6dhzudyzjmywjx25fkgw2fhsj70searwgy", + "jailed": false, + "status": 2, + "tokens": "1556931328488", + "delegator_shares": "1556931328488.000000000000000000", + "description": { + "moniker": "Cryptium Labs", + "identity": "5A309B5CA189D8B3", + "website": "https://cryptium.ch", + "details": "Secure and available validation from the Swiss Alps" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.110000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-27T11:16:35.284063151Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1kn3wugetjuy4zetlq6wadchfhvu3x740ae6z6x", + "consensus_pubkey": "cosmosvalconspub1zcjduepqc8slfqdszcd85wzzweuanv0em4h4gdc5wkh3et6e7t8z93z24u0s0rdlx2", + "jailed": false, + "status": 2, + "tokens": "2142209666422", + "delegator_shares": "2142209666422.000000000000000000", + "description": { + "moniker": "HuobiPool", + "identity": "23536C5BDE3EB949", + "website": "https://www.huobipool.com/", + "details": "Huobi Pool is a sub-brand of Huobi Group, which is an important part of the global ecological strategy of Huobi.Huobi Pool has become one of the largest POS communities in the Asia- Pacific region, the leading POW pool and nodes of a number of public chains." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.040000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-14T01:41:12.728555379Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1hvsdf03tl6w5pnfvfv5g8uphjd4wfw2h4gvnl7", + "consensus_pubkey": "cosmosvalconspub1zcjduepq5l63vgd8m9chc3c32wn5lthzsax6xxdylpzmhqmjwrgfhd3m2swsj2wc2d", + "jailed": false, + "status": 2, + "tokens": "100005083421", + "delegator_shares": "100015084598.752158521030469918", + "description": { + "moniker": "Atom.Bi23", + "identity": "EB3470949B3E89E2", + "website": "https://atom.bi23.com", + "details": "Bi23 focuses on the Crypto-Assets, providing customers with Staking and DeFi services." + }, + "unbonding_height": "0", + "unbonding_time": "2019-08-16T15:34:04.702756371Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-11T04:30:32.134491966Z" + }, + "min_self_delegation": "2" + }, + { + "operator_address": "cosmosvaloper1hjct6q7npsspsg3dgvzk3sdf89spmlpfdn6m9d", + "consensus_pubkey": "cosmosvalconspub1zcjduepqnltddase4lqjcfhup8ymg0qex3srakg54ppv06pstvwdjxkm6tmq08znvs", + "jailed": false, + "status": 2, + "tokens": "4532884973675", + "delegator_shares": "4532884973675.000000000000000000", + "description": { + "moniker": "Figment Networks", + "identity": "E5F274B870BDA01D", + "website": "https://figment.network", + "details": "Makers of Hubble and Canada’s largest Cosmos validator, Figment is the easiest and most secure way to stake your Atoms." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.090000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-06T12:17:54.693866931Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1crqm3598z6qmyn2kkcl9dz7uqs4qdqnr6s8jdn", + "consensus_pubkey": "cosmosvalconspub1zcjduepqt0fpxxufuuhavfqh8zg3pjnnwdvvzw9huemzxe59kpjt5e3xprhs7d8khn", + "jailed": false, + "status": 2, + "tokens": "449558836978", + "delegator_shares": "449558836978.000000000000000000", + "description": { + "moniker": "Bison Trails", + "identity": "A296556FF603197C", + "website": "bisontrails.co", + "details": "Bison Trails is the easiest way to run infrastructure on multiple blockchains." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.080000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-10-30T20:21:03.030621767Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1cgh5ksjwy2sd407lyre4l3uj2fdrqhpkzp06e6", + "consensus_pubkey": "cosmosvalconspub1zcjduepq3f6wnsk6k6qu6g8n5vly4z7ajw7q930wh3qx6zkxhktnh49l40kszf5lry", + "jailed": false, + "status": 2, + "tokens": "930138172612", + "delegator_shares": "930138172612.000000000000000000", + "description": { + "moniker": "HashQuark", + "identity": "31AFBBE0A52FA1ED", + "website": "https://www.hashquark.io", + "details": "Staking made easier!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-10-23T02:48:39.22540691Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1clpqr4nrk4khgkxj78fcwwh6dl3uw4epsluffn", + "consensus_pubkey": "cosmosvalconspub1zcjduepq0dc9apn3pz2x2qyujcnl2heqq4aceput2uaucuvhrjts75q0rv5smjjn7v", + "jailed": false, + "status": 2, + "tokens": "6046984071675", + "delegator_shares": "6046984071675.000000000000000000", + "description": { + "moniker": "Cosmostation", + "identity": "AE4C403A6E7AA1AC", + "website": "https://www.cosmostation.io", + "details": "CØSMOSTATION Validator. Delegate your atoms and Start Earning Staking Rewards" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "10" + }, + { + "operator_address": "cosmosvaloper1ey69r37gfxvxg62sh4r0ktpuc46pzjrm873ae8", + "consensus_pubkey": "cosmosvalconspub1zcjduepqg6y8magedjwr9p6s2c28zp28jdjtecxhn97ew6tnuzqklg63zgfspp9y3n", + "jailed": false, + "status": 2, + "tokens": "10377079380247", + "delegator_shares": "10377079378738.906130852393635459", + "description": { + "moniker": "Sikka", + "identity": "https://keybase.io/team/sikka", + "website": "sikka.tech", + "details": "Sunny Aggarwal (@sunnya97) and Dev Ojha (@ValarDragon)" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-01T04:08:08.548659287Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1et77usu8q2hargvyusl4qzryev8x8t9wwqkxfs", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfx0p8s3gmxmaftkkazw5wag4sfau3vgcn20ut4dn5rv2nr8ddq2s59rnvq", + "jailed": false, + "status": 2, + "tokens": "15846947873", + "delegator_shares": "15846947873.000000000000000000", + "description": { + "moniker": "👾replicator.network", + "identity": "9203983F91296B66", + "website": "https://replicator.network", + "details": "" + }, + "unbonding_height": "1686743", + "unbonding_time": "2020-05-19T11:00:40.160158437Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2020-04-28T19:23:18.063971937Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1e0plfg475phrsvrlzw8gwppeva0zk5yg9fgg8c", + "consensus_pubkey": "cosmosvalconspub1zcjduepqz83dmnt4g6w0w6syrf433mwpk86zejxnq6e336xtxd8pg9jtxkgq732tpu", + "jailed": false, + "status": 2, + "tokens": "331721337159", + "delegator_shares": "331721337159.000000000000000000", + "description": { + "moniker": "Easy 2 Stake", + "identity": "2C877AC873132C91", + "website": "www.easy2stake.com", + "details": "Easy.Stake.Trust. as easy and as simple as you would click next. Complete transparency and trust with a secure and stable validator. GoS winner, Never Jailed Crew" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-09-27T08:35:53.771679331Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fz4sdg3", + "consensus_pubkey": "cosmosvalconspub1zcjduepq8hu49qdl5594rzxmdsww3hleu8phxrajjfsseqjere9mjrrrv9tq35mll4", + "jailed": false, + "status": 2, + "tokens": "2150370557522", + "delegator_shares": "2150370557522.000000000000000000", + "description": { + "moniker": "BouBouNode", + "identity": "", + "website": "https://boubounode.com", + "details": "AI-based Validator. #1 AI Validator on Game of Stakes. Fairly priced. Don't trust (humans), verify. Made with BouBou love." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.061000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ehkfl7palwrh6w2hhr2yfrgrq8jetgucudztfe", + "consensus_pubkey": "cosmosvalconspub1zcjduepqvmmhug9hcmm26ce7we0n3esavn4c6tfcfd6zgnuj732ls7khjq4srpg0ft", + "jailed": false, + "status": 2, + "tokens": "1177437103283", + "delegator_shares": "1177437103283.000000000000000000", + "description": { + "moniker": "KalpaTech", + "identity": "B4AD06F0EB355573", + "website": "http://kalpatech.co", + "details": "KalpaTech | Genesis Validator | Game of Stakes winner | Services dedicated exclusively for Cosmos Hub | All resources put in one network" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-28T22:00:22.763748595Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ec3p6a75mqwkv33zt543n6cnxqwun37rr5xlqv", + "consensus_pubkey": "cosmosvalconspub1zcjduepqd85nu5nelvcyyzcsrr0yaglh8rfvn6cv9pp3p0hgmwtk8hf3cazqc7vz5c", + "jailed": false, + "status": 2, + "tokens": "1016350149259", + "delegator_shares": "1016350149259.000000000000000000", + "description": { + "moniker": "lunamint", + "identity": "4F26823468DD7518", + "website": "https://lunamint.com", + "details": "Always adding value to Cosmos. Check out Lunagram, the Cosmos wallet built into Telegram." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1emaa7mwgpnpmc7yptm728ytp9quamsvu837nc0", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfuxvufupnsm7v5anpwd7z8ec70z2k209j7xclnm25zz7vauhyc5qjgxx3h", + "jailed": false, + "status": 2, + "tokens": "525680707649", + "delegator_shares": "525680707649.000000000000000000", + "description": { + "moniker": "kochacolaj", + "identity": "1E9CE94FD0BA5CFEB901F90BC658D64D85B134D2", + "website": "https://blog.cosmos.network/game-of-stakes-closing-ceremonies-eddb71d3b114#147d", + "details": "Top 5 Game Of Stakes winner" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-04-25T14:55:05.718968098Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1eup5t8pp8jq354heck53qtama7vss9l354kh6r", + "consensus_pubkey": "cosmosvalconspub1zcjduepqxh4s2zj52uhfssu7u2xyhmnk5f7g9ty368twxkkcfllsq3fqaw9sdl6rj9", + "jailed": false, + "status": 2, + "tokens": "10436859212", + "delegator_shares": "10436859212.000000000000000000", + "description": { + "moniker": "IZ0", + "identity": "BF964D76855711CC", + "website": "www.izo.ro", + "details": "Izo Data Network ! Commission is 0% . Please join our [community](https://t.me/IzoData) or visit [website](https://www.izo.ro/)! " + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.100000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-12-26T08:56:10.399933806Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper16qme5yxucnaj6snx35nmwze0wyxr8wfgqxsqfw", + "consensus_pubkey": "cosmosvalconspub1zcjduepqwnhw3azrlhnx9kaujvn0es9u26e4a3af6hye6e9j0pl2tlpx9k3s59zwh0", + "jailed": false, + "status": 2, + "tokens": "328202291816", + "delegator_shares": "328202291816.000000000000000000", + "description": { + "moniker": "KIRA Staking", + "identity": "C86C8FF08A5269DC", + "website": "https://kiraex.com", + "details": "Kira Core Staking Services - Sentry, KMS, HSM, High Availability \u0026 Double Sign Protection" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-05-01T18:39:34.037797682Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper16zgjnqxryhq2kftfuv8urp50x0xwt5dagemhfl", + "consensus_pubkey": "cosmosvalconspub1zcjduepqeumluaf7n7ss9qmaj43v4gd4dzj5jfw7cdnn6vngwd2m7gmu48lqsyy3wa", + "jailed": false, + "status": 2, + "tokens": "1000040000000", + "delegator_shares": "1000040000000.000000000000000000", + "description": { + "moniker": "Alphemy Capital", + "identity": "78DAB5C26CB56856", + "website": "https://alphemy.capital", + "details": "Institutional grade staking for clients of Alphemy Capital." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-20T19:33:55.395872948Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper16v3f95amtvpewuajjcdsvaekuuy4yyzups85ec", + "consensus_pubkey": "cosmosvalconspub1zcjduepqmgwzcm3aqmc8nln9u4q5ydsjwx6rzqrch6p243x2gtzetnx5l3ls432euv", + "jailed": false, + "status": 2, + "tokens": "293516903946", + "delegator_shares": "293516903946.000000000000000000", + "description": { + "moniker": "BlockPool", + "identity": "", + "website": "www.blockpool.com", + "details": "Power the staking economy" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "0.030000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-06-22T05:19:17.897735561Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1648ynlpdw7fqa2axt0w2yp3fk542junl7rsvq6", + "consensus_pubkey": "cosmosvalconspub1zcjduepqf8llkc4p43lksktsqzr5nmgmw4ln9pzym2vp4kqfrny8xrgnqrsq76djjc", + "jailed": false, + "status": 2, + "tokens": "955816857915", + "delegator_shares": "955912449090.690555765999702861", + "description": { + "moniker": "Any Labs", + "identity": "B2D07CA3CCC907CE", + "website": "https://anylabs.io", + "details": "Blockchain staking and consultancy based in Japan." + }, + "unbonding_height": "25880", + "unbonding_time": "2020-01-03T18:48:44.276425288Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-05-08T11:30:02.004384504Z" + }, + "min_self_delegation": "100" + }, + { + "operator_address": "cosmosvaloper16k579jk6yt2cwmqx9dz5xvq9fug2tekvlu9qdv", + "consensus_pubkey": "cosmosvalconspub1zcjduepq55mjplg9gy979ua9r5qmk2wr5nysmputt28j0zsgadn933lyh32sh20cmm", + "jailed": false, + "status": 2, + "tokens": "931176202093", + "delegator_shares": "931269329007.764829857979365790", + "description": { + "moniker": "Cephalopod Equipment", + "identity": "6408AA029ADBE364", + "website": "https://cephalopod.equipment", + "details": "Cephalopod Equipment - infrastructure for decentralized intelligence" + }, + "unbonding_height": "0", + "unbonding_time": "2019-12-01T09:34:39.548038382Z", + "commission": { + "commission_rates": { + "rate": "0.081100000000000000", + "max_rate": "0.420000000000000000", + "max_change_rate": "0.011800000000000000" + }, + "update_time": "2019-09-19T12:26:43.48042061Z" + }, + "min_self_delegation": "100000" + }, + { + "operator_address": "cosmosvaloper1mykn77lkynl8fkwvl9tqg369u0zajzzcdhkptq", + "consensus_pubkey": "cosmosvalconspub1zcjduepqft6uxfmfjjce0p7ke4h0zc38x4d9d38wlmrgcc47flru92qq3ydq76mrsf", + "jailed": false, + "status": 2, + "tokens": "88053542555", + "delegator_shares": "88053542555.000000000000000000", + "description": { + "moniker": "Nodeasy.com", + "identity": "AB006A79DBD8FC57", + "website": "https://www.nodeasy.com", + "details": "Nodeasy.com,助你进入Staking时代!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-10-28T13:02:55.182998044Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1m83cwjucw9nt8xm66u8xavvy6v9m7xfspcszc5", + "consensus_pubkey": "cosmosvalconspub1zcjduepq7qnf5r40z7esjc2utrjrvzxg9sfd683hw0805ek85ddchdcptthqjnzxxu", + "jailed": false, + "status": 2, + "tokens": "160362681331", + "delegator_shares": "160362681331.000000000000000000", + "description": { + "moniker": "Fenbushi US - Staked", + "identity": "CC4B238C8F9FB2BE", + "website": "https://fenbushi.vc", + "details": "Fenbushi Capital is the first and most active blockchain-focused venture capital firm in Asia. Staked is the leading provider of validation technology and services. We're bringing our combined skills to Cosmos." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T18:07:08.897219336Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ma02nlc7lchu7caufyrrqt4r6v2mpsj90y9wzd", + "consensus_pubkey": "cosmosvalconspub1zcjduepqxtu8am2qmf0qnglqtvkar9gaclhccfn29tsp7n82vasrtnc8m2fsulp4h2", + "jailed": false, + "status": 2, + "tokens": "3441815546707", + "delegator_shares": "3441815546707.000000000000000000", + "description": { + "moniker": "hashtower", + "identity": "0BBBAE1FD11AEBAF", + "website": "http://hashtower.com", + "details": "Hashtower Actwo COSMOS Validator" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.200000000000000000" + }, + "update_time": "2019-07-16T08:46:06.560077744Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1uxh465053nq3at4dn0jywgwq3s9sme3la3drx6", + "consensus_pubkey": "cosmosvalconspub1zcjduepqc5y2du793cjut0cn6v7thp3xlvphggk6rt2dhw9ekjla5wtkm7nstmv5vy", + "jailed": false, + "status": 2, + "tokens": "520172159921", + "delegator_shares": "520172159921.000000000000000000", + "description": { + "moniker": "Bison Trails", + "identity": "A296556FF603197C", + "website": "https://bisontrails.co", + "details": "Bison Trails is the easiest way to run infrastructure on multiple blockchains." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1uhnsxv6m83jj3328mhrql7yax3nge5svrv6t6c", + "consensus_pubkey": "cosmosvalconspub1zcjduepql42t7mstnewp5rgweteuw95hawzystll7mq8dl24n5yh0th7q2jqetcy07", + "jailed": false, + "status": 2, + "tokens": "720894765456", + "delegator_shares": "720966862061.597270834863362006", + "description": { + "moniker": "Skystar Capital", + "identity": "", + "website": "", + "details": "" + }, + "unbonding_height": "1168707", + "unbonding_time": "2020-04-06T17:50:47.447745873Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1u6ddcsjueax884l3tfrs66497c7g86skn7pa0u", + "consensus_pubkey": "cosmosvalconspub1zcjduepq87zcnf8sm4ewacjafqujfevt8rhwj5qk9uwtx4ef89ctuqmndkeq446ahw", + "jailed": false, + "status": 2, + "tokens": "809352867566", + "delegator_shares": "809352867566.000000000000000000", + "description": { + "moniker": "Sentinel", + "identity": "D54C8032CF19C407", + "website": "https://sentinel.co", + "details": "We are team Sentinel, developer of infrastructure tools on Cosmos \u0026 other networks.Winner in the Uptime category during GOS.Developed the first working version of the dVPN which runs on Ethereum \u0026 Sentinel's own Tendermint TestNet" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-04-29T05:17:01.930702784Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "cosmosvaloper1uutuwrwt3z2a5z8z3uasml3rftlpmu25aga5c6", + "consensus_pubkey": "cosmosvalconspub1zcjduepqarrl0ppddzyczwvcqwf3jwd9qwkhxfy6lcv8ep4msk293mlxg39qgf77y3", + "jailed": false, + "status": 2, + "tokens": "908236212795", + "delegator_shares": "908236212795.000000000000000000", + "description": { + "moniker": "Delega Networks♾ ", + "identity": "1BED7C08416A619F", + "website": "https://delega.io", + "details": "Validador con énfasis en la comunidad de habla hispana, validando bloques en Cosmos desde el 2018. Mantenemos nuestra infraestructura segura y fiable el 99% del tiempo. Nodos manejados por Wimel.|N0∞D0|" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-05-06T03:25:11.392136982Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1ul2me6vukg2vac2p6ltxmqlaa7jywdgt8q76ag", + "consensus_pubkey": "cosmosvalconspub1zcjduepq0cet8ez89wj4yz8uencych7aldc5wyyrpx6jvh6n6kxxslumln5sxkq922", + "jailed": false, + "status": 2, + "tokens": "1219102963218", + "delegator_shares": "1219102963218.000000000000000000", + "description": { + "moniker": "HyperblocksPro", + "identity": "B073FA5BAD230585", + "website": "https://hyperblocks.pro/", + "details": "Secure the network and earn rewards with Hyperblocks.pro, one of the first companies in the world fully focused on Proof Of Stake protocols" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-04-05T23:57:19.320271237Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", + "consensus_pubkey": "cosmosvalconspub1zcjduepqc9ppxzktam9v39d9q07h6n98cdm7cgg4l65vq5yvtgruxp5h0yhs8tup68", + "jailed": false, + "status": 2, + "tokens": "572757556709", + "delegator_shares": "572757556709.000000000000000000", + "description": { + "moniker": "FRESHATOMS", + "identity": "63575EE3F0F9FAFC", + "website": "https://freshatoms.com", + "details": "FreshAtoms runs on bare metal in a SSAE16 SOC2 certified Tier 3 datacenter with geographically distributed private sentry nodes, YubiHSM2 hardware protected keys, with 24/7 monitoring, alerting, and analytics." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-09-23T20:29:05.781322875Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper17cy09npjq4sylkt56kwcuqcd74hlxj3fq4hwjd", + "consensus_pubkey": "cosmosvalconspub1zcjduepq4hwm4ev9d9cmg4v5sqkscmsy6g0qnhrskmhgacjux2l35lulfg8svx5ywk", + "jailed": false, + "status": 2, + "tokens": "13002678600", + "delegator_shares": "13006580000.000000000000000000", + "description": { + "moniker": "topool", + "identity": "9A866486C2AADA48", + "website": "http://topool.io", + "details": "The world's top PoS and Staking service providers in the future" + }, + "unbonding_height": "1840453", + "unbonding_time": "2020-06-01T00:43:55.825880187Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.200000000000000000" + }, + "update_time": "2020-05-01T03:41:16.979171357Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper17mggn4znyeyg25wd7498qxl7r2jhgue8u4qjcq", + "consensus_pubkey": "cosmosvalconspub1zcjduepqlzmd0spn9m0m3eq9zp93d4w6e5tugamv44yqjzyacelnvra634fqnfec0r", + "jailed": false, + "status": 2, + "tokens": "1079735204356", + "delegator_shares": "1079735204356.000000000000000000", + "description": { + "moniker": "01node", + "identity": "22823CD59617B8E3", + "website": "https://01node.com", + "details": "01node Professional Staking Services for Cosmos, Iris, Terra, Solana, Kava, Polkadot, Skale" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-03-13T23:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1l9fwl9c77zx850htsr20pq3ltc379xt86ndelm", + "consensus_pubkey": "cosmosvalconspub1zcjduepqfjgjrj4heptaw6h9nhtkng8hw2zsq5c6e9xzwvnjjx2n6pc7x6yq4ny2qc", + "jailed": false, + "status": 2, + "tokens": "10466688923", + "delegator_shares": "10466688923.000000000000000000", + "description": { + "moniker": "CosmosLink", + "identity": "3F7807C66CE770B0", + "website": "cosmoslink.network", + "details": "Based on Cosmos network digital asset security value-added service provider" + }, + "unbonding_height": "1276519", + "unbonding_time": "2020-04-15T17:26:54.325724353Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-18T16:46:59.079404223Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1lktjhnzkpkz3ehrg8psvmwhafg56kfss3q3t8m", + "consensus_pubkey": "cosmosvalconspub1zcjduepqelcwpat987h9yq0ck6g9fsc8t0mththk547gwvk0w4wnkpl0stnspr3hdc", + "jailed": false, + "status": 2, + "tokens": "1655592831912", + "delegator_shares": "1655592831912.000000000000000000", + "description": { + "moniker": "Umbrella ☔", + "identity": "A530AC4D75991FE2", + "website": "https://umbrellavalidator.com", + "details": "One of the winners of Cosmos Game of Stakes, and HackAtom3." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070400000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-08-05T07:10:23.689753607Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1lcwxu50rvvgf9v6jy6q5mrzyhlszwtjxhtscmp", + "consensus_pubkey": "cosmosvalconspub1zcjduepqh3jg5ld5xg5q5mcxrzn6fcuq696qqa3ut3azskphpdrty37ervjqcn8mfj", + "jailed": false, + "status": 2, + "tokens": "10717165430", + "delegator_shares": "10717165430.000000000000000000", + "description": { + "moniker": "stake.zone", + "identity": "0A888728046018EC", + "website": "http://stake.zone", + "details": "operated by nuevax" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2020-02-13T02:20:41.320594366Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1l6udzyaz8xaxv4hpagwauacm95jlcec3xlht2u", + "consensus_pubkey": "cosmosvalconspub1zcjduepq9t4r8jgr09rsscgacnaklxuf55pg0wq5zfwzw8ycawms5x0hrfhqks3dpe", + "jailed": false, + "status": 2, + "tokens": "12941250441", + "delegator_shares": "12941250441.000000000000000000", + "description": { + "moniker": "StakeHouse", + "identity": "A1AAB1D6D0E8F976", + "website": "stakehouse.org", + "details": "Low fees. No hassle. Enjoy your meal." + }, + "unbonding_height": "701066", + "unbonding_time": "2020-02-28T02:04:00.114690756Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-02-11T07:24:35.723449554Z" + }, + "min_self_delegation": "1" + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/cosmos-api_txs__limit_25_message.sender_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_page_1.json b/mock/ext-api-data/cosmos-api_txs__limit_25_message.sender_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_page_1.json new file mode 100644 index 000000000..5ea048ea1 --- /dev/null +++ b/mock/ext-api-data/cosmos-api_txs__limit_25_message.sender_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq_page_1.json @@ -0,0 +1,308 @@ +{ + "total_count": "2", + "count": "2", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "26616", + "txhash": "3FEE8F10FBA5505DE2A8D3EF220D5CE900CA76B96208234BBF89B8075743A230", + "data": "0C0886C1BEF00510E7FFF6F801", + "raw_log": "[{\"msg_index\":0,\"success\":true,\"log\":\"\",\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"sender\",\"value\":\"cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl\"},{\"key\":\"sender\",\"value\":\"cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh\"},{\"key\":\"module\",\"value\":\"staking\"},{\"key\":\"sender\",\"value\":\"cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq\"},{\"key\":\"action\",\"value\":\"begin_unbonding\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq\"},{\"key\":\"amount\",\"value\":\"1147uatom\"},{\"key\":\"recipient\",\"value\":\"cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r\"},{\"key\":\"amount\",\"value\":\"2203000uatom\"}]},{\"type\":\"unbond\",\"attributes\":[{\"key\":\"validator\",\"value\":\"cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5\"},{\"key\":\"amount\",\"value\":\"2203000\"},{\"key\":\"completion_time\",\"value\":\"2020-01-03T20:13:58Z\"}]}]}]", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "127111", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgUndelegate", + "value": { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", + "amount": { + "denom": "uatom", + "amount": "2203000" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" + }, + "signature": "fJkOgQX9FZz6UJJo48AA3qxc2v/vFrjxlMgq3iOhDmVUWjA2P6X+pPbPkSB1SHlBFlVbsNF/DDPB0pvP9LRPTg==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-12-13T20:13:58Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + }, + { + "height": "404179", + "txhash": "93E43518BAE4BC137605BBB7FD5D31FDAE6427ECE57EC299C43CE786FDAEBC63", + "raw_log": "[{\"msg_index\":0,\"success\":true,\"log\":\"\",\"events\":[{\"type\":\"delegate\",\"attributes\":[{\"key\":\"validator\",\"value\":\"cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh\"},{\"key\":\"amount\",\"value\":\"2211271\"}]},{\"type\":\"message\",\"attributes\":[{\"key\":\"module\",\"value\":\"staking\"},{\"key\":\"sender\",\"value\":\"cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq\"},{\"key\":\"action\",\"value\":\"delegate\"}]}]}]", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "delegate", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh" + }, + { + "key": "amount", + "value": "2211271" + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "delegate" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "93720", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgDelegate", + "value": { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", + "amount": { + "denom": "uatom", + "amount": "2211271" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" + }, + "signature": "X1/NzRdb+HUxE7N9gMk39XI8TyHFobLRQtsX4QxZZbYeKmEYOOZ7FyNSGqgmipCkpuysBeh6fNnbXmo3IFzFEQ==" + } + ], + "memo": "" + } + }, + "timestamp": "2020-01-13T15:23:12Z", + "events": [ + { + "type": "delegate", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh" + }, + { + "key": "amount", + "value": "2211271" + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "delegate" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/cosmos-api_txs__limit_25_page_1_transfer.recipient_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json b/mock/ext-api-data/cosmos-api_txs__limit_25_page_1_transfer.recipient_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json new file mode 100644 index 000000000..ca5fac28d --- /dev/null +++ b/mock/ext-api-data/cosmos-api_txs__limit_25_page_1_transfer.recipient_cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq.json @@ -0,0 +1,192 @@ +{ + "total_count": "1", + "count": "1", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "26616", + "txhash": "3FEE8F10FBA5505DE2A8D3EF220D5CE900CA76B96208234BBF89B8075743A230", + "data": "0C0886C1BEF00510E7FFF6F801", + "raw_log": "[{\"msg_index\":0,\"success\":true,\"log\":\"\",\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"sender\",\"value\":\"cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl\"},{\"key\":\"sender\",\"value\":\"cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh\"},{\"key\":\"module\",\"value\":\"staking\"},{\"key\":\"sender\",\"value\":\"cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq\"},{\"key\":\"action\",\"value\":\"begin_unbonding\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq\"},{\"key\":\"amount\",\"value\":\"1147uatom\"},{\"key\":\"recipient\",\"value\":\"cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r\"},{\"key\":\"amount\",\"value\":\"2203000uatom\"}]},{\"type\":\"unbond\",\"attributes\":[{\"key\":\"validator\",\"value\":\"cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5\"},{\"key\":\"amount\",\"value\":\"2203000\"},{\"key\":\"completion_time\",\"value\":\"2020-01-03T20:13:58Z\"}]}]}]", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "127111", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgUndelegate", + "value": { + "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", + "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", + "amount": { + "denom": "uatom", + "amount": "2203000" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" + }, + "signature": "fJkOgQX9FZz6UJJo48AA3qxc2v/vFrjxlMgq3iOhDmVUWjA2P6X+pPbPkSB1SHlBFlVbsNF/DDPB0pvP9LRPTg==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-12-13T20:13:58Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "sender", + "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" + }, + { + "key": "module", + "value": "staking" + }, + { + "key": "sender", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "action", + "value": "begin_unbonding" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" + }, + { + "key": "amount", + "value": "1147uatom" + }, + { + "key": "recipient", + "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" + }, + { + "key": "amount", + "value": "2203000uatom" + } + ] + }, + { + "type": "unbond", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "2203000" + }, + { + "key": "completion_time", + "value": "2020-01-03T20:13:58Z" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/dash-api_v2_address_XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG__details_txs.json b/mock/ext-api-data/dash-api_v2_address_XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG__details_txs.json new file mode 100644 index 000000000..1780f71a1 --- /dev/null +++ b/mock/ext-api-data/dash-api_v2_address_XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":73,"itemsOnPage":10,"address":"XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG","balance":"32621341881","totalReceived":"146027501461","totalSent":"113406159580","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":723,"transactions":[{"txid":"3db4dca70f007a6f9c20216d275a7817081f6ac0054c4080f42ec4a49ff9bd79","version":3,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"031772131a4d696e656420627920416e74506f6f6c347c002900202864bcf5865e0000ce290000"}],"vout":[{"value":"144313387","n":0,"hex":"76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac","addresses":["XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG"],"isAddress":true},{"value":"144313393","n":1,"hex":"76a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac","addresses":["Xb8cmjtK67y9T2haqrcDicoAMByDesLcAe"],"isAddress":true}],"blockHash":"0000000000000005db43b81ebbe8022ab3197b6ab4f75ff9fec25025181cb4eb","blockHeight":1274391,"confirmations":147,"blockTime":1590046619,"value":"288626780","valueIn":"0","fees":"0","hex":"03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff27031772131a4d696e656420627920416e74506f6f6c347c002900202864bcf5865e0000ce290000ffffffff022b0c9a08000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac310c9a08000000001976a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac0000000046020017721300b486d6efc4d82a46ef1d7fc6d892b988c55fa758cf48cfb4d359c4a43a30bc46398c15d48d495949a7ed6d7d56f681f7268e59d9091c810f2063773f2d97bb0c"},{"txid":"17cabd36cf9308d70f603c00ed4d29c6d448ee26a27d7bff080df7d516b0629c","version":3,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"031672131a4d696e656420627920416e74506f6f6c35fd003d00202811e2c39b7a0000af040000"}],"vout":[{"value":"144262270","n":0,"hex":"76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac","addresses":["XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG"],"isAddress":true},{"value":"144262289","n":1,"hex":"76a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac","addresses":["Xb8cmjtK67y9T2haqrcDicoAMByDesLcAe"],"isAddress":true}],"blockHash":"0000000000000007e165a9ffee645c50b4456718ad39faace1632b9cb378e005","blockHeight":1274390,"confirmations":148,"blockTime":1590046566,"value":"288524559","valueIn":"0","fees":"0","hex":"03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff27031672131a4d696e656420627920416e74506f6f6c35fd003d00202811e2c39b7a0000af040000ffffffff027e449908000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac91449908000000001976a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac0000000046020016721300b486d6efc4d82a46ef1d7fc6d892b988c55fa758cf48cfb4d359c4a43a30bc46398c15d48d495949a7ed6d7d56f681f7268e59d9091c810f2063773f2d97bb0c"},{"txid":"97a2fd473a553493b1ade2f68d013e32b67fdb140efa34c8ac95953bc1988bcf","version":3,"vin":[{"n":0,"isAddress":false,"coinbase":"03067213044524c65e08fabe6d6d000000002f6c6f6f5063746279432f0b00002eb26646e95f000000000000000101000000000000005fe9469e351e00000b2f4379627463506f6f6c2f"}],"vout":[{"value":"144236253","n":0,"hex":"76a914ed148451671949d7353471ee5ef203d424cfbc0a88ac","addresses":["XxJQZFhLtGYz97zH92Zs4QUSF8ej6K6Qwc"],"isAddress":true},{"value":"144236247","n":1,"hex":"76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac","addresses":["XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG"],"isAddress":true}],"blockHash":"000000000000000bea9a32a25b8b36b21d6e20a387a7b5c9189a57539290f8d7","blockHeight":1274374,"confirmations":164,"blockTime":1590043717,"value":"288472500","valueIn":"0","fees":"0","hex":"03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff4a03067213044524c65e08fabe6d6d000000002f6c6f6f5063746279432f0b00002eb26646e95f000000000000000101000000000000005fe9469e351e00000b2f4379627463506f6f6c2f0000000002ddde9808000000001976a914ed148451671949d7353471ee5ef203d424cfbc0a88acd7de9808000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac0000000046020006721300b486d6efc4d82a46ef1d7fc6d892b988c55fa758cf48cfb4d359c4a43a30bc466316990da5dbe77116b1dcb017f680b8f7f75f81254a5a7830fc8dd96cf94f89"},{"txid":"b4a0cc5bd09002efb169cc915b962f2362818d82862b384d169252fdb74e6c8e","version":3,"vin":[{"n":0,"isAddress":false,"coinbase":"03e1701304d96ec55e08fabe6d6d000000011d1c1fbf717559b370b05f48978c7cf9bc8f41ea83d251fd2000000001000000000000005fe94eecf74c00000b2f4379627463506f6f6c2f"}],"vout":[{"value":"144236253","n":0,"hex":"76a914ed148451671949d7353471ee5ef203d424cfbc0a88ac","addresses":["XxJQZFhLtGYz97zH92Zs4QUSF8ej6K6Qwc"],"isAddress":true},{"value":"144236247","n":1,"hex":"76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac","addresses":["XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG"],"isAddress":true}],"blockHash":"00000000000000081d7638e9faaccbaa8a11a92381b420e3bd75f1267ad8c33d","blockHeight":1274081,"confirmations":457,"blockTime":1589997273,"value":"288472500","valueIn":"0","fees":"0","hex":"03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff4a03e1701304d96ec55e08fabe6d6d000000011d1c1fbf717559b370b05f48978c7cf9bc8f41ea83d251fd2000000001000000000000005fe94eecf74c00000b2f4379627463506f6f6c2f0000000002ddde9808000000001976a914ed148451671949d7353471ee5ef203d424cfbc0a88acd7de9808000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac00000000460200e1701300eb6914c8accb8b7a0d350d0a70fd815d207c11dd2b8949d25cdae2c771b27e23209ee13c7e4ce98664264382e4041e6102dfe7c1441d375e5ae544b86ebcedbd"},{"txid":"4df67627b300f5dbfd59203fb17a7c606db089e77897cec0ec9bc973ab59ecdd","version":3,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"03a8701304184fc55e01000153aa2b000000000000"}],"vout":[{"value":"144548387","n":0,"hex":"76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac","addresses":["XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG"],"isAddress":true},{"value":"144548393","n":1,"hex":"76a91417158751f496276811c148495b28915314dd9fc088ac","addresses":["XcnuAVsG4pRCqxQmQB6PeTX8FJo2ssYPyB"],"isAddress":true}],"blockHash":"00000000000000114068e5f0b37266e8482d2fb61a2ffae5d4d02aeb8843ddd4","blockHeight":1274024,"confirmations":514,"blockTime":1589989156,"value":"289096780","valueIn":"0","fees":"0","hex":"03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff1503a8701304184fc55e01000153aa2b000000000000ffffffff0223a29d08000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac29a29d08000000001976a91417158751f496276811c148495b28915314dd9fc088ac00000000460200a87013007aa39890eaa3d3ad98bcf87390534ef109340e16ce4d2fbed4502d833a703312fa56b0bcd3dabf298ff9fabd00e5a906439b7cdca43e84f9a35fc54e2300b398"},{"txid":"13456921c40297a1e7c22ac32864c8c93f6aa8033ec1a9cdda28769998e427ef","version":3,"vin":[{"n":0,"isAddress":false,"coinbase":"03c66f131b5c4c55584f525c00000000bdf779f74ec2dd6dfc4a387e8f040000"}],"vout":[{"value":"144263769","n":0,"spent":true,"hex":"76a9148bf9a55d3864e49d0bb9f8cc75b6ab3949526ab888ac","addresses":["XoSxpd5VYNQvKbXbEaDKt6P1aZANzAkXrJ"],"isAddress":true},{"value":"144263750","n":1,"hex":"76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac","addresses":["XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG"],"isAddress":true}],"blockHash":"0000000000000011516ab91ba1ecb91b72e59eb4277f53595c91a438624e00a0","blockHeight":1273798,"confirmations":740,"blockTime":1589954367,"value":"288527519","valueIn":"0","fees":"0","hex":"03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff2003c66f131b5c4c55584f525c00000000bdf779f74ec2dd6dfc4a387e8f0400000000000002594a9908000000001976a9148bf9a55d3864e49d0bb9f8cc75b6ab3949526ab888ac464a9908000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac00000000460200c66f1300e8af15b313aaac73fe3b9fa249e138f50fee346803e2da15832d76eb851560d64fc1a256ba8f923ccda8a9a717b309208171399e34a5bb11ff16a52eaa5c8410"},{"txid":"18063c38154b6072e09be08293e0f4dc39379ae2c40bc09ee6b73b3bd4844dc5","version":3,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"03686f131d2f5669614254432f4d696e656420627920747275646f766f737475362f10303c2d0130a1ecf6892c72d6d4040000"}],"vout":[{"value":"144263186","n":0,"spent":true,"hex":"76a914bc89d6071dabc5b4494d303af761a052a5c70d5788ac","addresses":["XssjzLKgsfATYGqTQmiJURQzeKdpL5K1k3"],"isAddress":true},{"value":"144263181","n":1,"hex":"76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac","addresses":["XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG"],"isAddress":true}],"blockHash":"000000000000001f5a78354319984517bad7aba7aff7927e7bad64b2a1bf26f1","blockHeight":1273704,"confirmations":834,"blockTime":1589939700,"value":"288526367","valueIn":"0","fees":"0","hex":"03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff3303686f131d2f5669614254432f4d696e656420627920747275646f766f737475362f10303c2d0130a1ecf6892c72d6d4040000ffffffff0212489908000000001976a914bc89d6071dabc5b4494d303af761a052a5c70d5788ac0d489908000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac00000000460200686f130050689b664f559996fc8775aca110b2f0ed9aec7f8fe3aab4f79ec0fc4f8a344dedd7620153e1668282952353c7e2eef6405ef7c82a683d3c7a4f4210a78992c3"},{"txid":"321dbd1768fb763c350d6dd40b1b43f9ac9caea041ff7f12c6002b2cc4fee3b4","version":3,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"03506f1312b49ba1e25427ee6dc100000000002f4e614e"}],"vout":[{"value":"144250048","n":0,"hex":"76a91408b6841935f55cb830d14ecc863ea93fb969c63c88ac","addresses":["XbUutDsgJbf7Sjjq4omhusNtkT8ih1d7oQ"],"isAddress":true},{"value":"144250030","n":1,"hex":"76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac","addresses":["XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG"],"isAddress":true}],"blockHash":"000000000000000b5e5c93abd129d43f144b86c90b6a3439ec631021267220f7","blockHeight":1273680,"confirmations":858,"blockTime":1589934555,"value":"288500078","valueIn":"0","fees":"0","hex":"03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff1703506f1312b49ba1e25427ee6dc100000000002f4e614effffffff02c0149908000000001976a91408b6841935f55cb830d14ecc863ea93fb969c63c88acae149908000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac00000000460200506f1300e8a35551ae71fb9b09ecc86d8d728c832684ea2ad283e2b4d1ed31f6dd4bf11ac1c2e67062c1c299bd250c393058810a298e4ff291a529a5c93c477db90ebd64"},{"txid":"19686bf79281f204a3dc50ec2932a509f271577cecd844f7e27cc821aa433cab","version":3,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"033e6f131a4d696e656420627920416e74506f6f6c34fd004702207d54c8a01d770000bb0e0000"}],"vout":[{"value":"144444187","n":0,"hex":"76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac","addresses":["XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG"],"isAddress":true},{"value":"144444195","n":1,"hex":"76a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac","addresses":["Xb8cmjtK67y9T2haqrcDicoAMByDesLcAe"],"isAddress":true}],"blockHash":"000000000000000329e30b38a5fc07526b8f555b9514ae3102dee856e0f15c4a","blockHeight":1273662,"confirmations":876,"blockTime":1589932031,"value":"288888382","valueIn":"0","fees":"0","hex":"03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff27033e6f131a4d696e656420627920416e74506f6f6c34fd004702207d54c8a01d770000bb0e0000ffffffff021b0b9c08000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac230b9c08000000001976a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac000000004602003e6f1300d8198f241d16116008d7b0892570e17f538ccd37a328f192037cc4aedffc1868f827bfb72d03894bf5851a2ccf433500bb2996c3f5b035c5bfe1fff01bbe0857"},{"txid":"c94c9bb63e9f2e9bbd181f1910f17e651822958445ea6cf9885860b1163da6d4","version":3,"vin":[{"n":0,"isAddress":false,"coinbase":"03cd6e1304312bc45e08fabe6d6d6011161d248f19d800136ecc00024600000000ac880c555103d01da67a4825d001000000000000005fe95aa02e1d00000b2f4379627463506f6f6c2f"}],"vout":[{"value":"144236253","n":0,"spent":true,"hex":"76a914ed148451671949d7353471ee5ef203d424cfbc0a88ac","addresses":["XxJQZFhLtGYz97zH92Zs4QUSF8ej6K6Qwc"],"isAddress":true},{"value":"144236247","n":1,"hex":"76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac","addresses":["XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG"],"isAddress":true}],"blockHash":"0000000000000000b904566cb38be8c8fcbb3ed833ac95301f40d8420b835b63","blockHeight":1273549,"confirmations":989,"blockTime":1589914417,"value":"288472500","valueIn":"0","fees":"0","hex":"03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff4a03cd6e1304312bc45e08fabe6d6d6011161d248f19d800136ecc00024600000000ac880c555103d01da67a4825d001000000000000005fe95aa02e1d00000b2f4379627463506f6f6c2f0000000002ddde9808000000001976a914ed148451671949d7353471ee5ef203d424cfbc0a88acd7de9808000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac00000000460200cd6e1300d8198f241d16116008d7b0892570e17f538ccd37a328f192037cc4aedffc1868e36ee33703b2b2c01ab2296db5852004d07a8297ee0a2c87ed22ef2367a3eb4b"}]} diff --git a/mock/ext-api-data/dash-api_v2_xpub_xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD__details_txs.json b/mock/ext-api-data/dash-api_v2_xpub_xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD__details_txs.json new file mode 100644 index 000000000..cf76f04d8 --- /dev/null +++ b/mock/ext-api-data/dash-api_v2_xpub_xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":6,"itemsOnPage":10,"address":"xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD","balance":"2597761","totalReceived":"27175423","totalSent":"24577662","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":52,"transactions":[{"txid":"2b67e2fbe6a212286243bc539cca3c1d877e85ffec7c925e34f2bfb7b6cc498c","version":1,"vin":[{"txid":"227f1995f5d0b0adcd4f014159710892fa4b66a02ff7ad1e0fc4c1b84ca27cb2","n":0,"addresses":["XyPpEePUKruNEVgdp5jWSakfvoQTnkZxhL"],"isAddress":true,"value":"34508","hex":"483045022100bebce18899214200115fbb2e3b16cd7a6b61cca2cf3e1ffc3b26872f66b714f702203316ce9f1cfb7cef751dbba46015ea76d3c409d6b913b6e434553ebe66680713012103f556051304c43ef031a17615fd8b056c1ac7b0a50926137bf918e72be002f606"}],"vout":[{"value":"10000","n":0,"hex":"76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac","addresses":["Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq"],"isAddress":true},{"value":"18858","n":1,"hex":"76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac","addresses":["Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq"],"isAddress":true}],"blockHash":"000000000000000b3e9287157ae29c1c19bbd1e65660a5bbe723261d0fc57737","blockHeight":1226578,"confirmations":47963,"blockTime":1582509671,"value":"28858","valueIn":"34508","fees":"5650","hex":"0100000001b27ca24cb8c1c40f1eadf72fa0664bfa9208715941014fcdadb0d0f595197f22000000006b483045022100bebce18899214200115fbb2e3b16cd7a6b61cca2cf3e1ffc3b26872f66b714f702203316ce9f1cfb7cef751dbba46015ea76d3c409d6b913b6e434553ebe66680713012103f556051304c43ef031a17615fd8b056c1ac7b0a50926137bf918e72be002f606000000000210270000000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88acaa490000000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac00000000"},{"txid":"dc8e1219da91a24c2eca773a6853d7a0602eed509a4b71afd553f8b4c218b309","version":1,"vin":[{"txid":"501c3c7ecaae272de760e81d284e44644a0475c42e3ee15ae16a125650211c8e","vout":1,"n":0,"addresses":["Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq"],"isAddress":true,"value":"768334","hex":"483045022100805ae010fb81b3659f687d1f9da9efa27fa220d34c0f9c54dde4f8e8358e7c2e022003c2c89eb0372616ad50b74f627097e3ccf2ecd940bad616b0bf7caaab58615c01210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600"},{"txid":"501c3c7ecaae272de760e81d284e44644a0475c42e3ee15ae16a125650211c8e","n":1,"addresses":["Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq"],"isAddress":true,"value":"809686","hex":"483045022100ff644abb86e4272384e64de00d7ac2b1ed01e6848f59707f1bd93913b0f2ceeb02205ba0be94a02a2af3d7178977d828dda4268da4f83c00d2af1331e4274a5454a201210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600"}],"vout":[{"value":"1000000","n":0,"hex":"76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac","addresses":["Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq"],"isAddress":true},{"value":"576150","n":1,"hex":"76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac","addresses":["Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq"],"isAddress":true}],"blockHash":"000000000000000f727266a1a157af489fec0a009938dadeca89bc3edd1bc017","blockHeight":1215128,"confirmations":59413,"blockTime":1580704472,"value":"1576150","valueIn":"1578020","fees":"1870","hex":"01000000028e1c215056126ae15ae13e2ec475044a64444e281de860e72d27aeca7e3c1c50010000006b483045022100805ae010fb81b3659f687d1f9da9efa27fa220d34c0f9c54dde4f8e8358e7c2e022003c2c89eb0372616ad50b74f627097e3ccf2ecd940bad616b0bf7caaab58615c01210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600000000008e1c215056126ae15ae13e2ec475044a64444e281de860e72d27aeca7e3c1c50000000006b483045022100ff644abb86e4272384e64de00d7ac2b1ed01e6848f59707f1bd93913b0f2ceeb02205ba0be94a02a2af3d7178977d828dda4268da4f83c00d2af1331e4274a5454a201210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600000000000240420f00000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac96ca0800000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac00000000"},{"txid":"6696dd6c84e58023ecfd5418c9b729e35d2a87235dd0c260f2195ed1810a50d0","version":1,"vin":[{"txid":"31bb6217e1fec3f0041e15e8e8878bbbe1169520ac42fc08a2bb3718946ee309","n":0,"addresses":["XdSr6KFsDGmUpKuG5jWzjZWCbhCtUeT9TZ"],"isAddress":true,"value":"1000000","hex":"473044022010420f86db6de28f66abc96fb474f602f5d90700297555a638851403e70f385102201bb76e34df895edfbb2188b0d293eddbd0434847bedebd21949f5bd42f5048e001210282c2c88e60a8aa55be2c3ff46975e2f79d8d208751b59d4943a59d0a002d5ad0"},{"txid":"f7bc5be43c4dd9c5a23dc88ba5ba823f5109c16a15d69a4fee668311facb72b0","vout":1,"n":1,"addresses":["XqRxi4Y91n6P24eAfymkwckaHE2463Mvxf"],"isAddress":true,"value":"1014267","hex":"47304402204b85b8549fcd6f028d620d4855b03fd900f4a2a70515c7a8d27164b5d3955afd02204569a163bec5e3ee693de7ea11ea7ae611ac8cd7de492c88d328a177f8e5ebba01210276c23ac6a5245e706be703db4d317ecf4b7f341e6a5b9f72a5b364b3dd8746c9"}],"vout":[{"value":"1609050","n":0,"spent":true,"hex":"76a9143f9f7dbf8c17f6c5d96ed20ca8ac3c65f97b898b88ac","addresses":["XgVFTyuPdzk4VpUTYDt5Hyc7WSDRFUczPg"],"isAddress":true},{"value":"403347","n":1,"hex":"76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac","addresses":["Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq"],"isAddress":true}],"blockHash":"00000000000000170e5fa8aa5da53048e697284b8c2c7c540db6b97136d0aedd","blockHeight":1213079,"confirmations":61462,"blockTime":1580381547,"value":"2012397","valueIn":"2014267","fees":"1870","hex":"010000000209e36e941837bba208fc42ac209516e1bb8b87e8e8151e04f0c3fee11762bb31000000006a473044022010420f86db6de28f66abc96fb474f602f5d90700297555a638851403e70f385102201bb76e34df895edfbb2188b0d293eddbd0434847bedebd21949f5bd42f5048e001210282c2c88e60a8aa55be2c3ff46975e2f79d8d208751b59d4943a59d0a002d5ad000000000b072cbfa118366ee4f9ad6156ac109513f82baa58bc83da2c5d94d3ce45bbcf7010000006a47304402204b85b8549fcd6f028d620d4855b03fd900f4a2a70515c7a8d27164b5d3955afd02204569a163bec5e3ee693de7ea11ea7ae611ac8cd7de492c88d328a177f8e5ebba01210276c23ac6a5245e706be703db4d317ecf4b7f341e6a5b9f72a5b364b3dd8746c900000000025a8d1800000000001976a9143f9f7dbf8c17f6c5d96ed20ca8ac3c65f97b898b88ac93270600000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac00000000"},{"txid":"501c3c7ecaae272de760e81d284e44644a0475c42e3ee15ae16a125650211c8e","version":1,"vin":[{"txid":"d89f83e41cff574070841fb502e69be155ac38d3537047ab61ef597b0eeb9eb3","vout":1,"n":0,"addresses":["Xmt4GmF2Z8sSFtr4zQweZmwHXoEWAEjQjS"],"isAddress":true,"value":"1579150","hex":"473044022022fa02151b5a09be882b93fa1771f1fc9d2e1f3059d548f8afa7fa91d5474e5502200c9dc39c310103b4bcddf88cda6acac4151fd6164be63dff95baf63b306eb9710121022ceba3e32535678aa740a9ea4d333dcaf3cae9e5132586c149938a5d609dc837"}],"vout":[{"value":"809686","n":0,"spent":true,"hex":"76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac","addresses":["Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq"],"isAddress":true},{"value":"768334","n":1,"spent":true,"hex":"76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac","addresses":["Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq"],"isAddress":true}],"blockHash":"000000000000000f17a7d21440dc0980abac9f64a55d652a9e945a080b72c253","blockHeight":1213076,"confirmations":61465,"blockTime":1580381293,"value":"1578020","valueIn":"1579150","fees":"1130","hex":"0100000001b39eeb0e7b59ef61ab477053d338ac55e19be602b51f84704057ff1ce4839fd8010000006a473044022022fa02151b5a09be882b93fa1771f1fc9d2e1f3059d548f8afa7fa91d5474e5502200c9dc39c310103b4bcddf88cda6acac4151fd6164be63dff95baf63b306eb9710121022ceba3e32535678aa740a9ea4d333dcaf3cae9e5132586c149938a5d609dc8370000000002d65a0c00000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac4eb90b00000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac00000000"},{"txid":"c13e0718fdafa2a79153748092f978e63dfc8fd41b28bea23427e1d7c976c25b","version":1,"vin":[{"txid":"31bb6217e1fec3f0041e15e8e8878bbbe1169520ac42fc08a2bb3718946ee309","vout":1,"n":0,"addresses":["XgQ6GjrRACaU1ci8BGtALqwd3p7Z1W6m7p"],"isAddress":true,"value":"578870","hex":"483045022100b3683d1170e2e2395a7a35e5b0d0a674ff7b4e1660999893ae60d7e6bc841cbb022027e345eb9776b160260129f33ce6a404268f763d986cefb614573cdc12e7509201210372d1d3eb2c31f49510220dc2aaf32c6a363ed00827734d3713f7e72c8776def8"}],"vout":[{"value":"43000","n":0,"spent":true,"hex":"76a9144ad11db3087da53b67f56e87e9a53ecd89dde09b88ac","addresses":["XhWSM5qaV2dnuHPGzpogBGkhTBPMPjDXaG"],"isAddress":true},{"value":"534740","n":1,"hex":"76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac","addresses":["Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq"],"isAddress":true}],"blockHash":"00000000000000049439d5c7528b34e01643695735ef9db11696382f7c08f75a","blockHeight":1211620,"confirmations":62921,"blockTime":1580151375,"value":"577740","valueIn":"578870","fees":"1130","hex":"010000000109e36e941837bba208fc42ac209516e1bb8b87e8e8151e04f0c3fee11762bb31010000006b483045022100b3683d1170e2e2395a7a35e5b0d0a674ff7b4e1660999893ae60d7e6bc841cbb022027e345eb9776b160260129f33ce6a404268f763d986cefb614573cdc12e7509201210372d1d3eb2c31f49510220dc2aaf32c6a363ed00827734d3713f7e72c8776def80000000002f8a70000000000001976a9144ad11db3087da53b67f56e87e9a53ecd89dde09b88acd4280800000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac00000000"},{"txid":"31bb6217e1fec3f0041e15e8e8878bbbe1169520ac42fc08a2bb3718946ee309","version":1,"vin":[{"txid":"d89f83e41cff574070841fb502e69be155ac38d3537047ab61ef597b0eeb9eb3","n":0,"addresses":["Xjt3PDPSWXNet3o52JTwgr656mtygDZead"],"isAddress":true,"value":"1580000","hex":"4830450221009b25b8c7f8e188d7c4f1afd98519493e4f68150c1ef674d962191b142aac60df02204c04a7552183e5a19e3e8f3b1b837bee389a30fb72c1ee2704490c204c1d156301210267be33f661018e638b648038b2d5dc6e6920ca9ff71451047e7c66294bedbbbf"}],"vout":[{"value":"1000000","n":0,"spent":true,"hex":"76a9141e42c54a5e1b5d9b18027ba2d97143a87e5c32bb88ac","addresses":["XdSr6KFsDGmUpKuG5jWzjZWCbhCtUeT9TZ"],"isAddress":true},{"value":"578870","n":1,"spent":true,"hex":"76a9143ea5bc9cfe132f64cb0c141d1ea86223666f9c1888ac","addresses":["XgQ6GjrRACaU1ci8BGtALqwd3p7Z1W6m7p"],"isAddress":true}],"blockHash":"000000000000000eb3032ddc1a92f3058dc04d315cedb022c4a30b6ba30ae60a","blockHeight":1207821,"confirmations":66720,"blockTime":1579553025,"value":"1578870","valueIn":"1580000","fees":"1130","hex":"0100000001b39eeb0e7b59ef61ab477053d338ac55e19be602b51f84704057ff1ce4839fd8000000006b4830450221009b25b8c7f8e188d7c4f1afd98519493e4f68150c1ef674d962191b142aac60df02204c04a7552183e5a19e3e8f3b1b837bee389a30fb72c1ee2704490c204c1d156301210267be33f661018e638b648038b2d5dc6e6920ca9ff71451047e7c66294bedbbbf000000000240420f00000000001976a9141e42c54a5e1b5d9b18027ba2d97143a87e5c32bb88ac36d50800000000001976a9143ea5bc9cfe132f64cb0c141d1ea86223666f9c1888ac00000000"},{"txid":"227f1995f5d0b0adcd4f014159710892fa4b66a02ff7ad1e0fc4c1b84ca27cb2","version":1,"vin":[{"txid":"f7bc5be43c4dd9c5a23dc88ba5ba823f5109c16a15d69a4fee668311facb72b0","n":0,"addresses":["Xe4pb7964mDz3j6T8qME8oNPn4Qq7rvfLx"],"isAddress":true,"value":"34700","hex":"47304402205525a79b5e00f718c7de2543de0192e8fed59d1e566383e54dfda688295b773602200c962fe59cfc860191a6d721b3dfe76b01d0a282f109c86d1d3e3991d32da5a6012103015b8c707ded30b2750ac31665335c7ff60db8d18ede940cb70070267bf88617"}],"vout":[{"value":"34508","n":0,"spent":true,"hex":"76a914f9127d23bd2b473d5a9fa45a6b8b27c18cbeab6e88ac","addresses":["XyPpEePUKruNEVgdp5jWSakfvoQTnkZxhL"],"isAddress":true}],"blockHash":"000000000000000e84ed0e94fa47767d5be5c421a239079449fd7899a5ce5578","blockHeight":1166949,"confirmations":107592,"blockTime":1573112576,"value":"34508","valueIn":"34700","fees":"192","hex":"0100000001b072cbfa118366ee4f9ad6156ac109513f82baa58bc83da2c5d94d3ce45bbcf7000000006a47304402205525a79b5e00f718c7de2543de0192e8fed59d1e566383e54dfda688295b773602200c962fe59cfc860191a6d721b3dfe76b01d0a282f109c86d1d3e3991d32da5a6012103015b8c707ded30b2750ac31665335c7ff60db8d18ede940cb70070267bf886170000000001cc860000000000001976a914f9127d23bd2b473d5a9fa45a6b8b27c18cbeab6e88ac00000000"},{"txid":"9547b79e41fb869994b839fcd8b8c5ea580aaabc6711146d389b09e6cf624f06","version":1,"vin":[{"txid":"78481c5218b6c6d3cc4d07e0c6e52082a8d235596394ea794782de4ed80abbcb","sequence":4294967291,"n":0,"addresses":["Xki96Js2mRv6rC63UokDVbRmE7RDc7ULPp"],"isAddress":true,"value":"44892","hex":"4830450221008dbdd31911231aad03aef6eded9230a55607405b0dc77977e43c2ec339f8a8e002201b62bb327dc725263de1e75931cd6642f49d98d49a6e0424587ea478343eab680121020440f808adf979ca45adf2db3c91701c378e99f9770f84102c0b16eed8a0e81e"}],"vout":[{"value":"10000","n":0,"hex":"76a91474ec52b284baa7bc0a5c554726f1e2b717e24c3b88ac","addresses":["XmM5KX1Zpepji5V6RF7iypCkXBi4hSronS"],"isAddress":true},{"value":"34666","n":1,"hex":"76a91412084b5792de33e02d99c555a956ccd32586838488ac","addresses":["XcLBw1EUz5HPDJ5pZrSbeyXYBWcVCabZ56"],"isAddress":true}],"blockHash":"0000000000000005f32905ffe9cb77f22e372256f6d2657124f8bafd36fbc8c0","blockHeight":1166519,"confirmations":108022,"blockTime":1573044962,"value":"44666","valueIn":"44892","fees":"226","hex":"0100000001cbbb0ad84ede824779ea94635935d2a88220e5c6e0074dccd3c6b618521c4878000000006b4830450221008dbdd31911231aad03aef6eded9230a55607405b0dc77977e43c2ec339f8a8e002201b62bb327dc725263de1e75931cd6642f49d98d49a6e0424587ea478343eab680121020440f808adf979ca45adf2db3c91701c378e99f9770f84102c0b16eed8a0e81efbffffff0210270000000000001976a91474ec52b284baa7bc0a5c554726f1e2b717e24c3b88ac6a870000000000001976a91412084b5792de33e02d99c555a956ccd32586838488ac00000000"},{"txid":"f7bc5be43c4dd9c5a23dc88ba5ba823f5109c16a15d69a4fee668311facb72b0","version":1,"vin":[{"txid":"78481c5218b6c6d3cc4d07e0c6e52082a8d235596394ea794782de4ed80abbcb","vout":1,"n":0,"addresses":["XeFnGkttzWebuQvPRQMsCZx8irRqZh9bXB"],"isAddress":true,"value":"1274967","hex":"47304402202666f9d9294ee1baa863722543400ed9286e771462212e7fd9252ecb55dc160102202983aab7fbcd63103350be226fc2c0a1fe8aa8a197bd20634976f10a5b5fef49012103a67eb8083b43cd54ac56a5c5361825e0e4681984b6ea2300b398fb736f279cc8"}],"vout":[{"value":"34700","n":0,"spent":true,"hex":"76a91425107d7a41d6e6167a19873ace2a977eabaf058688ac","addresses":["Xe4pb7964mDz3j6T8qME8oNPn4Qq7rvfLx"],"isAddress":true},{"value":"1014267","n":1,"spent":true,"hex":"76a914a1b9631afa751aa45b0af6b873e44a0461e84b5d88ac","addresses":["XqRxi4Y91n6P24eAfymkwckaHE2463Mvxf"],"isAddress":true}],"blockHash":"000000000000002522f2157367c56683a7a26dea3e6be7bca4fcef8ee068eb7b","blockHeight":1140065,"confirmations":134476,"blockTime":1568874528,"value":"1048967","valueIn":"1274967","fees":"226000","hex":"0100000001cbbb0ad84ede824779ea94635935d2a88220e5c6e0074dccd3c6b618521c4878010000006a47304402202666f9d9294ee1baa863722543400ed9286e771462212e7fd9252ecb55dc160102202983aab7fbcd63103350be226fc2c0a1fe8aa8a197bd20634976f10a5b5fef49012103a67eb8083b43cd54ac56a5c5361825e0e4681984b6ea2300b398fb736f279cc800000000028c870000000000001976a91425107d7a41d6e6167a19873ace2a977eabaf058688acfb790f00000000001976a914a1b9631afa751aa45b0af6b873e44a0461e84b5d88ac00000000"},{"txid":"78481c5218b6c6d3cc4d07e0c6e52082a8d235596394ea794782de4ed80abbcb","version":1,"vin":[{"txid":"93aa38b6e55c08f0dcb1423626e226a459baa68c3246c93bd5b08c131a180cb8","sequence":4294967291,"n":0,"addresses":["XkbgwRmm1SKoKgBp3QAbqY3fvRA1DJfEij"],"isAddress":true,"value":"1320085","hex":"473044022033ce7e907f87dd5d6c6faea76688e0ea9367e71cfda58d1205d4adad13250f0a022072aaf56cdc36b9adb91819f34733ad1d1b74518befd26e0cd77691169831989001210343355be8a2bac33d30e878996016603717931287764d277876960416558fbcc9"}],"vout":[{"value":"44892","n":0,"spent":true,"hex":"76a9146df014d476d6e737f8e70e1123859e94e297062a88ac","addresses":["Xki96Js2mRv6rC63UokDVbRmE7RDc7ULPp"],"isAddress":true},{"value":"1274967","n":1,"spent":true,"hex":"76a914272321d2e254c762b38dcffd027e5f5b84b3798088ac","addresses":["XeFnGkttzWebuQvPRQMsCZx8irRqZh9bXB"],"isAddress":true}],"blockHash":"0000000000000018a47bfd48e74bed20fe83298904e5a52971f4e8ad9d51d727","blockHeight":1136578,"confirmations":137963,"blockTime":1568325650,"value":"1319859","valueIn":"1320085","fees":"226","hex":"0100000001b80c181a138cb0d53bc946328ca6ba59a426e2263642b1dcf0085ce5b638aa93000000006a473044022033ce7e907f87dd5d6c6faea76688e0ea9367e71cfda58d1205d4adad13250f0a022072aaf56cdc36b9adb91819f34733ad1d1b74518befd26e0cd77691169831989001210343355be8a2bac33d30e878996016603717931287764d277876960416558fbcc9fbffffff025caf0000000000001976a9146df014d476d6e737f8e70e1123859e94e297062a88ac57741300000000001976a914272321d2e254c762b38dcffd027e5f5b84b3798088ac00000000"}],"usedTokens":47,"tokens":[{"type":"XPUBAddress","name":"Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq","path":"m/44'/5'/0'/0/0","transfers":13,"decimals":8,"balance":"2543095","totalReceived":"4275043","totalSent":"1731948"},{"type":"XPUBAddress","name":"XezMSYZ3ucD2tNGVME1j3A8tM5q3NvigKu","path":"m/44'/5'/0'/0/15","transfers":1,"decimals":8,"balance":"10000","totalReceived":"10000","totalSent":"0"},{"type":"XPUBAddress","name":"XmM5KX1Zpepji5V6RF7iypCkXBi4hSronS","path":"m/44'/5'/0'/0/18","transfers":1,"decimals":8,"balance":"10000","totalReceived":"10000","totalSent":"0"},{"type":"XPUBAddress","name":"XcLBw1EUz5HPDJ5pZrSbeyXYBWcVCabZ56","path":"m/44'/5'/0'/1/24","transfers":1,"decimals":8,"balance":"34666","totalReceived":"34666","totalSent":"0"}]} diff --git a/mock/ext-api-data/decred-api_v2_address_DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY__details_txs.json b/mock/ext-api-data/decred-api_v2_address_DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY__details_txs.json new file mode 100644 index 000000000..957dc2412 --- /dev/null +++ b/mock/ext-api-data/decred-api_v2_address_DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY__details_txs.json @@ -0,0 +1,523 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", + "balance": "19370607", + "totalReceived": "75347145", + "totalSent": "55976538", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 11, + "transactions": [ + { + "txid": "22009e6feb0ecbd29004f8a5273163da53c112d93ec5f9dbff46bc41a30f90f0", + "version": 1, + "vin": [ + { + "txid": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0", + "vout": 1, + "sequence": 4294967283, + "n": 0, + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true, + "value": "489415", + "hex": "483045022100b67f278e9552abddde008a4d91e5c1044d8cf01248378f6b4ed94514b23dbf5e022025c96ea8974f40833287f91f5d7a2a672654950993322ec91b32caf45a9d9fc90121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a914f3fa335c33379fabe6d61c5491504d8d1ad6851c88ac", + "addresses": [ + "DsoCwRHkCHpR1Jvk9GnCT2M8hVgVjfyYAKE" + ], + "isAddress": true + }, + { + "value": "386875", + "n": 1, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000d08b3d88676bc81defa76eeb6f1322dd68bca50f34a9e8b", + "blockHeight": 447041, + "confirmations": 2034, + "blockTime": 1588752334, + "value": "486875", + "valueIn": "489415", + "fees": "2540", + "hex": "0100000001e036d74365e2c619c22c802c132e736a4bf966a4e5f5ab7b33b34c2d62d1e3660100000000f3ffffff02a08601000000000000001976a914f3fa335c33379fabe6d61c5491504d8d1ad6851c88ac3be705000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac000000000000000001c777070000000000298e0600030000006b483045022100b67f278e9552abddde008a4d91e5c1044d8cf01248378f6b4ed94514b23dbf5e022025c96ea8974f40833287f91f5d7a2a672654950993322ec91b32caf45a9d9fc90121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + }, + { + "txid": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0", + "version": 1, + "vin": [ + { + "txid": "2dc905f525885537310c8ab87f67dc175ca369af1fe7111a49a94451866aa019", + "sequence": 4294967291, + "n": 0, + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true, + "value": "591955", + "hex": "473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "489415", + "n": 1, + "spent": true, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000c12cb497e60470a3cf366d16705eaba303c2c4415cc7567", + "blockHeight": 429609, + "confirmations": 19466, + "blockTime": 1583516573, + "value": "589415", + "valueIn": "591955", + "fees": "2540", + "hex": "010000000119a06a865144a9491a11e71faf69a35c17dc677fb88a0c3137558825f505c92d0000000000fbffffff02a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acc77707000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac0000000000000000015308090000000000dbcc05000b0000006a473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + }, + { + "txid": "025abf340da79c4fc4de29667c08fc22cdafbded24c7c2a994a27f6fb4d5fa17", + "version": 1, + "vin": [ + { + "txid": "5a2a0d01ed8672d6bebd7dee447b2e0342bfc34fd4893bed58a4fa5aa87a4c42", + "n": 0, + "addresses": [ + "Dsf6WkLoiTcSGKmkXoSEdukqUfeRJMqUNJV" + ], + "isAddress": true, + "value": "19991980", + "hex": "483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "19889440", + "n": 1, + "hex": "76a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac", + "addresses": [ + "Dsesp1V6DZDEtcq2behmBVKdYqKMdkh96hL" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000264c499f21a7ef95bffb37148fc099514b2407dfa28c3287", + "blockHeight": 429186, + "confirmations": 19889, + "blockTime": 1583384838, + "value": "19989440", + "valueIn": "19991980", + "fees": "2540", + "hex": "0100000001424c7aa85afaa458ed3b89d44fc3bf42032e7b44ee7dbdbed67286ed010d2a5a00000000000000000002a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac207d2f010000000000001976a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac000000000000000001ac0d31010000000052630600050000006b483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" + }, + { + "txid": "68dcb93e36879f33e741f5706463af10387aadeba193cb204453ec23ad1b1979", + "version": 1, + "vin": [ + { + "txid": "d1352a165c773fe22556219916c2dbd3e184cbf29d9be88b4d52b1c321131601", + "vout": 1, + "sequence": 4294967291, + "n": 0, + "addresses": [ + "DseafVVZGqk4VMCiEJoxRS6FkUjxofh2PXA" + ], + "isAddress": true, + "value": "150582", + "hex": "473044022028e6a72865dfb231b6a64cb3bacc5421dde842c57a169d13b753c36e96cacd9f022049e381c5e8a7e82d96b8996898c43baebbb1e5e5e9f51c15beb17e29e784c257012102fed4dd58683487545cc89c1fd779bf70b46067b863921b0e0c1b09bbe56d4345" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "48042", + "n": 1, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000025750e22134a74a8a5389c716b51dc4757bf213c7dfbb70", + "blockHeight": 427612, + "confirmations": 21463, + "blockTime": 1582902615, + "value": "148042", + "valueIn": "150582", + "fees": "2540", + "hex": "010000000101161321c3b1524d8be89b9df2cb84e1d3dbc21699215625e23f775c162a35d10100000000fbffffff02a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acaabb00000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac000000000000000001364c020000000000f4c80500070000006a473044022028e6a72865dfb231b6a64cb3bacc5421dde842c57a169d13b753c36e96cacd9f022049e381c5e8a7e82d96b8996898c43baebbb1e5e5e9f51c15beb17e29e784c257012102fed4dd58683487545cc89c1fd779bf70b46067b863921b0e0c1b09bbe56d4345" + }, + { + "txid": "70a5caffaac9105b47ff9b70213f3a9f8bbd28f09335dce763a99f1b39e74ccf", + "version": 1, + "vin": [ + { + "txid": "2c922ec02ec0bc86803290191198232183e903ea2e79f7f6ddb6c7c7c193b9db", + "vout": 1, + "sequence": 4294967287, + "n": 0, + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true, + "value": "5292552", + "hex": "483045022100bc0999a9673f4f72b2bd79fd40c1b8a8398381edcc584f6ed868229e2ec5628b02205baab2c3b1cefdb41dc439782310931f15b31fd48544ca70f88c94940a3870800121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "4290012", + "n": 1, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000001c196ac1e8e050a3d7bc600bcb87826dca4ff558ac280014", + "blockHeight": 427609, + "confirmations": 21466, + "blockTime": 1582901951, + "value": "5290012", + "valueIn": "5292552", + "fees": "2540", + "hex": "0100000001dbb993c1c7c7b6ddf6f7792eea03e983212398111990328086bcc02ec02e922c0100000000f7ffffff0240420f000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acdc7541000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac00000000000000000108c2500000000000bc5d0600020000006b483045022100bc0999a9673f4f72b2bd79fd40c1b8a8398381edcc584f6ed868229e2ec5628b02205baab2c3b1cefdb41dc439782310931f15b31fd48544ca70f88c94940a3870800121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + }, + { + "txid": "2c922ec02ec0bc86803290191198232183e903ea2e79f7f6ddb6c7c7c193b9db", + "version": 1, + "vin": [ + { + "txid": "a81ab3f0d0744c42fcc8e5c3b0b77382323d0cf6ac73a55f982dcadc4fe604c7", + "vout": 1, + "n": 0, + "addresses": [ + "DseSHdQv3cZhuY3foizi3bbHHMw2o7RsNsu" + ], + "isAddress": true, + "value": "6295092", + "hex": "47304402206d190e10475b3dc57a9ec4aff060f1d9ee82e47b99d1f9cb2e926384ccdc04df022056040c8b364176c28876b597006faba7b0f1f74abcf0321e530520907b8ded8001210385ece82907d214f46db634a6326d99616ea022ec887991251215d1564120ac41" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "5292552", + "n": 1, + "spent": true, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000008e3020d59db97a9e69b7b77697369cee0cd600a3e3c106", + "blockHeight": 417211, + "confirmations": 31864, + "blockTime": 1579769314, + "value": "6292552", + "valueIn": "6295092", + "fees": "2540", + "hex": "0100000001c704e64fdcca2d985fa573acf60c3d328273b7b0c3e5c8fc424c74d0f0b31aa80100000000000000000240420f000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac08c250000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac000000000000000001340e600000000000c0050600070000006a47304402206d190e10475b3dc57a9ec4aff060f1d9ee82e47b99d1f9cb2e926384ccdc04df022056040c8b364176c28876b597006faba7b0f1f74abcf0321e530520907b8ded8001210385ece82907d214f46db634a6326d99616ea022ec887991251215d1564120ac41" + }, + { + "txid": "a81ab3f0d0744c42fcc8e5c3b0b77382323d0cf6ac73a55f982dcadc4fe604c7", + "version": 1, + "vin": [ + { + "txid": "f901951a6552d84a047170534a17f176dddf3ff05046d94d5a4f60e951cb7814", + "vout": 1, + "n": 0, + "addresses": [ + "Dse6xFAU3LBzNeFZiPGJHuBRebHN74Sr2ry" + ], + "isAddress": true, + "value": "18643310", + "hex": "4830450221008d6be510c08e051ed4b1f4e00503595531f4800d042a438cb76681677e471b3c022072fb18f79fd673d86449b3ca77e846a9c8ffb87551ce3597b1b206f5d99fa3ab01210212d8d67fa0db8a51432cbbff4d29d5a2ec407f43958800e3770c277b6c22e4ca" + } + ], + "vout": [ + { + "value": "12345678", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "6295092", + "n": 1, + "spent": true, + "hex": "76a91493c7588139797500ca13011a73e01a78da3092cd88ac", + "addresses": [ + "DseSHdQv3cZhuY3foizi3bbHHMw2o7RsNsu" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000017871738a562ecfe28699613f578177c3d43c00124b65abe", + "blockHeight": 394687, + "confirmations": 54388, + "blockTime": 1573005579, + "value": "18640770", + "valueIn": "18643310", + "fees": "2540", + "hex": "01000000011478cb51e9604f5a4dd94650f03fdfdd76f1174a537071044ad852651a9501f9010000000000000000024e61bc000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac340e60000000000000001976a91493c7588139797500ca13011a73e01a78da3092cd88ac0000000000000000016e791c0100000000d4cc0500010000006b4830450221008d6be510c08e051ed4b1f4e00503595531f4800d042a438cb76681677e471b3c022072fb18f79fd673d86449b3ca77e846a9c8ffb87551ce3597b1b206f5d99fa3ab01210212d8d67fa0db8a51432cbbff4d29d5a2ec407f43958800e3770c277b6c22e4ca" + }, + { + "txid": "ce314ec559ceae4d2a98ed4708848708c9cfde14b484b879838a2dc75c793910", + "version": 1, + "vin": [ + { + "txid": "6928795181bd951849bcdebab2f012b1f6a71f8f1993e573ee1b531207c61255", + "sequence": 4294967293, + "n": 0, + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true, + "value": "194571", + "hex": "483045022100dd4fafb4a6d89f81b0602a3305aac956decad8e65182cd690eda70854eccc43a022055a23cd4eff950901494fe0f53d880a5c04ca23e822116d91a9ada83ba6baf010121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + } + ], + "vout": [ + { + "value": "19457", + "n": 0, + "hex": "76a914a0f82f406aa9ce69402d915f9e93312c9e5d796988ac", + "addresses": [ + "Dsfe2vHn1TVqHJWeD37BXL1y31nWeBQqB7c" + ], + "isAddress": true + }, + { + "value": "172574", + "n": 1, + "spent": true, + "hex": "76a914cf1c37327174a9eb957bc879320c405f7f678b7588ac", + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000004f7b5a862dc2f9fa6acc037a743913056d2882856ba4314", + "blockHeight": 379022, + "confirmations": 70053, + "blockTime": 1568292291, + "value": "192031", + "valueIn": "194571", + "fees": "2540", + "hex": "01000000015512c60712531bee73e593198f1fa7f6b112f0b2badebc491895bd81517928690000000000fdffffff02014c00000000000000001976a914a0f82f406aa9ce69402d915f9e93312c9e5d796988ac1ea202000000000000001976a914cf1c37327174a9eb957bc879320c405f7f678b7588ac0000000000000000010bf80200000000008dc80500030000006b483045022100dd4fafb4a6d89f81b0602a3305aac956decad8e65182cd690eda70854eccc43a022055a23cd4eff950901494fe0f53d880a5c04ca23e822116d91a9ada83ba6baf010121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + }, + { + "txid": "6928795181bd951849bcdebab2f012b1f6a71f8f1993e573ee1b531207c61255", + "version": 1, + "vin": [ + { + "txid": "4510dd5fa05c5a8a1ab44a9b77315bf989a3749eb2ff2b651648313dc15c98f9", + "vout": 1, + "sequence": 4294967293, + "n": 0, + "addresses": [ + "DsmwaUbFCWoZCjGv2bYA8bmmXFarWgc6zHY" + ], + "isAddress": true, + "value": "19437456", + "hex": "483045022100a9bdbc46b9856b592d50fc718a818393a53c380fd08dae92a470293d0b7da5f102203e4addd7634bcc14546840cb80f13b6e994d4523a80a46dfd951b173d62a49d6012103bb6681dc8e643af1a54e94e7efe9089f4b9051b2e43803050d6b5a7de7991a11" + } + ], + "vout": [ + { + "value": "194571", + "n": 0, + "spent": true, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "19240345", + "n": 1, + "spent": true, + "hex": "76a914cf1c37327174a9eb957bc879320c405f7f678b7588ac", + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000bde3ce71634ce6fa7ed894c6d016fba61abb0a94d2c4afa", + "blockHeight": 379020, + "confirmations": 70055, + "blockTime": 1568292043, + "value": "19434916", + "valueIn": "19437456", + "fees": "2540", + "hex": "0100000001f9985cc13d314816652bffb29e74a389f95b31779b4ab41a8a5a5ca05fdd10450100000000fdffffff020bf802000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac999525010000000000001976a914cf1c37327174a9eb957bc879320c405f7f678b7588ac0000000000000000019097280100000000bdc70500030000006b483045022100a9bdbc46b9856b592d50fc718a818393a53c380fd08dae92a470293d0b7da5f102203e4addd7634bcc14546840cb80f13b6e994d4523a80a46dfd951b173d62a49d6012103bb6681dc8e643af1a54e94e7efe9089f4b9051b2e43803050d6b5a7de7991a11" + }, + { + "txid": "5015d14dcfd78998cfa13e0325798a74d95bbe75f167a49467303f70dde9bffd", + "version": 1, + "vin": [ + { + "txid": "ac4b4b9af3e0b8cdb7918bb6bfdf9878ace398b92e6e5ef7844936c676041a26", + "vout": 1, + "sequence": 4294967295, + "n": 0, + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true, + "value": "50000000", + "hex": "483045022100923900d86dfbfefa31c5789c0d142fd75d18dd91ea13930515c46e280b6f33fc022079fddaf46e6da7978b9226cc09c6d978bca89b37ec99becb65625ddb6d00f9180121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + } + ], + "vout": [ + { + "value": "39900000", + "n": 0, + "spent": true, + "hex": "76a914746462efaf7a648ccd1a46de4e2842f2b25f498588ac", + "addresses": [ + "DsbaL8f4Uu4bQ6wPpbjcLWxRDZQZo3Ncrrq" + ], + "isAddress": true + }, + { + "value": "10000000", + "n": 1, + "hex": "76a9145f6ef673184369f86779658d13f436a7d303276888ac", + "addresses": [ + "DsZfWcUeaTLtXz3roBmNCNP96srYmDFVZ1W" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000008e0427a4b4e95d540d03fcc28a059861204a8674bdf7a64", + "blockHeight": 330617, + "confirmations": 118458, + "blockTime": 1553754509, + "value": "49900000", + "valueIn": "50000000", + "fees": "100000", + "hex": "0100000001261a0476c6364984f75e6e2eb998e3ac7898dfbfb68b91b7cdb8e0f39a4b4bac0100000000ffffffff0260d360020000000000001976a914746462efaf7a648ccd1a46de4e2842f2b25f498588ac809698000000000000001976a9145f6ef673184369f86779658d13f436a7d303276888ac00000000000000000180f0fa020000000035ef0400150000006b483045022100923900d86dfbfefa31c5789c0d142fd75d18dd91ea13930515c46e280b6f33fc022079fddaf46e6da7978b9226cc09c6d978bca89b37ec99becb65625ddb6d00f9180121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + }, + { + "txid": "ac4b4b9af3e0b8cdb7918bb6bfdf9878ace398b92e6e5ef7844936c676041a26", + "version": 1, + "vin": [ + { + "txid": "9ecec2fc079ebc6646de451b73231cf422f7ad761472b6482c7453a82c87a321", + "vout": 5, + "sequence": 4294967295, + "n": 0, + "addresses": [ + "DsfMzjYfieAwq2zpeCRyDMiSVDxfEFfRNui" + ], + "isAddress": true, + "value": "7078093729", + "hex": "483045022100fef9f8fd733a94ee691d1845442335a3693882e441078c5dc1220ce21ce93d0f0220308aed0bd8cb2e5a040f46426be0b25fdb3605bb6ae3ec8252055bc2cbd13738012102167188e52e860521bd21cc3548f4250c75309a70ec182f081b4d04f788a48914" + } + ], + "vout": [ + { + "value": "7028091199", + "n": 0, + "spent": true, + "hex": "76a914d3b1286986e589b0e819f98e2a2462e5a17f1ef288ac", + "addresses": [ + "DskGEJ3taowt2PxqopPLSUoVh9eq4nWqDXT" + ], + "isAddress": true + }, + { + "value": "50000000", + "n": 1, + "spent": true, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000016d937210760bb0fbde311d3bfb0719abeb6a2230c537817", + "blockHeight": 323381, + "confirmations": 125694, + "blockTime": 1551595302, + "value": "7078091199", + "valueIn": "7078093729", + "fees": "2530", + "hex": "010000000121a3872ca853742c48b6721476adf722f41c23731b45de4666bc9e07fcc2ce9e0500000001ffffffff023f29e8a20100000000001976a914d3b1286986e589b0e819f98e2a2462e5a17f1ef288ac80f0fa020000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac000000000000000001a123e3a501000000a6ea0400030000006b483045022100fef9f8fd733a94ee691d1845442335a3693882e441078c5dc1220ce21ce93d0f0220308aed0bd8cb2e5a040f46426be0b25fdb3605bb6ae3ec8252055bc2cbd13738012102167188e52e860521bd21cc3548f4250c75309a70ec182f081b4d04f788a48914" + } + ] +} diff --git a/mock/ext-api-data/decred-api_v2_xpub_dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN__details_txs.json b/mock/ext-api-data/decred-api_v2_xpub_dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN__details_txs.json new file mode 100644 index 000000000..083825a97 --- /dev/null +++ b/mock/ext-api-data/decred-api_v2_xpub_dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN__details_txs.json @@ -0,0 +1,1447 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN", + "balance": "19514502", + "totalReceived": "376819168", + "totalSent": "357304666", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 29, + "transactions": [ + { + "txid": "22009e6feb0ecbd29004f8a5273163da53c112d93ec5f9dbff46bc41a30f90f0", + "version": 1, + "vin": [ + { + "txid": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0", + "vout": 1, + "sequence": 4294967283, + "n": 0, + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true, + "value": "489415", + "hex": "483045022100b67f278e9552abddde008a4d91e5c1044d8cf01248378f6b4ed94514b23dbf5e022025c96ea8974f40833287f91f5d7a2a672654950993322ec91b32caf45a9d9fc90121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a914f3fa335c33379fabe6d61c5491504d8d1ad6851c88ac", + "addresses": [ + "DsoCwRHkCHpR1Jvk9GnCT2M8hVgVjfyYAKE" + ], + "isAddress": true + }, + { + "value": "386875", + "n": 1, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000d08b3d88676bc81defa76eeb6f1322dd68bca50f34a9e8b", + "blockHeight": 447041, + "confirmations": 2034, + "blockTime": 1588752334, + "value": "486875", + "valueIn": "489415", + "fees": "2540", + "hex": "0100000001e036d74365e2c619c22c802c132e736a4bf966a4e5f5ab7b33b34c2d62d1e3660100000000f3ffffff02a08601000000000000001976a914f3fa335c33379fabe6d61c5491504d8d1ad6851c88ac3be705000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac000000000000000001c777070000000000298e0600030000006b483045022100b67f278e9552abddde008a4d91e5c1044d8cf01248378f6b4ed94514b23dbf5e022025c96ea8974f40833287f91f5d7a2a672654950993322ec91b32caf45a9d9fc90121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + }, + { + "txid": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0", + "version": 1, + "vin": [ + { + "txid": "2dc905f525885537310c8ab87f67dc175ca369af1fe7111a49a94451866aa019", + "sequence": 4294967291, + "n": 0, + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true, + "value": "591955", + "hex": "473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "489415", + "n": 1, + "spent": true, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000c12cb497e60470a3cf366d16705eaba303c2c4415cc7567", + "blockHeight": 429609, + "confirmations": 19466, + "blockTime": 1583516573, + "value": "589415", + "valueIn": "591955", + "fees": "2540", + "hex": "010000000119a06a865144a9491a11e71faf69a35c17dc677fb88a0c3137558825f505c92d0000000000fbffffff02a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acc77707000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac0000000000000000015308090000000000dbcc05000b0000006a473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + }, + { + "txid": "025abf340da79c4fc4de29667c08fc22cdafbded24c7c2a994a27f6fb4d5fa17", + "version": 1, + "vin": [ + { + "txid": "5a2a0d01ed8672d6bebd7dee447b2e0342bfc34fd4893bed58a4fa5aa87a4c42", + "n": 0, + "addresses": [ + "Dsf6WkLoiTcSGKmkXoSEdukqUfeRJMqUNJV" + ], + "isAddress": true, + "value": "19991980", + "hex": "483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "19889440", + "n": 1, + "hex": "76a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac", + "addresses": [ + "Dsesp1V6DZDEtcq2behmBVKdYqKMdkh96hL" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000264c499f21a7ef95bffb37148fc099514b2407dfa28c3287", + "blockHeight": 429186, + "confirmations": 19889, + "blockTime": 1583384838, + "value": "19989440", + "valueIn": "19991980", + "fees": "2540", + "hex": "0100000001424c7aa85afaa458ed3b89d44fc3bf42032e7b44ee7dbdbed67286ed010d2a5a00000000000000000002a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac207d2f010000000000001976a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac000000000000000001ac0d31010000000052630600050000006b483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" + }, + { + "txid": "68dcb93e36879f33e741f5706463af10387aadeba193cb204453ec23ad1b1979", + "version": 1, + "vin": [ + { + "txid": "d1352a165c773fe22556219916c2dbd3e184cbf29d9be88b4d52b1c321131601", + "vout": 1, + "sequence": 4294967291, + "n": 0, + "addresses": [ + "DseafVVZGqk4VMCiEJoxRS6FkUjxofh2PXA" + ], + "isAddress": true, + "value": "150582", + "hex": "473044022028e6a72865dfb231b6a64cb3bacc5421dde842c57a169d13b753c36e96cacd9f022049e381c5e8a7e82d96b8996898c43baebbb1e5e5e9f51c15beb17e29e784c257012102fed4dd58683487545cc89c1fd779bf70b46067b863921b0e0c1b09bbe56d4345" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "48042", + "n": 1, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000025750e22134a74a8a5389c716b51dc4757bf213c7dfbb70", + "blockHeight": 427612, + "confirmations": 21463, + "blockTime": 1582902615, + "value": "148042", + "valueIn": "150582", + "fees": "2540", + "hex": "010000000101161321c3b1524d8be89b9df2cb84e1d3dbc21699215625e23f775c162a35d10100000000fbffffff02a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acaabb00000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac000000000000000001364c020000000000f4c80500070000006a473044022028e6a72865dfb231b6a64cb3bacc5421dde842c57a169d13b753c36e96cacd9f022049e381c5e8a7e82d96b8996898c43baebbb1e5e5e9f51c15beb17e29e784c257012102fed4dd58683487545cc89c1fd779bf70b46067b863921b0e0c1b09bbe56d4345" + }, + { + "txid": "70a5caffaac9105b47ff9b70213f3a9f8bbd28f09335dce763a99f1b39e74ccf", + "version": 1, + "vin": [ + { + "txid": "2c922ec02ec0bc86803290191198232183e903ea2e79f7f6ddb6c7c7c193b9db", + "vout": 1, + "sequence": 4294967287, + "n": 0, + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true, + "value": "5292552", + "hex": "483045022100bc0999a9673f4f72b2bd79fd40c1b8a8398381edcc584f6ed868229e2ec5628b02205baab2c3b1cefdb41dc439782310931f15b31fd48544ca70f88c94940a3870800121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "4290012", + "n": 1, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000001c196ac1e8e050a3d7bc600bcb87826dca4ff558ac280014", + "blockHeight": 427609, + "confirmations": 21466, + "blockTime": 1582901951, + "value": "5290012", + "valueIn": "5292552", + "fees": "2540", + "hex": "0100000001dbb993c1c7c7b6ddf6f7792eea03e983212398111990328086bcc02ec02e922c0100000000f7ffffff0240420f000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acdc7541000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac00000000000000000108c2500000000000bc5d0600020000006b483045022100bc0999a9673f4f72b2bd79fd40c1b8a8398381edcc584f6ed868229e2ec5628b02205baab2c3b1cefdb41dc439782310931f15b31fd48544ca70f88c94940a3870800121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + }, + { + "txid": "2c922ec02ec0bc86803290191198232183e903ea2e79f7f6ddb6c7c7c193b9db", + "version": 1, + "vin": [ + { + "txid": "a81ab3f0d0744c42fcc8e5c3b0b77382323d0cf6ac73a55f982dcadc4fe604c7", + "vout": 1, + "n": 0, + "addresses": [ + "DseSHdQv3cZhuY3foizi3bbHHMw2o7RsNsu" + ], + "isAddress": true, + "value": "6295092", + "hex": "47304402206d190e10475b3dc57a9ec4aff060f1d9ee82e47b99d1f9cb2e926384ccdc04df022056040c8b364176c28876b597006faba7b0f1f74abcf0321e530520907b8ded8001210385ece82907d214f46db634a6326d99616ea022ec887991251215d1564120ac41" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "5292552", + "n": 1, + "spent": true, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000008e3020d59db97a9e69b7b77697369cee0cd600a3e3c106", + "blockHeight": 417211, + "confirmations": 31864, + "blockTime": 1579769314, + "value": "6292552", + "valueIn": "6295092", + "fees": "2540", + "hex": "0100000001c704e64fdcca2d985fa573acf60c3d328273b7b0c3e5c8fc424c74d0f0b31aa80100000000000000000240420f000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac08c250000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac000000000000000001340e600000000000c0050600070000006a47304402206d190e10475b3dc57a9ec4aff060f1d9ee82e47b99d1f9cb2e926384ccdc04df022056040c8b364176c28876b597006faba7b0f1f74abcf0321e530520907b8ded8001210385ece82907d214f46db634a6326d99616ea022ec887991251215d1564120ac41" + }, + { + "txid": "b23b63aff6fb5dbfef139f8e0ff0cb9a34b9dbe1b110278d8391b3713b6ca67c", + "version": 1, + "vin": [ + { + "txid": "2138de727f692d55e76f9cd9c1ce30203fe85d8fc64a72703fa0ad7b0a31ca6c", + "vout": 1, + "n": 0, + "addresses": [ + "DsmjpgebRNYbUtAc3KooGpM1pecV1ENJVUe" + ], + "isAddress": true, + "value": "87460", + "hex": "47304402202025782b52bb328a604b2a0c0458eda1c49b53e945cf9deb79627a8d6009cf64022057dcbbad19df5402309191d0ac1f8fc60b35e6ffe309e3c346bb69e5c46ebc6c012103ac7a88d60a68fd722e43a149cb50a7f05075e1192c4351df1dd244e1b38f5f05" + } + ], + "vout": [ + { + "value": "85300", + "n": 0, + "hex": "76a91479cf64f9c950f80da936b57a7d838ae4fd8b1d1388ac", + "addresses": [ + "Dsc4yhfEdqj31WCbtRgv2cXNCtdJNHFCg4o" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000118884be52c6ca7123b651a48dc1c3b9f069932a3694e7d0", + "blockHeight": 403824, + "confirmations": 45251, + "blockTime": 1575752600, + "value": "85300", + "valueIn": "87460", + "fees": "2160", + "hex": "01000000016cca310a7bada03f70724ac68f5de83f2030cec1d99c6fe7552d697f72de382101000000000000000001344d01000000000000001976a91479cf64f9c950f80da936b57a7d838ae4fd8b1d1388ac000000000000000001a45501000000000017c70500010000006a47304402202025782b52bb328a604b2a0c0458eda1c49b53e945cf9deb79627a8d6009cf64022057dcbbad19df5402309191d0ac1f8fc60b35e6ffe309e3c346bb69e5c46ebc6c012103ac7a88d60a68fd722e43a149cb50a7f05075e1192c4351df1dd244e1b38f5f05" + }, + { + "txid": "a81ab3f0d0744c42fcc8e5c3b0b77382323d0cf6ac73a55f982dcadc4fe604c7", + "version": 1, + "vin": [ + { + "txid": "f901951a6552d84a047170534a17f176dddf3ff05046d94d5a4f60e951cb7814", + "vout": 1, + "n": 0, + "addresses": [ + "Dse6xFAU3LBzNeFZiPGJHuBRebHN74Sr2ry" + ], + "isAddress": true, + "value": "18643310", + "hex": "4830450221008d6be510c08e051ed4b1f4e00503595531f4800d042a438cb76681677e471b3c022072fb18f79fd673d86449b3ca77e846a9c8ffb87551ce3597b1b206f5d99fa3ab01210212d8d67fa0db8a51432cbbff4d29d5a2ec407f43958800e3770c277b6c22e4ca" + } + ], + "vout": [ + { + "value": "12345678", + "n": 0, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "6295092", + "n": 1, + "spent": true, + "hex": "76a91493c7588139797500ca13011a73e01a78da3092cd88ac", + "addresses": [ + "DseSHdQv3cZhuY3foizi3bbHHMw2o7RsNsu" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000017871738a562ecfe28699613f578177c3d43c00124b65abe", + "blockHeight": 394687, + "confirmations": 54388, + "blockTime": 1573005579, + "value": "18640770", + "valueIn": "18643310", + "fees": "2540", + "hex": "01000000011478cb51e9604f5a4dd94650f03fdfdd76f1174a537071044ad852651a9501f9010000000000000000024e61bc000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac340e60000000000000001976a91493c7588139797500ca13011a73e01a78da3092cd88ac0000000000000000016e791c0100000000d4cc0500010000006b4830450221008d6be510c08e051ed4b1f4e00503595531f4800d042a438cb76681677e471b3c022072fb18f79fd673d86449b3ca77e846a9c8ffb87551ce3597b1b206f5d99fa3ab01210212d8d67fa0db8a51432cbbff4d29d5a2ec407f43958800e3770c277b6c22e4ca" + }, + { + "txid": "2dc905f525885537310c8ab87f67dc175ca369af1fe7111a49a94451866aa019", + "version": 1, + "vin": [ + { + "txid": "f901951a6552d84a047170534a17f176dddf3ff05046d94d5a4f60e951cb7814", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "DsoCwRHkCHpR1Jvk9GnCT2M8hVgVjfyYAKE" + ], + "isAddress": true, + "value": "594495", + "hex": "483045022100fdc5b54189aaaa7c0e622dd5723ab3da9431ef84b38f6a7d5fc5285f07dbe7980220207b75cd3f047757e54812a711f38add03073e24f767cc04b4f784ce1a8e3913012103702335aa130d38e61b4444b5413febdb3cffc552ddffa97212882908662ae454" + } + ], + "vout": [ + { + "value": "591955", + "n": 0, + "spent": true, + "hex": "76a914cf1c37327174a9eb957bc879320c405f7f678b7588ac", + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000017c392360a4bd7c3c184404d9f5c73abcf7aad990170948e", + "blockHeight": 380122, + "confirmations": 68953, + "blockTime": 1568625431, + "value": "591955", + "valueIn": "594495", + "fees": "2540", + "hex": "01000000011478cb51e9604f5a4dd94650f03fdfdd76f1174a537071044ad852651a9501f90000000000feffffff01530809000000000000001976a914cf1c37327174a9eb957bc879320c405f7f678b7588ac0000000000000000013f12090000000000d4cc0500010000006b483045022100fdc5b54189aaaa7c0e622dd5723ab3da9431ef84b38f6a7d5fc5285f07dbe7980220207b75cd3f047757e54812a711f38add03073e24f767cc04b4f784ce1a8e3913012103702335aa130d38e61b4444b5413febdb3cffc552ddffa97212882908662ae454" + }, + { + "txid": "f901951a6552d84a047170534a17f176dddf3ff05046d94d5a4f60e951cb7814", + "version": 1, + "vin": [ + { + "txid": "6928795181bd951849bcdebab2f012b1f6a71f8f1993e573ee1b531207c61255", + "vout": 1, + "sequence": 4294967293, + "n": 0, + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true, + "value": "19240345", + "hex": "483045022100feace09f456985a5d1d8a44fea21282138799202a2a441542b44f38ad9cc24fd022045b87fa9869462465bbe605863c31243911dccadde4ffb4c853be7719b31d9b9012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + } + ], + "vout": [ + { + "value": "594495", + "n": 0, + "spent": true, + "hex": "76a914f3fa335c33379fabe6d61c5491504d8d1ad6851c88ac", + "addresses": [ + "DsoCwRHkCHpR1Jvk9GnCT2M8hVgVjfyYAKE" + ], + "isAddress": true + }, + { + "value": "18643310", + "n": 1, + "spent": true, + "hex": "76a914901f43073875d802f83f19568407d3e4721ec6c688ac", + "addresses": [ + "Dse6xFAU3LBzNeFZiPGJHuBRebHN74Sr2ry" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000000181a2cb9b30a08020e747f249fc6ab8b6fed7d467565c608", + "blockHeight": 380115, + "confirmations": 68960, + "blockTime": 1568621402, + "value": "19237805", + "valueIn": "19240345", + "fees": "2540", + "hex": "01000000015512c60712531bee73e593198f1fa7f6b112f0b2badebc491895bd81517928690100000000fdffffff023f1209000000000000001976a914f3fa335c33379fabe6d61c5491504d8d1ad6851c88ac6e791c010000000000001976a914901f43073875d802f83f19568407d3e4721ec6c688ac00000000000000000199952501000000008dc80500030000006b483045022100feace09f456985a5d1d8a44fea21282138799202a2a441542b44f38ad9cc24fd022045b87fa9869462465bbe605863c31243911dccadde4ffb4c853be7719b31d9b9012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + }, + { + "txid": "d1352a165c773fe22556219916c2dbd3e184cbf29d9be88b4d52b1c321131601", + "version": 1, + "vin": [ + { + "txid": "ce314ec559ceae4d2a98ed4708848708c9cfde14b484b879838a2dc75c793910", + "vout": 1, + "sequence": 4294967291, + "n": 0, + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true, + "value": "172574", + "hex": "47304402203e9fb2dd6e7105ea850fed2ae1d7073c1aaa27bc8bbff79d03edd3799ff854f702200910ba540373613bed8f108754fab7cf9d2f4ff3cc807d0cab33637641044b07012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + } + ], + "vout": [ + { + "value": "19452", + "n": 0, + "hex": "76a9148e5323908a6d4869d4b85e45998a143ab4d0631a88ac", + "addresses": [ + "DsdwT3GGppDmuPSEetywszY7Y95jGpLopSU" + ], + "isAddress": true + }, + { + "value": "150582", + "n": 1, + "spent": true, + "hex": "76a914955cec92163c1b9b2469596948c1f4601955cc5688ac", + "addresses": [ + "DseafVVZGqk4VMCiEJoxRS6FkUjxofh2PXA" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000a7785b2e8916051e66db1f1fcaad299eb2a3c045b1d832d", + "blockHeight": 379124, + "confirmations": 69951, + "blockTime": 1568325197, + "value": "170034", + "valueIn": "172574", + "fees": "2540", + "hex": "01000000011039795cc72d8a8379b884b414decfc90887840847ed982a4daece59c54e31ce0100000000fbffffff02fc4b00000000000000001976a9148e5323908a6d4869d4b85e45998a143ab4d0631a88ac364c02000000000000001976a914955cec92163c1b9b2469596948c1f4601955cc5688ac0000000000000000011ea20200000000008ec80500080000006a47304402203e9fb2dd6e7105ea850fed2ae1d7073c1aaa27bc8bbff79d03edd3799ff854f702200910ba540373613bed8f108754fab7cf9d2f4ff3cc807d0cab33637641044b07012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" + }, + { + "txid": "ce314ec559ceae4d2a98ed4708848708c9cfde14b484b879838a2dc75c793910", + "version": 1, + "vin": [ + { + "txid": "6928795181bd951849bcdebab2f012b1f6a71f8f1993e573ee1b531207c61255", + "sequence": 4294967293, + "n": 0, + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true, + "value": "194571", + "hex": "483045022100dd4fafb4a6d89f81b0602a3305aac956decad8e65182cd690eda70854eccc43a022055a23cd4eff950901494fe0f53d880a5c04ca23e822116d91a9ada83ba6baf010121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + } + ], + "vout": [ + { + "value": "19457", + "n": 0, + "hex": "76a914a0f82f406aa9ce69402d915f9e93312c9e5d796988ac", + "addresses": [ + "Dsfe2vHn1TVqHJWeD37BXL1y31nWeBQqB7c" + ], + "isAddress": true + }, + { + "value": "172574", + "n": 1, + "spent": true, + "hex": "76a914cf1c37327174a9eb957bc879320c405f7f678b7588ac", + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000004f7b5a862dc2f9fa6acc037a743913056d2882856ba4314", + "blockHeight": 379022, + "confirmations": 70053, + "blockTime": 1568292291, + "value": "192031", + "valueIn": "194571", + "fees": "2540", + "hex": "01000000015512c60712531bee73e593198f1fa7f6b112f0b2badebc491895bd81517928690000000000fdffffff02014c00000000000000001976a914a0f82f406aa9ce69402d915f9e93312c9e5d796988ac1ea202000000000000001976a914cf1c37327174a9eb957bc879320c405f7f678b7588ac0000000000000000010bf80200000000008dc80500030000006b483045022100dd4fafb4a6d89f81b0602a3305aac956decad8e65182cd690eda70854eccc43a022055a23cd4eff950901494fe0f53d880a5c04ca23e822116d91a9ada83ba6baf010121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + }, + { + "txid": "6928795181bd951849bcdebab2f012b1f6a71f8f1993e573ee1b531207c61255", + "version": 1, + "vin": [ + { + "txid": "4510dd5fa05c5a8a1ab44a9b77315bf989a3749eb2ff2b651648313dc15c98f9", + "vout": 1, + "sequence": 4294967293, + "n": 0, + "addresses": [ + "DsmwaUbFCWoZCjGv2bYA8bmmXFarWgc6zHY" + ], + "isAddress": true, + "value": "19437456", + "hex": "483045022100a9bdbc46b9856b592d50fc718a818393a53c380fd08dae92a470293d0b7da5f102203e4addd7634bcc14546840cb80f13b6e994d4523a80a46dfd951b173d62a49d6012103bb6681dc8e643af1a54e94e7efe9089f4b9051b2e43803050d6b5a7de7991a11" + } + ], + "vout": [ + { + "value": "194571", + "n": 0, + "spent": true, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + }, + { + "value": "19240345", + "n": 1, + "spent": true, + "hex": "76a914cf1c37327174a9eb957bc879320c405f7f678b7588ac", + "addresses": [ + "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000bde3ce71634ce6fa7ed894c6d016fba61abb0a94d2c4afa", + "blockHeight": 379020, + "confirmations": 70055, + "blockTime": 1568292043, + "value": "19434916", + "valueIn": "19437456", + "fees": "2540", + "hex": "0100000001f9985cc13d314816652bffb29e74a389f95b31779b4ab41a8a5a5ca05fdd10450100000000fdffffff020bf802000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac999525010000000000001976a914cf1c37327174a9eb957bc879320c405f7f678b7588ac0000000000000000019097280100000000bdc70500030000006b483045022100a9bdbc46b9856b592d50fc718a818393a53c380fd08dae92a470293d0b7da5f102203e4addd7634bcc14546840cb80f13b6e994d4523a80a46dfd951b173d62a49d6012103bb6681dc8e643af1a54e94e7efe9089f4b9051b2e43803050d6b5a7de7991a11" + }, + { + "txid": "4510dd5fa05c5a8a1ab44a9b77315bf989a3749eb2ff2b651648313dc15c98f9", + "version": 1, + "vin": [ + { + "txid": "cc227d117d0f7d9b8aaaee4ce11bd6eaafa62adbddea9428c9bc8f257b56b50c", + "vout": 1, + "sequence": 2147483646, + "n": 0, + "addresses": [ + "DshALmistThHv2qmXM5wF5ACqPLzSfk8Syf" + ], + "isAddress": true, + "value": "19467142", + "hex": "4830450221009b010fbaeedc912e82c2d864a0d359f4b0723b1f17403c05d050f823b3015cd702204533b28be9722798f5c180ee381345115e914c55422ecdf7b4a2003f8b1d657e01210234a89c9f685966ab79a095d65e3253cb6e2fc0d5d6fb18fef090a045a729b7aa" + } + ], + "vout": [ + { + "value": "19686", + "n": 0, + "hex": "76a914f57b7845ed8064ab991b23ebd49003a1e596ecda88ac", + "addresses": [ + "DsoLtxGAPidBykdxWkzRAmhgBwBeqLdJEXR" + ], + "isAddress": true + }, + { + "value": "19437456", + "n": 1, + "spent": true, + "hex": "76a914e61a5a5f5a70f22de8156a15a510e82369bc48de88ac", + "addresses": [ + "DsmwaUbFCWoZCjGv2bYA8bmmXFarWgc6zHY" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000001c055f129cbd785708947616301cc4ec3cfe604c84be884f", + "blockHeight": 378812, + "confirmations": 70263, + "blockTime": 1568228155, + "value": "19457142", + "valueIn": "19467142", + "fees": "10000", + "hex": "01000000010cb5567b258fbcc92894eadddb2aa6afead61be14ceeaa8a9b7d0f7d117d22cc0100000000feffff7f02e64c00000000000000001976a914f57b7845ed8064ab991b23ebd49003a1e596ecda88ac909728010000000000001976a914e61a5a5f5a70f22de8156a15a510e82369bc48de88ac000000000000000001860b290100000000abc70500070000006b4830450221009b010fbaeedc912e82c2d864a0d359f4b0723b1f17403c05d050f823b3015cd702204533b28be9722798f5c180ee381345115e914c55422ecdf7b4a2003f8b1d657e01210234a89c9f685966ab79a095d65e3253cb6e2fc0d5d6fb18fef090a045a729b7aa" + }, + { + "txid": "cc227d117d0f7d9b8aaaee4ce11bd6eaafa62adbddea9428c9bc8f257b56b50c", + "version": 1, + "vin": [ + { + "txid": "ae12bcde96172c2953e27562a8ee0c0a3368ddfbca5f4d9562e866e965a5232b", + "sequence": 2147483644, + "n": 0, + "addresses": [ + "DsowaTuYHygWaxox11yKbRSoQhfpjLmbzuL" + ], + "isAddress": true, + "value": "193136", + "hex": "47304402204f2d922cc2b2f4fc31e9715369231ac622e6e018691c7187136cc6ab9918ce9702207c4925d14ac86f07a9e0300c7d1af3d4d18cc57fb90cde2c26f0230e4fcf6c860121025cc5f64fc451b54c56f044580a56c50b4fb3f4d4d69158e8898ddb8cf892de65" + }, + { + "txid": "8081de85157ca6cb5d12c3971e2cac6aa0e95370826a89307bfe144d3db33d1c", + "vout": 1, + "sequence": 2147483645, + "n": 1, + "addresses": [ + "DsRtQjGTkaBTyHqsTyN1Gv3N8QMkrnRg3yd" + ], + "isAddress": true, + "value": "19473775", + "hex": "483045022100f67c9e02ac7dbd58368c25c4b69ee6a4cfef77f0385677831c6f8625874917e102204e5e143fbc13c6187f4a02268cb53480ad6b10bafe74edb1fe67f72d608492850121034ebee1373499bec415fb9b6eabbf6d659fa4f5c06b93014c89c65777d7c3886c" + }, + { + "txid": "8081de85157ca6cb5d12c3971e2cac6aa0e95370826a89307bfe144d3db33d1c", + "sequence": 2147483646, + "n": 2, + "addresses": [ + "DsWmtukoGFxtrHUBoM7UnFVfnBANBRgZ22c" + ], + "isAddress": true, + "value": "19697", + "hex": "4730440220404be3f0940ad6d321b976e61802c15d9cfad4bff7bbdb58ffa81d044cfa085c02202257ab91ddde8b75f74785a850e71c0033dacf64aff194dd1f315e7121c1f5eb012102c6e0318938086b3b7164dabd33263de83a1c3e59cc6b4dde8853927dd0eb6853" + } + ], + "vout": [ + { + "value": "196866", + "n": 0, + "hex": "76a9140f685cce0b2c2825e4157c2af925f9cf21d691bd88ac", + "addresses": [ + "DsSNNeYSYA9VYNe9m1YBZPoUKmqmkts9moi" + ], + "isAddress": true + }, + { + "value": "19467142", + "n": 1, + "spent": true, + "hex": "76a914b1abb109bc360fdd86b8d1e728eb147164897c1f88ac", + "addresses": [ + "DshALmistThHv2qmXM5wF5ACqPLzSfk8Syf" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000f8c0b11a62d2df16039706c72d37c672cea8b02ea8b9393", + "blockHeight": 378794, + "confirmations": 70281, + "blockTime": 1568221848, + "value": "19664008", + "valueIn": "19686608", + "fees": "22600", + "hex": "01000000032b23a565e966e862954d5fcafbdd68330a0ceea86275e253292c1796debc12ae0000000000fcffff7f1c3db33d4d14fe7b30896a827053e9a06aac2c1e97c3125dcba67c1585de81800100000000fdffff7f1c3db33d4d14fe7b30896a827053e9a06aac2c1e97c3125dcba67c1585de81800000000000feffff7f02020103000000000000001976a9140f685cce0b2c2825e4157c2af925f9cf21d691bd88ac860b29010000000000001976a914b1abb109bc360fdd86b8d1e728eb147164897c1f88ac00000000000000000370f2020000000000a6c70500030000006a47304402204f2d922cc2b2f4fc31e9715369231ac622e6e018691c7187136cc6ab9918ce9702207c4925d14ac86f07a9e0300c7d1af3d4d18cc57fb90cde2c26f0230e4fcf6c860121025cc5f64fc451b54c56f044580a56c50b4fb3f4d4d69158e8898ddb8cf892de656f25290100000000a4c70500010000006b483045022100f67c9e02ac7dbd58368c25c4b69ee6a4cfef77f0385677831c6f8625874917e102204e5e143fbc13c6187f4a02268cb53480ad6b10bafe74edb1fe67f72d608492850121034ebee1373499bec415fb9b6eabbf6d659fa4f5c06b93014c89c65777d7c3886cf14c000000000000a4c70500010000006a4730440220404be3f0940ad6d321b976e61802c15d9cfad4bff7bbdb58ffa81d044cfa085c02202257ab91ddde8b75f74785a850e71c0033dacf64aff194dd1f315e7121c1f5eb012102c6e0318938086b3b7164dabd33263de83a1c3e59cc6b4dde8853927dd0eb6853" + }, + { + "txid": "ae12bcde96172c2953e27562a8ee0c0a3368ddfbca5f4d9562e866e965a5232b", + "version": 1, + "vin": [ + { + "txid": "374e7179bec21f341a648bd012a89863b8a262d3854c9e662837d2f32441bdef", + "sequence": 2147483646, + "n": 0, + "addresses": [ + "DshHAv8CmxHwdKUs1Dfddv8sv4o6hN8LpaQ" + ], + "isAddress": true, + "value": "196976", + "hex": "483045022100985710b5c20e407ac42b5c908c65408dc9118d040ee13e8cf1962df560956c2302202dc9c9ea10045380ba8ee402dff4832e66a28f9aa5f9dc8b0be080f9c1939d9e0121021224cf94a0455dcbfe727ea404e1ed174c112bbffb1d50dd383c50bc4d188406" + } + ], + "vout": [ + { + "value": "193136", + "n": 0, + "spent": true, + "hex": "76a914fc0a984061ba5819f7ab8a0ea7d546e691d1a50b88ac", + "addresses": [ + "DsowaTuYHygWaxox11yKbRSoQhfpjLmbzuL" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000db2a3d8ab366e7894d062919539dd92a05fb974731383af", + "blockHeight": 378790, + "confirmations": 70285, + "blockTime": 1568219847, + "value": "193136", + "valueIn": "196976", + "fees": "3840", + "hex": "0100000001efbd4124f3d23728669e4c85d362a2b86398a812d08b641a341fc2be79714e370000000000feffff7f0170f202000000000000001976a914fc0a984061ba5819f7ab8a0ea7d546e691d1a50b88ac0000000000000000017001030000000000a2c70500030000006b483045022100985710b5c20e407ac42b5c908c65408dc9118d040ee13e8cf1962df560956c2302202dc9c9ea10045380ba8ee402dff4832e66a28f9aa5f9dc8b0be080f9c1939d9e0121021224cf94a0455dcbfe727ea404e1ed174c112bbffb1d50dd383c50bc4d188406" + }, + { + "txid": "8081de85157ca6cb5d12c3971e2cac6aa0e95370826a89307bfe144d3db33d1c", + "version": 1, + "vin": [ + { + "txid": "374e7179bec21f341a648bd012a89863b8a262d3854c9e662837d2f32441bdef", + "vout": 1, + "sequence": 2147483646, + "n": 0, + "addresses": [ + "DsUg8xbvU9irDqtMmWxLHaXSByRGGFcbHs6" + ], + "isAddress": true, + "value": "19496184", + "hex": "483045022100a0fddf430dcd68754145d54b660064feca0d5fe173d6f76024f1e30ed856926402202314ab99f4e5b236458965038d6eea9b4e174ede6c3b122a7bb4554e84d54e63012102a3754902a372bee2b4f0946f3f4388d3b555ac77fde9360665d86f37ef3820f4" + } + ], + "vout": [ + { + "value": "19697", + "n": 0, + "spent": true, + "hex": "76a9143fbbb1c889263b06fc6383e77f87b30b865d507e88ac", + "addresses": [ + "DsWmtukoGFxtrHUBoM7UnFVfnBANBRgZ22c" + ], + "isAddress": true + }, + { + "value": "19473775", + "n": 1, + "spent": true, + "hex": "76a9140a1e73fe7705c2a5ca99e9caa309ad7fe22f318188ac", + "addresses": [ + "DsRtQjGTkaBTyHqsTyN1Gv3N8QMkrnRg3yd" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000006af0cbcd6a0882fe41155e54343d2491a745f72c6e6cec1", + "blockHeight": 378787, + "confirmations": 70288, + "blockTime": 1568218744, + "value": "19493472", + "valueIn": "19496184", + "fees": "2712", + "hex": "0100000001efbd4124f3d23728669e4c85d362a2b86398a812d08b641a341fc2be79714e370100000000feffff7f02f14c00000000000000001976a9143fbbb1c889263b06fc6383e77f87b30b865d507e88ac6f2529010000000000001976a9140a1e73fe7705c2a5ca99e9caa309ad7fe22f318188ac000000000000000001f87c290100000000a2c70500030000006b483045022100a0fddf430dcd68754145d54b660064feca0d5fe173d6f76024f1e30ed856926402202314ab99f4e5b236458965038d6eea9b4e174ede6c3b122a7bb4554e84d54e63012102a3754902a372bee2b4f0946f3f4388d3b555ac77fde9360665d86f37ef3820f4" + }, + { + "txid": "374e7179bec21f341a648bd012a89863b8a262d3854c9e662837d2f32441bdef", + "version": 1, + "vin": [ + { + "txid": "0e127e2c47f2a8779c007ec092bb641c84fcfaad043578b85193372ce57647ca", + "vout": 1, + "sequence": 2147483645, + "n": 0, + "addresses": [ + "DsoUYJStadLjrvgTSL4AVHsP8f6uG7TXEYi" + ], + "isAddress": true, + "value": "19677983", + "hex": "47304402207f20ea5436abacbf2e846c2f7a17a70a69970240cc0aadcd06491880e3e19ccf022016f21eeafeaaec1ccb50119f6d6707cb175fe8d52d71cbe09a233010429ddbdf01210277aabb5d244665b771ebd3c59d6eda42b7a95f53b937e7d8c74f85f0f9c3346a" + }, + { + "txid": "0e127e2c47f2a8779c007ec092bb641c84fcfaad043578b85193372ce57647ca", + "sequence": 2147483646, + "n": 1, + "addresses": [ + "DsnrYbE1bZ5yPMphTuZ8C7bQyRjBi4pbGeX" + ], + "isAddress": true, + "value": "19697", + "hex": "483045022100f11a5745288e675c7225a50db44f46e8f626112abe1236403b2a7821fad06c97022049d2d7b75092279e3246a84641abbc70606439b2c3e93a79b56b26a32b241a9b0121025e52eafdbe47878d9e8c6954123c6bb6eb40d851d57e14bda352b25489654650" + } + ], + "vout": [ + { + "value": "196976", + "n": 0, + "spent": true, + "hex": "76a914b2f6606b247714118e2824d8377d430289bf8e9a88ac", + "addresses": [ + "DshHAv8CmxHwdKUs1Dfddv8sv4o6hN8LpaQ" + ], + "isAddress": true + }, + { + "value": "19496184", + "n": 1, + "spent": true, + "hex": "76a91428b4acba0ed858454846b70a4cdfe34b926efae288ac", + "addresses": [ + "DsUg8xbvU9irDqtMmWxLHaXSByRGGFcbHs6" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000001a409bed8a0b608d015c15e8537387eb4bdb543b804874ee", + "blockHeight": 378786, + "confirmations": 70289, + "blockTime": 1568218103, + "value": "19693160", + "valueIn": "19697680", + "fees": "4520", + "hex": "0100000002ca4776e52c379351b8783504adfafc841c64bb92c07e009c77a8f2472c7e120e0100000000fdffff7fca4776e52c379351b8783504adfafc841c64bb92c07e009c77a8f2472c7e120e0000000000feffff7f02700103000000000000001976a914b2f6606b247714118e2824d8377d430289bf8e9a88acf87c29010000000000001976a91428b4acba0ed858454846b70a4cdfe34b926efae288ac0000000000000000021f432c01000000009ac70500010000006a47304402207f20ea5436abacbf2e846c2f7a17a70a69970240cc0aadcd06491880e3e19ccf022016f21eeafeaaec1ccb50119f6d6707cb175fe8d52d71cbe09a233010429ddbdf01210277aabb5d244665b771ebd3c59d6eda42b7a95f53b937e7d8c74f85f0f9c3346af14c0000000000009ac70500010000006b483045022100f11a5745288e675c7225a50db44f46e8f626112abe1236403b2a7821fad06c97022049d2d7b75092279e3246a84641abbc70606439b2c3e93a79b56b26a32b241a9b0121025e52eafdbe47878d9e8c6954123c6bb6eb40d851d57e14bda352b25489654650" + }, + { + "txid": "0e127e2c47f2a8779c007ec092bb641c84fcfaad043578b85193372ce57647ca", + "version": 1, + "vin": [ + { + "txid": "2138de727f692d55e76f9cd9c1ce30203fe85d8fc64a72703fa0ad7b0a31ca6c", + "sequence": 2147483643, + "n": 0, + "addresses": [ + "DspBxSac8FWcKWi1MfpZiYZeFPSWRznmBAT" + ], + "isAddress": true, + "value": "10000", + "hex": "4830450221008a34ff313ccb1facfa57a4fab181b1ff81ee1f3e8043d20524b4f909c8ae3440022021bd68bd9b6b13151de63194da93defcb78f605935060eebf3e453c0444e29da012102d77499b1b96917cde09a14f56972b9ce9a0a1d54ff4a8fb53cf661acc97e1947" + }, + { + "txid": "c416dd7cfb276aead083ea7bb3648f50902d6602d58624232dfc5035f1da8a88", + "vout": 1, + "sequence": 2147483644, + "n": 1, + "addresses": [ + "Dsn9CTECmGUK8uM8kKiTugmxiy16dh18pRZ" + ], + "isAddress": true, + "value": "897460", + "hex": "47304402205e34414797dec57016f7ac4ac9ab746fbe946150242a135f19b8d0ff3efcd5730220295e27becf1f67b3c6fa53977e54beef8abdc95a20f95c7639c6c801fba043280121039da1c8459eb5dcc38dede0f4caf9db65500136e385041e793695c4819d10a13b" + }, + { + "txid": "1a142ae8243b58062d63eefe3a9e824608ef4ad32fff00726a2ee66f08c165a5", + "vout": 1, + "sequence": 2147483645, + "n": 2, + "addresses": [ + "DsUz6RQnnhzhXphPe7wCRe1JE6Znn912VqC" + ], + "isAddress": true, + "value": "18690220", + "hex": "463043021f6ef23907add7ba3c03ac00ea02414e5cf9a1821eb19f71593d3e30e053bf2902201f95f1de74f94ab6e24372264cb4739fe47adb9c82b9b1abd14e7811587c91a10121023fb5b17d1eae140fe098877afab49d45f07509acf848bfb1311bf6cfb64ad8da" + }, + { + "txid": "076325760e3bdc16323b5de8ef5563ef10809568e13d9fc76e2ee8d523bb200c", + "sequence": 2147483646, + "n": 3, + "addresses": [ + "DsW4aSTWVaW1V6jPLu1K9PzSFWBCLJuexkm" + ], + "isAddress": true, + "value": "100000", + "hex": "483045022100d635b8214ee61095917956cdd2a1c0d35e7b135b280704a9db25f9d3a3a957d202204e45da95f8bf029be802c68aafb7f60ef820b194df2871a4a483499632002ca2012102a1608ef89e8b7a80531436eb05421a5dc427c1c1515f6ce8285df1bf20d59219" + } + ], + "vout": [ + { + "value": "19697", + "n": 0, + "spent": true, + "hex": "76a914f01ed3302c231e4ad30ad4965d058e68c1ef12ef88ac", + "addresses": [ + "DsnrYbE1bZ5yPMphTuZ8C7bQyRjBi4pbGeX" + ], + "isAddress": true + }, + { + "value": "19677983", + "n": 1, + "spent": true, + "hex": "76a914f6ed8edfe15349528b7e797fe64d5c032772627e88ac", + "addresses": [ + "DsoUYJStadLjrvgTSL4AVHsP8f6uG7TXEYi" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000001598d3aed4e50f75ba4e3abea4629853d3cc60d5de07adcd", + "blockHeight": 378778, + "confirmations": 70297, + "blockTime": 1568214596, + "value": "19697680", + "valueIn": "19697680", + "fees": "0", + "hex": "01000000046cca310a7bada03f70724ac68f5de83f2030cec1d99c6fe7552d697f72de38210000000000fbffff7f888adaf13550fc2d232486d502662d90508f64b37bea83d0ea6a27fb7cdd16c40100000000fcffff7fa565c1086fe62e6a7200ff2fd34aef0846829e3afeee632d06583b24e82a141a0100000000fdffff7f0c20bb23d5e82e6ec79f3de168958010ef6355efe85d3b3216dc3b0e762563070000000000feffff7f02f14c00000000000000001976a914f01ed3302c231e4ad30ad4965d058e68c1ef12ef88ac1f432c010000000000001976a914f6ed8edfe15349528b7e797fe64d5c032772627e88ac000000000000000004102700000000000017c70500010000006b4830450221008a34ff313ccb1facfa57a4fab181b1ff81ee1f3e8043d20524b4f909c8ae3440022021bd68bd9b6b13151de63194da93defcb78f605935060eebf3e453c0444e29da012102d77499b1b96917cde09a14f56972b9ce9a0a1d54ff4a8fb53cf661acc97e1947b4b10d0000000000edc40500040000006a47304402205e34414797dec57016f7ac4ac9ab746fbe946150242a135f19b8d0ff3efcd5730220295e27becf1f67b3c6fa53977e54beef8abdc95a20f95c7639c6c801fba043280121039da1c8459eb5dcc38dede0f4caf9db65500136e385041e793695c4819d10a13bac301d01000000006dc305000200000069463043021f6ef23907add7ba3c03ac00ea02414e5cf9a1821eb19f71593d3e30e053bf2902201f95f1de74f94ab6e24372264cb4739fe47adb9c82b9b1abd14e7811587c91a10121023fb5b17d1eae140fe098877afab49d45f07509acf848bfb1311bf6cfb64ad8daa08601000000000026c30500060000006b483045022100d635b8214ee61095917956cdd2a1c0d35e7b135b280704a9db25f9d3a3a957d202204e45da95f8bf029be802c68aafb7f60ef820b194df2871a4a483499632002ca2012102a1608ef89e8b7a80531436eb05421a5dc427c1c1515f6ce8285df1bf20d59219" + }, + { + "txid": "2138de727f692d55e76f9cd9c1ce30203fe85d8fc64a72703fa0ad7b0a31ca6c", + "version": 1, + "vin": [ + { + "txid": "c416dd7cfb276aead083ea7bb3648f50902d6602d58624232dfc5035f1da8a88", + "n": 0, + "addresses": [ + "DscLqW7bs478sVUKzi3e3q11ogmF7mKwnmd" + ], + "isAddress": true, + "value": "100000", + "hex": "473044022032026f00e5012dabfa73821e6396eec427e6352b0f70a1463c032ba9965092e302205e1de3b0c019c25aef610153a90aa2a53845c4fb5af91b5fa32389c1ada295e4012102301f55ea3a582662bd6a87acf3bbedba5c2f8e55b870105cf2af720562eb1636" + } + ], + "vout": [ + { + "value": "10000", + "n": 0, + "spent": true, + "hex": "76a914fec2c387356e5d0a0b2754ef7158f06a4f85e91288ac", + "addresses": [ + "DspBxSac8FWcKWi1MfpZiYZeFPSWRznmBAT" + ], + "isAddress": true + }, + { + "value": "87460", + "n": 1, + "spent": true, + "hex": "76a914e3e138bc8b704663c3bfecc603549d0c795bef3288ac", + "addresses": [ + "DsmjpgebRNYbUtAc3KooGpM1pecV1ENJVUe" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000000062626f17c08bee76c06d41438f6e996c0bfbbc1c2ed16", + "blockHeight": 378646, + "confirmations": 70429, + "blockTime": 1568179113, + "value": "97460", + "valueIn": "100000", + "fees": "2540", + "hex": "0100000001888adaf13550fc2d232486d502662d90508f64b37bea83d0ea6a27fb7cdd16c400000000000000000002102700000000000000001976a914fec2c387356e5d0a0b2754ef7158f06a4f85e91288aca45501000000000000001976a914e3e138bc8b704663c3bfecc603549d0c795bef3288ac000000000000000001a086010000000000edc40500040000006a473044022032026f00e5012dabfa73821e6396eec427e6352b0f70a1463c032ba9965092e302205e1de3b0c019c25aef610153a90aa2a53845c4fb5af91b5fa32389c1ada295e4012102301f55ea3a582662bd6a87acf3bbedba5c2f8e55b870105cf2af720562eb1636" + }, + { + "txid": "c416dd7cfb276aead083ea7bb3648f50902d6602d58624232dfc5035f1da8a88", + "version": 1, + "vin": [ + { + "txid": "1a142ae8243b58062d63eefe3a9e824608ef4ad32fff00726a2ee66f08c165a5", + "n": 0, + "addresses": [ + "DsU58J9shjqUh8QsEYn9N9xdq19SQRnw1WP" + ], + "isAddress": true, + "value": "1000000", + "hex": "4730440220769fd7bcbdf23848258688e60e6be15c16eed200f8c3d92e1e1e0af35f76f5d202200a69bdeba50dfcafeacee8acba1b8ae6608b786861310af6e2faef946d1aa8a0012103308b19c0e8e51700acebce494cd22fe5b2a5723279ecb90cb4e0ecd7c95f4141" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a9147ccf34a1e67d66714f0c162d0e84b9edaad895c688ac", + "addresses": [ + "DscLqW7bs478sVUKzi3e3q11ogmF7mKwnmd" + ], + "isAddress": true + }, + { + "value": "897460", + "n": 1, + "spent": true, + "hex": "76a914e84cf5d4407038a0e0f360dce5799f9882303cef88ac", + "addresses": [ + "Dsn9CTECmGUK8uM8kKiTugmxiy16dh18pRZ" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000001051551adf3ecba1cc7abbe16ae6c534664620dea0a15c92", + "blockHeight": 378093, + "confirmations": 70982, + "blockTime": 1568020338, + "value": "997460", + "valueIn": "1000000", + "fees": "2540", + "hex": "0100000001a565c1086fe62e6a7200ff2fd34aef0846829e3afeee632d06583b24e82a141a00000000000000000002a08601000000000000001976a9147ccf34a1e67d66714f0c162d0e84b9edaad895c688acb4b10d000000000000001976a914e84cf5d4407038a0e0f360dce5799f9882303cef88ac00000000000000000140420f00000000006dc30500020000006a4730440220769fd7bcbdf23848258688e60e6be15c16eed200f8c3d92e1e1e0af35f76f5d202200a69bdeba50dfcafeacee8acba1b8ae6608b786861310af6e2faef946d1aa8a0012103308b19c0e8e51700acebce494cd22fe5b2a5723279ecb90cb4e0ecd7c95f4141" + }, + { + "txid": "1a142ae8243b58062d63eefe3a9e824608ef4ad32fff00726a2ee66f08c165a5", + "version": 1, + "vin": [ + { + "txid": "076325760e3bdc16323b5de8ef5563ef10809568e13d9fc76e2ee8d523bb200c", + "vout": 1, + "n": 0, + "addresses": [ + "DsXJ2WL3RJggGuzdb14ngsZBsovbjJU3vfZ" + ], + "isAddress": true, + "value": "19692760", + "hex": "47304402200363d79ad40b72722a469469ec7af1c8d1d52c48b9acdbc47c542547db091d2f0220312dca3dfd741b461a3dee74e64b6d1d851a8c234253c4226240108eeeb60654012103b8f0e579be248f58d56310e839d0cd0433517a83dc20916ee18e7e3ec2120c84" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "hex": "76a9142215900ba09320357c5c01b3397cfcbbbc88de6388ac", + "addresses": [ + "DsU58J9shjqUh8QsEYn9N9xdq19SQRnw1WP" + ], + "isAddress": true + }, + { + "value": "18690220", + "n": 1, + "spent": true, + "hex": "76a9142c1a0b285426b6c050a32cc3ef7dc6c6c418aa1288ac", + "addresses": [ + "DsUz6RQnnhzhXphPe7wCRe1JE6Znn912VqC" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000002d73723a283859923c3147c38e0084e6fd5f713234549d1", + "blockHeight": 377709, + "confirmations": 71366, + "blockTime": 1567896183, + "value": "19690220", + "valueIn": "19692760", + "fees": "2540", + "hex": "01000000010c20bb23d5e82e6ec79f3de168958010ef6355efe85d3b3216dc3b0e762563070100000000000000000240420f000000000000001976a9142215900ba09320357c5c01b3397cfcbbbc88de6388acac301d010000000000001976a9142c1a0b285426b6c050a32cc3ef7dc6c6c418aa1288ac000000000000000001d87c2c010000000026c30500060000006a47304402200363d79ad40b72722a469469ec7af1c8d1d52c48b9acdbc47c542547db091d2f0220312dca3dfd741b461a3dee74e64b6d1d851a8c234253c4226240108eeeb60654012103b8f0e579be248f58d56310e839d0cd0433517a83dc20916ee18e7e3ec2120c84" + }, + { + "txid": "076325760e3bdc16323b5de8ef5563ef10809568e13d9fc76e2ee8d523bb200c", + "version": 1, + "vin": [ + { + "txid": "29521bf9516d976364d5dbbda9dfa35229aa52fcc6a3ad3c7d4b11ebe4008620", + "n": 0, + "addresses": [ + "DsesW1sQL9wkP9E3xnxRggR8uWbcyHv9mU2" + ], + "isAddress": true, + "value": "19795300", + "hex": "47304402207c29e0ee6f364841150fffe229ef48f77a8c8fee2e3a11b31aaa69ed1433e6c502204f9b426569ee04ef5319b53f6cd66f7999ba7bd92a8e41c7e95cd7b29ce3090d0121035bb46ab10dde3874cdb079be42261f31144a8ac568307b26e18d9db51aa8ac90" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a91437eb38b48e9113dc0d9a4f020aef3c708823cb2d88ac", + "addresses": [ + "DsW4aSTWVaW1V6jPLu1K9PzSFWBCLJuexkm" + ], + "isAddress": true + }, + { + "value": "19692760", + "n": 1, + "spent": true, + "hex": "76a914456e83a3a589cf1c3547a41f8246a8a5a60624c188ac", + "addresses": [ + "DsXJ2WL3RJggGuzdb14ngsZBsovbjJU3vfZ" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000019d72034c4f14e35f90640c34e4c1ba8c05283ef47f83c99", + "blockHeight": 377637, + "confirmations": 71438, + "blockTime": 1567871358, + "value": "19792760", + "valueIn": "19795300", + "fees": "2540", + "hex": "0100000001208600e4eb114b7d3cada3c6fc52aa2952a3dfa9bddbd56463976d51f91b522900000000000000000002a08601000000000000001976a91437eb38b48e9113dc0d9a4f020aef3c708823cb2d88acd87c2c010000000000001976a914456e83a3a589cf1c3547a41f8246a8a5a60624c188ac000000000000000001640d2e0100000000d4bc0500070000006a47304402207c29e0ee6f364841150fffe229ef48f77a8c8fee2e3a11b31aaa69ed1433e6c502204f9b426569ee04ef5319b53f6cd66f7999ba7bd92a8e41c7e95cd7b29ce3090d0121035bb46ab10dde3874cdb079be42261f31144a8ac568307b26e18d9db51aa8ac90" + }, + { + "txid": "29521bf9516d976364d5dbbda9dfa35229aa52fcc6a3ad3c7d4b11ebe4008620", + "version": 1, + "vin": [ + { + "txid": "4103946f2742b5f9bb5fd348c4722d0479861c4c0a9191d1e7578a7032f01f63", + "n": 0, + "addresses": [ + "DsSpq2ZoacCfmPqz1jtiQ881UsyxYFg3noz" + ], + "isAddress": true, + "value": "28561300", + "hex": "47304402206bc169542469496bcb667b14bbb36b5c14a86b33f3bd23ec2eaa2eb58feb5f3d02206517cc07ee54d148d7932d3c55ac60a28fe4d0dcad50118e8f63cbe764f33ddd01210264de4a69d3486f3fbe51fc422da7d482262e31c140fe2a3122d68ecb6d62a1a2" + } + ], + "vout": [ + { + "value": "19795300", + "n": 0, + "spent": true, + "hex": "76a914988c15c6f686270745e2fa320b5bf522ec0c0d5988ac", + "addresses": [ + "DsesW1sQL9wkP9E3xnxRggR8uWbcyHv9mU2" + ], + "isAddress": true + }, + { + "value": "8763460", + "n": 1, + "spent": true, + "hex": "76a91405392c56a7f131fc28a76f8b20b75ba3f52b767b88ac", + "addresses": [ + "DsRSXMrRri1Pt8qxP7YpR8qcMUxQiSgWkno" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000e7e8796398f4b9f59b1aa86987d002ce882ec231aa000ee", + "blockHeight": 376019, + "confirmations": 73056, + "blockTime": 1567390537, + "value": "28558760", + "valueIn": "28561300", + "fees": "2540", + "hex": "0100000001631ff032708a57e7d191910a4c1c8679042d72c448d35fbbf9b542276f94034100000000000000000002640d2e010000000000001976a914988c15c6f686270745e2fa320b5bf522ec0c0d5988ac44b885000000000000001976a91405392c56a7f131fc28a76f8b20b75ba3f52b767b88ac00000000000000000194cfb30100000000d2bc0500190000006a47304402206bc169542469496bcb667b14bbb36b5c14a86b33f3bd23ec2eaa2eb58feb5f3d02206517cc07ee54d148d7932d3c55ac60a28fe4d0dcad50118e8f63cbe764f33ddd01210264de4a69d3486f3fbe51fc422da7d482262e31c140fe2a3122d68ecb6d62a1a2" + }, + { + "txid": "4103946f2742b5f9bb5fd348c4722d0479861c4c0a9191d1e7578a7032f01f63", + "version": 1, + "vin": [ + { + "txid": "810cfe2b27d14f6ab7111afa53044c4e7d673f1626004c539e89cc118f9625be", + "vout": 1, + "n": 0, + "addresses": [ + "DsVoRmLjjFPVNTYjkwAM81KCNfhoPFJnFTR" + ], + "isAddress": true, + "value": "28563460", + "hex": "483045022100ec9f9ccfa8cd46c88abac0f9a7322c2ae6818a0bac87926f6acf39aaaf7d214d022005f2389507722c2b984d6a110a89b46141aed3e90fec5f829d7254a3e2e0dcf601210382f288c0618670d925727de89445e38fcef4f5b076b68c73affa9c812e092cdc" + } + ], + "vout": [ + { + "value": "28561300", + "n": 0, + "spent": true, + "hex": "76a914146932bd6eaa9b9c8e249334bc0aaf74147b31c588ac", + "addresses": [ + "DsSpq2ZoacCfmPqz1jtiQ881UsyxYFg3noz" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000001aa65c110419f3d53c56c511b327dc5600063b15f35df5f", + "blockHeight": 376017, + "confirmations": 73058, + "blockTime": 1567389612, + "value": "28561300", + "valueIn": "28563460", + "fees": "2160", + "hex": "0100000001be25968f11cc899e534c0026163f677d4e4c0453fa1a11b76a4fd1272bfe0c810100000000000000000194cfb3010000000000001976a914146932bd6eaa9b9c8e249334bc0aaf74147b31c588ac00000000000000000104d8b30100000000d1bc0500080000006b483045022100ec9f9ccfa8cd46c88abac0f9a7322c2ae6818a0bac87926f6acf39aaaf7d214d022005f2389507722c2b984d6a110a89b46141aed3e90fec5f829d7254a3e2e0dcf601210382f288c0618670d925727de89445e38fcef4f5b076b68c73affa9c812e092cdc" + }, + { + "txid": "810cfe2b27d14f6ab7111afa53044c4e7d673f1626004c539e89cc118f9625be", + "version": 1, + "vin": [ + { + "txid": "bcc5228e9d956918984d1853c31d7edcd862f8a7fca20ded114d93f8a74ad32a", + "vout": 1, + "n": 0, + "addresses": [ + "DsUoWCAxprdGNtKQqambFbTcSBgH1SHn9Gp" + ], + "isAddress": true, + "value": "29800000", + "hex": "483045022100daeed849e3a7d53ac2469cda56487598b4af6f32502b6ec17d2bf046671b8f6d022011f16ade4b20c11ce48bb910cebc19656e668e119071ac3fbeeb3fe411d1b6070121020dcb5dc1d90cb05e23350f2ede85746ec934a3b31a8a520907d47ebc8abeb1e1" + } + ], + "vout": [ + { + "value": "1234000", + "n": 0, + "spent": true, + "hex": "76a914146932bd6eaa9b9c8e249334bc0aaf74147b31c588ac", + "addresses": [ + "DsSpq2ZoacCfmPqz1jtiQ881UsyxYFg3noz" + ], + "isAddress": true + }, + { + "value": "28563460", + "n": 1, + "spent": true, + "hex": "76a914350dbdb43bc1e78bdad96522156fda5378a6c9be88ac", + "addresses": [ + "DsVoRmLjjFPVNTYjkwAM81KCNfhoPFJnFTR" + ], + "isAddress": true + } + ], + "blockHash": "00000000000000000af6dcbafdc58a4aa17a62d99e037a859c86791629f74c90", + "blockHeight": 376016, + "confirmations": 73059, + "blockTime": 1567387305, + "value": "29797460", + "valueIn": "29800000", + "fees": "2540", + "hex": "01000000012ad34aa7f8934d11ed0da2fca7f862d8dc7e1dc353184d981869959d8e22c5bc0100000000000000000250d412000000000000001976a914146932bd6eaa9b9c8e249334bc0aaf74147b31c588ac04d8b3010000000000001976a914350dbdb43bc1e78bdad96522156fda5378a6c9be88ac00000000000000000140b6c60100000000fbb90500030000006b483045022100daeed849e3a7d53ac2469cda56487598b4af6f32502b6ec17d2bf046671b8f6d022011f16ade4b20c11ce48bb910cebc19656e668e119071ac3fbeeb3fe411d1b6070121020dcb5dc1d90cb05e23350f2ede85746ec934a3b31a8a520907d47ebc8abeb1e1" + }, + { + "txid": "bcc5228e9d956918984d1853c31d7edcd862f8a7fca20ded114d93f8a74ad32a", + "version": 1, + "vin": [ + { + "txid": "5015d14dcfd78998cfa13e0325798a74d95bbe75f167a49467303f70dde9bffd", + "n": 0, + "addresses": [ + "DsbaL8f4Uu4bQ6wPpbjcLWxRDZQZo3Ncrrq" + ], + "isAddress": true, + "value": "39900000", + "hex": "47304402206e87253e8eb7629f3529934b831ed251d27bb429dec52cc96eedf2f7b1fa080002203682e702ab885ef2ecf0ec4a524288a1560b3e055550a767d10fb79483a18ba4012102b811228759df7b31eb5a219c4be0841c0341cd1e05a723d0dcba462d2aae0bfd" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "76a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac", + "addresses": [ + "Dsesp1V6DZDEtcq2behmBVKdYqKMdkh96hL" + ], + "isAddress": true + }, + { + "value": "29800000", + "n": 1, + "spent": true, + "hex": "76a9142a194fc92e27fef9cc2b057bc9060c580cbb484888ac", + "addresses": [ + "DsUoWCAxprdGNtKQqambFbTcSBgH1SHn9Gp" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000012f24e779cca63028a7dfae179182feabb065ae40e449199", + "blockHeight": 375290, + "confirmations": 73785, + "blockTime": 1567173553, + "value": "39800000", + "valueIn": "39900000", + "fees": "100000", + "hex": "0100000001fdbfe9dd703f306794a467f175be5bd9748a7925033ea1cf9889d7cf4dd1155000000000000000000002809698000000000000001976a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac40b6c6010000000000001976a9142a194fc92e27fef9cc2b057bc9060c580cbb484888ac00000000000000000160d3600200000000790b0500030000006a47304402206e87253e8eb7629f3529934b831ed251d27bb429dec52cc96eedf2f7b1fa080002203682e702ab885ef2ecf0ec4a524288a1560b3e055550a767d10fb79483a18ba4012102b811228759df7b31eb5a219c4be0841c0341cd1e05a723d0dcba462d2aae0bfd" + }, + { + "txid": "5015d14dcfd78998cfa13e0325798a74d95bbe75f167a49467303f70dde9bffd", + "version": 1, + "vin": [ + { + "txid": "ac4b4b9af3e0b8cdb7918bb6bfdf9878ace398b92e6e5ef7844936c676041a26", + "vout": 1, + "sequence": 4294967295, + "n": 0, + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true, + "value": "50000000", + "hex": "483045022100923900d86dfbfefa31c5789c0d142fd75d18dd91ea13930515c46e280b6f33fc022079fddaf46e6da7978b9226cc09c6d978bca89b37ec99becb65625ddb6d00f9180121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + } + ], + "vout": [ + { + "value": "39900000", + "n": 0, + "spent": true, + "hex": "76a914746462efaf7a648ccd1a46de4e2842f2b25f498588ac", + "addresses": [ + "DsbaL8f4Uu4bQ6wPpbjcLWxRDZQZo3Ncrrq" + ], + "isAddress": true + }, + { + "value": "10000000", + "n": 1, + "hex": "76a9145f6ef673184369f86779658d13f436a7d303276888ac", + "addresses": [ + "DsZfWcUeaTLtXz3roBmNCNP96srYmDFVZ1W" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000008e0427a4b4e95d540d03fcc28a059861204a8674bdf7a64", + "blockHeight": 330617, + "confirmations": 118458, + "blockTime": 1553754509, + "value": "49900000", + "valueIn": "50000000", + "fees": "100000", + "hex": "0100000001261a0476c6364984f75e6e2eb998e3ac7898dfbfb68b91b7cdb8e0f39a4b4bac0100000000ffffffff0260d360020000000000001976a914746462efaf7a648ccd1a46de4e2842f2b25f498588ac809698000000000000001976a9145f6ef673184369f86779658d13f436a7d303276888ac00000000000000000180f0fa020000000035ef0400150000006b483045022100923900d86dfbfefa31c5789c0d142fd75d18dd91ea13930515c46e280b6f33fc022079fddaf46e6da7978b9226cc09c6d978bca89b37ec99becb65625ddb6d00f9180121039b24b2073eef4835f226bb98ec9cb28b1cd0550c76077d3865a77870f119c344" + }, + { + "txid": "ac4b4b9af3e0b8cdb7918bb6bfdf9878ace398b92e6e5ef7844936c676041a26", + "version": 1, + "vin": [ + { + "txid": "9ecec2fc079ebc6646de451b73231cf422f7ad761472b6482c7453a82c87a321", + "vout": 5, + "sequence": 4294967295, + "n": 0, + "addresses": [ + "DsfMzjYfieAwq2zpeCRyDMiSVDxfEFfRNui" + ], + "isAddress": true, + "value": "7078093729", + "hex": "483045022100fef9f8fd733a94ee691d1845442335a3693882e441078c5dc1220ce21ce93d0f0220308aed0bd8cb2e5a040f46426be0b25fdb3605bb6ae3ec8252055bc2cbd13738012102167188e52e860521bd21cc3548f4250c75309a70ec182f081b4d04f788a48914" + } + ], + "vout": [ + { + "value": "7028091199", + "n": 0, + "spent": true, + "hex": "76a914d3b1286986e589b0e819f98e2a2462e5a17f1ef288ac", + "addresses": [ + "DskGEJ3taowt2PxqopPLSUoVh9eq4nWqDXT" + ], + "isAddress": true + }, + { + "value": "50000000", + "n": 1, + "spent": true, + "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", + "addresses": [ + "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000016d937210760bb0fbde311d3bfb0719abeb6a2230c537817", + "blockHeight": 323381, + "confirmations": 125694, + "blockTime": 1551595302, + "value": "7078091199", + "valueIn": "7078093729", + "fees": "2530", + "hex": "010000000121a3872ca853742c48b6721476adf722f41c23731b45de4666bc9e07fcc2ce9e0500000001ffffffff023f29e8a20100000000001976a914d3b1286986e589b0e819f98e2a2462e5a17f1ef288ac80f0fa020000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac000000000000000001a123e3a501000000a6ea0400030000006b483045022100fef9f8fd733a94ee691d1845442335a3693882e441078c5dc1220ce21ce93d0f0220308aed0bd8cb2e5a040f46426be0b25fdb3605bb6ae3ec8252055bc2cbd13738012102167188e52e860521bd21cc3548f4250c75309a70ec182f081b4d04f788a48914" + } + ], + "usedTokens": 27, + "tokens": [ + { + "type": "XPUBAddress", + "name": "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", + "path": "m/44'/42'/0'/0/0", + "transfers": 11, + "decimals": 8, + "balance": "19370607", + "totalReceived": "75347145", + "totalSent": "55976538" + }, + { + "type": "XPUBAddress", + "name": "Dsfe2vHn1TVqHJWeD37BXL1y31nWeBQqB7c", + "path": "m/44'/42'/0'/0/8", + "transfers": 1, + "decimals": 8, + "balance": "19457", + "totalReceived": "19457", + "totalSent": "0" + }, + { + "type": "XPUBAddress", + "name": "DsdwT3GGppDmuPSEetywszY7Y95jGpLopSU", + "path": "m/44'/42'/0'/0/9", + "transfers": 1, + "decimals": 8, + "balance": "19452", + "totalReceived": "19452", + "totalSent": "0" + }, + { + "type": "XPUBAddress", + "name": "Dsc4yhfEdqj31WCbtRgv2cXNCtdJNHFCg4o", + "path": "m/44'/42'/0'/0/10", + "transfers": 1, + "decimals": 8, + "balance": "85300", + "totalReceived": "85300", + "totalSent": "0" + }, + { + "type": "XPUBAddress", + "name": "DsoLtxGAPidBykdxWkzRAmhgBwBeqLdJEXR", + "path": "m/44'/42'/0'/0/23", + "transfers": 1, + "decimals": 8, + "balance": "19686", + "totalReceived": "19686", + "totalSent": "0" + } + ] +} diff --git a/mock/ext-api-data/digibyte-api_v2_address_DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi__details_txs.json b/mock/ext-api-data/digibyte-api_v2_address_DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi__details_txs.json new file mode 100644 index 000000000..cdc77c86e --- /dev/null +++ b/mock/ext-api-data/digibyte-api_v2_address_DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":384,"itemsOnPage":10,"address":"DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi","balance":"0","totalReceived":"244615238234","totalSent":"244615238234","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":3840,"transactions":[{"txid":"52618b3146251b767d6e9d0f4076da68d2af5b780be52eb34cf1c45188954acb","version":1,"vin":[{"txid":"9843f6b1c966663f6942061207b4fd549a23bcd0844827eea397dc2fc299e74f","sequence":4294967295,"n":0,"addresses":["DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi"],"isAddress":true,"value":"62143000","hex":"47304402207bd05f2a4487ebca7d722427497370a5cdcae44fb2e9a314d24a548c03261f2e02205883efc76c704dd67492adbb27a9d049d254f367e6b34c06de4b742dc59bdc5f0141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48"}],"vout":[{"value":"62142000","n":0,"spent":true,"hex":"76a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac","addresses":["DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW"],"isAddress":true},{"value":"0","n":1,"hex":"6a45524d555453422e41432e544800000000000029bfa398bee3241347368c2d4d758575c7fe00d60c05f90d1e6ddc36f99ef2f27683c59e41bb4c803c710e33ed63faefb68089","addresses":["OP_RETURN 524d555453422e41432e544800000000000029bfa398bee3241347368c2d4d758575c7fe00d60c05f90d1e6ddc36f99ef2f27683c59e41bb4c803c710e33ed63faefb68089"],"isAddress":false}],"blockHash":"9c082ff8666f530e114f9c07f564211a43d2809c6248e0b896c3787e69e1d963","blockHeight":10869003,"confirmations":3488,"blockTime":1590017999,"value":"62142000","valueIn":"62143000","fees":"1000","hex":"01000000014fe799c22fdc97a3ee274884d0bc239a54fdb407120642693f6666c9b1f64398000000008a47304402207bd05f2a4487ebca7d722427497370a5cdcae44fb2e9a314d24a548c03261f2e02205883efc76c704dd67492adbb27a9d049d254f367e6b34c06de4b742dc59bdc5f0141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48ffffffff023036b403000000001976a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac0000000000000000476a45524d555453422e41432e544800000000000029bfa398bee3241347368c2d4d758575c7fe00d60c05f90d1e6ddc36f99ef2f27683c59e41bb4c803c710e33ed63faefb6808900000000"},{"txid":"9843f6b1c966663f6942061207b4fd549a23bcd0844827eea397dc2fc299e74f","version":1,"vin":[{"txid":"b178d6584fe3b37d978f29f0fff899e6d36be05486e8a75b9d5b41bb3edaafcb","sequence":4294967295,"n":0,"addresses":["DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW"],"isAddress":true,"value":"62144000","hex":"473044022030312758b634855268aecd2b006c5ae8951723dbb76bac4af98b128f61b83aff022016069738e950590202c6d705d67da443848c05d4bf8ae0071856a8dff548b9ab012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057"}],"vout":[{"value":"62143000","n":0,"spent":true,"hex":"76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac","addresses":["DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi"],"isAddress":true},{"value":"0","n":1,"hex":"6a45524d555453422e41432e544800000000000029bfa398bee3241347368c2d4d758575c7fe00d60c05f90d1e6ddc36f99ef2f27683c59e41bb4c803c710e33ed63faefb68089","addresses":["OP_RETURN 524d555453422e41432e544800000000000029bfa398bee3241347368c2d4d758575c7fe00d60c05f90d1e6ddc36f99ef2f27683c59e41bb4c803c710e33ed63faefb68089"],"isAddress":false}],"blockHash":"e3e584e9072be121b3b1e94d2495a3c3974e0df1cfedc136936b70a5a5cac801","blockHeight":10869002,"confirmations":3489,"blockTime":1590017991,"value":"62143000","valueIn":"62144000","fees":"1000","hex":"0100000001cbafda3ebb415b9d5ba7e88654e06bd3e699f8fff0298f977db3e34f58d678b1000000006a473044022030312758b634855268aecd2b006c5ae8951723dbb76bac4af98b128f61b83aff022016069738e950590202c6d705d67da443848c05d4bf8ae0071856a8dff548b9ab012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff02183ab403000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e544800000000000029bfa398bee3241347368c2d4d758575c7fe00d60c05f90d1e6ddc36f99ef2f27683c59e41bb4c803c710e33ed63faefb6808900000000"},{"txid":"9d880c73ad1682b03339e884b97b022f408d90597d4c00a716b954724fed8e5e","version":1,"vin":[{"txid":"9e0487ae145d698e1eae57bf5a5c9bfbd2a8cb2a41dabefef822c9da976c5ecc","sequence":4294967295,"n":0,"addresses":["DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi"],"isAddress":true,"value":"61627000","hex":"47304402207eb214458be2185d7aa3d329995a9041ec29deef17ea9c2d1b34951c3582e3f302207415b095de42a5ad7b0e1cfa6006ec67ebe7c075e124d47c08f99daad60bb7010141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48"}],"vout":[{"value":"61626000","n":0,"spent":true,"hex":"76a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac","addresses":["DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW"],"isAddress":true},{"value":"0","n":1,"hex":"6a45524d555453422e41432e54480000000000002998a398bee3241347368c2d4d758575c7fe00ba8e9832f5eadcfc68d11b1417f1787de6ae95a47b0830c527be09ff693a17eb","addresses":["OP_RETURN 524d555453422e41432e54480000000000002998a398bee3241347368c2d4d758575c7fe00ba8e9832f5eadcfc68d11b1417f1787de6ae95a47b0830c527be09ff693a17eb"],"isAddress":false}],"blockHash":"847a223814159f3b0670c15742b778688aa381883cedc59456ab66ef4ab78811","blockHeight":10863931,"confirmations":8560,"blockTime":1589942553,"value":"61626000","valueIn":"61627000","fees":"1000","hex":"0100000001cc5e6c97dac922f8febeda412acba8d2fb9b5c5abf57ae1e8e695d14ae87049e000000008a47304402207eb214458be2185d7aa3d329995a9041ec29deef17ea9c2d1b34951c3582e3f302207415b095de42a5ad7b0e1cfa6006ec67ebe7c075e124d47c08f99daad60bb7010141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48ffffffff029056ac03000000001976a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac0000000000000000476a45524d555453422e41432e54480000000000002998a398bee3241347368c2d4d758575c7fe00ba8e9832f5eadcfc68d11b1417f1787de6ae95a47b0830c527be09ff693a17eb00000000"},{"txid":"9e0487ae145d698e1eae57bf5a5c9bfbd2a8cb2a41dabefef822c9da976c5ecc","version":1,"vin":[{"txid":"b215c706e32c44a1a30e110a1b60221c30c578d11d42142734803c90ced368df","sequence":4294967295,"n":0,"addresses":["DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW"],"isAddress":true,"value":"61628000","hex":"473044022059d09606a6e4ad6c854cba45e9b13d7be52641c705fee95637c90c7f6001ecd802204fb5b67f02fe9df02e89011ff808e17fbb9f406e1290739820ae438ead9e7069012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057"}],"vout":[{"value":"61627000","n":0,"spent":true,"hex":"76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac","addresses":["DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi"],"isAddress":true},{"value":"0","n":1,"hex":"6a45524d555453422e41432e54480000000000002998a398bee3241347368c2d4d758575c7fe00ba8e9832f5eadcfc68d11b1417f1787de6ae95a47b0830c527be09ff693a17eb","addresses":["OP_RETURN 524d555453422e41432e54480000000000002998a398bee3241347368c2d4d758575c7fe00ba8e9832f5eadcfc68d11b1417f1787de6ae95a47b0830c527be09ff693a17eb"],"isAddress":false}],"blockHash":"847a223814159f3b0670c15742b778688aa381883cedc59456ab66ef4ab78811","blockHeight":10863931,"confirmations":8560,"blockTime":1589942553,"value":"61627000","valueIn":"61628000","fees":"1000","hex":"0100000001df68d3ce903c80342714421dd178c5301c22601b0a110ea3a1442ce306c715b2000000006a473044022059d09606a6e4ad6c854cba45e9b13d7be52641c705fee95637c90c7f6001ecd802204fb5b67f02fe9df02e89011ff808e17fbb9f406e1290739820ae438ead9e7069012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff02785aac03000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e54480000000000002998a398bee3241347368c2d4d758575c7fe00ba8e9832f5eadcfc68d11b1417f1787de6ae95a47b0830c527be09ff693a17eb00000000"},{"txid":"565a6acc5b6e0832844a6cf1fb3a84330a57021256aebd667a99fddecde76ea7","version":1,"vin":[{"txid":"d32d7c65d4fdd8b7f77379e3c2f13dafc38ac4ba5bad391a8271305674be5deb","sequence":4294967295,"n":0,"addresses":["DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi"],"isAddress":true,"value":"61733000","hex":"473044022046232395d40a79d525972cf35962c6b082bf7e562315ffe20092371ce167010f022001d24738b76ae32b422465f2f8d2e7609c8243ac2d9f5698d4e795d973383f040141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48"}],"vout":[{"value":"61732000","n":0,"spent":true,"hex":"76a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac","addresses":["DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW"],"isAddress":true},{"value":"0","n":1,"hex":"6a45524d555453422e41432e5448000000000000297fa398bee3241347368c2d4d758575c7fe00b2bcd12aa47cd973e773af9d10317ca9d8d0210a141ffe684c7fef9a2477b7e8","addresses":["OP_RETURN 524d555453422e41432e5448000000000000297fa398bee3241347368c2d4d758575c7fe00b2bcd12aa47cd973e773af9d10317ca9d8d0210a141ffe684c7fef9a2477b7e8"],"isAddress":false}],"blockHash":"0000000000000000824fa33e16a642fb8a79e5507b64e4aa0534f766bf974978","blockHeight":10863924,"confirmations":8567,"blockTime":1589942406,"value":"61732000","valueIn":"61733000","fees":"1000","hex":"0100000001eb5dbe74563071821a39ad5bbac48ac3af3df1c2e37973f7b7d8fdd4657c2dd3000000008a473044022046232395d40a79d525972cf35962c6b082bf7e562315ffe20092371ce167010f022001d24738b76ae32b422465f2f8d2e7609c8243ac2d9f5698d4e795d973383f040141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48ffffffff02a0f4ad03000000001976a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac0000000000000000476a45524d555453422e41432e5448000000000000297fa398bee3241347368c2d4d758575c7fe00b2bcd12aa47cd973e773af9d10317ca9d8d0210a141ffe684c7fef9a2477b7e800000000"},{"txid":"d32d7c65d4fdd8b7f77379e3c2f13dafc38ac4ba5bad391a8271305674be5deb","version":1,"vin":[{"txid":"aca9b244d37d027233d37c9d8e83dcb0ced0bd5adda0d1eb2b10ade2e830117e","sequence":4294967295,"n":0,"addresses":["DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW"],"isAddress":true,"value":"61734000","hex":"47304402204a563a55460ce140c98a02c78cc926ea4fa0980963a5e1ad3806b066fcf3c79f02207a31e1604fd04996fd36344dcc70f2fd76412118dde4353e599711de5c5850ef012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057"}],"vout":[{"value":"61733000","n":0,"spent":true,"hex":"76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac","addresses":["DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi"],"isAddress":true},{"value":"0","n":1,"hex":"6a45524d555453422e41432e5448000000000000297fa398bee3241347368c2d4d758575c7fe00b2bcd12aa47cd973e773af9d10317ca9d8d0210a141ffe684c7fef9a2477b7e8","addresses":["OP_RETURN 524d555453422e41432e5448000000000000297fa398bee3241347368c2d4d758575c7fe00b2bcd12aa47cd973e773af9d10317ca9d8d0210a141ffe684c7fef9a2477b7e8"],"isAddress":false}],"blockHash":"0000000000000000824fa33e16a642fb8a79e5507b64e4aa0534f766bf974978","blockHeight":10863924,"confirmations":8567,"blockTime":1589942406,"value":"61733000","valueIn":"61734000","fees":"1000","hex":"01000000017e1130e8e2ad102bebd1a0dd5abdd0ceb0dc838e9d7cd33372027dd344b2a9ac000000006a47304402204a563a55460ce140c98a02c78cc926ea4fa0980963a5e1ad3806b066fcf3c79f02207a31e1604fd04996fd36344dcc70f2fd76412118dde4353e599711de5c5850ef012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff0288f8ad03000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e5448000000000000297fa398bee3241347368c2d4d758575c7fe00b2bcd12aa47cd973e773af9d10317ca9d8d0210a141ffe684c7fef9a2477b7e800000000"},{"txid":"aa8f2b0289f48a46521273f5b0664f5c8b4d62516be5a3ae9d09c2a8d0082a72","version":1,"vin":[{"txid":"083c2562fdc327c0f4d2a595b4858cd8b2abc07204dc118c8cf1d123ea2c8708","sequence":4294967295,"n":0,"addresses":["DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi"],"isAddress":true,"value":"61739000","hex":"473044022043b9d64b14a9132004d46871e3e9ecadb189a05f3b60cc92d75c59fb3668fa980220186a7e0af36bda79438502af16ad2980c86a2e923ba549ac5fa0dbbac77a5d6a0141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48"}],"vout":[{"value":"61738000","n":0,"spent":true,"hex":"76a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac","addresses":["DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW"],"isAddress":true},{"value":"0","n":1,"hex":"6a45524d555453422e41432e5448000000000000297ea398bee3241347368c2d4d758575c7fe002b23ecc5a066a8f952dbc9079ff75b3b2ae6650325c287a0ffb8677a1137ce36","addresses":["OP_RETURN 524d555453422e41432e5448000000000000297ea398bee3241347368c2d4d758575c7fe002b23ecc5a066a8f952dbc9079ff75b3b2ae6650325c287a0ffb8677a1137ce36"],"isAddress":false}],"blockHash":"0000000000000000437bee40996add8cf12f928f8d610dce4a3836cb499fdc27","blockHeight":10863919,"confirmations":8572,"blockTime":1589942373,"value":"61738000","valueIn":"61739000","fees":"1000","hex":"010000000108872cea23d1f18c8c11dc0472c0abb2d88c85b495a5d2f4c027c3fd62253c08000000008a473044022043b9d64b14a9132004d46871e3e9ecadb189a05f3b60cc92d75c59fb3668fa980220186a7e0af36bda79438502af16ad2980c86a2e923ba549ac5fa0dbbac77a5d6a0141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48ffffffff02100cae03000000001976a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac0000000000000000476a45524d555453422e41432e5448000000000000297ea398bee3241347368c2d4d758575c7fe002b23ecc5a066a8f952dbc9079ff75b3b2ae6650325c287a0ffb8677a1137ce3600000000"},{"txid":"083c2562fdc327c0f4d2a595b4858cd8b2abc07204dc118c8cf1d123ea2c8708","version":1,"vin":[{"txid":"b48316c1c90f0f107c884391a458e32d4353a6efa2d86f365ea2ae6325225c48","sequence":4294967295,"n":0,"addresses":["DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW"],"isAddress":true,"value":"61740000","hex":"47304402205110c23ef48578efeb572e5222e564261b699bfeb47d39644838dc22a7fbcab902206229983ac8734619759383e927f61139c2f4d36af4be9da385eb8787075673a9012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057"}],"vout":[{"value":"61739000","n":0,"spent":true,"hex":"76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac","addresses":["DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi"],"isAddress":true},{"value":"0","n":1,"hex":"6a45524d555453422e41432e5448000000000000297ea398bee3241347368c2d4d758575c7fe002b23ecc5a066a8f952dbc9079ff75b3b2ae6650325c287a0ffb8677a1137ce36","addresses":["OP_RETURN 524d555453422e41432e5448000000000000297ea398bee3241347368c2d4d758575c7fe002b23ecc5a066a8f952dbc9079ff75b3b2ae6650325c287a0ffb8677a1137ce36"],"isAddress":false}],"blockHash":"0000000000000000437bee40996add8cf12f928f8d610dce4a3836cb499fdc27","blockHeight":10863919,"confirmations":8572,"blockTime":1589942373,"value":"61739000","valueIn":"61740000","fees":"1000","hex":"0100000001485c222563aea25e366fd8a2efa653432de358a49143887c100f0fc9c11683b4000000006a47304402205110c23ef48578efeb572e5222e564261b699bfeb47d39644838dc22a7fbcab902206229983ac8734619759383e927f61139c2f4d36af4be9da385eb8787075673a9012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff02f80fae03000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e5448000000000000297ea398bee3241347368c2d4d758575c7fe002b23ecc5a066a8f952dbc9079ff75b3b2ae6650325c287a0ffb8677a1137ce3600000000"},{"txid":"aa6e59af4733d5de78a80f342de5c86cfd29ece94a240a34f9c03ee351907f40","version":1,"vin":[{"txid":"30508fb951fdd4feefab4e0ce0d169657a9922a5a87c8840e8a25222db2c9f16","sequence":4294967295,"n":0,"addresses":["DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi"],"isAddress":true,"value":"61775000","hex":"47304402205a24ed8a11b7d9a3b0125513cd96546a38260f04b844d974082798b17039628102203fb48a3c1c54a436218afe5ea022074c8a6e07f329c5fef7ccf1186feda96aee0141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48"}],"vout":[{"value":"61774000","n":0,"spent":true,"hex":"76a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac","addresses":["DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW"],"isAddress":true},{"value":"0","n":1,"hex":"6a45524d555453422e41432e544800000000000029aba398bee3241347368c2d4d758575c7fe0001299f8ab6e5ea61c29b366468451b067604214eb037811a7d67c4d785a9d956","addresses":["OP_RETURN 524d555453422e41432e544800000000000029aba398bee3241347368c2d4d758575c7fe0001299f8ab6e5ea61c29b366468451b067604214eb037811a7d67c4d785a9d956"],"isAddress":false}],"blockHash":"00000000000000005f8107124e967386137af8c6ae9cb7603711bccfbedd9fa9","blockHeight":10863261,"confirmations":9230,"blockTime":1589932487,"value":"61774000","valueIn":"61775000","fees":"1000","hex":"0100000001169f2cdb2252a2e840887ca8a522997a6569d1e00c4eabeffed4fd51b98f5030000000008a47304402205a24ed8a11b7d9a3b0125513cd96546a38260f04b844d974082798b17039628102203fb48a3c1c54a436218afe5ea022074c8a6e07f329c5fef7ccf1186feda96aee0141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48ffffffff02b098ae03000000001976a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac0000000000000000476a45524d555453422e41432e544800000000000029aba398bee3241347368c2d4d758575c7fe0001299f8ab6e5ea61c29b366468451b067604214eb037811a7d67c4d785a9d95600000000"},{"txid":"30508fb951fdd4feefab4e0ce0d169657a9922a5a87c8840e8a25222db2c9f16","version":1,"vin":[{"txid":"28cc8cf9a2d1012843cb11236b1ad118b3f8467ff76317242cab0c5c9f2821cb","sequence":4294967295,"n":0,"addresses":["DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW"],"isAddress":true,"value":"61776000","hex":"4730440220491a71aa59efd0a71754a52e0bbb5791581c30fa5c4f1760b1bc33da45d1358002207476d8ff39997599de89f28ae3188b7f26b19a15a6530079bfcf707eb91a04af012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057"}],"vout":[{"value":"61775000","n":0,"spent":true,"hex":"76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac","addresses":["DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi"],"isAddress":true},{"value":"0","n":1,"hex":"6a45524d555453422e41432e544800000000000029aba398bee3241347368c2d4d758575c7fe0001299f8ab6e5ea61c29b366468451b067604214eb037811a7d67c4d785a9d956","addresses":["OP_RETURN 524d555453422e41432e544800000000000029aba398bee3241347368c2d4d758575c7fe0001299f8ab6e5ea61c29b366468451b067604214eb037811a7d67c4d785a9d956"],"isAddress":false}],"blockHash":"00000000000000005f8107124e967386137af8c6ae9cb7603711bccfbedd9fa9","blockHeight":10863261,"confirmations":9230,"blockTime":1589932487,"value":"61775000","valueIn":"61776000","fees":"1000","hex":"0100000001cb21289f5c0cab2c241763f77f46f8b318d11a6b2311cb432801d1a2f98ccc28000000006a4730440220491a71aa59efd0a71754a52e0bbb5791581c30fa5c4f1760b1bc33da45d1358002207476d8ff39997599de89f28ae3188b7f26b19a15a6530079bfcf707eb91a04af012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff02989cae03000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e544800000000000029aba398bee3241347368c2d4d758575c7fe0001299f8ab6e5ea61c29b366468451b067604214eb037811a7d67c4d785a9d95600000000"}]} diff --git a/mock/ext-api-data/digibyte-api_v2_xpub_zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow__details_txs.json b/mock/ext-api-data/digibyte-api_v2_xpub_zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow__details_txs.json new file mode 100644 index 000000000..575335381 --- /dev/null +++ b/mock/ext-api-data/digibyte-api_v2_xpub_zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow__details_txs.json @@ -0,0 +1,389 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow", + "balance": "2599896040", + "totalReceived": "6895667780", + "totalSent": "4295771740", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 7, + "transactions": [ + { + "txid": "e13c81f4450e43ef8ef10dea8f4f9d53f357266563462df32a7fd61eb71bd190", + "version": 1, + "vin": [ + { + "txid": "34fac508c701939ac0fcb62bc436281cc28588d7986c5aa51de99e9835b9217b", + "vout": 1, + "n": 0, + "addresses": [ + "dgb1qxxdszsfkv4uvw8kzzl2wfatts5r9zex69x6076" + ], + "isAddress": true, + "value": "598908696" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "hex": "0014428a3010eb79c4d32478404200dbd41042e61fce", + "addresses": [ + "dgb1qg29rqy8t08zdxfrcgppqpk75zppwv87wknuder" + ], + "isAddress": true + }, + { + "value": "588896040", + "n": 1, + "hex": "00146542b8b7859994b18df4b71c72c4a72ed113662e", + "addresses": [ + "dgb1qv4pt3du9nx2trr05kuw893989mg3xe3w322vy7" + ], + "isAddress": true + } + ], + "blockHash": "000000000000000733a44ab2efd51c9485b05d905d2ba9092f716dcc0083116c", + "blockHeight": 9763292, + "confirmations": 1062143, + "blockTime": 1573501957, + "value": "598896040", + "valueIn": "598908696", + "fees": "12656", + "hex": "010000000001017b21b935989ee91da55a6c98d78885c21c2836c42bb6fcc09a9301c708c5fa34010000000000000000028096980000000000160014428a3010eb79c4d32478404200dbd41042e61fce28d71923000000001600146542b8b7859994b18df4b71c72c4a72ed113662e02473044022023b050ed97c4c7e334fec8efa3f27754e65c1e66a60ce142b2f8e2c16a1c847b02204a2e7d8a470a8978735a0b6d0f3649da6489612256f7cacd52e95034cc05365e012102cc9d7c2383e8f7c18e5af1852ddc35c5c4355a262a68b9d499ba173f6200ff9500000000" + }, + { + "txid": "303aa433530cb32762f8068ae14022e9a759b6c40bb69cee7e77abca333db317", + "version": 1, + "vin": [ + { + "txid": "d8d05cee8623257853b90cb1b0ff6c8e4bf5509818e812510f6715015fac1599", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "DTVYvQYvoXQjsiZQdvT9AaBjyQJr8TjAWu" + ], + "isAddress": true, + "value": "48587940518800", + "hex": "483045022100de758903643db73bc56bcd6b3e1e4bdafb3bd9b7a844286f66317de7c90b868702207eba0eeb32c817df9e79df2aad5f192808941ccb5d18430f9ee7ea18b8b1abad0121038f47ad4221aa24dbefe2b439f644b3af71428a7eb9e837517a162710fe631cf7" + } + ], + "vout": [ + { + "value": "48585940500900", + "n": 0, + "spent": true, + "hex": "76a914c30c2dd0e7b7f6506259f11e956d0f1085ca437588ac", + "addresses": [ + "DNvQtshdnrehs8MNRx6Mh9XDPz4UZucfEv" + ], + "isAddress": true + }, + { + "value": "2000000000", + "n": 1, + "hex": "00147ad8c91046724785f78b48d4ae606a3556ddf9b4", + "addresses": [ + "dgb1q0tvvjyzxwfrctautfr22ucr2x4tdm7d5va4lr6" + ], + "isAddress": true + } + ], + "blockHash": "311aa13d66a4cf6be602209601d7b54bc715320d9255d1abc822ad20a7e01a20", + "blockHeight": 9756845, + "confirmations": 1068590, + "blockTime": 1573405513, + "value": "48587940500900", + "valueIn": "48587940518800", + "fees": "17900", + "hex": "01000000019915ac5f0115670f5112e8189850f54b8e6cffb0b10cb95378252386ee5cd0d8000000006b483045022100de758903643db73bc56bcd6b3e1e4bdafb3bd9b7a844286f66317de7c90b868702207eba0eeb32c817df9e79df2aad5f192808941ccb5d18430f9ee7ea18b8b1abad0121038f47ad4221aa24dbefe2b439f644b3af71428a7eb9e837517a162710fe631cf7ffffffff02a481b94b302c00001976a914c30c2dd0e7b7f6506259f11e956d0f1085ca437588ac00943577000000001600147ad8c91046724785f78b48d4ae606a3556ddf9b400000000" + }, + { + "txid": "34fac508c701939ac0fcb62bc436281cc28588d7986c5aa51de99e9835b9217b", + "version": 1, + "vin": [ + { + "txid": "ac7b8ce8ceea74cfc5c9d6f64b9943a1f30747c8b5adad6e6a21bc715efb18e7", + "vout": 1, + "n": 0, + "addresses": [ + "dgb1qakdslehzre7rhfzwea93pkar95f3yxm73lyxp6" + ], + "isAddress": true, + "value": "798931522" + } + ], + "vout": [ + { + "value": "200000000", + "n": 0, + "spent": true, + "hex": "0014af765ac1eeb3b4ceb768994474288807d4624b24", + "addresses": [ + "dgb1q4am94s0wkw6vadmgn9z8g2ygql2xyjeyee6m6d" + ], + "isAddress": true + }, + { + "value": "598908696", + "n": 1, + "spent": true, + "hex": "0014319b0141366578c71ec217d4e4f56b85065164da", + "addresses": [ + "dgb1qxxdszsfkv4uvw8kzzl2wfatts5r9zex69x6076" + ], + "isAddress": true + } + ], + "blockHash": "9fef191db549b2ce895d1629b69be93d8fcd2eae74497ef43c4f1d13b807fb90", + "blockHeight": 9755214, + "confirmations": 1070221, + "blockTime": 1573381024, + "value": "798908696", + "valueIn": "798931522", + "fees": "22826", + "hex": "01000000000101e718fb5e71bc216a6eadadb5c84707f3a143994bf6d6c9c5cf74eacee88c7bac0100000000000000000200c2eb0b00000000160014af765ac1eeb3b4ceb768994474288807d4624b24189fb22300000000160014319b0141366578c71ec217d4e4f56b85065164da0247304402205602f6b4d6372eb954a89e9713789f6428ff4b3d023b8831f8e4d07ce51d725d02203c9608b45124b6233090250a59091f426c37d4df3c2563c758dbf95ae072c9ba012102d068173f4ca0b0c388fad24d262737615f0015498c2a09ff952249750d70f48300000000" + }, + { + "txid": "ac7b8ce8ceea74cfc5c9d6f64b9943a1f30747c8b5adad6e6a21bc715efb18e7", + "version": 1, + "vin": [ + { + "txid": "e1094c583bfbafe974ec819351a0491e44b6982ac4b37d859cec771df6c6dbe3", + "vout": 1, + "n": 0, + "addresses": [ + "dgb1qw97rz5cr7r3axm64pl9uefmvgw006gpjslsxzd" + ], + "isAddress": true, + "value": "898954348" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "001406f9f37f7ad63d990c4d3f2ec6276b78acef3805", + "addresses": [ + "dgb1qqmulxlm66c7ejrzd8uhvvfmt0zkw7wq9u2yd4y" + ], + "isAddress": true + }, + { + "value": "798931522", + "n": 1, + "spent": true, + "hex": "0014ed9b0fe6e21e7c3ba44ecf4b10dba32d13121b7e", + "addresses": [ + "dgb1qakdslehzre7rhfzwea93pkar95f3yxm73lyxp6" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000008a2e821f32358ac50b7f4856ba09ad0aaad54b8dc6ac21483", + "blockHeight": 9755127, + "confirmations": 1070308, + "blockTime": 1573379763, + "value": "898931522", + "valueIn": "898954348", + "fees": "22826", + "hex": "01000000000101e3dbc6f61d77ec9c857db3c42a98b6441e49a0519381ec74e9affb3b584c09e10100000000000000000200e1f5050000000016001406f9f37f7ad63d990c4d3f2ec6276b78acef380542ba9e2f00000000160014ed9b0fe6e21e7c3ba44ecf4b10dba32d13121b7e0247304402206f5b728f7489fa8571ee0deb80afd7eb3bb547cd1bd39849814c2d717c5593f302207f3aa1ddf3d49da1da354f6873cf0e2194b3eef685b0cce79be9c1cc4a9a7d2d012103978ec321da1421cf9e871732d06b4fbd15697fb3f0204348aa481b7899a584e600000000" + }, + { + "txid": "e1094c583bfbafe974ec819351a0491e44b6982ac4b37d859cec771df6c6dbe3", + "version": 1, + "vin": [ + { + "txid": "76256e4f59a2135e76ea87a513dcafc9803c64cb81848135bcef3fed60abb862", + "vout": 1, + "n": 0, + "addresses": [ + "dgb1qfnzgdpa76576kngxlh2zda0t2r5kh29mjd50l3" + ], + "isAddress": true, + "value": "998977174" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a91497421a26ae55a8c01ba339a0b65ab6a5f935a50488ac", + "addresses": [ + "DJvsm5mCp4a3YsJXxxiLk9MDWVwvrFDPm3" + ], + "isAddress": true + }, + { + "value": "898954348", + "n": 1, + "spent": true, + "hex": "0014717c315303f0e3d36f550fcbcca76c439efd2032", + "addresses": [ + "dgb1qw97rz5cr7r3axm64pl9uefmvgw006gpjslsxzd" + ], + "isAddress": true + } + ], + "blockHash": "5b6636f66d6ef37c4281bdf3088e48c9d22ca6c423cabaa18320fc303c861c71", + "blockHeight": 9755040, + "confirmations": 1070395, + "blockTime": 1573378521, + "value": "998954348", + "valueIn": "998977174", + "fees": "22826", + "hex": "0100000000010162b8ab60ed3fefbc35818481cb643c80c9afdc13a587ea765e13a2594f6e25760100000000000000000200e1f505000000001976a91497421a26ae55a8c01ba339a0b65ab6a5f935a50488ac6cf4943500000000160014717c315303f0e3d36f550fcbcca76c439efd20320248304502210084ebc948a2fa88ca2c893faa160a7f8340fcf057d764c898562206cb97eda44202201e7d790b34b9bdd946b1fbacbae02b5e9add3a2f11d2182cf76e83697c5e88e0012103cb1f31320481fea72f8f5a378578ca440ee2db3ebade1cea6e9ec15ee99c365600000000" + }, + { + "txid": "76256e4f59a2135e76ea87a513dcafc9803c64cb81848135bcef3fed60abb862", + "version": 1, + "vin": [ + { + "txid": "96c223272fce4e105cca3f2c9c966742c03f76b07aa5cfca514b890e90c46dc3", + "vout": 1, + "n": 0, + "addresses": [ + "dgb1q0tvvjyzxwfrctautfr22ucr2x4tdm7d5va4lr6" + ], + "isAddress": true, + "value": "1000000000" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "0014d1900052a23df4ba9e8c2adf0c7d815adb6de80e", + "addresses": [ + "dgb1q6xgqq54z8h6t485v9t0sclvpttdkm6qwp4292e" + ], + "isAddress": true + }, + { + "value": "998977174", + "n": 1, + "spent": true, + "hex": "00144cc48687bed53dab4d06fdd426f5eb50e96ba8bb", + "addresses": [ + "dgb1qfnzgdpa76576kngxlh2zda0t2r5kh29mjd50l3" + ], + "isAddress": true + } + ], + "blockHash": "d8122b3b73b70d8f78bded86562d9fd649b73209681ea5a7d3a0e14fb339e37d", + "blockHeight": 9755022, + "confirmations": 1070413, + "blockTime": 1573378224, + "value": "999977174", + "valueIn": "1000000000", + "fees": "22826", + "hex": "01000000000101c36dc4900e894b51cacfa57ab0763fc04267969c2c3fca5c104ece2f2723c2960100000000000000000240420f0000000000160014d1900052a23df4ba9e8c2adf0c7d815adb6de80e962e8b3b000000001600144cc48687bed53dab4d06fdd426f5eb50e96ba8bb02483045022100f09aeeb5dd360d691bf729f206fd24fb6aba185388ce387a7c7757bb88aa3cb80220203a4ca385ab6f21cc4606e83d492efb2b0a844294ab63773f5f4f8601cb54ef0121029df0ec50608f69a7e05097f33b731f2d4bf112001d25072f7a8ab065de5985ab00000000" + }, + { + "txid": "96c223272fce4e105cca3f2c9c966742c03f76b07aa5cfca514b890e90c46dc3", + "version": 1, + "vin": [ + { + "txid": "ce3d1d4de8c32659bd6329c516fbe348af53823236b4918f3f243d924a872354", + "vout": 50, + "sequence": 4294967295, + "n": 0, + "addresses": [ + "DJvsm5mCp4a3YsJXxxiLk9MDWVwvrFDPm3" + ], + "isAddress": true, + "value": "2936876555", + "hex": "473044022037c4cfbba57c9a9ac4b728e006e585d8b4422460ee714b21b9e0f9a4bd8dc04e02205ddfdc6dba325229406b57e6622d5f141e9c2dfb704db4e30be2e1e3dc0e16ee012103161f2325217e38461d71745e8652851a90285eb89e4344e48b804f3c943b5433" + }, + { + "txid": "ae2e1b22567da28d3a90f6920193cb4b5c3d32b921db80cd2859bc2eaccc0110", + "sequence": 4294967295, + "n": 1, + "addresses": [ + "DJvsm5mCp4a3YsJXxxiLk9MDWVwvrFDPm3" + ], + "isAddress": true, + "value": "1000000000", + "hex": "483045022100f43f677961c5cf4ad9df2351523e64e963f2e34082dde6ff2162e76f3ba2deed0220430bbfae4ee22884011c88db890848f0b880e6e6d3335fc1c93bd13f9a986b19012103161f2325217e38461d71745e8652851a90285eb89e4344e48b804f3c943b5433" + } + ], + "vout": [ + { + "value": "2936875555", + "n": 0, + "spent": true, + "hex": "0014f78aa1ee8590fad304450b732416ecbface4ea6b", + "addresses": [ + "dgb1q7792rm59jradxpz9pdejg9hvh7kwf6ntd8w0qq" + ], + "isAddress": true + }, + { + "value": "1000000000", + "n": 1, + "spent": true, + "hex": "00147ad8c91046724785f78b48d4ae606a3556ddf9b4", + "addresses": [ + "dgb1q0tvvjyzxwfrctautfr22ucr2x4tdm7d5va4lr6" + ], + "isAddress": true + } + ], + "blockHash": "102c0f5d2b8ad6db93419fb607127f482e0b2e2809970ee90479eb1158b15669", + "blockHeight": 9754963, + "confirmations": 1070472, + "blockTime": 1573377240, + "value": "3936875555", + "valueIn": "3936876555", + "fees": "1000", + "hex": "01000000025423874a923d243f8f91b436328253af48e3fb16c52963bd5926c3e84d1d3dce320000006a473044022037c4cfbba57c9a9ac4b728e006e585d8b4422460ee714b21b9e0f9a4bd8dc04e02205ddfdc6dba325229406b57e6622d5f141e9c2dfb704db4e30be2e1e3dc0e16ee012103161f2325217e38461d71745e8652851a90285eb89e4344e48b804f3c943b5433ffffffff1001ccac2ebc5928cd80db21b9323d5c4bcb930192f6903a8da27d56221b2eae000000006b483045022100f43f677961c5cf4ad9df2351523e64e963f2e34082dde6ff2162e76f3ba2deed0220430bbfae4ee22884011c88db890848f0b880e6e6d3335fc1c93bd13f9a986b19012103161f2325217e38461d71745e8652851a90285eb89e4344e48b804f3c943b5433ffffffff02232a0daf00000000160014f78aa1ee8590fad304450b732416ecbface4ea6b00ca9a3b000000001600147ad8c91046724785f78b48d4ae606a3556ddf9b400000000" + } + ], + "usedTokens": 8, + "tokens": [ + { + "type": "XPUBAddress", + "name": "dgb1q0tvvjyzxwfrctautfr22ucr2x4tdm7d5va4lr6", + "path": "m/84'/20'/0'/0/0", + "transfers": 3, + "decimals": 8, + "balance": "2000000000", + "totalReceived": "3000000000", + "totalSent": "1000000000" + }, + { + "type": "XPUBAddress", + "name": "dgb1q6xgqq54z8h6t485v9t0sclvpttdkm6qwp4292e", + "path": "m/84'/20'/0'/0/1", + "transfers": 1, + "decimals": 8, + "balance": "1000000", + "totalReceived": "1000000", + "totalSent": "0" + }, + { + "type": "XPUBAddress", + "name": "dgb1qg29rqy8t08zdxfrcgppqpk75zppwv87wknuder", + "path": "m/84'/20'/0'/0/2", + "transfers": 1, + "decimals": 8, + "balance": "10000000", + "totalReceived": "10000000", + "totalSent": "0" + }, + { + "type": "XPUBAddress", + "name": "dgb1qv4pt3du9nx2trr05kuw893989mg3xe3w322vy7", + "path": "m/84'/20'/0'/1/4", + "transfers": 1, + "decimals": 8, + "balance": "588896040", + "totalReceived": "588896040", + "totalSent": "0" + } + ] +} diff --git a/mock/ext-api-data/doge-api_v2_address_D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh__details_txs.json b/mock/ext-api-data/doge-api_v2_address_D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh__details_txs.json new file mode 100644 index 000000000..1028b577a --- /dev/null +++ b/mock/ext-api-data/doge-api_v2_address_D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh__details_txs.json @@ -0,0 +1,568 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh", + "balance": "50394795942", + "totalReceived": "160202987826", + "totalSent": "109808191884", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 12, + "transactions": [ + { + "txid": "fee8381fed7406a48a8ea9e62328a3134064210626e81489ed8906e18c433bdf", + "version": 1, + "vin": [ + { + "txid": "c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb", + "n": 0, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true, + "value": "1000000000", + "hex": "47304402200833c3184e768e5b6da836d9824f98b65704a24229a02e572ac760bb304ab9fb022068d102da9400afaeee3a6b42930a966ff107f5c68affde4a0239dab9fa21123d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + } + ], + "vout": [ + { + "value": "134700000", + "n": 0, + "hex": "76a9142ba977acdb30bc18d350df32f38a777313ae86b088ac", + "addresses": [ + "D97xcKB9EAPmgNExbB5nAXDAQ9s5ZJ91J4" + ], + "isAddress": true + }, + { + "value": "707100000", + "n": 1, + "hex": "76a914b358390833fd8371733c1d11477bdb2d185e61e988ac", + "addresses": [ + "DMVPBRTD6bgqr3fk2yTdz97hS4AA2gzj8g" + ], + "isAddress": true + } + ], + "blockHash": "b94fd58d99710000ff0991ebf82c85330ed706ea18bcd4265e1f22747b91ddfe", + "blockHeight": 3170421, + "confirmations": 56768, + "blockTime": 1585794154, + "value": "841800000", + "valueIn": "1000000000", + "fees": "158200000", + "hex": "0100000001fb1d11634e4149776ceb89325044be3f2b14989d65584f323c16bbd4d21ea5c6000000006a47304402200833c3184e768e5b6da836d9824f98b65704a24229a02e572ac760bb304ab9fb022068d102da9400afaeee3a6b42930a966ff107f5c68affde4a0239dab9fa21123d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca0000000002e05b0708000000001976a9142ba977acdb30bc18d350df32f38a777313ae86b088ac607d252a000000001976a914b358390833fd8371733c1d11477bdb2d185e61e988ac00000000" + }, + { + "txid": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9", + "version": 1, + "vin": [ + { + "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", + "vout": 1, + "sequence": 4294967288, + "n": 0, + "addresses": [ + "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" + ], + "isAddress": true, + "value": "533600000", + "hex": "483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + }, + { + "value": "275400000", + "n": 1, + "hex": "76a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac", + "addresses": [ + "DKix6fTygojRpBFbADfkYKDX9nZ2Y7Huqq" + ], + "isAddress": true + } + ], + "blockHash": "ece2c433edfaf7143ba79f381ea40ac8b7e38ce6c4ff0771ae1e3dda9246824a", + "blockHeight": 3099770, + "confirmations": 127419, + "blockTime": 1581351126, + "value": "375400000", + "valueIn": "533600000", + "fees": "158200000", + "hex": "0100000001987490208464a2b0547cf6fcae4b550be9bb9ca88ce526ef4a0ee5803da50df6010000006b483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5f8ffffff0200e1f505000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac40456a10000000001976a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac00000000" + }, + { + "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", + "version": 1, + "vin": [ + { + "txid": "c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb", + "vout": 1, + "sequence": 4294967291, + "n": 0, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true, + "value": "841800000", + "hex": "483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + } + ], + "vout": [ + { + "value": "150000000", + "n": 0, + "hex": "76a914e82178c73b5744342916f6a7a944af4fa37aebff88ac", + "addresses": [ + "DSJVQRY3wyVPrXbEDMSeoFufWNSsMeKEuj" + ], + "isAddress": true + }, + { + "value": "533600000", + "n": 1, + "spent": true, + "hex": "76a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac", + "addresses": [ + "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" + ], + "isAddress": true + } + ], + "blockHash": "d4a57feed1683117d412944fc6581eace1bc3a8be5ebab93cf2dd99f5918374d", + "blockHeight": 3088989, + "confirmations": 138200, + "blockTime": 1580673745, + "value": "683600000", + "valueIn": "841800000", + "fees": "158200000", + "hex": "0100000001fb1d11634e4149776ceb89325044be3f2b14989d65584f323c16bbd4d21ea5c6010000006b483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6cafbffffff0280d1f008000000001976a914e82178c73b5744342916f6a7a944af4fa37aebff88ac0017ce1f000000001976a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac00000000" + }, + { + "txid": "17e7d6371140eba1d57a2461a8d646534ff0c8044aff83b90c49f9d74aad0a8e", + "version": 1, + "vin": [ + { + "txid": "eaead3019d3a76858d7c106cdf3324595b8c1f06ae3ecf668327c997bb584f33", + "vout": 1, + "n": 0, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true, + "value": "483600000", + "hex": "4730440220336f743b7030ac993705d48a4e64d1bb5a7c2fbddeabdc4fdb33f7f41c7addc502202c723805658115ae148b9211b25987813c848949a3cd835b942de0b248168e7c012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + } + ], + "vout": [ + { + "value": "134700000", + "n": 0, + "spent": true, + "hex": "76a9147e2cd472834c324ead9cc333c50c55117e07525a88ac", + "addresses": [ + "DGeFPGDgmxcuVFS4WGKQ4cqEgJSAnz6tpt" + ], + "isAddress": true + }, + { + "value": "190700000", + "n": 1, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + } + ], + "blockHash": "03a3c4216bf64a38dac9ca5c34722f79ec67e0b3de9ba8a58108fced2b782374", + "blockHeight": 3082655, + "confirmations": 144534, + "blockTime": 1580277168, + "value": "325400000", + "valueIn": "483600000", + "fees": "158200000", + "hex": "0100000001334f58bb97c9278366cf3eae061f8c5b592433df6c107c8d85763a9d01d3eaea010000006a4730440220336f743b7030ac993705d48a4e64d1bb5a7c2fbddeabdc4fdb33f7f41c7addc502202c723805658115ae148b9211b25987813c848949a3cd835b942de0b248168e7c012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca0000000002e05b0708000000001976a9147e2cd472834c324ead9cc333c50c55117e07525a88ace0d95d0b000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000" + }, + { + "txid": "c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb", + "version": 1, + "vin": [ + { + "txid": "44941f1d6b3bf0361f00a00d8e503ce8d0289b0990c5b4a6d13de00fa4eec1cd", + "n": 0, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true, + "value": "2000000000", + "hex": "473044022027ca75c9763fa154134343a46d8ea35c28d1231d2a0e6857564773866f5a91fe02206ec5af0e55730bfbbf53eb0eb3fccfcace7b051af973a176d8d8d096675772b2012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + } + ], + "vout": [ + { + "value": "1000000000", + "n": 0, + "spent": true, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + }, + { + "value": "841800000", + "n": 1, + "spent": true, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + } + ], + "blockHash": "4701d7cf8b274af55ddddfbe76527f9b616fc69325c08b79ed35da5183be37c3", + "blockHeight": 3081510, + "confirmations": 145679, + "blockTime": 1580204896, + "value": "1841800000", + "valueIn": "2000000000", + "fees": "158200000", + "hex": "0100000001cdc1eea40fe03dd1a6b4c590099b28d0e83c508e0da0001f36f03b6b1d1f9444000000006a473044022027ca75c9763fa154134343a46d8ea35c28d1231d2a0e6857564773866f5a91fe02206ec5af0e55730bfbbf53eb0eb3fccfcace7b051af973a176d8d8d096675772b2012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca000000000200ca9a3b000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac40d92c32000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000" + }, + { + "txid": "eaead3019d3a76858d7c106cdf3324595b8c1f06ae3ecf668327c997bb584f33", + "version": 1, + "vin": [ + { + "txid": "a369bf2cee39e406b04d3782385f76956241b5ac1774db13f166c8e8a0172d36", + "vout": 1, + "n": 0, + "addresses": [ + "DAth3nj1fUStB8UHxxuE4uFfjg8Aze4S8v" + ], + "isAddress": true, + "value": "741800000", + "hex": "47304402202377dc80bcc0d43a2996ec3057056730489cc3b138f504c6be5229d5441246c202201c7bdfed8a8388336b754b7a21ec631e8f5bbfcfa3ebb68cfb5d5cea60971ec30121029f274c032269ab70b7a1bed45068f6e97f0b865ae652a98054fdd25e04af267a" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + }, + { + "value": "483600000", + "n": 1, + "spent": true, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + } + ], + "blockHash": "fab26df4f935751512760217249335c9a4218bd84766152bd1d1b47f7cdfe33e", + "blockHeight": 3079034, + "confirmations": 148155, + "blockTime": 1580049813, + "value": "583600000", + "valueIn": "741800000", + "fees": "158200000", + "hex": "0100000001362d17a0e8c866f113db7417acb5416295765f3882374db006e439ee2cbf69a3010000006a47304402202377dc80bcc0d43a2996ec3057056730489cc3b138f504c6be5229d5441246c202201c7bdfed8a8388336b754b7a21ec631e8f5bbfcfa3ebb68cfb5d5cea60971ec30121029f274c032269ab70b7a1bed45068f6e97f0b865ae652a98054fdd25e04af267a000000000200e1f505000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac8026d31c000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000" + }, + { + "txid": "44941f1d6b3bf0361f00a00d8e503ce8d0289b0990c5b4a6d13de00fa4eec1cd", + "version": 1, + "vin": [ + { + "txid": "2b59988ab83317341e9ee48a0ba80abf4399254089037dc7660d000de53565e7", + "vout": 1, + "n": 0, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true, + "value": "51162295942", + "hex": "4830450221009bd7a6e5d664c57b7c994fe2bba3fc14db41e3b961b52f6da46ea517f0a765bf022028a695add7d1f0e948a492ba196f6266cc7cafc9628a9ac4518cd7fceb1e1f54012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + } + ], + "vout": [ + { + "value": "2000000000", + "n": 0, + "spent": true, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + }, + { + "value": "49004095942", + "n": 1, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + } + ], + "blockHash": "a6ebe4f81737b59699c7a3a59f21b93280c7d2a88c9e84dd90b4326226074f4f", + "blockHeight": 3074554, + "confirmations": 152635, + "blockTime": 1579769000, + "value": "51004095942", + "valueIn": "51162295942", + "fees": "158200000", + "hex": "0100000001e76535e50d000d66c77d038940259943bf0aa80b8ae49e1e341733b88a98592b010000006b4830450221009bd7a6e5d664c57b7c994fe2bba3fc14db41e3b961b52f6da46ea517f0a765bf022028a695add7d1f0e948a492ba196f6266cc7cafc9628a9ac4518cd7fceb1e1f54012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca000000000200943577000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688acc629df680b0000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000" + }, + { + "txid": "a369bf2cee39e406b04d3782385f76956241b5ac1774db13f166c8e8a0172d36", + "version": 1, + "vin": [ + { + "txid": "2b59988ab83317341e9ee48a0ba80abf4399254089037dc7660d000de53565e7", + "sequence": 4294967291, + "n": 0, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true, + "value": "1000000000", + "hex": "4730440220348d03905d720f7bf4adf247195dcb30f4e581a88ca611ad2c336665acb10e73022034926b1fadbe03078c3210502f76cc34340b9e5a906ba1deb9ee9fc3c2a5b20d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "76a9149fc4e4b3c5a1331b93b26bcb290c7fa2633e304688ac", + "addresses": [ + "DKhsr9gcxfZ1EPGz7YK4BwWAPDeATwT94o" + ], + "isAddress": true + }, + { + "value": "741800000", + "n": 1, + "spent": true, + "hex": "76a9143f175272c8685646337257fdd4ff9837b3b37d0d88ac", + "addresses": [ + "DAth3nj1fUStB8UHxxuE4uFfjg8Aze4S8v" + ], + "isAddress": true + } + ], + "blockHash": "d677e3585338c456ba1c84e5ac360dba7b972840ece88b59b7977cab32fe697d", + "blockHeight": 3073761, + "confirmations": 153428, + "blockTime": 1579719400, + "value": "841800000", + "valueIn": "1000000000", + "fees": "158200000", + "hex": "0100000001e76535e50d000d66c77d038940259943bf0aa80b8ae49e1e341733b88a98592b000000006a4730440220348d03905d720f7bf4adf247195dcb30f4e581a88ca611ad2c336665acb10e73022034926b1fadbe03078c3210502f76cc34340b9e5a906ba1deb9ee9fc3c2a5b20d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6cafbffffff0200e1f505000000001976a9149fc4e4b3c5a1331b93b26bcb290c7fa2633e304688ac40f8362c000000001976a9143f175272c8685646337257fdd4ff9837b3b37d0d88ac00000000" + }, + { + "txid": "2b59988ab83317341e9ee48a0ba80abf4399254089037dc7660d000de53565e7", + "version": 1, + "vin": [ + { + "txid": "a5ea8e1bfcad3f860d8e2876486213d9448f14d0b4fae2d5f4c6f7ad9fd187bf", + "vout": 1, + "n": 0, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true, + "value": "52320495942", + "hex": "4830450221008e5dd501d7a6b0c9babca2f5d8b11ada06fb2918303c5f281b1fe8e64cde7b4802206f86df1d40eb42108ade7cad36226f9e1ba75cb282cab75ed12fcb387f4970b2012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + } + ], + "vout": [ + { + "value": "1000000000", + "n": 0, + "spent": true, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + }, + { + "value": "51162295942", + "n": 1, + "spent": true, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + } + ], + "blockHash": "0c13cea0560ccf100ccfa2b484aaf6639f4a75fe9029708728abbf42423981bf", + "blockHeight": 3070556, + "confirmations": 156633, + "blockTime": 1579517965, + "value": "52162295942", + "valueIn": "52320495942", + "fees": "158200000", + "hex": "0100000001bf87d19fadf7c6f4d5e2fab4d0148f44d913624876288e0d863fadfc1b8eeaa5010000006b4830450221008e5dd501d7a6b0c9babca2f5d8b11ada06fb2918303c5f281b1fe8e64cde7b4802206f86df1d40eb42108ade7cad36226f9e1ba75cb282cab75ed12fcb387f4970b2012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca000000000200ca9a3b000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac86ae82e90b0000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000" + }, + { + "txid": "a5ea8e1bfcad3f860d8e2876486213d9448f14d0b4fae2d5f4c6f7ad9fd187bf", + "version": 1, + "vin": [ + { + "txid": "0a43e6297dc2c63527bc0138e199cfe41b6b41c4877ba60a425bd425a7eafec9", + "vout": 1, + "n": 0, + "addresses": [ + "DLKFsc4PWe6KSGbeXZPv9kgCrQQBycf6nc" + ], + "isAddress": true, + "value": "53478695942", + "hex": "483045022100db69f1b5966a47c20de9fcf9891ff6bda8f9ccd28336acd51276a4134290bd9002200c33d0c4bb76c8c0596a68fb715a8e7cc47ac98a65266f9ef40ea2de36ca3a9b012102debf9eb33094bbbf385e118614f4e8d67c946067677dd85de913415800148c5f" + } + ], + "vout": [ + { + "value": "1000000000", + "n": 0, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + }, + { + "value": "52320495942", + "n": 1, + "spent": true, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + } + ], + "blockHash": "336481816fe09f284657ebe3c98fca8fab4c3edd7e15ddbb5f8c19bd00326f9c", + "blockHeight": 3070538, + "confirmations": 156651, + "blockTime": 1579516786, + "value": "53320495942", + "valueIn": "53478695942", + "fees": "158200000", + "hex": "0100000001c9feeaa725d45b420aa67b87c4416b1be4cf99e13801bc2735c6c27d29e6430a010000006b483045022100db69f1b5966a47c20de9fcf9891ff6bda8f9ccd28336acd51276a4134290bd9002200c33d0c4bb76c8c0596a68fb715a8e7cc47ac98a65266f9ef40ea2de36ca3a9b012102debf9eb33094bbbf385e118614f4e8d67c946067677dd85de913415800148c5f000000000200ca9a3b000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac46698b2e0c0000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000" + }, + { + "txid": "e71cf261f87ee49397315d77722e53b9bee1fd8ea2a4676386c3555151b6f722", + "version": 1, + "vin": [ + { + "txid": "535b9feb13c603f8bceaa79665fd03bd0f088080f4ea299b0cca7cce3632ad07", + "n": 0, + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true, + "value": "1000000000", + "hex": "483045022100a684b77c1875ab28357fef968c045cab2e58f1a22f0e98260a84290177cf538002202c509b3a44bc0dec7f921f8c94f3dd114f5be037b2ff0b9981548c37eebf010a012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a914f333c40dfb29e23867fe8dbd73627e0740de84ed88ac", + "addresses": [ + "DTK2kdJb313M5rUEtDZvBDXcDtutZo7dWT" + ], + "isAddress": true + }, + { + "value": "779950382", + "n": 1, + "spent": true, + "hex": "76a9143e03a905771cb71314952a02462d03e01a6c399288ac", + "addresses": [ + "DAnzpUCmzUU1QtGsoASw54jSphpxsm1Apa" + ], + "isAddress": true + } + ], + "blockHash": "c6e007320b2bbab17086a2b76ad823d976b5bb1b6c95a31ed43268d6db0744c8", + "blockHeight": 2679141, + "confirmations": 548048, + "blockTime": 1555034899, + "value": "879950382", + "valueIn": "1000000000", + "fees": "120049618", + "hex": "010000000107ad3236ce7cca0c9b29eaf48080080fbd03fd6596a7eabcf803c613eb9f5b53000000006b483045022100a684b77c1875ab28357fef968c045cab2e58f1a22f0e98260a84290177cf538002202c509b3a44bc0dec7f921f8c94f3dd114f5be037b2ff0b9981548c37eebf010a012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca000000000200e1f505000000001976a914f333c40dfb29e23867fe8dbd73627e0740de84ed88ac2e197d2e000000001976a9143e03a905771cb71314952a02462d03e01a6c399288ac00000000" + }, + { + "txid": "535b9feb13c603f8bceaa79665fd03bd0f088080f4ea299b0cca7cce3632ad07", + "version": 1, + "vin": [ + { + "txid": "89e57e06ee263f1dcfaf7da712b073ac8db0472314f8da74c37782843b836b00", + "vout": 1, + "sequence": 4294967295, + "n": 0, + "addresses": [ + "A5ozMKvBJhMi5sMgwzbfVLs1WZ1t4c7JKB" + ], + "isAddress": true, + "value": "297501351695", + "hex": "00483045022100ee88f81596f41103023e210369b1ff06dbcbec3480e06641b897f566fbfe3082022027ec2cc39cfadbfb38ad4833061014d381dc74e29204dabc9079d87626b0752e01483045022100faa61e1cbd295cae9a3347a82b46014daa3f5aba3058632c9ec03be8fa3e764802201427b682f7e99ea6cac888239399ec6cd58305304a3dd950149e5bacb5b0e30301475221032a6ddebdac7ca3f832d6a7124002a7d3d9fc7ee05c29cf566502b9a84c2ab70221036c8ffa92f159c02d49a2149f9901ad624aa65e05a33f0ffa0e1a0a3c163e065552ae" + } + ], + "vout": [ + { + "value": "1000000000", + "n": 0, + "spent": true, + "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", + "addresses": [ + "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" + ], + "isAddress": true + }, + { + "value": "296301351695", + "n": 1, + "spent": true, + "hex": "a91492b52b95d25a130ccbb077703596b26e9be3c84587", + "addresses": [ + "A5ozMKvBJhMi5sMgwzbfVLs1WZ1t4c7JKB" + ], + "isAddress": true + } + ], + "blockHash": "1addc60124792f9abed8bb39aa0cd63a81911e3c361e2c313b56083cc306de2b", + "blockHeight": 2677741, + "confirmations": 549448, + "blockTime": 1554946628, + "value": "297301351695", + "valueIn": "297501351695", + "fees": "200000000", + "hex": "0100000001006b833b848277c374daf8142347b08dac73b012a77dafcf1d3f26ee067ee58901000000db00483045022100ee88f81596f41103023e210369b1ff06dbcbec3480e06641b897f566fbfe3082022027ec2cc39cfadbfb38ad4833061014d381dc74e29204dabc9079d87626b0752e01483045022100faa61e1cbd295cae9a3347a82b46014daa3f5aba3058632c9ec03be8fa3e764802201427b682f7e99ea6cac888239399ec6cd58305304a3dd950149e5bacb5b0e30301475221032a6ddebdac7ca3f832d6a7124002a7d3d9fc7ee05c29cf566502b9a84c2ab70221036c8ffa92f159c02d49a2149f9901ad624aa65e05a33f0ffa0e1a0a3c163e065552aeffffffff0200ca9a3b000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac0fd3effc4400000017a91492b52b95d25a130ccbb077703596b26e9be3c8458700000000" + } + ] +} diff --git a/mock/ext-api-data/doge-api_v2_xpub_dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN__details_txs.json b/mock/ext-api-data/doge-api_v2_xpub_dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN__details_txs.json new file mode 100644 index 000000000..2ecb2d52d --- /dev/null +++ b/mock/ext-api-data/doge-api_v2_xpub_dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":12,"itemsOnPage":10,"address":"dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN","balance":"53244505232","totalReceived":"2702075149752","totalSent":"2648830644520","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":112,"transactions":[{"txid":"fee8381fed7406a48a8ea9e62328a3134064210626e81489ed8906e18c433bdf","version":1,"vin":[{"txid":"c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb","n":0,"addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true,"value":"1000000000","hex":"47304402200833c3184e768e5b6da836d9824f98b65704a24229a02e572ac760bb304ab9fb022068d102da9400afaeee3a6b42930a966ff107f5c68affde4a0239dab9fa21123d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca"}],"vout":[{"value":"134700000","n":0,"hex":"76a9142ba977acdb30bc18d350df32f38a777313ae86b088ac","addresses":["D97xcKB9EAPmgNExbB5nAXDAQ9s5ZJ91J4"],"isAddress":true},{"value":"707100000","n":1,"hex":"76a914b358390833fd8371733c1d11477bdb2d185e61e988ac","addresses":["DMVPBRTD6bgqr3fk2yTdz97hS4AA2gzj8g"],"isAddress":true}],"blockHash":"b94fd58d99710000ff0991ebf82c85330ed706ea18bcd4265e1f22747b91ddfe","blockHeight":3170421,"confirmations":67953,"blockTime":1585794154,"value":"841800000","valueIn":"1000000000","fees":"158200000","hex":"0100000001fb1d11634e4149776ceb89325044be3f2b14989d65584f323c16bbd4d21ea5c6000000006a47304402200833c3184e768e5b6da836d9824f98b65704a24229a02e572ac760bb304ab9fb022068d102da9400afaeee3a6b42930a966ff107f5c68affde4a0239dab9fa21123d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca0000000002e05b0708000000001976a9142ba977acdb30bc18d350df32f38a777313ae86b088ac607d252a000000001976a914b358390833fd8371733c1d11477bdb2d185e61e988ac00000000"},{"txid":"8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9","version":1,"vin":[{"txid":"f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498","vout":1,"sequence":4294967288,"n":0,"addresses":["DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3"],"isAddress":true,"value":"533600000","hex":"483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5"}],"vout":[{"value":"100000000","n":0,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true},{"value":"275400000","n":1,"hex":"76a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac","addresses":["DKix6fTygojRpBFbADfkYKDX9nZ2Y7Huqq"],"isAddress":true}],"blockHash":"ece2c433edfaf7143ba79f381ea40ac8b7e38ce6c4ff0771ae1e3dda9246824a","blockHeight":3099770,"confirmations":138604,"blockTime":1581351126,"value":"375400000","valueIn":"533600000","fees":"158200000","hex":"0100000001987490208464a2b0547cf6fcae4b550be9bb9ca88ce526ef4a0ee5803da50df6010000006b483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5f8ffffff0200e1f505000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac40456a10000000001976a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac00000000"},{"txid":"f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498","version":1,"vin":[{"txid":"c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb","vout":1,"sequence":4294967291,"n":0,"addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true,"value":"841800000","hex":"483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca"}],"vout":[{"value":"150000000","n":0,"hex":"76a914e82178c73b5744342916f6a7a944af4fa37aebff88ac","addresses":["DSJVQRY3wyVPrXbEDMSeoFufWNSsMeKEuj"],"isAddress":true},{"value":"533600000","n":1,"spent":true,"hex":"76a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac","addresses":["DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3"],"isAddress":true}],"blockHash":"d4a57feed1683117d412944fc6581eace1bc3a8be5ebab93cf2dd99f5918374d","blockHeight":3088989,"confirmations":149385,"blockTime":1580673745,"value":"683600000","valueIn":"841800000","fees":"158200000","hex":"0100000001fb1d11634e4149776ceb89325044be3f2b14989d65584f323c16bbd4d21ea5c6010000006b483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6cafbffffff0280d1f008000000001976a914e82178c73b5744342916f6a7a944af4fa37aebff88ac0017ce1f000000001976a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac00000000"},{"txid":"17e7d6371140eba1d57a2461a8d646534ff0c8044aff83b90c49f9d74aad0a8e","version":1,"vin":[{"txid":"eaead3019d3a76858d7c106cdf3324595b8c1f06ae3ecf668327c997bb584f33","vout":1,"n":0,"addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true,"value":"483600000","hex":"4730440220336f743b7030ac993705d48a4e64d1bb5a7c2fbddeabdc4fdb33f7f41c7addc502202c723805658115ae148b9211b25987813c848949a3cd835b942de0b248168e7c012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca"}],"vout":[{"value":"134700000","n":0,"spent":true,"hex":"76a9147e2cd472834c324ead9cc333c50c55117e07525a88ac","addresses":["DGeFPGDgmxcuVFS4WGKQ4cqEgJSAnz6tpt"],"isAddress":true},{"value":"190700000","n":1,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true}],"blockHash":"03a3c4216bf64a38dac9ca5c34722f79ec67e0b3de9ba8a58108fced2b782374","blockHeight":3082655,"confirmations":155719,"blockTime":1580277168,"value":"325400000","valueIn":"483600000","fees":"158200000","hex":"0100000001334f58bb97c9278366cf3eae061f8c5b592433df6c107c8d85763a9d01d3eaea010000006a4730440220336f743b7030ac993705d48a4e64d1bb5a7c2fbddeabdc4fdb33f7f41c7addc502202c723805658115ae148b9211b25987813c848949a3cd835b942de0b248168e7c012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca0000000002e05b0708000000001976a9147e2cd472834c324ead9cc333c50c55117e07525a88ace0d95d0b000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000"},{"txid":"c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb","version":1,"vin":[{"txid":"44941f1d6b3bf0361f00a00d8e503ce8d0289b0990c5b4a6d13de00fa4eec1cd","n":0,"addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true,"value":"2000000000","hex":"473044022027ca75c9763fa154134343a46d8ea35c28d1231d2a0e6857564773866f5a91fe02206ec5af0e55730bfbbf53eb0eb3fccfcace7b051af973a176d8d8d096675772b2012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca"}],"vout":[{"value":"1000000000","n":0,"spent":true,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true},{"value":"841800000","n":1,"spent":true,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true}],"blockHash":"4701d7cf8b274af55ddddfbe76527f9b616fc69325c08b79ed35da5183be37c3","blockHeight":3081510,"confirmations":156864,"blockTime":1580204896,"value":"1841800000","valueIn":"2000000000","fees":"158200000","hex":"0100000001cdc1eea40fe03dd1a6b4c590099b28d0e83c508e0da0001f36f03b6b1d1f9444000000006a473044022027ca75c9763fa154134343a46d8ea35c28d1231d2a0e6857564773866f5a91fe02206ec5af0e55730bfbbf53eb0eb3fccfcace7b051af973a176d8d8d096675772b2012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca000000000200ca9a3b000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac40d92c32000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000"},{"txid":"eaead3019d3a76858d7c106cdf3324595b8c1f06ae3ecf668327c997bb584f33","version":1,"vin":[{"txid":"a369bf2cee39e406b04d3782385f76956241b5ac1774db13f166c8e8a0172d36","vout":1,"n":0,"addresses":["DAth3nj1fUStB8UHxxuE4uFfjg8Aze4S8v"],"isAddress":true,"value":"741800000","hex":"47304402202377dc80bcc0d43a2996ec3057056730489cc3b138f504c6be5229d5441246c202201c7bdfed8a8388336b754b7a21ec631e8f5bbfcfa3ebb68cfb5d5cea60971ec30121029f274c032269ab70b7a1bed45068f6e97f0b865ae652a98054fdd25e04af267a"}],"vout":[{"value":"100000000","n":0,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true},{"value":"483600000","n":1,"spent":true,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true}],"blockHash":"fab26df4f935751512760217249335c9a4218bd84766152bd1d1b47f7cdfe33e","blockHeight":3079034,"confirmations":159340,"blockTime":1580049813,"value":"583600000","valueIn":"741800000","fees":"158200000","hex":"0100000001362d17a0e8c866f113db7417acb5416295765f3882374db006e439ee2cbf69a3010000006a47304402202377dc80bcc0d43a2996ec3057056730489cc3b138f504c6be5229d5441246c202201c7bdfed8a8388336b754b7a21ec631e8f5bbfcfa3ebb68cfb5d5cea60971ec30121029f274c032269ab70b7a1bed45068f6e97f0b865ae652a98054fdd25e04af267a000000000200e1f505000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac8026d31c000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000"},{"txid":"44941f1d6b3bf0361f00a00d8e503ce8d0289b0990c5b4a6d13de00fa4eec1cd","version":1,"vin":[{"txid":"2b59988ab83317341e9ee48a0ba80abf4399254089037dc7660d000de53565e7","vout":1,"n":0,"addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true,"value":"51162295942","hex":"4830450221009bd7a6e5d664c57b7c994fe2bba3fc14db41e3b961b52f6da46ea517f0a765bf022028a695add7d1f0e948a492ba196f6266cc7cafc9628a9ac4518cd7fceb1e1f54012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca"}],"vout":[{"value":"2000000000","n":0,"spent":true,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true},{"value":"49004095942","n":1,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true}],"blockHash":"a6ebe4f81737b59699c7a3a59f21b93280c7d2a88c9e84dd90b4326226074f4f","blockHeight":3074554,"confirmations":163820,"blockTime":1579769000,"value":"51004095942","valueIn":"51162295942","fees":"158200000","hex":"0100000001e76535e50d000d66c77d038940259943bf0aa80b8ae49e1e341733b88a98592b010000006b4830450221009bd7a6e5d664c57b7c994fe2bba3fc14db41e3b961b52f6da46ea517f0a765bf022028a695add7d1f0e948a492ba196f6266cc7cafc9628a9ac4518cd7fceb1e1f54012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca000000000200943577000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688acc629df680b0000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000"},{"txid":"a369bf2cee39e406b04d3782385f76956241b5ac1774db13f166c8e8a0172d36","version":1,"vin":[{"txid":"2b59988ab83317341e9ee48a0ba80abf4399254089037dc7660d000de53565e7","sequence":4294967291,"n":0,"addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true,"value":"1000000000","hex":"4730440220348d03905d720f7bf4adf247195dcb30f4e581a88ca611ad2c336665acb10e73022034926b1fadbe03078c3210502f76cc34340b9e5a906ba1deb9ee9fc3c2a5b20d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca"}],"vout":[{"value":"100000000","n":0,"hex":"76a9149fc4e4b3c5a1331b93b26bcb290c7fa2633e304688ac","addresses":["DKhsr9gcxfZ1EPGz7YK4BwWAPDeATwT94o"],"isAddress":true},{"value":"741800000","n":1,"spent":true,"hex":"76a9143f175272c8685646337257fdd4ff9837b3b37d0d88ac","addresses":["DAth3nj1fUStB8UHxxuE4uFfjg8Aze4S8v"],"isAddress":true}],"blockHash":"d677e3585338c456ba1c84e5ac360dba7b972840ece88b59b7977cab32fe697d","blockHeight":3073761,"confirmations":164613,"blockTime":1579719400,"value":"841800000","valueIn":"1000000000","fees":"158200000","hex":"0100000001e76535e50d000d66c77d038940259943bf0aa80b8ae49e1e341733b88a98592b000000006a4730440220348d03905d720f7bf4adf247195dcb30f4e581a88ca611ad2c336665acb10e73022034926b1fadbe03078c3210502f76cc34340b9e5a906ba1deb9ee9fc3c2a5b20d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6cafbffffff0200e1f505000000001976a9149fc4e4b3c5a1331b93b26bcb290c7fa2633e304688ac40f8362c000000001976a9143f175272c8685646337257fdd4ff9837b3b37d0d88ac00000000"},{"txid":"2b59988ab83317341e9ee48a0ba80abf4399254089037dc7660d000de53565e7","version":1,"vin":[{"txid":"a5ea8e1bfcad3f860d8e2876486213d9448f14d0b4fae2d5f4c6f7ad9fd187bf","vout":1,"n":0,"addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true,"value":"52320495942","hex":"4830450221008e5dd501d7a6b0c9babca2f5d8b11ada06fb2918303c5f281b1fe8e64cde7b4802206f86df1d40eb42108ade7cad36226f9e1ba75cb282cab75ed12fcb387f4970b2012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca"}],"vout":[{"value":"1000000000","n":0,"spent":true,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true},{"value":"51162295942","n":1,"spent":true,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true}],"blockHash":"0c13cea0560ccf100ccfa2b484aaf6639f4a75fe9029708728abbf42423981bf","blockHeight":3070556,"confirmations":167818,"blockTime":1579517965,"value":"52162295942","valueIn":"52320495942","fees":"158200000","hex":"0100000001bf87d19fadf7c6f4d5e2fab4d0148f44d913624876288e0d863fadfc1b8eeaa5010000006b4830450221008e5dd501d7a6b0c9babca2f5d8b11ada06fb2918303c5f281b1fe8e64cde7b4802206f86df1d40eb42108ade7cad36226f9e1ba75cb282cab75ed12fcb387f4970b2012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca000000000200ca9a3b000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac86ae82e90b0000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000"},{"txid":"a5ea8e1bfcad3f860d8e2876486213d9448f14d0b4fae2d5f4c6f7ad9fd187bf","version":1,"vin":[{"txid":"0a43e6297dc2c63527bc0138e199cfe41b6b41c4877ba60a425bd425a7eafec9","vout":1,"n":0,"addresses":["DLKFsc4PWe6KSGbeXZPv9kgCrQQBycf6nc"],"isAddress":true,"value":"53478695942","hex":"483045022100db69f1b5966a47c20de9fcf9891ff6bda8f9ccd28336acd51276a4134290bd9002200c33d0c4bb76c8c0596a68fb715a8e7cc47ac98a65266f9ef40ea2de36ca3a9b012102debf9eb33094bbbf385e118614f4e8d67c946067677dd85de913415800148c5f"}],"vout":[{"value":"1000000000","n":0,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true},{"value":"52320495942","n":1,"spent":true,"hex":"76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac","addresses":["D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh"],"isAddress":true}],"blockHash":"336481816fe09f284657ebe3c98fca8fab4c3edd7e15ddbb5f8c19bd00326f9c","blockHeight":3070538,"confirmations":167836,"blockTime":1579516786,"value":"53320495942","valueIn":"53478695942","fees":"158200000","hex":"0100000001c9feeaa725d45b420aa67b87c4416b1be4cf99e13801bc2735c6c27d29e6430a010000006b483045022100db69f1b5966a47c20de9fcf9891ff6bda8f9ccd28336acd51276a4134290bd9002200c33d0c4bb76c8c0596a68fb715a8e7cc47ac98a65266f9ef40ea2de36ca3a9b012102debf9eb33094bbbf385e118614f4e8d67c946067677dd85de913415800148c5f000000000200ca9a3b000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac46698b2e0c0000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac00000000"}],"usedTokens":111,"tokens":[{"type":"XPUBAddress","name":"D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh","path":"m/44'/3'/0'/0/0","transfers":12,"decimals":8,"balance":"50394795942","totalReceived":"160202987826","totalSent":"109808191884"},{"type":"XPUBAddress","name":"DAmfSJjQsNhZhG9ofHPVmBoycaVCsGyedt","path":"m/44'/3'/0'/0/6","transfers":3,"decimals":8,"balance":"55000000","totalReceived":"305000000","totalSent":"250000000"},{"type":"XPUBAddress","name":"DAzJEmCZXWWji8fjhKwA2WXZjbLNpbAbNa","path":"m/44'/3'/0'/0/7","transfers":1,"decimals":8,"balance":"77500000","totalReceived":"77500000","totalSent":"0"},{"type":"XPUBAddress","name":"DTUsUEgauBsHowJe2nuQMwVZ2irqhENJ6Y","path":"m/44'/3'/0'/0/8","transfers":1,"decimals":8,"balance":"66500000","totalReceived":"66500000","totalSent":"0"},{"type":"XPUBAddress","name":"DEcqrwwRs6gYH4YSvHhmiaPpd3DyQYa2uR","path":"m/44'/3'/0'/0/9","transfers":1,"decimals":8,"balance":"8454000","totalReceived":"8454000","totalSent":"0"},{"type":"XPUBAddress","name":"DGVDyBSb7NMzYna2V8u8exUecgUz2m4xXQ","path":"m/44'/3'/0'/0/10","transfers":1,"decimals":8,"balance":"3350000","totalReceived":"3350000","totalSent":"0"},{"type":"XPUBAddress","name":"DPdHGVnuP2k2CyY2zp4goS9EqQGD6hUzBR","path":"m/44'/3'/0'/0/11","transfers":1,"decimals":8,"balance":"5577000","totalReceived":"5577000","totalSent":"0"},{"type":"XPUBAddress","name":"DCKFrLUWqydYnX1Fs8iSzDqkskzATUoxpT","path":"m/44'/3'/0'/0/12","transfers":1,"decimals":8,"balance":"6688550","totalReceived":"6688550","totalSent":"0"},{"type":"XPUBAddress","name":"DBmCuiHwpBrGwFVRoKbpatCFFGQt5pxJ3T","path":"m/44'/3'/0'/0/14","transfers":1,"decimals":8,"balance":"90000000","totalReceived":"90000000","totalSent":"0"},{"type":"XPUBAddress","name":"DGy5ZmuRmF7qdhPnrNX6avTDYjABnS5xDk","path":"m/44'/3'/0'/0/17","transfers":1,"decimals":8,"balance":"5000","totalReceived":"5000","totalSent":"0"},{"type":"XPUBAddress","name":"DEnxVnyWxHCi64BwHDWHRuCnkTajMWzNQ6","path":"m/44'/3'/0'/0/19","transfers":1,"decimals":8,"balance":"100000000","totalReceived":"100000000","totalSent":"0"},{"type":"XPUBAddress","name":"DCtJGsdVMrr1MkXjHNq7JEw8g3wkV2Vucv","path":"m/44'/3'/0'/0/21","transfers":3,"decimals":8,"balance":"1000000","totalReceived":"2501000000","totalSent":"2500000000"},{"type":"XPUBAddress","name":"DMXSG11oMpiEXGVPFef22Gm3t6n5M3iC44","path":"m/44'/3'/0'/0/24","transfers":1,"decimals":8,"balance":"100000","totalReceived":"100000","totalSent":"0"},{"type":"XPUBAddress","name":"D9aUm1ghFCGAdf3A2F9yrfy7n8KcPUdQMP","path":"m/44'/3'/0'/0/25","transfers":1,"decimals":8,"balance":"100000000","totalReceived":"100000000","totalSent":"0"},{"type":"XPUBAddress","name":"DHBX9Bi3zPqypTuiTWyhwJofaYr57RkoCp","path":"m/44'/3'/0'/0/26","transfers":1,"decimals":8,"balance":"368650","totalReceived":"368650","totalSent":"0"},{"type":"XPUBAddress","name":"DSVfFWXDHk3X55egkvXALHy83XYz3xBDro","path":"m/44'/3'/0'/0/27","transfers":1,"decimals":8,"balance":"100300000","totalReceived":"100300000","totalSent":"0"},{"type":"XPUBAddress","name":"D9cgiTxGYh6aMveGG5Bu4HqHuujH7H1mYt","path":"m/44'/3'/0'/0/29","transfers":3,"decimals":8,"balance":"212600000","totalReceived":"54554702722","totalSent":"54342102722"},{"type":"XPUBAddress","name":"DUAqwidnicCws1SRyENmMJo2KekJmB72ZH","path":"m/44'/3'/0'/0/30","transfers":1,"decimals":8,"balance":"100000000","totalReceived":"100000000","totalSent":"0"},{"type":"XPUBAddress","name":"DTFB8Mf5zLx6fuEwheBUZmNUmyubQZkn8F","path":"m/44'/3'/0'/0/31","transfers":1,"decimals":8,"balance":"100000000","totalReceived":"100000000","totalSent":"0"},{"type":"XPUBAddress","name":"DKhsr9gcxfZ1EPGz7YK4BwWAPDeATwT94o","path":"m/44'/3'/0'/0/32","transfers":1,"decimals":8,"balance":"100000000","totalReceived":"100000000","totalSent":"0"},{"type":"XPUBAddress","name":"DSJVQRY3wyVPrXbEDMSeoFufWNSsMeKEuj","path":"m/44'/3'/0'/0/33","transfers":1,"decimals":8,"balance":"150000000","totalReceived":"150000000","totalSent":"0"},{"type":"XPUBAddress","name":"D6GBtZ7eWgeb9mWnewXzxJZFTBdp9wxkWP","path":"m/44'/3'/0'/1/14","transfers":1,"decimals":8,"balance":"53594096","totalReceived":"53594096","totalSent":"0"},{"type":"XPUBAddress","name":"DEWNmicZTDghQDGgBysziWnkQX7SJTTLB8","path":"m/44'/3'/0'/1/16","transfers":3,"decimals":8,"balance":"44999774","totalReceived":"590469146","totalSent":"545469372"},{"type":"XPUBAddress","name":"D9NnFbEq5xCqBa8HUx7nEdfcdazNqWMsJT","path":"m/44'/3'/0'/1/18","transfers":1,"decimals":8,"balance":"39281934","totalReceived":"39281934","totalSent":"0"},{"type":"XPUBAddress","name":"DHxauYh42gVDAuFzx5NjNDcNu5BqniTTwK","path":"m/44'/3'/0'/1/21","transfers":1,"decimals":8,"balance":"7807718","totalReceived":"7807718","totalSent":"0"},{"type":"XPUBAddress","name":"DEnByJTQuE5qW9LecZeUeqB8TShWRDpWhE","path":"m/44'/3'/0'/1/23","transfers":1,"decimals":8,"balance":"19811382","totalReceived":"19811382","totalSent":"0"},{"type":"XPUBAddress","name":"DDjudCpuaPaoi2FyiAVFu2vaxsAkJu5fxi","path":"m/44'/3'/0'/1/24","transfers":1,"decimals":8,"balance":"100175758","totalReceived":"100175758","totalSent":"0"},{"type":"XPUBAddress","name":"DDyapoohdiTuM5R8jjnpsnHsfW1NcSMrSL","path":"m/44'/3'/0'/1/27","transfers":1,"decimals":8,"balance":"75155276","totalReceived":"75155276","totalSent":"0"},{"type":"XPUBAddress","name":"DQwQAPehMc8B9cXTyHR852T73jKTpzttck","path":"m/44'/3'/0'/1/31","transfers":1,"decimals":8,"balance":"57559726","totalReceived":"57559726","totalSent":"0"},{"type":"XPUBAddress","name":"D98VNKCWrfxNnFRyTL5GnG81QrDhHa5oJb","path":"m/44'/3'/0'/1/37","transfers":3,"decimals":8,"balance":"100000000","totalReceived":"76212237584","totalSent":"76112237584"},{"type":"XPUBAddress","name":"DH8voVMkSxoyyLnd9TFvBEcbTRwk7DNqH1","path":"m/44'/3'/0'/1/49","transfers":1,"decimals":8,"balance":"580426","totalReceived":"580426","totalSent":"0"},{"type":"XPUBAddress","name":"DLEDSw71Emp4yJtp7q2HLXBapjVs7eSY42","path":"m/44'/3'/0'/1/58","transfers":1,"decimals":8,"balance":"90800000","totalReceived":"90800000","totalSent":"0"},{"type":"XPUBAddress","name":"DKix6fTygojRpBFbADfkYKDX9nZ2Y7Huqq","path":"m/44'/3'/0'/1/75","transfers":1,"decimals":8,"balance":"275400000","totalReceived":"275400000","totalSent":"0"},{"type":"XPUBAddress","name":"DMVPBRTD6bgqr3fk2yTdz97hS4AA2gzj8g","path":"m/44'/3'/0'/1/76","transfers":1,"decimals":8,"balance":"707100000","totalReceived":"707100000","totalSent":"0"}]} diff --git a/mock/ext-api-data/eth-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json b/mock/ext-api-data/eth-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json new file mode 100644 index 000000000..d0c420cca --- /dev/null +++ b/mock/ext-api-data/eth-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json @@ -0,0 +1,107 @@ +{ + "total": 17, + "docs": [ + { + "address": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + "name": "Kyber Network Crystal", + "decimals": 18, + "symbol": "KNC" + }, + { + "address": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", + "name": "BNB", + "decimals": 18, + "symbol": "BNB" + }, + { + "address": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "name": "Basic Attention Token", + "decimals": 18, + "symbol": "BAT" + }, + { + "address": "0x226bb599a12C826476e3A771454697EA52E9E220", + "name": "Propy", + "decimals": 8, + "symbol": "PRO" + }, + { + "address": "0xf3Db5Fa2C66B7aF3Eb0C0b782510816cbe4813b8", + "name": "Everex", + "decimals": 4, + "symbol": "EVX" + }, + { + "address": "0x85e076361cc813A908Ff672F9BAd1541474402b2", + "name": "Telcoin", + "decimals": 2, + "symbol": "TEL" + }, + { + "address": "0xD73bE539d6B2076BaB83CA6Ba62DfE189aBC6Bbe", + "name": "BlockchainCuties", + "decimals": 0, + "symbol": "BC" + }, + { + "address": "0x0000000000085d4780B73119b644AE5ecd22b376", + "name": "TrueUSD", + "decimals": 18, + "symbol": "TUSD" + }, + { + "address": "0xFBeef911Dc5821886e1dda71586d90eD28174B7d", + "name": "KnownOriginDigitalAsset", + "decimals": 0, + "symbol": "KODA" + }, + { + "address": "0xc3761EB917CD790B30dAD99f6Cc5b4Ff93C4F9eA", + "name": "ERC20", + "decimals": 18, + "symbol": "ERC20" + }, + { + "address": "0x77FE30b2cf39245267C0a5084B66a560f1cF9E1f", + "name": "Azbit", + "decimals": 18, + "symbol": "AZ" + }, + { + "address": "0x7f3EaB3491Ed282197038F1B89CA33D7e5ADffBa", + "name": "Coin-coin coinslot.com", + "decimals": 8, + "symbol": "CC coinslot.com" + }, + { + "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "name": "Tether USD", + "decimals": 6, + "symbol": "USDT" + }, + { + "address": "0xE1Ac9Eb7cDDAbfd9e5CA49c23bd521aFcDF8BE49", + "name": "Mycion", + "decimals": 18, + "symbol": "MYC" + }, + { + "address": "0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c", + "name": "Enjin Coin", + "decimals": 18, + "symbol": "ENJ" + }, + { + "address": "0x467Bccd9d29f223BcE8043b84E8C8B282827790F", + "name": "Telcoin", + "decimals": 2, + "symbol": "TEL" + }, + { + "address": "0xC12D1c73eE7DC3615BA4e37E4ABFdbDDFA38907E", + "name": "KickToken", + "decimals": 8, + "symbol": "KICK" + } + ] +} diff --git a/mock/ext-api-data/eth-api_transactions__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json b/mock/ext-api-data/eth-api_transactions__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json new file mode 100644 index 000000000..6b0295a70 --- /dev/null +++ b/mock/ext-api-data/eth-api_transactions__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json @@ -0,0 +1,58 @@ +{ + "docs": [ + { + "operations": [], + "contract": null, + "_id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", + "blockNumber": 9551915, + "time": 1582624428, + "nonce": 227, + "from": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "to": "0x1717f94202c126ef71d6C562de253Fe95eEbDD5f", + "value": "17635730000000000", + "gas": "21000", + "gasPrice": "4320000000", + "gasUsed": "21000", + "input": "0x", + "error": "", + "id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", + "timeStamp": "1582624428" + }, + { + "operations": [ + { + "transactionId": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3-0", + "contract": { + "address": "0x0d8775f648430679a709e98d2b0cb6250d2887ef", + "symbol": "BAT", + "decimals": 18, + "totalSupply": "1500000000000000000000000000", + "name": "Basic Attention Token", + "updatedAt": "2020-03-23T06:01:25.975Z" + }, + "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", + "to": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "type": "token_transfer", + "value": "400000000000000000", + "id": null + } + ], + "contract": null, + "_id": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", + "blockNumber": 9519169, + "time": 1582189159, + "nonce": 16, + "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", + "to": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "value": "0", + "gas": "51839", + "gasPrice": "11500000000", + "gasUsed": "37028", + "input": "0xa9059cbb0000000000000000000000000875bcab22de3d02402bc38aee4104e1239374a7000000000000000000000000000000000000000000000000058d15e176280000", + "error": "", + "id": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", + "timeStamp": "1582189159" + } + ], + "total": 2 +} \ No newline at end of file diff --git a/mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_tokenBalances.json b/mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_tokenBalances.json new file mode 100644 index 000000000..11ea43845 --- /dev/null +++ b/mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_tokenBalances.json @@ -0,0 +1,38 @@ +{ + "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "balance": "182976771756327797", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 263, + "nonTokenTxs": 243, + "nonce": "231", + "tokens": [ + { + "type": "ERC20", + "name": "Kyber Network Crystal", + "contract": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + "transfers": 13, + "symbol": "KNC", + "decimals": 18, + "balance": "41100" + }, + { + "type": "ERC20", + "name": "BNB", + "contract": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", + "transfers": 4, + "symbol": "BNB", + "decimals": 18, + "balance": "100500" + }, + { + "type": "ERC20", + "name": "BNB", + "contract": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", + "transfers": 4, + "symbol": "BNB", + "decimals": 18, + "balance": "0" + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_txs.json b/mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_txs.json new file mode 100644 index 000000000..38e87a47f --- /dev/null +++ b/mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_txs.json @@ -0,0 +1,97 @@ +{ + "page": 1, + "totalPages": 11, + "itemsOnPage": 25, + "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "balance": "185659745674589722", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 259, + "nonTokenTxs": 240, + "transactions": [ + { + "txid": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", + "vin": [ + { + "n": 0, + "addresses": [ + "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "17635730000000000", + "n": 0, + "addresses": [ + "0x1717f94202c126ef71d6C562de253Fe95eEbDD5f" + ], + "isAddress": true + } + ], + "blockHash": "0x5b8b39099d025a8feeed7575ebff6d0b2508e0542d6279c1b3b4f8b893e74296", + "blockHeight": 9551915, + "confirmations": 231227, + "blockTime": 1582624428, + "value": "17635730000000000", + "fees": "90720000000000", + "ethereumSpecific": { + "status": 1, + "nonce": 227, + "gasLimit": 21000, + "gasUsed": 21000, + "gasPrice": "4320000000" + } + }, + { + "txid": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", + "vin": [ + { + "n": 0, + "addresses": [ + "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8" + ], + "isAddress": true + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "addresses": [ + "0x0D8775F648430679A709E98d2b0Cb6250d2887EF" + ], + "isAddress": true + } + ], + "blockHash": "0x770332c9b4ea42e518f8c5a0178ca5732fd5edfe5e8e011e1362e6598de262d5", + "blockHeight": 9519169, + "confirmations": 263973, + "blockTime": 1582189159, + "value": "0", + "fees": "425822000000000", + "tokenTransfers": [ + { + "type": "ERC20", + "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", + "to": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + "token": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "name": "Basic Attention Token", + "symbol": "BAT", + "decimals": 18, + "value": "400000000000000000" + } + ], + "ethereumSpecific": { + "status": 1, + "nonce": 16, + "gasLimit": 51839, + "gasUsed": 37028, + "gasPrice": "11500000000" + } + } + ], + "nonce": "228", + "tokens": [] +} \ No newline at end of file diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.json b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.json new file mode 100644 index 000000000..55019963b --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","id":257,"result":"0x0000000000000000000000001da022710df5002339274aadee8d58218e9d6ab5"} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.request_json b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.request_json new file mode 100644 index 000000000..9fb2aae12 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.request_json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","method":"eth_call","params":[{"data":"0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047","to":"0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"},"latest"],"id":257} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.json b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.json new file mode 100644 index 000000000..95c58c4b8 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","id":251,"result":"0x000000000000000000000000bd5f5ec7ed5f19b53726344540296c02584a5237"} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.request_json b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.request_json new file mode 100644 index 000000000..234ab5a89 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.request_json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","method":"eth_call","params":[{"data":"0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4","to":"0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"},"latest"],"id":251} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835.json b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835.json new file mode 100644 index 000000000..7e6d9178d --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835.json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","id":249,"result":"0x000000000000000000000000226159d592e2b063810a10ebf6dcbada94ed68b8"} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835.request_json b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835.request_json new file mode 100644 index 000000000..eb0df06e4 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835.request_json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","method":"eth_call","params":[{"data":"0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835","to":"0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"},"latest"],"id":249} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.json b/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.json new file mode 100644 index 000000000..8e3f357e6 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","id":259,"result":"0x0000000000000000000000000c54eead78d555be3cbcd451424f9a27a7843935"} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.request_json b/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.request_json new file mode 100644 index 000000000..a9fda4132 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047.request_json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","method":"eth_call","params":[{"data":"0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047","to":"0x1da022710df5002339274aadee8d58218e9d6ab5"},"latest"],"id":259} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.json b/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.json new file mode 100644 index 000000000..06c0e5496 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","id":253,"result":"0x000000000000000000000000d8a667312d5260f12a306ae7730c754d938da86c"} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.request_json b/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.request_json new file mode 100644 index 000000000..7af97c924 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4.request_json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","method":"eth_call","params":[{"data":"0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4","to":"0xbd5f5ec7ed5f19b53726344540296c02584a5237"},"latest"],"id":253} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c.json b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c.json new file mode 100644 index 000000000..4033b5220 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c.json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","id":258,"result":"0x"} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c.request_json b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c.request_json new file mode 100644 index 000000000..f5ebff997 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c.request_json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","method":"eth_call","params":[{"data":"0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c","to":"0x1da022710df5002339274aadee8d58218e9d6ab5"},"latest"],"id":258} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c.json b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c.json new file mode 100644 index 000000000..46be200fc --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c.json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","id":252,"result":"0x"} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c.request_json b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c.request_json new file mode 100644 index 000000000..cac40fda0 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c.request_json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","method":"eth_call","params":[{"data":"0xf1cb7e06a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4000000000000000000000000000000000000000000000000000000000000003c","to":"0xbd5f5ec7ed5f19b53726344540296c02584a5237"},"latest"],"id":252} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c.json b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c.json new file mode 100644 index 000000000..92a7224b7 --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c.json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","id":328,"result":"0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000"} diff --git a/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c.request_json b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c.request_json new file mode 100644 index 000000000..456e91dcb --- /dev/null +++ b/mock/ext-api-data/eth-rpc__eth_call_data_0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c.request_json @@ -0,0 +1 @@ +{"jsonrpc":"2.0","method":"eth_call","params":[{"data":"0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c","to":"0x226159d592e2b063810a10ebf6dcbada94ed68b8"},"latest"],"id":328} diff --git a/mock/ext-api-data/ethclassic-api_tokens__address_0xa12105efa0663147bddee178f6a741ac15676b79.json b/mock/ext-api-data/ethclassic-api_tokens__address_0xa12105efa0663147bddee178f6a741ac15676b79.json new file mode 100644 index 000000000..b815fdb14 --- /dev/null +++ b/mock/ext-api-data/ethclassic-api_tokens__address_0xa12105efa0663147bddee178f6a741ac15676b79.json @@ -0,0 +1 @@ +{"total":2,"docs":[{"address":"0xCA68fE57A0E9987F940Ebcc65fe5F96E7bC30128","name":"Litecoin Classic Token","decimals":8,"symbol":"LCT"},{"address":"0x2B682bd9d5c31E67a95cbdF0292017C02E51923C","name":"Ether Klown","decimals":6,"symbol":"KLOWN2"}]} \ No newline at end of file diff --git a/mock/ext-api-data/ethclassic-api_transactions__address_0x7d2d0e153026fb428b885d86de50768d4cfeac37.json b/mock/ext-api-data/ethclassic-api_transactions__address_0x7d2d0e153026fb428b885d86de50768d4cfeac37.json new file mode 100644 index 000000000..096e71054 --- /dev/null +++ b/mock/ext-api-data/ethclassic-api_transactions__address_0x7d2d0e153026fb428b885d86de50768d4cfeac37.json @@ -0,0 +1 @@ +{"docs":[{"operations":[],"contract":null,"_id":"0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe","blockNumber":9833329,"time":1582237362,"nonce":7071,"from":"0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9","to":"0x7D2D0E153026fB428B885D86De50768D4cFeaC37","value":"18529160000000000","gas":"21000","gasPrice":"1000000000","gasUsed":"21000","input":"0x","error":"","id":"0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe","timeStamp":"1582237362"},{"operations":[],"contract":null,"_id":"0x524fb5fedace7bee35c165ac7f641d689122cb21390db7f7384507473a5ba058","blockNumber":9804290,"time":1581854371,"nonce":6918,"from":"0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9","to":"0x7D2D0E153026fB428B885D86De50768D4cFeaC37","value":"16208400000000000","gas":"21000","gasPrice":"1000000000","gasUsed":"21000","input":"0x","error":"","id":"0x524fb5fedace7bee35c165ac7f641d689122cb21390db7f7384507473a5ba058","timeStamp":"1581854371"},{"operations":[],"contract":null,"_id":"0xdafbb42223d0896d594b0d71e609bdb0ca88e9366dacb5b75936ea0314f24644","blockNumber":9800797,"time":1581807897,"nonce":6906,"from":"0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9","to":"0x7D2D0E153026fB428B885D86De50768D4cFeaC37","value":"15707220000000000","gas":"21000","gasPrice":"8750000000","gasUsed":"21000","input":"0x","error":"","id":"0xdafbb42223d0896d594b0d71e609bdb0ca88e9366dacb5b75936ea0314f24644","timeStamp":"1581807897"},{"operations":[],"contract":null,"_id":"0x7eae8a772f4cd047cb2fb6e51a97e6ec7330841893356faef9f1d27fc6863a13","blockNumber":9767819,"time":1581371768,"nonce":6760,"from":"0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9","to":"0x7D2D0E153026fB428B885D86De50768D4cFeaC37","value":"12382380000000000","gas":"21000","gasPrice":"1000000000","gasUsed":"21000","input":"0x","error":"","id":"0x7eae8a772f4cd047cb2fb6e51a97e6ec7330841893356faef9f1d27fc6863a13","timeStamp":"1581371768"},{"operations":[],"contract":null,"_id":"0x793030d8fefd7c8eab29b69f273c01be8a3f48dc7a729d492f0a534209a9f56f","blockNumber":9759207,"time":1581259513,"nonce":6725,"from":"0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9","to":"0x7D2D0E153026fB428B885D86De50768D4cFeaC37","value":"12243450000000000","gas":"21000","gasPrice":"1250000000","gasUsed":"21000","input":"0x","error":"","id":"0x793030d8fefd7c8eab29b69f273c01be8a3f48dc7a729d492f0a534209a9f56f","timeStamp":"1581259513"},{"operations":[],"contract":null,"_id":"0x4cd49c1cb015e1b2dbbe84b24028c03df4fd5267590ef8caa8771d84bbab6237","blockNumber":9753262,"time":1581181423,"nonce":6694,"from":"0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9","to":"0x7D2D0E153026fB428B885D86De50768D4cFeaC37","value":"12051340000000000","gas":"21000","gasPrice":"1000000000","gasUsed":"21000","input":"0x","error":"","id":"0x4cd49c1cb015e1b2dbbe84b24028c03df4fd5267590ef8caa8771d84bbab6237","timeStamp":"1581181423"}],"total":6} \ No newline at end of file diff --git a/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0001.json b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0001.json new file mode 100644 index 000000000..8e3369b1e --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0001.json @@ -0,0 +1 @@ +{"public_address":"0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a0001"} \ No newline at end of file diff --git a/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0001.request_json b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0001.request_json new file mode 100644 index 000000000..9d14efd43 --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0001.request_json @@ -0,0 +1,5 @@ +{ + fio_address: 'trust@trustwallet', + token_code: 'ETH', + chain_code: 'ETH' +} diff --git a/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0002.json b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0002.json new file mode 100644 index 000000000..cfe58ca56 --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0002.json @@ -0,0 +1 @@ +{"public_address":"0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a0002"} \ No newline at end of file diff --git a/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0002.request_json b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0002.request_json new file mode 100644 index 000000000..bed84d8a8 --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.0002.request_json @@ -0,0 +1,5 @@ +{ + fio_address: 'name@somefiodomain', + token_code: 'ETH', + chain_code: 'ETH' +} diff --git a/mock/ext-api-data/fio-api_v1_chain_get_pub_address.json b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.json new file mode 100644 index 000000000..337fd29a2 --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.json @@ -0,0 +1 @@ +{"public_address":"0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51"} \ No newline at end of file diff --git a/mock/ext-api-data/fio-api_v1_chain_get_pub_address.request_json b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.request_json new file mode 100644 index 000000000..519b92947 --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_chain_get_pub_address.request_json @@ -0,0 +1 @@ +{fio_address: "trust@trust", token_code: "ETH", chain_code: "ETH"} diff --git a/mock/ext-api-data/fio-api_v1_history_get_actions.0001.json b/mock/ext-api-data/fio-api_v1_history_get_actions.0001.json new file mode 100644 index 000000000..e27154ff8 --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_history_get_actions.0001.json @@ -0,0 +1,1100 @@ +{ + "actions": [ + { + "global_action_seq": 8085061, + "account_action_seq": 180, + "block_num": 7865147, + "block_time": "2020-05-09T13:01:02.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8085061, + "recv_sequence": 75973, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 132 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 3210, + "console": "", + "trx_id": "4224701156c93156bd287df4a2ff61484e00ce7bb1cb65c815e96ef725b4759a", + "block_num": 7865147, + "block_time": "2020-05-09T13:01:02.500", + "producer_block_id": "0078033b7e5ce84f17ac23d33981386f218a4186626108a70a4e712b2f37ea3e", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8143375, + "account_action_seq": 181, + "block_num": 7922745, + "block_time": "2020-05-09T21:01:01.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":208382292046}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8143375, + "recv_sequence": 76058, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 133 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 3832, + "console": "", + "trx_id": "4139ca4a56cef1ea04a751d7b4ce37c195793a1b1b05fa6017db55feb52c3204", + "block_num": 7922745, + "block_time": "2020-05-09T21:01:01.500", + "producer_block_id": "0078e439ac0f97d125d850ab6dfa190c15778ef4b1067e3adf5fbbc47e4baac6", + "account_ram_deltas": [ + { + "account": "fio.treasury", + "delta": -144 + }, + { + "account": "p5fi5ywnitjc", + "delta": -128 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8143379, + "account_action_seq": 182, + "block_num": 7922745, + "block_time": "2020-05-09T21:01:01.500", + "action_trace": { + "receipt": { + "receiver": "gmdncuvoqxfn", + "response": "", + "act_digest": "57cf1dae328832d3ccb2defa00c1f2bfcd494de88d9bed51443e1083d256f450", + "global_sequence": 8143379, + "recv_sequence": 47, + "auth_sequence": [ + [ + "fio.treasury", + 6266 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "gmdncuvoqxfn", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "from": "fio.treasury", + "to": "gmdncuvoqxfn", + "quantity": "208.382292046 FIO", + "memo": "Paying producer from treasury." + }, + "hex_data": "e0afc646dd0ca85b3057b7746b3493644e708d84300000000946494f000000001e506179696e672070726f64756365722066726f6d2074726561737572792e" + }, + "context_free": false, + "elapsed": 11, + "console": "", + "trx_id": "4139ca4a56cef1ea04a751d7b4ce37c195793a1b1b05fa6017db55feb52c3204", + "block_num": 7922745, + "block_time": "2020-05-09T21:01:01.500", + "producer_block_id": "0078e439ac0f97d125d850ab6dfa190c15778ef4b1067e3adf5fbbc47e4baac6", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 3, + "closest_unnotified_ancestor_action_ordinal": 3 + } + }, + { + "global_action_seq": 8201636, + "account_action_seq": 183, + "block_num": 7980333, + "block_time": "2020-05-10T05:01:01.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8201636, + "recv_sequence": 76107, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 134 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 3244, + "console": "", + "trx_id": "7f19f1cb309e871899777c7ff9c17a6874b4cbf33c74983a93e88711c975dff8", + "block_num": 7980333, + "block_time": "2020-05-10T05:01:01.500", + "producer_block_id": "0079c52dd5cf8c7376bdc775fc1200e9f9e1c91607df66179eca3784cb7d48c3", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8259758, + "account_action_seq": 184, + "block_num": 8037933, + "block_time": "2020-05-10T13:01:01.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8259758, + "recv_sequence": 76131, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 135 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 3120, + "console": "", + "trx_id": "bd0e433db980b3c89942e1bcf136375cddf14feb3b407a3eca7510415d2f22c4", + "block_num": 8037933, + "block_time": "2020-05-10T13:01:01.500", + "producer_block_id": "007aa62dd1433e0f3e095b3e5a247a0a54472a8502c7365cf5b0371456e50a6d", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8318046, + "account_action_seq": 185, + "block_num": 8095533, + "block_time": "2020-05-10T21:01:01.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":208379396046}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8318046, + "recv_sequence": 76198, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 136 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 3783, + "console": "", + "trx_id": "783a4ce87c415501967685985a0e9315dd36f415261faa08e76f06cc37bb547c", + "block_num": 8095533, + "block_time": "2020-05-10T21:01:01.500", + "producer_block_id": "007b872de3c104dafd36fb5cd565113c4d61a3ec0b72b357486787e270b2cfb3", + "account_ram_deltas": [ + { + "account": "akfxqn52fx3a", + "delta": -128 + }, + { + "account": "fio.treasury", + "delta": -144 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8318050, + "account_action_seq": 186, + "block_num": 8095533, + "block_time": "2020-05-10T21:01:01.500", + "action_trace": { + "receipt": { + "receiver": "gmdncuvoqxfn", + "response": "", + "act_digest": "1b7603066e70507a0962daa66c534a5a80a370e91fa839687f3e0bac002b3d2f", + "global_sequence": 8318050, + "recv_sequence": 48, + "auth_sequence": [ + [ + "fio.treasury", + 6460 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "gmdncuvoqxfn", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "from": "fio.treasury", + "to": "gmdncuvoqxfn", + "quantity": "208.379396046 FIO", + "memo": "Paying producer from treasury." + }, + "hex_data": "e0afc646dd0ca85b3057b7746b349364ce3f6184300000000946494f000000001e506179696e672070726f64756365722066726f6d2074726561737572792e" + }, + "context_free": false, + "elapsed": 7, + "console": "", + "trx_id": "783a4ce87c415501967685985a0e9315dd36f415261faa08e76f06cc37bb547c", + "block_num": 8095533, + "block_time": "2020-05-10T21:01:01.500", + "producer_block_id": "007b872de3c104dafd36fb5cd565113c4d61a3ec0b72b357486787e270b2cfb3", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 3, + "closest_unnotified_ancestor_action_ordinal": 3 + } + }, + { + "global_action_seq": 8376209, + "account_action_seq": 187, + "block_num": 8153133, + "block_time": "2020-05-11T05:01:02.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8376209, + "recv_sequence": 76232, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 137 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 1915, + "console": "", + "trx_id": "006b36840fcaabe6acca50c4f03e343b8eb6692e2e4a41609213f8d5845d4be9", + "block_num": 8153133, + "block_time": "2020-05-11T05:01:02.000", + "producer_block_id": "007c682d1169d963428ba9ac05f99230b4618251d8c200d158df7af219b8e419", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8434344, + "account_action_seq": 188, + "block_num": 8210732, + "block_time": "2020-05-11T13:01:01.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8434344, + "recv_sequence": 76259, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 138 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 2863, + "console": "", + "trx_id": "159867ae812d839bd273f5147fc08e1eec2d74cfc2f9643d2be95c9c39909cc2", + "block_num": 8210732, + "block_time": "2020-05-11T13:01:01.500", + "producer_block_id": "007d492c5e2c34cfce5c12a6d5d10c4a71a185f1119bd130a12b23786f2f4fb2", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8492674, + "account_action_seq": 189, + "block_num": 8268320, + "block_time": "2020-05-11T21:01:01.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":208378161259}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8492674, + "recv_sequence": 76327, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 139 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 2561, + "console": "", + "trx_id": "cbee2abb5a39c0f4218b60375935c35cb85f7210a6b39327439a134f10f9194e", + "block_num": 8268320, + "block_time": "2020-05-11T21:01:01.500", + "producer_block_id": "007e2a201791b43ea14f07c76aade167046a432476ea8dbe940f0f266e51da01", + "account_ram_deltas": [ + { + "account": "akfxqn52fx3a", + "delta": -128 + }, + { + "account": "fio.treasury", + "delta": -144 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8492678, + "account_action_seq": 190, + "block_num": 8268320, + "block_time": "2020-05-11T21:01:01.500", + "action_trace": { + "receipt": { + "receiver": "gmdncuvoqxfn", + "response": "", + "act_digest": "5c551fda3bffb5289db2114907c8c520519ef3fd2d5149827fcf35e7ab4452a5", + "global_sequence": 8492678, + "recv_sequence": 49, + "auth_sequence": [ + [ + "fio.treasury", + 6648 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "gmdncuvoqxfn", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "from": "fio.treasury", + "to": "gmdncuvoqxfn", + "quantity": "208.378161259 FIO", + "memo": "Paying producer from treasury." + }, + "hex_data": "e0afc646dd0ca85b3057b7746b3493646b684e84300000000946494f000000001e506179696e672070726f64756365722066726f6d2074726561737572792e" + }, + "context_free": false, + "elapsed": 6, + "console": "", + "trx_id": "cbee2abb5a39c0f4218b60375935c35cb85f7210a6b39327439a134f10f9194e", + "block_num": 8268320, + "block_time": "2020-05-11T21:01:01.500", + "producer_block_id": "007e2a201791b43ea14f07c76aade167046a432476ea8dbe940f0f266e51da01", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 3, + "closest_unnotified_ancestor_action_ordinal": 3 + } + }, + { + "global_action_seq": 8550775, + "account_action_seq": 191, + "block_num": 8325920, + "block_time": "2020-05-12T05:01:01.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8550775, + "recv_sequence": 76347, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 140 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 1596, + "console": "", + "trx_id": "18e740da12cdbce1287d18a2678f4a8e63ace3f9743e7f33e11fc629c684ca63", + "block_num": 8325920, + "block_time": "2020-05-12T05:01:01.500", + "producer_block_id": "007f0b20a791a1fb42f07038ddbc4c25f80bef7d6e393932e04d5be1678d3192", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8608936, + "account_action_seq": 192, + "block_num": 8383519, + "block_time": "2020-05-12T13:01:02.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8608936, + "recv_sequence": 76380, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 141 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 2402, + "console": "", + "trx_id": "badf5275adb7c766418b2f5676298a22c2dbef20f35f13d980a7316a205325b2", + "block_num": 8383519, + "block_time": "2020-05-12T13:01:02.000", + "producer_block_id": "007fec1f5ecac875ef78e4034a3684b42edcfe18f774b39ca0478fd995d4a09d", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8667271, + "account_action_seq": 193, + "block_num": 8441119, + "block_time": "2020-05-12T21:01:02.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":209426142191}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8667271, + "recv_sequence": 76454, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 142 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 3145, + "console": "", + "trx_id": "a160133574bd5775dec7fe60ce42542b9a4fdf58fb69525af7ed15a12c23661a", + "block_num": 8441119, + "block_time": "2020-05-12T21:01:02.000", + "producer_block_id": "0080cd1f4b1c6b2a607e5574131b1c94f63f935b6fe73f0a597cc9fb9fdbb3c2", + "account_ram_deltas": [ + { + "account": "fio.treasury", + "delta": -144 + }, + { + "account": "wrcjejslfplp", + "delta": -128 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8667275, + "account_action_seq": 194, + "block_num": 8441119, + "block_time": "2020-05-12T21:01:02.000", + "action_trace": { + "receipt": { + "receiver": "gmdncuvoqxfn", + "response": "", + "act_digest": "082f7056a955ced42388f8d2b9148d90dd73e6696d8cb56102abc69aae902d5e", + "global_sequence": 8667275, + "recv_sequence": 50, + "auth_sequence": [ + [ + "fio.treasury", + 6826 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "gmdncuvoqxfn", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "from": "fio.treasury", + "to": "gmdncuvoqxfn", + "quantity": "209.426142191 FIO", + "memo": "Paying producer from treasury." + }, + "hex_data": "e0afc646dd0ca85b3057b7746b349364ef53c5c2300000000946494f000000001e506179696e672070726f64756365722066726f6d2074726561737572792e" + }, + "context_free": false, + "elapsed": 6, + "console": "", + "trx_id": "a160133574bd5775dec7fe60ce42542b9a4fdf58fb69525af7ed15a12c23661a", + "block_num": 8441119, + "block_time": "2020-05-12T21:01:02.000", + "producer_block_id": "0080cd1f4b1c6b2a607e5574131b1c94f63f935b6fe73f0a597cc9fb9fdbb3c2", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 3, + "closest_unnotified_ancestor_action_ordinal": 3 + } + }, + { + "global_action_seq": 8725478, + "account_action_seq": 195, + "block_num": 8498718, + "block_time": "2020-05-13T05:01:01.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8725478, + "recv_sequence": 76496, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 143 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 1511, + "console": "", + "trx_id": "d81ea2da0f4733805bed6af8f3229d94056f6b341d75f89ce9d2c29f62a8b139", + "block_num": 8498718, + "block_time": "2020-05-13T05:01:01.500", + "producer_block_id": "0081ae1e2015b6fd525449a794cb24724afd0eec80a2fb90f312307ec76773ee", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8783826, + "account_action_seq": 196, + "block_num": 8556319, + "block_time": "2020-05-13T13:01:02.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8783826, + "recv_sequence": 76581, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 144 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 3262, + "console": "", + "trx_id": "7a3939b6e6e7a9a4e02b248a5652a406c3b039651eb3ae7af97360fc0ccb4207", + "block_num": 8556319, + "block_time": "2020-05-13T13:01:02.000", + "producer_block_id": "00828f1f9d548ecad56f7a4d693da6cd5bdd941c70c91e028f0f3119a11daf32", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8842416, + "account_action_seq": 197, + "block_num": 8613919, + "block_time": "2020-05-13T21:01:02.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":209423408688}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8842416, + "recv_sequence": 76714, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 145 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 3535, + "console": "", + "trx_id": "4c846201239987c42d087a6acc0b702b553656a269f0f95e23a5499d3f7f21c0", + "block_num": 8613919, + "block_time": "2020-05-13T21:01:02.000", + "producer_block_id": "0083701f4a7339d51d9e295ebf6fa84d4b7b8fa5b69c55392328b641b8f6b652", + "account_ram_deltas": [ + { + "account": "akfxqn52fx3a", + "delta": -128 + }, + { + "account": "fio.treasury", + "delta": -144 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8842420, + "account_action_seq": 198, + "block_num": 8613919, + "block_time": "2020-05-13T21:01:02.000", + "action_trace": { + "receipt": { + "receiver": "gmdncuvoqxfn", + "response": "", + "act_digest": "b3c0bd3b7c26fbab994d4b9a263d1a85e958546c201e0a89d6d43f4bb3f19fcb", + "global_sequence": 8842420, + "recv_sequence": 51, + "auth_sequence": [ + [ + "fio.treasury", + 7047 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "gmdncuvoqxfn", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "from": "fio.treasury", + "to": "gmdncuvoqxfn", + "quantity": "209.423408688 FIO", + "memo": "Paying producer from treasury." + }, + "hex_data": "e0afc646dd0ca85b3057b7746b349364309e9bc2300000000946494f000000001e506179696e672070726f64756365722066726f6d2074726561737572792e" + }, + "context_free": false, + "elapsed": 5, + "console": "", + "trx_id": "4c846201239987c42d087a6acc0b702b553656a269f0f95e23a5499d3f7f21c0", + "block_num": 8613919, + "block_time": "2020-05-13T21:01:02.000", + "producer_block_id": "0083701f4a7339d51d9e295ebf6fa84d4b7b8fa5b69c55392328b641b8f6b652", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 3, + "closest_unnotified_ancestor_action_ordinal": 3 + } + }, + { + "global_action_seq": 8900745, + "account_action_seq": 199, + "block_num": 8671519, + "block_time": "2020-05-14T05:01:02.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "cd645ad840c51edccb89bf75e1e035f88c4b7a8d2a608bfb262176185b61fc85", + "global_sequence": 8900745, + "recv_sequence": 76795, + "auth_sequence": [ + [ + "gmdncuvoqxfn", + 146 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "gmdncuvoqxfn", + "permission": "fioclaim" + } + ], + "data": { + "fio_address": "maltablockbp@maltablock", + "actor": "gmdncuvoqxfn" + }, + "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3057b7746b349364" + }, + "context_free": false, + "elapsed": 2845, + "console": "", + "trx_id": "afa96e24b429c5b22cc95c6f70452b059f589fe544f9ef4aed9bc58cbe829e97", + "block_num": 8671519, + "block_time": "2020-05-14T05:01:02.000", + "producer_block_id": "0084511f80b3c3529fc78b1813da0d9f2665ac5f563e6cc6cdb1dbe1b095dc1d", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + } + ], + "last_irreversible_block": 8724218 +} \ No newline at end of file diff --git a/mock/ext-api-data/fio-api_v1_history_get_actions.0001.request_json b/mock/ext-api-data/fio-api_v1_history_get_actions.0001.request_json new file mode 100644 index 000000000..3e7f4e4f7 --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_history_get_actions.0001.request_json @@ -0,0 +1,3 @@ +{ + "account_name": "gmdncuvoqxfn" +} \ No newline at end of file diff --git a/mock/ext-api-data/fio-api_v1_history_get_actions.0002.json b/mock/ext-api-data/fio-api_v1_history_get_actions.0002.json new file mode 100644 index 000000000..9e9b5f825 --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_history_get_actions.0002.json @@ -0,0 +1,1029 @@ +{ + "actions": [ + { + "global_action_seq": 8951703, + "account_action_seq": 82966, + "block_num": 8721919, + "block_time": "2020-05-14T12:01:02.000", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "{\"status\": \"OK\",\"amount\":0}", + "act_digest": "74ee42c53faf81069621ed0e2f04aaf6fa08a8955553368fa4a742b8f08839be", + "global_sequence": 8951703, + "recv_sequence": 76835, + "auth_sequence": [ + [ + "akfxqn52fx3a", + 144 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bpclaim", + "authorization": [ + { + "actor": "akfxqn52fx3a", + "permission": "claim" + } + ], + "data": { + "fio_address": "bp@everstake", + "actor": "akfxqn52fx3a" + }, + "hex_data": "0c627040657665727374616b6560465fa24cdb1734" + }, + "context_free": false, + "elapsed": 1955, + "console": "", + "trx_id": "2b8b2b3c99b8ffaff57505fa25289a7cfda33e40ab899e7a9f8d7cea9e33a529", + "block_num": 8721919, + "block_time": "2020-05-14T12:01:02.000", + "producer_block_id": "008515ffc1812cffae3d181369733b03884658e8b718b4c9734b0a62727f3fa6", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 8951704, + "account_action_seq": 82967, + "block_num": 8721919, + "block_time": "2020-05-14T12:01:02.000", + "action_trace": { + "receipt": { + "receiver": "eosio", + "response": "", + "act_digest": "7a3f646478a6b56858310974646a3ccdeed4b24522f5158f725a08c95e804c26", + "global_sequence": 8951704, + "recv_sequence": 8772433, + "auth_sequence": [ + [ + "fio.treasury", + 7127 + ] + ], + "code_sequence": 3, + "abi_sequence": 2 + }, + "receiver": "eosio", + "act": { + "account": "eosio", + "name": "updlbpclaim", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "producer": "akfxqn52fx3a" + }, + "hex_data": "60465fa24cdb1734" + }, + "context_free": false, + "elapsed": 265, + "console": "", + "trx_id": "2b8b2b3c99b8ffaff57505fa25289a7cfda33e40ab899e7a9f8d7cea9e33a529", + "block_num": 8721919, + "block_time": "2020-05-14T12:01:02.000", + "producer_block_id": "008515ffc1812cffae3d181369733b03884658e8b718b4c9734b0a62727f3fa6", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 2, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8952911, + "account_action_seq": 82968, + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "ab8ebb262909897219d717e0bebc0f93e95f67c90ccf6fb4f7ac7e1cca23d091", + "global_sequence": 8952911, + "recv_sequence": 76837, + "auth_sequence": [ + [ + "fio.reqobt", + 762 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "fdtnrwdupdat", + "authorization": [ + { + "actor": "fio.reqobt", + "permission": "active" + } + ], + "data": "80c3c90100000000" + }, + "context_free": false, + "elapsed": 72, + "console": "", + "trx_id": "a5d4f68f7de799655612baff3d74db6f1468fbe819c6f59468d8c4cd80342beb", + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "producer_block_id": "00851aa8133288ec60424e05e1901ff66a15e96cc2bfc8bf6bdcbcc623becfe2", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 3, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8952912, + "account_action_seq": 82969, + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "action_trace": { + "receipt": { + "receiver": "fio.token", + "response": "", + "act_digest": "506b33f30557b821c4e08fd99512c17dba04e5e6222dd0b2a041739747606f71", + "global_sequence": 8952912, + "recv_sequence": 4386, + "auth_sequence": [ + [ + "fio.treasury", + 7128 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.token", + "act": { + "account": "fio.token", + "name": "mintfio", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "to": "fio.treasury", + "amount": 240000000 + }, + "hex_data": "e0afc646dd0ca85b001c4e0e00000000" + }, + "context_free": false, + "elapsed": 82, + "console": "", + "trx_id": "a5d4f68f7de799655612baff3d74db6f1468fbe819c6f59468d8c4cd80342beb", + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "producer_block_id": "00851aa8133288ec60424e05e1901ff66a15e96cc2bfc8bf6bdcbcc623becfe2", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 4, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8952917, + "account_action_seq": 82970, + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "action_trace": { + "receipt": { + "receiver": "fio.tpid", + "response": "", + "act_digest": "829e00f2391396a0af7a6cd1cf62d7d9b93212d47b0efcadd8cbf8bfeae89505", + "global_sequence": 8952917, + "recv_sequence": 885, + "auth_sequence": [ + [ + "fio.treasury", + 7129 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.tpid", + "act": { + "account": "fio.tpid", + "name": "updatebounty", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "amount": 240000000 + }, + "hex_data": "001c4e0e00000000" + }, + "context_free": false, + "elapsed": 53, + "console": "", + "trx_id": "a5d4f68f7de799655612baff3d74db6f1468fbe819c6f59468d8c4cd80342beb", + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "producer_block_id": "00851aa8133288ec60424e05e1901ff66a15e96cc2bfc8bf6bdcbcc623becfe2", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 5, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8952919, + "account_action_seq": 82971, + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "1320ccc32ac047b301aa7a327cdc3815bea933ac691562b72666920144152587", + "global_sequence": 8952919, + "recv_sequence": 76839, + "auth_sequence": [ + [ + "fio.reqobt", + 764 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bprewdupdate", + "authorization": [ + { + "actor": "fio.reqobt", + "permission": "active" + } + ], + "data": "80fb651e00000000" + }, + "context_free": false, + "elapsed": 63, + "console": "", + "trx_id": "a5d4f68f7de799655612baff3d74db6f1468fbe819c6f59468d8c4cd80342beb", + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "producer_block_id": "00851aa8133288ec60424e05e1901ff66a15e96cc2bfc8bf6bdcbcc623becfe2", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 7, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8952910, + "account_action_seq": 82972, + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "9056c596a1ae40734409b7a81e3e793999a639b51b500aac8dc7555516704054", + "global_sequence": 8952910, + "recv_sequence": 76836, + "auth_sequence": [ + [ + "eosio", + 8858043 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "nvqpp5a3qmgh", + "to": "fio.treasury", + "quantity": "0.600000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "d098b4c3945aed9ee0afc646dd0ca85b0046c323000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 20, + "console": "", + "trx_id": "a5d4f68f7de799655612baff3d74db6f1468fbe819c6f59468d8c4cd80342beb", + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "producer_block_id": "00851aa8133288ec60424e05e1901ff66a15e96cc2bfc8bf6bdcbcc623becfe2", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 11, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 8952916, + "account_action_seq": 82973, + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "849eb5345ce7236ee40490bbffe754a8c6ba150f8e55bed1e37164079fd5c8c7", + "global_sequence": 8952916, + "recv_sequence": 76838, + "auth_sequence": [ + [ + "eosio", + 8858047 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "eosio", + "to": "fio.treasury", + "quantity": "0.240000000 FIO", + "memo": "New tokens produced from reserves" + }, + "hex_data": "0000000000ea3055e0afc646dd0ca85b001c4e0e000000000946494f00000000214e657720746f6b656e732070726f64756365642066726f6d207265736572766573" + }, + "context_free": false, + "elapsed": 13, + "console": "", + "trx_id": "a5d4f68f7de799655612baff3d74db6f1468fbe819c6f59468d8c4cd80342beb", + "block_num": 8723112, + "block_time": "2020-05-14T12:10:58.500", + "producer_block_id": "00851aa8133288ec60424e05e1901ff66a15e96cc2bfc8bf6bdcbcc623becfe2", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 15, + "creator_action_ordinal": 13, + "closest_unnotified_ancestor_action_ordinal": 13 + } + }, + { + "global_action_seq": 8953166, + "account_action_seq": 82974, + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "791e180b4f3a4a3ada178be99836ca9733969cae3316307162f534bb7869b6da", + "global_sequence": 8953166, + "recv_sequence": 76841, + "auth_sequence": [ + [ + "fio.token", + 3830 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "fdtnrwdupdat", + "authorization": [ + { + "actor": "fio.token", + "permission": "active" + } + ], + "data": "00e1f50500000000" + }, + "context_free": false, + "elapsed": 118, + "console": "", + "trx_id": "81220b549e832fcff40d7e9a6995eae0ab008bcf5a5814438643b5ae224a9281", + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "producer_block_id": "00851b900c2ef952df5034b123c7c0a2f4754ea45e9386cc6e9a3bcad1b72e77", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 5, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8953167, + "account_action_seq": 82975, + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "action_trace": { + "receipt": { + "receiver": "fio.token", + "response": "", + "act_digest": "fe397612c8c79fcd6ca4b6210d31e2b8fdc9b856d8bbd994bc6963dde6e52028", + "global_sequence": 8953167, + "recv_sequence": 4391, + "auth_sequence": [ + [ + "fio.treasury", + 7130 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.token", + "act": { + "account": "fio.token", + "name": "mintfio", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "to": "fio.treasury", + "amount": 800000000 + }, + "hex_data": "e0afc646dd0ca85b0008af2f00000000" + }, + "context_free": false, + "elapsed": 188, + "console": "", + "trx_id": "81220b549e832fcff40d7e9a6995eae0ab008bcf5a5814438643b5ae224a9281", + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "producer_block_id": "00851b900c2ef952df5034b123c7c0a2f4754ea45e9386cc6e9a3bcad1b72e77", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8953172, + "account_action_seq": 82976, + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "action_trace": { + "receipt": { + "receiver": "fio.tpid", + "response": "", + "act_digest": "1cdbbde4ed1d2950d721038c722d2b1e0712bf845c238d39fdafdbb7e4d976d7", + "global_sequence": 8953172, + "recv_sequence": 887, + "auth_sequence": [ + [ + "fio.treasury", + 7131 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.tpid", + "act": { + "account": "fio.tpid", + "name": "updatebounty", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "amount": 800000000 + }, + "hex_data": "0008af2f00000000" + }, + "context_free": false, + "elapsed": 83, + "console": "", + "trx_id": "81220b549e832fcff40d7e9a6995eae0ab008bcf5a5814438643b5ae224a9281", + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "producer_block_id": "00851b900c2ef952df5034b123c7c0a2f4754ea45e9386cc6e9a3bcad1b72e77", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 7, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8953174, + "account_action_seq": 82977, + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "5d78739015f359116070fbc500329c607e0714e4c1ad46c19799db45fdc3f29d", + "global_sequence": 8953174, + "recv_sequence": 76843, + "auth_sequence": [ + [ + "fio.token", + 3832 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bprewdupdate", + "authorization": [ + { + "actor": "fio.token", + "permission": "active" + } + ], + "data": "00f1536500000000" + }, + "context_free": false, + "elapsed": 133, + "console": "", + "trx_id": "81220b549e832fcff40d7e9a6995eae0ab008bcf5a5814438643b5ae224a9281", + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "producer_block_id": "00851b900c2ef952df5034b123c7c0a2f4754ea45e9386cc6e9a3bcad1b72e77", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 9, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8953165, + "account_action_seq": 82978, + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "ffbff6c9eda3ca64334e03dbbaba2e13185f50027c2105a004e92f9482bec8b0", + "global_sequence": 8953165, + "recv_sequence": 76840, + "auth_sequence": [ + [ + "eosio", + 8858286 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "5p35rb3vhqgp", + "to": "fio.treasury", + "quantity": "2.000000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "50996d7b9c5b462de0afc646dd0ca85b00943577000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 28, + "console": "", + "trx_id": "81220b549e832fcff40d7e9a6995eae0ab008bcf5a5814438643b5ae224a9281", + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "producer_block_id": "00851b900c2ef952df5034b123c7c0a2f4754ea45e9386cc6e9a3bcad1b72e77", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 15, + "creator_action_ordinal": 4, + "closest_unnotified_ancestor_action_ordinal": 4 + } + }, + { + "global_action_seq": 8953171, + "account_action_seq": 82979, + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "86bde9bb7482c4b8eda73331a5aa9805b028fd7837e5c727347fdf05078839ce", + "global_sequence": 8953171, + "recv_sequence": 76842, + "auth_sequence": [ + [ + "eosio", + 8858290 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "eosio", + "to": "fio.treasury", + "quantity": "0.800000000 FIO", + "memo": "New tokens produced from reserves" + }, + "hex_data": "0000000000ea3055e0afc646dd0ca85b0008af2f000000000946494f00000000214e657720746f6b656e732070726f64756365642066726f6d207265736572766573" + }, + "context_free": false, + "elapsed": 27, + "console": "", + "trx_id": "81220b549e832fcff40d7e9a6995eae0ab008bcf5a5814438643b5ae224a9281", + "block_num": 8723344, + "block_time": "2020-05-14T12:12:54.500", + "producer_block_id": "00851b900c2ef952df5034b123c7c0a2f4754ea45e9386cc6e9a3bcad1b72e77", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 19, + "creator_action_ordinal": 17, + "closest_unnotified_ancestor_action_ordinal": 17 + } + }, + { + "global_action_seq": 8953253, + "account_action_seq": 82980, + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "791e180b4f3a4a3ada178be99836ca9733969cae3316307162f534bb7869b6da", + "global_sequence": 8953253, + "recv_sequence": 76845, + "auth_sequence": [ + [ + "fio.token", + 3837 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "fdtnrwdupdat", + "authorization": [ + { + "actor": "fio.token", + "permission": "active" + } + ], + "data": "00e1f50500000000" + }, + "context_free": false, + "elapsed": 132, + "console": "", + "trx_id": "db59cebb03c7b1b27a4223258c5750bdf6619533ffde66d45282f4e4e9d807a5", + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "producer_block_id": "00851bd4b9678b6e93d59da45b9ea3daf473592a698125755f72a06959066aa9", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 5, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8953254, + "account_action_seq": 82981, + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "action_trace": { + "receipt": { + "receiver": "fio.token", + "response": "", + "act_digest": "fe397612c8c79fcd6ca4b6210d31e2b8fdc9b856d8bbd994bc6963dde6e52028", + "global_sequence": 8953254, + "recv_sequence": 4396, + "auth_sequence": [ + [ + "fio.treasury", + 7132 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.token", + "act": { + "account": "fio.token", + "name": "mintfio", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "to": "fio.treasury", + "amount": 800000000 + }, + "hex_data": "e0afc646dd0ca85b0008af2f00000000" + }, + "context_free": false, + "elapsed": 163, + "console": "", + "trx_id": "db59cebb03c7b1b27a4223258c5750bdf6619533ffde66d45282f4e4e9d807a5", + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "producer_block_id": "00851bd4b9678b6e93d59da45b9ea3daf473592a698125755f72a06959066aa9", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8953259, + "account_action_seq": 82982, + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "action_trace": { + "receipt": { + "receiver": "fio.tpid", + "response": "", + "act_digest": "1cdbbde4ed1d2950d721038c722d2b1e0712bf845c238d39fdafdbb7e4d976d7", + "global_sequence": 8953259, + "recv_sequence": 889, + "auth_sequence": [ + [ + "fio.treasury", + 7133 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.tpid", + "act": { + "account": "fio.tpid", + "name": "updatebounty", + "authorization": [ + { + "actor": "fio.treasury", + "permission": "active" + } + ], + "data": { + "amount": 800000000 + }, + "hex_data": "0008af2f00000000" + }, + "context_free": false, + "elapsed": 48, + "console": "", + "trx_id": "db59cebb03c7b1b27a4223258c5750bdf6619533ffde66d45282f4e4e9d807a5", + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "producer_block_id": "00851bd4b9678b6e93d59da45b9ea3daf473592a698125755f72a06959066aa9", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 7, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8953261, + "account_action_seq": 82983, + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "5d78739015f359116070fbc500329c607e0714e4c1ad46c19799db45fdc3f29d", + "global_sequence": 8953261, + "recv_sequence": 76847, + "auth_sequence": [ + [ + "fio.token", + 3839 + ] + ], + "code_sequence": 2, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.treasury", + "name": "bprewdupdate", + "authorization": [ + { + "actor": "fio.token", + "permission": "active" + } + ], + "data": "00f1536500000000" + }, + "context_free": false, + "elapsed": 62, + "console": "", + "trx_id": "db59cebb03c7b1b27a4223258c5750bdf6619533ffde66d45282f4e4e9d807a5", + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "producer_block_id": "00851bd4b9678b6e93d59da45b9ea3daf473592a698125755f72a06959066aa9", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 9, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 8953252, + "account_action_seq": 82984, + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "7c4342041fc654cd686584243a81e5b535d49fa448435e9882348ab1778f8da2", + "global_sequence": 8953252, + "recv_sequence": 76844, + "auth_sequence": [ + [ + "eosio", + 8858362 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "nvqpp5a3qmgh", + "to": "fio.treasury", + "quantity": "2.000000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "d098b4c3945aed9ee0afc646dd0ca85b00943577000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 39, + "console": "", + "trx_id": "db59cebb03c7b1b27a4223258c5750bdf6619533ffde66d45282f4e4e9d807a5", + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "producer_block_id": "00851bd4b9678b6e93d59da45b9ea3daf473592a698125755f72a06959066aa9", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 15, + "creator_action_ordinal": 4, + "closest_unnotified_ancestor_action_ordinal": 4 + } + }, + { + "global_action_seq": 8953258, + "account_action_seq": 82985, + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "action_trace": { + "receipt": { + "receiver": "fio.treasury", + "response": "", + "act_digest": "86bde9bb7482c4b8eda73331a5aa9805b028fd7837e5c727347fdf05078839ce", + "global_sequence": 8953258, + "recv_sequence": 76846, + "auth_sequence": [ + [ + "eosio", + 8858366 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.treasury", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "eosio", + "to": "fio.treasury", + "quantity": "0.800000000 FIO", + "memo": "New tokens produced from reserves" + }, + "hex_data": "0000000000ea3055e0afc646dd0ca85b0008af2f000000000946494f00000000214e657720746f6b656e732070726f64756365642066726f6d207265736572766573" + }, + "context_free": false, + "elapsed": 14, + "console": "", + "trx_id": "db59cebb03c7b1b27a4223258c5750bdf6619533ffde66d45282f4e4e9d807a5", + "block_num": 8723412, + "block_time": "2020-05-14T12:13:28.500", + "producer_block_id": "00851bd4b9678b6e93d59da45b9ea3daf473592a698125755f72a06959066aa9", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 19, + "creator_action_ordinal": 17, + "closest_unnotified_ancestor_action_ordinal": 17 + } + } + ], + "last_irreversible_block": 8724218 +} \ No newline at end of file diff --git a/mock/ext-api-data/fio-api_v1_history_get_actions.0002.request_json b/mock/ext-api-data/fio-api_v1_history_get_actions.0002.request_json new file mode 100644 index 000000000..6ad980f4e --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_history_get_actions.0002.request_json @@ -0,0 +1,3 @@ +{ + "account_name": "fio.treasury" +} \ No newline at end of file diff --git a/mock/ext-api-data/fio-api_v1_history_get_actions.json b/mock/ext-api-data/fio-api_v1_history_get_actions.json new file mode 100644 index 000000000..7ef9eb72d --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_history_get_actions.json @@ -0,0 +1,547 @@ +{ + "actions": [ + { + "global_action_seq": 507847, + "account_action_seq": 0, + "block_num": 358672, + "block_time": "2020-03-27T01:54:16.000", + "action_trace": { + "receipt": { + "receiver": "fio.address", + "response": "{\"status\": \"OK\",\"expiration\":\"2021-03-27T01:54:16\",\"fee_collected\":800000000000}", + "act_digest": "bb4962851e0ddc035f392123fd5aba50a0cc054f77afa9326905a9140d4fce58", + "global_sequence": 507847, + "recv_sequence": 34022, + "auth_sequence": [ + [ + "f5axfpgffiqz", + 122 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.address", + "act": { + "account": "fio.address", + "name": "regdomain", + "authorization": [ + { + "actor": "f5axfpgffiqz", + "permission": "active" + } + ], + "data": { + "fio_domain": "eosph", + "owner_fio_public_key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "max_fee": 800000000000, + "actor": "f5axfpgffiqz", + "tpid": "" + }, + "hex_data": "05656f7370683546494f375133586651326f634750317a5973743653667835717273695a383635437538536f326174727562394a4e3934736f3767740040b743ba000000f0ad5b8bd5d54d5900" + }, + "context_free": false, + "elapsed": 3164, + "console": "", + "trx_id": "6691d467499747b038c22a7eef5dbbea496439977a695949b62211753b70f9ef", + "block_num": 358672, + "block_time": "2020-03-27T01:54:16.000", + "producer_block_id": "000579108da2a1d46aeee860cdcee085554a7b5bd773cf14b5d4ae625541b3af", + "account_ram_deltas": [ + { + "account": "f5axfpgffiqz", + "delta": 559 + }, + { + "account": "fio.address", + "delta": 334 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 507848, + "account_action_seq": 1, + "block_num": 358672, + "block_time": "2020-03-27T01:54:16.000", + "action_trace": { + "receipt": { + "receiver": "eosio", + "response": "", + "act_digest": "9b9ca6fbd24dde59d084a1ef4b3291841877f9ab8dee970e53a62df5e50bc80b", + "global_sequence": 507848, + "recv_sequence": 402228, + "auth_sequence": [ + [ + "fio.address", + 72512 + ] + ], + "code_sequence": 2, + "abi_sequence": 2 + }, + "receiver": "eosio", + "act": { + "account": "eosio", + "name": "newaccount", + "authorization": [ + { + "actor": "fio.address", + "permission": "active" + } + ], + "data": { + "creator": "fio.address", + "name": "ezsmbcy2opod", + "owner": { + "threshold": 1, + "keys": [ + { + "key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "active": { + "threshold": 1, + "keys": [ + { + "key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + } + }, + "hex_data": "003056372503a85b9068a5c2a323f157010000000100034a7ff8128788fe6294353420e9143e3cc20dda7b6333bd433688218b58abe25601000000010000000100034a7ff8128788fe6294353420e9143e3cc20dda7b6333bd433688218b58abe25601000000" + }, + "context_free": false, + "elapsed": 275, + "console": "", + "trx_id": "6691d467499747b038c22a7eef5dbbea496439977a695949b62211753b70f9ef", + "block_num": 358672, + "block_time": "2020-03-27T01:54:16.000", + "producer_block_id": "000579108da2a1d46aeee860cdcee085554a7b5bd773cf14b5d4ae625541b3af", + "account_ram_deltas": [ + { + "account": "ezsmbcy2opod", + "delta": 2996 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 2, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 507872, + "account_action_seq": 2, + "block_num": 358689, + "block_time": "2020-03-27T01:54:24.500", + "action_trace": { + "receipt": { + "receiver": "fio.token", + "response": "{\"status\": \"OK\",\"fee_collected\":2000000000}", + "act_digest": "6ef1d997fd449b6fefb8df19401c71425d366a24aab4613ca2059478fef7915f", + "global_sequence": 507872, + "recv_sequence": 656, + "auth_sequence": [ + [ + "f5axfpgffiqz", + 123 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.token", + "act": { + "account": "fio.token", + "name": "trnsfiopubky", + "authorization": [ + { + "actor": "f5axfpgffiqz", + "permission": "active" + } + ], + "data": { + "payee_public_key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "amount": 700000000000, + "max_fee": 2000000000, + "actor": "f5axfpgffiqz", + "tpid": "" + }, + "hex_data": "3546494f375133586651326f634750317a5973743653667835717273695a383635437538536f326174727562394a4e3934736f376774005840fba20000000094357700000000f0ad5b8bd5d54d5900" + }, + "context_free": false, + "elapsed": 2898, + "console": "", + "trx_id": "2e0a7dc3640768e1d644cee871734dd2efa23e65a54c438c1ba03801d7386fb7", + "block_num": 358689, + "block_time": "2020-03-27T01:54:24.500", + "producer_block_id": "00057921b2a5f55fba29f7f08cd49dd095a18f0de2e4e06ba0833ca771ad699b", + "account_ram_deltas": [ + { + "account": "f5axfpgffiqz", + "delta": 240 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 507873, + "account_action_seq": 3, + "block_num": 358689, + "block_time": "2020-03-27T01:54:24.500", + "action_trace": { + "receipt": { + "receiver": "f5axfpgffiqz", + "response": "{\"status\": \"OK\",\"fee_collected\":2000000000}", + "act_digest": "6ef1d997fd449b6fefb8df19401c71425d366a24aab4613ca2059478fef7915f", + "global_sequence": 507873, + "recv_sequence": 98, + "auth_sequence": [ + [ + "f5axfpgffiqz", + 124 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "f5axfpgffiqz", + "act": { + "account": "fio.token", + "name": "trnsfiopubky", + "authorization": [ + { + "actor": "f5axfpgffiqz", + "permission": "active" + } + ], + "data": { + "payee_public_key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "amount": 700000000000, + "max_fee": 2000000000, + "actor": "f5axfpgffiqz", + "tpid": "" + }, + "hex_data": "3546494f375133586651326f634750317a5973743653667835717273695a383635437538536f326174727562394a4e3934736f376774005840fba20000000094357700000000f0ad5b8bd5d54d5900" + }, + "context_free": false, + "elapsed": 5, + "console": "", + "trx_id": "2e0a7dc3640768e1d644cee871734dd2efa23e65a54c438c1ba03801d7386fb7", + "block_num": 358689, + "block_time": "2020-03-27T01:54:24.500", + "producer_block_id": "00057921b2a5f55fba29f7f08cd49dd095a18f0de2e4e06ba0833ca771ad699b", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 5, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 507874, + "account_action_seq": 4, + "block_num": 358689, + "block_time": "2020-03-27T01:54:24.500", + "action_trace": { + "receipt": { + "receiver": "ezsmbcy2opod", + "response": "{\"status\": \"OK\",\"fee_collected\":2000000000}", + "act_digest": "6ef1d997fd449b6fefb8df19401c71425d366a24aab4613ca2059478fef7915f", + "global_sequence": 507874, + "recv_sequence": 1, + "auth_sequence": [ + [ + "f5axfpgffiqz", + 125 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "ezsmbcy2opod", + "act": { + "account": "fio.token", + "name": "trnsfiopubky", + "authorization": [ + { + "actor": "f5axfpgffiqz", + "permission": "active" + } + ], + "data": { + "payee_public_key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "amount": 700000000000, + "max_fee": 2000000000, + "actor": "f5axfpgffiqz", + "tpid": "" + }, + "hex_data": "3546494f375133586651326f634750317a5973743653667835717273695a383635437538536f326174727562394a4e3934736f376774005840fba20000000094357700000000f0ad5b8bd5d54d5900" + }, + "context_free": false, + "elapsed": 4, + "console": "", + "trx_id": "2e0a7dc3640768e1d644cee871734dd2efa23e65a54c438c1ba03801d7386fb7", + "block_num": 358689, + "block_time": "2020-03-27T01:54:24.500", + "producer_block_id": "00057921b2a5f55fba29f7f08cd49dd095a18f0de2e4e06ba0833ca771ad699b", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 1, + "closest_unnotified_ancestor_action_ordinal": 1 + } + }, + { + "global_action_seq": 508968, + "account_action_seq": 5, + "block_num": 359762, + "block_time": "2020-03-27T02:03:21.000", + "action_trace": { + "receipt": { + "receiver": "fio.address", + "response": "{\"status\": \"OK\",\"expiration\":\"2021-03-27T02:03:21\",\"fee_collected\":40000000000}", + "act_digest": "e054494384148e58122a10c3398d9e01a09a79cd6c22da0203653906afd79b3b", + "global_sequence": 508968, + "recv_sequence": 34025, + "auth_sequence": [ + [ + "ezsmbcy2opod", + 1 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "fio.address", + "act": { + "account": "fio.address", + "name": "regaddress", + "authorization": [ + { + "actor": "ezsmbcy2opod", + "permission": "active" + } + ], + "data": { + "fio_address": "bp@eosph", + "owner_fio_public_key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", + "max_fee": 40000000000, + "actor": "ezsmbcy2opod", + "tpid": "" + }, + "hex_data": "08627040656f7370683546494f375133586651326f634750317a5973743653667835717273695a383635437538536f326174727562394a4e3934736f37677400902f50090000009068a5c2a323f15700" + }, + "context_free": false, + "elapsed": 4624, + "console": "", + "trx_id": "b7dd60839ccce11cd175fce6816da04bbce9b70825661005d2ea5d3572408c04", + "block_num": 359762, + "block_time": "2020-03-27T02:03:21.000", + "producer_block_id": "00057d5209ad0141445b3ee2eb1ba7265ab4c7093f7bc4c2142e2eac4c8e5d10", + "account_ram_deltas": [ + { + "account": "ezsmbcy2opod", + "delta": 798 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 508970, + "account_action_seq": 6, + "block_num": 359762, + "block_time": "2020-03-27T02:03:21.000", + "action_trace": { + "receipt": { + "receiver": "ezsmbcy2opod", + "response": "", + "act_digest": "e6774ab921eabe540049667756efb5567b83b291b8a21c5bec81c8b5dc98c366", + "global_sequence": 508970, + "recv_sequence": 2, + "auth_sequence": [ + [ + "eosio", + 430085 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "ezsmbcy2opod", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "ezsmbcy2opod", + "to": "fio.treasury", + "quantity": "40.000000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "9068a5c2a323f157e0afc646dd0ca85b00902f50090000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 4, + "console": "", + "trx_id": "b7dd60839ccce11cd175fce6816da04bbce9b70825661005d2ea5d3572408c04", + "block_num": 359762, + "block_time": "2020-03-27T02:03:21.000", + "producer_block_id": "00057d5209ad0141445b3ee2eb1ba7265ab4c7093f7bc4c2142e2eac4c8e5d10", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + }, + { + "global_action_seq": 510503, + "account_action_seq": 7, + "block_num": 361281, + "block_time": "2020-03-27T02:16:00.500", + "action_trace": { + "receipt": { + "receiver": "eosio", + "response": "{\"status\": \"OK\",\"fee_collected\":200000000000}", + "act_digest": "52b1631c84896baaebd4b81a80c2cfab4f9741e0323d2845d1b3df5683ad7c3c", + "global_sequence": 510503, + "recv_sequence": 404854, + "auth_sequence": [ + [ + "ezsmbcy2opod", + 2 + ] + ], + "code_sequence": 2, + "abi_sequence": 2 + }, + "receiver": "eosio", + "act": { + "account": "eosio", + "name": "regproducer", + "authorization": [ + { + "actor": "ezsmbcy2opod", + "permission": "active" + } + ], + "data": { + "fio_address": "bp@eosph", + "fio_pub_key": "FIO5hZB8REVEirigba4N7TKa67MYm4HFwtiKz6GZJ2eRi5Paxwixz", + "url": "https://www.eosph.io", + "location": 10, + "actor": "ezsmbcy2opod", + "max_fee": 400000000000 + }, + "hex_data": "08627040656f7370683546494f35685a423852455645697269676261344e37544b6136374d596d3448467774694b7a36475a4a32655269355061787769787a1468747470733a2f2f7777772e656f7370682e696f0a009068a5c2a323f15700a0db215d000000" + }, + "context_free": false, + "elapsed": 2888, + "console": "", + "trx_id": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8", + "block_num": 361281, + "block_time": "2020-03-27T02:16:00.500", + "producer_block_id": "00058341700331f78adea1eec39e7150b743f171c9fd9dfff8ea7310f5e6b515", + "account_ram_deltas": [ + { + "account": "ezsmbcy2opod", + "delta": 635 + } + ], + "except": null, + "error_code": null, + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0 + } + }, + { + "global_action_seq": 510505, + "account_action_seq": 8, + "block_num": 361281, + "block_time": "2020-03-27T02:16:00.500", + "action_trace": { + "receipt": { + "receiver": "ezsmbcy2opod", + "response": "", + "act_digest": "a8dd1a5cfe8db5fb3ca38eed9e348acd73150d88211f93e0d37e332289fe76a3", + "global_sequence": 510505, + "recv_sequence": 3, + "auth_sequence": [ + [ + "eosio", + 431614 + ] + ], + "code_sequence": 1, + "abi_sequence": 1 + }, + "receiver": "ezsmbcy2opod", + "act": { + "account": "fio.token", + "name": "transfer", + "authorization": [ + { + "actor": "eosio", + "permission": "active" + } + ], + "data": { + "from": "ezsmbcy2opod", + "to": "fio.treasury", + "quantity": "200.000000000 FIO", + "memo": "FIO API fees. Thank you." + }, + "hex_data": "9068a5c2a323f157e0afc646dd0ca85b00d0ed902e0000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" + }, + "context_free": false, + "elapsed": 4, + "console": "", + "trx_id": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8", + "block_num": 361281, + "block_time": "2020-03-27T02:16:00.500", + "producer_block_id": "00058341700331f78adea1eec39e7150b743f171c9fd9dfff8ea7310f5e6b515", + "account_ram_deltas": [], + "except": null, + "error_code": null, + "action_ordinal": 6, + "creator_action_ordinal": 2, + "closest_unnotified_ancestor_action_ordinal": 2 + } + } + ], + "last_irreversible_block": 8724206 +} \ No newline at end of file diff --git a/mock/ext-api-data/fio-api_v1_history_get_actions.request_json b/mock/ext-api-data/fio-api_v1_history_get_actions.request_json new file mode 100644 index 000000000..3b372252b --- /dev/null +++ b/mock/ext-api-data/fio-api_v1_history_get_actions.request_json @@ -0,0 +1,3 @@ +{ + "account_name": "ezsmbcy2opod" +} \ No newline at end of file diff --git a/mock/ext-api-data/gochain-api_tokens__address_0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628.json b/mock/ext-api-data/gochain-api_tokens__address_0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628.json new file mode 100644 index 000000000..5ab72457f --- /dev/null +++ b/mock/ext-api-data/gochain-api_tokens__address_0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628.json @@ -0,0 +1 @@ +{"total":1,"docs":[{"address":"0x5f16Fa0B5c9d779a3C8d46859a27973Ff3511188","name":"pukkamex","decimals":18,"symbol":"PUX"}]} \ No newline at end of file diff --git a/mock/ext-api-data/gochain-api_transactions__address_0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896.json b/mock/ext-api-data/gochain-api_transactions__address_0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896.json new file mode 100644 index 000000000..6553ba4be --- /dev/null +++ b/mock/ext-api-data/gochain-api_transactions__address_0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896.json @@ -0,0 +1 @@ +{"docs":[{"operations":[],"contract":null,"_id":"0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7","blockNumber":10070535,"time":1576793173,"nonce":6,"from":"0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896","to":"0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3","value":"860000000000000000000000","gas":"90000","gasPrice":"2000000000","gasUsed":"21000","input":"0x","error":"","id":"0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7","timeStamp":"1576793173"},{"operations":[],"contract":null,"_id":"0x472c94385a46072713bb2bf3503fc1610135a70e415046bf61a937789c205f4c","blockNumber":10070520,"time":1576793098,"nonce":5,"from":"0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896","to":"0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3","value":"800000000000000000000","gas":"90000","gasPrice":"2000000000","gasUsed":"21000","input":"0x","error":"","id":"0x472c94385a46072713bb2bf3503fc1610135a70e415046bf61a937789c205f4c","timeStamp":"1576793098"},{"operations":[],"contract":null,"_id":"0x2b40299606beff9a6986b7ea20292e218aab27a40e423549124a3640423a9cdc","blockNumber":10070507,"time":1576793033,"nonce":4,"from":"0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896","to":"0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3","value":"1000000000000000000","gas":"90000","gasPrice":"2000000000","gasUsed":"21000","input":"0x","error":"","id":"0x2b40299606beff9a6986b7ea20292e218aab27a40e423549124a3640423a9cdc","timeStamp":"1576793033"},{"operations":[],"contract":null,"_id":"0xc1589183bcf01960b07bae9dbb8a43df18a287a663570f8d2dfdfc22fdd2768f","blockNumber":8201186,"nonce":3,"from":"0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896","to":"0xE12d1FD4B38bd9a162650d35FeC83d5105aD4b41","value":"1119287000000000000000000","gas":"90000","gasPrice":"2000000000","gasUsed":"21000","input":"0x","error":"","time":1567446425,"id":"0xc1589183bcf01960b07bae9dbb8a43df18a287a663570f8d2dfdfc22fdd2768f","timeStamp":"1567446425"},{"operations":[],"contract":null,"_id":"0x582feee80b66486254fc83d7aab9f313e7e6e0625ce5edd2b6a76f2d7b66a91a","blockNumber":5007262,"nonce":2,"from":"0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896","to":"0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3","value":"1843321000000000000000000","gas":"90000","gasPrice":"2000000000","gasUsed":"21000","input":"0x","error":"","time":1551472504,"id":"0x582feee80b66486254fc83d7aab9f313e7e6e0625ce5edd2b6a76f2d7b66a91a","timeStamp":"1551472504"}],"total":5} \ No newline at end of file diff --git a/mock/ext-api-data/groestlcoin-api_v2_address_33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj__details_txs.json b/mock/ext-api-data/groestlcoin-api_v2_address_33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj__details_txs.json new file mode 100644 index 000000000..043aff2fa --- /dev/null +++ b/mock/ext-api-data/groestlcoin-api_v2_address_33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj__details_txs.json @@ -0,0 +1,110 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj", + "balance": "0", + "totalReceived": "5951153060", + "totalSent": "5951153060", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 2, + "transactions": [ + { + "txid": "2640aa5de0c9603da1c0d9c16b2fd3fa0a17b1472c3aa02559d3ef5e1defceb5", + "version": 2, + "lockTime": 2959295, + "vin": [ + { + "txid": "d8e0d23dedc2c89e9de317e7a54bdc3d26f514918a9360aa04e271c4d8074c28", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" + ], + "isAddress": true, + "value": "5951153060", + "hex": "160014d6c589125f084df1e3286fcd55446b64dc7de130" + } + ], + "vout": [ + { + "value": "1151149700", + "n": 0, + "spent": true, + "hex": "a91436d64490426cc347a50bdd3f8db2ef20d62949f587", + "addresses": [ + "36gy6VVstfso35mS89pBg1PiUcYY3Gesar" + ], + "isAddress": true + }, + { + "value": "4800000000", + "n": 1, + "spent": true, + "hex": "76a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac", + "addresses": [ + "FtCkFSrwrgiJzjQzGRZvjHzrmHp4HJeGYm" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000a79428395294255704ed877847d93c6d36108dc8184b71c1f0a", + "blockHeight": 2959365, + "confirmations": 126518, + "blockTime": 1581386699, + "value": "5951149700", + "valueIn": "5951153060", + "fees": "3360", + "hex": "02000000000101284c07d8c471e204aa60938a9114f5263ddc4ba5e717e39d9ec8c2ed3dd2e0d80000000017160014d6c589125f084df1e3286fcd55446b64dc7de130feffffff0284269d440000000017a91436d64490426cc347a50bdd3f8db2ef20d62949f58700301a1e010000001976a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac02473044022034f3f2ab2d021a27ba999aebb40016f921433c39149d6908fe1e96d914c5c96402203d5d12127f64a01429775090abb445b5af2ec90803372c92499a35e12e229adb0121033ca60a0478fee5583e52c3b85c4dacb81faa9c4a10ad8b4f574c1b050f814463bf272d00" + }, + { + "txid": "d8e0d23dedc2c89e9de317e7a54bdc3d26f514918a9360aa04e271c4d8074c28", + "version": 2, + "lockTime": 2959360, + "vin": [ + { + "txid": "2ed852f7881270ec108c86482d609f818ee21ae07033796fb77cb8e52fa86ccd", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "Fg4WGddhNYayAF3mTPDNCFCEqrXydAd6Vu" + ], + "isAddress": true, + "value": "29751157520", + "hex": "47304402201fe0aff8dd5c35be49f824216adb51d0749878dc2d759d0dd6d4ed6612ca09cd02203ad7d2b2eaa52f341f325934cca2c2758ac4c4b7b8bc279e7748d48ab98b484901210246e7e23df8acf0a305b94009d9b60eca7230ce747493201a9574f7ccb03775e9" + } + ], + "vout": [ + { + "value": "5951153060", + "n": 0, + "spent": true, + "hex": "a914146081496e97dbb864af7df601184f8ec3624aa787", + "addresses": [ + "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" + ], + "isAddress": true + }, + { + "value": "23800000000", + "n": 1, + "spent": true, + "hex": "76a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac", + "addresses": [ + "FtCkFSrwrgiJzjQzGRZvjHzrmHp4HJeGYm" + ], + "isAddress": true + } + ], + "blockHash": "0000000000000a79428395294255704ed877847d93c6d36108dc8184b71c1f0a", + "blockHeight": 2959365, + "confirmations": 126518, + "blockTime": 1581386699, + "value": "29751153060", + "valueIn": "29751157520", + "fees": "4460", + "hex": "0200000001cd6ca82fe5b87cb76f793370e01ae28e819f602d48868c10ec701288f752d82e000000006a47304402201fe0aff8dd5c35be49f824216adb51d0749878dc2d759d0dd6d4ed6612ca09cd02203ad7d2b2eaa52f341f325934cca2c2758ac4c4b7b8bc279e7748d48ab98b484901210246e7e23df8acf0a305b94009d9b60eca7230ce747493201a9574f7ccb03775e9feffffff02a463b7620100000017a914146081496e97dbb864af7df601184f8ec3624aa787002e978a050000001976a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac00282d00" + } + ] +} diff --git a/mock/ext-api-data/groestlcoin-api_v2_xpub_zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf__details_txs.json b/mock/ext-api-data/groestlcoin-api_v2_xpub_zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf__details_txs.json new file mode 100644 index 000000000..05a25d50c --- /dev/null +++ b/mock/ext-api-data/groestlcoin-api_v2_xpub_zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":10,"itemsOnPage":10,"address":"zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf","balance":"412844353","totalReceived":"289739972697","totalSent":"289327128344","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":98,"transactions":[{"txid":"686c651223b937b1223560a60631ad79ad17351c88bba67cad8ea0c95fccbb83","version":1,"vin":[{"txid":"1e3362ef26063cae601362721fcde1c0e856b7d81abc9e541ba38a0b15330689","sequence":2147483644,"n":0,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"100000000"},{"txid":"1e3362ef26063cae601362721fcde1c0e856b7d81abc9e541ba38a0b15330689","vout":1,"sequence":2147483645,"n":1,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"212864353"},{"txid":"dd7780ee2529f7030153737c8ee2a16ef32817cbd63b6aba8553c4ccbeac368d","sequence":2147483646,"n":2,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"100000000"}],"vout":[{"value":"10000000","n":0,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true},{"value":"402844353","n":1,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true}],"blockHash":"00000000000003a48c30ddfaa9c875b902e8372c448413ee65dba418601a5b7e","blockHeight":2998112,"confirmations":98914,"blockTime":1583831414,"value":"412844353","valueIn":"412864353","fees":"20000","hex":"01000000000103890633150b8aa31b549ebc1ad8b756e8c0e1cd1f72621360ae3c0626ef62331e0000000000fcffff7f890633150b8aa31b549ebc1ad8b756e8c0e1cd1f72621360ae3c0626ef62331e0100000000fdffff7f8d36acbeccc45385ba6a3bd6cb1728f36ea1e28e7c73530103f72925ee8077dd0000000000feffff7f028096980000000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395c1ea021800000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb423950247304402201b4acd75cb1186fba1405bd604a2e24a960d94a39e14316f4e6ef5289808e4c90220569d652a91ecc149d543d7aab0653a646ce60d8e3bed053d421907432bd7c9bd012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b285024730440220426733a0a12dd1c34142d9814e74987fdbb41438189fb0bbed74ab2cd420a9b4022046dc588c6690b1ecba351b8a981ed3db63df9de95df49d5a8333b087b349b6c3012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b285024730440220291f4932101719b70630233d53503854f456a0a944453a6105f4e2b95fde526b0220617d4dd0b4dd12e8917d15f80dadf617ec584fe650a31ca8f07f4d6869256549012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000"},{"txid":"1e3362ef26063cae601362721fcde1c0e856b7d81abc9e541ba38a0b15330689","version":1,"vin":[{"txid":"dd7780ee2529f7030153737c8ee2a16ef32817cbd63b6aba8553c4ccbeac368d","vout":1,"n":0,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"312884353"}],"vout":[{"value":"100000000","n":0,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true},{"value":"212864353","n":1,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true}],"blockHash":"000000000000034560a3a07b6498c9b937da914a4f683d1575197a02c4b69a83","blockHeight":2989928,"confirmations":107098,"blockTime":1583315379,"value":"312864353","valueIn":"312884353","fees":"20000","hex":"010000000001018d36acbeccc45385ba6a3bd6cb1728f36ea1e28e7c73530103f72925ee8077dd0100000000000000000200e1f50500000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395610db00c00000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb4239502483045022100e0e7e5484f9d06120f0e3a63471d353d90b65ba63b0fbf640c714608414ffa5d02204556b0c2554bc33ebfb338d806fa1589df1e25afe251c5a7869cfad6e6ef0a61012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000"},{"txid":"dd7780ee2529f7030153737c8ee2a16ef32817cbd63b6aba8553c4ccbeac368d","version":1,"vin":[{"txid":"d9f0569c6eac51a47d2405a09d17c8811a3ef8df212e88d3b6e75f27768b8d83","sequence":2147483645,"n":0,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"100000000"},{"txid":"797b24cb13964ee062c31d171a84f54431e7eb329b89669a8db36a01fa1ada32","sequence":2147483646,"n":1,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"312904345"}],"vout":[{"value":"100000000","n":0,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true},{"value":"312884353","n":1,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true}],"blockHash":"00000000000009f6f6a14d76c13faf60debfd01d068cabf22435b1d24236ecab","blockHeight":2989926,"confirmations":107100,"blockTime":1583314946,"value":"412884353","valueIn":"412904345","fees":"19992","hex":"01000000000102838d8b76275fe7b6d3882e21dff83e1a81c8179da005247da451ac6e9c56f0d90000000000fdffff7f32da1afa016ab38d9a66899b32ebe73144f5841a171dc362e04e9613cb247b790000000000feffff7f0200e1f50500000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395813ca61200000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395024830450221008a65a121c2569ccf2d0c030ac2a30ff4580586b146fe85ce81c7137fd4b2c7a70220613166d4734ebbbc4011a433571088395c6ce3002779021988e58113880029b2012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28502483045022100f5ca4d53375a62b0945a31ccb6ac736581d088e78a7f9a2fcef823950ac5cc1302204ae591f46de9ac64412a319c91fcd04b42378fd8be7bef21359a61ed3802a2df012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000"},{"txid":"797b24cb13964ee062c31d171a84f54431e7eb329b89669a8db36a01fa1ada32","version":1,"vin":[{"txid":"25fad1c20e0618ebce0459c69abf6e9c892c07e38a0825568f74ab9cc1ffc629","vout":1,"n":0,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"10000"},{"txid":"95b6af107a45472754a76939acfc5ce4e324dcd3485630b9aa9fc9b9fcfb7ca5","n":1,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"10000"},{"txid":"6d7b5636e34cf5c43e545aeb6b2cd0ea7dbe855167d2f531b891d9e73bbbb161","vout":1,"n":2,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"10000"},{"txid":"c9dc7ce72e9db78c86f9223e28b4b1b822a8f30fb71378e28cc2f49bdb8873de","vout":1,"n":3,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"10000"},{"txid":"be861703ed533e39310b5e84bf45de3c6d0a009e4afc63d18168bf00f98edde2","vout":1,"n":4,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"60000"},{"txid":"dc4c38bec0e3ded98269cdf9651ed82936d4282bde51bbcc441a718a0f9b44d2","vout":1,"n":5,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"60000"},{"txid":"2afd7b893fade931618b5a20a5879970af9ece772f463227e09d555505f778e4","vout":1,"n":6,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"60000"},{"txid":"fc02e239d2fe65e10e0ac78c8b966140c61c47e66a6e8db67c2a2c26441284d4","vout":1,"n":7,"addresses":["grs1q9lgx0rfcxwra3q76uudtc0z5gsrx74p9eqeezt"],"isAddress":true,"value":"80000"},{"txid":"2afd7b893fade931618b5a20a5879970af9ece772f463227e09d555505f778e4","n":8,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"100000"},{"txid":"be861703ed533e39310b5e84bf45de3c6d0a009e4afc63d18168bf00f98edde2","n":9,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"100000"},{"txid":"8d5198d4dcaa1806cd717adc6117f23fe6a2c54aef6e27e93d99620bf4dc851e","vout":1,"n":10,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"140000"},{"txid":"d3fcee7c551b130583ac4d3122b105cc87026435949372c78d8b61fa9c3ff77a","vout":1,"n":11,"addresses":["grs1qysqxuj7vx04drafu6rx03vp0wgk9rg5pcqsduq"],"isAddress":true,"value":"160000"},{"txid":"d3fcee7c551b130583ac4d3122b105cc87026435949372c78d8b61fa9c3ff77a","n":12,"addresses":["grs1qn6wqssh5d5tc7zhwhj6erp6p28h879480e7tnj"],"isAddress":true,"value":"300000"},{"txid":"1a836aa25b8939c36df133f50104cbc6e00f91f0a6b02fd2951ad1a7260615f8","n":13,"addresses":["grs1q33p5fx3r3zlq7ckqhkh0vr9gx5xz3tltkewrs6"],"isAddress":true,"value":"300000"},{"txid":"a02cb677515fa2431b44139883d3d31ef71a0097489743f4397617698f9e0c72","n":14,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"300000"},{"txid":"6eec066fcf8a8029faee4f74ecc5264332ac3605e15de79b4a53660bd901203c","vout":1,"n":15,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"380000"},{"txid":"3e5e9e1de659729be31cd63deafecd29bf2b7766fad0f0ae907b7a5b260401f2","vout":1,"n":16,"addresses":["grs1qaqkc5ll6x0w4dx3g60n7w7gtd26np3lx0wwsey"],"isAddress":true,"value":"380000"},{"txid":"8df8d4f4375264cc5578e46f34c0d0cb1de19c2958220b7b4fd7a34afe6f627e","vout":1,"n":17,"addresses":["grs1qysqxuj7vx04drafu6rx03vp0wgk9rg5pcqsduq"],"isAddress":true,"value":"480000"},{"txid":"46d956d92c85161547038e6d9ecd4205505bc23809bea9979e0d380d78267c32","vout":1,"n":18,"addresses":["grs1qnflfe7dvfp4vysv4m8z0k9chqkteqe2w5ta8vh"],"isAddress":true,"value":"480000"},{"txid":"3e5e9e1de659729be31cd63deafecd29bf2b7766fad0f0ae907b7a5b260401f2","n":19,"addresses":["grs1q0zch5h5uxtfx94x6nh7levd78mq8gj67pa7wta"],"isAddress":true,"value":"600000"},{"txid":"4b994083a3f3ccc73783065c0a23bf9890790f295890edbd2ac8166c52dc77d7","vout":1,"n":20,"addresses":["grs1qa5gxtj9ls89rfjr6ccjydqm7xhq2x5zqvm6dm8"],"isAddress":true,"value":"840000"},{"txid":"b4ea5e7a4006b18410c38302382853e2fcaedb07a58cd53c3cc0ecb0a5f01c2e","vout":1,"n":21,"addresses":["grs1qa5gxtj9ls89rfjr6ccjydqm7xhq2x5zqvm6dm8"],"isAddress":true,"value":"980000"},{"txid":"1b083e1587a090590237b72a68837bb5fce67f50b87ce6933bdfcd24dff0f784","vout":1,"n":22,"addresses":["grs1q5xq4vqyf9jg6mrcjugghkhq0m7ksvl73v6eeq6"],"isAddress":true,"value":"980000"},{"txid":"b4ea5e7a4006b18410c38302382853e2fcaedb07a58cd53c3cc0ecb0a5f01c2e","n":23,"addresses":["grs1qw6spp4sev3c24mhydkllhpt8yt0gvd7tna7pce"],"isAddress":true,"value":"1000000"},{"txid":"b883f18c47a0e7fa25a461b1b8f3ac43d5c4b10be82c3c851931d01047a3a35c","n":24,"addresses":["grs1q66aqr09y4efltet3xu3dl9uxd2cwen9gvmnfdl"],"isAddress":true,"value":"1000000"},{"txid":"8d5198d4dcaa1806cd717adc6117f23fe6a2c54aef6e27e93d99620bf4dc851e","n":25,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"1000000"},{"txid":"0f9a5819a6cfd389c7870bcdff147e3db787b2682b3c36f51260090458f4c02c","n":26,"addresses":["grs1q3uaxdr5xpk9p3h7dg29gecn6lpy80zn394pkd7"],"isAddress":true,"value":"1000000"},{"txid":"655e88b80ef0c7818014a3711b7cfcf66fd572d886251db55f529756e62fa157","vout":1,"n":27,"addresses":["grs1qulmmx7q6r5gp0w34zz5zv84zmp3al2hmg5ansl"],"isAddress":true,"value":"1960000"},{"txid":"655e88b80ef0c7818014a3711b7cfcf66fd572d886251db55f529756e62fa157","n":28,"addresses":["grs1qgjazwnlc5hnss57u7tg3zzxlvgsxra0chljv40"],"isAddress":true,"value":"2000000"},{"txid":"1b083e1587a090590237b72a68837bb5fce67f50b87ce6933bdfcd24dff0f784","n":29,"addresses":["grs1qs2xyel4tgejyfxylv5xdaxaafnf2qmhsnpar8l"],"isAddress":true,"value":"3000000"},{"txid":"3c662c0051f454df3c998067cbe5028f45a0789a47c331dab6b92bde908de04f","vout":1,"n":30,"addresses":["grs1q7gldkf5p8083nz3dmsktdm3sfdej5n3cwmcaw6"],"isAddress":true,"value":"9860000"},{"txid":"f3078100a2485b62294b257953c89dff6032f4e7b2b81e2e02a304248e5eefec","n":31,"addresses":["grs1qtunv3tapt3ak5str09hfee4zfpwn8lc5ccam3v"],"isAddress":true,"value":"10000000"},{"txid":"3c662c0051f454df3c998067cbe5028f45a0789a47c331dab6b92bde908de04f","n":32,"addresses":["grs1q9hlg5xwfl5tmytung3qrwxfwvd60h897cgzscv"],"isAddress":true,"value":"10000000"},{"txid":"71417cb19534d074f449c12a7fd3c15f6cbe6df063d8035e89859067ddb5e126","n":33,"addresses":["grs1qqc9srdr2l22e3dt99ex738a9apy32swzc5y4r3"],"isAddress":true,"value":"10000000"},{"txid":"9c2b150712803cd419317c417cb8ccf0cc50d22b65c2667f4e677f77fb64b8a9","n":34,"addresses":["grs1qeysq7696ymswzd3nvgq5kngktktkf08ettu2t8"],"isAddress":true,"value":"10000000"},{"txid":"7bda34b60a14f1eb886c1a4ae771754fc7c4e75fae306a72d471c3eedfb1bbc4","n":35,"addresses":["grs1qj4qacxpay5v6p4rpa8juec6fjpjjlg740emrg3"],"isAddress":true,"value":"10000000"},{"txid":"7b3161f9892fb1b7aa08e0a039ebca3c8cd34129f3b7d9d04992d3b73e67e4e6","vout":1,"n":36,"addresses":["grs1qgjzg0rz25atwg4l968xswklhpqj3ngl4kuyl0v"],"isAddress":true,"value":"19980000"},{"txid":"b79cbc6d51b89cdf1756b8c26a2f51a93a5b86c4c35800dbbb7f3f87e7c9940e","n":37,"addresses":["grs1qmmvgl0em0wtvqf9l3fm4fef7ps6k0ckgwd8twz"],"isAddress":true,"value":"20000000"},{"txid":"b79cbc6d51b89cdf1756b8c26a2f51a93a5b86c4c35800dbbb7f3f87e7c9940e","vout":1,"n":38,"addresses":["grs1qsufm8h68fthghkwcu54kshf5jfzunjttek8djl"],"isAddress":true,"value":"29980000"},{"txid":"7b3161f9892fb1b7aa08e0a039ebca3c8cd34129f3b7d9d04992d3b73e67e4e6","n":39,"addresses":["grs1q28w2mmdepq549ylzfx8k6cpauuu6nzp2gw0kv9"],"isAddress":true,"value":"30000000"},{"txid":"4800c0d049ca18e7baac7c3e3b01e1a8109e4e013b3179edc1bb4d8c91dee58e","vout":1,"n":40,"addresses":["grs1qmvsay76u2re6vet9aul6etqzsmnv09rzq63g3d"],"isAddress":true,"value":"35324345"},{"txid":"56a1af8000df7c13a8a5ec0c47c5a9a578392197510cf244a8a1aeeaf399e04b","n":41,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"50000000"},{"txid":"0d8b50f75abb2ce4d45a96b58d2f785df7839fb0857ae4802f7e7f7af41b8201","n":42,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"50000000"}],"vout":[{"value":"312904345","n":0,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true}],"blockHash":"000000000000000fc88ac750552c327173b6532a50e71bc4c96a6c6b2b431eb0","blockHeight":2964150,"confirmations":132876,"blockTime":1581688771,"value":"312904345","valueIn":"312924345","fees":"20000","hex":"0100000000012b29c6ffc19cab748f5625088ae3072c899c6ebf9ac65904ceeb18060ec2d1fa25010000000000000000a57cfbfcb9c99faab9305648d3dc24e3e45cfcac3969a7542747457a10afb69500000000000000000061b1bb3be7d991b831f5d2675185be7dead02c6beb5a543ec4f54ce336567b6d010000000000000000de7388db9bf4c28ce27813b70ff3a822b8b1b4283e22f9868cb79d2ee77cdcc9010000000000000000e2dd8ef900bf6881d163fc4a9e000a6d3cde45bf845e0b31393e53ed031786be010000000000000000d2449b0f8a711a44ccbb51de2b28d43629d81e65f9cd6982d9dee3c0be384cdc010000000000000000e478f70555559de02732462f77ce9eaf709987a5205a8b6131e9ad3f897bfd2a010000000000000000d4841244262c2a7cb68d6e6ae6471cc64061968b8cc70a0ee165fed239e202fc010000000000000000e478f70555559de02732462f77ce9eaf709987a5205a8b6131e9ad3f897bfd2a000000000000000000e2dd8ef900bf6881d163fc4a9e000a6d3cde45bf845e0b31393e53ed031786be0000000000000000001e85dcf40b62993de9276eef4ac5a2e63ff21761dc7a71cd0618aadcd498518d0100000000000000007af73f9cfa618b8dc772939435640287cc05b122314dac8305131b557ceefcd30100000000000000007af73f9cfa618b8dc772939435640287cc05b122314dac8305131b557ceefcd3000000000000000000f8150626a7d11a95d22fb0a6f0910fe0c6cb0401f533f16dc339895ba26a831a000000000000000000720c9e8f69177639f443974897001af71ed3d3839813441b43a25f5177b62ca00000000000000000003c2001d90b66534a9be75de10536ac324326c5ec744feefa29808acf6f06ec6e010000000000000000f20104265b7a7b90aef0d0fa66772bbf29cdfeea3dd61ce39b7259e61d9e5e3e0100000000000000007e626ffe4aa3d74f7b0b2258299ce11dcbd0c0346fe47855cc645237f4d4f88d010000000000000000327c26780d380d9e97a9be0938c25b500542cd9e6d8e03471516852cd956d946010000000000000000f20104265b7a7b90aef0d0fa66772bbf29cdfeea3dd61ce39b7259e61d9e5e3e000000000000000000d777dc526c16c82abded9058290f799098bf230a5c068337c7ccf3a38340994b0100000000000000002e1cf0a5b0ecc03c3cd58ca507dbaefce25328380283c31084b106407a5eeab401000000000000000084f7f0df24cddf3b93e67cb8507fe6fcb57b83682ab737025990a087153e081b0100000000000000002e1cf0a5b0ecc03c3cd58ca507dbaefce25328380283c31084b106407a5eeab40000000000000000005ca3a34710d03119853c2ce80bb1c4d543acf3b8b161a425fae7a0478cf183b80000000000000000001e85dcf40b62993de9276eef4ac5a2e63ff21761dc7a71cd0618aadcd498518d0000000000000000002cc0f45804096012f5363c2b68b287b73d7e14ffcd0b87c789d3cfa619589a0f00000000000000000057a12fe65697525fb51d2586d872d56ff6fc7c1b71a3148081c7f00eb8885e6501000000000000000057a12fe65697525fb51d2586d872d56ff6fc7c1b71a3148081c7f00eb8885e6500000000000000000084f7f0df24cddf3b93e67cb8507fe6fcb57b83682ab737025990a087153e081b0000000000000000004fe08d90de2bb9b6da31c3479a78a0458f02e5cb6780993cdf54f451002c663c010000000000000000ecef5e8e2404a3022e1eb8b2e7f43260ff9dc85379254b29625b48a2008107f30000000000000000004fe08d90de2bb9b6da31c3479a78a0458f02e5cb6780993cdf54f451002c663c00000000000000000026e1b5dd679085895e03d863f06dbe6c5fc1d37f2ac149f474d03495b17c4171000000000000000000a9b864fb777f674e7f66c2652bd250ccf0ccb87c417c3119d43c801207152b9c000000000000000000c4bbb1dfeec371d4726a30ae5fe7c4c74f7571e74a1a6c88ebf1140ab634da7b000000000000000000e6e4673eb7d39249d0d9b7f32941d38c3ccaeb39a0e008aab7b12f89f961317b0100000000000000000e94c9e7873f7fbbdb0058c3c4865b3aa9512f6ac2b85617df9cb8516dbc9cb70000000000000000000e94c9e7873f7fbbdb0058c3c4865b3aa9512f6ac2b85617df9cb8516dbc9cb7010000000000000000e6e4673eb7d39249d0d9b7f32941d38c3ccaeb39a0e008aab7b12f89f961317b0000000000000000008ee5de918c4dbbc1ed79313b014e9e10a8e1013b3e7cacbae718ca49d0c000480100000000000000004be099f3eaaea1a844f20c5197213978a5a9c5470ceca5a8137cdf0080afa15600000000000000000001821bf47a7f7e2f80e47a85b09f83f75d782f8db5965ad4e42cbb5af7508b0d00000000000000000001998aa61200000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb4239502483045022100dda68285f5c98ac3f1736ff190a2e931192e38119ea4620ff0c340eee3a225380220118714a3c2fd206a5ef30e6508d2a0c1394abbcd66a00ab11a764e5b2b9456a1012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b2850247304402200aa1d6e9353c2e3375bb8e12821c5974b1698a18d07fccb905fb32cbcf36401c022062c65f61b2413cd6a8e2517ce9f854409b937447be27ebfcf0b20770352acd76012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b2850247304402202335efbc7588bb997a7fe685d345a14d54e5474c97512f51e75272cd7ff542db022003d098bbaf1f29432e030025f326116b74801f162cbe0db2720bd4e15b6a5867012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28502483045022100e3b26a46738dc8992208c17adda2384424f8c303ee82f5fe2035fa7b4cc224ac02205a713efa63f972a9018b3766d03344a01b5818547917eebb67030bfd11a5b41e012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b2850247304402205ecce3bfe33360ceff821d16ffdb98393ebfa0b70c21d8d7eb9d3586434ea05f0220507b34ef4ddbb61c9d4c25bea254b3bac8b7421434dc25ab051f59cc5fbef014012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b2850247304402207e9ed9125afa12d60bb40202fb640c5ea42093a402bff3eece690eabcb67d992022054f0cdc1632ae450c2fe3ce684bac9c6b35550275f30cd741aa2ab8b7f74b12a012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b2850247304402205013558c3a4645648289d2d583af3c0a16cfbd119473ba797b24da4dfc4fdd36022078469ba29159cfc01eea2e64d531726aee9f7c2d1655f3ec3ee87c9dbf10572a012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28502483045022100c979d0c578e73a54396921c4873cb6b9621bcdb1724cba891bdfa4b7983dbff70220490b4bb09552de441f34258598337202943209e5c3eb9af719e3e12359e6a8c2012103edbd754a1d9e666428585215dcc08c6c5b53fbfc7ec43c9ed2347816e1859f7402483045022100e291508a1006a8587e6be61b87aebdde15eacb50be63744a844be0b57c59358b022040b03991009ae49e3a7c98dcf84e8be3a414ca7c8409d1faa4a1997cfc0bcb33012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28502483045022100b250cf13aa399054afa288dd117a7bef97dd09b18f98d1cd248968e1a902d8d402207ccb8d5a4925ddc187e074f196ccd6e7a1ea9609496ac5405a73ea870892f5eb012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28502473044022075f9cf4f883488c5d5ffcbd6d74f7f8596fd4814ed1fed839954b4bd4b9c05b702204b4bb5aae4bc5da1e2b236de733931691e0fb447a1a1f94737586980981f9f16012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28502473044022001dcebb22afea18d449bbd3234d62a6fcf7e43e4de33b1a220b0e29940c567b70220568ae3f748d34b3e005406e068ad3e1be3a882d6adb897fa524e0559d1f6ffcc012102d50eb39ae3640520b11a145af5351d094f1d45165f80a88c21fde0acbca8c2b802483045022100862c018754abfbb449daa3b0c110af58180d7584d64f300665965ed9797595fe02202aee69f243ddd79f266b631faa515d8e585f5f0944f625e06378f3d4864ba5ae012102691c3911914784cc628a9248454cee36757f94f073a7d46205c623f1202e4cad02483045022100a15f8d3ce18d804fa06c61d474a4b7e52bfc39892453f7f74520875ccebe4a6a02202b82212215f387618407af1288b2092b63233b131e0d73729cd67ec01c2fe580012102c70aa060c3c3194145309d71208931107a943c426bb2460729e059d957a67ca00247304402203cd32aacdb7a6d9d9e4360ac5545a861ae00d6062d90a49eb3e5f599e695596d0220564ef105ce68d87465d8a84f7af28029b902f88b6a9a86d3c9976fb06d511dfc012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28502483045022100c0ade5d0763e0ea114d5c3099dff0dc976a602cc11938e97cdbcf9eca36968c40220745c82706ab10fd96be689607b21cab3057631bd4dbd9ad6edfb2a5fc8e72abc012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28502483045022100d80bbcd4b4ba5345a60c6f6b03499f51316e98cffd81c268f29bfb6bbc95c11802200cd135a3d96d29e9a1718907ab4565d20672f081cc1d10db05dcfd467c4a5e1301210399869f1bb9ca5b578bd9867e9a3ad4307f45f86bf25e086f73e9785167d18c4a0247304402205cca5d4234b7f2501cff3e35931b2823afada7331ec042166e60d887a024603c02206d6c8886d82234a79b06feca0cf26c08c2de6863461575505516cd1d38066d85012102d50eb39ae3640520b11a145af5351d094f1d45165f80a88c21fde0acbca8c2b802483045022100cb5d9e03a736844a75ab55e8211f5838d937d7ea1aa58094fc5d306f9dc14d980220242d1c153724d3350434a97b5cba84cc3531e2e1b2ac775a5ba0c4a22566220001210200bba2d78064e88196be9e44d01e3d633cae02a8a97bbd294ad5b4743466fa6402473044022057fd34054630770dfafcc1107d139795cefbc6becebb18d8f4ccd64cfcf8eb51022057d9235605db264d0f2c482ff9a9933a5295710238cd47cfe53bf09748961c0701210313b7f74f6ccff0e60fec38a6ddcfc85516f6347fe37a84355839cc5b6bd7e5ef02483045022100b78ff12d1f317dea3727bdfe1d5a2a6b2de33cc54ce52d7d42db71a06a6c502902200f9ccd01627e64102090254ba95a0fd93abc4b9a2a72e5673a00958708695178012102067face2b5fd21d6a0c71a2f52592cffc4607b3bda6da141576fadfa8e2fe8ed024730440220388dbad76966e966c4b0a6a9027fb7e28bae393ba5e20e6c352043abef5ff47c022002e0a9de09e3492b3084fbfb2396d9c4ffd12b20b4019512dfe5a5e813582561012102067face2b5fd21d6a0c71a2f52592cffc4607b3bda6da141576fadfa8e2fe8ed02483045022100ca8d7921e5515103abad52d2405f0c5bb59f558a13e5a8db81fe4b10a75da883022021e549a9efe783fbfeabfa1f7572bcc25573cc13046e05cccc85682aa565c1fd0121038b2213fedf1a31fb64893c17bcf95e3a44527ed19b2889afa55afefb85ebf1d302473044022013d1e23a2d2497b9560c2523263c73039a234411826bf50c86100e7e3c8fdd34022072c6fe7ec2d44677994f67339d46d6f6599ca618664c7386590faf16b4cec48a012102811ba8512dd3376f5365d46fd3129496813225c2f7cff20648c1ea1ca0e7467b02483045022100c9d4eba9da02605bfc9ca54033d4d2d18df5060f366faf6582bcbb3575ca60f8022079ff03cb214838d9455b1d23d0eb5d6f980e3d16757fe7973c15ac8405eac5aa01210277a931902ec986935cc7c50acbd9767392c047951f9f492193d23fbd5c1477aa024730440220290d63712eb341898d4d8f28f9a480ed6424f09965c545c7300f964d319176060220729b56e7fae20d56a032362cf020395907693f32d52e356dbd755811f95d0c09012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28502473044022010dcdbe82f785ccdd5b896aa91226aa8e071d0cd5b30dab8dfae9294296b394c02200ec34b1e4f8c992e70ab951caa8965193a8fa1602054ce6af682bd9b77d49ba7012102ec51df51936fc88305953727467960ef6f20c7b1e94484f60e0042e6e083974102463043022068f4223f9427cf521901f02715dd13ad228780073f7f0e2859fc4a148bcd5172021f0bcf979a56b14990d2db33928e67e7fad6073934ad8d7b710a456b9a5802ef01210275a6842bf4f000cc2b65034379a2cd240d241d9889027830e14d5d04b89fc7a90248304502210094baa0d9f3d91906deb394ec1c0f1e90ce4abb900eb1aebc4147e6a93daa577c02203793da9cc37682e7e3e17a3fcb8db864c55117cbda1cf9e8f7666ddcc724fe200121021c88fdbed94569b9673316a7ecf1b294e852d4778fdc0a540756cb11ce7d0e7102473044022005acf933345d5d2f80d95cc51a7bc852566127b6345b910aec679c3f89a7854802206b83101cc2d58c5a6e44c4bd99c750100b82ed0b2d7eb83640f215fa8bc7ea48012102d342287ffcd5b1d6e5ad75f526f253a914729c4cbc1db7f9837c55345479ebbd02483045022100a92afd6ff17e1bf4f034e6708e5b3a9fecfb921ddcac143f972c7f6c9ea90983022056373802c75b39898a04a70dd19d15b41f9a63fb6b199d0adf22ba6aa6d05cf6012103ef14c253b8c2d8e70f52e12066a87891dc36f388a7969711995871d0296c198f02483045022100ee66c3c4511f8e792c2291b59b686d1461b6d70e9ba82452db882c5cab4c4aa302201134ca0be18ab192fbf560b81037ce3db6c14b355eb54297c258a343fd1670620121036879b519b860ce9a0163705cb455ad9ca0f8916aaee9199c15dfaa195fd1e5ff02473044022070c2dba854e7a4805231131b99a5019edf7a9257c190481f85da2cb64c5ad23a02202ac776845c473e4d531bc72dbef7d1bb56b7e91c47782d875b402d42ac48a745012103b19992fe4f69e4178ce4235c1f97f7744cc7f134e9c31fb4b13cc05e4a717cc0024730440220546dc2404fc2f7d293876daa89bc57a0e5a8ac70c6477e1657a9689f694d844d02202798957ce5e07042e70fe07c9e961ab37f6c609d4eea44829c90d3f4641bf4b9012103e64a3083a453563dc008f59057fd3d8ecba0b8cca3ee063c0e9969a0aa5c673502473044022003879cbd7269be371c29cf3a8700c61a4c4e5aa9a3e201707787a731b2953d4702200f2365c53ce69a9887bd253d727cd3f1c4ee03fd2aa2abe3773f7b71645c1519012103c824f725960ebfaffbead29603ff839946d56ab49f8752b98340a94e558f3c0a02483045022100ca17414822a367194f09110591bb1db4c665a2d9dc47ced5f6274725c4c1e37e02201edcb9f84e293343a1386a928a135275bf7e08b30863a8d68d000b71c6b65681012103ffeadeb731370d6499f9a76d05351934a2e7ed1617d14dd84802c53177caeb3b02483045022100af87f2203f91194d6a49214062289c3d740671c87f0bf868cf0339b62d3da4810220137f6f743a9fde2353174b63dcab37544ffa3a2204002497cd3803d11d38341a012102440e20dc21e094ae046df896c4f56fed4fe0ca2e28e1497bb8e0f4d40049644c0247304402202aa214769893ae100d4e3f209d2ae4cfceb303fa033531d91764b23eb3d53a7602205888afaa73a7a9c7f42ab7f3ebd1feb5ab06d9679ed52e858441632a9c8cb8570121039d5aaa3e073c087f2fe02543dc8bea715999374b6ca4d33e0594169b4d162b080247304402206e2444c90bb2bab858b59613c6078373b1aec997a624d09e86a4a0545108bfba02204fbb292824da95fa0f456d936016d30ebc622f5cf6286faa9f5193247c4b70300121031e2eecd58bb0db3f57bfe5ff67b6178da2a9d823c8796be737bd0b6fa92ba5ad024730440220400a612984efc092a31efc5b50b8d80353b7412a32298fd4e053fb488ad1e07102206ffb46bce7b25745b3713f85105668409a51c6081c037804256825a2888ff7580121023d966cc3d039eab86c6e336c6fc1e9a52cf580c9960b7547a47989b0b8a5dd83024730440220157a51269fdf2ffa2a309440f11f796367c8459353bf52d4e2fd2628313007790220252732976412d249252de8b5a835218598ecfdb7c8fc5591465855163dc359d9012102168643c5e8d097fd3bf12053d2c5f04ad5eede983ff6dd1eb4ef4b81122eb396024730440220211f11b60f6ad795f09fef7d83bbe731c0b57628c879e1ba657a782a8538844b02200cf54877fdd5c5c4b69fd7ed8c2277d81af7f302ab89ea7573f0f1fce080159c012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b285024830450221008c1bea7747fc0600327df340bedffb8824497f74b0c2c556c33511f6c186bf0402200f6c2d70daa9f1a9c7d15a7697d5de838eae1a2b4537a6a4c8376e0e2e19dcdc012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000"},{"txid":"d9f0569c6eac51a47d2405a09d17c8811a3ef8df212e88d3b6e75f27768b8d83","version":1,"vin":[{"txid":"0aac62c7f63dea9398e7f5459432b2228c2896d4e68a11a02e66b91f5336e403","vout":1,"n":0,"addresses":["grs1qzj8ha64pvccsu0yvel8uqvgdndcg8zx0rm30dt"],"isAddress":true,"value":"388937964"}],"vout":[{"value":"100000000","n":0,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true},{"value":"288917964","n":1,"hex":"0014d19952adf465581f3262bded696cd869cf9619d6","addresses":["grs1q6xv49t05v4vp7vnzhhkkjmxcd88evxwkjeukhc"],"isAddress":true}],"blockHash":"000000000000000fc88ac750552c327173b6532a50e71bc4c96a6c6b2b431eb0","blockHeight":2964150,"confirmations":132876,"blockTime":1581688771,"value":"388917964","valueIn":"388937964","fees":"20000","hex":"0100000000010103e436531fb9662ea0118ae6d496288c22b2329445f5e79893ea3df6c762ac0a0100000000000000000200e1f50500000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395cc89381100000000160014d19952adf465581f3262bded696cd869cf9619d602483045022100b94d6b8dacffa6bd2eb7d34ecdd3f330b4b9df8b8ea8e5c6fcc1d9f9777fb377022049cc1534a177f296b03f0fcc6821501433add29990dfe795ca28f41e2e22008d0121037d4305c4c893c806fe789e46eb9e16926ac7c43fc99c8c3602ae04185dad512b00000000"},{"txid":"4800c0d049ca18e7baac7c3e3b01e1a8109e4e013b3179edc1bb4d8c91dee58e","version":1,"vin":[{"txid":"568acc4f54ce8eb03e09ccc16dbeee2b882f6ed620d565708133f71e0e163b60","vout":1,"n":0,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"145474926"},{"txid":"027f784db0849c599b411e8690f257bc3feb23272ffe709c7d486626c4872955","vout":1,"n":1,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"439889419"},{"txid":"56a1af8000df7c13a8a5ec0c47c5a9a578392197510cf244a8a1aeeaf399e04b","vout":1,"n":2,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"449980000"}],"vout":[{"value":"1000000000","n":0,"spent":true,"hex":"76a914bc3b34231b16f2af9d41c100ab833510c1d81b0988ac","addresses":["FnKzQWuu8zcL3u6hEuNZDsjBpgfDMhMhE1"],"isAddress":true},{"value":"35324345","n":1,"spent":true,"hex":"0014db21d27b5c50f3a66565ef3facac0286e6c79462","addresses":["grs1qmvsay76u2re6vet9aul6etqzsmnv09rzq63g3d"],"isAddress":true}],"blockHash":"0000000000000b2d30be42fd05d3f2a6807e6e53d203efb51496aa0fa8a80445","blockHeight":2964145,"confirmations":132881,"blockTime":1581688548,"value":"1035324345","valueIn":"1035344345","fees":"20000","hex":"01000000000103603b160e1ef733817065d520d66e2f882beebe6dc1cc093eb08ece544fcc8a56010000000000000000552987c42666487d9c70fe2f2723eb3fbc57f290861e419b599c84b04d787f020100000000000000004be099f3eaaea1a844f20c5197213978a5a9c5470ceca5a8137cdf0080afa1560100000000000000000200ca9a3b000000001976a914bc3b34231b16f2af9d41c100ab833510c1d81b0988acb9011b0200000000160014db21d27b5c50f3a66565ef3facac0286e6c7946202473044022062dadbf1c2b87701d4914ad3890bbd57004abd418b981d38c2403a49501ebdc402207ddf47f3be5ba2c6c7d82c79470c734acbb93941cbf1248008b7c9f242858689012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28502483045022100d43d73fc0d4fffeb4bcf71cea47e67f83f081ca5807cc3a0389e30611f7a450b0220371bdc9978fa570e2a27b6d2e88787d6a2b6ed2214af012499eb24a63f3da4c9012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b2850247304402200df81ade9e3ed8343c4ef75a3ec32455436fb9e0a511ff1e63447753f320db9a022064155850471cf0a5d50d684dd82144094ef11dbba0988bc34809237a8d6eb9f7012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000"},{"txid":"d71c47c7958f9867c0949bb3f8b66947b4fc117451e370dfa37ef5f94e95cc16","version":1,"vin":[{"txid":"27f1d526c40a097672571f9ce9eeb2b43c5f08ba5196cf452f023bd4ddde0c55","vout":1,"n":0,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"4439929419"}],"vout":[{"value":"2000000000","n":0,"spent":true,"hex":"76a914bc3b34231b16f2af9d41c100ab833510c1d81b0988ac","addresses":["FnKzQWuu8zcL3u6hEuNZDsjBpgfDMhMhE1"],"isAddress":true},{"value":"2439909419","n":1,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true}],"blockHash":"000000000000069196de5fb7d848deb7e9a9ee8586a889e262e8e5444d0883ac","blockHeight":2960855,"confirmations":136171,"blockTime":1581480399,"value":"4439909419","valueIn":"4439929419","fees":"20000","hex":"01000000000101550cdeddd43b022f45cf9651ba085f3cb4b2eee99c1f577276090ac426d5f1270100000000000000000200943577000000001976a914bc3b34231b16f2af9d41c100ab833510c1d81b0988ac2b106e9100000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb423950247304402206c50a3677f4fad4d721b869117581b4e1cf9534182efba30c17c7b1a6a9af52b022059d3a78a653d0479983287d679ce09f29aeef97cfe7e4b3a4f80cb4f9e2a4614012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000"},{"txid":"027f784db0849c599b411e8690f257bc3feb23272ffe709c7d486626c4872955","version":1,"vin":[{"txid":"d71c47c7958f9867c0949bb3f8b66947b4fc117451e370dfa37ef5f94e95cc16","vout":1,"n":0,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"2439909419"}],"vout":[{"value":"2000000000","n":0,"spent":true,"hex":"76a914bc3b34231b16f2af9d41c100ab833510c1d81b0988ac","addresses":["FnKzQWuu8zcL3u6hEuNZDsjBpgfDMhMhE1"],"isAddress":true},{"value":"439889419","n":1,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true}],"blockHash":"000000000000069196de5fb7d848deb7e9a9ee8586a889e262e8e5444d0883ac","blockHeight":2960855,"confirmations":136171,"blockTime":1581480399,"value":"2439889419","valueIn":"2439909419","fees":"20000","hex":"0100000000010116cc954ef9f57ea3df70e3517411fcb44769b6f8b39b94c067988f95c7471cd70100000000000000000200943577000000001976a914bc3b34231b16f2af9d41c100ab833510c1d81b0988ac0b2e381a00000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395024830450221009dd13372c1929d9d50d89297dd1ffb0887031186b68d353e6b5a1de60e4d1f29022033fa7956567456ebf1f32b4a2fb80e138b9052718d3250d54a95b79d196edafc012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000"},{"txid":"568acc4f54ce8eb03e09ccc16dbeee2b882f6ed620d565708133f71e0e163b60","version":1,"vin":[{"txid":"cfc8d72bc809328f6008b20e2aaa8409ad81c2f313ceb02b04c66af7ea76205b","vout":1,"n":0,"addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true,"value":"1145494926"}],"vout":[{"value":"1000000000","n":0,"spent":true,"hex":"76a914bc3b34231b16f2af9d41c100ab833510c1d81b0988ac","addresses":["FnKzQWuu8zcL3u6hEuNZDsjBpgfDMhMhE1"],"isAddress":true},{"value":"145474926","n":1,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true}],"blockHash":"000000000000069196de5fb7d848deb7e9a9ee8586a889e262e8e5444d0883ac","blockHeight":2960855,"confirmations":136171,"blockTime":1581480399,"value":"1145474926","valueIn":"1145494926","fees":"20000","hex":"010000000001015b2076eaf76ac6042bb0ce13f3c281ad0984aa2a0eb208608f3209c82bd7c8cf0100000000000000000200ca9a3b000000001976a914bc3b34231b16f2af9d41c100ab833510c1d81b0988ac6ec5ab0800000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395024730440220213d174a1ab818d62200684247f26a66714134079efa421125203ae5687138bf02206f0639a2f441edbfd69384cefa4c9fa196a4a401880a5cfc48cf6ba3589e8a86012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000"},{"txid":"2afd7b893fade931618b5a20a5879970af9ece772f463227e09d555505f778e4","version":1,"vin":[{"txid":"1a836aa25b8939c36df133f50104cbc6e00f91f0a6b02fd2951ad1a7260615f8","vout":1,"n":0,"addresses":["grs1qny6hgcxsw2lcm8g5prsuamytkehhv0m7gtktws"],"isAddress":true,"value":"180000"}],"vout":[{"value":"100000","n":0,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true},{"value":"60000","n":1,"spent":true,"hex":"0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395","addresses":["grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04"],"isAddress":true}],"blockHash":"00000000000006e959edec52f260e1c6c58930c96282b94ded283f9dda1973c5","blockHeight":2953512,"confirmations":143514,"blockTime":1581017188,"value":"160000","valueIn":"180000","fees":"20000","hex":"01000000000101f8150626a7d11a95d22fb0a6f0910fe0c6cb0401f533f16dc339895ba26a831a01000000000000000002a086010000000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb4239560ea000000000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb4239502483045022100fb5c6e06ec96646aba0ee19bedf98952ed5ae7145711258a3fd451dbfbdbbc5d022053660e9551f8deacd47fbaf5d688cad27f8400fc30bb28365f529c5939d749150121022ac3ed710b6ef6559923fa37dc128cfa6956fe307e55ed6620b8e600c1f3e7a200000000"}],"usedTokens":79,"tokens":[{"type":"XPUBAddress","name":"grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04","path":"m/84'/17'/0'/0/0","transfers":53,"decimals":8,"balance":"412844353","totalReceived":"34760610350","totalSent":"34347765997"}]} diff --git a/mock/ext-api-data/harmony-api.json b/mock/ext-api-data/harmony-api.json new file mode 100644 index 000000000..edc740137 --- /dev/null +++ b/mock/ext-api-data/harmony-api.json @@ -0,0 +1,84 @@ +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "transactions": [ + { + "blockHash": "0xe6e65f0f9f1e694d93012f1f2b4713cdd253cc6a15e729ff6df23a78d7694013", + "blockNumber": "0x1b2cd7", + "from": "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", + "timestamp": "0x5df7cb24", + "gas": "0x33450", + "gasPrice": "0x3b9aca00", + "hash": "0x391af85c5e25ee96cbbc417121b6bacc0ed466c0423467354192c075444e7603", + "input": "0x", + "nonce": "0x1f", + "to": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", + "transactionIndex": "0x0", + "value": "0x1bc0ae68df60e000", + "shardID": 0, + "toShardID": 0, + "v": "0x25", + "r": "0xb65b59fd1c9733977b0689e07a1869713ae2b2f8eabecee0a426c3f7fe62ac6b", + "s": "0x52b5be00be05173d89ffbf82a47b03f50268e6fe1ccd36a3fa7123a5255d2be2" + }, + { + "blockHash": "0x1b45da220f94f41bd42dc0eb89a5e83ce77b37cc78dbc9032bd10a5bbab13674", + "blockNumber": "0x1b2cdb", + "from": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", + "timestamp": "0x5df7cb45", + "gas": "0x33450", + "gasPrice": "0x3b9aca00", + "hash": "0x6bfd003239bf137855342f6266c456ae1b342e886bd1965a47edd4c74dd1a687", + "input": "0x", + "nonce": "0x0", + "to": "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", + "transactionIndex": "0x0", + "value": "0x1bbfef6a6ff9c000", + "shardID": 0, + "toShardID": 0, + "v": "0x26", + "r": "0x44c2a7b8c38612a3ce8b51967947c0c9756dda8d82d0f12137451ce33bbef390", + "s": "0x34234c6c26fe36bda246db845692fd248cb4060cda0d1c6056298b39486ed4f2" + }, + { + "blockHash": "0x58cc90d1b9302d0121b426f5fd35014acbc009defe36c5bbff6ac920d6005526", + "blockNumber": "0x1b2cf2", + "from": "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", + "timestamp": "0x5df7cc02", + "gas": "0x33450", + "gasPrice": "0x3b9aca00", + "hash": "0xf54f6f86df1624f38fcedf56eb248854a13a733e0b0f92d4b31b9cc7196d90b0", + "input": "0x", + "nonce": "0x20", + "to": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", + "transactionIndex": "0x0", + "value": "0x1bc0ae68df60e000", + "shardID": 0, + "toShardID": 0, + "v": "0x25", + "r": "0x46d14df06948f055e519ac244bcaaa3c3446ed20671d41db01546ddaad32503b", + "s": "0x50d13aeb94f2e8c760723afa4d892f3ca17690451a57465ea7e39c5d347efe8" + }, + { + "blockHash": "0xa84376f0f4d082b76355ccc6ec491660c0062d9ef3f39985ca00986e8dcbacc1", + "blockNumber": "0x1b2d1b", + "from": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", + "timestamp": "0x5df7cd50", + "gas": "0x33450", + "gasPrice": "0x3b9aca00", + "hash": "0x73355f625d0f7ef31512657c0f669e710c8c91a67180cd28bc919cfca0a2af82", + "input": "0x", + "nonce": "0x1", + "to": "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", + "transactionIndex": "0x0", + "value": "0x1bc09b4f6dd69000", + "shardID": 0, + "toShardID": 0, + "v": "0x26", + "r": "0xf31271b93e446bce8cc83eb997183146b4da2378a5f2cb1fc4ae64fbd65a93f5", + "s": "0x77e8e5693a87394204f96693a15f2157459b0329a2ddab97da0bf1cfb6fbce8c" + } + ] + } +} diff --git a/mock/ext-api-data/harmony-api.request_json b/mock/ext-api-data/harmony-api.request_json new file mode 100644 index 000000000..8349619a5 --- /dev/null +++ b/mock/ext-api-data/harmony-api.request_json @@ -0,0 +1,11 @@ +{ + "jsonrpc": "2.0", + "method": "hmy_getTransactionsHistory", + "params": [ + { + "address": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", + "fullTx": true + } + ], + "id": 1 +} \ No newline at end of file diff --git a/mock/ext-api-data/icon-api_address_txList__address_hxee691e7bccc4eb11fee922896e9f51490e62b12e_count_25.json b/mock/ext-api-data/icon-api_address_txList__address_hxee691e7bccc4eb11fee922896e9f51490e62b12e_count_25.json new file mode 100644 index 000000000..05e09038d --- /dev/null +++ b/mock/ext-api-data/icon-api_address_txList__address_hxee691e7bccc4eb11fee922896e9f51490e62b12e_count_25.json @@ -0,0 +1,53 @@ +{ + "data": [ + { + "txHash": "0x3b1a382884091e683350d6285d908406c149a030a7d52eb347f4571c1c904382", + "height": 7044559, + "createDate": "2019-08-13T06:53:56.000+0000", + "fromAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", + "toAddr": "hx06d5b88bb7089033a2d8a2b61b8a305ecff8774f", + "txType": "0", + "dataType": "icx", + "amount": "0.498", + "fee": "0.001", + "state": 1, + "errorMsg": null, + "targetContractAddr": null, + "id": null + }, + { + "txHash": "0x990b7f289aa465369e638b4f719c99f0d050f9756c19081ba86b2bae5b8e2f0d", + "height": 361987, + "createDate": "2019-04-17T01:16:02.000+0000", + "fromAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", + "toAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", + "txType": "0", + "dataType": "icx", + "amount": "0.00347", + "fee": "0.001", + "state": 1, + "errorMsg": null, + "targetContractAddr": null, + "id": null + }, + { + "txHash": "0x3a455daca1f5e4588adbc6ac5cdfd84126d0617d3ebcf5610eb44b15dfc71402", + "height": 112100, + "createDate": "2018-11-23T21:52:15.000+0000", + "fromAddr": "hx3709f4e615f072158247ca4973218e1d40e0ea35", + "toAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", + "txType": "0", + "dataType": "icx", + "amount": "0.5", + "fee": "0.001", + "state": 1, + "errorMsg": null, + "targetContractAddr": null, + "id": null + } + ], + "listSize": 3, + "totalSize": 3, + "result": "200", + "description": "success" +} \ No newline at end of file diff --git a/mock/ext-api-data/iotex-api_accounts_io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json b/mock/ext-api-data/iotex-api_accounts_io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json new file mode 100644 index 000000000..11b108553 --- /dev/null +++ b/mock/ext-api-data/iotex-api_accounts_io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json @@ -0,0 +1,9 @@ +{ + "accountMeta": { + "address": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", + "balance": "3472246872153132576758722", + "nonce": "628", + "pendingNonce": "629", + "numActions": "730" + } +} \ No newline at end of file diff --git a/mock/ext-api-data/iotex-api_accounts_io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5.json b/mock/ext-api-data/iotex-api_accounts_io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5.json new file mode 100644 index 000000000..d4957669a --- /dev/null +++ b/mock/ext-api-data/iotex-api_accounts_io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5.json @@ -0,0 +1,9 @@ +{ + "accountMeta": { + "address": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5", + "balance": "76393702651088989820", + "nonce": "4", + "pendingNonce": "5", + "numActions": "94" + } +} \ No newline at end of file diff --git a/mock/ext-api-data/iotex-api_actions_addr_io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5__count_25_start_32.json b/mock/ext-api-data/iotex-api_actions_addr_io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5__count_25_start_32.json new file mode 100644 index 000000000..3164324d0 --- /dev/null +++ b/mock/ext-api-data/iotex-api_actions_addr_io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5__count_25_start_32.json @@ -0,0 +1,555 @@ +{ + "total": "25", + "actionInfo": [ + { + "action": { + "core": { + "version": 1, + "nonce": "28462", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1139739152873976225", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "XPR9K36edqdorIp0/cGS8eWhY6i4+NAj0NCFG0VG88UeBpDwNSvljhZn5/MfmaBWRuqhKn/MUtEqUqNPl/OcBQA=" + }, + "actHash": "fb24096a9b1de30d419c3615470e6af0d76767dd5857b30d09be913c349114bb", + "blkHash": "8096fd14b838a82acfc32ac0aa278f75f7c39c748feafd4bfd7f55fbf4563573", + "blkHeight": "3771852", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-12T22:58:30Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "29979", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1111805680886352291", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "8e5VPalYrJEOcW0G0Hg+xNRKieUb14A7fikf+kmG3pUVfrGXCrfHb3dQlim5+3INi+mVIupWCz9lair8dn+AcwA=" + }, + "actHash": "fda766a321e525d1e444585ba9646f939660e8ecdd1b02e09830efad4f29b0fa", + "blkHash": "8c4d6bd99536567dfea8270a4cc44f969c3ab0cd0193489c2379f4f765b32e71", + "blkHeight": "3789752", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-13T23:50:15Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "30824", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1131271796026741329", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "amZfy8FnWCixh1DCZTJY956dLpw6dFj5zqS3pUexVtA2excq1eJ/hMVTmfUqa0et+2CRR4/56trgiy1Wsg2sIQE=" + }, + "actHash": "40fe7c8fa7f1a21e9c1b2808440b7b32e2da6eda591bba251cf5ffb9072c9fc4", + "blkHash": "edea990dff3e2937d0e2a1e8039b10211a4be71672d6f264fd798b2eb8ffb545", + "blkHeight": "3807009", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-14T23:48:50Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "32045", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1204451131406840247", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "Y+Dd+Day889zF+6OYLAa+2VXF9WsvvOh/UYZ/4MKsB46RXJjpBHXaq3vq+UH8gLj52h9O90iKegxY/9q/rB97AA=" + }, + "actHash": "d7adb924e0045eafc83849c5d3f5f0611e91ea220c4db5e78e5d4e9947e3f264", + "blkHash": "dfeea435007456c242acc73370ffb79d86a832ecc10b6edc739ad6abd3cc72d5", + "blkHeight": "3846116", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-17T06:08:40Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "32651", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1119197072222693878", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "bc/6E7HvxFWAQkkYsh/fajg4w2eCxg5KxvjFQy/u43p6Fw+N7eIF3XGfYIjMH6O5hvC3QWtLjO0+QmdbpaKI1QE=" + }, + "actHash": "8f40e5e4c9fb4e8e29505a8d0db6428f3d372109c1a96c807d120ae9fe84ff9e", + "blkHash": "d7351f1ebef30a156c7a015f8e22861d792919b31aa21b0fca2094fa6f9df3c9", + "blkHeight": "3847025", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-17T07:24:25Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "33170", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "616085709830862489", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "ghjLaSWIXzYXcnLm3R5xDX2TXbOMytdnoDoCJR2YYtRGq/U47v9zNIekPEOiuAr50958KqB9Jnxx+5eiitrdkgE=" + }, + "actHash": "b95d7eee5c4be3c3adc1b77dec67703217abc12859058ece4cbc6d0fac67e279", + "blkHash": "b9206c4013cbb5b4b5ca1c4252172762d888cad9d89e2a129c1f3a0851b94069", + "blkHeight": "3857939", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-17T22:34:05Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "34930", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1137180233280393945", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "jAeGulwT5pdSDbvAorEGaWwPMt8TQ7JqphRp8b83lfBeq2AzzC2BjnNnAt1KdOtTCi7tdP0FmwJcd2IDWvK86gA=" + }, + "actHash": "2ed4f066b1ac98e77e28d76c3a7b589d32fdd7170dff93c936ff06964a7e8364", + "blkHash": "51152bc5405b015eb7d546731800edde5cd1b9d6196fe220a1daee0fdeefb816", + "blkHeight": "3876469", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-19T00:18:35Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "35808", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1129516449938091591", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "S1JgjE+sUau9F3pCSqBQFEdld6JgyhHnpTS7MT7VfY8vChkzR64MOp0piTeG5LypwU085omb68cqWiZ4w7rZqwE=" + }, + "actHash": "924c7d38a8b7ea1790190a6c3251b8822a7d879f3dc7858b7d5146cbfa28d94b", + "blkHash": "a7875facf7db064acf5b2f40cc00c99f53a0abe1b46bead7d419fdaf952e09d1", + "blkHeight": "3893406", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-19T23:50:35Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "36585", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1181978062448451578", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "V1ukS9nGBatNPtFmhqwYZ58zJfZlr2My41OWMOEY2TsdTiFM2vn6U6dUOzP2Q87XK+POImXo1WuFPQKEVBESiwA=" + }, + "actHash": "d9dd50577c9ec22fad396994b6f568129304777b297cd38360a85c9100f89f04", + "blkHash": "94a0ee3e2d1acdc1da30a8a60ab13e926424dfabb5774cbe93ba13fd950ae9b1", + "blkHeight": "3910443", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-20T23:31:40Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "37104", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1137074169236917509", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "JveynAk719BtUVoD0qkrhU6yHnWLrxccJ8fJLjQCV1sI0x+mXGBtUo+VnsETNcaGgS3ZVXZ+/yljH207zZAUHAE=" + }, + "actHash": "c6d0c7635f572a6347f8af2e222ae390a1004c8781f0e86604d5f1b72d0fb08e", + "blkHash": "ec168e8daf8f8f2c069a574dfc14b5b35445e357a4cb2cd290f11c050c052d14", + "blkHeight": "3927027", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-21T22:34:45Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "37961", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1184316808242241414", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "vszB/AhgC+dDP/9O9W/sa/lRciYA5QEEwBvCH/1K22MNpfxSnBc/RFBQCUkwNZbWGReTwa8u1c0ZHJtM9mvRjAA=" + }, + "actHash": "b8da1695e9b29536e41020c38b9169aaf41044f537f237a77d9eea2112db1537", + "blkHash": "73af0b36b966992833e314d5e4956beb5252572b24093a54eea789d109aa1560", + "blkHeight": "3944042", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-22T22:12:45Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "39144", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1185206155867839721", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "wiaaZGhWP7shWeJ+jAZ0LJQ02Iqu3HpwD5l2ZUD/XgE5h9nzSJ01jeBmg0/eJfl1CSwBgjzbHuitSFQr8qkOAAA=" + }, + "actHash": "b551f9345b9ec7ab60a9cfdeba7f425c039d29b29ca85cdcccc76a258416943d", + "blkHash": "c038f79c56de675a6e73166f66c28e97077d32a3a20602558ebbe8b0bdf56c46", + "blkHeight": "3961739", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-23T22:47:55Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "40067", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1120195881668261370", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "eXBaTtXM94uKCfWFP4UMBMs7lQJx9cChvekJvF1GprtYwpuFUAYnOOw3zL8CNkIcYeu1vvFP7bKqcVWjvpq1AQA=" + }, + "actHash": "91ee5311e8b925d6b4f9990661b6346fff7621bb232f1bd57cf0865c6ec13f6a", + "blkHash": "508e96f8c8ad396492e8faee556ebda56934ca88d632b16fe70de1798dbfc992", + "blkHeight": "3978946", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-24T22:44:50Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "40896", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1149507256400194232", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "SeUHtmepKY7XqgNFgRsddSSDhl9hq1jEWprsD5RAfCJcCG4jDyhFfD1fSshq+3aXa4WsSzQL5VvEu9NNLX3JoAA=" + }, + "actHash": "16e4073278e504e531f7e27aa37debe0ace0319e7f8c7a1f1ae58fcb1f9c232e", + "blkHash": "18248815cfca2256d8dd3a71f2ee621a6ce53a509743f9aa0915d9f57068d4dd", + "blkHeight": "3995866", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-25T22:14:55Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "42361", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1178751709816943912", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "ItkmQLsdpbIh8l61Sv0dsIknSYEaNUH9MMGi3z1RPYBcskdqtUl+uA4exeGqmBPcB14KRpHxS0vn/ylv3rZElwE=" + }, + "actHash": "b926eb0785f51009d56994f420384239b906063709e6f28135fe87f8f6fa8eed", + "blkHash": "a687e5949c3fe7dadaed819108c4d6f88272a2bef43f6577407950d64b97bf95", + "blkHeight": "4014008", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-26T23:27:30Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "43185", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1163519091815786084", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "o8AKMh3tfGTVejJZEHgl1ru1NBGX58l3enO+Hgpfv4s//kMJJDXWmZPKyFkNPAi0pRUoDCcfhfgu3CQ5E+FqgwA=" + }, + "actHash": "b300484bf548132f8764faa7226cf834a9771b0bd3903815690c2fb4f57e6d70", + "blkHash": "be5f08a2d21fce143ebc54df600318c82ba0f0444395c47d9dc8148fc37bf17e", + "blkHeight": "4030942", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-27T22:58:40Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "44643", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1187241207292272207", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "a/ZabeQVo+q8OH62WT05wK6NrQ1foJ8MdIphfKZ16EEFHKw1/ORchlKnC45WQMdEptoQpgjBmlwNAshtWQ1YyQA=" + }, + "actHash": "43d787886c81368185300c3dbe6d230622f3a4fec0cf5c890264fcd8b8ccd451", + "blkHash": "b2fefb3f4999cc49ed939cc874910eb5e99444119bc05e7455d793f128b45bb6", + "blkHeight": "4048898", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-28T23:55:15Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "45616", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1179608785863654375", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "SnPDh1PGnRJRjxPK+VvSjI3X9l4VnSrWW1cT2Q6QyndrrJH5nFbH/lrYLO1billkU44BdB1J4cq4h+8JWUIbjwA=" + }, + "actHash": "f3827899d82f49b41e32eadcd2f5c1c77bd10bbe9426b4aee4108c6b8c6ff44f", + "blkHash": "52591d93ecd21afb578b8288dfbabc95065c58bcbde7f5b5e239c4a3a30e5bff", + "blkHeight": "4066230", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-30T00:00:55Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "46208", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1216969233453951224", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "cJ4tF0PdchnWFt/1VyRehYCU6//rs0TOvLrWQ/hjZ5FBXk1cslEworPBkDf+Y/Daaa/Kt67x+s19h/sWCOZ9AwE=" + }, + "actHash": "70a3e5d047feb19a6cf6fe5c462b99183e7c302f142496c067d9c8c7f551165d", + "blkHash": "7b20c3973ea91581301617d9e4fb2e2d29bb2907a6c1921f340bec7daf2fd1ed", + "blkHeight": "4082972", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-30T23:36:55Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "46956", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1137658532468953742", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "04Iz5C2ZEbz5W4XqOVkfd1Iu2L5cCwnNmA6kTgW5Dydj3eE+fUstEhXezFnYm84BKceS4S0IjY/fN2PNBLMCAAA=" + }, + "actHash": "7eb7defd7ca912cce37e164df0e29af7c0bd4a607546404278a48fe670df07f0", + "blkHash": "6d50e2ac079dfa1d30222a823573e6f7c67d159b7f9c67782b9e8db0b06ad74d", + "blkHeight": "4100040", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-03-31T23:33:05Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "48530", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1109317313247383997", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "L5vuCdcu7oVBL+bImrmhg6mAV9eB2b8P1Ro/9bUpjppb20cpOgSzex+u7zd9/bQ0y5xfo8Vusd9hGTLf+WyE2wE=" + }, + "actHash": "33adb824f4764c28d0fbc647070c673e56778a4336cb5231b4bafe66a6ca03f3", + "blkHash": "70dee6fa86281e7baa86fb1a122ac248bc9e60a796e05a007b03c8e403cdbd42", + "blkHeight": "4118003", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-04-02T01:17:20Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "49203", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1183775597584344784", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "DKT1Z0a5wSbVyCtosj2iLYVAX8bKT+VXnG7KdRaz/M5wgiH0qHB0rPwWBT0Ex6mWfV7TZv4Nk8N+wIXmF8QH1QA=" + }, + "actHash": "46f70a7b86717e4106bed9d87e40e9b34299e8058b4d840ac803ab0d91923025", + "blkHash": "0cb941b6bc328a18eb90c74450b4e5bbf2f3de09b892810118e00caaea48dcbc", + "blkHeight": "4134883", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-04-03T01:25:20Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "50571", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1174691181833403746", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "gwOpLdA8bdQ/GiVvW6r9xFCnxbXXcljoIvxfczkTnAIdEEDxWBVTRzU6/PhBsvK2zrciK9Xe6rietJTaKvL2mwA=" + }, + "actHash": "92c16dba51da8ed20f32dbbc2eb9761e02e1fc0b2bd0dc83eeb1060e2ac9b5e9", + "blkHash": "bacf45b2a93a17ff7c11017a218cebbde062167326acc6c7d9cce04838b1835b", + "blkHeight": "4152703", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-04-04T02:17:00Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "51520", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1199779673372762660", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "7aGfci1M3b0CfW/WM+amhDG/1CujoHM7Fo5iogUsbhFgs8CKqvLlKBxhnTe8RlTx9vvB7E7GIpZr+nnu7TWCwAA=" + }, + "actHash": "84db1a50fa3245355f2eeba6df65429ae821bb109aa6369ef623e4ddf72a6187", + "blkHash": "449bb470cb5790598c1b62a428d3eb3e3e76498bc2ca313b3753b83f67de39e4", + "blkHeight": "4169897", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-04-05T02:09:55Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "51884", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "1207553760674973468", + "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" + } + }, + "senderPubKey": "BOWWJrWizG7CKbZUhT0ljmq6HlTAWzqBeo2mW+rt3HfWvODg1UBWz7U4nzJEo02HybleBQbHOoyehaspU0t7jlQ=", + "signature": "qVaSqVfZ8jjkhnLJn486b40mzqFSaWZkW861lctzRhhTzZLBTCOaRwaOwzLpjxhluE+EI5BcF9e18pWhwLEb4QA=" + }, + "actHash": "dc0155fbb1936737b39e0c61a29be88dcaad88b765c69a6af34284d83a310c19", + "blkHash": "50e0787868975543d42fb6ac221ab1546b5d0745b8c2fb75d8f60e1ea479b6a1", + "blkHeight": "4186453", + "sender": "io1ey8s7p7kzu9lh68we7mstmyllaxc6tgwuj2whh", + "gasFee": "10000000000000000", + "timestamp": "2020-04-06T01:09:40Z" + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/iotex-api_staking_delegations_io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json b/mock/ext-api-data/iotex-api_staking_delegations_io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json new file mode 100644 index 000000000..25c2074cd --- /dev/null +++ b/mock/ext-api-data/iotex-api_staking_delegations_io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m.json @@ -0,0 +1,23 @@ +[ + { + "delegator": { + "id": "iotxplorerio", + "status": true, + "info": { + "name": "iotxplorer", + "description": "", + "image": "https://imgc.iotex.io/dokc3pa1x/image/upload/v1551121446/delegates/iotxplorer/Group_2.png", + "website": "https://twitter.com/iotxplorer" + }, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + "value": "100000000000000000000", + "status": "active" + } +] \ No newline at end of file diff --git a/mock/ext-api-data/iotex-api_staking_validators__status_bonded.json b/mock/ext-api-data/iotex-api_staking_validators__status_bonded.json new file mode 100644 index 000000000..718af9ac3 --- /dev/null +++ b/mock/ext-api-data/iotex-api_staking_validators__status_bonded.json @@ -0,0 +1,794 @@ +[ + { + "id": "droute", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "longz", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "coredev", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "keys", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "pubxpayments", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "royalland", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "gamefantasy#", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iosg", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "laomao", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "huobiwallet", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "cpc", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "hashbuy", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "enlightiv", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "metanyx", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "consensusnet", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "airfoil", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexteam", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "capitmu", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "hashquark", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "ducapital", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotxplorerio", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "pnp", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexcore", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "hofancrypto", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "draperdragon", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "coingecko", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "satoshi", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexlab", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "mrtrump", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "elitex", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "yvalidator", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "ratels", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "rockx", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "hotbit", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "infstones", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "blockfolio", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "blockboost", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "thebottoken#", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "zhcapital", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "cobo", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "tgb", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotask", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "cryptolionsx", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexgeeks", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "bittaker", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "snzholding", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "raketat8", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "wannodes", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "citex2018", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "wetez", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "eon", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "whales", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexunion", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "preangel", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "eatliverun", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexicu", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "matrix", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "everstake", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "nodeasy", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "slowmist", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "alphacoin", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "blackpool", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "link", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "lanhu", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexmainnet", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "meter", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "elink", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "bitwires", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "piexgo", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexhub", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "superiotex", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + }, + { + "id": "iotexbgogo", + "status": true, + "details": { + "reward": { + "annual": 0 + }, + "locktime": 259200, + "minimum_amount": "100000000000000000000" + } + } +] \ No newline at end of file diff --git a/mock/ext-api-data/kava-api_auth_accounts_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json b/mock/ext-api-data/kava-api_auth_accounts_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json new file mode 100644 index 000000000..a08ebead9 --- /dev/null +++ b/mock/ext-api-data/kava-api_auth_accounts_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json @@ -0,0 +1 @@ +{"height":"2283151","result":{"type":"cosmos-sdk/Account","value":{"address":"kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m","coins":[],"public_key":{"type":"tendermint/PubKeySecp256k1","value":"AvgGasyPvRpG68UQ6IGPVKN+HrJix24tgwcYXIcIfsna"},"account_number":"284","sequence":"1"}}} \ No newline at end of file diff --git a/mock/ext-api-data/kava-api_minting_inflation.json b/mock/ext-api-data/kava-api_minting_inflation.json new file mode 100644 index 000000000..e3fdddcc3 --- /dev/null +++ b/mock/ext-api-data/kava-api_minting_inflation.json @@ -0,0 +1,4 @@ +{ + "height": "2251949", + "result": "0.058055354540680354" +} \ No newline at end of file diff --git a/mock/ext-api-data/kava-api_staking_delegators_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_delegations.json b/mock/ext-api-data/kava-api_staking_delegators_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_delegations.json new file mode 100644 index 000000000..c78a91c88 --- /dev/null +++ b/mock/ext-api-data/kava-api_staking_delegators_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_delegations.json @@ -0,0 +1,4 @@ +{ + "height": "2251949", + "result": [] +} \ No newline at end of file diff --git a/mock/ext-api-data/kava-api_staking_pool.json b/mock/ext-api-data/kava-api_staking_pool.json new file mode 100644 index 000000000..acef3bc08 --- /dev/null +++ b/mock/ext-api-data/kava-api_staking_pool.json @@ -0,0 +1,7 @@ +{ + "height": "2251949", + "result": { + "not_bonded_tokens": "1411599189144", + "bonded_tokens": "80779823240237" + } +} \ No newline at end of file diff --git a/mock/ext-api-data/kava-api_staking_validators__status_bonded.json b/mock/ext-api-data/kava-api_staking_validators__status_bonded.json new file mode 100644 index 000000000..a28a80c59 --- /dev/null +++ b/mock/ext-api-data/kava-api_staking_validators__status_bonded.json @@ -0,0 +1,2371 @@ +{ + "height": "2251949", + "result": [ + { + "operator_address": "kavavaloper1qyc2cfl0nw8r95dsdw534x99wq0xcj9rmxpl7z", + "consensus_pubkey": "kavavalconspub1zcjduepqyj4j29k7hn58g7n6ert7mm4m7d0kllrx6h5rzzgpvjdt69r80zsq3az2xq", + "jailed": false, + "status": 2, + "tokens": "23004398541", + "delegator_shares": "23009000000.002955930745759376", + "description": { + "moniker": "Stake Capital", + "identity": "", + "website": "", + "security_contact": "", + "details": "\"Trustless Digital Asset Management\", Twitter: @StakeCapital, operated by @bneiluj @leopoldjoy" + }, + "unbonding_height": "1971549", + "unbonding_time": "2020-05-11T17:02:08.405902954Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.500000000000000000" + }, + "update_time": "2020-02-05T09:55:51.495267155Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1qfy0e2w62g6j4jg5djcqd4py3zsaeqexjplj2d", + "consensus_pubkey": "kavavalconspub1zcjduepqftv90yrm4g4w4mq47rdx9f384yxegfx7qfpkft89x2nlzafv36pq47wgls", + "jailed": false, + "status": 2, + "tokens": "20069063571", + "delegator_shares": "20069063571.000000000000000000", + "description": { + "moniker": "DragonStake", + "identity": "EA61A46F31742B22", + "website": "https://dragonstake.io", + "security_contact": "dragonstake@protonmail.com", + "details": "Forking the Banks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-20T18:38:18.607985797Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1q3y9qga5hf360dmzta67vp54qz25tmv4hhkk4t", + "consensus_pubkey": "kavavalconspub1zcjduepquu3m094f3j9jnklursgngn667tt3rz0ahpt4f7406qzqclc42mnqxlrn7e", + "jailed": false, + "status": 2, + "tokens": "20004700000", + "delegator_shares": "20004700000.000000000000000000", + "description": { + "moniker": "funky", + "identity": "1EBAA06E87B6DD60", + "website": "https://kava-funkyvalidator.nl", + "security_contact": "", + "details": "Validating with love in Holland for the world :)" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.110000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-21T00:42:13.651988876Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1qk0pta4ga5t8p5vv7me8dz32lvcrv2rp098cas", + "consensus_pubkey": "kavavalconspub1zcjduepq3tj0qkd8jw0w4epa3cmdr0mc2rp8qkkyllrged575vacx09alzdszuahy0", + "jailed": false, + "status": 2, + "tokens": "5515168654", + "delegator_shares": "5515168654.000000000000000000", + "description": { + "moniker": "silver", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-06T12:51:42.070726745Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvl7z9xh", + "consensus_pubkey": "kavavalconspub1zcjduepqfkq6kfq6v3avvrc6qvh0tr6h97qhqxcxw6yhmsgwrclpm3qdqwwq4zl4kc", + "jailed": false, + "status": 2, + "tokens": "124252239542", + "delegator_shares": "124252239542.000000000000000000", + "description": { + "moniker": "WeStaking", + "identity": "DA9C5AD3E308E426", + "website": "https://westaking.io", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-05-13T01:35:13.408787775Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1pn5k9c5pxmg5f0rycpl9rrx6k6mk85scxf06zx", + "consensus_pubkey": "kavavalconspub1zcjduepq5gqsp02excuz03zequ5xkygsj8t0su4g46p00q9p0se5kkhr2fmsusw7w7", + "jailed": false, + "status": 2, + "tokens": "22999900000", + "delegator_shares": "22999900000.000000000000000000", + "description": { + "moniker": "Stir", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:45:39.203670522Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1phd8jz25lumudc7ac7rhmupvcqcv7lg3c8dprc", + "consensus_pubkey": "kavavalconspub1zcjduepquugppwhq0s4t5q8vh6n3j0t4t3susfasdfapa0zp8a8c36tpgj6qpqvs3s", + "jailed": false, + "status": 2, + "tokens": "2116667666660", + "delegator_shares": "2116667666660.000000000000000000", + "description": { + "moniker": "the_valiator", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-13T08:47:32.032003423Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1pceqe8we7drpfqrutchwy3f99800hhzuw6cc84", + "consensus_pubkey": "kavavalconspub1zcjduepqypw0nlaweu77hnlmy37gy82d0cn57g07yy9qrkm36tx5zhp6rjzqzfqta0", + "jailed": false, + "status": 2, + "tokens": "23459640449", + "delegator_shares": "23459640449.000000000000000000", + "description": { + "moniker": "Galaxy", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-25T09:53:43.24669958Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1rgcgqmnkeffks7enrv6hk5u4wg3nzfkmqlzjqd", + "consensus_pubkey": "kavavalconspub1zcjduepqv3f0m888swgzamf2mh3vh2gaehredz9uktv9rjcyfdjzvzvsthks4e5f4t", + "jailed": false, + "status": 2, + "tokens": "21000000000", + "delegator_shares": "21000000000.000000000000000000", + "description": { + "moniker": "syncnode", + "identity": "F422F328C14AFBFA", + "website": "wallet.syncnode.ro", + "security_contact": "", + "details": "https://www.linkedin.com/in/gbunea/" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.190000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-26T09:09:30.282258822Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1yrm63pqvld8uyzkavz55p2cktpm2gm8jd8xxlu", + "consensus_pubkey": "kavavalconspub1zcjduepq6nje57k4x0n0uua5dl26ufpgj9jw2n945hkrv066fv54924vnmeq60d92r", + "jailed": false, + "status": 2, + "tokens": "100010000000", + "delegator_shares": "100010000000.000000000000000000", + "description": { + "moniker": "Nodeasy.com", + "identity": "F7BABF2C95B02A9F", + "website": "https://www.nodeasy.com", + "security_contact": "", + "details": "Nodeasy.com,助你进入Staking时代!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-12-04T03:53:57.870109232Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1yjj2wfers947l6n5pynpgsqlz7svc5n8ssl6ye", + "consensus_pubkey": "kavavalconspub1zcjduepqftnrqaely46s7tzfkczuqfecuk3664wks5www53x6cj7rtl90zhqq6pacf", + "jailed": false, + "status": 2, + "tokens": "20410000001", + "delegator_shares": "20410000001.000000000000000000", + "description": { + "moniker": "StakingHub", + "identity": "25D7A4013B5C2A8F", + "website": "http://www.stakinghub.net/", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-14T23:30:14.565194467Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1yna6lete8nwwwctsalzdg04ldqaz73gtn33ydq", + "consensus_pubkey": "kavavalconspub1zcjduepqzwu26st99545k4qp79vuuslynk5qaxne9z4ucjfzs5g6646klwrqg5dxfa", + "jailed": false, + "status": 2, + "tokens": "23163160000", + "delegator_shares": "23163160000.000000000000000000", + "description": { + "moniker": "ChainodeTech", + "identity": "E34BF744FF5BA8A9", + "website": "https://chainode.tech/", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:35:31.864391537Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper196anr2ycsalg806dz29afklnecuaupvkh5qz6c", + "consensus_pubkey": "kavavalconspub1zcjduepqh525w7mx9apyra8jqeclcs90e6u9p22jrqaw8ymuf7mug2m5cg6sw7v7yu", + "jailed": false, + "status": 2, + "tokens": "50894061712", + "delegator_shares": "50894061712.000000000000000000", + "description": { + "moniker": "Phorest 🌲", + "identity": "A5281CA10EBCDCB5", + "website": "http://phorest.xyz/kava", + "security_contact": "", + "details": "Secure and stable PoS validator" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2020-01-20T14:02:20.813362703Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1xzud24na9tucauc7lf6pjk84kqsgq3eq747ta7", + "consensus_pubkey": "kavavalconspub1zcjduepqncgh9yjqhyk4ezjkmfsugetqv3t3t59ddtu5qnaee5k4aam9x6wsj27w8a", + "jailed": false, + "status": 2, + "tokens": "23158079821", + "delegator_shares": "23160395806.729217551585427189", + "description": { + "moniker": "goose", + "identity": "EE700892E1359CE4", + "website": "", + "security_contact": "honk", + "details": "honk. honk." + }, + "unbonding_height": "1217698", + "unbonding_time": "2020-03-12T10:11:32.17419165Z", + "commission": { + "commission_rates": { + "rate": "0.250000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-12-19T22:27:40.022974742Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1x9hq3rjc48t5upcsr3c209ycgekfasne3l5nkc", + "consensus_pubkey": "kavavalconspub1zcjduepqvrf8r43ymaj39x73luu4qsp9sn4sw4t2lh77799mau2739xtrlnsqxyqju", + "jailed": false, + "status": 2, + "tokens": "32933474240", + "delegator_shares": "32933474240.000000000000000000", + "description": { + "moniker": "Masternode24.de", + "identity": "7EBA7730A85C865C", + "website": "https://masternode24.de/", + "security_contact": "", + "details": "Investieren Sie mit uns zusammen in die besten Blockchain Projekte" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-04-13T19:49:42.142115841Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1xftqdxvq0xkv2mu8c5y0jrsc578tak4m9u0s44", + "consensus_pubkey": "kavavalconspub1zcjduepqngw3s4hpzj8xscq6dfg4m8a6qeh5xwau0sjrknmlvg2lqdlgp0zszj7ewc", + "jailed": false, + "status": 2, + "tokens": "37775800000", + "delegator_shares": "37775800000.000000000000000000", + "description": { + "moniker": "Ping.pub", + "identity": "6EA723DA332200B2", + "website": "", + "security_contact": "", + "details": "We are one of the most secure and stable validator, welcome to delegate to us. 我们是最安全,最稳定,性价比最高的验证人节点,欢迎委托给我们!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.020000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-21T09:12:17.124698721Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1xka27j0jvmq97yunj5wp8fv242lycmax8ejlaf", + "consensus_pubkey": "kavavalconspub1zcjduepqx4zjl7vsh8pg4l3ndceu88h3027q0vvmpf7anv5c4xxq0htng5kqf24q07", + "jailed": false, + "status": 2, + "tokens": "2827139316200", + "delegator_shares": "2827139316200.000000000000000000", + "description": { + "moniker": "page2", + "identity": "", + "website": "https://coinmarketcap.com/2/", + "security_contact": "", + "details": "Lorem Ipsum" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1xhxzmj8fvkqn76knay9x2chfra826369dhdu2c", + "consensus_pubkey": "kavavalconspub1zcjduepqwsmxfu5vdulvnrwej06v4jj5hvdxxqqk82flvznhxkh5whrdnxms2z2kjx", + "jailed": false, + "status": 2, + "tokens": "929346000000", + "delegator_shares": "929346000000.000000000000000000", + "description": { + "moniker": "Figment Networks", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper18zksjhrefqew0zahmts894p8asscufxvdfq702", + "consensus_pubkey": "kavavalconspub1zcjduepq7qm0l9hy8m8a4my03x7rfvcy3vru0y0kv29n2fwcpmrvjda8n23skzza6m", + "jailed": false, + "status": 2, + "tokens": "14040219", + "delegator_shares": "14040219.000000000000000000", + "description": { + "moniker": "Consulnode", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-04T19:27:58.259245834Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper18s9m5d5cjf0humjv7mkq8pm47kchwm0r0369cx", + "consensus_pubkey": "kavavalconspub1zcjduepqphfe0vnahkpurcc6jn3kesfch6c0afnph8qv9ryx29gpec7rtf3q968vu3", + "jailed": false, + "status": 2, + "tokens": "20010000000", + "delegator_shares": "20010000000.000000000000000000", + "description": { + "moniker": "Stake5 Labs", + "identity": "C7595F18CC5D4FA6", + "website": "https://www.stake5labs.com", + "security_contact": "", + "details": "Professional PoS node contributor" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:01:13.609429004Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper18cf35l7req0k6ulqapeyv830mrrucn9xj87plr", + "consensus_pubkey": "kavavalconspub1zcjduepq7rr7drhvr6d67nydvwxtcqv3k0uv6krfn9ktm23l77eqrra9af9s828zrk", + "jailed": false, + "status": 2, + "tokens": "1171728959900", + "delegator_shares": "1171846144514.451445144514451445", + "description": { + "moniker": "mxcpospool", + "identity": "", + "website": "https://www.mxc.co", + "security_contact": "", + "details": "" + }, + "unbonding_height": "1433843", + "unbonding_time": "2020-03-29T19:11:06.277346205Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-13T10:05:51.300009009Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1g20mhvcpjxp6gzlwhtfcphjehwcl2njqydgu7q", + "consensus_pubkey": "kavavalconspub1zcjduepqcg7v7vpgw7tj2f4z6yle5vpwutm3n5zjmlx2dpypphxd0cdvyaeqyeyteg", + "jailed": false, + "status": 2, + "tokens": "23184200000", + "delegator_shares": "23184200000.000000000000000000", + "description": { + "moniker": "pi-londoner", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-02-10T23:44:11.226734593Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1gtd040dmljyaty9tkhq0mlqz7saer48v4d608x", + "consensus_pubkey": "kavavalconspub1zcjduepqqy2kzt636d5ak6l6gxsxexgtadcm8d59qh3wumgtswpa8hau7apsk4ecma", + "jailed": false, + "status": 2, + "tokens": "35931185577", + "delegator_shares": "35931185577.000000000000000000", + "description": { + "moniker": "kava.bi23", + "identity": "EB3470949B3E89E2", + "website": "https://kava.bi23.com", + "security_contact": "", + "details": "Bi23 focuses on the Crypto-Assets, providing customers with Staking and DeFi services." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-12-04T23:42:01.494010426Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1g4qpetrj59a29e4wxpe74x93q4df2czjh8r9ak", + "consensus_pubkey": "kavavalconspub1zcjduepqe3evdke2eyzv7ngkwj0w4qarpqad47s6eqsqavesmzhz664ewmzsre8fkj", + "jailed": false, + "status": 2, + "tokens": "466602000000", + "delegator_shares": "466602000000.000000000000000000", + "description": { + "moniker": "IOSG", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1ffcujj05v6220ccxa6qdnpz3j48ng024ykh2df", + "consensus_pubkey": "kavavalconspub1zcjduepqxzqld0trat9nu9j53rzxwvpnpjekxf02eeg8mw3xewjky2qgy69sgh0tcw", + "jailed": false, + "status": 2, + "tokens": "2303407078450", + "delegator_shares": "2303407078450.000000000000000000", + "description": { + "moniker": "🐠stake.fish", + "identity": "90B597A673FC950E", + "website": "http://stake.fish", + "security_contact": "", + "details": "stake.fish is a reliable validator for PoS blockchains. Stake with us. We know staking." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-12-03T18:59:42.821933888Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1fmas0qlsucg4qwf8mqyrylcg3uluz2ffg8952q", + "consensus_pubkey": "kavavalconspub1zcjduepqkv4fkh6u8l068xusy5dhz2jpz969nzszntuavsc0uu6sxxr9wafqewxkac", + "jailed": false, + "status": 2, + "tokens": "22631605772", + "delegator_shares": "22631605772.000000000000000000", + "description": { + "moniker": "mintonium", + "identity": "0FF7C542EF9422AB", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-15T14:00:18.218278987Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper12qn7y04wzr5s3h4dmdtre4q9f4nvc03a9a9qsz", + "consensus_pubkey": "kavavalconspub1zcjduepqsnl9ahysm5hypmpfuwyqkha280aa9ushdlvvqza4u7rfmf0pvdxqlla0wj", + "jailed": false, + "status": 2, + "tokens": "22994500500", + "delegator_shares": "22999100000.000000000000000000", + "description": { + "moniker": "dexhybrid", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "2111209", + "unbonding_time": "2020-05-23T00:58:22.825067041Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.020000000000000000" + }, + "update_time": "2019-11-16T14:33:31.092253347Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper12r77hhj6ylvvl4etjm0fmpzh07jum8u7qqd695", + "consensus_pubkey": "kavavalconspub1zcjduepq3ndp4jxqsvxlp5crspvu6tcra7zg7cnnxzm3hx6sxhcd409ytzyskcadfv", + "jailed": false, + "status": 2, + "tokens": "10000000", + "delegator_shares": "10000000.000000000000000000", + "description": { + "moniker": "stefansky", + "identity": "878AB3284CD8CBED", + "website": "http://stefancondurachi.com", + "security_contact": "", + "details": "Software Architect" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-02-03T05:32:50.725944775Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "kavavaloper129kkennsm7na34lu6sn4kwxp7ewes58y4fx6y9", + "consensus_pubkey": "kavavalconspub1zcjduepqz354kpmk0970fpvhw6va6ufhasrnh4sgzh82cfd5egm9ggl5gy6qlgwqjt", + "jailed": false, + "status": 2, + "tokens": "23011000000", + "delegator_shares": "23011000000.000000000000000000", + "description": { + "moniker": "stake.zone", + "identity": "0A888728046018EC", + "website": "http://stake.zone", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.040000000000000000" + }, + "update_time": "2019-11-15T14:01:07.22222101Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper12g40q2parn5z9ewh5xpltmayv6y0q3zs6ddmdg", + "consensus_pubkey": "kavavalconspub1zcjduepq0plta99ns8ec5h5sj8x4ufzkdpsz6xu7ckp62hkagfxey242qzgstm0ldw", + "jailed": false, + "status": 2, + "tokens": "5089172619037", + "delegator_shares": "5089172619037.000000000000000000", + "description": { + "moniker": "P2P.ORG - P2P Validator", + "identity": "E12F4695036D8072", + "website": "https://p2p.org", + "security_contact": "vladimir.m@p2p.org", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1t5l8ht0wxpd4lpe4cweftrpg5kyn3qp437yvnr", + "consensus_pubkey": "kavavalconspub1zcjduepqe58zj7f5zjqu023l3sd96qwurtzy7ayv2549z6mca8zmalvtlxfs80qsja", + "jailed": false, + "status": 2, + "tokens": "20650150000", + "delegator_shares": "20650150000.000000000000000000", + "description": { + "moniker": "DelegaNetworks", + "identity": "1BED7C08416A619F", + "website": "https://delega.io", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-24T20:37:25.840600387Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1vyx7wt8s8dwcspdt7dy49sq4l3jwyhxyndakmm", + "consensus_pubkey": "kavavalconspub1zcjduepq2v03gwaywadc7ar423rxmy7k7ev3y3tkvsetq7w30j0whymjkacsxjg9lt", + "jailed": false, + "status": 2, + "tokens": "1513306965388", + "delegator_shares": "1513306965388.000000000000000000", + "description": { + "moniker": "InfStones", + "identity": "39A41C2FDE0AD040", + "website": "https://infstones.io", + "security_contact": "", + "details": "Fueling Blockchain Beyond Infinity" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1vfawvtzvmcjkpqzhezvhk9q5tv5t7x8smz95uu", + "consensus_pubkey": "kavavalconspub1zcjduepq2yhf7ntk9dkkqpg07ead9nzjmldf2ar6tx6uz8jeaqjedrj9keqsq0hn02", + "jailed": false, + "status": 2, + "tokens": "23189000000", + "delegator_shares": "23189000000.000000000000000000", + "description": { + "moniker": "Newroad Network", + "identity": "91FAC10CA3718A17", + "website": "https://newroad.network/kava/", + "security_contact": "", + "details": "We provide a professional delegation service for multiple Proof of Stake networks. We use a secure and redundant setup. Visit our website for more information." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.080000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-04-28T16:16:55.826119569Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1vw35vclatlrcmzuaxf2fleyuk38xa7xf4vdaq2", + "consensus_pubkey": "kavavalconspub1zcjduepqnrpursauds6wjnqht0979kjr0pvk5jp4c0cv46feazqv4qappqsqn5rd22", + "jailed": false, + "status": 2, + "tokens": "125050100000", + "delegator_shares": "125050100000.000000000000000000", + "description": { + "moniker": "hashquark", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1vw4t8ge2ephu0wuhcmclcw04ag2vzj9rpdme2x", + "consensus_pubkey": "kavavalconspub1zcjduepq0fjxw9wq8swcrk26j2vk8qm90d0vn94c2c7cs0ru5rgy2zlyv5eq8q5kvc", + "jailed": false, + "status": 2, + "tokens": "20153000000", + "delegator_shares": "20153000000.000000000000000000", + "description": { + "moniker": "UbikCapital", + "identity": "8265DEAF50B61DF7", + "website": "https://ubik.capital", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-12-25T21:46:08.338409716Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1vuylvflgy75d8zr07ta8x0gcqynvkvw70et853", + "consensus_pubkey": "kavavalconspub1zcjduepqvk6tye9w7399g7xys6j5ycw5rly8wz92mp0pevgmrv30qc4nva5sc2u25u", + "jailed": false, + "status": 2, + "tokens": "1999980100000", + "delegator_shares": "1999980100000.000000000000000000", + "description": { + "moniker": "Lemniscap", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1dwae0ny4uuvacucakm9v8r8mxhw82zack4cn7y", + "consensus_pubkey": "kavavalconspub1zcjduepq3rfkl40umrfy0wq9u9m5mc5zv30x4lmj08vup2u5d90t4fu3qe7qvq5scl", + "jailed": false, + "status": 2, + "tokens": "3317977023616", + "delegator_shares": "3317977023616.000000000000000000", + "description": { + "moniker": "OKExPool", + "identity": "", + "website": "www.okex.com/pool", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-20T02:25:09.919481267Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1dj63l3z0smqa8au5yek37nmj0xd60zs9dwmdh0", + "consensus_pubkey": "kavavalconspub1zcjduepqq0hj2jx5x7p65t56c7s750e85yp0u6xvydk6eh5m45xq755rjqlsthzygr", + "jailed": false, + "status": 2, + "tokens": "20100000782", + "delegator_shares": "20100000782.000000000000000000", + "description": { + "moniker": "Yn", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:04:52.626128649Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1dntlhrw3jrej6ssdp64yfmkkz08ykyx4n7hphh", + "consensus_pubkey": "kavavalconspub1zcjduepqxd9wm06lw0p6nrysw2ecmusgrmsq6438ht4wh7gx64a0m6vnu4qs7jhyjk", + "jailed": false, + "status": 2, + "tokens": "4001052087322", + "delegator_shares": "4001052087322.000000000000000000", + "description": { + "moniker": "Staked", + "identity": "E7BFA6515FB02B3B", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-03T16:23:23.639110694Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1dede4flaq24j2g9u8f83vkqrqxe6cwzrxt5zsu", + "consensus_pubkey": "kavavalconspub1zcjduepqstxrft39yrg5hgalcnjqurms5tj2yqpw9y85axv9gsxyld62cneqg6k7nk", + "jailed": false, + "status": 2, + "tokens": "109213032359", + "delegator_shares": "109213032359.000000000000000000", + "description": { + "moniker": "Stakin by POS Bakerz", + "identity": "3AFAE7268F4DFD10", + "website": "http://stakin.com/", + "security_contact": "", + "details": "Your Trusted Crypto Rewards" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-05-07T20:51:51.964006239Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1davtd9w5yadvlg5x7aw0kpkyhckk5m5ecrmnyl", + "consensus_pubkey": "kavavalconspub1zcjduepq9x39e7g3m2hv8v6nxcx2lmy6fzaeqmvdz4uqtpm8qaxtr6527yrsh3fkgl", + "jailed": false, + "status": 2, + "tokens": "23000000000", + "delegator_shares": "23000000000.000000000000000000", + "description": { + "moniker": "Cyberili", + "identity": "3554F49719B1BF6F", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:55:31.701406451Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1wtcn3ylrsp4qp4urlhkf78kkt8f2ch7p0f0p98", + "consensus_pubkey": "kavavalconspub1zcjduepqjffmrcy39vaecs9rjaju3hzq97nggr2l0zg96k2u3c54mfx20hks43wvdy", + "jailed": false, + "status": 2, + "tokens": "23145977490", + "delegator_shares": "23145977490.000000000000000000", + "description": { + "moniker": "007", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.300000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-04-07T07:36:37.293429517Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1wu8m65vqazssv2rh8rthv532hzggfr3h9azwz9", + "consensus_pubkey": "kavavalconspub1zcjduepqqg29usle4d3hgt4eadn3epppa2h6dsga9mj6sxvyj5prchufgr5qmrneka", + "jailed": false, + "status": 2, + "tokens": "5005157202698", + "delegator_shares": "5005157202698.000000000000000000", + "description": { + "moniker": "Binance Staking", + "identity": "", + "website": "https://binance.com", + "security_contact": "", + "details": "Exchange the world!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1wacmlkst8s39fq83tqhlcuuacts2z6lvwfq8hv", + "consensus_pubkey": "kavavalconspub1zcjduepq8rt2a49hdz0tfp2gty7upe27k7gwkavf3kh60np940atacmwdxjs05uft3", + "jailed": false, + "status": 2, + "tokens": "4835289500", + "delegator_shares": "4835289500.000000000000000000", + "description": { + "moniker": "tokenweb.io", + "identity": "", + "website": "https://tokenweb.io", + "security_contact": "", + "details": "put your tokens to work" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-22T13:34:07.741893579Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1006e7kwuhthdtxe0d90pc209cy803ehem0dg0q", + "consensus_pubkey": "kavavalconspub1zcjduepq78wv8373p09g0kx9z02rm0vvfwy999d74wr2mnzplwmfphy7lxkshkgm54", + "jailed": false, + "status": 2, + "tokens": "251000000", + "delegator_shares": "251000000.000000000000000000", + "description": { + "moniker": "vcmain", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.030000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-20T19:53:59.310652973Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper10m3hjapny44txmgr47rf277364htgqpr646cty", + "consensus_pubkey": "kavavalconspub1zcjduepqy8galhn5awgvk5etjtuugkja6k2s8z0jsslharpprczjtec73gpskvt0pz", + "jailed": false, + "status": 2, + "tokens": "1010061607032", + "delegator_shares": "1010061607032.000000000000000000", + "description": { + "moniker": "HotBitPool", + "identity": "", + "website": "https://www.hotbit.io", + "security_contact": "", + "details": "Cryptocurrency Exchange" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-04-07T04:00:47.76026917Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1spkjjtwks5zt0dqexj8rv8ljwmwxe8ufkraukq", + "consensus_pubkey": "kavavalconspub1zcjduepq9gppak7hsjrwvyxz2y9hy830gzsx2r4nax43vh2lprj0wj3rvghsyu6xev", + "jailed": false, + "status": 2, + "tokens": "22950000000", + "delegator_shares": "22950000000.000000000000000000", + "description": { + "moniker": "Jupiter.IAM", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-17T11:35:54.989770823Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1srhded4xw0krcwlvddtcyycuh70fp5ry9yvp86", + "consensus_pubkey": "kavavalconspub1zcjduepq64ugztwcunjrpema5pqwherkfznms8ykc4jx7syc6tm5ztv58keqxlc6fv", + "jailed": false, + "status": 2, + "tokens": "1965109266679", + "delegator_shares": "1965109266679.000000000000000000", + "description": { + "moniker": "TRGCapital", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-12-12T17:38:19.894601876Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1s8akp0nq7z7vuf5g9agdswcwq7vm9uwudk0han", + "consensus_pubkey": "kavavalconspub1zcjduepqpgz29c6efzyj96y0kkjrxns67nsm5t3rae0ra2nmrx4fm5j33nkqn066rz", + "jailed": false, + "status": 2, + "tokens": "22950000000", + "delegator_shares": "22950000000.000000000000000000", + "description": { + "moniker": "IvoryTower", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-17T02:12:20.831453541Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper13fxkk4730cqglgdv7w0mdelyx07myyq76uf9f3", + "consensus_pubkey": "kavavalconspub1zcjduepquwqhhvst3t6pg7rzutmvr3dma46ux6nggfxrju4f6u2dza9n3l7s54jgu7", + "jailed": false, + "status": 2, + "tokens": "23213610000", + "delegator_shares": "23215931593.159315931593159315", + "description": { + "moniker": "Finantra.com", + "identity": "", + "website": "http://finantra.com", + "security_contact": "", + "details": "" + }, + "unbonding_height": "1122467", + "unbonding_time": "2020-03-04T18:59:03.214161979Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-03-14T19:38:24.407313925Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper13vstf6ecmfe4p0gaufumk569sdawhtrf8gu56h", + "consensus_pubkey": "kavavalconspub1zcjduepq2ye3234dt2jes9g49mf5sdy7f7xfshekg5xyjm7vq7m07s9uq82qger9yk", + "jailed": false, + "status": 2, + "tokens": "23081092090", + "delegator_shares": "23081092090.000000000000000000", + "description": { + "moniker": "QuantaFrontier.com", + "identity": "", + "website": "https://QuantaFrontier.com", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-03-10T19:08:38.751434231Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper13dfu6et0m8zm4hachudvn62w0c2zvcmrqn8cs3", + "consensus_pubkey": "kavavalconspub1zcjduepqcctrta82mcm79j0e6ttgguekmljvud0y4rlggrm9uw9t49qemujsd69h59", + "jailed": false, + "status": 2, + "tokens": "23144338847", + "delegator_shares": "23144338847.000000000000000000", + "description": { + "moniker": "Sunshine", + "identity": "24DB71E8B5076192", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.300000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-04-05T16:35:57.63239062Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1jyuv7z9at27elvmnmzh2v39dc06r9kjcy59xkr", + "consensus_pubkey": "kavavalconspub1zcjduepqcznteuyudn9zmfzyu6cksgh9qv3e9sc9fkyu32djy9d29ertyjrqfwcnvj", + "jailed": false, + "status": 2, + "tokens": "2588950000000", + "delegator_shares": "2588950000000.000000000000000000", + "description": { + "moniker": "DAF", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1j26c4k2jj9tv95whdhva3e8v2fcm4s3dsgstd2", + "consensus_pubkey": "kavavalconspub1zcjduepq3ra0zhkgeyqzksspztcx475dtlra5lckdpzwht29mk9fuepnkjqsw2rly7", + "jailed": false, + "status": 2, + "tokens": "3148249101016", + "delegator_shares": "3148249101016.000000000000000000", + "description": { + "moniker": "DokiaCapital", + "identity": "", + "website": "https://staking.dokia.cloud", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "0.120000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1jhraz4ftxl2pd37knmeua7wjxghmlskwf7x8pf", + "consensus_pubkey": "kavavalconspub1zcjduepq6rxswfd9puq5t7jlp52cetv5s7cqm4l4n5tx4gqsclg9ngswe45qwhz2dm", + "jailed": false, + "status": 2, + "tokens": "23443000000", + "delegator_shares": "23443000000.000000000000000000", + "description": { + "moniker": "mariposa2", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "1.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-12-26T13:44:37.328086675Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1jlzx4js09d9zzyuhuz8sfdweklrapzacuhsxq5", + "consensus_pubkey": "kavavalconspub1zcjduepqg94y638yaj7es28zdktmar4jn9wu0v2l4h8mr40gerr2rek8q3rq9d3gh6", + "jailed": false, + "status": 2, + "tokens": "3153557198531", + "delegator_shares": "3153557198531.000000000000000000", + "description": { + "moniker": "shiprekt", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1jl42l225565y3hm9dm4my33hjgdzleucqryhlx", + "consensus_pubkey": "kavavalconspub1zcjduepqtlmej0vprfmun69nsnmuv56j3dctzw90tmk0f805lqxcqn9sr77s4nzkx0", + "jailed": false, + "status": 2, + "tokens": "69171541930", + "delegator_shares": "69171541930.000000000000000000", + "description": { + "moniker": "0% commission: melea Validator", + "identity": "4BE49EABAA41B8BF", + "website": "https://meleatrust.com/kava/", + "security_contact": "meleacrypto@gmail.com", + "details": "Free Validator service at 0% Commission secure and trusted, awarded in Game Of Steaks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-12-27T14:23:19.174760869Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1nxgg4grsc0fwh893mks62d3x3r6uazgpj3m3cr", + "consensus_pubkey": "kavavalconspub1zcjduepqkk7jeymtt9rk3jlhxtxu95akmxfusj44mqq2wuq8c2hckulpga0q4yrauv", + "jailed": false, + "status": 2, + "tokens": "23085863116", + "delegator_shares": "23085863116.000000000000000000", + "description": { + "moniker": "Easy 2 Stake", + "identity": "2C877AC873132C91", + "website": "www.easy2stake.com", + "security_contact": "", + "details": "Easy.Stake.Trust. As easy and as simple as you would click next. Complete transparency and trust with a secure and stable validator." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:00:10.631092707Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1ndkn5rdl9n929am6q2zt9ndfhhggcxkhetna90", + "consensus_pubkey": "kavavalconspub1zcjduepq6ptpugu70hqgms3g3neyjx4fnse42tthm294g6vp5njpmgtw4wcs5l07lf", + "jailed": false, + "status": 2, + "tokens": "94355033398", + "delegator_shares": "94355033398.000000000000000000", + "description": { + "moniker": "stakewolf", + "identity": "F012ABCA5EA51F6B", + "website": "", + "security_contact": "", + "details": "Stake is Money, Stakewolf is Stake" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.000000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2020-04-14T01:18:50.785865364Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1njvaku4qg9pxmx9jgjks36xrxfd6fyqs3tgs4d", + "consensus_pubkey": "kavavalconspub1zcjduepqsxtm3s99l58x9e3sqfxx4z88v6t4pyhku6fnu60drwmq8zm4jwjqx257u9", + "jailed": false, + "status": 2, + "tokens": "1090886500000", + "delegator_shares": "1090886500000.000000000000000000", + "description": { + "moniker": "BitMax Staking", + "identity": "", + "website": "https://bitmax.io/", + "security_contact": "", + "details": "Trading Platform Industry Leader driven by Product Innovation" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-15T09:09:05.545733701Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1nnwwu4km0alut2q8vhg7zjt45wyehddpwlfrmj", + "consensus_pubkey": "kavavalconspub1zcjduepqey9flxqkdw5ewlskac3wltu4yl93asdamt66prm393zc8g93dcuszezutf", + "jailed": false, + "status": 2, + "tokens": "5744799001", + "delegator_shares": "5745373480.003702086936008957", + "description": { + "moniker": "Wetez", + "identity": "26FA2B24F46A98EF", + "website": "https://www.wetez.io", + "security_contact": "", + "details": "Wetez is the most professional team in the POS ( Proof of Stake) field.Wetez是POS领域最专业的团队,为POS带来的权益做更多赋能。" + }, + "unbonding_height": "448243", + "unbonding_time": "2020-01-11T04:03:40.112446434Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-17T01:33:27.008856884Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper15kwwzz908wl0qv4w66a5ee70kytpmfc9khvah6", + "consensus_pubkey": "kavavalconspub1zcjduepq8ylkkt83ktmljrmmk7evkj600j3p9xjnm4kf44z33hyr3cum448sqw2a6j", + "jailed": false, + "status": 2, + "tokens": "6118996081", + "delegator_shares": "6118996081.000000000000000000", + "description": { + "moniker": "Staking4All", + "identity": "", + "website": "https://www.staking4all.org", + "security_contact": "", + "details": "Validator for Proof of Stake blockchains. Delegate to us for a easy staking experience" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-25T15:53:47.321864774Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper15urq2dtp9qce4fyc85m6upwm9xul3049dcs7da", + "consensus_pubkey": "kavavalconspub1zcjduepqsglrgfudcqw4la7e54lfdu2va9z5gd4r8z6wrwe8m5rtz3d2vtsq55njyr", + "jailed": false, + "status": 2, + "tokens": "2224337117663", + "delegator_shares": "2224559573585.687076200777774018", + "description": { + "moniker": "Chorus One", + "identity": "00B79D689B7DC1CE", + "website": "https://chorus.one", + "security_contact": "security@chorus.one", + "details": "Secure Kava and shape its future by delegating to Chorus One, a highly secure and stable validator. By delegating, you agree to the terms of service." + }, + "unbonding_height": "2033098", + "unbonding_time": "2020-05-16T16:56:53.71682445Z", + "commission": { + "commission_rates": { + "rate": "0.075000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper14fkp35j5nkvtztmxmsxh88jks6p3w8u7p76zs9", + "consensus_pubkey": "kavavalconspub1zcjduepqlgrd20pqzw4dmkdkg3nd65mra077pjne8l0d43wsvw93y9dw450smyh79n", + "jailed": false, + "status": 2, + "tokens": "23744500000", + "delegator_shares": "23744500000.000000000000000000", + "description": { + "moniker": "Bit Cat🐱", + "identity": "FAB46CEEAEAB9FA1", + "website": "https://www.bitcat365.com", + "security_contact": "", + "details": "Secure and stable KAVA validator service from China team" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:01:37.718892109Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper140g8fnnl46mlvfhygj3zvjqlku6x0fwu6lgey7", + "consensus_pubkey": "kavavalconspub1zcjduepqvtvkhh22hgfvp865tj4uwltv0hu7fs3vwmxwrl0n2mdpfuzj0p0qes2k9e", + "jailed": false, + "status": 2, + "tokens": "3536248896890", + "delegator_shares": "3536248896890.000000000000000000", + "description": { + "moniker": "Cosmostation", + "identity": "AE4C403A6E7AA1AC", + "website": "https://www.cosmostation.io", + "security_contact": "", + "details": "Delegate your Kava and start earning your staking rewards." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.150000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-18T01:27:53.436530462Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper14kn0kk33szpwus9nh8n87fjel8djx0y02c7me3", + "consensus_pubkey": "kavavalconspub1zcjduepqk8fq7ssjps5r40j32lmhxrdzfg72k8dknc3xndljjtlghc9u9nrshrlf3r", + "jailed": false, + "status": 2, + "tokens": "2888251903903", + "delegator_shares": "2888251903903.000000000000000000", + "description": { + "moniker": "Forbole", + "identity": "2861F5EE06627224", + "website": "https://www.forbole.com", + "security_contact": "info@forbole.com", + "details": "Professional PoS validator based in Hong Kong" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.095000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1kgddca7qj96z0qcxr2c45z73cfl0c75p27tsg6", + "consensus_pubkey": "kavavalconspub1zcjduepqzah30dnsz855gnufkqlqnq50ksyc4jetprhz4ugg2rmuzhh3gvwsfxan38", + "jailed": false, + "status": 2, + "tokens": "2106193827976", + "delegator_shares": "2106193827976.000000000000000000", + "description": { + "moniker": "ChainLayer", + "identity": "AD3CDBC91802F94A", + "website": "https://www.chainlayer.io", + "security_contact": "", + "details": "Secure and reliable validator. TG: https://t.me/chainlayer" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.100000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1kwj4l5putuymgxw9kx8emh3e5dpaca0hnf3zdy", + "consensus_pubkey": "kavavalconspub1zcjduepqmqwfzwnmjdnkmt9k75k3q7rez3lr08m9fqev06rh6m2sdke8kmusjhywm9", + "jailed": false, + "status": 2, + "tokens": "23230000000", + "delegator_shares": "23230000000.000000000000000000", + "description": { + "moniker": "InChainWorks", + "identity": "BE448F9ECAB40ABE", + "website": "https://inchain.works", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-06T10:37:03.352901001Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1k4kxxfkhhwvyzxxxgksefkzpxahp9wfc572esl", + "consensus_pubkey": "kavavalconspub1zcjduepqt0k39t3zmz460are7rf9n97u20qhfmukp8ujeqhe0jg2q7ye99cqprr8nr", + "jailed": false, + "status": 2, + "tokens": "23388000000", + "delegator_shares": "23388000000.000000000000000000", + "description": { + "moniker": "Mr.K", + "identity": "74D3AF53635231D9", + "website": "", + "security_contact": "", + "details": "Validator on Tendermint base project" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.500000000000000000", + "max_rate": "0.500000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-29T03:49:52.013497324Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1kc6vzheht92jwf0gtzhjk6jjht67rxhal9z04v", + "consensus_pubkey": "kavavalconspub1zcjduepqt8065r783whzn3w47uuhm0t8rw2ke0zda6awa4j5lemlhw029mtqs79pcs", + "jailed": false, + "status": 2, + "tokens": "20028000000", + "delegator_shares": "20028000000.000000000000000000", + "description": { + "moniker": "moonli.me", + "identity": "662AEC27BD90D036", + "website": "https://moonli.me", + "security_contact": "", + "details": "How to Delegete: https://go.moonli.me/kava" + }, + "unbonding_height": "972523", + "unbonding_time": "2020-02-21T16:44:26.247476886Z", + "commission": { + "commission_rates": { + "rate": "0.120000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:03:28.153247409Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1k760ypy9tzhp6l2rmg06sq4n74z0d3rejwwaa0", + "consensus_pubkey": "kavavalconspub1zcjduepqqnxh5k4mhggtdx2u9j9xgq0etpkxpevg333sm954efqema6mn5yqqyf0gw", + "jailed": false, + "status": 2, + "tokens": "25830577485", + "delegator_shares": "25830577485.000000000000000000", + "description": { + "moniker": "novy", + "identity": "5422BE13389B2B4D", + "website": "https://novy.pw", + "security_contact": "", + "details": "Let's validate this network!" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-29T20:44:00.222304348Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1h9ulmhqv5e2373khk6s9n0wtrfc5qavre09fxl", + "consensus_pubkey": "kavavalconspub1zcjduepqjqsd0jkhftta7fuc9e45f3yat25ja9xknzrdqye6zk9kyx40wkaq50hcdv", + "jailed": false, + "status": 2, + "tokens": "23225502889", + "delegator_shares": "23225502889.000000000000000000", + "description": { + "moniker": "alexDcrypto", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.190000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-01-02T22:54:47.953329027Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1hezl6xwva28xt0hk204dllalagenmfsnuu50j6", + "consensus_pubkey": "kavavalconspub1zcjduepqwf05tj86hm83n55lha6zgeyf9jyyz053cwq957nhhv933v9z9sgqdcmt5s", + "jailed": false, + "status": 2, + "tokens": "169401000000", + "delegator_shares": "169401000000.000000000000000000", + "description": { + "moniker": "01node.com", + "identity": "22823CD59617B8E3", + "website": "https://01node.com", + "security_contact": "", + "details": "01node Staking Services" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.150000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:00:18.218278987Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1c9ye54e3pzwm3e0zpdlel6pnavrj9qqvh0atdq", + "consensus_pubkey": "kavavalconspub1zcjduepqc8585309s34yq92calayzy4xc4hu8rrx4pkrymewdy5qyjkx5tjqjgp7tq", + "jailed": false, + "status": 2, + "tokens": "4121140835669", + "delegator_shares": "4121140835669.000000000000000000", + "description": { + "moniker": "StakeWith.Us", + "identity": "609F83752053AD57", + "website": "https://stakewith.us", + "security_contact": "node@stakewith.us", + "details": "Secured Staking Made Easy. Put Your Crypto to Work - Hassle Free. Disclaimer: Delegators should understand that delegation comes with slashing risk. By delegating to StakeWithUs Pte Ltd, you acknowledge that StakeWithUs Pte Ltd is not liable for any losses on your investment." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.250000000000000000", + "max_change_rate": "0.050000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1cj9cdx9mg95lhvpquym08ncgzpjvhmnwdvm5kc", + "consensus_pubkey": "kavavalconspub1zcjduepq3w00ypwl5652c8unvwhn4urpkpcpztkusgqsdztdsq8fhycw224qwlcd33", + "jailed": false, + "status": 2, + "tokens": "933362497", + "delegator_shares": "933362497.000000000000000000", + "description": { + "moniker": "Sifu Ventures", + "identity": "", + "website": "http://sifu.ventures", + "security_contact": "", + "details": "dPos Tokens Investment Fund" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-24T08:49:40.805033852Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1ceun2qqw65qce5la33j8zv8ltyyaqqfctl35n4", + "consensus_pubkey": "kavavalconspub1zcjduepqsqtuf26ph4szcxutxscz5eq0g9tnqvedhdf203cha77m8xlnuy0sy3nky9", + "jailed": false, + "status": 2, + "tokens": "2451388401349", + "delegator_shares": "2451388401349.000000000000000000", + "description": { + "moniker": "sikka", + "identity": "", + "website": "https://sikka.tech", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper168g9nn9vnamhsnjkm7uqqee9f3v07flgwwddf9", + "consensus_pubkey": "kavavalconspub1zcjduepq29lrp34q3dveyt8r2mnc3kd82y5a5dsq39laj6yhkwans0ay2u9smmru3r", + "jailed": false, + "status": 2, + "tokens": "23202449322", + "delegator_shares": "23202449322.000000000000000000", + "description": { + "moniker": "sebytza05", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.140000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:00:18.218278987Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1645czvg787l0jr6mawhs9dm3mljnggj003yed9", + "consensus_pubkey": "kavavalconspub1zcjduepqws4aku5x2z0806kpyd750yzdpwrergpj82akyj0zz4ft6t38c4esdztwm8", + "jailed": false, + "status": 2, + "tokens": "23136261400", + "delegator_shares": "23143203500.319736666961944921", + "description": { + "moniker": "Mike Pocket", + "identity": "C57B29418AE33CC0", + "website": "", + "security_contact": "", + "details": "GO KAVA GO" + }, + "unbonding_height": "2123509", + "unbonding_time": "2020-05-24T00:52:50.9426213Z", + "commission": { + "commission_rates": { + "rate": "0.200000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-08T11:13:06.439174757Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper16lnfpgn6llvn4fstg5nfrljj6aaxyee9z59jqd", + "consensus_pubkey": "kavavalconspub1zcjduepquwh8pq39pwddp3etxk82d3u57kdfnvftgxamx4kcqduk8q02c3xqsyfaaa", + "jailed": false, + "status": 2, + "tokens": "2833230807310", + "delegator_shares": "2833230807310.000000000000000000", + "description": { + "moniker": "pylonvalidator", + "identity": "0979483D4F669CFF", + "website": "https://pylonvalidator.com", + "security_contact": "security@pylonvalidator.com", + "details": "'It doesn't matter whether the cat is black or white, as long as it catches mice.' --Deng Xiaoping" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "1.000000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1m9y0c7j7wxyu3nqtmeevyfzzpga8jhdyqw42wx", + "consensus_pubkey": "kavavalconspub1zcjduepqqpq85gztxdvheh48pugwp624mm6ey6u3464pj80c6s2epa8m9uwq4xr44m", + "jailed": false, + "status": 2, + "tokens": "1255000000000", + "delegator_shares": "1255000000000.000000000000000000", + "description": { + "moniker": "B-Harvest", + "identity": "8957C5091FBF4192", + "website": "https://bharvest.io", + "security_contact": "contact@bharvest.io", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-20T04:34:50.0221158Z" + }, + "min_self_delegation": "1000" + }, + { + "operator_address": "kavavaloper1mu78xhlr705mzgwqykcafp4xy3kgatvwzrww8z", + "consensus_pubkey": "kavavalconspub1zcjduepqhux83t9q55l0em60vq5a0p22zpf6kcqk3qs7cyzcc5huhycp6qnsutwsz3", + "jailed": false, + "status": 2, + "tokens": "21000000000", + "delegator_shares": "21000000000.000000000000000000", + "description": { + "moniker": "joesatri", + "identity": "649DD29EE41766EB", + "website": "", + "security_contact": "", + "details": "Game of Stakes Never Been Jailed Crew | Kava Founder Badge" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.110000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T15:01:47.310662882Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1uvz0vus7ktxt47cermscwe3k9gs7h9ag05sh6g", + "consensus_pubkey": "kavavalconspub1zcjduepq06xpflh9qkvgax8avl4wen49z48svsv4vplxk2jp2p4qx2htckzsfe2mwq", + "jailed": false, + "status": 2, + "tokens": "32995000000", + "delegator_shares": "32995000000.000000000000000000", + "description": { + "moniker": "Genesis Lab", + "identity": "C1A123F2723041F0", + "website": "https://genesislab.net", + "security_contact": "", + "details": "Genesis Lab is a blockchain-focused development company and validation nodes operator in PoS networks" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:15:12.174174763Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1udg4pal8c9gffv4l7zhvza027z0y345gd6esa6", + "consensus_pubkey": "kavavalconspub1zcjduepqpdjehvuwljjjp5se8t9xselu0hlneh2np3vrxwd0f4v6csdahclqktmkdp", + "jailed": false, + "status": 2, + "tokens": "1739652025086", + "delegator_shares": "1739652025086.000000000000000000", + "description": { + "moniker": "ATEAM", + "identity": "0CB9A4E7643FF992", + "website": "", + "security_contact": "", + "details": "Kava_Founding member | Cosmos_GOS: Never Jailed \u0026 Top-Tier | Terra_Validator Drill: Top 3 | IOV_Validator candidates score for mainnet: Top 5 | Lino_Founding Validator Prize Winners: Top 7 | IRISnet_Nyancat: Perfect score" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-19T01:30:06.727558554Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1u0kfndes0pf8dstaunsgumv7scsnmy09p3ln9r", + "consensus_pubkey": "kavavalconspub1zcjduepqxzxd363ej2v0kljvfvy5ff4dka90gnkkfemej9p6rkqv3zac9qhsy8p567", + "jailed": false, + "status": 2, + "tokens": "4370445500000", + "delegator_shares": "4370445500000.000000000000000000", + "description": { + "moniker": "SNZPool", + "identity": "FF2019D4CF1F3185", + "website": "https://snzholding.com", + "security_contact": "", + "details": "SNZ Pool is a professional \u0026 reliable POS validator for a dozen of projects like Cosmos, IRISnet, EOS, ONT, Loom, etc." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2019-11-15T14:18:22.510513847Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1u3jf6c2f85kmjldxsncnhsdp44nac7v5j7vzpc", + "consensus_pubkey": "kavavalconspub1zcjduepqvd3xz6346n447pvl3s3s73ee3zwwn54f4ejwjfue3ppvpjgdfxwqu95mqu", + "jailed": false, + "status": 2, + "tokens": "3304153570689", + "delegator_shares": "3304153570689.000000000000000000", + "description": { + "moniker": "HuobiPool", + "identity": "23536C5BDE3EB949", + "website": "https://www.huobipool.com/", + "security_contact": "", + "details": "Huobi Pool is a sub-brand of Huobi Group, which is an important part of the global ecological strategy of Huobi.Huobi Pool has become one of the largest POS communities in the Asia- Pacific region, the leading POW pool and nodes of a number of public chains." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-12-12T15:50:40.940881395Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1u3hqe2m7vm59l30tyaqd3zurz864dlsg7nq83f", + "consensus_pubkey": "kavavalconspub1zcjduepqrtnnezp4g67f7hh8fs7gtx23pmdfjwu37uqguq4hsrglqkfmyensl4xvdt", + "jailed": false, + "status": 2, + "tokens": "3308604907366", + "delegator_shares": "3308935800933.172872447705074902", + "description": { + "moniker": "Delchain", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "388052", + "unbonding_time": "2020-01-06T09:05:10.544078799Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-05T14:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1u7vsaanwt4e5mdzmxuqurmccxjka3h0ns2n3f5", + "consensus_pubkey": "kavavalconspub1zcjduepq7uy7ln7afmgrfutfpzhyy0llcndntx9q55nl5puqxcq5dqdzrnqswahrha", + "jailed": false, + "status": 2, + "tokens": "1000009950010", + "delegator_shares": "1000009950010.000000000000000000", + "description": { + "moniker": "BiKi Pool", + "identity": "", + "website": "https://www.biki.com", + "security_contact": "", + "details": "Popular Token's Choice" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-04T12:26:32.258743177Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper1aj9r9ll8m72xr5pmxr9fmum88k864tqg39nkfu", + "consensus_pubkey": "kavavalconspub1zcjduepq9nq9gdnvtl5as9sgl92exde7hju797hl20c9htje2chgwnlkwluq8hmtu0", + "jailed": false, + "status": 2, + "tokens": "21000000000", + "delegator_shares": "21000000000.000000000000000000", + "description": { + "moniker": "kytzu", + "identity": "909A480D5643CCC5", + "website": "https://www.linkedin.com/in/calinchitu", + "security_contact": "", + "details": "Blockchain consultant and developer" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.190000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T16:04:53.477387115Z" + }, + "min_self_delegation": "1000000" + }, + { + "operator_address": "kavavaloper1ajwfalplxnhkwhsycfax36yyyxpxz3450s800x", + "consensus_pubkey": "kavavalconspub1zcjduepq33ekkklqez4tdd37mrvptrkawejnj0p5caa0a6c7efqs8n7eg37qa2vega", + "jailed": false, + "status": 2, + "tokens": "61532020969", + "delegator_shares": "61532020969.000000000000000000", + "description": { + "moniker": "Ryabina.io - Staking provider in awesome networks", + "identity": "6B1C8FDD84CF4ACD", + "website": "https://ryabina.io", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.010000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-02-24T18:08:47.865265697Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper17wcggpjx007uc09s8y4hwrj8f228mlwez945ey", + "consensus_pubkey": "kavavalconspub1zcjduepq5jtcd7kxpft40l65gm5p2ecg8rcxp59nml424u88lxkpxu6yl9cq6hxvzd", + "jailed": false, + "status": 2, + "tokens": "23092086042", + "delegator_shares": "23092086042.000000000000000000", + "description": { + "moniker": "Inotel", + "identity": "975D494265B1AC25", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2019-11-15T14:04:03.245058425Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "kavavaloper17498ffqdj49zca4jm7mdf3eevq7uhcsgjvm0uk", + "consensus_pubkey": "kavavalconspub1zcjduepq0mk39ccslman3ame4s3dn5exml8upqearp089sa5tae6pchdyrcsmvwmhn", + "jailed": false, + "status": 2, + "tokens": "23794000000", + "delegator_shares": "23794000000.000000000000000000", + "description": { + "moniker": "kaval", + "identity": "5281C9C7BE5C2646", + "website": "", + "security_contact": "", + "details": "" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.550000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "update_time": "2020-03-07T10:24:27.851934685Z" + }, + "min_self_delegation": "1" + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/kava-api_txs__limit_25_message.sender_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_page_1.json b/mock/ext-api-data/kava-api_txs__limit_25_message.sender_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_page_1.json new file mode 100644 index 000000000..f65e7f75c --- /dev/null +++ b/mock/ext-api-data/kava-api_txs__limit_25_message.sender_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m_page_1.json @@ -0,0 +1,127 @@ +{ + "total_count": "1", + "count": "1", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "1101012", + "txhash": "30EFE9E830D317F84629F9DC35177577DF6713D78D354C2C469DE633900303BC", + "raw_log": "[{\"msg_index\":0,\"success\":true,\"log\":\"\",\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"send\"},{\"key\":\"sender\",\"value\":\"kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m\"},{\"key\":\"module\",\"value\":\"bank\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7\"},{\"key\":\"amount\",\"value\":\"9998000ukava\"}]}]}]", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" + }, + { + "key": "amount", + "value": "9998000ukava" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "68317", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", + "to_address": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7", + "amount": [ + { + "denom": "ukava", + "amount": "9998000" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "ukava", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "AvgGasyPvRpG68UQ6IGPVKN+HrJix24tgwcYXIcIfsna" + }, + "signature": "iST3iM8TtkR5VHTFFhJE1zi+Nh6Invrg4hKgLEY2HCQ+R6Qj9L3jET4yRtAg6+QxitJab27+etoPjJbK20V/Cw==" + } + ], + "memo": "100009547" + } + }, + "timestamp": "2020-02-11T01:33:46Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" + }, + { + "key": "amount", + "value": "9998000ukava" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/kava-api_txs__limit_25_page_1_transfer.recipient_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json b/mock/ext-api-data/kava-api_txs__limit_25_page_1_transfer.recipient_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json new file mode 100644 index 000000000..c20a2b4c6 --- /dev/null +++ b/mock/ext-api-data/kava-api_txs__limit_25_page_1_transfer.recipient_kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m.json @@ -0,0 +1,127 @@ +{ + "total_count": "1", + "count": "1", + "page_number": "1", + "page_total": "1", + "limit": "25", + "txs": [ + { + "height": "793039", + "txhash": "84FFA6CC8428B7A5E82003A7BCA6D1FAB2DF296AD18BE73EE61CBCBF67623880", + "raw_log": "[{\"msg_index\":0,\"success\":true,\"log\":\"\",\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"send\"},{\"key\":\"sender\",\"value\":\"kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7\"},{\"key\":\"module\",\"value\":\"bank\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m\"},{\"key\":\"amount\",\"value\":\"9999000ukava\"}]}]}]", + "logs": [ + { + "msg_index": 0, + "success": true, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "amount", + "value": "9999000ukava" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "70019", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7", + "to_address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", + "amount": [ + { + "denom": "ukava", + "amount": "9999000" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "ukava", + "amount": "1000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "As3eDIXFkLdMkBep+aV+6q9ccVRkA94snsXq2iL5bCTt" + }, + "signature": "QFx3iARLhLeuCCHRUbFAZTePzq+vGAYd4lB/F4JuCGYw1TrfIbAzJhmUHbXHcB/GC+f7Myv5xNrnlCPfCR53uA==" + } + ], + "memo": "" + } + }, + "timestamp": "2020-01-17T11:17:36Z", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" + }, + { + "key": "amount", + "value": "9999000ukava" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/kin-api_accounts_GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH_payments__limit_25_order_desc.json b/mock/ext-api-data/kin-api_accounts_GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH_payments__limit_25_order_desc.json new file mode 100644 index 000000000..5ae11e3a6 --- /dev/null +++ b/mock/ext-api-data/kin-api_accounts_GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH_payments__limit_25_order_desc.json @@ -0,0 +1,750 @@ +{ + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?cursor=\u0026limit=25\u0026order=desc" + }, + "next": { + "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?cursor=35733968989097985\u0026limit=25\u0026order=desc" + }, + "prev": { + "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?cursor=35876948450299905\u0026limit=25\u0026order=asc" + } + }, + "_embedded": { + "records": [ + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35876948450299905" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/1f84fef40d35a0ac46cd286063d517507d3ef553ce3c5284156b96267d21cf61" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35876948450299905/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35876948450299905" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35876948450299905" + } + }, + "id": "35876948450299905", + "paging_token": "35876948450299905", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-13T08:14:53Z", + "transaction_hash": "1f84fef40d35a0ac46cd286063d517507d3ef553ce3c5284156b96267d21cf61", + "starting_balance": "382691.56353", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GA6UCXDAYFVSFTAKMDUM5H7FGVLYF6CSDFHZ5X4QRLKG64EDLW6PEWSN" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35871399352672257" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/4188de4157264c5dfbb11d78ddb9fe4fbdb30f2b893c44bcf2d1e07f4b41ce61" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35871399352672257/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35871399352672257" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35871399352672257" + } + }, + "id": "35871399352672257", + "paging_token": "35871399352672257", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-13T06:27:12Z", + "transaction_hash": "4188de4157264c5dfbb11d78ddb9fe4fbdb30f2b893c44bcf2d1e07f4b41ce61", + "asset_type": "native", + "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "to": "GD7J5ZYRUN6GCY7XUP7MA2XPPKVFADYAJPTFMFK6SY5PBS6BX4SZNYUA", + "amount": "2106990.68969" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35871085820084225" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/e2816c4de264e4e561a3509ff32794942a529896f7043527bdab6604de9d8f39" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35871085820084225/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35871085820084225" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35871085820084225" + } + }, + "id": "35871085820084225", + "paging_token": "35871085820084225", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-13T06:21:06Z", + "transaction_hash": "e2816c4de264e4e561a3509ff32794942a529896f7043527bdab6604de9d8f39", + "starting_balance": "1.00000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GD7J5ZYRUN6GCY7XUP7MA2XPPKVFADYAJPTFMFK6SY5PBS6BX4SZNYUA" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35860975466917889" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/91fc518ab3b2d3e869c91dc4871af450b967f1b8591c2b78df4ebeaeff67f936" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35860975466917889/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35860975466917889" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35860975466917889" + } + }, + "id": "35860975466917889", + "paging_token": "35860975466917889", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-13T03:04:50Z", + "transaction_hash": "91fc518ab3b2d3e869c91dc4871af450b967f1b8591c2b78df4ebeaeff67f936", + "starting_balance": "1449999.10000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GCGD3QF5IRUWVKGY23XDANIOKYZTGUKSRTXUYQZ5H5PADAHZFXLZRGDI" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35846127765123073" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/fb9573473914636f9dfcc95667e33e9f00793da16fa302344ae21bedb05be48a" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35846127765123073/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35846127765123073" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35846127765123073" + } + }, + "id": "35846127765123073", + "paging_token": "35846127765123073", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-12T22:16:42Z", + "transaction_hash": "fb9573473914636f9dfcc95667e33e9f00793da16fa302344ae21bedb05be48a", + "starting_balance": "7213285.00000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GBMAIJKLMHSKAVMTI7AMHWBXM522LJOC2AMB3XZA2ZMGXTSL5GNGVLSX" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35842472747794433" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/0ab3c335134ed91d79bbbbad043cca6f5edbf31fee1785db000618859a742961" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35842472747794433/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35842472747794433" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35842472747794433" + } + }, + "id": "35842472747794433", + "paging_token": "35842472747794433", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-12T21:05:47Z", + "transaction_hash": "0ab3c335134ed91d79bbbbad043cca6f5edbf31fee1785db000618859a742961", + "asset_type": "native", + "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "to": "GCI2AFKGQ3JHSNHUYDRIYOOORC4V6IOICO62E73F6NA6IQFTGH7W6YJO", + "amount": "50.00000" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35833809798836225" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/1524d2b591e8033e33ecd4dd7a729312125908ea1181d12a4da872c233b873d8" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35833809798836225/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35833809798836225" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35833809798836225" + } + }, + "id": "35833809798836225", + "paging_token": "35833809798836225", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-12T18:17:42Z", + "transaction_hash": "1524d2b591e8033e33ecd4dd7a729312125908ea1181d12a4da872c233b873d8", + "asset_type": "native", + "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "to": "GDEYJYEGU3XNZM5Q3JI3AEDXSVIQMSPPJURVHHIFV6BJL65ZAGCYOU3A", + "amount": "3521990.00000" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35832933625516033" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/67586614cd531da0c7c7bae22ca0598d138c46435c0bc20ef03464cd0d31a59b" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35832933625516033/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35832933625516033" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35832933625516033" + } + }, + "id": "35832933625516033", + "paging_token": "35832933625516033", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-12T18:00:42Z", + "transaction_hash": "67586614cd531da0c7c7bae22ca0598d138c46435c0bc20ef03464cd0d31a59b", + "starting_balance": "10.00000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GDEYJYEGU3XNZM5Q3JI3AEDXSVIQMSPPJURVHHIFV6BJL65ZAGCYOU3A" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35831928603242497" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/384388d24a51d9fa71c314d175ecc4afb4a39734c7e628fda0c91ce112ecaf49" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35831928603242497/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35831928603242497" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35831928603242497" + } + }, + "id": "35831928603242497", + "paging_token": "35831928603242497", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-12T17:41:12Z", + "transaction_hash": "384388d24a51d9fa71c314d175ecc4afb4a39734c7e628fda0c91ce112ecaf49", + "starting_balance": "509751.60000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GATZKATB7GEQNRKKIGCQKSKBRK4OSL3VRZROTQPVSGOYMDR6CSINONNJ" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35831769689432065" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b9931b144c93b416ca304dceeb04dc32587c569080b11ed7e25599e44c82f448" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35831769689432065/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35831769689432065" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35831769689432065" + } + }, + "id": "35831769689432065", + "paging_token": "35831769689432065", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-12T17:38:07Z", + "transaction_hash": "b9931b144c93b416ca304dceeb04dc32587c569080b11ed7e25599e44c82f448", + "asset_type": "native", + "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "to": "GBQDSG233R5YPPKIYJRKFTAQHXU6EZIFEOBX3SD25DICYM7UZGK5KWXL", + "amount": "2862401.34917" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35819082356064257" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/76de247dc7b7e3fa5398a44ee110851d8c20a2a2bfe1101b7331194a623edb2f" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35819082356064257/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35819082356064257" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35819082356064257" + } + }, + "id": "35819082356064257", + "paging_token": "35819082356064257", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-12T13:31:42Z", + "transaction_hash": "76de247dc7b7e3fa5398a44ee110851d8c20a2a2bfe1101b7331194a623edb2f", + "asset_type": "native", + "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "to": "GCMWV4BHZKMBTXR2DU6TRROYE6CAIMZNYZZI6PPNNBFAXCXVIR2OT62G", + "amount": "1202214.16773" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35815710806609921" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/e4e69fa1c534f1b64cab38690be253985d33f3cb486393f08186c178c9146d5f" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35815710806609921/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35815710806609921" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35815710806609921" + } + }, + "id": "35815710806609921", + "paging_token": "35815710806609921", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-12T12:26:15Z", + "transaction_hash": "e4e69fa1c534f1b64cab38690be253985d33f3cb486393f08186c178c9146d5f", + "starting_balance": "200920.38792", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GAX72BTGWQLIVSB7443VNKGY7H6D4K5B7AOKFF5UMHHMRCVK2XSAQO3G" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35807460174491649" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/bdbd4075e6197a97e4732e534f93c7a75a56a6f12770d2ad9a06e2bcd669b871" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35807460174491649/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35807460174491649" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35807460174491649" + } + }, + "id": "35807460174491649", + "paging_token": "35807460174491649", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-12T09:46:08Z", + "transaction_hash": "bdbd4075e6197a97e4732e534f93c7a75a56a6f12770d2ad9a06e2bcd669b871", + "starting_balance": "210000.00000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GCWYBCAZLPQTDLKZOMWGCIKYMKFK6AYKGS46Z6IHWQ4R67FMDRSGREMQ" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35786724072296449" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/9387b2f623dfc60491616dd0b3e51ea12773ef7a6154d71660eb0467d5924a26" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35786724072296449/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35786724072296449" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35786724072296449" + } + }, + "id": "35786724072296449", + "paging_token": "35786724072296449", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-12T03:03:39Z", + "transaction_hash": "9387b2f623dfc60491616dd0b3e51ea12773ef7a6154d71660eb0467d5924a26", + "starting_balance": "1001057.00000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GBNLJH6VGCTX4GO6L5WIHIHEZ65LS56PWBLKYJ5TRDBEJACRYM7U3B4R" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35775509912895489" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/ed193af0d6e0f2f0cb20545f02d23e2bb74143267959e77750f75b208a82888b" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35775509912895489/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35775509912895489" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35775509912895489" + } + }, + "id": "35775509912895489", + "paging_token": "35775509912895489", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-11T23:25:54Z", + "transaction_hash": "ed193af0d6e0f2f0cb20545f02d23e2bb74143267959e77750f75b208a82888b", + "starting_balance": "8415499.17415", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GAGFPW2F7US2NHS4ZFATHTGCPAHIIWISKURZ6TMV7KJ5E7T7QFHRAFW3" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35768148338966529" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/cd315376a6f777c6c995f5798906fba1d6194bdc86c008af502ef4c77363e17e" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35768148338966529/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35768148338966529" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35768148338966529" + } + }, + "id": "35768148338966529", + "paging_token": "35768148338966529", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-11T21:02:59Z", + "transaction_hash": "cd315376a6f777c6c995f5798906fba1d6194bdc86c008af502ef4c77363e17e", + "asset_type": "native", + "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "to": "GBWTT6VXCGSMOZN2AWX2JWLHTQLPEIZCB34DZOEUEXYU7FMGQEWVVAA3", + "amount": "204286496.00000" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35766670869966849" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/7c8da7a5d2d5f2ef757fe2419fc7dbefd273fc7fb28d7c65f725e08cff3837e1" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35766670869966849/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35766670869966849" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35766670869966849" + } + }, + "id": "35766670869966849", + "paging_token": "35766670869966849", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-11T20:34:19Z", + "transaction_hash": "7c8da7a5d2d5f2ef757fe2419fc7dbefd273fc7fb28d7c65f725e08cff3837e1", + "starting_balance": "2000.00000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GBWTT6VXCGSMOZN2AWX2JWLHTQLPEIZCB34DZOEUEXYU7FMGQEWVVAA3" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35754696501268481" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/177871adfaadc911a4357653d2c60ff62cbfb6677ae381b94ddceea80d3c116d" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35754696501268481/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35754696501268481" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35754696501268481" + } + }, + "id": "35754696501268481", + "paging_token": "35754696501268481", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-11T16:41:58Z", + "transaction_hash": "177871adfaadc911a4357653d2c60ff62cbfb6677ae381b94ddceea80d3c116d", + "starting_balance": "926347.00000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GDHIZK6G5BLLYDNFRDCXI7Z2EV7XIFFLOGO2FNB226YUTBMXWKDODUMK" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35751930542325761" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/4d70f0d571839fcd2b1acd548464612b9e9f5e7844618cdf383d22ed24e7f282" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35751930542325761/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35751930542325761" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35751930542325761" + } + }, + "id": "35751930542325761", + "paging_token": "35751930542325761", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-11T15:48:18Z", + "transaction_hash": "4d70f0d571839fcd2b1acd548464612b9e9f5e7844618cdf383d22ed24e7f282", + "starting_balance": "2651456.00000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GB563OBW7JS4VMJNP7PMQWBZQBQSW4XKHTTMSZUMOEL5NW6APUYOHKOR" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35751535405195265" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/94c15cb26fd088ad1ccd0bd3b0530a2cdee6107c9005dcf58abe18a9a367e703" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35751535405195265/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35751535405195265" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35751535405195265" + } + }, + "id": "35751535405195265", + "paging_token": "35751535405195265", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-11T15:40:38Z", + "transaction_hash": "94c15cb26fd088ad1ccd0bd3b0530a2cdee6107c9005dcf58abe18a9a367e703", + "starting_balance": "2380384.05211", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GAJZQ6QUXL2I4E43OZWCSRSTART5WLDONBCIVATLGEIJLSSMSLUX73TE" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35750023576711169" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/1969f26276e5d3c3fc844da1065b1f067af2b6fb43c6b373b084193f75825fd5" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35750023576711169/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35750023576711169" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35750023576711169" + } + }, + "id": "35750023576711169", + "paging_token": "35750023576711169", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-11T15:11:18Z", + "transaction_hash": "1969f26276e5d3c3fc844da1065b1f067af2b6fb43c6b373b084193f75825fd5", + "asset_type": "native", + "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "to": "GDSSFOUI6NDAE44XBO2EMEXUQTLKERLB3TO5NQGZOCBSG5NVND6IWUAR", + "amount": "4799900.00000" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35749684274331649" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/4f7950f3458823252b3a725857dc403169dd59bc52e4bef3e9bf89008f88eb9a" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35749684274331649/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35749684274331649" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35749684274331649" + } + }, + "id": "35749684274331649", + "paging_token": "35749684274331649", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-11T15:04:43Z", + "transaction_hash": "4f7950f3458823252b3a725857dc403169dd59bc52e4bef3e9bf89008f88eb9a", + "starting_balance": "100.00000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GDSSFOUI6NDAE44XBO2EMEXUQTLKERLB3TO5NQGZOCBSG5NVND6IWUAR" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35748400079122433" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/8c53bf0ed861d956f91cf6eda4a7581280773ac7e778e53b8aca189cca6f6815" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35748400079122433/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35748400079122433" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35748400079122433" + } + }, + "id": "35748400079122433", + "paging_token": "35748400079122433", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-11T14:39:46Z", + "transaction_hash": "8c53bf0ed861d956f91cf6eda4a7581280773ac7e778e53b8aca189cca6f6815", + "asset_type": "native", + "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "to": "GBNVREV4JCITKKOILHR3FGSKLBT3PKCSWUIKTSF5ETEUIOZA3X2EZBAF", + "amount": "215499.00000" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35748146676203521" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/8f41a95986ed015982ab41cbffa85aca5efc80e913fa2d57b20059b3a9ecfd48" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35748146676203521/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35748146676203521" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35748146676203521" + } + }, + "id": "35748146676203521", + "paging_token": "35748146676203521", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-11T14:34:50Z", + "transaction_hash": "8f41a95986ed015982ab41cbffa85aca5efc80e913fa2d57b20059b3a9ecfd48", + "starting_balance": "1.00000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GBNVREV4JCITKKOILHR3FGSKLBT3PKCSWUIKTSF5ETEUIOZA3X2EZBAF" + }, + { + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35733968989097985" + }, + "transaction": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/15324f705df23f021b8dd443032965444880b0a64aa36a2b0766feede99e6ba3" + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/operations/35733968989097985/effects" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=35733968989097985" + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=35733968989097985" + } + }, + "id": "35733968989097985", + "paging_token": "35733968989097985", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "type": "create_account", + "type_i": 0, + "created_at": "2020-05-11T09:59:40Z", + "transaction_hash": "15324f705df23f021b8dd443032965444880b0a64aa36a2b0766feede99e6ba3", + "starting_balance": "3215955.01000", + "funder": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "account": "GAHV6GEJC77UTTR2NFWEQWRPQPFVPJZH6MPH7IUSGQOGUQPALYDGW4JN" + } + ] + } +} \ No newline at end of file diff --git a/mock/ext-api-data/kin-api_transactions_b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a__.json b/mock/ext-api-data/kin-api_transactions_b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a__.json new file mode 100644 index 000000000..3a9b870d4 --- /dev/null +++ b/mock/ext-api-data/kin-api_transactions_b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a__.json @@ -0,0 +1,45 @@ +{ + "memo": "Namilak8", + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a" + }, + "account": { + "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH" + }, + "ledger": { + "href": "https://horizon-block-explorer.kininfrastructure.com/ledgers/7485062" + }, + "operations": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a/operations{?cursor,limit,order}", + "templated": true + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a/effects{?cursor,limit,order}", + "templated": true + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=asc\u0026cursor=32148096498577408" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=desc\u0026cursor=32148096498577408" + } + }, + "id": "b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a", + "paging_token": "32148096498577408", + "hash": "b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a", + "ledger": 7485062, + "created_at": "2020-03-24T01:43:00Z", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "source_account_sequence": "3873257342118155", + "fee_paid": 100, + "operation_count": 1, + "envelope_xdr": "AAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAAAAZAANwrUAACkLAAAAAAAAAAEAAAAITmFtaWxhazgAAAABAAAAAQAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAAAEAAAAAbDIyvkAp46X97VW4/zmT18NY7BAFyxQxDNv5ve/FylMAAAAAAAAAA4aZXmAAAAAAAAAAATKoLogAAABAiivAdbjfQvWTMheamksBZp9yBc9oRN2E2OpPhTCeT/bICu6eSr3FJy+WqYlieBlXtdVbBaoCWOlR07Mi4QqjDQ==", + "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", + "result_meta_xdr": "AAAAAAAAAAEAAAAEAAAAAwByNoYAAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHRPE+rKwADcK1AAApCwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByNoYAAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHQWqlTkwADcK1AAApCwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBwLBkAAAAAAAAAAGwyMr5AKeOl/e1VuP85k9fDWOwQBcsUMQzb+b3vxcpTAAAAAzCVZ9QAcAeUAAAAAwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByNoYAAAAAAAAAAGwyMr5AKeOl/e1VuP85k9fDWOwQBcsUMQzb+b3vxcpTAAAABrcuxjQAcAeUAAAAAwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA", + "fee_meta_xdr": "AAAAAgAAAAMAcindAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR0TxPq0QAA3CtQAAKQoAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAcjaGAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR0TxPqysAA3CtQAAKQsAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==", + "memo_type": "text", + "signatures": [ + "iivAdbjfQvWTMheamksBZp9yBc9oRN2E2OpPhTCeT/bICu6eSr3FJy+WqYlieBlXtdVbBaoCWOlR07Mi4QqjDQ==" + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/kin-api_transactions_eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed.json b/mock/ext-api-data/kin-api_transactions_eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed.json new file mode 100644 index 000000000..7b568db8a --- /dev/null +++ b/mock/ext-api-data/kin-api_transactions_eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed.json @@ -0,0 +1,45 @@ +{ + "memo": "", + "_links": { + "self": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed" + }, + "account": { + "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH" + }, + "ledger": { + "href": "https://horizon-block-explorer.kininfrastructure.com/ledgers/7481821" + }, + "operations": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed/operations{?cursor,limit,order}", + "templated": true + }, + "effects": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed/effects{?cursor,limit,order}", + "templated": true + }, + "precedes": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=asc\u0026cursor=32134176509775872" + }, + "succeeds": { + "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=desc\u0026cursor=32134176509775872" + } + }, + "id": "eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed", + "paging_token": "32134176509775872", + "hash": "eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed", + "ledger": 7481821, + "created_at": "2020-03-23T21:12:01Z", + "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", + "source_account_sequence": "3873257342118154", + "fee_paid": 100, + "operation_count": 1, + "envelope_xdr": "AAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAAAAZAANwrUAACkKAAAAAAAAAAEAAAAAAAAAAQAAAAEAAAAATqpn4tSz1u76l93pz8ttLSIDQbslHppzlH1cgjKoLogAAAABAAAAADqMsEcsu8a3aP7yB8M2R8im3p4D+wRWZFJY8tvI0bNRAAAAAAAAAF1caQX1AAAAAAAAAAEyqC6IAAAAQFsrhOcyOXVWLIFf8aSJh37W1bx4ZP3qKXPejdB2M0z+FG09ggG0uDiV7FAsmRvzPUGoEgI3reEw+eAFByO6dAs=", + "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", + "result_meta_xdr": "AAAAAAAAAAEAAAAEAAAAAwByKaQAAAAAAAAAADqMsEcsu8a3aP7yB8M2R8im3p4D+wRWZFJY8tvI0bNRAAAAdGpUDqAAcik+AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByKd0AAAAAAAAAADqMsEcsu8a3aP7yB8M2R8im3p4D+wRWZFJY8tvI0bNRAAAA0ca9FJUAcik+AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwByKd0AAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHok2nswUADcK1AAApCgAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByKd0AAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHRPE+rRAADcK1AAApCgAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA", + "fee_meta_xdr": "AAAAAgAAAAMAcimkAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR6JNp7NpAA3CtQAAKQkAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAcindAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR6JNp7MFAA3CtQAAKQoAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==", + "memo_type": "text", + "signatures": [ + "WyuE5zI5dVYsgV/xpImHftbVvHhk/eopc96N0HYzTP4UbT2CAbS4OJXsUCyZG/M9QagSAjet4TD54AUHI7p0Cw==" + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/kusama-api_scan_transfers.json b/mock/ext-api-data/kusama-api_scan_transfers.json new file mode 100644 index 000000000..f59c65f36 --- /dev/null +++ b/mock/ext-api-data/kusama-api_scan_transfers.json @@ -0,0 +1 @@ +{"code":0,"message":"Success","ttl":1,"data":{"count":16,"transfers":[{"from":"EonK7NScfhd7ZRfgnLhm4cKRFJWK1z59zPximUZRg8VjHQj","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"15","hash":"0x5a5f9a4c2e09f5111244d77b424151b4e21be8e29b4b4e382a7b35a896512757","block_timestamp":1587746376,"block_num":2023403,"extrinsic_index":"2023403-3","success":true,"fee":"10000000000"},{"from":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"140","hash":"0xbcb7e99387c65024ef9ed1fc35ac703c1d4917694bb4c969c7d698142cc7c63d","block_timestamp":1586095086,"block_num":1756978,"extrinsic_index":"1756978-3","success":true,"fee":"10000000000"},{"from":"EonK7NScfhd7ZRfgnLhm4cKRFJWK1z59zPximUZRg8VjHQj","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"30","hash":"0x9908579abffb409aef95394128f9097f0a21cfdf16675588423e31ab0d3c58e2","block_timestamp":1583243826,"block_num":1291387,"extrinsic_index":"1291387-3","success":true,"fee":"10000000000"},{"from":"EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"7.333459","hash":"0xab5dbf2d38f249785c260c3fca9e19a17df298c5294a99eaec2baab29970eb85","block_timestamp":1581154290,"block_num":961987,"extrinsic_index":"961987-2","success":true,"fee":"10000000000"},{"from":"EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"233.193373","hash":"0x08aad18956058ee385387da2f7d613ed17ac5c98ad23683cfea855b0fd529a63","block_timestamp":1579722240,"block_num":738814,"extrinsic_index":"738814-3","success":true,"fee":"10000000000"},{"from":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","to":"EonK7NScfhd7ZRfgnLhm4cKRFJWK1z59zPximUZRg8VjHQj","module":"balances","amount":"10","hash":"0xe05a4493cd013e182ebf82169e818a251b2ed52e064452293e81428f825a70a2","block_timestamp":1579511916,"block_num":704522,"extrinsic_index":"704522-3","success":true,"fee":"10000000000"},{"from":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","to":"EonK7NScfhd7ZRfgnLhm4cKRFJWK1z59zPximUZRg8VjHQj","module":"balances","amount":"30","hash":"0x18e175b836a6ec97a7dddfe5ee142844681987480a29ae5d5166d36213a90c91","block_timestamp":1579442088,"block_num":693483,"extrinsic_index":"693483-3","success":true,"fee":"10000000000"},{"from":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","to":"EonK7NScfhd7ZRfgnLhm4cKRFJWK1z59zPximUZRg8VjHQj","module":"balances","amount":"5","hash":"0x95526174daf76fcff648f2c4bf88f347a84c9f8a88aa82e757d51d8f1cdbbd98","block_timestamp":1579441998,"block_num":693468,"extrinsic_index":"693468-3","success":true,"fee":"10000000000"},{"from":"EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"245.749804","hash":"0x290800b497f7b41a820df030d7a5311180b1584e4fa4e091e3a07d03db036427","block_timestamp":1579264992,"block_num":664802,"extrinsic_index":"664802-3","success":true,"fee":"10000000000"},{"from":"EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"985.894918","hash":"0x2c317ed47a9b9f8fed938f8541b5bca3dcd6702827e41ed38921cdce21017069","block_timestamp":1576716144,"block_num":285215,"extrinsic_index":"285215-3","success":true,"fee":"0"},{"from":"EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"327.967504","hash":"0xc6fdca126d15dd145ecdd704009881d8fa301f634766f909fb8d68e654c0d14a","block_timestamp":1576662756,"block_num":276469,"extrinsic_index":"276469-3","success":true,"fee":"0"},{"from":"EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"161.771866","hash":"0x4acc84472e2da51e9b35aa086296f8a256f75ff081a9e77468f10a74254f489b","block_timestamp":1576600764,"block_num":266305,"extrinsic_index":"266305-3","success":true,"fee":"0"},{"from":"EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"302.185312","hash":"0xa1ba1d239bb2511dcefba82e40d03fdf8be0c41a3b0353c414ad128d80205129","block_timestamp":1576507356,"block_num":251047,"extrinsic_index":"251047-3","success":true,"fee":"0"},{"from":"EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"533.4697945","hash":"0x755d63741e0068abdc6151eea305be952b7b7685c998964f170a3030f0581247","block_timestamp":1576163976,"block_num":194836,"extrinsic_index":"194836-3","success":true,"fee":"0"},{"from":"EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"533.4697945","hash":"0x5e976ac0316c5f0037fa89f40480e0d41b4d494c0dde786d6c80d2bbeb2b32bc","block_timestamp":1576162248,"block_num":194553,"extrinsic_index":"194553-3","success":true,"fee":"0"},{"from":"EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X","to":"HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK","module":"balances","amount":"2.8","hash":"0x9d42d83a6e340ac08a35ef691bbc71da9249e37d33d310bda08661cc8e2171a1","block_timestamp":1576161810,"block_num":194481,"extrinsic_index":"194481-2","success":true,"fee":"0"}]}} \ No newline at end of file diff --git a/mock/ext-api-data/kusama-api_scan_transfers.request_json b/mock/ext-api-data/kusama-api_scan_transfers.request_json new file mode 100644 index 000000000..fc31d1c0c --- /dev/null +++ b/mock/ext-api-data/kusama-api_scan_transfers.request_json @@ -0,0 +1,4 @@ +{ + "address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", + "row": 25 +} \ No newline at end of file diff --git a/mock/ext-api-data/litecoin-api_v2_address_ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept__details_txs.json b/mock/ext-api-data/litecoin-api_v2_address_ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept__details_txs.json new file mode 100644 index 000000000..26bd7b790 --- /dev/null +++ b/mock/ext-api-data/litecoin-api_v2_address_ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept__details_txs.json @@ -0,0 +1,1081 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept", + "balance": "1688078", + "totalReceived": "25679292", + "totalSent": "23991214", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 19, + "transactions": [ + { + "txid": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1", + "version": 1, + "vin": [ + { + "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", + "vout": 1, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "788530" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "0014ccf05f3bc453f7f66fb48b124bd79690bc309e22", + "addresses": [ + "ltc1qenc97w7y20mlvma53vfyh4ukjz7rp83zf892wx" + ], + "isAddress": true + }, + { + "value": "688078", + "n": 1, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "ae8df4fb9cbbd07375eef217dd25e8b918a1b2746907c23cf4f2e15cd18fccdd", + "blockHeight": 1804076, + "confirmations": 36291, + "blockTime": 1583910871, + "value": "788078", + "valueIn": "788530", + "fees": "452", + "hex": "0100000000010167f89bc6125388f252bd770e142e61b9ab23dfb18762ba210f6f162bed92406701000000000000000002a086010000000000160014ccf05f3bc453f7f66fb48b124bd79690bc309e22ce7f0a00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100a40df50e2b419a35001f40d508e911f36d01497ebe5225dc93c81f53a30452fb022034c086517326be293019c2cbf215d6b9a53aa0ab4a0c2b890a9f1b05e8052aac012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", + "version": 1, + "vin": [ + { + "txid": "f8ddc3eca55aa4bffd27b030fc3b35ceb8d503b31a03dafd32df56eec552fe99", + "vout": 1, + "sequence": 4294967290, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "1788982" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + }, + { + "value": "788530", + "n": 1, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "dd92763dcb8477d8f012e5ec0598ebf3c135a15780d7491754fff40d3d24dd9b", + "blockHeight": 1803562, + "confirmations": 36805, + "blockTime": 1583831802, + "value": "1788530", + "valueIn": "1788982", + "fees": "452", + "hex": "0100000000010199fe52c5ee56df32fdda031ab303d5b8ce353bfc30b027fdbfa45aa5ecc3ddf80100000000faffffff0240420f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c532080c00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100bbde918ff538468c440424323bbe8ba78eef14d9dde357c8e6496905d540098c02205700d984884edff918f827289898c16ec9ad30344a637ea85dc55f7f836143bd012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "f8ddc3eca55aa4bffd27b030fc3b35ceb8d503b31a03dafd32df56eec552fe99", + "version": 1, + "vin": [ + { + "txid": "0bc6314b50a192853d09b2ca3ebadea75288bfb66e9b254c8f55ebaa720a7d2f", + "vout": 1, + "n": 0, + "addresses": [ + "ltc1qd0huz2atjj0uyjlcp48ml9tltkzdta7sg8fn89" + ], + "isAddress": true, + "value": "1889434" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "0014e8d0e2bade0aefda201fad8ff5859d743b252a5b", + "addresses": [ + "ltc1qargw9wk7ptha5gql4k8ltpvawsaj22jmr8cejf" + ], + "isAddress": true + }, + { + "value": "1788982", + "n": 1, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "c9503e0fe18dd16a8a1e836d08d6966e443fbe79eeb0561f2fb18e5993a0cfec", + "blockHeight": 1800498, + "confirmations": 39869, + "blockTime": 1583384860, + "value": "1888982", + "valueIn": "1889434", + "fees": "452", + "hex": "010000000001012f7d0a72aaeb558f4c259b6eb6bf8852a7deba3ecab2093d8592a1504b31c60b01000000000000000002a086010000000000160014e8d0e2bade0aefda201fad8ff5859d743b252a5b364c1b00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100f6adacde68792f7862ec58b066ed4b521444929d90c163b5eb7b0a3d3e16c133022018f649e6a9cece3dc58fdb09f8cffb5cf9ba64f7a453ae6d82043b3fc65fe8ba01210273a11ff2e056c52a0a10c3b93590f60802ab8a74bf9828ea76ae87885fddfc8d00000000" + }, + { + "txid": "fdbf28c741e55f846a0a378e0cf2a7263540f8d24123b658f2beb0bd1b1788f0", + "version": 1, + "vin": [ + { + "txid": "07eb5638d1a2833a7eaea596b0dc8bacd8a51be6f18f8bb8cabd514255acebff", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "96312" + }, + { + "txid": "152c3d81f7272c91bd3d880d7b570619ef4141482cbcd62b5556fb00efc2bd94", + "sequence": 4294967293, + "n": 1, + "addresses": [ + "ltc1q5usqkt2x9tnqljy0tss9jqmlvcmakdp4l4rdt5" + ], + "isAddress": true, + "value": "400000" + }, + { + "txid": "152c3d81f7272c91bd3d880d7b570619ef4141482cbcd62b5556fb00efc2bd94", + "vout": 1, + "sequence": 4294967292, + "n": 2, + "addresses": [ + "ltc1q69juwlyyyks4ws8rdklldjvdxk3vk6gy9qkn99" + ], + "isAddress": true, + "value": "1650696" + } + ], + "vout": [ + { + "value": "1989886", + "n": 0, + "spent": true, + "hex": "001450e07ca8c4f2c7ec53351710013a03251ab5d1d8", + "addresses": [ + "ltc1q2rs8e2xy7tr7c5e4zugqzwsry5dtt5wcdk4zv9" + ], + "isAddress": true + } + ], + "blockHash": "5977afe7c387c7390498309e29ad71e8daef8c59df5b910cb05a3ae661db0919", + "blockHeight": 1783073, + "confirmations": 57294, + "blockTime": 1580799867, + "value": "1989886", + "valueIn": "2147008", + "fees": "157122", + "hex": "01000000000103ffebac554251bdcab88b8ff1e61ba5d8ac8bdcb096a5ae7e3a83a2d13856eb070100000000feffffff94bdc2ef00fb56552bd6bc2c484141ef1906577b0d883dbd912c27f7813d2c150000000000fdffffff94bdc2ef00fb56552bd6bc2c484141ef1906577b0d883dbd912c27f7813d2c150100000000fcffffff01fe5c1e000000000016001450e07ca8c4f2c7ec53351710013a03251ab5d1d802473044022015d518ae11502d4c832cde4627372c60fb89293d14f3dd39006445dce3bfe47f02207b97301e3f8b9016a515882072dafba705a4ec5e29f5ae222dbdfd5a6d83c90a012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd1024730440220478a6c3144e882f736b7b674d43768636f8d74eec28138d9ea36d05f64634aa402203827a08bb554c930e58178536257eb247a790866a7984fdffe549da7376244f201210262da88bf17e0b0575a3c9efecf7387e6d96fa9039547ac6707219defd321986102473044022053999ec5a5b454c60136144096f55a0de2402addd4a250396884bd00f3763dfe022054812eca7798ed4a4418b166c6a4e3e880cbd93ce41c620b611c35ad1c80735e012103c497991dbbf809288e18c5ab4744d59ab6b0b0bf875d2095267ea373e9837d3400000000" + }, + { + "txid": "152c3d81f7272c91bd3d880d7b570619ef4141482cbcd62b5556fb00efc2bd94", + "version": 1, + "vin": [ + { + "txid": "9cad90704b2c24e2300c496398ba66ba216bc1df01851ba8c14fc0da8814a8ec", + "vout": 1, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "2051148" + } + ], + "vout": [ + { + "value": "400000", + "n": 0, + "spent": true, + "hex": "0014a7200b2d462ae60fc88f5c2059037f6637db3435", + "addresses": [ + "ltc1q5usqkt2x9tnqljy0tss9jqmlvcmakdp4l4rdt5" + ], + "isAddress": true + }, + { + "value": "1650696", + "n": 1, + "spent": true, + "hex": "0014d165c77c8425a15740e36dbff6c98d35a2cb6904", + "addresses": [ + "ltc1q69juwlyyyks4ws8rdklldjvdxk3vk6gy9qkn99" + ], + "isAddress": true + } + ], + "blockHash": "686ab90a08327f65c4cb5aa4227f3c0c0eb3120e922f6f6a8ba37fd20d6d2a72", + "blockHeight": 1782650, + "confirmations": 57717, + "blockTime": 1580744939, + "value": "2050696", + "valueIn": "2051148", + "fees": "452", + "hex": "01000000000101eca81488dac04fc1a81b8501dfc16b21ba66ba9863490c30e2242c4b7090ad9c01000000000000000002801a060000000000160014a7200b2d462ae60fc88f5c2059037f6637db34350830190000000000160014d165c77c8425a15740e36dbff6c98d35a2cb690402483045022100e633d87b26da1f508018fdf1c54f9b8bb0813aeb326c17a2622e29dec94f48ce0220123208bd0d13e1c2f16c4d3a450b783ea89211fcb054db2211ed6403335a48f3012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "9cad90704b2c24e2300c496398ba66ba216bc1df01851ba8c14fc0da8814a8ec", + "version": 1, + "vin": [ + { + "txid": "b784d0389a2450e43ea043567329d0f4e00277ac430bbcedf335d9d85451e088", + "vout": 1, + "n": 0, + "addresses": [ + "ltc1q720spapzfq8j79gal5mg2efcrtv92hvktc8u76" + ], + "isAddress": true, + "value": "3051600" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "0014463fec54ea2c7210057b2d6d1972a8aaaf39a543", + "addresses": [ + "ltc1qgcl7c48293epqptm94k3ju4g42hnnf2r5d4ewq" + ], + "isAddress": true + }, + { + "value": "2051148", + "n": 1, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "8eccbbf11afd2c3a54f2a5eae52734b37b67df50cbdea00224ad39896e0bf4f7", + "blockHeight": 1781067, + "confirmations": 59300, + "blockTime": 1580515445, + "value": "3051148", + "valueIn": "3051600", + "fees": "452", + "hex": "0100000000010188e05154d8d935f3edbc0b43ac7702e0f4d029735643a03ee450249a38d084b70100000000000000000240420f0000000000160014463fec54ea2c7210057b2d6d1972a8aaaf39a5434c4c1f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c5024830450221009f248a6c27f931afca2480a0d9867f77a7ed9d15a1c81aa3f1398c86cd14b02502205b96bc4b1c4dc2b16835acc656203f837c37d389ec65decfe25691e667cc3dfe012103a845425673d8c68211ab69f7de46c81ed2c42e5afbadfe3a6eab971ce5da56fa00000000" + }, + { + "txid": "b784d0389a2450e43ea043567329d0f4e00277ac430bbcedf335d9d85451e088", + "version": 1, + "vin": [ + { + "txid": "b1208bcfb49b5fbc3366bf07b0000b884d59ecdbebc25b1a55f91330317603db", + "vout": 1, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "3152052" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "0014b329897dc74dc8d7fa2a68a366593bf266dcda5c", + "addresses": [ + "ltc1qkv5cjlw8fhyd0732dz3kvkfm7fndekjurha9ua" + ], + "isAddress": true + }, + { + "value": "3051600", + "n": 1, + "spent": true, + "hex": "0014f29f00f422480f2f151dfd368565381ad8555d96", + "addresses": [ + "ltc1q720spapzfq8j79gal5mg2efcrtv92hvktc8u76" + ], + "isAddress": true + } + ], + "blockHash": "28f684c412c4394e2da6255567957a493d35a7c7675d8d21a21fab4f3210d772", + "blockHeight": 1778975, + "confirmations": 61392, + "blockTime": 1580198750, + "value": "3151600", + "valueIn": "3152052", + "fees": "452", + "hex": "01000000000101db0376313013f9551a5bc2ebdbec594d880b00b007bf6633bc5f9bb4cf8b20b101000000000000000002a086010000000000160014b329897dc74dc8d7fa2a68a366593bf266dcda5c50902e0000000000160014f29f00f422480f2f151dfd368565381ad8555d9602483045022100e1af3d8173ca2c4c4ac5c2b1e5b20f7cc736563d67154ab8616cfc4f62c3d1b00220296e9595ad8276765d3f83119cb393c3adc4c2a9fb0ad1cb382d3dc13ad59707012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "b1208bcfb49b5fbc3366bf07b0000b884d59ecdbebc25b1a55f91330317603db", + "version": 1, + "vin": [ + { + "txid": "a54db30dd54adc3e90a1c5e72b6a5b94992591cbc325adfc28cee55ab5f9dbc0", + "vout": 1, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "3252504" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "0014b329897dc74dc8d7fa2a68a366593bf266dcda5c", + "addresses": [ + "ltc1qkv5cjlw8fhyd0732dz3kvkfm7fndekjurha9ua" + ], + "isAddress": true + }, + { + "value": "3152052", + "n": 1, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "28f684c412c4394e2da6255567957a493d35a7c7675d8d21a21fab4f3210d772", + "blockHeight": 1778975, + "confirmations": 61392, + "blockTime": 1580198750, + "value": "3252052", + "valueIn": "3252504", + "fees": "452", + "hex": "01000000000101c0dbf9b55ae5ce28fcad25c3cb912599945b6a2be7c5a1903edc4ad50db34da501000000000000000002a086010000000000160014b329897dc74dc8d7fa2a68a366593bf266dcda5cb4183000000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502473044022007410f524d5597d7ffde5ceff733bcbc05d842194c1ed650ba3ac0bcde4f561902201dde5782c6c47fac0d05fde0df0b7862649b6c3d391d61881733e4e0bb8bc0d8012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "07eb5638d1a2833a7eaea596b0dc8bacd8a51be6f18f8bb8cabd514255acebff", + "version": 1, + "vin": [ + { + "txid": "1d646fc08ce623e25db1ffb2a24edc9047290ed381a17055a3f80af73cb7b5f6", + "vout": 1, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "196764" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "0014b329897dc74dc8d7fa2a68a366593bf266dcda5c", + "addresses": [ + "ltc1qkv5cjlw8fhyd0732dz3kvkfm7fndekjurha9ua" + ], + "isAddress": true + }, + { + "value": "96312", + "n": 1, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "345e8d0e0db46e61a6cac57d6510c8a10aa96d19acc67b77a6f3da46852c534b", + "blockHeight": 1776086, + "confirmations": 64281, + "blockTime": 1579768496, + "value": "196312", + "valueIn": "196764", + "fees": "452", + "hex": "01000000000101f6b5b73cf70af8a35570a181d30e294790dc4ea2b2ffb15de223e68cc06f641d01000000000000000002a086010000000000160014b329897dc74dc8d7fa2a68a366593bf266dcda5c38780100000000001600140ee85acd7206ba404a684e9655b54d32f242b7c50247304402206245362876d0c13acd72bda09855d4bf9eee7ee0d1c7f623773b9bfe76a93c4d02201be35a5b8bb99c182afeed0bdf35b5b4e235945e8a8e50e8d35ab8176d81567e012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "1d646fc08ce623e25db1ffb2a24edc9047290ed381a17055a3f80af73cb7b5f6", + "version": 1, + "vin": [ + { + "txid": "b690c2b2d279f79d3f61fc9bdb7a21278b1614844c2131a0decc960e0a7f2168", + "n": 0, + "addresses": [ + "ltc1qwna0xhkrevtqmhzvhxk4m04l63wm7dpesz24qw" + ], + "isAddress": true, + "value": "299024" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "0014b329897dc74dc8d7fa2a68a366593bf266dcda5c", + "addresses": [ + "ltc1qkv5cjlw8fhyd0732dz3kvkfm7fndekjurha9ua" + ], + "isAddress": true + }, + { + "value": "196764", + "n": 1, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "68bf0fa93887199ced90a5eebf67af0fd93384b329fd1c93b23012ce0876ffcc", + "blockHeight": 1776080, + "confirmations": 64287, + "blockTime": 1579768089, + "value": "296764", + "valueIn": "299024", + "fees": "2260", + "hex": "0100000000010168217f0a0e96ccdea031214c8414168b27217adb9bfc613f9df779d2b2c290b600000000000000000002a086010000000000160014b329897dc74dc8d7fa2a68a366593bf266dcda5c9c000300000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100ab047a8d9acfc6dd818d8bee9aadfe2c53fb9991bc7bad81340df1dbce56325502202ab65afb51ec1f1104d95d773770cb4a6b51dc6cc81262a335d7ce51787df89c01210348dec0e7e62b72ba01b63fe25eb12ec8fc1a1e723383eacdc14acda7aef89bc000000000" + }, + { + "txid": "a54db30dd54adc3e90a1c5e72b6a5b94992591cbc325adfc28cee55ab5f9dbc0", + "version": 1, + "vin": [ + { + "txid": "002c4890e61f8469c440fb1d3f393a2decedce809f864215b325623ff22c378d", + "n": 0, + "addresses": [ + "ltc1qsht40umvdekkehcvhw36f4hr0yrgxkykmeccka" + ], + "isAddress": true, + "value": "4252956" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "0014463fec54ea2c7210057b2d6d1972a8aaaf39a543", + "addresses": [ + "ltc1qgcl7c48293epqptm94k3ju4g42hnnf2r5d4ewq" + ], + "isAddress": true + }, + { + "value": "3252504", + "n": 1, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "b176f179d76b21969f6f004900f1e507fa75a8514c7808b585e01f85f39adb75", + "blockHeight": 1775782, + "confirmations": 64585, + "blockTime": 1579720477, + "value": "4252504", + "valueIn": "4252956", + "fees": "452", + "hex": "010000000001018d372cf23f6225b31542869f80ceedec2d3a393f1dfb40c469841fe690482c000000000000000000000240420f0000000000160014463fec54ea2c7210057b2d6d1972a8aaaf39a54318a13100000000001600140ee85acd7206ba404a684e9655b54d32f242b7c50247304402207e77674f7980ac6579ebbdbc9bcb879da5dde0d7a640fda87187886a12f287d0022013f85719f8f187e315a9eda950b052549bbd839a921546b5b5001c138cda460e0121030b262bf5e861190da899d6165f272c51515ffc3371f1a4c2fb1454c9e0f0b17a00000000" + }, + { + "txid": "002c4890e61f8469c440fb1d3f393a2decedce809f864215b325623ff22c378d", + "version": 1, + "vin": [ + { + "txid": "a0a06e038a056a901f8661b95912427c758a67846a18c9e5c131bcf28840e25b", + "n": 0, + "addresses": [ + "ltc1q80jcymjkypzrmg7t7s77rjtxdlwu95hj24ejl9" + ], + "isAddress": true, + "value": "100000" + }, + { + "txid": "187e023a2ff48ff513b80f54e1ab11e436a41ee8c7e0da63e3c32a2b33a5d641", + "vout": 1, + "n": 1, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "4153636" + } + ], + "vout": [ + { + "value": "4252956", + "n": 0, + "spent": true, + "hex": "001485d757f36c6e6d6cdf0cbba3a4d6e37906835896", + "addresses": [ + "ltc1qsht40umvdekkehcvhw36f4hr0yrgxkykmeccka" + ], + "isAddress": true + } + ], + "blockHash": "b4c819420647722388529da151021a65f3eba29edec797687ba20276268a153e", + "blockHeight": 1774980, + "confirmations": 65387, + "blockTime": 1579585144, + "value": "4252956", + "valueIn": "4253636", + "fees": "680", + "hex": "010000000001025be24088f2bc31c1e5c9186a84678a757c421259b961861f906a058a036ea0a000000000000000000041d6a5332b2ac3e363dae0c7e81ea436e411abe1540fb813f58ff42f3a027e18010000000000000000011ce540000000000016001485d757f36c6e6d6cdf0cbba3a4d6e3790683589602483045022100bf9187a8b6e892ed9e6baf688a0b3099298876d5761575e25689a37a91d858430220232c9dd0f3d6ef5c5eff8e4d79ae8fcb3e6449f2de3f508950005a41a6e50aba01210349f5f593538e07d0353a19126148051ac2c3524f2a609d99ddef3f6cf120db9202473044022016f4fffa57e335405d114aaa3c10b14c75bdb496e72cab156efc0701c0fb6fb902200c20e9e61c5033f86a40f340923b22b3986314a017ffb5aba6c257c411ce812a012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "187e023a2ff48ff513b80f54e1ab11e436a41ee8c7e0da63e3c32a2b33a5d641", + "version": 1, + "vin": [ + { + "txid": "8ec0737898fc47b617e3cbae0bca4051e41dd819bca42d017ff3a2920b3c4509", + "vout": 1, + "n": 0, + "addresses": [ + "ltc1q5fe05r6kcdvtxeegp806p72kyky67394hpmsum" + ], + "isAddress": true, + "value": "4254088" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "0014b329897dc74dc8d7fa2a68a366593bf266dcda5c", + "addresses": [ + "ltc1qkv5cjlw8fhyd0732dz3kvkfm7fndekjurha9ua" + ], + "isAddress": true + }, + { + "value": "4153636", + "n": 1, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "98ab28fe0b5983eb1d0f8b416229f45a68428dedeb86ab3955513036f62c6487", + "blockHeight": 1774979, + "confirmations": 65388, + "blockTime": 1579584910, + "value": "4253636", + "valueIn": "4254088", + "fees": "452", + "hex": "0100000000010109453c0b92a2f37f012da4bc19d81de45140ca0baecbe317b647fc987873c08e01000000000000000002a086010000000000160014b329897dc74dc8d7fa2a68a366593bf266dcda5c24613f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c5024830450221009a577593c93bf576c25a91efe8fbb6b73a969eb383fab4fbbead2fc3c4689cfd022022036d3dfadbd81c35a2512225da857a6d6d3c4953de21421be9bb2d7f590dfb012102405d626b98304b8f35bf90004894f40f0d54aedef11b46612fed2e82a08640fe00000000" + }, + { + "txid": "a0a06e038a056a901f8661b95912427c758a67846a18c9e5c131bcf28840e25b", + "version": 1, + "vin": [ + { + "txid": "c58315f8f640bc758fb550860e6e7c0564f97933d2950f6436146265ac215c9e", + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "4555444" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "00143be5826e5620443da3cbf43de1c9666fddc2d2f2", + "addresses": [ + "ltc1q80jcymjkypzrmg7t7s77rjtxdlwu95hj24ejl9" + ], + "isAddress": true + }, + { + "value": "4454992", + "n": 1, + "spent": true, + "hex": "00142f6288391f29e894b4841a679bf3bffa1a2605dd", + "addresses": [ + "ltc1q9a3gswgl985ffdyyrfnehuallgdzvpwa9xyu0s" + ], + "isAddress": true + } + ], + "blockHash": "3128d4b4e5faeaa788048f39ae2c11d759b32057f81898b7873314e6bd0af6ea", + "blockHeight": 1773960, + "confirmations": 66407, + "blockTime": 1579432769, + "value": "4554992", + "valueIn": "4555444", + "fees": "452", + "hex": "010000000001019e5c21ac65621436640f95d23379f964057c6e0e8650b58f75bc40f6f81583c500000000000000000002a0860100000000001600143be5826e5620443da3cbf43de1c9666fddc2d2f250fa4300000000001600142f6288391f29e894b4841a679bf3bffa1a2605dd02483045022100d045b6218596f68e62da33b7ef1e24ffce728b0bdf9645169256fd9b2ea90e8f02207f2170ae269c8f7f5e1c6e4f728056ae8f642f0c41dac76d2bc1ae3b91416ba8012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "c58315f8f640bc758fb550860e6e7c0564f97933d2950f6436146265ac215c9e", + "version": 1, + "vin": [ + { + "txid": "afcaae3d72a005b3534fd2cceb756584e789a364422c1818cee1cc1a50f65b7b", + "n": 0, + "addresses": [ + "ltc1q2j0k8v7aczdajd42g96h7gy4jef63feh77494u" + ], + "isAddress": true, + "value": "1000" + }, + { + "txid": "afcaae3d72a005b3534fd2cceb756584e789a364422c1818cee1cc1a50f65b7b", + "vout": 1, + "n": 1, + "addresses": [ + "ltc1qctr5lrsrpek4uxhdkyvska86swvdvgdj5m6272" + ], + "isAddress": true, + "value": "4555124" + } + ], + "vout": [ + { + "value": "4555444", + "n": 0, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + } + ], + "blockHash": "85b2d5e43d9707cf230a01445c5a25c273da9fa54926e40a11e27b4c51507be5", + "blockHeight": 1773954, + "confirmations": 66413, + "blockTime": 1579432217, + "value": "4555444", + "valueIn": "4556124", + "fees": "680", + "hex": "010000000001027b5bf6501acce1ce18182c4264a389e7846575ebccd24f53b305a0723daecaaf0000000000000000007b5bf6501acce1ce18182c4264a389e7846575ebccd24f53b305a0723daecaaf01000000000000000001b4824500000000001600140ee85acd7206ba404a684e9655b54d32f242b7c50247304402206b44554da9ee7b0a5cd15fae67799cee60f9d1237cc85e939597b15c91caa5370220768d26750a4fd7c566282ebd162db24058bc0938d2d2aa8205e2b418c90733d90121023c3c2a4f46b4d9dd305d8e030efd76bee0f22f5794cdb69c761aaa7139d3885b02483045022100a38bd5236acaa978073ce5f6d67cf499b8dbb771cf4bc0b6e4dbfeecb637a1d0022042e076375eb8f4d872e2fa55089a5de2dd5de67ae91d0e621e4998fa4a2eda13012103de91c9cd7f1e0c7b37c997fc6ba9353504d9f283cda1e58cffee627bc1528bf300000000" + }, + { + "txid": "a86bec27c5c517f140d69e092c746296dcf2430602edd81bf680890a29b1108b", + "version": 1, + "vin": [ + { + "txid": "8658c06633a538405f4569cf6238641e80fa6fab176797a43c5b26c4fbac9ae8", + "n": 0, + "addresses": [ + "ltc1qmpsjljyexwn0dk4myglykyu56x9qkqnkgmpdrl" + ], + "isAddress": true, + "value": "10000" + }, + { + "txid": "511692fb776631e54f554a419115b975e60ac499f0e084851a1c01408fdf30a1", + "n": 1, + "addresses": [ + "ltc1qt7frzf37ndtta78fvmc3a4gphsvths9g4fqufk" + ], + "isAddress": true, + "value": "10000" + }, + { + "txid": "2f637249f0124fe6153b6489ed4c1f7dd0cd3a2a9889063de193064b720127ef", + "vout": 1, + "n": 2, + "addresses": [ + "ltc1qjzrcnxst987jepzuvmpgesu59zmnv44mjqs48t" + ], + "isAddress": true, + "value": "28644" + }, + { + "txid": "fbcf72d702ee78a83adf9c5699a45c367eaeb17e151ce4e320da423d8b7430cb", + "vout": 1, + "n": 3, + "addresses": [ + "ltc1q4g6egkjhwr64zptf2pngkn2u3v8wfa8n4fj8wr" + ], + "isAddress": true, + "value": "43866" + }, + { + "txid": "36734bc826395b278f5dc01f01f98276357660e81ffa27cd531d5db5b52fe621", + "vout": 1, + "n": 4, + "addresses": [ + "ltc1qxtx6ak7s2t3sjxvpvqccl4velnhmwlv0pqegce" + ], + "isAddress": true, + "value": "45886" + }, + { + "txid": "fbcf72d702ee78a83adf9c5699a45c367eaeb17e151ce4e320da423d8b7430cb", + "n": 5, + "addresses": [ + "ltc1qjvqng3u009ek9926eume6vmyu9quc0uy0utcpq" + ], + "isAddress": true, + "value": "55682" + }, + { + "txid": "36734bc826395b278f5dc01f01f98276357660e81ffa27cd531d5db5b52fe621", + "n": 6, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "55686" + }, + { + "txid": "00395a5ae5dd4a241827e5111df360a00a4823067da5b65b3c8e18a73449e50b", + "vout": 1, + "n": 7, + "addresses": [ + "ltc1qcjnfzmy6n34lqwvmv9j7nsj5dx042kswxjz2v7" + ], + "isAddress": true, + "value": "60246" + }, + { + "txid": "611c047d6e717414481f7c585b35c08c819f9fcd76f33de53976dcd64b33d6c5", + "vout": 1, + "n": 8, + "addresses": [ + "ltc1q7tz7p6g5gpgvnxg0t7glahl5ufg6fnq2q0uq4q" + ], + "isAddress": true, + "value": "82209" + }, + { + "txid": "ed2998bdab40da72b51c3e9c41e5363cfa344a0a066b4c5fbb9cc6d5848c6470", + "n": 9, + "addresses": [ + "ltc1qvetv0ghlrzf520d9hh508vwu273whxxlu8ln4v" + ], + "isAddress": true, + "value": "98244" + }, + { + "txid": "f9d23fa8e27ac9becc0a7087155478f1669b75b86f66e981c7ab44edecf41f82", + "vout": 1, + "n": 10, + "addresses": [ + "ltc1q9gsu5fdspttjq9wwnezjr43kd0luhqn329d0n9" + ], + "isAddress": true, + "value": "99548" + }, + { + "txid": "daca8142ff4e5bc58d6b61c91f7587cf57311e0aeef912b98e603b350a0116d1", + "n": 11, + "addresses": [ + "ltc1q8q9l9sjkdg840zgmf0egfaw5ndv4wxtwfck8d3" + ], + "isAddress": true, + "value": "100000" + }, + { + "txid": "00395a5ae5dd4a241827e5111df360a00a4823067da5b65b3c8e18a73449e50b", + "n": 12, + "addresses": [ + "ltc1qt84md3dmkwks35lawgwha95vmvvk8vhmfl98de" + ], + "isAddress": true, + "value": "100000" + }, + { + "txid": "f9d23fa8e27ac9becc0a7087155478f1669b75b86f66e981c7ab44edecf41f82", + "n": 13, + "addresses": [ + "ltc1qsjkccjvfzk9uewq9k9ckk3ar5ka4gp46vzwlt3" + ], + "isAddress": true, + "value": "100000" + }, + { + "txid": "644a3be94f70d3976796163fdef4c60ad1dc0e7ed8f1cee5d111e45fe2fa9189", + "vout": 1, + "n": 14, + "addresses": [ + "ltc1q3yq785557a33dhjzp59jrkkaujn0afsrguetcp" + ], + "isAddress": true, + "value": "188048" + }, + { + "txid": "4fe68a083656b6fae2d7fa623264698ce48f34ec37357c9177556b20b7dbe77c", + "n": 15, + "addresses": [ + "ltc1qpr6qvgwr4uv0tka9p5zx7gyhf88gam99xkhsn4" + ], + "isAddress": true, + "value": "288550" + }, + { + "txid": "9013075bc9ff19f7f23f8010585983bca5d602c6ed80e48ffe659de97246344c", + "n": 16, + "addresses": [ + "ltc1qjz0ent2u5xgsah9ar6zfm0e280g84yaw3060ze" + ], + "isAddress": true, + "value": "300000" + }, + { + "txid": "9e257fe060539ab61dd6285ffb6663035e4c74bc2a4269bea49688249a4a9672", + "vout": 1, + "n": 17, + "addresses": [ + "ltc1q4qsmvmhnvg5kf84syx3fxdyptfr0h7w7uf2et2" + ], + "isAddress": true, + "value": "543134" + }, + { + "txid": "ce9c46df8ef5fba0a385f71e89c2eab29f1b25cda0d257c4e3abb2da5259b83b", + "vout": 1, + "n": 18, + "addresses": [ + "ltc1q2vez3w9f7c0q4yreehjkmva8pv60uy77z69vm5" + ], + "isAddress": true, + "value": "667304" + }, + { + "txid": "574894f61396adb14b974031efda701829f0a91106bdd4745f7acd6a59b79563", + "n": 19, + "addresses": [ + "ltc1q3dq4vhjezkst2gtztw7a25z9jsmnzktc7jgcth" + ], + "isAddress": true, + "value": "690743" + }, + { + "txid": "b8fd90d4be97d54c8d737180ce405cf2293f54cc5000a34f11c13f889d2352d0", + "n": 20, + "addresses": [ + "ltc1q3hhcu482usaq66rzesdpdzne0wq54p3r7rknr2" + ], + "isAddress": true, + "value": "1000000" + }, + { + "txid": "d4f13258ac3595da242a83856dd3324522507a7f2a06b4c3c4829a570aa1990e", + "n": 21, + "addresses": [ + "ltc1qp96jhevfs75rlp34nxaanyxwn9mtgx5g0j896g" + ], + "isAddress": true, + "value": "1000000" + } + ], + "vout": [ + { + "value": "5561190", + "n": 0, + "spent": true, + "hex": "001474f62cc6a965d238623efd3868c2385eeb97aaba", + "addresses": [ + "ltc1qwnmze34fvhfrsc37l5ux3s3ctm4e0246w7lfy9" + ], + "isAddress": true + } + ], + "blockHash": "117bee1c7f2980b29cbcaf541f5b53a4f42f4ea34a4154e93744c713442a1c51", + "blockHeight": 1701667, + "confirmations": 138700, + "blockTime": 1568367063, + "value": "5561190", + "valueIn": "5567790", + "fees": "6600", + "hex": "01000000000116e89aacfbc4265b3ca4976717ab6ffa801e643862cf69455f4038a53366c05886000000000000000000a130df8f40011c1a8584e0f099c40ae675b91591414a554fe5316677fb921651000000000000000000ef2701724b0693e13d0689982a3acdd07d1f4ced89643b15e64f12f04972632f010000000000000000cb30748b3d42da20e3e41c157eb1ae7e365ca499569cdf3aa878ee02d772cffb01000000000000000021e62fb5b55d1d53cd27fa1fe86076357682f9011fc05d8f275b3926c84b7336010000000000000000cb30748b3d42da20e3e41c157eb1ae7e365ca499569cdf3aa878ee02d772cffb00000000000000000021e62fb5b55d1d53cd27fa1fe86076357682f9011fc05d8f275b3926c84b73360000000000000000000be54934a7188e3c5bb6a57d0623480aa060f31d11e52718244adde55a5a3900010000000000000000c5d6334bd6dc7639e53df376cd9f9f818cc0355b587c1f481474716e7d041c6101000000000000000070648c84d5c69cbb5f4c6b060a4a34fa3c36e5419c3e1cb572da40abbd9829ed000000000000000000821ff4eced44abc781e9666fb8759b66f178541587700accbec97ae2a83fd2f9010000000000000000d116010a353b608eb912f9ee0a1e3157cf87751fc9616b8dc55b4eff4281cada0000000000000000000be54934a7188e3c5bb6a57d0623480aa060f31d11e52718244adde55a5a3900000000000000000000821ff4eced44abc781e9666fb8759b66f178541587700accbec97ae2a83fd2f90000000000000000008991fae25fe411d1e5cef1d87e0edcd10ac6f4de3f16966797d3704fe93b4a640100000000000000007ce7dbb7206b5577917c3537ec348fe48c69643262fad7e2fab65636088ae64f0000000000000000004c344672e99d65fe8fe480edc602d6a5bc83595810803ff2f719ffc95b07139000000000000000000072964a9a248896a4be69422abc744c5e036366fb5f28d61db69a5360e07f259e0100000000000000003bb85952dab2abe3c457d2a0cd251b9fb2eac2891ef785a3a0fbf58edf469cce0100000000000000006395b7596acd7a5f74d4bd0611a9f0291870daef3140974bb1ad9613f6944857000000000000000000d052239d883fc1114fa30050cc543f29f25c40ce8071738d4cd597bed490fdb80000000000000000000e99a10a579a82c4c3b4062a7f7a50224532d36d85832a24da9535ac5832f1d40000000000000000000166db54000000000016001474f62cc6a965d238623efd3868c2385eeb97aaba0247304402203bf6ab7ea29cb1ca9e80555f07e5fea03941236db0e7eda0629126c22ec56eaf0220552aa5f962a8876ac74a5242b622668027f8f7417ae88032356d3b15c642668f012102b65d85bcfb9aadc1fe3b40fb79e8b52f096da4e588d2f9174a773d894e98c6fe02483045022100eb01bf49b1330223f00d03db4490a3d1fc09f5e25d8fa9e10805d782568483c902204e05f06f1184b63a2acc76ee6c0e16989329780aa3c1f9c981671c0b1400634e0121024657d84015314cec7322f9fba0137062cc5befd1c453f06a45ef9b254f95e4710247304402206f981a9fbb7805823a05156d0eb4d360f97151f8f56cf9c12d2ca5a4e32e758b022012ff0eee5a39b6f27188b639afc2dec45b40e3d87ae4f381b28af1b49bcdfd7e012103824fe9af295ce51dcf812e27162d346f2a278ac024610c184780d28989b896460247304402206e1818d244b9cddb31c20a2dfa55df18b66ed2b88c1dedf4fa842042c8b0760e022006c379842cb494a03c1cdb47a6a9e476854539e32954323fe7d550b81cdb0b970121021d27a125a6539b9c4f0a9c7be2b4ecb768603fb82559f971053d688184d84d5c02483045022100a5257c7fa40dc8e7f041ce6834b1ca2fd9db6a5e24d8e9bf4bc62dfe5175fd1202202a11909b2627c381bc56504c6bea08ed2a87fde1bd89b46b784f1787a8c65898012102fa952e151f9b7ce62774b428f0c65703955d3e9e82f6b8b06151b11ac5e6b9db02473044022018448ce769628b90c39047a8d98d622039882f3c68bf400a408cef14277244c1022065ca98159288b3967e47d6b76f04cb79aa86ad850ebfc8d6576837e7efa9eece01210255fc01e2aeb3f3d3d25dff9c8cbf5f722bb93c152d4646d01ef34ef7f041806102483045022100d42037c4feb57200e4ed4723f0f0f9150f2f3882491e9b086caedb8452ffde530220167d68970905568e3dab926a96cbfe94b01dd886902ef9895c3f332be890eb8f012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd102473044022067cbaa14c80f6ce2af43dcea8e50f162d64bd9d73d788dee5ec8aa0b3669dc7402206cc30081ef3a7a25d3386c8338a16c8ccbc84756885c5077a264245f5fefc83a012103f4ae1b4010e52d142ef2c07e2e1b14d716f8d29ea507127fe7ca59a4398c65460247304402205d7e19f44e23c03656a8c9c54c29a57248886a8217f1f9d5b341ca8382caf67902204c155a398b900d4fe9b8f06549dc0e81a0bd36bbd43e7943841c66280b0217220121021137293acd25f8494a6c5d585f113d96aa91cae982818a0aed862108f3552e470247304402206633b5bcf7357bde337cad546e844beb6145199a2762b842b623e519ea49a469022041dc087919d48c3f36be4cf8d065a9645ef61d179f7ddc5ec171991f5f99a43b0121030a7bd368800f5fcb0cd3691aae72cc10ae18d19418b1e9f340cedf447ae3c5020247304402207e524f9adc38f317002682c10a0fcf59f025b2e49da7f5dab447fc738c5a23f402202bb18a495da49203de0e36cf2416d0f10a3a39355abaaac643c2e756126ae46601210208c5e94833465331e6f6a4dba0bc93b9e486a1012e11a38fe5fc76c5b16ec21f0247304402205f7f65fc707468e9a21fb4be7ce4ed5d757c1a1eeef6147f8827c8ef8bd638af02204e33f0a5a84d641c2e921abcc3d64d27314ea4a5bfea9aee36e76ce67c3757dc0121033af85cca3c0a341068b0900a098d5a1c1ecda1dac67db6b457b65937fde93cfe0247304402201bba3c382c5c3298231b79fce8eb3c31473a95b8602ce89d03f317edea03d83102206de06bdfc5a0adbf0fd3700c5b3ce1e764be19d92d8269b8b340835218e81658012103f6c4ec9154083c6f4a82fabaf3253d87b61e64ad1023e5ffe3003e3ee92ba2cb0247304402202fbf0503733fdc01e7fb87902e0d144583aabc6bbb03dda71c251a8abc5f21eb022052dd70bb3caf32f7f9a9efb2a5008124b1494aa1e215828fd2c5039e3d28a8e10121028745fd18d99f19ea79f45dede4ff4297396d39464086a9e58f3100c6efcb8179024730440220662f7285e89d56c31429a39f5a68414529824c7e827d99ef2420e24a180604fa022078d9f263b636f4414dc190ee0a7b4a54f103abdefcc228874014c09fd9d72eae012102440f980c9746170db2a5aac6eed16f68bb0f83d2e4e7cfe953a025ac6e414e910247304402201ad5d8cb11d9ca2896509d99eef6496694920e6dd4c1804a8cd846da194d209a02201a4d6e635c6b23100272b4207ed77eeb45f8aa8dcd90801386432d6746f0acdf012103ad66203dc92d5b81773f332bc2c8bdfd3b27d90d359a21a8141407512f011f4502483045022100c1a82aa837704b975ed12785e9a33a4ec6f0d1a9131e17b6f28aaef8eb187a98022069e197cecff059133816c9e228c74242211a20a59aed646d3c12dcbcb48350cf012102c955da9410883590a79358485867ba6e3f53ea8d456873fc8d6f0b3b3fa6bc3402483045022100e4c0e7b2861c41e67b100e6c3c7a42a45ec7df9f276afcb60098b409e4677c7802207feb60ce5261b1d59818de0394e9492268b83d263da600fc9147f415fa6b652101210252127d906aa59a02d2fb617d7ff0789ce1e08b4bfea250575da50183963f56cd02473044022013b37a47a7b712569ad2db5016b81bc8ed308a1ef1e84a81326891b5fcbddb5402203574f470584185218dab0e8d9a634cd5c1f359ced78f36f4146ada86799dae360121037f0980f1dd44fe36db1cea51042ba40e88325e3792da02b2b5a6b246ca5862ab0248304502210080a2378ba9ad0738028994e1d6aa4c57405e0c7867bdb0cca578cc815ac1cd9e022020bd9a779cba23f9e6f2922ba70741b9403913d6ddc49df5c0a2544eb9a14f2c012103d37a0609c9ddbb8105e89c125f3531316322c2d9410b52512cf93a0076bdad180247304402200305f95ed6e310e12765c278f223cfef463954df9119bf2bdff357c558e856b5022019903dc65a8f3d267e56e009b85e63e86de05baebdb804f4538b753695491fec01210202f6bb1a32dd40d63f0e40a986b40bc316d69ccbf613b0e9e3f8f81e4afda63302483045022100f1e59775253a28a7f9483889d03a24216a2cd26f7a2ef4f27aa8a87b0acae11202204cb1d53dc9af89e6e4f03df16f74ef4db12ab451e616e0b2c0d745d310f93c0c0121023f82a1cb6dc690a0663518cd8f37de0b0ffc2d6701965f36e1fc6593a362266900000000" + }, + { + "txid": "36734bc826395b278f5dc01f01f98276357660e81ffa27cd531d5db5b52fe621", + "version": 1, + "vin": [ + { + "txid": "daca8142ff4e5bc58d6b61c91f7587cf57311e0aeef912b98e603b350a0116d1", + "vout": 1, + "sequence": 4294967289, + "n": 0, + "addresses": [ + "ltc1q54pcpg2fcnd4c4gwqc6uw30mjgnt086yxtfjpt" + ], + "isAddress": true, + "value": "102024" + } + ], + "vout": [ + { + "value": "55686", + "n": 0, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + }, + { + "value": "45886", + "n": 1, + "spent": true, + "hex": "001432cdaedbd052e309198160318fd599fcefb77d8f", + "addresses": [ + "ltc1qxtx6ak7s2t3sjxvpvqccl4velnhmwlv0pqegce" + ], + "isAddress": true + } + ], + "blockHash": "f6312bc43fb69c100c3faf23c9977760e1fa3932fe6f03762c62c1e38758ec19", + "blockHeight": 1699469, + "confirmations": 140898, + "blockTime": 1568043854, + "value": "101572", + "valueIn": "102024", + "fees": "452", + "hex": "01000000000101d116010a353b608eb912f9ee0a1e3157cf87751fc9616b8dc55b4eff4281cada0100000000f9ffffff0286d90000000000001600140ee85acd7206ba404a684e9655b54d32f242b7c53eb300000000000016001432cdaedbd052e309198160318fd599fcefb77d8f02473044022076533ef6060c6f92c25aa5c2f1e1cfeb9e215226518913a6cc6e2622fadf6827022078319b8fd96785034797693c0c5a8aae1504287bba2d39ad7c3d1e78d6b1aa9c01210341bc7668f0c3f15a6e227788f2654d3c9178ef0d9e7ec90312c2dcb6ff43295c00000000" + }, + { + "txid": "bf7e50d2556f5557756c52a7ccdd5349850a0552de043c96bf38dee05b9fcdcc", + "version": 1, + "vin": [ + { + "txid": "054685957c82eec4a729919809ca880e093d27d50d5fc364b6bc4000a66c62d8", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true, + "value": "3900156" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "00142b12c909673ca18b4f0e6a5eb7381e03aa94064a", + "addresses": [ + "ltc1q9vfvjzt88jsckncwdf0twwq7qw4fgpj2uf2jht" + ], + "isAddress": true + }, + { + "value": "3799704", + "n": 1, + "spent": true, + "hex": "0014260483f197a26a803ee8a57ef587bafeb74c8dbd", + "addresses": [ + "ltc1qyczg8uvh5f4gq0hg54l0tpa6l6m5erda6tw5jh" + ], + "isAddress": true + } + ], + "blockHash": "b54f669d59620ffb17a13e841bd4addcff223b8bd9a73ff10ff3e0b9b5a9dfaa", + "blockHeight": 1539785, + "confirmations": 300582, + "blockTime": 1544245351, + "value": "3899704", + "valueIn": "3900156", + "fees": "452", + "hex": "01000000000101d8626ca60040bcb664c35f0dd5273d090e88ca09989129a7c4ee827c958546050000000000ffffffff02a0860100000000001600142b12c909673ca18b4f0e6a5eb7381e03aa94064a98fa390000000000160014260483f197a26a803ee8a57ef587bafeb74c8dbd02483045022100b1fc6e52f4f462eb96ec396de56e6ea1b9bb67ceb5e447711907d1d08e78dd9702200b278ac4700ff295261d05b461984aa3ea04de118605866de12883adb52312e6012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" + }, + { + "txid": "054685957c82eec4a729919809ca880e093d27d50d5fc364b6bc4000a66c62d8", + "version": 1, + "vin": [ + { + "txid": "cf7ed8eb0b830868632072293de303d6d90ee240e80c104414b3ffeed4332e83", + "vout": 14, + "sequence": 4294967295, + "n": 0, + "addresses": [ + "MWceeqZHxJBj4UJCebKfnb1ie5akap9xsf" + ], + "isAddress": true, + "value": "5000000", + "hex": "160014c21653fb1b3d73b9b2aff9459a459e770adcc0d2" + } + ], + "vout": [ + { + "value": "3900156", + "n": 0, + "spent": true, + "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", + "addresses": [ + "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" + ], + "isAddress": true + }, + { + "value": "1099342", + "n": 1, + "spent": true, + "hex": "0014f26491d75185515cfb1d64a88eba8f3b48789137", + "addresses": [ + "ltc1q7fjfr463s4g4e7cavj5gaw508dy83yfhx7vgpw" + ], + "isAddress": true + } + ], + "blockHash": "9d5f9faba06cda333e32fb2fdc82daefeb65991417f2cebea25dabe51cd68ce6", + "blockHeight": 1539738, + "confirmations": 300629, + "blockTime": 1544237458, + "value": "4999498", + "valueIn": "5000000", + "fees": "502", + "hex": "01000000000101832e33d4eeffb31444100ce840e20ed9d603e33d297220636808830bebd87ecf0e00000017160014c21653fb1b3d73b9b2aff9459a459e770adcc0d2ffffffff02fc823b00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c54ec6100000000000160014f26491d75185515cfb1d64a88eba8f3b487891370247304402202c339116fc96796f40d8ead3ad7be4c26861b7b0a493ea4c4945b0fc4465c2ec02203055725efedbe971405671a6c148991e16b2e212c37ac02cc764881028b725690121029bbbd9e73d00bd5cb95e29077f17746cac5caa8abb7e23939a00ac18f1d8b99d00000000" + } + ] +} diff --git a/mock/ext-api-data/litecoin-api_v2_xpub_zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu__details_txs.json b/mock/ext-api-data/litecoin-api_v2_xpub_zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu__details_txs.json new file mode 100644 index 000000000..17698facd --- /dev/null +++ b/mock/ext-api-data/litecoin-api_v2_xpub_zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":13,"itemsOnPage":10,"address":"zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu","balance":"1818078","totalReceived":"379622767","totalSent":"377804689","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":130,"transactions":[{"txid":"bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1","version":1,"vin":[{"txid":"674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867","vout":1,"n":0,"addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true,"value":"788530"}],"vout":[{"value":"100000","n":0,"hex":"0014ccf05f3bc453f7f66fb48b124bd79690bc309e22","addresses":["ltc1qenc97w7y20mlvma53vfyh4ukjz7rp83zf892wx"],"isAddress":true},{"value":"688078","n":1,"hex":"00140ee85acd7206ba404a684e9655b54d32f242b7c5","addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true}],"blockHash":"ae8df4fb9cbbd07375eef217dd25e8b918a1b2746907c23cf4f2e15cd18fccdd","blockHeight":1804076,"confirmations":40929,"blockTime":1583910871,"value":"788078","valueIn":"788530","fees":"452","hex":"0100000000010167f89bc6125388f252bd770e142e61b9ab23dfb18762ba210f6f162bed92406701000000000000000002a086010000000000160014ccf05f3bc453f7f66fb48b124bd79690bc309e22ce7f0a00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100a40df50e2b419a35001f40d508e911f36d01497ebe5225dc93c81f53a30452fb022034c086517326be293019c2cbf215d6b9a53aa0ab4a0c2b890a9f1b05e8052aac012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000"},{"txid":"674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867","version":1,"vin":[{"txid":"f8ddc3eca55aa4bffd27b030fc3b35ceb8d503b31a03dafd32df56eec552fe99","vout":1,"sequence":4294967290,"n":0,"addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true,"value":"1788982"}],"vout":[{"value":"1000000","n":0,"hex":"00140ee85acd7206ba404a684e9655b54d32f242b7c5","addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true},{"value":"788530","n":1,"spent":true,"hex":"00140ee85acd7206ba404a684e9655b54d32f242b7c5","addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true}],"blockHash":"dd92763dcb8477d8f012e5ec0598ebf3c135a15780d7491754fff40d3d24dd9b","blockHeight":1803562,"confirmations":41443,"blockTime":1583831802,"value":"1788530","valueIn":"1788982","fees":"452","hex":"0100000000010199fe52c5ee56df32fdda031ab303d5b8ce353bfc30b027fdbfa45aa5ecc3ddf80100000000faffffff0240420f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c532080c00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100bbde918ff538468c440424323bbe8ba78eef14d9dde357c8e6496905d540098c02205700d984884edff918f827289898c16ec9ad30344a637ea85dc55f7f836143bd012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000"},{"txid":"f8ddc3eca55aa4bffd27b030fc3b35ceb8d503b31a03dafd32df56eec552fe99","version":1,"vin":[{"txid":"0bc6314b50a192853d09b2ca3ebadea75288bfb66e9b254c8f55ebaa720a7d2f","vout":1,"n":0,"addresses":["ltc1qd0huz2atjj0uyjlcp48ml9tltkzdta7sg8fn89"],"isAddress":true,"value":"1889434"}],"vout":[{"value":"100000","n":0,"spent":true,"hex":"0014e8d0e2bade0aefda201fad8ff5859d743b252a5b","addresses":["ltc1qargw9wk7ptha5gql4k8ltpvawsaj22jmr8cejf"],"isAddress":true},{"value":"1788982","n":1,"spent":true,"hex":"00140ee85acd7206ba404a684e9655b54d32f242b7c5","addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true}],"blockHash":"c9503e0fe18dd16a8a1e836d08d6966e443fbe79eeb0561f2fb18e5993a0cfec","blockHeight":1800498,"confirmations":44507,"blockTime":1583384860,"value":"1888982","valueIn":"1889434","fees":"452","hex":"010000000001012f7d0a72aaeb558f4c259b6eb6bf8852a7deba3ecab2093d8592a1504b31c60b01000000000000000002a086010000000000160014e8d0e2bade0aefda201fad8ff5859d743b252a5b364c1b00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100f6adacde68792f7862ec58b066ed4b521444929d90c163b5eb7b0a3d3e16c133022018f649e6a9cece3dc58fdb09f8cffb5cf9ba64f7a453ae6d82043b3fc65fe8ba01210273a11ff2e056c52a0a10c3b93590f60802ab8a74bf9828ea76ae87885fddfc8d00000000"},{"txid":"0bc6314b50a192853d09b2ca3ebadea75288bfb66e9b254c8f55ebaa720a7d2f","version":1,"vin":[{"txid":"fdbf28c741e55f846a0a378e0cf2a7263540f8d24123b658f2beb0bd1b1788f0","sequence":4294967291,"n":0,"addresses":["ltc1q2rs8e2xy7tr7c5e4zugqzwsry5dtt5wcdk4zv9"],"isAddress":true,"value":"1989886"}],"vout":[{"value":"100000","n":0,"hex":"0014307b46c6979c94598ce49d1145bc4d8eeb2704fb","addresses":["ltc1qxpa5d35hnj29nr8yn5g5t0zd3m4jwp8mwchc9c"],"isAddress":true},{"value":"1889434","n":1,"spent":true,"hex":"00146befc12bab949fc24bf80d4fbf957f5d84d5f7d0","addresses":["ltc1qd0huz2atjj0uyjlcp48ml9tltkzdta7sg8fn89"],"isAddress":true}],"blockHash":"d6aedacf9e98591e6fad1116d13d202a9067e0ace5e6c6ade28dba8ae06abe77","blockHeight":1797397,"confirmations":47608,"blockTime":1582916585,"value":"1989434","valueIn":"1989886","fees":"452","hex":"01000000000101f088171bbdb0bef258b62341d2f8403526a7f20c8e370a6a845fe541c728bffd0000000000fbffffff02a086010000000000160014307b46c6979c94598ce49d1145bc4d8eeb2704fb9ad41c00000000001600146befc12bab949fc24bf80d4fbf957f5d84d5f7d002483045022100bd323bdeb84893c4e8779a411f40d12a4ee29daf19f294e106c972f12c7a8df602207364621931435107e0b4abadc3182eb9cce20dbb932965b5a8c29196d40fb5d30121022a9c9134668be7db7109d82a55afdcc7d323eeccd8ab48704c9d16305349c08f00000000"},{"txid":"fdbf28c741e55f846a0a378e0cf2a7263540f8d24123b658f2beb0bd1b1788f0","version":1,"vin":[{"txid":"07eb5638d1a2833a7eaea596b0dc8bacd8a51be6f18f8bb8cabd514255acebff","vout":1,"sequence":4294967294,"n":0,"addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true,"value":"96312"},{"txid":"152c3d81f7272c91bd3d880d7b570619ef4141482cbcd62b5556fb00efc2bd94","sequence":4294967293,"n":1,"addresses":["ltc1q5usqkt2x9tnqljy0tss9jqmlvcmakdp4l4rdt5"],"isAddress":true,"value":"400000"},{"txid":"152c3d81f7272c91bd3d880d7b570619ef4141482cbcd62b5556fb00efc2bd94","vout":1,"sequence":4294967292,"n":2,"addresses":["ltc1q69juwlyyyks4ws8rdklldjvdxk3vk6gy9qkn99"],"isAddress":true,"value":"1650696"}],"vout":[{"value":"1989886","n":0,"spent":true,"hex":"001450e07ca8c4f2c7ec53351710013a03251ab5d1d8","addresses":["ltc1q2rs8e2xy7tr7c5e4zugqzwsry5dtt5wcdk4zv9"],"isAddress":true}],"blockHash":"5977afe7c387c7390498309e29ad71e8daef8c59df5b910cb05a3ae661db0919","blockHeight":1783073,"confirmations":61932,"blockTime":1580799867,"value":"1989886","valueIn":"2147008","fees":"157122","hex":"01000000000103ffebac554251bdcab88b8ff1e61ba5d8ac8bdcb096a5ae7e3a83a2d13856eb070100000000feffffff94bdc2ef00fb56552bd6bc2c484141ef1906577b0d883dbd912c27f7813d2c150000000000fdffffff94bdc2ef00fb56552bd6bc2c484141ef1906577b0d883dbd912c27f7813d2c150100000000fcffffff01fe5c1e000000000016001450e07ca8c4f2c7ec53351710013a03251ab5d1d802473044022015d518ae11502d4c832cde4627372c60fb89293d14f3dd39006445dce3bfe47f02207b97301e3f8b9016a515882072dafba705a4ec5e29f5ae222dbdfd5a6d83c90a012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd1024730440220478a6c3144e882f736b7b674d43768636f8d74eec28138d9ea36d05f64634aa402203827a08bb554c930e58178536257eb247a790866a7984fdffe549da7376244f201210262da88bf17e0b0575a3c9efecf7387e6d96fa9039547ac6707219defd321986102473044022053999ec5a5b454c60136144096f55a0de2402addd4a250396884bd00f3763dfe022054812eca7798ed4a4418b166c6a4e3e880cbd93ce41c620b611c35ad1c80735e012103c497991dbbf809288e18c5ab4744d59ab6b0b0bf875d2095267ea373e9837d3400000000"},{"txid":"152c3d81f7272c91bd3d880d7b570619ef4141482cbcd62b5556fb00efc2bd94","version":1,"vin":[{"txid":"9cad90704b2c24e2300c496398ba66ba216bc1df01851ba8c14fc0da8814a8ec","vout":1,"n":0,"addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true,"value":"2051148"}],"vout":[{"value":"400000","n":0,"spent":true,"hex":"0014a7200b2d462ae60fc88f5c2059037f6637db3435","addresses":["ltc1q5usqkt2x9tnqljy0tss9jqmlvcmakdp4l4rdt5"],"isAddress":true},{"value":"1650696","n":1,"spent":true,"hex":"0014d165c77c8425a15740e36dbff6c98d35a2cb6904","addresses":["ltc1q69juwlyyyks4ws8rdklldjvdxk3vk6gy9qkn99"],"isAddress":true}],"blockHash":"686ab90a08327f65c4cb5aa4227f3c0c0eb3120e922f6f6a8ba37fd20d6d2a72","blockHeight":1782650,"confirmations":62355,"blockTime":1580744939,"value":"2050696","valueIn":"2051148","fees":"452","hex":"01000000000101eca81488dac04fc1a81b8501dfc16b21ba66ba9863490c30e2242c4b7090ad9c01000000000000000002801a060000000000160014a7200b2d462ae60fc88f5c2059037f6637db34350830190000000000160014d165c77c8425a15740e36dbff6c98d35a2cb690402483045022100e633d87b26da1f508018fdf1c54f9b8bb0813aeb326c17a2622e29dec94f48ce0220123208bd0d13e1c2f16c4d3a450b783ea89211fcb054db2211ed6403335a48f3012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000"},{"txid":"d1dddff6518f20a251738d2e8e60a32a24a51f7714f115073724f1c926235c35","version":1,"vin":[{"txid":"ec3dabd2b86f78238fd8c1f113170815d8d8c71828e2b902b24123081cc18400","n":0,"addresses":["ltc1qargw9wk7ptha5gql4k8ltpvawsaj22jmr8cejf"],"isAddress":true,"value":"1000000"}],"vout":[{"value":"10000","n":0,"hex":"001450e07ca8c4f2c7ec53351710013a03251ab5d1d8","addresses":["ltc1q2rs8e2xy7tr7c5e4zugqzwsry5dtt5wcdk4zv9"],"isAddress":true},{"value":"989548","n":1,"spent":true,"hex":"0014a80b968f4309bff939d19a1c07155673087e45f4","addresses":["ltc1q4q9edr6rpxlljww3ngwqw92kwvy8u305z0uc0z"],"isAddress":true}],"blockHash":"3fa995b85d0a5a16ba7ea2201f18fff1093698abf589b509a6d03679fbca174a","blockHeight":1782621,"confirmations":62384,"blockTime":1580740200,"value":"999548","valueIn":"1000000","fees":"452","hex":"010000000001010084c11c082341b202b9e22818c7d8d815081713f1c1d88f23786fb8d2ab3dec00000000000000000002102700000000000016001450e07ca8c4f2c7ec53351710013a03251ab5d1d86c190f0000000000160014a80b968f4309bff939d19a1c07155673087e45f40247304402201551a2b9e94a2a257eed8056fe057f0c09a5199f2f1848793ef45e76a56e45ed022052205cbf0408b962a7b02343fade9ea383923c091ba8def4727f15ddcba8c73b012103ad9ca0f2fff21e45b0ebc715ed2b2d49d64e2c1ae0cd04b6caf5730471e273ca00000000"},{"txid":"c2730eca5ff4e5136371647623a0b55c020ef9003218aefebbe9347bff90c999","version":1,"vin":[{"txid":"d1dddff6518f20a251738d2e8e60a32a24a51f7714f115073724f1c926235c35","vout":1,"n":0,"addresses":["ltc1q4q9edr6rpxlljww3ngwqw92kwvy8u305z0uc0z"],"isAddress":true,"value":"989548"}],"vout":[{"value":"10000","n":0,"hex":"001450e07ca8c4f2c7ec53351710013a03251ab5d1d8","addresses":["ltc1q2rs8e2xy7tr7c5e4zugqzwsry5dtt5wcdk4zv9"],"isAddress":true},{"value":"979096","n":1,"spent":true,"hex":"0014a80b968f4309bff939d19a1c07155673087e45f4","addresses":["ltc1q4q9edr6rpxlljww3ngwqw92kwvy8u305z0uc0z"],"isAddress":true}],"blockHash":"3fa995b85d0a5a16ba7ea2201f18fff1093698abf589b509a6d03679fbca174a","blockHeight":1782621,"confirmations":62384,"blockTime":1580740200,"value":"989096","valueIn":"989548","fees":"452","hex":"01000000000101355c2326c9f124370715f114771fa5242aa3608e2e8d7351a2208f51f6dfddd101000000000000000002102700000000000016001450e07ca8c4f2c7ec53351710013a03251ab5d1d898f00e0000000000160014a80b968f4309bff939d19a1c07155673087e45f402473044022024c8ef5422a06aeb0caafa28cca510e2515896eb63b2e507ac8e466d3687983d022036529a6cff163a2c14610b1f407e8e7a0516921e454eaf0354b95888789d19d001210360847b9e16828bcad89705de8b752ea2a58ce95983ff0c30a64d48f52dfa57df00000000"},{"txid":"9cad90704b2c24e2300c496398ba66ba216bc1df01851ba8c14fc0da8814a8ec","version":1,"vin":[{"txid":"b784d0389a2450e43ea043567329d0f4e00277ac430bbcedf335d9d85451e088","vout":1,"n":0,"addresses":["ltc1q720spapzfq8j79gal5mg2efcrtv92hvktc8u76"],"isAddress":true,"value":"3051600"}],"vout":[{"value":"1000000","n":0,"hex":"0014463fec54ea2c7210057b2d6d1972a8aaaf39a543","addresses":["ltc1qgcl7c48293epqptm94k3ju4g42hnnf2r5d4ewq"],"isAddress":true},{"value":"2051148","n":1,"spent":true,"hex":"00140ee85acd7206ba404a684e9655b54d32f242b7c5","addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true}],"blockHash":"8eccbbf11afd2c3a54f2a5eae52734b37b67df50cbdea00224ad39896e0bf4f7","blockHeight":1781067,"confirmations":63938,"blockTime":1580515445,"value":"3051148","valueIn":"3051600","fees":"452","hex":"0100000000010188e05154d8d935f3edbc0b43ac7702e0f4d029735643a03ee450249a38d084b70100000000000000000240420f0000000000160014463fec54ea2c7210057b2d6d1972a8aaaf39a5434c4c1f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c5024830450221009f248a6c27f931afca2480a0d9867f77a7ed9d15a1c81aa3f1398c86cd14b02502205b96bc4b1c4dc2b16835acc656203f837c37d389ec65decfe25691e667cc3dfe012103a845425673d8c68211ab69f7de46c81ed2c42e5afbadfe3a6eab971ce5da56fa00000000"},{"txid":"b1208bcfb49b5fbc3366bf07b0000b884d59ecdbebc25b1a55f91330317603db","version":1,"vin":[{"txid":"a54db30dd54adc3e90a1c5e72b6a5b94992591cbc325adfc28cee55ab5f9dbc0","vout":1,"n":0,"addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true,"value":"3252504"}],"vout":[{"value":"100000","n":0,"spent":true,"hex":"0014b329897dc74dc8d7fa2a68a366593bf266dcda5c","addresses":["ltc1qkv5cjlw8fhyd0732dz3kvkfm7fndekjurha9ua"],"isAddress":true},{"value":"3152052","n":1,"spent":true,"hex":"00140ee85acd7206ba404a684e9655b54d32f242b7c5","addresses":["ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept"],"isAddress":true}],"blockHash":"28f684c412c4394e2da6255567957a493d35a7c7675d8d21a21fab4f3210d772","blockHeight":1778975,"confirmations":66030,"blockTime":1580198750,"value":"3252052","valueIn":"3252504","fees":"452","hex":"01000000000101c0dbf9b55ae5ce28fcad25c3cb912599945b6a2be7c5a1903edc4ad50db34da501000000000000000002a086010000000000160014b329897dc74dc8d7fa2a68a366593bf266dcda5cb4183000000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502473044022007410f524d5597d7ffde5ceff733bcbc05d842194c1ed650ba3ac0bcde4f561902201dde5782c6c47fac0d05fde0df0b7862649b6c3d391d61881733e4e0bb8bc0d8012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000"}],"usedTokens":123,"tokens":[{"type":"XPUBAddress","name":"ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept","path":"m/84'/2'/0'/0/0","transfers":19,"decimals":8,"balance":"1688078","totalReceived":"25679292","totalSent":"23991214"},{"type":"XPUBAddress","name":"ltc1q2rs8e2xy7tr7c5e4zugqzwsry5dtt5wcdk4zv9","path":"m/84'/2'/0'/0/54","transfers":4,"decimals":8,"balance":"20000","totalReceived":"2009886","totalSent":"1989886"},{"type":"XPUBAddress","name":"ltc1q2j0k8v7aczdajd42g96h7gy4jef63feh77494u","path":"m/84'/2'/0'/0/58","transfers":3,"decimals":8,"balance":"10000","totalReceived":"11000","totalSent":"1000"},{"type":"XPUBAddress","name":"ltc1qxpa5d35hnj29nr8yn5g5t0zd3m4jwp8mwchc9c","path":"m/84'/2'/0'/0/59","transfers":1,"decimals":8,"balance":"100000","totalReceived":"100000","totalSent":"0"}]} diff --git a/mock/ext-api-data/nano-api.json b/mock/ext-api-data/nano-api.json new file mode 100644 index 000000000..98330dded --- /dev/null +++ b/mock/ext-api-data/nano-api.json @@ -0,0 +1,69 @@ +{ + "account": "nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z", + "history": [ + { + "type": "send", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "1083000821328155744662798729216", + "local_timestamp": "1576911471", + "height": "8", + "hash": "05A23A254272028F349BB7E74115A5101B2048786A5437D1EBBE8807CEFF1E82" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "1047300821328155744662798729216", + "local_timestamp": "1576911468", + "height": "7", + "hash": "13B8146F059C4D5695DCBCEEC750EAEDDDD8F436A6FAD569A107F2FAC0F899D5" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "34700000000000000000000000000", + "local_timestamp": "1576911454", + "height": "6", + "hash": "8A2A5840C9286B35D998F5AD535851750C1AFE7B0C7D3AA61E06A1628EDD0E94" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "1000000000000000000000000000", + "local_timestamp": "1575913533", + "height": "5", + "hash": "6816B5AC0594ED768CEC45F5DE25CBF0420300800B6C3C55E6749102F8B09C81" + }, + { + "type": "send", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "1083000821328155744662798729216", + "local_timestamp": "1575498786", + "height": "4", + "hash": "D9F97A2AB82EDFAA7A23FFA3423B286A8DD361B5B9303C5E0262EB684162DFD6" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "713600821328155744662798729216", + "local_timestamp": "1575498271", + "height": "3", + "hash": "69F4616925EC95DC15D97037BD99E2E782C2D2A557D5CE11E7FBB4BB6FF617F5" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "234700000000000000000000000000", + "local_timestamp": "1575498125", + "height": "2", + "hash": "6CE398F84A6B3F71E41E843C34917DAC408990C8468EFBC36CFC04954B113A43" + }, + { + "type": "receive", + "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", + "amount": "134700000000000000000000000000", + "local_timestamp": "1575498066", + "height": "1", + "hash": "586BB82BADA98D6F8E4639DA6884C6562141AB983D885780FA41F31F7A04EC18" + } + ] +} diff --git a/mock/ext-api-data/nano-api.request_json b/mock/ext-api-data/nano-api.request_json new file mode 100644 index 000000000..8021a609a --- /dev/null +++ b/mock/ext-api-data/nano-api.request_json @@ -0,0 +1,5 @@ +{ + "action": "account_history", + "account": "nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z", + "count": "25" +} \ No newline at end of file diff --git a/mock/ext-api-data/nebulas-api_tx__a_n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a_p_0.json b/mock/ext-api-data/nebulas-api_tx__a_n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a_p_0.json new file mode 100644 index 000000000..cc9d4295c --- /dev/null +++ b/mock/ext-api-data/nebulas-api_tx__a_n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a_p_0.json @@ -0,0 +1,845 @@ +{ + "code": 0, + "msg": "success", + "data": { + "txnList": [ + { + "hash": "3afb557c68311d0a0045f4b7c3b2f1e96a128fdcd08e0d376a58f0c1f7df0959", + "block": { + "hash": "41895b3957647269a1d45fcde5b22a5f4c2b404f62e0b96ec5db44d0537aa293", + "height": 2857937, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 15, + "timestamp": 1565358420000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20719", + "createdAt": 1565358648000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"266794000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 24008254461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414380000000000" + }, + { + "hash": "2ffedf0d8d1f85717edbcec32c6b4da43687a783f535b65f772775015aa0ec24", + "block": { + "hash": "84e0ba4e7a4e7c6a4a3cd6b4c4a2ddb576eba3415bd0cdeb002539450ee95d9c", + "height": 2851699, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 14, + "timestamp": 1565264850000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20719", + "createdAt": 1565265078000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"366146000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 24101824461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414380000000000" + }, + { + "hash": "e80b921f5f275f0132608b9ea7e3c1b0e8509793f4c72ec9ea989687a715fb57", + "block": { + "hash": "e28ff13cbe3bd39dc3414f5b7c5ce0620955d27a582008a11382dc2c0d910103", + "height": 2769477, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 13, + "timestamp": 1564027140000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20717", + "createdAt": 1564027360000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"66500000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 25339534461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414340000000000" + }, + { + "hash": "821e8833cfb757e434f7a16b95189289c8dc6c69ef068827e78b0f69e7bb5514", + "block": { + "hash": "c9b02c838c3bcd3d891233ec933840b625122a8ae6ff76961de1d75120a0374f", + "height": 2765282, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 12, + "timestamp": 1563964215000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20717", + "createdAt": 1563964436000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"99100000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 25402459461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414340000000000" + }, + { + "hash": "e0c8342c894089927c2bbe8119605a472ad096184070da1c1591535975d067be", + "block": { + "hash": "5f0d55388f440868187b9f7942f0f8d9a76b91f16cc01bebcac66a59ec4ca500", + "height": 2735174, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 11, + "timestamp": 1563511485000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20717", + "createdAt": 1563511705000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"45000000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 25855189461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414340000000000" + }, + { + "hash": "3517fba15592a0f69deb921e9e6510d002cb2cc639943042fc063c854c03cd94", + "block": { + "hash": "7262c28414cb2728f093030b59fc1dbe9570b861dc3e1c8874b7963c8bec7376", + "height": 2717106, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 10, + "timestamp": 1563240465000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20717", + "createdAt": 1563240685000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"44300000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 26126209461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414340000000000" + }, + { + "hash": "477900d583540585ec39856d761fe200dee818d68312f0c79f9a67ab37f49712", + "block": { + "hash": "5bd043964e0a1e96cd3c92e3e21570e019671239cc187d72107841f720512e3a", + "height": 2705263, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 9, + "timestamp": 1563062820000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20717", + "createdAt": 1563063040000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"66600000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 26303854461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414340000000000" + }, + { + "hash": "69e18ceda9310b922cadc2b7d9979d516045d342be20f2301850ebe9160bc336", + "block": { + "hash": "3d8c155854dc9a739d274ef4ff3a60f53da2225e6ac2e672f827d2212f2e608b", + "height": 2694665, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 8, + "timestamp": 1562903850000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20717", + "createdAt": 1562904235000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"62600000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 26462824461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414340000000000" + }, + { + "hash": "5b8de6ea8ad09c42d3032047f4e2f43f4436576162b2ff27f9d9c87a6662e388", + "block": { + "hash": "034d985a2843214841caef93838291682687dcea5628b0499ed81bb01155627d", + "height": 2691184, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 7, + "timestamp": 1562851635000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20719", + "createdAt": 1562851854000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"360000000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 26515039461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414380000000000" + }, + { + "hash": "ec7babae2ecc45474dbed9a0bb68b570b0e58321fb7ccf36d15f6f6f8aa0b86b", + "block": { + "hash": "f2f917d6337d03fcfb4f9f810e7168dac5b36dd62446f4c767a9ec13521e2767", + "height": 2691056, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 6, + "timestamp": 1562849715000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20719", + "createdAt": 1562849934000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"186600000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 26516959461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414380000000000" + }, + { + "hash": "3e43a6e29a40e3eaed69bf20f256dba1e70c21beae56261259e79241aa43a5bd", + "block": { + "hash": "d3797ac98dd02768103c8340b7c00d8799f0f424648218656bd086897b602097", + "height": 2683417, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 5, + "timestamp": 1562735130000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20719", + "createdAt": 1562735349000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"360000000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 26631544461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414380000000000" + }, + { + "hash": "2a93c599c49af9664ff949cca00cbaf210e0702e9e7ba1fc708fc8f786822146", + "block": { + "hash": "e095e6ba7e621c9a6411e56e097bc952eb58ce7aa1807189f502e7690b5e7c93", + "height": 2667467, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 4, + "timestamp": 1562491605000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20719", + "createdAt": 1562491834000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"222200000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 26875069461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414380000000000" + }, + { + "hash": "60258c4568dd7abdca5c88c643af13658115958a707c22e0c3be0a81ccdbc415", + "block": { + "hash": "0943ddcc1c262579ef2a1490438c091e860ca0e84641e39bacb31ef9843a409b", + "height": 2666815, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 3, + "timestamp": 1562481825000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20717", + "createdAt": 1562482139000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"55500000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 26884849461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414340000000000" + }, + { + "hash": "30a4b0d3e04a43dd5fab02e6f48033acf6481be8fc04e0dcbff577b1f3e32477", + "block": { + "hash": "9aca38686b913c7d30c07df83fee4a6e4de69c5ffbe71c3a47f9da89613db9a7", + "height": 2662772, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 2, + "timestamp": 1562421180000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20717", + "createdAt": 1562421408000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"41200000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 26945494461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414340000000000" + }, + { + "hash": "3cd98a767d8f5eaa87c8ffa95adbde3a4c08236b49ab0296f04057491e4bd1a3", + "block": { + "hash": "9bb20444ae79a542af44ed64241a440759aa59363641fa1b7594266f6f16109d", + "height": 2659950, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", + "alias": "", + "balance": "200", + "percentage": null, + "txCnt": null, + "type": 1 + }, + "status": 1, + "value": "0", + "nonce": 1, + "timestamp": 1562378850000, + "type": "call", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20711", + "createdAt": 1562379080000, + "data": "{\"Function\":\"transfer\",\"Args\":\"[\\\"n1R6kbYGyb4vaX9ZKpjrFMd2Ry4CWhCV4B8\\\",\\\"116600000000\\\"]\"}", + "currentTimestamp": 1589366674461, + "timeDiff": 26987824461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "414220000000000" + }, + { + "hash": "0d06074b64c37ed24a17162d1e0ef8a8e65122fc7758c90c969e61735bc4396a", + "block": { + "hash": "faf4eb93b1a571c709bf1871e1c142570d3f5aeb787d325eba9a34a6ca56144b", + "height": 2659949, + "timestamp": null, + "parentHash": null, + "miner": null, + "txnCnt": 0, + "gasLimit": null, + "avgGasPrice": null, + "gasReward": null, + "currentTimestamp": null, + "timeDiff": null + }, + "from": { + "rank": null, + "hash": "n1YDRkSbuzjRVYPbmGC9qULchXMeqS451Je", + "alias": "", + "balance": "37962400000000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "to": { + "rank": null, + "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", + "alias": "", + "balance": "3784780000000000", + "percentage": null, + "txCnt": null, + "type": 0 + }, + "status": 1, + "value": "10000000000000000", + "nonce": 210, + "timestamp": 1562378835000, + "type": "binary", + "gasPrice": "20000000000", + "gasLimit": "50000", + "gasUsed": "20000", + "createdAt": 1562379063000, + "data": "", + "currentTimestamp": 1589366674461, + "timeDiff": 26987839461, + "contractAddress": "", + "executeError": "", + "events": null, + "tokenName": null, + "decimal": null, + "txFee": "400000000000000" + } + ], + "totalPage": 1, + "maxDisplayCnt": 16, + "type": "address", + "currentPage": 0, + "txnCnt": 16 + } +} \ No newline at end of file diff --git a/mock/ext-api-data/nimiq-rpc.json b/mock/ext-api-data/nimiq-rpc.json new file mode 100644 index 000000000..613ddfd30 --- /dev/null +++ b/mock/ext-api-data/nimiq-rpc.json @@ -0,0 +1,51 @@ +{ + "jsonrpc": "2.0", + "result": [ + { + "hash": "e22d6f251c507a9083a1f654ad002e5cbf31f61e4e3ac5e38ed69b291c78aaec", + "blockHash": "544db1d7d4216c97a9c3658c71f1a3e00783b28316ddee2c2fc26a4cfb6ccdb0", + "blockNumber": 1082279, + "timestamp": 1588928787, + "confirmations": 8628, + "from": "def95e3bb528fef142b1d78fa656cd7f76339345", + "fromAddress": "NQ25 TTUM UEVM 53YF 2GMH SX7S CMND FVT3 74S5", + "to": "8b12a9a5a81bf52a9afb47a16b57d4c81c51fc07", + "toAddress": "NQ94 HC9A K9D8 3FSJ M6PT 8XGN NMXL R0E5 3Y07", + "value": 10000, + "fee": 0, + "data": "74657374", + "flags": 0 + }, + { + "hash": "8674d985ac1ea2a75fe9b35ed11d629cef8adfed50db6a5eb125351e622bb405", + "blockHash": "11b0a3aaf64119cfbc66b7fdb8c38d5734a7f50d5bbb0116ee579eb1de513c3f", + "blockNumber": 543545, + "timestamp": 1556458272, + "confirmations": 547362, + "from": "21c7fc976349d39188b3d239b3b86ab66daeafc2", + "fromAddress": "NQ32 473Y R5T3 979R 325K S8UT 7E3A NRNS VBX2", + "to": "8b12a9a5a81bf52a9afb47a16b57d4c81c51fc07", + "toAddress": "NQ94 HC9A K9D8 3FSJ M6PT 8XGN NMXL R0E5 3Y07", + "value": 42839, + "fee": 138, + "data": null, + "flags": 0 + }, + { + "hash": "c3c6e87cba620095a2aeb9898f07077d184e20a68f53798032857cc842dfb0c0", + "blockHash": "9b51f58b8ca881e2b182e1f544d09e4f1fe265b0f478fd41bf0128099013abd8", + "blockNumber": 354736, + "timestamp": 1545080725, + "confirmations": 736171, + "from": "e9a799c4fce6198cfb2eaacdeda5231078227d62", + "fromAddress": "NQ61 V6KR KH7U UQCQ RXRE MB6X T993 21U2 4YB2", + "to": "8b12a9a5a81bf52a9afb47a16b57d4c81c51fc07", + "toAddress": "NQ94 HC9A K9D8 3FSJ M6PT 8XGN NMXL R0E5 3Y07", + "value": 99808, + "fee": 192, + "data": "3c7363726970743e64656275676765723b3c2f7363726970743e", + "flags": 0 + } + ], + "id": 345 +} diff --git a/mock/ext-api-data/nimiq-rpc.request_json b/mock/ext-api-data/nimiq-rpc.request_json new file mode 100644 index 000000000..f347dd267 --- /dev/null +++ b/mock/ext-api-data/nimiq-rpc.request_json @@ -0,0 +1,9 @@ +{ + "jsonrpc": "2.0", + "method": "getTransactionsByAddress", + "params": [ + "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", + "25" + ], + "id": 345 +} diff --git a/mock/ext-api-data/ontology-api_v2_addresses_AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7_transactions__page_number_1_page_size_20.json b/mock/ext-api-data/ontology-api_v2_addresses_AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7_transactions__page_number_1_page_size_20.json new file mode 100644 index 000000000..cb68c12eb --- /dev/null +++ b/mock/ext-api-data/ontology-api_v2_addresses_AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7_transactions__page_number_1_page_size_20.json @@ -0,0 +1,478 @@ +{ + "code": 0, + "msg": "SUCCESS", + "result": [ + { + "tx_hash": "d3be042ae21a313bc70fbfea62d11fb32731126101859a66f523e081c3fd429c", + "tx_type": 209, + "tx_time": 1582189609, + "block_height": 7836941, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.4", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "5c9a5f708953ee6cd13623e9d3fd610530159fafe71a8d207d890ed7b97f3ced", + "tx_type": 209, + "tx_time": 1582188446, + "block_height": 7836832, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.02", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "7e35568117aaed4e041d281087b2f47da91a4ac183c370d40040aa2b496d5878", + "tx_type": 209, + "tx_time": 1582122942, + "block_height": 7832679, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.011074432", + "from_address": "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "0ae15301f25a5067c075a25e722f0624a813a1352363197de2dd5f61ebd2998d", + "tx_type": 209, + "tx_time": 1581924056, + "block_height": 7819845, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "7703b0bdbd5dfc2aef18fca5e97e5111c6396afb2d47fd49d8e6e9b1883d9eae", + "tx_type": 209, + "tx_time": 1581923995, + "block_height": 7819841, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "f06739a6cc0234594e2596c1157421340a5402d745c9bfee3d670b9412a5968d", + "tx_type": 209, + "tx_time": 1581923960, + "block_height": 7819838, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "24a8ed27b5e9cbd05d3a7a7d0c9b4f6c7202506850fec9ceee61e3208bbad0bc", + "tx_type": 209, + "tx_time": 1581672488, + "block_height": 7802292, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "3", + "from_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "b9fb8e42805e3d3f12bfc7dd3006cfbc87b566ce30a6e79306703ed54cfb0f9b", + "tx_type": 209, + "tx_time": 1581672381, + "block_height": 7802280, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1.088812264", + "from_address": "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "4eafca0304ec6dcc379d08ab02937c206b0cb4832bf1bebc74f12b0700ab4b95", + "tx_type": 209, + "tx_time": 1581672318, + "block_height": 7802274, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "8", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "f16894191a43ab67d345157ef3dda6f1474a78bdecb1b6a48a70c67e07d5d729", + "tx_type": 209, + "tx_time": 1581672241, + "block_height": 7802270, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "5", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "a27863c8a5161fb825afa011833f9321f9ee5d204f24725cc8495c167df95d72", + "tx_type": 209, + "tx_time": 1581672122, + "block_height": 7802264, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "20867ce80fc89d6158bcf76d0e641da6fc15b0571ddeef1db673583c97619783", + "tx_type": 209, + "tx_time": 1581672070, + "block_height": 7802261, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "dde76879ca254fa32485e705e40be7cf909cf214f1c6be6871351f44594c57c1", + "tx_type": 209, + "tx_time": 1564153943, + "block_height": 5924951, + "fee": "0.01", + "block_index": 2, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "936ee120a79f40f7a9e74ca3888a8551a6d7699c1043118ebc69dd84c4e24194", + "tx_type": 209, + "tx_time": 1564152570, + "block_height": 5924099, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "25e89a33a79dd1763be5db1ea3cea8f484559df4c8d2141af4f1170bbfab10df", + "tx_type": 209, + "tx_time": 1564152252, + "block_height": 5924047, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "8ce81e7e435f37201a358acbe9b8feb4e820e9a33a66533cbbacb6e92e270ce8", + "tx_type": 209, + "tx_time": 1558638754, + "block_height": 4081289, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "c24bd2a5cf0d18716478a556fab43bf39aa87b914a5cc73d8882a9dc15e68510", + "tx_type": 209, + "tx_time": 1558638721, + "block_height": 4081280, + "fee": "0.01", + "block_index": 2, + "confirm_flag": 1, + "transfers": [ + { + "amount": "4.0801", + "from_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "076a3835937fca68d12ef08636e72ea95e7c0b4941b2290f34612e57520c7d4c", + "tx_type": 209, + "tx_time": 1558638699, + "block_height": 4081276, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "4", + "from_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "d68ee61fca2e8d958c92c802b0dbb5aec41d037fc8d20ddf5aaebea6a48d7388", + "tx_type": 209, + "tx_time": 1558028977, + "block_height": 3910475, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "1", + "from_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + } + ] + }, + { + "tx_hash": "d773150c3b2e4524cb8138a13528397c01436ece597056e9d86be8eee14c0902", + "tx_type": 209, + "tx_time": 1558028471, + "block_height": 3910415, + "fee": "0.01", + "block_index": 2, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.0001", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/opensea-api_api_v1_assets___collection_unstoppable-domains_limit_300_owner_0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d.json b/mock/ext-api-data/opensea-api_api_v1_assets___collection_unstoppable-domains_limit_300_owner_0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d.json new file mode 100644 index 000000000..412ba8d8e --- /dev/null +++ b/mock/ext-api-data/opensea-api_api_v1_assets___collection_unstoppable-domains_limit_300_owner_0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d.json @@ -0,0 +1,252 @@ +{ + "assets": [ + { + "token_id": "107221826727469155718680588460379721284635325845036369130032935095484960793482", + "num_sales": 0, + "background_color": "4C47F7", + "image_url": "https://storage.opensea.io/files/fec912a0664aecaa908ee888177ebfc6.svg", + "image_preview_url": "https://lh3.googleusercontent.com/cqCHmaBgbAtaE5i-jRKLGbJy2C-AUnDXN8zpkw8JPKnqRNGXdMJme_ThTFL30mDN9u9piJ4ACcfHmmDAyaXfIocN=s250", + "image_thumbnail_url": "https://lh3.googleusercontent.com/cqCHmaBgbAtaE5i-jRKLGbJy2C-AUnDXN8zpkw8JPKnqRNGXdMJme_ThTFL30mDN9u9piJ4ACcfHmmDAyaXfIocN=s128", + "image_original_url": null, + "animation_url": null, + "animation_original_url": null, + "name": "sloth", + "description": "A .crypto blockchain domain. Use it to resolve your cryptocurrency addresses and decentralized websites.", + "external_link": "https://unstoppabledomains.com/search?searchTerm=sloth.crypto", + "asset_contract": { + "address": "0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe", + "asset_contract_type": "non-fungible", + "created_date": "2019-12-10T08:55:01.176657", + "name": ".crypto", + "nft_version": "3.0", + "opensea_version": null, + "owner": null, + "schema_name": "ERC721", + "symbol": "", + "total_supply": null, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "external_link": "https://unstoppabledomains.com/", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + "owner": { + "user": null, + "profile_img_url": "https://storage.googleapis.com/opensea-static/opensea-profile/6.png", + "address": "0x84e79d544b4b13bc3560069cfd56a9d5bbe7521d", + "config": "", + "discord_id": "" + }, + "permalink": "https://opensea.io/assets/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/107221826727469155718680588460379721284635325845036369130032935095484960793482", + "collection": { + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-12-10T08:55:01.591598", + "default_to_fiat": false, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "discord_url": null, + "display_data": { + "card_display_style": "padded", + "images": [ + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" + ] + }, + "external_url": "https://unstoppabledomains.com/", + "featured": false, + "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", + "medium_username": null, + "name": "Unstoppable Domains", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "unstoppable-domains", + "telegram_url": null, + "twitter_username": null, + "wiki_url": null + }, + "decimals": 0, + "auctions": null, + "sell_orders": [], + "traits": [ + { + "trait_type": "level", + "value": 2, + "display_type": null, + "max_value": null, + "trait_count": 0, + "order": null + }, + { + "trait_type": "domain", + "value": "sloth.crypto", + "display_type": null, + "max_value": null, + "trait_count": 1, + "order": null + }, + { + "trait_type": "type", + "value": "standard", + "display_type": null, + "max_value": null, + "trait_count": 53754, + "order": null + } + ], + "last_sale": null, + "top_bid": null, + "current_price": null, + "current_escrow_price": null, + "listing_date": null, + "is_presale": false, + "transfer_fee_payment_token": null, + "transfer_fee": null + }, + { + "token_id": "39602885785430968515488172908991286516392379555774938600072517130912304722435", + "num_sales": 0, + "background_color": "4C47F7", + "image_url": "https://storage.opensea.io/files/a9d70320f34fb5fb5183d1a9913d2267.svg", + "image_preview_url": "https://lh3.googleusercontent.com/vbjIXUNL8ghOTEn7W6j_ALfwbFl4EOaYdqZjIwmtgdPQ92kzTd3jJjk7fsjJuW2IKkCT80JPuJ6PX_dChnOKI0yK=s250", + "image_thumbnail_url": "https://lh3.googleusercontent.com/vbjIXUNL8ghOTEn7W6j_ALfwbFl4EOaYdqZjIwmtgdPQ92kzTd3jJjk7fsjJuW2IKkCT80JPuJ6PX_dChnOKI0yK=s128", + "image_original_url": null, + "animation_url": null, + "animation_original_url": null, + "name": "vikmeup", + "description": "A .crypto blockchain domain. Use it to resolve your cryptocurrency addresses and decentralized websites.", + "external_link": "https://unstoppabledomains.com/search?searchTerm=vikmeup.crypto", + "asset_contract": { + "address": "0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe", + "asset_contract_type": "non-fungible", + "created_date": "2019-12-10T08:55:01.176657", + "name": ".crypto", + "nft_version": "3.0", + "opensea_version": null, + "owner": null, + "schema_name": "ERC721", + "symbol": "", + "total_supply": null, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "external_link": "https://unstoppabledomains.com/", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + "owner": { + "user": null, + "profile_img_url": "https://storage.googleapis.com/opensea-static/opensea-profile/6.png", + "address": "0x84e79d544b4b13bc3560069cfd56a9d5bbe7521d", + "config": "", + "discord_id": "" + }, + "permalink": "https://opensea.io/assets/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/39602885785430968515488172908991286516392379555774938600072517130912304722435", + "collection": { + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-12-10T08:55:01.591598", + "default_to_fiat": false, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "discord_url": null, + "display_data": { + "card_display_style": "padded", + "images": [ + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" + ] + }, + "external_url": "https://unstoppabledomains.com/", + "featured": false, + "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", + "medium_username": null, + "name": "Unstoppable Domains", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "unstoppable-domains", + "telegram_url": null, + "twitter_username": null, + "wiki_url": null + }, + "decimals": 0, + "auctions": null, + "sell_orders": [], + "traits": [ + { + "trait_type": "level", + "value": 2, + "display_type": null, + "max_value": null, + "trait_count": 0, + "order": null + }, + { + "trait_type": "domain", + "value": "vikmeup.crypto", + "display_type": null, + "max_value": null, + "trait_count": 1, + "order": null + }, + { + "trait_type": "type", + "value": "standard", + "display_type": null, + "max_value": null, + "trait_count": 53754, + "order": null + } + ], + "last_sale": null, + "top_bid": null, + "current_price": null, + "current_escrow_price": null, + "listing_date": null, + "is_presale": false, + "transfer_fee_payment_token": null, + "transfer_fee": null + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/opensea-api_api_v1_collections___asset_owner_0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d_limit_1000.json b/mock/ext-api-data/opensea-api_api_v1_collections___asset_owner_0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d_limit_1000.json new file mode 100644 index 000000000..7ca8e5f9d --- /dev/null +++ b/mock/ext-api-data/opensea-api_api_v1_collections___asset_owner_0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d_limit_1000.json @@ -0,0 +1,620 @@ +[ + { + "primary_asset_contracts": [ + { + "address": "0x1d963688fe2209a98db35c67a041524822cf04ff", + "asset_contract_type": "non-fungible", + "created_date": "2019-01-23T02:17:28.643618", + "name": "MarbleCards", + "nft_version": "3.0", + "opensea_version": null, + "owner": 204604, + "schema_name": "ERC721", + "symbol": "MRBLNFT", + "total_supply": null, + "description": "Claim the most amazing web pages. Remember that every web page can only be marbled once and by one person only. Once a card is created, that URL is claimed forever. Now go create some classics!", + "external_link": "https://marble.cards", + "image_url": "https://lh3.googleusercontent.com/JHs53JRA6f3VcBqqORnoL4_q4kLDeZkDgZkmbY3iziyQQ14IRtP3mQglePCmHpXE_fit88FH8cAFMUA3j54mivAA=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 250, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 500, + "payout_address": "0xee68e4c594b96efc19a9d7d2a33901651ce967a2" + } + ], + "traits": { + "collection_id": { + "min": 31, + "max": 1240 + }, + "Collection ID": { + "min": 1, + "max": 5874 + }, + "level": { + "min": 1, + "max": 100 + } + }, + "stats": { + "seven_day_volume": 3.55387032921667, + "seven_day_change": 3.477981220593884, + "total_volume": 355.11668333704, + "count": 58646, + "num_owners": 1112, + "market_cap": 5091.571634292053, + "average_price": 0.163799208181292, + "items_sold": 2055 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-04-26T22:13:21.421079", + "default_to_fiat": false, + "description": "Claim the most amazing web pages. Remember that every web page can only be marbled once and by one person only. Once a card is created, that URL is claimed forever. Now go create some classics!", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "250", + "discord_url": null, + "display_data": { + "card_display_style": "contain", + "images": [ + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18612-1552667321.png", + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18905-1552770831.png", + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18704-1552750420.png", + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/8829-1550886013.png", + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18951-1552772148.png", + "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18950-1552772146.png" + ] + }, + "external_url": "https://marble.cards", + "featured": false, + "featured_image_url": "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff-featured-1556589463.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/JHs53JRA6f3VcBqqORnoL4_q4kLDeZkDgZkmbY3iziyQQ14IRtP3mQglePCmHpXE_fit88FH8cAFMUA3j54mivAA=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/JHs53JRA6f3VcBqqORnoL4_q4kLDeZkDgZkmbY3iziyQQ14IRtP3mQglePCmHpXE_fit88FH8cAFMUA3j54mivAA", + "medium_username": null, + "name": "MarbleCards", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": "0xee68e4c594b96efc19a9d7d2a33901651ce967a2", + "require_email": false, + "short_description": "Claim websites as unique crypto collectibles", + "slug": "marblecards", + "telegram_url": null, + "twitter_username": null, + "wiki_url": null, + "owned_asset_count": 1 + }, + { + "primary_asset_contracts": [ + { + "address": "0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85", + "asset_contract_type": "non-fungible", + "created_date": "2019-05-08T21:59:29.327544", + "name": "ENS", + "nft_version": "3.0", + "opensea_version": null, + "owner": 279872, + "schema_name": "ERC721", + "symbol": "ENS", + "total_supply": null, + "description": "Ethereum Name Service (ENS) domains are secure domain names for the decentralized world. ENS domains provide a way for users to map human readable names to blockchain and non-blockchain resources, like Ethereum addresses, IPFS hashes, or website URLs. ENS domains can be bought and sold on secondary markets.", + "external_link": "https://ens.domains", + "image_url": "https://lh3.googleusercontent.com/0cOqWoYA7xL9CkUjGlxsjreSYBdrUBE0c6EO1COG4XE8UeP-Z30ckqUNiL872zHQHQU5MUNMNhfDpyXIP17hRSC5HQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": "" + } + ], + "traits": { + "Length": { + "min": 3, + "max": 70 + } + }, + "stats": { + "seven_day_volume": 2.265, + "seven_day_change": -0.2688529157501554, + "total_volume": 6335.24578031905, + "count": 353624, + "num_owners": 30593, + "market_cap": 270232.0665581858, + "average_price": 0.710298405063446, + "items_sold": 8913 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-05-08T21:59:36.282454", + "default_to_fiat": false, + "description": "Ethereum Name Service (ENS) domains are secure domain names for the decentralized world. ENS domains provide a way for users to map human readable names to blockchain and non-blockchain resources, like Ethereum addresses, IPFS hashes, or website URLs. ENS domains can be bought and sold on secondary markets.", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "discord_url": null, + "display_data": { + "card_display_style": "cover", + "images": [ + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/26693679858283927161893791132395207263838168762475401800426021835398462679008-1565293871.png", + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/14216961695379335495094368768338390872453914418325715259759390099828279953313-1565293758.png", + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/28032727276679833339346855127845420552876278365164540739421161968857583632995-1565293757.png", + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/5939065732706496924433039736405736608461463576171087944642507927497598723058-1565293758.png", + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/8268680357553423178495517182551079885250260646681574205692425339615070583014-1565293756.png", + "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/96156505551778134260224136134970011352406026760333505247707872912354314952431-1565293756.png" + ] + }, + "external_url": "https://ens.domains", + "featured": false, + "featured_image_url": "https://storage.googleapis.com/opensea-static/official-ens-logo.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/0cOqWoYA7xL9CkUjGlxsjreSYBdrUBE0c6EO1COG4XE8UeP-Z30ckqUNiL872zHQHQU5MUNMNhfDpyXIP17hRSC5HQ=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/0cOqWoYA7xL9CkUjGlxsjreSYBdrUBE0c6EO1COG4XE8UeP-Z30ckqUNiL872zHQHQU5MUNMNhfDpyXIP17hRSC5HQ", + "medium_username": null, + "name": "Ethereum Name Service (ENS)", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": "", + "require_email": false, + "short_description": null, + "slug": "ens", + "telegram_url": null, + "twitter_username": null, + "wiki_url": null, + "owned_asset_count": 2 + }, + { + "primary_asset_contracts": [ + { + "address": "0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c", + "asset_contract_type": "non-fungible", + "created_date": "2019-10-24T11:06:57.511707", + "name": "KnightStory Item", + "nft_version": "3.0", + "opensea_version": null, + "owner": 1672886, + "schema_name": "ERC721", + "symbol": "", + "total_supply": "1", + "description": "Knight Story is an innovative mobile RPG powered by blockchain. The game is the second title of Biscuit; developed EOS Knights, the legendary blockchain game.", + "external_link": "https://knightstory.io", + "image_url": "https://lh3.googleusercontent.com/Hwr0JNz9lHdTeu3mZTawVun-BdKRf-zSpi5ZUDxirBbPs_-hW92qHfh25QcTzeGCPy0FRULooZyTJ6MlRh8qaq4=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": "0x9702a479115788294232c384a5c1f42c881789fe" + } + ], + "traits": { + "attack": { + "min": 7, + "max": 5502 + }, + "attack (set)": { + "min": 60, + "max": 714 + }, + "defense": { + "min": 2, + "max": 2242 + }, + "defense (set)": { + "min": 70, + "max": 288 + }, + "hp": { + "min": 2, + "max": 5502 + }, + "hp (set)": { + "min": 60, + "max": 756 + }, + "luck": { + "min": 2, + "max": 1079 + }, + "luck (set)": { + "min": 40, + "max": 294 + }, + "magic_bean_purchase_bonus": { + "min": 2, + "max": 128 + }, + "None": { + "min": 0, + "max": 0 + }, + "score": { + "min": 28, + "max": 100 + } + }, + "stats": { + "seven_day_volume": 3.13785408582563, + "seven_day_change": -0.6247368483022884, + "total_volume": 565.839345302629, + "count": 40800, + "num_owners": 5830, + "market_cap": 1681.523681150229, + "average_price": 0.0315050942632965, + "items_sold": 17957 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-10-24T11:06:58.609791", + "default_to_fiat": false, + "description": "Knight Story is an innovative mobile RPG powered by blockchain. The game is the second title of Biscuit; developed EOS Knights, the legendary blockchain game.", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "discord_url": null, + "display_data": { + "card_display_style": "padded", + "images": [ + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/1-1571915237.svg", + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/2-1571982585.svg", + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/6-1571984918.svg", + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/5-1571984898.svg", + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/4-1571984887.svg", + "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/3-1571984879.svg" + ] + }, + "external_url": "https://knightstory.io", + "featured": false, + "featured_image_url": null, + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/Hwr0JNz9lHdTeu3mZTawVun-BdKRf-zSpi5ZUDxirBbPs_-hW92qHfh25QcTzeGCPy0FRULooZyTJ6MlRh8qaq4=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/Hwr0JNz9lHdTeu3mZTawVun-BdKRf-zSpi5ZUDxirBbPs_-hW92qHfh25QcTzeGCPy0FRULooZyTJ6MlRh8qaq4", + "medium_username": null, + "name": "KnightStory", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": "0x9702a479115788294232c384a5c1f42c881789fe", + "require_email": false, + "short_description": null, + "slug": "knightstory", + "telegram_url": null, + "twitter_username": null, + "wiki_url": null, + "owned_asset_count": 1 + }, + { + "primary_asset_contracts": [ + { + "address": "0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe", + "asset_contract_type": "non-fungible", + "created_date": "2019-12-10T08:55:01.176657", + "name": ".crypto", + "nft_version": "3.0", + "opensea_version": null, + "owner": null, + "schema_name": "ERC721", + "symbol": "", + "total_supply": null, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "external_link": "https://unstoppabledomains.com/", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + } + ], + "traits": { + "length": { + "min": 2, + "max": 34 + }, + "level": { + "min": 1, + "max": 3 + } + }, + "stats": { + "seven_day_volume": 3.97, + "seven_day_change": -0.17774740068762512, + "total_volume": 53.6400785864631, + "count": 57702, + "num_owners": 4456, + "market_cap": 13647.67704, + "average_price": 0.102562291752319, + "items_sold": 523 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-12-10T08:55:01.591598", + "default_to_fiat": false, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "discord_url": null, + "display_data": { + "card_display_style": "padded", + "images": [ + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" + ] + }, + "external_url": "https://unstoppabledomains.com/", + "featured": false, + "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", + "medium_username": null, + "name": "Unstoppable Domains", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "unstoppable-domains", + "telegram_url": null, + "twitter_username": null, + "wiki_url": null, + "owned_asset_count": 2 + }, + { + "primary_asset_contracts": [ + { + "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + "asset_contract_type": "semi-fungible", + "created_date": "2019-08-02T23:43:14.666153", + "name": "Enjin", + "nft_version": null, + "opensea_version": null, + "owner": null, + "schema_name": "ERC1155", + "symbol": "", + "total_supply": null, + "description": "Enjin assets are unique digital ERC1155 assets used in a variety of games in the Enjin multiverse.", + "external_link": "https://enjinx.io/", + "image_url": "https://lh3.googleusercontent.com/pz9RPxNoHxFTJNNySYV5bXjsWlajAiDiI1A5m5OvUaS1fd8N64yViclbRQqM8HViBTIUPrYgQ-w49h36NHL0D1Y=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + } + ], + "traits": {}, + "stats": { + "seven_day_volume": 1.8128, + "seven_day_change": 410.99999999999994, + "total_volume": 286.747475213277, + "count": 34146, + "num_owners": 29436, + "market_cap": 3499.0797333333308, + "average_price": 0.216576116108433, + "items_sold": 1316 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-12-15T03:51:34.864843", + "default_to_fiat": false, + "description": "The season of giving is upon us, and we come bearing gifts! Join us in the spirit of giving to receive one of our first-ever Binance Collectibles! “HO HO HODL: Binance Collectibles Series 1.”", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "discord_url": null, + "display_data": { + "card_display_style": "contain", + "images": [ + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727762-1576342335.jpg", + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420726407-1576341423.jpg", + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727252-1576342120.jpg", + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727146-1576342000.jpg", + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727063-1576341986.jpg", + "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727778-1576342346.jpg" + ] + }, + "external_url": "https://www.binance.com/en/blog/411120468693135360/Earn-a-Guaranteed-Binance-NFT--HO-HO-HODL-Binance-Collectibles-Series-1", + "featured": false, + "featured_image_url": null, + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/vbRXgbAGZVvBQw5q-qmV0tF3HHKCJeomBz5oHFTehsv2q6xuY7UyndXSWgCWqj2GGJM77DLFP-vLNVnaKYnVoD8=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/vbRXgbAGZVvBQw5q-qmV0tF3HHKCJeomBz5oHFTehsv2q6xuY7UyndXSWgCWqj2GGJM77DLFP-vLNVnaKYnVoD8", + "medium_username": null, + "name": "Binance", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "binance", + "telegram_url": null, + "twitter_username": null, + "wiki_url": null, + "owned_asset_count": 4 + }, + { + "primary_asset_contracts": [ + { + "address": "0x3eea5bf894236f4b7a6f1451bca89a9c91f49719", + "asset_contract_type": "non-fungible", + "created_date": "2019-12-24T15:08:28.581742", + "name": "Trust Collectible", + "nft_version": "3.0", + "opensea_version": null, + "owner": 1982280, + "schema_name": "ERC721", + "symbol": "", + "total_supply": "25", + "description": "Your friendly talkative crypto app.", + "external_link": "https://trustwallet.com", + "image_url": "https://storage.opensea.io/trust-collectible-1577200601.png", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + } + ], + "traits": { + "generation": { + "min": 1, + "max": 1 + }, + "level": { + "min": 2, + "max": 2 + } + }, + "stats": { + "seven_day_volume": 0, + "seven_day_change": 0, + "total_volume": 1.12728594516888, + "count": 50, + "num_owners": 22, + "market_cap": 0, + "average_price": 0.0230049142148904, + "items_sold": 47 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-12-24T15:08:28.833176", + "default_to_fiat": false, + "description": "Your friendly talkative crypto app.", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "discord_url": null, + "display_data": { + "card_display_style": "cover", + "images": [ + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/1-1577200113.png", + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/25-1577200136.png", + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/24-1577200136.png", + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/21-1577200135.png", + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/23-1577200135.png", + "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/22-1577200133.png" + ] + }, + "external_url": "https://trustwallet.com", + "featured": false, + "featured_image_url": null, + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://storage.opensea.io/trust-collectible-1577200601.png", + "is_subject_to_whitelist": false, + "large_image_url": "https://storage.opensea.io/trust-collectible-large-1577200602.png", + "medium_username": null, + "name": "Trust Collectibles", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "trust-collectible", + "telegram_url": null, + "twitter_username": null, + "wiki_url": null, + "owned_asset_count": 1 + }, + { + "primary_asset_contracts": [], + "traits": { + "length": { + "min": 7, + "max": 18 + }, + "level": { + "min": 2, + "max": 2 + } + }, + "stats": { + "seven_day_volume": 0.5486, + "seven_day_change": -0.7875680705545889, + "total_volume": 5.74316958623246, + "count": 14148, + "num_owners": 8485, + "market_cap": 193.4627697762295, + "average_price": 0.0136742133005535, + "items_sold": 420 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2020-04-13T20:06:38.168795", + "default_to_fiat": false, + "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "discord_url": null, + "display_data": { + "card_display_style": "padded", + "images": [ + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", + "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" + ] + }, + "external_url": "https://unstoppabledomains.com/", + "featured": false, + "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", + "hidden": false, + "safelist_request_status": "approved", + "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", + "medium_username": null, + "name": "Unstoppable Domains Animals", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "unstoppable-domains-animals", + "telegram_url": null, + "twitter_username": null, + "wiki_url": null, + "owned_asset_count": 1 + } +] \ No newline at end of file diff --git a/mock/ext-api-data/poa-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json b/mock/ext-api-data/poa-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json new file mode 100644 index 000000000..f696f03f9 --- /dev/null +++ b/mock/ext-api-data/poa-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json @@ -0,0 +1 @@ +{"total":1,"docs":[{"address":"0xADFE00d92e5A16e773891F59780e6e54f40B532e","name":"Viktor Coin","decimals":0,"symbol":"VIK"}]} \ No newline at end of file diff --git a/mock/ext-api-data/poa-api_transactions__address_0x55798eCbF17ce1241d543c22dCE46134c13b4bc0.json b/mock/ext-api-data/poa-api_transactions__address_0x55798eCbF17ce1241d543c22dCE46134c13b4bc0.json new file mode 100644 index 000000000..d84956613 --- /dev/null +++ b/mock/ext-api-data/poa-api_transactions__address_0x55798eCbF17ce1241d543c22dCE46134c13b4bc0.json @@ -0,0 +1 @@ +{"docs":[{"operations":[{"transactionId":"0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d-0","contract":{"address":"0xab2f2dd3120de530d38936ee09a74a6d17e3da44","decimals":18,"name":"GeonCoin","symbol":"GC","totalSupply":"100000000000000000000000000","updatedAt":"2020-02-26T23:41:29.763Z"},"from":"0x55798eCbF17ce1241d543c22dCE46134c13b4bc0","to":"0xE87E46032847e097F5bB51404d19A0449c704EE8","type":"token_transfer","value":"1000000000000000000","id":null}],"contract":null,"_id":"0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d","blockNumber":14115901,"time":1584448420,"nonce":1,"from":"0x55798eCbF17ce1241d543c22dCE46134c13b4bc0","to":"0xAb2f2Dd3120dE530d38936EE09A74a6d17e3Da44","value":"0","gas":"120000","gasPrice":"1000000000","gasUsed":"78484","input":"0xb88a3f725e70c38d1d03b5568e2f4d1600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000","error":"","id":"0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d","timeStamp":"1584448420"},{"operations":[],"contract":null,"_id":"0xcde1f2c3a262012f624065f167616db3160e763f4938ccfa0fcc742d5725eae2","blockNumber":14115900,"time":1584448415,"nonce":109291,"from":"0x628cF7150f8242b20B2ADB064D27183D2a026130","to":"0x55798eCbF17ce1241d543c22dCE46134c13b4bc0","value":"600000000000000","gas":"120000","gasPrice":"1000000000","gasUsed":"21000","input":"0x","error":"","id":"0xcde1f2c3a262012f624065f167616db3160e763f4938ccfa0fcc742d5725eae2","timeStamp":"1584448415"},{"operations":[],"contract":null,"_id":"0x90ef177d3448d379560218f99657027661a7238fb62c793dc2a7091a0d0d88e8","blockNumber":14115899,"time":1584448410,"nonce":0,"from":"0x55798eCbF17ce1241d543c22dCE46134c13b4bc0","to":"0xE87E46032847e097F5bB51404d19A0449c704EE8","value":"0","gas":"120000","gasPrice":"1000000000","gasUsed":"100890","input":"0x1e76c9445e70c38d1d03b5568e2f4d160000000000000000000000000000000000000000","error":"","id":"0x90ef177d3448d379560218f99657027661a7238fb62c793dc2a7091a0d0d88e8","timeStamp":"1584448410"},{"operations":[],"contract":null,"_id":"0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3","blockNumber":14115898,"time":1584448405,"nonce":109290,"from":"0x628cF7150f8242b20B2ADB064D27183D2a026130","to":"0x55798eCbF17ce1241d543c22dCE46134c13b4bc0","value":"600000000000000","gas":"120000","gasPrice":"1000000000","gasUsed":"21000","input":"0x","error":"","id":"0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3","timeStamp":"1584448405"},{"operations":[{"transactionId":"0x19ccc1fbaaf57ea72a5269d1b06630bffeb9ec0a8f0c64c6919f773c4d920312-0","contract":{"address":"0xab2f2dd3120de530d38936ee09a74a6d17e3da44","decimals":18,"name":"GeonCoin","symbol":"GC","totalSupply":"100000000000000000000000000","updatedAt":"2020-02-26T23:41:29.763Z"},"from":"0x4808A49bFB7527C142eb2C5b5718CeF432223ae7","to":"0x55798eCbF17ce1241d543c22dCE46134c13b4bc0","type":"token_transfer","value":"1000000000000000000","id":null}],"contract":null,"_id":"0x19ccc1fbaaf57ea72a5269d1b06630bffeb9ec0a8f0c64c6919f773c4d920312","blockNumber":14115844,"time":1584448120,"nonce":129540,"from":"0x4808A49bFB7527C142eb2C5b5718CeF432223ae7","to":"0xAb2f2Dd3120dE530d38936EE09A74a6d17e3Da44","value":"0","gas":"120000","gasPrice":"1000000000","gasUsed":"37088","input":"0xa9059cbb00000000000000000000000055798ecbf17ce1241d543c22dce46134c13b4bc00000000000000000000000000000000000000000000000000de0b6b3a7640000","error":"","id":"0x19ccc1fbaaf57ea72a5269d1b06630bffeb9ec0a8f0c64c6919f773c4d920312","timeStamp":"1584448120"},{"operations":[{"transactionId":"0xf538a2a6a604a7183f131795e81a913522fb94de578aecb87feb0ffb75729afa-0","contract":{"address":"0xab2f2dd3120de530d38936ee09a74a6d17e3da44","decimals":18,"name":"GeonCoin","symbol":"GC","totalSupply":"100000000000000000000000000","updatedAt":"2020-02-26T23:41:29.763Z"},"from":"0xcB8EDB02bb1f3b96f895D878DF2946a9809c0a8a","to":"0x55798eCbF17ce1241d543c22dCE46134c13b4bc0","type":"token_transfer","value":"1000000000000000000","id":null}],"contract":null,"_id":"0xf538a2a6a604a7183f131795e81a913522fb94de578aecb87feb0ffb75729afa","blockNumber":14103004,"time":1584379885,"nonce":130365,"from":"0xcB8EDB02bb1f3b96f895D878DF2946a9809c0a8a","to":"0xAb2f2Dd3120dE530d38936EE09A74a6d17e3Da44","value":"0","gas":"120000","gasPrice":"1000000000","gasUsed":"52088","input":"0xa9059cbb00000000000000000000000055798ecbf17ce1241d543c22dce46134c13b4bc00000000000000000000000000000000000000000000000000de0b6b3a7640000","error":"","id":"0xf538a2a6a604a7183f131795e81a913522fb94de578aecb87feb0ffb75729afa","timeStamp":"1584379885"},{"operations":[{"transactionId":"0x1150040f9f94353a144bfdefcd5691627b87bf4c70470ea9fe4c440edfd6a6eb-0","contract":{"address":"0xab2f2dd3120de530d38936ee09a74a6d17e3da44","decimals":18,"name":"GeonCoin","symbol":"GC","totalSupply":"100000000000000000000000000","updatedAt":"2020-02-26T23:41:29.763Z"},"from":"0xEfc020194845183A387475c4663CB314a22C4758","to":"0x55798eCbF17ce1241d543c22dCE46134c13b4bc0","type":"token_transfer","value":"1000000000000000000","id":null}],"contract":null,"_id":"0x1150040f9f94353a144bfdefcd5691627b87bf4c70470ea9fe4c440edfd6a6eb","blockNumber":14103004,"time":1584379885,"nonce":130048,"from":"0xEfc020194845183A387475c4663CB314a22C4758","to":"0xAb2f2Dd3120dE530d38936EE09A74a6d17e3Da44","value":"0","gas":"120000","gasPrice":"1000000000","gasUsed":"37088","input":"0xa9059cbb00000000000000000000000055798ecbf17ce1241d543c22dce46134c13b4bc00000000000000000000000000000000000000000000000000de0b6b3a7640000","error":"","id":"0x1150040f9f94353a144bfdefcd5691627b87bf4c70470ea9fe4c440edfd6a6eb","timeStamp":"1584379885"}],"total":7} \ No newline at end of file diff --git a/mock/ext-api-data/qtum-api_v2_address_QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ__details_txs.json b/mock/ext-api-data/qtum-api_v2_address_QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ__details_txs.json new file mode 100644 index 000000000..625ec5eca --- /dev/null +++ b/mock/ext-api-data/qtum-api_v2_address_QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ__details_txs.json @@ -0,0 +1,330 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", + "balance": "234243932", + "totalReceived": "43569601542", + "totalSent": "43335357610", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 6, + "transactions": [ + { + "txid": "fba987ecdac9307827d48776eb808050347b31bbc2ed2dbbc1d957d0c5c5213b", + "version": 1, + "vin": [ + { + "txid": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true, + "value": "235357610", + "hex": "48304502210099cd42a938de9b5ab1b5f7770cc99a9b5ab935e63911a13276510e9b1983c107022034f6d45e5ae6ce13b839427b91f2d0d98c7894610d5fe5d7aaa7e1ce2911627e01210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "76a914816e451a8afb6753d6617633cc8d9785fd33599c88ac", + "addresses": [ + "QYQMNjZ7iaJXRJnVAE11MzCFCwre7Fw9qZ" + ], + "isAddress": true + }, + { + "value": "234243932", + "n": 1, + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true + } + ], + "blockHash": "bd1c23ed73b801db65cda1e4c576812da2687e6cd71a33d3f03440b15c8d28b3", + "blockHeight": 602733, + "confirmations": 4804, + "blockTime": 1588752224, + "value": "235243932", + "valueIn": "235357610", + "fees": "113678", + "hex": "0100000001670f23606630d6f535a186ea5689f931709e190ea89cb8083a6c8558b68b4362000000006b48304502210099cd42a938de9b5ab1b5f7770cc99a9b5ab935e63911a13276510e9b1983c107022034f6d45e5ae6ce13b839427b91f2d0d98c7894610d5fe5d7aaa7e1ce2911627e01210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764feffffff0240420f00000000001976a914816e451a8afb6753d6617633cc8d9785fd33599c88ac5c47f60d000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac00000000" + }, + { + "txid": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67", + "version": 1, + "vin": [ + { + "txid": "782e18a7b1bf612972e773fd6ccdcbe0c4514c661c31a7942f5dcd4807c5ab68", + "sequence": 4294967293, + "n": 0, + "addresses": [ + "QWLQSMPF5WKAqhXxePJvjUJNjxDHrPCbjB" + ], + "isAddress": true, + "value": "100000", + "hex": "483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1e" + }, + { + "txid": "80b7c6bcba625ad4abb69f7e92521a782681e984982408d40ad35a24b3f78297", + "sequence": 4294967294, + "n": 1, + "addresses": [ + "QgqVXuCCN1m4Hfb9HCkrzbgUSkoodKsrVY" + ], + "isAddress": true, + "value": "100000", + "hex": "48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5b" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "sequence": 4294967292, + "n": 2, + "addresses": [ + "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" + ], + "isAddress": true, + "value": "10000000", + "hex": "473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbc" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "vout": 1, + "sequence": 4294967291, + "n": 3, + "addresses": [ + "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" + ], + "isAddress": true, + "value": "225494620", + "hex": "483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3" + } + ], + "vout": [ + { + "value": "235357610", + "n": 0, + "spent": true, + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true + } + ], + "blockHash": "6e71fa96ca29a6e4cbd10defaa4fc69ff09adec45fc666d82afade3f75206cc1", + "blockHeight": 563426, + "confirmations": 44111, + "blockTime": 1583720608, + "value": "235357610", + "valueIn": "235694620", + "fees": "337010", + "hex": "010000000468abc50748cd5d2f94a7311c664c51c4e0cbcd6cfd73e7722961bfb1a7182e78000000006b483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1efdffffff9782f7b3245ad30ad408249884e98126781a52927e9fb6abd45a62babcc6b780000000006b48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5bfeffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c000000006a473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbcfcffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c010000006b483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3fbffffff01aa45070e000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac00000000" + }, + { + "txid": "ef335bef783551cb054acd220555f1588cc4b03c0f47cc0839220c81d3ceb88d", + "version": 1, + "vin": [ + { + "txid": "506d07570d75914d5bd319d591374fb9cd1633f5c8b3cc800387e104298e8a62", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QfLtauKWxzF6pDf2ceXJe5oqizNHVMBneH" + ], + "isAddress": true, + "value": "198984808", + "hex": "4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081e" + }, + { + "txid": "e22c3e2ea4d285b71a73c41cdbb51f7c75d80b6f473e7f4aade6df5bf8771942", + "sequence": 4294967292, + "n": 1, + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true, + "value": "43000000000", + "hex": "483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764" + } + ], + "vout": [ + { + "value": "43000000000", + "n": 0, + "spent": true, + "hex": "76a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac", + "addresses": [ + "QURZqPoBfuXXoHDkCHCvhGJa1DP2Ahj1KX" + ], + "isAddress": true + }, + { + "value": "198831468", + "n": 1, + "spent": true, + "hex": "76a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac", + "addresses": [ + "QdfcTR3TQHjGHcKLiHmiPLRfVPFRWazJPg" + ], + "isAddress": true + } + ], + "blockHash": "918141389623f4f880b1ba279bb70ee91de6a005e1a9d523d21a66e8c55f0502", + "blockHeight": 393505, + "confirmations": 214032, + "blockTime": 1560879520, + "value": "43198831468", + "valueIn": "43198984808", + "fees": "153340", + "hex": "0100000002628a8e2904e1870380ccb3c8f53316cdb94f3791d519d35b4d91750d57076d50010000006b4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081efeffffff421977f85bdfe6ad4a7f3e476f0bd8757c1fb5db1cc4731ab785d2a42e3e2ce2000000006b483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764fcffffff0200eeff020a0000001976a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac6cedd90b000000001976a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac00000000" + }, + { + "txid": "e22c3e2ea4d285b71a73c41cdbb51f7c75d80b6f473e7f4aade6df5bf8771942", + "version": 1, + "vin": [ + { + "txid": "ee3b548dbe40fc15cb48fe297b2fa17f1bfffb5a91836bc25674f23b18156ab4", + "vout": 1, + "n": 0, + "addresses": [ + "QZsgcV5SxtrCxjyP5mXAmVosMKrxbEWFfL" + ], + "isAddress": true, + "value": "55000000000", + "hex": "473044022045cd6c3831cb6c0f33b2e3d05940b8205c6293c96f81cfbccc0c29c631dd2a2e0220263bd13fff18d75d45b15f1102118b28001bde09de38f4c5f9c5c5b6f27781c2012102817713bf5592a19279ed887fe88b04173c3844ecc6adf3f75213734b8cecbda4" + } + ], + "vout": [ + { + "value": "43000000000", + "n": 0, + "spent": true, + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true + }, + { + "value": "11999907792", + "n": 1, + "spent": true, + "hex": "76a914ccdab9a8e80f5c1b7f8eabbc9a8f5a00754d000a88ac", + "addresses": [ + "QfH9yjB4tEGd8jK1YY4JvXtT5TdaCGX7Rt" + ], + "isAddress": true + } + ], + "blockHash": "ce003cd41af05d06ef406e4798d3d8fc3113ae028336a92e22ea93ab5a73ea4a", + "blockHeight": 390495, + "confirmations": 217042, + "blockTime": 1560449520, + "value": "54999907792", + "valueIn": "55000000000", + "fees": "92208", + "hex": "0100000001b46a15183bf27456c26b83915afbff1b7fa12f7b29fe48cb15fc40be8d543bee010000006a473044022045cd6c3831cb6c0f33b2e3d05940b8205c6293c96f81cfbccc0c29c631dd2a2e0220263bd13fff18d75d45b15f1102118b28001bde09de38f4c5f9c5c5b6f27781c2012102817713bf5592a19279ed887fe88b04173c3844ecc6adf3f75213734b8cecbda4000000000200eeff020a0000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888acd00f40cb020000001976a914ccdab9a8e80f5c1b7f8eabbc9a8f5a00754d000a88ac00000000" + }, + { + "txid": "1c5aea829cb18e507d3a1eccb99db5744a9ff086ed87cc97d696231954ce7635", + "version": 1, + "vin": [ + { + "txid": "f09b2b7577dbf154f2c027ad8f1bb51e4c9917e809856be513e7b8067f6d888e", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true, + "value": "100000000", + "hex": "4730440220009bc2bb9bd0782aa38bfb3e9093d49fdfb31e4067a956adad2f888e9438e06b02206d7c5d60afffdb3685fced33d24ba9a6466a35b3aa933e4b1ffdd6ba8d23d57901210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "76a9146285651ee6abb6788c39df4ecb89f97345cbfa2588ac", + "addresses": [ + "QVav8YbUUwQq6yFCrkafW79Uv3NUMHT66n" + ], + "isAddress": true + }, + { + "value": "89780102", + "n": 1, + "spent": true, + "hex": "76a914ca1b74b3ae2a8e655487e131dbb820717c20610e88ac", + "addresses": [ + "Qf2dViTrEcWm7CawDDoDduzBrgRL3DnFWH" + ], + "isAddress": true + } + ], + "blockHash": "d61a1de7b586fee13bc44cd3ae0fa0392d6d9d75d7d3c7273481dfa2069eb9ab", + "blockHeight": 369474, + "confirmations": 238063, + "blockTime": 1557440448, + "value": "99780102", + "valueIn": "100000000", + "fees": "219898", + "hex": "01000000018e886d7f06b8e713e56b8509e817994c1eb51b8fad27c0f254f1db77752b9bf0000000006a4730440220009bc2bb9bd0782aa38bfb3e9093d49fdfb31e4067a956adad2f888e9438e06b02206d7c5d60afffdb3685fced33d24ba9a6466a35b3aa933e4b1ffdd6ba8d23d57901210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764feffffff0280969800000000001976a9146285651ee6abb6788c39df4ecb89f97345cbfa2588ac86ef5905000000001976a914ca1b74b3ae2a8e655487e131dbb820717c20610e88ac00000000" + }, + { + "txid": "f09b2b7577dbf154f2c027ad8f1bb51e4c9917e809856be513e7b8067f6d888e", + "version": 1, + "vin": [ + { + "txid": "3600156226ed9f04379dcf72795542d9b4de9d88b374b82b825497ff92e52830", + "vout": 1, + "n": 0, + "addresses": [ + "QUN6caK4ZEPLEoA3ZMC2oSR2kf6RCfGA9B" + ], + "isAddress": true, + "value": "109000000", + "hex": "483045022100cf97578c211296f9e3aa8e7718c7ec4a6fc240b46c29216f664fd68fdd81ec5202201a27971ba5e52b758a8295c870f037a67f20aab306a264e6249dd4f61705634401210360e37f3d88db15a76ffdb30179fc3a67e0fa320e8c6a82bbd93a8e40af30d963" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true + }, + { + "value": "8789820", + "n": 1, + "spent": true, + "hex": "76a91406ee9fbb22cc53a5190b0eddf26ed33d66a6ebfa88ac", + "addresses": [ + "QMEe2LEsZRLjf4UNuxkgMBHwkMB2zJuWjo" + ], + "isAddress": true + } + ], + "blockHash": "c23063e7715537c96898e8fe956bc45c98e0fb17c415ebdbbbb78f3ba8106494", + "blockHeight": 367729, + "confirmations": 239808, + "blockTime": 1557190080, + "value": "108789820", + "valueIn": "109000000", + "fees": "210180", + "hex": "01000000013028e592ff9754822bb874b3889ddeb4d942557972cf9d37049fed2662150036010000006b483045022100cf97578c211296f9e3aa8e7718c7ec4a6fc240b46c29216f664fd68fdd81ec5202201a27971ba5e52b758a8295c870f037a67f20aab306a264e6249dd4f61705634401210360e37f3d88db15a76ffdb30179fc3a67e0fa320e8c6a82bbd93a8e40af30d963000000000200e1f505000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac3c1f8600000000001976a91406ee9fbb22cc53a5190b0eddf26ed33d66a6ebfa88ac00000000" + } + ] +} diff --git a/mock/ext-api-data/qtum-api_v2_xpub_xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd__details_txs.json b/mock/ext-api-data/qtum-api_v2_xpub_xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd__details_txs.json new file mode 100644 index 000000000..e4d220739 --- /dev/null +++ b/mock/ext-api-data/qtum-api_v2_xpub_xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd__details_txs.json @@ -0,0 +1,1842 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd", + "balance": "234243932", + "totalReceived": "79147977228", + "totalSent": "78913733296", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 38, + "transactions": [ + { + "txid": "fba987ecdac9307827d48776eb808050347b31bbc2ed2dbbc1d957d0c5c5213b", + "version": 1, + "vin": [ + { + "txid": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true, + "value": "235357610", + "hex": "48304502210099cd42a938de9b5ab1b5f7770cc99a9b5ab935e63911a13276510e9b1983c107022034f6d45e5ae6ce13b839427b91f2d0d98c7894610d5fe5d7aaa7e1ce2911627e01210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "76a914816e451a8afb6753d6617633cc8d9785fd33599c88ac", + "addresses": [ + "QYQMNjZ7iaJXRJnVAE11MzCFCwre7Fw9qZ" + ], + "isAddress": true + }, + { + "value": "234243932", + "n": 1, + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true + } + ], + "blockHash": "bd1c23ed73b801db65cda1e4c576812da2687e6cd71a33d3f03440b15c8d28b3", + "blockHeight": 602733, + "confirmations": 4804, + "blockTime": 1588752224, + "value": "235243932", + "valueIn": "235357610", + "fees": "113678", + "hex": "0100000001670f23606630d6f535a186ea5689f931709e190ea89cb8083a6c8558b68b4362000000006b48304502210099cd42a938de9b5ab1b5f7770cc99a9b5ab935e63911a13276510e9b1983c107022034f6d45e5ae6ce13b839427b91f2d0d98c7894610d5fe5d7aaa7e1ce2911627e01210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764feffffff0240420f00000000001976a914816e451a8afb6753d6617633cc8d9785fd33599c88ac5c47f60d000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac00000000" + }, + { + "txid": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67", + "version": 1, + "vin": [ + { + "txid": "782e18a7b1bf612972e773fd6ccdcbe0c4514c661c31a7942f5dcd4807c5ab68", + "sequence": 4294967293, + "n": 0, + "addresses": [ + "QWLQSMPF5WKAqhXxePJvjUJNjxDHrPCbjB" + ], + "isAddress": true, + "value": "100000", + "hex": "483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1e" + }, + { + "txid": "80b7c6bcba625ad4abb69f7e92521a782681e984982408d40ad35a24b3f78297", + "sequence": 4294967294, + "n": 1, + "addresses": [ + "QgqVXuCCN1m4Hfb9HCkrzbgUSkoodKsrVY" + ], + "isAddress": true, + "value": "100000", + "hex": "48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5b" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "sequence": 4294967292, + "n": 2, + "addresses": [ + "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" + ], + "isAddress": true, + "value": "10000000", + "hex": "473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbc" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "vout": 1, + "sequence": 4294967291, + "n": 3, + "addresses": [ + "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" + ], + "isAddress": true, + "value": "225494620", + "hex": "483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3" + } + ], + "vout": [ + { + "value": "235357610", + "n": 0, + "spent": true, + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true + } + ], + "blockHash": "6e71fa96ca29a6e4cbd10defaa4fc69ff09adec45fc666d82afade3f75206cc1", + "blockHeight": 563426, + "confirmations": 44111, + "blockTime": 1583720608, + "value": "235357610", + "valueIn": "235694620", + "fees": "337010", + "hex": "010000000468abc50748cd5d2f94a7311c664c51c4e0cbcd6cfd73e7722961bfb1a7182e78000000006b483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1efdffffff9782f7b3245ad30ad408249884e98126781a52927e9fb6abd45a62babcc6b780000000006b48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5bfeffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c000000006a473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbcfcffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c010000006b483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3fbffffff01aa45070e000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac00000000" + }, + { + "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", + "version": 1, + "vin": [ + { + "txid": "1d597a91e1810fdbfcb712c11c4776f5384ab4e7bd94a2fdc6538b9afdc1e6d0", + "vout": 1, + "sequence": 4294967292, + "n": 0, + "addresses": [ + "QZsdyvpJnczcDPJoySkNTaSh8VP8XAXeMz" + ], + "isAddress": true, + "value": "235607620", + "hex": "4730440220679ad69958629be2516a0d93457ba24f154fd42e23a4f3f2896272fe97940eed0220395098fa364232f74440e50043d6b2868829cb11faf56057d12f68f4bac82bdc0121036ea9140776d2e6a3ec7dd32b9795b47cf592e90e4159f7db793019b069e78b46" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "76a9143dc1aae7701ab1f7be54fc69808c092ddb5a574088ac", + "addresses": [ + "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" + ], + "isAddress": true + }, + { + "value": "225494620", + "n": 1, + "spent": true, + "hex": "76a914d40a0b271f69b1d2f43f60c540325c9039b4a05588ac", + "addresses": [ + "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" + ], + "isAddress": true + } + ], + "blockHash": "a7a05f41f5f07faa5d3ca2cf5fb7de6a0cf46bc4ee465028ceda72ea5e6b5669", + "blockHeight": 479076, + "confirmations": 128461, + "blockTime": 1572922480, + "value": "235494620", + "valueIn": "235607620", + "fees": "113000", + "hex": "0100000001d0e6c1fd9a8b53c6fda294bde7b44a38f576471cc112b7fcdb0f81e1917a591d010000006a4730440220679ad69958629be2516a0d93457ba24f154fd42e23a4f3f2896272fe97940eed0220395098fa364232f74440e50043d6b2868829cb11faf56057d12f68f4bac82bdc0121036ea9140776d2e6a3ec7dd32b9795b47cf592e90e4159f7db793019b069e78b46fcffffff0280969800000000001976a9143dc1aae7701ab1f7be54fc69808c092ddb5a574088ac5cc6700d000000001976a914d40a0b271f69b1d2f43f60c540325c9039b4a05588ac00000000" + }, + { + "txid": "1d597a91e1810fdbfcb712c11c4776f5384ab4e7bd94a2fdc6538b9afdc1e6d0", + "version": 1, + "vin": [ + { + "txid": "782e18a7b1bf612972e773fd6ccdcbe0c4514c661c31a7942f5dcd4807c5ab68", + "vout": 1, + "n": 0, + "addresses": [ + "QT9VzxtbfiRSHzvGGqVk7XV4KAaSrb6L64" + ], + "isAddress": true, + "value": "245721298", + "hex": "483045022100d72a93beb503651f314d8cc384241142edde4083552c5e4701206fbb511e667602204994bef93808f562025a5f9b1e8f4e6d13a3a3a2f40b242f0e039163ae273d450121026067645fac1c14839ceb89d0c234cf1cb2a6b5a457c2f7784d25497942ec0e24" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "hex": "76a9143e4772f3e2ab9bbda5a0074f060a61161660443888ac", + "addresses": [ + "QSHHbZLJjaBaoUfDga44xX9miUJA29ccAa" + ], + "isAddress": true + }, + { + "value": "235607620", + "n": 1, + "spent": true, + "hex": "76a914918f7d459ed814895ebf60819ae860c514483c7a88ac", + "addresses": [ + "QZsdyvpJnczcDPJoySkNTaSh8VP8XAXeMz" + ], + "isAddress": true + } + ], + "blockHash": "2538360f74c1f5b8ee89ce05c8c09395bb41528853bdf75c532456045452b525", + "blockHeight": 452291, + "confirmations": 155246, + "blockTime": 1569265040, + "value": "245607620", + "valueIn": "245721298", + "fees": "113678", + "hex": "010000000168abc50748cd5d2f94a7311c664c51c4e0cbcd6cfd73e7722961bfb1a7182e78010000006b483045022100d72a93beb503651f314d8cc384241142edde4083552c5e4701206fbb511e667602204994bef93808f562025a5f9b1e8f4e6d13a3a3a2f40b242f0e039163ae273d450121026067645fac1c14839ceb89d0c234cf1cb2a6b5a457c2f7784d25497942ec0e24000000000280969800000000001976a9143e4772f3e2ab9bbda5a0074f060a61161660443888ac44160b0e000000001976a914918f7d459ed814895ebf60819ae860c514483c7a88ac00000000" + }, + { + "txid": "782e18a7b1bf612972e773fd6ccdcbe0c4514c661c31a7942f5dcd4807c5ab68", + "version": 1, + "vin": [ + { + "txid": "80b7c6bcba625ad4abb69f7e92521a782681e984982408d40ad35a24b3f78297", + "vout": 1, + "n": 0, + "addresses": [ + "QZw82ithbXQn6suPSFQJLxRVkCB5K7Lgct" + ], + "isAddress": true, + "value": "246047298", + "hex": "483045022100bebae6823f790dabee59584c40b4ff6f972f4644bf4e5b0568ba37aa1e16d5b602200ef27e41cb3713cebf39c99eab63e6db929ab1661b7a355762586521e7337cc101210226bfcb7cc0017a6467f7a6fb15e5eb6534afd071d2e2f9ab8f7c0165dc716799" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a9146abee92e5a38197d7b84a3bdf0c0ee38fa2b025a88ac", + "addresses": [ + "QWLQSMPF5WKAqhXxePJvjUJNjxDHrPCbjB" + ], + "isAddress": true + }, + { + "value": "245721298", + "n": 1, + "spent": true, + "hex": "76a91447c699e0f98138c82043ec652151d2f96620990f88ac", + "addresses": [ + "QT9VzxtbfiRSHzvGGqVk7XV4KAaSrb6L64" + ], + "isAddress": true + } + ], + "blockHash": "578aaf4f10edb65830fcc6d040750a7b8ea936f9138432a9bac983b4fe38a2d4", + "blockHeight": 441535, + "confirmations": 166002, + "blockTime": 1567735504, + "value": "245821298", + "valueIn": "246047298", + "fees": "226000", + "hex": "01000000019782f7b3245ad30ad408249884e98126781a52927e9fb6abd45a62babcc6b780010000006b483045022100bebae6823f790dabee59584c40b4ff6f972f4644bf4e5b0568ba37aa1e16d5b602200ef27e41cb3713cebf39c99eab63e6db929ab1661b7a355762586521e7337cc101210226bfcb7cc0017a6467f7a6fb15e5eb6534afd071d2e2f9ab8f7c0165dc7167990000000002a0860100000000001976a9146abee92e5a38197d7b84a3bdf0c0ee38fa2b025a88acd268a50e000000001976a91447c699e0f98138c82043ec652151d2f96620990f88ac00000000" + }, + { + "txid": "80b7c6bcba625ad4abb69f7e92521a782681e984982408d40ad35a24b3f78297", + "version": 1, + "vin": [ + { + "txid": "ce4e5b96472dd80cbc89dc9d9e9be23c0375605b9c8c1256ea0541c09fc79c68", + "n": 0, + "addresses": [ + "QUPmkCzWkLtMfWvjKEStpgqMADQjbDhxbn" + ], + "isAddress": true, + "value": "246373298", + "hex": "4730440220506172cf296bc5b7de8da3f840b579bd7b08ba664241b096cf6b4a6206d5fa3002205bc16a044e653605ed225a10c32ebf2fee95f04c216e77cbcfae8be8c36184bc01210255dedfd7fa97011c00833682c70f09ab0b750a5e204c73bcb7233c6bf592fe93" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a914ddf07c38931968ef5540ab424c1911297199a02088ac", + "addresses": [ + "QgqVXuCCN1m4Hfb9HCkrzbgUSkoodKsrVY" + ], + "isAddress": true + }, + { + "value": "246047298", + "n": 1, + "spent": true, + "hex": "76a91492382692505ccb0bae2864b8e878f0f017ffcad888ac", + "addresses": [ + "QZw82ithbXQn6suPSFQJLxRVkCB5K7Lgct" + ], + "isAddress": true + } + ], + "blockHash": "b7d8a4eee2cfc6d7ba0e152a3602f44f81cb34305daea7754e268e312f59da33", + "blockHeight": 441450, + "confirmations": 166087, + "blockTime": 1567723664, + "value": "246147298", + "valueIn": "246373298", + "fees": "226000", + "hex": "0100000001689cc79fc04105ea56128c9c5b6075033ce29b9e9ddc89bc0cd82d47965b4ece000000006a4730440220506172cf296bc5b7de8da3f840b579bd7b08ba664241b096cf6b4a6206d5fa3002205bc16a044e653605ed225a10c32ebf2fee95f04c216e77cbcfae8be8c36184bc01210255dedfd7fa97011c00833682c70f09ab0b750a5e204c73bcb7233c6bf592fe930000000002a0860100000000001976a914ddf07c38931968ef5540ab424c1911297199a02088ac4262aa0e000000001976a91492382692505ccb0bae2864b8e878f0f017ffcad888ac00000000" + }, + { + "txid": "ce4e5b96472dd80cbc89dc9d9e9be23c0375605b9c8c1256ea0541c09fc79c68", + "version": 1, + "vin": [ + { + "txid": "8433c6693d7771c515c5f1fb4e986a519979646b0ad291f6e8285a436eae6e77", + "n": 0, + "addresses": [ + "QLbzywq3JhTyzgMEnuQnAYHLxwXqr1Bv1y" + ], + "isAddress": true, + "value": "9889260", + "hex": "483045022100948d374e9148f549b215ef747fb22cd344b6cdb6250dd40b8fafebad4faa08c302200a5c69c7bbbc8d95aa957c9ba685436a8bc908d6929982a061d316c38382fbad0121035b43e656315335c7ab54661999c9471117234fcf7d37122b13e7563fbf0a0310" + }, + { + "txid": "7ee828de99e80017e210630a730e433dd05133d16efee0a6ebdd94c7140d33b8", + "n": 1, + "addresses": [ + "QhQxEbempk1agy7moRTwtedwciQxmPGqYZ" + ], + "isAddress": true, + "value": "10000000", + "hex": "483045022100af5a18452175a9ea7531428c7438589ef7cd6d1411f5553b8e2a50c7e5f558fc02207e4eb03f44c6b1540fafb7703ba90009c3431ec4c3603defb95e667dd6b5639a012103c9f314eefa81257877d5454256f5274f3e34cfd6130a7c745bd7bf8716a959f3" + }, + { + "txid": "80fe00fff38f8960db42f980bb0e1d163c4ef66c523c0bc8d396bdb8c40d9fde", + "n": 2, + "addresses": [ + "QcZDgRGkqxQGRZwpEhE2yGQbtwPMrKftcr" + ], + "isAddress": true, + "value": "99905728", + "hex": "47304402205819d69e0fe9c289379503c10db60f7452940885e3392e2d701db736ac7081b402202164e3de6275ecb9a5213f6fa3910e2cf6d3f72f31fdc7ba189bb121e8d8c27a0121034de1f3056ca8955db8c603d111a50f385199a2a5c386bd4bd270f22130fa4ba3" + }, + { + "txid": "151bfd09793a61e570a10e2e9a255b67687555dc7d042244bd84d5342dd75a96", + "vout": 1, + "n": 3, + "addresses": [ + "Qa9QnPPQkXuATT1oftnMxfk3yDbC6PeCvC" + ], + "isAddress": true, + "value": "127214310", + "hex": "483045022100e9ff37e8464654e16810047ff39504a5073996c2b74f3f0b766f836af42ac07b022045b8ac22c407e7f4a8ee146c07d612bc77bbeeaafc4bad58a7c9cc67c2b3ffb9012103437362508cfb7dba11a47eeb7c7ec016a2419c1212fb8c554fd27c9b5b0980b6" + } + ], + "vout": [ + { + "value": "246373298", + "n": 0, + "spent": true, + "hex": "76a9145571b1af28985745be76ab7d17ba22041707ae0e88ac", + "addresses": [ + "QUPmkCzWkLtMfWvjKEStpgqMADQjbDhxbn" + ], + "isAddress": true + } + ], + "blockHash": "262401097f9ff78c40407e583661ac67be2eba9f0f19b01de2a141083e079cb1", + "blockHeight": 439829, + "confirmations": 167708, + "blockTime": 1567495648, + "value": "246373298", + "valueIn": "247009298", + "fees": "636000", + "hex": "0100000004776eae6e435a28e8f691d20a6b647999516a984efbf1c515c571773d69c63384000000006b483045022100948d374e9148f549b215ef747fb22cd344b6cdb6250dd40b8fafebad4faa08c302200a5c69c7bbbc8d95aa957c9ba685436a8bc908d6929982a061d316c38382fbad0121035b43e656315335c7ab54661999c9471117234fcf7d37122b13e7563fbf0a031000000000b8330d14c794ddeba6e0fe6ed13351d03d430e730a6310e21700e899de28e87e000000006b483045022100af5a18452175a9ea7531428c7438589ef7cd6d1411f5553b8e2a50c7e5f558fc02207e4eb03f44c6b1540fafb7703ba90009c3431ec4c3603defb95e667dd6b5639a012103c9f314eefa81257877d5454256f5274f3e34cfd6130a7c745bd7bf8716a959f300000000de9f0dc4b8bd96d3c80b3c526cf64e3c161d0ebb80f942db60898ff3ff00fe80000000006a47304402205819d69e0fe9c289379503c10db60f7452940885e3392e2d701db736ac7081b402202164e3de6275ecb9a5213f6fa3910e2cf6d3f72f31fdc7ba189bb121e8d8c27a0121034de1f3056ca8955db8c603d111a50f385199a2a5c386bd4bd270f22130fa4ba300000000965ad72d34d584bd4422047ddc557568675b259a2e0ea170e5613a7909fd1b15010000006b483045022100e9ff37e8464654e16810047ff39504a5073996c2b74f3f0b766f836af42ac07b022045b8ac22c407e7f4a8ee146c07d612bc77bbeeaafc4bad58a7c9cc67c2b3ffb9012103437362508cfb7dba11a47eeb7c7ec016a2419c1212fb8c554fd27c9b5b0980b60000000001b25baf0e000000001976a9145571b1af28985745be76ab7d17ba22041707ae0e88ac00000000" + }, + { + "txid": "80fe00fff38f8960db42f980bb0e1d163c4ef66c523c0bc8d396bdb8c40d9fde", + "version": 1, + "vin": [ + { + "txid": "151bfd09793a61e570a10e2e9a255b67687555dc7d042244bd84d5342dd75a96", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QS9jjFyKa7vKVAvvQk68sk29Cq2kvrK1Hq" + ], + "isAddress": true, + "value": "100000000", + "hex": "47304402205e7d194cc6e73636ecf5765ece58ae05b2c96fd9d5b798e4fb7d187a9e80febb022003e50c9b0158a85ab9d26a0646d19331b7df0ab2bc0da2c481fbc883c83f922d0121032ea5359007513b35753e5221dddc38b063db93a187d2cbf6789a01dfc84611fc" + } + ], + "vout": [ + { + "value": "99905728", + "n": 0, + "spent": true, + "hex": "76a914aefc17db4cd14c4d9164c776ecd87bbeb4bd89fe88ac", + "addresses": [ + "QcZDgRGkqxQGRZwpEhE2yGQbtwPMrKftcr" + ], + "isAddress": true + } + ], + "blockHash": "8e030c2397afaf82a09af90c1e1efb689e3c7c47f1d8c2ebba09bd96992c1ef9", + "blockHeight": 429870, + "confirmations": 177667, + "blockTime": 1566071072, + "value": "99905728", + "valueIn": "100000000", + "fees": "94272", + "hex": "0100000001965ad72d34d584bd4422047ddc557568675b259a2e0ea170e5613a7909fd1b15000000006a47304402205e7d194cc6e73636ecf5765ece58ae05b2c96fd9d5b798e4fb7d187a9e80febb022003e50c9b0158a85ab9d26a0646d19331b7df0ab2bc0da2c481fbc883c83f922d0121032ea5359007513b35753e5221dddc38b063db93a187d2cbf6789a01dfc84611fcfeffffff01c070f405000000001976a914aefc17db4cd14c4d9164c776ecd87bbeb4bd89fe88ac00000000" + }, + { + "txid": "151bfd09793a61e570a10e2e9a255b67687555dc7d042244bd84d5342dd75a96", + "version": 1, + "vin": [ + { + "txid": "abcfcb76238977f7a456a86c9fb4dbcff9da781db93b2992c40d4a2e97a2b2a1", + "vout": 1, + "n": 0, + "addresses": [ + "QcZDgRGkqxQGRZwpEhE2yGQbtwPMrKftcr" + ], + "isAddress": true, + "value": "227440310", + "hex": "483045022100f133955b319de6ee167d49f77dbe49869206b27815b8a196a33162039c0eb28002206ad29c34667078876547fedbd35d9f9b3a5d45022d12a40deef0c3ebc293d2340121034de1f3056ca8955db8c603d111a50f385199a2a5c386bd4bd270f22130fa4ba3" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a9143cd9ef95a8f822932f2afb20993dd4325c42123288ac", + "addresses": [ + "QS9jjFyKa7vKVAvvQk68sk29Cq2kvrK1Hq" + ], + "isAddress": true + }, + { + "value": "127214310", + "n": 1, + "spent": true, + "hex": "76a914948b207393388b47023f5561f2d21235cb31bb7788ac", + "addresses": [ + "Qa9QnPPQkXuATT1oftnMxfk3yDbC6PeCvC" + ], + "isAddress": true + } + ], + "blockHash": "a295d2da8738dcb13ae2e23041fdba6c6b18b3e5ab8bd0ea73d8e131170b5cb1", + "blockHeight": 429869, + "confirmations": 177668, + "blockTime": 1566070960, + "value": "227214310", + "valueIn": "227440310", + "fees": "226000", + "hex": "0100000001a1b2a2972e4a0dc492293bb91d78daf9cfdbb49f6ca856a4f777892376cbcfab010000006b483045022100f133955b319de6ee167d49f77dbe49869206b27815b8a196a33162039c0eb28002206ad29c34667078876547fedbd35d9f9b3a5d45022d12a40deef0c3ebc293d2340121034de1f3056ca8955db8c603d111a50f385199a2a5c386bd4bd270f22130fa4ba3000000000200e1f505000000001976a9143cd9ef95a8f822932f2afb20993dd4325c42123288ace6229507000000001976a914948b207393388b47023f5561f2d21235cb31bb7788ac00000000" + }, + { + "txid": "8433c6693d7771c515c5f1fb4e986a519979646b0ad291f6e8285a436eae6e77", + "version": 1, + "vin": [ + { + "txid": "abcfcb76238977f7a456a86c9fb4dbcff9da781db93b2992c40d4a2e97a2b2a1", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QYQMNjZ7iaJXRJnVAE11MzCFCwre7Fw9qZ" + ], + "isAddress": true, + "value": "10000000", + "hex": "483045022100cc9a5ea14c568d646ca12debf9ebbe52c18c9521c3a56d3c1c68072302d0033c0220030de3c9fa1cb9d731616a204a34db259600d643bbb8536d60647aab3c9c3e340121028417e67c7627b28deb97d9eba306f60ad9f56f28ab9c2918ffb4f9cb1655131c" + } + ], + "vout": [ + { + "value": "9889260", + "n": 0, + "spent": true, + "hex": "76a9140000ba9b707dd9aa3aa14174cea6c42ac0d7478a88ac", + "addresses": [ + "QLbzywq3JhTyzgMEnuQnAYHLxwXqr1Bv1y" + ], + "isAddress": true + } + ], + "blockHash": "d117c8f87bf1328d993b6b5578bb69add612b98a289c3802637c16644f85177d", + "blockHeight": 399982, + "confirmations": 207555, + "blockTime": 1561806784, + "value": "9889260", + "valueIn": "10000000", + "fees": "110740", + "hex": "0100000001a1b2a2972e4a0dc492293bb91d78daf9cfdbb49f6ca856a4f777892376cbcfab000000006b483045022100cc9a5ea14c568d646ca12debf9ebbe52c18c9521c3a56d3c1c68072302d0033c0220030de3c9fa1cb9d731616a204a34db259600d643bbb8536d60647aab3c9c3e340121028417e67c7627b28deb97d9eba306f60ad9f56f28ab9c2918ffb4f9cb1655131cfeffffff01ece59600000000001976a9140000ba9b707dd9aa3aa14174cea6c42ac0d7478a88ac00000000" + }, + { + "txid": "abcfcb76238977f7a456a86c9fb4dbcff9da781db93b2992c40d4a2e97a2b2a1", + "version": 1, + "vin": [ + { + "txid": "7ee828de99e80017e210630a730e433dd05133d16efee0a6ebdd94c7140d33b8", + "vout": 1, + "sequence": 4294967293, + "n": 0, + "addresses": [ + "QMyP1kj8x2bPiC3Yrirv5wChafRvCdgqVR" + ], + "isAddress": true, + "value": "237551050", + "hex": "47304402201899d3b36561a2472a37061a706c31da8b37725591ede822da40a5b58b469af602206a8eaa1141badd3cdad6a559a39ecf5f74aba459cadd41b10cf7b8ab8246b9be012103bbaedda0fc7212f6ae36c6f118ceaad821693b68b9016b25e85b0e1d320abedb" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "76a914816e451a8afb6753d6617633cc8d9785fd33599c88ac", + "addresses": [ + "QYQMNjZ7iaJXRJnVAE11MzCFCwre7Fw9qZ" + ], + "isAddress": true + }, + { + "value": "227440310", + "n": 1, + "spent": true, + "hex": "76a914aefc17db4cd14c4d9164c776ecd87bbeb4bd89fe88ac", + "addresses": [ + "QcZDgRGkqxQGRZwpEhE2yGQbtwPMrKftcr" + ], + "isAddress": true + } + ], + "blockHash": "869311ff5fd04b0786f93c18e556cc01f229e29eb7ae049977454b770150efbb", + "blockHeight": 399839, + "confirmations": 207698, + "blockTime": 1561786736, + "value": "237440310", + "valueIn": "237551050", + "fees": "110740", + "hex": "0100000001b8330d14c794ddeba6e0fe6ed13351d03d430e730a6310e21700e899de28e87e010000006a47304402201899d3b36561a2472a37061a706c31da8b37725591ede822da40a5b58b469af602206a8eaa1141badd3cdad6a559a39ecf5f74aba459cadd41b10cf7b8ab8246b9be012103bbaedda0fc7212f6ae36c6f118ceaad821693b68b9016b25e85b0e1d320abedbfdffffff0280969800000000001976a914816e451a8afb6753d6617633cc8d9785fd33599c88acb6768e0d000000001976a914aefc17db4cd14c4d9164c776ecd87bbeb4bd89fe88ac00000000" + }, + { + "txid": "7ee828de99e80017e210630a730e433dd05133d16efee0a6ebdd94c7140d33b8", + "version": 1, + "vin": [ + { + "txid": "672cec4ecac82121424347aa17af0cee984cd62c77bb1f38d100acc200377b92", + "n": 0, + "addresses": [ + "QUFxdPbEwYK119NiorpWMR64yaQb8sdFJv" + ], + "isAddress": true, + "value": "247661790", + "hex": "463043021f01f8f944c31521e2be368f04c007e1bd54c204676ead74ec17e740f58ed7b302200707f009a240c94348bedf3861e816fac3498fefc1f5740d9f21ac12d951f441012103361b872338e22f1813d052d3244aec7df9a0b06540ba3b701e2e454ca3fd70fc" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "76a914e444805cfdf15b96b60952475723969e9322126588ac", + "addresses": [ + "QhQxEbempk1agy7moRTwtedwciQxmPGqYZ" + ], + "isAddress": true + }, + { + "value": "237551050", + "n": 1, + "spent": true, + "hex": "76a9140f03fb09f60fa04543e1d448ebd9610d4fa6876488ac", + "addresses": [ + "QMyP1kj8x2bPiC3Yrirv5wChafRvCdgqVR" + ], + "isAddress": true + } + ], + "blockHash": "9cdb9e6de87027fe2361d943701d28824265a99af193fa592e82c84cf0883d44", + "blockHeight": 399714, + "confirmations": 207823, + "blockTime": 1561769088, + "value": "247551050", + "valueIn": "247661790", + "fees": "110740", + "hex": "0100000001927b3700c2ac00d1381fbb772cd64c98ee0caf17aa4743422121c8ca4eec2c670000000069463043021f01f8f944c31521e2be368f04c007e1bd54c204676ead74ec17e740f58ed7b302200707f009a240c94348bedf3861e816fac3498fefc1f5740d9f21ac12d951f441012103361b872338e22f1813d052d3244aec7df9a0b06540ba3b701e2e454ca3fd70fc000000000280969800000000001976a914e444805cfdf15b96b60952475723969e9322126588accabd280e000000001976a9140f03fb09f60fa04543e1d448ebd9610d4fa6876488ac00000000" + }, + { + "txid": "672cec4ecac82121424347aa17af0cee984cd62c77bb1f38d100acc200377b92", + "version": 1, + "vin": [ + { + "txid": "7c3dd204f1f1b4ebb4a25e50f045123c718c296d5e2ffd5e0ad6a595c941a4b5", + "n": 0, + "addresses": [ + "QTQzku6DnxmwY7auEpZ5ReWhkpCyDb6SCY" + ], + "isAddress": true, + "value": "247755870", + "hex": "483045022100918f5efd86345de92d939572f92207e86afbc0c37a5c2cc1b5842b9ce192da0c02206bb03600e9fb1a32588093cb84ebef61a15c2e0e49499a08b85f79dac6c27d79012103c450d0f844424f8315166aba49a33ad036b7387e6b7d97568bcf71ccaac33fe9" + } + ], + "vout": [ + { + "value": "247661790", + "n": 0, + "spent": true, + "hex": "76a91453f7735ae364912de8ba1e98700f1e6b0211da0e88ac", + "addresses": [ + "QUFxdPbEwYK119NiorpWMR64yaQb8sdFJv" + ], + "isAddress": true + } + ], + "blockHash": "e1cbfe22ed9777c979c4703bb84dc7d7b957df927cb8dd71c79ba300c9f6beef", + "blockHeight": 399654, + "confirmations": 207883, + "blockTime": 1561760288, + "value": "247661790", + "valueIn": "247755870", + "fees": "94080", + "hex": "0100000001b5a441c995a5d60a5efd2f5e6d298c713c1245f0505ea2b4ebb4f1f104d23d7c000000006b483045022100918f5efd86345de92d939572f92207e86afbc0c37a5c2cc1b5842b9ce192da0c02206bb03600e9fb1a32588093cb84ebef61a15c2e0e49499a08b85f79dac6c27d79012103c450d0f844424f8315166aba49a33ad036b7387e6b7d97568bcf71ccaac33fe90000000001de04c30e000000001976a91453f7735ae364912de8ba1e98700f1e6b0211da0e88ac00000000" + }, + { + "txid": "7c3dd204f1f1b4ebb4a25e50f045123c718c296d5e2ffd5e0ad6a595c941a4b5", + "version": 1, + "vin": [ + { + "txid": "72fbc53fb360cc0620d8ba7afa3962fcf262c3484d7a0717dc1585df3d26516e", + "vout": 1, + "sequence": 4294967293, + "n": 0, + "addresses": [ + "Qffiov6Qpv2mguHJ8w1EgGWtCbE7JT5Th5" + ], + "isAddress": true, + "value": "4909600", + "hex": "47304402205049e57262c1774be9ad3ed35ef6986700c33f440e794be55dd451ddcc0f73ae02207bd1988f5fe5e27efd2e30400b3c99460489c11c73e5ae688f73ecf1b8e00098012103f0aaded07fe7d6fa752e7df6ae09df638192f0865bfb3388dfe8fd57682103e1" + }, + { + "txid": "233b7b7648a38b3d362f21c675ae5d3bd9109715639007131d45c83466fea7e7", + "sequence": 4294967294, + "n": 1, + "addresses": [ + "QUVMiuKoMV8aoTcU2YvJysRbQK7WZb7sCr" + ], + "isAddress": true, + "value": "242992878", + "hex": "47304402203b014a9e9d45b0479c0c270ed98fb7ceb1930e3f9f54447a910f611a3d3e188c022050764a1c4b02a51301aab97f8b1ee5be73fae74a5538c2a1367d254015e8b96601210224e25c02201d7e39527f5f271b01185d1a718f9af3da52a8fe3f5cec796c40e1" + } + ], + "vout": [ + { + "value": "247755870", + "n": 0, + "spent": true, + "hex": "76a9144ab4d8976ea36f098e46686c1edf953a443f957b88ac", + "addresses": [ + "QTQzku6DnxmwY7auEpZ5ReWhkpCyDb6SCY" + ], + "isAddress": true + } + ], + "blockHash": "427bb2df63e8b9ee5099cfd129143acd785bce0d824b58b69615f39226f783d4", + "blockHeight": 398295, + "confirmations": 209242, + "blockTime": 1561566016, + "value": "247755870", + "valueIn": "247902478", + "fees": "146608", + "hex": "01000000026e51263ddf8515dc17077a4d48c362f2fc6239fa7abad82006cc60b33fc5fb72010000006a47304402205049e57262c1774be9ad3ed35ef6986700c33f440e794be55dd451ddcc0f73ae02207bd1988f5fe5e27efd2e30400b3c99460489c11c73e5ae688f73ecf1b8e00098012103f0aaded07fe7d6fa752e7df6ae09df638192f0865bfb3388dfe8fd57682103e1fdffffffe7a7fe6634c8451d13079063159710d93b5dae75c6212f363d8ba348767b3b23000000006a47304402203b014a9e9d45b0479c0c270ed98fb7ceb1930e3f9f54447a910f611a3d3e188c022050764a1c4b02a51301aab97f8b1ee5be73fae74a5538c2a1367d254015e8b96601210224e25c02201d7e39527f5f271b01185d1a718f9af3da52a8fe3f5cec796c40e1feffffff015e74c40e000000001976a9144ab4d8976ea36f098e46686c1edf953a443f957b88ac00000000" + }, + { + "txid": "72fbc53fb360cc0620d8ba7afa3962fcf262c3484d7a0717dc1585df3d26516e", + "version": 1, + "vin": [ + { + "txid": "b7b6dd1d0a79f8d982d61d857445bdd05b4b7786b87445148071656f0aa23342", + "n": 0, + "addresses": [ + "QePvvosxwadDcnJZDrsfDikJrs4ZgbZniR" + ], + "isAddress": true, + "value": "10000000", + "hex": "483045022100be31157bea8b8540a84f212427e8d167186d15d10f60e1b6c6f0f4a1513204280220194848b7d3c1633ef113df3affab3432bc69ce7d7c3ce150da448f824724aed8012102b7526f57a2a1a25c8fac4ea88991162d0e11402bc9b6a147b7328345e5748a53" + } + ], + "vout": [ + { + "value": "5000000", + "n": 0, + "spent": true, + "hex": "76a9148890ed0efb68ed04eb8c29a2615eac20c44f13c188ac", + "addresses": [ + "QZ45d2KP5wXCh8BrPXG8u71Ewxjh2m4hmi" + ], + "isAddress": true + }, + { + "value": "4909600", + "n": 1, + "spent": true, + "hex": "76a914d11f483db486c73246c7d78a56282ae92594356a88ac", + "addresses": [ + "Qffiov6Qpv2mguHJ8w1EgGWtCbE7JT5Th5" + ], + "isAddress": true + } + ], + "blockHash": "76416e44f8a26cd0effeb92f16c8e75a71b15e42cd14c0c0b8e7678b51c14d44", + "blockHeight": 398206, + "confirmations": 209331, + "blockTime": 1561553136, + "value": "9909600", + "valueIn": "10000000", + "fees": "90400", + "hex": "01000000014233a20a6f657180144574b886774b5bd0bd4574851dd682d9f8790a1dddb6b7000000006b483045022100be31157bea8b8540a84f212427e8d167186d15d10f60e1b6c6f0f4a1513204280220194848b7d3c1633ef113df3affab3432bc69ce7d7c3ce150da448f824724aed8012102b7526f57a2a1a25c8fac4ea88991162d0e11402bc9b6a147b7328345e5748a530000000002404b4c00000000001976a9148890ed0efb68ed04eb8c29a2615eac20c44f13c188ac20ea4a00000000001976a914d11f483db486c73246c7d78a56282ae92594356a88ac00000000" + }, + { + "txid": "b7b6dd1d0a79f8d982d61d857445bdd05b4b7786b87445148071656f0aa23342", + "version": 1, + "vin": [ + { + "txid": "ef3b2f934b96df6d11d327710b1f18bc146b1eb420fa73ad17f068d0ce751f7e", + "n": 0, + "addresses": [ + "QV1LG9Wntr3JQKUSodXwaUojLG1DLVfCnT" + ], + "isAddress": true, + "value": "45600000", + "hex": "483045022100a25f1466a3680826f46ccf38f4fbd99185a696106fa479b545da5059c9d950c602200a0dc3f696040685cc9b391d1a7ac4508c1987aac130776f957323ca97b5dcf0012103a3fceb1dba0f312cfdb0c87e3f5409ae502e2748a3af990659ceeb0924b757d8" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "76a914c32a9e08a1d9178e68c3d067d228e48705d4268c88ac", + "addresses": [ + "QePvvosxwadDcnJZDrsfDikJrs4ZgbZniR" + ], + "isAddress": true + }, + { + "value": "35509600", + "n": 1, + "spent": true, + "hex": "76a91402ad7daabbda4deae283b97ab080852d36ed39b288ac", + "addresses": [ + "QLr9J3K3wbzxRYobsSLj7s2xvMwnCsHpLc" + ], + "isAddress": true + } + ], + "blockHash": "366d09f073da682b518e15da7c19dfc5abe4ed574353895b8a0c3d25a8a998ca", + "blockHeight": 398193, + "confirmations": 209344, + "blockTime": 1561551200, + "value": "45509600", + "valueIn": "45600000", + "fees": "90400", + "hex": "01000000017e1f75ced068f017ad73fa20b41e6b14bc181f0b7127d3116ddf964b932f3bef000000006b483045022100a25f1466a3680826f46ccf38f4fbd99185a696106fa479b545da5059c9d950c602200a0dc3f696040685cc9b391d1a7ac4508c1987aac130776f957323ca97b5dcf0012103a3fceb1dba0f312cfdb0c87e3f5409ae502e2748a3af990659ceeb0924b757d8000000000280969800000000001976a914c32a9e08a1d9178e68c3d067d228e48705d4268c88ac60d51d02000000001976a91402ad7daabbda4deae283b97ab080852d36ed39b288ac00000000" + }, + { + "txid": "233b7b7648a38b3d362f21c675ae5d3bd9109715639007131d45c83466fea7e7", + "version": 1, + "vin": [ + { + "txid": "ef3b2f934b96df6d11d327710b1f18bc146b1eb420fa73ad17f068d0ce751f7e", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QZ2VsubSNp9X9KbXCmwixzuRsFRZRi83Hb" + ], + "isAddress": true, + "value": "44308018", + "hex": "48304502210091da65c9c91407f0ec5fd3e6bc293e64d731f645e4f11ad2d8f5ed923e364dd902202c9e3bb8c2739f4b938d4c48804cd31db13a4397cae80800c98a98d59e59ba6a012102ca5ca40559a929d01cae26d3a591dc9d2baa4d90e8f9054b7884e5fdb1491f4b" + }, + { + "txid": "ef335bef783551cb054acd220555f1588cc4b03c0f47cc0839220c81d3ceb88d", + "vout": 1, + "sequence": 4294967293, + "n": 1, + "addresses": [ + "QdfcTR3TQHjGHcKLiHmiPLRfVPFRWazJPg" + ], + "isAddress": true, + "value": "198831468", + "hex": "483045022100855f6ffbd4720594a8d1fc881166b96faea86d25e8037bb502a7bafa74ea64b302201bf166370062e1fda50142ace2fb35f6ce1bac9f23a242483ae6a6036baf0ce0012103eacf72d93e33e03143ef74989f8d3299f30504d6fdd5ec5d5ff0da9251dd3a16" + } + ], + "vout": [ + { + "value": "242992878", + "n": 0, + "spent": true, + "hex": "76a9145680230ab546f13b6ba46d3d0d8dfaa39194886588ac", + "addresses": [ + "QUVMiuKoMV8aoTcU2YvJysRbQK7WZb7sCr" + ], + "isAddress": true + } + ], + "blockHash": "256af676be21e85a05e3da797466ce3cade2eb0ddae11fecea1254ba75a7542a", + "blockHeight": 398165, + "confirmations": 209372, + "blockTime": 1561547200, + "value": "242992878", + "valueIn": "243139486", + "fees": "146608", + "hex": "01000000027e1f75ced068f017ad73fa20b41e6b14bc181f0b7127d3116ddf964b932f3bef010000006b48304502210091da65c9c91407f0ec5fd3e6bc293e64d731f645e4f11ad2d8f5ed923e364dd902202c9e3bb8c2739f4b938d4c48804cd31db13a4397cae80800c98a98d59e59ba6a012102ca5ca40559a929d01cae26d3a591dc9d2baa4d90e8f9054b7884e5fdb1491f4bfeffffff8db8ced3810c223908cc470f3cb0c48c58f1550522cd4a05cb513578ef5b33ef010000006b483045022100855f6ffbd4720594a8d1fc881166b96faea86d25e8037bb502a7bafa74ea64b302201bf166370062e1fda50142ace2fb35f6ce1bac9f23a242483ae6a6036baf0ce0012103eacf72d93e33e03143ef74989f8d3299f30504d6fdd5ec5d5ff0da9251dd3a16fdffffff01eec67b0e000000001976a9145680230ab546f13b6ba46d3d0d8dfaa39194886588ac00000000" + }, + { + "txid": "ef335bef783551cb054acd220555f1588cc4b03c0f47cc0839220c81d3ceb88d", + "version": 1, + "vin": [ + { + "txid": "506d07570d75914d5bd319d591374fb9cd1633f5c8b3cc800387e104298e8a62", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QfLtauKWxzF6pDf2ceXJe5oqizNHVMBneH" + ], + "isAddress": true, + "value": "198984808", + "hex": "4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081e" + }, + { + "txid": "e22c3e2ea4d285b71a73c41cdbb51f7c75d80b6f473e7f4aade6df5bf8771942", + "sequence": 4294967292, + "n": 1, + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true, + "value": "43000000000", + "hex": "483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764" + } + ], + "vout": [ + { + "value": "43000000000", + "n": 0, + "spent": true, + "hex": "76a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac", + "addresses": [ + "QURZqPoBfuXXoHDkCHCvhGJa1DP2Ahj1KX" + ], + "isAddress": true + }, + { + "value": "198831468", + "n": 1, + "spent": true, + "hex": "76a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac", + "addresses": [ + "QdfcTR3TQHjGHcKLiHmiPLRfVPFRWazJPg" + ], + "isAddress": true + } + ], + "blockHash": "918141389623f4f880b1ba279bb70ee91de6a005e1a9d523d21a66e8c55f0502", + "blockHeight": 393505, + "confirmations": 214032, + "blockTime": 1560879520, + "value": "43198831468", + "valueIn": "43198984808", + "fees": "153340", + "hex": "0100000002628a8e2904e1870380ccb3c8f53316cdb94f3791d519d35b4d91750d57076d50010000006b4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081efeffffff421977f85bdfe6ad4a7f3e476f0bd8757c1fb5db1cc4731ab785d2a42e3e2ce2000000006b483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764fcffffff0200eeff020a0000001976a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac6cedd90b000000001976a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac00000000" + }, + { + "txid": "e22c3e2ea4d285b71a73c41cdbb51f7c75d80b6f473e7f4aade6df5bf8771942", + "version": 1, + "vin": [ + { + "txid": "ee3b548dbe40fc15cb48fe297b2fa17f1bfffb5a91836bc25674f23b18156ab4", + "vout": 1, + "n": 0, + "addresses": [ + "QZsgcV5SxtrCxjyP5mXAmVosMKrxbEWFfL" + ], + "isAddress": true, + "value": "55000000000", + "hex": "473044022045cd6c3831cb6c0f33b2e3d05940b8205c6293c96f81cfbccc0c29c631dd2a2e0220263bd13fff18d75d45b15f1102118b28001bde09de38f4c5f9c5c5b6f27781c2012102817713bf5592a19279ed887fe88b04173c3844ecc6adf3f75213734b8cecbda4" + } + ], + "vout": [ + { + "value": "43000000000", + "n": 0, + "spent": true, + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true + }, + { + "value": "11999907792", + "n": 1, + "spent": true, + "hex": "76a914ccdab9a8e80f5c1b7f8eabbc9a8f5a00754d000a88ac", + "addresses": [ + "QfH9yjB4tEGd8jK1YY4JvXtT5TdaCGX7Rt" + ], + "isAddress": true + } + ], + "blockHash": "ce003cd41af05d06ef406e4798d3d8fc3113ae028336a92e22ea93ab5a73ea4a", + "blockHeight": 390495, + "confirmations": 217042, + "blockTime": 1560449520, + "value": "54999907792", + "valueIn": "55000000000", + "fees": "92208", + "hex": "0100000001b46a15183bf27456c26b83915afbff1b7fa12f7b29fe48cb15fc40be8d543bee010000006a473044022045cd6c3831cb6c0f33b2e3d05940b8205c6293c96f81cfbccc0c29c631dd2a2e0220263bd13fff18d75d45b15f1102118b28001bde09de38f4c5f9c5c5b6f27781c2012102817713bf5592a19279ed887fe88b04173c3844ecc6adf3f75213734b8cecbda4000000000200eeff020a0000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888acd00f40cb020000001976a914ccdab9a8e80f5c1b7f8eabbc9a8f5a00754d000a88ac00000000" + }, + { + "txid": "ef3b2f934b96df6d11d327710b1f18bc146b1eb420fa73ad17f068d0ce751f7e", + "version": 1, + "vin": [ + { + "txid": "f81a7df95b23bdf45b8c575d07199cb7c3e46e84704412174c0eb38820459311", + "n": 0, + "addresses": [ + "QeUBhueTQt35s4BMRWvPcX3RCguSe2Ghf1" + ], + "isAddress": true, + "value": "90000000", + "hex": "47304402200ea13a1f081a5176d5c3ab8fcbc1b494fc0645fa0841fa354572487054ed95ee02200d0fd71fd6cf3031b86e15dafedc7ff85ca6f03412822c4c2a1e97c08a01f293012103a5acc1412252845944273732db657873b8241d005cdc8b7133636b4399d45b51" + } + ], + "vout": [ + { + "value": "45600000", + "n": 0, + "spent": true, + "hex": "76a9145c2b655a026e05d034505a47671a5a66cf3b1df688ac", + "addresses": [ + "QV1LG9Wntr3JQKUSodXwaUojLG1DLVfCnT" + ], + "isAddress": true + }, + { + "value": "44308018", + "n": 1, + "spent": true, + "hex": "76a914884457adbc0ff5a2007f43075c0414dd0753b5ec88ac", + "addresses": [ + "QZ2VsubSNp9X9KbXCmwixzuRsFRZRi83Hb" + ], + "isAddress": true + } + ], + "blockHash": "8fe138b14146bd34a4ede23ee13d2ab9f47fbd847bcac5aeef19e9c56ff917cf", + "blockHeight": 386238, + "confirmations": 221299, + "blockTime": 1559838400, + "value": "89908018", + "valueIn": "90000000", + "fees": "91982", + "hex": "01000000011193452088b30e4c17124470846ee4c3b79c19075d578c5bf4bd235bf97d1af8000000006a47304402200ea13a1f081a5176d5c3ab8fcbc1b494fc0645fa0841fa354572487054ed95ee02200d0fd71fd6cf3031b86e15dafedc7ff85ca6f03412822c4c2a1e97c08a01f293012103a5acc1412252845944273732db657873b8241d005cdc8b7133636b4399d45b51000000000200cdb702000000001976a9145c2b655a026e05d034505a47671a5a66cf3b1df688ac3216a402000000001976a914884457adbc0ff5a2007f43075c0414dd0753b5ec88ac00000000" + }, + { + "txid": "506d07570d75914d5bd319d591374fb9cd1633f5c8b3cc800387e104298e8a62", + "version": 1, + "vin": [ + { + "txid": "4e496fac305dbce97d96c067a4cbfaa7b5d4614d6c4041985c7dc89e99dd49cd", + "vout": 1, + "n": 0, + "addresses": [ + "QeFgFiCejVjBxRThhJ4ebRgmNXonzZkMfr" + ], + "isAddress": true, + "value": "599077016", + "hex": "473044022031fd10b86e02461dc593781f4c97d3d8e2892a802ff92b02b26ad67b780209a202205566b0ac15596893575d2fb762a082c6528c3047070b2d52c33690f3e90886c0012103f7505ebaded33df0549d5f84bfd176e94087216c34e7116c8c9348a201296b78" + } + ], + "vout": [ + { + "value": "400000000", + "n": 0, + "spent": true, + "hex": "76a9147453245910621e861271929af6b7154903f7a23188ac", + "addresses": [ + "QXD46Mh1rb1xvBvSamatQPfX3yv1M2shfe" + ], + "isAddress": true + }, + { + "value": "198984808", + "n": 1, + "spent": true, + "hex": "76a914cd8f8a0948e351270ee6b3fdc59622a372a7d85d88ac", + "addresses": [ + "QfLtauKWxzF6pDf2ceXJe5oqizNHVMBneH" + ], + "isAddress": true + } + ], + "blockHash": "082a3673444c4fc291d69a94717cf50c5fedebcf9321f311d4078f5f0915a1b3", + "blockHeight": 371887, + "confirmations": 235650, + "blockTime": 1557782304, + "value": "598984808", + "valueIn": "599077016", + "fees": "92208", + "hex": "0100000001cd49dd999ec87d5c9841406c4d61d4b5a7facba467c0967de9bc5d30ac6f494e010000006a473044022031fd10b86e02461dc593781f4c97d3d8e2892a802ff92b02b26ad67b780209a202205566b0ac15596893575d2fb762a082c6528c3047070b2d52c33690f3e90886c0012103f7505ebaded33df0549d5f84bfd176e94087216c34e7116c8c9348a201296b7800000000020084d717000000001976a9147453245910621e861271929af6b7154903f7a23188ac6844dc0b000000001976a914cd8f8a0948e351270ee6b3fdc59622a372a7d85d88ac00000000" + }, + { + "txid": "4e496fac305dbce97d96c067a4cbfaa7b5d4614d6c4041985c7dc89e99dd49cd", + "version": 1, + "vin": [ + { + "txid": "fd8f486538844c2ba61fcf19d2474d213f3b69bbc596e383a3df0b2a872be397", + "vout": 1, + "n": 0, + "addresses": [ + "QjCpHnT38X5e6cxqcTjNxYSKGqt71xydcG" + ], + "isAddress": true, + "value": "999169224", + "hex": "47304402205c7773681fd9219e2767e6562c2db4494ba5849ced0c587933c02995a31b6f820220008306c7e3e5a8ac9d10c0b5b7f51ca984292366d6026044dc7c187fda653283012103c8c65394bbcd25f8d8170603e004ee4aea13779d56772ae6b2eeb19459c1885e" + } + ], + "vout": [ + { + "value": "400000000", + "n": 0, + "spent": true, + "hex": "76a91430a20d6d186573efcb02ce987a4b122d2b2ae9ec88ac", + "addresses": [ + "QR38g7Dr4uHgNGV2WDN4FZ7zHWFAuseVcf" + ], + "isAddress": true + }, + { + "value": "599077016", + "n": 1, + "spent": true, + "hex": "76a914c19b0a513721b10aab8ba0a94cafcb41888c87aa88ac", + "addresses": [ + "QeFgFiCejVjBxRThhJ4ebRgmNXonzZkMfr" + ], + "isAddress": true + } + ], + "blockHash": "4c458211bf8dedc0bb0709171c26d7acd8ab966ae771686a48b4fafc23f61575", + "blockHeight": 371880, + "confirmations": 235657, + "blockTime": 1557781552, + "value": "999077016", + "valueIn": "999169224", + "fees": "92208", + "hex": "010000000197e32b872a0bdfa383e396c5bb693b3f214d47d219cf1fa62b4c843865488ffd010000006a47304402205c7773681fd9219e2767e6562c2db4494ba5849ced0c587933c02995a31b6f820220008306c7e3e5a8ac9d10c0b5b7f51ca984292366d6026044dc7c187fda653283012103c8c65394bbcd25f8d8170603e004ee4aea13779d56772ae6b2eeb19459c1885e00000000020084d717000000001976a91430a20d6d186573efcb02ce987a4b122d2b2ae9ec88ac9830b523000000001976a914c19b0a513721b10aab8ba0a94cafcb41888c87aa88ac00000000" + }, + { + "txid": "fd8f486538844c2ba61fcf19d2474d213f3b69bbc596e383a3df0b2a872be397", + "version": 1, + "vin": [ + { + "txid": "1aaecf66a34809ee22046be8bddf93207c8fc9b0213b3ab1d0ea3ce4f2f6880a", + "vout": 1, + "n": 0, + "addresses": [ + "QZofPF8hq3JoRpSmKAk3SVJhDaRxTydqrS" + ], + "isAddress": true, + "value": "1799261432", + "hex": "47304402205d9dd4efacdd8daadebc20e0f1ca9d27a669d7117a0fca3e816c6b4b6ed10a66022051962a17fb71fbb0609454ecd01fc39f5ec3db767a03d36c5f6757f94a8ee58401210272ba28d3e42d8ad70125456d39cd57b2fac15d7ebd5bf2cb5d25a9b8b7684e38" + } + ], + "vout": [ + { + "value": "800000000", + "n": 0, + "spent": true, + "hex": "76a9144d606371996c3627fb7ff801b4e60d139a73c14c88ac", + "addresses": [ + "QTf7cFrSjNAvP9guENBPTGkHmrXaBienwL" + ], + "isAddress": true + }, + { + "value": "999169224", + "n": 1, + "spent": true, + "hex": "76a914f7e92115bb48ad0010eb71968a8d3baf62a960b488ac", + "addresses": [ + "QjCpHnT38X5e6cxqcTjNxYSKGqt71xydcG" + ], + "isAddress": true + } + ], + "blockHash": "8b58575304b5a00df0a390ec07148cc96fef7ba7500bf2df533b3a6ea82a3859", + "blockHeight": 371877, + "confirmations": 235660, + "blockTime": 1557780768, + "value": "1799169224", + "valueIn": "1799261432", + "fees": "92208", + "hex": "01000000010a88f6f2e43cead0b13a3b21b0c98f7c2093dfbde86b0422ee0948a366cfae1a010000006a47304402205d9dd4efacdd8daadebc20e0f1ca9d27a669d7117a0fca3e816c6b4b6ed10a66022051962a17fb71fbb0609454ecd01fc39f5ec3db767a03d36c5f6757f94a8ee58401210272ba28d3e42d8ad70125456d39cd57b2fac15d7ebd5bf2cb5d25a9b8b7684e3800000000020008af2f000000001976a9144d606371996c3627fb7ff801b4e60d139a73c14c88acc81c8e3b000000001976a914f7e92115bb48ad0010eb71968a8d3baf62a960b488ac00000000" + }, + { + "txid": "1aaecf66a34809ee22046be8bddf93207c8fc9b0213b3ab1d0ea3ce4f2f6880a", + "version": 1, + "vin": [ + { + "txid": "faad61481f064446da34de34da9bc1c8f69f13083fbb8021600366f76a7b3475", + "vout": 1, + "n": 0, + "addresses": [ + "QZofPF8hq3JoRpSmKAk3SVJhDaRxTydqrS" + ], + "isAddress": true, + "value": "2199353640", + "hex": "483045022100d536d10736799426259dd17c5eeee98362b2b542b6c1418ac18e15cd66110709022035b4a2ce1ce7ad3978e4fdb69ef9369bfebbc3183c5964fc138a4dfdc7a183d301210272ba28d3e42d8ad70125456d39cd57b2fac15d7ebd5bf2cb5d25a9b8b7684e38" + } + ], + "vout": [ + { + "value": "400000000", + "n": 0, + "spent": true, + "hex": "76a9141f9b560a954cffd6cb305ce7ba963b516222f57488ac", + "addresses": [ + "QPV79BoKoNW4mW29U9BS7n82BDY44Z5Q7r" + ], + "isAddress": true + }, + { + "value": "1799261432", + "n": 1, + "spent": true, + "hex": "76a91490cefeee5907b57694e1e07e21bc93ad5a57675488ac", + "addresses": [ + "QZofPF8hq3JoRpSmKAk3SVJhDaRxTydqrS" + ], + "isAddress": true + } + ], + "blockHash": "81e08d0c8b36d1997465d157c31b285154661523247a3d41c11a5f0dc6250bc3", + "blockHeight": 371874, + "confirmations": 235663, + "blockTime": 1557780480, + "value": "2199261432", + "valueIn": "2199353640", + "fees": "92208", + "hex": "010000000175347b6af76603602180bb3f08139ff6c8c19bda34de34da4644061f4861adfa010000006b483045022100d536d10736799426259dd17c5eeee98362b2b542b6c1418ac18e15cd66110709022035b4a2ce1ce7ad3978e4fdb69ef9369bfebbc3183c5964fc138a4dfdc7a183d301210272ba28d3e42d8ad70125456d39cd57b2fac15d7ebd5bf2cb5d25a9b8b7684e3800000000020084d717000000001976a9141f9b560a954cffd6cb305ce7ba963b516222f57488acf88c3e6b000000001976a91490cefeee5907b57694e1e07e21bc93ad5a57675488ac00000000" + }, + { + "txid": "faad61481f064446da34de34da9bc1c8f69f13083fbb8021600366f76a7b3475", + "version": 1, + "vin": [ + { + "txid": "a6ccccbcd705751a1dcd2ffd7ad8e8ce400b3185121a67203115065ee4170628", + "vout": 1, + "n": 0, + "addresses": [ + "Qj35M7dSFHzRXPXrB2wAARpG7VUDdxdHCC" + ], + "isAddress": true, + "value": "2599445848", + "hex": "48304502210081206aae11555093d37ff11fcf03bf30175ec7107863ee9af3a286554c8e0db60220273c23796c213aa6afc4396ca1d16a801be76e10073bed917b01512090f13653012102133f6d9cf3aeb04891b6047aa869f5c80f526f5b2d5ad38cdaaff70f5277e158" + } + ], + "vout": [ + { + "value": "400000000", + "n": 0, + "spent": true, + "hex": "76a91468e132870bec77acd4731ec49ead03f99548a8d488ac", + "addresses": [ + "QWAYAEhgTjrFpSENigkRBSWqZQhJNUrX7i" + ], + "isAddress": true + }, + { + "value": "2199353640", + "n": 1, + "spent": true, + "hex": "76a91490cefeee5907b57694e1e07e21bc93ad5a57675488ac", + "addresses": [ + "QZofPF8hq3JoRpSmKAk3SVJhDaRxTydqrS" + ], + "isAddress": true + } + ], + "blockHash": "81e08d0c8b36d1997465d157c31b285154661523247a3d41c11a5f0dc6250bc3", + "blockHeight": 371874, + "confirmations": 235663, + "blockTime": 1557780480, + "value": "2599353640", + "valueIn": "2599445848", + "fees": "92208", + "hex": "0100000001280617e45e06153120671a1285310b40cee8d87afd2fcd1d1a7505d7bccccca6010000006b48304502210081206aae11555093d37ff11fcf03bf30175ec7107863ee9af3a286554c8e0db60220273c23796c213aa6afc4396ca1d16a801be76e10073bed917b01512090f13653012102133f6d9cf3aeb04891b6047aa869f5c80f526f5b2d5ad38cdaaff70f5277e15800000000020084d717000000001976a91468e132870bec77acd4731ec49ead03f99548a8d488ac28791783000000001976a91490cefeee5907b57694e1e07e21bc93ad5a57675488ac00000000" + }, + { + "txid": "a6ccccbcd705751a1dcd2ffd7ad8e8ce400b3185121a67203115065ee4170628", + "version": 1, + "vin": [ + { + "txid": "e48cb1618e8e0a689c6dc13cb5ddf919d79eeaa6c52f759a264045005c75ba3f", + "vout": 1, + "n": 0, + "addresses": [ + "QP6j9eg3afB4WMz1y9wLKez1J4aiC1wdpX" + ], + "isAddress": true, + "value": "2999538056", + "hex": "483045022100f18d78e8108ee38cdca476ec6d58555ae143a23d2f8cf53cc0e10047cb4565c702207021fa4d40704aae3652aca1292c968d45a91164046ab328b67fc15dbdd6f990012103ff3def0371177a677a5b4e8f77d0b8ddaf8285ab38e9225d0124bfd7b3614126" + } + ], + "vout": [ + { + "value": "400000000", + "n": 0, + "spent": true, + "hex": "76a91455ad628bd3280f7a25c6ffe632219969efd52e1288ac", + "addresses": [ + "QUR1FbrT5a7sjM7RZRWKvh9hKFdAvcStoM" + ], + "isAddress": true + }, + { + "value": "2599445848", + "n": 1, + "spent": true, + "hex": "76a914f61189f709c22ae8b15cf521047f04d52766096988ac", + "addresses": [ + "Qj35M7dSFHzRXPXrB2wAARpG7VUDdxdHCC" + ], + "isAddress": true + } + ], + "blockHash": "c15bc1dea688280b438487c7e861cbe5771bf86294a715450a52a145119e556f", + "blockHeight": 371865, + "confirmations": 235672, + "blockTime": 1557779168, + "value": "2999445848", + "valueIn": "2999538056", + "fees": "92208", + "hex": "01000000013fba755c004540269a752fc5a6ea9ed719f9ddb53cc16d9c680a8e8e61b18ce4010000006b483045022100f18d78e8108ee38cdca476ec6d58555ae143a23d2f8cf53cc0e10047cb4565c702207021fa4d40704aae3652aca1292c968d45a91164046ab328b67fc15dbdd6f990012103ff3def0371177a677a5b4e8f77d0b8ddaf8285ab38e9225d0124bfd7b361412600000000020084d717000000001976a91455ad628bd3280f7a25c6ffe632219969efd52e1288ac5865f09a000000001976a914f61189f709c22ae8b15cf521047f04d52766096988ac00000000" + }, + { + "txid": "e48cb1618e8e0a689c6dc13cb5ddf919d79eeaa6c52f759a264045005c75ba3f", + "version": 1, + "vin": [ + { + "txid": "2ece10754c7b21581762f0c97ba75c70ea4c27014c57c99e275fdcb3a81e4a82", + "vout": 1, + "n": 0, + "addresses": [ + "QbA1vmoTn9g2SWMEGxrwgMj4YJZBZjPM64" + ], + "isAddress": true, + "value": "3399630264", + "hex": "4730440220183d1378b64a7d45fa8161cc0009a02fa77ad64242f565a31df2739053d9cb5c02203e36d6e37251667f0fac98592537942fe4e7fca1b808a67cb1b7900ca6e66f530121020d5851125e817ce3476cf3df60f90fccd817886bbbeedab75f047c901eec800b" + } + ], + "vout": [ + { + "value": "400000000", + "n": 0, + "hex": "76a914d58637b5bc95ffd1c2b1394280d799806eb6e26788ac", + "addresses": [ + "Qg4zpmAYHDX2sqvNZvwcK6mXP2rYkx5HVy" + ], + "isAddress": true + }, + { + "value": "2999538056", + "n": 1, + "spent": true, + "hex": "76a9141b5fd3b1e5334f58da46d494098d984f997349cc88ac", + "addresses": [ + "QP6j9eg3afB4WMz1y9wLKez1J4aiC1wdpX" + ], + "isAddress": true + } + ], + "blockHash": "44bf2daa6095c2de48be35afb02c534709d8dee1618436efa2e87ac5bbeb32b2", + "blockHeight": 371863, + "confirmations": 235674, + "blockTime": 1557778720, + "value": "3399538056", + "valueIn": "3399630264", + "fees": "92208", + "hex": "0100000001824a1ea8b3dc5f279ec9574c01274cea705ca77bc9f0621758217b4c7510ce2e010000006a4730440220183d1378b64a7d45fa8161cc0009a02fa77ad64242f565a31df2739053d9cb5c02203e36d6e37251667f0fac98592537942fe4e7fca1b808a67cb1b7900ca6e66f530121020d5851125e817ce3476cf3df60f90fccd817886bbbeedab75f047c901eec800b00000000020084d717000000001976a914d58637b5bc95ffd1c2b1394280d799806eb6e26788ac8851c9b2000000001976a9141b5fd3b1e5334f58da46d494098d984f997349cc88ac00000000" + }, + { + "txid": "2ece10754c7b21581762f0c97ba75c70ea4c27014c57c99e275fdcb3a81e4a82", + "version": 1, + "vin": [ + { + "txid": "a5b112b2c4637f8f9d6c8d7f4bf5f4fb9760f57b96a16f21043c07a28614ecab", + "vout": 1, + "n": 0, + "addresses": [ + "QdWQyQ22AH15vFAduR5vXL96gy6jKGe83u" + ], + "isAddress": true, + "value": "3799722698", + "hex": "47304402201440eb1ec302b54d9a9335db3ec24dfce76f3d9d1d90850c8320a8570c94448702203e3aa49e12213fbcc6c177defea3100d9396bcb574405f9cca35758b439f84380121039083fb8237a9e073eb0f5e369fe4fe9e2d1680546b1d0843a7bc4fa28bb16ac2" + } + ], + "vout": [ + { + "value": "400000000", + "n": 0, + "spent": true, + "hex": "76a914dc68b2824d8b7f295d1f90846e34828afec326fe88ac", + "addresses": [ + "QghQBzp524R83f9H1yUwyBU4vWXuS5D3R4" + ], + "isAddress": true + }, + { + "value": "3399630264", + "n": 1, + "spent": true, + "hex": "76a9149fa096fba1a39f90fb14918a2e3fc83f6210060d88ac", + "addresses": [ + "QbA1vmoTn9g2SWMEGxrwgMj4YJZBZjPM64" + ], + "isAddress": true + } + ], + "blockHash": "b77d614d5ce54da3fa16bbdbffd019d50219f76cd355b8bda644db3da2321fc1", + "blockHeight": 371860, + "confirmations": 235677, + "blockTime": 1557778304, + "value": "3799630264", + "valueIn": "3799722698", + "fees": "92434", + "hex": "0100000001abec1486a2073c04216fa1967bf56097fbf4f54b7f8d6c9d8f7f63c4b212b1a5010000006a47304402201440eb1ec302b54d9a9335db3ec24dfce76f3d9d1d90850c8320a8570c94448702203e3aa49e12213fbcc6c177defea3100d9396bcb574405f9cca35758b439f84380121039083fb8237a9e073eb0f5e369fe4fe9e2d1680546b1d0843a7bc4fa28bb16ac200000000020084d717000000001976a914dc68b2824d8b7f295d1f90846e34828afec326fe88acb83da2ca000000001976a9149fa096fba1a39f90fb14918a2e3fc83f6210060d88ac00000000" + }, + { + "txid": "b828e72bfa1641a3b4f84c7ed123d0380a09108446b09b84516782cb40f05510", + "version": 1, + "vin": [ + { + "txid": "f787ea119a618193cb9faa653aa5629b1c6c84b0927779c93d20c346d9adf4ee", + "vout": 1, + "n": 0, + "addresses": [ + "QdWQyQ22AH15vFAduR5vXL96gy6jKGe83u" + ], + "isAddress": true, + "value": "4599907566", + "hex": "4730440220363dfb0b54b2ca3ee4bb8fdac4bf494913ef9f44f42a09a1936f795ba22fc7fe0220484772160ea280fbdc5b8a7f912a41dad6a8bc850f8dfcc97956a4271a476eec0121039083fb8237a9e073eb0f5e369fe4fe9e2d1680546b1d0843a7bc4fa28bb16ac2" + } + ], + "vout": [ + { + "value": "400000000", + "n": 0, + "spent": true, + "hex": "76a914a5dca0220e76f6cfc31c23d0763c4242d9f00fd088ac", + "addresses": [ + "QbiyuHEi7fzL97A7dfemXeJT7bjoj54ECs" + ], + "isAddress": true + }, + { + "value": "4199815132", + "n": 1, + "spent": true, + "hex": "76a914b96c65d540e98f1675427557987528f18c3a75f388ac", + "addresses": [ + "QdWQyQ22AH15vFAduR5vXL96gy6jKGe83u" + ], + "isAddress": true + } + ], + "blockHash": "4d25fc06d734cbc35872193bbe104981abf6c8bdd29cbbc697a16456e4e98f40", + "blockHeight": 371858, + "confirmations": 235679, + "blockTime": 1557778208, + "value": "4599815132", + "valueIn": "4599907566", + "fees": "92434", + "hex": "0100000001eef4add946c3203dc9797792b0846c1c9b62a53a65aa9fcb9381619a11ea87f7010000006a4730440220363dfb0b54b2ca3ee4bb8fdac4bf494913ef9f44f42a09a1936f795ba22fc7fe0220484772160ea280fbdc5b8a7f912a41dad6a8bc850f8dfcc97956a4271a476eec0121039083fb8237a9e073eb0f5e369fe4fe9e2d1680546b1d0843a7bc4fa28bb16ac200000000020084d717000000001976a914a5dca0220e76f6cfc31c23d0763c4242d9f00fd088acdc1754fa000000001976a914b96c65d540e98f1675427557987528f18c3a75f388ac00000000" + }, + { + "txid": "a5b112b2c4637f8f9d6c8d7f4bf5f4fb9760f57b96a16f21043c07a28614ecab", + "version": 1, + "vin": [ + { + "txid": "b828e72bfa1641a3b4f84c7ed123d0380a09108446b09b84516782cb40f05510", + "vout": 1, + "n": 0, + "addresses": [ + "QdWQyQ22AH15vFAduR5vXL96gy6jKGe83u" + ], + "isAddress": true, + "value": "4199815132", + "hex": "48304502210097597fd831bc8adaabf3751f183ee835d654a731ca187c8105a16381ed081c68022059ff6f13efbcdf20b0ea369907139d88f8f356ec9013b48594192bf3649072650121039083fb8237a9e073eb0f5e369fe4fe9e2d1680546b1d0843a7bc4fa28bb16ac2" + } + ], + "vout": [ + { + "value": "400000000", + "n": 0, + "spent": true, + "hex": "76a914cb13b0ee6e66b4db48fbeb595cde818ece2d097288ac", + "addresses": [ + "Qf7ksQRm1qrQe5KzEBjzm6zNdsTnk2udm8" + ], + "isAddress": true + }, + { + "value": "3799722698", + "n": 1, + "spent": true, + "hex": "76a914b96c65d540e98f1675427557987528f18c3a75f388ac", + "addresses": [ + "QdWQyQ22AH15vFAduR5vXL96gy6jKGe83u" + ], + "isAddress": true + } + ], + "blockHash": "4d25fc06d734cbc35872193bbe104981abf6c8bdd29cbbc697a16456e4e98f40", + "blockHeight": 371858, + "confirmations": 235679, + "blockTime": 1557778208, + "value": "4199722698", + "valueIn": "4199815132", + "fees": "92434", + "hex": "01000000011055f040cb826751849bb0468410090a38d023d17e4cf8b4a34116fa2be728b8010000006b48304502210097597fd831bc8adaabf3751f183ee835d654a731ca187c8105a16381ed081c68022059ff6f13efbcdf20b0ea369907139d88f8f356ec9013b48594192bf3649072650121039083fb8237a9e073eb0f5e369fe4fe9e2d1680546b1d0843a7bc4fa28bb16ac200000000020084d717000000001976a914cb13b0ee6e66b4db48fbeb595cde818ece2d097288acca2a7be2000000001976a914b96c65d540e98f1675427557987528f18c3a75f388ac00000000" + }, + { + "txid": "f787ea119a618193cb9faa653aa5629b1c6c84b0927779c93d20c346d9adf4ee", + "version": 1, + "vin": [ + { + "txid": "dfa44eb9994c1f44eb95efe2a7da492e87073ae96a3c3dd73555f61ce12e8320", + "vout": 1, + "n": 0, + "addresses": [ + "QaQvBedwizcQvX5pYFWEsnmDgZZ5jioA5m" + ], + "isAddress": true, + "value": "5000000000", + "hex": "483045022100f93275ba52e26f3a0ae2e45b233a6b03084494defe5f30e1d0ccc7935d0dc98d02206b9f26e31e5e3e36c39e472b41bda30c887b4febfc53ce2e38a8ff22464243170121020d89d58933b209f209c0a1edf40d051efb30753b9c250d8dc08fb864228b4c8c" + } + ], + "vout": [ + { + "value": "400000000", + "n": 0, + "spent": true, + "hex": "76a9145866765bb56403a71f9d542bd81ea4a69492e42888ac", + "addresses": [ + "QUfQKPTGwKY3UzXcPEGnX41vC1hprTr4qS" + ], + "isAddress": true + }, + { + "value": "4599907566", + "n": 1, + "spent": true, + "hex": "76a914b96c65d540e98f1675427557987528f18c3a75f388ac", + "addresses": [ + "QdWQyQ22AH15vFAduR5vXL96gy6jKGe83u" + ], + "isAddress": true + } + ], + "blockHash": "4d25fc06d734cbc35872193bbe104981abf6c8bdd29cbbc697a16456e4e98f40", + "blockHeight": 371858, + "confirmations": 235679, + "blockTime": 1557778208, + "value": "4999907566", + "valueIn": "5000000000", + "fees": "92434", + "hex": "010000000120832ee11cf65535d73d3c6ae93a07872e49daa7e2ef95eb441f4c99b94ea4df010000006b483045022100f93275ba52e26f3a0ae2e45b233a6b03084494defe5f30e1d0ccc7935d0dc98d02206b9f26e31e5e3e36c39e472b41bda30c887b4febfc53ce2e38a8ff22464243170121020d89d58933b209f209c0a1edf40d051efb30753b9c250d8dc08fb864228b4c8c00000000020084d717000000001976a9145866765bb56403a71f9d542bd81ea4a69492e42888acee042d12010000001976a914b96c65d540e98f1675427557987528f18c3a75f388ac00000000" + }, + { + "txid": "dfa44eb9994c1f44eb95efe2a7da492e87073ae96a3c3dd73555f61ce12e8320", + "version": 2, + "lockTime": 371847, + "vin": [ + { + "txid": "575487400aba81153c17789a5b23ee38fbb6cc49e1802be441f565b85b806e29", + "vout": 1, + "sequence": 4294967293, + "n": 0, + "addresses": [ + "QZBSG69TdoMNAAktaYFSpRzUKPMLNDQe4G" + ], + "isAddress": true, + "value": "23999851200", + "hex": "4730440220451f9a63166e695b6330ca2295129ac4b4d183753714e6e6f8b5aa2ace71841c02202302f8fa125424ced1dcdbbb2bff9736e58053080bf713d5f2e749e1f7027fe90121037025f8084201f448efd299c3be6d2559f02c7de1284d1efdcff680e623267816" + } + ], + "vout": [ + { + "value": "18999761200", + "n": 0, + "spent": true, + "hex": "76a91489f510fd9bd058b5f9e24059125f209d42efbe9a88ac", + "addresses": [ + "QZBSG69TdoMNAAktaYFSpRzUKPMLNDQe4G" + ], + "isAddress": true + }, + { + "value": "5000000000", + "n": 1, + "spent": true, + "hex": "76a9149779e8b2ef497557df77466c8c3c9193a43a7e2888ac", + "addresses": [ + "QaQvBedwizcQvX5pYFWEsnmDgZZ5jioA5m" + ], + "isAddress": true + } + ], + "blockHash": "f59bcf04c02890c625601b89a7e48fa4765c54f7ac186d302e1773a9170246d3", + "blockHeight": 371848, + "confirmations": 235689, + "blockTime": 1557776944, + "value": "23999761200", + "valueIn": "23999851200", + "fees": "90000", + "hex": "0200000001296e805bb865f541e42b80e149ccb6fb38ee235b9a78173c1581ba0a40875457010000006a4730440220451f9a63166e695b6330ca2295129ac4b4d183753714e6e6f8b5aa2ace71841c02202302f8fa125424ced1dcdbbb2bff9736e58053080bf713d5f2e749e1f7027fe90121037025f8084201f448efd299c3be6d2559f02c7de1284d1efdcff680e623267816fdffffff023059796c040000001976a91489f510fd9bd058b5f9e24059125f209d42efbe9a88ac00f2052a010000001976a9149779e8b2ef497557df77466c8c3c9193a43a7e2888ac87ac0500" + }, + { + "txid": "f81a7df95b23bdf45b8c575d07199cb7c3e46e84704412174c0eb38820459311", + "version": 1, + "vin": [ + { + "txid": "22121f29131b2219948e63b8aaac0573641f604c5b88e1fe28f9861f63051f5f", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QVav8YbUUwQq6yFCrkafW79Uv3NUMHT66n" + ], + "isAddress": true, + "value": "12555500", + "hex": "463043021f214ac8d3f6dab3ff4ed5cd862b52c582a829e6cecc8f8440e71e564dc174c90220526805a30f1e3959d9a6c16a9d06c34382dbfe2d26ec5b7a15db580f21c415ec0121023608e446e04c777b55ce0253a99d90d8c6902dab7f37b0b2e29b507849259e74" + }, + { + "txid": "b195994e3c56842a751b89a6c5daf6c286245b0b74b707412e2ff8dc753b1ca4", + "sequence": 4294967293, + "n": 1, + "addresses": [ + "QVav8YbUUwQq6yFCrkafW79Uv3NUMHT66n" + ], + "isAddress": true, + "value": "86483292", + "hex": "47304402207abf586a08f5bcff70a20a69b9bef6c137ace8f9745c045399a08e852d806a8a02207f8dfa6805db6ae119014a2e3732db8a145588b241076989793efd46b8a6a7bf0121023608e446e04c777b55ce0253a99d90d8c6902dab7f37b0b2e29b507849259e74" + } + ], + "vout": [ + { + "value": "90000000", + "n": 0, + "spent": true, + "hex": "76a914c3f89deaed494671b8be39cf3f0dfb90f9906ee588ac", + "addresses": [ + "QeUBhueTQt35s4BMRWvPcX3RCguSe2Ghf1" + ], + "isAddress": true + }, + { + "value": "8736600", + "n": 1, + "spent": true, + "hex": "76a9141bfd274c127df9c5002b1ca194410625cc363a9188ac", + "addresses": [ + "QP9ycthVwbF3xwVpLCcorC7uD6xya3ooKw" + ], + "isAddress": true + } + ], + "blockHash": "dd516586cac95af3fa14d3059f22ceaa23068692f91560dd2e2446eae88a0011", + "blockHeight": 369836, + "confirmations": 237701, + "blockTime": 1557491568, + "value": "98736600", + "valueIn": "99038792", + "fees": "302192", + "hex": "01000000025f1f05631f86f928fee1885b4c601f647305acaab8638e9419221b13291f12220000000069463043021f214ac8d3f6dab3ff4ed5cd862b52c582a829e6cecc8f8440e71e564dc174c90220526805a30f1e3959d9a6c16a9d06c34382dbfe2d26ec5b7a15db580f21c415ec0121023608e446e04c777b55ce0253a99d90d8c6902dab7f37b0b2e29b507849259e74feffffffa41c3b75dcf82f2e4107b7740b5b2486c2f6dac5a6891b752a84563c4e9995b1000000006a47304402207abf586a08f5bcff70a20a69b9bef6c137ace8f9745c045399a08e852d806a8a02207f8dfa6805db6ae119014a2e3732db8a145588b241076989793efd46b8a6a7bf0121023608e446e04c777b55ce0253a99d90d8c6902dab7f37b0b2e29b507849259e74fdffffff02804a5d05000000001976a914c3f89deaed494671b8be39cf3f0dfb90f9906ee588ac584f8500000000001976a9141bfd274c127df9c5002b1ca194410625cc363a9188ac00000000" + }, + { + "txid": "b195994e3c56842a751b89a6c5daf6c286245b0b74b707412e2ff8dc753b1ca4", + "version": 1, + "vin": [ + { + "txid": "143ec0b4f7a144aaeded1749739060d7c1c6d21ff463ea4fef95df357946adf6", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QeUBhueTQt35s4BMRWvPcX3RCguSe2Ghf1" + ], + "isAddress": true, + "value": "9780554", + "hex": "47304402207811d40f485915e1423d9996d38243958ab4768c96c4a8046261e57ae058c7f602203ad4371113afbd43cb805e39a90796c1bbad38054a856c5b9db9477542dfe140012103a5acc1412252845944273732db657873b8241d005cdc8b7133636b4399d45b51" + }, + { + "txid": "22121f29131b2219948e63b8aaac0573641f604c5b88e1fe28f9861f63051f5f", + "vout": 1, + "sequence": 4294967293, + "n": 1, + "addresses": [ + "QiE5pqKaWD6KuKJG1XqqaSuKscqw68WPDj" + ], + "isAddress": true, + "value": "77004930", + "hex": "47304402200dedf8c4f423ad6a5ba54aad47d7da0d6a89d5ebf8106a5725a1d54508c3ee4502203ca16b0c2d6fc903ba8e678c9634d31b4edf8be5b31103e7e7464b6784dc7b830121025c0fa32e88a54b3b57d8043f508bc58bcd0db113900b1c38e4e641e7bdf69837" + } + ], + "vout": [ + { + "value": "86483292", + "n": 0, + "spent": true, + "hex": "76a9146285651ee6abb6788c39df4ecb89f97345cbfa2588ac", + "addresses": [ + "QVav8YbUUwQq6yFCrkafW79Uv3NUMHT66n" + ], + "isAddress": true + } + ], + "blockHash": "cc770fb40122f9b7ebdaa9878ec78acd5a9e89a2410e9a7dd47e4b22c5817b29", + "blockHeight": 369831, + "confirmations": 237706, + "blockTime": 1557490880, + "value": "86483292", + "valueIn": "86785484", + "fees": "302192", + "hex": "0100000002f6ad467935df95ef4fea63f41fd2c6c1d76090734917ededaa44a1f7b4c03e14000000006a47304402207811d40f485915e1423d9996d38243958ab4768c96c4a8046261e57ae058c7f602203ad4371113afbd43cb805e39a90796c1bbad38054a856c5b9db9477542dfe140012103a5acc1412252845944273732db657873b8241d005cdc8b7133636b4399d45b51feffffff5f1f05631f86f928fee1885b4c601f647305acaab8638e9419221b13291f1222010000006a47304402200dedf8c4f423ad6a5ba54aad47d7da0d6a89d5ebf8106a5725a1d54508c3ee4502203ca16b0c2d6fc903ba8e678c9634d31b4edf8be5b31103e7e7464b6784dc7b830121025c0fa32e88a54b3b57d8043f508bc58bcd0db113900b1c38e4e641e7bdf69837fdffffff015ca12705000000001976a9146285651ee6abb6788c39df4ecb89f97345cbfa2588ac00000000" + }, + { + "txid": "22121f29131b2219948e63b8aaac0573641f604c5b88e1fe28f9861f63051f5f", + "version": 1, + "vin": [ + { + "txid": "1c5aea829cb18e507d3a1eccb99db5744a9ff086ed87cc97d696231954ce7635", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "Qf2dViTrEcWm7CawDDoDduzBrgRL3DnFWH" + ], + "isAddress": true, + "value": "89780102", + "hex": "483045022100d97be84585f063ebf9faf117728255db551c75e87c0d570cfd2fbd2ea47c969102200b50b8c4367981de9b26fb84b757ef88b40976b1a4ad0c1a54d58e67fa575200012102e75ea870219ec7bd72ea790e85459f367c11d82f7cffd72fdcd41943adb56817" + } + ], + "vout": [ + { + "value": "12555500", + "n": 0, + "spent": true, + "hex": "76a9146285651ee6abb6788c39df4ecb89f97345cbfa2588ac", + "addresses": [ + "QVav8YbUUwQq6yFCrkafW79Uv3NUMHT66n" + ], + "isAddress": true + }, + { + "value": "77004930", + "n": 1, + "spent": true, + "hex": "76a914ed2e633dc9806a955b0f637d682c5629ceaa2e8988ac", + "addresses": [ + "QiE5pqKaWD6KuKJG1XqqaSuKscqw68WPDj" + ], + "isAddress": true + } + ], + "blockHash": "7bf6daddf9d2fa6c0c57fc4b2e7696ccfefc65d5f6d52a4d5dba4741bdcb762b", + "blockHeight": 369490, + "confirmations": 238047, + "blockTime": 1557443008, + "value": "89560430", + "valueIn": "89780102", + "fees": "219672", + "hex": "01000000013576ce54192396d697cc87ed86f09f4a74b59db9cc1e3a7d508eb19c82ea5a1c010000006b483045022100d97be84585f063ebf9faf117728255db551c75e87c0d570cfd2fbd2ea47c969102200b50b8c4367981de9b26fb84b757ef88b40976b1a4ad0c1a54d58e67fa575200012102e75ea870219ec7bd72ea790e85459f367c11d82f7cffd72fdcd41943adb56817feffffff02ec94bf00000000001976a9146285651ee6abb6788c39df4ecb89f97345cbfa2588ac82009704000000001976a914ed2e633dc9806a955b0f637d682c5629ceaa2e8988ac00000000" + }, + { + "txid": "143ec0b4f7a144aaeded1749739060d7c1c6d21ff463ea4fef95df357946adf6", + "version": 1, + "vin": [ + { + "txid": "1c5aea829cb18e507d3a1eccb99db5744a9ff086ed87cc97d696231954ce7635", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QVav8YbUUwQq6yFCrkafW79Uv3NUMHT66n" + ], + "isAddress": true, + "value": "10000000", + "hex": "473044022043e99b1a4859135e6a9e4e03e239036a3724711e8e525872ba2679a3af864b80022004aefa4b0412126418080098baa5207b2b2c31b9c0086f495dc35f870e466cc10121023608e446e04c777b55ce0253a99d90d8c6902dab7f37b0b2e29b507849259e74" + } + ], + "vout": [ + { + "value": "9780554", + "n": 0, + "spent": true, + "hex": "76a914c3f89deaed494671b8be39cf3f0dfb90f9906ee588ac", + "addresses": [ + "QeUBhueTQt35s4BMRWvPcX3RCguSe2Ghf1" + ], + "isAddress": true + } + ], + "blockHash": "b64d9b0074e95e0aeecf4ef6b844b57bbdbe2a2fe9d0587606aaf4ba065f04e0", + "blockHeight": 369485, + "confirmations": 238052, + "blockTime": 1557441920, + "value": "9780554", + "valueIn": "10000000", + "fees": "219446", + "hex": "01000000013576ce54192396d697cc87ed86f09f4a74b59db9cc1e3a7d508eb19c82ea5a1c000000006a473044022043e99b1a4859135e6a9e4e03e239036a3724711e8e525872ba2679a3af864b80022004aefa4b0412126418080098baa5207b2b2c31b9c0086f495dc35f870e466cc10121023608e446e04c777b55ce0253a99d90d8c6902dab7f37b0b2e29b507849259e74feffffff014a3d9500000000001976a914c3f89deaed494671b8be39cf3f0dfb90f9906ee588ac00000000" + }, + { + "txid": "1c5aea829cb18e507d3a1eccb99db5744a9ff086ed87cc97d696231954ce7635", + "version": 1, + "vin": [ + { + "txid": "f09b2b7577dbf154f2c027ad8f1bb51e4c9917e809856be513e7b8067f6d888e", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true, + "value": "100000000", + "hex": "4730440220009bc2bb9bd0782aa38bfb3e9093d49fdfb31e4067a956adad2f888e9438e06b02206d7c5d60afffdb3685fced33d24ba9a6466a35b3aa933e4b1ffdd6ba8d23d57901210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "76a9146285651ee6abb6788c39df4ecb89f97345cbfa2588ac", + "addresses": [ + "QVav8YbUUwQq6yFCrkafW79Uv3NUMHT66n" + ], + "isAddress": true + }, + { + "value": "89780102", + "n": 1, + "spent": true, + "hex": "76a914ca1b74b3ae2a8e655487e131dbb820717c20610e88ac", + "addresses": [ + "Qf2dViTrEcWm7CawDDoDduzBrgRL3DnFWH" + ], + "isAddress": true + } + ], + "blockHash": "d61a1de7b586fee13bc44cd3ae0fa0392d6d9d75d7d3c7273481dfa2069eb9ab", + "blockHeight": 369474, + "confirmations": 238063, + "blockTime": 1557440448, + "value": "99780102", + "valueIn": "100000000", + "fees": "219898", + "hex": "01000000018e886d7f06b8e713e56b8509e817994c1eb51b8fad27c0f254f1db77752b9bf0000000006a4730440220009bc2bb9bd0782aa38bfb3e9093d49fdfb31e4067a956adad2f888e9438e06b02206d7c5d60afffdb3685fced33d24ba9a6466a35b3aa933e4b1ffdd6ba8d23d57901210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764feffffff0280969800000000001976a9146285651ee6abb6788c39df4ecb89f97345cbfa2588ac86ef5905000000001976a914ca1b74b3ae2a8e655487e131dbb820717c20610e88ac00000000" + }, + { + "txid": "f09b2b7577dbf154f2c027ad8f1bb51e4c9917e809856be513e7b8067f6d888e", + "version": 1, + "vin": [ + { + "txid": "3600156226ed9f04379dcf72795542d9b4de9d88b374b82b825497ff92e52830", + "vout": 1, + "n": 0, + "addresses": [ + "QUN6caK4ZEPLEoA3ZMC2oSR2kf6RCfGA9B" + ], + "isAddress": true, + "value": "109000000", + "hex": "483045022100cf97578c211296f9e3aa8e7718c7ec4a6fc240b46c29216f664fd68fdd81ec5202201a27971ba5e52b758a8295c870f037a67f20aab306a264e6249dd4f61705634401210360e37f3d88db15a76ffdb30179fc3a67e0fa320e8c6a82bbd93a8e40af30d963" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", + "addresses": [ + "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" + ], + "isAddress": true + }, + { + "value": "8789820", + "n": 1, + "spent": true, + "hex": "76a91406ee9fbb22cc53a5190b0eddf26ed33d66a6ebfa88ac", + "addresses": [ + "QMEe2LEsZRLjf4UNuxkgMBHwkMB2zJuWjo" + ], + "isAddress": true + } + ], + "blockHash": "c23063e7715537c96898e8fe956bc45c98e0fb17c415ebdbbbb78f3ba8106494", + "blockHeight": 367729, + "confirmations": 239808, + "blockTime": 1557190080, + "value": "108789820", + "valueIn": "109000000", + "fees": "210180", + "hex": "01000000013028e592ff9754822bb874b3889ddeb4d942557972cf9d37049fed2662150036010000006b483045022100cf97578c211296f9e3aa8e7718c7ec4a6fc240b46c29216f664fd68fdd81ec5202201a27971ba5e52b758a8295c870f037a67f20aab306a264e6249dd4f61705634401210360e37f3d88db15a76ffdb30179fc3a67e0fa320e8c6a82bbd93a8e40af30d963000000000200e1f505000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac3c1f8600000000001976a91406ee9fbb22cc53a5190b0eddf26ed33d66a6ebfa88ac00000000" + } + ], + "usedTokens": 33, + "tokens": [ + { + "type": "XPUBAddress", + "name": "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", + "path": "m/44'/2301'/0'/0/0", + "transfers": 6, + "decimals": 8, + "balance": "234243932", + "totalReceived": "43569601542", + "totalSent": "43335357610" + } + ] +} diff --git a/mock/ext-api-data/ravencoin-api_v2_address_RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo__details_txs.json b/mock/ext-api-data/ravencoin-api_v2_address_RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo__details_txs.json new file mode 100644 index 000000000..a80745d3a --- /dev/null +++ b/mock/ext-api-data/ravencoin-api_v2_address_RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo__details_txs.json @@ -0,0 +1,110 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo", + "balance": "0", + "totalReceived": "8525568094", + "totalSent": "8525568094", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 2, + "transactions": [ + { + "txid": "fc226aad6fc28e1204b747042e8c8b25f5d28424b9669bd162ba6a0149df2f71", + "version": 2, + "lockTime": 1201754, + "vin": [ + { + "txid": "1222cb57d31bfb439e94080266c33ebb0134cdb90999a9fad99455d09a15159b", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo" + ], + "isAddress": true, + "value": "8525568094", + "hex": "483045022100dc56832c815e7294dd51c7bb1ba342af80f5d25c3bc44c9689a55ccd94d18d01022063d3420930736fb1c1ab9a851ec0d1ff01dc906c66685b35972e3ab26b2d5d040121032dd4ba9d193e1912a6b48bd5642cb3579415ebabfc61e9fec9690fcd466dea15" + } + ], + "vout": [ + { + "value": "78460623", + "n": 0, + "spent": true, + "hex": "76a9141657456724a83ca9e4c4cc0b65c98b6ffdba5bae88ac", + "addresses": [ + "RBKKVSR79YjBSGBE5pymUCaa871qogE5aY" + ], + "isAddress": true + }, + { + "value": "8446853390", + "n": 1, + "spent": true, + "hex": "76a9142e664ae2c04d6292d50bcd65b644553eea7d7f1388ac", + "addresses": [ + "RDWXhkQyUkgmumGbzdR6JetLChVzUbStRq" + ], + "isAddress": true + } + ], + "blockHash": "000000000000244f2e3f48b9c6767465d0611995047368a06fbc28bde79d8ec6", + "blockHeight": 1201755, + "confirmations": 28073, + "blockTime": 1587702273, + "value": "8525314013", + "valueIn": "8525568094", + "fees": "254081", + "hex": "02000000019b15159ad05594d9faa99909b9cd3401bb3ec3660208949e43fb1bd357cb2212000000006b483045022100dc56832c815e7294dd51c7bb1ba342af80f5d25c3bc44c9689a55ccd94d18d01022063d3420930736fb1c1ab9a851ec0d1ff01dc906c66685b35972e3ab26b2d5d040121032dd4ba9d193e1912a6b48bd5642cb3579415ebabfc61e9fec9690fcd466dea15feffffff02cf36ad04000000001976a9141657456724a83ca9e4c4cc0b65c98b6ffdba5bae88ac0ec178f7010000001976a9142e664ae2c04d6292d50bcd65b644553eea7d7f1388ac5a561200" + }, + { + "txid": "1222cb57d31bfb439e94080266c33ebb0134cdb90999a9fad99455d09a15159b", + "version": 2, + "lockTime": 1201750, + "vin": [ + { + "txid": "003d748c2c3541535093e840b4c5e54b966915eb522bac06028bc8d1376e1e63", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "R9kyoRBmiF89o5ACFXF4EY7GawGjURP1Z5" + ], + "isAddress": true, + "value": "8530842427", + "hex": "47304402207ea927cfb1c7d8e14b067aa5b892cfde8b7b96b8bd95866b906c13e168581fd20220423bee1c4e25f66cc5ac27d94a33540307edb2a9a8874e800a1e1f875194dabf012103ded5613a24b22a8dc0c416f3ac4b436372a5b581b42e2d45f00fbd042cb066f1" + } + ], + "vout": [ + { + "value": "8525568094", + "n": 0, + "spent": true, + "hex": "76a9145208b754b23169797a19e0ffaa9041ab5e29b9ef88ac", + "addresses": [ + "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo" + ], + "isAddress": true + }, + { + "value": "5020252", + "n": 1, + "spent": true, + "hex": "76a914bb7590eef377d63adcda0d080073035ad9a86bfc88ac", + "addresses": [ + "RSNPH2YPN69PNRj6BYq4V3orCyC7nahG9R" + ], + "isAddress": true + } + ], + "blockHash": "00000000000003efc9fb9dd4d5deb4e6ca393266191771d5d2e2426a191e69b3", + "blockHeight": 1201752, + "confirmations": 28076, + "blockTime": 1587701825, + "value": "8530588346", + "valueIn": "8530842427", + "fees": "254081", + "hex": "0200000001631e6e37d1c88b0206ac2b52eb1569964be5c5b440e893505341352c8c743d00000000006a47304402207ea927cfb1c7d8e14b067aa5b892cfde8b7b96b8bd95866b906c13e168581fd20220423bee1c4e25f66cc5ac27d94a33540307edb2a9a8874e800a1e1f875194dabf012103ded5613a24b22a8dc0c416f3ac4b436372a5b581b42e2d45f00fbd042cb066f1feffffff025ed829fc010000001976a9145208b754b23169797a19e0ffaa9041ab5e29b9ef88ac5c9a4c00000000001976a914bb7590eef377d63adcda0d080073035ad9a86bfc88ac56561200" + } + ] +} diff --git a/mock/ext-api-data/ravencoin-api_v2_xpub_xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B__details_txs.json b/mock/ext-api-data/ravencoin-api_v2_xpub_xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B__details_txs.json new file mode 100644 index 000000000..a802a4ce7 --- /dev/null +++ b/mock/ext-api-data/ravencoin-api_v2_xpub_xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B__details_txs.json @@ -0,0 +1,393 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B", + "balance": "299445646", + "totalReceived": "2599356720", + "totalSent": "2299911074", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 8, + "transactions": [ + { + "txid": "5d22e5a84b0eb054b623fdc3caf88a60eaa646dc97922f06d325aa8d6f18c564", + "version": 1, + "vin": [ + { + "txid": "baa2ee45ad8b9922a9db3fdcc22f8c3b5257dc81fef609800e7bd138748b6977", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "RHhtrB8eUZuTp8m8HVEyGidEiSkSz5CRdM" + ], + "isAddress": true, + "value": "299456974", + "hex": "47304402204d44f9873e894314746557e4e7ba74e9436d7fa81986d0386684179d8acb77fe02206ff207862b3badbd41cc2ab584ff334410ab2bd089c6c4a1f6ffa59ce2b5d7da012102d34aee6afc67a1b86789beadf0ef2ed7dd5665776b734c0a4dba727bf532bd59" + } + ], + "vout": [ + { + "value": "299445646", + "n": 0, + "hex": "76a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac", + "addresses": [ + "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz" + ], + "isAddress": true + } + ], + "blockHash": "00000000000013c420937088dd9b69e5ef38c2c1e544828d222c1e8998d1358a", + "blockHeight": 843530, + "confirmations": 386298, + "blockTime": 1566071064, + "value": "299445646", + "valueIn": "299456974", + "fees": "11328", + "hex": "010000000177698b7438d17b0e8009f6fe81dc57523b8c2fc2dc3fdba922998bad45eea2ba000000006a47304402204d44f9873e894314746557e4e7ba74e9436d7fa81986d0386684179d8acb77fe02206ff207862b3badbd41cc2ab584ff334410ab2bd089c6c4a1f6ffa59ce2b5d7da012102d34aee6afc67a1b86789beadf0ef2ed7dd5665776b734c0a4dba727bf532bd59feffffff018e2dd911000000001976a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac00000000" + }, + { + "txid": "baa2ee45ad8b9922a9db3fdcc22f8c3b5257dc81fef609800e7bd138748b6977", + "version": 1, + "vin": [ + { + "txid": "0f517fd0d4e86070fdff40e95f5202a1b343f75d3168842feb2e8fd6f1be0ef9", + "n": 0, + "addresses": [ + "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz" + ], + "isAddress": true, + "value": "9990400", + "hex": "483045022100d8e3598c4d8829b39433c43d4a4c3c438754e8fa77284e1de606233b954770f2022034eb8b6ab6ca103f613d14ccc38fc6aea7bc8661dbff87b0c576b4712d202b3a012102ee0d81b0e40adde804683388953c9cef6276703a3d26e65f9f3433dff0b82dba" + }, + { + "txid": "b9db035506eaeb0de0dbc98a277c29f41c08317515538c79cdc542d759918004", + "vout": 1, + "n": 1, + "addresses": [ + "RGG4nwkVgFSpy5wdZVKkKFySUCz8N35B5L" + ], + "isAddress": true, + "value": "89988700", + "hex": "473044022075c8f6c3ce3de19c86bbaa845871e25af82ea40bb3793896e657dccbd350209a022033b983ef8733a74ca8e977e08c4ded3a027a800dedbe8aa65a06bca0dc87d09b012103d66703c2448791bcb6828c060de9c568853aa43a753ed227a1f14d70612d3144" + }, + { + "txid": "44172def2b5f799963adf28f0a3129e6f7910c8bc5ad09ad0e8155da24748d25", + "vout": 1, + "n": 2, + "addresses": [ + "RHj2wiQ8tDhJZKsNKsf48WzxAj2pVnhEnX" + ], + "isAddress": true, + "value": "199965874", + "hex": "4730440220601d4e0d8bc03cf5064dad0316cf61d996ec507aa92105711a0d480a561d9bbb02200acaf5ff2deed01fca255caeaeb63925097bad740adbfd952ab0df66fbfa8552012102eff42496547e74666a392bf8399072dc289ae1d1e835a1c7068650a76be44709" + } + ], + "vout": [ + { + "value": "299456974", + "n": 0, + "spent": true, + "hex": "76a9145c6d05bdca691ab3acfd59ad1a70e55aea1cece388ac", + "addresses": [ + "RHhtrB8eUZuTp8m8HVEyGidEiSkSz5CRdM" + ], + "isAddress": true + } + ], + "blockHash": "0000000000006c4af5eab913f98e03bb3ff45c8b580b88cbeba39b0748ec6f8c", + "blockHeight": 843527, + "confirmations": 386301, + "blockTime": 1566070929, + "value": "299456974", + "valueIn": "299944974", + "fees": "488000", + "hex": "0100000003f90ebef1d68f2eeb2f8468315df743b3a102525fe940fffd7060e8d4d07f510f000000006b483045022100d8e3598c4d8829b39433c43d4a4c3c438754e8fa77284e1de606233b954770f2022034eb8b6ab6ca103f613d14ccc38fc6aea7bc8661dbff87b0c576b4712d202b3a012102ee0d81b0e40adde804683388953c9cef6276703a3d26e65f9f3433dff0b82dba0000000004809159d742c5cd798c53157531081cf4297c278ac9dbe00debea065503dbb9010000006a473044022075c8f6c3ce3de19c86bbaa845871e25af82ea40bb3793896e657dccbd350209a022033b983ef8733a74ca8e977e08c4ded3a027a800dedbe8aa65a06bca0dc87d09b012103d66703c2448791bcb6828c060de9c568853aa43a753ed227a1f14d70612d314400000000258d7424da55810ead09adc58b0c91f7e629310a8ff2ad6399795f2bef2d1744010000006a4730440220601d4e0d8bc03cf5064dad0316cf61d996ec507aa92105711a0d480a561d9bbb02200acaf5ff2deed01fca255caeaeb63925097bad740adbfd952ab0df66fbfa8552012102eff42496547e74666a392bf8399072dc289ae1d1e835a1c7068650a76be447090000000001ce59d911000000001976a9145c6d05bdca691ab3acfd59ad1a70e55aea1cece388ac00000000" + }, + { + "txid": "0f517fd0d4e86070fdff40e95f5202a1b343f75d3168842feb2e8fd6f1be0ef9", + "version": 1, + "vin": [ + { + "txid": "b9db035506eaeb0de0dbc98a277c29f41c08317515538c79cdc542d759918004", + "n": 0, + "addresses": [ + "RArA49JQFoQZPZRUJqbnE6tp8fVRmAp8v7" + ], + "isAddress": true, + "value": "10000000", + "hex": "4830450221009370c852500b17d02ad9cc2f539a7b56fa237ccd108ec39b2e914fa9fdcde95e02203a730d6431a5e4ada7580644f0fc68ec57fc4e3519d8656e70790239bf12e6b501210214632a2120dc88ae7624ccb3e63534ae3c1d84aefe9f1b72ee23ba9876e3cbc6" + } + ], + "vout": [ + { + "value": "9990400", + "n": 0, + "spent": true, + "hex": "76a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac", + "addresses": [ + "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz" + ], + "isAddress": true + } + ], + "blockHash": "00000000000060b0a773ca5f98d4dfdfab1610d62c85f367aee85768852ba5f6", + "blockHeight": 741026, + "confirmations": 488802, + "blockTime": 1559880464, + "value": "9990400", + "valueIn": "10000000", + "fees": "9600", + "hex": "010000000104809159d742c5cd798c53157531081cf4297c278ac9dbe00debea065503dbb9000000006b4830450221009370c852500b17d02ad9cc2f539a7b56fa237ccd108ec39b2e914fa9fdcde95e02203a730d6431a5e4ada7580644f0fc68ec57fc4e3519d8656e70790239bf12e6b501210214632a2120dc88ae7624ccb3e63534ae3c1d84aefe9f1b72ee23ba9876e3cbc6000000000100719800000000001976a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac00000000" + }, + { + "txid": "b9db035506eaeb0de0dbc98a277c29f41c08317515538c79cdc542d759918004", + "version": 1, + "vin": [ + { + "txid": "10fb44c72200ff042b545c29969ca85943f55e33897823580a19b40fc10159f4", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "RG5LjQjL9GWjYoAQSQQVwoLeErG1UZMP3h" + ], + "isAddress": true, + "value": "100000000", + "hex": "473044022013aa396845c905d35d5f8cbd404c51f5246cd529e36ac15a723dbdd1058683dd02201d7f6fd12afc6284cca0d94dcea0606b5c1dc8121c40daed9192e0487baf161a012103041042bb05c5baa1e3783999835a37625403f9cbb89ec91fd643b9ffdfe03f3f" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "76a914113429cb4f5bd3d5825e1d521ae7cde85c9d21e188ac", + "addresses": [ + "RArA49JQFoQZPZRUJqbnE6tp8fVRmAp8v7" + ], + "isAddress": true + }, + { + "value": "89988700", + "n": 1, + "spent": true, + "hex": "76a9144c9261f9db4a82b622a7233feeb8058b738fb77088ac", + "addresses": [ + "RGG4nwkVgFSpy5wdZVKkKFySUCz8N35B5L" + ], + "isAddress": true + } + ], + "blockHash": "00000000000012c02a6248d62b3f0c0a99ed28db6be7e8b6618148b59562900f", + "blockHeight": 741022, + "confirmations": 488806, + "blockTime": 1559880370, + "value": "99988700", + "valueIn": "100000000", + "fees": "11300", + "hex": "0100000001f45901c10fb4190a58237889335ef54359a89c96295c542b04ff0022c744fb10000000006a473044022013aa396845c905d35d5f8cbd404c51f5246cd529e36ac15a723dbdd1058683dd02201d7f6fd12afc6284cca0d94dcea0606b5c1dc8121c40daed9192e0487baf161a012103041042bb05c5baa1e3783999835a37625403f9cbb89ec91fd643b9ffdfe03f3ffeffffff0280969800000000001976a914113429cb4f5bd3d5825e1d521ae7cde85c9d21e188ac5c1e5d05000000001976a9144c9261f9db4a82b622a7233feeb8058b738fb77088ac00000000" + }, + { + "txid": "44172def2b5f799963adf28f0a3129e6f7910c8bc5ad09ad0e8155da24748d25", + "version": 1, + "vin": [ + { + "txid": "10fb44c72200ff042b545c29969ca85943f55e33897823580a19b40fc10159f4", + "vout": 1, + "n": 0, + "addresses": [ + "R9in1jQ6JzYZSQABXnD5fr4xtEp5FpjnMr" + ], + "isAddress": true, + "value": "399977400", + "hex": "483045022100c104df759924b7e90a4c82f4767bd6667f10f86e9a88027832acab3b926fe764022021e1b3847b7951c3139c18d23d24f17385ac5a43c48ede235981f59c6cd45ccd01210390b9600abc44b0ce8a33f89f9d52d95aa472b3933000489fd53c12fb6dc82239" + } + ], + "vout": [ + { + "value": "200000000", + "n": 0, + "spent": true, + "hex": "76a91493a42b17108b467ca6d63171b3c8d1bd58f0989888ac", + "addresses": [ + "RNjr5L6TqoyiwBQp7kYFr4Yk5AsC8kkS6p" + ], + "isAddress": true + }, + { + "value": "199965874", + "n": 1, + "spent": true, + "hex": "76a9145ca432386ab4cf862f9b87f32fb334149e1ba40088ac", + "addresses": [ + "RHj2wiQ8tDhJZKsNKsf48WzxAj2pVnhEnX" + ], + "isAddress": true + } + ], + "blockHash": "0000000000003c4fb53bc5f505be6266d00ec058e15a3a0b6e24cacf5664622d", + "blockHeight": 739791, + "confirmations": 490037, + "blockTime": 1559805482, + "value": "399965874", + "valueIn": "399977400", + "fees": "11526", + "hex": "0100000001f45901c10fb4190a58237889335ef54359a89c96295c542b04ff0022c744fb10010000006b483045022100c104df759924b7e90a4c82f4767bd6667f10f86e9a88027832acab3b926fe764022021e1b3847b7951c3139c18d23d24f17385ac5a43c48ede235981f59c6cd45ccd01210390b9600abc44b0ce8a33f89f9d52d95aa472b3933000489fd53c12fb6dc82239000000000200c2eb0b000000001976a91493a42b17108b467ca6d63171b3c8d1bd58f0989888acb23ceb0b000000001976a9145ca432386ab4cf862f9b87f32fb334149e1ba40088ac00000000" + }, + { + "txid": "10fb44c72200ff042b545c29969ca85943f55e33897823580a19b40fc10159f4", + "version": 1, + "vin": [ + { + "txid": "9490bbc470862a5d8cd7f7c6c83a0cd4516d124a54b169f5d9f4e5ad6b2f05e7", + "vout": 1, + "n": 0, + "addresses": [ + "RQu6oko5Laega15FQSfhYTFAQPdWJt7MAg" + ], + "isAddress": true, + "value": "499988700", + "hex": "47304402205e63f89393bc37cab8c82b3f1bfece7b1e15a21a569bb2862db0b5d9ce5eddc3022075d1ba913743f309e8c4278155aabab48b2edd6f28ba78205b56695cb248330d01210272f8247a32b3a8d50d502a7a484132509480d6ca180305f541042d815f1949c8" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a9144a8b1cc5b6b4c61a66e29cdc4732d757f8b0b7c188ac", + "addresses": [ + "RG5LjQjL9GWjYoAQSQQVwoLeErG1UZMP3h" + ], + "isAddress": true + }, + { + "value": "399977400", + "n": 1, + "spent": true, + "hex": "76a91404d6b9f2268317e71889161c9f7430824b753e0e88ac", + "addresses": [ + "R9in1jQ6JzYZSQABXnD5fr4xtEp5FpjnMr" + ], + "isAddress": true + } + ], + "blockHash": "00000000000056a3b549a9e967d9a19af10e0a0227c2e33b3b087c18a6119049", + "blockHeight": 739591, + "confirmations": 490237, + "blockTime": 1559793642, + "value": "499977400", + "valueIn": "499988700", + "fees": "11300", + "hex": "0100000001e7052f6bade5f4d9f569b1544a126d51d40c3ac8c6f7d78c5d2a8670c4bb9094010000006a47304402205e63f89393bc37cab8c82b3f1bfece7b1e15a21a569bb2862db0b5d9ce5eddc3022075d1ba913743f309e8c4278155aabab48b2edd6f28ba78205b56695cb248330d01210272f8247a32b3a8d50d502a7a484132509480d6ca180305f541042d815f1949c8000000000200e1f505000000001976a9144a8b1cc5b6b4c61a66e29cdc4732d757f8b0b7c188acb82bd717000000001976a91404d6b9f2268317e71889161c9f7430824b753e0e88ac00000000" + }, + { + "txid": "9490bbc470862a5d8cd7f7c6c83a0cd4516d124a54b169f5d9f4e5ad6b2f05e7", + "version": 1, + "vin": [ + { + "txid": "3abc0a2a29dc20cbf828a5de9f7cb64f3343456efe257af9557a4365be279924", + "vout": 1, + "n": 0, + "addresses": [ + "RVG4EpTdouq8ui29pgrAAYfWYtzC5Gzn8h" + ], + "isAddress": true, + "value": "1000000000", + "hex": "473044022045d0fb08baa997552568132bc448854714bc2727a7e03d86eb96161cc83096f20220097e682ee7400b634a0f469a7d9450ce5d382e72aaf2ec0003fd362112f1c08b0121026c437d2701fdb8120793e23898b28eff9d0173413626b48970a2ad620beaf737" + } + ], + "vout": [ + { + "value": "500000000", + "n": 0, + "hex": "76a914e2f5abd0a8de78fd4c3ac1e363be073cd87a1a5b88ac", + "addresses": [ + "RVyF6QC7XYqEP4ZThVowJGeZg5Q5p683nV" + ], + "isAddress": true + }, + { + "value": "499988700", + "n": 1, + "spent": true, + "hex": "76a914ab5475f4b0dc2ebf15f4ba2c0371ed1a8f05285488ac", + "addresses": [ + "RQu6oko5Laega15FQSfhYTFAQPdWJt7MAg" + ], + "isAddress": true + } + ], + "blockHash": "0000000000002943f769a119d1095ccd49738e9036a17e0bea19ab052f8a00b2", + "blockHeight": 737804, + "confirmations": 492024, + "blockTime": 1559685656, + "value": "999988700", + "valueIn": "1000000000", + "fees": "11300", + "hex": "0100000001249927be65437a55f97a25fe6e4543334fb67c9fdea528f8cb20dc292a0abc3a010000006a473044022045d0fb08baa997552568132bc448854714bc2727a7e03d86eb96161cc83096f20220097e682ee7400b634a0f469a7d9450ce5d382e72aaf2ec0003fd362112f1c08b0121026c437d2701fdb8120793e23898b28eff9d0173413626b48970a2ad620beaf73700000000020065cd1d000000001976a914e2f5abd0a8de78fd4c3ac1e363be073cd87a1a5b88acdc38cd1d000000001976a914ab5475f4b0dc2ebf15f4ba2c0371ed1a8f05285488ac00000000" + }, + { + "txid": "3abc0a2a29dc20cbf828a5de9f7cb64f3343456efe257af9557a4365be279924", + "version": 2, + "lockTime": 737700, + "vin": [ + { + "txid": "5f0f926ff2ee476c68b4446050605417c138477492efc58ce98988691b209906", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "RVyF6QC7XYqEP4ZThVowJGeZg5Q5p683nV" + ], + "isAddress": true, + "value": "75499982022", + "hex": "483045022100a051cb8c2115b357d3bcbc2c067f841950024b6d029f5db596ea3d7978decf5d0220311088ae96aee032bd569c43582f31567dd419dd4f52ee5681c6b109e4184cb0012103176b9b14d363adf505b5e88f3682e966bab243c7ddc142d627ba4da5b7b43f40" + } + ], + "vout": [ + { + "value": "74499965072", + "n": 0, + "spent": true, + "hex": "76a914360823f5332cc0e0e963b0cefc81177fe1d1c9e288ac", + "addresses": [ + "RECtKV2R2Fm23UK252pxaHD1tPrzpSdiLN" + ], + "isAddress": true + }, + { + "value": "1000000000", + "n": 1, + "spent": true, + "hex": "76a914db2b8e380a550bc0fc4f0274b2421e1483f5305388ac", + "addresses": [ + "RVG4EpTdouq8ui29pgrAAYfWYtzC5Gzn8h" + ], + "isAddress": true + } + ], + "blockHash": "00000000000010983316addc1b38cbb32d7e31e85861b8cfdee7fd9e222f4c29", + "blockHeight": 737702, + "confirmations": 492126, + "blockTime": 1559679617, + "value": "75499965072", + "valueIn": "75499982022", + "fees": "16950", + "hex": "02000000010699201b698889e98cc5ef92744738c1175460506044b4686c47eef26f920f5f010000006b483045022100a051cb8c2115b357d3bcbc2c067f841950024b6d029f5db596ea3d7978decf5d0220311088ae96aee032bd569c43582f31567dd419dd4f52ee5681c6b109e4184cb0012103176b9b14d363adf505b5e88f3682e966bab243c7ddc142d627ba4da5b7b43f40feffffff0290408b58110000001976a914360823f5332cc0e0e963b0cefc81177fe1d1c9e288ac00ca9a3b000000001976a914db2b8e380a550bc0fc4f0274b2421e1483f5305388aca4410b00" + } + ], + "usedTokens": 7, + "tokens": [ + { + "type": "XPUBAddress", + "name": "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz", + "path": "m/44'/175'/0'/0/2", + "transfers": 3, + "decimals": 8, + "balance": "299445646", + "totalReceived": "309436046", + "totalSent": "9990400" + } + ] +} diff --git a/mock/ext-api-data/ripple-api_accounts_rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1_transactions__descending_false_limit_25_type_Payment.json b/mock/ext-api-data/ripple-api_accounts_rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1_transactions__descending_false_limit_25_type_Payment.json new file mode 100644 index 000000000..0ad523398 --- /dev/null +++ b/mock/ext-api-data/ripple-api_accounts_rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1_transactions__descending_false_limit_25_type_Payment.json @@ -0,0 +1,1977 @@ +{ + "result": "success", + "count": 23, + "transactions": [ + { + "hash": "40279A3DE51148BD41409DADF29DE8DCCD50F5AEE30840827B2C4C81C4E36505", + "ledger_index": 34698103, + "date": "2017-12-01T22:45:30+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 21, + "LastLedgerSequence": 34698105, + "Amount": "100000000", + "Fee": "3115", + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100D14057AA2A868F54FC7CA2E44C8310D9A944446580EAA45936A75CFFDD00425602205CCBFACB55AB0F5B02659F1EBE619FC04DE75B0227C8EB148DC6D08CABBAB072", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Memos": [ + { + "Memo": { + "MemoType": "636C69656E74", + "MemoFormat": "7274312E342E332D31332D6735383261336135" + } + } + ] + }, + "meta": { + "TransactionIndex": 20, + "AffectedNodes": [ + { + "CreatedNode": { + "LedgerEntryType": "AccountRoot", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "NewFields": { + "Sequence": 1, + "Balance": "100000000", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34698098, + "PreviousTxnID": "7040A099F51E0DC386B909FB4C01DCCF23CB61D3D05B0EC562C01359FB60C754", + "LedgerIndex": "D242D4E3501E5829AB003BA788CF361D4717419D9653304E556A14C6166847E8", + "PreviousFields": { + "Sequence": 21, + "Balance": "1999935364" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 22, + "OwnerCount": 0, + "Balance": "1899932249", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "100000000" + } + }, + { + "hash": "89BB38F93A332F89A22B0DDFE2373FB66F904F564D4EEA3EAB79EA2CCD142DE0", + "ledger_index": 34801077, + "date": "2017-12-05T22:24:42+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 2, + "LastLedgerSequence": 34850332, + "Amount": "2000000", + "Fee": "5000", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "r4MoybfgCHDoUByYyMejimaX6a8CEtWtav", + "Signers": [ + { + "Signer": { + "SigningPubKey": "0320ECD5569CAFA4E23147BE238DBFB268DB3B5A502ED339387AC7DCA0ADC6FB90", + "TxnSignature": "30440220530CEB333AB1F3D03D2BDE957D769CD764C20A4AE6D31F4FDDD9F7E6447E65E902202FDEAC35D24C94BE3F4FDF1705535D1BBCA49E3B3409EE2F44BCDD72CDE66689", + "Account": "re3LGjhrCvthtWWwrfKbVJjXN9PYDeQDJ" + } + }, + { + "Signer": { + "SigningPubKey": "03E51671887C1DE935B5F48DA56EB0A460678FF14E197A1142861150EAEEF6F56D", + "TxnSignature": "304402205232E208689892834FD2409EA4532D8AACF29BD24099470A32A71A544489BE17022034C91DE535FD9CB971EADC701EE6DC17474CD4C67C462B795C19B514FB70517E", + "Account": "rkPA5RwLVPnJgpcsrzYvHwx1HVfDb6zD3" + } + }, + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100CE4727E645B359E15B8AFBDFB9123DCECDDC83C95CDB033CDB8A4BC97EB8C92102207610F3E01D4C08880C6269282CA162360F23BAD5860BBDC9B82BCA478DC6B0A5", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "02259BC18378FD3C99B92C4A41ABA65B62333980DDF28F1F60EF8EF0B5CE7AD93D", + "TxnSignature": "3045022100F87262FA9D04A71349C731C938DB07DE9E7BE6B644B9B57A954A5165F8BC473A02206642A14066965FC99EBB362D0A95C008E49BD5EAC3FCC8151E2F70866002C773", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + } + ] + }, + "meta": { + "TransactionIndex": 5, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34747555, + "PreviousTxnID": "0B3A832DC409E51D53651839C89A05CF52293F83A0E431820C71575C390522E1", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 2, + "Balance": "99999000" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 3, + "OwnerCount": 10, + "Balance": "97994000", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34747567, + "PreviousTxnID": "6E26453E4AB713B55DD6EFC69D38D02D1433B54E3D2D5B9FF0EB936FAAA538DB", + "LedgerIndex": "FEBE44D92D1D8AED643BDCC2BF821581A986E99DA3B79EADAEDB69485139FE6A", + "PreviousFields": { + "Balance": "99999000" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 2, + "OwnerCount": 10, + "Balance": "101999000", + "Account": "r4MoybfgCHDoUByYyMejimaX6a8CEtWtav" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "2000000" + } + }, + { + "hash": "BB94F2DD534A1B15B4D2B9E74FF08E09F577252EC1C4B6CCFB277280BDB5ED82", + "ledger_index": 34801321, + "date": "2017-12-05T22:38:50+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 2, + "LastLedgerSequence": 34850325, + "Amount": "2000000", + "Fee": "5000", + "SigningPubKey": "", + "Account": "rMhkqz3DeU7GUUJKGZofusbrTwZe6bDyb1", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Signers": [ + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100B66CB56AD3BACD2C7C3FBDC73BCC4745E7980FF4CF3716EDECF3C6DE5F671F2F0220576676FFAE610289645E9264F60608A32D6B352F84056EA1505FE378BA8E8FF0", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "02259BC18378FD3C99B92C4A41ABA65B62333980DDF28F1F60EF8EF0B5CE7AD93D", + "TxnSignature": "30440220108F386906930DE078810A36A84D8EF454A9C06ED97652A17E2708543E453ABC0220697642287225A17A697E3958A51DB939D6EEC25C9E4AEC523EB1753FA68244C8", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + }, + { + "Signer": { + "SigningPubKey": "02FA11725F6F4E28C2E1617CC60C3A43161270A6B0C8B8DAB68265E7CFC27E0E4A", + "TxnSignature": "3044022022BFED134FA36E16A3FA2A11919F6D902B6FB9E9CE97CD8208EEBFB9AA7B25DB022076F470946D630A5C167696F57E6443E92DA259C3958D9452CDBB303F3F749559", + "Account": "rLW75SfEdnGVsa3fTFkSaDTzXuFapwNYtf" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "30440220427F5DCE2F3E5C30605AE5414FE9CBC48C82EFF27BB1236EFEC8FFACF8287F730220797C738418785FE3C9D0BEAC43DDC9D762707198E0D267B16E64BB6D3F81D93D", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + } + ] + }, + "meta": { + "TransactionIndex": 35, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34801077, + "PreviousTxnID": "89BB38F93A332F89A22B0DDFE2373FB66F904F564D4EEA3EAB79EA2CCD142DE0", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Balance": "97994000" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 3, + "OwnerCount": 10, + "Balance": "99994000", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34801295, + "PreviousTxnID": "5994761CBFD0B4E393FBC3169DFBA916C622EF755E9BD03EB404383688F2E859", + "LedgerIndex": "973C8CBC506C0AA2860EC4C1BD32D7BE2BB32FDD011160147797AA1BA0D79AD2", + "PreviousFields": { + "Sequence": 2, + "Balance": "101999000" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 3, + "OwnerCount": 10, + "Balance": "99994000", + "Account": "rMhkqz3DeU7GUUJKGZofusbrTwZe6bDyb1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "2000000" + } + }, + { + "hash": "ED6B5936B5A2A1262E6A4DAE0AFB03974225D4BDED9711E270BBDB47D0B8249F", + "ledger_index": 34854791, + "date": "2017-12-08T00:44:11+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 2, + "LastLedgerSequence": 34854794, + "Amount": "5935129579981200", + "Fee": "12", + "SigningPubKey": "02845A18021ACCA975FCA9CAAFE6FFD984E89920B21E0CC62101EBC899D7136B11", + "TxnSignature": "304402205A88126CCD486C0A248D0E2124542C507E773119E7D96D918E2BFB9A620217DD022045B5EC2D99DCCEC5727B24B7E724002970C9516B3C38D5644D1FEC16196DD4EC", + "Account": "rLj2CTJC8xPzCRPD2ymPbq2t1BDLj79hd4", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Memos": [ + { + "Memo": { + "MemoType": "636C69656E74", + "MemoFormat": "7274312E342E332D31332D6735383261336135" + } + } + ] + }, + "meta": { + "TransactionIndex": 13, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34823711, + "PreviousTxnID": "C85812AB8A17DEE78DA6A47DF7DBD2ACDEC1E35467AFD5AEEA0D572D91342158", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Balance": "99993000" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 4, + "OwnerCount": 10, + "Balance": "5935129679974200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34854778, + "PreviousTxnID": "65F95B73BC08A63E003417D9D42AB4E4A6E0E98FB4C4D92DA02EDB246F1DEDCB", + "LedgerIndex": "65515504E366E1A8C7A4E1DDAB03ADB015328166B443B62ADCEB8A662F816D7F", + "PreviousFields": { + "Sequence": 2, + "Balance": "5935129600973791" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 3, + "OwnerCount": 0, + "Balance": "20992579", + "Account": "rLj2CTJC8xPzCRPD2ymPbq2t1BDLj79hd4" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "5935129579981200" + } + }, + { + "hash": "E1094E64564CC70D2B4B0D3F6E0DC3C101E929FBD16E8F508FCBE2E41EF09495", + "ledger_index": 34948434, + "date": "2017-12-11T16:17:30+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 4, + "LastLedgerSequence": 34980940, + "Amount": "100000000000000", + "Fee": "5000", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rBg2FuZT91C52Nny68houguJ4vt5x1o91m", + "Signers": [ + { + "Signer": { + "SigningPubKey": "0320ECD5569CAFA4E23147BE238DBFB268DB3B5A502ED339387AC7DCA0ADC6FB90", + "TxnSignature": "304402205E1E8CF7021500849FAF97295ADBB329FF2ADDFC6FDABF0983B50A70585416740220365A8C9BBECA2B5DC1C7E9020364396B93731117BBE208BFC2CFA1239B6D4232", + "Account": "re3LGjhrCvthtWWwrfKbVJjXN9PYDeQDJ" + } + }, + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "304402204D32B8B2C3122F3DE3AD7381C862527965D970DED74769EE77011FFADE22724302205F8898582A227A98A4EBD3A4D042E84258FD74B641B6FB71742E9C54592FA77B", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "02FA11725F6F4E28C2E1617CC60C3A43161270A6B0C8B8DAB68265E7CFC27E0E4A", + "TxnSignature": "304402200EBC30457CC1315EC2031F1C4CF079E7ECE57911241DF370E568C1F4B68D834102207026BEF17503ADF13DC4360A9F4B0D3BDCDA9DAF9FCD654E2FDBE6F772A905F8", + "Account": "rLW75SfEdnGVsa3fTFkSaDTzXuFapwNYtf" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "304502210083EDE50767AEBF460F974B883D394BC9E29609ED52E5383FCBCB16FC3B6FFFE6022020BEF22E7B90A8DF42186AFBCD85EB0E104991EA210B83068C1AAD7DF72615ED", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + } + ] + }, + "meta": { + "TransactionIndex": 1, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34854791, + "PreviousTxnID": "ED6B5936B5A2A1262E6A4DAE0AFB03974225D4BDED9711E270BBDB47D0B8249F", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 4, + "Balance": "5935129679974200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 5, + "OwnerCount": 10, + "Balance": "5835129679969200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34880318, + "PreviousTxnID": "E9D4B5D93501B38DE6289EC0C8AEABFA820EE553BDD2AC427A62B3F985389656", + "LedgerIndex": "D474EB4E1F06E4266166832B3611A7E40B0C814CA742E5169BD5880569BCA9D2", + "PreviousFields": { + "Balance": "803134818019" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 155, + "OwnerCount": 2, + "Balance": "100803134818019", + "Account": "rBg2FuZT91C52Nny68houguJ4vt5x1o91m" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "100000000000000" + } + }, + { + "hash": "BAD994A5569F12A74520BD34226EE1EBEAF44C6DF3B375A0A1F1ADD39DE714DA", + "ledger_index": 35031684, + "date": "2017-12-14T22:32:51+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 5, + "LastLedgerSequence": 35109461, + "Amount": "150000000000000", + "Fee": "5000", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rBg2FuZT91C52Nny68houguJ4vt5x1o91m", + "Signers": [ + { + "Signer": { + "SigningPubKey": "0320ECD5569CAFA4E23147BE238DBFB268DB3B5A502ED339387AC7DCA0ADC6FB90", + "TxnSignature": "304402201C4D57AAF4B7BF40D17E69AAC69A24027972E44F53504009476E2947B744EB070220431E71A1305BEDFCD753EF766ABC8980D06BAA4E66341339905623F9DD808772", + "Account": "re3LGjhrCvthtWWwrfKbVJjXN9PYDeQDJ" + } + }, + { + "Signer": { + "SigningPubKey": "02259BC18378FD3C99B92C4A41ABA65B62333980DDF28F1F60EF8EF0B5CE7AD93D", + "TxnSignature": "30450221009070A61B831B6C253135165292ADA9546294F8CD3A752698CCF77319F5391B4B02201FA22DAA1D28071AE70F52AF595A225FD1A5798D078227DACD6E4B7C99C1AA87", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + }, + { + "Signer": { + "SigningPubKey": "02FA11725F6F4E28C2E1617CC60C3A43161270A6B0C8B8DAB68265E7CFC27E0E4A", + "TxnSignature": "30450221008B48D6367E7FE75518B71D2B2FBAC2555488275DB504BE4E5C27EFB2758CE3EE02200EEC265DF81D5D2ED0181BA5E02BF77D9E81DE5E4749D235ECBAE6226E0AC70C", + "Account": "rLW75SfEdnGVsa3fTFkSaDTzXuFapwNYtf" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "304402207F09AF57ED924E0184B7212E74CC9C8E999A5D444BA8E87975CDE252B116961D02207C329A50A41B733E26375F1F4207C0FDB76E073A990705127756594F09B41655", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + } + ] + }, + "meta": { + "TransactionIndex": 26, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34948434, + "PreviousTxnID": "E1094E64564CC70D2B4B0D3F6E0DC3C101E929FBD16E8F508FCBE2E41EF09495", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 5, + "Balance": "5835129679969200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 6, + "OwnerCount": 10, + "Balance": "5685129679964200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 35007021, + "PreviousTxnID": "B5D64155C19AFEA28E8C6B33C77FCC525443503A730E10269FC3A21BB2E3D370", + "LedgerIndex": "D474EB4E1F06E4266166832B3611A7E40B0C814CA742E5169BD5880569BCA9D2", + "PreviousFields": { + "Balance": "15802434798483" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 159, + "OwnerCount": 2, + "Balance": "165802434798483", + "Account": "rBg2FuZT91C52Nny68houguJ4vt5x1o91m" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "150000000000000" + } + }, + { + "hash": "44E2BA90CF6AAD90832E5DA22BCB7C8A6E1A55C903909E45333D227BECF6FB51", + "ledger_index": 36055443, + "date": "2018-01-23T23:58:22+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 5, + "LastLedgerSequence": 36055452, + "Amount": "1000000", + "Fee": "10", + "SigningPubKey": "0231975D7489F0C1E1D871A27F23DF1BAFE53055FA7ADDCB95F6E923B1710D6C05", + "TxnSignature": "304402207926EFE3A77E7A17087B54DD0FD7BE6BAF7AE0E025ECB532336CBCB6CF5DFAB002202B9EA53763FEE3D4742E419035D23448DDDC646116B37BA65183DAAE1C5B2F6C", + "Account": "rNuSNt1mAkGK5HBTDJN2Q2vD23YyaEEmSU", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + }, + "meta": { + "TransactionIndex": 6, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 35929929, + "PreviousTxnID": "521A8B08E2D4DE06C5B4B78541ADAA18157288FB4160BA93E465CC530306A831", + "LedgerIndex": "0F5E84C137AF95199945D4DC676259E34E7BD2AB36FF7D2200DE42EED496E135", + "PreviousFields": { + "Sequence": 5, + "Balance": "35018854314" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 6, + "OwnerCount": 0, + "Balance": "35017854304", + "Account": "rNuSNt1mAkGK5HBTDJN2Q2vD23YyaEEmSU" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 35031684, + "PreviousTxnID": "BAD994A5569F12A74520BD34226EE1EBEAF44C6DF3B375A0A1F1ADD39DE714DA", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Balance": "5685129679964200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 6, + "OwnerCount": 10, + "Balance": "5685129680964200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "1000000" + } + }, + { + "hash": "4E4509305CAF71A3D0A56ED4B1E9732BF2A8CD42633FA271EC71CA3B76519EF2", + "ledger_index": 38026583, + "date": "2018-04-17T14:54:21+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 28, + "LastLedgerSequence": 38026585, + "Amount": "1000000", + "Fee": "12", + "SendMax": { + "value": "0.0000202", + "currency": "XPD", + "issuer": "rLedgerMAX4v6YjDTbKdccP2wPbN1XhdcX" + }, + "SigningPubKey": "03740D0995283EF783A5EE2BB6EE93214FF91970AA509A02B9C55E133127FA609D", + "TxnSignature": "304402202D1D145250404A9E50FDDB301B57D1456FF5AE7EA7287C6EC3DB4324CFC5BA0F022017BF0C16A9AA46631AC0FE3910D9DB02DCE33B52B713D1B2CF6002F9ADA343DF", + "Account": "rLedgerMAX4v6YjDTbKdccP2wPbN1XhdcX", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Memos": [ + { + "Memo": { + "MemoData": "4F666665722058504420504F205B50726963653A20353030303020585250207C204D696E204F726465722031205850445D" + } + }, + { + "Memo": { + "MemoType": "636C69656E74", + "MemoData": "50616C6164696E73" + } + } + ], + "Paths": [ + [ + { + "account": "rMCa3o92WJDHDw7GLZiP85Pp3ZRkb87xUp" + }, + { + "account": "rfhzYEqyDBiKkdpPUbSdnuEenqbmfJCys5" + }, + { + "currency": "XRP" + } + ] + ] + }, + "meta": { + "TransactionIndex": 29, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 37981254, + "PreviousTxnID": "4559199AC5B4CDC4B2C9A880077E404C462E8E3312477950D8D61CFAE896BA11", + "LedgerIndex": "19CC29FF4382B5DE428F57AB7F892FAED220EC2A3E0B00A358D680BEDFE49A4B", + "PreviousFields": { + "Sequence": 28, + "AccountTxnID": "4559199AC5B4CDC4B2C9A880077E404C462E8E3312477950D8D61CFAE896BA11", + "Balance": "32099568" + }, + "FinalFields": { + "Flags": 4063232, + "Sequence": 29, + "OwnerCount": 2, + "EmailHash": "0068272433B9D73CC20F6D0856D0FF49", + "AccountTxnID": "4E4509305CAF71A3D0A56ED4B1E9732BF2A8CD42633FA271EC71CA3B76519EF2", + "Balance": "32099556", + "Domain": "7872702E6964", + "Account": "rLedgerMAX4v6YjDTbKdccP2wPbN1XhdcX", + "RegularKey": "rMCa3o92WJDHDw7GLZiP85Pp3ZRkb87xUp" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 38019315, + "PreviousTxnID": "ECA6CD39DB1BFFE6EFD92749747AEEE8C84978D5CCE2DBD52ADAC970B96DF714", + "LedgerIndex": "532740BCCCE8E47CAC62FED0E786BE6C33BDB1E28AF490CA93FA7A9287085524", + "PreviousFields": { + "Balance": "232960771" + }, + "FinalFields": { + "Flags": 11141120, + "Sequence": 602, + "TransferRate": 1150000000, + "OwnerCount": 41, + "EmailHash": "3A362880A9CCDF7AD417264EC76C7E31", + "AccountTxnID": "ECA6CD39DB1BFFE6EFD92749747AEEE8C84978D5CCE2DBD52ADAC970B96DF714", + "Balance": "231960771", + "Domain": "6C6564676572636861696E2E776F726C64", + "Account": "rMCa3o92WJDHDw7GLZiP85Pp3ZRkb87xUp", + "RegularKey": "rfhzYEqyDBiKkdpPUbSdnuEenqbmfJCys5", + "TickSize": 15 + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 36055443, + "PreviousTxnID": "44E2BA90CF6AAD90832E5DA22BCB7C8A6E1A55C903909E45333D227BECF6FB51", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Balance": "5685129680964200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 6, + "OwnerCount": 10, + "Balance": "5685129681964200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "Offer", + "PreviousTxnLgrSeq": 38018992, + "PreviousTxnID": "1706DDDBEEFF5479E8678F6D4546854B5DDAB384855ED912874B123091C56B32", + "LedgerIndex": "90618276E00443F08D6D62BF7D4B2DD4961D7F3EB1474EE9A88B7FD38EA634E6", + "PreviousFields": { + "TakerPays": { + "value": "10499.99936829082", + "currency": "XPD", + "issuer": "rfhzYEqyDBiKkdpPUbSdnuEenqbmfJCys5" + }, + "TakerGets": "524999968414541" + }, + "FinalFields": { + "Flags": 131072, + "Sequence": 421, + "BookNode": "0000000000000000", + "OwnerNode": "0000000000000001", + "BookDirectory": "7253BA4DA83003DCEEC2641ACEA931976B842A44510176E94A071AFD498D0000", + "TakerPays": { + "value": "10499.99934829082", + "currency": "XPD", + "issuer": "rfhzYEqyDBiKkdpPUbSdnuEenqbmfJCys5" + }, + "TakerGets": "524999967414541", + "Account": "rMCa3o92WJDHDw7GLZiP85Pp3ZRkb87xUp" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "RippleState", + "PreviousTxnLgrSeq": 37934707, + "PreviousTxnID": "26A9A0E390DCC9D5C9C781FC8CB6FB4B4760DB3925BBCB40D1DE3335CA82C859", + "LedgerIndex": "A1D3A25D09EA8AB50E92FEC2EF8B2027C474EE82ABBBB501FD18F524A7D9BB60", + "PreviousFields": { + "Balance": { + "value": "10", + "currency": "XPD", + "issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji" + } + }, + "FinalFields": { + "Flags": 65536, + "LowQualityIn": 1000000000, + "LowNode": "0000000000000000", + "HighNode": "0000000000000001", + "Balance": { + "value": "9.99998", + "currency": "XPD", + "issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji" + }, + "LowLimit": { + "value": "1000000", + "currency": "XPD", + "issuer": "rLedgerMAX4v6YjDTbKdccP2wPbN1XhdcX" + }, + "HighLimit": { + "value": "0", + "currency": "XPD", + "issuer": "rMCa3o92WJDHDw7GLZiP85Pp3ZRkb87xUp" + } + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "1000000" + } + }, + { + "hash": "68BD7AA168163BEBA43956C0946CC87041CD72368B040F4933E6429B903A882F", + "ledger_index": 38474522, + "date": "2018-05-06T19:22:32+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 1, + "DestinationTag": 42, + "LastLedgerSequence": 38474527, + "Amount": "1000", + "Fee": "10", + "SigningPubKey": "033C35B83EF461CA4F63CD442A3A7E4D0D1738ADD84E00AF197E2731AB1635CFB3", + "TxnSignature": "3045022100B9E241B0DC68177B0A4E26A6E8D1C2E68F8BA1B4591865746BFC6FAA2038426102203B395FBC424E0D3B8DF03ADD1A81319D987223EDD6959B68ADFE2184F896AE0A", + "Account": "rBYtAxpyfGQzRdCnUY7eUQY5auXJwDFx8J", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + }, + "meta": { + "TransactionIndex": 0, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 37761110, + "PreviousTxnID": "681BA318358ADAA87AA3395E3732B852A8400BB32170ED3F1C2A4D84E92BC805", + "LedgerIndex": "1DFECA815C5F6EE0BEA0FA51F051FCDAE16CCBC0C2A78646EE31E24E86A5FE9E", + "PreviousFields": { + "Sequence": 1, + "Balance": "16589493322" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 2, + "OwnerCount": 0, + "Balance": "16589492312", + "Account": "rBYtAxpyfGQzRdCnUY7eUQY5auXJwDFx8J" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 38026583, + "PreviousTxnID": "4E4509305CAF71A3D0A56ED4B1E9732BF2A8CD42633FA271EC71CA3B76519EF2", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Balance": "5685129681964200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 6, + "OwnerCount": 10, + "Balance": "5685129681965200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "1000" + } + }, + { + "hash": "FF6C1181F4EE3848B527A5432CAC42E65B24FD203BE126B15D41BA31816AB89E", + "ledger_index": 39575337, + "date": "2018-06-23T01:45:32+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 88, + "LastLedgerSequence": 39575341, + "Amount": "1000000", + "Fee": "15", + "SigningPubKey": "03F1B487CA869E2A9A1BE170E0C1907E1AE7B9E2B7264D7452FA2ADF7E063D3A0F", + "TxnSignature": "304402204E40395CF9ABE61A1EADE83F987693F09C6D37EFD85F5A4B768FB4C4F992488602207B2618EADC36687DB9B448727426BA83B1B4596D08DF75D1D171AA5243C8BF2D", + "Account": "rK7aFKgWd1xeqhsPNPrfUbKnfttxNvCp9E", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Memos": [ + { + "Memo": { + "MemoType": "636C69656E74", + "MemoData": "67617465687562", + "MemoFormat": "746578742F706C61696E" + } + } + ] + }, + "meta": { + "TransactionIndex": 4, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 38474522, + "PreviousTxnID": "68BD7AA168163BEBA43956C0946CC87041CD72368B040F4933E6429B903A882F", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Balance": "5685129681965200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 6, + "OwnerCount": 10, + "Balance": "5685129682965200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 39575141, + "PreviousTxnID": "DF2598973FA88D3B460A0461D577DADF1382882C775B2F04B023CF960C2A44BD", + "LedgerIndex": "6585D8808EC6A8B8263C7EBCA9806B4050DD299917571885FC9269FE68624B73", + "PreviousFields": { + "Sequence": 88, + "Balance": "263623032400" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 89, + "OwnerCount": 9, + "Balance": "263622032385", + "Account": "rK7aFKgWd1xeqhsPNPrfUbKnfttxNvCp9E" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "1000000" + } + }, + { + "hash": "2E773CE9FAA04594B8F2465FFAD4FE932BC8E2218EF8875D3AE8A8670F9779CF", + "ledger_index": 41827297, + "date": "2018-09-27T15:32:51+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 6, + "LastLedgerSequence": 41925142, + "Amount": "500000000000000", + "Fee": "5000", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rNuF65SoNFRgi7KomddPeSpLhdB2Y7RnsN", + "Signers": [ + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100A0AF71912B1E7D2C6CA3625761901A2DA573C79EFA04136DFCC5AEC9DEFD72750220655751B42DEDB60D5AE46CA36C10952D237145939118ADB7730D1857146E894B", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "02259BC18378FD3C99B92C4A41ABA65B62333980DDF28F1F60EF8EF0B5CE7AD93D", + "TxnSignature": "304502210080DC88DA724AC2986BFB5164177C970C5EDB989634C89F4098DA96E9936C6A4C0220718AC23377BAC42AD23833F962D1CEF034D43A0B9346B80E4F8AB28D5BACE933", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + }, + { + "Signer": { + "SigningPubKey": "02FA11725F6F4E28C2E1617CC60C3A43161270A6B0C8B8DAB68265E7CFC27E0E4A", + "TxnSignature": "304402204E514E447801FBBA6A8737952ECC307389624378EEB0DCCF55340202638A969A0220488919E2675AD88D4503C87B20EC1C93FFA64E70F9D438B526EEFEE1803A26FB", + "Account": "rLW75SfEdnGVsa3fTFkSaDTzXuFapwNYtf" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "3045022100A410BCCB1A705AB06910FC92A584D6808EE6CCA8D2BDA84F6C4C229D2DAFA0150220479BB0D656E8153DDFEA1D8D012C1190FCAC306D3C6F1E8FB902110038815725", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + } + ] + }, + "meta": { + "TransactionIndex": 6, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 39575337, + "PreviousTxnID": "FF6C1181F4EE3848B527A5432CAC42E65B24FD203BE126B15D41BA31816AB89E", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 6, + "Balance": "5685129682965200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 7, + "OwnerCount": 10, + "Balance": "5185129682960200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34823700, + "PreviousTxnID": "10096291E3C8D5A63E7FD5A839E52BDBBCA849042426D433F85B4AA549FF9E7C", + "LedgerIndex": "9E77AE4FC38D9A41794A008692545B5402F5C251A4838D5CC2A2842598329A64", + "PreviousFields": { + "Balance": "99993000" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 4, + "OwnerCount": 10, + "Balance": "500000099993000", + "Account": "rNuF65SoNFRgi7KomddPeSpLhdB2Y7RnsN" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "500000000000000" + } + }, + { + "hash": "6A3A36EAC8CC9EB65828D584E570A43988870A91ECD32A3C8EAD898EACCC1B1C", + "ledger_index": 43012867, + "date": "2018-11-16T01:35:41+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 7, + "LastLedgerSequence": 43068883, + "Amount": "200000000000000", + "Fee": "5000", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rNfwFmsgBRrtqQDcWtFAJMzK2P1yCs7XPy", + "Signers": [ + { + "Signer": { + "SigningPubKey": "0320ECD5569CAFA4E23147BE238DBFB268DB3B5A502ED339387AC7DCA0ADC6FB90", + "TxnSignature": "304502210095330DE1E672CF92E644A4DFB89C6ED7FEB80683092AD556E101ABE70BEEBCAC022028A25E06B26E29D9A76E8324065300055D7CE05B17AB8D11ACBE69F3F7460E08", + "Account": "re3LGjhrCvthtWWwrfKbVJjXN9PYDeQDJ" + } + }, + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100FFBFBD1D305376CC20F792E1F9C7F8FA501F6B1FE8D568E90B7DF78A6C0035E9022026D5B318122E68ED89D709368A27E8A689D39E1D03AF0584288BE5405E7D82CB", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "02FA11725F6F4E28C2E1617CC60C3A43161270A6B0C8B8DAB68265E7CFC27E0E4A", + "TxnSignature": "304402206D5EF7AA9D5E2C9B85A0E0FBC1594ADC5C4CFA9266BA207620F66E78DE200676022026CC3128337A013A29D18A23465090E36C68F7ADBED92AD7E4118EB686714598", + "Account": "rLW75SfEdnGVsa3fTFkSaDTzXuFapwNYtf" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "3045022100BED21F950C0C2CED2C0EC9287E6A84AEB49618CCA847EA611674AF5039889906022031CB7A499BE9AE962F0C02EF38A47BFE9B2A7029214D7338C692F81C7B08B986", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + } + ] + }, + "meta": { + "TransactionIndex": 9, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 42961397, + "PreviousTxnID": "C08998F3FDE4B6B569234D829B493EF1EC366EF4CF247DFC9AF30368D5AE3027", + "LedgerIndex": "42B63458984812E176A0B79A65BED3CDF103FCAD451C33E4976137EF2CE9D21F", + "PreviousFields": { + "Flags": 65536, + "Balance": "57995900" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 6, + "OwnerCount": 0, + "Balance": "200000057995900", + "Account": "rNfwFmsgBRrtqQDcWtFAJMzK2P1yCs7XPy", + "RegularKey": "racz6fAfyMp7PDGiwSqAxgg9kA5xUpe8gz" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 41827297, + "PreviousTxnID": "2E773CE9FAA04594B8F2465FFAD4FE932BC8E2218EF8875D3AE8A8670F9779CF", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 7, + "Balance": "5185129682960200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 8, + "OwnerCount": 10, + "Balance": "4985129682955200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "200000000000000" + } + }, + { + "hash": "F9BD43ACE9F2510743C9A293345FF1C821D76C7A3013F4DF3FBDD75114F92D44", + "ledger_index": 43012937, + "date": "2018-11-16T01:40:02+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 8, + "LastLedgerSequence": 43068937, + "Amount": "760000000000000", + "Fee": "5000", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rhyp1uMC9Xyj3Px8amUH3xVv6tbjYJkojs", + "Signers": [ + { + "Signer": { + "SigningPubKey": "0320ECD5569CAFA4E23147BE238DBFB268DB3B5A502ED339387AC7DCA0ADC6FB90", + "TxnSignature": "3045022100BC3B33F91561A5C415A4FBC30C79F099367AB83772926CA4251F2E2AC91D5AC002207D3F708F9074A0092B42D0F5DAAEE3A88D3B3DC4DCD206538890ADCAF10D80E3", + "Account": "re3LGjhrCvthtWWwrfKbVJjXN9PYDeQDJ" + } + }, + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100CE5488B682E7463E13E648D264F0541B06C8EC41EEFFE985B27D5D685EF0E39E0220273DFEEDF0B40C3691F194D4F20180977281E1C17F016645DEC50D2A8A72E57B", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "02FA11725F6F4E28C2E1617CC60C3A43161270A6B0C8B8DAB68265E7CFC27E0E4A", + "TxnSignature": "304502210087851F0C4E9F6AFD27F654A1B4C8D30CCDF267870D3E8F5C8F2D2AE3CA4E954902203FA729BE8752DC64F096EB89A27C3AD6BF402C9B436192E864DAB1B13FA8A141", + "Account": "rLW75SfEdnGVsa3fTFkSaDTzXuFapwNYtf" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "3045022100EAA85F6D82FE3F7CEAB63F30B5B01AF8BE9EF688B6EE4294A9A5E1A0E53452D202203A2CBC14B83C61C4A0A4F9335C1F173D52E42D70AFCDEDE0DB648A7A7A0A8BCF", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + } + ] + }, + "meta": { + "TransactionIndex": 27, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 43012867, + "PreviousTxnID": "6A3A36EAC8CC9EB65828D584E570A43988870A91ECD32A3C8EAD898EACCC1B1C", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 8, + "Balance": "4985129682955200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 9, + "OwnerCount": 10, + "Balance": "4225129682950200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 34823650, + "PreviousTxnID": "78D8E1FC5F061F9EFC24DE0F4BEC430CC5F23E9EE8744B5C809275A0D4395E51", + "LedgerIndex": "F6398B7FDCC804AFC061E644C2E526C781AC54A9F0EDB3D2DF8508670BDC87BE", + "PreviousFields": { + "Balance": "99993000" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 4, + "OwnerCount": 10, + "Balance": "760000099993000", + "Account": "rhyp1uMC9Xyj3Px8amUH3xVv6tbjYJkojs" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "760000000000000" + } + }, + { + "hash": "0E9ADE6EA164548849FCCD7DB93AF4DCEA2650F937CF544807B46AB839A76426", + "ledger_index": 43367293, + "date": "2018-11-30T21:21:11+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 9, + "LastLedgerSequence": 43550023, + "Amount": "709565665000000", + "Fee": "5000", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rNuF65SoNFRgi7KomddPeSpLhdB2Y7RnsN", + "Signers": [ + { + "Signer": { + "SigningPubKey": "0320ECD5569CAFA4E23147BE238DBFB268DB3B5A502ED339387AC7DCA0ADC6FB90", + "TxnSignature": "3045022100CB347DA08FE8DCFA6FEA5A64036E892D6837A2893FFC5AD8EC91BE5933960D9902203C4B28958F694C15489FFF7496EC48F8973A658EE200FBA65AA121F51FE64FF9", + "Account": "re3LGjhrCvthtWWwrfKbVJjXN9PYDeQDJ" + } + }, + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "304402207D15DB35E497D7830F567EEDD48F1B156088EE41ABC8653F33FAF756E8EE8FE302201C20B51FEBCED36EDB3CD320E9C18AA268DE5B9C930961673197FBD2FCDE5D0C", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "029A7A9E7A6175690C6E3D46EBBA33DA9EBF096EB5942E21C4A8C98F5606E6E6B8", + "TxnSignature": "3044022006824AAD9BF45AD9013E9C62905887C8A8FCC391909D841A683E47AB3163543D02201CD4A299228B7E5B5788E66C2538700C403662DD22A700E85299BBAB9116F158", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "3045022100FA1B7353DD93E05D273C07B2FDBD13539A43F53D14C09F70478ED963B18F05D80220750EADFC4DF068EB2D9C3B62D1A709BAD0FB1D91861A7A266310E90ECD6FA83D", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + } + ] + }, + "meta": { + "TransactionIndex": 10, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 43012937, + "PreviousTxnID": "F9BD43ACE9F2510743C9A293345FF1C821D76C7A3013F4DF3FBDD75114F92D44", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 9, + "Balance": "4225129682950200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 10, + "OwnerCount": 10, + "Balance": "3515564017945200", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 42002657, + "PreviousTxnID": "6B260AA7CC3C51CBC1C7A3986F1A84B11E76C8C457D55669E2A45281A9706242", + "LedgerIndex": "9E77AE4FC38D9A41794A008692545B5402F5C251A4838D5CC2A2842598329A64", + "PreviousFields": { + "Balance": "392224236973000" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 8, + "OwnerCount": 10, + "Balance": "1101789901973000", + "Account": "rNuF65SoNFRgi7KomddPeSpLhdB2Y7RnsN" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "709565665000000" + } + }, + { + "hash": "5581E189FDBA282D55FBED3936C25FACE36DBCA7F731E0BEEF2EE9BF737A5855", + "ledger_index": 43374095, + "date": "2018-12-01T04:06:11+00:00", + "tx": { + "TransactionType": "Payment", + "SourceTag": 5913, + "Sequence": 3585, + "DestinationTag": 0, + "LastLedgerSequence": 43374098, + "Amount": "5890", + "Fee": "12", + "SigningPubKey": "03DF3AB842EB1B57F0A848CD7CC2CFD35F66E4AD0625EEACFFE72A45E4D13E49AB", + "TxnSignature": "304502210086004E950E55F238EA0E108B066FE8F71BB079A25D78A32BF37F0F81AFFD3A0B022035234292D4C6D3B78178C17E54BFD418A864CB08B9D9CA71A64F6BEE24F6D1C0", + "Account": "rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Memos": [ + { + "Memo": { + "MemoType": "587270546970426F744E6F7465", + "MemoData": "5365636F6E64617279204C697175696469747920506F6F6C206E6F74206C6F636B656420696E20657363726F773F203230304D2052656C65617365642040354D2F706572206F6E2031737420616E64203135746820666F722032304D6F6E746873207374617274696E672031322F3230313820536F757263656420686572652E207E53616D49616D" + } + } + ] + }, + "meta": { + "TransactionIndex": 5, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 43373864, + "PreviousTxnID": "BC8809D9499F8EE41BC3AEE2710D3342DDD815174F659F9B6897264095DC6518", + "LedgerIndex": "44EF183C00DFCB5DAF505684AA7967C83F42C085EBA6B271E5349CB12C3D5965", + "PreviousFields": { + "Sequence": 3585, + "Balance": "9405394584" + }, + "FinalFields": { + "Flags": 131072, + "Sequence": 3586, + "OwnerCount": 51, + "EmailHash": "833237B8665D2F4E00135E8DE646589F", + "Balance": "9405388682", + "Domain": "787270746970626F742E636F6D", + "Account": "rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 43367293, + "PreviousTxnID": "0E9ADE6EA164548849FCCD7DB93AF4DCEA2650F937CF544807B46AB839A76426", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Balance": "3515564017945200" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 10, + "OwnerCount": 10, + "Balance": "3515564017951090", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "5890" + } + }, + { + "hash": "04B9FFC2AB5F5FDC95D1BCE94AD229D1046149DAEC6807326BED1B4A5D8D0862", + "ledger_index": 43707148, + "date": "2018-12-15T04:24:02+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 3, + "LastLedgerSequence": 43707157, + "Amount": "1000000", + "Fee": "10", + "SigningPubKey": "03ED3E890B17383F9CD91562087184E27509657B1276A22BE2EA968F8A47490592", + "TxnSignature": "3044022061B2FBCF22EFF32182CA4EDAB00870E9B5A548C63893B517DC3A54E00CA9F5F602207A671E3D9218A38497EAF53F10A66F8CF6484ED4F6574FA371A72565651C95FC", + "Account": "rDJ8NURUAxq3MDS8xAZNCx45VH159m2RW3", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + }, + "meta": { + "TransactionIndex": 1, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 43706798, + "PreviousTxnID": "97089534B6586ECED80AC176FE8CA26ACB3B6981BD48590EA9213322F09C3F26", + "LedgerIndex": "1F55D96C737869F0D45E7D46A012B22D0171D159BA3F30D3A6C4E00BA7D28E59", + "PreviousFields": { + "Sequence": 3, + "Balance": "239999990" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 4, + "OwnerCount": 0, + "Balance": "238999980", + "Account": "rDJ8NURUAxq3MDS8xAZNCx45VH159m2RW3" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 43374095, + "PreviousTxnID": "5581E189FDBA282D55FBED3936C25FACE36DBCA7F731E0BEEF2EE9BF737A5855", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Balance": "3515564017951090" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 10, + "OwnerCount": 10, + "Balance": "3515564018951090", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "1000000" + } + }, + { + "hash": "B89145E7420FCDCBB5795C0161619FA53F790ED72F14C03A2473346EC864824A", + "ledger_index": 44108034, + "date": "2019-01-01T17:05:02+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 7, + "LastLedgerSequence": 44334798, + "Amount": "1108302303980000", + "Fee": "500", + "SigningPubKey": "", + "Account": "r93oSNBKuFjuKt8GxhF8VYaGzzwsNDPaX5", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Signers": [ + { + "Signer": { + "SigningPubKey": "0320ECD5569CAFA4E23147BE238DBFB268DB3B5A502ED339387AC7DCA0ADC6FB90", + "TxnSignature": "3045022100985C236B3356C45664401C08BA779E27C73FDB4EE2DF71E0DAB74D1437D6B8C602207DC8B6B15D72CFD324569BBD5B722FD8830EE92CF6BBAF31497FDE782C19CD97", + "Account": "re3LGjhrCvthtWWwrfKbVJjXN9PYDeQDJ" + } + }, + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "304402205700D610EDD0CF37809CD51C194657E1B28FB54C71B00743142E020189A7EE5D022071338D4E10F4F20722B5A222165AA6E0E22EB28EBE0C18ACB2F54F99A4C2BB17", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "02FA11725F6F4E28C2E1617CC60C3A43161270A6B0C8B8DAB68265E7CFC27E0E4A", + "TxnSignature": "3045022100E1702141044877476C982DE6CCB1CE5AE328E38218046D7A25CD6C9C4CD3C8E6022006ADFB93730214FC7B94712220840B37AB288B720DB48AAFE5B25B512835A507", + "Account": "rLW75SfEdnGVsa3fTFkSaDTzXuFapwNYtf" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "30440220667B90CF533DA0A0C32D7E593B0F406B08CE8BB3D68C35D3549FDE6B2CE1AA0F022012854E0FC110F5013650F30B8BB144C435189C8D46ECA8E2789A609EA7CF7871", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + } + ] + }, + "meta": { + "TransactionIndex": 4, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 43707148, + "PreviousTxnID": "04B9FFC2AB5F5FDC95D1BCE94AD229D1046149DAEC6807326BED1B4A5D8D0862", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Balance": "3515564018951090" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 10, + "OwnerCount": 10, + "Balance": "4623866322931090", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 43702504, + "PreviousTxnID": "6EE150A056061F4DDB77D8AF282DB9F5ABDD9F244CF09B020BAF5DFFE014E668", + "LedgerIndex": "8E329FA7CCE1E2F0CB9D14D6647D2368B7F68080AE4D7D589FFA7E70F2B80017", + "PreviousFields": { + "Sequence": 7, + "Balance": "2080000078978000" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 8, + "OwnerCount": 10, + "Balance": "971697774997500", + "Account": "r93oSNBKuFjuKt8GxhF8VYaGzzwsNDPaX5" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "1108302303980000" + } + }, + { + "hash": "63429809CA00D66A3C7317876E8E21D14E4E1C5C3EEEA42D5E5F7B0C44A10C82", + "ledger_index": 44108075, + "date": "2019-01-01T17:07:42+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 10, + "LastLedgerSequence": 44334747, + "Amount": "107866784000000", + "Fee": "500", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rNuF65SoNFRgi7KomddPeSpLhdB2Y7RnsN", + "Signers": [ + { + "Signer": { + "SigningPubKey": "0320ECD5569CAFA4E23147BE238DBFB268DB3B5A502ED339387AC7DCA0ADC6FB90", + "TxnSignature": "304402204465A4271C16C5494F2E36A2F4CC344CB215B0840BFDAA8AB87F8BF155ADC87202201BE337A394182F8023B397E87050677F33075BF077079239C655639B6D06424B", + "Account": "re3LGjhrCvthtWWwrfKbVJjXN9PYDeQDJ" + } + }, + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100889EA900F6E3F408C60797FBB3B3E6AC45A9ED19052B61DE328BF71F84992A69022066639B85840097339D054A7253A7E6FEBA639AB9F30029ACE487CB15F093B632", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "02FA11725F6F4E28C2E1617CC60C3A43161270A6B0C8B8DAB68265E7CFC27E0E4A", + "TxnSignature": "30440220455D940A2F8FC47BE3C31E58748FCCB351F6AA1F7B7EBD509051F2B9D8B7685B0220212B9D978CB36EA0DFE372D5A4C2D06DFCD24F1384A89A24A30072DAE9B6F87E", + "Account": "rLW75SfEdnGVsa3fTFkSaDTzXuFapwNYtf" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "30450221009FF3ECC2BC7BD67F9B506C03D5E9FA3B22D58DF343DB57F4AE9046980E101E0D0220088C96E2E1275F6A611B7EC007118F4CB1529796020658BF6D12C23EC78EE111", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + } + ] + }, + "meta": { + "TransactionIndex": 7, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44108034, + "PreviousTxnID": "B89145E7420FCDCBB5795C0161619FA53F790ED72F14C03A2473346EC864824A", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 10, + "Balance": "4623866322931090" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 11, + "OwnerCount": 10, + "Balance": "4515999538930590", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 43927137, + "PreviousTxnID": "976861787CFA9CA97456849C0092BBE795F1BBFA5153D3FD6E6EDCF2AF7D2E0F", + "LedgerIndex": "9E77AE4FC38D9A41794A008692545B5402F5C251A4838D5CC2A2842598329A64", + "PreviousFields": { + "Balance": "941106818023790" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 11, + "OwnerCount": 10, + "Balance": "1048973602023790", + "Account": "rNuF65SoNFRgi7KomddPeSpLhdB2Y7RnsN" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "107866784000000" + } + }, + { + "hash": "9224129EC239ADB8C8659C711DFF9D364367FA79C1F7BC36C8F2AC664C50C0C1", + "ledger_index": 44115937, + "date": "2019-01-02T01:29:10+00:00", + "tx": { + "TransactionType": "Payment", + "SourceTag": 4112, + "Sequence": 4793, + "DestinationTag": 0, + "LastLedgerSequence": 44115940, + "Amount": "1", + "Fee": "12", + "SigningPubKey": "03DF3AB842EB1B57F0A848CD7CC2CFD35F66E4AD0625EEACFFE72A45E4D13E49AB", + "TxnSignature": "3045022100CD28E00906245332F2E65A84860F8D78B369E430399D0DB4243CA336FB1C17D502207947318F7809B8025AFE9F4EBEE6798FE11C73AD6CF58DDC08FB0F60DCEA8902", + "Account": "rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Memos": [ + { + "Memo": { + "MemoType": "587270546970426F744E6F7465", + "MemoData": "5468652040526970706C654E696E6A612077617320686572652121" + } + } + ] + }, + "meta": { + "TransactionIndex": 0, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44115921, + "PreviousTxnID": "A10B3A39BAC7FAFABBF0091F175DB7325B1F6B404EB403CDA37FF80581B243AB", + "LedgerIndex": "44EF183C00DFCB5DAF505684AA7967C83F42C085EBA6B271E5349CB12C3D5965", + "PreviousFields": { + "Sequence": 4793, + "Balance": "13529497722" + }, + "FinalFields": { + "Flags": 131072, + "Sequence": 4794, + "OwnerCount": 66, + "EmailHash": "833237B8665D2F4E00135E8DE646589F", + "Balance": "13529497709", + "Domain": "787270746970626F742E636F6D", + "Account": "rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44108075, + "PreviousTxnID": "63429809CA00D66A3C7317876E8E21D14E4E1C5C3EEEA42D5E5F7B0C44A10C82", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Balance": "4515999538930590" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 11, + "OwnerCount": 10, + "Balance": "4515999538930591", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "1" + } + }, + { + "hash": "665E556F663246371F3BDD0E319B0BD65C8546B359E17B5C0785A1D0D3934E22", + "ledger_index": 44644540, + "date": "2019-01-24T22:51:10+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 11, + "LastLedgerSequence": 44867434, + "Amount": "105000000", + "Fee": "500", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rUEchj8k8jvVXKGhfVYvrs5ntVEtc5F2hK", + "Signers": [ + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100828E4EA1AEA3DBB9C5E01237DA78C613727BA1B2699867E3E26643EF9DD6AC9B02203D7C0C3810AB7E9F8494C8D02B81903F76AF0781CA0C91DF53A47E07997FB11F", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "029A7A9E7A6175690C6E3D46EBBA33DA9EBF096EB5942E21C4A8C98F5606E6E6B8", + "TxnSignature": "3045022100E1D7E415924E30CA08329256396B4E11E5C8DBEE95D8521FAC4F60662E1CC020022009EEDFF57949AAF640FA8AC204E7AC099D41EE31976BD4FAF7410706DD31BFA5", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "3044022071028401D9E77304284AA5A136033DFB069F78E78383D1E705B5A60ACC0A4DA302205867226D428048BC4965F8A846D47BE20667E390213218C63380F82DBC64DAF6", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + }, + { + "Signer": { + "SigningPubKey": "0368CFF85FEF68857A445A3F51FFC6119F2A113C9590E898351CE49F61BA71E6E8", + "TxnSignature": "3045022100B86A960BB4B35B187ED74A6898942A1A040212E1368B8B12061C1C2E208969C60220284FF751E41865A6F704A077E29CFCB55DEC6E302CFB978E1F3776B188A0F249", + "Account": "rP5xpZ5KzPih69fLhG3NYvZEDfLmSEViUk" + } + } + ] + }, + "meta": { + "TransactionIndex": 3, + "AffectedNodes": [ + { + "CreatedNode": { + "LedgerEntryType": "AccountRoot", + "LedgerIndex": "459E688FB21500B75D59CBFA49EB4C17C54E81D32A7A69CF1910691AB6AA4DCC", + "NewFields": { + "Sequence": 1, + "Balance": "105000000", + "Account": "rUEchj8k8jvVXKGhfVYvrs5ntVEtc5F2hK" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44115937, + "PreviousTxnID": "9224129EC239ADB8C8659C711DFF9D364367FA79C1F7BC36C8F2AC664C50C0C1", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 11, + "Balance": "4515999538930591" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 12, + "OwnerCount": 10, + "Balance": "4515999433930091", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "105000000" + } + }, + { + "hash": "AB83FFE7B46FF4E44BC084DFBEBBCFAA09913770766CCBFC0B1858E8195CE94E", + "ledger_index": 44734265, + "date": "2019-01-28T18:57:50+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 12, + "LastLedgerSequence": 44913163, + "Amount": "392834642660000", + "Fee": "500", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rUEchj8k8jvVXKGhfVYvrs5ntVEtc5F2hK", + "Signers": [ + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "304402204DFFC9AE5E85D59DF9CF7B1D5E4C4338FE2EC20FC66704AEC2F184677F33BC960220023580FD9BB17860E77B2D5D96D404DC387CA49C564E1DFF486D6F0206703E6A", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "029A7A9E7A6175690C6E3D46EBBA33DA9EBF096EB5942E21C4A8C98F5606E6E6B8", + "TxnSignature": "3045022100BC7EB6E8AFC95E6FE75DE1790027CE425DB6684D59B9411383205DA4CECAD464022036BF1E5CBA757C0B74BE3F9133FD8F5BEF46D42130259443DE845DEB8650CEE7", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "304402206F15B3D3F5E5C2E397D232656417B7A79B22EB11B29997A7135D3EBE471B40A9022054F5525D5ECD2C6B681C60DD9ACA6AB8D6B10107FE8C5DDE483786FA8ECAE9F2", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + }, + { + "Signer": { + "SigningPubKey": "0368CFF85FEF68857A445A3F51FFC6119F2A113C9590E898351CE49F61BA71E6E8", + "TxnSignature": "304402201A72F38B0B70A8AB788C561B10B686E0FC99096F625DF224153B0F71DC31BB7F022060FD53CF1892F27A24597FF9E77696058650CA978B91603740F91C81DE0C5282", + "Account": "rP5xpZ5KzPih69fLhG3NYvZEDfLmSEViUk" + } + } + ] + }, + "meta": { + "TransactionIndex": 10, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44644540, + "PreviousTxnID": "665E556F663246371F3BDD0E319B0BD65C8546B359E17B5C0785A1D0D3934E22", + "LedgerIndex": "459E688FB21500B75D59CBFA49EB4C17C54E81D32A7A69CF1910691AB6AA4DCC", + "PreviousFields": { + "Balance": "105000000" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 1, + "OwnerCount": 0, + "Balance": "392834747660000", + "Account": "rUEchj8k8jvVXKGhfVYvrs5ntVEtc5F2hK" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44644540, + "PreviousTxnID": "665E556F663246371F3BDD0E319B0BD65C8546B359E17B5C0785A1D0D3934E22", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 12, + "Balance": "4515999433930091" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 13, + "OwnerCount": 10, + "Balance": "4123164791269591", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "392834642660000" + } + }, + { + "hash": "20F2F95E4612296B1A82CC72F0DC53C9EAA8DA1557A0D0AD6C1E3BCA7E67E7CE", + "ledger_index": 44734671, + "date": "2019-01-28T19:22:50+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 13, + "LastLedgerSequence": 44913253, + "Amount": "392834642660000", + "Fee": "500", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "rUEchj8k8jvVXKGhfVYvrs5ntVEtc5F2hK", + "Signers": [ + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "30440220247A6624588612C73EEC2CD5F8D0A74E7FF7EE36E1ECFFF413703E928654824702205E9F5DB179A9146331935C5B5762AAAE52AE09EFDDEFDA6C596A53AE870464D2", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "029A7A9E7A6175690C6E3D46EBBA33DA9EBF096EB5942E21C4A8C98F5606E6E6B8", + "TxnSignature": "304402201DFB1E6C459753DAAD5AA6D0D44501D5D1B067F18733E2DE23F3DA9E6F4A03E602201BD890DCDDA34E8304C7C29209EAAB3C34DE07C9FD4CF2537848EA4CA02FA1BB", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "304402205E1D7DE31B9E88848E370AD7D5D77FF16CED0807A3514918BA41718040A9721F02207A832DA5575C0B66B9FF0AC6C1C0BFAF15359727221A97D2027A69CFDA953297", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + }, + { + "Signer": { + "SigningPubKey": "0368CFF85FEF68857A445A3F51FFC6119F2A113C9590E898351CE49F61BA71E6E8", + "TxnSignature": "304402204BB844E6102A40079C9616AB888C7332F000353665B4FA972525B261DB3DDED6022018586112E834D6BC3A2A2151A4F39304B1357EB11617EE84ED55D862D7978E7C", + "Account": "rP5xpZ5KzPih69fLhG3NYvZEDfLmSEViUk" + } + } + ] + }, + "meta": { + "TransactionIndex": 2, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44734265, + "PreviousTxnID": "AB83FFE7B46FF4E44BC084DFBEBBCFAA09913770766CCBFC0B1858E8195CE94E", + "LedgerIndex": "459E688FB21500B75D59CBFA49EB4C17C54E81D32A7A69CF1910691AB6AA4DCC", + "PreviousFields": { + "Balance": "392834747660000" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 1, + "OwnerCount": 0, + "Balance": "785669390320000", + "Account": "rUEchj8k8jvVXKGhfVYvrs5ntVEtc5F2hK" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44734265, + "PreviousTxnID": "AB83FFE7B46FF4E44BC084DFBEBBCFAA09913770766CCBFC0B1858E8195CE94E", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 13, + "Balance": "4123164791269591" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 14, + "OwnerCount": 10, + "Balance": "3730330148609091", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "392834642660000" + } + }, + { + "hash": "000BC2AFC047BE45C43886109720F44B6F3F2434D59B1A16A9B2B4FC9B9C5A13", + "ledger_index": 51969362, + "date": "2019-12-11T00:00:01+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 14, + "LastLedgerSequence": 52151515, + "Amount": "220303137120000", + "Fee": "5000", + "SigningPubKey": "", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Destination": "r3a8tn1ubcP13np3giaLYzkmVKfnhLP2BL", + "Signers": [ + { + "Signer": { + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100BC1FBB9457B5A8684AACA1E949DB2640CE1D0C9907AA060D334655F4162D27D0022028DD17C6E2AAD9863D2FA7BE7F0D80D4181CB9B9349371959E5DB2D69BF662D3", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" + } + }, + { + "Signer": { + "SigningPubKey": "029A7A9E7A6175690C6E3D46EBBA33DA9EBF096EB5942E21C4A8C98F5606E6E6B8", + "TxnSignature": "3044022014FA8252577C836D14D796B59C74F377A23EE1D335AEB68ED21A4BF5D4D05BBE022054361EEC50A8F3C4A4AF4EFE61C83B399F7B5240C42C2FD4BBBCEAB1CFF138B4", + "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" + } + }, + { + "Signer": { + "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", + "TxnSignature": "3045022100B407D26B1A4ABAA6C0BC9C99EDB0DCB280852EF21974D82C8C8E5866FB08187A02207255B8CD26CCEFD8ACA1DD63A767CCC127AE6EA2115CC2F89D1B798EBFA3316C", + "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" + } + }, + { + "Signer": { + "SigningPubKey": "0368CFF85FEF68857A445A3F51FFC6119F2A113C9590E898351CE49F61BA71E6E8", + "TxnSignature": "3045022100A0A5FD62D9EC81D1F0C5474A7EEB31C45423D647764B352F947617C383CD9E6902201896720DB3B9876FE56DEA05E4F75B3F90A20B3A5EF95E39703F80F5166BD1F6", + "Account": "rP5xpZ5KzPih69fLhG3NYvZEDfLmSEViUk" + } + } + ] + }, + "meta": { + "TransactionIndex": 0, + "AffectedNodes": [ + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 51901464, + "PreviousTxnID": "607A53B712B938B1475D194EC4F3318E6EC4BACD430D6C5437AA4018F1754A2A", + "LedgerIndex": "45806910346E5E79AE202994014742DEDA552A6197C19E03C4DC5C5466A00DB2", + "PreviousFields": { + "Balance": "120000000" + }, + "FinalFields": { + "Flags": 0, + "Sequence": 2, + "OwnerCount": 0, + "Balance": "220303257120000", + "Account": "r3a8tn1ubcP13np3giaLYzkmVKfnhLP2BL" + } + } + }, + { + "ModifiedNode": { + "LedgerEntryType": "AccountRoot", + "PreviousTxnLgrSeq": 44734671, + "PreviousTxnID": "20F2F95E4612296B1A82CC72F0DC53C9EAA8DA1557A0D0AD6C1E3BCA7E67E7CE", + "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", + "PreviousFields": { + "Sequence": 14, + "Balance": "3730330148609091" + }, + "FinalFields": { + "Flags": 1048576, + "Sequence": 15, + "OwnerCount": 10, + "Balance": "3510027011484091", + "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" + } + } + } + ], + "TransactionResult": "tesSUCCESS", + "delivered_amount": "220303137120000" + } + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/stellar-api_accounts_GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX_payments__limit_25_order_desc.json b/mock/ext-api-data/stellar-api_accounts_GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX_payments__limit_25_order_desc.json new file mode 100644 index 000000000..2cecc0b5e --- /dev/null +++ b/mock/ext-api-data/stellar-api_accounts_GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX_payments__limit_25_order_desc.json @@ -0,0 +1,792 @@ +{ + "_links": { + "self": { + "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?cursor=\u0026limit=25\u0026order=desc" + }, + "next": { + "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?cursor=99566434367078401\u0026limit=25\u0026order=desc" + }, + "prev": { + "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?cursor=126805490620608513\u0026limit=25\u0026order=asc" + } + }, + "_embedded": { + "records": [ + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/126805490620608513" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/9fbf86268628fc41da6c984a764793f43bcac3b92ed2add6c87ecd0c9fe4d648" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/126805490620608513/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=126805490620608513" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=126805490620608513" + } + }, + "id": "126805490620608513", + "paging_token": "126805490620608513", + "transaction_successful": true, + "source_account": "GCTUYXRTC2OPWWUCE6KBQEJTDFALN6BWHUXT3IHCXMTHW5K46NJCVHYN", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-06T16:52:06Z", + "transaction_hash": "9fbf86268628fc41da6c984a764793f43bcac3b92ed2add6c87ecd0c9fe4d648", + "asset_type": "native", + "from": "GCTUYXRTC2OPWWUCE6KBQEJTDFALN6BWHUXT3IHCXMTHW5K46NJCVHYN", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "8354897.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/126804090461483009" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/b8a8a1df708ff34b0db62551fd2fe6ee9dcbdd2167b0c1460d4eee4d091c7389" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/126804090461483009/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=126804090461483009" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=126804090461483009" + } + }, + "id": "126804090461483009", + "paging_token": "126804090461483009", + "transaction_successful": true, + "source_account": "GB76DZDZQRUGK3KEINZM6YDZI5OPVAP6UTIZKZIFNTRMG5T7UC5IRVRE", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-06T16:21:22Z", + "transaction_hash": "b8a8a1df708ff34b0db62551fd2fe6ee9dcbdd2167b0c1460d4eee4d091c7389", + "asset_type": "native", + "from": "GB76DZDZQRUGK3KEINZM6YDZI5OPVAP6UTIZKZIFNTRMG5T7UC5IRVRE", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "119470463.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/126755664705576961" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/0a0c5de254df371f62c4eab051bc602abb54fe888aa8af157430dba4671d0534" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/126755664705576961/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=126755664705576961" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=126755664705576961" + } + }, + "id": "126755664705576961", + "paging_token": "126755664705576961", + "transaction_successful": true, + "source_account": "GCTUYXRTC2OPWWUCE6KBQEJTDFALN6BWHUXT3IHCXMTHW5K46NJCVHYN", + "type": "payment", + "type_i": 1, + "created_at": "2020-05-05T23:08:29Z", + "transaction_hash": "0a0c5de254df371f62c4eab051bc602abb54fe888aa8af157430dba4671d0534", + "asset_type": "native", + "from": "GCTUYXRTC2OPWWUCE6KBQEJTDFALN6BWHUXT3IHCXMTHW5K46NJCVHYN", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "5.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/126341642743132161" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/a9b7c2eb386c3a26e3e8dd3a5fcb38ce888d7dc8397d447ac60891e58a3bbd19" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/126341642743132161/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=126341642743132161" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=126341642743132161" + } + }, + "id": "126341642743132161", + "paging_token": "126341642743132161", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2020-04-29T17:54:59Z", + "transaction_hash": "a9b7c2eb386c3a26e3e8dd3a5fcb38ce888d7dc8397d447ac60891e58a3bbd19", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GCQZSPJVBQ5Q2PLDZAFB2MQ7VKVE6G7YL3HDRADQZYZ7X65OH4PUYZFS", + "amount": "2868852.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/126020495153016833" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/ce389b4dc50a4a8d60424223876168a88dd890b11790d032ed2c462d89451552" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/126020495153016833/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=126020495153016833" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=126020495153016833" + } + }, + "id": "126020495153016833", + "paging_token": "126020495153016833", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2020-04-25T01:01:33Z", + "transaction_hash": "ce389b4dc50a4a8d60424223876168a88dd890b11790d032ed2c462d89451552", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GCGVWRW5MHZW5OB2IR6RRFYBG5NV4BXUT5GYBRH2E3FD3TVYVINA72KM", + "amount": "3000000.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/125936425463291905" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/31042b47c4377175553d967a5c6e39aaf980a54bad9b270e4fdf08baee1031d7" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/125936425463291905/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=125936425463291905" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=125936425463291905" + } + }, + "id": "125936425463291905", + "paging_token": "125936425463291905", + "transaction_successful": true, + "source_account": "GDV4KECLSZLKRVH4ZTWVAS4I3W2LPAPV66ADFFUZKGIVOTK6GMKGJT53", + "type": "payment", + "type_i": 1, + "created_at": "2020-04-23T19:25:51Z", + "transaction_hash": "31042b47c4377175553d967a5c6e39aaf980a54bad9b270e4fdf08baee1031d7", + "asset_type": "native", + "from": "GDV4KECLSZLKRVH4ZTWVAS4I3W2LPAPV66ADFFUZKGIVOTK6GMKGJT53", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "64113700.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/125936279434747905" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/3b711a9204bafe25b1cd99643a65e02b77af6c5f6d6f6b33fee4d7bee9455b4c" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/125936279434747905/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=125936279434747905" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=125936279434747905" + } + }, + "id": "125936279434747905", + "paging_token": "125936279434747905", + "transaction_successful": true, + "source_account": "GDV4KECLSZLKRVH4ZTWVAS4I3W2LPAPV66ADFFUZKGIVOTK6GMKGJT53", + "type": "payment", + "type_i": 1, + "created_at": "2020-04-23T19:22:48Z", + "transaction_hash": "3b711a9204bafe25b1cd99643a65e02b77af6c5f6d6f6b33fee4d7bee9455b4c", + "asset_type": "native", + "from": "GDV4KECLSZLKRVH4ZTWVAS4I3W2LPAPV66ADFFUZKGIVOTK6GMKGJT53", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "55.4433220" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/125387090556133377" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/1eeb1cedf9b3b55f77a8bd92570c1216b4b4c88b6467ff17e62fed84df0060ee" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/125387090556133377/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=125387090556133377" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=125387090556133377" + } + }, + "id": "125387090556133377", + "paging_token": "125387090556133377", + "transaction_successful": true, + "source_account": "GCWXXU6OABUNBTAAKCNSUJZN3URC72KYMYBNVGOIAIW35B5LH4AARIOL", + "type": "payment", + "type_i": 1, + "created_at": "2020-04-15T18:01:03Z", + "transaction_hash": "1eeb1cedf9b3b55f77a8bd92570c1216b4b4c88b6467ff17e62fed84df0060ee", + "asset_type": "native", + "from": "GCWXXU6OABUNBTAAKCNSUJZN3URC72KYMYBNVGOIAIW35B5LH4AARIOL", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "0.1000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/118409941953355777" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/118409941953355777/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=118409941953355777" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=118409941953355777" + } + }, + "id": "118409941953355777", + "paging_token": "118409941953355777", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2020-01-03T00:26:37Z", + "transaction_hash": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GDBX63ONLLI372D7FHJYEPKP3KOCH7HZPKJWZPYJMC5RN7L5HB4VFXLM", + "amount": "500000.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/117528387031003137" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/117528387031003137/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=117528387031003137" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=117528387031003137" + } + }, + "id": "117528387031003137", + "paging_token": "117528387031003137", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2019-12-20T23:06:36Z", + "transaction_hash": "23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GCGVWRW5MHZW5OB2IR6RRFYBG5NV4BXUT5GYBRH2E3FD3TVYVINA72KM", + "amount": "3976053.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/117004160502652929" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/a20c22cda7686d367b904ac895144be4370440f513945898881db2c2b4964718" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/117004160502652929/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=117004160502652929" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=117004160502652929" + } + }, + "id": "117004160502652929", + "paging_token": "117004160502652929", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2019-12-12T22:23:15Z", + "transaction_hash": "a20c22cda7686d367b904ac895144be4370440f513945898881db2c2b4964718", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GCGVWRW5MHZW5OB2IR6RRFYBG5NV4BXUT5GYBRH2E3FD3TVYVINA72KM", + "amount": "8711596.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/116993702257340417" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/f858cff80f985226509bc1521c141372f40bb7d3148adc62daae0dd644b51a71" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/116993702257340417/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=116993702257340417" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=116993702257340417" + } + }, + "id": "116993702257340417", + "paging_token": "116993702257340417", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2019-12-12T18:38:25Z", + "transaction_hash": "f858cff80f985226509bc1521c141372f40bb7d3148adc62daae0dd644b51a71", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GBE3MDQFTXMCGMLUYQO2MKJ7IYEYZUWHF2O62EDYKS7SF5V4SOKDQZXQ", + "amount": "100000000.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/116590456367812609" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/0c68ce53b184605a326a9f0dd94435fa49b68b3fa127d144b5db3bbba02baafe" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/116590456367812609/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=116590456367812609" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=116590456367812609" + } + }, + "id": "116590456367812609", + "paging_token": "116590456367812609", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2019-12-06T21:00:24Z", + "transaction_hash": "0c68ce53b184605a326a9f0dd94435fa49b68b3fa127d144b5db3bbba02baafe", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GCGVWRW5MHZW5OB2IR6RRFYBG5NV4BXUT5GYBRH2E3FD3TVYVINA72KM", + "amount": "2000000.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/115003345692798977" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/d4cbf471f393b51cf4f759b0ba9955dbbb146db18759f8a69eed5d6479850750" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/115003345692798977/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=115003345692798977" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=115003345692798977" + } + }, + "id": "115003345692798977", + "paging_token": "115003345692798977", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2019-11-13T17:19:32Z", + "transaction_hash": "d4cbf471f393b51cf4f759b0ba9955dbbb146db18759f8a69eed5d6479850750", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GBE3MDQFTXMCGMLUYQO2MKJ7IYEYZUWHF2O62EDYKS7SF5V4SOKDQZXQ", + "amount": "100000000.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/114412018890498053" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/fc66377172cfeb1c464ddf6f316feee565d4cb2e8c7b14e75adb301524b40e8b" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/114412018890498053/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=114412018890498053" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=114412018890498053" + } + }, + "id": "114412018890498053", + "paging_token": "114412018890498053", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2019-11-04T23:01:12Z", + "transaction_hash": "fc66377172cfeb1c464ddf6f316feee565d4cb2e8c7b14e75adb301524b40e8b", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GBEVKAYIPWC5AQT6D4N7FC3XGKRRBMPCAMTO3QZWMHHACLHTMAHAM2TP", + "amount": "1999999990.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/114412018890498052" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/fc66377172cfeb1c464ddf6f316feee565d4cb2e8c7b14e75adb301524b40e8b" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/114412018890498052/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=114412018890498052" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=114412018890498052" + } + }, + "id": "114412018890498052", + "paging_token": "114412018890498052", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2019-11-04T23:01:12Z", + "transaction_hash": "fc66377172cfeb1c464ddf6f316feee565d4cb2e8c7b14e75adb301524b40e8b", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GALAXYVOIDAOPZTDLHILAJQKCVVFMD4IKLXLSZV5YHO7VY74IWZILUTO", + "amount": "37564933050.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/114388314965975041" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/6eb38f3442543aa1aacbe8bea11d150c957507126c3198642ee5a4ed0ccea5c7" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/114388314965975041/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=114388314965975041" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=114388314965975041" + } + }, + "id": "114388314965975041", + "paging_token": "114388314965975041", + "transaction_successful": true, + "source_account": "GB6D7BSIOPC7FTRLVMVRFPBQRFXWWDU3XXFU5YFSOPN4PQALNMQC7ANB", + "type": "payment", + "type_i": 1, + "created_at": "2019-11-04T14:39:10Z", + "transaction_hash": "6eb38f3442543aa1aacbe8bea11d150c957507126c3198642ee5a4ed0ccea5c7", + "asset_type": "native", + "from": "GB6D7BSIOPC7FTRLVMVRFPBQRFXWWDU3XXFU5YFSOPN4PQALNMQC7ANB", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "100.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/110559733873651713" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/cf0f5d6b2f5367335e7df7a6909d2fc18281b2d6c5b218419614a4f6acd5f86b" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/110559733873651713/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=110559733873651713" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=110559733873651713" + } + }, + "id": "110559733873651713", + "paging_token": "110559733873651713", + "transaction_successful": true, + "source_account": "GA2JXLLIT66SWSGI4TFWMUXRXAJAHLHCISNMRUDRWFDKIVPDKZJ456T3", + "type": "payment", + "type_i": 1, + "created_at": "2019-09-09T14:02:31Z", + "transaction_hash": "cf0f5d6b2f5367335e7df7a6909d2fc18281b2d6c5b218419614a4f6acd5f86b", + "asset_type": "native", + "from": "GA2JXLLIT66SWSGI4TFWMUXRXAJAHLHCISNMRUDRWFDKIVPDKZJ456T3", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "0.0010000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/110372091047493633" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/143c6d4b236818cda7613d9dec7489056a9ba28c459d0e92f3d429bfbdf38342" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/110372091047493633/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=110372091047493633" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=110372091047493633" + } + }, + "id": "110372091047493633", + "paging_token": "110372091047493633", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2019-09-06T20:09:26Z", + "transaction_hash": "143c6d4b236818cda7613d9dec7489056a9ba28c459d0e92f3d429bfbdf38342", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GBE3MDQFTXMCGMLUYQO2MKJ7IYEYZUWHF2O62EDYKS7SF5V4SOKDQZXQ", + "amount": "100000000.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/108226441350512641" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/6cd9ea51a4f0204a797f2ebe73867c5d7f9c426e1480549570b58d00db8a854e" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/108226441350512641/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=108226441350512641" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=108226441350512641" + } + }, + "id": "108226441350512641", + "paging_token": "108226441350512641", + "transaction_successful": true, + "source_account": "GC7PA2EZIS6CMKKC4D5MA33XZQIEZKOOHK37XDTTXIH5ZCIMC3XSA7KC", + "type": "payment", + "type_i": 1, + "created_at": "2019-08-06T15:41:36Z", + "transaction_hash": "6cd9ea51a4f0204a797f2ebe73867c5d7f9c426e1480549570b58d00db8a854e", + "asset_type": "native", + "from": "GC7PA2EZIS6CMKKC4D5MA33XZQIEZKOOHK37XDTTXIH5ZCIMC3XSA7KC", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "0.0010000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/108225427738238977" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/d20b732a936851897ba2971254e03f5923f2c462067c356ee76404f6cacead64" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/108225427738238977/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=108225427738238977" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=108225427738238977" + } + }, + "id": "108225427738238977", + "paging_token": "108225427738238977", + "transaction_successful": true, + "source_account": "GA4RHS5KNMRV3AKBGACZNP2Y3VGSYSOVJANM5BFG447S2AC6PZ3YBMGC", + "type": "payment", + "type_i": 1, + "created_at": "2019-08-06T15:20:22Z", + "transaction_hash": "d20b732a936851897ba2971254e03f5923f2c462067c356ee76404f6cacead64", + "asset_type": "native", + "from": "GA4RHS5KNMRV3AKBGACZNP2Y3VGSYSOVJANM5BFG447S2AC6PZ3YBMGC", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "1.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/105398746552012801" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/e4aee643787b337f9afea878cf3ddd17c3c75de520214990b39489403ca20320" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/105398746552012801/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=105398746552012801" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=105398746552012801" + } + }, + "id": "105398746552012801", + "paging_token": "105398746552012801", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2019-06-26T19:02:17Z", + "transaction_hash": "e4aee643787b337f9afea878cf3ddd17c3c75de520214990b39489403ca20320", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GAYOCVRRNXGQWREOZBDP4UEW475NKZKLA4EIEIBKBSJN2PQQWUQ5KGUH", + "amount": "3000000.0000000" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/100705086031818753" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/9e30119a30a046f7f9dd264415c6158a19189f5335df1561b18b365b08470124" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/100705086031818753/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=100705086031818753" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=100705086031818753" + } + }, + "id": "100705086031818753", + "paging_token": "100705086031818753", + "transaction_successful": true, + "source_account": "GCGKSRT5GYBRRBJYV3KCPWH2HSUBGLQQNDSIR2IFCMAXKNR4OKFU4CVE", + "type": "payment", + "type_i": 1, + "created_at": "2019-04-16T18:24:58Z", + "transaction_hash": "9e30119a30a046f7f9dd264415c6158a19189f5335df1561b18b365b08470124", + "asset_type": "native", + "from": "GCGKSRT5GYBRRBJYV3KCPWH2HSUBGLQQNDSIR2IFCMAXKNR4OKFU4CVE", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "0.0000100" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/99566494496600065" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/e33b85359d0f0644fb907e697d73525cb636bcb989576c0d2ff1c0d1b83f958a" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/99566494496600065/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=99566494496600065" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=99566494496600065" + } + }, + "id": "99566494496600065", + "paging_token": "99566494496600065", + "transaction_successful": true, + "source_account": "GDTUSYPQNM2UGX36P2QBUQALHPXUHMAJXUR6UFZXUDPE2EQR5INQIF33", + "type": "payment", + "type_i": 1, + "created_at": "2019-03-30T18:32:03Z", + "transaction_hash": "e33b85359d0f0644fb907e697d73525cb636bcb989576c0d2ff1c0d1b83f958a", + "asset_type": "native", + "from": "GDTUSYPQNM2UGX36P2QBUQALHPXUHMAJXUR6UFZXUDPE2EQR5INQIF33", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "0.0000001" + }, + { + "_links": { + "self": { + "href": "https://horizon.stellar.org/operations/99566434367078401" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/58cb690dafc9d384409e66f066422c4d7e6893c50964c15856d38a59471749f7" + }, + "effects": { + "href": "https://horizon.stellar.org/operations/99566434367078401/effects" + }, + "succeeds": { + "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=99566434367078401" + }, + "precedes": { + "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=99566434367078401" + } + }, + "id": "99566434367078401", + "paging_token": "99566434367078401", + "transaction_successful": true, + "source_account": "GDTUSYPQNM2UGX36P2QBUQALHPXUHMAJXUR6UFZXUDPE2EQR5INQIF33", + "type": "payment", + "type_i": 1, + "created_at": "2019-03-30T18:30:49Z", + "transaction_hash": "58cb690dafc9d384409e66f066422c4d7e6893c50964c15856d38a59471749f7", + "asset_type": "native", + "from": "GDTUSYPQNM2UGX36P2QBUQALHPXUHMAJXUR6UFZXUDPE2EQR5INQIF33", + "to": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "amount": "0.0000001" + } + ] + } +} \ No newline at end of file diff --git a/mock/ext-api-data/stellar-api_transactions_23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c.json b/mock/ext-api-data/stellar-api_transactions_23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c.json new file mode 100644 index 000000000..eebec9df0 --- /dev/null +++ b/mock/ext-api-data/stellar-api_transactions_23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c.json @@ -0,0 +1,52 @@ +{ + "_links": { + "self": { + "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c" + }, + "account": { + "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" + }, + "ledger": { + "href": "https://horizon.stellar.org/ledgers/27364210" + }, + "operations": { + "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c/operations{?cursor,limit,order}", + "templated": true + }, + "effects": { + "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c/effects{?cursor,limit,order}", + "templated": true + }, + "precedes": { + "href": "https://horizon.stellar.org/transactions?order=asc\u0026cursor=117528387031003136" + }, + "succeeds": { + "href": "https://horizon.stellar.org/transactions?order=desc\u0026cursor=117528387031003136" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c" + } + }, + "id": "23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c", + "paging_token": "117528387031003136", + "successful": true, + "hash": "23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c", + "ledger": 27364210, + "created_at": "2019-12-20T23:06:36Z", + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "source_account_sequence": "25002129911447567", + "fee_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "fee_charged": 100, + "max_fee": 100, + "operation_count": 1, + "envelope_xdr": "AAAAANSEpQq63M02LHthmlMK1zL6lF7mvGyAj9qoryiJWAQrAAAAZABY004AAAAPAAAAAAAAAAAAAAABAAAAAQAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwAAAAEAAAAAjVtG3WHzbrg6RH0YlwE3W14G9J9NgMT6Jso9zriqGg8AAAAAAAAkKXhESIAAAAAAAAAAA2b459kAAABA5EcZFubvZDa2IytO64bCB85UpjzLqHIS3FBWshoigfice819SwpBYkk7xa3kIWseL/kiQBCnrIAsU7ujYAR3AIlYBCsAAABA1oF6s5NMUEJas97SMRqHgeuXxCdKetSEPBtFGlgzSPTqG6mzAGPuwibKs3HaBjdmfbwh7ffTtjAAesLHIApdCRlL7xoAAABAkADolN0l8llCFxrkqMLbbU4NNKwPsQDrYDoxERo7uvuVJgg18zMBk4t1eqXqQfiYZVeIdAN/q9zcL2SGGYJaBg==", + "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", + "result_meta_xdr": "AAAAAQAAAAIAAAADAaGLcgAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAha/UmzjlhgBY004AAAAOAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAaGLcgAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAha/UmzjlhgBY004AAAAPAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAAAABAAAAAMBoJ96AAAAAAAAAACNW0bdYfNuuDpEfRiXATdbXgb0n02AxPomyj3OuKoaDwAAABwqq724AWpTdAAAABYAAAADAAAAAAAAAAAAAAAAAQMDAwAAAAMAAAAAVMpM+DapT2QOM7rVti7Nu9zC8ZweMu0F3X3WjmI18MwAAAABAAAAALpTQaHLUccK4ssbtsuxFMwYEVe6qosFYprYXIH5kg8bAAAAAQAAAAC6le9TwqPIBkG+/CAt9sGl/SpcdU21B5eJ4qdAhRlyIwAAAAEAAAAAAAAAAAAAAAEBoYtyAAAAAAAAAACNW0bdYfNuuDpEfRiXATdbXgb0n02AxPomyj3OuKoaDwAAJEWi8AY4AWpTdAAAABYAAAADAAAAAAAAAAAAAAAAAQMDAwAAAAMAAAAAVMpM+DapT2QOM7rVti7Nu9zC8ZweMu0F3X3WjmI18MwAAAABAAAAALpTQaHLUccK4ssbtsuxFMwYEVe6qosFYprYXIH5kg8bAAAAAQAAAAC6le9TwqPIBkG+/CAt9sGl/SpcdU21B5eJ4qdAhRlyIwAAAAEAAAAAAAAAAAAAAAMBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFr9SbOOWGAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAAAAAAEBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFi6si9J0GAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAA==", + "fee_meta_xdr": "AAAAAgAAAAMBn66qAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFr9SbOOXqAFjTTgAAAA4AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAAAAAAEBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFr9SbOOWGAFjTTgAAAA4AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAA==", + "memo_type": "none", + "signatures": [ + "5EcZFubvZDa2IytO64bCB85UpjzLqHIS3FBWshoigfice819SwpBYkk7xa3kIWseL/kiQBCnrIAsU7ujYAR3AA==", + "1oF6s5NMUEJas97SMRqHgeuXxCdKetSEPBtFGlgzSPTqG6mzAGPuwibKs3HaBjdmfbwh7ffTtjAAesLHIApdCQ==", + "kADolN0l8llCFxrkqMLbbU4NNKwPsQDrYDoxERo7uvuVJgg18zMBk4t1eqXqQfiYZVeIdAN/q9zcL2SGGYJaBg==" + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/stellar-api_transactions_2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029__.json b/mock/ext-api-data/stellar-api_transactions_2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029__.json new file mode 100644 index 000000000..768d4589e --- /dev/null +++ b/mock/ext-api-data/stellar-api_transactions_2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029__.json @@ -0,0 +1,52 @@ +{ + "_links": { + "self": { + "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029" + }, + "account": { + "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" + }, + "ledger": { + "href": "https://horizon.stellar.org/ledgers/27569463" + }, + "operations": { + "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029/operations{?cursor,limit,order}", + "templated": true + }, + "effects": { + "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029/effects{?cursor,limit,order}", + "templated": true + }, + "precedes": { + "href": "https://horizon.stellar.org/transactions?order=asc\u0026cursor=118409941953355776" + }, + "succeeds": { + "href": "https://horizon.stellar.org/transactions?order=desc\u0026cursor=118409941953355776" + }, + "transaction": { + "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029" + } + }, + "id": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029", + "paging_token": "118409941953355776", + "successful": true, + "hash": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029", + "ledger": 27569463, + "created_at": "2020-01-03T00:26:37Z", + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "source_account_sequence": "25002129911447568", + "fee_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "fee_charged": 100, + "max_fee": 100, + "operation_count": 1, + "envelope_xdr": "AAAAANSEpQq63M02LHthmlMK1zL6lF7mvGyAj9qoryiJWAQrAAAAZABY004AAAAQAAAAAAAAAAAAAAABAAAAAQAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwAAAAEAAAAAw39tzVrRv+h/KdOCPU/anCP8+XqTbL8JYLsW/X04eVIAAAAAAAAEjCc5UAAAAAAAAAAAA4lYBCsAAABAM4j0FWLKI8qMUcJMO3tP4rMAoIDZdbRlFjiFNACVoAd9dCtdgBBpbi6ZnXtimE370ar19q/qrbvOKBJrnYXjC2b459kAAABAtIedy2ER3ep90HE5rEPwh03iyQRp644Sm8/wK0c9sk6qPSTG2VEFEj85Jk0TrXLxDmxvnktEhPyec67ZcdxfDrEQC4sAAABAoabKlFbeUmDTtAiGVOHthzrCZHK8mpyFkKIS7QzjL4a6ASQ6RweWNUKedUBj4uuO5z1vHDr3I5EiLUhK8xceAQ==", + "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", + "result_meta_xdr": "AAAAAQAAAAIAAAADAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYurIvScogBY004AAAAPAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYurIvScogBY004AAAAQAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAAAABAAAAAMBlbvHAAAAAAAAAADDf23NWtG/6H8p04I9T9qcI/z5epNsvwlguxb9fTh5UgAAAAAEBsfCAWsUFwAAAAcAAAADAAAAAQAAAACEPwEuxkVAQXfespLpiilBRPdvqIsEbieyl7rz8ME0FgAAAAAAAAAIbm9kbGUua3kAAgICAAAAAwAAAABZb+AQ1x8C7yRRjZjmrWnGc3IjlX+nHwpN9kmfVrOUgwAAAAEAAAAAa+mvYlV3vvuiNbEFfIwap9J7CAY2vNceKVv68HTkxg8AAAABAAAAAOIt1YAF0nOgEaMoodWZu6F3u9zkCv+ua4tEMcnzooD+AAAAAQAAAAAAAAAAAAAAAQGkrTcAAAAAAAAAAMN/bc1a0b/ofynTgj1P2pwj/Pl6k2y/CWC7Fv19OHlSAAAEjCtAF8IBaxQXAAAABwAAAAMAAAABAAAAAIQ/AS7GRUBBd96ykumKKUFE92+oiwRuJ7KXuvPwwTQWAAAAAAAAAAhub2RsZS5reQACAgIAAAADAAAAAFlv4BDXHwLvJFGNmOatacZzciOVf6cfCk32SZ9Ws5SDAAAAAQAAAABr6a9iVXe++6I1sQV8jBqn0nsIBja81x4pW/rwdOTGDwAAAAEAAAAA4i3VgAXSc6ARoyih1Zm7oXe73OQK/65ri0QxyfOigP4AAAABAAAAAAAAAAAAAAADAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYurIvScogBY004AAAAQAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYce+7tMogBY004AAAAQAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAA=", + "fee_meta_xdr": "AAAAAgAAAAMBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFi6si9J0GAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAAAAAAEBpK03AAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFi6si9JyiAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAA==", + "memo_type": "none", + "signatures": [ + "M4j0FWLKI8qMUcJMO3tP4rMAoIDZdbRlFjiFNACVoAd9dCtdgBBpbi6ZnXtimE370ar19q/qrbvOKBJrnYXjCw==", + "tIedy2ER3ep90HE5rEPwh03iyQRp644Sm8/wK0c9sk6qPSTG2VEFEj85Jk0TrXLxDmxvnktEhPyec67ZcdxfDg==", + "oabKlFbeUmDTtAiGVOHthzrCZHK8mpyFkKIS7QzjL4a6ASQ6RweWNUKedUBj4uuO5z1vHDr3I5EiLUhK8xceAQ==" + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/tezos-api_account_tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8_op__limit_25_order_desc_type_transaction_delegation.json b/mock/ext-api-data/tezos-api_account_tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8_op__limit_25_order_desc_type_transaction_delegation.json new file mode 100644 index 000000000..1f71af453 --- /dev/null +++ b/mock/ext-api-data/tezos-api_account_tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8_op__limit_25_order_desc_type_transaction_delegation.json @@ -0,0 +1,163 @@ +{ + "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", + "address_type": "ed25519", + "delegate": "", + "manager": "", + "pubkey": "edpkvKiFTVXxttCcDa2N6QfwgsnWHoEQdYRsVfUDBWPXJbhBPQpLVk", + "first_in": 797595, + "first_out": 797612, + "last_in": 797595, + "last_out": 797612, + "first_seen": 797595, + "last_seen": 797612, + "delegated_since": 0, + "delegate_since": 0, + "first_in_time": "2020-01-26T23:49:01Z", + "first_out_time": "2020-01-27T00:06:01Z", + "last_in_time": "2020-01-26T23:49:01Z", + "last_out_time": "2020-01-27T00:06:01Z", + "first_seen_time": "2020-01-26T23:49:01Z", + "last_seen_time": "2020-01-27T00:06:01Z", + "delegated_since_time": "0001-01-01T00:00:00Z", + "delegate_since_time": "0001-01-01T00:00:00Z", + "total_received": 0.01, + "total_sent": 0.007, + "total_burned": 0, + "total_fees_paid": 0.003, + "total_rewards_earned": 0, + "total_fees_earned": 0, + "total_lost": 0, + "frozen_deposits": 0, + "frozen_rewards": 0, + "frozen_fees": 0, + "unclaimed_balance": 0, + "spendable_balance": 0, + "total_balance": 0, + "delegated_balance": 0, + "total_delegations": 0, + "active_delegations": 0, + "is_funded": false, + "is_activated": false, + "is_vesting": false, + "is_spendable": true, + "is_delegatable": false, + "is_delegated": false, + "is_revealed": false, + "is_delegate": false, + "is_active_delegate": false, + "is_contract": false, + "blocks_baked": 0, + "blocks_missed": 0, + "blocks_stolen": 0, + "blocks_endorsed": 0, + "slots_endorsed": 0, + "slots_missed": 0, + "n_ops": 3, + "n_ops_failed": 0, + "n_tx": 2, + "n_delegation": 0, + "n_origination": 0, + "n_proposal": 0, + "n_ballot": 0, + "token_gen_min": 0, + "token_gen_max": 0, + "grace_period": 0, + "staking_balance": 0, + "rolls": 0, + "rich_rank": 0, + "traffic_rank": 0, + "flow_rank": 0, + "last_bake_height": 0, + "last_bake_block": "", + "last_bake_time": "0001-01-01T00:00:00Z", + "last_endorse_height": 0, + "last_endorse_block": "", + "last_endorse_time": "0001-01-01T00:00:00Z", + "next_bake_height": 0, + "next_bake_priority": 0, + "next_bake_time": "0001-01-01T00:00:00Z", + "next_endorse_height": 0, + "next_endorse_time": "0001-01-01T00:00:00Z", + "ops": [ + { + "row_id": 20862164, + "hash": "ooLrNAP233Qvoz3AGvjRjhk1fjG7z19UfyLEGBm1rwfHn4NSVhd", + "type": "transaction", + "block": "BMRy3L1EEkPrmv4UwTUsFNnD3Q25hVB36VyN5Tx5G96vUpfkiR1", + "time": "2020-01-27T00:06:01Z", + "height": 797612, + "cycle": 194, + "counter": 2946274, + "op_n": 50, + "op_l": 3, + "op_p": 2, + "op_c": 1, + "op_i": 0, + "status": "applied", + "is_success": true, + "is_contract": false, + "gas_limit": 10600, + "gas_used": 10209, + "gas_price": 0.14693, + "storage_limit": 257, + "storage_size": 0, + "storage_paid": 0, + "volume": 0.007, + "fee": 0.0015, + "reward": 0, + "deposit": 0, + "burned": 0, + "is_internal": false, + "has_data": false, + "days_destroyed": 0.000083, + "sender": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", + "receiver": "tz1KqtebPYZopqj65E6qPseW2GDGVgUs82wK", + "branch_id": 797612, + "branch_height": 797611, + "branch_depth": 1, + "branch": "BMEPJ9BA41LZKuS9ywVQAvdtV7SHqiKU6vmFsxPSEUzCLZ2pG5D", + "is_implicit": false, + "entrypoint_id": 0 + }, + { + "row_id": 20861661, + "hash": "op2f6FPSKhzKcN6o2uUNETUrgF4vX8pAEyRJb4k9uPnAFEoJjYq", + "type": "transaction", + "block": "BMJtDFTTaWABiv8ye1qALB5Jss2wQz3CFYjrMVhTX8yBWA8dttt", + "time": "2020-01-26T23:49:01Z", + "height": 797595, + "cycle": 194, + "counter": 2555733, + "op_n": 19, + "op_l": 3, + "op_p": 0, + "op_c": 0, + "op_i": 0, + "status": "applied", + "is_success": true, + "is_contract": false, + "gas_limit": 10307, + "gas_used": 10207, + "gas_price": 0.1258, + "storage_limit": 277, + "storage_size": 0, + "storage_paid": 0, + "volume": 0.01, + "fee": 0.001284, + "reward": 0, + "deposit": 0, + "burned": 0.257, + "is_internal": false, + "has_data": false, + "days_destroyed": 0.019403, + "sender": "tz1VwmmesDxud2BJEyDKUTV5T5VEP8tGBKGD", + "receiver": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", + "branch_id": 797595, + "branch_height": 797594, + "branch_depth": 1, + "branch": "BLcdWDBAN4N38tnsEGMT8vorsKeMgAbCN154AM93eZ348uhZGWy", + "is_implicit": false, + "entrypoint_id": 0 + } + ] +} diff --git a/mock/ext-api-data/theta-api_accounttx_0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f__isEqualType_true_limitNumber_100_pageNumber_1_type_2.json b/mock/ext-api-data/theta-api_accounttx_0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f__isEqualType_true_limitNumber_100_pageNumber_1_type_2.json new file mode 100644 index 000000000..ba75bbf7a --- /dev/null +++ b/mock/ext-api-data/theta-api_accounttx_0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f__isEqualType_true_limitNumber_100_pageNumber_1_type_2.json @@ -0,0 +1,2527 @@ +{ + "type": "account_tx_list", + "body": [ + { + "_id": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78", + "block_height": "4160784", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "1000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "52", + "signature": "0x60ae320a7a0f7f6e72ed5080830d2156f145a191197092df9eb88e7b8c7637ad01894b128b81d33b67a6516e3a6c7dc064576eb40b9516b4dc127e9845ede8c300" + } + ], + "outputs": [ + { + "address": "0x082a2aef39b6473c55ba7e28c122ed3aea0de381", + "coins": { + "thetawei": "1000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78", + "number": 31836666, + "status": "finalized", + "timestamp": "1579009947", + "type": 2 + }, + { + "_id": "0x43804bbc7ff254f5eb3ff0a9bc1feed5788cbbc3eb5b535c52de4c47c8963dfd", + "block_height": "4160736", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "1000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "51", + "signature": "0x23cd4f14859ef6a9cd0bd820591101cd53c74d3421e01b42ca0671501afdd6f73dcf2ec8e35ceba773319ba552c0b170daa3460bf6125992e846f9d0cf839a9700" + } + ], + "outputs": [ + { + "address": "0x082a2aef39b6473c55ba7e28c122ed3aea0de381", + "coins": { + "thetawei": "1000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x43804bbc7ff254f5eb3ff0a9bc1feed5788cbbc3eb5b535c52de4c47c8963dfd", + "number": 31836430, + "status": "finalized", + "timestamp": "1579009642", + "type": 2 + }, + { + "_id": "0xf124f4a3aad047d677efda8d7f8ec7b14329d15fb1553b255e30a379cce72317", + "block_height": "4160649", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "100000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "50", + "signature": "0xdef6415ba77901c5aaff46b3d82675c71f37805bf7ee64b708f8f46f6a30356a0b30d095052452591bc8b4550650b41d5820fe8ffb3164f163609012b6561c4c00" + } + ], + "outputs": [ + { + "address": "0x082a2aef39b6473c55ba7e28c122ed3aea0de381", + "coins": { + "thetawei": "100000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xf124f4a3aad047d677efda8d7f8ec7b14329d15fb1553b255e30a379cce72317", + "number": 31835847, + "status": "finalized", + "timestamp": "1579009091", + "type": 2 + }, + { + "_id": "0xdac984b7c4dcaa5b797469c886b83e632ccac090f5511b6c5af61ad8d399247a", + "block_height": "2431518", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "15248860400000000" + }, + "sequence": "49", + "signature": "0x167c67f48664ef28d2d1a00f2ec572ce2651e523d3d51e0348b25311d8d680e4743ddb289fac786127e694179d4768a009a09ae53eaafef0df71c64534a8024900" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "0", + "tfuelwei": "15246860400000000" + } + } + ] + }, + "hash": "0xdac984b7c4dcaa5b797469c886b83e632ccac090f5511b6c5af61ad8d399247a", + "number": 17613936, + "status": "finalized", + "timestamp": "1568046061", + "type": 2 + }, + { + "_id": "0x9c16b1fd23c9cc53ea369eaf54ee73a57c82c33c80c2a919ecea253324a1a32e", + "block_height": "2430944", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xe9a02df5a59f9bd2b94adf0f8dc7f2311742a907", + "coins": { + "thetawei": "0", + "tfuelwei": "100000000000000000" + }, + "sequence": "1", + "signature": "0x4e34f9e1f9d541eb91b26f8814ad6c989378d528ac5b1ec41e9c7c23eeadfe7e2a58d522ba95fe6e2639011bfc3a49df44fbfd78338aac37f541e962da38b65100" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "99998000000000000" + } + } + ] + }, + "hash": "0x9c16b1fd23c9cc53ea369eaf54ee73a57c82c33c80c2a919ecea253324a1a32e", + "number": 17609546, + "status": "finalized", + "timestamp": "1568042434", + "type": 2 + }, + { + "_id": "0x0345f986a0401b124d437c819d424ed9673d3720a0cb18600a7f3f0adb172e63", + "block_height": "2430934", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "100002000000000000" + }, + "sequence": "48", + "signature": "0x754582f5b22f94c73d9b88af6adcd4b802939c9e59959412d1417c93b37b8e57129c76a66f2abef675e4715cd7f855faae0cd2f95bb5d0f12bfbe819faf3802f01" + } + ], + "outputs": [ + { + "address": "0xe9a02df5a59f9bd2b94adf0f8dc7f2311742a907", + "coins": { + "thetawei": "0", + "tfuelwei": "100000000000000000" + } + } + ] + }, + "hash": "0x0345f986a0401b124d437c819d424ed9673d3720a0cb18600a7f3f0adb172e63", + "number": 17609465, + "status": "finalized", + "timestamp": "1568042371", + "type": 2 + }, + { + "_id": "0xa28493e76cc5f22a2b2f1514ad983162186dc1e46158f0abd7053c9c14b8d48e", + "block_height": "1574584", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "10000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "47", + "signature": "0x8edf83cbd7ffb06c3580d17c95037e3f57e829390be80818e5644805a8a872ca385c705cc503488580ef5695882c8325ff55db6b91d3d98abb5f0d1ed4d5a98d01" + } + ], + "outputs": [ + { + "address": "0x082a2aef39b6473c55ba7e28c122ed3aea0de381", + "coins": { + "thetawei": "10000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xa28493e76cc5f22a2b2f1514ad983162186dc1e46158f0abd7053c9c14b8d48e", + "number": 12099631, + "status": "finalized", + "timestamp": "1562652647", + "type": 2 + }, + { + "_id": "0x37e130bdc7c189c02323191206b7d4d8083ee070704028aa6fd52c958cd782a6", + "block_height": "1564408", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "1000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "46", + "signature": "0x838ea223d3572f7a3a390d54aa284e6f2d5ca61fb3b3d4b0902354b530a48cef22e3436da51b8537e045ea62d04cbdc2252a0f7f0059d424a5ceac3ed60db8a001" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "1000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x37e130bdc7c189c02323191206b7d4d8083ee070704028aa6fd52c958cd782a6", + "number": 12056948, + "status": "finalized", + "timestamp": "1562589035", + "type": 2 + }, + { + "_id": "0x4f909d1e5ba2eba387e62dd235ceec9661db5e28138abd4bcb417f331a9461e2", + "block_height": "732538", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "5301960000000000" + }, + "sequence": "45", + "signature": "0xcd14b396f60dd1c943cd23b28c0218f2d292c30c3a8080bf88c201bbb5a9012033248b990de4674e41f257bdf85d8d919580d1681f25a7833cbfe9049df9dc4300" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "0", + "tfuelwei": "5299960000000000" + } + } + ] + }, + "hash": "0x4f909d1e5ba2eba387e62dd235ceec9661db5e28138abd4bcb417f331a9461e2", + "number": 7939449, + "status": "finalized", + "timestamp": "1557340224", + "type": 2 + }, + { + "_id": "0xdd10a6896132dd9873940dfba64c1bc450e9932ba7b09eeb002c687b7ff4f311", + "block_height": "729931", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "55000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "13", + "signature": "0x5a952dda238650d59315b4ce317cd2829339a3413ce93ef24c80c6ea8dc467e342612cf5527e61dd6d0aa289cb01b73e7b4337a53f03c9b1f97789486216f78d01" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "55000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xdd10a6896132dd9873940dfba64c1bc450e9932ba7b09eeb002c687b7ff4f311", + "number": 7925499, + "status": "finalized", + "timestamp": "1557323764", + "type": 2 + }, + { + "_id": "0x558cb5ec877119c2c84a677277efb5b3059adb830c6e74971b3dbe93221b7132", + "block_height": "700327", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "44326000000000000" + }, + "sequence": "44", + "signature": "0x96722b9dabab76bacfb22ee4b15d6e30f7565e3f62f69635227dac860a2228dd753e1ce5bb14fba9d3760aa2a45053ff9f0c218a11dab2ef45a3dcc05d17bfa201" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "0", + "tfuelwei": "44324000000000000" + } + } + ] + }, + "hash": "0x558cb5ec877119c2c84a677277efb5b3059adb830c6e74971b3dbe93221b7132", + "number": 7785266, + "status": "finalized", + "timestamp": "1557136821", + "type": 2 + }, + { + "_id": "0x413d8423fd1e6df99fc57f425dfd58c791c877657b364c62c15905ade5114a70", + "block_height": "700321", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "4000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "43", + "signature": "0xb6b6c09b6942cbbb972b190e6f6dc3ade0e56953aca33718e6f7da9eac450029676104f21a111a0a5a11d09c3f4b828061e2fe3fad9616a4af036b2e4bd5f8fb01" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "4000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x413d8423fd1e6df99fc57f425dfd58c791c877657b364c62c15905ade5114a70", + "number": 7785228, + "status": "finalized", + "timestamp": "1557136781", + "type": 2 + }, + { + "_id": "0xcd4072f7557bc943e17807b532deb4022b875d72a575da6d68d97f309a27e0aa", + "block_height": "700276", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "0", + "tfuelwei": "4236000000000000" + }, + "sequence": "12", + "signature": "0xed80cac7c8a7eab70ad64aa41536b2387890360e8bcc12996f478ad29670326168331ad4d92576ea7eac59963d169f804214117f155853f2b05f09d42983c4d800" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "4234000000000000" + } + } + ] + }, + "hash": "0xcd4072f7557bc943e17807b532deb4022b875d72a575da6d68d97f309a27e0aa", + "number": 7785052, + "status": "finalized", + "timestamp": "1557136496", + "type": 2 + }, + { + "_id": "0x97d9bd2d04691c8580216ef31f9934641fa1f20c41b2f6d31b94cb93a0c8dd02", + "block_height": "700266", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "514355440000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "11", + "signature": "0xf93200a589c0bb9e5904a315d3ddeb01eb2ef7c6012b9d868731db2c83f8a103357c97576f35f9797952504aa3119bcda55eb8d9043696e310ed671e50536c4e00" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "514355440000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x97d9bd2d04691c8580216ef31f9934641fa1f20c41b2f6d31b94cb93a0c8dd02", + "number": 7785014, + "status": "finalized", + "timestamp": "1557136431", + "type": 2 + }, + { + "_id": "0x48482084bb395439b8ce2c6fc28ab75f06793b8e54e79bf795aacc194d82e25e", + "block_height": "665871", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "100002000000000000" + }, + "sequence": "42", + "signature": "0xca0ae518aa8999fe071fd199bef5be946a669563edda323e143b78cb4d7fc13673aae5d727de1c30577cf788b3fd19ade0057a553b445cc8184eb259990d291900" + } + ], + "outputs": [ + { + "address": "0x351e35bf70f2228a6e34ed27c664240043a02f94", + "coins": { + "thetawei": "0", + "tfuelwei": "100000000000000000" + } + } + ] + }, + "hash": "0x48482084bb395439b8ce2c6fc28ab75f06793b8e54e79bf795aacc194d82e25e", + "number": 7618201, + "status": "finalized", + "timestamp": "1556919195", + "type": 2 + }, + { + "_id": "0x2f356f071a2e71aab3024906cc1d88538694ddd1087ac16d52d340d6a21fd83e", + "block_height": "583831", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "5500000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "41", + "signature": "0xfcdacd1d546f04cbb496eac3002bf8ce14b0d01fe6527bd0da72c9dd8d650a49696abe9ddf42edc1c934329e62aff5ff65f5a0dacea153bed0c6a3bd976f588901" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "5500000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x2f356f071a2e71aab3024906cc1d88538694ddd1087ac16d52d340d6a21fd83e", + "number": 7224733, + "status": "finalized", + "timestamp": "1556401357", + "type": 2 + }, + { + "_id": "0x0ed264b12694f0d0279012167a523dfa378fd1573923134e47e000412c18d7bf", + "block_height": "556079", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "502000000000000" + }, + "sequence": "40", + "signature": "0x754499d7b317867e434474221334eb105e6d60aaba96d7160a4c66c556f1906f7c04583c73137ce55fdd09d710e8c9cc4f05de15febdfeadbd48a89241d78bf400" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "0", + "tfuelwei": "500000000000000" + } + } + ] + }, + "hash": "0x0ed264b12694f0d0279012167a523dfa378fd1573923134e47e000412c18d7bf", + "number": 7085187, + "status": "finalized", + "timestamp": "1556226228", + "type": 2 + }, + { + "_id": "0x43a7e20dcf5b1e29b545b4d0c4f3d510317cada73648665630a77d0b83d2b4e7", + "block_height": "541058", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "202000000000000" + }, + "sequence": "39", + "signature": "0x4582a94ba36c6a56845f6863560d97d84fed9474b3b8182c4fa69cffa69c91ac3fb70fc92ccd7d441c035afc70b1e944b4aa6203c4444e7f1c483787ad16f5be00" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "0", + "tfuelwei": "200000000000000" + } + } + ] + }, + "hash": "0x43a7e20dcf5b1e29b545b4d0c4f3d510317cada73648665630a77d0b83d2b4e7", + "number": 7007032, + "status": "finalized", + "timestamp": "1556131470", + "type": 2 + }, + { + "_id": "0x8238c514e998706067720c7cc4f91605da8e4d8e7c9d8eca1bc798ae0e30f416", + "block_height": "540383", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "552000000000000" + }, + "sequence": "38", + "signature": "0xaedf23eb1f81d6d171c0442976f49eb22676226b04e9c8815f7a410f2307525a446026dc1c1084449cee19402a3e0d279b5dc77caecf31b1e9c1a83783abe77b01" + } + ], + "outputs": [ + { + "address": "0x2971e95728a971f92b79589567b00fa370a86a61", + "coins": { + "thetawei": "0", + "tfuelwei": "550000000000000" + } + } + ] + }, + "hash": "0x8238c514e998706067720c7cc4f91605da8e4d8e7c9d8eca1bc798ae0e30f416", + "number": 7002267, + "status": "finalized", + "timestamp": "1556127205", + "type": 2 + }, + { + "_id": "0xc9d604aa1e78f0ef08bfafd104b1806146315bc9c7737bbc7645742ea9456200", + "block_height": "540326", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "150002000000000000" + }, + "sequence": "37", + "signature": "0xb0ffada03a9add0d826126a0e65d1ed5ca78adcaf2a2a201b40c09a0dd8d3100221a89c5654cc1d811fff2a374133cd3a7ba761e98da881c47697f8521a4cbdd00" + } + ], + "outputs": [ + { + "address": "0x2971e95728a971f92b79589567b00fa370a86a61", + "coins": { + "thetawei": "0", + "tfuelwei": "150000000000000000" + } + } + ] + }, + "hash": "0xc9d604aa1e78f0ef08bfafd104b1806146315bc9c7737bbc7645742ea9456200", + "number": 7001830, + "status": "finalized", + "timestamp": "1556126848", + "type": 2 + }, + { + "_id": "0x5d67e2fb6509fde58281b565ec4aa10f642bdfe4197b8cc4d203d29fb5171974", + "block_height": "539967", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "8855440000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "36", + "signature": "0xea42ebb3bee2f4636a07eeeb0a72ec8364203dffa111bc050f558c726c2fc1d643e0e93e8f92cf120c53e91e370e78e149b3c657b38221a4fb2d88f471f60fa200" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "8855440000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x5d67e2fb6509fde58281b565ec4aa10f642bdfe4197b8cc4d203d29fb5171974", + "number": 6999082, + "status": "finalized", + "timestamp": "1556124581", + "type": 2 + }, + { + "_id": "0xd77abaf300edc06c1fa54f92bfb0f27dff5e41008ca0ef1dbd747a56cb67916a", + "block_height": "539799", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "500000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "35", + "signature": "0xdf9a59ff6596ccf5dcb9c71447ea6a61a037dba407ef26ff467f7fbfa9c42fae534b537d3e8ee3be9408f483fc2198ddbe23f6bb9a4137ecc38d9c8e021ed14300" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "500000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xd77abaf300edc06c1fa54f92bfb0f27dff5e41008ca0ef1dbd747a56cb67916a", + "number": 6997917, + "status": "finalized", + "timestamp": "1556123520", + "type": 2 + }, + { + "_id": "0xa5584debb3f26fb087b573f01dc5fd1bfa2cca160eb8b95b77e9ba20e06d0f6b", + "block_height": "522707", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "44126500000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "10", + "signature": "0x235b125bcfb8015ce4b71b2fbbe75785e10acd6beda3b205e87a586ec3daf05461ac1e95ee41c07d56663ec1a3ac457cfc90b6807513178ba28dd7516a4509dc00" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "44126500000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xa5584debb3f26fb087b573f01dc5fd1bfa2cca160eb8b95b77e9ba20e06d0f6b", + "number": 6914377, + "status": "finalized", + "timestamp": "1556015687", + "type": 2 + }, + { + "_id": "0x85671ec5bad6e347e6e91e04f57d052678c7d60a67aac2ba6b77ed358ab6da80", + "block_height": "522700", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "44126500000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "34", + "signature": "0x8e82cc09e462a23d61b17ca6e3c0d564119b3ddb2b43f5791fda02fb7c9b0bad17feb35ea6c9ffc95b2e6295ffb4df2a61e677b68176ef738d4023b4c81ade9e01" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "44126500000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x85671ec5bad6e347e6e91e04f57d052678c7d60a67aac2ba6b77ed358ab6da80", + "number": 6914351, + "status": "finalized", + "timestamp": "1556015641", + "type": 2 + }, + { + "_id": "0xaa758472a734a6672b27cab5b0963286a36457f25df8734e2efa87d65b36f8e9", + "block_height": "522682", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "44126498000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "9", + "signature": "0x39efdd9f02dcbe6de02b04f399a0ca312948b158a69b6ff77cc6624bc62b7cb03e42c34e706d2c8cea5da95e038180c47083777ae81cc08bac1ceac18ba3187f00" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "44126498000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xaa758472a734a6672b27cab5b0963286a36457f25df8734e2efa87d65b36f8e9", + "number": 6914279, + "status": "finalized", + "timestamp": "1556015528", + "type": 2 + }, + { + "_id": "0xd0cde1d4d5882aa8500147ef5f8596f7065ef4802d2b404e14f7e11d88d0492d", + "block_height": "522657", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "44126496000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "33", + "signature": "0xa7a1be3a61c5689020da1436defa0908f5e296a9b389e68786d7483d0beaa4cc47b94fd972861e5e46bd339d69d2ee1008ffc9cc27bb8b9b0d44e8fcac0b218601" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "44126496000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xd0cde1d4d5882aa8500147ef5f8596f7065ef4802d2b404e14f7e11d88d0492d", + "number": 6914165, + "status": "finalized", + "timestamp": "1556015370", + "type": 2 + }, + { + "_id": "0x18a9a03057fd73d74af779dca017ab060f657e6cafd17caeed377593f87e78fc", + "block_height": "522632", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "4999998000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "8", + "signature": "0x7873a6aa0aff1b2df83127bd8c7848d7580c9525d8e006cf730ace22fa92e6eb7e2a9183bf1e6509946dbd8bfa96350d8bdbb0006b4604df630dc2d9213f419a00" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "4999998000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x18a9a03057fd73d74af779dca017ab060f657e6cafd17caeed377593f87e78fc", + "number": 6914059, + "status": "finalized", + "timestamp": "1556015211", + "type": 2 + }, + { + "_id": "0xa7dacd47efeb1b7ff3de61c6796db0140c89b4bc371ac5d6366f2c81dd53eeee", + "block_height": "522353", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "5000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "32", + "signature": "0x7348da0a98909eb1e6dee672224ed8564b0363be55b2029a35e3b0ed4007caea556ab5f0b90f7a31da9d2ee4fb702491ceca8cc1ac5d2b7c57675ada137680d401" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "5000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xa7dacd47efeb1b7ff3de61c6796db0140c89b4bc371ac5d6366f2c81dd53eeee", + "number": 6912886, + "status": "finalized", + "timestamp": "1556013450", + "type": 2 + }, + { + "_id": "0xdc2af10591897be486f29d29b3896dd42c516b2845959ce32fdb744fe0816377", + "block_height": "522338", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "44126500000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "7", + "signature": "0x90a6afdec766f3fc5276d7b026173a0175894398fb9f90fc31f3769d578628e7390676d07609bb7977eaa8cd9b624788f9cc9a738722d1e9cfa07aa44bd9d79b01" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "44126500000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xdc2af10591897be486f29d29b3896dd42c516b2845959ce32fdb744fe0816377", + "number": 6912829, + "status": "finalized", + "timestamp": "1556013355", + "type": 2 + }, + { + "_id": "0x319026f316a1d180dbf9bc304be7f8797cf311a57628c6498fa31b88a0d604a4", + "block_height": "522317", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "2000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "31", + "signature": "0x64863e2f7f6ca1a6c2ef6011bb754df743ae87a8688f29daaa7acf19d833ff1853f8f9faafe9901078f88492450329357b68f2d7d9fab504db082b80b988e2ab00" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "2000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x319026f316a1d180dbf9bc304be7f8797cf311a57628c6498fa31b88a0d604a4", + "number": 6912743, + "status": "finalized", + "timestamp": "1556013222", + "type": 2 + }, + { + "_id": "0x9957ae551fc4dd001c8d3f55fa4abe28416f2bd8d3050d36c1e3f37f15a63388", + "block_height": "520920", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xefa0d997cfe96ff0b452e420b1434f05106c05b8", + "coins": { + "thetawei": "0", + "tfuelwei": "10002000000000000" + }, + "sequence": "3", + "signature": "0xa3fd8dd6a33d89a3fbb675de70372a476d37bac91df4f3e5fe38f80999f6297c62d02360ce883abd9c6a5e3f5094290bdfb2c3dfdd804152383f9a5db3c9c12b01" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "10000000000000000" + } + } + ] + }, + "hash": "0x9957ae551fc4dd001c8d3f55fa4abe28416f2bd8d3050d36c1e3f37f15a63388", + "number": 6907879, + "status": "finalized", + "timestamp": "1556004406", + "type": 2 + }, + { + "_id": "0x206b7926caea20ca6143ec5a53d08b1196c297fec4fef89e44172b7b2df77115", + "block_height": "520914", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xefa0d997cfe96ff0b452e420b1434f05106c05b8", + "coins": { + "thetawei": "2000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "2", + "signature": "0xe6068f24b67e3a07035e761154f11e4322809f709522b39f846fca5fcc6c3b74761a82d3f3655b8147b24d5bcedfccf2387f2677e3afffe6e3ca660e8ec64a8d00" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "2000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x206b7926caea20ca6143ec5a53d08b1196c297fec4fef89e44172b7b2df77115", + "number": 6907855, + "status": "finalized", + "timestamp": "1556004366", + "type": 2 + }, + { + "_id": "0x1df714aa5f6be1dc512ee65f8c4b3f5244d52a6e4a15efdf30b8c33214ece297", + "block_height": "515163", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "42126500000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "30", + "signature": "0xa2c8faab0a47009300f4723b01cbfd99dce795c64c2f01f7aeb17d75e6c45cd01e6d68a4e4adb1c2809f2c766615fa61a37ce2932b98c719a3ee83cd9d6ecaa600" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "42126500000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x1df714aa5f6be1dc512ee65f8c4b3f5244d52a6e4a15efdf30b8c33214ece297", + "number": 6881884, + "status": "finalized", + "timestamp": "1555968080", + "type": 2 + }, + { + "_id": "0x75b3816505dc54b8d6a15013f735790778b20c122f23bc77819eb4cc159f76f0", + "block_height": "514809", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "36893488147419103232", + "tfuelwei": "2000000000000" + }, + "sequence": "6", + "signature": "0xc2cbf3a20950d517c8dd18110362acc92890a06b4ca14dbb26a5f7ba8c49ab470bba541871daf03c16fa16fe0c0cd1e1a3df9acc87270b129dc9c24633b3e98100" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "36893488147419103232", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x75b3816505dc54b8d6a15013f735790778b20c122f23bc77819eb4cc159f76f0", + "number": 6879883, + "status": "finalized", + "timestamp": "1555965845", + "type": 2 + }, + { + "_id": "0x6317fcae6997876a388f869ca4a3b8ba27d082a7685fddb0b343639e4216a1a3", + "block_height": "514753", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "sequence": "5", + "signature": "0xa4b0c250c7d4e9cdddda8c0c1a8e29445b8efbfbca0c96216100eedceb8299db13e68898acc449e61138513b740c1043ee43a431eb07b651ea06a315177873a400" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x6317fcae6997876a388f869ca4a3b8ba27d082a7685fddb0b343639e4216a1a3", + "number": 6879560, + "status": "finalized", + "timestamp": "1555965492", + "type": 2 + }, + { + "_id": "0x5f19d4a8a83c7dc47f6040c14ef0121eed80b3d80b49742c20627da3b65c70a0", + "block_height": "514726", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "5233011852580896768", + "tfuelwei": "2000000000000" + }, + "sequence": "4", + "signature": "0x2f03352864a0798e1b918b67b688198abb01a89cc25a7c9b14242368a064902612e0954723df6ed8e595876d5a06a1a49d9f3e2ad8987e53534a5d93f69fd2d901" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "5233011852580896768", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x5f19d4a8a83c7dc47f6040c14ef0121eed80b3d80b49742c20627da3b65c70a0", + "number": 6879402, + "status": "finalized", + "timestamp": "1555965322", + "type": 2 + }, + { + "_id": "0xa5b18766f3fa9dee5b93da3bf6358098e88babe8504cad389b21db36e30a84bb", + "block_height": "514661", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "5233011852580896768", + "tfuelwei": "2000000000000" + }, + "sequence": "29", + "signature": "0x56fd0256058bf74520a1a0cfacb242dc3a83d13c45531f276dcc596b8981a47f40fe1dab7c774f15fe70faf73687adb1c91af4831f73c2ce24f297cdb4dfc27900" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "5233011852580896768", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xa5b18766f3fa9dee5b93da3bf6358098e88babe8504cad389b21db36e30a84bb", + "number": 6878999, + "status": "finalized", + "timestamp": "1555964914", + "type": 2 + }, + { + "_id": "0xa2abe6cf779790a37e1786bc71c7385e01ceba4843e59f5fd7530b6db9681f47", + "block_height": "514604", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "sequence": "3", + "signature": "0x4a8694a8418fc2f3c94f0c40298824f52b5ba635c2b30bbdc651284ffcf741882ea0c3afed5cf581be6533a19c287816cd59318ea9147de36a29528cc7a6333a01" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xa2abe6cf779790a37e1786bc71c7385e01ceba4843e59f5fd7530b6db9681f47", + "number": 6878652, + "status": "finalized", + "timestamp": "1555964552", + "type": 2 + }, + { + "_id": "0x195590302d9050a447c7a5a3b312419aad3e032f70319af1dfd1d0ebfc812941", + "block_height": "514534", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "5233009852580896768", + "tfuelwei": "2000000000000" + }, + "sequence": "2", + "signature": "0x5b1ab0af7393a7225489b8a75845ab06ef18cbae52de2a247104a5dae05cb5e87221d9213b7c82c44a825d4f720f46235996f50e56f16d2f2e74686cb69e615e01" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "5233009852580896768", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x195590302d9050a447c7a5a3b312419aad3e032f70319af1dfd1d0ebfc812941", + "number": 6878196, + "status": "finalized", + "timestamp": "1555964111", + "type": 2 + }, + { + "_id": "0x5be9eb1c1d552837c7f91f72e95563b5d2b5fd18e8e5a81454ee59de30c15a1b", + "block_height": "514405", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "36893486147419103232", + "tfuelwei": "2000000000000" + }, + "sequence": "28", + "signature": "0x4545703951750bc92c33fb085537f73e1949874c98dad687cacdff48fdebe4fc6ad22667da6908e21279e87be3aec3690469efac39ffd24f921769573fb9337201" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "36893486147419103232", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x5be9eb1c1d552837c7f91f72e95563b5d2b5fd18e8e5a81454ee59de30c15a1b", + "number": 6877410, + "status": "finalized", + "timestamp": "1555963299", + "type": 2 + }, + { + "_id": "0x653626d2fb460cfee647e050b9a302df8c6ff453eafb6a59393b9072cf02245f", + "block_height": "514287", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "5233011852580896768", + "tfuelwei": "2000000000000" + }, + "sequence": "27", + "signature": "0x45327c09b8b9a20e72104e61be207f61ea50f3c4f7519f455f1ddbca1771a811335591ac022bcb2b123a4563c2e08f1b07b7615d1e2dcce9639938d7bbdb50ee01" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "5233011852580896768", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x653626d2fb460cfee647e050b9a302df8c6ff453eafb6a59393b9072cf02245f", + "number": 6876766, + "status": "finalized", + "timestamp": "1555962555", + "type": 2 + }, + { + "_id": "0x6e154a4bdcebbf3464f6aaa7e0cacc2a52ef41e7b82813f341fcccfb05f70a50", + "block_height": "480727", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "4568500000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "1", + "signature": "0x23443c1b9b8542152d886bcc1552c92e6c34d5817b8d8039e37c53af250567377906d416963f31376a16303ed13b198b37134ab27d9a21e4de5e1837415e4a5700" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "4568500000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x6e154a4bdcebbf3464f6aaa7e0cacc2a52ef41e7b82813f341fcccfb05f70a50", + "number": 6758583, + "status": "finalized", + "timestamp": "1555750809", + "type": 2 + }, + { + "_id": "0xc83a3315d61211df66faebf10442a90b28c4e0b1b44a43907c4b160472e3e2d4", + "block_height": "448487", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "10002000000000000" + }, + "sequence": "26", + "signature": "0x42ced3509f6c3d5a1667d833e4405eb8c9fbc9787030adad9071432b78fc2d3a4a60f45bdb28c7c04d739715777637f28239c2ba41d9a01cf81a565d6777f6a000" + } + ], + "outputs": [ + { + "address": "0xd54d386b0590024ea00641ba0e9f4aaf52f9018e", + "coins": { + "thetawei": "0", + "tfuelwei": "10000000000000000" + } + } + ] + }, + "hash": "0xc83a3315d61211df66faebf10442a90b28c4e0b1b44a43907c4b160472e3e2d4", + "number": 6335899, + "status": "finalized", + "timestamp": "1555544770", + "type": 2 + }, + { + "_id": "0x311317eb46ca5e6a256ef87cfac85c3467ba8c850ff447575c6408e89e2a74dd", + "block_height": "448484", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "25", + "signature": "0x888a3b81c57e8aafb3f10259e78c9b0d299fac0ded08f9cce89ae13dc0cb4e796defac90b538cd19cb9426da87491fcbcacdce45b7cdf07c83538e62bc6a106501" + } + ], + "outputs": [ + { + "address": "0xd54d386b0590024ea00641ba0e9f4aaf52f9018e", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x311317eb46ca5e6a256ef87cfac85c3467ba8c850ff447575c6408e89e2a74dd", + "number": 6335806, + "status": "finalized", + "timestamp": "1555544752", + "type": 2 + }, + { + "_id": "0x9a067fc508fa584271c8228778e205f95a8577f4ee692365c696636d51f2bc8f", + "block_height": "448415", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "10002000000000000" + }, + "sequence": "24", + "signature": "0xdd42268f51c2db654708dc9c4d2a22a9a39701e8c60b0dec2c6bcc6e6c300c9231affe1e6e265984ba74f17d898ddfd7cb4e678d755ba94aab186fe18d63e2a901" + } + ], + "outputs": [ + { + "address": "0xc3e1fe158d3ba112d744f4cd7f298b9d18a4b049", + "coins": { + "thetawei": "0", + "tfuelwei": "10000000000000000" + } + } + ] + }, + "hash": "0x9a067fc508fa584271c8228778e205f95a8577f4ee692365c696636d51f2bc8f", + "number": 6334119, + "status": "finalized", + "timestamp": "1555544303", + "type": 2 + }, + { + "_id": "0x53718be0bac341fffedf123cca2f7def587a5626e754f11384f971bc3a00dd78", + "block_height": "448411", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "10002000000000000" + }, + "sequence": "23", + "signature": "0x5c6038236849203233ff93da2b9600eb4948ef29fc5cd651e4fc53918ed9cb8037a10761cfa7e35f44685a020a7ba547394051db7c6ad52d4a180d375c265e5900" + } + ], + "outputs": [ + { + "address": "0xd74b376cfbf678249a438abe5b56fa697603008e", + "coins": { + "thetawei": "0", + "tfuelwei": "10000000000000000" + } + } + ] + }, + "hash": "0x53718be0bac341fffedf123cca2f7def587a5626e754f11384f971bc3a00dd78", + "number": 6334020, + "status": "finalized", + "timestamp": "1555544277", + "type": 2 + }, + { + "_id": "0x4b0bfdf2b4fafe0ebfe7a437dbbb156e58d674190869af4e09bfa48170a3a971", + "block_height": "448406", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "10002000000000000" + }, + "sequence": "22", + "signature": "0x5fe69b2a3946880387dd5c2f18769e772ab446f587c8d01340fd7cc8449cf7f17fa50548f22c62e62d14d4bdcc656f7ba15072f77c7819012d349aa23f21c82101" + } + ], + "outputs": [ + { + "address": "0x07f9d0b8eb1e1b4ceeaade77467ed1b8267d2d81", + "coins": { + "thetawei": "0", + "tfuelwei": "10000000000000000" + } + } + ] + }, + "hash": "0x4b0bfdf2b4fafe0ebfe7a437dbbb156e58d674190869af4e09bfa48170a3a971", + "number": 6333904, + "status": "finalized", + "timestamp": "1555544245", + "type": 2 + }, + { + "_id": "0xd48940141a190497364960403e2c4bb2aeb16cfef1be4b6d8561415b927c7f09", + "block_height": "448403", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "10002000000000000" + }, + "sequence": "21", + "signature": "0x37296db338f0d55b19989b9b1994d1020cc3ea4f22d196af4164a75fe4482c8f53f6397a9e61420ef2a6713104f954a4eecf8f3c73f9f8d49040afa1e9e6cdae01" + } + ], + "outputs": [ + { + "address": "0xe6b5af7812dd571904d0b1e313ed4ab0579308a1", + "coins": { + "thetawei": "0", + "tfuelwei": "10000000000000000" + } + } + ] + }, + "hash": "0xd48940141a190497364960403e2c4bb2aeb16cfef1be4b6d8561415b927c7f09", + "number": 6333824, + "status": "finalized", + "timestamp": "1555544226", + "type": 2 + }, + { + "_id": "0x27a005b40c064ff636939ed389f86ad79ac9b9ee60a1bff1a805a1c81058fd35", + "block_height": "448399", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "10002000000000000" + }, + "sequence": "20", + "signature": "0x78c878d6c48ff64e4f82015a663ff94fbc5a65cf36ebb20aa5e31b0c13afc6be159b5d29e1c794bf5b281523e6c2d76466acca5e20859780c8093ce86b0c7f7701" + } + ], + "outputs": [ + { + "address": "0x07f9d0b8eb1e1b4ceeaade77467ed1b8267d2d81", + "coins": { + "thetawei": "0", + "tfuelwei": "10000000000000000" + } + } + ] + }, + "hash": "0x27a005b40c064ff636939ed389f86ad79ac9b9ee60a1bff1a805a1c81058fd35", + "number": 6333737, + "status": "finalized", + "timestamp": "1555544201", + "type": 2 + }, + { + "_id": "0xbe83e79914d187f568e471c9c986b4fe800a5c61ce684eb64ad675c868e1d0fd", + "block_height": "448389", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "19", + "signature": "0x3ba6d4ad2f2a6d1556746fc3b1c7ee9f5ac4103c04a4de3f1b01dc84367b43762fb4a167ea8b946d1f2c84395df13ab0df101024c227382716970f99a838e7c800" + } + ], + "outputs": [ + { + "address": "0xc3e1fe158d3ba112d744f4cd7f298b9d18a4b049", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xbe83e79914d187f568e471c9c986b4fe800a5c61ce684eb64ad675c868e1d0fd", + "number": 6333571, + "status": "finalized", + "timestamp": "1555544135", + "type": 2 + }, + { + "_id": "0x77bf4a03f3504c9d111cf078d6b7e11773e9dc389b65cb21b79725ba45334278", + "block_height": "448330", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "18", + "signature": "0xd4e72ef6a481202f02633f15f9bec1169c54baedbee2dba11224acfda2f3a79b4fd27de62e90f0118822485b8ed1dc5a07c6323682d6ccb378ae3f87f3ea2d2200" + } + ], + "outputs": [ + { + "address": "0xd74b376cfbf678249a438abe5b56fa697603008e", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x77bf4a03f3504c9d111cf078d6b7e11773e9dc389b65cb21b79725ba45334278", + "number": 6332075, + "status": "finalized", + "timestamp": "1555543751", + "type": 2 + }, + { + "_id": "0xbc3b3ac526e78e0e607a35047172cfae09c5441c03992d814943ae59165c7465", + "block_height": "448116", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "17", + "signature": "0xf896284d9f6e2b941063c01000d63869b0d1b4c94b8d8266468a6f813a11dd8d44caf2cd8ec07eea28379b70f7a9a89816c23f0ebb15b3273755f5396ca9b8ac01" + } + ], + "outputs": [ + { + "address": "0x25c69e1d90677bb717ac506c2760670b346e35a6", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xbc3b3ac526e78e0e607a35047172cfae09c5441c03992d814943ae59165c7465", + "number": 6326704, + "status": "finalized", + "timestamp": "1555542360", + "type": 2 + }, + { + "_id": "0x76578714ca49fa9b94773a26da2bd1ade7c76c45d22112f5b7c92581e53db4ef", + "block_height": "448112", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "16", + "signature": "0xc452595b91be0e5e515b48a00f7d35a1420318a304f89877b7f5cd5643bc3e3d784894f2605bb69efa59aa93d37a5260f4df19f73f41163e29063109c9ff08c100" + } + ], + "outputs": [ + { + "address": "0x07f9d0b8eb1e1b4ceeaade77467ed1b8267d2d81", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x76578714ca49fa9b94773a26da2bd1ade7c76c45d22112f5b7c92581e53db4ef", + "number": 6326620, + "status": "finalized", + "timestamp": "1555542334", + "type": 2 + }, + { + "_id": "0x9ab23428f133bbccefc7b020945c8853e7c016abaf452921aa5aa0d6600bb74b", + "block_height": "448108", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "15", + "signature": "0xaa6d0f2cf748a27778232cf9424411baaee57d369eb884b6726c3a21f9f9207e28e1b5a06bb45a0403f8332114ae389e8338700d2e5ac16644c511630231b1d201" + } + ], + "outputs": [ + { + "address": "0xe6b5af7812dd571904d0b1e313ed4ab0579308a1", + "coins": { + "thetawei": "25000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x9ab23428f133bbccefc7b020945c8853e7c016abaf452921aa5aa0d6600bb74b", + "number": 6326545, + "status": "finalized", + "timestamp": "1555542309", + "type": 2 + }, + { + "_id": "0x007260fba1949eceefb83705254bcaa2cba46affbc8427c4b7ff165db5590f12", + "block_height": "424192", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "2000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "14", + "signature": "0xfb5595bd6494f3109eefe42aec4fb06aa6bd56cbd726adc721233c4bcfcd8a6d4d1faa24db817eb2e9053b292a35a79e44962531038c0e58549393de9daffc0b01" + } + ], + "outputs": [ + { + "address": "0xefa0d997cfe96ff0b452e420b1434f05106c05b8", + "coins": { + "thetawei": "2000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x007260fba1949eceefb83705254bcaa2cba46affbc8427c4b7ff165db5590f12", + "number": 5902778, + "status": "finalized", + "timestamp": "1555388611", + "type": 2 + }, + { + "_id": "0x2fb3fc5769389efd178c9ba2a672e30f268744a1b9855241d70c6d55f1c8396b", + "block_height": "422336", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xefa0d997cfe96ff0b452e420b1434f05106c05b8", + "coins": { + "thetawei": "2000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "1", + "signature": "0x5e2016a265986a1c4f7ee08ceca82ce581b38f04670b1df117645ec4cdafca562953229d87c6fb828818db5a8252d48cf6283d54e0405bbfdcbbf4af08b59ef201" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "2000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x2fb3fc5769389efd178c9ba2a672e30f268744a1b9855241d70c6d55f1c8396b", + "number": 5881181, + "status": "finalized", + "timestamp": "1555376786", + "type": 2 + }, + { + "_id": "0xd7bbf5c90d27d2795a38537c1a1540484da333157cb77e6310cd33f06536e3b1", + "block_height": "421709", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "100002000000000000" + }, + "sequence": "13", + "signature": "0x0f6a1849ce86f85691644c2d312b67fa0289d92675c1ca5999e55d6ae2ccf7030d0f38e1a1161b4e4705af56ff45ffbdee95c0f544da88de2cfbbb5b8353b92300" + } + ], + "outputs": [ + { + "address": "0xefa0d997cfe96ff0b452e420b1434f05106c05b8", + "coins": { + "thetawei": "0", + "tfuelwei": "100000000000000000" + } + } + ] + }, + "hash": "0xd7bbf5c90d27d2795a38537c1a1540484da333157cb77e6310cd33f06536e3b1", + "number": 5870433, + "status": "finalized", + "timestamp": "1555372785", + "type": 2 + }, + { + "_id": "0xf3f4a2c5d74ec87bd7fb2dc090f126281ddcb6893657ea91758afa189772816c", + "block_height": "421698", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "2000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "12", + "signature": "0x58443a838a55b85f10d50a0762fea8483bacaa8c844872d6f197447f31af3f51615f5a83502e38d501034a1e0332cfba6de1e4aa24aeab1e182d7769324b4e2401" + } + ], + "outputs": [ + { + "address": "0xefa0d997cfe96ff0b452e420b1434f05106c05b8", + "coins": { + "thetawei": "2000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xf3f4a2c5d74ec87bd7fb2dc090f126281ddcb6893657ea91758afa189772816c", + "number": 5870303, + "status": "finalized", + "timestamp": "1555372712", + "type": 2 + }, + { + "_id": "0x932226a93869194fece8ceb209c3512f92e019fb8716f02b9e2610036f06d91b", + "block_height": "417455", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "850000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "11", + "signature": "0x9bf3d6070e873597094d9f04e9709d6f3d7929c1da2a6ad1291d43eda26b7065183a3d161156ab01aea22c700211fe946d3d94759887c8650bfef90410879b1e01" + } + ], + "outputs": [ + { + "address": "0x2971e95728a971f92b79589567b00fa370a86a61", + "coins": { + "thetawei": "850000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x932226a93869194fece8ceb209c3512f92e019fb8716f02b9e2610036f06d91b", + "number": 5798376, + "status": "finalized", + "timestamp": "1555345550", + "type": 2 + }, + { + "_id": "0xc35b1fd9655a745bcb8ad0da14519aed2ec45e5730b434aed9cb0d413e228056", + "block_height": "414933", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "6000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "10", + "signature": "0x600362cb40761bd0a6ba9e02d60ef063d8b8723bc601511ffe8f4b0dfa251afd5463656241fd58bdc13d24066f215042a05a320b40644ccd1da28b5011d6ccae00" + } + ], + "outputs": [ + { + "address": "0x7cd0835befd95bd0527c8254f14e1202bf113505", + "coins": { + "thetawei": "6000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xc35b1fd9655a745bcb8ad0da14519aed2ec45e5730b434aed9cb0d413e228056", + "number": 5768149, + "status": "finalized", + "timestamp": "1555329559", + "type": 2 + }, + { + "_id": "0x6e87d7cd010543b28306c8c07063970c2631fb2183d4f19c84a85dcf35e3292b", + "block_height": "414927", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "5002000000000000" + }, + "sequence": "9", + "signature": "0x0998593653b00b0e385e670521f5eac9573f1964daa9ddd58161bc826a2749d0087e859c57c058f95f010e6d7c9e1c43490d82fda44b1fd5dbb993455ad4bb0201" + } + ], + "outputs": [ + { + "address": "0x7cd0835befd95bd0527c8254f14e1202bf113505", + "coins": { + "thetawei": "0", + "tfuelwei": "5000000000000000" + } + } + ] + }, + "hash": "0x6e87d7cd010543b28306c8c07063970c2631fb2183d4f19c84a85dcf35e3292b", + "number": 5768087, + "status": "finalized", + "timestamp": "1555329523", + "type": 2 + }, + { + "_id": "0x9adb8681f2072f54b7dfef6d7c9a268e413e82cb6668030fb24cb10076221e9e", + "block_height": "406658", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "1000000000000" + }, + "inputs": [ + { + "address": "0x5bd04178a7cac9c8f8f8d93d1c6c53ed2056d6fa", + "coins": { + "thetawei": "200000000000000000000", + "tfuelwei": "1000000000000" + }, + "sequence": "6", + "signature": "0xc2fda1322df918a2fdb39df4d8018ddba946c413c334b1db08bf9345f16b1c2f1507757e1fed5c58d58d71945e10c78ceadc33a6970a1b9bc75181881f2dfc7b00" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "200000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x9adb8681f2072f54b7dfef6d7c9a268e413e82cb6668030fb24cb10076221e9e", + "number": 5708614, + "status": "finalized", + "timestamp": "1555277309", + "type": 2 + }, + { + "_id": "0x882cd203ea70b926218ae27ed4e57b9cced20310eb85c0546c85b70bf3b4d979", + "block_height": "357738", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "23300000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "8", + "signature": "0xd30437e7dd375f48998c236c13a9fb147d63b57e4cb1c5c59c914c1897fe991b44368151d21df7121f342bfcfd743f12ca584bec9412e4fe83d9d4b185b31dac00" + } + ], + "outputs": [ + { + "address": "0x4ddd0c6734a9bc4f49938ed0c8de257471c35755", + "coins": { + "thetawei": "23300000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x882cd203ea70b926218ae27ed4e57b9cced20310eb85c0546c85b70bf3b4d979", + "number": 5239549, + "status": "finalized", + "timestamp": "1554966610", + "type": 2 + }, + { + "_id": "0xa49d8b227a496f378552df5ede3fce41dd7f14c1d7dca69068602da32bfd1929", + "block_height": "357506", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "10002000000000000" + }, + "sequence": "7", + "signature": "0xb782d4dcea8d4e4e39066938c1d8c36677eec8632f5f558d50ca50114d3a723a10929015bcfcaea9bfd9a04257fc8908934589a3b9a2fee1ec37275072a44f3601" + } + ], + "outputs": [ + { + "address": "0x4ddd0c6734a9bc4f49938ed0c8de257471c35755", + "coins": { + "thetawei": "0", + "tfuelwei": "10000000000000000" + } + } + ] + }, + "hash": "0xa49d8b227a496f378552df5ede3fce41dd7f14c1d7dca69068602da32bfd1929", + "number": 5237001, + "status": "finalized", + "timestamp": "1554965141", + "type": 2 + }, + { + "_id": "0x62ae2679d93f2787991837379349df927efb640e01a46189d3e76f6bf751498a", + "block_height": "357502", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "10002000000000000" + }, + "sequence": "6", + "signature": "0xa5b8a62fee49ef84e349b81f522d4ad7e7a0834346af575e4cb1c6456f42dcca20b255755e0f71e5949ae73fe257a770e58457804e766d5f7a842217ce90e9cb01" + } + ], + "outputs": [ + { + "address": "0x4ddd0c6734a9bc4f49938ed0c8de257471c35755", + "coins": { + "thetawei": "0", + "tfuelwei": "10000000000000000" + } + } + ] + }, + "hash": "0x62ae2679d93f2787991837379349df927efb640e01a46189d3e76f6bf751498a", + "number": 5236954, + "status": "finalized", + "timestamp": "1554965115", + "type": 2 + }, + { + "_id": "0x9d82a263f3a1d93f0a40f877e966c5c6468094c96a228e08212686bb66228c02", + "block_height": "348734", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "3560000000000000" + }, + "sequence": "5", + "signature": "0x1325ff2e00b4b5b817c84732b4195e5ded9032be751ff9078a32681a38ce2381030a0ef635ea01b65ffa122587c75725da0c4fa2d6dd5da80507c6b444262ec901" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "0", + "tfuelwei": "3558000000000000" + } + } + ] + }, + "hash": "0x9d82a263f3a1d93f0a40f877e966c5c6468094c96a228e08212686bb66228c02", + "number": 5104041, + "status": "finalized", + "timestamp": "1554909040", + "type": 2 + }, + { + "_id": "0x5b549112550f013afe264886f9daab1e3c179146a0b755904979fbc2a9a57082", + "block_height": "348714", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "4568500000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "4", + "signature": "0x5956bf4b899e19bb12d3a1a4d0b2415921bb9e8fe73eb0580ae11c73fb8ea65b5da2df792fb650ddbf68e8f30029a3eb20d013350cfc44b1fba5d64a11b5f34d01" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "4568500000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x5b549112550f013afe264886f9daab1e3c179146a0b755904979fbc2a9a57082", + "number": 5103657, + "status": "finalized", + "timestamp": "1554908912", + "type": 2 + }, + { + "_id": "0xf0950f834cf61a523eabf2dcfb3ec138bdd44778e168107efaf0ed599fd713dd", + "block_height": "341414", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "12000000000000" + }, + "sequence": "3", + "signature": "0x4687755a59c47942d32ba953003d7c3ae44f2ae17e6bdbf4c52d313cd8f70d895b2216e10bd1305262e0e91bdc2310323e77d174aff3c51a21386908e344fc5501" + } + ], + "outputs": [ + { + "address": "0xcbcef62ca7a2e367a9c93aba07ea4e63139da99d", + "coins": { + "thetawei": "0", + "tfuelwei": "10000000000000" + } + } + ] + }, + "hash": "0xf0950f834cf61a523eabf2dcfb3ec138bdd44778e168107efaf0ed599fd713dd", + "number": 5009444, + "status": "finalized", + "timestamp": "1554862473", + "type": 2 + }, + { + "_id": "0x75f7730a1bac757e54d362246d9f6f64c517e39f1d5e0f2305b7f621382f0a99", + "block_height": "341409", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "100000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "2", + "signature": "0x6fe79d9a61cc1e71d4b7e0ac0a91ee3df99cda3671d04c9933b5d28bee9fc1c0075b034ae9319ecfadbdec12c025383e0aae2ea461a3f0c10e6a03614b7815d300" + } + ], + "outputs": [ + { + "address": "0xcbcef62ca7a2e367a9c93aba07ea4e63139da99d", + "coins": { + "thetawei": "100000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x75f7730a1bac757e54d362246d9f6f64c517e39f1d5e0f2305b7f621382f0a99", + "number": 5009436, + "status": "finalized", + "timestamp": "1554862440", + "type": 2 + }, + { + "_id": "0x2a9f6acbe86f2370a95d1cf41c274eb9b495244ffc24407c8502cffa8d6567de", + "block_height": "341096", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "10000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "100000000000000", + "tfuelwei": "10000000000000" + }, + "sequence": "1", + "signature": "0x824f4ced1a5c8c858e20c6aef30b8e79d054da992dc546111a9405009cf31fda38a0221a8c665a4853beb2ed16e6659c93e5e8930f10f4a23b9a7baca6efe56500" + } + ], + "outputs": [ + { + "address": "0xcbcef62ca7a2e367a9c93aba07ea4e63139da99d", + "coins": { + "thetawei": "100000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0x2a9f6acbe86f2370a95d1cf41c274eb9b495244ffc24407c8502cffa8d6567de", + "number": 5005700, + "status": "finalized", + "timestamp": "1554860438", + "type": 2 + }, + { + "_id": "0xaaae08793ca9cd550b85efa0bc02c9c2914f25286a345bcdc7aa5775263bfe04", + "block_height": "339188", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "1000000000000" + }, + "inputs": [ + { + "address": "0xc959606724d40fff9b6c5e65c4150938a890d5b5", + "coins": { + "thetawei": "0", + "tfuelwei": "1000001000000000000" + }, + "sequence": "23", + "signature": "0xc0ee1d5d23d7ea848751e1c4996d11f2f46604e3420c66be9fa0890169b439a41090595f803b8a30b631d5d92d2c69510f0c2588ab5d1337603112f4f645202d00" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "1000000000000000000" + } + } + ] + }, + "hash": "0xaaae08793ca9cd550b85efa0bc02c9c2914f25286a345bcdc7aa5775263bfe04", + "number": 4984497, + "status": "finalized", + "timestamp": "1554848327", + "type": 2 + }, + { + "_id": "0xfc0da11d52b6d5b810ad8f2f157ac23d010f515120c90fa589d267b7ba60d68e", + "block_height": "339185", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "1000000000000" + }, + "inputs": [ + { + "address": "0xc959606724d40fff9b6c5e65c4150938a890d5b5", + "coins": { + "thetawei": "1000000000000000000", + "tfuelwei": "1000000000000" + }, + "sequence": "22", + "signature": "0x42696f0ec72d2c9e566b5a2a1288b4a5b1f82361d85617ed042bd9172b15d24139ae3fd83682aaff0fd3863406eed92728b3dcfe2ee3f14e6bc662c51d247c5c01" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "1000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "hash": "0xfc0da11d52b6d5b810ad8f2f157ac23d010f515120c90fa589d267b7ba60d68e", + "number": 4984490, + "status": "finalized", + "timestamp": "1554848309", + "type": 2 + } + ], + "totalPageNumber": 1, + "currentPageNumber": 1 +} \ No newline at end of file diff --git a/mock/ext-api-data/thundertoken-api_tokens__address_0x0b230def08139f18a86536d9cfa150f04435414c.json b/mock/ext-api-data/thundertoken-api_tokens__address_0x0b230def08139f18a86536d9cfa150f04435414c.json new file mode 100644 index 000000000..4b4e394e0 --- /dev/null +++ b/mock/ext-api-data/thundertoken-api_tokens__address_0x0b230def08139f18a86536d9cfa150f04435414c.json @@ -0,0 +1 @@ +{"total":1,"docs":[{"address":"0x51BcA9300d034A7e6aB379399a317bDfA0D4835b","name":"The Third Identity","decimals":18,"symbol":"TTI"}]} \ No newline at end of file diff --git a/mock/ext-api-data/thundertoken-api_transactions__address_0x0b230def08139f18a86536d9cfa150f04435414c.json b/mock/ext-api-data/thundertoken-api_transactions__address_0x0b230def08139f18a86536d9cfa150f04435414c.json new file mode 100644 index 000000000..c84689686 --- /dev/null +++ b/mock/ext-api-data/thundertoken-api_transactions__address_0x0b230def08139f18a86536d9cfa150f04435414c.json @@ -0,0 +1 @@ +{"docs":[{"operations":[],"contract":null,"_id":"0xb644bbcdeedb68562c285ec962b4c15fc27578ad287282142e369112e6427603","blockNumber":37467849,"time":1588900192,"nonce":406,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0xb644bbcdeedb68562c285ec962b4c15fc27578ad287282142e369112e6427603","timeStamp":"1588900192"},{"operations":[{"transactionId":"0xd4625f9637f11983df28dc343742a25149ee2c0b4151329ad6fad989dac5d1d5-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0xd4625f9637f11983df28dc343742a25149ee2c0b4151329ad6fad989dac5d1d5","blockNumber":37467805,"time":1588900148,"nonce":405,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"1511414","input":"0x4008d2f3","error":"","id":"0xd4625f9637f11983df28dc343742a25149ee2c0b4151329ad6fad989dac5d1d5","timeStamp":"1588900148"},{"operations":[],"contract":null,"_id":"0x5d8c91495ceef7e46e209af540e77f7578764a754551a7808162c9f60fce2b6c","blockNumber":37391669,"time":1588823991,"nonce":404,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"421539","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000400","error":"","id":"0x5d8c91495ceef7e46e209af540e77f7578764a754551a7808162c9f60fce2b6c","timeStamp":"1588823991"},{"operations":[{"transactionId":"0xd4d51caebbd5e8eca4bf0e25ffba177c76a10f22cf4d93d79762649ad16d411a-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0xd4d51caebbd5e8eca4bf0e25ffba177c76a10f22cf4d93d79762649ad16d411a","blockNumber":37391647,"time":1588823969,"nonce":403,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"1511414","input":"0x4008d2f3","error":"","id":"0xd4d51caebbd5e8eca4bf0e25ffba177c76a10f22cf4d93d79762649ad16d411a","timeStamp":"1588823969"},{"operations":[],"contract":null,"_id":"0x72e90fd0fd35b976d7ef7986556418ba85add4ed81b4174b7f31fb70329e15e2","blockNumber":37298689,"time":1588730986,"nonce":402,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"2000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0x72e90fd0fd35b976d7ef7986556418ba85add4ed81b4174b7f31fb70329e15e2","timeStamp":"1588730986"},{"operations":[{"transactionId":"0x410849c83045527389f278c1e042f7e20fe46a95d66b4d0631067a2127896a42-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0x410849c83045527389f278c1e042f7e20fe46a95d66b4d0631067a2127896a42","blockNumber":37298664,"time":1588730961,"nonce":401,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"2000000000","gasUsed":"1511414","input":"0x4008d2f3","error":"","id":"0x410849c83045527389f278c1e042f7e20fe46a95d66b4d0631067a2127896a42","timeStamp":"1588730961"},{"operations":[],"contract":null,"_id":"0xb94e7973a2a72f41723abe3c6213d81cca14aabd38bec4993429732bbc6c8cc5","blockNumber":37218845,"time":1588651119,"nonce":400,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000001000","error":"","id":"0xb94e7973a2a72f41723abe3c6213d81cca14aabd38bec4993429732bbc6c8cc5","timeStamp":"1588651119"},{"operations":[{"transactionId":"0x9fe8d2ffe9e9e85f5f37061f209505c5af4a738b21f441ab5d8b57329bfabb0f-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0x9fe8d2ffe9e9e85f5f37061f209505c5af4a738b21f441ab5d8b57329bfabb0f","blockNumber":37218820,"time":1588651094,"nonce":399,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"1511414","input":"0x4008d2f3","error":"","id":"0x9fe8d2ffe9e9e85f5f37061f209505c5af4a738b21f441ab5d8b57329bfabb0f","timeStamp":"1588651094"},{"operations":[],"contract":null,"_id":"0x89f96a31725b8b0b5d7dc263e6df81a64501835c53f5b2c535d856cf06fb9c1c","blockNumber":37119075,"time":1588551300,"nonce":398,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0x89f96a31725b8b0b5d7dc263e6df81a64501835c53f5b2c535d856cf06fb9c1c","timeStamp":"1588551300"},{"operations":[{"transactionId":"0x9cf4f5ccf25256fd7244dd68faa118a36f8a1de33e447365982e3f0b51b4f4c3-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0x9cf4f5ccf25256fd7244dd68faa118a36f8a1de33e447365982e3f0b51b4f4c3","blockNumber":37119058,"time":1588551283,"nonce":397,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"1586414","input":"0x4008d2f3","error":"","id":"0x9cf4f5ccf25256fd7244dd68faa118a36f8a1de33e447365982e3f0b51b4f4c3","timeStamp":"1588551283"},{"operations":[],"contract":null,"_id":"0x2535a9542186fcfbd480434982bb34f9f3fb114627b01de69a18e40c5d893e9e","blockNumber":37033239,"time":1588465416,"nonce":396,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"2000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0x2535a9542186fcfbd480434982bb34f9f3fb114627b01de69a18e40c5d893e9e","timeStamp":"1588465416"},{"operations":[{"transactionId":"0x9831b826a58313bff055718d5034170384ded72f7d8089b9be9e1ae62877c375-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0x9831b826a58313bff055718d5034170384ded72f7d8089b9be9e1ae62877c375","blockNumber":37033207,"time":1588465384,"nonce":395,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"2000000000","gasUsed":"1556414","input":"0x4008d2f3","error":"","id":"0x9831b826a58313bff055718d5034170384ded72f7d8089b9be9e1ae62877c375","timeStamp":"1588465384"},{"operations":[],"contract":null,"_id":"0x0bd0b39760233ba693a280e8ee2fcb6afce866b4c80f82a742b4676c33626d74","blockNumber":36955282,"time":1588387435,"nonce":394,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"25000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0x0bd0b39760233ba693a280e8ee2fcb6afce866b4c80f82a742b4676c33626d74","timeStamp":"1588387435"},{"operations":[{"transactionId":"0x043f306a06f3821cb19d6f7eb62a800c384889e429d1e26c837e67259efd73d8-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0x043f306a06f3821cb19d6f7eb62a800c384889e429d1e26c837e67259efd73d8","blockNumber":36955254,"time":1588387407,"nonce":393,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"25000000000","gasUsed":"1511414","input":"0x4008d2f3","error":"","id":"0x043f306a06f3821cb19d6f7eb62a800c384889e429d1e26c837e67259efd73d8","timeStamp":"1588387407"},{"operations":[],"contract":null,"_id":"0x86394bbf49c7bc0e3fd02d5f875d160640e8d1f7a454bbd8dfedb922a0815f6a","blockNumber":36876439,"time":1588308515,"nonce":392,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"25000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0x86394bbf49c7bc0e3fd02d5f875d160640e8d1f7a454bbd8dfedb922a0815f6a","timeStamp":"1588308515"},{"operations":[{"transactionId":"0x842d46a52e0fedc5911b62629f51bb0693dbc75e8d7a61b33247864f7ba4fa11-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0x842d46a52e0fedc5911b62629f51bb0693dbc75e8d7a61b33247864f7ba4fa11","blockNumber":36876421,"time":1588308497,"nonce":391,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"25000000000","gasUsed":"1511414","input":"0x4008d2f3","error":"","id":"0x842d46a52e0fedc5911b62629f51bb0693dbc75e8d7a61b33247864f7ba4fa11","timeStamp":"1588308497"},{"operations":[],"contract":null,"_id":"0x01fc7ea6eaf9fe017ce6c4fa65e9a8b56abe9853947be17c5c73160f46757209","blockNumber":36776536,"time":1588208500,"nonce":390,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"7000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0x01fc7ea6eaf9fe017ce6c4fa65e9a8b56abe9853947be17c5c73160f46757209","timeStamp":"1588208500"},{"operations":[{"transactionId":"0x54539cc7c6dd0abd8dfd7db288812e1bbe387ad8f9c7f57c149d9b9b7b01c113-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0x54539cc7c6dd0abd8dfd7db288812e1bbe387ad8f9c7f57c149d9b9b7b01c113","blockNumber":36776511,"time":1588208474,"nonce":389,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"7000000000","gasUsed":"1586414","input":"0x4008d2f3","error":"","id":"0x54539cc7c6dd0abd8dfd7db288812e1bbe387ad8f9c7f57c149d9b9b7b01c113","timeStamp":"1588208474"},{"operations":[],"contract":null,"_id":"0x863bd927b9cfab490e61acc30d100c62e28180aac221f19921f8d2b7112d86a0","blockNumber":36709221,"time":1588141143,"nonce":388,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"5500000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0x863bd927b9cfab490e61acc30d100c62e28180aac221f19921f8d2b7112d86a0","timeStamp":"1588141143"},{"operations":[{"transactionId":"0xd9b8165580cf97970c40e32a121d64f67632f12268c70dc46dbc1705c3b16402-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0xd9b8165580cf97970c40e32a121d64f67632f12268c70dc46dbc1705c3b16402","blockNumber":36709202,"time":1588141124,"nonce":387,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"5500000000","gasUsed":"1511414","input":"0x4008d2f3","error":"","id":"0xd9b8165580cf97970c40e32a121d64f67632f12268c70dc46dbc1705c3b16402","timeStamp":"1588141124"},{"operations":[],"contract":null,"_id":"0x42e15675c2ac878131a7901f229c203b1000703935000c13f90738fe13274a7c","blockNumber":36621273,"time":1588053151,"nonce":386,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"25000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0x42e15675c2ac878131a7901f229c203b1000703935000c13f90738fe13274a7c","timeStamp":"1588053151"},{"operations":[{"transactionId":"0xfd329f552403b7befe724d63268e40a905d7da03bb0ac3dcb26e903607e4810f-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0xfd329f552403b7befe724d63268e40a905d7da03bb0ac3dcb26e903607e4810f","blockNumber":36621242,"time":1588053120,"nonce":385,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"25000000000","gasUsed":"1511414","input":"0x4008d2f3","error":"","id":"0xfd329f552403b7befe724d63268e40a905d7da03bb0ac3dcb26e903607e4810f","timeStamp":"1588053120"},{"operations":[],"contract":null,"_id":"0xe668c4999be866cbe3d58dcfd8dd5deb05112a6f7ff508727c8f9673c7ab1a9f","blockNumber":36517634,"time":1587949433,"nonce":384,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0xe668c4999be866cbe3d58dcfd8dd5deb05112a6f7ff508727c8f9673c7ab1a9f","timeStamp":"1587949433"},{"operations":[{"transactionId":"0xbefdf8b1b2e68f24ad8d1387b435a8ba9c250cd348c93b35cf306dab04886bb9-0","contract":{"address":"0x51bca9300d034a7e6ab379399a317bdfa0d4835b","decimals":18,"name":"The Third Identity","symbol":"TTI","totalSupply":"10000000000000000000000000000","updatedAt":"2020-02-26T21:42:19.178Z"},"from":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","to":"0x0B230dEf08139F18a86536d9CFa150f04435414c","type":"token_transfer","value":"322102000000000000000","id":null}],"contract":null,"_id":"0xbefdf8b1b2e68f24ad8d1387b435a8ba9c250cd348c93b35cf306dab04886bb9","blockNumber":36517608,"time":1587949407,"nonce":383,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x3270b4e0916B4556BF236B6E5D4377282b3255e5","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"1526414","input":"0x4008d2f3","error":"","id":"0xbefdf8b1b2e68f24ad8d1387b435a8ba9c250cd348c93b35cf306dab04886bb9","timeStamp":"1587949407"},{"operations":[],"contract":null,"_id":"0xdbc92db02a0dffb8d9aae8a3d1e0bde23ef46a2410c2d8d8cede2d08a25ee440","blockNumber":36439120,"time":1587870875,"nonce":382,"from":"0x0B230dEf08139F18a86536d9CFa150f04435414c","to":"0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1","value":"0","gas":"4700000","gasPrice":"1000000000","gasUsed":"421569","input":"0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800","error":"","id":"0xdbc92db02a0dffb8d9aae8a3d1e0bde23ef46a2410c2d8d8cede2d08a25ee440","timeStamp":"1587870875"}],"total":25} \ No newline at end of file diff --git a/mock/ext-api-data/tomochain-api_tokens__address_0x8b353021189375591723e7384262f45709a3c3dc.json b/mock/ext-api-data/tomochain-api_tokens__address_0x8b353021189375591723e7384262f45709a3c3dc.json new file mode 100644 index 000000000..9fbc560d6 --- /dev/null +++ b/mock/ext-api-data/tomochain-api_tokens__address_0x8b353021189375591723e7384262f45709a3c3dc.json @@ -0,0 +1 @@ +{"total":2,"docs":[{"address":"0xaB7e4aE99D7bfff4de8322aB915e9066857227F0","name":"KONG","decimals":18,"symbol":"KONG"},{"address":"0xc7BdF5D257fF4EC078e12A3ABD34dFc329E55130","name":"AIS Token","decimals":18,"symbol":"AIS"}]} \ No newline at end of file diff --git a/mock/ext-api-data/tomochain-api_transactions__address_0x17e4c16605e32adead5fa371bf6117df34ca0200.json b/mock/ext-api-data/tomochain-api_transactions__address_0x17e4c16605e32adead5fa371bf6117df34ca0200.json new file mode 100644 index 000000000..3011d3795 --- /dev/null +++ b/mock/ext-api-data/tomochain-api_transactions__address_0x17e4c16605e32adead5fa371bf6117df34ca0200.json @@ -0,0 +1 @@ +{"docs":[{"operations":[],"contract":null,"_id":"0x55bc7e249fb9998eec372eb75b3df89cc593e5fd9a4fa388ea3af5efdd5207e3","blockNumber":20584562,"time":1589318003,"nonce":1042050,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a18708c1582f5022b001fc8f5d3e4d78d78b92bd665f79f7dbd876970e489d89118b0","error":"","id":"0x55bc7e249fb9998eec372eb75b3df89cc593e5fd9a4fa388ea3af5efdd5207e3","timeStamp":"1589318003"},{"operations":[],"contract":null,"_id":"0xe917920d3121daf91c0888b0bb05947d5eea95a48d23f0d2a97c3469322369ed","blockNumber":20584547,"time":1589317973,"nonce":1042049,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a186186b2d4d01b7c8305842aab96eee8f641be494ac6cf45b51ceab4eaa93d52f17a","error":"","id":"0xe917920d3121daf91c0888b0bb05947d5eea95a48d23f0d2a97c3469322369ed","timeStamp":"1589317973"},{"operations":[],"contract":null,"_id":"0x8b68e187f8160a9dcad4b5447465f2daf1f6d3cc465213b60b6cc5e74e36abfd","blockNumber":20584532,"time":1589317943,"nonce":1042048,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a1852d733feca46a48d2b1605543c17a22c3641dbfe4582a66ead0e7428b051b528a9","error":"","id":"0x8b68e187f8160a9dcad4b5447465f2daf1f6d3cc465213b60b6cc5e74e36abfd","timeStamp":"1589317943"},{"operations":[],"contract":null,"_id":"0x61d9937d4b8a681455ddff82240f0f9313e0baa99d391c669ffebbc2bb40af7d","blockNumber":20584517,"time":1589317913,"nonce":1042047,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a184306200bedd5181ed7a808f7e7b8f964e14c627434aab7018a6a4cb889f51e97e2","error":"","id":"0x61d9937d4b8a681455ddff82240f0f9313e0baa99d391c669ffebbc2bb40af7d","timeStamp":"1589317913"},{"operations":[],"contract":null,"_id":"0xd0d224a26821cc89137c3f7de55568c8d637f4d744bec5f8f7312b1f505cf61a","blockNumber":20584502,"time":1589317883,"nonce":1042046,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a1834306752e7a66a502f1643a7a2193d87fd6ffa66f221e5ce3a3562c7fb869709aa","error":"","id":"0xd0d224a26821cc89137c3f7de55568c8d637f4d744bec5f8f7312b1f505cf61a","timeStamp":"1589317883"},{"operations":[],"contract":null,"_id":"0x7d71fa1fb6078546f176e4883ce31e874aa347948c1ff81785af0de73962f158","blockNumber":20584487,"time":1589317853,"nonce":1042045,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a1825867b0ca6d301d91b1fa753e7fe6f0cf9dc8273733ec4753c16056d3a36b86d1a","error":"","id":"0x7d71fa1fb6078546f176e4883ce31e874aa347948c1ff81785af0de73962f158","timeStamp":"1589317853"},{"operations":[],"contract":null,"_id":"0x1e5f4c1008c67a0ac3d4c2dc884b77d6b68ece8b174f3845a3e8a2b7c121ed57","blockNumber":20584477,"time":1589317833,"nonce":1042045,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000092","value":"0","gas":"40000000","gasPrice":"0","gasUsed":"0","input":"0x437e44fa06a10d89c737e276e3ece67b2bd2c139e5d661bec8c168504bbf467556e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","error":"","id":"0x1e5f4c1008c67a0ac3d4c2dc884b77d6b68ece8b174f3845a3e8a2b7c121ed57","timeStamp":"1589317833"},{"operations":[],"contract":null,"_id":"0xa44ee6f4518d1ba56af64a72bae4c82917c7ef7175c831c891a18dab8fc2e19e","blockNumber":20584472,"time":1589317823,"nonce":1042044,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a181644530c838e677e10b2923f7858970ee987668e1fd52e8581c82c6c2117130162","error":"","id":"0xa44ee6f4518d1ba56af64a72bae4c82917c7ef7175c831c891a18dab8fc2e19e","timeStamp":"1589317823"},{"operations":[],"contract":null,"_id":"0xf1a03d857a1e347545185bae66e4bca392c23732a788c5964e90e8169e5f6696","blockNumber":20584457,"time":1589317793,"nonce":1042043,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a180761ebf1a7b1c3ae7ed1b684064bb964e49ca7e1d93f921e1e0292c4bd1f1d12dc","error":"","id":"0xf1a03d857a1e347545185bae66e4bca392c23732a788c5964e90e8169e5f6696","timeStamp":"1589317793"},{"operations":[],"contract":null,"_id":"0x8c2fa072e5110f12cfb08620635ef9b4c172122cfcdd0ab140f896e47d6ca0d5","blockNumber":20584442,"time":1589317763,"nonce":1042042,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a17f800249caa62eb771a9236565ee1dbf9d4cdeca4447713676da87f3ce5d930925c","error":"","id":"0x8c2fa072e5110f12cfb08620635ef9b4c172122cfcdd0ab140f896e47d6ca0d5","timeStamp":"1589317763"},{"operations":[],"contract":null,"_id":"0x86868a56c9bbc35d150927e2ee14e300261d4d328ea70248c731a985d649fdd3","blockNumber":20584427,"time":1589317733,"nonce":1042041,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a17e9a3fa072992cdcbbcdd9893ef28f5b556d0d9a5d586356864c99c0c5030290bb8","error":"","id":"0x86868a56c9bbc35d150927e2ee14e300261d4d328ea70248c731a985d649fdd3","timeStamp":"1589317733"},{"operations":[],"contract":null,"_id":"0x5ae0338a127dacbbc27be5f1de92fb31b42fb137a305464f69cd1894bb40c52d","blockNumber":20584412,"time":1589317703,"nonce":1042040,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a17dad36e561e88b3e43fa73eded00ae1085044cfe303e3a99405c9571a4732a5855b","error":"","id":"0x5ae0338a127dacbbc27be5f1de92fb31b42fb137a305464f69cd1894bb40c52d","timeStamp":"1589317703"},{"operations":[],"contract":null,"_id":"0xc34e735b240969b67338af2db87de8247b25f8162f9e409d200cb57ca69cab0e","blockNumber":20584397,"time":1589317673,"nonce":1042039,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a17cb4bf64b5c4778a22a1cee73f5af4ec6d3e9dd473301a731e3b87a89430a1b69ad","error":"","id":"0xc34e735b240969b67338af2db87de8247b25f8162f9e409d200cb57ca69cab0e","timeStamp":"1589317673"},{"operations":[],"contract":null,"_id":"0xadeadb93356892184dff3ee6c9e17d6cefda998cd935731665c2523704bce17b","blockNumber":20584383,"time":1589317645,"nonce":1042038,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a17bc5d97eb0b280bee9f22f09828013a2f8860097ddbfc8ab2b66231f26b3e28abf0","error":"","id":"0xadeadb93356892184dff3ee6c9e17d6cefda998cd935731665c2523704bce17b","timeStamp":"1589317645"},{"operations":[],"contract":null,"_id":"0x0436c34409f37d3434011751790f04a75c53834411d8d00aafe6e2e8146240ae","blockNumber":20584367,"time":1589317613,"nonce":1042037,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a17ad8c43f40dde02e4589e8a78233f186b46ff813676e73e27b09b3247fc8fd97bef","error":"","id":"0x0436c34409f37d3434011751790f04a75c53834411d8d00aafe6e2e8146240ae","timeStamp":"1589317613"},{"operations":[],"contract":null,"_id":"0x9ea4323a24d3aa6d74a6538247c78153e39c7ae3516d229619cc220bd5e54d53","blockNumber":20584352,"time":1589317583,"nonce":1042036,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a179ee4cdb871e9309a76b2d45767e8b7ac68c6d911fd1925b3c461eedf935105757e","error":"","id":"0x9ea4323a24d3aa6d74a6538247c78153e39c7ae3516d229619cc220bd5e54d53","timeStamp":"1589317583"},{"operations":[],"contract":null,"_id":"0x5f78ef43e98d3914a2c7f4d6f296e3bff25acb09d24beae912f93f3dd6bec640","blockNumber":20584340,"time":1589317559,"nonce":1042036,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000092","value":"0","gas":"40000000","gasPrice":"0","gasUsed":"0","input":"0x437e44fa06a10d89c737e276e3ece67b2bd2c139e5d661bec8c168504bbf467556e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","error":"","id":"0x5f78ef43e98d3914a2c7f4d6f296e3bff25acb09d24beae912f93f3dd6bec640","timeStamp":"1589317559"},{"operations":[],"contract":null,"_id":"0x585fd5874cbc146123319ec736c3be06e57604f337880e8dea2d1a96dacfa588","blockNumber":20584337,"time":1589317553,"nonce":1042035,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a178fd5a162ccc57e40da3fc18a5ac927760e356be6f09034743b9c181eb6b829ae42","error":"","id":"0x585fd5874cbc146123319ec736c3be06e57604f337880e8dea2d1a96dacfa588","timeStamp":"1589317553"},{"operations":[],"contract":null,"_id":"0x0022acedbeed21b8f608c6939e2b2d1015c9036d1f94d396a7fe5159edba5af1","blockNumber":20584323,"time":1589317525,"nonce":1042034,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a1780892c51dc724a59a5099a0a181f86a43b01d7795fb81643306baa4459d1432e33","error":"","id":"0x0022acedbeed21b8f608c6939e2b2d1015c9036d1f94d396a7fe5159edba5af1","timeStamp":"1589317525"},{"operations":[],"contract":null,"_id":"0x66d90c80291875ca3ac395a137c45722d8d8a29ea31426284f5dc351a8e32723","blockNumber":20584307,"time":1589317493,"nonce":1042033,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a177143a3ebb98872d4bcd17d313c6c21a39039d235ab114835524b29934e113ed289","error":"","id":"0x66d90c80291875ca3ac395a137c45722d8d8a29ea31426284f5dc351a8e32723","timeStamp":"1589317493"},{"operations":[],"contract":null,"_id":"0x5c5b676b626929664c1007988a3d280804ea635b04de438d38a664d158db5c15","blockNumber":20584292,"time":1589317463,"nonce":1042032,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a1762170c3380b87bed310f585771de970929075bcd1a870d465fd7e18a6e922c562b","error":"","id":"0x5c5b676b626929664c1007988a3d280804ea635b04de438d38a664d158db5c15","timeStamp":"1589317463"},{"operations":[],"contract":null,"_id":"0x4d2d0e42b7410aa78e7ef9b9b333a003b7be36808eaf7d86adb4f35040901d4e","blockNumber":20584277,"time":1589317433,"nonce":1042031,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a1753295206e9f985d4e72fed5bd857e6306272666308b31c26173fbc65f6ee476c6f","error":"","id":"0x4d2d0e42b7410aa78e7ef9b9b333a003b7be36808eaf7d86adb4f35040901d4e","timeStamp":"1589317433"},{"operations":[],"contract":null,"_id":"0x8be6c87f63110b5991e5c2602213a3936cc21f32d052de3aa157bd70246dd6cd","blockNumber":20584262,"time":1589317403,"nonce":1042030,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a1744e506b96a9ccf6837e6efc8f90557a8763dfce5e359f6e4cd94369d97a75bf4e6","error":"","id":"0x8be6c87f63110b5991e5c2602213a3936cc21f32d052de3aa157bd70246dd6cd","timeStamp":"1589317403"},{"operations":[],"contract":null,"_id":"0x2f4dbe27e6a1150b1e72eaac7fc25936c6ad15a21e0f40479192995146da71ec","blockNumber":20584247,"time":1589317373,"nonce":1042029,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a1735b1a5471be4f06c297f2e17a9cb9301587f688b7ca0cd42fe51544c6fd2775ecd","error":"","id":"0x2f4dbe27e6a1150b1e72eaac7fc25936c6ad15a21e0f40479192995146da71ec","timeStamp":"1589317373"},{"operations":[],"contract":null,"_id":"0xd28781523e7da1f9892fec4eb96cd23b1e39c7a11d67be5bf4c9dba76faca0a5","blockNumber":20584232,"time":1589317343,"nonce":1042028,"from":"0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200","to":"0x0000000000000000000000000000000000000089","value":"0","gas":"200000","gasPrice":"0","gasUsed":"0","input":"0xe341eaa400000000000000000000000000000000000000000000000000000000013a1726bcecf8b2be5d3fa70b978b6eef49071884f90bb56fa88029bbfe03c2b75126d9","error":"","id":"0xd28781523e7da1f9892fec4eb96cd23b1e39c7a11d67be5bf4c9dba76faca0a5","timeStamp":"1589317343"}],"total":25} \ No newline at end of file diff --git a/mock/ext-api-data/tron-api_v1_accounts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB.json b/mock/ext-api-data/tron-api_v1_accounts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB.json new file mode 100644 index 000000000..07b024fb9 --- /dev/null +++ b/mock/ext-api-data/tron-api_v1_accounts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB.json @@ -0,0 +1,77 @@ +{ + "success": true, + "meta": { + "at": 1589366680095, + "page_size": 1 + }, + "data": [ + { + "account_resource": {}, + "active_permission": [ + { + "id": 2, + "keys": [ + { + "address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", + "weight": 1 + } + ], + "operations": "7fff1fc0033e0000000000000000000000000000000000000000000000000000", + "permission_name": "active", + "threshold": 1, + "type": "Active" + } + ], + "address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", + "allowance": 848829, + "assetV2": [ + { + "key": "1002000", + "value": 10189204891 + }, + { + "key": "1002798", + "value": 10000000 + }, + { + "key": "1002814", + "value": 10000000 + } + ], + "balance": 278720000, + "create_time": 1553864037000, + "free_asset_net_usageV2": [ + { + "key": "1002000", + "value": 0 + }, + { + "key": "1002798", + "value": 0 + }, + { + "key": "1002814", + "value": 0 + } + ], + "latest_consume_free_time": 1575142326000, + "latest_consume_time": 1576767612000, + "latest_opration_time": 1576767612000, + "owner_permission": { + "keys": [ + { + "address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", + "weight": 1 + } + ], + "permission_name": "owner", + "threshold": 1 + }, + "trc20": [ + { + "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7": "53135738" + } + ] + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/tron-api_v1_accounts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB_transactions__limit_25_order_by_block_timestamp_desc_token_id_.json b/mock/ext-api-data/tron-api_v1_accounts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB_transactions__limit_25_order_by_block_timestamp_desc_token_id_.json new file mode 100644 index 000000000..219d8a666 --- /dev/null +++ b/mock/ext-api-data/tron-api_v1_accounts_TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB_transactions__limit_25_order_by_block_timestamp_desc_token_id_.json @@ -0,0 +1,795 @@ +{ + "success": true, + "meta": { + "at": 1589366680021, + "page_size": 21 + }, + "data": [ + { + "blockNumber": 19634882, + "block_timestamp": 1589169090000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 2820, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2980411, + "asset_name": "1002000", + "owner_address": "41d0995a2071de293ff0c1fa25131c0f4bab3535ae", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1589251721359, + "fee_limit": 0, + "ref_block_bytes": "95da", + "ref_block_hash": "0d56df8c2d4c1260", + "timestamp": 1589166646700 + }, + "raw_data_hex": "0a0295da22080d56df8c2d4c1260408f91a3b6a02e5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a0731303032303030121541d0995a2071de293ff0c1fa25131c0f4bab3535ae1a154139fec4d95bb59f45a727f9234020adaf2cec9e2020bbf4b50170accbda8da02e", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 2820 + } + ], + "signature": [ + "55bb94741af3976f215bb97021f85f71caf87a9b86f870bc74bbed4133a1adb748de51eaaea5c90e4cae9b33d586346f9da43154231b3f83b1dda9e0b9dc5cf501" + ], + "txID": "f6804d16ac87fa77357e8145fbfdafd459433f89f87019bc8ea2308260abb761" + }, + { + "blockNumber": 18770770, + "block_timestamp": 1586575584000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 2820, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2984422, + "asset_name": "1002000", + "owner_address": "4186048ac2ac8bb7985a1f68abb0077d4267e1c201", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1586657356443, + "fee_limit": 0, + "ref_block_bytes": "6557", + "ref_block_hash": "59585d54bcb9da25", + "timestamp": 1586572629770 + }, + "raw_data_hex": "0a026557220859585d54bcb9da25409bd597e1962e5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a073130303230303012154186048ac2ac8bb7985a1f68abb0077d4267e1c2011a154139fec4d95bb59f45a727f9234020adaf2cec9e2020e693b601708aaee4b8962e", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 2820 + } + ], + "signature": [ + "2fa982f9e251780cc6f5c2354be8501d2b983ea099ed2e4f77ed0ab8f4842d240e206f9e5c068644e7c9c7a2b0f62a589216e576ea304423abf38664b3a1e78301" + ], + "txID": "b42ffe110198a5fa1351b41d23d5244b5fa69b92a6ecf30adcc582d65594c7f9" + }, + { + "block_timestamp": 1583897466000, + "internal_transactions": [], + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2988026, + "asset_name": "1002000", + "owner_address": "41934edccf923ee46daf057615d08f341f68078b41", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1583980512649, + "fee_limit": 0, + "ref_block_bytes": "ca0c", + "ref_block_hash": "50875d785e719200", + "timestamp": 1583895463611 + }, + "raw_data_hex": "0a02ca0c220850875d785e71920040898be2e48c2e5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a0731303032303030121541934edccf923ee46daf057615d08f341f68078b411a154139fec4d95bb59f45a727f9234020adaf2cec9e2020faafb60170bb8d9bbc8c2e", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 2820 + } + ], + "signature": [ + "d28985d624a39eba13b4f694bfd3cd1fa7451b3a047014d55aa1230fbf5148d840fa9239e714ab1e0020dc7e236ae82299685f4a79255acadee11db70b91fca200" + ], + "txID": "745387b731b5b9a4cdee2c1fbaff88bcbc8ee603cd66bfe14cd0da2fe218173a" + }, + { + "block_timestamp": 1581392205000, + "internal_transactions": [], + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2761954, + "asset_name": "1002000", + "owner_address": "417751ef8410331a318d2eb94cdb15e8f2fd4eded0", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1581475762919, + "fee_limit": 0, + "ref_block_bytes": "11cc", + "ref_block_hash": "60d8258a7feac870", + "timestamp": 1581390286202 + }, + "raw_data_hex": "0a0211cc220860d8258a7feac87040e7a5b4ba832e5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a07313030323030301215417751ef8410331a318d2eb94cdb15e8f2fd4eded01a154139fec4d95bb59f45a727f9234020adaf2cec9e2020e2c9a80170fa9ad391832e", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "c85bf358e1f0a6c0a84c82a02f0b47cc3e8c949a8b1c00117187c29ecb5e482c0e8dfa7b7e0c4963d036c5924d336d2ed636fa94601917acdebb8d10e24adb2000" + ], + "txID": "f478e08a3b79c0ede4d2869409792d303dba6591ac0dddf8c98dba6b54cd23dd" + }, + { + "block_timestamp": 1578712149000, + "internal_transactions": [], + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2766009, + "asset_name": "1002000", + "owner_address": "418c946a1b7974c653b5d6b8357c78e0feae15b066", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1578795827650, + "fee_limit": 0, + "ref_block_bytes": "732d", + "ref_block_hash": "f6702c3b51ba7e60", + "timestamp": 1578710431666 + }, + "raw_data_hex": "0a02732d2208f6702c3b51ba7e6040c283c2bcf92d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a07313030323030301215418c946a1b7974c653b5d6b8357c78e0feae15b0661a154139fec4d95bb59f45a727f9234020adaf2cec9e2020b9e9a80170b2efe593f92d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "afdf9e1e4068b132c4327ae0c96cb5ea18d90a39f86aeb7a98c44688e171702f4b025740bbfaf1c7863b5002c8dd21d0ec36c9cfac9d1c43c7d3bb480a8eb31601" + ], + "txID": "ea5211cc65b5f6424fa1d744eb4c21ea9edd451d2171dc6ea102754271d45c45" + }, + { + "block_timestamp": 1576767630000, + "internal_transactions": [], + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 10000000, + "asset_name": "1002814", + "owner_address": "419bd7449f9b84a1083622486c08573a7da0507154", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1576767684000, + "fee_limit": 0, + "ref_block_bytes": "93f5", + "ref_block_hash": "da4f57515fbead80", + "timestamp": 1576767626457 + }, + "raw_data_hex": "0a0293f52208da4f57515fbead8040a0fbb5f5f12d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a07313030323831341215419bd7449f9b84a1083622486c08573a7da05071541a154139fec4d95bb59f45a727f9234020adaf2cec9e202080ade20470d9b9b2f5f12d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "a89953a4b6c17b83570bf0e03a5e3ef4e8a1d73f4e2c70d976863241edcacbf8564cc551ac2738863a0782d3c0475ad316ea28ec1b766b71bb14fcaf5de799c001" + ], + "txID": "cf097ddd585d9bd7634cd78f8d5c19f66be8610befc1036f6db0d29b6004f0a2" + }, + { + "block_timestamp": 1576767615000, + "internal_transactions": [], + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.UnfreezeBalanceContract", + "value": { + "owner_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", + "resource": 0, + "resource_type": "BANDWIDTH" + } + }, + "type": "UnfreezeBalanceContract" + } + ], + "expiration": 1576803608549, + "fee_limit": 0, + "ref_block_bytes": "9401", + "ref_block_hash": "f36c8589c1e80d4c", + "timestamp": 1576767608549 + }, + "raw_data_hex": "0a0294012208f36c8589c1e80d4c40e5cfc686f22d5a53080c124f0a34747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e556e667265657a6542616c616e6365436f6e747261637412170a154139fec4d95bb59f45a727f9234020adaf2cec9e2070e5adb1f5f12d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "b873ad5cd7c00f370b8d395805775a12a3ace3e2025d5171b65d1679b115798400014ffa9a65535918b87022cce17441bf126f2f973d94a6b20f67b9d5d2e00600" + ], + "txID": "969e85b075fc94f8917c00461ed5e55f2e8e49e0ec26f529e7a52821b8ed65f9" + }, + { + "block_timestamp": 1576034517000, + "internal_transactions": [], + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2771361, + "asset_name": "1002000", + "owner_address": "413a094f1775afacfeedfd86a2f8f57f0230ee2723", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1576118376059, + "fee_limit": 0, + "ref_block_bytes": "dc86", + "ref_block_hash": "2f66710df37485fe", + "timestamp": 1576032773155 + }, + "raw_data_hex": "0a02dc8622082f66710df37485fe40fbace7bfef2d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a07313030323030301215413a094f1775afacfeedfd86a2f8f57f0230ee27231a154139fec4d95bb59f45a727f9234020adaf2cec9e2020a193a90170a3c8fe96ef2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "203bf41538ad46bb8477413cb25c61dba24055228ac79935369b84e16114f3873a22a1e78c4c89caf2580e1f48df8ec08b207747794300d4e583102b6f25196901" + ], + "txID": "97d2b6262d685aaa22ea5840bb6793049b908b524d0c5014af1291470f3d6be2" + }, + { + "block_timestamp": 1575142365000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 10000000, + "asset_name": "1002798", + "owner_address": "41aa5e59e84334df05368ae6e720b5167700b42e18", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1575142419000, + "fee_limit": 0, + "ref_block_bytes": "57b2", + "ref_block_hash": "b2ee022babe71218", + "timestamp": 1575142361463 + }, + "raw_data_hex": "0a0257b22208b2ee022babe7121840b8d4b7eeeb2d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a0731303032373938121541aa5e59e84334df05368ae6e720b5167700b42e181a154139fec4d95bb59f45a727f9234020adaf2cec9e202080ade20470f792b4eeeb2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "65bbe799908d92fa9b4c06fa4eaacc537c80a9c32833795197b6d2a88c88f7f45999ba22a930761d61874cc20887210959747a9c9014450a4fe0713cef2c9bc301" + ], + "txID": "af2c820fc24eebbd811da03e4053c0e99638d8220f1a704b5d813ef6f1f2a949" + }, + { + "block_timestamp": 1575142338000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.VoteWitnessContract", + "value": { + "owner_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", + "votes": [ + { + "vote_address": "4178c842ee63b253f8f0d2955bbc582c661a078c9d", + "vote_count": 278 + } + ] + } + }, + "type": "VoteWitnessContract" + } + ], + "expiration": 1575178334333, + "fee_limit": 0, + "ref_block_bytes": "57bb", + "ref_block_hash": "4b3d554e9eed24bf", + "timestamp": 1575142334333 + }, + "raw_data_hex": "0a0257bb22084b3d554e9eed24bf40fde0c7ffeb2d5a6b080412670a30747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e566f74655769746e657373436f6e747261637412330a154139fec4d95bb59f45a727f9234020adaf2cec9e20121a0a154178c842ee63b253f8f0d2955bbc582c661a078c9d10960270fdbeb2eeeb2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "426e9fe96b384552a6cdf06dbd6c644e2ba86d71b7b81d4944df9cf6f7f978f43ff59786927b59592fa7552c460352797b2dddab32700c5ea108e36d6bbc845d00" + ], + "txID": "01700b76279521d69c7b0b0e3ca929fde1630cead2f5f6912df4852e966136e4" + }, + { + "block_timestamp": 1575142329000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.FreezeBalanceContract", + "value": { + "frozen_balance": 278000000, + "frozen_duration": 3, + "owner_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", + "resource": 0, + "resource_type": "BANDWIDTH", + "resource_value": 0 + } + }, + "type": "FreezeBalanceContract" + } + ], + "expiration": 1575178323797, + "fee_limit": 0, + "ref_block_bytes": "57b8", + "ref_block_hash": "af6ffa6819c1f720", + "timestamp": 1575142323797 + }, + "raw_data_hex": "0a0257b82208af6ffa6819c1f72040d58ec7ffeb2d5a59080b12550a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e467265657a6542616c616e6365436f6e7472616374121f0a154139fec4d95bb59f45a727f9234020adaf2cec9e201080e3c78401180370d5ecb1eeeb2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "c6f428b1c3666a5becd409ffe0a8c6535c997466c4ae741de20100f1689157c234ffa0b1f75bf48b0e54a5074bab95e4ad2a119d21819399c99fd9cd1cc8e87100" + ], + "txID": "b56bd0f2bdff2806da052b013a183014b44b3b39797f5c30427695e94c92640d" + }, + { + "block_timestamp": 1573442805000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2773215, + "asset_name": "1002000", + "owner_address": "41eb054d59928ef6600fb86c5a158861d1faaba48e", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1573526182557, + "fee_limit": 0, + "ref_block_bytes": "afb3", + "ref_block_hash": "3c845aa598e806e7", + "timestamp": 1573441188048 + }, + "raw_data_hex": "0a02afb322083c845aa598e806e7409db5e0ebe52d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a0731303032303030121541eb054d59928ef6600fb86c5a158861d1faaba48e1a154139fec4d95bb59f45a727f9234020adaf2cec9e2020dfa1a90170d0e19cc3e52d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "b0b30bad88d0625ce88be0d0dfd4dee1dadce8321b09e98287c20f4c4c82da5b60f4d59f5e9edb0bfea841ef7f4053a242d52a657bf4de925935cfa317e42ba500" + ], + "txID": "d9486e03cdb6720e2995f7140dad80c06aeee1bc118392f166b8031142922c2f" + }, + { + "block_timestamp": 1570766748000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2774263, + "asset_name": "1002000", + "owner_address": "41d629aa1a501663918e9973381a65fa0239f77757", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1570847328110, + "fee_limit": 0, + "ref_block_bytes": "1249", + "ref_block_hash": "f6d9b560f362e182", + "timestamp": 1570763940319 + }, + "raw_data_hex": "0a0212492208f6d9b560f362e18240ee8eb0eedb2d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a0731303032303030121541d629aa1a501663918e9973381a65fa0239f777571a154139fec4d95bb59f45a727f9234020adaf2cec9e2020f7a9a90170dfc3cec6db2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "4c648c6f50cca283dbdcf33bf0f94996ee5596a84d2834a24d8b26d384edfeb30d217fc5df789fb970788db957e373f33a6233631d365ab482a1b2b1064a458901" + ], + "txID": "75e74b1cc3fca10b234193e3ea2314ad6158ee0ad90f115edd6d8d56e85df8fe" + }, + { + "block_timestamp": 1568172852000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2775304, + "asset_name": "1002000", + "owner_address": "41535565ae98247cee9b590983be8d09896f38e318", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1568255474558, + "fee_limit": 0, + "ref_block_bytes": "e6e2", + "ref_block_hash": "46c69a30e7c32b37", + "timestamp": 1568170813057 + }, + "raw_data_hex": "0a02e6e2220846c69a30e7c32b3740fef6bd9ad22d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a0731303032303030121541535565ae98247cee9b590983be8d09896f38e3181a154139fec4d95bb59f45a727f9234020adaf2cec9e202088b2a9017081cd8ef2d12d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "34ba1adc145857be9f77ccb09e9894d9beeb8b1f5d7bfe955ca6b3140113faf511a84388be0636ee2d4bdac3fa60c32337df56a3524a14a46a12566f8df45e0b00" + ], + "txID": "14a51866eebf58440789e617f63dca0f15bbdaf174f80af7c0b1e04b5887d94b" + }, + { + "block_timestamp": 1565486163000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2776267, + "asset_name": "1002000", + "owner_address": "4186da818766179e1fc4c7830ac345936ef3d04e8e", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1565569061084, + "fee_limit": 0, + "ref_block_bytes": "463d", + "ref_block_hash": "4dad9960c2c6d089", + "timestamp": 1565483669805 + }, + "raw_data_hex": "0a02463d22084dad9960c2c6d08940dca1c099c82d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a073130303230303012154186da818766179e1fc4c7830ac345936ef3d04e8e1a154139fec4d95bb59f45a727f9234020adaf2cec9e2020cbb9a90170adb2e4f0c72d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "f4aa7ffefd93421bc5113626c69f509da11746d0c0861990b6272d2290e31b0c2e2572f49469e15a979c514786fbda76b095dd0190f51a38987aaa255f2ccca000" + ], + "txID": "488e57c033a3d6ff193c0bda6f2b0ea224f82ad294b9ba705faaec2bcb02155a" + }, + { + "block_timestamp": 1562826081000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2776887, + "asset_name": "1002000", + "owner_address": "41313dbb31dd9eeb90c535edc7d2048182d3d5740a", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1562910473588, + "fee_limit": 0, + "ref_block_bytes": "ec00", + "ref_block_hash": "3f1eb9822744575d", + "timestamp": 1562824848491 + }, + "raw_data_hex": "0a02ec0022083f1eb9822744575d40f4fae4a5be2d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a0731303032303030121541313dbb31dd9eeb90c535edc7d2048182d3d5740a1a154139fec4d95bb59f45a727f9234020adaf2cec9e2020b7bea90170ebe8fafcbd2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "e2a28a242ac2d028a1771a8900d4b0678bb8a14c6e8b90ea4fdc916f71ed4c9c4f74ff16e0b2041e25936e1a84ed851510b209401e89fe116f2476619bf0f32900" + ], + "txID": "932473d894155439c55efc641c7eac203f9b9cc75aeddff9c4787fb29fc3799f" + }, + { + "block_timestamp": 1560214770000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2777963, + "asset_name": "1002000", + "owner_address": "41535df354e6e25707e2e566426fa9fbe26f2a00b4", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1560298462780, + "fee_limit": 0, + "ref_block_bytes": "b65e", + "ref_block_hash": "eb0ec24fdbaf4166", + "timestamp": 1560213325513 + }, + "raw_data_hex": "0a02b65e2208eb0ec24fdbaf416640bcbca4c8b42d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a0731303032303030121541535df354e6e25707e2e566426fa9fbe26f2a00b41a154139fec4d95bb59f45a727f9234020adaf2cec9e2020ebc6a90170c98dd89fb42d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "876c48d579b68af052bdbbce7e5338950466be7f72c44df177f1bfe619ae83957fb1a1425626c27fa488426f1c33b87cce4887505465864fcb51bc399eb6276901" + ], + "txID": "e0c51b1c38f35f13c45b5b10a8aa6ea03eaba85402a4f99d8b68c795d08fae69" + }, + { + "blockNumber": 9125059, + "block_timestamp": 1557536844000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 2820, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2778999, + "asset_name": "1002000", + "owner_address": "41f0121e7fb828baaf6016c30a38df2852cc91bf63", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1557620299006, + "fee_limit": 0, + "ref_block_bytes": "3950", + "ref_block_hash": "0fa563518d313adc", + "timestamp": 1557535303504 + }, + "raw_data_hex": "0a02395022080fa563518d313adc40fea99ecbaa2d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a0731303032303030121541f0121e7fb828baaf6016c30a38df2852cc91bf631a154139fec4d95bb59f45a727f9234020adaf2cec9e2020f7cea90170d0cedaa2aa2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 2820 + } + ], + "signature": [ + "a84d6291474b6a4403628a0f56ec9af02ae7002e4cec7fb1a222d4e532038852137163131d43e80a9fb304cf448620c009d0fb50d51bbd9409ae28765e81336d01" + ], + "txID": "e557b1e03142d68fce5a82db36f0c404e7db0609c4fd2d14395bab2616eb00ec" + }, + { + "block_timestamp": 1554947670000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 2779810, + "asset_name": "1002000", + "owner_address": "4173760159ffe7116385d5d64890d87f1254be65db", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1555030923157, + "fee_limit": 0, + "ref_block_bytes": "2502", + "ref_block_hash": "074004b3532d4b12", + "timestamp": 1554945513705 + }, + "raw_data_hex": "0a0225022208074004b3532d4b124095afc3f8a02d5a76080212720a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123c0a073130303230303012154173760159ffe7116385d5d64890d87f1254be65db1a154139fec4d95bb59f45a727f9234020adaf2cec9e2020a2d5a90170e9b1e6cfa02d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "c76cf4def7d0a38a5d04045183dc15b6512b576d2e49c110f733a5c7d591f6ee3a09ad6cd417590676aeffa2abcb47be22a19ebddcc2e09f12cd68a9ef6bf13400" + ], + "txID": "fd17c87acc8226989592d93e4e530ef3fe19a1c486259af23ad5ac1a68793d33" + }, + { + "block_timestamp": 1553870898000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 10149740000, + "asset_name": "1002000", + "owner_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1553870955000, + "fee_limit": 0, + "ref_block_bytes": "b560", + "ref_block_hash": "2d9026ee979db6b6", + "timestamp": 1553870897024 + }, + "raw_data_hex": "0a02b56022082d9026ee979db6b640f8c3b4cf9c2d5a77080212730a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123d0a07313030323030301215410583a68a3bcd86c25ab1bee482bac04a216b02611a154139fec4d95bb59f45a727f9234020adaf2cec9e2020e0fbe2e7257080ffb0cf9c2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "10c57bda2346f4cc7e287a2b696fcd8dcbec273d84df8b8d41fcf49d13e02fdf1ca539d1b631feabd58e3f0a8c501c8d74595774fd149cfba16770eb8a4bd18100" + ], + "txID": "d9206168ee601935bb19de30a613f735972f1ab59178ba05d078ff1ae19c0602" + }, + { + "block_timestamp": 1553864040000, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferContract", + "value": { + "amount": 278720000, + "owner_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261", + "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" + } + }, + "type": "TransferContract" + } + ], + "expiration": 1553864097000, + "fee_limit": 0, + "ref_block_bytes": "ac7f", + "ref_block_hash": "648c4cb65453b4de", + "timestamp": 1553864038710 + }, + "raw_data_hex": "0a02ac7f2208648c4cb65453b4de40e8f991cc9c2d5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a15410583a68a3bcd86c25ab1bee482bac04a216b026112154139fec4d95bb59f45a727f9234020adaf2cec9e201880dcf3840170b6b28ecc9c2d", + "ret": [ + { + "code": "SUCESS", + "contractRet": "SUCCESS", + "fee": 0 + } + ], + "signature": [ + "25052c3c653de8c06dc2294f9078a621179102282799f14f4a6950b805e66ea17c1a894a34922d92b7b14aad27cc07aeb129cb31570d55e9f21a0e3f5dd11ce701" + ], + "txID": "3ef5e225ce5bdd01333286e4ab4413ae3da8b80c24b26c5811ae78962940a8ca" + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/tron-api_v1_assets_1002000.json b/mock/ext-api-data/tron-api_v1_assets_1002000.json new file mode 100644 index 000000000..ea4261a3b --- /dev/null +++ b/mock/ext-api-data/tron-api_v1_assets_1002000.json @@ -0,0 +1,23 @@ +{ + "success": true, + "meta": { + "at": 1589387413939, + "page_size": 1 + }, + "data": [ + { + "id": "1002000", + "abbr": "BTT", + "description": "Official Token of BitTorrent Protocol", + "name": "BitTorrent", + "num": 1, + "precision": 6, + "total_supply": "990000000000000000", + "trx_num": 1, + "url": "www.bittorrent.com", + "owner_address": "4137fa1a56eb8c503624701d776d95f6dae1d9f0d6", + "start_time": 1548000000000, + "end_time": 1548000001000 + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/tron-api_v1_assets_1002798.json b/mock/ext-api-data/tron-api_v1_assets_1002798.json new file mode 100644 index 000000000..b5c850fad --- /dev/null +++ b/mock/ext-api-data/tron-api_v1_assets_1002798.json @@ -0,0 +1,24 @@ +{ + "success": true, + "meta": { + "at": 1589366702515, + "page_size": 1 + }, + "data": [ + { + "id": "1002798", + "abbr": "EPICAL", + "description": "The token of the game Builder III", + "name": "EPICAL", + "num": 1000000000, + "precision": 6, + "total_supply": "10000000000000000", + "trx_num": 1000000000, + "url": "https://builder3.fun", + "vote_score": 0, + "owner_address": "41133b084f5225a9112f4e8527db26b381a32babd0", + "start_time": 1574966426578, + "end_time": 1574966486578 + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/tron-api_v1_assets_1002814.json b/mock/ext-api-data/tron-api_v1_assets_1002814.json new file mode 100644 index 000000000..8af11521d --- /dev/null +++ b/mock/ext-api-data/tron-api_v1_assets_1002814.json @@ -0,0 +1,24 @@ +{ + "success": true, + "meta": { + "at": 1589387440079, + "page_size": 1 + }, + "data": [ + { + "id": "1002814", + "abbr": "AX", + "description": "The token of the game TrainX", + "name": "AX", + "num": 1000000000, + "precision": 6, + "total_supply": "10000000000000000", + "trx_num": 1000000000, + "url": "https://trainx.fun", + "vote_score": 0, + "owner_address": "418e267ead411aaaf671be100a7afe587d4eab0d71", + "start_time": 1576483805985, + "end_time": 1576483865985 + } + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/tron-api_wallet_getaccount.json b/mock/ext-api-data/tron-api_wallet_getaccount.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/mock/ext-api-data/tron-api_wallet_getaccount.json @@ -0,0 +1 @@ +{} diff --git a/mock/ext-api-data/tron-api_wallet_getaccount.request_json b/mock/ext-api-data/tron-api_wallet_getaccount.request_json new file mode 100644 index 000000000..bd1460390 --- /dev/null +++ b/mock/ext-api-data/tron-api_wallet_getaccount.request_json @@ -0,0 +1 @@ +{"address":"TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB","visible":true} diff --git a/mock/ext-api-data/tron-api_wallet_listwitnesses.json b/mock/ext-api-data/tron-api_wallet_listwitnesses.json new file mode 100644 index 000000000..ac7a02b97 --- /dev/null +++ b/mock/ext-api-data/tron-api_wallet_listwitnesses.json @@ -0,0 +1,1617 @@ +{ + "witnesses": [ + { + "address": "417bdd2efb4401c50b6ad255e6428ba688e0b83f81", + "voteCount": 298493753, + "url": "https://minergate.com", + "totalProduced": 409483, + "totalMissed": 801, + "latestBlockNum": 19700720, + "latestSlotNum": 529788893, + "isJobs": true + }, + { + "address": "41d376d829440505ea13c9d1c455317d51b62e4ab6", + "voteCount": 317269760, + "url": "http://blockchain.org", + "totalProduced": 482712, + "totalMissed": 2654, + "latestBlockNum": 19700712, + "latestSlotNum": 529788885, + "isJobs": true + }, + { + "address": "4138e3e3a163163db1f6cfceca1d1c64594dd1f0ca", + "voteCount": 312761034, + "url": "https://twitter.com/justinsuntron", + "totalProduced": 678403, + "totalMissed": 1714, + "latestBlockNum": 19700713, + "latestSlotNum": 529788886, + "isJobs": true + }, + { + "address": "41037e18c9ca44b2ba35f0bb7d0c075f252a191294", + "voteCount": 299572403, + "url": "https://trxultra.org", + "totalProduced": 414497, + "totalMissed": 1608, + "latestBlockNum": 19700719, + "latestSlotNum": 529788892, + "isJobs": true + }, + { + "address": "4114f2c09d3de3fe82a71960da65d4935a30b24e1f", + "voteCount": 304155685, + "url": "https://staked.us", + "totalProduced": 11668, + "latestBlockNum": 19700717, + "latestSlotNum": 529788890, + "isJobs": true + }, + { + "address": "41c05142fd1ca1e03688a43585096866ae658f2cb2", + "voteCount": 312143320, + "url": "http://tronalliance.org", + "totalProduced": 475137, + "totalMissed": 1236, + "latestBlockNum": 19700714, + "latestSlotNum": 529788887, + "isJobs": true + }, + { + "address": "41f29f57614a6b201729473c837e1d2879e9f90b8e", + "voteCount": 330655577, + "url": "https://www.utorrent.com/", + "totalProduced": 695385, + "totalMissed": 1972, + "latestBlockNum": 19700710, + "latestSlotNum": 529788883, + "isJobs": true + }, + { + "address": "4118e2e1c6cdf4b74b7c1eb84682e503213a174955", + "voteCount": 307176451, + "url": "https://tronscan.org", + "totalProduced": 419985, + "totalMissed": 436, + "latestBlockNum": 19700716, + "latestSlotNum": 529788889, + "isJobs": true + }, + { + "address": "41a9d4b388c009b7ee36819114b8558d078103ad0b", + "voteCount": 300055396, + "url": "https://hitbtc.com", + "totalProduced": 402664, + "totalMissed": 4553, + "latestBlockNum": 19700718, + "latestSlotNum": 529788891, + "isJobs": true + }, + { + "address": "414d1ef8673f916debb7e2515a8f3ecaf2611034aa", + "voteCount": 364140926, + "url": "https://www.sesameseed.org", + "totalProduced": 711187, + "totalMissed": 5755, + "latestBlockNum": 19700704, + "latestSlotNum": 529788877, + "isJobs": true + }, + { + "address": "4192c5d96c3b847268f4cb3e33b87ecfc67b5ce3de", + "voteCount": 330908358, + "url": "https://infstones.io/", + "totalProduced": 572555, + "totalMissed": 2232, + "latestBlockNum": 19700709, + "latestSlotNum": 529788882, + "isJobs": true + }, + { + "address": "4178c842ee63b253f8f0d2955bbc582c661a078c9d", + "voteCount": 311816791, + "url": "https://www.binance.com/en/staking", + "totalProduced": 241472, + "totalMissed": 73, + "latestBlockNum": 19700715, + "latestSlotNum": 529788888, + "isJobs": true + }, + { + "address": "415863f6091b8e71766da808b1dd3159790f61de7d", + "voteCount": 341400688, + "url": "https://www.huobipool.com", + "totalProduced": 662003, + "totalMissed": 7871, + "latestBlockNum": 19700706, + "latestSlotNum": 529788879, + "isJobs": true + }, + { + "address": "41e40302d6b5e889bfbd395ed884638d7f03ee3f87", + "voteCount": 344070018, + "url": "https://tronlink.org", + "totalProduced": 413730, + "totalMissed": 331, + "latestBlockNum": 19700705, + "latestSlotNum": 529788878, + "isJobs": true + }, + { + "address": "41beab998551416b02f6721129bb01b51fceceba08", + "voteCount": 330974623, + "url": "https://tronspark.com", + "totalProduced": 671456, + "totalMissed": 3504, + "latestBlockNum": 19700708, + "latestSlotNum": 529788881, + "isJobs": true + }, + { + "address": "41c189fa6fc9ed7a3580c3fe291915d5c6a6259be7", + "voteCount": 327673142, + "url": "https://www.cryptoguyinza.co.za/", + "totalProduced": 703648, + "totalMissed": 2328, + "latestBlockNum": 19700711, + "latestSlotNum": 529788884, + "isJobs": true + }, + { + "address": "41c81107148e5fa4b4a2edf3d5354db6c6be5b5549", + "voteCount": 367283865, + "url": "https://www.trongrid.io", + "totalProduced": 338991, + "totalMissed": 95, + "latestBlockNum": 19700703, + "latestSlotNum": 529788876, + "isJobs": true + }, + { + "address": "4167e39013be3cdd3814bed152d7439fb5b6791409", + "voteCount": 334317801, + "url": "http://cryptochain.network", + "totalProduced": 695157, + "totalMissed": 2269, + "latestBlockNum": 19700707, + "latestSlotNum": 529788880, + "isJobs": true + }, + { + "address": "4100e9fdbd1d24ab56996bd37d76fb7b16dcf62ff1", + "voteCount": 288043, + "url": "https://www.tronmacau.com" + }, + { + "address": "41012f81bd368f632fb22b9ddfeb284155f1f04198", + "voteCount": 213, + "url": "https://firekraken.media" + }, + { + "address": "4101c17562ee5a1ecb60f9ea6e49ef94ec0de99580", + "voteCount": 113369, + "url": "https://tronpad.com" + }, + { + "address": "4102a0ed82a9609e7ea9155f00137dc3fce818033f", + "voteCount": 1834997, + "url": "XREGlobal.com" + }, + { + "address": "4102f95b2185f52ac539128b28033998ab01466986", + "voteCount": 114, + "url": "http://imcash.io" + }, + { + "address": "4103ca8124bfa7c06b20b2e3d2278f67d5d1cb6a66", + "voteCount": 151702, + "url": "https://twitter.com/mr_oceanview" + }, + { + "address": "41061e3f4e108d8aaf5cd75b499f811ae30ed04b77", + "voteCount": 87612, + "url": "https://dexnode.net" + }, + { + "address": "410694981b116304ed21e05896fb16a6bc2e91c92c", + "voteCount": 1501, + "url": "http://TronGr21.com", + "totalProduced": 28449, + "latestBlockNum": 1614751, + "latestSlotNum": 511581581 + }, + { + "address": "41080126628c7a8c7edfddf6a027e458f0001d2e09", + "voteCount": 248, + "url": "https://rinzler.eu" + }, + { + "address": "4108b55b2611ec829d308a62b3339fba9dd5c27151", + "voteCount": 203, + "url": "http://TronGr5.com", + "totalProduced": 36710, + "latestBlockNum": 1226106, + "latestSlotNum": 511192800 + }, + { + "address": "410b05a97454cc7aac6e736b4390ee751665941568", + "voteCount": 778744, + "url": "http://test.com" + }, + { + "address": "410c6747caa68213bd0d1f3ed891ee93b090fbf223", + "voteCount": 3408489, + "url": "https://bixin.com" + }, + { + "address": "4110dc5d4731b5463c372a5615d47fc4ad470c3c6b", + "voteCount": 1037, + "url": "http://www.ocoins.cc/" + }, + { + "address": "411103d62d8299e90fa011b4ce7fc6ba151e5f1a23", + "voteCount": 106693397, + "url": "https://www.tronvietnam.com/", + "totalProduced": 594831, + "totalMissed": 9060, + "latestBlockNum": 17299301, + "latestSlotNum": 527385598 + }, + { + "address": "411155d10415fac16a8f4cb2f382ce0e0f0a7e64cc", + "voteCount": 1029, + "url": "http://TronGr22.com", + "totalProduced": 21773, + "latestBlockNum": 1593157, + "latestSlotNum": 511559981 + }, + { + "address": "41137c94812b79641515e92c5a567bd3a79d1f9f7b", + "voteCount": 29003, + "url": "http://tronjapan.io" + }, + { + "address": "4116329c4b64920408342e66221a1d52a974901984", + "voteCount": 7678, + "url": "https://trx.bitcoingod.org" + }, + { + "address": "4116440834509c59de4ee6ba4933678626f451befe", + "voteCount": 801768, + "url": "https://WINTokenGames.com", + "totalProduced": 104760, + "totalMissed": 819, + "latestBlockNum": 4144662, + "latestSlotNum": 514129269 + }, + { + "address": "411661f25387370c9cd3a9a5d97e60ca90f4844e7e", + "voteCount": 611, + "url": "http://TronGr8.com", + "totalProduced": 47910, + "totalMissed": 1, + "latestBlockNum": 1650122, + "latestSlotNum": 511617599 + }, + { + "address": "41167647e8720a4ac305c1c0fa3c71e8a7be3d7d39", + "voteCount": 15001, + "url": "NULL.DAT" + }, + { + "address": "4116aaab3741fc65dc875585ee7eae622daaf425ca", + "voteCount": 20, + "url": "http://blog.naver.com/coolkim01" + }, + { + "address": "4119bec4e96e417f936d40bd4fe3876d1a516a064d", + "voteCount": 340228, + "url": "digitalgeotreasure.com/" + }, + { + "address": "411d7aba13ea199a63d1647e58e39c16a9bb9da689", + "voteCount": 29410, + "url": "http://TronGr20.com", + "totalProduced": 56172, + "latestBlockNum": 1549970, + "latestSlotNum": 511516780 + }, + { + "address": "411e65f18ba80f132fa645727f4dd05cd7eb72e3b1", + "voteCount": 251, + "url": "https://theseusx.net" + }, + { + "address": "411ec54599d42f1e2e699cd1c24dcd79644d8b3e19", + "voteCount": 196, + "url": "https://twitter.com/KaanKOZANn" + }, + { + "address": "41207ab1585b9cc6c4c1232f67e4a10e19a442fe68", + "voteCount": 501, + "url": "http://TronGr10.com", + "totalProduced": 26298, + "latestBlockNum": 1076255, + "latestSlotNum": 511041581 + }, + { + "address": "4121eca596da7e2465b390df2e8bd297881ab3dc57", + "voteCount": 139058, + "url": "https://tronsecure.io" + }, + { + "address": "4123d6947ca8b9b3748f1d1aac88a0867d415d4ac9", + "voteCount": 601, + "url": "http://www.trongalaxy.io" + }, + { + "address": "41241d998b00b3431e3b2d1cce714566659ccaef5c", + "voteCount": 584, + "url": "https://www.museprotocol.com" + }, + { + "address": "41243accc5241d97ce79272b06952ee88a34d8e1f9", + "voteCount": 6490100, + "url": "https://www.tronics.io/", + "totalProduced": 134119, + "totalMissed": 96, + "latestBlockNum": 4203064, + "latestSlotNum": 514187999 + }, + { + "address": "4124443254e2d1f3e1f55521d518bd875138f4173c", + "voteCount": 6594518, + "url": "http://www.communitynode.org/" + }, + { + "address": "41247c3c989c2d31e454ba06e6d9d421908d7a0fd8", + "voteCount": 67132, + "url": "https://tronlottery.io" + }, + { + "address": "41267e38504037133a20a79d38dfbb2cf0988942e6", + "voteCount": 61, + "url": "https://reyna2.com" + }, + { + "address": "4127a6419bbe59f4e64a064d710787e578a150d6a7", + "voteCount": 2732, + "url": "http://TronGr4.com", + "totalProduced": 53772, + "latestBlockNum": 1513990, + "latestSlotNum": 511480789 + }, + { + "address": "4127bf0d1a57f335c11bc5d002dd82e9e0727cb967", + "voteCount": 1214, + "url": "http://TronGr26.com", + "totalProduced": 24711, + "latestBlockNum": 1104788, + "latestSlotNum": 511070388 + }, + { + "address": "4128283cfbbffe9e267fb32bfef1e0533042ad3756", + "voteCount": 61611, + "url": "https://www.tronboston.com" + }, + { + "address": "412929e0e1d5d0ba3b68d8e3a376ef884ab23dd8e0", + "voteCount": 300, + "url": "http://hqn.vn" + }, + { + "address": "4129f3dd5bb0941bde8dc4538332c14fca595a7fe0", + "voteCount": 604, + "url": "http://www.tron.school/" + }, + { + "address": "412a5308a747e62dda5fd06cf516b31bf746ce2b3d", + "voteCount": 600, + "url": "http://www.linkvc.com/" + }, + { + "address": "412c31119d41ba850dd666b6d7d5c52ec85da9e4ef", + "voteCount": 120, + "url": "http://cryptochain.network" + }, + { + "address": "412d62975bc329b501368110f435cd8d277a1115e9", + "voteCount": 79535, + "url": "https://sites.google.com/view/proudbtc1nvest/startsida" + }, + { + "address": "412d7bdb9846499a2e5e6c5a7e6fb05731c83107c7", + "voteCount": 407990435, + "url": "https://www.tronwallet.me/", + "totalProduced": 588418, + "totalMissed": 1230, + "latestBlockNum": 19700702, + "latestSlotNum": 529788875, + "isJobs": true + }, + { + "address": "412edce151c81d9b4aae17f974f7f646242eff989d", + "voteCount": 1839, + "url": "http://TronGr14.com", + "totalProduced": 27117, + "latestBlockNum": 760520, + "latestSlotNum": 510724788 + }, + { + "address": "412fb5abdf8a1670f533c219e7251fe30b89849359", + "voteCount": 6061915, + "url": "http://www.lianjinshu.com", + "totalProduced": 405906, + "totalMissed": 6512, + "latestBlockNum": 11497746, + "latestSlotNum": 521575194 + }, + { + "address": "412ff2cc08e2b4ae41adae991b20c582f42c958efa", + "url": "http://the-crazy-once.de" + }, + { + "address": "41318b2b6b4c7fcaa4b62f25a282329e1952a3c0d1", + "voteCount": 1525, + "url": "http://TronGr23.com", + "totalProduced": 19115, + "latestBlockNum": 1557177, + "latestSlotNum": 511523990 + }, + { + "address": "4131b0bbc3ec749ed0666e4ea6db0a58d464daf007", + "voteCount": 17, + "url": "https://darano.network/" + }, + { + "address": "4132c014adb6ff15038d5b67d97046c2556d9a9dc3", + "voteCount": 711, + "url": "https://www.robocoinexchange.com" + }, + { + "address": "41333bf31c095163a07e14a75c1f717f99f7934a8c", + "voteCount": 17712832, + "url": "\thttps://www.cashierest.com" + }, + { + "address": "4135c07ff4c26880a9c758a8b15e6fa1ad6d7e18a2", + "voteCount": 905197, + "url": "https://noraigi.com/en/home" + }, + { + "address": "4135c3c756c094d7b7f4f733f5b61bafc36b52510b", + "voteCount": 52, + "url": "https://inrtoken.io/" + }, + { + "address": "4135d7a72c7431d36f076d2c078a149a9037bb244b", + "voteCount": 27, + "url": "http://t.me/TheL1Crew" + }, + { + "address": "41362519bf874a901e7488fba6a0e06bc6ba781489", + "voteCount": 2239, + "url": "http://www.meg4tron.com/" + }, + { + "address": "4139801ec34decc39c8c206b46c79cd2c46f48e08a", + "voteCount": 408495, + "url": "." + }, + { + "address": "413ba13182b026a6e8ec8af2302ad86d221682000d", + "voteCount": 2138794, + "url": "https://www.coinnest.co.kr" + }, + { + "address": "413d2e1a011533da0da6f5b4d07384945b45e0cd0e", + "voteCount": 4415, + "url": "https://helloworldteam.org" + }, + { + "address": "413dd6a14c95be5d43d1d1e51f94205ffbfc63b8fb", + "voteCount": 93766, + "url": "https://tronbet.com", + "totalProduced": 13060, + "totalMissed": 1, + "latestBlockNum": 4259295, + "latestSlotNum": 514245587 + }, + { + "address": "413f5f20247069fe5b674ed21c693f7d382db0b8e0", + "voteCount": 54, + "url": "https://atticlab.net" + }, + { + "address": "414061ef90a87bf861cb5dddb7897f60ffd1f36372", + "voteCount": 82007323, + "url": "https://www.nodeasy.com" + }, + { + "address": "4140c59d6ae1923d3a67bc49b40981c1569b8a2475", + "voteCount": 1621, + "url": "https://tronkh.org" + }, + { + "address": "41410e468919155aa847d83b0c206148511b6dc848", + "voteCount": 5501, + "url": "http://TronGr11.com", + "totalProduced": 30041, + "totalMissed": 5, + "latestBlockNum": 1463589, + "latestSlotNum": 511430374 + }, + { + "address": "41411d7f31ae1a4840458667c52ac1e4d25843e009", + "voteCount": 1083, + "url": "https://globalricetoken.wixsite.com/grttoken" + }, + { + "address": "4141b285495e0dba4a39fe79dba38b068506b2f841", + "voteCount": 31, + "url": "http://tronman.io/" + }, + { + "address": "4142e95c76430e62dfe5182d58f46a482101648304", + "voteCount": 782704, + "url": "https://member.alleexchange.com", + "totalProduced": 37122, + "totalMissed": 1002, + "latestBlockNum": 5116518, + "latestSlotNum": 515131163 + }, + { + "address": "41432bd4093f1c8ef0ffe38f5e2f75f52c884c1986", + "voteCount": 645, + "url": "http://jdi.group" + }, + { + "address": "414431bf75a2acb6e36802a371447ffe559f3cf642", + "voteCount": 30086, + "url": "https://www.tron.buzz" + }, + { + "address": "414593d27b70d21454b39ab60bf13291dae8dc0326", + "voteCount": 4236, + "url": "http://TronGr16.com", + "totalProduced": 54023, + "totalMissed": 559, + "latestBlockNum": 1542790, + "latestSlotNum": 511509598 + }, + { + "address": "4145955a72c20b65ce9bae07830ce240bff3108389", + "voteCount": 521, + "url": "https://trongameglobal.network" + }, + { + "address": "41460b49a0ec5ce6340ff40020704f21b1d4e4f7ff", + "voteCount": 6, + "url": "http://www.nextgenius.com.au" + }, + { + "address": "4147e83677cf459b0bdc976ae6fe27b91c0d49329d", + "voteCount": 827, + "url": "http://VeganIS.ME/" + }, + { + "address": "414853b6a81a6ea7be929758c6adafda1f4f4faea2", + "voteCount": 600, + "url": "https://DoNotVote-Not-Active-SR" + }, + { + "address": "41496e85711fa3b7ba5a093af635269a67230ac2c1", + "voteCount": 21774463, + "url": "https://www.beatzcoin.io/", + "totalProduced": 221974, + "totalMissed": 3004, + "latestBlockNum": 14077587, + "latestSlotNum": 524159989 + }, + { + "address": "4149939465083f75a8769087f89aaf68032b575ceb", + "voteCount": 2963, + "url": "https://t.me/joinchat/F5QrYU9C8y-nAN2w0M327Q" + }, + { + "address": "4149f34cc0e7eecf4ad4515b7f5a5c333469f76ca5", + "voteCount": 15957, + "url": "https://twitter.com/1000WONG" + }, + { + "address": "414a193c92cd631c1911b99ca964da8fd342f4cddd", + "voteCount": 462393856, + "url": "http://www.skypeople.co.kr", + "totalProduced": 726373, + "totalMissed": 4883, + "latestBlockNum": 19700700, + "latestSlotNum": 529788873, + "isJobs": true + }, + { + "address": "414ac0706a3d08c0416ad361878b05d6fc8d36863e", + "voteCount": 207208, + "url": "https://cobo.com" + }, + { + "address": "414b4778beebb48abe0bc1df42e92e0fe64d0c8685", + "voteCount": 701, + "url": "http://TronGr7.com", + "totalProduced": 35113, + "latestBlockNum": 1571562, + "latestSlotNum": 511538379 + }, + { + "address": "414c121deddd140d5969dbbd8ac3aa611421251ecf", + "voteCount": 128, + "url": "http://he.capital/" + }, + { + "address": "414dd6d662582d5b6ff6c5b824a2b194f41e361631", + "voteCount": 5004, + "url": "https://tron.34rth.com/" + }, + { + "address": "414e785037af0091f269d1d47506be94336b317e86", + "voteCount": 12400, + "url": "https://gotno.life" + }, + { + "address": "415095d4f4d26ebc672ca12fc0e3a48d6ce3b169d2", + "voteCount": 5782, + "url": "http://TronGr1.com", + "totalProduced": 58297, + "latestBlockNum": 1621714, + "latestSlotNum": 511588788 + }, + { + "address": "4150eae1569968dbb87bbd786e6cfbf60c47464644", + "voteCount": 142499, + "url": "https://CharityCompassionCoin.com" + }, + { + "address": "4152a5962248ce05bcd114f976304eb2d052b6f034", + "voteCount": 12734, + "url": "https://www.neoply.com" + }, + { + "address": "4152bb0b293d6441ef44a36b92a290f0a9b952ffa0", + "voteCount": 2, + "url": "VoteTronicStorm" + }, + { + "address": "4152cca32a23b5a78b26237cb3ef587a0f20d113e1", + "voteCount": 20658, + "url": "https://www.thz.net" + }, + { + "address": "41530f931037de0c369968a5cf622003d240ef96e2", + "voteCount": 459657456, + "url": "https://www.beekuaibao.com", + "totalProduced": 213438, + "totalMissed": 475, + "latestBlockNum": 19700701, + "latestSlotNum": 529788874, + "isJobs": true + }, + { + "address": "41561bfd00769866b44282b773f2ed8bba00907dd9", + "voteCount": 35, + "url": "https://www.rightbtc.com" + }, + { + "address": "4157c381611f36ee7da21e6ab0bdc825774045de83", + "voteCount": 196, + "url": "https://www.livenodes.network/" + }, + { + "address": "415a8f7b00624fbcc0ec022d91a04000f573356cb9", + "voteCount": 408, + "url": "Https://www.numeriuno.eu" + }, + { + "address": "415baad9ab1e821a81ad4d512d71037326e3b04126", + "voteCount": 1260157, + "url": "http://troncoin.nl" + }, + { + "address": "415c6202be8f2a984c8f73f4d9fd841c0bfca8e3be", + "voteCount": 299011, + "url": "https://tronhope.org/" + }, + { + "address": "415c7f4890ed927ad276401851f38575fe42ff2eb3", + "voteCount": 12270, + "url": "https://www.cityuptake.com" + }, + { + "address": "415dc72ddad8966b1e22dfc94980243fce1c75ef9b", + "voteCount": 86686, + "url": "https://www.tron-mining.com" + }, + { + "address": "415f9d90205868184e240937140ab44b30f8012dbf", + "voteCount": 2033040, + "url": "www" + }, + { + "address": "416202093e031985b877eb60d508f583f45b50ae16", + "voteCount": 502, + "url": "http://www.apexinformatics.com" + }, + { + "address": "4162398d516b555ac64af24416e05c199c01823048", + "voteCount": 901559198, + "url": "https://poloniex.com/", + "totalProduced": 89458, + "totalMissed": 5, + "latestBlockNum": 19700698, + "latestSlotNum": 529788871, + "isJobs": true + }, + { + "address": "4162e1a76d28c0bee6eb56a53e864c810514c7fa08", + "voteCount": 1322, + "url": "www.tronixglobal.com" + }, + { + "address": "4163233b6d495606ded800a4e2d7b2a5eafbf4e53b", + "voteCount": 207, + "url": "https://molotovlab.com" + }, + { + "address": "4163ca1146abdf34944b5b84d62deac68b56fdc0f9", + "voteCount": 1837235, + "url": "https://activ8coin.com" + }, + { + "address": "416419765bacf1dc441f722cabc8b661140558bb5d", + "voteCount": 3257, + "url": "http://TronGr6.com", + "totalProduced": 55640, + "totalMissed": 1, + "latestBlockNum": 1513988, + "latestSlotNum": 511480787 + }, + { + "address": "4164bba21b3e2d1635fdf3eea556fe1e98763eb8a6", + "voteCount": 339976, + "url": "https://tran.systems/tronhub/" + }, + { + "address": "4165ad45cfb233daa0816f5df5444c5c5f4a189f20", + "voteCount": 501, + "url": "http://d2fapp.com" + }, + { + "address": "41685ef5321f2d94080d6bdcd1d4cbdded428cecb6", + "voteCount": 3529011, + "url": "http://tronkorea.io", + "totalProduced": 238, + "totalMissed": 28, + "latestBlockNum": 300029, + "latestSlotNum": 510263985 + }, + { + "address": "4168e2922f40b2971311b5e57b7573c526399860d0", + "voteCount": 158723, + "url": "https://promo.network/" + }, + { + "address": "4169051b001c6169201970f5a6a4f9ababfd916ae3", + "voteCount": 690238, + "url": "https://WinTokenGames.com", + "totalProduced": 23273, + "totalMissed": 187, + "latestBlockNum": 4791405, + "latestSlotNum": 514782404 + }, + { + "address": "416f849a033d62d854b6daad9052f6d9686c60c1c6", + "voteCount": 88, + "url": "https://cobo.com" + }, + { + "address": "417040583133e831953ea4f65a8196fcffcfbf0d80", + "voteCount": 330, + "url": "http://TronGr13.com", + "totalProduced": 24448, + "latestBlockNum": 1571564, + "latestSlotNum": 511538381 + }, + { + "address": "41704833c02883b3261f7baf62f8cb19b4b0c2e64e", + "voteCount": 6167, + "url": "https://game.com" + }, + { + "address": "4170b1be516ef67e1ca019d78b2112ccc8a3e8bd1b", + "voteCount": 7038, + "url": "https://tronvip.io" + }, + { + "address": "4172fd5dfb8ab36eb28df8e4aee97966a60ebf9efe", + "voteCount": 315, + "url": "http://TronGr27.com", + "totalProduced": 30838, + "latestBlockNum": 1513987, + "latestSlotNum": 511480786 + }, + { + "address": "417312080619a24d38a2029b724ff5c84d8f2e4483", + "voteCount": 9672, + "url": "https://weibo.com/bitdog666", + "totalProduced": 27199, + "totalMissed": 1, + "latestBlockNum": 3226491, + "latestSlotNum": 513208790 + }, + { + "address": "41746e6af4ac9db3473c0c955f1fca11d4013f32ed", + "voteCount": 7831, + "url": "http://TronGr17.com", + "totalProduced": 49765, + "totalMissed": 8, + "latestBlockNum": 1650121, + "latestSlotNum": 511617598 + }, + { + "address": "4175f1045e92680e52d072c1f92dec0874a8cbe2cc", + "voteCount": 35, + "url": "https://gconnect.io/" + }, + { + "address": "41770407d686a8a57c035a9615f25e4a7748a67739", + "voteCount": 416861, + "url": "http://tronshares.com" + }, + { + "address": "41788cd87d1525c0163240cd8832863845605fddc8", + "voteCount": 303500, + "url": "https://kryptowaluty.org.pl" + }, + { + "address": "4178af3274df44866a5bb63671d648583fce7ab08e", + "voteCount": 519, + "url": "https://c773.com/" + }, + { + "address": "4179497d5a29cbade8fac1394148379037e5618aed", + "voteCount": 4052, + "url": "http://tron-man.com/" + }, + { + "address": "417ad0ee1300d0366e901fa613a929137dde1d2224", + "voteCount": 221419, + "url": "https://mlgblockchain.com", + "totalProduced": 16896, + "totalMissed": 963, + "latestBlockNum": 1370030, + "latestSlotNum": 511336789 + }, + { + "address": "417b88db9da8aacae0a7e967d24c0fc00129e815f6", + "voteCount": 1498089, + "url": "www.Tron-Europe.com", + "totalProduced": 122888, + "totalMissed": 5326, + "latestBlockNum": 5101331, + "latestSlotNum": 515111693 + }, + { + "address": "417d0fa745bc8ee7137544ef93230089a34846892b", + "voteCount": 167, + "url": "https://cobo.com" + }, + { + "address": "417ec8dc8ceebf5e8b37875a3ab2769e93454465b9", + "voteCount": 2465, + "url": "Change Your Vote From This SR Position, To Our New SR Position: \"DEXExchange-DEXCOIN\"" + }, + { + "address": "417ecf3ba1ea90bce91a3b82c0774811d886bd85f6", + "voteCount": 240486, + "url": " https://www.phituasesor.com/smart-2/" + }, + { + "address": "4181d3b51217f51831d1600dc1903c7b7a3bbd5444", + "voteCount": 247, + "url": "https://twitter.com/@brianjun09" + }, + { + "address": "418276c0d4adc3f99daf592d90369f64ee16d1fb94", + "voteCount": 57667, + "url": "https://twitter.com/black0din" + }, + { + "address": "418343eae219414f585c21cd0c6610c0b0de19dedf", + "voteCount": 979612, + "url": "http://tronsiqveland.co.uk/" + }, + { + "address": "4183bbde499a4e7792dbf69033115180a36630cb8d", + "voteCount": 10, + "url": "https://www.wunderchain.com" + }, + { + "address": "41841201843fc3b0ee68a36ada464f606e82a53b05", + "voteCount": 5540, + "url": "https://gravelproject.io/" + }, + { + "address": "4184399fc6a98edc11a6efb146e86a3e153d0a0933", + "voteCount": 295142167, + "url": "https://www.tron-europe.org", + "totalProduced": 468341, + "totalMissed": 1894, + "latestBlockNum": 19700696, + "latestSlotNum": 529788869, + "isJobs": true + }, + { + "address": "418440ffd578f7a5abf3537b5f46a6980d382db581", + "voteCount": 17708684, + "url": "https://www.huobiwallet.com/" + }, + { + "address": "418565229cdbc48f6155c9863abedff8c8f3f61fcf", + "voteCount": 1616254, + "url": "https://twitter.com/TronsRocknRoll" + }, + { + "address": "41856eef3d964e450b52def7c0d49bb5719d2d22d3", + "voteCount": 11560, + "url": "tronsr", + "totalProduced": 1065, + "latestBlockNum": 3908714, + "latestSlotNum": 513892774 + }, + { + "address": "4185a503b5341d9628618d92b97d506788b92d0a12", + "voteCount": 32042, + "url": "http://www.tron-france.com" + }, + { + "address": "41869648f6368ec64afa4a68e00bd6864ee1b13583", + "voteCount": 4824, + "url": "https://www.gameoftron.net/" + }, + { + "address": "4186f5793eb678c65d9673d5498c550439d762c1cc", + "voteCount": 3370, + "url": "http://TronGr12.com", + "totalProduced": 46832, + "latestBlockNum": 1492394, + "latestSlotNum": 511459187 + }, + { + "address": "4187269d327159dcf579f267aa8d44631c49c7d8d6", + "voteCount": 3678, + "url": "https://www.google.com/" + }, + { + "address": "4187de03394f21e3d7b2e630296e4ea1ea994bb6d3", + "voteCount": 98664314, + "url": "https://tron.newdex.one" + }, + { + "address": "418891e5cd756727a61f2332bbaef99722a4e6d8b7", + "voteCount": 505, + "url": "http://www.tronium.net" + }, + { + "address": "418a445facc2aa94d72292ebbcb2a611e9fd8a6c6e", + "voteCount": 295494001, + "url": "http://zempty.peiwo.cn/", + "totalProduced": 559467, + "totalMissed": 1861, + "latestBlockNum": 19700695, + "latestSlotNum": 529788868, + "isJobs": true + }, + { + "address": "418a470d3a9614f93f43b332ba49b8848c26598352", + "voteCount": 800, + "url": "https://tronix.international/" + }, + { + "address": "418ac86d2381c71c405bd0703a944d428ac49a01a8", + "voteCount": 25, + "url": "www.upvote.world TBD" + }, + { + "address": "418ae580dfed3ce5c55232fb506c768463d68cf0db", + "voteCount": 376058, + "url": "https://www.baggi.co/" + }, + { + "address": "418b50e0f2952edcd43391aede597b85408f7eb4a2", + "voteCount": 250, + "url": "www.dtroynx.com" + }, + { + "address": "418bbd49f14ddd5d1ff996ccbbcde9ed0416c5a216", + "voteCount": 1000, + "url": "ffgtrgh" + }, + { + "address": "418c2e9bbc8c6fff0f947f264fae318b53815b4af7", + "voteCount": 103954, + "url": "https://healthport.io/" + }, + { + "address": "418c66e4883782b793fcf2dcb92b23eece57769499", + "voteCount": 290038614, + "url": "http://www.thelast.me", + "totalProduced": 215545, + "totalMissed": 3326, + "latestBlockNum": 18946553, + "latestSlotNum": 529034381 + }, + { + "address": "4193a8bc2e7d6bb1bd75fb2d74107ffbda81af439d", + "voteCount": 1839063, + "url": "http://www.cryptodiva.io/", + "totalProduced": 503055, + "totalMissed": 4892, + "latestBlockNum": 14005616, + "latestSlotNum": 524087980 + }, + { + "address": "41944d972a983881fd86c5b2cd49e18bdbaff116d0", + "voteCount": 174, + "url": "https://www.facebook.com/sevo.nikolov" + }, + { + "address": "4196ff32cfa51692dd6987ae161e3cf8b36143d827", + "voteCount": 35005157, + "url": "http://bz.com/" + }, + { + "address": "419837a9e5e14ce4921a2c6bd33cdba00e2f2688c5", + "voteCount": 518, + "url": "https://t.me/ONGISTRON_NewsChannel" + }, + { + "address": "4198787f5ebebb0a8fe26f148d81de0fdd88c28329", + "voteCount": 239, + "url": "http://www.contactnetwork.fr/" + }, + { + "address": "4198bf627cb3d9b3ac11cb9fbbb10aeed74615936d", + "voteCount": 562, + "url": "https://tronblock.co" + }, + { + "address": "4199fe7d33b4d7fc111fb1c5ef2c751676e1fb250b", + "voteCount": 76890, + "url": "https://TRONS.WORLD" + }, + { + "address": "419a856a04df38a4d9ce74d046af96872741ded747", + "voteCount": 1116, + "url": "https://trontx.com" + }, + { + "address": "419bae807d803192c5cc09a1f6c98c43a9141c32cf", + "voteCount": 83, + "url": "https://mobile.twitter.com/busyblaze" + }, + { + "address": "419deb263b16e25063fd47208fac89b01a32003ce7", + "voteCount": 500, + "url": "https://TRXGUARDIAN.ORG" + }, + { + "address": "419e46cd3c3b4a5543798962bd5f14d017cf6a124c", + "voteCount": 5131, + "url": "https://www.bitcoinworld.com/" + }, + { + "address": "41a300b290201cb337fe62794afbe9ed5cb183db55", + "voteCount": 103, + "url": "https://www.trxkings.com" + }, + { + "address": "41a4475dbd14feb2221f303fc33dc8d0a08f25f445", + "voteCount": 30583389, + "url": "https://tron-society.com", + "totalProduced": 168733, + "totalMissed": 2433, + "latestBlockNum": 8208429, + "latestSlotNum": 518255974 + }, + { + "address": "41a47e8b12d006a2c2a3f044453e2745bfb9321939", + "voteCount": 6859, + "url": "http://tronpro.io", + "totalProduced": 15194, + "totalMissed": 1, + "latestBlockNum": 1305260, + "latestSlotNum": 511271991 + }, + { + "address": "41a6c467ef40aa712fa239153309c0225300fbfa88", + "voteCount": 159, + "url": "https://www.vena.network" + }, + { + "address": "41a75a876ef0e8715aa2cd34597154382502b8d646", + "voteCount": 1523, + "url": " ", + "totalProduced": 102241, + "totalMissed": 426, + "latestBlockNum": 13998453, + "latestSlotNum": 524080797 + }, + { + "address": "41a857362c1b77cb04e8f2b51b6e970f24fa5c1e5b", + "voteCount": 6007, + "url": "http://TronGr24.com", + "totalProduced": 21248, + "latestBlockNum": 1614750, + "latestSlotNum": 511581580 + }, + { + "address": "41a89e743413e30d5462c95ac8ff0abcc13e7cf38f", + "voteCount": 2001, + "url": "https://mdt.co" + }, + { + "address": "41a8bb7680d85f9821b3d82505edc4663f6fbd8fde", + "voteCount": 1626, + "url": "http://TronGr25.com", + "totalProduced": 18571, + "totalMissed": 11, + "latestBlockNum": 1542791, + "latestSlotNum": 511509599 + }, + { + "address": "41a9b6a087c7f622548e338884f1a4c69972d691ab", + "voteCount": 6690, + "url": "https://www.troncanada.com/" + }, + { + "address": "41aa97642e4137cf828a971de448756958b844d72f", + "voteCount": 2830146, + "url": "https://github.com/trondex/", + "totalProduced": 25313, + "latestBlockNum": 1154111, + "latestSlotNum": 511120783 + }, + { + "address": "41ad85b8b51c9651f911da795e4d481db419c00c6b", + "voteCount": 497, + "url": "https://youtu.be/pWhw_NjVV68" + }, + { + "address": "41b096b3251f131f8a16f4b1beb7126d3ee071bc59", + "voteCount": 13457, + "url": "https://teamhelios.org/" + }, + { + "address": "41b25bd7ef93130ca2bf6eb05f1bdb9ee0f055c60a", + "voteCount": 80, + "url": "https://zhizhu.top/" + }, + { + "address": "41b3eec71481e8864f0fc1f601b836b74c40548287", + "voteCount": 293541325, + "url": "https://www.bittorrent.com/", + "totalProduced": 687487, + "totalMissed": 3836, + "latestBlockNum": 19479108, + "latestSlotNum": 529567199 + }, + { + "address": "41b438be21f9652e7f41b1d34a5a999f75ffeb2375", + "voteCount": 140, + "url": " " + }, + { + "address": "41b487cdc02de90f15ac89a68c82f44cbfe3d915ea", + "voteCount": 104879, + "url": "http://dapps.house", + "totalProduced": 250389, + "totalMissed": 2342, + "latestBlockNum": 8387532, + "latestSlotNum": 518435979 + }, + { + "address": "41b668d4991cd636b694989ebf3fa1a84613d7899e", + "voteCount": 5760439, + "url": "https://www.iggalaxy.com", + "totalProduced": 154409, + "totalMissed": 1550, + "latestBlockNum": 8416221, + "latestSlotNum": 518464799 + }, + { + "address": "41b6e726360eccfbeeb3bd52ae89aff8aeb2b23e14", + "voteCount": 1013, + "url": "https://tronswap.io" + }, + { + "address": "41b6eed928f86c2b80a85b83572a87311e7da7682c", + "voteCount": 206, + "url": "https://a4oo.ml" + }, + { + "address": "41b813e99b6a9fc38fb279d51a0d217fccece3280a", + "voteCount": 1567, + "url": "https://antpool.com" + }, + { + "address": "41ba7cc2711b5b3dcdedfd5ae493197d5bae597202", + "voteCount": 136738, + "url": "xreglobal.com" + }, + { + "address": "41bac7378c4265ad2739772337682183b8864f517a", + "voteCount": 295548591, + "url": "http://trx.market", + "totalProduced": 662356, + "totalMissed": 4092, + "latestBlockNum": 19700694, + "latestSlotNum": 529788867, + "isJobs": true + }, + { + "address": "41bd0e945de2c2397b24aafd0ab02422705f6dbc87", + "voteCount": 70946, + "url": "https://www.tronvietnam.org" + }, + { + "address": "41bd2fee2df4a2ba73f29d58b777c4c1113b74e5db", + "voteCount": 200, + "url": "https://www.teamx.com", + "totalProduced": 17850, + "totalMissed": 2, + "latestBlockNum": 3966296, + "latestSlotNum": 513950399 + }, + { + "address": "41bd58a790f43b052cd39418d2ffaefb316b846578", + "voteCount": 220791, + "url": "https://bankroll.network" + }, + { + "address": "41bfd6af35f4cbf8846b8ecd5d8d24a444d47e4aaf", + "voteCount": 984, + "url": "www.tbd.com" + }, + { + "address": "41c299c307d6dc655520f7e77438c57a002d0c3810", + "voteCount": 31, + "url": "Can" + }, + { + "address": "41c2de79fc11be35c35e5148bd2e45d0633f641ac8", + "voteCount": 2527121420, + "url": "https://www.neoply.com", + "totalProduced": 46832, + "totalMissed": 44, + "latestBlockNum": 19700697, + "latestSlotNum": 529788870, + "isJobs": true + }, + { + "address": "41c4bc4d7f64df4fd3670ce38e1a60080a50da85cf", + "voteCount": 72431, + "url": "http://raybo.com", + "totalProduced": 267142, + "totalMissed": 2326, + "latestBlockNum": 8523378, + "latestSlotNum": 518572799 + }, + { + "address": "41c56268480d3d9f8943eccd9a63caf19dd6fe4950", + "voteCount": 24871, + "url": "https://global.bittrex.com/" + }, + { + "address": "41c57a3e8c229b611fc81ba9adadd758ee47e58457", + "voteCount": 974, + "url": "http://tronbitcoin.io" + }, + { + "address": "41c6a0f6bdc5380d47d4d96a9ae5d283f9b520f8f3", + "voteCount": 32, + "url": "https://gsc.social" + }, + { + "address": "41c6ab8f6fa5717f49b5c19c5b527d34c885d507b3", + "voteCount": 3322, + "url": "https://dexexchange.us" + }, + { + "address": "41c8f401931724be02deed70cb7e8349a1a13af896", + "voteCount": 22531, + "url": "https://huxlium.org" + }, + { + "address": "41c912b348e87b518aacc270642e115b5cda59e409", + "voteCount": 10301, + "url": "http://StakeWithMe.io" + }, + { + "address": "41cc49d79ad451bcf4b35f785d84d169cda2913626", + "voteCount": 6021, + "url": "https://www.hashfin.com" + }, + { + "address": "41ced3494c81de8d5ff4da950c7137120a2bbf8e1e", + "voteCount": 6821, + "url": "https://trip4web.com" + }, + { + "address": "41d1dbde8b8f71b48655bec4f6bb532a0142b88bc0", + "voteCount": 5232636, + "url": "Tronstronics", + "totalProduced": 195873, + "totalMissed": 1952, + "latestBlockNum": 5971325, + "latestSlotNum": 516002399 + }, + { + "address": "41d25855804e4e65de904faf3ac74b0bdfc53fac76", + "voteCount": 691735170, + "url": "https://www.bitguild.com", + "totalProduced": 637652, + "totalMissed": 2606, + "latestBlockNum": 19700699, + "latestSlotNum": 529788872, + "isJobs": true + }, + { + "address": "41d32b3fa8ca0b4896257fdf1821ac8d116da84c45", + "voteCount": 3050, + "url": "http://TronGr2.com", + "totalProduced": 53764, + "totalMissed": 2, + "latestBlockNum": 1549967, + "latestSlotNum": 511516777 + }, + { + "address": "41d3b1e86db62d5a870d605ae39fb1ad7ee2ddca12", + "voteCount": 2017932, + "url": "HTTPS://AOCOIN.IO" + }, + { + "address": "41d492cf18007c62026f66742446d19368773fb8bc", + "voteCount": 206, + "url": "https://dootron.com/en/home" + }, + { + "address": "41d49bf5202b3dba65d46a5be73396b6b66d3555aa", + "voteCount": 2280286, + "url": "https://www.cryptogirls.ro/", + "totalProduced": 127145, + "totalMissed": 305, + "latestBlockNum": 4052661, + "latestSlotNum": 514036796 + }, + { + "address": "41d51fb9ae063610ddd8f04ecedb2a36f97fbb9a53", + "voteCount": 1015, + "url": "https://www.tronbet.io", + "totalProduced": 800, + "latestBlockNum": 17306496, + "latestSlotNum": 527392798 + }, + { + "address": "41d599cb8c1b609722e81741667ba3c8fb441fba41", + "voteCount": 120683597, + "url": "www.tronspirit.com", + "totalProduced": 214599, + "totalMissed": 4863, + "latestBlockNum": 17284888, + "latestSlotNum": 527371181 + }, + { + "address": "41d70365508e5a6fe846ad433af9302779fd5fdb1b", + "voteCount": 214157644, + "url": "http://krypto-knight.us/", + "totalProduced": 484381, + "totalMissed": 1288, + "latestBlockNum": 18550761, + "latestSlotNum": 528638395 + }, + { + "address": "41da5cf6279279a93572362b9edc7cdd86644b6214", + "voteCount": 1377, + "url": "https://coinhe.io" + }, + { + "address": "41dca1955f9edbfb7b25a3fe2998793a4b22746eb9", + "voteCount": 110011856, + "url": "https://www.tronace.com", + "totalProduced": 800, + "latestBlockNum": 17306495, + "latestSlotNum": 527392797 + }, + { + "address": "41de4c45a96857dc02fe1b9ba8d534dabc46245164", + "voteCount": 1558561, + "url": "https://www.millioncoinx.com/pl" + }, + { + "address": "41de9c3c2276abe2da70a7cdb34a205ecf7750d063", + "voteCount": 4010755, + "url": "https://www.tron-family.de" + }, + { + "address": "41df3bd4e0463534cb7f1f3ffc2ec14ac4693dc3b2", + "voteCount": 702, + "url": "http://TronGr3.com", + "totalProduced": 25247, + "latestBlockNum": 681353, + "latestSlotNum": 510645598 + }, + { + "address": "41e0a6cd1f1465a48195d93980b33e2658706203f6", + "voteCount": 346, + "url": " " + }, + { + "address": "41e27744d39af1e582cba7d80d65f413b5a3e80a70", + "voteCount": 1697784, + "url": "https://www.whaleex.com" + }, + { + "address": "41e2d3e56c42a2d304167b8abf5394ac2552f7f007", + "voteCount": 5002, + "url": "http://www.nodecap.com/" + }, + { + "address": "41e3b821e76830fef394a570c57c3c8aa2c1079348", + "voteCount": 4324, + "url": "https://tronvote.club" + }, + { + "address": "41e40de6895c142ade8b86194063bcdbaa6c9360b6", + "voteCount": 2452, + "url": "http://TronGr9.com", + "totalProduced": 47904, + "latestBlockNum": 1362829, + "latestSlotNum": 511329585 + }, + { + "address": "41e425fe49e76e7573b7aa746ac92fbf795b6b660e", + "voteCount": 5561, + "url": "http://bt.co" + }, + { + "address": "41e60b9bdd083676b2d58d179764edbe773e7f7fe6", + "voteCount": 5495, + "url": "https://www.troninvestgroup.org" + }, + { + "address": "41e72d833e0c46837c0802864acc5f119a0a904d05", + "voteCount": 8758, + "url": "http://TronGr18.com", + "totalProduced": 34565, + "latestBlockNum": 1492396, + "latestSlotNum": 511459189 + }, + { + "address": "41e7a7be105be761a13d3c821c1b02d0283e64669b", + "voteCount": 218503, + "url": "https://www.musiccasper.com/" + }, + { + "address": "41e85b204342401ab30a4e84f9b2356e05fb2c017f", + "voteCount": 659, + "url": "http://www.troncenter.com" + }, + { + "address": "41eb8d54ea7886df726114ac5089f253c13902c039", + "voteCount": 500, + "url": "https://t.me/TronParty" + }, + { + "address": "41ebf50b9054cd1c9f05cba54a9c335140cab81ca5", + "voteCount": 27507, + "url": "https://pyro.network" + }, + { + "address": "41ee98edeedd68ddce222f5f6ccfd07cea8735282f", + "voteCount": 247, + "url": "www" + }, + { + "address": "41ef5c9152d74a044cc0cd9156b1335345eea8aa25", + "voteCount": 136567, + "url": "https://TRON-Want" + }, + { + "address": "41f439093df1758a8b6b4b1279a702ef9939fef3ee", + "voteCount": 652, + "url": "http://www.dagbvi.com" + }, + { + "address": "41f5c3ccb9d2d776e20e892188d983dbcc590d3408", + "voteCount": 5012, + "url": "http://newgenesiscap.com/" + }, + { + "address": "41f6862099bff15eade076c3a8f1b5abd7712b46d4", + "voteCount": 1392, + "url": "http://www.tronfans.info", + "totalProduced": 5328, + "latestBlockNum": 2480734, + "latestSlotNum": 512452775 + }, + { + "address": "41f6af07517ab62b3af95017b440efb3e8454376b4", + "voteCount": 132843, + "url": "https://www.tronlabs.ro" + }, + { + "address": "41f70386347e689e6308e4172ed7319c49c0f66e0b", + "voteCount": 39457396, + "url": "http://tronone.com", + "totalProduced": 518353, + "totalMissed": 5124, + "latestBlockNum": 15149942, + "latestSlotNum": 525232781 + }, + { + "address": "41f8c7acc4c08cf36ca08fc2a61b1f5a7c8dea7bec", + "voteCount": 10, + "url": "http://TronGr19.com", + "totalProduced": 26567, + "latestBlockNum": 1621715, + "latestSlotNum": 511588789 + }, + { + "address": "41f90484ea93e94f2b92479d3d8b8dbadda6ddef3e", + "voteCount": 177799, + "url": "https://reyna.exchange/" + }, + { + "address": "41faec1ff18daaec28f080c54ba9bf8168c2cfadf8", + "voteCount": 46887, + "url": "https://www.gm-informatics.com" + }, + { + "address": "41fc45da0e51966bd1af2cb1e0f66633f160603a8b", + "voteCount": 3198, + "url": "http://www.etherpoker.cc", + "totalProduced": 69878, + "totalMissed": 249, + "latestBlockNum": 3548904, + "latestSlotNum": 513532790 + }, + { + "address": "41fcbc93454e116c2213f794d931c03b0943df2633", + "voteCount": 2103780, + "url": "https://metronix.imba-exchange.co" + }, + { + "address": "41fcf485751e99f5da9501b31733a2ae0c5c657ce2", + "voteCount": 667, + "url": "http://bit.ly/libertytron" + }, + { + "address": "41fe069c89ef4d59e7566ca7d794797a45feeb7a89", + "voteCount": 46979, + "url": "https://t.me/tron_my" + }, + { + "address": "41fe8d87ba51f89b6e29948dc86b69600d253632ec", + "voteCount": 205, + "url": "https://cryptotalkers.com" + }, + { + "address": "41ffd564656556a8b6b79311a932e3d216f4fc030b", + "voteCount": 125, + "url": "http://TronGr15.com", + "totalProduced": 25516, + "latestBlockNum": 1549971, + "latestSlotNum": 511516781 + } + ] +} diff --git a/mock/ext-api-data/unstoppabledomains_api_v1__dpantani.crypto.json b/mock/ext-api-data/unstoppabledomains_api_v1__dpantani.crypto.json new file mode 100644 index 000000000..3b6d9cb0f --- /dev/null +++ b/mock/ext-api-data/unstoppabledomains_api_v1__dpantani.crypto.json @@ -0,0 +1,23 @@ +{ + "addresses": { + "BCH": "qzpjlfnzudeu83krv0yk0r2kys67qptj6ys6eg6dms", + "BNB": "bnb1h4vyuuytu4rm86ust29wwlevt95du52383cctm", + "BTC": "bc1qd7eystu9xl53hkyxm4kyg7h5yk4p436sqx6f27", + "ETH": "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + "LTC": "ltc1qz6nd472gx5gl3urfeldkrhg3h83c8tp2m7m6sd", + "XRP": "rUvXBttEXhdwaKjEM2MxbtswHU6AMhUTgJ", + "ZIL": "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64", + "DOGE": "DP9VmQyDMyB1TWwgXkyRpBa7rTfPYgMvjy" + }, + "whois": {}, + "ipfs": { + "html": "QmUG2riiUkALEGB3AzgsJtN5KbgFcVb3p8qvc96gcsfzHo", + "redirect_domain": "https://abbfe6z95qov3d40hf6j30g7auo7afhp.mypinata.cloud/ipfs/QmUG2riiUkALEGB3AzgsJtN5KbgFcVb3p8qvc96gcsfzHo" + }, + "gundb": {}, + "meta": { + "owner": "0x5574cd97432ced0d7caf58ac3c4fedb2061c98fb", + "type": "CNS", + "ttl": 0 + } +} \ No newline at end of file diff --git a/mock/ext-api-data/unstoppabledomains_api_v1__dpantani.zil.json b/mock/ext-api-data/unstoppabledomains_api_v1__dpantani.zil.json new file mode 100644 index 000000000..d26241439 --- /dev/null +++ b/mock/ext-api-data/unstoppabledomains_api_v1__dpantani.zil.json @@ -0,0 +1,23 @@ +{ + "addresses": { + "BCH": "qzpjlfnzudeu83krv0yk0r2kys67qptj6ys6eg6dms", + "BNB": "bnb1h4vyuuytu4rm86ust29wwlevt95du52383cctm", + "BTC": "bc1qd7eystu9xl53hkyxm4kyg7h5yk4p436sqx6f27", + "ETH": "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", + "LTC": "ltc1qz6nd472gx5gl3urfeldkrhg3h83c8tp2m7m6sd", + "XRP": "rUvXBttEXhdwaKjEM2MxbtswHU6AMhUTgJ", + "ZIL": "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64", + "DOGE": "DP9VmQyDMyB1TWwgXkyRpBa7rTfPYgMvjy" + }, + "whois": {}, + "ipfs": { + "html": "QmUG2riiUkALEGB3AzgsJtN5KbgFcVb3p8qvc96gcsfzHo", + "redirect_domain": "https://abbfe6z95qov3d40hf6j30g7auo7afhp.mypinata.cloud/ipfs/QmUG2riiUkALEGB3AzgsJtN5KbgFcVb3p8qvc96gcsfzHo" + }, + "gundb": {}, + "meta": { + "owner": "0xe4da405976f315ab91ff9a43a51972cc94739aa8", + "type": "ZNS", + "ttl": 0 + } +} \ No newline at end of file diff --git a/mock/ext-api-data/vechain-api_blocks_best.json b/mock/ext-api-data/vechain-api_blocks_best.json new file mode 100644 index 000000000..916fe6589 --- /dev/null +++ b/mock/ext-api-data/vechain-api_blocks_best.json @@ -0,0 +1,20 @@ +{ + "number": 5887932, + "id": "0x0059d7bc873407f863b77f731f8e3c9335dc16aae1c53c0f18e780773d42a7f0", + "size": 542, + "parentID": "0x0059d7bb2f7ba5a8482d0b9937788f212f9b6b1de08818466985f943dbc8b4c6", + "timestamp": 1589366680, + "gasLimit": 38953771, + "beneficiary": "0xeb0c565f69557481c6c7fa347cae273128a0996e", + "gasUsed": 66003, + "totalScore": 566756408, + "txsRoot": "0xc4b8844cdc5dcd6b48627205ef30d7e09041d0e7ba013057690778e33e881127", + "txsFeatures": 1, + "stateRoot": "0xf572f33e7d55a193c7ef31f6cda0a0d51b339085e2296b6e05a81b593aa66e6e", + "receiptsRoot": "0x65bf45677f275349a9a9eeebdfdcb1ffd8760c98cd273fb909453b444265d081", + "signer": "0x8eaefdf7d25c001e7e59363c33d7f5ad47970086", + "isTrunk": true, + "transactions": [ + "0x36720eaff4ac46835d3300bab1c2a6e9f45907c3151ff36c247dd7c287ba8125" + ] +} \ No newline at end of file diff --git a/mock/ext-api-data/vechain-api_logs_transfer.json b/mock/ext-api-data/vechain-api_logs_transfer.json new file mode 100644 index 000000000..cdd48e25e --- /dev/null +++ b/mock/ext-api-data/vechain-api_logs_transfer.json @@ -0,0 +1,197 @@ +[ + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", + "amount": "0x12b1815d00738000", + "meta": { + "blockID": "0x004313a4bd4286e821b684cc1749deb3df12fa2a8114435fbd35baa155e82016", + "blockNumber": 4395940, + "blockTimestamp": 1574410670, + "txID": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0x00bae5ed35736e4ef17af1be0c6f50e0fb73d685", + "amount": "0x38f6ea18e810b6f00", + "meta": { + "blockID": "0x0042249bee56223e0ed7a9c7fcfffe8e61b9fd95d29d24843c558ff2c46ea094", + "blockNumber": 4334747, + "blockTimestamp": 1573795570, + "txID": "0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0x4563918244f40000", + "meta": { + "blockID": "0x003f8fcf4019eee33a337104e1ccc58cfdcc436fdff009d5fdc3c4a303ff0de2", + "blockNumber": 4165583, + "blockTimestamp": 1572095480, + "txID": "0x12914b9ea2f0b141b02666bd4b526e62b6a95c061c01bf8ed955e38ec3024d05", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003f7652b21c1c9bf22507a37277d6cfa1db4e319dd3a689c94a0d67ef2fbffa", + "blockNumber": 4159058, + "blockTimestamp": 1572030170, + "txID": "0x7d700869cbefe144639518db2b9ac5a695f62c62cea402d31dc6648d3ca27f00", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003f67aa05143d785f7ef7fdd7dd4def76e228c240cd3dcd980e6865f7e9add4", + "blockNumber": 4155306, + "blockTimestamp": 1571992620, + "txID": "0x9f14450a964396f24cacf144c6c674c81a034448e9de3c2a05c1e95480e58fc3", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003f2fe2ff00f12a5282d1dda4a5f1c968fd1c47c43c88fe3db50cfa789b98fb", + "blockNumber": 4141026, + "blockTimestamp": 1571848760, + "txID": "0x19c264236b5863300d93175997acd7d6a06856b3bc2fea083c1e14cf809f726f", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0x1322116c8720b18000", + "meta": { + "blockID": "0x003f04e8527d796d578a6b5688a6762c564f31fdaa6adc0f0492b783a269c2d1", + "blockNumber": 4130024, + "blockTimestamp": 1571738290, + "txID": "0x3d3ee661e3ac9e27540a9e292882ad56b52c1a4e5a7bc1d604e66f73e6d425b9", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0x8c7d176caa85c716a895026f32df2fd34a5f9146", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003f04e55bba0d119d3d3eb6de02d0e30f79a4a00390c574023f45ecf4adf08e", + "blockNumber": 4130021, + "blockTimestamp": 1571738260, + "txID": "0x561108d7be73258eb4f052dc4cb00326b007da003a199a7017d0e5b0b94f1e24", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003f04b84f961b775b344385459ce6be8af88d20a7e89ae05002d3a0372194d3", + "blockNumber": 4129976, + "blockTimestamp": 1571737810, + "txID": "0x1c647668741691fd82724cf50798ced8e0c980f88b0c1546e3435ad512c8e7e1", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003f047f4430df38a6a07166ea0a389867f6f49c10f745826cbfdbb37820fd6f", + "blockNumber": 4129919, + "blockTimestamp": 1571737220, + "txID": "0xc61f713a23462c9eb44b1695d855e21d21815340b4861ffaefa0b78a2cc463bf", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003f044fc421c9d57bdddf31f9122c1306a5417690cef59c0b589c522ae5d2b7", + "blockNumber": 4129871, + "blockTimestamp": 1571736740, + "txID": "0xbf666ca63607088267c3b769545585066bfc9239700e635ff9b60345ebc324cd", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003ef3d9151b500600c0a545cdcf31a322a3534123439fc42883b6d5145fd12e", + "blockNumber": 4125657, + "blockTimestamp": 1571694230, + "txID": "0xbc054c6e31fde87be89c863059f591247ad7fc72585d23c2e738a42d3c7ac1c6", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003ef3c8db0338c63459e85117da9e4085dd6eb9a2d3e075c07803611baeecfd", + "blockNumber": 4125640, + "blockTimestamp": 1571694060, + "txID": "0x645d86bac876a982dd273332b7ae4d6e64d1a96998ec9b663e5e3d0b40f6bb45", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003ef3953aecad21806c07bed0b225a070cffe5e6aa63cee293c21ecf471d7aa", + "blockNumber": 4125589, + "blockTimestamp": 1571693550, + "txID": "0xeb65e55d6fd6c6b40b663b8f06df8865a7ee3cfff6fa4a0a8a63eb35f565b5c8", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + }, + { + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0xb5e883349e68ab59307d1604555ac890fac47128", + "amount": "0xde0b6b3a7640000", + "meta": { + "blockID": "0x003ef3473d0ff2ab212fe729a57e27dbd28dfcb59dc24421d7815bba971a32fc", + "blockNumber": 4125511, + "blockTimestamp": 1571692770, + "txID": "0x80c404f93e5a915398d43ae90ed7c000f2b8ac37dcd2234d3ead3bfdaa726d92", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } + } +] \ No newline at end of file diff --git a/mock/ext-api-data/vechain-api_logs_transfer.request_json b/mock/ext-api-data/vechain-api_logs_transfer.request_json new file mode 100644 index 000000000..4d5973b67 --- /dev/null +++ b/mock/ext-api-data/vechain-api_logs_transfer.request_json @@ -0,0 +1,20 @@ +{ + "options": { + "offset": 0, + "limit": 15 + }, + "criteriaSet": [ + { + "sender": "0xB5e883349e68aB59307d1604555AC890fAC47128" + }, + { + "recipient": "0xB5e883349e68aB59307d1604555AC890fAC47128" + } + ], + "range": { + "unit": "block", + "from": 0, + "to": 5466405 + }, + "order": "desc" +} \ No newline at end of file diff --git a/mock/ext-api-data/vechain-api_transactions_0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5.json b/mock/ext-api-data/vechain-api_transactions_0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5.json new file mode 100644 index 000000000..e58892998 --- /dev/null +++ b/mock/ext-api-data/vechain-api_transactions_0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5.json @@ -0,0 +1,25 @@ +{ + "id": "0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5", + "chainTag": 74, + "blockRef": "0x0042249a647f63e7", + "expiration": 720, + "clauses": [ + { + "to": "0x00bae5ed35736e4ef17af1be0c6f50e0fb73d685", + "value": "0x38f6ea18e810b6f00", + "data": "0x" + } + ], + "gasPriceCoef": 0, + "gas": 21000, + "origin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "delegator": null, + "nonce": "0x6fa76caac4c18bd", + "dependsOn": null, + "size": 130, + "meta": { + "blockID": "0x0042249bee56223e0ed7a9c7fcfffe8e61b9fd95d29d24843c558ff2c46ea094", + "blockNumber": 4334747, + "blockTimestamp": 1573795570 + } +} \ No newline at end of file diff --git a/mock/ext-api-data/vechain-api_transactions_0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7.json b/mock/ext-api-data/vechain-api_transactions_0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7.json new file mode 100644 index 000000000..4e2823cf5 --- /dev/null +++ b/mock/ext-api-data/vechain-api_transactions_0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7.json @@ -0,0 +1,25 @@ +{ + "id": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", + "chainTag": 74, + "blockRef": "0x004313a393a18efb", + "expiration": 720, + "clauses": [ + { + "to": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", + "value": "0x12b1815d00738000", + "data": "0x" + } + ], + "gasPriceCoef": 0, + "gas": 21000, + "origin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "delegator": null, + "nonce": "0x8cff29df64a414f8", + "dependsOn": null, + "size": 129, + "meta": { + "blockID": "0x004313a4bd4286e821b684cc1749deb3df12fa2a8114435fbd35baa155e82016", + "blockNumber": 4395940, + "blockTimestamp": 1574410670 + } +} \ No newline at end of file diff --git a/mock/ext-api-data/viacoin-api_v2_address_VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A__details_txs.json b/mock/ext-api-data/viacoin-api_v2_address_VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A__details_txs.json new file mode 100644 index 000000000..08139f499 --- /dev/null +++ b/mock/ext-api-data/viacoin-api_v2_address_VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":160338,"itemsOnPage":10,"address":"VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A","balance":"151181530522","totalReceived":"18401865678328","totalSent":"18250684147806","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":1603379,"transactions":[{"txid":"fb71dae00a0ef3044c8085077e0def3147e0fc24e3a7d5e9fe67867e54a1a1d5","version":1,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03afa774045ec68b8f"}],"vout":[{"value":"976562","n":0,"hex":"76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac","addresses":["VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"]}],"blockHash":"2a9e6773dd0ace56fb7807423e4bf1615a96e246fba6f07ca3de06ca5fbb0c68","blockHeight":7645103,"confirmations":1,"blockTime":1590070159,"value":"976562","valueIn":"0","fees":"0","hex":"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0903afa774045ec68b8fffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000"},{"txid":"95bdfa9064b2e3089897c22fd21cf8eeb05e07d1a21c70b88e3ccce02c6b35e9","version":1,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03ada774045ec68b72"}],"vout":[{"value":"976562","n":0,"hex":"76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac","addresses":["VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"]}],"blockHash":"18c911c768a87370dcd1f4dd618893047fbe48a05f969cdc1b239754a4cc0ca3","blockHeight":7645101,"confirmations":3,"blockTime":1590070130,"value":"976562","valueIn":"0","fees":"0","hex":"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0903ada774045ec68b72ffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000"},{"txid":"9941602545e489e1370df8025a9ed100571f5056d5b36b5e0b90ede817bdb3c6","version":1,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03a6a774045ec68a7e"}],"vout":[{"value":"976562","n":0,"hex":"76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac","addresses":["VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"]},{"value":"0","n":1,"hex":"6a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9","addresses":["OP_RETURN aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9"]}],"blockHash":"c7b4ae0bcda9c6d70b1879eb761458a34a5411f6464f92e0fd6e09e45907db55","blockHeight":7645094,"confirmations":10,"blockTime":1590069886,"value":"976562","valueIn":"0","fees":"0","hex":"010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0903a6a774045ec68a7effffffff02b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"},{"txid":"d0f20c3cdb80d0467318a4168f24f57ba9eb5b5c398a889bd836a779d253a370","version":1,"vin":[{"sequence":4294967295,"n":0,"coinbase":"039fa774045ec68938"}],"vout":[{"value":"976562","n":0,"hex":"76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac","addresses":["VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"]}],"blockHash":"bb55efe10eb7e6a54f96a4cba73be191f58add358de83a68760ecdfe0e727ce5","blockHeight":7645087,"confirmations":17,"blockTime":1590069560,"value":"976562","valueIn":"0","fees":"0","hex":"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff09039fa774045ec68938ffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000"},{"txid":"7ff3b66c68baf22efa6767abede6e07cc42dbe7854ad9550230239b6bd5f9baa","version":1,"vin":[{"sequence":4294967295,"n":0,"coinbase":"039ea774045ec68915"}],"vout":[{"value":"976562","n":0,"hex":"76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac","addresses":["VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"]}],"blockHash":"723a275a090400a275bba97d26ee5053b79e0cab4b9d4cae3d07d84a9148cb16","blockHeight":7645086,"confirmations":18,"blockTime":1590069525,"value":"976562","valueIn":"0","fees":"0","hex":"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff09039ea774045ec68915ffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000"},{"txid":"d77862a099db4d33207ff7b98a534f618a00d73855186e9b7039edc490c0d4c4","version":1,"vin":[{"sequence":4294967295,"n":0,"coinbase":"039da774045ec68900"}],"vout":[{"value":"976562","n":0,"hex":"76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac","addresses":["VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"]},{"value":"0","n":1,"hex":"6a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9","addresses":["OP_RETURN aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9"]}],"blockHash":"1cf47ce738f299f7f99dfb09f1a6a97095340f38957a4726777ebb213c4d2521","blockHeight":7645085,"confirmations":19,"blockTime":1590069504,"value":"976562","valueIn":"0","fees":"0","hex":"010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff09039da774045ec68900ffffffff02b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"},{"txid":"f7dbeeea3ab0c44642c7647e0a6da4723d27cc6b01f18df03efee8377461cd52","version":1,"vin":[{"sequence":4294967295,"n":0,"coinbase":"0398a774045ec6888f"}],"vout":[{"value":"976562","n":0,"hex":"76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac","addresses":["VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"]}],"blockHash":"6c1df3751861f94df019ad0f5c2cfe78de848a1140c99c99d9b51755873395e0","blockHeight":7645080,"confirmations":24,"blockTime":1590069391,"value":"976562","valueIn":"0","fees":"0","hex":"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff090398a774045ec6888fffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000"},{"txid":"d00072dd6416f65a55b7178aa951b486fad6f71423d4fa0b8872cd3795282b63","version":1,"vin":[{"sequence":4294967295,"n":0,"coinbase":"0394a774045ec68821"}],"vout":[{"value":"976562","n":0,"hex":"76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac","addresses":["VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"]},{"value":"0","n":1,"hex":"6a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9","addresses":["OP_RETURN aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9"]}],"blockHash":"8324bb579b7e429723a10711ddc5338354ce1640632c1097bebac952bf0e39b0","blockHeight":7645076,"confirmations":28,"blockTime":1590069281,"value":"976562","valueIn":"0","fees":"0","hex":"010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff090394a774045ec68821ffffffff02b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"},{"txid":"bd408661283a213ec48b5e46314b687161914795b841bb2d1c3ccc0fc0e91360","version":1,"vin":[{"sequence":4294967295,"n":0,"coinbase":"0391a774045ec68802"}],"vout":[{"value":"976562","n":0,"hex":"76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac","addresses":["VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"]}],"blockHash":"9146e301cda547092e2d563db4e0437caa327fffcbbe4b16fe23b7704fe85b7f","blockHeight":7645073,"confirmations":31,"blockTime":1590069250,"value":"976562","valueIn":"0","fees":"0","hex":"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff090391a774045ec68802ffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000"},{"txid":"8aefbd2b6c32a6d70cb905d1c6303e5940fe26b242d40da8c34173252b41648c","version":1,"vin":[{"sequence":4294967295,"n":0,"coinbase":"038ea774045ec687cf"}],"vout":[{"value":"976562","n":0,"hex":"76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac","addresses":["VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"]}],"blockHash":"4627ee53a7487b762627dc42efe57c9f2e700d445c53740958bae483014070bb","blockHeight":7645070,"confirmations":34,"blockTime":1590069199,"value":"976562","valueIn":"0","fees":"0","hex":"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff09038ea774045ec687cfffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000"}]} diff --git a/mock/ext-api-data/viacoin-api_v2_xpub_zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK__details_txs.json b/mock/ext-api-data/viacoin-api_v2_xpub_zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK__details_txs.json new file mode 100644 index 000000000..ea82e7a48 --- /dev/null +++ b/mock/ext-api-data/viacoin-api_v2_xpub_zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK__details_txs.json @@ -0,0 +1,1814 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK", + "balance": "740523040", + "totalReceived": "57315523588", + "totalSent": "56575000548", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 40, + "transactions": [ + { + "txid": "dc45eec5b0660eac0a5e291839aef5f5c5d7ff5ac71d056afbb17780c9da53e8", + "version": 1, + "vin": [ + { + "txid": "bdff404da14940abd84f7cb741fe8f77ad5de5aefbb74254caee683fe2a9b540", + "sequence": 4294967293, + "n": 0, + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ], + "value": "100000000" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "00147689515a58655155c0b8cc73f94ae82b32045cb5", + "addresses": [ + "via1qw6y4zkjcv4g4ts9ce3eljjhg9veqgh94akn7j4" + ] + }, + { + "value": "98774000", + "n": 1, + "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ] + } + ], + "blockHash": "3ce7592c15b2987085e69e085888249e01819f306a84ced9180a0f7c53a65156", + "blockHeight": 7590296, + "confirmations": 25553, + "blockTime": 1588752167, + "value": "99774000", + "valueIn": "100000000", + "fees": "226000", + "hex": "0100000000010140b5a9e23f68eeca5442b7fbaee55dad778ffe41b77c4fd8ab4049a14d40ffbd0000000000fdffffff0240420f00000000001600147689515a58655155c0b8cc73f94ae82b32045cb5f02be305000000001600143379fd40508ec2101e11c3519a31615de6e7b67302483045022100e90168f0b832bb59cac87582e82c31a4cef5ead0f8075f1e65e880538c4f156002201628b227519f50c4346d6e9623a19ea9bafe86f4839f7ecc8784dbd7547afd82012102b5e09e1dbb76a0eeebea67bf80069ce41c26c81d0f06d1dd42e712ebf55de4bc00000000" + }, + { + "txid": "bdff404da14940abd84f7cb741fe8f77ad5de5aefbb74254caee683fe2a9b540", + "version": 1, + "vin": [ + { + "txid": "32790f42de714507b6a1e6001a4a334600ac316937a98489c19821bba0d5c74f", + "vout": 1, + "n": 0, + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ], + "value": "741862718" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ] + }, + { + "value": "641749040", + "n": 1, + "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ] + } + ], + "blockHash": "0853179f0baef807426b977e4a9ae260ba1a3a3726dbb7513ff4150991f5827a", + "blockHeight": 7305935, + "confirmations": 309914, + "blockTime": 1581914336, + "value": "741749040", + "valueIn": "741862718", + "fees": "113678", + "hex": "010000000001014fc7d5a0bb2198c18984a9376931ac0046334a1a00e6a1b6074571de420f79320100000000000000000200e1f505000000001600143379fd40508ec2101e11c3519a31615de6e7b67330504026000000001600143379fd40508ec2101e11c3519a31615de6e7b67302473044022049b1d030bd9ec88ec343a52971d354b470d1357413675e985161bf2d5f8ca8ba02205d393b4d5232ae983faba4237e0c8feace5483493bf4da35313ce62459c87c66012102b5e09e1dbb76a0eeebea67bf80069ce41c26c81d0f06d1dd42e712ebf55de4bc00000000" + }, + { + "txid": "32790f42de714507b6a1e6001a4a334600ac316937a98489c19821bba0d5c74f", + "version": 1, + "vin": [ + { + "txid": "442f51ea9ee10919f0af8f8d586926f700a5f0b04712e97e6565a19a6c5b739a", + "n": 0, + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ], + "value": "7741976396" + } + ], + "vout": [ + { + "value": "7000000000", + "n": 0, + "spent": true, + "hex": "76a9148c9ce0d33ef042c65356ed5b5d278d846e21c16a88ac", + "addresses": [ + "VnpKSf3qe4sJXNbj7PmMyiHZqpdzWVX84X" + ] + }, + { + "value": "741862718", + "n": 1, + "spent": true, + "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ] + } + ], + "blockHash": "325170b9481c815eee11755417ef4501551bf8a17c8ab318ade52709ed0de27d", + "blockHeight": 7273671, + "confirmations": 342178, + "blockTime": 1581138785, + "value": "7741862718", + "valueIn": "7741976396", + "fees": "113678", + "hex": "010000000001019a735b6c9aa165657ee91247b0f0a500f72669588d8faff01909e19eea512f440000000000000000000200863ba1010000001976a9148c9ce0d33ef042c65356ed5b5d278d846e21c16a88ac3eed372c000000001600143379fd40508ec2101e11c3519a31615de6e7b67302483045022100ba65ef64f992996ed7b1aa12c90ad9b71cfe12be556b454ceacaa7efec3ae42802203abe6719dae22105a9827f3a4d0836c67649d20539ce8cb1945e7a1801a58907012102b5e09e1dbb76a0eeebea67bf80069ce41c26c81d0f06d1dd42e712ebf55de4bc00000000" + }, + { + "txid": "442f51ea9ee10919f0af8f8d586926f700a5f0b04712e97e6565a19a6c5b739a", + "version": 1, + "vin": [ + { + "txid": "1f73b6896a2266a4410bd8ca059feaed6c41d2b0b330d5d35609c702c35f18cf", + "n": 0, + "addresses": [ + "via1qjzfzfshvkkfvke52mvr7rmlexdynkcvsqzvu8l" + ], + "value": "100000" + }, + { + "txid": "6d5151cb8df2eb819c9ea008a07e2e889edae7c70f187a578bbfbc226394d1ac", + "n": 1, + "addresses": [ + "via1qnjwjefwqm49uavy0w2n50gfwq722hn4ua6ka7h" + ], + "value": "10000000" + }, + { + "txid": "f70fa075aff2fd73c125975978d600b0b2f1bca878bc41209b1c6ae0aba3a459", + "n": 2, + "addresses": [ + "via1q8gyufeuhxkt428cgjn8wp6leydwwky0x30wvue" + ], + "value": "499890124" + }, + { + "txid": "6d5151cb8df2eb819c9ea008a07e2e889edae7c70f187a578bbfbc226394d1ac", + "vout": 1, + "n": 3, + "addresses": [ + "via1qc0c6g7pzce4dtseatgt9ltxvyap64efquhlu27" + ], + "value": "7232306180" + } + ], + "vout": [ + { + "value": "7741976396", + "n": 0, + "spent": true, + "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ] + } + ], + "blockHash": "4e98a8fad4bb02dcb799725d7ede5f545596688466d85a1091b2ba563d85a062", + "blockHeight": 7255611, + "confirmations": 360238, + "blockTime": 1580704540, + "value": "7741976396", + "valueIn": "7742296304", + "fees": "319908", + "hex": "01000000000104cf185fc302c70956d3d530b3b0d2416cedea9f05cad80b41a466226a89b6731f000000000000000000acd1946322bcbf8b577a180fc7e7da9e882e7ea008a09e9c81ebf28dcb51516d00000000000000000059a4a3abe06a1c9b2041bc78a8bcf1b2b000d678599725c173fdf2af75a00ff7000000000000000000acd1946322bcbf8b577a180fc7e7da9e882e7ea008a09e9c81ebf28dcb51516d010000000000000000014c2f75cd010000001600143379fd40508ec2101e11c3519a31615de6e7b6730247304402200f7e4b4573de54f1967e2f94daefb869ab99ee5fc9d00807d41d749cb8f4e74402205aa4ea6f7d0cf9742e7bbd46f47a2923cc586afd8699d143ccd02c36ee25f53b012102a56256f78e4dd22ec54125f908892a6d42b47e8638707245235a4ed03611b34102483045022100bef33dc381dd372513c8385a1c2e51f298fe992c71aa1ab4301c001c216f306402200dbc2a4736655cde7e4d6a3fffc507d2c67f2022438dc80065ca624ae6f50939012102252dd7efb799c8766b2ae1568a302b361bc3dfba811d29cea714be9c06916033024830450221008b80cad80219f536288d4a691bcc1f6b4520038da1e92161d201b2b9c8a106c30220255f17b669c3cc2ea1fb930e64ad5222751b2ef9c8a6eee478d62247273f5807012103f321418135881669dc1de73dec8f0c59af758be9b75b5b627efa9cb955a35e6102483045022100ff9ae1423ed28f7728c184d8df4ab158b66e756de1ecfa0bcb8e3d5b0164d71f0220343028022a63c3a327bf1ed242f2dc839a138784d1a7399ed26e5fdffa831fbb01210258cd0af468ed450ebbbaae8aed0e7ec7122856491a2fb84ea56a1f91f28e04cb00000000" + }, + { + "txid": "f70fa075aff2fd73c125975978d600b0b2f1bca878bc41209b1c6ae0aba3a459", + "version": 1, + "vin": [ + { + "txid": "e05387d8a470d7a144c19588c7f0613f5b8b3013ac34c34c561f124a71d81e4a", + "n": 0, + "addresses": [ + "via1qe2g00nkzhflfuq8ee65fyr92gq9240umdy902z" + ], + "value": "499986700" + } + ], + "vout": [ + { + "value": "499890124", + "n": 0, + "spent": true, + "hex": "00143a09c4e7973597551f0894cee0ebf9235ceb11e6", + "addresses": [ + "via1q8gyufeuhxkt428cgjn8wp6leydwwky0x30wvue" + ] + } + ], + "blockHash": "6670e848b2ad5123b9e01fa5e20722e2b127cc37f5f05c5d0a7f7262571f8038", + "blockHeight": 7130119, + "confirmations": 485730, + "blockTime": 1577687140, + "value": "499890124", + "valueIn": "499986700", + "fees": "96576", + "hex": "010000000001014a1ed8714a121f564cc334ac13308b5b3f61f0c78895c144a1d770a4d88753e000000000000000000001ccb7cb1d000000001600143a09c4e7973597551f0894cee0ebf9235ceb11e602483045022100d2ae492c00749ada65c3f214c4d639efc65439cc0516cf8d1b3904cb06ad201502203b97312193284a8429c6c2242c3ce023083f7f9446d473563d4b5047175244fd0121032e83d8ee4adcaf863a262c54aadc46cc3ace851e147ceac0b61dbd1f6910e3e400000000" + }, + { + "txid": "6d5151cb8df2eb819c9ea008a07e2e889edae7c70f187a578bbfbc226394d1ac", + "version": 1, + "vin": [ + { + "txid": "d483ff03f4ed67e3e34a8ac886fb975e25359c3d355ce729f3b935c44a4a74c8", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1q8yau03cmeg8meaw3jt5ducsjmm8mq7tyaynkqh" + ], + "value": "7242532180" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "00149c9d2ca5c0dd4bceb08f72a747a12e0794abcebc", + "addresses": [ + "via1qnjwjefwqm49uavy0w2n50gfwq722hn4ua6ka7h" + ] + }, + { + "value": "7232306180", + "n": 1, + "spent": true, + "hex": "0014c3f1a47822c66ad5c33d5a165faccc2743aae520", + "addresses": [ + "via1qc0c6g7pzce4dtseatgt9ltxvyap64efquhlu27" + ] + } + ], + "blockHash": "89f0e6e76d6024265570f05992d1b90fd40d5c8d9d4f0eae1983765f04273928", + "blockHeight": 7013403, + "confirmations": 602446, + "blockTime": 1574881934, + "value": "7242306180", + "valueIn": "7242532180", + "fees": "226000", + "hex": "01000000000101c8744a4ac435b9f329e75c353d9c35255e97fb86c88a4ae3e367edf403ff83d40000000000feffffff0280969800000000001600149c9d2ca5c0dd4bceb08f72a747a12e0794abcebc043c14af01000000160014c3f1a47822c66ad5c33d5a165faccc2743aae52002483045022100f6634aa4e8c532c2e13bf9c7f5426d642f3252a1dc2366801f7483237a97efec02207f1f74164ca966249e6e80668eb92e26b332aff23428c31f9697eb1a0dd7036901210330d36cece866b930e14d48e4a115b15aacc621a87c1f1c56e55dd3583239529300000000" + }, + { + "txid": "d483ff03f4ed67e3e34a8ac886fb975e25359c3d355ce729f3b935c44a4a74c8", + "version": 1, + "vin": [ + { + "txid": "c0e61eaebf96f6a9a193ef721327ca5924ad7562f1909b7b53ca291a5bf53d85", + "n": 0, + "addresses": [ + "via1qql3y6vknyd7d5dyzjdsw35lj8s5ntpkgul48xs" + ], + "value": "7242628756" + } + ], + "vout": [ + { + "value": "7242532180", + "n": 0, + "spent": true, + "hex": "0014393bc7c71bca0fbcf5d192e8de6212decfb07964", + "addresses": [ + "via1q8yau03cmeg8meaw3jt5ducsjmm8mq7tyaynkqh" + ] + } + ], + "blockHash": "892a289c68c3400c0984841d99e9e7f6ef4849c178cd06c7174068da60679b85", + "blockHeight": 6982859, + "confirmations": 632990, + "blockTime": 1574147784, + "value": "7242532180", + "valueIn": "7242628756", + "fees": "96576", + "hex": "01000000000101853df55b1a29ca537b9b90f16275ad2459ca271372ef93a1a9f696bfae1ee6c0000000000000000000015445b0af01000000160014393bc7c71bca0fbcf5d192e8de6212decfb079640247304402202b3f0bcfbb04fda92566defbd5307d86fac4dfb3bef74242f5b65e0f89e6f7b802202606741aeba63cc552d50551ce4a815d58a412901b7788b357d39ba6b745a83e0121024d07f866d7de139ebc87173745e1a17315d0c44d64063b23eb64c039c220667b00000000" + }, + { + "txid": "c0e61eaebf96f6a9a193ef721327ca5924ad7562f1909b7b53ca291a5bf53d85", + "version": 1, + "vin": [ + { + "txid": "d98a521e1f42848aa70889080954ce47e0a4dfa8a523e1a7ba6d786148be1998", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1qvh6wxn9ryr0pmp8xeeg29hgj4pwmaws4r78vq9" + ], + "value": "7242854756" + } + ], + "vout": [ + { + "value": "7242628756", + "n": 0, + "spent": true, + "hex": "001407e24d32d3237cda34829360e8d3f23c293586c8", + "addresses": [ + "via1qql3y6vknyd7d5dyzjdsw35lj8s5ntpkgul48xs" + ] + } + ], + "blockHash": "02bc047ccc595eede2828907af1e49915f3c90593e4529c1a1f0a978ad6d3672", + "blockHeight": 6982851, + "confirmations": 632998, + "blockTime": 1574147586, + "value": "7242628756", + "valueIn": "7242854756", + "fees": "226000", + "hex": "010000000001019819be4861786dbaa7e123a5a8dfa4e047ce5409088908a78a84421f1e528ad90000000000feffffff0194beb1af0100000016001407e24d32d3237cda34829360e8d3f23c293586c802473044022047726b9a153f1151e837092632bb35ce2bbc1a976864eaa4161b11879547738b0220028efd224a642aa05d11607df71319e77a67b8fa8a56050bb2cc3c33f904032401210292b315d9e4d889bcd69098e838b06ca697ac0eab6fcebf538a0f50c5322ea94600000000" + }, + { + "txid": "d98a521e1f42848aa70889080954ce47e0a4dfa8a523e1a7ba6d786148be1998", + "version": 1, + "vin": [ + { + "txid": "07dde2c136ffdeffebd630d4578c02aec2f62f2f7d7b1b53d7524c7382660acf", + "n": 0, + "addresses": [ + "via1q88qhrx05ukgx9py4uu7gz9l6fg7gsjx38u6v2x" + ], + "value": "7242951332" + } + ], + "vout": [ + { + "value": "7242854756", + "n": 0, + "spent": true, + "hex": "001465f4e34ca320de1d84e6ce50a2dd12a85dbeba15", + "addresses": [ + "via1qvh6wxn9ryr0pmp8xeeg29hgj4pwmaws4r78vq9" + ] + } + ], + "blockHash": "a9cd25d3fbaf1b469e09df2785f9da177e540533bcc92d22ce0409ea447b1405", + "blockHeight": 6982834, + "confirmations": 633015, + "blockTime": 1574147247, + "value": "7242854756", + "valueIn": "7242951332", + "fees": "96576", + "hex": "01000000000101cf0a6682734c52d7531b7b7d2f2ff6c2ae028c57d430d6ebffdeff36c1e2dd07000000000000000000016431b5af0100000016001465f4e34ca320de1d84e6ce50a2dd12a85dbeba1502473044022065495e4611f9aa444f52755ab7ed1af483a6114fd813e8cab82cbf0ba88220a4022018542a21f5ba5dc772ddc2f8ad36b102ff66dab484940f2ccc126c2387136bc1012103d8b633e95b597e0c204b9840daf65ea4130a49a4f253d0bd44dad6e8100626db00000000" + }, + { + "txid": "07dde2c136ffdeffebd630d4578c02aec2f62f2f7d7b1b53d7524c7382660acf", + "version": 1, + "vin": [ + { + "txid": "1f73b6896a2266a4410bd8ca059feaed6c41d2b0b330d5d35609c702c35f18cf", + "vout": 1, + "sequence": 4294967293, + "n": 0, + "addresses": [ + "via1qhh33kdegs4057ttyx3w4wqx8qucvj7yehc9t5e" + ], + "value": "674000" + }, + { + "txid": "5c52e68bb5c098edb2113d0a05f3e56acc421cb4733a98b831c2933c1f765578", + "sequence": 4294967294, + "n": 1, + "addresses": [ + "via1q78tmuzvnyffz9lc3yd3xx26qem3p80v6rz6lue" + ], + "value": "1000000" + }, + { + "txid": "7925e744dfa33513745962bba4d87e90f3264cb9131bb49461004865c587de1f", + "sequence": 4294967289, + "n": 2, + "addresses": [ + "via1q0kvzuak82rdaqmgtx0lzrus5c6ct9lx55t7seq" + ], + "value": "1000000" + }, + { + "txid": "639124722d1348e9fdce56feb2617d716abd5875a5d17adf95d32d9e0c02f70f", + "sequence": 4294967285, + "n": 3, + "addresses": [ + "via1q8lc7tuy04z9ssxmz3lndzpk3ul9favy7f70qme" + ], + "value": "1000000" + }, + { + "txid": "2171fc3bb981ea69eb5631b4ab3b48e06cfc273669f925d73511df360c23ead2", + "sequence": 4294967288, + "n": 4, + "addresses": [ + "via1qx72z9rxy3fmqvr47ak99uxam3fwgugvu60d6ws" + ], + "value": "1000000" + }, + { + "txid": "639124722d1348e9fdce56feb2617d716abd5875a5d17adf95d32d9e0c02f70f", + "vout": 1, + "sequence": 4294967284, + "n": 5, + "addresses": [ + "via1q9xpat8z29v8xv5265l53ee8gf0jn3fy8cu3j8e" + ], + "value": "8774000" + }, + { + "txid": "d51ee57fc297072a635b4bba5457511719a6b57b4b108f65e68ebcdb6690098b", + "sequence": 4294967283, + "n": 6, + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ], + "value": "10000000" + }, + { + "txid": "d51ee57fc297072a635b4bba5457511719a6b57b4b108f65e68ebcdb6690098b", + "vout": 1, + "sequence": 4294967282, + "n": 7, + "addresses": [ + "via1qgz6hyva6qcq4gpr030d4lamyuxamf4naawe0e5" + ], + "value": "23087332" + }, + { + "txid": "093904f8f08f3a651711efb2d338df6544252acbaf492aa266cd68239d76f9f8", + "vout": 1, + "sequence": 4294967290, + "n": 8, + "addresses": [ + "via1qtdu5et77ctlsydqwrfkxr5u63j26ng7lkwt0z7" + ], + "value": "46750366" + }, + { + "txid": "b1a53149702bcab970c8603f9844afc1d2543ebec3fcd1c219ea130468a967a2", + "vout": 1, + "sequence": 4294967291, + "n": 9, + "addresses": [ + "via1q760gw3alk4f2jn7wa8faldvrnh3ak3t7avjcwz" + ], + "value": "52119634" + }, + { + "txid": "b1a53149702bcab970c8603f9844afc1d2543ebec3fcd1c219ea130468a967a2", + "sequence": 4294967292, + "n": 10, + "addresses": [ + "via1q62j6pz8t0reg54vnmd4drqpm7ktq02kqcvkdpf" + ], + "value": "100000000" + }, + { + "txid": "8e1fde5beb90db4fe2664040bced2a906dec01d39b5e25f011b9ace488b01051", + "sequence": 4294967287, + "n": 11, + "addresses": [ + "via1qwn0emd9l0qj98xcuw707jxwytxuh36lempkfre" + ], + "value": "145731332" + }, + { + "txid": "8e1fde5beb90db4fe2664040bced2a906dec01d39b5e25f011b9ace488b01051", + "vout": 1, + "sequence": 4294967286, + "n": 12, + "addresses": [ + "via1q8cp08dqnhdwulv748chh8htzakwz2lfjksugtm" + ], + "value": "6853816668" + } + ], + "vout": [ + { + "value": "7242951332", + "n": 0, + "spent": true, + "hex": "001439c17199f4e590628495e73c8117fa4a3c8848d1", + "addresses": [ + "via1q88qhrx05ukgx9py4uu7gz9l6fg7gsjx38u6v2x" + ] + } + ], + "blockHash": "2bfee63a6cd5572890cc6d877a04b7ec0bfb621654ad97a80f09ed15a780beae", + "blockHeight": 6982823, + "confirmations": 633026, + "blockTime": 1574147048, + "value": "7242951332", + "valueIn": "7244953332", + "fees": "2002000", + "hex": "0100000000010dcf185fc302c70956d3d530b3b0d2416cedea9f05cad80b41a466226a89b6731f0100000000fdffffff7855761f3c93c231b8983a73b41c42cc6ae5f3050a3d11b2ed98c0b58be6525c0000000000feffffff1fde87c56548006194b41b13b94c26f3907ed8a4bb6259741335a3df44e725790000000000f9ffffff0ff7020c9e2dd395df7ad1a57558bd6a717d61b2fe56cefde948132d722491630000000000f5ffffffd2ea230c36df1135d725f9693627fc6ce0483babb43156eb69ea81b93bfc71210000000000f8ffffff0ff7020c9e2dd395df7ad1a57558bd6a717d61b2fe56cefde948132d722491630100000000f4ffffff8b099066dbbc8ee6658f104b7bb5a61917515754ba4b5b632a0797c27fe51ed50000000000f3ffffff8b099066dbbc8ee6658f104b7bb5a61917515754ba4b5b632a0797c27fe51ed50100000000f2fffffff8f9769d2368cd66a22a49afcb2a254465df38d3b2ef1117653a8ff0f80439090100000000faffffffa267a9680413ea19c2d1fcc3be3e54d2c1af44983f60c870b9ca2b704931a5b10100000000fbffffffa267a9680413ea19c2d1fcc3be3e54d2c1af44983f60c870b9ca2b704931a5b10000000000fcffffff5110b088e4acb911f0255e9bd301ec6d902aedbc404066e24fdb90eb5bde1f8e0000000000f7ffffff5110b088e4acb911f0255e9bd301ec6d902aedbc404066e24fdb90eb5bde1f8e0100000000f6ffffff01a4aab6af0100000016001439c17199f4e590628495e73c8117fa4a3c8848d1024730440220321ddeb00045126259c92d7a3528705730738bff24a88efbbf4d33ae44b34da5022019046eca1abcbe925f8ee71fdeafd70d697255579e63b7ea7200228e8bd97be60121039187e3d84bb3970d1d22429b3a484d6baaa00050e3b94b83f14abe4749c8470502473044022012e8d4bd47cc722d034d6924af284693a13fb5033478cd963a69a968f3cfbce40220294fdbe29d0998c77939ce6df339c68af6fbfbbbfa638e45e155ae73e52433c8012102ea92b54038005bca8e4d4249019be1b0b5d889208aaa14406d8387644797dd6c02473044022003e8a14b868fb30c43da60b4b909145c5315044ee557aee34ea4cef565fe459802203d9872afd539128ce4013392b912ef197490280f56f3610676d5de6fe8d4c0eb01210212bacd3361e85a16a16dc197d7fcbb9496fbf61e1a70e41ecc81da9d80dca8de02483045022100a064613164d6aedf724326e02621dc985683aa3f89643f57a892d28302e8e4df022052374f12980dab9d91d16ea678c4a7d12a1e68469d88633aa12ddbc6fc31c8ed012102213bcc708dbdf5fab6d3ac1499966dfce37510c6e09b2a58027c0ebe787141ad0247304402202752ec3d2f64b13bc1e64d11a072fe5212cb73fe903109eaf830d334898ed890022013e0973bc3e56b78948d0ea2309fb5bf2002c7ce73ac4193502ff6363589476601210270c78f1d49370f4f03c420ccd8fa35e9e40ee61405b30e4f1171054d3e9248bf02483045022100a730cf6a17580e170bfbbcec139cc2141b2a2091492ac80ad053a653eb04fe1702203efddff0ef666658109669ab2c84597b8f890a95d3fa776da51643825fa2e1570121021acd7a35a34f3e997d7289128f502b08a6e940130619ef7327f8047dc194d08d02483045022100db9a2c03b0750653a7cc3ec5370ebe0da19253e80e4fd0daa889aac942ad398a02202563b1d72248f0e60cd2e2e2143e51b6da8a940f07a684c8bee54afe6c76c184012102b5e09e1dbb76a0eeebea67bf80069ce41c26c81d0f06d1dd42e712ebf55de4bc02483045022100bb23d31e49852b2b5b85292c3cd8a9d6dc8c7487d01def5c74eb646a929e20e7022049b0c8a62cb4420ee1e558c410cd65d0fea44ba652b4d2a435610712ff6d4f700121020f082e2cc3561ea664c82d91deb6b87d99ac7dea173933e8f6529af73be0837d02483045022100d97b09fc661e97faba573d0e9484f6cb2bf08086852b150c15a3044efc0edbcf02200eea145be44dbe90b1bc8dcf26e8d6b1d7fa55f9db30586c688f32c14aef52560121034db1e84ae0636c1b0324e85a7efdcd03b0ca3ecabddb2bcb9ae87e7cf2bcb31102483045022100a4d13d895464e0575c028c2a917039fd33e2e513295d7b3136afb54ace4568e0022037c7ba83445de0aef3fc4659b5a0a1ae9dfc651cfedcaa74e719e47625d4b35f012103f00f6d89e6acd56ac44b0bb42bd30aede6d5180917e35197329108a1ef90fbb3024730440220080ce7571a2db052c45ad3273629a2cbedc787e73bf7cf6687b38b85521bd997022021dc670e9073fcf512640523460eb10d7d9be3e1c6b14392d451c3a1f681f28201210269306517d1eb1aa53bc236e3a62d68ccd24f43d7ad4180b08b4390908139fa24024730440220582ce53d504508435be22101e5d9950423cded2832b136cd02c11ade3e4e6aba022018ccd415785d615d429406eabb8d5aedf2ed8c578fdb028b60040ceaf910b466012102cd0cfcb09d4651c5f320567d61056cdbc9d402c38e6e8b94574aa9902959549602473044022003b362e0408039ac335ced057ece89425e8ea1050f9eddd9f1ae84c2a6ed6867022003f53f8ce13f6001e463c8941b64590cd36a28a24351219342a98519225a9101012103c03e2f55a1abe37ed1a7839ad66f27516a49711cab8c9e6390996ff9ea05455600000000" + }, + { + "txid": "d51ee57fc297072a635b4bba5457511719a6b57b4b108f65e68ebcdb6690098b", + "version": 1, + "vin": [ + { + "txid": "5a5bba52860dff14e1cd3975da180910eac9c1ce4b05df7e4bc287f283fd07b8", + "vout": 1, + "sequence": 4294967287, + "n": 0, + "addresses": [ + "via1qqv3wq50x9y4sdae4eqzpqwgrwtel5p7qdrc5cq" + ], + "value": "33313332" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ] + }, + { + "value": "23087332", + "n": 1, + "spent": true, + "hex": "001440b57233ba060154046f8bdb5ff764e1bbb4d67d", + "addresses": [ + "via1qgz6hyva6qcq4gpr030d4lamyuxamf4naawe0e5" + ] + } + ], + "blockHash": "8f2106b41d4988a3b4650d59a9d3fd7a4aa8e5ed3785d014783f90fcbdceac99", + "blockHeight": 6963630, + "confirmations": 652219, + "blockTime": 1573685639, + "value": "33087332", + "valueIn": "33313332", + "fees": "226000", + "hex": "01000000000101b807fd83f287c24b7edf054bcec1c9ea100918da7539cde114ff0d8652ba5b5a0100000000f7ffffff0280969800000000001600143379fd40508ec2101e11c3519a31615de6e7b673e44860010000000016001440b57233ba060154046f8bdb5ff764e1bbb4d67d0247304402200252d54e1ffa31b1be50cfe715f390d33617642686430416be24325fae853c82022073cd4c84df229af3645cf5795caf8081636cab3fb8a25a9c844aa318c0db96840121032b3a6da896cafe03264effa44dd349cb47bda0d86d5fc51224233828f045867100000000" + }, + { + "txid": "639124722d1348e9fdce56feb2617d716abd5875a5d17adf95d32d9e0c02f70f", + "version": 1, + "vin": [ + { + "txid": "5a5bba52860dff14e1cd3975da180910eac9c1ce4b05df7e4bc287f283fd07b8", + "sequence": 4294967287, + "n": 0, + "addresses": [ + "via1qvd32vttv9j55qdj0qwqltkrh29yxvv9f5wecsx" + ], + "value": "10000000" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "hex": "00143ff1e5f08fa88b081b628fe6d106d1e7ca9eb09e", + "addresses": [ + "via1q8lc7tuy04z9ssxmz3lndzpk3ul9favy7f70qme" + ] + }, + { + "value": "8774000", + "n": 1, + "spent": true, + "hex": "00142983d59c4a2b0e66515aa7e91ce4e84be538a487", + "addresses": [ + "via1q9xpat8z29v8xv5265l53ee8gf0jn3fy8cu3j8e" + ] + } + ], + "blockHash": "e792457c686024e8007938c432e6fafc78cc9ff24ea6d5ccb3ee0211f6c490d8", + "blockHeight": 6937938, + "confirmations": 677911, + "blockTime": 1573068178, + "value": "9774000", + "valueIn": "10000000", + "fees": "226000", + "hex": "01000000000101b807fd83f287c24b7edf054bcec1c9ea100918da7539cde114ff0d8652ba5b5a0000000000f7ffffff0240420f00000000001600143ff1e5f08fa88b081b628fe6d106d1e7ca9eb09e70e18500000000001600142983d59c4a2b0e66515aa7e91ce4e84be538a48702483045022100f28293b7857151eccad4a0c6b50e0d729981ce62c1c30149778a6f6c6b66517e022075bd4432991498a9e65a5d9dbda7d30f0bdf64f956bab2909e00e43bf4a3165701210266c2b86dd04e846725f7c826879a8e4e281ec08ebc665b65c329e8b00ec7516400000000" + }, + { + "txid": "8e1fde5beb90db4fe2664040bced2a906dec01d39b5e25f011b9ace488b01051", + "version": 1, + "vin": [ + { + "txid": "7d8fc63757811fe4d273e3b42b494d13545cf0710cd821f7465572a7584c8642", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1qhrqrcvj9djwrpyss5mk87gyz2k2t0r8feacgpj" + ], + "value": "6999774000" + } + ], + "vout": [ + { + "value": "145731332", + "n": 0, + "spent": true, + "hex": "001474df9db4bf7824539b1c779fe919c459b978ebf9", + "addresses": [ + "via1qwn0emd9l0qj98xcuw707jxwytxuh36lempkfre" + ] + }, + { + "value": "6853816668", + "n": 1, + "spent": true, + "hex": "00143e02f3b413bb5dcfb3d53e2f73dd62ed9c257d32", + "addresses": [ + "via1q8cp08dqnhdwulv748chh8htzakwz2lfjksugtm" + ] + } + ], + "blockHash": "aed49601b577434ba4b33e18e244119fb94d1c0cf5ff3126aba3520f3cd9f4df", + "blockHeight": 6915541, + "confirmations": 700308, + "blockTime": 1572529818, + "value": "6999548000", + "valueIn": "6999774000", + "fees": "226000", + "hex": "0100000000010142864c58a7725546f721d80c71f05c54134d492bb4e373d2e41f815737c68f7d0100000000feffffff0204afaf080000000016001474df9db4bf7824539b1c779fe919c459b978ebf95cf18498010000001600143e02f3b413bb5dcfb3d53e2f73dd62ed9c257d3202483045022100b839ad22d00b6bac9f4aba109d38a76a1724aa9d47d94d1d03b2fdd68bed5d9b0220595944e4b1c6170d8995fc9b506584d8a3c4d1ac0e110ace79f06d8e47b8c976012103a7ca8479fe2d2284eb91cd26d02c821a1cfe57eb5a660a06c02b72b1e2ed30dd00000000" + }, + { + "txid": "5a5bba52860dff14e1cd3975da180910eac9c1ce4b05df7e4bc287f283fd07b8", + "version": 1, + "vin": [ + { + "txid": "2171fc3bb981ea69eb5631b4ab3b48e06cfc273669f925d73511df360c23ead2", + "vout": 1, + "n": 0, + "addresses": [ + "via1qlm2s4wgh5n64kukpnjkq0kea3fg6lcw4l2ptrw" + ], + "value": "43427010" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "00146362a62d6c2ca940364f0381f5d87751486630a9", + "addresses": [ + "via1qvd32vttv9j55qdj0qwqltkrh29yxvv9f5wecsx" + ] + }, + { + "value": "33313332", + "n": 1, + "spent": true, + "hex": "00140322e051e6292b06f735c80410390372f3fa07c0", + "addresses": [ + "via1qqv3wq50x9y4sdae4eqzpqwgrwtel5p7qdrc5cq" + ] + } + ], + "blockHash": "754e01ca904e90b88da23b50237969099ea7a07ea71f5cb7842601559a852384", + "blockHeight": 6892052, + "confirmations": 723797, + "blockTime": 1571965158, + "value": "43313332", + "valueIn": "43427010", + "fees": "113678", + "hex": "01000000000101d2ea230c36df1135d725f9693627fc6ce0483babb43156eb69ea81b93bfc71210100000000000000000280969800000000001600146362a62d6c2ca940364f0381f5d87751486630a93452fc01000000001600140322e051e6292b06f735c80410390372f3fa07c00247304402203670013811d6b055f214dd0882b065b93850f842c5ff45d1c47618c7515a4c2802201ff4a11df094a857e8c1bbfa4cd4aec16593583c07596d2cd4ddf9276a9d8aea01210284942b015a484563494f37559e8f12958ef842439b95657c84fefa60b0c0116800000000" + }, + { + "txid": "2171fc3bb981ea69eb5631b4ab3b48e06cfc273669f925d73511df360c23ead2", + "version": 1, + "vin": [ + { + "txid": "7925e744dfa33513745962bba4d87e90f3264cb9131bb49461004865c587de1f", + "vout": 1, + "n": 0, + "addresses": [ + "via1qnuxuwrrscmdezm6xdl053hcedzmrl27ylnd5gw" + ], + "value": "44540688" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "hex": "00143794228cc48a76060ebeed8a5e1bbb8a5c8e219c", + "addresses": [ + "via1qx72z9rxy3fmqvr47ak99uxam3fwgugvu60d6ws" + ] + }, + { + "value": "43427010", + "n": 1, + "spent": true, + "hex": "0014fed50ab917a4f55b72c19cac07db3d8a51afe1d5", + "addresses": [ + "via1qlm2s4wgh5n64kukpnjkq0kea3fg6lcw4l2ptrw" + ] + } + ], + "blockHash": "cef1a23a742f6dd54d47604e7f4f84d0b1f88654ef7828279f28ee98272fbcfa", + "blockHeight": 6857056, + "confirmations": 758793, + "blockTime": 1571123779, + "value": "44427010", + "valueIn": "44540688", + "fees": "113678", + "hex": "010000000001011fde87c56548006194b41b13b94c26f3907ed8a4bb6259741335a3df44e725790100000000000000000240420f00000000001600143794228cc48a76060ebeed8a5e1bbb8a5c8e219cc2a4960200000000160014fed50ab917a4f55b72c19cac07db3d8a51afe1d502483045022100a23745485206718356760dd4ed48f48d034abfba0c45c172dc88df88e89d2a1b022024ad2aafb0fdace395b28fe01c9df8814afacb24740839384e82e99db8936b59012103e628b30b3fd01b370fba114c15c2233fcb37cb5450461b8428b08dda7466e12900000000" + }, + { + "txid": "7925e744dfa33513745962bba4d87e90f3264cb9131bb49461004865c587de1f", + "version": 1, + "vin": [ + { + "txid": "f89d999261e691ee65cc4d0dd8b516c7fbbb0f2a35f03ed449fa29388d0414c2", + "vout": 1, + "n": 0, + "addresses": [ + "via1qe43a7w7us8vyaa4mmdwjppr6gh8j9j9pwpxpyh" + ], + "value": "45654366" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "hex": "00147d982e76c750dbd06d0b33fe21f214c6b0b2fcd4", + "addresses": [ + "via1q0kvzuak82rdaqmgtx0lzrus5c6ct9lx55t7seq" + ] + }, + { + "value": "44540688", + "n": 1, + "spent": true, + "hex": "00149f0dc70c70c6db916f466fdf48df1968b63fabc4", + "addresses": [ + "via1qnuxuwrrscmdezm6xdl053hcedzmrl27ylnd5gw" + ] + } + ], + "blockHash": "d4e68ba9688ea2cd0523a9ce086b830cc90921780d86061a8294dc446a35f69e", + "blockHeight": 6856608, + "confirmations": 759241, + "blockTime": 1571113111, + "value": "45540688", + "valueIn": "45654366", + "fees": "113678", + "hex": "01000000000101c214048d3829fa49d43ef0352a0fbbfbc716b5d80d4dcc65ee91e66192999df80100000000000000000240420f00000000001600147d982e76c750dbd06d0b33fe21f214c6b0b2fcd410a3a702000000001600149f0dc70c70c6db916f466fdf48df1968b63fabc402483045022100b842ca78affb900ec901e48cf0b4df311d833cf8ac3fa168948f97099cd50f320220404d4c85ee2039371b5a9c14e2a74678b0888e8b60647a6152871e0a4480055d012102a14c53b1f112c58eabc9e58b07c7be3b81fb6ad4a7e5260952a66882d88d34cf00000000" + }, + { + "txid": "093904f8f08f3a651711efb2d338df6544252acbaf492aa266cd68239d76f9f8", + "version": 1, + "vin": [ + { + "txid": "8888df5bd0444723eabd8d3034ad042cf58f8aa2ffa9b18b8e7d3d3e0ed1763f", + "sequence": 4294967291, + "n": 0, + "addresses": [ + "via1qy6fkhfza4kj7f83lnkjkqyz73zuffyaq2ttxx6" + ], + "value": "146976366" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "001453e45e03d888aaef8c94fc144859448ddd4ed36d", + "addresses": [ + "via1q20j9uq7c3z4wlry5ls2ysk2y3hw5a5mdv709m8" + ] + }, + { + "value": "46750366", + "n": 1, + "spent": true, + "hex": "00145b794cafdec2ff02340e1a6c61d39a8c95a9a3df", + "addresses": [ + "via1qtdu5et77ctlsydqwrfkxr5u63j26ng7lkwt0z7" + ] + } + ], + "blockHash": "adb73826ff107abc11452d72d974980c1b9147dc505b3a1e6932178a7fffb26e", + "blockHeight": 6812515, + "confirmations": 803334, + "blockTime": 1570053434, + "value": "146750366", + "valueIn": "146976366", + "fees": "226000", + "hex": "010000000001013f76d10e3e3d7d8e8bb1a9ffa28a8ff52c04ad34308dbdea234744d05bdf88880000000000fbffffff0200e1f5050000000016001453e45e03d888aaef8c94fc144859448ddd4ed36d9e5ac902000000001600145b794cafdec2ff02340e1a6c61d39a8c95a9a3df02483045022100906f19bc71c18053459941d737a0efe321c3e6193e8f67e969ff2f1fea16ca0c0220711da1af0613e970bb04a3eb70373c91345cf39747d8fa5187bf4bac62a0546e012102f3236f9caf206ac54900f17d113ec9c298017f3a78179cfc738e06b364938a1100000000" + }, + { + "txid": "b1a53149702bcab970c8603f9844afc1d2543ebec3fcd1c219ea130468a967a2", + "version": 1, + "vin": [ + { + "txid": "8888df5bd0444723eabd8d3034ad042cf58f8aa2ffa9b18b8e7d3d3e0ed1763f", + "vout": 1, + "sequence": 4294967290, + "n": 0, + "addresses": [ + "via1qnjmu3ce5veyn4wd2wrjdvtz9amz0l2kw7x6hp4" + ], + "value": "152345634" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "0014d2a5a088eb78f28a5593db6ad1803bf59607aac0", + "addresses": [ + "via1q62j6pz8t0reg54vnmd4drqpm7ktq02kqcvkdpf" + ] + }, + { + "value": "52119634", + "n": 1, + "spent": true, + "hex": "0014f69e8747bfb552a94fcee9d3dfb5839de3db457e", + "addresses": [ + "via1q760gw3alk4f2jn7wa8faldvrnh3ak3t7avjcwz" + ] + } + ], + "blockHash": "831d5243d513772135fb5a8d8f4499db3ba6b513009afde1c01af14a2881883a", + "blockHeight": 6800220, + "confirmations": 815629, + "blockTime": 1569757759, + "value": "152119634", + "valueIn": "152345634", + "fees": "226000", + "hex": "010000000001013f76d10e3e3d7d8e8bb1a9ffa28a8ff52c04ad34308dbdea234744d05bdf88880100000000faffffff0200e1f50500000000160014d2a5a088eb78f28a5593db6ad1803bf59607aac052481b0300000000160014f69e8747bfb552a94fcee9d3dfb5839de3db457e024830450221008c8568f209b728145e3292d1480b5e1d8bff4c84c4f283d5a0ca2cc391bd0bfc0220465f0cf504ec5eb83055efd89bb50d26e04ce0b510ecd2f307cad22b37e2730d012102b73beb45f31938085a4e44a66c8d16c4f430d5cc203bf5861d20158d7260680a00000000" + }, + { + "txid": "1f73b6896a2266a4410bd8ca059feaed6c41d2b0b330d5d35609c702c35f18cf", + "version": 1, + "vin": [ + { + "txid": "c3ad35b33ba3d9c2b11335e6b2f63b3f60ee6a89e8f0f63f1c4a7867ac471410", + "sequence": 4294967292, + "n": 0, + "addresses": [ + "via1q78tmuzvnyffz9lc3yd3xx26qem3p80v6rz6lue" + ], + "value": "1000000" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "0014909224c2ecb592cb668adb07e1eff933493b6190", + "addresses": [ + "via1qjzfzfshvkkfvke52mvr7rmlexdynkcvsqzvu8l" + ] + }, + { + "value": "674000", + "n": 1, + "spent": true, + "hex": "0014bde31b3728855f4f2d64345d5700c70730c97899", + "addresses": [ + "via1qhh33kdegs4057ttyx3w4wqx8qucvj7yehc9t5e" + ] + } + ], + "blockHash": "ed79788499fcd324e8c3cc0dde623187d1f822c322b87c5ad2c5207bf5707845", + "blockHeight": 6795818, + "confirmations": 820031, + "blockTime": 1569652139, + "value": "774000", + "valueIn": "1000000", + "fees": "226000", + "hex": "01000000000101101447ac67784a1c3ff6f0e8896aee603f3bf6b2e63513b1c2d9a33bb335adc30000000000fcffffff02a086010000000000160014909224c2ecb592cb668adb07e1eff933493b6190d0480a0000000000160014bde31b3728855f4f2d64345d5700c70730c9789902483045022100b77fed5e8393b5da21303d9ca8f2166d1217a14937fd08dd13deda5ecb9d9c030220773124466fff61400df36eeb170cccff26a7d969c57cbff45d3e4c745d799819012102ea92b54038005bca8e4d4249019be1b0b5d889208aaa14406d8387644797dd6c00000000" + }, + { + "txid": "8888df5bd0444723eabd8d3034ad042cf58f8aa2ffa9b18b8e7d3d3e0ed1763f", + "version": 1, + "vin": [ + { + "txid": "67f57fffb949986e8e3a7ffb162246826f6a4c7868249f0ca01841c84ed849b5", + "vout": 1, + "sequence": 4294967293, + "n": 0, + "addresses": [ + "via1qc777z0fxa5zys4uqydcz2q8k9a9k38plskv9uj" + ], + "value": "299548000" + } + ], + "vout": [ + { + "value": "146976366", + "n": 0, + "spent": true, + "hex": "001426936ba45dada5e49e3f9da560105e88b89493a0", + "addresses": [ + "via1qy6fkhfza4kj7f83lnkjkqyz73zuffyaq2ttxx6" + ] + }, + { + "value": "152345634", + "n": 1, + "spent": true, + "hex": "00149cb7c8e33466493ab9aa70e4d62c45eec4ffaace", + "addresses": [ + "via1qnjmu3ce5veyn4wd2wrjdvtz9amz0l2kw7x6hp4" + ] + } + ], + "blockHash": "cd681ca3d28a391b0a5b8fd2e2b3f1f3fbf52a812766616ac785651b67b29424", + "blockHeight": 6784116, + "confirmations": 831733, + "blockTime": 1569370788, + "value": "299322000", + "valueIn": "299548000", + "fees": "226000", + "hex": "01000000000101b549d84ec84118a00c9f2468784c6a6f82462216fb7f3a8e6e9849b9ff7ff5670100000000fdffffff026eaec2080000000016001426936ba45dada5e49e3f9da560105e88b89493a0229c1409000000001600149cb7c8e33466493ab9aa70e4d62c45eec4ffaace0247304402200e4f5a4adf75abcd3f1ba0318d15f1723dddf0d3eec9ab1130e9987aad238ae10220195c0d0bc690f512272dbdaf8b84adff47779715917a583e02202872c753756e0121020fbccca36fb54cf3848401e73b9a5828006bcbafdc5456881d46253d7c72ec9500000000" + }, + { + "txid": "f89d999261e691ee65cc4d0dd8b516c7fbbb0f2a35f03ed449fa29388d0414c2", + "version": 1, + "vin": [ + { + "txid": "5c52e68bb5c098edb2113d0a05f3e56acc421cb4733a98b831c2933c1f765578", + "vout": 1, + "n": 0, + "addresses": [ + "via1qvunq979fdt26qt0ez7ftth8tlw6zrlpl832ddu" + ], + "value": "46768044" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "0014dc7aa2089196a3bc06b4a055419f4c81209a6748", + "addresses": [ + "via1qm3a2yzy3j63mcp455p25r86vsysf5e6gfvylv8" + ] + }, + { + "value": "45654366", + "n": 1, + "spent": true, + "hex": "0014cd63df3bdc81d84ef6bbdb5d20847a45cf22c8a1", + "addresses": [ + "via1qe43a7w7us8vyaa4mmdwjppr6gh8j9j9pwpxpyh" + ] + } + ], + "blockHash": "e7abb937d43aad42ba863751a358f0734c365a9aa64a06d9b35da09a5a41f0cc", + "blockHeight": 6780184, + "confirmations": 835665, + "blockTime": 1569276054, + "value": "46654366", + "valueIn": "46768044", + "fees": "113678", + "hex": "010000000001017855761f3c93c231b8983a73b41c42cc6ae5f3050a3d11b2ed98c0b58be6525c0100000000000000000240420f0000000000160014dc7aa2089196a3bc06b4a055419f4c81209a67485ea1b80200000000160014cd63df3bdc81d84ef6bbdb5d20847a45cf22c8a1024730440220477773a615d0b4ec4320e329a349c561c9e03af152d52f22a5713123b67d2daf02207d8b22fb6fef4b22add99dd2f0d7622ef85633a75ecdc1a890aa1b0899ffea2e0121033068f399551ff7b26ba4e0a9e77d775a2de00f72c75dd696e9d4bb990507b73800000000" + }, + { + "txid": "c3ad35b33ba3d9c2b11335e6b2f63b3f60ee6a89e8f0f63f1c4a7867ac471410", + "version": 1, + "vin": [ + { + "txid": "7c05afb2da19d6802ba6149e1830ad0461ce335b8f90a8edc0cd1766dc024cca", + "vout": 1, + "n": 0, + "addresses": [ + "via1qfc4y3lwjfpgvjlsu3y3cvekvmdrlp96ckeawxe" + ], + "value": "48995400" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "hex": "0014f1d7be0993225222ff112362632b40cee213bd9a", + "addresses": [ + "via1q78tmuzvnyffz9lc3yd3xx26qem3p80v6rz6lue" + ] + }, + { + "value": "47881722", + "n": 1, + "spent": true, + "hex": "0014672602f8a96ad5a02df91792b5dcebfbb421fc3f", + "addresses": [ + "via1qvunq979fdt26qt0ez7ftth8tlw6zrlpl832ddu" + ] + } + ], + "blockHash": "43f683cab4827c11326a51dedb7d4eb2736b93702bc7e569377a581087e4f3d7", + "blockHeight": 6780089, + "confirmations": 835760, + "blockTime": 1569273836, + "value": "48881722", + "valueIn": "48995400", + "fees": "113678", + "hex": "01000000000101ca4c02dc6617cdc0eda8908f5b33ce6104ad30189e14a62b80d619dab2af057c0100000000000000000240420f0000000000160014f1d7be0993225222ff112362632b40cee213bd9afa9dda0200000000160014672602f8a96ad5a02df91792b5dcebfbb421fc3f02473044022022c5c99e2dbaa1c699d4449a846aa0d7b2b2ad9a547712a93d9ade6592fd23cf022056b19faf1a0f7702137b7da2c8f131b1a1d509092634241b61a29d9b3474f47f0121037b45b9e2a32072e7546971aa5b39c90558bcd4784817946976ccf93ead81d71a00000000" + }, + { + "txid": "5c52e68bb5c098edb2113d0a05f3e56acc421cb4733a98b831c2933c1f765578", + "version": 1, + "vin": [ + { + "txid": "c3ad35b33ba3d9c2b11335e6b2f63b3f60ee6a89e8f0f63f1c4a7867ac471410", + "vout": 1, + "n": 0, + "addresses": [ + "via1qvunq979fdt26qt0ez7ftth8tlw6zrlpl832ddu" + ], + "value": "47881722" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "hex": "0014f1d7be0993225222ff112362632b40cee213bd9a", + "addresses": [ + "via1q78tmuzvnyffz9lc3yd3xx26qem3p80v6rz6lue" + ] + }, + { + "value": "46768044", + "n": 1, + "spent": true, + "hex": "0014672602f8a96ad5a02df91792b5dcebfbb421fc3f", + "addresses": [ + "via1qvunq979fdt26qt0ez7ftth8tlw6zrlpl832ddu" + ] + } + ], + "blockHash": "43f683cab4827c11326a51dedb7d4eb2736b93702bc7e569377a581087e4f3d7", + "blockHeight": 6780089, + "confirmations": 835760, + "blockTime": 1569273836, + "value": "47768044", + "valueIn": "47881722", + "fees": "113678", + "hex": "01000000000101101447ac67784a1c3ff6f0e8896aee603f3bf6b2e63513b1c2d9a33bb335adc30100000000000000000240420f0000000000160014f1d7be0993225222ff112362632b40cee213bd9aac9fc90200000000160014672602f8a96ad5a02df91792b5dcebfbb421fc3f024730440220169b26ddcb926c6c1660b8c36ec33ea3759d1309f45591a965b4cb22ab3317e60220531485fe11cb14f6207c70312cf1145d7d101782e6650d6e16ba77133159944c0121033068f399551ff7b26ba4e0a9e77d775a2de00f72c75dd696e9d4bb990507b73800000000" + }, + { + "txid": "67f57fffb949986e8e3a7ffb162246826f6a4c7868249f0ca01841c84ed849b5", + "version": 1, + "vin": [ + { + "txid": "2ae361d18204115b70ff6a4c9732731e17f7cbb74bba81e8da00ed59ccff341a", + "vout": 1, + "n": 0, + "addresses": [ + "via1q89sm5qp46gsz6v2fru3s9xts4l3zry4gh7t6ma" + ], + "value": "399774000" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "0014318c521111bce0532476791cd1ba35f141630758", + "addresses": [ + "via1qxxx9yyg3hns9xfrk0ywdrw3479qkxp6czjy88m" + ] + }, + { + "value": "299548000", + "n": 1, + "spent": true, + "hex": "0014c7bde13d26ed0448578023702500f62f4b689c3f", + "addresses": [ + "via1qc777z0fxa5zys4uqydcz2q8k9a9k38plskv9uj" + ] + } + ], + "blockHash": "18498d8579c63b3d8686bf8cac77cc45a2576252fad3bcbbd2c30eb82bee46ec", + "blockHeight": 6779825, + "confirmations": 836024, + "blockTime": 1569267386, + "value": "399548000", + "valueIn": "399774000", + "fees": "226000", + "hex": "010000000001011a34ffcc59ed00dae881ba4bb7cbf7171e7332974c6aff705b110482d161e32a0100000000000000000200e1f50500000000160014318c521111bce0532476791cd1ba35f14163075860bdda1100000000160014c7bde13d26ed0448578023702500f62f4b689c3f0247304402201d568d8335a7d33c44a61415c20b6c0806a1691a44469237587fd43e585037970220335d2bab70e5aa1b794b719ac49d904481bae8b0f9dfb586179285d1e44aece60121021d1d0eb5e3175a527826672498a86c3ccd64b73bb8c0659b601a1ceaf4e4521700000000" + }, + { + "txid": "7c05afb2da19d6802ba6149e1830ad0461ce335b8f90a8edc0cd1766dc024cca", + "version": 1, + "vin": [ + { + "txid": "4de1e3038e96ec2a5fcb6794d5929eeb29b1ef0c594310877260ab2ba28178ab", + "vout": 1, + "n": 0, + "addresses": [ + "via1qqffjd0qc7vxfrc3rp9phwvajlchg20e6lt3dmx" + ], + "value": "99221400" + } + ], + "vout": [ + { + "value": "50000000", + "n": 0, + "hex": "00148577f1eb6875c3999d4c5c758eb1de786225bdbf", + "addresses": [ + "via1qs4mlr6mgwhpen82vt36cavw70p3zt0dljekypn" + ] + }, + { + "value": "48995400", + "n": 1, + "spent": true, + "hex": "00144e2a48fdd24850c97e1c89238666ccdb47f09758", + "addresses": [ + "via1qfc4y3lwjfpgvjlsu3y3cvekvmdrlp96ckeawxe" + ] + } + ], + "blockHash": "d99d2b3fd6b0a12ba753976030fc58512c761701d4d6017a6dc0d733c2b116da", + "blockHeight": 6779783, + "confirmations": 836066, + "blockTime": 1569266470, + "value": "98995400", + "valueIn": "99221400", + "fees": "226000", + "hex": "01000000000101ab7881a22bab6072871043590cefb129eb9e92d59467cb5f2aec968e03e3e14d0100000000000000000280f0fa02000000001600148577f1eb6875c3999d4c5c758eb1de786225bdbf489ceb02000000001600144e2a48fdd24850c97e1c89238666ccdb47f09758024730440220162685e7ede00a699387514a18712e83688507bc3ffd5e4e1ebe004415dad2d602205793613e6fe1affff1218c2617c6be539e4dcd53ade1e32fab6d08927f0f4bd5012103a505d41830eadcdf44daefe4ac1ba38b68b331645ba13d5048d5d817b228374a00000000" + }, + { + "txid": "2ae361d18204115b70ff6a4c9732731e17f7cbb74bba81e8da00ed59ccff341a", + "version": 1, + "vin": [ + { + "txid": "dc42ddd940b64e9ff5f9e09e631b3796713ddb32bba866bcd6fdf37d646f34e9", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1q72a3hy7xpcyc2leda6qkct6xfwej8s4v9r3az8" + ], + "value": "500000000" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "001423b4e2d36ba4da7f817acac1b7007dc9312ecda4", + "addresses": [ + "via1qyw6w95mt5nd8lqt6etqmwqraeycjandyl330rv" + ] + }, + { + "value": "399774000", + "n": 1, + "spent": true, + "hex": "00143961ba0035d2202d31491f23029970afe22192a8", + "addresses": [ + "via1q89sm5qp46gsz6v2fru3s9xts4l3zry4gh7t6ma" + ] + } + ], + "blockHash": "289b8b2d4b4941918154906dd27eb74a81079a1e7760f0f842d0e56c1ede179b", + "blockHeight": 6779738, + "confirmations": 836111, + "blockTime": 1569265554, + "value": "499774000", + "valueIn": "500000000", + "fees": "226000", + "hex": "01000000000101e9346f647df3fdd6bc66a8bb32db3d7196371b639ee0f9f59f4eb640d9dd42dc0000000000feffffff0200e1f5050000000016001423b4e2d36ba4da7f817acac1b7007dc9312ecda43011d417000000001600143961ba0035d2202d31491f23029970afe22192a802483045022100ef67ba5a6f7d520489e442593c28efd4caf6603a2c9d28a8e81114db140a1bb1022008fb9a91f39a1bb2a0dd34235a18974c2f61038f57f2acc7a267d849df21c80001210378804c3bc03d59f9d42990d300b9a0a6b2617bb4d212fbc876c8b52a5cc1aaed00000000" + }, + { + "txid": "7d8fc63757811fe4d273e3b42b494d13545cf0710cd821f7465572a7584c8642", + "version": 1, + "vin": [ + { + "txid": "01260aa2c76f779bcaffe5b8ffa2c94679f04f5b56bb37c219d7a1e8709681ba", + "vout": 1, + "n": 0, + "addresses": [ + "via1qs0q96xq7sewylsn6ymnvav8wgmzmdmvmjyxgnj" + ], + "value": "8000000000" + } + ], + "vout": [ + { + "value": "1000000000", + "n": 0, + "hex": "001492ab39fd32ac57ba3a7addbd877edd26a478c8d7", + "addresses": [ + "via1qj24nnlfj43tm5wn6mk7cwlkay6j83jxhj9wnqj" + ] + }, + { + "value": "6999774000", + "n": 1, + "spent": true, + "hex": "0014b8c03c32456c9c309210a6ec7f20825594b78ce9", + "addresses": [ + "via1qhrqrcvj9djwrpyss5mk87gyz2k2t0r8feacgpj" + ] + } + ], + "blockHash": "b0c22a4281142db8bfcbd4b93cc2b487aab7dd70bb503d429b981eb4bcee3631", + "blockHeight": 6646858, + "confirmations": 968991, + "blockTime": 1566071686, + "value": "7999774000", + "valueIn": "8000000000", + "fees": "226000", + "hex": "01000000000101ba819670e8a1d719c237bb565b4ff07946c9a2ffb8e5ffca9b776fc7a20a26010100000000000000000200ca9a3b0000000016001492ab39fd32ac57ba3a7addbd877edd26a478c8d7301338a101000000160014b8c03c32456c9c309210a6ec7f20825594b78ce902473044022022068961df34895c5a49390d9697f940d9bd8655b1638ff3ea8f39a83bd1107d022071a0a89d18670d7300f95b4400783960dbdfbf31e92e9fbfc60e4d815dbc1fd4012103d6f34e01ca999f901846a299cbd1f20c3b249b10a3f84f960973126abbc42cdb00000000" + }, + { + "txid": "4de1e3038e96ec2a5fcb6794d5929eeb29b1ef0c594310877260ab2ba28178ab", + "version": 1, + "vin": [ + { + "txid": "63c1ca0539d77934114fef011b4bf63ba69509eafcdc4b1a398e5668a69fe80a", + "vout": 1, + "sequence": 4294967292, + "n": 0, + "addresses": [ + "via1qupymhaypcepp2jhsgnxch5amgnf860jwqp3u6h" + ], + "value": "184447400" + } + ], + "vout": [ + { + "value": "85000000", + "n": 0, + "hex": "001453e45e03d888aaef8c94fc144859448ddd4ed36d", + "addresses": [ + "via1q20j9uq7c3z4wlry5ls2ysk2y3hw5a5mdv709m8" + ] + }, + { + "value": "99221400", + "n": 1, + "spent": true, + "hex": "0014025326bc18f30c91e22309437733b2fe2e853f3a", + "addresses": [ + "via1qqffjd0qc7vxfrc3rp9phwvajlchg20e6lt3dmx" + ] + } + ], + "blockHash": "51a8c267d36372c67b0c10cf1c5e95ae3f57a1d0a4ca2011bf3b2a240c797ceb", + "blockHeight": 6609941, + "confirmations": 1005908, + "blockTime": 1565184213, + "value": "184221400", + "valueIn": "184447400", + "fees": "226000", + "hex": "010000000001010ae89fa668568e391a4bdcfcea0995a63bf64b1b01ef4f113479d73905cac1630100000000fcffffff0240ff10050000000016001453e45e03d888aaef8c94fc144859448ddd4ed36d98ffe90500000000160014025326bc18f30c91e22309437733b2fe2e853f3a0247304402207b4c49cc91b7352e74082d75dc03a73b12ce69c2ba04b5036803313e540fc5a302207c0a5dc7af53d02e3a4d4ace4a8177d304c199bcfebec300064a637c08f65e8c012102bf4cb51b466fcce619d09e4b94c2989cb43a562e90f1cc2dfb83583226e6924200000000" + }, + { + "txid": "63c1ca0539d77934114fef011b4bf63ba69509eafcdc4b1a398e5668a69fe80a", + "version": 1, + "vin": [ + { + "txid": "053f581b81e25e470986d39b65684c7980f2ebcc9a024bd48ae3b8f9610910d3", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1q9f0fhxl8sgrxegldfczed5lftf4wxy3c085ch2" + ], + "value": "191173400" + } + ], + "vout": [ + { + "value": "6500000", + "n": 0, + "hex": "001453e45e03d888aaef8c94fc144859448ddd4ed36d", + "addresses": [ + "via1q20j9uq7c3z4wlry5ls2ysk2y3hw5a5mdv709m8" + ] + }, + { + "value": "184447400", + "n": 1, + "spent": true, + "hex": "0014e049bbf481c642154af044cd8bd3bb44d27d3e4e", + "addresses": [ + "via1qupymhaypcepp2jhsgnxch5amgnf860jwqp3u6h" + ] + } + ], + "blockHash": "c8ec9dd52527c65404741e980d0cd36f5b56f30f3c9678fc30e6824485d75a06", + "blockHeight": 6609932, + "confirmations": 1005917, + "blockTime": 1565184011, + "value": "190947400", + "valueIn": "191173400", + "fees": "226000", + "hex": "01000000000101d3100961f9b8e38ad44b029accebf280794c68659bd38609475ee2811b583f050100000000feffffff02a02e63000000000016001453e45e03d888aaef8c94fc144859448ddd4ed36da871fe0a00000000160014e049bbf481c642154af044cd8bd3bb44d27d3e4e0247304402202768c6220d3e9b5640baffdf56b1196863d0a31b8efe88d656d504dc7eb02e720220359acab7fccf4ec647e3640256a92a46dbb542186ae0f9ebd3aadf9065eecab3012103a5ce3a1e5945c517b3e0b8843dccaa4fecb14ef243d536abe24480a2fd8c96c400000000" + }, + { + "txid": "01260aa2c76f779bcaffe5b8ffa2c94679f04f5b56bb37c219d7a1e8709681ba", + "version": 2, + "lockTime": 6301784, + "vin": [ + { + "txid": "773eb0c88439f8f97dc6f85537846d8afe536852fb4c08dbda69b6c89187b639", + "sequence": 4294967293, + "n": 0, + "addresses": [ + "EJ7xexKUB43nuGpZUvyVXreboogRAj2F6q" + ], + "value": "9300000000", + "hex": "16001423eb40fc587abc864be5996b6e38c974d01dd2a4" + } + ], + "vout": [ + { + "value": "1299967200", + "n": 0, + "hex": "0014c488f81733eac2080d4939e5b6fd70f18a493231", + "addresses": [ + "via1qcjy0s9enatpqsr2f88jmdlts7x9yjv33z5aj7x" + ] + }, + { + "value": "8000000000", + "n": 1, + "spent": true, + "hex": "001483c05d181e865c4fc27a26e6ceb0ee46c5b6ed9b", + "addresses": [ + "via1qs0q96xq7sewylsn6ymnvav8wgmzmdmvmjyxgnj" + ] + } + ], + "blockHash": "a2f204b450f1a1ae551fbc0355ae3b31e6f7080f04765761dcb2ff9af0beb29b", + "blockHeight": 6301790, + "confirmations": 1314059, + "blockTime": 1557777925, + "value": "9299967200", + "valueIn": "9300000000", + "fees": "32800", + "hex": "0200000000010139b68791c8b669dadb084cfb526853fe8a6d843755f8c67df9f83984c8b03e77000000001716001423eb40fc587abc864be5996b6e38c974d01dd2a4fdffffff02e0ec7b4d00000000160014c488f81733eac2080d4939e5b6fd70f18a4932310050d6dc0100000016001483c05d181e865c4fc27a26e6ceb0ee46c5b6ed9b02483045022100f86c406aca19b3df2429b612d23b3d1f0ede81969a7809b6979782aa1e886d2b022074c8186b06704bf8ffa0821241cf624e53be699be78c8a2243b7f58c8a38a3ad012102381b81cc88fbbe7c6dba6df6119d594232fe88e48e8f77201dd46ce4ae5120c158286000" + }, + { + "txid": "dc42ddd940b64e9ff5f9e09e631b3796713ddb32bba866bcd6fdf37d646f34e9", + "version": 1, + "vin": [ + { + "txid": "08fb8ccb9fd84b77618ac517246823482d483f1e8071e781dcfc750fc6a9062a", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "via1q9elq2d3w7fy0t9e4dlq97ke5wwvl8c0lnp39lv" + ], + "value": "45647600" + }, + { + "txid": "93fb0d8004081b534040a98918b5459b05f6cdffca8c1380da6ba9eadb9a95a3", + "vout": 1, + "sequence": 4294967295, + "n": 1, + "addresses": [ + "EYqWehbaMwECMmGNqrQJnCgBmYiM4Xyzq8" + ], + "value": "2000000000", + "hex": "160014c5c8806f9b4121da84c2e71d84aaa493b6483780" + } + ], + "vout": [ + { + "value": "500000000", + "n": 0, + "spent": true, + "hex": "0014f2bb1b93c60e09857f2dee816c2f464bb323c2ac", + "addresses": [ + "via1q72a3hy7xpcyc2leda6qkct6xfwej8s4v9r3az8" + ] + }, + { + "value": "1545624400", + "n": 1, + "spent": true, + "hex": "0014e3830780b3479eb68be6514ac99142e845546434", + "addresses": [ + "via1quwps0q9ng70tdzlx299vny2zapz4gep5uqhcza" + ] + } + ], + "blockHash": "4d40765a8809d91e63c0a1ed388b8e401a2e4842bef7eb072ba264c47b0841ba", + "blockHeight": 6301606, + "confirmations": 1314243, + "blockTime": 1557773592, + "value": "2045624400", + "valueIn": "2045647600", + "fees": "23200", + "hex": "010000000001022a06a9c60f75fcdc81e771801e3f482d4823682417c58a61774bd89fcb8cfb080000000000ffffffffa3959adbeaa96bda80138ccaffcdf6059b45b51889a94040531b0804800dfb930100000017160014c5c8806f9b4121da84c2e71d84aaa493b6483780ffffffff020065cd1d00000000160014f2bb1b93c60e09857f2dee816c2f464bb323c2ac505b205c00000000160014e3830780b3479eb68be6514ac99142e845546434024830450221008a830b1ee71835ad2a4c31001b49dc4e0fed6fb64968de90c94d2a046c7ca07902201a63bafb30b4492a344bea0ef820118e64503bbf4e9fa4a4b41e6697cc461367012103126b31ef1559c206cb2e44071e944cc06075bc6291c9c9461bf5ea2045758f55024830450221008bd85781519ebd1cdaa8266ffb3fc658e2c2c426a0836299419c5b0b75cdaa4602200f626b4f67a6f513584a7d3eb30443de417acc6b12996db08653596ad82e9658012103b547c68a31e3b76b35d9146b535294930a5171646a915a213d1bfe2ee16c5a3800000000" + }, + { + "txid": "053f581b81e25e470986d39b65684c7980f2ebcc9a024bd48ae3b8f9610910d3", + "version": 1, + "vin": [ + { + "txid": "d52996ebc9fb16d7fca7cf1525d15e905418e5be8ea65bff0ddc356bdece7ae3", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1qfw0fqy69hquwcss23vfzehtwaxmyygr0qs5hhl" + ], + "value": "196440000" + } + ], + "vout": [ + { + "value": "5244000", + "n": 0, + "hex": "001453e45e03d888aaef8c94fc144859448ddd4ed36d", + "addresses": [ + "via1q20j9uq7c3z4wlry5ls2ysk2y3hw5a5mdv709m8" + ] + }, + { + "value": "191173400", + "n": 1, + "spent": true, + "hex": "00142a5e9b9be782066ca3ed4e0596d3e95a6ae31238", + "addresses": [ + "via1q9f0fhxl8sgrxegldfczed5lftf4wxy3c085ch2" + ] + } + ], + "blockHash": "7149d870281bdba85945809863e34ce554a5d8c4d1f87bca8ef309430662a0a1", + "blockHeight": 6294326, + "confirmations": 1321523, + "blockTime": 1557598695, + "value": "196417400", + "valueIn": "196440000", + "fees": "22600", + "hex": "01000000000101e37acede6b35dc0dff5ba68ebee51854905ed12515cfa7fcd716fbc9eb9629d50000000000feffffff02600450000000000016001453e45e03d888aaef8c94fc144859448ddd4ed36d1813650b000000001600142a5e9b9be782066ca3ed4e0596d3e95a6ae312380247304402202626ce59799ce75e290cd16bb496a2e17a2a5c1670ef98e831cbcfe2ceb52cb502204237d5d75f759a74f81a8c575fcc1c9475059f578207a092ea2693c147c49b5a012102b9a28dacc8e9fae53c21becae0584357fab36731c90b295a819d859e4b7f6b7f00000000" + }, + { + "txid": "d52996ebc9fb16d7fca7cf1525d15e905418e5be8ea65bff0ddc356bdece7ae3", + "version": 1, + "vin": [ + { + "txid": "a0a853771d179d8470088256c619a84a931731979249c820d7c885213f499ec3", + "sequence": 4294967290, + "n": 0, + "addresses": [ + "via1q20j9uq7c3z4wlry5ls2ysk2y3hw5a5mdv709m8" + ], + "value": "200355200" + } + ], + "vout": [ + { + "value": "196440000", + "n": 0, + "spent": true, + "hex": "00144b9e901345b838ec420a8b122cdd6ee9b642206f", + "addresses": [ + "via1qfw0fqy69hquwcss23vfzehtwaxmyygr0qs5hhl" + ] + }, + { + "value": "3892600", + "n": 1, + "hex": "001427b6fa8e73f50a22d04072e591a2e7d541360469", + "addresses": [ + "via1qy7m04rnn759z95zqwtjergh864qnvprf7v7xcy" + ] + } + ], + "blockHash": "68ff8a072d6ddec6561194b33cd3a341cdc1a569fe161f5f69ed0703e78fd38a", + "blockHeight": 6294078, + "confirmations": 1321771, + "blockTime": 1557592523, + "value": "200332600", + "valueIn": "200355200", + "fees": "22600", + "hex": "01000000000101c39e493f2185c8d720c84992973117934aa819c656820870849d171d7753a8a00000000000faffffff02c06fb50b000000001600144b9e901345b838ec420a8b122cdd6ee9b642206f78653b000000000016001427b6fa8e73f50a22d04072e591a2e7d54136046902473044022045b9d5abbcfbff0c172908971fbd1fc96739e7013b68f964613627324103cb03022012c0b2dafc71660111e5edd34e37e394ad7a6634f1bdbeb62646e6bafd4dcb9401210315e1885595004e10a3be41030ca0ae3ad11bad0d290840a8a417e71f46b16d5000000000" + }, + { + "txid": "a0a853771d179d8470088256c619a84a931731979249c820d7c885213f499ec3", + "version": 1, + "vin": [ + { + "txid": "a807cc96408d93ba5537de360f68860a3c17329173501c33f6ae5f24ed390cf9", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1qfw0fqy69hquwcss23vfzehtwaxmyygr0qs5hhl" + ], + "value": "200377800" + } + ], + "vout": [ + { + "value": "200355200", + "n": 0, + "spent": true, + "hex": "001453e45e03d888aaef8c94fc144859448ddd4ed36d", + "addresses": [ + "via1q20j9uq7c3z4wlry5ls2ysk2y3hw5a5mdv709m8" + ] + } + ], + "blockHash": "483c4a4ecccfe5bd940f3ad22c78ee6462709642cbc2cc82b9bcfd682361b8e4", + "blockHeight": 6294075, + "confirmations": 1321774, + "blockTime": 1557592449, + "value": "200355200", + "valueIn": "200377800", + "fees": "22600", + "hex": "01000000000101f90c39ed245faef6331c50739132173c0a86680f36de3755ba938d4096cc07a80100000000feffffff01802df10b0000000016001453e45e03d888aaef8c94fc144859448ddd4ed36d0247304402202e641fbe3f03aab0fa2e2abddd284e038b7e81f5ac496bdf437eeb8893f6c92b02200c1d34a9a96af0baeff4fbb845ce9f0eae0f53503e63cf72b058913efb430620012102b9a28dacc8e9fae53c21becae0584357fab36731c90b295a819d859e4b7f6b7f00000000" + }, + { + "txid": "a807cc96408d93ba5537de360f68860a3c17329173501c33f6ae5f24ed390cf9", + "version": 1, + "vin": [ + { + "txid": "d51ef863702bf5152900e1ea78f9d27df22904cab7aa004f7033966deccbbd06", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1q7hnlgt3g8x8h2zyqjp557l0g24ryxkl9w0yvge" + ], + "value": "203988900" + } + ], + "vout": [ + { + "value": "3588500", + "n": 0, + "spent": true, + "hex": "00142677d00e44348ed8723c01fb8e12ced5db27e7f8", + "addresses": [ + "via1qyemaqrjyxj8dsu3uq8acuykw6hdj0elcueevju" + ] + }, + { + "value": "200377800", + "n": 1, + "spent": true, + "hex": "00144b9e901345b838ec420a8b122cdd6ee9b642206f", + "addresses": [ + "via1qfw0fqy69hquwcss23vfzehtwaxmyygr0qs5hhl" + ] + } + ], + "blockHash": "262dd8b5bd9006cac101676b69aaa5686626e98c782c2bb3daed97a3b8730ff1", + "blockHeight": 6289948, + "confirmations": 1325901, + "blockTime": 1557493487, + "value": "203966300", + "valueIn": "203988900", + "fees": "22600", + "hex": "0100000000010106bdcbec6d9633704f00aab7ca0429f27dd2f978eae1002915f52b7063f81ed50100000000feffffff0294c13600000000001600142677d00e44348ed8723c01fb8e12ced5db27e7f8c885f10b000000001600144b9e901345b838ec420a8b122cdd6ee9b642206f02483045022100e58997e0530db0a1947e9b939bccde4a9d7dc92ed5b67c2145064efcf795749a02200741b399a19366267b6738255794b19c668d3b4f094a968e45c9d08f485672c401210244dd18297b477142e681bc4cf5b5c9dde1e8bd22b0c246d56573cdef649a993000000000" + }, + { + "txid": "d51ef863702bf5152900e1ea78f9d27df22904cab7aa004f7033966deccbbd06", + "version": 1, + "vin": [ + { + "txid": "adac9e71a907cca1761ef2169130c1eae9dd67b5396ea4c7cdbfa9f47c789e05", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1qwyddvzw5rak3v4qp7sxn703lnvevr976jg8lc7" + ], + "value": "205000000" + } + ], + "vout": [ + { + "value": "988500", + "n": 0, + "hex": "001453e45e03d888aaef8c94fc144859448ddd4ed36d", + "addresses": [ + "via1q20j9uq7c3z4wlry5ls2ysk2y3hw5a5mdv709m8" + ] + }, + { + "value": "203988900", + "n": 1, + "spent": true, + "hex": "0014f5e7f42e28398f75088090694f7de85546435be5", + "addresses": [ + "via1q7hnlgt3g8x8h2zyqjp557l0g24ryxkl9w0yvge" + ] + } + ], + "blockHash": "603ebc256ee81f518d3ce3405408f79036956f0e0daf68184c4ad752848fec71", + "blockHeight": 6289936, + "confirmations": 1325913, + "blockTime": 1557493227, + "value": "204977400", + "valueIn": "205000000", + "fees": "22600", + "hex": "01000000000101059e787cf4a9bfcdc7a46e39b567dde9eac1309116f21e76a1cc07a9719eacad0000000000feffffff0254150f000000000016001453e45e03d888aaef8c94fc144859448ddd4ed36da49f280c00000000160014f5e7f42e28398f75088090694f7de85546435be502473044022059795753c9a3997c60fd6dfd1ee8ef58a404e8e193c4b3404d2003d5c8783cc102205ebbb9b615e39c99c74a2858b90ab1e206d31cfb3754bd3b80d095811770c11c01210344786208c833b70374d4dd49d151d9ff3454b401e6577757e2cf72b256a1979400000000" + }, + { + "txid": "adac9e71a907cca1761ef2169130c1eae9dd67b5396ea4c7cdbfa9f47c789e05", + "version": 1, + "vin": [ + { + "txid": "f5bc1231dc7337d7cdb9eb59d0496fab61378cb2b78563e372edb97f7a3581e5", + "sequence": 4294967293, + "n": 0, + "addresses": [ + "via1q20j9uq7c3z4wlry5ls2ysk2y3hw5a5mdv709m8" + ], + "value": "207854800" + } + ], + "vout": [ + { + "value": "205000000", + "n": 0, + "spent": true, + "hex": "0014711ad609d41f6d165401f40d3f3e3f9b32c197da", + "addresses": [ + "via1qwyddvzw5rak3v4qp7sxn703lnvevr976jg8lc7" + ] + }, + { + "value": "2832200", + "n": 1, + "hex": "001419f6fdd1a3bab54d58fe697d1a4f36c7393a2f0a", + "addresses": [ + "via1qr8m0m5drh2656k87d9735nekcuun5tc239kzyv" + ] + } + ], + "blockHash": "40ed688764298e87b7ee5cb47c163aa1f9883b6329b4e68e69043fe67b480cc2", + "blockHeight": 6289612, + "confirmations": 1326237, + "blockTime": 1557485360, + "value": "207832200", + "valueIn": "207854800", + "fees": "22600", + "hex": "01000000000101e581357a7fb9ed72e36385b7b28c3761ab6f49d059ebb9cdd73773dc3112bcf50000000000fdffffff02400d380c00000000160014711ad609d41f6d165401f40d3f3e3f9b32c197da48372b000000000016001419f6fdd1a3bab54d58fe697d1a4f36c7393a2f0a02473044022068803fbd0b8c77dd05cc075e51ebdab96c30d68cabbc29fd5ed78298e61559480220078686b023c0d3d684c1ed1fd7f5bbc0f92fb48288b591346cdbd6baef5ef9c001210315e1885595004e10a3be41030ca0ae3ad11bad0d290840a8a417e71f46b16d5000000000" + }, + { + "txid": "f5bc1231dc7337d7cdb9eb59d0496fab61378cb2b78563e372edb97f7a3581e5", + "version": 1, + "vin": [ + { + "txid": "28595f9ffe04d875043a88fd6fc4b7a48a27a3e2cb82834d610b40677a686466", + "vout": 1, + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1qzx37ahs0ua840ulkrdgh3mt4euzme25zu5j42k" + ], + "value": "207877400" + } + ], + "vout": [ + { + "value": "207854800", + "n": 0, + "spent": true, + "hex": "001453e45e03d888aaef8c94fc144859448ddd4ed36d", + "addresses": [ + "via1q20j9uq7c3z4wlry5ls2ysk2y3hw5a5mdv709m8" + ] + } + ], + "blockHash": "a6fe317eda080d0b3f9a8c21f277b3b83ff6b8ec11742bd6de1dd5c1a9adbaa9", + "blockHeight": 6289598, + "confirmations": 1326251, + "blockTime": 1557485034, + "value": "207854800", + "valueIn": "207877400", + "fees": "22600", + "hex": "010000000001016664687a67400b614d8382cbe2a3278aa4b7c46ffd883a0475d804fe9f5f59280100000000feffffff01d09c630c0000000016001453e45e03d888aaef8c94fc144859448ddd4ed36d02483045022100cf778eb2fe629653d565e3238dc8da5f0172b6320dadfce30808d43370aad44d02203b36044c1051aded9631edc737043aad28b6c8ce2991e62ffe2492dfb39dea6001210392e7c7848932c0c8d7c726fdf955c40148f9ec6166d1fff3bbee835c6448fe2400000000" + }, + { + "txid": "28595f9ffe04d875043a88fd6fc4b7a48a27a3e2cb82834d610b40677a686466", + "version": 1, + "vin": [ + { + "txid": "34bc3cc597340945e4cae362684605f211a062c47d092db3bd7b9cb0a3365871", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ], + "value": "210000000" + } + ], + "vout": [ + { + "value": "2100000", + "n": 0, + "hex": "001453e45e03d888aaef8c94fc144859448ddd4ed36d", + "addresses": [ + "via1q20j9uq7c3z4wlry5ls2ysk2y3hw5a5mdv709m8" + ] + }, + { + "value": "207877400", + "n": 1, + "spent": true, + "hex": "001411a3eede0fe74f57f3f61b5178ed75cf05bcaa82", + "addresses": [ + "via1qzx37ahs0ua840ulkrdgh3mt4euzme25zu5j42k" + ] + } + ], + "blockHash": "bc4ce65e505e62a2924fcbcd475c28f52fdf32fc92c76385277ce970ed51c52d", + "blockHeight": 6289161, + "confirmations": 1326688, + "blockTime": 1557474602, + "value": "209977400", + "valueIn": "210000000", + "fees": "22600", + "hex": "01000000000101715836a3b09c7bbdb32d097dc462a011f205466862e3cae445093497c53cbc340000000000feffffff02200b20000000000016001453e45e03d888aaef8c94fc144859448ddd4ed36d18f5630c0000000016001411a3eede0fe74f57f3f61b5178ed75cf05bcaa8202483045022100e2e680715b7df28e351786e05bcebe480fbb140a571374f47fece1a75cdfc47a02207830a798ed4cf273444305c9bffb9d4437322c3af170a0788cdc5a73310ee8fe012102b5e09e1dbb76a0eeebea67bf80069ce41c26c81d0f06d1dd42e712ebf55de4bc00000000" + }, + { + "txid": "34bc3cc597340945e4cae362684605f211a062c47d092db3bd7b9cb0a3365871", + "version": 1, + "vin": [ + { + "txid": "08fb8ccb9fd84b77618ac517246823482d483f1e8071e781dcfc750fc6a9062a", + "vout": 1, + "n": 0, + "addresses": [ + "via1qtphs73pytedrd6dxs2h695d0f5jtjxns95zykv" + ], + "value": "500000000" + } + ], + "vout": [ + { + "value": "210000000", + "n": 0, + "spent": true, + "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", + "addresses": [ + "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" + ] + }, + { + "value": "289977400", + "n": 1, + "spent": true, + "hex": "0014dd01ab573b2f4ca9aac3f89d101263be78896af4", + "addresses": [ + "via1qm5q6k4em9ax2n2krlzw3qynrheugj6h5vffra6" + ] + } + ], + "blockHash": "78dd08436d7baf989cafd3ef81905f5ca202ad0b971ec3040c93445b52ae626b", + "blockHeight": 6274638, + "confirmations": 1341211, + "blockTime": 1557125330, + "value": "499977400", + "valueIn": "500000000", + "fees": "22600", + "hex": "010000000001012a06a9c60f75fcdc81e771801e3f482d4823682417c58a61774bd89fcb8cfb08010000000000000000028058840c000000001600143379fd40508ec2101e11c3519a31615de6e7b67338b4481100000000160014dd01ab573b2f4ca9aac3f89d101263be78896af402473044022004607ace08c398815bb7218d514facd12444d0e740576b135d201d50c857b1ad0220010f726c44099352693a90c25939ef046006ef157763f0133a4b79b81d1010bd012103a8cfde9f4308008b74eb5649a5660c5f3657a892e4e971efbe5a6b9894a118e900000000" + } + ], + "usedTokens": 40, + "tokens": [ + { + "type": "XPUBAddress", + "name": "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp", + "path": "m/84'/14'/0'/0/0", + "transfers": 8, + "decimals": 8, + "balance": "740523040", + "totalReceived": "9544362154", + "totalSent": "8803839114" + } + ] +} diff --git a/mock/ext-api-data/waves-api_transactions_address_3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD_limit_25.json b/mock/ext-api-data/waves-api_transactions_address_3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD_limit_25.json new file mode 100644 index 000000000..a1e4d98ca --- /dev/null +++ b/mock/ext-api-data/waves-api_transactions_address_3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD_limit_25.json @@ -0,0 +1,183 @@ +[ + [ + { + "senderPublicKey": "2UstBx1nMYQ2mPeaJi6tv9oUFCUHLvU1G7nS8Leazsbw", + "amount": 369133368000, + "signature": "5Hw5SW7C1EK8hE2YKawFCAWcJoB1Z5NSZFkA65bS3PcDY9w2fi7etPCJDamK2WNb14RWa3BykdT5yFd64SxodjeQ", + "fee": 100000, + "type": 4, + "version": 1, + "attachment": "", + "sender": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "feeAssetId": null, + "proofs": [ + "5Hw5SW7C1EK8hE2YKawFCAWcJoB1Z5NSZFkA65bS3PcDY9w2fi7etPCJDamK2WNb14RWa3BykdT5yFd64SxodjeQ" + ], + "assetId": null, + "recipient": "3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", + "feeAsset": null, + "id": "23JGFzBh65fzZArK6KSeRqjjBG5WnQshJJkUv53hCE1E", + "timestamp": 1582527770493, + "height": 1943922 + }, + { + "senderPublicKey": "3uT3a9ceebFf6vEa5DmedD5pK6xa1GY7PnvhWPMVyqxC", + "amount": 369133468000, + "signature": "3Nrz47KpD3U39Nf7Los23MDoukqXCrCJun1BqnUgjpy9iZLfXc163dTrz4wVvURC2yiULsNYDYA2pxTPGWpBotc5", + "fee": 100000, + "type": 4, + "version": 1, + "attachment": "Paribu", + "sender": "3PHYYqBA6ZfBsoGsrXP8r7ZptLXYdGDt1Cm", + "feeAssetId": null, + "proofs": [ + "3Nrz47KpD3U39Nf7Los23MDoukqXCrCJun1BqnUgjpy9iZLfXc163dTrz4wVvURC2yiULsNYDYA2pxTPGWpBotc5" + ], + "assetId": null, + "recipient": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "feeAsset": null, + "id": "1456haw7zSTKDmVSbY1njrYdskX7xKbv241c5WJjWhCu", + "timestamp": 1582527244669, + "height": 1943911 + }, + { + "senderPublicKey": "2UstBx1nMYQ2mPeaJi6tv9oUFCUHLvU1G7nS8Leazsbw", + "amount": 698850000, + "signature": "3NzepUFYyrCPaK6GgVZW47hxQpMTaA3ETvYYA2QVGvbGaQWhxhuWW6nmED9SdmwNqq1tksWt2BVJM8B4NAGtPUiy", + "fee": 100000, + "type": 4, + "version": 1, + "attachment": "", + "sender": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "feeAssetId": null, + "proofs": [ + "3NzepUFYyrCPaK6GgVZW47hxQpMTaA3ETvYYA2QVGvbGaQWhxhuWW6nmED9SdmwNqq1tksWt2BVJM8B4NAGtPUiy" + ], + "assetId": null, + "recipient": "3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", + "feeAsset": null, + "id": "E9iL8JuspsUvf1umcWSir62wU9jsmUUU1ENbLPHJBu8z", + "timestamp": 1582257653562, + "height": 1939356 + }, + { + "senderPublicKey": "3uT3a9ceebFf6vEa5DmedD5pK6xa1GY7PnvhWPMVyqxC", + "amount": 698950000, + "signature": "5bW75Bk5oVzr9jNWa5sPCGJn5jC7zA4Z66kLGVgHznAXa54217HHMdto6yNEQfq7Qy3jh1oBE9EbnSzKP7sSCGNd", + "fee": 100000, + "type": 4, + "version": 1, + "attachment": "Paribu", + "sender": "3PHYYqBA6ZfBsoGsrXP8r7ZptLXYdGDt1Cm", + "feeAssetId": null, + "proofs": [ + "5bW75Bk5oVzr9jNWa5sPCGJn5jC7zA4Z66kLGVgHznAXa54217HHMdto6yNEQfq7Qy3jh1oBE9EbnSzKP7sSCGNd" + ], + "assetId": null, + "recipient": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "feeAsset": null, + "id": "AAkVWcPTPPAUxE86sK1Buvb4CzurLr8x3FLFR5U85cQz", + "timestamp": 1582256644982, + "height": 1939340 + }, + { + "senderPublicKey": "2UstBx1nMYQ2mPeaJi6tv9oUFCUHLvU1G7nS8Leazsbw", + "amount": 38291930000, + "signature": "4whJCn9BsVQfEsETHhAu9brPoPRCwHXnVz7mA7vA6fAY7Lth26brP6QmZdgsxHcw7Vr9n7WeRooBE2PBGbh2EduK", + "fee": 100000, + "type": 4, + "version": 1, + "attachment": "", + "sender": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "feeAssetId": null, + "proofs": [ + "4whJCn9BsVQfEsETHhAu9brPoPRCwHXnVz7mA7vA6fAY7Lth26brP6QmZdgsxHcw7Vr9n7WeRooBE2PBGbh2EduK" + ], + "assetId": null, + "recipient": "3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", + "feeAsset": null, + "id": "ALSHobQKkMkeeUySE1yK9s5FMLXmLYgSJ7b3jSCtGctr", + "timestamp": 1579504858670, + "height": 1892719 + }, + { + "senderPublicKey": "2otUJmrNBWHahdA9jUeBTLnW7g43hVfVKNyws9f1LFtR", + "amount": 38292030000, + "signature": "2oMvzrnMZzWX7Ne2McY8Zi3QZAHFMeomz4DiWGZLSRbMGC5W6h3aqDpo65TRrutLQ6p6UyWznxA67fPg3u2C8mo8", + "fee": 100000, + "type": 4, + "version": 1, + "attachment": "Paribu", + "sender": "3PEDjPSkKrMtaaJJLGfL849Fg39TSZ7WGzY", + "feeAssetId": null, + "proofs": [ + "2oMvzrnMZzWX7Ne2McY8Zi3QZAHFMeomz4DiWGZLSRbMGC5W6h3aqDpo65TRrutLQ6p6UyWznxA67fPg3u2C8mo8" + ], + "assetId": null, + "recipient": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "feeAsset": null, + "id": "EvTk5zX9vQTDD9qKPuGGHjAUzcbkeRjemWMqioubUNUV", + "timestamp": 1579503724349, + "height": 1892702 + }, + { + "senderPublicKey": "5LNhM4E1AkNcB4j5cYPVi4dcu6puMU9v83iKDt8w8V54", + "amount": 550000000, + "fee": 100000, + "type": 4, + "version": 2, + "attachment": "3cdoipiKbLBweYBgvay72xUe8WjA24XCcyyfxPmJimVgtvSUfecpFhFe2GdotgUwNhHKT6dqAHcp8FeESFpqPv3RoxcSR62Bv3LG", + "sender": "3PPqRC9iYTcgz16RLjpMJhevxStDJGcmgFr", + "feeAssetId": null, + "proofs": [ + "2r52JRLPFmrAnLnrYfdmCit6cmquDrW7GpRDVXnSqk8gYwKwuGrWdj2r9kS9MNHXnTVpvPFqCKDFmJjTuaqEubM6" + ], + "assetId": "8Yw4QmskrQauQeNjgh2fTQ4swmkNm85GTQzdHEf6QdUU", + "recipient": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "feeAsset": null, + "id": "FTTrC3xr3YAk8MeehkS4LbGLnzsYcmaJMfLdyezAhWte", + "timestamp": 1579189633267, + "height": 1887377 + }, + { + "senderPublicKey": "2UstBx1nMYQ2mPeaJi6tv9oUFCUHLvU1G7nS8Leazsbw", + "amount": 55628399500, + "signature": "5gsoW82BqH83gUWqTGUCL6cAdGeNnycVBvSKVJRGopaLbnHXVTBUdYQgL2zwjudHQ7DnYUyrAauDTLBFa91Pj97U", + "fee": 100000, + "type": 4, + "version": 1, + "attachment": "", + "sender": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "feeAssetId": null, + "proofs": [ + "5gsoW82BqH83gUWqTGUCL6cAdGeNnycVBvSKVJRGopaLbnHXVTBUdYQgL2zwjudHQ7DnYUyrAauDTLBFa91Pj97U" + ], + "assetId": null, + "recipient": "3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", + "feeAsset": null, + "id": "8CKBhfKiJQENKyjbySzaTshgcHd6tNccHu6oxQKXihBc", + "timestamp": 1579171201233, + "height": 1887049 + }, + { + "senderPublicKey": "2otUJmrNBWHahdA9jUeBTLnW7g43hVfVKNyws9f1LFtR", + "amount": 55628499500, + "signature": "QiDKpBkSECdxmRaBknCthgrjU3NXgWXWxNmHzv3bKLHCTFxg3hTe2Bnpv1UJFk1F9b9FJLXZzGm35C5fdXTXvxM", + "fee": 100000, + "type": 4, + "version": 1, + "attachment": "Paribu", + "sender": "3PEDjPSkKrMtaaJJLGfL849Fg39TSZ7WGzY", + "feeAssetId": null, + "proofs": [ + "QiDKpBkSECdxmRaBknCthgrjU3NXgWXWxNmHzv3bKLHCTFxg3hTe2Bnpv1UJFk1F9b9FJLXZzGm35C5fdXTXvxM" + ], + "assetId": null, + "recipient": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", + "feeAsset": null, + "id": "BNDCzVPK2j65Aunq7SavSNMWbn1N8iNxCwi4Hib1C2qt", + "timestamp": 1579063084088, + "height": 1885216 + } + ] +] \ No newline at end of file diff --git a/mock/ext-api-data/zcash-api_v2_address_t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX__details_txs.json b/mock/ext-api-data/zcash-api_v2_address_t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX__details_txs.json new file mode 100644 index 000000000..7a19d4c21 --- /dev/null +++ b/mock/ext-api-data/zcash-api_v2_address_t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":206,"itemsOnPage":10,"address":"t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX","balance":"12344656","totalReceived":"109663825939","totalSent":"109651481283","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2058,"transactions":[{"txid":"a81cae38d27445ad22dad26b60e10753e7b03aa6a0f58578d554f7702bf7f440","version":4,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"032bcb0c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b"}],"vout":[{"value":"0","n":0,"hex":"76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac","addresses":["t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX"],"isAddress":true},{"value":"125000000","n":1,"hex":"a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87","addresses":["t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME"],"isAddress":true},{"value":"6250000","n":2,"spent":true,"hex":"76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac","addresses":["t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv"],"isAddress":true},{"value":"493750000","n":3,"spent":true,"hex":"76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac","addresses":["t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2"],"isAddress":true}],"blockHash":"000000000194e6f92ba9ee20ed1ca0396858aca572898742e8920fa0ab0ae17e","blockHeight":838443,"confirmations":510,"blockTime":1590031334,"value":"625000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff50032bcb0c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000"},{"txid":"5af8584d87cbe7bf286def0325b23b42b6ebc380d4ebb4691e0c9e4b12ab13c2","version":4,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"031acb0c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b"}],"vout":[{"value":"0","n":0,"hex":"76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac","addresses":["t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX"],"isAddress":true},{"value":"125000000","n":1,"hex":"a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87","addresses":["t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME"],"isAddress":true},{"value":"6250000","n":2,"spent":true,"hex":"76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac","addresses":["t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv"],"isAddress":true},{"value":"493750000","n":3,"spent":true,"hex":"76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac","addresses":["t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2"],"isAddress":true}],"blockHash":"0000000000d49a802d7ee6dd713cd8eddbf8fb308eda8ec96deec7b0d1140cc5","blockHeight":838426,"confirmations":527,"blockTime":1590030285,"value":"625000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff50031acb0c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000"},{"txid":"e81a55bf227c8589bf22452ee0c958b491865917a09c56afb614d12db77c0697","version":4,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"03d7ca0c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b"}],"vout":[{"value":"0","n":0,"hex":"76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac","addresses":["t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX"],"isAddress":true},{"value":"125000000","n":1,"hex":"a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87","addresses":["t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME"],"isAddress":true},{"value":"6250000","n":2,"spent":true,"hex":"76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac","addresses":["t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv"],"isAddress":true},{"value":"493750000","n":3,"spent":true,"hex":"76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac","addresses":["t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2"],"isAddress":true}],"blockHash":"00000000021580cfb80cc7ddfa6d3b8e585a8612eb11d60d66cd6d6be43832f2","blockHeight":838359,"confirmations":594,"blockTime":1590024601,"value":"625000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff5003d7ca0c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000"},{"txid":"4ec0d7d0a12c5eb7eaeb13907c0e059d07f6800115344df3ad9c6be3fe16f773","version":4,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"03cdc90c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b"}],"vout":[{"value":"0","n":0,"hex":"76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac","addresses":["t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX"],"isAddress":true},{"value":"125000000","n":1,"hex":"a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87","addresses":["t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME"],"isAddress":true},{"value":"6250000","n":2,"spent":true,"hex":"76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac","addresses":["t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv"],"isAddress":true},{"value":"493750000","n":3,"spent":true,"hex":"76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac","addresses":["t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2"],"isAddress":true}],"blockHash":"0000000000cc015ff69beb89862035a623cb63c83a5b037066157067829fc077","blockHeight":838093,"confirmations":860,"blockTime":1590004400,"value":"625000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff5003cdc90c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000"},{"txid":"1fcd9251ec885b1ca028f702317ddd651b101a43d8516025f450518b0a388a8c","version":4,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"03acc90c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b"}],"vout":[{"value":"0","n":0,"hex":"76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac","addresses":["t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX"],"isAddress":true},{"value":"125000000","n":1,"hex":"a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87","addresses":["t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME"],"isAddress":true},{"value":"6250000","n":2,"spent":true,"hex":"76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac","addresses":["t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv"],"isAddress":true},{"value":"493750000","n":3,"spent":true,"hex":"76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac","addresses":["t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2"],"isAddress":true}],"blockHash":"000000000285693849986f6d070445fe86ca3b2ac60644e7d7921b8ec35408f9","blockHeight":838060,"confirmations":893,"blockTime":1590001994,"value":"625000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff5003acc90c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000"},{"txid":"4f5990dfd9ab8776c2e3bed233914e5cae004ca5ecaca0c257ea41446e55f598","version":4,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"03aac90c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b"}],"vout":[{"value":"0","n":0,"hex":"76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac","addresses":["t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX"],"isAddress":true},{"value":"125000000","n":1,"hex":"a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87","addresses":["t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME"],"isAddress":true},{"value":"6250000","n":2,"spent":true,"hex":"76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac","addresses":["t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv"],"isAddress":true},{"value":"493750000","n":3,"spent":true,"hex":"76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac","addresses":["t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2"],"isAddress":true}],"blockHash":"0000000002549398c6f738b370072dd776c5ecc68bb61b901ead2be118d08594","blockHeight":838058,"confirmations":895,"blockTime":1590001966,"value":"625000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff5003aac90c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000"},{"txid":"c2ff1c3389be5c112f3586c879a12e5e4058d570782c830efbf201adf21decd5","version":4,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"03a1c90c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b"}],"vout":[{"value":"0","n":0,"hex":"76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac","addresses":["t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX"],"isAddress":true},{"value":"125000000","n":1,"hex":"a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87","addresses":["t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME"],"isAddress":true},{"value":"6250000","n":2,"spent":true,"hex":"76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac","addresses":["t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv"],"isAddress":true},{"value":"493750000","n":3,"spent":true,"hex":"76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac","addresses":["t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2"],"isAddress":true}],"blockHash":"00000000007f764e8d2617be42bf862c41848f66e41e2c1f874f5f19473bad0e","blockHeight":838049,"confirmations":904,"blockTime":1590001194,"value":"625000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff5003a1c90c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000"},{"txid":"584593946525366bda4a42cb52a7b78dbd13b8d3ca1dbd579c7d5abd13674862","version":4,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"039fc70c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b"}],"vout":[{"value":"0","n":0,"hex":"76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac","addresses":["t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX"],"isAddress":true},{"value":"125000000","n":1,"hex":"a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87","addresses":["t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME"],"isAddress":true},{"value":"6250000","n":2,"spent":true,"hex":"76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac","addresses":["t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv"],"isAddress":true},{"value":"493750000","n":3,"spent":true,"hex":"76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac","addresses":["t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2"],"isAddress":true}],"blockHash":"0000000002514210f04068274b6ef055abf89acc4cd4c9365aa45bced87f0a36","blockHeight":837535,"confirmations":1418,"blockTime":1589962474,"value":"625000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff50039fc70c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000"},{"txid":"f4719e5b969917fd036160472cb0f3a4897171e582bb9469850a3a973256e213","version":4,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"0364c70c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b"}],"vout":[{"value":"0","n":0,"hex":"76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac","addresses":["t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX"],"isAddress":true},{"value":"125000000","n":1,"hex":"a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87","addresses":["t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME"],"isAddress":true},{"value":"6250000","n":2,"spent":true,"hex":"76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac","addresses":["t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv"],"isAddress":true},{"value":"493750000","n":3,"spent":true,"hex":"76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac","addresses":["t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2"],"isAddress":true}],"blockHash":"00000000002024dc913916a2fc57aad17251a3945a3d0ee10b70000d48cdac3d","blockHeight":837476,"confirmations":1477,"blockTime":1589958268,"value":"625000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff500364c70c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000"},{"txid":"19d3d66ee6ea94668fbe35c1b3a6d2b7406dae530d3ddbc83aa244b0f3b911f1","version":4,"vin":[{"sequence":4294967295,"n":0,"isAddress":false,"coinbase":"031dc70c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b"}],"vout":[{"value":"0","n":0,"hex":"76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac","addresses":["t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX"],"isAddress":true},{"value":"125000000","n":1,"hex":"a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87","addresses":["t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME"],"isAddress":true},{"value":"6250000","n":2,"spent":true,"hex":"76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac","addresses":["t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv"],"isAddress":true},{"value":"493750000","n":3,"spent":true,"hex":"76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac","addresses":["t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2"],"isAddress":true}],"blockHash":"00000000011800bb8eebdc5dda838753c18c886a9867e86c9424ba29ddcd2593","blockHeight":837405,"confirmations":1548,"blockTime":1589953090,"value":"625000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff50031dc70c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914accba16ec3b9fa60ca3143419c81e9fc4217d05a87105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000"}]} diff --git a/mock/ext-api-data/zcash-api_v2_xpub_xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS__details_txs.json b/mock/ext-api-data/zcash-api_v2_xpub_xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS__details_txs.json new file mode 100644 index 000000000..06a877601 --- /dev/null +++ b/mock/ext-api-data/zcash-api_v2_xpub_xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS__details_txs.json @@ -0,0 +1,1770 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS", + "balance": "836466", + "totalReceived": "15140484", + "totalSent": "14304018", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 39, + "transactions": [ + { + "txid": "bdb6ae8ea9f5f37b304b382a2bc92208c2408b2d79cbc60777e27b618c70ca66", + "version": 4, + "vin": [ + { + "txid": "f2438a93039faf08d39bd3df1f7b5f19a2c29ffe8753127e2956ab4461adab35", + "vout": 1, + "n": 0, + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true, + "value": "846466", + "hex": "473044022013f349ae165b1b96953081d47e588411387b7ecda4a7805d7f19dd369015c5ca022057313a41079ebf58e1ed35ad51425bf33011de475b55f5a085df7a9ab84a45e7012103fef9b9366755bd64a0579f1a5bfb92485c1f4ab33c53a1afb1899efa7e4782c1" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true + }, + { + "value": "736466", + "n": 1, + "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true + } + ], + "blockHash": "00000000011b874449ef84ae97f18834d733c00a385fa2d099350071ea5113fe", + "blockHeight": 788618, + "confirmations": 41022, + "blockTime": 1586276485, + "value": "836466", + "valueIn": "846466", + "fees": "10000", + "hex": "0400008085202f890135abad6144ab56297e125387fe9fc2a2195f7b1fdfd39bd308af9f03938a43f2010000006a473044022013f349ae165b1b96953081d47e588411387b7ecda4a7805d7f19dd369015c5ca022057313a41079ebf58e1ed35ad51425bf33011de475b55f5a085df7a9ab84a45e7012103fef9b9366755bd64a0579f1a5bfb92485c1f4ab33c53a1afb1899efa7e4782c10000000002a0860100000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988acd23c0b00000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac00000000000000000000000000000000000000" + }, + { + "txid": "f2438a93039faf08d39bd3df1f7b5f19a2c29ffe8753127e2956ab4461adab35", + "version": 4, + "vin": [ + { + "txid": "ee120b714991e6166b8ff4b6419cbfee657eca87675245ce8585787be3b07d70", + "vout": 1, + "n": 0, + "addresses": [ + "t1LJWoRDU14zUG4TGumHiobd9WBUjqLE5FU" + ], + "isAddress": true, + "value": "956466", + "hex": "483045022100d2ac7b2b17218572f3dc163063463be5143a8d3c2126b52eb73d49c9c4959da00220057417baaad53c168e82dd44a7f964759c7d584e0770b6284a8e1b0261f1c7e0012102a71eeea42aa1b4e30a409f9186bd88dc84dec5c404964f386c323f557ad268d9" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a914a2511fc37f67f3b5627affce89fb3f7bb186412888ac", + "addresses": [ + "t1Yfrf1dssDLmaMBsq2LFKWPbS5vH3nGpa2" + ], + "isAddress": true + }, + { + "value": "846466", + "n": 1, + "spent": true, + "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true + } + ], + "blockHash": "00000000005a238fecd893e55fba7072af65545fd43eaad63402c211cc172a61", + "blockHeight": 750255, + "confirmations": 79385, + "blockTime": 1583385097, + "value": "946466", + "valueIn": "956466", + "fees": "10000", + "hex": "0400008085202f8901707db0e37b788585ce45526787ca7e65eebf9c41b6f48f6b16e69149710b12ee010000006b483045022100d2ac7b2b17218572f3dc163063463be5143a8d3c2126b52eb73d49c9c4959da00220057417baaad53c168e82dd44a7f964759c7d584e0770b6284a8e1b0261f1c7e0012102a71eeea42aa1b4e30a409f9186bd88dc84dec5c404964f386c323f557ad268d90000000002a0860100000000001976a914a2511fc37f67f3b5627affce89fb3f7bb186412888ac82ea0c00000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac00000000000000000000000000000000000000" + }, + { + "txid": "ee120b714991e6166b8ff4b6419cbfee657eca87675245ce8585787be3b07d70", + "version": 4, + "vin": [ + { + "txid": "b49791a277ff137e37f9e163c8a5bc25492f741c275f9d36d5c0c713497c176c", + "vout": 1, + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1fuw3P3r5xbJXFqpaHUWb3TMz6xo9yPXEL" + ], + "isAddress": true, + "value": "996466", + "hex": "483045022100e7ddc39a2b976ee277d71f6130334084f1f21ef4f17cdd81514cf8af2181df1b02201c9a76a45b948c87940dc47525f1660d6c9c1e44ab22e4bcc16af0ce99c4c1890121031a03d4f4982aaa59d4087434907c9578fe77eadc73491b32f7373aaf9c17902e" + } + ], + "vout": [ + { + "value": "30000", + "n": 0, + "spent": true, + "hex": "76a914db49ca3524ee1e99aa097c6c9860ffcb5e5ed94a88ac", + "addresses": [ + "t1ds6PMeHUvAYtASPqCuEXzT1DsteXWwtTv" + ], + "isAddress": true + }, + { + "value": "956466", + "n": 1, + "spent": true, + "hex": "76a9141aa64e287339ad3fa041bc7a429bbcd57ac8a80088ac", + "addresses": [ + "t1LJWoRDU14zUG4TGumHiobd9WBUjqLE5FU" + ], + "isAddress": true + } + ], + "blockHash": "00000000008dcc62d679d7eaf05ac18403198f5f39b3e4e7f36869673855779b", + "blockHeight": 685806, + "confirmations": 143834, + "blockTime": 1578529212, + "value": "986466", + "valueIn": "996466", + "fees": "10000", + "hex": "0400008085202f89016c177c4913c7c0d5369d5f271c742f4925bca5c863e1f9377e13ff77a29197b4010000006b483045022100e7ddc39a2b976ee277d71f6130334084f1f21ef4f17cdd81514cf8af2181df1b02201c9a76a45b948c87940dc47525f1660d6c9c1e44ab22e4bcc16af0ce99c4c1890121031a03d4f4982aaa59d4087434907c9578fe77eadc73491b32f7373aaf9c17902efeffff7f0230750000000000001976a914db49ca3524ee1e99aa097c6c9860ffcb5e5ed94a88ac32980e00000000001976a9141aa64e287339ad3fa041bc7a429bbcd57ac8a80088ac00000000000000000000000000000000000000" + }, + { + "txid": "b49791a277ff137e37f9e163c8a5bc25492f741c275f9d36d5c0c713497c176c", + "version": 4, + "vin": [ + { + "txid": "4c3debb76fe8c9cb6fc4737de94212e91d4851945437d7852f44ad35439ce0fa", + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1WsYwrVPLHB4DzMrkAMCvY6h61RQPCJPkw" + ], + "isAddress": true, + "value": "1106466", + "hex": "473044022033c0e68231d1642e5028a480c6a47618975967b3a2f1f59d62d6d92d1b51d56102207a1e3385866e6a481a1f819946b07304660b72dbc437074da51caa089e965f3f012103a4065dbb978fe61c6ebb902a456af8f3240b17c5fb325cd2c05534a374a8ae21" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a914404d55f9d2bdeea3f1084b0aac4765384e3da4f488ac", + "addresses": [ + "t1Pjbu12gP3nTpjs36DRysrhwCFPLKhSKVk" + ], + "isAddress": true + }, + { + "value": "996466", + "n": 1, + "spent": true, + "hex": "76a914f1c37d2f80526621d728935b0ed624100f8493c388ac", + "addresses": [ + "t1fuw3P3r5xbJXFqpaHUWb3TMz6xo9yPXEL" + ], + "isAddress": true + } + ], + "blockHash": "000000000116d1e4a3b5d4264c98703e8be4486845fb3b286a25e167f84c0b0a", + "blockHeight": 685803, + "confirmations": 143837, + "blockTime": 1578529044, + "value": "1096466", + "valueIn": "1106466", + "fees": "10000", + "hex": "0400008085202f8901fae09c4335ad442f85d737549451481de91242e97d73c46fcbc9e86fb7eb3d4c000000006a473044022033c0e68231d1642e5028a480c6a47618975967b3a2f1f59d62d6d92d1b51d56102207a1e3385866e6a481a1f819946b07304660b72dbc437074da51caa089e965f3f012103a4065dbb978fe61c6ebb902a456af8f3240b17c5fb325cd2c05534a374a8ae21feffff7f02a0860100000000001976a914404d55f9d2bdeea3f1084b0aac4765384e3da4f488ac72340f00000000001976a914f1c37d2f80526621d728935b0ed624100f8493c388ac00000000000000000000000000000000000000" + }, + { + "txid": "4c3debb76fe8c9cb6fc4737de94212e91d4851945437d7852f44ad35439ce0fa", + "version": 4, + "vin": [ + { + "txid": "f5b76d963b246696b599d49302e401501c127d4f89cbcdf3cfd6e4d18f4cf659", + "vout": 1, + "n": 0, + "addresses": [ + "t1Q8ShbxcJ9pawxTx4ETFJMoQUSZrKCWzKr" + ], + "isAddress": true, + "value": "1116466", + "hex": "483045022100ec05147324a1a3720a1e5fb047d5323ba74c23b11b1f4cea25402d7972579b08022049624d957d303b05b0807f498376cc55dfdd0ae56df11a78dd77dd7555d9d690012103c55aec4f3d510a7fff0f2261ff3443bd93d516cfc4bcf02e9c4d246b4ff934f1" + } + ], + "vout": [ + { + "value": "1106466", + "n": 0, + "spent": true, + "hex": "76a9148e9714afd8e21ce9760bf49f6ac70ed32c0defa088ac", + "addresses": [ + "t1WsYwrVPLHB4DzMrkAMCvY6h61RQPCJPkw" + ], + "isAddress": true + } + ], + "blockHash": "000000000116d1e4a3b5d4264c98703e8be4486845fb3b286a25e167f84c0b0a", + "blockHeight": 685803, + "confirmations": 143837, + "blockTime": 1578529044, + "value": "1106466", + "valueIn": "1116466", + "fees": "10000", + "hex": "0400008085202f890159f64c8fd1e4d6cff3cdcb894f7d121c5001e40293d499b59666243b966db7f5010000006b483045022100ec05147324a1a3720a1e5fb047d5323ba74c23b11b1f4cea25402d7972579b08022049624d957d303b05b0807f498376cc55dfdd0ae56df11a78dd77dd7555d9d690012103c55aec4f3d510a7fff0f2261ff3443bd93d516cfc4bcf02e9c4d246b4ff934f1000000000122e21000000000001976a9148e9714afd8e21ce9760bf49f6ac70ed32c0defa088ac00000000000000000000000000000000000000" + }, + { + "txid": "f5b76d963b246696b599d49302e401501c127d4f89cbcdf3cfd6e4d18f4cf659", + "version": 4, + "vin": [ + { + "txid": "c3114bd9a0564c5609af3c4fe3f255760a2d996f85a2dfd871af85a429db909b", + "n": 0, + "addresses": [ + "t1dtiUUCSvFJYTm2XwdnJX2vUHeSxav6vhr" + ], + "isAddress": true, + "value": "1970000", + "hex": "473044022013e3683d230eee5fc307c283b39be0ff6e2f10d0eb3fa871d2c7ed7234be4fa60220360e34d9d5a6376a5d5596493d937817207e28166c720ae8c90b94834bc1f574012103507bb2cfbe1c83eaac54790b01159b505671d02241f7eb4ca756a7f906e3aaaa" + } + ], + "vout": [ + { + "value": "843534", + "n": 0, + "hex": "76a914a96bda74350574f56b30108b1cf7b13198aa74a188ac", + "addresses": [ + "t1ZKRQY3YnSSU3QvVPLw2qXHUvVNxpmaGjZ" + ], + "isAddress": true + }, + { + "value": "1116466", + "n": 1, + "spent": true, + "hex": "76a914449f39e1cf773b6ab8ca0a7b1f78b2b61ff887b388ac", + "addresses": [ + "t1Q8ShbxcJ9pawxTx4ETFJMoQUSZrKCWzKr" + ], + "isAddress": true + } + ], + "blockHash": "00000000004120e4e814488ef19d2bb67218c2c5ed9fcc607cd876f69e037aab", + "blockHeight": 661680, + "confirmations": 167960, + "blockTime": 1576711028, + "value": "1960000", + "valueIn": "1970000", + "fees": "10000", + "hex": "0400008085202f89019b90db29a485af71d8dfa2856f992d0a7655f2e34f3caf09564c56a0d94b11c3000000006a473044022013e3683d230eee5fc307c283b39be0ff6e2f10d0eb3fa871d2c7ed7234be4fa60220360e34d9d5a6376a5d5596493d937817207e28166c720ae8c90b94834bc1f574012103507bb2cfbe1c83eaac54790b01159b505671d02241f7eb4ca756a7f906e3aaaa00000000020edf0c00000000001976a914a96bda74350574f56b30108b1cf7b13198aa74a188ac32091100000000001976a914449f39e1cf773b6ab8ca0a7b1f78b2b61ff887b388ac00000000000000000000000000000000000000" + }, + { + "txid": "c3114bd9a0564c5609af3c4fe3f255760a2d996f85a2dfd871af85a429db909b", + "version": 4, + "vin": [ + { + "txid": "97537779723705ad8afe29cbfa352563ba1e9f637789f2650475420effce52a6", + "n": 0, + "addresses": [ + "t1VTcZ6fUY4Pctiwg3sRvr7Xtehd7t9oS8Y" + ], + "isAddress": true, + "value": "10000", + "hex": "47304402202f578d8ffedb4f18fa5de3d9d1397123259e6fdcae2c32b5545cf489a6d12236022056cac4deb4297d218cb8a8295779269c2d9047b521e15fe69fbd53c9b19176d0012103797ec761f2a682213010ba82e8d46e005f6421f683bc6ec733aaf303c193845d" + }, + { + "txid": "0ede27d0173c35fabede62340f1f86b29d3f834e06ed3cd5330bd2937d85a466", + "n": 1, + "addresses": [ + "t1S5DZbKS49jsGjdAGnVTG19kvqJCPmoaHK" + ], + "isAddress": true, + "value": "90000", + "hex": "48304502210093b597eebab4cc7c5acccd4946a3062ef703b6167dde3da43fece9663c021dac022039809adbd6b3f6bf52280ee01fd5b25eb9d5dfd983c264209aee0eb84ea9fe06012102c8dca1fa27e9f68a08511af6b60575670a039de832efd066f8c62a67d72df77b" + }, + { + "txid": "757eb1569c59609d0061a8fe7ec30a80a7103dded7f1b53ece4d70eb92d4a05c", + "n": 2, + "addresses": [ + "t1bkvrKbLLBT3vJFYt8SmoiyMBj7XmUGXf4" + ], + "isAddress": true, + "value": "100000", + "hex": "483045022100b4de7441499f166f1eeaba37c3cbbd19f186e90bf36edf87c3c0026099755ec50220644e76d23e67b706db3ec685f882bac62cd40176ec79b694b5f22cb73bf167ba012102422d0c15e66546d385bea2c732bc50ce4502c8d5189450201818a0ca375f5b05" + }, + { + "txid": "97f87c3ccaae4e136f89537ecbf69e3879003c4b3c2e3c63cb484e3f2aa8aee1", + "vout": 1, + "n": 3, + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true, + "value": "1780000", + "hex": "483045022100a463c890a3d714b5d0e11cbee5ac87bb81ec5104227828c292d553870ed82ac7022023f98c6637d3a1a663e2f0630d06827e9c2486510dcbc8aba7c8a4f2bb1bbf52012103fef9b9366755bd64a0579f1a5bfb92485c1f4ab33c53a1afb1899efa7e4782c1" + } + ], + "vout": [ + { + "value": "1970000", + "n": 0, + "spent": true, + "hex": "76a914db9854a96c6ad7158b58537717bd8a9ef711675888ac", + "addresses": [ + "t1dtiUUCSvFJYTm2XwdnJX2vUHeSxav6vhr" + ], + "isAddress": true + } + ], + "blockHash": "0000000001d4b7e021a788bd8e0c610337e7dc539473d203526ce97b11b61d93", + "blockHeight": 658381, + "confirmations": 171259, + "blockTime": 1576462351, + "value": "1970000", + "valueIn": "1980000", + "fees": "10000", + "hex": "0400008085202f8904a652ceff0e42750465f28977639f1eba632535facb29fe8aad05377279775397000000006a47304402202f578d8ffedb4f18fa5de3d9d1397123259e6fdcae2c32b5545cf489a6d12236022056cac4deb4297d218cb8a8295779269c2d9047b521e15fe69fbd53c9b19176d0012103797ec761f2a682213010ba82e8d46e005f6421f683bc6ec733aaf303c193845d0000000066a4857d93d20b33d53ced064e833f9db2861f0f3462debefa353c17d027de0e000000006b48304502210093b597eebab4cc7c5acccd4946a3062ef703b6167dde3da43fece9663c021dac022039809adbd6b3f6bf52280ee01fd5b25eb9d5dfd983c264209aee0eb84ea9fe06012102c8dca1fa27e9f68a08511af6b60575670a039de832efd066f8c62a67d72df77b000000005ca0d492eb704dce3eb5f1d7de3d10a7800ac37efea861009d60599c56b17e75000000006b483045022100b4de7441499f166f1eeaba37c3cbbd19f186e90bf36edf87c3c0026099755ec50220644e76d23e67b706db3ec685f882bac62cd40176ec79b694b5f22cb73bf167ba012102422d0c15e66546d385bea2c732bc50ce4502c8d5189450201818a0ca375f5b0500000000e1aea82a3f4e48cb633c2e3c4b3c0079389ef6cb7e53896f134eaeca3c7cf897010000006b483045022100a463c890a3d714b5d0e11cbee5ac87bb81ec5104227828c292d553870ed82ac7022023f98c6637d3a1a663e2f0630d06827e9c2486510dcbc8aba7c8a4f2bb1bbf52012103fef9b9366755bd64a0579f1a5bfb92485c1f4ab33c53a1afb1899efa7e4782c10000000001500f1e00000000001976a914db9854a96c6ad7158b58537717bd8a9ef711675888ac00000000000000000000000000000000000000" + }, + { + "txid": "0ede27d0173c35fabede62340f1f86b29d3f834e06ed3cd5330bd2937d85a466", + "version": 4, + "vin": [ + { + "txid": "97f87c3ccaae4e136f89537ecbf69e3879003c4b3c2e3c63cb484e3f2aa8aee1", + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1Yfrf1dssDLmaMBsq2LFKWPbS5vH3nGpa2" + ], + "isAddress": true, + "value": "100000", + "hex": "483045022100b949a9404e721e19e0fe82f028f62e9f3380b27ab714317ea08f9549fae63b6f022015113c5fadd85209650629ce3ad50fe14f833e94a4e9750c8a20f098ddc2df3a012103e22a9f6ad90405c4a3674e1344c9eb8cc5d1275e18c79c38e33a6b40eb4e25a8" + } + ], + "vout": [ + { + "value": "90000", + "n": 0, + "spent": true, + "hex": "76a91459f3433be138218d9f07a5d32b58b71c7621c5d388ac", + "addresses": [ + "t1S5DZbKS49jsGjdAGnVTG19kvqJCPmoaHK" + ], + "isAddress": true + } + ], + "blockHash": "0000000000ad38725a94c47c162019a0a5f5c89f967b9b567d415f6a31484252", + "blockHeight": 655109, + "confirmations": 174531, + "blockTime": 1576215924, + "value": "90000", + "valueIn": "100000", + "fees": "10000", + "hex": "0400008085202f8901e1aea82a3f4e48cb633c2e3c4b3c0079389ef6cb7e53896f134eaeca3c7cf897000000006b483045022100b949a9404e721e19e0fe82f028f62e9f3380b27ab714317ea08f9549fae63b6f022015113c5fadd85209650629ce3ad50fe14f833e94a4e9750c8a20f098ddc2df3a012103e22a9f6ad90405c4a3674e1344c9eb8cc5d1275e18c79c38e33a6b40eb4e25a8feffff7f01905f0100000000001976a91459f3433be138218d9f07a5d32b58b71c7621c5d388ac00000000000000000000000000000000000000" + }, + { + "txid": "97f87c3ccaae4e136f89537ecbf69e3879003c4b3c2e3c63cb484e3f2aa8aee1", + "version": 4, + "vin": [ + { + "txid": "757eb1569c59609d0061a8fe7ec30a80a7103dded7f1b53ece4d70eb92d4a05c", + "vout": 1, + "n": 0, + "addresses": [ + "t1S5DZbKS49jsGjdAGnVTG19kvqJCPmoaHK" + ], + "isAddress": true, + "value": "1890000", + "hex": "483045022100810999450a12d4b339018a4b82b76b84182fdc66ea8cafafd2b5925d95b44c700220704b4a67b2b66142d211eea2de7919effa45ba67200e0c4fb36bec784707f83e012102c8dca1fa27e9f68a08511af6b60575670a039de832efd066f8c62a67d72df77b" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a914a2511fc37f67f3b5627affce89fb3f7bb186412888ac", + "addresses": [ + "t1Yfrf1dssDLmaMBsq2LFKWPbS5vH3nGpa2" + ], + "isAddress": true + }, + { + "value": "1780000", + "n": 1, + "spent": true, + "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true + } + ], + "blockHash": "0000000001a0b8f060fc67bd6d3a6c1a4c1be5fc7207f8046275c6997a162b10", + "blockHeight": 655105, + "confirmations": 174535, + "blockTime": 1576215738, + "value": "1880000", + "valueIn": "1890000", + "fees": "10000", + "hex": "0400008085202f89015ca0d492eb704dce3eb5f1d7de3d10a7800ac37efea861009d60599c56b17e75010000006b483045022100810999450a12d4b339018a4b82b76b84182fdc66ea8cafafd2b5925d95b44c700220704b4a67b2b66142d211eea2de7919effa45ba67200e0c4fb36bec784707f83e012102c8dca1fa27e9f68a08511af6b60575670a039de832efd066f8c62a67d72df77b0000000002a0860100000000001976a914a2511fc37f67f3b5627affce89fb3f7bb186412888ac20291b00000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac00000000000000000000000000000000000000" + }, + { + "txid": "757eb1569c59609d0061a8fe7ec30a80a7103dded7f1b53ece4d70eb92d4a05c", + "version": 4, + "vin": [ + { + "txid": "6358ea195242ec9c2ae06e7be67c96ef901140e79d320eab9a42968ae2266b37", + "n": 0, + "addresses": [ + "t1dmuFMKkqoYs56Sqxg5Et5Yac2KFqtoGQe" + ], + "isAddress": true, + "value": "2000000", + "hex": "4830450221009c36192b84add900cc86bb110a7b82e4b28d8f016b598c4a5fa3373378d3e72d02204ffebee7e0be67f5660f54d7c83b983e24910e69b733fd14b3d96ed0fce0d4750121020d101a7957ebf37dae0fd0a86bf74d5e318a1507f358ddfe3d01f88808b70b06" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a914c42f154229ba025c563911a25116452f91aedeab88ac", + "addresses": [ + "t1bkvrKbLLBT3vJFYt8SmoiyMBj7XmUGXf4" + ], + "isAddress": true + }, + { + "value": "1890000", + "n": 1, + "spent": true, + "hex": "76a91459f3433be138218d9f07a5d32b58b71c7621c5d388ac", + "addresses": [ + "t1S5DZbKS49jsGjdAGnVTG19kvqJCPmoaHK" + ], + "isAddress": true + } + ], + "blockHash": "00000000034e557a024d485fadfcee86ab4d1c5436f8b3bcc405acd5ec22a97a", + "blockHeight": 654620, + "confirmations": 175020, + "blockTime": 1576179805, + "value": "1990000", + "valueIn": "2000000", + "fees": "10000", + "hex": "0400008085202f8901376b26e28a96429aab0e329de7401190ef967ce67b6ee02a9cec425219ea5863000000006b4830450221009c36192b84add900cc86bb110a7b82e4b28d8f016b598c4a5fa3373378d3e72d02204ffebee7e0be67f5660f54d7c83b983e24910e69b733fd14b3d96ed0fce0d4750121020d101a7957ebf37dae0fd0a86bf74d5e318a1507f358ddfe3d01f88808b70b060000000002a0860100000000001976a914c42f154229ba025c563911a25116452f91aedeab88acd0d61c00000000001976a91459f3433be138218d9f07a5d32b58b71c7621c5d388ac00000000000000000000000000000000000000" + }, + { + "txid": "97537779723705ad8afe29cbfa352563ba1e9f637789f2650475420effce52a6", + "version": 4, + "vin": [ + { + "txid": "ba6a3d21a328f62dae9c4bebd8d500918e2cdc6baa44a7984db3dc9a93c9652b", + "vout": 1, + "n": 0, + "addresses": [ + "t1KVd1yQGPBxNnH9e5jz4AHZsyezLJbeCpx" + ], + "isAddress": true, + "value": "46571", + "hex": "483045022100da924f0d853864baacd5e623612e05b0435477aa2299f91d414c6cd1f59b352502207a6bc1a148713fc3e6c05272536757be2f561d11182b509da9072406e8333d5f01210292cd04a3293951abedf0d16f233ebb9d34b9c16ce04ee617a712fa5a3ba40974" + } + ], + "vout": [ + { + "value": "10000", + "n": 0, + "spent": true, + "hex": "76a9147f17fbc46a8ccdc87e6ecfcdeafcafb42958ce2b88ac", + "addresses": [ + "t1VTcZ6fUY4Pctiwg3sRvr7Xtehd7t9oS8Y" + ], + "isAddress": true + }, + { + "value": "26571", + "n": 1, + "hex": "76a91442350ecf9013a7ef5aded68c21b88a6021019c4288ac", + "addresses": [ + "t1PugAXA5Vga3LV9SEicUZfEsx2KrtLTad7" + ], + "isAddress": true + } + ], + "blockHash": "00000000023add08ebb61e88e7ad48740c27570624f3508d5a21c5b65a39d7fa", + "blockHeight": 654372, + "confirmations": 175268, + "blockTime": 1576160170, + "value": "36571", + "valueIn": "46571", + "fees": "10000", + "hex": "0400008085202f89012b65c9939adcb34d98a744aa6bdc2c8e9100d5d8eb4b9cae2df628a3213d6aba010000006b483045022100da924f0d853864baacd5e623612e05b0435477aa2299f91d414c6cd1f59b352502207a6bc1a148713fc3e6c05272536757be2f561d11182b509da9072406e8333d5f01210292cd04a3293951abedf0d16f233ebb9d34b9c16ce04ee617a712fa5a3ba40974000000000210270000000000001976a9147f17fbc46a8ccdc87e6ecfcdeafcafb42958ce2b88accb670000000000001976a91442350ecf9013a7ef5aded68c21b88a6021019c4288ac00000000000000000000000000000000000000" + }, + { + "txid": "387939ff8eb07dd264376eeef2e126394ab139802b1d80e92b21c1a2ae54fe92", + "version": 4, + "vin": [ + { + "txid": "2381825cd9069a200944996257e25b9403ba3e296bbc1dd98b01019cc7028cde", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "t1ejPK3moem9SjQAqXeKBVYiCVqcezw4xAn" + ], + "isAddress": true, + "value": "27615", + "hex": "483045022100be56b29f0198d2fb514da2e6e2e45b79990f77fc1d03ec15b7432c049600e2b002200c44f2734224663077298fd891fcfee15073ce64efa9165f8b2e17fc20fe38d00121025bda2a553a7d3e1ccb2133eef1f009855feb3f5b2d213a664698fd39cec9d359" + } + ], + "vout": [ + { + "value": "17615", + "n": 0, + "hex": "76a914c3bacb129d85288a3deb5890ca9b711f7f71392688ac", + "addresses": [ + "t1biXYN8wJahR76SqZTe1LBzTLf3JAsmT93" + ], + "isAddress": true + } + ], + "blockHash": "000000000184d53c01bfe9c0516d274145229993296d4e9fb44920008f1908c0", + "blockHeight": 654034, + "confirmations": 175606, + "blockTime": 1576134503, + "value": "17615", + "valueIn": "27615", + "fees": "10000", + "hex": "0400008085202f8901de8c02c79c01018bd91dbc6b293eba03945be25762994409209a06d95c828123000000006b483045022100be56b29f0198d2fb514da2e6e2e45b79990f77fc1d03ec15b7432c049600e2b002200c44f2734224663077298fd891fcfee15073ce64efa9165f8b2e17fc20fe38d00121025bda2a553a7d3e1ccb2133eef1f009855feb3f5b2d213a664698fd39cec9d359ffffffff01cf440000000000001976a914c3bacb129d85288a3deb5890ca9b711f7f71392688ac00000000000000000000000000000000000000" + }, + { + "txid": "6358ea195242ec9c2ae06e7be67c96ef901140e79d320eab9a42968ae2266b37", + "version": 4, + "vin": [ + { + "txid": "004802e071ad43e33f14a198a626386f445da9a20d85cdc6cbf2464dbc0f5d5d", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "t1YUdySBxqnpA9dyJPwDqaY71EtiM9XqPXz" + ], + "isAddress": true, + "value": "4426404", + "hex": "483045022100adcba0664d7150a8b9d6bb14c61d88816d4cfde4b987dc7fdc0bac08f0bb069e02202e034144db8cff0a8b4a0a8c5017224b49a37a90a048c9e466ee2b642bbb2efc012103c05b6df7ed56a4c1e67f671e524f6d26bfca9fb2a2388a8af0a49399176b6355" + } + ], + "vout": [ + { + "value": "2000000", + "n": 0, + "spent": true, + "hex": "76a914da4e699a29b867c83a98987d99c46f8def145a3588ac", + "addresses": [ + "t1dmuFMKkqoYs56Sqxg5Et5Yac2KFqtoGQe" + ], + "isAddress": true + }, + { + "value": "2416404", + "n": 1, + "spent": true, + "hex": "76a9145d5cabf1815cbf48f581663c46a079f522e3e50a88ac", + "addresses": [ + "t1SPFs7dn3KQHYaXS8husDucMkTQJ6n3KH7" + ], + "isAddress": true + } + ], + "blockHash": "000000000285744d8b65e68d444438d5cd0cd4830cceb85eab51995ff07e153a", + "blockHeight": 653658, + "confirmations": 175982, + "blockTime": 1576106791, + "value": "4416404", + "valueIn": "4426404", + "fees": "10000", + "hex": "0400008085202f89015d5d0fbc4d46f2cbc6cd850da2a95d446f3826a698a1143fe343ad71e0024800000000006b483045022100adcba0664d7150a8b9d6bb14c61d88816d4cfde4b987dc7fdc0bac08f0bb069e02202e034144db8cff0a8b4a0a8c5017224b49a37a90a048c9e466ee2b642bbb2efc012103c05b6df7ed56a4c1e67f671e524f6d26bfca9fb2a2388a8af0a49399176b6355ffffffff0280841e00000000001976a914da4e699a29b867c83a98987d99c46f8def145a3588ac14df2400000000001976a9145d5cabf1815cbf48f581663c46a079f522e3e50a88ac0000000082f909000000000000000000000000" + }, + { + "txid": "2381825cd9069a200944996257e25b9403ba3e296bbc1dd98b01019cc7028cde", + "version": 4, + "vin": [ + { + "txid": "3cf0a895185be87b86f96ca213d0cceffc4ee402984505aeb491e379b122967b", + "n": 0, + "addresses": [ + "t1TwTPFb2ioL3H52XwnEYPk6FoU1awteAU9" + ], + "isAddress": true, + "value": "37615", + "hex": "4830450221009a42f5894abc9247d7253712c9fc33dd8b73b8196142d84009db4f2566bcf23d022035d5e555a84ce07c9f00db296d54ecf176bf6a88eeec4b1b3b434df32076f3bc012103ddf742213c30066ca096189e15540f34ad4d2bf7f0162115eb494a3034ed5c24" + } + ], + "vout": [ + { + "value": "27615", + "n": 0, + "spent": true, + "hex": "76a914e4ccb7831b849ae3fa8bfcd91b2242d9ef59ecb488ac", + "addresses": [ + "t1ejPK3moem9SjQAqXeKBVYiCVqcezw4xAn" + ], + "isAddress": true + } + ], + "blockHash": "0000000000de005c4451aea5f03920cf7b25cb206e5ece9042a2bd2172a911a7", + "blockHeight": 652406, + "confirmations": 177234, + "blockTime": 1575920739, + "value": "27615", + "valueIn": "37615", + "fees": "10000", + "hex": "0400008085202f89017b9622b179e391b4ae05459802e44efcefccd013a26cf9867be85b1895a8f03c000000006b4830450221009a42f5894abc9247d7253712c9fc33dd8b73b8196142d84009db4f2566bcf23d022035d5e555a84ce07c9f00db296d54ecf176bf6a88eeec4b1b3b434df32076f3bc012103ddf742213c30066ca096189e15540f34ad4d2bf7f0162115eb494a3034ed5c240000000001df6b0000000000001976a914e4ccb7831b849ae3fa8bfcd91b2242d9ef59ecb488ac00000000000000000000000000000000000000" + }, + { + "txid": "3cf0a895185be87b86f96ca213d0cceffc4ee402984505aeb491e379b122967b", + "version": 4, + "vin": [ + { + "txid": "1477d8b220b0215feef753f000f0dec7e8145b3a13748ca6f0dce21b67b07fd3", + "n": 0, + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true, + "value": "47615", + "hex": "483045022100e4bff2389e0ee07ee3e8bf0c776f4e46f08d1f7d5de3759796d499bb61685778022052a69c063d988e6077afa07b9a6fcaff08b7c288300c2f80e15c5453d6fc30b7012103fef9b9366755bd64a0579f1a5bfb92485c1f4ab33c53a1afb1899efa7e4782c1" + } + ], + "vout": [ + { + "value": "37615", + "n": 0, + "spent": true, + "hex": "76a9146e6bb96b8ab0006157a931100d83cd14f65dde4b88ac", + "addresses": [ + "t1TwTPFb2ioL3H52XwnEYPk6FoU1awteAU9" + ], + "isAddress": true + } + ], + "blockHash": "00000000011b2ec58f64a619f89ded65c2d097bb0354d164db1376300679c06c", + "blockHeight": 652349, + "confirmations": 177291, + "blockTime": 1575914154, + "value": "37615", + "valueIn": "47615", + "fees": "10000", + "hex": "0400008085202f8901d37fb0671be2dcf0a68c74133a5b14e8c7def000f053f7ee5f21b020b2d87714000000006b483045022100e4bff2389e0ee07ee3e8bf0c776f4e46f08d1f7d5de3759796d499bb61685778022052a69c063d988e6077afa07b9a6fcaff08b7c288300c2f80e15c5453d6fc30b7012103fef9b9366755bd64a0579f1a5bfb92485c1f4ab33c53a1afb1899efa7e4782c10000000001ef920000000000001976a9146e6bb96b8ab0006157a931100d83cd14f65dde4b88ac00000000000000000000000000000000000000" + }, + { + "txid": "1477d8b220b0215feef753f000f0dec7e8145b3a13748ca6f0dce21b67b07fd3", + "version": 4, + "vin": [ + { + "txid": "636ef8deb08d859e2cb1317561b3ea7eb96336f09fb64d88f48e9f8cf7e87641", + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1ZtFQa5CfNPdqZX8oy2y2kqMA89ASWNEWS" + ], + "isAddress": true, + "value": "57615", + "hex": "473044022062702a7f1ae45ebe6f77c6f37b40c1e190bccca884cc0e5390b02f234ab465c4022032f4732be66ba68880e1d7395e9def044254212c2d962c8a67ca6c283f191ba00121023756884cdf5cc6719e5c8948c6221e7be17510fa4de4dd2d0697e0b05ded0dba" + } + ], + "vout": [ + { + "value": "47615", + "n": 0, + "spent": true, + "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true + } + ], + "blockHash": "00000000009f7bf929ba73589b1c2f89c5fefd5bbee96db1d6e25eb8d5af3404", + "blockHeight": 636381, + "confirmations": 193259, + "blockTime": 1573508295, + "value": "47615", + "valueIn": "57615", + "fees": "10000", + "hex": "0400008085202f89014176e8f78c9f8ef4884db69ff03663b97eeab3617531b12c9e858db0def86e63000000006a473044022062702a7f1ae45ebe6f77c6f37b40c1e190bccca884cc0e5390b02f234ab465c4022032f4732be66ba68880e1d7395e9def044254212c2d962c8a67ca6c283f191ba00121023756884cdf5cc6719e5c8948c6221e7be17510fa4de4dd2d0697e0b05ded0dbafeffff7f01ffb90000000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac00000000000000000000000000000000000000" + }, + { + "txid": "636ef8deb08d859e2cb1317561b3ea7eb96336f09fb64d88f48e9f8cf7e87641", + "version": 4, + "vin": [ + { + "txid": "d8970d0c519ad553576ac4bf9151b553992c727b09654242c125afae9ea9d4c0", + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true, + "value": "67615", + "hex": "483045022100edbb8920f3292835ab04b35f1248651d56f260a1d47421dcf335e10ae96a4b7202207a44efbb7f4060e7fbcf27815da3c6856bb5d49e2fb76637278a0527d0ad1637012103fef9b9366755bd64a0579f1a5bfb92485c1f4ab33c53a1afb1899efa7e4782c1" + } + ], + "vout": [ + { + "value": "57615", + "n": 0, + "spent": true, + "hex": "76a914afa13ba5c9a11574d1f226fcb8aa55f9581d894f88ac", + "addresses": [ + "t1ZtFQa5CfNPdqZX8oy2y2kqMA89ASWNEWS" + ], + "isAddress": true + } + ], + "blockHash": "0000000000904db208136a8a16ada6db97e6e5c9c18b167f429af2fb1b022458", + "blockHeight": 601992, + "confirmations": 227648, + "blockTime": 1568325489, + "value": "57615", + "valueIn": "67615", + "fees": "10000", + "hex": "0400008085202f8901c0d4a99eaeaf25c1424265097b722c9953b55191bfc46a5753d59a510c0d97d8000000006b483045022100edbb8920f3292835ab04b35f1248651d56f260a1d47421dcf335e10ae96a4b7202207a44efbb7f4060e7fbcf27815da3c6856bb5d49e2fb76637278a0527d0ad1637012103fef9b9366755bd64a0579f1a5bfb92485c1f4ab33c53a1afb1899efa7e4782c1feffff7f010fe10000000000001976a914afa13ba5c9a11574d1f226fcb8aa55f9581d894f88ac00000000000000000000000000000000000000" + }, + { + "txid": "d8970d0c519ad553576ac4bf9151b553992c727b09654242c125afae9ea9d4c0", + "version": 4, + "vin": [ + { + "txid": "89db84acffdaa0d98d7b86351be3ba5abff842acdb8fbc31159f0b2e8da4368f", + "vout": 1, + "sequence": 2147483644, + "n": 0, + "addresses": [ + "t1LNfSM8HKK1iBmLty9LN1FrwiTTTmvU44J" + ], + "isAddress": true, + "value": "74396", + "hex": "483045022100abe0e95620f6eebc133cfe8c70dfa3d1d19a8d578328d9fc58de267fbe3cbff90220308cb9d2b539bede92482385c975992a3dd294df572ceae8d221ee9a56b11ebc0121030696c4d51da64931e563a9215953b8b734d38e307b4b08c9807b333d39cb711e" + }, + { + "txid": "89db84acffdaa0d98d7b86351be3ba5abff842acdb8fbc31159f0b2e8da4368f", + "sequence": 2147483645, + "n": 1, + "addresses": [ + "t1PjbgQCBHqvLLUAjGYhKMEXXvTpcLMzKAf" + ], + "isAddress": true, + "value": "2219", + "hex": "47304402201c07fab04d06567f557c1b9b5057dd0be83f9e50cf590d79913ff08f8e644ec702205d384e7ebb61420b8fb0e1df44ab3c4c9ef19f7db72e5530b3d16a74ab8c7101012103c8b1ed9a08e9b4ea4220c4035f3bc5723617bbccbef2091c9e74a89b24ed8bea" + }, + { + "txid": "7899e2e584b849a16d21dbbd6ac39e51b9ef23773022babe2868d10e6e772e06", + "sequence": 2147483646, + "n": 2, + "addresses": [ + "t1JKYSYmUS4tJMPEix2V8H3z8Grp51aTH2w" + ], + "isAddress": true, + "value": "1000", + "hex": "483045022100aee2bc7f92639e2657565cc0e70c982eaef2dbb1d316bea6e62759a1160f2e5b02204350ffaeffc76ff41ad856cf49b6a4b5e3afeac635b89b5b93f35538ef1371af01210200d8c5dca07ac681793dcac902634806553051398cf94c7c69bd144e14a225f4" + } + ], + "vout": [ + { + "value": "67615", + "n": 0, + "spent": true, + "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true + } + ], + "blockHash": "000000000060868b8d2216f304339e5507e655d1988d4a0d949fb10ee0e58578", + "blockHeight": 595990, + "confirmations": 233650, + "blockTime": 1567420905, + "value": "67615", + "valueIn": "77615", + "fees": "10000", + "hex": "0400008085202f89038f36a48d2e0b9f1531bc8fdbac42f8bf5abae31b35867b8dd9a0daffac84db89010000006b483045022100abe0e95620f6eebc133cfe8c70dfa3d1d19a8d578328d9fc58de267fbe3cbff90220308cb9d2b539bede92482385c975992a3dd294df572ceae8d221ee9a56b11ebc0121030696c4d51da64931e563a9215953b8b734d38e307b4b08c9807b333d39cb711efcffff7f8f36a48d2e0b9f1531bc8fdbac42f8bf5abae31b35867b8dd9a0daffac84db89000000006a47304402201c07fab04d06567f557c1b9b5057dd0be83f9e50cf590d79913ff08f8e644ec702205d384e7ebb61420b8fb0e1df44ab3c4c9ef19f7db72e5530b3d16a74ab8c7101012103c8b1ed9a08e9b4ea4220c4035f3bc5723617bbccbef2091c9e74a89b24ed8beafdffff7f062e776e0ed16828beba22307723efb9519ec36abddb216da149b884e5e29978000000006b483045022100aee2bc7f92639e2657565cc0e70c982eaef2dbb1d316bea6e62759a1160f2e5b02204350ffaeffc76ff41ad856cf49b6a4b5e3afeac635b89b5b93f35538ef1371af01210200d8c5dca07ac681793dcac902634806553051398cf94c7c69bd144e14a225f4feffff7f011f080100000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac00000000000000000000000000000000000000" + }, + { + "txid": "89db84acffdaa0d98d7b86351be3ba5abff842acdb8fbc31159f0b2e8da4368f", + "version": 4, + "vin": [ + { + "txid": "7899e2e584b849a16d21dbbd6ac39e51b9ef23773022babe2868d10e6e772e06", + "vout": 1, + "n": 0, + "addresses": [ + "t1VS1A32gPbGPtuwhttEHw1QvAJfPwTKJqp" + ], + "isAddress": true, + "value": "86615", + "hex": "483045022100dbbee07fd60e136497aa735f93a96005493d66bb8f3fa38ecf526b5863588ae70220707de0dcc3fecee251fd7b06dc6a10598cabbfd867f5ef002aeac461462ad0df0121037452ab70acb399482583cadf20f957e4739c0e677a29ce01ba4fd3ef5fabba66" + } + ], + "vout": [ + { + "value": "2219", + "n": 0, + "spent": true, + "hex": "76a914404d278cacec4b336a2bd73f625a6dcce9d2666988ac", + "addresses": [ + "t1PjbgQCBHqvLLUAjGYhKMEXXvTpcLMzKAf" + ], + "isAddress": true + }, + { + "value": "74396", + "n": 1, + "spent": true, + "hex": "76a9141b6f2dc084506144cfe883bc72376223cd5386da88ac", + "addresses": [ + "t1LNfSM8HKK1iBmLty9LN1FrwiTTTmvU44J" + ], + "isAddress": true + } + ], + "blockHash": "00000000001b3fe5eaf8b919b35a4e3195d67ee3b88c6b50f7bd8f0cb6491daf", + "blockHeight": 595650, + "confirmations": 233990, + "blockTime": 1567370080, + "value": "76615", + "valueIn": "86615", + "fees": "10000", + "hex": "0400008085202f8901062e776e0ed16828beba22307723efb9519ec36abddb216da149b884e5e29978010000006b483045022100dbbee07fd60e136497aa735f93a96005493d66bb8f3fa38ecf526b5863588ae70220707de0dcc3fecee251fd7b06dc6a10598cabbfd867f5ef002aeac461462ad0df0121037452ab70acb399482583cadf20f957e4739c0e677a29ce01ba4fd3ef5fabba660000000002ab080000000000001976a914404d278cacec4b336a2bd73f625a6dcce9d2666988ac9c220100000000001976a9141b6f2dc084506144cfe883bc72376223cd5386da88ac00000000000000000000000000000000000000" + }, + { + "txid": "7899e2e584b849a16d21dbbd6ac39e51b9ef23773022babe2868d10e6e772e06", + "version": 4, + "vin": [ + { + "txid": "a8218f12908291332a2640c1c0c342a0c0d6ddf545c416201fdf86a1f355ce61", + "n": 0, + "addresses": [ + "t1Xrv6J9sU2gWY9eqb7PgsxGMd2WHpok1XE" + ], + "isAddress": true, + "value": "97615", + "hex": "473044022049935dd1b1485173457c4fc80d59acf1b25a309d262edc0f79c0dd7d558a7c83022024f8dc29c5342a1a42a1607ea3989cb6a06db16ec5ed8944165a6831acd93ab001210365ba1fc37153f8d1d13553cf802a2a6643a23d362ca285d51309c3c42fbc439d" + } + ], + "vout": [ + { + "value": "1000", + "n": 0, + "spent": true, + "hex": "76a91404e7d6beccc84d52cf61d8fb17c95d131293c35188ac", + "addresses": [ + "t1JKYSYmUS4tJMPEix2V8H3z8Grp51aTH2w" + ], + "isAddress": true + }, + { + "value": "86615", + "n": 1, + "spent": true, + "hex": "76a9147eca04e061da84a586631747c1bfc9340277a73d88ac", + "addresses": [ + "t1VS1A32gPbGPtuwhttEHw1QvAJfPwTKJqp" + ], + "isAddress": true + } + ], + "blockHash": "00000000010accd88dac9bf3546d2018a46ccdc9129c0b28f331c4d2f6467a08", + "blockHeight": 595226, + "confirmations": 234414, + "blockTime": 1567305310, + "value": "87615", + "valueIn": "97615", + "fees": "10000", + "hex": "0400008085202f890161ce55f3a186df1f2016c445f5ddd6c0a042c3c0c140262a33918290128f21a8000000006a473044022049935dd1b1485173457c4fc80d59acf1b25a309d262edc0f79c0dd7d558a7c83022024f8dc29c5342a1a42a1607ea3989cb6a06db16ec5ed8944165a6831acd93ab001210365ba1fc37153f8d1d13553cf802a2a6643a23d362ca285d51309c3c42fbc439d0000000002e8030000000000001976a91404e7d6beccc84d52cf61d8fb17c95d131293c35188ac57520100000000001976a9147eca04e061da84a586631747c1bfc9340277a73d88ac00000000000000000000000000000000000000" + }, + { + "txid": "a8218f12908291332a2640c1c0c342a0c0d6ddf545c416201fdf86a1f355ce61", + "version": 4, + "vin": [ + { + "txid": "78e3fb2512eda4de98a0afca606c01ce608a2a51679c5400349999c68d8af94e", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "t1HsyCvdZZczFXgJJEXaoJujo2fVZeVpRxK" + ], + "isAddress": true, + "value": "107615", + "hex": "47304402200480f5dc34cc3fab8429bc29b7ef04bb59f4bf5016ac79a2e543e936dbce33be022063644c7d93a3e4ef7402ed544409e0faf6a6ec51d6164e2d84fad97cefb0e114012103df7baf7aece0effc84874c00b4a99fe143aeb36e1ac403c9dcf3037932d6d7e5" + } + ], + "vout": [ + { + "value": "97615", + "n": 0, + "spent": true, + "hex": "76a9149970712a7f2116b1de7f219ad3a337f3e77f3e7a88ac", + "addresses": [ + "t1Xrv6J9sU2gWY9eqb7PgsxGMd2WHpok1XE" + ], + "isAddress": true + } + ], + "blockHash": "0000000000e2b7074f5c3a02c99e54a1f4e447d3e710d57534058bc3904d1a8e", + "blockHeight": 587037, + "confirmations": 242603, + "blockTime": 1566071261, + "value": "97615", + "valueIn": "107615", + "fees": "10000", + "hex": "0400008085202f89014ef98a8dc699993400549c67512a8a60ce016c60caafa098dea4ed1225fbe378000000006a47304402200480f5dc34cc3fab8429bc29b7ef04bb59f4bf5016ac79a2e543e936dbce33be022063644c7d93a3e4ef7402ed544409e0faf6a6ec51d6164e2d84fad97cefb0e114012103df7baf7aece0effc84874c00b4a99fe143aeb36e1ac403c9dcf3037932d6d7e5feffffff014f7d0100000000001976a9149970712a7f2116b1de7f219ad3a337f3e77f3e7a88ac00000000000000000000000000000000000000" + }, + { + "txid": "78e3fb2512eda4de98a0afca606c01ce608a2a51679c5400349999c68d8af94e", + "version": 4, + "vin": [ + { + "txid": "3c0725a0e1f0d0de5b7810e0dc2cc75a9fb00835ab45f3e3b08b1cf96ee1f6a4", + "n": 0, + "addresses": [ + "t1Xrv6J9sU2gWY9eqb7PgsxGMd2WHpok1XE" + ], + "isAddress": true, + "value": "117615", + "hex": "473044022074bdb6b0c06625dc963a2ce028db78b0b95cfba7d228b05a0cf440b4c40ca4b0022018a98ef2516f4c8869b039e2428386f0b66812b36b2cdf97a854dde952d0427d01210365ba1fc37153f8d1d13553cf802a2a6643a23d362ca285d51309c3c42fbc439d" + } + ], + "vout": [ + { + "value": "107615", + "n": 0, + "spent": true, + "hex": "76a9140011b25c777caef601764607e7a302986eccb82588ac", + "addresses": [ + "t1HsyCvdZZczFXgJJEXaoJujo2fVZeVpRxK" + ], + "isAddress": true + } + ], + "blockHash": "00000000015c276dd33cac045fb755a86394acaa19615750fa3608bc4c8ff99e", + "blockHeight": 587035, + "confirmations": 242605, + "blockTime": 1566070856, + "value": "107615", + "valueIn": "117615", + "fees": "10000", + "hex": "0400008085202f8901a4f6e16ef91c8bb0e3f345ab3508b09f5ac72cdce010785bded0f0e1a025073c000000006a473044022074bdb6b0c06625dc963a2ce028db78b0b95cfba7d228b05a0cf440b4c40ca4b0022018a98ef2516f4c8869b039e2428386f0b66812b36b2cdf97a854dde952d0427d01210365ba1fc37153f8d1d13553cf802a2a6643a23d362ca285d51309c3c42fbc439d00000000015fa40100000000001976a9140011b25c777caef601764607e7a302986eccb82588ac00000000000000000000000000000000000000" + }, + { + "txid": "3c0725a0e1f0d0de5b7810e0dc2cc75a9fb00835ab45f3e3b08b1cf96ee1f6a4", + "version": 4, + "vin": [ + { + "txid": "bae4ead50cb6af925de4a800767467326009528d96698e547b4b3880cd0c774e", + "n": 0, + "addresses": [ + "t1SRU7H59hSyHCeZVSyQTy9eFWeZu58qCU5" + ], + "isAddress": true, + "value": "127615", + "hex": "483045022100fccbc13d0b0fb06eced6296b92d9810e6040a63506c604e226916301ae537ddd02207e0f0de7f0dfdc44a772e6eb5b40264eb9898011ea119fec0fbb9e2bc7830a24012103a07aa3081fe12b3d266b2dddd2cf03a8d064b532e992784583dfc3da89a9b19b" + } + ], + "vout": [ + { + "value": "117615", + "n": 0, + "spent": true, + "hex": "76a9149970712a7f2116b1de7f219ad3a337f3e77f3e7a88ac", + "addresses": [ + "t1Xrv6J9sU2gWY9eqb7PgsxGMd2WHpok1XE" + ], + "isAddress": true + } + ], + "blockHash": "0000000001457ae3eea0540bc6b0f2f7455e38dc8670af1c2f15f55d50a135ee", + "blockHeight": 552255, + "confirmations": 277385, + "blockTime": 1560830228, + "value": "117615", + "valueIn": "127615", + "fees": "10000", + "hex": "0400008085202f89014e770ccd80384b7b548e69968d5209603267747600a8e45d92afb60cd5eae4ba000000006b483045022100fccbc13d0b0fb06eced6296b92d9810e6040a63506c604e226916301ae537ddd02207e0f0de7f0dfdc44a772e6eb5b40264eb9898011ea119fec0fbb9e2bc7830a24012103a07aa3081fe12b3d266b2dddd2cf03a8d064b532e992784583dfc3da89a9b19b00000000016fcb0100000000001976a9149970712a7f2116b1de7f219ad3a337f3e77f3e7a88ac00000000000000000000000000000000000000" + }, + { + "txid": "bae4ead50cb6af925de4a800767467326009528d96698e547b4b3880cd0c774e", + "version": 4, + "vin": [ + { + "txid": "a9fe8bbc05bdd7ee41f5f5f23b09b55199426bb2a35dbe47010e08598f98e5c3", + "n": 0, + "addresses": [ + "t1PuJbdK5VEbMbQhQxZw5R2dAZXoBrRmQz2" + ], + "isAddress": true, + "value": "137615", + "hex": "483045022100dcf7b268d447abea180e21574aaa5be602c5fd6344e271b796c96814a6053f6f02201e7bff00a244b8d2be52fb186530461c75d8f1781ad896532a0dbfe5e045dcb4012103f4126fb596c4f86f2f252cd6b613601d4100881465deb0d18ea7f8a0b04ea590" + } + ], + "vout": [ + { + "value": "127615", + "n": 0, + "spent": true, + "hex": "76a9145dc7b9795d03a3c8fecb4278b764a4db8e1ee49488ac", + "addresses": [ + "t1SRU7H59hSyHCeZVSyQTy9eFWeZu58qCU5" + ], + "isAddress": true + } + ], + "blockHash": "00000000017e0ff0f957da216b91409ee1513fd365e0d65e6c06cc45cacf605b", + "blockHeight": 552253, + "confirmations": 277387, + "blockTime": 1560830099, + "value": "127615", + "valueIn": "137615", + "fees": "10000", + "hex": "0400008085202f8901c3e5988f59080e0147be5da3b26b429951b5093bf2f5f541eed7bd05bc8bfea9000000006b483045022100dcf7b268d447abea180e21574aaa5be602c5fd6344e271b796c96814a6053f6f02201e7bff00a244b8d2be52fb186530461c75d8f1781ad896532a0dbfe5e045dcb4012103f4126fb596c4f86f2f252cd6b613601d4100881465deb0d18ea7f8a0b04ea59000000000017ff20100000000001976a9145dc7b9795d03a3c8fecb4278b764a4db8e1ee49488ac00000000000000000000000000000000000000" + }, + { + "txid": "a9fe8bbc05bdd7ee41f5f5f23b09b55199426bb2a35dbe47010e08598f98e5c3", + "version": 4, + "vin": [ + { + "txid": "b2b4354a6f5c5e159e2bb2a0dc990c5f4ecfe365260ddb98921ad018b5030206", + "n": 0, + "addresses": [ + "t1aQHf67YqdbyNFzDpK4dXJsfjb4SPr9qRH" + ], + "isAddress": true, + "value": "60000", + "hex": "4730440220687c3b473abe367b46a88c51b36caf0d51926fbd4cc60df4cf7af30df53f4eec022068d34fdc54680ab3e574d8d1497c5b0832b00735929cd1e97e8ba03f3554aad6012103ec7908bb4a2ed3cf779f81691e30ccf867989b94e8cd79173796ffb6e18cf28c" + }, + { + "txid": "014795c69c6144f6c3b9be2b1f1f4d7617bac7e8a5f6e28673e3f901661c9444", + "vout": 1, + "n": 1, + "addresses": [ + "t1LmGZZN6oJsNV8wY9EDQYrhajg71YshkMo" + ], + "isAddress": true, + "value": "87615", + "hex": "4830450221009b4013ac2faa7d253b23bc7a05855130855332c39067fbc17e52d543cdce11e502201f640107c1a4f6415fbfd7b00cb66eaf047f45c5ca6a38f9e41ca526c036d2c5012102aa3981e0a468bc511b85746f1a33547105d16a244d23abe6f917c0b74777a24d" + } + ], + "vout": [ + { + "value": "137615", + "n": 0, + "spent": true, + "hex": "76a91442230df4c84c4dacb6945d0f7d300fd90557acca88ac", + "addresses": [ + "t1PuJbdK5VEbMbQhQxZw5R2dAZXoBrRmQz2" + ], + "isAddress": true + } + ], + "blockHash": "0000000000dc36e2f9d737c21143febc7f7a35a92769ca922c6321171d9b0886", + "blockHeight": 552248, + "confirmations": 277392, + "blockTime": 1560829106, + "value": "137615", + "valueIn": "147615", + "fees": "10000", + "hex": "0400008085202f8902060203b518d01a9298db0d2665e3cf4e5f0c99dca0b22b9e155e5c6f4a35b4b2000000006a4730440220687c3b473abe367b46a88c51b36caf0d51926fbd4cc60df4cf7af30df53f4eec022068d34fdc54680ab3e574d8d1497c5b0832b00735929cd1e97e8ba03f3554aad6012103ec7908bb4a2ed3cf779f81691e30ccf867989b94e8cd79173796ffb6e18cf28c0000000044941c6601f9e37386e2f6a5e8c7ba17764d1f1f2bbeb9c3f644619cc6954701010000006b4830450221009b4013ac2faa7d253b23bc7a05855130855332c39067fbc17e52d543cdce11e502201f640107c1a4f6415fbfd7b00cb66eaf047f45c5ca6a38f9e41ca526c036d2c5012102aa3981e0a468bc511b85746f1a33547105d16a244d23abe6f917c0b74777a24d00000000018f190200000000001976a91442230df4c84c4dacb6945d0f7d300fd90557acca88ac00000000000000000000000000000000000000" + }, + { + "txid": "b2b4354a6f5c5e159e2bb2a0dc990c5f4ecfe365260ddb98921ad018b5030206", + "version": 4, + "vin": [ + { + "txid": "4b061d48a56175194f35debff7cefdf2a738bcdccea5f0cebe4f5a95db9b6637", + "n": 0, + "addresses": [ + "t1WZBfArcTbjFo5By9tHg6aZ49u1XXokaPH" + ], + "isAddress": true, + "value": "10000", + "hex": "483045022100cf6f4bf09e1c9c64c1f8b6331e266c88d0402a4cfdf5d6176642f5d4c80dd5460220287b41c7c0000f34010310165bb44fd75c1e61f515c479918da467bd6e0b19c6012102eabba83fbfdb74b2e8a1f20dd9744682e34310535f6129bbd9f8005e917aef36" + }, + { + "txid": "ba6a3d21a328f62dae9c4bebd8d500918e2cdc6baa44a7984db3dc9a93c9652b", + "n": 1, + "addresses": [ + "t1azHScmQB3p7vsRaeEHR4xxAuiQ9SnC9GP" + ], + "isAddress": true, + "value": "20000", + "hex": "473044022039b4be3afde31864e91ba0b25837ed0e0b921709c95359c86497fa47e020d08f02203c7321c814d1cafbb010563e7ba02eb521b0982af59a08995c137e35765773f6012102abf02fc95b72e12a60ea199e9d33c1867687b31d6597ea6aaed07700c19952b6" + }, + { + "txid": "07597ac193a42bfd1a0370f26eb53c9cb6c383a43a15f689adc0f7fc6edf28c5", + "n": 2, + "addresses": [ + "t1ecYmJ9EtaU2Tq6MiEFe8dKtEbWDYM6EVV" + ], + "isAddress": true, + "value": "40000", + "hex": "483045022100bbb2369c802d32d26487ffd62fcdcb1c0d0690ac1d9521a86ad68d630ba1a5df022074ffbe6f532485e535814a2d2f502b2591f36b98a396c8bd49dcdfc5669230ee01210230ed84e0cb369ed38f38f58c39370e075a71dd4c9ef198c83dbb934140142281" + } + ], + "vout": [ + { + "value": "60000", + "n": 0, + "spent": true, + "hex": "76a914b54f971eeed8d512761bffe3403fb98dc68d1e5b88ac", + "addresses": [ + "t1aQHf67YqdbyNFzDpK4dXJsfjb4SPr9qRH" + ], + "isAddress": true + } + ], + "blockHash": "000000000065e2264cc41e0405783b6c5c53ae814f381fe2295344a74a264a19", + "blockHeight": 545291, + "confirmations": 284349, + "blockTime": 1559778739, + "value": "60000", + "valueIn": "70000", + "fees": "10000", + "hex": "0400008085202f890337669bdb955a4fbecef0a5cedcbc38a7f2fdcef7bfde354f197561a5481d064b000000006b483045022100cf6f4bf09e1c9c64c1f8b6331e266c88d0402a4cfdf5d6176642f5d4c80dd5460220287b41c7c0000f34010310165bb44fd75c1e61f515c479918da467bd6e0b19c6012102eabba83fbfdb74b2e8a1f20dd9744682e34310535f6129bbd9f8005e917aef36000000002b65c9939adcb34d98a744aa6bdc2c8e9100d5d8eb4b9cae2df628a3213d6aba000000006a473044022039b4be3afde31864e91ba0b25837ed0e0b921709c95359c86497fa47e020d08f02203c7321c814d1cafbb010563e7ba02eb521b0982af59a08995c137e35765773f6012102abf02fc95b72e12a60ea199e9d33c1867687b31d6597ea6aaed07700c19952b600000000c528df6efcf7c0ad89f6153aa483c3b69c3cb56ef270031afd2ba493c17a5907000000006b483045022100bbb2369c802d32d26487ffd62fcdcb1c0d0690ac1d9521a86ad68d630ba1a5df022074ffbe6f532485e535814a2d2f502b2591f36b98a396c8bd49dcdfc5669230ee01210230ed84e0cb369ed38f38f58c39370e075a71dd4c9ef198c83dbb934140142281000000000160ea0000000000001976a914b54f971eeed8d512761bffe3403fb98dc68d1e5b88ac00000000000000000000000000000000000000" + }, + { + "txid": "ba6a3d21a328f62dae9c4bebd8d500918e2cdc6baa44a7984db3dc9a93c9652b", + "version": 4, + "vin": [ + { + "txid": "2aa6a35c267895b2e69213ec76d97ce3e147e9e5ab8db4d14d97da8958efa9d0", + "vout": 1, + "n": 0, + "addresses": [ + "t1LEjcwGJyDNvMKDLB5k4CaghgfTZkjzzEw" + ], + "isAddress": true, + "value": "76571", + "hex": "483045022100dc687fa4a4c9548e110d44defafab7ea54d144f390944e357cfa26b6f790058d022069231e27f62ab31653b5c008118bb9869436fdb0d3a6eade372ea108d7daa7f601210213b1aae26c2f7ce235506548862a88ade9ffd3ce2b8b514d6bbbf7fc395bb590" + } + ], + "vout": [ + { + "value": "20000", + "n": 0, + "spent": true, + "hex": "76a914bbbd8db39d0f497de1ae92431a4b466e64293cd388ac", + "addresses": [ + "t1azHScmQB3p7vsRaeEHR4xxAuiQ9SnC9GP" + ], + "isAddress": true + }, + { + "value": "46571", + "n": 1, + "spent": true, + "hex": "76a91411c7f1c0835985c5ddd888c02c353f1bd8292e2f88ac", + "addresses": [ + "t1KVd1yQGPBxNnH9e5jz4AHZsyezLJbeCpx" + ], + "isAddress": true + } + ], + "blockHash": "00000000000b0040c2a6d132807a476ccfbe21905d00cb75d72dc40493714fa0", + "blockHeight": 536166, + "confirmations": 293474, + "blockTime": 1558404490, + "value": "66571", + "valueIn": "76571", + "fees": "10000", + "hex": "0400008085202f8901d0a9ef5889da974dd1b48dabe5e947e1e37cd976ec1392e6b29578265ca3a62a010000006b483045022100dc687fa4a4c9548e110d44defafab7ea54d144f390944e357cfa26b6f790058d022069231e27f62ab31653b5c008118bb9869436fdb0d3a6eade372ea108d7daa7f601210213b1aae26c2f7ce235506548862a88ade9ffd3ce2b8b514d6bbbf7fc395bb5900000000002204e0000000000001976a914bbbd8db39d0f497de1ae92431a4b466e64293cd388acebb50000000000001976a91411c7f1c0835985c5ddd888c02c353f1bd8292e2f88ac00000000000000000000000000000000000000" + }, + { + "txid": "4b061d48a56175194f35debff7cefdf2a738bcdccea5f0cebe4f5a95db9b6637", + "version": 4, + "vin": [ + { + "txid": "f50a4866f8903d33ca366c03b1532cf706332d1bdc7c6e750d6a7aff446e0c98", + "vout": 1, + "n": 0, + "addresses": [ + "t1VbtaqSjTYUTyE8Vd1kfiyyGanp6jgscU8" + ], + "isAddress": true, + "value": "116571", + "hex": "483045022100b7503d585b390559b925dcaed95fe1f8a16a016b5e5e951aa5ae7bb7de9594b8022054265524e2e5182f779a2ede0cbf6a9f1600ed008fdc73de898e4233b28cf5fc012102dcd6ea3c7eba94884ef03ca415da890518e577e3cfa94f0e77c9332be39d3602" + } + ], + "vout": [ + { + "value": "10000", + "n": 0, + "spent": true, + "hex": "76a9148b1dd2cea75b2d0d4c8d36c8a93439607b1e976088ac", + "addresses": [ + "t1WZBfArcTbjFo5By9tHg6aZ49u1XXokaPH" + ], + "isAddress": true + }, + { + "value": "96571", + "n": 1, + "spent": true, + "hex": "76a914e6d092ef8680c588ba47969614e2261d01d974e288ac", + "addresses": [ + "t1ev3HRtQ6ZtmeueaiXHWApFFVtMFnLxaf7" + ], + "isAddress": true + } + ], + "blockHash": "00000000002af42207e62b06294fdb4cc30f9f68b9997b2ba2c0408ee9c04243", + "blockHeight": 535691, + "confirmations": 293949, + "blockTime": 1558332379, + "value": "106571", + "valueIn": "116571", + "fees": "10000", + "hex": "0400008085202f8901980c6e44ff7a6a0d756e7cdc1b2d3306f72c53b1036c36ca333d90f866480af5010000006b483045022100b7503d585b390559b925dcaed95fe1f8a16a016b5e5e951aa5ae7bb7de9594b8022054265524e2e5182f779a2ede0cbf6a9f1600ed008fdc73de898e4233b28cf5fc012102dcd6ea3c7eba94884ef03ca415da890518e577e3cfa94f0e77c9332be39d3602000000000210270000000000001976a9148b1dd2cea75b2d0d4c8d36c8a93439607b1e976088ac3b790100000000001976a914e6d092ef8680c588ba47969614e2261d01d974e288ac00000000000000000000000000000000000000" + }, + { + "txid": "07597ac193a42bfd1a0370f26eb53c9cb6c383a43a15f689adc0f7fc6edf28c5", + "version": 4, + "vin": [ + { + "txid": "87a266b3f2a4b830b164a96a9e4b4b6061d7c5ffe1e30e57b642c571bf388e98", + "sequence": 2147483645, + "n": 0, + "addresses": [ + "t1SKY9rZvnTTS8ZoVjn4dAfCmUqmArtpFHi" + ], + "isAddress": true, + "value": "20000", + "hex": "4830450221009b6a147560a41c5285a7c35a21812b4be68bb52b1ce03e3bf0b475aa737c6eb2022048739d1c6c6ceca1f2e67d61752f97c81da4fcc09264867c6d4c299099b48bd30121026a9f1854fdd1c1ce3939d440c8840dbd2a63fc7008a18572d89ea2f1d63c9b32" + }, + { + "txid": "5741f65a1c49ba6f1baa4d1b82a3474c3789e9ba1b3e9bd5d60a8a0d479d750f", + "vout": 1, + "sequence": 2147483646, + "n": 1, + "addresses": [ + "t1dQQump9ZPt7urePRY8TgYvWv4xdmChAW6" + ], + "isAddress": true, + "value": "30000", + "hex": "4730440220712880521b4b31ebd9b424b9ec357280cd3fbed5dffa844aa7458da2724bbdf002203c725798727356eb4bae4689f9ced074a87310f10ff926503b7d492aa8e84128012102f97ce8805b15faa5eff060374e320d5f9e88169065debeff4d756ab345b3ec3b" + } + ], + "vout": [ + { + "value": "40000", + "n": 0, + "spent": true, + "hex": "76a914e381b21975ead95b7a21edd78f82b2f676b6e1bb88ac", + "addresses": [ + "t1ecYmJ9EtaU2Tq6MiEFe8dKtEbWDYM6EVV" + ], + "isAddress": true + } + ], + "blockHash": "000000000162ad34a620f5da8aaca7886ab814b42222fb3c19012d21e3f0076f", + "blockHeight": 530001, + "confirmations": 299639, + "blockTime": 1557475098, + "value": "40000", + "valueIn": "50000", + "fees": "10000", + "hex": "0400008085202f8902988e38bf71c542b6570ee3e1ffc5d761604b4b9e6aa964b130b8a4f2b366a287000000006b4830450221009b6a147560a41c5285a7c35a21812b4be68bb52b1ce03e3bf0b475aa737c6eb2022048739d1c6c6ceca1f2e67d61752f97c81da4fcc09264867c6d4c299099b48bd30121026a9f1854fdd1c1ce3939d440c8840dbd2a63fc7008a18572d89ea2f1d63c9b32fdffff7f0f759d470d8a0ad6d59b3e1bbae989374c47a3821b4daa1b6fba491c5af64157010000006a4730440220712880521b4b31ebd9b424b9ec357280cd3fbed5dffa844aa7458da2724bbdf002203c725798727356eb4bae4689f9ced074a87310f10ff926503b7d492aa8e84128012102f97ce8805b15faa5eff060374e320d5f9e88169065debeff4d756ab345b3ec3bfeffff7f01409c0000000000001976a914e381b21975ead95b7a21edd78f82b2f676b6e1bb88ac00000000000000000000000000000000000000" + }, + { + "txid": "87a266b3f2a4b830b164a96a9e4b4b6061d7c5ffe1e30e57b642c571bf388e98", + "version": 4, + "vin": [ + { + "txid": "6cb96616f80d3306b3d4fd070f8bbca86e2c6d07235e72d15c6594223660e3b4", + "n": 0, + "addresses": [ + "t1VuFmytzWfXkf4nFQ1qVyRVG6sA71Nb1XA" + ], + "isAddress": true, + "value": "186571", + "hex": "4830450221008a5d4a6844d7f8b57e8fd5a08e2f27da2197368b6679760601bfbfe36c2ee54b02202457c56bb0c5a4223cb2aa52eaf2a6f1d74b8d460aff3aa9a909f4ce1ab4164c012102d22925142a9dbfd799b338f234d23b89f9f7fdcf9ad00152b491dbb4eb116ec4" + } + ], + "vout": [ + { + "value": "20000", + "n": 0, + "spent": true, + "hex": "76a9145ca89ad87d3ea6efdaca1c6a27b556005d9b33e988ac", + "addresses": [ + "t1SKY9rZvnTTS8ZoVjn4dAfCmUqmArtpFHi" + ], + "isAddress": true + }, + { + "value": "156571", + "n": 1, + "spent": true, + "hex": "76a914bd5cdbfa6ff21f7bf3e608d75864fd80fb81d48f88ac", + "addresses": [ + "t1b8rxZuPquqUWECT4RZ2eCsFzUeRwmGzoW" + ], + "isAddress": true + } + ], + "blockHash": "00000000025e8dcff95a89e64a5f6e0e0276396c37122968b1df6778ebcfe793", + "blockHeight": 493797, + "confirmations": 335843, + "blockTime": 1552021263, + "value": "176571", + "valueIn": "186571", + "fees": "10000", + "hex": "0400008085202f8901b4e360362294655cd1725e23076d2c6ea8bc8b0f07fdd4b306330df81666b96c000000006b4830450221008a5d4a6844d7f8b57e8fd5a08e2f27da2197368b6679760601bfbfe36c2ee54b02202457c56bb0c5a4223cb2aa52eaf2a6f1d74b8d460aff3aa9a909f4ce1ab4164c012102d22925142a9dbfd799b338f234d23b89f9f7fdcf9ad00152b491dbb4eb116ec40000000002204e0000000000001976a9145ca89ad87d3ea6efdaca1c6a27b556005d9b33e988ac9b630200000000001976a914bd5cdbfa6ff21f7bf3e608d75864fd80fb81d48f88ac00000000000000000000000000000000000000" + }, + { + "txid": "5741f65a1c49ba6f1baa4d1b82a3474c3789e9ba1b3e9bd5d60a8a0d479d750f", + "version": 4, + "vin": [ + { + "txid": "bc5c5c66ad3ad122bb4d1c2496431e58fa14d574928f4c7e2460d8dcd4bd0e84", + "n": 0, + "addresses": [ + "t1YttEPhpzGVSYSp5R34wVqVPs2fyGiEZs2" + ], + "isAddress": true, + "value": "60205", + "hex": "47304402205721cbb1e623518d7ec2e830aa7460e58c42a9f787f11291f6c05a90afb6a657022069602db026217e31a8817d433a7f3e30f6659f57d6761e490acf7bc0a0521558012102b27a1fd41fce9b5b0f3dc90ffe2d535a2b86e608fba52a49c354c73e82bdd6a4" + } + ], + "vout": [ + { + "value": "20205", + "n": 0, + "spent": true, + "hex": "76a914955584a7abf343158e28cf3c0160796cbd12d08088ac", + "addresses": [ + "t1XVD8prU8TEAA1pxKyz6mrBNbBZ8wC4kTj" + ], + "isAddress": true + }, + { + "value": "30000", + "n": 1, + "spent": true, + "hex": "76a914d63e05b6989e6921c76479fc6ef0e7e9823d7c5c88ac", + "addresses": [ + "t1dQQump9ZPt7urePRY8TgYvWv4xdmChAW6" + ], + "isAddress": true + } + ], + "blockHash": "0000000001591c6609bb6c0edc720947abb7e712dbb8deea965b9246c3c1d0c8", + "blockHeight": 493429, + "confirmations": 336211, + "blockTime": 1551964242, + "value": "50205", + "valueIn": "60205", + "fees": "10000", + "hex": "0400008085202f8901840ebdd4dcd860247e4c8f9274d514fa581e4396241c4dbb22d13aad665c5cbc000000006a47304402205721cbb1e623518d7ec2e830aa7460e58c42a9f787f11291f6c05a90afb6a657022069602db026217e31a8817d433a7f3e30f6659f57d6761e490acf7bc0a0521558012102b27a1fd41fce9b5b0f3dc90ffe2d535a2b86e608fba52a49c354c73e82bdd6a40000000002ed4e0000000000001976a914955584a7abf343158e28cf3c0160796cbd12d08088ac30750000000000001976a914d63e05b6989e6921c76479fc6ef0e7e9823d7c5c88ac00000000000000000000000000000000000000" + }, + { + "txid": "bc5c5c66ad3ad122bb4d1c2496431e58fa14d574928f4c7e2460d8dcd4bd0e84", + "version": 4, + "vin": [ + { + "txid": "fbb42f66c7c89790d5dad4aa23e85dfc7b5ab1cfe5a4086527a23c7df20756b4", + "n": 0, + "addresses": [ + "t1YttEPhpzGVSYSp5R34wVqVPs2fyGiEZs2" + ], + "isAddress": true, + "value": "20000", + "hex": "463043022053699effba95c7d1bee5a8ae182dbcf0d86af5c082098dfae4ece7e54c3736e3021f355bfa5a836a92a441b6a4ff156bfdeba3f220d0003c9c9e6a4dc6d85752bf012102b27a1fd41fce9b5b0f3dc90ffe2d535a2b86e608fba52a49c354c73e82bdd6a4" + }, + { + "txid": "c82c968f0ac87b54466871720eef8c4d3f608d28438561c309f294b383aff17a", + "n": 1, + "addresses": [ + "t1Kcug9yvp6QLipTfd9RDrU5PQPsHzePhyv" + ], + "isAddress": true, + "value": "40545", + "hex": "483045022100fb9f78fb552c84334b81d2c3032b54c260fce7873500730c974ad34bba7644f102204ac0d79c0d5aef6f6f3c36ffe8254cc17cf92e33ff9571aead9523f300fec1a3012103dc373638b9cca448a4adb2c8e778a426c4a8216775498c7cf32feb810b3c4ec3" + } + ], + "vout": [ + { + "value": "60205", + "n": 0, + "spent": true, + "hex": "76a914a4c7d8c56f1ff151cbdeec12bc7b053b08ff52ac88ac", + "addresses": [ + "t1YttEPhpzGVSYSp5R34wVqVPs2fyGiEZs2" + ], + "isAddress": true + } + ], + "blockHash": "000000000158a121c2a75050705c45ff354af27544e229323d482e44d5914b06", + "blockHeight": 492785, + "confirmations": 336855, + "blockTime": 1551868143, + "value": "60205", + "valueIn": "60545", + "fees": "340", + "hex": "0400008085202f8902b45607f27d3ca2276508a4e5cfb15a7bfc5de823aad4dad59097c8c7662fb4fb0000000069463043022053699effba95c7d1bee5a8ae182dbcf0d86af5c082098dfae4ece7e54c3736e3021f355bfa5a836a92a441b6a4ff156bfdeba3f220d0003c9c9e6a4dc6d85752bf012102b27a1fd41fce9b5b0f3dc90ffe2d535a2b86e608fba52a49c354c73e82bdd6a4000000007af1af83b394f209c3618543288d603f4d8cef0e72716846547bc80a8f962cc8000000006b483045022100fb9f78fb552c84334b81d2c3032b54c260fce7873500730c974ad34bba7644f102204ac0d79c0d5aef6f6f3c36ffe8254cc17cf92e33ff9571aead9523f300fec1a3012103dc373638b9cca448a4adb2c8e778a426c4a8216775498c7cf32feb810b3c4ec300000000012deb0000000000001976a914a4c7d8c56f1ff151cbdeec12bc7b053b08ff52ac88ac00000000000000000000000000000000000000" + }, + { + "txid": "fbb42f66c7c89790d5dad4aa23e85dfc7b5ab1cfe5a4086527a23c7df20756b4", + "version": 4, + "vin": [ + { + "txid": "5d3f984c4563d5c363281e2be8de4122a5751bd502fb8782b0b12682a7ec5d42", + "n": 0, + "addresses": [ + "t1MTTLGaye2ZEPzKUc7EVLxAFx5B89rotcs" + ], + "isAddress": true, + "value": "94000", + "hex": "473044022079cc77a85e4465d4d176fda5cfde603d4721d93d3d4650b522b39efb24c17bbd022015bddf13c5cde76162cf7ccc2995d6851ba3bfaa99a6cc9016aaa41b46e0c2de012102baf4209fb6e235ad8c9705b2d4b9797b0f14545ffb1512e58b5d066548e03212" + } + ], + "vout": [ + { + "value": "20000", + "n": 0, + "spent": true, + "hex": "76a914a4c7d8c56f1ff151cbdeec12bc7b053b08ff52ac88ac", + "addresses": [ + "t1YttEPhpzGVSYSp5R34wVqVPs2fyGiEZs2" + ], + "isAddress": true + }, + { + "value": "73774", + "n": 1, + "spent": true, + "hex": "76a914e1794bf49a7ba4066ee119369e7b79430f34a52a88ac", + "addresses": [ + "t1eRoMLftw1xXFsSoL8ibmv8DFA3rzR6oeK" + ], + "isAddress": true + } + ], + "blockHash": "0000000001ac58459c37aa4254a1420711cd246737827936cdd9a78249236225", + "blockHeight": 492784, + "confirmations": 336856, + "blockTime": 1551867941, + "value": "93774", + "valueIn": "94000", + "fees": "226", + "hex": "0400008085202f8901425deca78226b1b08287fb02d51b75a52241dee82b1e2863c3d563454c983f5d000000006a473044022079cc77a85e4465d4d176fda5cfde603d4721d93d3d4650b522b39efb24c17bbd022015bddf13c5cde76162cf7ccc2995d6851ba3bfaa99a6cc9016aaa41b46e0c2de012102baf4209fb6e235ad8c9705b2d4b9797b0f14545ffb1512e58b5d066548e032120000000002204e0000000000001976a914a4c7d8c56f1ff151cbdeec12bc7b053b08ff52ac88ac2e200100000000001976a914e1794bf49a7ba4066ee119369e7b79430f34a52a88ac00000000000000000000000000000000000000" + }, + { + "txid": "c82c968f0ac87b54466871720eef8c4d3f608d28438561c309f294b383aff17a", + "version": 4, + "vin": [ + { + "txid": "eb15e83c5e3ad2b5cb18a2ce87d396bd3772f3332316ebbc7adf2fb33082c2f2", + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1VZp67AK9zgdXwa35kwYrJ1Mh4NWjUENrM" + ], + "isAddress": true, + "value": "50545", + "hex": "483045022100f401558fb69e77db46dc3fc50a9d133334004cb5e8c368a020bcf7f057ab6545022053e4c3cc1ee5f3f2b4559b5e9178428ceecdabf85786359be5d0fa0863655f0101210233258d2a0e50bb55ed56dc5bfc2d26295245a9e18ee95ac8b09f04f6618f70ec" + } + ], + "vout": [ + { + "value": "40545", + "n": 0, + "spent": true, + "hex": "76a9141328c3015cb87b03e8e6f0a5b9df3af2287e88d188ac", + "addresses": [ + "t1Kcug9yvp6QLipTfd9RDrU5PQPsHzePhyv" + ], + "isAddress": true + } + ], + "blockHash": "0000000001398c130afbd8c1fd48efaaf33e6ecb569e5af9cec2779af35bb440", + "blockHeight": 489873, + "confirmations": 339767, + "blockTime": 1551429261, + "value": "40545", + "valueIn": "50545", + "fees": "10000", + "hex": "0400008085202f8901f2c28230b32fdf7abceb162333f37237bd96d387cea218cbb5d23a5e3ce815eb000000006b483045022100f401558fb69e77db46dc3fc50a9d133334004cb5e8c368a020bcf7f057ab6545022053e4c3cc1ee5f3f2b4559b5e9178428ceecdabf85786359be5d0fa0863655f0101210233258d2a0e50bb55ed56dc5bfc2d26295245a9e18ee95ac8b09f04f6618f70ecfeffff7f01619e0000000000001976a9141328c3015cb87b03e8e6f0a5b9df3af2287e88d188ac00000000000000000000000000000000000000" + }, + { + "txid": "eb15e83c5e3ad2b5cb18a2ce87d396bd3772f3332316ebbc7adf2fb33082c2f2", + "version": 4, + "vin": [ + { + "txid": "5ba43d4ffc58827e896793f044f1bf78c382571761362dfa844422d575639d78", + "sequence": 2147483645, + "n": 0, + "addresses": [ + "t1ZBs9xvRypkjXmci2SS6zbNWVhuWH1h93L" + ], + "isAddress": true, + "value": "30545", + "hex": "483045022100ebc32cdf141e49adf2be0f0a70920f66ba3b206aaebcbc19a3f819ebc974d83102206175d4e979a0a0e2ff51b363552ac60b17dfc1d0a91c80395cb6ae2bfcf9476d012103132665bcf5b41abb7565ccfd53f748175cc42e9ddb4a845e79bcb79c8cd99f26" + }, + { + "txid": "5ba43d4ffc58827e896793f044f1bf78c382571761362dfa844422d575639d78", + "vout": 1, + "sequence": 2147483646, + "n": 1, + "addresses": [ + "t1Y5pJi1BzrppCFwVkaK1XTVv3BwCbytGaA" + ], + "isAddress": true, + "value": "30000", + "hex": "473044022076d426a3404a53ca2f93a4dcf1985fae899a373993d7c2e1fe94b05609b728d6022056116ac52a03b644f61456439a401a8f6d3ba061c17386dbf2fabbc0b306c01d01210201e594657c7cfbfe12a8c0943f39886d9cae06386275739bd7983a621c81c7c5" + } + ], + "vout": [ + { + "value": "50545", + "n": 0, + "spent": true, + "hex": "76a91480441b9ccba15c024878a39b9f85b98f9d333d6288ac", + "addresses": [ + "t1VZp67AK9zgdXwa35kwYrJ1Mh4NWjUENrM" + ], + "isAddress": true + } + ], + "blockHash": "0000000001dc7678276f7964adb7b932ae6d998cde2177e28e12d130759a7590", + "blockHeight": 485550, + "confirmations": 344090, + "blockTime": 1550776869, + "value": "50545", + "valueIn": "60545", + "fees": "10000", + "hex": "0400008085202f8902789d6375d5224484fa2d3661175782c378bff144f09367897e8258fc4f3da45b000000006b483045022100ebc32cdf141e49adf2be0f0a70920f66ba3b206aaebcbc19a3f819ebc974d83102206175d4e979a0a0e2ff51b363552ac60b17dfc1d0a91c80395cb6ae2bfcf9476d012103132665bcf5b41abb7565ccfd53f748175cc42e9ddb4a845e79bcb79c8cd99f26fdffff7f789d6375d5224484fa2d3661175782c378bff144f09367897e8258fc4f3da45b010000006a473044022076d426a3404a53ca2f93a4dcf1985fae899a373993d7c2e1fe94b05609b728d6022056116ac52a03b644f61456439a401a8f6d3ba061c17386dbf2fabbc0b306c01d01210201e594657c7cfbfe12a8c0943f39886d9cae06386275739bd7983a621c81c7c5feffff7f0171c50000000000001976a91480441b9ccba15c024878a39b9f85b98f9d333d6288ac00000000000000000000000000000000000000" + }, + { + "txid": "5ba43d4ffc58827e896793f044f1bf78c382571761362dfa844422d575639d78", + "version": 4, + "vin": [ + { + "txid": "37c7b9f9cebe1416d219ca05485ad778bc6f89856cba4c61bfaa7d9f458b2d55", + "vout": 1, + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1NbJzWWBkfUrxSN8FWNKSa9JUSTG26dStY" + ], + "isAddress": true, + "value": "70545", + "hex": "483045022100df78b552957f64a099afe79c2a6e1ec4acfa4c8577f7c0b1e8ad27ca468b26ca02203b530b1d959c049e4275a3fb5eef9605d96d1c58740a34a80bf4298a35d3a53a0121021f3209adeba8e2b478b4dec27e562b1203d6035333784da2af7cdc89ab33aace" + } + ], + "vout": [ + { + "value": "30545", + "n": 0, + "spent": true, + "hex": "76a914a7fe0506daff7402a5dd08659a86668a497614f988ac", + "addresses": [ + "t1ZBs9xvRypkjXmci2SS6zbNWVhuWH1h93L" + ], + "isAddress": true + }, + { + "value": "30000", + "n": 1, + "spent": true, + "hex": "76a9149be10506ef2c0a369929ca54873569ab55907d3f88ac", + "addresses": [ + "t1Y5pJi1BzrppCFwVkaK1XTVv3BwCbytGaA" + ], + "isAddress": true + } + ], + "blockHash": "000000000235fae347f9c305d34a76fc4b532d6f063eeb2304e37a31b183b281", + "blockHeight": 483265, + "confirmations": 346375, + "blockTime": 1550432494, + "value": "60545", + "valueIn": "70545", + "fees": "10000", + "hex": "0400008085202f8901552d8b459f7daabf614cba6c85896fbc78d75a4805ca19d21614becef9b9c737010000006b483045022100df78b552957f64a099afe79c2a6e1ec4acfa4c8577f7c0b1e8ad27ca468b26ca02203b530b1d959c049e4275a3fb5eef9605d96d1c58740a34a80bf4298a35d3a53a0121021f3209adeba8e2b478b4dec27e562b1203d6035333784da2af7cdc89ab33aacefeffff7f0251770000000000001976a914a7fe0506daff7402a5dd08659a86668a497614f988ac30750000000000001976a9149be10506ef2c0a369929ca54873569ab55907d3f88ac00000000000000000000000000000000000000" + }, + { + "txid": "37c7b9f9cebe1416d219ca05485ad778bc6f89856cba4c61bfaa7d9f458b2d55", + "version": 4, + "vin": [ + { + "txid": "1e4b4756b54858af5c93d916fd19e0e3bce148a84ee7bcf6200cb2252488791f", + "vout": 1, + "sequence": 1, + "n": 0, + "addresses": [ + "t1b4mu9ew2Ubf5pLBbNh9PbXfsdHR1aoQ99" + ], + "isAddress": true, + "value": "100771", + "hex": "483045022100b52a74148248ba2853bac2dd2cad4b6d1d46b8cdda51350384ff868411672c8d02203bf74c7cab9a615874e98aa3b63a6cf003a6f565a393c444553c300b9e881a8201210381c7ca3323110fdff2e27094d967cdf0ece3435793fc34c0af8140203bacaa89" + } + ], + "vout": [ + { + "value": "30000", + "n": 0, + "spent": true, + "hex": "76a914a2511fc37f67f3b5627affce89fb3f7bb186412888ac", + "addresses": [ + "t1Yfrf1dssDLmaMBsq2LFKWPbS5vH3nGpa2" + ], + "isAddress": true + }, + { + "value": "70545", + "n": 1, + "spent": true, + "hex": "76a91433c3c5503cb12ec7a87fcbb5f30ee8677d51a38688ac", + "addresses": [ + "t1NbJzWWBkfUrxSN8FWNKSa9JUSTG26dStY" + ], + "isAddress": true + } + ], + "blockHash": "000000000255e2cd35ef686be4492c8e84342945c1683cf108bfa8a480dc8266", + "blockHeight": 480644, + "confirmations": 348996, + "blockTime": 1550038730, + "value": "100545", + "valueIn": "100771", + "fees": "226", + "hex": "0400008085202f89011f79882425b20c20f6bce74ea848e1bce3e019fd16d9935caf5848b556474b1e010000006b483045022100b52a74148248ba2853bac2dd2cad4b6d1d46b8cdda51350384ff868411672c8d02203bf74c7cab9a615874e98aa3b63a6cf003a6f565a393c444553c300b9e881a8201210381c7ca3323110fdff2e27094d967cdf0ece3435793fc34c0af8140203bacaa89010000000230750000000000001976a914a2511fc37f67f3b5627affce89fb3f7bb186412888ac91130100000000001976a91433c3c5503cb12ec7a87fcbb5f30ee8677d51a38688ac00000000000000000000000000000000000000" + }, + { + "txid": "1e4b4756b54858af5c93d916fd19e0e3bce148a84ee7bcf6200cb2252488791f", + "version": 4, + "vin": [ + { + "txid": "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", + "n": 0, + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true, + "value": "200997", + "hex": "4730440220211441367b601960d81e802a74b92aedfe10d32c49c86e43186ab1e743c045af02207267c5c2dc3abbf71ec3e149d94736d3deac8c87be1d5ceae8648ce5cad416c9012103fef9b9366755bd64a0579f1a5bfb92485c1f4ab33c53a1afb1899efa7e4782c1" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a9145f17f252c1d48a7465f512c13ecc182a3c3e827788ac", + "addresses": [ + "t1SYQtPxi4BYbZpMWZb4F4aFnEBgfHuE5uW" + ], + "isAddress": true + }, + { + "value": "100771", + "n": 1, + "spent": true, + "hex": "76a914bc96f8f30d3e5a96cfa2b0143a4aa84fa60854ba88ac", + "addresses": [ + "t1b4mu9ew2Ubf5pLBbNh9PbXfsdHR1aoQ99" + ], + "isAddress": true + } + ], + "blockHash": "000000000046084d8c5331f53b4f91c9e4b5514854bedeac833882396900aa24", + "blockHeight": 479877, + "confirmations": 349763, + "blockTime": 1549921545, + "value": "200771", + "valueIn": "200997", + "fees": "226", + "hex": "0400008085202f8901d7fe79d60186239bd1aa810c02c63f664db3cd83fa59f176c4104512ee0bd7a2000000006a4730440220211441367b601960d81e802a74b92aedfe10d32c49c86e43186ab1e743c045af02207267c5c2dc3abbf71ec3e149d94736d3deac8c87be1d5ceae8648ce5cad416c9012103fef9b9366755bd64a0579f1a5bfb92485c1f4ab33c53a1afb1899efa7e4782c10000000002a0860100000000001976a9145f17f252c1d48a7465f512c13ecc182a3c3e827788aca3890100000000001976a914bc96f8f30d3e5a96cfa2b0143a4aa84fa60854ba88ac00000000000000000000000000000000000000" + }, + { + "txid": "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", + "version": 4, + "vin": [ + { + "txid": "5a3664328ac4e1c0688729573296c2ec69dd9a7cf98d49967b41520be794229b", + "n": 0, + "addresses": [ + "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD" + ], + "isAddress": true, + "value": "387582", + "hex": "483045022100ec29a476dac49578339a92e6c20451aaf3ff6691efaf7d4d3113d07589771ca702203c0c173bdc356300edbd64cdfaa868b97c13ebc403026b283eb5e1fca398db8b012103729cc4211cf70f87c70c3cef90e0ca9b91e99b42364b8c600d5781277647de5f" + } + ], + "vout": [ + { + "value": "200997", + "n": 0, + "spent": true, + "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", + "addresses": [ + "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" + ], + "isAddress": true + }, + { + "value": "186359", + "n": 1, + "spent": true, + "hex": "76a91484f0258cb7974993e6af928921b7f699c51a309488ac", + "addresses": [ + "t1VzWtLj9CSAK3QnxA7uuiK6XhJrjGjKoy4" + ], + "isAddress": true + } + ], + "blockHash": "0000000000a8248c4a14a2dcb74d92855bf9440da9b7b1e6d4baa14ee7e3081c", + "blockHeight": 479017, + "confirmations": 350623, + "blockTime": 1549793065, + "value": "387356", + "valueIn": "387582", + "fees": "226", + "hex": "0400008085202f89019b2294e70b52417b96498df97c9add69ecc2963257298768c0e1c48a3264365a000000006b483045022100ec29a476dac49578339a92e6c20451aaf3ff6691efaf7d4d3113d07589771ca702203c0c173bdc356300edbd64cdfaa868b97c13ebc403026b283eb5e1fca398db8b012103729cc4211cf70f87c70c3cef90e0ca9b91e99b42364b8c600d5781277647de5f000000000225110300000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988acf7d70200000000001976a91484f0258cb7974993e6af928921b7f699c51a309488ac00000000000000000000000000000000000000" + } + ], + "usedTokens": 30, + "tokens": [ + { + "type": "XPUBAddress", + "name": "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", + "path": "m/44'/133'/0'/0/0", + "transfers": 10, + "decimals": 8, + "balance": "836466", + "totalReceived": "3779159", + "totalSent": "2942693" + } + ] +} diff --git a/mock/ext-api-data/zcoin-api_v2_address_a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn__details_txs.json b/mock/ext-api-data/zcoin-api_v2_address_a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn__details_txs.json new file mode 100644 index 000000000..62dcfb166 --- /dev/null +++ b/mock/ext-api-data/zcoin-api_v2_address_a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":2,"itemsOnPage":10,"address":"a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn","balance":"63109110","totalReceived":"1565104974","totalSent":"1501995864","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":18,"transactions":[{"txid":"f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609","version":1,"vin":[{"txid":"cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564","vout":1,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"51916634","hex":"483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"13113178","n":0,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true},{"value":"38799388","n":1,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328","blockHeight":251191,"confirmations":17949,"blockTime":1584663676,"value":"51912566","valueIn":"51916634","fees":"4068","hex":"010000000164b574c298c44b23fc6f328494ff306444895262d7f670ebb2a5c48233ac33cd010000006b483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b1500000000025a17c800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac1c085002000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564","version":1,"vin":[{"txid":"50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd","vout":1,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"61920702","hex":"483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"10000000","n":0,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true},{"value":"51916634","n":1,"spent":true,"spentTxId":"f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609","spentHeight":251191,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328","blockHeight":251191,"confirmations":17949,"blockTime":1584663676,"value":"61916634","valueIn":"61920702","fees":"4068","hex":"0100000001fd296277b76a406837115f9213f3ce6ebfdb8408447c1423281c034e387acb50010000006b483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15000000000280969800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac5a2f1803000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd","version":1,"vin":[{"txid":"11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45","vout":1,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"62924770","hex":"4830450221009e0fe641502a598f5f470ff3a5cb4bd46e2906e0e09c7a8c93d80bfd61cfb26e0220199247204747faf99e8605e7c6af4a1a8489c2a133b92f1f547990cef62cc9f60121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"1000000","n":0,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true},{"value":"61920702","n":1,"spent":true,"spentTxId":"cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564","spentHeight":251191,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"1cb40b2f2d4618cd9606b0f476d2ccfeee4740bb76cd46e2c75df6e783017cb1","blockHeight":251156,"confirmations":17984,"blockTime":1584656561,"value":"62920702","valueIn":"62924770","fees":"4068","hex":"010000000145db9ddeddd58b983e4e7aa6909c09aa34fddf13657f512bba0821deeb51a011010000006b4830450221009e0fe641502a598f5f470ff3a5cb4bd46e2906e0e09c7a8c93d80bfd61cfb26e0220199247204747faf99e8605e7c6af4a1a8489c2a133b92f1f547990cef62cc9f60121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15000000000240420f00000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788acbed5b003000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45","version":1,"vin":[{"txid":"86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef","vout":1,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"63028838","hex":"483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"100000","n":0,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true},{"value":"62924770","n":1,"spent":true,"spentTxId":"50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd","spentHeight":251156,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"5ba0f8c0e58986d1eb5036e766e28ed541d0993cb717fc1aea46d714a89945e7","blockHeight":250864,"confirmations":18276,"blockTime":1584571576,"value":"63024770","valueIn":"63028838","fees":"4068","hex":"0100000001ef273981817358e256ecb5e87a9826056893b8e2672e49a6a8c29b0fe343fb86010000006b483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b150000000002a0860100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ace227c003000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef","version":1,"vin":[{"txid":"5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e","vout":1,"sequence":4294967294,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"64032906","hex":"483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"1000000","n":0,"spent":true,"spentTxId":"a0289b25937f9b682dd9f15a6c1af44eba405187bb5c23ea0f6310bb570c45e5","spentHeight":259026,"hex":"76a914cffef031eead7d332c245df1372dcf4980a0127c88ac","addresses":["aKgF22yWfjBqekrbkhkFYqenzsw9zfRch8"],"isAddress":true},{"value":"63028838","n":1,"spent":true,"spentTxId":"11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45","spentHeight":250864,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"fcfea4d17cde4cfc8d113d923e7e2978513e902448f1087fd448ae4162696f4f","blockHeight":244409,"confirmations":24731,"blockTime":1582620606,"value":"64028838","valueIn":"64032906","fees":"4068","hex":"01000000011e60be361fdabd33a545444bd7c0a6571e6e1fa9d92e65676da700d0aeebf75c010000006b483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15feffffff0240420f00000000001976a914cffef031eead7d332c245df1372dcf4980a0127c88ac66bec103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"4178eb3a84a34a9b508dbb61abbe725de115de2daea619e1cfa68eadf001fe51","version":1,"vin":[{"txid":"6de60b862ef752e24f1417c255f750e8e2e2b64ce4160eccbcdd82663a36daeb","n":0,"addresses":["aDVvWiM5PTv3QrUbrWQW3hPVLiFTMmzAHr"],"isAddress":true,"value":"100000","hex":"483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b"}],"vout":[{"value":"96544","n":0,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"e3d64bc33182f0b74b6247c7b37a9f8ff3c6852fe1c08116d460d067919345d1","blockHeight":241112,"confirmations":28028,"blockTime":1581616858,"value":"96544","valueIn":"100000","fees":"3456","hex":"0100000001ebda363a6682ddbccc0e16e44cb6e2e2e850f755c217144fe252f72e860be66d000000006b483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b000000000120790100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e","version":1,"vin":[{"txid":"5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241","vout":1,"n":0,"addresses":["aL96Xr2E1pMW3vcsZ5QV6BYLFE9jdCVBJL"],"isAddress":true,"value":"364036974","hex":"483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8"}],"vout":[{"value":"300000000","n":0,"spent":true,"spentTxId":"736d2ed9a2398511cc98f30df178db721716c1996fd8ab67970a5ac41a795e72","spentIndex":2,"spentHeight":239559,"hex":"76a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac","addresses":["aB3mWSqhFzszMJ3h8sxTedFYDhZCDBkeQT"],"isAddress":true},{"value":"64032906","n":1,"spent":true,"spentTxId":"86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef","spentHeight":244409,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"07d7c24529ee402be1a94b6b5a70d000c6002f0fa7201c1f5ef4ef7dd87f0117","blockHeight":239551,"confirmations":29589,"blockTime":1581138788,"value":"364032906","valueIn":"364036974","fees":"4068","hex":"010000000141320e1d67dca17a2d7107f1e3b378fbf443347afb21e16d130be718a8ce8254010000006b483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8000000000200a3e111000000001976a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac8a10d103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"c4f897a1d64e6c870184ff26a3ad8f5f4a94a6667f6d3486f21e52530d8ecea2","version":1,"vin":[{"txid":"3054b05d5f9624264bf7bfbb140749472c58670cc935efa5aab4a96c6430ed19","sequence":4294967294,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"365045110","hex":"473044022062705d4b0f266a25646c410e3a735b7665dafb85655bf4b9f3ce89ecde4306f20220702f5fd1f3d6e593c3e3e9a37adf6431b1920b55151872dc9c8f4dc166df1a8f0121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"365041042","n":0,"spent":true,"spentTxId":"5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241","spentHeight":238210,"hex":"76a914e5712d04a22c551a8261aea3f4a8d98ddb057f5988ac","addresses":["aMde4RuTWiNzoZN53SWZ7i7tKNbhSwt57U"],"isAddress":true}],"blockHash":"1afa27baa3146c5ae36cb93612f928b794b306d4d8b552636fb3f35891a7adb8","blockHeight":238176,"confirmations":30964,"blockTime":1580709451,"value":"365041042","valueIn":"365045110","fees":"4068","hex":"010000000119ed30646ca9b4aaa5ef35c90c67582c47490714bbbff74b2624965f5db05430000000006a473044022062705d4b0f266a25646c410e3a735b7665dafb85655bf4b9f3ce89ecde4306f20220702f5fd1f3d6e593c3e3e9a37adf6431b1920b55151872dc9c8f4dc166df1a8f0121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15feffffff019215c215000000001976a914e5712d04a22c551a8261aea3f4a8d98ddb057f5988ac00000000"},{"txid":"3054b05d5f9624264bf7bfbb140749472c58670cc935efa5aab4a96c6430ed19","version":1,"vin":[{"txid":"c7cd71424b7165ae60fe998767a43dab338915ef3215782ae7b9ba9710fd9aab","n":0,"addresses":["aDqeCrv3YqSr3UtBT9W6xnFNEJonV87mSt"],"isAddress":true,"value":"365048566","hex":"4730440220603f06106ee740b0399bc72c801fb7e4e3a907d06cd54c61dcac674cdd9cf3be02202ad273482c6300bae8f655523913845d50a2c805a173db3fb2c1bc65a2d894a701210296a3500dfacb901de8c43eb79b368bd7c710a65f6723d67ca51fa83728b8e402"}],"vout":[{"value":"365045110","n":0,"spent":true,"spentTxId":"c4f897a1d64e6c870184ff26a3ad8f5f4a94a6667f6d3486f21e52530d8ecea2","spentHeight":238176,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"419b039bfb0cdbe1a507c6ba5c1fa2828e6fe1785b748a29eb243186ab60430b","blockHeight":238161,"confirmations":30979,"blockTime":1580704843,"value":"365045110","valueIn":"365048566","fees":"3456","hex":"0100000001ab9afd1097bab9e72a781532ef158933ab3da4678799fe60ae65714b4271cdc7000000006a4730440220603f06106ee740b0399bc72c801fb7e4e3a907d06cd54c61dcac674cdd9cf3be02202ad273482c6300bae8f655523913845d50a2c805a173db3fb2c1bc65a2d894a701210296a3500dfacb901de8c43eb79b368bd7c710a65f6723d67ca51fa83728b8e40200000000017625c215000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"c7cd71424b7165ae60fe998767a43dab338915ef3215782ae7b9ba9710fd9aab","version":1,"vin":[{"txid":"5bb0f077e0cd6473c529db2f03b59150b6ea9f261f3d60fdc1e169d54c470a60","n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"1000000","hex":"483045022100c923f70b6f8dd9f7feee018e1c2009bece3255f8b317135ea635af1442325fd20220703ab8f539cbe261cf2836bb1659817afb17ea2ac382ba82ea30849266b28bdb0121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"},{"txid":"dc46c8292b9f154a0f3114d3d899852e8e8fd30dfa8736e9c4869121ea3b5e08","n":1,"addresses":["aF61ZkGfZNFMLumooKrNNDqCq9KSAmew6G"],"isAddress":true,"value":"2000000","hex":"483045022100e8bc25770f43b416fde1f8471fc0afe483b8b1cd961ade28c54c83757d30b3d602206c0c51c0a61a37c34f6887c8609aeff9ad60ee883738d455fb9f290481ca8ba00121027d09e12a82828d3170ef73784a179c14e106e2f0ca0c1e11b54b2e4a2c23c55b"},{"txid":"dc46c8292b9f154a0f3114d3d899852e8e8fd30dfa8736e9c4869121ea3b5e08","vout":1,"n":2,"addresses":["aK7W1TtDD5wfz7o2TcRyf7XycXuQ4XaX7X"],"isAddress":true,"value":"362057350","hex":"483045022100fe7f5b7ca2dac6f35ef1ebead1a5b268e852998dbc3877218b6494bb4ec4314002204fc5b6dc94bf440f2c52b766cc96d03745a85d62ec5cc08295714bb62fbe42580121023230b3fa3b145df6249c1dc4f72aaba101a1283e85644e73fd20019e5aeed68d"}],"vout":[{"value":"365048566","n":0,"spent":true,"spentTxId":"3054b05d5f9624264bf7bfbb140749472c58670cc935efa5aab4a96c6430ed19","spentHeight":238161,"hex":"76a9148ff5484fd892d16012bfd95ab4a9b9e53dbc052388ac","addresses":["aDqeCrv3YqSr3UtBT9W6xnFNEJonV87mSt"],"isAddress":true}],"blockHash":"0e88334c147d222909e2c2e67ed8f854269eea168ef7c566ca0c29a4dffbbdb7","blockHeight":237361,"confirmations":31779,"blockTime":1580453676,"value":"365048566","valueIn":"365057350","fees":"8784","hex":"0100000003600a474cd569e1c1fd603d1f269feab65091b5032fdb29c57364cde077f0b05b000000006b483045022100c923f70b6f8dd9f7feee018e1c2009bece3255f8b317135ea635af1442325fd20220703ab8f539cbe261cf2836bb1659817afb17ea2ac382ba82ea30849266b28bdb0121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b1500000000085e3bea219186c4e93687fa0dd38f8e2e8599d8d314310f4a159f2b29c846dc000000006b483045022100e8bc25770f43b416fde1f8471fc0afe483b8b1cd961ade28c54c83757d30b3d602206c0c51c0a61a37c34f6887c8609aeff9ad60ee883738d455fb9f290481ca8ba00121027d09e12a82828d3170ef73784a179c14e106e2f0ca0c1e11b54b2e4a2c23c55b00000000085e3bea219186c4e93687fa0dd38f8e2e8599d8d314310f4a159f2b29c846dc010000006b483045022100fe7f5b7ca2dac6f35ef1ebead1a5b268e852998dbc3877218b6494bb4ec4314002204fc5b6dc94bf440f2c52b766cc96d03745a85d62ec5cc08295714bb62fbe42580121023230b3fa3b145df6249c1dc4f72aaba101a1283e85644e73fd20019e5aeed68d0000000001f632c215000000001976a9148ff5484fd892d16012bfd95ab4a9b9e53dbc052388ac00000000"}]} diff --git a/mock/ext-api-data/zcoin-api_v2_xpub_xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK__details_txs.json b/mock/ext-api-data/zcoin-api_v2_xpub_xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK__details_txs.json new file mode 100644 index 000000000..6cbb02828 --- /dev/null +++ b/mock/ext-api-data/zcoin-api_v2_xpub_xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":6,"itemsOnPage":10,"address":"xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK","balance":"63109110","totalReceived":"19765346316","totalSent":"19702237206","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":54,"transactions":[{"txid":"cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564","version":1,"vin":[{"txid":"50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd","vout":1,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"61920702","hex":"483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"10000000","n":0,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true},{"value":"51916634","n":1,"spent":true,"spentTxId":"f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609","spentHeight":251191,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328","blockHeight":251191,"confirmations":17949,"blockTime":1584663676,"value":"61916634","valueIn":"61920702","fees":"4068","hex":"0100000001fd296277b76a406837115f9213f3ce6ebfdb8408447c1423281c034e387acb50010000006b483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15000000000280969800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac5a2f1803000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609","version":1,"vin":[{"txid":"cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564","vout":1,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"51916634","hex":"483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"13113178","n":0,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true},{"value":"38799388","n":1,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328","blockHeight":251191,"confirmations":17949,"blockTime":1584663676,"value":"51912566","valueIn":"51916634","fees":"4068","hex":"010000000164b574c298c44b23fc6f328494ff306444895262d7f670ebb2a5c48233ac33cd010000006b483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b1500000000025a17c800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac1c085002000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd","version":1,"vin":[{"txid":"11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45","vout":1,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"62924770","hex":"4830450221009e0fe641502a598f5f470ff3a5cb4bd46e2906e0e09c7a8c93d80bfd61cfb26e0220199247204747faf99e8605e7c6af4a1a8489c2a133b92f1f547990cef62cc9f60121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"1000000","n":0,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true},{"value":"61920702","n":1,"spent":true,"spentTxId":"cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564","spentHeight":251191,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"1cb40b2f2d4618cd9606b0f476d2ccfeee4740bb76cd46e2c75df6e783017cb1","blockHeight":251156,"confirmations":17984,"blockTime":1584656561,"value":"62920702","valueIn":"62924770","fees":"4068","hex":"010000000145db9ddeddd58b983e4e7aa6909c09aa34fddf13657f512bba0821deeb51a011010000006b4830450221009e0fe641502a598f5f470ff3a5cb4bd46e2906e0e09c7a8c93d80bfd61cfb26e0220199247204747faf99e8605e7c6af4a1a8489c2a133b92f1f547990cef62cc9f60121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15000000000240420f00000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788acbed5b003000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45","version":1,"vin":[{"txid":"86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef","vout":1,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"63028838","hex":"483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"100000","n":0,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true},{"value":"62924770","n":1,"spent":true,"spentTxId":"50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd","spentHeight":251156,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"5ba0f8c0e58986d1eb5036e766e28ed541d0993cb717fc1aea46d714a89945e7","blockHeight":250864,"confirmations":18276,"blockTime":1584571576,"value":"63024770","valueIn":"63028838","fees":"4068","hex":"0100000001ef273981817358e256ecb5e87a9826056893b8e2672e49a6a8c29b0fe343fb86010000006b483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b150000000002a0860100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ace227c003000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef","version":1,"vin":[{"txid":"5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e","vout":1,"sequence":4294967294,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"64032906","hex":"483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"1000000","n":0,"spent":true,"spentTxId":"a0289b25937f9b682dd9f15a6c1af44eba405187bb5c23ea0f6310bb570c45e5","spentHeight":259026,"hex":"76a914cffef031eead7d332c245df1372dcf4980a0127c88ac","addresses":["aKgF22yWfjBqekrbkhkFYqenzsw9zfRch8"],"isAddress":true},{"value":"63028838","n":1,"spent":true,"spentTxId":"11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45","spentHeight":250864,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"fcfea4d17cde4cfc8d113d923e7e2978513e902448f1087fd448ae4162696f4f","blockHeight":244409,"confirmations":24731,"blockTime":1582620606,"value":"64028838","valueIn":"64032906","fees":"4068","hex":"01000000011e60be361fdabd33a545444bd7c0a6571e6e1fa9d92e65676da700d0aeebf75c010000006b483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15feffffff0240420f00000000001976a914cffef031eead7d332c245df1372dcf4980a0127c88ac66bec103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"4178eb3a84a34a9b508dbb61abbe725de115de2daea619e1cfa68eadf001fe51","version":1,"vin":[{"txid":"6de60b862ef752e24f1417c255f750e8e2e2b64ce4160eccbcdd82663a36daeb","n":0,"addresses":["aDVvWiM5PTv3QrUbrWQW3hPVLiFTMmzAHr"],"isAddress":true,"value":"100000","hex":"483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b"}],"vout":[{"value":"96544","n":0,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"e3d64bc33182f0b74b6247c7b37a9f8ff3c6852fe1c08116d460d067919345d1","blockHeight":241112,"confirmations":28028,"blockTime":1581616858,"value":"96544","valueIn":"100000","fees":"3456","hex":"0100000001ebda363a6682ddbccc0e16e44cb6e2e2e850f755c217144fe252f72e860be66d000000006b483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b000000000120790100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e","version":1,"vin":[{"txid":"5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241","vout":1,"n":0,"addresses":["aL96Xr2E1pMW3vcsZ5QV6BYLFE9jdCVBJL"],"isAddress":true,"value":"364036974","hex":"483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8"}],"vout":[{"value":"300000000","n":0,"spent":true,"spentTxId":"736d2ed9a2398511cc98f30df178db721716c1996fd8ab67970a5ac41a795e72","spentIndex":2,"spentHeight":239559,"hex":"76a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac","addresses":["aB3mWSqhFzszMJ3h8sxTedFYDhZCDBkeQT"],"isAddress":true},{"value":"64032906","n":1,"spent":true,"spentTxId":"86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef","spentHeight":244409,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"07d7c24529ee402be1a94b6b5a70d000c6002f0fa7201c1f5ef4ef7dd87f0117","blockHeight":239551,"confirmations":29589,"blockTime":1581138788,"value":"364032906","valueIn":"364036974","fees":"4068","hex":"010000000141320e1d67dca17a2d7107f1e3b378fbf443347afb21e16d130be718a8ce8254010000006b483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8000000000200a3e111000000001976a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac8a10d103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"},{"txid":"5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241","version":1,"vin":[{"txid":"c4f897a1d64e6c870184ff26a3ad8f5f4a94a6667f6d3486f21e52530d8ecea2","sequence":4294967294,"n":0,"addresses":["aMde4RuTWiNzoZN53SWZ7i7tKNbhSwt57U"],"isAddress":true,"value":"365041042","hex":"4730440220260b40074ffa84cf4f747433efdc524a347bf9f2b995a212a7c7fafeeb9105180220222edad73b70511698a9dc68ae246b78a7ba9daf3c1b44fb5d7fdd4d8d008d890121035209cb9a9c86a775cb9593b4c6fdde4f23e4bb4193cfeae0706080702189efa3"}],"vout":[{"value":"1000000","n":0,"spent":true,"spentTxId":"c70c9d3bf599a9e3553b6235f6468c69c1fa54aa0505e49d81e37aa1a749379a","spentHeight":238297,"hex":"76a91480be9e18824eae9cc7771291b7a017a458fb48b388ac","addresses":["aCTCaoLEy6ZbKQGKjBe1kprQ4foEa2cBVv"],"isAddress":true},{"value":"364036974","n":1,"spent":true,"spentTxId":"5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e","spentHeight":239551,"hex":"76a914d51315e0d5624c84e9da869bd34735926022ae5888ac","addresses":["aL96Xr2E1pMW3vcsZ5QV6BYLFE9jdCVBJL"],"isAddress":true}],"blockHash":"fc464897e8c6bcbd5bede4109a24075894a61d3a2d7aa06cc0bc1a37b07d1903","blockHeight":238210,"confirmations":30930,"blockTime":1580718580,"value":"365036974","valueIn":"365041042","fees":"4068","hex":"0100000001a2ce8e0d53521ef286346d7f66a6944a5f8fada326ff8401876c4ed6a197f8c4000000006a4730440220260b40074ffa84cf4f747433efdc524a347bf9f2b995a212a7c7fafeeb9105180220222edad73b70511698a9dc68ae246b78a7ba9daf3c1b44fb5d7fdd4d8d008d890121035209cb9a9c86a775cb9593b4c6fdde4f23e4bb4193cfeae0706080702189efa3feffffff0240420f00000000001976a91480be9e18824eae9cc7771291b7a017a458fb48b388ac6ec3b215000000001976a914d51315e0d5624c84e9da869bd34735926022ae5888ac00000000"},{"txid":"c4f897a1d64e6c870184ff26a3ad8f5f4a94a6667f6d3486f21e52530d8ecea2","version":1,"vin":[{"txid":"3054b05d5f9624264bf7bfbb140749472c58670cc935efa5aab4a96c6430ed19","sequence":4294967294,"n":0,"addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true,"value":"365045110","hex":"473044022062705d4b0f266a25646c410e3a735b7665dafb85655bf4b9f3ce89ecde4306f20220702f5fd1f3d6e593c3e3e9a37adf6431b1920b55151872dc9c8f4dc166df1a8f0121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15"}],"vout":[{"value":"365041042","n":0,"spent":true,"spentTxId":"5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241","spentHeight":238210,"hex":"76a914e5712d04a22c551a8261aea3f4a8d98ddb057f5988ac","addresses":["aMde4RuTWiNzoZN53SWZ7i7tKNbhSwt57U"],"isAddress":true}],"blockHash":"1afa27baa3146c5ae36cb93612f928b794b306d4d8b552636fb3f35891a7adb8","blockHeight":238176,"confirmations":30964,"blockTime":1580709451,"value":"365041042","valueIn":"365045110","fees":"4068","hex":"010000000119ed30646ca9b4aaa5ef35c90c67582c47490714bbbff74b2624965f5db05430000000006a473044022062705d4b0f266a25646c410e3a735b7665dafb85655bf4b9f3ce89ecde4306f20220702f5fd1f3d6e593c3e3e9a37adf6431b1920b55151872dc9c8f4dc166df1a8f0121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15feffffff019215c215000000001976a914e5712d04a22c551a8261aea3f4a8d98ddb057f5988ac00000000"},{"txid":"3054b05d5f9624264bf7bfbb140749472c58670cc935efa5aab4a96c6430ed19","version":1,"vin":[{"txid":"c7cd71424b7165ae60fe998767a43dab338915ef3215782ae7b9ba9710fd9aab","n":0,"addresses":["aDqeCrv3YqSr3UtBT9W6xnFNEJonV87mSt"],"isAddress":true,"value":"365048566","hex":"4730440220603f06106ee740b0399bc72c801fb7e4e3a907d06cd54c61dcac674cdd9cf3be02202ad273482c6300bae8f655523913845d50a2c805a173db3fb2c1bc65a2d894a701210296a3500dfacb901de8c43eb79b368bd7c710a65f6723d67ca51fa83728b8e402"}],"vout":[{"value":"365045110","n":0,"spent":true,"spentTxId":"c4f897a1d64e6c870184ff26a3ad8f5f4a94a6667f6d3486f21e52530d8ecea2","spentHeight":238176,"hex":"76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac","addresses":["a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn"],"isAddress":true}],"blockHash":"419b039bfb0cdbe1a507c6ba5c1fa2828e6fe1785b748a29eb243186ab60430b","blockHeight":238161,"confirmations":30979,"blockTime":1580704843,"value":"365045110","valueIn":"365048566","fees":"3456","hex":"0100000001ab9afd1097bab9e72a781532ef158933ab3da4678799fe60ae65714b4271cdc7000000006a4730440220603f06106ee740b0399bc72c801fb7e4e3a907d06cd54c61dcac674cdd9cf3be02202ad273482c6300bae8f655523913845d50a2c805a173db3fb2c1bc65a2d894a701210296a3500dfacb901de8c43eb79b368bd7c710a65f6723d67ca51fa83728b8e40200000000017625c215000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000"}],"usedTokens":52,"tokens":[{"type":"XPUBAddress","name":"a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn","path":"m/44'/136'/0'/0/0","transfers":18,"decimals":8,"balance":"63109110","totalReceived":"1565104974","totalSent":"1501995864"}]} diff --git a/mock/ext-api-data/zelcash-api_v2_address_t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa__details_txs.json b/mock/ext-api-data/zelcash-api_v2_address_t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa__details_txs.json new file mode 100644 index 000000000..66fe7e7a5 --- /dev/null +++ b/mock/ext-api-data/zelcash-api_v2_address_t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa__details_txs.json @@ -0,0 +1 @@ +{"page":1,"totalPages":12736,"itemsOnPage":10,"address":"t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa","balance":"900000590194","totalReceived":"1340993049284812","totalSent":"1340093048694618","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":127356,"transactions":[{"txid":"4ec60a6461233aef764b3b7701155d0c0701e064ad27b4864135e4819e46ed6a","version":4,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03c4340900324d696e6572732068747470733a2f2f326d696e6572732e636f6d"}],"vout":[{"value":"11250010000","n":0,"hex":"76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac","addresses":["t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa"]},{"value":"562500000","n":1,"hex":"76a914ab8196e08b70ec6ec9b487a9546b554933f0920c88ac","addresses":["t1ZWSoAYkMLUyWTSF1KydkEeYxffvTCmGu3"]},{"value":"937500000","n":2,"hex":"76a914b8a6ab978880f5241e9488f3547ae18a2ea9ecc788ac","addresses":["t1ahx15yHu6SFQXvss3W44GZC28SoBYjGJH"]},{"value":"2250000000","n":3,"hex":"76a914680be69289a1f0b5a67c62576513d8467172a43a88ac","addresses":["t1TMkYABufakzp4sSGAQQ7d4AHdKxkxv34d"]}],"blockHash":"0000007a7284c006997f38cb798f52e64c20122bbd606dfb519bfa446c1d51ad","blockHeight":603332,"confirmations":2,"blockTime":1590069744,"value":"15000010000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003c4340900324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0490878d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914ab8196e08b70ec6ec9b487a9546b554933f0920c88ac601de137000000001976a914b8a6ab978880f5241e9488f3547ae18a2ea9ecc788ac80461c86000000001976a914680be69289a1f0b5a67c62576513d8467172a43a88ac00000000000000000000000000000000000000"},{"txid":"c8899f9bd2f80474383d72daa2bb8b81cac3e66d0c4fa543f00471d249931549","version":4,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03c3340900324d696e6572732068747470733a2f2f326d696e6572732e636f6d"}],"vout":[{"value":"11250001000","n":0,"hex":"76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac","addresses":["t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa"]},{"value":"562500000","n":1,"hex":"76a914ded2dec28f6414578208d69e6305319ccaf9dc1f88ac","addresses":["t1eBndSK9bCRJ82wpxWxjqWoRno6zKjxJjn"]},{"value":"937500000","n":2,"hex":"76a914422fd29f94a792a3c189b57d52b74d5c45091b6588ac","addresses":["t1PuZtn9GEaJk7PbqzWa7oiW4MqQRhCE6DU"]},{"value":"2250000000","n":3,"hex":"76a9141de04cabb3724f4c750fb62f0546a1f70fd6426088ac","addresses":["t1LbaJVztxuY4oSbXHKBFmNfqrASM8Wsv5Y"]}],"blockHash":"00000011d100045d55c701cfdedaab7e62ca29fb581a51ff6c924393f695d045","blockHeight":603331,"confirmations":3,"blockTime":1590069594,"value":"15000001000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003c3340900324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0468648d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914ded2dec28f6414578208d69e6305319ccaf9dc1f88ac601de137000000001976a914422fd29f94a792a3c189b57d52b74d5c45091b6588ac80461c86000000001976a9141de04cabb3724f4c750fb62f0546a1f70fd6426088ac00000000000000000000000000000000000000"},{"txid":"91132541ca3c72884ba0bba9a8db785e2e45b5425d20a5c499dca5fac8128dc7","version":4,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03c2340900324d696e6572732068747470733a2f2f326d696e6572732e636f6d"}],"vout":[{"value":"11250000000","n":0,"hex":"76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac","addresses":["t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa"]},{"value":"562500000","n":1,"hex":"76a914c85c93462875819a331a9ae7dc36f12bbed327ef88ac","addresses":["t1c923wo15tdZg3ziVPzL3GbYX6jzJEG377"]},{"value":"937500000","n":2,"hex":"76a914fa0fe057eb22bd5df1022ddf5658d05fae13857988ac","addresses":["t1gfoxQCK8yg2PLSYWy8DXMmQZFpw11CDiH"]},{"value":"2250000000","n":3,"hex":"76a914c8e005c8ea2bd432970172ef1d6d90bd221ee93a88ac","addresses":["t1cBjX4hVfYMBPE3T6FJbtRWvu9YQg4syc8"]}],"blockHash":"0000009e780901d002b05706e0bf663443efc01e7beb7105ab3a2bad0a02e4ad","blockHeight":603330,"confirmations":4,"blockTime":1590069261,"value":"15000000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003c2340900324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0480608d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914c85c93462875819a331a9ae7dc36f12bbed327ef88ac601de137000000001976a914fa0fe057eb22bd5df1022ddf5658d05fae13857988ac80461c86000000001976a914c8e005c8ea2bd432970172ef1d6d90bd221ee93a88ac00000000000000000000000000000000000000"},{"txid":"0c2fa3526e6c6236ca0047cc6e0f455e36607ad0abfbde4ebd62d47451cab3d5","version":4,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03c1340900324d696e6572732068747470733a2f2f326d696e6572732e636f6d"}],"vout":[{"value":"11250040721","n":0,"hex":"76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac","addresses":["t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa"]},{"value":"562500000","n":1,"hex":"76a9145f3f89ba88e3d738f97e5905e33c799fee3a17ca88ac","addresses":["t1SZEKFsjzQSctXnVc3da5RRxMkcVmqvgPx"]},{"value":"937500000","n":2,"hex":"76a9144089337f98c9b083d3f96735176c7a6813cbbe1e88ac","addresses":["t1PkqcWvupQaBZ2g26UAuhH3nvWSqE1iH6z"]},{"value":"2250000000","n":3,"hex":"76a914902d58ccbb395ab2f56e5e400f3bba367113865b88ac","addresses":["t1X1wdiSBDPd1C6ujaxNgzH8a5Tj8TM6LNb"]}],"blockHash":"000000339a081532aff027fe30e7ae60d722b29fcbf906b43221daf78ee045eb","blockHeight":603329,"confirmations":5,"blockTime":1590069102,"value":"15000040721","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003c1340900324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0491ff8d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a9145f3f89ba88e3d738f97e5905e33c799fee3a17ca88ac601de137000000001976a9144089337f98c9b083d3f96735176c7a6813cbbe1e88ac80461c86000000001976a914902d58ccbb395ab2f56e5e400f3bba367113865b88ac00000000000000000000000000000000000000"},{"txid":"76b5298831a3eb8919c34cfd6e434ba1b319ad9361341fd446d0f60c12e64960","version":4,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03c0340900324d696e6572732068747470733a2f2f326d696e6572732e636f6d"}],"vout":[{"value":"11250010000","n":0,"hex":"76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac","addresses":["t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa"]},{"value":"562500000","n":1,"hex":"76a91472b3326f7c20cda07ea9e337f2715313b3b3cd1488ac","addresses":["t1UL5i2ke2H2CCmaCimWM5xNf97SpcUZy89"]},{"value":"937500000","n":2,"hex":"76a9145aa0cd79ab6f52aad05cb950b2e1215827c2f9eb88ac","addresses":["t1S8oTN2wBzXnWSwz7TpsSsQkNiYJYqeHRQ"]},{"value":"2250000000","n":3,"hex":"76a914c2af4d039c06fc03721a0a7c623ec2764211b25188ac","addresses":["t1bd16fbkY2mS54ka6zKeVb8rwvWQ76r5iS"]}],"blockHash":"0000001f328281cf72af7f273333e2a67e708e13d08bab269a732ec9d2b93f14","blockHeight":603328,"confirmations":6,"blockTime":1590068652,"value":"15000010000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003c0340900324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0490878d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a91472b3326f7c20cda07ea9e337f2715313b3b3cd1488ac601de137000000001976a9145aa0cd79ab6f52aad05cb950b2e1215827c2f9eb88ac80461c86000000001976a914c2af4d039c06fc03721a0a7c623ec2764211b25188ac00000000000000000000000000000000000000"},{"txid":"d8c2edd3a3e73e823bdfb53e0a16ea78513c3fb36ccf3a5227fefeaf3d53b4cb","version":4,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03bf340900324d696e6572732068747470733a2f2f326d696e6572732e636f6d"}],"vout":[{"value":"11250000000","n":0,"hex":"76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac","addresses":["t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa"]},{"value":"562500000","n":1,"hex":"76a914e11f474e1e6a3d48fc20d83f853f95620467d28388ac","addresses":["t1ePwWmWS2T5PRo4z9zKcvNnHam91tcupnm"]},{"value":"937500000","n":2,"hex":"76a9144d8ea2df3c9c44e23ca0eddf148f4e6bfaa3b4bd88ac","addresses":["t1QwgueMBetkiPTkJMowkSFgohiT68p54UD"]},{"value":"2250000000","n":3,"hex":"76a91468c01116ec9b9811267dadf5c37735ffe57ab92688ac","addresses":["t1TRUNKQMx1DVzym4d2Ay5E1dudEcHiyk9C"]}],"blockHash":"000000d2350de7e8ef59c2881d53f30876324def22d63ffc26024ef866621127","blockHeight":603327,"confirmations":7,"blockTime":1590068550,"value":"15000000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003bf340900324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0480608d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914e11f474e1e6a3d48fc20d83f853f95620467d28388ac601de137000000001976a9144d8ea2df3c9c44e23ca0eddf148f4e6bfaa3b4bd88ac80461c86000000001976a91468c01116ec9b9811267dadf5c37735ffe57ab92688ac00000000000000000000000000000000000000"},{"txid":"0712452932e94b21106e3a729bad1ac2dc1132dbbd8b510828de507c73af5362","version":4,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03be340900324d696e6572732068747470733a2f2f326d696e6572732e636f6d"}],"vout":[{"value":"11250020000","n":0,"hex":"76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac","addresses":["t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa"]},{"value":"562500000","n":1,"hex":"76a914c718ff5e608276a84b76f286408340ce17bf7ac988ac","addresses":["t1c2LRNMLZb4zs9oecko6pHv14QWUKQwJkd"]},{"value":"937500000","n":2,"hex":"76a914334765007510b372da5e5ef25e654b01ca092e3f88ac","addresses":["t1NYjzhThu7YdTSK48tGEdnRc9eTkDfWTxb"]},{"value":"2250000000","n":3,"hex":"76a914eb89013136c8d505e7e2d50205e780c3461d7b1188ac","addresses":["t1fLzvfbKnNYeQBUB8aCEYVnyXXvxUtbVja"]}],"blockHash":"00000082b40daa8db4cd0f75c0893f59c9a6afd89a0e1f44abf3885bd59dd85b","blockHeight":603326,"confirmations":8,"blockTime":1590068543,"value":"15000020000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003be340900324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff04a0ae8d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914c718ff5e608276a84b76f286408340ce17bf7ac988ac601de137000000001976a914334765007510b372da5e5ef25e654b01ca092e3f88ac80461c86000000001976a914eb89013136c8d505e7e2d50205e780c3461d7b1188ac00000000000000000000000000000000000000"},{"txid":"fef38b2bf0644a076771a3915150342fb6c1ed6dea3cc76b9c5c617fb377d56c","version":4,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03bc340900324d696e6572732068747470733a2f2f326d696e6572732e636f6d"}],"vout":[{"value":"11250000000","n":0,"hex":"76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac","addresses":["t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa"]},{"value":"562500000","n":1,"hex":"76a914fcdbb728a535aec6d81b366fd22af437457a385488ac","addresses":["t1gvbVmu4E8sDziJXPCWd3ggdBUpbZ8kVN8"]},{"value":"937500000","n":2,"hex":"76a914f9c4b9822fa37c937fdb78602cebd222c940d49588ac","addresses":["t1geFvmZhWNitgmgipJLnswq6AHHuj777Vp"]},{"value":"2250000000","n":3,"hex":"76a9143d94fc18dd332c386014f9e5b05cce17710a2ce688ac","addresses":["t1PVDhgMueDh8vY3JfkZoXcGrwATCfkwaL9"]}],"blockHash":"0000005936823db3f9a971fb8d3c3fbef6ea9da0761d88815836ce9dc30ae937","blockHeight":603324,"confirmations":10,"blockTime":1590067974,"value":"15000000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003bc340900324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0480608d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914fcdbb728a535aec6d81b366fd22af437457a385488ac601de137000000001976a914f9c4b9822fa37c937fdb78602cebd222c940d49588ac80461c86000000001976a9143d94fc18dd332c386014f9e5b05cce17710a2ce688ac00000000000000000000000000000000000000"},{"txid":"6356612d62b81566774bee79a4a23689a218558d92ab3a93f84baa396c19bb54","version":4,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03bb340900324d696e6572732068747470733a2f2f326d696e6572732e636f6d"}],"vout":[{"value":"11250000000","n":0,"hex":"76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac","addresses":["t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa"]},{"value":"562500000","n":1,"hex":"76a91402eaf41ee9372e92e25d25bf196ed82dee08137388ac","addresses":["t1J92pafqy7CXPdPfGYPKw7NXpU4M5594zv"]},{"value":"937500000","n":2,"hex":"76a91493e5a686a7b343097fb7325840cb098bd4f85f4e88ac","addresses":["t1XMcSvvj4aLbwzWpeMJWvwnesK2pcWsVoM"]},{"value":"2250000000","n":3,"hex":"76a914b42021e23a66f80148741e9ce5d08b592bba0ef088ac","addresses":["t1aJ28TfBXyvZaAsxD8GnJdfjqpx72yRCsA"]}],"blockHash":"00000013e741f51d2c17c61ec1f2739fb26df31a51ed296534c9c426027fcf30","blockHeight":603323,"confirmations":11,"blockTime":1590067957,"value":"15000000000","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003bb340900324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0480608d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a91402eaf41ee9372e92e25d25bf196ed82dee08137388ac601de137000000001976a91493e5a686a7b343097fb7325840cb098bd4f85f4e88ac80461c86000000001976a914b42021e23a66f80148741e9ce5d08b592bba0ef088ac00000000000000000000000000000000000000"},{"txid":"bc4de1a0197710be803bddeb6e4f24e5438abede4c2c68c623f4c5cc77ee28e2","version":4,"vin":[{"sequence":4294967295,"n":0,"coinbase":"03b8340900324d696e6572732068747470733a2f2f326d696e6572732e636f6d"}],"vout":[{"value":"11250010245","n":0,"hex":"76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac","addresses":["t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa"]},{"value":"562500000","n":1,"hex":"76a914d900399ef7162894cc2a2865712fcbc6279b969788ac","addresses":["t1dezubrWdABDDhNL9TLn8nfNwQovhB2FXF"]},{"value":"937500000","n":2,"hex":"76a91483f17701299e54c4b8f1c97c5935ec3bdc3cb56e88ac","addresses":["t1VuFnjm6wQCzPzVoZWVcCKZ4ybqk4q9JWW"]},{"value":"2250000000","n":3,"hex":"76a914bd05fba3d61efdff58aa527d18e8d05a36cd05c688ac","addresses":["t1b74tJ6FNsKS5SMScmXRtqVi5o6ZHGnxv1"]}],"blockHash":"0000001259bdff5b52c495e48ccb3bc6de494b6f8bc0d897478996bc4d683487","blockHeight":603320,"confirmations":14,"blockTime":1590067530,"value":"15000010245","valueIn":"0","fees":"0","hex":"0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff2003b8340900324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0485888d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914d900399ef7162894cc2a2865712fcbc6279b969788ac601de137000000001976a91483f17701299e54c4b8f1c97c5935ec3bdc3cb56e88ac80461c86000000001976a914bd05fba3d61efdff58aa527d18e8d05a36cd05c688ac00000000000000000000000000000000000000"}]} diff --git a/mock/ext-api-data/zelcash-api_v2_xpub_xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf__details_txs.json b/mock/ext-api-data/zelcash-api_v2_xpub_xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf__details_txs.json new file mode 100644 index 000000000..463036686 --- /dev/null +++ b/mock/ext-api-data/zelcash-api_v2_xpub_xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf__details_txs.json @@ -0,0 +1,1463 @@ +{ + "page": 1, + "totalPages": 1, + "itemsOnPage": 1000, + "address": "xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf", + "balance": "9209317640", + "totalReceived": "135114824440", + "totalSent": "125905506800", + "unconfirmedBalance": "0", + "unconfirmedTxs": 0, + "txs": 29, + "transactions": [ + { + "txid": "c7beecf9ee82e09319012defde98abe58f4227265a3946d2052019c477b930e9", + "version": 4, + "vin": [ + { + "txid": "16757f263140419a557425ec7d286995491160ceebca53ac07bbe3021a49d93c", + "sequence": 2147483641, + "n": 0, + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ], + "value": "12300000", + "hex": "483045022100c91ed67b1f0859b559bf83f4ae94b46d8249117b3e6263f20dffb80979eaaca0022012bebce65ff538408acadd8d86ad23021d08dbe5026d46ad781e81b8c8e793bb012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" + }, + { + "txid": "640ea080f060fbfcc6722f861c93483551a831020f6731a37ba5383da71b4972", + "sequence": 2147483642, + "n": 1, + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ], + "value": "100000", + "hex": "483045022100f702c86f237035747db777e28cddc7f1d00bb608076eb0a3b90e38dfb9d63627022075bbb974a89ade1bfbf36ab249c42186ec21421454c0b170126b3cd0d6b95f6a012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" + }, + { + "txid": "640ea080f060fbfcc6722f861c93483551a831020f6731a37ba5383da71b4972", + "vout": 1, + "sequence": 2147483643, + "n": 2, + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ], + "value": "890000", + "hex": "47304402206e642c188a9a3cc160edacdf637586fbf621ebd83b9bcd3bf69809259cc1bcaa02200b526e4011d173bf454b3592a9e134c94af4bc7ef5468cbdd450de8ebf0ed62a012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" + }, + { + "txid": "a3db9e10aa146805477b9012130e6f68d473975095b82c7e6e6ab5f409da9eef", + "vout": 1, + "sequence": 2147483644, + "n": 3, + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ], + "value": "898950000", + "hex": "483045022100aaa260947b85fe11edd6ce9b71c496cbe00c148d97ebeeefedbd743591b63f95022054e4938c4cee3587ed625563ef732dc097252286b5feb98280f5935ee53f9924012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" + }, + { + "txid": "d6669b431916c5794fe1be5ffb0594aed0a3828c9ff7614c2f2a3e1eacce7360", + "vout": 1, + "sequence": 2147483645, + "n": 4, + "addresses": [ + "t1ZdL1GA9PFrU2sPqWZGBCjbbmb6bKoaLRR" + ], + "value": "8296087640", + "hex": "4830450221009b6e1d3b1d5d578d4c7f6f34be73de3764c83e5a55b663e8eafc66ac2722d1e5022020e420e0b21989791775f53db76c30373b790f75a4009a815919110c688fb33d012102986c87346f73a3ac0b601782d2463b1e6d69f75a6ffac305319fa27d6e4ffffc" + }, + { + "txid": "d6669b431916c5794fe1be5ffb0594aed0a3828c9ff7614c2f2a3e1eacce7360", + "sequence": 2147483646, + "n": 5, + "addresses": [ + "t1c3uqCTSGfyia7rotNoNLm7cV7UqCpXT21" + ], + "value": "1000000", + "hex": "47304402201f3f367f2b476bb333b1bd7ed91648b44a88598599a20153f6b4a5fea423369702203a16248718cfaac42ab4239708d6f327c0fe6c8e49527f451f2de0fed4c2c0040121028eb47e98c32ad1d7a2ac0e1524431b2c7fb2142b3a036adaab3aaf07be82c026" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "hex": "76a914ec5240b297e3c8e6f0b38103c43686d618c91f8d88ac", + "addresses": [ + "t1fRA1dKnK7Z78ZhMqKP2VxdS9VfYeGvLYm" + ] + }, + { + "value": "9208317640", + "n": 1, + "hex": "76a9140f6081e0b391e1f5795c4ff86b3edad2b267196f88ac", + "addresses": [ + "t1KGukfFELYq5cYpCgieyes3dCuaxNMUcb1" + ] + } + ], + "blockHash": "00000002031260dc8b9ec8c19aa16a2aabd2edc6e21fa57df7fad0fa963f319d", + "blockHeight": 562339, + "confirmations": 35171, + "blockTime": 1585117482, + "value": "9209317640", + "valueIn": "9209327640", + "fees": "10000", + "hex": "0400008085202f89063cd9491a02e3bb07ac53caebce6011499569287dec2574559a414031267f7516000000006b483045022100c91ed67b1f0859b559bf83f4ae94b46d8249117b3e6263f20dffb80979eaaca0022012bebce65ff538408acadd8d86ad23021d08dbe5026d46ad781e81b8c8e793bb012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644f9ffff7f72491ba73d38a57ba331670f0231a8513548931c862f72c6fcfb60f080a00e64000000006b483045022100f702c86f237035747db777e28cddc7f1d00bb608076eb0a3b90e38dfb9d63627022075bbb974a89ade1bfbf36ab249c42186ec21421454c0b170126b3cd0d6b95f6a012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644faffff7f72491ba73d38a57ba331670f0231a8513548931c862f72c6fcfb60f080a00e64010000006a47304402206e642c188a9a3cc160edacdf637586fbf621ebd83b9bcd3bf69809259cc1bcaa02200b526e4011d173bf454b3592a9e134c94af4bc7ef5468cbdd450de8ebf0ed62a012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644fbffff7fef9eda09f4b56a6e7e2cb895509773d4686f0e1312907b47056814aa109edba3010000006b483045022100aaa260947b85fe11edd6ce9b71c496cbe00c148d97ebeeefedbd743591b63f95022054e4938c4cee3587ed625563ef732dc097252286b5feb98280f5935ee53f9924012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644fcffff7f6073ceac1e3e2a2f4c61f79f8c82a3d0ae9405fb5fbee14f79c51619439b66d6010000006b4830450221009b6e1d3b1d5d578d4c7f6f34be73de3764c83e5a55b663e8eafc66ac2722d1e5022020e420e0b21989791775f53db76c30373b790f75a4009a815919110c688fb33d012102986c87346f73a3ac0b601782d2463b1e6d69f75a6ffac305319fa27d6e4ffffcfdffff7f6073ceac1e3e2a2f4c61f79f8c82a3d0ae9405fb5fbee14f79c51619439b66d6000000006a47304402201f3f367f2b476bb333b1bd7ed91648b44a88598599a20153f6b4a5fea423369702203a16248718cfaac42ab4239708d6f327c0fe6c8e49527f451f2de0fed4c2c0040121028eb47e98c32ad1d7a2ac0e1524431b2c7fb2142b3a036adaab3aaf07be82c026feffff7f0240420f00000000001976a914ec5240b297e3c8e6f0b38103c43686d618c91f8d88acc8c6db24020000001976a9140f6081e0b391e1f5795c4ff86b3edad2b267196f88ac00000000000000000000000000000000000000" + }, + { + "txid": "16757f263140419a557425ec7d286995491160ceebca53ac07bbe3021a49d93c", + "version": 4, + "vin": [ + { + "txid": "b8843a9c37d921ef3d3f22e0ed7a4241c819403148e53f7da52000e194688af0", + "n": 0, + "addresses": [ + "t1fu9mBwE7T9MYcLMiQjcXiS2tfUFcJK14F" + ], + "value": "100000000", + "hex": "483045022100c61a676888765a783afeb24cf7351bfa55213c99979e4472db6f09c4083364e9022033065f3d7ec5511fb29349a698b82866d3d8106284e991a9984e26ef7a430ede012102a5fd93af1e208f0b9652a21674f5800d60c83323406ebd2c69be74dfb493ea1e" + } + ], + "vout": [ + { + "value": "12300000", + "n": 0, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + }, + { + "value": "87690000", + "n": 1, + "hex": "76a9147f1271095e3e2063ca859588b40dad6c13995dce88ac", + "addresses": [ + "t1VTVv3Ebwo2zvEdE3PDrJyTATKDTXg7CvB" + ] + } + ], + "blockHash": "000000835a29d9743a37f7fa03613163a206ede7adbdb33b2626540697cc4e24", + "blockHeight": 561716, + "confirmations": 35794, + "blockTime": 1585043485, + "value": "99990000", + "valueIn": "100000000", + "fees": "10000", + "hex": "0400008085202f8901f08a6894e10020a57d3fe548314019c841427aede0223f3def21d9379c3a84b8000000006b483045022100c61a676888765a783afeb24cf7351bfa55213c99979e4472db6f09c4083364e9022033065f3d7ec5511fb29349a698b82866d3d8106284e991a9984e26ef7a430ede012102a5fd93af1e208f0b9652a21674f5800d60c83323406ebd2c69be74dfb493ea1e0000000002e0aebb00000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac100b3a05000000001976a9147f1271095e3e2063ca859588b40dad6c13995dce88ac00000000000000000000000000000000000000" + }, + { + "txid": "640ea080f060fbfcc6722f861c93483551a831020f6731a37ba5383da71b4972", + "version": 4, + "vin": [ + { + "txid": "a3db9e10aa146805477b9012130e6f68d473975095b82c7e6e6ab5f409da9eef", + "n": 0, + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ], + "value": "1000000", + "hex": "47304402205f7e4f5c17f6bf9880bd0afecec581253419a7b94a440fc9d4a4f4c35ee5b69102203a5c1ba8fc40098e9de6d4df71bb364e9028ddf9eb6ec31e42a1293c19170d8d012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + }, + { + "value": "890000", + "n": 1, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + } + ], + "blockHash": "0000004957cd52c4654e44b0a02cd33be907ae3ae47949e44984cccaf0e34e96", + "blockHeight": 560762, + "confirmations": 36748, + "blockTime": 1584928030, + "value": "990000", + "valueIn": "1000000", + "fees": "10000", + "hex": "0400008085202f8901ef9eda09f4b56a6e7e2cb895509773d4686f0e1312907b47056814aa109edba3000000006a47304402205f7e4f5c17f6bf9880bd0afecec581253419a7b94a440fc9d4a4f4c35ee5b69102203a5c1ba8fc40098e9de6d4df71bb364e9028ddf9eb6ec31e42a1293c19170d8d012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e366440000000002a0860100000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac90940d00000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac00000000000000000000000000000000000000" + }, + { + "txid": "a3db9e10aa146805477b9012130e6f68d473975095b82c7e6e6ab5f409da9eef", + "version": 4, + "vin": [ + { + "txid": "2de19629bbf78af114ff9cf3332229dc336be4758481b72828f1bd786e8cc41e", + "vout": 1, + "n": 0, + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ], + "value": "899960000", + "hex": "4830450221008f14795cde861210cbd9a1c3d89a29f0efe5c3cdceb2049795d5a9a84cc2571f02203c4e360575b7e5a45b067382b7d4e3fadbc80382eaa32e08a0bba46ae9bc7cb9012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + }, + { + "value": "898950000", + "n": 1, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + } + ], + "blockHash": "0000008979ea8aac4d45ae6b5db721845d2d909e723b8fbb87d81f528a7ceefe", + "blockHeight": 558864, + "confirmations": 38646, + "blockTime": 1584697832, + "value": "899950000", + "valueIn": "899960000", + "fees": "10000", + "hex": "0400008085202f89011ec48c6e78bdf12828b7818475e46b33dc292233f39cff14f18af7bb2996e12d010000006b4830450221008f14795cde861210cbd9a1c3d89a29f0efe5c3cdceb2049795d5a9a84cc2571f02203c4e360575b7e5a45b067382b7d4e3fadbc80382eaa32e08a0bba46ae9bc7cb9012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644000000000240420f00000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac70e39435000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac00000000000000000000000000000000000000" + }, + { + "txid": "2de19629bbf78af114ff9cf3332229dc336be4758481b72828f1bd786e8cc41e", + "version": 4, + "vin": [ + { + "txid": "7db9135b1dabcecccff9e4d403802d1bf0d7850438233b3091b876331bab551b", + "n": 0, + "addresses": [ + "t1MpHLd2vryyTufEMF3WBHy7VP63YKigi53" + ], + "value": "999970000", + "hex": "473044022040534cefd8cfbe8f2705032a3636067fb8612ec3449f75699fcd894e5f2dc9960220363c26ddbbdb840fc76fbb950aecbfd6fa7d03e64da1c5890c302f0bb6f007a8012103d6bf5faa2c95ae8c4572f0755f45dba20dcd806ef8344a5dc2a54996874661c4" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "hex": "76a914a394f62bbe0a47af97171e99bd8ff4fed9cae33188ac", + "addresses": [ + "t1YnYbdwU1ReMUbN46byAQNtnDPqMRYxFPJ" + ] + }, + { + "value": "899960000", + "n": 1, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + } + ], + "blockHash": "0000007f0db0ed2ac5f5747e7746dc5e016e1f2a84df54115e85eee4d7aecb3b", + "blockHeight": 547987, + "confirmations": 49523, + "blockTime": 1583385317, + "value": "999960000", + "valueIn": "999970000", + "fees": "10000", + "hex": "0400008085202f89011b55ab1b3376b891303b23380485d7f01b2d8003d4e4f9cfccceab1d5b13b97d000000006a473044022040534cefd8cfbe8f2705032a3636067fb8612ec3449f75699fcd894e5f2dc9960220363c26ddbbdb840fc76fbb950aecbfd6fa7d03e64da1c5890c302f0bb6f007a8012103d6bf5faa2c95ae8c4572f0755f45dba20dcd806ef8344a5dc2a54996874661c4000000000200e1f505000000001976a914a394f62bbe0a47af97171e99bd8ff4fed9cae33188acc04ca435000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac00000000000000000000000000000000000000" + }, + { + "txid": "7db9135b1dabcecccff9e4d403802d1bf0d7850438233b3091b876331bab551b", + "version": 4, + "vin": [ + { + "txid": "3ce3913910d9aab7ddb308b16abd6d5d66c258737b5f86e829cc741fa317820b", + "n": 0, + "addresses": [ + "t1YnYbdwU1ReMUbN46byAQNtnDPqMRYxFPJ" + ], + "value": "999980000", + "hex": "483045022100fdf9542e8c44a218601d427ac9d8262866083c3ac1312c1448c345ed54782901022077a4c5e1d22657e000a2c76dc6f873fcb70b7298bd627dd3dc7bb24fa6175ab10121033985b538c7c62cd419a5b24e0dd8d322174303f376e025fddd1f19da2cebcc50" + } + ], + "vout": [ + { + "value": "999970000", + "n": 0, + "spent": true, + "hex": "76a9142b3fac242eb3d7e20130082190605a5f7750037788ac", + "addresses": [ + "t1MpHLd2vryyTufEMF3WBHy7VP63YKigi53" + ] + } + ], + "blockHash": "00000021b6af345a3d3010cdf9811fa9ca1f1163841519f2906ababa766b21ec", + "blockHeight": 494906, + "confirmations": 102604, + "blockTime": 1576977235, + "value": "999970000", + "valueIn": "999980000", + "fees": "10000", + "hex": "0400008085202f89010b8217a31f74cc29e8865f7b7358c2665d6dbd6ab108b3ddb7aad9103991e33c000000006b483045022100fdf9542e8c44a218601d427ac9d8262866083c3ac1312c1448c345ed54782901022077a4c5e1d22657e000a2c76dc6f873fcb70b7298bd627dd3dc7bb24fa6175ab10121033985b538c7c62cd419a5b24e0dd8d322174303f376e025fddd1f19da2cebcc500000000001d0549a3b000000001976a9142b3fac242eb3d7e20130082190605a5f7750037788ac00000000000000000000000000000000000000" + }, + { + "txid": "d6669b431916c5794fe1be5ffb0594aed0a3828c9ff7614c2f2a3e1eacce7360", + "version": 4, + "vin": [ + { + "txid": "b8843a9c37d921ef3d3f22e0ed7a4241c819403148e53f7da52000e194688af0", + "vout": 1, + "n": 0, + "addresses": [ + "t1JF7Y8w4gG9DCKRq3dkqgAPnhFaRZ5CpYP" + ], + "value": "8297097640", + "hex": "483045022100f8a66fee4cfd5e1f58539bfcc0b901c0197a2f92c3e667665ead8ae7b589a72b02202d17a5fc783fd7ece35682d967f7fe0fd74899feefe8751cc3946bd538cb91f701210308fcc9e30b408352f32f7899b27bce32569ed790ae582220880dd2cb8104dbea" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "hex": "76a914c7654db037525b8de1a9e925f8aa8df9a948170c88ac", + "addresses": [ + "t1c3uqCTSGfyia7rotNoNLm7cV7UqCpXT21" + ] + }, + { + "value": "8296087640", + "n": 1, + "spent": true, + "hex": "76a914acced4f6d3ae68dfe384c349a95475dbd2ea6eba88ac", + "addresses": [ + "t1ZdL1GA9PFrU2sPqWZGBCjbbmb6bKoaLRR" + ] + } + ], + "blockHash": "000000143de9914e1b7b3a86bdfada47bfa68b7cf50a8b7950a2ff65b7ea8895", + "blockHeight": 488284, + "confirmations": 109226, + "blockTime": 1576179943, + "value": "8297087640", + "valueIn": "8297097640", + "fees": "10000", + "hex": "0400008085202f8901f08a6894e10020a57d3fe548314019c841427aede0223f3def21d9379c3a84b8010000006b483045022100f8a66fee4cfd5e1f58539bfcc0b901c0197a2f92c3e667665ead8ae7b589a72b02202d17a5fc783fd7ece35682d967f7fe0fd74899feefe8751cc3946bd538cb91f701210308fcc9e30b408352f32f7899b27bce32569ed790ae582220880dd2cb8104dbea000000000240420f00000000001976a914c7654db037525b8de1a9e925f8aa8df9a948170c88ac58407cee010000001976a914acced4f6d3ae68dfe384c349a95475dbd2ea6eba88ac00000000000000000000000000000000000000" + }, + { + "txid": "b8843a9c37d921ef3d3f22e0ed7a4241c819403148e53f7da52000e194688af0", + "version": 4, + "vin": [ + { + "txid": "7feac61d5721b3248fe5165666ccbc0911c1dcfd66a335c7c4e239e4b29deeb2", + "n": 0, + "addresses": [ + "t1a6HWWPH7TgJVhqjHYoNu4F7SPHZaLGuBg" + ], + "value": "8397107640", + "hex": "4830450221009356bcac0f406e79e2bb61d7566e5d60bed87a0f7683024e343ea7ff5bccb6da022031ccc587fa326087d6319190127fbd71ba1c3f98aeb5e4eb3343b8c2d76a3e2a012102c9764269807a6f8600a14e15ea90adbcb7608dd022c00e8507468436ec5e2cf5" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a914f19db11ddaf48cb289080b98d132257bcd534dbd88ac", + "addresses": [ + "t1fu9mBwE7T9MYcLMiQjcXiS2tfUFcJK14F" + ] + }, + { + "value": "8297097640", + "n": 1, + "spent": true, + "hex": "76a914041162f12c4959cfa081f551a451fe23ed94717688ac", + "addresses": [ + "t1JF7Y8w4gG9DCKRq3dkqgAPnhFaRZ5CpYP" + ] + } + ], + "blockHash": "00000055b79ef86e240667b6a507f2d64359a7ef827e66f03a171b9c86b4c3e1", + "blockHeight": 488122, + "confirmations": 109388, + "blockTime": 1576160510, + "value": "8397097640", + "valueIn": "8397107640", + "fees": "10000", + "hex": "0400008085202f8901b2ee9db2e439e2c4c735a366fddcc11109bccc665616e58f24b321571dc6ea7f000000006b4830450221009356bcac0f406e79e2bb61d7566e5d60bed87a0f7683024e343ea7ff5bccb6da022031ccc587fa326087d6319190127fbd71ba1c3f98aeb5e4eb3343b8c2d76a3e2a012102c9764269807a6f8600a14e15ea90adbcb7608dd022c00e8507468436ec5e2cf5000000000200e1f505000000001976a914f19db11ddaf48cb289080b98d132257bcd534dbd88aca8a98bee010000001976a914041162f12c4959cfa081f551a451fe23ed94717688ac00000000000000000000000000000000000000" + }, + { + "txid": "7feac61d5721b3248fe5165666ccbc0911c1dcfd66a335c7c4e239e4b29deeb2", + "version": 4, + "vin": [ + { + "txid": "3b75d26bc474aaf1bab27fb890c439e99c4a83092797e8acfcbfa88713d99a4f", + "n": 0, + "addresses": [ + "t1Ps4cyeWT5sTxoNabuMmhRD3c2j5SdmVP8" + ], + "value": "100000", + "hex": "47304402201bfa05833ba6ef1c893a1cfab205d7931d9f5e5c41bdcdce503645c2ca170cf502206bbcfb59d76a7b3324bb34678f9b3dc3fbb769ee2b4253982ccb2bd4dd23407c012103758ac64bf8fef07ca3eff6cdf48255d53e0c6c559bed57a2b45e03b28727afcc" + }, + { + "txid": "88450e5030b295935e6dd558bc08e1a0af70f42e0cd3c9eda75c4cbd1e1da728", + "n": 1, + "addresses": [ + "t1PJCnDXNZuoKU5sCAJm15YGqnQdJTQw4Jy" + ], + "value": "1000000", + "hex": "47304402200e6be05443eade67815792991cea7c7a217ab6add0600e96d9603b25902f15140220699d63231f9e93c163ff0d740af1593e15ccc1b9a8f994e4537f3ec8659d96ec01210268e3b9550b815d540c9095d8f9851add0b783c6e37646f2b24a4c9fb5bbf1b64" + }, + { + "txid": "88450e5030b295935e6dd558bc08e1a0af70f42e0cd3c9eda75c4cbd1e1da728", + "vout": 1, + "n": 2, + "addresses": [ + "t1TDT81WmcqUXeBxV1JjTEb4usYbMPtqBJU" + ], + "value": "8880000", + "hex": "4730440220399cf1468ec607160f21259c0ee5351aed6f18c4f3a1bd6eaecc87afd6e42ac302204a958dd1579c92bce445af8e57dfa55e6efc77e602c20f2f6cba8edfbd92ace7012102f54777c45b02213eb5c81207a2477c915c1409dadc837e6040184e7b4a44800a" + }, + { + "txid": "14b090db86ab475ebbd9726489b30d27ed0edb3048ada7979df40f8541431e13", + "vout": 1, + "n": 3, + "addresses": [ + "t1PWD48DZfotRZLerFP6gzxQUqggbJ78Chb" + ], + "value": "87423640", + "hex": "483045022100f15454b8464f7d9d61b55bc429d1f19a43203c65e1f4c2cd94a2f645bdb6c8a402200a79568c70eae3bf0f9dee20dfd06f296d36b4f7be66d1456235f107e595c2e40121032ce19f2a74593a655d7bf9b78621bae60126d196bca77e720a27704be8dd1d79" + }, + { + "txid": "d9219d1700edf561928502db23a4cc3ac170bb1613b6f45776a17198ac091a02", + "n": 4, + "addresses": [ + "t1geFpG91gvaF7AKdbGskigvbaVVU9PzRy2" + ], + "value": "100000000", + "hex": "483045022100980b258ac75a3bea4e4b9147393d8dd697a314f1d1ba5076b8ddba90e037377102207847eca2541c4d48bf23d00588a01905b8278e3f49a475b2990be3844ff506420121031331dd0ba0ec99a31f29b28fd81672deea62d0b85ac92f526e98f77248e16850" + }, + { + "txid": "8c15c29ebba85a7bc6890e83e631f450c8910fe7c4489c7e7f342bc066fa7fb8", + "n": 5, + "addresses": [ + "t1ebDFfLgbfMwkq5aV18qBuF5uTUfXWtBNp" + ], + "value": "100000000", + "hex": "47304402201770c03c47411c0323652221b71c12e5093bca73c8bab929c42a3d4471aa6db5022034811d195eb0bba3015d9e493343b0e80f5da073431780de8f7ca61d4b0bc8f601210385f796e7c269bddd30f9e2ec5ade628e902e60ecfaf33bedcab8d51f21544ee6" + }, + { + "txid": "4b0ef37fa5f5e3d9f338b0db84a1ed79557a74bf9dfe648041e770b8ecbf88ac", + "n": 6, + "addresses": [ + "t1a6HWWPH7TgJVhqjHYoNu4F7SPHZaLGuBg" + ], + "value": "100000000", + "hex": "483045022100ad770d1107449f7c9a786b1114058255639d36a02df62ee9b5f240ae5d9b068502200b6f99ab8dfa928ce25e9e04ae1068ecf00c1a19fbddcc048e17388966b6480f012102c9764269807a6f8600a14e15ea90adbcb7608dd022c00e8507468436ec5e2cf5" + }, + { + "txid": "4b0ef37fa5f5e3d9f338b0db84a1ed79557a74bf9dfe648041e770b8ecbf88ac", + "vout": 1, + "n": 7, + "addresses": [ + "t1JG5Jg84RDtdyfg8wX521kbfGpirH1yx8g" + ], + "value": "699960000", + "hex": "483045022100eacf96e3df6249a92de030d61d0e19611e9b1d45d5223117463289049de58ee3022034e2be6bc7fa6053faee42a80b2d46707a0429d24a9d07415af8582ae64af86b01210288fde1c8d0c560e9b0885b2f2a6c2dc153fad665f09d8d421e2dcaa3ffef8b11" + }, + { + "txid": "a5d46a20f4918e7fead31889a67d7fe191c54dd780ea7184c5c369833537fc86", + "vout": 1, + "n": 8, + "addresses": [ + "t1Q4YXf89ReUrron31TEr7v4zhgxcRZhi5r" + ], + "value": "7299754000", + "hex": "473044022060e50791e1334cc91694f16899e4a4a4e52954d4dd818208e81e6bde579abd1902200568999f1fc2d2c6d52b416a198e787e91fe001efc0a3c8a615494824e2f327d0121020adc2d256b07692d746e900811c61b8b31422628fb0e1e311455dc072c68da12" + } + ], + "vout": [ + { + "value": "8397107640", + "n": 0, + "spent": true, + "hex": "76a914b1e7fac02d708380ce081c1b7af039ce1ab4a01288ac", + "addresses": [ + "t1a6HWWPH7TgJVhqjHYoNu4F7SPHZaLGuBg" + ] + } + ], + "blockHash": "0000004273cafef2af8bcae09a59953d9dd7088f9ad3a36e661b61fb655cdf3f", + "blockHeight": 488119, + "confirmations": 109391, + "blockTime": 1576159919, + "value": "8397107640", + "valueIn": "8397117640", + "fees": "10000", + "hex": "0400008085202f89094f9ad91387a8bffcace8972709834a9ce939c490b87fb2baf1aa74c46bd2753b000000006a47304402201bfa05833ba6ef1c893a1cfab205d7931d9f5e5c41bdcdce503645c2ca170cf502206bbcfb59d76a7b3324bb34678f9b3dc3fbb769ee2b4253982ccb2bd4dd23407c012103758ac64bf8fef07ca3eff6cdf48255d53e0c6c559bed57a2b45e03b28727afcc0000000028a71d1ebd4c5ca7edc9d30c2ef470afa0e108bc58d56d5e9395b230500e4588000000006a47304402200e6be05443eade67815792991cea7c7a217ab6add0600e96d9603b25902f15140220699d63231f9e93c163ff0d740af1593e15ccc1b9a8f994e4537f3ec8659d96ec01210268e3b9550b815d540c9095d8f9851add0b783c6e37646f2b24a4c9fb5bbf1b640000000028a71d1ebd4c5ca7edc9d30c2ef470afa0e108bc58d56d5e9395b230500e4588010000006a4730440220399cf1468ec607160f21259c0ee5351aed6f18c4f3a1bd6eaecc87afd6e42ac302204a958dd1579c92bce445af8e57dfa55e6efc77e602c20f2f6cba8edfbd92ace7012102f54777c45b02213eb5c81207a2477c915c1409dadc837e6040184e7b4a44800a00000000131e4341850ff49d97a7ad4830db0eed270db3896472d9bb5e47ab86db90b014010000006b483045022100f15454b8464f7d9d61b55bc429d1f19a43203c65e1f4c2cd94a2f645bdb6c8a402200a79568c70eae3bf0f9dee20dfd06f296d36b4f7be66d1456235f107e595c2e40121032ce19f2a74593a655d7bf9b78621bae60126d196bca77e720a27704be8dd1d7900000000021a09ac9871a17657f4b61316bb70c13acca423db02859261f5ed00179d21d9000000006b483045022100980b258ac75a3bea4e4b9147393d8dd697a314f1d1ba5076b8ddba90e037377102207847eca2541c4d48bf23d00588a01905b8278e3f49a475b2990be3844ff506420121031331dd0ba0ec99a31f29b28fd81672deea62d0b85ac92f526e98f77248e1685000000000b87ffa66c02b347f7e9c48c4e70f91c850f431e6830e89c67b5aa8bb9ec2158c000000006a47304402201770c03c47411c0323652221b71c12e5093bca73c8bab929c42a3d4471aa6db5022034811d195eb0bba3015d9e493343b0e80f5da073431780de8f7ca61d4b0bc8f601210385f796e7c269bddd30f9e2ec5ade628e902e60ecfaf33bedcab8d51f21544ee600000000ac88bfecb870e7418064fe9dbf747a5579eda184dbb038f3d9e3f5a57ff30e4b000000006b483045022100ad770d1107449f7c9a786b1114058255639d36a02df62ee9b5f240ae5d9b068502200b6f99ab8dfa928ce25e9e04ae1068ecf00c1a19fbddcc048e17388966b6480f012102c9764269807a6f8600a14e15ea90adbcb7608dd022c00e8507468436ec5e2cf500000000ac88bfecb870e7418064fe9dbf747a5579eda184dbb038f3d9e3f5a57ff30e4b010000006b483045022100eacf96e3df6249a92de030d61d0e19611e9b1d45d5223117463289049de58ee3022034e2be6bc7fa6053faee42a80b2d46707a0429d24a9d07415af8582ae64af86b01210288fde1c8d0c560e9b0885b2f2a6c2dc153fad665f09d8d421e2dcaa3ffef8b110000000086fc37358369c3c58471ea80d74dc591e17f7da68918d3ea7f8e91f4206ad4a5010000006a473044022060e50791e1334cc91694f16899e4a4a4e52954d4dd818208e81e6bde579abd1902200568999f1fc2d2c6d52b416a198e787e91fe001efc0a3c8a615494824e2f327d0121020adc2d256b07692d746e900811c61b8b31422628fb0e1e311455dc072c68da120000000001b8b181f4010000001976a914b1e7fac02d708380ce081c1b7af039ce1ab4a01288ac00000000000000000000000000000000000000" + }, + { + "txid": "4b0ef37fa5f5e3d9f338b0db84a1ed79557a74bf9dfe648041e770b8ecbf88ac", + "version": 4, + "vin": [ + { + "txid": "d9219d1700edf561928502db23a4cc3ac170bb1613b6f45776a17198ac091a02", + "vout": 1, + "n": 0, + "addresses": [ + "t1W8AuGBCy1VMQWy7JUrKogQbpsQJSV7efV" + ], + "value": "799970000", + "hex": "473044022078790509c123dca7891ac77fac4b2f764dca7ebb677083fb00b9ab42a845ad4302203a0ebf51edae13061edd60b74ab9462be1853091064f43803e8bff7c43a105de0121038375e6a728b548f1d3fcd24a538195ac6a5d9f8b7c31f1d56870c3f62dfa0045" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a914b1e7fac02d708380ce081c1b7af039ce1ab4a01288ac", + "addresses": [ + "t1a6HWWPH7TgJVhqjHYoNu4F7SPHZaLGuBg" + ] + }, + { + "value": "699960000", + "n": 1, + "spent": true, + "hex": "76a914043ff06e66c8b70071a1a90c1bf0328e3550bcbc88ac", + "addresses": [ + "t1JG5Jg84RDtdyfg8wX521kbfGpirH1yx8g" + ] + } + ], + "blockHash": "000000560c905936b77d72bb0baa1acea23f4a5081412f57358d68bb086297c0", + "blockHeight": 487934, + "confirmations": 109576, + "blockTime": 1576137717, + "value": "799960000", + "valueIn": "799970000", + "fees": "10000", + "hex": "0400008085202f8901021a09ac9871a17657f4b61316bb70c13acca423db02859261f5ed00179d21d9010000006a473044022078790509c123dca7891ac77fac4b2f764dca7ebb677083fb00b9ab42a845ad4302203a0ebf51edae13061edd60b74ab9462be1853091064f43803e8bff7c43a105de0121038375e6a728b548f1d3fcd24a538195ac6a5d9f8b7c31f1d56870c3f62dfa0045000000000200e1f505000000001976a914b1e7fac02d708380ce081c1b7af039ce1ab4a01288acc08ab829000000001976a914043ff06e66c8b70071a1a90c1bf0328e3550bcbc88ac00000000000000000000000000000000000000" + }, + { + "txid": "88450e5030b295935e6dd558bc08e1a0af70f42e0cd3c9eda75c4cbd1e1da728", + "version": 4, + "vin": [ + { + "txid": "3b75d26bc474aaf1bab27fb890c439e99c4a83092797e8acfcbfa88713d99a4f", + "vout": 1, + "n": 0, + "addresses": [ + "t1JqpFtnqTHeuxHhP2eXcEUp111WWoQ3Fj2" + ], + "value": "9890000", + "hex": "47304402200e36bcaee420658c15eefadfe0d06211d2f825de15fc15b5a470e46c25f603290220297f5bbaf4ad468bb7b97f9fc0e1932099197a837a12149ad77c7c0bb04738630121022bdc67121f765090084b56ae8dac9166637d467bb5b90231dc8ceae63880474a" + } + ], + "vout": [ + { + "value": "1000000", + "n": 0, + "spent": true, + "hex": "76a9143b7fa3c4a3cc8640a4cb48d8065d802c7698750d88ac", + "addresses": [ + "t1PJCnDXNZuoKU5sCAJm15YGqnQdJTQw4Jy" + ] + }, + { + "value": "8880000", + "n": 1, + "spent": true, + "hex": "76a914667a08d692c001b0dc895e1efb115cc54a32eec288ac", + "addresses": [ + "t1TDT81WmcqUXeBxV1JjTEb4usYbMPtqBJU" + ] + } + ], + "blockHash": "0000002f5d2c5ce0762500fa7fd0ce7ce077fba4b1b290fdc73cc605ccc57c04", + "blockHeight": 418360, + "confirmations": 179150, + "blockTime": 1567734616, + "value": "9880000", + "valueIn": "9890000", + "fees": "10000", + "hex": "0400008085202f89014f9ad91387a8bffcace8972709834a9ce939c490b87fb2baf1aa74c46bd2753b010000006a47304402200e36bcaee420658c15eefadfe0d06211d2f825de15fc15b5a470e46c25f603290220297f5bbaf4ad468bb7b97f9fc0e1932099197a837a12149ad77c7c0bb04738630121022bdc67121f765090084b56ae8dac9166637d467bb5b90231dc8ceae63880474a000000000240420f00000000001976a9143b7fa3c4a3cc8640a4cb48d8065d802c7698750d88ac807f8700000000001976a914667a08d692c001b0dc895e1efb115cc54a32eec288ac00000000000000000000000000000000000000" + }, + { + "txid": "d9219d1700edf561928502db23a4cc3ac170bb1613b6f45776a17198ac091a02", + "version": 4, + "vin": [ + { + "txid": "8c15c29ebba85a7bc6890e83e631f450c8910fe7c4489c7e7f342bc066fa7fb8", + "vout": 1, + "n": 0, + "addresses": [ + "t1f4Kyg1bRWTt2YDWxCQWvHNA8sejSuLgZz" + ], + "value": "899980000", + "hex": "4730440220037132d99a1a19d1e0302e22b4952609a08668286fa57083fab6cc605eee07c302200446536f492497d74bb2823d2b2c602e2f64807c20af39442bfe151f72dbdee0012102621d97835d046d2a404d4f6a1fa719a6654f092e4f0bf2d50c86a2366e010323" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a914f9c4a188575f9c84b36d44ac45840e1961b384d488ac", + "addresses": [ + "t1geFpG91gvaF7AKdbGskigvbaVVU9PzRy2" + ] + }, + { + "value": "799970000", + "n": 1, + "spent": true, + "hex": "76a9148662cadfc04a343c5dba3ee75116922a9a2a512188ac", + "addresses": [ + "t1W8AuGBCy1VMQWy7JUrKogQbpsQJSV7efV" + ] + } + ], + "blockHash": "00000039b2eb21aa867598c3907dc73205c2d3864abe3d655c21a7ffcfbd0249", + "blockHeight": 418352, + "confirmations": 179158, + "blockTime": 1567733843, + "value": "899970000", + "valueIn": "899980000", + "fees": "10000", + "hex": "0400008085202f8901b87ffa66c02b347f7e9c48c4e70f91c850f431e6830e89c67b5aa8bb9ec2158c010000006a4730440220037132d99a1a19d1e0302e22b4952609a08668286fa57083fab6cc605eee07c302200446536f492497d74bb2823d2b2c602e2f64807c20af39442bfe151f72dbdee0012102621d97835d046d2a404d4f6a1fa719a6654f092e4f0bf2d50c86a2366e010323000000000200e1f505000000001976a914f9c4a188575f9c84b36d44ac45840e1961b384d488acd092ae2f000000001976a9148662cadfc04a343c5dba3ee75116922a9a2a512188ac00000000000000000000000000000000000000" + }, + { + "txid": "8c15c29ebba85a7bc6890e83e631f450c8910fe7c4489c7e7f342bc066fa7fb8", + "version": 4, + "vin": [ + { + "txid": "17fa0cd349b820474816bc4b6482cd212f9897eeceb26db6133256c9c8fc445a", + "n": 0, + "addresses": [ + "t1bQhfSPZE8Do6qf1ohYcG5j591i3PpNykJ" + ], + "value": "999990000", + "hex": "47304402204ef82fa2370116d8c61bb2c7a744f7b8ae0abe222262a0b6d2c9b2663f1182b2022044539e387abeee1943b834a80efd142b31b4045aed03f0f89492032d949167d9012103834594213870cb448637157b78a115d0ee38db8affa982526511a84f92252b0e" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a914e340fe29e1bcf32d1ff41716fe781b8ea8e3cdf388ac", + "addresses": [ + "t1ebDFfLgbfMwkq5aV18qBuF5uTUfXWtBNp" + ] + }, + { + "value": "899980000", + "n": 1, + "spent": true, + "hex": "76a914e861d644e9a6fce70751d186034df7440a2cb1bf88ac", + "addresses": [ + "t1f4Kyg1bRWTt2YDWxCQWvHNA8sejSuLgZz" + ] + } + ], + "blockHash": "0000002a163eff0d20cdf72672cbd5b56f1e5e03364a2b547326560e99141b0c", + "blockHeight": 415334, + "confirmations": 182176, + "blockTime": 1567370685, + "value": "999980000", + "valueIn": "999990000", + "fees": "10000", + "hex": "0400008085202f89015a44fcc8c9563213b66db2ceee97982f21cd82644bbc16484720b849d30cfa17000000006a47304402204ef82fa2370116d8c61bb2c7a744f7b8ae0abe222262a0b6d2c9b2663f1182b2022044539e387abeee1943b834a80efd142b31b4045aed03f0f89492032d949167d9012103834594213870cb448637157b78a115d0ee38db8affa982526511a84f92252b0e000000000200e1f505000000001976a914e340fe29e1bcf32d1ff41716fe781b8ea8e3cdf388ace09aa435000000001976a914e861d644e9a6fce70751d186034df7440a2cb1bf88ac00000000000000000000000000000000000000" + }, + { + "txid": "3b75d26bc474aaf1bab27fb890c439e99c4a83092797e8acfcbfa88713d99a4f", + "version": 4, + "vin": [ + { + "txid": "d50b535474820e492e983ac1e28f35f3a438f75de4608bd607de3f353b4734e1", + "n": 0, + "addresses": [ + "t1NxxzpojGhvtLHwiJvdivokWY4KfJuT1pd" + ], + "value": "10000000", + "hex": "483045022100df19f9252513678259f56acb5fdcb437890a25ee77aa8bc97523922c2f10169b022041f6e0701564228d6a5949a67533ae22096956f40efcdd2f67b9341174696967012102f5a3ac1537190c715de17ca1f105fcac8dffd761244adca9ba36105da3788aa3" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a91441b68e2ffc0bf598c376842c007fd831beb7917988ac", + "addresses": [ + "t1Ps4cyeWT5sTxoNabuMmhRD3c2j5SdmVP8" + ] + }, + { + "value": "9890000", + "n": 1, + "spent": true, + "hex": "76a9140aa1853e57472c179d09457201ca02cc08838e0f88ac", + "addresses": [ + "t1JqpFtnqTHeuxHhP2eXcEUp111WWoQ3Fj2" + ] + } + ], + "blockHash": "000000039f8a845ebd4607ab16391f00611f94853263e222a6c951e88fed69dd", + "blockHeight": 414780, + "confirmations": 182730, + "blockTime": 1567304242, + "value": "9990000", + "valueIn": "10000000", + "fees": "10000", + "hex": "0400008085202f8901e134473b353fde07d68b60e45df738a4f3358fe2c13a982e490e827454530bd5000000006b483045022100df19f9252513678259f56acb5fdcb437890a25ee77aa8bc97523922c2f10169b022041f6e0701564228d6a5949a67533ae22096956f40efcdd2f67b9341174696967012102f5a3ac1537190c715de17ca1f105fcac8dffd761244adca9ba36105da3788aa30000000002a0860100000000001976a91441b68e2ffc0bf598c376842c007fd831beb7917988acd0e89600000000001976a9140aa1853e57472c179d09457201ca02cc08838e0f88ac00000000000000000000000000000000000000" + }, + { + "txid": "17fa0cd349b820474816bc4b6482cd212f9897eeceb26db6133256c9c8fc445a", + "version": 4, + "vin": [ + { + "txid": "a5d46a20f4918e7fead31889a67d7fe191c54dd780ea7184c5c369833537fc86", + "sequence": 4294967294, + "n": 0, + "addresses": [ + "t1S2iUUwT3rjQeU6kcucbunr4avRNH3W34V" + ], + "value": "1000000000", + "hex": "483045022100b2a76edd1b63c6d575047556d88d1728931825f21e812d5a091f31f2012abbba02204461ec8971d81413b6e04dde57b325982d5a59688f761cbe58916a44a7ac5ad00121022337efa16ee696bfc459b7d0c0a202044bc62c14c12c1e7310de57ccc59d5c22" + } + ], + "vout": [ + { + "value": "999990000", + "n": 0, + "spent": true, + "hex": "76a914c05bc15cc814aedb18b50ed152cf930df8eeda4488ac", + "addresses": [ + "t1bQhfSPZE8Do6qf1ohYcG5j591i3PpNykJ" + ] + } + ], + "blockHash": "00000033eb355a1da3bd1c2441b4c1a238cd7063dfc4676387b4c25978c84dce", + "blockHeight": 404602, + "confirmations": 192908, + "blockTime": 1566071583, + "value": "999990000", + "valueIn": "1000000000", + "fees": "10000", + "hex": "0400008085202f890186fc37358369c3c58471ea80d74dc591e17f7da68918d3ea7f8e91f4206ad4a5000000006b483045022100b2a76edd1b63c6d575047556d88d1728931825f21e812d5a091f31f2012abbba02204461ec8971d81413b6e04dde57b325982d5a59688f761cbe58916a44a7ac5ad00121022337efa16ee696bfc459b7d0c0a202044bc62c14c12c1e7310de57ccc59d5c22feffffff01f0a29a3b000000001976a914c05bc15cc814aedb18b50ed152cf930df8eeda4488ac00000000000000000000000000000000000000" + }, + { + "txid": "a5d46a20f4918e7fead31889a67d7fe191c54dd780ea7184c5c369833537fc86", + "version": 4, + "vin": [ + { + "txid": "fc66fbfa6531984d26301d0599a555bdab9612dbfe35ea53997f7633d097f672", + "vout": 1, + "n": 0, + "addresses": [ + "t1bQhfSPZE8Do6qf1ohYcG5j591i3PpNykJ" + ], + "value": "8299764000", + "hex": "47304402206974f18033a7ae20ecb6700c848e517409fec6fe2103a6516de62eaec13528b30220676f6a9ce3c14ab2b4e7be47ee4a1c0e756d5e346a4c982281ca1a9e6d9bac2d012103834594213870cb448637157b78a115d0ee38db8affa982526511a84f92252b0e" + } + ], + "vout": [ + { + "value": "1000000000", + "n": 0, + "spent": true, + "hex": "76a914597a2630de1576e75fad04f4122f81dcb6cea8f788ac", + "addresses": [ + "t1S2iUUwT3rjQeU6kcucbunr4avRNH3W34V" + ] + }, + { + "value": "7299754000", + "n": 1, + "spent": true, + "hex": "76a91443e26d7b61b9b8426c3cb7099cad858a2319362488ac", + "addresses": [ + "t1Q4YXf89ReUrron31TEr7v4zhgxcRZhi5r" + ] + } + ], + "blockHash": "00000037543ab8923662e5928364e2dd2a82318c253ab9b9aa92b83521b6ff8b", + "blockHeight": 404601, + "confirmations": 192909, + "blockTime": 1566071132, + "value": "8299754000", + "valueIn": "8299764000", + "fees": "10000", + "hex": "0400008085202f890172f697d033767f9953ea35fedb1296abbd55a599051d30264d983165fafb66fc010000006a47304402206974f18033a7ae20ecb6700c848e517409fec6fe2103a6516de62eaec13528b30220676f6a9ce3c14ab2b4e7be47ee4a1c0e756d5e346a4c982281ca1a9e6d9bac2d012103834594213870cb448637157b78a115d0ee38db8affa982526511a84f92252b0e000000000200ca9a3b000000001976a914597a2630de1576e75fad04f4122f81dcb6cea8f788ac106819b3010000001976a91443e26d7b61b9b8426c3cb7099cad858a2319362488ac00000000000000000000000000000000000000" + }, + { + "txid": "fc66fbfa6531984d26301d0599a555bdab9612dbfe35ea53997f7633d097f672", + "version": 4, + "vin": [ + { + "txid": "7568654a592eb35c8c8cec7c7e9d93ffb2f1d6770576369991e8eefb9da97df1", + "vout": 1, + "n": 0, + "addresses": [ + "t1V1f4WNQB8zeTA8z27zqcFwpsGrbcSo7Eo" + ], + "value": "9299774000", + "hex": "473044022028e6f1f002911c7f0503187b0750b114e8cd36eaec2ad32dfb0aad44b820f078022008e03c1058128e99698165c0de3691acd0a9f314d535c55827f0d3269bbbcbdd01210266fb4c06ad0a274aba63820224d142ed1db4781abd5909702f71900e4c2d0340" + } + ], + "vout": [ + { + "value": "1000000000", + "n": 0, + "hex": "76a9147f1271095e3e2063ca859588b40dad6c13995dce88ac", + "addresses": [ + "t1VTVv3Ebwo2zvEdE3PDrJyTATKDTXg7CvB" + ] + }, + { + "value": "8299764000", + "n": 1, + "spent": true, + "hex": "76a914c05bc15cc814aedb18b50ed152cf930df8eeda4488ac", + "addresses": [ + "t1bQhfSPZE8Do6qf1ohYcG5j591i3PpNykJ" + ] + } + ], + "blockHash": "00000013cd50f912ef02928735f3aaa8dd75c2a1b075f5f336e73d85220f862c", + "blockHeight": 403671, + "confirmations": 193839, + "blockTime": 1565958928, + "value": "9299764000", + "valueIn": "9299774000", + "fees": "10000", + "hex": "0400008085202f8901f17da99dfbeee8919936760577d6f1b2ff939d7e7cec8c8c5cb32e594a656875010000006a473044022028e6f1f002911c7f0503187b0750b114e8cd36eaec2ad32dfb0aad44b820f078022008e03c1058128e99698165c0de3691acd0a9f314d535c55827f0d3269bbbcbdd01210266fb4c06ad0a274aba63820224d142ed1db4781abd5909702f71900e4c2d0340000000000200ca9a3b000000001976a9147f1271095e3e2063ca859588b40dad6c13995dce88ac2059b4ee010000001976a914c05bc15cc814aedb18b50ed152cf930df8eeda4488ac00000000000000000000000000000000000000" + }, + { + "txid": "d50b535474820e492e983ac1e28f35f3a438f75de4608bd607de3f353b4734e1", + "version": 4, + "vin": [ + { + "txid": "14b090db86ab475ebbd9726489b30d27ed0edb3048ada7979df40f8541431e13", + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1URfpa81UtVrj4kbKpsW3Yq9QhKBxx6mSQ" + ], + "value": "112300000", + "hex": "4830450221008b0569773b9b10607bf07f31376d02a7fb6a777b16302479ec29b3464c41389002202a31dc5d02630e72ad9627f39cc7357f7f3d7090cf00c41f727c9a4ada704673012102826f2aebbdad38b97d070fff71d5e9c87e926e682e02601ffc8f82450b9bd33e" + } + ], + "vout": [ + { + "value": "10000000", + "n": 0, + "spent": true, + "hex": "76a91437dc3b364dab71edf5ad84578ec901b10eb6c71788ac", + "addresses": [ + "t1NxxzpojGhvtLHwiJvdivokWY4KfJuT1pd" + ] + }, + { + "value": "102074000", + "n": 1, + "spent": true, + "hex": "76a9149d8b8c5ddd77a98b1cb09ba93f5cd0c11e74fb5f88ac", + "addresses": [ + "t1YEdGSS9ErsDbtfKzZN39kLr3LGP8xRu1G" + ] + } + ], + "blockHash": "000000145ea129bb32d171e2050b764dff4e30d13a3a2b0974e72f8d0aaf9a57", + "blockHeight": 337841, + "confirmations": 259669, + "blockTime": 1557995255, + "value": "112074000", + "valueIn": "112300000", + "fees": "226000", + "hex": "0400008085202f8901131e4341850ff49d97a7ad4830db0eed270db3896472d9bb5e47ab86db90b014000000006b4830450221008b0569773b9b10607bf07f31376d02a7fb6a777b16302479ec29b3464c41389002202a31dc5d02630e72ad9627f39cc7357f7f3d7090cf00c41f727c9a4ada704673012102826f2aebbdad38b97d070fff71d5e9c87e926e682e02601ffc8f82450b9bd33efeffff7f0280969800000000001976a91437dc3b364dab71edf5ad84578ec901b10eb6c71788ac90861506000000001976a9149d8b8c5ddd77a98b1cb09ba93f5cd0c11e74fb5f88ac00000000000000000000000000000000000000" + }, + { + "txid": "14b090db86ab475ebbd9726489b30d27ed0edb3048ada7979df40f8541431e13", + "version": 4, + "vin": [ + { + "txid": "9349dc789e58ae48cf7c0e0200237aeb2d71e03ea75422dbb0d08a9cea86022b", + "n": 0, + "addresses": [ + "t1NxxzpojGhvtLHwiJvdivokWY4KfJuT1pd" + ], + "value": "199733640", + "hex": "483045022100ac753e2e0ad2b248d6aaa3e50cf9f82d6b478b922aaaf6f8d9446b265a0a085c02206a5676e6334a66f770a02e753edf26fd22fa7cb7797386a8043cae121a78d071012102f5a3ac1537190c715de17ca1f105fcac8dffd761244adca9ba36105da3788aa3" + } + ], + "vout": [ + { + "value": "112300000", + "n": 0, + "spent": true, + "hex": "76a91473c1c0b3022da242b74bddba0dc556d0ef96ea4488ac", + "addresses": [ + "t1URfpa81UtVrj4kbKpsW3Yq9QhKBxx6mSQ" + ] + }, + { + "value": "87423640", + "n": 1, + "spent": true, + "hex": "76a9143dc4dc377fd0b413affda4d928294f99ed987f6a88ac", + "addresses": [ + "t1PWD48DZfotRZLerFP6gzxQUqggbJ78Chb" + ] + } + ], + "blockHash": "000000329c8e95b91fe0dbf20960435fb3525c440edd90ed35714a8d92020883", + "blockHeight": 337812, + "confirmations": 259698, + "blockTime": 1557991696, + "value": "199723640", + "valueIn": "199733640", + "fees": "10000", + "hex": "0400008085202f89012b0286ea9c8ad0b0db2254a73ee0712deb7a2300020e7ccf48ae589e78dc4993000000006b483045022100ac753e2e0ad2b248d6aaa3e50cf9f82d6b478b922aaaf6f8d9446b265a0a085c02206a5676e6334a66f770a02e753edf26fd22fa7cb7797386a8043cae121a78d071012102f5a3ac1537190c715de17ca1f105fcac8dffd761244adca9ba36105da3788aa30000000002e08fb106000000001976a91473c1c0b3022da242b74bddba0dc556d0ef96ea4488ac98fa3505000000001976a9143dc4dc377fd0b413affda4d928294f99ed987f6a88ac00000000000000000000000000000000000000" + }, + { + "txid": "9349dc789e58ae48cf7c0e0200237aeb2d71e03ea75422dbb0d08a9cea86022b", + "version": 4, + "vin": [ + { + "txid": "7568654a592eb35c8c8cec7c7e9d93ffb2f1d6770576369991e8eefb9da97df1", + "sequence": 2147483644, + "n": 0, + "addresses": [ + "t1PJfL2QqQSERTXHDqSBw6WKKE4bXGJjLB7" + ], + "value": "340169480", + "hex": "473044022021f5f09419eaf1896a1f9e7b108780e04136bd083395a167ba7803b5d27cc473022040fdfc66536f8910927032c9b4d90e408aceb431626c47e8b33812af10c18aee01210290f437489bf989f9f74597799262d0e6ffa5fa6cb83922b2a2fe5856420c528a" + }, + { + "txid": "4dc556de97672632e5b4d5e06562b1225e83f461d713928142a5582a117c69de", + "sequence": 2147483645, + "n": 1, + "addresses": [ + "t1PJfL2QqQSERTXHDqSBw6WKKE4bXGJjLB7" + ], + "value": "100000000", + "hex": "48304502210098257b740550470d0213f3e25ac0c0a70762f149953cbaa4ff06058cf6be7bce022068a8967485b476fa8ad94b1fe0667e07c7323e38213c00dac155a3b79b1b659001210290f437489bf989f9f74597799262d0e6ffa5fa6cb83922b2a2fe5856420c528a" + }, + { + "txid": "49575259c2f421bd6586e7506353c2e2c4c04eca9355c2c61e8ff22b69a98f68", + "sequence": 2147483646, + "n": 2, + "addresses": [ + "t1PJfL2QqQSERTXHDqSBw6WKKE4bXGJjLB7" + ], + "value": "259564160", + "hex": "483045022100dab8d58404248321208cbde2b95d399ec33a0d023e18108833b27e2705118d660220736d69b128e2474996442e58d5f72b24820105004e32c020c85a57bc382b459801210290f437489bf989f9f74597799262d0e6ffa5fa6cb83922b2a2fe5856420c528a" + } + ], + "vout": [ + { + "value": "199733640", + "n": 0, + "spent": true, + "hex": "76a91437dc3b364dab71edf5ad84578ec901b10eb6c71788ac", + "addresses": [ + "t1NxxzpojGhvtLHwiJvdivokWY4KfJuT1pd" + ] + }, + { + "value": "499774000", + "n": 1, + "hex": "76a914ec1bc34cc218f75a453e476bf3fee959f6859cbe88ac", + "addresses": [ + "t1fQ2jcA6zm59QzACiiQdZCe85uQJghkbiN" + ] + } + ], + "blockHash": "00000012362103edf57021e6f7f73743062f7935d15d0f13a88a6da2b9f5a7a0", + "blockHeight": 337460, + "confirmations": 260050, + "blockTime": 1557949204, + "value": "699507640", + "valueIn": "699733640", + "fees": "226000", + "hex": "0400008085202f8903f17da99dfbeee8919936760577d6f1b2ff939d7e7cec8c8c5cb32e594a656875000000006a473044022021f5f09419eaf1896a1f9e7b108780e04136bd083395a167ba7803b5d27cc473022040fdfc66536f8910927032c9b4d90e408aceb431626c47e8b33812af10c18aee01210290f437489bf989f9f74597799262d0e6ffa5fa6cb83922b2a2fe5856420c528afcffff7fde697c112a58a542819213d761f4835e22b16265e0d5b4e532266797de56c54d000000006b48304502210098257b740550470d0213f3e25ac0c0a70762f149953cbaa4ff06058cf6be7bce022068a8967485b476fa8ad94b1fe0667e07c7323e38213c00dac155a3b79b1b659001210290f437489bf989f9f74597799262d0e6ffa5fa6cb83922b2a2fe5856420c528afdffff7f688fa9692bf28f1ec6c25593ca4ec0c4e2c2536350e78665bd21f4c259525749000000006b483045022100dab8d58404248321208cbde2b95d399ec33a0d023e18108833b27e2705118d660220736d69b128e2474996442e58d5f72b24820105004e32c020c85a57bc382b459801210290f437489bf989f9f74597799262d0e6ffa5fa6cb83922b2a2fe5856420c528afeffff7f0288b1e70b000000001976a91437dc3b364dab71edf5ad84578ec901b10eb6c71788ac30f2c91d000000001976a914ec1bc34cc218f75a453e476bf3fee959f6859cbe88ac00000000000000000000000000000000000000" + }, + { + "txid": "7568654a592eb35c8c8cec7c7e9d93ffb2f1d6770576369991e8eefb9da97df1", + "version": 4, + "vin": [ + { + "txid": "4dc556de97672632e5b4d5e06562b1225e83f461d713928142a5582a117c69de", + "vout": 1, + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1NxxzpojGhvtLHwiJvdivokWY4KfJuT1pd" + ], + "value": "9640169480", + "hex": "483045022100c3fab53af64f87850dc757b7db2195f8c5058bc3711af11b57a4c5b3105ab877022012f11149aefd859a554b09b54f44ed2307a2c17714f638587f39bb95eeaf81a6012102f5a3ac1537190c715de17ca1f105fcac8dffd761244adca9ba36105da3788aa3" + } + ], + "vout": [ + { + "value": "340169480", + "n": 0, + "spent": true, + "hex": "76a9143b95cd1d119904d38c4e250e52253c66066ed60c88ac", + "addresses": [ + "t1PJfL2QqQSERTXHDqSBw6WKKE4bXGJjLB7" + ] + }, + { + "value": "9299774000", + "n": 1, + "spent": true, + "hex": "76a9147a2f42e0673605fb11884b35e79bbcc525ac7b1088ac", + "addresses": [ + "t1V1f4WNQB8zeTA8z27zqcFwpsGrbcSo7Eo" + ] + } + ], + "blockHash": "00000030651071f9961b36bf9f7183a7b4428f438af5f42eca1512fb09575175", + "blockHeight": 337456, + "confirmations": 260054, + "blockTime": 1557948761, + "value": "9639943480", + "valueIn": "9640169480", + "fees": "226000", + "hex": "0400008085202f8901de697c112a58a542819213d761f4835e22b16265e0d5b4e532266797de56c54d010000006b483045022100c3fab53af64f87850dc757b7db2195f8c5058bc3711af11b57a4c5b3105ab877022012f11149aefd859a554b09b54f44ed2307a2c17714f638587f39bb95eeaf81a6012102f5a3ac1537190c715de17ca1f105fcac8dffd761244adca9ba36105da3788aa3feffff7f0208934614000000001976a9143b95cd1d119904d38c4e250e52253c66066ed60c88ac304a4f2a020000001976a9147a2f42e0673605fb11884b35e79bbcc525ac7b1088ac00000000000000000000000000000000000000" + }, + { + "txid": "4dc556de97672632e5b4d5e06562b1225e83f461d713928142a5582a117c69de", + "version": 4, + "vin": [ + { + "txid": "49575259c2f421bd6586e7506353c2e2c4c04eca9355c2c61e8ff22b69a98f68", + "vout": 1, + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1aCdgJD9R5tumv4Lj5sDNyQkfpwSjYj34A" + ], + "value": "9740395480", + "hex": "483045022100f23c9c3ee498fc654a32eeb094de699e704e4af118d2a5fc852bb808d4b04ae10220497da33b6a8a3011244bd9c3d1e6a6d7b15b1e6e52d690a10ccbd6cba05028bb012102b0f3aa87ed650b61719eb7019683de78a77d9166a5b6924cbc2eaac9da650445" + } + ], + "vout": [ + { + "value": "100000000", + "n": 0, + "spent": true, + "hex": "76a9143b95cd1d119904d38c4e250e52253c66066ed60c88ac", + "addresses": [ + "t1PJfL2QqQSERTXHDqSBw6WKKE4bXGJjLB7" + ] + }, + { + "value": "9640169480", + "n": 1, + "spent": true, + "hex": "76a91437dc3b364dab71edf5ad84578ec901b10eb6c71788ac", + "addresses": [ + "t1NxxzpojGhvtLHwiJvdivokWY4KfJuT1pd" + ] + } + ], + "blockHash": "0000000a2cbdac0d5d68b2bd53e136901de71badef2953449f91eb5dbecf5e7e", + "blockHeight": 336048, + "confirmations": 261462, + "blockTime": 1557776516, + "value": "9740169480", + "valueIn": "9740395480", + "fees": "226000", + "hex": "0400008085202f8901688fa9692bf28f1ec6c25593ca4ec0c4e2c2536350e78665bd21f4c259525749010000006b483045022100f23c9c3ee498fc654a32eeb094de699e704e4af118d2a5fc852bb808d4b04ae10220497da33b6a8a3011244bd9c3d1e6a6d7b15b1e6e52d690a10ccbd6cba05028bb012102b0f3aa87ed650b61719eb7019683de78a77d9166a5b6924cbc2eaac9da650445feffff7f0200e1f505000000001976a9143b95cd1d119904d38c4e250e52253c66066ed60c88ac0850993e020000001976a91437dc3b364dab71edf5ad84578ec901b10eb6c71788ac00000000000000000000000000000000000000" + }, + { + "txid": "49575259c2f421bd6586e7506353c2e2c4c04eca9355c2c61e8ff22b69a98f68", + "version": 4, + "vin": [ + { + "txid": "608bc6d8a25d368f63816087e8760fddac7522776dd3cba2109d7cd3a93ee7bf", + "sequence": 2147483645, + "n": 0, + "addresses": [ + "t1ZYbmtqhQrmEhhQx4qjn1pE1nm3xQvZzv4" + ], + "value": "307888200", + "hex": "47304402201d4884ba653ad26e0d8f25358c80d39ac80403f48bdfefdb4daec9be039d24ab02206e4fad2814b69417ffc3e65e033c01e4fe90a715e35224cc78b470935e165279012102f7bb101f35466e6264aea052956beda92b309f99fa322388c7a003f57cd318bd" + }, + { + "txid": "54c13888cb5b85383d008a02aad2187fcff03feb6c0f5ab963c1d916bc9ef0d1", + "vout": 1, + "sequence": 2147483646, + "n": 1, + "addresses": [ + "t1N1d1XJqrNzorBZUJb4cUWitAC9B5RcUoX" + ], + "value": "9692075960", + "hex": "47304402200e1716c15faae00a049d7979e60ddd039b59f64181f9fa5222ffad76a51eab46022005fa1b5ed1659e5fd48cabb20e8c6a56e4a80453142b743412632dd93ccaf10401210320893fa384153625abfd90b12ecd180b3d73c64fdfc783207b5354c3b61ecadd" + } + ], + "vout": [ + { + "value": "259564160", + "n": 0, + "spent": true, + "hex": "76a9143b95cd1d119904d38c4e250e52253c66066ed60c88ac", + "addresses": [ + "t1PJfL2QqQSERTXHDqSBw6WKKE4bXGJjLB7" + ] + }, + { + "value": "9740395480", + "n": 1, + "spent": true, + "hex": "76a914b31b4fb329e7bbf7e2f20719d78d79685963670c88ac", + "addresses": [ + "t1aCdgJD9R5tumv4Lj5sDNyQkfpwSjYj34A" + ] + } + ], + "blockHash": "0000001162097734f4e2e45aa56c3ecab443a0d687af8402c7b7f63170830318", + "blockHeight": 335709, + "confirmations": 261801, + "blockTime": 1557736095, + "value": "9999959640", + "valueIn": "9999964160", + "fees": "4520", + "hex": "0400008085202f8902bfe73ea9d37c9d10a2cbd36d772275acdd0f76e8876081638f365da2d8c68b60000000006a47304402201d4884ba653ad26e0d8f25358c80d39ac80403f48bdfefdb4daec9be039d24ab02206e4fad2814b69417ffc3e65e033c01e4fe90a715e35224cc78b470935e165279012102f7bb101f35466e6264aea052956beda92b309f99fa322388c7a003f57cd318bdfdffff7fd1f09ebc16d9c163b95a0f6ceb3ff0cf7f18d2aa028a003d38855bcb8838c154010000006a47304402200e1716c15faae00a049d7979e60ddd039b59f64181f9fa5222ffad76a51eab46022005fa1b5ed1659e5fd48cabb20e8c6a56e4a80453142b743412632dd93ccaf10401210320893fa384153625abfd90b12ecd180b3d73c64fdfc783207b5354c3b61ecaddfeffff7f0280a2780f000000001976a9143b95cd1d119904d38c4e250e52253c66066ed60c88acd8a39244020000001976a914b31b4fb329e7bbf7e2f20719d78d79685963670c88ac00000000000000000000000000000000000000" + }, + { + "txid": "608bc6d8a25d368f63816087e8760fddac7522776dd3cba2109d7cd3a93ee7bf", + "version": 4, + "vin": [ + { + "txid": "54c13888cb5b85383d008a02aad2187fcff03feb6c0f5ab963c1d916bc9ef0d1", + "sequence": 2147483645, + "n": 0, + "addresses": [ + "t1fvxYkVjkmYJFaSR4254YNa6kwxXe2wEQA" + ], + "value": "112345000", + "hex": "473044022033609c40da85357f58a0edb2fd6f02efac74a1422c1e2882ababd6576cb94f2002207180a21a0db61296fd22d4bbd1302ea7fc70f3540b6b5b1ab0b2594ed0443c310121023f0760e051894921eb0da99a97bf45b5279a1f19daab7144c060c4a6cbdad263" + }, + { + "txid": "2b9a6838fa428396f8ef34119b951480d676d022cbb29f0a9575e1fd185a96a3", + "sequence": 2147483646, + "n": 1, + "addresses": [ + "t1fvxYkVjkmYJFaSR4254YNa6kwxXe2wEQA" + ], + "value": "195550000", + "hex": "473044022043c21784a268c2c99dc0f54a8da62dc2367dfc3739aace1a9035117c4ef514ae022034586a0a13eeb0b3336c722d9fd10504d71cd57e1d2dff3868c37dc37defe90d0121023f0760e051894921eb0da99a97bf45b5279a1f19daab7144c060c4a6cbdad263" + } + ], + "vout": [ + { + "value": "307888200", + "n": 0, + "spent": true, + "hex": "76a914abe9ea731a821de6c87b3d0184fc405c0b8dcdc888ac", + "addresses": [ + "t1ZYbmtqhQrmEhhQx4qjn1pE1nm3xQvZzv4" + ] + } + ], + "blockHash": "0000000a6cbd7756c970f1f0fa2e32b62872f1ded7af827b3eaa0665baa7df9d", + "blockHeight": 335704, + "confirmations": 261806, + "blockTime": 1557735455, + "value": "307888200", + "valueIn": "307895000", + "fees": "6800", + "hex": "0400008085202f8902d1f09ebc16d9c163b95a0f6ceb3ff0cf7f18d2aa028a003d38855bcb8838c154000000006a473044022033609c40da85357f58a0edb2fd6f02efac74a1422c1e2882ababd6576cb94f2002207180a21a0db61296fd22d4bbd1302ea7fc70f3540b6b5b1ab0b2594ed0443c310121023f0760e051894921eb0da99a97bf45b5279a1f19daab7144c060c4a6cbdad263fdffff7fa3965a18fde175950a9fb2cb22d076d68014959b1134eff8968342fa38689a2b000000006a473044022043c21784a268c2c99dc0f54a8da62dc2367dfc3739aace1a9035117c4ef514ae022034586a0a13eeb0b3336c722d9fd10504d71cd57e1d2dff3868c37dc37defe90d0121023f0760e051894921eb0da99a97bf45b5279a1f19daab7144c060c4a6cbdad263feffff7f0148005a12000000001976a914abe9ea731a821de6c87b3d0184fc405c0b8dcdc888ac00000000000000000000000000000000000000" + }, + { + "txid": "54c13888cb5b85383d008a02aad2187fcff03feb6c0f5ab963c1d916bc9ef0d1", + "version": 4, + "vin": [ + { + "txid": "2b9a6838fa428396f8ef34119b951480d676d022cbb29f0a9575e1fd185a96a3", + "vout": 1, + "sequence": 2147483646, + "n": 0, + "addresses": [ + "t1dfCmUsQAD73vkFSsHPC1ak9b7ven8P7pe" + ], + "value": "9804425480", + "hex": "483045022100b25ab6c1a994d0f99c874187427802f1a2e8ee3746784fd32fc358b522d5467402207ea330c77121f8b426d79f9778f16be2d3f625afc8fc851ae9b0aa7418c6a938012103c85acfe75a3bb4418d5f604aced599253cb639a417c9920103016ca79402a0de" + } + ], + "vout": [ + { + "value": "112345000", + "n": 0, + "spent": true, + "hex": "76a914f1f52994ca1ca3b41cb3a56de4f8b79f71297d5f88ac", + "addresses": [ + "t1fvxYkVjkmYJFaSR4254YNa6kwxXe2wEQA" + ] + }, + { + "value": "9692075960", + "n": 1, + "spent": true, + "hex": "76a9142d64ab150e654be79bcdbdd5dbf207e15ae90d3688ac", + "addresses": [ + "t1N1d1XJqrNzorBZUJb4cUWitAC9B5RcUoX" + ] + } + ], + "blockHash": "00000009610f94d5f51aceb2db2e7fb1ea0ebcb8c6857be2927b24a69ed59fc3", + "blockHeight": 335702, + "confirmations": 261808, + "blockTime": 1557735070, + "value": "9804420960", + "valueIn": "9804425480", + "fees": "4520", + "hex": "0400008085202f8901a3965a18fde175950a9fb2cb22d076d68014959b1134eff8968342fa38689a2b010000006b483045022100b25ab6c1a994d0f99c874187427802f1a2e8ee3746784fd32fc358b522d5467402207ea330c77121f8b426d79f9778f16be2d3f625afc8fc851ae9b0aa7418c6a938012103c85acfe75a3bb4418d5f604aced599253cb639a417c9920103016ca79402a0defeffff7f02a83fb206000000001976a914f1f52994ca1ca3b41cb3a56de4f8b79f71297d5f88acb857b141020000001976a9142d64ab150e654be79bcdbdd5dbf207e15ae90d3688ac00000000000000000000000000000000000000" + }, + { + "txid": "2b9a6838fa428396f8ef34119b951480d676d022cbb29f0a9575e1fd185a96a3", + "version": 4, + "vin": [ + { + "txid": "62182822cdbd2b7ad71b16367ccf596d8544ee4450b2c35a5b41fae161d9dfbc", + "vout": 1, + "sequence": 2147483644, + "n": 0, + "addresses": [ + "t1SgcKEowio345qNu4WP7XTYiveQfqbCCAR" + ], + "value": "9999780000", + "hex": "483045022100fdda44566c57e863456a2b484b23d428862004373fd1ffbb58c259b21e7c6420022034def3b5529041c618beeb42b0df14c72ea1f809c69bda7a45015f85bfabfd03012102f7db5b974c39646b235a4cc595e02667e3a49f6abe85e7a6abf22d1175e507bf" + }, + { + "txid": "62182822cdbd2b7ad71b16367ccf596d8544ee4450b2c35a5b41fae161d9dfbc", + "sequence": 2147483645, + "n": 1, + "addresses": [ + "t1bhSBfm7skGsVTsviTWJXfnemYkALxu6DQ" + ], + "value": "100000", + "hex": "483045022100f629a4105fc6b570c2fd77ccf0c4fc8cf1736014636eab5f2371d07bf63162270220338d1a472f71a7422b22522a11a287e2df5447d91e37ad5061d37ca6d7ab6246012102ac2c1cf8d7d5544a561e24dc2248d9d902d23b05f07b2e5b956caa58c43e967c" + }, + { + "txid": "3a88dcfb1a9a463b4f84518dab55ac163b9268aac79892a8d78be871368413e2", + "sequence": 2147483646, + "n": 2, + "addresses": [ + "t1aq5qqeEHCDRiZqxD66Ep8rG4C4t5bzfxj" + ], + "value": "100000", + "hex": "473044022033835423ef187b91284117d613dda15d0ad207480cf5bd4b1fe0bfa6640a90a0022055dd8d1bcdd9a01b5ae62d12602201e62baf9211fe67c2bd0fa224d97dbca181012102372994d86b56a483bc44e3ee25f53c97da15cc62dd3d7ae7bf89a678beaa56dc" + } + ], + "vout": [ + { + "value": "195550000", + "n": 0, + "spent": true, + "hex": "76a914f1f52994ca1ca3b41cb3a56de4f8b79f71297d5f88ac", + "addresses": [ + "t1fvxYkVjkmYJFaSR4254YNa6kwxXe2wEQA" + ] + }, + { + "value": "9804425480", + "n": 1, + "spent": true, + "hex": "76a914d90a2013ffe67484c05734b43b67955b6204301e88ac", + "addresses": [ + "t1dfCmUsQAD73vkFSsHPC1ak9b7ven8P7pe" + ] + } + ], + "blockHash": "000000117a47ddada66503612c032fd535243e04a771f8f04165623462b414ce", + "blockHeight": 335698, + "confirmations": 261812, + "blockTime": 1557734698, + "value": "9999975480", + "valueIn": "9999980000", + "fees": "4520", + "hex": "0400008085202f8903bcdfd961e1fa415b5ac3b25044ee44856d59cf7c36161bd77a2bbdcd22281862010000006b483045022100fdda44566c57e863456a2b484b23d428862004373fd1ffbb58c259b21e7c6420022034def3b5529041c618beeb42b0df14c72ea1f809c69bda7a45015f85bfabfd03012102f7db5b974c39646b235a4cc595e02667e3a49f6abe85e7a6abf22d1175e507bffcffff7fbcdfd961e1fa415b5ac3b25044ee44856d59cf7c36161bd77a2bbdcd22281862000000006b483045022100f629a4105fc6b570c2fd77ccf0c4fc8cf1736014636eab5f2371d07bf63162270220338d1a472f71a7422b22522a11a287e2df5447d91e37ad5061d37ca6d7ab6246012102ac2c1cf8d7d5544a561e24dc2248d9d902d23b05f07b2e5b956caa58c43e967cfdffff7fe213843671e88bd7a89298c7aa68923b16ac55ab8d51844f3b469a1afbdc883a000000006a473044022033835423ef187b91284117d613dda15d0ad207480cf5bd4b1fe0bfa6640a90a0022055dd8d1bcdd9a01b5ae62d12602201e62baf9211fe67c2bd0fa224d97dbca181012102372994d86b56a483bc44e3ee25f53c97da15cc62dd3d7ae7bf89a678beaa56dcfeffff7f0230dba70b000000001976a914f1f52994ca1ca3b41cb3a56de4f8b79f71297d5f88ac08a96348020000001976a914d90a2013ffe67484c05734b43b67955b6204301e88ac00000000000000000000000000000000000000" + }, + { + "txid": "62182822cdbd2b7ad71b16367ccf596d8544ee4450b2c35a5b41fae161d9dfbc", + "version": 4, + "vin": [ + { + "txid": "3a88dcfb1a9a463b4f84518dab55ac163b9268aac79892a8d78be871368413e2", + "vout": 1, + "n": 0, + "addresses": [ + "t1Uw7KatAex6XFc9pJGQBHZyVZWHJXMbvcz" + ], + "value": "9999890000", + "hex": "483045022100d90f5d69666a57a174b0092a150f7d59057bf6bcb9ef8dcf0839026dc2d9fbd902200ca850dbb66e1a10354f568471e10fa84ceb08f0805bc71259c04575b43ace7a012103c54ccc3fb56214fb90806fab5ff6807714060d25a0e4e8b59043fa3036f9fc44" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a914c385e7d7a9acce2dd1b8b2ff5fad07a7ce3e9fee88ac", + "addresses": [ + "t1bhSBfm7skGsVTsviTWJXfnemYkALxu6DQ" + ] + }, + { + "value": "9999780000", + "n": 1, + "spent": true, + "hex": "76a91460a4d06bdc93a79772d8915d9283974b1b8e16cd88ac", + "addresses": [ + "t1SgcKEowio345qNu4WP7XTYiveQfqbCCAR" + ] + } + ], + "blockHash": "0000002b39c084a105209115a1286fea6c4bb42556bc7b32db31d82b1c68f739", + "blockHeight": 335465, + "confirmations": 262045, + "blockTime": 1557705637, + "value": "9999880000", + "valueIn": "9999890000", + "fees": "10000", + "hex": "0400008085202f8901e213843671e88bd7a89298c7aa68923b16ac55ab8d51844f3b469a1afbdc883a010000006b483045022100d90f5d69666a57a174b0092a150f7d59057bf6bcb9ef8dcf0839026dc2d9fbd902200ca850dbb66e1a10354f568471e10fa84ceb08f0805bc71259c04575b43ace7a012103c54ccc3fb56214fb90806fab5ff6807714060d25a0e4e8b59043fa3036f9fc440000000002a0860100000000001976a914c385e7d7a9acce2dd1b8b2ff5fad07a7ce3e9fee88aca0880854020000001976a91460a4d06bdc93a79772d8915d9283974b1b8e16cd88ac00000000000000000000000000000000000000" + }, + { + "txid": "3a88dcfb1a9a463b4f84518dab55ac163b9268aac79892a8d78be871368413e2", + "version": 4, + "vin": [ + { + "txid": "2d02c105ac454698edacd39e4ff848b9756aae6732a060f73a20adf403688b25", + "n": 0, + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ], + "value": "10000000000", + "hex": "47304402204b239697ced2ce8dc71bf5b58a1d8a13b0ac3c13799e0712454ffbfdc5b9568902205682bfa6f5b040f95e7931afeb64c67388b20566220ea0f4fafca66116a54313012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" + } + ], + "vout": [ + { + "value": "100000", + "n": 0, + "spent": true, + "hex": "76a914ba0020826df8b9c6666ebd22345e79fe569eb01b88ac", + "addresses": [ + "t1aq5qqeEHCDRiZqxD66Ep8rG4C4t5bzfxj" + ] + }, + { + "value": "9999890000", + "n": 1, + "spent": true, + "hex": "76a91479531a25ddc6e1196ebc275a6ca8211a6bbf077f88ac", + "addresses": [ + "t1Uw7KatAex6XFc9pJGQBHZyVZWHJXMbvcz" + ] + } + ], + "blockHash": "00000014c2f3537ad6b930e329f483f025b87e0528b7dce2a901043dde3eb5f6", + "blockHeight": 335455, + "confirmations": 262055, + "blockTime": 1557705029, + "value": "9999990000", + "valueIn": "10000000000", + "fees": "10000", + "hex": "0400008085202f8901258b6803f4ad203af760a03267ae6a75b948f84f9ed3aced984645ac05c1022d000000006a47304402204b239697ced2ce8dc71bf5b58a1d8a13b0ac3c13799e0712454ffbfdc5b9568902205682bfa6f5b040f95e7931afeb64c67388b20566220ea0f4fafca66116a54313012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e366440000000002a0860100000000001976a914ba0020826df8b9c6666ebd22345e79fe569eb01b88ac50360a54020000001976a91479531a25ddc6e1196ebc275a6ca8211a6bbf077f88ac00000000000000000000000000000000000000" + }, + { + "txid": "2d02c105ac454698edacd39e4ff848b9756aae6732a060f73a20adf403688b25", + "version": 4, + "vin": [ + { + "txid": "870055cfff44ee7dd33e66b2b2246ee3f02b1dffd6c510e2e43e11da0f59bc15", + "sequence": 4294967295, + "n": 0, + "addresses": [ + "t1bJ2ot9ifKpiCn4FkhLJSDr1zxhB5x1AED" + ], + "value": "776500000000", + "hex": "4730440220438664cefb58d3b262b1acc91b02b7c2775385010f517f172e5d128b063c599d02203e1f6bc61e5a5538a384294e8bec7495bd167653cf040201ba651114565356fc012102fd6409055f25dcecf801a024a204b38d3d00ab6113f8c940000757070922b4ff" + } + ], + "vout": [ + { + "value": "10000000000", + "n": 0, + "spent": true, + "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", + "addresses": [ + "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" + ] + }, + { + "value": "766499996260", + "n": 1, + "spent": true, + "hex": "76a914bf18d3556e440187a15ff49f0bb3b16a3ded8b3d88ac", + "addresses": [ + "t1bJ2ot9ifKpiCn4FkhLJSDr1zxhB5x1AED" + ] + }, + { + "value": "0", + "n": 2, + "hex": "6a095a656c205465737420", + "addresses": [ + "OP_RETURN (Zel Test )" + ] + } + ], + "blockHash": "00000005b411a80eded51d3d934f947be0678d536007319e588d1b3af80e25c8", + "blockHeight": 335454, + "confirmations": 262056, + "blockTime": 1557704853, + "value": "776499996260", + "valueIn": "776500000000", + "fees": "3740", + "hex": "0400008085202f890115bc590fda113ee4e210c5d6ff1d2bf0e36e24b2b2663ed37dee44ffcf550087000000006a4730440220438664cefb58d3b262b1acc91b02b7c2775385010f517f172e5d128b063c599d02203e1f6bc61e5a5538a384294e8bec7495bd167653cf040201ba651114565356fc012102fd6409055f25dcecf801a024a204b38d3d00ab6113f8c940000757070922b4ffffffffff0300e40b54020000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac64c2f576b20000001976a914bf18d3556e440187a15ff49f0bb3b16a3ded8b3d88ac00000000000000000b6a095a656c205465737420000000009d2005000000000000000000000000" + } + ], + "usedTokens": 30, + "tokens": [ + { + "type": "XPUBAddress", + "name": "t1fRA1dKnK7Z78ZhMqKP2VxdS9VfYeGvLYm", + "path": "m/44'/19167'/0'/0/11", + "transfers": 1, + "decimals": 8, + "balance": "1000000", + "totalReceived": "1000000", + "totalSent": "0" + }, + { + "type": "XPUBAddress", + "name": "t1KGukfFELYq5cYpCgieyes3dCuaxNMUcb1", + "path": "m/44'/19167'/0'/1/17", + "transfers": 1, + "decimals": 8, + "balance": "9208317640", + "totalReceived": "9208317640", + "totalSent": "0" + } + ] +} diff --git a/mock/ext-api-data/zilliqa-api_addresses_zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z_txs.json b/mock/ext-api-data/zilliqa-api_addresses_zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z_txs.json new file mode 100644 index 000000000..6b197bf28 --- /dev/null +++ b/mock/ext-api-data/zilliqa-api_addresses_zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z_txs.json @@ -0,0 +1,30 @@ +[ + { + "hash": "0xa5d0e0cefd6f114e9659f15016f9f4a303a8367eb373beb6909ee44f7f39834d", + "blockHeight": 459052, + "from": "zil10lx2eurx5hexaca0lshdr75czr025cevqu83uz", + "to": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", + "value": "1000000000000", + "fee": "1000000000", + "timestamp": 1583384813191, + "signature": "0x00AF9733DF8FAEFA0FCC9BBAD21DB30A4815749C19CBFFA5A3BCE75A199E4C84FB4728CB946A2F043B8FCA338C8EEC26855CD7B88D8925E69F87CADF5D072343", + "direction": "in", + "nonce": 25, + "receiptSuccess": true, + "events": [] + }, + { + "hash": "0xe29a7e17402c0c067af4c285dedc79114fe62f23d39843c15756db4641f1a00d", + "blockHeight": 414452, + "from": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", + "to": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", + "value": "10000000000", + "fee": "1000000000", + "timestamp": 1580891803587, + "signature": "0xA5F2C86098A37149CDDD0884009FF1032714DDAC07B2831C87E1FEEB16B8D9B5EB5D310D042003B3AA27A31BE16FD62CD41E5B1F5108475FEB3EB5B8524DA3F4", + "direction": "self", + "nonce": 47, + "receiptSuccess": true, + "events": [] + } +] diff --git a/mock/ext-api-dyson/dyson.json b/mock/ext-api-dyson/dyson.json deleted file mode 100644 index 897ddd5f2..000000000 --- a/mock/ext-api-dyson/dyson.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "port": 3347, - "proxy": false, - "multiRequest": "+", - "quiet": false -} diff --git a/mock/ext-api-dyson/get/aeternity-api-transactions.js b/mock/ext-api-dyson/get/aeternity-api-transactions.js deleted file mode 100644 index 3f7eb9c40..000000000 --- a/mock/ext-api-dyson/get/aeternity-api-transactions.js +++ /dev/null @@ -1,60 +0,0 @@ -/// Aeternity API Mock -/// See: -/// curl "http://localhost:3347/aeternity-api/middleware/transactions/account/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb?" -/// curl "https://mdw.aepps.com/middleware/transactions/account/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb?" -/// curl http://localhost:8437/v1/aeternity/ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb -module.exports = { - path: "/aeternity-api/middleware/transactions/:type/:address?", - template: function(params, query, body) { - //console.log(query) - if (params.type === 'account') { - if (params.address === 'ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb') { - return JSON.parse(` - [ - { - "block_hash": "mh_2V2PJ732cTfDqD4CaWr6W1s1fN531PqiVydMiy7gooccQFoGvM", - "block_height": 222994, - "hash": "th_WfeoRYXd13MMmDBzMXjBBdaNSSaRXkwUwJ7tFxJ7ZKPQVNXC4", - "signatures": [ - "sg_MLBxuqnHUD21i747SKnQuyNh1LzLuH7RDHqY1mngZyJMDWL9LFcuMbKdo2XMbwkMmskFsgfsZZBwgyA5w4Xs3ghynF2AF" - ], - "time": 1583633007081, - "tx": { - "amount": 1.99979979992e21, - "fee": 16840000000000, - "nonce": 3, - "payload": "ba_Xfbg4g==", - "recipient_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", - "sender_id": "ak_26dGJ7S5ba7LhUXPo8vMPe4QuNaQbskWnM5jkopPuim3PGny9Y", - "type": "SpendTx", - "version": 1 - } - }, - { - "block_hash": "mh_Z1a6HSs9vE5XDf8JtSiQMN5UpX49Spgnf9Sn32TiXxKwSbsP6", - "block_height": 186035, - "hash": "th_2wGEGmqwRMPYdv3vz1EE7ueJEveMTzEWzosgUH9ytERjGMv3rX", - "signatures": [ - "sg_66c2LXv4rvYnn4r2fZ4H1wxieDUuVEUF6fLCB3M13MjB9QNfEH4q9YThUWJCo5WzWKxzqjb3RbumhXdUZh8YDq3v8KZ2M" - ], - "time": 1576946253731, - "tx": { - "amount": 1.00079975e21, - "fee": 50000000000000, - "nonce": 3, - "payload": "ba_Xfbg4g==", - "recipient_id": "ak_26dGJ7S5ba7LhUXPo8vMPe4QuNaQbskWnM5jkopPuim3PGny9Y", - "sender_id": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", - "ttl": 186135, - "type": "SpendTx", - "version": 1 - } - } - ] - `); - } - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js b/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js deleted file mode 100644 index a9af61863..000000000 --- a/mock/ext-api-dyson/get/aion-get-getTransactionsByAddress.js +++ /dev/null @@ -1,75 +0,0 @@ -/// Aion API Mock -/// See: -/// curl "http://localhost:3347/aion-api/getTransactionsByAddress?accountAddress=0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed&size=25" -/// curl "https://mainnet-api.theoan.com/aion/dashboard/getTransactionsByAddress?accountAddress=0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed&size=25" -/// curl http://localhost:8437/v1/aion/0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed -module.exports = { - path: "/aion-api/getTransactionsByAddress?", - template: function(params, query, body) { - //console.log(query) - if (query.accountAddress === '0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed') { - return JSON.parse(` - { - "page": { - "number": 0, - "size": 25, - "totalPages": 1, - "start": 1582532306, - "end": 1585037906, - "totalElements": 2 - }, - "content": [ - { - "blockHash": "f9aab3a58f9211d9d37458d8a87e49f2e00d1d242390d4650cd4092897650797", - "nrgPrice": 10000000000, - "toAddr": "a0c00cfc4c53bb6d49f385b91f58a23dd7b1dc024976b391bb8b81eb9e8801ab", - "contractAddr": "", - "data": "", - "year": 2020, - "internalTransactionCount": 0, - "transactionIndex": 0, - "type": "DEFAULT", - "nonce": "1e2f", - "transactionHash": "511d3a4aafbdd26825a1655b5c7525df5bea8a8ef0f887d5490b490055b53df7", - "transactionTimestamp": 1584349754, - "nrgConsumed": 21000, - "month": 3, - "blockNumber": 5619712, - "blockTimestamp": 1584349754, - "transactionLog": "[]", - "fromAddr": "a04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed", - "day": 16, - "value": "1.002217611212000000000000000000000000", - "txError": "" - }, - { - "blockHash": "ed8d3d92da7228c35c363f55383c602b6f5041b37ff165231245cfa83b863ae7", - "nrgPrice": 10000000000, - "toAddr": "a04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed", - "contractAddr": "", - "data": "", - "year": 2020, - "internalTransactionCount": 0, - "transactionIndex": 2, - "type": "DEFAULT", - "nonce": "2b2e55", - "transactionHash": "84789693b108bc3c437f8dccbd517682f611036d54621ec1f4db26f661fde468", - "transactionTimestamp": 1584349550, - "nrgConsumed": 21000, - "month": 3, - "blockNumber": 5619690, - "blockTimestamp": 1584349550, - "transactionLog": "[]", - "fromAddr": "a00983f07c11ee9160a64dd3ba3dc3d1f88332a2869f25725f56cbd0be32ef7a", - "day": 16, - "value": "1.002427611212000000000000000000000000", - "txError": "" - } - ] - } - `); - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/algorand-api-account.js b/mock/ext-api-dyson/get/algorand-api-account.js deleted file mode 100644 index f923d29ac..000000000 --- a/mock/ext-api-dyson/get/algorand-api-account.js +++ /dev/null @@ -1,41 +0,0 @@ -/// Mock for external Algorand API -/// curl "http://localhost:3347/algorand-api/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions?" -/// curl "http://{algorand rpc}/v1/account/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U/transactions?" -/// curl http://localhost:8437/v1/algorand/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U - -module.exports = { - path: '/algorand-api/v1/account/:account/transactions?', - template: function(params, query, body) { - //console.log(params) - switch (params.account) { - case '4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U': - return JSON.parse(` - { - "transactions": [ - { - "type": "pay", - "tx": "JZTKP6RRFGUDOZ7DQIR26DQWRDYZVYG2G3WDE4WLBJ77AMAEBFBA", - "from": "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", - "fee": 1000, - "first-round": 5478300, - "last-round": 5478749, - "noteb64": "sHLxsLBrP3o=", - "round": 5478346, - "payment": { - "to": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", - "amount": 1, - "torewards": 2052177, - "closerewards": 0 - }, - "fromrewards": 0, - "genesisID": "mainnet-v1.0", - "genesishashb64": "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=" - } - ] - } - `); - } - - return {error: "Not implemented"} - } -}; diff --git a/mock/ext-api-dyson/get/algorand-api-block.js b/mock/ext-api-dyson/get/algorand-api-block.js deleted file mode 100644 index 2b28a1490..000000000 --- a/mock/ext-api-dyson/get/algorand-api-block.js +++ /dev/null @@ -1,61 +0,0 @@ -/// Mock for external Algorand API -/// curl "http://localhost:3347/algorand-api/v1/block/5478346?" -/// curl "http://{algorand rpc}/v1/block/5478346?" -/// curl http://localhost:8437/v1/algorand/4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U - -module.exports = { - path: '/algorand-api/v1/block/:block?', - template: function(params, query, body) { - //console.log(params) - switch (params.block) { - case '5478346': - return JSON.parse(` - { - "hash": "SU4PUD4YK5DPIXUXDLEZOEHVVIIP4SWZORFPJBW2J22QO444NSAA", - "previousBlockHash": "CC4CQRE2U5AC7S7JLJHDVVGIDCHGWTDFIZM3P34TVTC7AP4BA2AQ", - "seed": "NLAQIQXPCZI5QMKMRFFKMIKANNBC4PTFW5QFVAK7U6FE477T2TRA", - "proposer": "WCFKBT4NEPDUCQP7MGLIWV4QGXIBOCXJFVYNTXF3HZHFHGQGHGR5WWA7XA", - "round": 5478346, - "period": 0, - "txnRoot": "KFADZYI64LDUX76VWVVV3MROORV5RXAVNZA7MVTWOP2QTGW6DZ2A", - "reward": 111421, - "rate": 25999967, - "frac": 2639736378, - "txns": { - "transactions": [ - { - "type": "pay", - "tx": "JZTKP6RRFGUDOZ7DQIR26DQWRDYZVYG2G3WDE4WLBJ77AMAEBFBA", - "from": "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", - "fee": 1000, - "first-round": 5478300, - "last-round": 5478749, - "noteb64": "sHLxsLBrP3o=", - "round": 5478346, - "payment": { - "to": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", - "amount": 1, - "torewards": 2052177, - "closerewards": 0 - }, - "fromrewards": 0, - "genesisID": "mainnet-v1.0", - "genesishashb64": "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=" - } - ] - }, - "timestamp": 1584332782, - "currentProtocol": "https://github.com/algorandfoundation/specs/tree/4a9db6a25595c6fd097cf9cc137cc83027787eaa", - "nextProtocol": "", - "nextProtocolApprovals": 0, - "nextProtocolVoteBefore": 0, - "nextProtocolSwitchOn": 0, - "upgradePropose": "", - "upgradeApprove": false - } - `); - } - - return {error: "Not implemented"} - } -}; diff --git a/mock/ext-api-dyson/get/binance-rpc-commands2.js b/mock/ext-api-dyson/get/binance-rpc-commands2.js deleted file mode 100644 index a20a7f4fd..000000000 --- a/mock/ext-api-dyson/get/binance-rpc-commands2.js +++ /dev/null @@ -1,143 +0,0 @@ -/// Binance chain RPC Mock -/// See: -/// curl "http://localhost:3347/binance-rpc/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q" -/// curl "http://localhost:3347/binance-rpc/v1/tokens?limit=1000&offset=0" -/// curl "https://{binance_rpc}/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q" -/// curl "https://{binance_rpc}/v1/tokens?limit=1000&offset=0" -/// curl "http://localhost:8437/v2/binance/tokens/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q?Authorization=Bearer" - -module.exports = { - path: '/binance-rpc/:version/:command1/:command2?', - template: function(params, query, body) { - switch (params.version) { - case 'v1': - switch (params.command1) { - case 'account': - switch (params.command2) { - case 'bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q': - return JSON.parse(` - { - "account_number": 273171, - "address": "bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q", - "balances": [ - { - "free": "226.53110295", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BNB" - }, - { - "free": "2623.96917801", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "BUSD-BD1" - }, - { - "free": "0.05000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "TWT-8C2" - } - ], - "flags": 0, - "public_key": [ - 2, 142, 117 - ], - "sequence": 75 - } - `); - } - break; - - case 'tokens': - return JSON.parse(` - [ - { - "mintable": true, - "name": "Africa Stable-Coin", - "original_symbol": "ABCD", - "owner": "bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms", - "symbol": "ABCD-5D8", - "total_supply": "3347000.00000000" - }, - { - "mintable": false, - "name": "Aditus", - "original_symbol": "ADI", - "owner": "bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps", - "symbol": "ADI-6BB", - "total_supply": "750000000.00000000" - }, - { - "mintable": false, - "name": "Aergo", - "original_symbol": "AERGO", - "owner": "bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl", - "symbol": "AERGO-46B", - "total_supply": "500000000.00000000" - }, - { - "mintable": false, - "name": "Alaris", - "original_symbol": "ALA", - "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", - "symbol": "ALA-DCD", - "total_supply": "60000000.00000000" - }, - { - "mintable": false, - "name": "ANKR", - "original_symbol": "ANKR", - "owner": "bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn", - "symbol": "ANKR-E97", - "total_supply": "10000000000.00000000" - }, - { - "mintable": false, - "name": "Aeron", - "original_symbol": "ARN", - "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", - "symbol": "ARN-71B", - "total_supply": "20000000.00000000" - }, - { - "mintable": true, - "name": "ARPA", - "original_symbol": "ARPA", - "owner": "bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c", - "symbol": "ARPA-575", - "total_supply": "12000000.00000000" - }, - { - "mintable": false, - "name": "Maecenas ART Token", - "original_symbol": "ART", - "owner": "bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l", - "symbol": "ART-3C9", - "total_supply": "100000000.00000000" - }, - { - "mintable": true, - "name": "Atlas Protocol", - "original_symbol": "ATP", - "owner": "bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf", - "symbol": "ATP-38C", - "total_supply": "40000000.00000000" - }, - { - "mintable": false, - "name": "Travala.com Token", - "original_symbol": "AVA", - "owner": "bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c", - "symbol": "AVA-645", - "total_supply": "61383832.00000000" - } - ] - `); - } - } - - // not found, address - return {txNums: 0, txArray: []} - } -}; diff --git a/mock/ext-api-dyson/get/binance-rpc-txs.js b/mock/ext-api-dyson/get/binance-rpc-txs.js deleted file mode 100644 index 5813d3dc9..000000000 --- a/mock/ext-api-dyson/get/binance-rpc-txs.js +++ /dev/null @@ -1,69 +0,0 @@ -/// Binance chain block explorer mock transaction -/// Returns: -/// - Multi-transaction transaction for a specific address -/// 1. newman calls: http://localhost:8437/v1/binance/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q -/// 2. Block Atlas calls internally : https://{binance_explorer}/api/v1/txs?address=bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q&page=1&rows=25&txType=TRANSFER -/// 3. Dyson response mock data: http://localhost:3347/binance-explorer/api/v1/txs?address=bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q&page=1&rows=25&txType=TRANSFER -/// - empty response for other txHash'es - -// Example contains each type, BNB transfer, BEP2 transfer, BEP2 transfer as multisend transaction -module.exports = { - path: '/binance-explorer/api/v1/txs', - template: function (params, query, body) { - return JSON.parse(`{ - "txNums": 3, - "txArray": [ - { - "txHash": "963D8C627DE1E739845C0AC0C0EAC3387B53806C77289ACB8C1653CD6D62C9CC", - "blockHeight": 84191249, - "txType": "TRANSFER", - "timeStamp": 1588086370574, - "fromAddr": "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", - "toAddr": "bnb1mr5f97rx5wnkfcakx9fcpvljmx2s6kwqc08yur", - "value": 2800.00000000, - "txAsset": "TWT-8C2", - "txFee": 0.00037500, - "txAge": 446701, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "", - "source": 0, - "hasChildren": 0 - }, - { - "txHash": "4577CB3B5B202696E9E0B093A6DA973C7DD9CBC6808DA1326872745C35F3C089", - "blockHeight": 84191216, - "txType": "TRANSFER", - "timeStamp": 1588086357686, - "fromAddr": "bnb1mr5f97rx5wnkfcakx9fcpvljmx2s6kwqc08yur", - "toAddr": "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", - "value": 0.00040000, - "txAsset": "BNB", - "txFee": 0.00037500, - "txAge": 446714, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "", - "source": 0, - "hasChildren": 0 - }, - { - "txHash": "FAD8C1C5E450BE5E0913B12007AAEACC307F8CFFAFFB0844A9F83155E1235C25", - "blockHeight": 80167666, - "txType": "TRANSFER", - "timeStamp": 1586464452922, - "txFee": 0.29970000, - "txAge": 2068619, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "", - "source": 0, - "hasChildren": 1 - } - ] -}`) - } -}; diff --git a/mock/ext-api-dyson/get/bitcoin-api-address.js b/mock/ext-api-dyson/get/bitcoin-api-address.js deleted file mode 100644 index a8e8f7529..000000000 --- a/mock/ext-api-dyson/get/bitcoin-api-address.js +++ /dev/null @@ -1,113 +0,0 @@ -/// Mock for external Bitcoin API -/// See: -/// curl "http://localhost:3347/bitcoin-api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" -/// curl "https://btc1.trezor.io/api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs" -/// curl "http://localhost:8437/v1/bitcoin/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - -module.exports = { - path: '/bitcoin-api/v2/address/:address?', - template: function (params, query, body) { - switch (params.address) { - case 'bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj", - "balance": "15245", - "totalReceived": "91089", - "totalSent": "75844", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 12, - "transactions": [{ - "txid": "36b1e721a25ea3ac2fcc09a92d4ff1e2ae4ed70d593e276806d9a9fd2a901132", - "version": 1, - "vin": [{ - "txid": "c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be", - "vout": 1, - "n": 0, - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true, - "value": "4829" - }], - "vout": [{ - "value": "1000", - "n": 0, - "hex": "a9141ba5187259ae22520f99ec3522d320279066aafd87", - "addresses": [ - "34DBwkzPz6yeqU1LoZLVzdCm91oeyxq37T" - ], - "isAddress": true - }, - { - "value": "2699", - "n": 1, - "hex": "00148f347b3ea1ce113b09e096125a3ad3310dd0a947", - "addresses": [ - "bc1q3u68k04pecgnkz0qjcf95wknxyxap2287gyzrg" - ], - "isAddress": true - } - ], - "blockHash": "0000000000000000000fccc2c78e235d6ea3da4013ea98c8376c7c41f7f71938", - "blockHeight": 624894, - "confirmations": 2494, - "blockTime": 1586299624, - "value": "3699", - "valueIn": "4829", - "fees": "1130", - "hex": "01000000000101be328cc2ca0135e640bc1e795f20d3189939ab3712d8e79627347a5c2dc8a4c601000000000000000002e80300000000000017a9141ba5187259ae22520f99ec3522d320279066aafd878b0a0000000000001600148f347b3ea1ce113b09e096125a3ad3310dd0a94702483045022100c251d7e2497b42d57ff00c92eeb8a6faa86a3d5d77a9d257b7e464400306fa5502204f532ab553ba711779cf1f93cab47c4f5e0f11dbc6017781c79b76caa6ea322b012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" - }, - { - "txid": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4", - "version": 1, - "vin": [{ - "txid": "270a6490cc806d99aa84bb8079b543d9d7a255fc59364890e7a4cb57970daef8", - "vout": 1, - "sequence": 4294967294, - "n": 0, - "addresses": [ - "bc1q3230a7cqt2drewuza8qff4c4gpt4muy9qyqknw" - ], - "isAddress": true, - "value": "1699" - }], - "vout": [{ - "value": "375", - "n": 0, - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true - }, - { - "value": "1098", - "n": 1, - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true - } - ], - "blockHash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", - "blockHeight": 622017, - "confirmations": 5371, - "blockTime": 1584485709, - "value": "1473", - "valueIn": "1699", - "fees": "226", - "hex": "01000000000101f8ae0d9757cba4e790483659fc55a2d7d943b57980bb84aa996d80cc90640a270100000000feffffff0277010000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a4a040000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220683d9c2b40958fd706623783017300ebbc9b73ce1db571963d9bb40679c3079c02207ee68976e225e1e98d20e66d4d8a498cddf3268d0d7b66827a2ed3ac4330f137012102b7f0cb54c2a6a4da3372fe17d7a07475f575777364633e89dacb39eb1fd5a09c00000000" - } - ] - } - `); - } - return { error: "Not implemented" }; - } -} diff --git a/mock/ext-api-dyson/get/bitcoin-api-xpub.js b/mock/ext-api-dyson/get/bitcoin-api-xpub.js deleted file mode 100644 index c5a5a12b5..000000000 --- a/mock/ext-api-dyson/get/bitcoin-api-xpub.js +++ /dev/null @@ -1,168 +0,0 @@ -/// Mock for external Bitcoin API -/// See: -/// curl "https://btc1.trezor.io/api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs" -/// curl "http://localhost:3347/bitcoin-api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs" -/// curl "http://localhost:8437/v1/bitcoin/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC" - -module.exports = { - path: '/bitcoin-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - "balance": "37093", - "totalReceived": "4218808", - "totalSent": "4181715", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 92, - "transactions": [ - { - "txid": "c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be", - "version": 1, - "vin": [ - { - "txid": "d39d78838d5a3c870aa5acdc9e518945bd6ad86af093b38f85c714f790f28c76", - "vout": 1, - "n": 0, - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true, - "value": "6055" - } - ], - "vout": [ - { - "value": "1000", - "n": 0, - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true - }, - { - "value": "4829", - "n": 1, - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true - } - ], - "blockHash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", - "blockHeight": 622017, - "confirmations": 780, - "blockTime": 1584485709, - "value": "5829", - "valueIn": "6055", - "fees": "226", - "hex": "01000000000101768cf290f714c7858fb393f06ad86abd4589519edcaca50a873c5a8d83789dd301000000000000000002e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169add120000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a02483045022100cb25ac0d9e69ddaaedd49e3a3f9efb218b38bf49c2abf44ff2266bfb941bd3b202206b32cc1337f9a6a176fabadd6aefdf5a95d479e5db856d4e3e8eee7fefc26773012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" - }, - { - "txid": "8180545030fcfb7b14ee90acb01b606c5a68fe1d520bcf140bd0097108c2b7f4", - "version": 1, - "vin": [ - { - "txid": "270a6490cc806d99aa84bb8079b543d9d7a255fc59364890e7a4cb57970daef8", - "vout": 1, - "sequence": 4294967294, - "n": 0, - "addresses": [ - "bc1q3230a7cqt2drewuza8qff4c4gpt4muy9qyqknw" - ], - "isAddress": true, - "value": "1699" - } - ], - "vout": [ - { - "value": "375", - "n": 0, - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true - }, - { - "value": "1098", - "n": 1, - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true - } - ], - "blockHash": "00000000000000000006ff4c09a5e05c4a28dffe54beb7ef0c61f8dd940a951e", - "blockHeight": 622017, - "confirmations": 780, - "blockTime": 1584485709, - "value": "1473", - "valueIn": "1699", - "fees": "226", - "hex": "01000000000101f8ae0d9757cba4e790483659fc55a2d7d943b57980bb84aa996d80cc90640a270100000000feffffff0277010000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a4a040000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220683d9c2b40958fd706623783017300ebbc9b73ce1db571963d9bb40679c3079c02207ee68976e225e1e98d20e66d4d8a498cddf3268d0d7b66827a2ed3ac4330f137012102b7f0cb54c2a6a4da3372fe17d7a07475f575777364633e89dacb39eb1fd5a09c00000000" - }, - { - "txid": "d39d78838d5a3c870aa5acdc9e518945bd6ad86af093b38f85c714f790f28c76", - "version": 1, - "vin": [ - { - "txid": "c215e9c6f9533d584effc4d31d08736a0ef4f717b7d42563ebba053f5f3bc1d5", - "vout": 1, - "sequence": 4294967287, - "n": 0, - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true, - "value": "8185" - } - ], - "vout": [ - { - "value": "1000", - "n": 0, - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true - }, - { - "value": "6055", - "n": 1, - "spent": true, - "hex": "00141a475acd52ae04da60ab33bf373c9255cea3169a", - "addresses": [ - "bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj" - ], - "isAddress": true - } - ], - "blockHash": "0000000000000000000ab8b2230f5b63d4d4be1a0aa6b9296cfc09e48c8e42e0", - "blockHeight": 619385, - "confirmations": 3412, - "blockTime": 1582902175, - "value": "7055", - "valueIn": "8185", - "fees": "1130", - "hex": "01000000000101d5c13b5f3f05baeb6325d4b717f7f40e6a73081dd3c4ff4e583d53f9c6e915c20100000000f7ffffff02e8030000000000001600141a475acd52ae04da60ab33bf373c9255cea3169aa7170000000000001600141a475acd52ae04da60ab33bf373c9255cea3169a024730440220158b0d8c5fb6cb9f60d0af05ce8b63abe934dca8eca380013bc7e8463420810f02207d7e6594586ec8196546e2520b6775c2e8659c8f266acb3b861e99f13cf1b380012102624729d04d58fa33eb3f7be9fe9c307c60aa1bad52f4ffbacc78ba3808faf62500000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/bitcoincash-api-address.js b/mock/ext-api-dyson/get/bitcoincash-api-address.js deleted file mode 100644 index c92626142..000000000 --- a/mock/ext-api-dyson/get/bitcoincash-api-address.js +++ /dev/null @@ -1,1391 +0,0 @@ -/// Mock for external Bitcoincash API -/// See: -/// curl "http://{bch rpc}/api/v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" -/// curl "http://localhost:3347/bitcoincash-api/v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs" -/// curl "http://localhost:8437/v1/bitcoincash/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - -module.exports = { - path: '/bitcoincash-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 'bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme': - return JSON.parse(` - { - "page": 1, - "totalPages": 5034, - "itemsOnPage": 2, - "address": "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme", - "balance": "0", - "totalReceived": "12502830507987", - "totalSent": "12502830507987", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 10067, - "transactions": [ - { - "txid": "0284cb9b8deb0534efa8fc8911db1e8f9b106d00608c712d31c3680f303fbf36", - "version": 2, - "lockTime": 611622, - "vin": [ - { - "txid": "2f150ee63214982edbaf23c85629e920e16093d0506ed284ec3018ebe8746b12", - "sequence": 4294967294, - "n": 0, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250119473", - "hex": "47304402206f992d73dfa7e518b00190f220ad5dc7b7947b1d75a2fcd8251b59f3d29d89af022036c6c44f52f9aeed406dec72a9aab1f82c3b997c36742f4a3504e4f93e6f8557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "550ba873216e6690c8ca34992da41ecaa29e74a557943af604537de13fb84838", - "sequence": 4294967294, - "n": 1, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250052374", - "hex": "483045022100db30ebe47536e42115a507f88bb8d5c97b81ad05ce334872235811134c5948bb0220418d77aed78cc4a332b1858c1d2e9ab169828b9c12e8c0d0f8d155964e5d0b8e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "ed8d8d9810ca30cd0512a0e0ca87649713a550a015bb0022c16686c2ccb22143", - "sequence": 4294967294, - "n": 2, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250058021", - "hex": "483045022100d30c9fd598613586d8d0460fb6c9ffc1d0c6dff6f647535d2a9f69cf373193d102207fff687aa035910db124adad8b59607a72b3d24aca9096217ec6b90fa132a2ae412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "a2d79bacd53918c9ad6b27055eff555130f1af8522f77a09c4d74321dad8a032", - "sequence": 4294967294, - "n": 3, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250022804", - "hex": "47304402207b30e99cb1f6754d227a4511c5b7791f3b896724b170716d6ed238017f191bb102202c1fadc4c572c86288b002a0d6b6d2460a14a6d3c8b49efc17a03e59d2db18e3412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "9a0679dc735b7774ab3aa55a01188ce4d70613927b1b0ca9f96784b09479f762", - "vout": 1, - "sequence": 4294967294, - "n": 4, - "addresses": [ - "bitcoincash:qzqn6xdqhaqa8yykvq4e94td4yg0k9ll9vyjf47x0f" - ], - "isAddress": true, - "value": "1620505", - "hex": "48304502210092b7f176f182936323df8e4359b2a329b0c1e4b48a529d6e32867038a2a453cc02203c24a8bb46b7fea4ef5c78ff116a51fd0a04dee25bfcdffe856fb8988a7a97f64121035b4e75dda9fb0d55d856f54f24fc65da6657939b9559ab2c623c8ef325f14d8d" - }, - { - "txid": "5d557c0c3331dc1dc4db34776603c01ce24ac8b0adf1f6fc2cc07a88baf5bf5c", - "sequence": 4294967294, - "n": 5, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250096547", - "hex": "47304402202a2bcfdaf12c398ed5372e6b168a786edb8972df1146b705d3cccf2d9601517d022020b90ac89d9141d68817850d1cdffaf6c51f45249a44fd6861b361a6025d8ac4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "61dbe706b513c1ee5aa577a07782471cf5c0c13fd7ce31b29cdd1c2362ea0bca", - "sequence": 4294967294, - "n": 6, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250179897", - "hex": "48304502210087ef2709b9fe8e7f136219254229edd45e94c3f6ebd2bb149aadd9b1d44d89e202206ffde3c9491c012832967e4d34e02ece2c08bc4c07967b3b466d4800f9ca0746412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "54b28d128142bb03aa60e9cf535fe30d5916089f1e70ac94444572008e9b3b84", - "sequence": 4294967294, - "n": 7, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250044246", - "hex": "483045022100c7dbd1117c57eedc8fc006e818371bfe6399c4d25e8b40482c1f0858a3d98a4b0220426d1196513a87fc7afb5b107b770a90af789536799a11686eab96b04afa6326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "750c2e638eb26bd271586fe201f48e21ef7fcef1154a6b6335d2bd4381450123", - "sequence": 4294967294, - "n": 8, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1252404910", - "hex": "47304402203604fbb20824443899030d2c1f5cd0dc2b88174929861a708bdca878868e910c02200a607b1da53483bc95d3a5c54e5ad66e459827d4ecf8b4ef9909e9d58b2d329b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "9b6dc387b59e4af25bfa14067e24c399fae3fbb744e97edb670087265ebcecf9", - "sequence": 4294967294, - "n": 9, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1256320052", - "hex": "4730440220399c36174173cca01f6d6a234a935d6f776b549e1ea2fc2635193924c4ac2eb002205aea7741fafd95f862588c480aaa282d7a344d32d6318aec1a908cbb939e5d0e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "8f27da29f81ae3ac3ab90f29cd4988d718cd351f965892b073a80b9a9492f49e", - "vout": 1, - "sequence": 4294967294, - "n": 10, - "addresses": [ - "bitcoincash:qz8mkaldpk8zk2ge27wpn8ue0uwu28xq5552u5c5my" - ], - "isAddress": true, - "value": "1687043", - "hex": "483045022100da9075310e7af59456423be99362f2cc686d50571e0f0b016bcfae1f0bc4692802203379b648d47704dba48542b8b6d5e515bf3c4fd7ff8a7be82cd0c8c0c7be56f7412103a344a84dc1a919a64874605fae200861b7af3ecd02dc5d52dd00eb6f8845525a" - }, - { - "txid": "109bf48f720a9d05fd7a74b632164ed96db721b00458420595d799b437305f5c", - "sequence": 4294967294, - "n": 11, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1251895732", - "hex": "47304402206cbf93634d6a477a571fa2884c19918b19ddfb008ff9fe405954720047efdb88022003e755313436d406dddfe3cfb68719e8f39e43de7c586489cc543dac0347da9f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "d3e570366f647db1f73079b743ec994169875c7af42ff2e9f3cf290fcb3f180b", - "sequence": 4294967294, - "n": 12, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250081823", - "hex": "483045022100f23d4cf11fd0a5ab83dc053ca64066cbdd2fb4107e0977a3a880c68a67636f7d0220220a47c66d3944cfc309c059fe8013c4de742e4d8590003fd56c5e0b3c7da557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "6f05f99a402127463db6dc2f8f6b1064109fbfb93bacb258babd2aa861055480", - "sequence": 4294967294, - "n": 13, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250020672", - "hex": "4830450221009f522beef55cbf8c7f10e88739846f78ef1c9d9cbc6959dba6f687a08fec0ef502203a160231733b87c6cfd8afd148994c9b6c5d5db9bb9847aa9e60938a6e79d5b1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "3d93b717b0676245a3dc3fb86625d9abffac4f66e2889a81a07733a14e1e4a4a", - "sequence": 4294967294, - "n": 14, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250118486", - "hex": "47304402201f5d29be80192a752fe28ff141ed702640df88083faf3f9573e52405cb4bd79a02202d751649aa600c4fdb8b1d1b21f0d134c2f4e5af9ecbe7d87180d667140f0a11412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "c77ac92e646677bf9e59873c5f5036831d5d5597cda469b7e6b30a9563a3419b", - "sequence": 4294967294, - "n": 15, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250097156", - "hex": "47304402203f4bea3816d252cb19d4247f587a146901c74d04e783efddfd5089942f2abcdb022069012613c4ee4b3b0212ae71dbd2071e01665148697011eb03eba25431e679cf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "90cba3db7e020c7b8943293ecca7f6a2150082a372972c0ed65646337b0b05ab", - "sequence": 4294967294, - "n": 16, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250175150", - "hex": "4730440220782ba77287116d5d735f67a3738fbecc1a802d2141a1fa544f61a5e8ba682a4402205473d68019cc8895ecb1d87bfced62ddb6dc48b81152f2684ae8530122d5b41f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "e25ec382049a4d8edd530469e5e41d9e056a2081b661f505414b1348e482dd26", - "vout": 1, - "sequence": 4294967294, - "n": 17, - "addresses": [ - "bitcoincash:qqnfldeu0yd4wd89c44sujdz2w7hwvvd3y8g9tuech" - ], - "isAddress": true, - "value": "1884419", - "hex": "473044022044ed9bfa8674d7e83112fa22280797169d45bd971b185da2413e36252637529d0220531eefc480e0911d6ccda42002942883149bc1cdd1f3bbde313751d80bcf98b641210328ac4ed2b30ddc04c778a78b24e7256b08c55758c1465defd997ff4bcefacf10" - }, - { - "txid": "13a148dff09d7786a7e0d0929e7ece3c9fb8de532597cbb0d045f5ec531b2e9e", - "sequence": 4294967294, - "n": 18, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250028570", - "hex": "4830450221008cfdfd352e268dba2022e7fbfc37a90401c40fdf6f1d8ba9dcb97d67743eddc302202c0a1b604d34aa174fddef63c9115c95465548855c5f783bb206eb4ff8fda235412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "700dfcfa0847678c56a084b5a75fb8aef1b1a1126512b026ebdb8c45d55efdf9", - "sequence": 4294967294, - "n": 19, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250039508", - "hex": "473044022001b33b610b8d742df2ad98679f1e41f0c647faf272e15e7ea93171ba29c33bcd022061646fbcb81ba30d6e8b030ee12101d1f1bef38ba44a6d5daf40c4ff6d644e6e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "6810932357166daa33c2125cf38be6076f7b6f718f199348905459f22ba7f2a6", - "sequence": 4294967294, - "n": 20, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250136993", - "hex": "483045022100ec9b6bbaba90d8902ec8a1ca0e90ea594264bc1add204b756cc89def4d7e9a2a022066b2bc84f94e1a99effe0e929be8de8669631143ca20c73e700d182ad4884e71412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "42a98564873f7c888a6a569cb97066b4bc43c5fa41d732573774f996b91980b3", - "sequence": 4294967294, - "n": 21, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250053520", - "hex": "473044022057117591cc465c48da58ebcb8f57fcd56359757d41e1397e45b5e33e034ea5d8022001de1d78ce9e8e73370a0778b4a8595045c6faeb2497ab4296d0cff735711276412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "f7b56e95b5a48a66649fd3e9e9bc94a7a01bd1c4822c4dcc2c40243c8da60bbd", - "sequence": 4294967294, - "n": 22, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250111141", - "hex": "483045022100dace56650d1d9edaef30e8c9ecb4b78499a573984c8a451253295a90c84a3ed702201f4587d4a760cd77a2e21d5f6f2b7aacf668220c8c7c62fc1ae4779f7c0141cd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "d58b912c125283ee0249b670a7901bd5a1061d92f7c06627b5e963fb0b2c3d14", - "sequence": 4294967294, - "n": 23, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250143132", - "hex": "47304402200db6b461a0082807f59053bea210d38f5f82f02dd63a57f6e3987339cac23870022064ba927fc11b36318785d4e861a7f94cb3909ef8fe882360e2041f7b4a444692412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "530326ce09e8f933a604488e5e2f06845c3e805761c02eced5cc02856be1b7b0", - "sequence": 4294967294, - "n": 24, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250022822", - "hex": "483045022100a3e75a6c7918db32a27be348493b831631856ec8f546ca43d143cdc3c1cd03c802201e6ae036423bfce45c500b0c049f68396deae5cb999038de61e972ccd4cba5e7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "ca51412ad37c5e5a49b11dc7858b4013ff68288c56e6026b11a4266e184b286d", - "sequence": 4294967294, - "n": 25, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250033136", - "hex": "483045022100caf952ca1760052cfefe8df283fdd0eccb9e1238eea88eef287df9404c622e8b022072027363fa1070548576fbf9bcbddf2e435fd020662b2d8f0582b52bfa487b31412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "c03e268bbb105f171305f7fd994c0e15fbff5ae3d08f3c332c48cacca66bbb38", - "sequence": 4294967294, - "n": 26, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250037356", - "hex": "47304402201a4b4efff2b70a4039b4dc120141da04ae84f63906df10c3cad08838c01b6b8702205a065d025c338547ea07b2095ad31252658e57f1a7a04c7f4eacc0248e611fa2412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "46c8b9fca6423412b3d40cf7606b79678807d75b2be1e848765c40f367b326a3", - "sequence": 4294967294, - "n": 27, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250061192", - "hex": "47304402206b0a876d78793710acaa8bbeb58a2d908bd4936f2a88825f944b190041b5e0be0220279560be5009e4a3fab44d08f4748e2dead710a8ccc77e06a03ba8112d728856412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "fadc6b6f3225ea8686c7a03cd8362765f91e604c260beaf965c4e7093fb16b74", - "sequence": 4294967294, - "n": 28, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250118669", - "hex": "4730440220799bdb7ac60cdf3314cc1f157299858d353e22c00354707337ab5b497619d626022000e41053afe44fa65227b7dd8498300a2dc89367d9daf0586caba5bffdfde567412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "adb5163c2bd4b1c35c1eac2671e6124e6c6b9b6c3e2abdc8372601528600a98d", - "sequence": 4294967294, - "n": 29, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250075561", - "hex": "483045022100a1af33a83edb7fdc289a48a4f77cf286a88b38c21ddf27dd4ec3df007ce11046022074dd56730730f958039efd70edfe7e181060fec306c6df4cf75209600ebebed7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "db1a00011dcc02708d6757b7435a3163d4dc384d8490208656229b0780b4a184", - "sequence": 4294967294, - "n": 30, - "addresses": [ - "bitcoincash:qzduecze3gvxk6y7rcjmvnau8c3ncddvvvs05z5gz6" - ], - "isAddress": true, - "value": "1400587", - "hex": "483045022100eff445419ec63d1e9f51a5324c3be0315911b39f30657639e84ea7d2f739e0510220218e73140a39542ec8055b6645cbb7989f96b9d9a93c67549c059509de06f0ba412103dd71b53aaa823b09a68aba30c7603c6a397e7c183f708c9dfb0d9d0a9cd1c722" - }, - { - "txid": "df69893e75d4acee084666c023822f07196dcae429a07b136fe92a87262f87f8", - "sequence": 4294967294, - "n": 31, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250118543", - "hex": "473044022050b7ed06a6832b8831c08ba86049b3793b5a71fd6d5177c9f268b79c3074bca7022047447c23429de30c361875642d9058bf1b5e0e6c5516d6e71b70b7cfb29827aa412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "8432efebc29ead31beb783d5d27cc379fa31cee352cc19a75746768b2fbfbe7e", - "sequence": 4294967294, - "n": 32, - "addresses": [ - "bitcoincash:qqfs2vp95prfunn2r9wh5lf2g6k7k6jjr5qld8a37e" - ], - "isAddress": true, - "value": "1772743", - "hex": "483045022100fb072bfd399dc11191ac449a9d60119bd191ce6b19a5d92412a805ddc8d4b46f022021e463686560b15ddf272b9943d8e41425ed500f77698aba518ccf546a97aeb4412103e35c58a738805f53af73472ffb671a9bd3556ddef47c62f18ced868bb5033d0d" - }, - { - "txid": "29ff4caeaa127c04ecc8141f49462390a13febd47877abda62a7ebb66658f0ba", - "sequence": 4294967294, - "n": 33, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250075582", - "hex": "483045022100b25e7d4ebaa0e7d8e24498b039e756d568b67316aa14d05abafaec59e216a73d0220010d0b6548a74435907eb0d548dfe8e52a949bbb785eb2be3bce14053953784f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "3b46f445ddc1b8acd4fa933fb8d7dba9bd95ce53a579339b32a1e97352323013", - "sequence": 4294967294, - "n": 34, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250043307", - "hex": "473044022007d2baa9a766c120e111a727bfa8e8bc2e01cc285d4d4f67d2323b213525a10c022020f32be2d9935b6d9b5091db27ebf00aaeb54adc7032badc7ad63f20741ff28a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "1bd4b1e18be85528e214e16c69f459272ec126ff0dfd1948de6838b5b50e5344", - "sequence": 4294967294, - "n": 35, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1251821842", - "hex": "483045022100f98ee28ffb66acd04474a120904ec1be2327d727d8ed8fe99d8b95c174b8f46a022041d21406dd8df10cecc1d6435de68fef3f9db71838c1ca2910895bb184b4a6e4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "067492a2b7fe0787a44ceba7d6ee64da25aa8be08357576e4cef97ef76babf2f", - "sequence": 4294967294, - "n": 36, - "addresses": [ - "bitcoincash:qr99zjexsl5dtdu38wu8w7jdmsmcxtcr9qw64zjhdk" - ], - "isAddress": true, - "value": "1843864", - "hex": "483045022100ee3f7961f0f23137d753affe85b777e94c1db3f656cf41b8f59fcf82d9226eb7022025009482a6c0002e409590075caf7a78023ebc1457f100c8b922a4974ebf86ba412103f1d1dd7685d3781f58f9aa399a16f6bb9ccc7d008cdb7c63a7945cfcaa6ba0e2" - }, - { - "txid": "bcc168ae5cc9dd70fabab262712036bacea7250db404c0d5af438b0b085c52bf", - "sequence": 4294967294, - "n": 37, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250034365", - "hex": "47304402201fed9da4c0526ac5ce257fce2b7fc995646b5f0d2961396327f93e2dfda3e4a0022035b217adc5a9be2ca34f4361ceafd9f2d09a6fa47d4a767f7001ade40c08fe26412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "025d365f0471a48171c3f50ba4e9ee04ee74f72c2e8d0cddca600f3a900b7b32", - "sequence": 4294967294, - "n": 38, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250085848", - "hex": "483045022100fa8ee82d42f524290319fb3ee47a1afa70cb952f8a37325680d6fd651ac3699f02205ac0cd86fece03ca204bd881d67ccce0cccbbc98704d9e955e2f92b5b77121dd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "c61c8a5fd411f160bac0e4b4e703e1caf7d3f8218b0ca5f2aa7b762bb9d3ad5f", - "sequence": 4294967294, - "n": 39, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250086233", - "hex": "483045022100f3cb343c4704bebbc78c6492dd72ca19c388b285f44f574dcff25f993add6d5f02200e050dacd78de955cf552f9158beaac5fa64995f5bf7c8a919a231a39425730c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "207dd74726483c593b21c180a9467166af7f5b02450fd3613268cea239aed047", - "sequence": 4294967294, - "n": 40, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250080933", - "hex": "47304402203f05a035f5d42fbfe97172b431a613110ad733e356ebfd08886fa11bedaf1faf022061c4a3bc3417390910612bae46f5acf8b6e8a5b008d273a52e483a315bfb950b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "facaafec82e7853c85dca5fcecad9c62d830a2421c98e8c5896b793966face46", - "sequence": 4294967294, - "n": 41, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250075132", - "hex": "483045022100bf60fbd4716339bbb42ce150966ad6caf90b14e57f45eb6804756cf8ff36b23a02202f16aaecdb9994f3b683cc7fab45bd0a3f54795c336b5fc224fc51270a7f3f4f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "26703badea466dcf8446e1ee49868ed4259ff22e0f13460db9d79819115b5c4e", - "sequence": 4294967294, - "n": 42, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250118800", - "hex": "483045022100bcdcae99c9289b5fc89d3227daaea8df7d0a0f3a8971d841ebe1ab7a1ecf72e202202ca21447a6b3e96540e32529697d523b7b08c65845d6a13f6b1475de94919bb6412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "c94103172a643e1ae22c3955749bf7af337a914a48d124fb5cbaae1ab5fa9e48", - "vout": 1, - "sequence": 4294967294, - "n": 43, - "addresses": [ - "bitcoincash:qzfvx98n9r4yzlvk2h736rn3qftpl2uttuu76kvt5x" - ], - "isAddress": true, - "value": "1631430", - "hex": "4830450221009535c27b5bbca0db2bcf1a0d0b3b283a2171df53f0d68f1a138888fcc6ddd996022068af19252ac4376cffdbfaacb2e0f0c216deb7e2478b586abe7c2679501eac34412103a47e5dea4ab8d785f4e00994d0faf1a8f384c41e74ed8e4b776fa6ce136ebc42" - }, - { - "txid": "180544709d0cc711566118b48af548a7b199c639185685c7228676725c28ee7e", - "sequence": 4294967294, - "n": 44, - "addresses": [ - "bitcoincash:qrrv55s5ag0dduyjsc83ds7hstqc0m9htqk764mtaq" - ], - "isAddress": true, - "value": "1078385", - "hex": "483045022100b456847e29f8a648730f0fd34cc7edcfb35daba866ab7d800472beaf2836ce4202207db401f0a5e30efc53c7bf58e57d1dec5874d64768ad9eb4895351cc4be9226f412102291b40a9a927dafeb53cdfc7e722ee5c9dfd6eac2d81331678b9ab405bb25d21" - }, - { - "txid": "67c24b19a0f444541bcbcb15e708f7713f5168f89f3d42df51d1909f6e22b093", - "sequence": 4294967294, - "n": 45, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250191671", - "hex": "47304402205ff244c77726def0e3697a3e546bdf74c7f31479c9d01a7a6f8cd1656482d537022045d78dba8ed4d3777f473736daedbdaca6f5698dd306898d144eb43f96259766412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "208d4a8a6afa218a65416286733a5158e7ca393003e30f88dec606e771e384c7", - "sequence": 4294967294, - "n": 46, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250036468", - "hex": "483045022100ec6b35ce6d24889726480d70a31bc0d62800bf7ac49ecf084b98137322606bca0220432d33e2d8b508f26d7d813d18629453c537a4d90f73a104bbf80627f9fe8d62412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "60a7eef8d0b9e7cbfe602bedebd75a80121587af1236fcb8ddf00e510cb4caa4", - "sequence": 4294967294, - "n": 47, - "addresses": [ - "bitcoincash:qq788skgg7eqc7unt733wahchmx08h87tgn20l2n3l" - ], - "isAddress": true, - "value": "1329593", - "hex": "4730440220423ea635717cff512d9262b7c8932c0122ca868251f019ae033101c28771a52302200cd3ae05f2e88d9f64207beb4b715ba480bde9ffdd40ab61a36feff88f2968d54121035530745f3cd4d31532991e460bd2a15e1944e690643f73133a9918edb95da53e" - }, - { - "txid": "7033ed9dcbb1af754c41046bf1ec51c16285336abc235b9485dd9c8829f32b85", - "sequence": 4294967294, - "n": 48, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250053803", - "hex": "473044022055cc4dfa48a79b8584a9352be34ab5fe9cae4132d264dd827d14ae06d35ad4090220652a83c93505f8a8527c5bc0479f37da0593595c1bf18c12b8fa0b41a2e37a64412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "929f05541924a6eb7dc7f2e11310037de210718c5896b9d9475ca5724dc13532", - "sequence": 4294967294, - "n": 49, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250171060", - "hex": "4830450221009acc8d0e06d10b0c764a27613bcef41fc75f910875eae3989a7f8725f81814cd02207146ff66f412910ed993fbda4ad6ed48862a02f366dd88a83856a17e7f96d83e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "a7e965c2d147a2bcc7d99f61bada49696703563d7b8225c9e69c29e312aab0a0", - "sequence": 4294967294, - "n": 50, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250030500", - "hex": "47304402202d8cd72290f04063c0ae9bc06d2cae3ac74ef4cb6945c92c3e3ccca210c127ef022030471726cd87ac9d55f3d246095f64ae22b611aa8791922236bbdb19ec273322412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "e6897dfc8254d449f61372cb7c4131c4caaf2781fa60cf930a36421d0bc156c8", - "vout": 1, - "sequence": 4294967294, - "n": 51, - "addresses": [ - "bitcoincash:qq64kqwmv0gu5naq8ztaj5ecef3042n3pceymy9fw2" - ], - "isAddress": true, - "value": "1746309", - "hex": "483045022100ffaa954e5b86d54ece9bcb9e37895047221828ca381b03266de3d9341599c8f902200ea1c5ed36e893df822c698a474b062d4f93005c32f9d2f0d78ecaf5a56e4fbd4121031a00f43cd99e015c72acace20ac47d887a39ef284f89a5aa09abd968d06f5e9d" - }, - { - "txid": "d69c6ead378471a3f30a9a7b10381a88bd8c5e343b8108a0f189f9f665901269", - "vout": 1, - "sequence": 4294967294, - "n": 52, - "addresses": [ - "bitcoincash:qzudxte3pz9qf5gmnpr5yxj97kv3flcs2gv5mct8gm" - ], - "isAddress": true, - "value": "1792586", - "hex": "4730440220457d59caf24eb6e10664d06f3e936f6ee31d9d59f1cc4f6f62788f022bce8c1b02202ce7c37ae6832b078c1cb9a055e3ffcf4674081f0738fd9c3eb4465b52bcc9ca412102fea9ae922223f2c68c68d7672b7656885c3e1321d35cc8f5f445179df6f7d27a" - }, - { - "txid": "212aa8288a75640e62292417bf53dad20d242df7579c38fa10f2f63d8c03d38a", - "sequence": 4294967294, - "n": 53, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250046573", - "hex": "47304402205e0f5cb06f7fd741825c669c87e9db1a433913fb8577adb92b779d3a693b4f080220120648a5f9d2abae83a29cd2c79f5c61b9bc40da8990736ab97ccf6f82c586cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "3d6a1aebc3f48b843e408421c9f421d3934670d86a3f5df49a6530152056da4f", - "sequence": 4294967294, - "n": 54, - "addresses": [ - "bitcoincash:qrt6ljgpzzmamr2ukg9a3jxe46ufaa8fr5yp6f9pfy" - ], - "isAddress": true, - "value": "1801618", - "hex": "483045022100debfb215f94e9d784e91fe0b9d2541d09a4c7591172fad1441506db4a3590fd102200cce728e344933111c9548162e62872fccac624f6f98d92ccdcf98dbed09ac544121039b8a20c23f32f5b14e76fb29e0baade695810aa7b6dac9e9638a8d13b6ad8221" - }, - { - "txid": "91585d5312b1a4c8bca993b6db304a65c7bda601113960cccc978f28c381bfe7", - "sequence": 4294967294, - "n": 55, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250046545", - "hex": "4830450221008110aec39b127143891069590fa0d9e1d8b41bdda70d9807848eba92cb48736b02201bcfdc1a1cedfa4c53efd941482f6157774b2aa80af44e500263be6a3cbcbacb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "b9b3d23c90954095289ff5feff55de3cbd7469cbb179e38aa74dc813fd6b684c", - "sequence": 4294967294, - "n": 56, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250022645", - "hex": "4830450221009f76d6838b8fd8bb74f50c67920fda9f28054d093b30fd03b54b3fb888db046f0220307944f3abec07c3570614f418056aeff03c0830173c963bb0b65bd5ef24b4a9412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "65f9a63b7bf753423cca4a5ec229f566e61cd1ec8f745683da2a934b1308713f", - "vout": 1, - "sequence": 4294967294, - "n": 57, - "addresses": [ - "bitcoincash:qz86ljat9dnhjp2wplpm7ncfm7q69hk58svu9g46ex" - ], - "isAddress": true, - "value": "1593178", - "hex": "47304402207b93e2500b189b51fbc3a49a191c4b92ac76e32ce86f6f1b9af4afbb3a91fbe002200b5617cf52095bf882a5129f5477f119c9c565dd582a9f19493cf1bdae6527ac41210323ab0930ba40688e66bef6e08f673bd6bcd3df687e4c503387f48c24bffdc93d" - }, - { - "txid": "48ddbf6a4cc52b15bb4d2cb7e39fcecae29483bcd3d6471e3543785621f3df7e", - "sequence": 4294967294, - "n": 58, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250019587", - "hex": "4730440220731ab37e71d9c6f63333ba205a318d36e5847706381f571b4b562e5e6f6e403c02200704ca9d9a33843d9a16135f56eced1fd18e227385671a8df5fa41e505e3ba3c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "5027ac365cb55b21278f32710703d9ad932912919c58de364e1eb1e9d79412f7", - "sequence": 4294967294, - "n": 59, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250045268", - "hex": "483045022100d1d3565175e1f529124ebba1bcdf8c1704e753c2f91ddcd1a093b5f5403cd0ed02207420ee9d6082356cba6d8075b4fbf310bd84dc770734a8ab30e74741a779bae8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "93cc92162ee854259d3b3f9ad1886847eadb2ccc86d03bcc6b89718da9ca23f4", - "sequence": 4294967294, - "n": 60, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250086952", - "hex": "47304402203ddf5c6c5065f03229cdf837d9f8d3d22314834b006e0aba8dacabea206b3b150220417c49c9095372d3dfd954688bcd43fdfd2a121989fde18456a9428b2a8e3c63412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "c672af6e97eeecc79e87e708d57e20e2c7d811bf3431eaa928f7efc24b663dce", - "sequence": 4294967294, - "n": 61, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250143426", - "hex": "483045022100a20e6aaca7df2b142b768d3b1cbf8f783f3d4997d155a32f0e066b4255777c9f02206deb15cf53d6b27a973df9aa7080691e5914538d9e97ec7c6e797ce03333238b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "5f64a0a07336a2bad8f9611709653146fad9fc796f1e92dbd12afbf0d6dcf5b8", - "sequence": 4294967294, - "n": 62, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250125454", - "hex": "483045022100cc2cf5c6c2d4862dfdf65407138684ba45565bd8ec46594ed4586bfa37b715dd022013255b2eb22f5bb93d2afdd07ec4c3b5efe0aa16134b2fd084c6bc720f8cfd5c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "256b18d5861752fb617796cef5ceba05e42de141e48aa2737c77020e8d1f337c", - "sequence": 4294967294, - "n": 63, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250058048", - "hex": "47304402202c9dd98c9a72e5a8df4b01f09d18e2826d8b9871db89c5d3b24ffd673facaa0702207523bfcf3ab80790167a2b1159fe268770371fcc7d770995c19eace3181ec8af412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "aeda3cb9ccecf67cabaae458862b2068129297b1b502b862067f578a2201d54c", - "sequence": 4294967294, - "n": 64, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250083898", - "hex": "483045022100bfac8828df10b7911d341c15a532819c429c7185d8883de19de84e71b97d78730220177603a3572908c90dad865770906b5ad228da7ee5da39503ececf60ac735158412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "0b11e279a95eaf9241bd55fd7f7b045e2ff047b307b25f3885feb6a71140d6db", - "sequence": 4294967294, - "n": 65, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250050928", - "hex": "483045022100d598e2ccdeecfdfea9d5139a49a94fa39414f9e1ecb13d54efeb34c168e58aec02202a59463710905613844f48dc71d316c0cae54ab9e16dd95beb8902e5940024ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "82026eabe17877d3aae729eee2612778389a9246d56b8032706c454223760eb9", - "sequence": 4294967294, - "n": 66, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250039790", - "hex": "4830450221008302d38e9eaccaea812c853047931562417a3665b8b9373cf7f63e58180b002602207ac8fddbbd19560a74333ec92fa077d169b4902a41e0431113f8fdb75b304ecf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "43a94c82abb414437ac13038fa5840a6038733dc156bf160cf30db31a82355e1", - "sequence": 4294967294, - "n": 67, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250105160", - "hex": "483045022100c0d85a1f9146e8ef9efaef8ed9b3ed09c55e51b25e189735610da89b6d212360022003a49114e504741befcdb95d52a3dedd1aadef68b7c48f0a4a8c7dddfb4201b5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "41f835819365a32c2ce1138c131a4039c6dfeb034d922af573d997697b409378", - "sequence": 4294967294, - "n": 68, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250127067", - "hex": "48304502210091ec8402cafd1e7eb11b56ac56a994ac79c435893108d0b7c8cfff87c07ba0a602204fd98efddc1b4e21bd3cb81217579a7b9621f9c3c204f2f5800e75ce1c60b19c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "2f8ca9dea380bd026636e2281f1e42e63dd54a04be1c1526574994450ca36f01", - "sequence": 4294967294, - "n": 69, - "addresses": [ - "bitcoincash:qzzkjplzf0yw2xej4u9he5pr5evgup2snqqxs823e8" - ], - "isAddress": true, - "value": "1366913", - "hex": "483045022100a850bf088a08baac1f1f577da8946befe2e6b0354d6a29f636afd39982569a7e022062652d6b75dee145f741d28d6f1870fde9a7d66b994f0d3162abdc42fbf54458412103ffdeec10b52942b0c46d6578998efdc1d64073de579e92e7c5dfa97fdf3ac391" - }, - { - "txid": "404829243c500005d37a95164bf6610005ccfa19cb7660ac9c1ee0da009465d8", - "vout": 1, - "sequence": 4294967294, - "n": 70, - "addresses": [ - "bitcoincash:qq4kx2926zmnhfa36xzfswf9p9raqlapmysqvr4ck6" - ], - "isAddress": true, - "value": "1292340", - "hex": "4730440220762f7c017672dfc71d487f3730e26d69d0e53902f579ba348095ca164d27b094022076c7e8045ec9fc57af6dd95f35c0ffad2c0ca8f83f112f60fb9851ba4ba15d92412103a2d2d8251728b11fd4afe7b8c73a8442f76dff9bfa424f5cad9b98083936259d" - }, - { - "txid": "2624cad28a9b7f55434b68fc8be7aadb87d40003d786f0e414cc1eff74a12b64", - "sequence": 4294967294, - "n": 71, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250134907", - "hex": "47304402200654032c5760f8b94cc089da51773447f19c1cd2108cab89bb53ccfdb6dbee56022015e277622dea4bd1a7913ff934b2bb2d1b3d75f05285b51690160e1197a258c5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "893b3cfda77c1371e21df17e45910578fd778958f9b51fcebb24a2e92c604d65", - "sequence": 4294967294, - "n": 72, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250033040", - "hex": "4730440220712877c0dc553096eb0ebf101d1555fda5235db26ad074d2f330163fab63fc7802202c89752dd7645e8a3da7e8af5fb68dc8b177700766b79cf6a35695a0c7c873cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "cd86f3aba8b0553de0041a2173507a34f595a3785dbaeb8c9b2cc1c1c34c61cc", - "sequence": 4294967294, - "n": 73, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250105407", - "hex": "483045022100f3fa1e305666e2a62afaa11fd37025b25c0bdff8709fe1580406615934228cee02204841a7d96f36d3c183f06e22a58175756c3e9a76c93c7cb4e9945f31ddedc902412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "ae8ae862b5ddba89e69b42aa8a6ea2693e61f90ad3a5625b5f81605c7aedb226", - "sequence": 4294967294, - "n": 74, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1254457185", - "hex": "473044022047c158e3fe3f40de3f39796dcecb7df3cf344f14009de9826b62a43837f2cdcb0220759d823cc145fd5e8b651a7bcc399544692bbf596189b1fc50bba5f4ca02cdd1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "b402b3d23c910e0ed869045671269210f6594f308b6b01a0bed2052f6012b0eb", - "sequence": 4294967294, - "n": 75, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250101109", - "hex": "483045022100bd70744c867943bc3bf578e192c8a87a5ed5126aac4acd98efa06ea2483911fa02207377e11ae2d2bbaab00da86ec73c26e596bfcc680c0b8eddc5d44bda650bc299412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "e1deda4073c863ba018bd7334f625f79884854006f27712cd010e57bf59c8087", - "sequence": 4294967294, - "n": 76, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250083658", - "hex": "473044022059ee25066b8a2a4fdfc35f14c5cbb7f22ab181fcfa9702d4f3de7aa4d738c7a402206dff315ad1cd2222cd6ac074bf34241fc22db38a57bf089f7e24542323f1766c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "219c39d91c3d5d3d1f81c83ba373df7ccaecb45f5e4a2f7422bb2021afb7338c", - "sequence": 4294967294, - "n": 77, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250032757", - "hex": "473044022039657cdf4fcd5a9e81766ba11db495b8be5664612d3b91f8504bea342c4ecbe702206ca4913e5807cd697d30dbc93e0a9d679eb01ee84b687ab0c642e2f3ebde745b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "3a1f594a74bad6de4c762a78a6c06db3900c45408ec0f785c61bf9f29bc34281", - "sequence": 4294967294, - "n": 78, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1253061599", - "hex": "47304402200232ee94873317eae275cf715f4c3aca25dd0c8db4800946a45cc1d9c45732fa02203d9ce9c9aedc0a3899dd027df32e683438769d66f33ffe52006454614b77821d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "14cf83e6c8b80366b8651c6b4a0f7d2270290066325d686ba671ab5c4c9a3b50", - "sequence": 4294967294, - "n": 79, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250121784", - "hex": "483045022100900bdc6f705efa56449a65f15a67fc7fbbc102f78e7974ea6ac2849c75d2dfec02203b78de71dad2e3f6ffad2779cb9007217c957c8f5db7abd58fd0537fbabb8c6b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "1dd1ec6c4b4ec9bf13aec933506376c77e63254d5573c2584d7515554f14ed8b", - "sequence": 4294967294, - "n": 80, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250044721", - "hex": "483045022100becbb21c7937b9b27ea3cdac5f2048ab9ac314de59c3ee2926a5cfb258ce14e902201c8022bf275c1a761e7715b14e15d74526901363ae5f8bf5489d00908dd758eb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "9957066f6fe221a9423b0f54ce1188000e1e9f7bf9085527d9e1edb31d88b7bc", - "sequence": 4294967294, - "n": 81, - "addresses": [ - "bitcoincash:qp7zwhgnhhuh4j8644mqg7y3fqejm2jkfvkt6qp4pp" - ], - "isAddress": true, - "value": "1876300", - "hex": "483045022100ad84bcd69a85a0d487fd7cbe4d76b95bffa303e76615a4336419fd182eeae4b902206d21e4f592297e87f1af9e19c80fd978914aaf5a2db2cf499b72cabbbe73c831412102958762ff6c8985dc9656afda59e61afc6c0131a5d8f1d86c87c83c9b37f7bd18" - }, - { - "txid": "ca467662c89f207dbfc6ec016e126693a204f17d6151987aa748838852aeffb7", - "sequence": 4294967294, - "n": 82, - "addresses": [ - "bitcoincash:qq7fvpnuflq4cq6wc5t4qjuzj8l59puq75h022fyxs" - ], - "isAddress": true, - "value": "1114817", - "hex": "483045022100edfd64cf9335d094d5873deb38cda5f4ceda3351df722f1c718993a2dd12c8e302203126b0f9470a4d0867ed4e773518b8ad689ce43a2c9f65a1f297525fc22201dc412103f37089783028c0776f2b8a9d8481ec8d6d0652a31edc03cc274032ae17c63c62" - }, - { - "txid": "54fde006c8dbb7a3de68e0609d057a3f2337c99ee2ae70cc715d72f5dc881a80", - "sequence": 4294967294, - "n": 83, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250175152", - "hex": "4730440220448751a749e7cccacab0ae1ad4da948b0e0b5d8e3f41ac2b22c18928e8e67d41022051c107c345c06ea82fe8329a8cf3a96b516fd8750611d8ef438b8545416398ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "a08d7c70130d925e33b93e21cf77b5790a2ab5b5dfc4ec2198b9d81a74af06bb", - "sequence": 4294967294, - "n": 84, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250056417", - "hex": "47304402207f9b2802ed1e893168277204b7919ff479efe5c71ad2a255e1738a52bacd758f0220253780485f2e3ee960e058d449c647b147b8f64b49b913e7e9615a6c7114f18e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "e2c0a8e67a48286fb8801c0faa3951a268c5f6cc450c445c380e80e09c752778", - "sequence": 4294967294, - "n": 85, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250043784", - "hex": "4730440220778fd8ba1dd9f71df55bbe1c3c4185b8da21dda82198546c2a0c30250f4c1d66022040f17a46187d535c6e943c047942f45159a37b2e171db18c657cd24168c22e2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "221971a381aaba4e963d21b54e625b764016e848a5390a0df32a29aadf35f92a", - "sequence": 4294967294, - "n": 86, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250090058", - "hex": "47304402202cd2fd29fa395a5a80893de065c8bbe71e0bfe0e7b2224cfd5684736a086aabc02206720226ba63a3e5d9e2dc67e404625cdf31a7a08da0e8a22717e558f7abc817c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "bf6623abb315d54e6b7d9428133d913121ac875dc4c8e3f698477dff8cb7e3e3", - "sequence": 4294967294, - "n": 87, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250229940", - "hex": "483045022100f8769b797386f0bdd662483096f4e0a33c13f6074a4aaba3fd590b9abbca7c2402201eb064869fcd17a59ac028145b08c73b3552544cd7fc62245d1fd1d369ecf765412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "e66b832bf71437eeb367e6cd7818658f960a4845bdf3f5081aa474935c9b31dc", - "sequence": 4294967294, - "n": 88, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250154777", - "hex": "4730440220558e65fd916d9c9616a3e0bd41111dba3914867b1ce5d487df4f77feadc0059502203198566c0d58af8551b65f884db98bde161bac140c7a900cd40df97a40c267de412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "452873e0c38438227a2fcf64230973ea8f5868fabf05603b629881a2b46a4069", - "sequence": 4294967294, - "n": 89, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250103829", - "hex": "483045022100ca93287feb58daad47c5388067b219e44f8533a214eb8eea9b5313040579773002201716a6ad2de70eff6721ae7950edaf9230420648bb8ec53173c215cbd12246c0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "60b3b027b67f550a0544a539f173066031914f0a49897379b51ffa127117e521", - "sequence": 4294967294, - "n": 90, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250125814", - "hex": "473044022003240fd71510800910b448c62a03178b4ef62299b17d6d2c06ac8f3293684ff50220637e3ba59fc884a8bd16aa2e884b379d85f38ae4ba049a0365f33644febee6df412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "6cf9e489432bda9fa9eb865587eb28ff525b5171c38f746c55b85a577ae68854", - "sequence": 4294967294, - "n": 91, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250144563", - "hex": "47304402202e2ac9c8b619b8e2626895c20f6bdd1a24fa27de017d05d5fa2ce120b3421f25022053ef6f82ccf9a132d40ce566d45f4ec18bf30048d415f6ec1c783cda027b6747412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "9c9923f0c3366eea9c229233d8828825beb12a2c28ae3bfaf46203dd1fe8ab03", - "sequence": 4294967294, - "n": 92, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250218730", - "hex": "4730440220352bdfe541e9e1ce428ac4eb4c8ba9391a118b7dbe57b4fe3c4ecd30f228fbff02204a0b78ada1d74a7e7b9ae912e6f445d9ce9050855d9c5ecc7d477d2590a68b18412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "5ed23fa46f4db7043e14b845ef13a37712170f7cb25f88ff9acbbd6bc97a9d87", - "sequence": 4294967294, - "n": 93, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250079095", - "hex": "46304302203f767d8f64e3c9e5773d94a325f8029d21d1c9a0f470c9288cd99f70d2d90ec2021f50b395f9329ffe64ff8084c1506e904ffc02dfac7f7e15461c3e8a077f604c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "fb09c795e5cf32d174df4efe8b2208de9819ed024511d9fd684556ec8adc00ff", - "sequence": 4294967294, - "n": 94, - "addresses": [ - "bitcoincash:qr3vdgfvrp77mlhac73ujqgtn78cg6yeeurwnjqylu" - ], - "isAddress": true, - "value": "1792434", - "hex": "483045022100f17f8045a627bf96fe09d868109063d8040e3e2df8944e05f9b20a15273d0bdb022059c31e2d849abd57e784f1a3903f49f18c7c5a624545bab98649e8a092e12a10412103ee2a3f78cd4930dac8c030ccc93381ec5eab259c1607360d85d1728fc296dacf" - }, - { - "txid": "36bf90cf0b6074a361292ec88ef58d76780d301a1e5709bf013808c068af253f", - "vout": 1, - "sequence": 4294967294, - "n": 95, - "addresses": [ - "bitcoincash:qzjvk52q08wp84x9uelf7k3572fx4z5q4q7vkpaalx" - ], - "isAddress": true, - "value": "1713598", - "hex": "483045022100b58c7dd3fa1f8dc50edc7b5546b8ccef8ffc5c179fee774999c63fa729ae3cef02205eb611cc887e5a62a4e9da33318ce6e216ca353225f452ebca51be1dd10f544941210267f3c9b9bfb6bc5c1f68dd1d18623a9986408202cf232ad1e4089933c83f186b" - }, - { - "txid": "259bc4abb9f14457e323223bcbbf772afc0a0252556e69c9e13e8c7860e7946a", - "sequence": 4294967294, - "n": 96, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250075778", - "hex": "4730440220097f46c588f37ced4846a45905df1a0ae22709760f8a1bc930a58f5054cbe482022053b418af66d1edcb3887616feb23e5dd4095f29e74ac89853c3b909eb42bac34412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "14a32331f78309de6ddad707840b364aace14cbef8694ab16a55305fd44260b2", - "sequence": 4294967294, - "n": 97, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250085059", - "hex": "483045022100cf98e22a2854c7088a0572e1edb4e876aa622ed10dc0376806e1432f5dc1eef90220527845f8dd2522fbdf423b4fc34a4792a7f82e04b314e0d83e2425daa2f92115412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "acd836ea3252a7610e6c1d426f2cc739f73fe1a0768048d7431a69d4bff3f0e5", - "sequence": 4294967294, - "n": 98, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250132855", - "hex": "473044022070c7aaa7d7f050b1b520878e55db3ca491fb33211150e2f620b685cb49d7d885022022d9ede63e3b196a1c33c2d211c1eacf2e2411820ecf5155b5e4244f5dfd9f1d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "348cdfc73c3172311b972b8c529545591f725b86ad065f88d7a78c2fcc05f9fe", - "sequence": 4294967294, - "n": 99, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250023474", - "hex": "473044022018cd70c3e62563ea92ea12735e2efb4b905df85e6b290d573051f49c63d07c60022037a537ca3514121d5c2b8753833808a5e0432f1a8f277d91495953c8211ad326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "af7baa39bec2ba327ff720a7c782f833d18c0677c644080f59996e2270756c55", - "sequence": 4294967294, - "n": 100, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250249377", - "hex": "483045022100a01ad9ec8d24fdf01eb203c2887c1413ae56990d4600a18010959f6df43de08d022056f0f0dccb8f772f29a7835d7dc40f242348805005b5f80ae8f2fbdb600ab2ca412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "6ba95cc08cb6849c9599eea8ec3abeb7ba7c7b42399cfc6d807dbc5aa8c1be52", - "sequence": 4294967294, - "n": 101, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250192878", - "hex": "483045022100cdd770159d56ac518ecb0dc916df0da06eed536e540582680f742389f53fa4be022012d372e2c04176bcb82b91b02ea23c9c1464baef7d1dda66066bf84c402c0012412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "41ebe9615cb3037d95ed10c37be1fc80d216619086c5cfc256e489ce42042d3b", - "sequence": 4294967294, - "n": 102, - "addresses": [ - "bitcoincash:qp4h56rtxkel7traz24d3ep3jq0yxqm82stgclvks8" - ], - "isAddress": true, - "value": "1288555", - "hex": "473044022001dc7db378891c1c5bf07a09d14fcc6675965976e2e3e762786b1b1e0f4a4bb702206db6f284dec835823fb516fad89543edd3bd7af3ed33940fa296939fadb41ba841210393ae47ec2e844378cda3630abe12082401f2e0f98d016dde2b152b42e335630d" - }, - { - "txid": "a135747cbd99ace7bf495ba29e49b5595f32259ee7df61d9549cf3d4274880c3", - "sequence": 4294967294, - "n": 103, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250118091", - "hex": "4730440220290a5055313d68f9461ce830f8a7395022d2d55abf28f6b4bd665693b4a13730022035d4cc2a6676ed842027dd4f21d31dd5a956f4b1f5cf771b866cc0d4a6400df0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "90095e01bb497ffceeb85366ee1b9603b96c33ee0acb47a64fe3af23911410d6", - "sequence": 4294967294, - "n": 104, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250028058", - "hex": "47304402201fd6be6d72ae75b61a624c13476b538ec2f9e5146f3074c879af57ecfbe1679702200ab10ae612e7fe0f76fe943c1f6a02262008407f86782c1536e92e3bad77d3db412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "44b169e5c5414cd335ef67906c0f4425e8b190ab366dd1e16641a34d85ab5f20", - "sequence": 4294967294, - "n": 105, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250132073", - "hex": "483045022100a4132f408b5299dfed6153b7a331f9fe866f1b042e4263bf7574ea0964c450a202203d99cf8dc9a9194269bce400185a4f86f5d35b5be83f6dbc3166b600392f1b00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "f7f16d4c8f00cb446063f53a75d2dbb2c54d9d474abc836b92d48ed76a5ead8e", - "sequence": 4294967294, - "n": 106, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250210684", - "hex": "483045022100bbcc2e2d77458abc30898cddc7eda060b23a62f0a53b81c3db47f284cd7b29cf0220705328a29bd30792a7f5a704fd74b771c3c8a099265f5e7c9d70046da5b03ff4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "0252408a18fc77479f6e664fab80cbc6d90c1c5e369c34661effa52b9f1f36f2", - "vout": 1, - "sequence": 4294967294, - "n": 107, - "addresses": [ - "bitcoincash:qqe36s4qsvdfjzwrv8whsc0z94unav03agzr35m4d7" - ], - "isAddress": true, - "value": "1591983", - "hex": "483045022100d2f40145c4b9a17b3582aabdf7d9ac2d47546b3eea5350c4e2ec1e9c2466343d02203354ce620aa056a749de847f867c49dd121579c9fc50bd6258bff7cfb173c5f24121035bf755e8b075665a85155618f6e9022196a09c486415587dd3af0d25b76e9c27" - }, - { - "txid": "74002fe81a5931658cbde74c28933bb36cdaed62201be1c0e26a53c92d6bf5c8", - "sequence": 4294967294, - "n": 108, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250148696", - "hex": "483045022100cf8c593dec0724644d034f17ccde99feaf0416334219f158f884badf500fc93e022035af1b68574e88ef15e1c05c1b36638401613a31aa7096d97efba6df62695706412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "496b4d67e0a734740962920c116d56121c16ca60787812fea76d69b9161f8395", - "sequence": 4294967294, - "n": 109, - "addresses": [ - "bitcoincash:qq99u7jj9ujglljvh8nzaqtq0kfl8matf5eldrwhmm" - ], - "isAddress": true, - "value": "1859920", - "hex": "483045022100a669e8918ba68754b84d584f38afdd34be387773449784a6c61ef3f33d0fd99e02204d007ef31f5a3a7c412ac3d2660633fcef137964ef2ff6269c41e933896d918b41210383b6491fd80e1411675d7c8eda9b756c30a814b45fa565b7ac24d7be9dedcaaa" - }, - { - "txid": "4a6f608d6ce8efcc0cbd3b55bfa0feef86f5493331564dee943fa554fc84111e", - "sequence": 4294967294, - "n": 110, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250058421", - "hex": "483045022100fc35ed21833c3ea3ff5f832ef02236a08ded0999ea367aa6eaaff364ecac3e5002206e291d7c4fca0485dd8ea22519544ac632909d706741710a6e5f0d472c0b0656412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "a9cfa2539cb07c0903e2a01a343c6ea8566bc063b4c301ce2efee45760e36448", - "sequence": 4294967294, - "n": 111, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1251645868", - "hex": "4730440220485937c55c67c8eb46b94523cb06f9572ffb55094536d8b1a458c76b67dec75b02204e5007f610e491d043a412696d4fd769bb2f5d8c3e8b3a59e6ec3bb598f775a7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "62466cac8a8cb05584af3ce85d0eb8d4a5edf644a374aa23989bfa2adad2d8ee", - "sequence": 4294967294, - "n": 112, - "addresses": [ - "bitcoincash:qzl7yg7fxw5ls4jum50st5z7valsu7qa7v63ks2730" - ], - "isAddress": true, - "value": "1579507", - "hex": "483045022100b430528ddfca4431cf5cec08964f7325c036fdee55edc0ea0181d34ed72469bc022074b75bfa66dd4a87fab93da0f2f0def65b785fb0b51fe07355799cbd8b30c39a41210316d35753d58318c06d0faadcb723563316847ae06019984f42f2c75deaf3727d" - }, - { - "txid": "559927367907ed4d3822c2b4c0dca89ba2a4df844daa1033123e9939c9e81743", - "sequence": 4294967294, - "n": 113, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250110065", - "hex": "483045022100c6ccc3891fa3924c7b1e69b855628230c48d85d1e1331f037823ab7c5928610c0220050c9c0e078f34ced537e88f95289863a663b28488880f6ada3f1dbbcb1743a1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - }, - { - "txid": "7b5bfd94b29844e13c3fce76d9579dc7d20b3fa0ef15309714530152e4d5ae85", - "sequence": 4294967294, - "n": 114, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1251309649", - "hex": "4730440220168f31f413d65ce64bccb62390490dae2e4a00f98c2c44bd4fd689cd942da8b1022006f1b2aa4fae9587c688e8b7ca5c07db3b3c3afd6961f9f843099ed30b583369412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - } - ], - "vout": [ - { - "value": "32902", - "n": 0, - "spent": true, - "hex": "76a9149a262d0621819c8c17d34a7feca1b39b39157af988ac", - "addresses": [ - "bitcoincash:qzdzvtgxyxqeerqh6d98lm9pkwdnj9t6lydxqg82t6" - ], - "isAddress": true - }, - { - "value": "115067302350", - "n": 1, - "spent": true, - "hex": "76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac", - "addresses": [ - "bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7" - ], - "isAddress": true - } - ], - "blockHash": "0000000000000000023414a6f8ec13dd4f85b3fb1c71b937d5dcaa14e350cd4d", - "blockHeight": 611623, - "confirmations": 20560, - "blockTime": 1575319726, - "value": "115067335252", - "valueIn": "115067352350", - "fees": "17098", - "hex": "0200000073126b74e8eb1830ec84d26e50d09360e120e92956c823afdb2e981432e60e152f000000006a47304402206f992d73dfa7e518b00190f220ad5dc7b7947b1d75a2fcd8251b59f3d29d89af022036c6c44f52f9aeed406dec72a9aab1f82c3b997c36742f4a3504e4f93e6f8557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3848b83fe17d5304f63a9457a5749ea2ca1ea42d9934cac890666e2173a80b55000000006b483045022100db30ebe47536e42115a507f88bb8d5c97b81ad05ce334872235811134c5948bb0220418d77aed78cc4a332b1858c1d2e9ab169828b9c12e8c0d0f8d155964e5d0b8e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4321b2ccc28666c12200bb15a050a513976487cae0a01205cd30ca10988d8ded000000006b483045022100d30c9fd598613586d8d0460fb6c9ffc1d0c6dff6f647535d2a9f69cf373193d102207fff687aa035910db124adad8b59607a72b3d24aca9096217ec6b90fa132a2ae412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff32a0d8da2143d7c4097af72285aff1305155ff5e05276badc91839d5ac9bd7a2000000006a47304402207b30e99cb1f6754d227a4511c5b7791f3b896724b170716d6ed238017f191bb102202c1fadc4c572c86288b002a0d6b6d2460a14a6d3c8b49efc17a03e59d2db18e3412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff62f77994b08467f9a90c1b7b921306d7e48c18015aa53aab74775b73dc79069a010000006b48304502210092b7f176f182936323df8e4359b2a329b0c1e4b48a529d6e32867038a2a453cc02203c24a8bb46b7fea4ef5c78ff116a51fd0a04dee25bfcdffe856fb8988a7a97f64121035b4e75dda9fb0d55d856f54f24fc65da6657939b9559ab2c623c8ef325f14d8dfeffffff5cbff5ba887ac02cfcf6f1adb0c84ae21cc003667734dbc41ddc31330c7c555d000000006a47304402202a2bcfdaf12c398ed5372e6b168a786edb8972df1146b705d3cccf2d9601517d022020b90ac89d9141d68817850d1cdffaf6c51f45249a44fd6861b361a6025d8ac4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffca0bea62231cdd9cb231ced73fc1c0f51c478277a077a55aeec113b506e7db61000000006b48304502210087ef2709b9fe8e7f136219254229edd45e94c3f6ebd2bb149aadd9b1d44d89e202206ffde3c9491c012832967e4d34e02ece2c08bc4c07967b3b466d4800f9ca0746412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff843b9b8e0072454494ac701e9f0816590de35f53cfe960aa03bb4281128db254000000006b483045022100c7dbd1117c57eedc8fc006e818371bfe6399c4d25e8b40482c1f0858a3d98a4b0220426d1196513a87fc7afb5b107b770a90af789536799a11686eab96b04afa6326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2301458143bdd235636b4a15f1ce7fef218ef401e26f5871d26bb28e632e0c75000000006a47304402203604fbb20824443899030d2c1f5cd0dc2b88174929861a708bdca878868e910c02200a607b1da53483bc95d3a5c54e5ad66e459827d4ecf8b4ef9909e9d58b2d329b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff9ecbc5e26870067db7ee944b7fbe3fa99c3247e0614fa5bf24a9eb587c36d9b000000006a4730440220399c36174173cca01f6d6a234a935d6f776b549e1ea2fc2635193924c4ac2eb002205aea7741fafd95f862588c480aaa282d7a344d32d6318aec1a908cbb939e5d0e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff9ef492949a0ba873b09258961f35cd18d78849cd290fb93aace31af829da278f010000006b483045022100da9075310e7af59456423be99362f2cc686d50571e0f0b016bcfae1f0bc4692802203379b648d47704dba48542b8b6d5e515bf3c4fd7ff8a7be82cd0c8c0c7be56f7412103a344a84dc1a919a64874605fae200861b7af3ecd02dc5d52dd00eb6f8845525afeffffff5c5f3037b499d79505425804b021b76dd94e1632b6747afd059d0a728ff49b10000000006a47304402206cbf93634d6a477a571fa2884c19918b19ddfb008ff9fe405954720047efdb88022003e755313436d406dddfe3cfb68719e8f39e43de7c586489cc543dac0347da9f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0b183fcb0f29cff3e9f22ff47a5c87694199ec43b77930f7b17d646f3670e5d3000000006b483045022100f23d4cf11fd0a5ab83dc053ca64066cbdd2fb4107e0977a3a880c68a67636f7d0220220a47c66d3944cfc309c059fe8013c4de742e4d8590003fd56c5e0b3c7da557412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff80540561a82abdba58b2ac3bb9bf9f1064106b8f2fdcb63d462721409af9056f000000006b4830450221009f522beef55cbf8c7f10e88739846f78ef1c9d9cbc6959dba6f687a08fec0ef502203a160231733b87c6cfd8afd148994c9b6c5d5db9bb9847aa9e60938a6e79d5b1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4a4a1e4ea13377a0819a88e2664facffabd92566b83fdca3456267b017b7933d000000006a47304402201f5d29be80192a752fe28ff141ed702640df88083faf3f9573e52405cb4bd79a02202d751649aa600c4fdb8b1d1b21f0d134c2f4e5af9ecbe7d87180d667140f0a11412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff9b41a363950ab3e6b769a4cd97555d1d8336505f3c87599ebf7766642ec97ac7000000006a47304402203f4bea3816d252cb19d4247f587a146901c74d04e783efddfd5089942f2abcdb022069012613c4ee4b3b0212ae71dbd2071e01665148697011eb03eba25431e679cf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffab050b7b334656d60e2c9772a3820015a2f6a7cc3e2943897b0c027edba3cb90000000006a4730440220782ba77287116d5d735f67a3738fbecc1a802d2141a1fa544f61a5e8ba682a4402205473d68019cc8895ecb1d87bfced62ddb6dc48b81152f2684ae8530122d5b41f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff26dd82e448134b4105f561b681206a059e1de4e5690453dd8e4d9a0482c35ee2010000006a473044022044ed9bfa8674d7e83112fa22280797169d45bd971b185da2413e36252637529d0220531eefc480e0911d6ccda42002942883149bc1cdd1f3bbde313751d80bcf98b641210328ac4ed2b30ddc04c778a78b24e7256b08c55758c1465defd997ff4bcefacf10feffffff9e2e1b53ecf545d0b0cb972553deb89f3cce7e9e92d0e0a786779df0df48a113000000006b4830450221008cfdfd352e268dba2022e7fbfc37a90401c40fdf6f1d8ba9dcb97d67743eddc302202c0a1b604d34aa174fddef63c9115c95465548855c5f783bb206eb4ff8fda235412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff9fd5ed5458cdbeb26b0126512a1b1f1aeb85fa7b584a0568c674708fafc0d70000000006a473044022001b33b610b8d742df2ad98679f1e41f0c647faf272e15e7ea93171ba29c33bcd022061646fbcb81ba30d6e8b030ee12101d1f1bef38ba44a6d5daf40c4ff6d644e6e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa6f2a72bf25954904893198f716f7b6f07e68bf35c12c233aa6d165723931068000000006b483045022100ec9b6bbaba90d8902ec8a1ca0e90ea594264bc1add204b756cc89def4d7e9a2a022066b2bc84f94e1a99effe0e929be8de8669631143ca20c73e700d182ad4884e71412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb38019b996f974375732d741fac543bcb46670b99c566a8a887c3f876485a942000000006a473044022057117591cc465c48da58ebcb8f57fcd56359757d41e1397e45b5e33e034ea5d8022001de1d78ce9e8e73370a0778b4a8595045c6faeb2497ab4296d0cff735711276412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbd0ba68d3c24402ccc4d2c82c4d11ba0a794bce9e9d39f64668aa4b5956eb5f7000000006b483045022100dace56650d1d9edaef30e8c9ecb4b78499a573984c8a451253295a90c84a3ed702201f4587d4a760cd77a2e21d5f6f2b7aacf668220c8c7c62fc1ae4779f7c0141cd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff143d2c0bfb63e9b52766c0f7921d06a1d51b90a770b64902ee8352122c918bd5000000006a47304402200db6b461a0082807f59053bea210d38f5f82f02dd63a57f6e3987339cac23870022064ba927fc11b36318785d4e861a7f94cb3909ef8fe882360e2041f7b4a444692412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb0b7e16b8502ccd5ce2ec06157803e5c84062f5e8e4804a633f9e809ce260353000000006b483045022100a3e75a6c7918db32a27be348493b831631856ec8f546ca43d143cdc3c1cd03c802201e6ae036423bfce45c500b0c049f68396deae5cb999038de61e972ccd4cba5e7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff6d284b186e26a4116b02e6568c2868ff13408b85c71db1495a5e7cd32a4151ca000000006b483045022100caf952ca1760052cfefe8df283fdd0eccb9e1238eea88eef287df9404c622e8b022072027363fa1070548576fbf9bcbddf2e435fd020662b2d8f0582b52bfa487b31412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff38bb6ba6ccca482c333c8fd0e35afffb150e4c99fdf70513175f10bb8b263ec0000000006a47304402201a4b4efff2b70a4039b4dc120141da04ae84f63906df10c3cad08838c01b6b8702205a065d025c338547ea07b2095ad31252658e57f1a7a04c7f4eacc0248e611fa2412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa326b367f3405c7648e8e12b5bd7078867796b60f70cd4b3123442a6fcb9c846000000006a47304402206b0a876d78793710acaa8bbeb58a2d908bd4936f2a88825f944b190041b5e0be0220279560be5009e4a3fab44d08f4748e2dead710a8ccc77e06a03ba8112d728856412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff746bb13f09e7c465f9ea0b264c601ef9652736d83ca0c78686ea25326f6bdcfa000000006a4730440220799bdb7ac60cdf3314cc1f157299858d353e22c00354707337ab5b497619d626022000e41053afe44fa65227b7dd8498300a2dc89367d9daf0586caba5bffdfde567412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8da9008652012637c8bd2a3e6c9b6b6c4e12e67126ac1e5cc3b1d42b3c16b5ad000000006b483045022100a1af33a83edb7fdc289a48a4f77cf286a88b38c21ddf27dd4ec3df007ce11046022074dd56730730f958039efd70edfe7e181060fec306c6df4cf75209600ebebed7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff84a1b480079b2256862090844d38dcd463315a43b757678d7002cc1d01001adb000000006b483045022100eff445419ec63d1e9f51a5324c3be0315911b39f30657639e84ea7d2f739e0510220218e73140a39542ec8055b6645cbb7989f96b9d9a93c67549c059509de06f0ba412103dd71b53aaa823b09a68aba30c7603c6a397e7c183f708c9dfb0d9d0a9cd1c722fefffffff8872f26872ae96f137ba029e4ca6d19072f8223c0664608eeacd4753e8969df000000006a473044022050b7ed06a6832b8831c08ba86049b3793b5a71fd6d5177c9f268b79c3074bca7022047447c23429de30c361875642d9058bf1b5e0e6c5516d6e71b70b7cfb29827aa412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7ebebf2f8b764657a719cc52e3ce31fa79c37cd2d583b7be31ad9ec2ebef3284000000006b483045022100fb072bfd399dc11191ac449a9d60119bd191ce6b19a5d92412a805ddc8d4b46f022021e463686560b15ddf272b9943d8e41425ed500f77698aba518ccf546a97aeb4412103e35c58a738805f53af73472ffb671a9bd3556ddef47c62f18ced868bb5033d0dfeffffffbaf05866b6eba762daab7778d4eb3fa1902346491f14c8ec047c12aaae4cff29000000006b483045022100b25e7d4ebaa0e7d8e24498b039e756d568b67316aa14d05abafaec59e216a73d0220010d0b6548a74435907eb0d548dfe8e52a949bbb785eb2be3bce14053953784f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff1330325273e9a1329b3379a553ce95bda9dbd7b83f93fad4acb8c1dd45f4463b000000006a473044022007d2baa9a766c120e111a727bfa8e8bc2e01cc285d4d4f67d2323b213525a10c022020f32be2d9935b6d9b5091db27ebf00aaeb54adc7032badc7ad63f20741ff28a412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff44530eb5b53868de4819fd0dff26c12e2759f4696ce114e22855e88be1b1d41b000000006b483045022100f98ee28ffb66acd04474a120904ec1be2327d727d8ed8fe99d8b95c174b8f46a022041d21406dd8df10cecc1d6435de68fef3f9db71838c1ca2910895bb184b4a6e4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2fbfba76ef97ef4c6e575783e08baa25da64eed6a7eb4ca48707feb7a2927406000000006b483045022100ee3f7961f0f23137d753affe85b777e94c1db3f656cf41b8f59fcf82d9226eb7022025009482a6c0002e409590075caf7a78023ebc1457f100c8b922a4974ebf86ba412103f1d1dd7685d3781f58f9aa399a16f6bb9ccc7d008cdb7c63a7945cfcaa6ba0e2feffffffbf525c080b8b43afd5c004b40d25a7ceba36207162b2bafa70ddc95cae68c1bc000000006a47304402201fed9da4c0526ac5ce257fce2b7fc995646b5f0d2961396327f93e2dfda3e4a0022035b217adc5a9be2ca34f4361ceafd9f2d09a6fa47d4a767f7001ade40c08fe26412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff327b0b903a0f60cadd0c8d2e2cf774ee04eee9a40bf5c37181a471045f365d02000000006b483045022100fa8ee82d42f524290319fb3ee47a1afa70cb952f8a37325680d6fd651ac3699f02205ac0cd86fece03ca204bd881d67ccce0cccbbc98704d9e955e2f92b5b77121dd412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff5fadd3b92b767baaf2a50c8b21f8d3f7cae103e7b4e4c0ba60f111d45f8a1cc6000000006b483045022100f3cb343c4704bebbc78c6492dd72ca19c388b285f44f574dcff25f993add6d5f02200e050dacd78de955cf552f9158beaac5fa64995f5bf7c8a919a231a39425730c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff47d0ae39a2ce683261d30f45025b7faf667146a980c1213b593c482647d77d20000000006a47304402203f05a035f5d42fbfe97172b431a613110ad733e356ebfd08886fa11bedaf1faf022061c4a3bc3417390910612bae46f5acf8b6e8a5b008d273a52e483a315bfb950b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff46cefa6639796b89c5e8981c42a230d8629cadecfca5dc853c85e782ecafcafa000000006b483045022100bf60fbd4716339bbb42ce150966ad6caf90b14e57f45eb6804756cf8ff36b23a02202f16aaecdb9994f3b683cc7fab45bd0a3f54795c336b5fc224fc51270a7f3f4f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4e5c5b111998d7b90d46130f2ef29f25d48e8649eee14684cf6d46eaad3b7026000000006b483045022100bcdcae99c9289b5fc89d3227daaea8df7d0a0f3a8971d841ebe1ab7a1ecf72e202202ca21447a6b3e96540e32529697d523b7b08c65845d6a13f6b1475de94919bb6412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff489efab51aaeba5cfb24d1484a917a33aff79b7455392ce21a3e642a170341c9010000006b4830450221009535c27b5bbca0db2bcf1a0d0b3b283a2171df53f0d68f1a138888fcc6ddd996022068af19252ac4376cffdbfaacb2e0f0c216deb7e2478b586abe7c2679501eac34412103a47e5dea4ab8d785f4e00994d0faf1a8f384c41e74ed8e4b776fa6ce136ebc42feffffff7eee285c72768622c785561839c699b1a748f58ab418615611c70c9d70440518000000006b483045022100b456847e29f8a648730f0fd34cc7edcfb35daba866ab7d800472beaf2836ce4202207db401f0a5e30efc53c7bf58e57d1dec5874d64768ad9eb4895351cc4be9226f412102291b40a9a927dafeb53cdfc7e722ee5c9dfd6eac2d81331678b9ab405bb25d21feffffff93b0226e9f90d151df423d9ff868513f71f708e715cbcb1b5444f4a0194bc267000000006a47304402205ff244c77726def0e3697a3e546bdf74c7f31479c9d01a7a6f8cd1656482d537022045d78dba8ed4d3777f473736daedbdaca6f5698dd306898d144eb43f96259766412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc784e371e706c6de880fe3033039cae758513a73866241658a21fa6a8a4a8d20000000006b483045022100ec6b35ce6d24889726480d70a31bc0d62800bf7ac49ecf084b98137322606bca0220432d33e2d8b508f26d7d813d18629453c537a4d90f73a104bbf80627f9fe8d62412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa4cab40c510ef0ddb8fc3612af871512805ad7ebed2b60fecbe7b9d0f8eea760000000006a4730440220423ea635717cff512d9262b7c8932c0122ca868251f019ae033101c28771a52302200cd3ae05f2e88d9f64207beb4b715ba480bde9ffdd40ab61a36feff88f2968d54121035530745f3cd4d31532991e460bd2a15e1944e690643f73133a9918edb95da53efeffffff852bf329889cdd85945b23bc6a338562c151ecf16b04414c75afb1cb9ded3370000000006a473044022055cc4dfa48a79b8584a9352be34ab5fe9cae4132d264dd827d14ae06d35ad4090220652a83c93505f8a8527c5bc0479f37da0593595c1bf18c12b8fa0b41a2e37a64412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3235c14d72a55c47d9b996588c7110e27d031013e1f2c77deba6241954059f92000000006b4830450221009acc8d0e06d10b0c764a27613bcef41fc75f910875eae3989a7f8725f81814cd02207146ff66f412910ed993fbda4ad6ed48862a02f366dd88a83856a17e7f96d83e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffa0b0aa12e3299ce6c925827b3d5603676949daba619fd9c7bca247d1c265e9a7000000006a47304402202d8cd72290f04063c0ae9bc06d2cae3ac74ef4cb6945c92c3e3ccca210c127ef022030471726cd87ac9d55f3d246095f64ae22b611aa8791922236bbdb19ec273322412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffc856c10b1d42360a93cf60fa8127afcac431417ccb7213f649d45482fc7d89e6010000006b483045022100ffaa954e5b86d54ece9bcb9e37895047221828ca381b03266de3d9341599c8f902200ea1c5ed36e893df822c698a474b062d4f93005c32f9d2f0d78ecaf5a56e4fbd4121031a00f43cd99e015c72acace20ac47d887a39ef284f89a5aa09abd968d06f5e9dfeffffff69129065f6f989f1a008813b345e8cbd881a38107b9a0af3a3718437ad6e9cd6010000006a4730440220457d59caf24eb6e10664d06f3e936f6ee31d9d59f1cc4f6f62788f022bce8c1b02202ce7c37ae6832b078c1cb9a055e3ffcf4674081f0738fd9c3eb4465b52bcc9ca412102fea9ae922223f2c68c68d7672b7656885c3e1321d35cc8f5f445179df6f7d27afeffffff8ad3038c3df6f210fa389c57f72d240dd2da53bf172429620e64758a28a82a21000000006a47304402205e0f5cb06f7fd741825c669c87e9db1a433913fb8577adb92b779d3a693b4f080220120648a5f9d2abae83a29cd2c79f5c61b9bc40da8990736ab97ccf6f82c586cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4fda56201530659af45d3f6ad8704693d321f4c92184403e848bf4c3eb1a6a3d000000006b483045022100debfb215f94e9d784e91fe0b9d2541d09a4c7591172fad1441506db4a3590fd102200cce728e344933111c9548162e62872fccac624f6f98d92ccdcf98dbed09ac544121039b8a20c23f32f5b14e76fb29e0baade695810aa7b6dac9e9638a8d13b6ad8221feffffffe7bf81c3288f97cccc60391101a6bdc7654a30dbb693a9bcc8a4b112535d5891000000006b4830450221008110aec39b127143891069590fa0d9e1d8b41bdda70d9807848eba92cb48736b02201bcfdc1a1cedfa4c53efd941482f6157774b2aa80af44e500263be6a3cbcbacb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4c686bfd13c84da78ae379b1cb6974bd3cde55fffef59f28954095903cd2b3b9000000006b4830450221009f76d6838b8fd8bb74f50c67920fda9f28054d093b30fd03b54b3fb888db046f0220307944f3abec07c3570614f418056aeff03c0830173c963bb0b65bd5ef24b4a9412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3f7108134b932ada8356748fecd11ce666f529c25e4aca3c4253f77b3ba6f965010000006a47304402207b93e2500b189b51fbc3a49a191c4b92ac76e32ce86f6f1b9af4afbb3a91fbe002200b5617cf52095bf882a5129f5477f119c9c565dd582a9f19493cf1bdae6527ac41210323ab0930ba40688e66bef6e08f673bd6bcd3df687e4c503387f48c24bffdc93dfeffffff7edff321567843351e47d6d3bc8394e2cace9fe3b72c4dbb152bc54c6abfdd48000000006a4730440220731ab37e71d9c6f63333ba205a318d36e5847706381f571b4b562e5e6f6e403c02200704ca9d9a33843d9a16135f56eced1fd18e227385671a8df5fa41e505e3ba3c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff71294d7e9b11e4e36de589c91122993add9030771328f27215bb55c36ac2750000000006b483045022100d1d3565175e1f529124ebba1bcdf8c1704e753c2f91ddcd1a093b5f5403cd0ed02207420ee9d6082356cba6d8075b4fbf310bd84dc770734a8ab30e74741a779bae8412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff423caa98d71896bcc3bd086cc2cdbea476888d19a3f3b9d2554e82e1692cc93000000006a47304402203ddf5c6c5065f03229cdf837d9f8d3d22314834b006e0aba8dacabea206b3b150220417c49c9095372d3dfd954688bcd43fdfd2a121989fde18456a9428b2a8e3c63412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffce3d664bc2eff728a9ea3134bf11d8c7e2207ed508e7879ec7ecee976eaf72c6000000006b483045022100a20e6aaca7df2b142b768d3b1cbf8f783f3d4997d155a32f0e066b4255777c9f02206deb15cf53d6b27a973df9aa7080691e5914538d9e97ec7c6e797ce03333238b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb8f5dcd6f0fb2ad1db921e6f79fcd9fa463165091761f9d8baa23673a0a0645f000000006b483045022100cc2cf5c6c2d4862dfdf65407138684ba45565bd8ec46594ed4586bfa37b715dd022013255b2eb22f5bb93d2afdd07ec4c3b5efe0aa16134b2fd084c6bc720f8cfd5c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7c331f8d0e02777c73a28ae441e12de405bacef5ce967761fb521786d5186b25000000006a47304402202c9dd98c9a72e5a8df4b01f09d18e2826d8b9871db89c5d3b24ffd673facaa0702207523bfcf3ab80790167a2b1159fe268770371fcc7d770995c19eace3181ec8af412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4cd501228a577f0662b802b5b197921268202b8658e4aaab7cf6ecccb93cdaae000000006b483045022100bfac8828df10b7911d341c15a532819c429c7185d8883de19de84e71b97d78730220177603a3572908c90dad865770906b5ad228da7ee5da39503ececf60ac735158412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffdbd64011a7b6fe85385fb207b347f02f5e047b7ffd55bd4192af5ea979e2110b000000006b483045022100d598e2ccdeecfdfea9d5139a49a94fa39414f9e1ecb13d54efeb34c168e58aec02202a59463710905613844f48dc71d316c0cae54ab9e16dd95beb8902e5940024ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb90e762342456c7032806bd546929a38782761e2ee29e7aad37778e1ab6e0282000000006b4830450221008302d38e9eaccaea812c853047931562417a3665b8b9373cf7f63e58180b002602207ac8fddbbd19560a74333ec92fa077d169b4902a41e0431113f8fdb75b304ecf412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe15523a831db30cf60f16b15dc338703a64058fa3830c17a4314b4ab824ca943000000006b483045022100c0d85a1f9146e8ef9efaef8ed9b3ed09c55e51b25e189735610da89b6d212360022003a49114e504741befcdb95d52a3dedd1aadef68b7c48f0a4a8c7dddfb4201b5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7893407b6997d973f52a924d03ebdfc639401a138c13e12c2ca365938135f841000000006b48304502210091ec8402cafd1e7eb11b56ac56a994ac79c435893108d0b7c8cfff87c07ba0a602204fd98efddc1b4e21bd3cb81217579a7b9621f9c3c204f2f5800e75ce1c60b19c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff016fa30c4594495726151cbe044ad53de6421e1f28e2366602bd80a3dea98c2f000000006b483045022100a850bf088a08baac1f1f577da8946befe2e6b0354d6a29f636afd39982569a7e022062652d6b75dee145f741d28d6f1870fde9a7d66b994f0d3162abdc42fbf54458412103ffdeec10b52942b0c46d6578998efdc1d64073de579e92e7c5dfa97fdf3ac391feffffffd8659400dae01e9cac6076cb19facc050061f64b16957ad30500503c24294840010000006a4730440220762f7c017672dfc71d487f3730e26d69d0e53902f579ba348095ca164d27b094022076c7e8045ec9fc57af6dd95f35c0ffad2c0ca8f83f112f60fb9851ba4ba15d92412103a2d2d8251728b11fd4afe7b8c73a8442f76dff9bfa424f5cad9b98083936259dfeffffff642ba174ff1ecc14e4f086d70300d487dbaae78bfc684b43557f9b8ad2ca2426000000006a47304402200654032c5760f8b94cc089da51773447f19c1cd2108cab89bb53ccfdb6dbee56022015e277622dea4bd1a7913ff934b2bb2d1b3d75f05285b51690160e1197a258c5412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff654d602ce9a224bbce1fb5f9588977fd780591457ef11de271137ca7fd3c3b89000000006a4730440220712877c0dc553096eb0ebf101d1555fda5235db26ad074d2f330163fab63fc7802202c89752dd7645e8a3da7e8af5fb68dc8b177700766b79cf6a35695a0c7c873cb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffcc614cc3c1c12c9b8cebba5d78a395f5347a5073211a04e03d55b0a8abf386cd000000006b483045022100f3fa1e305666e2a62afaa11fd37025b25c0bdff8709fe1580406615934228cee02204841a7d96f36d3c183f06e22a58175756c3e9a76c93c7cb4e9945f31ddedc902412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff26b2ed7a5c60815f5b62a5d30af9613e69a26e8aaa429be689baddb562e88aae000000006a473044022047c158e3fe3f40de3f39796dcecb7df3cf344f14009de9826b62a43837f2cdcb0220759d823cc145fd5e8b651a7bcc399544692bbf596189b1fc50bba5f4ca02cdd1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffebb012602f05d2bea0016b8b304f59f610922671560469d80e0e913cd2b302b4000000006b483045022100bd70744c867943bc3bf578e192c8a87a5ed5126aac4acd98efa06ea2483911fa02207377e11ae2d2bbaab00da86ec73c26e596bfcc680c0b8eddc5d44bda650bc299412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff87809cf57be510d02c71276f00544888795f624f33d78b01ba63c87340dadee1000000006a473044022059ee25066b8a2a4fdfc35f14c5cbb7f22ab181fcfa9702d4f3de7aa4d738c7a402206dff315ad1cd2222cd6ac074bf34241fc22db38a57bf089f7e24542323f1766c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8c33b7af2120bb22742f4a5e5fb4ecca7cdf73a33bc8811f3d5d3d1cd9399c21000000006a473044022039657cdf4fcd5a9e81766ba11db495b8be5664612d3b91f8504bea342c4ecbe702206ca4913e5807cd697d30dbc93e0a9d679eb01ee84b687ab0c642e2f3ebde745b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8142c39bf2f91bc685f7c08e40450c90b36dc0a6782a764cded6ba744a591f3a000000006a47304402200232ee94873317eae275cf715f4c3aca25dd0c8db4800946a45cc1d9c45732fa02203d9ce9c9aedc0a3899dd027df32e683438769d66f33ffe52006454614b77821d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff503b9a4c5cab71a66b685d3266002970227d0f4a6b1c65b86603b8c8e683cf14000000006b483045022100900bdc6f705efa56449a65f15a67fc7fbbc102f78e7974ea6ac2849c75d2dfec02203b78de71dad2e3f6ffad2779cb9007217c957c8f5db7abd58fd0537fbabb8c6b412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8bed144f5515754d58c273554d25637ec776635033c9ae13bfc94e4b6cecd11d000000006b483045022100becbb21c7937b9b27ea3cdac5f2048ab9ac314de59c3ee2926a5cfb258ce14e902201c8022bf275c1a761e7715b14e15d74526901363ae5f8bf5489d00908dd758eb412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbcb7881db3ede1d9275508f97b9f1e0e008811ce540f3b42a921e26f6f065799000000006b483045022100ad84bcd69a85a0d487fd7cbe4d76b95bffa303e76615a4336419fd182eeae4b902206d21e4f592297e87f1af9e19c80fd978914aaf5a2db2cf499b72cabbbe73c831412102958762ff6c8985dc9656afda59e61afc6c0131a5d8f1d86c87c83c9b37f7bd18feffffffb7ffae52888348a77a9851617df104a29366126e01ecc6bf7d209fc8627646ca000000006b483045022100edfd64cf9335d094d5873deb38cda5f4ceda3351df722f1c718993a2dd12c8e302203126b0f9470a4d0867ed4e773518b8ad689ce43a2c9f65a1f297525fc22201dc412103f37089783028c0776f2b8a9d8481ec8d6d0652a31edc03cc274032ae17c63c62feffffff801a88dcf5725d71cc70aee29ec937233f7a059d60e068dea3b7dbc806e0fd54000000006a4730440220448751a749e7cccacab0ae1ad4da948b0e0b5d8e3f41ac2b22c18928e8e67d41022051c107c345c06ea82fe8329a8cf3a96b516fd8750611d8ef438b8545416398ee412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffbb06af741ad8b99821ecc4dfb5b52a0a79b577cf213eb9335e920d13707c8da0000000006a47304402207f9b2802ed1e893168277204b7919ff479efe5c71ad2a255e1738a52bacd758f0220253780485f2e3ee960e058d449c647b147b8f64b49b913e7e9615a6c7114f18e412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff7827759ce0800e385c440c45ccf6c568a25139aa0f1c80b86f28487ae6a8c0e2000000006a4730440220778fd8ba1dd9f71df55bbe1c3c4185b8da21dda82198546c2a0c30250f4c1d66022040f17a46187d535c6e943c047942f45159a37b2e171db18c657cd24168c22e2f412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff2af935dfaa292af30d0a39a548e81640765b624eb5213d964ebaaa81a3711922000000006a47304402202cd2fd29fa395a5a80893de065c8bbe71e0bfe0e7b2224cfd5684736a086aabc02206720226ba63a3e5d9e2dc67e404625cdf31a7a08da0e8a22717e558f7abc817c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe3e3b78cff7d4798f6e3c8c45d87ac2131913d1328947d6b4ed515b3ab2366bf000000006b483045022100f8769b797386f0bdd662483096f4e0a33c13f6074a4aaba3fd590b9abbca7c2402201eb064869fcd17a59ac028145b08c73b3552544cd7fc62245d1fd1d369ecf765412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffdc319b5c9374a41a08f5f3bd45480a968f651878cde667b3ee3714f72b836be6000000006a4730440220558e65fd916d9c9616a3e0bd41111dba3914867b1ce5d487df4f77feadc0059502203198566c0d58af8551b65f884db98bde161bac140c7a900cd40df97a40c267de412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff69406ab4a28198623b6005bffa68588fea73092364cf2f7a223884c3e0732845000000006b483045022100ca93287feb58daad47c5388067b219e44f8533a214eb8eea9b5313040579773002201716a6ad2de70eff6721ae7950edaf9230420648bb8ec53173c215cbd12246c0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff21e5177112fa1fb5797389490a4f9131600673f139a544050a557fb627b0b360000000006a473044022003240fd71510800910b448c62a03178b4ef62299b17d6d2c06ac8f3293684ff50220637e3ba59fc884a8bd16aa2e884b379d85f38ae4ba049a0365f33644febee6df412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff5488e67a575ab8556c748fc371515b52ff28eb875586eba99fda2b4389e4f96c000000006a47304402202e2ac9c8b619b8e2626895c20f6bdd1a24fa27de017d05d5fa2ce120b3421f25022053ef6f82ccf9a132d40ce566d45f4ec18bf30048d415f6ec1c783cda027b6747412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff03abe81fdd0362f4fa3bae282c2ab1be258882d83392229cea6e36c3f023999c000000006a4730440220352bdfe541e9e1ce428ac4eb4c8ba9391a118b7dbe57b4fe3c4ecd30f228fbff02204a0b78ada1d74a7e7b9ae912e6f445d9ce9050855d9c5ecc7d477d2590a68b18412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff879d7ac96bbdcb9aff885fb27c0f171277a313ef45b8143e04b74d6fa43fd25e000000006946304302203f767d8f64e3c9e5773d94a325f8029d21d1c9a0f470c9288cd99f70d2d90ec2021f50b395f9329ffe64ff8084c1506e904ffc02dfac7f7e15461c3e8a077f604c412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffff00dc8aec564568fdd9114502ed1998de08228bfe4edf74d132cfe595c709fb000000006b483045022100f17f8045a627bf96fe09d868109063d8040e3e2df8944e05f9b20a15273d0bdb022059c31e2d849abd57e784f1a3903f49f18c7c5a624545bab98649e8a092e12a10412103ee2a3f78cd4930dac8c030ccc93381ec5eab259c1607360d85d1728fc296dacffeffffff3f25af68c0083801bf09571e1a300d78768df58ec82e2961a374600bcf90bf36010000006b483045022100b58c7dd3fa1f8dc50edc7b5546b8ccef8ffc5c179fee774999c63fa729ae3cef02205eb611cc887e5a62a4e9da33318ce6e216ca353225f452ebca51be1dd10f544941210267f3c9b9bfb6bc5c1f68dd1d18623a9986408202cf232ad1e4089933c83f186bfeffffff6a94e760788c3ee1c9696e5552020afc2a77bfcb3b2223e35744f1b9abc49b25000000006a4730440220097f46c588f37ced4846a45905df1a0ae22709760f8a1bc930a58f5054cbe482022053b418af66d1edcb3887616feb23e5dd4095f29e74ac89853c3b909eb42bac34412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffb26042d45f30556ab14a69f8be4ce1ac4a360b8407d7da6dde0983f73123a314000000006b483045022100cf98e22a2854c7088a0572e1edb4e876aa622ed10dc0376806e1432f5dc1eef90220527845f8dd2522fbdf423b4fc34a4792a7f82e04b314e0d83e2425daa2f92115412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffe5f0f3bfd4691a43d7488076a0e13ff739c72c6f421d6c0e61a75232ea36d8ac000000006a473044022070c7aaa7d7f050b1b520878e55db3ca491fb33211150e2f620b685cb49d7d885022022d9ede63e3b196a1c33c2d211c1eacf2e2411820ecf5155b5e4244f5dfd9f1d412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffffef905cc2f8ca7d7885f06ad865b721f594595528c2b971b3172313cc7df8c34000000006a473044022018cd70c3e62563ea92ea12735e2efb4b905df85e6b290d573051f49c63d07c60022037a537ca3514121d5c2b8753833808a5e0432f1a8f277d91495953c8211ad326412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff556c7570226e99590f0844c677068cd133f882c7a720f77f32bac2be39aa7baf000000006b483045022100a01ad9ec8d24fdf01eb203c2887c1413ae56990d4600a18010959f6df43de08d022056f0f0dccb8f772f29a7835d7dc40f242348805005b5f80ae8f2fbdb600ab2ca412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff52bec1a85abc7d806dfc9c39427b7cbab7be3aeca8ee99959c84b68cc05ca96b000000006b483045022100cdd770159d56ac518ecb0dc916df0da06eed536e540582680f742389f53fa4be022012d372e2c04176bcb82b91b02ea23c9c1464baef7d1dda66066bf84c402c0012412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff3b2d0442ce89e456c2cfc586906116d280fce17bc310ed957d03b35c61e9eb41000000006a473044022001dc7db378891c1c5bf07a09d14fcc6675965976e2e3e762786b1b1e0f4a4bb702206db6f284dec835823fb516fad89543edd3bd7af3ed33940fa296939fadb41ba841210393ae47ec2e844378cda3630abe12082401f2e0f98d016dde2b152b42e335630dfeffffffc3804827d4f39c54d961dfe79e25325f59b5499ea25b49bfe7ac99bd7c7435a1000000006a4730440220290a5055313d68f9461ce830f8a7395022d2d55abf28f6b4bd665693b4a13730022035d4cc2a6676ed842027dd4f21d31dd5a956f4b1f5cf771b866cc0d4a6400df0412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffd610149123afe34fa647cb0aee336cb903961bee6653b8eefc7f49bb015e0990000000006a47304402201fd6be6d72ae75b61a624c13476b538ec2f9e5146f3074c879af57ecfbe1679702200ab10ae612e7fe0f76fe943c1f6a02262008407f86782c1536e92e3bad77d3db412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff205fab854da34166e1d16d36ab90b1e825440f6c9067ef35d34c41c5e569b144000000006b483045022100a4132f408b5299dfed6153b7a331f9fe866f1b042e4263bf7574ea0964c450a202203d99cf8dc9a9194269bce400185a4f86f5d35b5be83f6dbc3166b600392f1b00412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff8ead5e6ad78ed4926b83bc4a479d4dc5b2dbd2753af5636044cb008f4c6df1f7000000006b483045022100bbcc2e2d77458abc30898cddc7eda060b23a62f0a53b81c3db47f284cd7b29cf0220705328a29bd30792a7f5a704fd74b771c3c8a099265f5e7c9d70046da5b03ff4412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806fefffffff2361f9f2ba5ff1e66349c365e1c0cd9c6cb80ab4f666e9f4777fc188a405202010000006b483045022100d2f40145c4b9a17b3582aabdf7d9ac2d47546b3eea5350c4e2ec1e9c2466343d02203354ce620aa056a749de847f867c49dd121579c9fc50bd6258bff7cfb173c5f24121035bf755e8b075665a85155618f6e9022196a09c486415587dd3af0d25b76e9c27feffffffc8f56b2dc9536ae2c0e11b2062edda6cb33b93284ce7bd8c6531591ae82f0074000000006b483045022100cf8c593dec0724644d034f17ccde99feaf0416334219f158f884badf500fc93e022035af1b68574e88ef15e1c05c1b36638401613a31aa7096d97efba6df62695706412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff95831f16b9696da7fe12787860ca161c12566d110c9262097434a7e0674d6b49000000006b483045022100a669e8918ba68754b84d584f38afdd34be387773449784a6c61ef3f33d0fd99e02204d007ef31f5a3a7c412ac3d2660633fcef137964ef2ff6269c41e933896d918b41210383b6491fd80e1411675d7c8eda9b756c30a814b45fa565b7ac24d7be9dedcaaafeffffff1e1184fc54a53f94ee4d56313349f586effea0bf553bbd0cccefe86c8d606f4a000000006b483045022100fc35ed21833c3ea3ff5f832ef02236a08ded0999ea367aa6eaaff364ecac3e5002206e291d7c4fca0485dd8ea22519544ac632909d706741710a6e5f0d472c0b0656412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff4864e36057e4fe2ece01c3b463c06b56a86e3c341aa0e203097cb09c53a2cfa9000000006a4730440220485937c55c67c8eb46b94523cb06f9572ffb55094536d8b1a458c76b67dec75b02204e5007f610e491d043a412696d4fd769bb2f5d8c3e8b3a59e6ec3bb598f775a7412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffffeed8d2da2afa9b9823aa74a344f6eda5d4b80e5de83caf8455b08c8aac6c4662000000006b483045022100b430528ddfca4431cf5cec08964f7325c036fdee55edc0ea0181d34ed72469bc022074b75bfa66dd4a87fab93da0f2f0def65b785fb0b51fe07355799cbd8b30c39a41210316d35753d58318c06d0faadcb723563316847ae06019984f42f2c75deaf3727dfeffffff4317e8c939993e123310aa4d84dfa4a29ba8dcc0b4c222384ded077936279955000000006b483045022100c6ccc3891fa3924c7b1e69b855628230c48d85d1e1331f037823ab7c5928610c0220050c9c0e078f34ced537e88f95289863a663b28488880f6ada3f1dbbcb1743a1412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff85aed5e452015314973015efa03f0bd2c79d57d976ce3f3ce14498b294fd5b7b000000006a4730440220168f31f413d65ce64bccb62390490dae2e4a00f98c2c44bd4fd689cd942da8b1022006f1b2aa4fae9587c688e8b7ca5c07db3b3c3afd6961f9f843099ed30b583369412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0286800000000000001976a9149a262d0621819c8c17d34a7feca1b39b39157af988acceb18bca1a0000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac26550900" - }, - { - "txid": "99300f90ced7d053b3b24ef3a8fdb5774418e616f07971366a63b9938944ab2d", - "version": 2, - "lockTime": 609135, - "vin": [ - { - "txid": "f0202389fab209e6975199ec2d8abf76fd4cea5d7d441ea0938ff47a35366c45", - "sequence": 4294967294, - "n": 0, - "addresses": [ - "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme" - ], - "isAddress": true, - "value": "1250016811", - "hex": "473044022001b8ba5dbc580e3bf4419b65892f15423e8b0e48d52479fd0317fe4c03ede0a002204013a50c3914aeb7f59183f9e44c880bc94fe9c23045a6311ae4b07da3c2d209412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806" - } - ], - "vout": [ - { - "value": "1000000000", - "n": 0, - "spent": true, - "hex": "76a9142ed9aeddd3aa62d922d33025901531e344914a6288ac", - "addresses": [ - "bitcoincash:qqhdntka6w4x9kfz6vcztyq4x835fy22vg3yc55de7" - ], - "isAddress": true - }, - { - "value": "250016585", - "n": 1, - "spent": true, - "hex": "76a9146932df2f990838523783075db0b985b9bd2330b088ac", - "addresses": [ - "bitcoincash:qp5n9he0nyyrs53hsvr4mv9eskum6geskqthlx9n4d" - ], - "isAddress": true - } - ], - "blockHash": "000000000000000002132a5e60d7b9de0524eeffb36fc91972a7d68afdf17b65", - "blockHeight": 611545, - "confirmations": 20638, - "blockTime": 1575274423, - "value": "1250016585", - "valueIn": "1250016811", - "fees": "226", - "hex": "0200000001456c36357af48f93a01e447d5dea4cfd76bf8a2dec995197e609b2fa892320f0000000006a473044022001b8ba5dbc580e3bf4419b65892f15423e8b0e48d52479fd0317fe4c03ede0a002204013a50c3914aeb7f59183f9e44c880bc94fe9c23045a6311ae4b07da3c2d209412102e367f6787fe02523fe7b16fff187757207befd49d038f1a80363592ef5f12806feffffff0200ca9a3b000000001976a9142ed9aeddd3aa62d922d33025901531e344914a6288ac49f3e60e000000001976a9146932df2f990838523783075db0b985b9bd2330b088ac6f4b0900" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/bitcoincash-api-xpub.js b/mock/ext-api-dyson/get/bitcoincash-api-xpub.js deleted file mode 100644 index 9a8abeb55..000000000 --- a/mock/ext-api-dyson/get/bitcoincash-api-xpub.js +++ /dev/null @@ -1,184 +0,0 @@ -/// Mock for external Bitcoincash API -/// See: -/// curl "http://{bch rpc}/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs" -/// curl "http://localhost:3347/bitcoincash-api/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs" -/// curl "http://localhost:8437/v1/bitcoincash/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX" - -module.exports = { - path: '/bitcoincash-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX", - "balance": "177672", - "totalReceived": "13221795", - "totalSent": "13044123", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 72, - "transactions": [ - { - "txid": "269d428f01fbe49cd6d2c2ca5e6e2f0ff68aece905313932156078d4341d347a", - "version": 1, - "vin": [ - { - "txid": "5536327a38fddb32a92a98582aca4e85b4e50f40b9d3c03db360eaca7b512f97", - "n": 0, - "addresses": [ - "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" - ], - "isAddress": true, - "value": "188124", - "hex": "473044022057e811d95dfce16c7f1d1da574ab4ca1bf883359da34a1e7a380f5045fcffc960220149c357343f0172301f06b914a2844d3755a3e990a236ae33f71afed52f0849d41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" - } - ], - "vout": [ - { - "value": "10000", - "n": 0, - "hex": "76a9147222fa3e0a256cc45823a641aa4060e66718276288ac", - "addresses": [ - "bitcoincash:qpez9737pgjke3zcywnyr2jqvrnxwxp8vgu3nnxf6x" - ], - "isAddress": true - }, - { - "value": "177672", - "n": 1, - "hex": "76a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac", - "addresses": [ - "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" - ], - "isAddress": true - } - ], - "blockHash": "000000000000000000e0846c675bda2ea268eaa290287aef83f8877c40f07743", - "blockHeight": 620315, - "confirmations": 7640, - "blockTime": 1580517507, - "value": "187672", - "valueIn": "188124", - "fees": "452", - "hex": "0100000001972f517bcaea60b33dc0d3b9400fe5b4854eca2a58982aa932dbfd387a323655000000006a473044022057e811d95dfce16c7f1d1da574ab4ca1bf883359da34a1e7a380f5045fcffc960220149c357343f0172301f06b914a2844d3755a3e990a236ae33f71afed52f0849d41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5000000000210270000000000001976a9147222fa3e0a256cc45823a641aa4060e66718276288ac08b60200000000001976a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac00000000" - }, - { - "txid": "5536327a38fddb32a92a98582aca4e85b4e50f40b9d3c03db360eaca7b512f97", - "version": 1, - "vin": [ - { - "txid": "feac34105f3f0bd442f75acaff6b2e840b9e2c0e32e897393d9d0fe47fe76ba1", - "vout": 1, - "n": 0, - "addresses": [ - "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" - ], - "isAddress": true, - "value": "38804", - "hex": "483045022100dbbf18561baf7fdb46c21d27801594209f2067f1d7735e245c56001c4e462d3c0220016e052ebbcf350bd64a257f7cc52ef23730fe50b24355d098f87c528fcd839641210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" - }, - { - "txid": "01b8958ff2a939534269d05af5ac747238eb3a8c91b2a564107af20e4de55680", - "n": 1, - "addresses": [ - "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" - ], - "isAddress": true, - "value": "150000", - "hex": "47304402202100334789951706405faa9ddc191702b88d9438d5a461d1f008a9bd097bd9b0022062cd93003ad63bfbb16386b90e619c2b32d9caef5229d8943c11309f26b6c19f41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" - } - ], - "vout": [ - { - "value": "188124", - "n": 0, - "spent": true, - "hex": "76a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac", - "addresses": [ - "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" - ], - "isAddress": true - } - ], - "blockHash": "00000000000000000028351f97cd867acbba39b5a81137ce35a1ac18444aaa76", - "blockHeight": 619773, - "confirmations": 8182, - "blockTime": 1580201823, - "value": "188124", - "valueIn": "188804", - "fees": "680", - "hex": "0100000002a16be77fe40f9d3d3997e8320e2c9e0b842e6bffca5af742d40b3f5f1034acfe010000006b483045022100dbbf18561baf7fdb46c21d27801594209f2067f1d7735e245c56001c4e462d3c0220016e052ebbcf350bd64a257f7cc52ef23730fe50b24355d098f87c528fcd839641210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5000000008056e54d0ef27a1064a5b2918c3aeb387274acf55ad069425339a9f28f95b801000000006a47304402202100334789951706405faa9ddc191702b88d9438d5a461d1f008a9bd097bd9b0022062cd93003ad63bfbb16386b90e619c2b32d9caef5229d8943c11309f26b6c19f41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd50000000001dcde0200000000001976a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac00000000" - }, - { - "txid": "feac34105f3f0bd442f75acaff6b2e840b9e2c0e32e897393d9d0fe47fe76ba1", - "version": 1, - "vin": [ - { - "txid": "6f2d6fb46039f192f82cfd9bc85dcf0575fdf5eda9b726643314be883c8c0559", - "vout": 1, - "n": 0, - "addresses": [ - "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" - ], - "isAddress": true, - "value": "49256", - "hex": "47304402207df4bd44f74e9a077b84f547b29c595e808bfb3ebc23e070e975905e2012044c02206fa66e30f9afe063c5a5c30d0bb20c6d0eece782a9b6211676180c25d745e98c41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5" - } - ], - "vout": [ - { - "value": "10000", - "n": 0, - "spent": true, - "hex": "76a914045891bcbb214544c47a8dbc75350584d8042bc288ac", - "addresses": [ - "bitcoincash:qqz93yduhvs523xy02xmcaf4qkzdspptcgq4dscr8c" - ], - "isAddress": true - }, - { - "value": "38804", - "n": 1, - "spent": true, - "hex": "76a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac", - "addresses": [ - "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25" - ], - "isAddress": true - } - ], - "blockHash": "0000000000000000015997ed69ac8b1e1d19c006bca7fb08faf3442890b2fed5", - "blockHeight": 619764, - "confirmations": 8191, - "blockTime": 1580198433, - "value": "48804", - "valueIn": "49256", - "fees": "452", - "hex": "010000000159058c3c88be14336426b7a9edf5fd7505cf5dc89bfd2cf892f13960b46f2d6f010000006a47304402207df4bd44f74e9a077b84f547b29c595e808bfb3ebc23e070e975905e2012044c02206fa66e30f9afe063c5a5c30d0bb20c6d0eece782a9b6211676180c25d745e98c41210259dc89eeb4c7b349faab20e932be226a1ed7d582f25b64e9abf84f73e1d25fd5000000000210270000000000001976a914045891bcbb214544c47a8dbc75350584d8042bc288ac94970000000000001976a9149800c09de05d8e2aadcf475f33bed97481c469aa88ac00000000" - } - ], - "usedTokens": 71, - "tokens": [ - { - "type": "XPUBAddress", - "name": "bitcoincash:qzvqpsyaupwcu24dear47va7m96gr3rf4g9gcq4h25", - "path": "m/44'/145'/0'/0/0", - "transfers": 11, - "decimals": 8, - "balance": "177672", - "totalReceived": "850002", - "totalSent": "672330" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/callisto-api-commands1.js b/mock/ext-api-dyson/get/callisto-api-commands1.js deleted file mode 100644 index 01d4a9452..000000000 --- a/mock/ext-api-dyson/get/callisto-api-commands1.js +++ /dev/null @@ -1,84 +0,0 @@ -/// Callisto API Mock -/// See: -/// curl "http://localhost:3347/callisto-api/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" -/// curl "http://localhost:3347/callisto-api/tokens?address=0xc3d5b69f65027ddf48f894e6e90121293a2f6615" -/// curl "https://{callisto rpc}/transactions?address=0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" -/// curl "https://{callisto rpc}/tokens?address=0xc3d5b69f65027ddf48f894e6e90121293a2f6615" -/// curl "http://localhost:8437/v1/callisto/0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7" -/// curl "http://localhost:8437/v2/callisto/tokens/0xc3d5b69f65027ddf48f894e6e90121293a2f6615?Authorization=Bearer" - -module.exports = { - path: '/callisto-api/:command1?', - template: function(params, query, body) { - //console.log(query); - switch (params.command1) { - case 'transactions': - if (query.address === '0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7') { - return JSON.parse(` - { - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0x4052f55ee615a783abaa22a62100a45d2eee27ecab3a599e9d6691371336463e", - "blockNumber": 4699868, - "time": 1584952936, - "nonce": 7973, - "from": "0x28D2c7db63a9fC5f0b1eE3Ee2B7c0c350Eb9256A", - "to": "0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7", - "value": "120071054450000000000", - "gas": "21000", - "gasPrice": "50000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x4052f55ee615a783abaa22a62100a45d2eee27ecab3a599e9d6691371336463e", - "timeStamp": "1584952936" - }, - { - "operations": [], - "contract": null, - "_id": "0x8d50f2e48d3616e55c4adf2b579aa4696459714c2777baf01d43333389acf9c5", - "blockNumber": 4699693, - "time": 1584950541, - "nonce": 1466, - "from": "0x1212c7aE2d01E3d174C759EF616c46C9C50bd94f", - "to": "0x3083a7Ec44ca2b038D4BE4B0798152F948f0f3d7", - "value": "179512617388000000000", - "gas": "21000", - "gasPrice": "50000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x8d50f2e48d3616e55c4adf2b579aa4696459714c2777baf01d43333389acf9c5", - "timeStamp": "1584950541" - } - ], - "total": 2 - } - `); - } - break; - - case 'tokens': - if (query.address === '0xc3d5b69f65027ddf48f894e6e90121293a2f6615') { - return JSON.parse(` - { - "total": 1, - "docs": [ - { - "address": "0xc3d5B69F65027dDF48f894E6e90121293a2F6615", - "name": "The Hitchhikers Guide to the Galaxy", - "decimals": 18, - "symbol": "H2G2" - } - ] - } - `); - } - break; - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/cosmos-api-commands2.js b/mock/ext-api-dyson/get/cosmos-api-commands2.js deleted file mode 100644 index 4a5de1ffc..000000000 --- a/mock/ext-api-dyson/get/cosmos-api-commands2.js +++ /dev/null @@ -1,3686 +0,0 @@ -/// Cosmos API Mock -/// See: -/// curl "http://localhost:3347/cosmos-api/staking/validators?status=bonded" -/// curl "http://localhost:3347/cosmos-api/staking/pool" -/// curl "http://localhost:3347/cosmos-api/minting/inflation" -/// curl "https://{cosmos_rpc}/staking/validators?status=bonded" -/// curl "https://{cosmos_rpc}/staking/pool" -/// curl "https://{cosmos_rpc}/minting/inflation" -/// curl "http://localhost:8437/v2/cosmos/staking/validators" -/// curl "http://localhost:8437/v2/cosmos/staking/delegations/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq?Authorization=Bearer" - -module.exports = { - path: "/cosmos-api/:command1/:command2?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch(params.command1) { - case 'minting': - switch(params.command2) { - case 'inflation': - // status=bonded - return JSON.parse(`{"height":"1419036","result":"0.070000000000000000"}`); - } - - case 'txs': { - if (query["transfer.recipient"] === 'cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq') { - return JSON.parse(` - { - "total_count": "1", - "count": "1", - "page_number": "1", - "page_total": "1", - "limit": "25", - "txs": [ - { - "height": "26616", - "txhash": "3FEE8F10FBA5505DE2A8D3EF220D5CE900CA76B96208234BBF89B8075743A230", - "data": "0C0886C1BEF00510E7FFF6F801", - "logs": [ - { - "msg_index": 0, - "success": true, - "log": "", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "sender", - "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" - }, - { - "key": "sender", - "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" - }, - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "begin_unbonding" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "amount", - "value": "1147uatom" - }, - { - "key": "recipient", - "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" - }, - { - "key": "amount", - "value": "2203000uatom" - } - ] - }, - { - "type": "unbond", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - }, - { - "key": "amount", - "value": "2203000" - }, - { - "key": "completion_time", - "value": "2020-01-03T20:13:58Z" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "127111", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgUndelegate", - "value": { - "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", - "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", - "amount": { - "denom": "uatom", - "amount": "2203000" - } - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "1000" - } - ], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" - }, - "signature": "fJkOgQX9FZz6UJJo48AA3qxc2v/vFrjxlMgq3iOhDmVUWjA2P6X+pPbPkSB1SHlBFlVbsNF/DDPB0pvP9LRPTg==" - } - ], - "memo": "" - } - }, - "timestamp": "2019-12-13T20:13:58Z", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "sender", - "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" - }, - { - "key": "sender", - "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" - }, - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "begin_unbonding" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "amount", - "value": "1147uatom" - }, - { - "key": "recipient", - "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" - }, - { - "key": "amount", - "value": "2203000uatom" - } - ] - }, - { - "type": "unbond", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - }, - { - "key": "amount", - "value": "2203000" - }, - { - "key": "completion_time", - "value": "2020-01-03T20:13:58Z" - } - ] - } - ] - } - ] - } - `); - } - - if (query["message.sender"] === 'cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq') { - return JSON.parse(` - { - "total_count": "2", - "count": "2", - "page_number": "1", - "page_total": "1", - "limit": "25", - "txs": [ - { - "height": "26616", - "txhash": "3FEE8F10FBA5505DE2A8D3EF220D5CE900CA76B96208234BBF89B8075743A230", - "data": "0C0886C1BEF00510E7FFF6F801", - "logs": [ - { - "msg_index": 0, - "success": true, - "log": "", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "sender", - "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" - }, - { - "key": "sender", - "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" - }, - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "begin_unbonding" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "amount", - "value": "1147uatom" - }, - { - "key": "recipient", - "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" - }, - { - "key": "amount", - "value": "2203000uatom" - } - ] - }, - { - "type": "unbond", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - }, - { - "key": "amount", - "value": "2203000" - }, - { - "key": "completion_time", - "value": "2020-01-03T20:13:58Z" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "127111", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgUndelegate", - "value": { - "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", - "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", - "amount": { - "denom": "uatom", - "amount": "2203000" - } - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "1000" - } - ], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" - }, - "signature": "fJkOgQX9FZz6UJJo48AA3qxc2v/vFrjxlMgq3iOhDmVUWjA2P6X+pPbPkSB1SHlBFlVbsNF/DDPB0pvP9LRPTg==" - } - ], - "memo": "" - } - }, - "timestamp": "2019-12-13T20:13:58Z", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "sender", - "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" - }, - { - "key": "sender", - "value": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh" - }, - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "begin_unbonding" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "amount", - "value": "1147uatom" - }, - { - "key": "recipient", - "value": "cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r" - }, - { - "key": "amount", - "value": "2203000uatom" - } - ] - }, - { - "type": "unbond", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - }, - { - "key": "amount", - "value": "2203000" - }, - { - "key": "completion_time", - "value": "2020-01-03T20:13:58Z" - } - ] - } - ] - }, - { - "height": "404179", - "txhash": "93E43518BAE4BC137605BBB7FD5D31FDAE6427ECE57EC299C43CE786FDAEBC63", - "logs": [ - { - "msg_index": 0, - "success": true, - "log": "", - "events": [ - { - "type": "delegate", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh" - }, - { - "key": "amount", - "value": "2211271" - } - ] - }, - { - "type": "message", - "attributes": [ - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "delegate" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "93720", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgDelegate", - "value": { - "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", - "validator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", - "amount": { - "denom": "uatom", - "amount": "2211271" - } - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "1000" - } - ], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A782zo6TI2H3DfHJ7X1WHOJz6p4fUYVRYhb/XqMTcVQt" - }, - "signature": "X1/NzRdb+HUxE7N9gMk39XI8TyHFobLRQtsX4QxZZbYeKmEYOOZ7FyNSGqgmipCkpuysBeh6fNnbXmo3IFzFEQ==" - } - ], - "memo": "" - } - }, - "timestamp": "2020-01-13T15:23:12Z", - "events": [ - { - "type": "delegate", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh" - }, - { - "key": "amount", - "value": "2211271" - } - ] - }, - { - "type": "message", - "attributes": [ - { - "key": "module", - "value": "staking" - }, - { - "key": "sender", - "value": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "key": "action", - "value": "delegate" - } - ] - } - ] - } - ] - } - `); - } - } - - case 'staking': - switch(params.command2) { - case 'pool': - return JSON.parse(` - { - "height":"1419019", - "result": { - "not_bonded_tokens": "2422309183727", - "bonded_tokens": "182732778407119" - } - } - `); - - case 'validators': - return JSON.parse(` - { - "height": "1418977", - "result": [ - { - "operator_address": "cosmosvaloper1qdxmyqkvt8jsxpn5pp45a38ngs36mn2604cqk9", - "consensus_pubkey": "cosmosvalconspub1zcjduepqmq2l5ehgl3rxwjgzgr6sgzp69qwjl5ufvtyvacc9ms8p3phazl2qh3ulfw", - "jailed": false, - "status": 2, - "tokens": "94117413314", - "delegator_shares": "94117413314.000000000000000000", - "description": { - "moniker": "真本聪\u0026IOSG", - "identity": "8A79F44CC25D26DF", - "website": "realsatoshi.net", - "details": "To The Moon Then Cosmos. We are a crypto community and venture capital combined staking service provider" - }, - "unbonding_height": "0", - "unbonding_time": "2019-06-24T19:55:42.604341211Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-08-05T07:24:32.572614545Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", - "consensus_pubkey": "cosmosvalconspub1zcjduepqwrjpn0slu86e32zfu5xxg8l42uk40guuw6er44vw2yl6s7wc38est6l0ux", - "jailed": false, - "status": 2, - "tokens": "5289222663449", - "delegator_shares": "5289222663449.000000000000000000", - "description": { - "moniker": "Certus One", - "identity": "ABD51DF68C0D1ECF", - "website": "https://certus.one", - "details": "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.125000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1qs8tnw2t8l6amtzvdemnnsq9dzk0ag0z52uzay", - "consensus_pubkey": "cosmosvalconspub1zcjduepqsszd2gzte82dzt0xpa3w0ky8lxhjs6zpd5ft8akmkscwujpftymsnt83qc", - "jailed": false, - "status": 2, - "tokens": "1605450345336", - "delegator_shares": "1605450345336.000000000000000000", - "description": { - "moniker": "Castlenode", - "identity": "F685CC35D748424C", - "website": "https://www.castlenode.com/cosmos", - "details": "Castlenode is a validator operator focused on security and run by experienced professionals. Please read our Terms and Conditions on our website before delegating" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.090000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1pz0lfq40sa63n0wany3v95x3yvznc5gyf8u28w", - "consensus_pubkey": "cosmosvalconspub1zcjduepqv03r9c26w884sqw0zdqg9cdx4xxwgn3dd2s6wa3x346tm83nxudqwhm3jl", - "jailed": false, - "status": 2, - "tokens": "296744671239", - "delegator_shares": "296744671239.000000000000000000", - "description": { - "moniker": "Cobo", - "identity": "3B7C85200D5B57A9", - "website": "https://cobo.com/", - "details": "Cobo is the first leading company in the world to offer Proof-of-Stake (PoS) and masternode rewards on user holdings, making it easy for users to grow their digital assets effortlessly." - }, - "unbonding_height": "0", - "unbonding_time": "2019-05-18T11:34:21.668987388Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-06-15T05:45:23.950986198Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1pgsjyvkg3y2m7qas534zzdhsqsxqyph2jh3uck", - "consensus_pubkey": "cosmosvalconspub1zcjduepq5tycuhznpjuwlr93ypflreaddk0r66hdryzgmfvmlj2ekdd5sqrqnxclgg", - "jailed": false, - "status": 2, - "tokens": "228520445065", - "delegator_shares": "228520445065.000000000000000000", - "description": { - "moniker": "OneSixtyTwo", - "identity": "1C136F82A18BB2E2", - "website": "", - "details": "OneSixtyTwo" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-20T16:43:30.502949835Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", - "consensus_pubkey": "cosmosvalconspub1zcjduepqtcsm8lp7n6ph98vd59qa9esgyuysuntww9juz5wynxrhzpspmuuq6g5pzg", - "jailed": false, - "status": 2, - "tokens": "1125811000585", - "delegator_shares": "1125811000585.000000000000000000", - "description": { - "moniker": "WeStaking", - "identity": "DA9C5AD3E308E426", - "website": "https://www.westaking.io", - "details": "Delegate your atom to us for the staking rewards. We will do our best as secure and stable validator." - }, - "unbonding_height": "0", - "unbonding_time": "2019-09-07T12:24:58.270714195Z", - "commission": { - "commission_rates": { - "rate": "0.030000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-29T00:37:22.163935678Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1pjmngrwcsatsuyy8m3qrunaun67sr9x7z5r2qs", - "consensus_pubkey": "cosmosvalconspub1zcjduepqcdav5ylt2zst90qmuh8e5w07xmxv9y6wufp5k9ngzmx7v9qewqtqkcq4z8", - "jailed": false, - "status": 2, - "tokens": "654800077136", - "delegator_shares": "654800077136.000000000000000000", - "description": { - "moniker": "Cypher Core", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1p650epkdwj0jte6sjc3ep0n3wz6jc9ehh8jutg", - "consensus_pubkey": "cosmosvalconspub1zcjduepqmy5ja8dee3sprtmxkekcuvwz20y2x9d6llcsjl6p6553rpqev0eql6qccf", - "jailed": false, - "status": 2, - "tokens": "111582433714", - "delegator_shares": "111615914997.731210796675788592", - "description": { - "moniker": "Cosmos Suisse", - "identity": "2D875495A911A943", - "website": "https://cosmos-suisse.com", - "details": "An awesome Validator based in Crypto Valley, Switzerland." - }, - "unbonding_height": "970101", - "unbonding_time": "2020-03-21T06:33:36.130547135Z", - "commission": { - "commission_rates": { - "rate": "0.295000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-04-05T06:40:17.027131003Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1zqgheeawp7cmqk27dgyctd80rd8ryhqs6la9wc", - "consensus_pubkey": "cosmosvalconspub1zcjduepq5tm478lhn4du7l46yp6fgu9e8fcfks0j4kf87pk4z8vc3clckxzqvh2q72", - "jailed": false, - "status": 2, - "tokens": "685457015651", - "delegator_shares": "685457015651.000000000000000000", - "description": { - "moniker": "melea-◮👁◭", - "identity": "4BE49EABAA41B8BF", - "website": "https://meleatrust.com/", - "details": "Validator service secure and trusted, awarded in Game Of Steaks" - }, - "unbonding_height": "0", - "unbonding_time": "2019-06-26T23:50:09.38840326Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-27T05:18:46.405341672Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1rpgtz9pskr5geavkjz02caqmeep7cwwpv73axj", - "consensus_pubkey": "cosmosvalconspub1zcjduepq04y0dtylyed2f8drc9t78dmptfuta7l6xyujwmsgrqefs0sxpgjsnzpsj6", - "jailed": false, - "status": 2, - "tokens": "3995820273418", - "delegator_shares": "3996619557261.806706040418750517", - "description": { - "moniker": "Blockpower", - "identity": "C374865C7ADE710B", - "website": "http://blockpower.capital/cosmos", - "details": "We self-bond 1m atoms and will keep our fee low till transfer enabled. We are top-ten validator in Tezos and operate professional staking services for multiple PoS platforms. Twitter: https://twitter.com/blockpowercap and TG: https://t.me/blockpowercosmos" - }, - "unbonding_height": "0", - "unbonding_time": "2019-11-04T04:14:24.222468286Z", - "commission": { - "commission_rates": { - "rate": "0.030000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-31T19:58:53.172697095Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1r8kyvg4me2upnvlk26n2ay0zd5t4jktna8hhxp", - "consensus_pubkey": "cosmosvalconspub1zcjduepqsl29jhapyxf4fa5a947dmnlvrt266fm959hfg2c657ju80hq0ljs3qejr7", - "jailed": false, - "status": 2, - "tokens": "250002000000", - "delegator_shares": "250002000000.000000000000000000", - "description": { - "moniker": "noma", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-03-14T03:50:13.123302789Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1rwh0cxa72d3yle3r4l8gd7vyphrmjy2kpe4x72", - "consensus_pubkey": "cosmosvalconspub1zcjduepq5kg8xls9l35ftulkm2rt70hexeeyr5cqqkcv4h7936z5uasvvazqla8eck", - "jailed": false, - "status": 2, - "tokens": "5699344397878", - "delegator_shares": "5699344397878.000000000000000000", - "description": { - "moniker": "SparkPool", - "identity": "DE8E37240061B04E", - "website": "https://cosmos.sparkpool.com/", - "details": "The biggest Ethereum mining pool, we can be a reliable validator with our 3 years" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.040000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-09-26T06:05:19.676181518Z" - }, - "min_self_delegation": "100000000000" - }, - { - "operator_address": "cosmosvaloper1rcp29q3hpd246n6qak7jluqep4v006cdsc2kkl", - "consensus_pubkey": "cosmosvalconspub1zcjduepq7mft6gfls57a0a42d7uhx656cckhfvtrlmw744jv4q0mvlv0dypskehfk8", - "jailed": false, - "status": 2, - "tokens": "243735228951", - "delegator_shares": "243735228951.000000000000000000", - "description": { - "moniker": "2nd only to Certus One in GoS: in3s.com", - "identity": "0CE19EE3E4BA48E5", - "website": "https://in3s.com/Services#CosmosValidator", - "details": "https://in3s.com/Delegate#Delegate" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-03-18T20:31:50.23335594Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1y0us8xvsvfvqkk9c6nt5cfyu5au5tww2ztve7q", - "consensus_pubkey": "cosmosvalconspub1zcjduepqqhkzzgfc876q287ny2v9lqwmjpenuzkzlsnstrmg7krwrrf0pfqs9fxvs0", - "jailed": false, - "status": 2, - "tokens": "12973804826", - "delegator_shares": "12973804826.000000000000000000", - "description": { - "moniker": "Swiss Staking", - "identity": "165F85FC0194320D", - "website": "https://swiss-staking.ch", - "details": "Experienced PoS Validator. We refund downtime slashing to 100%." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-12-11T18:25:42.711862818Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper19yy989ka5usws6gsd8vl94y7l6ssgdwsrnscjc", - "consensus_pubkey": "cosmosvalconspub1zcjduepqf22yaz9nsxlh043qm0tmupw8pnpver2n8lm3mwz6jzmsql76fkmqa482y8", - "jailed": false, - "status": 2, - "tokens": "500001550260", - "delegator_shares": "500001550260.000000000000000000", - "description": { - "moniker": "OKEx Pool", - "identity": "406C257E090E70AA", - "website": "http://www.okpool.top", - "details": "An innovative mining pool with higher yield" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-09-26T10:31:26.722694911Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1998928nfs697ep5d825y5jah0nq9zrtd00yyj7", - "consensus_pubkey": "cosmosvalconspub1zcjduepqlecm0rrfrr0vfgl624s7su9xvd3ycsaetndeuw2c7us0v8vfyfsq7cqz80", - "jailed": false, - "status": 2, - "tokens": "105880988262", - "delegator_shares": "105902167539.392512073112670643", - "description": { - "moniker": "HLT", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "2019-12-22T20:58:53.786852369Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-06-17T11:29:36.731435956Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper199mlc7fr6ll5t54w7tts7f4s0cvnqgc59nmuxf", - "consensus_pubkey": "cosmosvalconspub1zcjduepqajqpmv4j70a08ahs8lyjt8qk28ffa77zjegd7yajghchy8au575qmmxuyt", - "jailed": false, - "status": 2, - "tokens": "571392869594", - "delegator_shares": "571392869594.000000000000000000", - "description": { - "moniker": "Velocity V1", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-05-30T20:41:10.689796224Z" - }, - "min_self_delegation": "1000000" - }, - { - "operator_address": "cosmosvaloper19v9ej55ataqrfl39v83pf4e0dm69u89rngf928", - "consensus_pubkey": "cosmosvalconspub1zcjduepqa32xgy8y5s69j6dynjmr3rlpv5dv35whz2tyaedwtjeqckm5gg4s2hj8ss", - "jailed": false, - "status": 2, - "tokens": "14356837431", - "delegator_shares": "14356837431.000000000000000000", - "description": { - "moniker": "blockscape", - "identity": "C46C8329BB5F48D8", - "website": "https://blockscape.network/", - "details": "By delegating, you confirm that you are aware of the risk of slashing and that M-Way Solutions GmbH is not liable for any potential damages to your investment." - }, - "unbonding_height": "483", - "unbonding_time": "2020-01-01T17:32:11.54021567Z", - "commission": { - "commission_rates": { - "rate": "0.099900000000000000", - "max_rate": "0.399900000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-02T09:18:02.304119479Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper19j2hd230c3hw6ds843yu8akc0xgvdvyuz9v02v", - "consensus_pubkey": "cosmosvalconspub1zcjduepq9ge7uqrfp9qkdapzd29tjtwrqpt2mm9meptx395ygxgm40tdc8ysrzj40a", - "jailed": false, - "status": 2, - "tokens": "441435636408", - "delegator_shares": "441435636408.000000000000000000", - "description": { - "moniker": "syncnode", - "identity": "F422F328C14AFBFA", - "website": "wallet.syncnode.ro", - "details": "email: g@ysncnode.ro || Operator's LinkedIn: https://www.linkedin.com/in/gbunea/ || Telegram Channel: https://t.me/syncnodeValidator || Blog: https://medium.com/syncnode-validator" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-01-15T11:41:35.747062104Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper19kwwdw0j64xhrmgkz49l0lmu5uyujjayxakwsn", - "consensus_pubkey": "cosmosvalconspub1zcjduepq668g4epaumjtx35rk3ucz2nlm7l7zuewkt0kzutg9hha859zjxmsvl2v67", - "jailed": false, - "status": 2, - "tokens": "630448698935", - "delegator_shares": "630448698935.000000000000000000", - "description": { - "moniker": "Firmamint", - "identity": "2FE4BC7A59E09FD0", - "website": "https://www.firmamint.io/", - "details": "The FUTURE is at STAKE - Proudly Canadian - Tier 1 WINNER of Game of Stakes Adversarial Testnet" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.030000000000000000" - }, - "update_time": "2019-03-18T22:02:43.333950761Z" - }, - "min_self_delegation": "1500000000" - }, - { - "operator_address": "cosmosvaloper1xym2qygmr9vanpa0m7ndk3n0qxgey3ffzcyd5c", - "consensus_pubkey": "cosmosvalconspub1zcjduepq5evf9e4qhkxym6lx0ur2mwuz5e09u2v7u54yz3wcfanqwvhkc7rqcgpmlw", - "jailed": false, - "status": 2, - "tokens": "100726900000", - "delegator_shares": "100726900000.000000000000000000", - "description": { - "moniker": "🐡grant.fish", - "identity": "BE328F9A089F50C9", - "website": "http://grant.fish", - "details": "Providing grants to projects contributing to the Cosmos ecosystem." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-12-11T17:14:13.747872899Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1x8rr4hcf54nz6hfckyy2n05sxss54h8wz9puzg", - "consensus_pubkey": "cosmosvalconspub1zcjduepq8xpk5nh78lmgg0s0qqdyh4xtcw66xemt8anjsr6hrvlhauq252kstq7zr7", - "jailed": false, - "status": 2, - "tokens": "876463600211", - "delegator_shares": "876463600211.000000000000000000", - "description": { - "moniker": "cosmosgbt", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-10-18T04:22:16.555340871Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1x88j7vp2xnw3zec8ur3g4waxycyz7m0mahdv3p", - "consensus_pubkey": "cosmosvalconspub1zcjduepqhm6gjjkwecqyfrgey96s5up7drnspnl4t3rdr79grklkg9ff6zaqnfl2dg", - "jailed": false, - "status": 2, - "tokens": "2025689252407", - "delegator_shares": "2025689252407.000000000000000000", - "description": { - "moniker": "Staking Facilities", - "identity": "6B0DF6793DE1FB1F", - "website": "stakingfacilities.com", - "details": "Earn rewards with one of the most experienced and secure validators. More than 150k USD in customer rewards paid out. We exclude liability for any financial damage resulting from delegating." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-23T22:11:43.172644866Z" - }, - "min_self_delegation": "100000000000" - }, - { - "operator_address": "cosmosvaloper1x065cjlgejk2p2la0029akfvdy52gtq9mm58ta", - "consensus_pubkey": "cosmosvalconspub1zcjduepqny59kv2elgh89tq9qr4jje2n0my4gyvh2hlnydzljtt542a5plwswtas48", - "jailed": false, - "status": 2, - "tokens": "150298393037", - "delegator_shares": "150298393037.000000000000000000", - "description": { - "moniker": "MathWallet麦子钱包", - "identity": "58320327FF6C928C", - "website": "https://mathwallet.org", - "details": "Math Wallet is a powerful and secure universal crypto wallet that enables storage of all BTC, ETH/ERC20, NEO/NEP5, EOS/ENU/Telos, TRON, ONT, BinanceChain, Cosmos/IRISnet tokens, supports cross-chain token exchange and a multi-chain dApp store." - }, - "unbonding_height": "0", - "unbonding_time": "2019-07-21T13:52:13.251185336Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-09-09T03:44:27.230973438Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03xfytvz7", - "consensus_pubkey": "cosmosvalconspub1zcjduepqdgvppnyr5c9pulsrmzr9e9rp7qpgm9jwp5yu8g3aumekgjugxacq8a9p2c", - "jailed": false, - "status": 2, - "tokens": "5364854020103", - "delegator_shares": "5364854020103.000000000000000000", - "description": { - "moniker": "iqlusion", - "identity": "DCB176E79AE7D51F", - "website": "iqlusion.io", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "100000000000" - }, - { - "operator_address": "cosmosvaloper1gdg6qqe5a3u483unqlqsnullja23g0xvqkxtk0", - "consensus_pubkey": "cosmosvalconspub1zcjduepqlsvqw4vacnv2qtwxmm8tq32lrcdhau3szqxevrrzy8u0jvwz69pqphnkzk", - "jailed": false, - "status": 2, - "tokens": "76705740036", - "delegator_shares": "76705740036.000000000000000000", - "description": { - "moniker": "zugerselfdelegation", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2020-02-21T16:46:55.500729256Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1fqzqejwkk898fcslw4z4eeqjzesynvrdfr5hte", - "consensus_pubkey": "cosmosvalconspub1zcjduepqd4hvh0rwfkhtwrj4ly3ptyxs8pyfaser57wx2tcnzzp0rlref90sxm5kwr", - "jailed": false, - "status": 2, - "tokens": "412308417647", - "delegator_shares": "412308417647.000000000000000000", - "description": { - "moniker": "commercio.network", - "identity": "ADBDB0178E4441BE", - "website": "https://commercio.network", - "details": "The Documents Blockchain" - }, - "unbonding_height": "0", - "unbonding_time": "2019-06-23T11:25:09.272949514Z", - "commission": { - "commission_rates": { - "rate": "0.090000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-05-25T10:53:14.835657659Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1ff0dw8kawsnxkrgj7p65kvw7jxxakyf8n583gx", - "consensus_pubkey": "cosmosvalconspub1zcjduepqu08f7tuce8k88tgewhwer69kfvk5az3cn5lz3v8phl8gvu9nxu8qhrjxfj", - "jailed": false, - "status": 2, - "tokens": "685381971996", - "delegator_shares": "685450516977.642009537883274736", - "description": { - "moniker": "Compass", - "identity": "72CB5AAAAFB1CE69", - "website": "http://val.network/", - "details": "EasyZone is a decentralized light client, which means users can access account, stake and earn rewords with local key store. For the time being we focus on Tendermint ecosystem, including Cosmos, QOS and Irisnet etc. Winner of the Game of Stakes." - }, - "unbonding_height": "0", - "unbonding_time": "2019-10-14T04:10:07.163539573Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2", - "consensus_pubkey": "cosmosvalconspub1zcjduepqzu34dgs2p6ysz52hpdycls4jcfwgnf2pvxv0eh539ypmadkjfmes6mwaa3", - "jailed": false, - "status": 2, - "tokens": "717001927145", - "delegator_shares": "717001927145.000000000000000000", - "description": { - "moniker": "POS Bakerz", - "identity": "3AFAE7268F4DFD10", - "website": "https://posbakerz.com/", - "details": "Secure, Reliable and Efficient Staking-as-a-Service" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-02T09:39:28.188566867Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", - "consensus_pubkey": "cosmosvalconspub1zcjduepquuc5k7egx8ymejamr27c3sgw6tyhmt0eq0ak4qvflvhxx56nvjzsx9etmd", - "jailed": false, - "status": 2, - "tokens": "3596427902503", - "delegator_shares": "3596427902503.000000000000000000", - "description": { - "moniker": "Huobi Wallet", - "identity": "CF01514DBF6583FE", - "website": "https://www.huobiwallet.com", - "details": "Huobi Wallet is a leading multi-chain wallet from Huobi Group and also offering competitive Proof-of-Stake (PoS) rewards for users to grow their digital assets. As a Cosmos validator, Huobi Wallet offers the one and only hard slashing insurance fund to our delegators" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.020000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-01-06T02:06:36.387455308Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper125umsz3fws7gepn5ccsh0sv4gre9r6a3tccz4r", - "consensus_pubkey": "cosmosvalconspub1zcjduepqkzserh5aetg6m33vrfcsuz60qpkgkpkpzkh8gp9lsd7cxffgph4qjzkxft", - "jailed": false, - "status": 2, - "tokens": "6281466956", - "delegator_shares": "6281466956.000000000000000000", - "description": { - "moniker": "Moonstake", - "identity": "742F7B64C32DF7A6", - "website": "https://www.moonstake.io/", - "details": "Shoot For The Moon" - }, - "unbonding_height": "950642", - "unbonding_time": "2020-03-19T15:59:10.375998429Z", - "commission": { - "commission_rates": { - "rate": "0.030000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2020-03-03T10:05:22.79594206Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper124maqmcqv8tquy764ktz7cu0gxnzfw54n3vww8", - "consensus_pubkey": "cosmosvalconspub1zcjduepq279zs0zgd53ujngs6v2hus2le9rk2a2rs66j4yvv6ewvvxn29yqqk95h8x", - "jailed": false, - "status": 2, - "tokens": "636354488555", - "delegator_shares": "636354488555.000000000000000000", - "description": { - "moniker": "Simply Staking", - "identity": "F74595D6D5D568A2", - "website": "https://www.simply-vc.com.mt", - "details": "Simply VC runs highly reliable and secure infrastructure in our own datacentre in Malta, built with the aim of supporting the growth of the blockchain ecosystem." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.070000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-05-11T17:29:59.537654017Z" - }, - "min_self_delegation": "1000000" - }, - { - "operator_address": "cosmosvaloper1tflk30mq5vgqjdly92kkhhq3raev2hnz6eete3", - "consensus_pubkey": "cosmosvalconspub1zcjduepqwcvy8hyw2phdp080ggj7prxv972rvqc9gwyjnl0uwf7uxn63s8vqdctdcw", - "jailed": false, - "status": 2, - "tokens": "164930806828", - "delegator_shares": "164930806828.000000000000000000", - "description": { - "moniker": "Everstake", - "identity": "", - "website": "https://everstake.one", - "details": "Reliable and experienced staking service provider from Ukraine. Visit our website for more details." - }, - "unbonding_height": "0", - "unbonding_time": "2019-12-07T19:10:59.878559804Z", - "commission": { - "commission_rates": { - "rate": "0.030000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-07-14T19:56:46.186760169Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1ttfytaf43nkytzp8hkfjfgjc693ky4t3y2n2ku", - "consensus_pubkey": "cosmosvalconspub1zcjduepq2nfs6lcwu6ksq54yf0ptgrmjjrnm5p5ywng3x0t0767m777hvctq30rwcs", - "jailed": false, - "status": 2, - "tokens": "68002415747", - "delegator_shares": "68009216666.737140135826986143", - "description": { - "moniker": "StarCluster", - "identity": "F97B6EF4FD82202F", - "website": "https://starcluster.tech", - "details": "With decades of passion invested in tech, we provide a team of top security and infrastructure engineers as a service. With extensive knowledge in the blockchain space and having run a successful ICO, we are confident that providing our experience \u0026 skills could benefit many." - }, - "unbonding_height": "0", - "unbonding_time": "2019-12-24T15:27:58.293852371Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "0.150000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-10-26T21:50:11.42045872Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v", - "consensus_pubkey": "cosmosvalconspub1zcjduepqjg26g27dtvjqstyqktmp4jsn98473vfz0mek2eyklfp0yqapav5szdrvpd", - "jailed": false, - "status": 2, - "tokens": "3519949961612", - "delegator_shares": "3519949961612.000000000000000000", - "description": { - "moniker": "CoinoneNode", - "identity": "F4E86EE9BD73A11F", - "website": "https://node.coinone.co.kr", - "details": "The more, the easier. Coinone Node manages your assets securely." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-14T09:22:28.276013718Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1vrg6ruw00lhszl4sjgwt5ldvl8z0f7pfp5va85", - "consensus_pubkey": "cosmosvalconspub1zcjduepq2hfnf0rvk6nksvtzkqly4vy362sencfkt7tgsrvx30krj5vxw0asa7hmjh", - "jailed": false, - "status": 2, - "tokens": "342783139733", - "delegator_shares": "342783139733.000000000000000000", - "description": { - "moniker": "SSSnodes", - "identity": "C5B68615F8828EC0", - "website": "http://sssnodes.com/cosmos", - "details": "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by SSSnodes, a Corp. focused on delegation service for multiple Proof of Stake networks, such as COSMOS, ChainX, IOST, CyberMiles, Lambda, ONT, etc." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.018000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-28T08:09:59.47667909Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1vf44d85es37hwl9f4h9gv0e064m0lla60j9luj", - "consensus_pubkey": "cosmosvalconspub1zcjduepqtj2urav4g9wex3hku588au0x4sucrc9lpky46zp5u8w4mvd584sqmcxxhs", - "jailed": false, - "status": 2, - "tokens": "7246081767965", - "delegator_shares": "7246081767965.000000000000000000", - "description": { - "moniker": "MultiChain Ventures", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.020000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-08-21T08:01:01.670548948Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1v5y0tg0jllvxf5c3afml8s3awue0ymju89frut", - "consensus_pubkey": "cosmosvalconspub1zcjduepq9kun5ty55rl3lnmf46tfxhj06as8h7zpxcdhujm6d708ffn6kgss43q6u9", - "jailed": false, - "status": 2, - "tokens": "5856792267830", - "delegator_shares": "5856792267830.000000000000000000", - "description": { - "moniker": "Zero Knowledge Validator (ZKV)", - "identity": "3E38E52A12F94561", - "website": "https://zkvalidator.com/", - "details": "Zero Knowledge Validator: Stake \u0026 Support ZKP Research \u0026 Privacy Tech" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-11-11T15:48:18.737920871Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1vk706z2tfnqhdg6jrkngyx7f463jq58nj0x7p7", - "consensus_pubkey": "cosmosvalconspub1zcjduepq0qdudwaluzpy5ptluu5umck5fp2ns2qf2kjp367qlr7yf65agx5s0n8h7f", - "jailed": false, - "status": 2, - "tokens": "26192977888", - "delegator_shares": "26192977888.000000000000000000", - "description": { - "moniker": "Public Payments", - "identity": "1850627141D54797", - "website": "https://www.publicpayments.io", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-01-02T12:25:53.791107872Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1d0aup392g3enru7eash83sedqclaxvp7fzh6gk", - "consensus_pubkey": "cosmosvalconspub1zcjduepql9j7qpwvfl0pspymhesj48t3t0aazjx0m2jwjuyxd7zw53hqnkss4hmasl", - "jailed": false, - "status": 2, - "tokens": "194657773848", - "delegator_shares": "194677241406.157421240224999535", - "description": { - "moniker": "Stir", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "2019-06-21T20:37:09.115641759Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-14T13:03:10.437070061Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1dse76yk5jmj85jsd77ewsczc4k3u4s7a870wtj", - "consensus_pubkey": "cosmosvalconspub1zcjduepqjdc9grwq5mxdtg26hv9t75y3ltsau3rtmg6p72p0dh8343nj4s6qr6xymd", - "jailed": false, - "status": 2, - "tokens": "399992036873", - "delegator_shares": "400032040000.820061751426683457", - "description": { - "moniker": "gf.network", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "10001", - "unbonding_time": "2020-01-02T11:58:18.459331455Z", - "commission": { - "commission_rates": { - "rate": "0.080000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-05-27T12:23:08.242833465Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1de7qx00pz2j6gn9k88ntxxylelkazfk3g8fgh9", - "consensus_pubkey": "cosmosvalconspub1zcjduepqwr5p8j076mfydn7wckqz748lr0j50zwgsftnfpvgz6rz0rkvvqwqg5fyaf", - "jailed": false, - "status": 2, - "tokens": "222020931706", - "delegator_shares": "222020931706.000000000000000000", - "description": { - "moniker": "Cosmic Validator", - "identity": "FF4B91B50B71CEDA", - "website": "", - "details": "A reliable, passionate and service oriented Cosmos, Polkadot and Sentinel validator. We are long term trusted community members and have received delegation from the Interchain Foundation (ICF) as a reward for our continuous support and effort." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-10-07T05:35:40.25581859Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1d7ufwp2rgfj7s7pfw2q7vm2lc9txmr8vh77ztr", - "consensus_pubkey": "cosmosvalconspub1zcjduepq2x456pyef8jdnjgk8j62fuug24xfg9cnnjl66ewtgttwr00phz8sdzatkj", - "jailed": false, - "status": 2, - "tokens": "117924360855", - "delegator_shares": "117924360855.000000000000000000", - "description": { - "moniker": "Cybernetic Destiny", - "identity": "", - "website": "", - "details": "The future you’ve always wanted." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2020-02-07T23:19:03.834895518Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1wp9jne5t3e4au7u8gfep90g59j0qdhpeqvlg7n", - "consensus_pubkey": "cosmosvalconspub1zcjduepq6740f8r23xr74w94l5ew9fh6n8wquutgm22pw6yyrydq507mgdkqghsjtd", - "jailed": false, - "status": 2, - "tokens": "92787621513", - "delegator_shares": "92787621513.000000000000000000", - "description": { - "moniker": "Newroad Network", - "identity": "F898ACE263EC1C4E", - "website": "https://newroad.network/cosmos/", - "details": "We provide a professional delegation service for multiple Proof of Stake networks. We use a secure and redundant setup. Visit our website for more information." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2020-02-26T08:44:32.038638755Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1wtv0kp6ydt03edd8kyr5arr4f3yc52vp3u2x3u", - "consensus_pubkey": "cosmosvalconspub1zcjduepq0zyaquh6c8vmjfzft43uqylf2ejjpjcvup2zrtsk40uyz8xsq29s0k4eaw", - "jailed": false, - "status": 2, - "tokens": "353202000001", - "delegator_shares": "353202000001.000000000000000000", - "description": { - "moniker": "kytzu", - "identity": "909A480D5643CCC5", - "website": "https://www.linkedin.com/in/calinchitu", - "details": "Blockchain consultant, running on IPSX infrastructure (calin@ip.sx)" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-07-13T04:46:58.395203387Z" - }, - "min_self_delegation": "1000000" - }, - { - "operator_address": "cosmosvaloper1wdrypwex63geqswmcy5qynv4w3z3dyef2qmyna", - "consensus_pubkey": "cosmosvalconspub1zcjduepqs0et7kpf82glsw5j9jnppekrpa7kl6gr6xk67ztqg9ynmhgj82ks9edcrw", - "jailed": false, - "status": 2, - "tokens": "457217580134", - "delegator_shares": "457217580134.000000000000000000", - "description": { - "moniker": "Genesis Lab", - "identity": "C1A123F2723041F0", - "website": "https://genesislab.net", - "details": "Genesis Lab is a blockchain-focused development company and validation nodes operator in PoS networks" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.070000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-15T17:32:00.387570437Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1wd8vquxza6svsvvnh489tdvg9vdjjfpepcfvf9", - "consensus_pubkey": "cosmosvalconspub1zcjduepqf4qptg2va4frg7g35c4plnlq0ngny64qv34a9vzhy39vuv8jwjfsexun5p", - "jailed": false, - "status": 2, - "tokens": "6427445224", - "delegator_shares": "6427445224.000000000000000000", - "description": { - "moniker": "DeBank", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-12-25T08:04:37.22829156Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1wwspfe7whh3zu4ql5rvpg044lyk6cuu7fpnd9e", - "consensus_pubkey": "cosmosvalconspub1zcjduepqz7ylkz6wapcwa5k3gn7vh6efd0qk7cqwp2rxh5lf0l7lhvsh4m8qhgp2zf", - "jailed": false, - "status": 2, - "tokens": "5699129041", - "delegator_shares": "5699129041.000000000000000000", - "description": { - "moniker": "Bit Cat🐱", - "identity": "FAB46CEEAEAB9FA1", - "website": "https://www.bitcat365.com", - "details": "Secure and stable validator service from China team" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.020000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-07-30T09:12:32.806551501Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1w0494h0l4mneaq7ajkrcjvn73m2n04l87j2nst", - "consensus_pubkey": "cosmosvalconspub1zcjduepquxeuhp0gj88u5mrukuazzrxc4rnjjuakls4fr2gzxlwj4f9p8lfs965r7z", - "jailed": false, - "status": 2, - "tokens": "96449451062", - "delegator_shares": "96478391551.647848054450574736", - "description": { - "moniker": "Angel", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "804087", - "unbonding_time": "2020-03-07T13:08:49.834368524Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.500000000000000000" - }, - "update_time": "2019-03-18T15:40:26.600089741Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1w42lm7zv55jrh5ggpecg0v643qeatfkd9aqf3f", - "consensus_pubkey": "cosmosvalconspub1zcjduepqz679nxu2dkfd6y9hytqwvf2z4yuevraqykkm2464ag4e6z278h3qdq92xu", - "jailed": false, - "status": 2, - "tokens": "761888512720", - "delegator_shares": "761888512720.000000000000000000", - "description": { - "moniker": "Mythos", - "identity": "2E9FDF34351A5112", - "website": "https://mythos.services", - "details": "Staking and validator services for crypto networks" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw", - "consensus_pubkey": "cosmosvalconspub1zcjduepq6adydsk7nw3d63qtn30t5rexhfg56pq44sw4l9ld0tcj6jvnx30s5xw9ar", - "jailed": false, - "status": 2, - "tokens": "1817891090486", - "delegator_shares": "1817891090486.000000000000000000", - "description": { - "moniker": "Staked", - "identity": "E7BFA6515FB02B3B", - "website": "https://staked.us/", - "details": "Staked operates highly available and highly secure, institutional grade staking infrastructure for leading proof-of-stake (PoS) protocols." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.020000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1wauge4px27c257nfn4k3329wteddqw7gs3n66u", - "consensus_pubkey": "cosmosvalconspub1zcjduepqqaffdhuhdtr0d6nl8twpraxps74q3mxn68qknrex465yd9cc9l0qeh6lkk", - "jailed": false, - "status": 2, - "tokens": "166849428224", - "delegator_shares": "166849428224.000000000000000000", - "description": { - "moniker": "DappPub", - "identity": "BB2D113EFC6DFDC4", - "website": "https://dapp.pub", - "details": "DappPub, Unleashing the Power of DApps" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-05-15T10:37:35.020580984Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper102ruvpv2srmunfffxavttxnhezln6fnc54at8c", - "consensus_pubkey": "cosmosvalconspub1zcjduepq9weu2v0za8fdcvx0w3ps972k5v7sm6h5as9qaznc437vwpfxu37q0f3lyg", - "jailed": false, - "status": 2, - "tokens": "419722382279", - "delegator_shares": "419722382279.000000000000000000", - "description": { - "moniker": "Ztake.org", - "identity": "09A303A2C724C591", - "website": "https://ztake.org/", - "details": "Support reliable independent validator" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.070000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-08-14T05:12:52.848294105Z" - }, - "min_self_delegation": "10" - }, - { - "operator_address": "cosmosvaloper1000ya26q2cmh399q4c5aaacd9lmmdqp90kw2jn", - "consensus_pubkey": "cosmosvalconspub1zcjduepqe93asg05nlnj30ej2pe3r8rkeryyuflhtfw3clqjphxn4j3u27msrr63nk", - "jailed": false, - "status": 2, - "tokens": "457608104422", - "delegator_shares": "457608104422.000000000000000000", - "description": { - "moniker": "Staking Fund", - "identity": "805F39B20E881861", - "website": "https://www.staking.fund", - "details": "Staking Fund has been participating in the validating role since early 2018 and is a proud member of the Never Jailed Crew of Game of Stakes." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.120000000000000000", - "max_rate": "0.334000000000000000", - "max_change_rate": "0.012019031323000000" - }, - "update_time": "2020-02-02T00:47:46.138000758Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper10nzaaeh2kq28t3nqsh5m8kmyv90vx7ym5mpakx", - "consensus_pubkey": "cosmosvalconspub1zcjduepqmuspsp8739l0lgn2qz0arargk6ccfy2p82mwflsrsqzwpvhuh5usuwykf6", - "jailed": false, - "status": 2, - "tokens": "73145988986", - "delegator_shares": "73145988986.000000000000000000", - "description": { - "moniker": "Blockdaemon", - "identity": "8F898657DE26D645", - "website": "https://blockdaemon.com/node-marketplace/#staking", - "details": "Blockdaemon provides maximum uptime for the Cosmos network so that you can be confident your node will be there, ready and secure, for optimal reward generation. Contact us to stake on Cosmos today." - }, - "unbonding_height": "0", - "unbonding_time": "2019-12-19T03:19:44.114438899Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-10-29T19:55:36.41178089Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper10e4vsut6suau8tk9m6dnrm0slgd6npe3jx5xpv", - "consensus_pubkey": "cosmosvalconspub1zcjduepqteacnywz7urnac46wtrcy34myyj82j250ny7866yffypdgavae5s0lf4a0", - "jailed": false, - "status": 2, - "tokens": "3607499246627", - "delegator_shares": "3607499246627.000000000000000000", - "description": { - "moniker": "B-Harvest", - "identity": "8957C5091FBF4192", - "website": "https://bharvest.io", - "details": "B-Harvest focus on the value of high standard security \u0026 stability, active community participation on Cosmos Network, and real world practical use-case of blockchain technology." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-24T11:21:51.694254562Z" - }, - "min_self_delegation": "9000000000" - }, - { - "operator_address": "cosmosvaloper1sxx9mszve0gaedz5ld7qdkjkfv8z992ax69k08", - "consensus_pubkey": "cosmosvalconspub1zcjduepqjnnwe2jsywv0kfc97pz04zkm7tc9k2437cde2my3y5js9t7cw9mstfg3sa", - "jailed": false, - "status": 2, - "tokens": "2545294437814", - "delegator_shares": "2545294437814.000000000000000000", - "description": { - "moniker": "validator.network | Security first. Highly available.", - "identity": "357F80896B3311B4", - "website": "https://validator.network", - "details": "Highly resilient and secure validator operating out of Northern Europe. See website for terms of service." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-06-30T08:32:22.562118158Z" - }, - "min_self_delegation": "100000000" - }, - { - "operator_address": "cosmosvaloper1sd4tl9aljmmezzudugs7zlaya7pg2895ws8tfs", - "consensus_pubkey": "cosmosvalconspub1zcjduepq8y846wm58fmmuctxp7csqmaz3594xnykcean0lp722ntf6u5ycaqss4prd", - "jailed": false, - "status": 2, - "tokens": "1080650483982", - "delegator_shares": "1080650483982.000000000000000000", - "description": { - "moniker": "InfStones (Infinity Stones)", - "identity": "39A41C2FDE0AD040", - "website": "https://infstones.io", - "details": "Fueling Blockchain Beyond Infinity!" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-05-10T06:56:55.530159974Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1s05va5d09xlq3et8mapsesqh6r5lqy7mkhwshm", - "consensus_pubkey": "cosmosvalconspub1zcjduepqgx5xdrx0xktl5r8e3w7vj329fgh3fnep8ahgx8027nd5nkjxzuqs5us5en", - "jailed": false, - "status": 2, - "tokens": "557166703758", - "delegator_shares": "557166703758.000000000000000000", - "description": { - "moniker": "Wetez", - "identity": "26FA2B24F46A98EF", - "website": "https://www.wetez.io", - "details": "Wetez is the most professional team in the POS ( Proof of Stake) field.Wetez是POS领域最专业的团队,为POS带来的权益做更多赋能。" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-03-25T02:35:12.908955321Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1ssm0d433seakyak8kcf93yefhknjleeds4y3em", - "consensus_pubkey": "cosmosvalconspub1zcjduepqrgyyjxpe0ujefxwnkpmqz9m0hj03y09tdz9lwc0s7mvy469hulfq69f8sd", - "jailed": false, - "status": 2, - "tokens": "1548438266517", - "delegator_shares": "1548438266517.000000000000000000", - "description": { - "moniker": "IRISnet-Bianjie", - "identity": "DB667A6F239969F5", - "website": "https://irisnet.org/irisnet-bianjie", - "details": "Interchain Service Hub for NextGen Distributed Applications." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.020000000000000000" - }, - "update_time": "2019-06-21T04:33:57.044358454Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9u2lcnj0", - "consensus_pubkey": "cosmosvalconspub1zcjduepq6fpkt3qn9xd7u44478ypkhrvtx45uhfj3uhdny420hzgsssrvh3qnzwdpe", - "jailed": false, - "status": 2, - "tokens": "12598748851227", - "delegator_shares": "12598748851227.000000000000000000", - "description": { - "moniker": "🐠stake.fish", - "identity": "90B597A673FC950E", - "website": "stake.fish", - "details": "We are the leading staking service provider for blockchain projects. Join our community to help secure networks and earn rewards. We know staking." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.040000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1s6x9fy4wc49wj9jx4jv6czredqsmp46h7vnk2q", - "consensus_pubkey": "cosmosvalconspub1zcjduepqfkkyuexns2l7rw2mx2ms988heah0rjv42e9q88scc3ms5hzg45psycrvr4", - "jailed": false, - "status": 2, - "tokens": "735675714417", - "delegator_shares": "735675714417.000000000000000000", - "description": { - "moniker": "SNZPool", - "identity": "FF2019D4CF1F3185", - "website": "https://snzholding.com", - "details": "SNZ is a crypto assets capital, consulting agency, community builder and professional \u0026 reliable POS validator for a dozen of projects like Cosmos, IRISnet, EOS, ONT, Loom, etc." - }, - "unbonding_height": "0", - "unbonding_time": "2019-05-31T14:02:51.669843605Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1s6t3wzx6mcv3pjg5fp2ddzplm3gj4pg6d330wg", - "consensus_pubkey": "cosmosvalconspub1zcjduepqncdd6lvm4r42eke822e5eg0alentpvlxjwzat7nvpynlp0vcu55sl5z96g", - "jailed": false, - "status": 2, - "tokens": "245002260000", - "delegator_shares": "245002260000.000000000000000000", - "description": { - "moniker": "omega3", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-03-22T01:22:56.42711479Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1s65zmn32zugl57ysj47s7vmfcek0rtd7he7wde", - "consensus_pubkey": "cosmosvalconspub1zcjduepqrc6g9m2eyy4zs7kyeph8vk5ldpgnceveelc39zf7lc32j8k3shqssevdlg", - "jailed": false, - "status": 2, - "tokens": "194202250000", - "delegator_shares": "194202250000.000000000000000000", - "description": { - "moniker": "firstblock", - "identity": "23D9B8528FC93D58", - "website": "https://firstblock.io", - "details": "You Delegate. We Validate." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-01-09T03:45:47.112144406Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1s7jnk7t6yqzensdgpvkvkag022udk842qdjdtd", - "consensus_pubkey": "cosmosvalconspub1zcjduepqnnh28nlj55sc329ppnhcr0xx7kuc9vnsp3dpwc28wdhhxtjc7jfs9k57f7", - "jailed": false, - "status": 2, - "tokens": "336505666793", - "delegator_shares": "336505666793.000000000000000000", - "description": { - "moniker": "Blockscale", - "identity": "F38EDEA063FD446C", - "website": "https://blockscale.net", - "details": "Planet-scale blockchain infrastructure." - }, - "unbonding_height": "0", - "unbonding_time": "2019-06-14T07:33:07.032714186Z", - "commission": { - "commission_rates": { - "rate": "0.250000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-09-21T01:23:56.63727699Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper132juzk0gdmwuxvx4phug7m3ymyatxlh9734g4w", - "consensus_pubkey": "cosmosvalconspub1zcjduepq9xu9z6ky3nz3k544ar4zhupjehkxdlpmt2l90kekxkrvuu7hxfgslcdqwy", - "jailed": false, - "status": 2, - "tokens": "2451022343872", - "delegator_shares": "2451022343872.000000000000000000", - "description": { - "moniker": "P2P.ORG - P2P Validator", - "identity": "E12F4695036D8072", - "website": "https://p2p.org", - "details": "One of the winners of Cosmos Game of Stakes. We provide a simple, secure and intelligent staking service to help you generate rewards on your blockchain assets across 9+ networks within a single interface. Let’s stake together - p2p.org." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.010000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-11T17:13:40.302520375Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper130mdu9a0etmeuw52qfxk73pn0ga6gawkxsrlwf", - "consensus_pubkey": "cosmosvalconspub1zcjduepqfahazsjeru5wqulfuzklmkh272ggss2ru6fk00zq2fmlfzcq773sqlqe42", - "jailed": false, - "status": 2, - "tokens": "1127978319378", - "delegator_shares": "1127978319378.000000000000000000", - "description": { - "moniker": "jackzampolin", - "identity": "0979483D4F669CFF", - "website": "https://pylonvalidator.com", - "details": "'You must construct additional pylons' -StarCraft" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.150000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-03-25T15:28:01.171914203Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper13sduv92y3xdhy3rpmhakrc3v7t37e7ps9l0kpv", - "consensus_pubkey": "cosmosvalconspub1zcjduepqqddwwkhkfrsd66u49kg3h6q36t4kv557vlszqaed4c3y936ncq9s0r0tm2", - "jailed": false, - "status": 2, - "tokens": "1647613576303", - "delegator_shares": "1647613576303.000000000000000000", - "description": { - "moniker": "nylira.net", - "identity": "6A0D65E29A4CBC8E", - "website": "https://nylira.net", - "details": "Stake and earn with security and peace of mind. Operated by Peng Zhong." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-05-14T21:33:23.86382871Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper13ce7hhqa0z3tpc2l7jm0lcvwe073hdkkpp2nst", - "consensus_pubkey": "cosmosvalconspub1zcjduepqmx0dcpmd9uq7ueck8d880lrt8tp9kvkfmaz0mtv0arye2cda2zrsrlla3n", - "jailed": false, - "status": 2, - "tokens": "61552309043", - "delegator_shares": "61552309043.000000000000000000", - "description": { - "moniker": "RockX", - "identity": "A15B586AB203F14E", - "website": "www.rockx.com", - "details": "Unlocking the full value of digital assets and decentralized governance" - }, - "unbonding_height": "0", - "unbonding_time": "2019-12-24T17:24:12.507160243Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-09-05T08:00:55.144718017Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1jxv0u20scum4trha72c7ltfgfqef6nsch7q6cu", - "consensus_pubkey": "cosmosvalconspub1zcjduepqnru7aa6ayyuwddd5qsa6tvutzs7xl9jk6pfx4ka5dr4y9d3q6eesgz9rz7", - "jailed": false, - "status": 2, - "tokens": "302293155457", - "delegator_shares": "302293155457.000000000000000000", - "description": { - "moniker": "Ping.pub", - "identity": "6EA723DA332200B2", - "website": "https://ping.pub", - "details": "We are one of the most secure and stable validator, welcome to delegate to us. 我们是最安全,最稳定,性价比最高的验证人节点,欢迎委托给我们!" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.020000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.200000000000000000" - }, - "update_time": "2019-11-18T12:14:35.328556Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1j0vaeh27t4rll7zhmarwcuq8xtrmvqhudrgcky", - "consensus_pubkey": "cosmosvalconspub1zcjduepqvn4a4skwj88c8e0jvns3qjrhyy0whvnuwmth3k8kexvqk5vupw4qsdje47", - "jailed": false, - "status": 2, - "tokens": "1071888285988", - "delegator_shares": "1071888285988.000000000000000000", - "description": { - "moniker": "chainflow-cosmos-prodval-01", - "identity": "81D443FA08A4A926", - "website": "https://chainflow.io/cosmos", - "details": "Operated by Chris Remus (Twitter @cjremus) / Validating since the Validator Working Group formed in October 2017" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.120000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-04-01T15:19:20.666364183Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1jlr62guqwrwkdt4m3y00zh2rrsamhjf9num5xr", - "consensus_pubkey": "cosmosvalconspub1zcjduepq5e8w7t7k9pwfewgrwy8vn6cghk0x49chx64vt0054yl4wwsmjgrqfackxm", - "jailed": false, - "status": 2, - "tokens": "723622196447", - "delegator_shares": "723622196447.000000000000000000", - "description": { - "moniker": "StakeWith.Us", - "identity": "609F83752053AD57", - "website": "https://stakewith.us", - "details": "Secured Staking Made Easy. Put Your Crypto to Work - Hassle Free. Disclaimer: Delegators should understand that delegation comes with slashing risk. By delegating to StakeWithUs Pte Ltd, you acknowledge that StakeWithUs Pte Ltd is not liable for any losses on your investment." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-04-22T12:01:25.715205208Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1n5pu2rtz4e2skaeatcmlexza7kheedzh8a2680", - "consensus_pubkey": "cosmosvalconspub1zcjduepqnd9kzfhhvuv5k2cq62yu0e5v73ymsgxa0wlen9c7999ucwg7hg6qdm34pm", - "jailed": false, - "status": 2, - "tokens": "576060849627", - "delegator_shares": "576060849627.000000000000000000", - "description": { - "moniker": "BlockMatrix 🚀", - "identity": "DA33F58EC17769B4", - "website": "https://blockmatrix.network", - "details": "Experienced validator across multiple PoS and DPoS networks. Winners in the Game of Stakes. Cosmos FTW!" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "10" - }, - { - "operator_address": "cosmosvaloper1nm0rrq86ucezaf8uj35pq9fpwr5r82clzyvtd8", - "consensus_pubkey": "cosmosvalconspub1zcjduepqsnngsdda53d9aqwezvpsx4uh2nkwkn4nra5lw4tyl9n3m02q4kvsrqq0pw", - "jailed": false, - "status": 2, - "tokens": "145001000000", - "delegator_shares": "145001000000.000000000000000000", - "description": { - "moniker": "Cthulhu", - "identity": "Cthulhu", - "website": "Cthul.hu", - "details": "Cthulhu" - }, - "unbonding_height": "644758", - "unbonding_time": "2020-02-23T10:33:51.593569686Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2020-01-22T08:27:20.214359212Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper15r4tc0m6hc7z8drq3dzlrtcs6rq2q9l2nvwher", - "consensus_pubkey": "cosmosvalconspub1zcjduepqjcp9ez3dzmvsdfcw2h5kllmqvjgqnhtlvhad4q9wzcqf34gf6ewq6zl5mm", - "jailed": false, - "status": 2, - "tokens": "730533169795", - "delegator_shares": "730533169795.000000000000000000", - "description": { - "moniker": "DragonStake", - "identity": "EA61A46F31742B22", - "website": "https://dragonstake.io", - "details": "Forking the Banks" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-24T18:52:31.67294751Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper159eexl76jlygrxnfreehl3j9tt70d8wfnn39fw", - "consensus_pubkey": "cosmosvalconspub1zcjduepq0jhujmf2ur4uk7al8pht6rpxwf7a24gqmhggeche0w09fglj9tmss4a0ql", - "jailed": false, - "status": 2, - "tokens": "8594550000", - "delegator_shares": "8594550000.000000000000000000", - "description": { - "moniker": "fishegg.net", - "identity": "", - "website": "http://www.fishegg.net", - "details": "welcome to join staking" - }, - "unbonding_height": "7949", - "unbonding_time": "2020-01-02T07:58:37.125916904Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-13T14:17:35.977287639Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf", - "consensus_pubkey": "cosmosvalconspub1zcjduepqtw8862dhw8uty58d6t2szfd6kqram2t234zjteaaeem6l45wclaq8l60gn", - "jailed": false, - "status": 2, - "tokens": "9408964703954", - "delegator_shares": "9408964703954.000000000000000000", - "description": { - "moniker": "Binance Staking", - "identity": "", - "website": "https://binance.com", - "details": "Exchange the world" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.025000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-06T07:47:39.033746293Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper15urq2dtp9qce4fyc85m6upwm9xul3049e02707", - "consensus_pubkey": "cosmosvalconspub1zcjduepqjc07nu2ya8tyzl8m385rnc382pkulwt2gh8yary73f3a96jak7pqsf63xf", - "jailed": false, - "status": 2, - "tokens": "4800643669275", - "delegator_shares": "4800643669275.000000000000000000", - "description": { - "moniker": "Chorus One", - "identity": "00B79D689B7DC1CE", - "website": "https://chorus.one/", - "details": "Secure Cosmos and shape its future by delegating to Chorus One, a highly secure and stable validator. By delegating, you agree to the terms of service at: https://chorus.one/cosmos/tos" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.075000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.020000000000000000" - }, - "update_time": "2019-08-13T17:43:26.871706216Z" - }, - "min_self_delegation": "10" - }, - { - "operator_address": "cosmosvaloper1402ggxz5u6vm29sqztwqq8vxs3ke6dmwl2z5dk", - "consensus_pubkey": "cosmosvalconspub1zcjduepqd4qh9dqgyce948kn48r2aqk7qlgtuwdmfeewj0z9aj4dr30v33cq6pmlql", - "jailed": false, - "status": 2, - "tokens": "9831948191", - "delegator_shares": "9832931400.858711612156228525", - "description": { - "moniker": "Cosmoon", - "identity": "8935A6F323FA0881", - "website": "https://cosmoon.org/", - "details": " Professional Stake Rewards Service " - }, - "unbonding_height": "1126591", - "unbonding_time": "2020-04-03T05:56:12.40115085Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2020-01-27T22:18:16.158833459Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper14kn0kk33szpwus9nh8n87fjel8djx0y070ymmj", - "consensus_pubkey": "cosmosvalconspub1zcjduepqmfxl36td7rcdzszzrk6c7kzp5l3jlw4lnxz8zms3py7qcsa9xlns7zxfd6", - "jailed": false, - "status": 2, - "tokens": "2279800547152", - "delegator_shares": "2279800547152.000000000000000000", - "description": { - "moniker": "Forbole", - "identity": "2861F5EE06627224", - "website": "https://www.forbole.com/cosmos-hub-validator/", - "details": "As a prominent validator and contributor in Cosmos since 2017, Forbole is devoted to build a stronger Cosmos ecosystem. We are award winners in Game of Stakes and HackAtom. Please join our [community](https://t.me/forbole) or visit [our website](https://www.forbole.com/)." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.095000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-10T16:52:29.417872059Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper14k4pzckkre6uxxyd2lnhnpp8sngys9m6hl6ml7", - "consensus_pubkey": "cosmosvalconspub1zcjduepquhlqdhjw4qp2c2t6qh5z7tfk52qc72623f0etc8f3n7hy8uuh25ql34fvu", - "jailed": false, - "status": 2, - "tokens": "11370687848139", - "delegator_shares": "11370687848139.000000000000000000", - "description": { - "moniker": "Polychain Labs", - "identity": "A51CE3B9CD649C3F", - "website": "https://cosmos.polychainlabs.com", - "details": "Secure staking with Polychain Labs, the most experienced institutional grade staking team." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-04-22T04:57:29.717811274Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper146kwpzhmleafmhtaxulfptyhnvwxzlvm87hwnm", - "consensus_pubkey": "cosmosvalconspub1zcjduepqfc7vnpgls3an0w2pv60pu4vr30p2dxqlmhmlrdv0m38y3tg689vs5qg4u5", - "jailed": false, - "status": 2, - "tokens": "85928911865", - "delegator_shares": "85928911865.000000000000000000", - "description": { - "moniker": "🌐 KysenPool.io", - "identity": "2474A8FCC4426BC5", - "website": "https://www.kysenpool.io", - "details": "Based in Silicon Valley. Help secure Cosmos by delegating to Kysen. Validators are backed by HSMs in Tier 3 enterprise-grade data centers." - }, - "unbonding_height": "0", - "unbonding_time": "2019-09-06T03:47:00.801583378Z", - "commission": { - "commission_rates": { - "rate": "0.079000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-23T06:10:09.194879379Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper14az9dmutwtz4vuycvae8csm4wwwtm0aumtlppe", - "consensus_pubkey": "cosmosvalconspub1zcjduepq59t2nm3ph5k6uc804w0n7ey69ul8ntee2dy47d7u53q248ud822sunv93j", - "jailed": false, - "status": 2, - "tokens": "1745806120297", - "delegator_shares": "1745980718357.935064116083909306", - "description": { - "moniker": "F4RM", - "identity": "181FAE6C0E4FA498", - "website": "http://www.f4rm.io", - "details": "F4RM - secure network validation \u0026 pooled digital asset staking" - }, - "unbonding_height": "546055", - "unbonding_time": "2020-02-15T08:28:57.815140271Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-15T10:36:44.571237954Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper14l0fp639yudfl46zauvv8rkzjgd4u0zk2aseys", - "consensus_pubkey": "cosmosvalconspub1zcjduepq7jsrkl9fgqk0wj3ahmfr8pgxj6vakj2wzn656s8pehh0zhv2w5as5gd80a", - "jailed": false, - "status": 2, - "tokens": "1970826215820", - "delegator_shares": "1970826215820.000000000000000000", - "description": { - "moniker": "ATEAM", - "identity": "0CB9A4E7643FF992", - "website": "nodeateam.com", - "details": "[GOS Never Jailed crew \u0026 Top-Tier] Node A-Team promises to provide validator node operation services at the highest quality" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.099000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-03-15T00:18:37.289241198Z" - }, - "min_self_delegation": "5000" - }, - { - "operator_address": "cosmosvaloper14lultfckehtszvzw4ehu0apvsr77afvyju5zzy", - "consensus_pubkey": "cosmosvalconspub1zcjduepqp0j4vum7ryt6nl6zsgq9ar347afmq2c5z6jmzeavv2p2ns6m0dgs5zmg4z", - "jailed": false, - "status": 2, - "tokens": "11215950232520", - "delegator_shares": "11215950232520.000000000000000000", - "description": { - "moniker": "DokiaCapital", - "identity": "25422F4ADF3F6765", - "website": "https://staking.dokia.cloud", - "details": "Downtime is not an option for Dokia Capital. We operate an enterprise-grade infrastructure that is robust and secure." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "0.150000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1k9a0cs97vul8w2vwknlfmpez6prv8klv03lv3d", - "consensus_pubkey": "cosmosvalconspub1zcjduepqfgpyq4xk4s96ksmkfrr7juea9kmdxkl5ht94xgpxe240743u9cvsht489p", - "jailed": false, - "status": 2, - "tokens": "900772962204", - "delegator_shares": "900772962204.000000000000000000", - "description": { - "moniker": "Stake Capital", - "identity": "1DD9A932591FA928", - "website": "https://stake.capital", - "details": "'Trustless Digital Asset Management', Twitter: @StakeCapital, operated by @bneiluj @leopoldjoy" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.080000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.030000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1kgddca7qj96z0qcxr2c45z73cfl0c75p7f3s2e", - "consensus_pubkey": "cosmosvalconspub1zcjduepqay5ldqdmyzy9qfr93enxmm7cwsd5aafz6huqvczytqahpw4twa8qvtrwhv", - "jailed": false, - "status": 2, - "tokens": "599883677526", - "delegator_shares": "599883677526.000000000000000000", - "description": { - "moniker": "ChainLayer", - "identity": "AD3CDBC91802F94A", - "website": "https://www.chainlayer.io", - "details": "Secure and reliable validator. TG: https://t.me/chainlayer" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-04-01T18:02:13.514368678Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1ktecz4dr56j9tsfh7nwg8s9suvhfu70qykhu5s", - "consensus_pubkey": "cosmosvalconspub1zcjduepq4euv7ertqhgvxrla583fg9g6z2v2dzrkl9spche4j4r23vukmx2q8gqvev", - "jailed": false, - "status": 2, - "tokens": "5766932920", - "delegator_shares": "5766932920.000000000000000000", - "description": { - "moniker": "Dawns.World", - "identity": "AA70E5B206F952A3", - "website": "https://dawns.world", - "details": "To discover token's intrinsic real value and enhance its liquidity" - }, - "unbonding_height": "1282180", - "unbonding_time": "2020-04-16T04:36:32.319738894Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-17T15:57:42.95929171Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1kj0h4kn4z5xvedu2nd9c4a9a559wvpuvu0h6qn", - "consensus_pubkey": "cosmosvalconspub1zcjduepqvc5xdrpvduse3fc084s56n4a6dhzudyzjmywjx25fkgw2fhsj70searwgy", - "jailed": false, - "status": 2, - "tokens": "1564634211770", - "delegator_shares": "1564634211770.000000000000000000", - "description": { - "moniker": "Cryptium Labs", - "identity": "5A309B5CA189D8B3", - "website": "https://cryptium.ch", - "details": "Secure and available validation from the Swiss Alps" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.110000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-27T11:16:35.284063151Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1kn3wugetjuy4zetlq6wadchfhvu3x740ae6z6x", - "consensus_pubkey": "cosmosvalconspub1zcjduepqc8slfqdszcd85wzzweuanv0em4h4gdc5wkh3et6e7t8z93z24u0s0rdlx2", - "jailed": false, - "status": 2, - "tokens": "3445647543790", - "delegator_shares": "3445647543790.000000000000000000", - "description": { - "moniker": "HuobiPool", - "identity": "23536C5BDE3EB949", - "website": "https://www.huobipool.com/", - "details": "Huobi Pool is a sub-brand of Huobi Group, which is an important part of the global ecological strategy of Huobi.Huobi Pool has become one of the largest POS communities in the Asia- Pacific region, the leading POW pool and nodes of a number of public chains." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.010000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-04-05T10:43:26.93220487Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1hvsdf03tl6w5pnfvfv5g8uphjd4wfw2h4gvnl7", - "consensus_pubkey": "cosmosvalconspub1zcjduepq5l63vgd8m9chc3c32wn5lthzsax6xxdylpzmhqmjwrgfhd3m2swsj2wc2d", - "jailed": false, - "status": 2, - "tokens": "100005087848", - "delegator_shares": "100015089026.194888154307376423", - "description": { - "moniker": "Atom.Bi23", - "identity": "EB3470949B3E89E2", - "website": "https://atom.bi23.com", - "details": "Bi23 focuses on the Crypto-Assets, providing customers with Staking and DeFi services." - }, - "unbonding_height": "0", - "unbonding_time": "2019-08-16T15:34:04.702756371Z", - "commission": { - "commission_rates": { - "rate": "0.500000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-11T04:30:32.134491966Z" - }, - "min_self_delegation": "2" - }, - { - "operator_address": "cosmosvaloper1hjct6q7npsspsg3dgvzk3sdf89spmlpfdn6m9d", - "consensus_pubkey": "cosmosvalconspub1zcjduepqnltddase4lqjcfhup8ymg0qex3srakg54ppv06pstvwdjxkm6tmq08znvs", - "jailed": false, - "status": 2, - "tokens": "4653603791655", - "delegator_shares": "4653603791655.000000000000000000", - "description": { - "moniker": "Figment Networks", - "identity": "E5F274B870BDA01D", - "website": "https://figment.network", - "details": "Makers of Hubble and Canada’s largest Cosmos validator, Figment is the easiest and most secure way to stake your Atoms." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.090000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-06T12:17:54.693866931Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1crqm3598z6qmyn2kkcl9dz7uqs4qdqnr6s8jdn", - "consensus_pubkey": "cosmosvalconspub1zcjduepqt0fpxxufuuhavfqh8zg3pjnnwdvvzw9huemzxe59kpjt5e3xprhs7d8khn", - "jailed": false, - "status": 2, - "tokens": "447018398440", - "delegator_shares": "447018398440.000000000000000000", - "description": { - "moniker": "Bison Trails", - "identity": "A296556FF603197C", - "website": "bisontrails.co", - "details": "Bison Trails is the easiest way to run infrastructure on multiple blockchains." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.080000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-10-30T20:21:03.030621767Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1cgh5ksjwy2sd407lyre4l3uj2fdrqhpkzp06e6", - "consensus_pubkey": "cosmosvalconspub1zcjduepq3f6wnsk6k6qu6g8n5vly4z7ajw7q930wh3qx6zkxhktnh49l40kszf5lry", - "jailed": false, - "status": 2, - "tokens": "932859245807", - "delegator_shares": "932859245807.000000000000000000", - "description": { - "moniker": "HashQuark", - "identity": "31AFBBE0A52FA1ED", - "website": "https://www.hashquark.io", - "details": "Staking made easier!" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-10-23T02:48:39.22540691Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1clpqr4nrk4khgkxj78fcwwh6dl3uw4epsluffn", - "consensus_pubkey": "cosmosvalconspub1zcjduepq0dc9apn3pz2x2qyujcnl2heqq4aceput2uaucuvhrjts75q0rv5smjjn7v", - "jailed": false, - "status": 2, - "tokens": "6103920214139", - "delegator_shares": "6103920214139.000000000000000000", - "description": { - "moniker": "Cosmostation", - "identity": "AE4C403A6E7AA1AC", - "website": "https://www.cosmostation.io", - "details": "CØSMOSTATION Validator. Delegate your atoms and Start Earning Staking Rewards" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.120000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "10" - }, - { - "operator_address": "cosmosvaloper1ey69r37gfxvxg62sh4r0ktpuc46pzjrm873ae8", - "consensus_pubkey": "cosmosvalconspub1zcjduepqg6y8magedjwr9p6s2c28zp28jdjtecxhn97ew6tnuzqklg63zgfspp9y3n", - "jailed": false, - "status": 2, - "tokens": "10361463918660", - "delegator_shares": "10361463917414.465324179280152398", - "description": { - "moniker": "Sikka", - "identity": "https://keybase.io/team/sikka", - "website": "sikka.tech", - "details": "Sunny Aggarwal (@sunnya97) and Dev Ojha (@ValarDragon)" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.030000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-11-01T04:08:08.548659287Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1e859xaue4k2jzqw20cv6l7p3tmc378pc3k8g2u", - "consensus_pubkey": "cosmosvalconspub1zcjduepql9gmstvlcyxpa7ndyl08y694xxc8r03e8nn0zfvl3x255ev6q7rq9hevuz", - "jailed": false, - "status": 2, - "tokens": "2164966230", - "delegator_shares": "2164966230.000000000000000000", - "description": { - "moniker": "#fuckgoogle", - "identity": "", - "website": "https://github.com/cybercongress", - "details": "" - }, - "unbonding_height": "1357109", - "unbonding_time": "2020-04-22T09:09:26.8630982Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-12T12:34:44.598269429Z" - }, - "min_self_delegation": "10" - }, - { - "operator_address": "cosmosvaloper1et77usu8q2hargvyusl4qzryev8x8t9wwqkxfs", - "consensus_pubkey": "cosmosvalconspub1zcjduepqfx0p8s3gmxmaftkkazw5wag4sfau3vgcn20ut4dn5rv2nr8ddq2s59rnvq", - "jailed": false, - "status": 2, - "tokens": "6938017012", - "delegator_shares": "6938017012.000000000000000000", - "description": { - "moniker": "👾replicator.network", - "identity": "9203983F91296B66", - "website": "https://replicator.network", - "details": "" - }, - "unbonding_height": "8201", - "unbonding_time": "2020-01-02T08:27:54.43078638Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-12-12T04:01:41.501864578Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1e0plfg475phrsvrlzw8gwppeva0zk5yg9fgg8c", - "consensus_pubkey": "cosmosvalconspub1zcjduepqz83dmnt4g6w0w6syrf433mwpk86zejxnq6e336xtxd8pg9jtxkgq732tpu", - "jailed": false, - "status": 2, - "tokens": "331202100073", - "delegator_shares": "331202100073.000000000000000000", - "description": { - "moniker": "Easy 2 Stake", - "identity": "2C877AC873132C91", - "website": "www.easy2stake.com", - "details": "Easy.Stake.Trust. as easy and as simple as you would click next. Complete transparency and trust with a secure and stable validator. GoS winner, Never Jailed Crew" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-09-27T08:35:53.771679331Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1e0jnq2sun3dzjh8p2xq95kk0expwmd7sj6x59m", - "consensus_pubkey": "cosmosvalconspub1zcjduepqfndze9l7th79g0m4fguf5cueksmywl6sw2xhuz7gp6jatr39ffuqn3exk9", - "jailed": false, - "status": 2, - "tokens": "116267146692", - "delegator_shares": "116267146692.000000000000000000", - "description": { - "moniker": "Fission Labs", - "identity": "7DAC30FBD99879B0", - "website": "https://fissionlabs.io/", - "details": "Fission Labs - Blockchain infrastructure and development services" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-10-27T15:17:00.635446897Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fz4sdg3", - "consensus_pubkey": "cosmosvalconspub1zcjduepq8hu49qdl5594rzxmdsww3hleu8phxrajjfsseqjere9mjrrrv9tq35mll4", - "jailed": false, - "status": 2, - "tokens": "2135806970012", - "delegator_shares": "2135806970012.000000000000000000", - "description": { - "moniker": "BouBouNode", - "identity": "", - "website": "https://boubounode.com", - "details": "AI-based Validator. #1 AI Validator on Game of Stakes. Fairly priced. Don't trust (humans), verify. Made with BouBou love." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.061000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1ehkfl7palwrh6w2hhr2yfrgrq8jetgucudztfe", - "consensus_pubkey": "cosmosvalconspub1zcjduepqvmmhug9hcmm26ce7we0n3esavn4c6tfcfd6zgnuj732ls7khjq4srpg0ft", - "jailed": false, - "status": 2, - "tokens": "1138068194456", - "delegator_shares": "1138068194456.000000000000000000", - "description": { - "moniker": "KalpaTech", - "identity": "B4AD06F0EB355573", - "website": "http://kalpatech.co", - "details": "KalpaTech | Genesis Validator | Game of Stakes winner | Services dedicated exclusively for Cosmos Hub | All resources put in one network" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-28T22:00:22.763748595Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1ec3p6a75mqwkv33zt543n6cnxqwun37rr5xlqv", - "consensus_pubkey": "cosmosvalconspub1zcjduepqd85nu5nelvcyyzcsrr0yaglh8rfvn6cv9pp3p0hgmwtk8hf3cazqc7vz5c", - "jailed": false, - "status": 2, - "tokens": "1049353149259", - "delegator_shares": "1049353149259.000000000000000000", - "description": { - "moniker": "lunamint", - "identity": "4F26823468DD7518", - "website": "https://lunamint.com", - "details": "Always adding value to Cosmos. Check out Lunagram, the Cosmos wallet built into Telegram." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1emaa7mwgpnpmc7yptm728ytp9quamsvu837nc0", - "consensus_pubkey": "cosmosvalconspub1zcjduepqfuxvufupnsm7v5anpwd7z8ec70z2k209j7xclnm25zz7vauhyc5qjgxx3h", - "jailed": false, - "status": 2, - "tokens": "525602853385", - "delegator_shares": "525602853385.000000000000000000", - "description": { - "moniker": "kochacolaj", - "identity": "1E9CE94FD0BA5CFEB901F90BC658D64D85B134D2", - "website": "https://blog.cosmos.network/game-of-stakes-closing-ceremonies-eddb71d3b114#147d", - "details": "Top 5 Game Of Stakes winner" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2020-02-29T17:40:11.439163513Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1eup5t8pp8jq354heck53qtama7vss9l354kh6r", - "consensus_pubkey": "cosmosvalconspub1zcjduepqxh4s2zj52uhfssu7u2xyhmnk5f7g9ty368twxkkcfllsq3fqaw9sdl6rj9", - "jailed": false, - "status": 2, - "tokens": "8452580358", - "delegator_shares": "8452580358.000000000000000000", - "description": { - "moniker": "IZ0", - "identity": "BF964D76855711CC", - "website": "www.izo.ro", - "details": "Izo Data Network ! Commission is 0% . Please join our [community](https://t.me/IzoData) or visit [website](https://www.izo.ro/)! " - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.100000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-12-26T08:56:10.399933806Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper16qme5yxucnaj6snx35nmwze0wyxr8wfgqxsqfw", - "consensus_pubkey": "cosmosvalconspub1zcjduepqwnhw3azrlhnx9kaujvn0es9u26e4a3af6hye6e9j0pl2tlpx9k3s59zwh0", - "jailed": false, - "status": 2, - "tokens": "260865453794", - "delegator_shares": "260865453794.000000000000000000", - "description": { - "moniker": "KIRA Staking", - "identity": "C86C8FF08A5269DC", - "website": "https://kiraex.com", - "details": "Kira Core Staking Services - Sentry, KMS, HSM, High Availability \u0026 Double Sign Protection" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.010000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2020-04-01T21:07:55.105865438Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper16v3f95amtvpewuajjcdsvaekuuy4yyzups85ec", - "consensus_pubkey": "cosmosvalconspub1zcjduepqmgwzcm3aqmc8nln9u4q5ydsjwx6rzqrch6p243x2gtzetnx5l3ls432euv", - "jailed": false, - "status": 2, - "tokens": "147885388389", - "delegator_shares": "147885388389.000000000000000000", - "description": { - "moniker": "BlockPool", - "identity": "", - "website": "www.blockpool.com", - "details": "Power the staking economy" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.020000000000000000", - "max_rate": "0.030000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-06-22T05:19:17.897735561Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1648ynlpdw7fqa2axt0w2yp3fk542junl7rsvq6", - "consensus_pubkey": "cosmosvalconspub1zcjduepqf8llkc4p43lksktsqzr5nmgmw4ln9pzym2vp4kqfrny8xrgnqrsq76djjc", - "jailed": false, - "status": 2, - "tokens": "797707710682", - "delegator_shares": "797787489383.461009934458905148", - "description": { - "moniker": "Any Labs", - "identity": "B2D07CA3CCC907CE", - "website": "https://anylabs.io", - "details": "Blockchain staking and consultancy based in Japan." - }, - "unbonding_height": "25880", - "unbonding_time": "2020-01-03T18:48:44.276425288Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-05-08T11:30:02.004384504Z" - }, - "min_self_delegation": "100" - }, - { - "operator_address": "cosmosvaloper16k579jk6yt2cwmqx9dz5xvq9fug2tekvlu9qdv", - "consensus_pubkey": "cosmosvalconspub1zcjduepq55mjplg9gy979ua9r5qmk2wr5nysmputt28j0zsgadn933lyh32sh20cmm", - "jailed": false, - "status": 2, - "tokens": "928458345391", - "delegator_shares": "928551200492.966284028096640587", - "description": { - "moniker": "Cephalopod Equipment", - "identity": "6408AA029ADBE364", - "website": "https://cephalopod.equipment", - "details": "Cephalopod Equipment - infrastructure for decentralized intelligence" - }, - "unbonding_height": "0", - "unbonding_time": "2019-12-01T09:34:39.548038382Z", - "commission": { - "commission_rates": { - "rate": "0.081100000000000000", - "max_rate": "0.420000000000000000", - "max_change_rate": "0.011800000000000000" - }, - "update_time": "2019-09-19T12:26:43.48042061Z" - }, - "min_self_delegation": "100000" - }, - { - "operator_address": "cosmosvaloper1mykn77lkynl8fkwvl9tqg369u0zajzzcdhkptq", - "consensus_pubkey": "cosmosvalconspub1zcjduepqft6uxfmfjjce0p7ke4h0zc38x4d9d38wlmrgcc47flru92qq3ydq76mrsf", - "jailed": false, - "status": 2, - "tokens": "89943764382", - "delegator_shares": "89943764382.000000000000000000", - "description": { - "moniker": "Nodeasy.com", - "identity": "AB006A79DBD8FC57", - "website": "https://www.nodeasy.com", - "details": "Nodeasy.com,助你进入Staking时代!" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-10-28T13:02:55.182998044Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1m83cwjucw9nt8xm66u8xavvy6v9m7xfspcszc5", - "consensus_pubkey": "cosmosvalconspub1zcjduepq7qnf5r40z7esjc2utrjrvzxg9sfd683hw0805ek85ddchdcptthqjnzxxu", - "jailed": false, - "status": 2, - "tokens": "159214462425", - "delegator_shares": "159214462425.000000000000000000", - "description": { - "moniker": "Fenbushi US - Staked", - "identity": "CC4B238C8F9FB2BE", - "website": "https://fenbushi.vc", - "details": "Fenbushi Capital is the first and most active blockchain-focused venture capital firm in Asia. Staked is the leading provider of validation technology and services. We're bringing our combined skills to Cosmos." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T18:07:08.897219336Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1ma02nlc7lchu7caufyrrqt4r6v2mpsj90y9wzd", - "consensus_pubkey": "cosmosvalconspub1zcjduepqxtu8am2qmf0qnglqtvkar9gaclhccfn29tsp7n82vasrtnc8m2fsulp4h2", - "jailed": false, - "status": 2, - "tokens": "3464569661466", - "delegator_shares": "3464569661466.000000000000000000", - "description": { - "moniker": "hashtower", - "identity": "0BBBAE1FD11AEBAF", - "website": "http://hashtower.com", - "details": "Hashtower Actwo COSMOS Validator" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.030000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.200000000000000000" - }, - "update_time": "2019-07-16T08:46:06.560077744Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1uxh465053nq3at4dn0jywgwq3s9sme3la3drx6", - "consensus_pubkey": "cosmosvalconspub1zcjduepqc5y2du793cjut0cn6v7thp3xlvphggk6rt2dhw9ekjla5wtkm7nstmv5vy", - "jailed": false, - "status": 2, - "tokens": "520672159921", - "delegator_shares": "520672159921.000000000000000000", - "description": { - "moniker": "Bison Trails", - "identity": "A296556FF603197C", - "website": "https://bisontrails.co", - "details": "Bison Trails is the easiest way to run infrastructure on multiple blockchains." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1udpsgkgyutgsglauk9vk9rs03a3skc62gup9ny", - "consensus_pubkey": "cosmosvalconspub1zcjduepq38tmpw8wujah8nhvkkd26tskx4p7l0qx2kqwfkp3hj8644e9kevqxe5zl2", - "jailed": false, - "status": 2, - "tokens": "5000000000", - "delegator_shares": "5000000000.000000000000000000", - "description": { - "moniker": "TEST_NODE", - "identity": "", - "website": "", - "details": "Test Node." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.075000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-30T11:04:05.791970925Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1uhnsxv6m83jj3328mhrql7yax3nge5svrv6t6c", - "consensus_pubkey": "cosmosvalconspub1zcjduepql42t7mstnewp5rgweteuw95hawzystll7mq8dl24n5yh0th7q2jqetcy07", - "jailed": false, - "status": 2, - "tokens": "720793765456", - "delegator_shares": "720865851960.598464555143928151", - "description": { - "moniker": "Skystar Capital", - "identity": "", - "website": "", - "details": "" - }, - "unbonding_height": "1168707", - "unbonding_time": "2020-04-06T17:50:47.447745873Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1u6ddcsjueax884l3tfrs66497c7g86skn7pa0u", - "consensus_pubkey": "cosmosvalconspub1zcjduepq87zcnf8sm4ewacjafqujfevt8rhwj5qk9uwtx4ef89ctuqmndkeq446ahw", - "jailed": false, - "status": 2, - "tokens": "809489002763", - "delegator_shares": "809489002763.000000000000000000", - "description": { - "moniker": "Sentinel", - "identity": "D54C8032CF19C407", - "website": "https://sentinel.co", - "details": "We are team Sentinel, developer of infrastructure tools on Cosmos \u0026 other networks.Winner in the Uptime category during GOS.Developed the first working version of the dVPN which runs on Ethereum \u0026 Sentinel's own Tendermint TestNet" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1000000" - }, - { - "operator_address": "cosmosvaloper1uutuwrwt3z2a5z8z3uasml3rftlpmu25aga5c6", - "consensus_pubkey": "cosmosvalconspub1zcjduepqarrl0ppddzyczwvcqwf3jwd9qwkhxfy6lcv8ep4msk293mlxg39qgf77y3", - "jailed": false, - "status": 2, - "tokens": "894288539493", - "delegator_shares": "894288539493.000000000000000000", - "description": { - "moniker": "Delega Networks♾ ", - "identity": "1BED7C08416A619F", - "website": "https://delega.io", - "details": "Nodes managed by wimel" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.180000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-04-05T00:45:01.073794845Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1ul2me6vukg2vac2p6ltxmqlaa7jywdgt8q76ag", - "consensus_pubkey": "cosmosvalconspub1zcjduepq0cet8ez89wj4yz8uencych7aldc5wyyrpx6jvh6n6kxxslumln5sxkq922", - "jailed": false, - "status": 2, - "tokens": "1208359862997", - "delegator_shares": "1208359862997.000000000000000000", - "description": { - "moniker": "HyperblocksPro", - "identity": "B073FA5BAD230585", - "website": "https://hyperblocks.pro/", - "details": "Secure the network and earn rewards with Hyperblocks.pro, one of the first companies in the world fully focused on Proof Of Stake protocols" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-04-05T23:57:19.320271237Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1a3yjj7d3qnx4spgvjcwjq9cw9snrrrhu5h6jll", - "consensus_pubkey": "cosmosvalconspub1zcjduepqxjkll4nxla8gtekx2ueq3tc8vv4e6rn79jmdead30jeqlm3kc7eqqx7hs8", - "jailed": false, - "status": 2, - "tokens": "10041185315", - "delegator_shares": "10041185315.000000000000000000", - "description": { - "moniker": "Coinbase Custody", - "identity": "Coinbase Custody", - "website": "https://custody.coinbase.com", - "details": "Coinbase Custody Cosmos Validator" - }, - "unbonding_height": "676534", - "unbonding_time": "2020-02-26T01:41:46.759697123Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2020-02-05T00:29:51.081896503Z" - }, - "min_self_delegation": "1000000" - }, - { - "operator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", - "consensus_pubkey": "cosmosvalconspub1zcjduepqc9ppxzktam9v39d9q07h6n98cdm7cgg4l65vq5yvtgruxp5h0yhs8tup68", - "jailed": false, - "status": 2, - "tokens": "202801407477", - "delegator_shares": "202801407477.000000000000000000", - "description": { - "moniker": "FRESHATOMS", - "identity": "63575EE3F0F9FAFC", - "website": "https://freshatoms.com", - "details": "FreshAtoms runs on bare metal in a SSAE16 SOC2 certified Tier 3 datacenter with geographically distributed private sentry nodes, YubiHSM2 hardware protected keys, with 24/7 monitoring, alerting, and analytics." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-09-23T20:29:05.781322875Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper17mggn4znyeyg25wd7498qxl7r2jhgue8u4qjcq", - "consensus_pubkey": "cosmosvalconspub1zcjduepqlzmd0spn9m0m3eq9zp93d4w6e5tugamv44yqjzyacelnvra634fqnfec0r", - "jailed": false, - "status": 2, - "tokens": "1079608204356", - "delegator_shares": "1079608204356.000000000000000000", - "description": { - "moniker": "01node", - "identity": "22823CD59617B8E3", - "website": "https://01node.com", - "details": "01node Professional Staking Services for Cosmos, Iris, Terra, Solana, Kava, Polkadot, Skale" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-03-13T23:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1l9fwl9c77zx850htsr20pq3ltc379xt86ndelm", - "consensus_pubkey": "cosmosvalconspub1zcjduepqfjgjrj4heptaw6h9nhtkng8hw2zsq5c6e9xzwvnjjx2n6pc7x6yq4ny2qc", - "jailed": false, - "status": 2, - "tokens": "5057317038", - "delegator_shares": "5057317038.000000000000000000", - "description": { - "moniker": "CosmosLink", - "identity": "3F7807C66CE770B0", - "website": "cosmoslink.network", - "details": "Based on Cosmos network digital asset security value-added service provider" - }, - "unbonding_height": "1276519", - "unbonding_time": "2020-04-15T17:26:54.325724353Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-18T16:46:59.079404223Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1lktjhnzkpkz3ehrg8psvmwhafg56kfss3q3t8m", - "consensus_pubkey": "cosmosvalconspub1zcjduepqelcwpat987h9yq0ck6g9fsc8t0mththk547gwvk0w4wnkpl0stnspr3hdc", - "jailed": false, - "status": 2, - "tokens": "1720474496626", - "delegator_shares": "1720474496626.000000000000000000", - "description": { - "moniker": "Umbrella ☔", - "identity": "A530AC4D75991FE2", - "website": "https://umbrellavalidator.com", - "details": "One of the winners of Cosmos Game of Stakes, and HackAtom3." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.070400000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-08-05T07:10:23.689753607Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1lcwxu50rvvgf9v6jy6q5mrzyhlszwtjxhtscmp", - "consensus_pubkey": "cosmosvalconspub1zcjduepqh3jg5ld5xg5q5mcxrzn6fcuq696qqa3ut3azskphpdrty37ervjqcn8mfj", - "jailed": false, - "status": 2, - "tokens": "9713509339", - "delegator_shares": "9713509339.000000000000000000", - "description": { - "moniker": "stake.zone", - "identity": "0A888728046018EC", - "website": "http://stake.zone", - "details": "operated by nuevax" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2020-02-13T02:20:41.320594366Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1l6udzyaz8xaxv4hpagwauacm95jlcec3xlht2u", - "consensus_pubkey": "cosmosvalconspub1zcjduepq9t4r8jgr09rsscgacnaklxuf55pg0wq5zfwzw8ycawms5x0hrfhqks3dpe", - "jailed": false, - "status": 2, - "tokens": "10802365900", - "delegator_shares": "10802365900.000000000000000000", - "description": { - "moniker": "StakeHouse", - "identity": "A1AAB1D6D0E8F976", - "website": "stakehouse.org", - "details": "Low fees. No hassle. Enjoy your meal." - }, - "unbonding_height": "701066", - "unbonding_time": "2020-02-28T02:04:00.114690756Z", - "commission": { - "commission_rates": { - "rate": "0.010000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-02-11T07:24:35.723449554Z" - }, - "min_self_delegation": "1" - } - ] - } - `); - } - } - - return {error: "Not implemented"}; - } -}; - diff --git a/mock/ext-api-dyson/get/cosmos-api-commands4.js b/mock/ext-api-dyson/get/cosmos-api-commands4.js deleted file mode 100644 index f59cea546..000000000 --- a/mock/ext-api-dyson/get/cosmos-api-commands4.js +++ /dev/null @@ -1,42 +0,0 @@ -/// Cosmos API Mock -/// See: -/// curl "http://localhost:3347/cosmos-api/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/delegations" -/// curl "https://{cosmos_rpc}/staking/delegators/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq/delegations" -/// curl "http://localhost:8437/v2/cosmos/staking/delegations/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq?Authorization=Bearer" - -module.exports = { - path: "/cosmos-api/:command1/:command2/:arg3/:arg4?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch(params.command1) { - case 'staking': - switch(params.command2) { - case 'delegators': - switch (params.arg3) { - case 'cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq': - switch (params.arg4) { - case 'delegations': - case 'unbonding_delegations': - return JSON.parse(` - { - "height": "1419065", - "result": [ - { - "delegator_address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", - "validator_address": "cosmosvaloper17h2x3j7u44qkrq0sk8ul0r2qr440rwgjkfg0gh", - "shares": "2211271.000000000000000000", - "balance": "2211271" - } - ] - } - `); - } - } - } - } - - return {error: "Not implemented"}; - } -}; - diff --git a/mock/ext-api-dyson/get/dash-api-address.js b/mock/ext-api-dyson/get/dash-api-address.js deleted file mode 100644 index 68f5bb930..000000000 --- a/mock/ext-api-dyson/get/dash-api-address.js +++ /dev/null @@ -1,112 +0,0 @@ -/// Mock for external Dash API -/// See: -/// curl "http://{dash rpc}/api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" -/// curl "http://localhost:3347/dash-api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs" -/// curl "http://localhost:8437/v1/dash/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" - -module.exports = { - path: '/dash-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 'XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG': - return JSON.parse(` - { - "page": 1, - "totalPages": 333, - "itemsOnPage": 2, - "address": "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG", - "balance": "24107591472", - "totalReceived": "137513751052", - "totalSent": "113406159580", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 665, - "transactions": [ - { - "txid": "8a1859bb849e207b7771c0301a6109a039eec955234b7848715b150f20fabeca", - "version": 3, - "vin": [ - { - "sequence": 4294967295, - "n": 0, - "isAddress": false, - "coinbase": "035c33131a4d696e656420627920416e74506f6f6c347c000b02203c94a613416a0000be010000" - } - ], - "vout": [ - { - "value": "155331342", - "n": 0, - "hex": "76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac", - "addresses": [ - "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" - ], - "isAddress": true - }, - { - "value": "155331350", - "n": 1, - "hex": "76a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac", - "addresses": [ - "Xb8cmjtK67y9T2haqrcDicoAMByDesLcAe" - ], - "isAddress": true - } - ], - "blockHash": "000000000000000f2a4362c05fd3aeca12640061c9c119862cf20b2cc95560a8", - "blockHeight": 1258332, - "confirmations": 1181, - "blockTime": 1587515977, - "value": "310662692", - "valueIn": "0", - "fees": "0", - "hex": "03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff27035c33131a4d696e656420627920416e74506f6f6c347c000b02203c94a613416a0000be010000ffffffff020e2b4209000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac162b4209000000001976a91404dfe99f6dda028e4e6a90595096e63787a4a01c88ac000000004602005c3313008c104ddcb4ef489cb517b4ae6aeec851ab8010748b00d20c7bb10b2a86c9ed6478777117ab77017feac02c03ef31f19a0ddfa3e1039f8d364a79cb22052233e3" - }, - { - "txid": "bc017866f1eb2118c59d3c7b6127b96ecce595062abc626f468345782f0bba9f", - "version": 3, - "vin": [ - { - "sequence": 4294967295, - "n": 0, - "isAddress": false, - "coinbase": "03033313042c599f5e0100048e1c1d000000000000" - } - ], - "vout": [ - { - "value": "155462330", - "n": 0, - "hex": "76a914aeb4b16eb331e7be66082f1dc132ef245e722d7188ac", - "addresses": [ - "XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG" - ], - "isAddress": true - }, - { - "value": "155462346", - "n": 1, - "spent": true, - "hex": "76a91417158751f496276811c148495b28915314dd9fc088ac", - "addresses": [ - "XcnuAVsG4pRCqxQmQB6PeTX8FJo2ssYPyB" - ], - "isAddress": true - } - ], - "blockHash": "000000000000001c141317365929a3d7937f21be525873142bdaebbdcebe7a1d", - "blockHeight": 1258243, - "confirmations": 1270, - "blockTime": 1587501361, - "value": "310924676", - "valueIn": "0", - "fees": "0", - "hex": "03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff1503033313042c599f5e0100048e1c1d000000000000ffffffff02ba2a4409000000001976a914aeb4b16eb331e7be66082f1dc132ef245e722d7188acca2a4409000000001976a91417158751f496276811c148495b28915314dd9fc088ac000000004602000333130024b54c2354b15fb05d02604e811682ea82b3e81abf3610a4019a9fde7963be6ef022b80b9ef1524c1629323e53296cebee22b80dde230ed8eaee578d5a0f4457" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/dash-api-xpub.js b/mock/ext-api-dyson/get/dash-api-xpub.js deleted file mode 100644 index 300246007..000000000 --- a/mock/ext-api-dyson/get/dash-api-xpub.js +++ /dev/null @@ -1,175 +0,0 @@ -/// Mock for external Dash API -/// See: -/// curl "http://{dash rpc}/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs" -/// curl "http://localhost:3347/dash-api/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs" -/// curl "http://localhost:8437/v1/dash/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD" - -module.exports = { - path: '/dash-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD", - "balance": "2597761", - "totalReceived": "27175423", - "totalSent": "24577662", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 52, - "transactions": [ - { - "txid": "2b67e2fbe6a212286243bc539cca3c1d877e85ffec7c925e34f2bfb7b6cc498c", - "version": 1, - "vin": [ - { - "txid": "227f1995f5d0b0adcd4f014159710892fa4b66a02ff7ad1e0fc4c1b84ca27cb2", - "n": 0, - "addresses": [ - "XyPpEePUKruNEVgdp5jWSakfvoQTnkZxhL" - ], - "isAddress": true, - "value": "34508", - "hex": "483045022100bebce18899214200115fbb2e3b16cd7a6b61cca2cf3e1ffc3b26872f66b714f702203316ce9f1cfb7cef751dbba46015ea76d3c409d6b913b6e434553ebe66680713012103f556051304c43ef031a17615fd8b056c1ac7b0a50926137bf918e72be002f606" - } - ], - "vout": [ - { - "value": "10000", - "n": 0, - "hex": "76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac", - "addresses": [ - "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" - ], - "isAddress": true - }, - { - "value": "18858", - "n": 1, - "hex": "76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac", - "addresses": [ - "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" - ], - "isAddress": true - } - ], - "blockHash": "000000000000000b3e9287157ae29c1c19bbd1e65660a5bbe723261d0fc57737", - "blockHeight": 1226578, - "confirmations": 16630, - "blockTime": 1582509671, - "value": "28858", - "valueIn": "34508", - "fees": "5650", - "hex": "0100000001b27ca24cb8c1c40f1eadf72fa0664bfa9208715941014fcdadb0d0f595197f22000000006b483045022100bebce18899214200115fbb2e3b16cd7a6b61cca2cf3e1ffc3b26872f66b714f702203316ce9f1cfb7cef751dbba46015ea76d3c409d6b913b6e434553ebe66680713012103f556051304c43ef031a17615fd8b056c1ac7b0a50926137bf918e72be002f606000000000210270000000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88acaa490000000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac00000000" - }, - { - "txid": "dc8e1219da91a24c2eca773a6853d7a0602eed509a4b71afd553f8b4c218b309", - "version": 1, - "vin": [ - { - "txid": "501c3c7ecaae272de760e81d284e44644a0475c42e3ee15ae16a125650211c8e", - "vout": 1, - "n": 0, - "addresses": [ - "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" - ], - "isAddress": true, - "value": "768334", - "hex": "483045022100805ae010fb81b3659f687d1f9da9efa27fa220d34c0f9c54dde4f8e8358e7c2e022003c2c89eb0372616ad50b74f627097e3ccf2ecd940bad616b0bf7caaab58615c01210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600" - }, - { - "txid": "501c3c7ecaae272de760e81d284e44644a0475c42e3ee15ae16a125650211c8e", - "n": 1, - "addresses": [ - "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" - ], - "isAddress": true, - "value": "809686", - "hex": "483045022100ff644abb86e4272384e64de00d7ac2b1ed01e6848f59707f1bd93913b0f2ceeb02205ba0be94a02a2af3d7178977d828dda4268da4f83c00d2af1331e4274a5454a201210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600" - } - ], - "vout": [ - { - "value": "1000000", - "n": 0, - "hex": "76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac", - "addresses": [ - "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" - ], - "isAddress": true - }, - { - "value": "576150", - "n": 1, - "hex": "76a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac", - "addresses": [ - "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq" - ], - "isAddress": true - } - ], - "blockHash": "000000000000000f727266a1a157af489fec0a009938dadeca89bc3edd1bc017", - "blockHeight": 1215128, - "confirmations": 28080, - "blockTime": 1580704472, - "value": "1576150", - "valueIn": "1578020", - "fees": "1870", - "hex": "01000000028e1c215056126ae15ae13e2ec475044a64444e281de860e72d27aeca7e3c1c50010000006b483045022100805ae010fb81b3659f687d1f9da9efa27fa220d34c0f9c54dde4f8e8358e7c2e022003c2c89eb0372616ad50b74f627097e3ccf2ecd940bad616b0bf7caaab58615c01210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600000000008e1c215056126ae15ae13e2ec475044a64444e281de860e72d27aeca7e3c1c50000000006b483045022100ff644abb86e4272384e64de00d7ac2b1ed01e6848f59707f1bd93913b0f2ceeb02205ba0be94a02a2af3d7178977d828dda4268da4f83c00d2af1331e4274a5454a201210359d6639a8c603a3ecf0384373935c90a93477668c148929be3b5752fcdf64600000000000240420f00000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac96ca0800000000001976a9149b80787d880fd9f6a822fad78037c9563790a6fa88ac00000000" - } - ], - "usedTokens": 47, - "tokens": [ - { - "type": "XPUBAddress", - "name": "Xps4UHWgH1Ge9HAJijuJMA1i6Ybhq8JNkq", - "path": "m/44'/5'/0'/0/0", - "transfers": 13, - "decimals": 8, - "balance": "2543095", - "totalReceived": "4275043", - "totalSent": "1731948" - }, - { - "type": "XPUBAddress", - "name": "XezMSYZ3ucD2tNGVME1j3A8tM5q3NvigKu", - "path": "m/44'/5'/0'/0/15", - "transfers": 1, - "decimals": 8, - "balance": "10000", - "totalReceived": "10000", - "totalSent": "0" - }, - { - "type": "XPUBAddress", - "name": "XmM5KX1Zpepji5V6RF7iypCkXBi4hSronS", - "path": "m/44'/5'/0'/0/18", - "transfers": 1, - "decimals": 8, - "balance": "10000", - "totalReceived": "10000", - "totalSent": "0" - }, - { - "type": "XPUBAddress", - "name": "XcLBw1EUz5HPDJ5pZrSbeyXYBWcVCabZ56", - "path": "m/44'/5'/0'/1/24", - "transfers": 1, - "decimals": 8, - "balance": "34666", - "totalReceived": "34666", - "totalSent": "0" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/decred-api-address.js b/mock/ext-api-dyson/get/decred-api-address.js deleted file mode 100644 index 92301c2fb..000000000 --- a/mock/ext-api-dyson/get/decred-api-address.js +++ /dev/null @@ -1,120 +0,0 @@ -/// Mock for external Decred API -/// See: -/// curl "http://{decred rpc}/api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" -/// curl "http://localhost:3347/decred-api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs" -/// curl "http://localhost:8437/v1/decred/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" - -module.exports = { - path: '/decred-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 'DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY': - return JSON.parse(` - { - "page": 1, - "totalPages": 5, - "itemsOnPage": 2, - "address": "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", - "balance": "19473147", - "totalReceived": "74960270", - "totalSent": "55487123", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 10, - "transactions": [ - { - "txid": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0", - "version": 1, - "vin": [ - { - "txid": "2dc905f525885537310c8ab87f67dc175ca369af1fe7111a49a94451866aa019", - "sequence": 4294967291, - "n": 0, - "addresses": [ - "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" - ], - "isAddress": true, - "value": "591955", - "hex": "473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" - } - ], - "vout": [ - { - "value": "100000", - "n": 0, - "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", - "addresses": [ - "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" - ], - "isAddress": true - }, - { - "value": "489415", - "n": 1, - "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", - "addresses": [ - "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" - ], - "isAddress": true - } - ], - "blockHash": "00000000000000000c12cb497e60470a3cf366d16705eaba303c2c4415cc7567", - "blockHeight": 429609, - "confirmations": 13942, - "blockTime": 1583516573, - "value": "589415", - "valueIn": "591955", - "fees": "2540", - "hex": "010000000119a06a865144a9491a11e71faf69a35c17dc677fb88a0c3137558825f505c92d0000000000fbffffff02a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acc77707000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac0000000000000000015308090000000000dbcc05000b0000006a473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" - }, - { - "txid": "025abf340da79c4fc4de29667c08fc22cdafbded24c7c2a994a27f6fb4d5fa17", - "version": 1, - "vin": [ - { - "txid": "5a2a0d01ed8672d6bebd7dee447b2e0342bfc34fd4893bed58a4fa5aa87a4c42", - "n": 0, - "addresses": [ - "Dsf6WkLoiTcSGKmkXoSEdukqUfeRJMqUNJV" - ], - "isAddress": true, - "value": "19991980", - "hex": "483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" - } - ], - "vout": [ - { - "value": "100000", - "n": 0, - "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", - "addresses": [ - "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" - ], - "isAddress": true - }, - { - "value": "19889440", - "n": 1, - "hex": "76a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac", - "addresses": [ - "Dsesp1V6DZDEtcq2behmBVKdYqKMdkh96hL" - ], - "isAddress": true - } - ], - "blockHash": "0000000000000000264c499f21a7ef95bffb37148fc099514b2407dfa28c3287", - "blockHeight": 429186, - "confirmations": 14365, - "blockTime": 1583384838, - "value": "19989440", - "valueIn": "19991980", - "fees": "2540", - "hex": "0100000001424c7aa85afaa458ed3b89d44fc3bf42032e7b44ee7dbdbed67286ed010d2a5a00000000000000000002a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac207d2f010000000000001976a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac000000000000000001ac0d31010000000052630600050000006b483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/decred-api-xpub.js b/mock/ext-api-dyson/get/decred-api-xpub.js deleted file mode 100644 index 399cdf7cd..000000000 --- a/mock/ext-api-dyson/get/decred-api-xpub.js +++ /dev/null @@ -1,122 +0,0 @@ -/// Mock for external Decred API -/// See: -/// curl "http://{decred rpc}v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs" -/// curl "http://localhost:3347/decred-api/v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs" -/// curl "http://localhost:8437/v1/decred/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN" - -module.exports = { - path: '/decred-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN", - "balance": "19617042", - "totalReceived": "376432293", - "totalSent": "356815251", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 28, - "transactions": [ - { - "txid": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0", - "version": 1, - "vin": [ - { - "txid": "2dc905f525885537310c8ab87f67dc175ca369af1fe7111a49a94451866aa019", - "sequence": 4294967291, - "n": 0, - "addresses": [ - "Dsjr1AbSRiZaN9PkCGaNyjfAVkbcPLozafq" - ], - "isAddress": true, - "value": "591955", - "hex": "473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" - } - ], - "vout": [ - { - "value": "100000", - "n": 0, - "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", - "addresses": [ - "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" - ], - "isAddress": true - }, - { - "value": "489415", - "n": 1, - "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", - "addresses": [ - "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" - ], - "isAddress": true - } - ], - "blockHash": "00000000000000000c12cb497e60470a3cf366d16705eaba303c2c4415cc7567", - "blockHeight": 429609, - "confirmations": 5412, - "blockTime": 1583516573, - "value": "589415", - "valueIn": "591955", - "fees": "2540", - "hex": "010000000119a06a865144a9491a11e71faf69a35c17dc677fb88a0c3137558825f505c92d0000000000fbffffff02a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888acc77707000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac0000000000000000015308090000000000dbcc05000b0000006a473044022045cb71f2c6c446a69cdf77cc7beedf6f4616091a7fc4843ef74757475f5a95c402203609e095561a11e0ac32f51de870a597b39dce4596b5b253842c838b7c4c9953012102eefcb948122fad71682df1ed8c59a9852afeffea086650e3a86e8a1214c0a94f" - }, - { - "txid": "025abf340da79c4fc4de29667c08fc22cdafbded24c7c2a994a27f6fb4d5fa17", - "version": 1, - "vin": [ - { - "txid": "5a2a0d01ed8672d6bebd7dee447b2e0342bfc34fd4893bed58a4fa5aa87a4c42", - "n": 0, - "addresses": [ - "Dsf6WkLoiTcSGKmkXoSEdukqUfeRJMqUNJV" - ], - "isAddress": true, - "value": "19991980", - "hex": "483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" - } - ], - "vout": [ - { - "value": "100000", - "n": 0, - "hex": "76a91420cf523034c462f8e09fc0fd35c47760b822398888ac", - "addresses": [ - "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY" - ], - "isAddress": true - }, - { - "value": "19889440", - "n": 1, - "hex": "76a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac", - "addresses": [ - "Dsesp1V6DZDEtcq2behmBVKdYqKMdkh96hL" - ], - "isAddress": true - } - ], - "blockHash": "0000000000000000264c499f21a7ef95bffb37148fc099514b2407dfa28c3287", - "blockHeight": 429186, - "confirmations": 5835, - "blockTime": 1583384838, - "value": "19989440", - "valueIn": "19991980", - "fees": "2540", - "hex": "0100000001424c7aa85afaa458ed3b89d44fc3bf42032e7b44ee7dbdbed67286ed010d2a5a00000000000000000002a08601000000000000001976a91420cf523034c462f8e09fc0fd35c47760b822398888ac207d2f010000000000001976a914989b1aecabf1c24e213cc0f2d8a22ffee25dd4e188ac000000000000000001ac0d31010000000052630600050000006b483045022100dd6997eab2e2bed5b275af4f2511a62b90da430ecb67f960afe4e06ebf8f362b022017e62873f5bd86abe725ef8fa75d506235ef174e18a06305b889d207ca6194e70121039603af712bd8410ada5a3b6c99d536b2e91dfaf4aa27e488b118cf6a9920e769" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/digibyte-api-address.js b/mock/ext-api-dyson/get/digibyte-api-address.js deleted file mode 100644 index b010065d7..000000000 --- a/mock/ext-api-dyson/get/digibyte-api-address.js +++ /dev/null @@ -1,123 +0,0 @@ -/// Mock for external Digibyte API -/// See: -/// curl "http://{digibyte rpc}/api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" -/// curl "http://localhost:3347/digibyte-api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs" -/// curl "http://localhost:8437/v1/digibyte/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" - -module.exports = { - path: '/digibyte-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 'DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi': - return JSON.parse(` - { - "page": 1, - "totalPages": 1821, - "itemsOnPage": 2, - "address": "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi", - "balance": "0", - "totalReceived": "238524073234", - "totalSent": "238524073234", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 3642, - "transactions": [ - { - "txid": "2b7ba9b43d615fe03bc14bc18201d1bd73c7a0f8aad428accf51725743f9073a", - "version": 1, - "vin": [ - { - "txid": "cba15c1782f15d1f3a5dfd6f06bad6ee03183d4d2bb3699bf72b9a423f4a97a3", - "sequence": 4294967295, - "n": 0, - "addresses": [ - "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" - ], - "isAddress": true, - "value": "47451000", - "hex": "473044022015642218d196b2bf010e10eb0eff952e0a6bd5bcb8aecd09751599bef8ca5df802205d277e3f6ac47ad360785df4462ffd2092618a58bcb0c8ae94751f26e5918fa30141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48" - } - ], - "vout": [ - { - "value": "47450000", - "n": 0, - "spent": true, - "hex": "76a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac", - "addresses": [ - "DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW" - ], - "isAddress": true - }, - { - "value": "0", - "n": 1, - "hex": "6a45524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de", - "addresses": [ - "OP_RETURN 524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de" - ], - "isAddress": false - } - ], - "blockHash": "00000000000000018af4a98ade5bb1d29d65871fd99b3cbaa8ea6266ea2c16a5", - "blockHeight": 10712917, - "confirmations": 1047, - "blockTime": 1587685950, - "value": "47450000", - "valueIn": "47451000", - "fees": "1000", - "hex": "0100000001a3974a3f429a2bf79b69b32b4d3d1803eed6ba066ffd5d3a1f5df182175ca1cb000000008a473044022015642218d196b2bf010e10eb0eff952e0a6bd5bcb8aecd09751599bef8ca5df802205d277e3f6ac47ad360785df4462ffd2092618a58bcb0c8ae94751f26e5918fa30141041dd9c41a6c1a3ea6c9fd53eecc0314c79386eb56f380552d46644d106bdbc4dfd389027e1498313480441bbf5130461af785656deaea87348dd7ac523eaeff48ffffffff029007d402000000001976a914562e330d8879eeaf17c72c8ad7f3acb4ebb6262c88ac0000000000000000476a45524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de00000000" - }, - { - "txid": "cba15c1782f15d1f3a5dfd6f06bad6ee03183d4d2bb3699bf72b9a423f4a97a3", - "version": 1, - "vin": [ - { - "txid": "fae67ad84a3f6a7e7648f12122d649bb711178f0fd129286e2566df1f31fa08f", - "sequence": 4294967295, - "n": 0, - "addresses": [ - "DCzmzkMBqEz2tLn47W9YuNAV9cFzuWCydW" - ], - "isAddress": true, - "value": "47452000", - "hex": "46304302205da10139f9ff5f0c0579237108634edce8dafa82feb7f63f0104b4596c5d0c98021f75ca71439e45a274b8953fa383d51938403043d961b59e9b078ef50a6fba01012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057" - } - ], - "vout": [ - { - "value": "47451000", - "n": 0, - "spent": true, - "hex": "76a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac", - "addresses": [ - "DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi" - ], - "isAddress": true - }, - { - "value": "0", - "n": 1, - "hex": "6a45524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de", - "addresses": [ - "OP_RETURN 524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de" - ], - "isAddress": false - } - ], - "blockHash": "00000000000000018af4a98ade5bb1d29d65871fd99b3cbaa8ea6266ea2c16a5", - "blockHeight": 10712917, - "confirmations": 1047, - "blockTime": 1587685950, - "value": "47451000", - "valueIn": "47452000", - "fees": "1000", - "hex": "01000000018fa01ff3f16d56e2869212fdf0781171bb49d62221f148767e6a3f4ad87ae6fa000000006946304302205da10139f9ff5f0c0579237108634edce8dafa82feb7f63f0104b4596c5d0c98021f75ca71439e45a274b8953fa383d51938403043d961b59e9b078ef50a6fba01012102aa3f5da884ab5654137cf660576e590830f6ec177ca84629d5a0264a1e494057ffffffff02780bd402000000001976a9146aa65418d9de46d678eb71db1d2616f5a96acdc588ac0000000000000000476a45524d555453422e41432e5448000000000000280ca398bee3241347368c2d4d758575c7fe0079c3ea7e1cb73919815c2534d932c4b305dd86f2aafcfc843c264594069454de00000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/digibyte-api-xpub.js b/mock/ext-api-dyson/get/digibyte-api-xpub.js deleted file mode 100644 index fea8f1f4c..000000000 --- a/mock/ext-api-dyson/get/digibyte-api-xpub.js +++ /dev/null @@ -1,123 +0,0 @@ -/// Mock for external Digibyte API -/// See: -/// curl "http://{digibyte rpc}/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs" -/// curl "http://localhost:3347/digibyte-api/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs" -/// curl "http://localhost:8437/v1/digibyte/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow" - -module.exports = { - path: '/digibyte-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow", - "balance": "2599896040", - "totalReceived": "6895667780", - "totalSent": "4295771740", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 7, - "transactions": [ - { - "txid": "e13c81f4450e43ef8ef10dea8f4f9d53f357266563462df32a7fd61eb71bd190", - "version": 1, - "vin": [ - { - "txid": "34fac508c701939ac0fcb62bc436281cc28588d7986c5aa51de99e9835b9217b", - "vout": 1, - "n": 0, - "addresses": [ - "dgb1qxxdszsfkv4uvw8kzzl2wfatts5r9zex69x6076" - ], - "isAddress": true, - "value": "598908696" - } - ], - "vout": [ - { - "value": "10000000", - "n": 0, - "hex": "0014428a3010eb79c4d32478404200dbd41042e61fce", - "addresses": [ - "dgb1qg29rqy8t08zdxfrcgppqpk75zppwv87wknuder" - ], - "isAddress": true - }, - { - "value": "588896040", - "n": 1, - "hex": "00146542b8b7859994b18df4b71c72c4a72ed113662e", - "addresses": [ - "dgb1qv4pt3du9nx2trr05kuw893989mg3xe3w322vy7" - ], - "isAddress": true - } - ], - "blockHash": "000000000000000733a44ab2efd51c9485b05d905d2ba9092f716dcc0083116c", - "blockHeight": 9763292, - "confirmations": 777936, - "blockTime": 1573501957, - "value": "598896040", - "valueIn": "598908696", - "fees": "12656", - "hex": "010000000001017b21b935989ee91da55a6c98d78885c21c2836c42bb6fcc09a9301c708c5fa34010000000000000000028096980000000000160014428a3010eb79c4d32478404200dbd41042e61fce28d71923000000001600146542b8b7859994b18df4b71c72c4a72ed113662e02473044022023b050ed97c4c7e334fec8efa3f27754e65c1e66a60ce142b2f8e2c16a1c847b02204a2e7d8a470a8978735a0b6d0f3649da6489612256f7cacd52e95034cc05365e012102cc9d7c2383e8f7c18e5af1852ddc35c5c4355a262a68b9d499ba173f6200ff9500000000" - }, - { - "txid": "303aa433530cb32762f8068ae14022e9a759b6c40bb69cee7e77abca333db317", - "version": 1, - "vin": [ - { - "txid": "d8d05cee8623257853b90cb1b0ff6c8e4bf5509818e812510f6715015fac1599", - "sequence": 4294967295, - "n": 0, - "addresses": [ - "DTVYvQYvoXQjsiZQdvT9AaBjyQJr8TjAWu" - ], - "isAddress": true, - "value": "48587940518800", - "hex": "483045022100de758903643db73bc56bcd6b3e1e4bdafb3bd9b7a844286f66317de7c90b868702207eba0eeb32c817df9e79df2aad5f192808941ccb5d18430f9ee7ea18b8b1abad0121038f47ad4221aa24dbefe2b439f644b3af71428a7eb9e837517a162710fe631cf7" - } - ], - "vout": [ - { - "value": "48585940500900", - "n": 0, - "spent": true, - "hex": "76a914c30c2dd0e7b7f6506259f11e956d0f1085ca437588ac", - "addresses": [ - "DNvQtshdnrehs8MNRx6Mh9XDPz4UZucfEv" - ], - "isAddress": true - }, - { - "value": "2000000000", - "n": 1, - "hex": "00147ad8c91046724785f78b48d4ae606a3556ddf9b4", - "addresses": [ - "dgb1q0tvvjyzxwfrctautfr22ucr2x4tdm7d5va4lr6" - ], - "isAddress": true - } - ], - "blockHash": "311aa13d66a4cf6be602209601d7b54bc715320d9255d1abc822ad20a7e01a20", - "blockHeight": 9756845, - "confirmations": 784383, - "blockTime": 1573405513, - "value": "48587940500900", - "valueIn": "48587940518800", - "fees": "17900", - "hex": "01000000019915ac5f0115670f5112e8189850f54b8e6cffb0b10cb95378252386ee5cd0d8000000006b483045022100de758903643db73bc56bcd6b3e1e4bdafb3bd9b7a844286f66317de7c90b868702207eba0eeb32c817df9e79df2aad5f192808941ccb5d18430f9ee7ea18b8b1abad0121038f47ad4221aa24dbefe2b439f644b3af71428a7eb9e837517a162710fe631cf7ffffffff02a481b94b302c00001976a914c30c2dd0e7b7f6506259f11e956d0f1085ca437588ac00943577000000001600147ad8c91046724785f78b48d4ae606a3556ddf9b400000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/doge-api-address.js b/mock/ext-api-dyson/get/doge-api-address.js deleted file mode 100644 index cbb40e34f..000000000 --- a/mock/ext-api-dyson/get/doge-api-address.js +++ /dev/null @@ -1,121 +0,0 @@ -/// Mock for external Doge API -/// See: -/// curl "http://{doge rpc}/api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" -/// curl "http://localhost:3347/doge-api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs" -/// curl "http://localhost:8437/v1/doge/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" - -module.exports = { - path: '/doge-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 'D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh': - return JSON.parse(` - { - "page": 1, - "totalPages": 6, - "itemsOnPage": 2, - "address": "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh", - "balance": "50394795942", - "totalReceived": "160202987826", - "totalSent": "109808191884", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 12, - "transactions": [ - { - "txid": "fee8381fed7406a48a8ea9e62328a3134064210626e81489ed8906e18c433bdf", - "version": 1, - "vin": [ - { - "txid": "c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb", - "n": 0, - "addresses": [ - "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" - ], - "isAddress": true, - "value": "1000000000", - "hex": "47304402200833c3184e768e5b6da836d9824f98b65704a24229a02e572ac760bb304ab9fb022068d102da9400afaeee3a6b42930a966ff107f5c68affde4a0239dab9fa21123d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" - } - ], - "vout": [ - { - "value": "134700000", - "n": 0, - "hex": "76a9142ba977acdb30bc18d350df32f38a777313ae86b088ac", - "addresses": [ - "D97xcKB9EAPmgNExbB5nAXDAQ9s5ZJ91J4" - ], - "isAddress": true - }, - { - "value": "707100000", - "n": 1, - "hex": "76a914b358390833fd8371733c1d11477bdb2d185e61e988ac", - "addresses": [ - "DMVPBRTD6bgqr3fk2yTdz97hS4AA2gzj8g" - ], - "isAddress": true - } - ], - "blockHash": "b94fd58d99710000ff0991ebf82c85330ed706ea18bcd4265e1f22747b91ddfe", - "blockHeight": 3170421, - "confirmations": 30293, - "blockTime": 1585794154, - "value": "841800000", - "valueIn": "1000000000", - "fees": "158200000", - "hex": "0100000001fb1d11634e4149776ceb89325044be3f2b14989d65584f323c16bbd4d21ea5c6000000006a47304402200833c3184e768e5b6da836d9824f98b65704a24229a02e572ac760bb304ab9fb022068d102da9400afaeee3a6b42930a966ff107f5c68affde4a0239dab9fa21123d012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca0000000002e05b0708000000001976a9142ba977acdb30bc18d350df32f38a777313ae86b088ac607d252a000000001976a914b358390833fd8371733c1d11477bdb2d185e61e988ac00000000" - }, - { - "txid": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9", - "version": 1, - "vin": [ - { - "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", - "vout": 1, - "sequence": 4294967288, - "n": 0, - "addresses": [ - "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" - ], - "isAddress": true, - "value": "533600000", - "hex": "483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5" - } - ], - "vout": [ - { - "value": "100000000", - "n": 0, - "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", - "addresses": [ - "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" - ], - "isAddress": true - }, - { - "value": "275400000", - "n": 1, - "hex": "76a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac", - "addresses": [ - "DKix6fTygojRpBFbADfkYKDX9nZ2Y7Huqq" - ], - "isAddress": true - } - ], - "blockHash": "ece2c433edfaf7143ba79f381ea40ac8b7e38ce6c4ff0771ae1e3dda9246824a", - "blockHeight": 3099770, - "confirmations": 100944, - "blockTime": 1581351126, - "value": "375400000", - "valueIn": "533600000", - "fees": "158200000", - "hex": "0100000001987490208464a2b0547cf6fcae4b550be9bb9ca88ce526ef4a0ee5803da50df6010000006b483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5f8ffffff0200e1f505000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac40456a10000000001976a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac00000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/doge-api-xpub.js b/mock/ext-api-dyson/get/doge-api-xpub.js deleted file mode 100644 index c9fd225fb..000000000 --- a/mock/ext-api-dyson/get/doge-api-xpub.js +++ /dev/null @@ -1,126 +0,0 @@ -/// Mock for external Doge API -/// See: -/// curl "http://{doge rpc}/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs" -/// curl "http://localhost:3347/doge-api/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs" -/// curl "http://localhost:8437/v1/doge/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN" - -module.exports = { - path: '/doge-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN", - "balance": "53537405232", - "totalReceived": "2701368049752", - "totalSent": "2647830644520", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 2, - "transactions": [ - { - "txid": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9", - "version": 1, - "vin": [ - { - "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", - "vout": 1, - "sequence": 4294967288, - "n": 0, - "addresses": [ - "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" - ], - "isAddress": true, - "value": "533600000", - "hex": "483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5" - } - ], - "vout": [ - { - "value": "100000000", - "n": 0, - "hex": "76a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac", - "addresses": [ - "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" - ], - "isAddress": true - }, - { - "value": "275400000", - "n": 1, - "hex": "76a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac", - "addresses": [ - "DKix6fTygojRpBFbADfkYKDX9nZ2Y7Huqq" - ], - "isAddress": true - } - ], - "blockHash": "ece2c433edfaf7143ba79f381ea40ac8b7e38ce6c4ff0771ae1e3dda9246824a", - "blockHeight": 3099770, - "confirmations": 59977, - "blockTime": 1581351126, - "value": "375400000", - "valueIn": "533600000", - "fees": "158200000", - "hex": "0100000001987490208464a2b0547cf6fcae4b550be9bb9ca88ce526ef4a0ee5803da50df6010000006b483045022100f357d4cb4fbef56bc76de9894e330ce485085c3cbe58dc9680db2a35dcf99dbf02204d7ef785782d75025c117c5e70ae009104b7cdd7cd1554d5cf4cb884958c06be01210391c22d3c06172377ff770f0832a4decf91ee38b975eb65451c38faa6bef861b5f8ffffff0200e1f505000000001976a914054eed59ece5b6aa1ef15f3713765e708cf3d5f688ac40456a10000000001976a9149ff8db746d4f6b11acab2bda9288dde3b8428d8e88ac00000000" - }, - { - "txid": "f60da53d80e50e4aef26e58ca89cbbe90b554baefcf67c54b0a2648420907498", - "version": 1, - "vin": [ - { - "txid": "c6a51ed2d4bb163c324f58659d98142b3fbe44503289eb6c7749414e63111dfb", - "vout": 1, - "sequence": 4294967291, - "n": 0, - "addresses": [ - "D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh" - ], - "isAddress": true, - "value": "841800000", - "hex": "483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6ca" - } - ], - "vout": [ - { - "value": "150000000", - "n": 0, - "hex": "76a914e82178c73b5744342916f6a7a944af4fa37aebff88ac", - "addresses": [ - "DSJVQRY3wyVPrXbEDMSeoFufWNSsMeKEuj" - ], - "isAddress": true - }, - { - "value": "533600000", - "n": 1, - "spent": true, - "hex": "76a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac", - "addresses": [ - "DF5TedCytjJRQdvTbMPJuMwbMWoveWZYp3" - ], - "isAddress": true - } - ], - "blockHash": "d4a57feed1683117d412944fc6581eace1bc3a8be5ebab93cf2dd99f5918374d", - "blockHeight": 3088989, - "confirmations": 70758, - "blockTime": 1580673745, - "value": "683600000", - "valueIn": "841800000", - "fees": "158200000", - "hex": "0100000001fb1d11634e4149776ceb89325044be3f2b14989d65584f323c16bbd4d21ea5c6010000006b483045022100f80b337309fcefc7886364f9a87ff9afcadf876542a5a36b543547f7e9d43ef10220397d6aaa649814b68dc98a1ed1027de34c8aa06cbe480e34bbe5a7ba5f282402012102cc82e0824da5cc96d5967cfc06d4b82e29c44ce10cb86028d15b5e67ceb1b6cafbffffff0280d1f008000000001976a914e82178c73b5744342916f6a7a944af4fa37aebff88ac0017ce1f000000001976a9146d01372d8c138cddcc142ade8a7ebc84948b87df88ac00000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/dyson-ping.js b/mock/ext-api-dyson/get/dyson-ping.js deleted file mode 100644 index 604711052..000000000 --- a/mock/ext-api-dyson/get/dyson-ping.js +++ /dev/null @@ -1,11 +0,0 @@ -/// Health-check for Dyson - -module.exports = { - path: '/dyson-ping/ping', - template: function(params, query) { - return { - status: true, - msg: 'Dyson is alive' - }; - } -} diff --git a/mock/ext-api-dyson/get/eth-api-commands1.js b/mock/ext-api-dyson/get/eth-api-commands1.js deleted file mode 100644 index 38a844c6f..000000000 --- a/mock/ext-api-dyson/get/eth-api-commands1.js +++ /dev/null @@ -1,194 +0,0 @@ -/// Ethereum API Mock -/// See: -/// curl "http://localhost:3347/eth-api/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://localhost:3347/eth-api/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "https://{eth rpc}/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "https://{eth rpc}/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://localhost:8437/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://localhost:8437/v2/ethereum/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" - -module.exports = { - path: '/eth-api/:command1?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.command1) { - case 'transactions': - if (query.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { - return JSON.parse(`{ - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", - "blockNumber": 9551915, - "time": 1582624428, - "nonce": 227, - "from": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "to": "0x1717f94202c126ef71d6C562de253Fe95eEbDD5f", - "value": "17635730000000000", - "gas": "21000", - "gasPrice": "4320000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", - "timeStamp": "1582624428" - }, - { - "operations": [ - { - "transactionId": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3-0", - "contract": { - "address": "0x0d8775f648430679a709e98d2b0cb6250d2887ef", - "symbol": "BAT", - "decimals": 18, - "totalSupply": "1500000000000000000000000000", - "name": "Basic Attention Token", - "updatedAt": "2020-03-23T06:01:25.975Z" - }, - "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", - "to": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "type": "token_transfer", - "value": "400000000000000000", - "id": null - } - ], - "contract": null, - "_id": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", - "blockNumber": 9519169, - "time": 1582189159, - "nonce": 16, - "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", - "to": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", - "value": "0", - "gas": "51839", - "gasPrice": "11500000000", - "gasUsed": "37028", - "input": "0xa9059cbb0000000000000000000000000875bcab22de3d02402bc38aee4104e1239374a7000000000000000000000000000000000000000000000000058d15e176280000", - "error": "", - "id": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", - "timeStamp": "1582189159" - } - ], - "total": 2 - }`); - } - - case 'tokens': - if (query.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { - return JSON.parse(` - { - "total": 17, - "docs": [ - { - "address": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - "name": "Kyber Network Crystal", - "decimals": 18, - "symbol": "KNC" - }, - { - "address": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", - "name": "BNB", - "decimals": 18, - "symbol": "BNB" - }, - { - "address": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", - "name": "Basic Attention Token", - "decimals": 18, - "symbol": "BAT" - }, - { - "address": "0x226bb599a12C826476e3A771454697EA52E9E220", - "name": "Propy", - "decimals": 8, - "symbol": "PRO" - }, - { - "address": "0xf3Db5Fa2C66B7aF3Eb0C0b782510816cbe4813b8", - "name": "Everex", - "decimals": 4, - "symbol": "EVX" - }, - { - "address": "0x85e076361cc813A908Ff672F9BAd1541474402b2", - "name": "Telcoin", - "decimals": 2, - "symbol": "TEL" - }, - { - "address": "0xD73bE539d6B2076BaB83CA6Ba62DfE189aBC6Bbe", - "name": "BlockchainCuties", - "decimals": 0, - "symbol": "BC" - }, - { - "address": "0x0000000000085d4780B73119b644AE5ecd22b376", - "name": "TrueUSD", - "decimals": 18, - "symbol": "TUSD" - }, - { - "address": "0xFBeef911Dc5821886e1dda71586d90eD28174B7d", - "name": "KnownOriginDigitalAsset", - "decimals": 0, - "symbol": "KODA" - }, - { - "address": "0xc3761EB917CD790B30dAD99f6Cc5b4Ff93C4F9eA", - "name": "ERC20", - "decimals": 18, - "symbol": "ERC20" - }, - { - "address": "0x77FE30b2cf39245267C0a5084B66a560f1cF9E1f", - "name": "Azbit", - "decimals": 18, - "symbol": "AZ" - }, - { - "address": "0x7f3EaB3491Ed282197038F1B89CA33D7e5ADffBa", - "name": "Coin-coin coinslot.com", - "decimals": 8, - "symbol": "CC coinslot.com" - }, - { - "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", - "name": "Tether USD", - "decimals": 6, - "symbol": "USDT" - }, - { - "address": "0xE1Ac9Eb7cDDAbfd9e5CA49c23bd521aFcDF8BE49", - "name": "Mycion", - "decimals": 18, - "symbol": "MYC" - }, - { - "address": "0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c", - "name": "Enjin Coin", - "decimals": 18, - "symbol": "ENJ" - }, - { - "address": "0x467Bccd9d29f223BcE8043b84E8C8B282827790F", - "name": "Telcoin", - "decimals": 2, - "symbol": "TEL" - }, - { - "address": "0xC12D1c73eE7DC3615BA4e37E4ABFdbDDFA38907E", - "name": "KickToken", - "decimals": 8, - "symbol": "KICK" - } - ] - } - `); - } - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js b/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js deleted file mode 100644 index 4ff105f0a..000000000 --- a/mock/ext-api-dyson/get/eth-blockbook-api-transactions.js +++ /dev/null @@ -1,159 +0,0 @@ -/// Ethereum Blockbook API Mock -/// See: -/// curl "http://localhost:3347/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs" -/// curl "http://localhost:3347/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances" -/// curl "https://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs" -/// curl "https://{eth blockbook api}/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances" -/// curl "http://localhost:8437/v1/ethereum/0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://localhost:8437/v2/ethereum/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" - -module.exports = { - path: '/eth-blockbook-api/v2/address/:address?', - template: function(params, query) { - if (params.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { - if (query.details === 'tokenBalances') { - return JSON.parse(` - { - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "balance": "182976771756327797", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 263, - "nonTokenTxs": 243, - "nonce": "231", - "tokens": [ - { - "type": "ERC20", - "name": "Kyber Network Crystal", - "contract": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - "transfers": 13, - "symbol": "KNC", - "decimals": 18, - "balance": "41100" - }, - { - "type": "ERC20", - "name": "BNB", - "contract": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", - "transfers": 4, - "symbol": "BNB", - "decimals": 18, - "balance": "100500" - }, - { - "type": "ERC20", - "name": "BNB", - "contract": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", - "transfers": 4, - "symbol": "BNB", - "decimals": 18, - "balance": "0" - } - ] - } - `); - } - return JSON.parse(` - { - "page": 1, - "totalPages": 11, - "itemsOnPage": 25, - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "balance": "185659745674589722", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 259, - "nonTokenTxs": 240, - "transactions": [ - { - "txid": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47", - "vin": [ - { - "n": 0, - "addresses": [ - "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" - ], - "isAddress": true - } - ], - "vout": [ - { - "value": "17635730000000000", - "n": 0, - "addresses": [ - "0x1717f94202c126ef71d6C562de253Fe95eEbDD5f" - ], - "isAddress": true - } - ], - "blockHash": "0x5b8b39099d025a8feeed7575ebff6d0b2508e0542d6279c1b3b4f8b893e74296", - "blockHeight": 9551915, - "confirmations": 231227, - "blockTime": 1582624428, - "value": "17635730000000000", - "fees": "90720000000000", - "ethereumSpecific": { - "status": 1, - "nonce": 227, - "gasLimit": 21000, - "gasUsed": 21000, - "gasPrice": "4320000000" - } - }, - { - "txid": "0xb669b69afee75c6ef073a603600041d3708d54da8d43cab7b35ee66baa7510d3", - "vin": [ - { - "n": 0, - "addresses": [ - "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8" - ], - "isAddress": true - } - ], - "vout": [ - { - "value": "0", - "n": 0, - "addresses": [ - "0x0D8775F648430679A709E98d2b0Cb6250d2887EF" - ], - "isAddress": true - } - ], - "blockHash": "0x770332c9b4ea42e518f8c5a0178ca5732fd5edfe5e8e011e1362e6598de262d5", - "blockHeight": 9519169, - "confirmations": 263973, - "blockTime": 1582189159, - "value": "0", - "fees": "425822000000000", - "tokenTransfers": [ - { - "type": "ERC20", - "from": "0xeCe114137b2e9Dbf29712BDC39639EB0B72B41b8", - "to": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "token": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", - "name": "Basic Attention Token", - "symbol": "BAT", - "decimals": 18, - "value": "400000000000000000" - } - ], - "ethereumSpecific": { - "status": 1, - "nonce": 16, - "gasLimit": 51839, - "gasUsed": 37028, - "gasPrice": "11500000000" - } - } - ], - "nonce": "228", - "tokens": [] - } - `); - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/ethclassic-api-commands1.js b/mock/ext-api-dyson/get/ethclassic-api-commands1.js deleted file mode 100644 index 482e00725..000000000 --- a/mock/ext-api-dyson/get/ethclassic-api-commands1.js +++ /dev/null @@ -1,89 +0,0 @@ -/// Ethereum Classic API Mock -/// See: -/// curl "http://localhost:3347/ethclassic-api/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" -/// curl "http://localhost:3347/ethclassic-api/tokens?address=0xa12105efa0663147bddee178f6a741ac15676b79" -/// curl "https://{etc rpc}/transactions?address=0x7d2d0e153026fb428b885d86de50768d4cfeac37" -/// curl "https://{etc rpc}/tokens?address=0xa12105efa0663147bddee178f6a741ac15676b79" -/// curl "http://localhost:8437/v1/ethereumclassic/0x7d2d0e153026fb428b885d86de50768d4cfeac37" -/// curl "http://localhost:8437/v2/classic/tokens/0xa12105efa0663147bddee178f6a741ac15676b79?Authorization=Bearer" - -module.exports = { - path: '/ethclassic-api/:command1?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.command1) { - case 'transactions': - if (query.address === '0x7d2d0e153026fb428b885d86de50768d4cfeac37') { - return JSON.parse(` - { - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe", - "blockNumber": 9833329, - "time": 1582237362, - "nonce": 7071, - "from": "0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9", - "to": "0x7D2D0E153026fB428B885D86De50768D4cFeaC37", - "value": "18529160000000000", - "gas": "21000", - "gasPrice": "1000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe", - "timeStamp": "1582237362" - }, - { - "operations": [], - "contract": null, - "_id": "0x524fb5fedace7bee35c165ac7f641d689122cb21390db7f7384507473a5ba058", - "blockNumber": 9804290, - "time": 1581854371, - "nonce": 6918, - "from": "0x2d4BeCA01fDE8963b3A2DBf8a838e0F2EBaB0FF9", - "to": "0x7D2D0E153026fB428B885D86De50768D4cFeaC37", - "value": "16208400000000000", - "gas": "21000", - "gasPrice": "1000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x524fb5fedace7bee35c165ac7f641d689122cb21390db7f7384507473a5ba058", - "timeStamp": "1581854371" - } - ], - "total": 2 - } - `); - } - - case 'tokens': - if (query.address === '0xa12105efa0663147bddee178f6a741ac15676b79') { - return JSON.parse(` - { - "total": 2, - "docs": [ - { - "address": "0xCA68fE57A0E9987F940Ebcc65fe5F96E7bC30128", - "name": "Litecoin Classic Token", - "decimals": 8, - "symbol": "LCT" - }, - { - "address": "0x2B682bd9d5c31E67a95cbdF0292017C02E51923C", - "name": "Ether Klown", - "decimals": 6, - "symbol": "KLOWN2" - } - ] - } - `); - } - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/gochain-api-commands1.js b/mock/ext-api-dyson/get/gochain-api-commands1.js deleted file mode 100644 index 268fab6a2..000000000 --- a/mock/ext-api-dyson/get/gochain-api-commands1.js +++ /dev/null @@ -1,83 +0,0 @@ -/// Gochain API Mock -/// See: -/// curl "http://localhost:3347/gochain-api/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" -/// curl "http://localhost:3347/gochain-api/tokens?address=0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628" -/// curl "https://{go rpc}/transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" -/// curl "https://{go rpc}/ -/// curl "http://localhost:8437/v1/gochain/0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896" -/// curl "http://localhost:8437/v2/gochain/tokens/0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628?Authorization=Bearer" - -module.exports = { - path: '/gochain-api/:command1?', - template: function(params, query, body) { - //console.log(params); - //console.log(query); - switch (params.command1) { - case 'transactions': - if (query.address === '0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896') { - return JSON.parse(`{ - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7", - "blockNumber": 10070535, - "time": 1576793173, - "nonce": 6, - "from": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", - "to": "0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3", - "value": "860000000000000000000000", - "gas": "90000", - "gasPrice": "2000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7", - "timeStamp": "1576793173" - }, - { - "operations": [], - "contract": null, - "_id": "0x472c94385a46072713bb2bf3503fc1610135a70e415046bf61a937789c205f4c", - "blockNumber": 10070520, - "time": 1576793098, - "nonce": 5, - "from": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", - "to": "0x65a0e277B2d0eEF62b8C30b280B4C49f83a104d3", - "value": "800000000000000000000", - "gas": "90000", - "gasPrice": "2000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x472c94385a46072713bb2bf3503fc1610135a70e415046bf61a937789c205f4c", - "timeStamp": "1576793098" - } - ], - "total": 2 - }`); - } - break; - - case 'tokens': - if (query.address === '0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628') { - return JSON.parse(` - { - "total": 1, - "docs": [ - { - "address": "0x5f16Fa0B5c9d779a3C8d46859a27973Ff3511188", - "name": "pukkamex", - "decimals": 18, - "symbol": "PUX" - } - ] - } - `); - } - break; - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/groestlcoin-api-address.js b/mock/ext-api-dyson/get/groestlcoin-api-address.js deleted file mode 100644 index c82622302..000000000 --- a/mock/ext-api-dyson/get/groestlcoin-api-address.js +++ /dev/null @@ -1,127 +0,0 @@ -/// Mock for external Groestlcoin API -/// See: -/// curl "http://{groestlcoin rpc}/api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" -/// curl "http://localhost:3347/groestlcoin-api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs" -/// curl "http://localhost:8437/v1/groestlcoin/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" - -module.exports = { - path: '/groestlcoin-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case '33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 2, - "address": "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj", - "balance": "0", - "totalReceived": "5951153060", - "totalSent": "5951153060", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 2, - "transactions": [ - { - "txid": "2640aa5de0c9603da1c0d9c16b2fd3fa0a17b1472c3aa02559d3ef5e1defceb5", - "version": 2, - "lockTime": 2959295, - "vin": [ - { - "txid": "d8e0d23dedc2c89e9de317e7a54bdc3d26f514918a9360aa04e271c4d8074c28", - "sequence": 4294967294, - "n": 0, - "addresses": [ - "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" - ], - "isAddress": true, - "value": "5951153060", - "hex": "160014d6c589125f084df1e3286fcd55446b64dc7de130" - } - ], - "vout": [ - { - "value": "1151149700", - "n": 0, - "spent": true, - "hex": "a91436d64490426cc347a50bdd3f8db2ef20d62949f587", - "addresses": [ - "36gy6VVstfso35mS89pBg1PiUcYY3Gesar" - ], - "isAddress": true - }, - { - "value": "4800000000", - "n": 1, - "spent": true, - "hex": "76a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac", - "addresses": [ - "FtCkFSrwrgiJzjQzGRZvjHzrmHp4HJeGYm" - ], - "isAddress": true - } - ], - "blockHash": "0000000000000a79428395294255704ed877847d93c6d36108dc8184b71c1f0a", - "blockHeight": 2959365, - "confirmations": 100119, - "blockTime": 1581386699, - "value": "5951149700", - "valueIn": "5951153060", - "fees": "3360", - "hex": "02000000000101284c07d8c471e204aa60938a9114f5263ddc4ba5e717e39d9ec8c2ed3dd2e0d80000000017160014d6c589125f084df1e3286fcd55446b64dc7de130feffffff0284269d440000000017a91436d64490426cc347a50bdd3f8db2ef20d62949f58700301a1e010000001976a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac02473044022034f3f2ab2d021a27ba999aebb40016f921433c39149d6908fe1e96d914c5c96402203d5d12127f64a01429775090abb445b5af2ec90803372c92499a35e12e229adb0121033ca60a0478fee5583e52c3b85c4dacb81faa9c4a10ad8b4f574c1b050f814463bf272d00" - }, - { - "txid": "d8e0d23dedc2c89e9de317e7a54bdc3d26f514918a9360aa04e271c4d8074c28", - "version": 2, - "lockTime": 2959360, - "vin": [ - { - "txid": "2ed852f7881270ec108c86482d609f818ee21ae07033796fb77cb8e52fa86ccd", - "sequence": 4294967294, - "n": 0, - "addresses": [ - "Fg4WGddhNYayAF3mTPDNCFCEqrXydAd6Vu" - ], - "isAddress": true, - "value": "29751157520", - "hex": "47304402201fe0aff8dd5c35be49f824216adb51d0749878dc2d759d0dd6d4ed6612ca09cd02203ad7d2b2eaa52f341f325934cca2c2758ac4c4b7b8bc279e7748d48ab98b484901210246e7e23df8acf0a305b94009d9b60eca7230ce747493201a9574f7ccb03775e9" - } - ], - "vout": [ - { - "value": "5951153060", - "n": 0, - "spent": true, - "hex": "a914146081496e97dbb864af7df601184f8ec3624aa787", - "addresses": [ - "33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj" - ], - "isAddress": true - }, - { - "value": "23800000000", - "n": 1, - "spent": true, - "hex": "76a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac", - "addresses": [ - "FtCkFSrwrgiJzjQzGRZvjHzrmHp4HJeGYm" - ], - "isAddress": true - } - ], - "blockHash": "0000000000000a79428395294255704ed877847d93c6d36108dc8184b71c1f0a", - "blockHeight": 2959365, - "confirmations": 100119, - "blockTime": 1581386699, - "value": "29751153060", - "valueIn": "29751157520", - "fees": "4460", - "hex": "0200000001cd6ca82fe5b87cb76f793370e01ae28e819f602d48868c10ec701288f752d82e000000006a47304402201fe0aff8dd5c35be49f824216adb51d0749878dc2d759d0dd6d4ed6612ca09cd02203ad7d2b2eaa52f341f325934cca2c2758ac4c4b7b8bc279e7748d48ab98b484901210246e7e23df8acf0a305b94009d9b60eca7230ce747493201a9574f7ccb03775e9feffffff02a463b7620100000017a914146081496e97dbb864af7df601184f8ec3624aa787002e978a050000001976a914fcad3abf614562d224c6cc8b0e00d2fa9016404388ac00282d00" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/groestlcoin-api-xpub.js b/mock/ext-api-dyson/get/groestlcoin-api-xpub.js deleted file mode 100644 index de299f7c6..000000000 --- a/mock/ext-api-dyson/get/groestlcoin-api-xpub.js +++ /dev/null @@ -1,157 +0,0 @@ -/// Mock for external Groestlcoin API -/// See: -/// curl "http://{groestlcoin rpc}/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs" -/// curl "http://localhost:3347/groestlcoin-api/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs" -/// curl "http://localhost:8437/v1/groestlcoin/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf" - -module.exports = { - path: '/groestlcoin-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf", - "balance": "412844353", - "totalReceived": "289739972697", - "totalSent": "289327128344", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 98, - "transactions": [ - { - "txid": "686c651223b937b1223560a60631ad79ad17351c88bba67cad8ea0c95fccbb83", - "version": 1, - "vin": [ - { - "txid": "1e3362ef26063cae601362721fcde1c0e856b7d81abc9e541ba38a0b15330689", - "sequence": 2147483644, - "n": 0, - "addresses": [ - "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" - ], - "isAddress": true, - "value": "100000000" - }, - { - "txid": "1e3362ef26063cae601362721fcde1c0e856b7d81abc9e541ba38a0b15330689", - "vout": 1, - "sequence": 2147483645, - "n": 1, - "addresses": [ - "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" - ], - "isAddress": true, - "value": "212864353" - }, - { - "txid": "dd7780ee2529f7030153737c8ee2a16ef32817cbd63b6aba8553c4ccbeac368d", - "sequence": 2147483646, - "n": 2, - "addresses": [ - "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" - ], - "isAddress": true, - "value": "100000000" - } - ], - "vout": [ - { - "value": "10000000", - "n": 0, - "hex": "0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395", - "addresses": [ - "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" - ], - "isAddress": true - }, - { - "value": "402844353", - "n": 1, - "hex": "0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395", - "addresses": [ - "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" - ], - "isAddress": true - } - ], - "blockHash": "00000000000003a48c30ddfaa9c875b902e8372c448413ee65dba418601a5b7e", - "blockHeight": 2998112, - "confirmations": 20605, - "blockTime": 1583831414, - "value": "412844353", - "valueIn": "412864353", - "fees": "20000", - "hex": "01000000000103890633150b8aa31b549ebc1ad8b756e8c0e1cd1f72621360ae3c0626ef62331e0000000000fcffff7f890633150b8aa31b549ebc1ad8b756e8c0e1cd1f72621360ae3c0626ef62331e0100000000fdffff7f8d36acbeccc45385ba6a3bd6cb1728f36ea1e28e7c73530103f72925ee8077dd0000000000feffff7f028096980000000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395c1ea021800000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb423950247304402201b4acd75cb1186fba1405bd604a2e24a960d94a39e14316f4e6ef5289808e4c90220569d652a91ecc149d543d7aab0653a646ce60d8e3bed053d421907432bd7c9bd012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b285024730440220426733a0a12dd1c34142d9814e74987fdbb41438189fb0bbed74ab2cd420a9b4022046dc588c6690b1ecba351b8a981ed3db63df9de95df49d5a8333b087b349b6c3012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b285024730440220291f4932101719b70630233d53503854f456a0a944453a6105f4e2b95fde526b0220617d4dd0b4dd12e8917d15f80dadf617ec584fe650a31ca8f07f4d6869256549012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000" - }, - { - "txid": "1e3362ef26063cae601362721fcde1c0e856b7d81abc9e541ba38a0b15330689", - "version": 1, - "vin": [ - { - "txid": "dd7780ee2529f7030153737c8ee2a16ef32817cbd63b6aba8553c4ccbeac368d", - "vout": 1, - "n": 0, - "addresses": [ - "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" - ], - "isAddress": true, - "value": "312884353" - } - ], - "vout": [ - { - "value": "100000000", - "n": 0, - "spent": true, - "hex": "0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395", - "addresses": [ - "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" - ], - "isAddress": true - }, - { - "value": "212864353", - "n": 1, - "spent": true, - "hex": "0014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395", - "addresses": [ - "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04" - ], - "isAddress": true - } - ], - "blockHash": "000000000000034560a3a07b6498c9b937da914a4f683d1575197a02c4b69a83", - "blockHeight": 2989928, - "confirmations": 28789, - "blockTime": 1583315379, - "value": "312864353", - "valueIn": "312884353", - "fees": "20000", - "hex": "010000000001018d36acbeccc45385ba6a3bd6cb1728f36ea1e28e7c73530103f72925ee8077dd0100000000000000000200e1f50500000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb42395610db00c00000000160014e9c2ceb5078d184f14f31c6cb1b3f633fdb4239502483045022100e0e7e5484f9d06120f0e3a63471d353d90b65ba63b0fbf640c714608414ffa5d02204556b0c2554bc33ebfb338d806fa1589df1e25afe251c5a7869cfad6e6ef0a61012102ab2d3112dfb83d7e08949ec32128e24a4be5c588640eee5028cdba56aae7b28500000000" - } - ], - "usedTokens": 79, - "tokens": [ - { - "type": "XPUBAddress", - "name": "grs1qa8pvadg835vy798nr3ktrvlkx07mggu4hqvv04", - "path": "m/84'/17'/0'/0/0", - "transfers": 53, - "decimals": 8, - "balance": "412844353", - "totalReceived": "34760610350", - "totalSent": "34347765997" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/icon-api-actions.js b/mock/ext-api-dyson/get/icon-api-actions.js deleted file mode 100644 index 58494d90d..000000000 --- a/mock/ext-api-dyson/get/icon-api-actions.js +++ /dev/null @@ -1,72 +0,0 @@ -/// Icon API Mock -/// See: -/// curl "http://localhost:3347/icon-api/address/txList?address=hxee691e7bccc4eb11fee922896e9f51490e62b12e&count=25" -/// curl "https://tracker.icon.foundation/v3/address/txList?address=hxee691e7bccc4eb11fee922896e9f51490e62b12e&count=25" -/// curl http://localhost:8437/v1/icon/hxee691e7bccc4eb11fee922896e9f51490e62b12e -module.exports = { - path: "/icon-api/address/:action?", - template: function(params, query, body) { - //console.log(query) - if (params.action === 'txList') { - if (query.address === 'hxee691e7bccc4eb11fee922896e9f51490e62b12e') { - return JSON.parse(` - { - "data": [ - { - "txHash": "0x3b1a382884091e683350d6285d908406c149a030a7d52eb347f4571c1c904382", - "height": 7044559, - "createDate": "2019-08-13T06:53:56.000+0000", - "fromAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", - "toAddr": "hx06d5b88bb7089033a2d8a2b61b8a305ecff8774f", - "txType": "0", - "dataType": "icx", - "amount": "0.498", - "fee": "0.001", - "state": 1, - "errorMsg": null, - "targetContractAddr": null, - "id": null - }, - { - "txHash": "0x990b7f289aa465369e638b4f719c99f0d050f9756c19081ba86b2bae5b8e2f0d", - "height": 361987, - "createDate": "2019-04-17T01:16:02.000+0000", - "fromAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", - "toAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", - "txType": "0", - "dataType": "icx", - "amount": "0.00347", - "fee": "0.001", - "state": 1, - "errorMsg": null, - "targetContractAddr": null, - "id": null - }, - { - "txHash": "0x3a455daca1f5e4588adbc6ac5cdfd84126d0617d3ebcf5610eb44b15dfc71402", - "height": 112100, - "createDate": "2018-11-23T21:52:15.000+0000", - "fromAddr": "hx3709f4e615f072158247ca4973218e1d40e0ea35", - "toAddr": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", - "txType": "0", - "dataType": "icx", - "amount": "0.5", - "fee": "0.001", - "state": 1, - "errorMsg": null, - "targetContractAddr": null, - "id": null - } - ], - "listSize": 3, - "totalSize": 3, - "result": "200", - "description": "success" - } - `); - } - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/iotex-api-commands2.js b/mock/ext-api-dyson/get/iotex-api-commands2.js deleted file mode 100644 index 2172af297..000000000 --- a/mock/ext-api-dyson/get/iotex-api-commands2.js +++ /dev/null @@ -1,821 +0,0 @@ -/// Iotex API Mock -/// See: -/// curl "http://localhost:3347/iotex-api/staking/validators?status=bonded" -/// curl "http://localhost:3347/iotex-api/accounts/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" -/// curl "https://{iotex_rpc}/v1/staking/validators?status=bonded" -/// curl "https://{iotex_rpc}/v1/accounts/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" -/// curl "http://localhost:8437/v2/iotex/staking/validators" -/// curl "http://localhost:8437/v2/iotex/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m?Authorization=Bearer" - -module.exports = { - path: "/iotex-api/:command1/:command2?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch(params.command1) { - case 'accounts': - switch(params.command2) { - case 'io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m': - // status=bonded - return JSON.parse(`{"accountMeta":{"address":"io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m","balance":"15578806681028832609262","nonce":"583","pendingNonce":"584","numActions":"647"}}`); - - case 'io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5': - return JSON.parse(`{"accountMeta":{"address":"io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5","balance":"33829692159741946535","nonce":"4","pendingNonce":"5","numActions":"57"}}`); - } - - case 'staking': - switch(params.command2) { - case 'validators': - // status=bonded - return JSON.parse(` - [ - { - "id": "huobiwallet", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotexcore", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "pubxpayments", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "droute", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "coredev", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "enlightiv", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iosg", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "royalland", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "gamefantasy#", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "laomao", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "cpc", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "hashbuy", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "hotbit", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotxplorerio", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotexteam", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "airfoil", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "capitmu", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "ducapital", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "pnp", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "longz", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotexlab", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "hofancrypto", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "draperdragon", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "yvalidator", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "satoshi", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "hashquark", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "mrtrump", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "elitex", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "ratels", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "rockx", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "blockfolio", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "preangel", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "consensusnet", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "blockboost", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "metanyx", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "coingecko", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "thebottoken#", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "cobo", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "zhcapital", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "infstones", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "tgb", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotexgeeks", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotask", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "cryptolionsx", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "bittaker", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "keys", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "snzholding", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotexunion", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "raketat8", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "wannodes", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "citex2018", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "wetez", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "eon", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "whales", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "eatliverun", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotexicu", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "everstake", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "nodeasy", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "slowmist", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "alphacoin", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotexhub", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "blackpool", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "superiotex", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "link", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotexmainnet", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "lanhu", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "piexgo", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "iotexbgogo", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "meter", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "bitwires", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - { - "id": "elink", - "status": true, - "details": { - "reward": { - "annual": 0 - }, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - } - ] - `); - } - } - - return {error: "Not implemented"}; - } -}; - diff --git a/mock/ext-api-dyson/get/iotex-api-commands4.js b/mock/ext-api-dyson/get/iotex-api-commands4.js deleted file mode 100644 index 5aba7f53e..000000000 --- a/mock/ext-api-dyson/get/iotex-api-commands4.js +++ /dev/null @@ -1,108 +0,0 @@ -/// Iotex API Mock -/// See: -/// curl "http://localhost:3347/iotex-api/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" -/// curl "https://{iotex_rpc}/v1/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" -/// curl "http://localhost:8437/v2/iotex/staking/delegations/io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m?Authorization=Bearer" - -module.exports = { - path: "/iotex-api/:command1/:command2/:arg3/:arg4?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch(params.command1) { - case 'actions': - switch(params.command2) { - case 'addr': - switch(params.arg3) { - case 'io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5': - return JSON.parse(` - { - "total": "2", - "actionInfo": [ - { - "action": { - "core": { - "version": 1, - "nonce": "40", - "gasLimit": "10000", - "gasPrice": "1000000000000", - "transfer": { - "amount": "5010000000000000000000", - "recipient": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5" - } - }, - "senderPubKey": "BHd42w46LIO7qw5+TsTo+QjAUZBhVc3NPwEVh3IHePcFQQeb9rFSPmEV6LhFS7cqRzDBpgSHuQbelY6wnPvMYmw=", - "signature": "CiJdvAO3jNUX7agpE4AvtrBdEzgFsm1MANhXTXeVtdkXxNrDV8xbSiFz6FuFUTd1L5uaFXoe1mxUPIrbTabh4QE=" - }, - "actHash": "7aceeda86535b8dd345e1ab2176a7f12e1907aac3591cf9422a5393feadb6bb6", - "blkHash": "57ca5160cb9aac7a16b4e5006295d93857220de966335a2a453992c824037ebe", - "blkHeight": "3291297", - "sender": "io1r8cwhdec6y3fpv42hv7ak0aqh0cfyc279ladxl", - "gasFee": "10000000000000000", - "timestamp": "2020-02-14T01:44:30Z" - }, - { - "action": { - "core": { - "version": 1, - "nonce": "1", - "gasLimit": "500000", - "gasPrice": "1000000000000", - "execution": { - "amount": "5000000000000000000000", - "contract": "io1zn9mn4v63jg3047ylqx9nqaqz0ev659777q3xc", - "data": "B8NfwAAAAAAAY29yZWRldgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" - } - }, - "senderPubKey": "BKarIa2N7C/tz6r93fnnHXHEXyGC4aG9fiTYSjwSKpUOWl2efDuLb9Fk+NysVn1hEFgFLjRONu/KlM4TnHaIQLQ=", - "signature": "0Pn96CJXbUmNvXsnvx0RgqPYuac7YD699liT/WqmE9Ak4EHYZXhTozu+t+JrM4cHmt37z7M3R4lbzC77gggHdgA=" - }, - "actHash": "7644e425163920f1d5658e12c96d6dfb4961ee35bc9886347fbb339d6b939dd8", - "blkHash": "1f7ab328160d0643b7a6af287a1559a88de70cd8a2068d40dcc814fdcdfba996", - "blkHeight": "3292065", - "sender": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5", - "gasFee": "264146000000000000", - "timestamp": "2020-02-14T02:48:30Z" - } - ] - } - `); - } - } - - case 'staking': - switch(params.command2) { - case 'delegations': - switch (params.arg3) { - case 'io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m': - return JSON.parse(` - [ - { - "delegator": { - "id": "iotxplorerio", - "status": true, - "info": { - "name": "iotxplorer", - "description": "", - "image": "https://imgc.iotex.io/dokc3pa1x/image/upload/v1551121446/delegates/iotxplorer/Group_2.png", - "website": "https://twitter.com/iotxplorer" - }, - "details": { - "reward": {"annual": 0}, - "locktime": 259200, - "minimum_amount": "100000000000000000000" - } - }, - "value": "100000000000000000000", - "status": "active" - } - ] - `); - } - } - } - - return {error: "Not implemented"}; - } -}; - diff --git a/mock/ext-api-dyson/get/kava-api-commands2.js b/mock/ext-api-dyson/get/kava-api-commands2.js deleted file mode 100644 index 3a3f61485..000000000 --- a/mock/ext-api-dyson/get/kava-api-commands2.js +++ /dev/null @@ -1,2628 +0,0 @@ -/// Kava API Mock -/// See: -/// curl "http://localhost:3347/kava-api/staking/validators?status=bonded" -/// curl "http://localhost:3347/kava-api/staking/pool" -/// curl "http://localhost:3347/kava-api/minting/inflation" -/// curl "https://{kava_rpc}/staking/validators?status=bonded" -/// curl "https://{kava_rpc}/staking/pool" -/// curl "https://{kava_rpc}/minting/inflation" -/// curl "http://localhost:8437/v2/kava/staking/validators" -/// curl "http://localhost:8437/v2/kava/staking/delegations/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m?Authorization=Bearer" - -module.exports = { - path: "/kava-api/:command1/:command2?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch(params.command1) { - case 'minting': - switch(params.command2) { - case 'inflation': - // status=bonded - return JSON.parse(`{"height":"1793129","result":"0.060343307052455856"}`); - } - - case 'txs': { - if (query["transfer.recipient"] === 'kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m') { - return JSON.parse(` - { - "total_count": "1", - "count": "1", - "page_number": "1", - "page_total": "1", - "limit": "25", - "txs": [ - { - "height": "793039", - "txhash": "84FFA6CC8428B7A5E82003A7BCA6D1FAB2DF296AD18BE73EE61CBCBF67623880", - "logs": [ - { - "msg_index": 0, - "success": true, - "log": "", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7" - }, - { - "key": "module", - "value": "bank" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - }, - { - "key": "amount", - "value": "9999000ukava" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "70019", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgSend", - "value": { - "from_address": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7", - "to_address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", - "amount": [ - { - "denom": "ukava", - "amount": "9999000" - } - ] - } - } - ], - "fee": { - "amount": [ - { - "denom": "ukava", - "amount": "1000" - } - ], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "As3eDIXFkLdMkBep+aV+6q9ccVRkA94snsXq2iL5bCTt" - }, - "signature": "QFx3iARLhLeuCCHRUbFAZTePzq+vGAYd4lB/F4JuCGYw1TrfIbAzJhmUHbXHcB/GC+f7Myv5xNrnlCPfCR53uA==" - } - ], - "memo": "" - } - }, - "timestamp": "2020-01-17T11:17:36Z", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7" - }, - { - "key": "module", - "value": "bank" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - }, - { - "key": "amount", - "value": "9999000ukava" - } - ] - } - ] - } - ] - } - `); - } - - if (query["message.sender"] === 'kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m') { - return JSON.parse(` - { - "total_count": "1", - "count": "1", - "page_number": "1", - "page_total": "1", - "limit": "25", - "txs": [ - { - "height": "1101012", - "txhash": "30EFE9E830D317F84629F9DC35177577DF6713D78D354C2C469DE633900303BC", - "logs": [ - { - "msg_index": 0, - "success": true, - "log": "", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - }, - { - "key": "module", - "value": "bank" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" - }, - { - "key": "amount", - "value": "9998000ukava" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "68317", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgSend", - "value": { - "from_address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", - "to_address": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7", - "amount": [ - { - "denom": "ukava", - "amount": "9998000" - } - ] - } - } - ], - "fee": { - "amount": [ - { - "denom": "ukava", - "amount": "1000" - } - ], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "AvgGasyPvRpG68UQ6IGPVKN+HrJix24tgwcYXIcIfsna" - }, - "signature": "iST3iM8TtkR5VHTFFhJE1zi+Nh6Invrg4hKgLEY2HCQ+R6Qj9L3jET4yRtAg6+QxitJab27+etoPjJbK20V/Cw==" - } - ], - "memo": "100009547" - } - }, - "timestamp": "2020-02-11T01:33:46Z", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - }, - { - "key": "module", - "value": "bank" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" - }, - { - "key": "amount", - "value": "9998000ukava" - } - ] - } - ] - } - ] - } - `); - } - } - - case 'staking': - switch(params.command2) { - case 'pool': - return JSON.parse(` - { - "height":"1793093", - "result": { - "not_bonded_tokens": "1664170404961", - "bonded_tokens": "86469758994132" - } - } - `); - - case 'validators': - // status=bonded - return JSON.parse(` - {"height":"1793067","result":[ - { - "operator_address": "kavavaloper1qyc2cfl0nw8r95dsdw534x99wq0xcj9rmxpl7z", - "consensus_pubkey": "kavavalconspub1zcjduepqyj4j29k7hn58g7n6ert7mm4m7d0kllrx6h5rzzgpvjdt69r80zsq3az2xq", - "jailed": false, - "status": 2, - "tokens": "23006899100", - "delegator_shares": "23009200000.000000000000000000", - "description": { - "moniker": "Stake Capital", - "identity": "", - "website": "", - "security_contact": "", - "details": "'Trustless Digital Asset Management', Twitter: @StakeCapital, operated by @bneiluj @leopoldjoy" - }, - "unbonding_height": "1415519", - "unbonding_time": "2020-03-28T07:43:47.102756457Z", - "commission": { - "commission_rates": { - "rate": "0.500000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.500000000000000000" - }, - "update_time": "2020-02-05T09:55:51.495267155Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1qfy0e2w62g6j4jg5djcqd4py3zsaeqexjplj2d", - "consensus_pubkey": "kavavalconspub1zcjduepqftv90yrm4g4w4mq47rdx9f384yxegfx7qfpkft89x2nlzafv36pq47wgls", - "jailed": false, - "status": 2, - "tokens": "20069063571", - "delegator_shares": "20069063571.000000000000000000", - "description": { - "moniker": "DragonStake", - "identity": "EA61A46F31742B22", - "website": "https://dragonstake.io", - "security_contact": "dragonstake@protonmail.com", - "details": "Forking the Banks" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-11-20T18:38:18.607985797Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1q3y9qga5hf360dmzta67vp54qz25tmv4hhkk4t", - "consensus_pubkey": "kavavalconspub1zcjduepquu3m094f3j9jnklursgngn667tt3rz0ahpt4f7406qzqclc42mnqxlrn7e", - "jailed": false, - "status": 2, - "tokens": "20004700000", - "delegator_shares": "20004700000.000000000000000000", - "description": { - "moniker": "funky", - "identity": "1EBAA06E87B6DD60", - "website": "https://kava-funkyvalidator.nl", - "security_contact": "", - "details": "Validating with love in Holland for the world :)" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.110000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-21T00:42:13.651988876Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvl7z9xh", - "consensus_pubkey": "kavavalconspub1zcjduepqfkq6kfq6v3avvrc6qvh0tr6h97qhqxcxw6yhmsgwrclpm3qdqwwq4zl4kc", - "jailed": false, - "status": 2, - "tokens": "106190067334", - "delegator_shares": "106190067334.000000000000000000", - "description": { - "moniker": "WeStaking", - "identity": "DA9C5AD3E308E426", - "website": "https://westaking.io", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2020-03-17T04:24:29.070264845Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1pn5k9c5pxmg5f0rycpl9rrx6k6mk85scxf06zx", - "consensus_pubkey": "kavavalconspub1zcjduepq5gqsp02excuz03zequ5xkygsj8t0su4g46p00q9p0se5kkhr2fmsusw7w7", - "jailed": false, - "status": 2, - "tokens": "22999900000", - "delegator_shares": "22999900000.000000000000000000", - "description": { - "moniker": "Stir", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:45:39.203670522Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1phd8jz25lumudc7ac7rhmupvcqcv7lg3c8dprc", - "consensus_pubkey": "kavavalconspub1zcjduepquugppwhq0s4t5q8vh6n3j0t4t3susfasdfapa0zp8a8c36tpgj6qpqvs3s", - "jailed": false, - "status": 2, - "tokens": "2675001000000", - "delegator_shares": "2675001000000.000000000000000000", - "description": { - "moniker": "the_valiator", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-13T08:47:32.032003423Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1pceqe8we7drpfqrutchwy3f99800hhzuw6cc84", - "consensus_pubkey": "kavavalconspub1zcjduepqypw0nlaweu77hnlmy37gy82d0cn57g07yy9qrkm36tx5zhp6rjzqzfqta0", - "jailed": false, - "status": 2, - "tokens": "23459640449", - "delegator_shares": "23459640449.000000000000000000", - "description": { - "moniker": "Galaxy", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.500000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-11-25T09:53:43.24669958Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1rgcgqmnkeffks7enrv6hk5u4wg3nzfkmqlzjqd", - "consensus_pubkey": "kavavalconspub1zcjduepqv3f0m888swgzamf2mh3vh2gaehredz9uktv9rjcyfdjzvzvsthks4e5f4t", - "jailed": false, - "status": 2, - "tokens": "21000000000", - "delegator_shares": "21000000000.000000000000000000", - "description": { - "moniker": "syncnode", - "identity": "F422F328C14AFBFA", - "website": "wallet.syncnode.ro", - "security_contact": "", - "details": "https://www.linkedin.com/in/gbunea/" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.190000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-26T09:09:30.282258822Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1yrm63pqvld8uyzkavz55p2cktpm2gm8jd8xxlu", - "consensus_pubkey": "kavavalconspub1zcjduepq6nje57k4x0n0uua5dl26ufpgj9jw2n945hkrv066fv54924vnmeq60d92r", - "jailed": false, - "status": 2, - "tokens": "200010000000", - "delegator_shares": "200010000000.000000000000000000", - "description": { - "moniker": "Nodeasy.com", - "identity": "F7BABF2C95B02A9F", - "website": "https://www.nodeasy.com", - "security_contact": "", - "details": "Nodeasy.com,助你进入Staking时代!" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-12-04T03:53:57.870109232Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1yjj2wfers947l6n5pynpgsqlz7svc5n8ssl6ye", - "consensus_pubkey": "kavavalconspub1zcjduepqftnrqaely46s7tzfkczuqfecuk3664wks5www53x6cj7rtl90zhqq6pacf", - "jailed": false, - "status": 2, - "tokens": "20410000001", - "delegator_shares": "20410000001.000000000000000000", - "description": { - "moniker": "StakingHub", - "identity": "25D7A4013B5C2A8F", - "website": "http://www.stakinghub.net/", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-01-14T23:30:14.565194467Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1yna6lete8nwwwctsalzdg04ldqaz73gtn33ydq", - "consensus_pubkey": "kavavalconspub1zcjduepqzwu26st99545k4qp79vuuslynk5qaxne9z4ucjfzs5g6646klwrqg5dxfa", - "jailed": false, - "status": 2, - "tokens": "23163160000", - "delegator_shares": "23163160000.000000000000000000", - "description": { - "moniker": "ChainodeTech", - "identity": "E34BF744FF5BA8A9", - "website": "https://chainode.tech/", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:35:31.864391537Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper196anr2ycsalg806dz29afklnecuaupvkh5qz6c", - "consensus_pubkey": "kavavalconspub1zcjduepqh525w7mx9apyra8jqeclcs90e6u9p22jrqaw8ymuf7mug2m5cg6sw7v7yu", - "jailed": false, - "status": 2, - "tokens": "47900816757", - "delegator_shares": "47900816757.000000000000000000", - "description": { - "moniker": "Phorest 🌲", - "identity": "A5281CA10EBCDCB5", - "website": "http://phorest.xyz/kava", - "security_contact": "", - "details": "Secure and stable PoS validator" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2020-01-20T14:02:20.813362703Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1x9hq3rjc48t5upcsr3c209ycgekfasne3l5nkc", - "consensus_pubkey": "kavavalconspub1zcjduepqvrf8r43ymaj39x73luu4qsp9sn4sw4t2lh77799mau2739xtrlnsqxyqju", - "jailed": false, - "status": 2, - "tokens": "23114805000", - "delegator_shares": "23114805000.000000000000000000", - "description": { - "moniker": "Masternode24.de", - "identity": "7EBA7730A85C865C", - "website": "https://masternode24.de/", - "security_contact": "", - "details": "Investieren Sie mit uns zusammen in die besten Blockchain Projekte" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2020-02-20T16:21:56.085890332Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1xftqdxvq0xkv2mu8c5y0jrsc578tak4m9u0s44", - "consensus_pubkey": "kavavalconspub1zcjduepqngw3s4hpzj8xscq6dfg4m8a6qeh5xwau0sjrknmlvg2lqdlgp0zszj7ewc", - "jailed": false, - "status": 2, - "tokens": "28160800000", - "delegator_shares": "28160800000.000000000000000000", - "description": { - "moniker": "Ping.pub", - "identity": "6EA723DA332200B2", - "website": "", - "security_contact": "", - "details": "We are one of the most secure and stable validator, welcome to delegate to us. 我们是最安全,最稳定,性价比最高的验证人节点,欢迎委托给我们!" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.020000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-11-21T09:12:17.124698721Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1xka27j0jvmq97yunj5wp8fv242lycmax8ejlaf", - "consensus_pubkey": "kavavalconspub1zcjduepqx4zjl7vsh8pg4l3ndceu88h3027q0vvmpf7anv5c4xxq0htng5kqf24q07", - "jailed": false, - "status": 2, - "tokens": "3047139316200", - "delegator_shares": "3047139316200.000000000000000000", - "description": { - "moniker": "page2", - "identity": "", - "website": "https://coinmarketcap.com/2/", - "security_contact": "", - "details": "Lorem Ipsum" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.050000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1xhxzmj8fvkqn76knay9x2chfra826369dhdu2c", - "consensus_pubkey": "kavavalconspub1zcjduepqwsmxfu5vdulvnrwej06v4jj5hvdxxqqk82flvznhxkh5whrdnxms2z2kjx", - "jailed": false, - "status": 2, - "tokens": "1050206000000", - "delegator_shares": "1050206000000.000000000000000000", - "description": { - "moniker": "Figment Networks", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper18zksjhrefqew0zahmts894p8asscufxvdfq702", - "consensus_pubkey": "kavavalconspub1zcjduepq7qm0l9hy8m8a4my03x7rfvcy3vru0y0kv29n2fwcpmrvjda8n23skzza6m", - "jailed": false, - "status": 2, - "tokens": "14040219", - "delegator_shares": "14040219.000000000000000000", - "description": { - "moniker": "Consulnode", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-04T19:27:58.259245834Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper18s9m5d5cjf0humjv7mkq8pm47kchwm0r0369cx", - "consensus_pubkey": "kavavalconspub1zcjduepqphfe0vnahkpurcc6jn3kesfch6c0afnph8qv9ryx29gpec7rtf3q968vu3", - "jailed": false, - "status": 2, - "tokens": "20010000000", - "delegator_shares": "20010000000.000000000000000000", - "description": { - "moniker": "Stake5 Labs", - "identity": "C7595F18CC5D4FA6", - "website": "https://www.stake5labs.com", - "security_contact": "", - "details": "Professional PoS node contributor" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:01:13.609429004Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper18cf35l7req0k6ulqapeyv830mrrucn9xj87plr", - "consensus_pubkey": "kavavalconspub1zcjduepq7rr7drhvr6d67nydvwxtcqv3k0uv6krfn9ktm23l77eqrra9af9s828zrk", - "jailed": false, - "status": 2, - "tokens": "1171728959900", - "delegator_shares": "1171846144514.451445144514451445", - "description": { - "moniker": "mxcpospool", - "identity": "", - "website": "https://www.mxc.co", - "security_contact": "", - "details": "" - }, - "unbonding_height": "1433843", - "unbonding_time": "2020-03-29T19:11:06.277346205Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-13T10:05:51.300009009Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1g20mhvcpjxp6gzlwhtfcphjehwcl2njqydgu7q", - "consensus_pubkey": "kavavalconspub1zcjduepqcg7v7vpgw7tj2f4z6yle5vpwutm3n5zjmlx2dpypphxd0cdvyaeqyeyteg", - "jailed": false, - "status": 2, - "tokens": "23142100000", - "delegator_shares": "23142100000.000000000000000000", - "description": { - "moniker": "pi-londoner", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-02-10T23:44:11.226734593Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1gtd040dmljyaty9tkhq0mlqz7saer48v4d608x", - "consensus_pubkey": "kavavalconspub1zcjduepqqy2kzt636d5ak6l6gxsxexgtadcm8d59qh3wumgtswpa8hau7apsk4ecma", - "jailed": false, - "status": 2, - "tokens": "2391603214", - "delegator_shares": "2391603214.000000000000000000", - "description": { - "moniker": "kava.bi23", - "identity": "EB3470949B3E89E2", - "website": "https://kava.bi23.com", - "security_contact": "", - "details": "Bi23 focuses on the Crypto-Assets, providing customers with Staking and DeFi services." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-12-04T23:42:01.494010426Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1g4qpetrj59a29e4wxpe74x93q4df2czjh8r9ak", - "consensus_pubkey": "kavavalconspub1zcjduepqe3evdke2eyzv7ngkwj0w4qarpqad47s6eqsqavesmzhz664ewmzsre8fkj", - "jailed": false, - "status": 2, - "tokens": "978579000000", - "delegator_shares": "978579000000.000000000000000000", - "description": { - "moniker": "IOSG", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1ffcujj05v6220ccxa6qdnpz3j48ng024ykh2df", - "consensus_pubkey": "kavavalconspub1zcjduepqxzqld0trat9nu9j53rzxwvpnpjekxf02eeg8mw3xewjky2qgy69sgh0tcw", - "jailed": false, - "status": 2, - "tokens": "2207656905814", - "delegator_shares": "2207656905814.000000000000000000", - "description": { - "moniker": "🐠stake.fish", - "identity": "90B597A673FC950E", - "website": "http://stake.fish", - "security_contact": "", - "details": "stake.fish is a reliable validator for PoS blockchains. Stake with us. We know staking." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-12-03T18:59:42.821933888Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1fw7vjc3fphahqxpdjypddlulnltxws8g0mrds7", - "consensus_pubkey": "kavavalconspub1zcjduepq0hlydw7ztc5fp7e6k3snlafkz4h45tyaqzxxw5j87g4trdy826yskkmmgc", - "jailed": false, - "status": 2, - "tokens": "20090000000", - "delegator_shares": "20090000000.000000000000000000", - "description": { - "moniker": "BasBlock", - "identity": "E0A6A3980E464A66", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "1318309", - "unbonding_time": "2020-03-20T12:28:42.433079809Z", - "commission": { - "commission_rates": { - "rate": "0.130000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-02-01T11:28:28.795491395Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1fmas0qlsucg4qwf8mqyrylcg3uluz2ffg8952q", - "consensus_pubkey": "kavavalconspub1zcjduepqkv4fkh6u8l068xusy5dhz2jpz969nzszntuavsc0uu6sxxr9wafqewxkac", - "jailed": false, - "status": 2, - "tokens": "22612704810", - "delegator_shares": "22612704810.000000000000000000", - "description": { - "moniker": "mintonium", - "identity": "0FF7C542EF9422AB", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-11-15T14:00:18.218278987Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper12qn7y04wzr5s3h4dmdtre4q9f4nvc03a9a9qsz", - "consensus_pubkey": "kavavalconspub1zcjduepqsnl9ahysm5hypmpfuwyqkha280aa9ushdlvvqza4u7rfmf0pvdxqlla0wj", - "jailed": false, - "status": 2, - "tokens": "22996800100", - "delegator_shares": "22999100000.000000000000000000", - "description": { - "moniker": "dexhybrid", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "1321471", - "unbonding_time": "2020-03-20T18:38:12.071818929Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.020000000000000000" - }, - "update_time": "2019-11-16T14:33:31.092253347Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper12r77hhj6ylvvl4etjm0fmpzh07jum8u7qqd695", - "consensus_pubkey": "kavavalconspub1zcjduepq3ndp4jxqsvxlp5crspvu6tcra7zg7cnnxzm3hx6sxhcd409ytzyskcadfv", - "jailed": false, - "status": 2, - "tokens": "10000000", - "delegator_shares": "10000000.000000000000000000", - "description": { - "moniker": "stefansky", - "identity": "878AB3284CD8CBED", - "website": "http://stefancondurachi.com", - "security_contact": "", - "details": "Software Architect" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-02-03T05:32:50.725944775Z" - }, - "min_self_delegation": "1000000" - }, - { - "operator_address": "kavavaloper129kkennsm7na34lu6sn4kwxp7ewes58y4fx6y9", - "consensus_pubkey": "kavavalconspub1zcjduepqz354kpmk0970fpvhw6va6ufhasrnh4sgzh82cfd5egm9ggl5gy6qlgwqjt", - "jailed": false, - "status": 2, - "tokens": "23011000000", - "delegator_shares": "23011000000.000000000000000000", - "description": { - "moniker": "stake.zone", - "identity": "0A888728046018EC", - "website": "http://stake.zone", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.040000000000000000" - }, - "update_time": "2019-11-15T14:01:07.22222101Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper12g40q2parn5z9ewh5xpltmayv6y0q3zs6ddmdg", - "consensus_pubkey": "kavavalconspub1zcjduepq0plta99ns8ec5h5sj8x4ufzkdpsz6xu7ckp62hkagfxey242qzgstm0ldw", - "jailed": false, - "status": 2, - "tokens": "5085834241836", - "delegator_shares": "5085834241836.000000000000000000", - "description": { - "moniker": "P2P.ORG - P2P Validator", - "identity": "E12F4695036D8072", - "website": "https://p2p.org", - "security_contact": "vladimir.m@p2p.org", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper12et238paeqxyhvk2pfs20ygfj6ct0dx2ccsdz5", - "consensus_pubkey": "kavavalconspub1zcjduepqzmls593jxfkz8unn306c8nh757n24ztxhnzwzvpuadalk0skuvfsaamxwx", - "jailed": false, - "status": 2, - "tokens": "3000000", - "delegator_shares": "3000000.000000000000000000", - "description": { - "moniker": "hippo", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2020-03-10T14:45:34.603416711Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1t5l8ht0wxpd4lpe4cweftrpg5kyn3qp437yvnr", - "consensus_pubkey": "kavavalconspub1zcjduepqe58zj7f5zjqu023l3sd96qwurtzy7ayv2549z6mca8zmalvtlxfs80qsja", - "jailed": false, - "status": 2, - "tokens": "20517050000", - "delegator_shares": "20517050000.000000000000000000", - "description": { - "moniker": "DelegaNetworks", - "identity": "1BED7C08416A619F", - "website": "https://delega.io", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-11-24T20:37:25.840600387Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1vyx7wt8s8dwcspdt7dy49sq4l3jwyhxyndakmm", - "consensus_pubkey": "kavavalconspub1zcjduepq2v03gwaywadc7ar423rxmy7k7ev3y3tkvsetq7w30j0whymjkacsxjg9lt", - "jailed": false, - "status": 2, - "tokens": "2999557167252", - "delegator_shares": "2999557167252.000000000000000000", - "description": { - "moniker": "InfStones", - "identity": "39A41C2FDE0AD040", - "website": "https://infstones.io", - "security_contact": "", - "details": "Fueling Blockchain Beyond Infinity" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.010000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1vfawvtzvmcjkpqzhezvhk9q5tv5t7x8smz95uu", - "consensus_pubkey": "kavavalconspub1zcjduepq2yhf7ntk9dkkqpg07ead9nzjmldf2ar6tx6uz8jeaqjedrj9keqsq0hn02", - "jailed": false, - "status": 2, - "tokens": "23079000000", - "delegator_shares": "23079000000.000000000000000000", - "description": { - "moniker": "Newroad Network", - "identity": "91FAC10CA3718A17", - "website": "https://newroad.network/kava/", - "security_contact": "", - "details": "We provide a professional delegation service for multiple Proof of Stake networks. We use a secure and redundant setup. Visit our website for more information." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.350000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2020-02-03T04:21:51.013448233Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1vw35vclatlrcmzuaxf2fleyuk38xa7xf4vdaq2", - "consensus_pubkey": "kavavalconspub1zcjduepqnrpursauds6wjnqht0979kjr0pvk5jp4c0cv46feazqv4qappqsqn5rd22", - "jailed": false, - "status": 2, - "tokens": "875050100000", - "delegator_shares": "875050100000.000000000000000000", - "description": { - "moniker": "hashquark", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1vw4t8ge2ephu0wuhcmclcw04ag2vzj9rpdme2x", - "consensus_pubkey": "kavavalconspub1zcjduepq0fjxw9wq8swcrk26j2vk8qm90d0vn94c2c7cs0ru5rgy2zlyv5eq8q5kvc", - "jailed": false, - "status": 2, - "tokens": "20153000000", - "delegator_shares": "20153000000.000000000000000000", - "description": { - "moniker": "UbikCapital", - "identity": "8265DEAF50B61DF7", - "website": "https://ubik.capital", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.500000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-12-25T21:46:08.338409716Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1vuylvflgy75d8zr07ta8x0gcqynvkvw70et853", - "consensus_pubkey": "kavavalconspub1zcjduepqvk6tye9w7399g7xys6j5ycw5rly8wz92mp0pevgmrv30qc4nva5sc2u25u", - "jailed": false, - "status": 2, - "tokens": "1874980100000", - "delegator_shares": "1874980100000.000000000000000000", - "description": { - "moniker": "Lemniscap", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1dwae0ny4uuvacucakm9v8r8mxhw82zack4cn7y", - "consensus_pubkey": "kavavalconspub1zcjduepq3rfkl40umrfy0wq9u9m5mc5zv30x4lmj08vup2u5d90t4fu3qe7qvq5scl", - "jailed": false, - "status": 2, - "tokens": "3317768400000", - "delegator_shares": "3317768400000.000000000000000000", - "description": { - "moniker": "OKExPool", - "identity": "", - "website": "www.okex.com/pool", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-20T02:25:09.919481267Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1dj63l3z0smqa8au5yek37nmj0xd60zs9dwmdh0", - "consensus_pubkey": "kavavalconspub1zcjduepqq0hj2jx5x7p65t56c7s750e85yp0u6xvydk6eh5m45xq755rjqlsthzygr", - "jailed": false, - "status": 2, - "tokens": "20100000782", - "delegator_shares": "20100000782.000000000000000000", - "description": { - "moniker": "Yn", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:04:52.626128649Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1dntlhrw3jrej6ssdp64yfmkkz08ykyx4n7hphh", - "consensus_pubkey": "kavavalconspub1zcjduepqxd9wm06lw0p6nrysw2ecmusgrmsq6438ht4wh7gx64a0m6vnu4qs7jhyjk", - "jailed": false, - "status": 2, - "tokens": "4001049500000", - "delegator_shares": "4001049500000.000000000000000000", - "description": { - "moniker": "Staked", - "identity": "E7BFA6515FB02B3B", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-03T16:23:23.639110694Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1dede4flaq24j2g9u8f83vkqrqxe6cwzrxt5zsu", - "consensus_pubkey": "kavavalconspub1zcjduepqstxrft39yrg5hgalcnjqurms5tj2yqpw9y85axv9gsxyld62cneqg6k7nk", - "jailed": false, - "status": 2, - "tokens": "104328140934", - "delegator_shares": "104328140934.000000000000000000", - "description": { - "moniker": "POS Bakerz", - "identity": "3AFAE7268F4DFD10", - "website": "https://posbakerz.com/", - "security_contact": "", - "details": "Secure, Reliable and Efficient Staking-as-a-Service" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.098500000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-20T12:29:19.763049675Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1davtd9w5yadvlg5x7aw0kpkyhckk5m5ecrmnyl", - "consensus_pubkey": "kavavalconspub1zcjduepq9x39e7g3m2hv8v6nxcx2lmy6fzaeqmvdz4uqtpm8qaxtr6527yrsh3fkgl", - "jailed": false, - "status": 2, - "tokens": "23000000000", - "delegator_shares": "23000000000.000000000000000000", - "description": { - "moniker": "Cyberili", - "identity": "3554F49719B1BF6F", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:55:31.701406451Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1wtcn3ylrsp4qp4urlhkf78kkt8f2ch7p0f0p98", - "consensus_pubkey": "kavavalconspub1zcjduepqjffmrcy39vaecs9rjaju3hzq97nggr2l0zg96k2u3c54mfx20hks43wvdy", - "jailed": false, - "status": 2, - "tokens": "23124628440", - "delegator_shares": "23124628440.000000000000000000", - "description": { - "moniker": "007", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2020-03-20T19:41:53.352622226Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1wu8m65vqazssv2rh8rthv532hzggfr3h9azwz9", - "consensus_pubkey": "kavavalconspub1zcjduepqqg29usle4d3hgt4eadn3epppa2h6dsga9mj6sxvyj5prchufgr5qmrneka", - "jailed": false, - "status": 2, - "tokens": "5005157202698", - "delegator_shares": "5005157202698.000000000000000000", - "description": { - "moniker": "Binance Staking", - "identity": "", - "website": "https://binance.com", - "security_contact": "", - "details": "Exchange the world!" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1spkjjtwks5zt0dqexj8rv8ljwmwxe8ufkraukq", - "consensus_pubkey": "kavavalconspub1zcjduepq9gppak7hsjrwvyxz2y9hy830gzsx2r4nax43vh2lprj0wj3rvghsyu6xev", - "jailed": false, - "status": 2, - "tokens": "22950000000", - "delegator_shares": "22950000000.000000000000000000", - "description": { - "moniker": "Jupiter.IAM", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-17T11:35:54.989770823Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1srhded4xw0krcwlvddtcyycuh70fp5ry9yvp86", - "consensus_pubkey": "kavavalconspub1zcjduepq64ugztwcunjrpema5pqwherkfznms8ykc4jx7syc6tm5ztv58keqxlc6fv", - "jailed": false, - "status": 2, - "tokens": "2402020264361", - "delegator_shares": "2402020264361.000000000000000000", - "description": { - "moniker": "TRGCapital", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-12-12T17:38:19.894601876Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1s8akp0nq7z7vuf5g9agdswcwq7vm9uwudk0han", - "consensus_pubkey": "kavavalconspub1zcjduepqpgz29c6efzyj96y0kkjrxns67nsm5t3rae0ra2nmrx4fm5j33nkqn066rz", - "jailed": false, - "status": 2, - "tokens": "22950000000", - "delegator_shares": "22950000000.000000000000000000", - "description": { - "moniker": "IvoryTower", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-17T02:12:20.831453541Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper13fxkk4730cqglgdv7w0mdelyx07myyq76uf9f3", - "consensus_pubkey": "kavavalconspub1zcjduepquwqhhvst3t6pg7rzutmvr3dma46ux6nggfxrju4f6u2dza9n3l7s54jgu7", - "jailed": false, - "status": 2, - "tokens": "23213610000", - "delegator_shares": "23215931593.159315931593159315", - "description": { - "moniker": "Finantra.com", - "identity": "", - "website": "http://finantra.com", - "security_contact": "", - "details": "" - }, - "unbonding_height": "1122467", - "unbonding_time": "2020-03-04T18:59:03.214161979Z", - "commission": { - "commission_rates": { - "rate": "0.500000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2020-03-14T19:38:24.407313925Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper13vstf6ecmfe4p0gaufumk569sdawhtrf8gu56h", - "consensus_pubkey": "kavavalconspub1zcjduepq2ye3234dt2jes9g49mf5sdy7f7xfshekg5xyjm7vq7m07s9uq82qger9yk", - "jailed": false, - "status": 2, - "tokens": "23081092090", - "delegator_shares": "23081092090.000000000000000000", - "description": { - "moniker": "QuantaFrontier.com", - "identity": "", - "website": "https://QuantaFrontier.com", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.120000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2020-03-10T19:08:38.751434231Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper13dfu6et0m8zm4hachudvn62w0c2zvcmrqn8cs3", - "consensus_pubkey": "kavavalconspub1zcjduepqcctrta82mcm79j0e6ttgguekmljvud0y4rlggrm9uw9t49qemujsd69h59", - "jailed": false, - "status": 2, - "tokens": "23144338847", - "delegator_shares": "23144338847.000000000000000000", - "description": { - "moniker": "Sunshine", - "identity": "24DB71E8B5076192", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.300000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2020-04-05T16:35:57.63239062Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1jyuv7z9at27elvmnmzh2v39dc06r9kjcy59xkr", - "consensus_pubkey": "kavavalconspub1zcjduepqcznteuyudn9zmfzyu6cksgh9qv3e9sc9fkyu32djy9d29ertyjrqfwcnvj", - "jailed": false, - "status": 2, - "tokens": "2799950000000", - "delegator_shares": "2799950000000.000000000000000000", - "description": { - "moniker": "DAF", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.050000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1j26c4k2jj9tv95whdhva3e8v2fcm4s3dsgstd2", - "consensus_pubkey": "kavavalconspub1zcjduepq3ra0zhkgeyqzksspztcx475dtlra5lckdpzwht29mk9fuepnkjqsw2rly7", - "jailed": false, - "status": 2, - "tokens": "3269187409856", - "delegator_shares": "3269187409856.000000000000000000", - "description": { - "moniker": "DokiaCapital", - "identity": "", - "website": "https://staking.dokia.cloud", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.120000000000000000", - "max_rate": "0.120000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1jhraz4ftxl2pd37knmeua7wjxghmlskwf7x8pf", - "consensus_pubkey": "kavavalconspub1zcjduepq6rxswfd9puq5t7jlp52cetv5s7cqm4l4n5tx4gqsclg9ngswe45qwhz2dm", - "jailed": false, - "status": 2, - "tokens": "23443000000", - "delegator_shares": "23443000000.000000000000000000", - "description": { - "moniker": "mariposa2", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-12-26T13:44:37.328086675Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1jlzx4js09d9zzyuhuz8sfdweklrapzacuhsxq5", - "consensus_pubkey": "kavavalconspub1zcjduepqg94y638yaj7es28zdktmar4jn9wu0v2l4h8mr40gerr2rek8q3rq9d3gh6", - "jailed": false, - "status": 2, - "tokens": "3099479960136", - "delegator_shares": "3099479960136.000000000000000000", - "description": { - "moniker": "shiprekt", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1jl42l225565y3hm9dm4my33hjgdzleucqryhlx", - "consensus_pubkey": "kavavalconspub1zcjduepqtlmej0vprfmun69nsnmuv56j3dctzw90tmk0f805lqxcqn9sr77s4nzkx0", - "jailed": false, - "status": 2, - "tokens": "34047476004", - "delegator_shares": "34047476004.000000000000000000", - "description": { - "moniker": "melea-◮👁◭", - "identity": "4BE49EABAA41B8BF", - "website": "https://meleatrust.com/kava/", - "security_contact": "meleacrypto@gmail.com", - "details": "Validator service secure and trusted, awarded in Game Of Steaks" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.000000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-12-27T14:23:19.174760869Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1nxgg4grsc0fwh893mks62d3x3r6uazgpj3m3cr", - "consensus_pubkey": "kavavalconspub1zcjduepqkk7jeymtt9rk3jlhxtxu95akmxfusj44mqq2wuq8c2hckulpga0q4yrauv", - "jailed": false, - "status": 2, - "tokens": "23085863116", - "delegator_shares": "23085863116.000000000000000000", - "description": { - "moniker": "Easy 2 Stake", - "identity": "2C877AC873132C91", - "website": "www.easy2stake.com", - "security_contact": "", - "details": "Easy.Stake.Trust. As easy and as simple as you would click next. Complete transparency and trust with a secure and stable validator." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:00:10.631092707Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1njvaku4qg9pxmx9jgjks36xrxfd6fyqs3tgs4d", - "consensus_pubkey": "kavavalconspub1zcjduepqsxtm3s99l58x9e3sqfxx4z88v6t4pyhku6fnu60drwmq8zm4jwjqx257u9", - "jailed": false, - "status": 2, - "tokens": "1000002000000", - "delegator_shares": "1000002000000.000000000000000000", - "description": { - "moniker": "BitMax Staking", - "identity": "", - "website": "https://bitmax.io/", - "security_contact": "", - "details": "Trading Platform Industry Leader driven by Product Innovation" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-01-15T09:09:05.545733701Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1nnwwu4km0alut2q8vhg7zjt45wyehddpwlfrmj", - "consensus_pubkey": "kavavalconspub1zcjduepqey9flxqkdw5ewlskac3wltu4yl93asdamt66prm393zc8g93dcuszezutf", - "jailed": false, - "status": 2, - "tokens": "5681499001", - "delegator_shares": "5682067150.013579192799429688", - "description": { - "moniker": "Wetez", - "identity": "26FA2B24F46A98EF", - "website": "https://www.wetez.io", - "security_contact": "", - "details": "Wetez is the most professional team in the POS ( Proof of Stake) field.Wetez是POS领域最专业的团队,为POS带来的权益做更多赋能。" - }, - "unbonding_height": "448243", - "unbonding_time": "2020-01-11T04:03:40.112446434Z", - "commission": { - "commission_rates": { - "rate": "0.010000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-11-17T01:33:27.008856884Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper15kwwzz908wl0qv4w66a5ee70kytpmfc9khvah6", - "consensus_pubkey": "kavavalconspub1zcjduepq8ylkkt83ktmljrmmk7evkj600j3p9xjnm4kf44z33hyr3cum448sqw2a6j", - "jailed": false, - "status": 2, - "tokens": "6118996081", - "delegator_shares": "6118996081.000000000000000000", - "description": { - "moniker": "Staking4All", - "identity": "", - "website": "https://www.staking4all.org", - "security_contact": "", - "details": "Validator for Proof of Stake blockchains. Delegate to us for a easy staking experience" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-25T15:53:47.321864774Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper15urq2dtp9qce4fyc85m6upwm9xul3049dcs7da", - "consensus_pubkey": "kavavalconspub1zcjduepqsglrgfudcqw4la7e54lfdu2va9z5gd4r8z6wrwe8m5rtz3d2vtsq55njyr", - "jailed": false, - "status": 2, - "tokens": "2475995760455", - "delegator_shares": "2475995760455.000000000000000000", - "description": { - "moniker": "Chorus One", - "identity": "00B79D689B7DC1CE", - "website": "https://chorus.one", - "security_contact": "security@chorus.one", - "details": "Secure Kava and shape its future by delegating to Chorus One, a highly secure and stable validator. By delegating, you agree to the terms of service." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.075000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper14fkp35j5nkvtztmxmsxh88jks6p3w8u7p76zs9", - "consensus_pubkey": "kavavalconspub1zcjduepqlgrd20pqzw4dmkdkg3nd65mra077pjne8l0d43wsvw93y9dw450smyh79n", - "jailed": false, - "status": 2, - "tokens": "23654500000", - "delegator_shares": "23654500000.000000000000000000", - "description": { - "moniker": "Bit Cat🐱", - "identity": "FAB46CEEAEAB9FA1", - "website": "https://www.bitcat365.com", - "security_contact": "", - "details": "Secure and stable KAVA validator service from China team" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:01:37.718892109Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper140g8fnnl46mlvfhygj3zvjqlku6x0fwu6lgey7", - "consensus_pubkey": "kavavalconspub1zcjduepqvtvkhh22hgfvp865tj4uwltv0hu7fs3vwmxwrl0n2mdpfuzj0p0qes2k9e", - "jailed": false, - "status": 2, - "tokens": "4051502234537", - "delegator_shares": "4051502234537.000000000000000000", - "description": { - "moniker": "Cosmostation", - "identity": "AE4C403A6E7AA1AC", - "website": "https://www.cosmostation.io", - "security_contact": "", - "details": "Delegate your Kava and start earning your staking rewards." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.150000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-11-18T01:27:53.436530462Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper14kn0kk33szpwus9nh8n87fjel8djx0y02c7me3", - "consensus_pubkey": "kavavalconspub1zcjduepqk8fq7ssjps5r40j32lmhxrdzfg72k8dknc3xndljjtlghc9u9nrshrlf3r", - "jailed": false, - "status": 2, - "tokens": "2883221903903", - "delegator_shares": "2883221903903.000000000000000000", - "description": { - "moniker": "Forbole", - "identity": "2861F5EE06627224", - "website": "https://www.forbole.com", - "security_contact": "info@forbole.com", - "details": "Professional PoS validator based in Hong Kong" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.095000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1kgddca7qj96z0qcxr2c45z73cfl0c75p27tsg6", - "consensus_pubkey": "kavavalconspub1zcjduepqzah30dnsz855gnufkqlqnq50ksyc4jetprhz4ugg2rmuzhh3gvwsfxan38", - "jailed": false, - "status": 2, - "tokens": "2156193000000", - "delegator_shares": "2156193000000.000000000000000000", - "description": { - "moniker": "ChainLayer", - "identity": "AD3CDBC91802F94A", - "website": "https://www.chainlayer.io", - "security_contact": "", - "details": "Secure and reliable validator. TG: https://t.me/chainlayer" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.100000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1kwj4l5putuymgxw9kx8emh3e5dpaca0hnf3zdy", - "consensus_pubkey": "kavavalconspub1zcjduepqmqwfzwnmjdnkmt9k75k3q7rez3lr08m9fqev06rh6m2sdke8kmusjhywm9", - "jailed": false, - "status": 2, - "tokens": "23173000000", - "delegator_shares": "23173000000.000000000000000000", - "description": { - "moniker": "InChainWorks", - "identity": "BE448F9ECAB40ABE", - "website": "https://inchain.works", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-06T10:37:03.352901001Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1k4kxxfkhhwvyzxxxgksefkzpxahp9wfc572esl", - "consensus_pubkey": "kavavalconspub1zcjduepqt0k39t3zmz460are7rf9n97u20qhfmukp8ujeqhe0jg2q7ye99cqprr8nr", - "jailed": false, - "status": 2, - "tokens": "23215000000", - "delegator_shares": "23215000000.000000000000000000", - "description": { - "moniker": "Mr.K", - "identity": "74D3AF53635231D9", - "website": "", - "security_contact": "", - "details": "Validator on Tendermint base project" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.500000000000000000", - "max_rate": "0.500000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-11-29T03:49:52.013497324Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1kc6vzheht92jwf0gtzhjk6jjht67rxhal9z04v", - "consensus_pubkey": "kavavalconspub1zcjduepqt8065r783whzn3w47uuhm0t8rw2ke0zda6awa4j5lemlhw029mtqs79pcs", - "jailed": false, - "status": 2, - "tokens": "20028000000", - "delegator_shares": "20028000000.000000000000000000", - "description": { - "moniker": "moonli.me", - "identity": "662AEC27BD90D036", - "website": "https://moonli.me", - "security_contact": "", - "details": "How to Delegete: https://go.moonli.me/kava" - }, - "unbonding_height": "972523", - "unbonding_time": "2020-02-21T16:44:26.247476886Z", - "commission": { - "commission_rates": { - "rate": "0.120000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:03:28.153247409Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1k760ypy9tzhp6l2rmg06sq4n74z0d3rejwwaa0", - "consensus_pubkey": "kavavalconspub1zcjduepqqnxh5k4mhggtdx2u9j9xgq0etpkxpevg333sm954efqema6mn5yqqyf0gw", - "jailed": false, - "status": 2, - "tokens": "25190876386", - "delegator_shares": "25190876386.000000000000000000", - "description": { - "moniker": "novy", - "identity": "5422BE13389B2B4D", - "website": "https://novy.pw", - "security_contact": "", - "details": "Let's validate this network!" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-29T20:44:00.222304348Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1h9ulmhqv5e2373khk6s9n0wtrfc5qavre09fxl", - "consensus_pubkey": "kavavalconspub1zcjduepqjqsd0jkhftta7fuc9e45f3yat25ja9xknzrdqye6zk9kyx40wkaq50hcdv", - "jailed": false, - "status": 2, - "tokens": "23182088934", - "delegator_shares": "23182088934.000000000000000000", - "description": { - "moniker": "alexDcrypto", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.190000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-01-02T22:54:47.953329027Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1hezl6xwva28xt0hk204dllalagenmfsnuu50j6", - "consensus_pubkey": "kavavalconspub1zcjduepqwf05tj86hm83n55lha6zgeyf9jyyz053cwq957nhhv933v9z9sgqdcmt5s", - "jailed": false, - "status": 2, - "tokens": "169401100000", - "delegator_shares": "169401100000.000000000000000000", - "description": { - "moniker": "01node.com", - "identity": "22823CD59617B8E3", - "website": "https://01node.com", - "security_contact": "", - "details": "01node Staking Services" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.150000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:00:18.218278987Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1c9ye54e3pzwm3e0zpdlel6pnavrj9qqvh0atdq", - "consensus_pubkey": "kavavalconspub1zcjduepqc8585309s34yq92calayzy4xc4hu8rrx4pkrymewdy5qyjkx5tjqjgp7tq", - "jailed": false, - "status": 2, - "tokens": "4116869613316", - "delegator_shares": "4116869613316.000000000000000000", - "description": { - "moniker": "StakeWith.Us", - "identity": "609F83752053AD57", - "website": "https://stakewith.us", - "security_contact": "node@stakewith.us", - "details": "Secured Staking Made Easy. Put Your Crypto to Work - Hassle Free. Disclaimer: Delegators should understand that delegation comes with slashing risk. By delegating to StakeWithUs Pte Ltd, you acknowledge that StakeWithUs Pte Ltd is not liable for any losses on your investment." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.250000000000000000", - "max_change_rate": "0.050000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1cj9cdx9mg95lhvpquym08ncgzpjvhmnwdvm5kc", - "consensus_pubkey": "kavavalconspub1zcjduepq3w00ypwl5652c8unvwhn4urpkpcpztkusgqsdztdsq8fhycw224qwlcd33", - "jailed": false, - "status": 2, - "tokens": "868075391", - "delegator_shares": "868075391.000000000000000000", - "description": { - "moniker": "Sifu Ventures", - "identity": "", - "website": "http://sifu.ventures", - "security_contact": "", - "details": "dPos Tokens Investment Fund" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.050000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-24T08:49:40.805033852Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1ceun2qqw65qce5la33j8zv8ltyyaqqfctl35n4", - "consensus_pubkey": "kavavalconspub1zcjduepqsqtuf26ph4szcxutxscz5eq0g9tnqvedhdf203cha77m8xlnuy0sy3nky9", - "jailed": false, - "status": 2, - "tokens": "3266752395198", - "delegator_shares": "3266752395198.000000000000000000", - "description": { - "moniker": "sikka", - "identity": "", - "website": "https://sikka.tech", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.010000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper168g9nn9vnamhsnjkm7uqqee9f3v07flgwwddf9", - "consensus_pubkey": "kavavalconspub1zcjduepq29lrp34q3dveyt8r2mnc3kd82y5a5dsq39laj6yhkwans0ay2u9smmru3r", - "jailed": false, - "status": 2, - "tokens": "23164473513", - "delegator_shares": "23164473513.000000000000000000", - "description": { - "moniker": "sebytza05", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.140000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:00:18.218278987Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1645czvg787l0jr6mawhs9dm3mljnggj003yed9", - "consensus_pubkey": "kavavalconspub1zcjduepqws4aku5x2z0806kpyd750yzdpwrergpj82akyj0zz4ft6t38c4esdztwm8", - "jailed": false, - "status": 2, - "tokens": "23138575200", - "delegator_shares": "23143203500.319736666961944921", - "description": { - "moniker": "Mike Pocket", - "identity": "C57B29418AE33CC0", - "website": "", - "security_contact": "", - "details": "GO KAVA GO" - }, - "unbonding_height": "1426431", - "unbonding_time": "2020-03-29T04:47:39.676931865Z", - "commission": { - "commission_rates": { - "rate": "0.200000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-08T11:13:06.439174757Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper16lnfpgn6llvn4fstg5nfrljj6aaxyee9z59jqd", - "consensus_pubkey": "kavavalconspub1zcjduepquwh8pq39pwddp3etxk82d3u57kdfnvftgxamx4kcqduk8q02c3xqsyfaaa", - "jailed": false, - "status": 2, - "tokens": "2833230807310", - "delegator_shares": "2833230807310.000000000000000000", - "description": { - "moniker": "pylonvalidator", - "identity": "0979483D4F669CFF", - "website": "https://pylonvalidator.com", - "security_contact": "security@pylonvalidator.com", - "details": "'It doesn't matter whether the cat is black or white, as long as it catches mice.' --Deng Xiaoping" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "1.000000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1m9y0c7j7wxyu3nqtmeevyfzzpga8jhdyqw42wx", - "consensus_pubkey": "kavavalconspub1zcjduepqqpq85gztxdvheh48pugwp624mm6ey6u3464pj80c6s2epa8m9uwq4xr44m", - "jailed": false, - "status": 2, - "tokens": "1255000300000", - "delegator_shares": "1255000300000.000000000000000000", - "description": { - "moniker": "B-Harvest", - "identity": "8957C5091FBF4192", - "website": "https://bharvest.io", - "security_contact": "contact@bharvest.io", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-20T04:34:50.0221158Z" - }, - "min_self_delegation": "1000" - }, - { - "operator_address": "kavavaloper1mu78xhlr705mzgwqykcafp4xy3kgatvwzrww8z", - "consensus_pubkey": "kavavalconspub1zcjduepqhux83t9q55l0em60vq5a0p22zpf6kcqk3qs7cyzcc5huhycp6qnsutwsz3", - "jailed": false, - "status": 2, - "tokens": "21000000000", - "delegator_shares": "21000000000.000000000000000000", - "description": { - "moniker": "joesatri", - "identity": "649DD29EE41766EB", - "website": "", - "security_contact": "", - "details": "Game of Stakes Never Been Jailed Crew | Kava Founder Badge" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.110000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T15:01:47.310662882Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1uvz0vus7ktxt47cermscwe3k9gs7h9ag05sh6g", - "consensus_pubkey": "kavavalconspub1zcjduepq06xpflh9qkvgax8avl4wen49z48svsv4vplxk2jp2p4qx2htckzsfe2mwq", - "jailed": false, - "status": 2, - "tokens": "32995000000", - "delegator_shares": "32995000000.000000000000000000", - "description": { - "moniker": "Genesis Lab", - "identity": "C1A123F2723041F0", - "website": "https://genesislab.net", - "security_contact": "", - "details": "Genesis Lab is a blockchain-focused development company and validation nodes operator in PoS networks" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.070000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:15:12.174174763Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1udg4pal8c9gffv4l7zhvza027z0y345gd6esa6", - "consensus_pubkey": "kavavalconspub1zcjduepqpdjehvuwljjjp5se8t9xselu0hlneh2np3vrxwd0f4v6csdahclqktmkdp", - "jailed": false, - "status": 2, - "tokens": "1739934640784", - "delegator_shares": "1739934640784.000000000000000000", - "description": { - "moniker": "ATEAM", - "identity": "0CB9A4E7643FF992", - "website": "", - "security_contact": "", - "details": "Kava_Founding member | Cosmos_GOS: Never Jailed \u0026 Top-Tier | Terra_Validator Drill: Top 3 | IOV_Validator candidates score for mainnet: Top 5 | Lino_Founding Validator Prize Winners: Top 7 | IRISnet_Nyancat: Perfect score" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.050000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-11-19T01:30:06.727558554Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1u0kfndes0pf8dstaunsgumv7scsnmy09p3ln9r", - "consensus_pubkey": "kavavalconspub1zcjduepqxzxd363ej2v0kljvfvy5ff4dka90gnkkfemej9p6rkqv3zac9qhsy8p567", - "jailed": false, - "status": 2, - "tokens": "4800705821800", - "delegator_shares": "4800705821800.000000000000000000", - "description": { - "moniker": "SNZPool", - "identity": "FF2019D4CF1F3185", - "website": "https://snzholding.com", - "security_contact": "", - "details": "SNZ Pool is a professional \u0026 reliable POS validator for a dozen of projects like Cosmos, IRISnet, EOS, ONT, Loom, etc." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2019-11-15T14:18:22.510513847Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1u3jf6c2f85kmjldxsncnhsdp44nac7v5j7vzpc", - "consensus_pubkey": "kavavalconspub1zcjduepqvd3xz6346n447pvl3s3s73ee3zwwn54f4ejwjfue3ppvpjgdfxwqu95mqu", - "jailed": false, - "status": 2, - "tokens": "3314184935364", - "delegator_shares": "3314184935364.000000000000000000", - "description": { - "moniker": "HuobiPool", - "identity": "23536C5BDE3EB949", - "website": "https://www.huobipool.com/", - "security_contact": "", - "details": "Huobi Pool is a sub-brand of Huobi Group, which is an important part of the global ecological strategy of Huobi.Huobi Pool has become one of the largest POS communities in the Asia- Pacific region, the leading POW pool and nodes of a number of public chains." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-12T15:50:40.940881395Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1u3hqe2m7vm59l30tyaqd3zurz864dlsg7nq83f", - "consensus_pubkey": "kavavalconspub1zcjduepqrtnnezp4g67f7hh8fs7gtx23pmdfjwu37uqguq4hsrglqkfmyensl4xvdt", - "jailed": false, - "status": 2, - "tokens": "4039881397431", - "delegator_shares": "4040285425961.491814603996529363", - "description": { - "moniker": "Delchain", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "388052", - "unbonding_time": "2020-01-06T09:05:10.544078799Z", - "commission": { - "commission_rates": { - "rate": "0.050000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-05T14:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1uu9zguynwjyyyq57jnm3j2q47d5c362wafgsmf", - "consensus_pubkey": "kavavalconspub1zcjduepqn5uazvr3ew6ktstgshs9pfmh3vh9f9m36e76era3hxffxk8pr5asux5v9a", - "jailed": false, - "status": 2, - "tokens": "1000000", - "delegator_shares": "1000000.000000000000000000", - "description": { - "moniker": "sentry_lab", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "1.000000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-12-13T08:30:36.49152285Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1u7vsaanwt4e5mdzmxuqurmccxjka3h0ns2n3f5", - "consensus_pubkey": "kavavalconspub1zcjduepq7uy7ln7afmgrfutfpzhyy0llcndntx9q55nl5puqxcq5dqdzrnqswahrha", - "jailed": false, - "status": 2, - "tokens": "1000009950010", - "delegator_shares": "1000009950010.000000000000000000", - "description": { - "moniker": "BiKi Pool", - "identity": "", - "website": "https://www.biki.com", - "security_contact": "", - "details": "Popular Token's Choice" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-04T12:26:32.258743177Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1atelyappg8x4ndgtj6h2jng532a5hvuke2cajr", - "consensus_pubkey": "kavavalconspub1zcjduepqrwah2t8gezgv79stgnzju9ank4rpe85juf6xf4zzfhwgfawc5jpse287y0", - "jailed": false, - "status": 2, - "tokens": "567000000", - "delegator_shares": "567000000.000000000000000000", - "description": { - "moniker": "Nosce", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.007000000000000000", - "max_rate": "0.007700000000000000", - "max_change_rate": "0.000100000000000000" - }, - "update_time": "2020-02-19T04:09:38.903736876Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper1aj9r9ll8m72xr5pmxr9fmum88k864tqg39nkfu", - "consensus_pubkey": "kavavalconspub1zcjduepq9nq9gdnvtl5as9sgl92exde7hju797hl20c9htje2chgwnlkwluq8hmtu0", - "jailed": false, - "status": 2, - "tokens": "21000000000", - "delegator_shares": "21000000000.000000000000000000", - "description": { - "moniker": "kytzu", - "identity": "909A480D5643CCC5", - "website": "https://www.linkedin.com/in/calinchitu", - "security_contact": "", - "details": "Blockchain consultant and developer" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.190000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T16:04:53.477387115Z" - }, - "min_self_delegation": "1000000" - }, - { - "operator_address": "kavavaloper1ajwfalplxnhkwhsycfax36yyyxpxz3450s800x", - "consensus_pubkey": "kavavalconspub1zcjduepq33ekkklqez4tdd37mrvptrkawejnj0p5caa0a6c7efqs8n7eg37qa2vega", - "jailed": false, - "status": 2, - "tokens": "42770134655", - "delegator_shares": "42770134655.000000000000000000", - "description": { - "moniker": "Ryabina.io - Staking provider in awesome networks", - "identity": "6B1C8FDD84CF4ACD", - "website": "https://ryabina.io", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.010000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-02-24T18:08:47.865265697Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper17wcggpjx007uc09s8y4hwrj8f228mlwez945ey", - "consensus_pubkey": "kavavalconspub1zcjduepq5jtcd7kxpft40l65gm5p2ecg8rcxp59nml424u88lxkpxu6yl9cq6hxvzd", - "jailed": false, - "status": 2, - "tokens": "23092086042", - "delegator_shares": "23092086042.000000000000000000", - "description": { - "moniker": "Inotel", - "identity": "975D494265B1AC25", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2019-11-15T14:04:03.245058425Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "kavavaloper17498ffqdj49zca4jm7mdf3eevq7uhcsgjvm0uk", - "consensus_pubkey": "kavavalconspub1zcjduepq0mk39ccslman3ame4s3dn5exml8upqearp089sa5tae6pchdyrcsmvwmhn", - "jailed": false, - "status": 2, - "tokens": "23699000000", - "delegator_shares": "23699000000.000000000000000000", - "description": { - "moniker": "kaval", - "identity": "5281C9C7BE5C2646", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.550000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2020-03-07T10:24:27.851934685Z" - }, - "min_self_delegation": "1" - } - ]} - `); - } - } - - return {error: "Not implemented"}; - } -}; - diff --git a/mock/ext-api-dyson/get/kava-api-commands4.js b/mock/ext-api-dyson/get/kava-api-commands4.js deleted file mode 100644 index 09a878064..000000000 --- a/mock/ext-api-dyson/get/kava-api-commands4.js +++ /dev/null @@ -1,30 +0,0 @@ -/// Kava API Mock -/// See: -/// curl "http://localhost:3347/kava-api/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/delegations" -/// curl "https://{kava_rpc}/staking/delegators/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m/delegations" -/// curl "http://localhost:8437/v2/kava/staking/delegations/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m?Authorization=Bearer" - -module.exports = { - path: "/kava-api/:command1/:command2/:arg3/:arg4?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch(params.command1) { - case 'staking': - switch(params.command2) { - case 'delegators': - switch (params.arg3) { - case 'kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m': - switch (params.arg4) { - case 'delegations': - case 'unbonding_delegations': - return {height: "1793219", result: []}; - } - } - } - } - - return {error: "Not implemented"}; - } -}; - diff --git a/mock/ext-api-dyson/get/kava-api-txs.js b/mock/ext-api-dyson/get/kava-api-txs.js deleted file mode 100644 index 2fc327c9c..000000000 --- a/mock/ext-api-dyson/get/kava-api-txs.js +++ /dev/null @@ -1,277 +0,0 @@ -/// Kava API Mock -/// See: -/// curl "http://localhost:3347/kava-api/txs?transfer.recipient=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" -/// curl "http://localhost:3347/kava-api/txs?message.sender=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" -/// curl "http://{kava rpc}/txs?transfer.recipient=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" -/// curl "http://{kava rpc}/txs?message.sender=kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m&page=1&limit=25" -/// curl http://localhost:8437/v1/kava/kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m -module.exports = { - path: "/kava-api/txs?", - template: function(params, query, body) { - //console.log(query) - if (query["transfer.recipient"] === 'kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m') { - return JSON.parse(` - { - "total_count": "1", - "count": "1", - "page_number": "1", - "page_total": "1", - "limit": "25", - "txs": [ - { - "height": "793039", - "txhash": "84FFA6CC8428B7A5E82003A7BCA6D1FAB2DF296AD18BE73EE61CBCBF67623880", - "logs": [ - { - "msg_index": 0, - "success": true, - "log": "", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7" - }, - { - "key": "module", - "value": "bank" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - }, - { - "key": "amount", - "value": "9999000ukava" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "70019", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgSend", - "value": { - "from_address": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7", - "to_address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", - "amount": [ - { - "denom": "ukava", - "amount": "9999000" - } - ] - } - } - ], - "fee": { - "amount": [ - { - "denom": "ukava", - "amount": "1000" - } - ], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "As3eDIXFkLdMkBep+aV+6q9ccVRkA94snsXq2iL5bCTt" - }, - "signature": "QFx3iARLhLeuCCHRUbFAZTePzq+vGAYd4lB/F4JuCGYw1TrfIbAzJhmUHbXHcB/GC+f7Myv5xNrnlCPfCR53uA==" - } - ], - "memo": "" - } - }, - "timestamp": "2020-01-17T11:17:36Z", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "kava1g2rqynrdw22ca7y8a4cj3sncylspsg7r04fcr7" - }, - { - "key": "module", - "value": "bank" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - }, - { - "key": "amount", - "value": "9999000ukava" - } - ] - } - ] - } - ] - } - `); - } - - if (query["message.sender"] === 'kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m') { - return JSON.parse(` - { - "total_count": "1", - "count": "1", - "page_number": "1", - "page_total": "1", - "limit": "25", - "txs": [ - { - "height": "1101012", - "txhash": "30EFE9E830D317F84629F9DC35177577DF6713D78D354C2C469DE633900303BC", - "logs": [ - { - "msg_index": 0, - "success": true, - "log": "", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - }, - { - "key": "module", - "value": "bank" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" - }, - { - "key": "amount", - "value": "9998000ukava" - } - ] - } - ] - } - ], - "gas_wanted": "200000", - "gas_used": "68317", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgSend", - "value": { - "from_address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", - "to_address": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7", - "amount": [ - { - "denom": "ukava", - "amount": "9998000" - } - ] - } - } - ], - "fee": { - "amount": [ - { - "denom": "ukava", - "amount": "1000" - } - ], - "gas": "200000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "AvgGasyPvRpG68UQ6IGPVKN+HrJix24tgwcYXIcIfsna" - }, - "signature": "iST3iM8TtkR5VHTFFhJE1zi+Nh6Invrg4hKgLEY2HCQ+R6Qj9L3jET4yRtAg6+QxitJab27+etoPjJbK20V/Cw==" - } - ], - "memo": "100009547" - } - }, - "timestamp": "2020-02-11T01:33:46Z", - "events": [ - { - "type": "message", - "attributes": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - }, - { - "key": "module", - "value": "bank" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" - }, - { - "key": "amount", - "value": "9998000ukava" - } - ] - } - ] - } - ] - } - `); - } - - return {error: "Not implemented"}; - } -}; - diff --git a/mock/ext-api-dyson/get/kin-api-accounts.js b/mock/ext-api-dyson/get/kin-api-accounts.js deleted file mode 100644 index 8ed0c808b..000000000 --- a/mock/ext-api-dyson/get/kin-api-accounts.js +++ /dev/null @@ -1,96 +0,0 @@ -/// Kin API Mock, accounts -/// See: -/// curl "http://localhost:3347/kin-api/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?order=desc&limit=25" -/// curl "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?order=desc&limit=25" -/// curl http://localhost:8437/v1/kin/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH -module.exports = { - path: "/kin-api/accounts/:address/:operation?", - template: function(params, query, body) { - //console.log(query) - if (params.operation === 'payments') { - if (params.address === 'GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH') { - return JSON.parse(` - { - "_links": { - "self": { - "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?cursor=\u0026limit=25\u0026order=desc" - }, - "next": { - "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?cursor=31839477328764929\u0026limit=25\u0026order=desc" - }, - "prev": { - "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH/payments?cursor=32148096498577409\u0026limit=25\u0026order=asc" - } - }, - "_embedded": { - "records": [ - { - "_links": { - "self": { - "href": "https://horizon-block-explorer.kininfrastructure.com/operations/32148096498577409" - }, - "transaction": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a" - }, - "effects": { - "href": "https://horizon-block-explorer.kininfrastructure.com/operations/32148096498577409/effects" - }, - "succeeds": { - "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=32148096498577409" - }, - "precedes": { - "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=32148096498577409" - } - }, - "id": "32148096498577409", - "paging_token": "32148096498577409", - "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", - "type": "payment", - "type_i": 1, - "created_at": "2020-03-24T01:43:00Z", - "transaction_hash": "b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a", - "asset_type": "native", - "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", - "to": "GBWDEMV6IAU6HJP55VK3R7ZZSPL4GWHMCAC4WFBRBTN7TPPPYXFFH4AR", - "amount": "151431.00000" - }, - { - "_links": { - "self": { - "href": "https://horizon-block-explorer.kininfrastructure.com/operations/32134176509775873" - }, - "transaction": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed" - }, - "effects": { - "href": "https://horizon-block-explorer.kininfrastructure.com/operations/32134176509775873/effects" - }, - "succeeds": { - "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=desc\u0026cursor=32134176509775873" - }, - "precedes": { - "href": "https://horizon-block-explorer.kininfrastructure.com/effects?order=asc\u0026cursor=32134176509775873" - } - }, - "id": "32134176509775873", - "paging_token": "32134176509775873", - "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", - "type": "payment", - "type_i": 1, - "created_at": "2020-03-23T21:12:01Z", - "transaction_hash": "eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed", - "asset_type": "native", - "from": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", - "to": "GA5IZMCHFS54NN3I73ZAPQZWI7EKNXU6AP5QIVTEKJMPFW6I2GZVD3JO", - "amount": "4009823.45205" - } - ] - } - } - `); - } - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/kin-api-transactions.js b/mock/ext-api-dyson/get/kin-api-transactions.js deleted file mode 100644 index 34b3d37ad..000000000 --- a/mock/ext-api-dyson/get/kin-api-transactions.js +++ /dev/null @@ -1,111 +0,0 @@ -/// Kin API Mock, transactions -/// See: -/// curl "http://localhost:3347/kin-api/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a?" -/// curl "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a?" -/// curl http://localhost:8437/v1/kin/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX -module.exports = { - path: "/kin-api/transactions/:txid?", - template: function(params, query, body) { - //console.log(query) - if (params.txid === 'b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a') { - return JSON.parse(` - { - "memo": "Namilak8", - "_links": { - "self": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a" - }, - "account": { - "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH" - }, - "ledger": { - "href": "https://horizon-block-explorer.kininfrastructure.com/ledgers/7485062" - }, - "operations": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a/operations{?cursor,limit,order}", - "templated": true - }, - "effects": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a/effects{?cursor,limit,order}", - "templated": true - }, - "precedes": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=asc\u0026cursor=32148096498577408" - }, - "succeeds": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=desc\u0026cursor=32148096498577408" - } - }, - "id": "b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a", - "paging_token": "32148096498577408", - "hash": "b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a", - "ledger": 7485062, - "created_at": "2020-03-24T01:43:00Z", - "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", - "source_account_sequence": "3873257342118155", - "fee_paid": 100, - "operation_count": 1, - "envelope_xdr": "AAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAAAAZAANwrUAACkLAAAAAAAAAAEAAAAITmFtaWxhazgAAAABAAAAAQAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAAAEAAAAAbDIyvkAp46X97VW4/zmT18NY7BAFyxQxDNv5ve/FylMAAAAAAAAAA4aZXmAAAAAAAAAAATKoLogAAABAiivAdbjfQvWTMheamksBZp9yBc9oRN2E2OpPhTCeT/bICu6eSr3FJy+WqYlieBlXtdVbBaoCWOlR07Mi4QqjDQ==", - "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", - "result_meta_xdr": "AAAAAAAAAAEAAAAEAAAAAwByNoYAAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHRPE+rKwADcK1AAApCwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByNoYAAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHQWqlTkwADcK1AAApCwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwBwLBkAAAAAAAAAAGwyMr5AKeOl/e1VuP85k9fDWOwQBcsUMQzb+b3vxcpTAAAAAzCVZ9QAcAeUAAAAAwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByNoYAAAAAAAAAAGwyMr5AKeOl/e1VuP85k9fDWOwQBcsUMQzb+b3vxcpTAAAABrcuxjQAcAeUAAAAAwAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA", - "fee_meta_xdr": "AAAAAgAAAAMAcindAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR0TxPq0QAA3CtQAAKQoAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAcjaGAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR0TxPqysAA3CtQAAKQsAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==", - "memo_type": "text", - "signatures": [ - "iivAdbjfQvWTMheamksBZp9yBc9oRN2E2OpPhTCeT/bICu6eSr3FJy+WqYlieBlXtdVbBaoCWOlR07Mi4QqjDQ==" - ] - } - `); - } - if (params.txid === 'eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed') { - return JSON.parse(` - { - "memo": "", - "_links": { - "self": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed" - }, - "account": { - "href": "https://horizon-block-explorer.kininfrastructure.com/accounts/GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH" - }, - "ledger": { - "href": "https://horizon-block-explorer.kininfrastructure.com/ledgers/7481821" - }, - "operations": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed/operations{?cursor,limit,order}", - "templated": true - }, - "effects": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed/effects{?cursor,limit,order}", - "templated": true - }, - "precedes": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=asc\u0026cursor=32134176509775872" - }, - "succeeds": { - "href": "https://horizon-block-explorer.kininfrastructure.com/transactions?order=desc\u0026cursor=32134176509775872" - } - }, - "id": "eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed", - "paging_token": "32134176509775872", - "hash": "eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed", - "ledger": 7481821, - "created_at": "2020-03-23T21:12:01Z", - "source_account": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", - "source_account_sequence": "3873257342118154", - "fee_paid": 100, - "operation_count": 1, - "envelope_xdr": "AAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAAAAZAANwrUAACkKAAAAAAAAAAEAAAAAAAAAAQAAAAEAAAAATqpn4tSz1u76l93pz8ttLSIDQbslHppzlH1cgjKoLogAAAABAAAAADqMsEcsu8a3aP7yB8M2R8im3p4D+wRWZFJY8tvI0bNRAAAAAAAAAF1caQX1AAAAAAAAAAEyqC6IAAAAQFsrhOcyOXVWLIFf8aSJh37W1bx4ZP3qKXPejdB2M0z+FG09ggG0uDiV7FAsmRvzPUGoEgI3reEw+eAFByO6dAs=", - "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", - "result_meta_xdr": "AAAAAAAAAAEAAAAEAAAAAwByKaQAAAAAAAAAADqMsEcsu8a3aP7yB8M2R8im3p4D+wRWZFJY8tvI0bNRAAAAdGpUDqAAcik+AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByKd0AAAAAAAAAADqMsEcsu8a3aP7yB8M2R8im3p4D+wRWZFJY8tvI0bNRAAAA0ca9FJUAcik+AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAwByKd0AAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHok2nswUADcK1AAApCgAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQByKd0AAAAAAAAAAE6qZ+LUs9bu+pfd6c/LbS0iA0G7JR6ac5R9XIIyqC6IAABHRPE+rRAADcK1AAApCgAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA", - "fee_meta_xdr": "AAAAAgAAAAMAcimkAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR6JNp7NpAA3CtQAAKQkAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAcindAAAAAAAAAABOqmfi1LPW7vqX3enPy20tIgNBuyUemnOUfVyCMqguiAAAR6JNp7MFAA3CtQAAKQoAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==", - "memo_type": "text", - "signatures": [ - "WyuE5zI5dVYsgV/xpImHftbVvHhk/eopc96N0HYzTP4UbT2CAbS4OJXsUCyZG/M9QagSAjet4TD54AUHI7p0Cw==" - ] - } - `); - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/litecoin-api-address.js b/mock/ext-api-dyson/get/litecoin-api-address.js deleted file mode 100644 index 63a900e43..000000000 --- a/mock/ext-api-dyson/get/litecoin-api-address.js +++ /dev/null @@ -1,121 +0,0 @@ -/// Mock for external Litecoin API -/// See: -/// curl "http://{ltc rpc}/api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" -/// curl "http://localhost:3347/litecoin-api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs" -/// curl "http://localhost:8437/v1/litecoin/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - -module.exports = { - path: '/litecoin-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 'ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept': - return JSON.parse(` - { - "page": 1, - "totalPages": 10, - "itemsOnPage": 2, - "address": "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept", - "balance": "1688078", - "totalReceived": "25679292", - "totalSent": "23991214", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 19, - "transactions": [ - { - "txid": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1", - "version": 1, - "vin": [ - { - "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", - "vout": 1, - "n": 0, - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "isAddress": true, - "value": "788530" - } - ], - "vout": [ - { - "value": "100000", - "n": 0, - "hex": "0014ccf05f3bc453f7f66fb48b124bd79690bc309e22", - "addresses": [ - "ltc1qenc97w7y20mlvma53vfyh4ukjz7rp83zf892wx" - ], - "isAddress": true - }, - { - "value": "688078", - "n": 1, - "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "isAddress": true - } - ], - "blockHash": "ae8df4fb9cbbd07375eef217dd25e8b918a1b2746907c23cf4f2e15cd18fccdd", - "blockHeight": 1804076, - "confirmations": 25056, - "blockTime": 1583910871, - "value": "788078", - "valueIn": "788530", - "fees": "452", - "hex": "0100000000010167f89bc6125388f252bd770e142e61b9ab23dfb18762ba210f6f162bed92406701000000000000000002a086010000000000160014ccf05f3bc453f7f66fb48b124bd79690bc309e22ce7f0a00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100a40df50e2b419a35001f40d508e911f36d01497ebe5225dc93c81f53a30452fb022034c086517326be293019c2cbf215d6b9a53aa0ab4a0c2b890a9f1b05e8052aac012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" - }, - { - "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", - "version": 1, - "vin": [ - { - "txid": "f8ddc3eca55aa4bffd27b030fc3b35ceb8d503b31a03dafd32df56eec552fe99", - "vout": 1, - "sequence": 4294967290, - "n": 0, - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "isAddress": true, - "value": "1788982" - } - ], - "vout": [ - { - "value": "1000000", - "n": 0, - "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "isAddress": true - }, - { - "value": "788530", - "n": 1, - "spent": true, - "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "isAddress": true - } - ], - "blockHash": "dd92763dcb8477d8f012e5ec0598ebf3c135a15780d7491754fff40d3d24dd9b", - "blockHeight": 1803562, - "confirmations": 25570, - "blockTime": 1583831802, - "value": "1788530", - "valueIn": "1788982", - "fees": "452", - "hex": "0100000000010199fe52c5ee56df32fdda031ab303d5b8ce353bfc30b027fdbfa45aa5ecc3ddf80100000000faffffff0240420f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c532080c00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100bbde918ff538468c440424323bbe8ba78eef14d9dde357c8e6496905d540098c02205700d984884edff918f827289898c16ec9ad30344a637ea85dc55f7f836143bd012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/litecoin-api-xpub.js b/mock/ext-api-dyson/get/litecoin-api-xpub.js deleted file mode 100644 index cbe27e8e3..000000000 --- a/mock/ext-api-dyson/get/litecoin-api-xpub.js +++ /dev/null @@ -1,166 +0,0 @@ -/// Mock for external Litecoin API -/// See: -/// curl "http://{ltc rpc}/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs" -/// curl "http://localhost:3347/litecoin-api/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs" -/// curl "http://localhost:8437/v1/litecoin/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu" - -module.exports = { - path: '/litecoin-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu", - "balance": "1818078", - "totalReceived": "379622767", - "totalSent": "377804689", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 130, - "transactions": [ - { - "txid": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1", - "version": 1, - "vin": [ - { - "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", - "vout": 1, - "n": 0, - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "isAddress": true, - "value": "788530" - } - ], - "vout": [ - { - "value": "100000", - "n": 0, - "hex": "0014ccf05f3bc453f7f66fb48b124bd79690bc309e22", - "addresses": [ - "ltc1qenc97w7y20mlvma53vfyh4ukjz7rp83zf892wx" - ], - "isAddress": true - }, - { - "value": "688078", - "n": 1, - "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "isAddress": true - } - ], - "blockHash": "ae8df4fb9cbbd07375eef217dd25e8b918a1b2746907c23cf4f2e15cd18fccdd", - "blockHeight": 1804076, - "confirmations": 7532, - "blockTime": 1583910871, - "value": "788078", - "valueIn": "788530", - "fees": "452", - "hex": "0100000000010167f89bc6125388f252bd770e142e61b9ab23dfb18762ba210f6f162bed92406701000000000000000002a086010000000000160014ccf05f3bc453f7f66fb48b124bd79690bc309e22ce7f0a00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100a40df50e2b419a35001f40d508e911f36d01497ebe5225dc93c81f53a30452fb022034c086517326be293019c2cbf215d6b9a53aa0ab4a0c2b890a9f1b05e8052aac012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" - }, - { - "txid": "674092ed2b166f0f21ba6287b1df23abb9612e140e77bd52f2885312c69bf867", - "version": 1, - "vin": [ - { - "txid": "f8ddc3eca55aa4bffd27b030fc3b35ceb8d503b31a03dafd32df56eec552fe99", - "vout": 1, - "sequence": 4294967290, - "n": 0, - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "isAddress": true, - "value": "1788982" - } - ], - "vout": [ - { - "value": "1000000", - "n": 0, - "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "isAddress": true - }, - { - "value": "788530", - "n": 1, - "spent": true, - "hex": "00140ee85acd7206ba404a684e9655b54d32f242b7c5", - "addresses": [ - "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept" - ], - "isAddress": true - } - ], - "blockHash": "dd92763dcb8477d8f012e5ec0598ebf3c135a15780d7491754fff40d3d24dd9b", - "blockHeight": 1803562, - "confirmations": 8046, - "blockTime": 1583831802, - "value": "1788530", - "valueIn": "1788982", - "fees": "452", - "hex": "0100000000010199fe52c5ee56df32fdda031ab303d5b8ce353bfc30b027fdbfa45aa5ecc3ddf80100000000faffffff0240420f00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c532080c00000000001600140ee85acd7206ba404a684e9655b54d32f242b7c502483045022100bbde918ff538468c440424323bbe8ba78eef14d9dde357c8e6496905d540098c02205700d984884edff918f827289898c16ec9ad30344a637ea85dc55f7f836143bd012102872f9e841a8150ab716574ff897d915f575ed9abe9b4c9426617f6a1d8b3bbd100000000" - } - ], - "usedTokens": 123, - "tokens": [ - { - "type": "XPUBAddress", - "name": "ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept", - "path": "m/84'/2'/0'/0/0", - "transfers": 19, - "decimals": 8, - "balance": "1688078", - "totalReceived": "25679292", - "totalSent": "23991214" - }, - { - "type": "XPUBAddress", - "name": "ltc1q2rs8e2xy7tr7c5e4zugqzwsry5dtt5wcdk4zv9", - "path": "m/84'/2'/0'/0/54", - "transfers": 4, - "decimals": 8, - "balance": "20000", - "totalReceived": "2009886", - "totalSent": "1989886" - }, - { - "type": "XPUBAddress", - "name": "ltc1q2j0k8v7aczdajd42g96h7gy4jef63feh77494u", - "path": "m/84'/2'/0'/0/58", - "transfers": 3, - "decimals": 8, - "balance": "10000", - "totalReceived": "11000", - "totalSent": "1000" - }, - { - "type": "XPUBAddress", - "name": "ltc1qxpa5d35hnj29nr8yn5g5t0zd3m4jwp8mwchc9c", - "path": "m/84'/2'/0'/0/59", - "transfers": 1, - "decimals": 8, - "balance": "100000", - "totalReceived": "100000", - "totalSent": "0" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/nebulas-api-tx.js b/mock/ext-api-dyson/get/nebulas-api-tx.js deleted file mode 100644 index 3a990801b..000000000 --- a/mock/ext-api-dyson/get/nebulas-api-tx.js +++ /dev/null @@ -1,132 +0,0 @@ -/// Nebulas API Mock -/// See: -/// curl "http://localhost:3347/nebulas-api/tx?a=n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a&p=0" -/// curl "https://explorer-backend.nebulas.io/api/tx?a=n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a&p=0" -/// curl http://localhost:8437/v1/nebulas/n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a -module.exports = { - path: "/nebulas-api/tx?", - template: function(params, query, body) { - //console.log(query) - if (query.a === 'n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a') { - return JSON.parse(` - { - "code": 0, - "msg": "success", - "data": { - "txnList": [ - { - "hash": "3cd98a767d8f5eaa87c8ffa95adbde3a4c08236b49ab0296f04057491e4bd1a3", - "block": { - "hash": "9bb20444ae79a542af44ed64241a440759aa59363641fa1b7594266f6f16109d", - "height": 2659950, - "timestamp": null, - "parentHash": null, - "miner": null, - "txnCnt": 0, - "gasLimit": null, - "avgGasPrice": null, - "gasReward": null, - "currentTimestamp": null, - "timeDiff": null - }, - "from": { - "rank": null, - "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", - "alias": "", - "balance": "3784780000000000", - "percentage": null, - "txCnt": null, - "type": 0 - }, - "to": { - "rank": null, - "hash": "n1hiWG7Ce8HhTaJGzSJoAaJ9w1CJd7Do2rm", - "alias": "", - "balance": "200", - "percentage": null, - "txCnt": null, - "type": 1 - }, - "status": 1, - "value": "0", - "nonce": 1, - "timestamp": 1562378850000, - "type": "call", - "gasPrice": "20000000000", - "gasLimit": "50000", - "gasUsed": "20711", - "createdAt": 1562379080000, - "currentTimestamp": 1585045274097, - "timeDiff": 22666424097, - "contractAddress": "", - "executeError": "", - "events": null, - "tokenName": null, - "decimal": null, - "txFee": "414220000000000" - }, - { - "hash": "0d06074b64c37ed24a17162d1e0ef8a8e65122fc7758c90c969e61735bc4396a", - "block": { - "hash": "faf4eb93b1a571c709bf1871e1c142570d3f5aeb787d325eba9a34a6ca56144b", - "height": 2659949, - "timestamp": null, - "parentHash": null, - "miner": null, - "txnCnt": 0, - "gasLimit": null, - "avgGasPrice": null, - "gasReward": null, - "currentTimestamp": null, - "timeDiff": null - }, - "from": { - "rank": null, - "hash": "n1YDRkSbuzjRVYPbmGC9qULchXMeqS451Je", - "alias": "", - "balance": "37962400000000000000", - "percentage": null, - "txCnt": null, - "type": 0 - }, - "to": { - "rank": null, - "hash": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", - "alias": "", - "balance": "3784780000000000", - "percentage": null, - "txCnt": null, - "type": 0 - }, - "status": 1, - "value": "10000000000000000", - "nonce": 210, - "timestamp": 1562378835000, - "type": "binary", - "gasPrice": "20000000000", - "gasLimit": "50000", - "gasUsed": "20000", - "createdAt": 1562379063000, - "currentTimestamp": 1585045274097, - "timeDiff": 22666439097, - "contractAddress": "", - "executeError": "", - "events": null, - "tokenName": null, - "decimal": null, - "txFee": "400000000000000" - } - ], - "totalPage": 1, - "maxDisplayCnt": 16, - "type": "address", - "currentPage": 0, - "txnCnt": 2 - } - } - `); - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js b/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js deleted file mode 100644 index 59ff4a8f3..000000000 --- a/mock/ext-api-dyson/get/ontolotgy-api-v2-addresses.js +++ /dev/null @@ -1,123 +0,0 @@ -/// Ontology API Mock -/// See: -/// curl "http://localhost:3347/ontology-api/v2/addresses/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7/transactions?page_size=20&page_number=1" -/// curl "https://explorer.ont.io/v2/addresses/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7/transactions?page_size=20&page_number=1" -/// curl http://localhost:8437/v1/ontology/AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7 -module.exports = { - path: "/ontology-api/v2/addresses/:address/:operation?", - template: function(params, query, body) { - //console.log(params) - if (params.address === 'AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7') { - return JSON.parse(` - { - "code": 0, - "msg": "SUCCESS", - "result": [ - { - "tx_hash": "d3be042ae21a313bc70fbfea62d11fb32731126101859a66f523e081c3fd429c", - "tx_type": 209, - "tx_time": 1582189609, - "block_height": 7836941, - "fee": "0.01", - "block_index": 1, - "confirm_flag": 1, - "transfers": [ - { - "amount": "0.4", - "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "to_address": "Abm1FqnU4qur9bviXmrD5YnNixXGvMsi9R", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - }, - { - "amount": "0.01", - "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - } - ] - }, - { - "tx_hash": "5c9a5f708953ee6cd13623e9d3fd610530159fafe71a8d207d890ed7b97f3ced", - "tx_type": 209, - "tx_time": 1582188446, - "block_height": 7836832, - "fee": "0.01", - "block_index": 1, - "confirm_flag": 1, - "transfers": [ - { - "amount": "0.02", - "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - }, - { - "amount": "0.01", - "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - } - ] - }, - { - "tx_hash": "7e35568117aaed4e041d281087b2f47da91a4ac183c370d40040aa2b496d5878", - "tx_type": 209, - "tx_time": 1582122942, - "block_height": 7832679, - "fee": "0.01", - "block_index": 1, - "confirm_flag": 1, - "transfers": [ - { - "amount": "0.011074432", - "from_address": "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", - "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - }, - { - "amount": "0.01", - "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - } - ] - }, - { - "tx_hash": "0ae15301f25a5067c075a25e722f0624a813a1352363197de2dd5f61ebd2998d", - "tx_type": 209, - "tx_time": 1581924056, - "block_height": 7819845, - "fee": "0.01", - "block_index": 1, - "confirm_flag": 1, - "transfers": [ - { - "amount": "1", - "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "to_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "asset_name": "ont", - "contract_hash": "0100000000000000000000000000000000000000" - }, - { - "amount": "0.01", - "from_address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - } - ] - } - ] - } - `); - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/opensea-api-command1.js b/mock/ext-api-dyson/get/opensea-api-command1.js deleted file mode 100644 index 1aef38cdc..000000000 --- a/mock/ext-api-dyson/get/opensea-api-command1.js +++ /dev/null @@ -1,862 +0,0 @@ -/// OpenSea API Mock -/// See: - -/// curl "http://localhost:3347/opensea-api/api/v1/assets/?collection=unstoppable-domains&limit=300&owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d" -/// curl "https://api.opensea.io/api/v1/assets/?collection=unstoppable-domains&limit=300&owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d" -/// curl "http://localhost:8437/v4/ethereum/collections/0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d/collection/unstoppable-domains" - -/// curl "http://localhost:3347/opensea-api/api/v1/collections/?asset_owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d&limit=1000" -/// curl "https://api.opensea.io/api/v1/collections?asset_owner=0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d&limit=1000" -/// curl -d '{"60":["0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d"]}' http://localhost:8437/v4/collectibles/categories - -module.exports = { - path: "/opensea-api/api/v1/:command1/?", - template: function(params, query) { - switch (params.command1) { - case 'assets': - if (query.owner == '0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d' && - query.collection == 'unstoppable-domains') { - return JSON.parse(` - { - "assets": [ - { - "token_id": "107221826727469155718680588460379721284635325845036369130032935095484960793482", - "num_sales": 0, - "background_color": "4C47F7", - "image_url": "https://storage.opensea.io/files/fec912a0664aecaa908ee888177ebfc6.svg", - "image_preview_url": "https://lh3.googleusercontent.com/cqCHmaBgbAtaE5i-jRKLGbJy2C-AUnDXN8zpkw8JPKnqRNGXdMJme_ThTFL30mDN9u9piJ4ACcfHmmDAyaXfIocN=s250", - "image_thumbnail_url": "https://lh3.googleusercontent.com/cqCHmaBgbAtaE5i-jRKLGbJy2C-AUnDXN8zpkw8JPKnqRNGXdMJme_ThTFL30mDN9u9piJ4ACcfHmmDAyaXfIocN=s128", - "image_original_url": null, - "animation_url": null, - "animation_original_url": null, - "name": "sloth", - "description": "A .crypto blockchain domain. Use it to resolve your cryptocurrency addresses and decentralized websites.", - "external_link": "https://unstoppabledomains.com/search?searchTerm=sloth.crypto", - "asset_contract": { - "address": "0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe", - "asset_contract_type": "non-fungible", - "created_date": "2019-12-10T08:55:01.176657", - "name": ".crypto", - "nft_version": "3.0", - "opensea_version": null, - "owner": null, - "schema_name": "ERC721", - "symbol": "", - "total_supply": null, - "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", - "external_link": "https://unstoppabledomains.com/", - "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - }, - "owner": { - "user": null, - "profile_img_url": "https://storage.googleapis.com/opensea-static/opensea-profile/6.png", - "address": "0x84e79d544b4b13bc3560069cfd56a9d5bbe7521d", - "config": "", - "discord_id": "" - }, - "permalink": "https://opensea.io/assets/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/107221826727469155718680588460379721284635325845036369130032935095484960793482", - "collection": { - "banner_image_url": null, - "chat_url": null, - "created_date": "2019-12-10T08:55:01.591598", - "default_to_fiat": false, - "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", - "dev_buyer_fee_basis_points": "0", - "dev_seller_fee_basis_points": "0", - "display_data": { - "card_display_style": "padded", - "images": [ - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" - ] - }, - "external_url": "https://unstoppabledomains.com/", - "featured": false, - "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", - "hidden": false, - "safelist_request_status": "approved", - "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", - "is_subject_to_whitelist": false, - "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", - "name": "Unstoppable Domains", - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": "0", - "opensea_seller_fee_basis_points": "250", - "payout_address": null, - "require_email": false, - "short_description": null, - "slug": "unstoppable-domains", - "wiki_url": null - }, - "decimals": 0, - "auctions": null, - "sell_orders": [], - "traits": [ - { - "trait_type": "level", - "value": 2, - "display_type": null, - "max_value": null, - "trait_count": 0, - "order": null - }, - { - "trait_type": "domain", - "value": "sloth.crypto", - "display_type": null, - "max_value": null, - "trait_count": 1, - "order": null - }, - { - "trait_type": "type", - "value": "standard", - "display_type": null, - "max_value": null, - "trait_count": 52377, - "order": null - } - ], - "last_sale": null, - "top_bid": null, - "current_price": null, - "current_escrow_price": null, - "listing_date": null, - "is_presale": false, - "transfer_fee_payment_token": null, - "transfer_fee": null - }, - { - "token_id": "39602885785430968515488172908991286516392379555774938600072517130912304722435", - "num_sales": 0, - "background_color": "4C47F7", - "image_url": "https://storage.opensea.io/files/a9d70320f34fb5fb5183d1a9913d2267.svg", - "image_preview_url": "https://lh3.googleusercontent.com/vbjIXUNL8ghOTEn7W6j_ALfwbFl4EOaYdqZjIwmtgdPQ92kzTd3jJjk7fsjJuW2IKkCT80JPuJ6PX_dChnOKI0yK=s250", - "image_thumbnail_url": "https://lh3.googleusercontent.com/vbjIXUNL8ghOTEn7W6j_ALfwbFl4EOaYdqZjIwmtgdPQ92kzTd3jJjk7fsjJuW2IKkCT80JPuJ6PX_dChnOKI0yK=s128", - "image_original_url": null, - "animation_url": null, - "animation_original_url": null, - "name": "vikmeup", - "description": "A .crypto blockchain domain. Use it to resolve your cryptocurrency addresses and decentralized websites.", - "external_link": "https://unstoppabledomains.com/search?searchTerm=vikmeup.crypto", - "asset_contract": { - "address": "0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe", - "asset_contract_type": "non-fungible", - "created_date": "2019-12-10T08:55:01.176657", - "name": ".crypto", - "nft_version": "3.0", - "opensea_version": null, - "owner": null, - "schema_name": "ERC721", - "symbol": "", - "total_supply": null, - "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", - "external_link": "https://unstoppabledomains.com/", - "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - }, - "owner": { - "user": null, - "profile_img_url": "https://storage.googleapis.com/opensea-static/opensea-profile/6.png", - "address": "0x84e79d544b4b13bc3560069cfd56a9d5bbe7521d", - "config": "", - "discord_id": "" - }, - "permalink": "https://opensea.io/assets/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/39602885785430968515488172908991286516392379555774938600072517130912304722435", - "collection": { - "banner_image_url": null, - "chat_url": null, - "created_date": "2019-12-10T08:55:01.591598", - "default_to_fiat": false, - "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", - "dev_buyer_fee_basis_points": "0", - "dev_seller_fee_basis_points": "0", - "display_data": { - "card_display_style": "padded", - "images": [ - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" - ] - }, - "external_url": "https://unstoppabledomains.com/", - "featured": false, - "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", - "hidden": false, - "safelist_request_status": "approved", - "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", - "is_subject_to_whitelist": false, - "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", - "name": "Unstoppable Domains", - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": "0", - "opensea_seller_fee_basis_points": "250", - "payout_address": null, - "require_email": false, - "short_description": null, - "slug": "unstoppable-domains", - "wiki_url": null - }, - "decimals": 0, - "auctions": null, - "sell_orders": [], - "traits": [ - { - "trait_type": "level", - "value": 2, - "display_type": null, - "max_value": null, - "trait_count": 0, - "order": null - }, - { - "trait_type": "domain", - "value": "vikmeup.crypto", - "display_type": null, - "max_value": null, - "trait_count": 1, - "order": null - }, - { - "trait_type": "type", - "value": "standard", - "display_type": null, - "max_value": null, - "trait_count": 52377, - "order": null - } - ], - "last_sale": null, - "top_bid": null, - "current_price": null, - "current_escrow_price": null, - "listing_date": null, - "is_presale": false, - "transfer_fee_payment_token": null, - "transfer_fee": null - } - ] - } - `); - } - break; - - case 'collections': - if (query.asset_owner == '0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d') { - return JSON.parse(` - [ - { - "primary_asset_contracts": [ - { - "address": "0x1d963688fe2209a98db35c67a041524822cf04ff", - "asset_contract_type": "non-fungible", - "created_date": "2019-01-23T02:17:28.643618", - "name": "MarbleCards", - "nft_version": "3.0", - "opensea_version": null, - "owner": 204604, - "schema_name": "ERC721", - "symbol": "MRBLNFT", - "total_supply": null, - "description": "Claim the most amazing web pages. Remember that every web page can only be marbled once and by one person only. Once a card is created, that URL is claimed forever. Now go create some classics!", - "external_link": "https://marble.cards", - "image_url": "https://lh3.googleusercontent.com/JHs53JRA6f3VcBqqORnoL4_q4kLDeZkDgZkmbY3iziyQQ14IRtP3mQglePCmHpXE_fit88FH8cAFMUA3j54mivAA=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 250, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 500, - "payout_address": "0xee68e4c594b96efc19a9d7d2a33901651ce967a2" - } - ], - "traits": { - "Collection ID": { - "min": 1, - "max": 5865 - }, - "level": { - "min": 1, - "max": 100 - }, - "collection_id": { - "min": 1, - "max": 4033 - } - }, - "stats": { - "seven_day_volume": 1.01145277777778, - "seven_day_change": 4.163107594577744, - "total_volume": 350.909262241233, - "count": 57728, - "num_owners": 1091, - "market_cap": 3029.695577899588, - "average_price": 0.164129682994029, - "items_sold": 2026 - }, - "banner_image_url": null, - "chat_url": null, - "created_date": "2019-04-26T22:13:21.421079", - "default_to_fiat": false, - "description": "Claim the most amazing web pages. Remember that every web page can only be marbled once and by one person only. Once a card is created, that URL is claimed forever. Now go create some classics!", - "dev_buyer_fee_basis_points": "0", - "dev_seller_fee_basis_points": "250", - "display_data": { - "card_display_style": "contain", - "images": [ - "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18612-1552667321.png", - "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18905-1552770831.png", - "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18704-1552750420.png", - "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/8829-1550886013.png", - "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18951-1552772148.png", - "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff/18950-1552772146.png" - ] - }, - "external_url": "https://marble.cards", - "featured": false, - "featured_image_url": "https://storage.opensea.io/0x1d963688fe2209a98db35c67a041524822cf04ff-featured-1556589463.png", - "hidden": false, - "safelist_request_status": "approved", - "image_url": "https://lh3.googleusercontent.com/JHs53JRA6f3VcBqqORnoL4_q4kLDeZkDgZkmbY3iziyQQ14IRtP3mQglePCmHpXE_fit88FH8cAFMUA3j54mivAA=s60", - "is_subject_to_whitelist": false, - "large_image_url": "https://lh3.googleusercontent.com/JHs53JRA6f3VcBqqORnoL4_q4kLDeZkDgZkmbY3iziyQQ14IRtP3mQglePCmHpXE_fit88FH8cAFMUA3j54mivAA", - "name": "MarbleCards", - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": "0", - "opensea_seller_fee_basis_points": "250", - "payout_address": "0xee68e4c594b96efc19a9d7d2a33901651ce967a2", - "require_email": false, - "short_description": "Claim websites as unique crypto collectibles", - "slug": "marblecards", - "wiki_url": null, - "owned_asset_count": 1 - }, - { - "primary_asset_contracts": [ - { - "address": "0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85", - "asset_contract_type": "non-fungible", - "created_date": "2019-05-08T21:59:29.327544", - "name": "ENS", - "nft_version": "3.0", - "opensea_version": null, - "owner": 279872, - "schema_name": "ERC721", - "symbol": "ENS", - "total_supply": null, - "description": "Ethereum Name Service (ENS) domains are secure domain names for the decentralized world. ENS domains provide a way for users to map human readable names to blockchain and non-blockchain resources, like Ethereum addresses, IPFS hashes, or website URLs. ENS domains can be bought and sold on secondary markets.", - "external_link": "https://ens.domains", - "image_url": "https://lh3.googleusercontent.com/0cOqWoYA7xL9CkUjGlxsjreSYBdrUBE0c6EO1COG4XE8UeP-Z30ckqUNiL872zHQHQU5MUNMNhfDpyXIP17hRSC5HQ=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": "" - } - ], - "traits": { - "Length": { - "min": 3, - "max": 70 - } - }, - "stats": { - "seven_day_volume": 61.5400674228928, - "seven_day_change": 24.471538567710834, - "total_volume": 6330.17513707834, - "count": 352132, - "num_owners": 30272, - "market_cap": 349849.79099535465, - "average_price": 0.713098472127782, - "items_sold": 8868 - }, - "banner_image_url": null, - "chat_url": null, - "created_date": "2019-05-08T21:59:36.282454", - "default_to_fiat": false, - "description": "Ethereum Name Service (ENS) domains are secure domain names for the decentralized world. ENS domains provide a way for users to map human readable names to blockchain and non-blockchain resources, like Ethereum addresses, IPFS hashes, or website URLs. ENS domains can be bought and sold on secondary markets.", - "dev_buyer_fee_basis_points": "0", - "dev_seller_fee_basis_points": "0", - "display_data": { - "card_display_style": "cover", - "images": [ - "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/26693679858283927161893791132395207263838168762475401800426021835398462679008-1565293871.png", - "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/14216961695379335495094368768338390872453914418325715259759390099828279953313-1565293758.png", - "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/28032727276679833339346855127845420552876278365164540739421161968857583632995-1565293757.png", - "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/5939065732706496924433039736405736608461463576171087944642507927497598723058-1565293758.png", - "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/8268680357553423178495517182551079885250260646681574205692425339615070583014-1565293756.png", - "https://storage.opensea.io/0xfac7bea255a6990f749363002136af6556b31e04/96156505551778134260224136134970011352406026760333505247707872912354314952431-1565293756.png" - ] - }, - "external_url": "https://ens.domains", - "featured": false, - "featured_image_url": "https://storage.googleapis.com/opensea-static/official-ens-logo.png", - "hidden": false, - "safelist_request_status": "approved", - "image_url": "https://lh3.googleusercontent.com/0cOqWoYA7xL9CkUjGlxsjreSYBdrUBE0c6EO1COG4XE8UeP-Z30ckqUNiL872zHQHQU5MUNMNhfDpyXIP17hRSC5HQ=s60", - "is_subject_to_whitelist": false, - "large_image_url": "https://lh3.googleusercontent.com/0cOqWoYA7xL9CkUjGlxsjreSYBdrUBE0c6EO1COG4XE8UeP-Z30ckqUNiL872zHQHQU5MUNMNhfDpyXIP17hRSC5HQ", - "name": "Ethereum Name Service (ENS)", - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": "0", - "opensea_seller_fee_basis_points": "250", - "payout_address": "", - "require_email": false, - "short_description": null, - "slug": "ens", - "wiki_url": null, - "owned_asset_count": 2 - }, - { - "primary_asset_contracts": [ - { - "address": "0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c", - "asset_contract_type": "non-fungible", - "created_date": "2019-10-24T11:06:57.511707", - "name": "KnightStory Item", - "nft_version": "3.0", - "opensea_version": null, - "owner": 1672886, - "schema_name": "ERC721", - "symbol": "", - "total_supply": "1", - "description": "Knight Story is an innovative mobile RPG powered by blockchain. The game is the second title of Biscuit; developed EOS Knights, the legendary blockchain game.", - "external_link": "https://knightstory.io", - "image_url": "https://lh3.googleusercontent.com/Hwr0JNz9lHdTeu3mZTawVun-BdKRf-zSpi5ZUDxirBbPs_-hW92qHfh25QcTzeGCPy0FRULooZyTJ6MlRh8qaq4=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": "0x9702a479115788294232c384a5c1f42c881789fe" - } - ], - "traits": { - "hp": { - "min": 2, - "max": 5502 - }, - "defense (set)": { - "min": 70, - "max": 288 - }, - "attack (set)": { - "min": 60, - "max": 714 - }, - "score": { - "min": 28, - "max": 100 - }, - "luck": { - "min": 2, - "max": 1079 - }, - "magic_bean_purchase_bonus": { - "min": 2, - "max": 128 - }, - "luck (set)": { - "min": 40, - "max": 294 - }, - "defense": { - "min": 2, - "max": 2242 - }, - "hp (set)": { - "min": 60, - "max": 756 - }, - "None": { - "min": 0, - "max": 0 - }, - "attack": { - "min": 7, - "max": 5502 - } - }, - "stats": { - "seven_day_volume": 16.6826531170265, - "seven_day_change": -0.42001600555972113, - "total_volume": 555.213393323626, - "count": 39491, - "num_owners": 5650, - "market_cap": 1592.9963396829778, - "average_price": 0.0318228574152362, - "items_sold": 17443 - }, - "banner_image_url": null, - "chat_url": null, - "created_date": "2019-10-24T11:06:58.609791", - "default_to_fiat": false, - "description": "Knight Story is an innovative mobile RPG powered by blockchain. The game is the second title of Biscuit; developed EOS Knights, the legendary blockchain game.", - "dev_buyer_fee_basis_points": "0", - "dev_seller_fee_basis_points": "0", - "display_data": { - "card_display_style": "padded", - "images": [ - "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/1-1571915237.svg", - "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/2-1571982585.svg", - "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/6-1571984918.svg", - "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/5-1571984898.svg", - "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/4-1571984887.svg", - "https://storage.opensea.io/0x2fb5d7dda4f1f20f974a0fdd547c38674e8d940c/3-1571984879.svg" - ] - }, - "external_url": "https://knightstory.io", - "featured": false, - "featured_image_url": null, - "hidden": false, - "safelist_request_status": "approved", - "image_url": "https://lh3.googleusercontent.com/Hwr0JNz9lHdTeu3mZTawVun-BdKRf-zSpi5ZUDxirBbPs_-hW92qHfh25QcTzeGCPy0FRULooZyTJ6MlRh8qaq4=s60", - "is_subject_to_whitelist": false, - "large_image_url": "https://lh3.googleusercontent.com/Hwr0JNz9lHdTeu3mZTawVun-BdKRf-zSpi5ZUDxirBbPs_-hW92qHfh25QcTzeGCPy0FRULooZyTJ6MlRh8qaq4", - "name": "KnightStory", - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": "0", - "opensea_seller_fee_basis_points": "250", - "payout_address": "0x9702a479115788294232c384a5c1f42c881789fe", - "require_email": false, - "short_description": null, - "slug": "knightstory", - "wiki_url": null, - "owned_asset_count": 1 - }, - { - "primary_asset_contracts": [ - { - "address": "0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe", - "asset_contract_type": "non-fungible", - "created_date": "2019-12-10T08:55:01.176657", - "name": ".crypto", - "nft_version": "3.0", - "opensea_version": null, - "owner": null, - "schema_name": "ERC721", - "symbol": "", - "total_supply": null, - "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", - "external_link": "https://unstoppabledomains.com/", - "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - } - ], - "traits": { - "level": { - "min": 1, - "max": 3 - } - }, - "stats": { - "seven_day_volume": 8.232, - "seven_day_change": -0.43929053087580205, - "total_volume": 46.0238785864631, - "count": 56375, - "num_owners": 4213, - "market_cap": 8820.628142903694, - "average_price": 0.104362536477241, - "items_sold": 441 - }, - "banner_image_url": null, - "chat_url": null, - "created_date": "2019-12-10T08:55:01.591598", - "default_to_fiat": false, - "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", - "dev_buyer_fee_basis_points": "0", - "dev_seller_fee_basis_points": "0", - "display_data": { - "card_display_style": "padded", - "images": [ - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" - ] - }, - "external_url": "https://unstoppabledomains.com/", - "featured": false, - "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", - "hidden": false, - "safelist_request_status": "approved", - "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", - "is_subject_to_whitelist": false, - "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", - "name": "Unstoppable Domains", - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": "0", - "opensea_seller_fee_basis_points": "250", - "payout_address": null, - "require_email": false, - "short_description": null, - "slug": "unstoppable-domains", - "wiki_url": null, - "owned_asset_count": 2 - }, - { - "primary_asset_contracts": [ - { - "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - "asset_contract_type": "semi-fungible", - "created_date": "2019-08-02T23:43:14.666153", - "name": "Enjin", - "nft_version": null, - "opensea_version": null, - "owner": null, - "schema_name": "ERC1155", - "symbol": "", - "total_supply": null, - "description": "Enjin assets are unique digital ERC1155 assets used in a variety of games in the Enjin multiverse.", - "external_link": "https://enjinx.io/", - "image_url": "https://lh3.googleusercontent.com/pz9RPxNoHxFTJNNySYV5bXjsWlajAiDiI1A5m5OvUaS1fd8N64yViclbRQqM8HViBTIUPrYgQ-w49h36NHL0D1Y=s60", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - } - ], - "traits": {}, - "stats": { - "seven_day_volume": 0.6148, - "seven_day_change": 3.6330067822155234, - "total_volume": 284.785297517294, - "count": 34146, - "num_owners": 29430, - "market_cap": 907.2470250000015, - "average_price": 0.21673158106339, - "items_sold": 1306 - }, - "banner_image_url": null, - "chat_url": null, - "created_date": "2019-12-15T03:51:34.864843", - "default_to_fiat": false, - "description": "The season of giving is upon us, and we come bearing gifts! Join us in the spirit of giving to receive one of our first-ever Binance Collectibles! “HO HO HODL: Binance Collectibles Series 1.”", - "dev_buyer_fee_basis_points": "0", - "dev_seller_fee_basis_points": "0", - "display_data": { - "card_display_style": "contain", - "images": [ - "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727762-1576342335.jpg", - "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420726407-1576341423.jpg", - "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727252-1576342120.jpg", - "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727146-1576342000.jpg", - "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727063-1576341986.jpg", - "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50885195465617477053098479556454830685103047942629492242239710623321420727778-1576342346.jpg" - ] - }, - "external_url": "https://www.binance.com/en/blog/411120468693135360/Earn-a-Guaranteed-Binance-NFT--HO-HO-HODL-Binance-Collectibles-Series-1", - "featured": false, - "featured_image_url": null, - "hidden": false, - "safelist_request_status": "approved", - "image_url": "https://lh3.googleusercontent.com/vbRXgbAGZVvBQw5q-qmV0tF3HHKCJeomBz5oHFTehsv2q6xuY7UyndXSWgCWqj2GGJM77DLFP-vLNVnaKYnVoD8=s60", - "is_subject_to_whitelist": false, - "large_image_url": "https://lh3.googleusercontent.com/vbRXgbAGZVvBQw5q-qmV0tF3HHKCJeomBz5oHFTehsv2q6xuY7UyndXSWgCWqj2GGJM77DLFP-vLNVnaKYnVoD8", - "name": "Binance", - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": "0", - "opensea_seller_fee_basis_points": "250", - "payout_address": null, - "require_email": false, - "short_description": null, - "slug": "binance", - "wiki_url": null, - "owned_asset_count": 4 - }, - { - "primary_asset_contracts": [ - { - "address": "0x3eea5bf894236f4b7a6f1451bca89a9c91f49719", - "asset_contract_type": "non-fungible", - "created_date": "2019-12-24T15:08:28.581742", - "name": "Trust Collectible", - "nft_version": "3.0", - "opensea_version": null, - "owner": 1982280, - "schema_name": "ERC721", - "symbol": "", - "total_supply": "25", - "description": "Your friendly talkative crypto app.", - "external_link": "https://trustwallet.com", - "image_url": "https://storage.opensea.io/trust-collectible-1577200601.png", - "default_to_fiat": false, - "dev_buyer_fee_basis_points": 0, - "dev_seller_fee_basis_points": 0, - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": 0, - "opensea_seller_fee_basis_points": 250, - "buyer_fee_basis_points": 0, - "seller_fee_basis_points": 250, - "payout_address": null - } - ], - "traits": { - "level": { - "min": 2, - "max": 2 - }, - "generation": { - "min": 1, - "max": 1 - } - }, - "stats": { - "seven_day_volume": 0, - "seven_day_change": 0, - "total_volume": 1.12550814873532, - "count": 50, - "num_owners": 22, - "market_cap": 0, - "average_price": 0.0229695540558228, - "items_sold": 47 - }, - "banner_image_url": null, - "chat_url": null, - "created_date": "2019-12-24T15:08:28.833176", - "default_to_fiat": false, - "description": "Your friendly talkative crypto app.", - "dev_buyer_fee_basis_points": "0", - "dev_seller_fee_basis_points": "0", - "display_data": { - "card_display_style": "cover", - "images": [ - "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/1-1577200113.png", - "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/25-1577200136.png", - "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/24-1577200136.png", - "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/21-1577200135.png", - "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/23-1577200135.png", - "https://storage.opensea.io/0x3eea5bf894236f4b7a6f1451bca89a9c91f49719/22-1577200133.png" - ] - }, - "external_url": "https://trustwallet.com", - "featured": false, - "featured_image_url": null, - "hidden": false, - "safelist_request_status": "approved", - "image_url": "https://storage.opensea.io/trust-collectible-1577200601.png", - "is_subject_to_whitelist": false, - "large_image_url": "https://storage.opensea.io/trust-collectible-large-1577200602.png", - "name": "Trust Collectibles", - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": "0", - "opensea_seller_fee_basis_points": "250", - "payout_address": null, - "require_email": false, - "short_description": null, - "slug": "trust-collectible", - "wiki_url": null, - "owned_asset_count": 1 - }, - { - "primary_asset_contracts": [], - "traits": { - "level": { - "min": 2, - "max": 2 - } - }, - "stats": { - "seven_day_volume": 2.11109527819312, - "seven_day_change": 2.279116617261758, - "total_volume": 2.78059527819312, - "count": 14085, - "num_owners": 8511, - "market_cap": 126.33769191403255, - "average_price": 0.00896966218771974, - "items_sold": 310 - }, - "banner_image_url": null, - "chat_url": null, - "created_date": "2020-04-13T20:06:38.168795", - "default_to_fiat": false, - "description": "Simplify your crypto currency payments with human readable names and build censorship resistant websites. Purchase your blockchain domains today!", - "dev_buyer_fee_basis_points": "0", - "dev_seller_fee_basis_points": "0", - "display_data": { - "card_display_style": "padded", - "images": [ - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/100260309576151364545964131889528085814542346820268672379352985861671742542725-1576285529.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/4421676099993643179128103015054658901819404648065294942165491120042640407039-1576285527.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/73695583292838981607767254059063047756835875089503078348607895437407313924749-1576285524.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/27205116107504397094907367426483105387345010197719784382188136305164707242210-1576285522.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/101523982898827340730362103529507400599025467135859971366386174116683457290786-1576285522.png", - "https://storage.opensea.io/0xd1e5b0ff1287aa9f9a268759062e4ab08b9dacbe/113871464558189091408051847721365479982421488926705310425753631895495013528420-1576285520.png" - ] - }, - "external_url": "https://unstoppabledomains.com/", - "featured": false, - "featured_image_url": "https://storage.googleapis.com/opensea-static/featured-images/unstoppable-domains-featured.png", - "hidden": false, - "safelist_request_status": "approved", - "image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB=s60", - "is_subject_to_whitelist": false, - "large_image_url": "https://lh3.googleusercontent.com/Ak1PwcaxSjJmX2ZR4XN1GOYw1ZqQPlJo48FJaD_RHJykq9p_-lrmLDDv2x5cjgDncxJphoSkWL4hEPA_693aXHJB", - "name": "Unstoppable Domains Animals", - "only_proxied_transfers": false, - "opensea_buyer_fee_basis_points": "0", - "opensea_seller_fee_basis_points": "250", - "payout_address": null, - "require_email": false, - "short_description": null, - "slug": "unstoppable-domains-animals", - "wiki_url": null, - "owned_asset_count": 1 - } - ] - `); - } - break; - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/poa-api-commands1.js b/mock/ext-api-dyson/get/poa-api-commands1.js deleted file mode 100644 index 2bb424218..000000000 --- a/mock/ext-api-dyson/get/poa-api-commands1.js +++ /dev/null @@ -1,138 +0,0 @@ -/// POA API Mock -/// See: -/// curl "http://localhost:3347/poa-api/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" -/// curl "http://localhost:3347/poa-api/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "https://{poa rpc}/transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" -/// curl "https://{poa rpc}/tokens?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7" -/// curl "http://localhost:8437/v1/poa/0x55798eCbF17ce1241d543c22dCE46134c13b4bc0" -/// curl "http://localhost:8437/v2/poa/tokens/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?Authorization=Bearer" - -module.exports = { - path: '/poa-api/:command1?', - template: function(params, query, body) { - //console.log(params); - //console.log(query); - switch (params.command1) { - case 'tokens': - if (query.address === '0x0875BCab22dE3d02402bc38aEe4104e1239374a7') { - return JSON.parse(` - { - "total": 1, - "docs": [ - { - "address": "0xADFE00d92e5A16e773891F59780e6e54f40B532e", - "name": "Viktor Coin", - "decimals": 0, - "symbol": "VIK" - } - ] - } - `); - } - break; - - case 'transactions': - if (query.address === '0x55798eCbF17ce1241d543c22dCE46134c13b4bc0') { - return JSON.parse(` - { - "docs": [ - { - "operations": [ - { - "transactionId": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d-0", - "contract": { - "address": "0xab2f2dd3120de530d38936ee09a74a6d17e3da44", - "decimals": 18, - "name": "GeonCoin", - "symbol": "GC", - "totalSupply": "100000000000000000000000000", - "updatedAt": "2020-02-26T23:41:29.763Z" - }, - "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "to": "0xE87E46032847e097F5bB51404d19A0449c704EE8", - "type": "token_transfer", - "value": "1000000000000000000", - "id": null - } - ], - "contract": null, - "_id": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d", - "blockNumber": 14115901, - "time": 1584448420, - "nonce": 1, - "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "to": "0xAb2f2Dd3120dE530d38936EE09A74a6d17e3Da44", - "value": "0", - "gas": "120000", - "gasPrice": "1000000000", - "gasUsed": "78484", - "input": "0xb88a3f725e70c38d1d03b5568e2f4d1600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000", - "error": "", - "id": "0x544f5c54ad3c0b048ae81ef6f14507f934c4e53031bb2d39e074871c22f5ff9d", - "timeStamp": "1584448420" - }, - { - "operations": [], - "contract": null, - "_id": "0xcde1f2c3a262012f624065f167616db3160e763f4938ccfa0fcc742d5725eae2", - "blockNumber": 14115900, - "time": 1584448415, - "nonce": 109291, - "from": "0x628cF7150f8242b20B2ADB064D27183D2a026130", - "to": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "value": "600000000000000", - "gas": "120000", - "gasPrice": "1000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0xcde1f2c3a262012f624065f167616db3160e763f4938ccfa0fcc742d5725eae2", - "timeStamp": "1584448415" - }, - { - "operations": [], - "contract": null, - "_id": "0x90ef177d3448d379560218f99657027661a7238fb62c793dc2a7091a0d0d88e8", - "blockNumber": 14115899, - "time": 1584448410, - "nonce": 0, - "from": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "to": "0xE87E46032847e097F5bB51404d19A0449c704EE8", - "value": "0", - "gas": "120000", - "gasPrice": "1000000000", - "gasUsed": "100890", - "input": "0x1e76c9445e70c38d1d03b5568e2f4d160000000000000000000000000000000000000000", - "error": "", - "id": "0x90ef177d3448d379560218f99657027661a7238fb62c793dc2a7091a0d0d88e8", - "timeStamp": "1584448410" - }, - { - "operations": [], - "contract": null, - "_id": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3", - "blockNumber": 14115898, - "time": 1584448405, - "nonce": 109290, - "from": "0x628cF7150f8242b20B2ADB064D27183D2a026130", - "to": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "value": "600000000000000", - "gas": "120000", - "gasPrice": "1000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3", - "timeStamp": "1584448405" - } - ], - "total": 4 - } - `); - } - break; - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/qtum-api-address.js b/mock/ext-api-dyson/get/qtum-api-address.js deleted file mode 100644 index 1ee20d3e2..000000000 --- a/mock/ext-api-dyson/get/qtum-api-address.js +++ /dev/null @@ -1,160 +0,0 @@ -/// Mock for external Qtum API -/// See: -/// curl "http://{qtum rpc}/api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" -/// curl "http://localhost:3347/qtum-api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs" -/// curl "http://localhost:8437/v1/qtum/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" - -module.exports = { - path: '/qtum-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 'QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ': - return JSON.parse(` - { - "page": 1, - "totalPages": 3, - "itemsOnPage": 2, - "address": "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", - "balance": "235357610", - "totalReceived": "43335357610", - "totalSent": "43100000000", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 5, - "transactions": [ - { - "txid": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67", - "version": 1, - "vin": [ - { - "txid": "782e18a7b1bf612972e773fd6ccdcbe0c4514c661c31a7942f5dcd4807c5ab68", - "sequence": 4294967293, - "n": 0, - "addresses": [ - "QWLQSMPF5WKAqhXxePJvjUJNjxDHrPCbjB" - ], - "isAddress": true, - "value": "100000", - "hex": "483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1e" - }, - { - "txid": "80b7c6bcba625ad4abb69f7e92521a782681e984982408d40ad35a24b3f78297", - "sequence": 4294967294, - "n": 1, - "addresses": [ - "QgqVXuCCN1m4Hfb9HCkrzbgUSkoodKsrVY" - ], - "isAddress": true, - "value": "100000", - "hex": "48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5b" - }, - { - "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", - "sequence": 4294967292, - "n": 2, - "addresses": [ - "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" - ], - "isAddress": true, - "value": "10000000", - "hex": "473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbc" - }, - { - "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", - "vout": 1, - "sequence": 4294967291, - "n": 3, - "addresses": [ - "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" - ], - "isAddress": true, - "value": "225494620", - "hex": "483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3" - } - ], - "vout": [ - { - "value": "235357610", - "n": 0, - "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", - "addresses": [ - "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" - ], - "isAddress": true - } - ], - "blockHash": "6e71fa96ca29a6e4cbd10defaa4fc69ff09adec45fc666d82afade3f75206cc1", - "blockHeight": 563426, - "confirmations": 31109, - "blockTime": 1583720608, - "value": "235357610", - "valueIn": "235694620", - "fees": "337010", - "hex": "010000000468abc50748cd5d2f94a7311c664c51c4e0cbcd6cfd73e7722961bfb1a7182e78000000006b483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1efdffffff9782f7b3245ad30ad408249884e98126781a52927e9fb6abd45a62babcc6b780000000006b48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5bfeffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c000000006a473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbcfcffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c010000006b483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3fbffffff01aa45070e000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac00000000" - }, - { - "txid": "ef335bef783551cb054acd220555f1588cc4b03c0f47cc0839220c81d3ceb88d", - "version": 1, - "vin": [ - { - "txid": "506d07570d75914d5bd319d591374fb9cd1633f5c8b3cc800387e104298e8a62", - "vout": 1, - "sequence": 4294967294, - "n": 0, - "addresses": [ - "QfLtauKWxzF6pDf2ceXJe5oqizNHVMBneH" - ], - "isAddress": true, - "value": "198984808", - "hex": "4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081e" - }, - { - "txid": "e22c3e2ea4d285b71a73c41cdbb51f7c75d80b6f473e7f4aade6df5bf8771942", - "sequence": 4294967292, - "n": 1, - "addresses": [ - "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" - ], - "isAddress": true, - "value": "43000000000", - "hex": "483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764" - } - ], - "vout": [ - { - "value": "43000000000", - "n": 0, - "spent": true, - "hex": "76a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac", - "addresses": [ - "QURZqPoBfuXXoHDkCHCvhGJa1DP2Ahj1KX" - ], - "isAddress": true - }, - { - "value": "198831468", - "n": 1, - "spent": true, - "hex": "76a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac", - "addresses": [ - "QdfcTR3TQHjGHcKLiHmiPLRfVPFRWazJPg" - ], - "isAddress": true - } - ], - "blockHash": "918141389623f4f880b1ba279bb70ee91de6a005e1a9d523d21a66e8c55f0502", - "blockHeight": 393505, - "confirmations": 201030, - "blockTime": 1560879520, - "value": "43198831468", - "valueIn": "43198984808", - "fees": "153340", - "hex": "0100000002628a8e2904e1870380ccb3c8f53316cdb94f3791d519d35b4d91750d57076d50010000006b4830450221008676b34896a922ac913b0922319f98ab4bb5223f479c19d62b92f0f187b2759d02204e6c2f57337f9b3ef262e2262b3e04a971635c450fbe4278db8b2b25e5a816540121027f67fba269482ce4eecfbcc31e7acefaf17a8cb3b4f7ccfb5447c71688e1081efeffffff421977f85bdfe6ad4a7f3e476f0bd8757c1fb5db1cc4731ab785d2a42e3e2ce2000000006b483045022100e33513c3a4251a92af231c1d3e3bec9d13be2289c1fb203cb0096c6c073a8b840220206f696ee4e38da215f0b1e2c9d2005f085b8bb967d030caa70439046df64d4601210317cfe4e8b0e35f4c2c561921fe019910e3ddbe78d500a8ff546cf1843f723764fcffffff0200eeff020a0000001976a91455c89563888363b725aa0ebd8191a2e9ea54474d88ac6cedd90b000000001976a914bb29ba1df86d8507e0de32f187fe401cc3817fc388ac00000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/qtum-api-xpub.js b/mock/ext-api-dyson/get/qtum-api-xpub.js deleted file mode 100644 index 8893d2a03..000000000 --- a/mock/ext-api-dyson/get/qtum-api-xpub.js +++ /dev/null @@ -1,164 +0,0 @@ -/// Mock for external Qtum API -/// See: -/// curl "http://{qtum rpc}/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs" -/// curl "http://localhost:3347/qtum-api/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs" -/// curl "http://localhost:8437/v1/qtum/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd" - -module.exports = { - path: '/qtum-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd", - "balance": "235357610", - "totalReceived": "78913733296", - "totalSent": "78678375686", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 37, - "transactions": [ - { - "txid": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67", - "version": 1, - "vin": [ - { - "txid": "782e18a7b1bf612972e773fd6ccdcbe0c4514c661c31a7942f5dcd4807c5ab68", - "sequence": 4294967293, - "n": 0, - "addresses": [ - "QWLQSMPF5WKAqhXxePJvjUJNjxDHrPCbjB" - ], - "isAddress": true, - "value": "100000", - "hex": "483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1e" - }, - { - "txid": "80b7c6bcba625ad4abb69f7e92521a782681e984982408d40ad35a24b3f78297", - "sequence": 4294967294, - "n": 1, - "addresses": [ - "QgqVXuCCN1m4Hfb9HCkrzbgUSkoodKsrVY" - ], - "isAddress": true, - "value": "100000", - "hex": "48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5b" - }, - { - "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", - "sequence": 4294967292, - "n": 2, - "addresses": [ - "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" - ], - "isAddress": true, - "value": "10000000", - "hex": "473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbc" - }, - { - "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", - "vout": 1, - "sequence": 4294967291, - "n": 3, - "addresses": [ - "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" - ], - "isAddress": true, - "value": "225494620", - "hex": "483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3" - } - ], - "vout": [ - { - "value": "235357610", - "n": 0, - "hex": "76a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac", - "addresses": [ - "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ" - ], - "isAddress": true - } - ], - "blockHash": "6e71fa96ca29a6e4cbd10defaa4fc69ff09adec45fc666d82afade3f75206cc1", - "blockHeight": 563426, - "confirmations": 11012, - "blockTime": 1583720608, - "value": "235357610", - "valueIn": "235694620", - "fees": "337010", - "hex": "010000000468abc50748cd5d2f94a7311c664c51c4e0cbcd6cfd73e7722961bfb1a7182e78000000006b483045022100b660d73ff3bd7cc52d1052b933828cc2bb23b7a94500dff4bf00d5640ff4951702206ac6ecdaf3818dc57d54f8e860bbf212846200ccb2d1a323bf5b59868dcba872012102d7062f4af80f3a31f67c928e141627d807f0641b0bb0d466f4a62ee31230aa1efdffffff9782f7b3245ad30ad408249884e98126781a52927e9fb6abd45a62babcc6b780000000006b48304502210090ea4a4aac51d8734ad9ffecf0e5c14be50a8941b8cac6a492c002a0be99e5e102203550b52b7ad546adf8b1e5ed00b7aa755cc296d4bd61004b2ace43bfe0007d17012103692f9ee47370b3a70e8d7b6ac36c705b2d3296bb37c0f02e15158f3a6001ce5bfeffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c000000006a473044022055806e0939aa734d296ac364d4edf430bcd4fc15a377d35205362d09f7367d8e02202cc4e691c31ece66abb9adcd20bf8e3f500a2254edaaf2c241529cee670972440121025249520b3d48efd435e6cc30c9af238d054461d51f8beeaf75c4de50a647acbcfcffffffbef0e21e57bead973034708a81d3219aa23eaae20f53592e8a8607fab96e3a9c010000006b483045022100e9d2126507af25eed231d27db52794bf6dc67c33800ebafd99b44b13394e1a2d02206b5abdce728114fa75624cd50d70f3c7da77c5b00433fa306b203e4bfb7d96320121020d708ba820b87e195b5790fa2723033cfec259ce5af4270a431cd7297d7704d3fbffffff01aa45070e000000001976a9148b4f969602a4579f9c982e7d30c3a06e2f0cacc888ac00000000" - }, - { - "txid": "9c3a6eb9fa07868a2e59530fe2aa3ea29a21d3818a70343097adbe571ee2f0be", - "version": 1, - "vin": [ - { - "txid": "1d597a91e1810fdbfcb712c11c4776f5384ab4e7bd94a2fdc6538b9afdc1e6d0", - "vout": 1, - "sequence": 4294967292, - "n": 0, - "addresses": [ - "QZsdyvpJnczcDPJoySkNTaSh8VP8XAXeMz" - ], - "isAddress": true, - "value": "235607620", - "hex": "4730440220679ad69958629be2516a0d93457ba24f154fd42e23a4f3f2896272fe97940eed0220395098fa364232f74440e50043d6b2868829cb11faf56057d12f68f4bac82bdc0121036ea9140776d2e6a3ec7dd32b9795b47cf592e90e4159f7db793019b069e78b46" - } - ], - "vout": [ - { - "value": "10000000", - "n": 0, - "spent": true, - "hex": "76a9143dc1aae7701ab1f7be54fc69808c092ddb5a574088ac", - "addresses": [ - "QSEXLG5qct47UtMHiXNg2Y27KSDSAEHJp9" - ], - "isAddress": true - }, - { - "value": "225494620", - "n": 1, - "spent": true, - "hex": "76a914d40a0b271f69b1d2f43f60c540325c9039b4a05588ac", - "addresses": [ - "Qfw9Poi2c4gGEkAAuVyG21PsBmNGsmZKFC" - ], - "isAddress": true - } - ], - "blockHash": "a7a05f41f5f07faa5d3ca2cf5fb7de6a0cf46bc4ee465028ceda72ea5e6b5669", - "blockHeight": 479076, - "confirmations": 95362, - "blockTime": 1572922480, - "value": "235494620", - "valueIn": "235607620", - "fees": "113000", - "hex": "0100000001d0e6c1fd9a8b53c6fda294bde7b44a38f576471cc112b7fcdb0f81e1917a591d010000006a4730440220679ad69958629be2516a0d93457ba24f154fd42e23a4f3f2896272fe97940eed0220395098fa364232f74440e50043d6b2868829cb11faf56057d12f68f4bac82bdc0121036ea9140776d2e6a3ec7dd32b9795b47cf592e90e4159f7db793019b069e78b46fcffffff0280969800000000001976a9143dc1aae7701ab1f7be54fc69808c092ddb5a574088ac5cc6700d000000001976a914d40a0b271f69b1d2f43f60c540325c9039b4a05588ac00000000" - } - ], - "usedTokens": 33, - "tokens": [ - { - "type": "XPUBAddress", - "name": "QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", - "path": "m/44'/2301'/0'/0/0", - "transfers": 5, - "decimals": 8, - "balance": "235357610", - "totalReceived": "43335357610", - "totalSent": "43100000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/ravencoin-api-address.js b/mock/ext-api-dyson/get/ravencoin-api-address.js deleted file mode 100644 index b6bd59d37..000000000 --- a/mock/ext-api-dyson/get/ravencoin-api-address.js +++ /dev/null @@ -1,123 +0,0 @@ -/// Mock for external Ravencoin API -/// See: -/// curl "http://{Ravencoin rpc}/api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs" -/// curl "http://localhost:3347/ravencoin-api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs" -/// curl "http://localhost:8437/v1/ravencoin/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo" - -module.exports = { - path: '/ravencoin-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 'RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo", - "balance": "8525568094", - "totalReceived": "8525568094", - "totalSent": "0", - "unconfirmedBalance": "-8525568094", - "unconfirmedTxs": 1, - "txs": 1, - "transactions": [ - { - "txid": "fc226aad6fc28e1204b747042e8c8b25f5d28424b9669bd162ba6a0149df2f71", - "version": 2, - "lockTime": 1201754, - "vin": [ - { - "txid": "1222cb57d31bfb439e94080266c33ebb0134cdb90999a9fad99455d09a15159b", - "sequence": 4294967294, - "n": 0, - "addresses": [ - "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo" - ], - "isAddress": true, - "value": "8525568094", - "hex": "483045022100dc56832c815e7294dd51c7bb1ba342af80f5d25c3bc44c9689a55ccd94d18d01022063d3420930736fb1c1ab9a851ec0d1ff01dc906c66685b35972e3ab26b2d5d040121032dd4ba9d193e1912a6b48bd5642cb3579415ebabfc61e9fec9690fcd466dea15" - } - ], - "vout": [ - { - "value": "78460623", - "n": 0, - "hex": "76a9141657456724a83ca9e4c4cc0b65c98b6ffdba5bae88ac", - "addresses": [ - "RBKKVSR79YjBSGBE5pymUCaa871qogE5aY" - ], - "isAddress": true - }, - { - "value": "8446853390", - "n": 1, - "hex": "76a9142e664ae2c04d6292d50bcd65b644553eea7d7f1388ac", - "addresses": [ - "RDWXhkQyUkgmumGbzdR6JetLChVzUbStRq" - ], - "isAddress": true - } - ], - "blockHeight": -1, - "confirmations": 0, - "blockTime": 1587702074, - "value": "8525314013", - "valueIn": "8525568094", - "fees": "254081", - "hex": "02000000019b15159ad05594d9faa99909b9cd3401bb3ec3660208949e43fb1bd357cb2212000000006b483045022100dc56832c815e7294dd51c7bb1ba342af80f5d25c3bc44c9689a55ccd94d18d01022063d3420930736fb1c1ab9a851ec0d1ff01dc906c66685b35972e3ab26b2d5d040121032dd4ba9d193e1912a6b48bd5642cb3579415ebabfc61e9fec9690fcd466dea15feffffff02cf36ad04000000001976a9141657456724a83ca9e4c4cc0b65c98b6ffdba5bae88ac0ec178f7010000001976a9142e664ae2c04d6292d50bcd65b644553eea7d7f1388ac5a561200" - }, - { - "txid": "1222cb57d31bfb439e94080266c33ebb0134cdb90999a9fad99455d09a15159b", - "version": 2, - "lockTime": 1201750, - "vin": [ - { - "txid": "003d748c2c3541535093e840b4c5e54b966915eb522bac06028bc8d1376e1e63", - "sequence": 4294967294, - "n": 0, - "addresses": [ - "R9kyoRBmiF89o5ACFXF4EY7GawGjURP1Z5" - ], - "isAddress": true, - "value": "8530842427", - "hex": "47304402207ea927cfb1c7d8e14b067aa5b892cfde8b7b96b8bd95866b906c13e168581fd20220423bee1c4e25f66cc5ac27d94a33540307edb2a9a8874e800a1e1f875194dabf012103ded5613a24b22a8dc0c416f3ac4b436372a5b581b42e2d45f00fbd042cb066f1" - } - ], - "vout": [ - { - "value": "8525568094", - "n": 0, - "hex": "76a9145208b754b23169797a19e0ffaa9041ab5e29b9ef88ac", - "addresses": [ - "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo" - ], - "isAddress": true - }, - { - "value": "5020252", - "n": 1, - "spent": true, - "hex": "76a914bb7590eef377d63adcda0d080073035ad9a86bfc88ac", - "addresses": [ - "RSNPH2YPN69PNRj6BYq4V3orCyC7nahG9R" - ], - "isAddress": true - } - ], - "blockHash": "00000000000003efc9fb9dd4d5deb4e6ca393266191771d5d2e2426a191e69b3", - "blockHeight": 1201752, - "confirmations": 3, - "blockTime": 1587701825, - "value": "8530588346", - "valueIn": "8530842427", - "fees": "254081", - "hex": "0200000001631e6e37d1c88b0206ac2b52eb1569964be5c5b440e893505341352c8c743d00000000006a47304402207ea927cfb1c7d8e14b067aa5b892cfde8b7b96b8bd95866b906c13e168581fd20220423bee1c4e25f66cc5ac27d94a33540307edb2a9a8874e800a1e1f875194dabf012103ded5613a24b22a8dc0c416f3ac4b436372a5b581b42e2d45f00fbd042cb066f1feffffff025ed829fc010000001976a9145208b754b23169797a19e0ffaa9041ab5e29b9ef88ac5c9a4c00000000001976a914bb7590eef377d63adcda0d080073035ad9a86bfc88ac56561200" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/ravencoin-api-xpub.js b/mock/ext-api-dyson/get/ravencoin-api-xpub.js deleted file mode 100644 index f7ef19629..000000000 --- a/mock/ext-api-dyson/get/ravencoin-api-xpub.js +++ /dev/null @@ -1,176 +0,0 @@ -/// Mock for external Ravencoin API -/// See: -/// curl "http://{Ravencoin rpc}/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs" -/// curl "http://localhost:3347/ravencoin-api/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs" -/// curl "http://localhost:8437/v1/ravencoin/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B" - -module.exports = { - path: '/ravencoin-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B", - "balance": "299445646", - "totalReceived": "2599356720", - "totalSent": "2299911074", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 8, - "transactions": [ - { - "txid": "5d22e5a84b0eb054b623fdc3caf88a60eaa646dc97922f06d325aa8d6f18c564", - "version": 1, - "vin": [ - { - "txid": "baa2ee45ad8b9922a9db3fdcc22f8c3b5257dc81fef609800e7bd138748b6977", - "sequence": 4294967294, - "n": 0, - "addresses": [ - "RHhtrB8eUZuTp8m8HVEyGidEiSkSz5CRdM" - ], - "isAddress": true, - "value": "299456974", - "hex": "47304402204d44f9873e894314746557e4e7ba74e9436d7fa81986d0386684179d8acb77fe02206ff207862b3badbd41cc2ab584ff334410ab2bd089c6c4a1f6ffa59ce2b5d7da012102d34aee6afc67a1b86789beadf0ef2ed7dd5665776b734c0a4dba727bf532bd59" - } - ], - "vout": [ - { - "value": "299445646", - "n": 0, - "hex": "76a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac", - "addresses": [ - "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz" - ], - "isAddress": true - } - ], - "blockHash": "00000000000013c420937088dd9b69e5ef38c2c1e544828d222c1e8998d1358a", - "blockHeight": 843530, - "confirmations": 315623, - "blockTime": 1566071064, - "value": "299445646", - "valueIn": "299456974", - "fees": "11328", - "hex": "010000000177698b7438d17b0e8009f6fe81dc57523b8c2fc2dc3fdba922998bad45eea2ba000000006a47304402204d44f9873e894314746557e4e7ba74e9436d7fa81986d0386684179d8acb77fe02206ff207862b3badbd41cc2ab584ff334410ab2bd089c6c4a1f6ffa59ce2b5d7da012102d34aee6afc67a1b86789beadf0ef2ed7dd5665776b734c0a4dba727bf532bd59feffffff018e2dd911000000001976a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac00000000" - }, - { - "txid": "baa2ee45ad8b9922a9db3fdcc22f8c3b5257dc81fef609800e7bd138748b6977", - "version": 1, - "vin": [ - { - "txid": "0f517fd0d4e86070fdff40e95f5202a1b343f75d3168842feb2e8fd6f1be0ef9", - "n": 0, - "addresses": [ - "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz" - ], - "isAddress": true, - "value": "9990400", - "hex": "483045022100d8e3598c4d8829b39433c43d4a4c3c438754e8fa77284e1de606233b954770f2022034eb8b6ab6ca103f613d14ccc38fc6aea7bc8661dbff87b0c576b4712d202b3a012102ee0d81b0e40adde804683388953c9cef6276703a3d26e65f9f3433dff0b82dba" - }, - { - "txid": "b9db035506eaeb0de0dbc98a277c29f41c08317515538c79cdc542d759918004", - "vout": 1, - "n": 1, - "addresses": [ - "RGG4nwkVgFSpy5wdZVKkKFySUCz8N35B5L" - ], - "isAddress": true, - "value": "89988700", - "hex": "473044022075c8f6c3ce3de19c86bbaa845871e25af82ea40bb3793896e657dccbd350209a022033b983ef8733a74ca8e977e08c4ded3a027a800dedbe8aa65a06bca0dc87d09b012103d66703c2448791bcb6828c060de9c568853aa43a753ed227a1f14d70612d3144" - }, - { - "txid": "44172def2b5f799963adf28f0a3129e6f7910c8bc5ad09ad0e8155da24748d25", - "vout": 1, - "n": 2, - "addresses": [ - "RHj2wiQ8tDhJZKsNKsf48WzxAj2pVnhEnX" - ], - "isAddress": true, - "value": "199965874", - "hex": "4730440220601d4e0d8bc03cf5064dad0316cf61d996ec507aa92105711a0d480a561d9bbb02200acaf5ff2deed01fca255caeaeb63925097bad740adbfd952ab0df66fbfa8552012102eff42496547e74666a392bf8399072dc289ae1d1e835a1c7068650a76be44709" - } - ], - "vout": [ - { - "value": "299456974", - "n": 0, - "spent": true, - "hex": "76a9145c6d05bdca691ab3acfd59ad1a70e55aea1cece388ac", - "addresses": [ - "RHhtrB8eUZuTp8m8HVEyGidEiSkSz5CRdM" - ], - "isAddress": true - } - ], - "blockHash": "0000000000006c4af5eab913f98e03bb3ff45c8b580b88cbeba39b0748ec6f8c", - "blockHeight": 843527, - "confirmations": 315626, - "blockTime": 1566070929, - "value": "299456974", - "valueIn": "299944974", - "fees": "488000", - "hex": "0100000003f90ebef1d68f2eeb2f8468315df743b3a102525fe940fffd7060e8d4d07f510f000000006b483045022100d8e3598c4d8829b39433c43d4a4c3c438754e8fa77284e1de606233b954770f2022034eb8b6ab6ca103f613d14ccc38fc6aea7bc8661dbff87b0c576b4712d202b3a012102ee0d81b0e40adde804683388953c9cef6276703a3d26e65f9f3433dff0b82dba0000000004809159d742c5cd798c53157531081cf4297c278ac9dbe00debea065503dbb9010000006a473044022075c8f6c3ce3de19c86bbaa845871e25af82ea40bb3793896e657dccbd350209a022033b983ef8733a74ca8e977e08c4ded3a027a800dedbe8aa65a06bca0dc87d09b012103d66703c2448791bcb6828c060de9c568853aa43a753ed227a1f14d70612d314400000000258d7424da55810ead09adc58b0c91f7e629310a8ff2ad6399795f2bef2d1744010000006a4730440220601d4e0d8bc03cf5064dad0316cf61d996ec507aa92105711a0d480a561d9bbb02200acaf5ff2deed01fca255caeaeb63925097bad740adbfd952ab0df66fbfa8552012102eff42496547e74666a392bf8399072dc289ae1d1e835a1c7068650a76be447090000000001ce59d911000000001976a9145c6d05bdca691ab3acfd59ad1a70e55aea1cece388ac00000000" - }, - { - "txid": "0f517fd0d4e86070fdff40e95f5202a1b343f75d3168842feb2e8fd6f1be0ef9", - "version": 1, - "vin": [ - { - "txid": "b9db035506eaeb0de0dbc98a277c29f41c08317515538c79cdc542d759918004", - "n": 0, - "addresses": [ - "RArA49JQFoQZPZRUJqbnE6tp8fVRmAp8v7" - ], - "isAddress": true, - "value": "10000000", - "hex": "4830450221009370c852500b17d02ad9cc2f539a7b56fa237ccd108ec39b2e914fa9fdcde95e02203a730d6431a5e4ada7580644f0fc68ec57fc4e3519d8656e70790239bf12e6b501210214632a2120dc88ae7624ccb3e63534ae3c1d84aefe9f1b72ee23ba9876e3cbc6" - } - ], - "vout": [ - { - "value": "9990400", - "n": 0, - "spent": true, - "hex": "76a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac", - "addresses": [ - "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz" - ], - "isAddress": true - } - ], - "blockHash": "00000000000060b0a773ca5f98d4dfdfab1610d62c85f367aee85768852ba5f6", - "blockHeight": 741026, - "confirmations": 418127, - "blockTime": 1559880464, - "value": "9990400", - "valueIn": "10000000", - "fees": "9600", - "hex": "010000000104809159d742c5cd798c53157531081cf4297c278ac9dbe00debea065503dbb9000000006b4830450221009370c852500b17d02ad9cc2f539a7b56fa237ccd108ec39b2e914fa9fdcde95e02203a730d6431a5e4ada7580644f0fc68ec57fc4e3519d8656e70790239bf12e6b501210214632a2120dc88ae7624ccb3e63534ae3c1d84aefe9f1b72ee23ba9876e3cbc6000000000100719800000000001976a91469a82a3f4a8441d7eb0805e9c1ca421761eb456588ac00000000" - } - ], - "usedTokens": 7, - "tokens": [ - { - "type": "XPUBAddress", - "name": "RJurUyAqde3GLkDgkTzAuHHMbdMPMqfBsz", - "path": "m/44'/175'/0'/0/2", - "transfers": 3, - "decimals": 8, - "balance": "299445646", - "totalReceived": "309436046", - "totalSent": "9990400" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/ripple-get-accounts.js b/mock/ext-api-dyson/get/ripple-get-accounts.js deleted file mode 100644 index 11ec2dc72..000000000 --- a/mock/ext-api-dyson/get/ripple-get-accounts.js +++ /dev/null @@ -1,204 +0,0 @@ -/// Ripple API Mock -/// See: -/// curl "http://localhost:3347/ripple-api/accounts/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1/transactions?type=Payment&descending=false&limit=25" -/// curl "https://data.ripple.com/v2/accounts/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1/transactions?type=Payment&descending=false&limit=25" -/// curl http://localhost:8437/v1/ripple/rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1 -module.exports = { - path: "/ripple-api/accounts/:address/transactions?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - if (params.address === 'rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1') { - return JSON.parse(` - { - "result": "success", - "count": 2, - "transactions": [ - { - "hash": "20F2F95E4612296B1A82CC72F0DC53C9EAA8DA1557A0D0AD6C1E3BCA7E67E7CE", - "ledger_index": 44734671, - "date": "2019-01-28T19:22:50+00:00", - "tx": { - "TransactionType": "Payment", - "Flags": 2147483648, - "Sequence": 13, - "LastLedgerSequence": 44913253, - "Amount": "392834642660000", - "Fee": "500", - "SigningPubKey": "", - "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", - "Destination": "rUEchj8k8jvVXKGhfVYvrs5ntVEtc5F2hK", - "Signers": [ - { - "Signer": { - "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", - "TxnSignature": "30440220247A6624588612C73EEC2CD5F8D0A74E7FF7EE36E1ECFFF413703E928654824702205E9F5DB179A9146331935C5B5762AAAE52AE09EFDDEFDA6C596A53AE870464D2", - "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" - } - }, - { - "Signer": { - "SigningPubKey": "029A7A9E7A6175690C6E3D46EBBA33DA9EBF096EB5942E21C4A8C98F5606E6E6B8", - "TxnSignature": "304402201DFB1E6C459753DAAD5AA6D0D44501D5D1B067F18733E2DE23F3DA9E6F4A03E602201BD890DCDDA34E8304C7C29209EAAB3C34DE07C9FD4CF2537848EA4CA02FA1BB", - "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" - } - }, - { - "Signer": { - "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", - "TxnSignature": "304402205E1D7DE31B9E88848E370AD7D5D77FF16CED0807A3514918BA41718040A9721F02207A832DA5575C0B66B9FF0AC6C1C0BFAF15359727221A97D2027A69CFDA953297", - "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" - } - }, - { - "Signer": { - "SigningPubKey": "0368CFF85FEF68857A445A3F51FFC6119F2A113C9590E898351CE49F61BA71E6E8", - "TxnSignature": "304402204BB844E6102A40079C9616AB888C7332F000353665B4FA972525B261DB3DDED6022018586112E834D6BC3A2A2151A4F39304B1357EB11617EE84ED55D862D7978E7C", - "Account": "rP5xpZ5KzPih69fLhG3NYvZEDfLmSEViUk" - } - } - ] - }, - "meta": { - "TransactionIndex": 2, - "AffectedNodes": [ - { - "ModifiedNode": { - "LedgerEntryType": "AccountRoot", - "PreviousTxnLgrSeq": 44734265, - "PreviousTxnID": "AB83FFE7B46FF4E44BC084DFBEBBCFAA09913770766CCBFC0B1858E8195CE94E", - "LedgerIndex": "459E688FB21500B75D59CBFA49EB4C17C54E81D32A7A69CF1910691AB6AA4DCC", - "PreviousFields": { - "Balance": "392834747660000" - }, - "FinalFields": { - "Flags": 0, - "Sequence": 1, - "OwnerCount": 0, - "Balance": "785669390320000", - "Account": "rUEchj8k8jvVXKGhfVYvrs5ntVEtc5F2hK" - } - } - }, - { - "ModifiedNode": { - "LedgerEntryType": "AccountRoot", - "PreviousTxnLgrSeq": 44734265, - "PreviousTxnID": "AB83FFE7B46FF4E44BC084DFBEBBCFAA09913770766CCBFC0B1858E8195CE94E", - "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", - "PreviousFields": { - "Sequence": 13, - "Balance": "4123164791269591" - }, - "FinalFields": { - "Flags": 1048576, - "Sequence": 14, - "OwnerCount": 10, - "Balance": "3730330148609091", - "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" - } - } - } - ], - "TransactionResult": "tesSUCCESS", - "delivered_amount": "392834642660000" - } - }, - { - "hash": "000BC2AFC047BE45C43886109720F44B6F3F2434D59B1A16A9B2B4FC9B9C5A13", - "ledger_index": 51969362, - "date": "2019-12-11T00:00:01+00:00", - "tx": { - "TransactionType": "Payment", - "Flags": 2147483648, - "Sequence": 14, - "LastLedgerSequence": 52151515, - "Amount": "220303137120000", - "Fee": "5000", - "SigningPubKey": "", - "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", - "Destination": "r3a8tn1ubcP13np3giaLYzkmVKfnhLP2BL", - "Signers": [ - { - "Signer": { - "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", - "TxnSignature": "3045022100BC1FBB9457B5A8684AACA1E949DB2640CE1D0C9907AA060D334655F4162D27D0022028DD17C6E2AAD9863D2FA7BE7F0D80D4181CB9B9349371959E5DB2D69BF662D3", - "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq" - } - }, - { - "Signer": { - "SigningPubKey": "029A7A9E7A6175690C6E3D46EBBA33DA9EBF096EB5942E21C4A8C98F5606E6E6B8", - "TxnSignature": "3044022014FA8252577C836D14D796B59C74F377A23EE1D335AEB68ED21A4BF5D4D05BBE022054361EEC50A8F3C4A4AF4EFE61C83B399F7B5240C42C2FD4BBBCEAB1CFF138B4", - "Account": "rHH2gS6XikKoEt9i1xAxEBvXLHKFr7oLn8" - } - }, - { - "Signer": { - "SigningPubKey": "03797EFEC20C8DBF46C20FCC75AB22168AAC34D9E18BFD81C3CC007DC80C389686", - "TxnSignature": "3045022100B407D26B1A4ABAA6C0BC9C99EDB0DCB280852EF21974D82C8C8E5866FB08187A02207255B8CD26CCEFD8ACA1DD63A767CCC127AE6EA2115CC2F89D1B798EBFA3316C", - "Account": "rMY6Wm2RWQLN4d3Jjz15MKP74GJWVQE2pb" - } - }, - { - "Signer": { - "SigningPubKey": "0368CFF85FEF68857A445A3F51FFC6119F2A113C9590E898351CE49F61BA71E6E8", - "TxnSignature": "3045022100A0A5FD62D9EC81D1F0C5474A7EEB31C45423D647764B352F947617C383CD9E6902201896720DB3B9876FE56DEA05E4F75B3F90A20B3A5EF95E39703F80F5166BD1F6", - "Account": "rP5xpZ5KzPih69fLhG3NYvZEDfLmSEViUk" - } - } - ] - }, - "meta": { - "TransactionIndex": 0, - "AffectedNodes": [ - { - "ModifiedNode": { - "LedgerEntryType": "AccountRoot", - "PreviousTxnLgrSeq": 51901464, - "PreviousTxnID": "607A53B712B938B1475D194EC4F3318E6EC4BACD430D6C5437AA4018F1754A2A", - "LedgerIndex": "45806910346E5E79AE202994014742DEDA552A6197C19E03C4DC5C5466A00DB2", - "PreviousFields": { - "Balance": "120000000" - }, - "FinalFields": { - "Flags": 0, - "Sequence": 2, - "OwnerCount": 0, - "Balance": "220303257120000", - "Account": "r3a8tn1ubcP13np3giaLYzkmVKfnhLP2BL" - } - } - }, - { - "ModifiedNode": { - "LedgerEntryType": "AccountRoot", - "PreviousTxnLgrSeq": 44734671, - "PreviousTxnID": "20F2F95E4612296B1A82CC72F0DC53C9EAA8DA1557A0D0AD6C1E3BCA7E67E7CE", - "LedgerIndex": "564241023DCB6F74760910F17F78B179AEC159C701BBACD99A1D3259D77D3CFF", - "PreviousFields": { - "Sequence": 14, - "Balance": "3730330148609091" - }, - "FinalFields": { - "Flags": 1048576, - "Sequence": 15, - "OwnerCount": 10, - "Balance": "3510027011484091", - "Account": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1" - } - } - } - ], - "TransactionResult": "tesSUCCESS", - "delivered_amount": "220303137120000" - } - } - ] - } - `); - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/stellar-api-accounts.js b/mock/ext-api-dyson/get/stellar-api-accounts.js deleted file mode 100644 index 6432dd67e..000000000 --- a/mock/ext-api-dyson/get/stellar-api-accounts.js +++ /dev/null @@ -1,98 +0,0 @@ -/// Stellar API Mock, accounts -/// See: -/// curl "http://localhost:3347/stellar-api/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?order=desc&limit=25" -/// curl "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?order=desc&limit=25" -/// curl http://localhost:8437/v1/stellar/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX -module.exports = { - path: "/stellar-api/accounts/:address/:operation?", - template: function(params, query, body) { - //console.log(query) - if (params.operation === 'payments') { - if (params.address === 'GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX') { - return JSON.parse(` - { - "_links": { - "self": { - "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?cursor=\u0026limit=25\u0026order=desc" - }, - "next": { - "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?cursor=68651109446586369\u0026limit=25\u0026order=desc" - }, - "prev": { - "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX/payments?cursor=118409941953355777\u0026limit=25\u0026order=asc" - } - }, - "_embedded": { - "records": [ - { - "_links": { - "self": { - "href": "https://horizon.stellar.org/operations/118409941953355777" - }, - "transaction": { - "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029" - }, - "effects": { - "href": "https://horizon.stellar.org/operations/118409941953355777/effects" - }, - "succeeds": { - "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=118409941953355777" - }, - "precedes": { - "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=118409941953355777" - } - }, - "id": "118409941953355777", - "paging_token": "118409941953355777", - "transaction_successful": true, - "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - "type": "payment", - "type_i": 1, - "created_at": "2020-01-03T00:26:37Z", - "transaction_hash": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029", - "asset_type": "native", - "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - "to": "GDBX63ONLLI372D7FHJYEPKP3KOCH7HZPKJWZPYJMC5RN7L5HB4VFXLM", - "amount": "500000.0000000" - }, - { - "_links": { - "self": { - "href": "https://horizon.stellar.org/operations/117528387031003137" - }, - "transaction": { - "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c" - }, - "effects": { - "href": "https://horizon.stellar.org/operations/117528387031003137/effects" - }, - "succeeds": { - "href": "https://horizon.stellar.org/effects?order=desc\u0026cursor=117528387031003137" - }, - "precedes": { - "href": "https://horizon.stellar.org/effects?order=asc\u0026cursor=117528387031003137" - } - }, - "id": "117528387031003137", - "paging_token": "117528387031003137", - "transaction_successful": true, - "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - "type": "payment", - "type_i": 1, - "created_at": "2019-12-20T23:06:36Z", - "transaction_hash": "23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c", - "asset_type": "native", - "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - "to": "GCGVWRW5MHZW5OB2IR6RRFYBG5NV4BXUT5GYBRH2E3FD3TVYVINA72KM", - "amount": "3976053.0000000" - } - ] - } - } - `); - } - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/stellar-api-transactions.js b/mock/ext-api-dyson/get/stellar-api-transactions.js deleted file mode 100644 index 3597a7864..000000000 --- a/mock/ext-api-dyson/get/stellar-api-transactions.js +++ /dev/null @@ -1,117 +0,0 @@ -/// Stellar API Mock, transactions -/// See: -/// curl "http://localhost:3347/stellar-api/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029?" -/// curl "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029?" -/// curl http://localhost:8437/v1/stellar/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX -module.exports = { - path: "/stellar-api/transactions/:txid?", - template: function(params, query, body) { - //console.log(query) - if (params.txid === '2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029') { - return JSON.parse(` - { - "_links": { - "self": { - "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029" - }, - "account": { - "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" - }, - "ledger": { - "href": "https://horizon.stellar.org/ledgers/27569463" - }, - "operations": { - "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029/operations{?cursor,limit,order}", - "templated": true - }, - "effects": { - "href": "https://horizon.stellar.org/transactions/2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029/effects{?cursor,limit,order}", - "templated": true - }, - "precedes": { - "href": "https://horizon.stellar.org/transactions?order=asc\u0026cursor=118409941953355776" - }, - "succeeds": { - "href": "https://horizon.stellar.org/transactions?order=desc\u0026cursor=118409941953355776" - } - }, - "id": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029", - "paging_token": "118409941953355776", - "successful": true, - "hash": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029", - "ledger": 27569463, - "created_at": "2020-01-03T00:26:37Z", - "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - "source_account_sequence": "25002129911447568", - "fee_charged": 100, - "max_fee": 100, - "operation_count": 1, - "envelope_xdr": "AAAAANSEpQq63M02LHthmlMK1zL6lF7mvGyAj9qoryiJWAQrAAAAZABY004AAAAQAAAAAAAAAAAAAAABAAAAAQAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwAAAAEAAAAAw39tzVrRv+h/KdOCPU/anCP8+XqTbL8JYLsW/X04eVIAAAAAAAAEjCc5UAAAAAAAAAAAA4lYBCsAAABAM4j0FWLKI8qMUcJMO3tP4rMAoIDZdbRlFjiFNACVoAd9dCtdgBBpbi6ZnXtimE370ar19q/qrbvOKBJrnYXjC2b459kAAABAtIedy2ER3ep90HE5rEPwh03iyQRp644Sm8/wK0c9sk6qPSTG2VEFEj85Jk0TrXLxDmxvnktEhPyec67ZcdxfDrEQC4sAAABAoabKlFbeUmDTtAiGVOHthzrCZHK8mpyFkKIS7QzjL4a6ASQ6RweWNUKedUBj4uuO5z1vHDr3I5EiLUhK8xceAQ==", - "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", - "result_meta_xdr": "AAAAAQAAAAIAAAADAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYurIvScogBY004AAAAPAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYurIvScogBY004AAAAQAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAAAABAAAAAMBlbvHAAAAAAAAAADDf23NWtG/6H8p04I9T9qcI/z5epNsvwlguxb9fTh5UgAAAAAEBsfCAWsUFwAAAAcAAAADAAAAAQAAAACEPwEuxkVAQXfespLpiilBRPdvqIsEbieyl7rz8ME0FgAAAAAAAAAIbm9kbGUua3kAAgICAAAAAwAAAABZb+AQ1x8C7yRRjZjmrWnGc3IjlX+nHwpN9kmfVrOUgwAAAAEAAAAAa+mvYlV3vvuiNbEFfIwap9J7CAY2vNceKVv68HTkxg8AAAABAAAAAOIt1YAF0nOgEaMoodWZu6F3u9zkCv+ua4tEMcnzooD+AAAAAQAAAAAAAAAAAAAAAQGkrTcAAAAAAAAAAMN/bc1a0b/ofynTgj1P2pwj/Pl6k2y/CWC7Fv19OHlSAAAEjCtAF8IBaxQXAAAABwAAAAMAAAABAAAAAIQ/AS7GRUBBd96ykumKKUFE92+oiwRuJ7KXuvPwwTQWAAAAAAAAAAhub2RsZS5reQACAgIAAAADAAAAAFlv4BDXHwLvJFGNmOatacZzciOVf6cfCk32SZ9Ws5SDAAAAAQAAAABr6a9iVXe++6I1sQV8jBqn0nsIBja81x4pW/rwdOTGDwAAAAEAAAAA4i3VgAXSc6ARoyih1Zm7oXe73OQK/65ri0QxyfOigP4AAAABAAAAAAAAAAAAAAADAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYurIvScogBY004AAAAQAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAaStNwAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAhYce+7tMogBY004AAAAQAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAA=", - "fee_meta_xdr": "AAAAAgAAAAMBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFi6si9J0GAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAAAAAAEBpK03AAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFi6si9JyiAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAA==", - "memo_type": "none", - "signatures": [ - "M4j0FWLKI8qMUcJMO3tP4rMAoIDZdbRlFjiFNACVoAd9dCtdgBBpbi6ZnXtimE370ar19q/qrbvOKBJrnYXjCw==", - "tIedy2ER3ep90HE5rEPwh03iyQRp644Sm8/wK0c9sk6qPSTG2VEFEj85Jk0TrXLxDmxvnktEhPyec67ZcdxfDg==", - "oabKlFbeUmDTtAiGVOHthzrCZHK8mpyFkKIS7QzjL4a6ASQ6RweWNUKedUBj4uuO5z1vHDr3I5EiLUhK8xceAQ==" - ] - } - `); - } - if (params.txid === '23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c') { - return JSON.parse(` - { - "_links": { - "self": { - "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c" - }, - "account": { - "href": "https://horizon.stellar.org/accounts/GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" - }, - "ledger": { - "href": "https://horizon.stellar.org/ledgers/27364210" - }, - "operations": { - "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c/operations{?cursor,limit,order}", - "templated": true - }, - "effects": { - "href": "https://horizon.stellar.org/transactions/23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c/effects{?cursor,limit,order}", - "templated": true - }, - "precedes": { - "href": "https://horizon.stellar.org/transactions?order=asc\u0026cursor=117528387031003136" - }, - "succeeds": { - "href": "https://horizon.stellar.org/transactions?order=desc\u0026cursor=117528387031003136" - } - }, - "id": "23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c", - "paging_token": "117528387031003136", - "successful": true, - "hash": "23fa4d3c787f22a1755afa4275761ffba516ec4f2e039440ec02a5522b388f2c", - "ledger": 27364210, - "created_at": "2019-12-20T23:06:36Z", - "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - "source_account_sequence": "25002129911447567", - "fee_charged": 100, - "max_fee": 100, - "operation_count": 1, - "envelope_xdr": "AAAAANSEpQq63M02LHthmlMK1zL6lF7mvGyAj9qoryiJWAQrAAAAZABY004AAAAPAAAAAAAAAAAAAAABAAAAAQAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwAAAAEAAAAAjVtG3WHzbrg6RH0YlwE3W14G9J9NgMT6Jso9zriqGg8AAAAAAAAkKXhESIAAAAAAAAAAA2b459kAAABA5EcZFubvZDa2IytO64bCB85UpjzLqHIS3FBWshoigfice819SwpBYkk7xa3kIWseL/kiQBCnrIAsU7ujYAR3AIlYBCsAAABA1oF6s5NMUEJas97SMRqHgeuXxCdKetSEPBtFGlgzSPTqG6mzAGPuwibKs3HaBjdmfbwh7ffTtjAAesLHIApdCRlL7xoAAABAkADolN0l8llCFxrkqMLbbU4NNKwPsQDrYDoxERo7uvuVJgg18zMBk4t1eqXqQfiYZVeIdAN/q9zcL2SGGYJaBg==", - "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", - "result_meta_xdr": "AAAAAQAAAAIAAAADAaGLcgAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAha/UmzjlhgBY004AAAAOAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAaGLcgAAAAAAAAAA1ISlCrrczTYse2GaUwrXMvqUXua8bICP2qivKIlYBCsAha/UmzjlhgBY004AAAAPAAAABAAAAAEAAAAA7Nxp7lmV7taqQfqoSP+tlqjOHWeANaQYFqhDkCQERZQAAAAAAAAABXdvcmxkAAAAAQMDAwAAAAQAAAAAWAWHCZ+B/csQs61aiNJ9HpeG/AFGn4PbMb3ICbEQC4sAAAABAAAAAHO8jVAFNWHAG/OA+bnwjmclTaRHgkjQOY2lwwkZS+8aAAAAAQAAAAC69o1dnVJ6rMdVlL7PU3WLsy2q4KJFUBkNPUfSPIFLmAAAAAEAAAAA1bzMAeuKubyXUug/Xnyj1KYkv+cSUtCSvAczI2b459kAAAABAAAAAAAAAAAAAAABAAAABAAAAAMBoJ96AAAAAAAAAACNW0bdYfNuuDpEfRiXATdbXgb0n02AxPomyj3OuKoaDwAAABwqq724AWpTdAAAABYAAAADAAAAAAAAAAAAAAAAAQMDAwAAAAMAAAAAVMpM+DapT2QOM7rVti7Nu9zC8ZweMu0F3X3WjmI18MwAAAABAAAAALpTQaHLUccK4ssbtsuxFMwYEVe6qosFYprYXIH5kg8bAAAAAQAAAAC6le9TwqPIBkG+/CAt9sGl/SpcdU21B5eJ4qdAhRlyIwAAAAEAAAAAAAAAAAAAAAEBoYtyAAAAAAAAAACNW0bdYfNuuDpEfRiXATdbXgb0n02AxPomyj3OuKoaDwAAJEWi8AY4AWpTdAAAABYAAAADAAAAAAAAAAAAAAAAAQMDAwAAAAMAAAAAVMpM+DapT2QOM7rVti7Nu9zC8ZweMu0F3X3WjmI18MwAAAABAAAAALpTQaHLUccK4ssbtsuxFMwYEVe6qosFYprYXIH5kg8bAAAAAQAAAAC6le9TwqPIBkG+/CAt9sGl/SpcdU21B5eJ4qdAhRlyIwAAAAEAAAAAAAAAAAAAAAMBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFr9SbOOWGAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAAAAAAEBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFi6si9J0GAFjTTgAAAA8AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAA==", - "fee_meta_xdr": "AAAAAgAAAAMBn66qAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFr9SbOOXqAFjTTgAAAA4AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAAAAAAEBoYtyAAAAAAAAAADUhKUKutzNNix7YZpTCtcy+pRe5rxsgI/aqK8oiVgEKwCFr9SbOOWGAFjTTgAAAA4AAAAEAAAAAQAAAADs3GnuWZXu1qpB+qhI/62WqM4dZ4A1pBgWqEOQJARFlAAAAAAAAAAFd29ybGQAAAABAwMDAAAABAAAAABYBYcJn4H9yxCzrVqI0n0el4b8AUafg9sxvcgJsRALiwAAAAEAAAAAc7yNUAU1YcAb84D5ufCOZyVNpEeCSNA5jaXDCRlL7xoAAAABAAAAALr2jV2dUnqsx1WUvs9TdYuzLargokVQGQ09R9I8gUuYAAAAAQAAAADVvMwB64q5vJdS6D9efKPUpiS/5xJS0JK8BzMjZvjn2QAAAAEAAAAAAAAAAA==", - "memo_type": "none", - "signatures": [ - "5EcZFubvZDa2IytO64bCB85UpjzLqHIS3FBWshoigfice819SwpBYkk7xa3kIWseL/kiQBCnrIAsU7ujYAR3AA==", - "1oF6s5NMUEJas97SMRqHgeuXxCdKetSEPBtFGlgzSPTqG6mzAGPuwibKs3HaBjdmfbwh7ffTtjAAesLHIApdCQ==", - "kADolN0l8llCFxrkqMLbbU4NNKwPsQDrYDoxERo7uvuVJgg18zMBk4t1eqXqQfiYZVeIdAN/q9zcL2SGGYJaBg==" - ] - } - `); - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/tezos-api-transactions.js b/mock/ext-api-dyson/get/tezos-api-transactions.js deleted file mode 100644 index 2d7c25bc4..000000000 --- a/mock/ext-api-dyson/get/tezos-api-transactions.js +++ /dev/null @@ -1,182 +0,0 @@ -/// Mock for external Tezos API, transactions -/// See -/// curl "https://api.tzstats.com/explorer/account/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8/op?limit=25&order=desc&type=transaction%2Cdelegation" -/// curl "http://localhost:3347/tezos-api/account/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8/op?limit=25&order=desc&type=transaction%2Cdelegation" -/// curl "http://localhost:8437/v1/tezos/tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" - -module.exports = { - path: '/tezos-api/account/:account/:op?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - if (params.account === 'tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8') { - return JSON.parse(` - { - "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", - "address_type": "ed25519", - "delegate": "", - "manager": "", - "pubkey": "edpkvKiFTVXxttCcDa2N6QfwgsnWHoEQdYRsVfUDBWPXJbhBPQpLVk", - "first_in": 797595, - "first_out": 797612, - "last_in": 797595, - "last_out": 797612, - "first_seen": 797595, - "last_seen": 797612, - "delegated_since": 0, - "delegate_since": 0, - "first_in_time": "2020-01-26T23:49:01Z", - "first_out_time": "2020-01-27T00:06:01Z", - "last_in_time": "2020-01-26T23:49:01Z", - "last_out_time": "2020-01-27T00:06:01Z", - "first_seen_time": "2020-01-26T23:49:01Z", - "last_seen_time": "2020-01-27T00:06:01Z", - "delegated_since_time": "0001-01-01T00:00:00Z", - "delegate_since_time": "0001-01-01T00:00:00Z", - "total_received": 0.01, - "total_sent": 0.007, - "total_burned": 0, - "total_fees_paid": 0.003, - "total_rewards_earned": 0, - "total_fees_earned": 0, - "total_lost": 0, - "frozen_deposits": 0, - "frozen_rewards": 0, - "frozen_fees": 0, - "unclaimed_balance": 0, - "spendable_balance": 0, - "total_balance": 0, - "delegated_balance": 0, - "total_delegations": 0, - "active_delegations": 0, - "is_funded": false, - "is_activated": false, - "is_vesting": false, - "is_spendable": true, - "is_delegatable": false, - "is_delegated": false, - "is_revealed": false, - "is_delegate": false, - "is_active_delegate": false, - "is_contract": false, - "blocks_baked": 0, - "blocks_missed": 0, - "blocks_stolen": 0, - "blocks_endorsed": 0, - "slots_endorsed": 0, - "slots_missed": 0, - "n_ops": 3, - "n_ops_failed": 0, - "n_tx": 2, - "n_delegation": 0, - "n_origination": 0, - "n_proposal": 0, - "n_ballot": 0, - "token_gen_min": 0, - "token_gen_max": 0, - "grace_period": 0, - "staking_balance": 0, - "rolls": 0, - "rich_rank": 0, - "traffic_rank": 0, - "flow_rank": 0, - "last_bake_height": 0, - "last_bake_block": "", - "last_bake_time": "0001-01-01T00:00:00Z", - "last_endorse_height": 0, - "last_endorse_block": "", - "last_endorse_time": "0001-01-01T00:00:00Z", - "next_bake_height": 0, - "next_bake_priority": 0, - "next_bake_time": "0001-01-01T00:00:00Z", - "next_endorse_height": 0, - "next_endorse_time": "0001-01-01T00:00:00Z", - "ops": [ - { - "row_id": 20862164, - "hash": "ooLrNAP233Qvoz3AGvjRjhk1fjG7z19UfyLEGBm1rwfHn4NSVhd", - "type": "transaction", - "block": "BMRy3L1EEkPrmv4UwTUsFNnD3Q25hVB36VyN5Tx5G96vUpfkiR1", - "time": "2020-01-27T00:06:01Z", - "height": 797612, - "cycle": 194, - "counter": 2946274, - "op_n": 50, - "op_l": 3, - "op_p": 2, - "op_c": 1, - "op_i": 0, - "status": "applied", - "is_success": true, - "is_contract": false, - "gas_limit": 10600, - "gas_used": 10209, - "gas_price": 0.14693, - "storage_limit": 257, - "storage_size": 0, - "storage_paid": 0, - "volume": 0.007, - "fee": 0.0015, - "reward": 0, - "deposit": 0, - "burned": 0, - "is_internal": false, - "has_data": false, - "days_destroyed": 0.000083, - "sender": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", - "receiver": "tz1KqtebPYZopqj65E6qPseW2GDGVgUs82wK", - "branch_id": 797612, - "branch_height": 797611, - "branch_depth": 1, - "branch": "BMEPJ9BA41LZKuS9ywVQAvdtV7SHqiKU6vmFsxPSEUzCLZ2pG5D", - "is_implicit": false, - "entrypoint_id": 0 - }, - { - "row_id": 20861661, - "hash": "op2f6FPSKhzKcN6o2uUNETUrgF4vX8pAEyRJb4k9uPnAFEoJjYq", - "type": "transaction", - "block": "BMJtDFTTaWABiv8ye1qALB5Jss2wQz3CFYjrMVhTX8yBWA8dttt", - "time": "2020-01-26T23:49:01Z", - "height": 797595, - "cycle": 194, - "counter": 2555733, - "op_n": 19, - "op_l": 3, - "op_p": 0, - "op_c": 0, - "op_i": 0, - "status": "applied", - "is_success": true, - "is_contract": false, - "gas_limit": 10307, - "gas_used": 10207, - "gas_price": 0.1258, - "storage_limit": 277, - "storage_size": 0, - "storage_paid": 0, - "volume": 0.01, - "fee": 0.001284, - "reward": 0, - "deposit": 0, - "burned": 0.257, - "is_internal": false, - "has_data": false, - "days_destroyed": 0.019403, - "sender": "tz1VwmmesDxud2BJEyDKUTV5T5VEP8tGBKGD", - "receiver": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", - "branch_id": 797595, - "branch_height": 797594, - "branch_depth": 1, - "branch": "BLcdWDBAN4N38tnsEGMT8vorsKeMgAbCN154AM93eZ348uhZGWy", - "is_implicit": false, - "entrypoint_id": 0 - } - ] - } - `) - } - - return {error: "Not implemented"} - } -}; diff --git a/mock/ext-api-dyson/get/theta-api-accounttx.js b/mock/ext-api-dyson/get/theta-api-accounttx.js deleted file mode 100644 index 633266650..000000000 --- a/mock/ext-api-dyson/get/theta-api-accounttx.js +++ /dev/null @@ -1,94 +0,0 @@ -/// Theta API Mock -/// See: -/// curl "http://localhost:3347/theta-api/accounttx/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f?type=2&pageNumber=1&limitNumber=100&isEqualType=true" -/// curl "https://explorer.thetatoken.org:9000/api/accounttx/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f?type=2&pageNumber=1&limitNumber=100&isEqualType=true" -/// curl http://localhost:8437/v1/theta/0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f -module.exports = { - path: "/theta-api/accounttx/:address?", - template: function(params, query, body) { - //console.log(params) - if (params.address === '0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f') { - return JSON.parse(` - { - "type": "account_tx_list", - "body": [ - { - "_id": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78", - "block_height": "4160784", - "data": { - "fee": { - "thetawei": "0", - "tfuelwei": "2000000000000" - }, - "inputs": [ - { - "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - "coins": { - "thetawei": "1000000000000000", - "tfuelwei": "2000000000000" - }, - "sequence": "52", - "signature": "0x60ae320a7a0f7f6e72ed5080830d2156f145a191197092df9eb88e7b8c7637ad01894b128b81d33b67a6516e3a6c7dc064576eb40b9516b4dc127e9845ede8c300" - } - ], - "outputs": [ - { - "address": "0x082a2aef39b6473c55ba7e28c122ed3aea0de381", - "coins": { - "thetawei": "1000000000000000", - "tfuelwei": "0" - } - } - ] - }, - "hash": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78", - "number": 31836666, - "status": "finalized", - "timestamp": "1579009947", - "type": 2 - }, - { - "_id": "0x43804bbc7ff254f5eb3ff0a9bc1feed5788cbbc3eb5b535c52de4c47c8963dfd", - "block_height": "4160736", - "data": { - "fee": { - "thetawei": "0", - "tfuelwei": "2000000000000" - }, - "inputs": [ - { - "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - "coins": { - "thetawei": "1000000000000000", - "tfuelwei": "2000000000000" - }, - "sequence": "51", - "signature": "0x23cd4f14859ef6a9cd0bd820591101cd53c74d3421e01b42ca0671501afdd6f73dcf2ec8e35ceba773319ba552c0b170daa3460bf6125992e846f9d0cf839a9700" - } - ], - "outputs": [ - { - "address": "0x082a2aef39b6473c55ba7e28c122ed3aea0de381", - "coins": { - "thetawei": "1000000000000000", - "tfuelwei": "0" - } - } - ] - }, - "hash": "0x43804bbc7ff254f5eb3ff0a9bc1feed5788cbbc3eb5b535c52de4c47c8963dfd", - "number": 31836430, - "status": "finalized", - "timestamp": "1579009642", - "type": 2 - } - ], - "totalPageNumber": 1, - "currentPageNumber": 1 - } - `); - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/thundertoken-api-commands1.js b/mock/ext-api-dyson/get/thundertoken-api-commands1.js deleted file mode 100644 index b6cdbb654..000000000 --- a/mock/ext-api-dyson/get/thundertoken-api-commands1.js +++ /dev/null @@ -1,100 +0,0 @@ -/// Thundertoken API Mock -/// See: -/// curl "http://localhost:3347/thundertoken-api/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" -/// curl "http://localhost:3347/thundertoken-api/tokens?address=0x0b230def08139f18a86536d9cfa150f04435414c" -/// curl "https://{Thundertoken rpc}/transactions?address=0x0b230def08139f18a86536d9cfa150f04435414c" -/// curl "https://{Thundertoken rpc}/tokens?address=0x0b230def08139f18a86536d9cfa150f04435414c" -/// curl "http://localhost:8437/v1/thundertoken/0x0b230def08139f18a86536d9cfa150f04435414c" -/// curl "http://localhost:8437/v2/thundertoken/tokens/0x0b230def08139f18a86536d9cfa150f04435414c?Authorization=Bearer" - -module.exports = { - path: '/thundertoken-api/:command1?', - template: function(params, query, body) { - //console.log(params); - //console.log(query); - switch (params.command1) { - case 'transactions': - if (query.address === '0x0b230def08139f18a86536d9cfa150f04435414c') { - return JSON.parse(`{ - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0x80929a2170969364e06d253d2b853fe0b2ca3a307e61d629946b9b76e2f983cf", - "blockNumber": 33514713, - "time": 1584945288, - "nonce": 312, - "from": "0x0B230dEf08139F18a86536d9CFa150f04435414c", - "to": "0x83Ed8e6135e079a49085CA2f2F5E502691ccC0B1", - "value": "0", - "gas": "4700000", - "gasPrice": "4000000000", - "gasUsed": "421569", - "input": "0xc78b6dea0000000000000000000000000000000000000000000000000000000000000800", - "error": "", - "id": "0x80929a2170969364e06d253d2b853fe0b2ca3a307e61d629946b9b76e2f983cf", - "timeStamp": "1584945288" - }, - { - "operations": [ - { - "transactionId": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00-0", - "contract": { - "address": "0x51bca9300d034a7e6ab379399a317bdfa0d4835b", - "decimals": 18, - "name": "The Third Identity", - "symbol": "TTI", - "totalSupply": "10000000000000000000000000000", - "updatedAt": "2020-02-26T21:42:19.178Z" - }, - "from": "0x3270b4e0916B4556BF236B6E5D4377282b3255e5", - "to": "0x0B230dEf08139F18a86536d9CFa150f04435414c", - "type": "token_transfer", - "value": "292820000000000000000", - "id": null - } - ], - "contract": null, - "_id": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00", - "blockNumber": 33514370, - "time": 1584944945, - "nonce": 311, - "from": "0x0B230dEf08139F18a86536d9CFa150f04435414c", - "to": "0x3270b4e0916B4556BF236B6E5D4377282b3255e5", - "value": "0", - "gas": "4700000", - "gasPrice": "2880000000", - "gasUsed": "1511414", - "input": "0x4008d2f3", - "error": "", - "id": "0xa8f78b26a4bf9e89bd2662cb2dcd2e9031a8d38df2ed85d6d52526589bbfed00", - "timeStamp": "1584944945" - } - ], - "total": 2 - }`); - } - break; - - case 'tokens': - if (query.address === '0x0b230def08139f18a86536d9cfa150f04435414c') { - return JSON.parse(` - { - "total": 1, - "docs": [ - { - "address": "0x51BcA9300d034A7e6aB379399a317bDfA0D4835b", - "name": "The Third Identity", - "decimals": 18, - "symbol": "TTI" - } - ] - } - `); - } - break; - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/tomochain-api-commands1.js b/mock/ext-api-dyson/get/tomochain-api-commands1.js deleted file mode 100644 index 3f5054b2c..000000000 --- a/mock/ext-api-dyson/get/tomochain-api-commands1.js +++ /dev/null @@ -1,89 +0,0 @@ -/// Tomochain API Mock -/// See: -/// curl "http://localhost:3347/tomochain-api/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" -/// curl "http://localhost:3347/tomochain-api/tokens?address=0x8b353021189375591723e7384262f45709a3c3dc" -/// curl "https://{Tomochain rpc}/transactions?address=0x17e4c16605e32adead5fa371bf6117df34ca0200" -/// curl "https://{Tomochain rpc}/tokens?address=0x8b353021189375591723e7384262f45709a3c3dc" -/// curl "http://localhost:8437/v1/tomochain/0x17e4c16605e32adead5fa371bf6117df34ca0200" -/// curl "http://localhost:8437/v2/tomochain/tokens/0x8b353021189375591723e7384262f45709a3c3dc?Authorization=Bearer" - -module.exports = { - path: '/tomochain-api/:command1?', - template: function(params, query, body) { - //console.log(params); - //console.log(query); - switch (params.command1) { - case 'transactions': - if (query.address === '0x17e4c16605e32adead5fa371bf6117df34ca0200') { - return JSON.parse(`{ - "docs": [ - { - "operations": [], - "contract": null, - "_id": "0xb2af5ad5eebaba1da3452e0281f9b6ec9e00a5bb832793a912eb3959b6c2fdd2", - "blockNumber": 18455252, - "time": 1584963130, - "nonce": 892939, - "from": "0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200", - "to": "0x0000000000000000000000000000000000000089", - "value": "0", - "gas": "200000", - "gasPrice": "0", - "gasUsed": "0", - "input": "0xe341eaa40000000000000000000000000000000000000000000000000000000001199ad29a43ad0df08d1ff128de7642208ce68720dc77bbe7e02acb2685951f73efea56", - "error": "", - "id": "0xb2af5ad5eebaba1da3452e0281f9b6ec9e00a5bb832793a912eb3959b6c2fdd2", - "timeStamp": "1584963130" - }, - { - "operations": [], - "contract": null, - "_id": "0x9181d170fb77eb55e1dda42c55080230397702204247e8b242c8f6588f61f41d", - "blockNumber": 18455237, - "time": 1584963100, - "nonce": 892938, - "from": "0x17e4C16605E32ADEaD5FA371BF6117Df34Ca0200", - "to": "0x0000000000000000000000000000000000000089", - "value": "0", - "gas": "200000", - "gasPrice": "0", - "gasUsed": "0", - "input": "0xe341eaa40000000000000000000000000000000000000000000000000000000001199ac3f1234069ee58f791cc422978d794e7f3c1e82d580013038badd5493ed854b6e4", - "error": "", - "id": "0x9181d170fb77eb55e1dda42c55080230397702204247e8b242c8f6588f61f41d", - "timeStamp": "1584963100" - } - ], - "total": 2 - }`); - } - break; - - case 'tokens': - if (query.address === '0x8b353021189375591723e7384262f45709a3c3dc') { - return JSON.parse(` - { - "total": 2, - "docs": [ - { - "address": "0xaB7e4aE99D7bfff4de8322aB915e9066857227F0", - "name": "KONG", - "decimals": 18, - "symbol": "KONG" - }, - { - "address": "0xc7BdF5D257fF4EC078e12A3ABD34dFc329E55130", - "name": "AIS Token", - "decimals": 18, - "symbol": "AIS" - } - ] - } - `); - } - break; - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/tron-api-v1-accounts.js b/mock/ext-api-dyson/get/tron-api-v1-accounts.js deleted file mode 100644 index d57d81719..000000000 --- a/mock/ext-api-dyson/get/tron-api-v1-accounts.js +++ /dev/null @@ -1,188 +0,0 @@ -/// Tron API Mock -/// See: -/// curl "http://localhost:3347/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?token_id=&limit=25&order_by=block_timestamp,desc" -/// curl "http://localhost:3347/tron-api/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" -/// curl "http://{Tron rpc}/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB/transactions?token_id=&limit=25&order_by=block_timestamp,desc" -/// curl "http://{Tron rpc}/v1/accounts/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" -/// curl "http://localhost:8437/v1/tron/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" -/// curl "http://localhost:8437/v2/tron/tokens/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB?Authorization=Bearer" - -module.exports = { - path: "/tron-api/v1/accounts/:address/:operation?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - if (params.operation === 'transactions') { - if (params.address === 'TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB') { - return JSON.parse(` - { - "success": true, - "meta": { - "at": 1585038748264, - "page_size": 2 - }, - "data": [ - { - "block_timestamp": 1553870898000, - "raw_data": { - "contract": [ - { - "parameter": { - "type_url": "type.googleapis.com/protocol.TransferAssetContract", - "value": { - "amount": 10149740000, - "asset_name": "1002000", - "owner_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261", - "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" - } - }, - "type": "TransferAssetContract" - } - ], - "expiration": 1553870955000, - "fee_limit": 0, - "ref_block_bytes": "b560", - "ref_block_hash": "2d9026ee979db6b6", - "timestamp": 1553870897024 - }, - "raw_data_hex": "0a02b56022082d9026ee979db6b640f8c3b4cf9c2d5a77080212730a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123d0a07313030323030301215410583a68a3bcd86c25ab1bee482bac04a216b02611a154139fec4d95bb59f45a727f9234020adaf2cec9e2020e0fbe2e7257080ffb0cf9c2d", - "ret": [ - { - "code": "SUCESS", - "contractRet": "SUCCESS", - "fee": 0 - } - ], - "signature": [ - "10c57bda2346f4cc7e287a2b696fcd8dcbec273d84df8b8d41fcf49d13e02fdf1ca539d1b631feabd58e3f0a8c501c8d74595774fd149cfba16770eb8a4bd18100" - ], - "txID": "d9206168ee601935bb19de30a613f735972f1ab59178ba05d078ff1ae19c0602" - }, - { - "block_timestamp": 1553864040000, - "raw_data": { - "contract": [ - { - "parameter": { - "type_url": "type.googleapis.com/protocol.TransferContract", - "value": { - "amount": 278720000, - "owner_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261", - "to_address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20" - } - }, - "type": "TransferContract" - } - ], - "expiration": 1553864097000, - "fee_limit": 0, - "ref_block_bytes": "ac7f", - "ref_block_hash": "648c4cb65453b4de", - "timestamp": 1553864038710 - }, - "raw_data_hex": "0a02ac7f2208648c4cb65453b4de40e8f991cc9c2d5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a15410583a68a3bcd86c25ab1bee482bac04a216b026112154139fec4d95bb59f45a727f9234020adaf2cec9e201880dcf3840170b6b28ecc9c2d", - "ret": [ - { - "code": "SUCESS", - "contractRet": "SUCCESS", - "fee": 0 - } - ], - "signature": [ - "25052c3c653de8c06dc2294f9078a621179102282799f14f4a6950b805e66ea17c1a894a34922d92b7b14aad27cc07aeb129cb31570d55e9f21a0e3f5dd11ce701" - ], - "txID": "3ef5e225ce5bdd01333286e4ab4413ae3da8b80c24b26c5811ae78962940a8ca" - } - ] - } - `); - } - } - - if (typeof params.operation === 'undefined') { - if (params.address === 'TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB') { - return JSON.parse(` - { - "success": true, - "meta": { - "at": 1586264949424, - "page_size": 1 - }, - "data": [ - { - "account_resource": {}, - "active_permission": [ - { - "id": 2, - "keys": [ - { - "address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", - "weight": 1 - } - ], - "operations": "7fff1fc0033e0000000000000000000000000000000000000000000000000000", - "permission_name": "active", - "threshold": 1, - "type": "Active" - } - ], - "address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", - "allowance": 848829, - "assetV2": [ - { - "key": "1002000", - "value": 10183240058 - }, - { - "key": "1002798", - "value": 10000000 - }, - { - "key": "1002814", - "value": 10000000 - } - ], - "balance": 278720000, - "create_time": 1553864037000, - "free_asset_net_usageV2": [ - { - "key": "1002000", - "value": 0 - }, - { - "key": "1002798", - "value": 0 - }, - { - "key": "1002814", - "value": 0 - } - ], - "latest_consume_free_time": 1575142326000, - "latest_consume_time": 1576767612000, - "latest_opration_time": 1576767612000, - "owner_permission": { - "keys": [ - { - "address": "4139fec4d95bb59f45a727f9234020adaf2cec9e20", - "weight": 1 - } - ], - "permission_name": "owner", - "threshold": 1 - }, - "trc20": [ - { - "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7": "50356946" - } - ] - } - ] - } - `); - } - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/tron-api-v1-assets.js b/mock/ext-api-dyson/get/tron-api-v1-assets.js deleted file mode 100644 index e476c4ae7..000000000 --- a/mock/ext-api-dyson/get/tron-api-v1-assets.js +++ /dev/null @@ -1,101 +0,0 @@ -/// Tron API Mock -/// See: -/// curl "http://localhost:3347/tron-api/v1/assets/1002798" -/// curl "https://{tron_rpc}/v1/assets/1002798" -/// curl "http://localhost:8437/v2/tron/tokens/TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB?Authorization=Bearer" - -module.exports = { - path: "/tron-api/v1/assets/:arg2?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.arg2) { - case '1002000': - return JSON.parse(` - { - "success": true, - "meta": { - "at": 1586265512148, - "page_size": 1 - }, - "data": [ - { - "id": "1002000", - "abbr": "BTT", - "description": "Official Token of BitTorrent Protocol", - "name": "BitTorrent", - "num": 1, - "precision": 6, - "total_supply": "990000000000000000", - "trx_num": 1, - "url": "www.bittorrent.com", - "owner_address": "4137fa1a56eb8c503624701d776d95f6dae1d9f0d6", - "start_time": 1548000000000, - "end_time": 1548000001000 - } - ] - } - `); - - case '1002798': - return JSON.parse(` - { - "success": true, - "meta": { - "at": 1586265317378, - "page_size": 1 - }, - "data": [ - { - "id": "1002798", - "abbr": "EPICAL", - "description": "The token of the game Builder III", - "name": "EPICAL", - "num": 1000000000, - "precision": 6, - "total_supply": "10000000000000000", - "trx_num": 1000000000, - "url": "https://builder3.fun", - "vote_score": 0, - "owner_address": "41133b084f5225a9112f4e8527db26b381a32babd0", - "start_time": 1574966426578, - "end_time": 1574966486578 - } - ] - } - `); - - - - case '1002814': - return JSON.parse(` - { - "success": true, - "meta": { - "at": 1586265542289, - "page_size": 1 - }, - "data": [ - { - "id": "1002814", - "abbr": "AX", - "description": "The token of the game TrainX", - "name": "AX", - "num": 1000000000, - "precision": 6, - "total_supply": "10000000000000000", - "trx_num": 1000000000, - "url": "https://trainx.fun", - "vote_score": 0, - "owner_address": "418e267ead411aaaf671be100a7afe587d4eab0d71", - "start_time": 1576483805985, - "end_time": 1576483865985 - } - ] - } - `); - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/tron-api-wallet.js b/mock/ext-api-dyson/get/tron-api-wallet.js deleted file mode 100644 index 099836d9c..000000000 --- a/mock/ext-api-dyson/get/tron-api-wallet.js +++ /dev/null @@ -1,88 +0,0 @@ -/// Tron API Mock -/// See: -/// curl http://localhost:3347/tron-api/wallet/listwitnesses -/// curl http://localhost:8437/v2/tron/staking/validators - -module.exports = { - path: "/tron-api/wallet/:operation?", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - if (params.operation === 'listwitnesses') { - return JSON.parse(` - { - "witnesses": [ - - { - "address": "4178c842ee63b253f8f0d2955bbc582c661a078c9d", - "voteCount": 13546358416, - "url": "https://www.binance.com/en/staking", - "totalProduced": 197868, - "totalMissed": 68, - "latestBlockNum": 18523838, - "latestSlotNum": 528611454, - "isJobs": true - }, - { - "address": "41d25855804e4e65de904faf3ac74b0bdfc53fac76", - "voteCount": 698985941, - "url": "https://www.bitguild.com", - "totalProduced": 594077, - "totalMissed": 2605, - "latestBlockNum": 18523841, - "latestSlotNum": 528611457, - "isJobs": true - }, - { - "address": "41d376d829440505ea13c9d1c455317d51b62e4ab6", - "voteCount": 317223159, - "url": "http://blockchain.org", - "totalProduced": 439090, - "totalMissed": 2650, - "latestBlockNum": 18523376, - "latestSlotNum": 528610983, - "isJobs": true - }, - { - "address": "4192c5d96c3b847268f4cb3e33b87ecfc67b5ce3de", - "voteCount": 331299971, - "url": "https://infstones.io/", - "totalProduced": 528971, - "totalMissed": 2232, - "latestBlockNum": 18523824, - "latestSlotNum": 528611440, - "isJobs": true - }, - { - "address": "417bdd2efb4401c50b6ad255e6428ba688e0b83f81", - "voteCount": 292566620, - "url": "https://minergate.com", - "totalProduced": 365859, - "totalMissed": 798, - "latestBlockNum": 18523360, - "latestSlotNum": 528610967, - "isJobs": true - }, - { - "address": "414d1ef8673f916debb7e2515a8f3ecaf2611034aa", - "voteCount": 392387821, - "url": "https://www.sesameseed.org", - "totalProduced": 667595, - "totalMissed": 5738, - "latestBlockNum": 18523844, - "latestSlotNum": 528611460, - "isJobs": true - }, - { - "address": "41de9c3c2276abe2da70a7cdb34a205ecf7750d063", - "voteCount": 4575746, - "url": "https://www.tron-family.de" - } - ] - } - `) - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/unstoppabledomains-lookup.js b/mock/ext-api-dyson/get/unstoppabledomains-lookup.js deleted file mode 100644 index e0168f642..000000000 --- a/mock/ext-api-dyson/get/unstoppabledomains-lookup.js +++ /dev/null @@ -1,38 +0,0 @@ - -/// Unstoppabledomains API Mock, lookup -/// Returns: -/// - public address for certain name and coin combinations -/// - public address not found message for other input -/// See: -/// curl "http://localhost:3347/unstoppabledomains/api/v1//dpantani.zil" -/// curl "https://unstoppabledomains.com/api/v1/dpantani.zil" -/// curl "http://localhost:8437/v2/ns/lookup?name=dpantani.zil&coins=313" - -module.exports = { - path: '/unstoppabledomains/api/v1//:name?', - template: function(params, query, body) { return lookup(params, query, body); } -}; - -function lookup(params, query, body) { - var addr = getAddresses(params.name); - if (addr == '') { - return {addresses: {}, meta: {owner: null, type: "ZNS", ttl: 0}, claimed: false}; - } - return addr; -} - -function getAddresses(address) { - if (address !== 'dpantani.zil' && address !== 'dpantani.crypto') { return ''; } - return { - addresses: { - BTC: "bc1qd7eystu9xl53hkyxm4kyg7h5yk4p436sqx6f27", - ETH: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - ZIL: "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64" - }, - meta: { - owner: "0xe4da405976f315ab91ff9a43a51972cc94739aa8", - type: "ZNS", - ttl: 0 - } - } -}; diff --git a/mock/ext-api-dyson/get/vechain-api-entities.js b/mock/ext-api-dyson/get/vechain-api-entities.js deleted file mode 100644 index 691a5ff00..000000000 --- a/mock/ext-api-dyson/get/vechain-api-entities.js +++ /dev/null @@ -1,106 +0,0 @@ -/// Mock for external coin API, transactions -/// See -/// curl https://vethor-pubnode.digonchain.com/blocks/best -/// curl https://vethor-pubnode.digonchain.com/transactions/0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7 -/// curl http://localhost:3347/vechain-api/blocks/best -/// curl http://localhost:3347/vechain-api/transactions/0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7 -/// curl "http://localhost:8437/v1/vechain/0xB5e883349e68aB59307d1604555AC890fAC47128" - -module.exports = { - path: '/vechain-api/:entity/:id?', - template: function(params, query, body) { - //console.log(params) - if (params.entity === 'blocks') { - if (params.id === 'best') { - return JSON.parse(` - { - "number": 5466405, - "id": "0x00536925d12b64746d8ca1d75db659b0688da13191f709304c88d8372de53519", - "size": 1021, - "parentID": "0x00536924049d49e0f4605b72f313ccac653ee54e2523f515113db3998ac30cc5", - "timestamp": 1585149040, - "gasLimit": 35201963, - "beneficiary": "0x5643143716537c9c86c558091d2a30710f71fec7", - "gasUsed": 184188, - "totalScore": 526861845, - "txsRoot": "0x81c1361fff2a3cb206f6ecd94d644220d11d91dde4295a0a7b9b0f0e549b9008", - "txsFeatures": 1, - "stateRoot": "0xcbf49e247ca8bb1826cf101480c05c1470a54c4fdc10702932ac7613ea297d81", - "receiptsRoot": "0x0e7dfcee0f0e1fcc1b6888e6eb9f767b6f37aaa5614efcee0faf94e6a62bcb6d", - "signer": "0x2da258cae01aac5cd0e4bd876f708081f78b327d", - "isTrunk": true, - "transactions": [ - "0x3985abfc8963bc7adfc54d534f0a89498aa986bb49ff87b4eb3d0aa47aeefa87", - "0xeedebfba7af9d6a99561f1c02509ce792eb6a2b582f0e35ea4dc571f9ae2306c", - "0xbb386e125bfb9bd81e32af6a4b2ef30ff8f89461a94f7be2b3a42135b490562a", - "0x49c295e28b017cf337325ea7d6e112ab11afde0433c65c8e71778e21b5acc7d9" - ] - } - `); - } - } - if (params.entity === 'transactions') { - switch (params.id) { - case '0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7': - return JSON.parse(` - { - "id": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", - "chainTag": 74, - "blockRef": "0x004313a393a18efb", - "expiration": 720, - "clauses": [ - { - "to": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", - "value": "0x12b1815d00738000", - "data": "0x" - } - ], - "gasPriceCoef": 0, - "gas": 21000, - "origin": "0xb5e883349e68ab59307d1604555ac890fac47128", - "delegator": null, - "nonce": "0x8cff29df64a414f8", - "dependsOn": null, - "size": 129, - "meta": { - "blockID": "0x004313a4bd4286e821b684cc1749deb3df12fa2a8114435fbd35baa155e82016", - "blockNumber": 4395940, - "blockTimestamp": 1574410670 - } - } - `); - - case '0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5': - return JSON.parse(` - { - "id": "0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5", - "chainTag": 74, - "blockRef": "0x0042249a647f63e7", - "expiration": 720, - "clauses": [ - { - "to": "0x00bae5ed35736e4ef17af1be0c6f50e0fb73d685", - "value": "0x38f6ea18e810b6f00", - "data": "0x" - } - ], - "gasPriceCoef": 0, - "gas": 21000, - "origin": "0xb5e883349e68ab59307d1604555ac890fac47128", - "delegator": null, - "nonce": "0x6fa76caac4c18bd", - "dependsOn": null, - "size": 130, - "meta": { - "blockID": "0x0042249bee56223e0ed7a9c7fcfffe8e61b9fd95d29d24843c558ff2c46ea094", - "blockNumber": 4334747, - "blockTimestamp": 1573795570 - } - } - `); - } - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/get/viacoin-api-address.js b/mock/ext-api-dyson/get/viacoin-api-address.js deleted file mode 100644 index be045dc72..000000000 --- a/mock/ext-api-dyson/get/viacoin-api-address.js +++ /dev/null @@ -1,89 +0,0 @@ -/// Mock for external Viacoin API -/// See: -/// curl "http://{Viacoin rpc}/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" -/// curl "http://localhost:3347/viacoin-api/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs" -/// curl "http://localhost:8437/v1/viacoin/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" - -module.exports = { - path: '/viacoin-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 'VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A': - return JSON.parse(` - { - "page": 1, - "totalPages": 785695, - "itemsOnPage": 2, - "address": "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A", - "balance": "120312392935", - "totalReceived": "18370512600313", - "totalSent": "18250200207378", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 1571390, - "transactions": [ - { - "txid": "1b311427cd4749cbebd5c1fc70896b9e92a58d6935ba75bb40ed4a9e22e4a6cb", - "version": 1, - "vin": [ - { - "sequence": 4294967295, - "n": 0, - "coinbase": "03a02873045ea2915d" - } - ], - "vout": [ - { - "value": "976562", - "n": 0, - "hex": "76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac", - "addresses": [ - "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" - ] - } - ], - "blockHash": "c590a4a7357d308917c6d3d8a8bd75b27968db346b965f2cd6e2be639e792f24", - "blockHeight": 7547040, - "confirmations": 3, - "blockTime": 1587712349, - "value": "976562", - "valueIn": "0", - "fees": "0", - "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0903a02873045ea2915dffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000" - }, - { - "txid": "e7393042e4b7755ba320a80ee734b0f0bd496a46fa3c9e9982c1a8176b6815b4", - "version": 1, - "vin": [ - { - "sequence": 4294967295, - "n": 0, - "coinbase": "039e2873045ea29101" - } - ], - "vout": [ - { - "value": "976562", - "n": 0, - "hex": "76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac", - "addresses": [ - "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A" - ] - } - ], - "blockHash": "87f245b6882d8d1a0a2122c5dd5e00a8a6ea0e811d8bc53cde5ba00a1a7b63ce", - "blockHeight": 7547038, - "confirmations": 5, - "blockTime": 1587712257, - "value": "976562", - "valueIn": "0", - "fees": "0", - "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff09039e2873045ea29101ffffffff01b2e60e00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/viacoin-api-xpub.js b/mock/ext-api-dyson/get/viacoin-api-xpub.js deleted file mode 100644 index 81906bf00..000000000 --- a/mock/ext-api-dyson/get/viacoin-api-xpub.js +++ /dev/null @@ -1,87 +0,0 @@ -/// Mock for external Viacoin API -/// See: -/// curl "http://{Viacoin rpc}/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs" -/// curl "http://localhost:3347/viacoin-api/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs" -/// curl "http://localhost:8437/v1/viacoin/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK" - -module.exports = { - path: '/viacoin-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1, - "address": "zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK", - "balance": "741749040", - "totalReceived": "57216749588", - "totalSent": "56475000548", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 39, - "transactions": [ - { - "txid": "bdff404da14940abd84f7cb741fe8f77ad5de5aefbb74254caee683fe2a9b540", - "version": 1, - "vin": [ - { - "txid": "32790f42de714507b6a1e6001a4a334600ac316937a98489c19821bba0d5c74f", - "vout": 1, - "n": 0, - "addresses": [ - "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" - ], - "value": "741862718" - } - ], - "vout": [ - { - "value": "100000000", - "n": 0, - "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", - "addresses": [ - "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" - ] - }, - { - "value": "641749040", - "n": 1, - "hex": "00143379fd40508ec2101e11c3519a31615de6e7b673", - "addresses": [ - "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp" - ] - } - ], - "blockHash": "0853179f0baef807426b977e4a9ae260ba1a3a3726dbb7513ff4150991f5827a", - "blockHeight": 7305935, - "confirmations": 117673, - "blockTime": 1581914336, - "value": "741749040", - "valueIn": "741862718", - "fees": "113678", - "hex": "010000000001014fc7d5a0bb2198c18984a9376931ac0046334a1a00e6a1b6074571de420f79320100000000000000000200e1f505000000001600143379fd40508ec2101e11c3519a31615de6e7b67330504026000000001600143379fd40508ec2101e11c3519a31615de6e7b67302473044022049b1d030bd9ec88ec343a52971d354b470d1357413675e985161bf2d5f8ca8ba02205d393b4d5232ae983faba4237e0c8feace5483493bf4da35313ce62459c87c66012102b5e09e1dbb76a0eeebea67bf80069ce41c26c81d0f06d1dd42e712ebf55de4bc00000000" - } - ], - "usedTokens": 40, - "tokens": [ - { - "type": "XPUBAddress", - "name": "via1qxdul6szs3mppq8s3cdge5vtpthnw0dnn06m5qp", - "path": "m/84'/14'/0'/0/0", - "transfers": 7, - "decimals": 8, - "balance": "741749040", - "totalReceived": "9445588154", - "totalSent": "8703839114" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/waves-api-transactions-address.js b/mock/ext-api-dyson/get/waves-api-transactions-address.js deleted file mode 100644 index c2756b7c3..000000000 --- a/mock/ext-api-dyson/get/waves-api-transactions-address.js +++ /dev/null @@ -1,60 +0,0 @@ -/// Waves API Mock -/// See: -/// curl "http://localhost:3347/waves-api/transactions/address/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD/limit/25" -/// curl "https://nodes.wavesnodes.com/transactions/address/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD/limit/25" -/// curl http://localhost:8437/v1/waves/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD -module.exports = { - path: "/waves-api/transactions/address/:address/limit/:limit", - template: function (params, query, body) { - //console.log(params) - if (params.address === '3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD') { - return [ - [ - { - senderPublicKey: "2UstBx1nMYQ2mPeaJi6tv9oUFCUHLvU1G7nS8Leazsbw", - amount: parseFloat("369133368000"), - signature: "5Hw5SW7C1EK8hE2YKawFCAWcJoB1Z5NSZFkA65bS3PcDY9w2fi7etPCJDamK2WNb14RWa3BykdT5yFd64SxodjeQ", - fee: parseFloat("100000"), - type: parseFloat("4"), - version: parseFloat("1"), - attachment: "", - sender: "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", - feeAssetId: null, - proofs: [ - "5Hw5SW7C1EK8hE2YKawFCAWcJoB1Z5NSZFkA65bS3PcDY9w2fi7etPCJDamK2WNb14RWa3BykdT5yFd64SxodjeQ" - ], - assetId: null, - recipient: "3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", - feeAsset: null, - id: "23JGFzBh65fzZArK6KSeRqjjBG5WnQshJJkUv53hCE1E", - timestamp: parseFloat("1582527770493"), - height: parseFloat("1943922") - }, - { - senderPublicKey: "3uT3a9ceebFf6vEa5DmedD5pK6xa1GY7PnvhWPMVyqxC", - amount: parseFloat("369133468000"), - signature: "3Nrz47KpD3U39Nf7Los23MDoukqXCrCJun1BqnUgjpy9iZLfXc163dTrz4wVvURC2yiULsNYDYA2pxTPGWpBotc5", - fee: parseFloat("100000"), - type: parseFloat("4"), - version: parseFloat("1"), - attachment: "Paribu", - sender: "3PHYYqBA6ZfBsoGsrXP8r7ZptLXYdGDt1Cm", - feeAssetId: null, - proofs: [ - "3Nrz47KpD3U39Nf7Los23MDoukqXCrCJun1BqnUgjpy9iZLfXc163dTrz4wVvURC2yiULsNYDYA2pxTPGWpBotc5" - ], - assetId: null, - recipient: "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", - feeAsset: null, - id: "1456haw7zSTKDmVSbY1njrYdskX7xKbv241c5WJjWhCu", - timestamp: parseFloat("1582527244669"), - height: parseFloat("1943911") - } - ] - ] - } - - return {error: "Not implemented"}; - } -} -; diff --git a/mock/ext-api-dyson/get/zcash-api-address.js b/mock/ext-api-dyson/get/zcash-api-address.js deleted file mode 100644 index 637c6d853..000000000 --- a/mock/ext-api-dyson/get/zcash-api-address.js +++ /dev/null @@ -1,149 +0,0 @@ -/// Mock for external Zcash API -/// See: -/// curl "http://{Zcash rpc}/api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" -/// curl "http://localhost:3347/zcash-api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs" -/// curl "http://localhost:8437/v1/zcash/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" - -module.exports = { - path: '/zcash-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 't1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX': - return JSON.parse(` - { - "page": 1, - "totalPages": 917, - "itemsOnPage": 2, - "address": "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX", - "balance": "12344656", - "totalReceived": "109663825939", - "totalSent": "109651481283", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 1833, - "transactions": [ - { - "txid": "ca640e5215e141a4f9c235dd91e4b99fd1e0defdd5da27d78ec2cee02d3493dc", - "version": 4, - "vin": [ - { - "sequence": 4294967295, - "n": 0, - "isAddress": false, - "coinbase": "0323520c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b" - } - ], - "vout": [ - { - "value": "0", - "n": 0, - "hex": "76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac", - "addresses": [ - "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" - ], - "isAddress": true - }, - { - "value": "125000000", - "n": 1, - "hex": "a914cdcd95aa6892db5fc849ac15804d2b9dd035a3b787", - "addresses": [ - "t3dKojUU2EMjs28nHV84TvkVEUDu1M1FaEx" - ], - "isAddress": true - }, - { - "value": "6250000", - "n": 2, - "hex": "76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac", - "addresses": [ - "t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv" - ], - "isAddress": true - }, - { - "value": "493750000", - "n": 3, - "hex": "76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac", - "addresses": [ - "t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2" - ], - "isAddress": true - } - ], - "blockHash": "000000000031b763658a48c735fa02d9e5181b12683cc66a93d79caf5f66e9b0", - "blockHeight": 807459, - "confirmations": 89, - "blockTime": 1587696399, - "value": "625000000", - "valueIn": "0", - "fees": "0", - "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff500323520c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914cdcd95aa6892db5fc849ac15804d2b9dd035a3b787105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000" - }, - { - "txid": "7bbf19b071907f23bd3d124d8f28a2aa8445a38d9f8a915487e9a36686c9094f", - "version": 4, - "vin": [ - { - "sequence": 4294967295, - "n": 0, - "isAddress": false, - "coinbase": "03a2510c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6b" - } - ], - "vout": [ - { - "value": "0", - "n": 0, - "hex": "76a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac", - "addresses": [ - "t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX" - ], - "isAddress": true - }, - { - "value": "125000000", - "n": 1, - "hex": "a914cdcd95aa6892db5fc849ac15804d2b9dd035a3b787", - "addresses": [ - "t3dKojUU2EMjs28nHV84TvkVEUDu1M1FaEx" - ], - "isAddress": true - }, - { - "value": "6250000", - "n": 2, - "spent": true, - "hex": "76a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688ac", - "addresses": [ - "t1gVpRrLdr8R2M2RaGisWZRspEF8EZvLZHv" - ], - "isAddress": true - }, - { - "value": "493750000", - "n": 3, - "spent": true, - "hex": "76a914521d713a3660b86d03ab6c68358433c30389ea1f88ac", - "addresses": [ - "t1RMngkaWf2F8EDrpzQ1fhLBhfi89L14tN2" - ], - "isAddress": true - } - ], - "blockHash": "00000000030219218c61edcf72dcd6c3512bbf9d3e5ffc34b607625d476dc558", - "blockHeight": 807330, - "confirmations": 218, - "blockTime": 1587686790, - "value": "625000000", - "valueIn": "0", - "fees": "0", - "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff5003a2510c0044656661756c7420732d6e6f6d7020706f6f6c2068747470733a2f2f6769746875622e636f6d2f732d6e6f6d702f732d6e6f6d702f77696b692f496e73696768742d706f6f6c2d6c696e6bffffffff0400000000000000001976a914219d1bea95fc9c401d4073a20f840c71fc1a920288ac405973070000000017a914cdcd95aa6892db5fc849ac15804d2b9dd035a3b787105e5f00000000001976a914f82c1c9f44630fe1a9ab4cb1b5023c91ee4ddae688acf0066e1d000000001976a914521d713a3660b86d03ab6c68358433c30389ea1f88ac00000000000000000000000000000000000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/zcash-api-xpub.js b/mock/ext-api-dyson/get/zcash-api-xpub.js deleted file mode 100644 index 84612673a..000000000 --- a/mock/ext-api-dyson/get/zcash-api-xpub.js +++ /dev/null @@ -1,126 +0,0 @@ -/// Mock for external Zcash API -/// See: -/// curl "http://{Zcash rpc}/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs" -/// curl "http://localhost:3347/zcash-api/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs" -/// curl "http://localhost:8437/v1/zcash/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS" - -module.exports = { - path: '/zcash-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 2, - "address": "xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS", - "balance": "846466", - "totalReceived": "14304018", - "totalSent": "13457552", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 38, - "transactions": [ - { - "txid": "f2438a93039faf08d39bd3df1f7b5f19a2c29ffe8753127e2956ab4461adab35", - "version": 4, - "vin": [ - { - "txid": "ee120b714991e6166b8ff4b6419cbfee657eca87675245ce8585787be3b07d70", - "vout": 1, - "n": 0, - "addresses": [ - "t1LJWoRDU14zUG4TGumHiobd9WBUjqLE5FU" - ], - "isAddress": true, - "value": "956466", - "hex": "483045022100d2ac7b2b17218572f3dc163063463be5143a8d3c2126b52eb73d49c9c4959da00220057417baaad53c168e82dd44a7f964759c7d584e0770b6284a8e1b0261f1c7e0012102a71eeea42aa1b4e30a409f9186bd88dc84dec5c404964f386c323f557ad268d9" - } - ], - "vout": [ - { - "value": "100000", - "n": 0, - "hex": "76a914a2511fc37f67f3b5627affce89fb3f7bb186412888ac", - "addresses": [ - "t1Yfrf1dssDLmaMBsq2LFKWPbS5vH3nGpa2" - ], - "isAddress": true - }, - { - "value": "846466", - "n": 1, - "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", - "addresses": [ - "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM" - ], - "isAddress": true - } - ], - "blockHash": "00000000005a238fecd893e55fba7072af65545fd43eaad63402c211cc172a61", - "blockHeight": 750255, - "confirmations": 18102, - "blockTime": 1583385097, - "value": "946466", - "valueIn": "956466", - "fees": "10000", - "hex": "0400008085202f8901707db0e37b788585ce45526787ca7e65eebf9c41b6f48f6b16e69149710b12ee010000006b483045022100d2ac7b2b17218572f3dc163063463be5143a8d3c2126b52eb73d49c9c4959da00220057417baaad53c168e82dd44a7f964759c7d584e0770b6284a8e1b0261f1c7e0012102a71eeea42aa1b4e30a409f9186bd88dc84dec5c404964f386c323f557ad268d90000000002a0860100000000001976a914a2511fc37f67f3b5627affce89fb3f7bb186412888ac82ea0c00000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac00000000000000000000000000000000000000" - }, - { - "txid": "ee120b714991e6166b8ff4b6419cbfee657eca87675245ce8585787be3b07d70", - "version": 4, - "vin": [ - { - "txid": "b49791a277ff137e37f9e163c8a5bc25492f741c275f9d36d5c0c713497c176c", - "vout": 1, - "sequence": 2147483646, - "n": 0, - "addresses": [ - "t1fuw3P3r5xbJXFqpaHUWb3TMz6xo9yPXEL" - ], - "isAddress": true, - "value": "996466", - "hex": "483045022100e7ddc39a2b976ee277d71f6130334084f1f21ef4f17cdd81514cf8af2181df1b02201c9a76a45b948c87940dc47525f1660d6c9c1e44ab22e4bcc16af0ce99c4c1890121031a03d4f4982aaa59d4087434907c9578fe77eadc73491b32f7373aaf9c17902e" - } - ], - "vout": [ - { - "value": "30000", - "n": 0, - "spent": true, - "hex": "76a914db49ca3524ee1e99aa097c6c9860ffcb5e5ed94a88ac", - "addresses": [ - "t1ds6PMeHUvAYtASPqCuEXzT1DsteXWwtTv" - ], - "isAddress": true - }, - { - "value": "956466", - "n": 1, - "spent": true, - "hex": "76a9141aa64e287339ad3fa041bc7a429bbcd57ac8a80088ac", - "addresses": [ - "t1LJWoRDU14zUG4TGumHiobd9WBUjqLE5FU" - ], - "isAddress": true - } - ], - "blockHash": "00000000008dcc62d679d7eaf05ac18403198f5f39b3e4e7f36869673855779b", - "blockHeight": 685806, - "confirmations": 82551, - "blockTime": 1578529212, - "value": "986466", - "valueIn": "996466", - "fees": "10000", - "hex": "0400008085202f89016c177c4913c7c0d5369d5f271c742f4925bca5c863e1f9377e13ff77a29197b4010000006b483045022100e7ddc39a2b976ee277d71f6130334084f1f21ef4f17cdd81514cf8af2181df1b02201c9a76a45b948c87940dc47525f1660d6c9c1e44ab22e4bcc16af0ce99c4c1890121031a03d4f4982aaa59d4087434907c9578fe77eadc73491b32f7373aaf9c17902efeffff7f0230750000000000001976a914db49ca3524ee1e99aa097c6c9860ffcb5e5ed94a88ac32980e00000000001976a9141aa64e287339ad3fa041bc7a429bbcd57ac8a80088ac00000000000000000000000000000000000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/zcoin-api-address.js b/mock/ext-api-dyson/get/zcoin-api-address.js deleted file mode 100644 index 9257ac3b8..000000000 --- a/mock/ext-api-dyson/get/zcoin-api-address.js +++ /dev/null @@ -1,124 +0,0 @@ -/// Mock for external Zcoin API -/// See: -/// curl "http://{Zcoin rpc}/api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" -/// curl "http://localhost:3347/zcoin-api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs" -/// curl "http://localhost:8437/v1/zcoin/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - -module.exports = { - path: '/zcoin-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 'a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn': - return JSON.parse(` - { - "page": 1, - "totalPages": 9, - "itemsOnPage": 2, - "address": "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn", - "balance": "63109110", - "totalReceived": "1565104974", - "totalSent": "1501995864", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 18, - "transactions": [ - { - "txid": "f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609", - "version": 1, - "vin": [ - { - "txid": "cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564", - "vout": 1, - "n": 0, - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true, - "value": "51916634", - "hex": "483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" - } - ], - "vout": [ - { - "value": "13113178", - "n": 0, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - }, - { - "value": "38799388", - "n": 1, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - } - ], - "blockHash": "f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328", - "blockHeight": 251191, - "confirmations": 10102, - "blockTime": 1584663676, - "value": "51912566", - "valueIn": "51916634", - "fees": "4068", - "hex": "010000000164b574c298c44b23fc6f328494ff306444895262d7f670ebb2a5c48233ac33cd010000006b483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b1500000000025a17c800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac1c085002000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564", - "version": 1, - "vin": [ - { - "txid": "50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd", - "vout": 1, - "n": 0, - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true, - "value": "61920702", - "hex": "483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" - } - ], - "vout": [ - { - "value": "10000000", - "n": 0, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - }, - { - "value": "51916634", - "n": 1, - "spent": true, - "spentTxId": "f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609", - "spentHeight": 251191, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - } - ], - "blockHash": "f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328", - "blockHeight": 251191, - "confirmations": 10102, - "blockTime": 1584663676, - "value": "61916634", - "valueIn": "61920702", - "fees": "4068", - "hex": "0100000001fd296277b76a406837115f9213f3ce6ebfdb8408447c1423281c034e387acb50010000006b483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15000000000280969800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac5a2f1803000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/zcoin-api-xpub.js b/mock/ext-api-dyson/get/zcoin-api-xpub.js deleted file mode 100644 index 0fe98efda..000000000 --- a/mock/ext-api-dyson/get/zcoin-api-xpub.js +++ /dev/null @@ -1,422 +0,0 @@ -/// Mock for external Zcoin API -/// See: -/// curl "http://{Zcoin rpc}/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs" -/// curl "http://localhost:3347/zcoin-api/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs" -/// curl "http://localhost:8437/v1/zcoin/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK" - -module.exports = { - path: '/zcoin-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK", - "balance": "63109110", - "totalReceived": "19765346316", - "totalSent": "19702237206", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 54, - "transactions": [ - { - "txid": "cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564", - "version": 1, - "vin": [ - { - "txid": "50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd", - "vout": 1, - "n": 0, - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true, - "value": "61920702", - "hex": "483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" - } - ], - "vout": [ - { - "value": "10000000", - "n": 0, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - }, - { - "value": "51916634", - "n": 1, - "spent": true, - "spentTxId": "f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609", - "spentHeight": 251191, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - } - ], - "blockHash": "f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328", - "blockHeight": 251191, - "confirmations": 1518, - "blockTime": 1584663676, - "value": "61916634", - "valueIn": "61920702", - "fees": "4068", - "hex": "0100000001fd296277b76a406837115f9213f3ce6ebfdb8408447c1423281c034e387acb50010000006b483045022100aff10fef2849988470ac3411bd463ae03a17a88336283290095f8247dc0531a4022064f2c0e60662effb5b46c2a70318331b007df7441a209e2bf6489924c73952f50121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15000000000280969800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac5a2f1803000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609", - "version": 1, - "vin": [ - { - "txid": "cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564", - "vout": 1, - "n": 0, - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true, - "value": "51916634", - "hex": "483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" - } - ], - "vout": [ - { - "value": "13113178", - "n": 0, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - }, - { - "value": "38799388", - "n": 1, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - } - ], - "blockHash": "f85889dc565371828f3c0821f2507ca2fa2f83eae557b7d3ba7270eab6ac7328", - "blockHeight": 251191, - "confirmations": 1518, - "blockTime": 1584663676, - "value": "51912566", - "valueIn": "51916634", - "fees": "4068", - "hex": "010000000164b574c298c44b23fc6f328494ff306444895262d7f670ebb2a5c48233ac33cd010000006b483045022100dc5a93fa3bd1f61115062700756163da79860b38fe348aa9c3bc5d9c578c8d55022048f2f300dce9858fa3a24e05084bb892287a623b40271289cb5fce9783e77b730121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b1500000000025a17c800000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac1c085002000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd", - "version": 1, - "vin": [ - { - "txid": "11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45", - "vout": 1, - "n": 0, - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true, - "value": "62924770", - "hex": "4830450221009e0fe641502a598f5f470ff3a5cb4bd46e2906e0e09c7a8c93d80bfd61cfb26e0220199247204747faf99e8605e7c6af4a1a8489c2a133b92f1f547990cef62cc9f60121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" - } - ], - "vout": [ - { - "value": "1000000", - "n": 0, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - }, - { - "value": "61920702", - "n": 1, - "spent": true, - "spentTxId": "cd33ac3382c4a5b2eb70f6d7625289446430ff9484326ffc234bc498c274b564", - "spentHeight": 251191, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - } - ], - "blockHash": "1cb40b2f2d4618cd9606b0f476d2ccfeee4740bb76cd46e2c75df6e783017cb1", - "blockHeight": 251156, - "confirmations": 1553, - "blockTime": 1584656561, - "value": "62920702", - "valueIn": "62924770", - "fees": "4068", - "hex": "010000000145db9ddeddd58b983e4e7aa6909c09aa34fddf13657f512bba0821deeb51a011010000006b4830450221009e0fe641502a598f5f470ff3a5cb4bd46e2906e0e09c7a8c93d80bfd61cfb26e0220199247204747faf99e8605e7c6af4a1a8489c2a133b92f1f547990cef62cc9f60121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15000000000240420f00000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788acbed5b003000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45", - "version": 1, - "vin": [ - { - "txid": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", - "vout": 1, - "n": 0, - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true, - "value": "63028838", - "hex": "483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" - } - ], - "vout": [ - { - "value": "100000", - "n": 0, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - }, - { - "value": "62924770", - "n": 1, - "spent": true, - "spentTxId": "50cb7a384e031c2823147c440884dbbf6ecef313925f113768406ab7776229fd", - "spentHeight": 251156, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - } - ], - "blockHash": "5ba0f8c0e58986d1eb5036e766e28ed541d0993cb717fc1aea46d714a89945e7", - "blockHeight": 250864, - "confirmations": 1845, - "blockTime": 1584571576, - "value": "63024770", - "valueIn": "63028838", - "fees": "4068", - "hex": "0100000001ef273981817358e256ecb5e87a9826056893b8e2672e49a6a8c29b0fe343fb86010000006b483045022100dde950aa0f6d73c2e78afdb66a138ff3ca481983977baad260c0632dfb2b4ee202202c840111ac82603f436bb698a8d9a50f97d0155b2d4c4576ed66ad4ad6b901020121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b150000000002a0860100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ace227c003000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", - "version": 1, - "vin": [ - { - "txid": "5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e", - "vout": 1, - "sequence": 4294967294, - "n": 0, - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true, - "value": "64032906", - "hex": "483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15" - } - ], - "vout": [ - { - "value": "1000000", - "n": 0, - "hex": "76a914cffef031eead7d332c245df1372dcf4980a0127c88ac", - "addresses": [ - "aKgF22yWfjBqekrbkhkFYqenzsw9zfRch8" - ], - "isAddress": true - }, - { - "value": "63028838", - "n": 1, - "spent": true, - "spentTxId": "11a051ebde2108ba2b517f6513dffd34aa099c90a67a4e3e988bd5ddde9ddb45", - "spentHeight": 250864, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - } - ], - "blockHash": "fcfea4d17cde4cfc8d113d923e7e2978513e902448f1087fd448ae4162696f4f", - "blockHeight": 244409, - "confirmations": 8300, - "blockTime": 1582620606, - "value": "64028838", - "valueIn": "64032906", - "fees": "4068", - "hex": "01000000011e60be361fdabd33a545444bd7c0a6571e6e1fa9d92e65676da700d0aeebf75c010000006b483045022100b3638e753ae9136ee38906754c8d7e44e10e3f1b08dc37948ba317a5e28eb8e60220391cca6fb14eb0392c03df3bfb9639ae76a523ad7bc3f669483d5afa7ed629570121030987bda3c78bd6e2dd765f3767cc3611cd05c9e3c0d49873f2cd68d3fd305b15feffffff0240420f00000000001976a914cffef031eead7d332c245df1372dcf4980a0127c88ac66bec103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "4178eb3a84a34a9b508dbb61abbe725de115de2daea619e1cfa68eadf001fe51", - "version": 1, - "vin": [ - { - "txid": "6de60b862ef752e24f1417c255f750e8e2e2b64ce4160eccbcdd82663a36daeb", - "n": 0, - "addresses": [ - "aDVvWiM5PTv3QrUbrWQW3hPVLiFTMmzAHr" - ], - "isAddress": true, - "value": "100000", - "hex": "483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b" - } - ], - "vout": [ - { - "value": "96544", - "n": 0, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - } - ], - "blockHash": "e3d64bc33182f0b74b6247c7b37a9f8ff3c6852fe1c08116d460d067919345d1", - "blockHeight": 241112, - "confirmations": 11597, - "blockTime": 1581616858, - "value": "96544", - "valueIn": "100000", - "fees": "3456", - "hex": "0100000001ebda363a6682ddbccc0e16e44cb6e2e2e850f755c217144fe252f72e860be66d000000006b483045022100e51595fc45741b1d43f5cef9b662605a98634644fc4281ddb471d5feee389bc402207b8b6d103f94ff1278a5d364b92b395021496c39b3f06241ca584036567fb54d012102ed835d6c0f1f4c0df53bbd728376362180010101f0ce9d79bf4ce61363d14b4b000000000120790100000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e", - "version": 1, - "vin": [ - { - "txid": "5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241", - "vout": 1, - "n": 0, - "addresses": [ - "aL96Xr2E1pMW3vcsZ5QV6BYLFE9jdCVBJL" - ], - "isAddress": true, - "value": "364036974", - "hex": "483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8" - } - ], - "vout": [ - { - "value": "300000000", - "n": 0, - "spent": true, - "spentTxId": "736d2ed9a2398511cc98f30df178db721716c1996fd8ab67970a5ac41a795e72", - "spentIndex": 2, - "spentHeight": 239559, - "hex": "76a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac", - "addresses": [ - "aB3mWSqhFzszMJ3h8sxTedFYDhZCDBkeQT" - ], - "isAddress": true - }, - { - "value": "64032906", - "n": 1, - "spent": true, - "spentTxId": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef", - "spentHeight": 244409, - "hex": "76a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac", - "addresses": [ - "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn" - ], - "isAddress": true - } - ], - "blockHash": "07d7c24529ee402be1a94b6b5a70d000c6002f0fa7201c1f5ef4ef7dd87f0117", - "blockHeight": 239551, - "confirmations": 13158, - "blockTime": 1581138788, - "value": "364032906", - "valueIn": "364036974", - "fees": "4068", - "hex": "010000000141320e1d67dca17a2d7107f1e3b378fbf443347afb21e16d130be718a8ce8254010000006b483045022100c2a0003ab30fe8f3ffbb20e9cc38232256ce27b287c24293eff40fe4224f933502202882f50cb71e93fb432c8f244ae7dbe7f52f492452a1da68003cc0d43e9fea08012103cf5fc72d3c15e517443f8fc4295c816e5a791d7e8971943ce7c45a7bfd1ca8e8000000000200a3e111000000001976a9147157fe38b8108bcc0f8b6ea5cab365e2233ed0e888ac8a10d103000000001976a914526ac6dd84927e5e26dc6c89976d58ea4c1a4d4788ac00000000" - }, - { - "txid": "5482cea818e70b136de121fb7a3443f4fb78b3e3f107712d7aa1dc671d0e3241", - "version": 1, - "vin": [ - { - "txid": "c4f897a1d64e6c870184ff26a3ad8f5f4a94a6667f6d3486f21e52530d8ecea2", - "sequence": 4294967294, - "n": 0, - "addresses": [ - "aMde4RuTWiNzoZN53SWZ7i7tKNbhSwt57U" - ], - "isAddress": true, - "value": "365041042", - "hex": "4730440220260b40074ffa84cf4f747433efdc524a347bf9f2b995a212a7c7fafeeb9105180220222edad73b70511698a9dc68ae246b78a7ba9daf3c1b44fb5d7fdd4d8d008d890121035209cb9a9c86a775cb9593b4c6fdde4f23e4bb4193cfeae0706080702189efa3" - } - ], - "vout": [ - { - "value": "1000000", - "n": 0, - "spent": true, - "spentTxId": "c70c9d3bf599a9e3553b6235f6468c69c1fa54aa0505e49d81e37aa1a749379a", - "spentHeight": 238297, - "hex": "76a91480be9e18824eae9cc7771291b7a017a458fb48b388ac", - "addresses": [ - "aCTCaoLEy6ZbKQGKjBe1kprQ4foEa2cBVv" - ], - "isAddress": true - }, - { - "value": "364036974", - "n": 1, - "spent": true, - "spentTxId": "5cf7ebaed000a76d67652ed9a91f6e1e57a6c0d74b4445a533bdda1f36be601e", - "spentHeight": 239551, - "hex": "76a914d51315e0d5624c84e9da869bd34735926022ae5888ac", - "addresses": [ - "aL96Xr2E1pMW3vcsZ5QV6BYLFE9jdCVBJL" - ], - "isAddress": true - } - ], - "blockHash": "fc464897e8c6bcbd5bede4109a24075894a61d3a2d7aa06cc0bc1a37b07d1903", - "blockHeight": 238210, - "confirmations": 14499, - "blockTime": 1580718580, - "value": "365036974", - "valueIn": "365041042", - "fees": "4068", - "hex": "0100000001a2ce8e0d53521ef286346d7f66a6944a5f8fada326ff8401876c4ed6a197f8c4000000006a4730440220260b40074ffa84cf4f747433efdc524a347bf9f2b995a212a7c7fafeeb9105180220222edad73b70511698a9dc68ae246b78a7ba9daf3c1b44fb5d7fdd4d8d008d890121035209cb9a9c86a775cb9593b4c6fdde4f23e4bb4193cfeae0706080702189efa3feffffff0240420f00000000001976a91480be9e18824eae9cc7771291b7a017a458fb48b388ac6ec3b215000000001976a914d51315e0d5624c84e9da869bd34735926022ae5888ac00000000" - } - ], - "usedTokens": 52, - "tokens": [ - { - "type": "XPUBAddress", - "name": "a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn", - "path": "m/44'/136'/0'/0/0", - "transfers": 18, - "decimals": 8, - "balance": "63109110", - "totalReceived": "1565104974", - "totalSent": "1501995864" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/zelcash-api-address.js b/mock/ext-api-dyson/get/zelcash-api-address.js deleted file mode 100644 index a8e3bd4bd..000000000 --- a/mock/ext-api-dyson/get/zelcash-api-address.js +++ /dev/null @@ -1,137 +0,0 @@ -/// Mock for external Zelcash API -/// See: -/// curl "http://{Zelcash rpc}/api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs&pageSize=25" -/// curl "http://localhost:3347/zelcash-api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs" -/// curl "http://localhost:8437/v1/zelcash/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" - -module.exports = { - path: '/zelcash-api/v2/address/:address?', - template: function(params, query, body) { - switch (params.address) { - case 't1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa': - return JSON.parse(` - { - "page": 1, - "totalPages": 58223, - "itemsOnPage": 2, - "address": "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa", - "balance": "787501194898", - "totalReceived": "1224870418723238", - "totalSent": "1224082917528340", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 116445, - "transactions": [ - { - "txid": "58b5ce7d497d95e21ad9ebe2f2a3fb480483f77ca4de3ce1bc9a95eb9c0d18e1", - "version": 4, - "vin": [ - { - "sequence": 4294967295, - "n": 0, - "coinbase": "0322e80800324d696e6572732068747470733a2f2f326d696e6572732e636f6d" - } - ], - "vout": [ - { - "value": "11250000000", - "n": 0, - "hex": "76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac", - "addresses": [ - "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" - ] - }, - { - "value": "562500000", - "n": 1, - "hex": "76a914cc069c2af44790f67f6d1a26fa4668cd18ae3cee88ac", - "addresses": [ - "t1cUPmjzAv1UHmVDbdhwJTXQWER1Y9RXrab" - ] - }, - { - "value": "937500000", - "n": 2, - "hex": "76a9147e89c1c8a911588d4dd2df5ee0906de9b367631c88ac", - "addresses": [ - "t1VQgB2axkuPhYQfsbvUG7Wfhfm7WBEYiEb" - ] - }, - { - "value": "2250000000", - "n": 3, - "hex": "76a914c33faabb9d5162c37c0b29dcdb357a39738637b888ac", - "addresses": [ - "t1bfz3Q3E1adjroiPrGXaWsWNJ7u3WJHBgS" - ] - } - ], - "blockHash": "0000009f069aa63aef11ed375763532f3863bb2f03135827e1d6dfc5af3c4746", - "blockHeight": 583714, - "confirmations": 2, - "blockTime": 1587702257, - "value": "15000000000", - "valueIn": "0", - "fees": "0", - "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff200322e80800324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff0480608d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a914cc069c2af44790f67f6d1a26fa4668cd18ae3cee88ac601de137000000001976a9147e89c1c8a911588d4dd2df5ee0906de9b367631c88ac80461c86000000001976a914c33faabb9d5162c37c0b29dcdb357a39738637b888ac00000000000000000000000000000000000000" - }, - { - "txid": "eaddfc88f931b67c3046b8046fa96831fdeb590db9be4b1e59e706479b0f3012", - "version": 4, - "vin": [ - { - "sequence": 4294967295, - "n": 0, - "coinbase": "031fe80800324d696e6572732068747470733a2f2f326d696e6572732e636f6d" - } - ], - "vout": [ - { - "value": "11250011000", - "n": 0, - "hex": "76a91404e2699cec5f44280540fb752c7660aa3ba857cc88ac", - "addresses": [ - "t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa" - ] - }, - { - "value": "562500000", - "n": 1, - "hex": "76a9148a8b9570ece58cfce36487fe68da103964f2ff4288ac", - "addresses": [ - "t1WWAUFtKyytFzuXpn3Rzc6fGFndzD6xWLK" - ] - }, - { - "value": "937500000", - "n": 2, - "hex": "76a914c6e488b6eaa3becba6a1f439d3a5c05a41b6b77f88ac", - "addresses": [ - "t1c1Fa9ARp7KvHgEi3SKefpkLzy2yBTZvZc" - ] - }, - { - "value": "2250000000", - "n": 3, - "hex": "76a91446f4a65996b3689d296445f2a1170f9f87c2f82e88ac", - "addresses": [ - "t1QLnPL6ozQjArqX4QSDesMNkXTFWUUhbeF" - ] - } - ], - "blockHash": "0000006926830de74fa8629389bb21802ecbfe254ab52198678de133ed6c3b22", - "blockHeight": 583711, - "confirmations": 5, - "blockTime": 1587701924, - "value": "15000011000", - "valueIn": "0", - "fees": "0", - "hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff20031fe80800324d696e6572732068747470733a2f2f326d696e6572732e636f6dffffffff04788b8d9e020000001976a91404e2699cec5f44280540fb752c7660aa3ba857cc88aca0118721000000001976a9148a8b9570ece58cfce36487fe68da103964f2ff4288ac601de137000000001976a914c6e488b6eaa3becba6a1f439d3a5c05a41b6b77f88ac80461c86000000001976a91446f4a65996b3689d296445f2a1170f9f87c2f82e88ac00000000000000000000000000000000000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/zelcash-api-xpub.js b/mock/ext-api-dyson/get/zelcash-api-xpub.js deleted file mode 100644 index 62f932ce7..000000000 --- a/mock/ext-api-dyson/get/zelcash-api-xpub.js +++ /dev/null @@ -1,196 +0,0 @@ -/// Mock for external Zelcash API -/// See: -/// curl "http://{Zelcash rpc}/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs" -/// curl "http://localhost:3347/zelcash-api/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs" -/// curl "http://localhost:8437/v1/zelcash/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf" - -module.exports = { - path: '/zelcash-api/v2/xpub/:xpubkey?', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.xpubkey) { - case 'xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf': - return JSON.parse(` - { - "page": 1, - "totalPages": 1, - "itemsOnPage": 1000, - "address": "xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf", - "balance": "9209317640", - "totalReceived": "135114824440", - "totalSent": "125905506800", - "unconfirmedBalance": "0", - "unconfirmedTxs": 0, - "txs": 29, - "transactions": [ - { - "txid": "640ea080f060fbfcc6722f861c93483551a831020f6731a37ba5383da71b4972", - "version": 4, - "vin": [ - { - "txid": "a3db9e10aa146805477b9012130e6f68d473975095b82c7e6e6ab5f409da9eef", - "n": 0, - "addresses": [ - "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" - ], - "value": "1000000", - "hex": "47304402205f7e4f5c17f6bf9880bd0afecec581253419a7b94a440fc9d4a4f4c35ee5b69102203a5c1ba8fc40098e9de6d4df71bb364e9028ddf9eb6ec31e42a1293c19170d8d012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" - } - ], - "vout": [ - { - "value": "100000", - "n": 0, - "spent": true, - "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", - "addresses": [ - "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" - ] - }, - { - "value": "890000", - "n": 1, - "spent": true, - "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", - "addresses": [ - "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" - ] - } - ], - "blockHash": "0000004957cd52c4654e44b0a02cd33be907ae3ae47949e44984cccaf0e34e96", - "blockHeight": 560762, - "confirmations": 1627, - "blockTime": 1584928030, - "value": "990000", - "valueIn": "1000000", - "fees": "10000", - "hex": "0400008085202f8901ef9eda09f4b56a6e7e2cb895509773d4686f0e1312907b47056814aa109edba3000000006a47304402205f7e4f5c17f6bf9880bd0afecec581253419a7b94a440fc9d4a4f4c35ee5b69102203a5c1ba8fc40098e9de6d4df71bb364e9028ddf9eb6ec31e42a1293c19170d8d012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e366440000000002a0860100000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac90940d00000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac00000000000000000000000000000000000000" - }, - { - "txid": "a3db9e10aa146805477b9012130e6f68d473975095b82c7e6e6ab5f409da9eef", - "version": 4, - "vin": [ - { - "txid": "2de19629bbf78af114ff9cf3332229dc336be4758481b72828f1bd786e8cc41e", - "vout": 1, - "n": 0, - "addresses": [ - "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" - ], - "value": "899960000", - "hex": "4830450221008f14795cde861210cbd9a1c3d89a29f0efe5c3cdceb2049795d5a9a84cc2571f02203c4e360575b7e5a45b067382b7d4e3fadbc80382eaa32e08a0bba46ae9bc7cb9012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644" - } - ], - "vout": [ - { - "value": "1000000", - "n": 0, - "spent": true, - "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", - "addresses": [ - "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" - ] - }, - { - "value": "898950000", - "n": 1, - "spent": true, - "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", - "addresses": [ - "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" - ] - } - ], - "blockHash": "0000008979ea8aac4d45ae6b5db721845d2d909e723b8fbb87d81f528a7ceefe", - "blockHeight": 558864, - "confirmations": 3525, - "blockTime": 1584697832, - "value": "899950000", - "valueIn": "899960000", - "fees": "10000", - "hex": "0400008085202f89011ec48c6e78bdf12828b7818475e46b33dc292233f39cff14f18af7bb2996e12d010000006b4830450221008f14795cde861210cbd9a1c3d89a29f0efe5c3cdceb2049795d5a9a84cc2571f02203c4e360575b7e5a45b067382b7d4e3fadbc80382eaa32e08a0bba46ae9bc7cb9012103aa6d9069ced0b9b556ac6eb7468d5f15422b16903507e8651824c1b7e6e36644000000000240420f00000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac70e39435000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac00000000000000000000000000000000000000" - }, - { - "txid": "2de19629bbf78af114ff9cf3332229dc336be4758481b72828f1bd786e8cc41e", - "version": 4, - "vin": [ - { - "txid": "7db9135b1dabcecccff9e4d403802d1bf0d7850438233b3091b876331bab551b", - "n": 0, - "addresses": [ - "t1MpHLd2vryyTufEMF3WBHy7VP63YKigi53" - ], - "value": "999970000", - "hex": "473044022040534cefd8cfbe8f2705032a3636067fb8612ec3449f75699fcd894e5f2dc9960220363c26ddbbdb840fc76fbb950aecbfd6fa7d03e64da1c5890c302f0bb6f007a8012103d6bf5faa2c95ae8c4572f0755f45dba20dcd806ef8344a5dc2a54996874661c4" - } - ], - "vout": [ - { - "value": "100000000", - "n": 0, - "hex": "76a914a394f62bbe0a47af97171e99bd8ff4fed9cae33188ac", - "addresses": [ - "t1YnYbdwU1ReMUbN46byAQNtnDPqMRYxFPJ" - ] - }, - { - "value": "899960000", - "n": 1, - "spent": true, - "hex": "76a9143b6a6100245510218dc29b313b988df0628ab36388ac", - "addresses": [ - "t1PHmJzMdeErPQGL9WEavrVakYiCzxKXi9z" - ] - } - ], - "blockHash": "0000007f0db0ed2ac5f5747e7746dc5e016e1f2a84df54115e85eee4d7aecb3b", - "blockHeight": 547987, - "confirmations": 14402, - "blockTime": 1583385317, - "value": "999960000", - "valueIn": "999970000", - "fees": "10000", - "hex": "0400008085202f89011b55ab1b3376b891303b23380485d7f01b2d8003d4e4f9cfccceab1d5b13b97d000000006a473044022040534cefd8cfbe8f2705032a3636067fb8612ec3449f75699fcd894e5f2dc9960220363c26ddbbdb840fc76fbb950aecbfd6fa7d03e64da1c5890c302f0bb6f007a8012103d6bf5faa2c95ae8c4572f0755f45dba20dcd806ef8344a5dc2a54996874661c4000000000200e1f505000000001976a914a394f62bbe0a47af97171e99bd8ff4fed9cae33188acc04ca435000000001976a9143b6a6100245510218dc29b313b988df0628ab36388ac00000000000000000000000000000000000000" - }, - { - "txid": "7db9135b1dabcecccff9e4d403802d1bf0d7850438233b3091b876331bab551b", - "version": 4, - "vin": [ - { - "txid": "3ce3913910d9aab7ddb308b16abd6d5d66c258737b5f86e829cc741fa317820b", - "n": 0, - "addresses": [ - "t1YnYbdwU1ReMUbN46byAQNtnDPqMRYxFPJ" - ], - "value": "999980000", - "hex": "483045022100fdf9542e8c44a218601d427ac9d8262866083c3ac1312c1448c345ed54782901022077a4c5e1d22657e000a2c76dc6f873fcb70b7298bd627dd3dc7bb24fa6175ab10121033985b538c7c62cd419a5b24e0dd8d322174303f376e025fddd1f19da2cebcc50" - } - ], - "vout": [ - { - "value": "999970000", - "n": 0, - "spent": true, - "hex": "76a9142b3fac242eb3d7e20130082190605a5f7750037788ac", - "addresses": [ - "t1MpHLd2vryyTufEMF3WBHy7VP63YKigi53" - ] - } - ], - "blockHash": "00000021b6af345a3d3010cdf9811fa9ca1f1163841519f2906ababa766b21ec", - "blockHeight": 494906, - "confirmations": 67483, - "blockTime": 1576977235, - "value": "999970000", - "valueIn": "999980000", - "fees": "10000", - "hex": "0400008085202f89010b8217a31f74cc29e8865f7b7358c2665d6dbd6ab108b3ddb7aad9103991e33c000000006b483045022100fdf9542e8c44a218601d427ac9d8262866083c3ac1312c1448c345ed54782901022077a4c5e1d22657e000a2c76dc6f873fcb70b7298bd627dd3dc7bb24fa6175ab10121033985b538c7c62cd419a5b24e0dd8d322174303f376e025fddd1f19da2cebcc500000000001d0549a3b000000001976a9142b3fac242eb3d7e20130082190605a5f7750037788ac00000000000000000000000000000000000000" - } - ] - } - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js b/mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js deleted file mode 100644 index ae84e9283..000000000 --- a/mock/ext-api-dyson/get/zilliqa-api-addresses-txs.js +++ /dev/null @@ -1,49 +0,0 @@ -/// Mock for external Zilliqa API -/// See: -/// curl -H "X-APIKEY: YOUR_API_KEY" "https://api.viewblock.io/v1/zilliqa/addresses/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z/txs" -/// curl "http://localhost:3347/zilliqa-api/addresses/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z/txs" -/// curl "http://localhost:8437/v1/zilliqa/zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z" - -module.exports = { - path: '/zilliqa-api/addresses/:address/txs', - template: function(params, query, body) { - //console.log(params) - //console.log(query) - switch (params.address) { - case 'zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z': - return JSON.parse(` - [ - { - "hash": "0xa5d0e0cefd6f114e9659f15016f9f4a303a8367eb373beb6909ee44f7f39834d", - "blockHeight": 459052, - "from": "zil10lx2eurx5hexaca0lshdr75czr025cevqu83uz", - "to": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", - "value": "1000000000000", - "fee": "1000000000", - "timestamp": 1583384813191, - "signature": "0x00AF9733DF8FAEFA0FCC9BBAD21DB30A4815749C19CBFFA5A3BCE75A199E4C84FB4728CB946A2F043B8FCA338C8EEC26855CD7B88D8925E69F87CADF5D072343", - "direction": "in", - "nonce": 25, - "receiptSuccess": true, - "events": [] - }, - { - "hash": "0xe29a7e17402c0c067af4c285dedc79114fe62f23d39843c15756db4641f1a00d", - "blockHeight": 414452, - "from": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", - "to": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", - "value": "10000000000", - "fee": "1000000000", - "timestamp": 1580891803587, - "signature": "0xA5F2C86098A37149CDDD0884009FF1032714DDAC07B2831C87E1FEEB16B8D9B5EB5D310D042003B3AA27A31BE16FD62CD41E5B1F5108475FEB3EB5B8524DA3F4", - "direction": "self", - "nonce": 47, - "receiptSuccess": true, - "events": [] - } - ] - `); - } - return {error: "Not implemented"}; - } -} diff --git a/mock/ext-api-dyson/post/eth-rpc.js b/mock/ext-api-dyson/post/eth-rpc.js deleted file mode 100644 index 62ba4a0be..000000000 --- a/mock/ext-api-dyson/post/eth-rpc.js +++ /dev/null @@ -1,81 +0,0 @@ -/// ETH RPC API Mock -/// See: -/// curl -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":2,"method":"eth_call","params":[{"data":"0x02571be3ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835","from":"0x0000000000000000000000000000000000000000","to":"0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e"},"latest"]}' http://localhost:3347/eth-rpc -/// curl "http://localhost:8437/v2/ns/lookup?name=vitalik.eth&coins=60" - -module.exports = { - path: '/eth-rpc', - template: function(params, query, body) { - //console.log(body); - var jsonrpc = body.jsonrpc; - var id = body.id; - //console.log('body.method', body.method); - if (body.method === 'net_version') { - return {jsonrpc: jsonrpc, id: id, result: "1"} - } else if (body.method === 'eth_call') { - //console.log('body.params', body.params); - //console.log('body.params[0].data', body.params[0].data); - switch (body.params[0].data) { - case '0x0178b8bfee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835': - // name lookup, vitalik.eth, part 2 - return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000226159d592e2b063810a10ebf6dcbada94ed68b8"}; - case '0x02571be32337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047': - // name lookup, ourxyzwallet.xyz, part 1 - return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000b30b09da480dd907907d98af5102c2034ed7df60"}; - case '0x02571be3a538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4': - // name lookup, vitalik.luxe, part 1 - return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000d8a667312d5260f12a306ae7730c754d938da86c"}; - case '0x02571be3ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835': - // name lookup, vitalik.eth, part 1 - return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045"}; - case '0x0178b8bf2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047': - // name lookup, ourxyzwallet.xyz, part 2 - return {jsonrpc: jsonrpc, id: id, result: "0x0000000000000000000000001da022710df5002339274aadee8d58218e9d6ab5"}; - case '0x0178b8bfa538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4': - // name lookup, vitalik.luxe, part 2 - return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000bd5f5ec7ed5f19b53726344540296c02584a5237"}; - case '0x3b3b57de2337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047': - // name lookup, ourxyzwallet.xyz, part 5 - return {jsonrpc: jsonrpc, id: id, result: "0x0000000000000000000000000c54eead78d555be3cbcd451424f9a27a7843935"}; - case '0x3b3b57dea538cd174de170e8062c97c25c40a7ceb56aca81b12e6f5afc46f5a429999aa4': - // name lookup, vitalik.luxe, part 4 - return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000d8a667312d5260f12a306ae7730c754d938da86c"}; - - case '0x3b3b57deeb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1': - switch (body.params[0].to) { - case '0x1da022710df5002339274aadee8d58218e9d6ab5': - // name lookup, ourxyzwallet.xyz, part 3 - return {jsonrpc: jsonrpc, id: id, result: "0x0000000000000000000000000000000000000000000000000000000000000000"}; - case '0x226159d592e2b063810a10ebf6dcbada94ed68b8': - // name lookup, vitalik.eth, part 3 - return {jsonrpc: jsonrpc, id: id, result: "0x000000000000000000000000eefb13c7d42efcc655e528da6d6f7bbcf9a2251d"}; - case '0xbd5f5ec7ed5f19b53726344540296c02584a5237': - // name lookup, vitalik.luxe, part 3 - return {jsonrpc: jsonrpc, id: id, result: "0x0000000000000000000000006109dd117aa5486605fc85e040ab00163a75c662"}; - } - - case '0xf1cb7e062337fcf9521666fd5114df2902fa9e6da5a6b004b5a192a0f55d2d9fab4f1047000000000000000000000000000000000000000000000000000000000000003c': - switch (body.params[0].to) { - case '0x1da022710df5002339274aadee8d58218e9d6ab5': - // name lookup, ourxyzwallet.xyz, part 4 - return {jsonrpc: jsonrpc, id: id, result: "0x"}; - } - - case '0xf1cb7e06ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835000000000000000000000000000000000000000000000000000000000000003c': - switch (body.params[0].to) { - case '0x226159d592e2b063810a10ebf6dcbada94ed68b8': - // name lookup, vitalik.eth, part 4 - return {jsonrpc: jsonrpc, id: id, result: "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000"}; - case '0xbd5f5ec7ed5f19b53726344540296c02584a5237': - // name lookup, vitalik.luxe, part 4 - return {jsonrpc: jsonrpc, id: id, result: "0x"}; - } - } - // fallback - return {error: "wrong data"}; - } else { - // fallback - return {error: "wrong method"}; - } - } -}; diff --git a/mock/ext-api-dyson/post/fio-api-chain.js b/mock/ext-api-dyson/post/fio-api-chain.js deleted file mode 100644 index 7f0c32cd5..000000000 --- a/mock/ext-api-dyson/post/fio-api-chain.js +++ /dev/null @@ -1,41 +0,0 @@ -/// FIO RPC API Mock, chain API -/// Returns: -/// - public address for certain fio name and coin combinations -/// - public address not found message for other input -/// See: -/// curl -H "Content-Type: application/json" -d '{"fio_address":"trust@trust","token_code":"BTC","chain_code":"BTC"}' "http://localhost:3347/fio-api/v1/chain/get_pub_address" -/// curl -H "Content-Type: application/json" -d '{"fio_address":"trust@trust","token_code":"BTC","chain_code":"BTC"}' "http://testnet.fioprotocol.io/v1/chain/get_pub_address" -/// curl "http://localhost:8437/v2/ns/lookup?name=trust@trust&coins=60" - -module.exports = { - path: '/fio-api/v1/chain/:action', - template: function(params, query, body) { - if (params.action === 'get_pub_address') { - var addr = getAddress(body.fio_address, body.token_code); - if (addr == '') { - return {message: 'Public address not found'}; - } - return {public_address: addr}; - } - return {error: 'Not implemented'}; - } -}; - -function getAddress(fio_address, token_code) { - switch (fio_address) { - case 'trust@trust': - switch (token_code) { - case 'BTC': return 'bc1qvy4074rggkdr2pzw5vpnn62eg0smzlxwp70d7v'; - case 'ETH': return '0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51'; - case 'BNB': return 'bnb1ts3dg54apwlvr9hupv2n0j6e46q54znnusjk9s'; - default: return ''; - } - - case 'trust@trustwallet': - return '0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a0001'; - - case 'name@somefiodomain': - return '0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a0002'; - } - return ''; -}; diff --git a/mock/ext-api-dyson/post/fio-api-history.js b/mock/ext-api-dyson/post/fio-api-history.js deleted file mode 100644 index fdbbb0b05..000000000 --- a/mock/ext-api-dyson/post/fio-api-history.js +++ /dev/null @@ -1,1498 +0,0 @@ -/// FIO RPC API Mock, history API -/// curl -H "Content-Type: application/json" -d '{"account_name": "ezsmbcy2opod"}' https://fio.greymass.com/v1/history/get_actions -/// curl -H "Content-Type: application/json" -d '{"account_name": "ezsmbcy2opod"}' http://localhost:3347/fio-api/v1/history/get_actions -/// curl "http://localhost:8437/v1/fio/FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt" - -module.exports = { - path: '/fio-api/v1/history/:action', - template: function(params, query, body) { - //console.log(params); - //console.log(body); - if (params.action === 'get_actions') { - switch (body.account_name) { - case 'ezsmbcy2opod': // FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt - return JSON.parse(` - { - "actions": [ - { - "global_action_seq": 507874, - "account_action_seq": 0, - "block_num": 358689, - "block_time": "2020-03-27T01:54:24.500", - "action_trace": { - "receipt": { - "receiver": "ezsmbcy2opod", - "response": "{'status': 'OK','fee_collected':2000000000}", - "act_digest": "6ef1d997fd449b6fefb8df19401c71425d366a24aab4613ca2059478fef7915f", - "global_sequence": 507874, - "recv_sequence": 1, - "auth_sequence": [ - [ - "f5axfpgffiqz", - 125 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "ezsmbcy2opod", - "act": { - "account": "fio.token", - "name": "trnsfiopubky", - "authorization": [ - { - "actor": "f5axfpgffiqz", - "permission": "active" - } - ], - "data": { - "payee_public_key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", - "amount": 700000000000, - "max_fee": 2000000000, - "actor": "f5axfpgffiqz", - "tpid": "" - }, - "hex_data": "3546494f375133586651326f634750317a5973743653667835717273695a383635437538536f326174727562394a4e3934736f376774005840fba20000000094357700000000f0ad5b8bd5d54d5900" - }, - "context_free": false, - "elapsed": 6, - "console": "", - "trx_id": "2e0a7dc3640768e1d644cee871734dd2efa23e65a54c438c1ba03801d7386fb7", - "block_num": 358689, - "block_time": "2020-03-27T01:54:24.500", - "producer_block_id": "00057921b2a5f55fba29f7f08cd49dd095a18f0de2e4e06ba0833ca771ad699b", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 1, - "closest_unnotified_ancestor_action_ordinal": 1 - } - }, - { - "global_action_seq": 508968, - "account_action_seq": 1, - "block_num": 359762, - "block_time": "2020-03-27T02:03:21.000", - "action_trace": { - "receipt": { - "receiver": "fio.address", - "response": "{'status': 'OK','expiration':'2021-03-27T02:03:21','fee_collected':40000000000}", - "act_digest": "e054494384148e58122a10c3398d9e01a09a79cd6c22da0203653906afd79b3b", - "global_sequence": 508968, - "recv_sequence": 34025, - "auth_sequence": [ - [ - "ezsmbcy2opod", - 1 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.address", - "act": { - "account": "fio.address", - "name": "regaddress", - "authorization": [ - { - "actor": "ezsmbcy2opod", - "permission": "active" - } - ], - "data": { - "fio_address": "bp@eosph", - "owner_fio_public_key": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", - "max_fee": 40000000000, - "actor": "ezsmbcy2opod", - "tpid": "" - }, - "hex_data": "08627040656f7370683546494f375133586651326f634750317a5973743653667835717273695a383635437538536f326174727562394a4e3934736f37677400902f50090000009068a5c2a323f15700" - }, - "context_free": false, - "elapsed": 2834, - "console": "", - "trx_id": "b7dd60839ccce11cd175fce6816da04bbce9b70825661005d2ea5d3572408c04", - "block_num": 359762, - "block_time": "2020-03-27T02:03:21.000", - "producer_block_id": "00057d5209ad0141445b3ee2eb1ba7265ab4c7093f7bc4c2142e2eac4c8e5d10", - "account_ram_deltas": [ - { - "account": "ezsmbcy2opod", - "delta": 798 - } - ], - "except": null, - "error_code": null, - "action_ordinal": 1, - "creator_action_ordinal": 0, - "closest_unnotified_ancestor_action_ordinal": 0 - } - }, - { - "global_action_seq": 508970, - "account_action_seq": 2, - "block_num": 359762, - "block_time": "2020-03-27T02:03:21.000", - "action_trace": { - "receipt": { - "receiver": "ezsmbcy2opod", - "response": "", - "act_digest": "e6774ab921eabe540049667756efb5567b83b291b8a21c5bec81c8b5dc98c366", - "global_sequence": 508970, - "recv_sequence": 2, - "auth_sequence": [ - [ - "eosio", - 430085 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "ezsmbcy2opod", - "act": { - "account": "fio.token", - "name": "transfer", - "authorization": [ - { - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "from": "ezsmbcy2opod", - "to": "fio.treasury", - "quantity": "40.000000000 FIO", - "memo": "FIO API fees. Thank you." - }, - "hex_data": "9068a5c2a323f157e0afc646dd0ca85b00902f50090000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" - }, - "context_free": false, - "elapsed": 6, - "console": "", - "trx_id": "b7dd60839ccce11cd175fce6816da04bbce9b70825661005d2ea5d3572408c04", - "block_num": 359762, - "block_time": "2020-03-27T02:03:21.000", - "producer_block_id": "00057d5209ad0141445b3ee2eb1ba7265ab4c7093f7bc4c2142e2eac4c8e5d10", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 510503, - "account_action_seq": 3, - "block_num": 361281, - "block_time": "2020-03-27T02:16:00.500", - "action_trace": { - "receipt": { - "receiver": "eosio", - "response": "{'status': 'OK','fee_collected':200000000000}", - "act_digest": "52b1631c84896baaebd4b81a80c2cfab4f9741e0323d2845d1b3df5683ad7c3c", - "global_sequence": 510503, - "recv_sequence": 404854, - "auth_sequence": [ - [ - "ezsmbcy2opod", - 2 - ] - ], - "code_sequence": 2, - "abi_sequence": 2 - }, - "receiver": "eosio", - "act": { - "account": "eosio", - "name": "regproducer", - "authorization": [ - { - "actor": "ezsmbcy2opod", - "permission": "active" - } - ], - "data": { - "fio_address": "bp@eosph", - "fio_pub_key": "FIO5hZB8REVEirigba4N7TKa67MYm4HFwtiKz6GZJ2eRi5Paxwixz", - "url": "https://www.eosph.io", - "location": 10, - "actor": "ezsmbcy2opod", - "max_fee": 400000000000 - }, - "hex_data": "08627040656f7370683546494f35685a423852455645697269676261344e37544b6136374d596d3448467774694b7a36475a4a32655269355061787769787a1468747470733a2f2f7777772e656f7370682e696f0a009068a5c2a323f15700a0db215d000000" - }, - "context_free": false, - "elapsed": 2207, - "console": "", - "trx_id": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8", - "block_num": 361281, - "block_time": "2020-03-27T02:16:00.500", - "producer_block_id": "00058341700331f78adea1eec39e7150b743f171c9fd9dfff8ea7310f5e6b515", - "account_ram_deltas": [ - { - "account": "ezsmbcy2opod", - "delta": 635 - } - ], - "except": null, - "error_code": null, - "action_ordinal": 1, - "creator_action_ordinal": 0, - "closest_unnotified_ancestor_action_ordinal": 0 - } - }, - { - "global_action_seq": 510505, - "account_action_seq": 4, - "block_num": 361281, - "block_time": "2020-03-27T02:16:00.500", - "action_trace": { - "receipt": { - "receiver": "ezsmbcy2opod", - "response": "", - "act_digest": "a8dd1a5cfe8db5fb3ca38eed9e348acd73150d88211f93e0d37e332289fe76a3", - "global_sequence": 510505, - "recv_sequence": 3, - "auth_sequence": [ - [ - "eosio", - 431614 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "ezsmbcy2opod", - "act": { - "account": "fio.token", - "name": "transfer", - "authorization": [ - { - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "from": "ezsmbcy2opod", - "to": "fio.treasury", - "quantity": "200.000000000 FIO", - "memo": "FIO API fees. Thank you." - }, - "hex_data": "9068a5c2a323f157e0afc646dd0ca85b00d0ed902e0000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" - }, - "context_free": false, - "elapsed": 6, - "console": "", - "trx_id": "5cd8d902a675d608d4c82eca892c7973deaa6aefcc58ed9bcbd382ebdc7271c8", - "block_num": 361281, - "block_time": "2020-03-27T02:16:00.500", - "producer_block_id": "00058341700331f78adea1eec39e7150b743f171c9fd9dfff8ea7310f5e6b515", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - } - ], - "last_irreversible_block": 928886 - } - `); - - case 'gmdncuvoqxfn': // FIO6gZthsHigy7wXeev4MKS4MuoygkxQ1yirmmUqpoubDWLJTASa2 - return JSON.parse(` - { - "actions": [ - { - "global_action_seq": 1158276, - "account_action_seq": 0, - "block_num": 1008911, - "block_time": "2020-03-30T20:12:55.500", - "action_trace": { - "receipt": { - "receiver": "gmdncuvoqxfn", - "response": "{'status': 'OK','fee_collected':2000000000}", - "act_digest": "dcff7e3441ac0e2ce3677fca269d04c4a6ee81a10c830a22fa37dcdc7595f1c1", - "global_sequence": 1158276, - "recv_sequence": 1, - "auth_sequence": [ - [ - "f5axfpgffiqz", - 129 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "gmdncuvoqxfn", - "act": { - "account": "fio.token", - "name": "trnsfiopubky", - "authorization": [ - { - "actor": "f5axfpgffiqz", - "permission": "active" - } - ], - "data": { - "payee_public_key": "FIO6gZthsHigy7wXeev4MKS4MuoygkxQ1yirmmUqpoubDWLJTASa2", - "amount": 700000000000, - "max_fee": 2000000000, - "actor": "f5axfpgffiqz", - "tpid": "" - }, - "hex_data": "3546494f36675a74687348696779377758656576344d4b53344d756f79676b7851317969726d6d5571706f756244574c4a5441536132005840fba20000000094357700000000f0ad5b8bd5d54d5900" - }, - "context_free": false, - "elapsed": 8, - "console": "", - "trx_id": "d2dd588ac5e46cb072d0a2673ea59b88187f0331b26906fabbafddbcea291450", - "block_num": 1008911, - "block_time": "2020-03-30T20:12:55.500", - "producer_block_id": "000f650fae073cc3a5c4eaf40a68051dab80e642d815345fca490f66067bfe8d", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 1, - "closest_unnotified_ancestor_action_ordinal": 1 - } - }, - { - "global_action_seq": 1247174, - "account_action_seq": 1, - "block_num": 1097674, - "block_time": "2020-03-31T08:32:37.000", - "action_trace": { - "receipt": { - "receiver": "fio.address", - "response": "{'status': 'OK','expiration':'2021-03-31T08:32:37','fee_collected':40000000000}", - "act_digest": "4a17b4b8b5f8c318d0a08b9766a793f9a60063acf98a0acaf2177c880e852855", - "global_sequence": 1247174, - "recv_sequence": 34050, - "auth_sequence": [ - [ - "gmdncuvoqxfn", - 1 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.address", - "act": { - "account": "fio.address", - "name": "regaddress", - "authorization": [ - { - "actor": "gmdncuvoqxfn", - "permission": "active" - } - ], - "data": { - "fio_address": "maltablockbp@maltablock", - "owner_fio_public_key": "FIO6gZthsHigy7wXeev4MKS4MuoygkxQ1yirmmUqpoubDWLJTASa2", - "max_fee": 40000000000, - "actor": "gmdncuvoqxfn", - "tpid": "" - }, - "hex_data": "176d616c7461626c6f636b6270406d616c7461626c6f636b3546494f36675a74687348696779377758656576344d4b53344d756f79676b7851317969726d6d5571706f756244574c4a544153613200902f50090000003057b7746b34936400" - }, - "context_free": false, - "elapsed": 3142, - "console": "", - "trx_id": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a", - "block_num": 1097674, - "block_time": "2020-03-31T08:32:37.000", - "producer_block_id": "0010bfca1e5c31bb4b4af9ec59df5c3f92b7adc33aa3f0967ae8a4538c78c982", - "account_ram_deltas": [ - { - "account": "gmdncuvoqxfn", - "delta": 818 - } - ], - "except": null, - "error_code": null, - "action_ordinal": 1, - "creator_action_ordinal": 0, - "closest_unnotified_ancestor_action_ordinal": 0 - } - }, - { - "global_action_seq": 1247176, - "account_action_seq": 2, - "block_num": 1097674, - "block_time": "2020-03-31T08:32:37.000", - "action_trace": { - "receipt": { - "receiver": "gmdncuvoqxfn", - "response": "", - "act_digest": "601cd0faa0fca3e16359d623dbf5c0906fdbc41e6c494a0fd58c0f836ac89793", - "global_sequence": 1247176, - "recv_sequence": 2, - "auth_sequence": [ - [ - "eosio", - 1168156 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "gmdncuvoqxfn", - "act": { - "account": "fio.token", - "name": "transfer", - "authorization": [ - { - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "from": "gmdncuvoqxfn", - "to": "fio.treasury", - "quantity": "40.000000000 FIO", - "memo": "FIO API fees. Thank you." - }, - "hex_data": "3057b7746b349364e0afc646dd0ca85b00902f50090000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" - }, - "context_free": false, - "elapsed": 4, - "console": "", - "trx_id": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a", - "block_num": 1097674, - "block_time": "2020-03-31T08:32:37.000", - "producer_block_id": "0010bfca1e5c31bb4b4af9ec59df5c3f92b7adc33aa3f0967ae8a4538c78c982", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - } - ], - "last_irreversible_block": 1104980 - } - `); - - case 'fio.treasury': - return JSON.parse(` - { - "actions": [ - { - "global_action_seq": 1205798, - "account_action_seq": 69910, - "block_num": 1056340, - "block_time": "2020-03-31T02:48:10.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "7523d7353879acaf9d41d6078cebd956a5ad6980ce1ada7a840f90ba275851d9", - "global_sequence": 1205798, - "recv_sequence": 69907, - "auth_sequence": [ - [ - "fio.fee", - 1643 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "fdtnrwdupdat", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "002d310100000000" - }, - "context_free": false, - "elapsed": 56, - "console": "", - "trx_id": "7fc2be4379b1cbb2ac95a1ef00149a2cbf559cc1e563cb2d237bb829001cf298", - "block_num": 1056340, - "block_time": "2020-03-31T02:48:10.000", - "producer_block_id": "00101e54f8bc28902f8fcd26eb3dba2a96278ad3380bfba98dcffef5d220bd4c", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1205796, - "account_action_seq": 69911, - "block_num": 1056340, - "block_time": "2020-03-31T02:48:10.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "902802357ab59f73547676540fb71244591e71819a763429e562091ffca4b324", - "global_sequence": 1205796, - "recv_sequence": 69905, - "auth_sequence": [ - [ - "eosio", - 1126799 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.token", - "name": "transfer", - "authorization": [ - { - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "from": "c1dlj1dcjzno", - "to": "fio.treasury", - "quantity": "0.400000000 FIO", - "memo": "FIO API fees. Thank you." - }, - "hex_data": "40e77f2885175340e0afc646dd0ca85b0084d717000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" - }, - "context_free": false, - "elapsed": 21, - "console": "", - "trx_id": "7fc2be4379b1cbb2ac95a1ef00149a2cbf559cc1e563cb2d237bb829001cf298", - "block_num": 1056340, - "block_time": "2020-03-31T02:48:10.000", - "producer_block_id": "00101e54f8bc28902f8fcd26eb3dba2a96278ad3380bfba98dcffef5d220bd4c", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 8, - "creator_action_ordinal": 4, - "closest_unnotified_ancestor_action_ordinal": 4 - } - }, - { - "global_action_seq": 1216171, - "account_action_seq": 69912, - "block_num": 1066706, - "block_time": "2020-03-31T04:14:33.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "b93c4648862a6a184d38af9f078f1c352a7bf07cddb8f6d457148847cbfa479a", - "global_sequence": 1216171, - "recv_sequence": 69909, - "auth_sequence": [ - [ - "fio.fee", - 1644 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "bprewdupdate", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "80d99f3800000000" - }, - "context_free": false, - "elapsed": 42, - "console": "", - "trx_id": "b088bf3b4663118a177bb48da45374f29e3988141d4fed81f92124880318f88d", - "block_num": 1066706, - "block_time": "2020-03-31T04:14:33.000", - "producer_block_id": "001046d219e699f20c31ff0fed77bd361bf2323cb06a46a9417a1c908294c29a", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 5, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1216172, - "account_action_seq": 69913, - "block_num": 1066706, - "block_time": "2020-03-31T04:14:33.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "fefe089e3efc8a4b18d94b377e52b2d688e3d9321eef5c8f7d1fa6b060f2b687", - "global_sequence": 1216172, - "recv_sequence": 69910, - "auth_sequence": [ - [ - "fio.fee", - 1645 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "fdtnrwdupdat", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "80f0fa0200000000" - }, - "context_free": false, - "elapsed": 32, - "console": "", - "trx_id": "b088bf3b4663118a177bb48da45374f29e3988141d4fed81f92124880318f88d", - "block_num": 1066706, - "block_time": "2020-03-31T04:14:33.000", - "producer_block_id": "001046d219e699f20c31ff0fed77bd361bf2323cb06a46a9417a1c908294c29a", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1216170, - "account_action_seq": 69914, - "block_num": 1066706, - "block_time": "2020-03-31T04:14:33.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "facd8187719c8282812a04b487e67cc2202c472183b4e4ee114fcfa492c05573", - "global_sequence": 1216170, - "recv_sequence": 69908, - "auth_sequence": [ - [ - "eosio", - 1137169 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.token", - "name": "transfer", - "authorization": [ - { - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "from": "aloha3joooqd", - "to": "fio.treasury", - "quantity": "1.000000000 FIO", - "memo": "FIO API fees. Thank you." - }, - "hex_data": "902ca5f40dd36834e0afc646dd0ca85b00ca9a3b000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" - }, - "context_free": false, - "elapsed": 12, - "console": "", - "trx_id": "b088bf3b4663118a177bb48da45374f29e3988141d4fed81f92124880318f88d", - "block_num": 1066706, - "block_time": "2020-03-31T04:14:33.000", - "producer_block_id": "001046d219e699f20c31ff0fed77bd361bf2323cb06a46a9417a1c908294c29a", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 8, - "creator_action_ordinal": 4, - "closest_unnotified_ancestor_action_ordinal": 4 - } - }, - { - "global_action_seq": 1216854, - "account_action_seq": 69915, - "block_num": 1067381, - "block_time": "2020-03-31T04:20:10.500", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "088307ffafcae045997b5ce895a1208f845b47cb363ac9bff52df318f23b257d", - "global_sequence": 1216854, - "recv_sequence": 69912, - "auth_sequence": [ - [ - "fio.fee", - 1646 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "bprewdupdate", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "0057a61600000000" - }, - "context_free": false, - "elapsed": 56, - "console": "", - "trx_id": "2c755be0cd59e443b5e1fc33443594a0770b7a6dcfdef4709c98145a2e36bf1b", - "block_num": 1067381, - "block_time": "2020-03-31T04:20:10.500", - "producer_block_id": "001049757562cbc8bb5db955d8c7ee14689c7383bd9a6211ea9a5cb5d024827a", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 5, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1216855, - "account_action_seq": 69916, - "block_num": 1067381, - "block_time": "2020-03-31T04:20:10.500", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "7523d7353879acaf9d41d6078cebd956a5ad6980ce1ada7a840f90ba275851d9", - "global_sequence": 1216855, - "recv_sequence": 69913, - "auth_sequence": [ - [ - "fio.fee", - 1647 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "fdtnrwdupdat", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "002d310100000000" - }, - "context_free": false, - "elapsed": 41, - "console": "", - "trx_id": "2c755be0cd59e443b5e1fc33443594a0770b7a6dcfdef4709c98145a2e36bf1b", - "block_num": 1067381, - "block_time": "2020-03-31T04:20:10.500", - "producer_block_id": "001049757562cbc8bb5db955d8c7ee14689c7383bd9a6211ea9a5cb5d024827a", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1216853, - "account_action_seq": 69917, - "block_num": 1067381, - "block_time": "2020-03-31T04:20:10.500", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "a5180fd568f15f4722641a839c5f2b9d9fcf7597464d1e9e5b84ffdf63a48fb1", - "global_sequence": 1216853, - "recv_sequence": 69911, - "auth_sequence": [ - [ - "eosio", - 1137848 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.token", - "name": "transfer", - "authorization": [ - { - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "from": "wwgwvaijiuag", - "to": "fio.treasury", - "quantity": "0.400000000 FIO", - "memo": "FIO API fees. Thank you." - }, - "hex_data": "c08c76cf99cd19e7e0afc646dd0ca85b0084d717000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" - }, - "context_free": false, - "elapsed": 16, - "console": "", - "trx_id": "2c755be0cd59e443b5e1fc33443594a0770b7a6dcfdef4709c98145a2e36bf1b", - "block_num": 1067381, - "block_time": "2020-03-31T04:20:10.500", - "producer_block_id": "001049757562cbc8bb5db955d8c7ee14689c7383bd9a6211ea9a5cb5d024827a", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 8, - "creator_action_ordinal": 4, - "closest_unnotified_ancestor_action_ordinal": 4 - } - }, - { - "global_action_seq": 1216978, - "account_action_seq": 69918, - "block_num": 1067497, - "block_time": "2020-03-31T04:21:08.500", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "088307ffafcae045997b5ce895a1208f845b47cb363ac9bff52df318f23b257d", - "global_sequence": 1216978, - "recv_sequence": 69915, - "auth_sequence": [ - [ - "fio.fee", - 1648 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "bprewdupdate", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "0057a61600000000" - }, - "context_free": false, - "elapsed": 44, - "console": "", - "trx_id": "7535cb0a48298e8d8c636dcdfc7742af43a35fccf9fdd7d8d8e5ee80a253ce48", - "block_num": 1067497, - "block_time": "2020-03-31T04:21:08.500", - "producer_block_id": "001049e9f3572dde8f852624dd489c884309a27c277bfb251bc353ce7a80a05f", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 5, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1216979, - "account_action_seq": 69919, - "block_num": 1067497, - "block_time": "2020-03-31T04:21:08.500", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "7523d7353879acaf9d41d6078cebd956a5ad6980ce1ada7a840f90ba275851d9", - "global_sequence": 1216979, - "recv_sequence": 69916, - "auth_sequence": [ - [ - "fio.fee", - 1649 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "fdtnrwdupdat", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "002d310100000000" - }, - "context_free": false, - "elapsed": 45, - "console": "", - "trx_id": "7535cb0a48298e8d8c636dcdfc7742af43a35fccf9fdd7d8d8e5ee80a253ce48", - "block_num": 1067497, - "block_time": "2020-03-31T04:21:08.500", - "producer_block_id": "001049e9f3572dde8f852624dd489c884309a27c277bfb251bc353ce7a80a05f", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1216977, - "account_action_seq": 69920, - "block_num": 1067497, - "block_time": "2020-03-31T04:21:08.500", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "a5180fd568f15f4722641a839c5f2b9d9fcf7597464d1e9e5b84ffdf63a48fb1", - "global_sequence": 1216977, - "recv_sequence": 69914, - "auth_sequence": [ - [ - "eosio", - 1137968 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.token", - "name": "transfer", - "authorization": [ - { - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "from": "wwgwvaijiuag", - "to": "fio.treasury", - "quantity": "0.400000000 FIO", - "memo": "FIO API fees. Thank you." - }, - "hex_data": "c08c76cf99cd19e7e0afc646dd0ca85b0084d717000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" - }, - "context_free": false, - "elapsed": 12, - "console": "", - "trx_id": "7535cb0a48298e8d8c636dcdfc7742af43a35fccf9fdd7d8d8e5ee80a253ce48", - "block_num": 1067497, - "block_time": "2020-03-31T04:21:08.500", - "producer_block_id": "001049e9f3572dde8f852624dd489c884309a27c277bfb251bc353ce7a80a05f", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 8, - "creator_action_ordinal": 4, - "closest_unnotified_ancestor_action_ordinal": 4 - } - }, - { - "global_action_seq": 1241641, - "account_action_seq": 69921, - "block_num": 1092152, - "block_time": "2020-03-31T07:46:36.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "088307ffafcae045997b5ce895a1208f845b47cb363ac9bff52df318f23b257d", - "global_sequence": 1241641, - "recv_sequence": 69918, - "auth_sequence": [ - [ - "fio.fee", - 1650 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "bprewdupdate", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "0057a61600000000" - }, - "context_free": false, - "elapsed": 66, - "console": "", - "trx_id": "9429e1dccf6e50e00c6f03c51d2ae37cb936bc7593b8719a89b13fff40574218", - "block_num": 1092152, - "block_time": "2020-03-31T07:46:36.000", - "producer_block_id": "0010aa38918e0b7ca42cf76a59cfdac5bcc06cdbcc6e83f8b2e4959ba222da90", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 5, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1241642, - "account_action_seq": 69922, - "block_num": 1092152, - "block_time": "2020-03-31T07:46:36.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "7523d7353879acaf9d41d6078cebd956a5ad6980ce1ada7a840f90ba275851d9", - "global_sequence": 1241642, - "recv_sequence": 69919, - "auth_sequence": [ - [ - "fio.fee", - 1651 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "fdtnrwdupdat", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "002d310100000000" - }, - "context_free": false, - "elapsed": 66, - "console": "", - "trx_id": "9429e1dccf6e50e00c6f03c51d2ae37cb936bc7593b8719a89b13fff40574218", - "block_num": 1092152, - "block_time": "2020-03-31T07:46:36.000", - "producer_block_id": "0010aa38918e0b7ca42cf76a59cfdac5bcc06cdbcc6e83f8b2e4959ba222da90", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1241640, - "account_action_seq": 69923, - "block_num": 1092152, - "block_time": "2020-03-31T07:46:36.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "e780fffd69aa5812e49e034ad42f6ae16d639562eaf9476c974dc8cb8db88919", - "global_sequence": 1241640, - "recv_sequence": 69917, - "auth_sequence": [ - [ - "eosio", - 1162627 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.token", - "name": "transfer", - "authorization": [ - { - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "from": "u2rwmaqfxtvs", - "to": "fio.treasury", - "quantity": "0.400000000 FIO", - "memo": "FIO API fees. Thank you." - }, - "hex_data": "8077eecb1ac9afd0e0afc646dd0ca85b0084d717000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" - }, - "context_free": false, - "elapsed": 21, - "console": "", - "trx_id": "9429e1dccf6e50e00c6f03c51d2ae37cb936bc7593b8719a89b13fff40574218", - "block_num": 1092152, - "block_time": "2020-03-31T07:46:36.000", - "producer_block_id": "0010aa38918e0b7ca42cf76a59cfdac5bcc06cdbcc6e83f8b2e4959ba222da90", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 8, - "creator_action_ordinal": 4, - "closest_unnotified_ancestor_action_ordinal": 4 - } - }, - { - "global_action_seq": 1241684, - "account_action_seq": 69924, - "block_num": 1092187, - "block_time": "2020-03-31T07:46:53.500", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "088307ffafcae045997b5ce895a1208f845b47cb363ac9bff52df318f23b257d", - "global_sequence": 1241684, - "recv_sequence": 69921, - "auth_sequence": [ - [ - "fio.fee", - 1652 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "bprewdupdate", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "0057a61600000000" - }, - "context_free": false, - "elapsed": 47, - "console": "", - "trx_id": "6d67c62ac8c778963972064b3aaf302cf6f7b8d3625ef40cebcebda92276bed2", - "block_num": 1092187, - "block_time": "2020-03-31T07:46:53.500", - "producer_block_id": "0010aa5b487b38bb00a45860ac534767e302a285994ad9b5fd6aa671e37e1551", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 5, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1241685, - "account_action_seq": 69925, - "block_num": 1092187, - "block_time": "2020-03-31T07:46:53.500", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "7523d7353879acaf9d41d6078cebd956a5ad6980ce1ada7a840f90ba275851d9", - "global_sequence": 1241685, - "recv_sequence": 69922, - "auth_sequence": [ - [ - "fio.fee", - 1653 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "fdtnrwdupdat", - "authorization": [ - { - "actor": "fio.fee", - "permission": "active" - } - ], - "data": "002d310100000000" - }, - "context_free": false, - "elapsed": 32, - "console": "", - "trx_id": "6d67c62ac8c778963972064b3aaf302cf6f7b8d3625ef40cebcebda92276bed2", - "block_num": 1092187, - "block_time": "2020-03-31T07:46:53.500", - "producer_block_id": "0010aa5b487b38bb00a45860ac534767e302a285994ad9b5fd6aa671e37e1551", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 6, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - }, - { - "global_action_seq": 1241683, - "account_action_seq": 69926, - "block_num": 1092187, - "block_time": "2020-03-31T07:46:53.500", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "e780fffd69aa5812e49e034ad42f6ae16d639562eaf9476c974dc8cb8db88919", - "global_sequence": 1241683, - "recv_sequence": 69920, - "auth_sequence": [ - [ - "eosio", - 1162666 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.token", - "name": "transfer", - "authorization": [ - { - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "from": "u2rwmaqfxtvs", - "to": "fio.treasury", - "quantity": "0.400000000 FIO", - "memo": "FIO API fees. Thank you." - }, - "hex_data": "8077eecb1ac9afd0e0afc646dd0ca85b0084d717000000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" - }, - "context_free": false, - "elapsed": 19, - "console": "", - "trx_id": "6d67c62ac8c778963972064b3aaf302cf6f7b8d3625ef40cebcebda92276bed2", - "block_num": 1092187, - "block_time": "2020-03-31T07:46:53.500", - "producer_block_id": "0010aa5b487b38bb00a45860ac534767e302a285994ad9b5fd6aa671e37e1551", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 8, - "creator_action_ordinal": 4, - "closest_unnotified_ancestor_action_ordinal": 4 - } - }, - { - "global_action_seq": 1247178, - "account_action_seq": 69927, - "block_num": 1097674, - "block_time": "2020-03-31T08:32:37.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "d86fcb99d2b33d23d674f18ae83a278b6ad4dae408eba0a125b4978c534ce715", - "global_sequence": 1247178, - "recv_sequence": 69924, - "auth_sequence": [ - [ - "fio.address", - 72535 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "fdtnrwdupdat", - "authorization": [ - { - "actor": "fio.address", - "permission": "active" - } - ], - "data": "0094357700000000" - }, - "context_free": false, - "elapsed": 46, - "console": "", - "trx_id": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a", - "block_num": 1097674, - "block_time": "2020-03-31T08:32:37.000", - "producer_block_id": "0010bfca1e5c31bb4b4af9ec59df5c3f92b7adc33aa3f0967ae8a4538c78c982", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 3, - "creator_action_ordinal": 1, - "closest_unnotified_ancestor_action_ordinal": 1 - } - }, - { - "global_action_seq": 1247179, - "account_action_seq": 69928, - "block_num": 1097674, - "block_time": "2020-03-31T08:32:37.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "5bceab55ed2ffde8ba5cbf5b9b309c48a75e181f8d13ea981f856c1f66699682", - "global_sequence": 1247179, - "recv_sequence": 69925, - "auth_sequence": [ - [ - "fio.address", - 72536 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.treasury", - "name": "bppoolupdate", - "authorization": [ - { - "actor": "fio.address", - "permission": "active" - } - ], - "data": "00fcf9d808000000" - }, - "context_free": false, - "elapsed": 31, - "console": "", - "trx_id": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a", - "block_num": 1097674, - "block_time": "2020-03-31T08:32:37.000", - "producer_block_id": "0010bfca1e5c31bb4b4af9ec59df5c3f92b7adc33aa3f0967ae8a4538c78c982", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 4, - "creator_action_ordinal": 1, - "closest_unnotified_ancestor_action_ordinal": 1 - } - }, - { - "global_action_seq": 1247177, - "account_action_seq": 69929, - "block_num": 1097674, - "block_time": "2020-03-31T08:32:37.000", - "action_trace": { - "receipt": { - "receiver": "fio.treasury", - "response": "", - "act_digest": "601cd0faa0fca3e16359d623dbf5c0906fdbc41e6c494a0fd58c0f836ac89793", - "global_sequence": 1247177, - "recv_sequence": 69923, - "auth_sequence": [ - [ - "eosio", - 1168157 - ] - ], - "code_sequence": 1, - "abi_sequence": 1 - }, - "receiver": "fio.treasury", - "act": { - "account": "fio.token", - "name": "transfer", - "authorization": [ - { - "actor": "eosio", - "permission": "active" - } - ], - "data": { - "from": "gmdncuvoqxfn", - "to": "fio.treasury", - "quantity": "40.000000000 FIO", - "memo": "FIO API fees. Thank you." - }, - "hex_data": "3057b7746b349364e0afc646dd0ca85b00902f50090000000946494f000000001846494f2041504920666565732e205468616e6b20796f752e" - }, - "context_free": false, - "elapsed": 15, - "console": "", - "trx_id": "0abe876176bbc7b29ef837d180b1061b5839e67f9211a5c26dea55360baa758a", - "block_num": 1097674, - "block_time": "2020-03-31T08:32:37.000", - "producer_block_id": "0010bfca1e5c31bb4b4af9ec59df5c3f92b7adc33aa3f0967ae8a4538c78c982", - "account_ram_deltas": [], - "except": null, - "error_code": null, - "action_ordinal": 7, - "creator_action_ordinal": 2, - "closest_unnotified_ancestor_action_ordinal": 2 - } - } - ], - "last_irreversible_block": 1104241 - } - `); - } - } - return {error: 'Not implemented'}; - } -}; diff --git a/mock/ext-api-dyson/post/harmony-api.js b/mock/ext-api-dyson/post/harmony-api.js deleted file mode 100644 index d61797ef4..000000000 --- a/mock/ext-api-dyson/post/harmony-api.js +++ /dev/null @@ -1,83 +0,0 @@ -/// Harmony RPC Mock -/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":1} ' http://localhost:3347/harmony-api -/// curl -H 'Content-Type: application/json' -d ' {"jsonrpc":"2.0","method":"hmy_getTransactionsHistory","params":[{"address":"one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv","fullTx":true}],"id":1} ' https://{harmony_rpc} -/// curl "http://localhost:8437/v2/harmony/one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv" - -module.exports = { - path: '/harmony-api', - template: function(params, query, body) { - //console.log("curl -H 'Content-Type: application/json' -d '", JSON.stringify(body), "' https://{harmony_rpc}"); - if (body.method === 'hmy_getTransactionsHistory') { - //console.log('body.params[0].address', body.params[0].address); - if (body.params[0].address === 'one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv') { - return JSON.parse(`{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "transactions": [ - { - "blockHash": "0x1b45da220f94f41bd42dc0eb89a5e83ce77b37cc78dbc9032bd10a5bbab13674", - "blockNumber": "0x1b2cdb", - "from": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", - "timestamp": "0x5df7cb45", - "gas": "0x33450", - "gasPrice": "0x3b9aca00", - "hash": "0x6bfd003239bf137855342f6266c456ae1b342e886bd1965a47edd4c74dd1a687", - "input": "0x", - "nonce": "0x0", - "to": "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", - "transactionIndex": "0x0", - "value": "0x1bbfef6a6ff9c000", - "shardID": 0, - "toShardID": 0, - "v": "0x26", - "r": "0x44c2a7b8c38612a3ce8b51967947c0c9756dda8d82d0f12137451ce33bbef390", - "s": "0x34234c6c26fe36bda246db845692fd248cb4060cda0d1c6056298b39486ed4f2" - }, - { - "blockHash": "0x58cc90d1b9302d0121b426f5fd35014acbc009defe36c5bbff6ac920d6005526", - "blockNumber": "0x1b2cf2", - "from": "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", - "timestamp": "0x5df7cc02", - "gas": "0x33450", - "gasPrice": "0x3b9aca00", - "hash": "0xf54f6f86df1624f38fcedf56eb248854a13a733e0b0f92d4b31b9cc7196d90b0", - "input": "0x", - "nonce": "0x20", - "to": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", - "transactionIndex": "0x0", - "value": "0x1bc0ae68df60e000", - "shardID": 0, - "toShardID": 0, - "v": "0x25", - "r": "0x46d14df06948f055e519ac244bcaaa3c3446ed20671d41db01546ddaad32503b", - "s": "0x50d13aeb94f2e8c760723afa4d892f3ca17690451a57465ea7e39c5d347efe8" - }, - { - "blockHash": "0xa84376f0f4d082b76355ccc6ec491660c0062d9ef3f39985ca00986e8dcbacc1", - "blockNumber": "0x1b2d1b", - "from": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", - "timestamp": "0x5df7cd50", - "gas": "0x33450", - "gasPrice": "0x3b9aca00", - "hash": "0x73355f625d0f7ef31512657c0f669e710c8c91a67180cd28bc919cfca0a2af82", - "input": "0x", - "nonce": "0x1", - "to": "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", - "transactionIndex": "0x0", - "value": "0x1bc09b4f6dd69000", - "shardID": 0, - "toShardID": 0, - "v": "0x26", - "r": "0xf31271b93e446bce8cc83eb997183146b4da2378a5f2cb1fc4ae64fbd65a93f5", - "s": "0x77e8e5693a87394204f96693a15f2157459b0329a2ddab97da0bf1cfb6fbce8c" - } - ] - } - }`); - } - return {jsonrpc:"2.0",id:1,result:{"transactions":[]}}; - } - return {error: 'Invalid request'}; - } -}; diff --git a/mock/ext-api-dyson/post/kusama-api.js b/mock/ext-api-dyson/post/kusama-api.js deleted file mode 100644 index 6d3112ddd..000000000 --- a/mock/ext-api-dyson/post/kusama-api.js +++ /dev/null @@ -1,64 +0,0 @@ -/// Kusama RPC API Mock -/// See: -/// curl -H "Content-Type: application/json" -d '{"address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", "row": 25}' https://kusama.subscan.io/api/scan/transfers -/// curl -H "Content-Type: application/json" -d '{"address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", "row": 25}' http://localhost:3347/kusama-rpc/scan/transfers -/// curl "http://localhost:8437/v1/kusama/HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK" - -module.exports = { - path: '/kusama-rpc/scan/transfers', - template: function(params, query, body) { - //console.log(body); - switch (body.address) { - case 'HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK': - return JSON.parse(` - { - "code": 0, - "message": "Success", - "ttl": 1, - "data": { - "count": 3, - "transfers": [ - { - "from": "EonK7NScfhd7ZRfgnLhm4cKRFJWK1z59zPximUZRg8VjHQj", - "to": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", - "module": "balances", - "amount": "30", - "hash": "0x9908579abffb409aef95394128f9097f0a21cfdf16675588423e31ab0d3c58e2", - "block_timestamp": 1583243826, - "block_num": 1291387, - "extrinsic_index": "1291387-3", - "success": true, - "fee": "10000000000" - }, - { - "from": "EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X", - "to": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", - "module": "balances", - "amount": "7.333459", - "hash": "0xab5dbf2d38f249785c260c3fca9e19a17df298c5294a99eaec2baab29970eb85", - "block_timestamp": 1581154290, - "block_num": 961987, - "extrinsic_index": "961987-2", - "success": true, - "fee": "10000000000" - }, - { - "from": "EEWyMLHgwtemr48spFNnS3U2XjaYswqAYAbadx2jr9ppp4X", - "to": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", - "module": "balances", - "amount": "233.193373", - "hash": "0x08aad18956058ee385387da2f7d613ed17ac5c98ad23683cfea855b0fd529a63", - "block_timestamp": 1579722240, - "block_num": 738814, - "extrinsic_index": "738814-3", - "success": true, - "fee": "10000000000" - } - ] - } - } - `); - } - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/post/nano-api.js b/mock/ext-api-dyson/post/nano-api.js deleted file mode 100644 index cc36cb391..000000000 --- a/mock/ext-api-dyson/post/nano-api.js +++ /dev/null @@ -1,48 +0,0 @@ -/// Nano RPC Mock -/// curl -H 'Content-Type: application/json' -d ' {"action":"account_history","account":"nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z","count":"25"} ' http://localhost:3347/nano-api -/// curl -H 'Content-Type: application/json' -d ' {"action":"account_history","account":"nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z","count":"25"} ' https://{nano_rpc} -/// curl "http://localhost:8437/v1/nano/nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z" - -module.exports = { - path: '/nano-api', - template: function(params, query, body) { - //console.log("curl -H 'Content-Type: application/json' -d '", JSON.stringify(body), "' https://{nano_rpc}"); - if (body.action === 'account_history') { - //console.log('body.account', body.account); - if (body.account === 'nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z') { - return JSON.parse(`{ - "account": "nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z", - "history": [ - { - "type": "send", - "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", - "amount": "1083000821328155744662798729216", - "local_timestamp": "1576911470", - "height": "8", - "hash": "05A23A254272028F349BB7E74115A5101B2048786A5437D1EBBE8807CEFF1E82" - }, - { - "type": "receive", - "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", - "amount": "1047300821328155744662798729216", - "local_timestamp": "1576911457", - "height": "7", - "hash": "13B8146F059C4D5695DCBCEEC750EAEDDDD8F436A6FAD569A107F2FAC0F899D5" - }, - { - "type": "receive", - "account": "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", - "amount": "34700000000000000000000000000", - "local_timestamp": "1576911446", - "height": "6", - "hash": "8A2A5840C9286B35D998F5AD535851750C1AFE7B0C7D3AA61E06A1628EDD0E94" - } - ] - }`); - } - return {error: 'Bad account number'}; - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/post/nimiq-rpc.js b/mock/ext-api-dyson/post/nimiq-rpc.js deleted file mode 100644 index 18a42afb8..000000000 --- a/mock/ext-api-dyson/post/nimiq-rpc.js +++ /dev/null @@ -1,66 +0,0 @@ -/// Nimiq RPC API Mock -/// See: -/// curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "getTransactionsByAddress", "params": [ "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", "25" ], "id": "getTransactionsByAddress"}' https://{nimiq_rpc} -/// curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "getTransactionsByAddress", "params": [ "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", "25" ], "id": "getTransactionsByAddress"}' http://localhost:3347/nimiq-rpc -/// curl "http://localhost:8437/v1/nimiq/NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07" - -module.exports = { - path: '/nimiq-rpc', - template: function(params, query, body) { - //console.log(body); - //console.log('body.method', body.method); - if (body.method === 'getTransactionsByAddress') { - //console.log('body.params', body.params); - if (body.params.length == 0) { - return {error: "missing parameters"}; - } - var address = body.params[0]; - switch (address) { - case 'NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07': - return JSON.parse(` - { - "jsonrpc": "2.0", - "result": [ - { - "hash": "8674d985ac1ea2a75fe9b35ed11d629cef8adfed50db6a5eb125351e622bb405", - "blockHash": "11b0a3aaf64119cfbc66b7fdb8c38d5734a7f50d5bbb0116ee579eb1de513c3f", - "blockNumber": 543545, - "timestamp": 1556458272, - "confirmations": 475868, - "from": "21c7fc976349d39188b3d239b3b86ab66daeafc2", - "fromAddress": "NQ32 473Y R5T3 979R 325K S8UT 7E3A NRNS VBX2", - "to": "8b12a9a5a81bf52a9afb47a16b57d4c81c51fc07", - "toAddress": "NQ94 HC9A K9D8 3FSJ M6PT 8XGN NMXL R0E5 3Y07", - "value": 42839, - "fee": 138, - "data": null, - "flags": 0 - }, - { - "hash": "c3c6e87cba620095a2aeb9898f07077d184e20a68f53798032857cc842dfb0c0", - "blockHash": "9b51f58b8ca881e2b182e1f544d09e4f1fe265b0f478fd41bf0128099013abd8", - "blockNumber": 354736, - "timestamp": 1545080725, - "confirmations": 664677, - "from": "e9a799c4fce6198cfb2eaacdeda5231078227d62", - "fromAddress": "NQ61 V6KR KH7U UQCQ RXRE MB6X T993 21U2 4YB2", - "to": "8b12a9a5a81bf52a9afb47a16b57d4c81c51fc07", - "toAddress": "NQ94 HC9A K9D8 3FSJ M6PT 8XGN NMXL R0E5 3Y07", - "value": 99808, - "fee": 192, - "data": "3c7363726970743e64656275676765723b3c2f7363726970743e", - "flags": 0 - } - ], - "id": 2 - } - `); - } - // fallback - return {error: "wrong data"}; - } else { - // fallback - return {error: "wrong method"}; - } - } -}; diff --git a/mock/ext-api-dyson/post/tron-api-wallet.js b/mock/ext-api-dyson/post/tron-api-wallet.js deleted file mode 100644 index d897760d9..000000000 --- a/mock/ext-api-dyson/post/tron-api-wallet.js +++ /dev/null @@ -1,17 +0,0 @@ -/// Tron API Mock -/// See: -/// curl http://localhost:3347/tron-api/wallet/listwitnesses -/// curl http://localhost:8437/v2/tron/staking/validators - -module.exports = { - path: "/tron-api/wallet/:operation", - template: function(params, query, body) { - //console.log(params) - //console.log(query) - if (params.operation === 'getaccount') { - return {balance: 1, assetV2: [], votes: [], frozen: []} - } - - return {error: "Not implemented"}; - } -}; diff --git a/mock/ext-api-dyson/post/vechain-api-logs.js b/mock/ext-api-dyson/post/vechain-api-logs.js deleted file mode 100644 index 0be3129d2..000000000 --- a/mock/ext-api-dyson/post/vechain-api-logs.js +++ /dev/null @@ -1,50 +0,0 @@ -/// Vechain RPC API Mock -/// See: -/// curl -H "Content-Type: application/json" -d '{"options": {"offset": 0, "limit": 15 }, "criteriaSet": [{"sender": "0xB5e883349e68aB59307d1604555AC890fAC47128"},{"recipient": "0xB5e883349e68aB59307d1604555AC890fAC47128"}], "range": {"unit": "block", "from": 0, "to": 5466405 }, "order": "desc"}' https://vethor-pubnode.digonchain.com/logs/transfer -/// curl -H "Content-Type: application/json" -d '{"options": {"offset": 0, "limit": 15 }, "criteriaSet": [{"sender": "0xB5e883349e68aB59307d1604555AC890fAC47128"},{"recipient": "0xB5e883349e68aB59307d1604555AC890fAC47128"}], "range": {"unit": "block", "from": 0, "to": 5466405 }, "order": "desc"}' http://localhost:3347/vechain-api/logs/transfer -/// curl "http://localhost:8437/v1/vechain/0xB5e883349e68aB59307d1604555AC890fAC47128" - -module.exports = { - path: '/vechain-api/logs/:entity', - template: function(params, query, body) { - //console.log(params); - //console.log(body); - if (params.entity === 'transfer') { - // TODO check sender/recipient - if (body["criteriaSet"][0]["sender"] === '0xB5e883349e68aB59307d1604555AC890fAC47128' || - body["criteriaSet"][1]["recipient"] === '0xB5e883349e68aB59307d1604555AC890fAC47128') { - return JSON.parse(` - [ - { - "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", - "recipient": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", - "amount": "0x12b1815d00738000", - "meta": { - "blockID": "0x004313a4bd4286e821b684cc1749deb3df12fa2a8114435fbd35baa155e82016", - "blockNumber": 4395940, - "blockTimestamp": 1574410670, - "txID": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", - "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", - "clauseIndex": 0 - } - }, - { - "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", - "recipient": "0x00bae5ed35736e4ef17af1be0c6f50e0fb73d685", - "amount": "0x38f6ea18e810b6f00", - "meta": { - "blockID": "0x0042249bee56223e0ed7a9c7fcfffe8e61b9fd95d29d24843c558ff2c46ea094", - "blockNumber": 4334747, - "blockTimestamp": 1573795570, - "txID": "0x004aa0448e458105b098aea2a764a1d54ab95451bee488869f417b351857c3c5", - "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", - "clauseIndex": 0 - } - } - ] - `); - } - } - return {error: "Not implemented"}; - } -}; diff --git a/mock/mockserver/mock-healthcheck.json b/mock/mockserver/mock-healthcheck.json new file mode 100644 index 000000000..17741549f --- /dev/null +++ b/mock/mockserver/mock-healthcheck.json @@ -0,0 +1,4 @@ +{ + "status": true, + "msg": "Mockserver is alive" +} diff --git a/mock/mockserver/mockserver.go b/mock/mockserver/mockserver.go new file mode 100644 index 000000000..913ab863b --- /dev/null +++ b/mock/mockserver/mockserver.go @@ -0,0 +1,232 @@ +// Tool to update test data files. Real URLs are derived from test data file names and urlmap.yaml + +package main + +import ( + "errors" + "fmt" + "gopkg.in/yaml.v2" + "io/ioutil" + "log" + "net/http" + "net/url" + "strconv" + "strings" +) + +type TestDataEntry struct { + Filename string `yaml:"file"` + MockURL string `yaml:"mockURL"` + Method string `yaml:"method"` + ExtURL string `yaml:"extURL,omitempty"` + ReqFile string `yaml:"reqFile,omitempty"` + ReqField string `yaml:"reqField,omitempty"` +} + +type TestDataEntryInternal struct { + TestDataEntry + ParsedURL *url.URL `yaml:"-"` +} + +var files []TestDataEntryInternal + +// matchQueryParams compares HTTP GET params, checks that all provided params contain all parameters from the expected params, with the same values +func matchQueryParams(expected, actual string) bool { + if len(expected) == 0 { + return true + } + valuesExp, err := url.ParseQuery(expected) + if err != nil { + return false + } + valuesAct, err := url.ParseQuery(actual) + if err != nil { + return false + } + for vv := range valuesExp { + if _, ok := valuesAct[vv]; !ok { + // param vv from valuesExp is not present in valuesAct + return false + } + if valuesAct[vv][0] != valuesExp[vv][0] { + // param is present in both, but value is different + return false + } + } + // all present with same values + return true +} + +func readFileList(directory string) error { + filename := directory + "/datafiles.yaml" + yamlFile, err := ioutil.ReadFile(filename) + if err != nil { + log.Fatalf("Could not read index err %v file %v", err.Error(), filename) + return errors.New("Could not read index file, err " + err.Error() + " file " + filename) + } + files1 := []TestDataEntry{} + err = yaml.Unmarshal(yamlFile, &files1) + if err != nil { + log.Fatalf("Could not read index err %v file %v", err.Error(), filename) + return errors.New("Could not read index file, err " + err.Error() + " file " + filename) + } + + // some preprocessing + files = []TestDataEntryInternal{} + for _, e := range files1 { + parsedURL, err := url.Parse(e.MockURL) + if err == nil { + files = append(files, TestDataEntryInternal{e, parsedURL}) + } + } + fmt.Printf("Info about %v data files read\n", len(files)) + return nil +} + +func fieldValueFromJson(json, field string) (string, error) { + fieldIdx := strings.Index(json, field) + if fieldIdx < 0 { + return "", errors.New("Field not found") + } + rest := json[fieldIdx+len(field)+1:] + firstQuote := strings.Index(rest, "\"") + if fieldIdx < 0 { + return "", errors.New("1st quote not found") + } + rest = rest[firstQuote+1:] + secondQuote := strings.Index(rest, "\"") + if fieldIdx < 0 { + return "", errors.New("1st quote not found") + } + val := rest[:secondQuote] + return val, nil +} + +func preprocessRequestJson(j string) string { + j = strings.Replace(j, "\"", "", -1) + j = strings.Replace(j, "'", "", -1) + j = strings.Replace(j, " ", "", -1) + j = strings.Replace(j, "\n", "", -1) + j = strings.Replace(j, "\t", "", -1) + return j +} + +func matchRequestDataJson(actualReqData, expReqData, fieldDiscriminator string) error { + if len(fieldDiscriminator) > 0 { + valActual, err := fieldValueFromJson(actualReqData, fieldDiscriminator) + if err != nil { + return err + } + valExp, err := fieldValueFromJson(expReqData, fieldDiscriminator) + if err != nil { + return err + } + if valExp == valActual { + // OK, match + log.Println("Request data match based on discriminator field " + fieldDiscriminator + " val " + valActual) + return nil + } + return errors.New("Request data mismatch, discriminator field " + fieldDiscriminator + " actual " + valActual + " expected " + valExp) + } + // no field separator, full match + if actualReqData == expReqData { + return nil + } + v1r := preprocessRequestJson(actualReqData) + v2r := preprocessRequestJson(expReqData) + if v1r == v2r { + return nil + } + return errors.New("Mismatch in request data, actual '" + actualReqData + "' expected '" + expReqData + "'") +} + +func findFileForMockURL(mockURL, method, queryParams, requestBody string) (TestDataEntryInternal, error) { + lasterr := "" + for _, ff := range files { + if method != ff.Method { + continue + } + // simple check + if mockURL != ff.ParsedURL.Path { + continue + } + // check query params + if len(queryParams) > 0 { + if !matchQueryParams(ff.ParsedURL.RawQuery, queryParams) { + // mismatch in query, remember message, but continue trying + lasterr = "Mismatch in query params, expected " + ff.ParsedURL.RawQuery + ", actual " + queryParams + continue + } + } + // check request data + if len(requestBody) > 0 { + // read request file + reqFileB, err := ioutil.ReadFile(ff.ReqFile) + if err == nil { + expectedRequestData := string(reqFileB) + if err = matchRequestDataJson(requestBody, expectedRequestData, ff.ReqField); err != nil { + // mismatch in request data, remember message, but continue trying + lasterr = "Mismatch in request data " + err.Error() + continue + } + } + } + // all matches + return ff, nil + } + return TestDataEntryInternal{}, errors.New("Could not find matching entry for URL, " + lasterr) +} + +func requestHandlerIntern(w http.ResponseWriter, r *http.Request, method, body, basedir string) error { + mockURL := r.URL.Path + entry, err := findFileForMockURL(mockURL, method, r.URL.RawQuery, body) + if err != nil { + return err + } + // read and return response + b, err := ioutil.ReadFile(basedir + "/" + entry.Filename) + if err != nil { + return errors.New("Could not read data file for request") + } + fmt.Fprint(w, string(b)) + return nil +} + +func requestHandler(w http.ResponseWriter, r *http.Request, basedir string) { + // read body + body := "" + if r.Method == "POST" { + bodyByte, err := ioutil.ReadAll(r.Body) + if err == nil { + body = string(bodyByte) + } + } + err := requestHandlerIntern(w, r, r.Method, body, basedir) + if err == nil { + log.Println("Request ok", r.Method, r.URL.Path, r.URL.RawQuery, body) + return + } + // error + errorMsg := err.Error() + log.Println("ERROR for request:", errorMsg, r.Method, r.URL.Path, r.URL.RawQuery, body) + fmt.Fprintf(w, "{\"error\": \""+errorMsg+"\", \"url\": \""+r.URL.Path+"\"") +} + +func main() { + basedir := "." + if err := readFileList(basedir + "/mock"); err != nil { + log.Fatalf("Could not read data file list, err %v", err.Error()) + return + } + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + requestHandler(w, r, basedir) + }) + + port := 3347 + log.Printf("About to listen on port %v", port) + err := http.ListenAndServe(":"+strconv.Itoa(port), nil) + if err != nil { + log.Fatalf("Could not listen on port %v", port) + } +} diff --git a/mock/mockserver/mockserver_test.go b/mock/mockserver/mockserver_test.go new file mode 100644 index 000000000..8a636c2b5 --- /dev/null +++ b/mock/mockserver/mockserver_test.go @@ -0,0 +1,67 @@ +package main + +import ( + "testing" +) + +func TestMatchQueryParams(t *testing.T) { + tests := [][]string{ + []string{ + "a=1&b=20", + "a=1&b=20", + "true", + }, + []string{ + "a=1&b=20", + "a=1&b=20&c=3", + "true", + }, + []string{ + "a=1&b=20", + "b=20&a=1", + "true", + }, + []string{ + "a=1&b=20", + "a=1&b=500", + "false", + }, + []string{ + "a=1&b=20", + "a=123&b=20", + "false", + }, + []string{ + "a=1&b=20", + "a=1", + "false", + }, + []string{ + "a=1&b=20", + "b=20", + "false", + }, + []string{ + "", + "c=500", + "true", + }, + []string{ + "", + "", + "true", + }, + } + for _, tt := range tests { + inputExpected := tt[0] + inputActual := tt[1] + expectedResult := true + if tt[2] == "false" { + expectedResult = false + } + result := matchQueryParams(inputExpected, inputActual) + if result != expectedResult { + t.Errorf("Did not match, inputExpected %v inputActual %v expectedResult %v", inputExpected, inputActual, expectedResult) + } + } +} diff --git a/tests/postman/blockatlas.postman_collection.json b/tests/postman/blockatlas.postman_collection.json index c023db8f2..869859918 100644 --- a/tests/postman/blockatlas.postman_collection.json +++ b/tests/postman/blockatlas.postman_collection.json @@ -2076,12 +2076,12 @@ "method": "GET", "header": [], "url": { - "raw": "localhost:3347/dyson-ping/ping", + "raw": "localhost:3347/mock/mock-healthcheck", "host": [ "localhost:3347" ], "path": [ - "dyson-ping/ping" + "mock/mock-healthcheck" ] } }, From cb480aa8c2d67cccd6bc9f3aaf4aab9af2ffb9e0 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Tue, 26 May 2020 19:26:11 +0300 Subject: [PATCH 308/506] Change subscriptions table and the way of storing it (#1115) * Change subscriptions table and the way of storing it * Cleanup --- db/db.go | 1 - db/models/subscriptions.go | 18 +- db/subscriptions.go | 162 ++------ db/subscritions_test.go | 91 ----- pkg/blockatlas/observer.go | 3 - pkg/blockatlas/observer_test.go | 12 +- services/observer/notifier/notifier.go | 8 +- services/observer/subscriber/subscriber.go | 20 +- .../observer/subscriber/subscriber_test.go | 16 +- .../integration/db_test/subscriptions_test.go | 355 ++++++------------ .../data/given_subscriptions_added.json | 4 - .../data/given_subscriptions_deleted.json | 4 - .../data/wanted_subscriptions_added.json | 12 +- .../observer_test/full_flow_test.go | 3 +- .../observer_test/notifier_test.go | 3 +- .../observer_test/subscriber_test.go | 46 ++- tests/integration/setup/postgres.go | 1 - 17 files changed, 210 insertions(+), 549 deletions(-) delete mode 100644 db/subscritions_test.go diff --git a/db/db.go b/db/db.go index fe79c9638..5eed3e70e 100644 --- a/db/db.go +++ b/db/db.go @@ -30,7 +30,6 @@ func New(uri, env string) (*Instance, error) { g.AutoMigrate( &models.Subscription{}, - &models.SubscriptionData{}, &models.Tracker{}, ) diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index 016e8624a..740d7ce2b 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -1,16 +1,12 @@ package models -import "time" +import ( + "time" +) type Subscription struct { - SubscriptionId uint `gorm:"primary_key:true"` - UpdatedAt time.Time - Data []SubscriptionData `gorm:"foreignkey:SubscriptionId"` -} - -type SubscriptionData struct { - ID uint `gorm:"primary_key;"` - SubscriptionId uint `gorm:"primary_key; column:subscription_id; auto_increment:false"` - Coin uint `gorm:"primary_key; column:coin; auto_increment:false"` - Address string `gorm:"primary_key; column:address; type:varchar(128)"` + CreatedAt time.Time + DeletedAt *time.Time `sql:"index"` + Coin uint `gorm:"primary_key; column:coin; auto_increment:false"` + Address string `gorm:"primary_key; column:address; type:varchar(128)"` } diff --git a/db/subscriptions.go b/db/subscriptions.go index 917fc4021..e351790a2 100644 --- a/db/subscriptions.go +++ b/db/subscriptions.go @@ -3,24 +3,23 @@ package db import ( "context" "fmt" + "github.com/jinzhu/gorm" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/errors" + "go.elastic.co/apm" "go.elastic.co/apm/module/apmgorm" - "strconv" "strings" "time" ) -const rawBulkInsert = `INSERT INTO subscription_data(subscription_id, coin, address) VALUES %s ON CONFLICT DO NOTHING` - -func (i *Instance) GetSubscriptionData(coin uint, addresses []string, ctx context.Context) ([]models.SubscriptionData, error) { +func (i *Instance) GetSubscriptions(coin uint, addresses []string, ctx context.Context) ([]models.Subscription, error) { if len(addresses) == 0 { return nil, errors.E("Empty addresses") } g := apmgorm.WithContext(ctx, i.Gorm) - var subscriptionsDataList []models.SubscriptionData + var subscriptionsDataList []models.Subscription err := g. - Model(&models.SubscriptionData{}). + Model(&models.Subscription{}). Where("address in (?) AND coin = ?", addresses, coin). Find(&subscriptionsDataList).Error @@ -30,113 +29,44 @@ func (i *Instance) GetSubscriptionData(coin uint, addresses []string, ctx contex return subscriptionsDataList, nil } -func (i *Instance) AddSubscriptions(id uint, subscriptions []models.SubscriptionData, ctx context.Context) error { +func (i *Instance) AddSubscriptions(subscriptions []models.Subscription, ctx context.Context) error { if len(subscriptions) == 0 { return errors.E("Empty subscriptions") } - g := apmgorm.WithContext(ctx, i.Gorm) - txInstance := Instance{Gorm: g.Begin()} - defer func() { - if r := recover(); r != nil { - txInstance.Gorm.Rollback() - } - }() - - if err := txInstance.Gorm.Error; err != nil { - return err - } - var ( - existingSub models.Subscription - err error - ) - - recordNotFound := txInstance.Gorm. - Where(models.Subscription{SubscriptionId: id}). - First(&existingSub). - RecordNotFound() + subscriptionsBatch := toSubscriptionBatch(subscriptions, batchLimit, ctx) + g := apmgorm.WithContext(ctx, i.Gorm) - subscriptions = removeSubscriptionDuplicates(subscriptions) - if recordNotFound { - err = txInstance.Gorm.Set("gorm:insert_option", - "ON CONFLICT (subscription_id) DO UPDATE SET subscription_id = excluded.subscription_id"). - Create(&models.Subscription{SubscriptionId: id, UpdatedAt: time.Now()}).Error - if err != nil { - txInstance.Gorm.Rollback() + for _, s := range subscriptionsBatch { + if err := bulkCreate(g, s); err != nil { return err } - err = txInstance.BulkCreate(subscriptions) - } else { - err = txInstance.AddToExistingSubscription(id, subscriptions) } - if err != nil { - txInstance.Gorm.Rollback() - return err - } - return txInstance.Gorm.Commit().Error + return nil } -func (i *Instance) AddToExistingSubscription(id uint, subscriptions []models.SubscriptionData) error { - var ( - existingData []models.SubscriptionData - association = i.Gorm.Model(&models.Subscription{SubscriptionId: id}).Association("Data") - ) - if err := association.Error; err != nil { - return err - } - if err := association.Find(&existingData).Error; err != nil { - return err +func (i *Instance) DeleteSubscriptions(subscriptions []models.Subscription, ctx context.Context) error { + if len(subscriptions) == 0 { + return errors.E("Empty subscriptions") } - updateList, deleteList := getSubscriptionsToDeleteAndUpdate(existingData, subscriptions) - if len(updateList) > 0 { - if err := i.BulkCreate(updateList); err != nil { - return err - } - } - if len(deleteList) > 0 { - if err := i.DeleteSubscriptions(deleteList); err != nil { + g := apmgorm.WithContext(ctx, i.Gorm) + for _, s := range subscriptions { + err := g.Where("coin = ? and address = ?", s.Coin, s.Address).Delete(&models.Subscription{}).Error + if err != nil { return err } } - - if err := i.Gorm.Model(&models.Subscription{SubscriptionId: id}).Update("updated_at", time.Now()).Error; err != nil { - return err - } - return nil } -func (i *Instance) DeleteAllSubscriptions(id uint, ctx context.Context) error { - g := apmgorm.WithContext(ctx, i.Gorm) - request := g.Where("subscription_id = ?", id) - if err := request.Error; err != nil { - return err - } - return request.Delete(&models.SubscriptionData{}).Error -} - -func (i *Instance) DeleteSubscriptions(subscriptions []models.SubscriptionData) error { - var idList = make([]string, 0, len(subscriptions)) - - for _, sub := range subscriptions { - idList = append(idList, strconv.Itoa(int(sub.ID))) - } - - request := i.Gorm.Where("id in (?)", idList) - - if err := request.Error; err != nil { - return err - } - if err := request.Delete(&models.SubscriptionData{}).Error; err != nil { - return err - } - - return nil -} +const ( + batchLimit = 3000 + rawBulkInsert = `INSERT INTO subscriptions(created_at,coin,address) VALUES %s ON CONFLICT DO NOTHING` +) -func (i *Instance) BulkCreate(dataList []models.SubscriptionData) error { +func bulkCreate(db *gorm.DB, dataList []models.Subscription) error { var ( valueStrings []string valueArgs []interface{} @@ -145,51 +75,33 @@ func (i *Instance) BulkCreate(dataList []models.SubscriptionData) error { for _, d := range dataList { valueStrings = append(valueStrings, "(?, ?, ?)") - valueArgs = append(valueArgs, d.SubscriptionId) + valueArgs = append(valueArgs, time.Now()) valueArgs = append(valueArgs, d.Coin) valueArgs = append(valueArgs, d.Address) } smt := fmt.Sprintf(rawBulkInsert, strings.Join(valueStrings, ",")) - if err := i.Gorm.Exec(smt, valueArgs...).Error; err != nil { + if err := db.Exec(smt, valueArgs...).Error; err != nil { return err } return nil } -func getSubscriptionsToDeleteAndUpdate(existing, new []models.SubscriptionData) (subToUpdate, subToDelete []models.SubscriptionData) { - for _, n := range new { - if !containSubscription(n, existing) { - subToUpdate = append(subToUpdate, n) - } - } - for _, e := range existing { - if !containSubscription(e, new) { - subToDelete = append(subToDelete, e) - } - } - return subToUpdate, subToDelete -} - -func containSubscription(sub models.SubscriptionData, list []models.SubscriptionData) bool { - for _, s := range list { - if s.Address == sub.Address && sub.Coin == s.Coin && s.SubscriptionId == sub.SubscriptionId { - return true - } - } - return false -} - -func removeSubscriptionDuplicates(sub []models.SubscriptionData) []models.SubscriptionData { - keys := make(map[models.SubscriptionData]bool) - result := make([]models.SubscriptionData, 0) - for _, entry := range sub { - if _, value := keys[entry]; !value { - keys[entry] = true - result = append(result, entry) +func toSubscriptionBatch(txs []models.Subscription, sizeUint uint, ctx context.Context) [][]models.Subscription { + span, _ := apm.StartSpan(ctx, "toSubscriptionBatch", "app") + defer span.End() + size := int(sizeUint) + resultLength := (len(txs) + size - 1) / size + result := make([][]models.Subscription, resultLength) + lo, hi := 0, size + for i := range result { + if hi > len(txs) { + hi = len(txs) } + result[i] = txs[lo:hi:hi] + lo, hi = hi, hi+size } return result } diff --git a/db/subscritions_test.go b/db/subscritions_test.go deleted file mode 100644 index 274ceec5a..000000000 --- a/db/subscritions_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package db - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/db/models" - "testing" -) - -func TestGetSubscriptionsToDeleteAndUpdate(t *testing.T) { - oldSubscriptions := []models.SubscriptionData{{ - SubscriptionId: 1, - Coin: 60, - Address: "A", - }, { - SubscriptionId: 1, - Coin: 60, - Address: "B", - }, { - SubscriptionId: 1, - Coin: 60, - Address: "C", - }} - - newSubscription := []models.SubscriptionData{{ - SubscriptionId: 1, - Coin: 60, - Address: "B", - }, { - SubscriptionId: 1, - Coin: 60, - Address: "C", - }} - - update, delete := getSubscriptionsToDeleteAndUpdate(oldSubscriptions, newSubscription) - assert.Len(t, update, 0) - assert.Len(t, delete, 1) - assert.Equal(t, "A", delete[0].Address) - - oldSubscriptions = []models.SubscriptionData{{ - SubscriptionId: 1, - Coin: 60, - Address: "A", - }, { - SubscriptionId: 1, - Coin: 60, - Address: "B", - }, { - SubscriptionId: 1, - Coin: 60, - Address: "C", - }, { - SubscriptionId: 1, - Coin: 60, - Address: "D", - }} - - newSubscription = []models.SubscriptionData{{ - SubscriptionId: 1, - Coin: 60, - Address: "E", - }} - - update, delete = getSubscriptionsToDeleteAndUpdate(oldSubscriptions, newSubscription) - assert.Len(t, update, 1) - assert.Len(t, delete, 4) - - oldSubscriptions = []models.SubscriptionData{{ - SubscriptionId: 1, - Coin: 60, - Address: "A", - }, { - SubscriptionId: 1, - Coin: 60, - Address: "B", - }} - - newSubscription = []models.SubscriptionData{{ - SubscriptionId: 1, - Coin: 60, - Address: "A", - }, { - SubscriptionId: 1, - Coin: 60, - Address: "B", - }} - - update, delete = getSubscriptionsToDeleteAndUpdate(oldSubscriptions, newSubscription) - assert.Len(t, update, 0) - assert.Len(t, delete, 0) - -} diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go index da61b1b7a..0caaaebe9 100644 --- a/pkg/blockatlas/observer.go +++ b/pkg/blockatlas/observer.go @@ -9,14 +9,12 @@ type ( SubscriptionEvent struct { Subscriptions Subscriptions `json:"subscriptions"` - Id uint `json:"id"` Operation SubscriptionOperation `json:"operation"` } Subscription struct { Coin uint `json:"coin"` Address string `json:"address"` - Id uint `json:"id"` } CoinStatus struct { @@ -41,7 +39,6 @@ func (e *SubscriptionEvent) ParseSubscriptions(s Subscriptions) []Subscription { subs = append(subs, Subscription{ Coin: uint(coin), Address: addr, - Id: e.Id, }) } } diff --git a/pkg/blockatlas/observer_test.go b/pkg/blockatlas/observer_test.go index 1cd29b123..b0386c4f9 100644 --- a/pkg/blockatlas/observer_test.go +++ b/pkg/blockatlas/observer_test.go @@ -15,18 +15,17 @@ func Test_parseSubscriptions(t *testing.T) { { name: "guid with 1 coin", subscriptions: SubscriptionEvent{ - Id: 1, Subscriptions: Subscriptions{ "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, }, }, wantSubs: []Subscription{ { - Coin: 0, Id: 1, + Coin: 0, Address: "xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", }, { - Coin: 0, Id: 1, + Coin: 0, Address: "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL", }, }, @@ -34,7 +33,6 @@ func Test_parseSubscriptions(t *testing.T) { { name: "guid with 2 coins", subscriptions: SubscriptionEvent{ - Id: 1, Subscriptions: Subscriptions{ "2": {"zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc"}, "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, @@ -42,15 +40,15 @@ func Test_parseSubscriptions(t *testing.T) { }, wantSubs: []Subscription{ { - Coin: 2, Id: 1, + Coin: 2, Address: "zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc", }, { - Coin: 0, Id: 1, + Coin: 0, Address: "xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", }, { - Coin: 0, Id: 1, + Coin: 0, Address: "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL", }, }, diff --git a/services/observer/notifier/notifier.go b/services/observer/notifier/notifier.go index 898242bb6..e1a01932c 100644 --- a/services/observer/notifier/notifier.go +++ b/services/observer/notifier/notifier.go @@ -22,7 +22,6 @@ var MaxPushNotificationsBatchLimit uint = DefaultPushNotificationsBatchLimit type TransactionNotification struct { Action blockatlas.TransactionType `json:"action"` Result *blockatlas.Tx `json:"result"` - Id uint `json:"id"` } func RunNotifier(database *db.Instance, delivery amqp.Delivery) { @@ -51,7 +50,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { } addresses := blockTransactions.GetUniqueAddresses() - subscriptionsDataList, err := database.GetSubscriptionData(txs[0].Coin, addresses, ctx) + subscriptionsDataList, err := database.GetSubscriptions(txs[0].Coin, addresses, ctx) if err != nil || len(subscriptionsDataList) == 0 { return } @@ -61,7 +60,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { for _, data := range subscriptionsDataList { go buildAndPostMessage( blockTransactions, - blockatlas.Subscription{Coin: data.Coin, Address: data.Address, Id: data.SubscriptionId}, + blockatlas.Subscription{Coin: data.Coin, Address: data.Address}, &wg, ctx) } wg.Wait() @@ -84,10 +83,9 @@ func buildAndPostMessage(blockTransactions blockatlas.TxSetMap, sub blockatlas.S notification := TransactionNotification{ Action: tx.Type, Result: &tx, - Id: sub.Id, } - logger.Info("Notification ready", logger.Params{"Id": sub.Id, "coin": sub.Coin, "txID": tx.ID}) + logger.Info("Notification ready", logger.Params{"coin": sub.Coin, "txID": tx.ID}) notifications = append(notifications, notification) } diff --git a/services/observer/subscriber/subscriber.go b/services/observer/subscriber/subscriber.go index 1100b4361..d4ced170e 100644 --- a/services/observer/subscriber/subscriber.go +++ b/services/observer/subscriber/subscriber.go @@ -20,28 +20,28 @@ const ( func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { tx := apm.DefaultTracer.StartTransaction("RunSubscriber", "app") defer tx.End() + ctx := apm.ContextWithTransaction(context.Background(), tx) + var event blockatlas.SubscriptionEvent err := json.Unmarshal(delivery.Body, &event) if err != nil { - logger.Fatal(err) + errAck := delivery.Ack(false) + logger.Fatal(err, errAck) } subscriptions := event.ParseSubscriptions(event.Subscriptions) - - params := logger.Params{"operation": event.Operation, "id": event.Id, "subscriptions_len": len(subscriptions)} - - id := event.Id + params := logger.Params{"operation": event.Operation, "subscriptions_len": len(subscriptions)} switch event.Operation { case AddSubscription, UpdateSubscription: - err = database.AddSubscriptions(id, ToSubscriptionData(subscriptions), ctx) + err = database.AddSubscriptions(ToSubscriptionData(subscriptions), ctx) if err != nil { logger.Error(err, params) } logger.Info("Added", params) case DeleteSubscription: - err := database.DeleteAllSubscriptions(id, ctx) + err := database.DeleteSubscriptions(ToSubscriptionData(subscriptions), ctx) if err != nil { logger.Error(err, params) } @@ -54,10 +54,10 @@ func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { } } -func ToSubscriptionData(sub []blockatlas.Subscription) []models.SubscriptionData { - data := make([]models.SubscriptionData, 0, len(sub)) +func ToSubscriptionData(sub []blockatlas.Subscription) []models.Subscription { + data := make([]models.Subscription, 0, len(sub)) for _, s := range sub { - data = append(data, models.SubscriptionData{Coin: s.Coin, Address: s.Address, SubscriptionId: s.Id}) + data = append(data, models.Subscription{Coin: s.Coin, Address: s.Address}) } return data } diff --git a/services/observer/subscriber/subscriber_test.go b/services/observer/subscriber/subscriber_test.go index 713b879e8..bb75f7cba 100644 --- a/services/observer/subscriber/subscriber_test.go +++ b/services/observer/subscriber/subscriber_test.go @@ -11,23 +11,19 @@ func TestToSubscriptionData(t *testing.T) { sub := blockatlas.Subscription{ Coin: 60, Address: "A", - Id: 1, } sub2 := blockatlas.Subscription{ Coin: 60, Address: "B", - Id: 2, } - expectedModel := models.SubscriptionData{ - SubscriptionId: 1, - Coin: 60, - Address: "A", + expectedModel := models.Subscription{ + Coin: 60, + Address: "A", } - expectedModel1 := models.SubscriptionData{ - SubscriptionId: 2, - Coin: 60, - Address: "B", + expectedModel1 := models.Subscription{ + Coin: 60, + Address: "B", } res := ToSubscriptionData([]blockatlas.Subscription{sub, sub2}) diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go index 0cafda6dd..6503ed4ec 100644 --- a/tests/integration/db_test/subscriptions_test.go +++ b/tests/integration/db_test/subscriptions_test.go @@ -15,170 +15,147 @@ import ( func TestDb_AddSubscriptionsBulk(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.SubscriptionData - - id := uint(1) + var subscriptions []models.Subscription for i := 0; i < 100; i++ { - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: uint(i), - Address: "testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr", + subscriptions = append(subscriptions, models.Subscription{ + Coin: uint(i), + Address: "testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr", }) } - assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) for i := 0; i < 100; i++ { - s, err := database.GetSubscriptionData(uint(i), []string{"testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr"}, context.Background()) + s, err := database.GetSubscriptions(uint(i), []string{"testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr"}, context.Background()) assert.Nil(t, err) - assert.Equal(t, id, s[0].SubscriptionId) + assert.NotNil(t, s) } } func TestDb_AddSubscriptions(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.SubscriptionData + var subscriptions []models.Subscription - id := uint(1) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 60, - Address: "testAddr", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 60, + Address: "testAddr", }) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 61, - Address: "testAddr2", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 61, + Address: "testAddr2", }) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 62, - Address: "testAddr3", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 62, + Address: "testAddr3", }) - assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) + subs, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) - assert.Equal(t, subscriptions[0].SubscriptionId, subs[0].SubscriptionId) assert.Equal(t, subscriptions[0].Coin, subs[0].Coin) assert.Equal(t, subscriptions[0].Address, subs[0].Address) - subs, err = database.GetSubscriptionData(61, []string{"testAddr2"}, context.Background()) + subs, err = database.GetSubscriptions(61, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) - assert.Equal(t, subscriptions[1].SubscriptionId, subs[0].SubscriptionId) assert.Equal(t, subscriptions[1].Coin, subs[0].Coin) assert.Equal(t, subscriptions[1].Address, subs[0].Address) - subs, err = database.GetSubscriptionData(62, []string{"testAddr3"}, context.Background()) + subs, err = database.GetSubscriptions(62, []string{"testAddr3"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) - assert.Equal(t, subscriptions[2].SubscriptionId, subs[0].SubscriptionId) assert.Equal(t, subscriptions[2].Coin, subs[0].Coin) assert.Equal(t, subscriptions[2].Address, subs[0].Address) } func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - id := uint(1) - var subscriptions []models.SubscriptionData - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 60, - Address: "testAddr", + var subscriptions []models.Subscription + subscriptions = append(subscriptions, models.Subscription{ + Coin: 60, + Address: "testAddr", }) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 714, - Address: "testAddr", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 714, + Address: "testAddr", }) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 144, - Address: "testAddr", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 144, + Address: "testAddr", }) - assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) + subs60, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs60) assert.Equal(t, 1, len(subs60)) - assert.Equal(t, subscriptions[0].SubscriptionId, subs60[0].SubscriptionId) assert.Equal(t, subscriptions[0].Coin, subs60[0].Coin) assert.Equal(t, subscriptions[0].Address, subs60[0].Address) - subs714, err := database.GetSubscriptionData(714, []string{"testAddr"}, context.Background()) + subs714, err := database.GetSubscriptions(714, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs714) assert.Equal(t, 1, len(subs714)) - assert.Equal(t, subscriptions[1].SubscriptionId, subs714[0].SubscriptionId) assert.Equal(t, subscriptions[1].Coin, subs714[0].Coin) assert.Equal(t, subscriptions[1].Address, subs714[0].Address) - subs144, err := database.GetSubscriptionData(144, []string{"testAddr"}, context.Background()) + subs144, err := database.GetSubscriptions(144, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs144) assert.Equal(t, 1, len(subs144)) - assert.Equal(t, subscriptions[2].SubscriptionId, subs144[0].SubscriptionId) assert.Equal(t, subscriptions[2].Coin, subs144[0].Coin) assert.Equal(t, subscriptions[2].Address, subs144[0].Address) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 60, - Address: "testAddr2", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 60, + Address: "testAddr2", }) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 714, - Address: "testAddr2", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 714, + Address: "testAddr2", }) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 144, - Address: "testAddr2", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 144, + Address: "testAddr2", }) - assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - subs2N60, err := database.GetSubscriptionData(60, []string{"testAddr2"}, context.Background()) + subs2N60, err := database.GetSubscriptions(60, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.Nil(t, err) assert.NotNil(t, subs2N60) assert.Equal(t, 1, len(subs2N60)) - assert.Equal(t, subscriptions[3].SubscriptionId, subs2N60[0].SubscriptionId) assert.Equal(t, subscriptions[3].Coin, subs2N60[0].Coin) assert.Equal(t, subscriptions[3].Address, subs2N60[0].Address) - subs2N714, err := database.GetSubscriptionData(714, []string{"testAddr2"}, context.Background()) + subs2N714, err := database.GetSubscriptions(714, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.Nil(t, err) assert.NotNil(t, subs2N714) assert.Equal(t, 1, len(subs2N714)) - assert.Equal(t, subscriptions[4].SubscriptionId, subs2N714[0].SubscriptionId) assert.Equal(t, subscriptions[4].Coin, subs2N714[0].Coin) assert.Equal(t, subscriptions[4].Address, subs2N714[0].Address) - subs2N114, err := database.GetSubscriptionData(144, []string{"testAddr2"}, context.Background()) + subs2N114, err := database.GetSubscriptions(144, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.Nil(t, err) assert.NotNil(t, subs2N114) assert.Equal(t, 1, len(subs2N114)) - assert.Equal(t, subscriptions[5].SubscriptionId, subs2N114[0].SubscriptionId) assert.Equal(t, subscriptions[5].Coin, subs2N114[0].Coin) assert.Equal(t, subscriptions[5].Address, subs2N114[0].Address) } @@ -187,324 +164,220 @@ func TestDb_FindSubscriptions(t *testing.T) { setup.CleanupPgContainer(database.Gorm) var subscriptionsA []blockatlas.Subscription - id := uint(1) subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ - Id: id, Coin: 60, Address: "etherAddress", }) subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ - Id: id, Coin: 714, Address: "binanceAddress", }) subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ - Id: id, Coin: 148, Address: "AtomAddress", }) subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ - Id: id, Coin: 144, Address: "XLMAddress", }) subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ - Id: id, Coin: 61, Address: "ETCAddress", }) - assert.Nil(t, database.AddSubscriptions(id, subscriber.ToSubscriptionData(subscriptionsA), context.Background())) + assert.Nil(t, database.AddSubscriptions(subscriber.ToSubscriptionData(subscriptionsA), context.Background())) var subscriptionsB []blockatlas.Subscription for _, sub := range subscriptionsA { - sub.Id = uint(2) subscriptionsB = append(subscriptionsB, sub) } - assert.Nil(t, database.AddSubscriptions(2, subscriber.ToSubscriptionData(subscriptionsB), context.Background())) + assert.Nil(t, database.AddSubscriptions(subscriber.ToSubscriptionData(subscriptionsB), context.Background())) - returnedSubs, err := database.GetSubscriptionData(60, []string{"etherAddress"}, context.Background()) + returnedSubs, err := database.GetSubscriptions(60, []string{"etherAddress"}, context.Background()) assert.Nil(t, err) - assert.Equal(t, 2, len(returnedSubs)) + assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionData(714, []string{"binanceAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptions(714, []string{"binanceAddress"}, context.Background()) assert.Nil(t, err) - assert.Equal(t, 2, len(returnedSubs)) + assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionData(144, []string{"XLMAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptions(144, []string{"XLMAddress"}, context.Background()) assert.Nil(t, err) - assert.Equal(t, 2, len(returnedSubs)) + assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionData(148, []string{"AtomAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptions(148, []string{"AtomAddress"}, context.Background()) assert.Nil(t, err) - assert.Equal(t, 2, len(returnedSubs)) + assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionData(61, []string{"ETCAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptions(61, []string{"ETCAddress"}, context.Background()) assert.Nil(t, err) - assert.Equal(t, 2, len(returnedSubs)) + assert.Equal(t, 1, len(returnedSubs)) } func TestDb_DeleteSubscriptions(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.SubscriptionData + var subscriptions []models.Subscription - id := uint(1) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 60, - Address: "testAddr", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 60, + Address: "testAddr", }) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 714, - Address: "testAddr2", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 714, + Address: "testAddr2", }) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 144, - Address: "testAddr3", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 144, + Address: "testAddr3", }) - assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) + subs60, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs60) assert.Equal(t, 1, len(subs60)) - assert.Equal(t, subscriptions[0].SubscriptionId, subs60[0].SubscriptionId) assert.Equal(t, subscriptions[0].Coin, subs60[0].Coin) assert.Equal(t, subscriptions[0].Address, subs60[0].Address) - subs714, err := database.GetSubscriptionData(714, []string{"testAddr2"}, context.Background()) + subs714, err := database.GetSubscriptions(714, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs714) assert.Equal(t, 1, len(subs714)) - assert.Equal(t, subscriptions[1].SubscriptionId, subs714[0].SubscriptionId) assert.Equal(t, subscriptions[1].Coin, subs714[0].Coin) assert.Equal(t, subscriptions[1].Address, subs714[0].Address) - subs144, err := database.GetSubscriptionData(144, []string{"testAddr3"}, context.Background()) + subs144, err := database.GetSubscriptions(144, []string{"testAddr3"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs144) assert.Equal(t, 1, len(subs144)) - assert.Equal(t, subscriptions[2].SubscriptionId, subs144[0].SubscriptionId) assert.Equal(t, subscriptions[2].Coin, subs144[0].Coin) assert.Equal(t, subscriptions[2].Address, subs144[0].Address) - subscriptions[0].ID = subs60[0].ID - subsToDel := []models.SubscriptionData{subscriptions[0]} + subsToDel := []models.Subscription{subscriptions[0]} - assert.Nil(t, database.DeleteSubscriptions(subsToDel)) + assert.Nil(t, database.DeleteSubscriptions(subsToDel, context.Background())) - subs714N2, err := database.GetSubscriptionData(714, []string{"testAddr2"}, context.Background()) + subs714N2, err := database.GetSubscriptions(714, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs714N2) assert.Equal(t, 1, len(subs714N2)) - assert.Equal(t, subscriptions[1].SubscriptionId, subs714N2[0].SubscriptionId) assert.Equal(t, subscriptions[1].Coin, subs714N2[0].Coin) assert.Equal(t, subscriptions[1].Address, subs714N2[0].Address) - subs144N2, err := database.GetSubscriptionData(144, []string{"testAddr3"}, context.Background()) + subs144N2, err := database.GetSubscriptions(144, []string{"testAddr3"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs144N2) assert.Equal(t, 1, len(subs144N2)) - assert.Equal(t, subscriptions[2].SubscriptionId, subs144N2[0].SubscriptionId) assert.Equal(t, subscriptions[2].Coin, subs144N2[0].Coin) assert.Equal(t, subscriptions[2].Address, subs144N2[0].Address) - subs60N2, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) + subs60N2, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs60N2, 0) } func TestDeleteAll(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.SubscriptionData + var subscriptions []models.Subscription - id := uint(1) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 60, - Address: "testAddr", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 60, + Address: "testAddr", }) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 714, - Address: "testAddr2", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 714, + Address: "testAddr2", }) - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 144, - Address: "testAddr3", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 144, + Address: "testAddr3", }) - assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - subs60, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) + subs60, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs60, 1) - subs714, err := database.GetSubscriptionData(714, []string{"testAddr2"}, context.Background()) + subs714, err := database.GetSubscriptions(714, []string{"testAddr2"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs714, 1) - subs144, err := database.GetSubscriptionData(144, []string{"testAddr3"}, context.Background()) + subs144, err := database.GetSubscriptions(144, []string{"testAddr3"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs144, 1) - - assert.Nil(t, database.DeleteAllSubscriptions(1, context.Background())) - - subs60, err = database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) - assert.Nil(t, err) - assert.Len(t, subs60, 0) - - subs714, err = database.GetSubscriptionData(714, []string{"testAddr2"}, context.Background()) - assert.Nil(t, err) - assert.Len(t, subs714, 0) - - subs144, err = database.GetSubscriptionData(144, []string{"testAddr3"}, context.Background()) - assert.Nil(t, err) - assert.Len(t, subs144, 0) - - assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) - - subs60, err = database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) - assert.Nil(t, err) - assert.Len(t, subs60, 1) } func TestDb_DuplicateEntries(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.SubscriptionData - - id := uint(1) + var subscriptions []models.Subscription for i := 0; i < 10; i++ { - subscriptions = append(subscriptions, models.SubscriptionData{ - SubscriptionId: id, - Coin: 60, - Address: "testAddr", + subscriptions = append(subscriptions, models.Subscription{ + Coin: 60, + Address: "testAddr", }) } - assert.Nil(t, database.AddSubscriptions(id, subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) + subs, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) assert.True(t, containSub(subscriptions[0], subs)) } -func TestDb_FindSubscriptions_Multiple(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.SubscriptionData - subscriptions = append(subscriptions, models.SubscriptionData{ - Coin: 60, - Address: "testAddr", - }) - - for i := 1; i < 6; i++ { - subscriptions[0].SubscriptionId = uint(i) - assert.Nil(t, database.AddSubscriptions(uint(i), subscriptions, context.Background())) - } - - subscriptions[0].SubscriptionId = uint(1) - assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) - - subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) - assert.Nil(t, err) - assert.Equal(t, 5, len(subs)) - - for i := 0; i < 5; i++ { - assert.Equal(t, uint(i)+1, subs[i].SubscriptionId) - } -} - -func TestDb_AddToExisting(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.SubscriptionData - subscriptions = append(subscriptions, models.SubscriptionData{ - Coin: 60, - Address: "testAddr", - }) - - subscriptions[0].SubscriptionId = uint(1) - assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) - - subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) - assert.Nil(t, err) - assert.Equal(t, 1, len(subs)) - - assert.Equal(t, uint(1), subs[0].SubscriptionId) - assert.Nil(t, database.AddToExistingSubscription(uint(1), subscriptions)) - - subs2, err2 := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) - assert.Nil(t, err2) - assert.Equal(t, 1, len(subs2)) - - assert.Equal(t, uint(1), subs2[0].SubscriptionId) - - assert.Nil(t, database.AddToExistingSubscription(uint(2), subscriptions)) - assert.Nil(t, database.AddToExistingSubscription(uint(1), subscriptions)) - - for i := 1; i < 2; i++ { - assert.Nil(t, database.AddToExistingSubscription(uint(i), subscriptions)) - } - assert.NotNil(t, database.AddToExistingSubscription(uint(0), subscriptions)) - -} - func TestDb_UpdatedAt(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.SubscriptionData - subscriptions = append(subscriptions, models.SubscriptionData{ + var subscriptions []models.Subscription + subscriptions = append(subscriptions, models.Subscription{ Coin: 60, Address: "testAddr", }) - subscriptions[0].SubscriptionId = uint(1) - assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) - subs, err := database.GetSubscriptionData(60, []string{"testAddr"}, context.Background()) + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) + subs, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(subs)) time.Sleep(time.Second) var existingSub models.Subscription - assert.False(t, database.Gorm.Where(models.Subscription{SubscriptionId: uint(1)}).First(&existingSub).RecordNotFound()) - assert.Greater(t, time.Now().Unix(), existingSub.UpdatedAt.Unix()) - assert.Greater(t, existingSub.UpdatedAt.Unix(), time.Now().Unix()-120) + assert.False(t, database.Gorm.Where(models.Subscription{Address: "testAddr"}).First(&existingSub).RecordNotFound()) + assert.Greater(t, time.Now().Unix(), existingSub.CreatedAt.Unix()) + assert.Greater(t, existingSub.CreatedAt.Unix(), time.Now().Unix()-120) - subscriptions = append(subscriptions, models.SubscriptionData{ + subscriptions = append(subscriptions, models.Subscription{ Coin: 714, Address: "newtestAddr", }) - assert.Nil(t, database.AddSubscriptions(uint(1), subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) time.Sleep(time.Second) var existingSub2 models.Subscription - assert.False(t, database.Gorm.Where(models.Subscription{SubscriptionId: uint(1)}).First(&existingSub2).RecordNotFound()) + assert.False(t, database.Gorm.Where(models.Subscription{Address: "testAddr"}).First(&existingSub2).RecordNotFound()) - assert.Greater(t, time.Now().Unix(), existingSub2.UpdatedAt.Unix()) - assert.Greater(t, existingSub2.UpdatedAt.Unix(), time.Now().Unix()-120) - assert.Greater(t, existingSub2.UpdatedAt.Unix(), existingSub.UpdatedAt.Unix()) + assert.Greater(t, time.Now().Unix(), existingSub2.CreatedAt.Unix()) + assert.Greater(t, existingSub2.CreatedAt.Unix(), time.Now().Unix()-120) + assert.GreaterOrEqual(t, existingSub2.CreatedAt.Unix(), existingSub.CreatedAt.Unix()) } -func containSub(sub models.SubscriptionData, list []models.SubscriptionData) bool { +func containSub(sub models.Subscription, list []models.Subscription) bool { for _, s := range list { - if sub.Address == s.Address && sub.Coin == s.Coin && sub.SubscriptionId == s.SubscriptionId { + if sub.Address == s.Address && sub.Coin == s.Coin { return true } } diff --git a/tests/integration/observer_test/data/given_subscriptions_added.json b/tests/integration/observer_test/data/given_subscriptions_added.json index 87fdbc915..e046cbd4d 100644 --- a/tests/integration/observer_test/data/given_subscriptions_added.json +++ b/tests/integration/observer_test/data/given_subscriptions_added.json @@ -5,7 +5,6 @@ "0x0000000000000000000000000000000000000000" ] }, - "id": 10, "operation": "AddSubscription" }, { @@ -14,7 +13,6 @@ "0x0000000000000000000000000000000000000001" ] }, - "id": 1, "operation": "AddSubscription" }, { @@ -23,7 +21,6 @@ "0x0000000000000000000000000000000000000002" ] }, - "id": 2, "operation": "AddSubscription" }, { @@ -32,7 +29,6 @@ "0x0000000000000000000000000000000000000003" ] }, - "id": 3, "operation": "AddSubscription" } ] diff --git a/tests/integration/observer_test/data/given_subscriptions_deleted.json b/tests/integration/observer_test/data/given_subscriptions_deleted.json index 7c887378b..7eaf817cd 100644 --- a/tests/integration/observer_test/data/given_subscriptions_deleted.json +++ b/tests/integration/observer_test/data/given_subscriptions_deleted.json @@ -5,7 +5,6 @@ "0x0000000000000000000000000000000000000000" ] }, - "id": 10, "operation": "UpdateSubscription" }, { @@ -14,7 +13,6 @@ "0x0000000000000000000000000000000000000001" ] }, - "id": 1, "operation": "UpdateSubscription" }, { @@ -23,7 +21,6 @@ "0x0000000000000000000000000000000000000002" ] }, - "id": 2, "operation": "UpdateSubscription" }, { @@ -32,7 +29,6 @@ "0x0000000000000000000000000000000000000003" ] }, - "id": 3, "operation": "UpdateSubscription" } ] diff --git a/tests/integration/observer_test/data/wanted_subscriptions_added.json b/tests/integration/observer_test/data/wanted_subscriptions_added.json index 7007019a0..051f5d674 100644 --- a/tests/integration/observer_test/data/wanted_subscriptions_added.json +++ b/tests/integration/observer_test/data/wanted_subscriptions_added.json @@ -1,22 +1,18 @@ [ { "coin": 60, - "address": "0x0000000000000000000000000000000000000000", - "id": 10 + "address": "0x0000000000000000000000000000000000000000" }, { "coin": 118, - "address": "0x0000000000000000000000000000000000000001", - "id": 1 + "address": "0x0000000000000000000000000000000000000001" }, { "coin": 714, - "address": "0x0000000000000000000000000000000000000002", - "id": 2 + "address": "0x0000000000000000000000000000000000000002" }, { "coin": 144, - "address": "0x0000000000000000000000000000000000000003", - "id": 3 + "address": "0x0000000000000000000000000000000000000003" } ] diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 29cce3ab3..d859ab1ea 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -25,7 +25,7 @@ var ( func TestFullFlow(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 60, Address: "testAddress", SubscriptionId: 1}}, context.Background()) + err := database.AddSubscriptions([]models.Subscription{{Coin: 60, Address: "testAddress"}}, context.Background()) assert.Nil(t, err) ctx, cancel := context.WithCancel(context.Background()) @@ -135,7 +135,6 @@ func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel Memo: "test", Meta: &memo, }, - Id: 1, }, notifications[0]) if counter == 10 { diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index 0f6a1abe9..dda305226 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -44,7 +44,7 @@ var ( func TestNotifier(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptions(1, []models.SubscriptionData{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", SubscriptionId: 1}}, context.Background()) + err := database.AddSubscriptions([]models.Subscription{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"}}, context.Background()) assert.Nil(t, err) err = produceTxs(txs) @@ -96,7 +96,6 @@ func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { Memo: "test", Meta: &memo, }, - Id: 1, }, notifications[0]) return diff --git a/tests/integration/observer_test/subscriber_test.go b/tests/integration/observer_test/subscriber_test.go index b7e9ac166..540d71524 100644 --- a/tests/integration/observer_test/subscriber_test.go +++ b/tests/integration/observer_test/subscriber_test.go @@ -57,9 +57,8 @@ func TestSubscriberAddSubscription(t *testing.T) { } for _, wanted := range wantedEvents { - result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}, context.Background()) + result, err := database.GetSubscriptions(wanted.Coin, []string{wanted.Address}, context.Background()) assert.Nil(t, err) - assert.Equal(t, result[0].SubscriptionId, wanted.Id) assert.Equal(t, result[0].Coin, wanted.Coin) assert.Equal(t, result[0].Address, wanted.Address) } @@ -92,18 +91,14 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { t.Fatal(err) } - database.AddSubscriptions(10, []models.SubscriptionData{ - {Coin: 61, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 10}, - }, context.Background()) - database.AddSubscriptions(1, []models.SubscriptionData{ - {Coin: 62, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 1}, - }, context.Background()) - database.AddSubscriptions(2, []models.SubscriptionData{ - {Coin: 63, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 2}, - }, context.Background()) - database.AddSubscriptions(3, []models.SubscriptionData{ - {Coin: 64, Address: "0x0000000000000000000000000000000000000000", SubscriptionId: 3}, - }, context.Background()) + database.AddSubscriptions([]models.Subscription{ + {Coin: 61, Address: "0x0000000000000000000000000000000000000000"}}, context.Background()) + database.AddSubscriptions([]models.Subscription{ + {Coin: 62, Address: "0x0000000000000000000000000000000000000000"}}, context.Background()) + database.AddSubscriptions([]models.Subscription{ + {Coin: 63, Address: "0x0000000000000000000000000000000000000000"}}, context.Background()) + database.AddSubscriptions([]models.Subscription{ + {Coin: 64, Address: "0x0000000000000000000000000000000000000000"}}, context.Background()) for _, event := range givenEvents { body, err := json.Marshal(event) @@ -120,27 +115,30 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { } for _, wanted := range wantedEvents { - result, err := database.GetSubscriptionData(wanted.Coin, []string{wanted.Address}, context.Background()) + result, err := database.GetSubscriptions(wanted.Coin, []string{wanted.Address}, context.Background()) assert.Nil(t, err) - assert.Equal(t, result[0].SubscriptionId, wanted.Id) assert.Equal(t, result[0].Coin, wanted.Coin) assert.Equal(t, result[0].Address, wanted.Address) } - abs61, err := database.GetSubscriptionData(61, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) + abs61, err := database.GetSubscriptions(61, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) - assert.Len(t, abs61, 0) + assert.Len(t, abs61, 1) - abs62, err := database.GetSubscriptionData(62, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) + abs62, err := database.GetSubscriptions(62, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) - assert.Len(t, abs62, 0) + assert.Len(t, abs62, 1) - abs63, err := database.GetSubscriptionData(63, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) + abs63, err := database.GetSubscriptions(63, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) - assert.Len(t, abs63, 0) + assert.Len(t, abs63, 1) - abs64, err := database.GetSubscriptionData(64, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) + abs64, err := database.GetSubscriptions(64, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) - assert.Len(t, abs64, 0) + assert.Len(t, abs64, 1) + + abs65, err := database.GetSubscriptions(65, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) + assert.Nil(t, err) + assert.Len(t, abs65, 0) } diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go index 63ee3aa68..ec09821fe 100644 --- a/tests/integration/setup/postgres.go +++ b/tests/integration/setup/postgres.go @@ -25,7 +25,6 @@ var ( tables = []interface{}{ &models.Subscription{}, - &models.SubscriptionData{}, &models.Tracker{}, } From efb4080e0af48af298ef5a541eb55fb9580f5011 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Wed, 27 May 2020 21:21:03 +0300 Subject: [PATCH 309/506] Change gorm option for subscriptions createdAt field (#1117) * Change subscriptions table and the way of storing it * Change DB tables * Lint fix --- db/models/subscriptions.go | 6 +++--- db/subscriptions.go | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index 740d7ce2b..bb7ac0c80 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -5,8 +5,8 @@ import ( ) type Subscription struct { - CreatedAt time.Time + CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"` DeletedAt *time.Time `sql:"index"` - Coin uint `gorm:"primary_key; column:coin; auto_increment:false"` - Address string `gorm:"primary_key; column:address; type:varchar(128)"` + Coin uint `gorm:"primary_key; column:coin; auto_increment:false" sql:"index"` + Address string `gorm:"primary_key; column:address; type:varchar(128)" sql:"index"` } diff --git a/db/subscriptions.go b/db/subscriptions.go index e351790a2..121ce3490 100644 --- a/db/subscriptions.go +++ b/db/subscriptions.go @@ -9,7 +9,6 @@ import ( "go.elastic.co/apm" "go.elastic.co/apm/module/apmgorm" "strings" - "time" ) func (i *Instance) GetSubscriptions(coin uint, addresses []string, ctx context.Context) ([]models.Subscription, error) { @@ -63,7 +62,7 @@ func (i *Instance) DeleteSubscriptions(subscriptions []models.Subscription, ctx const ( batchLimit = 3000 - rawBulkInsert = `INSERT INTO subscriptions(created_at,coin,address) VALUES %s ON CONFLICT DO NOTHING` + rawBulkInsert = `INSERT INTO subscriptions(coin,address) VALUES %s ON CONFLICT DO NOTHING` ) func bulkCreate(db *gorm.DB, dataList []models.Subscription) error { @@ -73,9 +72,8 @@ func bulkCreate(db *gorm.DB, dataList []models.Subscription) error { ) for _, d := range dataList { - valueStrings = append(valueStrings, "(?, ?, ?)") + valueStrings = append(valueStrings, "(?, ?)") - valueArgs = append(valueArgs, time.Now()) valueArgs = append(valueArgs, d.Coin) valueArgs = append(valueArgs, d.Address) } From e71a841c7a30b0ffd4f61459643c3b6517bf9c5b Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 29 May 2020 05:55:14 +0300 Subject: [PATCH 310/506] Remove patch check for codecov (#1118) --- .codecov.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.codecov.yml b/.codecov.yml index aac5fb868..4d43e123f 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -9,6 +9,8 @@ coverage: # basic target: 30% + patch: no + ignore: - "mock" - "config" From 09801db5339a51505c266a16a12d9046d4352c41 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 29 May 2020 22:06:45 +0300 Subject: [PATCH 311/506] Fix issues with notifier (#1119) * Start to fix issue with notifier. Remove legacy codebase * Delete TestTxSet_Add and TestGetTxsTx * Add tests, fix linter errors * Additional changes of TransactionNotification struct * Integration test fix * Unit test fix Co-authored-by: Alexey Prazdnikov --- cmd/observer_parser/main.go | 3 +- pkg/blockatlas/tx.go | 15 -- pkg/blockatlas/tx_test.go | 102 ------------ pkg/blockatlas/txset.go | 55 ------- services/observer/notifier/base.go | 55 +++++++ services/observer/notifier/delivery.go | 48 ++++++ services/observer/notifier/models.go | 91 +++++++++++ services/observer/notifier/models_test.go | 146 ++++++++++++++++++ services/observer/notifier/notifier.go | 140 ----------------- services/observer/notifier/notifier_test.go | 54 ------- services/observer/parser/parser.go | 8 + services/observer/parser/parser_test.go | 47 ++++++ .../observer_test/full_flow_test.go | 4 +- .../observer_test/notifier_test.go | 2 +- .../integration/observer_test/parser_test.go | 3 +- 15 files changed, 400 insertions(+), 373 deletions(-) delete mode 100644 pkg/blockatlas/txset.go create mode 100644 services/observer/notifier/base.go create mode 100644 services/observer/notifier/delivery.go create mode 100644 services/observer/notifier/models.go create mode 100644 services/observer/notifier/models_test.go delete mode 100644 services/observer/notifier/notifier.go delete mode 100644 services/observer/notifier/notifier_test.go diff --git a/cmd/observer_parser/main.go b/cmd/observer_parser/main.go index e8282835e..ccbd384b6 100644 --- a/cmd/observer_parser/main.go +++ b/cmd/observer_parser/main.go @@ -9,7 +9,6 @@ import ( "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/services/observer/notifier" "github.com/trustwallet/blockatlas/services/observer/parser" "os" "os/signal" @@ -86,7 +85,7 @@ func main() { for _, api := range platform.BlockAPIs { time.Sleep(time.Millisecond * 5) coin := api.Coin() - pollInterval := notifier.GetInterval(coin.BlockTime, minInterval, maxInterval) + pollInterval := parser.GetInterval(coin.BlockTime, minInterval, maxInterval) var backlogCount int if coin.BlockTime == 0 { diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index d0ec8a63a..a555d6f43 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -228,21 +228,6 @@ func (t Txs) SortByDate() Txs { return t } -func (t Txs) GetTransactionsMap() TxSetMap { - txSetMap := TxSetMap{Map: make(map[string]*TxSet)} - for i := 0; i < len(t); i++ { - addresses := t[i].GetAddresses() - addresses = append(addresses, t[i].GetUtxoAddresses()...) - for _, address := range addresses { - if txSetMap.Map[address] == nil { - txSetMap.Map[address] = new(TxSet) - } - txSetMap.Map[address].Add(&t[i]) - } - } - return txSetMap -} - func (t *Tx) GetUtxoAddresses() (addresses []string) { for _, input := range t.Inputs { addresses = append(addresses, input.Address) diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 688f73355..1f1fc8de4 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -109,17 +109,6 @@ var utxoTransferDst2 = Tx{ Memo: "test", } -func TestTxSet_Add(t *testing.T) { - set := TxSet{} - set.Add(&transferDst1) - var txs = set.Txs() - assert.Equal(t, txs[0].ID, transferDst1.ID) - set.Add(&transferDst1) - assert.Equal(t, set.Size(), 1) - set.Add(&nativeTransferDst1) - assert.Equal(t, set.Size(), 2) -} - func TestTx_GetAddresses(t *testing.T) { assert.Equal(t, transferDst1.GetAddresses(), []string{"tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5"}) assert.Equal(t, nativeTransferDst1.GetAddresses(), []string{"tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex"}) @@ -403,97 +392,6 @@ func TestInferDirection(t *testing.T) { } } -var ( - transferDstOne = Tx{ - ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", - Coin: coin.BNB, - From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - To: "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5", - Fee: "125000", - Date: 1555049867, - Block: 7761368, - Status: StatusCompleted, - Memo: "test", - Meta: Transfer{ - Value: "10000000000000", - Decimals: 8, - Symbol: "BNB", - }, - } - - transferDst2 = Tx{ - ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44556", - Coin: coin.BNB, - From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - To: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - Fee: "125000", - Date: 1555049867, - Block: 7761368, - Status: StatusCompleted, - Memo: "test", - Meta: Transfer{ - Value: "10000000000000", - Decimals: 8, - Symbol: "BNB", - }, - } - - nativeTransferDstOne = Tx{ - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: StatusCompleted, - Memo: "test", - Meta: NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, - } - - nativeTransferDst2 = Tx{ - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4D0", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: StatusCompleted, - Memo: "test", - Meta: NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, - } -) - -func TestGetTxsTx(t *testing.T) { - tx := Txs{ - transferDstOne, - transferDst2, - nativeTransferDstOne, - nativeTransferDst2, - } - txs := tx.GetTransactionsMap() - assert.Equal(t, len(txs.Map), 4) - assert.Equal(t, txs.Map["tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2"].Size(), 2) - assert.Equal(t, txs.Map["tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5"].Size(), 1) - assert.Equal(t, txs.Map["tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"].Size(), 2) - assert.Equal(t, txs.Map["tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex"].Size(), 2) -} - func TestTx_GetTransactionDirection(t *testing.T) { txMeta := TokenTransfer{ Name: "Kyber Network Crystal", diff --git a/pkg/blockatlas/txset.go b/pkg/blockatlas/txset.go deleted file mode 100644 index 1819a149f..000000000 --- a/pkg/blockatlas/txset.go +++ /dev/null @@ -1,55 +0,0 @@ -package blockatlas - -import "sync" - -type ( - TxSetMap struct { - Map map[string]*TxSet - } - - TxSet struct { - items map[*Tx]bool - lock sync.RWMutex - } -) - -// Add adds a new element to the Map. Returns a pointer to the Map. -func (s *TxSet) Add(t *Tx) *TxSet { - s.lock.Lock() - defer s.lock.Unlock() - if s.items == nil { - s.items = make(map[*Tx]bool) - } - _, ok := s.items[t] - if !ok { - s.items[t] = true - } - return s -} - -func (s *TxSet) Txs() []Tx { - s.lock.RLock() - defer s.lock.RUnlock() - items := []Tx{} - for i := range s.items { - items = append(items, *i) - } - return items -} - -func (s *TxSet) Size() int { - s.lock.RLock() - defer s.lock.RUnlock() - return len(s.items) -} - -func (s TxSetMap) GetUniqueAddresses() []string { - var addresses []string - for address := range s.Map { - if len(address) == 0 { - continue - } - addresses = append(addresses, address) - } - return addresses -} diff --git a/services/observer/notifier/base.go b/services/observer/notifier/base.go new file mode 100644 index 000000000..2e56ae461 --- /dev/null +++ b/services/observer/notifier/base.go @@ -0,0 +1,55 @@ +package notifier + +import ( + "context" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/pkg/logger" + + "go.elastic.co/apm" +) + +const DefaultPushNotificationsBatchLimit = 50 + +var MaxPushNotificationsBatchLimit uint = DefaultPushNotificationsBatchLimit + +func RunNotifier(database *db.Instance, delivery amqp.Delivery) { + tx := apm.DefaultTracer.StartTransaction("RunNotifier", "app") + defer tx.End() + ctx := apm.ContextWithTransaction(context.Background(), tx) + + defer func() { + if err := delivery.Ack(false); err != nil { + logger.Error(err) + } + }() + + txs, err := getTransactionsFromDelivery(delivery, ctx) + if err != nil { + logger.Error("failed to get transactions", err) + } + + allAddresses := make([]string, 0) + for _, tx := range txs { + allAddresses = append(allAddresses, tx.GetAddresses()...) + } + + addresses := toUniqueAddresses(allAddresses) + + subscriptionsDataList, err := database.GetSubscriptions(txs[0].Coin, addresses, ctx) + if err != nil || len(subscriptionsDataList) == 0 { + return + } + + notifications := make([]TransactionNotification, 0) + for _, sub := range subscriptionsDataList { + notificationsForAddress := buildNotificationsByAddress(sub.Address, txs, ctx) + notifications = append(notifications, notificationsForAddress...) + } + + batches := getNotificationBatches(notifications, MaxPushNotificationsBatchLimit, ctx) + + for _, batch := range batches { + publishNotificationBatch(batch, ctx) + } +} diff --git a/services/observer/notifier/delivery.go b/services/observer/notifier/delivery.go new file mode 100644 index 000000000..9a1c3caf7 --- /dev/null +++ b/services/observer/notifier/delivery.go @@ -0,0 +1,48 @@ +package notifier + +import ( + "context" + "encoding/json" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/logger" + "go.elastic.co/apm" +) + +func getTransactionsFromDelivery(delivery amqp.Delivery, ctx context.Context) (blockatlas.Txs, error) { + var txs blockatlas.Txs + + span, _ := apm.StartSpan(ctx, "getTransactionsFromDelivery", "app") + defer span.End() + + if err := json.Unmarshal(delivery.Body, &txs); err != nil { + return nil, err + } + + logger.Info("Consumed", logger.Params{"txs": len(txs), "coin": txs[0].Coin}) + + if len(txs) == 0 { + return nil, errors.E("empty txs list") + } + return txs, nil +} + +func publishNotificationBatch(batch []TransactionNotification, ctx context.Context) { + span, _ := apm.StartSpan(ctx, "getNotificationBatches", "app") + defer span.End() + + raw, err := json.Marshal(batch) + if err != nil { + err = errors.E(err, " failed to dispatch event") + logger.Fatal(err) + } + err = mq.TxNotifications.Publish(raw) + if err != nil { + err = errors.E(err, " failed to dispatch event") + logger.Fatal(err) + } + + logger.Info("Txs batch dispatched", logger.Params{"txs": len(batch)}) +} diff --git a/services/observer/notifier/models.go b/services/observer/notifier/models.go new file mode 100644 index 000000000..f33054c8a --- /dev/null +++ b/services/observer/notifier/models.go @@ -0,0 +1,91 @@ +package notifier + +import ( + "context" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "go.elastic.co/apm" +) + +type TransactionNotification struct { + Action blockatlas.TransactionType `json:"action"` + Result blockatlas.Tx `json:"result"` +} + +func getNotificationBatches(notifications []TransactionNotification, sizeUint uint, ctx context.Context) [][]TransactionNotification { + span, _ := apm.StartSpan(ctx, "getNotificationBatches", "app") + defer span.End() + size := int(sizeUint) + resultLength := (len(notifications) + size - 1) / size + result := make([][]TransactionNotification, resultLength) + lo, hi := 0, size + for i := range result { + if hi > len(notifications) { + hi = len(notifications) + } + result[i] = notifications[lo:hi:hi] + lo, hi = hi, hi+size + } + return result +} + +func buildNotificationsByAddress(address string, txs blockatlas.Txs, ctx context.Context) []TransactionNotification { + span, _ := apm.StartSpan(ctx, "buildNotification", "app") + defer span.End() + + transactionsByAddress := toUniqueTransactions(findTransactionsByAddress(txs, address)) + + result := make([]TransactionNotification, 0, len(transactionsByAddress)) + for _, tx := range transactionsByAddress { + tx.Direction = tx.GetTransactionDirection(address) + tx.InferUtxoValue(address, tx.Coin) + result = append(result, TransactionNotification{Action: tx.Type, Result: tx}) + } + + return result +} + +func toUniqueAddresses(addresses []string) []string { + keys := make(map[string]bool) + var list []string + for _, entry := range addresses { + if _, value := keys[entry]; !value { + keys[entry] = true + list = append(list, entry) + } + } + return list +} + +func toUniqueTransactions(txs []blockatlas.Tx) []blockatlas.Tx { + keys := make(map[string]bool) + var list []blockatlas.Tx + for _, entry := range txs { + key := entry.ID + string(entry.Direction) + if _, value := keys[key]; !value { + keys[key] = true + list = append(list, entry) + } + } + return list +} + +func findTransactionsByAddress(txs blockatlas.Txs, address string) []blockatlas.Tx { + result := make([]blockatlas.Tx, 0) + for _, tx := range txs { + if containsAddress(tx, address) { + result = append(result, tx) + } + } + return result +} + +func containsAddress(tx blockatlas.Tx, address string) bool { + allAddresses := tx.GetAddresses() + txAddresses := toUniqueAddresses(allAddresses) + for _, a := range txAddresses { + if a == address { + return true + } + } + return false +} diff --git a/services/observer/notifier/models_test.go b/services/observer/notifier/models_test.go new file mode 100644 index 000000000..0569906dd --- /dev/null +++ b/services/observer/notifier/models_test.go @@ -0,0 +1,146 @@ +package notifier + +import ( + "context" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "sort" + "testing" +) + +var ( + nativeTokenTransfer = blockatlas.Tx{ + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + }, + } + tokenTransfer = blockatlas.Tx{ + ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c4", + Coin: 60, + From: "0x08777CB1e80F45642752662B04886Df2d271E049", + To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + Fee: "52473000000000", + Date: 1585169424, + Block: 9742705, + Status: "completed", + Sequence: 149, + Type: "token_transfer", + Meta: blockatlas.TokenTransfer{ + Name: "Kyber Network Crystal", + Symbol: "KNC", + TokenID: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", + Decimals: 18, + Value: "100000000000000", + From: "0x08777CB1e80F45642752662B04886Df2d271E049", + To: "0x38d45371993eEc84f38FEDf93C646aA2D2267CEA", + }, + } + transfer = blockatlas.Tx{ + ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44556", + Coin: coin.BNB, + From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", + To: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", + Fee: "125000", + Date: 1555049867, + Block: 7761368, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.Transfer{ + Value: "10000000000000", + Decimals: 8, + Symbol: "BNB", + }, + } + utxoTransfer = blockatlas.Tx{ + ID: "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", + Coin: coin.BTC, + Inputs: []blockatlas.TxOutput{ + { + Address: "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", + Value: "1", + }, + { + Address: "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh", + Value: "1", + }, + { + Address: "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737", + Value: "1", + }, + }, + Outputs: []blockatlas.TxOutput{ + { + Address: "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", + Value: "3", + }, + }, + From: "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", + To: "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", + Fee: "125000", + Date: 1555117625, + Block: 592400, + Status: blockatlas.StatusCompleted, + Memo: "test", + Meta: blockatlas.Transfer{ + Value: "10000000000000", + Decimals: 8, + Symbol: "BNB", + }, + } +) + +func Test_containsAddress(t *testing.T) { + assert.True(t, containsAddress(tokenTransfer, "0x08777CB1e80F45642752662B04886Df2d271E049")) + assert.False(t, containsAddress(tokenTransfer, "0xdd974D5C2e2928deA5F71b9825b8b646686BD200")) + assert.True(t, containsAddress(tokenTransfer, "0x38d45371993eEc84f38FEDf93C646aA2D2267CEA")) + assert.False(t, containsAddress(tokenTransfer, "0xdd974D5C2e2928deA5F71b9825b8b646686BD200")) + + assert.True(t, containsAddress(transfer, "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2")) + assert.False(t, containsAddress(transfer, "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44556")) + assert.True(t, containsAddress(transfer, "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2")) + + assert.True(t, containsAddress(nativeTokenTransfer, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a")) + assert.False(t, containsAddress(nativeTokenTransfer, "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9")) + assert.True(t, containsAddress(nativeTokenTransfer, "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex")) + + assert.True(t, containsAddress(utxoTransfer, "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h")) + assert.False(t, containsAddress(utxoTransfer, "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh")) + assert.False(t, containsAddress(utxoTransfer, "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737")) + assert.False(t, containsAddress(utxoTransfer, "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC")) + assert.True(t, containsAddress(utxoTransfer, "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6")) +} + +func Test_findTransactionsByAddress(t *testing.T) { + res := findTransactionsByAddress([]blockatlas.Tx{nativeTokenTransfer, tokenTransfer}, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a") + sort.Slice(res, func(i, j int) bool { + return res[i].ID < res[j].ID + }) + assert.Equal(t, []blockatlas.Tx{nativeTokenTransfer}, res) + + resFail := findTransactionsByAddress([]blockatlas.Tx{nativeTokenTransfer, tokenTransfer}, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced") + assert.Equal(t, []blockatlas.Tx{}, resFail) +} + +func Test_buildNotificationsByAddress(t *testing.T) { + notifications := buildNotificationsByAddress("tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", []blockatlas.Tx{nativeTokenTransfer, tokenTransfer}, context.Background()) + sort.Slice(notifications, func(i, j int) bool { + return notifications[i].Action < notifications[j].Action + }) + nativeTokenTransfer.Direction = blockatlas.DirectionOutgoing + assert.Equal(t, nativeTokenTransfer, notifications[0].Result) +} diff --git a/services/observer/notifier/notifier.go b/services/observer/notifier/notifier.go deleted file mode 100644 index e1a01932c..000000000 --- a/services/observer/notifier/notifier.go +++ /dev/null @@ -1,140 +0,0 @@ -package notifier - -import ( - "context" - "encoding/json" - "github.com/streadway/amqp" - "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/pkg/numbers" - "go.elastic.co/apm" - "sync" - "time" -) - -const DefaultPushNotificationsBatchLimit = 50 - -var MaxPushNotificationsBatchLimit uint = DefaultPushNotificationsBatchLimit - -type TransactionNotification struct { - Action blockatlas.TransactionType `json:"action"` - Result *blockatlas.Tx `json:"result"` -} - -func RunNotifier(database *db.Instance, delivery amqp.Delivery) { - tx := apm.DefaultTracer.StartTransaction("RunNotifier", "app") - defer tx.End() - ctx := apm.ContextWithTransaction(context.Background(), tx) - defer func() { - if err := delivery.Ack(false); err != nil { - logger.Error(err) - } - }() - var txs blockatlas.Txs - if err := json.Unmarshal(delivery.Body, &txs); err != nil { - logger.Error(err) - return - } - if len(txs) == 0 { - return - } - - logger.Info("Consumed", logger.Params{"txs": len(txs), "coin": txs[0].Coin}) - - blockTransactions := txs.GetTransactionsMap() - if len(blockTransactions.Map) == 0 { - return - } - - addresses := blockTransactions.GetUniqueAddresses() - subscriptionsDataList, err := database.GetSubscriptions(txs[0].Coin, addresses, ctx) - if err != nil || len(subscriptionsDataList) == 0 { - return - } - - var wg sync.WaitGroup - wg.Add(len(subscriptionsDataList)) - for _, data := range subscriptionsDataList { - go buildAndPostMessage( - blockTransactions, - blockatlas.Subscription{Coin: data.Coin, Address: data.Address}, - &wg, ctx) - } - wg.Wait() -} - -func buildAndPostMessage(blockTransactions blockatlas.TxSetMap, sub blockatlas.Subscription, wg *sync.WaitGroup, ctx context.Context) { - defer wg.Done() - - span, ctx := apm.StartSpan(ctx, "buildAndPostMessage", "app") - defer span.End() - - tx, ok := blockTransactions.Map[sub.Address] - if !ok { - return - } - notifications := make([]TransactionNotification, 0, len(tx.Txs())) - for _, tx := range tx.Txs() { - tx.Direction = tx.GetTransactionDirection(sub.Address) - tx.InferUtxoValue(sub.Address, tx.Coin) - notification := TransactionNotification{ - Action: tx.Type, - Result: &tx, - } - - logger.Info("Notification ready", logger.Params{"coin": sub.Coin, "txID": tx.ID}) - - notifications = append(notifications, notification) - } - - batches := getNotificationBatches(notifications, MaxPushNotificationsBatchLimit, ctx) - - for _, batch := range batches { - publishNotificationBatch(batch, ctx) - } -} - -func publishNotificationBatch(batch []TransactionNotification, ctx context.Context) { - span, _ := apm.StartSpan(ctx, "getNotificationBatches", "app") - defer span.End() - raw, err := json.Marshal(batch) - if err != nil { - err = errors.E(err, " failed to dispatch event") - logger.Fatal(err) - } - - err = mq.TxNotifications.Publish(raw) - if err != nil { - err = errors.E(err, " failed to dispatch event") - logger.Fatal(err) - } - - logger.Info("Txs batch dispatched", logger.Params{"txs": len(batch)}) -} - -func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duration { - interval := time.Duration(value) * time.Millisecond - pMin := numbers.Max(minInterval.Nanoseconds(), interval.Nanoseconds()) - pMax := numbers.Min(int(maxInterval.Nanoseconds()), int(pMin)) - return time.Duration(pMax) -} - -func getNotificationBatches(notifications []TransactionNotification, sizeUint uint, ctx context.Context) [][]TransactionNotification { - span, _ := apm.StartSpan(ctx, "getNotificationBatches", "app") - defer span.End() - size := int(sizeUint) - resultLength := (len(notifications) + size - 1) / size - result := make([][]TransactionNotification, resultLength) - lo, hi := 0, size - for i := range result { - if hi > len(notifications) { - hi = len(notifications) - } - result[i] = notifications[lo:hi:hi] - lo, hi = hi, hi+size - } - return result -} diff --git a/services/observer/notifier/notifier_test.go b/services/observer/notifier/notifier_test.go deleted file mode 100644 index 882343ede..000000000 --- a/services/observer/notifier/notifier_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package notifier - -import ( - "github.com/stretchr/testify/assert" - "testing" - "time" -) - -func TestGetInterval(t *testing.T) { - min, _ := time.ParseDuration("2s") - max, _ := time.ParseDuration("30s") - type args struct { - blockTime int - minInterval time.Duration - maxInterval time.Duration - } - tests := []struct { - name string - args args - want time.Duration - }{ - { - "test minimum", - args{ - blockTime: 100, - minInterval: min, - maxInterval: max, - }, - min, - }, { - "test maximum", - args{ - blockTime: 600000, - minInterval: min, - maxInterval: max, - }, - max, - }, { - "test right blocktime", - args{ - blockTime: 5000, - minInterval: min, - maxInterval: max, - }, - 5000 * time.Millisecond, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := GetInterval(tt.args.blockTime, tt.args.minInterval, tt.args.maxInterval) - assert.EqualValues(t, tt.want, got) - }) - } -} diff --git a/services/observer/parser/parser.go b/services/observer/parser/parser.go index e5e103c2d..0e793c601 100644 --- a/services/observer/parser/parser.go +++ b/services/observer/parser/parser.go @@ -8,6 +8,7 @@ import ( "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/numbers" "go.elastic.co/apm" "strconv" "sync/atomic" @@ -61,6 +62,13 @@ func RunParser(params Params) { } } +func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duration { + interval := time.Duration(value) * time.Millisecond + pMin := numbers.Max(minInterval.Nanoseconds(), interval.Nanoseconds()) + pMax := numbers.Min(int(maxInterval.Nanoseconds()), int(pMin)) + return time.Duration(pMax) +} + func parse(params Params) { tx := apm.DefaultTracer.StartTransaction("parse", "app") ctx := apm.ContextWithTransaction(context.Background(), tx) diff --git a/services/observer/parser/parser_test.go b/services/observer/parser/parser_test.go index a6e87a394..e4a8e78d4 100644 --- a/services/observer/parser/parser_test.go +++ b/services/observer/parser/parser_test.go @@ -174,3 +174,50 @@ func TestGetTxBatches(t *testing.T) { batches = getTxsBatches(txs, 5000, context.Background()) assert.Len(t, batches, 200) } + +func TestGetInterval(t *testing.T) { + min, _ := time.ParseDuration("2s") + max, _ := time.ParseDuration("30s") + type args struct { + blockTime int + minInterval time.Duration + maxInterval time.Duration + } + tests := []struct { + name string + args args + want time.Duration + }{ + { + "test minimum", + args{ + blockTime: 100, + minInterval: min, + maxInterval: max, + }, + min, + }, { + "test maximum", + args{ + blockTime: 600000, + minInterval: min, + maxInterval: max, + }, + max, + }, { + "test right blocktime", + args{ + blockTime: 5000, + minInterval: min, + maxInterval: max, + }, + 5000 * time.Millisecond, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := GetInterval(tt.args.blockTime, tt.args.minInterval, tt.args.maxInterval) + assert.EqualValues(t, tt.want, got) + }) + } +} diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index d859ab1ea..031d424a3 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -121,7 +121,7 @@ func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel assert.Equal(t, notifier.TransactionNotification{ Action: blockatlas.TxNativeTokenTransfer, - Result: &blockatlas.Tx{ + Result: blockatlas.Tx{ Type: blockatlas.TxNativeTokenTransfer, Direction: "incoming", ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", @@ -147,7 +147,7 @@ func setupParserFull(stopChan chan<- struct{}) parser.Params { maxTime := time.Second * 2 maxBatchBlocksAmount := 1 - pollInterval := notifier.GetInterval(0, minTime, maxTime) + pollInterval := parser.GetInterval(0, minTime, maxTime) backlogCount := 1 diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index dda305226..1f64e5de6 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -82,7 +82,7 @@ func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { assert.Equal(t, notifier.TransactionNotification{ Action: blockatlas.TxNativeTokenTransfer, - Result: &blockatlas.Tx{ + Result: blockatlas.Tx{ Type: blockatlas.TxNativeTokenTransfer, Direction: "outgoing", ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", diff --git a/tests/integration/observer_test/parser_test.go b/tests/integration/observer_test/parser_test.go index a4f9a2979..1c5d6b714 100644 --- a/tests/integration/observer_test/parser_test.go +++ b/tests/integration/observer_test/parser_test.go @@ -11,7 +11,6 @@ import ( "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/services/observer/notifier" "github.com/trustwallet/blockatlas/services/observer/parser" "github.com/trustwallet/blockatlas/tests/integration/setup" "testing" @@ -105,7 +104,7 @@ func setupParser(stopChan chan struct{}) parser.Params { maxTime := time.Second * 2 maxBatchBlocksAmount := 100 - pollInterval := notifier.GetInterval(0, minTime, maxTime) + pollInterval := parser.GetInterval(0, minTime, maxTime) backlogCount := 50 From 57ee82f1aee3acf324b06912f80515a1793ba6de Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Fri, 29 May 2020 22:29:47 +0300 Subject: [PATCH 312/506] Add additional check for txs len at notifier --- services/observer/notifier/base.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/observer/notifier/base.go b/services/observer/notifier/base.go index 2e56ae461..082c154ed 100644 --- a/services/observer/notifier/base.go +++ b/services/observer/notifier/base.go @@ -36,6 +36,9 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { addresses := toUniqueAddresses(allAddresses) + if len(txs) < 1 { + return + } subscriptionsDataList, err := database.GetSubscriptions(txs[0].Coin, addresses, ctx) if err != nil || len(subscriptionsDataList) == 0 { return From 1f14d1954bfc52cda9e9f80a3004ec112e55451c Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Thu, 4 Jun 2020 10:08:44 +0300 Subject: [PATCH 313/506] Filter all token transaction by token (#1130) --- api/endpoint/transaction.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 78136f8a4..df51ac233 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -6,6 +6,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "net/http" + "strings" ) // @Summary Get Transactions @@ -70,6 +71,11 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b tx.Direction = tx.GetTransactionDirection(address) page = append(page, tx) } + + if token != "" { + page = filterTransactionsByToken(token, page) + } + if len(page) > blockatlas.TxPerPage { page = page[0:blockatlas.TxPerPage] } @@ -124,3 +130,18 @@ func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { } c.JSON(http.StatusOK, &page) } + +func filterTransactionsByToken(token string, txs blockatlas.TxPage) blockatlas.TxPage { + result := make(blockatlas.TxPage, 0) + for _, tx := range txs { + switch tx.Meta.(type) { + case *blockatlas.TokenTransfer, blockatlas.TokenTransfer: + if strings.EqualFold(tx.Meta.(blockatlas.TokenTransfer).TokenID, token) { + result = append(result, tx) + } + default: + continue + } + } + return result +} From 3cf3b6276429bdaa7a125d3336a4637013330150 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Thu, 4 Jun 2020 10:15:59 +0300 Subject: [PATCH 314/506] Sort staking delegations in inc. order (#1131) --- api/endpoint/staking.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index c5c9a7104..94e5240e4 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -8,6 +8,8 @@ import ( "github.com/trustwallet/blockatlas/pkg/errors" services "github.com/trustwallet/blockatlas/services/assets" "net/http" + "sort" + "strconv" "strings" ) @@ -60,6 +62,7 @@ func GetStakeDelegationsWithAllInfoForBatch(c *gin.Context, apis map[string]bloc if err != nil { continue } + delegation.Delegations = sortDelegations(delegation.Delegations) batch = append(batch, delegation) } c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &batch}) @@ -178,6 +181,7 @@ func GetStakingDelegationsForSpecificCoin(c *gin.Context, api blockatlas.StakeAP c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) return } + result.Delegations = sortDelegations(result.Delegations) c.JSON(http.StatusOK, &result) } @@ -212,3 +216,18 @@ func getStakingResponse(api blockatlas.StakeAPI) blockatlas.StakingResponse { Details: api.GetDetails(), } } + +func sortDelegations(delegations blockatlas.DelegationsPage) blockatlas.DelegationsPage { + sort.Slice(delegations, func(i, j int) bool { + iA, err := strconv.Atoi(delegations[i].Value) + if err != nil { + return false + } + jA, err := strconv.Atoi(delegations[j].Value) + if err != nil { + return false + } + return iA > jA + }) + return delegations +} From 0ae4f086c765e1663751be2eb8071873aa4e9bef Mon Sep 17 00:00:00 2001 From: hewig <360470+hewigovens@users.noreply.github.com> Date: Thu, 4 Jun 2020 16:48:35 +0800 Subject: [PATCH 315/506] Update swagger files and readme (#1128) * update swagger and readme * keep v1 --- README.md | 21 +++++++++++++++------ api/endpoint/transaction.go | 13 ++++++++----- docs/docs.go | 4 ++-- docs/swagger.json | 2 +- docs/swagger.yaml | 2 +- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 83af69774..909598b24 100644 --- a/README.md +++ b/README.md @@ -206,16 +206,25 @@ Therefore mocked API-level tests are used, whereby external APIs are replaced by Swagger API docs provided at path `/swagger/index.html` -#### Updating Docs +or you can install `go-swagger` and render it locally (macOS example) -- After creating a new route, add comments to your API source code, [See Declarative Comments Format](https://swaggo.github.io/swaggo.io/declarative_comments_format/). -- Download Swag for Go by using: +Install: + +```shell +brew tap go-swagger/go-swagger +brew install go-swagger +``` - `$ go get -u github.com/swaggo/swag/cmd/swag` +Render: +```shell +swagger serve docs/swagger.yaml +``` -- Run the Swag in your Go project root folder. +#### Updating Docs + +- After creating a new route, add comments to your API source code, [See Declarative Comments Format](https://swaggo.github.io/swaggo.io/declarative_comments_format/). - `$ swag init -g ./cmd/platform_api/main.go -o ./docs` +- Run `$ make go-gen-docs` in root folder. ## Contributing diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index df51ac233..792af4775 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -1,16 +1,17 @@ package endpoint import ( + "net/http" + "strings" + "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/api/model" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" - "net/http" - "strings" ) // @Summary Get Transactions -// @ID tx_v1 +// @ID tx_v2 // @Description Get transactions from the address // @Accept json // @Produce json @@ -19,6 +20,7 @@ import ( // @Param address path string true "the query address" default(tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q) // @Failure 500 {object} model.ErrorResponse // @Router /v1/{coin}/{address} [get] +// @Router /v2/{coin}/transactions/{address} [get] func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI blockatlas.TokenTxAPI) { address := c.Param("address") if address == "" { @@ -83,7 +85,7 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b } // @Summary Get Transactions by XPUB -// @ID txxpub_v1 +// @ID tx_xpub_v2 // @Description Get transactions from XPUB address // @Accept json // @Produce json @@ -91,7 +93,8 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b // @Param coin path string true "the coin name" default(bitcoin) // @Param xpub path string true "the xpub key" default(zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC) // @Failure 500 {object} model.ErrorResponse -// @Router /v1/{coin}/xpub/{xpub} [get] +// @Router /v1/{coin}/{address} [get] +// @Router /v2/{coin}/transactions/xpub/{xpub} [get] func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { xPubKey := c.Param("xpub") if xPubKey == "" { diff --git a/docs/docs.go b/docs/docs.go index 45ca2468c..8cdd7368b 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-05-05 16:09:19.422499 +0300 MSK m=+0.199865137 +// 2020-06-03 12:57:01.548632 +0800 CST m=+0.074416980 package docs @@ -594,7 +594,7 @@ var doc = `{ "Transactions" ], "summary": "Get Transactions by XPUB", - "operationId": "txxpub_v2", + "operationId": "tx_xpub_v2", "parameters": [ { "type": "string", diff --git a/docs/swagger.json b/docs/swagger.json index 9689467c0..9391ffd55 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -573,7 +573,7 @@ "Transactions" ], "summary": "Get Transactions by XPUB", - "operationId": "txxpub_v2", + "operationId": "tx_xpub_v2", "parameters": [ { "type": "string", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 986373a42..8e6198cff 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -652,7 +652,7 @@ paths: consumes: - application/json description: Get transactions from XPUB address - operationId: txxpub_v2 + operationId: tx_xpub_v2 parameters: - default: bitcoin description: the coin name From 3dc74e0df7d09fe29ecd1f938a049f3a8c02de44 Mon Sep 17 00:00:00 2001 From: Nick Kozlov Date: Sat, 6 Jun 2020 01:01:11 +0300 Subject: [PATCH 316/506] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 909598b24..5bd0953fb 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ ![CI](https://github.com/trustwallet/blockatlas/workflows/CI/badge.svg) [![codecov](https://codecov.io/gh/trustwallet/blockatlas/branch/master/graph/badge.svg)](https://codecov.io/gh/trustwallet/blockatlas) [![Go Report Card](https://goreportcard.com/badge/trustwallet/blockatlas)](https://goreportcard.com/report/TrustWallet/blockatlas) +[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=trustwallet/blockatlas)](https://dependabot.com) + > BlockAtlas is a clean explorer API and transaction observer for cryptocurrencies. From c1bc33b9e6ab2d91d85302ab397eba40ff7cbbf7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 01:05:01 +0300 Subject: [PATCH 317/506] Bump github.com/swaggo/swag from 1.6.5 to 1.6.7 (#1133) Bumps [github.com/swaggo/swag](https://github.com/swaggo/swag) from 1.6.5 to 1.6.7. - [Release notes](https://github.com/swaggo/swag/releases) - [Changelog](https://github.com/swaggo/swag/blob/master/.goreleaser.yml) - [Commits](https://github.com/swaggo/swag/compare/v1.6.5...v1.6.7) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Nick Kozlov --- go.mod | 2 +- go.sum | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 443ac6020..83926417c 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 github.com/stretchr/testify v1.5.1 github.com/swaggo/gin-swagger v1.2.0 - github.com/swaggo/swag v1.6.5 + github.com/swaggo/swag v1.6.7 github.com/trustwallet/ens-coincodec v1.0.5 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 diff --git a/go.sum b/go.sum index 4d2b75351..c365212cc 100644 --- a/go.sum +++ b/go.sum @@ -419,6 +419,8 @@ github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.6.5 h1:2C+t+xyK6p1sujqncYO/VnMvPZcBJjNdKKyxbOdAW8o= github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= +github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= +github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/ens-coincodec v1.0.5 h1:rdebDQYHqNjv+yUdtMf3DXyMgJpEJSI2DSbC1GUFuyk= github.com/trustwallet/ens-coincodec v1.0.5/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= @@ -432,6 +434,7 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= From c656c235fc4e1a4dd994db4489f3cb89eed8d8f1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 01:09:31 +0300 Subject: [PATCH 318/506] Bump github.com/mitchellh/mapstructure from 1.3.0 to 1.3.1 (#1134) Bumps [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) from 1.3.0 to 1.3.1. - [Release notes](https://github.com/mitchellh/mapstructure/releases) - [Changelog](https://github.com/mitchellh/mapstructure/blob/master/CHANGELOG.md) - [Commits](https://github.com/mitchellh/mapstructure/compare/v1.3.0...v1.3.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Nick Kozlov --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 83926417c..f734b168c 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/golang/protobuf v1.4.2 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/jinzhu/gorm v1.9.12 - github.com/mitchellh/mapstructure v1.3.0 + github.com/mitchellh/mapstructure v1.3.1 github.com/mr-tron/base58 v1.1.3 github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v0.1.1 // indirect diff --git a/go.sum b/go.sum index c365212cc..66d10a27a 100644 --- a/go.sum +++ b/go.sum @@ -300,6 +300,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.0 h1:iDwIio/3gk2QtLLEsqU5lInaMzos0hDTz8a6lazSFVw= github.com/mitchellh/mapstructure v1.3.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA= +github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= From 90f7bc1698d043df469f23170dc96feb5d39ca10 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 01:13:30 +0300 Subject: [PATCH 319/506] Bump github.com/stretchr/testify from 1.5.1 to 1.6.1 (#1135) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.5.1 to 1.6.1. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.5.1...v1.6.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Nick Kozlov --- go.mod | 2 +- go.sum | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f734b168c..160fb9804 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sirupsen/logrus v1.6.0 github.com/spf13/viper v1.7.0 github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 - github.com/stretchr/testify v1.5.1 + github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 github.com/trustwallet/ens-coincodec v1.0.5 diff --git a/go.sum b/go.sum index 66d10a27a..da2ce458d 100644 --- a/go.sum +++ b/go.sum @@ -407,12 +407,15 @@ github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5 github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= @@ -662,6 +665,8 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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= 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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From dc5b1ee7348a4ca7bea90a66895129bca837a20a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2020 01:19:50 +0300 Subject: [PATCH 320/506] Bump github.com/mr-tron/base58 from 1.1.3 to 1.2.0 (#1136) Bumps [github.com/mr-tron/base58](https://github.com/mr-tron/base58) from 1.1.3 to 1.2.0. - [Release notes](https://github.com/mr-tron/base58/releases) - [Commits](https://github.com/mr-tron/base58/compare/v1.1.3...v1.2.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Nick Kozlov --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 160fb9804..162d77a52 100644 --- a/go.mod +++ b/go.mod @@ -21,8 +21,8 @@ require ( github.com/golang/protobuf v1.4.2 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/jinzhu/gorm v1.9.12 + github.com/mr-tron/base58 v1.2.0 github.com/mitchellh/mapstructure v1.3.1 - github.com/mr-tron/base58 v1.1.3 github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v0.1.1 // indirect github.com/ory/dockertest v3.3.5+incompatible diff --git a/go.sum b/go.sum index da2ce458d..37a12f6d0 100644 --- a/go.sum +++ b/go.sum @@ -310,6 +310,8 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= From 7cdf22d43e074ce2ac9c6ef68f19eaa05afd98cc Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Sat, 6 Jun 2020 00:31:31 +0200 Subject: [PATCH 321/506] Refactor Naming provider: logic to select provider (#1132) * Refactor Naming provider: logic to select provider based on name is in the providers. * Move GetTLD to pkg, adjust test. * Lint fix. * Add tests, some renames. * Review comments. * Cleanup. * Remove comments. * Some renames, review comments. * Rename ToLower(), simplify test. * Move to pkg/naming from address. * Rename CanHandle <-- Match. * Change list of domains to Set type. * Move ToLower inside GetTopDomain(). * Rename. * Remove idiotic alias * Add unit test to services/domain. * Replace set lookup with switch. * Lint fix. Co-authored-by: Catenocrypt Co-authored-by: Nick Kozlov --- pkg/blockatlas/platform.go | 3 +- pkg/naming/naming.go | 14 ++++++ pkg/naming/naming_test.go | 31 ++++++++++++ platform/ethereum/domain.go | 27 +++++++--- platform/ethereum/domain_test.go | 31 ++++++++++++ platform/fio/domain.go | 20 ++++++++ platform/fio/domain_test.go | 32 ++++++++++++ platform/platform.go | 16 ++---- platform/zilliqa/domain.go | 19 +++++-- platform/zilliqa/domain_test.go | 29 +++++++++++ services/domains/domains.go | 70 +++++++------------------- services/domains/domains_test.go | 85 +++++++++++++++++++++++--------- 12 files changed, 278 insertions(+), 99 deletions(-) create mode 100644 pkg/naming/naming.go create mode 100644 pkg/naming/naming_test.go create mode 100644 platform/ethereum/domain_test.go create mode 100644 platform/fio/domain_test.go create mode 100644 platform/zilliqa/domain_test.go diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 1ddf2c9e9..177de17ab 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -59,9 +59,8 @@ type ( GetCollectiblesV3(owner, collectibleID string) (CollectiblePageV3, error) } - // NamingServiceAPI provides public name service domains HTTP routes NamingServiceAPI interface { - Platform + CanHandle(name string) bool Lookup(coins []uint64, name string) ([]Resolved, error) } diff --git a/pkg/naming/naming.go b/pkg/naming/naming.go new file mode 100644 index 000000000..63c47aabb --- /dev/null +++ b/pkg/naming/naming.go @@ -0,0 +1,14 @@ +package naming + +import ( + "strings" +) + +func GetTopDomain(name, separator string) string { + lastIdx := strings.LastIndex(name, separator) + if lastIdx < 0 || lastIdx >= len(name)-1 { + return "" + } + // return tail including separator + return strings.ToLower(name[lastIdx:]) +} diff --git a/pkg/naming/naming_test.go b/pkg/naming/naming_test.go new file mode 100644 index 000000000..c8de70705 --- /dev/null +++ b/pkg/naming/naming_test.go @@ -0,0 +1,31 @@ +package naming + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetTopDomain(t *testing.T) { + tests := []struct { + name, separator, wantTLD string + }{ + {"vitalik.eth", ".", ".eth"}, + {"vitalik.ETH", ".", ".eth"}, + {"vitalik.ens", ".", ".ens"}, + {"ourxyzwallet.xyz", ".", ".xyz"}, + {"Cameron.Kred", ".", ".kred"}, + {"btc.zil", ".", ".zil"}, + {"btc.crypto", ".", ".crypto"}, + {"nick@fiotestnet", "@", "@fiotestnet"}, + {"a", ".", ""}, + {"a.", ".", ""}, + {"a.b", ".", ".b"}, + {"a@b.c", ".", ".c"}, + {"a@b.c", "@", "@b.c"}, + } + for _, tt := range tests { + result := GetTopDomain(tt.name, tt.separator) + assert.Equal(t, tt.wantTLD, result) + } +} diff --git a/platform/ethereum/domain.go b/platform/ethereum/domain.go index c7ebeaedd..faa9f57d9 100644 --- a/platform/ethereum/domain.go +++ b/platform/ethereum/domain.go @@ -1,14 +1,29 @@ package ethereum import ( - CoinType "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/pkg/naming" "github.com/trustwallet/blockatlas/platform/ethereum/ens" - AddressEncoder "github.com/trustwallet/ens-coincodec" + "github.com/trustwallet/ens-coincodec" ) +func (p *Platform) CanHandle(name string) bool { + switch naming.GetTopDomain(name, ".") { + case ".eth": + return true + case ".xyz": + return true + case ".luxe": + return true + case ".kred": + return true + } + return false +} + func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { var result []blockatlas.Resolved node, err := ens.NameHash(name) @@ -32,10 +47,10 @@ func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, e return result, nil } -func (p *Platform) addressForCoin(resovler string, node []byte, coin uint64) (string, error) { - result, err := p.ens.Addr(resovler, node, coin) +func (p *Platform) addressForCoin(resovler string, node []byte, coinID uint64) (string, error) { + result, err := p.ens.Addr(resovler, node, coinID) if err != nil { - if coin == CoinType.ETH { + if coinID == coin.ETH { // user may not set multi coin address result, err := p.lookupLegacyETH(resovler, node) if err != nil { @@ -45,7 +60,7 @@ func (p *Platform) addressForCoin(resovler string, node []byte, coin uint64) (st } return "", errors.E(err, "query multi coin address failed") } - encoded, err := AddressEncoder.ToString(result, uint32(coin)) + encoded, err := coincodec.ToString(result, uint32(coinID)) if err != nil { return "", errors.E(err, "encode to address failed") } diff --git a/platform/ethereum/domain_test.go b/platform/ethereum/domain_test.go new file mode 100644 index 000000000..3bddce29b --- /dev/null +++ b/platform/ethereum/domain_test.go @@ -0,0 +1,31 @@ +package ethereum + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCanHandle(t *testing.T) { + tests := []struct { + name string + want bool + }{ + {"vitalik.eth", true}, + {"vitalik.xyz", true}, + {"vitalik.luxe", true}, + {"vitalik.kred", true}, + {"vitalik.ETH", true}, + {"vitalik.Eth", true}, + {"vitalik.wrongdomain", false}, + {"v.eth", true}, + {".eth", true}, + {"vitalik", false}, + {"vitalik.", false}, + } + p := Init(0, "", "") + for _, tt := range tests { + res := p.CanHandle(tt.name) + assert.Equal(t, tt.want, res) + } +} diff --git a/platform/fio/domain.go b/platform/fio/domain.go index 4da1846b6..ccb7fef09 100644 --- a/platform/fio/domain.go +++ b/platform/fio/domain.go @@ -3,8 +3,28 @@ package fio import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/naming" ) +func (p *Platform) CanHandle(name string) bool { + domain := naming.GetTopDomain(name, "@") + if len(domain) == 0 { + return false + } + switch domain { + case "@trust": + return true + case "@trustwallet": + return true + case "@binance": + return true + case "@fiomembers": + return true + } + // we match any @xxx domain! + return len(domain) >= 2 +} + func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { var result []blockatlas.Resolved for _, coinId := range coins { diff --git a/platform/fio/domain_test.go b/platform/fio/domain_test.go new file mode 100644 index 000000000..4681f844c --- /dev/null +++ b/platform/fio/domain_test.go @@ -0,0 +1,32 @@ +package fio + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCanHandle(t *testing.T) { + tests := []struct { + name string + want bool + }{ + {"vitalik@trust", true}, + {"vitalik@trustwallet", true}, + {"vitalik@binance", true}, + {"vitalik@fiomembers", true}, + {"vitalik@TRUST", true}, + {"vitalik@Trust", true}, + {"vitalik@somedomain", true}, + {"vitalik@x", true}, + {"v@trust", true}, + {"@trust", true}, + {"vitalik", false}, + {"vitalik@", false}, + } + p := Init("") + for _, tt := range tests { + res := p.CanHandle(tt.name) + assert.Equal(t, tt.want, res) + } +} diff --git a/platform/platform.go b/platform/platform.go index b85fe7b7b..2e4eefcc2 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -112,21 +112,15 @@ func getAllHandlers() blockatlas.Platforms { } func getCollectionsHandlers() blockatlas.CollectionsAPIs { - return blockatlas.CollectionsAPIs { + return blockatlas.CollectionsAPIs{ coin.ETH: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), } } func getNamingHandlers() map[uint]blockatlas.NamingServiceAPI { - return map[uint]blockatlas.NamingServiceAPI { - coin.ETH: ethereum.Init(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH)), - coin.CLO: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO)), - coin.TOMO: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), - coin.GO: ethereum.Init(coin.GO, GetApiVar(coin.GO), GetRpcVar(coin.GO)), - coin.ETC: ethereum.Init(coin.ETC, GetApiVar(coin.ETC), GetRpcVar(coin.ETC)), - coin.POA: ethereum.Init(coin.POA, GetApiVar(coin.POA), GetRpcVar(coin.POA)), - coin.TT: ethereum.Init(coin.TT, GetApiVar(coin.TT), GetRpcVar(coin.TT)), - coin.FIO: fio.Init(GetApiVar(coin.FIO)), - coin.ZIL: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL), GetVar("zilliqa.lookup")), + return map[uint]blockatlas.NamingServiceAPI{ + coin.ETH: ethereum.Init(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH)), + coin.FIO: fio.Init(GetApiVar(coin.FIO)), + coin.ZIL: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL), GetVar("zilliqa.lookup")), } } diff --git a/platform/zilliqa/domain.go b/platform/zilliqa/domain.go index d31cd3e54..0cf297103 100644 --- a/platform/zilliqa/domain.go +++ b/platform/zilliqa/domain.go @@ -1,27 +1,38 @@ package zilliqa import ( - CoinType "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/naming" ) type ZNSResponse struct { Addresses map[string]string } +func (p *Platform) CanHandle(name string) bool { + switch naming.GetTopDomain(name, ".") { + case ".zil": + return true + case ".crypto": + return true + } + return false +} + func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { var result []blockatlas.Resolved resp, err := p.udClient.LookupName(name) if err != nil { return result, err } - for _, coin := range coins { - symbol := CoinType.Coins[uint(coin)].Symbol + for _, c := range coins { + symbol := coin.Coins[uint(c)].Symbol address := resp.Addresses[symbol] if len(address) == 0 { continue } - result = append(result, blockatlas.Resolved{Coin: coin, Result: address}) + result = append(result, blockatlas.Resolved{Coin: c, Result: address}) } return result, nil } diff --git a/platform/zilliqa/domain_test.go b/platform/zilliqa/domain_test.go new file mode 100644 index 000000000..7ce4a3dab --- /dev/null +++ b/platform/zilliqa/domain_test.go @@ -0,0 +1,29 @@ +package zilliqa + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCanHandle(t *testing.T) { + tests := []struct { + name string + want bool + }{ + {"vitalik.zil", true}, + {"vitalik.crypto", true}, + {"vitalik.ZIL", true}, + {"vitalik.Zil", true}, + {"vitalik.wrongdomain", false}, + {"v.zil", true}, + {".zil", true}, + {"vitalik", false}, + {"vitalik.", false}, + } + p := Init("", "", "", "") + for _, tt := range tests { + res := p.CanHandle(tt.name) + assert.Equal(t, tt.want, res) + } +} diff --git a/services/domains/domains.go b/services/domains/domains.go index 38dfe642f..5421d2818 100644 --- a/services/domains/domains.go +++ b/services/domains/domains.go @@ -1,69 +1,33 @@ package domains import ( - "math" - "strings" - - CoinType "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/platform" ) -// TLDMapping Mapping of name TLD's to coin where they are handled -var TLDMapping = map[string]uint{ - ".eth": CoinType.ETH, - ".xyz": CoinType.ETH, - ".luxe": CoinType.ETH, - ".kred": CoinType.ETH, - ".zil": CoinType.ZIL, - ".crypto": CoinType.ZIL, - "@trust": CoinType.FIO, - "@trustwallet": CoinType.FIO, - "@binance": CoinType.FIO, - "@fiomembers": CoinType.FIO, - "@": CoinType.FIO, // any FIO domain -} - func HandleLookup(name string, coins []uint64) ([]blockatlas.Resolved, error) { - // Assumption: format of the name can be decided (top-level-domain), and at most one naming service is tried - name = strings.ToLower(name) - tld, err := getTLD(name) - if err != nil { - return nil, errors.E(err, "name format not recognized", errors.Params{"name": name, "coins": coins}) - } - id, ok := TLDMapping[tld] - if !ok { - // special handling for FIO, any fio domain - if len(tld) >= 2 && tld[0] == '@' { - tld = string("@") - id, ok = TLDMapping[tld] - if !ok { - return nil, errors.E("name not found", errors.Params{"name": name, "coins": coins, "tld": tld}) - } - } - } - api, ok := platform.NamingAPIs[id] - if !ok { + addresses := make([]blockatlas.Resolved, 0) + apis := findHandlerApis(name, platform.NamingAPIs) + if len(apis) == 0 { return nil, errors.E("platform not found", errors.Params{"name": name, "coins": coins}) } - result, err := api.Lookup(coins, name) - if err != nil { - return nil, errors.E(err, "name format not recognized", errors.Params{"name": name, "coins": coins}) + for _, api := range apis { + provAddresses, err := api.Lookup(coins, name) + if err != nil { + return nil, errors.E(err, "name format not recognized", errors.Params{"name": name, "coins": coins}) + } + addresses = append(addresses, provAddresses...) } - return result, nil + return addresses, nil } -// Obtain tld from then name, e.g. ".ens" from "nick.ens" -func getTLD(name string) (tld string, error error) { - // find last separator - lastSeparatorIdx := int(math.Max( - float64(strings.LastIndex(name, ".")), - float64(strings.LastIndex(name, "@")))) - if lastSeparatorIdx <= -1 || lastSeparatorIdx >= len(name)-1 { - // no separator inside string - return "", errors.E("No TLD found in name", errors.Params{"name": name}) +func findHandlerApis(name string, allApis map[uint]blockatlas.NamingServiceAPI) []blockatlas.NamingServiceAPI { + apis := []blockatlas.NamingServiceAPI{} + for _, api := range allApis { + if api.CanHandle(name) { + apis = append(apis, api) + } } - // return tail including separator - return name[lastSeparatorIdx:], nil + return apis } diff --git a/services/domains/domains_test.go b/services/domains/domains_test.go index 9786527f8..8539e5d0a 100644 --- a/services/domains/domains_test.go +++ b/services/domains/domains_test.go @@ -1,34 +1,73 @@ package domains import ( - "strings" "testing" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/naming" ) -func checkGetTLD(t *testing.T, name string, expectedTLD string, expectedError error) { - name = strings.ToLower(name) - tld, err := getTLD(name) - assert.Equal(t, expectedTLD, tld) - if expectedError == nil { - assert.Nil(t, err) - } else { - assert.NotNil(t, err) +type ( + ProviderOne struct{} + ProviderTwo struct{} +) + +func (p *ProviderOne) CanHandle(name string) bool { + domain := naming.GetTopDomain(name, ".") + return domain == ".one" || domain == ".zero" +} + +func (p *ProviderOne) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { + return []blockatlas.Resolved{}, nil +} + +func (p *ProviderTwo) CanHandle(name string) bool { + domain := naming.GetTopDomain(name, ".") + return domain == ".two" || domain == ".zero" +} + +func (p *ProviderTwo) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { + return []blockatlas.Resolved{}, nil +} + +func setupProviders() map[uint]blockatlas.NamingServiceAPI { + return map[uint]blockatlas.NamingServiceAPI{ + 1: &ProviderOne{}, + 2: &ProviderTwo{}, } } -func Test_getTLD(t *testing.T) { - checkGetTLD(t, "vitalik.eth", ".eth", nil) - checkGetTLD(t, "vitalik.ens", ".ens", nil) - checkGetTLD(t, "ourxyzwallet.xyz", ".xyz", nil) - checkGetTLD(t, "Cameron.Kred", ".kred", nil) - checkGetTLD(t, "btc.zil", ".zil", nil) - checkGetTLD(t, "btc.crypto", ".crypto", nil) - checkGetTLD(t, "nick@fiotestnet", "@fiotestnet", nil) - checkGetTLD(t, "a", "", errors.E("No TLD found in name")) // no tld - checkGetTLD(t, "a.", "", errors.E("No TLD found in name")) // empty tld - checkGetTLD(t, "a@b.c", ".c", nil) - checkGetTLD(t, "a.b@c", "@c", nil) +func TestFindHandlerApis(t *testing.T) { + tests := []struct { + name string + wantCount int + }{ + { + name: "user.one", + wantCount: 1, + }, + { + name: "user.two", + wantCount: 1, + }, + { + name: "user.NOSUCHDOMAIN", + wantCount: 0, + }, + { + name: "user.zero", + wantCount: 2, + }, + { + name: "user.ONE", + wantCount: 1, + }, + } + allApis := setupProviders() + for _, tt := range tests { + res := findHandlerApis(tt.name, allApis) + if len(res) != tt.wantCount { + t.Errorf("Wrong answer %v %v %v", tt.name, len(res), tt.wantCount) + } + } } From 16c483f237258e8311cfe3f4030c178822b6fa2d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2020 12:03:53 +0300 Subject: [PATCH 322/506] Bump github.com/mitchellh/mapstructure from 1.3.1 to 1.3.2 (#1137) Bumps [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) from 1.3.1 to 1.3.2. - [Release notes](https://github.com/mitchellh/mapstructure/releases) - [Changelog](https://github.com/mitchellh/mapstructure/blob/master/CHANGELOG.md) - [Commits](https://github.com/mitchellh/mapstructure/compare/v1.3.1...v1.3.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 162d77a52..04ec4f71d 100644 --- a/go.mod +++ b/go.mod @@ -21,8 +21,8 @@ require ( github.com/golang/protobuf v1.4.2 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/jinzhu/gorm v1.9.12 + github.com/mitchellh/mapstructure v1.3.2 github.com/mr-tron/base58 v1.2.0 - github.com/mitchellh/mapstructure v1.3.1 github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v0.1.1 // indirect github.com/ory/dockertest v3.3.5+incompatible diff --git a/go.sum b/go.sum index 37a12f6d0..55fcfdec1 100644 --- a/go.sum +++ b/go.sum @@ -302,6 +302,8 @@ github.com/mitchellh/mapstructure v1.3.0 h1:iDwIio/3gk2QtLLEsqU5lInaMzos0hDTz8a6 github.com/mitchellh/mapstructure v1.3.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA= github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= From 893cf60408d67e85bb7b51af5ceadd6c0c3f8d94 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 9 Jun 2020 02:22:12 -0700 Subject: [PATCH 323/506] Run go mod tidy (#1138) --- go.sum | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/go.sum b/go.sum index 55fcfdec1..14ce4b61b 100644 --- a/go.sum +++ b/go.sum @@ -298,10 +298,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.0 h1:iDwIio/3gk2QtLLEsqU5lInaMzos0hDTz8a6lazSFVw= -github.com/mitchellh/mapstructure v1.3.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA= -github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -310,8 +306,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -416,8 +410,6 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= @@ -426,8 +418,6 @@ github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuI github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= -github.com/swaggo/swag v1.6.5 h1:2C+t+xyK6p1sujqncYO/VnMvPZcBJjNdKKyxbOdAW8o= -github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -442,7 +432,6 @@ github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2t github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= From 8dd152187225ff5229414c6a4162ec149578c627 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Tue, 9 Jun 2020 13:17:32 +0300 Subject: [PATCH 324/506] Update swagger, remove all old endpoints --- docs/docs.go | 502 +--------------------------------------------- docs/swagger.json | 500 --------------------------------------------- docs/swagger.yaml | 341 ------------------------------- 3 files changed, 1 insertion(+), 1342 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 8cdd7368b..a066c814e 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-06-03 12:57:01.548632 +0800 CST m=+0.074416980 +// 2020-06-09 13:15:24.760729 +0300 MSK m=+0.130569342 package docs @@ -67,233 +67,6 @@ var doc = `{ } } }, - "/v1/market/charts": { - "get": { - "description": "Get the charts data from an market and coin/token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get charts data for a specific coin", - "operationId": "get_charts_data", - "parameters": [ - { - "type": "integer", - "default": 60, - "description": "Coin ID", - "name": "coin", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Token ID", - "name": "token", - "in": "query" - }, - { - "type": "integer", - "default": 1574483028, - "description": "Start timestamp", - "name": "time_start", - "in": "query" - }, - { - "type": "integer", - "default": 64, - "description": "Max number of items in result prices array", - "name": "max_items", - "in": "query" - }, - { - "type": "string", - "default": "USD", - "description": "The currency to show charts", - "name": "currency", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/endpoint.ChartData" - } - } - } - } - }, - "/v1/market/info": { - "get": { - "description": "Get the charts coin info data from an market and coin/contract", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get charts coin info data for a specific coin", - "operationId": "get_charts_coin_info", - "parameters": [ - { - "type": "integer", - "default": 60, - "description": "Coin ID", - "name": "coin", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Token ID", - "name": "token", - "in": "query" - }, - { - "type": "string", - "default": "USD", - "description": "The currency to show coin info in", - "name": "currency", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/endpoint.ChartCoinInfo" - } - } - } - } - }, - "/v1/market/ticker": { - "post": { - "description": "Get the ticker values from many market and coin/token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get ticker values for a specific market", - "operationId": "get_tickers", - "parameters": [ - { - "description": "Ticker", - "name": "tickers", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/endpoint.TickerRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/endpoint.Tickers" - } - } - } - } - }, - "/v1/{coin}/xpub/{xpub}": { - "get": { - "description": "Get transactions from XPUB address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Transactions" - ], - "summary": "Get Transactions by XPUB", - "operationId": "txxpub_v1", - "parameters": [ - { - "type": "string", - "default": "bitcoin", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - "description": "the xpub key", - "name": "xpub", - "in": "path", - "required": true - } - ], - "responses": { - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/model.ErrorResponse" - } - } - } - } - }, - "/v1/{coin}/{address}": { - "get": { - "description": "Get transactions from the address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Transactions" - ], - "summary": "Get Transactions", - "operationId": "tx_v1", - "parameters": [ - { - "type": "string", - "default": "tezos", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", - "description": "the query address", - "name": "address", - "in": "path", - "required": true - } - ], - "responses": { - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/model.ErrorResponse" - } - } - } - } - }, "/v2/ns/lookup": { "get": { "description": "Lookup ENS/ZNS to find registered addresses for multiple coins", @@ -656,12 +429,6 @@ var doc = `{ } ], "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.TxPage" - } - }, "500": { "description": "Internal Server Error", "schema": { @@ -984,97 +751,6 @@ var doc = `{ } } }, - "blockatlas.Tx": { - "type": "object", - "properties": { - "block": { - "description": "Height of the block the transaction was included in", - "type": "integer" - }, - "coin": { - "description": "SLIP-44 coin index of the platform", - "type": "integer" - }, - "date": { - "description": "Unix timestamp of the block the transaction was included in", - "type": "integer" - }, - "direction": { - "description": "Transaction Direction", - "type": "string" - }, - "error": { - "description": "Empty if the transaction was successful,\nelse error explaining why the transaction failed (optional)", - "type": "string" - }, - "fee": { - "description": "Transaction fee (native currency)", - "type": "string" - }, - "from": { - "description": "Address of the transaction sender", - "type": "string" - }, - "id": { - "description": "Unique identifier", - "type": "string" - }, - "inputs": { - "description": "Input addresses", - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.TxOutput" - } - }, - "memo": { - "description": "Meta data object", - "type": "string" - }, - "metadata": { - "type": "object" - }, - "outputs": { - "description": "Output addresses", - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.TxOutput" - } - }, - "sequence": { - "description": "Transaction nonce or sequence", - "type": "integer" - }, - "status": { - "description": "Status of the transaction", - "type": "string" - }, - "to": { - "description": "Address of the transaction recipient", - "type": "string" - }, - "type": { - "description": "Type of metadata", - "type": "string" - } - } - }, - "blockatlas.TxOutput": { - "type": "object", - "properties": { - "address": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "blockatlas.TxPage": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Tx" - } - }, "coin.ExternalCoin": { "type": "object", "properties": { @@ -1109,182 +785,6 @@ var doc = `{ "$ref": "#/definitions/endpoint.AddressBatchRequest" } }, - "endpoint.ChartCoinInfo": { - "type": "object", - "properties": { - "circulating_supply": { - "type": "number" - }, - "info": { - "type": "object", - "$ref": "#/definitions/endpoint.CoinInfo" - }, - "market_cap": { - "type": "number" - }, - "provider": { - "type": "string" - }, - "total_supply": { - "type": "number" - }, - "volume_24": { - "type": "number" - } - } - }, - "endpoint.ChartData": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "prices": { - "type": "array", - "items": { - "$ref": "#/definitions/endpoint.ChartPrice" - } - }, - "provider": { - "type": "string" - } - } - }, - "endpoint.ChartPrice": { - "type": "object", - "properties": { - "date": { - "type": "integer" - }, - "price": { - "type": "number" - } - } - }, - "endpoint.Coin": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "token_id": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "endpoint.CoinInfo": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "explorer": { - "type": "string" - }, - "name": { - "type": "string" - }, - "short_description": { - "type": "string" - }, - "socials": { - "type": "array", - "items": { - "$ref": "#/definitions/endpoint.SocialLink" - } - }, - "source_code": { - "type": "string" - }, - "website": { - "type": "string" - }, - "white_paper": { - "type": "string" - } - } - }, - "endpoint.SocialLink": { - "type": "object", - "properties": { - "handle": { - "type": "string" - }, - "name": { - "type": "string" - }, - "url": { - "type": "string" - } - } - }, - "endpoint.Ticker": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "coin_name": { - "type": "string" - }, - "error": { - "type": "string" - }, - "last_update": { - "type": "string" - }, - "price": { - "type": "object", - "$ref": "#/definitions/endpoint.TickerPrice" - }, - "token_id": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "endpoint.TickerPrice": { - "type": "object", - "properties": { - "change_24h": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "provider": { - "type": "string" - }, - "value": { - "type": "number" - } - } - }, - "endpoint.TickerRequest": { - "type": "object", - "properties": { - "assets": { - "type": "array", - "items": { - "$ref": "#/definitions/endpoint.Coin" - } - }, - "currency": { - "type": "string" - } - } - }, - "endpoint.Tickers": { - "type": "array", - "items": { - "$ref": "#/definitions/endpoint.Ticker" - } - }, "model.ErrorDetails": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 9391ffd55..c9702ec99 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -46,233 +46,6 @@ } } }, - "/v1/market/charts": { - "get": { - "description": "Get the charts data from an market and coin/token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get charts data for a specific coin", - "operationId": "get_charts_data", - "parameters": [ - { - "type": "integer", - "default": 60, - "description": "Coin ID", - "name": "coin", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Token ID", - "name": "token", - "in": "query" - }, - { - "type": "integer", - "default": 1574483028, - "description": "Start timestamp", - "name": "time_start", - "in": "query" - }, - { - "type": "integer", - "default": 64, - "description": "Max number of items in result prices array", - "name": "max_items", - "in": "query" - }, - { - "type": "string", - "default": "USD", - "description": "The currency to show charts", - "name": "currency", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/endpoint.ChartData" - } - } - } - } - }, - "/v1/market/info": { - "get": { - "description": "Get the charts coin info data from an market and coin/contract", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get charts coin info data for a specific coin", - "operationId": "get_charts_coin_info", - "parameters": [ - { - "type": "integer", - "default": 60, - "description": "Coin ID", - "name": "coin", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Token ID", - "name": "token", - "in": "query" - }, - { - "type": "string", - "default": "USD", - "description": "The currency to show coin info in", - "name": "currency", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/endpoint.ChartCoinInfo" - } - } - } - } - }, - "/v1/market/ticker": { - "post": { - "description": "Get the ticker values from many market and coin/token", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Market" - ], - "summary": "Get ticker values for a specific market", - "operationId": "get_tickers", - "parameters": [ - { - "description": "Ticker", - "name": "tickers", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/endpoint.TickerRequest" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/endpoint.Tickers" - } - } - } - } - }, - "/v1/{coin}/xpub/{xpub}": { - "get": { - "description": "Get transactions from XPUB address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Transactions" - ], - "summary": "Get Transactions by XPUB", - "operationId": "txxpub_v1", - "parameters": [ - { - "type": "string", - "default": "bitcoin", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - "description": "the xpub key", - "name": "xpub", - "in": "path", - "required": true - } - ], - "responses": { - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/model.ErrorResponse" - } - } - } - } - }, - "/v1/{coin}/{address}": { - "get": { - "description": "Get transactions from the address", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Transactions" - ], - "summary": "Get Transactions", - "operationId": "tx_v1", - "parameters": [ - { - "type": "string", - "default": "tezos", - "description": "the coin name", - "name": "coin", - "in": "path", - "required": true - }, - { - "type": "string", - "default": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", - "description": "the query address", - "name": "address", - "in": "path", - "required": true - } - ], - "responses": { - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/model.ErrorResponse" - } - } - } - } - }, "/v2/ns/lookup": { "get": { "description": "Lookup ENS/ZNS to find registered addresses for multiple coins", @@ -635,12 +408,6 @@ } ], "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.TxPage" - } - }, "500": { "description": "Internal Server Error", "schema": { @@ -963,97 +730,6 @@ } } }, - "blockatlas.Tx": { - "type": "object", - "properties": { - "block": { - "description": "Height of the block the transaction was included in", - "type": "integer" - }, - "coin": { - "description": "SLIP-44 coin index of the platform", - "type": "integer" - }, - "date": { - "description": "Unix timestamp of the block the transaction was included in", - "type": "integer" - }, - "direction": { - "description": "Transaction Direction", - "type": "string" - }, - "error": { - "description": "Empty if the transaction was successful,\nelse error explaining why the transaction failed (optional)", - "type": "string" - }, - "fee": { - "description": "Transaction fee (native currency)", - "type": "string" - }, - "from": { - "description": "Address of the transaction sender", - "type": "string" - }, - "id": { - "description": "Unique identifier", - "type": "string" - }, - "inputs": { - "description": "Input addresses", - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.TxOutput" - } - }, - "memo": { - "description": "Meta data object", - "type": "string" - }, - "metadata": { - "type": "object" - }, - "outputs": { - "description": "Output addresses", - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.TxOutput" - } - }, - "sequence": { - "description": "Transaction nonce or sequence", - "type": "integer" - }, - "status": { - "description": "Status of the transaction", - "type": "string" - }, - "to": { - "description": "Address of the transaction recipient", - "type": "string" - }, - "type": { - "description": "Type of metadata", - "type": "string" - } - } - }, - "blockatlas.TxOutput": { - "type": "object", - "properties": { - "address": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "blockatlas.TxPage": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Tx" - } - }, "coin.ExternalCoin": { "type": "object", "properties": { @@ -1088,182 +764,6 @@ "$ref": "#/definitions/endpoint.AddressBatchRequest" } }, - "endpoint.ChartCoinInfo": { - "type": "object", - "properties": { - "circulating_supply": { - "type": "number" - }, - "info": { - "type": "object", - "$ref": "#/definitions/endpoint.CoinInfo" - }, - "market_cap": { - "type": "number" - }, - "provider": { - "type": "string" - }, - "total_supply": { - "type": "number" - }, - "volume_24": { - "type": "number" - } - } - }, - "endpoint.ChartData": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "prices": { - "type": "array", - "items": { - "$ref": "#/definitions/endpoint.ChartPrice" - } - }, - "provider": { - "type": "string" - } - } - }, - "endpoint.ChartPrice": { - "type": "object", - "properties": { - "date": { - "type": "integer" - }, - "price": { - "type": "number" - } - } - }, - "endpoint.Coin": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "token_id": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "endpoint.CoinInfo": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "explorer": { - "type": "string" - }, - "name": { - "type": "string" - }, - "short_description": { - "type": "string" - }, - "socials": { - "type": "array", - "items": { - "$ref": "#/definitions/endpoint.SocialLink" - } - }, - "source_code": { - "type": "string" - }, - "website": { - "type": "string" - }, - "white_paper": { - "type": "string" - } - } - }, - "endpoint.SocialLink": { - "type": "object", - "properties": { - "handle": { - "type": "string" - }, - "name": { - "type": "string" - }, - "url": { - "type": "string" - } - } - }, - "endpoint.Ticker": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "coin_name": { - "type": "string" - }, - "error": { - "type": "string" - }, - "last_update": { - "type": "string" - }, - "price": { - "type": "object", - "$ref": "#/definitions/endpoint.TickerPrice" - }, - "token_id": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - "endpoint.TickerPrice": { - "type": "object", - "properties": { - "change_24h": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "provider": { - "type": "string" - }, - "value": { - "type": "number" - } - } - }, - "endpoint.TickerRequest": { - "type": "object", - "properties": { - "assets": { - "type": "array", - "items": { - "$ref": "#/definitions/endpoint.Coin" - } - }, - "currency": { - "type": "string" - } - } - }, - "endpoint.Tickers": { - "type": "array", - "items": { - "$ref": "#/definitions/endpoint.Ticker" - } - }, "model.ErrorDetails": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 8e6198cff..e57ba914c 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -118,73 +118,6 @@ definitions: annual: type: number type: object - blockatlas.Tx: - properties: - block: - description: Height of the block the transaction was included in - type: integer - coin: - description: SLIP-44 coin index of the platform - type: integer - date: - description: Unix timestamp of the block the transaction was included in - type: integer - direction: - description: Transaction Direction - type: string - error: - description: |- - Empty if the transaction was successful, - else error explaining why the transaction failed (optional) - type: string - fee: - description: Transaction fee (native currency) - type: string - from: - description: Address of the transaction sender - type: string - id: - description: Unique identifier - type: string - inputs: - description: Input addresses - items: - $ref: '#/definitions/blockatlas.TxOutput' - type: array - memo: - description: Meta data object - type: string - metadata: - type: object - outputs: - description: Output addresses - items: - $ref: '#/definitions/blockatlas.TxOutput' - type: array - sequence: - description: Transaction nonce or sequence - type: integer - status: - description: Status of the transaction - type: string - to: - description: Address of the transaction recipient - type: string - type: - description: Type of metadata - type: string - type: object - blockatlas.TxOutput: - properties: - address: - type: string - value: - type: string - type: object - blockatlas.TxPage: - items: - $ref: '#/definitions/blockatlas.Tx' - type: array coin.ExternalCoin: properties: coin: @@ -207,121 +140,6 @@ definitions: items: $ref: '#/definitions/endpoint.AddressBatchRequest' type: array - endpoint.ChartCoinInfo: - properties: - circulating_supply: - type: number - info: - $ref: '#/definitions/endpoint.CoinInfo' - type: object - market_cap: - type: number - provider: - type: string - total_supply: - type: number - volume_24: - type: number - type: object - endpoint.ChartData: - properties: - error: - type: string - prices: - items: - $ref: '#/definitions/endpoint.ChartPrice' - type: array - provider: - type: string - type: object - endpoint.ChartPrice: - properties: - date: - type: integer - price: - type: number - type: object - endpoint.Coin: - properties: - coin: - type: integer - token_id: - type: string - type: - type: string - type: object - endpoint.CoinInfo: - properties: - description: - type: string - explorer: - type: string - name: - type: string - short_description: - type: string - socials: - items: - $ref: '#/definitions/endpoint.SocialLink' - type: array - source_code: - type: string - website: - type: string - white_paper: - type: string - type: object - endpoint.SocialLink: - properties: - handle: - type: string - name: - type: string - url: - type: string - type: object - endpoint.Ticker: - properties: - coin: - type: integer - coin_name: - type: string - error: - type: string - last_update: - type: string - price: - $ref: '#/definitions/endpoint.TickerPrice' - type: object - token_id: - type: string - type: - type: string - type: object - endpoint.TickerPrice: - properties: - change_24h: - type: number - currency: - type: string - provider: - type: string - value: - type: number - type: object - endpoint.TickerRequest: - properties: - assets: - items: - $ref: '#/definitions/endpoint.Coin' - type: array - currency: - type: string - type: object - endpoint.Tickers: - items: - $ref: '#/definitions/endpoint.Ticker' - type: array model.ErrorDetails: properties: code: @@ -366,161 +184,6 @@ paths: summary: Lookup .eth / .zil addresses tags: - Naming - /v1/{coin}/{address}: - get: - consumes: - - application/json - description: Get transactions from the address - operationId: tx_v1 - parameters: - - default: tezos - description: the coin name - in: path - name: coin - required: true - type: string - - default: tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q - description: the query address - in: path - name: address - required: true - type: string - produces: - - application/json - responses: - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/model.ErrorResponse' - summary: Get Transactions - tags: - - Transactions - /v1/{coin}/xpub/{xpub}: - get: - consumes: - - application/json - description: Get transactions from XPUB address - operationId: txxpub_v1 - parameters: - - default: bitcoin - description: the coin name - in: path - name: coin - required: true - type: string - - default: zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC - description: the xpub key - in: path - name: xpub - required: true - type: string - produces: - - application/json - responses: - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/model.ErrorResponse' - summary: Get Transactions by XPUB - tags: - - Transactions - /v1/market/charts: - get: - consumes: - - application/json - description: Get the charts data from an market and coin/token - operationId: get_charts_data - parameters: - - default: 60 - description: Coin ID - in: query - name: coin - required: true - type: integer - - description: Token ID - in: query - name: token - type: string - - default: 1574483028 - description: Start timestamp - in: query - name: time_start - type: integer - - default: 64 - description: Max number of items in result prices array - in: query - name: max_items - type: integer - - default: USD - description: The currency to show charts - in: query - name: currency - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/endpoint.ChartData' - summary: Get charts data for a specific coin - tags: - - Market - /v1/market/info: - get: - consumes: - - application/json - description: Get the charts coin info data from an market and coin/contract - operationId: get_charts_coin_info - parameters: - - default: 60 - description: Coin ID - in: query - name: coin - required: true - type: integer - - description: Token ID - in: query - name: token - type: string - - default: USD - description: The currency to show coin info in - in: query - name: currency - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/endpoint.ChartCoinInfo' - summary: Get charts coin info data for a specific coin - tags: - - Market - /v1/market/ticker: - post: - consumes: - - application/json - description: Get the ticker values from many market and coin/token - operationId: get_tickers - parameters: - - description: Ticker - in: body - name: tickers - required: true - schema: - $ref: '#/definitions/endpoint.TickerRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/endpoint.Tickers' - summary: Get ticker values for a specific market - tags: - - Market /v2/{coin}/staking/delegations/{address}: get: consumes: @@ -636,10 +299,6 @@ paths: produces: - application/json responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.TxPage' "500": description: Internal Server Error schema: From 78eb7408e7b9ba66daee633ecee5ace51475255e Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Tue, 9 Jun 2020 20:32:10 +0300 Subject: [PATCH 325/506] API errors handling changes (#1140) * Errors handling changes - Remove models package - Use AbortWithJSON - Small cleanup as well * Change namings of projects, change swagger init way * Change configmock.yml * Change configmock.yml --- Makefile | 98 ++++++++----------- README.md | 49 +++++----- api/api.go | 11 +++ api/endpoint/basic.go | 6 -- api/endpoint/collection.go | 13 ++- api/endpoint/domain.go | 20 ++-- api/{model/model.go => endpoint/errors.go} | 4 +- api/endpoint/staking.go | 23 +++-- api/endpoint/token.go | 7 +- api/endpoint/transaction.go | 63 +++++++----- cmd/{platform_api => api}/main.go | 10 +- cmd/{observer_notifier => notifier}/main.go | 0 cmd/{observer_parser => parser}/main.go | 0 .../main.go | 0 cmd/swagger_api/main.go | 37 ------- config.yml | 3 + configmock.yml | 5 + docker-compose.yml | 12 +-- scripts/.goreleaser.yml | 24 ++--- 19 files changed, 182 insertions(+), 203 deletions(-) rename api/{model/model.go => endpoint/errors.go} (84%) rename cmd/{platform_api => api}/main.go (78%) rename cmd/{observer_notifier => notifier}/main.go (100%) rename cmd/{observer_parser => parser}/main.go (100%) rename cmd/{observer_subscriber => subscriber}/main.go (100%) delete mode 100644 cmd/swagger_api/main.go diff --git a/Makefile b/Makefile index 0342a453c..f2c29bcfa 100644 --- a/Makefile +++ b/Makefile @@ -6,11 +6,10 @@ VERSION := $(shell git describe --tags 2>/dev/null || git describe --all) BUILD := $(shell git rev-parse --short HEAD) DATETIME := $(shell date +"%Y.%m.%d-%H:%M:%S") PROJECT_NAME := $(shell basename "$(PWD)") -API_SERVICE := platform_api -OBSERVER_NOTIFIER := observer_notifier -OBSERVER_PARSER := observer_parser -OBSERVER_SUBSCRIBER := observer_subscriber -SWAGGER_API := swagger_api +API := api +NOTIFIER := notifier +PARSER := parser +SUBSCRIBER := subscriber COIN_FILE := coin/coins.yml COIN_GO_FILE := coin/coins.go GEN_COIN_FILE := coin/gen.go @@ -34,11 +33,10 @@ LDFLAGS=-ldflags "-X=$(PACKAGE)/build.Version=$(VERSION) -X=$(PACKAGE)/build.Bui STDERR := /tmp/.$(PROJECT_NAME)-stderr.txt # PID file will keep the process id of the server -PID_API := /tmp/.$(PROJECT_NAME).$(API_SERVICE).pid -PID_OBSERVER_NOTIFIER := /tmp/.$(PROJECT_NAME).$(OBSERVER_NOTIFIER).pid -PID_OBSERVER_PARSER := /tmp/.$(PROJECT_NAME).$(OBSERVER_PARSER).pid -PID_OBSERVER_SUBSCRIBER := /tmp/.$(PROJECT_NAME).$(OBSERVER_SUBSCRIBER).pid -PID_SWAGGER_API := /tmp/.$(PROJECT_NAME).$(SWAGGER_API).pid +PID_API := /tmp/.$(PROJECT_NAME).$(API).pid +PID_NOTIFIER := /tmp/.$(PROJECT_NAME).$(NOTIFIER).pid +PID_PARSER := /tmp/.$(PROJECT_NAME).$(PARSER).pid +PID_SUBSCRIBER := /tmp/.$(PROJECT_NAME).$(SUBSCRIBER).pid PID_MOCKSERVER := /tmp/.$(PROJECT_NAME).mockserver.pid # Make is verbose in Linux. Make it silent. MAKEFLAGS += --silent @@ -48,60 +46,52 @@ install: go-get ## start: Start API, Observer and Sync in development mode. start: - @bash -c "$(MAKE) clean compile start-platform-api start-observer-parser start-observer-notifier start-observer-subscriber" + @bash -c "$(MAKE) clean compile start-api start-parser start-notifier start-subscriber" ## start-api: Start platform api in development mode. -start-platform-api: stop +start-api: stop @echo " > Starting $(PROJECT_NAME)" - @-$(GOBIN)/$(API_SERVICE)/platform_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_API) + @-$(GOBIN)/$(API)/api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_API) @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" @echo " > Error log: $(STDERR)" # start-platform-api-mock: Start API. Similar to start-platform-api, but uses config file with mock URLs, and port 8437. -start-platform-api-mock: stop start-mockserver +start-api-mock: stop start-mockserver @echo " > Starting $(PROJECT_NAME) API" - @-$(GOBIN)/$(API_SERVICE)/platform_api -p 8437 -c $(CONFIG_MOCK_FILE) 2>&1 & echo $$! > $(PID_API) + @-$(GOBIN)/$(API)/api -p 8437 -c $(CONFIG_MOCK_FILE) 2>&1 & echo $$! > $(PID_API) @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" @echo " > Error log: $(STDERR)" -## start-swagger-api: Start swagger api in development mode. -start-swagger-api: stop - @echo " > Starting $(PROJECT_NAME)" - @-$(GOBIN)/$(SWAGGER_API)/swagger_api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SWAGGER_API) - @cat $(PID_SWAGGER_API) | sed "/^/s/^/ \> Sync PID: /" - @echo " > Error log: $(STDERR)" - ## start-observer-parser: Start observer-parser in development mode. -start-observer-parser: stop +start-parser: stop @echo " > Starting $(PROJECT_NAME)" - @-$(GOBIN)/$(OBSERVER_PARSER)/observer_parser -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_PARSER) - @cat $(PID_OBSERVER_PARSER) | sed "/^/s/^/ \> Sync PID: /" + @-$(GOBIN)/$(PARSER)/parser -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_PARSER) + @cat $(PID_PARSER) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" ## start-observer-notifier: Start observer-notifier in development mode. -start-observer-notifier: stop +start-notifier: stop @echo " > Starting $(PROJECT_NAME)" - @-$(GOBIN)/$(OBSERVER_NOTIFIER)/observer_notifier -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_NOTIFIER) - @cat $(PID_OBSERVER_NOTIFIER) | sed "/^/s/^/ \> Sync PID: /" + @-$(GOBIN)/$(NOTIFIER)/notifier -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_NOTIFIER) + @cat $(PID_NOTIFIER) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" ## start-observer-subscriber: Start observer-subscriber in development mode. -start-observer-subscriber: stop +start-subscriber: stop @echo " > Starting $(PROJECT_NAME)" - @-$(GOBIN)/$(OBSERVER_SUBSCRIBER)/observer_subscriber -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_OBSERVER_SUBSCRIBER) - @cat $(PID_OBSERVER_SUBSCRIBER) | sed "/^/s/^/ \> Sync PID: /" + @-$(GOBIN)/$(SUBSCRIBER)/subscriber -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SUBSCRIBER) + @cat $(PID_SUBSCRIBER) | sed "/^/s/^/ \> Sync PID: /" @echo " > Error log: $(STDERR)" ## stop: Stop development mode. stop: - @-touch $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) $(PID_MOCKSERVER) + @-touch $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_MOCKSERVER) @-kill `cat $(PID_API)` 2> /dev/null || true - @-kill `cat $(PID_OBSERVER_NOTIFIER)` 2> /dev/null || true - @-kill `cat $(PID_OBSERVER_PARSER)` 2> /dev/null || true - @-kill `cat $(PID_OBSERVER_SUBSCRIBER)` 2> /dev/null || true - @-kill `cat $(PID_SWAGGER_API)` 2> /dev/null || true + @-kill `cat $(PID_NOTIFIER)` 2> /dev/null || true + @-kill `cat $(PID_PARSER)` 2> /dev/null || true + @-kill `cat $(PID_SUBSCRIBER)` 2> /dev/null || true @-kill `cat $(PID_MOCKSERVER)` 2> /dev/null || true - @-rm $(PID_API) $(PID_OBSERVER_NOTIFIER) $(PID_OBSERVER_PARSER) $(PID_OBSERVER_SUBSCRIBER) $(PID_SWAGGER_API) $(PID_MOCKSERVER) + @-rm $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_MOCKSERVER) stop-mockserver: @-touch $(PID_MOCKSERVER) @@ -177,7 +167,7 @@ newman-mocked: install-newman go-compile ## newman-mocked-params: Run mocked Postman Newman tests, after starting platform api. ## The host parameter is required. ## E.g.: $ make newman-mocked-params test=domain host=http://localhost:8437 -newman-mocked-params: start-platform-api-mock +newman-mocked-params: start-api-mock ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host) && \ $(MAKE) newman-run test=domain host=$(host) && \ @@ -214,27 +204,23 @@ endif go-compile: go-get go-build -go-build: go-build-platform-api go-build-observer-notifier go-build-observer-parser go-build-observer-subscriber go-build-swagger-api - -go-build-platform-api: - @echo " > Building platform_api binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API_SERVICE)/platform_api ./cmd/$(API_SERVICE) +go-build: go-build-api go-build-notifier go-build-parser go-build-subscriber -go-build-observer-notifier: - @echo " > Building observer_notifier binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_NOTIFIER)/observer_notifier ./cmd/$(OBSERVER_NOTIFIER) +go-build-api: + @echo " > Building api binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API)/api ./cmd/$(API) -go-build-observer-parser: - @echo " > Building observer_parser binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_PARSER)/observer_parser ./cmd/$(OBSERVER_PARSER) +go-build-notifier: + @echo " > Building notifier binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(NOTIFIER)/notifier ./cmd/$(NOTIFIER) -go-build-observer-subscriber: - @echo " > Building observer_subscriber binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(OBSERVER_SUBSCRIBER)/observer_subscriber ./cmd/$(OBSERVER_SUBSCRIBER) +go-build-parser: + @echo " > Building parser binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(PARSER)/parser ./cmd/$(PARSER) -go-build-swagger-api: - @echo " > Building swagger_api binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SWAGGER_API)/swagger_api ./cmd/$(SWAGGER_API) +go-build-subscriber: + @echo " > Building subscriber binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SUBSCRIBER)/subscriber ./cmd/$(SUBSCRIBER) go-generate: @echo " > Generating dependency files..." @@ -269,7 +255,7 @@ go-gen-coins: go-gen-docs: @echo " > Generating swagger files" - swag init -g ./cmd/platform_api/main.go -o ./docs + swag init -g ./cmd/api/main.go -o ./docs go-goreleaser: @echo " > Releasing a new version" diff --git a/README.md b/README.md index 5bd0953fb..2e7254c01 100644 --- a/README.md +++ b/README.md @@ -53,15 +53,15 @@ Platform API is independent service and can work with the specific blockchain on Notifications: -(Observer Subscriber Producer) - Create new blockatlas.SubscriptionEvent [Not implemented at Atlas, write it on your own] +- Subscriber Producer - Create new blockatlas.SubscriptionEvent [Not implemented at Atlas, write it on your own] -(Observer Subscriber) - Get subscriptions from queue, set them to the DB +- Subscriber - Get subscriptions from queue, set them to the DB -(Observer Parser) - Parse the block, convert block to the transactions batch, send to queue +- Parser - Parse the block, convert block to the transactions batch, send to queue -(Observer Notifier) - Check each transaction for having the same address as stored at DB, if so - send tx data and id to the next queue +- Notifier - Check each transaction for having the same address as stored at DB, if so - send tx data and id to the next queue -(Observer Notifier Consumer) - Notify the user [Not implemented at Atlas, write it on your own] +- Notifier Consumer - Notify the user [Not implemented at Atlas, write it on your own] ``` New Subscriptions --(Rabbit MQ)--> Subscriber --> DB @@ -97,22 +97,16 @@ Read [configuration](#configuration) info ```shell # Start Platform API server at port 8420 with the path to the config.yml ./ -go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8420 +go build -o api-bin cmd/api/main.go && ./api-bin -p 8420 -# Start observer_parser with the path to the config.yml ./ -go build -o observer_parser-bin cmd/observer_parser/main.go && ./observer_parser-bin +# Start parser with the path to the config.yml ./ +go build -o parser-bin cmd/parser/main.go && ./parser-bin -# Start observer_notifier with the path to the config.yml ./ -go build -o observer_notifier-bin cmd/observer_notifier/main.go && ./observer_notifier-bin +# Start notifier with the path to the config.yml ./ +go build -o notifier-bin cmd/notifier/main.go && ./notifier-bin -# Start observer_subscriber with the path to the config.yml ./ -go build -o observer_subscriber-bin cmd/observer_subscriber/main.go && ./observer_subscriber-bin - -# Startp Swagger API server at port 8422 with the path to the config.yml ./ -go build -o swagger-api-bin cmd/swagger-api/main.go && ./swagger-api-bin -p 8423 - -# Start Platform API server with mocked config, at port 8437 ./ -go build -o platform-api-bin cmd/platform_api/main.go && ./platform-api-bin -p 8437 -c configmock.yml +# Start subscriber with the path to the config.yml ./ +go build -o subscriber-bin cmd/subscriber/main.go && ./subscriber-bin ``` ### make command @@ -125,7 +119,7 @@ make start Build and start individual service: ```shell -make go-build-platform-api +make go-build-api make start ``` @@ -140,8 +134,8 @@ docker-compose up Build and run individual service: ```shell -docker-compose build swagger_api -docker-compose start swagger_api +docker-compose build api +docker-compose start api ``` ## Configuration @@ -149,11 +143,11 @@ When any of Block Atlas services started they look up inside [default configurat Most coins offering public RPC/explorer APIs are enabled, thus Block Atlas can be started and used right away, no additional configuration needed. By default starting any of the [services](#architecture) will enable all platforms -To run a specific service only by passing environmental variable, e.g: `platfrom_api` : +To run a specific service only by passing environmental variable, e.g: `ATLAS_PLATFORM=ethereum` : ```shell -ATLAS_PLATFORM=ethereum go run cmd/platform_api/main.go +ATLAS_PLATFORM=ethereum go run cmd/api/main.go -ATLAS_PLATFORM=ethereum binance bitcoin go run cmd/platform_api/main.go # for multiple platforms +ATLAS_PLATFORM=ethereum binance bitcoin go run cmd/api/main.go # for multiple platforms ``` or change in config file @@ -171,7 +165,7 @@ To enable use of private endpoint: nimiq: api: http://localhost:8648 ``` -It works the same for observer_worker - you can run all observer at 1 binary or 30 coins per 30 binaries +It works the same for worker - you can run all observer at 1 binary or 30 coins per 30 binaries #### Environment @@ -194,6 +188,11 @@ make test End-to-end tests with calls to external APIs has great value, but they are not suitable for regular CI verification, beacuse any external reason could break the tests. +``` +# Start API server with mocked config, at port 8437 ./ +go build -o api-bin cmd/api/main.go && ./api-bin -p 8437 -c configmock.yml +``` + Therefore mocked API-level tests are used, whereby external APIs are replaced by mocks. * External mocks are implemented as a simple, own, golang `mockserver`. It listens locally, and returns responses to specific API paths, taken from json data files. diff --git a/api/api.go b/api/api.go index be6f0b742..f9e0c5933 100644 --- a/api/api.go +++ b/api/api.go @@ -2,6 +2,10 @@ package api import ( "github.com/gin-gonic/gin" + "github.com/spf13/viper" + ginSwagger "github.com/swaggo/gin-swagger" + "github.com/swaggo/gin-swagger/swaggerFiles" + _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/platform" ) @@ -19,3 +23,10 @@ func SetupPlatformAPI(router gin.IRouter) { RegisterDomainAPI(router) RegisterBasicAPI(router) } + +func SetupSwaggerAPI(router gin.IRouter) { + admin := router.Group("/admin", gin.BasicAuth(gin.Accounts{ + viper.GetString("gin.login"): viper.GetString("gin.pass"), + })) + admin.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) +} diff --git a/api/endpoint/basic.go b/api/endpoint/basic.go index 5d912be9c..110b6b21d 100644 --- a/api/endpoint/basic.go +++ b/api/endpoint/basic.go @@ -3,7 +3,6 @@ package endpoint import ( "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/http" ) @@ -14,8 +13,3 @@ func GetStatus(c *gin.Context) { "date": internal.Date, }) } - -func EmptyPage(c *gin.Context) { - var page blockatlas.TxPage - c.JSON(http.StatusOK, &page) -} diff --git a/api/endpoint/collection.go b/api/endpoint/collection.go index 76052ddf8..7ae0d0a86 100644 --- a/api/endpoint/collection.go +++ b/api/endpoint/collection.go @@ -2,7 +2,6 @@ package endpoint import ( "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/api/model" "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/http" "strconv" @@ -18,12 +17,12 @@ import ( // @Param owner path string true "the query address" default(0x0875BCab22dE3d02402bc38aEe4104e1239374a7) // @Param collection_id path string true "the query collection" default(0x06012c8cf97bead5deae237070f9587f8e7a266d) // @Success 200 {object} blockatlas.CollectionPage -// @Failure 500 {object} model.ErrorResponse +// @Failure 500 {object} ErrorResponse // @Router /v4/{coin}/collections/{owner}/collection/{collection_id} [get] func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas.CollectionsAPI) { collectibles, err := api.GetCollectibles(c.Param("owner"), c.Param("collection_id")) if err != nil { - c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) return } c.JSON(http.StatusOK, &collectibles) @@ -41,7 +40,7 @@ func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas func GetCollectionCategoriesFromList(c *gin.Context, apis blockatlas.CollectionsAPIs) { var reqs map[string][]string if err := c.BindJSON(&reqs); err != nil { - c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.Default, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(Default, err)) return } @@ -69,7 +68,7 @@ func GetCollectionCategoriesFromList(c *gin.Context, apis blockatlas.Collections func GetCollectiblesForOwnerV3(c *gin.Context, api blockatlas.CollectionsAPI) { collections, err := api.GetCollectionsV3(c.Param("owner")) if err != nil { - c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) return } @@ -79,7 +78,7 @@ func GetCollectiblesForOwnerV3(c *gin.Context, api blockatlas.CollectionsAPI) { func GetCollectiblesForSpecificCollectionAndOwnerV3(c *gin.Context, api blockatlas.CollectionsAPI) { collectibles, err := api.GetCollectiblesV3(c.Param("owner"), c.Param("collection_id")) if err != nil { - c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) return } c.JSON(http.StatusOK, &collectibles) @@ -88,7 +87,7 @@ func GetCollectiblesForSpecificCollectionAndOwnerV3(c *gin.Context, api blockatl func GetCollectionCategoriesFromListV3(c *gin.Context, apis blockatlas.CollectionsAPIs) { var reqs map[string][]string if err := c.BindJSON(&reqs); err != nil { - c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.Default, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(Default, err)) return } diff --git a/api/endpoint/domain.go b/api/endpoint/domain.go index b83baebef..2f211fa3b 100644 --- a/api/endpoint/domain.go +++ b/api/endpoint/domain.go @@ -6,8 +6,6 @@ import ( "strings" "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/api/model" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/domains" ) @@ -19,24 +17,23 @@ import ( // @Param name query string empty "string name" // @Param coin query string 60 "string coin" // @Success 200 {object} blockatlas.Resolved -// @Failure 500 {object} model.ErrorResponse +// @Failure 500 {object} ErrorResponse // @Router /ns/lookup [get] func GetAddressByCoinAndDomain(c *gin.Context) { name := c.Query("name") coinQuery := c.Query("coin") coin, err := strconv.ParseUint(coinQuery, 10, 64) if err != nil { - c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, err)) return } result, err := domains.HandleLookup(name, []uint64{coin}) if err != nil { - logger.Warn(err) - c.JSON(http.StatusNotFound, model.CreateErrorResponse(model.InternalFail, err)) + c.AbortWithStatusJSON(http.StatusNotFound, createErrorResponse(InternalFail, err)) return } if len(result) == 0 { - c.JSON(http.StatusNotFound, model.CreateErrorResponse(model.RequestedDataNotFound, err)) + c.AbortWithStatusJSON(http.StatusNotFound, createErrorResponse(RequestedDataNotFound, err)) return } c.JSON(http.StatusOK, result[0]) @@ -50,24 +47,23 @@ func GetAddressByCoinAndDomain(c *gin.Context) { // @Param name query string empty "string name" // @Param coins query string true "List of coins" // @Success 200 {array} blockatlas.Resolved -// @Failure 500 {object} model.ErrorResponse +// @Failure 500 {object} ErrorResponse // @Router /v2/ns/lookup [get] func GetAddressByCoinAndDomainBatch(c *gin.Context) { name := c.Query("name") coinsRaw := strings.Split(c.Query("coins"), ",") coins, err := sliceAtoi(coinsRaw) if err != nil { - c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, err)) return } result, err := domains.HandleLookup(name, coins) if err != nil { - logger.Warn(err) - c.JSON(http.StatusNotFound, model.CreateErrorResponse(model.InternalFail, err)) + c.AbortWithStatusJSON(http.StatusNotFound, createErrorResponse(InternalFail, err)) return } if len(result) == 0 { - c.JSON(http.StatusNotFound, model.CreateErrorResponse(model.RequestedDataNotFound, err)) + c.AbortWithStatusJSON(http.StatusNotFound, createErrorResponse(RequestedDataNotFound, err)) return } c.JSON(http.StatusOK, &result) diff --git a/api/model/model.go b/api/endpoint/errors.go similarity index 84% rename from api/model/model.go rename to api/endpoint/errors.go index e7708e475..2a2fc79f4 100644 --- a/api/model/model.go +++ b/api/endpoint/errors.go @@ -1,4 +1,4 @@ -package model +package endpoint const ( Default ErrorCode = iota @@ -19,7 +19,7 @@ type ( ErrorCode int ) -func CreateErrorResponse(code ErrorCode, err error) ErrorResponse { +func createErrorResponse(code ErrorCode, err error) ErrorResponse { var message string if err != nil { message = err.Error() diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index 94e5240e4..5b743efe2 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -2,11 +2,10 @@ package endpoint import ( "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/api/model" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" - services "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/blockatlas/services/assets" "net/http" "sort" "strconv" @@ -44,7 +43,7 @@ type ( func GetStakeDelegationsWithAllInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { var reqs AddressesRequest if err := c.BindJSON(&reqs); err != nil { - c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, err)) return } @@ -80,7 +79,7 @@ func GetStakeDelegationsWithAllInfoForBatch(c *gin.Context, apis map[string]bloc func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { var reqs CoinsRequest if err := c.BindJSON(&reqs); err != nil { - c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, err)) return } @@ -107,12 +106,12 @@ func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { // @Tags Staking // @Param coins query string true "List of coins" // @Success 200 {array} blockatlas.DelegationsBatchPage -// @Failure 400 {object} model.ErrorResponse +// @Failure 400 {object} ErrorResponse // @Router /v3/staking/list [get] func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { coinsRequest := c.Query("coins") if coinsRequest == "" { - c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, errors.E("empty coins list"))) + c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, errors.E("empty coins list"))) return } @@ -120,7 +119,7 @@ func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { coins, err := sliceAtoi(coinsRaw) if err != nil { - c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, err)) return } @@ -153,12 +152,12 @@ func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { // @Tags Staking // @Param coin path string true "the coin name" default(cosmos) // @Success 200 {object} blockatlas.DocsResponse -// @Failure 500 {object} model.ErrorResponse +// @Failure 500 {object} ErrorResponse // @Router /v2/{coin}/staking/validators [get] func GetValidators(c *gin.Context, api blockatlas.StakeAPI) { - results, err := services.GetActiveValidators(api) + results, err := assets.GetActiveValidators(api) if err != nil { - c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) return } c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &results}) @@ -173,12 +172,12 @@ func GetValidators(c *gin.Context, api blockatlas.StakeAPI) { // @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 -// @Failure 500 {object} model.ErrorResponse +// @Failure 500 {object} ErrorResponse // @Router /v2/{coin}/staking/delegations/{address} [get] func GetStakingDelegationsForSpecificCoin(c *gin.Context, api blockatlas.StakeAPI) { result, err := getDelegationResponse(api, c.Param("address")) if err != nil { - c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) return } result.Delegations = sortDelegations(result.Delegations) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index c065fa51e..c3a2e5a5b 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -2,7 +2,6 @@ package endpoint import ( "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/api/model" "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/http" "strconv" @@ -24,13 +23,13 @@ import ( func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { address := c.Param("address") if address == "" { - EmptyPage(c) + c.JSON(http.StatusOK, blockatlas.TxPage{}) return } result, err := tokenAPI.GetTokenListByAddress(address) if err != nil { - c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) return } c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &result}) @@ -48,7 +47,7 @@ func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { func GetTokens(c *gin.Context, apis map[uint]blockatlas.TokensAPI) { var query map[string][]string if err := c.Bind(&query); err != nil { - c.JSON(http.StatusInternalServerError, model.CreateErrorResponse(model.InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) return } result := make(blockatlas.TokenPage, 0) diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 792af4775..9a4a56276 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/api/model" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" ) @@ -18,13 +17,13 @@ import ( // @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} model.ErrorResponse +// @Failure 500 {object} ErrorResponse // @Router /v1/{coin}/{address} [get] // @Router /v2/{coin}/transactions/{address} [get] func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI blockatlas.TokenTxAPI) { address := c.Param("address") if address == "" { - c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, blockatlas.ErrInvalidAddr)) + c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, blockatlas.ErrInvalidAddr)) return } token := c.Query("token") @@ -40,28 +39,38 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b case token != "" && tokenTxAPI != nil: txs, err = tokenTxAPI.GetTokenTxsByAddress(address, token) default: - c.JSON(http.StatusInternalServerError, - model.CreateErrorResponse(model.InternalFail, errors.E("Failed to find api for that coin"))) + c.AbortWithStatusJSON( + http.StatusInternalServerError, + createErrorResponse(InternalFail, errors.E("Failed to find api for that coin")), + ) return } if err != nil { switch err { case blockatlas.ErrInvalidAddr: - c.JSON(http.StatusBadRequest, - model.CreateErrorResponse(model.InvalidQuery, blockatlas.ErrInvalidAddr)) + c.AbortWithStatusJSON( + http.StatusBadRequest, + createErrorResponse(InvalidQuery, blockatlas.ErrInvalidAddr), + ) return case blockatlas.ErrNotFound: - c.JSON(http.StatusNotFound, - model.CreateErrorResponse(model.RequestedDataNotFound, blockatlas.ErrNotFound)) + c.AbortWithStatusJSON( + http.StatusNotFound, + createErrorResponse(RequestedDataNotFound, blockatlas.ErrNotFound), + ) return case blockatlas.ErrSourceConn: - c.JSON(http.StatusServiceUnavailable, - model.CreateErrorResponse(model.InternalFail, blockatlas.ErrSourceConn)) + c.AbortWithStatusJSON( + http.StatusServiceUnavailable, + createErrorResponse(InternalFail, blockatlas.ErrSourceConn), + ) return default: - c.JSON(http.StatusInternalServerError, - model.CreateErrorResponse(model.Default, err)) + c.AbortWithStatusJSON( + http.StatusInternalServerError, + createErrorResponse(Default, err), + ) return } } @@ -92,13 +101,13 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b // @Tags Transactions // @Param coin path string true "the coin name" default(bitcoin) // @Param xpub path string true "the xpub key" default(zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC) -// @Failure 500 {object} model.ErrorResponse +// @Failure 500 {object} ErrorResponse // @Router /v1/{coin}/{address} [get] // @Router /v2/{coin}/transactions/xpub/{xpub} [get] func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { xPubKey := c.Param("xpub") if xPubKey == "" { - c.JSON(http.StatusBadRequest, model.CreateErrorResponse(model.InvalidQuery, blockatlas.ErrInvalidKey)) + c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, blockatlas.ErrInvalidKey)) return } @@ -106,20 +115,28 @@ func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { if err != nil { switch err { case blockatlas.ErrInvalidKey: - c.JSON(http.StatusBadRequest, - model.CreateErrorResponse(model.InvalidQuery, blockatlas.ErrInvalidKey)) + c.AbortWithStatusJSON( + http.StatusBadRequest, + createErrorResponse(InvalidQuery, blockatlas.ErrInvalidKey), + ) return case blockatlas.ErrNotFound: - c.JSON(http.StatusNotFound, - model.CreateErrorResponse(model.RequestedDataNotFound, blockatlas.ErrNotFound)) + c.AbortWithStatusJSON( + http.StatusNotFound, + createErrorResponse(RequestedDataNotFound, blockatlas.ErrNotFound), + ) return case blockatlas.ErrSourceConn: - c.JSON(http.StatusServiceUnavailable, - model.CreateErrorResponse(model.InternalFail, blockatlas.ErrSourceConn)) + c.AbortWithStatusJSON( + http.StatusServiceUnavailable, + createErrorResponse(InternalFail, blockatlas.ErrSourceConn), + ) return default: - c.JSON(http.StatusInternalServerError, - model.CreateErrorResponse(model.Default, err)) + c.AbortWithStatusJSON( + http.StatusInternalServerError, + createErrorResponse(Default, err), + ) return } } diff --git a/cmd/platform_api/main.go b/cmd/api/main.go similarity index 78% rename from cmd/platform_api/main.go rename to cmd/api/main.go index 40c971d3c..b840f241c 100644 --- a/cmd/platform_api/main.go +++ b/cmd/api/main.go @@ -32,6 +32,14 @@ func init() { } func main() { - api.SetupPlatformAPI(engine) + switch viper.GetString("rest_api") { + case "swagger": + api.SetupSwaggerAPI(engine) + case "platform": + api.SetupPlatformAPI(engine) + default: + api.SetupSwaggerAPI(engine) + api.SetupPlatformAPI(engine) + } internal.SetupGracefulShutdown(port, engine) } diff --git a/cmd/observer_notifier/main.go b/cmd/notifier/main.go similarity index 100% rename from cmd/observer_notifier/main.go rename to cmd/notifier/main.go diff --git a/cmd/observer_parser/main.go b/cmd/parser/main.go similarity index 100% rename from cmd/observer_parser/main.go rename to cmd/parser/main.go diff --git a/cmd/observer_subscriber/main.go b/cmd/subscriber/main.go similarity index 100% rename from cmd/observer_subscriber/main.go rename to cmd/subscriber/main.go diff --git a/cmd/swagger_api/main.go b/cmd/swagger_api/main.go deleted file mode 100644 index dc2ad7802..000000000 --- a/cmd/swagger_api/main.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "github.com/gin-gonic/gin" - "github.com/spf13/viper" - ginSwagger "github.com/swaggo/gin-swagger" - "github.com/swaggo/gin-swagger/swaggerFiles" - _ "github.com/trustwallet/blockatlas/docs" - "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/logger" -) - -const ( - defaultPort = "8423" - defaultConfigPath = "../../config.yml" -) - -var ( - port, confPath string - engine *gin.Engine -) - -func init() { - port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) - internal.InitConfig(confPath) - logger.InitLogger() - engine = internal.InitEngine(viper.GetString("gin.mode")) -} - -func main() { - logger.Info("Loading Swagger API") - admin := engine.Group("/admin", gin.BasicAuth(gin.Accounts{ - viper.GetString("gin.login"): viper.GetString("gin.pass"), - })) - admin.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - internal.SetupGracefulShutdown(port, engine) -} diff --git a/config.yml b/config.yml index 61a8b41c8..a4bc5e8cb 100644 --- a/config.yml +++ b/config.yml @@ -13,6 +13,9 @@ gin: # You can see all the coin handles at coins/coins.yml file platform: [ethereum] +# Can be platform or swagger +rest_api: all + # The transaction watcher observer: # Don't request blocks older than this diff --git a/configmock.yml b/configmock.yml index 54476ca9e..4e030b440 100644 --- a/configmock.yml +++ b/configmock.yml @@ -1,6 +1,8 @@ # Gin is the web framework gin: # Possible values: "debug", "release" + login: admin + pass: pass mode: release # App running behind a reverse proxy? # If set, HTTP Forwarded headers will be respected @@ -11,6 +13,9 @@ gin: # You can see all the coin handles at coins/coins.yml file platform: all +# Can be platform or swagger +rest_api: all + # The transaction watcher observer: backlog: 3h diff --git a/docker-compose.yml b/docker-compose.yml index e744b50c1..6fae13f6d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,11 +12,11 @@ services: - swagger_api platform_api: - container_name: platform_api + container_name: api build: context: . args: - - SERVICE=platform_api + - SERVICE=api ports: - 8420:8420 - 8437:8437 @@ -34,7 +34,7 @@ services: build: context: . args: - - SERVICE=observer_notifier + - SERVICE=notifier links: - rabbit - postgres @@ -44,18 +44,18 @@ services: build: context: . args: - - SERVICE=observer_parser + - SERVICE=parser links: - rabbit - postgres restart: on-failure observer_subscriber: - container_name: observer_subscriber + container_name: subscriber build: context: . args: - - SERVICE=observer_subscriber + - SERVICE=subscriber links: - rabbit - postgres diff --git a/scripts/.goreleaser.yml b/scripts/.goreleaser.yml index 573ad2bdf..0a338f976 100644 --- a/scripts/.goreleaser.yml +++ b/scripts/.goreleaser.yml @@ -3,9 +3,9 @@ before: - git reset --hard - git checkout . builds: - - id: platform_api - binary: platform_api - main: "./cmd/platform_api/main.go" + - id: api + binary: api + main: "./cmd/api/main.go" goos: - linux goarch: @@ -21,27 +21,27 @@ builds: - amd64 env: - CGO_ENABLED=0 - - id: observer_parser - binary: observer_parser - main: "./cmd/observer_parser/main.go" + - id: parser + binary: parser + main: "./cmd/parser/main.go" goos: - linux goarch: - amd64 env: - CGO_ENABLED=0 - - id: observer_subscriber - binary: observer_subscriber - main: "./cmd/observer_subscriber/main.go" + - id: subscriber + binary: subscriber + main: "./cmd/subscriber/main.go" goos: - linux goarch: - amd64 env: - CGO_ENABLED=0 - - id: observer_notifier - binary: observer_notifier - main: "./cmd/observer_notifier/main.go" + - id: notifier + binary: notifier + main: "./cmd/notifier/main.go" goos: - linux goarch: From 4f915a0fa715e6cce7cc6c4c47ec5ac37df5f02e Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov Date: Thu, 11 Jun 2020 00:32:32 +0300 Subject: [PATCH 326/506] [API] Update errorResponse, delete response code (#1141) --- api/endpoint/collection.go | 10 +++++----- api/endpoint/domain.go | 12 ++++++------ api/endpoint/errors.go | 13 ++----------- api/endpoint/staking.go | 12 ++++++------ api/endpoint/token.go | 4 ++-- api/endpoint/transaction.go | 38 ++++++++++++++++++------------------- 6 files changed, 40 insertions(+), 49 deletions(-) diff --git a/api/endpoint/collection.go b/api/endpoint/collection.go index 7ae0d0a86..735a44318 100644 --- a/api/endpoint/collection.go +++ b/api/endpoint/collection.go @@ -22,7 +22,7 @@ import ( func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas.CollectionsAPI) { collectibles, err := api.GetCollectibles(c.Param("owner"), c.Param("collection_id")) if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return } c.JSON(http.StatusOK, &collectibles) @@ -40,7 +40,7 @@ func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas func GetCollectionCategoriesFromList(c *gin.Context, apis blockatlas.CollectionsAPIs) { var reqs map[string][]string if err := c.BindJSON(&reqs); err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(Default, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) return } @@ -68,7 +68,7 @@ func GetCollectionCategoriesFromList(c *gin.Context, apis blockatlas.Collections func GetCollectiblesForOwnerV3(c *gin.Context, api blockatlas.CollectionsAPI) { collections, err := api.GetCollectionsV3(c.Param("owner")) if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return } @@ -78,7 +78,7 @@ func GetCollectiblesForOwnerV3(c *gin.Context, api blockatlas.CollectionsAPI) { func GetCollectiblesForSpecificCollectionAndOwnerV3(c *gin.Context, api blockatlas.CollectionsAPI) { collectibles, err := api.GetCollectiblesV3(c.Param("owner"), c.Param("collection_id")) if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return } c.JSON(http.StatusOK, &collectibles) @@ -87,7 +87,7 @@ func GetCollectiblesForSpecificCollectionAndOwnerV3(c *gin.Context, api blockatl func GetCollectionCategoriesFromListV3(c *gin.Context, apis blockatlas.CollectionsAPIs) { var reqs map[string][]string if err := c.BindJSON(&reqs); err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(Default, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) return } diff --git a/api/endpoint/domain.go b/api/endpoint/domain.go index 2f211fa3b..58a1c2c33 100644 --- a/api/endpoint/domain.go +++ b/api/endpoint/domain.go @@ -24,16 +24,16 @@ func GetAddressByCoinAndDomain(c *gin.Context) { coinQuery := c.Query("coin") coin, err := strconv.ParseUint(coinQuery, 10, 64) if err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) return } result, err := domains.HandleLookup(name, []uint64{coin}) if err != nil { - c.AbortWithStatusJSON(http.StatusNotFound, createErrorResponse(InternalFail, err)) + c.AbortWithStatusJSON(http.StatusNotFound, errorResponse(err)) return } if len(result) == 0 { - c.AbortWithStatusJSON(http.StatusNotFound, createErrorResponse(RequestedDataNotFound, err)) + c.AbortWithStatusJSON(http.StatusNotFound, errorResponse(err)) return } c.JSON(http.StatusOK, result[0]) @@ -54,16 +54,16 @@ func GetAddressByCoinAndDomainBatch(c *gin.Context) { coinsRaw := strings.Split(c.Query("coins"), ",") coins, err := sliceAtoi(coinsRaw) if err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) return } result, err := domains.HandleLookup(name, coins) if err != nil { - c.AbortWithStatusJSON(http.StatusNotFound, createErrorResponse(InternalFail, err)) + c.AbortWithStatusJSON(http.StatusNotFound, errorResponse(err)) return } if len(result) == 0 { - c.AbortWithStatusJSON(http.StatusNotFound, createErrorResponse(RequestedDataNotFound, err)) + c.AbortWithStatusJSON(http.StatusNotFound, errorResponse(err)) return } c.JSON(http.StatusOK, &result) diff --git a/api/endpoint/errors.go b/api/endpoint/errors.go index 2a2fc79f4..48f65578f 100644 --- a/api/endpoint/errors.go +++ b/api/endpoint/errors.go @@ -1,31 +1,22 @@ package endpoint -const ( - Default ErrorCode = iota - InvalidQuery - RequestedDataNotFound - InternalFail -) - type ( ErrorResponse struct { Error ErrorDetails `json:"error"` } ErrorDetails struct { - Message string `json:"message"` - Code ErrorCode `json:"code"` + Message string `json:"message"` } ErrorCode int ) -func createErrorResponse(code ErrorCode, err error) ErrorResponse { +func errorResponse(err error) ErrorResponse { var message string if err != nil { message = err.Error() } return ErrorResponse{Error: ErrorDetails{ Message: message, - Code: code, }} } diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index 5b743efe2..f4e6b5bcd 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -43,7 +43,7 @@ type ( func GetStakeDelegationsWithAllInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { var reqs AddressesRequest if err := c.BindJSON(&reqs); err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) return } @@ -79,7 +79,7 @@ func GetStakeDelegationsWithAllInfoForBatch(c *gin.Context, apis map[string]bloc func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { var reqs CoinsRequest if err := c.BindJSON(&reqs); err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) return } @@ -111,7 +111,7 @@ func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { coinsRequest := c.Query("coins") if coinsRequest == "" { - c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, errors.E("empty coins list"))) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(errors.E("empty coins list"))) return } @@ -119,7 +119,7 @@ func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { coins, err := sliceAtoi(coinsRaw) if err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, err)) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) return } @@ -157,7 +157,7 @@ func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { func GetValidators(c *gin.Context, api blockatlas.StakeAPI) { results, err := assets.GetActiveValidators(api) if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return } c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &results}) @@ -177,7 +177,7 @@ func GetValidators(c *gin.Context, api blockatlas.StakeAPI) { func GetStakingDelegationsForSpecificCoin(c *gin.Context, api blockatlas.StakeAPI) { result, err := getDelegationResponse(api, c.Param("address")) if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return } result.Delegations = sortDelegations(result.Delegations) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index c3a2e5a5b..606ce4a77 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -29,7 +29,7 @@ func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { result, err := tokenAPI.GetTokenListByAddress(address) if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return } c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &result}) @@ -47,7 +47,7 @@ func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { func GetTokens(c *gin.Context, apis map[uint]blockatlas.TokensAPI) { var query map[string][]string if err := c.Bind(&query); err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, createErrorResponse(InternalFail, err)) + c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return } result := make(blockatlas.TokenPage, 0) diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 9a4a56276..4cabba8b3 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -23,7 +23,7 @@ import ( func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI blockatlas.TokenTxAPI) { address := c.Param("address") if address == "" { - c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, blockatlas.ErrInvalidAddr)) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(blockatlas.ErrInvalidAddr)) return } token := c.Query("token") @@ -41,7 +41,7 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b default: c.AbortWithStatusJSON( http.StatusInternalServerError, - createErrorResponse(InternalFail, errors.E("Failed to find api for that coin")), + errorResponse(errors.E("Failed to find api for that coin")), ) return } @@ -51,26 +51,26 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b case blockatlas.ErrInvalidAddr: c.AbortWithStatusJSON( http.StatusBadRequest, - createErrorResponse(InvalidQuery, blockatlas.ErrInvalidAddr), - ) + errorResponse(blockatlas.ErrInvalidAddr), + ) return case blockatlas.ErrNotFound: c.AbortWithStatusJSON( http.StatusNotFound, - createErrorResponse(RequestedDataNotFound, blockatlas.ErrNotFound), - ) + errorResponse(blockatlas.ErrNotFound), + ) return case blockatlas.ErrSourceConn: c.AbortWithStatusJSON( http.StatusServiceUnavailable, - createErrorResponse(InternalFail, blockatlas.ErrSourceConn), - ) + errorResponse(blockatlas.ErrSourceConn), + ) return default: c.AbortWithStatusJSON( http.StatusInternalServerError, - createErrorResponse(Default, err), - ) + errorResponse(err), + ) return } } @@ -107,7 +107,7 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { xPubKey := c.Param("xpub") if xPubKey == "" { - c.AbortWithStatusJSON(http.StatusBadRequest, createErrorResponse(InvalidQuery, blockatlas.ErrInvalidKey)) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(blockatlas.ErrInvalidKey)) return } @@ -117,26 +117,26 @@ func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { case blockatlas.ErrInvalidKey: c.AbortWithStatusJSON( http.StatusBadRequest, - createErrorResponse(InvalidQuery, blockatlas.ErrInvalidKey), - ) + errorResponse(blockatlas.ErrInvalidKey), + ) return case blockatlas.ErrNotFound: c.AbortWithStatusJSON( http.StatusNotFound, - createErrorResponse(RequestedDataNotFound, blockatlas.ErrNotFound), - ) + errorResponse(blockatlas.ErrNotFound), + ) return case blockatlas.ErrSourceConn: c.AbortWithStatusJSON( http.StatusServiceUnavailable, - createErrorResponse(InternalFail, blockatlas.ErrSourceConn), - ) + errorResponse(blockatlas.ErrSourceConn), + ) return default: c.AbortWithStatusJSON( http.StatusInternalServerError, - createErrorResponse(Default, err), - ) + errorResponse(err), + ) return } } From b440bdb5c4f6dbb05bcb9f76cbf4ddc5baccd8a5 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 11 Jun 2020 13:57:57 +0300 Subject: [PATCH 327/506] Remove swagger auth (#1143) --- api/api.go | 6 +----- config.yml | 2 -- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/api/api.go b/api/api.go index f9e0c5933..32bc8506d 100644 --- a/api/api.go +++ b/api/api.go @@ -2,7 +2,6 @@ package api import ( "github.com/gin-gonic/gin" - "github.com/spf13/viper" ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" _ "github.com/trustwallet/blockatlas/docs" @@ -25,8 +24,5 @@ func SetupPlatformAPI(router gin.IRouter) { } func SetupSwaggerAPI(router gin.IRouter) { - admin := router.Group("/admin", gin.BasicAuth(gin.Accounts{ - viper.GetString("gin.login"): viper.GetString("gin.pass"), - })) - admin.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + router.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) } diff --git a/config.yml b/config.yml index a4bc5e8cb..cb2f42f92 100644 --- a/config.yml +++ b/config.yml @@ -1,8 +1,6 @@ # Gin is the web framework gin: # Possible values: "debug", "release" - login: admin - pass: pass mode: release # App running behind a reverse proxy? # If set, HTTP Forwarded headers will be respected From 77849bce546013cb31d77562838f51268a9a3533 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2020 12:21:50 +0300 Subject: [PATCH 328/506] Bump github.com/jinzhu/gorm from 1.9.12 to 1.9.13 (#1145) Bumps [github.com/jinzhu/gorm](https://github.com/jinzhu/gorm) from 1.9.12 to 1.9.13. - [Release notes](https://github.com/jinzhu/gorm/releases) - [Commits](https://github.com/jinzhu/gorm/compare/v1.9.12...v1.9.13) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 04ec4f71d..12e591646 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/gin-gonic/gin v1.6.3 github.com/golang/protobuf v1.4.2 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect - github.com/jinzhu/gorm v1.9.12 + github.com/jinzhu/gorm v1.9.13 github.com/mitchellh/mapstructure v1.3.2 github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/image-spec v1.0.1 // indirect diff --git a/go.sum b/go.sum index 14ce4b61b..530452bd5 100644 --- a/go.sum +++ b/go.sum @@ -238,6 +238,8 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +github.com/jinzhu/gorm v1.9.13 h1:fcdacwmUcoyon8XHkQrdPJZ7pnHAYclHZ6iLYER5nX4= +github.com/jinzhu/gorm v1.9.13/go.mod h1:C0zfmO9z9J61PGrs46nfRkfsq0/8ErGTKBxyudR2KvI= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= From ed798d795e7d7b6475e9ed2e495a26e71c798ce2 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Wed, 17 Jun 2020 17:51:00 +0300 Subject: [PATCH 329/506] Fix timestamp for BNB notifications (#1147) * Change normalizeTxsToExplorer() * Fix tests --- platform/binance/block.go | 2 +- platform/binance/block_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/binance/block.go b/platform/binance/block.go index 90b931d90..be0beb46b 100644 --- a/platform/binance/block.go +++ b/platform/binance/block.go @@ -63,7 +63,7 @@ func normalizeTxsToExplorer(txV2 TxV2) ExplorerTxs { tx.HasChildren = 1 } if t, err := time.Parse(time.RFC3339, txV2.Timestamp); err == nil { - tx.Timestamp = t.Unix() + tx.Timestamp = t.Unix() * 1000 } mts := make([]MultiTransfer, len(txV2.SubTransactions)) diff --git a/platform/binance/block_test.go b/platform/binance/block_test.go index 6baaf37df..d2c05383c 100644 --- a/platform/binance/block_test.go +++ b/platform/binance/block_test.go @@ -74,7 +74,7 @@ var ( HasChildren: 0, Memo: "", MultisendTransfers: []MultiTransfer{}, - Timestamp: 1588086357, + Timestamp: 1588086357000, ToAddr: "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", TxFee: 0.000375, TxHash: "4577CB3B5B202696E9E0B093A6DA973C7DD9CBC6808DA1326872745C35F3C089", @@ -89,7 +89,7 @@ var ( HasChildren: 1, Memo: "multisend", MultisendTransfers: bep2MultisendTransfer, - Timestamp: 1586464452, + Timestamp: 1586464452000, TxHash: "FAD8C1C5E450BE5E0913B12007AAEACC307F8CFFAFFB0844A9F83155E1235C25", TxType: "TRANSFER", Value: 0, From 20efcf8b85e04174f0e67d9e18ba2d41d3b5806c Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov Date: Wed, 17 Jun 2020 21:44:14 +0300 Subject: [PATCH 330/506] Add make swag to CI test pipeline, update Makefile and swagger docs (#1149) * Add make swag to CI test pipeline, update Makefile * Update swagger --- .github/workflows/ci.yml | 3 +++ Makefile | 18 ++++++++++++------ api/endpoint/token.go | 2 +- docs/docs.go | 30 +++++++++++++----------------- docs/swagger.json | 27 ++++++++++++--------------- docs/swagger.yaml | 26 ++++++++++++-------------- 6 files changed, 53 insertions(+), 53 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cfc01ce6..92f9b3693 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,9 @@ jobs: - name: Lint run: make lint + - name: Swagger + run: make swag + - name: Build run: make go-build diff --git a/Makefile b/Makefile index f2c29bcfa..b8f2a56d5 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,9 @@ GEN_COIN_FILE := coin/gen.go GOBASE := $(shell pwd) GOBIN := $(GOBASE)/bin GOPKG := $(.) +# A valid GOPATH is required to use the `go get` command. +# If $GOPATH is not specified, $HOME/go will be used by default +GOPATH := $(if $(GOPATH),$(GOPATH),~/go) # Environment variables CONFIG_FILE=$(GOBASE)/config.yml @@ -150,8 +153,15 @@ govet: go-vet ## golint: Run golint. lint: go-lint-install go-lint -## docs: Generate swagger docs. -docs: go-gen-docs + +install-swag: +ifeq (,$(wildcard test -f $(GOPATH)/bin/swag)) + @echo " > Installing swagger" + @-bash -c "go get github.com/swaggo/swag/cmd/swag" +endif + +swag: install-swag + @bash -c "$(GOPATH)/bin/swag init --parseDependency -g ./cmd/api/main.go -o ./docs" ## install-newman: Install Postman Newman for tests. install-newman: @@ -253,10 +263,6 @@ go-gen-coins: @echo " > Generating coin file" COIN_FILE=$(COIN_FILE) COIN_GO_FILE=$(COIN_GO_FILE) GOBIN=$(GOBIN) go run -tags=coins $(GEN_COIN_FILE) -go-gen-docs: - @echo " > Generating swagger files" - swag init -g ./cmd/api/main.go -o ./docs - go-goreleaser: @echo " > Releasing a new version" GOBIN=$(GOBIN) scripts/goreleaser --rm-dist diff --git a/api/endpoint/token.go b/api/endpoint/token.go index 606ce4a77..f1535f13f 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -18,7 +18,7 @@ import ( // @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 -// @Failure 500 {object} model.ErrorResponse +// @Failure 500 {object} ErrorResponse // @Router /v2/{coin}/tokens/{address} [get] func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { address := c.Param("address") diff --git a/docs/docs.go b/docs/docs.go index a066c814e..465e12021 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,6 +1,5 @@ // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT -// This file was generated by swaggo/swag at -// 2020-06-09 13:15:24.760729 +0300 MSK m=+0.130569342 +// This file was generated by swaggo/swag package docs @@ -61,7 +60,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -106,7 +105,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -260,7 +259,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -300,7 +299,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -348,7 +347,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -390,7 +389,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -432,7 +431,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -471,7 +470,7 @@ var doc = `{ "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -563,7 +562,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -785,23 +784,20 @@ var doc = `{ "$ref": "#/definitions/endpoint.AddressBatchRequest" } }, - "model.ErrorDetails": { + "endpoint.ErrorDetails": { "type": "object", "properties": { - "code": { - "type": "integer" - }, "message": { "type": "string" } } }, - "model.ErrorResponse": { + "endpoint.ErrorResponse": { "type": "object", "properties": { "error": { "type": "object", - "$ref": "#/definitions/model.ErrorDetails" + "$ref": "#/definitions/endpoint.ErrorDetails" } } } diff --git a/docs/swagger.json b/docs/swagger.json index c9702ec99..610ae0451 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -40,7 +40,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -85,7 +85,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -239,7 +239,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -279,7 +279,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -327,7 +327,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -369,7 +369,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -411,7 +411,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -450,7 +450,7 @@ "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -542,7 +542,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/model.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -764,23 +764,20 @@ "$ref": "#/definitions/endpoint.AddressBatchRequest" } }, - "model.ErrorDetails": { + "endpoint.ErrorDetails": { "type": "object", "properties": { - "code": { - "type": "integer" - }, "message": { "type": "string" } } }, - "model.ErrorResponse": { + "endpoint.ErrorResponse": { "type": "object", "properties": { "error": { "type": "object", - "$ref": "#/definitions/model.ErrorDetails" + "$ref": "#/definitions/endpoint.ErrorDetails" } } } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index e57ba914c..836b13e3d 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -140,17 +140,15 @@ definitions: items: $ref: '#/definitions/endpoint.AddressBatchRequest' type: array - model.ErrorDetails: + endpoint.ErrorDetails: properties: - code: - type: integer message: type: string type: object - model.ErrorResponse: + endpoint.ErrorResponse: properties: error: - $ref: '#/definitions/model.ErrorDetails' + $ref: '#/definitions/endpoint.ErrorDetails' type: object type: object info: @@ -180,7 +178,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/model.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Lookup .eth / .zil addresses tags: - Naming @@ -213,7 +211,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/model.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Stake Delegations tags: - Staking @@ -240,7 +238,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/model.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Validators tags: - Staking @@ -273,7 +271,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/model.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Tokens tags: - Transactions @@ -302,7 +300,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/model.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Transactions tags: - Transactions @@ -331,7 +329,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/model.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Transactions by XPUB tags: - Transactions @@ -361,7 +359,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/model.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Lookup .eth / .zil addresses tags: - Naming @@ -457,7 +455,7 @@ paths: "400": description: Bad Request schema: - $ref: '#/definitions/model.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get staking info by coin ID tags: - Staking @@ -496,7 +494,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/model.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Collection tags: - Collections From bcf8ea5a1be162ac559d7b8432ae56aa03647b4a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2020 17:29:12 +0300 Subject: [PATCH 331/506] Bump github.com/prometheus/client_golang from 1.6.0 to 1.7.0 (#1150) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.6.0 to 1.7.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/master/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.6.0...v1.7.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 4 +--- go.sum | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 12e591646..df0c04bb8 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,6 @@ require ( github.com/elastic/go-sysinfo v1.3.0 // indirect github.com/elastic/go-windows v1.0.1 // indirect github.com/gin-gonic/gin v1.6.3 - github.com/golang/protobuf v1.4.2 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/jinzhu/gorm v1.9.13 github.com/mitchellh/mapstructure v1.3.2 @@ -28,7 +27,7 @@ require ( github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.6.0 + github.com/prometheus/client_golang v1.7.0 github.com/shopspring/decimal v1.2.0 github.com/sirupsen/logrus v1.6.0 github.com/spf13/viper v1.7.0 @@ -46,7 +45,6 @@ require ( go.uber.org/atomic v1.6.0 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f - golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect golang.org/x/tools v0.0.0-20200513175351-0951661448da // indirect gopkg.in/yaml.v2 v2.3.0 gotest.tools v2.2.0+incompatible // indirect diff --git a/go.sum b/go.sum index 530452bd5..4efd1c080 100644 --- a/go.sum +++ b/go.sum @@ -252,6 +252,7 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -347,6 +348,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= +github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U= +github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -358,6 +361,7 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -366,6 +370,7 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -564,6 +569,7 @@ golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslY golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= From 36ebc62215d855ed7d9b34e57e8d11857d62696d Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 18 Jun 2020 19:01:33 +0300 Subject: [PATCH 332/506] Fix transactions api by changing filterTransactionsByToken() (#1151) * Fix transactions api by changing filterTransactionsByToken() * Add tests --- api/endpoint/transaction.go | 14 +++++++++++++- api/endpoint/transaction_test.go | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 api/endpoint/transaction_test.go diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 4cabba8b3..d75579aa0 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -155,10 +155,22 @@ func filterTransactionsByToken(token string, txs blockatlas.TxPage) blockatlas.T result := make(blockatlas.TxPage, 0) for _, tx := range txs { switch tx.Meta.(type) { - case *blockatlas.TokenTransfer, blockatlas.TokenTransfer: + case blockatlas.TokenTransfer: if strings.EqualFold(tx.Meta.(blockatlas.TokenTransfer).TokenID, token) { result = append(result, tx) } + case *blockatlas.TokenTransfer: + if strings.EqualFold(tx.Meta.(*blockatlas.TokenTransfer).TokenID, token) { + result = append(result, tx) + } + case blockatlas.NativeTokenTransfer: + if strings.EqualFold(tx.Meta.(blockatlas.NativeTokenTransfer).TokenID, token) { + result = append(result, tx) + } + case *blockatlas.NativeTokenTransfer: + if strings.EqualFold(tx.Meta.(*blockatlas.NativeTokenTransfer).TokenID, token) { + result = append(result, tx) + } default: continue } diff --git a/api/endpoint/transaction_test.go b/api/endpoint/transaction_test.go new file mode 100644 index 000000000..e200e0f8b --- /dev/null +++ b/api/endpoint/transaction_test.go @@ -0,0 +1,22 @@ +package endpoint + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" +) + +var ( + beforeTransactions = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + wantedTransactions = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` +) + +func Test_filterTransactionsByToken(t *testing.T) { + var p blockatlas.TxPage + assert.Nil(t, json.Unmarshal([]byte(beforeTransactions), &p)) + result := filterTransactionsByToken("BUSD-BD1", p) + rawResult, err := json.Marshal(result) + assert.Nil(t, err) + assert.Equal(t, wantedTransactions, string(rawResult)) +} From 69a7d06835d337193845157104a11d94dcd0569c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2020 19:25:53 +0300 Subject: [PATCH 333/506] Bump github.com/jinzhu/gorm from 1.9.13 to 1.9.14 (#1152) Bumps [github.com/jinzhu/gorm](https://github.com/jinzhu/gorm) from 1.9.13 to 1.9.14. - [Release notes](https://github.com/jinzhu/gorm/releases) - [Commits](https://github.com/jinzhu/gorm/compare/v1.9.13...v1.9.14) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index df0c04bb8..f69e5e8ea 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/elastic/go-windows v1.0.1 // indirect github.com/gin-gonic/gin v1.6.3 github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect - github.com/jinzhu/gorm v1.9.13 + github.com/jinzhu/gorm v1.9.14 github.com/mitchellh/mapstructure v1.3.2 github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/image-spec v1.0.1 // indirect diff --git a/go.sum b/go.sum index 4efd1c080..3107f60e5 100644 --- a/go.sum +++ b/go.sum @@ -28,6 +28,7 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -41,6 +42,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -240,6 +242,8 @@ github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= github.com/jinzhu/gorm v1.9.13 h1:fcdacwmUcoyon8XHkQrdPJZ7pnHAYclHZ6iLYER5nX4= github.com/jinzhu/gorm v1.9.13/go.mod h1:C0zfmO9z9J61PGrs46nfRkfsq0/8ErGTKBxyudR2KvI= +github.com/jinzhu/gorm v1.9.14 h1:Kg3ShyTPcM6nzVo148fRrcMO6MNKuqtOUwnzqMgVniM= +github.com/jinzhu/gorm v1.9.14/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= @@ -289,6 +293,7 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -506,6 +511,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -527,7 +533,9 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= From aeb9222185c0f6a151acd8cf81fd776fb344ad97 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Sat, 20 Jun 2020 19:30:34 +0300 Subject: [PATCH 334/506] Change stake api (Tezos) (#1153) * Start to change stake api * Filter tezos validators * Add test --- api/endpoint/staking.go | 3 +- go.sum | 3 + pkg/blockatlas/platform.go | 1 + platform/algorand/stake.go | 14 +++- platform/cosmos/stake.go | 16 ++++- platform/harmony/stake.go | 16 ++++- platform/iotex/stake.go | 13 ++++ platform/ontology/stake.go | 14 +++- platform/solana/stake.go | 16 ++++- platform/tezos/model.go | 68 ++++++++++--------- platform/tezos/rpc.go | 11 +++ platform/tezos/stake.go | 23 +++++++ platform/tezos/stake_test.go | 26 +++++++ platform/tron/stake.go | 20 ++++-- platform/vechain/stake.go | 14 +++- services/assets/client.go | 22 ++++++ services/assets/{stake.go => validator.go} | 31 +-------- .../{stake_test.go => validator_test.go} | 0 18 files changed, 237 insertions(+), 74 deletions(-) create mode 100644 services/assets/client.go rename services/assets/{stake.go => validator.go} (69%) rename services/assets/{stake_test.go => validator_test.go} (100%) diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index f4e6b5bcd..74a1dd8d4 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -5,7 +5,6 @@ import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/services/assets" "net/http" "sort" "strconv" @@ -155,7 +154,7 @@ func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { // @Failure 500 {object} ErrorResponse // @Router /v2/{coin}/staking/validators [get] func GetValidators(c *gin.Context, api blockatlas.StakeAPI) { - results, err := assets.GetActiveValidators(api) + results, err := api.GetActiveValidators() if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return diff --git a/go.sum b/go.sum index 3107f60e5..3f5f34697 100644 --- a/go.sum +++ b/go.sum @@ -366,6 +366,7 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -375,6 +376,7 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -577,6 +579,7 @@ golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslY golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 177de17ab..296c3c103 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -48,6 +48,7 @@ type ( GetDetails() StakingDetails GetValidators() (ValidatorPage, error) GetDelegations(address string) (DelegationsPage, error) + GetActiveValidators() (StakeValidators, error) } CollectionsAPI interface { diff --git a/platform/algorand/stake.go b/platform/algorand/stake.go index 4adfa2f39..910aa9aed 100644 --- a/platform/algorand/stake.go +++ b/platform/algorand/stake.go @@ -1,13 +1,25 @@ package algorand import ( + "github.com/trustwallet/blockatlas/services/assets" "strconv" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + result := make(blockatlas.StakeValidators, 0, len(validators)) + for _, v := range validators { + result = append(result, v) + } + return result, nil +} + func (p *Platform) GetDetails() blockatlas.StakingDetails { - //TODO: Find a way to have a dynamic return blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: 6.1}, MinimumAmount: "0", diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index 5b8bf46ea..09515c4d1 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -5,7 +5,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" - services "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/blockatlas/services/assets" "strconv" "time" ) @@ -15,6 +15,18 @@ const ( minimumAmount = "1" ) +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + result := make(blockatlas.StakeValidators, 0, len(validators)) + for _, v := range validators { + result = append(result, v) + } + return result, nil +} + func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { results := make(blockatlas.ValidatorPage, 0) validators, err := p.client.GetValidators() @@ -84,7 +96,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e if delegations.List == nil && unbondingDelegations.List == nil { return results, nil } - validators, err := services.GetValidatorsMap(p) + validators, err := assets.GetValidatorsMap(p) if err != nil { return nil, err } diff --git a/platform/harmony/stake.go b/platform/harmony/stake.go index 706465465..ef7e57ec1 100644 --- a/platform/harmony/stake.go +++ b/platform/harmony/stake.go @@ -4,7 +4,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" - services "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/blockatlas/services/assets" "math/big" "strconv" ) @@ -13,6 +13,18 @@ const ( lockTime = 604800 // in seconds (7 epochs or 7 days) ) +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + result := make(blockatlas.StakeValidators, 0, len(validators)) + for _, v := range validators { + result = append(result, v) + } + return result, nil +} + func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { results := make(blockatlas.ValidatorPage, 0) validators, err := p.client.GetValidators() @@ -64,7 +76,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e return nil, err } - validators, err := services.GetValidatorsMap(p) + validators, err := assets.GetValidatorsMap(p) if err != nil { return nil, err } diff --git a/platform/iotex/stake.go b/platform/iotex/stake.go index dc8b24fb9..bdab23966 100644 --- a/platform/iotex/stake.go +++ b/platform/iotex/stake.go @@ -2,8 +2,21 @@ package iotex import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/assets" ) +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + result := make(blockatlas.StakeValidators, 0, len(validators)) + for _, v := range validators { + result = append(result, v) + } + return result, nil +} + func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { return p.client.GetValidators() } diff --git a/platform/ontology/stake.go b/platform/ontology/stake.go index 135434405..ed6f84491 100644 --- a/platform/ontology/stake.go +++ b/platform/ontology/stake.go @@ -3,14 +3,26 @@ package ontology import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/services/assets" ) const ( - // TODO: Find a way to have a dynamic APR // The current value comes from https://cryptoslate.com/coins/ontology Annual = 4.45 ) +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + result := make(blockatlas.StakeValidators, 0, len(validators)) + for _, v := range validators { + result = append(result, v) + } + return result, nil +} + func (p *Platform) GetDetails() blockatlas.StakingDetails { return blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: Annual}, diff --git a/platform/solana/stake.go b/platform/solana/stake.go index 6babc8ef3..3cbbe0b33 100644 --- a/platform/solana/stake.go +++ b/platform/solana/stake.go @@ -7,7 +7,7 @@ import ( "github.com/btcsuite/btcutil/base58" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" - services "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/blockatlas/services/assets" "strconv" ) @@ -17,6 +17,18 @@ func arrayOfPubkey(pubkey string) [32]byte { return array } +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + result := make(blockatlas.StakeValidators, 0, len(validators)) + for _, v := range validators { + result = append(result, v) + } + return result, nil +} + func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { results := make(blockatlas.ValidatorPage, 0) @@ -83,7 +95,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e return make(blockatlas.DelegationsPage, 0), nil } - validators, err := services.GetValidatorsMap(p) + validators, err := assets.GetValidatorsMap(p) if err != nil { return nil, err } diff --git a/platform/tezos/model.go b/platform/tezos/model.go index 836b4fbb1..02f93bfbe 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -13,42 +13,48 @@ const ( TxStatusApplied string = "applied" ) -type Account struct { - Balance string `json:"balance"` - Delegate string `json:"delegate"` -} +type ( + Account struct { + Balance string `json:"balance"` + Delegate string `json:"delegate"` + } -type ExplorerAccount struct { - Transactions []Transaction `json:"ops"` -} + ExplorerAccount struct { + Transactions []Transaction `json:"ops"` + } -type Transaction struct { - Delegate string `json:"delegate"` // Current delegate (may be self when registered as delegate). - Errors []Error `json:"errors"` // Operation status applied, failed, backtracked, skipped. - Fee float64 `json:"fee"` // Total fee paid (and frozen) by all operations. - Hash string `json:"hash"` // Operation hash. - Height uint64 `json:"height"` - IsSuccess bool `json:"is_success"` // Flag indicating operation was successfully applied. - Receiver string `json:"receiver"` - Sender string `json:"sender"` - Stat string `json:"status"` // Operation status applied, failed, backtracked, skipped. - Time string `json:"time"` // Block time at which the operation was included on-chain e.g: 2019-09-28T13:10:51Z - Type string `json:"type"` // Operation type, one of activate_account, double_baking_evidence, double_endorsement_evidence, seed_nonce_revelation, transaction, origination, delegation, reveal, endorsement, proposals, ballot. - Volume float64 `json:"volume"` -} + Transaction struct { + Delegate string `json:"delegate"` // Current delegate (may be self when registered as delegate). + Errors []Error `json:"errors"` // Operation status applied, failed, backtracked, skipped. + Fee float64 `json:"fee"` // Total fee paid (and frozen) by all operations. + Hash string `json:"hash"` // Operation hash. + Height uint64 `json:"height"` + IsSuccess bool `json:"is_success"` // Flag indicating operation was successfully applied. + Receiver string `json:"receiver"` + Sender string `json:"sender"` + Stat string `json:"status"` // Operation status applied, failed, backtracked, skipped. + Time string `json:"time"` // Block time at which the operation was included on-chain e.g: 2019-09-28T13:10:51Z + Type string `json:"type"` // Operation type, one of activate_account, double_baking_evidence, double_endorsement_evidence, seed_nonce_revelation, transaction, origination, delegation, reveal, endorsement, proposals, ballot. + Volume float64 `json:"volume"` + } -type Error struct { - ID string `json:"id"` - Kind string `json:"kind"` -} + Error struct { + ID string `json:"id"` + Kind string `json:"kind"` + } -type Status struct { - Indexed int64 `json:"indexed"` -} + Status struct { + Indexed int64 `json:"indexed"` + } -type Validator struct { - Address string `json:"pkh"` -} + Validator struct { + Address string `json:"pkh"` + } + + ActivityValidatorInfo struct { + Deactivated bool `json:"deactivated"` + } +) func (t *Transaction) Status() blockatlas.Status { switch t.Stat { diff --git a/platform/tezos/rpc.go b/platform/tezos/rpc.go index 2f4cb6955..1e068888c 100644 --- a/platform/tezos/rpc.go +++ b/platform/tezos/rpc.go @@ -3,6 +3,7 @@ package tezos import ( "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "time" ) type RpcClient struct { @@ -29,3 +30,13 @@ func (c *RpcClient) GetAccount(address string) (account Account, err error) { err = c.Get(&account, "chains/main/blocks/head/context/contracts/"+address, nil) return } + +func (c *RpcClient) fetchValidatorActivityInfo(id string) (ActivityValidatorInfo, error) { + var info ActivityValidatorInfo + path := fmt.Sprintf("/chains/main/blocks/head/context/delegates/%s", id) + err := c.GetWithCache(&info, path, nil, time.Minute*5) + if err != nil { + return ActivityValidatorInfo{}, err + } + return info, nil +} diff --git a/platform/tezos/stake.go b/platform/tezos/stake.go index e83a9c8ae..25e0ebc27 100644 --- a/platform/tezos/stake.go +++ b/platform/tezos/stake.go @@ -12,6 +12,29 @@ const ( MinimumStakeAmount = "0" ) +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + result := make(blockatlas.StakeValidators, 0, len(validators)) + for _, v := range validators { + if p.isValidatorActive(v.ID) { + result = append(result, v) + } + } + return result, nil +} + +func (p *Platform) isValidatorActive(id string) bool { + res, err := p.rpcClient.fetchValidatorActivityInfo(id) + if err != nil { + logger.Error("Tezos activity validator " + err.Error()) + return false + } + return !res.Deactivated +} + func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { account, err := p.rpcClient.GetAccount(address) if err != nil { diff --git a/platform/tezos/stake_test.go b/platform/tezos/stake_test.go index cf8a50983..7fb4e8ad4 100644 --- a/platform/tezos/stake_test.go +++ b/platform/tezos/stake_test.go @@ -2,8 +2,11 @@ package tezos import ( "encoding/json" + "fmt" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "net/http" + "net/http/httptest" "testing" ) @@ -72,3 +75,26 @@ func TestNormalizeDelegations(t *testing.T) { assert.NoError(t, err) assert.Equal(t, delegation, result) } + +func TestPlatform_isValidatorActive(t *testing.T) { + server := httptest.NewServer(createMockedAPI()) + defer server.Close() + + p := Init(server.URL, server.URL) + assert.True(t, p.isValidatorActive("tz1V3yg82mcrPJbegqVCPn6bC8w1CSTRp3f8")) +} + +var mockedTezosResponse = `{"balance":"19924380870","frozen_balance":"16854253212","frozen_balance_by_cycle":[{"cycle":240,"deposit":"3072000000","fees":"15676","rewards":"90000000"},{"cycle":241,"deposit":"3328000000","fees":"621522","rewards":"95000000"},{"cycle":242,"deposit":"3648000000","fees":"4360","rewards":"101250000"},{"cycle":243,"deposit":"3392000000","fees":"28321","rewards":"125833333"},{"cycle":244,"deposit":"2816000000","fees":"0","rewards":"55000000"},{"cycle":245,"deposit":"128000000","fees":"0","rewards":"2500000"}],"staking_balance":"163002104470","delegated_contracts":["tz1YGsmfUfed8fmG4QLhGB1Y3gCMX44t1JTc","tz1WnfCXDniXhHzbXEPTQ1JSoyb7EzotYJs3","tz1RqtpgLw3uedpWaDVC5WAdvNfiUnsY7ZC5","tz1eLjmx4j7QLX2RabyS8Pf3sSe1U6H2UZji","tz1TYhMcdYah6QJWQbL853x4Rn6fSvtHhqDf","tz1XcmqCntUEzrpV6xcvw449Ro83KU5W3vv6","tz1QfbGBmr5dvha6agPcmsvnaz2EfcctW4ZJ","tz1bN4kotiEE7dAEsTGWpNTF2DnjJw9NNSoD","tz1hoj3Lw71qgsQf5a7cdhdU9crEH3mAAaNn","tz1SfvgWvSBxNsgta6UCmytMTPHzMsmjMB54","tz1ZsKynrRs8KNe3ao1ZMaKk6he6VUWtjcFU","tz1ZEKCiu7QspFVZL1svyr9vvir7tTm5CEdW","tz1gScW33c2EjpusjaPCm7r82QVZsALnNsXk","tz1TDnm46TxwLRbihJf2yTQLJGJYe6k7N3Kw","tz1NQCizMgAvmjhMJEidnTNPFEPHxA6XLY65","tz1dp6YqFkjoDZqrceSEC7cKFDEWbynyv7UV","tz1RctGdDVhQFoqL99bXJvYTwQNJWEL2Rx6Y","tz1hqd37vwxZcNeiNMrz6kpujusPRxcaFyhv","tz1crpuStZ66tv89kZMQbiGHk2C2RyD87o2S","tz1a45AtW3gs964AxC7X2sShAj9wsBGQjsWQ","tz1Xi1AtnoAv74PAQFDUY67TEjww1J2e6FaQ","tz1XqSWe3M9eEd2mueqEWmgKZLoYVJCRC92B","tz1Y5JZMUEsuX9oicG9AqXG8XWPHmKeWFrb8","tz1LVtuGkbCgEZsZhbzu1sonVg5xZyrrWqGD","tz1cfqx7H6qsXgsLTHFn7hWjdkU1SjpzpFyx","tz1SFMBqUwq6JJP1mQZfp8ae4GsfGSM8812Y","tz1LeU73Tm2eBcUV1prcHLjK1Pb7KgC8rPTu","tz1dMvyK57FBfUqzSenaWSoY1Rng77KxwTT8","tz1S382giorXLVdzw79LVcMj5MLJkYK8Ex8d","tz1TAscJC43xhPBNBESuNupw3FhLsfE4Ghxd","tz1eACKAsqr5faLgsE3ACdHeejrdM4igY2qj","tz1Ln7pr3Bf7Yxmnf57iEkgEUvo7PrMh3HJh","tz1XC1DbtQjUu2udaeVbSa3G2rrU9dJKmN6V","tz1PCa2Drre9MaJ5pcKpQHh8A75LDEYYA4rq","tz1S7SacT3Pe8EfDfMEnR7fdvDamZDiwVMoQ","tz1U6V2mWc6zd31yFXME5Xnoifo3PeHQhuJA","tz1V54Uhpp2i8pUVEFNcmhrkJqfDZhqb5F5C","tz1aTmVHkGBChKHfAqdJjjadkP4rz4MDjbJS","tz1dpijoKv5dCFT1BvtEmxy4YLcCsAc9ZGeh","tz1Mmv9StLbPu3jYVBDoKgNJTb3FD5wuA2vA","tz1PkJZs2Eb3ouLd9cTf4wSQ3n9aMz7YLGNR","tz1YpTsHeubr7WQaKu3Yfs3m1gKw5QP1MbdM","tz1ZP1EgEkNwB1nYA8bQdJ7YcttsbJuJCZLe","tz1Wh7XciNS6oUTW14bQ5PD7pQjqae2tNA8S","tz1bgRKKwMc4s8fxTDJrauCx3NoGLSRJ5B49","tz1URZ8CPFhzLz3UjQD9zUjTZY38XwGTCiKn","tz1KrUvC8nUGRnk4RXtqAFLsJj4cbtXjR5Wg","tz1f8eDjy48LDcWrrNTF3wwkGEjyXqDcoMro","tz1RStdCWJXpVVvYvAB5VZXgzrxPGoHpEhjK","tz1LWjsR3LiBDPyvuf7S1qJxaVKNZV9TSbaW","KT1DMboG5KtaPbMTaA2PeV8FqRcqbt9adzQE","tz1iq1eA7i2ogVCQ52g3zeSEqCrFTSVxhE2c","tz1Y9tfG6Gs5oFdLtcE9obQaxbwZyK8CTn6e","tz1XotDGePt679YtqexwfFvE9AutjdkvemH2","tz1LG4KEFVjp1MxSCXQWUSyoZpE4Nq3gbxHy","tz1TMRCpNgKAdp8GH3jXAVR3MuLMMPZBzevi","tz1hZY5ix3GTTUMAsv6anwD2817RspnnEb81","tz1gzPsf717fNkpFVQYuNAKBBQngqGx6CFJz","tz1TTxhXmRRdMAKdF7ykdyybgg1baD686JWs","tz1dPnbKhnmJo3J7S2rokMSmTtaWNGDeQuYa","tz1irRBG7qLAeo6URDn4bnUb9NByoLQUHN7K","tz1d9d9brjpFRrErRF8tT5StDve7svAQueTB","tz1SBRVFKJCaDnPRzHrn1Pc7NG61tqNY1HpM","tz1h4Ag9NixUomVaFo8MatDpEL84JEEs9oFx","tz1NVzxdVF2gy276bGAt3TFJHWUMtnS5BZrN","tz1Ytb5C7xDvWArsif3cEfWC7NpEiWkGVcW4","tz1WQ4w3WQUzReKAehyDKkVQjiVNJLuWoCrx","tz1StPqh4Jybs5yE4adLLBvrirwm7cuoEMC3","tz1f5yKJQwdEx1XbqUreT5E5MG2ddoP9sxG6","tz1hVxLkK7fDPCsgRytKyqSYoRGdPYkRAHK4","tz1Qs7gcTNMN759qBUukQmfA6cUeWzqtU7sq","tz1SsR67T1ykErBtVinVMCWhvwrUWBMkzxQu","tz1QD8a5kJBGHArP1DHECBzj4gbRPZuBGGL9","tz1inQ6S764Btu5HgHRGMg72Tee5UjQtri7y","tz1asvE47tkUoYPrb6HrVzkHVhfx3roZA56f","tz1ZqdsHNTeYLCw3Etw1BwMTRbU3Ji42HT4N","tz1Zd43K6xBnpddV2pv2PcbKPBXpYo6qAAxc","tz1YbEBGE1KQXAMLiQEnXVKLoNKVAmtQxJ2y","tz1QFhih66LJDFpm9T6a2gWdg7551k65C9ke","tz1T4RpJjC671WadSwA145zMZNSCmvcwGL5R","tz1Pibvp7EttcPX56CTvmxPsSLqwsDhd2fC1","tz1cFu4B4afDVkcojpv43h7wbv8169VA7mSU","tz1ixKgGdRoSzsp57qe5WXHLbeu2GRpXYmGW","KT1M6T4ft8UXXwFxa6QxRU3T1JDEKQBRK8Li","tz1csRh2tzRZw8dcuAm1LMCMUQBEq7N3EmY7","tz1gaz2QgwUTyZypSmMx72oUrraD1hZ4CWEB","tz1TpW2WB8Y9mYsDp2Lx4EoKcocyFWApScFy","tz1f9Hg7KF6xKLabL4UNLPdtJeohQbuJrVa2","tz1Q8Q7sT3r7pdGGyYEtX7v6jTxCwJ3bSdtJ","tz1iLAxh9M6xcaNMVhb5hGxZb9qvzBVwo5UT","tz1XXHuK4tMKJZBQDeDFCpzWdH4g26Q42gFW","tz1VvZYohqJvKzTKsRYcfuQuak6LYFao9hkD","KT1E6sM9KBpYWoK7ZxoxrcAzbngVhn9ZxkPw","tz1TuBtRJ5bGa7KRyhiZcoFiZTHXnuq4wz4X","tz1fQRtYbQqenvb171siK8KqScBZKHrsqKW4","tz1dn9tn4UqhwLiAShcaq63oiwzQ7X8aySTz","tz1Uvknh1VNhYYQbhFaP1rDU1GNtFpGWG98c","tz1ZosT8MD6tibQDYLbhfTm5Z9oQPL2f7LwP","tz1Yk9Mz6hSBrq7qWLUZKDqcuwyu19i7FS4Q","tz1i5wEnEp1Wf4WiL7dFxiTj81VSiDprGWyZ","tz1fQv9BGCjZC29DFPSmqNxkjFx2tLzRy9Kn","tz1M7TVpisBJfPkkjrfsnK7CZyRbVb2Vdooa","tz1TJ6ZPJVrAFZUNhReL9FnhzXXd86Hmtk3d","tz1hbeGj3krpLMdKMumeukTatZcDCG9RGnyT","tz1Xm41xUyqvV5caWkpx1ym2p8uTvJPKZMdw","tz1XZEpd7EnfzmjYKfRY2zrfEd4trBJWBybN","tz1QZAQoaXbLXW3WjYB8os5xjwe4mB62KjPi","tz1gd8XNS2Me4oRXq9XTkTX9kYumRM4Y6rXf","tz1aK1rKDWDSa31kB1SwP1tD3BvPTNQWXwwK","tz1Ui8BtvQpJpF155ppgMZSEpCKEDuLXNMX4","tz1ioGHFTom3ojBbcfgEb8mt1f1ceobVEcEq","tz1LxreKnQEFW2QB3dZDX1bNThcW8vmem4E8","tz1gu2wRjBfY7jpMokMDZGNZVBE5n98J65g4","tz1dfAqA9rhx1tFuu86FdhBwKMwaisVe1dEg","tz1ND2YvsV6mnWSUHA2bd1oUcTmshMbxYV1M","tz1aSBidSCjNqLcEk8BYvA43EenEZNtsvkuW","tz1e8Fk5whgxrPzTZAMiW2FbatdaABNt5hpX","tz1QeU3SH1pGYTWmKfZKovH2RiiqSnd3zFPo","tz1UkUgyb3Au9GeQx6YbcJJaafNDpgGRLDeV","tz1WPnZxticG6xGpHNhaV9kvU1PfgYiMXp7A","tz1LKVTXzQtDwQWXJpbe88Q2U5TceBrEJf5i","tz1X4tzFR73YRBBora46aevdGn3aqz5UzdrJ","tz1PouWF6hyoHmMYAGuwDBAXJKL4Z8yixEwq","tz1ib38e3VCZgvRxc2Gj6KtAgAv9FkWx3xt1","tz1Ndenm8uaonPs8oo7iqXQ6RRho6cG8GBd1","tz1WRAfQ4c98Lxz5k2j5QFwcaw31Z6zSuiza","tz1W7G8pgorMWDcWSsTpQLuQoKqVPk6MNTV5","tz1NY7t1otGmLV9VuhdApzsqwwqGEK6iLeyH","tz1MA5ywEYaPNzJWeLWBDfvAfZmryeFdrexy","tz1Rzq5gz824wG4gt4MPX13oKojnY3cJVTAB","KT1MmHkxDKy16ETe6CKY6Hs3SXGzAeMKHcmy","tz1aYL7YjKn8zFV8kCNMg5qjJTXQ5sPhnVQU","tz1Mqazkg2SgqB4ibXxpFudp2HVYEZ2s3t59","tz1X1o4zSNrnTDouETFM9AXQzamWcUkEj59n","tz1Qe9fqiQnizh5gzuURT3J24MQxd7A9qxTt","tz1UWyf2N1yCiEkfyCKdyMitKMAaUWACWpro","tz1LYCQsxVf2RdDEWcG5N1zY72XskyXevciC","tz1XD2yz8UQYGJ6BRb7h7wZp854fQXC9DQFm","tz1iiT4XbLvffTJbGhuiCg3ofaaNdLX2thSu","tz1YrCk1KZu9wwn9vCUYuZp8medpViizrZwK","tz1QPmsd6BS9CUAugcNGJP9me8V6qtEEYrV8","tz1adgGe3ghX6DH7kh1BAasaCGrf6ermGY53","tz1M7PNxBBCUx14jfdv5ZERWZWBhPJVjKHJD","tz1VcWpMRqd5xxoauw1urcnPQ2kZZxhbqgcv","tz1Y2nVkzQQmdVnDcuo6VDAgnBufoUHLXR3r","tz1bGvZzpjJZHzFJGQYWPVg4JQ7arsmX3CBW","tz1ZGn1qwM2Bg65xqNx37XB4ptSQnRh7LjED","tz1Pku546auwaUBm4Wht1zwZtfxg7ic81p6Z","tz1R5yUME8wSYtyZNpfWdoPZcQgNLtaUUvef","tz1b5HuS35FKB7qWvFuALXX6ZFspEWWJVjxP","tz1ihSZ12F2y6H778E6L4ciWzvX7rfPwmGQd","tz1T4yyuchdPqtZSbtsaBS3GLqLeUg8dJmb4","tz1LnRcJUtFBKcht4n2jo2PAJF1ufwAVa1nL","tz1iwdFtYWaicwc1dfJA6YmN7eRCX1RkaGuz","tz1aD3HxUFLSr6tmYuP7HKvx7t8WgKTY5pYs","tz1XJMJ7XjbHkkFkAWw9C8ocjfmkmTBXo5TG","tz1PfUUZ1YTRqP7qkjsSR1X7TCeYbRpnCfaj","tz1aLVDxteKdmBRaRMcQPQaEL2ExbDwQA7fP","tz1QoFWg86UsKYjtskkmBkz58mftgHLrvrci","tz1ZWbmnG1sb4KCkrjii1FoiJ1RcJEg7Tf5V","tz1VGrdEoiWdSpUFGZAbX6hxuQAJjEXqXvwW","tz1Q8gvcfGC74oaWx2Gb4TipRLb7aEfsWyAG","tz1QVsVf5VQfihDiBED7ZMn5Ai637z9GwfpB","tz1Nqf8Do6NFXncMzGhYasnif7iTJ8UgGHTn","tz1KotnQg3tbzTLxYJc9XW3dagmYjAMHzYV7","tz1QzMbAcThy4EX8ENvHZm2BVxQMmCY7wsUw","tz1YKTfdWtb6gzr26mRsLsGCNK8TBBVEHC1E","tz1egRyJLzTmC4aMUCRZLKEhtYd2MyD9f8RP","tz1NJFR2PLvbijMGGZ9LnW88CZxo1SSFxsxR","tz1fU6Zxx14MCEqfkSwDWRMqFmYmhygSJrcK","tz1aN9Gp5FXc7CQoR8MGSf3VUFohe6f9rFJ6","tz1KuQ5yDerio8tW294zHsYofWc8TQ3xnbaJ","tz1Yi1qojMoS2JhESiE4vAeo7dWUqQbnEQeL","tz1RxecATFfopVUvE9HS45rL6rgzGVg4cFG2","tz1hXRjun9ou7YN7sFKJJsgHPkGpdXzamzKY","tz1dWg4SYTFiYfPrDGBNCaNZunjCi9CyK8PU","tz1N7CRoQTrTjM6BG6PK4XfwnkEERKj1GgTt","tz1T8RkwAcBBwc9uCovercc6Qr326ezqtoij","tz1UkDYB4RgqBcRL7yYSikc8r6fpAeRVP9c4","tz1WLjJEwxQK3hbnZWkmEzGzQ988MdQVq1iB","tz1bLijXE1D8XxHjzK9wBK2udxNqXbHkMzFg","tz1VMWRzCPN9E7NLBfSHxFVzjZ2vxNPKRXCT","tz1eUfNmzeZWccsAV2ZzCovjMR4HSDH6eiiq","tz1VASv4WieYkgmUCeh2j5ftEw72NkkuCDje","tz1fZH9g6npSMZgSGzcaqegnuftJ1AcNEQ6F","tz1QGzvcCDezxV439D5cjRaTFXC8Y2bF6qTw","tz1PxPHvFdkGY7XkyuV2eUDYH3wxuerKiYiC","tz1YJUngcjMCStvP7MABMVBPyFkU3BupNymQ","tz1NoKTHMvzPooEbyeMHQBaia7Ekf8aTrv8g","tz1aQHYPPW8dq7ucWUccV74cEyzt6AiMjrfj","tz1dpCdky48ELUbjrzY89Uy4fTukmmJdr9tJ","tz1SQcKWYJCatD4jVFRNtR8UVBmtZT5VAM3x","tz1a6rVyLh6z7akANZsBuxSb2g9gNthXuFM1","tz1eNv53m15QQhKYyREahAx6LCK9YYczEUPe","tz1Z5Lgu8CDhbWNdyEzXkCC2TrkHrSDVwMWp","tz1Prq1iQE4xMn3JqwK6rMaJXoGjS9sfWM3L","tz1hxtCEcD7idQJEDiJEq37vBkoRcwF6KC2X","tz1ZTmAakWGa9fefwoaomG7wFPQhPXepyxdT","tz1dXKPAsBG4DG6oKki84UVTBYw5doTGbu95","tz1ZGCukFkDD5ns2aA8HuKGrE68DVmbhLvvs","tz1cvSwVukfoTNS16f1Y12mHYqsrnCK2z7ZM","tz1PV34FXaBY5mqLLyjG8TdzNCo5SUz51d1a","tz1KxhXker6qezyPyzpLcTVXxAadWuaRMB8Y","tz1cZmvFJgdJfUoBF2USegkoEq653qx3KgxB","tz1M8NxQupHMQ5uW1k25wCYYdxMWojKfiVNa","tz1eqnkA7YZS5uVhH42WfZkwkECTxCkUqKJG","tz1Z2ERSqjQjTtGdv6XZJ9ZoffxAQVCLHrLM","tz1iXW4XFVvg1QS6bGhuPo1VCGT6WTgEaoA5","tz1VMDp7io6vgXo8jsLcgbsUB6Vc9mdAw69x","tz1edVs2PENzexqcwWv22pwu4HfcgXbKcV4R","tz1LSUEVASTpic9FawaAMtZgR39LSYmPYcLM","tz1REnhE8TEzXdcWSRrzBYPWuveyY61Pe79R","tz1TrDkd3wtJcYnXZiB1kdoHtDJ61eP4QMA2","tz1fKL8yNKW98UGCE5duxSyM11QqzFBvQW36","tz1dPXJpxXqqLeoCs3X4GfribJKfyFVH1Jta","tz1NhzBdBcokEFPuzfdMrjihST3WU1F7uTGe","tz1crd1XnXNsCfgXVaHzYpsAe6XBEuhcYRF5","tz1N7T11AEwWAoqE6pYyU8ZYcdfBnMyPmr4X","tz1f5V7ijjQ8WBN5UUAnQvGcdXg7cAPxGCUu","KT1Vhqza4MMuELxENaiBYc6UB7syRpaZ12LF","tz1g81GLa2GeT6AgQ3CxtYBdwD3kwMLR1Hpt","tz1ifm8828dvFuS8wbwqCGhyoGKoXMAkpqbz","tz1ZfX2axfXid7Bnt2BiSv6QonweVFuuaAhM","tz1aJtqVgev1Jrc4utBfgZDj83ZFLjJKiZJu","tz1TyyjZ9adDW6rranHNXQVqEMp4Zb2rhegW","tz1iZS4BRLqyLbWbyyKt3e9gvAa6MJnDM2qj","tz1XM3wst4ioyMBHdkCVMdo3nfqYzb6zqbpn","tz1g54U8WwX4h7sVAfwNAMfmN191E1nYD42V","tz1ifvWnxwudcmQptnvbb5aRyDyWLLdUJmv3","tz1RDNwx22yxJ5x24ZxsrqFtA4bXY4gtwm4Q","tz1YvE23HCvxMNPqWsgQyYMw8Rm2UeMnPCMs","tz1dYeNiX8ayqUAc1SzDnr1iy259L5Djf1Rg","tz1Xrk1gZ6UGs2zr1RBCgexckHpS8CjgtdX2","tz1cp2AxYptGFABzTbnEWo62Rhixc5HKpjFu","tz1SCWJXrAiGQmoBPMLGifjrbTi7HnKgEDdu","tz1fxbW6z9xts7LnbXqvcdoqwp13rBavG6hP","tz1imF1LwtUxRojZSK6povb8mePfxQyk7UiF","tz1faBfWwvmovgkngNv2v4bW313jrepqdjAW","tz1XPjXcjWvqiNC4erXakoCiMY9Xx3omBRvZ","tz1iuPqyGQepHBWiVgTTdndbpnfkqckQb94n","tz1Kuu9FQu6L4bkNwLt39BGWAMSfDefWMCR7","tz1eEea8fmMweaMGbtUSa3AVWE8pgC7WM5Ym","tz1ceedKUzespKvmnaZApaXXcZTDJdVjenBa","tz1QbVugeaLaXJXqgD9s1gAYMwAJkW9rTgn3","tz1NqVdJps7ppiy5EbahVuAmDw1iKjhHsXG9","tz1UJ6u1bGV182edaXg5uPdbJq1qHR6xdJSZ","tz1fQiLH4SyuXumvKejsnQZgdnJ33J3kCqk6","tz1SBTErzCAU6o85X4xTdRzzCHQ79JkmGgRx","KT1UXH1LJ33HSaEvzW1Pk92tLbGEdsqcN93q","tz1iRk79QEsJ6Lj5F7pGaTAiQKTYw9RSUqzU","tz1ZKvoYkCB8otTqdWp1Mm3WvemXMQCSpsgT","tz1R6esD6XuzJ7hrC3ngrWdafh9FFJ9NV3oT","tz1bsVgtu9zggDAMvHWPWZET1wMEMTfzDTL1","tz1ivnzrqG3bpXuDchcS5KCpQMvEvB14Wxw2","tz1MaKRHHCaUqfaY8SgiHBzNNgvUF8EiB9RE","tz1LN4xvgHB9dqiuc9fqco1ZEwDueXDgDw8T","tz1i55Li1zdF52PXSKGavRjmE6pCpSgmA5To","tz1V9wpVevfkEfNe2JnsBGuzQKJfpGzvs6vB","tz1dGRzqFXkur4d4HEr5q5ULSTpxtT8a8y3t","tz1QVCn1BYxpeWSVsu6ZvoSm1vMwFs3U49ZV","tz1Ltc6HqhjcMEXGnW8wSaqEJfi4kse77oHS","tz1LzvmQDVt7iTDevkAu6TZAd6LkhYaw5i8W","tz1cGaQgUitUa9TYfDdgAKLY5zyh5GUVHPzs","tz1YMFNXmBU81a3hkDAf5w6oADRPuieefX4i","tz1QMMwLkiHSRxXMP2LUuLfvw4HCq2c5JfMk","tz1UYdeecJh8w5EoraCHT1TgKA1bL4jGaDWJ","tz1Lor69x8DPG9AJ5xSthwVqQ8XtqLvnSofa","tz1NUHJF4PcYq1QbN3sW7RX76b81r96hKKoz","tz1YEhhVsJTQkxcgD24tQEjfhBKETkdBip9H","tz1SVDQFfuBiQV8qbhjw5YGxxVWFkPvEmodP","tz1hjZuttQSUcSbkg47i1izUMykXCcdqq1zx","tz1fF85RhHDzszowsTj9KGwcFwfDjfWqX7UM","tz1LsXSAtqk2UaAi5UqPgnxiMSx5aNarTiZt","tz1ZMLcTZuhe1FrCtbbTyiEp4r7PBbQZ52HQ","tz1dLBPNqqKTEqWEMqyzh64jdTVMoaZij9sm","tz1VvsF4iSFq7KVV4YFznaN7ZQYSNqcrQbyS","tz1ZbdR5gF7VrGT81o2Ny4c9UVfCc7gzB8En","tz1gC8bBi8dJKzEn97fvc1cp31qBctXUHfPv","tz1WsYZt814Mg9brcP2scWD9CcCywj8NnRBQ","tz1fv4smnQUbKXARxBKkUh5tQtADqFMKKQDJ","tz1i3UYmtRdoDwcHFSRV2e3Tk47fchbwUMwT","tz1XGjuyXeeCK3EuHYnSVMqqeJj41aNDzGDG","tz1SgfF5YhWA7Y1L5kEwv5cgRTbLm998fJC5","tz1SoikxCAviVXxs3pdc8UArM6unU1mffMHV","tz1NnvH3F8SfaB39KvD7Wyep1ytDCXjPoCJ4","tz1VCjP2P3sBtCLQXKkDG6xRyz1o6Sh4cngZ","tz1YqLMuu5gqPcWZjGAaCY4cHgKFW1bUYeKR","tz1Nev8pcv8qZDK2q2Ps4isYMtcJpXWaGcUa","tz1RrEVWkWxxQY5uLuBbVU2WR9W3EFtU8iKf","tz1dfc5ei2TSihvEpFnyTTb9nuQbDWvEEEvN","tz1iGL8vPK2DNvYf67FrqdsTDyXCtpBMbgkC","tz1YXFAkEgAbgy5Mrsr2DnPhbuq2WnBhnDCa","tz1SJLqfbEyGJ21wfhMJvxgu2EjQ346o22mZ","tz1NwPTbuzs8s6mrGEJisP9CaXC458jjzzPF","tz1VGdetQxEuDWGQYE5BDREBvpzQY9javJyp","tz1awa88jNvcsmbBHXbGLk6fcqEycYZecic8","tz1dJKVHdNapMkayYcmHFVYutVXXHx5mTKri","tz1NneEsPdJRrDgse4TzLpRqvbksphYBXBMY","tz1gtGWmzyGZTz7D1BheVa4ooocxjwamba4R","tz1VXvbmwHskMRHcbcCLi6bihPt5KNtMgVeX","tz1T5MBz5WXy4mCrdVHy19zrFDa3uu5vuKG3","tz1TH3yto3yViq21nG84zmcTmuvRfVgfMRGf","tz1eJ7HaiQu85aNYwXnYByr4voQJe65wWTzv","tz1Vz1XhyYidM2zjSZoN2H5Ku3a4ctHVvGm7","tz1MVTqQAvvurF7Abs4vBmPUoSFtqPuXacmv","tz1hFFvzPH5DxuHA4ivQvrtEX92FGntGMRBi","tz1fmLPPwGznV4R6vFyW8sswUZYwcYLJeYAp","tz1N6Xh2h2K4unzgXv1XitABtA3eB26wDAUD","tz1iGEPSzjQN8PzT5FrGUzhRQnx59hVzeXn8","KT1Prk9xaXSd7uz4NzWQfZ8bWyY4csVvox5w","tz1et74jh4CLmpfmvYCG5398iygUkdL962fy","KT1PHojJp48asdfyvT9kMmnsEzB6cdUGpwFf","tz1fNt7sqTh21sekaMdsPTQvjYsC1SduMagV","tz1idn8cD2bFaftnFzvJ2gik9wGuWKDGmhsP","tz1Qz93toMBURzKyjbECFe8YKAwARu8t1C3C","KT1FBMtK4T7K5UC3nuc8YRG3wnQK3oaCH9Uo","tz1Ly6UMQm3NCmDQ2udu6WvPCJGqauhR9FWk","tz1epXpov9hcoRUaGVJ222t67udd3vV6jn35","tz1ZVR7QMhJWCKEhp4SdynXNnikdxTs5XxQT","KT1KRdu1hDLtDRufZqNMU2z42uKrXhmsmzJd","tz1ivo3rkUgJQ1Nbe4VEhNetCREAvbGZwi25","tz1UBQvZkovRpZwML86qTpL59gedS1FeWpRw","tz1d9CzUNaFMmsnUZTihrz6wDA8ZP3GvAKbj","tz1MZHrRbLDMczK4xtJP1BrRdoYnoMq6c3P7","tz1Rw3VKh9yAWLWaQMhzWoRRQoEouGTCzgV7","tz1iABqHT2J4XKEnHp8JYJNiXEJtFg8r9RbC","tz1fxdeeUWT6YG5aSQcaJVU5sbeFCQYKCvPX","tz1dNA8PnEfRgV4ZqrX3i43Lh7Rxpx9bwy78","tz1MEEdk9w54LTcHz1oSkwAY9UUSepg8WrFG","tz1Zgo1nWvejNmjhzqEYPoRc57JhWrKhetAH","tz1gk9E28K1b6xQNw2wFLG9WERwzKDDwVNT9","tz1ftbRcC92jdKCTj91Qor9EkoJUcwqFFvH4","tz1hjorZSyLWMvupoBgWZsKbDFyca4B6wK36","tz1YNktyxUEzwpKq6QaWafka5CeKokJAEqi5","tz1KiuNcJNJ451967gXPwSDLvQmXryMvgTmL","tz1XDqZ4z2d5sRLkywYRwEMBQH5hHzaCaRre","tz1aQNn7eMC7kP1EyQetvocKS4TXmzEd5Gaw","tz1fnBJmAxoJbfAaMcCar3Aa8MFFH69dKYJv","tz1cZwxsasN1KorL8hYJPBy7gaBdNtsbjNvm","tz1b5qJrAgViKFPM5BdLeVasrxest7EWnf5z","tz1h87YTFnTCHKHTUEG2BxWq7DSRf861U8e6","tz1LPjWu1P11x1aizsD9wmqzey7ob66vvymg","tz1NBmAeLwsXxLcvAwJXM4nS199qkFcH4313","tz1cPL3YSMFiRC2yiMvSr7RLPVg5H5XhNvgW","tz1ZzGYssgyWGEZYVgCpMiYA1eBMWxRVrrqP","tz1ZgEQPeGYXeMLePL5sgR94RrRxwbsyK85z","tz1NcRjeevWE6E5B1pBsDexSB3cPJDTpQ9UL","tz1dBhoxSAU58V43Kvb7hG71iRxsfzmj7Z2y","tz1UwEDdQfpdcnYtfU7BRqXGPXbeaJmXk63c","tz1cpiGQS4rjtqnbndrbRnihtUjKH8aa1yHf","tz1eBdroBUqaUQ4h4xYXB26z67L8cj6ZyLsx","tz1Lk6U6erqH6EEuqMqk6u8gjqtJybZTirDs","tz1iAeHTDNZSwJjXaqbRyfyp96ych9j36tW1","tz1PDpbmvvBbFcEzctGfNt9mvvVTgTWxGGPZ","tz1RkXsWMgAtz85cD4iBckPC8xUFf3fPUFw2","tz1LcGrFcHLS9jgmWij4u7EWJDRrnU4xhVGL","tz1R752LZLPkJ1dhMs49zJqDcRZMic7nvL6g","tz1bpSiotWsQCz7jLjU4FV5K9PCZ79jinbs5","tz1bbsn8DMXJMEW7gVeuBbpMFBf65dq3VTtv","tz1V7aymCngroTZBxraVxp5kRtLh8qFRLcMN","tz1WxVo86ucoAE5RwCUe3tHTVV7r2GwRRvMN","tz1VXY3dXhE1s5huXnyFT7vfXgNroR5hTdjr","tz1LrYXWJ8Z3eKLSAYfCUaoZjpaqNrTqEd8w","tz1ZdYg6spcG9yk4ZXHHLcgNL2p8Y5wyhWYp","tz1PSqayN9mB1Wxk9SMjcGixX5PX9zRvtLZ8","tz1Pnke8YsfcDZfcqpZwpyFxLFCzEnSG9ews","tz1Qcgog1zYs6evgGP6aNEpGvDnCa7rAPvx5","tz1R5S8M9FAHs3eYjKY9ci3RD6iBgV8QCiLM","tz1iwGHsJu1Mq3eGGj2dmp5xj7N9kqxvuJzy","tz1TiEvTkhsuF5drB6Q9gDAQ3ejjp9GkMjdw","tz1LQPiugXCFuDit9232iqWGfj41PQGaCKvV","tz1TkAAz3CXdKiN4T8jAqxfWCBddQ39Vcewf","tz1ViczpurHDugWPgYzh5sE7Y7CDUB6qxseX","tz1NMf4uWqQNaVLFLjztKMpYphGdGSPu89pu","tz1ViNQrnj5aPjhZ9EQ1UuFcH6UUALqo3EUU","tz1Zqneq8GbnQ1G3g1Jnh9Vv4qGMnzLXbt3s","tz1dHH1xpCwZXE66WWK4SKDPLzF1JHX5KC96","tz1aXL6EouwJR3yMDK9jgD7zL5tpM12Vx3RY","tz1gtaaw2gzQjJmx8R17BRpYdkR9haE7i811","tz1aj98BzdTbicVFrqSYeAFjRwHGmRAwo2J6","tz1TS2ByHGPAgDb2AYv3bQWakG1tiH7uPwQb","tz1Q1t1xazVvEgN1dmxPCDXt8hqK9BY6qF5T","tz1fYzKUnmF873zvfcyUaX6yvRHbNTqakkSw","tz1g81md3cSqEtozkZggJnvRUNbMCbFHETqL","tz1bENLm1iQRnPsybc6HvrfR3W2nvuGErdFK","tz1TktVVrHESq3mdw6hpohXQFjbpGkdERsKT","tz1YSQ3PA5t3drYuAXYX5VE2mRcK143vjkKJ","tz1VFsJNozUp4mmtpv98bS2Q3B72qXWagDsq","tz1W47pyCkjpiWRAHmR9rHTmM5a1Yf9dtzkB","tz1Td2RL3zTSRZFac1SaXVxcXeAXHzTATsAU","KT1Tvqr6CTN3Lj2usqGPNG5Uog8JdgnDnhps","KT1CStwHYoGYzXENQamy2nc251enF5wk7Yjy","tz1UZuJ7Ae3m3rhsBjig955Fcy8vyfPYTDEr","tz1Qs9UZiWESjBJAA1SkqDm4eMDm78wo1QpN","tz1ZeovPMP8hy3PaJDg7AC8HP3rjNKpfRFes","tz1dkzioZTg4E3yVShiX1hdpAkE84wYhzRL8","KT1QhJRX8884Ccb9EKpNNFsbB27P6sRoqo4t","tz1Ww975VPEgcZdiTQGahABVkMf8yrcZb9A3","tz1RBv1smMW4xtTWG53fkzRZJGPmMotNJTEE","tz1cQD5tsef53FPzMmN5kLoLjvLD7VAGGQU5","tz1SUwahJKb5V9dxwk8N8quQWc5bQ1Zm6cva","tz1ciLo5K3g1pHPJKjEQp4WNvu6e9bxDtmwT","tz1ZTv3NVL4ry3qHZdmo7Y4rLjciHRcmptbA","tz1Z8TYYJsQgCqvvMtDo9Z56CzAtdVEi88NA","tz1hqbwdkxsh2MNaqoPVNycWA6cu1EKonKy8","tz1M4QhH1WQqrQWtsnDvyAqtfm3S7UcFAb78","tz1hxJteiSNWfmj12WdmHaPsdGtbZxZn1W9H","tz1cEnJ8Cu9AJcrfg9tajTmBEyTXPJM4teKP","tz1eSjS3Q2Rc36o2hHMRNX5pErtfGQRH9spH","tz1W7XN1Si3eGg4b6a7opsZ8EKjdiYVvmtfR","tz1gwyEjft79QrS5RKgLM3WozabfFeXn5kSC","tz1avdpHLEVbCKJPbFRD8pqySrZjPT64meHC","tz1NjziRqzmncVzU3CHXyo5BSVsn5CwXrUxS","tz1diyBGHXh6QR88Ps8guLmv8yCyyYTSoYjK","tz1RNVWP9MqtDSukfN9xZjNibKUMyq9ih2m1","tz1N1wThWmdxubf8y18ySS4KG69tR7icTHLn","tz1P96NympEyX7h4K5az2H8qr5vi7HyYGd7T","tz1Y7Ft4jEFvKE3dAHMUSwz9W3gXAWvN2ADR","tz1ND1DoSpPTtyooQQLxfNq7w8FR9dw9ZzuR","tz1SuBRZzrE98AeHRMy25zbNxwQfT5Wv1Cpp","tz1Q8HLHCFUFQVn38UeiSCNJUQsZxF2d6vtp","tz1TJrVZoozuTqzdeMakTnJQEogvm4q2531m","tz1TnfvKsMQajLzijg2EoKpE5yBGmXDiRQ1K","tz1gzg3UU6UMjVMGrcuetgnQ6btdVUGxYfyP","tz1KwcHHYUT7kMKeY6zXwUAq9Kuj3ryeX1iy","tz1WXuFmAiWqreKWY465FEps1Ei2XrAyHGGt","tz1TZafuJ3eWM3d3mckARNaP2oxBNyjLQVG6","tz1N7mPBeSrRsAgcukmRj2Twp6fvNshT1Uyc","tz1gFFSNHfQeNED9wYqThHMJZm5CNe6sFEUE","tz1L5xtPTd4XceH85n9W8vB3TjK45XGt63hC","tz1h6rqcMhAoEG2cMhiPjdJoemaHenY9mH7L","tz1bK9XE8khrUn7VxmEuNzF6FidGqpjTTXDs","tz1NUZw2MUG2AmSrtwTF3qdAUwgqBfnAGyu2","tz1ichwjUoGrUSawDKP6wMVLghJNX196aEBi","tz1UEEsxKrP1FH3RtUFt2esg7UdFQ74VeasS","tz1aNF6AiXu5uG6LENhYvJMwqYJc1bKTRuKr","KT1AG7uQwt3VX6JZah9KbD8n4sYSyaTUNqB3","tz1byac5DY5hA7dJ3uPvWvYAsWcAcdAGy953","tz1abWuJnBvT9o5TWzkEA2u3BbQ2mqFNoX3e","tz1Qin5ErcHtxtZV1njJ3cmzjw6GghWsEGGc"],"delegated_balance":"143547306933","deactivated":false,"grace_period":251}` + +func createMockedAPI() http.Handler { + r := http.NewServeMux() + + r.HandleFunc("/chains/main/blocks/head/context/delegates/tz1V3yg82mcrPJbegqVCPn6bC8w1CSTRp3f8", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedTezosResponse); err != nil { + panic(err) + } + }) + + return r +} diff --git a/platform/tron/stake.go b/platform/tron/stake.go index 340660123..18b9a38b4 100644 --- a/platform/tron/stake.go +++ b/platform/tron/stake.go @@ -4,13 +4,25 @@ import ( "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" - services "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/blockatlas/services/assets" "strconv" "time" ) const Annual = 0.74 +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + result := make(blockatlas.StakeValidators, 0, len(validators)) + for _, v := range validators { + result = append(result, v) + } + return result, nil +} + func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { results := make(blockatlas.ValidatorPage, 0) validators, err := p.client.GetValidators() @@ -48,7 +60,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e if len(votes.Votes) == 0 { return results, nil } - validators, err := services.GetValidatorsMap(p) + validators, err := assets.GetValidatorsMap(p) if err != nil { return nil, err } @@ -69,14 +81,14 @@ func (p *Platform) UndelegatedBalance(address string) (string, error) { } func normalizeValidator(v Validator) (validator blockatlas.Validator, ok bool) { - address, err := address.HexToAddress(v.Address) + a, err := address.HexToAddress(v.Address) if err != nil { return validator, false } return blockatlas.Validator{ Status: true, - ID: address, + ID: a, Details: getDetails(), }, true } diff --git a/platform/vechain/stake.go b/platform/vechain/stake.go index ed993e6a8..c407c3b19 100644 --- a/platform/vechain/stake.go +++ b/platform/vechain/stake.go @@ -4,14 +4,26 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/blockatlas/services/assets" ) const ( - // TODO: Find a way to have a dynamic APR // The current value comes from https://www.stakingrewards.com/asset/vechain Annual = 1.35 ) +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + result := make(blockatlas.StakeValidators, 0, len(validators)) + for _, v := range validators { + result = append(result, v) + } + return result, nil +} + func (p *Platform) GetDetails() blockatlas.StakingDetails { return blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: Annual}, diff --git a/services/assets/client.go b/services/assets/client.go new file mode 100644 index 000000000..a70fbc916 --- /dev/null +++ b/services/assets/client.go @@ -0,0 +1,22 @@ +package assets + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "time" +) + +const ( + AssetsURL = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/" +) + +func fetchValidatorsInfo(coin coin.Coin) (AssetValidators, error) { + var results AssetValidators + request := blockatlas.InitClient(AssetsURL + coin.Handle) + err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) + if err != nil { + return nil, errors.E(err, errors.Params{"coin": coin.Handle}) + } + return results, nil +} diff --git a/services/assets/stake.go b/services/assets/validator.go similarity index 69% rename from services/assets/stake.go rename to services/assets/validator.go index 5abac0507..cee5bcc58 100644 --- a/services/assets/stake.go +++ b/services/assets/validator.go @@ -6,25 +6,10 @@ import ( "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" "sort" - "time" ) -const ( - AssetsURL = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/" -) - -func requestValidatorsInfo(coin coin.Coin) (AssetValidators, error) { - var results AssetValidators - request := blockatlas.InitClient(AssetsURL + coin.Handle) - err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) - if err != nil { - return nil, errors.E(err, errors.Params{"coin": coin.Handle}) - } - return results, nil -} - func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) { - assets, validators, err := GetValidators(api) + assets, validators, err := getValidators(api) if err != nil { return nil, err } @@ -32,18 +17,8 @@ func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) return results.ToMap(), nil } -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 -} - -// Get validators from assets repository and RPC -func GetValidators(api blockatlas.StakeAPI) (AssetValidators, blockatlas.ValidatorPage, error) { - assetsValidators, err := requestValidatorsInfo(api.Coin()) +func getValidators(api blockatlas.StakeAPI) (AssetValidators, blockatlas.ValidatorPage, error) { + assetsValidators, err := fetchValidatorsInfo(api.Coin()) if err != nil { return nil, nil, errors.E(err, "unable to fetch validators list from the registry") } diff --git a/services/assets/stake_test.go b/services/assets/validator_test.go similarity index 100% rename from services/assets/stake_test.go rename to services/assets/validator_test.go From 344ded5aa7a1d0b93b6ca1dab23303dfac7a50d2 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Mon, 22 Jun 2020 15:36:14 +0300 Subject: [PATCH 335/506] Add TRC20 tokens for TRON (#1154) * Add trc20 tokens for tokens and transaction api for TRON * Small cleanup * Add test to the GetTokenListAddress * Add tests, change client url params * Change GetTokenTxsByAddress() --- config.yml | 3 +- platform/platform.go | 2 +- platform/tron/base.go | 8 +- platform/tron/block.go | 10 +- platform/tron/client.go | 55 +++++-- platform/tron/model.go | 241 +++++++++++++++++------------- platform/tron/stake.go | 6 +- platform/tron/token.go | 23 ++- platform/tron/token_test.go | 92 ++++++++++++ platform/tron/transaction.go | 105 +++++++++---- platform/tron/transaction_test.go | 54 ++++++- 11 files changed, 442 insertions(+), 157 deletions(-) diff --git a/config.yml b/config.yml index cb2f42f92..243651413 100644 --- a/config.yml +++ b/config.yml @@ -9,7 +9,7 @@ gin: # If all - run all platforms in one binary. You can pick specific coin handle to run binary only with specific coin # Example: ethereum # You can see all the coin handles at coins/coins.yml file -platform: [ethereum] +platform: [all] # Can be platform or swagger rest_api: all @@ -111,6 +111,7 @@ icon: # [TRX] Tron: https://tron.network/ tron: api: https://api.trongrid.io + explorer: https://apilist.tronscan.org # [VET] VeChain: https://www.vechain.org vechain: diff --git a/platform/platform.go b/platform/platform.go index 2e4eefcc2..8012bebdf 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -62,7 +62,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Fio().Handle: fio.Init(GetApiVar(coin.FIO)), coin.Aion().Handle: aion.Init(GetApiVar(coin.AION)), coin.Icon().Handle: icon.Init(GetApiVar(coin.ICX)), - coin.Tron().Handle: tron.Init(GetApiVar(coin.TRX)), + coin.Tron().Handle: tron.Init(GetApiVar(coin.TRX), GetVar("tron.explorer")), coin.Nano().Handle: nano.Init(GetApiVar(coin.NANO)), coin.Nimiq().Handle: nimiq.Init(GetApiVar(coin.NIM)), coin.Iotex().Handle: iotex.Init(GetApiVar(coin.IOTX)), diff --git a/platform/tron/base.go b/platform/tron/base.go index 24c15a083..5b42418c9 100644 --- a/platform/tron/base.go +++ b/platform/tron/base.go @@ -6,12 +6,14 @@ import ( ) type Platform struct { - client Client + client Client + explorerClient ExplorerClient } -func Init(api string) *Platform { +func Init(api, explorerApi string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{blockatlas.InitClient(api)}, + explorerClient: ExplorerClient{blockatlas.InitClient(explorerApi)}, } } diff --git a/platform/tron/block.go b/platform/tron/block.go index dba8310d9..66c2e853f 100644 --- a/platform/tron/block.go +++ b/platform/tron/block.go @@ -7,11 +7,11 @@ import ( ) func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.CurrentBlockNumber() + return p.client.fetchCurrentBlockNumber() } func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - block, err := p.client.GetBlockByNumber(num) + block, err := p.client.fetchBlockByNumber(num) if err != nil { return nil, err } @@ -48,7 +48,7 @@ func (p *Platform) NormalizeBlockChannel(srcTx Tx, txChan chan blockatlas.Tx) { return } - tx, err := Normalize(srcTx) + tx, err := normalize(srcTx) if err != nil { return } @@ -56,9 +56,9 @@ func (p *Platform) NormalizeBlockChannel(srcTx Tx, txChan chan blockatlas.Tx) { if len(transfer.AssetName) > 0 { assetName, err := hex.DecodeString(transfer.AssetName[:]) if err == nil { - info, err := p.client.GetTokenInfo(string(assetName)) + info, err := p.client.fetchTokenInfo(string(assetName)) if err == nil && len(info.Data) > 0 { - setTokenMeta(tx, srcTx, info.Data[0]) + addTokenMeta(tx, srcTx, info.Data[0]) } } } diff --git a/platform/tron/client.go b/platform/tron/client.go index dfa484ac2..5eb98880e 100644 --- a/platform/tron/client.go +++ b/platform/tron/client.go @@ -8,17 +8,23 @@ import ( "time" ) -type Client struct { - blockatlas.Request -} +type ( + Client struct { + blockatlas.Request + } -func (c *Client) CurrentBlockNumber() (int64, error) { + ExplorerClient struct { + blockatlas.Request + } +) + +func (c *Client) fetchCurrentBlockNumber() (int64, error) { var block Block err := c.Post(&block, "wallet/getnowblock", nil) return block.BlockHeader.Data.Number, err } -func (c *Client) GetBlockByNumber(num int64) (Block, error) { +func (c *Client) fetchBlockByNumber(num int64) (Block, error) { var blocks Blocks err := c.Post(&blocks, "wallet/getblockbylimitnext", BlockRequest{StartNum: num, EndNum: num + 1}) if err != nil || blocks.Blocks == nil || len(blocks.Blocks) == 0 { @@ -27,7 +33,7 @@ func (c *Client) GetBlockByNumber(num int64) (Block, error) { return blocks.Blocks[0], nil } -func (c *Client) GetTxsOfAddress(address, token string) ([]Tx, error) { +func (c *Client) fetchTxsOfAddress(address, token string) ([]Tx, error) { path := fmt.Sprintf("v1/accounts/%s/transactions", url.PathEscape(address)) var txs Page @@ -40,24 +46,53 @@ func (c *Client) GetTxsOfAddress(address, token string) ([]Tx, error) { return txs.Txs, err } -func (c *Client) GetAccount(address string) (accounts *Account, err error) { +func (c *Client) fetchAccount(address string) (accounts *Account, err error) { path := fmt.Sprintf("v1/accounts/%s", address) err = c.Get(&accounts, path, nil) return } -func (c *Client) GetAccountVotes(address string) (account *AccountData, err error) { +func (c *Client) fetchAccountVotes(address string) (account *AccountData, err error) { err = c.Post(&account, "wallet/getaccount", VotesRequest{Address: address, Visible: true}) return } -func (c *Client) GetTokenInfo(id string) (asset Asset, err error) { +func (c *Client) fetchTokenInfo(id string) (asset Asset, err error) { path := fmt.Sprintf("v1/assets/%s", id) err = c.GetWithCache(&asset, path, nil, time.Hour*24) return } -func (c *Client) GetValidators() (validators Validators, err error) { +func (c *Client) fetchValidators() (validators Validators, err error) { err = c.Get(&validators, "wallet/listwitnesses", nil) return } + +func (c *Client) fetchTRC20Transactions(address string) (TRC20Transactions, error) { + var result TRC20Transactions + path := fmt.Sprintf("v1/accounts/%s/transactions/trc20", address) + err := c.Get(&result, path, url.Values{ + "limit": {"200"}, + "order_by": {"block_timestamp,desc"}, + "only_confirmed": {"true"}, + }) + if err != nil { + return TRC20Transactions{}, err + } + return result, nil +} + +func (c *ExplorerClient) fetchAllTRC20Tokens(address string) ([]ExplorerTrc20Tokens, error) { + var result ExplorerResponse + path := "api/account" + err := c.Get(&result, path, url.Values{ + "address": {address}, + }) + if err != nil { + return nil, err + } + if result.ExplorerTrc20Tokens != nil { + return result.ExplorerTrc20Tokens, nil + } + return nil, nil +} diff --git a/platform/tron/model.go b/platform/tron/model.go index 38e90ed06..840a07867 100644 --- a/platform/tron/model.go +++ b/platform/tron/model.go @@ -4,111 +4,146 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" ) -type BlockRequest struct { - StartNum int64 `json:"startNum"` - EndNum int64 `json:"endNum"` -} - -type Blocks struct { - Blocks []Block `json:"block"` -} - -type Block struct { - BlockId string `json:"blockID"` - Txs []Tx `json:"transactions"` - BlockHeader struct { - Data BlockData `json:"raw_data"` - } `json:"block_header"` -} - -type BlockData struct { - Number int64 `json:"number"` - Timestamp int64 `json:"timestamp"` -} - -type Page struct { - Success bool `json:"success"` - Error string `json:"error,omitempty"` - Txs []Tx `json:"data"` -} - -type Tx struct { - ID string `json:"txID"` - BlockTime int64 `json:"block_timestamp"` - Data TxData `json:"raw_data"` -} - -type TxData struct { - Timestamp int64 `json:"timestamp"` - Contracts []Contract `json:"contract"` -} - -type ContractType string +type ( + BlockRequest struct { + StartNum int64 `json:"startNum"` + EndNum int64 `json:"endNum"` + } + + Blocks struct { + Blocks []Block `json:"block"` + } + + Block struct { + BlockId string `json:"blockID"` + Txs []Tx `json:"transactions"` + BlockHeader struct { + Data BlockData `json:"raw_data"` + } `json:"block_header"` + } + + BlockData struct { + Number int64 `json:"number"` + Timestamp int64 `json:"timestamp"` + } + + Page struct { + Success bool `json:"success"` + Error string `json:"error,omitempty"` + Txs []Tx `json:"data"` + } + + Tx struct { + ID string `json:"txID"` + BlockTime int64 `json:"block_timestamp"` + Data TxData `json:"raw_data"` + } + + TxData struct { + Timestamp int64 `json:"timestamp"` + Contracts []Contract `json:"contract"` + } + + ContractType string + + Contract struct { + Type ContractType `json:"type"` + Parameter struct { + Value TransferValue `json:"value"` + } `json:"parameter"` + } + + TransferValue struct { + Amount blockatlas.Amount `json:"amount"` + OwnerAddress string `json:"owner_address"` + ToAddress string `json:"to_address"` + AssetName string `json:"asset_name,omitempty"` + } + + Account struct { + Data []AccountData `json:"data"` + } + + AccountData struct { + Balance uint `json:"balance"` + AssetsV2 []AssetV2 `json:"assetV2"` + Votes []Votes `json:"votes"` + Frozen []Frozen `json:"frozen"` + Trc20 []map[string]string `json:"trc20"` + } + + AssetV2 struct { + Key string `json:"key"` + } + + Votes struct { + VoteAddress string `json:"vote_address"` + VoteCount int `json:"vote_count"` + } + + Frozen struct { + ExpireTime int64 `json:"expire_time"` + FrozenBalance interface{} `json:"frozen_balance,string"` // nolint + } + + Asset struct { + Data []AssetInfo `json:"data"` + } + + AssetInfo struct { + Name string `json:"name"` + Symbol string `json:"abbr"` + ID string `json:"id"` + Decimals uint `json:"precision"` + } + + Validators struct { + Witnesses []Validator `json:"witnesses"` + } + + Validator struct { + Address string `json:"address"` + } + + VotesRequest struct { + Address string `json:"address"` + Visible bool `json:"visible"` + } + + TRC20Transactions struct { + Data []TRC20Transaction `json:"data"` + } + + TRC20Transaction struct { + From string `json:"from"` + To string `json:"to"` + BlockTimestamp int64 `json:"block_timestamp"` + Value string `json:"value"` + Type string `json:"type"` + TransactionID string `json:"transaction_id"` + TokenInfo TRC20TokenInfo `json:"token_info"` + } + + TRC20TokenInfo struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals int `json:"decimals"` + Address string `json:"address"` + } + + ExplorerResponse struct { + ExplorerTrc20Tokens []ExplorerTrc20Tokens `json:"trc20token_balances"` + } + + ExplorerTrc20Tokens struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals int `json:"decimals"` + ContractAddress string `json:"contract_address"` + } +) const ( TransferContract ContractType = "TransferContract" TransferAssetContract ContractType = "TransferAssetContract" ) - -type Contract struct { - Type ContractType `json:"type"` - Parameter struct { - Value TransferValue `json:"value"` - } `json:"parameter"` -} - -type TransferValue struct { - Amount blockatlas.Amount `json:"amount"` - OwnerAddress string `json:"owner_address"` - ToAddress string `json:"to_address"` - AssetName string `json:"asset_name,omitempty"` -} - -type Account struct { - Data []AccountData `json:"data"` -} - -type AccountData struct { - Balance uint `json:"balance"` - AssetsV2 []AssetV2 `json:"assetV2"` - Votes []Votes `json:"votes"` - Frozen []Frozen `json:"frozen"` -} - -type AssetV2 struct { - Key string `json:"key"` -} - -type Votes struct { - VoteAddress string `json:"vote_address"` - VoteCount int `json:"vote_count"` -} - -type Frozen struct { - ExpireTime int64 `json:"expire_time"` - FrozenBalance interface{} `json:"frozen_balance,string"` // nolint -} - -type Asset struct { - Data []AssetInfo `json:"data"` -} - -type AssetInfo struct { - Name string `json:"name"` - Symbol string `json:"abbr"` - ID string `json:"id"` - Decimals uint `json:"precision"` -} - -type Validators struct { - Witnesses []Validator `json:"witnesses"` -} - -type Validator struct { - Address string `json:"address"` -} - -type VotesRequest struct { - Address string `json:"address"` - Visible bool `json:"visible"` -} diff --git a/platform/tron/stake.go b/platform/tron/stake.go index 18b9a38b4..c8c785939 100644 --- a/platform/tron/stake.go +++ b/platform/tron/stake.go @@ -25,7 +25,7 @@ func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { results := make(blockatlas.ValidatorPage, 0) - validators, err := p.client.GetValidators() + validators, err := p.client.fetchValidators() if err != nil { return results, err } @@ -53,7 +53,7 @@ func getDetails() blockatlas.StakingDetails { func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { results := make(blockatlas.DelegationsPage, 0) - votes, err := p.client.GetAccountVotes(address) + votes, err := p.client.fetchAccountVotes(address) if err != nil { return nil, err } @@ -69,7 +69,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e } func (p *Platform) UndelegatedBalance(address string) (string, error) { - account, err := p.client.GetAccount(address) + account, err := p.client.fetchAccount(address) if err != nil { return "0", err } diff --git a/platform/tron/token.go b/platform/tron/token.go index fc7f21f9c..e46aaf8cf 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -8,7 +8,7 @@ import ( ) func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { - tokens, err := p.client.GetAccount(address) + tokens, err := p.client.fetchAccount(address) if err != nil { return nil, err } @@ -26,6 +26,23 @@ func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, for info := range tokensChan { tokenPage = append(tokenPage, info) } + + trc20Tokens, err := p.explorerClient.fetchAllTRC20Tokens(address) + if err != nil { + logger.Error("Explorer error" + err.Error()) + } + + for _, t := range trc20Tokens { + tokenPage = append(tokenPage, blockatlas.Token{ + Name: t.Name, + Symbol: t.Symbol, + Decimals: uint(t.Decimals), + TokenID: t.ContractAddress, + Coin: coin.Tron().ID, + Type: blockatlas.TokenTypeTRC20, + }) + } + return tokenPage, nil } @@ -48,9 +65,9 @@ func (p *Platform) getTokens(ids []string) chan blockatlas.Token { } func (p *Platform) getTokensChannel(id string, tkChan chan blockatlas.Token) error { - info, err := p.client.GetTokenInfo(id) + info, err := p.client.fetchTokenInfo(id) if err != nil || len(info.Data) == 0 { - logger.Error(err, "GetTokenInfo: invalid token") + logger.Error(err, "fetchTokenInfo: invalid token") return err } asset := NormalizeToken(info.Data[0]) diff --git a/platform/tron/token_test.go b/platform/tron/token_test.go index 8bf9089d7..c324f095c 100644 --- a/platform/tron/token_test.go +++ b/platform/tron/token_test.go @@ -1,8 +1,13 @@ package tron import ( + "encoding/json" + "fmt" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "net/http" + "net/http/httptest" + "sort" "testing" ) @@ -20,3 +25,90 @@ func TestNormalizeToken(t *testing.T) { actual := NormalizeToken(asset) assert.Equal(t, tokenDst, actual) } + +func TestPlatform_GetTokenListByAddress(t *testing.T) { + server := httptest.NewServer(createMockedAPI()) + defer server.Close() + + p := Init(server.URL, server.URL) + res, err := p.GetTokenListByAddress("TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R") + assert.Nil(t, err) + sort.Slice(res, func(i, j int) bool { + return res[i].TokenID < res[j].TokenID + }) + rawRes, err := json.Marshal(res) + assert.Nil(t, err) + assert.Equal(t, wantedTokensResponse, string(rawRes)) +} + +func createMockedAPI() http.Handler { + r := http.NewServeMux() + + r.HandleFunc("/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedAccountsResponse); err != nil { + panic(err) + } + }) + + r.HandleFunc("/v1/assets/1000542", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedAsset1000542Response); err != nil { + panic(err) + } + }) + + r.HandleFunc("/v1/assets/1000567", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedAsset1000567Response); err != nil { + panic(err) + } + }) + r.HandleFunc("/v1/assets/TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedAssetTR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6tResponse); err != nil { + panic(err) + } + }) + + r.HandleFunc("/api/account", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedTrc20Response); err != nil { + panic(err) + } + }) + r.HandleFunc("/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R/transactions", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedAccountsTransactionsResponse); err != nil { + panic(err) + } + }) + + r.HandleFunc("/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D/transactions", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedTransactionsEmptyResponse); err != nil { + panic(err) + } + }) + + r.HandleFunc("/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D/transactions/trc20", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedTransactionsTrc20Response); err != nil { + panic(err) + } + }) + + return r +} + +var ( + wantedTokensResponse = `[{"name":"FomoThreeD","symbol":"FOM","decimals":0,"token_id":"1000542","coin":195,"type":"TRC10"},{"name":"OtonamiS","symbol":"os","decimals":0,"token_id":"1000567","coin":195,"type":"TRC10"},{"name":"JUST GOV","symbol":"JST","decimals":18,"token_id":"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9","coin":195,"type":"TRC20"},{"name":"Enme Token","symbol":"EME","decimals":6,"token_id":"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF","coin":195,"type":"TRC20"},{"name":"BeeHive","symbol":"Bee","decimals":8,"token_id":"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK","coin":195,"type":"TRC20"},{"name":"Mono Token","symbol":"MONO","decimals":18,"token_id":"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak","coin":195,"type":"TRC20"},{"name":"WINK","symbol":"WIN","decimals":6,"token_id":"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7","coin":195,"type":"TRC20"},{"name":"PYRO Network","symbol":"PYRO","decimals":6,"token_id":"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e","coin":195,"type":"TRC20"},{"name":"NoleCoin","symbol":"NOLE","decimals":6,"token_id":"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG","coin":195,"type":"TRC20"},{"name":"Tether USD","symbol":"USDT","decimals":6,"token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","coin":195,"type":"TRC20"},{"name":"Wuhan Fried Bats","symbol":"WUHAN","decimals":4,"token_id":"TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr","coin":195,"type":"TRC20"},{"name":"HelGro","symbol":"HGRO","decimals":6,"token_id":"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm","coin":195,"type":"TRC20"}]` + mockedAccountsTransactionsResponse = `{"success":true,"meta":{"at":1592755486554,"page_size":25,"fingerprint":"4CwRecxbH99eRRkU2FFkGRCvoQGwphNyRcTTiM1GfUrkoQ1fG9Kcc8ADZo7pSCYXja28JWKUACy2Xt6UG1Fa5tSZh5dqpUEuTi1W","links":{"next":"https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R/transactions?limit=25&order_by=block_timestamp%2Cdesc&token_id=&fingerprint=4CwRecxbH99eRRkU2FFkGRCvoQGwphNyRcTTiM1GfUrkoQ1fG9Kcc8ADZo7pSCYXja28JWKUACy2Xt6UG1Fa5tSZh5dqpUEuTi1W"}},"data":[{"blockNumber":20829763,"block_timestamp":1592755239000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000413b334848f75cf8c27ec975bcc7cc7e54f140b3c000000000000000000000000000000000000000000000000000000000cd0e33a0","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758890000,"fee_limit":1000000000,"ref_block_bytes":"d62e","ref_block_hash":"bbf7d06ee7004d5a","timestamp":1592755233594},"raw_data_hex":"0a02d62e2208bbf7d06ee7004d5a4090dccfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413b334848f75cf8c27ec975bcc7cc7e54f140b3c000000000000000000000000000000000000000000000000000000000cd0e33a070bac6f0bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["c9a405be8b12f92747cc0f0d979606807a03edcefd154bcf517ce26f8bf681400d6cdacda11c98e7ae61d51905f7113658a786d6022b97e025f5a7e99b53845d01"],"txID":"18f5908a7e208e16bfb892a5b06df75675d3142d03a0d99d270ac46143b78d06"},{"blockNumber":20829760,"block_timestamp":1592755230000,"energy_fee":146310,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb00000000000000000000004158a82464024027b8e81bd1997cc7ba8f26a01314000000000000000000000000000000000000000000000000000000001dce7a58","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758881000,"fee_limit":1000000000,"ref_block_bytes":"d62b","ref_block_hash":"38ebe631e633b827","timestamp":1592755223352},"raw_data_hex":"0a02d62b220838ebe631e633b82740e895cfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb00000000000000000000004158a82464024027b8e81bd1997cc7ba8f26a01314000000000000000000000000000000000000000000000000000000001dce7a5870b8f6efbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":149770}],"signature":["39ee8b2e7ab589538f3a976644399ba60667ede4d9611229298d52f5aeb01a6624e2346703d8a19edc9f457b89a0dbb800ae87d049ad3a7d72353fde77635f1a00"],"txID":"2a9eda92b9a2a0e56d29000ad24daae7d577c5db44d2b737f6a35584cd81b5e0"},{"blockNumber":20829760,"block_timestamp":1592755230000,"energy_fee":119110,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac84000000000000000000000000000000000000000000000000000000037e11d600","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758881000,"fee_limit":1000000000,"ref_block_bytes":"d62b","ref_block_hash":"38ebe631e633b827","timestamp":1592755223053},"raw_data_hex":"0a02d62b220838ebe631e633b82740e895cfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac84000000000000000000000000000000000000000000000000000000037e11d600708df4efbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":122570}],"signature":["710a4b8543a9f605acc809ebe5b8a3a3b4681ebf2123fcdda39187bde86c9bc839cf6d882d9d15052b94ed6bba6474f9fdf09e73afefe40f6bad909029cadd2500"],"txID":"c838b8a683d39c6f1a8a173e6fffc5cc9122acc690f5e35fa7c1935cc5eae540"},{"blockNumber":20829742,"block_timestamp":1592755176000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041c80ab7aac02a3d4b3d89ee781cddce55286bcf2d000000000000000000000000000000000000000000000000000000000bebc200","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758830000,"fee_limit":1000000000,"ref_block_bytes":"d61a","ref_block_hash":"b1015d64daa873a3","timestamp":1592755172703},"raw_data_hex":"0a02d61a2208b1015d64daa873a340b087ccbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041c80ab7aac02a3d4b3d89ee781cddce55286bcf2d000000000000000000000000000000000000000000000000000000000bebc20070dfeaecbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["a7583c4e402eff463b083de5cfcbaadc46ed8601e2346f20d01eb0ec7a6824d869be27371f8c0e5a38a708df724be60a818b9647757bdde73ed743ff9324115c01"],"txID":"ad631a0e55bd2bb64747bf388dc92084c32506843c19a0a2b69234b4d4e56a6b"},{"blockNumber":20829732,"block_timestamp":1592755146000,"energy_fee":231500,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000410d4fd52433f30edd0b512f59fa021527bbd7de610000000000000000000000000000000000000000000000000000000001c9c380","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758800000,"fee_limit":1000000000,"ref_block_bytes":"d610","ref_block_hash":"2a14293035535e85","timestamp":1592755142312},"raw_data_hex":"0a02d61022082a14293035535e8540809dcabead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000410d4fd52433f30edd0b512f59fa021527bbd7de610000000000000000000000000000000000000000000000000000000001c9c38070a8fdeabcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":234960}],"signature":["3095c2130ee5d4da72246a17098b587c25108e1c1884f9128911e079997dd25c45e0b0acfc99e3ee4367c4670e2117dd24884c32ae0ea15ec9f9368910e4c42801"],"txID":"f1920eefa4de8370bc349fbd6ca73e24d9000d9d8fe5c71260a2902d3b49b02a"},{"blockNumber":20829718,"block_timestamp":1592755104000,"energy_fee":166720,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb00000000000000000000004135c4d4a5544d25a2f25a7cda73d57c45a36578bc0000000000000000000000000000000000000000000000000000000010089d40","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758761000,"fee_limit":1000000000,"ref_block_bytes":"d603","ref_block_hash":"f84579e34d118430","timestamp":1592755101713},"raw_data_hex":"0a02d6032208f84579e34d11843040a8ecc7bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb00000000000000000000004135c4d4a5544d25a2f25a7cda73d57c45a36578bc0000000000000000000000000000000000000000000000000000000010089d407091c0e8bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170180}],"signature":["816b2747c6c1f6be139d233118b4b1e3c3942d62f56d1b0c8a496851ea233c5c1b6e0e0a13e22c3a4c1bd106eb6c0e987d5c84f9fcc29ee7b86bd4d1874ade9601"],"txID":"cec1061166e4924123356b8066872b641956691d1b1f11a12f293c54e7178362"},{"blockNumber":20829716,"block_timestamp":1592755098000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":2690,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":13195916000,"owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874","to_address":"41d9378a9849912a41ec1f0e4677c074edf0516241"}},"type":"TransferContract"}],"expiration":1592758749000,"fee_limit":0,"ref_block_bytes":"d5ff","ref_block_hash":"c753125289c79c7c","timestamp":1592755089996},"raw_data_hex":"0a02d5ff2208c753125289c79c7c40c88ec7bead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a154179309abcff2cf531070ca9222a1f72c4a5136874121541d9378a9849912a41ec1f0e4677c074edf051624118e0e5a6943170cce4e7bcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":2690}],"signature":["bae63e4214b0ab611079beabca020c82fbcada902f1f0c13106e7c4ba463efb25610d13b00b28cd19b54f648b88a4b05a08583b44b4f4179c2c605b42b22ad4b00"],"txID":"3fca53c08ccb48bb625439a58998713d8ecc3dc1348cc3cfab912e0815b62b1a"},{"blockNumber":20829708,"block_timestamp":1592755074000,"energy_fee":146310,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005fc2678","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758719000,"fee_limit":1000000000,"ref_block_bytes":"d5f5","ref_block_hash":"84843b5d1de30802","timestamp":1592755061404},"raw_data_hex":"0a02d5f5220884843b5d1de308024098a4c5bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005fc2678709c85e6bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":149770}],"signature":["6dd6709cee109df62c3a7f196f45d3efa16c25738c1c4ea371cce18443016c8911a2d65fd4f2d7b4932aed34634169adc981db081522b094e63d9528882b3de801"],"txID":"8e886732999efe30e0d7c93eee40c41f058f33c82194141317768810a5a84b82"},{"blockNumber":20829681,"block_timestamp":1592754993000,"energy_fee":231500,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005e5eb10","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758638000,"fee_limit":1000000000,"ref_block_bytes":"d5da","ref_block_hash":"3234615516f16ee9","timestamp":1592754980996},"raw_data_hex":"0a02d5da22083234615516f16ee940b0abc0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005e5eb10708491e1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":234960}],"signature":["896243c9d9c8ba595deafb81b7c4fc283271e0f46aa7031f270d91a383ce997a09f4a3aa6fb0478a7dac9b7df295dcf232f8bf4941583848f45bd8e258f9482e01"],"txID":"8b7c9f9f29cbf9ced22761f918d19471b3bb638438e6cc23e8104fed7dda1ef3"},{"blockNumber":20829627,"block_timestamp":1592754831000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":2850,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferAssetContract","value":{"amount":7639170000000,"asset_name":"1002000","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874","to_address":"410a60e164aa897ef76779164dff6e36161980c6fb"}},"type":"TransferAssetContract"}],"expiration":1592758479000,"fee_limit":0,"ref_block_bytes":"d5a5","ref_block_hash":"462e1cfdbe99a85b","timestamp":1592754820511},"raw_data_hex":"0a02d5a52208462e1cfdbe99a85b4098d1b6bead2e5a79080212750a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123f0a073130303230303012154179309abcff2cf531070ca9222a1f72c4a51368741a15410a60e164aa897ef76779164dff6e36161980c6fb2080c98e90aade01709fabd7bcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":2850}],"signature":["b49c878a8e85339fc4917e7f20625b38b941871c86572d2c01322ec26575c7024c34b498e464109a03f8e42df24cc0868910a0e7b1f7c174f5005a483a93dac600"],"txID":"79010512f8e58574cbd066d1a1bd1c7f46f65e59e3b7733010047ff8350f15f1"},{"blockNumber":20829617,"block_timestamp":1592754801000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000412b764790f38a7373d56dfdf4f866fa027e28c8af0000000000000000000000000000000000000000000000000000000071006010","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758449000,"fee_limit":1000000000,"ref_block_bytes":"d59b","ref_block_hash":"beab372f7f7d493b","timestamp":1592754790236},"raw_data_hex":"0a02d59b2208beab372f7f7d493b40e8e6b4bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000412b764790f38a7373d56dfdf4f866fa027e28c8af000000000000000000000000000000000000000000000000000000007100601070dcbed5bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["52b662780f176048c4fd9e8db15756d0ef397cb60a8be6ea3421993ec2c6e1636d9aaf8a596f9255c182284e1efbd5410e2a11d10b82b4e4fec5a43ffea357cc01"],"txID":"809ec9beb99cf756bb02155199a35b766f3ec18dd6bea6b3d69dd38f6b51138f"},{"blockNumber":20829617,"block_timestamp":1592754801000,"energy_fee":166700,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041d8692da59c130875e13587a82bc93b917c49526a0000000000000000000000000000000000000000000000000000000054c92b70","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758449000,"fee_limit":1000000000,"ref_block_bytes":"d59b","ref_block_hash":"beab372f7f7d493b","timestamp":1592754789857},"raw_data_hex":"0a02d59b2208beab372f7f7d493b40e8e6b4bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041d8692da59c130875e13587a82bc93b917c49526a0000000000000000000000000000000000000000000000000000000054c92b7070e1bbd5bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170160}],"signature":["fe96d2be46a37f89531d10cdca823ec82c603a3bb9f858aa76db20468e8d9d6058de643460e11b50e0982fa6ab6b81439cee6c9286b5d6bb7c18206e2ab066fb01"],"txID":"bc0c429e33d3c668e5e5a55831efb3aba7e917c52cd3892aeb252f1a7b2ddb41"},{"blockNumber":20829596,"block_timestamp":1592754738000,"energy_fee":166700,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041ec853dc8fe0dab78d3234ba356ebae7984da322c00000000000000000000000000000000000000000000000000000004a817c800","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758386000,"fee_limit":1000000000,"ref_block_bytes":"d586","ref_block_hash":"4007c65312ba945c","timestamp":1592754729408},"raw_data_hex":"0a02d58622084007c65312ba945c40d0fab0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041ec853dc8fe0dab78d3234ba356ebae7984da322c00000000000000000000000000000000000000000000000000000004a817c80070c0e3d1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170160}],"signature":["93119466b23346e095d256537f2bf8c639dd157f896eaaff972f0be83663bca34a21df4e25fa61ba071588a58f98874a58705844a8cc36a321bf30e722028c8201"],"txID":"3bcd581a833abb16529e1f5187615866ba72f2e61c590c993f5b461ba5073d45"},{"blockNumber":20829592,"block_timestamp":1592754726000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac8400000000000000000000000000000000000000000000000000000000001e8480","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758377000,"fee_limit":1000000000,"ref_block_bytes":"d583","ref_block_hash":"0bc07e9ae4eb32b0","timestamp":1592754719032},"raw_data_hex":"0a02d58322080bc07e9ae4eb32b040a8b4b0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac8400000000000000000000000000000000000000000000000000000000001e848070b892d1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["80fe656c430afb348327f279a2d454d277bf64564111e49118ed85f1021528920ba5be044956084f543a087a61aa14b595a4fc2cc6aff2ad2ac5d7533a6b122f01"],"txID":"3baff897a2b39720727549216ea6f4bc580eed2f239967e158e9e7ea74146822"},{"blockNumber":20829589,"block_timestamp":1592754717000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":2690,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":8737000000,"owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874","to_address":"412886fdc89587dbe8a57d0b9589581bd084384d5f"}},"type":"TransferContract"}],"expiration":1592758368000,"fee_limit":0,"ref_block_bytes":"d580","ref_block_hash":"ebf8d3b3837d87a8","timestamp":1592754708731},"raw_data_hex":"0a02d5802208ebf8d3b3837d87a84080eeafbead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a154179309abcff2cf531070ca9222a1f72c4a51368741215412886fdc89587dbe8a57d0b9589581bd084384d5f18c09490c62070fbc1d0bcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":2690}],"signature":["b92bdde424aee97b4e7a63716056daa963afce89701bf6d8c8b1b6221f65afb94b8ff3865650aff83d590cad87359ae5f272ed732738093a0a9aa587cc3503aa01"],"txID":"b38fb6328e1fa622b7762eed856778551845c33723491e36baf357f00cc48002"},{"blockNumber":20829585,"block_timestamp":1592754705000,"energy_fee":43900,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000416128e41b6aa8c531b05999c2861f846459fb10e60000000000000000000000000000000000000000000000000000000005f5e100","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758356000,"fee_limit":1000000000,"ref_block_bytes":"d57c","ref_block_hash":"c7c6e5795625dc5b","timestamp":1592754698724},"raw_data_hex":"0a02d57c2208c7c6e5795625dc5b40a090afbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000416128e41b6aa8c531b05999c2861f846459fb10e60000000000000000000000000000000000000000000000000000000005f5e10070e4f3cfbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":47360}],"signature":["b90e38665957e47ba8f7731e3b8c943471cd6ef9a95efcd25ad880323f2e397b56927e943c7e605a1996900fe269db6edbc7d7ff094f23393c6546ef0927bae300"],"txID":"d8d53a627fa9f885ad77dcc2f3d3a5eceece36d1ef0f54990dff900484550304"},{"blockNumber":20829577,"block_timestamp":1592754681000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041dd81641cca9a855b7a657153fdda9b3f469693660000000000000000000000000000000000000000000000000000000217a31ba0","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758335000,"fee_limit":1000000000,"ref_block_bytes":"d575","ref_block_hash":"003bba00242a2488","timestamp":1592754678392},"raw_data_hex":"0a02d5752208003bba00242a24884098ecadbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd81641cca9a855b7a657153fdda9b3f469693660000000000000000000000000000000000000000000000000000000217a31ba070f8d4cebcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["0abe6787b18631ae746b4a9c9669e3e878b88c3628a3656e3709b4036b14414525bdb9cdb3c97fce48c9d21f2afab9492a436861e2e85ec1f68bab078859eb1d01"],"txID":"b419c05c877e0176619ec3659470c71822a7840a91a940169eaaf1abb9c38fea"},{"blockNumber":20829564,"block_timestamp":1592754642000,"energy_fee":43900,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041a3af64559a63856c625b02e9def8a4dc0f63f38b0000000000000000000000000000000000000000000000000000000010c18918","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758287000,"fee_limit":1000000000,"ref_block_bytes":"d565","ref_block_hash":"afd9deb62b6fa5e0","timestamp":1592754628020},"raw_data_hex":"0a02d5652208afd9deb62b6fa5e04098f5aabead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041a3af64559a63856c625b02e9def8a4dc0f63f38b0000000000000000000000000000000000000000000000000000000010c1891870b4cbcbbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":47360}],"signature":["070c1a53f2fc6b12825b99c9179899e1effbbdf2fad17d273b64bc47f16ee53a0f56096d4ef6ce58aeee65083dcdef8f3c808d6889a990c23a8d45a84cd69bf101"],"txID":"abb6c40f8f8afcc69fb5b549ffb17bd779fa6588dbbbd5e4ee8568839462b37a"},{"blockNumber":20829535,"block_timestamp":1592754555000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000410ae0647bbaa1aebafcc9a360d0e22a791a215c930000000000000000000000000000000000000000000000000000000011e1a300","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758206000,"fee_limit":1000000000,"ref_block_bytes":"d54a","ref_block_hash":"d27814b2e9763d5d","timestamp":1592754547598},"raw_data_hex":"0a02d54a2208d27814b2e9763d5d40b0fca5bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000410ae0647bbaa1aebafcc9a360d0e22a791a215c930000000000000000000000000000000000000000000000000000000011e1a300708ed7c6bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["6a0f4d4d5021c46d522f45552b20218ea16c437e6e87130339c90752f63f7a805763699bad3b22fb3199efdce75f1929ac94482be8551107b051ae4b9ef532bb01"],"txID":"7da3a7819e4de9311464963f829e3ceeff0a045bbd587030deba863a04d250db"},{"blockNumber":20829504,"block_timestamp":1592754462000,"energy_fee":166700,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041042b5bc43cf6aabae0533f4f671eb810615c32be0000000000000000000000000000000000000000000000000000000054c92b70","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758116000,"fee_limit":1000000000,"ref_block_bytes":"d52c","ref_block_hash":"9486bdd9554ef09e","timestamp":1592754457197},"raw_data_hex":"0a02d52c22089486bdd9554ef09e40a0bda0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041042b5bc43cf6aabae0533f4f671eb810615c32be0000000000000000000000000000000000000000000000000000000054c92b7070ed94c1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170160}],"signature":["2bfe810fa90d3aee965ff990fd68490ce9c8421844c1e792a57faeb556e5c9b004499016ace19afdb49ba65531c2d829890b4c6a14a7e58c6b71bfdacc7709e201"],"txID":"4d5e74b87f782060e0657a48898626a51a1bf2dcccfc2083955fa4f43e4516b0"},{"blockNumber":20829499,"block_timestamp":1592754447000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":2538461,"owner_address":"41da03247c21301eaf0538c1b9f79e5c8ea7cbb386","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758089000,"fee_limit":0,"ref_block_bytes":"d523","ref_block_hash":"dc512cab1e07f960","timestamp":1592754430099},"raw_data_hex":"0a02d5232208dc512cab1e07f96040a8ea9ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541da03247c21301eaf0538c1b9f79e5c8ea7cbb38612154179309abcff2cf531070ca9222a1f72c4a513687418ddf79a017093c1bfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["0b542abf1657965deeb06123636f6e4ccaea5f4ab0a14f81f3164b286cb6ede37c62d701c796ae86cbd5c908009e5ac6db73d4532a9976ce5b30df47460957d601"],"txID":"82efc8456a3c38a0919af416a53363405ced78db7c13e1b94a79ebcea98f9909"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":30000000,"owner_address":"41f3eb90cf03d6301e1d10b6095113494bc704992c","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758089000,"fee_limit":0,"ref_block_bytes":"d523","ref_block_hash":"dc512cab1e07f960","timestamp":1592754429791},"raw_data_hex":"0a02d5232208dc512cab1e07f96040a8ea9ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541f3eb90cf03d6301e1d10b6095113494bc704992c12154179309abcff2cf531070ca9222a1f72c4a5136874188087a70e70dfbebfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["d44a181a6ff560bbcd8a89f9b14247f3d3c781020404eb6462926f3e60dfe32c38ee17f0e752346229de30db033352240152891a168285581558f80af90f83fd00"],"txID":"a336bd174c127d38bf2325bc9c927059af099e8cfb91159750a1b1be16dd0bd4"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":111337320,"owner_address":"41b4fd934c73429b27c1e9180e04ccfc44c14f15a9","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758086000,"fee_limit":0,"ref_block_bytes":"d522","ref_block_hash":"9ecd3926187cf28e","timestamp":1592754429463},"raw_data_hex":"0a02d52222089ecd3926187cf28e40f0d29ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541b4fd934c73429b27c1e9180e04ccfc44c14f15a912154179309abcff2cf531070ca9222a1f72c4a513687418e8be8b357097bcbfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["a40ce5f8ab4d9283fd9982eb38aa2a8b8ad9aeaa9bfc8acc220673a367fd420c034f89110e74a99745a96e103b883a85036c64e1c992a7a12c594f11954bacca01"],"txID":"007bbcc3855f4bf51bd76e63d7776160c115c803e227f7c44c7d1fd1bd587611"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":200000000,"owner_address":"413c5d20a6b1747c65903e2874614d6b8a038b818c","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758086000,"fee_limit":0,"ref_block_bytes":"d522","ref_block_hash":"9ecd3926187cf28e","timestamp":1592754429137},"raw_data_hex":"0a02d52222089ecd3926187cf28e40f0d29ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a15413c5d20a6b1747c65903e2874614d6b8a038b818c12154179309abcff2cf531070ca9222a1f72c4a5136874188084af5f70d1b9bfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["9192ee355f2b8c4b21cb68d5b5b2647a4ccb3a00c2bdaeb65cddef4785e7a31e364e21ef3c8b78628c8d342d6f7727ab391b064c1f0b02105e300108ca9cf88800"],"txID":"9351e87b129142844f000a52911daf36fc95677dfe2846abcd28ea0d8fe2e2ea"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":269,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":511000000,"owner_address":"414a5a0f19fd4b1c85208764a7a8cdcdb88171fc71","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758086000,"fee_limit":0,"ref_block_bytes":"d522","ref_block_hash":"9ecd3926187cf28e","timestamp":1592754428706},"raw_data_hex":"0a02d52222089ecd3926187cf28e40f0d29ebead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a15414a5a0f19fd4b1c85208764a7a8cdcdb88171fc7112154179309abcff2cf531070ca9222a1f72c4a513687418c0fbd4f30170a2b6bfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["fac73d7f6540a63c27717cbe04197d8ae89bd906f6c59eba71cc3a2630e29d9b6e0e4400b5e316289e5b6608d84a1a47673674605e48776f8d97aa3dedcfc60301"],"txID":"008ebda5749c38e26a69717faa66e6f4fd8a0d358c9b947192765cc9843cff5a"}]}` + mockedTrc20Response = `{"trc20token_balances":[{"name":"BeeHive","symbol":"Bee","decimals":8,"contract_address":"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK","balance":"100000000000000"},{"name":"NoleCoin","symbol":"NOLE","decimals":6,"contract_address":"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG","balance":"20000","priceInTrx":20.000000},{"name":"Enme Token","symbol":"EME","decimals":6,"contract_address":"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF","balance":"175798"},{"name":"PYRO Network","symbol":"PYRO","decimals":6,"contract_address":"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e","balance":"5000000000","priceInTrx":0.005821},{"name":"Wuhan Fried Bats","symbol":"WUHAN","decimals":4,"contract_address":"TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr","balance":"690000"},{"name":"WINK","symbol":"WIN","decimals":6,"contract_address":"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7","balance":"191543058623486","priceInTrx":0.004665},{"name":"Mono Token","symbol":"MONO","decimals":18,"contract_address":"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak","balance":"1"},{"name":"HelGro","symbol":"HGRO","decimals":6,"contract_address":"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm","balance":"20000000"},{"name":"JUST GOV","symbol":"JST","decimals":18,"contract_address":"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9","balance":"955973733483987848990056","priceInTrx":0.313300},{"name":"Tether USD","symbol":"USDT","decimals":6,"contract_address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","balance":"6781725898163","priceInTrx":64.102564}],"allowExchange":[],"address":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","frozen_supply":[],"bandwidth":{"energyRemaining":0,"totalEnergyLimit":90000000000,"totalEnergyWeight":1446707995,"netUsed":0,"storageLimit":0,"storagePercentage":0.0,"assets":{"1000542":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002446":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002721":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001510":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002962":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001479":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002288":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001594":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002683":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000541":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001079":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000145":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002608":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000821":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002845":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001759":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002726":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001230":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001467":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002798":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000894":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000532":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002830":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000017":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000494":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002398":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002552":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002551":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002672":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002037":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002950":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000935":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000938":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002438":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000491":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000096":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002671":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000493":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001064":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001581":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002270":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000322":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002589":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001411":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002467":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002742":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001414":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001535":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000567":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000165":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001011":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002342":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001132":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000562":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000287":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001815":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002907":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002746":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002748":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001090":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000278":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000157":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002578":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002577":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002852":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002459":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000396":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002573":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002454":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000959":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002736":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002858":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003022":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001038":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000983":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001433":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000743":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001953":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002646":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000985":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002524":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002001":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002881":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002488":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002521":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002762":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002927":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002926":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000745":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000744":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000746":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002000":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000181":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002116":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001301":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001425":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002876":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000176":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000451":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003049":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002597":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002918":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002636":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002999":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001825":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000856":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002517":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002230":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002071":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003041":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002072":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000003":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000520":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000884":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002544":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001854":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002822":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000006":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002662":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002669":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002384":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002263":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001203":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002897":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001565":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002775":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002657":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001204":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001446":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002892":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002939":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002814":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002250":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002099":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000190":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0}},"netPercentage":0.0,"storageUsed":0,"storageRemaining":0,"freeNetLimit":5000,"energyUsed":0,"freeNetRemaining":211,"netLimit":0,"netRemaining":0,"energyLimit":0,"freeNetUsed":4789,"totalNetWeight":26789943446,"freeNetPercentage":0.9578,"energyPercentage":0.0,"totalNetLimit":43200000000},"accountType":0,"exchanges":[],"frozen":{"total":0,"balances":[]},"accountResource":{"frozen_balance_for_energy":{}},"tokenBalances":[{"balance":346976329314696,"name":"_"},{"balance":1273,"name":"1000003"},{"balance":113,"name":"1000006"},{"balance":145,"name":"1000165"},{"balance":416,"name":"1000520"},{"balance":596,"name":"1000491"},{"balance":242,"name":"1000176","owner_address":"THG48yHsR6inxrCJk2hhxZPsFLq1ehP88V"},{"balance":62,"name":"1000542"},{"balance":53,"name":"1000494","owner_address":"TXJnVqqwLSNmdXDLWn1Yfjhe8aZH2oaAuq"},{"balance":56,"name":"1000493"},{"balance":599,"name":"1000744"},{"balance":628,"name":"1000746"},{"balance":234,"name":"1000743"},{"balance":113,"name":"1000396"},{"balance":206,"name":"1000745","owner_address":"TPCEi45wZQ1PPChUg5uqoK1D5kKnjCR8Li"},{"balance":61,"name":"1000821","owner_address":"TBm3Peu51gYwn2iPwNEDxc9vBMc3eRGUGu"},{"balance":25,"name":"1000541"},{"balance":7,"name":"1000278","owner_address":"TRMUimDekf9nDLuVMp6TKzcw4axNnajGJr"},{"balance":1,"name":"1000567","owner_address":"TFXJMhB4ZKBfcQWfCLbSyQGhonHXABaWku"},{"balance":1,"name":"1000856","owner_address":"TXf3X8YMdDho2xwA6QDbFZiTGPnk8ghfLm"},{"balance":30,"name":"1000884"},{"balance":1,"name":"1000894"},{"balance":200,"name":"1000181","owner_address":"TEmTbbvH5ZPJPZ8CbffjqonFRiAAFgfc9o"},{"balance":7,"name":"1000935","owner_address":"TPVkcFYTEi9Dia45AveiTcaYoaU9ux7xC7"},{"balance":1000,"name":"1000938","owner_address":"TNgkWTabK1rMWwgLjmLdsZbzYfGTx5Tpe9"},{"balance":10,"name":"1000017","owner_address":"TV6qcwSp38uESiDczxxb7zbJX1h2LfDs78"},{"balance":10,"name":"1001011","owner_address":"TNUbeTQXPtRXtBX3dJboVkhdhaiws29Aky"},{"balance":2,"name":"1001038","owner_address":"TFujVDp8U578L2AtsorYN3pwdXmH2HxbQv"},{"balance":100,"name":"1000983","owner_address":"TYmiZ7xCeqboiizb2jsjVQuRABXzVSjKFR"},{"balance":1,"name":"1001203","owner_address":"TBmaT8mcrdkrRL2Q6ur7grMYAcaGtfxsz7"},{"balance":1,"name":"1000190","owner_address":"TNXjXURue38Wa641pmqMH4vbJN1WZLKMnr"},{"balance":100,"name":"1001204"},{"balance":1000,"name":"1001230"},{"balance":1300000,"name":"1001301","owner_address":"TVgJEbc9NEYxVr1h6rJQiMqySePsJQDCA7"},{"balance":11,"name":"1000959"},{"balance":10,"name":"1001425"},{"balance":17,"name":"1001433","owner_address":"TWPMz6FPEAV6qP4VRMG3Y69ftEov1R7YWT"},{"balance":100,"name":"1001446"},{"balance":12,"name":"1001411","owner_address":"TPL6zNujtEQ8kp213n58UxAhGRCU3aozkc"},{"balance":12,"name":"1001467"},{"balance":100,"name":"1001414","owner_address":"TT43DgfxgMdR4BVZNua4YCwG34AgfGN6Uu"},{"balance":100,"name":"1001510","owner_address":"TPKq9bVZyM2sZ8XersMmXhy1NbjhdxRwwj"},{"balance":50,"name":"1001565","owner_address":"TKY7Vmq78b2c83fLXrPijkhQkk4EJtfViD"},{"balance":5,"name":"1001535"},{"balance":10,"name":"1000532","owner_address":"TGQwBNht8h3zev4gBtDMoQjWE2WJm1Zr9B"},{"balance":3,"name":"1001479","owner_address":"TC9FtB1EoiV3jfXgZvmqUmfeCmdWNmCxdY"},{"balance":13,"name":"1001090","owner_address":"TU1LUTYDMG6iihimUpAmdnnBthawPKh1cm","priceInTrx":0.004360},{"balance":200,"name":"1001759","owner_address":"TWKWWJAFBYyjvLtfqKCSeMyUW7TjWhkY4e"},{"balance":12,"name":"1000096","owner_address":"TSfjkVSKJGW4aybDQcxi4bpythU7WCXV3v"},{"balance":15,"name":"1001594"},{"balance":10,"name":"1001815","owner_address":"TB3iM1RsKXagV7hdz2QpWnaChptwrU3tCL"},{"balance":10,"name":"1001064","owner_address":"THnWV416C9mfJ1LFwopUjGXZEr1xFtAdrD"},{"balance":5192508733304578,"name":"1002000","owner_address":"TF5Bn4cJCT6GVeUgyCN4rBhDg42KBrpAjg","priceInTrx":0.018900},{"balance":7742069,"name":"1002037","owner_address":"TBekuTCZwPG2o88SmiS58VALkxBemoX4yS"},{"balance":585,"name":"1002001"},{"balance":5441,"name":"1002071","owner_address":"TS79aik831csqUnQgnqrKG6hov2iL8yPbD"},{"balance":80312957663126,"name":"1002072","owner_address":"TP6PtaBSMM6sfWtWWD9k77YHWGmh7K3Lae"},{"balance":520,"name":"1000451","owner_address":"THPXuypwcnWo4wi5KqFfuRjgjeT5khUDKF"},{"balance":10011237,"name":"1001953","owner_address":"TSyG9BdjsGE2GoHG9eeYKMns6zMQFDmbvS"},{"balance":5,"name":"1000562","owner_address":"TWqKTJ5JhyD7rsbbWzEvS5ZZD9Q5QPPvSH"},{"balance":50000000,"name":"1002099","owner_address":"TYWmiPERm9kWUcnduqaE5jxT7eeZxfn5SQ"},{"balance":625100,"name":"1001581","owner_address":"TNkRSKWP7VvdrisTwC8iNzUV6MRoEJh6xx"},{"balance":11000000,"name":"1002342","owner_address":"TUCd8NiBUuxrjz1kSrUbAg2JXu6o27Ukrq"},{"balance":7,"name":"1000322","owner_address":"TDGy2M9qWBepSHDEutWWxWd1JZfmAed3BP","priceInTrx":0.000422},{"balance":12,"name":"1001825","owner_address":"TPcUbNeYwwYqbX23w3sVf1X61cwpAfPK2T"},{"balance":1000,"name":"1002384","owner_address":"TFYuPxyjDTvH1TLm2phpzJFw7AhjCgu8xP"},{"balance":44444,"name":"1001132","owner_address":"TWDUanVdxEShjpbiX57ExztMCDy8vCFcHh"},{"balance":30000000,"name":"1002398","owner_address":"TUXSuMg41nJXm9TuDgF6EZWjEbP2vx1Hd4"},{"balance":10000060,"name":"1002116","owner_address":"TAEvo6MgLgV3A75L3cr3BAsLDJikWcAt3j"},{"balance":50000000,"name":"1002446","owner_address":"TJKf72NjL1cR49SHfDnPTXTFjRwjgr7v8Z"},{"balance":10000000,"name":"1002459","owner_address":"TNWy3mX85JsX2mPLgLc4cKJiWtJahhz3t3"},{"balance":1,"name":"1001079","owner_address":"TLQfc5EwZQqZc6jMNkMpxyJy5wucA6UX24"},{"balance":12345,"name":"1002467","owner_address":"TP429SKrsp4BoTiEFXHj4TNSJwqDFsygnr"},{"balance":1234,"name":"1002230","owner_address":"TWB9Q1JoB3fSLsahNq31gydRxYyWxDhSyk"},{"balance":10000000,"name":"1002288","owner_address":"TPzfpaaKUPgJPZ39YeyvBaTYNXBYpnhxDg"},{"balance":5,"name":"1002488","owner_address":"TMeAzhdgzu1sFMTsP75BffJ2tEzuGsYqR6"},{"balance":666,"name":"1002438","owner_address":"TMqNJwD3qVmuRxzzP3Q4A24fuByVBKQ39E"},{"balance":10000000,"name":"1002517","owner_address":"TP9m11ERHhE1qgDtL83c2AHHNkWvdUfKTz"},{"balance":10000000000,"name":"1002521","owner_address":"TJUwM4qk1et2nNKuESQ7UVHPjAHoRqAz3T"},{"balance":13699,"name":"1000157","owner_address":"TUahmv54ZiDnjQWG2VAeyMphebXQ4m6Hb5"},{"balance":65895,"name":"1002524","owner_address":"TRzZeBPt69utiWx1po5ghLH8uSP8uJGsa5"},{"balance":16,"name":"1000287","owner_address":"TFZCyZ18XNzMfEr6W5kLkGrs4HVmou9H3y"},{"balance":10000000,"name":"1002544","owner_address":"TQHBbjES5DNjDfDHBbpnh9qcDM7mVjSVcL"},{"balance":10000000000,"name":"1002551","owner_address":"TVrGxBCQkWjQ52D7S67UgFsUzcX4E8EsNB"},{"balance":10000000,"name":"1002573","owner_address":"TBfmGqmZtdEQNuYCz8s1izBUDxZbkPmMcj"},{"balance":10000000,"name":"1002552","owner_address":"TCxeAH2ajBqoWzqV9m5YiFTyeQ5FvzVqSH"},{"balance":1000000,"name":"1002578","owner_address":"TUjBG7C1CU7X75UmacnyrRTYLmbSeX7iDa"},{"balance":2555000,"name":"1002270","owner_address":"TMSpdYHCgZuxM7AjqKsjGMM1cpxraFuZGp"},{"balance":10000000,"name":"1002597","owner_address":"TDEBhgsdGTSzrgMsPDUQ1pt59fR6wWR7Rq"},{"balance":10000000,"name":"1002636","owner_address":"TKL54NcGXvBckkGbPjYzAmdwFs3usv8VY9"},{"balance":100000000,"name":"1002250","owner_address":"THUHfNqiYo4KS3GLM8MUU4x3wek9uPD47d"},{"balance":1000000,"name":"1002662","owner_address":"TEV5PJWga6crSeNLHmHaaco8fon6nm74wJ"},{"balance":10000000,"name":"1002672","owner_address":"TBHJCf3nymJPt1hVPjSJfH5ssJLdNMPepe"},{"balance":24120,"name":"1002657","owner_address":"TCKiVea721ycNAWonb2dpwr65AJkMiGSFb"},{"balance":1000000,"name":"1002683","owner_address":"TL6YggMQQ3YFEc41wesBMHZjDxcGpX3y5q"},{"balance":3000000,"name":"1002671","owner_address":"TDQ5q4Hf6UqR43Smp67sndMQfdTcGgP88s"},{"balance":20,"name":"1002577","owner_address":"TGZzci6a9wtcSiNekqYLP84ECRoaJ6pBwY"},{"balance":10000000,"name":"1002721","owner_address":"TUkUgsTTo74B9XG9da4d2NsaZqCKLNFwNS"},{"balance":10000,"name":"1002726","owner_address":"TRXw3Ggt3xs3fHbcoark1aeKwUZFKTYcsS"},{"balance":21092024781,"name":"1002263","owner_address":"TD5AwyiTNbKN9jQqyMzwQ6NLrWGbtAcotK"},{"balance":10000000,"name":"1002736","owner_address":"TBB19fMCf19wuiu5omtA1nAqALPpo4oa32"},{"balance":10000000,"name":"1002646","owner_address":"TRUnzvtzT6o35M4XHUvKr48yCZjw4dQyvp"},{"balance":7392000000,"name":"1002589","owner_address":"TUL9NhGQkRFLTRcHGkdoSniAeVaNPZGgot"},{"balance":10000000,"name":"1002742","owner_address":"TWfrNPVGDh1tyPVM79bfEASb7jw2bLbZPJ"},{"balance":8822711275000000,"name":"1002762","owner_address":"TRChSJM8TjQj7vvJCN9W8WBcfkJq2eBxgv"},{"balance":10000000,"name":"1002775"},{"balance":10000000,"name":"1002798","owner_address":"TBitZMK7YSUb2Q1Cm537D5iAZSJkaPdN9c"},{"balance":95,"name":"1001854","owner_address":"TSMeDkfmX6m1NZmDBrVtGPnACJCUWVkx4p"},{"balance":10000000,"name":"1002746","owner_address":"TQbbAyfcrKERXjUDf8TZfcdtjFQbCSgEfc"},{"balance":2000000,"name":"1002669","owner_address":"THhgpkHBdJDDWBPnZKRgzdvRr3qCtAa2cv"},{"balance":10000000,"name":"1002814","owner_address":"TNvq4y2A2beBENtcGknwhX6XHgk8hqgnVh"},{"balance":10000000,"name":"1002830","owner_address":"THLLMnsEKEci5e5dJHnW28QQU8AujGhSoK"},{"balance":10000000,"name":"1002845","owner_address":"TUzpDkzjWkZasA6Dx7nx5PPskMkCcNxVyQ"},{"balance":10000000,"name":"1002858","owner_address":"TRKJcugHJeffVpCAFGapZMwuH8HaTWjbof"},{"balance":200,"name":"1002454","owner_address":"TDCGkNf3XB3jRGg7bhFkNynkGw7q4kV3z9"},{"balance":10000000,"name":"1002876","owner_address":"TGqiinRV6nn8GbF5LX7zue4fpjstG1gVvu"},{"balance":20000000,"name":"1002881","owner_address":"TWpKN6y3NVXm5mMjGmPEtLpS6boGM4q8T4"},{"balance":350,"name":"1000145","owner_address":"TNFcvwJgvBRg2Dq5Qyx1gxcvqU3dwPyVNc"},{"balance":10000000,"name":"1002892","owner_address":"TECsVV1kTtx48sbdjvptq544h4H3Qqr24c"},{"balance":10000000,"name":"1002897","owner_address":"TPKqse19ALipJ1uBZHGWHzuTrQqZa4HtaM"},{"balance":2055000000,"name":"1002822","owner_address":"TURy9pFLskqTWgkZqUCUdPXkezZfYL76YQ"},{"balance":1000000,"name":"1002852","owner_address":"TUmad3hCqxu78n8GuULrdJMUB4qmTUYgv3"},{"balance":10000000,"name":"1002907","owner_address":"TKC9HMUXx3qLE7d19KWzWVjFxEcWQdSYK9"},{"balance":10000000,"name":"1002927","owner_address":"TAwRvFAqfB4bbzVCVPgGATZV5uMVs9UyVL"},{"balance":10000000,"name":"1002926","owner_address":"TF5jfDiQ3d7T5ihcBxeWS9S8xSR5tS738x"},{"balance":1000000,"name":"1002748","owner_address":"TTUAmhh9k2Yegf3TxZc86vG5E9kT24vgcw"},{"balance":189990000000,"name":"1002950","owner_address":"TNCZCGDPQ69ieJFsY1jZUohXmR46A4kM24"},{"balance":10,"name":"1000985","owner_address":"TRH5jmPx77UnMvfdvfo2m3FCkZVcBiFvqP"},{"balance":10000000,"name":"1002962","owner_address":"TFDwGwod9qopreRiirsFMwPzX4v2r662P4"},{"balance":10000000,"name":"1002918","owner_address":"TKGpTks1myPrJ9ZtEdLgpjvg1RMR2wGAFz"},{"balance":1000,"name":"1002608","owner_address":"TDPsSgBQznKEffdTMq3aspsvrmFfhL7ZcP"},{"balance":10000000,"name":"1002999","owner_address":"TTL52uBzTG7qorL7BQYdjGUY3HWWr9Kvao"},{"balance":100000000000,"name":"1003022","owner_address":"TAAJiJ1NgkEkE3w1PQk4dA8XH9rpfk5eVE"},{"balance":1000000000,"name":"1003041","owner_address":"TQADZoww5HstdsJM1GXwstqsRRnmrkThzY"},{"balance":10000000,"name":"1003049","owner_address":"THFJwSN5Z3zTc5TvkSiVh8m4kQMZaTMaqk"},{"balance":1,"name":"1002939","owner_address":"TAsSw8hUddYi8AN8EkDuAMS9r8pkriyUxs"}],"balances":[{"balance":346976329314696,"name":"_"},{"balance":1273,"name":"1000003"},{"balance":113,"name":"1000006"},{"balance":145,"name":"1000165"},{"balance":416,"name":"1000520"},{"balance":596,"name":"1000491"},{"balance":242,"name":"1000176","owner_address":"THG48yHsR6inxrCJk2hhxZPsFLq1ehP88V"},{"balance":62,"name":"1000542"},{"balance":53,"name":"1000494","owner_address":"TXJnVqqwLSNmdXDLWn1Yfjhe8aZH2oaAuq"},{"balance":56,"name":"1000493"},{"balance":599,"name":"1000744"},{"balance":628,"name":"1000746"},{"balance":234,"name":"1000743"},{"balance":113,"name":"1000396"},{"balance":206,"name":"1000745","owner_address":"TPCEi45wZQ1PPChUg5uqoK1D5kKnjCR8Li"},{"balance":61,"name":"1000821","owner_address":"TBm3Peu51gYwn2iPwNEDxc9vBMc3eRGUGu"},{"balance":25,"name":"1000541"},{"balance":7,"name":"1000278","owner_address":"TRMUimDekf9nDLuVMp6TKzcw4axNnajGJr"},{"balance":1,"name":"1000567","owner_address":"TFXJMhB4ZKBfcQWfCLbSyQGhonHXABaWku"},{"balance":1,"name":"1000856","owner_address":"TXf3X8YMdDho2xwA6QDbFZiTGPnk8ghfLm"},{"balance":30,"name":"1000884"},{"balance":1,"name":"1000894"},{"balance":200,"name":"1000181","owner_address":"TEmTbbvH5ZPJPZ8CbffjqonFRiAAFgfc9o"},{"balance":7,"name":"1000935","owner_address":"TPVkcFYTEi9Dia45AveiTcaYoaU9ux7xC7"},{"balance":1000,"name":"1000938","owner_address":"TNgkWTabK1rMWwgLjmLdsZbzYfGTx5Tpe9"},{"balance":10,"name":"1000017","owner_address":"TV6qcwSp38uESiDczxxb7zbJX1h2LfDs78"},{"balance":10,"name":"1001011","owner_address":"TNUbeTQXPtRXtBX3dJboVkhdhaiws29Aky"},{"balance":2,"name":"1001038","owner_address":"TFujVDp8U578L2AtsorYN3pwdXmH2HxbQv"},{"balance":100,"name":"1000983","owner_address":"TYmiZ7xCeqboiizb2jsjVQuRABXzVSjKFR"},{"balance":1,"name":"1001203","owner_address":"TBmaT8mcrdkrRL2Q6ur7grMYAcaGtfxsz7"},{"balance":1,"name":"1000190","owner_address":"TNXjXURue38Wa641pmqMH4vbJN1WZLKMnr"},{"balance":100,"name":"1001204"},{"balance":1000,"name":"1001230"},{"balance":1300000,"name":"1001301","owner_address":"TVgJEbc9NEYxVr1h6rJQiMqySePsJQDCA7"},{"balance":11,"name":"1000959"},{"balance":10,"name":"1001425"},{"balance":17,"name":"1001433","owner_address":"TWPMz6FPEAV6qP4VRMG3Y69ftEov1R7YWT"},{"balance":100,"name":"1001446"},{"balance":12,"name":"1001411","owner_address":"TPL6zNujtEQ8kp213n58UxAhGRCU3aozkc"},{"balance":12,"name":"1001467"},{"balance":100,"name":"1001414","owner_address":"TT43DgfxgMdR4BVZNua4YCwG34AgfGN6Uu"},{"balance":100,"name":"1001510","owner_address":"TPKq9bVZyM2sZ8XersMmXhy1NbjhdxRwwj"},{"balance":50,"name":"1001565","owner_address":"TKY7Vmq78b2c83fLXrPijkhQkk4EJtfViD"},{"balance":5,"name":"1001535"},{"balance":10,"name":"1000532","owner_address":"TGQwBNht8h3zev4gBtDMoQjWE2WJm1Zr9B"},{"balance":3,"name":"1001479","owner_address":"TC9FtB1EoiV3jfXgZvmqUmfeCmdWNmCxdY"},{"balance":13,"name":"1001090","owner_address":"TU1LUTYDMG6iihimUpAmdnnBthawPKh1cm","priceInTrx":0.004360},{"balance":200,"name":"1001759","owner_address":"TWKWWJAFBYyjvLtfqKCSeMyUW7TjWhkY4e"},{"balance":12,"name":"1000096","owner_address":"TSfjkVSKJGW4aybDQcxi4bpythU7WCXV3v"},{"balance":15,"name":"1001594"},{"balance":10,"name":"1001815","owner_address":"TB3iM1RsKXagV7hdz2QpWnaChptwrU3tCL"},{"balance":10,"name":"1001064","owner_address":"THnWV416C9mfJ1LFwopUjGXZEr1xFtAdrD"},{"balance":5192508733304578,"name":"1002000","owner_address":"TF5Bn4cJCT6GVeUgyCN4rBhDg42KBrpAjg","priceInTrx":0.018900},{"balance":7742069,"name":"1002037","owner_address":"TBekuTCZwPG2o88SmiS58VALkxBemoX4yS"},{"balance":585,"name":"1002001"},{"balance":5441,"name":"1002071","owner_address":"TS79aik831csqUnQgnqrKG6hov2iL8yPbD"},{"balance":80312957663126,"name":"1002072","owner_address":"TP6PtaBSMM6sfWtWWD9k77YHWGmh7K3Lae"},{"balance":520,"name":"1000451","owner_address":"THPXuypwcnWo4wi5KqFfuRjgjeT5khUDKF"},{"balance":10011237,"name":"1001953","owner_address":"TSyG9BdjsGE2GoHG9eeYKMns6zMQFDmbvS"},{"balance":5,"name":"1000562","owner_address":"TWqKTJ5JhyD7rsbbWzEvS5ZZD9Q5QPPvSH"},{"balance":50000000,"name":"1002099","owner_address":"TYWmiPERm9kWUcnduqaE5jxT7eeZxfn5SQ"},{"balance":625100,"name":"1001581","owner_address":"TNkRSKWP7VvdrisTwC8iNzUV6MRoEJh6xx"},{"balance":11000000,"name":"1002342","owner_address":"TUCd8NiBUuxrjz1kSrUbAg2JXu6o27Ukrq"},{"balance":7,"name":"1000322","owner_address":"TDGy2M9qWBepSHDEutWWxWd1JZfmAed3BP","priceInTrx":0.000422},{"balance":12,"name":"1001825","owner_address":"TPcUbNeYwwYqbX23w3sVf1X61cwpAfPK2T"},{"balance":1000,"name":"1002384","owner_address":"TFYuPxyjDTvH1TLm2phpzJFw7AhjCgu8xP"},{"balance":44444,"name":"1001132","owner_address":"TWDUanVdxEShjpbiX57ExztMCDy8vCFcHh"},{"balance":30000000,"name":"1002398","owner_address":"TUXSuMg41nJXm9TuDgF6EZWjEbP2vx1Hd4"},{"balance":10000060,"name":"1002116","owner_address":"TAEvo6MgLgV3A75L3cr3BAsLDJikWcAt3j"},{"balance":50000000,"name":"1002446","owner_address":"TJKf72NjL1cR49SHfDnPTXTFjRwjgr7v8Z"},{"balance":10000000,"name":"1002459","owner_address":"TNWy3mX85JsX2mPLgLc4cKJiWtJahhz3t3"},{"balance":1,"name":"1001079","owner_address":"TLQfc5EwZQqZc6jMNkMpxyJy5wucA6UX24"},{"balance":12345,"name":"1002467","owner_address":"TP429SKrsp4BoTiEFXHj4TNSJwqDFsygnr"},{"balance":1234,"name":"1002230","owner_address":"TWB9Q1JoB3fSLsahNq31gydRxYyWxDhSyk"},{"balance":10000000,"name":"1002288","owner_address":"TPzfpaaKUPgJPZ39YeyvBaTYNXBYpnhxDg"},{"balance":5,"name":"1002488","owner_address":"TMeAzhdgzu1sFMTsP75BffJ2tEzuGsYqR6"},{"balance":666,"name":"1002438","owner_address":"TMqNJwD3qVmuRxzzP3Q4A24fuByVBKQ39E"},{"balance":10000000,"name":"1002517","owner_address":"TP9m11ERHhE1qgDtL83c2AHHNkWvdUfKTz"},{"balance":10000000000,"name":"1002521","owner_address":"TJUwM4qk1et2nNKuESQ7UVHPjAHoRqAz3T"},{"balance":13699,"name":"1000157","owner_address":"TUahmv54ZiDnjQWG2VAeyMphebXQ4m6Hb5"},{"balance":65895,"name":"1002524","owner_address":"TRzZeBPt69utiWx1po5ghLH8uSP8uJGsa5"},{"balance":16,"name":"1000287","owner_address":"TFZCyZ18XNzMfEr6W5kLkGrs4HVmou9H3y"},{"balance":10000000,"name":"1002544","owner_address":"TQHBbjES5DNjDfDHBbpnh9qcDM7mVjSVcL"},{"balance":10000000000,"name":"1002551","owner_address":"TVrGxBCQkWjQ52D7S67UgFsUzcX4E8EsNB"},{"balance":10000000,"name":"1002573","owner_address":"TBfmGqmZtdEQNuYCz8s1izBUDxZbkPmMcj"},{"balance":10000000,"name":"1002552","owner_address":"TCxeAH2ajBqoWzqV9m5YiFTyeQ5FvzVqSH"},{"balance":1000000,"name":"1002578","owner_address":"TUjBG7C1CU7X75UmacnyrRTYLmbSeX7iDa"},{"balance":2555000,"name":"1002270","owner_address":"TMSpdYHCgZuxM7AjqKsjGMM1cpxraFuZGp"},{"balance":10000000,"name":"1002597","owner_address":"TDEBhgsdGTSzrgMsPDUQ1pt59fR6wWR7Rq"},{"balance":10000000,"name":"1002636","owner_address":"TKL54NcGXvBckkGbPjYzAmdwFs3usv8VY9"},{"balance":100000000,"name":"1002250","owner_address":"THUHfNqiYo4KS3GLM8MUU4x3wek9uPD47d"},{"balance":1000000,"name":"1002662","owner_address":"TEV5PJWga6crSeNLHmHaaco8fon6nm74wJ"},{"balance":10000000,"name":"1002672","owner_address":"TBHJCf3nymJPt1hVPjSJfH5ssJLdNMPepe"},{"balance":24120,"name":"1002657","owner_address":"TCKiVea721ycNAWonb2dpwr65AJkMiGSFb"},{"balance":1000000,"name":"1002683","owner_address":"TL6YggMQQ3YFEc41wesBMHZjDxcGpX3y5q"},{"balance":3000000,"name":"1002671","owner_address":"TDQ5q4Hf6UqR43Smp67sndMQfdTcGgP88s"},{"balance":20,"name":"1002577","owner_address":"TGZzci6a9wtcSiNekqYLP84ECRoaJ6pBwY"},{"balance":10000000,"name":"1002721","owner_address":"TUkUgsTTo74B9XG9da4d2NsaZqCKLNFwNS"},{"balance":10000,"name":"1002726","owner_address":"TRXw3Ggt3xs3fHbcoark1aeKwUZFKTYcsS"},{"balance":21092024781,"name":"1002263","owner_address":"TD5AwyiTNbKN9jQqyMzwQ6NLrWGbtAcotK"},{"balance":10000000,"name":"1002736","owner_address":"TBB19fMCf19wuiu5omtA1nAqALPpo4oa32"},{"balance":10000000,"name":"1002646","owner_address":"TRUnzvtzT6o35M4XHUvKr48yCZjw4dQyvp"},{"balance":7392000000,"name":"1002589","owner_address":"TUL9NhGQkRFLTRcHGkdoSniAeVaNPZGgot"},{"balance":10000000,"name":"1002742","owner_address":"TWfrNPVGDh1tyPVM79bfEASb7jw2bLbZPJ"},{"balance":8822711275000000,"name":"1002762","owner_address":"TRChSJM8TjQj7vvJCN9W8WBcfkJq2eBxgv"},{"balance":10000000,"name":"1002775"},{"balance":10000000,"name":"1002798","owner_address":"TBitZMK7YSUb2Q1Cm537D5iAZSJkaPdN9c"},{"balance":95,"name":"1001854","owner_address":"TSMeDkfmX6m1NZmDBrVtGPnACJCUWVkx4p"},{"balance":10000000,"name":"1002746","owner_address":"TQbbAyfcrKERXjUDf8TZfcdtjFQbCSgEfc"},{"balance":2000000,"name":"1002669","owner_address":"THhgpkHBdJDDWBPnZKRgzdvRr3qCtAa2cv"},{"balance":10000000,"name":"1002814","owner_address":"TNvq4y2A2beBENtcGknwhX6XHgk8hqgnVh"},{"balance":10000000,"name":"1002830","owner_address":"THLLMnsEKEci5e5dJHnW28QQU8AujGhSoK"},{"balance":10000000,"name":"1002845","owner_address":"TUzpDkzjWkZasA6Dx7nx5PPskMkCcNxVyQ"},{"balance":10000000,"name":"1002858","owner_address":"TRKJcugHJeffVpCAFGapZMwuH8HaTWjbof"},{"balance":200,"name":"1002454","owner_address":"TDCGkNf3XB3jRGg7bhFkNynkGw7q4kV3z9"},{"balance":10000000,"name":"1002876","owner_address":"TGqiinRV6nn8GbF5LX7zue4fpjstG1gVvu"},{"balance":20000000,"name":"1002881","owner_address":"TWpKN6y3NVXm5mMjGmPEtLpS6boGM4q8T4"},{"balance":350,"name":"1000145","owner_address":"TNFcvwJgvBRg2Dq5Qyx1gxcvqU3dwPyVNc"},{"balance":10000000,"name":"1002892","owner_address":"TECsVV1kTtx48sbdjvptq544h4H3Qqr24c"},{"balance":10000000,"name":"1002897","owner_address":"TPKqse19ALipJ1uBZHGWHzuTrQqZa4HtaM"},{"balance":2055000000,"name":"1002822","owner_address":"TURy9pFLskqTWgkZqUCUdPXkezZfYL76YQ"},{"balance":1000000,"name":"1002852","owner_address":"TUmad3hCqxu78n8GuULrdJMUB4qmTUYgv3"},{"balance":10000000,"name":"1002907","owner_address":"TKC9HMUXx3qLE7d19KWzWVjFxEcWQdSYK9"},{"balance":10000000,"name":"1002927","owner_address":"TAwRvFAqfB4bbzVCVPgGATZV5uMVs9UyVL"},{"balance":10000000,"name":"1002926","owner_address":"TF5jfDiQ3d7T5ihcBxeWS9S8xSR5tS738x"},{"balance":1000000,"name":"1002748","owner_address":"TTUAmhh9k2Yegf3TxZc86vG5E9kT24vgcw"},{"balance":189990000000,"name":"1002950","owner_address":"TNCZCGDPQ69ieJFsY1jZUohXmR46A4kM24"},{"balance":10,"name":"1000985","owner_address":"TRH5jmPx77UnMvfdvfo2m3FCkZVcBiFvqP"},{"balance":10000000,"name":"1002962","owner_address":"TFDwGwod9qopreRiirsFMwPzX4v2r662P4"},{"balance":10000000,"name":"1002918","owner_address":"TKGpTks1myPrJ9ZtEdLgpjvg1RMR2wGAFz"},{"balance":1000,"name":"1002608","owner_address":"TDPsSgBQznKEffdTMq3aspsvrmFfhL7ZcP"},{"balance":10000000,"name":"1002999","owner_address":"TTL52uBzTG7qorL7BQYdjGUY3HWWr9Kvao"},{"balance":100000000000,"name":"1003022","owner_address":"TAAJiJ1NgkEkE3w1PQk4dA8XH9rpfk5eVE"},{"balance":1000000000,"name":"1003041","owner_address":"TQADZoww5HstdsJM1GXwstqsRRnmrkThzY"},{"balance":10000000,"name":"1003049","owner_address":"THFJwSN5Z3zTc5TvkSiVh8m4kQMZaTMaqk"},{"balance":1,"name":"1002939","owner_address":"TAsSw8hUddYi8AN8EkDuAMS9r8pkriyUxs"}],"balance":346976329314696,"voteTotal":0,"name":"","delegated":{"sentDelegatedBandwidth":[],"sentDelegatedResource":[],"receivedDelegatedResource":[],"receivedDelegatedBandwidth":[]},"totalTransactionCount":508552,"representative":{"lastWithDrawTime":0,"allowance":0,"enabled":false,"url":""},"activePermissions":[]}` + mockedTransactionsTrc20Response = `{"success":true,"meta":{"at":1592757126588,"page_size":20,"fingerprint":"2tmLC90HQEnpnJ02w3n","links":{"next":"https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D/transactions/trc20?fingerprint=2tmLC90HQEnpnJ02w3n"}},"data":[{"block_timestamp":1592757117000,"value":"500000000","type":"Transfer","transaction_id":"fb078403adfee637608c3906d9d21dd158611aba149b9993f43d0f292ce543a0","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","token_info":{"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","name":"Tether USD","symbol":"USDT","decimals":6},"_unconfirmed":true},{"block_timestamp":1592757066000,"value":"50000000","type":"Transfer","transaction_id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","token_info":{"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","name":"Tether USD","symbol":"USDT","decimals":6},"_unconfirmed":true},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","block_timestamp":1592757066000,"value":"50000000","type":"Transfer","transaction_id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV","block_timestamp":1592756784000,"value":"3988000000","type":"Transfer","transaction_id":"0b52a4ef9fb8c13fbfae2b8c3506333ec1d718f307062a15f170562818a01d0a","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am","block_timestamp":1592756763000,"value":"640990000","type":"Transfer","transaction_id":"19d2ec6174bf64beb1061475f6429cba03b64944a763686cc3551447d0e8d9d5","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756631000,"value":"1062000000","type":"Transfer","transaction_id":"efb7d44305759cfb189c9fd22720609a2ddeb7fbd7c8afe1dd8851342471da8d","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","block_timestamp":1592756610000,"value":"2000000","type":"Transfer","transaction_id":"48bd90dc3f12086178e65b9389caa8b3c74683937b86d4d61cdec77f0095994a","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R","block_timestamp":1592756589000,"value":"1000000000","type":"Transfer","transaction_id":"afd5ae7e2462c9cc899c7f730b90fd2a5e4c1315e836c92468b504ed85f0b798","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq","block_timestamp":1592756583000,"value":"21200000","type":"Transfer","transaction_id":"3d613031f4b2a0e19deeea030d1d18599b6d9799d2dd530005ead9712c6d219d","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5","block_timestamp":1592756583000,"value":"125000000","type":"Transfer","transaction_id":"cbe359c2574efbdc8fc6a892ffc54812837295067c9816d41734126c82d0c141","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC","block_timestamp":1592756583000,"value":"5277600000","type":"Transfer","transaction_id":"c87248b02a4caaa6f443c1b8c4d4588c8dd281a4687b73e6afecfba6741b50d8","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W","block_timestamp":1592756583000,"value":"485342000","type":"Transfer","transaction_id":"8584f1b6a70ead8232fed19bd653ba13e4c2a8befd070f4a9a06eca3a2e3e548","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr","block_timestamp":1592756583000,"value":"1000000000","type":"Transfer","transaction_id":"2b28b69e6747db68647acc3a62c45da5355b97acd8d2c260ee752aa9bd63a624","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x","block_timestamp":1592756583000,"value":"2000000000","type":"Transfer","transaction_id":"1da6576dec0bd303f56cbfb5712f782e0a56a8713cb661f8afd2f2533e5c6209","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK","block_timestamp":1592756583000,"value":"24216600000","type":"Transfer","transaction_id":"f9c86cce1873cb816d6cd8718e76df8839172add293bbc8d11a5f98c80f9e322","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756541000,"value":"8241997837","type":"Transfer","transaction_id":"75eb35734857daa79c38ef923a7e7eb2e3dfb23d2722762fd2b180651021643f","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756220000,"value":"18000000000","type":"Transfer","transaction_id":"adee73dadce006ff848ff30d8c5c41f033be2e5e1a8b875f6dbbaab524177d08","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592755962000,"value":"863399098","type":"Transfer","transaction_id":"3655a1156c9adcb876c6c9c9e0f5f1f39704ac4c7296fea05fedf5ca8f6b1a19","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ","block_timestamp":1592755740000,"value":"20000000","type":"Transfer","transaction_id":"03574741eb0016050a19f181e4acc4b20b70f41e11e63140c9556c31eae09fba","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug","block_timestamp":1592755722000,"value":"21161340000","type":"Transfer","transaction_id":"f3aa00595996e31dbe9528a3cb21bff987f333bf1f675420ba4fa2ad43c8205f","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}}]}` + mockedTransactionsEmptyResponse = `{"success":true,"meta":{"at":1592757318961,"page_size":20,"fingerprint":"AYa6eBNpCs5E2DnumiJJJWJ3n2PYMBRFvU7BLjXD49Jm779DJ1C1hUgjwJAmQx5Y2BnkStKMjzQvcALKeQJYfW51m6sY7YEWW","links":{"next":"https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R/transactions?fingerprint=AYa6eBNpCs5E2DnumiJJJWJ3n2PYMBRFvU7BLjXD49Jm779DJ1C1hUgjwJAmQx5Y2BnkStKMjzQvcALKeQJYfW51m6sY7YEWW"}},"data":[]}` + mockedAsset1000542Response = `{"success":true,"meta":{"at":1592754266101,"page_size":1},"data":[{"id":"1000542","abbr":"FOM","description":"Fomo3D is a decentralized, trustless blockchain game.","name":"FomoThreeD","num":1,"total_supply":80000000000,"trx_num":1000000,"url":"https://fomo3d.games/","owner_address":"4134f1b9c19cf40f565661697eb47b0090ac779507","start_time":1534348821000,"end_time":1924876800000}]}` + mockedAsset1000567Response = `{"success":true,"meta":{"at":1592754347268,"page_size":1},"data":[{"id":"1000567","abbr":"os","description":"Open Decentralized Search Engine","frozen_supply":[{"frozen_amount":74000000000,"frozen_days":3652}],"name":"OtonamiS","num":100,"total_supply":99000000000,"trx_num":1000000,"url":"https://OtonamiS.com","owner_address":"413cea69143b5a5b1ff15d847a7e30e3bffa6a2247","start_time":1534773969000,"end_time":1566280800000}]}` + mockedAssetTR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6tResponse = `{"success":true,"meta":{"at":1592754347268,"page_size":1},"data":[]}` + mockedAccountsResponse = `{"success":true,"meta":{"at":1592753781505,"page_size":1},"data":[{"account_resource":{"latest_consume_time_for_energy":1592753721000},"address":"4179309abcff2cf531070ca9222a1f72c4a5136874","asset":[{"key":"IPFS","value":1273},{"key":"TRXTestCoin","value":113},{"key":"Skypeople","value":145},{"key":"binance","value":416},{"key":"BitTorrent","value":596},{"key":"ofoBike","value":242},{"key":"FomoThreeD","value":62},{"key":"Durex","value":53},{"key":"Pornhub","value":56},{"key":"NBACoin","value":599},{"key":"HuobiToken","value":628},{"key":"MacCoin","value":234},{"key":"Messenger","value":113},{"key":"Bithumb","value":206},{"key":"James","value":61},{"key":"RingCoin","value":25},{"key":"DACC","value":7},{"key":"OtonamiS","value":1},{"key":"intrxChain","value":1},{"key":"TRONEX","value":30},{"key":"Petro","value":1},{"key":"KrMaToken","value":200},{"key":"KsumNole","value":7},{"key":"eFilingPlus","value":1000},{"key":"Tarquin","value":10},{"key":"KiloReX","value":10},{"key":"BESTCOIN","value":2},{"key":"Makememillionaire","value":100},{"key":"MedicCoin","value":1},{"key":"DMT","value":1},{"key":"MedIBlock","value":100},{"key":"ethereum","value":1000},{"key":"COLORBIKE","value":1300000},{"key":"WatsonAI","value":11},{"key":"Litcoin","value":10},{"key":"TronMatrixAI","value":17},{"key":"GoodKarma","value":100},{"key":"CryptoBankCoin","value":12},{"key":"EXODUS","value":12},{"key":"TRONO","value":100},{"key":"NMIToken","value":100},{"key":"Ton","value":50},{"key":"Twx","value":5},{"key":"TronLottery","value":10},{"key":"TronTokensGuardian","value":3},{"key":"TRONONE","value":13},{"key":"ELVIS","value":200},{"key":"URUNIT","value":12},{"key":"CRYPTYK","value":15},{"key":"TronRoyal","value":10}],"assetV2":[{"key":"1000542","value":62},{"key":"1000567","value":0}],"balance":346991703615806,"create_time":1535532969000,"free_asset_net_usageV2":[{"key":"1000542","value":0},{"key":"1000567","value":0}],"free_net_usage":4828,"latest_consume_free_time":1592751174000,"latest_opration_time":1592753721000,"trc20":[{"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9":"955973733483987848990056"},{"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7":"191543058623486"},{"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK":"100000000000000"},{"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t":"6849738905400"},{"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e":"5000000000"},{"TJSF4iVkzkRkYwEVNkqJkeGDaZpnFbGy9x":"500000000"},{"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm":"20000000"},{"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF":"175798"},{"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG":"20000"},{"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak":"1"}]}]}` +) diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index baf200c18..156eed36e 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -6,17 +6,18 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" + "strconv" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - Txs, err := p.client.GetTxsOfAddress(address, "") + Txs, err := p.client.fetchTxsOfAddress(address, "") if err != nil && len(Txs) == 0 { return nil, err } txs := make(blockatlas.TxPage, 0) for _, srcTx := range Txs { - tx, err := Normalize(srcTx) + tx, err := normalize(srcTx) if err != nil { continue } @@ -32,52 +33,106 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { } func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { - tokenTxs, err := p.client.GetTxsOfAddress(address, token) + unknownTokenType := errors.E("unknownTokenType") + tokenType := getTokenType(token) + + switch tokenType { + case blockatlas.TokenTypeTRC10: + txs, err := p.fetchTransactionsForTRC10Tokens(address, token) + if err != nil { + return nil, err + } + return txs, nil + case blockatlas.TokenTypeTRC20: + trc20Transactions, err := p.client.fetchTRC20Transactions(address) + if err != nil { + return nil, err + } + return blockatlas.TxPage(normalizeTRC20Transactions(trc20Transactions)), nil + default: + return nil, unknownTokenType + } +} + +func getTokenType(token string) blockatlas.TokenType { + _, err := strconv.Atoi(token) if err != nil { - return nil, errors.E(err, "TRON: failed to get token from address", errors.TypePlatformApi, - errors.Params{"address": address, "token": token}) + return blockatlas.TokenTypeTRC20 + } else { + return blockatlas.TokenTypeTRC10 } +} +func addTokenMeta(tx *blockatlas.Tx, srcTx Tx, tokenInfo AssetInfo) { + transfer := srcTx.Data.Contracts[0].Parameter.Value + tx.Meta = blockatlas.TokenTransfer{ + Name: tokenInfo.Name, + Symbol: tokenInfo.Symbol, + TokenID: tokenInfo.ID, + Decimals: tokenInfo.Decimals, + Value: transfer.Amount, + From: tx.From, + To: tx.To, + } +} + +func (p *Platform) fetchTransactionsForTRC10Tokens(address, token string) (blockatlas.TxPage, error) { txs := make(blockatlas.TxPage, 0) - if len(tokenTxs) == 0 { - return txs, nil + tokenTxs, err := p.client.fetchTxsOfAddress(address, token) + if err != nil { + return nil, errors.E(err, "TRON: failed to get token from address", errors.TypePlatformApi, + errors.Params{"address": address, "token": token}) } - info, err := p.client.GetTokenInfo(token) - if err != nil || len(info.Data) == 0 { + info, err := p.client.fetchTokenInfo(token) + if err != nil { return nil, errors.E(err, "TRON: failed to get token info", errors.TypePlatformApi, errors.Params{"address": address, "token": token}) } - for _, srcTx := range tokenTxs { - tx, err := Normalize(srcTx) + tx, err := normalize(srcTx) if err != nil { logger.Error(err) continue } - setTokenMeta(tx, srcTx, info.Data[0]) + if info.Data != nil && len(info.Data) > 0 { + addTokenMeta(tx, srcTx, info.Data[0]) + } + txs = append(txs, *tx) } - return txs, nil } -func setTokenMeta(tx *blockatlas.Tx, srcTx Tx, tokenInfo AssetInfo) { - transfer := srcTx.Data.Contracts[0].Parameter.Value - tx.Meta = blockatlas.TokenTransfer{ - Name: tokenInfo.Name, - Symbol: tokenInfo.Symbol, - TokenID: tokenInfo.ID, - Decimals: tokenInfo.Decimals, - Value: transfer.Amount, - From: tx.From, - To: tx.To, +func normalizeTRC20Transactions(transactions TRC20Transactions) blockatlas.Txs { + txs := make(blockatlas.Txs, 0, len(transactions.Data)) + for _, rawTx := range transactions.Data { + tx := blockatlas.Tx{ + ID: rawTx.TransactionID, + Coin: coin.TRX, + Date: rawTx.BlockTimestamp / 1000, + From: rawTx.From, + To: rawTx.To, + Fee: "0", + Block: 0, + Status: blockatlas.StatusCompleted, + Meta: blockatlas.TokenTransfer{ + Name: rawTx.TokenInfo.Name, + Symbol: rawTx.TokenInfo.Symbol, + TokenID: rawTx.TokenInfo.Address, + Decimals: uint(rawTx.TokenInfo.Decimals), + Value: blockatlas.Amount(rawTx.Value), + From: rawTx.From, + To: rawTx.To, + }, + } + txs = append(txs, tx) } + return txs } -/// Normalize converts a Tron transaction into the generic model -func Normalize(srcTx Tx) (*blockatlas.Tx, error) { +func normalize(srcTx Tx) (*blockatlas.Tx, error) { if len(srcTx.Data.Contracts) == 0 { return nil, errors.E("TRON: transfer without contract", errors.TypePlatformApi, errors.Params{"tx": srcTx}) diff --git a/platform/tron/transaction_test.go b/platform/tron/transaction_test.go index 6a619e990..e3da6d200 100644 --- a/platform/tron/transaction_test.go +++ b/platform/tron/transaction_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "net/http/httptest" "testing" ) @@ -108,10 +109,10 @@ func testNormalizeTokenTransfer(t *testing.T, _test *test) { err := json.Unmarshal([]byte(_test.apiResponse), &srcTx) assert.NoError(t, err) assert.NotNil(t, srcTx) - res, err := Normalize(srcTx) + res, err := normalize(srcTx) assert.NoError(t, err) assert.NotNil(t, res) - setTokenMeta(res, srcTx, assetInfo) + addTokenMeta(res, srcTx, assetInfo) assert.Equal(t, _test.expected, res) } @@ -128,8 +129,55 @@ func testNormalize(t *testing.T, _test *test) { err := json.Unmarshal([]byte(_test.apiResponse), &srcTx) assert.NoError(t, err) assert.NotNil(t, srcTx) - res, err := Normalize(srcTx) + res, err := normalize(srcTx) assert.NoError(t, err) assert.NotNil(t, res) assert.Equal(t, _test.expected, res) } + +func TestPlatform_GetTxsByAddress(t *testing.T) { + server := httptest.NewServer(createMockedAPI()) + defer server.Close() + + p := Init(server.URL, server.URL) + res, err := p.GetTxsByAddress("TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R") + assert.Nil(t, err) + + rawRes, err := json.Marshal(res) + assert.Nil(t, err) + assert.Equal(t, wantedTransactionsOnly, string(rawRes)) +} + +func TestPlatform_GetTokenTxsByAddress(t *testing.T) { + server := httptest.NewServer(createMockedAPI()) + defer server.Close() + + p := Init(server.URL, server.URL) + res, err := p.GetTokenTxsByAddress("TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t") + assert.Nil(t, err) + + rawRes, err := json.Marshal(res) + assert.Nil(t, err) + assert.Equal(t, wantedTransactionsWithToken, string(rawRes)) +} + +func Test_getTokenType(t *testing.T) { + tests := []struct { + name string + token string + want blockatlas.TokenType + }{ + {"default trc20", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", blockatlas.TokenTypeTRC20}, + {"default trc10", "1002001", blockatlas.TokenTypeTRC10}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, getTokenType(tt.token)) + }) + } +} + +var ( + wantedTransactionsWithToken = `[{"id":"fb078403adfee637608c3906d9d21dd158611aba149b9993f43d0f292ce543a0","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","fee":"0","date":1592757117,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"500000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A"}},{"id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","fee":"0","date":1592757066,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"50000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd"}},{"id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","fee":"0","date":1592757066,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"50000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd"}},{"id":"0b52a4ef9fb8c13fbfae2b8c3506333ec1d718f307062a15f170562818a01d0a","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV","fee":"0","date":1592756784,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"3988000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV"}},{"id":"19d2ec6174bf64beb1061475f6429cba03b64944a763686cc3551447d0e8d9d5","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am","fee":"0","date":1592756763,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"640990000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am"}},{"id":"efb7d44305759cfb189c9fd22720609a2ddeb7fbd7c8afe1dd8851342471da8d","coin":195,"from":"TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","fee":"0","date":1592756631,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"1062000000","from":"TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D"}},{"id":"48bd90dc3f12086178e65b9389caa8b3c74683937b86d4d61cdec77f0095994a","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","fee":"0","date":1592756610,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"2000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A"}},{"id":"afd5ae7e2462c9cc899c7f730b90fd2a5e4c1315e836c92468b504ed85f0b798","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R","fee":"0","date":1592756589,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"1000000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R"}},{"id":"3d613031f4b2a0e19deeea030d1d18599b6d9799d2dd530005ead9712c6d219d","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"21200000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq"}},{"id":"cbe359c2574efbdc8fc6a892ffc54812837295067c9816d41734126c82d0c141","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"125000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5"}},{"id":"c87248b02a4caaa6f443c1b8c4d4588c8dd281a4687b73e6afecfba6741b50d8","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"5277600000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC"}},{"id":"8584f1b6a70ead8232fed19bd653ba13e4c2a8befd070f4a9a06eca3a2e3e548","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"485342000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W"}},{"id":"2b28b69e6747db68647acc3a62c45da5355b97acd8d2c260ee752aa9bd63a624","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"1000000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr"}},{"id":"1da6576dec0bd303f56cbfb5712f782e0a56a8713cb661f8afd2f2533e5c6209","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"2000000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x"}},{"id":"f9c86cce1873cb816d6cd8718e76df8839172add293bbc8d11a5f98c80f9e322","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"24216600000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK"}},{"id":"75eb35734857daa79c38ef923a7e7eb2e3dfb23d2722762fd2b180651021643f","coin":195,"from":"TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","fee":"0","date":1592756541,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"8241997837","from":"TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D"}},{"id":"adee73dadce006ff848ff30d8c5c41f033be2e5e1a8b875f6dbbaab524177d08","coin":195,"from":"TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","fee":"0","date":1592756220,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"18000000000","from":"TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D"}},{"id":"3655a1156c9adcb876c6c9c9e0f5f1f39704ac4c7296fea05fedf5ca8f6b1a19","coin":195,"from":"TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","fee":"0","date":1592755962,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"863399098","from":"TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D"}},{"id":"03574741eb0016050a19f181e4acc4b20b70f41e11e63140c9556c31eae09fba","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ","fee":"0","date":1592755740,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"20000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ"}},{"id":"f3aa00595996e31dbe9528a3cb21bff987f333bf1f675420ba4fa2ad43c8205f","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug","fee":"0","date":1592755722,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"21161340000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug"}}]` + wantedTransactionsOnly = `[{"id":"3fca53c08ccb48bb625439a58998713d8ecc3dc1348cc3cfab912e0815b62b1a","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","to":"TVmkAmaQrY6raatYozLtcQCGqWP6VaPnHU","fee":"0","date":1592755098,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"13195916000","symbol":"TRX","decimals":6}},{"id":"b38fb6328e1fa622b7762eed856778551845c33723491e36baf357f00cc48002","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","to":"TDfVk6U7i6m82ZCRprbrfz7QE3sTEnN1Xs","fee":"0","date":1592754717,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"8737000000","symbol":"TRX","decimals":6}},{"id":"82efc8456a3c38a0919af416a53363405ced78db7c13e1b94a79ebcea98f9909","coin":195,"from":"TVqx5Dx54HgBQFfpN7KN4MWiHEnRXbch7a","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","fee":"0","date":1592754447,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"2538461","symbol":"TRX","decimals":6}},{"id":"a336bd174c127d38bf2325bc9c927059af099e8cfb91159750a1b1be16dd0bd4","coin":195,"from":"TYCwQ4bC1mHR6heAe1qgHrktFtyJ8mKkC3","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","fee":"0","date":1592754444,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"30000000","symbol":"TRX","decimals":6}},{"id":"007bbcc3855f4bf51bd76e63d7776160c115c803e227f7c44c7d1fd1bd587611","coin":195,"from":"TSUCQKEKhXREEaod5WgSKETKjYUhL2TUV7","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","fee":"0","date":1592754444,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"111337320","symbol":"TRX","decimals":6}},{"id":"9351e87b129142844f000a52911daf36fc95677dfe2846abcd28ea0d8fe2e2ea","coin":195,"from":"TFUP7BdBj61oyTHt52McZC5Q1w6CKzyNCN","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","fee":"0","date":1592754444,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"200000000","symbol":"TRX","decimals":6}},{"id":"008ebda5749c38e26a69717faa66e6f4fd8a0d358c9b947192765cc9843cff5a","coin":195,"from":"TGkLtfPuPhkG4RzewwkgNHfPxTwb5YRq6b","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","fee":"0","date":1592754444,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"511000000","symbol":"TRX","decimals":6}}]` +) From b58fdc08ffbadcba94534f9d40f23956fb4df062 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2020 21:17:00 +0300 Subject: [PATCH 336/506] Bump github.com/prometheus/client_golang from 1.7.0 to 1.7.1 (#1156) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.7.0 to 1.7.1. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/master/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.7.0...v1.7.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f69e5e8ea..d02df4d7d 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.7.0 + github.com/prometheus/client_golang v1.7.1 github.com/shopspring/decimal v1.2.0 github.com/sirupsen/logrus v1.6.0 github.com/spf13/viper v1.7.0 diff --git a/go.sum b/go.sum index 3f5f34697..98ed2b8c8 100644 --- a/go.sum +++ b/go.sum @@ -355,6 +355,8 @@ github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mgln github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U= github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= From 2a52c8b47a45ba0a5db0a749f3fdf504a3ee0822 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Tue, 30 Jun 2020 17:50:50 +0300 Subject: [PATCH 337/506] Add updatedAt to db model (#1160) * Add updatedAt to db model * Update db test --- db/models/tracker.go | 7 +++++-- db/tracker.go | 2 +- db/tracker_test.go | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/db/models/tracker.go b/db/models/tracker.go index 723531df6..14bbd3523 100644 --- a/db/models/tracker.go +++ b/db/models/tracker.go @@ -1,6 +1,9 @@ package models +import "time" + type Tracker struct { - Coin string `gorm:"primary_key:true; type:varchar(64)"` - Height int64 + UpdatedAt time.Time + Coin string `gorm:"primary_key:true; type:varchar(64)"` + Height int64 } diff --git a/db/tracker.go b/db/tracker.go index 86c8ba69f..04f54d264 100644 --- a/db/tracker.go +++ b/db/tracker.go @@ -52,7 +52,7 @@ func (i *Instance) SetLastParsedBlockNumber(coin string, num int64, ctx context. } g := apmgorm.WithContext(ctx, i.Gorm) return g. - Set("gorm:insert_option", "ON CONFLICT (coin) DO UPDATE SET height = excluded.height"). + Set("gorm:insert_option", "ON CONFLICT (coin) DO UPDATE SET height = excluded.height, updated_at = excluded.updated_at"). Where(models.Tracker{Coin: coin}). Create(&tracker).Error } diff --git a/db/tracker_test.go b/db/tracker_test.go index 502c4a867..fc7984c9a 100644 --- a/db/tracker_test.go +++ b/db/tracker_test.go @@ -15,7 +15,7 @@ func TestHeightBlockMap_SetHeight(t *testing.T) { mock.ExpectBegin() mock.ExpectQuery( regexp.QuoteMeta( - `INSERT INTO "trackers" ("coin","height") VALUES ($1,$2) ON CONFLICT (coin) DO UPDATE SET height = excluded.height RETURNING "trackers"."coin"`)).WithArgs("bitcoin", 1).WillReturnRows(sqlmock.NewRows([]string{"id"}). + `INSERT INTO "trackers" ("updated_at","coin","height") VALUES ($1,$2,$3) ON CONFLICT (coin) DO UPDATE SET height = excluded.height, updated_at = excluded.updated_at RETURNING "trackers"."coin"`)).WithArgs(sqlmock.AnyArg(), "bitcoin", 1).WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow("id")) mock.ExpectCommit() i := Instance{Gorm: db} @@ -29,7 +29,7 @@ func TestHeightBlockMap_GetHeight(t *testing.T) { mock.ExpectBegin() mock.ExpectQuery( regexp.QuoteMeta( - `INSERT INTO "trackers" ("coin","height") VALUES ($1,$2) ON CONFLICT (coin) DO UPDATE SET height = excluded.height RETURNING "trackers"."coin"`)).WithArgs("bitcoin", 1).WillReturnRows(sqlmock.NewRows([]string{"id"}). + `INSERT INTO "trackers" ("updated_at","coin","height") VALUES ($1,$2,$3) ON CONFLICT (coin) DO UPDATE SET height = excluded.height, updated_at = excluded.updated_at RETURNING "trackers"."coin"`)).WithArgs(sqlmock.AnyArg(), "bitcoin", 1).WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow("id")) mock.ExpectCommit() i := Instance{Gorm: db} From ddc089e67a3c9842d7320ec7d19cd4708428b1ad Mon Sep 17 00:00:00 2001 From: Alexey Prazdnikov Date: Tue, 7 Jul 2020 01:06:20 +0300 Subject: [PATCH 338/506] [Makefile] Add start-docker-services (#1161) --- Makefile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Makefile b/Makefile index b8f2a56d5..cb3c7b913 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,11 @@ SUBSCRIBER := subscriber COIN_FILE := coin/coins.yml COIN_GO_FILE := coin/coins.go GEN_COIN_FILE := coin/gen.go +DOCKER_LOCAL_DB_IMAGE_NAME := test_db +DOCKER_LOCAL_MQ_IMAGE_NAME := mq +DOCKER_LOCAL_DB_USER :=user +DOCKER_LOCAL_DB_PASS :=pass +DOCKER_LOCAL_DB := my_db # Go related variables. GOBASE := $(shell pwd) @@ -216,6 +221,16 @@ go-compile: go-get go-build go-build: go-build-api go-build-notifier go-build-parser go-build-subscriber +docker-shutdown: + @echo " > Shutdown docker containers..." + @-bash -c "docker rm -f $(DOCKER_LOCAL_DB_IMAGE_NAME) 2> /dev/null" + @-bash -c "docker rm -f $(DOCKER_LOCAL_MQ_IMAGE_NAME) 2> /dev/null" + +start-docker-services: docker-shutdown + @echo " > Starting docker containers" + docker run -d -p 5432:5432 --name $(DOCKER_LOCAL_DB_IMAGE_NAME) -e POSTGRES_USER=$(DOCKER_LOCAL_DB_USER) -e POSTGRES_PASSWORD=$(DOCKER_LOCAL_DB_PASS) -e POSTGRES_DB=$(DOCKER_LOCAL_DB) postgres + docker run -d -p 5672:5672 --name $(DOCKER_LOCAL_MQ_IMAGE_NAME) rabbitmq + go-build-api: @echo " > Building api binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API)/api ./cmd/$(API) From 6d92b29d9fb2c74328467dc0edc141e8bbeaa9ea Mon Sep 17 00:00:00 2001 From: maxUo <20925019+maxUo@users.noreply.github.com> Date: Tue, 7 Jul 2020 18:25:09 +0300 Subject: [PATCH 339/506] [DevOps] Improve CI/CD Speed (#1162) * no message * Naming Cleanup * Cleanup master-ci * Fix PR-build CI * Change Master CI * Fix CI * Fix CI paths * Test Swagger Changes * Revert Swagger Changes --- .github/workflows/master.yml | 122 +++++++++++++++++++++ .github/workflows/pr-build.yml | 58 ++++++++++ .github/workflows/{ci.yml => pr-tests.yml} | 19 +--- Dockerfile.runner | 5 + 4 files changed, 187 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/master.yml create mode 100644 .github/workflows/pr-build.yml rename .github/workflows/{ci.yml => pr-tests.yml} (68%) create mode 100644 Dockerfile.runner diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml new file mode 100644 index 000000000..fdee7085e --- /dev/null +++ b/.github/workflows/master.yml @@ -0,0 +1,122 @@ +name: Master CI + +on: + push: + branches: [ master ] + +jobs: + test: + name: Unit Test + runs-on: ubuntu-latest + steps: + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + go get -v -t -d ./... + + - name: Lint + run: make lint + + - name: Swagger + run: make swag + + - name: Build + run: make go-build + + - name: Unit Test + run: make test + + - name: Upload coverage + run: bash <(curl -s https://codecov.io/bash) -f coverage.txt + + integration: + name: Integration Test + runs-on: ubuntu-latest + steps: + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + go get -v -t -d ./... + + - name: Integration Test + run: make integration + + - name: Mock Test + run: make newman-mocked + + deploy: + name: CD + runs-on: ubuntu-latest + needs: [test, integration] + steps: + - name: Login to DockerHub Registry + run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin + + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Get short commit hash + id: hash + run: echo "::set-output name=sha7::$(echo $(git rev-parse --short HEAD) | cut -c1-7)" + + - name: Show short hash + run: | + echo ${{ steps.hash.outputs.sha7 }} + + - name: Get dependencies + run: | + go get -v -t -d ./... + + - name: Swagger + run: make swag + + - name: Build + run: make go-build + + - name: Docker Build & Push Release Images + env: + API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} + PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} + OBSERVER_SUBSCRIBER_IMAGE: ${{ secrets.REGISTRY }}:subscriber-${{ steps.hash.outputs.sha7 }} + OBSERVER_NOTIFIER_IMAGE: ${{ secrets.REGISTRY }}:notifier-${{ steps.hash.outputs.sha7 }} + run: | + docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . + docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . + docker build --build-arg SERVICE=subscriber/subscriber -f Dockerfile.runner -t $OBSERVER_SUBSCRIBER_IMAGE . + docker build --build-arg SERVICE=notifier/notifier -f Dockerfile.runner -t $OBSERVER_NOTIFIER_IMAGE . + docker push $API_IMAGE + docker push $PARSER_IMAGE + docker push $OBSERVER_SUBSCRIBER_IMAGE + docker push $OBSERVER_NOTIFIER_IMAGE + + - name: CD Trigger + if: github.ref == 'refs/heads/master' + uses: Azure/pipelines@releases/v1 + with: + azure-devops-project-url: 'https://dev.azure.com/TrustWallet/Trust%20BlockAtlas' + azure-pipeline-name: 'AutomaticCD' + azure-devops-token: '${{ secrets.AZURE_DEVOPS_TOKEN }}' diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml new file mode 100644 index 000000000..3c3c1820d --- /dev/null +++ b/.github/workflows/pr-build.yml @@ -0,0 +1,58 @@ +name: PRBuild + +on: + pull_request: + branches: [ master ] + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Login to DockerHub Registry + run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin + + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Get short commit hash + id: hash + run: echo "::set-output name=sha7::$(echo $(git rev-parse --short HEAD) | cut -c1-7)" + + - name: Show short hash + run: | + echo ${{ steps.hash.outputs.sha7 }} + + - name: Get dependencies + run: | + go get -v -t -d ./... + + - name: Swagger + run: make swag + + - name: Build + run: make go-build + + - name: Docker Build & Push Release Images + env: + API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} + PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} + OBSERVER_SUBSCRIBER_IMAGE: ${{ secrets.REGISTRY }}:subscriber-${{ steps.hash.outputs.sha7 }} + OBSERVER_NOTIFIER_IMAGE: ${{ secrets.REGISTRY }}:notifier-${{ steps.hash.outputs.sha7 }} + run: | + docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . + docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . + docker build --build-arg SERVICE=subscriber/subscriber -f Dockerfile.runner -t $OBSERVER_SUBSCRIBER_IMAGE . + docker build --build-arg SERVICE=notifier/notifier -f Dockerfile.runner -t $OBSERVER_NOTIFIER_IMAGE . + docker push $API_IMAGE + docker push $PARSER_IMAGE + docker push $OBSERVER_SUBSCRIBER_IMAGE + docker push $OBSERVER_NOTIFIER_IMAGE diff --git a/.github/workflows/ci.yml b/.github/workflows/pr-tests.yml similarity index 68% rename from .github/workflows/ci.yml rename to .github/workflows/pr-tests.yml index 92f9b3693..66305a463 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/pr-tests.yml @@ -1,8 +1,6 @@ -name: CI +name: PRTests on: - push: - branches: [ master ] pull_request: branches: [ master ] @@ -60,17 +58,4 @@ jobs: run: make integration - name: Mock Test - run: make newman-mocked - - deploy: - name: CD - runs-on: ubuntu-latest - needs: [test, integration] - steps: - - name: CD Trigger - if: github.ref == 'refs/heads/master' - uses: Azure/pipelines@releases/v1 - with: - azure-devops-project-url: 'https://dev.azure.com/TrustWallet/Trust%20BlockAtlas' - azure-pipeline-name: 'AutomaticCD' - azure-devops-token: '${{ secrets.AZURE_DEVOPS_TOKEN }}' + run: make newman-mocked \ No newline at end of file diff --git a/Dockerfile.runner b/Dockerfile.runner new file mode 100644 index 000000000..1bcbbbe7e --- /dev/null +++ b/Dockerfile.runner @@ -0,0 +1,5 @@ +FROM golang:1.13.6-stretch +ARG SERVICE +COPY ./bin/$SERVICE /app/main +COPY ./config.yml /config/ +ENTRYPOINT ["/app/main", "-c", "/config/config.yml"] From 79c69267fe02eb3f74191ea08d22caefd412f7f0 Mon Sep 17 00:00:00 2001 From: maxUo <20925019+maxUo@users.noreply.github.com> Date: Tue, 7 Jul 2020 18:47:39 +0300 Subject: [PATCH 340/506] Speed up Master CI/CD (#1163) * no message * Naming Cleanup * Cleanup master-ci * Fix PR-build CI * Change Master CI * Fix CI * Fix CI paths * Test Swagger Changes * Revert Swagger Changes * Change Master CD --- .github/workflows/master.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index fdee7085e..e966bf110 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -60,10 +60,9 @@ jobs: - name: Mock Test run: make newman-mocked - deploy: - name: CD + build: + name: Build runs-on: ubuntu-latest - needs: [test, integration] steps: - name: Login to DockerHub Registry run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin @@ -113,6 +112,11 @@ jobs: docker push $OBSERVER_SUBSCRIBER_IMAGE docker push $OBSERVER_NOTIFIER_IMAGE + deploy: + name: CD + runs-on: ubuntu-latest + needs: [test, integration, build] + steps: - name: CD Trigger if: github.ref == 'refs/heads/master' uses: Azure/pipelines@releases/v1 From fb9479c12fc6cd4d2f82c29a4933d470a4a3281a Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 9 Jul 2020 22:37:17 -0700 Subject: [PATCH 341/506] Add BEP8 Token Type enum (#1166) --- pkg/blockatlas/tx.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index a555d6f43..e5768c308 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -18,6 +18,7 @@ const ( TokenTypeERC20 TokenType = "ERC20" TokenTypeBEP2 TokenType = "BEP2" + TokenTypeBEP8 TokenType = "BEP8" TokenTypeTRC10 TokenType = "TRC10" TokenTypeETC20 TokenType = "ETC20" TokenTypePOA20 TokenType = "POA20" From 5d7a05e85c13a2e85ea373cb2d24a1114a336828 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Tue, 14 Jul 2020 20:36:04 +0300 Subject: [PATCH 342/506] Remove deleted_at from db field (#1167) --- db/models/subscriptions.go | 1 - .../integration/db_test/subscriptions_test.go | 29 ++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index bb7ac0c80..019159e40 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -6,7 +6,6 @@ import ( type Subscription struct { CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"` - DeletedAt *time.Time `sql:"index"` Coin uint `gorm:"primary_key; column:coin; auto_increment:false" sql:"index"` Address string `gorm:"primary_key; column:address; type:varchar(128)" sql:"index"` } diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go index 6503ed4ec..fdf2fad97 100644 --- a/tests/integration/db_test/subscriptions_test.go +++ b/tests/integration/db_test/subscriptions_test.go @@ -337,6 +337,34 @@ func TestDb_DuplicateEntries(t *testing.T) { assert.True(t, containSub(subscriptions[0], subs)) } +func TestDb_CreateDeleteCreate(t *testing.T) { + setup.CleanupPgContainer(database.Gorm) + var subscriptions []models.Subscription + subscriptions = append(subscriptions, models.Subscription{ + Coin: 60, + Address: "testAddr", + }) + + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) + subs, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + assert.Nil(t, err) + assert.Equal(t, 1, len(subs)) + + time.Sleep(time.Second) + + assert.Nil(t, database.DeleteSubscriptions(subs, context.Background())) + + subs2, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + assert.Nil(t, err) + assert.Equal(t, 0, len(subs2)) + + assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) + + subs3, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + assert.Nil(t, err) + assert.Equal(t, 1, len(subs3)) +} + func TestDb_UpdatedAt(t *testing.T) { setup.CleanupPgContainer(database.Gorm) var subscriptions []models.Subscription @@ -372,7 +400,6 @@ func TestDb_UpdatedAt(t *testing.T) { assert.Greater(t, time.Now().Unix(), existingSub2.CreatedAt.Unix()) assert.Greater(t, existingSub2.CreatedAt.Unix(), time.Now().Unix()-120) assert.GreaterOrEqual(t, existingSub2.CreatedAt.Unix(), existingSub.CreatedAt.Unix()) - } func containSub(sub models.Subscription, list []models.Subscription) bool { From 01c1aafd70ecd8d413af16e3705e3c770ae93208 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2020 13:14:49 +0300 Subject: [PATCH 343/506] Bump github.com/jinzhu/gorm from 1.9.14 to 1.9.15 (#1170) Bumps [github.com/jinzhu/gorm](https://github.com/jinzhu/gorm) from 1.9.14 to 1.9.15. - [Release notes](https://github.com/jinzhu/gorm/releases) - [Commits](https://github.com/jinzhu/gorm/compare/v1.9.14...v1.9.15) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index d02df4d7d..e449c2708 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/elastic/go-windows v1.0.1 // indirect github.com/gin-gonic/gin v1.6.3 github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect - github.com/jinzhu/gorm v1.9.14 + github.com/jinzhu/gorm v1.9.15 github.com/mitchellh/mapstructure v1.3.2 github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/image-spec v1.0.1 // indirect diff --git a/go.sum b/go.sum index 98ed2b8c8..0b584a045 100644 --- a/go.sum +++ b/go.sum @@ -244,6 +244,8 @@ github.com/jinzhu/gorm v1.9.13 h1:fcdacwmUcoyon8XHkQrdPJZ7pnHAYclHZ6iLYER5nX4= github.com/jinzhu/gorm v1.9.13/go.mod h1:C0zfmO9z9J61PGrs46nfRkfsq0/8ErGTKBxyudR2KvI= github.com/jinzhu/gorm v1.9.14 h1:Kg3ShyTPcM6nzVo148fRrcMO6MNKuqtOUwnzqMgVniM= github.com/jinzhu/gorm v1.9.14/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= +github.com/jinzhu/gorm v1.9.15 h1:OdR1qFvtXktlxk73XFYMiYn9ywzTwytqe4QkuMRqc38= +github.com/jinzhu/gorm v1.9.15/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= From efc86ae3e6211e2d83ff9b64c3c32d594079ff5e Mon Sep 17 00:00:00 2001 From: maxUo <20925019+maxUo@users.noreply.github.com> Date: Tue, 21 Jul 2020 21:33:49 +0300 Subject: [PATCH 344/506] Fix pipeline (#1173) * Update pr-build.yml * Update master.yml * Update master.yml * Update pr-build.yml * Update pr-build.yml * Update pr-build.yml * Update master.yml * Update pr-build.yml --- .github/workflows/master.yml | 30 ++++++++++++++++++++++++++---- .github/workflows/pr-build.yml | 16 +++++++++++++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index e966bf110..7aed10e1f 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -64,9 +64,6 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - name: Login to DockerHub Registry - run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin - - name: Set up Go 1.x uses: actions/setup-go@v2 with: @@ -95,8 +92,25 @@ jobs: - name: Build run: make go-build + + - name: Check user permission + id: check_for_build + uses: scherermichael-oss/action-has-permission@master + with: + required-permission: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to DockerHub Registry + if: steps.check_for_build.outputs.has-permission + uses: azure/docker-login@v1 + with: + login-server: index.docker.io/v2/ + username: ${{ secrets.REGISTRY_USERNAME }} + password: ${{ secrets.REGISTRY_PASSWORD }} - name: Docker Build & Push Release Images + if: steps.check_for_build.outputs.has-permission env: API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} @@ -117,8 +131,16 @@ jobs: runs-on: ubuntu-latest needs: [test, integration, build] steps: + - name: Check user permission + id: check_for_deploy + uses: scherermichael-oss/action-has-permission@master + with: + required-permission: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: CD Trigger - if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/master' && steps.check_for_deploy.outputs.has-permission uses: Azure/pipelines@releases/v1 with: azure-devops-project-url: 'https://dev.azure.com/TrustWallet/Trust%20BlockAtlas' diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 3c3c1820d..3559348f6 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -9,9 +9,6 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - name: Login to DockerHub Registry - run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin - - name: Set up Go 1.x uses: actions/setup-go@v2 with: @@ -41,7 +38,20 @@ jobs: - name: Build run: make go-build + - name: Check user permission + id: check + uses: scherermichael-oss/action-has-permission@master + with: + required-permission: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to DockerHub Registry + if: steps.check.outputs.has-permission + run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin + - name: Docker Build & Push Release Images + if: steps.check.outputs.has-permission env: API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} From 20fb8416129680cb0827cc25603633d070de57c1 Mon Sep 17 00:00:00 2001 From: maxUo <20925019+maxUo@users.noreply.github.com> Date: Tue, 21 Jul 2020 21:41:30 +0300 Subject: [PATCH 345/506] Fix pipeline --- .github/workflows/master.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 7aed10e1f..3414c5b33 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -103,11 +103,7 @@ jobs: - name: Login to DockerHub Registry if: steps.check_for_build.outputs.has-permission - uses: azure/docker-login@v1 - with: - login-server: index.docker.io/v2/ - username: ${{ secrets.REGISTRY_USERNAME }} - password: ${{ secrets.REGISTRY_PASSWORD }} + run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin - name: Docker Build & Push Release Images if: steps.check_for_build.outputs.has-permission From 3e7b61bb3628c95a8b3031b520c774de10125b0a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2020 19:24:31 +0300 Subject: [PATCH 346/506] Bump github.com/mitchellh/mapstructure from 1.3.2 to 1.3.3 (#1174) Bumps [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) from 1.3.2 to 1.3.3. - [Release notes](https://github.com/mitchellh/mapstructure/releases) - [Changelog](https://github.com/mitchellh/mapstructure/blob/master/CHANGELOG.md) - [Commits](https://github.com/mitchellh/mapstructure/compare/v1.3.2...v1.3.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index e449c2708..9059dc362 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/gin-gonic/gin v1.6.3 github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/jinzhu/gorm v1.9.15 - github.com/mitchellh/mapstructure v1.3.2 + github.com/mitchellh/mapstructure v1.3.3 github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v0.1.1 // indirect diff --git a/go.sum b/go.sum index 0b584a045..44741146f 100644 --- a/go.sum +++ b/go.sum @@ -310,6 +310,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= From b478b403a6db2eebe901b928c37995c3afc56584 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 28 Jul 2020 14:47:41 +0800 Subject: [PATCH 347/506] Update ens coincodec to fix TRX resolving (#1177) --- go.mod | 2 +- go.sum | 28 ++++------------------------ 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 9059dc362..3361b441d 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 - github.com/trustwallet/ens-coincodec v1.0.5 + github.com/trustwallet/ens-coincodec v1.0.6 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmgorm v1.8.0 diff --git a/go.sum b/go.sum index 44741146f..f5001c724 100644 --- a/go.sum +++ b/go.sum @@ -238,12 +238,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= -github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= -github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= -github.com/jinzhu/gorm v1.9.13 h1:fcdacwmUcoyon8XHkQrdPJZ7pnHAYclHZ6iLYER5nX4= -github.com/jinzhu/gorm v1.9.13/go.mod h1:C0zfmO9z9J61PGrs46nfRkfsq0/8ErGTKBxyudR2KvI= -github.com/jinzhu/gorm v1.9.14 h1:Kg3ShyTPcM6nzVo148fRrcMO6MNKuqtOUwnzqMgVniM= -github.com/jinzhu/gorm v1.9.14/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/gorm v1.9.15 h1:OdR1qFvtXktlxk73XFYMiYn9ywzTwytqe4QkuMRqc38= github.com/jinzhu/gorm v1.9.15/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -258,6 +252,7 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -295,9 +290,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= -github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= -github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 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= @@ -308,8 +302,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= -github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -355,10 +347,6 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= -github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= -github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U= -github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -370,8 +358,6 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -380,8 +366,6 @@ github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -441,8 +425,8 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/ens-coincodec v1.0.5 h1:rdebDQYHqNjv+yUdtMf3DXyMgJpEJSI2DSbC1GUFuyk= -github.com/trustwallet/ens-coincodec v1.0.5/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= +github.com/trustwallet/ens-coincodec v1.0.6 h1:ZPvFDJwvv4s+XCnUM7pzub8wYHy37tyJBNtKvgx9FDs= +github.com/trustwallet/ens-coincodec v1.0.6/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= @@ -581,10 +565,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From b28ecd64012cfd5d4d918ce9b09f171419a885fe Mon Sep 17 00:00:00 2001 From: maxUo <20925019+maxUo@users.noreply.github.com> Date: Tue, 28 Jul 2020 15:52:29 +0300 Subject: [PATCH 348/506] Update pr-build.yml --- .github/workflows/pr-build.yml | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 3559348f6..8647e99c9 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -9,43 +9,50 @@ jobs: name: Build runs-on: ubuntu-latest steps: + - name: Check user permission + id: check + uses: scherermichael-oss/action-has-permission@master + with: + required-permission: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Set up Go 1.x + if: steps.check.outputs.has-permission uses: actions/setup-go@v2 with: go-version: ^1.13 id: go - name: Check out code into the Go module directory + if: steps.check.outputs.has-permission uses: actions/checkout@v2 with: ref: ${{ github.head_ref }} - name: Get short commit hash + if: steps.check.outputs.has-permission id: hash run: echo "::set-output name=sha7::$(echo $(git rev-parse --short HEAD) | cut -c1-7)" - name: Show short hash + if: steps.check.outputs.has-permission run: | echo ${{ steps.hash.outputs.sha7 }} - name: Get dependencies + if: steps.check.outputs.has-permission run: | go get -v -t -d ./... - name: Swagger + if: steps.check.outputs.has-permission run: make swag - name: Build + if: steps.check.outputs.has-permission run: make go-build - - name: Check user permission - id: check - uses: scherermichael-oss/action-has-permission@master - with: - required-permission: write - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Login to DockerHub Registry if: steps.check.outputs.has-permission run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin From 163b5a9ffc54bebdcabc19f114b771504ba6080e Mon Sep 17 00:00:00 2001 From: Iuga Mihai <50499646+miiu96@users.noreply.github.com> Date: Thu, 30 Jul 2020 15:48:03 +0300 Subject: [PATCH 349/506] Update Elrond integration (#1168) * update block atlas elrond integration to work with latest version of responses from rest api * small fix * use json.RawMessage instead of interface{} * empty commit * revert modifications --- platform/elrond/client.go | 23 +++++++++++++++++++---- platform/elrond/model.go | 9 ++++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/platform/elrond/client.go b/platform/elrond/client.go index 10405557b..63a21a431 100644 --- a/platform/elrond/client.go +++ b/platform/elrond/client.go @@ -1,7 +1,9 @@ package elrond import ( + "encoding/json" "fmt" + "net/url" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -13,12 +15,12 @@ type Client struct { func (c *Client) CurrentBlockNumber() (num int64, err error) { var networkStatus NetworkStatus path := fmt.Sprintf("network/status/%s", metachainID) - err = c.Get(&networkStatus, path, nil) + err = c.getResponse(&networkStatus, path, nil) if err != nil { return 0, err } - latestNonce := networkStatus.NetworkStatus.Status.Nonce + latestNonce := networkStatus.Status.Nonce return int64(latestNonce), nil } @@ -27,7 +29,7 @@ func (c *Client) GetBlockByNumber(height int64) (*blockatlas.Block, error) { var blockRes BlockResponse path := fmt.Sprintf("block/%s/%d", metachainID, uint64(height)) - err := c.Get(&blockRes, path, nil) + err := c.getResponse(&blockRes, path, nil) if err != nil { return nil, err } @@ -47,7 +49,7 @@ func (c *Client) GetTxsOfAddress(address string) (blockatlas.TxPage, error) { // TODO: enable pagination of Elrond transactions in the future. // TODO: currently Elrond only fetches the most recent 20 transactions. path := fmt.Sprintf("address/%s/transactions", address) - err := c.Get(&txPage, path, nil) + err := c.getResponse(&txPage, path, nil) if err != nil { return nil, err } @@ -56,3 +58,16 @@ func (c *Client) GetTxsOfAddress(address string) (blockatlas.TxPage, error) { return txs, nil } + +func (c *Client) getResponse(result interface{}, path string, query url.Values) error { + var genericResponse GenericResponse + if err := c.Get(&genericResponse, path, query); err != nil { + return err + } + + if genericResponse.Code != "successful" { + return fmt.Errorf("%s", genericResponse.Error) + } + + return json.Unmarshal(genericResponse.Data, &result) +} diff --git a/platform/elrond/model.go b/platform/elrond/model.go index 98fbddab3..ab607cca5 100644 --- a/platform/elrond/model.go +++ b/platform/elrond/model.go @@ -1,16 +1,19 @@ package elrond import ( + "encoding/json" "time" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) -type NetworkStatus struct { - NetworkStatus Status `json:"message"` +type GenericResponse struct { + Data json.RawMessage `json:"data"` + Code string `json:"code"` + Error string `json:"error"` } -type Status struct { +type NetworkStatus struct { Status StatusDetails `json:"status"` } From 9f150d202d05323338abe2ce88a93e66c4b2ece5 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Mon, 3 Aug 2020 17:00:48 +0300 Subject: [PATCH 350/506] =?UTF-8?q?=C2=A0[Parser]=20Fix=20bug=20with=20wg?= =?UTF-8?q?=20wait=20(#1179)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Setup debug logs to get info about the problem with parser * Lint fix * Remove sync.wg --- services/observer/parser/parser.go | 36 +++++++++++++----------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/services/observer/parser/parser.go b/services/observer/parser/parser.go index 0e793c601..331d25fe0 100644 --- a/services/observer/parser/parser.go +++ b/services/observer/parser/parser.go @@ -10,7 +10,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" "go.elastic.co/apm" - "strconv" "sync/atomic" "github.com/trustwallet/blockatlas/pkg/logger" @@ -57,8 +56,12 @@ func RunParser(params Params) { return default: parse(params) + logger.Info("Sleep ...", logger.Params{"interval": params.ParsingBlocksInterval.String()}) time.Sleep(params.ParsingBlocksInterval) + logger.Info("Leaving select") } + logger.Info("Going to the next cycle... ") + logger.Info("------------------------------------------------------------") } } @@ -71,36 +74,30 @@ func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duratio func parse(params Params) { tx := apm.DefaultTracer.StartTransaction("parse", "app") - ctx := apm.ContextWithTransaction(context.Background(), tx) - defer tx.End() + ctx := apm.ContextWithTransaction(context.Background(), tx) + lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params, ctx) if err != nil || lastParsedBlock > currentBlock { logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) time.Sleep(params.ParsingBlocksInterval) - tx.Result = "failed" return } - tx.Context.SetTag("lastParsedBlock", strconv.Itoa(int(lastParsedBlock))) - tx.Context.SetTag("lastParsedBlock", strconv.Itoa(int(lastParsedBlock))) blocks := FetchBlocks(params, lastParsedBlock, currentBlock, ctx) - tx.Context.SetTag("blocks len", strconv.Itoa(len(blocks))) - err = SaveLastParsedBlock(params, blocks, ctx) if err != nil { logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) time.Sleep(params.ParsingBlocksInterval) - tx.Result = "failed" return } txs := ConvertToBatch(blocks, ctx) - tx.Result = "success" - tx.Context.SetTag("txs", strconv.Itoa(len(txs))) PublishTransactionsBatch(params, txs, ctx) + + logger.Info("End of parse step") } func GetBlocksIntervalToFetch(params Params, ctx context.Context) (int64, int64, error) { @@ -124,7 +121,6 @@ func GetBlocksIntervalToFetch(params Params, ctx context.Context) (int64, int64, if currentBlock-lastParsedBlock > params.MaxBacklogBlocks { lastParsedBlock = currentBlock - params.MaxBacklogBlocks } - return lastParsedBlock, currentBlock, nil } @@ -209,6 +205,9 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block, ctx context.C sort.Slice(blocks, func(i, j int) bool { return blocks[i].Number < blocks[j].Number }) + if len(blocks)-1 < 0 { + return errors.E(fmt.Sprintf("Cannot get last block number for %s", params.Api.Coin().Handle)) + } lastBlockNumber := blocks[len(blocks)-1].Number if lastBlockNumber <= 0 { @@ -256,27 +255,24 @@ func ConvertToBatch(blocks []blockatlas.Block, ctx context.Context) blockatlas.T func PublishTransactionsBatch(params Params, txs blockatlas.Txs, ctx context.Context) { span, ctx := apm.StartSpan(ctx, "PublishTransactionsBatch", "app") defer span.End() + if len(txs) == 0 { - logger.Info("------------------------------------------------------------") return } batches := getTxsBatches(txs, params.TxBatchLimit, ctx) - var wg sync.WaitGroup for _, batch := range batches { - wg.Add(1) - go publish(params, batch, &wg, ctx) + publish(params, batch, ctx) } - wg.Wait() logger.Info("Published transactions batch", logger.Params{"txs": len(txs), "batchCount": len(batches)}) - logger.Info("------------------------------------------------------------") } func getTxsBatches(txs blockatlas.Txs, sizeUint uint, ctx context.Context) []blockatlas.Txs { span, _ := apm.StartSpan(ctx, "getTxsBatches", "app") defer span.End() + size := int(sizeUint) resultLength := (len(txs) + size - 1) / size result := make([]blockatlas.Txs, resultLength) @@ -291,10 +287,10 @@ func getTxsBatches(txs blockatlas.Txs, sizeUint uint, ctx context.Context) []blo return result } -func publish(params Params, txs blockatlas.Txs, wg *sync.WaitGroup, ctx context.Context) { +func publish(params Params, txs blockatlas.Txs, ctx context.Context) { span, _ := apm.StartSpan(ctx, "publish", "app") defer span.End() - defer wg.Done() + body, err := json.Marshal(txs) if err != nil { logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) From c0b13ea31855fbab3061bedadb10d85d39beef3d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2020 21:43:54 +0300 Subject: [PATCH 351/506] Bump github.com/spf13/viper from 1.7.0 to 1.7.1 (#1181) Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.7.0 to 1.7.1. - [Release notes](https://github.com/spf13/viper/releases) - [Commits](https://github.com/spf13/viper/compare/v1.7.0...v1.7.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 3361b441d..553070cfb 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/prometheus/client_golang v1.7.1 github.com/shopspring/decimal v1.2.0 github.com/sirupsen/logrus v1.6.0 - github.com/spf13/viper v1.7.0 + github.com/spf13/viper v1.7.1 github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 diff --git a/go.sum b/go.sum index f5001c724..8211724e3 100644 --- a/go.sum +++ b/go.sum @@ -405,6 +405,8 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5NYJe/zRYDwOu9ku6YHy+Iw7l5DM= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= From f56c46e2eccef524f337f333d6798151e5df7cac Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Mon, 3 Aug 2020 21:51:42 +0300 Subject: [PATCH 352/506] Add FormatAddress function (#1182) --- pkg/address/address.go | 17 +++++++++++++++++ pkg/address/address_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/pkg/address/address.go b/pkg/address/address.go index 50610e8e7..dce324001 100644 --- a/pkg/address/address.go +++ b/pkg/address/address.go @@ -11,6 +11,8 @@ import ( "strings" ) +const prefixBitcoinCash = "bitcoincash:" + // Decode decodes a hex string with 0x prefix. func Remove0x(input string) string { if strings.HasPrefix(input, "0x") { @@ -98,3 +100,18 @@ func ToEIP55ByCoinID(str string, coinID uint) string { return str } } + +func removePrefix(address string) string { + return strings.TrimPrefix(address, prefixBitcoinCash) +} + +func FormatAddress(address string, coinID uint) string { + switch coinID { + case coin.ETH, coin.POA, coin.ETC, coin.TOMO, coin.CLO, coin.TT, coin.GO, coin.WAN: + return ToEIP55ByCoinID(address, coinID) + case coin.BCH: + return removePrefix(address) + default: + return address + } +} diff --git a/pkg/address/address_test.go b/pkg/address/address_test.go index 9e9b74a2f..f9685233d 100644 --- a/pkg/address/address_test.go +++ b/pkg/address/address_test.go @@ -119,3 +119,40 @@ func TestToEIP55ByCoinID(t *testing.T) { } }) } + +func TestFormatAddress(t *testing.T) { + var ( + addr1 = "0xea674fdde714fd979de3edf0f56aa9716b898ec8" + addr1EIP55 = "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8" + wanAddrLowercase = "0xae96137e0e05681ed2f5d1af272c3ee512939d0f" + wanAddrEIP55Checksum = "0xAe96137E0e05681eD2F5D1AF272C3ee512939D0F" + wanAddrEIP55ChecksumWanchain = "0xaE96137e0E05681Ed2f5d1af272c3EE512939d0f" + tests = []struct { + name, address, expectedAddress string + coinID uint + }{ + {"Ethereum", addr1, addr1EIP55, coin.ETH}, + {"Ethereum Classic", addr1, addr1EIP55, coin.ETC}, + {"POA", addr1, addr1EIP55, coin.POA}, + {"Callisto", addr1, addr1EIP55, coin.CLO}, + {"Tomochain", addr1, addr1EIP55, coin.TOMO}, + {"Thunder", addr1, addr1EIP55, coin.TT}, + {"Thunder", addr1, addr1EIP55, coin.TT}, + {"GoChain", addr1, addr1EIP55, coin.GO}, + {"Wanchain 1", wanAddrLowercase, wanAddrEIP55ChecksumWanchain, coin.WAN}, + {"Wanchain 2", wanAddrEIP55Checksum, wanAddrEIP55ChecksumWanchain, coin.WAN}, + {"Non Ethereum like chain 1", "", "", coin.TRX}, + {"Non Ethereum like chain 2", addr1, addr1, coin.BNB}, + {"Bitcoin cash case with prefix", "bitcoincash:qzzhnrz43k86r3shen9se96uqeu5mxe0msa2auy85w", "qzzhnrz43k86r3shen9se96uqeu5mxe0msa2auy85w", coin.BCH}, + {"Bitcoin cash case without prefix", "qr5q38d4g02u976jtl7s2ygsewlpaaaylsp2jm6wpf", "qr5q38d4g02u976jtl7s2ygsewlpaaaylsp2jm6wpf", coin.BCH}, + {"Bitcoin cash case without prefix", "qr5q38d4g02u976jtl7s2ygsewlpaaaylsp2jm6wpf", "qr5q38d4g02u976jtl7s2ygsewlpaaaylsp2jm6wpf", coin.BTC}, + } + ) + + t.Run("Test TestToEIP55ByCoinID", func(t *testing.T) { + for _, tt := range tests { + actual := FormatAddress(tt.address, tt.coinID) + assert.Equal(t, tt.expectedAddress, actual) + } + }) +} From 32d69d10ee4df9ab9aa95ae6e0979d29f71ac273 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Mon, 10 Aug 2020 17:49:01 +0300 Subject: [PATCH 353/506] [API/Binance] Change client implementation, remove explorer api (#1184) * Start to migrate binance to RPC only * Add GetBlockByNumber with test * Fixes and new test for multi-transaction * Add transactions api * Add tokens api * Add test to model * Remove extra param from init * Lint fixes * Fix binance mock tests * Some cleanup after notifier test * Api cleanup * Naming cleanup * model.go cleanup * base.go cleanup * Requested changes * Add new params for client request --- api/endpoint/transaction.go | 8 + go.mod | 1 + go.sum | 2 + mock/datafiles.yaml | 6 +- ...le77vddclka9z84ugywug48gn_txAsset_BNB.json | 1 + ...zevgcmf0q_txAsset_BNB_txType_TRANSFER.json | 1 - platform/binance/base.go | 13 +- platform/binance/base_test.go | 85 ++++ platform/binance/block.go | 63 +-- platform/binance/block_test.go | 136 +----- platform/binance/client.go | 119 +++-- platform/binance/explorer_client.go | 32 -- platform/binance/model.go | 457 ++++++++++-------- platform/binance/model_test.go | 229 +-------- platform/binance/token.go | 54 +-- platform/binance/token_test.go | 168 +------ platform/binance/transaction.go | 186 +------ platform/binance/transaction_test.go | 184 +------ platform/platform.go | 2 +- tests/postman/transaction_data.json | 4 +- 20 files changed, 522 insertions(+), 1229 deletions(-) create mode 100644 mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json delete mode 100644 mock/ext-api-data/binance-explorer_v1_txs__address_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q_txAsset_BNB_txType_TRANSFER.json create mode 100644 platform/binance/base_test.go delete mode 100644 platform/binance/explorer_client.go diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index d75579aa0..f072ce47c 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -171,6 +171,14 @@ func filterTransactionsByToken(token string, txs blockatlas.TxPage) blockatlas.T if strings.EqualFold(tx.Meta.(*blockatlas.NativeTokenTransfer).TokenID, token) { result = append(result, tx) } + case blockatlas.AnyAction: + if strings.EqualFold(tx.Meta.(blockatlas.AnyAction).TokenID, token) { + result = append(result, tx) + } + case *blockatlas.AnyAction: + if strings.EqualFold(tx.Meta.(*blockatlas.AnyAction).TokenID, token) { + result = append(result, tx) + } default: continue } diff --git a/go.mod b/go.mod index 553070cfb..3d2358596 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/elastic/go-windows v1.0.1 // indirect github.com/gin-gonic/gin v1.6.3 github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect + github.com/imroc/req v0.3.0 github.com/jinzhu/gorm v1.9.15 github.com/mitchellh/mapstructure v1.3.3 github.com/mr-tron/base58 v1.2.0 diff --git a/go.sum b/go.sum index 8211724e3..d263a18c7 100644 --- a/go.sum +++ b/go.sum @@ -234,6 +234,8 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U= +github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= diff --git a/mock/datafiles.yaml b/mock/datafiles.yaml index 4f9f4a3ff..c3c83b051 100644 --- a/mock/datafiles.yaml +++ b/mock/datafiles.yaml @@ -17,10 +17,10 @@ mockURL: /mock/algorand-api/v1/block/5478346 method: GET extURL: https://mainnet-algorand.api.purestake.io/ps1/v1/block/5478346 -- file: mock/ext-api-data/binance-explorer_v1_txs__address_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q_txAsset_BNB_txType_TRANSFER.json - mockURL: /mock/binance-explorer/v1/txs?address=bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q&txAsset=BNB&txType=TRANSFER +- file: mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json + mockURL: /mock/binance-api/v1/transactions?address=bnb1z35wusfv8twfele77vddclka9z84ugywug48gn&txAsset=BNB method: GET - extURL: https://explorer.binance.org/api/v1/txs?address=bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q&page=1&rows=20&txAsset=BNB&txType=TRANSFER + extURL: https://dex.binance.org/api/v1/transactions?address=bnb1z35wusfv8twfele77vddclka9z84ugywug48gn&txAsset=BNB - file: mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q mockURL: /mock/binance-api/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q method: GET diff --git a/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json b/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json new file mode 100644 index 000000000..77dafc5e7 --- /dev/null +++ b/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json @@ -0,0 +1 @@ +{"tx":[{"txHash":"FB38CE6A7D0E0DA2E720FDC7017C4207BD449E2D4C80D095C014DE2C9E1DB74A","blockHeight":105745488,"txType":"NEW_ORDER","timeStamp":"2020-08-07T21:30:24.258Z","fromAddr":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","toAddr":null,"value":"592.87095000","txAsset":"BNB","txFee":"0.00000000","proposalId":null,"txAge":14,"orderId":"1468EE412C3ADC9CFF3EF31ADC7EDD288F5E208E-11413870","code":0,"data":"{\"orderData\":{\"symbol\":\"BNB_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"21.9875\",\"quantity\":\"26.964\",\"timeInForce\":\"GTE\",\"orderId\":\"1468EE412C3ADC9CFF3EF31ADC7EDD288F5E208E-11413870\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":11413869}],"total":3140} diff --git a/mock/ext-api-data/binance-explorer_v1_txs__address_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q_txAsset_BNB_txType_TRANSFER.json b/mock/ext-api-data/binance-explorer_v1_txs__address_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q_txAsset_BNB_txType_TRANSFER.json deleted file mode 100644 index 980f8e988..000000000 --- a/mock/ext-api-data/binance-explorer_v1_txs__address_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q_txAsset_BNB_txType_TRANSFER.json +++ /dev/null @@ -1 +0,0 @@ -{"txNums":169,"txArray":[{"txHash":"CC11034825A1BB932D608F36BAA0655E6216C9BBA4769BC87FF0139609035650","blockHeight":87897954,"txType":"TRANSFER","timeStamp":1589571344220,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":219373,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"7DAD217B37B177538F60286E1ACAE0A739FA3EDC365F92C9A8BCA1EB9D1C466B","blockHeight":87897869,"txType":"TRANSFER","timeStamp":1589571308616,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":219409,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"3235A163F37B0F99C7570BDA9A2621CC115087FF8C6252B4FC340DF9C10C64EE","blockHeight":87897753,"txType":"TRANSFER","timeStamp":1589571259838,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00010000,"txAsset":"BNB","txFee":0.00037500,"txAge":219458,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"A0ED9785BAB44DE6D9F5311CE04E667E0107664B9E27C3ACA05AF4DBFE509474","blockHeight":87897702,"txType":"TRANSFER","timeStamp":1589571238493,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000100,"txAsset":"BNB","txFee":0.00037500,"txAge":219479,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"67B40FD9BD380D8BDB6ED0DF213690658A5B9FE1275FEE360A31E7D9D56D3156","blockHeight":87897594,"txType":"TRANSFER","timeStamp":1589571193162,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00010000,"txAsset":"BNB","txFee":0.00037500,"txAge":219524,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"A6603647F2DCC653A2A11FB5F3D2B82EF503860CECE7A5127BD9E3FA678CA4C8","blockHeight":87891198,"txType":"TRANSFER","timeStamp":1589568627146,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":222090,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"32080C2367C103C6B70EF8179BEA07803BA1A8A478897DE9EC99D95D5B6DBFA9","blockHeight":87890837,"txType":"TRANSFER","timeStamp":1589568487902,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":222230,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"AF6B71DA568D561E6DC450DE15FC9A77C58917323F67536AEB9EBC459D414000","blockHeight":87888079,"txType":"TRANSFER","timeStamp":1589567383565,"fromAddr":"bnb1xwalxpaes9r0z0fqdy70j3kz6aayetegur38gl","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":223334,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"ACC83ACD8D8F9073B25DD0A504EAA936882DA5305EA805622A34E725AABB8B73","blockHeight":87769136,"txType":"TRANSFER","timeStamp":1589519763058,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":270955,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"CED98241EE857C699FCCA5FBEC16F6604F93FA2943AD281A366AEF771B4F6081","blockHeight":87764491,"txType":"TRANSFER","timeStamp":1589517890608,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":272827,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"4A254FDDC8C3FAEE0E2BDF58370DD27055CA4D6C298730397D9702AC4FE676B0","blockHeight":87764293,"txType":"TRANSFER","timeStamp":1589517808749,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000100,"txAsset":"BNB","txFee":0.00037500,"txAge":272909,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"568B67B0B264031E6F712C31A2B81D86F74D839F131D1E562B20AE06A61252A5","blockHeight":87709527,"txType":"TRANSFER","timeStamp":1589495866706,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000001,"txAsset":"BNB","txFee":0.00037500,"txAge":294851,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"A5F25D0CA39CFC42C901E61E610C3D791E26D4F0401A74F7249B69029CC953E9","blockHeight":87709081,"txType":"TRANSFER","timeStamp":1589495676493,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":295041,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"B915CE3D9B0C92EB44A4197455A8A27A94566A20A2384E05F20A31C4276EAE54","blockHeight":87708586,"txType":"TRANSFER","timeStamp":1589495469184,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":295248,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"F105829EF7E0828CDADA00B0E0CD84443D219ED475EF452E685DD0FD74A9CA96","blockHeight":86779776,"txType":"TRANSFER","timeStamp":1589124863044,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":665855,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"2DD72EAEDAD575F956BAF5C0EE86A2BEF322715FB9D831959BF8D82A992D41DF","blockHeight":86779508,"txType":"TRANSFER","timeStamp":1589124756232,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00010000,"txAsset":"BNB","txFee":0.00037500,"txAge":665961,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"395F3450AF823D472C9F6DD626B50F2B0875E8BAEE9CE4EEF98C76640B25BFBE","blockHeight":86779356,"txType":"TRANSFER","timeStamp":1589124695388,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":666022,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"EB52141321642002C91551C4511C522F10887F338699E9C4D5821C879F73A669","blockHeight":85915186,"txType":"TRANSFER","timeStamp":1588777143568,"fromAddr":"bnb1m7ly8xsty9rcfnhcdjnde4qtns27j0umpnv3ja","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00001000,"txAsset":"BNB","txFee":0.00037500,"txAge":1013574,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"F15B711FA2F6DCCDC3D28FB74138B037E9B3840FFDB87F0E322DA4544982B65C","blockHeight":80642308,"txType":"TRANSFER","timeStamp":1586654422855,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000010,"txAsset":"BNB","txFee":0.00037500,"txAge":3136295,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0},{"txHash":"D6E00221A466618281A82B053C0C0C89FC99AB637343079C89F0184611263BBD","blockHeight":80636397,"txType":"TRANSFER","timeStamp":1586652053921,"fromAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","toAddr":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","value":0.00000100,"txAsset":"BNB","txFee":0.00037500,"txAge":3138664,"code":0,"log":"Msg 0: ","confirmBlocks":0,"memo":"","source":0,"hasChildren":0}]} \ No newline at end of file diff --git a/platform/binance/base.go b/platform/binance/base.go index 678bf0f81..a7a9ed430 100644 --- a/platform/binance/base.go +++ b/platform/binance/base.go @@ -2,24 +2,19 @@ package binance import ( "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" ) type Platform struct { - rpcClient Client - explorerClient ExplorerClient + client Client } -func Init(rpcApi, explorerApi string) *Platform { +func Init(api string) *Platform { p := Platform{ - rpcClient: Client{blockatlas.InitClient(rpcApi)}, - explorerClient: ExplorerClient{blockatlas.InitClient(explorerApi)}, + client: InitClient(api), } - p.rpcClient.ErrorHandler = handleHTTPError - p.explorerClient.ErrorHandler = handleHTTPError return &p } func (p *Platform) Coin() coin.Coin { - return coin.Coins[coin.BNB] + return coin.Binance() } diff --git a/platform/binance/base_test.go b/platform/binance/base_test.go new file mode 100644 index 000000000..40f481e49 --- /dev/null +++ b/platform/binance/base_test.go @@ -0,0 +1,85 @@ +package binance + +import ( + "fmt" + "net/http" +) + +const ( + wantedBlock = `{"number":104867508,"txs":[{"id":"4CD5BAA433BABA63D862141A4A2F9235B0BA5CBAB8114C93A0556ECA4EC7A68A","coin":714,"from":"bnb1l83kstts7lt9dpgawzechnrgjq54dql36dyspc","to":"","fee":"0","date":1596472337,"block":104867508,"status":"completed","sequence":1023322,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Cancel Order","key":"cancel_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"0"}},{"id":"9B87D17581F2AC73D2999EDE56535E50D9D4DB75150A92A90122190F77D47755","coin":714,"from":"bnb1c4czpzvn0ttdcpnv3cy2858l2m9frxdfgk4jr0","to":"bnb1g2ukzn702napq3levm54m2z3p2gam7upern9aq","fee":"37500","date":1596472337,"block":104867508,"status":"completed","sequence":6,"type":"transfer","memo":"","metadata":{"value":"24481570","symbol":"BNB","decimals":8}},{"id":"5C0580AC983C1CF36F1656D9E8B062CD0578839BEFC839EFD6720FF315B45EEB","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596472337,"block":104867508,"status":"completed","sequence":1509154,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"10500000000"}}]}` + wantedTxs = `[{"id":"771B07C8D921B5995524C163E9D4504C31A9E07EC858263A53EA007484009C90","coin":714,"from":"bnb1d83u9afqw296ejw9jdfhc22f0ljr23nn7pradx","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826106,"block":105722032,"status":"completed","sequence":33,"type":"transfer","memo":"106890151","metadata":{"value":"120740436","symbol":"BNB","decimals":8}},{"id":"1C5682716D2D34DD01428AD8D4200081FBDA06CE886B77499F755E9D93B0FF20","coin":714,"from":"bnb1k9ktd79psysucucyxqcd5r9ahuuygk8gh3ly8q","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826069,"block":105721942,"status":"completed","sequence":64,"type":"transfer","memo":"103215089","metadata":{"value":"229350524","symbol":"BNB","decimals":8}},{"id":"C728F7C13977649FCDF9B8E983A9E3AA257EB5596DBCA2A2580584312B5AA535","coin":714,"from":"bnb155svs6sgxe55rnvs6ghprtqu0mh69kehphsppd","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826063,"block":105721925,"status":"completed","sequence":23121,"type":"transfer","memo":"101045880","metadata":{"value":"11964120000","symbol":"BNB","decimals":8}},{"id":"794302F9C6562358581A3A8432AF82CD70DF0DA345C917BDE21DDF9A9D4B9DE7","coin":714,"from":"bnb14gk6m77tswyks9nnadm92mdy3066wj42t60z0l","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826058,"block":105721913,"status":"completed","sequence":11228,"type":"transfer","memo":"100341541","metadata":{"value":"456000000","symbol":"BNB","decimals":8}},{"id":"2827377A04E3B22DD654A02AD4BA50B3CB83973B6B9BA1A423ABD5045873850C","coin":714,"from":"bnb132gvg9gdthtaf6xgkk9jkmsep56fv62vg95unv","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826024,"block":105721828,"status":"completed","sequence":4,"type":"transfer","memo":"105772095","metadata":{"value":"1045498916","symbol":"BNB","decimals":8}},{"id":"AACC80FDA9C45DCD7F6DBAA40A2EB600FF6EBB24A5A840578D4AB306C3427385","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826006,"block":105721785,"status":"completed","sequence":65,"type":"transfer","memo":"109027392","metadata":{"value":"8750000000","symbol":"BNB","decimals":8}},{"id":"66CF0F65442FD35A3B91CC2655CE60E565D13EEFC6BDB1C5AF9F9E484C8B6295","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825967,"block":105721686,"status":"completed","sequence":896,"type":"transfer","memo":"107780643","metadata":{"value":"878900000","symbol":"BNB","decimals":8}},{"id":"81EA185BE754809E40FCBF1B07A0C389F39DECD38D56302D980534850996B144","coin":714,"from":"bnb12nq7fhh3t8q0m9s2n5gqwd9gcx0j85yn0h5zcu","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825888,"block":105721490,"status":"completed","sequence":0,"type":"transfer","memo":"101210049","metadata":{"value":"4498159221","symbol":"BNB","decimals":8}},{"id":"24ED2153427ABACD7F6DB53A1339D9C2573D720FDE6EC45B0047CB146227FF9A","coin":714,"from":"bnb1s5qucugaxv7gkzyg4kacf225s6mhj0ysejn8jq","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825847,"block":105721385,"status":"completed","sequence":40,"type":"transfer","memo":"104298046","metadata":{"value":"34300000000","symbol":"BNB","decimals":8}},{"id":"411A27CE85D0928BC5908DA5BA288CB52E152C1E54FA35042147A90FCEBAB29C","coin":714,"from":"bnb1erj09eqrnz06jv2acxhhy7s3k0q6w4hfmj9rey","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825789,"block":105721238,"status":"completed","sequence":12,"type":"transfer","memo":"107303874","metadata":{"value":"6319074","symbol":"BNB","decimals":8}},{"id":"25359F7277760004BBD42557B3E50F86F06B096478840E057C6F394BF63F6081","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825692,"block":105720997,"status":"completed","sequence":57,"type":"transfer","memo":"109027392","metadata":{"value":"1090000000","symbol":"BNB","decimals":8}},{"id":"1DB710AF4983D9CAFB24AC3DD7C2C6EBC7752F347E5A7599840AB3EFBD436C5D","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825639,"block":105720867,"status":"completed","sequence":56,"type":"transfer","memo":"109027392","metadata":{"value":"2000000000","symbol":"BNB","decimals":8}},{"id":"B7C799B9853ECA41F02241B67E294E2642AE88BBF551DE188A73C48D1A0E821D","coin":714,"from":"bnb1q2994t0djzsy0q2fc62jruxr22nxq6y8l4503l","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825619,"block":105720816,"status":"completed","sequence":1,"type":"transfer","memo":"108202494","metadata":{"value":"295957149","symbol":"BNB","decimals":8}},{"id":"865C098D021CC649FC83B2442092E4D6F0777488163E5797DA9D264C87F1F4F4","coin":714,"from":"bnb16xqcchlutsm8g6gk7wvlzukeu2sy9xt2u77056","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825548,"block":105720641,"status":"completed","sequence":33,"type":"transfer","memo":"102080722","metadata":{"value":"1373501799","symbol":"BNB","decimals":8}},{"id":"1D4F777D1D227D57E4D4BAC3E83FB203147E7B0E7429E60A48A9053372359174","coin":714,"from":"bnb1t6tk66zncqqt7twnfyxx22fn9t3wz3nac5hkck","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825500,"block":105720519,"status":"completed","sequence":14,"type":"transfer","memo":"106456805","metadata":{"value":"1490609","symbol":"BNB","decimals":8}},{"id":"9A818687D52B4E9E0C5F962E6E464ECC6348D6A41AE2C5DD051A5EF71E15B1AC","coin":714,"from":"bnb1v47qw5acc72c34uwt7t9wm9ztqtg6678dmrssa","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825415,"block":105720307,"status":"completed","sequence":6273,"type":"transfer","memo":"104471384","metadata":{"value":"356700000","symbol":"BNB","decimals":8}},{"id":"6C7D4469525E44501ED03BA38A6D54A04DFD6AD2D13328761DA4602A3D777332","coin":714,"from":"bnb1tzet704pc6zjsl3xcwdexn6xlu0zc092y0n4ay","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825348,"block":105720136,"status":"completed","sequence":721,"type":"transfer","memo":"101245732","metadata":{"value":"93900000","symbol":"BNB","decimals":8}},{"id":"8C47875F09371B45C0A29D7C6EF308A1C499D1BBECD5A56E0561B40675AF2D26","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825311,"block":105720042,"status":"completed","sequence":1912,"type":"transfer","memo":"101186586","metadata":{"value":"95193451","symbol":"BNB","decimals":8}},{"id":"39A48766F8ACC33B3BB1B4F442ABFDFBC695F440D72795794A01E8E446CE8EAE","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825298,"block":105720010,"status":"completed","sequence":47,"type":"transfer","memo":"109027392","metadata":{"value":"480000000","symbol":"BNB","decimals":8}},{"id":"54248E3C09713E3870F661749A8690DAD46A8078C7346C497EB4E166564420F4","coin":714,"from":"bnb1hc304lytvp9jnumnjmppq97erm70r7muzv6y98","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825237,"block":105719860,"status":"completed","sequence":1,"type":"transfer","memo":"105261446","metadata":{"value":"10210962500","symbol":"BNB","decimals":8}},{"id":"ADDDB705AB8C2B1AF58D7EDCAEC00C893A6CD87281D7A7146689E9FE1A846EAE","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825173,"block":105719705,"status":"completed","sequence":895,"type":"transfer","memo":"103617121","metadata":{"value":"297900000","symbol":"BNB","decimals":8}},{"id":"7C338C78BBBCD998628CCAF85211883AACB159201755501139F56E0D2A7941A4","coin":714,"from":"bnb1pys084nlc8gqm7lvjje4kt39dn84vd2xsvnwqa","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825147,"block":105719641,"status":"completed","sequence":18,"type":"transfer","memo":"108802310","metadata":{"value":"200000000","symbol":"BNB","decimals":8}},{"id":"6DD7120E43CD5031E2DD6C7977D141B74CA41C8E476D8AE972A9DA2D2EFD2D84","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825061,"block":105719428,"status":"completed","sequence":894,"type":"transfer","memo":"102393444","metadata":{"value":"677900000","symbol":"BNB","decimals":8}},{"id":"86FB14C637D7B0A4AA123FFF76C5C541C70568B67E3F5BC63EB0FDEDEF30301F","coin":714,"from":"bnb17nak8gnucl6lcze0d04def4de77a33qh29f6ur","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825051,"block":105719403,"status":"completed","sequence":3,"type":"transfer","memo":"109823910","metadata":{"value":"900000","symbol":"BNB","decimals":8}},{"id":"1DEEFC0A838F80704574951DF15969CCE34654BE2007BF77F9521A1B4686BE33","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825014,"block":105719312,"status":"completed","sequence":1431,"type":"transfer","memo":"103268674","metadata":{"value":"315739000","symbol":"BNB","decimals":8}}]` + wantedTokens = `[{"name":"Travala.com Token","symbol":"AVA","decimals":8,"token_id":"AVA-645","coin":714,"type":"BEP2"},{"name":"Binance Chain Native Token","symbol":"BNB","decimals":8,"token_id":"BNB","coin":714,"type":"BEP2"},{"name":"Binance USD","symbol":"BUSD","decimals":8,"token_id":"BUSD-BD1","coin":714,"type":"BEP2"}]` + wantedTxsAva = `[{"id":"2BF49DF1D10D9A20438376E760352734DAEBD5D92D6CAA14735EE095A3F65FD3","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827621,"block":105725696,"status":"completed","sequence":1594673,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"2700000000"}},{"id":"C858D15E2745A61D0D3D354750E4462792160FFBB9927739587FFAAEDEFA00FF","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827612,"block":105725676,"status":"completed","sequence":1594670,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"13100000000"}},{"id":"9BDCF416622AA4E8F11162747614585FD840F5721D7163A68BC03EC94E855DEE","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827611,"block":105725673,"status":"completed","sequence":1594669,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1700000000"}},{"id":"52512D9498D4CF51997A5A62C0A55252776B00C888D2D01502C68B56E892F42E","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827603,"block":105725652,"status":"completed","sequence":1594666,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"2200000000"}},{"id":"1BAF96AB01E7AB5A7746CA7E76B293CD636D55713C7CCE71FD0E0ED8ACE05C92","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827600,"block":105725646,"status":"completed","sequence":1594665,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"9990419EFE1B327966EBAAFFC2771046E1AC2E4DDFAD8A93C55DE105A2948A8D","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827591,"block":105725624,"status":"completed","sequence":1594662,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"10800000000"}},{"id":"922F86E110E897233A7B43C0D31397923298C176EBE6F33D98B70ACB911A497A","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827589,"block":105725620,"status":"completed","sequence":1594661,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1800000000"}},{"id":"925A208AFDCD718F8383F7559C7BBA5AE616B693A6029F57BFB67AEBB1CE5F3C","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827580,"block":105725597,"status":"completed","sequence":1594658,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"8200000000"}},{"id":"2B69327D6C0C7B9061AAD962BF4838E3B630A844439013E0EBEFC5B722205774","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827571,"block":105725575,"status":"completed","sequence":1594655,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"BB6FD86C9738C2991F587996ABBAC1151DF1F9DE57FDCC977BB0D8FBAD31188A","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827552,"block":105725529,"status":"completed","sequence":1594653,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"2500000000"}},{"id":"97856635BDBA4B0B3EAAA76EA46D848A2DFE3AAE554A33D308CFC4474C769290","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827550,"block":105725526,"status":"completed","sequence":1594652,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"5500000000"}},{"id":"4B4EC65A5972CC15C4B410339ED0081C4BB57F4E08F2A35744845F5A71531B59","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827537,"block":105725493,"status":"completed","sequence":1594648,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1700000000"}},{"id":"86B5FFDDB06E0973A05434DDB858868A45EDA8B07E0D75125FEAEBA1093D4EA5","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827535,"block":105725489,"status":"completed","sequence":1594647,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"11800000000"}},{"id":"D20757EB130E8146D1A12E869BE69EC2CB03193D8E62467327B09A5D73BBC6F8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827529,"block":105725473,"status":"completed","sequence":1594645,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"3300000000"}},{"id":"04291A7AE08A78C5E5AE216C67D17B6A4260950FFAB6FD3D1C1B991E3B7BB935","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827527,"block":105725470,"status":"completed","sequence":1594644,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"14600000000"}},{"id":"31E16E3F53DD476475256C8D872AF3FD86DC44F3085EF87DDE3643E20C0CE624","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827518,"block":105725448,"status":"completed","sequence":1594641,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1800000000"}},{"id":"1D61A9E35893BB51DE4AE63FA6898FCAE14B6D48F7A2EFD0B51DCCACF6E36B88","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827517,"block":105725446,"status":"completed","sequence":1594640,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"13700000000"}},{"id":"AB9E29B110844BD76F58B058CC20F1E13B37A1AAC4F09978BDE159F1B09B585E","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827509,"block":105725425,"status":"completed","sequence":1594637,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"F81649BAF3D888E3772C8708D255FE91E0CDB2818006A1FC96FFBDAC24BDE675","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827508,"block":105725422,"status":"completed","sequence":1594636,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"8700000000"}},{"id":"71B25BF61219BC87980EB67064C346801C01B00FFE52932799E28FB20DAF41D8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827499,"block":105725401,"status":"completed","sequence":1594633,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1200000000"}},{"id":"3424BFCA860A878FDCF304AD414EDE2AB3B0FF258CA940CD1269F469ED7C422C","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827490,"block":105725379,"status":"completed","sequence":1594630,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"7600000000"}},{"id":"46FFA039B955953D4F19BE7D56FA793B71F34BFB460D9B84A152B554E9219C44","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827488,"block":105725375,"status":"completed","sequence":1594629,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"13900000000"}},{"id":"701100D3783744D633FF34A6E211CEB923EA9BCE6D87A64211801E71F71AEE03","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827469,"block":105725327,"status":"completed","sequence":1594627,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"4900000000"}},{"id":"B12B30509B45CEFE526DAADDAC6399F902B30418859042D7A23F9A2FB311A6C8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827467,"block":105725323,"status":"completed","sequence":1594626,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"2700000000"}},{"id":"933819F35F0F89FB2D58DC50CD15FABB3DA0B817BFCD39A8DDC99DFEC1663F7D","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827458,"block":105725301,"status":"completed","sequence":1594623,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"9500000000"}}]` + wantedBlockMulti = `{"number":105529271,"txs":[{"id":"432FF828B1DC1C4DAF13A51B6AE7ADD9932B7FC6526C28F7FE9C905F95472820","coin":714,"from":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","to":"","fee":"0","date":1596746326,"block":105529271,"status":"completed","sequence":11317170,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Cancel Order","key":"cancel_order","token_id":"","name":"","symbol":"","decimals":8,"value":"0"}},{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","to":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","fee":"60000","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"1","symbol":"BNB","decimals":8}},{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb1t38ccns9var4ac4yj2ylmu99r9ecmggr8ye5e5","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"0","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"39421249","symbol":"BNB","decimals":8}}]}` + wantedTxsResponse = `{"tx":[{"txHash":"771B07C8D921B5995524C163E9D4504C31A9E07EC858263A53EA007484009C90","blockHeight":105722032,"txType":"TRANSFER","timeStamp":"2020-08-07T18:48:26.284Z","fromAddr":"bnb1d83u9afqw296ejw9jdfhc22f0ljr23nn7pradx","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"1.20740436","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":104,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"106890151","source":1,"sequence":33},{"txHash":"1C5682716D2D34DD01428AD8D4200081FBDA06CE886B77499F755E9D93B0FF20","blockHeight":105721942,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:49.895Z","fromAddr":"bnb1k9ktd79psysucucyxqcd5r9ahuuygk8gh3ly8q","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.29350524","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":140,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"103215089","source":2,"sequence":64},{"txHash":"C728F7C13977649FCDF9B8E983A9E3AA257EB5596DBCA2A2580584312B5AA535","blockHeight":105721925,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:43.111Z","fromAddr":"bnb155svs6sgxe55rnvs6ghprtqu0mh69kehphsppd","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"119.64120000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":147,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101045880","source":1,"sequence":23121},{"txHash":"794302F9C6562358581A3A8432AF82CD70DF0DA345C917BDE21DDF9A9D4B9DE7","blockHeight":105721913,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:38.279Z","fromAddr":"bnb14gk6m77tswyks9nnadm92mdy3066wj42t60z0l","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"4.56000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":152,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"100341541","source":1,"sequence":11228},{"txHash":"2827377A04E3B22DD654A02AD4BA50B3CB83973B6B9BA1A423ABD5045873850C","blockHeight":105721828,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:04.205Z","fromAddr":"bnb132gvg9gdthtaf6xgkk9jkmsep56fv62vg95unv","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"10.45498916","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":186,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"105772095","source":2,"sequence":4},{"txHash":"AACC80FDA9C45DCD7F6DBAA40A2EB600FF6EBB24A5A840578D4AB306C3427385","blockHeight":105721785,"txType":"TRANSFER","timeStamp":"2020-08-07T18:46:46.832Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"87.50000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":203,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":65},{"txHash":"66CF0F65442FD35A3B91CC2655CE60E565D13EEFC6BDB1C5AF9F9E484C8B6295","blockHeight":105721686,"txType":"TRANSFER","timeStamp":"2020-08-07T18:46:07.122Z","fromAddr":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"8.78900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":243,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"107780643","source":0,"sequence":896},{"txHash":"81EA185BE754809E40FCBF1B07A0C389F39DECD38D56302D980534850996B144","blockHeight":105721490,"txType":"TRANSFER","timeStamp":"2020-08-07T18:44:48.958Z","fromAddr":"bnb12nq7fhh3t8q0m9s2n5gqwd9gcx0j85yn0h5zcu","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"44.98159221","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":321,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101210049","source":0,"sequence":0},{"txHash":"24ED2153427ABACD7F6DB53A1339D9C2573D720FDE6EC45B0047CB146227FF9A","blockHeight":105721385,"txType":"TRANSFER","timeStamp":"2020-08-07T18:44:07.201Z","fromAddr":"bnb1s5qucugaxv7gkzyg4kacf225s6mhj0ysejn8jq","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"343.00000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":363,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"104298046","source":2,"sequence":40},{"txHash":"411A27CE85D0928BC5908DA5BA288CB52E152C1E54FA35042147A90FCEBAB29C","blockHeight":105721238,"txType":"TRANSFER","timeStamp":"2020-08-07T18:43:09.084Z","fromAddr":"bnb1erj09eqrnz06jv2acxhhy7s3k0q6w4hfmj9rey","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.06319074","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":421,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"107303874","source":2,"sequence":12},{"txHash":"25359F7277760004BBD42557B3E50F86F06B096478840E057C6F394BF63F6081","blockHeight":105720997,"txType":"TRANSFER","timeStamp":"2020-08-07T18:41:32.193Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"10.90000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":518,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":57},{"txHash":"1DB710AF4983D9CAFB24AC3DD7C2C6EBC7752F347E5A7599840AB3EFBD436C5D","blockHeight":105720867,"txType":"TRANSFER","timeStamp":"2020-08-07T18:40:39.623Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"20.00000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":570,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":56},{"txHash":"B7C799B9853ECA41F02241B67E294E2642AE88BBF551DE188A73C48D1A0E821D","blockHeight":105720816,"txType":"TRANSFER","timeStamp":"2020-08-07T18:40:19.123Z","fromAddr":"bnb1q2994t0djzsy0q2fc62jruxr22nxq6y8l4503l","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.95957149","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":591,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"108202494","source":0,"sequence":1},{"txHash":"865C098D021CC649FC83B2442092E4D6F0777488163E5797DA9D264C87F1F4F4","blockHeight":105720641,"txType":"TRANSFER","timeStamp":"2020-08-07T18:39:08.972Z","fromAddr":"bnb16xqcchlutsm8g6gk7wvlzukeu2sy9xt2u77056","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"13.73501799","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":661,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"102080722","source":1,"sequence":33},{"txHash":"1D4F777D1D227D57E4D4BAC3E83FB203147E7B0E7429E60A48A9053372359174","blockHeight":105720519,"txType":"TRANSFER","timeStamp":"2020-08-07T18:38:20.149Z","fromAddr":"bnb1t6tk66zncqqt7twnfyxx22fn9t3wz3nac5hkck","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.01490609","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":710,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"106456805","source":2,"sequence":14},{"txHash":"9A818687D52B4E9E0C5F962E6E464ECC6348D6A41AE2C5DD051A5EF71E15B1AC","blockHeight":105720307,"txType":"TRANSFER","timeStamp":"2020-08-07T18:36:55.571Z","fromAddr":"bnb1v47qw5acc72c34uwt7t9wm9ztqtg6678dmrssa","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"3.56700000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":794,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"104471384","source":2,"sequence":6273},{"txHash":"6C7D4469525E44501ED03BA38A6D54A04DFD6AD2D13328761DA4602A3D777332","blockHeight":105720136,"txType":"TRANSFER","timeStamp":"2020-08-07T18:35:48.142Z","fromAddr":"bnb1tzet704pc6zjsl3xcwdexn6xlu0zc092y0n4ay","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.93900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":862,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101245732","source":0,"sequence":721},{"txHash":"8C47875F09371B45C0A29D7C6EF308A1C499D1BBECD5A56E0561B40675AF2D26","blockHeight":105720042,"txType":"TRANSFER","timeStamp":"2020-08-07T18:35:11.247Z","fromAddr":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.95193451","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":899,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101186586","source":2,"sequence":1912},{"txHash":"39A48766F8ACC33B3BB1B4F442ABFDFBC695F440D72795794A01E8E446CE8EAE","blockHeight":105720010,"txType":"TRANSFER","timeStamp":"2020-08-07T18:34:58.634Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"4.80000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":911,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":47},{"txHash":"54248E3C09713E3870F661749A8690DAD46A8078C7346C497EB4E166564420F4","blockHeight":105719860,"txType":"TRANSFER","timeStamp":"2020-08-07T18:33:57.102Z","fromAddr":"bnb1hc304lytvp9jnumnjmppq97erm70r7muzv6y98","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"102.10962500","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":973,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"105261446","source":0,"sequence":1},{"txHash":"ADDDB705AB8C2B1AF58D7EDCAEC00C893A6CD87281D7A7146689E9FE1A846EAE","blockHeight":105719705,"txType":"TRANSFER","timeStamp":"2020-08-07T18:32:53.527Z","fromAddr":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.97900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1036,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"103617121","source":0,"sequence":895},{"txHash":"7C338C78BBBCD998628CCAF85211883AACB159201755501139F56E0D2A7941A4","blockHeight":105719641,"txType":"TRANSFER","timeStamp":"2020-08-07T18:32:27.476Z","fromAddr":"bnb1pys084nlc8gqm7lvjje4kt39dn84vd2xsvnwqa","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.00000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1062,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"108802310","source":0,"sequence":18},{"txHash":"6DD7120E43CD5031E2DD6C7977D141B74CA41C8E476D8AE972A9DA2D2EFD2D84","blockHeight":105719428,"txType":"TRANSFER","timeStamp":"2020-08-07T18:31:01.143Z","fromAddr":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"6.77900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1149,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"102393444","source":0,"sequence":894},{"txHash":"86FB14C637D7B0A4AA123FFF76C5C541C70568B67E3F5BC63EB0FDEDEF30301F","blockHeight":105719403,"txType":"TRANSFER","timeStamp":"2020-08-07T18:30:51.089Z","fromAddr":"bnb17nak8gnucl6lcze0d04def4de77a33qh29f6ur","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.00900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1159,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109823910","source":2,"sequence":3},{"txHash":"1DEEFC0A838F80704574951DF15969CCE34654BE2007BF77F9521A1B4686BE33","blockHeight":105719312,"txType":"TRANSFER","timeStamp":"2020-08-07T18:30:14.498Z","fromAddr":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"3.15739000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1195,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"103268674","source":2,"sequence":1431}],"total":1636}` + wantedAccountMetaResponse = `{"account_number":398176,"address":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","balances":[{"free":"366.87270502","frozen":"0.00000000","locked":"2226.00000000","symbol":"AVA-645"},{"free":"6.51198688","frozen":"0.00000000","locked":"0.00000000","symbol":"BNB"},{"free":"850.41375978","frozen":"0.00000000","locked":"3220.00483000","symbol":"BUSD-BD1"}],"flags":0,"public_key":[2,241,253,162,68,84,67,180,235,15,238,212,39,75,236,33,202,249,109,68,247,56,104,66,240,219,8,22,245,187,84,46,54],"sequence":1595533}` + wantedTokensResponse = `[{"mintable":true,"name":"Africa Stable-Coin","original_symbol":"ABCD","owner":"bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms","symbol":"ABCD-5D8","total_supply":"3000000.00000000"},{"mintable":false,"name":"Aditus","original_symbol":"ADI","owner":"bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps","symbol":"ADI-6BB","total_supply":"750000000.00000000"},{"mintable":false,"name":"Aergo","original_symbol":"AERGO","owner":"bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl","symbol":"AERGO-46B","total_supply":"500000000.00000000"},{"mintable":false,"name":"Alaris","original_symbol":"ALA","owner":"bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7","symbol":"ALA-DCD","total_supply":"60000000.00000000"},{"mintable":false,"name":"ANKR","original_symbol":"ANKR","owner":"bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn","symbol":"ANKR-E97","total_supply":"10000000000.00000000"},{"mintable":false,"name":"Aeron","original_symbol":"ARN","owner":"bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne","symbol":"ARN-71B","total_supply":"20000000.00000000"},{"mintable":true,"name":"ARPA","original_symbol":"ARPA","owner":"bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c","symbol":"ARPA-575","total_supply":"12000000.00000000"},{"mintable":false,"name":"Maecenas ART Token","original_symbol":"ART","owner":"bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l","symbol":"ART-3C9","total_supply":"100000000.00000000"},{"mintable":true,"name":"Atlas Protocol","original_symbol":"ATP","owner":"bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf","symbol":"ATP-38C","total_supply":"40000000.00000000"},{"mintable":false,"name":"Travala.com Token","original_symbol":"AVA","owner":"bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c","symbol":"AVA-645","total_supply":"61228716.00000000"},{"mintable":true,"name":"“Atomic","original_symbol":"AWC","owner":"bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw","symbol":"AWC-8B2","total_supply":"147.00000000"},{"mintable":false,"name":"Atomic Wallet Token","original_symbol":"AWC","owner":"bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw","symbol":"AWC-986","total_supply":"50000000.00000000"},{"mintable":false,"name":"AXPR.B","original_symbol":"AXPR","owner":"bnb1zpnmet0vhfupn9ysu26gukzj7a2xkkcry22n9t","symbol":"AXPR-777","total_supply":"347955111.02000000"},{"mintable":true,"name":"BAWnetwork","original_symbol":"BAW","owner":"bnb1umdp5z4hugur26tcgf48fhr0548fv0q0fga84u","symbol":"BAW-DFB","total_supply":"25000000000.00000000"},{"mintable":true,"name":"BCH BEP2","original_symbol":"BCH","owner":"bnb15tjhzw85wyywwp7zvc4l3ux3j0393rzp9exl0p","symbol":"BCH-1FD","total_supply":"5000.00000000"},{"mintable":false,"name":"Blockmason Credit Protocol","original_symbol":"BCPT","owner":"bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew","symbol":"BCPT-95A","total_supply":"116158667.00000000"},{"mintable":true,"name":"3X Short Bitcoin Token","original_symbol":"BEAR","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"BEAR-14C","total_supply":"50301.00000000"},{"mintable":false,"name":"EOSBet Token","original_symbol":"BET","owner":"bnb1rgylg0f3ka24a63rnq926quvet438fxrz3320c","symbol":"BET-844","total_supply":"88000000.00000000"},{"mintable":false,"name":"BETX Token","original_symbol":"BETX","owner":"bnb15v9e3c4wy8vpex0c5fj702lexjesh30v2203f2","symbol":"BETX-A0C","total_supply":"200000000.00000000"},{"mintable":true,"name":"Binance GBP Stable Coin","original_symbol":"BGBP","owner":"bnb1r4ag7kd90rptlhcuuc8trh60v4m4vvzrfyecta","symbol":"BGBP-CF3","total_supply":"200.00000000"},{"mintable":true,"name":"Humanity First Token","original_symbol":"BHFT","owner":"bnb148t3u8zxa44vhydes5qa8xnxuzuq6zgyxmzt6d","symbol":"BHFT-BBE","total_supply":"636425000.00000000"},{"mintable":true,"name":"BIDR BEP2","original_symbol":"BIDR","owner":"bnb1v7hlk89x4t6wtfx89wrvhxj5wcv7sxjrve6dav","symbol":"BIDR-0E9","total_supply":"13700000000.00000000"},{"mintable":false,"name":"Bitwires Token","original_symbol":"BKBT","owner":"bnb104p50kz2uvep5s5u6j0lr6vkl6rp5g4653d7w4","symbol":"BKBT-3A6","total_supply":"10000000000.00000000"},{"mintable":true,"name":"Binance KRW","original_symbol":"BKRW","owner":"bnb18kha55gvsxl7gkdh8y329hu3p6wndh6jkwqnxn","symbol":"BKRW-AB7","total_supply":"1571020711.00000000"},{"mintable":false,"name":"Blockmason Link","original_symbol":"BLINK","owner":"bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew","symbol":"BLINK-9C6","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Binance Chain Native Token","original_symbol":"BNB","owner":"bnb1ultyhpw2p2ktvr68swz56570lgj2rdsadq3ym2","symbol":"BNB","total_supply":"176406560.90000000"},{"mintable":false,"name":"BOLT Token","original_symbol":"BOLT","owner":"bnb177ujwmshxu8r9za4vy9ztqn65tmr54ddw958rt","symbol":"BOLT-4C6","total_supply":"980230000.00000000"},{"mintable":false,"name":"Bitcloud Pro","original_symbol":"BPRO","owner":"bnb1482svhhrffpga5wmqw8068af4c9u2q9dp3hg4m","symbol":"BPRO-5A6","total_supply":"5000000000.00000000"},{"mintable":true,"name":"BQTX","original_symbol":"BQTX","owner":"bnb1j42h6j40htujnjmtp4ckw4zx27vp0f93cvmua8","symbol":"BQTX-235","total_supply":"1000000.00000000"},{"mintable":false,"name":"BOOSTO","original_symbol":"BST2","owner":"bnb19k2av7cmdvp9f0qkeu5vfl59yp8ftqv2s55dzs","symbol":"BST2-2F2","total_supply":"500000000.00000000"},{"mintable":true,"name":"Bitcoin BEP2","original_symbol":"BTCB","owner":"bnb1akey87kt0r8y3fmhu2l8eyzdjvt9ptl5cppz0v","symbol":"BTCB-1DE","total_supply":"9001.00000000"},{"mintable":true,"name":"BTTB","original_symbol":"BTTB","owner":"bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq","symbol":"BTTB-D31","total_supply":"1000000000.00000000"},{"mintable":true,"name":"3x Long Bitcoin Token","original_symbol":"BULL","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"BULL-BE4","total_supply":"604.80000000"},{"mintable":true,"name":"Binance USD","original_symbol":"BUSD","owner":"bnb19v2ayq6k6e5x6ny3jdutdm6kpqn3n6mxheegvj","symbol":"BUSD-BD1","total_supply":"26000000.00000000"},{"mintable":false,"name":"Bezant Token","original_symbol":"BZNT","owner":"bnb1w5a5jywe3cu20uq6n6x3vmzcq342s6st4cz73s","symbol":"BZNT-464","total_supply":"964511442.00000000"},{"mintable":false,"name":"CanYaCoin","original_symbol":"CAN","owner":"bnb16w59lfh4y2cqvu8f7yr000ll37ldh4w6hnz7l0","symbol":"CAN-677","total_supply":"95827000.00000000"},{"mintable":false,"name":"CASHAA","original_symbol":"CAS","owner":"bnb1xkw2sagpx6t0cmwzapxpv94tupvqk7tpgy72ku","symbol":"CAS-167","total_supply":"1000000000.00000000"},{"mintable":false,"name":"Cubiex","original_symbol":"CBIX","owner":"bnb1jlm66w38gpfuqr4s2jcfwlcrlx46p05thdnv7g","symbol":"CBIX-3C9","total_supply":"150000000.00000000"},{"mintable":false,"name":"CryptoBonusMiles","original_symbol":"CBM","owner":"bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne","symbol":"CBM-4B2","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Clipper Coin","original_symbol":"CCCX","owner":"bnb1ry99rte8gfnn9c6at9mlmrrq6p2k4u7732j9h7","symbol":"CCCX-10D","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Chiliz","original_symbol":"CHZ","owner":"bnb1cghr4z8ag440tv4wnk3l6wzynytlpvfqltm9ph","symbol":"CHZ-ECD","total_supply":"8888888888.00000000"},{"mintable":false,"name":"Crypto Neo-value Neural System","original_symbol":"CNNS","owner":"bnb193wdp4gdnm58urnsjf8nv57lxt58sckt2k50ss","symbol":"CNNS-E16","total_supply":"10000000000.00000000"},{"mintable":false,"name":"Contentos","original_symbol":"COS","owner":"bnb1u9j9hkst6gf09dkdvxlj7puk8c7vh68a0kkmht","symbol":"COS-2E4","total_supply":"9400000000.00000000"},{"mintable":true,"name":"COTI","original_symbol":"COTI","owner":"bnb1kn733gkku9xsqkuk6wcz86gftqtl4qvthvrj5m","symbol":"COTI-CBB","total_supply":"80000000.00000000"},{"mintable":false,"name":"Covalent Token","original_symbol":"COVA","owner":"bnb1pucvxaf3l9rslupza75r9fca9h5892ntumszfm","symbol":"COVA-218","total_supply":"6500000000.00000000"},{"mintable":false,"name":"CPChain","original_symbol":"CPC","owner":"bnb1wq4rlwrmvvltlarvypql8wrr4vlh0dczd8uksg","symbol":"CPC-FED","total_supply":"150000000.00000000"},{"mintable":false,"name":"Crypterium Token","original_symbol":"CRPT","owner":"bnb17fk3uvagucxzpvmdvd373fapqsahxvzevdard9","symbol":"CRPT-8C9","total_supply":"99968575.14285720"},{"mintable":false,"name":"“Consentium”","original_symbol":"CSM","owner":"bnb1gguz7vcrlf7a87et8u5gt40f0890qvkpkn9y79","symbol":"CSM-734","total_supply":"84000000.00000000"},{"mintable":true,"name":"Carbon Dollar","original_symbol":"CUSD","owner":"bnb1y9797dtklkm3haajsfnevm9ruuxs5fyf5rpj67","symbol":"CUSD-24B","total_supply":"9999999999.00000000"},{"mintable":false,"name":"Konstellation Network","original_symbol":"DARC","owner":"bnb1gyhnhdns4vf63nfzfq7g25czj8swjgrz3rhah8","symbol":"DARC-24B","total_supply":"1000000000.00000000"},{"mintable":true,"name":"DeepCloud","original_symbol":"DEEP","owner":"bnb1t0ws9gvnjm7j7qssk8te7m2dt5hmm8s3amqk2d","symbol":"DEEP-9D3","total_supply":"200000000.00000000"},{"mintable":false,"name":"DeFi Token","original_symbol":"DEFI","owner":"bnb1q5xefr07503pqtfrl5sfyyhlghxwc80d4vpas2","symbol":"DEFI-FA5","total_supply":"2500000000.00000000"},{"mintable":true,"name":"DOS Network Token","original_symbol":"DOS","owner":"bnb13gse9n7mvrjg5w2cymnt4nmxkgj200k9k2l2nh","symbol":"DOS-120","total_supply":"1000000000.00000000"},{"mintable":false,"name":"DREP","original_symbol":"DREP","owner":"bnb1ez5s9v4rcgsmhwr4fkrnlv6zwsukjnh4y754kn","symbol":"DREP-7D2","total_supply":"10000000000.00000000"},{"mintable":true,"name":"Dusk Network","original_symbol":"DUSK","owner":"bnb1dfls6c8y39l7qq4gj2479wkehg85pt5m07y94g","symbol":"DUSK-45E","total_supply":"50000000.00000000"},{"mintable":false,"name":"eBoost","original_symbol":"EBST","owner":"bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7","symbol":"EBST-783","total_supply":"80838159.07000000"},{"mintable":true,"name":"Ormeus Ecosystem","original_symbol":"ECO","owner":"bnb1tr49nv08k828n2lqfw0vrgvwj7xtep5kg8wr4c","symbol":"ECO-083","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Energy Eco Token","original_symbol":"EET","owner":"bnb1pt353m8ygvvgy4f2ud9xx85tl7fqewkrksh6r5","symbol":"EET-45C","total_supply":"600000000.00000000"},{"mintable":false,"name":"Hut34 Entropy","original_symbol":"ENTRP","owner":"bnb1wu0hu9pelx3yvplysx0je7d93htcandpj86aev","symbol":"ENTRP-C8D","total_supply":"100000000.00000000"},{"mintable":true,"name":"EOS BEP2","original_symbol":"EOS","owner":"bnb1la8alalwjzkchd67wza3r75lj5rm7m9e85ffqr","symbol":"EOS-CDD","total_supply":"500000.00000000"},{"mintable":true,"name":"3X Short EOS Token","original_symbol":"EOSBEAR","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"EOSBEAR-721","total_supply":"32301.00000000"},{"mintable":true,"name":"3X Long EOS Token","original_symbol":"EOSBULL","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"EOSBULL-F0D","total_supply":"456191.00000000"},{"mintable":false,"name":"EQUAL","original_symbol":"EQL","owner":"bnb1uz0s54rzv022dh66l7atwk83wqcet9qstgg358","symbol":"EQL-586","total_supply":"675259060.00000000"},{"mintable":true,"name":"Elrond","original_symbol":"ERD","owner":"bnb1m5uzzfxs7x05sl28gg96zyecn9jwgtkpyeftyn","symbol":"ERD-D06","total_supply":"13000000000.00000000"},{"mintable":true,"name":"ETH BEP2","original_symbol":"ETH","owner":"bnb1yss2345dphss8c823dh2jzje2w8k8x4jguuxhf","symbol":"ETH-1C9","total_supply":"10000.00000000"},{"mintable":true,"name":"3X Short Ethereum Token","original_symbol":"ETHBEAR","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"ETHBEAR-B2B","total_supply":"61821.00000000"},{"mintable":true,"name":"3X Long Ethereum Token","original_symbol":"ETHBULL","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"ETHBULL-D33","total_supply":"33684.00000000"},{"mintable":true,"name":"everiToken","original_symbol":"EVT","owner":"bnb1v3fl4kuwuhzf3g7ghscsq7uzmu5dw50waseptd","symbol":"EVT-49B","total_supply":"1000000000.00000000"},{"mintable":true,"name":"The Force Token","original_symbol":"FOR","owner":"bnb1c46nhwdwm3u2mlfhx6t07fls25shnvktpr9w9m","symbol":"FOR-997","total_supply":"100000000.00000000"},{"mintable":false,"name":"Ferrum Network Token","original_symbol":"FRM","owner":"bnb1um8ntkgwle8yrdk0yn5hwdf7hckjpyjjg29k2p","symbol":"FRM-DE7","total_supply":"164609374.50000000"},{"mintable":false,"name":"Fusion","original_symbol":"FSN","owner":"bnb17mnutyduat9fe02r2dawp3kn4rnaqamp5kpg0c","symbol":"FSN-E14","total_supply":"57344000.00000000"},{"mintable":true,"name":"Fantom","original_symbol":"FTM","owner":"bnb1f6sxnf3nhn9fcfwkuccrzvl2pgu3sq0m8pyjhw","symbol":"FTM-A64","total_supply":"952500000.00000000"},{"mintable":true,"name":"FTX Token","original_symbol":"FTT","owner":"bnb1msxdh7e7smpg68gxxhs0p3fhuj9tzhrxa4c2x2","symbol":"FTT-F11","total_supply":"10000000.00000000"},{"mintable":true,"name":"Givly Coin","original_symbol":"GIV","owner":"bnb13jzr6sqz72fl0edg2tpqp8tddyzvyt4su2490m","symbol":"GIV-94E","total_supply":"1000000000.00000000"},{"mintable":false,"name":"GoWithMi","original_symbol":"GMAT","owner":"bnb1yltla9mnk8999ygmjjn3kwmmz2zs94a9v20sca","symbol":"GMAT-FC8","total_supply":"14900000000.00000000"},{"mintable":false,"name":"Global Gaming","original_symbol":"GMNG","owner":"bnb1qe6zxqptfxw0kh38t8pg6c3qa527n2x2a87qvm","symbol":"GMNG-F3E","total_supply":"5000000000.00000000"},{"mintable":false,"name":"GTEX","original_symbol":"GTEX","owner":"bnb1nksrzfl24he9xtvdvpypsl6r5jnh5x2uf9s82z","symbol":"GTEX-71B","total_supply":"4000000000.00000000"},{"mintable":false,"name":"Gifto","original_symbol":"GTO","owner":"bnb1lvp8k3zenlfp2pl2nyaf428xjgh385m258gzvq","symbol":"GTO-908","total_supply":"1000000000.00000000"},{"mintable":true,"name":"“Hermes","original_symbol":"HEC","owner":"bnb1dfyydqkmsv5m0rs0pa4uut2gwrcsahppktns2t","symbol":"HEC-1A9","total_supply":"100000000.00000000"},{"mintable":false,"name":"Honest","original_symbol":"HNST","owner":"bnb1k9fv2hz0w3l9v9z4g9samg3gtc7nc2xgyqw5u0","symbol":"HNST-3C9","total_supply":"400000000.00000000"},{"mintable":true,"name":"Hyperion Token","original_symbol":"HYN","owner":"bnb1q5cqecuy2g7syl8fssp9a7v2sjamtrzlr3pa0n","symbol":"HYN-F21","total_supply":"10000000000.00000000"},{"mintable":true,"name":"Rupiah Token","original_symbol":"IDRTB","owner":"bnb1wc44duax6pygh23psx0u945skvs3eh7w59e4sp","symbol":"IDRTB-178","total_supply":"90000000000.00000000"},{"mintable":false,"name":"IKU","original_symbol":"IKU","owner":"bnb1f52tc9l0qg337qtgu4n024ayllc78wxpc5xhvd","symbol":"IKU-416","total_supply":"300000000.00000000"},{"mintable":true,"name":"IRIS Network","original_symbol":"IRIS","owner":"bnb1dcpm0jjj8el8g6ekr3mvjxa8kptgu4e5xzvqv8","symbol":"IRIS-D88","total_supply":"2000000000.00000000"},{"mintable":false,"name":"JDXUCoin","original_symbol":"JDXU","owner":"bnb1dwcsg0t86g7935zpxc054n97styzgdtnu2kzg6","symbol":"JDXU-706","total_supply":"1000000000.00000000"},{"mintable":false,"name":"Kambria Token","original_symbol":"KAT","owner":"bnb1l68n6equtr925lhnentyq54zfrzqyj45lg8uwj","symbol":"KAT-7BB","total_supply":"3700000000.00000000"},{"mintable":true,"name":"Kava BEP2 Token","original_symbol":"KAVA","owner":"bnb1uyekdn62yur9zuctzqyd9ckasfvqttjz9c33me","symbol":"KAVA-10C","total_supply":"271190.72181900"},{"mintable":false,"name":"Sessia Kicks","original_symbol":"KICKS","owner":"bnb130tmwjd3fc79eh6f5ezl2326ur8rqpsxeeq30x","symbol":"KICKS-162","total_supply":"5000000.00000000"},{"mintable":true,"name":"Lambda","original_symbol":"LAMB","owner":"bnb19vnwdjwthm9unxe9hxdxmgm6qw0d42d2lmcesw","symbol":"LAMB-46C","total_supply":"5000000.00000000"},{"mintable":false,"name":"Lend-Borrow-Asset","original_symbol":"LBA","owner":"bnb1m8r74hr532lfwtaf5e88cxeakd36ut0ufpd4yu","symbol":"LBA-340","total_supply":"1000000000.00000000"},{"mintable":true,"name":"LITION","original_symbol":"LIT","owner":"bnb1fhlxwqlwd7cm5fmurg0wmsaalshnp7lwu46nk9","symbol":"LIT-099","total_supply":"145061313.45061312"},{"mintable":true,"name":"Loki","original_symbol":"LOKI","owner":"bnb1j5sft8wp7tktjwauy30x79f3tqa53fycmgxxs0","symbol":"LOKI-6A9","total_supply":"3000000.00000000"},{"mintable":true,"name":"LTC BEP2","original_symbol":"LTC","owner":"bnb1cn4sqm79wqmr8rey923r34cp2wrtyhlr9easpg","symbol":"LTC-F07","total_supply":"18500.00000000"},{"mintable":false,"name":"LTO Network","original_symbol":"LTO","owner":"bnb1ac6p45m00pv36y9mu48e5xr73fyxke3zv2rhmq","symbol":"LTO-BDF","total_supply":"500000000.00000000"},{"mintable":false,"name":"LYFE","original_symbol":"LYFE","owner":"bnb1k0779dltjkl6a05v5uq06zym62hcufzcqu6gq7","symbol":"LYFE-6AB","total_supply":"231250000.00000000"},{"mintable":false,"name":"Matic Token","original_symbol":"MATIC","owner":"bnb1a6nkf3g7c2z0jcrqhp8c9upcwmme0y49qx58nz","symbol":"MATIC-84A","total_supply":"10000000000.00000000"},{"mintable":false,"name":"Moviebloc","original_symbol":"MBL","owner":"bnb17p8rc0z5vlysff2wc7xehff464dm0v7nhl27xq","symbol":"MBL-2D2","total_supply":"30000000000.00000000"},{"mintable":true,"name":"Mcashchain","original_symbol":"MCASH","owner":"bnb1q420q7qpyv7tghfp6aac7vnjq74dhkeutdhqsg","symbol":"MCASH-869","total_supply":"200000000.00000000"},{"mintable":false,"name":"Magic Cube Token","original_symbol":"MCC","owner":"bnb14nt79d6hzhjefkys2cgrc9nrzugdjwwtggfmu4","symbol":"MCC-33B","total_supply":"20000000000.00000000"},{"mintable":false,"name":"MDAB","original_symbol":"MDAB","owner":"bnb1m3edd4q4nd3wxg9vm3xe8pnfnetu5yjmhtnrqz","symbol":"MDAB-D42","total_supply":"1000000000.00000000"}]` + wantedTxsResponseAva = `{"tx":[{"txHash":"2BF49DF1D10D9A20438376E760352734DAEBD5D92D6CAA14735EE095A3F65FD3","blockHeight":105725696,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:41.390Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"47.98467000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":5,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594674","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77721\",\"quantity\":\"27\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594674\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594673},{"txHash":"C858D15E2745A61D0D3D354750E4462792160FFBB9927739587FFAAEDEFA00FF","blockHeight":105725676,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:32.989Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"250.85976000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":13,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594671","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.91496\",\"quantity\":\"131\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594671\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594670},{"txHash":"9BDCF416622AA4E8F11162747614585FD840F5721D7163A68BC03EC94E855DEE","blockHeight":105725673,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:31.760Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"30.17126000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":14,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594670","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77478\",\"quantity\":\"17\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594670\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594669},{"txHash":"52512D9498D4CF51997A5A62C0A55252776B00C888D2D01502C68B56E892F42E","blockHeight":105725652,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:23.040Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"41.48298000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":23,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594667","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.88559\",\"quantity\":\"22\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594667\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594666},{"txHash":"1BAF96AB01E7AB5A7746CA7E76B293CD636D55713C7CCE71FD0E0ED8ACE05C92","blockHeight":105725646,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:20.614Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"26.59905000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":26,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594666","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77327\",\"quantity\":\"15\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594666\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594665},{"txHash":"9990419EFE1B327966EBAAFFC2771046E1AC2E4DDFAD8A93C55DE105A2948A8D","blockHeight":105725624,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:11.499Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"206.81568000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":35,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594663","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.91496\",\"quantity\":\"108\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594663\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594662},{"txHash":"922F86E110E897233A7B43C0D31397923298C176EBE6F33D98B70ACB911A497A","blockHeight":105725620,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:09.679Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"31.95630000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":36,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594662","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77535\",\"quantity\":\"18\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594662\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594661},{"txHash":"925A208AFDCD718F8383F7559C7BBA5AE616B693A6029F57BFB67AEBB1CE5F3C","blockHeight":105725597,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:00.237Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"135.99044000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":46,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594659","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65842\",\"quantity\":\"82\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594659\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594658},{"txHash":"2B69327D6C0C7B9061AAD962BF4838E3B630A844439013E0EBEFC5B722205774","blockHeight":105725575,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:51.165Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"26.39040000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":55,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594656","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.75936\",\"quantity\":\"15\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594656\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594655},{"txHash":"BB6FD86C9738C2991F587996ABBAC1151DF1F9DE57FDCC977BB0D8FBAD31188A","blockHeight":105725529,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:32.108Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"44.90475000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":74,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594654","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79619\",\"quantity\":\"25\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594654\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594653},{"txHash":"97856635BDBA4B0B3EAAA76EA46D848A2DFE3AAE554A33D308CFC4474C769290","blockHeight":105725526,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:30.917Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"94.10225000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":75,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594653","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.71095\",\"quantity\":\"55\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594653\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594652},{"txHash":"4B4EC65A5972CC15C4B410339ED0081C4BB57F4E08F2A35744845F5A71531B59","blockHeight":105725493,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:17.373Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"30.49341000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":89,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594649","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79373\",\"quantity\":\"17\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594649\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594648},{"txHash":"86B5FFDDB06E0973A05434DDB858868A45EDA8B07E0D75125FEAEBA1093D4EA5","blockHeight":105725489,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:15.680Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"195.81982000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":90,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594648","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"118\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594648\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594647},{"txHash":"D20757EB130E8146D1A12E869BE69EC2CB03193D8E62467327B09A5D73BBC6F8","blockHeight":105725473,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:09.086Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"59.27427000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":97,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594646","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79619\",\"quantity\":\"33\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594646\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594645},{"txHash":"04291A7AE08A78C5E5AE216C67D17B6A4260950FFAB6FD3D1C1B991E3B7BB935","blockHeight":105725470,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:07.990Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"242.28554000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":98,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594645","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"146\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594645\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594644},{"txHash":"31E16E3F53DD476475256C8D872AF3FD86DC44F3085EF87DDE3643E20C0CE624","blockHeight":105725448,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:58.857Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"32.30208000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":107,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594642","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79456\",\"quantity\":\"18\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594642\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594641},{"txHash":"1D61A9E35893BB51DE4AE63FA6898FCAE14B6D48F7A2EFD0B51DCCACF6E36B88","blockHeight":105725446,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:57.974Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"227.35013000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":108,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594641","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"137\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594641\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594640},{"txHash":"AB9E29B110844BD76F58B058CC20F1E13B37A1AAC4F09978BDE159F1B09B585E","blockHeight":105725425,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:49.358Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"26.88420000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":117,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594638","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79228\",\"quantity\":\"15\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594638\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594637},{"txHash":"F81649BAF3D888E3772C8708D255FE91E0CDB2818006A1FC96FFBDAC24BDE675","blockHeight":105725422,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:48.006Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"144.37563000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":118,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594637","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"87\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594637\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594636},{"txHash":"71B25BF61219BC87980EB67064C346801C01B00FFE52932799E28FB20DAF41D8","blockHeight":105725401,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:39.380Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"21.47556000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":127,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594634","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.78963\",\"quantity\":\"12\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594634\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594633},{"txHash":"3424BFCA860A878FDCF304AD414EDE2AB3B0FF258CA940CD1269F469ED7C422C","blockHeight":105725379,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:30.336Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"144.92516000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":136,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594631","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.90691\",\"quantity\":\"76\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594631\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594630},{"txHash":"46FFA039B955953D4F19BE7D56FA793B71F34BFB460D9B84A152B554E9219C44","blockHeight":105725375,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:28.671Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"231.90204000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":137,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594630","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.66836\",\"quantity\":\"139\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594630\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594629},{"txHash":"701100D3783744D633FF34A6E211CEB923EA9BCE6D87A64211801E71F71AEE03","blockHeight":105725327,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:09.184Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"92.81678000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":157,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594628","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.89422\",\"quantity\":\"49\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594628\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594627},{"txHash":"B12B30509B45CEFE526DAADDAC6399F902B30418859042D7A23F9A2FB311A6C8","blockHeight":105725323,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:07.404Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"47.87208000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":159,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594627","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77304\",\"quantity\":\"27\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594627\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594626},{"txHash":"933819F35F0F89FB2D58DC50CD15FABB3DA0B817BFCD39A8DDC99DFEC1663F7D","blockHeight":105725301,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:10:58.404Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"181.49465000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":168,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594624","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.91047\",\"quantity\":\"95\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594624\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594623}],"total":11603}` + wantedBlockResponseMulti = `{"blockHeight":105529271,"tx":[{"txHash":"432FF828B1DC1C4DAF13A51B6AE7ADD9932B7FC6526C28F7FE9C905F95472820","blockHeight":105529271,"txType":"CANCEL_ORDER","timeStamp":"2020-08-06T20:38:46.583Z","fromAddr":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","toAddr":null,"value":null,"txAsset":null,"txFee":null,"code":0,"data":"{\"orderData\":{\"orderId\":\"1468EE412C3ADC9CFF3EF31ADC7EDD288F5E208E-11315084\"}}","memo":"","source":0,"sequence":11317170},{"txHash":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","blockHeight":105529271,"txType":"TRANSFER","timeStamp":"2020-08-06T20:38:46.583Z","fromAddr":null,"toAddr":null,"value":null,"txAsset":null,"txFee":null,"code":0,"data":null,"memo":"0","source":1,"sequence":2300,"subTransactions":[{"txHash":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","blockHeight":105529271,"txType":"TRANSFER","fromAddr":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","toAddr":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","txAsset":"BNB","txFee":"0.00060000","value":"0.00000001"},{"txHash":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","blockHeight":105529271,"txType":"TRANSFER","fromAddr":"bnb1t38ccns9var4ac4yj2ylmu99r9ecmggr8ye5e5","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","txAsset":"BNB","txFee":null,"value":"0.39421249"}]}]}` + mockedBlockResponse = `{"blockHeight":104867508,"tx":[{"txHash":"4CD5BAA433BABA63D862141A4A2F9235B0BA5CBAB8114C93A0556ECA4EC7A68A","blockHeight":104867508,"txType":"CANCEL_ORDER","timeStamp":"2020-08-03T16:32:17.963Z","fromAddr":"bnb1l83kstts7lt9dpgawzechnrgjq54dql36dyspc","toAddr":null,"value":null,"txAsset":null,"txFee":null,"code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.94064\",\"quantity\":\"40\",\"timeInForce\":\"GTE\",\"orderId\":\"F9E3682D70F7D656851D70B38BCC6890295683F1-1023254\"}}","memo":"","source":0,"sequence":1023322},{"txHash":"9B87D17581F2AC73D2999EDE56535E50D9D4DB75150A92A90122190F77D47755","blockHeight":104867508,"txType":"TRANSFER","timeStamp":"2020-08-03T16:32:17.963Z","fromAddr":"bnb1c4czpzvn0ttdcpnv3cy2858l2m9frxdfgk4jr0","toAddr":"bnb1g2ukzn702napq3levm54m2z3p2gam7upern9aq","value":"0.24481570","txAsset":"BNB","txFee":"0.00037500","code":0,"data":null,"memo":"","source":0,"sequence":6},{"txHash":"5C0580AC983C1CF36F1656D9E8B062CD0578839BEFC839EFD6720FF315B45EEB","blockHeight":104867508,"txType":"NEW_ORDER","timeStamp":"2020-08-03T16:32:17.963Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"169.20330000","txAsset":"AVA-645","txFee":"0.00000000","orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1509155","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.61146\",\"quantity\":\"105\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1509155\"}}","memo":"","source":0,"sequence":1509154}]}` + mockedNodeInfo = `{"node_info":{"protocol_version":{"p2p":7,"block":10,"app":0},"id":"46ba46d5b6fcb61b7839881a75b081123297f7cf","listen_addr":"10.212.32.84:27146","network":"Binance-Chain-Tigris","version":"0.32.3","channels":"3640202122233038","moniker":"Ararat","other":{"tx_index":"on","rpc_address":"tcp://0.0.0.0:27147"}},"sync_info":{"latest_block_hash":"507BB016F306906569F12883617A4231AB51DAF5FA5004C8F70B17CDF73A8B40","latest_app_hash":"A96FA3DB1FAC12D325845FFEE679EC52CB944BE4B343BC016CE4707FA63EE2BE","latest_block_height":104867535,"latest_block_time":"2020-08-03T16:32:29.834625465Z","catching_up":false},"validator_info":{"address":"B7707D9F593C62E85BB9E1A2366D12A97CD5DFF2","pub_key":[113,242,215,184,236,28,139,153,166,83,66,155,1,24,205,32,31,121,79,64,157,15,234,77,101,177,182,98,242,176,0,99],"voting_power":1000000000000}}` +) + +func createMockedAPI() http.Handler { + r := http.NewServeMux() + + r.HandleFunc("/v1/node-info", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedNodeInfo); err != nil { + panic(err) + } + }) + + r.HandleFunc("/v2/transactions-in-block/104867508", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, mockedBlockResponse); err != nil { + panic(err) + } + }) + + r.HandleFunc("/v2/transactions-in-block/105529271", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, wantedBlockResponseMulti); err != nil { + panic(err) + } + }) + + r.HandleFunc("/v1/tokens", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, wantedTokensResponse); err != nil { + panic(err) + } + }) + + r.HandleFunc("/v1/account/bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, wantedAccountMetaResponse); err != nil { + panic(err) + } + }) + + r.HandleFunc("/v1/transactions", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + var ( + address = r.URL.Query().Get("address") + txAsset = r.URL.Query().Get("txAsset") + + response string + ) + + switch { + case address == "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" && txAsset == "BNB": + response = wantedTxsResponse + case address == "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg" && txAsset == "AVA-645": + response = wantedTxsResponseAva + default: + response = "" + } + + if _, err := fmt.Fprint(w, response); err != nil { + panic(err) + } + }) + + return r +} diff --git a/platform/binance/block.go b/platform/binance/block.go index be0beb46b..49492b2c4 100644 --- a/platform/binance/block.go +++ b/platform/binance/block.go @@ -2,74 +2,21 @@ package binance import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" - "time" ) func (p *Platform) CurrentBlockNumber() (int64, error) { - info, err := p.rpcClient.fetchNodeInfo() + block, err := p.client.FetchLatestBlockNumber() if err != nil { return 0, err } - - return info.SyncInfo.LatestBlockHeight, nil + return block, nil } func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - blockTransactions, err := p.rpcClient.fetchBlockTransactions(num) + transactionInBlockResponse, err := p.client.FetchTransactionsInBlock(num) if err != nil { return nil, err } - - explorerTransactions := make([]ExplorerTxs, 0, len(blockTransactions)) - for _, tx := range blockTransactions { - explorerTransactions = append(explorerTransactions, normalizeTxsToExplorer(tx)) - } - - var normalizedTxs []blockatlas.Tx - for _, tx := range explorerTransactions { - normalizedTx := normalizeTx(tx, "") - if normalizedTx == nil { - continue - } - normalizedTxs = append(normalizedTxs, normalizedTx...) - } - - return &blockatlas.Block{Number: num, Txs: normalizedTxs}, nil -} - -func normalizeTxsToExplorer(txV2 TxV2) ExplorerTxs { - tx := ExplorerTxs{ - TxAsset: txV2.Asset, - Code: txV2.Code, - FromAddr: txV2.FromAddr, - TxHash: txV2.TxHash, - Memo: txV2.Memo, - ToAddr: txV2.ToAddr, - TxType: txV2.Type, - BlockHeight: txV2.BlockHeight, - } - - if value, err := numbers.StringNumberToFloat64(txV2.Value); err == nil { - tx.Value = value - } - if txV2.Fee == "" && len(txV2.SubTransactions) > 1 { - txV2.Fee = txV2.SubTransactions[0].Fee - } - if fee, err := numbers.StringNumberToFloat64(txV2.Fee); err == nil { - tx.TxFee = fee - } - if len(txV2.SubTransactions) > 0 { - tx.HasChildren = 1 - } - if t, err := time.Parse(time.RFC3339, txV2.Timestamp); err == nil { - tx.Timestamp = t.Unix() * 1000 - } - - mts := make([]MultiTransfer, len(txV2.SubTransactions)) - for i, st := range txV2.SubTransactions { - mts[i] = MultiTransfer{Amount: st.Value, Asset: st.Asset, From: st.FromAddr, To: st.ToAddr} - } - tx.MultisendTransfers = mts - return tx + block := normalizeBlock(transactionInBlockResponse) + return &block, nil } diff --git a/platform/binance/block_test.go b/platform/binance/block_test.go index d2c05383c..02f12fc54 100644 --- a/platform/binance/block_test.go +++ b/platform/binance/block_test.go @@ -3,122 +3,32 @@ package binance import ( "encoding/json" "github.com/stretchr/testify/assert" + "net/http/httptest" "testing" ) -const ( - bnbSingleTransfer = ` -{ - "blockHeight": 84191216, - "tx": [ - { - "txHash": "4577CB3B5B202696E9E0B093A6DA973C7DD9CBC6808DA1326872745C35F3C089", - "blockHeight": 84191216, - "txType": "TRANSFER", - "timeStamp": "2020-04-28T15:05:57.686Z", - "fromAddr": "bnb1mr5f97rx5wnkfcakx9fcpvljmx2s6kwqc08yur", - "toAddr": "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", - "value": "0.00040000", - "txAsset": "BNB", - "txFee": "0.00037500", - "code": 0, - "data": null, - "memo": "", - "source": 0, - "sequence": 95 - } - ] -}` - bep2MultiTransfer = ` -{ - "blockHeight": 80167666, - "tx": [ - { - "txHash": "FAD8C1C5E450BE5E0913B12007AAEACC307F8CFFAFFB0844A9F83155E1235C25", - "blockHeight": 80167666, - "txType": "TRANSFER", - "timeStamp": "2020-04-09T20:34:12.922Z", - "fromAddr": null, - "toAddr": null, - "value": null, - "txAsset": null, - "txFee": null, - "code": 0, - "data": null, - "memo": "multisend", - "source": 1, - "sequence": 72, - "subTransactions": [ - { - "txHash": "FAD8C1C5E450BE5E0913B12007AAEACC307F8CFFAFFB0844A9F83155E1235C25", - "blockHeight": 80167666, - "txType": "TRANSFER", - "fromAddr": "bnb1ds83nt2tz2s9m7kkdcu53t3ccjc07un4xvdld7", - "toAddr": "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", - "txAsset": "TWT-8C2", - "txFee": "0.29970000", - "value": "2800.00000000" - } - ] - } - ] +func TestPlatform_CurrentBlockNumber(t *testing.T) { + server := httptest.NewServer(createMockedAPI()) + defer server.Close() + p := Init(server.URL) + number, err := p.CurrentBlockNumber() + assert.Nil(t, err) + assert.Equal(t, int64(104867535), number) } -` -) - -var ( - expectBnbSingleRPCV2TransferResponse = ExplorerTxs{ - BlockHeight: 84191216, - Code: 0, - FromAddr: "bnb1mr5f97rx5wnkfcakx9fcpvljmx2s6kwqc08yur", - HasChildren: 0, - Memo: "", - MultisendTransfers: []MultiTransfer{}, - Timestamp: 1588086357000, - ToAddr: "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl", - TxFee: 0.000375, - TxHash: "4577CB3B5B202696E9E0B093A6DA973C7DD9CBC6808DA1326872745C35F3C089", - TxType: "TRANSFER", - Value: 0.0004, - TxAsset: "BNB", - } - - expectBEP2MultiRPCV2TransferResponse = ExplorerTxs{ - BlockHeight: 80167666, - Code: 0, - HasChildren: 1, - Memo: "multisend", - MultisendTransfers: bep2MultisendTransfer, - Timestamp: 1586464452000, - TxHash: "FAD8C1C5E450BE5E0913B12007AAEACC307F8CFFAFFB0844A9F83155E1235C25", - TxType: "TRANSFER", - Value: 0, - } - - sender = "bnb1ds83nt2tz2s9m7kkdcu53t3ccjc07un4xvdld7" - receiver = "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl" - - bep2MultisendTransfer = []MultiTransfer{ - {Amount: "2800.00000000", Asset: "TWT-8C2", From: sender, To: receiver}, - } -) - -func Test_normalizeBlockSubTx(t *testing.T) { - tests := []struct { - name string - V2Response string - expected ExplorerTxs - }{ - {name: "Normalize single BNB transfer", V2Response: bnbSingleTransfer, expected: expectBnbSingleRPCV2TransferResponse}, - {name: "Normalize multiple BEP2 transfer", V2Response: bep2MultiTransfer, expected: expectBEP2MultiRPCV2TransferResponse}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var blockTxs BlockTransactions - err := json.Unmarshal([]byte(tt.V2Response), &blockTxs) - assert.Nil(t, err) - assert.Equal(t, tt.expected, normalizeTxsToExplorer(blockTxs.Txs[0]), "tx don't equal") - }) - } +func TestPlatform_GetBlockByNumber(t *testing.T) { + server := httptest.NewServer(createMockedAPI()) + defer server.Close() + p := Init(server.URL) + block, err := p.GetBlockByNumber(104867508) + assert.Nil(t, err) + res, err := json.Marshal(block) + assert.Nil(t, err) + assert.Equal(t, wantedBlock, string(res)) + + blockMulti, err := p.GetBlockByNumber(105529271) + assert.Nil(t, err) + resMulti, err := json.Marshal(blockMulti) + assert.Nil(t, err) + assert.Equal(t, wantedBlockMulti, string(resMulti)) } diff --git a/platform/binance/client.go b/platform/binance/client.go index b920034f0..b2a1792ca 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -1,71 +1,100 @@ package binance import ( - "encoding/json" "fmt" + "github.com/imroc/req" + "github.com/patrickmn/go-cache" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" - "net/http" "net/url" + "strconv" "time" ) type Client struct { - blockatlas.Request + *cache.Cache + url string } -const tokensLimit = "1000" - -func (c *Client) fetchNodeInfo() (*NodeInfo, error) { - result := new(NodeInfo) - err := c.Get(result, "v1/node-info", nil) - return result, err -} - -func (c *Client) fetchBlockTransactions(num int64) ([]TxV2, error) { - stx := new(BlockTransactions) - err := c.Get(stx, fmt.Sprintf("v2/transactions-in-block/%d", num), nil) - return stx.Txs, err +func InitClient(url string) Client { + return Client{url: url, Cache: cache.New(5*time.Minute, 10*time.Minute)} } -func (c *Client) fetchAccountMetadata(address string) (*Account, error) { - var result Account - err := c.Get(&result, fmt.Sprintf("v1/account/%s", address), nil) - return &result, err +func (c Client) FetchLatestBlockNumber() (int64, error) { + resp, err := req.Get(c.url+"/v1/node-info", nil) + if err != nil { + return 0, err + } + var result NodeInfoResponse + if err := resp.ToJSON(&result); err != nil { + logger.Error("URL: " + resp.Request().URL.String()) + logger.Error("Status code: " + resp.Response().Status) + return 0, err + } + return int64(result.SyncInfo.LatestBlockHeight), nil } -func (c *Client) fetchTokens() (*TokenList, error) { - stp := new(TokenList) - query := url.Values{"limit": {tokensLimit}} - err := c.GetWithCache(stp, "v1/tokens", query, time.Minute*1) - return stp, err +func (c Client) FetchTransactionsInBlock(blockNumber int64) (TransactionsInBlockResponse, error) { + resp, err := req.Get(c.url+fmt.Sprintf("/v2/transactions-in-block/%d", blockNumber), nil) + if err != nil { + return TransactionsInBlockResponse{}, err + } + var result TransactionsInBlockResponse + if err := resp.ToJSON(&result); err != nil { + logger.Error("URL: " + resp.Request().URL.String()) + logger.Error("Status code: " + resp.Response().Status) + return TransactionsInBlockResponse{}, err + } + return result, nil } -func (c *Client) fetchTransactionHash(hash string) (*TxHashRPC, error) { - var result TxHashRPC - err := c.Get(&result, fmt.Sprintf("v1/tx/%s", hash), url.Values{"format": {"json"}}) - return &result, err +func (c Client) FetchTransactionsByAddressAndTokenID(address, tokenID string) ([]Tx, error) { + startTime := strconv.Itoa(int(time.Now().AddDate(0, -3, 0).Unix() * 1000)) + limit := strconv.Itoa(blockatlas.TxPerPage) + params := url.Values{"address": {address}, "txAsset": {tokenID}, "startTime": {startTime}, "limit": {limit}} + resp, err := req.Get(c.url+"/v1/transactions", params) + if err != nil { + return nil, err + } + var result TransactionsInBlockResponse + if err := resp.ToJSON(&result); err != nil { + logger.Error("URL: " + resp.Request().URL.String()) + logger.Error("Status code: " + resp.Response().Status) + return nil, err + } + return result.Tx, nil } -func handleHTTPError(res *http.Response, desc string) error { - switch res.StatusCode { - case http.StatusBadRequest: - return handleAPIError(res, desc) - case http.StatusNotFound: - return blockatlas.ErrNotFound - case http.StatusOK: - return nil - default: - return errors.E("handleHTTPError error", errors.Params{"status": res.Status}) +func (c Client) FetchAccountMeta(address string) (AccountMeta, error) { + resp, err := req.Get(c.url+fmt.Sprintf("/v1/account/%s", address), nil) + if err != nil { + return AccountMeta{}, err + } + var result AccountMeta + if err := resp.ToJSON(&result); err != nil { + logger.Error("URL: " + resp.Request().URL.String()) + logger.Error("Status code: " + resp.Response().Status) + return AccountMeta{}, err } + return result, nil } -func handleAPIError(res *http.Response, desc string) error { - var e Error - if json.NewDecoder(res.Body).Decode(&e) == nil && e.Message == "address is not valid" { - return blockatlas.ErrInvalidAddr +func (c Client) FetchTokens() (Tokens, error) { + cachedResult, ok := c.Cache.Get("tokens") + if ok { + return cachedResult.(Tokens), nil + } + result := new(Tokens) + query := url.Values{"limit": {tokensLimit}} + resp, err := req.Get(c.url+"/v1/tokens", query) + if err != nil { + return nil, err + } + if err := resp.ToJSON(&result); err != nil { + logger.Error("URL: " + resp.Request().URL.String()) + logger.Error("Status code: " + resp.Response().Status) + return nil, err } - logger.Error(desc, logger.Params{"status": res.StatusCode, "code": e.Code, "message": e.Message}) - return blockatlas.ErrSourceConn + c.Cache.Set("tokens", *result, cache.DefaultExpiration) + return *result, nil } diff --git a/platform/binance/explorer_client.go b/platform/binance/explorer_client.go deleted file mode 100644 index 1c9bce492..000000000 --- a/platform/binance/explorer_client.go +++ /dev/null @@ -1,32 +0,0 @@ -package binance - -import ( - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "net/url" -) - -type ExplorerClient struct { - blockatlas.Request -} - -const ( - explorerRows = "25" - explorerPage = "1" -) - -func (c *ExplorerClient) getTxsOfAddress(address, token string) (ExplorerResponse, error) { - result := new(ExplorerResponse) - if token == "" { - token = coin.Binance().Symbol - } - query := url.Values{ - "address": {address}, - "rows": {explorerRows}, - "page": {explorerPage}, - "txType": {string(TxTransfer)}, - "txAsset": {token}, - } - err := c.Get(result, "v1/txs", query) - return *result, err -} diff --git a/platform/binance/model.go b/platform/binance/model.go index 1a350fd35..68cbdb157 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -1,97 +1,98 @@ package binance import ( - "fmt" + "encoding/json" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" "strconv" + "strings" + "time" ) const ( - TxTransfer TxType = "TRANSFER" // e.g: BNB, TWT-8C2 - SingleTransferOperation ExplorerTransactionType = "singleTransfer" // e.g: BNB, TWT-8C2 - MultiTransferOperation ExplorerTransactionType = "multiTransfer" // e.g [BNB, BNB], [TWT-8C2, TWT-8C2] + NewOrder TxType = "NEW_ORDER" + CancelOrder TxType = "CANCEL_ORDER" + Transfer TxType = "TRANSFER" ) -type ( - TxType string - ExplorerTransactionType string - - Account struct { - AccountNumber int `json:"account_number"` - Address string `json:"address"` - Balances []Balance `json:"balances"` - PublicKey []byte `json:"public_key"` - Sequence uint64 `json:"sequence"` - } - - Balance struct { - Free string `json:"free"` - Frozen string `json:"frozen"` - Locked string `json:"locked"` - Symbol string `json:"symbol"` - } - - Error struct { - Code int64 `json:"code"` - Message string `json:"message"` - } +const ( + BNBAsset = "BNB" + tokensLimit = "1000" +) - NodeInfo struct { - SyncInfo SyncInfo `json:"sync_info"` +type ( + NodeInfoResponse struct { + SyncInfo struct { + LatestBlockHeight int `json:"latest_block_height"` + } `json:"sync_info"` } - SyncInfo struct { - LatestBlockHeight int64 `json:"latest_block_height"` - } + TxType string - Transactions struct { - Total int `json:"total"` - Txs []Tx `json:"tx"` + TransactionsInBlockResponse struct { + BlockHeight int `json:"blockHeight"` + Tx []Tx `json:"tx"` } Tx struct { - Asset string `json:"txAsset"` - BlockHeight uint64 `json:"blockHeight"` - Code int `json:"code"` - Data string `json:"data"` - Fee string `json:"txFee"` + TxHash string `json:"txHash"` + BlockHeight int `json:"blockHeight"` + TxType TxType `json:"txType"` + TimeStamp time.Time `json:"timeStamp"` + FromAddr interface{} `json:"fromAddr"` + ToAddr interface{} `json:"toAddr"` + Value string `json:"value"` + TxAsset string `json:"txAsset"` + TxFee string `json:"txFee"` + OrderID string `json:"orderId,omitempty"` + Code int `json:"code"` + Data string `json:"data"` + Memo string `json:"memo"` + Source int `json:"source"` + SubTransactions []SubTransactions `json:"subTransactions,omitempty"` + Sequence int `json:"sequence"` + } + + TransactionData struct { + OrderData struct { + Symbol string `json:"symbol"` + OrderType string `json:"orderType"` + Side string `json:"side"` + Price string `json:"price"` + Quantity string `json:"quantity"` + TimeInForce string `json:"timeInForce"` + OrderID string `json:"orderId"` + } `json:"orderData"` + } + + SubTransactions struct { + TxHash string `json:"txHash"` + BlockHeight int `json:"blockHeight"` + TxType string `json:"txType"` FromAddr string `json:"fromAddr"` - Memo string `json:"memo"` - OrderID string `json:"orderId"` - Sequence uint64 `json:"sequence"` - Source int `json:"source"` - Timestamp string `json:"timeStamp"` ToAddr string `json:"toAddr"` - TxHash string `json:"txHash"` - Type TxType `json:"txType"` + TxAsset string `json:"txAsset"` + TxFee string `json:"txFee"` Value string `json:"value"` } - BlockTransactions struct { - BlockHeight int64 `json:"blockHeight"` - Txs []TxV2 `json:"tx"` + TransactionsByAddressAndAssetResponse struct { + Txs []Tx `json:"tx"` } - TxV2 struct { - Tx - OrderID string `json:"orderId"` // Optional. Available when the transaction type is NEW_ORDER - SubTransactions []SubTx `json:"subTransactions"` // Optional. Available when the transaction has sub-transactions, such as multi-send transaction or a transaction have multiple assets + AccountMeta struct { + Balances []TokenBalance `json:"balances"` } - SubTx struct { - Asset string `json:"txAsset"` - Height uint64 `json:"blockHeight"` - Fee string `json:"txFee"` - FromAddr string `json:"fromAddr"` - Hash string `json:"txHash"` - ToAddr string `json:"toAddr"` - Type TxType `json:"txType"` - Value string `json:"value"` + TokenBalance struct { + Free string `json:"free"` + Frozen string `json:"frozen"` + Locked string `json:"locked"` + Symbol string `json:"symbol"` } - TokenList []Token + Tokens []Token Token struct { Name string `json:"name"` @@ -100,159 +101,219 @@ type ( Symbol string `json:"symbol"` TotalSupply string `json:"total_supply"` } +) - // Transaction response from Explorer - ExplorerResponse struct { - Nums int `json:"txNums"` - Txs []ExplorerTxs `json:"txArray"` - } - - ExplorerTxs struct { - BlockHeight uint64 `json:"blockHeight"` - Code int `json:"code"` - FromAddr string `json:"fromAddr"` - HasChildren int `json:"hasChildren"` - Memo string `json:"memo"` - MultisendTransfers []MultiTransfer `json:"subTxsDto"` // Not part of response, added from hash info tx for simplifying logic - Timestamp int64 `json:"timeStamp"` - ToAddr string `json:"toAddr"` - TxFee float64 `json:"txFee"` - TxHash string `json:"txHash"` - TxType TxType `json:"txType"` - Value float64 `json:"value"` - TxAsset string `json:"txAsset"` - } - - TxHashRPC struct { - Hash string `json:"hash"` - Tx TxHashTx `json:"tx"` - } - - TxHashTx struct { - Value Value `json:"value"` - } - - Value struct { - Msg []Msg `json:"msg"` +func normalizeBlock(response TransactionsInBlockResponse) blockatlas.Block { + result := blockatlas.Block{ + Number: int64(response.BlockHeight), } + result.Txs = normalizeTransactions(response.Tx) + return result +} - Msg struct { - Value MsgValue `json:"value"` +func normalizeTransactions(txs []Tx) []blockatlas.Tx { + totalTxs := make([]blockatlas.Tx, 0, len(txs)) + for _, t := range txs { + var txs []blockatlas.Tx + switch t.TxType { + case CancelOrder, NewOrder: + txs = append(txs, normalizeOrderTransaction(t)) + case Transfer: + if len(t.SubTransactions) > 0 { + txs = normalizeMultiTransferTransaction(t) + } else { + txs = append(txs, normalizeTransferTransaction(t)) + } + } + totalTxs = append(totalTxs, txs...) } + return totalTxs +} - MsgValue struct { - Inputs []Input `json:"inputs"` - Outputs []Output `json:"outputs"` +func normalizeTransferTransaction(t Tx) blockatlas.Tx { + tx := normalizeBaseOfTransaction(t) + tx.To = t.ToAddr.(string) + tx.From = t.FromAddr.(string) + switch { + case t.TxAsset == BNBAsset: + tx.Type = blockatlas.TxTransfer + tx.Meta = blockatlas.Transfer{ + Value: normalizeAmount(t.Value), + Symbol: coin.Binance().Symbol, + Decimals: coin.Binance().Decimals, + } + case t.TxAsset != "": + tx.Type = blockatlas.TxNativeTokenTransfer + tx.Meta = blockatlas.NativeTokenTransfer{ + Decimals: coin.Binance().Decimals, + From: t.FromAddr.(string), + Symbol: getTokenSymbolFromID(t.TxAsset), + To: t.ToAddr.(string), + TokenID: t.TxAsset, + Value: normalizeAmount(t.Value), + } } + return tx +} - Input struct { - Address string `json:"address"` +func normalizeMultiTransferTransaction(t Tx) []blockatlas.Tx { + txs := make([]blockatlas.Tx, 0, len(t.SubTransactions)) + for _, subTx := range t.SubTransactions { + tx := blockatlas.Tx{ + ID: subTx.TxHash, + Coin: coin.Binance().ID, + From: subTx.FromAddr, + To: subTx.ToAddr, + Fee: normalizeFee(subTx.TxFee), + Date: t.TimeStamp.Unix(), + Block: uint64(t.BlockHeight), + Status: blockatlas.StatusCompleted, + Sequence: uint64(t.Sequence), + Memo: t.Memo, + } + switch { + case subTx.TxAsset == BNBAsset: + tx.Type = blockatlas.TxTransfer + tx.Meta = blockatlas.Transfer{ + Value: normalizeAmount(subTx.Value), + Symbol: coin.Binance().Symbol, + Decimals: coin.Binance().Decimals, + } + case subTx.TxAsset != "": + tx.Type = blockatlas.TxNativeTokenTransfer + tx.Meta = blockatlas.NativeTokenTransfer{ + Decimals: coin.Binance().Decimals, + From: subTx.FromAddr, + Symbol: getTokenSymbolFromID(subTx.TxAsset), + To: subTx.ToAddr, + TokenID: subTx.TxAsset, + Value: normalizeAmount(subTx.Value), + } + default: + continue + } + txs = append(txs, tx) } + return txs +} - Output struct { - Address string `json:"address"` - Coins []Coins `json:"coins"` - } - Coins struct { - Amount string `json:"amount"` - Denom string `json:"denom"` +func normalizeBaseOfTransaction(t Tx) blockatlas.Tx { + return blockatlas.Tx{ + ID: t.TxHash, + Coin: coin.Binance().ID, + From: t.FromAddr.(string), + Fee: normalizeFee(t.TxFee), + Date: t.TimeStamp.Unix(), + Block: uint64(t.BlockHeight), + Status: blockatlas.StatusCompleted, + Sequence: uint64(t.Sequence), + Memo: t.Memo, } +} - MultiTransfer struct { - Amount string `json:"amount"` // Float string ind decimal point - Asset string `json:"asset"` - From string `json:"from"` - To string `json:"to"` - } -) +func normalizeOrderTransaction(t Tx) blockatlas.Tx { + tx := normalizeBaseOfTransaction(t) + tx.Type = blockatlas.TxAnyAction + meta := blockatlas.AnyAction{ + Coin: coin.Binance().ID, + Decimals: coin.Binance().Decimals, + } + + data, err := getTransactionData(t.Data) + if err == nil { + base, _ := getTokenIDsFromPair(data.OrderData.Symbol) + meta.TokenID = base + meta.Value = blockatlas.Amount(numbers.FromDecimalExp(data.OrderData.Quantity, int(coin.Binance().Decimals))) + meta.Name = data.OrderData.Side + meta.Symbol = getTokenSymbolFromID(base) + } + switch t.TxType { + case CancelOrder: + meta.Title = blockatlas.KeyTitleCancelOrder + meta.Key = blockatlas.KeyCancelOrder + meta.Value = "0" + case NewOrder: + meta.Title = blockatlas.KeyTitlePlaceOrder + meta.Key = blockatlas.KeyPlaceOrder + } + + tx.Meta = meta + tx.Direction = blockatlas.DirectionOutgoing + return tx +} -func extractMultiTransfers(messages Value) []MultiTransfer { - var extracted = make([]MultiTransfer, 0) - for _, msg := range messages.Msg { - var tr MultiTransfer - tr.From = msg.Value.Inputs[0].Address // Assumed multisend transfer has one input, never seen multiple - for _, output := range msg.Value.Outputs { - tr.To = output.Address - for _, c := range output.Coins { - tr.Amount = c.Amount - tr.Asset = c.Denom - extracted = append(extracted, tr) - } +func normalizeTokens(srcBalance []TokenBalance, tokens Tokens) []blockatlas.Token { + tokensList := make([]blockatlas.Token, 0, len(srcBalance)) + for _, srcToken := range srcBalance { + token, ok := normalizeToken(srcToken, tokens) + if !ok { + continue } + tokensList = append(tokensList, token) } - return extracted + return tokensList } -// Get explorer transfer fee converted to decimal expression -func (tx *Tx) getFee() string { - if _, err := strconv.ParseFloat(tx.Fee, 64); err == nil { - return numbers.DecimalExp(tx.Fee, int(coin.Binance().Decimals)) +func normalizeToken(srcToken TokenBalance, tokens Tokens) (blockatlas.Token, bool) { + var result blockatlas.Token + if srcToken.isAllZeroBalance() { + return result, false } - return "0" -} -// Converts explorer transfer fee to amount in decimal expression -func (tx *ExplorerTxs) getDexFee() blockatlas.Amount { - if tx.TxFee > 0 { - return blockatlas.Amount(numbers.DecimalExp(numbers.Float64toString(tx.TxFee), int(coin.Binance().Decimals))) - } else { - return blockatlas.Amount(0) + token, ok := tokens.findTokenBySymbol(srcToken.Symbol) + if !ok { + return result, false } -} -// Get Explorer transfer status based on transfer code -func (tx *ExplorerTxs) getStatus() blockatlas.Status { - switch tx.Code { - case 0: - return blockatlas.StatusCompleted - default: - return blockatlas.StatusError + result = blockatlas.Token{ + Name: token.Name, + Symbol: token.OriginalSymbol, + TokenID: token.Symbol, + Coin: coin.Binance().ID, + Decimals: coin.Binance().Decimals, + Type: blockatlas.TokenTypeBEP2, } + + return result, true } -func (tx *ExplorerTxs) getDexValue() blockatlas.Amount { - val := numbers.DecimalExp(numbers.Float64toString(tx.Value), int(coin.Binance().Decimals)) - return blockatlas.Amount(val) +func getTransactionData(rawOrderData string) (TransactionData, error) { + var result TransactionData + err := json.Unmarshal([]byte(rawOrderData), &result) + return result, err } -// Determines transaction status -func (tx *Tx) getStatus() blockatlas.Status { - switch tx.Code { - case 0: - return blockatlas.StatusCompleted - default: - return blockatlas.StatusError +func getTokenIDsFromPair(pair string) (string, string) { + result := strings.Split(pair, "_") + if len(result) == 1 || len(result) == 0 { + return pair, pair } + return result[0], result[1] } -// Get explorer transfer error message if transaction failed -func (tx *ExplorerTxs) getError() string { - switch tx.getStatus() { - case blockatlas.StatusCompleted: - return "" - default: - return "error" +func getTokenSymbolFromID(tokenID string) string { + s := strings.Split(tokenID, "-") + if len(s) > 1 { + return s[0] } + return tokenID } -func (tx *Tx) containAddress(address string) bool { - if len(address) == 0 || tx.FromAddr == address || tx.ToAddr == address { - return true - } - return false +func normalizeAmount(amount string) blockatlas.Amount { + val := numbers.DecimalExp(amount, int(coin.Binance().Decimals)) + return blockatlas.Amount(val) } -// findToken find a token into a token list -func (page TokenList) findToken(symbol string) *Token { - for _, t := range page { - if t.Symbol == symbol { - return &t - } +func normalizeFee(amount string) blockatlas.Amount { + a, err := numbers.StringNumberToFloat64(amount) + if a != 0 && err == nil { + return blockatlas.Amount(numbers.DecimalExp(amount, int(coin.Binance().Decimals))) + } else { + return "0" } - return nil } -func (balance *Balance) isAllZeroBalance() bool { +func (balance TokenBalance) isAllZeroBalance() bool { balances := [3]string{balance.Frozen, balance.Free, balance.Locked} for _, value := range balances { value, err := strconv.ParseFloat(value, 64) @@ -263,33 +324,11 @@ func (balance *Balance) isAllZeroBalance() bool { return true } -func (e *Error) Error() string { - return fmt.Sprintf("%d: %s", e.Code, e.Message) -} - -// Determines Explorer transaction direction relatively to address -func (tx *ExplorerTxs) getDirection(address string) blockatlas.Direction { - if address == "" { - return "" - } - - if tx.FromAddr == address && tx.ToAddr == address { - return blockatlas.DirectionSelf - } - if tx.FromAddr == address && tx.ToAddr != address { - return blockatlas.DirectionOutgoing - } - - return blockatlas.DirectionIncoming -} - -// Determines Explorer transaction type -func (tx *ExplorerTxs) getTransactionType() ExplorerTransactionType { - var txType ExplorerTransactionType - if tx.HasChildren == 1 { - txType = MultiTransferOperation - } else { - txType = SingleTransferOperation +func (page Tokens) findTokenBySymbol(symbol string) (Token, bool) { + for _, t := range page { + if t.Symbol == symbol { + return t, true + } } - return txType + return Token{}, false } diff --git a/platform/binance/model_test.go b/platform/binance/model_test.go index 36b61f149..8073699da 100644 --- a/platform/binance/model_test.go +++ b/platform/binance/model_test.go @@ -1,34 +1,28 @@ package binance -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "strconv" - "testing" -) +import "testing" func Test_isZeroBalance(t *testing.T) { type testZeroStruct struct { name string - balance Balance + balance TokenBalance want bool } - // all combinations of 3 variables with 2 possible value 0 or 1 is 2^3 = 8 tests := []testZeroStruct{ - {"1", Balance{"0.00000000", "0.00000000", "0.00000000", "BNB"}, true}, - {"2", Balance{"0.00000000", "0", "0.00000001", "BNB"}, false}, - {"3", Balance{"0.00000000", "0.00000001", "0.00000000", "BNB"}, false}, - {"4", Balance{"0.00000000", "0.00000001", "0.00000001", "BNB"}, false}, - {"5", Balance{"0.00000001", "0.00000000", "0.00000000", "BNB"}, false}, - {"6", Balance{"0.00000001", "0.00000000", "0.00000001", "BNB"}, false}, - {"7", Balance{"0.00000001", "0.00000001", "0.00000000", "BNB"}, false}, - {"8", Balance{"0.00000001", "0.00000001", "0.00000001", "BNB"}, false}, - {"Negative", Balance{"-0.00000001", "0.00000001", "0.00000001", "BNB"}, false}, - {"Bad others are 0", Balance{"f", "0.0000000", "0.0000000", "BNB"}, false}, - {"Bad others are not 0", Balance{"f", "0.0000001", "0.0000000", "BNB"}, false}, - {"Empty others are not 0", Balance{"", "0.00000001", "0.00000001", "BNB"}, false}, - {"Empty others are 0", Balance{"", "0.00000000", "0.00000000", "BNB"}, false}, - {"Big", Balance{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999" + + {"1", TokenBalance{"0.00000000", "0.00000000", "0.00000000", "BNB"}, true}, + {"2", TokenBalance{"0.00000000", "0", "0.00000001", "BNB"}, false}, + {"3", TokenBalance{"0.00000000", "0.00000001", "0.00000000", "BNB"}, false}, + {"4", TokenBalance{"0.00000000", "0.00000001", "0.00000001", "BNB"}, false}, + {"5", TokenBalance{"0.00000001", "0.00000000", "0.00000000", "BNB"}, false}, + {"6", TokenBalance{"0.00000001", "0.00000000", "0.00000001", "BNB"}, false}, + {"7", TokenBalance{"0.00000001", "0.00000001", "0.00000000", "BNB"}, false}, + {"8", TokenBalance{"0.00000001", "0.00000001", "0.00000001", "BNB"}, false}, + {"Negative", TokenBalance{"-0.00000001", "0.00000001", "0.00000001", "BNB"}, false}, + {"Bad others are 0", TokenBalance{"f", "0.0000000", "0.0000000", "BNB"}, false}, + {"Bad others are not 0", TokenBalance{"f", "0.0000001", "0.0000000", "BNB"}, false}, + {"Empty others are not 0", TokenBalance{"", "0.00000001", "0.00000001", "BNB"}, false}, + {"Empty others are 0", TokenBalance{"", "0.00000000", "0.00000000", "BNB"}, false}, + {"Big", TokenBalance{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999" + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + @@ -55,194 +49,3 @@ func Test_isZeroBalance(t *testing.T) { }) } } - -// - -func TestTx_containAddress(t *testing.T) { - type fields struct { - FromAddr string - ToAddr string - } - tests := []struct { - name string - fields fields - address string - want bool - }{ - {"test from address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", true}, - {"test to address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", true}, - {"test no address valid", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "tbnb1qxm48ndhmh7su0r7zgwmwkltuqgly57jdf8yf8", false}, - {"test empty address", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "", true}, - {"test empty address without from", fields{FromAddr: "", ToAddr: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn"}, "", true}, - {"test empty address without to", fields{FromAddr: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", ToAddr: ""}, "", true}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tx := &Tx{ - FromAddr: tt.fields.FromAddr, - ToAddr: tt.fields.ToAddr, - } - if got := tx.containAddress(tt.address); got != tt.want { - t.Errorf("containAddress() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_getFee(t *testing.T) { - tests := []struct { - name string - fee string - want string - }{ - {"test empty", "", "0"}, - {"test error", "test", "0"}, - {"test float 1", "444.5", "44450000000"}, - {"test float 2", "0.00000001", "1"}, - {"test float 3", "0.00037500", "37500"}, // standard transfer fee - {"test int", "3", "300000000"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tx := &Tx{Fee: tt.fee} - if got := tx.getFee(); got != tt.want { - t.Errorf("getFee() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_getStatus(t *testing.T) { - tests := []struct { - name string - trx Tx - expect blockatlas.Status - }{ - {"Should have status completed", Tx{Code: 0}, blockatlas.StatusCompleted}, - {"Should have status error", Tx{Code: 1}, blockatlas.StatusError}, - {"Should have status error", Tx{Code: -1}, blockatlas.StatusError}, - } - for _, tt := range tests { - t.Run("", func(t *testing.T) { - assert.Equal(t, tt.trx.getStatus(), tt.expect) - }) - } -} - -func Test_getError(t *testing.T) { - tests := []struct { - name string - trx ExplorerTxs - expect string - }{ - {"Should not have error message", ExplorerTxs{Code: 0}, ""}, - {"Should have error message", ExplorerTxs{Code: 1}, "error"}, - {"Should have error message", ExplorerTxs{Code: -1}, "error"}, - } - for _, tt := range tests { - t.Run("", func(t *testing.T) { - assert.Equal(t, tt.trx.getError(), tt.expect) - }) - } -} - -func Test_QuantityTransferType(t *testing.T) { - tests := []struct { - name string - trx ExplorerTxs - expect ExplorerTransactionType - }{ - {"Should be multi transfer", ExplorerTxs{HasChildren: 1}, MultiTransferOperation}, - {"Should be single transfer", ExplorerTxs{HasChildren: 0}, SingleTransferOperation}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.trx.getTransactionType(), tt.expect) - }) - } -} - -func TestExplorerTxs_getDirection(t *testing.T) { - const ( - addr1 = "bnb14cjy0yl23xkf0hnw3ql295v8nghqstvlzkvqpl" - addr2 = "bnb1mr5f97rx5wnkfcakx9fcpvljmx2s6kwqc08yur" - ) - - tests := []struct { - name string - address string - trx ExplorerTxs - expect blockatlas.Direction - }{ - {"getDirection should be self send", addr1, ExplorerTxs{FromAddr: addr1, ToAddr: addr1}, blockatlas.DirectionSelf}, - {"getDirection should be incoming", addr1, ExplorerTxs{FromAddr: addr2, ToAddr: addr1}, blockatlas.DirectionIncoming}, - {"getDirection should be outgoing", addr1, ExplorerTxs{FromAddr: addr1, ToAddr: addr2}, blockatlas.DirectionOutgoing}, - {"getDirection should be empty", "", ExplorerTxs{FromAddr: addr1, ToAddr: addr2}, blockatlas.Direction("")}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.trx.getDirection(tt.address), tt.expect) - }) - } -} - -func Test_getDexFee(t *testing.T) { - tests := []struct { - name string - trx ExplorerTxs - expectFee blockatlas.Amount - }{ - {"Should have zero fee", ExplorerTxs{TxFee: 0}, blockatlas.Amount(0)}, - {"Should have zero fee", ExplorerTxs{TxFee: 0.0}, blockatlas.Amount(0)}, - {"Should have standard fee", ExplorerTxs{TxFee: 0.00037500}, blockatlas.Amount(strconv.Itoa(37500))}, - } - for _, tt := range tests { - t.Run("", func(t *testing.T) { - fee := tt.trx.getDexFee() - assert.Equal(t, fee, tt.expectFee) - }) - } -} - -func Test_extractMultiTransfers(t *testing.T) { - multiAssetTransfer := Value{ - Msg: []Msg{ - { - MsgValue{ - Inputs: []Input{ - {Address: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8"}, - }, - Outputs: []Output{ - {Address: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", Coins: []Coins{ - {Amount: "3068900000000", Denom: "AERGO-46B"}, - {Amount: "4100000000", Denom: "BNB"}, - }, - }, - }, - }, - }, - }, - } - - wantedAssetMultiTransfers := []MultiTransfer{ - { - Amount: "3068900000000", - Asset: "AERGO-46B", - From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - }, - { - Amount: "4100000000", - Asset: "BNB", - From: "bnb1nm4n03x00gw0x6v784jzryyp6wxnjaxswr3xm8", - To: "bnb1eff4hzx4lfsun3px5walchdy4vek4n0njcdzyn", - }, - } - - res := extractMultiTransfers(multiAssetTransfer) - assert.NotNil(t, res) - - assert.Equal(t, 2, len(res)) - assert.Equal(t, res[0], wantedAssetMultiTransfers[0]) - assert.Equal(t, res[1], wantedAssetMultiTransfers[1]) -} diff --git a/platform/binance/token.go b/platform/binance/token.go index 425d40fa2..490d4162a 100644 --- a/platform/binance/token.go +++ b/platform/binance/token.go @@ -1,65 +1,17 @@ package binance import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "strings" ) func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { - account, err := p.rpcClient.fetchAccountMetadata(address) + account, err := p.client.FetchAccountMeta(address) if err != nil || len(account.Balances) == 0 { - return []blockatlas.Token{}, nil + return nil, nil } - tokens, err := p.rpcClient.fetchTokens() + tokens, err := p.client.FetchTokens() if err != nil { return nil, err } return normalizeTokens(account.Balances, tokens), nil } - -// NormalizeTxs converts multiple Binance tokens -func normalizeTokens(srcBalance []Balance, tokens *TokenList) []blockatlas.Token { - tokensList := make([]blockatlas.Token, 0, len(srcBalance)) - for _, srcToken := range srcBalance { - token, ok := normalizeToken(&srcToken, tokens) - if !ok { - continue - } - tokensList = append(tokensList, token) - } - return tokensList -} - -// normalizeToken converts a Binance token into the generic model -func normalizeToken(srcToken *Balance, tokens *TokenList) (blockatlas.Token, bool) { - var result blockatlas.Token - if srcToken.isAllZeroBalance() { - return result, false - } - - token := tokens.findToken(srcToken.Symbol) - if token == nil { - return result, false - } - - result = blockatlas.Token{ - Name: token.Name, - Symbol: token.OriginalSymbol, - TokenID: token.Symbol, - Coin: coin.BNB, - Decimals: uint(decimalPlaces(token.TotalSupply)), - Type: blockatlas.TokenTypeBEP2, - } - - return result, true -} - -// decimalPlaces count the decimals places. -func decimalPlaces(v string) int { - s := strings.Split(v, ".") - if len(s) < 2 { - return 0 - } - return len(s[1]) -} diff --git a/platform/binance/token_test.go b/platform/binance/token_test.go index 33734c07e..e01c2068d 100644 --- a/platform/binance/token_test.go +++ b/platform/binance/token_test.go @@ -3,152 +3,30 @@ package binance import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "net/http/httptest" "testing" ) -const ( - myToken = ` -{ - "free": "17199.38841739", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ARN-71B" -} -` - myTokenAllZero = ` -{ - "free": "0.00000000", - "frozen": "0.00000000", - "locked": "0.00000000", - "symbol": "ARN-71B" -} -` - myTokenFreeZero = ` -{ - "free": "0.00000000", - "frozen": "1.00000000", - "locked": "0.00000000", - "symbol": "ARN-71B" -} -` - myTokenFrozenAndFreeZero = ` -{ - "free": "0.00000000", - "frozen": "0.00000000", - "locked": "0.00000001", - "symbol": "ARN-71B" -} -` - tokenList = ` -[ - { - "mintable": false, - "name": "Aeron", - "original_symbol": "ARN", - "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", - "symbol": "ARN-71B", - "total_supply": "20000000.00000000" - }, - { - "mintable": false, - "name": "BOLT Token", - "original_symbol": "BOLT", - "owner": "bnb177ujwmshxu8r9za4vy9ztqn65tmr54ddw958rt", - "symbol": "BOLT-4C6", - "total_supply": "995000000.00000000" - } -] -` -) - -var ( - tokenDst = blockatlas.Token{ - Name: "Aeron", - Symbol: "ARN", - Decimals: 8, - TokenID: "ARN-71B", - Coin: coin.BNB, - Type: blockatlas.TokenTypeBEP2, - } - emptyTokenDst = blockatlas.Token{} -) - -type testToken struct { - name string - apiResponse string - expected blockatlas.Token - tokens string - ok bool -} - -func TestNormalizeToken(t *testing.T) { - testingTokens := []testToken{ - { - name: "Test with not zero balance", - apiResponse: myToken, - tokens: tokenList, - expected: tokenDst, - ok: true, - }, - { - name: "Test with all zero balance", - apiResponse: myTokenAllZero, - tokens: tokenList, - expected: emptyTokenDst, - ok: false, - }, - { - name: "Test with only free zero balance", - apiResponse: myTokenFreeZero, - tokens: tokenList, - expected: tokenDst, - ok: true, - }, - { - name: "Test with free and frozen zero balances", - apiResponse: myTokenFrozenAndFreeZero, - tokens: tokenList, - expected: tokenDst, - ok: true, - }, - } - for _, testToken := range testingTokens { - t.Run(testToken.name, func(t *testing.T) { - var srcToken Balance - err := json.Unmarshal([]byte(testToken.apiResponse), &srcToken) - assert.Nil(t, err) - - var srcTokens TokenList - err = json.Unmarshal([]byte(testToken.tokens), &srcTokens) - assert.Nil(t, err) - - tk, ok := normalizeToken(&srcToken, &srcTokens) - assert.Equal(t, testToken.ok, ok, "token: token could not be normalized") - assert.Equal(t, testToken.expected, tk, "token: token don't equal") - }) - } -} - -func TestDecimalPlaces(t *testing.T) { - tests := []struct { - name string - value string - want int - }{ - {"Test text value with dot", "decimal.places", 6}, - {"Test float value", "1234.543212222", 9}, - {"Test float value", "5.33333333", 8}, - {"Test text value", "decimal", 0}, - {"Test integer value", "4", 0}, - {"Test empty value", "", 0}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := decimalPlaces(tt.value); got != tt.want { - t.Errorf("decimalPlaces() = %v, want %v", got, tt.want) - } - }) - } +func TestPlatform_GetTokenListByAddress(t *testing.T) { + server := httptest.NewServer(createMockedAPI()) + defer server.Close() + p := Init(server.URL) + + tokens, err := p.GetTokenListByAddress("bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg") + assert.Nil(t, err) + res, err := json.Marshal(tokens) + assert.Nil(t, err) + assert.Equal(t, wantedTokens, string(res)) + + tokens, err = p.GetTokenListByAddress("bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg") + assert.Nil(t, err) + res, err = json.Marshal(tokens) + assert.Nil(t, err) + assert.Equal(t, wantedTokens, string(res)) + + tokens, err = p.GetTokenListByAddress("bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg") + assert.Nil(t, err) + res, err = json.Marshal(tokens) + assert.Nil(t, err) + assert.Equal(t, wantedTokens, string(res)) } diff --git a/platform/binance/transaction.go b/platform/binance/transaction.go index 84581cbce..cffbb7e82 100644 --- a/platform/binance/transaction.go +++ b/platform/binance/transaction.go @@ -3,198 +3,20 @@ package binance import ( "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" - "strconv" - "strings" - "sync" ) -const emptyToken = "" - func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - explorerResponse, err := p.GetTokenTxsByAddress(address, emptyToken) + txsFromClient, err := p.client.FetchTransactionsByAddressAndTokenID(address, coin.Binance().Symbol) if err != nil { return nil, err } - return filterTxsByType(explorerResponse, blockatlas.TxTransfer), nil + return normalizeTransactions(txsFromClient), nil } func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { - explorerResponse, err := p.explorerClient.getTxsOfAddress(address, token) + txsFromClient, err := p.client.FetchTransactionsByAddressAndTokenID(address, token) if err != nil { return nil, err } - - explorerTxs, err := p.addTxDetails(explorerResponse.Txs) - if err != nil { - return nil, err - } - - return normalizeTxs(explorerTxs, address), nil -} - -func normalizeTxs(explorerTxs []ExplorerTxs, address string) []blockatlas.Tx { - var txs []blockatlas.Tx - for _, tx := range explorerTxs { - normalizedTxs := normalizeTx(tx, address) - if normalizedTxs == nil { - continue - } - txs = append(txs, normalizedTxs...) - } - return txs -} - -func filterTxsByType(txs []blockatlas.Tx, txType blockatlas.TransactionType) []blockatlas.Tx { - var result = make([]blockatlas.Tx, 0, len(txs)) - for _, tx := range txs { - if tx.Type == txType { - result = append(result, tx) - } - } - return result -} - -func normalizeTx(srcTx ExplorerTxs, address string) []blockatlas.Tx { - explorerTxType := srcTx.getTransactionType() - switch explorerTxType { - case SingleTransferOperation: - return normalizeSingleTransfer(srcTx, address) - case MultiTransferOperation: - return normalizeMultiTransfer(srcTx, address) - default: - return nil - } -} - -func normalizeSingleTransfer(srcTx ExplorerTxs, address string) blockatlas.TxPage { - if srcTx.TxType != TxTransfer { - return nil - } - tx := getBase(srcTx) - tx.Direction = srcTx.getDirection(address) - bnbCoin := coin.Coins[coin.BNB] - - if srcTx.TxAsset == bnbCoin.Symbol { - tx.Type = blockatlas.TxTransfer - tx.Meta = blockatlas.Transfer{ - Decimals: bnbCoin.Decimals, - Symbol: bnbCoin.Symbol, - Value: srcTx.getDexValue(), - } - return blockatlas.TxPage{tx} - } - - if srcTx.TxAsset != "" { - tx.Type = blockatlas.TxNativeTokenTransfer - tx.Meta = blockatlas.NativeTokenTransfer{ - Decimals: bnbCoin.Decimals, - From: srcTx.FromAddr, - Symbol: tokenSymbol(srcTx.TxAsset), - To: srcTx.ToAddr, - TokenID: srcTx.TxAsset, - Value: srcTx.getDexValue(), - } - return blockatlas.TxPage{tx} - } - return nil -} - -func normalizeMultiTransfer(srcTx ExplorerTxs, address string) []blockatlas.Tx { - var txs blockatlas.TxPage - for _, t := range srcTx.MultisendTransfers { - if t.From == address || t.To == address { - srcTx.FromAddr = t.From - srcTx.ToAddr = t.To - srcTx.TxAsset = t.Asset - - if value, err := strconv.ParseFloat(numbers.ToDecimal(t.Amount, 8), 64); err == nil { - srcTx.Value = value - } - - if single := normalizeSingleTransfer(srcTx, address); single != nil { - txs = append(txs, single...) - } - } - } - return txs -} - -func (p *Platform) addTxDetails(txs []ExplorerTxs) ([]ExplorerTxs, error) { - var ( - wg sync.WaitGroup - txsWithDetails = make([]ExplorerTxs, 0, len(txs)) - txHashChan = make(chan TxHashRPC, len(txs)) - multiSendTxsMap = make(map[string]ExplorerTxs, len(txs)) - ) - - for _, tx := range txs { - multiSendTxsMap[tx.TxHash] = tx - - if tx.HasChildren != 1 { - continue - } - - wg.Add(1) - - go func(srcTx ExplorerTxs, txHashChan chan TxHashRPC, wg *sync.WaitGroup) { - defer wg.Done() - txHash, err := p.rpcClient.fetchTransactionHash(srcTx.TxHash) - if err != nil { - return - } - txHashChan <- *txHash - }(tx, txHashChan, &wg) - } - - wg.Wait() - close(txHashChan) - - for res := range txHashChan { - if len(res.Tx.Value.Msg) > 0 { - a, ok := multiSendTxsMap[res.Hash] - if !ok { - continue - } - a.MultisendTransfers = extractMultiTransfers(res.Tx.Value) - multiSendTxsMap[res.Hash] = a - } - } - - for _, tx := range multiSendTxsMap { - txsWithDetails = append(txsWithDetails, tx) - } - - return txsWithDetails, nil -} - -// Construct base Tx out of explorer transfer using common fields for all type of Blockatlas transfers -func getBase(srcTx ExplorerTxs) blockatlas.Tx { - base := blockatlas.Tx{ - ID: srcTx.TxHash, - Coin: coin.BNB, - From: srcTx.FromAddr, - Fee: srcTx.getDexFee(), - Date: srcTx.Timestamp / 1000, - Block: srcTx.BlockHeight, - Memo: srcTx.Memo, - To: srcTx.ToAddr, - } - - status := srcTx.getStatus() - base.Status = status - if status == blockatlas.StatusError { - base.Error = srcTx.getError() - } - - return base -} - -// Extract BEP2 token symbol from asset name e.g: TWT-8C2 => TWT -func tokenSymbol(asset string) string { - s := strings.Split(asset, "-") - if len(s) > 1 { - return s[0] - } - return asset + return normalizeTransactions(txsFromClient), nil } diff --git a/platform/binance/transaction_test.go b/platform/binance/transaction_test.go index eb4a8a394..b9d6ac0ca 100644 --- a/platform/binance/transaction_test.go +++ b/platform/binance/transaction_test.go @@ -3,174 +3,28 @@ package binance import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "net/http/httptest" "testing" ) -const ( - addr1 = "bnb13a7gyv5zl57c0rzeu0henx6d0tzspvrrakxxtv" - addr2 = "bnb1t6tnm2rckd3pfptngj6u8466v3ah4fcdu78n5y" -) - -const ( - bnbSingleExplorerTransferResponse = ` - { - "txHash": "73176E5BFA5856AEAB9BAB1F3030E6F2B2F274324052E84562BE9BE70E1AAEE7", - "blockHeight": 74821444, - "txType": "TRANSFER", - "timeStamp": 1588086370574, - "fromAddr": "bnb13a7gyv5zl57c0rzeu0henx6d0tzspvrrakxxtv", - "toAddr": "bnb1t6tnm2rckd3pfptngj6u8466v3ah4fcdu78n5y", - "value": 10.00000000, - "txAsset": "BNB", - "txFee": 0.00037500, - "txAge": 1868055, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "bnb-transfer", - "source": 1, - "hasChildren": 0 - }` - - bep2SingleExplorerTransferResponse = ` - { - "txHash": "73176E5BFA5856AEAB9BAB1F3030E6F2B2F274324052E84562BE9BE70E1AAEE7", - "blockHeight": 74821444, - "txType": "TRANSFER", - "timeStamp": 1588086357686, - "fromAddr": "bnb13a7gyv5zl57c0rzeu0henx6d0tzspvrrakxxtv", - "toAddr": "bnb1t6tnm2rckd3pfptngj6u8466v3ah4fcdu78n5y", - "value": 2800.00000000, - "txAsset": "TWT-8C2", - "txFee": 0.00037500, - "txAge": 276251, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "bep2-transfer", - "source": 0, - "hasChildren": 0 - }` - bep2MultipleExplorerTransferResponse = ` - { - "txHash": "73176E5BFA5856AEAB9BAB1F3030E6F2B2F274324052E84562BE9BE70E1AAEE7", - "blockHeight": 74821444, - "txType": "TRANSFER", - "timeStamp": 1588086357686, - "txFee": 0.00037500, - "txAge": 2068619, - "code": 0, - "log": "Msg 0: ", - "confirmBlocks": 0, - "memo": "bep2-transfer", - "source": 0, - "hasChildren": 1, - "subTxsDto": [ - { - "amount": "280000000000", - "asset": "TWT-8C2", - "from": "bnb13a7gyv5zl57c0rzeu0henx6d0tzspvrrakxxtv", - "to": "bnb1t6tnm2rckd3pfptngj6u8466v3ah4fcdu78n5y" - } - ] - }` -) - -var ( - expectBnbSingleExplorerTransfer = blockatlas.Tx{ - ID: "73176E5BFA5856AEAB9BAB1F3030E6F2B2F274324052E84562BE9BE70E1AAEE7", - Coin: 714, - From: addr1, - To: addr2, - Fee: "37500", - Date: 1588086370, - Block: 74821444, - Status: blockatlas.StatusCompleted, - Error: "", - Sequence: 0, - Type: blockatlas.TxTransfer, - Direction: blockatlas.DirectionOutgoing, - Memo: "bnb-transfer", - Meta: blockatlas.Transfer{ - Value: "1000000000", - Symbol: "BNB", - Decimals: 8, - }, - } - - expectBEP2SingleExplorerTransfer = blockatlas.Tx{ - ID: "73176E5BFA5856AEAB9BAB1F3030E6F2B2F274324052E84562BE9BE70E1AAEE7", - Coin: 714, - From: addr1, - To: addr2, - Fee: "37500", - Date: 1588086357, - Block: 74821444, - Status: blockatlas.StatusCompleted, - Error: "", - Sequence: 0, - Type: blockatlas.TxNativeTokenTransfer, - Direction: blockatlas.DirectionIncoming, - Memo: "bep2-transfer", - Meta: blockatlas.NativeTokenTransfer{ - Decimals: 8, - From: addr1, - Name: "", - Symbol: "TWT", - To: addr2, - TokenID: "TWT-8C2", - Value: "280000000000", - }, - } -) - -func TestNormalizeTxs(t *testing.T) { - type test struct { - name, address, dexTxResponse string - expected []blockatlas.Tx - } - tests := []test{ - {name: "BNB single transfer", dexTxResponse: bnbSingleExplorerTransferResponse, expected: []blockatlas.Tx{expectBnbSingleExplorerTransfer}, address: addr1}, - {name: "BEP2 single transfer", dexTxResponse: bep2SingleExplorerTransferResponse, expected: []blockatlas.Tx{expectBEP2SingleExplorerTransfer}, address: addr2}, - {name: "BEP2 multiple transfer", dexTxResponse: bep2MultipleExplorerTransferResponse, expected: []blockatlas.Tx{expectBEP2SingleExplorerTransfer}, address: addr2}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var srcTx ExplorerTxs - err := json.Unmarshal([]byte(tt.dexTxResponse), &srcTx) - assert.Nil(t, err) - actual := normalizeTx(srcTx, tt.address) - assert.Equal(t, tt.expected, actual, "tx don't equal") - }) - } +func TestPlatform_GetTxsByAddress(t *testing.T) { + server := httptest.NewServer(createMockedAPI()) + defer server.Close() + p := Init(server.URL) + txs, err := p.GetTxsByAddress("bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23") + assert.Nil(t, err) + res, err := json.Marshal(txs) + assert.Nil(t, err) + assert.Equal(t, wantedTxs, string(res)) } -func TestTokenSymbol(t *testing.T) { - assert.Equal(t, "UGAS", tokenSymbol("UGAS")) - assert.Equal(t, "UGAS", tokenSymbol("UGAS-B0C")) - assert.Equal(t, "cargabe", tokenSymbol("cargabe")) - assert.Equal(t, "CARBAGE", tokenSymbol("CARBAGE")) - assert.Equal(t, "", tokenSymbol("")) -} - -func Test_getBase(t *testing.T) { - tests := []struct { - name string - srcTx ExplorerTxs - expectStatus blockatlas.Status - expectErrorMsg string - }{ - {"Should have status completed", ExplorerTxs{Code: 0}, blockatlas.StatusCompleted, ""}, - {"Should have status error and error message", ExplorerTxs{Code: 1}, blockatlas.StatusError, "error"}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - base := getBase(tt.srcTx) - assert.Equal(t, base.Status, tt.expectStatus) - assert.Equal(t, base.Error, tt.expectErrorMsg) - }) - } +func TestPlatform_GetTokenTxsByAddress(t *testing.T) { + server := httptest.NewServer(createMockedAPI()) + defer server.Close() + p := Init(server.URL) + txs, err := p.GetTokenTxsByAddress("bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", "AVA-645") + assert.Nil(t, err) + res, err := json.Marshal(txs) + assert.Nil(t, err) + assert.Equal(t, wantedTxsAva, string(res)) } diff --git a/platform/platform.go b/platform/platform.go index 8012bebdf..95b59e46c 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -77,7 +77,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Aeternity().Handle: aeternity.Init(GetApiVar(coin.AE)), coin.Solana().Handle: solana.Init(GetApiVar(coin.SOL)), coin.Tezos().Handle: tezos.Init(GetApiVar(coin.XTZ), GetRpcVar(coin.XTZ)), - coin.Binance().Handle: binance.Init(GetApiVar(coin.BNB), GetVar("binance.explorer")), + coin.Binance().Handle: binance.Init(GetApiVar(coin.BNB)), coin.Zilliqa().Handle: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL), GetVar("zilliqa.lookup")), coin.Kusama().Handle: polkadot.Init(coin.KSM, GetApiVar(coin.KSM)), coin.Stellar().Handle: stellar.Init(coin.XLM, GetApiVar(coin.XLM)), diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index 5cf4224b7..4d49e5145 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -85,9 +85,9 @@ }, { "handler": "binance", - "address": "bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q", + "address": "bnb1z35wusfv8twfele77vddclka9z84ugywug48gn", "expectedTxNum": 1, - "expectedTxId": "4577CB3B5B202696E9E0B093A6DA973C7DD9CBC6808DA1326872745C35F3C089" + "expectedTxId": "FB38CE6A7D0E0DA2E720FDC7017C4207BD449E2D4C80D095C014DE2C9E1DB74A" }, { "handler": "tezos", From b54c432a261cdac9ca57c7420dd71f1c8b693c2c Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Wed, 12 Aug 2020 15:37:04 +0300 Subject: [PATCH 354/506] Temporary remove orders normalization (#1185) * Temporary remove orders normalization * Lint cleanup * Change mock tests --- ...le77vddclka9z84ugywug48gn_txAsset_BNB.json | 2 +- platform/binance/base_test.go | 12 +-- platform/binance/block_test.go | 4 +- platform/binance/model.go | 90 +++++++++---------- platform/binance/transaction_test.go | 3 +- tests/postman/transaction_data.json | 2 +- 6 files changed, 58 insertions(+), 55 deletions(-) diff --git a/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json b/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json index 77dafc5e7..e08c30bad 100644 --- a/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json +++ b/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json @@ -1 +1 @@ -{"tx":[{"txHash":"FB38CE6A7D0E0DA2E720FDC7017C4207BD449E2D4C80D095C014DE2C9E1DB74A","blockHeight":105745488,"txType":"NEW_ORDER","timeStamp":"2020-08-07T21:30:24.258Z","fromAddr":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","toAddr":null,"value":"592.87095000","txAsset":"BNB","txFee":"0.00000000","proposalId":null,"txAge":14,"orderId":"1468EE412C3ADC9CFF3EF31ADC7EDD288F5E208E-11413870","code":0,"data":"{\"orderData\":{\"symbol\":\"BNB_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"21.9875\",\"quantity\":\"26.964\",\"timeInForce\":\"GTE\",\"orderId\":\"1468EE412C3ADC9CFF3EF31ADC7EDD288F5E208E-11413870\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":11413869}],"total":3140} +{"tx":[{"txHash":"0CE23D9F143F7FAF192BB55F33C8FCBC1095D98410A750F63777987685E2C154","blockHeight":106690566,"txType":"TRANSFER","timeStamp":"2020-08-12T10:18:26.388Z","fromAddr":"bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m","toAddr":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","value":"6018.97200000","txAsset":"RUNE-B1A","txFee":"0.00037500","proposalId":null,"txAge":8026,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"","source":0,"sequence":736321}],"total":1} diff --git a/platform/binance/base_test.go b/platform/binance/base_test.go index 40f481e49..10cf81163 100644 --- a/platform/binance/base_test.go +++ b/platform/binance/base_test.go @@ -6,11 +6,13 @@ import ( ) const ( - wantedBlock = `{"number":104867508,"txs":[{"id":"4CD5BAA433BABA63D862141A4A2F9235B0BA5CBAB8114C93A0556ECA4EC7A68A","coin":714,"from":"bnb1l83kstts7lt9dpgawzechnrgjq54dql36dyspc","to":"","fee":"0","date":1596472337,"block":104867508,"status":"completed","sequence":1023322,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Cancel Order","key":"cancel_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"0"}},{"id":"9B87D17581F2AC73D2999EDE56535E50D9D4DB75150A92A90122190F77D47755","coin":714,"from":"bnb1c4czpzvn0ttdcpnv3cy2858l2m9frxdfgk4jr0","to":"bnb1g2ukzn702napq3levm54m2z3p2gam7upern9aq","fee":"37500","date":1596472337,"block":104867508,"status":"completed","sequence":6,"type":"transfer","memo":"","metadata":{"value":"24481570","symbol":"BNB","decimals":8}},{"id":"5C0580AC983C1CF36F1656D9E8B062CD0578839BEFC839EFD6720FF315B45EEB","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596472337,"block":104867508,"status":"completed","sequence":1509154,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"10500000000"}}]}` - wantedTxs = `[{"id":"771B07C8D921B5995524C163E9D4504C31A9E07EC858263A53EA007484009C90","coin":714,"from":"bnb1d83u9afqw296ejw9jdfhc22f0ljr23nn7pradx","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826106,"block":105722032,"status":"completed","sequence":33,"type":"transfer","memo":"106890151","metadata":{"value":"120740436","symbol":"BNB","decimals":8}},{"id":"1C5682716D2D34DD01428AD8D4200081FBDA06CE886B77499F755E9D93B0FF20","coin":714,"from":"bnb1k9ktd79psysucucyxqcd5r9ahuuygk8gh3ly8q","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826069,"block":105721942,"status":"completed","sequence":64,"type":"transfer","memo":"103215089","metadata":{"value":"229350524","symbol":"BNB","decimals":8}},{"id":"C728F7C13977649FCDF9B8E983A9E3AA257EB5596DBCA2A2580584312B5AA535","coin":714,"from":"bnb155svs6sgxe55rnvs6ghprtqu0mh69kehphsppd","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826063,"block":105721925,"status":"completed","sequence":23121,"type":"transfer","memo":"101045880","metadata":{"value":"11964120000","symbol":"BNB","decimals":8}},{"id":"794302F9C6562358581A3A8432AF82CD70DF0DA345C917BDE21DDF9A9D4B9DE7","coin":714,"from":"bnb14gk6m77tswyks9nnadm92mdy3066wj42t60z0l","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826058,"block":105721913,"status":"completed","sequence":11228,"type":"transfer","memo":"100341541","metadata":{"value":"456000000","symbol":"BNB","decimals":8}},{"id":"2827377A04E3B22DD654A02AD4BA50B3CB83973B6B9BA1A423ABD5045873850C","coin":714,"from":"bnb132gvg9gdthtaf6xgkk9jkmsep56fv62vg95unv","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826024,"block":105721828,"status":"completed","sequence":4,"type":"transfer","memo":"105772095","metadata":{"value":"1045498916","symbol":"BNB","decimals":8}},{"id":"AACC80FDA9C45DCD7F6DBAA40A2EB600FF6EBB24A5A840578D4AB306C3427385","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826006,"block":105721785,"status":"completed","sequence":65,"type":"transfer","memo":"109027392","metadata":{"value":"8750000000","symbol":"BNB","decimals":8}},{"id":"66CF0F65442FD35A3B91CC2655CE60E565D13EEFC6BDB1C5AF9F9E484C8B6295","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825967,"block":105721686,"status":"completed","sequence":896,"type":"transfer","memo":"107780643","metadata":{"value":"878900000","symbol":"BNB","decimals":8}},{"id":"81EA185BE754809E40FCBF1B07A0C389F39DECD38D56302D980534850996B144","coin":714,"from":"bnb12nq7fhh3t8q0m9s2n5gqwd9gcx0j85yn0h5zcu","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825888,"block":105721490,"status":"completed","sequence":0,"type":"transfer","memo":"101210049","metadata":{"value":"4498159221","symbol":"BNB","decimals":8}},{"id":"24ED2153427ABACD7F6DB53A1339D9C2573D720FDE6EC45B0047CB146227FF9A","coin":714,"from":"bnb1s5qucugaxv7gkzyg4kacf225s6mhj0ysejn8jq","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825847,"block":105721385,"status":"completed","sequence":40,"type":"transfer","memo":"104298046","metadata":{"value":"34300000000","symbol":"BNB","decimals":8}},{"id":"411A27CE85D0928BC5908DA5BA288CB52E152C1E54FA35042147A90FCEBAB29C","coin":714,"from":"bnb1erj09eqrnz06jv2acxhhy7s3k0q6w4hfmj9rey","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825789,"block":105721238,"status":"completed","sequence":12,"type":"transfer","memo":"107303874","metadata":{"value":"6319074","symbol":"BNB","decimals":8}},{"id":"25359F7277760004BBD42557B3E50F86F06B096478840E057C6F394BF63F6081","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825692,"block":105720997,"status":"completed","sequence":57,"type":"transfer","memo":"109027392","metadata":{"value":"1090000000","symbol":"BNB","decimals":8}},{"id":"1DB710AF4983D9CAFB24AC3DD7C2C6EBC7752F347E5A7599840AB3EFBD436C5D","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825639,"block":105720867,"status":"completed","sequence":56,"type":"transfer","memo":"109027392","metadata":{"value":"2000000000","symbol":"BNB","decimals":8}},{"id":"B7C799B9853ECA41F02241B67E294E2642AE88BBF551DE188A73C48D1A0E821D","coin":714,"from":"bnb1q2994t0djzsy0q2fc62jruxr22nxq6y8l4503l","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825619,"block":105720816,"status":"completed","sequence":1,"type":"transfer","memo":"108202494","metadata":{"value":"295957149","symbol":"BNB","decimals":8}},{"id":"865C098D021CC649FC83B2442092E4D6F0777488163E5797DA9D264C87F1F4F4","coin":714,"from":"bnb16xqcchlutsm8g6gk7wvlzukeu2sy9xt2u77056","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825548,"block":105720641,"status":"completed","sequence":33,"type":"transfer","memo":"102080722","metadata":{"value":"1373501799","symbol":"BNB","decimals":8}},{"id":"1D4F777D1D227D57E4D4BAC3E83FB203147E7B0E7429E60A48A9053372359174","coin":714,"from":"bnb1t6tk66zncqqt7twnfyxx22fn9t3wz3nac5hkck","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825500,"block":105720519,"status":"completed","sequence":14,"type":"transfer","memo":"106456805","metadata":{"value":"1490609","symbol":"BNB","decimals":8}},{"id":"9A818687D52B4E9E0C5F962E6E464ECC6348D6A41AE2C5DD051A5EF71E15B1AC","coin":714,"from":"bnb1v47qw5acc72c34uwt7t9wm9ztqtg6678dmrssa","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825415,"block":105720307,"status":"completed","sequence":6273,"type":"transfer","memo":"104471384","metadata":{"value":"356700000","symbol":"BNB","decimals":8}},{"id":"6C7D4469525E44501ED03BA38A6D54A04DFD6AD2D13328761DA4602A3D777332","coin":714,"from":"bnb1tzet704pc6zjsl3xcwdexn6xlu0zc092y0n4ay","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825348,"block":105720136,"status":"completed","sequence":721,"type":"transfer","memo":"101245732","metadata":{"value":"93900000","symbol":"BNB","decimals":8}},{"id":"8C47875F09371B45C0A29D7C6EF308A1C499D1BBECD5A56E0561B40675AF2D26","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825311,"block":105720042,"status":"completed","sequence":1912,"type":"transfer","memo":"101186586","metadata":{"value":"95193451","symbol":"BNB","decimals":8}},{"id":"39A48766F8ACC33B3BB1B4F442ABFDFBC695F440D72795794A01E8E446CE8EAE","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825298,"block":105720010,"status":"completed","sequence":47,"type":"transfer","memo":"109027392","metadata":{"value":"480000000","symbol":"BNB","decimals":8}},{"id":"54248E3C09713E3870F661749A8690DAD46A8078C7346C497EB4E166564420F4","coin":714,"from":"bnb1hc304lytvp9jnumnjmppq97erm70r7muzv6y98","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825237,"block":105719860,"status":"completed","sequence":1,"type":"transfer","memo":"105261446","metadata":{"value":"10210962500","symbol":"BNB","decimals":8}},{"id":"ADDDB705AB8C2B1AF58D7EDCAEC00C893A6CD87281D7A7146689E9FE1A846EAE","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825173,"block":105719705,"status":"completed","sequence":895,"type":"transfer","memo":"103617121","metadata":{"value":"297900000","symbol":"BNB","decimals":8}},{"id":"7C338C78BBBCD998628CCAF85211883AACB159201755501139F56E0D2A7941A4","coin":714,"from":"bnb1pys084nlc8gqm7lvjje4kt39dn84vd2xsvnwqa","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825147,"block":105719641,"status":"completed","sequence":18,"type":"transfer","memo":"108802310","metadata":{"value":"200000000","symbol":"BNB","decimals":8}},{"id":"6DD7120E43CD5031E2DD6C7977D141B74CA41C8E476D8AE972A9DA2D2EFD2D84","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825061,"block":105719428,"status":"completed","sequence":894,"type":"transfer","memo":"102393444","metadata":{"value":"677900000","symbol":"BNB","decimals":8}},{"id":"86FB14C637D7B0A4AA123FFF76C5C541C70568B67E3F5BC63EB0FDEDEF30301F","coin":714,"from":"bnb17nak8gnucl6lcze0d04def4de77a33qh29f6ur","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825051,"block":105719403,"status":"completed","sequence":3,"type":"transfer","memo":"109823910","metadata":{"value":"900000","symbol":"BNB","decimals":8}},{"id":"1DEEFC0A838F80704574951DF15969CCE34654BE2007BF77F9521A1B4686BE33","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825014,"block":105719312,"status":"completed","sequence":1431,"type":"transfer","memo":"103268674","metadata":{"value":"315739000","symbol":"BNB","decimals":8}}]` - wantedTokens = `[{"name":"Travala.com Token","symbol":"AVA","decimals":8,"token_id":"AVA-645","coin":714,"type":"BEP2"},{"name":"Binance Chain Native Token","symbol":"BNB","decimals":8,"token_id":"BNB","coin":714,"type":"BEP2"},{"name":"Binance USD","symbol":"BUSD","decimals":8,"token_id":"BUSD-BD1","coin":714,"type":"BEP2"}]` - wantedTxsAva = `[{"id":"2BF49DF1D10D9A20438376E760352734DAEBD5D92D6CAA14735EE095A3F65FD3","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827621,"block":105725696,"status":"completed","sequence":1594673,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"2700000000"}},{"id":"C858D15E2745A61D0D3D354750E4462792160FFBB9927739587FFAAEDEFA00FF","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827612,"block":105725676,"status":"completed","sequence":1594670,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"13100000000"}},{"id":"9BDCF416622AA4E8F11162747614585FD840F5721D7163A68BC03EC94E855DEE","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827611,"block":105725673,"status":"completed","sequence":1594669,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1700000000"}},{"id":"52512D9498D4CF51997A5A62C0A55252776B00C888D2D01502C68B56E892F42E","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827603,"block":105725652,"status":"completed","sequence":1594666,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"2200000000"}},{"id":"1BAF96AB01E7AB5A7746CA7E76B293CD636D55713C7CCE71FD0E0ED8ACE05C92","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827600,"block":105725646,"status":"completed","sequence":1594665,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"9990419EFE1B327966EBAAFFC2771046E1AC2E4DDFAD8A93C55DE105A2948A8D","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827591,"block":105725624,"status":"completed","sequence":1594662,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"10800000000"}},{"id":"922F86E110E897233A7B43C0D31397923298C176EBE6F33D98B70ACB911A497A","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827589,"block":105725620,"status":"completed","sequence":1594661,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1800000000"}},{"id":"925A208AFDCD718F8383F7559C7BBA5AE616B693A6029F57BFB67AEBB1CE5F3C","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827580,"block":105725597,"status":"completed","sequence":1594658,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"8200000000"}},{"id":"2B69327D6C0C7B9061AAD962BF4838E3B630A844439013E0EBEFC5B722205774","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827571,"block":105725575,"status":"completed","sequence":1594655,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"BB6FD86C9738C2991F587996ABBAC1151DF1F9DE57FDCC977BB0D8FBAD31188A","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827552,"block":105725529,"status":"completed","sequence":1594653,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"2500000000"}},{"id":"97856635BDBA4B0B3EAAA76EA46D848A2DFE3AAE554A33D308CFC4474C769290","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827550,"block":105725526,"status":"completed","sequence":1594652,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"5500000000"}},{"id":"4B4EC65A5972CC15C4B410339ED0081C4BB57F4E08F2A35744845F5A71531B59","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827537,"block":105725493,"status":"completed","sequence":1594648,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1700000000"}},{"id":"86B5FFDDB06E0973A05434DDB858868A45EDA8B07E0D75125FEAEBA1093D4EA5","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827535,"block":105725489,"status":"completed","sequence":1594647,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"11800000000"}},{"id":"D20757EB130E8146D1A12E869BE69EC2CB03193D8E62467327B09A5D73BBC6F8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827529,"block":105725473,"status":"completed","sequence":1594645,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"3300000000"}},{"id":"04291A7AE08A78C5E5AE216C67D17B6A4260950FFAB6FD3D1C1B991E3B7BB935","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827527,"block":105725470,"status":"completed","sequence":1594644,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"14600000000"}},{"id":"31E16E3F53DD476475256C8D872AF3FD86DC44F3085EF87DDE3643E20C0CE624","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827518,"block":105725448,"status":"completed","sequence":1594641,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1800000000"}},{"id":"1D61A9E35893BB51DE4AE63FA6898FCAE14B6D48F7A2EFD0B51DCCACF6E36B88","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827517,"block":105725446,"status":"completed","sequence":1594640,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"13700000000"}},{"id":"AB9E29B110844BD76F58B058CC20F1E13B37A1AAC4F09978BDE159F1B09B585E","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827509,"block":105725425,"status":"completed","sequence":1594637,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"F81649BAF3D888E3772C8708D255FE91E0CDB2818006A1FC96FFBDAC24BDE675","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827508,"block":105725422,"status":"completed","sequence":1594636,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"8700000000"}},{"id":"71B25BF61219BC87980EB67064C346801C01B00FFE52932799E28FB20DAF41D8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827499,"block":105725401,"status":"completed","sequence":1594633,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1200000000"}},{"id":"3424BFCA860A878FDCF304AD414EDE2AB3B0FF258CA940CD1269F469ED7C422C","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827490,"block":105725379,"status":"completed","sequence":1594630,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"7600000000"}},{"id":"46FFA039B955953D4F19BE7D56FA793B71F34BFB460D9B84A152B554E9219C44","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827488,"block":105725375,"status":"completed","sequence":1594629,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"13900000000"}},{"id":"701100D3783744D633FF34A6E211CEB923EA9BCE6D87A64211801E71F71AEE03","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827469,"block":105725327,"status":"completed","sequence":1594627,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"4900000000"}},{"id":"B12B30509B45CEFE526DAADDAC6399F902B30418859042D7A23F9A2FB311A6C8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827467,"block":105725323,"status":"completed","sequence":1594626,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"2700000000"}},{"id":"933819F35F0F89FB2D58DC50CD15FABB3DA0B817BFCD39A8DDC99DFEC1663F7D","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827458,"block":105725301,"status":"completed","sequence":1594623,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"9500000000"}}]` - wantedBlockMulti = `{"number":105529271,"txs":[{"id":"432FF828B1DC1C4DAF13A51B6AE7ADD9932B7FC6526C28F7FE9C905F95472820","coin":714,"from":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","to":"","fee":"0","date":1596746326,"block":105529271,"status":"completed","sequence":11317170,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Cancel Order","key":"cancel_order","token_id":"","name":"","symbol":"","decimals":8,"value":"0"}},{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","to":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","fee":"60000","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"1","symbol":"BNB","decimals":8}},{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb1t38ccns9var4ac4yj2ylmu99r9ecmggr8ye5e5","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"0","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"39421249","symbol":"BNB","decimals":8}}]}` + //wantedBlock = `{"number":104867508,"txs":[{"id":"4CD5BAA433BABA63D862141A4A2F9235B0BA5CBAB8114C93A0556ECA4EC7A68A","coin":714,"from":"bnb1l83kstts7lt9dpgawzechnrgjq54dql36dyspc","to":"","fee":"0","date":1596472337,"block":104867508,"status":"completed","sequence":1023322,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Cancel Order","key":"cancel_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"0"}},{"id":"9B87D17581F2AC73D2999EDE56535E50D9D4DB75150A92A90122190F77D47755","coin":714,"from":"bnb1c4czpzvn0ttdcpnv3cy2858l2m9frxdfgk4jr0","to":"bnb1g2ukzn702napq3levm54m2z3p2gam7upern9aq","fee":"37500","date":1596472337,"block":104867508,"status":"completed","sequence":6,"type":"transfer","memo":"","metadata":{"value":"24481570","symbol":"BNB","decimals":8}},{"id":"5C0580AC983C1CF36F1656D9E8B062CD0578839BEFC839EFD6720FF315B45EEB","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596472337,"block":104867508,"status":"completed","sequence":1509154,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"10500000000"}}]}` + wantedBlockNoOrders = `{"number":104867508,"txs":[{"id":"9B87D17581F2AC73D2999EDE56535E50D9D4DB75150A92A90122190F77D47755","coin":714,"from":"bnb1c4czpzvn0ttdcpnv3cy2858l2m9frxdfgk4jr0","to":"bnb1g2ukzn702napq3levm54m2z3p2gam7upern9aq","fee":"37500","date":1596472337,"block":104867508,"status":"completed","sequence":6,"type":"transfer","memo":"","metadata":{"value":"24481570","symbol":"BNB","decimals":8}}]}` + wantedTxs = `[{"id":"771B07C8D921B5995524C163E9D4504C31A9E07EC858263A53EA007484009C90","coin":714,"from":"bnb1d83u9afqw296ejw9jdfhc22f0ljr23nn7pradx","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826106,"block":105722032,"status":"completed","sequence":33,"type":"transfer","memo":"106890151","metadata":{"value":"120740436","symbol":"BNB","decimals":8}},{"id":"1C5682716D2D34DD01428AD8D4200081FBDA06CE886B77499F755E9D93B0FF20","coin":714,"from":"bnb1k9ktd79psysucucyxqcd5r9ahuuygk8gh3ly8q","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826069,"block":105721942,"status":"completed","sequence":64,"type":"transfer","memo":"103215089","metadata":{"value":"229350524","symbol":"BNB","decimals":8}},{"id":"C728F7C13977649FCDF9B8E983A9E3AA257EB5596DBCA2A2580584312B5AA535","coin":714,"from":"bnb155svs6sgxe55rnvs6ghprtqu0mh69kehphsppd","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826063,"block":105721925,"status":"completed","sequence":23121,"type":"transfer","memo":"101045880","metadata":{"value":"11964120000","symbol":"BNB","decimals":8}},{"id":"794302F9C6562358581A3A8432AF82CD70DF0DA345C917BDE21DDF9A9D4B9DE7","coin":714,"from":"bnb14gk6m77tswyks9nnadm92mdy3066wj42t60z0l","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826058,"block":105721913,"status":"completed","sequence":11228,"type":"transfer","memo":"100341541","metadata":{"value":"456000000","symbol":"BNB","decimals":8}},{"id":"2827377A04E3B22DD654A02AD4BA50B3CB83973B6B9BA1A423ABD5045873850C","coin":714,"from":"bnb132gvg9gdthtaf6xgkk9jkmsep56fv62vg95unv","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826024,"block":105721828,"status":"completed","sequence":4,"type":"transfer","memo":"105772095","metadata":{"value":"1045498916","symbol":"BNB","decimals":8}},{"id":"AACC80FDA9C45DCD7F6DBAA40A2EB600FF6EBB24A5A840578D4AB306C3427385","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826006,"block":105721785,"status":"completed","sequence":65,"type":"transfer","memo":"109027392","metadata":{"value":"8750000000","symbol":"BNB","decimals":8}},{"id":"66CF0F65442FD35A3B91CC2655CE60E565D13EEFC6BDB1C5AF9F9E484C8B6295","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825967,"block":105721686,"status":"completed","sequence":896,"type":"transfer","memo":"107780643","metadata":{"value":"878900000","symbol":"BNB","decimals":8}},{"id":"81EA185BE754809E40FCBF1B07A0C389F39DECD38D56302D980534850996B144","coin":714,"from":"bnb12nq7fhh3t8q0m9s2n5gqwd9gcx0j85yn0h5zcu","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825888,"block":105721490,"status":"completed","sequence":0,"type":"transfer","memo":"101210049","metadata":{"value":"4498159221","symbol":"BNB","decimals":8}},{"id":"24ED2153427ABACD7F6DB53A1339D9C2573D720FDE6EC45B0047CB146227FF9A","coin":714,"from":"bnb1s5qucugaxv7gkzyg4kacf225s6mhj0ysejn8jq","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825847,"block":105721385,"status":"completed","sequence":40,"type":"transfer","memo":"104298046","metadata":{"value":"34300000000","symbol":"BNB","decimals":8}},{"id":"411A27CE85D0928BC5908DA5BA288CB52E152C1E54FA35042147A90FCEBAB29C","coin":714,"from":"bnb1erj09eqrnz06jv2acxhhy7s3k0q6w4hfmj9rey","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825789,"block":105721238,"status":"completed","sequence":12,"type":"transfer","memo":"107303874","metadata":{"value":"6319074","symbol":"BNB","decimals":8}},{"id":"25359F7277760004BBD42557B3E50F86F06B096478840E057C6F394BF63F6081","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825692,"block":105720997,"status":"completed","sequence":57,"type":"transfer","memo":"109027392","metadata":{"value":"1090000000","symbol":"BNB","decimals":8}},{"id":"1DB710AF4983D9CAFB24AC3DD7C2C6EBC7752F347E5A7599840AB3EFBD436C5D","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825639,"block":105720867,"status":"completed","sequence":56,"type":"transfer","memo":"109027392","metadata":{"value":"2000000000","symbol":"BNB","decimals":8}},{"id":"B7C799B9853ECA41F02241B67E294E2642AE88BBF551DE188A73C48D1A0E821D","coin":714,"from":"bnb1q2994t0djzsy0q2fc62jruxr22nxq6y8l4503l","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825619,"block":105720816,"status":"completed","sequence":1,"type":"transfer","memo":"108202494","metadata":{"value":"295957149","symbol":"BNB","decimals":8}},{"id":"865C098D021CC649FC83B2442092E4D6F0777488163E5797DA9D264C87F1F4F4","coin":714,"from":"bnb16xqcchlutsm8g6gk7wvlzukeu2sy9xt2u77056","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825548,"block":105720641,"status":"completed","sequence":33,"type":"transfer","memo":"102080722","metadata":{"value":"1373501799","symbol":"BNB","decimals":8}},{"id":"1D4F777D1D227D57E4D4BAC3E83FB203147E7B0E7429E60A48A9053372359174","coin":714,"from":"bnb1t6tk66zncqqt7twnfyxx22fn9t3wz3nac5hkck","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825500,"block":105720519,"status":"completed","sequence":14,"type":"transfer","memo":"106456805","metadata":{"value":"1490609","symbol":"BNB","decimals":8}},{"id":"9A818687D52B4E9E0C5F962E6E464ECC6348D6A41AE2C5DD051A5EF71E15B1AC","coin":714,"from":"bnb1v47qw5acc72c34uwt7t9wm9ztqtg6678dmrssa","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825415,"block":105720307,"status":"completed","sequence":6273,"type":"transfer","memo":"104471384","metadata":{"value":"356700000","symbol":"BNB","decimals":8}},{"id":"6C7D4469525E44501ED03BA38A6D54A04DFD6AD2D13328761DA4602A3D777332","coin":714,"from":"bnb1tzet704pc6zjsl3xcwdexn6xlu0zc092y0n4ay","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825348,"block":105720136,"status":"completed","sequence":721,"type":"transfer","memo":"101245732","metadata":{"value":"93900000","symbol":"BNB","decimals":8}},{"id":"8C47875F09371B45C0A29D7C6EF308A1C499D1BBECD5A56E0561B40675AF2D26","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825311,"block":105720042,"status":"completed","sequence":1912,"type":"transfer","memo":"101186586","metadata":{"value":"95193451","symbol":"BNB","decimals":8}},{"id":"39A48766F8ACC33B3BB1B4F442ABFDFBC695F440D72795794A01E8E446CE8EAE","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825298,"block":105720010,"status":"completed","sequence":47,"type":"transfer","memo":"109027392","metadata":{"value":"480000000","symbol":"BNB","decimals":8}},{"id":"54248E3C09713E3870F661749A8690DAD46A8078C7346C497EB4E166564420F4","coin":714,"from":"bnb1hc304lytvp9jnumnjmppq97erm70r7muzv6y98","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825237,"block":105719860,"status":"completed","sequence":1,"type":"transfer","memo":"105261446","metadata":{"value":"10210962500","symbol":"BNB","decimals":8}},{"id":"ADDDB705AB8C2B1AF58D7EDCAEC00C893A6CD87281D7A7146689E9FE1A846EAE","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825173,"block":105719705,"status":"completed","sequence":895,"type":"transfer","memo":"103617121","metadata":{"value":"297900000","symbol":"BNB","decimals":8}},{"id":"7C338C78BBBCD998628CCAF85211883AACB159201755501139F56E0D2A7941A4","coin":714,"from":"bnb1pys084nlc8gqm7lvjje4kt39dn84vd2xsvnwqa","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825147,"block":105719641,"status":"completed","sequence":18,"type":"transfer","memo":"108802310","metadata":{"value":"200000000","symbol":"BNB","decimals":8}},{"id":"6DD7120E43CD5031E2DD6C7977D141B74CA41C8E476D8AE972A9DA2D2EFD2D84","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825061,"block":105719428,"status":"completed","sequence":894,"type":"transfer","memo":"102393444","metadata":{"value":"677900000","symbol":"BNB","decimals":8}},{"id":"86FB14C637D7B0A4AA123FFF76C5C541C70568B67E3F5BC63EB0FDEDEF30301F","coin":714,"from":"bnb17nak8gnucl6lcze0d04def4de77a33qh29f6ur","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825051,"block":105719403,"status":"completed","sequence":3,"type":"transfer","memo":"109823910","metadata":{"value":"900000","symbol":"BNB","decimals":8}},{"id":"1DEEFC0A838F80704574951DF15969CCE34654BE2007BF77F9521A1B4686BE33","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825014,"block":105719312,"status":"completed","sequence":1431,"type":"transfer","memo":"103268674","metadata":{"value":"315739000","symbol":"BNB","decimals":8}}]` + wantedTokens = `[{"name":"Travala.com Token","symbol":"AVA","decimals":8,"token_id":"AVA-645","coin":714,"type":"BEP2"},{"name":"Binance Chain Native Token","symbol":"BNB","decimals":8,"token_id":"BNB","coin":714,"type":"BEP2"},{"name":"Binance USD","symbol":"BUSD","decimals":8,"token_id":"BUSD-BD1","coin":714,"type":"BEP2"}]` + //wantedTxsAva = `[{"id":"2BF49DF1D10D9A20438376E760352734DAEBD5D92D6CAA14735EE095A3F65FD3","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827621,"block":105725696,"status":"completed","sequence":1594673,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"2700000000"}},{"id":"C858D15E2745A61D0D3D354750E4462792160FFBB9927739587FFAAEDEFA00FF","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827612,"block":105725676,"status":"completed","sequence":1594670,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"13100000000"}},{"id":"9BDCF416622AA4E8F11162747614585FD840F5721D7163A68BC03EC94E855DEE","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827611,"block":105725673,"status":"completed","sequence":1594669,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1700000000"}},{"id":"52512D9498D4CF51997A5A62C0A55252776B00C888D2D01502C68B56E892F42E","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827603,"block":105725652,"status":"completed","sequence":1594666,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"2200000000"}},{"id":"1BAF96AB01E7AB5A7746CA7E76B293CD636D55713C7CCE71FD0E0ED8ACE05C92","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827600,"block":105725646,"status":"completed","sequence":1594665,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"9990419EFE1B327966EBAAFFC2771046E1AC2E4DDFAD8A93C55DE105A2948A8D","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827591,"block":105725624,"status":"completed","sequence":1594662,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"10800000000"}},{"id":"922F86E110E897233A7B43C0D31397923298C176EBE6F33D98B70ACB911A497A","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827589,"block":105725620,"status":"completed","sequence":1594661,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1800000000"}},{"id":"925A208AFDCD718F8383F7559C7BBA5AE616B693A6029F57BFB67AEBB1CE5F3C","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827580,"block":105725597,"status":"completed","sequence":1594658,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"8200000000"}},{"id":"2B69327D6C0C7B9061AAD962BF4838E3B630A844439013E0EBEFC5B722205774","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827571,"block":105725575,"status":"completed","sequence":1594655,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"BB6FD86C9738C2991F587996ABBAC1151DF1F9DE57FDCC977BB0D8FBAD31188A","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827552,"block":105725529,"status":"completed","sequence":1594653,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"2500000000"}},{"id":"97856635BDBA4B0B3EAAA76EA46D848A2DFE3AAE554A33D308CFC4474C769290","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827550,"block":105725526,"status":"completed","sequence":1594652,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"5500000000"}},{"id":"4B4EC65A5972CC15C4B410339ED0081C4BB57F4E08F2A35744845F5A71531B59","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827537,"block":105725493,"status":"completed","sequence":1594648,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1700000000"}},{"id":"86B5FFDDB06E0973A05434DDB858868A45EDA8B07E0D75125FEAEBA1093D4EA5","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827535,"block":105725489,"status":"completed","sequence":1594647,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"11800000000"}},{"id":"D20757EB130E8146D1A12E869BE69EC2CB03193D8E62467327B09A5D73BBC6F8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827529,"block":105725473,"status":"completed","sequence":1594645,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"3300000000"}},{"id":"04291A7AE08A78C5E5AE216C67D17B6A4260950FFAB6FD3D1C1B991E3B7BB935","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827527,"block":105725470,"status":"completed","sequence":1594644,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"14600000000"}},{"id":"31E16E3F53DD476475256C8D872AF3FD86DC44F3085EF87DDE3643E20C0CE624","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827518,"block":105725448,"status":"completed","sequence":1594641,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1800000000"}},{"id":"1D61A9E35893BB51DE4AE63FA6898FCAE14B6D48F7A2EFD0B51DCCACF6E36B88","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827517,"block":105725446,"status":"completed","sequence":1594640,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"13700000000"}},{"id":"AB9E29B110844BD76F58B058CC20F1E13B37A1AAC4F09978BDE159F1B09B585E","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827509,"block":105725425,"status":"completed","sequence":1594637,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"F81649BAF3D888E3772C8708D255FE91E0CDB2818006A1FC96FFBDAC24BDE675","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827508,"block":105725422,"status":"completed","sequence":1594636,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"8700000000"}},{"id":"71B25BF61219BC87980EB67064C346801C01B00FFE52932799E28FB20DAF41D8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827499,"block":105725401,"status":"completed","sequence":1594633,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1200000000"}},{"id":"3424BFCA860A878FDCF304AD414EDE2AB3B0FF258CA940CD1269F469ED7C422C","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827490,"block":105725379,"status":"completed","sequence":1594630,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"7600000000"}},{"id":"46FFA039B955953D4F19BE7D56FA793B71F34BFB460D9B84A152B554E9219C44","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827488,"block":105725375,"status":"completed","sequence":1594629,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"13900000000"}},{"id":"701100D3783744D633FF34A6E211CEB923EA9BCE6D87A64211801E71F71AEE03","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827469,"block":105725327,"status":"completed","sequence":1594627,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"4900000000"}},{"id":"B12B30509B45CEFE526DAADDAC6399F902B30418859042D7A23F9A2FB311A6C8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827467,"block":105725323,"status":"completed","sequence":1594626,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"2700000000"}},{"id":"933819F35F0F89FB2D58DC50CD15FABB3DA0B817BFCD39A8DDC99DFEC1663F7D","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827458,"block":105725301,"status":"completed","sequence":1594623,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"9500000000"}}]` + //wantedBlockMulti = `{"number":105529271,"txs":[{"id":"432FF828B1DC1C4DAF13A51B6AE7ADD9932B7FC6526C28F7FE9C905F95472820","coin":714,"from":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","to":"","fee":"0","date":1596746326,"block":105529271,"status":"completed","sequence":11317170,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Cancel Order","key":"cancel_order","token_id":"","name":"","symbol":"","decimals":8,"value":"0"}},{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","to":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","fee":"60000","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"1","symbol":"BNB","decimals":8}},{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb1t38ccns9var4ac4yj2ylmu99r9ecmggr8ye5e5","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"0","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"39421249","symbol":"BNB","decimals":8}}]}` + wantedBlockMultiNoOrders = `{"number":105529271,"txs":[{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","to":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","fee":"60000","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"1","symbol":"BNB","decimals":8}},{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb1t38ccns9var4ac4yj2ylmu99r9ecmggr8ye5e5","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"0","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"39421249","symbol":"BNB","decimals":8}}]}` wantedTxsResponse = `{"tx":[{"txHash":"771B07C8D921B5995524C163E9D4504C31A9E07EC858263A53EA007484009C90","blockHeight":105722032,"txType":"TRANSFER","timeStamp":"2020-08-07T18:48:26.284Z","fromAddr":"bnb1d83u9afqw296ejw9jdfhc22f0ljr23nn7pradx","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"1.20740436","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":104,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"106890151","source":1,"sequence":33},{"txHash":"1C5682716D2D34DD01428AD8D4200081FBDA06CE886B77499F755E9D93B0FF20","blockHeight":105721942,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:49.895Z","fromAddr":"bnb1k9ktd79psysucucyxqcd5r9ahuuygk8gh3ly8q","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.29350524","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":140,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"103215089","source":2,"sequence":64},{"txHash":"C728F7C13977649FCDF9B8E983A9E3AA257EB5596DBCA2A2580584312B5AA535","blockHeight":105721925,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:43.111Z","fromAddr":"bnb155svs6sgxe55rnvs6ghprtqu0mh69kehphsppd","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"119.64120000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":147,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101045880","source":1,"sequence":23121},{"txHash":"794302F9C6562358581A3A8432AF82CD70DF0DA345C917BDE21DDF9A9D4B9DE7","blockHeight":105721913,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:38.279Z","fromAddr":"bnb14gk6m77tswyks9nnadm92mdy3066wj42t60z0l","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"4.56000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":152,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"100341541","source":1,"sequence":11228},{"txHash":"2827377A04E3B22DD654A02AD4BA50B3CB83973B6B9BA1A423ABD5045873850C","blockHeight":105721828,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:04.205Z","fromAddr":"bnb132gvg9gdthtaf6xgkk9jkmsep56fv62vg95unv","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"10.45498916","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":186,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"105772095","source":2,"sequence":4},{"txHash":"AACC80FDA9C45DCD7F6DBAA40A2EB600FF6EBB24A5A840578D4AB306C3427385","blockHeight":105721785,"txType":"TRANSFER","timeStamp":"2020-08-07T18:46:46.832Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"87.50000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":203,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":65},{"txHash":"66CF0F65442FD35A3B91CC2655CE60E565D13EEFC6BDB1C5AF9F9E484C8B6295","blockHeight":105721686,"txType":"TRANSFER","timeStamp":"2020-08-07T18:46:07.122Z","fromAddr":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"8.78900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":243,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"107780643","source":0,"sequence":896},{"txHash":"81EA185BE754809E40FCBF1B07A0C389F39DECD38D56302D980534850996B144","blockHeight":105721490,"txType":"TRANSFER","timeStamp":"2020-08-07T18:44:48.958Z","fromAddr":"bnb12nq7fhh3t8q0m9s2n5gqwd9gcx0j85yn0h5zcu","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"44.98159221","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":321,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101210049","source":0,"sequence":0},{"txHash":"24ED2153427ABACD7F6DB53A1339D9C2573D720FDE6EC45B0047CB146227FF9A","blockHeight":105721385,"txType":"TRANSFER","timeStamp":"2020-08-07T18:44:07.201Z","fromAddr":"bnb1s5qucugaxv7gkzyg4kacf225s6mhj0ysejn8jq","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"343.00000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":363,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"104298046","source":2,"sequence":40},{"txHash":"411A27CE85D0928BC5908DA5BA288CB52E152C1E54FA35042147A90FCEBAB29C","blockHeight":105721238,"txType":"TRANSFER","timeStamp":"2020-08-07T18:43:09.084Z","fromAddr":"bnb1erj09eqrnz06jv2acxhhy7s3k0q6w4hfmj9rey","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.06319074","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":421,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"107303874","source":2,"sequence":12},{"txHash":"25359F7277760004BBD42557B3E50F86F06B096478840E057C6F394BF63F6081","blockHeight":105720997,"txType":"TRANSFER","timeStamp":"2020-08-07T18:41:32.193Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"10.90000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":518,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":57},{"txHash":"1DB710AF4983D9CAFB24AC3DD7C2C6EBC7752F347E5A7599840AB3EFBD436C5D","blockHeight":105720867,"txType":"TRANSFER","timeStamp":"2020-08-07T18:40:39.623Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"20.00000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":570,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":56},{"txHash":"B7C799B9853ECA41F02241B67E294E2642AE88BBF551DE188A73C48D1A0E821D","blockHeight":105720816,"txType":"TRANSFER","timeStamp":"2020-08-07T18:40:19.123Z","fromAddr":"bnb1q2994t0djzsy0q2fc62jruxr22nxq6y8l4503l","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.95957149","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":591,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"108202494","source":0,"sequence":1},{"txHash":"865C098D021CC649FC83B2442092E4D6F0777488163E5797DA9D264C87F1F4F4","blockHeight":105720641,"txType":"TRANSFER","timeStamp":"2020-08-07T18:39:08.972Z","fromAddr":"bnb16xqcchlutsm8g6gk7wvlzukeu2sy9xt2u77056","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"13.73501799","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":661,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"102080722","source":1,"sequence":33},{"txHash":"1D4F777D1D227D57E4D4BAC3E83FB203147E7B0E7429E60A48A9053372359174","blockHeight":105720519,"txType":"TRANSFER","timeStamp":"2020-08-07T18:38:20.149Z","fromAddr":"bnb1t6tk66zncqqt7twnfyxx22fn9t3wz3nac5hkck","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.01490609","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":710,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"106456805","source":2,"sequence":14},{"txHash":"9A818687D52B4E9E0C5F962E6E464ECC6348D6A41AE2C5DD051A5EF71E15B1AC","blockHeight":105720307,"txType":"TRANSFER","timeStamp":"2020-08-07T18:36:55.571Z","fromAddr":"bnb1v47qw5acc72c34uwt7t9wm9ztqtg6678dmrssa","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"3.56700000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":794,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"104471384","source":2,"sequence":6273},{"txHash":"6C7D4469525E44501ED03BA38A6D54A04DFD6AD2D13328761DA4602A3D777332","blockHeight":105720136,"txType":"TRANSFER","timeStamp":"2020-08-07T18:35:48.142Z","fromAddr":"bnb1tzet704pc6zjsl3xcwdexn6xlu0zc092y0n4ay","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.93900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":862,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101245732","source":0,"sequence":721},{"txHash":"8C47875F09371B45C0A29D7C6EF308A1C499D1BBECD5A56E0561B40675AF2D26","blockHeight":105720042,"txType":"TRANSFER","timeStamp":"2020-08-07T18:35:11.247Z","fromAddr":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.95193451","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":899,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101186586","source":2,"sequence":1912},{"txHash":"39A48766F8ACC33B3BB1B4F442ABFDFBC695F440D72795794A01E8E446CE8EAE","blockHeight":105720010,"txType":"TRANSFER","timeStamp":"2020-08-07T18:34:58.634Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"4.80000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":911,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":47},{"txHash":"54248E3C09713E3870F661749A8690DAD46A8078C7346C497EB4E166564420F4","blockHeight":105719860,"txType":"TRANSFER","timeStamp":"2020-08-07T18:33:57.102Z","fromAddr":"bnb1hc304lytvp9jnumnjmppq97erm70r7muzv6y98","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"102.10962500","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":973,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"105261446","source":0,"sequence":1},{"txHash":"ADDDB705AB8C2B1AF58D7EDCAEC00C893A6CD87281D7A7146689E9FE1A846EAE","blockHeight":105719705,"txType":"TRANSFER","timeStamp":"2020-08-07T18:32:53.527Z","fromAddr":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.97900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1036,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"103617121","source":0,"sequence":895},{"txHash":"7C338C78BBBCD998628CCAF85211883AACB159201755501139F56E0D2A7941A4","blockHeight":105719641,"txType":"TRANSFER","timeStamp":"2020-08-07T18:32:27.476Z","fromAddr":"bnb1pys084nlc8gqm7lvjje4kt39dn84vd2xsvnwqa","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.00000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1062,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"108802310","source":0,"sequence":18},{"txHash":"6DD7120E43CD5031E2DD6C7977D141B74CA41C8E476D8AE972A9DA2D2EFD2D84","blockHeight":105719428,"txType":"TRANSFER","timeStamp":"2020-08-07T18:31:01.143Z","fromAddr":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"6.77900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1149,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"102393444","source":0,"sequence":894},{"txHash":"86FB14C637D7B0A4AA123FFF76C5C541C70568B67E3F5BC63EB0FDEDEF30301F","blockHeight":105719403,"txType":"TRANSFER","timeStamp":"2020-08-07T18:30:51.089Z","fromAddr":"bnb17nak8gnucl6lcze0d04def4de77a33qh29f6ur","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.00900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1159,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109823910","source":2,"sequence":3},{"txHash":"1DEEFC0A838F80704574951DF15969CCE34654BE2007BF77F9521A1B4686BE33","blockHeight":105719312,"txType":"TRANSFER","timeStamp":"2020-08-07T18:30:14.498Z","fromAddr":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"3.15739000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1195,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"103268674","source":2,"sequence":1431}],"total":1636}` wantedAccountMetaResponse = `{"account_number":398176,"address":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","balances":[{"free":"366.87270502","frozen":"0.00000000","locked":"2226.00000000","symbol":"AVA-645"},{"free":"6.51198688","frozen":"0.00000000","locked":"0.00000000","symbol":"BNB"},{"free":"850.41375978","frozen":"0.00000000","locked":"3220.00483000","symbol":"BUSD-BD1"}],"flags":0,"public_key":[2,241,253,162,68,84,67,180,235,15,238,212,39,75,236,33,202,249,109,68,247,56,104,66,240,219,8,22,245,187,84,46,54],"sequence":1595533}` wantedTokensResponse = `[{"mintable":true,"name":"Africa Stable-Coin","original_symbol":"ABCD","owner":"bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms","symbol":"ABCD-5D8","total_supply":"3000000.00000000"},{"mintable":false,"name":"Aditus","original_symbol":"ADI","owner":"bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps","symbol":"ADI-6BB","total_supply":"750000000.00000000"},{"mintable":false,"name":"Aergo","original_symbol":"AERGO","owner":"bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl","symbol":"AERGO-46B","total_supply":"500000000.00000000"},{"mintable":false,"name":"Alaris","original_symbol":"ALA","owner":"bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7","symbol":"ALA-DCD","total_supply":"60000000.00000000"},{"mintable":false,"name":"ANKR","original_symbol":"ANKR","owner":"bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn","symbol":"ANKR-E97","total_supply":"10000000000.00000000"},{"mintable":false,"name":"Aeron","original_symbol":"ARN","owner":"bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne","symbol":"ARN-71B","total_supply":"20000000.00000000"},{"mintable":true,"name":"ARPA","original_symbol":"ARPA","owner":"bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c","symbol":"ARPA-575","total_supply":"12000000.00000000"},{"mintable":false,"name":"Maecenas ART Token","original_symbol":"ART","owner":"bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l","symbol":"ART-3C9","total_supply":"100000000.00000000"},{"mintable":true,"name":"Atlas Protocol","original_symbol":"ATP","owner":"bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf","symbol":"ATP-38C","total_supply":"40000000.00000000"},{"mintable":false,"name":"Travala.com Token","original_symbol":"AVA","owner":"bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c","symbol":"AVA-645","total_supply":"61228716.00000000"},{"mintable":true,"name":"“Atomic","original_symbol":"AWC","owner":"bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw","symbol":"AWC-8B2","total_supply":"147.00000000"},{"mintable":false,"name":"Atomic Wallet Token","original_symbol":"AWC","owner":"bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw","symbol":"AWC-986","total_supply":"50000000.00000000"},{"mintable":false,"name":"AXPR.B","original_symbol":"AXPR","owner":"bnb1zpnmet0vhfupn9ysu26gukzj7a2xkkcry22n9t","symbol":"AXPR-777","total_supply":"347955111.02000000"},{"mintable":true,"name":"BAWnetwork","original_symbol":"BAW","owner":"bnb1umdp5z4hugur26tcgf48fhr0548fv0q0fga84u","symbol":"BAW-DFB","total_supply":"25000000000.00000000"},{"mintable":true,"name":"BCH BEP2","original_symbol":"BCH","owner":"bnb15tjhzw85wyywwp7zvc4l3ux3j0393rzp9exl0p","symbol":"BCH-1FD","total_supply":"5000.00000000"},{"mintable":false,"name":"Blockmason Credit Protocol","original_symbol":"BCPT","owner":"bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew","symbol":"BCPT-95A","total_supply":"116158667.00000000"},{"mintable":true,"name":"3X Short Bitcoin Token","original_symbol":"BEAR","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"BEAR-14C","total_supply":"50301.00000000"},{"mintable":false,"name":"EOSBet Token","original_symbol":"BET","owner":"bnb1rgylg0f3ka24a63rnq926quvet438fxrz3320c","symbol":"BET-844","total_supply":"88000000.00000000"},{"mintable":false,"name":"BETX Token","original_symbol":"BETX","owner":"bnb15v9e3c4wy8vpex0c5fj702lexjesh30v2203f2","symbol":"BETX-A0C","total_supply":"200000000.00000000"},{"mintable":true,"name":"Binance GBP Stable Coin","original_symbol":"BGBP","owner":"bnb1r4ag7kd90rptlhcuuc8trh60v4m4vvzrfyecta","symbol":"BGBP-CF3","total_supply":"200.00000000"},{"mintable":true,"name":"Humanity First Token","original_symbol":"BHFT","owner":"bnb148t3u8zxa44vhydes5qa8xnxuzuq6zgyxmzt6d","symbol":"BHFT-BBE","total_supply":"636425000.00000000"},{"mintable":true,"name":"BIDR BEP2","original_symbol":"BIDR","owner":"bnb1v7hlk89x4t6wtfx89wrvhxj5wcv7sxjrve6dav","symbol":"BIDR-0E9","total_supply":"13700000000.00000000"},{"mintable":false,"name":"Bitwires Token","original_symbol":"BKBT","owner":"bnb104p50kz2uvep5s5u6j0lr6vkl6rp5g4653d7w4","symbol":"BKBT-3A6","total_supply":"10000000000.00000000"},{"mintable":true,"name":"Binance KRW","original_symbol":"BKRW","owner":"bnb18kha55gvsxl7gkdh8y329hu3p6wndh6jkwqnxn","symbol":"BKRW-AB7","total_supply":"1571020711.00000000"},{"mintable":false,"name":"Blockmason Link","original_symbol":"BLINK","owner":"bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew","symbol":"BLINK-9C6","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Binance Chain Native Token","original_symbol":"BNB","owner":"bnb1ultyhpw2p2ktvr68swz56570lgj2rdsadq3ym2","symbol":"BNB","total_supply":"176406560.90000000"},{"mintable":false,"name":"BOLT Token","original_symbol":"BOLT","owner":"bnb177ujwmshxu8r9za4vy9ztqn65tmr54ddw958rt","symbol":"BOLT-4C6","total_supply":"980230000.00000000"},{"mintable":false,"name":"Bitcloud Pro","original_symbol":"BPRO","owner":"bnb1482svhhrffpga5wmqw8068af4c9u2q9dp3hg4m","symbol":"BPRO-5A6","total_supply":"5000000000.00000000"},{"mintable":true,"name":"BQTX","original_symbol":"BQTX","owner":"bnb1j42h6j40htujnjmtp4ckw4zx27vp0f93cvmua8","symbol":"BQTX-235","total_supply":"1000000.00000000"},{"mintable":false,"name":"BOOSTO","original_symbol":"BST2","owner":"bnb19k2av7cmdvp9f0qkeu5vfl59yp8ftqv2s55dzs","symbol":"BST2-2F2","total_supply":"500000000.00000000"},{"mintable":true,"name":"Bitcoin BEP2","original_symbol":"BTCB","owner":"bnb1akey87kt0r8y3fmhu2l8eyzdjvt9ptl5cppz0v","symbol":"BTCB-1DE","total_supply":"9001.00000000"},{"mintable":true,"name":"BTTB","original_symbol":"BTTB","owner":"bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq","symbol":"BTTB-D31","total_supply":"1000000000.00000000"},{"mintable":true,"name":"3x Long Bitcoin Token","original_symbol":"BULL","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"BULL-BE4","total_supply":"604.80000000"},{"mintable":true,"name":"Binance USD","original_symbol":"BUSD","owner":"bnb19v2ayq6k6e5x6ny3jdutdm6kpqn3n6mxheegvj","symbol":"BUSD-BD1","total_supply":"26000000.00000000"},{"mintable":false,"name":"Bezant Token","original_symbol":"BZNT","owner":"bnb1w5a5jywe3cu20uq6n6x3vmzcq342s6st4cz73s","symbol":"BZNT-464","total_supply":"964511442.00000000"},{"mintable":false,"name":"CanYaCoin","original_symbol":"CAN","owner":"bnb16w59lfh4y2cqvu8f7yr000ll37ldh4w6hnz7l0","symbol":"CAN-677","total_supply":"95827000.00000000"},{"mintable":false,"name":"CASHAA","original_symbol":"CAS","owner":"bnb1xkw2sagpx6t0cmwzapxpv94tupvqk7tpgy72ku","symbol":"CAS-167","total_supply":"1000000000.00000000"},{"mintable":false,"name":"Cubiex","original_symbol":"CBIX","owner":"bnb1jlm66w38gpfuqr4s2jcfwlcrlx46p05thdnv7g","symbol":"CBIX-3C9","total_supply":"150000000.00000000"},{"mintable":false,"name":"CryptoBonusMiles","original_symbol":"CBM","owner":"bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne","symbol":"CBM-4B2","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Clipper Coin","original_symbol":"CCCX","owner":"bnb1ry99rte8gfnn9c6at9mlmrrq6p2k4u7732j9h7","symbol":"CCCX-10D","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Chiliz","original_symbol":"CHZ","owner":"bnb1cghr4z8ag440tv4wnk3l6wzynytlpvfqltm9ph","symbol":"CHZ-ECD","total_supply":"8888888888.00000000"},{"mintable":false,"name":"Crypto Neo-value Neural System","original_symbol":"CNNS","owner":"bnb193wdp4gdnm58urnsjf8nv57lxt58sckt2k50ss","symbol":"CNNS-E16","total_supply":"10000000000.00000000"},{"mintable":false,"name":"Contentos","original_symbol":"COS","owner":"bnb1u9j9hkst6gf09dkdvxlj7puk8c7vh68a0kkmht","symbol":"COS-2E4","total_supply":"9400000000.00000000"},{"mintable":true,"name":"COTI","original_symbol":"COTI","owner":"bnb1kn733gkku9xsqkuk6wcz86gftqtl4qvthvrj5m","symbol":"COTI-CBB","total_supply":"80000000.00000000"},{"mintable":false,"name":"Covalent Token","original_symbol":"COVA","owner":"bnb1pucvxaf3l9rslupza75r9fca9h5892ntumszfm","symbol":"COVA-218","total_supply":"6500000000.00000000"},{"mintable":false,"name":"CPChain","original_symbol":"CPC","owner":"bnb1wq4rlwrmvvltlarvypql8wrr4vlh0dczd8uksg","symbol":"CPC-FED","total_supply":"150000000.00000000"},{"mintable":false,"name":"Crypterium Token","original_symbol":"CRPT","owner":"bnb17fk3uvagucxzpvmdvd373fapqsahxvzevdard9","symbol":"CRPT-8C9","total_supply":"99968575.14285720"},{"mintable":false,"name":"“Consentium”","original_symbol":"CSM","owner":"bnb1gguz7vcrlf7a87et8u5gt40f0890qvkpkn9y79","symbol":"CSM-734","total_supply":"84000000.00000000"},{"mintable":true,"name":"Carbon Dollar","original_symbol":"CUSD","owner":"bnb1y9797dtklkm3haajsfnevm9ruuxs5fyf5rpj67","symbol":"CUSD-24B","total_supply":"9999999999.00000000"},{"mintable":false,"name":"Konstellation Network","original_symbol":"DARC","owner":"bnb1gyhnhdns4vf63nfzfq7g25czj8swjgrz3rhah8","symbol":"DARC-24B","total_supply":"1000000000.00000000"},{"mintable":true,"name":"DeepCloud","original_symbol":"DEEP","owner":"bnb1t0ws9gvnjm7j7qssk8te7m2dt5hmm8s3amqk2d","symbol":"DEEP-9D3","total_supply":"200000000.00000000"},{"mintable":false,"name":"DeFi Token","original_symbol":"DEFI","owner":"bnb1q5xefr07503pqtfrl5sfyyhlghxwc80d4vpas2","symbol":"DEFI-FA5","total_supply":"2500000000.00000000"},{"mintable":true,"name":"DOS Network Token","original_symbol":"DOS","owner":"bnb13gse9n7mvrjg5w2cymnt4nmxkgj200k9k2l2nh","symbol":"DOS-120","total_supply":"1000000000.00000000"},{"mintable":false,"name":"DREP","original_symbol":"DREP","owner":"bnb1ez5s9v4rcgsmhwr4fkrnlv6zwsukjnh4y754kn","symbol":"DREP-7D2","total_supply":"10000000000.00000000"},{"mintable":true,"name":"Dusk Network","original_symbol":"DUSK","owner":"bnb1dfls6c8y39l7qq4gj2479wkehg85pt5m07y94g","symbol":"DUSK-45E","total_supply":"50000000.00000000"},{"mintable":false,"name":"eBoost","original_symbol":"EBST","owner":"bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7","symbol":"EBST-783","total_supply":"80838159.07000000"},{"mintable":true,"name":"Ormeus Ecosystem","original_symbol":"ECO","owner":"bnb1tr49nv08k828n2lqfw0vrgvwj7xtep5kg8wr4c","symbol":"ECO-083","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Energy Eco Token","original_symbol":"EET","owner":"bnb1pt353m8ygvvgy4f2ud9xx85tl7fqewkrksh6r5","symbol":"EET-45C","total_supply":"600000000.00000000"},{"mintable":false,"name":"Hut34 Entropy","original_symbol":"ENTRP","owner":"bnb1wu0hu9pelx3yvplysx0je7d93htcandpj86aev","symbol":"ENTRP-C8D","total_supply":"100000000.00000000"},{"mintable":true,"name":"EOS BEP2","original_symbol":"EOS","owner":"bnb1la8alalwjzkchd67wza3r75lj5rm7m9e85ffqr","symbol":"EOS-CDD","total_supply":"500000.00000000"},{"mintable":true,"name":"3X Short EOS Token","original_symbol":"EOSBEAR","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"EOSBEAR-721","total_supply":"32301.00000000"},{"mintable":true,"name":"3X Long EOS Token","original_symbol":"EOSBULL","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"EOSBULL-F0D","total_supply":"456191.00000000"},{"mintable":false,"name":"EQUAL","original_symbol":"EQL","owner":"bnb1uz0s54rzv022dh66l7atwk83wqcet9qstgg358","symbol":"EQL-586","total_supply":"675259060.00000000"},{"mintable":true,"name":"Elrond","original_symbol":"ERD","owner":"bnb1m5uzzfxs7x05sl28gg96zyecn9jwgtkpyeftyn","symbol":"ERD-D06","total_supply":"13000000000.00000000"},{"mintable":true,"name":"ETH BEP2","original_symbol":"ETH","owner":"bnb1yss2345dphss8c823dh2jzje2w8k8x4jguuxhf","symbol":"ETH-1C9","total_supply":"10000.00000000"},{"mintable":true,"name":"3X Short Ethereum Token","original_symbol":"ETHBEAR","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"ETHBEAR-B2B","total_supply":"61821.00000000"},{"mintable":true,"name":"3X Long Ethereum Token","original_symbol":"ETHBULL","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"ETHBULL-D33","total_supply":"33684.00000000"},{"mintable":true,"name":"everiToken","original_symbol":"EVT","owner":"bnb1v3fl4kuwuhzf3g7ghscsq7uzmu5dw50waseptd","symbol":"EVT-49B","total_supply":"1000000000.00000000"},{"mintable":true,"name":"The Force Token","original_symbol":"FOR","owner":"bnb1c46nhwdwm3u2mlfhx6t07fls25shnvktpr9w9m","symbol":"FOR-997","total_supply":"100000000.00000000"},{"mintable":false,"name":"Ferrum Network Token","original_symbol":"FRM","owner":"bnb1um8ntkgwle8yrdk0yn5hwdf7hckjpyjjg29k2p","symbol":"FRM-DE7","total_supply":"164609374.50000000"},{"mintable":false,"name":"Fusion","original_symbol":"FSN","owner":"bnb17mnutyduat9fe02r2dawp3kn4rnaqamp5kpg0c","symbol":"FSN-E14","total_supply":"57344000.00000000"},{"mintable":true,"name":"Fantom","original_symbol":"FTM","owner":"bnb1f6sxnf3nhn9fcfwkuccrzvl2pgu3sq0m8pyjhw","symbol":"FTM-A64","total_supply":"952500000.00000000"},{"mintable":true,"name":"FTX Token","original_symbol":"FTT","owner":"bnb1msxdh7e7smpg68gxxhs0p3fhuj9tzhrxa4c2x2","symbol":"FTT-F11","total_supply":"10000000.00000000"},{"mintable":true,"name":"Givly Coin","original_symbol":"GIV","owner":"bnb13jzr6sqz72fl0edg2tpqp8tddyzvyt4su2490m","symbol":"GIV-94E","total_supply":"1000000000.00000000"},{"mintable":false,"name":"GoWithMi","original_symbol":"GMAT","owner":"bnb1yltla9mnk8999ygmjjn3kwmmz2zs94a9v20sca","symbol":"GMAT-FC8","total_supply":"14900000000.00000000"},{"mintable":false,"name":"Global Gaming","original_symbol":"GMNG","owner":"bnb1qe6zxqptfxw0kh38t8pg6c3qa527n2x2a87qvm","symbol":"GMNG-F3E","total_supply":"5000000000.00000000"},{"mintable":false,"name":"GTEX","original_symbol":"GTEX","owner":"bnb1nksrzfl24he9xtvdvpypsl6r5jnh5x2uf9s82z","symbol":"GTEX-71B","total_supply":"4000000000.00000000"},{"mintable":false,"name":"Gifto","original_symbol":"GTO","owner":"bnb1lvp8k3zenlfp2pl2nyaf428xjgh385m258gzvq","symbol":"GTO-908","total_supply":"1000000000.00000000"},{"mintable":true,"name":"“Hermes","original_symbol":"HEC","owner":"bnb1dfyydqkmsv5m0rs0pa4uut2gwrcsahppktns2t","symbol":"HEC-1A9","total_supply":"100000000.00000000"},{"mintable":false,"name":"Honest","original_symbol":"HNST","owner":"bnb1k9fv2hz0w3l9v9z4g9samg3gtc7nc2xgyqw5u0","symbol":"HNST-3C9","total_supply":"400000000.00000000"},{"mintable":true,"name":"Hyperion Token","original_symbol":"HYN","owner":"bnb1q5cqecuy2g7syl8fssp9a7v2sjamtrzlr3pa0n","symbol":"HYN-F21","total_supply":"10000000000.00000000"},{"mintable":true,"name":"Rupiah Token","original_symbol":"IDRTB","owner":"bnb1wc44duax6pygh23psx0u945skvs3eh7w59e4sp","symbol":"IDRTB-178","total_supply":"90000000000.00000000"},{"mintable":false,"name":"IKU","original_symbol":"IKU","owner":"bnb1f52tc9l0qg337qtgu4n024ayllc78wxpc5xhvd","symbol":"IKU-416","total_supply":"300000000.00000000"},{"mintable":true,"name":"IRIS Network","original_symbol":"IRIS","owner":"bnb1dcpm0jjj8el8g6ekr3mvjxa8kptgu4e5xzvqv8","symbol":"IRIS-D88","total_supply":"2000000000.00000000"},{"mintable":false,"name":"JDXUCoin","original_symbol":"JDXU","owner":"bnb1dwcsg0t86g7935zpxc054n97styzgdtnu2kzg6","symbol":"JDXU-706","total_supply":"1000000000.00000000"},{"mintable":false,"name":"Kambria Token","original_symbol":"KAT","owner":"bnb1l68n6equtr925lhnentyq54zfrzqyj45lg8uwj","symbol":"KAT-7BB","total_supply":"3700000000.00000000"},{"mintable":true,"name":"Kava BEP2 Token","original_symbol":"KAVA","owner":"bnb1uyekdn62yur9zuctzqyd9ckasfvqttjz9c33me","symbol":"KAVA-10C","total_supply":"271190.72181900"},{"mintable":false,"name":"Sessia Kicks","original_symbol":"KICKS","owner":"bnb130tmwjd3fc79eh6f5ezl2326ur8rqpsxeeq30x","symbol":"KICKS-162","total_supply":"5000000.00000000"},{"mintable":true,"name":"Lambda","original_symbol":"LAMB","owner":"bnb19vnwdjwthm9unxe9hxdxmgm6qw0d42d2lmcesw","symbol":"LAMB-46C","total_supply":"5000000.00000000"},{"mintable":false,"name":"Lend-Borrow-Asset","original_symbol":"LBA","owner":"bnb1m8r74hr532lfwtaf5e88cxeakd36ut0ufpd4yu","symbol":"LBA-340","total_supply":"1000000000.00000000"},{"mintable":true,"name":"LITION","original_symbol":"LIT","owner":"bnb1fhlxwqlwd7cm5fmurg0wmsaalshnp7lwu46nk9","symbol":"LIT-099","total_supply":"145061313.45061312"},{"mintable":true,"name":"Loki","original_symbol":"LOKI","owner":"bnb1j5sft8wp7tktjwauy30x79f3tqa53fycmgxxs0","symbol":"LOKI-6A9","total_supply":"3000000.00000000"},{"mintable":true,"name":"LTC BEP2","original_symbol":"LTC","owner":"bnb1cn4sqm79wqmr8rey923r34cp2wrtyhlr9easpg","symbol":"LTC-F07","total_supply":"18500.00000000"},{"mintable":false,"name":"LTO Network","original_symbol":"LTO","owner":"bnb1ac6p45m00pv36y9mu48e5xr73fyxke3zv2rhmq","symbol":"LTO-BDF","total_supply":"500000000.00000000"},{"mintable":false,"name":"LYFE","original_symbol":"LYFE","owner":"bnb1k0779dltjkl6a05v5uq06zym62hcufzcqu6gq7","symbol":"LYFE-6AB","total_supply":"231250000.00000000"},{"mintable":false,"name":"Matic Token","original_symbol":"MATIC","owner":"bnb1a6nkf3g7c2z0jcrqhp8c9upcwmme0y49qx58nz","symbol":"MATIC-84A","total_supply":"10000000000.00000000"},{"mintable":false,"name":"Moviebloc","original_symbol":"MBL","owner":"bnb17p8rc0z5vlysff2wc7xehff464dm0v7nhl27xq","symbol":"MBL-2D2","total_supply":"30000000000.00000000"},{"mintable":true,"name":"Mcashchain","original_symbol":"MCASH","owner":"bnb1q420q7qpyv7tghfp6aac7vnjq74dhkeutdhqsg","symbol":"MCASH-869","total_supply":"200000000.00000000"},{"mintable":false,"name":"Magic Cube Token","original_symbol":"MCC","owner":"bnb14nt79d6hzhjefkys2cgrc9nrzugdjwwtggfmu4","symbol":"MCC-33B","total_supply":"20000000000.00000000"},{"mintable":false,"name":"MDAB","original_symbol":"MDAB","owner":"bnb1m3edd4q4nd3wxg9vm3xe8pnfnetu5yjmhtnrqz","symbol":"MDAB-D42","total_supply":"1000000000.00000000"}]` diff --git a/platform/binance/block_test.go b/platform/binance/block_test.go index 02f12fc54..5fcc19bfa 100644 --- a/platform/binance/block_test.go +++ b/platform/binance/block_test.go @@ -24,11 +24,11 @@ func TestPlatform_GetBlockByNumber(t *testing.T) { assert.Nil(t, err) res, err := json.Marshal(block) assert.Nil(t, err) - assert.Equal(t, wantedBlock, string(res)) + assert.Equal(t, wantedBlockNoOrders, string(res)) blockMulti, err := p.GetBlockByNumber(105529271) assert.Nil(t, err) resMulti, err := json.Marshal(blockMulti) assert.Nil(t, err) - assert.Equal(t, wantedBlockMulti, string(resMulti)) + assert.Equal(t, wantedBlockMultiNoOrders, string(resMulti)) } diff --git a/platform/binance/model.go b/platform/binance/model.go index 68cbdb157..6c3170925 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -1,7 +1,6 @@ package binance import ( - "encoding/json" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" @@ -117,7 +116,8 @@ func normalizeTransactions(txs []Tx) []blockatlas.Tx { var txs []blockatlas.Tx switch t.TxType { case CancelOrder, NewOrder: - txs = append(txs, normalizeOrderTransaction(t)) + //txs = append(txs, normalizeOrderTransaction(t)) + continue case Transfer: if len(t.SubTransactions) > 0 { txs = normalizeMultiTransferTransaction(t) @@ -211,36 +211,36 @@ func normalizeBaseOfTransaction(t Tx) blockatlas.Tx { } } -func normalizeOrderTransaction(t Tx) blockatlas.Tx { - tx := normalizeBaseOfTransaction(t) - tx.Type = blockatlas.TxAnyAction - meta := blockatlas.AnyAction{ - Coin: coin.Binance().ID, - Decimals: coin.Binance().Decimals, - } - - data, err := getTransactionData(t.Data) - if err == nil { - base, _ := getTokenIDsFromPair(data.OrderData.Symbol) - meta.TokenID = base - meta.Value = blockatlas.Amount(numbers.FromDecimalExp(data.OrderData.Quantity, int(coin.Binance().Decimals))) - meta.Name = data.OrderData.Side - meta.Symbol = getTokenSymbolFromID(base) - } - switch t.TxType { - case CancelOrder: - meta.Title = blockatlas.KeyTitleCancelOrder - meta.Key = blockatlas.KeyCancelOrder - meta.Value = "0" - case NewOrder: - meta.Title = blockatlas.KeyTitlePlaceOrder - meta.Key = blockatlas.KeyPlaceOrder - } - - tx.Meta = meta - tx.Direction = blockatlas.DirectionOutgoing - return tx -} +//func normalizeOrderTransaction(t Tx) blockatlas.Tx { +// tx := normalizeBaseOfTransaction(t) +// tx.Type = blockatlas.TxAnyAction +// meta := blockatlas.AnyAction{ +// Coin: coin.Binance().ID, +// Decimals: coin.Binance().Decimals, +// } +// +// data, err := getTransactionData(t.Data) +// if err == nil { +// base, _ := getTokenIDsFromPair(data.OrderData.Symbol) +// meta.TokenID = base +// meta.Value = blockatlas.Amount(numbers.FromDecimalExp(data.OrderData.Quantity, int(coin.Binance().Decimals))) +// meta.Name = data.OrderData.Side +// meta.Symbol = getTokenSymbolFromID(base) +// } +// switch t.TxType { +// case CancelOrder: +// meta.Title = blockatlas.KeyTitleCancelOrder +// meta.Key = blockatlas.KeyCancelOrder +// meta.Value = "0" +// case NewOrder: +// meta.Title = blockatlas.KeyTitlePlaceOrder +// meta.Key = blockatlas.KeyPlaceOrder +// } +// +// tx.Meta = meta +// tx.Direction = blockatlas.DirectionOutgoing +// return tx +//} func normalizeTokens(srcBalance []TokenBalance, tokens Tokens) []blockatlas.Token { tokensList := make([]blockatlas.Token, 0, len(srcBalance)) @@ -277,19 +277,19 @@ func normalizeToken(srcToken TokenBalance, tokens Tokens) (blockatlas.Token, boo return result, true } -func getTransactionData(rawOrderData string) (TransactionData, error) { - var result TransactionData - err := json.Unmarshal([]byte(rawOrderData), &result) - return result, err -} - -func getTokenIDsFromPair(pair string) (string, string) { - result := strings.Split(pair, "_") - if len(result) == 1 || len(result) == 0 { - return pair, pair - } - return result[0], result[1] -} +//func getTransactionData(rawOrderData string) (TransactionData, error) { +// var result TransactionData +// err := json.Unmarshal([]byte(rawOrderData), &result) +// return result, err +//} +// +//func getTokenIDsFromPair(pair string) (string, string) { +// result := strings.Split(pair, "_") +// if len(result) == 1 || len(result) == 0 { +// return pair, pair +// } +// return result[0], result[1] +//} func getTokenSymbolFromID(tokenID string) string { s := strings.Split(tokenID, "-") diff --git a/platform/binance/transaction_test.go b/platform/binance/transaction_test.go index b9d6ac0ca..f3b9af8da 100644 --- a/platform/binance/transaction_test.go +++ b/platform/binance/transaction_test.go @@ -26,5 +26,6 @@ func TestPlatform_GetTokenTxsByAddress(t *testing.T) { assert.Nil(t, err) res, err := json.Marshal(txs) assert.Nil(t, err) - assert.Equal(t, wantedTxsAva, string(res)) + assert.Len(t, res, 2) + //assert.Equal(t, wantedTxsAva, string(res)) } diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index 4d49e5145..b594767d7 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -87,7 +87,7 @@ "handler": "binance", "address": "bnb1z35wusfv8twfele77vddclka9z84ugywug48gn", "expectedTxNum": 1, - "expectedTxId": "FB38CE6A7D0E0DA2E720FDC7017C4207BD449E2D4C80D095C014DE2C9E1DB74A" + "expectedTxId": "0CE23D9F143F7FAF192BB55F33C8FCBC1095D98410A750F63777987685E2C154" }, { "handler": "tezos", From e7e7008a3718449f7b95a6a4424deb2d4c0887ed Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 13 Aug 2020 13:33:46 +0300 Subject: [PATCH 355/506] Fix amount issue (#1187) --- platform/aeternity/transaction.go | 23 +++++++++++++++++------ platform/aeternity/transaction_test.go | 3 ++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/platform/aeternity/transaction.go b/platform/aeternity/transaction.go index 48adf1f72..2d904c9e1 100644 --- a/platform/aeternity/transaction.go +++ b/platform/aeternity/transaction.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/numbers" "strings" ) @@ -15,30 +16,40 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { var txs []blockatlas.Tx for _, srcTx := range addressTxs { - txs = append(txs, NormalizeTx(&srcTx)) + tx, err := NormalizeTx(&srcTx) + if err != nil { + continue + } + txs = append(txs, tx) } return txs, nil } -func NormalizeTx(srcTx *Transaction) blockatlas.Tx { +func NormalizeTx(srcTx *Transaction) (blockatlas.Tx, error) { txValue := srcTx.TxValue + decimals := coin.Coins[coin.AE].Decimals + amountFloat, err := txValue.Amount.Float64() + if err != nil { + return blockatlas.Tx{}, err + } + amount := numbers.Float64toString(amountFloat) return blockatlas.Tx{ ID: srcTx.Hash, Coin: coin.AE, From: txValue.Sender, To: txValue.Recipient, Fee: blockatlas.Amount(txValue.Fee), - Date: int64(srcTx.Timestamp) / 1000, + Date: srcTx.Timestamp / 1000, Block: srcTx.BlockHeight, Memo: getPayload(txValue.Payload), Status: blockatlas.StatusCompleted, Sequence: txValue.Nonce, Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(txValue.Amount), + Value: blockatlas.Amount(amount), Symbol: coin.Coins[coin.AE].Symbol, - Decimals: coin.Coins[coin.AE].Decimals, + Decimals: decimals, }, - } + }, nil } func getPayload(encodedPayload string) string { diff --git a/platform/aeternity/transaction_test.go b/platform/aeternity/transaction_test.go index fec5dbbae..8392602d3 100644 --- a/platform/aeternity/transaction_test.go +++ b/platform/aeternity/transaction_test.go @@ -63,7 +63,8 @@ func testNormalize(t *testing.T, _test *test) { return } - tx := NormalizeTx(&srcTx) + tx, err := NormalizeTx(&srcTx) + assert.Nil(t, err) resJSON, err := json.Marshal(&tx) if err != nil { From 4d64802e94fcd7bdd937a23757d8075ace3641ab Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 14 Aug 2020 15:31:53 +0800 Subject: [PATCH 356/506] enable polkadot tx api (#1189) --- coin/coins.go | 16 +++++++++++++++- coin/coins.yml | 8 ++++++++ config.yml | 3 +++ platform/platform.go | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/coin/coins.go b/coin/coins.go index 9fa098e0e..cd2dc90e8 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2020-05-18 14:17:38.050930018 +0300 EEST m=+0.001659149 +// 2020-08-14 12:59:11.508841 +0800 CST m=+0.001995886 // using data from coins.yml package coin @@ -71,6 +71,7 @@ const ( DGB = 20 ONE = 1023 KSM = 434 + DOT = 354 SOL = 501 NEAR = 397 ERD = 508 @@ -537,6 +538,16 @@ var Coins = map[uint]Coin{ MinConfirmations: 0, SampleAddr: "HewiDTQv92L2bVtkziZC8ASxrFUxr6ajQ62RXAnwQ8FDVmg", }, + DOT: { + ID: 354, + Handle: "polkadot", + Symbol: "DOT", + Name: "Polkadot", + Decimals: 10, + BlockTime: 6000, + MinConfirmations: 0, + SampleAddr: "13SkL2uACPqBzpKBh3d2n5msYNFB2QapA5vEDeKeLjG2LS3Y", + }, SOL: { ID: 501, Handle: "solana", @@ -706,6 +717,9 @@ func Harmony() Coin { func Kusama() Coin { return Coins[KSM] } +func Polkadot() Coin { + return Coins[DOT] +} func Solana() Coin { return Coins[SOL] } diff --git a/coin/coins.yml b/coin/coins.yml index 05c583b12..b297c168f 100644 --- a/coin/coins.yml +++ b/coin/coins.yml @@ -365,6 +365,14 @@ blockTime: 6000 sampleAddress: 'HewiDTQv92L2bVtkziZC8ASxrFUxr6ajQ62RXAnwQ8FDVmg' +- id: 354 + symbol: DOT + handle: polkadot + name: Polkadot + decimals: 10 + blockTime: 6000 + sampleAddress: '13SkL2uACPqBzpKBh3d2n5msYNFB2QapA5vEDeKeLjG2LS3Y' + - id: 501 symbol: SOL handle: solana diff --git a/config.yml b/config.yml index 243651413..51c074a74 100644 --- a/config.yml +++ b/config.yml @@ -214,6 +214,9 @@ kava: kusama: api: https://kusama.subscan.io/api +polkadot: + api: https://polkadot.subscan.io/api + solana: api: https://api.mainnet-beta.solana.com diff --git a/platform/platform.go b/platform/platform.go index 95b59e46c..8efdbf35c 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -80,6 +80,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Binance().Handle: binance.Init(GetApiVar(coin.BNB)), coin.Zilliqa().Handle: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL), GetVar("zilliqa.lookup")), coin.Kusama().Handle: polkadot.Init(coin.KSM, GetApiVar(coin.KSM)), + coin.Polkadot().Handle: polkadot.Init(coin.DOT, GetApiVar(coin.DOT)), coin.Stellar().Handle: stellar.Init(coin.XLM, GetApiVar(coin.XLM)), coin.Kin().Handle: stellar.Init(coin.KIN, GetApiVar(coin.KIN)), coin.Cosmos().Handle: cosmos.Init(coin.ATOM, GetApiVar(coin.ATOM)), From 4d2defec3bc491e7cab3a30976334d37a77e7fe9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2020 12:34:18 +0300 Subject: [PATCH 357/506] Bump github.com/jinzhu/gorm from 1.9.15 to 1.9.16 (#1192) Bumps [github.com/jinzhu/gorm](https://github.com/jinzhu/gorm) from 1.9.15 to 1.9.16. - [Release notes](https://github.com/jinzhu/gorm/releases) - [Commits](https://github.com/jinzhu/gorm/compare/v1.9.15...v1.9.16) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 3d2358596..3ff2a472b 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/gin-gonic/gin v1.6.3 github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/imroc/req v0.3.0 - github.com/jinzhu/gorm v1.9.15 + github.com/jinzhu/gorm v1.9.16 github.com/mitchellh/mapstructure v1.3.3 github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/image-spec v1.0.1 // indirect diff --git a/go.sum b/go.sum index d263a18c7..da332a6cd 100644 --- a/go.sum +++ b/go.sum @@ -242,6 +242,8 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= github.com/jinzhu/gorm v1.9.15 h1:OdR1qFvtXktlxk73XFYMiYn9ywzTwytqe4QkuMRqc38= github.com/jinzhu/gorm v1.9.15/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= +github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= +github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= From 73558eb007831e64f693b81ffb78cc427a0e9ac5 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Fri, 14 Aug 2020 12:51:33 +0300 Subject: [PATCH 358/506] [Platform/API] Fix zilliqa api (#1193) * [Platform/API] Fix zilliqa api * Fix lint --- platform/zilliqa/model.go | 16 +++++++++++++++- platform/zilliqa/rpc.go | 17 +++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/platform/zilliqa/model.go b/platform/zilliqa/model.go index 8f932866b..45580e011 100644 --- a/platform/zilliqa/model.go +++ b/platform/zilliqa/model.go @@ -77,7 +77,7 @@ func (t *TxRPC) toTx() *Tx { } height, err := strconv.ParseUint(t.Receipt.EpochNum, 10, 64) if err != nil { - return nil + height = 0 } gasLimt, ok := new(big.Int).SetString(t.GasLimit, 10) if !ok { @@ -108,3 +108,17 @@ type BlockTxRpc struct { Result BlockTxs `json:"result,omitempty"` Id string `json:"id,omitempty"` } + +type HashesResponse struct { + ID int `json:"id"` + Jsonrpc string `json:"jsonrpc"` + Result [][]string `json:"result"` +} + +func (h HashesResponse) Txs() []string { + var result []string + for _, subRes := range h.Result { + result = append(result, subRes...) + } + return result +} diff --git a/platform/zilliqa/rpc.go b/platform/zilliqa/rpc.go index 533823a9c..0118cbcef 100644 --- a/platform/zilliqa/rpc.go +++ b/platform/zilliqa/rpc.go @@ -1,11 +1,11 @@ package zilliqa import ( + "github.com/imroc/req" "strconv" "github.com/mitchellh/mapstructure" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" ) type RpcClient struct { @@ -24,24 +24,21 @@ func (c *RpcClient) GetTx(hash string) (tx TxRPC, err error) { func (c *RpcClient) GetBlockByNumber(number int64) ([]string, error) { strNumber := strconv.FormatInt(number, 10) - req := &blockatlas.RpcRequest{ + requestBody := &blockatlas.RpcRequest{ JsonRpc: blockatlas.JsonRpcVersion, Method: "GetTransactionsForTxBlock", Params: []string{strNumber}, Id: number, } - var resp *BlockTxRpc - err := c.Post(&resp, "", req) + resp, err := req.Post(c.BaseUrl, req.BodyJSON(requestBody)) if err != nil { return nil, err } - if resp.Error != nil && resp.Error.Code != -1 { - return nil, errors.E("RPC Call error", errors.Params{ - "method": "GetTransactionsForTxBlock", - "error_code": resp.Error.Code, - "error_message": resp.Error.Message}) + var result HashesResponse + if err = resp.ToJSON(&result); err != nil { + return nil, err } - return resp.Result.txs(), nil + return result.Txs(), nil } func (c *RpcClient) GetTxInBlock(number int64) ([]Tx, error) { From 768eb7b83925d29891989bb0cddbbaecaa912cec Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Fri, 14 Aug 2020 13:54:22 +0300 Subject: [PATCH 359/506] [API/Vechain] Only VTHO is supported for such token (#1194) --- platform/vechain/model.go | 1 + platform/vechain/transaction.go | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/vechain/model.go b/platform/vechain/model.go index f136c0b3f..0d9fff073 100644 --- a/platform/vechain/model.go +++ b/platform/vechain/model.go @@ -8,6 +8,7 @@ const ( const ( gasTokenName = "VeThor" gasTokenSymbol = "VTHO" + gasTokenAddress = "0x0000000000000000000000000000456E65726779" gasTokenDecimals = 18 ) diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 5d3edfa75..ade4ffbf7 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -11,6 +11,9 @@ import ( ) func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { + if token != gasTokenAddress { + return nil, nil + } curBlock, err := p.CurrentBlockNumber() if err != nil { return nil, err @@ -87,7 +90,7 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (block if len(output.Events) == 0 || len(output.Events[0].Topics) < 3 { continue } - event := output.Events[0] // TODO add support for multisend + event := output.Events[0] value, err := numbers.HexToDecimal(event.Data) if err != nil { continue From bea0c7fa7df3158fc5ca3d3887cfd7c309d198c0 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2020 17:47:30 +0300 Subject: [PATCH 360/506] Bump github.com/DATA-DOG/go-sqlmock from 1.4.1 to 1.5.0 (#1196) Bumps [github.com/DATA-DOG/go-sqlmock](https://github.com/DATA-DOG/go-sqlmock) from 1.4.1 to 1.5.0. - [Release notes](https://github.com/DATA-DOG/go-sqlmock/releases) - [Commits](https://github.com/DATA-DOG/go-sqlmock/compare/v1.4.1...v1.5.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 3ff2a472b..a174c8518 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect - github.com/DATA-DOG/go-sqlmock v1.4.1 + github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Microsoft/go-winio v0.4.14 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 diff --git a/go.sum b/go.sum index da332a6cd..5c5a6c425 100644 --- a/go.sum +++ b/go.sum @@ -21,6 +21,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= From 756a7dd064e80216e95f82634ef3c1270ea6f2d5 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 20 Aug 2020 06:43:06 -0700 Subject: [PATCH 361/506] Add api prefix to bitcoin, binance, blockbook routes (#1198) * Add api prefix to bitcoin, binance, blockbook routes * Adjust config * Update client.go * Fix bnb path in test * Change mock paths * Change mock paths * Change mock paths * Change mock paths * Change mock paths * Remove / * Remove eth api / Co-authored-by: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> --- config.yml | 34 +- mock/datafiles.yaml | 72 +- ...bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q | 1 - ...ce-api_v1_tokens__limit_1000_offset_0.json | 1466 ----------------- ...le77vddclka9z84ugywug48gn_txAsset_BNB.json | 1 - platform/binance/base_test.go | 12 +- platform/binance/client.go | 10 +- platform/bitcoin/client.go | 10 +- platform/ethereum/blockbook/client.go | 8 +- tests/postman/token_data.json | 4 - tests/postman/transaction_data.json | 6 - 11 files changed, 67 insertions(+), 1557 deletions(-) delete mode 100644 mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q delete mode 100644 mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json delete mode 100644 mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json diff --git a/config.yml b/config.yml index 51c074a74..75a1b1aa8 100644 --- a/config.yml +++ b/config.yml @@ -40,8 +40,8 @@ postgres: # [BNB] Binance DEX: https://www.binance.org/ binance: - api: https://dex.binance.org/api - explorer: https://explorer.binance.org/api + api: https://dex.binance.org + explorer: https://explorer.binance.org # [NIM] Nimiq: https://nimiq.com #nimiq: @@ -67,7 +67,7 @@ tezos: # [ETH] Ethereum: https://ethereum.org ethereum: api: https://localhost:4567 #(Trust-Ray API) - blockbook_api: https://eth1.trezor.io/api + blockbook_api: https://eth1.trezor.io collections_api: https://api.opensea.io # collections_api_key: [opensea_api_key] rpc: https://main-rpc.linkpool.io @@ -158,43 +158,43 @@ fio: # [BTC] Bitcoin: https://bitcoin.org/ (Blockbook API https://github.com/trezor/blockbook) bitcoin: - api: https://btc1.trezor.io/api + api: https://btc1.trezor.io litecoin: - api: https://ltc1.trezor.io/api + api: https://ltc1.trezor.io bitcoincash: - api: https://bch1.trezor.io/api + api: https://bch1.trezor.io doge: - api: https://doge1.trezor.io/api + api: https://doge1.trezor.io dash: - api: https://dash1.trezor.io/api + api: https://dash1.trezor.io zcoin: - api: https://blockbook.zcoin.io/api + api: https://blockbook.zcoin.io zcash: - api: https://zec1.trezor.io/api + api: https://zec1.trezor.io zelcash: - api: https://blockbook.zel.network/api + api: https://blockbook.zel.network viacoin: - api: https://blockbook.viacoin.org/api + api: https://blockbook.viacoin.org qtum: - api: https://blockv3.qtum.info/api + api: https://blockv3.qtum.info groestlcoin: - api: https://blockbook.groestlcoin.org/api + api: https://blockbook.groestlcoin.org ravencoin: - api: https://blockbook.ravencoin.org/api + api: https://blockbook.ravencoin.org decred: - api: https://blockbook.decred.org:9161/api + api: https://blockbook.decred.org:9161 algorand: api: https://mainnet-algorand.api.purestake.io/ps1 @@ -203,7 +203,7 @@ nano: api: https://nanoverse.io/api/node digibyte: - api: https://dgb1.trezor.io/api + api: https://dgb1.trezor.io harmony: api: https://api.s0.t.hmny.io diff --git a/mock/datafiles.yaml b/mock/datafiles.yaml index c3c83b051..98c196131 100644 --- a/mock/datafiles.yaml +++ b/mock/datafiles.yaml @@ -17,32 +17,20 @@ mockURL: /mock/algorand-api/v1/block/5478346 method: GET extURL: https://mainnet-algorand.api.purestake.io/ps1/v1/block/5478346 -- file: mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json - mockURL: /mock/binance-api/v1/transactions?address=bnb1z35wusfv8twfele77vddclka9z84ugywug48gn&txAsset=BNB - method: GET - extURL: https://dex.binance.org/api/v1/transactions?address=bnb1z35wusfv8twfele77vddclka9z84ugywug48gn&txAsset=BNB -- file: mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q - mockURL: /mock/binance-api/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q - method: GET - extURL: https://dex.binance.org/api/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q -- file: mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json - mockURL: /mock/binance-api/v1/tokens?limit=1000 - method: GET - extURL: https://dex.binance.org/api/v1/tokens?limit=1000&offset=0 - file: mock/ext-api-data/bitcoin-api_v2_address_bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj__details_txs.json - mockURL: /mock/bitcoin-api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs + mockURL: /mock/bitcoin-api/api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs method: GET extURL: https://btc1.trezor.io/api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs&pageSize=10 - file: mock/ext-api-data/bitcoin-api_v2_xpub_zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC__details_txs.json - mockURL: /mock/bitcoin-api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs + mockURL: /mock/bitcoin-api/api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs method: GET extURL: https://btc1.trezor.io/api/v2/xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC?details=txs&pageSize=10 - file: mock/ext-api-data/bitcoincash-api_v2_address_bitcoincash_qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme__details_txs.json - mockURL: /mock/bitcoincash-api/v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs + mockURL: /mock/bitcoincash-api/api/v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs method: GET extURL: https:///v2/address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme?details=txs&pageSize=5 - file: mock/ext-api-data/bitcoincash-api_v2_xpub_xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX__details_txs.json - mockURL: /mock/bitcoincash-api/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs + mockURL: /mock/bitcoincash-api/api/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs method: GET extURL: https:///api/v2/xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX?details=txs&pageSize=10 - file: mock/ext-api-data/callisto-api_tokens__address_0xc3d5b69f65027ddf48f894e6e90121293a2f6615.json @@ -86,35 +74,35 @@ method: GET extURL: https://api.cosmos.network/auth/accounts/cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq - file: mock/ext-api-data/dash-api_v2_address_XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG__details_txs.json - mockURL: /mock/dash-api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs + mockURL: /mock/dash-api/api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs method: GET extURL: https://dash1.trezor.io/api/v2/address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG?details=txs&pageSize=10 - file: mock/ext-api-data/dash-api_v2_xpub_xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD__details_txs.json - mockURL: /mock/dash-api/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs + mockURL: /mock/dash-api/api/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs method: GET extURL: https://dash1.trezor.io/api/v2/xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD?details=txs&pageSize=10 - file: mock/ext-api-data/decred-api_v2_address_DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY__details_txs.json - mockURL: /mock/decred-api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs + mockURL: /mock/decred-api/api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs method: GET extURL: https://blockbook.decred.org:9161/api/v2/address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY?details=txs&pageSize=10 - file: mock/ext-api-data/decred-api_v2_xpub_dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN__details_txs.json - mockURL: /mock/decred-api/v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs + mockURL: /mock/decred-api/api/v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs method: GET extURL: https://blockbook.decred.org:9161/api/v2/xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN?details=txs&pageSize=10 - file: mock/ext-api-data/digibyte-api_v2_address_DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi__details_txs.json - mockURL: /mock/digibyte-api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs + mockURL: /mock/digibyte-api/api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs method: GET extURL: https://dgb1.trezor.io/api/v2/address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi?details=txs&pageSize=10 - file: mock/ext-api-data/digibyte-api_v2_xpub_zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow__details_txs.json - mockURL: /mock/digibyte-api/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs + mockURL: /mock/digibyte-api/api/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs method: GET extURL: https://dgb1.trezor.io/api/v2/xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow?details=txs&pageSize=10 - file: mock/ext-api-data/doge-api_v2_address_D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh__details_txs.json - mockURL: /mock/doge-api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs + mockURL: /mock/doge-api/api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs method: GET extURL: https://doge1.trezor.io/api/v2/address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh?details=txs&pageSize=10 - file: mock/ext-api-data/doge-api_v2_xpub_dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN__details_txs.json - mockURL: /mock/doge-api/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs + mockURL: /mock/doge-api/api/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs method: GET extURL: https://doge1.trezor.io/api/v2/xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN?details=txs&pageSize=10 - file: mock/ext-api-data/eth-api_tokens__address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7.json @@ -126,11 +114,11 @@ method: GET extURL: https://localhost:4567/transactions?address=0x0875BCab22dE3d02402bc38aEe4104e1239374a7 - file: mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_tokenBalances.json - mockURL: /mock/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances + mockURL: /mock/eth-blockbook-api/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances method: GET extURL: https:///api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=tokenBalances - file: mock/ext-api-data/eth-blockbook-api_v2_address_0x0875BCab22dE3d02402bc38aEe4104e1239374a7__details_txs.json - mockURL: /mock/eth-blockbook-api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs + mockURL: /mock/eth-blockbook-api/api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs method: GET extURL: https:///api/v2/address/0x0875BCab22dE3d02402bc38aEe4104e1239374a7?details=txs&pageSize=10 - file: mock/ext-api-data/ethclassic-api_tokens__address_0xa12105efa0663147bddee178f6a741ac15676b79.json @@ -150,11 +138,11 @@ method: GET extURL: https:///transactions?address=0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896 - file: mock/ext-api-data/groestlcoin-api_v2_address_33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj__details_txs.json - mockURL: /mock/groestlcoin-api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs + mockURL: /mock/groestlcoin-api/api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs method: GET extURL: https://blockbook.groestlcoin.org/api/v2/address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj?details=txs&pageSize=10 - file: mock/ext-api-data/groestlcoin-api_v2_xpub_zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf__details_txs.json - mockURL: /mock/groestlcoin-api/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs + mockURL: /mock/groestlcoin-api/api/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs method: GET extURL: https://blockbook.groestlcoin.org/api/v2/xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf?details=txs&pageSize=10 - file: mock/ext-api-data/icon-api_address_txList__address_hxee691e7bccc4eb11fee922896e9f51490e62b12e_count_25.json @@ -226,11 +214,11 @@ method: GET extURL: https://horizon-block-explorer.kininfrastructure.com/transactions/eb070218bfde8c48af6071432bc9f19b7690b9dc50535cc135f67ea046e70bed - file: mock/ext-api-data/litecoin-api_v2_address_ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept__details_txs.json - mockURL: /mock/litecoin-api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs + mockURL: /mock/litecoin-api/api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs method: GET extURL: https://ltc1.trezor.io/api/v2/address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept?details=txs&pageSize=10 - file: mock/ext-api-data/litecoin-api_v2_xpub_zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu__details_txs.json - mockURL: /mock/litecoin-api/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs + mockURL: /mock/litecoin-api/api/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs method: GET extURL: https://ltc1.trezor.io/api/v2/xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu?details=txs&pageSize=10 - file: mock/ext-api-data/nebulas-api_tx__a_n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a_p_0.json @@ -258,19 +246,19 @@ method: GET extURL: https:///transactions?address=0x55798eCbF17ce1241d543c22dCE46134c13b4bc0 - file: mock/ext-api-data/qtum-api_v2_address_QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ__details_txs.json - mockURL: /mock/qtum-api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs + mockURL: /mock/qtum-api/api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs method: GET extURL: https://blockv3.qtum.info/api/v2/address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ?details=txs&pageSize=10 - file: mock/ext-api-data/qtum-api_v2_xpub_xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd__details_txs.json - mockURL: /mock/qtum-api/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs + mockURL: /mock/qtum-api/api/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs method: GET extURL: https://blockv3.qtum.info/api/v2/xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd?details=txs&pageSize=10 - file: mock/ext-api-data/ravencoin-api_v2_address_RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo__details_txs.json - mockURL: /mock/ravencoin-api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs + mockURL: /mock/ravencoin-api/api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs method: GET extURL: https://blockbook.ravencoin.org/api/v2/address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo?details=txs&pageSize=10 - file: mock/ext-api-data/ravencoin-api_v2_xpub_xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B__details_txs.json - mockURL: /mock/ravencoin-api/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs + mockURL: /mock/ravencoin-api/api/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs method: GET extURL: https://blockbook.ravencoin.org/api/v2/xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B?details=txs&pageSize=10 - file: mock/ext-api-data/ripple-api_accounts_rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1_transactions__descending_false_limit_25_type_Payment.json @@ -358,11 +346,11 @@ method: GET extURL: https://vethor-pubnode.digonchain.com/transactions/0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7 - file: mock/ext-api-data/viacoin-api_v2_address_VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A__details_txs.json - mockURL: /mock/viacoin-api/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs + mockURL: /mock/viacoin-api/api/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs method: GET extURL: https://blockbook.viacoin.org/api/v2/address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A?details=txs&pageSize=10 - file: mock/ext-api-data/viacoin-api_v2_xpub_zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK__details_txs.json - mockURL: /mock/viacoin-api/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs + mockURL: /mock/viacoin-api/api/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs method: GET extURL: https://blockbook.viacoin.org/api/v2/xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK?details=txs&pageSize=10 - file: mock/ext-api-data/waves-api_transactions_address_3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD_limit_25.json @@ -370,27 +358,27 @@ method: GET extURL: https://nodes.wavesnodes.com/transactions/address/3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD/limit/25 - file: mock/ext-api-data/zcash-api_v2_address_t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX__details_txs.json - mockURL: /mock/zcash-api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs + mockURL: /mock/zcash-api/api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs method: GET extURL: https://zec1.trezor.io/api/v2/address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX?details=txs&pageSize=10 - file: mock/ext-api-data/zcash-api_v2_xpub_xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS__details_txs.json - mockURL: /mock/zcash-api/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs + mockURL: /mock/zcash-api/api/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs method: GET extURL: https://zec1.trezor.io/api/v2/xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS?details=txs&pageSize=10 - file: mock/ext-api-data/zcoin-api_v2_address_a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn__details_txs.json - mockURL: /mock/zcoin-api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs + mockURL: /mock/zcoin-api/api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs method: GET extURL: https://blockbook.zcoin.io/api/v2/address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn?details=txs&pageSize=10 - file: mock/ext-api-data/zcoin-api_v2_xpub_xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK__details_txs.json - mockURL: /mock/zcoin-api/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs + mockURL: /mock/zcoin-api/api/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs method: GET extURL: https://blockbook.zcoin.io/api/v2/xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK?details=txs&pageSize=10 - file: mock/ext-api-data/zelcash-api_v2_address_t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa__details_txs.json - mockURL: /mock/zelcash-api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs + mockURL: /mock/zelcash-api/api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs method: GET extURL: https://blockbook.zel.network/api/v2/address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa?details=txs&&pageSize=10 - file: mock/ext-api-data/zelcash-api_v2_xpub_xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf__details_txs.json - mockURL: /mock/zelcash-api/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs + mockURL: /mock/zelcash-api/api/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs method: GET extURL: https://blockbook.zel.network/api/v2/xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf?details=txs&pageSize=10 - file: mock/ext-api-data/zilliqa-api_addresses_zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z_txs.json diff --git a/mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q b/mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q deleted file mode 100644 index ff8e44b50..000000000 --- a/mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q +++ /dev/null @@ -1 +0,0 @@ -{"account_number":273171,"address":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","balances":[{"free":"226.52883965","frozen":"0.00000000","locked":"0.00000000","symbol":"BNB"},{"free":"3649.96917801","frozen":"0.00000000","locked":"0.00000000","symbol":"BUSD-BD1"},{"free":"0.05000000","frozen":"0.00000000","locked":"0.00000000","symbol":"TWT-8C2"}],"flags":0,"public_key":[2,142,117,1,132,202,113,77,165,176,46,204,240,131,18,251,120,168,140,204,43,27,32,135,157,30,25,86,154,105,108,64,211],"sequence":82} diff --git a/mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json b/mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json deleted file mode 100644 index ef085c1eb..000000000 --- a/mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json +++ /dev/null @@ -1,1466 +0,0 @@ -[ - { - "mintable": true, - "name": "Africa Stable-Coin", - "original_symbol": "ABCD", - "owner": "bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms", - "symbol": "ABCD-5D8", - "total_supply": "3000000.00000000" - }, - { - "mintable": false, - "name": "Aditus", - "original_symbol": "ADI", - "owner": "bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps", - "symbol": "ADI-6BB", - "total_supply": "750000000.00000000" - }, - { - "mintable": false, - "name": "Aergo", - "original_symbol": "AERGO", - "owner": "bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl", - "symbol": "AERGO-46B", - "total_supply": "500000000.00000000" - }, - { - "mintable": false, - "name": "Alaris", - "original_symbol": "ALA", - "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", - "symbol": "ALA-DCD", - "total_supply": "60000000.00000000" - }, - { - "mintable": false, - "name": "ANKR", - "original_symbol": "ANKR", - "owner": "bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn", - "symbol": "ANKR-E97", - "total_supply": "10000000000.00000000" - }, - { - "mintable": false, - "name": "Aeron", - "original_symbol": "ARN", - "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", - "symbol": "ARN-71B", - "total_supply": "20000000.00000000" - }, - { - "mintable": true, - "name": "ARPA", - "original_symbol": "ARPA", - "owner": "bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c", - "symbol": "ARPA-575", - "total_supply": "12000000.00000000" - }, - { - "mintable": false, - "name": "Maecenas ART Token", - "original_symbol": "ART", - "owner": "bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l", - "symbol": "ART-3C9", - "total_supply": "100000000.00000000" - }, - { - "mintable": true, - "name": "Atlas Protocol", - "original_symbol": "ATP", - "owner": "bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf", - "symbol": "ATP-38C", - "total_supply": "40000000.00000000" - }, - { - "mintable": false, - "name": "Travala.com Token", - "original_symbol": "AVA", - "owner": "bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c", - "symbol": "AVA-645", - "total_supply": "61242960.00000000" - }, - { - "mintable": true, - "name": "“Atomic", - "original_symbol": "AWC", - "owner": "bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw", - "symbol": "AWC-8B2", - "total_supply": "147.00000000" - }, - { - "mintable": false, - "name": "Atomic Wallet Token", - "original_symbol": "AWC", - "owner": "bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw", - "symbol": "AWC-986", - "total_supply": "50000000.00000000" - }, - { - "mintable": false, - "name": "AXPR.B", - "original_symbol": "AXPR", - "owner": "bnb1zpnmet0vhfupn9ysu26gukzj7a2xkkcry22n9t", - "symbol": "AXPR-777", - "total_supply": "347955111.02000000" - }, - { - "mintable": true, - "name": "BAWnetwork", - "original_symbol": "BAW", - "owner": "bnb1umdp5z4hugur26tcgf48fhr0548fv0q0fga84u", - "symbol": "BAW-DFB", - "total_supply": "25000000000.00000000" - }, - { - "mintable": true, - "name": "BCH BEP2", - "original_symbol": "BCH", - "owner": "bnb15tjhzw85wyywwp7zvc4l3ux3j0393rzp9exl0p", - "symbol": "BCH-1FD", - "total_supply": "5000.00000000" - }, - { - "mintable": false, - "name": "Blockmason Credit Protocol", - "original_symbol": "BCPT", - "owner": "bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew", - "symbol": "BCPT-95A", - "total_supply": "116158667.00000000" - }, - { - "mintable": true, - "name": "3X Short Bitcoin Token", - "original_symbol": "BEAR", - "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", - "symbol": "BEAR-14C", - "total_supply": "50301.00000000" - }, - { - "mintable": false, - "name": "EOSBet Token", - "original_symbol": "BET", - "owner": "bnb1rgylg0f3ka24a63rnq926quvet438fxrz3320c", - "symbol": "BET-844", - "total_supply": "88000000.00000000" - }, - { - "mintable": false, - "name": "BETX Token", - "original_symbol": "BETX", - "owner": "bnb15v9e3c4wy8vpex0c5fj702lexjesh30v2203f2", - "symbol": "BETX-A0C", - "total_supply": "200000000.00000000" - }, - { - "mintable": true, - "name": "Binance GBP Stable Coin", - "original_symbol": "BGBP", - "owner": "bnb1r4ag7kd90rptlhcuuc8trh60v4m4vvzrfyecta", - "symbol": "BGBP-CF3", - "total_supply": "200.00000000" - }, - { - "mintable": true, - "name": "Humanity First Token", - "original_symbol": "BHFT", - "owner": "bnb148t3u8zxa44vhydes5qa8xnxuzuq6zgyxmzt6d", - "symbol": "BHFT-BBE", - "total_supply": "636425000.00000000" - }, - { - "mintable": false, - "name": "Bitwires Token", - "original_symbol": "BKBT", - "owner": "bnb104p50kz2uvep5s5u6j0lr6vkl6rp5g4653d7w4", - "symbol": "BKBT-3A6", - "total_supply": "10000000000.00000000" - }, - { - "mintable": true, - "name": "Binance KRW", - "original_symbol": "BKRW", - "owner": "bnb18kha55gvsxl7gkdh8y329hu3p6wndh6jkwqnxn", - "symbol": "BKRW-AB7", - "total_supply": "1418984074.00000000" - }, - { - "mintable": false, - "name": "Blockmason Link", - "original_symbol": "BLINK", - "owner": "bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew", - "symbol": "BLINK-9C6", - "total_supply": "5000000000.00000000" - }, - { - "mintable": false, - "name": "Binance Chain Native Token", - "original_symbol": "BNB", - "owner": "bnb1ultyhpw2p2ktvr68swz56570lgj2rdsadq3ym2", - "symbol": "BNB", - "total_supply": "179883948.90000000" - }, - { - "mintable": false, - "name": "BOLT Token", - "original_symbol": "BOLT", - "owner": "bnb177ujwmshxu8r9za4vy9ztqn65tmr54ddw958rt", - "symbol": "BOLT-4C6", - "total_supply": "980230000.00000000" - }, - { - "mintable": false, - "name": "Bitcloud Pro", - "original_symbol": "BPRO", - "owner": "bnb1482svhhrffpga5wmqw8068af4c9u2q9dp3hg4m", - "symbol": "BPRO-5A6", - "total_supply": "5000000000.00000000" - }, - { - "mintable": true, - "name": "BQTX", - "original_symbol": "BQTX", - "owner": "bnb1j42h6j40htujnjmtp4ckw4zx27vp0f93cvmua8", - "symbol": "BQTX-235", - "total_supply": "1000000.00000000" - }, - { - "mintable": false, - "name": "BOOSTO", - "original_symbol": "BST2", - "owner": "bnb19k2av7cmdvp9f0qkeu5vfl59yp8ftqv2s55dzs", - "symbol": "BST2-2F2", - "total_supply": "500000000.00000000" - }, - { - "mintable": true, - "name": "Bitcoin BEP2", - "original_symbol": "BTCB", - "owner": "bnb1akey87kt0r8y3fmhu2l8eyzdjvt9ptl5cppz0v", - "symbol": "BTCB-1DE", - "total_supply": "9001.00000000" - }, - { - "mintable": true, - "name": "BTTB", - "original_symbol": "BTTB", - "owner": "bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq", - "symbol": "BTTB-D31", - "total_supply": "1000000000.00000000" - }, - { - "mintable": true, - "name": "3x Long Bitcoin Token", - "original_symbol": "BULL", - "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", - "symbol": "BULL-BE4", - "total_supply": "604.80000000" - }, - { - "mintable": true, - "name": "Binance USD", - "original_symbol": "BUSD", - "owner": "bnb19v2ayq6k6e5x6ny3jdutdm6kpqn3n6mxheegvj", - "symbol": "BUSD-BD1", - "total_supply": "13000000.00000000" - }, - { - "mintable": false, - "name": "Bezant Token", - "original_symbol": "BZNT", - "owner": "bnb1w5a5jywe3cu20uq6n6x3vmzcq342s6st4cz73s", - "symbol": "BZNT-464", - "total_supply": "964511442.00000000" - }, - { - "mintable": false, - "name": "CanYaCoin", - "original_symbol": "CAN", - "owner": "bnb16w59lfh4y2cqvu8f7yr000ll37ldh4w6hnz7l0", - "symbol": "CAN-677", - "total_supply": "95827000.00000000" - }, - { - "mintable": false, - "name": "CASHAA", - "original_symbol": "CAS", - "owner": "bnb1xkw2sagpx6t0cmwzapxpv94tupvqk7tpgy72ku", - "symbol": "CAS-167", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "Cubiex", - "original_symbol": "CBIX", - "owner": "bnb1jlm66w38gpfuqr4s2jcfwlcrlx46p05thdnv7g", - "symbol": "CBIX-3C9", - "total_supply": "150000000.00000000" - }, - { - "mintable": false, - "name": "CryptoBonusMiles", - "original_symbol": "CBM", - "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", - "symbol": "CBM-4B2", - "total_supply": "5000000000.00000000" - }, - { - "mintable": false, - "name": "Clipper Coin", - "original_symbol": "CCCX", - "owner": "bnb1ry99rte8gfnn9c6at9mlmrrq6p2k4u7732j9h7", - "symbol": "CCCX-10D", - "total_supply": "5000000000.00000000" - }, - { - "mintable": false, - "name": "Chiliz", - "original_symbol": "CHZ", - "owner": "bnb1cghr4z8ag440tv4wnk3l6wzynytlpvfqltm9ph", - "symbol": "CHZ-ECD", - "total_supply": "8888888888.00000000" - }, - { - "mintable": false, - "name": "Crypto Neo-value Neural System", - "original_symbol": "CNNS", - "owner": "bnb193wdp4gdnm58urnsjf8nv57lxt58sckt2k50ss", - "symbol": "CNNS-E16", - "total_supply": "10000000000.00000000" - }, - { - "mintable": false, - "name": "Contentos", - "original_symbol": "COS", - "owner": "bnb1u9j9hkst6gf09dkdvxlj7puk8c7vh68a0kkmht", - "symbol": "COS-2E4", - "total_supply": "9400000000.00000000" - }, - { - "mintable": true, - "name": "COTI", - "original_symbol": "COTI", - "owner": "bnb1kn733gkku9xsqkuk6wcz86gftqtl4qvthvrj5m", - "symbol": "COTI-CBB", - "total_supply": "80000000.00000000" - }, - { - "mintable": false, - "name": "Covalent Token", - "original_symbol": "COVA", - "owner": "bnb1pucvxaf3l9rslupza75r9fca9h5892ntumszfm", - "symbol": "COVA-218", - "total_supply": "6500000000.00000000" - }, - { - "mintable": false, - "name": "CPChain", - "original_symbol": "CPC", - "owner": "bnb1wq4rlwrmvvltlarvypql8wrr4vlh0dczd8uksg", - "symbol": "CPC-FED", - "total_supply": "150000000.00000000" - }, - { - "mintable": false, - "name": "Crypterium Token", - "original_symbol": "CRPT", - "owner": "bnb17fk3uvagucxzpvmdvd373fapqsahxvzevdard9", - "symbol": "CRPT-8C9", - "total_supply": "99968575.14285720" - }, - { - "mintable": false, - "name": "“Consentium”", - "original_symbol": "CSM", - "owner": "bnb1gguz7vcrlf7a87et8u5gt40f0890qvkpkn9y79", - "symbol": "CSM-734", - "total_supply": "84000000.00000000" - }, - { - "mintable": true, - "name": "Carbon Dollar", - "original_symbol": "CUSD", - "owner": "bnb1y9797dtklkm3haajsfnevm9ruuxs5fyf5rpj67", - "symbol": "CUSD-24B", - "total_supply": "9999999999.00000000" - }, - { - "mintable": false, - "name": "Konstellation Network", - "original_symbol": "DARC", - "owner": "bnb1gyhnhdns4vf63nfzfq7g25czj8swjgrz3rhah8", - "symbol": "DARC-24B", - "total_supply": "1000000000.00000000" - }, - { - "mintable": true, - "name": "DeepCloud", - "original_symbol": "DEEP", - "owner": "bnb1t0ws9gvnjm7j7qssk8te7m2dt5hmm8s3amqk2d", - "symbol": "DEEP-9D3", - "total_supply": "200000000.00000000" - }, - { - "mintable": false, - "name": "DeFi Token", - "original_symbol": "DEFI", - "owner": "bnb1q5xefr07503pqtfrl5sfyyhlghxwc80d4vpas2", - "symbol": "DEFI-FA5", - "total_supply": "2500000000.00000000" - }, - { - "mintable": true, - "name": "DOS Network Token", - "original_symbol": "DOS", - "owner": "bnb13gse9n7mvrjg5w2cymnt4nmxkgj200k9k2l2nh", - "symbol": "DOS-120", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "DREP", - "original_symbol": "DREP", - "owner": "bnb1ez5s9v4rcgsmhwr4fkrnlv6zwsukjnh4y754kn", - "symbol": "DREP-7D2", - "total_supply": "10000000000.00000000" - }, - { - "mintable": true, - "name": "Dusk Network", - "original_symbol": "DUSK", - "owner": "bnb1dfls6c8y39l7qq4gj2479wkehg85pt5m07y94g", - "symbol": "DUSK-45E", - "total_supply": "50000000.00000000" - }, - { - "mintable": false, - "name": "eBoost", - "original_symbol": "EBST", - "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", - "symbol": "EBST-783", - "total_supply": "80838159.07000000" - }, - { - "mintable": true, - "name": "Ormeus Ecosystem", - "original_symbol": "ECO", - "owner": "bnb1tr49nv08k828n2lqfw0vrgvwj7xtep5kg8wr4c", - "symbol": "ECO-083", - "total_supply": "2200000000.00000000" - }, - { - "mintable": false, - "name": "Energy Eco Token", - "original_symbol": "EET", - "owner": "bnb1pt353m8ygvvgy4f2ud9xx85tl7fqewkrksh6r5", - "symbol": "EET-45C", - "total_supply": "600000000.00000000" - }, - { - "mintable": false, - "name": "Hut34 Entropy", - "original_symbol": "ENTRP", - "owner": "bnb1wu0hu9pelx3yvplysx0je7d93htcandpj86aev", - "symbol": "ENTRP-C8D", - "total_supply": "100000000.00000000" - }, - { - "mintable": true, - "name": "EOS BEP2", - "original_symbol": "EOS", - "owner": "bnb1la8alalwjzkchd67wza3r75lj5rm7m9e85ffqr", - "symbol": "EOS-CDD", - "total_supply": "500000.00000000" - }, - { - "mintable": true, - "name": "3X Short EOS Token", - "original_symbol": "EOSBEAR", - "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", - "symbol": "EOSBEAR-721", - "total_supply": "32301.00000000" - }, - { - "mintable": true, - "name": "3X Long EOS Token", - "original_symbol": "EOSBULL", - "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", - "symbol": "EOSBULL-F0D", - "total_supply": "456191.00000000" - }, - { - "mintable": false, - "name": "EQUAL", - "original_symbol": "EQL", - "owner": "bnb1uz0s54rzv022dh66l7atwk83wqcet9qstgg358", - "symbol": "EQL-586", - "total_supply": "675259060.00000000" - }, - { - "mintable": true, - "name": "Elrond", - "original_symbol": "ERD", - "owner": "bnb1m5uzzfxs7x05sl28gg96zyecn9jwgtkpyeftyn", - "symbol": "ERD-D06", - "total_supply": "14500000000.00000000" - }, - { - "mintable": true, - "name": "ETH BEP2", - "original_symbol": "ETH", - "owner": "bnb1yss2345dphss8c823dh2jzje2w8k8x4jguuxhf", - "symbol": "ETH-1C9", - "total_supply": "10000.00000000" - }, - { - "mintable": true, - "name": "3X Short Ethereum Token", - "original_symbol": "ETHBEAR", - "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", - "symbol": "ETHBEAR-B2B", - "total_supply": "61821.00000000" - }, - { - "mintable": true, - "name": "3X Long Ethereum Token", - "original_symbol": "ETHBULL", - "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", - "symbol": "ETHBULL-D33", - "total_supply": "33684.00000000" - }, - { - "mintable": true, - "name": "everiToken", - "original_symbol": "EVT", - "owner": "bnb1v3fl4kuwuhzf3g7ghscsq7uzmu5dw50waseptd", - "symbol": "EVT-49B", - "total_supply": "1000000000.00000000" - }, - { - "mintable": true, - "name": "The Force Token", - "original_symbol": "FOR", - "owner": "bnb1c46nhwdwm3u2mlfhx6t07fls25shnvktpr9w9m", - "symbol": "FOR-997", - "total_supply": "100000000.00000000" - }, - { - "mintable": false, - "name": "Ferrum Network Token", - "original_symbol": "FRM", - "owner": "bnb1um8ntkgwle8yrdk0yn5hwdf7hckjpyjjg29k2p", - "symbol": "FRM-DE7", - "total_supply": "164609374.50000000" - }, - { - "mintable": false, - "name": "Fusion", - "original_symbol": "FSN", - "owner": "bnb17mnutyduat9fe02r2dawp3kn4rnaqamp5kpg0c", - "symbol": "FSN-E14", - "total_supply": "57344000.00000000" - }, - { - "mintable": true, - "name": "Fantom", - "original_symbol": "FTM", - "owner": "bnb1f6sxnf3nhn9fcfwkuccrzvl2pgu3sq0m8pyjhw", - "symbol": "FTM-A64", - "total_supply": "952500000.00000000" - }, - { - "mintable": true, - "name": "FTX Token", - "original_symbol": "FTT", - "owner": "bnb1msxdh7e7smpg68gxxhs0p3fhuj9tzhrxa4c2x2", - "symbol": "FTT-F11", - "total_supply": "10000000.00000000" - }, - { - "mintable": true, - "name": "Givly Coin", - "original_symbol": "GIV", - "owner": "bnb13jzr6sqz72fl0edg2tpqp8tddyzvyt4su2490m", - "symbol": "GIV-94E", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "GoWithMi", - "original_symbol": "GMAT", - "owner": "bnb1yltla9mnk8999ygmjjn3kwmmz2zs94a9v20sca", - "symbol": "GMAT-FC8", - "total_supply": "14900000000.00000000" - }, - { - "mintable": false, - "name": "Global Gaming", - "original_symbol": "GMNG", - "owner": "bnb1qe6zxqptfxw0kh38t8pg6c3qa527n2x2a87qvm", - "symbol": "GMNG-F3E", - "total_supply": "5000000000.00000000" - }, - { - "mintable": false, - "name": "GTEX", - "original_symbol": "GTEX", - "owner": "bnb1nksrzfl24he9xtvdvpypsl6r5jnh5x2uf9s82z", - "symbol": "GTEX-71B", - "total_supply": "4000000000.00000000" - }, - { - "mintable": false, - "name": "Gifto", - "original_symbol": "GTO", - "owner": "bnb1lvp8k3zenlfp2pl2nyaf428xjgh385m258gzvq", - "symbol": "GTO-908", - "total_supply": "1000000000.00000000" - }, - { - "mintable": true, - "name": "“Hermes", - "original_symbol": "HEC", - "owner": "bnb1dfyydqkmsv5m0rs0pa4uut2gwrcsahppktns2t", - "symbol": "HEC-1A9", - "total_supply": "100000000.00000000" - }, - { - "mintable": false, - "name": "Honest", - "original_symbol": "HNST", - "owner": "bnb1k9fv2hz0w3l9v9z4g9samg3gtc7nc2xgyqw5u0", - "symbol": "HNST-3C9", - "total_supply": "400000000.00000000" - }, - { - "mintable": true, - "name": "Hyperion Token", - "original_symbol": "HYN", - "owner": "bnb1q5cqecuy2g7syl8fssp9a7v2sjamtrzlr3pa0n", - "symbol": "HYN-F21", - "total_supply": "10000000000.00000000" - }, - { - "mintable": true, - "name": "Rupiah Token", - "original_symbol": "IDRTB", - "owner": "bnb1wc44duax6pygh23psx0u945skvs3eh7w59e4sp", - "symbol": "IDRTB-178", - "total_supply": "90000000000.00000000" - }, - { - "mintable": false, - "name": "IKU", - "original_symbol": "IKU", - "owner": "bnb1f52tc9l0qg337qtgu4n024ayllc78wxpc5xhvd", - "symbol": "IKU-416", - "total_supply": "300000000.00000000" - }, - { - "mintable": true, - "name": "IRIS Network", - "original_symbol": "IRIS", - "owner": "bnb1dcpm0jjj8el8g6ekr3mvjxa8kptgu4e5xzvqv8", - "symbol": "IRIS-D88", - "total_supply": "2000000000.00000000" - }, - { - "mintable": false, - "name": "JDXUCoin", - "original_symbol": "JDXU", - "owner": "bnb1dwcsg0t86g7935zpxc054n97styzgdtnu2kzg6", - "symbol": "JDXU-706", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "Kambria Token", - "original_symbol": "KAT", - "owner": "bnb1l68n6equtr925lhnentyq54zfrzqyj45lg8uwj", - "symbol": "KAT-7BB", - "total_supply": "3700000000.00000000" - }, - { - "mintable": true, - "name": "Kava BEP2 Token", - "original_symbol": "KAVA", - "owner": "bnb1uyekdn62yur9zuctzqyd9ckasfvqttjz9c33me", - "symbol": "KAVA-10C", - "total_supply": "6071200.72181900" - }, - { - "mintable": false, - "name": "Sessia Kicks", - "original_symbol": "KICKS", - "owner": "bnb130tmwjd3fc79eh6f5ezl2326ur8rqpsxeeq30x", - "symbol": "KICKS-162", - "total_supply": "5000000.00000000" - }, - { - "mintable": true, - "name": "Lambda", - "original_symbol": "LAMB", - "owner": "bnb19vnwdjwthm9unxe9hxdxmgm6qw0d42d2lmcesw", - "symbol": "LAMB-46C", - "total_supply": "5000000.00000000" - }, - { - "mintable": false, - "name": "Lend-Borrow-Asset", - "original_symbol": "LBA", - "owner": "bnb1m8r74hr532lfwtaf5e88cxeakd36ut0ufpd4yu", - "symbol": "LBA-340", - "total_supply": "1000000000.00000000" - }, - { - "mintable": true, - "name": "LITION", - "original_symbol": "LIT", - "owner": "bnb1fhlxwqlwd7cm5fmurg0wmsaalshnp7lwu46nk9", - "symbol": "LIT-099", - "total_supply": "145061313.45061312" - }, - { - "mintable": true, - "name": "Loki", - "original_symbol": "LOKI", - "owner": "bnb1j5sft8wp7tktjwauy30x79f3tqa53fycmgxxs0", - "symbol": "LOKI-6A9", - "total_supply": "3000000.00000000" - }, - { - "mintable": true, - "name": "LTC BEP2", - "original_symbol": "LTC", - "owner": "bnb1cn4sqm79wqmr8rey923r34cp2wrtyhlr9easpg", - "symbol": "LTC-F07", - "total_supply": "18500.00000000" - }, - { - "mintable": false, - "name": "LTO Network", - "original_symbol": "LTO", - "owner": "bnb1ac6p45m00pv36y9mu48e5xr73fyxke3zv2rhmq", - "symbol": "LTO-BDF", - "total_supply": "500000000.00000000" - }, - { - "mintable": false, - "name": "Matic Token", - "original_symbol": "MATIC", - "owner": "bnb1a6nkf3g7c2z0jcrqhp8c9upcwmme0y49qx58nz", - "symbol": "MATIC-84A", - "total_supply": "10000000000.00000000" - }, - { - "mintable": false, - "name": "Moviebloc", - "original_symbol": "MBL", - "owner": "bnb17p8rc0z5vlysff2wc7xehff464dm0v7nhl27xq", - "symbol": "MBL-2D2", - "total_supply": "30000000000.00000000" - }, - { - "mintable": true, - "name": "Mcashchain", - "original_symbol": "MCASH", - "owner": "bnb1q420q7qpyv7tghfp6aac7vnjq74dhkeutdhqsg", - "symbol": "MCASH-869", - "total_supply": "200000000.00000000" - }, - { - "mintable": false, - "name": "Magic Cube Token", - "original_symbol": "MCC", - "owner": "bnb14nt79d6hzhjefkys2cgrc9nrzugdjwwtggfmu4", - "symbol": "MCC-33B", - "total_supply": "20000000000.00000000" - }, - { - "mintable": false, - "name": "MDAB", - "original_symbol": "MDAB", - "owner": "bnb1m3edd4q4nd3wxg9vm3xe8pnfnetu5yjmhtnrqz", - "symbol": "MDAB-D42", - "total_supply": "1000000000.00000000" - }, - { - "mintable": true, - "name": "MediBloc", - "original_symbol": "MEDB", - "owner": "bnb1za3ytyh55wprmn4ew8gat657lpjdzhafwrded3", - "symbol": "MEDB-87E", - "total_supply": "10000000000.00000000" - }, - { - "mintable": false, - "name": "MEET.ONE", - "original_symbol": "MEETONE", - "owner": "bnb1zquk6usn03xnnht6ws6p0h4ylgk8jkhch6c6ck", - "symbol": "MEETONE-031", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "SyncFab Smart Manufacturing", - "original_symbol": "MFGB", - "owner": "bnb104qhlkx4fu6nvm32v4k7zzgtt4eqtyzvh9yq48", - "symbol": "MFGB-0A0", - "total_supply": "100000000.00000000" - }, - { - "mintable": false, - "name": "Mithril", - "original_symbol": "MITH", - "owner": "bnb15krsh6x2343qskf86cw0hazchl5pkfw53zllut", - "symbol": "MITH-C76", - "total_supply": "988855068.00409432" - }, - { - "mintable": false, - "name": "Morpheus Infrastructure Token", - "original_symbol": "MITX", - "owner": "bnb17e2n869fp6zvdyfaqkq3tgfmj8pskq20mdaz7e", - "symbol": "MITX-CAA", - "total_supply": "400000000.00000000" - }, - { - "mintable": false, - "name": "MultiVAC", - "original_symbol": "MTV", - "owner": "bnb18cjgqwpj2sxdxf7u84hgzh76cmqvthw7fgtr7z", - "symbol": "MTV-4C6", - "total_supply": "8000000000.00000000" - }, - { - "mintable": false, - "name": "Tixl", - "original_symbol": "MTXLT", - "owner": "bnb1pwcluc3a2lswrdd8v3uq43qrgfdl6kv2ahrz43", - "symbol": "MTXLT-286", - "total_supply": "900000.00000000" - }, - { - "mintable": true, - "name": "Mass Vehicle Ledger", - "original_symbol": "MVL", - "owner": "bnb1mqdkp0ujngm58sus3fh5x9c0j59madqxej9q75", - "symbol": "MVL-7B0", - "total_supply": "8000000000.00000000" - }, - { - "mintable": false, - "name": "Muzika", - "original_symbol": "MZK", - "owner": "bnb1dkqsj76yr6nlegs3433m3c59mm0j7vy72nn275", - "symbol": "MZK-2C7", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "NEWTON", - "original_symbol": "NEW", - "owner": "bnb1ud4ak7pj5kg5kqddhx9yacdu6sf7sxhqdv30k0", - "symbol": "NEW-09E", - "total_supply": "90000000000.00000000" - }, - { - "mintable": true, - "name": "Nexo", - "original_symbol": "NEXO", - "owner": "bnb15ngukylwcleljegx32ykefqxw8jz42szar6vf5", - "symbol": "NEXO-A84", - "total_supply": "100000000.00000000" - }, - { - "mintable": false, - "name": "NODE", - "original_symbol": "NODE", - "owner": "bnb1xljnjk7msm5t5lwp4zv2ua80rrxzn2s2afce4j", - "symbol": "NODE-F3A", - "total_supply": "2000000000.00000000" - }, - { - "mintable": false, - "name": "NOIZ Token", - "original_symbol": "NOIZB", - "owner": "bnb1fa9xgszkn57zq0aulfgk5hct09yx5heepum3x7", - "symbol": "NOIZB-878", - "total_supply": "400000000.00000000" - }, - { - "mintable": true, - "name": "NOW Token", - "original_symbol": "NOW", - "owner": "bnb1nug8ls9f0et0t558m4chmm46mf85ehpq0u8gwv", - "symbol": "NOW-E68", - "total_supply": "99939495.70000000" - }, - { - "mintable": false, - "name": "NPX Binance token", - "original_symbol": "NPXB", - "owner": "bnb1wf7z3e8wvcu7gs74stmfmktsa2m5738rd0znae", - "symbol": "NPXB-1E8", - "total_supply": "29800000.00000000" - }, - { - "mintable": false, - "name": "Pundi X NEM", - "original_symbol": "NPXSXEM", - "owner": "bnb1wuww3cqy6wn5jdp6emv0eqwd5khlc3qyy0ympp", - "symbol": "NPXSXEM-89C", - "total_supply": "44815631324.40000000" - }, - { - "mintable": true, - "name": "Harmony.One", - "original_symbol": "ONE", - "owner": "bnb1a03uvqmnqzl85csnxnsx2xy28m76gkkht46f2l", - "symbol": "ONE-5F9", - "total_supply": "12600000000.00000000" - }, - { - "mintable": true, - "name": "ONTBEP2", - "original_symbol": "ONT", - "owner": "bnb1lxlxzanvg5ud02vjcvuxqrdystcehvtj6a05s2", - "symbol": "ONT-33D", - "total_supply": "1500000.00000000" - }, - { - "mintable": false, - "name": "OpenWeb Token", - "original_symbol": "OWTX", - "owner": "bnb1qnzqrxpek5dy6hh4fjywjv60x806yv2kpwt64y", - "symbol": "OWTX-A6B", - "total_supply": "1000000000.00000000" - }, - { - "mintable": true, - "name": "Pink Care Token", - "original_symbol": "PCAT", - "owner": "bnb1xx54pavpran2c36ugvnxnrfszwn36cryqfzufa", - "symbol": "PCAT-4BB", - "total_supply": "50000.00000000" - }, - { - "mintable": true, - "name": "Red Pulse Phoenix Binance", - "original_symbol": "PHB", - "owner": "bnb1vvvm62cezjy35xa46lghjs2jthzzdlpfyqg90a", - "symbol": "PHB-2DF", - "total_supply": "1598758851.80873855" - }, - { - "mintable": true, - "name": "PathHive Network", - "original_symbol": "PHV", - "owner": "bnb13nltf0vw66kw737dej6kc0fy85u3a38avr0xmf", - "symbol": "PHV-4A1", - "total_supply": "350000000.00000000" - }, - { - "mintable": false, - "name": "PCHAIN Token", - "original_symbol": "PIBNB", - "owner": "bnb1lvq8c3ul472aqrsknnvqumjszt2v60s0zagw6r", - "symbol": "PIBNB-43C", - "total_supply": "1071000000.00000000" - }, - { - "mintable": false, - "name": "Pledge Coin", - "original_symbol": "PLG", - "owner": "bnb1wjxhqa6ud4ucxayjqd9necfq0n954ztncsn7zn", - "symbol": "PLG-D8D", - "total_supply": "10000000000.00000000" - }, - { - "mintable": true, - "name": "PPE Token", - "original_symbol": "PPE", - "owner": "bnb1ry96fn3gl3wskha86lhgx8ckrgt3vgrnwq8quz", - "symbol": "PPE-942", - "total_supply": "200000.00000000" - }, - { - "mintable": false, - "name": "Pivot Token", - "original_symbol": "PVT", - "owner": "bnb1vgzzktw8j46hd87npsrukxhzxecq8knnt96tyf", - "symbol": "PVT-554", - "total_supply": "6283185307.00000000" - }, - { - "mintable": false, - "name": "paycentos", - "original_symbol": "PYN", - "owner": "bnb190acfwshh899eylweut9xarls2ma953rvkdlhf", - "symbol": "PYN-C37", - "total_supply": "100000000.00000000" - }, - { - "mintable": false, - "name": "QARK", - "original_symbol": "QARK", - "owner": "bnb1wnwrnmc6y9pl6ve9g7mahd4wkactaldyx3hsmu", - "symbol": "QARK-FCE", - "total_supply": "77000000.00000000" - }, - { - "mintable": true, - "name": "qiibeeToken", - "original_symbol": "QBX", - "owner": "bnb1eq8cytar7a3rer3ms7dpatd3cuhpfhaw3ts6tr", - "symbol": "QBX-38C", - "total_supply": "138039216.00000000" - }, - { - "mintable": false, - "name": "Raven Protocol", - "original_symbol": "RAVEN", - "owner": "bnb1vdjhrkgvt4y76ykyvrvh68pzqg3lvv0y5yfxyf", - "symbol": "RAVEN-F66", - "total_supply": "10000000000.00000000" - }, - { - "mintable": true, - "name": "Reporter News Agency Token", - "original_symbol": "RNA", - "owner": "bnb1m033d9a5fuf6r8wxqcguhwrnnk7sffcljzrc83", - "symbol": "RNA-23B", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "Rasputin Party Mansion Phase2", - "original_symbol": "ROCP2", - "owner": "bnb16fyhf2hw8d5raxtympp48nzt2ezw6dqvfv5cd3", - "symbol": "ROCP2-F01", - "total_supply": "27000000.00000000" - }, - { - "mintable": false, - "name": "Rapids", - "original_symbol": "RPD", - "owner": "bnb1vtpy8dly2jfsn6v3t0qnyfxrex9sdy0entp5zs", - "symbol": "RPD-9E0", - "total_supply": "1500000000.00000000" - }, - { - "mintable": false, - "name": "Rune", - "original_symbol": "RUNE", - "owner": "bnb1e4q8whcufp6d72w8nwmpuhxd96r4n0fstegyuy", - "symbol": "RUNE-B1A", - "total_supply": "500000000.00000000" - }, - { - "mintable": false, - "name": "ShareToken", - "original_symbol": "SHR", - "owner": "bnb12c94hfu5vm77a9xkwfyl2ztgwgk503a06zl70e", - "symbol": "SHR-DB6", - "total_supply": "4396000000.00000000" - }, - { - "mintable": false, - "name": "Silverway", - "original_symbol": "SLV", - "owner": "bnb15nhdv2m09uwgnmmhx73dcguag7n363fdzdsg23", - "symbol": "SLV-986", - "total_supply": "1000000000.00000000" - }, - { - "mintable": true, - "name": "SPIN Protocol", - "original_symbol": "SPIN", - "owner": "bnb12n8fqjp8vh00s5u89paewv0wk8avr3nyvhsl4j", - "symbol": "SPIN-9DD", - "total_supply": "100000000.00000000" - }, - { - "mintable": true, - "name": "Spendcoin", - "original_symbol": "SPNDB", - "owner": "bnb105n32ugq55kzlyz3tuug35d3t0ul37lx9aksah", - "symbol": "SPNDB-916", - "total_supply": "2000000000.00000000" - }, - { - "mintable": false, - "name": "STIPS Token", - "original_symbol": "STIPS", - "owner": "bnb1tug8sgfcuh0rdyr697k5pnwz9expj7v5zr3qs5", - "symbol": "STIPS-14F", - "total_supply": "128806335.86000000" - }, - { - "mintable": false, - "name": "STIPS", - "original_symbol": "STIPS", - "owner": "bnb1tug8sgfcuh0rdyr697k5pnwz9expj7v5zr3qs5", - "symbol": "STIPS-770", - "total_supply": "243585434.00000000" - }, - { - "mintable": false, - "name": "Yin Lang Music IP Token", - "original_symbol": "STYL", - "owner": "bnb1j2dgknw9l4jny8crjdn6vcjsnu23ejxhchrumg", - "symbol": "STYL-65B", - "total_supply": "100000.00000000" - }, - { - "mintable": false, - "name": "Swingby Token", - "original_symbol": "SWINGBY", - "owner": "bnb1thagrtfude74x2j2wuknhj2savucy2tx0k58y9", - "symbol": "SWINGBY-888", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "SWIPE Token", - "original_symbol": "SWIPE.B", - "owner": "bnb17pwyw202w7fssznnnv8f2gukau49uc4m4chz4m", - "symbol": "SWIPE.B-DC0", - "total_supply": "1500000000.00000000" - }, - { - "mintable": true, - "name": "TrueAUD", - "original_symbol": "TAUDB", - "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", - "symbol": "TAUDB-888", - "total_supply": "90000000000.00000000" - }, - { - "mintable": true, - "name": "TBCC Coin", - "original_symbol": "TBC", - "owner": "bnb18hvknjyd73dx3ud02zp3z8v6du50vw7jxp06xt", - "symbol": "TBC-3A7", - "total_supply": "1000000000.00000000" - }, - { - "mintable": true, - "name": "TrueCAD", - "original_symbol": "TCADB", - "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", - "symbol": "TCADB-888", - "total_supply": "90000000000.00000000" - }, - { - "mintable": false, - "name": "TrustED Token", - "original_symbol": "TED", - "owner": "bnb1zwg63xvmn02u8lv8v2sq0ypaejehhv3fceeu8a", - "symbol": "TED-A85", - "total_supply": "1720000000.00000000" - }, - { - "mintable": true, - "name": "TrueGBP", - "original_symbol": "TGBPB", - "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", - "symbol": "TGBPB-888", - "total_supply": "90000000000.00000000" - }, - { - "mintable": true, - "name": "TrueHKD", - "original_symbol": "THKDB", - "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", - "symbol": "THKDB-888", - "total_supply": "90000000000.00000000" - }, - { - "mintable": false, - "name": "Traxia 2", - "original_symbol": "TM2", - "owner": "bnb1pdeggk7lgch37ks7e3l5x3n5y245krl3zmrl8e", - "symbol": "TM2-0C4", - "total_supply": "1000000000.00000000" - }, - { - "mintable": true, - "name": "TomoChain", - "original_symbol": "TOMOB", - "owner": "bnb1jmgew0xvtkfjhnqsglm50tynxgps3xkx0xqffy", - "symbol": "TOMOB-4BC", - "total_supply": "5000000.00000000" - }, - { - "mintable": false, - "name": "TOP Network", - "original_symbol": "TOP", - "owner": "bnb1lqc7vjrag9sdaqeuv22jccr4rxtdxdtq6ve2w6", - "symbol": "TOP-491", - "total_supply": "20000000000.00000000" - }, - { - "mintable": false, - "name": "TROY", - "original_symbol": "TROY", - "owner": "bnb1scrark2sv6fpngyqxrryw9hw7y05euwntz45ae", - "symbol": "TROY-9B8", - "total_supply": "10000000000.00000000" - }, - { - "mintable": false, - "name": "TrueChain", - "original_symbol": "TRUE", - "owner": "bnb1m0llwxe0nwtw98m7knpz3g7r0c98mwn7tfwjcc", - "symbol": "TRUE-D84", - "total_supply": "100000000.00000000" - }, - { - "mintable": true, - "name": "TRXB", - "original_symbol": "TRXB", - "owner": "bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq", - "symbol": "TRXB-2E6", - "total_supply": "100000000.00000000" - }, - { - "mintable": true, - "name": "TrueUSD", - "original_symbol": "TUSDB", - "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", - "symbol": "TUSDB-888", - "total_supply": "90000000000.00000000" - }, - { - "mintable": false, - "name": "Trust Wallet", - "original_symbol": "TWT", - "owner": "bnb1fkyxlq9kz5368ux29aeeztslclgf8e7tja345x", - "symbol": "TWT-8C2", - "total_supply": "90000000000.00000000" - }, - { - "mintable": true, - "name": "“Ubet", - "original_symbol": "UBETS", - "owner": "bnb1gcpctmgmf0am0ft85ttswy2epd9d6vvvxu2ly6", - "symbol": "UBETS-068", - "total_supply": "4000000000.00000000" - }, - { - "mintable": false, - "name": "Ultrain Coin", - "original_symbol": "UGAS", - "owner": "bnb1mj2nncwkmrw9pr6d0spkfmewz5eynz63w67f6e", - "symbol": "UGAS-B0C", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "United Network Distribution", - "original_symbol": "UND", - "owner": "bnb1q5tr6ggvg0h38axzw2dc4606j3edg58qug9ajr", - "symbol": "UND-EBC", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "UPX", - "original_symbol": "UPX", - "owner": "bnb1588jx9ylvfpfhdzy672lk3pulleq8md0a4wcjl", - "symbol": "UPX-F3E", - "total_supply": "10000000000.00000000" - }, - { - "mintable": true, - "name": "HonestCoin", - "original_symbol": "USDH", - "owner": "bnb1kel6x8nl37j2w6963c3gxnwzplvkwkphrkdmx9", - "symbol": "USDH-5B5", - "total_supply": "10000000000.00000000" - }, - { - "mintable": true, - "name": "USDS", - "original_symbol": "USDSB", - "owner": "bnb1nf5qjthrmxwxnfct4j0w4ct03fghthq24qt990", - "symbol": "USDSB-1AC", - "total_supply": "90000000000.00000000" - }, - { - "mintable": false, - "name": "UTU Coin", - "original_symbol": "UTU", - "owner": "bnb1r7whkqt8q2efn3c2ynsshrvxkg07cu8etuxkwr", - "symbol": "UTU-159", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "UNetwork Token", - "original_symbol": "UUU", - "owner": "bnb17mkwwvzxaxa792rggvcmrpe6d7la4j9tjhdaql", - "symbol": "UUU-35C", - "total_supply": "10000000000.00000000" - }, - { - "mintable": true, - "name": "Vodi X", - "original_symbol": "VDX", - "owner": "bnb1pk6umuhxjcd3ggyztw7a7lfggwgyyx2w5h8j59", - "symbol": "VDX-A17", - "total_supply": "300000000.00000000" - }, - { - "mintable": false, - "name": "V-ID Token", - "original_symbol": "VIDT", - "owner": "bnb1k8870xayp29jug2lw9ujcqnjv6q6nu92enkg8v", - "symbol": "VIDT-F53", - "total_supply": "36800171.30000000" - }, - { - "mintable": true, - "name": "VNDC", - "original_symbol": "VNDC", - "owner": "bnb1zxt4xh4xxdnv5aagh77a4zp2kflg6a2c22hp73", - "symbol": "VNDC-DB9", - "total_supply": "2050000000.00000000" - }, - { - "mintable": false, - "name": "Vote", - "original_symbol": "VOTE", - "owner": "bnb1px34z7hw3hjtcf4ul664azxl4jwmkvgdnfep5e", - "symbol": "VOTE-FD4", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "VERA", - "original_symbol": "VRAB", - "owner": "bnb1ucrwnsvjetufca3u6hnqskz0jfrwascwzg5tyf", - "symbol": "VRAB-B56", - "total_supply": "10839985784.00000000" - }, - { - "mintable": true, - "name": "Wagerr", - "original_symbol": "WGR", - "owner": "bnb194yuu322fqk69g2el8c874np5hjc8fykft3wv3", - "symbol": "WGR-D3D", - "total_supply": "205000000.00000000" - }, - { - "mintable": true, - "name": "WaykiChain Coin", - "original_symbol": "WICC", - "owner": "bnb1cw6kw5q0xcaxvpqravfewrcca9jgkdmd3zpc5n", - "symbol": "WICC-01D", - "total_supply": "210000000.00000000" - }, - { - "mintable": true, - "name": "WINB", - "original_symbol": "WINB", - "owner": "bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq", - "symbol": "WINB-41F", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "MyWish", - "original_symbol": "WISH", - "owner": "bnb1tawge8u97slduhhtumm03l4xl4c46dwv5m9yzk", - "symbol": "WISH-2D5", - "total_supply": "9546650.62357825" - }, - { - "mintable": false, - "name": "WazirX Token", - "original_symbol": "WRX", - "owner": "bnb19cvhgyrxmkw30hlqs9c5lp966drjzyylytl74z", - "symbol": "WRX-ED1", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "Eterbase Coin", - "original_symbol": "XBASE", - "owner": "bnb177v0mn59lmuxu90uph5mg065n9l4f3r4zqllvd", - "symbol": "XBASE-CD2", - "total_supply": "1000000000.00000000" - }, - { - "mintable": false, - "name": "XIO", - "original_symbol": "XIO", - "owner": "bnb1egwrlcwqkluqpujfwc5r2d27ggg7kv0lteyez9", - "symbol": "XIO-B05", - "total_supply": "100000000.00000000" - }, - { - "mintable": true, - "name": "Xeonbit Token", - "original_symbol": "XNS", - "owner": "bnb17az2n3ll3wjgf3gnn2chqxawzgrv9xv9vrkc79", - "symbol": "XNS-760", - "total_supply": "300000000.00000000" - }, - { - "mintable": true, - "name": "XRP BEP2", - "original_symbol": "XRP", - "owner": "bnb1x0vv5l6u5c7vpl7c947uxmm0gfstpdhg93gxpt", - "symbol": "XRP-BF2", - "total_supply": "10000000.00000000" - }, - { - "mintable": true, - "name": "3X Short XRP Token", - "original_symbol": "XRPBEAR", - "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", - "symbol": "XRPBEAR-00B", - "total_supply": "1348.00000000" - }, - { - "mintable": true, - "name": "3X Long XRP Token", - "original_symbol": "XRPBULL", - "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", - "symbol": "XRPBULL-E7C", - "total_supply": "121291.00000000" - }, - { - "mintable": true, - "name": "XTZ BEP2", - "original_symbol": "XTZ", - "owner": "bnb12twkcedchmx3xn09jcf28u7xrg0mqsyluf56g4", - "symbol": "XTZ-F7A", - "total_supply": "250000.00000000" - }, - { - "mintable": false, - "name": "XWG", - "original_symbol": "XWG", - "owner": "bnb10s02g69vhym56ke23nkacmuf9038e8rr7dm8e8", - "symbol": "XWG-478", - "total_supply": "10000000000.00000000" - }, - { - "mintable": false, - "name": "“YeeCo”", - "original_symbol": "YEE", - "owner": "bnb1ykzzc0zevzsade3urq4t27rfz98xgquphm8ucs", - "symbol": "YEE-EAE", - "total_supply": "10000000000.00000000" - }, - { - "mintable": false, - "name": "ZEBI", - "original_symbol": "ZEBI", - "owner": "bnb1gca96lw9zlr8fct47wznsae67pc5wjwsjzamaf", - "symbol": "ZEBI-84F", - "total_supply": "1000000000.00000000" - } -] diff --git a/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json b/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json deleted file mode 100644 index e08c30bad..000000000 --- a/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json +++ /dev/null @@ -1 +0,0 @@ -{"tx":[{"txHash":"0CE23D9F143F7FAF192BB55F33C8FCBC1095D98410A750F63777987685E2C154","blockHeight":106690566,"txType":"TRANSFER","timeStamp":"2020-08-12T10:18:26.388Z","fromAddr":"bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m","toAddr":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","value":"6018.97200000","txAsset":"RUNE-B1A","txFee":"0.00037500","proposalId":null,"txAge":8026,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"","source":0,"sequence":736321}],"total":1} diff --git a/platform/binance/base_test.go b/platform/binance/base_test.go index 10cf81163..9d633904b 100644 --- a/platform/binance/base_test.go +++ b/platform/binance/base_test.go @@ -25,42 +25,42 @@ const ( func createMockedAPI() http.Handler { r := http.NewServeMux() - r.HandleFunc("/v1/node-info", func(w http.ResponseWriter, r *http.Request) { + r.HandleFunc("/api/v1/node-info", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) if _, err := fmt.Fprint(w, mockedNodeInfo); err != nil { panic(err) } }) - r.HandleFunc("/v2/transactions-in-block/104867508", func(w http.ResponseWriter, r *http.Request) { + r.HandleFunc("/api/v2/transactions-in-block/104867508", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) if _, err := fmt.Fprint(w, mockedBlockResponse); err != nil { panic(err) } }) - r.HandleFunc("/v2/transactions-in-block/105529271", func(w http.ResponseWriter, r *http.Request) { + r.HandleFunc("/api/v2/transactions-in-block/105529271", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) if _, err := fmt.Fprint(w, wantedBlockResponseMulti); err != nil { panic(err) } }) - r.HandleFunc("/v1/tokens", func(w http.ResponseWriter, r *http.Request) { + r.HandleFunc("/api/v1/tokens", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) if _, err := fmt.Fprint(w, wantedTokensResponse); err != nil { panic(err) } }) - r.HandleFunc("/v1/account/bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", func(w http.ResponseWriter, r *http.Request) { + r.HandleFunc("/api/v1/account/bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) if _, err := fmt.Fprint(w, wantedAccountMetaResponse); err != nil { panic(err) } }) - r.HandleFunc("/v1/transactions", func(w http.ResponseWriter, r *http.Request) { + r.HandleFunc("/api/v1/transactions", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) var ( address = r.URL.Query().Get("address") diff --git a/platform/binance/client.go b/platform/binance/client.go index b2a1792ca..3229fb9d6 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -21,7 +21,7 @@ func InitClient(url string) Client { } func (c Client) FetchLatestBlockNumber() (int64, error) { - resp, err := req.Get(c.url+"/v1/node-info", nil) + resp, err := req.Get(c.url+"/api/v1/node-info", nil) if err != nil { return 0, err } @@ -35,7 +35,7 @@ func (c Client) FetchLatestBlockNumber() (int64, error) { } func (c Client) FetchTransactionsInBlock(blockNumber int64) (TransactionsInBlockResponse, error) { - resp, err := req.Get(c.url+fmt.Sprintf("/v2/transactions-in-block/%d", blockNumber), nil) + resp, err := req.Get(c.url+fmt.Sprintf("/api/v2/transactions-in-block/%d", blockNumber), nil) if err != nil { return TransactionsInBlockResponse{}, err } @@ -52,7 +52,7 @@ func (c Client) FetchTransactionsByAddressAndTokenID(address, tokenID string) ([ startTime := strconv.Itoa(int(time.Now().AddDate(0, -3, 0).Unix() * 1000)) limit := strconv.Itoa(blockatlas.TxPerPage) params := url.Values{"address": {address}, "txAsset": {tokenID}, "startTime": {startTime}, "limit": {limit}} - resp, err := req.Get(c.url+"/v1/transactions", params) + resp, err := req.Get(c.url+"/api/v1/transactions", params) if err != nil { return nil, err } @@ -66,7 +66,7 @@ func (c Client) FetchTransactionsByAddressAndTokenID(address, tokenID string) ([ } func (c Client) FetchAccountMeta(address string) (AccountMeta, error) { - resp, err := req.Get(c.url+fmt.Sprintf("/v1/account/%s", address), nil) + resp, err := req.Get(c.url+fmt.Sprintf("/api/v1/account/%s", address), nil) if err != nil { return AccountMeta{}, err } @@ -86,7 +86,7 @@ func (c Client) FetchTokens() (Tokens, error) { } result := new(Tokens) query := url.Values{"limit": {tokensLimit}} - resp, err := req.Get(c.url+"/v1/tokens", query) + resp, err := req.Get(c.url+"/api/v1/tokens", query) if err != nil { return nil, err } diff --git a/platform/bitcoin/client.go b/platform/bitcoin/client.go index a1c400602..6e3df4753 100644 --- a/platform/bitcoin/client.go +++ b/platform/bitcoin/client.go @@ -13,7 +13,7 @@ type Client struct { } func (c *Client) GetTransactions(address string) (transactions TransactionsList, err error) { - path := fmt.Sprintf("v2/address/%s", address) + path := fmt.Sprintf("api/v2/address/%s", address) err = c.Get(&transactions, path, url.Values{ "details": {"txs"}, "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, @@ -22,7 +22,7 @@ func (c *Client) GetTransactions(address string) (transactions TransactionsList, } func (c *Client) GetTransactionsByXpub(xpub string) (transactions TransactionsList, err error) { - path := fmt.Sprintf("v2/xpub/%s", xpub) + path := fmt.Sprintf("api/v2/xpub/%s", xpub) args := url.Values{ "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, "details": {"txs"}, @@ -33,7 +33,7 @@ func (c *Client) GetTransactionsByXpub(xpub string) (transactions TransactionsLi } func (c *Client) GetAddressesFromXpub(xpub string) (tokens []Token, err error) { - path := fmt.Sprintf("v2/xpub/%s", xpub) + path := fmt.Sprintf("api/v2/xpub/%s", xpub) args := url.Values{ "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, "details": {"txs"}, @@ -45,7 +45,7 @@ func (c *Client) GetAddressesFromXpub(xpub string) (tokens []Token, err error) { } func (c *Client) GetTransactionsByBlock(number int64, page int64) (block TransactionsList, err error) { - path := fmt.Sprintf("v2/block/%s", strconv.FormatInt(number, 10)) + path := fmt.Sprintf("api/v2/block/%s", strconv.FormatInt(number, 10)) args := url.Values{ "page": {strconv.FormatInt(page, 10)}, } @@ -54,6 +54,6 @@ func (c *Client) GetTransactionsByBlock(number int64, page int64) (block Transac } func (c *Client) GetBlockNumber() (status BlockchainStatus, err error) { - err = c.Get(&status, "v2", nil) + err = c.Get(&status, "api", nil) return status, err } diff --git a/platform/ethereum/blockbook/client.go b/platform/ethereum/blockbook/client.go index 1fd894cdc..ea9717e4c 100644 --- a/platform/ethereum/blockbook/client.go +++ b/platform/ethereum/blockbook/client.go @@ -25,7 +25,7 @@ func (c *Client) GetTokens(address string) ([]Token, error) { func (c *Client) GetCurrentBlockNumber() (int64, error) { var nodeInfo NodeInfo - err := c.Get(&nodeInfo, "", nil) + err := c.Get(&nodeInfo, "api", nil) if err != nil { return 0, err } @@ -33,13 +33,13 @@ func (c *Client) GetCurrentBlockNumber() (int64, error) { } func (c *Client) GetBlock(num int64) (block Block, err error) { - path := fmt.Sprintf("v2/block/%d", num) + path := fmt.Sprintf("api/v2/block/%d", num) err = c.Get(&block, path, nil) return } func (c *Client) getTransactions(address, contract string) (page *Page, err error) { - path := fmt.Sprintf("v2/address/%s", address) + path := fmt.Sprintf("api/v2/address/%s", address) query := url.Values{"page": {"1"}, "pageSize": {"25"}, "details": {"txs"}, "contract": {contract}} err = c.Get(&page, path, query) return @@ -47,7 +47,7 @@ func (c *Client) getTransactions(address, contract string) (page *Page, err erro func (c *Client) getTokens(address string) ([]Token, error) { var res Page - path := fmt.Sprintf("v2/address/%s", address) + path := fmt.Sprintf("api/v2/address/%s", address) query := url.Values{"details": {"tokenBalances"}} err := c.Get(&res, path, query) diff --git a/tests/postman/token_data.json b/tests/postman/token_data.json index f53b1c75e..476e64773 100644 --- a/tests/postman/token_data.json +++ b/tests/postman/token_data.json @@ -27,10 +27,6 @@ "handler": "ethereum", "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" }, - { - "handler": "binance", - "address": "bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q" - }, { "handler": "classic", "address": "0xa12105efa0663147bddee178f6a741ac15676b79" diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index b594767d7..a4f8b4dea 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -83,12 +83,6 @@ "expectedTxNum": 2, "expectedTxId": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78" }, - { - "handler": "binance", - "address": "bnb1z35wusfv8twfele77vddclka9z84ugywug48gn", - "expectedTxNum": 1, - "expectedTxId": "0CE23D9F143F7FAF192BB55F33C8FCBC1095D98410A750F63777987685E2C154" - }, { "handler": "tezos", "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", From de10f68c4635c2c19670ec971944715989df3cd6 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Tue, 25 Aug 2020 21:11:52 +0300 Subject: [PATCH 362/506] [Tokens] Add new temp tokens api (#1199) * Add new temp tokens api * Fix lint * Tokens v2 struct fix * Remove v3 * Lint fixes --- api/endpoint/token.go | 42 ++++++++++++++++++++++++++---------------- platform/tron/token.go | 4 +++- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index f1535f13f..84da5b7fc 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -9,6 +9,13 @@ import ( "time" ) +type ( + tokensResult struct { + Result blockatlas.TokenPage + mu sync.Mutex + } +) + // @Summary Get Tokens // @ID tokens // @Description Get tokens from the address @@ -50,7 +57,11 @@ func GetTokens(c *gin.Context, apis map[uint]blockatlas.TokensAPI) { c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return } - result := make(blockatlas.TokenPage, 0) + result := tokensResult{ + Result: make(blockatlas.TokenPage, 0), + mu: sync.Mutex{}, + } + var wg sync.WaitGroup for coinStr, addresses := range query { coinNum, err := strconv.ParseUint(coinStr, 10, 32) if err != nil { @@ -60,23 +71,22 @@ func GetTokens(c *gin.Context, apis map[uint]blockatlas.TokensAPI) { if !ok { continue } - - tokens := getTokens(api, addresses) - result = append(result, tokens...) + wg.Add(1) + go getTokens(api, addresses, &result, &wg) } - c.JSON(http.StatusOK, blockatlas.ResultsResponse{Total: len(result), Results: &result}) + wg.Wait() + c.JSON(http.StatusOK, blockatlas.ResultsResponse{Total: len(result.Result), Results: &result.Result}) } -func getTokens(tokenAPI blockatlas.TokensAPI, addresses []string) blockatlas.TokenPage { +func getTokens(tokenAPI blockatlas.TokensAPI, addresses []string, data *tokensResult, wg *sync.WaitGroup) { var ( tokenPagesChan = make(chan blockatlas.TokenPage, len(addresses)) - wg sync.WaitGroup - result blockatlas.TokenPage + wgLocal sync.WaitGroup timeout = time.Second * 3 ) - + defer wg.Done() for _, address := range addresses { - wg.Add(1) + wgLocal.Add(1) go func(address string, wg *sync.WaitGroup) { defer wg.Done() @@ -102,14 +112,14 @@ func getTokens(tokenAPI blockatlas.TokensAPI, addresses []string) blockatlas.Tok case p := <-pageChan: tokenPagesChan <- p } - }(address, &wg) + }(address, &wgLocal) } - wg.Wait() + wgLocal.Wait() close(tokenPagesChan) - + data.mu.Lock() for page := range tokenPagesChan { - result = append(result, page...) + r := data.Result + data.Result = append(r, page...) } - - return result + data.mu.Unlock() } diff --git a/platform/tron/token.go b/platform/tron/token.go index e46aaf8cf..8b15aa6c8 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -5,6 +5,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" "sync" + "time" ) func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { @@ -53,9 +54,10 @@ func (p *Platform) getTokens(ids []string) chan blockatlas.Token { wg.Add(1) go func(i string, c chan blockatlas.Token) { defer wg.Done() + time.Sleep(time.Millisecond) err := p.getTokensChannel(i, c) if err != nil { - logger.Error(err) + logger.Error("TRON getTokens token: " + i) } }(id, tkChan) } From 3523d03e649abb2eb7c2ab7773de2ae0c4253603 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Tue, 25 Aug 2020 21:36:25 +0300 Subject: [PATCH 363/506] Workflow cleanup (#1200) --- .github/workflows/pr-build.yml | 2 +- .github/workflows/pr-tests.yml | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 8647e99c9..1b81a1b5a 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -1,4 +1,4 @@ -name: PRBuild +name: Build on: pull_request: diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index 66305a463..0476831d4 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -1,4 +1,4 @@ -name: PRTests +name: Test on: pull_request: @@ -6,7 +6,7 @@ on: jobs: test: - name: Unit Test + name: Unit runs-on: ubuntu-latest steps: - name: Set up Go 1.x @@ -25,12 +25,6 @@ jobs: - name: Lint run: make lint - - name: Swagger - run: make swag - - - name: Build - run: make go-build - - name: Unit Test run: make test @@ -38,7 +32,7 @@ jobs: run: bash <(curl -s https://codecov.io/bash) -f coverage.txt integration: - name: Integration Test + name: Integration runs-on: ubuntu-latest steps: - name: Set up Go 1.x @@ -58,4 +52,4 @@ jobs: run: make integration - name: Mock Test - run: make newman-mocked \ No newline at end of file + run: make newman-mocked From a1703e0d03d7a48eb79863cfd696e067c7be4783 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 27 Aug 2020 01:57:48 +0300 Subject: [PATCH 364/506] [ATOM] Change model for delegations (#1203) * Change model for delegations * Fix test --- platform/cosmos/model.go | 6 +++--- platform/cosmos/stake_test.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/cosmos/model.go b/platform/cosmos/model.go index c9b1e6ec9..23dec863d 100644 --- a/platform/cosmos/model.go +++ b/platform/cosmos/model.go @@ -171,15 +171,15 @@ type Delegations struct { type Delegation struct { DelegatorAddress string `json:"delegator_address"` ValidatorAddress string `json:"validator_address"` - Shares string `json:"shares,omitempty"` + Balance string `json:"balance,omitempty"` } func (d *Delegation) Value() string { - shares := strings.Split(d.Shares, ".") + shares := strings.Split(d.Balance, ".") if len(shares) > 0 { return shares[0] } - return d.Shares + return d.Balance } type UnbondingDelegations struct { diff --git a/platform/cosmos/stake_test.go b/platform/cosmos/stake_test.go index 20af2f9b0..18acf1d2a 100644 --- a/platform/cosmos/stake_test.go +++ b/platform/cosmos/stake_test.go @@ -41,7 +41,7 @@ const delegationsSrc = ` "delegator_address": "cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0", "validator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", "shares": "109999.000001746056062372", - "balance": "0" + "balance": "109999.000001746056062372" } ]` From e208173bc330eea7a7527349c8005945dfa4bd49 Mon Sep 17 00:00:00 2001 From: Adam R <13562139+catenocrypt@users.noreply.github.com> Date: Thu, 27 Aug 2020 10:32:35 +0200 Subject: [PATCH 365/506] Re-add removed Binance tests. (#1202) Co-authored-by: Catenocrypt --- mock/datafiles.yaml | 12 + ...bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q | 1 + ...ce-api_v1_tokens__limit_1000_offset_0.json | 1466 +++++++++++++++++ ...le77vddclka9z84ugywug48gn_txAsset_BNB.json | 1 + tests/postman/token_data.json | 4 + tests/postman/transaction_data.json | 6 + 6 files changed, 1490 insertions(+) create mode 100644 mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q create mode 100644 mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json create mode 100644 mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json diff --git a/mock/datafiles.yaml b/mock/datafiles.yaml index 98c196131..4da3c2ed6 100644 --- a/mock/datafiles.yaml +++ b/mock/datafiles.yaml @@ -17,6 +17,18 @@ mockURL: /mock/algorand-api/v1/block/5478346 method: GET extURL: https://mainnet-algorand.api.purestake.io/ps1/v1/block/5478346 +- file: mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json + mockURL: /mock/binance-api/api/v1/transactions?address=bnb1z35wusfv8twfele77vddclka9z84ugywug48gn&txAsset=BNB + method: GET + extURL: https://dex.binance.org/api/v1/transactions?address=bnb1z35wusfv8twfele77vddclka9z84ugywug48gn&txAsset=BNB +- file: mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q + mockURL: /mock/binance-api/api/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q + method: GET + extURL: https://dex.binance.org/api/v1/account/bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q +- file: mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json + mockURL: /mock/binance-api/api/v1/tokens?limit=1000 + method: GET + extURL: https://dex.binance.org/api/v1/tokens?limit=1000&offset=0 - file: mock/ext-api-data/bitcoin-api_v2_address_bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj__details_txs.json mockURL: /mock/bitcoin-api/api/v2/address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj?details=txs method: GET diff --git a/mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q b/mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q new file mode 100644 index 000000000..ff8e44b50 --- /dev/null +++ b/mock/ext-api-data/binance-api_v1_account_bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q @@ -0,0 +1 @@ +{"account_number":273171,"address":"bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q","balances":[{"free":"226.52883965","frozen":"0.00000000","locked":"0.00000000","symbol":"BNB"},{"free":"3649.96917801","frozen":"0.00000000","locked":"0.00000000","symbol":"BUSD-BD1"},{"free":"0.05000000","frozen":"0.00000000","locked":"0.00000000","symbol":"TWT-8C2"}],"flags":0,"public_key":[2,142,117,1,132,202,113,77,165,176,46,204,240,131,18,251,120,168,140,204,43,27,32,135,157,30,25,86,154,105,108,64,211],"sequence":82} diff --git a/mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json b/mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json new file mode 100644 index 000000000..ef085c1eb --- /dev/null +++ b/mock/ext-api-data/binance-api_v1_tokens__limit_1000_offset_0.json @@ -0,0 +1,1466 @@ +[ + { + "mintable": true, + "name": "Africa Stable-Coin", + "original_symbol": "ABCD", + "owner": "bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms", + "symbol": "ABCD-5D8", + "total_supply": "3000000.00000000" + }, + { + "mintable": false, + "name": "Aditus", + "original_symbol": "ADI", + "owner": "bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps", + "symbol": "ADI-6BB", + "total_supply": "750000000.00000000" + }, + { + "mintable": false, + "name": "Aergo", + "original_symbol": "AERGO", + "owner": "bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl", + "symbol": "AERGO-46B", + "total_supply": "500000000.00000000" + }, + { + "mintable": false, + "name": "Alaris", + "original_symbol": "ALA", + "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", + "symbol": "ALA-DCD", + "total_supply": "60000000.00000000" + }, + { + "mintable": false, + "name": "ANKR", + "original_symbol": "ANKR", + "owner": "bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn", + "symbol": "ANKR-E97", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Aeron", + "original_symbol": "ARN", + "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", + "symbol": "ARN-71B", + "total_supply": "20000000.00000000" + }, + { + "mintable": true, + "name": "ARPA", + "original_symbol": "ARPA", + "owner": "bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c", + "symbol": "ARPA-575", + "total_supply": "12000000.00000000" + }, + { + "mintable": false, + "name": "Maecenas ART Token", + "original_symbol": "ART", + "owner": "bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l", + "symbol": "ART-3C9", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "Atlas Protocol", + "original_symbol": "ATP", + "owner": "bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf", + "symbol": "ATP-38C", + "total_supply": "40000000.00000000" + }, + { + "mintable": false, + "name": "Travala.com Token", + "original_symbol": "AVA", + "owner": "bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c", + "symbol": "AVA-645", + "total_supply": "61242960.00000000" + }, + { + "mintable": true, + "name": "“Atomic", + "original_symbol": "AWC", + "owner": "bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw", + "symbol": "AWC-8B2", + "total_supply": "147.00000000" + }, + { + "mintable": false, + "name": "Atomic Wallet Token", + "original_symbol": "AWC", + "owner": "bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw", + "symbol": "AWC-986", + "total_supply": "50000000.00000000" + }, + { + "mintable": false, + "name": "AXPR.B", + "original_symbol": "AXPR", + "owner": "bnb1zpnmet0vhfupn9ysu26gukzj7a2xkkcry22n9t", + "symbol": "AXPR-777", + "total_supply": "347955111.02000000" + }, + { + "mintable": true, + "name": "BAWnetwork", + "original_symbol": "BAW", + "owner": "bnb1umdp5z4hugur26tcgf48fhr0548fv0q0fga84u", + "symbol": "BAW-DFB", + "total_supply": "25000000000.00000000" + }, + { + "mintable": true, + "name": "BCH BEP2", + "original_symbol": "BCH", + "owner": "bnb15tjhzw85wyywwp7zvc4l3ux3j0393rzp9exl0p", + "symbol": "BCH-1FD", + "total_supply": "5000.00000000" + }, + { + "mintable": false, + "name": "Blockmason Credit Protocol", + "original_symbol": "BCPT", + "owner": "bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew", + "symbol": "BCPT-95A", + "total_supply": "116158667.00000000" + }, + { + "mintable": true, + "name": "3X Short Bitcoin Token", + "original_symbol": "BEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "BEAR-14C", + "total_supply": "50301.00000000" + }, + { + "mintable": false, + "name": "EOSBet Token", + "original_symbol": "BET", + "owner": "bnb1rgylg0f3ka24a63rnq926quvet438fxrz3320c", + "symbol": "BET-844", + "total_supply": "88000000.00000000" + }, + { + "mintable": false, + "name": "BETX Token", + "original_symbol": "BETX", + "owner": "bnb15v9e3c4wy8vpex0c5fj702lexjesh30v2203f2", + "symbol": "BETX-A0C", + "total_supply": "200000000.00000000" + }, + { + "mintable": true, + "name": "Binance GBP Stable Coin", + "original_symbol": "BGBP", + "owner": "bnb1r4ag7kd90rptlhcuuc8trh60v4m4vvzrfyecta", + "symbol": "BGBP-CF3", + "total_supply": "200.00000000" + }, + { + "mintable": true, + "name": "Humanity First Token", + "original_symbol": "BHFT", + "owner": "bnb148t3u8zxa44vhydes5qa8xnxuzuq6zgyxmzt6d", + "symbol": "BHFT-BBE", + "total_supply": "636425000.00000000" + }, + { + "mintable": false, + "name": "Bitwires Token", + "original_symbol": "BKBT", + "owner": "bnb104p50kz2uvep5s5u6j0lr6vkl6rp5g4653d7w4", + "symbol": "BKBT-3A6", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Binance KRW", + "original_symbol": "BKRW", + "owner": "bnb18kha55gvsxl7gkdh8y329hu3p6wndh6jkwqnxn", + "symbol": "BKRW-AB7", + "total_supply": "1418984074.00000000" + }, + { + "mintable": false, + "name": "Blockmason Link", + "original_symbol": "BLINK", + "owner": "bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew", + "symbol": "BLINK-9C6", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "Binance Chain Native Token", + "original_symbol": "BNB", + "owner": "bnb1ultyhpw2p2ktvr68swz56570lgj2rdsadq3ym2", + "symbol": "BNB", + "total_supply": "179883948.90000000" + }, + { + "mintable": false, + "name": "BOLT Token", + "original_symbol": "BOLT", + "owner": "bnb177ujwmshxu8r9za4vy9ztqn65tmr54ddw958rt", + "symbol": "BOLT-4C6", + "total_supply": "980230000.00000000" + }, + { + "mintable": false, + "name": "Bitcloud Pro", + "original_symbol": "BPRO", + "owner": "bnb1482svhhrffpga5wmqw8068af4c9u2q9dp3hg4m", + "symbol": "BPRO-5A6", + "total_supply": "5000000000.00000000" + }, + { + "mintable": true, + "name": "BQTX", + "original_symbol": "BQTX", + "owner": "bnb1j42h6j40htujnjmtp4ckw4zx27vp0f93cvmua8", + "symbol": "BQTX-235", + "total_supply": "1000000.00000000" + }, + { + "mintable": false, + "name": "BOOSTO", + "original_symbol": "BST2", + "owner": "bnb19k2av7cmdvp9f0qkeu5vfl59yp8ftqv2s55dzs", + "symbol": "BST2-2F2", + "total_supply": "500000000.00000000" + }, + { + "mintable": true, + "name": "Bitcoin BEP2", + "original_symbol": "BTCB", + "owner": "bnb1akey87kt0r8y3fmhu2l8eyzdjvt9ptl5cppz0v", + "symbol": "BTCB-1DE", + "total_supply": "9001.00000000" + }, + { + "mintable": true, + "name": "BTTB", + "original_symbol": "BTTB", + "owner": "bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq", + "symbol": "BTTB-D31", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "3x Long Bitcoin Token", + "original_symbol": "BULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "BULL-BE4", + "total_supply": "604.80000000" + }, + { + "mintable": true, + "name": "Binance USD", + "original_symbol": "BUSD", + "owner": "bnb19v2ayq6k6e5x6ny3jdutdm6kpqn3n6mxheegvj", + "symbol": "BUSD-BD1", + "total_supply": "13000000.00000000" + }, + { + "mintable": false, + "name": "Bezant Token", + "original_symbol": "BZNT", + "owner": "bnb1w5a5jywe3cu20uq6n6x3vmzcq342s6st4cz73s", + "symbol": "BZNT-464", + "total_supply": "964511442.00000000" + }, + { + "mintable": false, + "name": "CanYaCoin", + "original_symbol": "CAN", + "owner": "bnb16w59lfh4y2cqvu8f7yr000ll37ldh4w6hnz7l0", + "symbol": "CAN-677", + "total_supply": "95827000.00000000" + }, + { + "mintable": false, + "name": "CASHAA", + "original_symbol": "CAS", + "owner": "bnb1xkw2sagpx6t0cmwzapxpv94tupvqk7tpgy72ku", + "symbol": "CAS-167", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "Cubiex", + "original_symbol": "CBIX", + "owner": "bnb1jlm66w38gpfuqr4s2jcfwlcrlx46p05thdnv7g", + "symbol": "CBIX-3C9", + "total_supply": "150000000.00000000" + }, + { + "mintable": false, + "name": "CryptoBonusMiles", + "original_symbol": "CBM", + "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", + "symbol": "CBM-4B2", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "Clipper Coin", + "original_symbol": "CCCX", + "owner": "bnb1ry99rte8gfnn9c6at9mlmrrq6p2k4u7732j9h7", + "symbol": "CCCX-10D", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "Chiliz", + "original_symbol": "CHZ", + "owner": "bnb1cghr4z8ag440tv4wnk3l6wzynytlpvfqltm9ph", + "symbol": "CHZ-ECD", + "total_supply": "8888888888.00000000" + }, + { + "mintable": false, + "name": "Crypto Neo-value Neural System", + "original_symbol": "CNNS", + "owner": "bnb193wdp4gdnm58urnsjf8nv57lxt58sckt2k50ss", + "symbol": "CNNS-E16", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Contentos", + "original_symbol": "COS", + "owner": "bnb1u9j9hkst6gf09dkdvxlj7puk8c7vh68a0kkmht", + "symbol": "COS-2E4", + "total_supply": "9400000000.00000000" + }, + { + "mintable": true, + "name": "COTI", + "original_symbol": "COTI", + "owner": "bnb1kn733gkku9xsqkuk6wcz86gftqtl4qvthvrj5m", + "symbol": "COTI-CBB", + "total_supply": "80000000.00000000" + }, + { + "mintable": false, + "name": "Covalent Token", + "original_symbol": "COVA", + "owner": "bnb1pucvxaf3l9rslupza75r9fca9h5892ntumszfm", + "symbol": "COVA-218", + "total_supply": "6500000000.00000000" + }, + { + "mintable": false, + "name": "CPChain", + "original_symbol": "CPC", + "owner": "bnb1wq4rlwrmvvltlarvypql8wrr4vlh0dczd8uksg", + "symbol": "CPC-FED", + "total_supply": "150000000.00000000" + }, + { + "mintable": false, + "name": "Crypterium Token", + "original_symbol": "CRPT", + "owner": "bnb17fk3uvagucxzpvmdvd373fapqsahxvzevdard9", + "symbol": "CRPT-8C9", + "total_supply": "99968575.14285720" + }, + { + "mintable": false, + "name": "“Consentium”", + "original_symbol": "CSM", + "owner": "bnb1gguz7vcrlf7a87et8u5gt40f0890qvkpkn9y79", + "symbol": "CSM-734", + "total_supply": "84000000.00000000" + }, + { + "mintable": true, + "name": "Carbon Dollar", + "original_symbol": "CUSD", + "owner": "bnb1y9797dtklkm3haajsfnevm9ruuxs5fyf5rpj67", + "symbol": "CUSD-24B", + "total_supply": "9999999999.00000000" + }, + { + "mintable": false, + "name": "Konstellation Network", + "original_symbol": "DARC", + "owner": "bnb1gyhnhdns4vf63nfzfq7g25czj8swjgrz3rhah8", + "symbol": "DARC-24B", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "DeepCloud", + "original_symbol": "DEEP", + "owner": "bnb1t0ws9gvnjm7j7qssk8te7m2dt5hmm8s3amqk2d", + "symbol": "DEEP-9D3", + "total_supply": "200000000.00000000" + }, + { + "mintable": false, + "name": "DeFi Token", + "original_symbol": "DEFI", + "owner": "bnb1q5xefr07503pqtfrl5sfyyhlghxwc80d4vpas2", + "symbol": "DEFI-FA5", + "total_supply": "2500000000.00000000" + }, + { + "mintable": true, + "name": "DOS Network Token", + "original_symbol": "DOS", + "owner": "bnb13gse9n7mvrjg5w2cymnt4nmxkgj200k9k2l2nh", + "symbol": "DOS-120", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "DREP", + "original_symbol": "DREP", + "owner": "bnb1ez5s9v4rcgsmhwr4fkrnlv6zwsukjnh4y754kn", + "symbol": "DREP-7D2", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Dusk Network", + "original_symbol": "DUSK", + "owner": "bnb1dfls6c8y39l7qq4gj2479wkehg85pt5m07y94g", + "symbol": "DUSK-45E", + "total_supply": "50000000.00000000" + }, + { + "mintable": false, + "name": "eBoost", + "original_symbol": "EBST", + "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", + "symbol": "EBST-783", + "total_supply": "80838159.07000000" + }, + { + "mintable": true, + "name": "Ormeus Ecosystem", + "original_symbol": "ECO", + "owner": "bnb1tr49nv08k828n2lqfw0vrgvwj7xtep5kg8wr4c", + "symbol": "ECO-083", + "total_supply": "2200000000.00000000" + }, + { + "mintable": false, + "name": "Energy Eco Token", + "original_symbol": "EET", + "owner": "bnb1pt353m8ygvvgy4f2ud9xx85tl7fqewkrksh6r5", + "symbol": "EET-45C", + "total_supply": "600000000.00000000" + }, + { + "mintable": false, + "name": "Hut34 Entropy", + "original_symbol": "ENTRP", + "owner": "bnb1wu0hu9pelx3yvplysx0je7d93htcandpj86aev", + "symbol": "ENTRP-C8D", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "EOS BEP2", + "original_symbol": "EOS", + "owner": "bnb1la8alalwjzkchd67wza3r75lj5rm7m9e85ffqr", + "symbol": "EOS-CDD", + "total_supply": "500000.00000000" + }, + { + "mintable": true, + "name": "3X Short EOS Token", + "original_symbol": "EOSBEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "EOSBEAR-721", + "total_supply": "32301.00000000" + }, + { + "mintable": true, + "name": "3X Long EOS Token", + "original_symbol": "EOSBULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "EOSBULL-F0D", + "total_supply": "456191.00000000" + }, + { + "mintable": false, + "name": "EQUAL", + "original_symbol": "EQL", + "owner": "bnb1uz0s54rzv022dh66l7atwk83wqcet9qstgg358", + "symbol": "EQL-586", + "total_supply": "675259060.00000000" + }, + { + "mintable": true, + "name": "Elrond", + "original_symbol": "ERD", + "owner": "bnb1m5uzzfxs7x05sl28gg96zyecn9jwgtkpyeftyn", + "symbol": "ERD-D06", + "total_supply": "14500000000.00000000" + }, + { + "mintable": true, + "name": "ETH BEP2", + "original_symbol": "ETH", + "owner": "bnb1yss2345dphss8c823dh2jzje2w8k8x4jguuxhf", + "symbol": "ETH-1C9", + "total_supply": "10000.00000000" + }, + { + "mintable": true, + "name": "3X Short Ethereum Token", + "original_symbol": "ETHBEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "ETHBEAR-B2B", + "total_supply": "61821.00000000" + }, + { + "mintable": true, + "name": "3X Long Ethereum Token", + "original_symbol": "ETHBULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "ETHBULL-D33", + "total_supply": "33684.00000000" + }, + { + "mintable": true, + "name": "everiToken", + "original_symbol": "EVT", + "owner": "bnb1v3fl4kuwuhzf3g7ghscsq7uzmu5dw50waseptd", + "symbol": "EVT-49B", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "The Force Token", + "original_symbol": "FOR", + "owner": "bnb1c46nhwdwm3u2mlfhx6t07fls25shnvktpr9w9m", + "symbol": "FOR-997", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "Ferrum Network Token", + "original_symbol": "FRM", + "owner": "bnb1um8ntkgwle8yrdk0yn5hwdf7hckjpyjjg29k2p", + "symbol": "FRM-DE7", + "total_supply": "164609374.50000000" + }, + { + "mintable": false, + "name": "Fusion", + "original_symbol": "FSN", + "owner": "bnb17mnutyduat9fe02r2dawp3kn4rnaqamp5kpg0c", + "symbol": "FSN-E14", + "total_supply": "57344000.00000000" + }, + { + "mintable": true, + "name": "Fantom", + "original_symbol": "FTM", + "owner": "bnb1f6sxnf3nhn9fcfwkuccrzvl2pgu3sq0m8pyjhw", + "symbol": "FTM-A64", + "total_supply": "952500000.00000000" + }, + { + "mintable": true, + "name": "FTX Token", + "original_symbol": "FTT", + "owner": "bnb1msxdh7e7smpg68gxxhs0p3fhuj9tzhrxa4c2x2", + "symbol": "FTT-F11", + "total_supply": "10000000.00000000" + }, + { + "mintable": true, + "name": "Givly Coin", + "original_symbol": "GIV", + "owner": "bnb13jzr6sqz72fl0edg2tpqp8tddyzvyt4su2490m", + "symbol": "GIV-94E", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "GoWithMi", + "original_symbol": "GMAT", + "owner": "bnb1yltla9mnk8999ygmjjn3kwmmz2zs94a9v20sca", + "symbol": "GMAT-FC8", + "total_supply": "14900000000.00000000" + }, + { + "mintable": false, + "name": "Global Gaming", + "original_symbol": "GMNG", + "owner": "bnb1qe6zxqptfxw0kh38t8pg6c3qa527n2x2a87qvm", + "symbol": "GMNG-F3E", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "GTEX", + "original_symbol": "GTEX", + "owner": "bnb1nksrzfl24he9xtvdvpypsl6r5jnh5x2uf9s82z", + "symbol": "GTEX-71B", + "total_supply": "4000000000.00000000" + }, + { + "mintable": false, + "name": "Gifto", + "original_symbol": "GTO", + "owner": "bnb1lvp8k3zenlfp2pl2nyaf428xjgh385m258gzvq", + "symbol": "GTO-908", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "“Hermes", + "original_symbol": "HEC", + "owner": "bnb1dfyydqkmsv5m0rs0pa4uut2gwrcsahppktns2t", + "symbol": "HEC-1A9", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "Honest", + "original_symbol": "HNST", + "owner": "bnb1k9fv2hz0w3l9v9z4g9samg3gtc7nc2xgyqw5u0", + "symbol": "HNST-3C9", + "total_supply": "400000000.00000000" + }, + { + "mintable": true, + "name": "Hyperion Token", + "original_symbol": "HYN", + "owner": "bnb1q5cqecuy2g7syl8fssp9a7v2sjamtrzlr3pa0n", + "symbol": "HYN-F21", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Rupiah Token", + "original_symbol": "IDRTB", + "owner": "bnb1wc44duax6pygh23psx0u945skvs3eh7w59e4sp", + "symbol": "IDRTB-178", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "IKU", + "original_symbol": "IKU", + "owner": "bnb1f52tc9l0qg337qtgu4n024ayllc78wxpc5xhvd", + "symbol": "IKU-416", + "total_supply": "300000000.00000000" + }, + { + "mintable": true, + "name": "IRIS Network", + "original_symbol": "IRIS", + "owner": "bnb1dcpm0jjj8el8g6ekr3mvjxa8kptgu4e5xzvqv8", + "symbol": "IRIS-D88", + "total_supply": "2000000000.00000000" + }, + { + "mintable": false, + "name": "JDXUCoin", + "original_symbol": "JDXU", + "owner": "bnb1dwcsg0t86g7935zpxc054n97styzgdtnu2kzg6", + "symbol": "JDXU-706", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "Kambria Token", + "original_symbol": "KAT", + "owner": "bnb1l68n6equtr925lhnentyq54zfrzqyj45lg8uwj", + "symbol": "KAT-7BB", + "total_supply": "3700000000.00000000" + }, + { + "mintable": true, + "name": "Kava BEP2 Token", + "original_symbol": "KAVA", + "owner": "bnb1uyekdn62yur9zuctzqyd9ckasfvqttjz9c33me", + "symbol": "KAVA-10C", + "total_supply": "6071200.72181900" + }, + { + "mintable": false, + "name": "Sessia Kicks", + "original_symbol": "KICKS", + "owner": "bnb130tmwjd3fc79eh6f5ezl2326ur8rqpsxeeq30x", + "symbol": "KICKS-162", + "total_supply": "5000000.00000000" + }, + { + "mintable": true, + "name": "Lambda", + "original_symbol": "LAMB", + "owner": "bnb19vnwdjwthm9unxe9hxdxmgm6qw0d42d2lmcesw", + "symbol": "LAMB-46C", + "total_supply": "5000000.00000000" + }, + { + "mintable": false, + "name": "Lend-Borrow-Asset", + "original_symbol": "LBA", + "owner": "bnb1m8r74hr532lfwtaf5e88cxeakd36ut0ufpd4yu", + "symbol": "LBA-340", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "LITION", + "original_symbol": "LIT", + "owner": "bnb1fhlxwqlwd7cm5fmurg0wmsaalshnp7lwu46nk9", + "symbol": "LIT-099", + "total_supply": "145061313.45061312" + }, + { + "mintable": true, + "name": "Loki", + "original_symbol": "LOKI", + "owner": "bnb1j5sft8wp7tktjwauy30x79f3tqa53fycmgxxs0", + "symbol": "LOKI-6A9", + "total_supply": "3000000.00000000" + }, + { + "mintable": true, + "name": "LTC BEP2", + "original_symbol": "LTC", + "owner": "bnb1cn4sqm79wqmr8rey923r34cp2wrtyhlr9easpg", + "symbol": "LTC-F07", + "total_supply": "18500.00000000" + }, + { + "mintable": false, + "name": "LTO Network", + "original_symbol": "LTO", + "owner": "bnb1ac6p45m00pv36y9mu48e5xr73fyxke3zv2rhmq", + "symbol": "LTO-BDF", + "total_supply": "500000000.00000000" + }, + { + "mintable": false, + "name": "Matic Token", + "original_symbol": "MATIC", + "owner": "bnb1a6nkf3g7c2z0jcrqhp8c9upcwmme0y49qx58nz", + "symbol": "MATIC-84A", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Moviebloc", + "original_symbol": "MBL", + "owner": "bnb17p8rc0z5vlysff2wc7xehff464dm0v7nhl27xq", + "symbol": "MBL-2D2", + "total_supply": "30000000000.00000000" + }, + { + "mintable": true, + "name": "Mcashchain", + "original_symbol": "MCASH", + "owner": "bnb1q420q7qpyv7tghfp6aac7vnjq74dhkeutdhqsg", + "symbol": "MCASH-869", + "total_supply": "200000000.00000000" + }, + { + "mintable": false, + "name": "Magic Cube Token", + "original_symbol": "MCC", + "owner": "bnb14nt79d6hzhjefkys2cgrc9nrzugdjwwtggfmu4", + "symbol": "MCC-33B", + "total_supply": "20000000000.00000000" + }, + { + "mintable": false, + "name": "MDAB", + "original_symbol": "MDAB", + "owner": "bnb1m3edd4q4nd3wxg9vm3xe8pnfnetu5yjmhtnrqz", + "symbol": "MDAB-D42", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "MediBloc", + "original_symbol": "MEDB", + "owner": "bnb1za3ytyh55wprmn4ew8gat657lpjdzhafwrded3", + "symbol": "MEDB-87E", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "MEET.ONE", + "original_symbol": "MEETONE", + "owner": "bnb1zquk6usn03xnnht6ws6p0h4ylgk8jkhch6c6ck", + "symbol": "MEETONE-031", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "SyncFab Smart Manufacturing", + "original_symbol": "MFGB", + "owner": "bnb104qhlkx4fu6nvm32v4k7zzgtt4eqtyzvh9yq48", + "symbol": "MFGB-0A0", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "Mithril", + "original_symbol": "MITH", + "owner": "bnb15krsh6x2343qskf86cw0hazchl5pkfw53zllut", + "symbol": "MITH-C76", + "total_supply": "988855068.00409432" + }, + { + "mintable": false, + "name": "Morpheus Infrastructure Token", + "original_symbol": "MITX", + "owner": "bnb17e2n869fp6zvdyfaqkq3tgfmj8pskq20mdaz7e", + "symbol": "MITX-CAA", + "total_supply": "400000000.00000000" + }, + { + "mintable": false, + "name": "MultiVAC", + "original_symbol": "MTV", + "owner": "bnb18cjgqwpj2sxdxf7u84hgzh76cmqvthw7fgtr7z", + "symbol": "MTV-4C6", + "total_supply": "8000000000.00000000" + }, + { + "mintable": false, + "name": "Tixl", + "original_symbol": "MTXLT", + "owner": "bnb1pwcluc3a2lswrdd8v3uq43qrgfdl6kv2ahrz43", + "symbol": "MTXLT-286", + "total_supply": "900000.00000000" + }, + { + "mintable": true, + "name": "Mass Vehicle Ledger", + "original_symbol": "MVL", + "owner": "bnb1mqdkp0ujngm58sus3fh5x9c0j59madqxej9q75", + "symbol": "MVL-7B0", + "total_supply": "8000000000.00000000" + }, + { + "mintable": false, + "name": "Muzika", + "original_symbol": "MZK", + "owner": "bnb1dkqsj76yr6nlegs3433m3c59mm0j7vy72nn275", + "symbol": "MZK-2C7", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "NEWTON", + "original_symbol": "NEW", + "owner": "bnb1ud4ak7pj5kg5kqddhx9yacdu6sf7sxhqdv30k0", + "symbol": "NEW-09E", + "total_supply": "90000000000.00000000" + }, + { + "mintable": true, + "name": "Nexo", + "original_symbol": "NEXO", + "owner": "bnb15ngukylwcleljegx32ykefqxw8jz42szar6vf5", + "symbol": "NEXO-A84", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "NODE", + "original_symbol": "NODE", + "owner": "bnb1xljnjk7msm5t5lwp4zv2ua80rrxzn2s2afce4j", + "symbol": "NODE-F3A", + "total_supply": "2000000000.00000000" + }, + { + "mintable": false, + "name": "NOIZ Token", + "original_symbol": "NOIZB", + "owner": "bnb1fa9xgszkn57zq0aulfgk5hct09yx5heepum3x7", + "symbol": "NOIZB-878", + "total_supply": "400000000.00000000" + }, + { + "mintable": true, + "name": "NOW Token", + "original_symbol": "NOW", + "owner": "bnb1nug8ls9f0et0t558m4chmm46mf85ehpq0u8gwv", + "symbol": "NOW-E68", + "total_supply": "99939495.70000000" + }, + { + "mintable": false, + "name": "NPX Binance token", + "original_symbol": "NPXB", + "owner": "bnb1wf7z3e8wvcu7gs74stmfmktsa2m5738rd0znae", + "symbol": "NPXB-1E8", + "total_supply": "29800000.00000000" + }, + { + "mintable": false, + "name": "Pundi X NEM", + "original_symbol": "NPXSXEM", + "owner": "bnb1wuww3cqy6wn5jdp6emv0eqwd5khlc3qyy0ympp", + "symbol": "NPXSXEM-89C", + "total_supply": "44815631324.40000000" + }, + { + "mintable": true, + "name": "Harmony.One", + "original_symbol": "ONE", + "owner": "bnb1a03uvqmnqzl85csnxnsx2xy28m76gkkht46f2l", + "symbol": "ONE-5F9", + "total_supply": "12600000000.00000000" + }, + { + "mintable": true, + "name": "ONTBEP2", + "original_symbol": "ONT", + "owner": "bnb1lxlxzanvg5ud02vjcvuxqrdystcehvtj6a05s2", + "symbol": "ONT-33D", + "total_supply": "1500000.00000000" + }, + { + "mintable": false, + "name": "OpenWeb Token", + "original_symbol": "OWTX", + "owner": "bnb1qnzqrxpek5dy6hh4fjywjv60x806yv2kpwt64y", + "symbol": "OWTX-A6B", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "Pink Care Token", + "original_symbol": "PCAT", + "owner": "bnb1xx54pavpran2c36ugvnxnrfszwn36cryqfzufa", + "symbol": "PCAT-4BB", + "total_supply": "50000.00000000" + }, + { + "mintable": true, + "name": "Red Pulse Phoenix Binance", + "original_symbol": "PHB", + "owner": "bnb1vvvm62cezjy35xa46lghjs2jthzzdlpfyqg90a", + "symbol": "PHB-2DF", + "total_supply": "1598758851.80873855" + }, + { + "mintable": true, + "name": "PathHive Network", + "original_symbol": "PHV", + "owner": "bnb13nltf0vw66kw737dej6kc0fy85u3a38avr0xmf", + "symbol": "PHV-4A1", + "total_supply": "350000000.00000000" + }, + { + "mintable": false, + "name": "PCHAIN Token", + "original_symbol": "PIBNB", + "owner": "bnb1lvq8c3ul472aqrsknnvqumjszt2v60s0zagw6r", + "symbol": "PIBNB-43C", + "total_supply": "1071000000.00000000" + }, + { + "mintable": false, + "name": "Pledge Coin", + "original_symbol": "PLG", + "owner": "bnb1wjxhqa6ud4ucxayjqd9necfq0n954ztncsn7zn", + "symbol": "PLG-D8D", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "PPE Token", + "original_symbol": "PPE", + "owner": "bnb1ry96fn3gl3wskha86lhgx8ckrgt3vgrnwq8quz", + "symbol": "PPE-942", + "total_supply": "200000.00000000" + }, + { + "mintable": false, + "name": "Pivot Token", + "original_symbol": "PVT", + "owner": "bnb1vgzzktw8j46hd87npsrukxhzxecq8knnt96tyf", + "symbol": "PVT-554", + "total_supply": "6283185307.00000000" + }, + { + "mintable": false, + "name": "paycentos", + "original_symbol": "PYN", + "owner": "bnb190acfwshh899eylweut9xarls2ma953rvkdlhf", + "symbol": "PYN-C37", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "QARK", + "original_symbol": "QARK", + "owner": "bnb1wnwrnmc6y9pl6ve9g7mahd4wkactaldyx3hsmu", + "symbol": "QARK-FCE", + "total_supply": "77000000.00000000" + }, + { + "mintable": true, + "name": "qiibeeToken", + "original_symbol": "QBX", + "owner": "bnb1eq8cytar7a3rer3ms7dpatd3cuhpfhaw3ts6tr", + "symbol": "QBX-38C", + "total_supply": "138039216.00000000" + }, + { + "mintable": false, + "name": "Raven Protocol", + "original_symbol": "RAVEN", + "owner": "bnb1vdjhrkgvt4y76ykyvrvh68pzqg3lvv0y5yfxyf", + "symbol": "RAVEN-F66", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Reporter News Agency Token", + "original_symbol": "RNA", + "owner": "bnb1m033d9a5fuf6r8wxqcguhwrnnk7sffcljzrc83", + "symbol": "RNA-23B", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "Rasputin Party Mansion Phase2", + "original_symbol": "ROCP2", + "owner": "bnb16fyhf2hw8d5raxtympp48nzt2ezw6dqvfv5cd3", + "symbol": "ROCP2-F01", + "total_supply": "27000000.00000000" + }, + { + "mintable": false, + "name": "Rapids", + "original_symbol": "RPD", + "owner": "bnb1vtpy8dly2jfsn6v3t0qnyfxrex9sdy0entp5zs", + "symbol": "RPD-9E0", + "total_supply": "1500000000.00000000" + }, + { + "mintable": false, + "name": "Rune", + "original_symbol": "RUNE", + "owner": "bnb1e4q8whcufp6d72w8nwmpuhxd96r4n0fstegyuy", + "symbol": "RUNE-B1A", + "total_supply": "500000000.00000000" + }, + { + "mintable": false, + "name": "ShareToken", + "original_symbol": "SHR", + "owner": "bnb12c94hfu5vm77a9xkwfyl2ztgwgk503a06zl70e", + "symbol": "SHR-DB6", + "total_supply": "4396000000.00000000" + }, + { + "mintable": false, + "name": "Silverway", + "original_symbol": "SLV", + "owner": "bnb15nhdv2m09uwgnmmhx73dcguag7n363fdzdsg23", + "symbol": "SLV-986", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "SPIN Protocol", + "original_symbol": "SPIN", + "owner": "bnb12n8fqjp8vh00s5u89paewv0wk8avr3nyvhsl4j", + "symbol": "SPIN-9DD", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "Spendcoin", + "original_symbol": "SPNDB", + "owner": "bnb105n32ugq55kzlyz3tuug35d3t0ul37lx9aksah", + "symbol": "SPNDB-916", + "total_supply": "2000000000.00000000" + }, + { + "mintable": false, + "name": "STIPS Token", + "original_symbol": "STIPS", + "owner": "bnb1tug8sgfcuh0rdyr697k5pnwz9expj7v5zr3qs5", + "symbol": "STIPS-14F", + "total_supply": "128806335.86000000" + }, + { + "mintable": false, + "name": "STIPS", + "original_symbol": "STIPS", + "owner": "bnb1tug8sgfcuh0rdyr697k5pnwz9expj7v5zr3qs5", + "symbol": "STIPS-770", + "total_supply": "243585434.00000000" + }, + { + "mintable": false, + "name": "Yin Lang Music IP Token", + "original_symbol": "STYL", + "owner": "bnb1j2dgknw9l4jny8crjdn6vcjsnu23ejxhchrumg", + "symbol": "STYL-65B", + "total_supply": "100000.00000000" + }, + { + "mintable": false, + "name": "Swingby Token", + "original_symbol": "SWINGBY", + "owner": "bnb1thagrtfude74x2j2wuknhj2savucy2tx0k58y9", + "symbol": "SWINGBY-888", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "SWIPE Token", + "original_symbol": "SWIPE.B", + "owner": "bnb17pwyw202w7fssznnnv8f2gukau49uc4m4chz4m", + "symbol": "SWIPE.B-DC0", + "total_supply": "1500000000.00000000" + }, + { + "mintable": true, + "name": "TrueAUD", + "original_symbol": "TAUDB", + "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", + "symbol": "TAUDB-888", + "total_supply": "90000000000.00000000" + }, + { + "mintable": true, + "name": "TBCC Coin", + "original_symbol": "TBC", + "owner": "bnb18hvknjyd73dx3ud02zp3z8v6du50vw7jxp06xt", + "symbol": "TBC-3A7", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "TrueCAD", + "original_symbol": "TCADB", + "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", + "symbol": "TCADB-888", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "TrustED Token", + "original_symbol": "TED", + "owner": "bnb1zwg63xvmn02u8lv8v2sq0ypaejehhv3fceeu8a", + "symbol": "TED-A85", + "total_supply": "1720000000.00000000" + }, + { + "mintable": true, + "name": "TrueGBP", + "original_symbol": "TGBPB", + "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", + "symbol": "TGBPB-888", + "total_supply": "90000000000.00000000" + }, + { + "mintable": true, + "name": "TrueHKD", + "original_symbol": "THKDB", + "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", + "symbol": "THKDB-888", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "Traxia 2", + "original_symbol": "TM2", + "owner": "bnb1pdeggk7lgch37ks7e3l5x3n5y245krl3zmrl8e", + "symbol": "TM2-0C4", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "TomoChain", + "original_symbol": "TOMOB", + "owner": "bnb1jmgew0xvtkfjhnqsglm50tynxgps3xkx0xqffy", + "symbol": "TOMOB-4BC", + "total_supply": "5000000.00000000" + }, + { + "mintable": false, + "name": "TOP Network", + "original_symbol": "TOP", + "owner": "bnb1lqc7vjrag9sdaqeuv22jccr4rxtdxdtq6ve2w6", + "symbol": "TOP-491", + "total_supply": "20000000000.00000000" + }, + { + "mintable": false, + "name": "TROY", + "original_symbol": "TROY", + "owner": "bnb1scrark2sv6fpngyqxrryw9hw7y05euwntz45ae", + "symbol": "TROY-9B8", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "TrueChain", + "original_symbol": "TRUE", + "owner": "bnb1m0llwxe0nwtw98m7knpz3g7r0c98mwn7tfwjcc", + "symbol": "TRUE-D84", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "TRXB", + "original_symbol": "TRXB", + "owner": "bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq", + "symbol": "TRXB-2E6", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "TrueUSD", + "original_symbol": "TUSDB", + "owner": "bnb100dxzy02a6k7vysc5g4kk4fqamr7jhjg4m83l0", + "symbol": "TUSDB-888", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "Trust Wallet", + "original_symbol": "TWT", + "owner": "bnb1fkyxlq9kz5368ux29aeeztslclgf8e7tja345x", + "symbol": "TWT-8C2", + "total_supply": "90000000000.00000000" + }, + { + "mintable": true, + "name": "“Ubet", + "original_symbol": "UBETS", + "owner": "bnb1gcpctmgmf0am0ft85ttswy2epd9d6vvvxu2ly6", + "symbol": "UBETS-068", + "total_supply": "4000000000.00000000" + }, + { + "mintable": false, + "name": "Ultrain Coin", + "original_symbol": "UGAS", + "owner": "bnb1mj2nncwkmrw9pr6d0spkfmewz5eynz63w67f6e", + "symbol": "UGAS-B0C", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "United Network Distribution", + "original_symbol": "UND", + "owner": "bnb1q5tr6ggvg0h38axzw2dc4606j3edg58qug9ajr", + "symbol": "UND-EBC", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "UPX", + "original_symbol": "UPX", + "owner": "bnb1588jx9ylvfpfhdzy672lk3pulleq8md0a4wcjl", + "symbol": "UPX-F3E", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "HonestCoin", + "original_symbol": "USDH", + "owner": "bnb1kel6x8nl37j2w6963c3gxnwzplvkwkphrkdmx9", + "symbol": "USDH-5B5", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "USDS", + "original_symbol": "USDSB", + "owner": "bnb1nf5qjthrmxwxnfct4j0w4ct03fghthq24qt990", + "symbol": "USDSB-1AC", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "UTU Coin", + "original_symbol": "UTU", + "owner": "bnb1r7whkqt8q2efn3c2ynsshrvxkg07cu8etuxkwr", + "symbol": "UTU-159", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "UNetwork Token", + "original_symbol": "UUU", + "owner": "bnb17mkwwvzxaxa792rggvcmrpe6d7la4j9tjhdaql", + "symbol": "UUU-35C", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Vodi X", + "original_symbol": "VDX", + "owner": "bnb1pk6umuhxjcd3ggyztw7a7lfggwgyyx2w5h8j59", + "symbol": "VDX-A17", + "total_supply": "300000000.00000000" + }, + { + "mintable": false, + "name": "V-ID Token", + "original_symbol": "VIDT", + "owner": "bnb1k8870xayp29jug2lw9ujcqnjv6q6nu92enkg8v", + "symbol": "VIDT-F53", + "total_supply": "36800171.30000000" + }, + { + "mintable": true, + "name": "VNDC", + "original_symbol": "VNDC", + "owner": "bnb1zxt4xh4xxdnv5aagh77a4zp2kflg6a2c22hp73", + "symbol": "VNDC-DB9", + "total_supply": "2050000000.00000000" + }, + { + "mintable": false, + "name": "Vote", + "original_symbol": "VOTE", + "owner": "bnb1px34z7hw3hjtcf4ul664azxl4jwmkvgdnfep5e", + "symbol": "VOTE-FD4", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "VERA", + "original_symbol": "VRAB", + "owner": "bnb1ucrwnsvjetufca3u6hnqskz0jfrwascwzg5tyf", + "symbol": "VRAB-B56", + "total_supply": "10839985784.00000000" + }, + { + "mintable": true, + "name": "Wagerr", + "original_symbol": "WGR", + "owner": "bnb194yuu322fqk69g2el8c874np5hjc8fykft3wv3", + "symbol": "WGR-D3D", + "total_supply": "205000000.00000000" + }, + { + "mintable": true, + "name": "WaykiChain Coin", + "original_symbol": "WICC", + "owner": "bnb1cw6kw5q0xcaxvpqravfewrcca9jgkdmd3zpc5n", + "symbol": "WICC-01D", + "total_supply": "210000000.00000000" + }, + { + "mintable": true, + "name": "WINB", + "original_symbol": "WINB", + "owner": "bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq", + "symbol": "WINB-41F", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "MyWish", + "original_symbol": "WISH", + "owner": "bnb1tawge8u97slduhhtumm03l4xl4c46dwv5m9yzk", + "symbol": "WISH-2D5", + "total_supply": "9546650.62357825" + }, + { + "mintable": false, + "name": "WazirX Token", + "original_symbol": "WRX", + "owner": "bnb19cvhgyrxmkw30hlqs9c5lp966drjzyylytl74z", + "symbol": "WRX-ED1", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "Eterbase Coin", + "original_symbol": "XBASE", + "owner": "bnb177v0mn59lmuxu90uph5mg065n9l4f3r4zqllvd", + "symbol": "XBASE-CD2", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "XIO", + "original_symbol": "XIO", + "owner": "bnb1egwrlcwqkluqpujfwc5r2d27ggg7kv0lteyez9", + "symbol": "XIO-B05", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "Xeonbit Token", + "original_symbol": "XNS", + "owner": "bnb17az2n3ll3wjgf3gnn2chqxawzgrv9xv9vrkc79", + "symbol": "XNS-760", + "total_supply": "300000000.00000000" + }, + { + "mintable": true, + "name": "XRP BEP2", + "original_symbol": "XRP", + "owner": "bnb1x0vv5l6u5c7vpl7c947uxmm0gfstpdhg93gxpt", + "symbol": "XRP-BF2", + "total_supply": "10000000.00000000" + }, + { + "mintable": true, + "name": "3X Short XRP Token", + "original_symbol": "XRPBEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "XRPBEAR-00B", + "total_supply": "1348.00000000" + }, + { + "mintable": true, + "name": "3X Long XRP Token", + "original_symbol": "XRPBULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "XRPBULL-E7C", + "total_supply": "121291.00000000" + }, + { + "mintable": true, + "name": "XTZ BEP2", + "original_symbol": "XTZ", + "owner": "bnb12twkcedchmx3xn09jcf28u7xrg0mqsyluf56g4", + "symbol": "XTZ-F7A", + "total_supply": "250000.00000000" + }, + { + "mintable": false, + "name": "XWG", + "original_symbol": "XWG", + "owner": "bnb10s02g69vhym56ke23nkacmuf9038e8rr7dm8e8", + "symbol": "XWG-478", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "“YeeCo”", + "original_symbol": "YEE", + "owner": "bnb1ykzzc0zevzsade3urq4t27rfz98xgquphm8ucs", + "symbol": "YEE-EAE", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "ZEBI", + "original_symbol": "ZEBI", + "owner": "bnb1gca96lw9zlr8fct47wznsae67pc5wjwsjzamaf", + "symbol": "ZEBI-84F", + "total_supply": "1000000000.00000000" + } +] diff --git a/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json b/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json new file mode 100644 index 000000000..e08c30bad --- /dev/null +++ b/mock/ext-api-data/binance-api_v1_txs__address_bnb1z35wusfv8twfele77vddclka9z84ugywug48gn_txAsset_BNB.json @@ -0,0 +1 @@ +{"tx":[{"txHash":"0CE23D9F143F7FAF192BB55F33C8FCBC1095D98410A750F63777987685E2C154","blockHeight":106690566,"txType":"TRANSFER","timeStamp":"2020-08-12T10:18:26.388Z","fromAddr":"bnb1jxfh2g85q3v0tdq56fnevx6xcxtcnhtsmcu64m","toAddr":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","value":"6018.97200000","txAsset":"RUNE-B1A","txFee":"0.00037500","proposalId":null,"txAge":8026,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"","source":0,"sequence":736321}],"total":1} diff --git a/tests/postman/token_data.json b/tests/postman/token_data.json index 476e64773..f53b1c75e 100644 --- a/tests/postman/token_data.json +++ b/tests/postman/token_data.json @@ -27,6 +27,10 @@ "handler": "ethereum", "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" }, + { + "handler": "binance", + "address": "bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q" + }, { "handler": "classic", "address": "0xa12105efa0663147bddee178f6a741ac15676b79" diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json index a4f8b4dea..b594767d7 100644 --- a/tests/postman/transaction_data.json +++ b/tests/postman/transaction_data.json @@ -83,6 +83,12 @@ "expectedTxNum": 2, "expectedTxId": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78" }, + { + "handler": "binance", + "address": "bnb1z35wusfv8twfele77vddclka9z84ugywug48gn", + "expectedTxNum": 1, + "expectedTxId": "0CE23D9F143F7FAF192BB55F33C8FCBC1095D98410A750F63777987685E2C154" + }, { "handler": "tezos", "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", From e90b7df9a3bb607b9791da377e313fe97a82d3f5 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Fri, 28 Aug 2020 01:28:28 +0300 Subject: [PATCH 366/506] [KAVA] Setup kava chain (#1204) --- platform/kava/base.go | 22 + platform/kava/block.go | 22 + platform/kava/client.go | 92 ++++ platform/kava/model.go | 270 +++++++++++ platform/kava/stake.go | 230 +++++++++ platform/kava/stake_test.go | 152 ++++++ platform/kava/transaction.go | 185 ++++++++ platform/kava/transaction_test.go | 747 ++++++++++++++++++++++++++++++ platform/platform.go | 3 +- 9 files changed, 1722 insertions(+), 1 deletion(-) create mode 100644 platform/kava/base.go create mode 100644 platform/kava/block.go create mode 100644 platform/kava/client.go create mode 100644 platform/kava/model.go create mode 100644 platform/kava/stake.go create mode 100644 platform/kava/stake_test.go create mode 100644 platform/kava/transaction.go create mode 100644 platform/kava/transaction_test.go diff --git a/platform/kava/base.go b/platform/kava/base.go new file mode 100644 index 000000000..3ab5b4889 --- /dev/null +++ b/platform/kava/base.go @@ -0,0 +1,22 @@ +package kava + +import ( + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Platform struct { + client Client + CoinIndex uint +} + +func Init(coin uint, api string) *Platform { + return &Platform{ + CoinIndex: coin, + client: Client{blockatlas.InitClient(api)}, + } +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[p.CoinIndex] +} diff --git a/platform/kava/block.go b/platform/kava/block.go new file mode 100644 index 000000000..ce03a0e3e --- /dev/null +++ b/platform/kava/block.go @@ -0,0 +1,22 @@ +package kava + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + srcTxs, err := p.client.GetBlockByNumber(num) + if err != nil { + return nil, err + } + + txs := p.NormalizeTxs(srcTxs.Txs) + return &blockatlas.Block{ + Number: num, + Txs: txs, + }, nil +} + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.CurrentBlockNumber() +} diff --git a/platform/kava/client.go b/platform/kava/client.go new file mode 100644 index 000000000..a6a9dc096 --- /dev/null +++ b/platform/kava/client.go @@ -0,0 +1,92 @@ +package kava + +import ( + "fmt" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/logger" + "net/url" + "strconv" + "time" +) + +// Client - the HTTP client +type Client struct { + blockatlas.Request +} + +// GetAddrTxs - get all ATOM transactions for a given address +func (c *Client) GetAddrTxs(address, tag string, page int) (txs TxPage, err error) { + query := url.Values{ + tag: {address}, + "page": {strconv.Itoa(page)}, + "limit": {"25"}, + } + err = c.Get(&txs, "txs", query) + if err != nil { + return TxPage{}, err + } + return +} + +func (c *Client) GetValidators() (validators Validators, err error) { + query := url.Values{ + "status": {"bonded"}, + } + err = c.GetWithCache(&validators, "staking/validators", query, time.Minute*10) + return +} + +func (c *Client) GetBlockByNumber(num int64) (txs TxPage, err error) { + err = c.Get(&txs, "txs", url.Values{"tx.height": {strconv.FormatInt(num, 10)}}) + return +} + +func (c *Client) CurrentBlockNumber() (num int64, err error) { + var block Block + err = c.Get(&block, "blocks/latest", nil) + + if err != nil { + return num, err + } + + num, err = strconv.ParseInt(block.Meta.Header.Height, 10, 64) + if err != nil { + return num, errors.E("error to ParseInt", errors.TypePlatformUnmarshal) + } + + return +} + +func (c *Client) GetPool() (result StakingPool, err error) { + return result, c.GetWithCache(&result, "staking/pool", nil, time.Minute*20) +} + +func (c *Client) GetInflation() (inflation Inflation, err error) { + err = c.GetWithCache(&inflation, "minting/inflation", nil, time.Minute*20) + return +} + +func (c *Client) GetDelegations(address string) (delegations Delegations, err error) { + path := fmt.Sprintf("staking/delegators/%s/delegations", address) + err = c.Get(&delegations, path, nil) + if err != nil { + logger.Error(err, "Cosmos: Failed to get delegations for address") + } + return +} + +func (c *Client) GetUnbondingDelegations(address string) (delegations UnbondingDelegations, err error) { + path := fmt.Sprintf("staking/delegators/%s/unbonding_delegations", address) + err = c.Get(&delegations, path, nil) + if err != nil { + logger.Error(err, "Cosmos: Failed to get unbonding delegations for address") + } + return +} + +func (c *Client) GetAccount(address string) (result AuthAccount, err error) { + path := fmt.Sprintf("auth/accounts/%s", address) + err = c.Get(&result, path, nil) + return +} diff --git a/platform/kava/model.go b/platform/kava/model.go new file mode 100644 index 000000000..10093f19c --- /dev/null +++ b/platform/kava/model.go @@ -0,0 +1,270 @@ +package kava + +import ( + "encoding/json" + "strconv" + "strings" +) + +type TxType string +type EventType string +type AttributeKey string +type DenomType string + +// Types of messages +const ( + MsgSend TxType = "cosmos-sdk/MsgSend" + MsgMultiSend TxType = "cosmos-sdk/MsgMultiSend" + MsgCreateValidator TxType = "cosmos-sdk/MsgCreateValidator" + MsgDelegate TxType = "cosmos-sdk/MsgDelegate" + MsgUndelegate TxType = "cosmos-sdk/MsgUndelegate" + MsgBeginRedelegate TxType = "cosmos-sdk/MsgBeginRedelegate" + MsgWithdrawDelegationReward TxType = "cosmos-sdk/MsgWithdrawDelegationReward" + MsgWithdrawValidatorCommission TxType = "cosmos-sdk/MsgWithdrawValidatorCommission" + MsgSubmitProposal TxType = "cosmos-sdk/MsgSubmitProposal" + MsgDeposit TxType = "cosmos-sdk/MsgDeposit" + MsgVote TxType = "cosmos-sdk/MsgVote" + TextProposal TxType = "cosmos-sdk/TextProposal" + MsgUnjail TxType = "cosmos-sdk/MsgUnjail" + + EventTransfer EventType = "transfer" + EventWithdrawRewards EventType = "withdraw_rewards" + + AttributeAmount AttributeKey = "amount" + AttributeValidator AttributeKey = "validator" + + DenomAtom DenomType = "uatom" + DenomKava DenomType = "ukava" +) + +// Tx - Base transaction object. Always returned as part of an array +type Tx struct { + Block string `json:"height"` + Code int `json:"code"` + Date string `json:"timestamp"` + ID string `json:"txhash"` + Data Data `json:"tx"` + Events Events `json:"events"` +} + +type TxPage struct { + PageTotal string `json:"page_total"` + Txs []Tx `json:"txs"` +} + +// Events +type Event struct { + Type EventType + Attributes Attributes `json:"Attributes"` +} + +type Events []*Event + +func (e Events) GetWithdrawRewardValue() string { + result := int64(0) + for _, att := range e { + if att.Type == EventWithdrawRewards { + result += att.Attributes.GetWithdrawRewardValue() + } + } + return strconv.FormatInt(result, 10) +} + +type Attribute struct { + Key AttributeKey `json:"key"` + Value string `json:"value"` +} + +type Attributes []Attribute + +func (a Attributes) GetWithdrawRewardValue() int64 { + result := int64(0) + for _, att := range a { + if att.Key == AttributeAmount { + idx := strings.IndexByte(att.Value, 'u') + if idx < 0 { + continue + } + value := att.Value[:idx] + v, err := strconv.ParseInt(value, 10, 64) + if err != nil { + continue + } + result += v + } + } + return result +} + +// Data - "tx" sub object +type Data struct { + Contents Contents `json:"value"` +} + +// Contents - amount, fee, and memo +type Contents struct { + Message []Message `json:"msg"` + Fee Fee `json:"fee"` + Memo string `json:"memo"` +} + +// Message - an array that holds multiple 'particulars' entries. Possibly used for multiple transfers in one transaction? +type Message struct { + Type TxType + Value interface{} +} + +// MessageValueTransfer - from, to, and amount +type MessageValueTransfer struct { + FromAddr string `json:"from_address"` + ToAddr string `json:"to_address"` + Amount []Amount `json:"amount,omitempty"` +} + +// MessageValueDelegate - from, to, and amount +type MessageValueDelegate struct { + DelegatorAddr string `json:"delegator_address"` + ValidatorAddr string `json:"validator_address"` + Amount Amount `json:"amount,omitempty"` +} + +// Fee - also references the "amount" struct +type Fee struct { + FeeAmount []Amount `json:"amount"` +} + +// Amount - the asset & quantity. Always seems to be enclosed in an array/list for some reason. +// Perhaps used for multiple tokens transferred in a single sender/reciever transfer? +type Amount struct { + Denom string `json:"denom"` + Quantity string `json:"amount"` +} + +// # Staking + +type CosmosCommission struct { + Commision CosmosCommissionRates `json:"commission_rates"` +} + +type CosmosCommissionRates struct { + Rate string `json:"rate"` +} + +type Validators struct { + Result []Validator `json:"result"` +} + +type Validator struct { + Status int `json:"status"` + Address string `json:"operator_address"` + Commission CosmosCommission `json:"commission"` +} + +type Inflation struct { + Result string `json:"result"` +} + +type Delegations struct { + List []Delegation `json:"result"` +} + +type Delegation struct { + DelegatorAddress string `json:"delegator_address"` + ValidatorAddress string `json:"validator_address"` + Shares string `json:"shares"` + Balance struct { + Denom string `json:"denom"` + Amount string `json:"amount"` + } `json:"balance"` +} + +func (d *Delegation) Value() string { + shares := strings.Split(d.Balance.Amount, ".") + if len(shares) > 0 { + return shares[0] + } + return d.Balance.Amount +} + +type UnbondingDelegations struct { + List []UnbondingDelegation `json:"result"` +} + +type UnbondingDelegation struct { + Delegation + Entries []UnbondingDelegationEntry `json:"entries"` +} + +type UnbondingDelegationEntry struct { + DelegatorAddress string `json:"creation_height"` + CompletionTime string `json:"completion_time"` + Balance string `json:"balance"` +} + +type StakingPool struct { + Pool Pool `json:"result"` +} + +type Pool struct { + NotBondedTokens string `json:"not_bonded_tokens"` + BondedTokens string `json:"bonded_tokens"` +} + +// Block - top object of get las block request +type Block struct { + Meta BlockMeta `json:"block"` +} + +//BlockMeta - "Block" sub object +type BlockMeta struct { + Header BlockHeader `json:"header"` +} + +//BlockHeader - "BlockMeta" sub object, height +type BlockHeader struct { + Height string `json:"height"` +} + +//UnmarshalJSON reads different message types +func (m *Message) UnmarshalJSON(buf []byte) error { + var messageInternal struct { + Type TxType `json:"type"` + Value json.RawMessage `json:"value"` + } + + err := json.Unmarshal(buf, &messageInternal) + if err != nil { + return err + } + + m.Type = messageInternal.Type + + switch messageInternal.Type { + case MsgUndelegate, MsgDelegate, MsgWithdrawDelegationReward: + var msgDelegate MessageValueDelegate + err = json.Unmarshal(messageInternal.Value, &msgDelegate) + m.Value = msgDelegate + case MsgSend: + var msgTransfer MessageValueTransfer + err = json.Unmarshal(messageInternal.Value, &msgTransfer) + m.Value = msgTransfer + } + return err +} + +type AuthAccount struct { + Account Account `json:"result"` +} + +type Account struct { + Value AccountValue `json:"value"` +} + +type AccountValue struct { + Coins []Balance `json:"coins"` +} + +type Balance struct { + Denom DenomType `json:"denom"` + Amount string `json:"amount"` +} diff --git a/platform/kava/stake.go b/platform/kava/stake.go new file mode 100644 index 000000000..c3b120cef --- /dev/null +++ b/platform/kava/stake.go @@ -0,0 +1,230 @@ +package kava + +import ( + "fmt" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/services/assets" + "strconv" + "time" +) + +const ( + lockTime = 1814400 // in seconds (21 days) + minimumAmount = "1" +) + +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + result := make(blockatlas.StakeValidators, 0, len(validators)) + for _, v := range validators { + result = append(result, v) + } + return result, nil +} + +func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { + results := make(blockatlas.ValidatorPage, 0) + validators, err := p.client.GetValidators() + if err != nil { + return nil, err + } + pool, err := p.client.GetPool() + if err != nil { + return nil, err + } + + inflation, err := p.client.GetInflation() + if err != nil { + return nil, err + } + inflationValue, err := strconv.ParseFloat(inflation.Result, 32) + if err != nil { + return nil, errors.E("error to parse inflationValue to float", errors.TypePlatformUnmarshal) + } + + for _, validator := range validators.Result { + results = append(results, normalizeValidator(validator, pool.Pool, inflationValue)) + } + + return results, nil +} + +func (p *Platform) GetDetails() blockatlas.StakingDetails { + return blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: p.GetMaxAPR(), + }, + MinimumAmount: minimumAmount, + LockTime: lockTime, + Type: blockatlas.DelegationTypeDelegate, + } +} + +func (p *Platform) GetMaxAPR() float64 { + validators, err := p.GetValidators() + if err != nil { + logger.Error("GetMaxAPR", logger.Params{"details": err, "platform": p.Coin().Symbol}) + return blockatlas.DefaultAnnualReward + } + + var max = 0.0 + for _, e := range validators { + v := e.Details.Reward.Annual + if v > max { + max = v + } + } + + return max +} + +func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + results := make(blockatlas.DelegationsPage, 0) + delegations, err := p.client.GetDelegations(address) + if err != nil { + return nil, err + } + unbondingDelegations, err := p.client.GetUnbondingDelegations(address) + if err != nil { + return nil, err + } + if delegations.List == nil && unbondingDelegations.List == nil { + return results, nil + } + validators, err := assets.GetValidatorsMap(p) + if err != nil { + return nil, err + } + results = append(results, NormalizeDelegations(delegations.List, validators)...) + results = append(results, NormalizeUnbondingDelegations(unbondingDelegations.List, validators)...) + + return results, nil +} + +func (p *Platform) UndelegatedBalance(address string) (string, error) { + account, err := p.client.GetAccount(address) + if err != nil { + return "0", err + } + for _, coin := range account.Account.Value.Coins { + if coin.Denom == p.Denom() { + return coin.Amount, nil + } + } + return "0", nil +} + +func NormalizeDelegations(delegations []Delegation, validators blockatlas.ValidatorMap) []blockatlas.Delegation { + results := make([]blockatlas.Delegation, 0) + for _, v := range delegations { + validator, ok := validators[v.ValidatorAddress] + if !ok { + logger.Warn("Validator not found", logger.Params{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}) + validator = getUnknownValidator(v.ValidatorAddress) + + } + delegation := blockatlas.Delegation{ + Delegator: validator, + Value: v.Value(), + Status: blockatlas.DelegationStatusActive, + } + results = append(results, delegation) + } + return results +} + +func NormalizeUnbondingDelegations(delegations []UnbondingDelegation, validators blockatlas.ValidatorMap) []blockatlas.Delegation { + results := make([]blockatlas.Delegation, 0) + for _, v := range delegations { + for _, entry := range v.Entries { + validator, ok := validators[v.ValidatorAddress] + if !ok { + logger.Warn("Validator not found", logger.Params{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}) + validator = getUnknownValidator(v.ValidatorAddress) + } + t, _ := time.Parse(time.RFC3339, entry.CompletionTime) + delegation := blockatlas.Delegation{ + Delegator: validator, + Value: entry.Balance, + Status: blockatlas.DelegationStatusPending, + Metadata: blockatlas.DelegationMetaDataPending{ + AvailableDate: uint(t.Unix()), + }, + } + results = append(results, delegation) + } + } + return results +} + +func normalizeValidator(v Validator, p Pool, inflation float64) (validator blockatlas.Validator) { + reward := CalculateAnnualReward(p, inflation, v) + return blockatlas.Validator{ + Status: v.Status == 2, + ID: v.Address, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: reward}, + MinimumAmount: minimumAmount, + LockTime: lockTime, + Type: blockatlas.DelegationTypeDelegate, + }, + } +} + +func CalculateAnnualReward(p Pool, inflation float64, validator Validator) float64 { + if validator.Address == "kavavaloper1wu8m65vqazssv2rh8rthv532hzggfr3h9azwz9" { + fmt.Println(1) + } + notBondedTokens, err := strconv.ParseFloat(p.NotBondedTokens, 32) + if err != nil { + return 0 + } + + bondedTokens, err := strconv.ParseFloat(p.BondedTokens, 32) + if err != nil { + return 0 + } + + commission, err := strconv.ParseFloat(validator.Commission.Commision.Rate, 32) + if err != nil { + return 0 + } + result := (notBondedTokens + bondedTokens) / bondedTokens * inflation + return (result - (result * commission)) * 100 +} + +func (p *Platform) Denom() DenomType { + switch p.CoinIndex { + case coin.Cosmos().ID: + return DenomAtom + case coin.Kava().ID: + return DenomKava + default: + return DenomAtom + } +} + +func getUnknownValidator(address string) blockatlas.StakeValidator { + return blockatlas.StakeValidator{ + ID: address, + Status: false, + Info: blockatlas.StakeValidatorInfo{ + Name: "Decommissioned", + Description: "Decommissioned", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 0, + }, + LockTime: lockTime, + MinimumAmount: minimumAmount, + Type: blockatlas.DelegationTypeDelegate, + }, + } +} diff --git a/platform/kava/stake_test.go b/platform/kava/stake_test.go new file mode 100644 index 000000000..a177ce2c0 --- /dev/null +++ b/platform/kava/stake_test.go @@ -0,0 +1,152 @@ +package kava + +import ( + "encoding/json" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" + + "github.com/stretchr/testify/assert" +) + +const validatorSrc = ` +{ + "operator_address": "cosmosvaloper1lktjhnzkpkz3ehrg8psvmwhafg56kfss3q3t8m", + "consensus_pubkey": "cosmosvalconspub1zcjduepqelcwpat987h9yq0ck6g9fsc8t0mththk547gwvk0w4wnkpl0stnspr3hdc", + "jailed": false, + "status": 2, + "tokens": "1557750969185", + "delegator_shares": "1557750969185.000000000000000000", + "description": { + "moniker": "Umbrella ☔", + "identity": "A530AC4D75991FE2", + "website": "https://umbrellavalidator.com", + "details": "One of the winners of Cosmos Game of Stakes, and HackAtom3." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070400000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000", + "update_time": "2019-08-05T07:10:23.689753607Z" + } + }, + "min_self_delegation": "1" +}` + +const delegationsSrc = ` +[ + { + "delegator_address": "cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0", + "validator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", + "shares": "109999.000001746056062372", + "balance": { + "denom": "ukava", + "amount": "109999" + } + } +]` + +const unbondingDelegationsSrc = ` +[ + { + "delegator_address": "cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0", + "validator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", + "entries": [ + { + "creation_height": "0", + "completion_time": "2020-01-01T06:54:18.441436491Z", + "initial_balance": "109999", + "balance": "109999" + } + ] + } +]` + +var stakingPool = Pool{"1222", "200"} + +var cosmosValidator = Validator{Commission: CosmosCommission{CosmosCommissionRates{Rate: "0.4"}}} + +var inflation = 0.7 + +func TestNormalizeValidator(t *testing.T) { + var v Validator + _ = json.Unmarshal([]byte(validatorSrc), &v) + expected := blockatlas.Validator{ + Status: true, + ID: v.Address, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 462.6619201898575}, + LockTime: lockTime, + MinimumAmount: minimumAmount, + Type: blockatlas.DelegationTypeDelegate, + }, + } + result := normalizeValidator(v, stakingPool, inflation) + assert.Equal(t, expected, result) +} + +func TestCalculateAnnualReward(t *testing.T) { + result := CalculateAnnualReward(Pool{"1222", "200"}, inflation, cosmosValidator) + assert.Equal(t, 298.61999703347686, result) +} + +var validator1 = blockatlas.StakeValidator{ + ID: "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "Certus One", + Description: "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment.", + Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys/logo.png", + Website: "https://certus.one", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 9.259735525366604, + }, + LockTime: lockTime, + MinimumAmount: minimumAmount, + }, +} + +var validatorMap = blockatlas.ValidatorMap{ + "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys": validator1, +} + +func TestNormalizeDelegations(t *testing.T) { + var delegations []Delegation + err := json.Unmarshal([]byte(delegationsSrc), &delegations) + assert.NoError(t, err) + assert.NotNil(t, delegations) + + expected := []blockatlas.Delegation{ + { + Delegator: validator1, + Value: "109999", + Status: blockatlas.DelegationStatusActive, + }, + } + result := NormalizeDelegations(delegations, validatorMap) + assert.Equal(t, expected, result) +} + +func TestNormalizeUnbondingDelegations(t *testing.T) { + var delegations []UnbondingDelegation + err := json.Unmarshal([]byte(unbondingDelegationsSrc), &delegations) + assert.NoError(t, err) + assert.NotNil(t, delegations) + + expected := []blockatlas.Delegation{ + { + Delegator: validator1, + Value: "109999", + Status: blockatlas.DelegationStatusPending, + Metadata: blockatlas.DelegationMetaDataPending{ + AvailableDate: 1577861658, + }, + }, + } + result := NormalizeUnbondingDelegations(delegations, validatorMap) + assert.Equal(t, expected, result) +} diff --git a/platform/kava/transaction.go b/platform/kava/transaction.go new file mode 100644 index 000000000..6212e337c --- /dev/null +++ b/platform/kava/transaction.go @@ -0,0 +1,185 @@ +package kava + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/pkg/numbers" + "strconv" + "sync" + "time" +) + +func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + tagsList := []string{"transfer.recipient", "message.sender"} + var wg sync.WaitGroup + out := make(chan []Tx, len(tagsList)) + wg.Add(len(tagsList)) + for _, t := range tagsList { + go func(tag, addr string, wg *sync.WaitGroup) { + defer wg.Done() + page := 1 + txs, err := p.client.GetAddrTxs(addr, tag, page) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"address": tag, "tag": tag}) + return + } + // Condition when no more pages to paginate + if txs.PageTotal == "1" { + out <- txs.Txs + return + } + + totalPages, err := strconv.Atoi(txs.PageTotal) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"totalPages": totalPages}) + return + } + // gaia does support sort option, paginate to get latest transactions by passing total pages page + // https://github.com/cosmos/gaia/blob/f61b391aee5d04364d2b5539692bbb187ad9b946/docs/resources/gaiacli.md#query-transactions + txs2, err := p.client.GetAddrTxs(addr, tag, totalPages) + if err != nil { + logger.Error("GetAddrTxs", err, logger.Params{"address": tag, "tag": tag}) + return + } + out <- txs2.Txs + }(t, address, &wg) + } + wg.Wait() + close(out) + srcTxs := make([]Tx, 0) + for r := range out { + srcTxs = append(srcTxs, r...) + } + return p.NormalizeTxs(srcTxs), nil +} + +// NormalizeTxs converts multiple Cosmos transactions +func (p *Platform) NormalizeTxs(srcTxs []Tx) blockatlas.TxPage { + txMap := make(map[string]bool) + txs := make(blockatlas.TxPage, 0) + for _, srcTx := range srcTxs { + _, ok := txMap[srcTx.ID] + if ok { + continue + } + normalisedInputTx, ok := p.Normalize(&srcTx) + if ok { + txMap[srcTx.ID] = true + txs = append(txs, normalisedInputTx) + } + } + return txs +} + +// Normalize converts an Cosmos transaction into the generic model +func (p *Platform) Normalize(srcTx *Tx) (tx blockatlas.Tx, ok bool) { + date, err := time.Parse("2006-01-02T15:04:05Z", srcTx.Date) + if err != nil { + return blockatlas.Tx{}, false + } + block, err := strconv.ParseUint(srcTx.Block, 10, 64) + if err != nil { + return blockatlas.Tx{}, false + } + // Sometimes fees can be null objects (in the case of no fees e.g. F044F91441C460EDCD90E0063A65356676B7B20684D94C731CF4FAB204035B41) + fee := "0" + if len(srcTx.Data.Contents.Fee.FeeAmount) > 0 { + qty := srcTx.Data.Contents.Fee.FeeAmount[0].Quantity + if len(qty) > 0 && qty != fee { + fee, err = numbers.DecimalToSatoshis(srcTx.Data.Contents.Fee.FeeAmount[0].Quantity) + if err != nil { + return blockatlas.Tx{}, false + } + } + } + + status := blockatlas.StatusCompleted + // https://github.com/cosmos/cosmos-sdk/blob/95ddc242ad024ca78a359a13122dade6f14fd676/types/errors/errors.go#L19 + if srcTx.Code > 0 { + status = blockatlas.StatusError + } + + tx = blockatlas.Tx{ + ID: srcTx.ID, + Coin: p.Coin().ID, + Date: date.Unix(), + Status: status, + Fee: blockatlas.Amount(fee), + Block: block, + Memo: srcTx.Data.Contents.Memo, + } + + if len(srcTx.Data.Contents.Message) == 0 { + return tx, false + } + + msg := srcTx.Data.Contents.Message[0] + switch msg.Value.(type) { + case MessageValueTransfer: + transfer := msg.Value.(MessageValueTransfer) + p.fillTransfer(&tx, transfer) + return tx, true + case MessageValueDelegate: + delegate := msg.Value.(MessageValueDelegate) + p.fillDelegate(&tx, delegate, srcTx.Events, msg.Type) + return tx, true + } + return tx, false +} + +func (p *Platform) fillTransfer(tx *blockatlas.Tx, transfer MessageValueTransfer) { + if len(transfer.Amount) == 0 { + return + } + value, err := numbers.DecimalToSatoshis(transfer.Amount[0].Quantity) + if err != nil { + return + } + tx.From = transfer.FromAddr + tx.To = transfer.ToAddr + tx.Type = blockatlas.TxTransfer + tx.Meta = blockatlas.Transfer{ + Value: blockatlas.Amount(value), + Symbol: p.Coin().Symbol, + Decimals: p.Coin().Decimals, + } +} + +func (p *Platform) fillDelegate(tx *blockatlas.Tx, delegate MessageValueDelegate, events Events, msgType TxType) { + value := "" + if len(delegate.Amount.Quantity) > 0 { + var err error + value, err = numbers.DecimalToSatoshis(delegate.Amount.Quantity) + if err != nil { + return + } + } + tx.From = delegate.DelegatorAddr + tx.To = delegate.ValidatorAddr + tx.Type = blockatlas.TxAnyAction + + key := blockatlas.KeyStakeDelegate + title := blockatlas.KeyTitle("") + switch msgType { + case MsgDelegate: + tx.Direction = blockatlas.DirectionOutgoing + title = blockatlas.AnyActionDelegation + case MsgUndelegate: + tx.Direction = blockatlas.DirectionIncoming + title = blockatlas.AnyActionUndelegation + case MsgWithdrawDelegationReward: + tx.Direction = blockatlas.DirectionIncoming + title = blockatlas.AnyActionClaimRewards + key = blockatlas.KeyStakeClaimRewards + value = events.GetWithdrawRewardValue() + } + tx.Meta = blockatlas.AnyAction{ + Coin: p.Coin().ID, + Title: title, + Key: key, + Name: p.Coin().Name, + Symbol: p.Coin().Symbol, + Decimals: p.Coin().Decimals, + Value: blockatlas.Amount(value), + } +} diff --git a/platform/kava/transaction_test.go b/platform/kava/transaction_test.go new file mode 100644 index 000000000..1169330cd --- /dev/null +++ b/platform/kava/transaction_test.go @@ -0,0 +1,747 @@ +package kava + +import ( + "encoding/json" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" + + "github.com/trustwallet/blockatlas/coin" +) + +const transferSrc = ` +{ + "height": "151980", + "txhash": "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", + "raw_log": "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", + "logs": [ + { + "msg_index": "0", + "success": true, + "log": "" + } + ], + "gas_wanted": "100000", + "gas_used": "27678", + "tags": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl" + }, + { + "key": "recipient", + "value": "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae" + } + ], + "tx": { + "type": "auth/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl", + "to_address": "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae", + "amount": [ + { + "denom": "uatom", + "amount": "2271999999" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1" + } + ], + "gas": "100000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A21fdP6IbVC9hER5smiim8I4EbFeIF/bW81IKwmmsdjH" + }, + "signature": "MuR85p714L94tCenogRqzLh1bsbmhKTjs1L9JJPdhSVwQKh61EGlLqYGoUeN/n9xb+OOR9ESUOh2CAzVulKoVQ==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-05-04T17:57:57Z" +}` + +const transferSrcKava = ` +{ + "height": "151980", + "txhash": "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", + "raw_log": "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", + "logs": [ + { + "msg_index": "0", + "success": true, + "log": "" + } + ], + "gas_wanted": "100000", + "gas_used": "27678", + "tags": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn" + }, + { + "key": "recipient", + "value": "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0" + } + ], + "tx": { + "type": "auth/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn", + "to_address": "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0", + "amount": [ + { + "denom": "uatom", + "amount": "2271999999" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1" + } + ], + "gas": "100000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A21fdP6IbVC9hER5smiim8I4EbFeIF/bW81IKwmmsdjH" + }, + "signature": "MuR85p714L94tCenogRqzLh1bsbmhKTjs1L9JJPdhSVwQKh61EGlLqYGoUeN/n9xb+OOR9ESUOh2CAzVulKoVQ==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-05-04T17:57:57Z" +}` + +const failedTransferSrc = ` +{ + "height": "5552", + "txhash": "5E78C65A8C1A6C8239EBBBBF2E42020E6ADBA8037EDEA83BF88E1A9159CF13B8", + "code": 12, + "raw_log": "{\"codespace\":\"sdk\",\"code\":12,\"message\":\"out of gas in location: WritePerByte; gasWanted: 40000, gasUsed: 40480\"}", + "gas_wanted": "40000", + "gas_used": "40480", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "cosmos1shpfyt7psrff2ux7nznxvj6f7gq59fcqng5mku", + "to_address": "cosmos1za4pu5gxm80fg6sx0956f88l2sx7jfg2vf7nlc", + "amount": [ + { + "denom": "uatom", + "amount": "100000" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "2000" + } + ], + "gas": "40000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A0IDIokqw01U2YcdylvqD/sJHW5w9puS5vZWSf2GUaqL" + }, + "signature": "1Kwp4dBZUbVV6Fk8AFcmNfSqi7MXFfqyLvHexFZXoqcKh+sNuezry89RhDAWgSMNLyaK20hI2XcUyks+Vo4QEQ==" + } + ], + "memo": "UniCoins registration rewards" + } + }, + "timestamp": "2019-12-12T03:21:42Z" +}` + +const delegateSrc = ` +{ + "height":"1258202", + "txhash":"11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7", + "raw_log":"[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", + "logs":[ + { + "msg_index":"0", + "success":true, + "log":"" + } + ], + "gas_wanted":"200000", + "gas_used":"103206", + "tags":[ + { + "key":"action", + "value":"delegate" + }, + { + "key":"delegator", + "value":"cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3" + }, + { + "key":"destination-validator", + "value":"cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + } + ], + "tx":{ + "type":"auth/StdTx", + "value":{ + "msg":[ + { + "type":"cosmos-sdk/MsgDelegate", + "value":{ + "delegator_address":"cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3", + "validator_address":"cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", + "amount":{ + "denom":"uatom", + "amount":"49920" + } + } + } + ], + "fee":{ + "amount":[ + { + "denom":"uatom", + "amount":"5000" + } + ], + "gas":"200000" + }, + "signatures":[ + { + "pub_key":{ + "type":"tendermint/PubKeySecp256k1", + "value":"AsZL4GaIEGW6ogh1rEasxHtmirpeBnycLz4VR0rSVr9p" + }, + "signature":"w6sNVzTSsE32ERbBdYYySSp6nj+4xNODuq5GKRVb8q04jMHUbx9AhuZeAhYrkvdkzOl3bD7vRYGx9P1V6yHj0A==" + } + ], + "memo":"" + } + }, + "timestamp":"2019-08-01T04:10:16Z" +}` + +const unDelegateSrc = ` +{ + "height":"1257037", + "txhash":"A1EC36741FEF681F4A77B8F6032AD081100EE5ECB4CC76AEAC2174BC6B871CFE", + "data":"0C0889ECF7EA0510FB9D8CAD03", + "raw_log":"[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", + "logs":[ + { + "msg_index":"0", + "success":true, + "log":"" + } + ], + "gas_wanted":"200000", + "gas_used":"107804", + "tags":[ + { + "key":"action", + "value":"begin_unbonding" + }, + { + "key":"delegator", + "value":"cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94" + }, + { + "key":"source-validator", + "value":"cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v" + }, + { + "key":"end-time", + "value":"2019-08-22T01:55:21Z" + } + ], + "tx":{ + "type":"auth/StdTx", + "value":{ + "msg":[ + { + "type":"cosmos-sdk/MsgUndelegate", + "value":{ + "delegator_address":"cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94", + "validator_address":"cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v", + "amount":{ + "denom":"uatom", + "amount":"5100000000" + } + } + } + ], + "fee":{ + "amount":[ + { + "denom":"uatom", + "amount":"5000" + } + ], + "gas":"200000" + }, + "signatures":[ + { + "pub_key":{ + "type":"tendermint/PubKeySecp256k1", + "value":"A+tPzMXCW7vxmW5VN9Q/CO+fxnEXYlSMOklDVgaFutQD" + }, + "signature":"rh25A/RTm8TUTUGOGhufqxn9vLFef/04xEKMJLUD5QhBVabRADvEgAP1J842XTDtVBS0SpVD/MrPduqRp0nNzg==" + } + ], + "memo":"" + } + }, + "timestamp":"2019-08-01T01:55:21Z" +}` + +const claimRewardSrc1 = ` +{ + "height": "79678", + "txhash": "C382DCFDC30E2DA294421DAEAD5862F118592A7B000EE91F6BEF8452A1F525D7", + "gas_wanted": "1600000", + "gas_used": "492252", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgWithdrawDelegationReward", + "value": { + "delegator_address": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", + "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + } + }, + { + "type": "cosmos-sdk/MsgWithdrawDelegationReward", + "value": { + "delegator_address": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", + "validator_address": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2" + } + }, + { + "type": "cosmos-sdk/MsgWithdrawDelegationReward", + "value": { + "delegator_address": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", + "validator_address": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw" + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "1600000" + }, + "memo": "" + } + }, + "timestamp": "2019-12-18T03:04:33Z", + "events": [ + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug" + } + ] + }, + { + "type": "withdraw_rewards", + "attributes": [ + { + "key": "amount", + "value": "1138uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "40612uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2" + }, + { + "key": "amount", + "value": "954uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw" + }, + { + "key": "amount", + "value": "43574uatom" + }, + { + "key": "amount" + } + ] + } + ] +}` + +const claimRewardSrc2 = ` +{ + "height": "54561", + "txhash": "082BA88EC055A7C343A353297EAC104CE87C659E0DDD84621C9AC3C284232800", + "gas_wanted": "300000", + "gas_used": "156772", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgWithdrawDelegationReward", + "value": { + "delegator_address": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", + "validator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + } + }, + { + "type": "cosmos-sdk/MsgDelegate", + "value": { + "delegator_address": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", + "validator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", + "amount": { + "denom": "uatom", + "amount": "2692326" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "0" + } + ], + "gas": "300000" + }, + "memo": "复投" + } + }, + "timestamp": "2019-12-16T02:21:03Z", + "events": [ + { + "type": "delegate", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + }, + { + "key": "amount", + "value": "2692326" + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "module", + "value": "distribution" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46" + }, + { + "key": "amount", + "value": "2692701uatom" + } + ] + }, + { + "type": "withdraw_rewards", + "attributes": [ + { + "key": "amount", + "value": "2692701uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + } + ] + } + ] +}` + +var transferDst = blockatlas.Tx{ + ID: "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", + Coin: coin.ATOM, + From: "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl", + To: "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae", + Fee: "1", + Date: 1556992677, + Block: 151980, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxTransfer, + Meta: blockatlas.Transfer{ + Value: "2271999999", + Symbol: coin.Cosmos().Symbol, + Decimals: 6, + }, +} + +var transferDstKava = blockatlas.Tx{ + ID: "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", + Coin: coin.KAVA, + From: "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn", + To: "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0", + Fee: "1", + Date: 1556992677, + Block: 151980, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxTransfer, + Meta: blockatlas.Transfer{ + Value: "2271999999", + Symbol: coin.Kava().Symbol, + Decimals: 6, + }, +} + +var delegateDst = blockatlas.Tx{ + ID: "11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7", + Coin: coin.ATOM, + From: "cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3", + To: "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", + Fee: "5000", + Date: 1564632616, + Block: 1258202, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxAnyAction, + Direction: blockatlas.DirectionOutgoing, + Meta: blockatlas.AnyAction{ + Coin: coin.ATOM, + Title: blockatlas.AnyActionDelegation, + Key: blockatlas.KeyStakeDelegate, + Name: coin.Cosmos().Name, + Symbol: coin.Coins[coin.ATOM].Symbol, + Decimals: coin.Coins[coin.ATOM].Decimals, + Value: "49920", + }, +} + +var unDelegateDst = blockatlas.Tx{ + ID: "A1EC36741FEF681F4A77B8F6032AD081100EE5ECB4CC76AEAC2174BC6B871CFE", + Coin: coin.ATOM, + From: "cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94", + To: "cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v", + Fee: "5000", + Date: 1564624521, + Block: 1257037, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxAnyAction, + Direction: blockatlas.DirectionIncoming, + Meta: blockatlas.AnyAction{ + Coin: coin.ATOM, + Title: blockatlas.AnyActionUndelegation, + Key: blockatlas.KeyStakeDelegate, + Name: coin.Cosmos().Name, + Symbol: coin.Coins[coin.ATOM].Symbol, + Decimals: coin.Coins[coin.ATOM].Decimals, + Value: "5100000000", + }, +} + +var claimRewardDst2 = blockatlas.Tx{ + ID: "082BA88EC055A7C343A353297EAC104CE87C659E0DDD84621C9AC3C284232800", + Coin: coin.ATOM, + From: "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", + To: "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", + Fee: "0", + Date: 1576462863, + Block: 54561, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxAnyAction, + Direction: blockatlas.DirectionIncoming, + Memo: "复投", + Meta: blockatlas.AnyAction{ + Coin: coin.ATOM, + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + Name: coin.Cosmos().Name, + Symbol: coin.Coins[coin.ATOM].Symbol, + Decimals: coin.Coins[coin.ATOM].Decimals, + Value: "2692701", + }, +} + +var claimRewardDst1 = blockatlas.Tx{ + ID: "C382DCFDC30E2DA294421DAEAD5862F118592A7B000EE91F6BEF8452A1F525D7", + Coin: coin.ATOM, + From: "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", + To: "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", + Fee: "1000", + Date: 1576638273, + Block: 79678, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxAnyAction, + Direction: blockatlas.DirectionIncoming, + Memo: "", + Meta: blockatlas.AnyAction{ + Coin: coin.ATOM, + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + Name: coin.Cosmos().Name, + Symbol: coin.Coins[coin.ATOM].Symbol, + Decimals: coin.Coins[coin.ATOM].Decimals, + Value: "86278", + }, +} + +var failedTransferDst = blockatlas.Tx{ + ID: "5E78C65A8C1A6C8239EBBBBF2E42020E6ADBA8037EDEA83BF88E1A9159CF13B8", + Coin: coin.ATOM, + From: "cosmos1shpfyt7psrff2ux7nznxvj6f7gq59fcqng5mku", + To: "cosmos1za4pu5gxm80fg6sx0956f88l2sx7jfg2vf7nlc", + Fee: "2000", + Date: 1576120902, + Block: 5552, + Status: blockatlas.StatusError, + Type: blockatlas.TxTransfer, + Memo: "UniCoins registration rewards", + Meta: blockatlas.Transfer{ + Value: "100000", + Symbol: coin.Cosmos().Symbol, + Decimals: 6, + }, +} + +type test struct { + name string + platform Platform + Data string + want blockatlas.Tx +} + +func TestNormalize(t *testing.T) { + + cosmos := Platform{CoinIndex: coin.ATOM} + kava := Platform{CoinIndex: coin.KAVA} + + tests := []test{ + { + "test transfer tx", + cosmos, + transferSrc, + transferDst, + }, + { + "test delegate tx", + cosmos, + delegateSrc, + delegateDst, + }, + { + "test undelegate tx", + cosmos, + unDelegateSrc, + unDelegateDst, + }, + { + "test claimReward tx 1", + cosmos, + claimRewardSrc1, + claimRewardDst1, + }, + { + "test claimReward tx 2", + cosmos, + claimRewardSrc2, + claimRewardDst2, + }, + { + "test failed tx", + cosmos, + failedTransferSrc, + failedTransferDst, + }, + { + "test kava transfer tx", + kava, + transferSrcKava, + transferDstKava, + }, + } + for _, tt := range tests { + testNormalize(t, tt) + } +} + +func testNormalize(t *testing.T, tt test) { + t.Run(tt.name, func(t *testing.T) { + var srcTx Tx + err := json.Unmarshal([]byte(tt.Data), &srcTx) + assert.Nil(t, err) + tx, ok := tt.platform.Normalize(&srcTx) + assert.True(t, ok) + assert.Equal(t, tt.want, tx, "transfer: tx don't equal") + }) +} diff --git a/platform/platform.go b/platform/platform.go index 8efdbf35c..a796cb017 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -2,6 +2,7 @@ package platform import ( "fmt" + "github.com/trustwallet/blockatlas/platform/kava" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/coin" @@ -84,7 +85,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Stellar().Handle: stellar.Init(coin.XLM, GetApiVar(coin.XLM)), coin.Kin().Handle: stellar.Init(coin.KIN, GetApiVar(coin.KIN)), coin.Cosmos().Handle: cosmos.Init(coin.ATOM, GetApiVar(coin.ATOM)), - coin.Kava().Handle: cosmos.Init(coin.KAVA, GetApiVar(coin.KAVA)), + coin.Kava().Handle: kava.Init(coin.KAVA, GetApiVar(coin.KAVA)), coin.Bitcoin().Handle: bitcoin.Init(coin.BTC, GetApiVar(coin.BTC)), coin.Litecoin().Handle: bitcoin.Init(coin.LTC, GetApiVar(coin.LTC)), coin.Bitcoincash().Handle: bitcoin.Init(coin.BCH, GetApiVar(coin.BCH)), From b573ace185121f4cd763c982ae646d79fcb81b98 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 31 Aug 2020 18:03:32 +0800 Subject: [PATCH 367/506] [Smart Chain] Add config (#1206) * Add smart chain config * update bsc sample config --- coin/coins.go | 18 +++++++++++++++++- coin/coins.yml | 9 +++++++++ coin/gen.go | 24 +++++++++++++++++++++--- coin/gen_test.go | 14 +++++++++++--- config.yml | 4 ++++ platform/platform.go | 2 ++ 6 files changed, 64 insertions(+), 7 deletions(-) diff --git a/coin/coins.go b/coin/coins.go index cd2dc90e8..98cfe5134 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2020-08-14 12:59:11.508841 +0800 CST m=+0.001995886 +// 2020-08-29 17:30:10.735834 +0800 CST m=+0.001454710 // using data from coins.yml package coin @@ -13,6 +13,7 @@ type Coin struct { ID uint Handle string Symbol string + PreferedSymbol string Name string Decimals uint BlockTime int @@ -75,6 +76,7 @@ const ( SOL = 501 NEAR = 397 ERD = 508 + BSC = 10000714 ) var Coins = map[uint]Coin{ @@ -578,6 +580,17 @@ var Coins = map[uint]Coin{ MinConfirmations: 0, SampleAddr: "erd12tqtt5zcg6vpw65y4hkanvt49kzq695sr3ctuszjy92xw0ppzcssy2xd5r", }, + BSC: { + ID: 10000714, + Handle: "bsc", + Symbol: "BNB", + PreferedSymbol: "BSC", + Name: "Binance Smart Chain", + Decimals: 18, + BlockTime: 3000, + MinConfirmations: 0, + SampleAddr: "0x3efb67b34a9b69b54d4027e044954f483dc31678", + }, } func Ethereum() Coin { return Coins[ETH] @@ -729,4 +742,7 @@ func Near() Coin { func Elrond() Coin { return Coins[ERD] } +func Bsc() Coin { + return Coins[BSC] +} diff --git a/coin/coins.yml b/coin/coins.yml index b297c168f..619b48df1 100644 --- a/coin/coins.yml +++ b/coin/coins.yml @@ -396,3 +396,12 @@ decimals: 18 blockTime: 6000 sampleAddress: 'erd12tqtt5zcg6vpw65y4hkanvt49kzq695sr3ctuszjy92xw0ppzcssy2xd5r' + +- id: 10000714 + symbol: BNB + preferedSymbol: BSC + handle: bsc + name: 'Binance Smart Chain' + decimals: 18 + blockTime: 3000 + sampleAddress: '0x3efb67b34a9b69b54d4027e044954f483dc31678' diff --git a/coin/gen.go b/coin/gen.go index ee65f3bad..665740291 100644 --- a/coin/gen.go +++ b/coin/gen.go @@ -6,12 +6,13 @@ package main import ( - "gopkg.in/yaml.v2" "html/template" "log" "os" "strings" "time" + + "gopkg.in/yaml.v2" ) const ( @@ -32,6 +33,7 @@ type Coin struct { ID uint Handle string Symbol string + PreferedSymbol string Name string Decimals uint BlockTime int @@ -45,16 +47,27 @@ func (c *Coin) String() string { const ( {{- range .Coins }} +{{- if .PreferedSymbol}} + {{ .PreferedSymbol }} = {{ .ID }} +{{- else}} {{ .Symbol }} = {{ .ID }} +{{- end}} {{- end }} ) var Coins = map[uint]Coin{ {{- range .Coins }} +{{- if .PreferedSymbol }} + {{ .PreferedSymbol }}: { +{{- else }} {{ .Symbol }}: { +{{- end }} ID: {{.ID}}, Handle: "{{.Handle}}", Symbol: "{{.Symbol}}", +{{- if .PreferedSymbol }} + PreferedSymbol: "{{.PreferedSymbol}}", +{{- end }} Name: "{{.Name}}", Decimals: {{.Decimals}}, BlockTime: {{.BlockTime}}, @@ -65,8 +78,12 @@ var Coins = map[uint]Coin{ } {{- range .Coins }} -func {{ .Handle.Upper }}() Coin { +func {{ .Handle.Capitalize }}() Coin { +{{- if .PreferedSymbol }} + return Coins[{{ .PreferedSymbol }}] +{{- else }} return Coins[{{ .Symbol }}] +{{- end}} } {{- end }} @@ -76,7 +93,7 @@ func {{ .Handle.Upper }}() Coin { type Handle string -func (h Handle) Upper() string { +func (h Handle) Capitalize() string { return strings.Title(string(h)) } @@ -84,6 +101,7 @@ type Coin struct { ID uint `yaml:"id"` Handle Handle `yaml:"handle"` Symbol string `yaml:"symbol"` + PreferedSymbol string `yaml:"preferedSymbol,omitempty"` Name string `yaml:"name"` Decimals uint `yaml:"decimals"` BlockTime int `yaml:"blockTime"` diff --git a/coin/gen_test.go b/coin/gen_test.go index 45e8f47da..e4229aec0 100644 --- a/coin/gen_test.go +++ b/coin/gen_test.go @@ -2,12 +2,13 @@ package coin import ( "fmt" - "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v2" "io/ioutil" "os" "strings" "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v2" ) const ( @@ -19,6 +20,7 @@ type TestCoin struct { ID uint `yaml:"id"` Handle string `yaml:"handle"` Symbol string `yaml:"symbol"` + PreferedSymbol string `yaml:"preferedSymbol,omitempty"` Name string `yaml:"name"` Decimals uint `yaml:"decimals"` BlockTime int `yaml:"blockTime"` @@ -69,8 +71,14 @@ func TestCoinFile(t *testing.T) { s := strings.Title(want.Handle) method := fmt.Sprintf("func %s() Coin", s) assert.True(t, strings.Contains(code, method), "Coin method not found") - enum := fmt.Sprintf("%s = %d", want.Symbol, want.ID) + var enum string + if want.PreferedSymbol != "" { + enum = fmt.Sprintf("%s = %d", want.PreferedSymbol, want.ID) + } else { + enum = fmt.Sprintf("%s = %d", want.Symbol, want.ID) + } assert.True(t, strings.Contains(code, enum), "Coin enum not found") + } } diff --git a/config.yml b/config.yml index 75a1b1aa8..9e001433c 100644 --- a/config.yml +++ b/config.yml @@ -225,3 +225,7 @@ near: elrond: api: https://api.elrond.com + +# bsc: + # api: + # rpc: diff --git a/platform/platform.go b/platform/platform.go index a796cb017..064fbb1d5 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -2,6 +2,7 @@ package platform import ( "fmt" + "github.com/trustwallet/blockatlas/platform/kava" "github.com/spf13/viper" @@ -107,6 +108,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Callisto().Handle: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO)), coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN)), coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), + coin.Bsc().Handle: ethereum.InitWithBlockbook(coin.BSC, GetApiVar(coin.BSC), GetRpcVar(coin.BSC)), coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), coin.Near().Handle: near.Init(GetApiVar(coin.NEAR)), coin.Elrond().Handle: elrond.Init(coin.ERD, GetApiVar(coin.ERD)), From 1702681ef869b0ff54d7d0accc33cb1a8ef99562 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Mon, 31 Aug 2020 18:35:15 +0300 Subject: [PATCH 368/506] Create codeql-analysis.yml (#1208) --- .github/workflows/codeql-analysis.yml | 62 +++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000..973d564b7 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,62 @@ +name: "CodeQL" + +on: + push: + branches: [master] + pull_request: + # The branches below must be a subset of the branches above + branches: [master] + schedule: + - cron: '0 1 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + # Override automatic language detection by changing the below list + # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] + language: ['go'] + # Learn more... + # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 33772ade7ee0b3fe4a02b7a30c773320e469c0ce Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Tue, 1 Sep 2020 03:24:37 +0300 Subject: [PATCH 369/506] [General] Implement token searcher (#1197) * Init token searcher * Continue to work on tokens searcher * Continue to work on tokens searcher * Add bulkInsert, add UpdateAssociationsForExistingAddresses, update models * Update GetAssociationsByAddresses * Add AddAssociationsForAddress * Setup test * Add tests * Add new tests * Add new tests * Some cleanup & fixes * Add new db function * Start to add api * Almost finish with assets index api * Setup tokens subscriber.go * Setup api * Add basic functions skeleton * Add basic functions skeleton #2 * Some api changes * Some api changes #2 * Add api test * Add new api tests * Fill fetchAssets func * Make fetchAssets concurrent * Add tests for getAssets * Add tests for getAssets * Finish with api * Some fixes * Fixes, full flow test done * Fixes * Fix of tests * Small cleanup * Start to change db models and implementation * Setup GetSubscribedAddresses() * Rewrite GetSubscribedAddresses * Rewrite AddSubs & DeleteSubs * Start to rewrite tests * Continue with tests * Start fix tests * Update tests * Continue with tests * Fix integration tests * Fix unit test * Fixes to address to asset * Fix integration * Fix integration * Add from param, add tests * Fixes after review * Change CI Co-authored-by: Alexey Prazdnikov Co-authored-by: maxUo --- .github/workflows/master.yml | 3 + .github/workflows/pr-build.yml | 3 + Makefile | 32 +- api/api.go | 5 + api/endpoint/token.go | 15 + api/registry.go | 7 + cmd/api/main.go | 34 +- cmd/notifier/main.go | 2 +- cmd/parser/main.go | 4 +- cmd/searcher/main.go | 74 +++++ cmd/subscriber/main.go | 15 +- config.yml | 7 +- configmock.yml | 4 +- db/addresstoasset.go | 279 ++++++++++++++++ db/db.go | 58 +++- db/models/address.go | 8 + db/models/addresstoasset.go | 17 + db/models/asset.go | 8 + db/models/subscriptions.go | 20 +- db/notification.go | 86 +++++ db/subscriptions.go | 105 ------- go.mod | 19 +- go.sum | 34 ++ mq/mq.go | 7 +- pkg/address/address.go | 18 ++ pkg/address/address_test.go | 12 + pkg/blockatlas/tx.go | 23 ++ pkg/blockatlas/tx_test.go | 44 +++ platform/tron/token.go | 3 +- services/{observer => }/notifier/base.go | 17 +- services/{observer => }/notifier/delivery.go | 4 +- services/{observer => }/notifier/models.go | 4 +- .../{observer => }/notifier/models_test.go | 0 services/{observer => }/parser/parser.go | 19 +- services/{observer => }/parser/parser_test.go | 3 +- services/subscriber/subscriber.go | 3 + services/subscriber/tokens.go | 37 +++ .../transactions.go} | 19 +- .../transactions_test.go} | 16 +- services/tokensearcher/api.go | 183 +++++++++++ services/tokensearcher/api_test.go | 93 ++++++ services/tokensearcher/association.go | 62 ++++ services/tokensearcher/association_test.go | 100 ++++++ services/tokensearcher/models.go | 23 ++ services/tokensearcher/tokensearcher.go | 53 ++++ .../integration/db_test/subscriptions_test.go | 297 ++++-------------- .../db_test/tokenassociations_test.go | 179 +++++++++++ .../data/wanted_subscriptions_added.json | 8 +- .../observer_test/full_flow_test.go | 9 +- .../observer_test/notifier_test.go | 5 +- .../integration/observer_test/parser_test.go | 4 +- .../observer_test/subscriber_test.go | 47 ++- tests/integration/setup/postgres.go | 6 +- 53 files changed, 1667 insertions(+), 470 deletions(-) create mode 100644 cmd/searcher/main.go create mode 100644 db/addresstoasset.go create mode 100644 db/models/address.go create mode 100644 db/models/addresstoasset.go create mode 100644 db/models/asset.go create mode 100644 db/notification.go delete mode 100644 db/subscriptions.go rename services/{observer => }/notifier/base.go (70%) rename services/{observer => }/notifier/delivery.go (89%) rename services/{observer => }/notifier/models.go (95%) rename services/{observer => }/notifier/models_test.go (100%) rename services/{observer => }/parser/parser.go (96%) rename services/{observer => }/parser/parser_test.go (98%) create mode 100644 services/subscriber/subscriber.go create mode 100644 services/subscriber/tokens.go rename services/{observer/subscriber/subscriber.go => subscriber/transactions.go} (66%) rename services/{observer/subscriber/subscriber_test.go => subscriber/transactions_test.go} (59%) create mode 100644 services/tokensearcher/api.go create mode 100644 services/tokensearcher/api_test.go create mode 100644 services/tokensearcher/association.go create mode 100644 services/tokensearcher/association_test.go create mode 100644 services/tokensearcher/models.go create mode 100644 services/tokensearcher/tokensearcher.go create mode 100644 tests/integration/db_test/tokenassociations_test.go diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 3414c5b33..75861debc 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -112,15 +112,18 @@ jobs: PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} OBSERVER_SUBSCRIBER_IMAGE: ${{ secrets.REGISTRY }}:subscriber-${{ steps.hash.outputs.sha7 }} OBSERVER_NOTIFIER_IMAGE: ${{ secrets.REGISTRY }}:notifier-${{ steps.hash.outputs.sha7 }} + SEARCHER_IMAGE: ${{ secrets.REGISTRY }}:searcher-${{ steps.hash.outputs.sha7 }} run: | docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . docker build --build-arg SERVICE=subscriber/subscriber -f Dockerfile.runner -t $OBSERVER_SUBSCRIBER_IMAGE . docker build --build-arg SERVICE=notifier/notifier -f Dockerfile.runner -t $OBSERVER_NOTIFIER_IMAGE . + docker build --build-arg SERVICE=searcher/searcher -f Dockerfile.runner -t $SEARCHER_IMAGE . docker push $API_IMAGE docker push $PARSER_IMAGE docker push $OBSERVER_SUBSCRIBER_IMAGE docker push $OBSERVER_NOTIFIER_IMAGE + docker push $SEARCHER_IMAGE deploy: name: CD diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 1b81a1b5a..1759a5124 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -64,12 +64,15 @@ jobs: PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} OBSERVER_SUBSCRIBER_IMAGE: ${{ secrets.REGISTRY }}:subscriber-${{ steps.hash.outputs.sha7 }} OBSERVER_NOTIFIER_IMAGE: ${{ secrets.REGISTRY }}:notifier-${{ steps.hash.outputs.sha7 }} + SEARCHER_IMAGE: ${{ secrets.REGISTRY }}:searcher-${{ steps.hash.outputs.sha7 }} run: | docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . docker build --build-arg SERVICE=subscriber/subscriber -f Dockerfile.runner -t $OBSERVER_SUBSCRIBER_IMAGE . docker build --build-arg SERVICE=notifier/notifier -f Dockerfile.runner -t $OBSERVER_NOTIFIER_IMAGE . + docker build --build-arg SERVICE=searcher/searcher -f Dockerfile.runner -t $SEARCHER_IMAGE . docker push $API_IMAGE docker push $PARSER_IMAGE docker push $OBSERVER_SUBSCRIBER_IMAGE docker push $OBSERVER_NOTIFIER_IMAGE + docker push $SEARCHER_IMAGE diff --git a/Makefile b/Makefile index cb3c7b913..d630b4248 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ API := api NOTIFIER := notifier PARSER := parser SUBSCRIBER := subscriber +SEARCHER := searcher COIN_FILE := coin/coins.yml COIN_GO_FILE := coin/coins.go GEN_COIN_FILE := coin/gen.go @@ -42,6 +43,7 @@ STDERR := /tmp/.$(PROJECT_NAME)-stderr.txt # PID file will keep the process id of the server PID_API := /tmp/.$(PROJECT_NAME).$(API).pid +PID_SEARCHER := /tmp/.$(PROJECT_NAME).$(SEARCHER).pid PID_NOTIFIER := /tmp/.$(PROJECT_NAME).$(NOTIFIER).pid PID_PARSER := /tmp/.$(PROJECT_NAME).$(PARSER).pid PID_SUBSCRIBER := /tmp/.$(PROJECT_NAME).$(SUBSCRIBER).pid @@ -54,52 +56,60 @@ install: go-get ## start: Start API, Observer and Sync in development mode. start: - @bash -c "$(MAKE) clean compile start-api start-parser start-notifier start-subscriber" + @bash -c "$(MAKE) clean compile start-api start-parser start-notifier start-subscriber start-searcher" ## start-api: Start platform api in development mode. start-api: stop @echo " > Starting $(PROJECT_NAME)" @-$(GOBIN)/$(API)/api -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_API) - @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" + @cat $(PID_API) | sed "/^/s/^/ \> Api PID: /" @echo " > Error log: $(STDERR)" # start-platform-api-mock: Start API. Similar to start-platform-api, but uses config file with mock URLs, and port 8437. start-api-mock: stop start-mockserver @echo " > Starting $(PROJECT_NAME) API" @-$(GOBIN)/$(API)/api -p 8437 -c $(CONFIG_MOCK_FILE) 2>&1 & echo $$! > $(PID_API) - @cat $(PID_API) | sed "/^/s/^/ \> API PID: /" + @cat $(PID_API) | sed "/^/s/^/ \> Mock PID: /" @echo " > Error log: $(STDERR)" ## start-observer-parser: Start observer-parser in development mode. start-parser: stop @echo " > Starting $(PROJECT_NAME)" @-$(GOBIN)/$(PARSER)/parser -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_PARSER) - @cat $(PID_PARSER) | sed "/^/s/^/ \> Sync PID: /" + @cat $(PID_PARSER) | sed "/^/s/^/ \> Parser PID: /" @echo " > Error log: $(STDERR)" ## start-observer-notifier: Start observer-notifier in development mode. start-notifier: stop @echo " > Starting $(PROJECT_NAME)" @-$(GOBIN)/$(NOTIFIER)/notifier -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_NOTIFIER) - @cat $(PID_NOTIFIER) | sed "/^/s/^/ \> Sync PID: /" + @cat $(PID_NOTIFIER) | sed "/^/s/^/ \> Notifier PID: /" @echo " > Error log: $(STDERR)" ## start-observer-subscriber: Start observer-subscriber in development mode. start-subscriber: stop @echo " > Starting $(PROJECT_NAME)" @-$(GOBIN)/$(SUBSCRIBER)/subscriber -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SUBSCRIBER) - @cat $(PID_SUBSCRIBER) | sed "/^/s/^/ \> Sync PID: /" + @cat $(PID_SUBSCRIBER) | sed "/^/s/^/ \> Subscriber PID: /" + @echo " > Error log: $(STDERR)" + +## start-api: Start searcher in development mode. +start-searcher: stop + @echo " > Starting $(PROJECT_NAME)" + @-$(GOBIN)/$(SEARCHER)/searcher -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SEARCHER) + @cat $(PID_SEARCHER) | sed "/^/s/^/ \> Searcher PID: /" @echo " > Error log: $(STDERR)" ## stop: Stop development mode. stop: - @-touch $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_MOCKSERVER) + @-touch $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_MOCKSERVER) $(PID_SEARCHER) @-kill `cat $(PID_API)` 2> /dev/null || true @-kill `cat $(PID_NOTIFIER)` 2> /dev/null || true @-kill `cat $(PID_PARSER)` 2> /dev/null || true @-kill `cat $(PID_SUBSCRIBER)` 2> /dev/null || true @-kill `cat $(PID_MOCKSERVER)` 2> /dev/null || true - @-rm $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_MOCKSERVER) + @-kill `cat $(PID_SEARCHER)` 2> /dev/null || true + @-rm $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_MOCKSERVER) $(PID_SEARCHER) stop-mockserver: @-touch $(PID_MOCKSERVER) @@ -219,7 +229,7 @@ endif go-compile: go-get go-build -go-build: go-build-api go-build-notifier go-build-parser go-build-subscriber +go-build: go-build-api go-build-notifier go-build-parser go-build-subscriber go-build-searcher docker-shutdown: @echo " > Shutdown docker containers..." @@ -247,6 +257,10 @@ go-build-subscriber: @echo " > Building subscriber binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SUBSCRIBER)/subscriber ./cmd/$(SUBSCRIBER) +go-build-searcher: + @echo " > Building searcher binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SEARCHER)/searcher ./cmd/$(SEARCHER) + go-generate: @echo " > Generating dependency files..." GOBIN=$(GOBIN) go generate $(generate) diff --git a/api/api.go b/api/api.go index 32bc8506d..01ed5070e 100644 --- a/api/api.go +++ b/api/api.go @@ -6,6 +6,7 @@ import ( "github.com/swaggo/gin-swagger/swaggerFiles" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/services/tokensearcher" ) func SetupPlatformAPI(router gin.IRouter) { @@ -23,6 +24,10 @@ func SetupPlatformAPI(router gin.IRouter) { RegisterBasicAPI(router) } +func SetupTokensIndexAPI(router gin.IRouter, instance tokensearcher.Instance) { + RegisterTokensIndexAPI(router, instance) +} + func SetupSwaggerAPI(router gin.IRouter) { router.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) } diff --git a/api/endpoint/token.go b/api/endpoint/token.go index 84da5b7fc..6c0c6a140 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -3,6 +3,7 @@ package endpoint import ( "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/tokensearcher" "net/http" "strconv" "sync" @@ -123,3 +124,17 @@ func getTokens(tokenAPI blockatlas.TokensAPI, addresses []string, data *tokensRe } data.mu.Unlock() } + +func GetTokensByAddressIndexer(c *gin.Context, instance tokensearcher.Instance) { + var query tokensearcher.Request + if err := c.Bind(&query); err != nil { + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) + return + } + result, err := instance.HandleTokensRequest(query, c.Request.Context()) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) + return + } + c.JSON(http.StatusOK, result) +} diff --git a/api/registry.go b/api/registry.go index 2346249c3..fdd4eff0a 100644 --- a/api/registry.go +++ b/api/registry.go @@ -8,6 +8,7 @@ import ( "github.com/trustwallet/blockatlas/api/middleware" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/services/tokensearcher" "time" ) @@ -106,3 +107,9 @@ func RegisterBasicAPI(router gin.IRouter) { router.GET("/", endpoint.GetStatus) router.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) } + +func RegisterTokensIndexAPI(router gin.IRouter, instance tokensearcher.Instance) { + router.POST("/v3/tokens", func(c *gin.Context) { + endpoint.GetTokensByAddressIndexer(c, instance) + }) +} diff --git a/cmd/api/main.go b/cmd/api/main.go index b840f241c..ab6f60429 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -4,20 +4,28 @@ import ( "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/db" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/services/tokensearcher" + "time" ) const ( defaultPort = "8420" defaultConfigPath = "../../config.yml" + prod = "prod" ) var ( port, confPath string engine *gin.Engine + database *db.Instance + t tokensearcher.Instance + restAPI string ) func init() { @@ -26,18 +34,42 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() + restAPI = viper.GetString("rest_api") engine = internal.InitEngine(viper.GetString("gin.mode")) + if restAPI == "tokens" || restAPI == "all" { + pgUri := viper.GetString("postgres.uri") + + var err error + database, err = db.New(pgUri, prod) + if err != nil { + logger.Fatal(err) + } + + mqHost := viper.GetString("observer.rabbitmq.uri") + prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + internal.InitRabbitMQ(mqHost, prefetchCount) + if err := mq.TokensRegistration.Declare(); err != nil { + logger.Fatal(err) + } + t = tokensearcher.Init(database, platform.TokensAPIs, mq.TokensRegistration) + + go db.RestoreConnectionWorker(database, time.Second*10, pgUri) + go mq.FatalWorker(time.Second * 10) + } platform.Init(viper.GetStringSlice("platform")) } func main() { - switch viper.GetString("rest_api") { + switch restAPI { case "swagger": api.SetupSwaggerAPI(engine) case "platform": api.SetupPlatformAPI(engine) + case "tokens": + api.SetupTokensIndexAPI(engine, t) default: + api.SetupTokensIndexAPI(engine, t) api.SetupSwaggerAPI(engine) api.SetupPlatformAPI(engine) } diff --git a/cmd/notifier/main.go b/cmd/notifier/main.go index b71fe186e..5bee2ce6b 100644 --- a/cmd/notifier/main.go +++ b/cmd/notifier/main.go @@ -7,7 +7,7 @@ import ( "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/services/observer/notifier" + "github.com/trustwallet/blockatlas/services/notifier" "time" ) diff --git a/cmd/parser/main.go b/cmd/parser/main.go index ccbd384b6..e9b721cc3 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -9,7 +9,7 @@ import ( "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/services/observer/parser" + "github.com/trustwallet/blockatlas/services/parser" "os" "os/signal" "sync" @@ -107,7 +107,7 @@ func main() { params := parser.Params{ Ctx: ctx, Api: api, - Queue: mq.RawTransactions, + Queue: []mq.Queue{mq.RawTransactions, mq.TokensRegistration}, ParsingBlocksInterval: pollInterval, FetchBlocksTimeout: fetchBlocksInterval, BacklogCount: backlogCount, diff --git a/cmd/searcher/main.go b/cmd/searcher/main.go new file mode 100644 index 000000000..b58faa1a4 --- /dev/null +++ b/cmd/searcher/main.go @@ -0,0 +1,74 @@ +package main + +import ( + "context" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/services/notifier" + "github.com/trustwallet/blockatlas/services/tokensearcher" + "time" +) + +const ( + defaultConfigPath = "../../config.yml" + prod = "prod" +) + +var ( + confPath string + database *db.Instance +) + +func init() { + _, confPath = internal.ParseArgs("", defaultConfigPath) + + internal.InitConfig(confPath) + logger.InitLogger() + + mqHost := viper.GetString("observer.rabbitmq.uri") + prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") + pgUri := viper.GetString("postgres.uri") + + internal.InitRabbitMQ(mqHost, prefetchCount) + + if err := mq.RawTransactions.Declare(); err != nil { + logger.Fatal(err) + } + + if err := mq.TxNotifications.Declare(); err != nil { + logger.Fatal(err) + } + + var err error + database, err = db.New(pgUri, prod) + if err != nil { + logger.Fatal(err) + } + + if maxPushNotificationsBatchLimit == 0 { + notifier.MaxPushNotificationsBatchLimit = notifier.DefaultPushNotificationsBatchLimit + } else { + notifier.MaxPushNotificationsBatchLimit = maxPushNotificationsBatchLimit + } + + logger.Info("maxPushNotificationsBatchLimit ", logger.Params{"limit": maxPushNotificationsBatchLimit}) + + go mq.FatalWorker(time.Second * 10) + go db.RestoreConnectionWorker(database, time.Second*10, pgUri) + + time.Sleep(time.Millisecond) +} + +func main() { + defer mq.Close() + + ctx, cancel := context.WithCancel(context.Background()) + + go mq.TokensRegistration.RunConsumerWithCancelAndDbConn(tokensearcher.Run, database, ctx) + + internal.SetupGracefulShutdownForObserver(cancel) +} diff --git a/cmd/subscriber/main.go b/cmd/subscriber/main.go index 38d8dfdc5..ee130d00e 100644 --- a/cmd/subscriber/main.go +++ b/cmd/subscriber/main.go @@ -8,7 +8,7 @@ import ( "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/services/observer/subscriber" + "github.com/trustwallet/blockatlas/services/subscriber" "time" ) @@ -51,9 +51,20 @@ func main() { if err := mq.Subscriptions.Declare(); err != nil { logger.Fatal(err) } + if err := mq.TokensRegistration.Declare(); err != nil { + logger.Fatal(err) + } ctx, cancel := context.WithCancel(context.Background()) - go mq.Subscriptions.RunConsumerWithCancelAndDbConn(subscriber.RunSubscriber, database, ctx) + subscriberType := subscriber.Subscriber(viper.GetString("subscriber")) + switch subscriberType { + case subscriber.Tokens: + go mq.TokensRegistration.RunConsumerWithCancelAndDbConn(subscriber.RunTokensSubscriber, database, ctx) + case subscriber.Notifications: + go mq.Subscriptions.RunConsumerWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, database, ctx) + default: + logger.Fatal("bad subscriber: " + subscriberType) + } internal.SetupGracefulShutdownForObserver(cancel) } diff --git a/config.yml b/config.yml index 9e001433c..c9c2b9ba4 100644 --- a/config.yml +++ b/config.yml @@ -11,9 +11,12 @@ gin: # You can see all the coin handles at coins/coins.yml file platform: [all] -# Can be platform or swagger +# Can be platform or swagger, or tokens, or all rest_api: all +# Can be tokens or notifications +subscriber: tokens + # The transaction watcher observer: # Don't request blocks older than this @@ -69,7 +72,7 @@ ethereum: api: https://localhost:4567 #(Trust-Ray API) blockbook_api: https://eth1.trezor.io collections_api: https://api.opensea.io -# collections_api_key: [opensea_api_key] + # collections_api_key: [opensea_api_key] rpc: https://main-rpc.linkpool.io # [ETC] Ethereum Classic: https://ethereumclassic.org (Trust-Ray API) diff --git a/configmock.yml b/configmock.yml index 4e030b440..db7167871 100644 --- a/configmock.yml +++ b/configmock.yml @@ -13,8 +13,8 @@ gin: # You can see all the coin handles at coins/coins.yml file platform: all -# Can be platform or swagger -rest_api: all +# Can be platform or swagger, or tokens, or all +rest_api: platform # The transaction watcher observer: diff --git a/db/addresstoasset.go b/db/addresstoasset.go new file mode 100644 index 000000000..924a40db0 --- /dev/null +++ b/db/addresstoasset.go @@ -0,0 +1,279 @@ +package db + +import ( + "context" + "github.com/jinzhu/gorm" + "github.com/trustwallet/blockatlas/db/models" + "go.elastic.co/apm/module/apmgorm" + "time" +) + +func (i Instance) GetSubscribedAddressesForAssets(ctx context.Context, addresses []string) ([]models.Address, error) { + db := apmgorm.WithContext(ctx, i.Gorm) + + addressesSubQuery := db. + Table("addresses"). + Select("id"). + Where("address in (?)", addresses). + QueryExpr() + + var assetSubs []models.AssetSubscription + err := db. + Preload("Address"). + Where("address_id in (?)", addressesSubQuery). + Find(&assetSubs). + Error + if err != nil { + return nil, err + } + + var result []models.Address + for _, a := range assetSubs { + result = append(result, a.Address) + } + return result, nil +} + +func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Context) (map[string][]string, error) { + db := apmgorm.WithContext(ctx, i.Gorm) + + var dbAddresses []models.Address + err := db.Where("address in (?)", addresses).Find(&dbAddresses).Error + if err != nil { + return nil, err + } + + addressesIDs := make([]uint, 0, len(dbAddresses)) + for _, a := range dbAddresses { + addressesIDs = append(addressesIDs, a.ID) + } + + var associations []models.AddressToAssetAssociation + err = db. + Preload("Address"). + Preload("Asset"). + Where("address_id in (?)", addressesIDs). + Find(&associations). + Error + if err != nil { + return nil, err + } + + result := make(map[string][]string) + for _, a := range associations { + assets := result[a.Address.Address] + result[a.Address.Address] = append(assets, a.Asset.AssetID) + } + return result, nil +} + +func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) (map[string][]string, error) { + db := apmgorm.WithContext(ctx, i.Gorm) + + var dbAddresses []models.Address + err := db.Where("address in (?)", addresses).Find(&dbAddresses).Error + if err != nil { + return nil, err + } + + addressesIDs := make([]uint, 0, len(dbAddresses)) + for _, a := range dbAddresses { + addressesIDs = append(addressesIDs, a.ID) + } + + var associations []models.AddressToAssetAssociation + err = db. + Preload("Address"). + Preload("Asset"). + Where("address_id in (?)", addressesIDs). + Where("updated_at > ?", from). + Find(&associations). + Error + if err != nil { + return nil, err + } + + result := make(map[string][]string) + for _, a := range associations { + assets := result[a.Address.Address] + result[a.Address.Address] = append(assets, a.Asset.AssetID) + } + return result, nil +} + +func (i *Instance) GetAssociationsByAddresses(addresses []string, ctx context.Context) ([]models.AddressToAssetAssociation, error) { + db := apmgorm.WithContext(ctx, i.Gorm) + + addressesSubQuery := db.Table("addresses"). + Select("id"). + Where("address in (?)", addresses). + QueryExpr() + + var result []models.AddressToAssetAssociation + err := db. + Preload("Address"). + Preload("Asset"). + Where("address_id in (?)", addressesSubQuery). + Find(&result). + Error + return result, err +} + +func (i *Instance) GetAssociationsByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) ([]models.AddressToAssetAssociation, error) { + db := apmgorm.WithContext(ctx, i.Gorm) + + addressesSubQuery := db.Table("addresses"). + Select("id"). + Where("address in (?)", addresses). + QueryExpr() + + var result []models.AddressToAssetAssociation + err := db. + Preload("Address"). + Preload("Asset"). + Where("address_id in (?)", addressesSubQuery). + Where("updated_at > ?", from). + Find(&result). + Error + return result, err +} + +func (i *Instance) AddAssociationsForAddress(address string, assets []string, ctx context.Context) error { + db := apmgorm.WithContext(ctx, i.Gorm) + return db.Transaction(func(tx *gorm.DB) error { + uniqueAssets := getUniqueStrings(assets) + uniqueAssetsModel := make([]models.Asset, 0, len(uniqueAssets)) + for _, l := range uniqueAssets { + uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{ + AssetID: l, + }) + } + + err := BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), uniqueAssetsModel) + if err != nil { + return err + } + + var dbAssets []models.Asset + err = db.Where("asset_id in (?)", uniqueAssets).Find(&dbAssets).Error + if err != nil { + return err + } + + dbAddress := models.Address{Address: address} + err = db.Where("address = ?", address).FirstOrCreate(&dbAddress).Error + if err != nil { + return err + } + + assetsSub := models.AssetSubscription{AddressID: dbAddress.ID} + err = db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING").Create(&assetsSub).Error + if err != nil { + return err + } + + result := make([]models.AddressToAssetAssociation, 0, len(dbAssets)) + for _, asset := range dbAssets { + result = append(result, models.AddressToAssetAssociation{ + AddressID: dbAddress.ID, + AssetID: asset.ID, + }) + } + return BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), result) + }) +} + +func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[string][]string, ctx context.Context) error { + db := apmgorm.WithContext(ctx, i.Gorm) + return db.Transaction(func(tx *gorm.DB) error { + var assets []string + + for _, v := range associations { + assets = append(assets, v...) + } + + uniqueAssets := getUniqueStrings(assets) + uniqueAssetsModel := make([]models.Asset, 0, len(uniqueAssets)) + for _, l := range uniqueAssets { + uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{ + AssetID: l, + }) + } + + err := BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), uniqueAssetsModel) + if err != nil { + return err + } + + var dbAssets []models.Asset + err = db.Where("asset_id in (?)", uniqueAssets).Find(&dbAssets).Error + if err != nil { + return err + } + + assetsMap := makeMapAssets(dbAssets) + + var addresses []string + for k := range associations { + addresses = append(addresses, k) + } + + var dbAddresses []models.Address + if err := db.Where("address in (?)", addresses).Find(&dbAddresses).Error; err != nil { + return err + } + + var addressSubs []models.AssetSubscription + for _, a := range dbAddresses { + sub := models.AssetSubscription{AddressID: a.ID} + addressSubs = append(addressSubs, sub) + } + + err = BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), addressSubs) + if err != nil { + return err + } + + addressesMap := makeMapAddress(dbAddresses) + + var result []models.AddressToAssetAssociation + for address, assets := range associations { + for _, asset := range assets { + r := models.AddressToAssetAssociation{ + AddressID: addressesMap[address], + AssetID: assetsMap[asset], + } + result = append(result, r) + } + } + return BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), result) + }) +} + +func makeMapAssets(addresses []models.Asset) map[string]uint { + result := make(map[string]uint) + for _, a := range addresses { + result[a.AssetID] = a.ID + } + return result +} + +func makeMapAddress(addresses []models.Address) map[string]uint { + result := make(map[string]uint) + for _, a := range addresses { + result[a.Address] = a.ID + } + return result +} + +func getUniqueStrings(values []string) []string { + keys := make(map[string]bool) + var list []string + for _, entry := range values { + if _, value := keys[entry]; !value { + keys[entry] = true + list = append(list, entry) + } + } + return list +} diff --git a/db/db.go b/db/db.go index 5eed3e70e..dc56c920a 100644 --- a/db/db.go +++ b/db/db.go @@ -1,11 +1,14 @@ package db import ( + "errors" "github.com/jinzhu/gorm" + gormbulk "github.com/t-tiger/gorm-bulk-insert" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/logger" "go.elastic.co/apm/module/apmgorm" _ "go.elastic.co/apm/module/apmgorm/dialects/postgres" + "reflect" "time" ) @@ -13,6 +16,8 @@ type Instance struct { Gorm *gorm.DB } +const batchCount = 3000 + func New(uri, env string) (*Instance, error) { var ( g *gorm.DB @@ -29,8 +34,12 @@ func New(uri, env string) (*Instance, error) { } g.AutoMigrate( - &models.Subscription{}, + &models.NotificationSubscription{}, &models.Tracker{}, + &models.AddressToAssetAssociation{}, + &models.Asset{}, + &models.AssetSubscription{}, + &models.Address{}, ) i := &Instance{Gorm: g} @@ -59,3 +68,50 @@ func RestoreConnectionWorker(database *Instance, timeout time.Duration, uri stri time.Sleep(timeout) } } + +// Example: +// postgres.BulkInsert(DBWrite, []models.User{...}) +func BulkInsert(db *gorm.DB, dbModels interface{}) error { + interfaceSlice, err := getInterfaceSlice(dbModels) + if err != nil { + return err + } + batchList := getInterfaceSliceBatch(interfaceSlice, batchCount) + for _, batch := range batchList { + err := gormbulk.BulkInsert(db, batch, len(batch)) + if err != nil { + return err + } + } + return nil +} + +func getInterfaceSliceBatch(values []interface{}, sizeUint uint) [][]interface{} { + size := int(sizeUint) + resultLength := (len(values) + size - 1) / size + result := make([][]interface{}, resultLength) + lo, hi := 0, size + for i := range result { + if hi > len(values) { + hi = len(values) + } + result[i] = values[lo:hi:hi] + lo, hi = hi, hi+size + } + return result +} + +func getInterfaceSlice(slice interface{}) ([]interface{}, error) { + s := reflect.ValueOf(slice) + if s.Kind() != reflect.Slice { + return nil, errors.New("InterfaceSlice() given a non-slice type") + } + + ret := make([]interface{}, s.Len()) + + for i := 0; i < s.Len(); i++ { + ret[i] = s.Index(i).Interface() + } + + return ret, nil +} diff --git a/db/models/address.go b/db/models/address.go new file mode 100644 index 000000000..85b211f17 --- /dev/null +++ b/db/models/address.go @@ -0,0 +1,8 @@ +package models + +import "github.com/jinzhu/gorm" + +type Address struct { + gorm.Model + Address string `gorm:"type:varchar(128); unique" sql:"index"` +} diff --git a/db/models/addresstoasset.go b/db/models/addresstoasset.go new file mode 100644 index 000000000..034ddfeae --- /dev/null +++ b/db/models/addresstoasset.go @@ -0,0 +1,17 @@ +package models + +import ( + "time" +) + +type AddressToAssetAssociation struct { + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time `sql:"index"` + + Address Address `gorm:"ForeignKey:AddressID; not null"` + AddressID uint `sql:"index"` + + Asset Asset `gorm:"ForeignKey:AssetID; not null"` + AssetID uint `sql:"index"` +} diff --git a/db/models/asset.go b/db/models/asset.go new file mode 100644 index 000000000..79441c4ba --- /dev/null +++ b/db/models/asset.go @@ -0,0 +1,8 @@ +package models + +import "github.com/jinzhu/gorm" + +type Asset struct { + gorm.Model + AssetID string `gorm:"type:varchar(128); unique_index"` +} diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index 019159e40..909df39a9 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -1,11 +1,19 @@ package models import ( - "time" + "github.com/jinzhu/gorm" ) -type Subscription struct { - CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"` - Coin uint `gorm:"primary_key; column:coin; auto_increment:false" sql:"index"` - Address string `gorm:"primary_key; column:address; type:varchar(128)" sql:"index"` -} +type ( + NotificationSubscription struct { + gorm.Model + Address Address `gorm:"ForeignKey:AddressID; not null"` + AddressID uint `gorm:"unique" sql:"index"` + } + + AssetSubscription struct { + gorm.Model + Address Address `gorm:"ForeignKey:AddressID; not null"` + AddressID uint `gorm:"unique" sql:"index"` + } +) diff --git a/db/notification.go b/db/notification.go new file mode 100644 index 000000000..9455c881c --- /dev/null +++ b/db/notification.go @@ -0,0 +1,86 @@ +package db + +import ( + "context" + "github.com/jinzhu/gorm" + "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/pkg/errors" + "go.elastic.co/apm/module/apmgorm" +) + +func (i *Instance) GetSubscriptionsForNotifications(addresses []string, ctx context.Context) ([]models.NotificationSubscription, error) { + if len(addresses) == 0 { + return nil, errors.E("Empty addresses") + } + db := apmgorm.WithContext(ctx, i.Gorm) + + addressesSubQuery := db. + Table("addresses"). + Select("id"). + Where("address in (?)", addresses). + QueryExpr() + + var subscriptionsDataList []models.NotificationSubscription + err := db. + Preload("Address"). + Where("address_id in (?)", addressesSubQuery). + Find(&subscriptionsDataList). + Error + if err != nil { + return nil, err + } + return subscriptionsDataList, nil +} + +func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx context.Context) error { + if len(addresses) == 0 { + return errors.E("Empty subscriptions") + } + db := apmgorm.WithContext(ctx, i.Gorm) + + return db.Transaction(func(tx *gorm.DB) error { + uniqueAddresses := getUniqueStrings(addresses) + uniqueAddressesModel := make([]models.Address, 0, len(uniqueAddresses)) + for _, a := range uniqueAddresses { + uniqueAddressesModel = append(uniqueAddressesModel, models.Address{ + Address: a, + }) + } + + err := BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), uniqueAddressesModel) + if err != nil { + return err + } + + var dbAddresses []models.Address + err = db.Where("address in (?)", uniqueAddresses).Find(&dbAddresses).Error + if err != nil { + return err + } + + result := make([]models.NotificationSubscription, 0, len(dbAddresses)) + for _, a := range dbAddresses { + result = append(result, models.NotificationSubscription{ + AddressID: a.ID, + }) + } + return BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT (address_id) DO UPDATE SET deleted_at = null, updated_at = now()"), result) + }) +} + +func (i *Instance) DeleteSubscriptionsForNotifications(addresses []string, ctx context.Context) error { + if len(addresses) == 0 { + return errors.E("Empty subscriptions") + } + db := apmgorm.WithContext(ctx, i.Gorm) + + addressSubQuery := db.Table("addresses"). + Select("id"). + Where("address in (?)", addresses). + QueryExpr() + + return db. + Where("address_id in (?)", addressSubQuery). + Delete(&models.NotificationSubscription{}). + Error +} diff --git a/db/subscriptions.go b/db/subscriptions.go deleted file mode 100644 index 121ce3490..000000000 --- a/db/subscriptions.go +++ /dev/null @@ -1,105 +0,0 @@ -package db - -import ( - "context" - "fmt" - "github.com/jinzhu/gorm" - "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/errors" - "go.elastic.co/apm" - "go.elastic.co/apm/module/apmgorm" - "strings" -) - -func (i *Instance) GetSubscriptions(coin uint, addresses []string, ctx context.Context) ([]models.Subscription, error) { - if len(addresses) == 0 { - return nil, errors.E("Empty addresses") - } - g := apmgorm.WithContext(ctx, i.Gorm) - var subscriptionsDataList []models.Subscription - err := g. - Model(&models.Subscription{}). - Where("address in (?) AND coin = ?", addresses, coin). - Find(&subscriptionsDataList).Error - - if err != nil { - return nil, err - } - return subscriptionsDataList, nil -} - -func (i *Instance) AddSubscriptions(subscriptions []models.Subscription, ctx context.Context) error { - if len(subscriptions) == 0 { - return errors.E("Empty subscriptions") - } - - subscriptionsBatch := toSubscriptionBatch(subscriptions, batchLimit, ctx) - g := apmgorm.WithContext(ctx, i.Gorm) - - for _, s := range subscriptionsBatch { - if err := bulkCreate(g, s); err != nil { - return err - } - } - - return nil -} - -func (i *Instance) DeleteSubscriptions(subscriptions []models.Subscription, ctx context.Context) error { - if len(subscriptions) == 0 { - return errors.E("Empty subscriptions") - } - - g := apmgorm.WithContext(ctx, i.Gorm) - for _, s := range subscriptions { - err := g.Where("coin = ? and address = ?", s.Coin, s.Address).Delete(&models.Subscription{}).Error - if err != nil { - return err - } - } - return nil -} - -const ( - batchLimit = 3000 - rawBulkInsert = `INSERT INTO subscriptions(coin,address) VALUES %s ON CONFLICT DO NOTHING` -) - -func bulkCreate(db *gorm.DB, dataList []models.Subscription) error { - var ( - valueStrings []string - valueArgs []interface{} - ) - - for _, d := range dataList { - valueStrings = append(valueStrings, "(?, ?)") - - valueArgs = append(valueArgs, d.Coin) - valueArgs = append(valueArgs, d.Address) - } - - smt := fmt.Sprintf(rawBulkInsert, strings.Join(valueStrings, ",")) - - if err := db.Exec(smt, valueArgs...).Error; err != nil { - return err - } - - return nil -} - -func toSubscriptionBatch(txs []models.Subscription, sizeUint uint, ctx context.Context) [][]models.Subscription { - span, _ := apm.StartSpan(ctx, "toSubscriptionBatch", "app") - defer span.End() - size := int(sizeUint) - resultLength := (len(txs) + size - 1) / size - result := make([][]models.Subscription, resultLength) - lo, hi := 0, size - for i := range result { - if hi > len(txs) { - hi = len(txs) - } - result[i] = txs[lo:hi:hi] - lo, hi = hi, hi+size - } - return result -} diff --git a/go.mod b/go.mod index a174c8518..94cb23284 100644 --- a/go.mod +++ b/go.mod @@ -3,31 +3,18 @@ module github.com/trustwallet/blockatlas go 1.14 require ( - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/DATA-DOG/go-sqlmock v1.5.0 - github.com/Microsoft/go-winio v0.4.14 // indirect - github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 - github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 - github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb // indirect github.com/deckarep/golang-set v1.7.1 - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.4.0 // indirect - github.com/elastic/go-sysinfo v1.3.0 // indirect - github.com/elastic/go-windows v1.0.1 // indirect github.com/gin-gonic/gin v1.6.3 - github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/imroc/req v0.3.0 github.com/jinzhu/gorm v1.9.16 github.com/mitchellh/mapstructure v1.3.3 github.com/mr-tron/base58 v1.2.0 - github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/opencontainers/runc v0.1.1 // indirect github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.7.1 github.com/shopspring/decimal v1.2.0 github.com/sirupsen/logrus v1.6.0 @@ -36,18 +23,16 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 + github.com/t-tiger/gorm-bulk-insert v1.3.0 github.com/trustwallet/ens-coincodec v1.0.6 + github.com/trustwallet/watchmarket v1.1.0 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmgorm v1.8.0 go.elastic.co/apm/module/apmhttp v1.8.0 go.elastic.co/apm/module/apmlogrus v1.8.0 - go.elastic.co/fastjson v1.1.0 // indirect go.uber.org/atomic v1.6.0 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f - golang.org/x/tools v0.0.0-20200513175351-0951661448da // indirect gopkg.in/yaml.v2 v2.3.0 - gotest.tools v2.2.0+incompatible // indirect - howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 // indirect ) diff --git a/go.sum b/go.sum index 5c5a6c425..ae48691e3 100644 --- a/go.sum +++ b/go.sum @@ -44,6 +44,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis/v2 v2.13.1/go.mod h1:0UIBNuf97uxrWhdVBpJvPtafKyGpL2NS2pYe0tYM97k= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -77,6 +79,9 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 h1:3Wv1E0CqL45hBs4bykb586wvZMRGKfFITHrN3ilm4FE= github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb h1:nXPkFq8X1a9ycY3GYQpFNxHh3j2JgY7zDZfq2EXMIzk= github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= @@ -162,6 +167,8 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-redis/redis v6.15.3-0.20190424063336-97e6ed817821+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= @@ -190,6 +197,7 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.8.1/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -242,6 +250,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= +github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= +github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= github.com/jinzhu/gorm v1.9.15 h1:OdR1qFvtXktlxk73XFYMiYn9ywzTwytqe4QkuMRqc38= github.com/jinzhu/gorm v1.9.15/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= @@ -296,8 +306,10 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= +github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 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= @@ -308,6 +320,7 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -316,14 +329,17 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -353,6 +369,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -364,6 +381,7 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -372,10 +390,12 @@ github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -422,6 +442,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= @@ -430,11 +451,18 @@ github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuI github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= +github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= +github.com/t-tiger/gorm-bulk-insert v1.3.0 h1:9k7BaVEhw/3fsvh6GTOBwJ2RXk3asc5xs5m6hwozq20= +github.com/t-tiger/gorm-bulk-insert v1.3.0/go.mod h1:ruDlk8xDl+8sX4bA7PQuYly9YEb3pbp1eP2LCyeRrFY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/trustwallet/blockatlas v1.1.3-0.20200518232337-7495506f457c/go.mod h1:5Ev/iawD12+qgmtMkGgjYCKmGLF724YaxYfEbfY8lKc= +github.com/trustwallet/ens-coincodec v1.0.5/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= github.com/trustwallet/ens-coincodec v1.0.6 h1:ZPvFDJwvv4s+XCnUM7pzub8wYHy37tyJBNtKvgx9FDs= github.com/trustwallet/ens-coincodec v1.0.6/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= +github.com/trustwallet/watchmarket v1.1.0 h1:tD+dlnKRONYr2ljsirM0Gx90ahzlfL1ceNSJlpTxINQ= +github.com/trustwallet/watchmarket v1.1.0/go.mod h1:VKVAqqClA5Oc6jaJvNorvn9wRnp9BKV04jVbjTGx0Zw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= @@ -444,15 +472,18 @@ github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2t github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= go.elastic.co/apm v1.8.0 h1:AWEKpHwRal0yCMd4K8Oxy1HAa7xid+xq1yy+XjgoVU0= go.elastic.co/apm v1.8.0/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= go.elastic.co/apm/module/apmgin v1.8.0 h1:QcXVtFhqAcSGqC/ywzqZBHdWzJG3wyrBxgvCvAZ98do= go.elastic.co/apm/module/apmgin v1.8.0/go.mod h1:heH2rXaOluBb+ucwlG3FBCGrx56qHqoxb1KI7uBLlAk= +go.elastic.co/apm/module/apmgoredis v1.8.0/go.mod h1:J8mXOp8sOJG1/Vuz0gPB7+ovcQY6vYqpabuRsk9beBM= go.elastic.co/apm/module/apmgorm v1.8.0 h1:1vKuD8hsbJcChcUQTBb1N8Zy1tILR5pGTExLtijyhko= go.elastic.co/apm/module/apmgorm v1.8.0/go.mod h1:18ttEKPQr0cvRSeG95WMXoPUy2BT8Jp1EzhPU5NQYTY= go.elastic.co/apm/module/apmhttp v1.8.0 h1:5AJPefWJzWDLX/47XIDfaloGiYWkkOQEULvlrI6Ieaw= @@ -556,6 +587,7 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -573,6 +605,8 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/mq/mq.go b/mq/mq.go index e2c2a6016..431ed8c87 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -22,9 +22,10 @@ type ( ) const ( - TxNotifications Queue = "txNotifications" - Subscriptions Queue = "subscriptions" - RawTransactions Queue = "rawTransactions" + TxNotifications Queue = "txNotifications" + Subscriptions Queue = "subscriptions" + RawTransactions Queue = "rawTransactions" + TokensRegistration Queue = "tokensRegistration" ) func Init(uri string) (err error) { diff --git a/pkg/address/address.go b/pkg/address/address.go index dce324001..34a08f7e0 100644 --- a/pkg/address/address.go +++ b/pkg/address/address.go @@ -8,6 +8,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "golang.org/x/crypto/sha3" + "strconv" "strings" ) @@ -115,3 +116,20 @@ func FormatAddress(address string, coinID uint) string { return address } } + +func PrefixedAddress(coinID uint, address string) string { + return strconv.Itoa(int(coinID)) + "_" + address +} + +func UnprefixedAddress(address string) (string, uint, bool) { + result := strings.Split(address, "_") + if len(result) != 2 { + return "", 0, false + } + id, err := strconv.Atoi(result[0]) + if err != nil { + return "", 0, false + } + return result[1], uint(id), true + +} diff --git a/pkg/address/address_test.go b/pkg/address/address_test.go index f9685233d..e1c8cda52 100644 --- a/pkg/address/address_test.go +++ b/pkg/address/address_test.go @@ -156,3 +156,15 @@ func TestFormatAddress(t *testing.T) { } }) } + +func TestUnprefixedAddress(t *testing.T) { + address, id, ok := UnprefixedAddress("60_a") + assert.Equal(t, "a", address) + assert.Equal(t, uint(60), id) + assert.True(t, ok) +} + +func TestPrefixedAddress(t *testing.T) { + address := PrefixedAddress(60, "a") + assert.Equal(t, "60_a", address) +} diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index e5768c308..02b83d836 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -269,6 +269,29 @@ func (t *Tx) GetAddresses() []string { } } +func (t *Tx) TokenID() (string, bool) { + var tokenID string + switch t.Meta.(type) { + case Transfer, *Transfer, CollectibleTransfer, *CollectibleTransfer, ContractCall, *ContractCall, MultiCurrencyTransfer, *MultiCurrencyTransfer: + return "", false + case NativeTokenTransfer: + tokenID = t.Meta.(NativeTokenTransfer).TokenID + case *NativeTokenTransfer: + tokenID = t.Meta.(*NativeTokenTransfer).TokenID + case TokenTransfer: + tokenID = t.Meta.(TokenTransfer).TokenID + case *TokenTransfer: + tokenID = t.Meta.(*TokenTransfer).TokenID + case AnyAction: + tokenID = t.Meta.(AnyAction).TokenID + case *AnyAction: + tokenID = t.Meta.(*AnyAction).TokenID + default: + return "", false + } + return tokenID, true +} + func (t *Tx) GetTransactionDirection(address string) Direction { if t.Direction != "" { return t.Direction diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 1f1fc8de4..5b7db6e32 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -521,3 +521,47 @@ func TestTxs_SortByDate(t *testing.T) { }) assert.True(t, isSorted) } + +func TestTx_TokenID(t *testing.T) { + tx1 := Tx{ + Coin: 60, + From: "A", + To: "B", + Meta: NativeTokenTransfer{ + TokenID: "ABC", + From: "A", + To: "C", + }, + } + + tx2 := Tx{ + Coin: 60, + From: "D", + To: "V", + Meta: TokenTransfer{ + TokenID: "EFG", + From: "D", + To: "F", + }, + } + + tx3 := Tx{ + Coin: 60, + From: "Q", + To: "L", + Meta: AnyAction{ + TokenID: "HIJ", + }, + } + + token1, ok1 := tx1.TokenID() + assert.True(t, ok1) + assert.Equal(t, token1, "ABC") + token2, ok2 := tx2.TokenID() + assert.True(t, ok2) + assert.Equal(t, token2, "EFG") + token3, ok3 := tx3.TokenID() + assert.Equal(t, token3, "HIJ") + assert.True(t, ok3) + +} diff --git a/platform/tron/token.go b/platform/tron/token.go index 8b15aa6c8..29a18d2b7 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -57,7 +57,7 @@ func (p *Platform) getTokens(ids []string) chan blockatlas.Token { time.Sleep(time.Millisecond) err := p.getTokensChannel(i, c) if err != nil { - logger.Error("TRON getTokens token: " + i) + logger.Error("tron getTokens: " + i) } }(id, tkChan) } @@ -69,7 +69,6 @@ func (p *Platform) getTokens(ids []string) chan blockatlas.Token { func (p *Platform) getTokensChannel(id string, tkChan chan blockatlas.Token) error { info, err := p.client.fetchTokenInfo(id) if err != nil || len(info.Data) == 0 { - logger.Error(err, "fetchTokenInfo: invalid token") return err } asset := NormalizeToken(info.Data[0]) diff --git a/services/observer/notifier/base.go b/services/notifier/base.go similarity index 70% rename from services/observer/notifier/base.go rename to services/notifier/base.go index 082c154ed..dc1d85e9b 100644 --- a/services/observer/notifier/base.go +++ b/services/notifier/base.go @@ -4,7 +4,9 @@ import ( "context" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/logger" + "strconv" "go.elastic.co/apm" ) @@ -24,7 +26,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { } }() - txs, err := getTransactionsFromDelivery(delivery, ctx) + txs, err := GetTransactionsFromDelivery(delivery, ctx) if err != nil { logger.Error("failed to get transactions", err) } @@ -34,19 +36,26 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { allAddresses = append(allAddresses, tx.GetAddresses()...) } - addresses := toUniqueAddresses(allAddresses) + addresses := ToUniqueAddresses(allAddresses) + for i := range addresses { + addresses[i] = strconv.Itoa(int(txs[0].Coin)) + "_" + addresses[i] + } if len(txs) < 1 { return } - subscriptionsDataList, err := database.GetSubscriptions(txs[0].Coin, addresses, ctx) + subscriptionsDataList, err := database.GetSubscriptionsForNotifications(addresses, ctx) if err != nil || len(subscriptionsDataList) == 0 { return } notifications := make([]TransactionNotification, 0) for _, sub := range subscriptionsDataList { - notificationsForAddress := buildNotificationsByAddress(sub.Address, txs, ctx) + ua, _, ok := address.UnprefixedAddress(sub.Address.Address) + if !ok { + continue + } + notificationsForAddress := buildNotificationsByAddress(ua, txs, ctx) notifications = append(notifications, notificationsForAddress...) } diff --git a/services/observer/notifier/delivery.go b/services/notifier/delivery.go similarity index 89% rename from services/observer/notifier/delivery.go rename to services/notifier/delivery.go index 9a1c3caf7..cc5c5c189 100644 --- a/services/observer/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -11,10 +11,10 @@ import ( "go.elastic.co/apm" ) -func getTransactionsFromDelivery(delivery amqp.Delivery, ctx context.Context) (blockatlas.Txs, error) { +func GetTransactionsFromDelivery(delivery amqp.Delivery, ctx context.Context) (blockatlas.Txs, error) { var txs blockatlas.Txs - span, _ := apm.StartSpan(ctx, "getTransactionsFromDelivery", "app") + span, _ := apm.StartSpan(ctx, "GetTransactionsFromDelivery", "app") defer span.End() if err := json.Unmarshal(delivery.Body, &txs); err != nil { diff --git a/services/observer/notifier/models.go b/services/notifier/models.go similarity index 95% rename from services/observer/notifier/models.go rename to services/notifier/models.go index f33054c8a..9227ab54c 100644 --- a/services/observer/notifier/models.go +++ b/services/notifier/models.go @@ -44,7 +44,7 @@ func buildNotificationsByAddress(address string, txs blockatlas.Txs, ctx context return result } -func toUniqueAddresses(addresses []string) []string { +func ToUniqueAddresses(addresses []string) []string { keys := make(map[string]bool) var list []string for _, entry := range addresses { @@ -81,7 +81,7 @@ func findTransactionsByAddress(txs blockatlas.Txs, address string) []blockatlas. func containsAddress(tx blockatlas.Tx, address string) bool { allAddresses := tx.GetAddresses() - txAddresses := toUniqueAddresses(allAddresses) + txAddresses := ToUniqueAddresses(allAddresses) for _, a := range txAddresses { if a == address { return true diff --git a/services/observer/notifier/models_test.go b/services/notifier/models_test.go similarity index 100% rename from services/observer/notifier/models_test.go rename to services/notifier/models_test.go diff --git a/services/observer/parser/parser.go b/services/parser/parser.go similarity index 96% rename from services/observer/parser/parser.go rename to services/parser/parser.go index 331d25fe0..07785191b 100644 --- a/services/observer/parser/parser.go +++ b/services/parser/parser.go @@ -23,7 +23,7 @@ type ( Params struct { Ctx context.Context Api blockatlas.BlockAPI - Queue mq.Queue + Queue []mq.Queue ParsingBlocksInterval, FetchBlocksTimeout time.Duration BacklogCount int MaxBacklogBlocks int64 @@ -296,10 +296,12 @@ func publish(params Params, txs blockatlas.Txs, ctx context.Context) { logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) return } - err = params.Queue.Publish(body) - if err != nil { - logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) - return + for _, q := range params.Queue { + err = q.Publish(body) + if err != nil { + logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + return + } } } @@ -318,12 +320,7 @@ func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumb sleep = sleep + jitter/2 logger.Info("retry GetBlockByNumber", - logger.Params{ - "number": n, - "attempts": attempts, - "sleep": sleep.String(), - "symbol": symbol, - }, + logger.Params{"number": n, "attempts": attempts, "sleep": sleep.String(), "symbol": symbol}, ) time.Sleep(sleep) diff --git a/services/observer/parser/parser_test.go b/services/parser/parser_test.go similarity index 98% rename from services/observer/parser/parser_test.go rename to services/parser/parser_test.go index e4a8e78d4..6b9eaee2f 100644 --- a/services/observer/parser/parser_test.go +++ b/services/parser/parser_test.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "sync" "testing" @@ -45,7 +46,7 @@ func TestFetchBlocks(t *testing.T) { params := Params{ Ctx: nil, Api: getMockedBlockAPI(), - Queue: "", + Queue: []mq.Queue{""}, ParsingBlocksInterval: 0, FetchBlocksTimeout: 0, BacklogCount: 0, diff --git a/services/subscriber/subscriber.go b/services/subscriber/subscriber.go new file mode 100644 index 000000000..7d9a0aaf2 --- /dev/null +++ b/services/subscriber/subscriber.go @@ -0,0 +1,3 @@ +package subscriber + +type Subscriber string diff --git a/services/subscriber/tokens.go b/services/subscriber/tokens.go new file mode 100644 index 000000000..80ffe7847 --- /dev/null +++ b/services/subscriber/tokens.go @@ -0,0 +1,37 @@ +package subscriber + +import ( + "context" + "encoding/json" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/pkg/logger" + "go.elastic.co/apm" + "strconv" +) + +const Tokens Subscriber = "tokens" + +func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { + tx := apm.DefaultTracer.StartTransaction("RunTokensSubscriber", "app") + defer tx.End() + + ctx := apm.ContextWithTransaction(context.Background(), tx) + + event := make(map[string][]string) + if err := json.Unmarshal(delivery.Body, &event); err != nil { + if err := delivery.Ack(false); err != nil { + logger.Fatal(err, err) + } + } + + for address, assets := range event { + if err := database.AddAssociationsForAddress(address, assets, ctx); err != nil { + logger.Error("Failed to AddAssociationsForAddress: " + err.Error()) + } + } + logger.Info("Subscribed " + strconv.Itoa(len(event))) + if err := delivery.Ack(false); err != nil { + logger.Fatal(err, err) + } +} diff --git a/services/observer/subscriber/subscriber.go b/services/subscriber/transactions.go similarity index 66% rename from services/observer/subscriber/subscriber.go rename to services/subscriber/transactions.go index d4ced170e..05626ca4a 100644 --- a/services/observer/subscriber/subscriber.go +++ b/services/subscriber/transactions.go @@ -5,20 +5,21 @@ import ( "encoding/json" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" "go.elastic.co/apm" + "strconv" ) const ( + Notifications Subscriber = "notifications" AddSubscription blockatlas.SubscriptionOperation = "AddSubscription" DeleteSubscription blockatlas.SubscriptionOperation = "DeleteSubscription" UpdateSubscription blockatlas.SubscriptionOperation = "UpdateSubscription" ) -func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { - tx := apm.DefaultTracer.StartTransaction("RunSubscriber", "app") +func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { + tx := apm.DefaultTracer.StartTransaction("RunTransactionsSubscriber", "app") defer tx.End() ctx := apm.ContextWithTransaction(context.Background(), tx) @@ -35,13 +36,13 @@ func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { switch event.Operation { case AddSubscription, UpdateSubscription: - err = database.AddSubscriptions(ToSubscriptionData(subscriptions), ctx) + err = database.AddSubscriptionsForNotifications(ToSubscriptionData(subscriptions), ctx) if err != nil { logger.Error(err, params) } logger.Info("Added", params) case DeleteSubscription: - err := database.DeleteSubscriptions(ToSubscriptionData(subscriptions), ctx) + err := database.DeleteSubscriptionsForNotifications(ToSubscriptionData(subscriptions), ctx) if err != nil { logger.Error(err, params) } @@ -54,10 +55,12 @@ func RunSubscriber(database *db.Instance, delivery amqp.Delivery) { } } -func ToSubscriptionData(sub []blockatlas.Subscription) []models.Subscription { - data := make([]models.Subscription, 0, len(sub)) +func ToSubscriptionData(sub []blockatlas.Subscription) []string { + data := make([]string, 0, len(sub)) for _, s := range sub { - data = append(data, models.Subscription{Coin: s.Coin, Address: s.Address}) + coinStr := strconv.FormatUint(uint64(s.Coin), 10) + address := coinStr + "_" + s.Address + data = append(data, address) } return data } diff --git a/services/observer/subscriber/subscriber_test.go b/services/subscriber/transactions_test.go similarity index 59% rename from services/observer/subscriber/subscriber_test.go rename to services/subscriber/transactions_test.go index bb75f7cba..ab27df743 100644 --- a/services/observer/subscriber/subscriber_test.go +++ b/services/subscriber/transactions_test.go @@ -2,7 +2,6 @@ package subscriber import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" ) @@ -17,17 +16,10 @@ func TestToSubscriptionData(t *testing.T) { Address: "B", } - expectedModel := models.Subscription{ - Coin: 60, - Address: "A", - } - expectedModel1 := models.Subscription{ - Coin: 60, - Address: "B", - } - + expected := "60_A" + expected1 := "60_B" res := ToSubscriptionData([]blockatlas.Subscription{sub, sub2}) assert.Equal(t, 2, len(res)) - assert.Equal(t, expectedModel, res[0]) - assert.Equal(t, expectedModel1, res[1]) + assert.Equal(t, expected, res[0]) + assert.Equal(t, expected1, res[1]) } diff --git a/services/tokensearcher/api.go b/services/tokensearcher/api.go new file mode 100644 index 000000000..cad07cdea --- /dev/null +++ b/services/tokensearcher/api.go @@ -0,0 +1,183 @@ +package tokensearcher + +import ( + "context" + "encoding/json" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/address" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "sync" + "time" +) + +type ( + AddressesByCoin map[uint][]string + AssetsByAddress map[string][]string + Request struct { + AddressesByCoin map[string][]string `json:"addresses"` + From uint `json:"from"` + } +) + +type Instance struct { + database *db.Instance + apis map[uint]blockatlas.TokensAPI + queue mq.Queue +} + +func Init(database *db.Instance, apis map[uint]blockatlas.TokensAPI, queue mq.Queue) Instance { + return Instance{database: database, apis: apis, queue: queue} +} + +func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (AssetsByAddress, error) { + addresses := getAddressesFromRequest(request) + + subscribedAddresses, err := getSubscribedAddresses(i.database, addresses, ctx) + if err != nil { + return nil, err + } + unsubscribedAddresses := getUnsubscribedAddresses(subscribedAddresses, addresses) + + assetsFromDB, err := i.database.GetAssetsMapByAddressesFromTime( + subscribedAddresses, + time.Unix(int64(request.From), 0), + ctx) + if err != nil { + return nil, err + } + + assetsFromNodes := make(AssetsByAddress) + if len(unsubscribedAddresses) != 0 { + assetsFromNodes = getAssetsByAddressFromNodes(unsubscribedAddresses, i.apis) + err = publishNewAddressesToQueue(i.queue, assetsFromNodes) + if err != nil { + logger.Error(err) + } + } + + return getAssetsToResponse(assetsFromDB, assetsFromNodes, addresses), nil +} + +func getSubscribedAddresses(database *db.Instance, addresses []string, ctx context.Context) ([]string, error) { + subscribedAddressesModel, err := database.GetSubscribedAddressesForAssets(ctx, addresses) + if err != nil { + return nil, err + } + + subscribedAddresses := make([]string, 0, len(subscribedAddressesModel)) + for _, a := range subscribedAddressesModel { + subscribedAddresses = append(subscribedAddresses, a.Address) + } + return subscribedAddresses, nil +} + +func getAddressesFromRequest(request Request) []string { + var addresses []string + for coinID, requestAddresses := range request.AddressesByCoin { + for _, a := range requestAddresses { + addresses = append(addresses, coinID+"_"+a) + } + } + return addresses +} + +func getUnsubscribedAddresses(subscribed []string, all []string) AddressesByCoin { + addressesByCoin := make(AddressesByCoin) + subscribedMap := make(map[string]bool) + for _, a := range subscribed { + subscribedMap[a] = true + } + for _, a := range all { + _, ok := subscribedMap[a] + if !ok { + ua, coinID, ok := address.UnprefixedAddress(a) + if !ok { + continue + } + currentAddresses := addressesByCoin[coinID] + addressesByCoin[coinID] = append(currentAddresses, ua) + } + } + return addressesByCoin +} + +func getAddressesToRegisterByCoin(assetsByAddresses AssetsByAddress, addresses []string) AddressesByCoin { + addressesByCoin := make(AddressesByCoin) + addressesFromRequestMap := make(map[string]bool) + for _, a := range addresses { + addressesFromRequestMap[a] = true + } + for _, a := range addresses { + _, ok := assetsByAddresses[a] + if !ok { + ua, coinID, ok := address.UnprefixedAddress(a) + if !ok { + continue + } + currentAddresses := addressesByCoin[coinID] + addressesByCoin[coinID] = append(currentAddresses, ua) + } + } + return addressesByCoin +} + +func getAssetsByAddressFromNodes(addressesByCoin AddressesByCoin, apis map[uint]blockatlas.TokensAPI) AssetsByAddress { + a := NodesResponse{AssetsByAddress: make(AssetsByAddress)} + var wg sync.WaitGroup + for coinID, addresses := range addressesByCoin { + api, ok := apis[coinID] + if !ok { + continue + } + wg.Add(1) + go fetchAssetsByAddresses(api, addresses, &a, &wg) + } + wg.Wait() + return a.AssetsByAddress +} + +func fetchAssetsByAddresses(tokenAPI blockatlas.TokensAPI, addresses []string, result *NodesResponse, wg *sync.WaitGroup) { + defer wg.Done() + + var tWg sync.WaitGroup + tWg.Add(len(addresses)) + for _, a := range addresses { + go func(address string, tWg *sync.WaitGroup) { + defer tWg.Done() + tokens, err := tokenAPI.GetTokenListByAddress(address) + if err != nil { + logger.Error("Chain: " + tokenAPI.Coin().Handle + " Address: " + address) + return + } + result.UpdateAssetsByAddress(tokens, int(tokenAPI.Coin().ID), address) + }(a, &tWg) + } + tWg.Wait() +} + +func publishNewAddressesToQueue(queue mq.Queue, message AssetsByAddress) error { + body, err := json.Marshal(message) + if err != nil { + return err + } + return queue.Publish(body) +} + +func getAssetsToResponse(dbAssetsMap, nodesAssetsMap AssetsByAddress, addresses []string) map[string][]string { + result := make(map[string][]string) + for _, address := range addresses { + dbAddresses, ok := dbAssetsMap[address] + if !ok { + nodesAssets, ok := nodesAssetsMap[address] + if !ok { + continue + } + result[address] = nodesAssets + continue + } + result[address] = dbAddresses + } + return result +} diff --git a/services/tokensearcher/api_test.go b/services/tokensearcher/api_test.go new file mode 100644 index 000000000..5524a3c7f --- /dev/null +++ b/services/tokensearcher/api_test.go @@ -0,0 +1,93 @@ +package tokensearcher + +import ( + "errors" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" +) + +func Test_getAddressesFromRequest(t *testing.T) { + request := Request{ + AddressesByCoin: make(map[string][]string), + From: 0, + } + request.AddressesByCoin["60"] = []string{"1", "2", "3"} + r := getAddressesFromRequest(request) + assert.Equal(t, []string{"60_1", "60_2", "60_3"}, r) +} + +func Test_getUnsubscribedAddresses(t *testing.T) { + r := getUnsubscribedAddresses([]string{"60_1"}, []string{"60_1", "714_2", "714_22", "118_3"}) + assert.Equal(t, []string{"2", "22"}, r[714]) + assert.Equal(t, []string{"3"}, r[118]) +} + +func Test_getAddressesToRegisterByCoin(t *testing.T) { + addressFromDB := make(map[string][]string) + addressFromDB["60_a"] = []string{"1", "2", "3"} + addressFromDB["714_b"] = []string{"1", "3"} + + addressesFromRequest := []string{"60_a", "714_b", "118_c"} + result := getAddressesToRegisterByCoin(addressFromDB, addressesFromRequest) + + c, ok := result[118] + assert.True(t, ok) + assert.Equal(t, []string{"c"}, c) +} + +func Test_getAssetsToResponse(t *testing.T) { + addressFromDB := make(map[string][]string) + addressFromDB["60_a"] = []string{"1", "2", "3"} + addressFromDB["714_b"] = []string{"1", "3"} + + addressFromNodes := make(map[string][]string) + addressFromNodes["118_c"] = []string{"1", "2", "3"} + + addressesFromRequest := []string{"60_a", "714_b", "118_c"} + + result := getAssetsToResponse(addressFromDB, addressFromNodes, addressesFromRequest) + assert.NotNil(t, result) + + assert.Equal(t, []string{"1", "2", "3"}, result["60_a"]) + assert.Equal(t, []string{"1", "3"}, result["714_b"]) + assert.Equal(t, []string{"1", "2", "3"}, result["118_c"]) +} + +func Test_getAssetsForAddressesFromNodes(t *testing.T) { + apis := make(map[uint]blockatlas.TokensAPI) + mock0 := mockedTokenAPI{WantedToken: "ABC", WantedCoin: 0} + mock60 := mockedTokenAPI{WantedToken: "XYZ", WantedCoin: 60} + apis[0] = mock0 + apis[60] = mock60 + + addresses := make(map[uint][]string) + addresses[0] = []string{"A", "B", "C"} + addresses[60] = []string{"X", "Y", "Z"} + result := getAssetsByAddressFromNodes(addresses, apis) + assert.NotNil(t, result) +} + +type mockedTokenAPI struct { + WantedCoin uint + WantedToken string +} + +func (m mockedTokenAPI) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { + if address == "Y" { + return nil, errors.New("failed") + } + tk := blockatlas.Token{ + Name: "", + Symbol: "", + Decimals: 0, + TokenID: m.WantedToken, + Coin: m.WantedCoin, + Type: "", + } + return blockatlas.TokenPage{tk}, nil +} +func (m mockedTokenAPI) Coin() coin.Coin { + return coin.Coin{ID: m.WantedCoin} +} diff --git a/services/tokensearcher/association.go b/services/tokensearcher/association.go new file mode 100644 index 000000000..948c14630 --- /dev/null +++ b/services/tokensearcher/association.go @@ -0,0 +1,62 @@ +package tokensearcher + +import ( + "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/watchmarket/pkg/watchmarket" + "strings" +) + +func assetsMap(txs blockatlas.Txs, coinID string) map[string][]string { + result := make(map[string][]string) + prefix := coinID + "_" + for _, tx := range txs { + addresses := tx.GetAddresses() + tokenID, ok := tx.TokenID() + if !ok { + continue + } + assetID := watchmarket.BuildID(tx.Coin, tokenID) + for _, a := range addresses { + assetIDs := result[prefix+a] + result[prefix+a] = append(assetIDs, assetID) + } + } + return result +} + +func associationsToAdd(oldAssociations map[string][]string, newAssociations map[string][]string) map[string][]string { + result := make(map[string][]string) + for oldAddresses, oldAssets := range oldAssociations { + for newAddresses, newAssets := range newAssociations { + if strings.EqualFold(oldAddresses, newAddresses) { + m := result[newAddresses] + result[newAddresses] = append(m, newAssociationsForAddress(oldAssets, newAssets)...) + } + } + } + return result +} + +func newAssociationsForAddress(oldAssociations []string, newAssociations []string) []string { + var result []string + oldM := make(map[string]bool) + for _, o := range oldAssociations { + oldM[o] = true + } + for _, n := range newAssociations { + if ok := oldM[n]; !ok { + result = append(result, n) + } + } + return result +} + +func fromModelToAssociation(associations []models.AddressToAssetAssociation) map[string][]string { + result := make(map[string][]string) + for _, a := range associations { + m := result[a.Address.Address] + result[a.Address.Address] = append(m, a.Asset.AssetID) + } + return result +} diff --git a/services/tokensearcher/association_test.go b/services/tokensearcher/association_test.go new file mode 100644 index 000000000..b861b67ff --- /dev/null +++ b/services/tokensearcher/association_test.go @@ -0,0 +1,100 @@ +package tokensearcher + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "testing" +) + +func Test_assetsMap(t *testing.T) { + tx1 := blockatlas.Tx{ + Coin: 60, + From: "A", + To: "B", + Meta: blockatlas.NativeTokenTransfer{ + TokenID: "ABC", + From: "A", + To: "C", + }, + } + + tx2 := blockatlas.Tx{ + Coin: 60, + From: "D", + To: "V", + Meta: blockatlas.TokenTransfer{ + TokenID: "EFG", + From: "D", + To: "F", + }, + } + + tx3 := blockatlas.Tx{ + Coin: 60, + From: "Q", + To: "L", + Meta: blockatlas.AnyAction{ + TokenID: "HIJ", + }, + } + + result := assetsMap(blockatlas.Txs{tx1, tx2, tx3}, "60") + assert.Equal(t, result["60_A"], []string{"c60_tABC"}) + assert.Equal(t, result["60_C"], []string{"c60_tABC"}) + assert.Equal(t, result["60_D"], []string{"c60_tEFG"}) + assert.Equal(t, result["60_F"], []string{"c60_tEFG"}) + assert.Equal(t, result["60_Q"], []string{"c60_tHIJ"}) + assert.Equal(t, result["60_L"], []string{"c60_tHIJ"}) +} + +func Test_associationsToAdd(t *testing.T) { + o := make(map[string][]string) + n := make(map[string][]string) + + o["A"] = []string{"1", "2", "3"} + o["B"] = []string{"3", "4", "5"} + + n["A"] = []string{"1", "2", "5"} + n["B"] = []string{"3", "9", "8"} + + result := associationsToAdd(o, n) + + assert.Equal(t, result["A"], []string{"5"}) + assert.Equal(t, result["B"], []string{"9", "8"}) +} + +func Test_newAssociationsForAddress(t *testing.T) { + o := []string{"1", "2", "3"} + n := []string{"1", "2", "3", "4", "5"} + + result := newAssociationsForAddress(o, n) + assert.Equal(t, result, []string{"4", "5"}) + + o = []string{"1", "2", "3"} + n = []string{"1", "2", "3"} + + result = newAssociationsForAddress(o, n) + assert.Equal(t, len(result), len([]string{})) + + o = []string{"1", "2", "3"} + n = []string{"1", "2"} + + result = newAssociationsForAddress(o, n) + assert.Equal(t, len(result), len([]string{})) +} + +func Test_fromModelToAssociation(t *testing.T) { + a := []models.AddressToAssetAssociation{ + {Address: models.Address{Address: "A"}, Asset: models.Asset{AssetID: "1"}}, + {Address: models.Address{Address: "A"}, Asset: models.Asset{AssetID: "2"}}, + {Address: models.Address{Address: "A"}, Asset: models.Asset{AssetID: "3"}}, + {Address: models.Address{Address: "B"}, Asset: models.Asset{AssetID: "2"}}, + {Address: models.Address{Address: "B"}, Asset: models.Asset{AssetID: "3"}}, + {Address: models.Address{Address: "B"}, Asset: models.Asset{AssetID: "4"}}, + } + + result := fromModelToAssociation(a) + assert.Equal(t, result["A"], []string{"1", "2", "3"}) + assert.Equal(t, result["B"], []string{"2", "3", "4"}) +} diff --git a/services/tokensearcher/models.go b/services/tokensearcher/models.go new file mode 100644 index 000000000..0897e3b7e --- /dev/null +++ b/services/tokensearcher/models.go @@ -0,0 +1,23 @@ +package tokensearcher + +import ( + "github.com/trustwallet/blockatlas/pkg/address" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/watchmarket/pkg/watchmarket" + "sync" +) + +type NodesResponse struct { + sync.Mutex + AssetsByAddress AssetsByAddress +} + +func (nr *NodesResponse) UpdateAssetsByAddress(tokens blockatlas.TokenPage, coin int, a string) { + nr.Lock() + for _, t := range tokens { + key := address.PrefixedAddress(uint(coin), a) + r := nr.AssetsByAddress[key] + nr.AssetsByAddress[key] = append(r, watchmarket.BuildID(t.Coin, t.TokenID)) + } + nr.Unlock() +} diff --git a/services/tokensearcher/tokensearcher.go b/services/tokensearcher/tokensearcher.go new file mode 100644 index 000000000..29716ab87 --- /dev/null +++ b/services/tokensearcher/tokensearcher.go @@ -0,0 +1,53 @@ +package tokensearcher + +import ( + "context" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/services/notifier" + "go.elastic.co/apm" + "strconv" +) + +func Run(database *db.Instance, delivery amqp.Delivery) { + tx := apm.DefaultTracer.StartTransaction("RunNotifier", "app") + defer tx.End() + ctx := apm.ContextWithTransaction(context.Background(), tx) + + txs, err := notifier.GetTransactionsFromDelivery(delivery, ctx) + if err != nil { + logger.Error("failed to get transactions", err) + if err := delivery.Ack(false); err != nil { + logger.Error(err) + } + } + if len(txs) == 0 { + return + } + coinID := strconv.Itoa(int(txs[0].Coin)) + var addresses []string + for _, tx := range txs { + addresses = append(addresses, tx.GetAddresses()...) + } + for i := range addresses { + addresses[i] = coinID + "_" + addresses[i] + } + + associationsFromTransactions, err := database.GetAssociationsByAddresses(notifier.ToUniqueAddresses(addresses), ctx) + if err != nil { + logger.Error(err) + return + } + + associationsToAdd := associationsToAdd(fromModelToAssociation(associationsFromTransactions), assetsMap(txs, coinID)) + err = database.UpdateAssociationsForExistingAddresses(associationsToAdd, ctx) + if err != nil { + logger.Error(err) + return + } + + if err := delivery.Ack(false); err != nil { + logger.Error(err) + } +} diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go index fdf2fad97..c35cbef92 100644 --- a/tests/integration/db_test/subscriptions_test.go +++ b/tests/integration/db_test/subscriptions_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/observer/subscriber" + "github.com/trustwallet/blockatlas/services/subscriber" "github.com/trustwallet/blockatlas/tests/integration/setup" "testing" "time" @@ -15,155 +15,49 @@ import ( func TestDb_AddSubscriptionsBulk(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.Subscription + var subscriptions []string for i := 0; i < 100; i++ { - subscriptions = append(subscriptions, models.Subscription{ - Coin: uint(i), - Address: "testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr", - }) + subscriptions = append(subscriptions, "testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr") } - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriptions, context.Background())) for i := 0; i < 100; i++ { - s, err := database.GetSubscriptions(uint(i), []string{"testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr"}, context.Background()) + s, err := database.GetSubscriptionsForNotifications([]string{"testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, s) } - } func TestDb_AddSubscriptions(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.Subscription - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 60, - Address: "testAddr", - }) - subscriptions = append(subscriptions, models.Subscription{ - Coin: 61, - Address: "testAddr2", - }) - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 62, - Address: "testAddr3", - }) - - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications([]string{"60_testAddr", "60_testAddr2", "60_testAddr3"}, context.Background())) - subs, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) - assert.Equal(t, subscriptions[0].Coin, subs[0].Coin) - assert.Equal(t, subscriptions[0].Address, subs[0].Address) + assert.Equal(t, "60_testAddr", subs[0].Address.Address) - subs, err = database.GetSubscriptions(61, []string{"testAddr2"}, context.Background()) + subs, err = database.GetSubscriptionsForNotifications([]string{"60_testAddr2"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) - assert.Equal(t, subscriptions[1].Coin, subs[0].Coin) - assert.Equal(t, subscriptions[1].Address, subs[0].Address) + assert.Equal(t, "60_testAddr2", subs[0].Address.Address) - subs, err = database.GetSubscriptions(62, []string{"testAddr3"}, context.Background()) + subs, err = database.GetSubscriptionsForNotifications([]string{"60_testAddr3"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) - assert.Equal(t, subscriptions[2].Coin, subs[0].Coin) - assert.Equal(t, subscriptions[2].Address, subs[0].Address) -} - -func TestDb_AddSubscriptionsWithRewrite(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - - var subscriptions []models.Subscription - subscriptions = append(subscriptions, models.Subscription{ - Coin: 60, - Address: "testAddr", - }) - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 714, - Address: "testAddr", - }) - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 144, - Address: "testAddr", - }) - - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - - subs60, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) - assert.Nil(t, err) - assert.NotNil(t, subs60) - assert.Equal(t, 1, len(subs60)) - assert.Equal(t, subscriptions[0].Coin, subs60[0].Coin) - assert.Equal(t, subscriptions[0].Address, subs60[0].Address) - - subs714, err := database.GetSubscriptions(714, []string{"testAddr"}, context.Background()) - assert.Nil(t, err) - assert.NotNil(t, subs714) - assert.Equal(t, 1, len(subs714)) - assert.Equal(t, subscriptions[1].Coin, subs714[0].Coin) - assert.Equal(t, subscriptions[1].Address, subs714[0].Address) - - subs144, err := database.GetSubscriptions(144, []string{"testAddr"}, context.Background()) - assert.Nil(t, err) - assert.NotNil(t, subs144) - assert.Equal(t, 1, len(subs144)) - assert.Equal(t, subscriptions[2].Coin, subs144[0].Coin) - assert.Equal(t, subscriptions[2].Address, subs144[0].Address) - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 60, - Address: "testAddr2", - }) - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 714, - Address: "testAddr2", - }) - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 144, - Address: "testAddr2", - }) - - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - - subs2N60, err := database.GetSubscriptions(60, []string{"testAddr2"}, context.Background()) - assert.Nil(t, err) - assert.Nil(t, err) - assert.NotNil(t, subs2N60) - assert.Equal(t, 1, len(subs2N60)) - assert.Equal(t, subscriptions[3].Coin, subs2N60[0].Coin) - assert.Equal(t, subscriptions[3].Address, subs2N60[0].Address) - - subs2N714, err := database.GetSubscriptions(714, []string{"testAddr2"}, context.Background()) - assert.Nil(t, err) - assert.Nil(t, err) - assert.NotNil(t, subs2N714) - assert.Equal(t, 1, len(subs2N714)) - assert.Equal(t, subscriptions[4].Coin, subs2N714[0].Coin) - assert.Equal(t, subscriptions[4].Address, subs2N714[0].Address) - - subs2N114, err := database.GetSubscriptions(144, []string{"testAddr2"}, context.Background()) - assert.Nil(t, err) - assert.Nil(t, err) - assert.NotNil(t, subs2N114) - assert.Equal(t, 1, len(subs2N114)) - assert.Equal(t, subscriptions[5].Coin, subs2N114[0].Coin) - assert.Equal(t, subscriptions[5].Address, subs2N114[0].Address) + assert.Equal(t, "60_testAddr3", subs[0].Address.Address) } func TestDb_FindSubscriptions(t *testing.T) { setup.CleanupPgContainer(database.Gorm) var subscriptionsA []blockatlas.Subscription + subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ Coin: 60, Address: "etherAddress", @@ -189,224 +83,151 @@ func TestDb_FindSubscriptions(t *testing.T) { Address: "ETCAddress", }) - assert.Nil(t, database.AddSubscriptions(subscriber.ToSubscriptionData(subscriptionsA), context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptionsA), context.Background())) var subscriptionsB []blockatlas.Subscription for _, sub := range subscriptionsA { subscriptionsB = append(subscriptionsB, sub) } - assert.Nil(t, database.AddSubscriptions(subscriber.ToSubscriptionData(subscriptionsB), context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptionsB), context.Background())) - returnedSubs, err := database.GetSubscriptions(60, []string{"etherAddress"}, context.Background()) + returnedSubs, err := database.GetSubscriptionsForNotifications([]string{"60_etherAddress"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptions(714, []string{"binanceAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"714_binanceAddress"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptions(144, []string{"XLMAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"144_XLMAddress"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptions(148, []string{"AtomAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"148_AtomAddress"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptions(61, []string{"ETCAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"61_ETCAddress"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(returnedSubs)) } func TestDb_DeleteSubscriptions(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.Subscription - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 60, - Address: "testAddr", - }) - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 714, - Address: "testAddr2", - }) - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 144, - Address: "testAddr3", - }) + subscriptions := []string{ + "60_testAddr", + "714_testAddr2", + "144_testAddr3", + } - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriptions, context.Background())) - subs60, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + subs60, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs60) assert.Equal(t, 1, len(subs60)) - assert.Equal(t, subscriptions[0].Coin, subs60[0].Coin) - assert.Equal(t, subscriptions[0].Address, subs60[0].Address) - subs714, err := database.GetSubscriptions(714, []string{"testAddr2"}, context.Background()) + subs714, err := database.GetSubscriptionsForNotifications([]string{"714_testAddr2"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs714) assert.Equal(t, 1, len(subs714)) - assert.Equal(t, subscriptions[1].Coin, subs714[0].Coin) - assert.Equal(t, subscriptions[1].Address, subs714[0].Address) - subs144, err := database.GetSubscriptions(144, []string{"testAddr3"}, context.Background()) + subs144, err := database.GetSubscriptionsForNotifications([]string{"144_testAddr3"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs144) assert.Equal(t, 1, len(subs144)) - assert.Equal(t, subscriptions[2].Coin, subs144[0].Coin) - assert.Equal(t, subscriptions[2].Address, subs144[0].Address) - - subsToDel := []models.Subscription{subscriptions[0]} - assert.Nil(t, database.DeleteSubscriptions(subsToDel, context.Background())) + assert.Nil(t, database.DeleteSubscriptionsForNotifications([]string{subscriptions[0]}, context.Background())) - subs714N2, err := database.GetSubscriptions(714, []string{"testAddr2"}, context.Background()) + subs714N2, err := database.GetSubscriptionsForNotifications([]string{"714_testAddr2"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs714N2) assert.Equal(t, 1, len(subs714N2)) - assert.Equal(t, subscriptions[1].Coin, subs714N2[0].Coin) - assert.Equal(t, subscriptions[1].Address, subs714N2[0].Address) - subs144N2, err := database.GetSubscriptions(144, []string{"testAddr3"}, context.Background()) + subs144N2, err := database.GetSubscriptionsForNotifications([]string{"144_testAddr3"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs144N2) assert.Equal(t, 1, len(subs144N2)) - assert.Equal(t, subscriptions[2].Coin, subs144N2[0].Coin) - assert.Equal(t, subscriptions[2].Address, subs144N2[0].Address) - subs60N2, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + subs60N2, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) assert.Nil(t, err) assert.Len(t, subs60N2, 0) } -func TestDeleteAll(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.Subscription - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 60, - Address: "testAddr", - }) - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 714, - Address: "testAddr2", - }) - - subscriptions = append(subscriptions, models.Subscription{ - Coin: 144, - Address: "testAddr3", - }) - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - - subs60, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) - assert.Nil(t, err) - assert.Len(t, subs60, 1) - - subs714, err := database.GetSubscriptions(714, []string{"testAddr2"}, context.Background()) - assert.Nil(t, err) - assert.Len(t, subs714, 1) - - subs144, err := database.GetSubscriptions(144, []string{"testAddr3"}, context.Background()) - assert.Nil(t, err) - assert.Len(t, subs144, 1) -} - func TestDb_DuplicateEntries(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.Subscription + var subscriptions []blockatlas.Subscription for i := 0; i < 10; i++ { - subscriptions = append(subscriptions, models.Subscription{ + subscriptions = append(subscriptions, blockatlas.Subscription{ Coin: 60, Address: "testAddr", }) } - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions), context.Background())) - subs, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) - assert.True(t, containSub(subscriptions[0], subs)) } func TestDb_CreateDeleteCreate(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.Subscription - subscriptions = append(subscriptions, models.Subscription{ + var subscriptions []blockatlas.Subscription + subscriptions = append(subscriptions, blockatlas.Subscription{ Coin: 60, Address: "testAddr", }) - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - subs, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions), context.Background())) + subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(subs)) - time.Sleep(time.Second) + assert.Nil(t, database.DeleteSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background())) - assert.Nil(t, database.DeleteSubscriptions(subs, context.Background())) - - subs2, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + subs2, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 0, len(subs2)) - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions), context.Background())) - subs3, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + subs3, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(subs3)) } func TestDb_UpdatedAt(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - var subscriptions []models.Subscription - subscriptions = append(subscriptions, models.Subscription{ + var subscriptions []blockatlas.Subscription + subscriptions = append(subscriptions, blockatlas.Subscription{ Coin: 60, Address: "testAddr", }) - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - subs, err := database.GetSubscriptions(60, []string{"testAddr"}, context.Background()) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions), context.Background())) + subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) assert.Nil(t, err) assert.Equal(t, 1, len(subs)) - time.Sleep(time.Second) + var existingSub models.NotificationSubscription + var existingAddr models.Address - var existingSub models.Subscription - assert.False(t, database.Gorm.Where(models.Subscription{Address: "testAddr"}).First(&existingSub).RecordNotFound()) - assert.Greater(t, time.Now().Unix(), existingSub.CreatedAt.Unix()) - assert.Greater(t, existingSub.CreatedAt.Unix(), time.Now().Unix()-120) + assert.False(t, database.Gorm.Where("address = ?", "60_testAddr").First(&existingAddr).RecordNotFound()) + assert.False(t, database.Gorm.Where("address_id = ?", existingAddr.ID).First(&existingSub).RecordNotFound()) + assert.Greater(t, existingSub.UpdatedAt.Unix(), time.Now().Unix()-120) - subscriptions = append(subscriptions, models.Subscription{ + subscriptions = append(subscriptions, blockatlas.Subscription{ Coin: 714, Address: "newtestAddr", }) - assert.Nil(t, database.AddSubscriptions(subscriptions, context.Background())) - - time.Sleep(time.Second) - - var existingSub2 models.Subscription - assert.False(t, database.Gorm.Where(models.Subscription{Address: "testAddr"}).First(&existingSub2).RecordNotFound()) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions), context.Background())) - assert.Greater(t, time.Now().Unix(), existingSub2.CreatedAt.Unix()) - assert.Greater(t, existingSub2.CreatedAt.Unix(), time.Now().Unix()-120) - assert.GreaterOrEqual(t, existingSub2.CreatedAt.Unix(), existingSub.CreatedAt.Unix()) -} - -func containSub(sub models.Subscription, list []models.Subscription) bool { - for _, s := range list { - if sub.Address == s.Address && sub.Coin == s.Coin { - return true - } - } - return false + var existingSub2 models.NotificationSubscription + assert.False(t, database.Gorm.Where("address_id = ?", existingSub.ID).First(&existingSub2).RecordNotFound()) + assert.Greater(t, existingSub2.UpdatedAt.Unix(), time.Now().Unix()-120) } diff --git a/tests/integration/db_test/tokenassociations_test.go b/tests/integration/db_test/tokenassociations_test.go new file mode 100644 index 000000000..39bd5c42d --- /dev/null +++ b/tests/integration/db_test/tokenassociations_test.go @@ -0,0 +1,179 @@ +// +build integration + +package db_test + +import ( + "context" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/tests/integration/setup" + "sort" + "testing" + "time" +) + +func Test_GetAssetsMapByAddresses(t *testing.T) { + setup.CleanupPgContainer(database.Gorm) + + assets := []string{"aa", "bbb", "cccc"} + + err := database.AddAssociationsForAddress("a", assets, context.Background()) + assert.Nil(t, err) + + err = database.AddAssociationsForAddress("b", nil, context.Background()) + assert.Nil(t, err) + + m, err := database.GetAssetsMapByAddresses([]string{"a", "b"}, context.Background()) + assert.Nil(t, err) + wantedMap := make(map[string][]string) + wantedMap["a"] = assets + assert.Equal(t, wantedMap, m) +} + +func Test_GetAssetsMapByAddressesFromTime(t *testing.T) { + setup.CleanupPgContainer(database.Gorm) + + assets := []string{"aa", "bbb", "cccc"} + + err := database.AddAssociationsForAddress("a", assets, context.Background()) + assert.Nil(t, err) + + err = database.AddAssociationsForAddress("b", nil, context.Background()) + assert.Nil(t, err) + tm := time.Now().Unix() - 100 + m, err := database.GetAssetsMapByAddressesFromTime([]string{"a", "b"}, time.Unix(tm, 0), context.Background()) + assert.Nil(t, err) + wantedMap := make(map[string][]string) + wantedMap["a"] = assets + assert.Equal(t, wantedMap, m) + + m, err = database.GetAssetsMapByAddressesFromTime([]string{"a", "b"}, time.Unix(tm+101, 0), context.Background()) + assert.Nil(t, err) + assert.Equal(t, 0, len(m)) +} + +func Test_GetSubscribedAddressesForAssets(t *testing.T) { + setup.CleanupPgContainer(database.Gorm) + + assets := []string{"aa", "bbb", "cccc"} + + err := database.AddAssociationsForAddress("a", assets, context.Background()) + assert.Nil(t, err) + + err = database.AddAssociationsForAddress("b", nil, context.Background()) + assert.Nil(t, err) + + m, err := database.GetSubscribedAddressesForAssets(context.Background(), []string{"a", "b"}) + assert.Nil(t, err) + assert.Equal(t, 2, len(m)) +} + +func Test_AddNewAssociationForAddress(t *testing.T) { + setup.CleanupPgContainer(database.Gorm) + assets := []string{"aa", "bbb", "cccc"} + + err := database.AddAssociationsForAddress("a", assets, context.Background()) + assert.Nil(t, err) + + associations, err := database.GetAssociationsByAddresses([]string{"a"}, context.Background()) + assert.Nil(t, err) + + var assetIDsFromDB []string + for _, a := range associations { + assetIDsFromDB = append(assetIDsFromDB, a.Asset.AssetID) + } + + sort.Slice(assets, func(i, j int) bool { + return len(assets[i]) > len(assets[j]) + }) + + sort.Slice(assetIDsFromDB, func(i, j int) bool { + return len(assetIDsFromDB[i]) > len(assetIDsFromDB[j]) + }) + + assert.Equal(t, assetIDsFromDB, assets) + + err = database.AddAssociationsForAddress("b", nil, context.Background()) + assert.Nil(t, err) + + associations2, err := database.GetAssociationsByAddresses([]string{"b"}, context.Background()) + assert.Nil(t, err) + assert.NotNil(t, associations2) +} + +func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { + setup.CleanupPgContainer(database.Gorm) + assets := []string{"f"} + + err := database.AddAssociationsForAddress("A", assets, context.Background()) + assert.Nil(t, err) + + err = database.AddAssociationsForAddress("B", assets, context.Background()) + assert.Nil(t, err) + + assetsForA := []string{"aa", "bbb", "cccc"} + assetsForB := []string{"as", "bbb", "cccc"} + + updateMap := make(map[string][]string) + updateMap["A"] = assetsForA + updateMap["B"] = assetsForB + + err = database.UpdateAssociationsForExistingAddresses(updateMap, context.Background()) + assert.Nil(t, err) + + associationsA, err := database.GetAssociationsByAddresses([]string{"A"}, context.Background()) + assert.Nil(t, err) + + var assetIDsFromDBA []string + for _, a := range associationsA { + assetIDsFromDBA = append(assetIDsFromDBA, a.Asset.AssetID) + } + assetsA := []string{"aa", "bbb", "cccc", "f"} + + sort.Slice(assetsA, func(i, j int) bool { + return len(assetsA[i]) > len(assetsA[j]) + }) + + sort.Slice(assetIDsFromDBA, func(i, j int) bool { + return len(assetIDsFromDBA[i]) > len(assetIDsFromDBA[j]) + }) + + assert.Equal(t, assetIDsFromDBA, assetsA) + + associationsB, err := database.GetAssociationsByAddresses([]string{"B"}, context.Background()) + assert.Nil(t, err) + + var assetIDsFromDBB []string + for _, a := range associationsB { + assetIDsFromDBB = append(assetIDsFromDBB, a.Asset.AssetID) + } + assetsB := []string{"as", "bbb", "cccc", "f"} + + sort.Slice(assetsB, func(i, j int) bool { + return len(assetsB[i]) > len(assetsB[j]) + }) + + sort.Slice(assetIDsFromDBB, func(i, j int) bool { + return len(assetIDsFromDBB[i]) > len(assetIDsFromDBB[j]) + }) + + assert.Equal(t, assetIDsFromDBB, assetsB) + + associationsAB, err := database.GetAssociationsByAddresses([]string{"A", "B"}, context.Background()) + assert.Nil(t, err) + + var assetIDsFromDBAB []string + for _, a := range associationsAB { + assetIDsFromDBAB = append(assetIDsFromDBAB, a.Asset.AssetID) + } + assetsAB := []string{"cccc", "cccc", "bbb", "bbb", "aa", "as", "f", "f"} + + sort.Slice(assetsAB, func(i, j int) bool { + return len(assetsAB[i]) > len(assetsAB[j]) + }) + + sort.Slice(assetIDsFromDBAB, func(i, j int) bool { + return len(assetIDsFromDBAB[i]) > len(assetIDsFromDBAB[j]) + }) + + assert.Equal(t, assetIDsFromDBAB, assetsAB) +} diff --git a/tests/integration/observer_test/data/wanted_subscriptions_added.json b/tests/integration/observer_test/data/wanted_subscriptions_added.json index 051f5d674..febd62730 100644 --- a/tests/integration/observer_test/data/wanted_subscriptions_added.json +++ b/tests/integration/observer_test/data/wanted_subscriptions_added.json @@ -1,18 +1,18 @@ [ { "coin": 60, - "address": "0x0000000000000000000000000000000000000000" + "address": "60_0x0000000000000000000000000000000000000000" }, { "coin": 118, - "address": "0x0000000000000000000000000000000000000001" + "address": "118_0x0000000000000000000000000000000000000001" }, { "coin": 714, - "address": "0x0000000000000000000000000000000000000002" + "address": "714_0x0000000000000000000000000000000000000002" }, { "coin": 144, - "address": "0x0000000000000000000000000000000000000003" + "address": "144_0x0000000000000000000000000000000000000003" } ] diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 031d424a3..d2fddf69f 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -8,11 +8,10 @@ import ( "github.com/streadway/amqp" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/observer/notifier" - "github.com/trustwallet/blockatlas/services/observer/parser" + "github.com/trustwallet/blockatlas/services/notifier" + "github.com/trustwallet/blockatlas/services/parser" "github.com/trustwallet/blockatlas/tests/integration/setup" "go.uber.org/atomic" "testing" @@ -25,7 +24,7 @@ var ( func TestFullFlow(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptions([]models.Subscription{{Coin: 60, Address: "testAddress"}}, context.Background()) + err := database.AddSubscriptionsForNotifications([]string{"60_testAddress"}, context.Background()) assert.Nil(t, err) ctx, cancel := context.WithCancel(context.Background()) @@ -35,7 +34,7 @@ func TestFullFlow(t *testing.T) { params := setupParserFull(stopChan) params.Database = database params.Ctx = ctx - params.Queue = mq.RawTransactions + params.Queue = []mq.Queue{mq.RawTransactions} go parser.RunParser(params) time.Sleep(time.Second * 2) diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index 1f64e5de6..39d00b056 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -8,10 +8,9 @@ import ( "github.com/streadway/amqp" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" - "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/observer/notifier" + "github.com/trustwallet/blockatlas/services/notifier" "github.com/trustwallet/blockatlas/tests/integration/setup" "testing" "time" @@ -44,7 +43,7 @@ var ( func TestNotifier(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptions([]models.Subscription{{Coin: 714, Address: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"}}, context.Background()) + err := database.AddSubscriptionsForNotifications([]string{"714_tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"}, context.Background()) assert.Nil(t, err) err = produceTxs(txs) diff --git a/tests/integration/observer_test/parser_test.go b/tests/integration/observer_test/parser_test.go index 1c5d6b714..860b55211 100644 --- a/tests/integration/observer_test/parser_test.go +++ b/tests/integration/observer_test/parser_test.go @@ -11,7 +11,7 @@ import ( "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/services/observer/parser" + "github.com/trustwallet/blockatlas/services/parser" "github.com/trustwallet/blockatlas/tests/integration/setup" "testing" "time" @@ -27,7 +27,7 @@ func TestParserFetchAndPublishBlock_NormalCase(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) params.Ctx = ctx - params.Queue = mq.RawTransactions + params.Queue = []mq.Queue{mq.RawTransactions} go parser.RunParser(params) diff --git a/tests/integration/observer_test/subscriber_test.go b/tests/integration/observer_test/subscriber_test.go index 540d71524..fa804f05a 100644 --- a/tests/integration/observer_test/subscriber_test.go +++ b/tests/integration/observer_test/subscriber_test.go @@ -6,10 +6,9 @@ import ( "context" "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/observer/subscriber" + "github.com/trustwallet/blockatlas/services/subscriber" "github.com/trustwallet/blockatlas/tests/integration/setup" "io/ioutil" "path/filepath" @@ -51,16 +50,15 @@ func TestSubscriberAddSubscription(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) - go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunSubscriber, subscriptionChannel, database, ctx) + go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, subscriptionChannel, database, ctx) time.Sleep(time.Second * 2) cancel() } for _, wanted := range wantedEvents { - result, err := database.GetSubscriptions(wanted.Coin, []string{wanted.Address}, context.Background()) + result, err := database.GetSubscriptionsForNotifications([]string{wanted.Address}, context.Background()) assert.Nil(t, err) - assert.Equal(t, result[0].Coin, wanted.Coin) - assert.Equal(t, result[0].Address, wanted.Address) + assert.Equal(t, result[0].Address.Address, wanted.Address) } } @@ -91,14 +89,17 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { t.Fatal(err) } - database.AddSubscriptions([]models.Subscription{ - {Coin: 61, Address: "0x0000000000000000000000000000000000000000"}}, context.Background()) - database.AddSubscriptions([]models.Subscription{ - {Coin: 62, Address: "0x0000000000000000000000000000000000000000"}}, context.Background()) - database.AddSubscriptions([]models.Subscription{ - {Coin: 63, Address: "0x0000000000000000000000000000000000000000"}}, context.Background()) - database.AddSubscriptions([]models.Subscription{ - {Coin: 64, Address: "0x0000000000000000000000000000000000000000"}}, context.Background()) + database.AddSubscriptionsForNotifications( + []string{"61_0x0000000000000000000000000000000000000000"}, context.Background()) + + database.AddSubscriptionsForNotifications( + []string{"62_0x0000000000000000000000000000000000000000"}, context.Background()) + + database.AddSubscriptionsForNotifications( + []string{"63_0x0000000000000000000000000000000000000000"}, context.Background()) + + database.AddSubscriptionsForNotifications( + []string{"64_0x0000000000000000000000000000000000000000"}, context.Background()) for _, event := range givenEvents { body, err := json.Marshal(event) @@ -109,36 +110,34 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) - go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunSubscriber, subscriptionChannel, database, ctx) + go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, subscriptionChannel, database, ctx) time.Sleep(time.Second) cancel() } for _, wanted := range wantedEvents { - result, err := database.GetSubscriptions(wanted.Coin, []string{wanted.Address}, context.Background()) + result, err := database.GetSubscriptionsForNotifications([]string{wanted.Address}, context.Background()) assert.Nil(t, err) - assert.Equal(t, result[0].Coin, wanted.Coin) - assert.Equal(t, result[0].Address, wanted.Address) - + assert.Len(t, result, 1) } - abs61, err := database.GetSubscriptions(61, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) + abs61, err := database.GetSubscriptionsForNotifications([]string{"61_0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) assert.Len(t, abs61, 1) - abs62, err := database.GetSubscriptions(62, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) + abs62, err := database.GetSubscriptionsForNotifications([]string{"62_0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) assert.Len(t, abs62, 1) - abs63, err := database.GetSubscriptions(63, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) + abs63, err := database.GetSubscriptionsForNotifications([]string{"63_0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) assert.Len(t, abs63, 1) - abs64, err := database.GetSubscriptions(64, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) + abs64, err := database.GetSubscriptionsForNotifications([]string{"64_0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) assert.Len(t, abs64, 1) - abs65, err := database.GetSubscriptions(65, []string{"0x0000000000000000000000000000000000000000"}, context.Background()) + abs65, err := database.GetSubscriptionsForNotifications([]string{"65_0x0000000000000000000000000000000000000000"}, context.Background()) assert.Nil(t, err) assert.Len(t, abs65, 0) } diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go index ec09821fe..d300c16d8 100644 --- a/tests/integration/setup/postgres.go +++ b/tests/integration/setup/postgres.go @@ -24,8 +24,12 @@ var ( } tables = []interface{}{ - &models.Subscription{}, + &models.AssetSubscription{}, + &models.NotificationSubscription{}, &models.Tracker{}, + &models.AddressToAssetAssociation{}, + &models.Asset{}, + &models.Address{}, } uri string From 5b58831bcb465865a7774ae658ed589e716df567 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Tue, 1 Sep 2020 03:58:53 +0300 Subject: [PATCH 370/506] [API] Change platform init order (#1210) --- cmd/api/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index ab6f60429..50c32b823 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -36,6 +36,7 @@ func init() { restAPI = viper.GetString("rest_api") engine = internal.InitEngine(viper.GetString("gin.mode")) + platform.Init(viper.GetStringSlice("platform")) if restAPI == "tokens" || restAPI == "all" { pgUri := viper.GetString("postgres.uri") @@ -57,7 +58,6 @@ func init() { go db.RestoreConnectionWorker(database, time.Second*10, pgUri) go mq.FatalWorker(time.Second * 10) } - platform.Init(viper.GetStringSlice("platform")) } func main() { From ce5a721781b6c960ba4d0b94602dfe5da1839c1f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2020 02:33:58 +0300 Subject: [PATCH 371/506] Bump github.com/trustwallet/watchmarket from 1.1.0 to 1.1.1 (#1211) Bumps [github.com/trustwallet/watchmarket](https://github.com/trustwallet/watchmarket) from 1.1.0 to 1.1.1. - [Release notes](https://github.com/trustwallet/watchmarket/releases) - [Commits](https://github.com/trustwallet/watchmarket/compare/v1.1.0...v1.1.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 94cb23284..b23fbc298 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/swaggo/swag v1.6.7 github.com/t-tiger/gorm-bulk-insert v1.3.0 github.com/trustwallet/ens-coincodec v1.0.6 - github.com/trustwallet/watchmarket v1.1.0 + github.com/trustwallet/watchmarket v1.1.1 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmgorm v1.8.0 diff --git a/go.sum b/go.sum index ae48691e3..05df30e37 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.13.1/go.mod h1:0UIBNuf97uxrWhdVBpJvPtafKyGpL2NS2pYe0tYM97k= +github.com/alicebob/miniredis/v2 v2.13.2/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -169,6 +170,7 @@ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1 github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-redis/redis v6.15.3-0.20190424063336-97e6ed817821+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= @@ -458,11 +460,14 @@ github.com/t-tiger/gorm-bulk-insert v1.3.0 h1:9k7BaVEhw/3fsvh6GTOBwJ2RXk3asc5xs5 github.com/t-tiger/gorm-bulk-insert v1.3.0/go.mod h1:ruDlk8xDl+8sX4bA7PQuYly9YEb3pbp1eP2LCyeRrFY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/blockatlas v1.1.3-0.20200518232337-7495506f457c/go.mod h1:5Ev/iawD12+qgmtMkGgjYCKmGLF724YaxYfEbfY8lKc= +github.com/trustwallet/blockatlas v1.1.7-0.20200831100332-b573ace18512/go.mod h1:rq6APqrT+vR58h+WWrCyadT80QDKmDEJvHDllWSUwnM= github.com/trustwallet/ens-coincodec v1.0.5/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= github.com/trustwallet/ens-coincodec v1.0.6 h1:ZPvFDJwvv4s+XCnUM7pzub8wYHy37tyJBNtKvgx9FDs= github.com/trustwallet/ens-coincodec v1.0.6/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= github.com/trustwallet/watchmarket v1.1.0 h1:tD+dlnKRONYr2ljsirM0Gx90ahzlfL1ceNSJlpTxINQ= github.com/trustwallet/watchmarket v1.1.0/go.mod h1:VKVAqqClA5Oc6jaJvNorvn9wRnp9BKV04jVbjTGx0Zw= +github.com/trustwallet/watchmarket v1.1.1 h1:gErSfLLDhEblFqvW8V3RyzRqq4R6MCYEDWjO6j5uJfE= +github.com/trustwallet/watchmarket v1.1.1/go.mod h1:DvqzLzxXOaZajbkryVZcNgBS4yibZhk3rCc41ZSJEBs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= From c5ae1a3d2af68f5d51aaea5d108c569ca4d32f71 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 3 Sep 2020 00:52:48 +0300 Subject: [PATCH 372/506] [DB] Redesign models (#1212) * Start to redesign db models again * Changes to model * Fixes * Change db funcs and model * Add migrations and foreign keys * Setup migrations for prod * Changes to the addresstoasset * Remove migrations --- cmd/api/main.go | 3 +- cmd/notifier/main.go | 3 +- cmd/parser/main.go | 3 +- cmd/searcher/main.go | 4 +- cmd/subscriber/main.go | 3 +- config.yml | 1 + db/addresstoasset.go | 70 +++++++++++-------- db/db.go | 15 +++- db/models/address.go | 10 +-- db/models/addresstoasset.go | 5 +- db/models/asset.go | 4 +- db/models/subscriptions.go | 16 ++--- db/notification.go | 14 ++-- services/tokensearcher/api.go | 6 ++ services/tokensearcher/tokensearcher.go | 3 + .../integration/db_test/subscriptions_test.go | 34 --------- .../db_test/tokenassociations_test.go | 6 +- tests/integration/setup/postgres.go | 3 +- 18 files changed, 102 insertions(+), 101 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index 50c32b823..3003aa96a 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -35,6 +35,7 @@ func init() { logger.InitLogger() restAPI = viper.GetString("rest_api") + logMode := viper.GetBool("postgres.log") engine = internal.InitEngine(viper.GetString("gin.mode")) platform.Init(viper.GetStringSlice("platform")) @@ -42,7 +43,7 @@ func init() { pgUri := viper.GetString("postgres.uri") var err error - database, err = db.New(pgUri, prod) + database, err = db.New(pgUri, prod, logMode) if err != nil { logger.Fatal(err) } diff --git a/cmd/notifier/main.go b/cmd/notifier/main.go index 5bee2ce6b..068a19baf 100644 --- a/cmd/notifier/main.go +++ b/cmd/notifier/main.go @@ -28,6 +28,7 @@ func init() { logger.InitLogger() mqHost := viper.GetString("observer.rabbitmq.uri") + logMode := viper.GetBool("postgres.log") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") pgUri := viper.GetString("postgres.uri") @@ -43,7 +44,7 @@ func init() { } var err error - database, err = db.New(pgUri, prod) + database, err = db.New(pgUri, prod, logMode) if err != nil { logger.Fatal(err) } diff --git a/cmd/parser/main.go b/cmd/parser/main.go index e9b721cc3..d7e0fb2bd 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -52,6 +52,7 @@ func init() { } pgUri := viper.GetString("postgres.uri") + logMode := viper.GetBool("postgres.log") txsBatchLimit = viper.GetUint("observer.txs_batch_limit") backlogTime = viper.GetDuration("observer.backlog") @@ -63,7 +64,7 @@ func init() { logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") } var err error - database, err = db.New(pgUri, prod) + database, err = db.New(pgUri, prod, logMode) if err != nil { logger.Fatal(err) } diff --git a/cmd/searcher/main.go b/cmd/searcher/main.go index b58faa1a4..02e1ad84a 100644 --- a/cmd/searcher/main.go +++ b/cmd/searcher/main.go @@ -32,7 +32,7 @@ func init() { prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") pgUri := viper.GetString("postgres.uri") - + logMode := viper.GetBool("postgres.log") internal.InitRabbitMQ(mqHost, prefetchCount) if err := mq.RawTransactions.Declare(); err != nil { @@ -44,7 +44,7 @@ func init() { } var err error - database, err = db.New(pgUri, prod) + database, err = db.New(pgUri, prod, logMode) if err != nil { logger.Fatal(err) } diff --git a/cmd/subscriber/main.go b/cmd/subscriber/main.go index ee130d00e..69240f128 100644 --- a/cmd/subscriber/main.go +++ b/cmd/subscriber/main.go @@ -29,6 +29,7 @@ func init() { logger.InitLogger() pgUri := viper.GetString("postgres.uri") + logMode := viper.GetBool("postgres.log") mqHost := viper.GetString("observer.rabbitmq.uri") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") @@ -36,7 +37,7 @@ func init() { internal.InitRabbitMQ(mqHost, prefetchCount) var err error - database, err = db.New(pgUri, prod) + database, err = db.New(pgUri, prod, logMode) if err != nil { logger.Fatal(err) } diff --git a/config.yml b/config.yml index c9c2b9ba4..36ca64634 100644 --- a/config.yml +++ b/config.yml @@ -40,6 +40,7 @@ observer: postgres: uri: postgresql://user:pass@localhost/my_db?sslmode=disable + log: false # [BNB] Binance DEX: https://www.binance.org/ binance: diff --git a/db/addresstoasset.go b/db/addresstoasset.go index 924a40db0..d2933c743 100644 --- a/db/addresstoasset.go +++ b/db/addresstoasset.go @@ -15,13 +15,16 @@ func (i Instance) GetSubscribedAddressesForAssets(ctx context.Context, addresses Table("addresses"). Select("id"). Where("address in (?)", addresses). + Limit(len(addresses)). QueryExpr() var assetSubs []models.AssetSubscription err := db. + Set("gorm:insert_option", "ON CONFLICT (address_id) DO UPDATE SET deleted_at = null"). Preload("Address"). Where("address_id in (?)", addressesSubQuery). Find(&assetSubs). + Limit(len(addresses)). Error if err != nil { return nil, err @@ -37,23 +40,19 @@ func (i Instance) GetSubscribedAddressesForAssets(ctx context.Context, addresses func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Context) (map[string][]string, error) { db := apmgorm.WithContext(ctx, i.Gorm) - var dbAddresses []models.Address - err := db.Where("address in (?)", addresses).Find(&dbAddresses).Error - if err != nil { - return nil, err - } - - addressesIDs := make([]uint, 0, len(dbAddresses)) - for _, a := range dbAddresses { - addressesIDs = append(addressesIDs, a.ID) - } + addressesSubQuery := db.Table("addresses"). + Select("id"). + Where("address in (?)", addresses). + Limit(len(addresses)). + QueryExpr() var associations []models.AddressToAssetAssociation - err = db. + err := db. Preload("Address"). Preload("Asset"). - Where("address_id in (?)", addressesIDs). + Where("address_id in (?)", addressesSubQuery). Find(&associations). + Limit(len(addresses)). Error if err != nil { return nil, err @@ -70,24 +69,20 @@ func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Contex func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) (map[string][]string, error) { db := apmgorm.WithContext(ctx, i.Gorm) - var dbAddresses []models.Address - err := db.Where("address in (?)", addresses).Find(&dbAddresses).Error - if err != nil { - return nil, err - } - - addressesIDs := make([]uint, 0, len(dbAddresses)) - for _, a := range dbAddresses { - addressesIDs = append(addressesIDs, a.ID) - } + addressesSubQuery := db.Table("addresses"). + Select("id"). + Where("address in (?)", addresses). + Limit(len(addresses)). + QueryExpr() var associations []models.AddressToAssetAssociation - err = db. + err := db. Preload("Address"). Preload("Asset"). - Where("address_id in (?)", addressesIDs). - Where("updated_at > ?", from). + Where("address_id in (?)", addressesSubQuery). + Where("created_at > ?", from). Find(&associations). + Limit(len(addresses)). Error if err != nil { return nil, err @@ -107,6 +102,7 @@ func (i *Instance) GetAssociationsByAddresses(addresses []string, ctx context.Co addressesSubQuery := db.Table("addresses"). Select("id"). Where("address in (?)", addresses). + Limit(len(addresses)). QueryExpr() var result []models.AddressToAssetAssociation @@ -115,6 +111,7 @@ func (i *Instance) GetAssociationsByAddresses(addresses []string, ctx context.Co Preload("Asset"). Where("address_id in (?)", addressesSubQuery). Find(&result). + Limit(len(addresses)). Error return result, err } @@ -125,6 +122,7 @@ func (i *Instance) GetAssociationsByAddressesFromTime(addresses []string, from t addressesSubQuery := db.Table("addresses"). Select("id"). Where("address in (?)", addresses). + Limit(len(addresses)). QueryExpr() var result []models.AddressToAssetAssociation @@ -132,8 +130,9 @@ func (i *Instance) GetAssociationsByAddressesFromTime(addresses []string, from t Preload("Address"). Preload("Asset"). Where("address_id in (?)", addressesSubQuery). - Where("updated_at > ?", from). + Where("created_at > ?", from). Find(&result). + Limit(len(addresses)). Error return result, err } @@ -161,13 +160,16 @@ func (i *Instance) AddAssociationsForAddress(address string, assets []string, ct } dbAddress := models.Address{Address: address} - err = db.Where("address = ?", address).FirstOrCreate(&dbAddress).Error + err = db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"). + Where("address = ?", address). + FirstOrCreate(&dbAddress). + Error if err != nil { return err } assetsSub := models.AssetSubscription{AddressID: dbAddress.ID} - err = db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING").Create(&assetsSub).Error + err = db.Set("gorm:insert_option", "ON CONFLICT (address_id) DO UPDATE SET deleted_at = null").Create(&assetsSub).Error if err != nil { return err } @@ -206,7 +208,10 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin } var dbAssets []models.Asset - err = db.Where("asset_id in (?)", uniqueAssets).Find(&dbAssets).Error + err = db.Where("asset_id in (?)", uniqueAssets). + Find(&dbAssets). + Limit(len(uniqueAssets)). + Error if err != nil { return err } @@ -219,7 +224,10 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin } var dbAddresses []models.Address - if err := db.Where("address in (?)", addresses).Find(&dbAddresses).Error; err != nil { + if err := db.Where("address in (?)", addresses). + Find(&dbAddresses). + Limit(len(addresses)). + Error; err != nil { return err } @@ -229,7 +237,7 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin addressSubs = append(addressSubs, sub) } - err = BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), addressSubs) + err = BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT (address_id) DO UPDATE SET deleted_at = null"), addressSubs) if err != nil { return err } diff --git a/db/db.go b/db/db.go index dc56c920a..ce0ffcc95 100644 --- a/db/db.go +++ b/db/db.go @@ -16,9 +16,9 @@ type Instance struct { Gorm *gorm.DB } -const batchCount = 3000 +const batchCount = 1000 -func New(uri, env string) (*Instance, error) { +func New(uri, env string, mode bool) (*Instance, error) { var ( g *gorm.DB err error @@ -41,6 +41,17 @@ func New(uri, env string) (*Instance, error) { &models.AssetSubscription{}, &models.Address{}, ) + g.Table("address_to_asset_associations"). + AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT"). + AddForeignKey("asset_id", "assets(id)", "RESTRICT", "RESTRICT") + + g.Table("notification_subscriptions"). + AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT") + + g.Table("asset_subscriptions"). + AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT") + + g.LogMode(mode) i := &Instance{Gorm: g} diff --git a/db/models/address.go b/db/models/address.go index 85b211f17..01d6b02b8 100644 --- a/db/models/address.go +++ b/db/models/address.go @@ -1,8 +1,10 @@ package models -import "github.com/jinzhu/gorm" - type Address struct { - gorm.Model - Address string `gorm:"type:varchar(128); unique" sql:"index"` + ID uint `gorm:"primary_key"` + Address string `gorm:"unique_index; type:varchar(128)"` } + +// Use such model in future +// Coin uint `gorm:"index:idx_coin;" sql:"unique_index:idx_ca"` +// Address string `gorm:"index:idx_address; type:varchar(128)" sql:"unique_index:idx_ca"` diff --git a/db/models/addresstoasset.go b/db/models/addresstoasset.go index 034ddfeae..e03d74248 100644 --- a/db/models/addresstoasset.go +++ b/db/models/addresstoasset.go @@ -6,12 +6,11 @@ import ( type AddressToAssetAssociation struct { CreatedAt time.Time - UpdatedAt time.Time DeletedAt *time.Time `sql:"index"` Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `sql:"index"` + AddressID uint `gorm:"index:idx_address" sql:"unique_index:idx_aa"` Asset Asset `gorm:"ForeignKey:AssetID; not null"` - AssetID uint `sql:"index"` + AssetID uint `gorm:"index:idx_asset" sql:"unique_index:idx_aa"` } diff --git a/db/models/asset.go b/db/models/asset.go index 79441c4ba..067cdbb8d 100644 --- a/db/models/asset.go +++ b/db/models/asset.go @@ -1,8 +1,6 @@ package models -import "github.com/jinzhu/gorm" - type Asset struct { - gorm.Model + ID uint `gorm:"primary_key"` AssetID string `gorm:"type:varchar(128); unique_index"` } diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index 909df39a9..88fb84ba8 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -1,19 +1,17 @@ package models -import ( - "github.com/jinzhu/gorm" -) +import "time" type ( NotificationSubscription struct { - gorm.Model - Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"unique" sql:"index"` + DeletedAt *time.Time `sql:"index"` + Address Address `gorm:"ForeignKey:AddressID; not null"` + AddressID uint `gorm:"unique_index"` } AssetSubscription struct { - gorm.Model - Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"unique" sql:"index"` + DeletedAt *time.Time `sql:"index"` + Address Address `gorm:"ForeignKey:AddressID; not null"` + AddressID uint `gorm:"unique_index"` } ) diff --git a/db/notification.go b/db/notification.go index 9455c881c..a7c19310d 100644 --- a/db/notification.go +++ b/db/notification.go @@ -18,6 +18,7 @@ func (i *Instance) GetSubscriptionsForNotifications(addresses []string, ctx cont Table("addresses"). Select("id"). Where("address in (?)", addresses). + Limit(len(addresses)). QueryExpr() var subscriptionsDataList []models.NotificationSubscription @@ -25,6 +26,7 @@ func (i *Instance) GetSubscriptionsForNotifications(addresses []string, ctx cont Preload("Address"). Where("address_id in (?)", addressesSubQuery). Find(&subscriptionsDataList). + Limit(len(addresses)). Error if err != nil { return nil, err @@ -53,7 +55,10 @@ func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx cont } var dbAddresses []models.Address - err = db.Where("address in (?)", uniqueAddresses).Find(&dbAddresses).Error + err = db.Where("address in (?)", uniqueAddresses). + Find(&dbAddresses). + Limit(len(uniqueAddressesModel)). + Error if err != nil { return err } @@ -64,7 +69,7 @@ func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx cont AddressID: a.ID, }) } - return BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT (address_id) DO UPDATE SET deleted_at = null, updated_at = now()"), result) + return BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT (address_id) DO UPDATE SET deleted_at = null"), result) }) } @@ -77,10 +82,11 @@ func (i *Instance) DeleteSubscriptionsForNotifications(addresses []string, ctx c addressSubQuery := db.Table("addresses"). Select("id"). Where("address in (?)", addresses). + Limit(len(addresses)). QueryExpr() - return db. - Where("address_id in (?)", addressSubQuery). + return db.Where("address_id in (?)", addressSubQuery). Delete(&models.NotificationSubscription{}). + Limit(len(addresses)). Error } diff --git a/services/tokensearcher/api.go b/services/tokensearcher/api.go index cad07cdea..8eb57043f 100644 --- a/services/tokensearcher/api.go +++ b/services/tokensearcher/api.go @@ -8,6 +8,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" + "strconv" "sync" "time" ) @@ -38,8 +39,10 @@ func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (Ass if err != nil { return nil, err } + logger.Info("subscribedAddresses " + strconv.Itoa(len(subscribedAddresses))) unsubscribedAddresses := getUnsubscribedAddresses(subscribedAddresses, addresses) + logger.Info("unsubscribedAddresses " + strconv.Itoa(len(unsubscribedAddresses))) assetsFromDB, err := i.database.GetAssetsMapByAddressesFromTime( subscribedAddresses, time.Unix(int64(request.From), 0), @@ -48,6 +51,7 @@ func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (Ass return nil, err } + logger.Info("assetsFromDB " + strconv.Itoa(len(assetsFromDB))) assetsFromNodes := make(AssetsByAddress) if len(unsubscribedAddresses) != 0 { assetsFromNodes = getAssetsByAddressFromNodes(unsubscribedAddresses, i.apis) @@ -158,7 +162,9 @@ func fetchAssetsByAddresses(tokenAPI blockatlas.TokensAPI, addresses []string, r } func publishNewAddressesToQueue(queue mq.Queue, message AssetsByAddress) error { + logger.Info("Published to queue") body, err := json.Marshal(message) + logger.Info(string(body)) if err != nil { return err } diff --git a/services/tokensearcher/tokensearcher.go b/services/tokensearcher/tokensearcher.go index 29716ab87..555a42cee 100644 --- a/services/tokensearcher/tokensearcher.go +++ b/services/tokensearcher/tokensearcher.go @@ -39,8 +39,11 @@ func Run(database *db.Instance, delivery amqp.Delivery) { logger.Error(err) return } + logger.Info("associationsFromTransactions " + strconv.Itoa(len(associationsFromTransactions))) associationsToAdd := associationsToAdd(fromModelToAssociation(associationsFromTransactions), assetsMap(txs, coinID)) + + logger.Info("associationsToAdd " + strconv.Itoa(len(associationsToAdd))) err = database.UpdateAssociationsForExistingAddresses(associationsToAdd, ctx) if err != nil { logger.Error(err) diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go index c35cbef92..34f503da1 100644 --- a/tests/integration/db_test/subscriptions_test.go +++ b/tests/integration/db_test/subscriptions_test.go @@ -5,12 +5,10 @@ package db_test import ( "context" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/subscriber" "github.com/trustwallet/blockatlas/tests/integration/setup" "testing" - "time" ) func TestDb_AddSubscriptionsBulk(t *testing.T) { @@ -199,35 +197,3 @@ func TestDb_CreateDeleteCreate(t *testing.T) { assert.Nil(t, err) assert.Equal(t, 1, len(subs3)) } - -func TestDb_UpdatedAt(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - var subscriptions []blockatlas.Subscription - subscriptions = append(subscriptions, blockatlas.Subscription{ - Coin: 60, - Address: "testAddr", - }) - - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions), context.Background())) - subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) - assert.Nil(t, err) - assert.Equal(t, 1, len(subs)) - - var existingSub models.NotificationSubscription - var existingAddr models.Address - - assert.False(t, database.Gorm.Where("address = ?", "60_testAddr").First(&existingAddr).RecordNotFound()) - assert.False(t, database.Gorm.Where("address_id = ?", existingAddr.ID).First(&existingSub).RecordNotFound()) - assert.Greater(t, existingSub.UpdatedAt.Unix(), time.Now().Unix()-120) - - subscriptions = append(subscriptions, blockatlas.Subscription{ - Coin: 714, - Address: "newtestAddr", - }) - - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions), context.Background())) - - var existingSub2 models.NotificationSubscription - assert.False(t, database.Gorm.Where("address_id = ?", existingSub.ID).First(&existingSub2).RecordNotFound()) - assert.Greater(t, existingSub2.UpdatedAt.Unix(), time.Now().Unix()-120) -} diff --git a/tests/integration/db_test/tokenassociations_test.go b/tests/integration/db_test/tokenassociations_test.go index 39bd5c42d..2779cb8cc 100644 --- a/tests/integration/db_test/tokenassociations_test.go +++ b/tests/integration/db_test/tokenassociations_test.go @@ -111,7 +111,7 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { assert.Nil(t, err) assetsForA := []string{"aa", "bbb", "cccc"} - assetsForB := []string{"as", "bbb", "cccc"} + assetsForB := []string{"bbb", "cccc"} updateMap := make(map[string][]string) updateMap["A"] = assetsForA @@ -146,7 +146,7 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { for _, a := range associationsB { assetIDsFromDBB = append(assetIDsFromDBB, a.Asset.AssetID) } - assetsB := []string{"as", "bbb", "cccc", "f"} + assetsB := []string{"bbb", "cccc", "f"} sort.Slice(assetsB, func(i, j int) bool { return len(assetsB[i]) > len(assetsB[j]) @@ -165,7 +165,7 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { for _, a := range associationsAB { assetIDsFromDBAB = append(assetIDsFromDBAB, a.Asset.AssetID) } - assetsAB := []string{"cccc", "cccc", "bbb", "bbb", "aa", "as", "f", "f"} + assetsAB := []string{"cccc", "cccc", "bbb", "bbb", "aa", "f", "f"} sort.Slice(assetsAB, func(i, j int) bool { return len(assetsAB[i]) > len(assetsAB[j]) diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go index d300c16d8..f3248e426 100644 --- a/tests/integration/setup/postgres.go +++ b/tests/integration/setup/postgres.go @@ -42,13 +42,12 @@ func runPgContainerAndInitConnection() (*db.Instance, error) { err error ) if err := pool.Retry(func() error { - dbConn, err = db.New(uri, "test") + dbConn, err = db.New(uri, "test", false) return err }); err != nil { return nil, err } autoMigrate(dbConn.Gorm) - return dbConn, nil } From 977175911599e4e07f4f96de236275d1d74d5bfe Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 3 Sep 2020 03:50:49 +0300 Subject: [PATCH 373/506] [DB] Add pg read connection (#1216) * Add pg read option * Update tests * Fixes to models * Fixes to models * Fixes to models * Fixes to queue --- cmd/api/main.go | 3 ++- cmd/notifier/main.go | 3 ++- cmd/parser/main.go | 6 +++-- cmd/searcher/main.go | 11 ++++----- cmd/subscriber/main.go | 3 ++- config.yml | 5 ++-- configmock.yml | 2 ++ db/addresstoasset.go | 24 +++++++++---------- db/db.go | 19 ++++++++++++--- db/models/address.go | 2 +- db/models/addresstoasset.go | 6 ++--- db/models/asset.go | 4 ++-- db/models/subscriptions.go | 4 ++-- db/notification.go | 2 +- db/tracker.go | 2 +- db/tracker_test.go | 4 ++-- mq/mq.go | 9 +++---- services/subscriber/tokens.go | 2 +- services/tokensearcher/association.go | 2 +- services/tokensearcher/association_test.go | 12 +++++----- .../db_test/tokenassociations_test.go | 8 +++---- tests/integration/setup/postgres.go | 12 +++++++++- 22 files changed, 87 insertions(+), 58 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index 3003aa96a..3af1d976d 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -41,9 +41,10 @@ func init() { if restAPI == "tokens" || restAPI == "all" { pgUri := viper.GetString("postgres.uri") + pgReadUri := viper.GetString("postgres.read_uri") var err error - database, err = db.New(pgUri, prod, logMode) + database, err = db.New(pgUri, pgReadUri, prod, logMode) if err != nil { logger.Fatal(err) } diff --git a/cmd/notifier/main.go b/cmd/notifier/main.go index 068a19baf..0193446b9 100644 --- a/cmd/notifier/main.go +++ b/cmd/notifier/main.go @@ -32,6 +32,7 @@ func init() { prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") pgUri := viper.GetString("postgres.uri") + pgReadUri := viper.GetString("postgres.read_uri") internal.InitRabbitMQ(mqHost, prefetchCount) @@ -44,7 +45,7 @@ func init() { } var err error - database, err = db.New(pgUri, prod, logMode) + database, err = db.New(pgUri, pgReadUri, prod, logMode) if err != nil { logger.Fatal(err) } diff --git a/cmd/parser/main.go b/cmd/parser/main.go index d7e0fb2bd..48f2949f1 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -52,6 +52,8 @@ func init() { } pgUri := viper.GetString("postgres.uri") + pgReadUri := viper.GetString("postgres.read_uri") + logMode := viper.GetBool("postgres.log") txsBatchLimit = viper.GetUint("observer.txs_batch_limit") @@ -64,7 +66,7 @@ func init() { logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") } var err error - database, err = db.New(pgUri, prod, logMode) + database, err = db.New(pgUri, pgReadUri, prod, logMode) if err != nil { logger.Fatal(err) } @@ -108,7 +110,7 @@ func main() { params := parser.Params{ Ctx: ctx, Api: api, - Queue: []mq.Queue{mq.RawTransactions, mq.TokensRegistration}, + Queue: []mq.Queue{mq.RawTransactions, mq.RawTransactionsSearcher}, ParsingBlocksInterval: pollInterval, FetchBlocksTimeout: fetchBlocksInterval, BacklogCount: backlogCount, diff --git a/cmd/searcher/main.go b/cmd/searcher/main.go index 02e1ad84a..dc0e0b075 100644 --- a/cmd/searcher/main.go +++ b/cmd/searcher/main.go @@ -32,19 +32,16 @@ func init() { prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") pgUri := viper.GetString("postgres.uri") + pgReadUri := viper.GetString("postgres.read_uri") logMode := viper.GetBool("postgres.log") internal.InitRabbitMQ(mqHost, prefetchCount) - if err := mq.RawTransactions.Declare(); err != nil { - logger.Fatal(err) - } - - if err := mq.TxNotifications.Declare(); err != nil { + if err := mq.RawTransactionsSearcher.Declare(); err != nil { logger.Fatal(err) } var err error - database, err = db.New(pgUri, prod, logMode) + database, err = db.New(pgUri, pgReadUri, prod, logMode) if err != nil { logger.Fatal(err) } @@ -68,7 +65,7 @@ func main() { ctx, cancel := context.WithCancel(context.Background()) - go mq.TokensRegistration.RunConsumerWithCancelAndDbConn(tokensearcher.Run, database, ctx) + go mq.RawTransactionsSearcher.RunConsumerWithCancelAndDbConn(tokensearcher.Run, database, ctx) internal.SetupGracefulShutdownForObserver(cancel) } diff --git a/cmd/subscriber/main.go b/cmd/subscriber/main.go index 69240f128..162e00cdd 100644 --- a/cmd/subscriber/main.go +++ b/cmd/subscriber/main.go @@ -29,6 +29,7 @@ func init() { logger.InitLogger() pgUri := viper.GetString("postgres.uri") + pgReadUri := viper.GetString("postgres.read_uri") logMode := viper.GetBool("postgres.log") mqHost := viper.GetString("observer.rabbitmq.uri") @@ -37,7 +38,7 @@ func init() { internal.InitRabbitMQ(mqHost, prefetchCount) var err error - database, err = db.New(pgUri, prod, logMode) + database, err = db.New(pgUri, pgReadUri, prod, logMode) if err != nil { logger.Fatal(err) } diff --git a/config.yml b/config.yml index 36ca64634..9d56d5d6e 100644 --- a/config.yml +++ b/config.yml @@ -9,7 +9,7 @@ gin: # If all - run all platforms in one binary. You can pick specific coin handle to run binary only with specific coin # Example: ethereum # You can see all the coin handles at coins/coins.yml file -platform: [all] +platform: [ all ] # Can be platform or swagger, or tokens, or all rest_api: all @@ -40,6 +40,7 @@ observer: postgres: uri: postgresql://user:pass@localhost/my_db?sslmode=disable + read_uri: postgresql://user:pass@localhost/my_db?sslmode=disable log: false # [BNB] Binance DEX: https://www.binance.org/ @@ -230,6 +231,6 @@ near: elrond: api: https://api.elrond.com -# bsc: + # bsc: # api: # rpc: diff --git a/configmock.yml b/configmock.yml index db7167871..6f68db7b0 100644 --- a/configmock.yml +++ b/configmock.yml @@ -34,6 +34,8 @@ observer: postgres: uri: postgresql://user:pass@localhost/my_db?sslmode=disable + read_uri: postgresql://user:pass@localhost/my_db?sslmode=disable + log: false # [BNB] Binance DEX: https://wallet.binance.org # Binance Chain: https://explorer.binance.org diff --git a/db/addresstoasset.go b/db/addresstoasset.go index d2933c743..6a7300315 100644 --- a/db/addresstoasset.go +++ b/db/addresstoasset.go @@ -9,7 +9,7 @@ import ( ) func (i Instance) GetSubscribedAddressesForAssets(ctx context.Context, addresses []string) ([]models.Address, error) { - db := apmgorm.WithContext(ctx, i.Gorm) + db := apmgorm.WithContext(ctx, i.GormRead) addressesSubQuery := db. Table("addresses"). @@ -38,7 +38,7 @@ func (i Instance) GetSubscribedAddressesForAssets(ctx context.Context, addresses } func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Context) (map[string][]string, error) { - db := apmgorm.WithContext(ctx, i.Gorm) + db := apmgorm.WithContext(ctx, i.GormRead) addressesSubQuery := db.Table("addresses"). Select("id"). @@ -61,13 +61,13 @@ func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Contex result := make(map[string][]string) for _, a := range associations { assets := result[a.Address.Address] - result[a.Address.Address] = append(assets, a.Asset.AssetID) + result[a.Address.Address] = append(assets, a.Asset.Asset) } return result, nil } func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) (map[string][]string, error) { - db := apmgorm.WithContext(ctx, i.Gorm) + db := apmgorm.WithContext(ctx, i.GormRead) addressesSubQuery := db.Table("addresses"). Select("id"). @@ -91,13 +91,13 @@ func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time. result := make(map[string][]string) for _, a := range associations { assets := result[a.Address.Address] - result[a.Address.Address] = append(assets, a.Asset.AssetID) + result[a.Address.Address] = append(assets, a.Asset.Asset) } return result, nil } func (i *Instance) GetAssociationsByAddresses(addresses []string, ctx context.Context) ([]models.AddressToAssetAssociation, error) { - db := apmgorm.WithContext(ctx, i.Gorm) + db := apmgorm.WithContext(ctx, i.GormRead) addressesSubQuery := db.Table("addresses"). Select("id"). @@ -117,7 +117,7 @@ func (i *Instance) GetAssociationsByAddresses(addresses []string, ctx context.Co } func (i *Instance) GetAssociationsByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) ([]models.AddressToAssetAssociation, error) { - db := apmgorm.WithContext(ctx, i.Gorm) + db := apmgorm.WithContext(ctx, i.GormRead) addressesSubQuery := db.Table("addresses"). Select("id"). @@ -144,7 +144,7 @@ func (i *Instance) AddAssociationsForAddress(address string, assets []string, ct uniqueAssetsModel := make([]models.Asset, 0, len(uniqueAssets)) for _, l := range uniqueAssets { uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{ - AssetID: l, + Asset: l, }) } @@ -154,7 +154,7 @@ func (i *Instance) AddAssociationsForAddress(address string, assets []string, ct } var dbAssets []models.Asset - err = db.Where("asset_id in (?)", uniqueAssets).Find(&dbAssets).Error + err = db.Where("asset in (?)", uniqueAssets).Find(&dbAssets).Error if err != nil { return err } @@ -198,7 +198,7 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin uniqueAssetsModel := make([]models.Asset, 0, len(uniqueAssets)) for _, l := range uniqueAssets { uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{ - AssetID: l, + Asset: l, }) } @@ -208,7 +208,7 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin } var dbAssets []models.Asset - err = db.Where("asset_id in (?)", uniqueAssets). + err = db.Where("asset in (?)", uniqueAssets). Find(&dbAssets). Limit(len(uniqueAssets)). Error @@ -261,7 +261,7 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin func makeMapAssets(addresses []models.Asset) map[string]uint { result := make(map[string]uint) for _, a := range addresses { - result[a.AssetID] = a.ID + result[a.Asset] = a.ID } return result } diff --git a/db/db.go b/db/db.go index ce0ffcc95..f6c6fe36e 100644 --- a/db/db.go +++ b/db/db.go @@ -13,14 +13,16 @@ import ( ) type Instance struct { - Gorm *gorm.DB + Gorm *gorm.DB + GormRead *gorm.DB } const batchCount = 1000 -func New(uri, env string, mode bool) (*Instance, error) { +func New(uri, readURI, env string, mode bool) (*Instance, error) { var ( g *gorm.DB + rg *gorm.DB err error ) if env == "prod" { @@ -33,6 +35,16 @@ func New(uri, env string, mode bool) (*Instance, error) { return nil, err } + if env == "prod" { + rg, err = apmgorm.Open("postgres", readURI) + } else { + rg, err = gorm.Open("postgres", readURI) + } + + if err != nil { + return nil, err + } + g.AutoMigrate( &models.NotificationSubscription{}, &models.Tracker{}, @@ -52,8 +64,9 @@ func New(uri, env string, mode bool) (*Instance, error) { AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT") g.LogMode(mode) + rg.LogMode(mode) - i := &Instance{Gorm: g} + i := &Instance{Gorm: g, GormRead: rg} return i, nil } diff --git a/db/models/address.go b/db/models/address.go index 01d6b02b8..3f6fa08fc 100644 --- a/db/models/address.go +++ b/db/models/address.go @@ -2,7 +2,7 @@ package models type Address struct { ID uint `gorm:"primary_key"` - Address string `gorm:"unique_index; type:varchar(128)"` + Address string `gorm:"type:varchar(128); unique_index"` } // Use such model in future diff --git a/db/models/addresstoasset.go b/db/models/addresstoasset.go index e03d74248..2d27a5031 100644 --- a/db/models/addresstoasset.go +++ b/db/models/addresstoasset.go @@ -5,12 +5,12 @@ import ( ) type AddressToAssetAssociation struct { - CreatedAt time.Time + CreatedAt time.Time `sql:"index"` DeletedAt *time.Time `sql:"index"` Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"index:idx_address" sql:"unique_index:idx_aa"` + AddressID uint `gorm:"primary_key; auto_increment:false" sql:"index"` Asset Asset `gorm:"ForeignKey:AssetID; not null"` - AssetID uint `gorm:"index:idx_asset" sql:"unique_index:idx_aa"` + AssetID uint `gorm:"primary_key; auto_increment:false" sql:"index"` } diff --git a/db/models/asset.go b/db/models/asset.go index 067cdbb8d..d91d8d90c 100644 --- a/db/models/asset.go +++ b/db/models/asset.go @@ -1,6 +1,6 @@ package models type Asset struct { - ID uint `gorm:"primary_key"` - AssetID string `gorm:"type:varchar(128); unique_index"` + ID uint `gorm:"primary_key"` + Asset string `gorm:"type:varchar(128); unique_index"` } diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index 88fb84ba8..10d4734f3 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -6,12 +6,12 @@ type ( NotificationSubscription struct { DeletedAt *time.Time `sql:"index"` Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"unique_index"` + AddressID uint `gorm:"primary_key; auto_increment:false"` } AssetSubscription struct { DeletedAt *time.Time `sql:"index"` Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"unique_index"` + AddressID uint `gorm:"primary_key; auto_increment:false"` } ) diff --git a/db/notification.go b/db/notification.go index a7c19310d..8ecc9be71 100644 --- a/db/notification.go +++ b/db/notification.go @@ -12,7 +12,7 @@ func (i *Instance) GetSubscriptionsForNotifications(addresses []string, ctx cont if len(addresses) == 0 { return nil, errors.E("Empty addresses") } - db := apmgorm.WithContext(ctx, i.Gorm) + db := apmgorm.WithContext(ctx, i.GormRead) addressesSubQuery := db. Table("addresses"). diff --git a/db/tracker.go b/db/tracker.go index 04f54d264..f6bf74d1c 100644 --- a/db/tracker.go +++ b/db/tracker.go @@ -37,7 +37,7 @@ func (i *Instance) GetLastParsedBlockNumber(coin string, ctx context.Context) (i return height, nil } var tracker models.Tracker - g := apmgorm.WithContext(ctx, i.Gorm) + g := apmgorm.WithContext(ctx, i.GormRead) if err := g.Where(models.Tracker{Coin: coin}).Find(&tracker).Error; err != nil { return 0, nil } diff --git a/db/tracker_test.go b/db/tracker_test.go index fc7984c9a..c98530664 100644 --- a/db/tracker_test.go +++ b/db/tracker_test.go @@ -18,7 +18,7 @@ func TestHeightBlockMap_SetHeight(t *testing.T) { `INSERT INTO "trackers" ("updated_at","coin","height") VALUES ($1,$2,$3) ON CONFLICT (coin) DO UPDATE SET height = excluded.height, updated_at = excluded.updated_at RETURNING "trackers"."coin"`)).WithArgs(sqlmock.AnyArg(), "bitcoin", 1).WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow("id")) mock.ExpectCommit() - i := Instance{Gorm: db} + i := Instance{Gorm: db, GormRead: db} assert.Nil(t, i.SetLastParsedBlockNumber("bitcoin", 1, context.Background())) } @@ -32,7 +32,7 @@ func TestHeightBlockMap_GetHeight(t *testing.T) { `INSERT INTO "trackers" ("updated_at","coin","height") VALUES ($1,$2,$3) ON CONFLICT (coin) DO UPDATE SET height = excluded.height, updated_at = excluded.updated_at RETURNING "trackers"."coin"`)).WithArgs(sqlmock.AnyArg(), "bitcoin", 1).WillReturnRows(sqlmock.NewRows([]string{"id"}). AddRow("id")) mock.ExpectCommit() - i := Instance{Gorm: db} + i := Instance{Gorm: db, GormRead: db} assert.Nil(t, i.SetLastParsedBlockNumber("bitcoin", 1, context.Background())) block, err := i.GetLastParsedBlockNumber("bitcoin", context.Background()) diff --git a/mq/mq.go b/mq/mq.go index 431ed8c87..aecb96fba 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -22,10 +22,11 @@ type ( ) const ( - TxNotifications Queue = "txNotifications" - Subscriptions Queue = "subscriptions" - RawTransactions Queue = "rawTransactions" - TokensRegistration Queue = "tokensRegistration" + TxNotifications Queue = "txNotifications" + Subscriptions Queue = "subscriptions" + RawTransactions Queue = "rawTransactions" + RawTransactionsSearcher Queue = "rawTransactionsSearcher" + TokensRegistration Queue = "tokensRegistration" ) func Init(uri string) (err error) { diff --git a/services/subscriber/tokens.go b/services/subscriber/tokens.go index 80ffe7847..825d2b30f 100644 --- a/services/subscriber/tokens.go +++ b/services/subscriber/tokens.go @@ -17,7 +17,7 @@ func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { defer tx.End() ctx := apm.ContextWithTransaction(context.Background(), tx) - + logger.Info("body " + string(delivery.Body)) event := make(map[string][]string) if err := json.Unmarshal(delivery.Body, &event); err != nil { if err := delivery.Ack(false); err != nil { diff --git a/services/tokensearcher/association.go b/services/tokensearcher/association.go index 948c14630..220270980 100644 --- a/services/tokensearcher/association.go +++ b/services/tokensearcher/association.go @@ -56,7 +56,7 @@ func fromModelToAssociation(associations []models.AddressToAssetAssociation) map result := make(map[string][]string) for _, a := range associations { m := result[a.Address.Address] - result[a.Address.Address] = append(m, a.Asset.AssetID) + result[a.Address.Address] = append(m, a.Asset.Asset) } return result } diff --git a/services/tokensearcher/association_test.go b/services/tokensearcher/association_test.go index b861b67ff..2013d545a 100644 --- a/services/tokensearcher/association_test.go +++ b/services/tokensearcher/association_test.go @@ -86,12 +86,12 @@ func Test_newAssociationsForAddress(t *testing.T) { func Test_fromModelToAssociation(t *testing.T) { a := []models.AddressToAssetAssociation{ - {Address: models.Address{Address: "A"}, Asset: models.Asset{AssetID: "1"}}, - {Address: models.Address{Address: "A"}, Asset: models.Asset{AssetID: "2"}}, - {Address: models.Address{Address: "A"}, Asset: models.Asset{AssetID: "3"}}, - {Address: models.Address{Address: "B"}, Asset: models.Asset{AssetID: "2"}}, - {Address: models.Address{Address: "B"}, Asset: models.Asset{AssetID: "3"}}, - {Address: models.Address{Address: "B"}, Asset: models.Asset{AssetID: "4"}}, + {Address: models.Address{Address: "A"}, Asset: models.Asset{Asset: "1"}}, + {Address: models.Address{Address: "A"}, Asset: models.Asset{Asset: "2"}}, + {Address: models.Address{Address: "A"}, Asset: models.Asset{Asset: "3"}}, + {Address: models.Address{Address: "B"}, Asset: models.Asset{Asset: "2"}}, + {Address: models.Address{Address: "B"}, Asset: models.Asset{Asset: "3"}}, + {Address: models.Address{Address: "B"}, Asset: models.Asset{Asset: "4"}}, } result := fromModelToAssociation(a) diff --git a/tests/integration/db_test/tokenassociations_test.go b/tests/integration/db_test/tokenassociations_test.go index 2779cb8cc..2547a92f3 100644 --- a/tests/integration/db_test/tokenassociations_test.go +++ b/tests/integration/db_test/tokenassociations_test.go @@ -79,7 +79,7 @@ func Test_AddNewAssociationForAddress(t *testing.T) { var assetIDsFromDB []string for _, a := range associations { - assetIDsFromDB = append(assetIDsFromDB, a.Asset.AssetID) + assetIDsFromDB = append(assetIDsFromDB, a.Asset.Asset) } sort.Slice(assets, func(i, j int) bool { @@ -125,7 +125,7 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { var assetIDsFromDBA []string for _, a := range associationsA { - assetIDsFromDBA = append(assetIDsFromDBA, a.Asset.AssetID) + assetIDsFromDBA = append(assetIDsFromDBA, a.Asset.Asset) } assetsA := []string{"aa", "bbb", "cccc", "f"} @@ -144,7 +144,7 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { var assetIDsFromDBB []string for _, a := range associationsB { - assetIDsFromDBB = append(assetIDsFromDBB, a.Asset.AssetID) + assetIDsFromDBB = append(assetIDsFromDBB, a.Asset.Asset) } assetsB := []string{"bbb", "cccc", "f"} @@ -163,7 +163,7 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { var assetIDsFromDBAB []string for _, a := range associationsAB { - assetIDsFromDBAB = append(assetIDsFromDBAB, a.Asset.AssetID) + assetIDsFromDBAB = append(assetIDsFromDBAB, a.Asset.Asset) } assetsAB := []string{"cccc", "cccc", "bbb", "bbb", "aa", "f", "f"} diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go index f3248e426..f5e38ba1c 100644 --- a/tests/integration/setup/postgres.go +++ b/tests/integration/setup/postgres.go @@ -42,11 +42,21 @@ func runPgContainerAndInitConnection() (*db.Instance, error) { err error ) if err := pool.Retry(func() error { - dbConn, err = db.New(uri, "test", false) + dbConn, err = db.New(uri, uri, "test", false) return err }); err != nil { return nil, err } + dbConn.Gorm.Table("address_to_asset_associations"). + AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT"). + AddForeignKey("asset_id", "assets(id)", "RESTRICT", "RESTRICT") + + dbConn.Gorm.Table("notification_subscriptions"). + AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT") + + dbConn.Gorm.Table("asset_subscriptions"). + AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT") + autoMigrate(dbConn.Gorm) return dbConn, nil } From c5b1b1d8cade3937b169fa04557c3e89a7a1f08a Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Wed, 2 Sep 2020 18:08:09 -0700 Subject: [PATCH 374/506] Add BEP20 support (#1213) * Add BEP20 support * Rename GetEthereumTokenTypeByIndex function * Add TestGetEthereumTokenTypeByIndex * Default to ERC20 name * Update token_test.go Co-authored-by: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> --- pkg/blockatlas/tx.go | 26 +++++++++++++++ pkg/blockatlas/tx_test.go | 40 ++++++++++++++++++++++++ platform/ethereum/blockbook/token.go | 3 +- platform/ethereum/trustray/token.go | 26 +-------------- platform/ethereum/trustray/token_test.go | 4 +-- 5 files changed, 70 insertions(+), 29 deletions(-) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 02b83d836..f8ab42e9b 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -19,6 +19,7 @@ const ( TokenTypeERC20 TokenType = "ERC20" TokenTypeBEP2 TokenType = "BEP2" TokenTypeBEP8 TokenType = "BEP8" + TokenTypeBEP20 TokenType = "BEP20" TokenTypeTRC10 TokenType = "TRC10" TokenTypeETC20 TokenType = "ETC20" TokenTypePOA20 TokenType = "POA20" @@ -375,3 +376,28 @@ func InferValue(tx *Tx, direction Direction, addressSet mapset.Set) Amount { } return value } + +func GetEthereumTokenTypeByIndex(coinIndex uint) TokenType { + var tokenType TokenType + switch coinIndex { + case coin.Ethereum().ID: + tokenType = TokenTypeERC20 + case coin.Classic().ID: + tokenType = TokenTypeETC20 + case coin.Poa().ID: + tokenType = TokenTypePOA20 + case coin.Callisto().ID: + tokenType = TokenTypeCLO20 + case coin.Wanchain().ID: + tokenType = TokenTypeWAN20 + case coin.Thundertoken().ID: + tokenType = TokenTypeTT20 + case coin.Gochain().ID: + tokenType = TokenTypeGO20 + case coin.Bsc().ID: + tokenType = TokenTypeBEP20 + default: + tokenType = TokenTypeERC20 + } + return tokenType +} diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 5b7db6e32..738d4ec64 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -565,3 +565,43 @@ func TestTx_TokenID(t *testing.T) { assert.True(t, ok3) } + +func TestGetEthereumTokenTypeByIndex(t *testing.T) { + type args struct { + coinIndex uint + } + tests := []struct { + name string + args args + want TokenType + }{ + { + "Ethereum", + args{ + coinIndex: coin.Ethereum().ID, + }, + TokenTypeERC20, + }, + { + "Smart Chain", + args{ + coinIndex: coin.Bsc().ID, + }, + TokenTypeBEP20, + }, + { + "Default Name", + args{ + coinIndex: coin.Bitcoin().ID, + }, + TokenTypeERC20, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetEthereumTokenTypeByIndex(tt.args.coinIndex); got != tt.want { + t.Errorf("GetEthereumTokenTypeByIndex() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/platform/ethereum/blockbook/token.go b/platform/ethereum/blockbook/token.go index 2e8e2b03e..a99ff339f 100644 --- a/platform/ethereum/blockbook/token.go +++ b/platform/ethereum/blockbook/token.go @@ -2,7 +2,6 @@ package blockbook import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/platform/ethereum/trustray" ) func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) { @@ -32,6 +31,6 @@ func NormalizeToken(srcToken *Token, coinIndex uint) blockatlas.Token { TokenID: srcToken.Contract, Coin: coinIndex, Decimals: srcToken.Decimals, - Type: trustray.GetTokenTypeByIndex(coinIndex), + Type: blockatlas.GetEthereumTokenTypeByIndex(coinIndex), } } diff --git a/platform/ethereum/trustray/token.go b/platform/ethereum/trustray/token.go index fe68a920e..8ce8d4165 100644 --- a/platform/ethereum/trustray/token.go +++ b/platform/ethereum/trustray/token.go @@ -1,7 +1,6 @@ package trustray import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -13,32 +12,9 @@ func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenP return NormalizeTokens(account.Docs, coinIndex), nil } -func GetTokenTypeByIndex(coinIndex uint) blockatlas.TokenType { - var tokenType blockatlas.TokenType - switch coinIndex { - case coin.Ethereum().ID: - tokenType = blockatlas.TokenTypeERC20 - case coin.Classic().ID: - tokenType = blockatlas.TokenTypeETC20 - case coin.Poa().ID: - tokenType = blockatlas.TokenTypePOA20 - case coin.Callisto().ID: - tokenType = blockatlas.TokenTypeCLO20 - case coin.Wanchain().ID: - tokenType = blockatlas.TokenTypeWAN20 - case coin.Thundertoken().ID: - tokenType = blockatlas.TokenTypeTT20 - case coin.Gochain().ID: - tokenType = blockatlas.TokenTypeGO20 - default: - tokenType = "unknown" - } - return tokenType -} - // NormalizeToken converts a Ethereum token into the generic model func NormalizeToken(srcToken *Contract, coinIndex uint) blockatlas.Token { - tokenType := GetTokenTypeByIndex(coinIndex) + tokenType := blockatlas.GetEthereumTokenTypeByIndex(coinIndex) return blockatlas.Token{ Name: srcToken.Name, diff --git a/platform/ethereum/trustray/token_test.go b/platform/ethereum/trustray/token_test.go index c2d134175..e7c7acc5c 100644 --- a/platform/ethereum/trustray/token_test.go +++ b/platform/ethereum/trustray/token_test.go @@ -115,7 +115,7 @@ func TestNormalizeToken(t *testing.T) { Type: blockatlas.TokenTypeCLO20, }, }, - {"unkown", + {"unknown", tokenSrc, 1999, blockatlas.Token{ @@ -124,7 +124,7 @@ func TestNormalizeToken(t *testing.T) { Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: 1999, - Type: "unknown", + Type: blockatlas.TokenTypeERC20, }, }, } From 250f14c0b3489ba9735363064297101ac777bdf9 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Fri, 4 Sep 2020 03:06:40 -0700 Subject: [PATCH 375/506] Add tomochain handle for GetEthereumTokenTypeByIndex (#1220) --- pkg/blockatlas/tx.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index f8ab42e9b..c12509ad6 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -394,6 +394,8 @@ func GetEthereumTokenTypeByIndex(coinIndex uint) TokenType { tokenType = TokenTypeTT20 case coin.Gochain().ID: tokenType = TokenTypeGO20 + case coin.Tomochain().ID: + tokenType = TokenTypeTRC20 case coin.Bsc().ID: tokenType = TokenTypeBEP20 default: From 8ddeccda67cccdb7053ba232e8bf4377257e4c87 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sat, 5 Sep 2020 02:58:35 -0700 Subject: [PATCH 376/506] Run go mod tidy (#1217) Co-authored-by: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> --- go.sum | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/go.sum b/go.sum index 05df30e37..f93503ff0 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,6 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= -github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= @@ -45,7 +43,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.13.1/go.mod h1:0UIBNuf97uxrWhdVBpJvPtafKyGpL2NS2pYe0tYM97k= github.com/alicebob/miniredis/v2 v2.13.2/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -169,7 +166,6 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-redis/redis v6.15.3-0.20190424063336-97e6ed817821+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -199,7 +195,6 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomodule/redigo v1.8.1/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -253,9 +248,6 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= -github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= -github.com/jinzhu/gorm v1.9.15 h1:OdR1qFvtXktlxk73XFYMiYn9ywzTwytqe4QkuMRqc38= -github.com/jinzhu/gorm v1.9.15/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -311,6 +303,7 @@ github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= +github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 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= @@ -322,7 +315,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -331,7 +323,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -371,7 +362,6 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -383,7 +373,6 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -392,7 +381,6 @@ github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -431,8 +419,6 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6 github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5NYJe/zRYDwOu9ku6YHy+Iw7l5DM= @@ -444,7 +430,6 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= @@ -453,19 +438,14 @@ github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuI github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= -github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/t-tiger/gorm-bulk-insert v1.3.0 h1:9k7BaVEhw/3fsvh6GTOBwJ2RXk3asc5xs5m6hwozq20= github.com/t-tiger/gorm-bulk-insert v1.3.0/go.mod h1:ruDlk8xDl+8sX4bA7PQuYly9YEb3pbp1eP2LCyeRrFY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/blockatlas v1.1.3-0.20200518232337-7495506f457c/go.mod h1:5Ev/iawD12+qgmtMkGgjYCKmGLF724YaxYfEbfY8lKc= github.com/trustwallet/blockatlas v1.1.7-0.20200831100332-b573ace18512/go.mod h1:rq6APqrT+vR58h+WWrCyadT80QDKmDEJvHDllWSUwnM= -github.com/trustwallet/ens-coincodec v1.0.5/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= github.com/trustwallet/ens-coincodec v1.0.6 h1:ZPvFDJwvv4s+XCnUM7pzub8wYHy37tyJBNtKvgx9FDs= github.com/trustwallet/ens-coincodec v1.0.6/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= -github.com/trustwallet/watchmarket v1.1.0 h1:tD+dlnKRONYr2ljsirM0Gx90ahzlfL1ceNSJlpTxINQ= -github.com/trustwallet/watchmarket v1.1.0/go.mod h1:VKVAqqClA5Oc6jaJvNorvn9wRnp9BKV04jVbjTGx0Zw= github.com/trustwallet/watchmarket v1.1.1 h1:gErSfLLDhEblFqvW8V3RyzRqq4R6MCYEDWjO6j5uJfE= github.com/trustwallet/watchmarket v1.1.1/go.mod h1:DvqzLzxXOaZajbkryVZcNgBS4yibZhk3rCc41ZSJEBs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -477,7 +457,6 @@ github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2t github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= @@ -610,8 +589,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 8aaf355e46b2c94587da250995c5629bbf891c33 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 10 Sep 2020 01:51:49 +0300 Subject: [PATCH 377/506] [COINS] Change BSC ID (#1221) * Change BSC ID * Add smartchain handle * Add smart chain initializer * Update platform.go * Add BEP20 for smartchain Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> --- coin/coins.go | 23 +++++++++++++++++++---- coin/coins.yml | 13 +++++++++++-- pkg/blockatlas/tx.go | 2 +- pkg/blockatlas/tx_test.go | 2 +- platform/platform.go | 3 ++- 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/coin/coins.go b/coin/coins.go index 98cfe5134..384a4bcca 100644 --- a/coin/coins.go +++ b/coin/coins.go @@ -1,6 +1,6 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots at -// 2020-08-29 17:30:10.735834 +0800 CST m=+0.001454710 +// 2020-09-09 14:29:27.707466 -0700 PDT m=+0.001959780 // using data from coins.yml package coin @@ -76,7 +76,8 @@ const ( SOL = 501 NEAR = 397 ERD = 508 - BSC = 10000714 + BSCLegacy = 10000714 + BSC = 20000714 ) var Coins = map[uint]Coin{ @@ -580,16 +581,27 @@ var Coins = map[uint]Coin{ MinConfirmations: 0, SampleAddr: "erd12tqtt5zcg6vpw65y4hkanvt49kzq695sr3ctuszjy92xw0ppzcssy2xd5r", }, - BSC: { + BSCLegacy: { ID: 10000714, Handle: "bsc", Symbol: "BNB", + PreferedSymbol: "BSCLegacy", + Name: "Binance Smart Chain", + Decimals: 18, + BlockTime: 3000, + MinConfirmations: 0, + SampleAddr: "0x35552c16704d214347f29Fa77f77DA6d75d7C752", + }, + BSC: { + ID: 20000714, + Handle: "smartchain", + Symbol: "BNB", PreferedSymbol: "BSC", Name: "Binance Smart Chain", Decimals: 18, BlockTime: 3000, MinConfirmations: 0, - SampleAddr: "0x3efb67b34a9b69b54d4027e044954f483dc31678", + SampleAddr: "0x35552c16704d214347f29Fa77f77DA6d75d7C752", }, } func Ethereum() Coin { @@ -743,6 +755,9 @@ func Elrond() Coin { return Coins[ERD] } func Bsc() Coin { + return Coins[BSCLegacy] +} +func Smartchain() Coin { return Coins[BSC] } diff --git a/coin/coins.yml b/coin/coins.yml index 619b48df1..f8bc3c880 100644 --- a/coin/coins.yml +++ b/coin/coins.yml @@ -399,9 +399,18 @@ - id: 10000714 symbol: BNB - preferedSymbol: BSC + preferedSymbol: BSCLegacy handle: bsc name: 'Binance Smart Chain' decimals: 18 blockTime: 3000 - sampleAddress: '0x3efb67b34a9b69b54d4027e044954f483dc31678' + sampleAddress: '0x35552c16704d214347f29Fa77f77DA6d75d7C752' + +- id: 20000714 + symbol: BNB + preferedSymbol: BSC + handle: smartchain + name: 'Binance Smart Chain' + decimals: 18 + blockTime: 3000 + sampleAddress: '0x35552c16704d214347f29Fa77f77DA6d75d7C752' diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index c12509ad6..675cc3221 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -396,7 +396,7 @@ func GetEthereumTokenTypeByIndex(coinIndex uint) TokenType { tokenType = TokenTypeGO20 case coin.Tomochain().ID: tokenType = TokenTypeTRC20 - case coin.Bsc().ID: + case coin.Bsc().ID, coin.Smartchain().ID: tokenType = TokenTypeBEP20 default: tokenType = TokenTypeERC20 diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 738d4ec64..457953f0e 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -585,7 +585,7 @@ func TestGetEthereumTokenTypeByIndex(t *testing.T) { { "Smart Chain", args{ - coinIndex: coin.Bsc().ID, + coinIndex: coin.Smartchain().ID, }, TokenTypeBEP20, }, diff --git a/platform/platform.go b/platform/platform.go index 064fbb1d5..23379c365 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -108,7 +108,8 @@ func getAllHandlers() blockatlas.Platforms { coin.Callisto().Handle: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO)), coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN)), coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), - coin.Bsc().Handle: ethereum.InitWithBlockbook(coin.BSC, GetApiVar(coin.BSC), GetRpcVar(coin.BSC)), + coin.Bsc().Handle: ethereum.InitWithBlockbook(coin.BSCLegacy, GetApiVar(coin.BSC), GetRpcVar(coin.BSC)), + coin.Smartchain().Handle: ethereum.InitWithBlockbook(coin.BSC, GetApiVar(coin.BSC), GetRpcVar(coin.BSC)), coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), coin.Near().Handle: near.Init(GetApiVar(coin.NEAR)), coin.Elrond().Handle: elrond.Init(coin.ERD, GetApiVar(coin.ERD)), From 78f5f4128e6fe23f8526eb66741c14f6c93ee182 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 10 Sep 2020 04:15:20 +0300 Subject: [PATCH 378/506] Use bsclegacy routes for bsc (#1222) --- platform/platform.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform.go b/platform/platform.go index 23379c365..957ad7e81 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -108,7 +108,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Callisto().Handle: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO)), coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN)), coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), - coin.Bsc().Handle: ethereum.InitWithBlockbook(coin.BSCLegacy, GetApiVar(coin.BSC), GetRpcVar(coin.BSC)), + coin.Bsc().Handle: ethereum.InitWithBlockbook(coin.BSCLegacy, GetApiVar(coin.BSCLegacy), GetRpcVar(coin.BSCLegacy)), coin.Smartchain().Handle: ethereum.InitWithBlockbook(coin.BSC, GetApiVar(coin.BSC), GetRpcVar(coin.BSC)), coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), coin.Near().Handle: near.Init(GetApiVar(coin.NEAR)), From 5fd976ed507b75bc8472414063297c29fba8fb50 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 10 Sep 2020 17:29:24 -0700 Subject: [PATCH 379/506] Add TRC21 token type for tomochcain --- pkg/blockatlas/tx.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 675cc3221..3318f81f5 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -24,6 +24,7 @@ const ( TokenTypeETC20 TokenType = "ETC20" TokenTypePOA20 TokenType = "POA20" TokenTypeTRC20 TokenType = "TRC20" + TokenTypeTRC21 TokenType = "TRC21" TokenTypeCLO20 TokenType = "CLO20" TokenTypeGO20 TokenType = "G020" TokenTypeWAN20 TokenType = "WAN20" @@ -395,7 +396,7 @@ func GetEthereumTokenTypeByIndex(coinIndex uint) TokenType { case coin.Gochain().ID: tokenType = TokenTypeGO20 case coin.Tomochain().ID: - tokenType = TokenTypeTRC20 + tokenType = TokenTypeTRC21 case coin.Bsc().ID, coin.Smartchain().ID: tokenType = TokenTypeBEP20 default: From bd99b50b60706dd2b433d327c94a3a500de05b12 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2020 09:46:05 +0300 Subject: [PATCH 380/506] Bump go.uber.org/atomic from 1.6.0 to 1.7.0 (#1225) Bumps [go.uber.org/atomic](https://github.com/uber-go/atomic) from 1.6.0 to 1.7.0. - [Release notes](https://github.com/uber-go/atomic/releases) - [Changelog](https://github.com/uber-go/atomic/blob/master/CHANGELOG.md) - [Commits](https://github.com/uber-go/atomic/compare/v1.6.0...v1.7.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b23fbc298..d4c73c08c 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( go.elastic.co/apm/module/apmgorm v1.8.0 go.elastic.co/apm/module/apmhttp v1.8.0 go.elastic.co/apm/module/apmlogrus v1.8.0 - go.uber.org/atomic v1.6.0 + go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f gopkg.in/yaml.v2 v2.3.0 diff --git a/go.sum b/go.sum index f93503ff0..f53a541bc 100644 --- a/go.sum +++ b/go.sum @@ -487,6 +487,8 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= From 47326fd0a3540808989a216fbcef5b4f70155ddc Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 24 Sep 2020 18:29:27 +0300 Subject: [PATCH 381/506] =?UTF-8?q?[DB]=20Replaces=20subquery=20by=20Joins?= =?UTF-8?q?=20in=20GetSubscriptionsForNotifications.=20=E2=80=A6=20(#1226)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [DB] Replaces subquery by Joins in GetSubscriptionsForNotifications. (#1218) * Replaces subquery by Joins. * Fixes Where condition. * Puts Where condition in Find method. * Changes RestoreConnectionWorker. Starts setup gorm v2. * Deletes unused. * Setup gorm v2... * WIP * Changes balk in AddAssociationsForAddress, AddSubscriptionsForNotifications to gorm native balk. Adds gormlogger in setup. * Discard Dockerfile changes. * Change invalid annotate tag in models.Address. * Migrates subscriptions on gorm v2. All subscriptions tests pass. * Wip. * Fixes AddAssociationsForAddress. WIP. * Optimizes GetSubscribedAddressesForAssets. * Optimizes GetSubscribedAddressesForAssets, GetAssetsMapByAddresses, GetAssetsMapByAddressesFromTime, GetSubscriptionsForNotifications. * Optimizes GetAssociationsByAddresses. * Fixes Where in Joins. Changes gorm tags for v2. * Linter fix. * Fixes GetSubscriptionsForNotifications where condition. * Does suggestions and optimize SetLastParsedBlockNumber. * Optimize GetLastParsedBlockNumber, SetLastParsedBlockNumber. * Cleanup AddSubscriptionsForNotifications. * Cleanup main.go files * Cleanup TestHeightBlockMap_SetHeight * Fixes init db, mq. * Fixes DeleteSubscriptionsForNotifications. * Reset auto go fmt in coins.go * Adds check in GetAssetsMapByAddressesFromTime if len addresses is 0. Deletes mock tracker_test.go. * Fixes context. * Fixes api main.go init database and mq. * Fixes parses main.go ctx. * Adds gorm.v2-dbresolver for read replica. * Adds type int4 for gorm v2 auto migrate. * Updates go.mod * Fixes type serial. * Fixes type serial in Asset. * Reverts bigint default types. * Turn off logs in db integrations tests. * Puts FatalWorker after tokensearcher.Init in api/main.go. Co-authored-by: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> * Fixes GetSubscribedAddressesForAssets. * Fixes AddAssociationsForAddress. Co-authored-by: Ivan Frolov <45122314+jeyldii@users.noreply.github.com> Co-authored-by: jeyldii --- cmd/api/main.go | 15 +- cmd/notifier/main.go | 20 +- cmd/parser/main.go | 23 +- cmd/searcher/main.go | 22 +- cmd/subscriber/main.go | 22 +- db/addresstoasset.go | 204 +++++++----------- db/db.go | 147 +++++-------- db/models/address.go | 2 +- db/models/addresstoasset.go | 8 +- db/models/asset.go | 2 +- db/models/subscriptions.go | 8 +- db/notification.go | 60 ++---- db/tracker.go | 20 +- db/tracker_test.go | 65 ------ go.mod | 9 +- go.sum | 112 +++++++++- internal/shutdown.go | 7 +- mock/mockserver/mockserver.go | 2 +- pkg/numbers/decimal_test.go | 2 +- pkg/numbers/number.go | 2 +- .../ethereum/trustray/transaction_test.go | 1 - platform/harmony/client.go | 3 +- platform/harmony/model.go | 16 +- platform/harmony/stake.go | 2 +- platform/harmony/stake_test.go | 34 ++- platform/nimiq/transaction_test.go | 2 +- platform/tezos/model_test.go | 4 +- tests/integration/setup/postgres.go | 27 +-- 28 files changed, 380 insertions(+), 461 deletions(-) delete mode 100644 db/tracker_test.go diff --git a/cmd/api/main.go b/cmd/api/main.go index 3af1d976d..735865750 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" @@ -17,10 +18,11 @@ import ( const ( defaultPort = "8420" defaultConfigPath = "../../config.yml" - prod = "prod" ) var ( + ctx context.Context + cancel context.CancelFunc port, confPath string engine *gin.Engine database *db.Instance @@ -30,6 +32,7 @@ var ( func init() { port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) + ctx, cancel = context.WithCancel(context.Background()) internal.InitConfig(confPath) logger.InitLogger() @@ -40,14 +43,15 @@ func init() { platform.Init(viper.GetStringSlice("platform")) if restAPI == "tokens" || restAPI == "all" { - pgUri := viper.GetString("postgres.uri") + pgURI := viper.GetString("postgres.uri") pgReadUri := viper.GetString("postgres.read_uri") var err error - database, err = db.New(pgUri, pgReadUri, prod, logMode) + database, err = db.New(pgURI, pgReadUri, logMode) if err != nil { logger.Fatal(err) } + go database.RestoreConnectionWorker(ctx, time.Second*10, pgURI) mqHost := viper.GetString("observer.rabbitmq.uri") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") @@ -57,7 +61,6 @@ func init() { } t = tokensearcher.Init(database, platform.TokensAPIs, mq.TokensRegistration) - go db.RestoreConnectionWorker(database, time.Second*10, pgUri) go mq.FatalWorker(time.Second * 10) } } @@ -75,5 +78,7 @@ func main() { api.SetupSwaggerAPI(engine) api.SetupPlatformAPI(engine) } - internal.SetupGracefulShutdown(port, engine) + + internal.SetupGracefulShutdown(ctx, port, engine) + cancel() } diff --git a/cmd/notifier/main.go b/cmd/notifier/main.go index 0193446b9..bb6a64835 100644 --- a/cmd/notifier/main.go +++ b/cmd/notifier/main.go @@ -13,15 +13,17 @@ import ( const ( defaultConfigPath = "../../config.yml" - prod = "prod" ) var ( + ctx context.Context + cancel context.CancelFunc confPath string database *db.Instance ) func init() { + ctx, cancel = context.WithCancel(context.Background()) _, confPath = internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) @@ -31,8 +33,6 @@ func init() { logMode := viper.GetBool("postgres.log") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") - pgUri := viper.GetString("postgres.uri") - pgReadUri := viper.GetString("postgres.read_uri") internal.InitRabbitMQ(mqHost, prefetchCount) @@ -44,11 +44,14 @@ func init() { logger.Fatal(err) } + pgUri := viper.GetString("postgres.uri") + pgReadUri := viper.GetString("postgres.read_uri") var err error - database, err = db.New(pgUri, pgReadUri, prod, logMode) + database, err = db.New(pgUri, pgReadUri, logMode) if err != nil { logger.Fatal(err) } + go database.RestoreConnectionWorker(ctx, time.Second*10, pgUri) if maxPushNotificationsBatchLimit == 0 { notifier.MaxPushNotificationsBatchLimit = notifier.DefaultPushNotificationsBatchLimit @@ -58,18 +61,15 @@ func init() { logger.Info("maxPushNotificationsBatchLimit ", logger.Params{"limit": maxPushNotificationsBatchLimit}) - go mq.FatalWorker(time.Second * 10) - go db.RestoreConnectionWorker(database, time.Second*10, pgUri) - time.Sleep(time.Millisecond) } func main() { defer mq.Close() - ctx, cancel := context.WithCancel(context.Background()) - go mq.RawTransactions.RunConsumerWithCancelAndDbConn(notifier.RunNotifier, database, ctx) + go mq.FatalWorker(time.Second * 10) - internal.SetupGracefulShutdownForObserver(cancel) + internal.SetupGracefulShutdownForObserver() + cancel() } diff --git a/cmd/parser/main.go b/cmd/parser/main.go index 48f2949f1..870b8860b 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -19,10 +19,11 @@ import ( const ( defaultConfigPath = "../../config.yml" - prod = "prod" ) var ( + ctx context.Context + cancel context.CancelFunc confPath string backlogTime, minInterval, maxInterval, fetchBlocksInterval time.Duration maxBackLogBlocks int64 @@ -31,6 +32,7 @@ var ( ) func init() { + ctx, cancel = context.WithCancel(context.Background()) _, confPath = internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) @@ -51,11 +53,6 @@ func init() { logger.Fatal("No APIs to observe") } - pgUri := viper.GetString("postgres.uri") - pgReadUri := viper.GetString("postgres.read_uri") - - logMode := viper.GetBool("postgres.log") - txsBatchLimit = viper.GetUint("observer.txs_batch_limit") backlogTime = viper.GetDuration("observer.backlog") minInterval = viper.GetDuration("observer.block_poll.min") @@ -65,14 +62,17 @@ func init() { if minInterval >= maxInterval { logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") } + + pgURI := viper.GetString("postgres.uri") + pgReadUri := viper.GetString("postgres.read_uri") + logMode := viper.GetBool("postgres.log") var err error - database, err = db.New(pgUri, pgReadUri, prod, logMode) + database, err = db.New(pgURI, pgReadUri, logMode) if err != nil { logger.Fatal(err) } + go database.RestoreConnectionWorker(ctx, time.Second*10, pgURI) - go mq.FatalWorker(time.Second * 10) - go db.RestoreConnectionWorker(database, time.Second*10, pgUri) time.Sleep(time.Millisecond) } @@ -84,6 +84,8 @@ func main() { stopChannel = make(chan<- struct{}, len(platform.BlockAPIs)) ) + go mq.FatalWorker(time.Second * 10) + wg.Add(len(platform.BlockAPIs)) for _, api := range platform.BlockAPIs { time.Sleep(time.Millisecond * 5) @@ -103,8 +105,6 @@ func main() { txsBatchLimit = parser.MinTxsBatchLimit } - ctx, cancel := context.WithCancel(context.Background()) - coinCancel[coin.Handle] = cancel params := parser.Params{ @@ -138,6 +138,7 @@ func main() { quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit + cancel() logger.Info("Shutdown parser ...") for coin, cancel := range coinCancel { logger.Info(fmt.Sprintf("Starting to stop %s parser...", coin)) diff --git a/cmd/searcher/main.go b/cmd/searcher/main.go index dc0e0b075..52908fb4b 100644 --- a/cmd/searcher/main.go +++ b/cmd/searcher/main.go @@ -14,15 +14,17 @@ import ( const ( defaultConfigPath = "../../config.yml" - prod = "prod" ) var ( + ctx context.Context + cancel context.CancelFunc confPath string database *db.Instance ) func init() { + ctx, cancel = context.WithCancel(context.Background()) _, confPath = internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) @@ -31,20 +33,21 @@ func init() { mqHost := viper.GetString("observer.rabbitmq.uri") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") - pgUri := viper.GetString("postgres.uri") - pgReadUri := viper.GetString("postgres.read_uri") - logMode := viper.GetBool("postgres.log") internal.InitRabbitMQ(mqHost, prefetchCount) if err := mq.RawTransactionsSearcher.Declare(); err != nil { logger.Fatal(err) } + pgURI := viper.GetString("postgres.uri") + pgReadUri := viper.GetString("postgres.read_uri") + logMode := viper.GetBool("postgres.log") var err error - database, err = db.New(pgUri, pgReadUri, prod, logMode) + database, err = db.New(pgURI, pgReadUri, logMode) if err != nil { logger.Fatal(err) } + go database.RestoreConnectionWorker(ctx, time.Second*10, pgURI) if maxPushNotificationsBatchLimit == 0 { notifier.MaxPushNotificationsBatchLimit = notifier.DefaultPushNotificationsBatchLimit @@ -54,18 +57,15 @@ func init() { logger.Info("maxPushNotificationsBatchLimit ", logger.Params{"limit": maxPushNotificationsBatchLimit}) - go mq.FatalWorker(time.Second * 10) - go db.RestoreConnectionWorker(database, time.Second*10, pgUri) - time.Sleep(time.Millisecond) } func main() { defer mq.Close() - ctx, cancel := context.WithCancel(context.Background()) - go mq.RawTransactionsSearcher.RunConsumerWithCancelAndDbConn(tokensearcher.Run, database, ctx) + go mq.FatalWorker(time.Second * 10) - internal.SetupGracefulShutdownForObserver(cancel) + internal.SetupGracefulShutdownForObserver() + cancel() } diff --git a/cmd/subscriber/main.go b/cmd/subscriber/main.go index 162e00cdd..5f2551c78 100644 --- a/cmd/subscriber/main.go +++ b/cmd/subscriber/main.go @@ -14,37 +14,37 @@ import ( const ( defaultConfigPath = "../../config.yml" - prod = "prod" ) var ( + ctx context.Context + cancel context.CancelFunc confPath string database *db.Instance ) func init() { + ctx, cancel = context.WithCancel(context.Background()) _, confPath = internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) logger.InitLogger() - pgUri := viper.GetString("postgres.uri") - pgReadUri := viper.GetString("postgres.read_uri") - logMode := viper.GetBool("postgres.log") - mqHost := viper.GetString("observer.rabbitmq.uri") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") internal.InitRabbitMQ(mqHost, prefetchCount) + pgURI := viper.GetString("postgres.uri") + pgReadUri := viper.GetString("postgres.read_uri") + logMode := viper.GetBool("postgres.log") var err error - database, err = db.New(pgUri, pgReadUri, prod, logMode) + database, err = db.New(pgURI, pgReadUri, logMode) if err != nil { logger.Fatal(err) } + go database.RestoreConnectionWorker(ctx, time.Second*10, pgURI) - go mq.FatalWorker(time.Second * 10) - go db.RestoreConnectionWorker(database, time.Second*10, pgUri) time.Sleep(time.Millisecond) } @@ -56,7 +56,6 @@ func main() { if err := mq.TokensRegistration.Declare(); err != nil { logger.Fatal(err) } - ctx, cancel := context.WithCancel(context.Background()) subscriberType := subscriber.Subscriber(viper.GetString("subscriber")) switch subscriberType { @@ -68,5 +67,8 @@ func main() { logger.Fatal("bad subscriber: " + subscriberType) } - internal.SetupGracefulShutdownForObserver(cancel) + go mq.FatalWorker(time.Second * 10) + + internal.SetupGracefulShutdownForObserver() + cancel() } diff --git a/db/addresstoasset.go b/db/addresstoasset.go index 6a7300315..d9d407fc8 100644 --- a/db/addresstoasset.go +++ b/db/addresstoasset.go @@ -2,59 +2,31 @@ package db import ( "context" - "github.com/jinzhu/gorm" "github.com/trustwallet/blockatlas/db/models" - "go.elastic.co/apm/module/apmgorm" + "gorm.io/gorm" + "gorm.io/gorm/clause" "time" ) func (i Instance) GetSubscribedAddressesForAssets(ctx context.Context, addresses []string) ([]models.Address, error) { - db := apmgorm.WithContext(ctx, i.GormRead) - - addressesSubQuery := db. - Table("addresses"). - Select("id"). + db := i.Gorm.WithContext(ctx) + var result []models.Address + err := db.Model(&models.AssetSubscription{}). + Select("id", "address"). + Joins("LEFT JOIN addresses a ON a.id = address_id"). Where("address in (?)", addresses). - Limit(len(addresses)). - QueryExpr() - - var assetSubs []models.AssetSubscription - err := db. - Set("gorm:insert_option", "ON CONFLICT (address_id) DO UPDATE SET deleted_at = null"). - Preload("Address"). - Where("address_id in (?)", addressesSubQuery). - Find(&assetSubs). - Limit(len(addresses)). - Error + Scan(&result). + Limit(len(addresses)).Error if err != nil { return nil, err } - - var result []models.Address - for _, a := range assetSubs { - result = append(result, a.Address) - } return result, nil } func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Context) (map[string][]string, error) { - db := apmgorm.WithContext(ctx, i.GormRead) - - addressesSubQuery := db.Table("addresses"). - Select("id"). - Where("address in (?)", addresses). - Limit(len(addresses)). - QueryExpr() - + db := i.Gorm.WithContext(ctx) var associations []models.AddressToAssetAssociation - err := db. - Preload("Address"). - Preload("Asset"). - Where("address_id in (?)", addressesSubQuery). - Find(&associations). - Limit(len(addresses)). - Error - if err != nil { + if err := db.Joins("Address").Joins("Asset").Find(&associations, "address in (?)", addresses).Error; err != nil { return nil, err } @@ -67,23 +39,12 @@ func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Contex } func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) (map[string][]string, error) { - db := apmgorm.WithContext(ctx, i.GormRead) - - addressesSubQuery := db.Table("addresses"). - Select("id"). - Where("address in (?)", addresses). - Limit(len(addresses)). - QueryExpr() - + if len(addresses) == 0 { + return map[string][]string{}, nil + } + db := i.Gorm.WithContext(ctx) var associations []models.AddressToAssetAssociation - err := db. - Preload("Address"). - Preload("Asset"). - Where("address_id in (?)", addressesSubQuery). - Where("created_at > ?", from). - Find(&associations). - Limit(len(addresses)). - Error + err := db.Joins("Address").Where("address in (?)", addresses).Joins("Asset").Find(&associations, "created_at > ?", from).Error if err != nil { return nil, err } @@ -97,48 +58,26 @@ func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time. } func (i *Instance) GetAssociationsByAddresses(addresses []string, ctx context.Context) ([]models.AddressToAssetAssociation, error) { - db := apmgorm.WithContext(ctx, i.GormRead) - - addressesSubQuery := db.Table("addresses"). - Select("id"). - Where("address in (?)", addresses). - Limit(len(addresses)). - QueryExpr() - + db := i.Gorm.WithContext(ctx) var result []models.AddressToAssetAssociation - err := db. - Preload("Address"). - Preload("Asset"). - Where("address_id in (?)", addressesSubQuery). - Find(&result). - Limit(len(addresses)). - Error - return result, err + if err := db.Joins("Address").Joins("Asset").Find(&result, "address in (?)", addresses).Error; err != nil { + return nil, err + } + return result, nil } func (i *Instance) GetAssociationsByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) ([]models.AddressToAssetAssociation, error) { - db := apmgorm.WithContext(ctx, i.GormRead) - - addressesSubQuery := db.Table("addresses"). - Select("id"). - Where("address in (?)", addresses). - Limit(len(addresses)). - QueryExpr() - + db := i.Gorm.WithContext(ctx) var result []models.AddressToAssetAssociation - err := db. - Preload("Address"). - Preload("Asset"). - Where("address_id in (?)", addressesSubQuery). - Where("created_at > ?", from). - Find(&result). - Limit(len(addresses)). - Error - return result, err + err := db.Joins("Address").Where("address in (?)", addresses).Joins("Asset").Find(&result, "created_at > ?", from).Error + if err != nil { + return nil, err + } + return result, nil } func (i *Instance) AddAssociationsForAddress(address string, assets []string, ctx context.Context) error { - db := apmgorm.WithContext(ctx, i.Gorm) + db := i.Gorm.WithContext(ctx) return db.Transaction(func(tx *gorm.DB) error { uniqueAssets := getUniqueStrings(assets) uniqueAssetsModel := make([]models.Asset, 0, len(uniqueAssets)) @@ -148,28 +87,37 @@ func (i *Instance) AddAssociationsForAddress(address string, assets []string, ct }) } - err := BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), uniqueAssetsModel) + var err error + dbAddress := models.Address{Address: address} + err = db.Clauses(clause.OnConflict{DoNothing: true}).FirstOrCreate(&dbAddress, "address = ?", address).Error if err != nil { return err } - var dbAssets []models.Asset - err = db.Where("asset in (?)", uniqueAssets).Find(&dbAssets).Error - if err != nil { - return err + if len(uniqueAssetsModel) > 0 { + if err = db.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssetsModel).Error; err != nil { + return err + } } - dbAddress := models.Address{Address: address} - err = db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"). - Where("address = ?", address). - FirstOrCreate(&dbAddress). - Error - if err != nil { - return err + var dbAssets []models.Asset + if len(uniqueAssets) > 0 { + if err = db.Where("asset in (?)", uniqueAssets).Find(&dbAssets).Error; err != nil { + return err + } } assetsSub := models.AssetSubscription{AddressID: dbAddress.ID} - err = db.Set("gorm:insert_option", "ON CONFLICT (address_id) DO UPDATE SET deleted_at = null").Create(&assetsSub).Error + err = db.Clauses(clause.OnConflict{ + Columns: []clause.Column{ + { + Name: "address_id", + }, + }, + DoUpdates: clause.Assignments(map[string]interface{}{ + "deleted_at": nil, + }), + }).Create(&assetsSub).Error if err != nil { return err } @@ -181,15 +129,17 @@ func (i *Instance) AddAssociationsForAddress(address string, assets []string, ct AssetID: asset.ID, }) } - return BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), result) + if len(result) > 0 { + return db.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error + } + return nil }) } func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[string][]string, ctx context.Context) error { - db := apmgorm.WithContext(ctx, i.Gorm) + db := i.Gorm.WithContext(ctx) return db.Transaction(func(tx *gorm.DB) error { - var assets []string - + assets := make([]string, 0, len(associations)) for _, v := range associations { assets = append(assets, v...) } @@ -197,37 +147,22 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin uniqueAssets := getUniqueStrings(assets) uniqueAssetsModel := make([]models.Asset, 0, len(uniqueAssets)) for _, l := range uniqueAssets { - uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{ - Asset: l, - }) + uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{Asset: l}) } - err := BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), uniqueAssetsModel) - if err != nil { - return err - } - - var dbAssets []models.Asset - err = db.Where("asset in (?)", uniqueAssets). - Find(&dbAssets). - Limit(len(uniqueAssets)). - Error - if err != nil { + if err := db.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssetsModel).Error; err != nil { return err } - assetsMap := makeMapAssets(dbAssets) + assetsMap := makeMapAssets(uniqueAssetsModel) - var addresses []string + addresses := make([]string, 0, len(associations)) for k := range associations { addresses = append(addresses, k) } var dbAddresses []models.Address - if err := db.Where("address in (?)", addresses). - Find(&dbAddresses). - Limit(len(addresses)). - Error; err != nil { + if err := db.Find(&dbAddresses, "address in (?)", addresses).Limit(len(addresses)).Error; err != nil { return err } @@ -237,7 +172,16 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin addressSubs = append(addressSubs, sub) } - err = BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT (address_id) DO UPDATE SET deleted_at = null"), addressSubs) + err := db.Clauses(clause.OnConflict{ + Columns: []clause.Column{ + { + Name: "address_id", + }, + }, + DoUpdates: clause.Assignments(map[string]interface{}{ + "deleted_at": nil, + }), + }).Create(&addressSubs).Error if err != nil { return err } @@ -254,7 +198,7 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin result = append(result, r) } } - return BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), result) + return db.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error }) } @@ -275,11 +219,11 @@ func makeMapAddress(addresses []models.Address) map[string]uint { } func getUniqueStrings(values []string) []string { - keys := make(map[string]bool) + keys := make(map[string]struct{}) var list []string for _, entry := range values { if _, value := keys[entry]; !value { - keys[entry] = true + keys[entry] = struct{}{} list = append(list, entry) } } diff --git a/db/db.go b/db/db.go index f6c6fe36e..4a66aa64f 100644 --- a/db/db.go +++ b/db/db.go @@ -1,51 +1,49 @@ package db import ( - "errors" - "github.com/jinzhu/gorm" - gormbulk "github.com/t-tiger/gorm-bulk-insert" + "context" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/logger" - "go.elastic.co/apm/module/apmgorm" - _ "go.elastic.co/apm/module/apmgorm/dialects/postgres" - "reflect" + "gorm.io/driver/postgres" + "gorm.io/gorm" + gormlogger "gorm.io/gorm/logger" + "gorm.io/plugin/dbresolver" + "log" + "os" "time" ) type Instance struct { - Gorm *gorm.DB - GormRead *gorm.DB + Gorm *gorm.DB } -const batchCount = 1000 - -func New(uri, readURI, env string, mode bool) (*Instance, error) { - var ( - g *gorm.DB - rg *gorm.DB - err error - ) - if env == "prod" { - g, err = apmgorm.Open("postgres", uri) - } else { - g, err = gorm.Open("postgres", uri) +func New(uri, readUri string, logMode bool) (*Instance, error) { + cfg := &gorm.Config{} + if logMode { + cfg.Logger = gormlogger.New( + log.New(os.Stdout, "\r\n", log.LstdFlags), + gormlogger.Config{ + SlowThreshold: time.Second, + LogLevel: gormlogger.Info, + Colorful: false, + }, + ) } - + db, err := gorm.Open(postgres.Open(uri), cfg) if err != nil { return nil, err } - if env == "prod" { - rg, err = apmgorm.Open("postgres", readURI) - } else { - rg, err = gorm.Open("postgres", readURI) - } - + err = db.Use(dbresolver.Register(dbresolver.Config{ + Replicas: []gorm.Dialector{ + postgres.Open(readUri), + }, + })) if err != nil { return nil, err } - g.AutoMigrate( + err = db.AutoMigrate( &models.NotificationSubscription{}, &models.Tracker{}, &models.AddressToAssetAssociation{}, @@ -53,89 +51,48 @@ func New(uri, readURI, env string, mode bool) (*Instance, error) { &models.AssetSubscription{}, &models.Address{}, ) - g.Table("address_to_asset_associations"). - AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT"). - AddForeignKey("asset_id", "assets(id)", "RESTRICT", "RESTRICT") - - g.Table("notification_subscriptions"). - AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT") - - g.Table("asset_subscriptions"). - AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT") - - g.LogMode(mode) - rg.LogMode(mode) + if err != nil { + return nil, err + } - i := &Instance{Gorm: g, GormRead: rg} + i := &Instance{Gorm: db} return i, nil } -func RestoreConnectionWorker(database *Instance, timeout time.Duration, uri string) { +func (i *Instance) RestoreConnectionWorker(ctx context.Context, timeout time.Duration, uri string) { logger.Info("Run PG RestoreConnectionWorker") - for { - if err := database.Gorm.DB().Ping(); err != nil { - for { - logger.Warn("PG is not available now") - logger.Warn("Trying to connect to PG...") - database.Gorm, err = gorm.Open("postgres", uri) - if err != nil { - logger.Warn("PG is still unavailable:", err.Error()) - time.Sleep(timeout) - continue - } else { - logger.Info("PG connection restored") - break - } - } + t := time.NewTicker(timeout) + + if err := i.restoreConnection(uri); err != nil { + logger.Warn("PG is still unavailable:", err) + } + + select { + case <-ctx.Done(): + logger.Info("Ctx.Done RestoreConnectionWorker exit") + return + case <-t.C: + if err := i.restoreConnection(uri); err != nil { + logger.Warn("PG is still unavailable:", err) } - time.Sleep(timeout) } } -// Example: -// postgres.BulkInsert(DBWrite, []models.User{...}) -func BulkInsert(db *gorm.DB, dbModels interface{}) error { - interfaceSlice, err := getInterfaceSlice(dbModels) +func (i *Instance) restoreConnection(uri string) error { + db, err := i.Gorm.DB() if err != nil { return err } - batchList := getInterfaceSliceBatch(interfaceSlice, batchCount) - for _, batch := range batchList { - err := gormbulk.BulkInsert(db, batch, len(batch)) + + if err = db.Ping(); err != nil { + logger.Warn("PG is not available now") + logger.Warn("Trying to connect to PG...") + i.Gorm, err = gorm.Open(postgres.Open(uri), &gorm.Config{}) if err != nil { return err } + logger.Info("PG connection restored") } return nil } - -func getInterfaceSliceBatch(values []interface{}, sizeUint uint) [][]interface{} { - size := int(sizeUint) - resultLength := (len(values) + size - 1) / size - result := make([][]interface{}, resultLength) - lo, hi := 0, size - for i := range result { - if hi > len(values) { - hi = len(values) - } - result[i] = values[lo:hi:hi] - lo, hi = hi, hi+size - } - return result -} - -func getInterfaceSlice(slice interface{}) ([]interface{}, error) { - s := reflect.ValueOf(slice) - if s.Kind() != reflect.Slice { - return nil, errors.New("InterfaceSlice() given a non-slice type") - } - - ret := make([]interface{}, s.Len()) - - for i := 0; i < s.Len(); i++ { - ret[i] = s.Index(i).Interface() - } - - return ret, nil -} diff --git a/db/models/address.go b/db/models/address.go index 3f6fa08fc..9ef66921d 100644 --- a/db/models/address.go +++ b/db/models/address.go @@ -2,7 +2,7 @@ package models type Address struct { ID uint `gorm:"primary_key"` - Address string `gorm:"type:varchar(128); unique_index"` + Address string `gorm:"type:varchar(128); uniqueIndex"` } // Use such model in future diff --git a/db/models/addresstoasset.go b/db/models/addresstoasset.go index 2d27a5031..6330f90a1 100644 --- a/db/models/addresstoasset.go +++ b/db/models/addresstoasset.go @@ -5,12 +5,12 @@ import ( ) type AddressToAssetAssociation struct { - CreatedAt time.Time `sql:"index"` - DeletedAt *time.Time `sql:"index"` + CreatedAt time.Time `gorm:"index:,"` + DeletedAt *time.Time `gorm:"index:,; default:NULL"` Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"primary_key; auto_increment:false" sql:"index"` + AddressID uint `gorm:"primary_key; autoIncrement:false; index:,"` Asset Asset `gorm:"ForeignKey:AssetID; not null"` - AssetID uint `gorm:"primary_key; auto_increment:false" sql:"index"` + AssetID uint `gorm:"primary_key; autoIncrement:false; index:,"` } diff --git a/db/models/asset.go b/db/models/asset.go index d91d8d90c..d889854c7 100644 --- a/db/models/asset.go +++ b/db/models/asset.go @@ -2,5 +2,5 @@ package models type Asset struct { ID uint `gorm:"primary_key"` - Asset string `gorm:"type:varchar(128); unique_index"` + Asset string `gorm:"type:varchar(128); uniqueIndex"` } diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index 10d4734f3..207246697 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -4,14 +4,14 @@ import "time" type ( NotificationSubscription struct { - DeletedAt *time.Time `sql:"index"` + DeletedAt *time.Time `gorm:"default:NULL; index"` Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"primary_key; auto_increment:false"` + AddressID uint `gorm:"primary_key; autoIncrement:false"` } AssetSubscription struct { - DeletedAt *time.Time `sql:"index"` + DeletedAt *time.Time `gorm:"default:NULL; index"` Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"primary_key; auto_increment:false"` + AddressID uint `gorm:"primary_key; autoIncrement:false"` } ) diff --git a/db/notification.go b/db/notification.go index 8ecc9be71..70cffe399 100644 --- a/db/notification.go +++ b/db/notification.go @@ -2,32 +2,20 @@ package db import ( "context" - "github.com/jinzhu/gorm" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/errors" - "go.elastic.co/apm/module/apmgorm" + "gorm.io/gorm" + "gorm.io/gorm/clause" ) func (i *Instance) GetSubscriptionsForNotifications(addresses []string, ctx context.Context) ([]models.NotificationSubscription, error) { if len(addresses) == 0 { return nil, errors.E("Empty addresses") } - db := apmgorm.WithContext(ctx, i.GormRead) - - addressesSubQuery := db. - Table("addresses"). - Select("id"). - Where("address in (?)", addresses). - Limit(len(addresses)). - QueryExpr() + db := i.Gorm.WithContext(ctx) var subscriptionsDataList []models.NotificationSubscription - err := db. - Preload("Address"). - Where("address_id in (?)", addressesSubQuery). - Find(&subscriptionsDataList). - Limit(len(addresses)). - Error + err := db.Joins("Address").Limit(len(addresses)).Find(&subscriptionsDataList, "address in (?)", addresses).Error if err != nil { return nil, err } @@ -38,8 +26,7 @@ func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx cont if len(addresses) == 0 { return errors.E("Empty subscriptions") } - db := apmgorm.WithContext(ctx, i.Gorm) - + db := i.Gorm.WithContext(ctx) return db.Transaction(func(tx *gorm.DB) error { uniqueAddresses := getUniqueStrings(addresses) uniqueAddressesModel := make([]models.Address, 0, len(uniqueAddresses)) @@ -49,27 +36,30 @@ func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx cont }) } - err := BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT DO NOTHING"), uniqueAddressesModel) + err := db.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAddressesModel).Error if err != nil { return err } var dbAddresses []models.Address - err = db.Where("address in (?)", uniqueAddresses). - Find(&dbAddresses). - Limit(len(uniqueAddressesModel)). - Error - if err != nil { + if err = db.Find(&dbAddresses, "address in (?)", uniqueAddresses).Error; err != nil { return err } result := make([]models.NotificationSubscription, 0, len(dbAddresses)) for _, a := range dbAddresses { - result = append(result, models.NotificationSubscription{ - AddressID: a.ID, - }) + result = append(result, models.NotificationSubscription{AddressID: a.ID}) } - return BulkInsert(db.Set("gorm:insert_option", "ON CONFLICT (address_id) DO UPDATE SET deleted_at = null"), result) + return db.Clauses(clause.OnConflict{ + Columns: []clause.Column{ + { + Name: "address_id", + }, + }, + DoUpdates: clause.Assignments(map[string]interface{}{ + "deleted_at": nil, + }), + }).Create(&result).Error }) } @@ -77,16 +67,6 @@ func (i *Instance) DeleteSubscriptionsForNotifications(addresses []string, ctx c if len(addresses) == 0 { return errors.E("Empty subscriptions") } - db := apmgorm.WithContext(ctx, i.Gorm) - - addressSubQuery := db.Table("addresses"). - Select("id"). - Where("address in (?)", addresses). - Limit(len(addresses)). - QueryExpr() - - return db.Where("address_id in (?)", addressSubQuery). - Delete(&models.NotificationSubscription{}). - Limit(len(addresses)). - Error + q := `DELETE FROM notification_subscriptions ns USING addresses a where ns.address_id = a.id AND a.address IN (?);` + return i.Gorm.WithContext(ctx).Exec(q, addresses).Error } diff --git a/db/tracker.go b/db/tracker.go index f6bf74d1c..a55ddd7a1 100644 --- a/db/tracker.go +++ b/db/tracker.go @@ -3,7 +3,7 @@ package db import ( "context" "github.com/trustwallet/blockatlas/db/models" - "go.elastic.co/apm/module/apmgorm" + "gorm.io/gorm/clause" "sync" ) @@ -37,8 +37,8 @@ func (i *Instance) GetLastParsedBlockNumber(coin string, ctx context.Context) (i return height, nil } var tracker models.Tracker - g := apmgorm.WithContext(ctx, i.GormRead) - if err := g.Where(models.Tracker{Coin: coin}).Find(&tracker).Error; err != nil { + db := i.Gorm.WithContext(ctx) + if err := db.Find(&tracker, "coin = ?", coin).Error; err != nil { return 0, nil } return tracker.Height, nil @@ -50,9 +50,13 @@ func (i *Instance) SetLastParsedBlockNumber(coin string, num int64, ctx context. Coin: coin, Height: num, } - g := apmgorm.WithContext(ctx, i.Gorm) - return g. - Set("gorm:insert_option", "ON CONFLICT (coin) DO UPDATE SET height = excluded.height, updated_at = excluded.updated_at"). - Where(models.Tracker{Coin: coin}). - Create(&tracker).Error + db := i.Gorm.WithContext(ctx) + return db.Clauses(clause.OnConflict{ + Columns: []clause.Column{ + { + Name: "coin", + }, + }, + DoUpdates: clause.AssignmentColumns([]string{"height", "updated_at"}), + }).Create(&tracker).Error } diff --git a/db/tracker_test.go b/db/tracker_test.go deleted file mode 100644 index c98530664..000000000 --- a/db/tracker_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package db - -import ( - "context" - "github.com/DATA-DOG/go-sqlmock" - "github.com/jinzhu/gorm" - "github.com/stretchr/testify/assert" - "regexp" - "testing" -) - -func TestHeightBlockMap_SetHeight(t *testing.T) { - db, mock := setupDB(t) - defer db.Close() - mock.ExpectBegin() - mock.ExpectQuery( - regexp.QuoteMeta( - `INSERT INTO "trackers" ("updated_at","coin","height") VALUES ($1,$2,$3) ON CONFLICT (coin) DO UPDATE SET height = excluded.height, updated_at = excluded.updated_at RETURNING "trackers"."coin"`)).WithArgs(sqlmock.AnyArg(), "bitcoin", 1).WillReturnRows(sqlmock.NewRows([]string{"id"}). - AddRow("id")) - mock.ExpectCommit() - i := Instance{Gorm: db, GormRead: db} - - assert.Nil(t, i.SetLastParsedBlockNumber("bitcoin", 1, context.Background())) -} - -func TestHeightBlockMap_GetHeight(t *testing.T) { - db, mock := setupDB(t) - defer db.Close() - mock.ExpectBegin() - mock.ExpectQuery( - regexp.QuoteMeta( - `INSERT INTO "trackers" ("updated_at","coin","height") VALUES ($1,$2,$3) ON CONFLICT (coin) DO UPDATE SET height = excluded.height, updated_at = excluded.updated_at RETURNING "trackers"."coin"`)).WithArgs(sqlmock.AnyArg(), "bitcoin", 1).WillReturnRows(sqlmock.NewRows([]string{"id"}). - AddRow("id")) - mock.ExpectCommit() - i := Instance{Gorm: db, GormRead: db} - - assert.Nil(t, i.SetLastParsedBlockNumber("bitcoin", 1, context.Background())) - block, err := i.GetLastParsedBlockNumber("bitcoin", context.Background()) - assert.Nil(t, err) - assert.Equal(t, int64(1), block) - - mock.ExpectQuery( - regexp.QuoteMeta( - `SELECT * FROM "trackers" WHERE ("trackers"."coin" = $1`)).WithArgs("ethereum").WillReturnRows(sqlmock.NewRows([]string{"coin", "height"}). - AddRow("ethereum", 1)) - - b, err := i.GetLastParsedBlockNumber("ethereum", context.Background()) - assert.Nil(t, err) - assert.Equal(t, int64(1), b) - -} - -func setupDB(t *testing.T) (*gorm.DB, sqlmock.Sqlmock) { - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("an error '%s' was not expected when sqlmock", err) - } - - d, err := gorm.Open("postgres", db) - if err != nil { - t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) - } - d.LogMode(true) - return d, mock -} diff --git a/go.mod b/go.mod index d4c73c08c..3031c15af 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,12 @@ module github.com/trustwallet/blockatlas go 1.14 require ( - github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 github.com/deckarep/golang-set v1.7.1 github.com/gin-gonic/gin v1.6.3 github.com/imroc/req v0.3.0 - github.com/jinzhu/gorm v1.9.16 github.com/mitchellh/mapstructure v1.3.3 github.com/mr-tron/base58 v1.2.0 github.com/ory/dockertest v3.3.5+incompatible @@ -23,16 +21,17 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 - github.com/t-tiger/gorm-bulk-insert v1.3.0 github.com/trustwallet/ens-coincodec v1.0.6 github.com/trustwallet/watchmarket v1.1.1 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 - go.elastic.co/apm/module/apmgorm v1.8.0 go.elastic.co/apm/module/apmhttp v1.8.0 go.elastic.co/apm/module/apmlogrus v1.8.0 go.uber.org/atomic v1.7.0 - golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f gopkg.in/yaml.v2 v2.3.0 + gorm.io/driver/postgres v1.0.0 + gorm.io/gorm v1.20.0 + gorm.io/plugin/dbresolver v1.0.0 ) diff --git a/go.sum b/go.sum index f53a541bc..5be382ee8 100644 --- a/go.sum +++ b/go.sum @@ -81,16 +81,20 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb h1:nXPkFq8X1a9ycY3GYQpFNxHh3j2JgY7zDZfq2EXMIzk= github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c h1:4e6Zsb6LFd3kadoMiut2zcd3hCb4zywpJnQa8+NV2Cs= github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c/go.mod h1:k5D13LCXSsMrQyfdW0yGYs4GWUvirqoxHht8qwtqyRY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cucumber/godog v0.8.1 h1:lVb+X41I4YDreE+ibZ50bdXmySxgRviYFgKY6Aw4XE8= github.com/cucumber/godog v0.8.1/go.mod h1:vSh3r/lM+psC1BPXvdkSEuNjmXfpVqrMGYAElF6hxnA= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -172,6 +176,8 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -244,16 +250,68 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U= github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= +github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.6.4 h1:S7T6cx5o2OqmxdHaXLH1ZeD1SbI8jBznyYE9Ec0RCQ8= +github.com/jackc/pgconn v1.6.4/go.mod h1:w2pne1C2tZgP+TvjqLpOigGzNqjBgQW9dUw/4Chex78= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.2 h1:q1Hsy66zh4vuNsajBUF2PNqfAMMfxU5mk594lPE9vjY= +github.com/jackc/pgproto3/v2 v2.0.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= +github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= +github.com/jackc/pgtype v1.4.2 h1:t+6LWm5eWPLX1H5Se702JSBcirq6uWa4jiG4wV1rAWY= +github.com/jackc/pgtype v1.4.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= +github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= +github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= +github.com/jackc/pgx/v4 v4.8.1 h1:SUbCLP2pXvf/Sr/25KsuI4aTxiFYIvpfk4l6aTSdyCw= +github.com/jackc/pgx/v4 v4.8.1/go.mod h1:4HOLxrl8wToZJReD04/yB20GDwf4KBYETvlHciCnwW0= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= -github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= +github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -272,6 +330,7 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -279,13 +338,18 @@ github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -293,14 +357,18 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +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/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= @@ -388,12 +456,17 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -430,6 +503,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= @@ -440,8 +514,6 @@ github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= -github.com/t-tiger/gorm-bulk-insert v1.3.0 h1:9k7BaVEhw/3fsvh6GTOBwJ2RXk3asc5xs5m6hwozq20= -github.com/t-tiger/gorm-bulk-insert v1.3.0/go.mod h1:ruDlk8xDl+8sX4bA7PQuYly9YEb3pbp1eP2LCyeRrFY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/blockatlas v1.1.7-0.20200831100332-b573ace18512/go.mod h1:rq6APqrT+vR58h+WWrCyadT80QDKmDEJvHDllWSUwnM= github.com/trustwallet/ens-coincodec v1.0.6 h1:ZPvFDJwvv4s+XCnUM7pzub8wYHy37tyJBNtKvgx9FDs= @@ -463,6 +535,7 @@ github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.elastic.co/apm v1.8.0 h1:AWEKpHwRal0yCMd4K8Oxy1HAa7xid+xq1yy+XjgoVU0= go.elastic.co/apm v1.8.0/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= go.elastic.co/apm/module/apmgin v1.8.0 h1:QcXVtFhqAcSGqC/ywzqZBHdWzJG3wyrBxgvCvAZ98do= @@ -484,12 +557,16 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -497,16 +574,22 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -549,6 +632,7 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -577,6 +661,7 @@ golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -586,10 +671,12 @@ golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -597,6 +684,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -609,6 +698,7 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -617,15 +707,19 @@ golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200513175351-0951661448da h1:ZR1ivkcQoKXKtux9Rx3Em7iiSViMxQ5suNd5PZMUkPc= golang.org/x/tools v0.0.0-20200513175351-0951661448da/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -676,6 +770,7 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -691,6 +786,15 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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/mysql v1.0.1 h1:omJoilUzyrAp0xNoio88lGJCroGdIOen9hq2A/+3ifw= +gorm.io/driver/mysql v1.0.1/go.mod h1:KtqSthtg55lFp3S5kUXqlGaelnWpKitn4k1xZTnoiPw= +gorm.io/driver/postgres v1.0.0 h1:Yh4jyFQ0a7F+JPU0Gtiam/eKmpT/XFc1FKxotGqc6FM= +gorm.io/driver/postgres v1.0.0/go.mod h1:wtMFcOzmuA5QigNsgEIb7O5lhvH1tHAF1RbWmLWV4to= +gorm.io/gorm v1.9.19/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.20.0 h1:qfIlyaZvrF7kMWY3jBdEBXkXJ2M5MFYMTppjILxS3fQ= +gorm.io/gorm v1.20.0/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/plugin/dbresolver v1.0.0 h1:fHIWRRkoDmXkBPYyg9GMmLugcM9fcbZiG0Zy/cwiPlM= +gorm.io/plugin/dbresolver v1.0.0/go.mod h1:sK1Alv120lfrjRQXrzyAw4ssxDPJjamm2cbBOZBHM68= 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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/shutdown.go b/internal/shutdown.go index 234766d9d..9d5c0ce5a 100644 --- a/internal/shutdown.go +++ b/internal/shutdown.go @@ -11,14 +11,12 @@ import ( "time" ) -func SetupGracefulShutdown(port string, engine *gin.Engine) { +func SetupGracefulShutdown(ctx context.Context, port string, engine *gin.Engine) { server := &http.Server{ Addr: ":" + port, Handler: engine, } - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() defer func() { if err := server.Shutdown(ctx); err != nil { logger.Fatal("Server Shutdown: ", err) @@ -44,11 +42,10 @@ func SetupGracefulShutdown(port string, engine *gin.Engine) { logger.Info("Waiting for all jobs to stop") } -func SetupGracefulShutdownForObserver(cancel context.CancelFunc) { +func SetupGracefulShutdownForObserver() { quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit - cancel() logger.Info("Shutdown ...") time.Sleep(time.Second * 5) logger.Info("Exiting gracefully") diff --git a/mock/mockserver/mockserver.go b/mock/mockserver/mockserver.go index 913ab863b..45a958dd1 100644 --- a/mock/mockserver/mockserver.go +++ b/mock/mockserver/mockserver.go @@ -17,7 +17,7 @@ import ( type TestDataEntry struct { Filename string `yaml:"file"` MockURL string `yaml:"mockURL"` - Method string `yaml:"method"` + Method string `yaml:"method"` ExtURL string `yaml:"extURL,omitempty"` ReqFile string `yaml:"reqFile,omitempty"` ReqField string `yaml:"reqField,omitempty"` diff --git a/pkg/numbers/decimal_test.go b/pkg/numbers/decimal_test.go index 89c3c3765..3d1dbcfa0 100644 --- a/pkg/numbers/decimal_test.go +++ b/pkg/numbers/decimal_test.go @@ -31,7 +31,7 @@ func TestDecimalToSatoshis(t *testing.T) { assertSatEquals("11001100", "0011001100") assertSatEquals("376", " 376") assertSatEquals("376", "376 ") - + assertSatError("12NotNumber34") assertSatError("12,34") assertSatError("") diff --git a/pkg/numbers/number.go b/pkg/numbers/number.go index 7ac3208fa..101b5f69c 100644 --- a/pkg/numbers/number.go +++ b/pkg/numbers/number.go @@ -38,7 +38,7 @@ func Float64toString(num float64) string { } // "0.00037500" => 0.000375, "non-string-number" => 0 -func StringNumberToFloat64(str string) (float64, error) { +func StringNumberToFloat64(str string) (float64, error) { value, err := strconv.ParseFloat(str, 64) if err != nil { return 0, err diff --git a/platform/ethereum/trustray/transaction_test.go b/platform/ethereum/trustray/transaction_test.go index f723eeb33..3195abd2c 100644 --- a/platform/ethereum/trustray/transaction_test.go +++ b/platform/ethereum/trustray/transaction_test.go @@ -227,4 +227,3 @@ func TestNormalize(t *testing.T) { } }) } - diff --git a/platform/harmony/client.go b/platform/harmony/client.go index 70de06a87..2749c611f 100644 --- a/platform/harmony/client.go +++ b/platform/harmony/client.go @@ -43,7 +43,6 @@ func (c *Client) GetBlockByNumber(num int64) (info BlockInfo, err error) { return } - func (c *Client) GetValidators() (validators Validators, err error) { err = rpcCallStub(c, &validators.Validators, "hmy_getAllValidatorInformation", []interface{}{-1}) @@ -86,6 +85,6 @@ func hexToInt(hex string) (uint64, error) { } // rpcCallStub is can be overwritten by the unit test -var rpcCallStub = func (c *Client, result interface{}, method string, params interface{}) error { +var rpcCallStub = func(c *Client, result interface{}, method string, params interface{}) error { return c.RpcCall(result, method, params) } diff --git a/platform/harmony/model.go b/platform/harmony/model.go index 698465edb..a9db97b2f 100644 --- a/platform/harmony/model.go +++ b/platform/harmony/model.go @@ -28,17 +28,17 @@ type BlockInfo struct { } type ValidatorInfo struct { - Address string `json:"address"` + Address string `json:"address"` } type LifetimeInfo struct { - Apr string `json:"apr"` + Apr string `json:"apr"` } type Validator struct { - Info ValidatorInfo `json:"validator"` - Active bool `json:"currently-in-committee"` - Lifetime LifetimeInfo `json:"lifetime"` + Info ValidatorInfo `json:"validator"` + Active bool `json:"currently-in-committee"` + Lifetime LifetimeInfo `json:"lifetime"` } type Validators struct { @@ -46,9 +46,9 @@ type Validators struct { } type Delegation struct { - DelegatorAddress string `json:"delegator_address"` - ValidatorAddress string `json:"validator_address"` - Amount float64 `json:"amount"` + DelegatorAddress string `json:"delegator_address"` + ValidatorAddress string `json:"validator_address"` + Amount float64 `json:"amount"` } type Delegations struct { diff --git a/platform/harmony/stake.go b/platform/harmony/stake.go index ef7e57ec1..6d9d4cd07 100644 --- a/platform/harmony/stake.go +++ b/platform/harmony/stake.go @@ -10,7 +10,7 @@ import ( ) const ( - lockTime = 604800 // in seconds (7 epochs or 7 days) + lockTime = 604800 // in seconds (7 epochs or 7 days) ) func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { diff --git a/platform/harmony/stake_test.go b/platform/harmony/stake_test.go index 202672be9..c4fc8ebe8 100644 --- a/platform/harmony/stake_test.go +++ b/platform/harmony/stake_test.go @@ -102,7 +102,7 @@ func TestNormalizeValidator(t *testing.T) { var apr float64 var err error - if apr, err = strconv.ParseFloat(v.Lifetime.Apr,64); err != nil { + if apr, err = strconv.ParseFloat(v.Lifetime.Apr, 64); err != nil { apr = 0 } @@ -152,22 +152,21 @@ func TestNormalizeDelegations(t *testing.T) { func TestHexToInt(t *testing.T) { result, _ := hexToInt("0x604800") - assert.Equal(t,uint64(6309888), result) + assert.Equal(t, uint64(6309888), result) } func TestGetDetails(t *testing.T) { var expected = blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 10}, - LockTime: lockTime, - MinimumAmount: "1000", - Type: blockatlas.DelegationTypeDelegate, - } + Reward: blockatlas.StakingReward{Annual: 10}, + LockTime: lockTime, + MinimumAmount: "1000", + Type: blockatlas.DelegationTypeDelegate, + } result := getDetails(10) - assert.Equal(t,expected, result) + assert.Equal(t, expected, result) } - func TestGetValidators(t *testing.T) { var c Client @@ -180,14 +179,14 @@ func TestGetValidators(t *testing.T) { Info: ValidatorInfo{ Address: "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", }, - Active: true, + Active: true, Lifetime: LifetimeInfo{Apr: "10"}, }, } - rpcCallStub = func (c *Client, result interface{}, method string, params interface{}) error { + rpcCallStub = func(c *Client, result interface{}, method string, params interface{}) error { jsonData, _ := json.Marshal(validators) - _ = json.Unmarshal(jsonData, result) + _ = json.Unmarshal(jsonData, result) return nil } @@ -216,13 +215,13 @@ func TestGetDelegation(t *testing.T) { Info: ValidatorInfo{ Address: "one1a0au0p33zrns49h3qw7prn02s4wphu0ggcqrhm", }, - Active: true, + Active: true, Lifetime: LifetimeInfo{Apr: "10"}, }, } - rpcCallStub = func (c *Client, result interface{}, method string, params interface{}) error { - if (method == "hmy_getAllValidatorInformation") { + rpcCallStub = func(c *Client, result interface{}, method string, params interface{}) error { + if method == "hmy_getAllValidatorInformation" { jsonData, _ := json.Marshal(validators) _ = json.Unmarshal(jsonData, result) } else { @@ -236,7 +235,6 @@ func TestGetDelegation(t *testing.T) { assert.Equal(t, delegations[0].DelegatorAddress, result[0].Delegator.ID) } - func TestGeBalance(t *testing.T) { var c Client @@ -246,12 +244,12 @@ func TestGeBalance(t *testing.T) { var balance = "0x100" - rpcCallStub = func (c *Client, result interface{}, method string, params interface{}) error { + rpcCallStub = func(c *Client, result interface{}, method string, params interface{}) error { jsonData, _ := json.Marshal(balance) _ = json.Unmarshal(jsonData, result) return nil } result, _ := p.UndelegatedBalance("one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy") - assert.Equal(t, "256",result) + assert.Equal(t, "256", result) } diff --git a/platform/nimiq/transaction_test.go b/platform/nimiq/transaction_test.go index f936434ce..ee5b822f4 100644 --- a/platform/nimiq/transaction_test.go +++ b/platform/nimiq/transaction_test.go @@ -99,7 +99,7 @@ func TestNormalizeTx1(t *testing.T) { } got := NormalizeTx(&srcTx) // special handling for current date, if around now, replace with special value - if math.Abs(float64(got.Date - now)) < 30 { + if math.Abs(float64(got.Date-now)) < 30 { got.Date = 666666 } assert.Equal(t, tt.want, got) diff --git a/platform/tezos/model_test.go b/platform/tezos/model_test.go index 153adfce8..cb3ee9643 100644 --- a/platform/tezos/model_test.go +++ b/platform/tezos/model_test.go @@ -84,8 +84,8 @@ func TestTransaction_Status(t *testing.T) { in Transaction out blockatlas.TransactionType }{ - {"Type should be transaction", Transaction{Type: "transaction",}, blockatlas.TxTransfer}, - {"Type should be delegation", Transaction{Type: "delegation",}, blockatlas.TxAnyAction}, + {"Type should be transaction", Transaction{Type: "transaction"}, blockatlas.TxTransfer}, + {"Type should be delegation", Transaction{Type: "delegation"}, blockatlas.TxAnyAction}, {"Type unsupported", Transaction{Type: "bake"}, "unsupported type"}, } diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go index f5e38ba1c..ac6d96474 100644 --- a/tests/integration/setup/postgres.go +++ b/tests/integration/setup/postgres.go @@ -2,10 +2,10 @@ package setup import ( "fmt" - "github.com/jinzhu/gorm" "github.com/ory/dockertest" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" + "gorm.io/gorm" "log" ) @@ -41,33 +41,28 @@ func runPgContainerAndInitConnection() (*db.Instance, error) { dbConn *db.Instance err error ) - if err := pool.Retry(func() error { - dbConn, err = db.New(uri, uri, "test", false) + err = pool.Retry(func() error { + dbConn, err = db.New(uri, uri, false) return err - }); err != nil { + }) + if err != nil { return nil, err } - dbConn.Gorm.Table("address_to_asset_associations"). - AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT"). - AddForeignKey("asset_id", "assets(id)", "RESTRICT", "RESTRICT") - - dbConn.Gorm.Table("notification_subscriptions"). - AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT") - - dbConn.Gorm.Table("asset_subscriptions"). - AddForeignKey("address_id", "addresses(id)", "RESTRICT", "RESTRICT") - autoMigrate(dbConn.Gorm) return dbConn, nil } func CleanupPgContainer(dbConn *gorm.DB) { - dbConn.DropTable(tables...) + if err := dbConn.Migrator().DropTable(tables...); err != nil { + log.Fatal(err) + } autoMigrate(dbConn) } func autoMigrate(dbConn *gorm.DB) { - dbConn.AutoMigrate(tables...) + if err := dbConn.AutoMigrate(tables...); err != nil { + log.Fatal(err) + } } func stopPgContainer() error { From 42b58e70f2e52c3b36b0e67fc74a9317987eb84a Mon Sep 17 00:00:00 2001 From: Ivan Frolov <45122314+jeyldii@users.noreply.github.com> Date: Sat, 26 Sep 2020 10:07:56 +0300 Subject: [PATCH 382/506] [DB] Fixes UpdateAssociationsForExistingAddresses if len assets is 0. (#1227) * Fixes UpdateAssociationsForExistingAddresses if len assets is 0. * Fixes UpdateAssociationsForExistingAddresses by adds dbAssets. * Fixes UpdateAssociationsForExistingAddresses by check if len assets is 0 return. * Adds logs * Adds logs * Deletes logs. --- db/addresstoasset.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/db/addresstoasset.go b/db/addresstoasset.go index d9d407fc8..5d0f73541 100644 --- a/db/addresstoasset.go +++ b/db/addresstoasset.go @@ -144,17 +144,29 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin assets = append(assets, v...) } + if len(assets) == 0 { + return nil + } + uniqueAssets := getUniqueStrings(assets) uniqueAssetsModel := make([]models.Asset, 0, len(uniqueAssets)) for _, l := range uniqueAssets { uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{Asset: l}) } - if err := db.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssetsModel).Error; err != nil { return err } - assetsMap := makeMapAssets(uniqueAssetsModel) + var dbAssets []models.Asset + err := db.Where("asset in (?)", uniqueAssets). + Find(&dbAssets). + Limit(len(uniqueAssets)). + Error + if err != nil { + return err + } + + assetsMap := makeMapAssets(dbAssets) addresses := make([]string, 0, len(associations)) for k := range associations { @@ -172,7 +184,7 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin addressSubs = append(addressSubs, sub) } - err := db.Clauses(clause.OnConflict{ + err = db.Clauses(clause.OnConflict{ Columns: []clause.Column{ { Name: "address_id", From 86d749a5d1eac34c88f74b382f8245f8c05414ad Mon Sep 17 00:00:00 2001 From: Ivan Frolov <45122314+jeyldii@users.noreply.github.com> Date: Tue, 29 Sep 2020 17:15:53 +0300 Subject: [PATCH 383/506] [DB] Fixes empty values in UpdateAssociationsForExistingAddresses. (#1230) * Fixes UpdateAssociationsForExistingAddresses if len assets is 0. * Fixes UpdateAssociationsForExistingAddresses by adds dbAssets. * Fixes UpdateAssociationsForExistingAddresses by check if len assets is 0 return. * Adds logs * Adds logs * Deletes logs. * Fixes empty values in UpdateAssociationsForExistingAddresses. --- db/addresstoasset.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/db/addresstoasset.go b/db/addresstoasset.go index 5d0f73541..7cc3650a7 100644 --- a/db/addresstoasset.go +++ b/db/addresstoasset.go @@ -203,9 +203,17 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin var result []models.AddressToAssetAssociation for address, assets := range associations { for _, asset := range assets { + addressID, ok := addressesMap[address] + if !ok { + continue + } + assetID, ok := assetsMap[asset] + if !ok { + continue + } r := models.AddressToAssetAssociation{ - AddressID: addressesMap[address], - AssetID: assetsMap[asset], + AddressID: addressID, + AssetID: assetID, } result = append(result, r) } From 10281597a226a81787a067dd312e7921383baf65 Mon Sep 17 00:00:00 2001 From: Ivan Frolov <45122314+jeyldii@users.noreply.github.com> Date: Thu, 1 Oct 2020 15:13:28 +0300 Subject: [PATCH 384/506] Fixes tx's everywhere. (#1235) --- db/addresstoasset.go | 24 ++++++++++++------------ db/notification.go | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/db/addresstoasset.go b/db/addresstoasset.go index 7cc3650a7..e084d47f1 100644 --- a/db/addresstoasset.go +++ b/db/addresstoasset.go @@ -89,26 +89,26 @@ func (i *Instance) AddAssociationsForAddress(address string, assets []string, ct var err error dbAddress := models.Address{Address: address} - err = db.Clauses(clause.OnConflict{DoNothing: true}).FirstOrCreate(&dbAddress, "address = ?", address).Error + err = tx.Clauses(clause.OnConflict{DoNothing: true}).FirstOrCreate(&dbAddress, "address = ?", address).Error if err != nil { return err } if len(uniqueAssetsModel) > 0 { - if err = db.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssetsModel).Error; err != nil { + if err = tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssetsModel).Error; err != nil { return err } } var dbAssets []models.Asset if len(uniqueAssets) > 0 { - if err = db.Where("asset in (?)", uniqueAssets).Find(&dbAssets).Error; err != nil { + if err = tx.Where("asset in (?)", uniqueAssets).Find(&dbAssets).Error; err != nil { return err } } assetsSub := models.AssetSubscription{AddressID: dbAddress.ID} - err = db.Clauses(clause.OnConflict{ + err = tx.Clauses(clause.OnConflict{ Columns: []clause.Column{ { Name: "address_id", @@ -130,7 +130,7 @@ func (i *Instance) AddAssociationsForAddress(address string, assets []string, ct }) } if len(result) > 0 { - return db.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error + return tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error } return nil }) @@ -153,12 +153,12 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin for _, l := range uniqueAssets { uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{Asset: l}) } - if err := db.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssetsModel).Error; err != nil { + if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssetsModel).Error; err != nil { return err } var dbAssets []models.Asset - err := db.Where("asset in (?)", uniqueAssets). + err := tx.Where("asset in (?)", uniqueAssets). Find(&dbAssets). Limit(len(uniqueAssets)). Error @@ -174,7 +174,7 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin } var dbAddresses []models.Address - if err := db.Find(&dbAddresses, "address in (?)", addresses).Limit(len(addresses)).Error; err != nil { + if err := tx.Find(&dbAddresses, "address in (?)", addresses).Limit(len(addresses)).Error; err != nil { return err } @@ -184,7 +184,7 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin addressSubs = append(addressSubs, sub) } - err = db.Clauses(clause.OnConflict{ + err = tx.Clauses(clause.OnConflict{ Columns: []clause.Column{ { Name: "address_id", @@ -204,11 +204,11 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin for address, assets := range associations { for _, asset := range assets { addressID, ok := addressesMap[address] - if !ok { + if !ok || addressID == 0 { continue } assetID, ok := assetsMap[asset] - if !ok { + if !ok || assetID == 0 { continue } r := models.AddressToAssetAssociation{ @@ -218,7 +218,7 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin result = append(result, r) } } - return db.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error + return tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error }) } diff --git a/db/notification.go b/db/notification.go index 70cffe399..6044645ed 100644 --- a/db/notification.go +++ b/db/notification.go @@ -36,13 +36,13 @@ func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx cont }) } - err := db.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAddressesModel).Error + err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAddressesModel).Error if err != nil { return err } var dbAddresses []models.Address - if err = db.Find(&dbAddresses, "address in (?)", uniqueAddresses).Error; err != nil { + if err = tx.Find(&dbAddresses, "address in (?)", uniqueAddresses).Error; err != nil { return err } @@ -50,7 +50,7 @@ func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx cont for _, a := range dbAddresses { result = append(result, models.NotificationSubscription{AddressID: a.ID}) } - return db.Clauses(clause.OnConflict{ + return tx.Clauses(clause.OnConflict{ Columns: []clause.Column{ { Name: "address_id", From 26cfc3b0082ad93b222e3d4625ffd653a3ff0f5d Mon Sep 17 00:00:00 2001 From: Ivan Frolov <45122314+jeyldii@users.noreply.github.com> Date: Wed, 14 Oct 2020 20:10:40 +0300 Subject: [PATCH 385/506] [DB] Fixes GetSubscribedAddressesForAssets if addresses are empty. (#1241) * Fixes GetSubscribedAddressesForAssets if addresses are empty. * Fixes GetSubscribedAddressesForAssets if addresses are empty another way. --- services/tokensearcher/api.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/tokensearcher/api.go b/services/tokensearcher/api.go index 8eb57043f..5d60fc2ed 100644 --- a/services/tokensearcher/api.go +++ b/services/tokensearcher/api.go @@ -34,6 +34,9 @@ func Init(database *db.Instance, apis map[uint]blockatlas.TokensAPI, queue mq.Qu func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (AssetsByAddress, error) { addresses := getAddressesFromRequest(request) + if len(addresses) == 0 { + return nil, nil + } subscribedAddresses, err := getSubscribedAddresses(i.database, addresses, ctx) if err != nil { From 8af515cc628326d8312fd2f5b7047ff811a742e5 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Wed, 14 Oct 2020 23:58:12 +0300 Subject: [PATCH 386/506] [API] Setup spam list (#1242) * Setup spam list check * Continue * Done * Add regexp for url * Fix lint * Add tests and fixes * Fix integration --- api/endpoint/transaction.go | 17 ++++++++++++++++- api/endpoint/transaction_test.go | 21 +++++++++++++++++---- cmd/api/main.go | 2 ++ config.yml | 2 ++ configmock.yml | 2 ++ services/spamfilter/spamfilter.go | 23 +++++++++++++++++++++++ services/spamfilter/spamfilter_test.go | 13 +++++++++++++ 7 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 services/spamfilter/spamfilter.go create mode 100644 services/spamfilter/spamfilter_test.go diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index f072ce47c..b3e1faa1c 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -7,6 +7,7 @@ import ( "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/services/spamfilter" ) // @Summary Get Transactions @@ -83,6 +84,7 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b page = append(page, tx) } + page = filterTransactionsByMemo(page) if token != "" { page = filterTransactionsByToken(token, page) } @@ -90,6 +92,7 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b if len(page) > blockatlas.TxPerPage { page = page[0:blockatlas.TxPerPage] } + c.JSON(http.StatusOK, &page) } @@ -144,13 +147,25 @@ func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { filteredTxs = blockatlas.Txs(txs).FilterUniqueID().SortByDate() page = blockatlas.TxPage(filteredTxs) ) - + page = filterTransactionsByMemo(page) if len(page) > blockatlas.TxPerPage { page = page[0:blockatlas.TxPerPage] } + c.JSON(http.StatusOK, &page) } +func filterTransactionsByMemo(txs blockatlas.TxPage) blockatlas.TxPage { + result := make(blockatlas.TxPage, 0) + for _, tx := range txs { + if spamfilter.ContainsSpam(tx.Memo) { + tx.Memo = "" + } + result = append(result, tx) + } + return result +} + func filterTransactionsByToken(token string, txs blockatlas.TxPage) blockatlas.TxPage { result := make(blockatlas.TxPage, 0) for _, tx := range txs { diff --git a/api/endpoint/transaction_test.go b/api/endpoint/transaction_test.go index e200e0f8b..f8b4dd903 100644 --- a/api/endpoint/transaction_test.go +++ b/api/endpoint/transaction_test.go @@ -4,19 +4,32 @@ import ( "encoding/json" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/spamfilter" "testing" ) var ( - beforeTransactions = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` - wantedTransactions = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + beforeTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + beforeTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"trust.com","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + wantedTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + wantedTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` ) func Test_filterTransactionsByToken(t *testing.T) { var p blockatlas.TxPage - assert.Nil(t, json.Unmarshal([]byte(beforeTransactions), &p)) + assert.Nil(t, json.Unmarshal([]byte(beforeTransactionsToken), &p)) result := filterTransactionsByToken("BUSD-BD1", p) rawResult, err := json.Marshal(result) assert.Nil(t, err) - assert.Equal(t, wantedTransactions, string(rawResult)) + assert.Equal(t, wantedTransactionsToken, string(rawResult)) +} + +func Test_filterTransactionsByMemo(t *testing.T) { + var p blockatlas.TxPage + spamfilter.SpamList = []string{"word", "free"} + assert.Nil(t, json.Unmarshal([]byte(beforeTransactionsMemo), &p)) + result := filterTransactionsByMemo(p) + rawResult, err := json.Marshal(result) + assert.Nil(t, err) + assert.Equal(t, wantedTransactionsMemo, string(rawResult)) } diff --git a/cmd/api/main.go b/cmd/api/main.go index 735865750..3be4ef7b0 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -11,6 +11,7 @@ import ( "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/services/spamfilter" "github.com/trustwallet/blockatlas/services/tokensearcher" "time" ) @@ -41,6 +42,7 @@ func init() { logMode := viper.GetBool("postgres.log") engine = internal.InitEngine(viper.GetString("gin.mode")) platform.Init(viper.GetStringSlice("platform")) + spamfilter.SpamList = viper.GetStringSlice("spam_words") if restAPI == "tokens" || restAPI == "all" { pgURI := viper.GetString("postgres.uri") diff --git a/config.yml b/config.yml index 9d56d5d6e..59b0e6892 100644 --- a/config.yml +++ b/config.yml @@ -14,6 +14,8 @@ platform: [ all ] # Can be platform or swagger, or tokens, or all rest_api: all +spam_words: [ "airdrop","www", "http" ] + # Can be tokens or notifications subscriber: tokens diff --git a/configmock.yml b/configmock.yml index 6f68db7b0..4035fe986 100644 --- a/configmock.yml +++ b/configmock.yml @@ -16,6 +16,8 @@ platform: all # Can be platform or swagger, or tokens, or all rest_api: platform +spam_words: [ "airdrop","www", "http" ] + # The transaction watcher observer: backlog: 3h diff --git a/services/spamfilter/spamfilter.go b/services/spamfilter/spamfilter.go new file mode 100644 index 000000000..8e6b58686 --- /dev/null +++ b/services/spamfilter/spamfilter.go @@ -0,0 +1,23 @@ +package spamfilter + +import ( + "regexp" + "strings" +) + +var SpamList []string + +func ContainsSpam(name string) bool { + lowerCaseName := strings.ToLower(name) + for _, word := range SpamList { + if strings.Contains(lowerCaseName, word) || isURL(lowerCaseName) { + return true + } + } + return false +} + +func isURL(host string) bool { + var URLRegex = `[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)` + return regexp.MustCompile(URLRegex).MatchString(host) +} diff --git a/services/spamfilter/spamfilter_test.go b/services/spamfilter/spamfilter_test.go new file mode 100644 index 000000000..c3814e9d7 --- /dev/null +++ b/services/spamfilter/spamfilter_test.go @@ -0,0 +1,13 @@ +package spamfilter + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func Test_isURL(t *testing.T) { + assert.True(t, isURL("http://www.trust.com")) + assert.True(t, isURL("www.trust.com")) + assert.True(t, isURL("trust.com")) + assert.True(t, isURL("saa,c trust.com")) +} From f4306e4e6daafd1d75037e298d3080885f3b4cc7 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Sun, 18 Oct 2020 21:59:38 +0300 Subject: [PATCH 387/506] [SPAM] Add spamgfilter to parser, cleanup (#1245) * Add spamgfilter to parser, cleanuo * Delete go_build_main_go * Swagger fixes --- api/endpoint/domain.go | 4 +- api/endpoint/staking.go | 8 +-- api/endpoint/transaction.go | 57 ++----------------- api/endpoint/transaction_test.go | 35 ------------ pkg/blockatlas/tx.go | 48 ++++++++++++++++ pkg/blockatlas/tx_test.go | 28 +++++++++ services/parser/parser.go | 2 + services/spamfilter/spamfilter.go | 15 +++-- .../integration/observer_test/parser_test.go | 2 +- 9 files changed, 100 insertions(+), 99 deletions(-) delete mode 100644 api/endpoint/transaction_test.go diff --git a/api/endpoint/domain.go b/api/endpoint/domain.go index 58a1c2c33..5fe7c3e01 100644 --- a/api/endpoint/domain.go +++ b/api/endpoint/domain.go @@ -10,7 +10,7 @@ import ( ) // @Summary Lookup .eth / .zil addresses -// @ID lookup +// @ID lookup_v1 // @Description Lookup ENS/ZNS to find registered addresses // @Produce json // @Tags Naming @@ -40,7 +40,7 @@ func GetAddressByCoinAndDomain(c *gin.Context) { } // @Summary Lookup .eth / .zil addresses -// @ID lookup +// @ID lookup_v2 // @Description Lookup ENS/ZNS to find registered addresses for multiple coins // @Produce json // @Tags Naming diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index 74a1dd8d4..e32143c28 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -31,7 +31,7 @@ type ( ) // @Summary Get Multiple Stake Delegations -// @ID batch_delegations +// @ID staking_v2_batch // @Description Get Stake Delegations for multiple coins // @Accept json // @Produce json @@ -67,7 +67,7 @@ func GetStakeDelegationsWithAllInfoForBatch(c *gin.Context, apis map[string]bloc } // @Summary Get Multiple Stake Delegations -// @ID batch_delegations +// @ID staking_v2 // @Description Get Stake Delegations for multiple coins // @Accept json // @Produce json @@ -99,7 +99,7 @@ func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { } // @Summary Get staking info by coin ID -// @ID batch_info +// @ID staking_v3 // @Description Get staking info by coin ID // @Produce json // @Tags Staking @@ -144,7 +144,7 @@ func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { } // @Summary Get Validators -// @ID validators +// @ID validators_v2 // @Description Get validators from the address // @Accept json // @Produce json diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index b3e1faa1c..2bd2013fd 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -1,13 +1,10 @@ package endpoint import ( - "net/http" - "strings" - "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/services/spamfilter" + "net/http" ) // @Summary Get Transactions @@ -84,9 +81,9 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b page = append(page, tx) } - page = filterTransactionsByMemo(page) + page = page.FilterTransactionsByMemo() if token != "" { - page = filterTransactionsByToken(token, page) + page = page.FilterTransactionsByToken(token) } if len(page) > blockatlas.TxPerPage { @@ -147,56 +144,10 @@ func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { filteredTxs = blockatlas.Txs(txs).FilterUniqueID().SortByDate() page = blockatlas.TxPage(filteredTxs) ) - page = filterTransactionsByMemo(page) + page = page.FilterTransactionsByMemo() if len(page) > blockatlas.TxPerPage { page = page[0:blockatlas.TxPerPage] } c.JSON(http.StatusOK, &page) } - -func filterTransactionsByMemo(txs blockatlas.TxPage) blockatlas.TxPage { - result := make(blockatlas.TxPage, 0) - for _, tx := range txs { - if spamfilter.ContainsSpam(tx.Memo) { - tx.Memo = "" - } - result = append(result, tx) - } - return result -} - -func filterTransactionsByToken(token string, txs blockatlas.TxPage) blockatlas.TxPage { - result := make(blockatlas.TxPage, 0) - for _, tx := range txs { - switch tx.Meta.(type) { - case blockatlas.TokenTransfer: - if strings.EqualFold(tx.Meta.(blockatlas.TokenTransfer).TokenID, token) { - result = append(result, tx) - } - case *blockatlas.TokenTransfer: - if strings.EqualFold(tx.Meta.(*blockatlas.TokenTransfer).TokenID, token) { - result = append(result, tx) - } - case blockatlas.NativeTokenTransfer: - if strings.EqualFold(tx.Meta.(blockatlas.NativeTokenTransfer).TokenID, token) { - result = append(result, tx) - } - case *blockatlas.NativeTokenTransfer: - if strings.EqualFold(tx.Meta.(*blockatlas.NativeTokenTransfer).TokenID, token) { - result = append(result, tx) - } - case blockatlas.AnyAction: - if strings.EqualFold(tx.Meta.(blockatlas.AnyAction).TokenID, token) { - result = append(result, tx) - } - case *blockatlas.AnyAction: - if strings.EqualFold(tx.Meta.(*blockatlas.AnyAction).TokenID, token) { - result = append(result, tx) - } - default: - continue - } - } - return result -} diff --git a/api/endpoint/transaction_test.go b/api/endpoint/transaction_test.go deleted file mode 100644 index f8b4dd903..000000000 --- a/api/endpoint/transaction_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package endpoint - -import ( - "encoding/json" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/spamfilter" - "testing" -) - -var ( - beforeTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` - beforeTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"trust.com","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` - wantedTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` - wantedTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` -) - -func Test_filterTransactionsByToken(t *testing.T) { - var p blockatlas.TxPage - assert.Nil(t, json.Unmarshal([]byte(beforeTransactionsToken), &p)) - result := filterTransactionsByToken("BUSD-BD1", p) - rawResult, err := json.Marshal(result) - assert.Nil(t, err) - assert.Equal(t, wantedTransactionsToken, string(rawResult)) -} - -func Test_filterTransactionsByMemo(t *testing.T) { - var p blockatlas.TxPage - spamfilter.SpamList = []string{"word", "free"} - assert.Nil(t, json.Unmarshal([]byte(beforeTransactionsMemo), &p)) - result := filterTransactionsByMemo(p) - rawResult, err := json.Marshal(result) - assert.Nil(t, err) - assert.Equal(t, wantedTransactionsMemo, string(rawResult)) -} diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 3318f81f5..fd03e28bb 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -4,7 +4,9 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/blockatlas/services/spamfilter" "sort" + "strings" ) const ( @@ -224,6 +226,52 @@ func (t Txs) FilterUniqueID() Txs { return list } +func (txs TxPage) FilterTransactionsByMemo() TxPage { + result := make(TxPage, 0) + for _, tx := range txs { + if spamfilter.ContainsSpam(tx.Memo) { + tx.Memo = "" + } + result = append(result, tx) + } + return result +} + +func (txs TxPage) FilterTransactionsByToken(token string) TxPage { + result := make(TxPage, 0) + for _, tx := range txs { + switch tx.Meta.(type) { + case TokenTransfer: + if strings.EqualFold(tx.Meta.(TokenTransfer).TokenID, token) { + result = append(result, tx) + } + case *TokenTransfer: + if strings.EqualFold(tx.Meta.(*TokenTransfer).TokenID, token) { + result = append(result, tx) + } + case NativeTokenTransfer: + if strings.EqualFold(tx.Meta.(NativeTokenTransfer).TokenID, token) { + result = append(result, tx) + } + case *NativeTokenTransfer: + if strings.EqualFold(tx.Meta.(*NativeTokenTransfer).TokenID, token) { + result = append(result, tx) + } + case AnyAction: + if strings.EqualFold(tx.Meta.(AnyAction).TokenID, token) { + result = append(result, tx) + } + case *AnyAction: + if strings.EqualFold(tx.Meta.(*AnyAction).TokenID, token) { + result = append(result, tx) + } + default: + continue + } + } + return result +} + func (t Txs) SortByDate() Txs { sort.Slice(t, func(i, j int) bool { return t[i].Date > t[j].Date diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 457953f0e..88074e8cf 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -1,9 +1,11 @@ package blockatlas import ( + "encoding/json" mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/blockatlas/services/spamfilter" "sort" "testing" ) @@ -605,3 +607,29 @@ func TestGetEthereumTokenTypeByIndex(t *testing.T) { }) } } + +var ( + beforeTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + beforeTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"trust.com","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + wantedTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + wantedTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` +) + +func Test_filterTransactionsByToken(t *testing.T) { + var p TxPage + assert.Nil(t, json.Unmarshal([]byte(beforeTransactionsToken), &p)) + result := p.FilterTransactionsByToken("BUSD-BD1") + rawResult, err := json.Marshal(result) + assert.Nil(t, err) + assert.Equal(t, wantedTransactionsToken, string(rawResult)) +} + +func Test_filterTransactionsByMemo(t *testing.T) { + var p TxPage + spamfilter.SpamList = []string{"word", "free"} + assert.Nil(t, json.Unmarshal([]byte(beforeTransactionsMemo), &p)) + result := p.FilterTransactionsByMemo() + rawResult, err := json.Marshal(result) + assert.Nil(t, err) + assert.Equal(t, wantedTransactionsMemo, string(rawResult)) +} diff --git a/services/parser/parser.go b/services/parser/parser.go index 07785191b..454cb7a6d 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -95,6 +95,8 @@ func parse(params Params) { } txs := ConvertToBatch(blocks, ctx) + txs = blockatlas.Txs(blockatlas.TxPage(txs).FilterTransactionsByMemo()) + PublishTransactionsBatch(params, txs, ctx) logger.Info("End of parse step") diff --git a/services/spamfilter/spamfilter.go b/services/spamfilter/spamfilter.go index 8e6b58686..2bfa2fbfe 100644 --- a/services/spamfilter/spamfilter.go +++ b/services/spamfilter/spamfilter.go @@ -5,12 +5,20 @@ import ( "strings" ) -var SpamList []string +const URLRegex = `[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)` + +var ( + SpamList []string + compiledRegexp = regexp.MustCompile(URLRegex) +) func ContainsSpam(name string) bool { + if isURL(name) { + return true + } lowerCaseName := strings.ToLower(name) for _, word := range SpamList { - if strings.Contains(lowerCaseName, word) || isURL(lowerCaseName) { + if strings.Contains(lowerCaseName, word) { return true } } @@ -18,6 +26,5 @@ func ContainsSpam(name string) bool { } func isURL(host string) bool { - var URLRegex = `[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)` - return regexp.MustCompile(URLRegex).MatchString(host) + return compiledRegexp.MatchString(host) } diff --git a/tests/integration/observer_test/parser_test.go b/tests/integration/observer_test/parser_test.go index 860b55211..08b9d5d6b 100644 --- a/tests/integration/observer_test/parser_test.go +++ b/tests/integration/observer_test/parser_test.go @@ -68,7 +68,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { Date: 1555117625, Block: 7928667, Status: blockatlas.StatusCompleted, - Memo: "test", + Memo: "google.com", Meta: blockatlas.NativeTokenTransfer{ TokenID: "YLC-D8B", Symbol: "YLC", From e912404f10b0570b5292a75aef7415b5176d91f5 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 22 Oct 2020 20:06:27 +0800 Subject: [PATCH 388/506] add filecoin placeholder and use golibs/coin package (#1247) --- api/endpoint/staking.go | 2 +- coin/coins.go | 763 ------------------ coin/coins.yml | 416 ---------- coin/gen.go | 145 ---- coin/gen_test.go | 96 --- coin/models.go | 17 - config.yml | 2 + go.mod | 3 +- go.sum | 4 + pkg/address/address.go | 2 +- pkg/address/address_test.go | 2 +- pkg/blockatlas/marshal_test.go | 2 +- pkg/blockatlas/platform.go | 2 +- pkg/blockatlas/staking.go | 2 +- pkg/blockatlas/tx.go | 2 +- pkg/blockatlas/tx_test.go | 2 +- platform/aeternity/base.go | 2 +- platform/aeternity/transaction.go | 2 +- platform/aeternity/transaction_test.go | 2 +- platform/aion/base.go | 2 +- platform/aion/transaction.go | 2 +- platform/aion/transaction_test.go | 2 +- platform/algorand/base.go | 2 +- platform/algorand/transaction.go | 2 +- platform/algorand/transaction_test.go | 2 +- platform/binance/base.go | 2 +- platform/binance/model.go | 2 +- platform/binance/transaction.go | 2 +- platform/bitcoin/base.go | 2 +- platform/bitcoin/transaction.go | 2 +- platform/bitcoin/transaction_test.go | 2 +- platform/cosmos/base.go | 2 +- platform/cosmos/stake.go | 2 +- platform/cosmos/transaction_test.go | 2 +- platform/elrond/base.go | 2 +- platform/elrond/transaction.go | 2 +- platform/elrond/transaction_test.go | 2 +- platform/ethereum/base.go | 2 +- platform/ethereum/blockbook/transaction.go | 2 +- platform/ethereum/collection_test.go | 2 +- platform/ethereum/domain.go | 2 +- platform/ethereum/trustray/token_test.go | 2 +- platform/ethereum/trustray/transaction.go | 2 +- .../ethereum/trustray/transaction_test.go | 2 +- platform/filecoin/base.go | 21 + platform/filecoin/client.go | 9 + platform/filecoin/transaction.go | 10 + platform/fio/base.go | 2 +- platform/fio/domain.go | 2 +- platform/harmony/base.go | 2 +- platform/harmony/transaction.go | 2 +- platform/harmony/transaction_test.go | 2 +- platform/icon/base.go | 2 +- platform/icon/transaction.go | 2 +- platform/icon/transaction_test.go | 2 +- platform/iotex/base.go | 2 +- platform/iotex/transaction.go | 2 +- platform/iotex/transaction_test.go | 2 +- platform/kava/base.go | 2 +- platform/kava/stake.go | 2 +- platform/kava/transaction_test.go | 2 +- platform/nano/base.go | 2 +- platform/near/base.go | 2 +- platform/nebulas/base.go | 2 +- platform/nebulas/transaction.go | 2 +- platform/nebulas/transaction_test.go | 2 +- platform/nimiq/base.go | 2 +- platform/nimiq/transaction.go | 2 +- platform/nimiq/transaction_test.go | 2 +- platform/ontology/base.go | 2 +- platform/ontology/transaction.go | 2 +- platform/ontology/transaction_test.go | 2 +- platform/platform.go | 4 +- platform/polkadot/base.go | 2 +- platform/polkadot/transaction_test.go | 2 +- platform/ripple/base.go | 2 +- platform/ripple/transaction.go | 2 +- platform/ripple/transaction_test.go | 2 +- platform/solana/base.go | 2 +- platform/stellar/base.go | 2 +- platform/stellar/transaction.go | 2 +- platform/stellar/transaction_test.go | 2 +- platform/tezos/base.go | 2 +- platform/tezos/transaction.go | 2 +- platform/theta/base.go | 2 +- platform/theta/transaction.go | 2 +- platform/theta/transaction_test.go | 2 +- platform/tron/base.go | 2 +- platform/tron/token.go | 2 +- platform/tron/transaction.go | 2 +- platform/tron/transaction_test.go | 2 +- platform/vechain/base.go | 2 +- platform/vechain/transaction_test.go | 2 +- platform/waves/base.go | 2 +- platform/waves/transaction.go | 2 +- platform/zilliqa/base.go | 2 +- platform/zilliqa/domain.go | 2 +- platform/zilliqa/transaction.go | 2 +- platform/zilliqa/transaction_test.go | 2 +- services/assets/client.go | 2 +- services/assets/validator.go | 2 +- services/assets/validator_test.go | 2 +- services/notifier/models_test.go | 2 +- services/parser/parser_test.go | 2 +- services/tokensearcher/api_test.go | 2 +- .../observer_test/full_flow_test.go | 2 +- .../observer_test/notifier_test.go | 2 +- .../integration/observer_test/parser_test.go | 2 +- 108 files changed, 147 insertions(+), 1535 deletions(-) delete mode 100644 coin/coins.go delete mode 100644 coin/coins.yml delete mode 100644 coin/gen.go delete mode 100644 coin/gen_test.go delete mode 100644 coin/models.go create mode 100644 platform/filecoin/base.go create mode 100644 platform/filecoin/client.go create mode 100644 platform/filecoin/transaction.go diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index e32143c28..86171635f 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -2,9 +2,9 @@ package endpoint import ( "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/golibs/coin" "net/http" "sort" "strconv" diff --git a/coin/coins.go b/coin/coins.go deleted file mode 100644 index 384a4bcca..000000000 --- a/coin/coins.go +++ /dev/null @@ -1,763 +0,0 @@ -// Code generated by go generate; DO NOT EDIT. -// This file was generated by robots at -// 2020-09-09 14:29:27.707466 -0700 PDT m=+0.001959780 -// using data from coins.yml -package coin - -import ( - "fmt" -) - -// Coin is the native currency of a blockchain -type Coin struct { - ID uint - Handle string - Symbol string - PreferedSymbol string - Name string - Decimals uint - BlockTime int - MinConfirmations int64 - SampleAddr string -} - -func (c *Coin) String() string { - return fmt.Sprintf("[%s] %s (#%d)", c.Symbol, c.Name, c.ID) -} - -const ( - ETH = 60 - ETC = 61 - ICX = 74 - ATOM = 118 - XRP = 144 - XLM = 148 - POA = 178 - TRX = 195 - FIO = 235 - NIM = 242 - IOTX = 304 - ZIL = 313 - AION = 425 - AE = 457 - KAVA = 459 - THETA = 500 - BNB = 714 - VET = 818 - CLO = 820 - TOMO = 889 - TT = 1001 - ONT = 1024 - XTZ = 1729 - KIN = 2017 - NAS = 2718 - GO = 6060 - WAN = 5718350 - WAVES = 5741564 - BTC = 0 - LTC = 2 - DOGE = 3 - DASH = 5 - VIA = 14 - GRS = 17 - ZEC = 133 - XZC = 136 - BCH = 145 - RVN = 175 - QTUM = 2301 - ZEL = 19167 - DCR = 42 - ALGO = 283 - NANO = 165 - DGB = 20 - ONE = 1023 - KSM = 434 - DOT = 354 - SOL = 501 - NEAR = 397 - ERD = 508 - BSCLegacy = 10000714 - BSC = 20000714 -) - -var Coins = map[uint]Coin{ - ETH: { - ID: 60, - Handle: "ethereum", - Symbol: "ETH", - Name: "Ethereum", - Decimals: 18, - BlockTime: 10000, - MinConfirmations: 0, - SampleAddr: "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1", - }, - ETC: { - ID: 61, - Handle: "classic", - Symbol: "ETC", - Name: "Ethereum Classic", - Decimals: 18, - BlockTime: 30000, - MinConfirmations: 0, - SampleAddr: "0xf3524415b6D873205B4c3Cda783527b2aC4daAA9", - }, - ICX: { - ID: 74, - Handle: "icon", - Symbol: "ICX", - Name: "ICON", - Decimals: 18, - BlockTime: 0, - MinConfirmations: 0, - SampleAddr: "hxee691e7bccc4eb11fee922896e9f51490e62b12e", - }, - ATOM: { - ID: 118, - Handle: "cosmos", - Symbol: "ATOM", - Name: "Cosmos", - Decimals: 6, - BlockTime: 5000, - MinConfirmations: 0, - SampleAddr: "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl", - }, - XRP: { - ID: 144, - Handle: "ripple", - Symbol: "XRP", - Name: "Ripple", - Decimals: 6, - BlockTime: 5000, - MinConfirmations: 0, - SampleAddr: "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", - }, - XLM: { - ID: 148, - Handle: "stellar", - Symbol: "XLM", - Name: "Stellar", - Decimals: 7, - BlockTime: 5000, - MinConfirmations: 0, - SampleAddr: "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - }, - POA: { - ID: 178, - Handle: "poa", - Symbol: "POA", - Name: "Poa", - Decimals: 18, - BlockTime: 30000, - MinConfirmations: 0, - SampleAddr: "0x1fddEc96688e0538A316C64dcFd211c491ECf0d8", - }, - TRX: { - ID: 195, - Handle: "tron", - Symbol: "TRX", - Name: "Tron", - Decimals: 6, - BlockTime: 10000, - MinConfirmations: 0, - SampleAddr: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", - }, - FIO: { - ID: 235, - Handle: "fio", - Symbol: "FIO", - Name: "FIO", - Decimals: 9, - BlockTime: 0, - MinConfirmations: 0, - SampleAddr: "FIO5J2xdfWygeNdHZNZRzRws8YGbVxjUXtp4eP8KoGkGKoLFQ7CaU", - }, - NIM: { - ID: 242, - Handle: "nimiq", - Symbol: "NIM", - Name: "Nimiq", - Decimals: 5, - BlockTime: 60000, - MinConfirmations: 0, - SampleAddr: "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA", - }, - IOTX: { - ID: 304, - Handle: "iotex", - Symbol: "IOTX", - Name: "IoTeX", - Decimals: 18, - BlockTime: 10000, - MinConfirmations: 0, - SampleAddr: "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", - }, - ZIL: { - ID: 313, - Handle: "zilliqa", - Symbol: "ZIL", - Name: "Zilliqa", - Decimals: 12, - BlockTime: 30000, - MinConfirmations: 1, - SampleAddr: "zil1anrjcsj2ntklaa3arq4w3s6gw4l4hqrycs9egy", - }, - AION: { - ID: 425, - Handle: "aion", - Symbol: "AION", - Name: "Aion", - Decimals: 18, - BlockTime: 10000, - MinConfirmations: 0, - SampleAddr: "0xa07981da70ce919e1db5f051c3c386eb526e6ce8b9e2bfd56e3f3d754b0a17f3", - }, - AE: { - ID: 457, - Handle: "aeternity", - Symbol: "AE", - Name: "Aeternity", - Decimals: 18, - BlockTime: 6000, - MinConfirmations: 0, - SampleAddr: "ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw", - }, - KAVA: { - ID: 459, - Handle: "kava", - Symbol: "KAVA", - Name: "Kava", - Decimals: 6, - BlockTime: 5000, - MinConfirmations: 0, - SampleAddr: "kava13fxkk4730cqglgdv7w0mdelyx07myyq7h2nd3x", - }, - THETA: { - ID: 500, - Handle: "theta", - Symbol: "THETA", - Name: "Theta", - Decimals: 18, - BlockTime: 0, - MinConfirmations: 0, - SampleAddr: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - }, - BNB: { - ID: 714, - Handle: "binance", - Symbol: "BNB", - Name: "BNB", - Decimals: 8, - BlockTime: 4000, - MinConfirmations: 2, - SampleAddr: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - }, - VET: { - ID: 818, - Handle: "vechain", - Symbol: "VET", - Name: "VeChain Token", - Decimals: 18, - BlockTime: 20000, - MinConfirmations: 0, - SampleAddr: "0xB5e883349e68aB59307d1604555AC890fAC47128", - }, - CLO: { - ID: 820, - Handle: "callisto", - Symbol: "CLO", - Name: "Callisto", - Decimals: 18, - BlockTime: 10000, - MinConfirmations: 0, - SampleAddr: "0x39ec1c88a7a7c1a575e8c8f42eff7630d9278179", - }, - TOMO: { - ID: 889, - Handle: "tomochain", - Symbol: "TOMO", - Name: "TOMO", - Decimals: 18, - BlockTime: 4000, - MinConfirmations: 0, - SampleAddr: "0x7daa83030e3086477b79b6e757ca8608899fe783", - }, - TT: { - ID: 1001, - Handle: "thundertoken", - Symbol: "TT", - Name: "ThunderCore", - Decimals: 18, - BlockTime: 10000, - MinConfirmations: 0, - SampleAddr: "0x0ad80a408eac4f17ba0a9de8a12d8736f60700c3", - }, - ONT: { - ID: 1024, - Handle: "ontology", - Symbol: "ONT", - Name: "Ontology", - Decimals: 0, - BlockTime: 10000, - MinConfirmations: 0, - SampleAddr: "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - }, - XTZ: { - ID: 1729, - Handle: "tezos", - Symbol: "XTZ", - Name: "Tezos", - Decimals: 6, - BlockTime: 20000, - MinConfirmations: 0, - SampleAddr: "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", - }, - KIN: { - ID: 2017, - Handle: "kin", - Symbol: "KIN", - Name: "Kin", - Decimals: 5, - BlockTime: 5000, - MinConfirmations: 0, - SampleAddr: "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", - }, - NAS: { - ID: 2718, - Handle: "nebulas", - Symbol: "NAS", - Name: "Nebulas", - Decimals: 18, - BlockTime: 30000, - MinConfirmations: 0, - SampleAddr: "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", - }, - GO: { - ID: 6060, - Handle: "gochain", - Symbol: "GO", - Name: "GoChain GO", - Decimals: 18, - BlockTime: 20000, - MinConfirmations: 0, - SampleAddr: "0x76c2F81716A8D198a00502Ae9a59126418899FDe", - }, - WAN: { - ID: 5718350, - Handle: "wanchain", - Symbol: "WAN", - Name: "Wanchain", - Decimals: 18, - BlockTime: 30000, - MinConfirmations: 0, - SampleAddr: "0x36cEdc3A9d969306AF4F7CA2b83ABBf74095914d", - }, - WAVES: { - ID: 5741564, - Handle: "waves", - Symbol: "WAVES", - Name: "WAVES", - Decimals: 8, - BlockTime: 30000, - MinConfirmations: 1, - SampleAddr: "3P7wz6TXienpw3BHe8eHUEuZWb6WE58kgnQ", - }, - BTC: { - ID: 0, - Handle: "bitcoin", - Symbol: "BTC", - Name: "Bitcoin", - Decimals: 8, - BlockTime: 600000, - MinConfirmations: 0, - SampleAddr: "bc1quvuarfksewfeuevuc6tn0kfyptgjvwsvrprk9d", - }, - LTC: { - ID: 2, - Handle: "litecoin", - Symbol: "LTC", - Name: "Litecoin", - Decimals: 8, - BlockTime: 150000, - MinConfirmations: 0, - SampleAddr: "ltc1qhd8fxxp2dx3vsmpac43z6ev0kllm4n53t5sk0u", - }, - DOGE: { - ID: 3, - Handle: "doge", - Symbol: "DOGE", - Name: "Dogecoin", - Decimals: 8, - BlockTime: 60000, - MinConfirmations: 0, - SampleAddr: "DJRFZNg8jkUtjcpo2zJd92FUAzwRjitw6f", - }, - DASH: { - ID: 5, - Handle: "dash", - Symbol: "DASH", - Name: "Dash", - Decimals: 8, - BlockTime: 180000, - MinConfirmations: 0, - SampleAddr: "XqHiz8EXYbTAtBEYs4pWTHh7ipEDQcNQeT", - }, - VIA: { - ID: 14, - Handle: "viacoin", - Symbol: "VIA", - Name: "Viacoin", - Decimals: 8, - BlockTime: 15000, - MinConfirmations: 0, - SampleAddr: "via1qnmsgjd6cvfprnszdgmyg9kewtjfgqflz67wwhc", - }, - GRS: { - ID: 17, - Handle: "groestlcoin", - Symbol: "GRS", - Name: "Groestlcoin", - Decimals: 8, - BlockTime: 60000, - MinConfirmations: 0, - SampleAddr: "grs1qexwmshts5pdpeqglkl39zyl6693tmfwp0cue4j", - }, - ZEC: { - ID: 133, - Handle: "zcash", - Symbol: "ZEC", - Name: "Zcash", - Decimals: 8, - BlockTime: 150000, - MinConfirmations: 0, - SampleAddr: "t1YYnByMzdGhQv3W3rnjHMrJs6HH4Y231gy", - }, - XZC: { - ID: 136, - Handle: "zcoin", - Symbol: "XZC", - Name: "Zcoin", - Decimals: 8, - BlockTime: 300000, - MinConfirmations: 0, - SampleAddr: "aEd5XFChyXobvEics2ppAqgK3Bgusjxtik", - }, - BCH: { - ID: 145, - Handle: "bitcoincash", - Symbol: "BCH", - Name: "Bitcoin Cash", - Decimals: 8, - BlockTime: 600000, - MinConfirmations: 0, - SampleAddr: "bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme", - }, - RVN: { - ID: 175, - Handle: "ravencoin", - Symbol: "RVN", - Name: "Raven", - Decimals: 8, - BlockTime: 60000, - MinConfirmations: 0, - SampleAddr: "RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo", - }, - QTUM: { - ID: 2301, - Handle: "qtum", - Symbol: "QTUM", - Name: "Qtum", - Decimals: 8, - BlockTime: 60000, - MinConfirmations: 0, - SampleAddr: "QhceuaTdeCZtcxmVc6yyEDEJ7Riu5gWFoF", - }, - ZEL: { - ID: 19167, - Handle: "zelcash", - Symbol: "ZEL", - Name: "Zelcash", - Decimals: 8, - BlockTime: 120000, - MinConfirmations: 0, - SampleAddr: "t1UKbRPzL4WN8Rs8aZ8RNiWoD2ftCMHKGUf", - }, - DCR: { - ID: 42, - Handle: "decred", - Symbol: "DCR", - Name: "Decred", - Decimals: 8, - BlockTime: 300000, - MinConfirmations: 0, - SampleAddr: "DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", - }, - ALGO: { - ID: 283, - Handle: "algorand", - Symbol: "ALGO", - Name: "Algorand", - Decimals: 6, - BlockTime: 20000, - MinConfirmations: 0, - SampleAddr: "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", - }, - NANO: { - ID: 165, - Handle: "nano", - Symbol: "NANO", - Name: "Nano", - Decimals: 30, - BlockTime: 0, - MinConfirmations: 0, - SampleAddr: "nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw", - }, - DGB: { - ID: 20, - Handle: "digibyte", - Symbol: "DGB", - Name: "DigiByte", - Decimals: 8, - BlockTime: 15000, - MinConfirmations: 0, - SampleAddr: "D8NBg12kfW8uLjzCv7LYnPYCNhqvVtHaMQ", - }, - ONE: { - ID: 1023, - Handle: "harmony", - Symbol: "ONE", - Name: "Harmony", - Decimals: 18, - BlockTime: 5000, - MinConfirmations: 0, - SampleAddr: "one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk", - }, - KSM: { - ID: 434, - Handle: "kusama", - Symbol: "KSM", - Name: "Kusama", - Decimals: 12, - BlockTime: 6000, - MinConfirmations: 0, - SampleAddr: "HewiDTQv92L2bVtkziZC8ASxrFUxr6ajQ62RXAnwQ8FDVmg", - }, - DOT: { - ID: 354, - Handle: "polkadot", - Symbol: "DOT", - Name: "Polkadot", - Decimals: 10, - BlockTime: 6000, - MinConfirmations: 0, - SampleAddr: "13SkL2uACPqBzpKBh3d2n5msYNFB2QapA5vEDeKeLjG2LS3Y", - }, - SOL: { - ID: 501, - Handle: "solana", - Symbol: "SOL", - Name: "Solana", - Decimals: 9, - BlockTime: 500, - MinConfirmations: 0, - SampleAddr: "boot1Z6jb15CLqpaMTn2CxktktwZpRAVAgHZEW6SxQ7", - }, - NEAR: { - ID: 397, - Handle: "near", - Symbol: "NEAR", - Name: "NEAR", - Decimals: 18, - BlockTime: 2000, - MinConfirmations: 0, - SampleAddr: "NEAR6Y66fCzeKqWiwxoPox5oGeDN9VhNCu7CEQ9M86iniqoN9vg2X", - }, - ERD: { - ID: 508, - Handle: "elrond", - Symbol: "ERD", - Name: "Elrond", - Decimals: 18, - BlockTime: 6000, - MinConfirmations: 0, - SampleAddr: "erd12tqtt5zcg6vpw65y4hkanvt49kzq695sr3ctuszjy92xw0ppzcssy2xd5r", - }, - BSCLegacy: { - ID: 10000714, - Handle: "bsc", - Symbol: "BNB", - PreferedSymbol: "BSCLegacy", - Name: "Binance Smart Chain", - Decimals: 18, - BlockTime: 3000, - MinConfirmations: 0, - SampleAddr: "0x35552c16704d214347f29Fa77f77DA6d75d7C752", - }, - BSC: { - ID: 20000714, - Handle: "smartchain", - Symbol: "BNB", - PreferedSymbol: "BSC", - Name: "Binance Smart Chain", - Decimals: 18, - BlockTime: 3000, - MinConfirmations: 0, - SampleAddr: "0x35552c16704d214347f29Fa77f77DA6d75d7C752", - }, -} -func Ethereum() Coin { - return Coins[ETH] -} -func Classic() Coin { - return Coins[ETC] -} -func Icon() Coin { - return Coins[ICX] -} -func Cosmos() Coin { - return Coins[ATOM] -} -func Ripple() Coin { - return Coins[XRP] -} -func Stellar() Coin { - return Coins[XLM] -} -func Poa() Coin { - return Coins[POA] -} -func Tron() Coin { - return Coins[TRX] -} -func Fio() Coin { - return Coins[FIO] -} -func Nimiq() Coin { - return Coins[NIM] -} -func Iotex() Coin { - return Coins[IOTX] -} -func Zilliqa() Coin { - return Coins[ZIL] -} -func Aion() Coin { - return Coins[AION] -} -func Aeternity() Coin { - return Coins[AE] -} -func Kava() Coin { - return Coins[KAVA] -} -func Theta() Coin { - return Coins[THETA] -} -func Binance() Coin { - return Coins[BNB] -} -func Vechain() Coin { - return Coins[VET] -} -func Callisto() Coin { - return Coins[CLO] -} -func Tomochain() Coin { - return Coins[TOMO] -} -func Thundertoken() Coin { - return Coins[TT] -} -func Ontology() Coin { - return Coins[ONT] -} -func Tezos() Coin { - return Coins[XTZ] -} -func Kin() Coin { - return Coins[KIN] -} -func Nebulas() Coin { - return Coins[NAS] -} -func Gochain() Coin { - return Coins[GO] -} -func Wanchain() Coin { - return Coins[WAN] -} -func Waves() Coin { - return Coins[WAVES] -} -func Bitcoin() Coin { - return Coins[BTC] -} -func Litecoin() Coin { - return Coins[LTC] -} -func Doge() Coin { - return Coins[DOGE] -} -func Dash() Coin { - return Coins[DASH] -} -func Viacoin() Coin { - return Coins[VIA] -} -func Groestlcoin() Coin { - return Coins[GRS] -} -func Zcash() Coin { - return Coins[ZEC] -} -func Zcoin() Coin { - return Coins[XZC] -} -func Bitcoincash() Coin { - return Coins[BCH] -} -func Ravencoin() Coin { - return Coins[RVN] -} -func Qtum() Coin { - return Coins[QTUM] -} -func Zelcash() Coin { - return Coins[ZEL] -} -func Decred() Coin { - return Coins[DCR] -} -func Algorand() Coin { - return Coins[ALGO] -} -func Nano() Coin { - return Coins[NANO] -} -func Digibyte() Coin { - return Coins[DGB] -} -func Harmony() Coin { - return Coins[ONE] -} -func Kusama() Coin { - return Coins[KSM] -} -func Polkadot() Coin { - return Coins[DOT] -} -func Solana() Coin { - return Coins[SOL] -} -func Near() Coin { - return Coins[NEAR] -} -func Elrond() Coin { - return Coins[ERD] -} -func Bsc() Coin { - return Coins[BSCLegacy] -} -func Smartchain() Coin { - return Coins[BSC] -} - diff --git a/coin/coins.yml b/coin/coins.yml deleted file mode 100644 index f8bc3c880..000000000 --- a/coin/coins.yml +++ /dev/null @@ -1,416 +0,0 @@ -- id: 60 - symbol: ETH - handle: ethereum - name: Ethereum - decimals: 18 - blockTime: 10000 - sampleAddress: '0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1' - -- id: 61 - symbol: ETC - handle: classic - name: Ethereum Classic - decimals: 18 - blockTime: 30000 - sampleAddress: '0xf3524415b6D873205B4c3Cda783527b2aC4daAA9' - -- id: 74 - symbol: ICX - handle: icon - name: ICON - decimals: 18 - sampleAddress: 'hxee691e7bccc4eb11fee922896e9f51490e62b12e' - -- id: 118 - symbol: ATOM - handle: cosmos - name: Cosmos - decimals: 6 - blockTime: 5000 - sampleAddress: 'cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl' - -- id: 144 - symbol: XRP - handle: ripple - name: Ripple - decimals: 6 - blockTime: 5000 - sampleAddress: 'rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1' - -- id: 148 - symbol: XLM - handle: stellar - name: Stellar - decimals: 7 - blockTime: 5000 - sampleAddress: 'GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX' - -- id: 178 - symbol: POA - handle: poa - name: Poa - decimals: 18 - blockTime: 30000 - sampleAddress: '0x1fddEc96688e0538A316C64dcFd211c491ECf0d8' - -- id: 195 - symbol: TRX - handle: tron - name: Tron - decimals: 6 - blockTime: 10000 - sampleAddress: 'TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9' - -- id: 235 - symbol: FIO - handle: fio - name: FIO - decimals: 9 - sampleAddress: 'FIO5J2xdfWygeNdHZNZRzRws8YGbVxjUXtp4eP8KoGkGKoLFQ7CaU' - -- id: 242 - symbol: NIM - handle: nimiq - name: Nimiq - decimals: 5 - blockTime: 60000 - sampleAddress: 'NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA' - -- id: 304 - symbol: IOTX - handle: iotex - name: IoTeX - decimals: 18 - blockTime: 10000 - sampleAddress: 'io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m' - -- id: 313 - symbol: ZIL - handle: zilliqa - name: Zilliqa - decimals: 12 - blockTime: 30000 - minConfirmations: 1 - sampleAddress: 'zil1anrjcsj2ntklaa3arq4w3s6gw4l4hqrycs9egy' - -- id: 425 - symbol: AION - handle: aion - name: Aion - decimals: 18 - blockTime: 10000 - sampleAddress: '0xa07981da70ce919e1db5f051c3c386eb526e6ce8b9e2bfd56e3f3d754b0a17f3' - -- id: 457 - symbol: AE - handle: aeternity - name: Aeternity - decimals: 18 - blockTime: 6000 - sampleAddress: 'ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw' - -- id: 459 - symbol: KAVA - handle: kava - name: Kava - decimals: 6 - blockTime: 5000 - sampleAddress: 'kava13fxkk4730cqglgdv7w0mdelyx07myyq7h2nd3x' - -- id: 500 - symbol: THETA - handle: theta - name: Theta - decimals: 18 - sampleAddress: '0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f' - -- id: 714 - symbol: BNB - handle: binance - name: BNB - decimals: 8 - blockTime: 4000 - minConfirmations: 2 - sampleAddress: 'tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2' - -- id: 818 - symbol: VET - handle: vechain - name: VeChain Token - decimals: 18 - blockTime: 20000 - sampleAddress: '0xB5e883349e68aB59307d1604555AC890fAC47128' - -- id: 820 - symbol: CLO - handle: callisto - name: Callisto - decimals: 18 - blockTime: 10000 - sampleAddress: '0x39ec1c88a7a7c1a575e8c8f42eff7630d9278179' - -- id: 889 - symbol: TOMO - handle: tomochain - name: TOMO - blockTime: 4000 - decimals: 18 - sampleAddress: '0x7daa83030e3086477b79b6e757ca8608899fe783' - -- id: 1001 - symbol: TT - handle: thundertoken - name: ThunderCore - decimals: 18 - blockTime: 10000 - sampleAddress: '0x0ad80a408eac4f17ba0a9de8a12d8736f60700c3' - -- id: 1024 - symbol: ONT - handle: ontology - name: Ontology - decimals: 0 - blockTime: 10000 - sampleAddress: 'AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7' - -- id: 1729 - symbol: XTZ - handle: tezos - name: Tezos - decimals: 6 - blockTime: 20000 - sampleAddress: 'tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q' - -- id: 2017 - symbol: KIN - handle: kin - name: Kin - decimals: 5 - blockTime: 5000 - sampleAddress: 'GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH' - -- id: 2718 - symbol: NAS - handle: nebulas - name: Nebulas - decimals: 18 - blockTime: 30000 - sampleAddress: 'n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a' - -- id: 6060 - symbol: GO - handle: gochain - name: GoChain GO - decimals: 18 - blockTime: 20000 - sampleAddress: '0x76c2F81716A8D198a00502Ae9a59126418899FDe' - -- id: 5718350 - symbol: WAN - handle: wanchain - name: Wanchain - decimals: 18 - blockTime: 30000 - sampleAddress: '0x36cEdc3A9d969306AF4F7CA2b83ABBf74095914d' - -- id: 5741564 - symbol: WAVES - handle: waves - name: WAVES - decimals: 8 - blockTime: 30000 - minConfirmations: 1 - sampleAddress: '3P7wz6TXienpw3BHe8eHUEuZWb6WE58kgnQ' - -- id: 0 - symbol: BTC - handle: bitcoin - name: Bitcoin - decimals: 8 - blockTime: 600000 - sampleAddress: 'bc1quvuarfksewfeuevuc6tn0kfyptgjvwsvrprk9d' - -- id: 2 - symbol: LTC - handle: litecoin - name: Litecoin - decimals: 8 - blockTime: 150000 - sampleAddress: 'ltc1qhd8fxxp2dx3vsmpac43z6ev0kllm4n53t5sk0u' - -- id: 3 - symbol: DOGE - handle: doge - name: Dogecoin - decimals: 8 - blockTime: 60000 - sampleAddress: 'DJRFZNg8jkUtjcpo2zJd92FUAzwRjitw6f' - -- id: 5 - symbol: DASH - handle: dash - name: Dash - decimals: 8 - blockTime: 180000 - sampleAddress: 'XqHiz8EXYbTAtBEYs4pWTHh7ipEDQcNQeT' - -- id: 14 - symbol: VIA - handle: viacoin - name: Viacoin - decimals: 8 - blockTime: 15000 - sampleAddress: 'via1qnmsgjd6cvfprnszdgmyg9kewtjfgqflz67wwhc' - -- id: 17 - symbol: GRS - handle: groestlcoin - name: Groestlcoin - decimals: 8 - blockTime: 60000 - sampleAddress: 'grs1qexwmshts5pdpeqglkl39zyl6693tmfwp0cue4j' - -- id: 133 - symbol: ZEC - handle: zcash - name: Zcash - decimals: 8 - blockTime: 150000 - sampleAddress: 't1YYnByMzdGhQv3W3rnjHMrJs6HH4Y231gy' - -- id: 136 - symbol: XZC - handle: zcoin - name: Zcoin - decimals: 8 - blockTime: 300000 - sampleAddress: 'aEd5XFChyXobvEics2ppAqgK3Bgusjxtik' - -- id: 145 - symbol: BCH - handle: bitcoincash - name: Bitcoin Cash - decimals: 8 - blockTime: 600000 - sampleAddress: 'bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme' - -- id: 175 - symbol: RVN - handle: ravencoin - name: Raven - decimals: 8 - blockTime: 60000 - sampleAddress: 'RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo' - -- id: 2301 - symbol: QTUM - handle: qtum - name: Qtum - decimals: 8 - blockTime: 60000 - sampleAddress: 'QhceuaTdeCZtcxmVc6yyEDEJ7Riu5gWFoF' - -- id: 19167 - symbol: ZEL - handle: zelcash - name: Zelcash - decimals: 8 - blockTime: 120000 - sampleAddress: 't1UKbRPzL4WN8Rs8aZ8RNiWoD2ftCMHKGUf' - -- id: 42 - symbol: DCR - handle: decred - name: Decred - decimals: 8 - blockTime: 300000 - sampleAddress: 'DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY' - -- id: 283 - symbol: ALGO - handle: algorand - name: Algorand - decimals: 6 - blockTime: 20000 - sampleAddress: '4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U' - -- id: 165 - symbol: NANO - handle: nano - name: Nano - decimals: 30 - sampleAddress: 'nano_1trqphog5noig7z888asnjejcie8z1iopxyepcjdo1atps8whxiuwd51ehbw' - -- id: 20 - symbol: DGB - handle: digibyte - name: DigiByte - decimals: 8 - blockTime: 15000 - sampleAddress: 'D8NBg12kfW8uLjzCv7LYnPYCNhqvVtHaMQ' - -- id: 1023 - symbol: ONE - handle: harmony - name: Harmony - decimals: 18 - blockTime: 5000 - sampleAddress: 'one1syjs6cnfwd9fgrhng03dyzs07suwtywwreczmk' - -- id: 434 - symbol: KSM - handle: kusama - name: Kusama - decimals: 12 - blockTime: 6000 - sampleAddress: 'HewiDTQv92L2bVtkziZC8ASxrFUxr6ajQ62RXAnwQ8FDVmg' - -- id: 354 - symbol: DOT - handle: polkadot - name: Polkadot - decimals: 10 - blockTime: 6000 - sampleAddress: '13SkL2uACPqBzpKBh3d2n5msYNFB2QapA5vEDeKeLjG2LS3Y' - -- id: 501 - symbol: SOL - handle: solana - name: Solana - decimals: 9 - blockTime: 500 - sampleAddress: 'boot1Z6jb15CLqpaMTn2CxktktwZpRAVAgHZEW6SxQ7' - -- id: 397 - symbol: NEAR - handle: near - name: NEAR - decimals: 18 - blockTime: 2000 - sampleAddress: 'NEAR6Y66fCzeKqWiwxoPox5oGeDN9VhNCu7CEQ9M86iniqoN9vg2X' - -- id: 508 - symbol: ERD - handle: elrond - name: Elrond - decimals: 18 - blockTime: 6000 - sampleAddress: 'erd12tqtt5zcg6vpw65y4hkanvt49kzq695sr3ctuszjy92xw0ppzcssy2xd5r' - -- id: 10000714 - symbol: BNB - preferedSymbol: BSCLegacy - handle: bsc - name: 'Binance Smart Chain' - decimals: 18 - blockTime: 3000 - sampleAddress: '0x35552c16704d214347f29Fa77f77DA6d75d7C752' - -- id: 20000714 - symbol: BNB - preferedSymbol: BSC - handle: smartchain - name: 'Binance Smart Chain' - decimals: 18 - blockTime: 3000 - sampleAddress: '0x35552c16704d214347f29Fa77f77DA6d75d7C752' diff --git a/coin/gen.go b/coin/gen.go deleted file mode 100644 index 665740291..000000000 --- a/coin/gen.go +++ /dev/null @@ -1,145 +0,0 @@ -// +build coins - -//go:generate rm -f coins.go -//go:generate go run gen.go - -package main - -import ( - "html/template" - "log" - "os" - "strings" - "time" - - "gopkg.in/yaml.v2" -) - -const ( - coinFile = "coins.yml" - filename = "coins.go" - templateFile = `// Code generated by go generate; DO NOT EDIT. -// This file was generated by robots at -// {{ .Timestamp }} -// using data from coins.yml -package coin - -import ( - "fmt" -) - -// Coin is the native currency of a blockchain -type Coin struct { - ID uint - Handle string - Symbol string - PreferedSymbol string - Name string - Decimals uint - BlockTime int - MinConfirmations int64 - SampleAddr string -} - -func (c *Coin) String() string { - return fmt.Sprintf("[%s] %s (#%d)", c.Symbol, c.Name, c.ID) -} - -const ( -{{- range .Coins }} -{{- if .PreferedSymbol}} - {{ .PreferedSymbol }} = {{ .ID }} -{{- else}} - {{ .Symbol }} = {{ .ID }} -{{- end}} -{{- end }} -) - -var Coins = map[uint]Coin{ -{{- range .Coins }} -{{- if .PreferedSymbol }} - {{ .PreferedSymbol }}: { -{{- else }} - {{ .Symbol }}: { -{{- end }} - ID: {{.ID}}, - Handle: "{{.Handle}}", - Symbol: "{{.Symbol}}", -{{- if .PreferedSymbol }} - PreferedSymbol: "{{.PreferedSymbol}}", -{{- end }} - Name: "{{.Name}}", - Decimals: {{.Decimals}}, - BlockTime: {{.BlockTime}}, - MinConfirmations: {{.MinConfirmations}}, - SampleAddr: "{{.SampleAddr}}", - }, -{{- end }} -} - -{{- range .Coins }} -func {{ .Handle.Capitalize }}() Coin { -{{- if .PreferedSymbol }} - return Coins[{{ .PreferedSymbol }}] -{{- else }} - return Coins[{{ .Symbol }}] -{{- end}} -} - -{{- end }} - -` -) - -type Handle string - -func (h Handle) Capitalize() string { - return strings.Title(string(h)) -} - -type Coin struct { - ID uint `yaml:"id"` - Handle Handle `yaml:"handle"` - Symbol string `yaml:"symbol"` - PreferedSymbol string `yaml:"preferedSymbol,omitempty"` - Name string `yaml:"name"` - Decimals uint `yaml:"decimals"` - BlockTime int `yaml:"blockTime"` - MinConfirmations int64 `yaml:"minConfirmations"` - SampleAddr string `yaml:"sampleAddress"` -} - -func main() { - coinFile := getValidParameter("COIN_FILE", coinFile) - var coinList []Coin - coin, err := os.Open(coinFile) - dec := yaml.NewDecoder(coin) - err = dec.Decode(&coinList) - if err != nil { - log.Panic(err) - } - - goFile := getValidParameter("COIN_GO_FILE", filename) - f, err := os.Create(goFile) - if err != nil { - log.Panic(err) - } - defer f.Close() - - coinsTemplate := template.Must(template.New("").Parse(templateFile)) - err = coinsTemplate.Execute(f, map[string]interface{}{ - "Timestamp": time.Now(), - "Coins": coinList, - }) - if err != nil { - log.Panic(err) - } -} - -func getValidParameter(env, variable string) string { - e, ok := os.LookupEnv(env) - if ok { - return e - } - return variable -} diff --git a/coin/gen_test.go b/coin/gen_test.go deleted file mode 100644 index e4229aec0..000000000 --- a/coin/gen_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package coin - -import ( - "fmt" - "io/ioutil" - "os" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v2" -) - -const ( - coinFile = "coins.yml" - filename = "coins.go" -) - -type TestCoin struct { - ID uint `yaml:"id"` - Handle string `yaml:"handle"` - Symbol string `yaml:"symbol"` - PreferedSymbol string `yaml:"preferedSymbol,omitempty"` - Name string `yaml:"name"` - Decimals uint `yaml:"decimals"` - BlockTime int `yaml:"blockTime"` - MinConfirmations int64 `yaml:"minConfirmations"` - SampleAddr string `yaml:"sampleAddress"` -} - -func TestFilesExists(t *testing.T) { - assert.True(t, assert.FileExists(t, coinFile)) - assert.True(t, assert.FileExists(t, filename)) -} - -func TestCoinFile(t *testing.T) { - var coinList []TestCoin - coin, err := os.Open(coinFile) - if err != nil { - t.Error(err) - } - dec := yaml.NewDecoder(coin) - err = dec.Decode(&coinList) - if err != nil { - t.Error(err) - } - - f, err := os.Open(filename) - if err != nil { - t.Error(err) - } - defer f.Close() - b, err := ioutil.ReadAll(f) - if err != nil { - t.Error(err) - } - code := string(b) - - for _, want := range coinList { - got, ok := Coins[want.ID] - assert.True(t, ok) - assert.Equal(t, got.ID, want.ID) - assert.Equal(t, got.Handle, want.Handle) - assert.Equal(t, got.Symbol, want.Symbol) - assert.Equal(t, got.Name, want.Name) - assert.Equal(t, got.Decimals, want.Decimals) - assert.Equal(t, got.BlockTime, want.BlockTime) - assert.Equal(t, got.MinConfirmations, want.MinConfirmations) - assert.Equal(t, got.SampleAddr, want.SampleAddr) - - s := strings.Title(want.Handle) - method := fmt.Sprintf("func %s() Coin", s) - assert.True(t, strings.Contains(code, method), "Coin method not found") - var enum string - if want.PreferedSymbol != "" { - enum = fmt.Sprintf("%s = %d", want.PreferedSymbol, want.ID) - } else { - enum = fmt.Sprintf("%s = %d", want.Symbol, want.ID) - } - assert.True(t, strings.Contains(code, enum), "Coin enum not found") - - } -} - -func TestEthereum(t *testing.T) { - - c := Ethereum() - - assert.Equal(t, uint(60), c.ID) - assert.Equal(t, "ethereum", c.Handle) - assert.Equal(t, "ETH", c.Symbol) - assert.Equal(t, "Ethereum", c.Name) - assert.Equal(t, uint(18), c.Decimals) - assert.Equal(t, 10000, c.BlockTime) - assert.Equal(t, int64(0), c.MinConfirmations) -} diff --git a/coin/models.go b/coin/models.go deleted file mode 100644 index 06429cfe4..000000000 --- a/coin/models.go +++ /dev/null @@ -1,17 +0,0 @@ -package coin - -type ExternalCoin struct { - Coin uint `json:"coin"` - Symbol string `json:"symbol"` - Name string `json:"name"` - Decimals uint `json:"decimals"` -} - -func (c *Coin) External() *ExternalCoin { - return &ExternalCoin{ - Coin: c.ID, - Name: c.Name, - Symbol: c.Symbol, - Decimals: c.Decimals, - } -} diff --git a/config.yml b/config.yml index 59b0e6892..4f06471f0 100644 --- a/config.yml +++ b/config.yml @@ -233,6 +233,8 @@ near: elrond: api: https://api.elrond.com +filecoin: + api: https://api.filscan.io:8700/rpc/v1 # bsc: # api: # rpc: diff --git a/go.mod b/go.mod index 3031c15af..ab171ffa1 100644 --- a/go.mod +++ b/go.mod @@ -22,13 +22,14 @@ require ( github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 github.com/trustwallet/ens-coincodec v1.0.6 + github.com/trustwallet/golibs v0.0.8 github.com/trustwallet/watchmarket v1.1.1 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmhttp v1.8.0 go.elastic.co/apm/module/apmlogrus v1.8.0 go.uber.org/atomic v1.7.0 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 + golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f gopkg.in/yaml.v2 v2.3.0 gorm.io/driver/postgres v1.0.0 diff --git a/go.sum b/go.sum index 5be382ee8..36c615607 100644 --- a/go.sum +++ b/go.sum @@ -518,6 +518,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/trustwallet/blockatlas v1.1.7-0.20200831100332-b573ace18512/go.mod h1:rq6APqrT+vR58h+WWrCyadT80QDKmDEJvHDllWSUwnM= github.com/trustwallet/ens-coincodec v1.0.6 h1:ZPvFDJwvv4s+XCnUM7pzub8wYHy37tyJBNtKvgx9FDs= github.com/trustwallet/ens-coincodec v1.0.6/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= +github.com/trustwallet/golibs v0.0.8 h1:eviuHKqIXDs+DGgWNHF/gNTrV6jmJTfYYEHVbCeniWE= +github.com/trustwallet/golibs v0.0.8/go.mod h1:QB6tQe5tvZOAPmvpeaveFwCQpTqdelSgO6UlMZN30Co= github.com/trustwallet/watchmarket v1.1.1 h1:gErSfLLDhEblFqvW8V3RyzRqq4R6MCYEDWjO6j5uJfE= github.com/trustwallet/watchmarket v1.1.1/go.mod h1:DvqzLzxXOaZajbkryVZcNgBS4yibZhk3rCc41ZSJEBs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -590,6 +592,8 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= diff --git a/pkg/address/address.go b/pkg/address/address.go index 34a08f7e0..9096fd6e2 100644 --- a/pkg/address/address.go +++ b/pkg/address/address.go @@ -4,9 +4,9 @@ import ( "crypto/sha256" "encoding/hex" "github.com/mr-tron/base58" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/golibs/coin" "golang.org/x/crypto/sha3" "strconv" "strings" diff --git a/pkg/address/address_test.go b/pkg/address/address_test.go index e1c8cda52..8c60ecc50 100644 --- a/pkg/address/address_test.go +++ b/pkg/address/address_test.go @@ -2,7 +2,7 @@ package address import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/pkg/blockatlas/marshal_test.go b/pkg/blockatlas/marshal_test.go index 68566e110..96d683afc 100644 --- a/pkg/blockatlas/marshal_test.go +++ b/pkg/blockatlas/marshal_test.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" "reflect" "sort" "testing" diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 296c3c103..a4f28c455 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -1,7 +1,7 @@ package blockatlas import ( - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" ) type ( diff --git a/pkg/blockatlas/staking.go b/pkg/blockatlas/staking.go index 94f315126..3f82b1fe6 100644 --- a/pkg/blockatlas/staking.go +++ b/pkg/blockatlas/staking.go @@ -1,6 +1,6 @@ package blockatlas -import "github.com/trustwallet/blockatlas/coin" +import "github.com/trustwallet/golibs/coin" const ( DelegationStatusActive DelegationStatus = "active" diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index fd03e28bb..f90d923e8 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -2,9 +2,9 @@ package blockatlas import ( mapset "github.com/deckarep/golang-set" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/blockatlas/services/spamfilter" + "github.com/trustwallet/golibs/coin" "sort" "strings" ) diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 88074e8cf..a737f5ca9 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/services/spamfilter" + "github.com/trustwallet/golibs/coin" "sort" "testing" ) diff --git a/platform/aeternity/base.go b/platform/aeternity/base.go index bf412ce27..ea445b5e8 100644 --- a/platform/aeternity/base.go +++ b/platform/aeternity/base.go @@ -1,8 +1,8 @@ package aeternity import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/aeternity/transaction.go b/platform/aeternity/transaction.go index 2d904c9e1..1e67e5c50 100644 --- a/platform/aeternity/transaction.go +++ b/platform/aeternity/transaction.go @@ -2,9 +2,9 @@ package aeternity import ( "encoding/base64" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/coin" "strings" ) diff --git a/platform/aeternity/transaction_test.go b/platform/aeternity/transaction_test.go index 8392602d3..4b4a6f153 100644 --- a/platform/aeternity/transaction_test.go +++ b/platform/aeternity/transaction_test.go @@ -3,8 +3,8 @@ package aeternity import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/aion/base.go b/platform/aion/base.go index 1e7fa8487..6b5e2db3f 100644 --- a/platform/aion/base.go +++ b/platform/aion/base.go @@ -1,8 +1,8 @@ package aion import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/aion/transaction.go b/platform/aion/transaction.go index d1bc7c31f..b20d93d39 100644 --- a/platform/aion/transaction.go +++ b/platform/aion/transaction.go @@ -1,9 +1,9 @@ package aion import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/coin" "strconv" ) diff --git a/platform/aion/transaction_test.go b/platform/aion/transaction_test.go index dbaff0539..43e09bafa 100644 --- a/platform/aion/transaction_test.go +++ b/platform/aion/transaction_test.go @@ -3,8 +3,8 @@ package aion import ( "bytes" "encoding/json" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/algorand/base.go b/platform/algorand/base.go index 3dd9cde67..019b5354a 100644 --- a/platform/algorand/base.go +++ b/platform/algorand/base.go @@ -1,8 +1,8 @@ package algorand import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/algorand/transaction.go b/platform/algorand/transaction.go index 9a25e24bb..2eb677a06 100644 --- a/platform/algorand/transaction.go +++ b/platform/algorand/transaction.go @@ -3,8 +3,8 @@ package algorand import ( "strconv" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/algorand/transaction_test.go b/platform/algorand/transaction_test.go index bddec1400..d5b09eb99 100644 --- a/platform/algorand/transaction_test.go +++ b/platform/algorand/transaction_test.go @@ -3,8 +3,8 @@ package algorand import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/binance/base.go b/platform/binance/base.go index a7a9ed430..e39ec58cc 100644 --- a/platform/binance/base.go +++ b/platform/binance/base.go @@ -1,7 +1,7 @@ package binance import ( - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/binance/model.go b/platform/binance/model.go index 6c3170925..a3e0a3aa8 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -1,9 +1,9 @@ package binance import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/coin" "strconv" "strings" "time" diff --git a/platform/binance/transaction.go b/platform/binance/transaction.go index cffbb7e82..ca73e1584 100644 --- a/platform/binance/transaction.go +++ b/platform/binance/transaction.go @@ -1,8 +1,8 @@ package binance import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/bitcoin/base.go b/platform/bitcoin/base.go index ada173e4d..ae0a2f871 100644 --- a/platform/bitcoin/base.go +++ b/platform/bitcoin/base.go @@ -1,8 +1,8 @@ package bitcoin import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/bitcoin/transaction.go b/platform/bitcoin/transaction.go index 25b98ec21..7adeb2a1d 100644 --- a/platform/bitcoin/transaction.go +++ b/platform/bitcoin/transaction.go @@ -4,9 +4,9 @@ import ( "sort" mapset "github.com/deckarep/golang-set" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/coin" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/bitcoin/transaction_test.go b/platform/bitcoin/transaction_test.go index 4fe8065f3..11a681872 100644 --- a/platform/bitcoin/transaction_test.go +++ b/platform/bitcoin/transaction_test.go @@ -8,8 +8,8 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) const outgoingTx = `{ diff --git a/platform/cosmos/base.go b/platform/cosmos/base.go index 3b3b92c50..b5ecc3a0c 100644 --- a/platform/cosmos/base.go +++ b/platform/cosmos/base.go @@ -1,8 +1,8 @@ package cosmos import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index 09515c4d1..b94887305 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -1,11 +1,11 @@ package cosmos import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/golibs/coin" "strconv" "time" ) diff --git a/platform/cosmos/transaction_test.go b/platform/cosmos/transaction_test.go index 32570c79e..d13788c6b 100644 --- a/platform/cosmos/transaction_test.go +++ b/platform/cosmos/transaction_test.go @@ -6,7 +6,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" ) const transferSrc = ` diff --git a/platform/elrond/base.go b/platform/elrond/base.go index ac154eba1..c1833c64c 100644 --- a/platform/elrond/base.go +++ b/platform/elrond/base.go @@ -1,8 +1,8 @@ package elrond import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/elrond/transaction.go b/platform/elrond/transaction.go index f56ffb995..156bf0e63 100644 --- a/platform/elrond/transaction.go +++ b/platform/elrond/transaction.go @@ -1,8 +1,8 @@ package elrond import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) const metachainID = "4294967295" diff --git a/platform/elrond/transaction_test.go b/platform/elrond/transaction_test.go index 04c11a27c..914cf60e8 100644 --- a/platform/elrond/transaction_test.go +++ b/platform/elrond/transaction_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/stretchr/testify/require" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) const userAddress = `erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0` diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index f26fa94cb..11eea4f1a 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -1,12 +1,12 @@ package ethereum import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/ethereum/blockbook" "github.com/trustwallet/blockatlas/platform/ethereum/collection" "github.com/trustwallet/blockatlas/platform/ethereum/ens" "github.com/trustwallet/blockatlas/platform/ethereum/trustray" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/ethereum/blockbook/transaction.go b/platform/ethereum/blockbook/transaction.go index e539d54b5..89f7f2e04 100644 --- a/platform/ethereum/blockbook/transaction.go +++ b/platform/ethereum/blockbook/transaction.go @@ -3,9 +3,9 @@ package blockbook import ( "strings" - "github.com/trustwallet/blockatlas/coin" Address "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) func (c *Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) { diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/collection_test.go index 661d3bc2e..797ff885e 100644 --- a/platform/ethereum/collection_test.go +++ b/platform/ethereum/collection_test.go @@ -3,9 +3,9 @@ package ethereum import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/ethereum/collection" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/ethereum/domain.go b/platform/ethereum/domain.go index faa9f57d9..7ff5c17b5 100644 --- a/platform/ethereum/domain.go +++ b/platform/ethereum/domain.go @@ -1,13 +1,13 @@ package ethereum import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/naming" "github.com/trustwallet/blockatlas/platform/ethereum/ens" "github.com/trustwallet/ens-coincodec" + "github.com/trustwallet/golibs/coin" ) func (p *Platform) CanHandle(name string) bool { diff --git a/platform/ethereum/trustray/token_test.go b/platform/ethereum/trustray/token_test.go index e7c7acc5c..ba5db892c 100644 --- a/platform/ethereum/trustray/token_test.go +++ b/platform/ethereum/trustray/token_test.go @@ -5,8 +5,8 @@ import ( "encoding/json" "testing" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) const tokenSrc = ` diff --git a/platform/ethereum/trustray/transaction.go b/platform/ethereum/trustray/transaction.go index 4e63361a6..2e52ecf75 100644 --- a/platform/ethereum/trustray/transaction.go +++ b/platform/ethereum/trustray/transaction.go @@ -3,9 +3,9 @@ package trustray import ( "math/big" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) func (c *Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) { diff --git a/platform/ethereum/trustray/transaction_test.go b/platform/ethereum/trustray/transaction_test.go index 3195abd2c..5258c956d 100644 --- a/platform/ethereum/trustray/transaction_test.go +++ b/platform/ethereum/trustray/transaction_test.go @@ -3,8 +3,8 @@ package trustray import ( "bytes" "encoding/json" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/filecoin/base.go b/platform/filecoin/base.go new file mode 100644 index 000000000..cb04661d2 --- /dev/null +++ b/platform/filecoin/base.go @@ -0,0 +1,21 @@ +package filecoin + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" +) + +type Platform struct { + client Client +} + +func Init(api string) *Platform { + p := &Platform{ + client: Client{blockatlas.InitClient(api)}, + } + return p +} + +func (p *Platform) Coin() coin.Coin { + return coin.Coins[coin.FIL] +} diff --git a/platform/filecoin/client.go b/platform/filecoin/client.go new file mode 100644 index 000000000..db68d5a30 --- /dev/null +++ b/platform/filecoin/client.go @@ -0,0 +1,9 @@ +package filecoin + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Client struct { + blockatlas.Request +} diff --git a/platform/filecoin/transaction.go b/platform/filecoin/transaction.go new file mode 100644 index 000000000..c4325d8b2 --- /dev/null +++ b/platform/filecoin/transaction.go @@ -0,0 +1,10 @@ +package filecoin + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + normalized := make([]blockatlas.Tx, 0) + return normalized, nil +} diff --git a/platform/fio/base.go b/platform/fio/base.go index 0f4ba28dc..aad0f32aa 100644 --- a/platform/fio/base.go +++ b/platform/fio/base.go @@ -1,8 +1,8 @@ package fio import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/fio/domain.go b/platform/fio/domain.go index ccb7fef09..389405e45 100644 --- a/platform/fio/domain.go +++ b/platform/fio/domain.go @@ -1,9 +1,9 @@ package fio import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/naming" + "github.com/trustwallet/golibs/coin" ) func (p *Platform) CanHandle(name string) bool { diff --git a/platform/harmony/base.go b/platform/harmony/base.go index 83b6ceb48..9b5b073d7 100644 --- a/platform/harmony/base.go +++ b/platform/harmony/base.go @@ -1,8 +1,8 @@ package harmony import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index 920ed2cba..1b88657e3 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -1,10 +1,10 @@ package harmony import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/coin" "strconv" ) diff --git a/platform/harmony/transaction_test.go b/platform/harmony/transaction_test.go index 42b69f69e..75861f29b 100644 --- a/platform/harmony/transaction_test.go +++ b/platform/harmony/transaction_test.go @@ -3,8 +3,8 @@ package harmony import ( "bytes" "encoding/json" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/icon/base.go b/platform/icon/base.go index d247899cd..250edd7a6 100644 --- a/platform/icon/base.go +++ b/platform/icon/base.go @@ -1,8 +1,8 @@ package icon import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/icon/transaction.go b/platform/icon/transaction.go index 350609284..ed1fc646c 100644 --- a/platform/icon/transaction.go +++ b/platform/icon/transaction.go @@ -1,11 +1,11 @@ package icon import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/coin" "time" ) diff --git a/platform/icon/transaction_test.go b/platform/icon/transaction_test.go index b6de316ba..df7735627 100644 --- a/platform/icon/transaction_test.go +++ b/platform/icon/transaction_test.go @@ -3,8 +3,8 @@ package icon import ( "bytes" "encoding/json" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/iotex/base.go b/platform/iotex/base.go index b7880f7d0..fbd9fabec 100644 --- a/platform/iotex/base.go +++ b/platform/iotex/base.go @@ -1,8 +1,8 @@ package iotex import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/iotex/transaction.go b/platform/iotex/transaction.go index 03f5086e5..d79ad52c1 100644 --- a/platform/iotex/transaction.go +++ b/platform/iotex/transaction.go @@ -5,7 +5,7 @@ import ( "strconv" "time" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/iotex/transaction_test.go b/platform/iotex/transaction_test.go index c74dde030..717fd4e6e 100644 --- a/platform/iotex/transaction_test.go +++ b/platform/iotex/transaction_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" ) const ( diff --git a/platform/kava/base.go b/platform/kava/base.go index 3ab5b4889..2552186bf 100644 --- a/platform/kava/base.go +++ b/platform/kava/base.go @@ -1,8 +1,8 @@ package kava import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/kava/stake.go b/platform/kava/stake.go index c3b120cef..47dbc313c 100644 --- a/platform/kava/stake.go +++ b/platform/kava/stake.go @@ -2,11 +2,11 @@ package kava import ( "fmt" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/golibs/coin" "strconv" "time" ) diff --git a/platform/kava/transaction_test.go b/platform/kava/transaction_test.go index 1169330cd..0419a1c31 100644 --- a/platform/kava/transaction_test.go +++ b/platform/kava/transaction_test.go @@ -6,7 +6,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" ) const transferSrc = ` diff --git a/platform/nano/base.go b/platform/nano/base.go index ed413ca1d..d76b22c1b 100644 --- a/platform/nano/base.go +++ b/platform/nano/base.go @@ -1,8 +1,8 @@ package nano import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/near/base.go b/platform/near/base.go index 53407e774..04828078b 100644 --- a/platform/near/base.go +++ b/platform/near/base.go @@ -1,8 +1,8 @@ package near import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/nebulas/base.go b/platform/nebulas/base.go index 6d41707a4..a165ba77a 100644 --- a/platform/nebulas/base.go +++ b/platform/nebulas/base.go @@ -1,8 +1,8 @@ package nebulas import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/nebulas/transaction.go b/platform/nebulas/transaction.go index c22ce5a2c..dcff7c674 100644 --- a/platform/nebulas/transaction.go +++ b/platform/nebulas/transaction.go @@ -1,8 +1,8 @@ package nebulas import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/nebulas/transaction_test.go b/platform/nebulas/transaction_test.go index 4c6126a92..c809ad5ea 100644 --- a/platform/nebulas/transaction_test.go +++ b/platform/nebulas/transaction_test.go @@ -4,8 +4,8 @@ import ( "bytes" "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/nimiq/base.go b/platform/nimiq/base.go index 855490a7e..5c845c37b 100644 --- a/platform/nimiq/base.go +++ b/platform/nimiq/base.go @@ -1,8 +1,8 @@ package nimiq import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/nimiq/transaction.go b/platform/nimiq/transaction.go index e16a14406..1d99fb63b 100644 --- a/platform/nimiq/transaction.go +++ b/platform/nimiq/transaction.go @@ -1,8 +1,8 @@ package nimiq import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "sort" "time" ) diff --git a/platform/nimiq/transaction_test.go b/platform/nimiq/transaction_test.go index ee5b822f4..40528b8b4 100644 --- a/platform/nimiq/transaction_test.go +++ b/platform/nimiq/transaction_test.go @@ -3,8 +3,8 @@ package nimiq import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "io/ioutil" "math" "path/filepath" diff --git a/platform/ontology/base.go b/platform/ontology/base.go index cd7945c0f..157f0dd68 100644 --- a/platform/ontology/base.go +++ b/platform/ontology/base.go @@ -1,8 +1,8 @@ package ontology import ( - "github.com/trustwallet/blockatlas/coin" blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/ontology/transaction.go b/platform/ontology/transaction.go index 57216401e..765319740 100644 --- a/platform/ontology/transaction.go +++ b/platform/ontology/transaction.go @@ -1,11 +1,11 @@ package ontology import ( - "github.com/trustwallet/blockatlas/coin" blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/coin" "sync" ) diff --git a/platform/ontology/transaction_test.go b/platform/ontology/transaction_test.go index 4e505018a..fe51342da 100644 --- a/platform/ontology/transaction_test.go +++ b/platform/ontology/transaction_test.go @@ -3,8 +3,8 @@ package ontology import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/platform.go b/platform/platform.go index 957ad7e81..7b0aca24c 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -3,10 +3,10 @@ package platform import ( "fmt" + "github.com/trustwallet/blockatlas/platform/filecoin" "github.com/trustwallet/blockatlas/platform/kava" "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/aeternity" "github.com/trustwallet/blockatlas/platform/aion" @@ -35,6 +35,7 @@ import ( "github.com/trustwallet/blockatlas/platform/vechain" "github.com/trustwallet/blockatlas/platform/waves" "github.com/trustwallet/blockatlas/platform/zilliqa" + "github.com/trustwallet/golibs/coin" ) const ( @@ -113,6 +114,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), coin.Near().Handle: near.Init(GetApiVar(coin.NEAR)), coin.Elrond().Handle: elrond.Init(coin.ERD, GetApiVar(coin.ERD)), + coin.Filecoin().Handle: filecoin.Init(GetApiVar(coin.FIL)), } } diff --git a/platform/polkadot/base.go b/platform/polkadot/base.go index 1aa284b27..c847a757c 100644 --- a/platform/polkadot/base.go +++ b/platform/polkadot/base.go @@ -1,8 +1,8 @@ package polkadot import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/polkadot/transaction_test.go b/platform/polkadot/transaction_test.go index 5f0930a2f..95e0a8e42 100644 --- a/platform/polkadot/transaction_test.go +++ b/platform/polkadot/transaction_test.go @@ -4,8 +4,8 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) func TestNormalizeTransfer(t *testing.T) { diff --git a/platform/ripple/base.go b/platform/ripple/base.go index ea0dfc262..339fd6899 100644 --- a/platform/ripple/base.go +++ b/platform/ripple/base.go @@ -1,8 +1,8 @@ package ripple import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/ripple/transaction.go b/platform/ripple/transaction.go index 68e054a6d..e536b1338 100644 --- a/platform/ripple/transaction.go +++ b/platform/ripple/transaction.go @@ -1,8 +1,8 @@ package ripple import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "strconv" "time" ) diff --git a/platform/ripple/transaction_test.go b/platform/ripple/transaction_test.go index 8cbc06a19..6cfdc3c6e 100644 --- a/platform/ripple/transaction_test.go +++ b/platform/ripple/transaction_test.go @@ -6,7 +6,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" ) const paymentSrc = ` diff --git a/platform/solana/base.go b/platform/solana/base.go index 88bf65bf7..6dfa983b9 100644 --- a/platform/solana/base.go +++ b/platform/solana/base.go @@ -1,8 +1,8 @@ package solana import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/stellar/base.go b/platform/stellar/base.go index fe4be7cf2..4fe753e66 100644 --- a/platform/stellar/base.go +++ b/platform/stellar/base.go @@ -1,8 +1,8 @@ package stellar import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/stellar/transaction.go b/platform/stellar/transaction.go index 001ee6fe2..14caa4375 100644 --- a/platform/stellar/transaction.go +++ b/platform/stellar/transaction.go @@ -1,9 +1,9 @@ package stellar import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/coin" "time" ) diff --git a/platform/stellar/transaction_test.go b/platform/stellar/transaction_test.go index f08661258..57c30d2fc 100644 --- a/platform/stellar/transaction_test.go +++ b/platform/stellar/transaction_test.go @@ -3,8 +3,8 @@ package stellar import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/tezos/base.go b/platform/tezos/base.go index bbb3e1c20..459d75878 100644 --- a/platform/tezos/base.go +++ b/platform/tezos/base.go @@ -1,8 +1,8 @@ package tezos import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index 023e84e65..bd5168b48 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -1,10 +1,10 @@ package tezos import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/coin" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/theta/base.go b/platform/theta/base.go index 317bdcd77..4d1a9e731 100644 --- a/platform/theta/base.go +++ b/platform/theta/base.go @@ -1,8 +1,8 @@ package theta import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/theta/transaction.go b/platform/theta/transaction.go index d96100f05..7d4d55b5d 100644 --- a/platform/theta/transaction.go +++ b/platform/theta/transaction.go @@ -2,8 +2,8 @@ package theta import ( "fmt" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "strconv" "strings" ) diff --git a/platform/theta/transaction_test.go b/platform/theta/transaction_test.go index ce9a95113..e3f521fa5 100644 --- a/platform/theta/transaction_test.go +++ b/platform/theta/transaction_test.go @@ -4,8 +4,8 @@ import ( "bytes" "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/tron/base.go b/platform/tron/base.go index 5b42418c9..361ac206c 100644 --- a/platform/tron/base.go +++ b/platform/tron/base.go @@ -1,8 +1,8 @@ package tron import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/tron/token.go b/platform/tron/token.go index 29a18d2b7..b99bb24ae 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -1,9 +1,9 @@ package tron import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/golibs/coin" "sync" "time" ) diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index 156eed36e..8fdeaab2b 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -1,11 +1,11 @@ package tron import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/golibs/coin" "strconv" ) diff --git a/platform/tron/transaction_test.go b/platform/tron/transaction_test.go index e3da6d200..52ad1bd11 100644 --- a/platform/tron/transaction_test.go +++ b/platform/tron/transaction_test.go @@ -3,8 +3,8 @@ package tron import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "net/http/httptest" "testing" ) diff --git a/platform/vechain/base.go b/platform/vechain/base.go index 19c7d3070..846f3e4a9 100644 --- a/platform/vechain/base.go +++ b/platform/vechain/base.go @@ -1,8 +1,8 @@ package vechain import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/vechain/transaction_test.go b/platform/vechain/transaction_test.go index 43fd3bb1b..06d9f780d 100644 --- a/platform/vechain/transaction_test.go +++ b/platform/vechain/transaction_test.go @@ -3,8 +3,8 @@ package vechain import ( "encoding/json" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/platform/waves/base.go b/platform/waves/base.go index 26897e990..1471ebf01 100644 --- a/platform/waves/base.go +++ b/platform/waves/base.go @@ -1,8 +1,8 @@ package waves import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/waves/transaction.go b/platform/waves/transaction.go index aafa2ea37..4ec70a2ad 100644 --- a/platform/waves/transaction.go +++ b/platform/waves/transaction.go @@ -4,7 +4,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "strconv" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/zilliqa/base.go b/platform/zilliqa/base.go index 44602f8f8..61daa8580 100644 --- a/platform/zilliqa/base.go +++ b/platform/zilliqa/base.go @@ -1,8 +1,8 @@ package zilliqa import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) type Platform struct { diff --git a/platform/zilliqa/domain.go b/platform/zilliqa/domain.go index 0cf297103..40b3001c3 100644 --- a/platform/zilliqa/domain.go +++ b/platform/zilliqa/domain.go @@ -1,9 +1,9 @@ package zilliqa import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/naming" + "github.com/trustwallet/golibs/coin" ) type ZNSResponse struct { diff --git a/platform/zilliqa/transaction.go b/platform/zilliqa/transaction.go index c18bda5d2..4d55afc5d 100644 --- a/platform/zilliqa/transaction.go +++ b/platform/zilliqa/transaction.go @@ -1,8 +1,8 @@ package zilliqa import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/zilliqa/transaction_test.go b/platform/zilliqa/transaction_test.go index 8395e71de..046fd522a 100644 --- a/platform/zilliqa/transaction_test.go +++ b/platform/zilliqa/transaction_test.go @@ -6,7 +6,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" ) const transferTransaction = ` diff --git a/services/assets/client.go b/services/assets/client.go index a70fbc916..2b03c261c 100644 --- a/services/assets/client.go +++ b/services/assets/client.go @@ -1,9 +1,9 @@ package assets import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/golibs/coin" "time" ) diff --git a/services/assets/validator.go b/services/assets/validator.go index cee5bcc58..64a12f923 100644 --- a/services/assets/validator.go +++ b/services/assets/validator.go @@ -1,10 +1,10 @@ package assets import ( - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/coin" "sort" ) diff --git a/services/assets/validator_test.go b/services/assets/validator_test.go index 84f635772..231ffa624 100644 --- a/services/assets/validator_test.go +++ b/services/assets/validator_test.go @@ -2,8 +2,8 @@ package assets import ( "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/services/notifier/models_test.go b/services/notifier/models_test.go index 0569906dd..fb2cf7dfe 100644 --- a/services/notifier/models_test.go +++ b/services/notifier/models_test.go @@ -3,8 +3,8 @@ package notifier import ( "context" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "sort" "testing" ) diff --git a/services/parser/parser_test.go b/services/parser/parser_test.go index 6b9eaee2f..60f81d72b 100644 --- a/services/parser/parser_test.go +++ b/services/parser/parser_test.go @@ -4,9 +4,9 @@ import ( "context" "errors" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "sync" "testing" "time" diff --git a/services/tokensearcher/api_test.go b/services/tokensearcher/api_test.go index 5524a3c7f..3aa7212bd 100644 --- a/services/tokensearcher/api_test.go +++ b/services/tokensearcher/api_test.go @@ -3,8 +3,8 @@ package tokensearcher import ( "errors" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" "testing" ) diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index d2fddf69f..96d235879 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -7,7 +7,7 @@ import ( "encoding/json" "github.com/streadway/amqp" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/notifier" diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index 39d00b056..0fdf43fcc 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -7,7 +7,7 @@ import ( "encoding/json" "github.com/streadway/amqp" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" + "github.com/trustwallet/golibs/coin" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/notifier" diff --git a/tests/integration/observer_test/parser_test.go b/tests/integration/observer_test/parser_test.go index 08b9d5d6b..a86fb4347 100644 --- a/tests/integration/observer_test/parser_test.go +++ b/tests/integration/observer_test/parser_test.go @@ -7,12 +7,12 @@ import ( "encoding/json" "github.com/streadway/amqp" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/coin" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/parser" "github.com/trustwallet/blockatlas/tests/integration/setup" + "github.com/trustwallet/golibs/coin" "testing" "time" ) From d440578aa5228fe08a242518fbed2e3c8682557c Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 22 Oct 2020 14:17:58 -0700 Subject: [PATCH 389/506] Update tx.go --- pkg/blockatlas/tx.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index f90d923e8..3f3f4cae8 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -3,7 +3,6 @@ package blockatlas import ( mapset "github.com/deckarep/golang-set" "github.com/trustwallet/blockatlas/pkg/numbers" - "github.com/trustwallet/blockatlas/services/spamfilter" "github.com/trustwallet/golibs/coin" "sort" "strings" @@ -229,9 +228,8 @@ func (t Txs) FilterUniqueID() Txs { func (txs TxPage) FilterTransactionsByMemo() TxPage { result := make(TxPage, 0) for _, tx := range txs { - if spamfilter.ContainsSpam(tx.Memo) { - tx.Memo = "" - } + //TODO. Temporary disable memo + tx.Memo = "" result = append(result, tx) } return result From 8f252482564051bf0d98af5352de6d4055a6d997 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 22 Oct 2020 15:22:52 -0700 Subject: [PATCH 390/506] Disable Test_filterTransactionsByMemo --- pkg/blockatlas/tx_test.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index a737f5ca9..96c888c83 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -4,7 +4,6 @@ import ( "encoding/json" mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/services/spamfilter" "github.com/trustwallet/golibs/coin" "sort" "testing" @@ -624,12 +623,12 @@ func Test_filterTransactionsByToken(t *testing.T) { assert.Equal(t, wantedTransactionsToken, string(rawResult)) } -func Test_filterTransactionsByMemo(t *testing.T) { - var p TxPage - spamfilter.SpamList = []string{"word", "free"} - assert.Nil(t, json.Unmarshal([]byte(beforeTransactionsMemo), &p)) - result := p.FilterTransactionsByMemo() - rawResult, err := json.Marshal(result) - assert.Nil(t, err) - assert.Equal(t, wantedTransactionsMemo, string(rawResult)) -} +//func Test_filterTransactionsByMemo(t *testing.T) { +// var p TxPage +// spamfilter.SpamList = []string{"word", "free"} +// assert.Nil(t, json.Unmarshal([]byte(beforeTransactionsMemo), &p)) +// result := p.FilterTransactionsByMemo() +// rawResult, err := json.Marshal(result) +// assert.Nil(t, err) +// assert.Equal(t, wantedTransactionsMemo, string(rawResult)) +//} From 8ca1fba517826f5cf97f790e7055d5eef01ccda0 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 22 Oct 2020 15:37:22 -0700 Subject: [PATCH 391/506] Disable memo (#1249) * Disable memo * Update full_flow_test.go --- pkg/blockatlas/tx_test.go | 4 ++-- tests/integration/observer_test/full_flow_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 96c888c83..5f6a25bc4 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -609,9 +609,9 @@ func TestGetEthereumTokenTypeByIndex(t *testing.T) { var ( beforeTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` - beforeTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"trust.com","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + //beforeTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"trust.com","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` wantedTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` - wantedTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + //wantedTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` ) func Test_filterTransactionsByToken(t *testing.T) { diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 96d235879..65bb41e50 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -131,7 +131,7 @@ func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel Date: 1555117625, Block: 7928667, Status: blockatlas.StatusCompleted, - Memo: "test", + Memo: "", Meta: &memo, }, }, notifications[0]) From 6eee385094bdea8ac6b53a35a9ddd884c9cb071e Mon Sep 17 00:00:00 2001 From: Ivan Frolov <45122314+jeyldii@users.noreply.github.com> Date: Sat, 24 Oct 2020 00:48:13 +0300 Subject: [PATCH 392/506] [TokenIndexer] Setup service (#1239) * Adds draft. * Adds helper func GetTokenType. * Setups token type models. * Adds tokenindexer service. Adds new que for tokenindexer. Adds CR funcs for token types. * Cleanups models annotations. Adds integration tests for token types. * Fixes model tag. * Setup token indexer * Fixes * More fixes * Fix tests * Fixes to models * Add tokenindexer * Use batch insert to add assets * Fix tests * More fixes * Update tx.go * Add Indexer CI * Cleanup * Add filter assets func for db insert to protect from non-utf8 case * Change CI * Temp add logs Co-authored-by: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Co-authored-by: Max --- .github/workflows/master.yml | 5 +- .github/workflows/pr-build.yml | 3 + Makefile | 26 +++- api/api.go | 8 +- api/endpoint/token.go | 15 ++ api/registry.go | 9 +- cmd/api/main.go | 16 ++- cmd/indexer/main.go | 61 ++++++++ cmd/parser/main.go | 14 +- db/addresstoasset.go | 60 ++++---- db/asset.go | 107 ++++++++++++++ db/db.go | 6 +- db/models/addresstoasset.go | 4 +- db/models/asset.go | 20 ++- go.mod | 3 + mq/mq.go | 11 +- pkg/blockatlas/tx.go | 94 +++++++++++++ pkg/blockatlas/tx_test.go | 61 ++++++++ platform/binance/model.go | 2 + platform/tron/token.go | 5 +- platform/tron/token_test.go | 2 +- platform/tron/transaction.go | 3 +- services/notifier/delivery.go | 5 + services/subscriber/tokens.go | 3 +- services/tokenindexer/api.go | 40 ++++++ services/tokenindexer/indexer.go | 57 ++++++++ services/tokenindexer/models.go | 18 +++ services/tokensearcher/api.go | 9 +- services/tokensearcher/api_test.go | 17 +-- services/tokensearcher/association.go | 28 ++-- services/tokensearcher/association_test.go | 46 +++--- services/tokensearcher/models.go | 11 +- .../db_test/tokenassociations_test.go | 89 +++++++----- .../integration/db_test/tokenindexer_test.go | 133 ++++++++++++++++++ 34 files changed, 848 insertions(+), 143 deletions(-) create mode 100644 cmd/indexer/main.go create mode 100644 db/asset.go create mode 100644 services/tokenindexer/api.go create mode 100644 services/tokenindexer/indexer.go create mode 100644 services/tokenindexer/models.go create mode 100644 tests/integration/db_test/tokenindexer_test.go diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 75861debc..cb473fa03 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -106,24 +106,27 @@ jobs: run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin - name: Docker Build & Push Release Images - if: steps.check_for_build.outputs.has-permission + if: steps.check.outputs.has-permission env: API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} OBSERVER_SUBSCRIBER_IMAGE: ${{ secrets.REGISTRY }}:subscriber-${{ steps.hash.outputs.sha7 }} OBSERVER_NOTIFIER_IMAGE: ${{ secrets.REGISTRY }}:notifier-${{ steps.hash.outputs.sha7 }} SEARCHER_IMAGE: ${{ secrets.REGISTRY }}:searcher-${{ steps.hash.outputs.sha7 }} + INDEXER_IMAGE: ${{ secrets.REGISTRY }}:indexer-${{ steps.hash.outputs.sha7 }} run: | docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . docker build --build-arg SERVICE=subscriber/subscriber -f Dockerfile.runner -t $OBSERVER_SUBSCRIBER_IMAGE . docker build --build-arg SERVICE=notifier/notifier -f Dockerfile.runner -t $OBSERVER_NOTIFIER_IMAGE . docker build --build-arg SERVICE=searcher/searcher -f Dockerfile.runner -t $SEARCHER_IMAGE . + docker build --build-arg SERVICE=indexer/indexer -f Dockerfile.runner -t $INDEXER_IMAGE . docker push $API_IMAGE docker push $PARSER_IMAGE docker push $OBSERVER_SUBSCRIBER_IMAGE docker push $OBSERVER_NOTIFIER_IMAGE docker push $SEARCHER_IMAGE + docker push $INDEXER_IMAGE deploy: name: CD diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 1759a5124..25e746753 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -65,14 +65,17 @@ jobs: OBSERVER_SUBSCRIBER_IMAGE: ${{ secrets.REGISTRY }}:subscriber-${{ steps.hash.outputs.sha7 }} OBSERVER_NOTIFIER_IMAGE: ${{ secrets.REGISTRY }}:notifier-${{ steps.hash.outputs.sha7 }} SEARCHER_IMAGE: ${{ secrets.REGISTRY }}:searcher-${{ steps.hash.outputs.sha7 }} + INDEXER_IMAGE: ${{ secrets.REGISTRY }}:indexer-${{ steps.hash.outputs.sha7 }} run: | docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . docker build --build-arg SERVICE=subscriber/subscriber -f Dockerfile.runner -t $OBSERVER_SUBSCRIBER_IMAGE . docker build --build-arg SERVICE=notifier/notifier -f Dockerfile.runner -t $OBSERVER_NOTIFIER_IMAGE . docker build --build-arg SERVICE=searcher/searcher -f Dockerfile.runner -t $SEARCHER_IMAGE . + docker build --build-arg SERVICE=indexer/indexer -f Dockerfile.runner -t $INDEXER_IMAGE . docker push $API_IMAGE docker push $PARSER_IMAGE docker push $OBSERVER_SUBSCRIBER_IMAGE docker push $OBSERVER_NOTIFIER_IMAGE docker push $SEARCHER_IMAGE + docker push $INDEXER_IMAGE diff --git a/Makefile b/Makefile index d630b4248..7fae89871 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ NOTIFIER := notifier PARSER := parser SUBSCRIBER := subscriber SEARCHER := searcher +INDEXER := indexer COIN_FILE := coin/coins.yml COIN_GO_FILE := coin/coins.go GEN_COIN_FILE := coin/gen.go @@ -44,6 +45,7 @@ STDERR := /tmp/.$(PROJECT_NAME)-stderr.txt # PID file will keep the process id of the server PID_API := /tmp/.$(PROJECT_NAME).$(API).pid PID_SEARCHER := /tmp/.$(PROJECT_NAME).$(SEARCHER).pid +PID_INDEXER := /tmp/.$(PROJECT_NAME).$(INDEXER).pid PID_NOTIFIER := /tmp/.$(PROJECT_NAME).$(NOTIFIER).pid PID_PARSER := /tmp/.$(PROJECT_NAME).$(PARSER).pid PID_SUBSCRIBER := /tmp/.$(PROJECT_NAME).$(SUBSCRIBER).pid @@ -72,34 +74,41 @@ start-api-mock: stop start-mockserver @cat $(PID_API) | sed "/^/s/^/ \> Mock PID: /" @echo " > Error log: $(STDERR)" -## start-observer-parser: Start observer-parser in development mode. +## start-parser: Start observer-parser in development mode. start-parser: stop @echo " > Starting $(PROJECT_NAME)" @-$(GOBIN)/$(PARSER)/parser -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_PARSER) @cat $(PID_PARSER) | sed "/^/s/^/ \> Parser PID: /" @echo " > Error log: $(STDERR)" -## start-observer-notifier: Start observer-notifier in development mode. +## start-notifier: Start observer-notifier in development mode. start-notifier: stop @echo " > Starting $(PROJECT_NAME)" @-$(GOBIN)/$(NOTIFIER)/notifier -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_NOTIFIER) @cat $(PID_NOTIFIER) | sed "/^/s/^/ \> Notifier PID: /" @echo " > Error log: $(STDERR)" -## start-observer-subscriber: Start observer-subscriber in development mode. +## start-subscriber: Start observer-subscriber in development mode. start-subscriber: stop @echo " > Starting $(PROJECT_NAME)" @-$(GOBIN)/$(SUBSCRIBER)/subscriber -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SUBSCRIBER) @cat $(PID_SUBSCRIBER) | sed "/^/s/^/ \> Subscriber PID: /" @echo " > Error log: $(STDERR)" -## start-api: Start searcher in development mode. +## start-searcher: Start searcher in development mode. start-searcher: stop @echo " > Starting $(PROJECT_NAME)" @-$(GOBIN)/$(SEARCHER)/searcher -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SEARCHER) @cat $(PID_SEARCHER) | sed "/^/s/^/ \> Searcher PID: /" @echo " > Error log: $(STDERR)" +## start-indexer: Start indexer in development mode. +start-indexer: stop + @echo " > Starting $(PROJECT_NAME)" + @-$(GOBIN)/$(INDEXER)/indexer -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_INDEXER) + @cat $(PID_INDEXER) | sed "/^/s/^/ \> Indexer PID: /" + @echo " > Error log: $(STDERR)" + ## stop: Stop development mode. stop: @-touch $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_MOCKSERVER) $(PID_SEARCHER) @@ -109,7 +118,8 @@ stop: @-kill `cat $(PID_SUBSCRIBER)` 2> /dev/null || true @-kill `cat $(PID_MOCKSERVER)` 2> /dev/null || true @-kill `cat $(PID_SEARCHER)` 2> /dev/null || true - @-rm $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_MOCKSERVER) $(PID_SEARCHER) + @-kill `cat $(PID_INDEXER)` 2> /dev/null || true + @-rm $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_INDEXER) $(PID_MOCKSERVER) $(PID_SEARCHER) stop-mockserver: @-touch $(PID_MOCKSERVER) @@ -229,7 +239,7 @@ endif go-compile: go-get go-build -go-build: go-build-api go-build-notifier go-build-parser go-build-subscriber go-build-searcher +go-build: go-build-api go-build-notifier go-build-parser go-build-subscriber go-build-searcher go-build-indexer docker-shutdown: @echo " > Shutdown docker containers..." @@ -261,6 +271,10 @@ go-build-searcher: @echo " > Building searcher binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SEARCHER)/searcher ./cmd/$(SEARCHER) +go-build-indexer: + @echo " > Building indexer binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(INDEXER)/indexer ./cmd/$(INDEXER) + go-generate: @echo " > Generating dependency files..." GOBIN=$(GOBIN) go generate $(generate) diff --git a/api/api.go b/api/api.go index 01ed5070e..799f13454 100644 --- a/api/api.go +++ b/api/api.go @@ -6,6 +6,7 @@ import ( "github.com/swaggo/gin-swagger/swaggerFiles" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" ) @@ -24,10 +25,13 @@ func SetupPlatformAPI(router gin.IRouter) { RegisterBasicAPI(router) } -func SetupTokensIndexAPI(router gin.IRouter, instance tokensearcher.Instance) { - RegisterTokensIndexAPI(router, instance) +func SetupTokensSearcherAPI(router gin.IRouter, instance tokensearcher.Instance) { + RegisterTokensSearcherAPI(router, instance) } +func SetupTokensIndexAPI(router gin.IRouter, instance tokenindexer.Instance) { + RegisterTokensIndexAPI(router, instance) +} func SetupSwaggerAPI(router gin.IRouter) { router.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) } diff --git a/api/endpoint/token.go b/api/endpoint/token.go index 6c0c6a140..c2b57f842 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -3,6 +3,7 @@ package endpoint import ( "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" "net/http" "strconv" @@ -138,3 +139,17 @@ func GetTokensByAddressIndexer(c *gin.Context, instance tokensearcher.Instance) } c.JSON(http.StatusOK, result) } + +func GetNewTokens(c *gin.Context, instance tokenindexer.Instance) { + var query tokenindexer.Request + if err := c.Bind(&query); err != nil { + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) + return + } + resp, err := instance.HandleNewTokensRequest(query, c.Request.Context()) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) + return + } + c.JSON(http.StatusOK, resp) +} diff --git a/api/registry.go b/api/registry.go index fdd4eff0a..50d0cc10f 100644 --- a/api/registry.go +++ b/api/registry.go @@ -8,6 +8,7 @@ import ( "github.com/trustwallet/blockatlas/api/middleware" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform" + "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" "time" ) @@ -108,8 +109,14 @@ func RegisterBasicAPI(router gin.IRouter) { router.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) } -func RegisterTokensIndexAPI(router gin.IRouter, instance tokensearcher.Instance) { +func RegisterTokensSearcherAPI(router gin.IRouter, instance tokensearcher.Instance) { router.POST("/v3/tokens", func(c *gin.Context) { endpoint.GetTokensByAddressIndexer(c, instance) }) } + +func RegisterTokensIndexAPI(router gin.IRouter, instance tokenindexer.Instance) { + router.POST("/v3/tokens/new", func(c *gin.Context) { + endpoint.GetNewTokens(c, instance) + }) +} diff --git a/cmd/api/main.go b/cmd/api/main.go index 3be4ef7b0..2e92f7f9d 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -12,6 +12,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/spamfilter" + "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" "time" ) @@ -27,7 +28,8 @@ var ( port, confPath string engine *gin.Engine database *db.Instance - t tokensearcher.Instance + ts tokensearcher.Instance + ti tokenindexer.Instance restAPI string ) @@ -61,7 +63,12 @@ func init() { if err := mq.TokensRegistration.Declare(); err != nil { logger.Fatal(err) } - t = tokensearcher.Init(database, platform.TokensAPIs, mq.TokensRegistration) + if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { + logger.Fatal(err) + } + + ts = tokensearcher.Init(database, platform.TokensAPIs, mq.TokensRegistration) + ti = tokenindexer.Init(database) go mq.FatalWorker(time.Second * 10) } @@ -74,9 +81,10 @@ func main() { case "platform": api.SetupPlatformAPI(engine) case "tokens": - api.SetupTokensIndexAPI(engine, t) + api.SetupTokensSearcherAPI(engine, ts) default: - api.SetupTokensIndexAPI(engine, t) + api.SetupTokensIndexAPI(engine, ti) + api.SetupTokensSearcherAPI(engine, ts) api.SetupSwaggerAPI(engine) api.SetupPlatformAPI(engine) } diff --git a/cmd/indexer/main.go b/cmd/indexer/main.go new file mode 100644 index 000000000..ca6b8a26a --- /dev/null +++ b/cmd/indexer/main.go @@ -0,0 +1,61 @@ +package main + +import ( + "context" + "github.com/spf13/viper" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/services/tokenindexer" + "time" +) + +const ( + defaultConfigPath = "../../config.yml" +) + +var ( + ctx context.Context + cancel context.CancelFunc + confPath string + database *db.Instance +) + +func init() { + ctx, cancel = context.WithCancel(context.Background()) + _, confPath = internal.ParseArgs("", defaultConfigPath) + + internal.InitConfig(confPath) + logger.InitLogger() + + mqHost := viper.GetString("observer.rabbitmq.uri") + logMode := viper.GetBool("postgres.log") + prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + + internal.InitRabbitMQ(mqHost, prefetchCount) + + pgUri := viper.GetString("postgres.uri") + pgReadUri := viper.GetString("postgres.read_uri") + var err error + database, err = db.New(pgUri, pgReadUri, logMode) + if err != nil { + logger.Fatal(err) + } + go database.RestoreConnectionWorker(ctx, time.Second*10, pgUri) + + time.Sleep(time.Millisecond) +} + +func main() { + defer mq.Close() + + if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { + logger.Fatal(err) + } + go mq.RawTransactionsTokenIndexer.RunConsumerWithCancelAndDbConn(tokenindexer.RunTokenIndexer, database, ctx) + go mq.FatalWorker(time.Second * 10) + + internal.SetupGracefulShutdownForObserver() + cancel() +} diff --git a/cmd/parser/main.go b/cmd/parser/main.go index 870b8860b..0f12a0f2e 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -49,6 +49,10 @@ func init() { logger.Fatal(err) } + if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { + logger.Fatal(err) + } + if len(platform.BlockAPIs) == 0 { logger.Fatal("No APIs to observe") } @@ -108,9 +112,13 @@ func main() { coinCancel[coin.Handle] = cancel params := parser.Params{ - Ctx: ctx, - Api: api, - Queue: []mq.Queue{mq.RawTransactions, mq.RawTransactionsSearcher}, + Ctx: ctx, + Api: api, + Queue: []mq.Queue{ + mq.RawTransactions, + mq.RawTransactionsSearcher, + mq.RawTransactionsTokenIndexer, + }, ParsingBlocksInterval: pollInterval, FetchBlocksTimeout: fetchBlocksInterval, BacklogCount: backlogCount, diff --git a/db/addresstoasset.go b/db/addresstoasset.go index e084d47f1..b089ca0e9 100644 --- a/db/addresstoasset.go +++ b/db/addresstoasset.go @@ -23,36 +23,36 @@ func (i Instance) GetSubscribedAddressesForAssets(ctx context.Context, addresses return result, nil } -func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Context) (map[string][]string, error) { +func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Context) (map[string][]models.Asset, error) { db := i.Gorm.WithContext(ctx) var associations []models.AddressToAssetAssociation if err := db.Joins("Address").Joins("Asset").Find(&associations, "address in (?)", addresses).Error; err != nil { return nil, err } - result := make(map[string][]string) + result := make(map[string][]models.Asset) for _, a := range associations { assets := result[a.Address.Address] - result[a.Address.Address] = append(assets, a.Asset.Asset) + result[a.Address.Address] = append(assets, a.Asset) } return result, nil } -func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) (map[string][]string, error) { +func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) (map[string][]models.Asset, error) { if len(addresses) == 0 { - return map[string][]string{}, nil + return map[string][]models.Asset{}, nil } db := i.Gorm.WithContext(ctx) var associations []models.AddressToAssetAssociation - err := db.Joins("Address").Where("address in (?)", addresses).Joins("Asset").Find(&associations, "created_at > ?", from).Error + err := db.Joins("Address").Where("address in (?)", addresses).Joins("Asset").Find(&associations, "address_to_asset_associations.created_at > ?", from).Error if err != nil { return nil, err } - result := make(map[string][]string) + result := make(map[string][]models.Asset) for _, a := range associations { assets := result[a.Address.Address] - result[a.Address.Address] = append(assets, a.Asset.Asset) + result[a.Address.Address] = append(assets, a.Asset) } return result, nil } @@ -76,16 +76,10 @@ func (i *Instance) GetAssociationsByAddressesFromTime(addresses []string, from t return result, nil } -func (i *Instance) AddAssociationsForAddress(address string, assets []string, ctx context.Context) error { +func (i *Instance) AddAssociationsForAddress(address string, assets []models.Asset, ctx context.Context) error { db := i.Gorm.WithContext(ctx) return db.Transaction(func(tx *gorm.DB) error { - uniqueAssets := getUniqueStrings(assets) - uniqueAssetsModel := make([]models.Asset, 0, len(uniqueAssets)) - for _, l := range uniqueAssets { - uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{ - Asset: l, - }) - } + uniqueAssets := getUniqueAssets(assets) var err error dbAddress := models.Address{Address: address} @@ -94,15 +88,18 @@ func (i *Instance) AddAssociationsForAddress(address string, assets []string, ct return err } - if len(uniqueAssetsModel) > 0 { - if err = tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssetsModel).Error; err != nil { + if len(uniqueAssets) > 0 { + if err = tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssets).Error; err != nil { return err } } var dbAssets []models.Asset if len(uniqueAssets) > 0 { - if err = tx.Where("asset in (?)", uniqueAssets).Find(&dbAssets).Error; err != nil { + err = tx. + Where("asset in (?)", models.AssetIDs(uniqueAssets)). + Find(&dbAssets).Error + if err != nil { return err } } @@ -136,10 +133,10 @@ func (i *Instance) AddAssociationsForAddress(address string, assets []string, ct }) } -func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[string][]string, ctx context.Context) error { +func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[string][]models.Asset, ctx context.Context) error { db := i.Gorm.WithContext(ctx) return db.Transaction(func(tx *gorm.DB) error { - assets := make([]string, 0, len(associations)) + assets := make([]models.Asset, 0, len(associations)) for _, v := range associations { assets = append(assets, v...) } @@ -148,17 +145,18 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin return nil } - uniqueAssets := getUniqueStrings(assets) + uniqueAssets := getUniqueAssets(assets) uniqueAssetsModel := make([]models.Asset, 0, len(uniqueAssets)) for _, l := range uniqueAssets { - uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{Asset: l}) + uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{Asset: l.Asset}) } if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssetsModel).Error; err != nil { return err } var dbAssets []models.Asset - err := tx.Where("asset in (?)", uniqueAssets). + err := tx. + Where("asset in (?)", models.AssetIDs(uniqueAssets)). Find(&dbAssets). Limit(len(uniqueAssets)). Error @@ -207,7 +205,7 @@ func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[strin if !ok || addressID == 0 { continue } - assetID, ok := assetsMap[asset] + assetID, ok := assetsMap[asset.Asset] if !ok || assetID == 0 { continue } @@ -249,3 +247,15 @@ func getUniqueStrings(values []string) []string { } return list } + +func getUniqueAssets(values []models.Asset) []models.Asset { + keys := make(map[string]struct{}) + var list []models.Asset + for _, entry := range values { + if _, value := keys[entry.Asset]; !value { + keys[entry.Asset] = struct{}{} + list = append(list, entry) + } + } + return list +} diff --git a/db/asset.go b/db/asset.go new file mode 100644 index 000000000..1fa4984c9 --- /dev/null +++ b/db/asset.go @@ -0,0 +1,107 @@ +package db + +import ( + "context" + "gorm.io/gorm" + "gorm.io/gorm/clause" + "time" + "unicode/utf8" + + "github.com/trustwallet/blockatlas/db/models" +) + +func (i *Instance) AddNewAssets(assets []models.Asset, ctx context.Context) error { + db := i.Gorm.WithContext(ctx) + if len(assets) == 0 { + return nil + } + uniqueAssets := getUniqueAssets(assets) + uniqueAssets = filterAssets(uniqueAssets) + existingAssets, err := i.GetAssetsByIDs(models.AssetIDs(uniqueAssets), ctx) + if err != nil { + return err + } + if len(existingAssets) == 0 { + return db.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssets).Error + } + allAssetsMap := make(map[string]models.Asset) + for _, ua := range uniqueAssets { + allAssetsMap[ua.Asset] = ua + } + existingAssetsMap := make(map[string]models.Asset) + for _, ea := range existingAssets { + existingAssetsMap[ea.Asset] = ea + } + var newAssets []models.Asset + for k, v := range allAssetsMap { + _, ok := existingAssetsMap[k] + if !ok && v.Asset != "" { + newAssets = append(newAssets, v) + } + } + if len(newAssets) == 0 { + return nil + } + + assetsBatch := assetsBatch(newAssets, batchCount) + + return db.Transaction(func(tx *gorm.DB) error { + for _, na := range assetsBatch { + err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&na).Error + if err != nil { + return err + } + } + return nil + }) +} + +func (i *Instance) GetAssetsByIDs(ids []string, ctx context.Context) ([]models.Asset, error) { + db := i.Gorm.WithContext(ctx) + // todo: look why nil and len 0 make db calls rn + if len(ids) == 0 { + return nil, nil + } + var dbAssets []models.Asset + if err := db.Where("asset in (?)", ids).Find(&dbAssets).Error; err != nil { + return nil, err + } + return dbAssets, nil +} + +func (i *Instance) GetAssetsFrom(from time.Time, ctx context.Context) ([]models.Asset, error) { + db := i.Gorm.WithContext(ctx) + var dbAssets []models.Asset + if err := db.Find(&dbAssets, "created_at > ?", from).Error; err != nil { + return nil, err + } + return dbAssets, nil +} + +func assetsBatch(values []models.Asset, sizeUint uint) [][]models.Asset { + size := int(sizeUint) + resultLength := (len(values) + size - 1) / size + result := make([][]models.Asset, resultLength) + lo, hi := 0, size + for i := range result { + if hi > len(values) { + hi = len(values) + } + result[i] = values[lo:hi:hi] + lo, hi = hi, hi+size + } + return result +} + +func filterAssets(values []models.Asset) []models.Asset { + result := make([]models.Asset, 0, len(values)) + for _, v := range values { + if utf8.ValidString(v.Asset) && + utf8.ValidString(v.Type) && + utf8.ValidString(v.Symbol) && + utf8.ValidString(v.Name) { + result = append(result, v) + } + } + return result +} diff --git a/db/db.go b/db/db.go index 4a66aa64f..df27d65fe 100644 --- a/db/db.go +++ b/db/db.go @@ -17,6 +17,10 @@ type Instance struct { Gorm *gorm.DB } +// By gorm-bulk-insert author: +// "Depending on the number of variables included, 2000 to 3000 is recommended." +const batchCount = 3000 + func New(uri, readUri string, logMode bool) (*Instance, error) { cfg := &gorm.Config{} if logMode { @@ -46,10 +50,10 @@ func New(uri, readUri string, logMode bool) (*Instance, error) { err = db.AutoMigrate( &models.NotificationSubscription{}, &models.Tracker{}, - &models.AddressToAssetAssociation{}, &models.Asset{}, &models.AssetSubscription{}, &models.Address{}, + &models.AddressToAssetAssociation{}, ) if err != nil { return nil, err diff --git a/db/models/addresstoasset.go b/db/models/addresstoasset.go index 6330f90a1..e86322ca8 100644 --- a/db/models/addresstoasset.go +++ b/db/models/addresstoasset.go @@ -9,8 +9,8 @@ type AddressToAssetAssociation struct { DeletedAt *time.Time `gorm:"index:,; default:NULL"` Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"primary_key; autoIncrement:false; index:,"` + AddressID uint `gorm:"primaryKey; autoIncrement:false; index:,"` Asset Asset `gorm:"ForeignKey:AssetID; not null"` - AssetID uint `gorm:"primary_key; autoIncrement:false; index:,"` + AssetID uint `gorm:"primaryKey; autoIncrement:false; index:,"` } diff --git a/db/models/asset.go b/db/models/asset.go index d889854c7..5e323e2f9 100644 --- a/db/models/asset.go +++ b/db/models/asset.go @@ -1,6 +1,22 @@ package models +import "time" + type Asset struct { - ID uint `gorm:"primary_key"` - Asset string `gorm:"type:varchar(128); uniqueIndex"` + CreatedAt time.Time `gorm:"index:,"` + ID uint `gorm:"primary_key; uniqueIndex"` + Asset string `gorm:"type:varchar(128); uniqueIndex"` + + Decimals uint `gorm:"int(4)"` + Name string `gorm:"type:varchar(128)"` + Symbol string `gorm:"type:varchar(128)"` + Type string `gorm:"type:varchar(12)"` +} + +func AssetIDs(assets []Asset) []string { + result := make([]string, 0, len(assets)) + for _, a := range assets { + result = append(result, a.Asset) + } + return result } diff --git a/go.mod b/go.mod index ab171ffa1..ab29c1714 100644 --- a/go.mod +++ b/go.mod @@ -6,9 +6,11 @@ require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 + github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect github.com/deckarep/golang-set v1.7.1 github.com/gin-gonic/gin v1.6.3 github.com/imroc/req v0.3.0 + github.com/kr/pty v1.1.8 // indirect github.com/mitchellh/mapstructure v1.3.3 github.com/mr-tron/base58 v1.2.0 github.com/ory/dockertest v3.3.5+incompatible @@ -29,6 +31,7 @@ require ( go.elastic.co/apm/module/apmhttp v1.8.0 go.elastic.co/apm/module/apmlogrus v1.8.0 go.uber.org/atomic v1.7.0 + go.uber.org/multierr v1.5.0 // indirect golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f gopkg.in/yaml.v2 v2.3.0 diff --git a/mq/mq.go b/mq/mq.go index aecb96fba..2bd1bac3c 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -22,11 +22,12 @@ type ( ) const ( - TxNotifications Queue = "txNotifications" - Subscriptions Queue = "subscriptions" - RawTransactions Queue = "rawTransactions" - RawTransactionsSearcher Queue = "rawTransactionsSearcher" - TokensRegistration Queue = "tokensRegistration" + TxNotifications Queue = "txNotifications" + Subscriptions Queue = "subscriptions" + RawTransactions Queue = "rawTransactions" + RawTransactionsSearcher Queue = "rawTransactionsSearcher" + RawTransactionsTokenIndexer Queue = "rawTransactionsTokenIndexer" + TokensRegistration Queue = "tokensRegistration" ) func Init(uri string) (err error) { diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 3f3f4cae8..ea3fb2625 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -2,9 +2,12 @@ package blockatlas import ( mapset "github.com/deckarep/golang-set" + "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/watchmarket/pkg/watchmarket" "sort" + "strconv" "strings" ) @@ -450,3 +453,94 @@ func GetEthereumTokenTypeByIndex(coinIndex uint) TokenType { } return tokenType } + +func (t Tx) AssetModel() (models.Asset, bool) { + var asset models.Asset + switch t.Meta.(type) { + case TokenTransfer: + asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(TokenTransfer).TokenID) + asset.Decimals = t.Meta.(TokenTransfer).Decimals + asset.Name = t.Meta.(TokenTransfer).Name + asset.Symbol = t.Meta.(TokenTransfer).Symbol + tp, ok := GetTokenType(t.Coin, t.Meta.(TokenTransfer).TokenID) + if !ok { + return models.Asset{}, false + } + asset.Type = tp + case *TokenTransfer: + asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(*TokenTransfer).TokenID) + asset.Decimals = t.Meta.(*TokenTransfer).Decimals + asset.Name = t.Meta.(*TokenTransfer).Name + asset.Symbol = t.Meta.(*TokenTransfer).Symbol + tp, ok := GetTokenType(t.Coin, t.Meta.(*TokenTransfer).TokenID) + if !ok { + return models.Asset{}, false + } + asset.Type = tp + case NativeTokenTransfer: + asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(NativeTokenTransfer).TokenID) + asset.Decimals = t.Meta.(NativeTokenTransfer).Decimals + asset.Name = t.Meta.(NativeTokenTransfer).Name + asset.Symbol = t.Meta.(NativeTokenTransfer).Symbol + tp, ok := GetTokenType(t.Coin, t.Meta.(NativeTokenTransfer).TokenID) + if !ok { + return models.Asset{}, false + } + asset.Type = tp + case *NativeTokenTransfer: + asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(*NativeTokenTransfer).TokenID) + asset.Decimals = t.Meta.(*NativeTokenTransfer).Decimals + asset.Name = t.Meta.(*NativeTokenTransfer).Name + asset.Symbol = t.Meta.(*NativeTokenTransfer).Symbol + tp, ok := GetTokenType(t.Coin, t.Meta.(*NativeTokenTransfer).TokenID) + if !ok { + return models.Asset{}, false + } + asset.Type = tp + case AnyAction: + asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(AnyAction).TokenID) + asset.Decimals = t.Meta.(AnyAction).Decimals + asset.Name = t.Meta.(AnyAction).Name + asset.Symbol = t.Meta.(AnyAction).Symbol + tp, ok := GetTokenType(t.Coin, t.Meta.(AnyAction).TokenID) + if !ok { + return models.Asset{}, false + } + asset.Type = tp + case *AnyAction: + asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(*AnyAction).TokenID) + asset.Decimals = t.Meta.(*AnyAction).Decimals + asset.Name = t.Meta.(*AnyAction).Name + asset.Symbol = t.Meta.(*AnyAction).Symbol + tp, ok := GetTokenType(t.Coin, t.Meta.(*AnyAction).TokenID) + if !ok { + return models.Asset{}, false + } + asset.Type = tp + default: + return models.Asset{}, false + } + if asset.Asset == "" { + return models.Asset{}, false + } + return asset, true +} + +func GetTokenType(c uint, tokenID string) (string, bool) { + switch c { + case coin.Ethereum().ID: + return string(TokenTypeERC20), true + case coin.Tron().ID: + _, err := strconv.Atoi(tokenID) + if err != nil { + return string(TokenTypeTRC20), true + } + return string(TokenTypeTRC10), true + case coin.Smartchain().ID: + return string(TokenTypeBEP20), true + case coin.Binance().ID: + return string(TokenTypeBEP2), true + default: + return "", false + } +} diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 5f6a25bc4..0e5ba3ff3 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -607,6 +607,67 @@ func TestGetEthereumTokenTypeByIndex(t *testing.T) { } } +func TestTokenType(t *testing.T) { + type testStruct struct { + Name string + ID uint + TokenID string + WantedType string + WantedOk bool + } + tests := []testStruct{ + { + Name: "Tron TRC20", + ID: coin.Tron().ID, + TokenID: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + WantedType: string(TokenTypeTRC20), + WantedOk: true, + }, + { + Name: "Tron TRC10", + ID: coin.Tron().ID, + TokenID: "1002000", + WantedType: string(TokenTypeTRC10), + WantedOk: true, + }, + { + Name: "Ethereum ERC20", + ID: coin.Ethereum().ID, + TokenID: "dai", + WantedType: string(TokenTypeERC20), + WantedOk: true, + }, + { + Name: "Binance BEP20", + ID: coin.Smartchain().ID, + TokenID: "busd", + WantedType: string(TokenTypeBEP20), + WantedOk: true, + }, + { + Name: "Binance BEP10", + ID: coin.Binance().ID, + TokenID: "busd", + WantedType: string(TokenTypeBEP2), + WantedOk: true, + }, + { + Name: "Wrong", + ID: coin.Bitcoin().ID, + TokenID: "busd", + WantedType: "", + WantedOk: false, + }, + } + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + expectedType, expectedOk := GetTokenType(tt.ID, tt.TokenID) + assert.Equal(t, tt.WantedType, expectedType) + assert.Equal(t, tt.WantedOk, expectedOk) + }) + } +} + var ( beforeTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` //beforeTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"trust.com","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` diff --git a/platform/binance/model.go b/platform/binance/model.go index a3e0a3aa8..8ad80ee65 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -148,6 +148,7 @@ func normalizeTransferTransaction(t Tx) blockatlas.Tx { Decimals: coin.Binance().Decimals, From: t.FromAddr.(string), Symbol: getTokenSymbolFromID(t.TxAsset), + Name: getTokenSymbolFromID(t.TxAsset), To: t.ToAddr.(string), TokenID: t.TxAsset, Value: normalizeAmount(t.Value), @@ -183,6 +184,7 @@ func normalizeMultiTransferTransaction(t Tx) []blockatlas.Tx { tx.Type = blockatlas.TxNativeTokenTransfer tx.Meta = blockatlas.NativeTokenTransfer{ Decimals: coin.Binance().Decimals, + Name: getTokenSymbolFromID(subTx.TxAsset), From: subTx.FromAddr, Symbol: getTokenSymbolFromID(subTx.TxAsset), To: subTx.ToAddr, diff --git a/platform/tron/token.go b/platform/tron/token.go index b99bb24ae..e6e6406be 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -3,6 +3,7 @@ package tron import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" + "strings" "github.com/trustwallet/golibs/coin" "sync" "time" @@ -36,7 +37,7 @@ func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, for _, t := range trc20Tokens { tokenPage = append(tokenPage, blockatlas.Token{ Name: t.Name, - Symbol: t.Symbol, + Symbol: strings.ToUpper(t.Symbol), Decimals: uint(t.Decimals), TokenID: t.ContractAddress, Coin: coin.Tron().ID, @@ -79,7 +80,7 @@ func (p *Platform) getTokensChannel(id string, tkChan chan blockatlas.Token) err func NormalizeToken(info AssetInfo) blockatlas.Token { return blockatlas.Token{ Name: info.Name, - Symbol: info.Symbol, + Symbol: strings.ToUpper(info.Symbol), TokenID: info.ID, Coin: coin.TRX, Decimals: info.Decimals, diff --git a/platform/tron/token_test.go b/platform/tron/token_test.go index c324f095c..91c9a6c57 100644 --- a/platform/tron/token_test.go +++ b/platform/tron/token_test.go @@ -102,7 +102,7 @@ func createMockedAPI() http.Handler { } var ( - wantedTokensResponse = `[{"name":"FomoThreeD","symbol":"FOM","decimals":0,"token_id":"1000542","coin":195,"type":"TRC10"},{"name":"OtonamiS","symbol":"os","decimals":0,"token_id":"1000567","coin":195,"type":"TRC10"},{"name":"JUST GOV","symbol":"JST","decimals":18,"token_id":"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9","coin":195,"type":"TRC20"},{"name":"Enme Token","symbol":"EME","decimals":6,"token_id":"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF","coin":195,"type":"TRC20"},{"name":"BeeHive","symbol":"Bee","decimals":8,"token_id":"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK","coin":195,"type":"TRC20"},{"name":"Mono Token","symbol":"MONO","decimals":18,"token_id":"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak","coin":195,"type":"TRC20"},{"name":"WINK","symbol":"WIN","decimals":6,"token_id":"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7","coin":195,"type":"TRC20"},{"name":"PYRO Network","symbol":"PYRO","decimals":6,"token_id":"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e","coin":195,"type":"TRC20"},{"name":"NoleCoin","symbol":"NOLE","decimals":6,"token_id":"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG","coin":195,"type":"TRC20"},{"name":"Tether USD","symbol":"USDT","decimals":6,"token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","coin":195,"type":"TRC20"},{"name":"Wuhan Fried Bats","symbol":"WUHAN","decimals":4,"token_id":"TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr","coin":195,"type":"TRC20"},{"name":"HelGro","symbol":"HGRO","decimals":6,"token_id":"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm","coin":195,"type":"TRC20"}]` + wantedTokensResponse = `[{"name":"FomoThreeD","symbol":"FOM","decimals":0,"token_id":"1000542","coin":195,"type":"TRC10"},{"name":"OtonamiS","symbol":"OS","decimals":0,"token_id":"1000567","coin":195,"type":"TRC10"},{"name":"JUST GOV","symbol":"JST","decimals":18,"token_id":"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9","coin":195,"type":"TRC20"},{"name":"Enme Token","symbol":"EME","decimals":6,"token_id":"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF","coin":195,"type":"TRC20"},{"name":"BeeHive","symbol":"BEE","decimals":8,"token_id":"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK","coin":195,"type":"TRC20"},{"name":"Mono Token","symbol":"MONO","decimals":18,"token_id":"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak","coin":195,"type":"TRC20"},{"name":"WINK","symbol":"WIN","decimals":6,"token_id":"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7","coin":195,"type":"TRC20"},{"name":"PYRO Network","symbol":"PYRO","decimals":6,"token_id":"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e","coin":195,"type":"TRC20"},{"name":"NoleCoin","symbol":"NOLE","decimals":6,"token_id":"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG","coin":195,"type":"TRC20"},{"name":"Tether USD","symbol":"USDT","decimals":6,"token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","coin":195,"type":"TRC20"},{"name":"Wuhan Fried Bats","symbol":"WUHAN","decimals":4,"token_id":"TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr","coin":195,"type":"TRC20"},{"name":"HelGro","symbol":"HGRO","decimals":6,"token_id":"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm","coin":195,"type":"TRC20"}]` mockedAccountsTransactionsResponse = `{"success":true,"meta":{"at":1592755486554,"page_size":25,"fingerprint":"4CwRecxbH99eRRkU2FFkGRCvoQGwphNyRcTTiM1GfUrkoQ1fG9Kcc8ADZo7pSCYXja28JWKUACy2Xt6UG1Fa5tSZh5dqpUEuTi1W","links":{"next":"https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R/transactions?limit=25&order_by=block_timestamp%2Cdesc&token_id=&fingerprint=4CwRecxbH99eRRkU2FFkGRCvoQGwphNyRcTTiM1GfUrkoQ1fG9Kcc8ADZo7pSCYXja28JWKUACy2Xt6UG1Fa5tSZh5dqpUEuTi1W"}},"data":[{"blockNumber":20829763,"block_timestamp":1592755239000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000413b334848f75cf8c27ec975bcc7cc7e54f140b3c000000000000000000000000000000000000000000000000000000000cd0e33a0","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758890000,"fee_limit":1000000000,"ref_block_bytes":"d62e","ref_block_hash":"bbf7d06ee7004d5a","timestamp":1592755233594},"raw_data_hex":"0a02d62e2208bbf7d06ee7004d5a4090dccfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413b334848f75cf8c27ec975bcc7cc7e54f140b3c000000000000000000000000000000000000000000000000000000000cd0e33a070bac6f0bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["c9a405be8b12f92747cc0f0d979606807a03edcefd154bcf517ce26f8bf681400d6cdacda11c98e7ae61d51905f7113658a786d6022b97e025f5a7e99b53845d01"],"txID":"18f5908a7e208e16bfb892a5b06df75675d3142d03a0d99d270ac46143b78d06"},{"blockNumber":20829760,"block_timestamp":1592755230000,"energy_fee":146310,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb00000000000000000000004158a82464024027b8e81bd1997cc7ba8f26a01314000000000000000000000000000000000000000000000000000000001dce7a58","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758881000,"fee_limit":1000000000,"ref_block_bytes":"d62b","ref_block_hash":"38ebe631e633b827","timestamp":1592755223352},"raw_data_hex":"0a02d62b220838ebe631e633b82740e895cfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb00000000000000000000004158a82464024027b8e81bd1997cc7ba8f26a01314000000000000000000000000000000000000000000000000000000001dce7a5870b8f6efbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":149770}],"signature":["39ee8b2e7ab589538f3a976644399ba60667ede4d9611229298d52f5aeb01a6624e2346703d8a19edc9f457b89a0dbb800ae87d049ad3a7d72353fde77635f1a00"],"txID":"2a9eda92b9a2a0e56d29000ad24daae7d577c5db44d2b737f6a35584cd81b5e0"},{"blockNumber":20829760,"block_timestamp":1592755230000,"energy_fee":119110,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac84000000000000000000000000000000000000000000000000000000037e11d600","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758881000,"fee_limit":1000000000,"ref_block_bytes":"d62b","ref_block_hash":"38ebe631e633b827","timestamp":1592755223053},"raw_data_hex":"0a02d62b220838ebe631e633b82740e895cfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac84000000000000000000000000000000000000000000000000000000037e11d600708df4efbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":122570}],"signature":["710a4b8543a9f605acc809ebe5b8a3a3b4681ebf2123fcdda39187bde86c9bc839cf6d882d9d15052b94ed6bba6474f9fdf09e73afefe40f6bad909029cadd2500"],"txID":"c838b8a683d39c6f1a8a173e6fffc5cc9122acc690f5e35fa7c1935cc5eae540"},{"blockNumber":20829742,"block_timestamp":1592755176000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041c80ab7aac02a3d4b3d89ee781cddce55286bcf2d000000000000000000000000000000000000000000000000000000000bebc200","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758830000,"fee_limit":1000000000,"ref_block_bytes":"d61a","ref_block_hash":"b1015d64daa873a3","timestamp":1592755172703},"raw_data_hex":"0a02d61a2208b1015d64daa873a340b087ccbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041c80ab7aac02a3d4b3d89ee781cddce55286bcf2d000000000000000000000000000000000000000000000000000000000bebc20070dfeaecbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["a7583c4e402eff463b083de5cfcbaadc46ed8601e2346f20d01eb0ec7a6824d869be27371f8c0e5a38a708df724be60a818b9647757bdde73ed743ff9324115c01"],"txID":"ad631a0e55bd2bb64747bf388dc92084c32506843c19a0a2b69234b4d4e56a6b"},{"blockNumber":20829732,"block_timestamp":1592755146000,"energy_fee":231500,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000410d4fd52433f30edd0b512f59fa021527bbd7de610000000000000000000000000000000000000000000000000000000001c9c380","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758800000,"fee_limit":1000000000,"ref_block_bytes":"d610","ref_block_hash":"2a14293035535e85","timestamp":1592755142312},"raw_data_hex":"0a02d61022082a14293035535e8540809dcabead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000410d4fd52433f30edd0b512f59fa021527bbd7de610000000000000000000000000000000000000000000000000000000001c9c38070a8fdeabcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":234960}],"signature":["3095c2130ee5d4da72246a17098b587c25108e1c1884f9128911e079997dd25c45e0b0acfc99e3ee4367c4670e2117dd24884c32ae0ea15ec9f9368910e4c42801"],"txID":"f1920eefa4de8370bc349fbd6ca73e24d9000d9d8fe5c71260a2902d3b49b02a"},{"blockNumber":20829718,"block_timestamp":1592755104000,"energy_fee":166720,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb00000000000000000000004135c4d4a5544d25a2f25a7cda73d57c45a36578bc0000000000000000000000000000000000000000000000000000000010089d40","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758761000,"fee_limit":1000000000,"ref_block_bytes":"d603","ref_block_hash":"f84579e34d118430","timestamp":1592755101713},"raw_data_hex":"0a02d6032208f84579e34d11843040a8ecc7bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb00000000000000000000004135c4d4a5544d25a2f25a7cda73d57c45a36578bc0000000000000000000000000000000000000000000000000000000010089d407091c0e8bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170180}],"signature":["816b2747c6c1f6be139d233118b4b1e3c3942d62f56d1b0c8a496851ea233c5c1b6e0e0a13e22c3a4c1bd106eb6c0e987d5c84f9fcc29ee7b86bd4d1874ade9601"],"txID":"cec1061166e4924123356b8066872b641956691d1b1f11a12f293c54e7178362"},{"blockNumber":20829716,"block_timestamp":1592755098000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":2690,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":13195916000,"owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874","to_address":"41d9378a9849912a41ec1f0e4677c074edf0516241"}},"type":"TransferContract"}],"expiration":1592758749000,"fee_limit":0,"ref_block_bytes":"d5ff","ref_block_hash":"c753125289c79c7c","timestamp":1592755089996},"raw_data_hex":"0a02d5ff2208c753125289c79c7c40c88ec7bead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a154179309abcff2cf531070ca9222a1f72c4a5136874121541d9378a9849912a41ec1f0e4677c074edf051624118e0e5a6943170cce4e7bcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":2690}],"signature":["bae63e4214b0ab611079beabca020c82fbcada902f1f0c13106e7c4ba463efb25610d13b00b28cd19b54f648b88a4b05a08583b44b4f4179c2c605b42b22ad4b00"],"txID":"3fca53c08ccb48bb625439a58998713d8ecc3dc1348cc3cfab912e0815b62b1a"},{"blockNumber":20829708,"block_timestamp":1592755074000,"energy_fee":146310,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005fc2678","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758719000,"fee_limit":1000000000,"ref_block_bytes":"d5f5","ref_block_hash":"84843b5d1de30802","timestamp":1592755061404},"raw_data_hex":"0a02d5f5220884843b5d1de308024098a4c5bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005fc2678709c85e6bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":149770}],"signature":["6dd6709cee109df62c3a7f196f45d3efa16c25738c1c4ea371cce18443016c8911a2d65fd4f2d7b4932aed34634169adc981db081522b094e63d9528882b3de801"],"txID":"8e886732999efe30e0d7c93eee40c41f058f33c82194141317768810a5a84b82"},{"blockNumber":20829681,"block_timestamp":1592754993000,"energy_fee":231500,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005e5eb10","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758638000,"fee_limit":1000000000,"ref_block_bytes":"d5da","ref_block_hash":"3234615516f16ee9","timestamp":1592754980996},"raw_data_hex":"0a02d5da22083234615516f16ee940b0abc0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005e5eb10708491e1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":234960}],"signature":["896243c9d9c8ba595deafb81b7c4fc283271e0f46aa7031f270d91a383ce997a09f4a3aa6fb0478a7dac9b7df295dcf232f8bf4941583848f45bd8e258f9482e01"],"txID":"8b7c9f9f29cbf9ced22761f918d19471b3bb638438e6cc23e8104fed7dda1ef3"},{"blockNumber":20829627,"block_timestamp":1592754831000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":2850,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferAssetContract","value":{"amount":7639170000000,"asset_name":"1002000","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874","to_address":"410a60e164aa897ef76779164dff6e36161980c6fb"}},"type":"TransferAssetContract"}],"expiration":1592758479000,"fee_limit":0,"ref_block_bytes":"d5a5","ref_block_hash":"462e1cfdbe99a85b","timestamp":1592754820511},"raw_data_hex":"0a02d5a52208462e1cfdbe99a85b4098d1b6bead2e5a79080212750a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123f0a073130303230303012154179309abcff2cf531070ca9222a1f72c4a51368741a15410a60e164aa897ef76779164dff6e36161980c6fb2080c98e90aade01709fabd7bcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":2850}],"signature":["b49c878a8e85339fc4917e7f20625b38b941871c86572d2c01322ec26575c7024c34b498e464109a03f8e42df24cc0868910a0e7b1f7c174f5005a483a93dac600"],"txID":"79010512f8e58574cbd066d1a1bd1c7f46f65e59e3b7733010047ff8350f15f1"},{"blockNumber":20829617,"block_timestamp":1592754801000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000412b764790f38a7373d56dfdf4f866fa027e28c8af0000000000000000000000000000000000000000000000000000000071006010","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758449000,"fee_limit":1000000000,"ref_block_bytes":"d59b","ref_block_hash":"beab372f7f7d493b","timestamp":1592754790236},"raw_data_hex":"0a02d59b2208beab372f7f7d493b40e8e6b4bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000412b764790f38a7373d56dfdf4f866fa027e28c8af000000000000000000000000000000000000000000000000000000007100601070dcbed5bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["52b662780f176048c4fd9e8db15756d0ef397cb60a8be6ea3421993ec2c6e1636d9aaf8a596f9255c182284e1efbd5410e2a11d10b82b4e4fec5a43ffea357cc01"],"txID":"809ec9beb99cf756bb02155199a35b766f3ec18dd6bea6b3d69dd38f6b51138f"},{"blockNumber":20829617,"block_timestamp":1592754801000,"energy_fee":166700,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041d8692da59c130875e13587a82bc93b917c49526a0000000000000000000000000000000000000000000000000000000054c92b70","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758449000,"fee_limit":1000000000,"ref_block_bytes":"d59b","ref_block_hash":"beab372f7f7d493b","timestamp":1592754789857},"raw_data_hex":"0a02d59b2208beab372f7f7d493b40e8e6b4bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041d8692da59c130875e13587a82bc93b917c49526a0000000000000000000000000000000000000000000000000000000054c92b7070e1bbd5bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170160}],"signature":["fe96d2be46a37f89531d10cdca823ec82c603a3bb9f858aa76db20468e8d9d6058de643460e11b50e0982fa6ab6b81439cee6c9286b5d6bb7c18206e2ab066fb01"],"txID":"bc0c429e33d3c668e5e5a55831efb3aba7e917c52cd3892aeb252f1a7b2ddb41"},{"blockNumber":20829596,"block_timestamp":1592754738000,"energy_fee":166700,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041ec853dc8fe0dab78d3234ba356ebae7984da322c00000000000000000000000000000000000000000000000000000004a817c800","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758386000,"fee_limit":1000000000,"ref_block_bytes":"d586","ref_block_hash":"4007c65312ba945c","timestamp":1592754729408},"raw_data_hex":"0a02d58622084007c65312ba945c40d0fab0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041ec853dc8fe0dab78d3234ba356ebae7984da322c00000000000000000000000000000000000000000000000000000004a817c80070c0e3d1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170160}],"signature":["93119466b23346e095d256537f2bf8c639dd157f896eaaff972f0be83663bca34a21df4e25fa61ba071588a58f98874a58705844a8cc36a321bf30e722028c8201"],"txID":"3bcd581a833abb16529e1f5187615866ba72f2e61c590c993f5b461ba5073d45"},{"blockNumber":20829592,"block_timestamp":1592754726000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac8400000000000000000000000000000000000000000000000000000000001e8480","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758377000,"fee_limit":1000000000,"ref_block_bytes":"d583","ref_block_hash":"0bc07e9ae4eb32b0","timestamp":1592754719032},"raw_data_hex":"0a02d58322080bc07e9ae4eb32b040a8b4b0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac8400000000000000000000000000000000000000000000000000000000001e848070b892d1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["80fe656c430afb348327f279a2d454d277bf64564111e49118ed85f1021528920ba5be044956084f543a087a61aa14b595a4fc2cc6aff2ad2ac5d7533a6b122f01"],"txID":"3baff897a2b39720727549216ea6f4bc580eed2f239967e158e9e7ea74146822"},{"blockNumber":20829589,"block_timestamp":1592754717000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":2690,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":8737000000,"owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874","to_address":"412886fdc89587dbe8a57d0b9589581bd084384d5f"}},"type":"TransferContract"}],"expiration":1592758368000,"fee_limit":0,"ref_block_bytes":"d580","ref_block_hash":"ebf8d3b3837d87a8","timestamp":1592754708731},"raw_data_hex":"0a02d5802208ebf8d3b3837d87a84080eeafbead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a154179309abcff2cf531070ca9222a1f72c4a51368741215412886fdc89587dbe8a57d0b9589581bd084384d5f18c09490c62070fbc1d0bcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":2690}],"signature":["b92bdde424aee97b4e7a63716056daa963afce89701bf6d8c8b1b6221f65afb94b8ff3865650aff83d590cad87359ae5f272ed732738093a0a9aa587cc3503aa01"],"txID":"b38fb6328e1fa622b7762eed856778551845c33723491e36baf357f00cc48002"},{"blockNumber":20829585,"block_timestamp":1592754705000,"energy_fee":43900,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000416128e41b6aa8c531b05999c2861f846459fb10e60000000000000000000000000000000000000000000000000000000005f5e100","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758356000,"fee_limit":1000000000,"ref_block_bytes":"d57c","ref_block_hash":"c7c6e5795625dc5b","timestamp":1592754698724},"raw_data_hex":"0a02d57c2208c7c6e5795625dc5b40a090afbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000416128e41b6aa8c531b05999c2861f846459fb10e60000000000000000000000000000000000000000000000000000000005f5e10070e4f3cfbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":47360}],"signature":["b90e38665957e47ba8f7731e3b8c943471cd6ef9a95efcd25ad880323f2e397b56927e943c7e605a1996900fe269db6edbc7d7ff094f23393c6546ef0927bae300"],"txID":"d8d53a627fa9f885ad77dcc2f3d3a5eceece36d1ef0f54990dff900484550304"},{"blockNumber":20829577,"block_timestamp":1592754681000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041dd81641cca9a855b7a657153fdda9b3f469693660000000000000000000000000000000000000000000000000000000217a31ba0","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758335000,"fee_limit":1000000000,"ref_block_bytes":"d575","ref_block_hash":"003bba00242a2488","timestamp":1592754678392},"raw_data_hex":"0a02d5752208003bba00242a24884098ecadbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd81641cca9a855b7a657153fdda9b3f469693660000000000000000000000000000000000000000000000000000000217a31ba070f8d4cebcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["0abe6787b18631ae746b4a9c9669e3e878b88c3628a3656e3709b4036b14414525bdb9cdb3c97fce48c9d21f2afab9492a436861e2e85ec1f68bab078859eb1d01"],"txID":"b419c05c877e0176619ec3659470c71822a7840a91a940169eaaf1abb9c38fea"},{"blockNumber":20829564,"block_timestamp":1592754642000,"energy_fee":43900,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041a3af64559a63856c625b02e9def8a4dc0f63f38b0000000000000000000000000000000000000000000000000000000010c18918","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758287000,"fee_limit":1000000000,"ref_block_bytes":"d565","ref_block_hash":"afd9deb62b6fa5e0","timestamp":1592754628020},"raw_data_hex":"0a02d5652208afd9deb62b6fa5e04098f5aabead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041a3af64559a63856c625b02e9def8a4dc0f63f38b0000000000000000000000000000000000000000000000000000000010c1891870b4cbcbbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":47360}],"signature":["070c1a53f2fc6b12825b99c9179899e1effbbdf2fad17d273b64bc47f16ee53a0f56096d4ef6ce58aeee65083dcdef8f3c808d6889a990c23a8d45a84cd69bf101"],"txID":"abb6c40f8f8afcc69fb5b549ffb17bd779fa6588dbbbd5e4ee8568839462b37a"},{"blockNumber":20829535,"block_timestamp":1592754555000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000410ae0647bbaa1aebafcc9a360d0e22a791a215c930000000000000000000000000000000000000000000000000000000011e1a300","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758206000,"fee_limit":1000000000,"ref_block_bytes":"d54a","ref_block_hash":"d27814b2e9763d5d","timestamp":1592754547598},"raw_data_hex":"0a02d54a2208d27814b2e9763d5d40b0fca5bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000410ae0647bbaa1aebafcc9a360d0e22a791a215c930000000000000000000000000000000000000000000000000000000011e1a300708ed7c6bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["6a0f4d4d5021c46d522f45552b20218ea16c437e6e87130339c90752f63f7a805763699bad3b22fb3199efdce75f1929ac94482be8551107b051ae4b9ef532bb01"],"txID":"7da3a7819e4de9311464963f829e3ceeff0a045bbd587030deba863a04d250db"},{"blockNumber":20829504,"block_timestamp":1592754462000,"energy_fee":166700,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041042b5bc43cf6aabae0533f4f671eb810615c32be0000000000000000000000000000000000000000000000000000000054c92b70","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758116000,"fee_limit":1000000000,"ref_block_bytes":"d52c","ref_block_hash":"9486bdd9554ef09e","timestamp":1592754457197},"raw_data_hex":"0a02d52c22089486bdd9554ef09e40a0bda0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041042b5bc43cf6aabae0533f4f671eb810615c32be0000000000000000000000000000000000000000000000000000000054c92b7070ed94c1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170160}],"signature":["2bfe810fa90d3aee965ff990fd68490ce9c8421844c1e792a57faeb556e5c9b004499016ace19afdb49ba65531c2d829890b4c6a14a7e58c6b71bfdacc7709e201"],"txID":"4d5e74b87f782060e0657a48898626a51a1bf2dcccfc2083955fa4f43e4516b0"},{"blockNumber":20829499,"block_timestamp":1592754447000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":2538461,"owner_address":"41da03247c21301eaf0538c1b9f79e5c8ea7cbb386","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758089000,"fee_limit":0,"ref_block_bytes":"d523","ref_block_hash":"dc512cab1e07f960","timestamp":1592754430099},"raw_data_hex":"0a02d5232208dc512cab1e07f96040a8ea9ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541da03247c21301eaf0538c1b9f79e5c8ea7cbb38612154179309abcff2cf531070ca9222a1f72c4a513687418ddf79a017093c1bfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["0b542abf1657965deeb06123636f6e4ccaea5f4ab0a14f81f3164b286cb6ede37c62d701c796ae86cbd5c908009e5ac6db73d4532a9976ce5b30df47460957d601"],"txID":"82efc8456a3c38a0919af416a53363405ced78db7c13e1b94a79ebcea98f9909"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":30000000,"owner_address":"41f3eb90cf03d6301e1d10b6095113494bc704992c","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758089000,"fee_limit":0,"ref_block_bytes":"d523","ref_block_hash":"dc512cab1e07f960","timestamp":1592754429791},"raw_data_hex":"0a02d5232208dc512cab1e07f96040a8ea9ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541f3eb90cf03d6301e1d10b6095113494bc704992c12154179309abcff2cf531070ca9222a1f72c4a5136874188087a70e70dfbebfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["d44a181a6ff560bbcd8a89f9b14247f3d3c781020404eb6462926f3e60dfe32c38ee17f0e752346229de30db033352240152891a168285581558f80af90f83fd00"],"txID":"a336bd174c127d38bf2325bc9c927059af099e8cfb91159750a1b1be16dd0bd4"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":111337320,"owner_address":"41b4fd934c73429b27c1e9180e04ccfc44c14f15a9","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758086000,"fee_limit":0,"ref_block_bytes":"d522","ref_block_hash":"9ecd3926187cf28e","timestamp":1592754429463},"raw_data_hex":"0a02d52222089ecd3926187cf28e40f0d29ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541b4fd934c73429b27c1e9180e04ccfc44c14f15a912154179309abcff2cf531070ca9222a1f72c4a513687418e8be8b357097bcbfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["a40ce5f8ab4d9283fd9982eb38aa2a8b8ad9aeaa9bfc8acc220673a367fd420c034f89110e74a99745a96e103b883a85036c64e1c992a7a12c594f11954bacca01"],"txID":"007bbcc3855f4bf51bd76e63d7776160c115c803e227f7c44c7d1fd1bd587611"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":200000000,"owner_address":"413c5d20a6b1747c65903e2874614d6b8a038b818c","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758086000,"fee_limit":0,"ref_block_bytes":"d522","ref_block_hash":"9ecd3926187cf28e","timestamp":1592754429137},"raw_data_hex":"0a02d52222089ecd3926187cf28e40f0d29ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a15413c5d20a6b1747c65903e2874614d6b8a038b818c12154179309abcff2cf531070ca9222a1f72c4a5136874188084af5f70d1b9bfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["9192ee355f2b8c4b21cb68d5b5b2647a4ccb3a00c2bdaeb65cddef4785e7a31e364e21ef3c8b78628c8d342d6f7727ab391b064c1f0b02105e300108ca9cf88800"],"txID":"9351e87b129142844f000a52911daf36fc95677dfe2846abcd28ea0d8fe2e2ea"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":269,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":511000000,"owner_address":"414a5a0f19fd4b1c85208764a7a8cdcdb88171fc71","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758086000,"fee_limit":0,"ref_block_bytes":"d522","ref_block_hash":"9ecd3926187cf28e","timestamp":1592754428706},"raw_data_hex":"0a02d52222089ecd3926187cf28e40f0d29ebead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a15414a5a0f19fd4b1c85208764a7a8cdcdb88171fc7112154179309abcff2cf531070ca9222a1f72c4a513687418c0fbd4f30170a2b6bfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["fac73d7f6540a63c27717cbe04197d8ae89bd906f6c59eba71cc3a2630e29d9b6e0e4400b5e316289e5b6608d84a1a47673674605e48776f8d97aa3dedcfc60301"],"txID":"008ebda5749c38e26a69717faa66e6f4fd8a0d358c9b947192765cc9843cff5a"}]}` mockedTrc20Response = `{"trc20token_balances":[{"name":"BeeHive","symbol":"Bee","decimals":8,"contract_address":"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK","balance":"100000000000000"},{"name":"NoleCoin","symbol":"NOLE","decimals":6,"contract_address":"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG","balance":"20000","priceInTrx":20.000000},{"name":"Enme Token","symbol":"EME","decimals":6,"contract_address":"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF","balance":"175798"},{"name":"PYRO Network","symbol":"PYRO","decimals":6,"contract_address":"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e","balance":"5000000000","priceInTrx":0.005821},{"name":"Wuhan Fried Bats","symbol":"WUHAN","decimals":4,"contract_address":"TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr","balance":"690000"},{"name":"WINK","symbol":"WIN","decimals":6,"contract_address":"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7","balance":"191543058623486","priceInTrx":0.004665},{"name":"Mono Token","symbol":"MONO","decimals":18,"contract_address":"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak","balance":"1"},{"name":"HelGro","symbol":"HGRO","decimals":6,"contract_address":"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm","balance":"20000000"},{"name":"JUST GOV","symbol":"JST","decimals":18,"contract_address":"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9","balance":"955973733483987848990056","priceInTrx":0.313300},{"name":"Tether USD","symbol":"USDT","decimals":6,"contract_address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","balance":"6781725898163","priceInTrx":64.102564}],"allowExchange":[],"address":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","frozen_supply":[],"bandwidth":{"energyRemaining":0,"totalEnergyLimit":90000000000,"totalEnergyWeight":1446707995,"netUsed":0,"storageLimit":0,"storagePercentage":0.0,"assets":{"1000542":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002446":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002721":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001510":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002962":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001479":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002288":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001594":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002683":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000541":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001079":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000145":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002608":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000821":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002845":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001759":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002726":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001230":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001467":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002798":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000894":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000532":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002830":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000017":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000494":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002398":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002552":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002551":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002672":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002037":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002950":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000935":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000938":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002438":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000491":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000096":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002671":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000493":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001064":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001581":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002270":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000322":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002589":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001411":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002467":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002742":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001414":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001535":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000567":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000165":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001011":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002342":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001132":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000562":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000287":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001815":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002907":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002746":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002748":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001090":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000278":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000157":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002578":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002577":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002852":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002459":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000396":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002573":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002454":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000959":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002736":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002858":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003022":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001038":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000983":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001433":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000743":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001953":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002646":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000985":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002524":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002001":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002881":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002488":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002521":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002762":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002927":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002926":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000745":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000744":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000746":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002000":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000181":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002116":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001301":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001425":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002876":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000176":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000451":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003049":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002597":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002918":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002636":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002999":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001825":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000856":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002517":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002230":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002071":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003041":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002072":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000003":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000520":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000884":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002544":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001854":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002822":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000006":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002662":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002669":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002384":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002263":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001203":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002897":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001565":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002775":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002657":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001204":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001446":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002892":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002939":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002814":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002250":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002099":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000190":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0}},"netPercentage":0.0,"storageUsed":0,"storageRemaining":0,"freeNetLimit":5000,"energyUsed":0,"freeNetRemaining":211,"netLimit":0,"netRemaining":0,"energyLimit":0,"freeNetUsed":4789,"totalNetWeight":26789943446,"freeNetPercentage":0.9578,"energyPercentage":0.0,"totalNetLimit":43200000000},"accountType":0,"exchanges":[],"frozen":{"total":0,"balances":[]},"accountResource":{"frozen_balance_for_energy":{}},"tokenBalances":[{"balance":346976329314696,"name":"_"},{"balance":1273,"name":"1000003"},{"balance":113,"name":"1000006"},{"balance":145,"name":"1000165"},{"balance":416,"name":"1000520"},{"balance":596,"name":"1000491"},{"balance":242,"name":"1000176","owner_address":"THG48yHsR6inxrCJk2hhxZPsFLq1ehP88V"},{"balance":62,"name":"1000542"},{"balance":53,"name":"1000494","owner_address":"TXJnVqqwLSNmdXDLWn1Yfjhe8aZH2oaAuq"},{"balance":56,"name":"1000493"},{"balance":599,"name":"1000744"},{"balance":628,"name":"1000746"},{"balance":234,"name":"1000743"},{"balance":113,"name":"1000396"},{"balance":206,"name":"1000745","owner_address":"TPCEi45wZQ1PPChUg5uqoK1D5kKnjCR8Li"},{"balance":61,"name":"1000821","owner_address":"TBm3Peu51gYwn2iPwNEDxc9vBMc3eRGUGu"},{"balance":25,"name":"1000541"},{"balance":7,"name":"1000278","owner_address":"TRMUimDekf9nDLuVMp6TKzcw4axNnajGJr"},{"balance":1,"name":"1000567","owner_address":"TFXJMhB4ZKBfcQWfCLbSyQGhonHXABaWku"},{"balance":1,"name":"1000856","owner_address":"TXf3X8YMdDho2xwA6QDbFZiTGPnk8ghfLm"},{"balance":30,"name":"1000884"},{"balance":1,"name":"1000894"},{"balance":200,"name":"1000181","owner_address":"TEmTbbvH5ZPJPZ8CbffjqonFRiAAFgfc9o"},{"balance":7,"name":"1000935","owner_address":"TPVkcFYTEi9Dia45AveiTcaYoaU9ux7xC7"},{"balance":1000,"name":"1000938","owner_address":"TNgkWTabK1rMWwgLjmLdsZbzYfGTx5Tpe9"},{"balance":10,"name":"1000017","owner_address":"TV6qcwSp38uESiDczxxb7zbJX1h2LfDs78"},{"balance":10,"name":"1001011","owner_address":"TNUbeTQXPtRXtBX3dJboVkhdhaiws29Aky"},{"balance":2,"name":"1001038","owner_address":"TFujVDp8U578L2AtsorYN3pwdXmH2HxbQv"},{"balance":100,"name":"1000983","owner_address":"TYmiZ7xCeqboiizb2jsjVQuRABXzVSjKFR"},{"balance":1,"name":"1001203","owner_address":"TBmaT8mcrdkrRL2Q6ur7grMYAcaGtfxsz7"},{"balance":1,"name":"1000190","owner_address":"TNXjXURue38Wa641pmqMH4vbJN1WZLKMnr"},{"balance":100,"name":"1001204"},{"balance":1000,"name":"1001230"},{"balance":1300000,"name":"1001301","owner_address":"TVgJEbc9NEYxVr1h6rJQiMqySePsJQDCA7"},{"balance":11,"name":"1000959"},{"balance":10,"name":"1001425"},{"balance":17,"name":"1001433","owner_address":"TWPMz6FPEAV6qP4VRMG3Y69ftEov1R7YWT"},{"balance":100,"name":"1001446"},{"balance":12,"name":"1001411","owner_address":"TPL6zNujtEQ8kp213n58UxAhGRCU3aozkc"},{"balance":12,"name":"1001467"},{"balance":100,"name":"1001414","owner_address":"TT43DgfxgMdR4BVZNua4YCwG34AgfGN6Uu"},{"balance":100,"name":"1001510","owner_address":"TPKq9bVZyM2sZ8XersMmXhy1NbjhdxRwwj"},{"balance":50,"name":"1001565","owner_address":"TKY7Vmq78b2c83fLXrPijkhQkk4EJtfViD"},{"balance":5,"name":"1001535"},{"balance":10,"name":"1000532","owner_address":"TGQwBNht8h3zev4gBtDMoQjWE2WJm1Zr9B"},{"balance":3,"name":"1001479","owner_address":"TC9FtB1EoiV3jfXgZvmqUmfeCmdWNmCxdY"},{"balance":13,"name":"1001090","owner_address":"TU1LUTYDMG6iihimUpAmdnnBthawPKh1cm","priceInTrx":0.004360},{"balance":200,"name":"1001759","owner_address":"TWKWWJAFBYyjvLtfqKCSeMyUW7TjWhkY4e"},{"balance":12,"name":"1000096","owner_address":"TSfjkVSKJGW4aybDQcxi4bpythU7WCXV3v"},{"balance":15,"name":"1001594"},{"balance":10,"name":"1001815","owner_address":"TB3iM1RsKXagV7hdz2QpWnaChptwrU3tCL"},{"balance":10,"name":"1001064","owner_address":"THnWV416C9mfJ1LFwopUjGXZEr1xFtAdrD"},{"balance":5192508733304578,"name":"1002000","owner_address":"TF5Bn4cJCT6GVeUgyCN4rBhDg42KBrpAjg","priceInTrx":0.018900},{"balance":7742069,"name":"1002037","owner_address":"TBekuTCZwPG2o88SmiS58VALkxBemoX4yS"},{"balance":585,"name":"1002001"},{"balance":5441,"name":"1002071","owner_address":"TS79aik831csqUnQgnqrKG6hov2iL8yPbD"},{"balance":80312957663126,"name":"1002072","owner_address":"TP6PtaBSMM6sfWtWWD9k77YHWGmh7K3Lae"},{"balance":520,"name":"1000451","owner_address":"THPXuypwcnWo4wi5KqFfuRjgjeT5khUDKF"},{"balance":10011237,"name":"1001953","owner_address":"TSyG9BdjsGE2GoHG9eeYKMns6zMQFDmbvS"},{"balance":5,"name":"1000562","owner_address":"TWqKTJ5JhyD7rsbbWzEvS5ZZD9Q5QPPvSH"},{"balance":50000000,"name":"1002099","owner_address":"TYWmiPERm9kWUcnduqaE5jxT7eeZxfn5SQ"},{"balance":625100,"name":"1001581","owner_address":"TNkRSKWP7VvdrisTwC8iNzUV6MRoEJh6xx"},{"balance":11000000,"name":"1002342","owner_address":"TUCd8NiBUuxrjz1kSrUbAg2JXu6o27Ukrq"},{"balance":7,"name":"1000322","owner_address":"TDGy2M9qWBepSHDEutWWxWd1JZfmAed3BP","priceInTrx":0.000422},{"balance":12,"name":"1001825","owner_address":"TPcUbNeYwwYqbX23w3sVf1X61cwpAfPK2T"},{"balance":1000,"name":"1002384","owner_address":"TFYuPxyjDTvH1TLm2phpzJFw7AhjCgu8xP"},{"balance":44444,"name":"1001132","owner_address":"TWDUanVdxEShjpbiX57ExztMCDy8vCFcHh"},{"balance":30000000,"name":"1002398","owner_address":"TUXSuMg41nJXm9TuDgF6EZWjEbP2vx1Hd4"},{"balance":10000060,"name":"1002116","owner_address":"TAEvo6MgLgV3A75L3cr3BAsLDJikWcAt3j"},{"balance":50000000,"name":"1002446","owner_address":"TJKf72NjL1cR49SHfDnPTXTFjRwjgr7v8Z"},{"balance":10000000,"name":"1002459","owner_address":"TNWy3mX85JsX2mPLgLc4cKJiWtJahhz3t3"},{"balance":1,"name":"1001079","owner_address":"TLQfc5EwZQqZc6jMNkMpxyJy5wucA6UX24"},{"balance":12345,"name":"1002467","owner_address":"TP429SKrsp4BoTiEFXHj4TNSJwqDFsygnr"},{"balance":1234,"name":"1002230","owner_address":"TWB9Q1JoB3fSLsahNq31gydRxYyWxDhSyk"},{"balance":10000000,"name":"1002288","owner_address":"TPzfpaaKUPgJPZ39YeyvBaTYNXBYpnhxDg"},{"balance":5,"name":"1002488","owner_address":"TMeAzhdgzu1sFMTsP75BffJ2tEzuGsYqR6"},{"balance":666,"name":"1002438","owner_address":"TMqNJwD3qVmuRxzzP3Q4A24fuByVBKQ39E"},{"balance":10000000,"name":"1002517","owner_address":"TP9m11ERHhE1qgDtL83c2AHHNkWvdUfKTz"},{"balance":10000000000,"name":"1002521","owner_address":"TJUwM4qk1et2nNKuESQ7UVHPjAHoRqAz3T"},{"balance":13699,"name":"1000157","owner_address":"TUahmv54ZiDnjQWG2VAeyMphebXQ4m6Hb5"},{"balance":65895,"name":"1002524","owner_address":"TRzZeBPt69utiWx1po5ghLH8uSP8uJGsa5"},{"balance":16,"name":"1000287","owner_address":"TFZCyZ18XNzMfEr6W5kLkGrs4HVmou9H3y"},{"balance":10000000,"name":"1002544","owner_address":"TQHBbjES5DNjDfDHBbpnh9qcDM7mVjSVcL"},{"balance":10000000000,"name":"1002551","owner_address":"TVrGxBCQkWjQ52D7S67UgFsUzcX4E8EsNB"},{"balance":10000000,"name":"1002573","owner_address":"TBfmGqmZtdEQNuYCz8s1izBUDxZbkPmMcj"},{"balance":10000000,"name":"1002552","owner_address":"TCxeAH2ajBqoWzqV9m5YiFTyeQ5FvzVqSH"},{"balance":1000000,"name":"1002578","owner_address":"TUjBG7C1CU7X75UmacnyrRTYLmbSeX7iDa"},{"balance":2555000,"name":"1002270","owner_address":"TMSpdYHCgZuxM7AjqKsjGMM1cpxraFuZGp"},{"balance":10000000,"name":"1002597","owner_address":"TDEBhgsdGTSzrgMsPDUQ1pt59fR6wWR7Rq"},{"balance":10000000,"name":"1002636","owner_address":"TKL54NcGXvBckkGbPjYzAmdwFs3usv8VY9"},{"balance":100000000,"name":"1002250","owner_address":"THUHfNqiYo4KS3GLM8MUU4x3wek9uPD47d"},{"balance":1000000,"name":"1002662","owner_address":"TEV5PJWga6crSeNLHmHaaco8fon6nm74wJ"},{"balance":10000000,"name":"1002672","owner_address":"TBHJCf3nymJPt1hVPjSJfH5ssJLdNMPepe"},{"balance":24120,"name":"1002657","owner_address":"TCKiVea721ycNAWonb2dpwr65AJkMiGSFb"},{"balance":1000000,"name":"1002683","owner_address":"TL6YggMQQ3YFEc41wesBMHZjDxcGpX3y5q"},{"balance":3000000,"name":"1002671","owner_address":"TDQ5q4Hf6UqR43Smp67sndMQfdTcGgP88s"},{"balance":20,"name":"1002577","owner_address":"TGZzci6a9wtcSiNekqYLP84ECRoaJ6pBwY"},{"balance":10000000,"name":"1002721","owner_address":"TUkUgsTTo74B9XG9da4d2NsaZqCKLNFwNS"},{"balance":10000,"name":"1002726","owner_address":"TRXw3Ggt3xs3fHbcoark1aeKwUZFKTYcsS"},{"balance":21092024781,"name":"1002263","owner_address":"TD5AwyiTNbKN9jQqyMzwQ6NLrWGbtAcotK"},{"balance":10000000,"name":"1002736","owner_address":"TBB19fMCf19wuiu5omtA1nAqALPpo4oa32"},{"balance":10000000,"name":"1002646","owner_address":"TRUnzvtzT6o35M4XHUvKr48yCZjw4dQyvp"},{"balance":7392000000,"name":"1002589","owner_address":"TUL9NhGQkRFLTRcHGkdoSniAeVaNPZGgot"},{"balance":10000000,"name":"1002742","owner_address":"TWfrNPVGDh1tyPVM79bfEASb7jw2bLbZPJ"},{"balance":8822711275000000,"name":"1002762","owner_address":"TRChSJM8TjQj7vvJCN9W8WBcfkJq2eBxgv"},{"balance":10000000,"name":"1002775"},{"balance":10000000,"name":"1002798","owner_address":"TBitZMK7YSUb2Q1Cm537D5iAZSJkaPdN9c"},{"balance":95,"name":"1001854","owner_address":"TSMeDkfmX6m1NZmDBrVtGPnACJCUWVkx4p"},{"balance":10000000,"name":"1002746","owner_address":"TQbbAyfcrKERXjUDf8TZfcdtjFQbCSgEfc"},{"balance":2000000,"name":"1002669","owner_address":"THhgpkHBdJDDWBPnZKRgzdvRr3qCtAa2cv"},{"balance":10000000,"name":"1002814","owner_address":"TNvq4y2A2beBENtcGknwhX6XHgk8hqgnVh"},{"balance":10000000,"name":"1002830","owner_address":"THLLMnsEKEci5e5dJHnW28QQU8AujGhSoK"},{"balance":10000000,"name":"1002845","owner_address":"TUzpDkzjWkZasA6Dx7nx5PPskMkCcNxVyQ"},{"balance":10000000,"name":"1002858","owner_address":"TRKJcugHJeffVpCAFGapZMwuH8HaTWjbof"},{"balance":200,"name":"1002454","owner_address":"TDCGkNf3XB3jRGg7bhFkNynkGw7q4kV3z9"},{"balance":10000000,"name":"1002876","owner_address":"TGqiinRV6nn8GbF5LX7zue4fpjstG1gVvu"},{"balance":20000000,"name":"1002881","owner_address":"TWpKN6y3NVXm5mMjGmPEtLpS6boGM4q8T4"},{"balance":350,"name":"1000145","owner_address":"TNFcvwJgvBRg2Dq5Qyx1gxcvqU3dwPyVNc"},{"balance":10000000,"name":"1002892","owner_address":"TECsVV1kTtx48sbdjvptq544h4H3Qqr24c"},{"balance":10000000,"name":"1002897","owner_address":"TPKqse19ALipJ1uBZHGWHzuTrQqZa4HtaM"},{"balance":2055000000,"name":"1002822","owner_address":"TURy9pFLskqTWgkZqUCUdPXkezZfYL76YQ"},{"balance":1000000,"name":"1002852","owner_address":"TUmad3hCqxu78n8GuULrdJMUB4qmTUYgv3"},{"balance":10000000,"name":"1002907","owner_address":"TKC9HMUXx3qLE7d19KWzWVjFxEcWQdSYK9"},{"balance":10000000,"name":"1002927","owner_address":"TAwRvFAqfB4bbzVCVPgGATZV5uMVs9UyVL"},{"balance":10000000,"name":"1002926","owner_address":"TF5jfDiQ3d7T5ihcBxeWS9S8xSR5tS738x"},{"balance":1000000,"name":"1002748","owner_address":"TTUAmhh9k2Yegf3TxZc86vG5E9kT24vgcw"},{"balance":189990000000,"name":"1002950","owner_address":"TNCZCGDPQ69ieJFsY1jZUohXmR46A4kM24"},{"balance":10,"name":"1000985","owner_address":"TRH5jmPx77UnMvfdvfo2m3FCkZVcBiFvqP"},{"balance":10000000,"name":"1002962","owner_address":"TFDwGwod9qopreRiirsFMwPzX4v2r662P4"},{"balance":10000000,"name":"1002918","owner_address":"TKGpTks1myPrJ9ZtEdLgpjvg1RMR2wGAFz"},{"balance":1000,"name":"1002608","owner_address":"TDPsSgBQznKEffdTMq3aspsvrmFfhL7ZcP"},{"balance":10000000,"name":"1002999","owner_address":"TTL52uBzTG7qorL7BQYdjGUY3HWWr9Kvao"},{"balance":100000000000,"name":"1003022","owner_address":"TAAJiJ1NgkEkE3w1PQk4dA8XH9rpfk5eVE"},{"balance":1000000000,"name":"1003041","owner_address":"TQADZoww5HstdsJM1GXwstqsRRnmrkThzY"},{"balance":10000000,"name":"1003049","owner_address":"THFJwSN5Z3zTc5TvkSiVh8m4kQMZaTMaqk"},{"balance":1,"name":"1002939","owner_address":"TAsSw8hUddYi8AN8EkDuAMS9r8pkriyUxs"}],"balances":[{"balance":346976329314696,"name":"_"},{"balance":1273,"name":"1000003"},{"balance":113,"name":"1000006"},{"balance":145,"name":"1000165"},{"balance":416,"name":"1000520"},{"balance":596,"name":"1000491"},{"balance":242,"name":"1000176","owner_address":"THG48yHsR6inxrCJk2hhxZPsFLq1ehP88V"},{"balance":62,"name":"1000542"},{"balance":53,"name":"1000494","owner_address":"TXJnVqqwLSNmdXDLWn1Yfjhe8aZH2oaAuq"},{"balance":56,"name":"1000493"},{"balance":599,"name":"1000744"},{"balance":628,"name":"1000746"},{"balance":234,"name":"1000743"},{"balance":113,"name":"1000396"},{"balance":206,"name":"1000745","owner_address":"TPCEi45wZQ1PPChUg5uqoK1D5kKnjCR8Li"},{"balance":61,"name":"1000821","owner_address":"TBm3Peu51gYwn2iPwNEDxc9vBMc3eRGUGu"},{"balance":25,"name":"1000541"},{"balance":7,"name":"1000278","owner_address":"TRMUimDekf9nDLuVMp6TKzcw4axNnajGJr"},{"balance":1,"name":"1000567","owner_address":"TFXJMhB4ZKBfcQWfCLbSyQGhonHXABaWku"},{"balance":1,"name":"1000856","owner_address":"TXf3X8YMdDho2xwA6QDbFZiTGPnk8ghfLm"},{"balance":30,"name":"1000884"},{"balance":1,"name":"1000894"},{"balance":200,"name":"1000181","owner_address":"TEmTbbvH5ZPJPZ8CbffjqonFRiAAFgfc9o"},{"balance":7,"name":"1000935","owner_address":"TPVkcFYTEi9Dia45AveiTcaYoaU9ux7xC7"},{"balance":1000,"name":"1000938","owner_address":"TNgkWTabK1rMWwgLjmLdsZbzYfGTx5Tpe9"},{"balance":10,"name":"1000017","owner_address":"TV6qcwSp38uESiDczxxb7zbJX1h2LfDs78"},{"balance":10,"name":"1001011","owner_address":"TNUbeTQXPtRXtBX3dJboVkhdhaiws29Aky"},{"balance":2,"name":"1001038","owner_address":"TFujVDp8U578L2AtsorYN3pwdXmH2HxbQv"},{"balance":100,"name":"1000983","owner_address":"TYmiZ7xCeqboiizb2jsjVQuRABXzVSjKFR"},{"balance":1,"name":"1001203","owner_address":"TBmaT8mcrdkrRL2Q6ur7grMYAcaGtfxsz7"},{"balance":1,"name":"1000190","owner_address":"TNXjXURue38Wa641pmqMH4vbJN1WZLKMnr"},{"balance":100,"name":"1001204"},{"balance":1000,"name":"1001230"},{"balance":1300000,"name":"1001301","owner_address":"TVgJEbc9NEYxVr1h6rJQiMqySePsJQDCA7"},{"balance":11,"name":"1000959"},{"balance":10,"name":"1001425"},{"balance":17,"name":"1001433","owner_address":"TWPMz6FPEAV6qP4VRMG3Y69ftEov1R7YWT"},{"balance":100,"name":"1001446"},{"balance":12,"name":"1001411","owner_address":"TPL6zNujtEQ8kp213n58UxAhGRCU3aozkc"},{"balance":12,"name":"1001467"},{"balance":100,"name":"1001414","owner_address":"TT43DgfxgMdR4BVZNua4YCwG34AgfGN6Uu"},{"balance":100,"name":"1001510","owner_address":"TPKq9bVZyM2sZ8XersMmXhy1NbjhdxRwwj"},{"balance":50,"name":"1001565","owner_address":"TKY7Vmq78b2c83fLXrPijkhQkk4EJtfViD"},{"balance":5,"name":"1001535"},{"balance":10,"name":"1000532","owner_address":"TGQwBNht8h3zev4gBtDMoQjWE2WJm1Zr9B"},{"balance":3,"name":"1001479","owner_address":"TC9FtB1EoiV3jfXgZvmqUmfeCmdWNmCxdY"},{"balance":13,"name":"1001090","owner_address":"TU1LUTYDMG6iihimUpAmdnnBthawPKh1cm","priceInTrx":0.004360},{"balance":200,"name":"1001759","owner_address":"TWKWWJAFBYyjvLtfqKCSeMyUW7TjWhkY4e"},{"balance":12,"name":"1000096","owner_address":"TSfjkVSKJGW4aybDQcxi4bpythU7WCXV3v"},{"balance":15,"name":"1001594"},{"balance":10,"name":"1001815","owner_address":"TB3iM1RsKXagV7hdz2QpWnaChptwrU3tCL"},{"balance":10,"name":"1001064","owner_address":"THnWV416C9mfJ1LFwopUjGXZEr1xFtAdrD"},{"balance":5192508733304578,"name":"1002000","owner_address":"TF5Bn4cJCT6GVeUgyCN4rBhDg42KBrpAjg","priceInTrx":0.018900},{"balance":7742069,"name":"1002037","owner_address":"TBekuTCZwPG2o88SmiS58VALkxBemoX4yS"},{"balance":585,"name":"1002001"},{"balance":5441,"name":"1002071","owner_address":"TS79aik831csqUnQgnqrKG6hov2iL8yPbD"},{"balance":80312957663126,"name":"1002072","owner_address":"TP6PtaBSMM6sfWtWWD9k77YHWGmh7K3Lae"},{"balance":520,"name":"1000451","owner_address":"THPXuypwcnWo4wi5KqFfuRjgjeT5khUDKF"},{"balance":10011237,"name":"1001953","owner_address":"TSyG9BdjsGE2GoHG9eeYKMns6zMQFDmbvS"},{"balance":5,"name":"1000562","owner_address":"TWqKTJ5JhyD7rsbbWzEvS5ZZD9Q5QPPvSH"},{"balance":50000000,"name":"1002099","owner_address":"TYWmiPERm9kWUcnduqaE5jxT7eeZxfn5SQ"},{"balance":625100,"name":"1001581","owner_address":"TNkRSKWP7VvdrisTwC8iNzUV6MRoEJh6xx"},{"balance":11000000,"name":"1002342","owner_address":"TUCd8NiBUuxrjz1kSrUbAg2JXu6o27Ukrq"},{"balance":7,"name":"1000322","owner_address":"TDGy2M9qWBepSHDEutWWxWd1JZfmAed3BP","priceInTrx":0.000422},{"balance":12,"name":"1001825","owner_address":"TPcUbNeYwwYqbX23w3sVf1X61cwpAfPK2T"},{"balance":1000,"name":"1002384","owner_address":"TFYuPxyjDTvH1TLm2phpzJFw7AhjCgu8xP"},{"balance":44444,"name":"1001132","owner_address":"TWDUanVdxEShjpbiX57ExztMCDy8vCFcHh"},{"balance":30000000,"name":"1002398","owner_address":"TUXSuMg41nJXm9TuDgF6EZWjEbP2vx1Hd4"},{"balance":10000060,"name":"1002116","owner_address":"TAEvo6MgLgV3A75L3cr3BAsLDJikWcAt3j"},{"balance":50000000,"name":"1002446","owner_address":"TJKf72NjL1cR49SHfDnPTXTFjRwjgr7v8Z"},{"balance":10000000,"name":"1002459","owner_address":"TNWy3mX85JsX2mPLgLc4cKJiWtJahhz3t3"},{"balance":1,"name":"1001079","owner_address":"TLQfc5EwZQqZc6jMNkMpxyJy5wucA6UX24"},{"balance":12345,"name":"1002467","owner_address":"TP429SKrsp4BoTiEFXHj4TNSJwqDFsygnr"},{"balance":1234,"name":"1002230","owner_address":"TWB9Q1JoB3fSLsahNq31gydRxYyWxDhSyk"},{"balance":10000000,"name":"1002288","owner_address":"TPzfpaaKUPgJPZ39YeyvBaTYNXBYpnhxDg"},{"balance":5,"name":"1002488","owner_address":"TMeAzhdgzu1sFMTsP75BffJ2tEzuGsYqR6"},{"balance":666,"name":"1002438","owner_address":"TMqNJwD3qVmuRxzzP3Q4A24fuByVBKQ39E"},{"balance":10000000,"name":"1002517","owner_address":"TP9m11ERHhE1qgDtL83c2AHHNkWvdUfKTz"},{"balance":10000000000,"name":"1002521","owner_address":"TJUwM4qk1et2nNKuESQ7UVHPjAHoRqAz3T"},{"balance":13699,"name":"1000157","owner_address":"TUahmv54ZiDnjQWG2VAeyMphebXQ4m6Hb5"},{"balance":65895,"name":"1002524","owner_address":"TRzZeBPt69utiWx1po5ghLH8uSP8uJGsa5"},{"balance":16,"name":"1000287","owner_address":"TFZCyZ18XNzMfEr6W5kLkGrs4HVmou9H3y"},{"balance":10000000,"name":"1002544","owner_address":"TQHBbjES5DNjDfDHBbpnh9qcDM7mVjSVcL"},{"balance":10000000000,"name":"1002551","owner_address":"TVrGxBCQkWjQ52D7S67UgFsUzcX4E8EsNB"},{"balance":10000000,"name":"1002573","owner_address":"TBfmGqmZtdEQNuYCz8s1izBUDxZbkPmMcj"},{"balance":10000000,"name":"1002552","owner_address":"TCxeAH2ajBqoWzqV9m5YiFTyeQ5FvzVqSH"},{"balance":1000000,"name":"1002578","owner_address":"TUjBG7C1CU7X75UmacnyrRTYLmbSeX7iDa"},{"balance":2555000,"name":"1002270","owner_address":"TMSpdYHCgZuxM7AjqKsjGMM1cpxraFuZGp"},{"balance":10000000,"name":"1002597","owner_address":"TDEBhgsdGTSzrgMsPDUQ1pt59fR6wWR7Rq"},{"balance":10000000,"name":"1002636","owner_address":"TKL54NcGXvBckkGbPjYzAmdwFs3usv8VY9"},{"balance":100000000,"name":"1002250","owner_address":"THUHfNqiYo4KS3GLM8MUU4x3wek9uPD47d"},{"balance":1000000,"name":"1002662","owner_address":"TEV5PJWga6crSeNLHmHaaco8fon6nm74wJ"},{"balance":10000000,"name":"1002672","owner_address":"TBHJCf3nymJPt1hVPjSJfH5ssJLdNMPepe"},{"balance":24120,"name":"1002657","owner_address":"TCKiVea721ycNAWonb2dpwr65AJkMiGSFb"},{"balance":1000000,"name":"1002683","owner_address":"TL6YggMQQ3YFEc41wesBMHZjDxcGpX3y5q"},{"balance":3000000,"name":"1002671","owner_address":"TDQ5q4Hf6UqR43Smp67sndMQfdTcGgP88s"},{"balance":20,"name":"1002577","owner_address":"TGZzci6a9wtcSiNekqYLP84ECRoaJ6pBwY"},{"balance":10000000,"name":"1002721","owner_address":"TUkUgsTTo74B9XG9da4d2NsaZqCKLNFwNS"},{"balance":10000,"name":"1002726","owner_address":"TRXw3Ggt3xs3fHbcoark1aeKwUZFKTYcsS"},{"balance":21092024781,"name":"1002263","owner_address":"TD5AwyiTNbKN9jQqyMzwQ6NLrWGbtAcotK"},{"balance":10000000,"name":"1002736","owner_address":"TBB19fMCf19wuiu5omtA1nAqALPpo4oa32"},{"balance":10000000,"name":"1002646","owner_address":"TRUnzvtzT6o35M4XHUvKr48yCZjw4dQyvp"},{"balance":7392000000,"name":"1002589","owner_address":"TUL9NhGQkRFLTRcHGkdoSniAeVaNPZGgot"},{"balance":10000000,"name":"1002742","owner_address":"TWfrNPVGDh1tyPVM79bfEASb7jw2bLbZPJ"},{"balance":8822711275000000,"name":"1002762","owner_address":"TRChSJM8TjQj7vvJCN9W8WBcfkJq2eBxgv"},{"balance":10000000,"name":"1002775"},{"balance":10000000,"name":"1002798","owner_address":"TBitZMK7YSUb2Q1Cm537D5iAZSJkaPdN9c"},{"balance":95,"name":"1001854","owner_address":"TSMeDkfmX6m1NZmDBrVtGPnACJCUWVkx4p"},{"balance":10000000,"name":"1002746","owner_address":"TQbbAyfcrKERXjUDf8TZfcdtjFQbCSgEfc"},{"balance":2000000,"name":"1002669","owner_address":"THhgpkHBdJDDWBPnZKRgzdvRr3qCtAa2cv"},{"balance":10000000,"name":"1002814","owner_address":"TNvq4y2A2beBENtcGknwhX6XHgk8hqgnVh"},{"balance":10000000,"name":"1002830","owner_address":"THLLMnsEKEci5e5dJHnW28QQU8AujGhSoK"},{"balance":10000000,"name":"1002845","owner_address":"TUzpDkzjWkZasA6Dx7nx5PPskMkCcNxVyQ"},{"balance":10000000,"name":"1002858","owner_address":"TRKJcugHJeffVpCAFGapZMwuH8HaTWjbof"},{"balance":200,"name":"1002454","owner_address":"TDCGkNf3XB3jRGg7bhFkNynkGw7q4kV3z9"},{"balance":10000000,"name":"1002876","owner_address":"TGqiinRV6nn8GbF5LX7zue4fpjstG1gVvu"},{"balance":20000000,"name":"1002881","owner_address":"TWpKN6y3NVXm5mMjGmPEtLpS6boGM4q8T4"},{"balance":350,"name":"1000145","owner_address":"TNFcvwJgvBRg2Dq5Qyx1gxcvqU3dwPyVNc"},{"balance":10000000,"name":"1002892","owner_address":"TECsVV1kTtx48sbdjvptq544h4H3Qqr24c"},{"balance":10000000,"name":"1002897","owner_address":"TPKqse19ALipJ1uBZHGWHzuTrQqZa4HtaM"},{"balance":2055000000,"name":"1002822","owner_address":"TURy9pFLskqTWgkZqUCUdPXkezZfYL76YQ"},{"balance":1000000,"name":"1002852","owner_address":"TUmad3hCqxu78n8GuULrdJMUB4qmTUYgv3"},{"balance":10000000,"name":"1002907","owner_address":"TKC9HMUXx3qLE7d19KWzWVjFxEcWQdSYK9"},{"balance":10000000,"name":"1002927","owner_address":"TAwRvFAqfB4bbzVCVPgGATZV5uMVs9UyVL"},{"balance":10000000,"name":"1002926","owner_address":"TF5jfDiQ3d7T5ihcBxeWS9S8xSR5tS738x"},{"balance":1000000,"name":"1002748","owner_address":"TTUAmhh9k2Yegf3TxZc86vG5E9kT24vgcw"},{"balance":189990000000,"name":"1002950","owner_address":"TNCZCGDPQ69ieJFsY1jZUohXmR46A4kM24"},{"balance":10,"name":"1000985","owner_address":"TRH5jmPx77UnMvfdvfo2m3FCkZVcBiFvqP"},{"balance":10000000,"name":"1002962","owner_address":"TFDwGwod9qopreRiirsFMwPzX4v2r662P4"},{"balance":10000000,"name":"1002918","owner_address":"TKGpTks1myPrJ9ZtEdLgpjvg1RMR2wGAFz"},{"balance":1000,"name":"1002608","owner_address":"TDPsSgBQznKEffdTMq3aspsvrmFfhL7ZcP"},{"balance":10000000,"name":"1002999","owner_address":"TTL52uBzTG7qorL7BQYdjGUY3HWWr9Kvao"},{"balance":100000000000,"name":"1003022","owner_address":"TAAJiJ1NgkEkE3w1PQk4dA8XH9rpfk5eVE"},{"balance":1000000000,"name":"1003041","owner_address":"TQADZoww5HstdsJM1GXwstqsRRnmrkThzY"},{"balance":10000000,"name":"1003049","owner_address":"THFJwSN5Z3zTc5TvkSiVh8m4kQMZaTMaqk"},{"balance":1,"name":"1002939","owner_address":"TAsSw8hUddYi8AN8EkDuAMS9r8pkriyUxs"}],"balance":346976329314696,"voteTotal":0,"name":"","delegated":{"sentDelegatedBandwidth":[],"sentDelegatedResource":[],"receivedDelegatedResource":[],"receivedDelegatedBandwidth":[]},"totalTransactionCount":508552,"representative":{"lastWithDrawTime":0,"allowance":0,"enabled":false,"url":""},"activePermissions":[]}` mockedTransactionsTrc20Response = `{"success":true,"meta":{"at":1592757126588,"page_size":20,"fingerprint":"2tmLC90HQEnpnJ02w3n","links":{"next":"https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D/transactions/trc20?fingerprint=2tmLC90HQEnpnJ02w3n"}},"data":[{"block_timestamp":1592757117000,"value":"500000000","type":"Transfer","transaction_id":"fb078403adfee637608c3906d9d21dd158611aba149b9993f43d0f292ce543a0","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","token_info":{"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","name":"Tether USD","symbol":"USDT","decimals":6},"_unconfirmed":true},{"block_timestamp":1592757066000,"value":"50000000","type":"Transfer","transaction_id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","token_info":{"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","name":"Tether USD","symbol":"USDT","decimals":6},"_unconfirmed":true},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","block_timestamp":1592757066000,"value":"50000000","type":"Transfer","transaction_id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV","block_timestamp":1592756784000,"value":"3988000000","type":"Transfer","transaction_id":"0b52a4ef9fb8c13fbfae2b8c3506333ec1d718f307062a15f170562818a01d0a","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am","block_timestamp":1592756763000,"value":"640990000","type":"Transfer","transaction_id":"19d2ec6174bf64beb1061475f6429cba03b64944a763686cc3551447d0e8d9d5","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756631000,"value":"1062000000","type":"Transfer","transaction_id":"efb7d44305759cfb189c9fd22720609a2ddeb7fbd7c8afe1dd8851342471da8d","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","block_timestamp":1592756610000,"value":"2000000","type":"Transfer","transaction_id":"48bd90dc3f12086178e65b9389caa8b3c74683937b86d4d61cdec77f0095994a","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R","block_timestamp":1592756589000,"value":"1000000000","type":"Transfer","transaction_id":"afd5ae7e2462c9cc899c7f730b90fd2a5e4c1315e836c92468b504ed85f0b798","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq","block_timestamp":1592756583000,"value":"21200000","type":"Transfer","transaction_id":"3d613031f4b2a0e19deeea030d1d18599b6d9799d2dd530005ead9712c6d219d","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5","block_timestamp":1592756583000,"value":"125000000","type":"Transfer","transaction_id":"cbe359c2574efbdc8fc6a892ffc54812837295067c9816d41734126c82d0c141","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC","block_timestamp":1592756583000,"value":"5277600000","type":"Transfer","transaction_id":"c87248b02a4caaa6f443c1b8c4d4588c8dd281a4687b73e6afecfba6741b50d8","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W","block_timestamp":1592756583000,"value":"485342000","type":"Transfer","transaction_id":"8584f1b6a70ead8232fed19bd653ba13e4c2a8befd070f4a9a06eca3a2e3e548","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr","block_timestamp":1592756583000,"value":"1000000000","type":"Transfer","transaction_id":"2b28b69e6747db68647acc3a62c45da5355b97acd8d2c260ee752aa9bd63a624","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x","block_timestamp":1592756583000,"value":"2000000000","type":"Transfer","transaction_id":"1da6576dec0bd303f56cbfb5712f782e0a56a8713cb661f8afd2f2533e5c6209","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK","block_timestamp":1592756583000,"value":"24216600000","type":"Transfer","transaction_id":"f9c86cce1873cb816d6cd8718e76df8839172add293bbc8d11a5f98c80f9e322","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756541000,"value":"8241997837","type":"Transfer","transaction_id":"75eb35734857daa79c38ef923a7e7eb2e3dfb23d2722762fd2b180651021643f","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756220000,"value":"18000000000","type":"Transfer","transaction_id":"adee73dadce006ff848ff30d8c5c41f033be2e5e1a8b875f6dbbaab524177d08","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592755962000,"value":"863399098","type":"Transfer","transaction_id":"3655a1156c9adcb876c6c9c9e0f5f1f39704ac4c7296fea05fedf5ca8f6b1a19","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ","block_timestamp":1592755740000,"value":"20000000","type":"Transfer","transaction_id":"03574741eb0016050a19f181e4acc4b20b70f41e11e63140c9556c31eae09fba","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug","block_timestamp":1592755722000,"value":"21161340000","type":"Transfer","transaction_id":"f3aa00595996e31dbe9528a3cb21bff987f333bf1f675420ba4fa2ad43c8205f","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}}]}` diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index 8fdeaab2b..cf3a53ec9 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -7,6 +7,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/golibs/coin" "strconv" + "strings" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { @@ -67,7 +68,7 @@ func addTokenMeta(tx *blockatlas.Tx, srcTx Tx, tokenInfo AssetInfo) { transfer := srcTx.Data.Contracts[0].Parameter.Value tx.Meta = blockatlas.TokenTransfer{ Name: tokenInfo.Name, - Symbol: tokenInfo.Symbol, + Symbol: strings.ToUpper(tokenInfo.Symbol), TokenID: tokenInfo.ID, Decimals: tokenInfo.Decimals, Value: transfer.Amount, diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index cc5c5c189..6306228bc 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -17,9 +17,14 @@ func GetTransactionsFromDelivery(delivery amqp.Delivery, ctx context.Context) (b span, _ := apm.StartSpan(ctx, "GetTransactionsFromDelivery", "app") defer span.End() + logger.Info("--------------------------------------------") + logger.Info("Unmarshal: ") + logger.Info(delivery.Body) if err := json.Unmarshal(delivery.Body, &txs); err != nil { return nil, err } + logger.Info("Done") + logger.Info("--------------------------------------------") logger.Info("Consumed", logger.Params{"txs": len(txs), "coin": txs[0].Coin}) diff --git a/services/subscriber/tokens.go b/services/subscriber/tokens.go index 825d2b30f..d5112ef69 100644 --- a/services/subscriber/tokens.go +++ b/services/subscriber/tokens.go @@ -5,6 +5,7 @@ import ( "encoding/json" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/logger" "go.elastic.co/apm" "strconv" @@ -18,7 +19,7 @@ func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { ctx := apm.ContextWithTransaction(context.Background(), tx) logger.Info("body " + string(delivery.Body)) - event := make(map[string][]string) + event := make(map[string][]models.Asset) if err := json.Unmarshal(delivery.Body, &event); err != nil { if err := delivery.Ack(false); err != nil { logger.Fatal(err, err) diff --git a/services/tokenindexer/api.go b/services/tokenindexer/api.go new file mode 100644 index 000000000..3a4ba6a5d --- /dev/null +++ b/services/tokenindexer/api.go @@ -0,0 +1,40 @@ +package tokenindexer + +import ( + "context" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/db/models" + "time" +) + +type Instance struct { + database *db.Instance +} + +func Init(database *db.Instance) Instance { + return Instance{database: database} +} + +func (i Instance) HandleNewTokensRequest(r Request, ctx context.Context) (Response, error) { + from := time.Unix(r.From, 0) + result, err := i.database.GetAssetsFrom(from, ctx) + if err != nil { + return Response{}, err + } + return normalize(result), nil +} + +func normalize(dbAssets []models.Asset) Response { + var result []Asset + for _, a := range dbAssets { + asset := Asset{ + Asset: a.Asset, + Name: a.Name, + Symbol: a.Symbol, + Type: a.Type, + Decimals: a.Decimals, + } + result = append(result, asset) + } + return Response{Assets: result} +} diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go new file mode 100644 index 000000000..8040d3e46 --- /dev/null +++ b/services/tokenindexer/indexer.go @@ -0,0 +1,57 @@ +package tokenindexer + +import ( + "context" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/services/notifier" + "go.elastic.co/apm" +) + +func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) { + tx := apm.DefaultTracer.StartTransaction("RunTokenIndexer", "app") + defer tx.End() + defer func() { + if err := delivery.Ack(false); err != nil { + logger.Error(err) + } + }() + ctx := apm.ContextWithTransaction(context.Background(), tx) + + txs, err := notifier.GetTransactionsFromDelivery(delivery, ctx) + if err != nil { + logger.Error("failed to get transactions", err) + if err := delivery.Ack(false); err != nil { + logger.Error(err) + } + return + } + if len(txs) == 0 { + return + } + + assets := GetAssetsFromTransactions(txs) + err = database.AddNewAssets(assets, ctx) + if err != nil { + logger.Error("failed to add assets", err) + return + } +} + +func GetAssetsFromTransactions(txs []blockatlas.Tx) []models.Asset { + var result []models.Asset + for _, tx := range txs { + a, ok := tx.AssetModel() + if !ok { + continue + } + if a.Asset == "" { + continue + } + result = append(result, a) + } + return result +} diff --git a/services/tokenindexer/models.go b/services/tokenindexer/models.go new file mode 100644 index 000000000..c6aeb28dd --- /dev/null +++ b/services/tokenindexer/models.go @@ -0,0 +1,18 @@ +package tokenindexer + +type Request struct { + From int64 +} + +type Response struct { + Assets []Asset `json:"assets"` +} + +type Asset struct { + Asset string `json:"asset"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Type string `json:"type"` + + Decimals uint `json:"decimals"` +} diff --git a/services/tokensearcher/api.go b/services/tokensearcher/api.go index 5d60fc2ed..fe567aa50 100644 --- a/services/tokensearcher/api.go +++ b/services/tokensearcher/api.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -15,7 +16,7 @@ import ( type ( AddressesByCoin map[uint][]string - AssetsByAddress map[string][]string + AssetsByAddress map[string][]models.Asset Request struct { AddressesByCoin map[string][]string `json:"addresses"` From uint `json:"from"` @@ -32,7 +33,7 @@ func Init(database *db.Instance, apis map[uint]blockatlas.TokensAPI, queue mq.Qu return Instance{database: database, apis: apis, queue: queue} } -func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (AssetsByAddress, error) { +func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (map[string][]string, error) { addresses := getAddressesFromRequest(request) if len(addresses) == 0 { return nil, nil @@ -183,10 +184,10 @@ func getAssetsToResponse(dbAssetsMap, nodesAssetsMap AssetsByAddress, addresses if !ok { continue } - result[address] = nodesAssets + result[address] = models.AssetIDs(nodesAssets) continue } - result[address] = dbAddresses + result[address] = models.AssetIDs(dbAddresses) } return result } diff --git a/services/tokensearcher/api_test.go b/services/tokensearcher/api_test.go index 3aa7212bd..ec80ac330 100644 --- a/services/tokensearcher/api_test.go +++ b/services/tokensearcher/api_test.go @@ -3,6 +3,7 @@ package tokensearcher import ( "errors" "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "testing" @@ -25,9 +26,9 @@ func Test_getUnsubscribedAddresses(t *testing.T) { } func Test_getAddressesToRegisterByCoin(t *testing.T) { - addressFromDB := make(map[string][]string) - addressFromDB["60_a"] = []string{"1", "2", "3"} - addressFromDB["714_b"] = []string{"1", "3"} + addressFromDB := make(map[string][]models.Asset) + addressFromDB["60_a"] = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} + addressFromDB["714_b"] = []models.Asset{{Asset: "1"}, {Asset: "3"}} addressesFromRequest := []string{"60_a", "714_b", "118_c"} result := getAddressesToRegisterByCoin(addressFromDB, addressesFromRequest) @@ -38,12 +39,12 @@ func Test_getAddressesToRegisterByCoin(t *testing.T) { } func Test_getAssetsToResponse(t *testing.T) { - addressFromDB := make(map[string][]string) - addressFromDB["60_a"] = []string{"1", "2", "3"} - addressFromDB["714_b"] = []string{"1", "3"} + addressFromDB := make(map[string][]models.Asset) + addressFromDB["60_a"] = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} + addressFromDB["714_b"] = []models.Asset{{Asset: "1"}, {Asset: "3"}} - addressFromNodes := make(map[string][]string) - addressFromNodes["118_c"] = []string{"1", "2", "3"} + addressFromNodes := make(map[string][]models.Asset) + addressFromNodes["118_c"] = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} addressesFromRequest := []string{"60_a", "714_b", "118_c"} diff --git a/services/tokensearcher/association.go b/services/tokensearcher/association.go index 220270980..de61ed3d8 100644 --- a/services/tokensearcher/association.go +++ b/services/tokensearcher/association.go @@ -3,30 +3,28 @@ package tokensearcher import ( "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/watchmarket/pkg/watchmarket" "strings" ) -func assetsMap(txs blockatlas.Txs, coinID string) map[string][]string { - result := make(map[string][]string) +func assetsMap(txs blockatlas.Txs, coinID string) map[string][]models.Asset { + result := make(map[string][]models.Asset) prefix := coinID + "_" for _, tx := range txs { addresses := tx.GetAddresses() - tokenID, ok := tx.TokenID() + asset, ok := tx.AssetModel() if !ok { continue } - assetID := watchmarket.BuildID(tx.Coin, tokenID) for _, a := range addresses { assetIDs := result[prefix+a] - result[prefix+a] = append(assetIDs, assetID) + result[prefix+a] = append(assetIDs, asset) } } return result } -func associationsToAdd(oldAssociations map[string][]string, newAssociations map[string][]string) map[string][]string { - result := make(map[string][]string) +func associationsToAdd(oldAssociations map[string][]models.Asset, newAssociations map[string][]models.Asset) map[string][]models.Asset { + result := make(map[string][]models.Asset) for oldAddresses, oldAssets := range oldAssociations { for newAddresses, newAssets := range newAssociations { if strings.EqualFold(oldAddresses, newAddresses) { @@ -38,25 +36,25 @@ func associationsToAdd(oldAssociations map[string][]string, newAssociations map[ return result } -func newAssociationsForAddress(oldAssociations []string, newAssociations []string) []string { - var result []string +func newAssociationsForAddress(oldAssociations []models.Asset, newAssociations []models.Asset) []models.Asset { + var result []models.Asset oldM := make(map[string]bool) for _, o := range oldAssociations { - oldM[o] = true + oldM[o.Asset] = true } for _, n := range newAssociations { - if ok := oldM[n]; !ok { + if ok := oldM[n.Asset]; !ok { result = append(result, n) } } return result } -func fromModelToAssociation(associations []models.AddressToAssetAssociation) map[string][]string { - result := make(map[string][]string) +func fromModelToAssociation(associations []models.AddressToAssetAssociation) map[string][]models.Asset { + result := make(map[string][]models.Asset) for _, a := range associations { m := result[a.Address.Address] - result[a.Address.Address] = append(m, a.Asset.Asset) + result[a.Address.Address] = append(m, a.Asset) } return result } diff --git a/services/tokensearcher/association_test.go b/services/tokensearcher/association_test.go index 2013d545a..7d79f6cae 100644 --- a/services/tokensearcher/association_test.go +++ b/services/tokensearcher/association_test.go @@ -40,45 +40,45 @@ func Test_assetsMap(t *testing.T) { } result := assetsMap(blockatlas.Txs{tx1, tx2, tx3}, "60") - assert.Equal(t, result["60_A"], []string{"c60_tABC"}) - assert.Equal(t, result["60_C"], []string{"c60_tABC"}) - assert.Equal(t, result["60_D"], []string{"c60_tEFG"}) - assert.Equal(t, result["60_F"], []string{"c60_tEFG"}) - assert.Equal(t, result["60_Q"], []string{"c60_tHIJ"}) - assert.Equal(t, result["60_L"], []string{"c60_tHIJ"}) + assert.Equal(t, result["60_A"], []models.Asset{{Asset: "c60_tABC", Type: "ERC20"}}) + assert.Equal(t, result["60_C"], []models.Asset{{Asset: "c60_tABC", Type: "ERC20"}}) + assert.Equal(t, result["60_D"], []models.Asset{{Asset: "c60_tEFG", Type: "ERC20"}}) + assert.Equal(t, result["60_F"], []models.Asset{{Asset: "c60_tEFG", Type: "ERC20"}}) + assert.Equal(t, result["60_Q"], []models.Asset{{Asset: "c60_tHIJ", Type: "ERC20"}}) + assert.Equal(t, result["60_L"], []models.Asset{{Asset: "c60_tHIJ", Type: "ERC20"}}) } func Test_associationsToAdd(t *testing.T) { - o := make(map[string][]string) - n := make(map[string][]string) + o := make(map[string][]models.Asset) + n := make(map[string][]models.Asset) - o["A"] = []string{"1", "2", "3"} - o["B"] = []string{"3", "4", "5"} + o["A"] = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} + o["B"] = []models.Asset{{Asset: "3"}, {Asset: "4"}, {Asset: "5"}} - n["A"] = []string{"1", "2", "5"} - n["B"] = []string{"3", "9", "8"} + n["A"] = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "5"}} + n["B"] = []models.Asset{{Asset: "3"}, {Asset: "9"}, {Asset: "8"}} result := associationsToAdd(o, n) - assert.Equal(t, result["A"], []string{"5"}) - assert.Equal(t, result["B"], []string{"9", "8"}) + assert.Equal(t, result["A"], []models.Asset{{Asset: "5"}}) + assert.Equal(t, result["B"], []models.Asset{{Asset: "9"}, {Asset: "8"}}) } func Test_newAssociationsForAddress(t *testing.T) { - o := []string{"1", "2", "3"} - n := []string{"1", "2", "3", "4", "5"} + o := []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} + n := []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}, {Asset: "4"}, {Asset: "5"}} result := newAssociationsForAddress(o, n) - assert.Equal(t, result, []string{"4", "5"}) + assert.Equal(t, result, []models.Asset{{Asset: "4"}, {Asset: "5"}}) - o = []string{"1", "2", "3"} - n = []string{"1", "2", "3"} + o = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} + n = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} result = newAssociationsForAddress(o, n) assert.Equal(t, len(result), len([]string{})) - o = []string{"1", "2", "3"} - n = []string{"1", "2"} + o = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} + n = []models.Asset{{Asset: "1"}, {Asset: "2"}} result = newAssociationsForAddress(o, n) assert.Equal(t, len(result), len([]string{})) @@ -95,6 +95,6 @@ func Test_fromModelToAssociation(t *testing.T) { } result := fromModelToAssociation(a) - assert.Equal(t, result["A"], []string{"1", "2", "3"}) - assert.Equal(t, result["B"], []string{"2", "3", "4"}) + assert.Equal(t, result["A"], []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}}) + assert.Equal(t, result["B"], []models.Asset{{Asset: "2"}, {Asset: "3"}, {Asset: "4"}}) } diff --git a/services/tokensearcher/models.go b/services/tokensearcher/models.go index 0897e3b7e..1f88485dc 100644 --- a/services/tokensearcher/models.go +++ b/services/tokensearcher/models.go @@ -1,6 +1,7 @@ package tokensearcher import ( + "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/watchmarket/pkg/watchmarket" @@ -17,7 +18,15 @@ func (nr *NodesResponse) UpdateAssetsByAddress(tokens blockatlas.TokenPage, coin for _, t := range tokens { key := address.PrefixedAddress(uint(coin), a) r := nr.AssetsByAddress[key] - nr.AssetsByAddress[key] = append(r, watchmarket.BuildID(t.Coin, t.TokenID)) + nr.AssetsByAddress[key] = append(r, + models.Asset{ + Asset: watchmarket.BuildID(t.Coin, t.TokenID), + Decimals: t.Decimals, + Name: t.Name, + Symbol: t.Symbol, + Type: string(t.Type), + }, + ) } nr.Unlock() } diff --git a/tests/integration/db_test/tokenassociations_test.go b/tests/integration/db_test/tokenassociations_test.go index 2547a92f3..8b297b748 100644 --- a/tests/integration/db_test/tokenassociations_test.go +++ b/tests/integration/db_test/tokenassociations_test.go @@ -5,6 +5,7 @@ package db_test import ( "context" "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/tests/integration/setup" "sort" "testing" @@ -14,7 +15,7 @@ import ( func Test_GetAssetsMapByAddresses(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - assets := []string{"aa", "bbb", "cccc"} + assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} err := database.AddAssociationsForAddress("a", assets, context.Background()) assert.Nil(t, err) @@ -24,15 +25,20 @@ func Test_GetAssetsMapByAddresses(t *testing.T) { m, err := database.GetAssetsMapByAddresses([]string{"a", "b"}, context.Background()) assert.Nil(t, err) - wantedMap := make(map[string][]string) + wantedMap := make(map[string][]models.Asset) wantedMap["a"] = assets - assert.Equal(t, wantedMap, m) + for i, a := range m { + for ii, aa := range a { + assert.Equal(t, wantedMap[i][ii].Asset, aa.Asset) + } + } + } func Test_GetAssetsMapByAddressesFromTime(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - assets := []string{"aa", "bbb", "cccc"} + assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} err := database.AddAssociationsForAddress("a", assets, context.Background()) assert.Nil(t, err) @@ -42,9 +48,14 @@ func Test_GetAssetsMapByAddressesFromTime(t *testing.T) { tm := time.Now().Unix() - 100 m, err := database.GetAssetsMapByAddressesFromTime([]string{"a", "b"}, time.Unix(tm, 0), context.Background()) assert.Nil(t, err) - wantedMap := make(map[string][]string) + wantedMap := make(map[string][]models.Asset) wantedMap["a"] = assets - assert.Equal(t, wantedMap, m) + + for i, a := range m { + for ii, aa := range a { + assert.Equal(t, wantedMap[i][ii].Asset, aa.Asset) + } + } m, err = database.GetAssetsMapByAddressesFromTime([]string{"a", "b"}, time.Unix(tm+101, 0), context.Background()) assert.Nil(t, err) @@ -54,7 +65,7 @@ func Test_GetAssetsMapByAddressesFromTime(t *testing.T) { func Test_GetSubscribedAddressesForAssets(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - assets := []string{"aa", "bbb", "cccc"} + assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} err := database.AddAssociationsForAddress("a", assets, context.Background()) assert.Nil(t, err) @@ -69,7 +80,7 @@ func Test_GetSubscribedAddressesForAssets(t *testing.T) { func Test_AddNewAssociationForAddress(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - assets := []string{"aa", "bbb", "cccc"} + assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} err := database.AddAssociationsForAddress("a", assets, context.Background()) assert.Nil(t, err) @@ -77,20 +88,22 @@ func Test_AddNewAssociationForAddress(t *testing.T) { associations, err := database.GetAssociationsByAddresses([]string{"a"}, context.Background()) assert.Nil(t, err) - var assetIDsFromDB []string + var assetIDsFromDB []models.Asset for _, a := range associations { - assetIDsFromDB = append(assetIDsFromDB, a.Asset.Asset) + assetIDsFromDB = append(assetIDsFromDB, a.Asset) } sort.Slice(assets, func(i, j int) bool { - return len(assets[i]) > len(assets[j]) + return len(assets[i].Asset) > len(assets[j].Asset) }) sort.Slice(assetIDsFromDB, func(i, j int) bool { - return len(assetIDsFromDB[i]) > len(assetIDsFromDB[j]) + return len(assetIDsFromDB[i].Asset) > len(assetIDsFromDB[j].Asset) }) - assert.Equal(t, assetIDsFromDB, assets) + for i, a := range assets { + assert.Equal(t, assetIDsFromDB[i].Asset, a.Asset) + } err = database.AddAssociationsForAddress("b", nil, context.Background()) assert.Nil(t, err) @@ -102,7 +115,7 @@ func Test_AddNewAssociationForAddress(t *testing.T) { func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - assets := []string{"f"} + assets := []models.Asset{{Asset: "f"}} err := database.AddAssociationsForAddress("A", assets, context.Background()) assert.Nil(t, err) @@ -110,10 +123,10 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { err = database.AddAssociationsForAddress("B", assets, context.Background()) assert.Nil(t, err) - assetsForA := []string{"aa", "bbb", "cccc"} - assetsForB := []string{"bbb", "cccc"} + assetsForA := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} + assetsForB := []models.Asset{{Asset: "bbb"}, {Asset: "cccc"}} - updateMap := make(map[string][]string) + updateMap := make(map[string][]models.Asset) updateMap["A"] = assetsForA updateMap["B"] = assetsForB @@ -123,57 +136,63 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { associationsA, err := database.GetAssociationsByAddresses([]string{"A"}, context.Background()) assert.Nil(t, err) - var assetIDsFromDBA []string + var assetIDsFromDBA []models.Asset for _, a := range associationsA { - assetIDsFromDBA = append(assetIDsFromDBA, a.Asset.Asset) + assetIDsFromDBA = append(assetIDsFromDBA, a.Asset) } - assetsA := []string{"aa", "bbb", "cccc", "f"} + assetsA := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}, {Asset: "f"}} sort.Slice(assetsA, func(i, j int) bool { - return len(assetsA[i]) > len(assetsA[j]) + return len(assetsA[i].Asset) > len(assetsA[j].Asset) }) sort.Slice(assetIDsFromDBA, func(i, j int) bool { - return len(assetIDsFromDBA[i]) > len(assetIDsFromDBA[j]) + return len(assetIDsFromDBA[i].Asset) > len(assetIDsFromDBA[j].Asset) }) - assert.Equal(t, assetIDsFromDBA, assetsA) + for i, a := range assetsA { + assert.Equal(t, assetIDsFromDBA[i].Asset, a.Asset) + } associationsB, err := database.GetAssociationsByAddresses([]string{"B"}, context.Background()) assert.Nil(t, err) - var assetIDsFromDBB []string + var assetIDsFromDBB []models.Asset for _, a := range associationsB { - assetIDsFromDBB = append(assetIDsFromDBB, a.Asset.Asset) + assetIDsFromDBB = append(assetIDsFromDBB, a.Asset) } - assetsB := []string{"bbb", "cccc", "f"} + assetsB := []models.Asset{{Asset: "bbb"}, {Asset: "cccc"}, {Asset: "f"}} sort.Slice(assetsB, func(i, j int) bool { - return len(assetsB[i]) > len(assetsB[j]) + return len(assetsB[i].Asset) > len(assetsB[j].Asset) }) sort.Slice(assetIDsFromDBB, func(i, j int) bool { - return len(assetIDsFromDBB[i]) > len(assetIDsFromDBB[j]) + return len(assetIDsFromDBB[i].Asset) > len(assetIDsFromDBB[j].Asset) }) - assert.Equal(t, assetIDsFromDBB, assetsB) + for i, a := range assetsB { + assert.Equal(t, assetIDsFromDBB[i].Asset, a.Asset) + } associationsAB, err := database.GetAssociationsByAddresses([]string{"A", "B"}, context.Background()) assert.Nil(t, err) - var assetIDsFromDBAB []string + var assetIDsFromDBAB []models.Asset for _, a := range associationsAB { - assetIDsFromDBAB = append(assetIDsFromDBAB, a.Asset.Asset) + assetIDsFromDBAB = append(assetIDsFromDBAB, a.Asset) } - assetsAB := []string{"cccc", "cccc", "bbb", "bbb", "aa", "f", "f"} + assetsAB := []models.Asset{{Asset: "cccc"}, {Asset: "cccc"}, {Asset: "bbb"}, {Asset: "bbb"}, {Asset: "aa"}, {Asset: "f"}, {Asset: "f"}} sort.Slice(assetsAB, func(i, j int) bool { - return len(assetsAB[i]) > len(assetsAB[j]) + return len(assetsAB[i].Asset) > len(assetsAB[j].Asset) }) sort.Slice(assetIDsFromDBAB, func(i, j int) bool { - return len(assetIDsFromDBAB[i]) > len(assetIDsFromDBAB[j]) + return len(assetIDsFromDBAB[i].Asset) > len(assetIDsFromDBAB[j].Asset) }) - assert.Equal(t, assetIDsFromDBAB, assetsAB) + for i, a := range assetsAB { + assert.Equal(t, assetIDsFromDBAB[i].Asset, a.Asset) + } } diff --git a/tests/integration/db_test/tokenindexer_test.go b/tests/integration/db_test/tokenindexer_test.go new file mode 100644 index 000000000..fc053b73a --- /dev/null +++ b/tests/integration/db_test/tokenindexer_test.go @@ -0,0 +1,133 @@ +// +build integration + +package db_test + +import ( + "context" + assert "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/db/models" + "sort" + "testing" +) + +func Test_AddNewAssets(t *testing.T) { + type testsStruct struct { + Name string + Assets []models.Asset + AssetsIDs []string + WantedErr error + WantedAssets []models.Asset + } + tests := []testsStruct{ + { + Name: "Normal case", + Assets: []models.Asset{ + { + Asset: "c714_a", + Decimals: 18, + Name: "A", + Symbol: "ABC", + Type: "BEP20", + }, + { + Asset: "c714_b", + Decimals: 18, + Name: "B", + Symbol: "BCD", + Type: "BEP20", + }, + }, + AssetsIDs: []string{"c714_a", "c714_b"}, + WantedErr: nil, + WantedAssets: []models.Asset{ + { + Asset: "c714_a", + Decimals: 18, + Name: "A", + Symbol: "ABC", + Type: "BEP20", + }, + { + Asset: "c714_b", + Decimals: 18, + Name: "B", + Symbol: "BCD", + Type: "BEP20", + }, + }, + }, + { + Name: "Case with new tokens and old tokens", + Assets: []models.Asset{ + { + Asset: "c714_c", + Decimals: 18, + Name: "C", + Symbol: "FFF", + Type: "ERC20", + }, + { + Asset: "c714_d", + Decimals: 18, + Name: "D", + Symbol: "RRR", + Type: "TRC20", + }, + }, + AssetsIDs: []string{"c714_a", "c714_b", "c714_c", "c714_d"}, + WantedErr: nil, + WantedAssets: []models.Asset{ + { + Asset: "c714_a", + Decimals: 18, + Name: "A", + Symbol: "ABC", + Type: "BEP20", + }, + { + Asset: "c714_b", + Decimals: 18, + Name: "B", + Symbol: "BCD", + Type: "BEP20", + }, + { + Asset: "c714_c", + Decimals: 18, + Name: "C", + Symbol: "FFF", + Type: "ERC20", + }, + { + Asset: "c714_d", + Decimals: 18, + Name: "D", + Symbol: "RRR", + Type: "TRC20", + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.Name, func(t *testing.T) { + err := database.AddNewAssets(tt.Assets, context.Background()) + assert.Equal(t, tt.WantedErr, err) + assets, err := database.GetAssetsByIDs(tt.AssetsIDs, context.Background()) + assert.Nil(t, err) + sort.Slice(tt.WantedAssets, func(i, j int) bool { + return tt.WantedAssets[i].Asset > tt.WantedAssets[j].Asset + }) + sort.Slice(assets, func(i, j int) bool { + return assets[i].Asset > assets[j].Asset + }) + for i, a := range assets { + assert.Equal(t, tt.WantedAssets[i].Asset, a.Asset) + assert.Equal(t, tt.WantedAssets[i].Name, a.Name) + assert.Equal(t, tt.WantedAssets[i].Symbol, a.Symbol) + assert.Equal(t, tt.WantedAssets[i].Type, a.Type) + assert.Equal(t, tt.WantedAssets[i].Decimals, a.Decimals) + } + }) + } +} From 9e9f9ac3b80c66a37a249745fa82033e7d0d2266 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Sat, 24 Oct 2020 00:57:59 +0300 Subject: [PATCH 393/506] [IOTEX] Fix tx normalization for block api (#1252) --- platform/iotex/transaction.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/iotex/transaction.go b/platform/iotex/transaction.go index d79ad52c1..9b2ad9c3d 100644 --- a/platform/iotex/transaction.go +++ b/platform/iotex/transaction.go @@ -63,7 +63,9 @@ func Normalize(trx *ActionInfo) *blockatlas.Tx { if err != nil { return nil } - + if trx.GasFee == "" { + trx.GasFee = "0" + } return &blockatlas.Tx{ ID: trx.ActHash, Coin: coin.IOTX, From 639f9b385b9e286fbbad6737b70f756020578ae5 Mon Sep 17 00:00:00 2001 From: maxUo <20925019+maxUo@users.noreply.github.com> Date: Sat, 24 Oct 2020 01:20:09 +0300 Subject: [PATCH 394/506] Update master.yml (#1254) --- .github/workflows/master.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index cb473fa03..d96def741 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -106,7 +106,7 @@ jobs: run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin - name: Docker Build & Push Release Images - if: steps.check.outputs.has-permission + if: steps.check_for_deploy.outputs.has-permission env: API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} From f8a7bb5c9b001e0e7c99aa017ae14d472f4052ec Mon Sep 17 00:00:00 2001 From: maxUo <20925019+maxUo@users.noreply.github.com> Date: Sat, 24 Oct 2020 01:24:51 +0300 Subject: [PATCH 395/506] Update master.yml --- .github/workflows/master.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index d96def741..eb61c5f55 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -106,7 +106,7 @@ jobs: run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin - name: Docker Build & Push Release Images - if: steps.check_for_deploy.outputs.has-permission + if: steps.check_for_build.outputs.has-permission env: API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} From 3b76b7abe017bbd22e82f6854f5f9b8020698148 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sat, 24 Oct 2020 13:05:54 -0700 Subject: [PATCH 396/506] Enable numeric values in the memo (#1255) * Enable numeric values in the memo * Update full_flow_test.go * Rename to AllowMemo * Update tx_test.go --- pkg/blockatlas/tx.go | 11 ++- pkg/blockatlas/tx_test.go | 85 +++++++++++++++++-- .../observer_test/full_flow_test.go | 4 +- 3 files changed, 87 insertions(+), 13 deletions(-) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index ea3fb2625..ecfb56643 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -231,13 +231,20 @@ func (t Txs) FilterUniqueID() Txs { func (txs TxPage) FilterTransactionsByMemo() TxPage { result := make(TxPage, 0) for _, tx := range txs { - //TODO. Temporary disable memo - tx.Memo = "" + if !AllowMemo(tx.Memo) { + tx.Memo = "" + } result = append(result, tx) } return result } +func AllowMemo(memo string) bool { + // only allows numeric values + _, err := strconv.ParseFloat(memo, 64) + return err == nil +} + func (txs TxPage) FilterTransactionsByToken(token string) TxPage { result := make(TxPage, 0) for _, tx := range txs { diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 0e5ba3ff3..842542adc 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -5,6 +5,7 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" "github.com/trustwallet/golibs/coin" + "reflect" "sort" "testing" ) @@ -684,12 +685,78 @@ func Test_filterTransactionsByToken(t *testing.T) { assert.Equal(t, wantedTransactionsToken, string(rawResult)) } -//func Test_filterTransactionsByMemo(t *testing.T) { -// var p TxPage -// spamfilter.SpamList = []string{"word", "free"} -// assert.Nil(t, json.Unmarshal([]byte(beforeTransactionsMemo), &p)) -// result := p.FilterTransactionsByMemo() -// rawResult, err := json.Marshal(result) -// assert.Nil(t, err) -// assert.Equal(t, wantedTransactionsMemo, string(rawResult)) -//} +func Test_AllowMemo(t *testing.T) { + type args struct { + memo string + } + tests := []struct { + name string + args args + want bool + }{ + { + "Numeric memo", + args{memo: "123"}, + true, + }, + { + "Numeric memo", + args{memo: "12356172321321"}, + true, + }, + { + "Numeric memo", + args{memo: "test"}, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := AllowMemo(tt.args.memo); got != tt.want { + t.Errorf("isMemoAllowed() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestTxPage_FilterTransactionsByMemo(t *testing.T) { + tests := []struct { + name string + txs TxPage + want TxPage + }{ + { + name: "Allow memo", + txs: TxPage{ + { + Memo: "123", + }, + }, + want: TxPage{ + { + Memo: "123", + }, + }, + }, + { + name: "Disallow memo", + txs: TxPage{ + { + Memo: "test", + }, + }, + want: TxPage{ + { + Memo: "", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.txs.FilterTransactionsByMemo(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("FilterTransactionsByMemo() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 65bb41e50..b9c9c0e98 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -83,7 +83,7 @@ func (p *PlatformFullFlow) GetBlockByNumber(num int64) (*blockatlas.Block, error Date: 1555117625, Block: 7928667, Status: blockatlas.StatusCompleted, - Memo: "test", + Memo: "123", Meta: blockatlas.NativeTokenTransfer{ TokenID: "YLC-D8B", Symbol: "YLC", @@ -131,7 +131,7 @@ func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel Date: 1555117625, Block: 7928667, Status: blockatlas.StatusCompleted, - Memo: "", + Memo: "123", Meta: &memo, }, }, notifications[0]) From 4876978074fb86fc9b678dfba12434e0c300da01 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Wed, 28 Oct 2020 01:16:02 +0300 Subject: [PATCH 397/506] [Indexer] Add memoryCache to instance (#1256) * Add memoryCache to instance * Implement memory caching for assets * Setup assets caching * Add filters and tests * Fixes and cleanup * Fix integration test with meme cache --- db/asset.go | 50 +++++++++-- db/db.go | 34 ++++++-- services/notifier/delivery.go | 5 -- .../integration/db_test/tokenindexer_test.go | 86 +++++++++++++++---- 4 files changed, 139 insertions(+), 36 deletions(-) diff --git a/db/asset.go b/db/asset.go index 1fa4984c9..db14c7e08 100644 --- a/db/asset.go +++ b/db/asset.go @@ -2,11 +2,15 @@ package db import ( "context" - "gorm.io/gorm" - "gorm.io/gorm/clause" + "encoding/json" "time" "unicode/utf8" + "gorm.io/gorm" + "gorm.io/gorm/clause" + + gocache "github.com/patrickmn/go-cache" + "github.com/trustwallet/blockatlas/db/models" ) @@ -17,15 +21,28 @@ func (i *Instance) AddNewAssets(assets []models.Asset, ctx context.Context) erro } uniqueAssets := getUniqueAssets(assets) uniqueAssets = filterAssets(uniqueAssets) - existingAssets, err := i.GetAssetsByIDs(models.AssetIDs(uniqueAssets), ctx) + + var notInMemoryAssets []models.Asset + for _, a := range uniqueAssets { + _, err := i.MemoryGet(a.Asset, ctx) + if err != nil { + notInMemoryAssets = append(notInMemoryAssets, a) + } + } + if len(notInMemoryAssets) == 0 { + return nil + } + + existingAssets, err := i.GetAssetsByIDs(models.AssetIDs(notInMemoryAssets), ctx) if err != nil { return err } if len(existingAssets) == 0 { - return db.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssets).Error + i.addToMemory(notInMemoryAssets, ctx) + return db.Clauses(clause.OnConflict{DoNothing: true}).Create(¬InMemoryAssets).Error } allAssetsMap := make(map[string]models.Asset) - for _, ua := range uniqueAssets { + for _, ua := range notInMemoryAssets { allAssetsMap[ua.Asset] = ua } existingAssetsMap := make(map[string]models.Asset) @@ -42,6 +59,7 @@ func (i *Instance) AddNewAssets(assets []models.Asset, ctx context.Context) erro if len(newAssets) == 0 { return nil } + i.addToMemory(newAssets, ctx) assetsBatch := assetsBatch(newAssets, batchCount) @@ -56,12 +74,26 @@ func (i *Instance) AddNewAssets(assets []models.Asset, ctx context.Context) erro }) } +func (i *Instance) addToMemory(newAssets []models.Asset, ctx context.Context) { + for _, a := range newAssets { + raw, err := json.Marshal(a) + if err != nil { + continue + } + err = i.MemorySet(a.Asset, raw, gocache.NoExpiration, ctx) + if err != nil { + continue + } + } +} + func (i *Instance) GetAssetsByIDs(ids []string, ctx context.Context) ([]models.Asset, error) { db := i.Gorm.WithContext(ctx) // todo: look why nil and len 0 make db calls rn if len(ids) == 0 { return nil, nil } + var dbAssets []models.Asset if err := db.Where("asset in (?)", ids).Find(&dbAssets).Error; err != nil { return nil, err @@ -96,10 +128,14 @@ func assetsBatch(values []models.Asset, sizeUint uint) [][]models.Asset { func filterAssets(values []models.Asset) []models.Asset { result := make([]models.Asset, 0, len(values)) for _, v := range values { - if utf8.ValidString(v.Asset) && + valuesAreAtUTF8 := utf8.ValidString(v.Asset) && utf8.ValidString(v.Type) && utf8.ValidString(v.Symbol) && - utf8.ValidString(v.Name) { + utf8.ValidString(v.Name) + valuesAreNotEmpty := v.Asset != "" && + v.Type != "" && v.Symbol != "" && + v.Name != "" && v.Decimals != 0 + if valuesAreAtUTF8 && valuesAreNotEmpty { result = append(result, v) } } diff --git a/db/db.go b/db/db.go index df27d65fe..578113afa 100644 --- a/db/db.go +++ b/db/db.go @@ -2,19 +2,26 @@ package db import ( "context" + "errors" + "log" + "os" + "time" + "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/logger" + + gocache "github.com/patrickmn/go-cache" + + gormlogger "gorm.io/gorm/logger" + "gorm.io/driver/postgres" "gorm.io/gorm" - gormlogger "gorm.io/gorm/logger" "gorm.io/plugin/dbresolver" - "log" - "os" - "time" ) type Instance struct { - Gorm *gorm.DB + Gorm *gorm.DB + MemoryCache *gocache.Cache } // By gorm-bulk-insert author: @@ -58,8 +65,8 @@ func New(uri, readUri string, logMode bool) (*Instance, error) { if err != nil { return nil, err } - - i := &Instance{Gorm: db} + mc := gocache.New(gocache.NoExpiration, gocache.NoExpiration) + i := &Instance{Gorm: db, MemoryCache: mc} return i, nil } @@ -100,3 +107,16 @@ func (i *Instance) restoreConnection(uri string) error { } return nil } + +func (i *Instance) MemorySet(key string, data []byte, exp time.Duration, ctx context.Context) error { + i.MemoryCache.Set(key, data, exp) + return nil +} + +func (i *Instance) MemoryGet(key string, ctx context.Context) ([]byte, error) { + res, ok := i.MemoryCache.Get(key) + if !ok { + return nil, errors.New("not found") + } + return res.([]byte), nil +} diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index 6306228bc..cc5c5c189 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -17,14 +17,9 @@ func GetTransactionsFromDelivery(delivery amqp.Delivery, ctx context.Context) (b span, _ := apm.StartSpan(ctx, "GetTransactionsFromDelivery", "app") defer span.End() - logger.Info("--------------------------------------------") - logger.Info("Unmarshal: ") - logger.Info(delivery.Body) if err := json.Unmarshal(delivery.Body, &txs); err != nil { return nil, err } - logger.Info("Done") - logger.Info("--------------------------------------------") logger.Info("Consumed", logger.Params{"txs": len(txs), "coin": txs[0].Coin}) diff --git a/tests/integration/db_test/tokenindexer_test.go b/tests/integration/db_test/tokenindexer_test.go index fc053b73a..7a83724c2 100644 --- a/tests/integration/db_test/tokenindexer_test.go +++ b/tests/integration/db_test/tokenindexer_test.go @@ -4,13 +4,62 @@ package db_test import ( "context" + gocache "github.com/patrickmn/go-cache" assert "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/pkg/logger" + "github.com/trustwallet/blockatlas/tests/integration/setup" "sort" "testing" ) +func Test_AddNewAssets_Simple(t *testing.T) { + a := []models.Asset{ + { + Asset: "c714_a", + Decimals: 18, + Name: "A", + Symbol: "ABC", + Type: "BEP20", + }, + { + Asset: "c714_b", + Decimals: 18, + Name: "B", + Symbol: "BCD", + Type: "BEP20", + }, + } + err := database.AddNewAssets(a, context.Background()) + assert.Nil(t, err) + assets, err := database.GetAssetsByIDs([]string{"c714_b", "c714_a"}, context.Background()) + assert.Nil(t, err) + assert.NotNil(t, assets) + a = append(a, models.Asset{ + Asset: "c714_d", + Decimals: 18, + Name: "D", + Symbol: "DTS", + Type: "BEP20", + }) + err = database.AddNewAssets(a, context.Background()) + assert.Nil(t, err) + err = database.AddNewAssets([]models.Asset{{ + Asset: "c714_p", + Decimals: 0, + Name: "D", + Symbol: "DTS", + Type: "BEP20", + }}, context.Background()) + assert.Nil(t, err) + assets, err = database.GetAssetsByIDs([]string{"c714_p"}, context.Background()) + assert.Nil(t, err) + assert.Equal(t, 0, len(assets)) +} + func Test_AddNewAssets(t *testing.T) { + setup.CleanupPgContainer(database.Gorm) + database.MemoryCache = gocache.New(gocache.NoExpiration, gocache.NoExpiration) type testsStruct struct { Name string Assets []models.Asset @@ -24,15 +73,15 @@ func Test_AddNewAssets(t *testing.T) { Assets: []models.Asset{ { Asset: "c714_a", - Decimals: 18, + Decimals: 15, Name: "A", Symbol: "ABC", Type: "BEP20", }, { Asset: "c714_b", - Decimals: 18, - Name: "B", + Decimals: 16, + Name: "BB", Symbol: "BCD", Type: "BEP20", }, @@ -42,15 +91,15 @@ func Test_AddNewAssets(t *testing.T) { WantedAssets: []models.Asset{ { Asset: "c714_a", - Decimals: 18, + Decimals: 15, Name: "A", Symbol: "ABC", Type: "BEP20", }, { Asset: "c714_b", - Decimals: 18, - Name: "B", + Decimals: 16, + Name: "BB", Symbol: "BCD", Type: "BEP20", }, @@ -61,15 +110,15 @@ func Test_AddNewAssets(t *testing.T) { Assets: []models.Asset{ { Asset: "c714_c", - Decimals: 18, - Name: "C", + Decimals: 17, + Name: "CCC", Symbol: "FFF", Type: "ERC20", }, { Asset: "c714_d", Decimals: 18, - Name: "D", + Name: "DDDD", Symbol: "RRR", Type: "TRC20", }, @@ -79,29 +128,29 @@ func Test_AddNewAssets(t *testing.T) { WantedAssets: []models.Asset{ { Asset: "c714_a", - Decimals: 18, + Decimals: 15, Name: "A", Symbol: "ABC", Type: "BEP20", }, { Asset: "c714_b", - Decimals: 18, - Name: "B", + Decimals: 16, + Name: "BB", Symbol: "BCD", Type: "BEP20", }, { Asset: "c714_c", - Decimals: 18, - Name: "C", + Decimals: 17, + Name: "CCC", Symbol: "FFF", Type: "ERC20", }, { Asset: "c714_d", Decimals: 18, - Name: "D", + Name: "DDDD", Symbol: "RRR", Type: "TRC20", }, @@ -116,11 +165,14 @@ func Test_AddNewAssets(t *testing.T) { assets, err := database.GetAssetsByIDs(tt.AssetsIDs, context.Background()) assert.Nil(t, err) sort.Slice(tt.WantedAssets, func(i, j int) bool { - return tt.WantedAssets[i].Asset > tt.WantedAssets[j].Asset + return len(tt.WantedAssets[i].Name) > len(tt.WantedAssets[j].Name) }) sort.Slice(assets, func(i, j int) bool { - return assets[i].Asset > assets[j].Asset + return len(assets[i].Name) > len(assets[j].Name) }) + logger.Info(tt.WantedAssets) + logger.Info("----------------------") + logger.Info(assets) for i, a := range assets { assert.Equal(t, tt.WantedAssets[i].Asset, a.Asset) assert.Equal(t, tt.WantedAssets[i].Name, a.Name) From 1a1afb3656ed5910fe0eb2d29e7b11de81d52d6b Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 27 Oct 2020 16:17:13 -0700 Subject: [PATCH 398/506] [Zilliqa] Fix block number and timestamp in block parsing (#1257) * Rename my_db to blockatlas * [Zilliqa] Fix block number and timestamp in block parsing * Fix timestamp zil tx * Add blocks endpoint * Update block.go * Run go mod tidy --- Makefile | 2 +- api/endpoint/block.go | 39 +++++++++++++++++++++++++++++ api/registry.go | 9 ++++++- config.yml | 4 +-- configmock.yml | 4 +-- docker-compose.yml | 2 +- go.mod | 3 --- go.sum | 2 ++ platform/zilliqa/model.go | 27 +++++++++++++++++--- platform/zilliqa/model_test.go | 5 +++- platform/zilliqa/rpc.go | 19 +++++++++++--- tests/integration/setup/postgres.go | 2 +- 12 files changed, 98 insertions(+), 20 deletions(-) create mode 100644 api/endpoint/block.go diff --git a/Makefile b/Makefile index 7fae89871..f30b178e6 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ DOCKER_LOCAL_DB_IMAGE_NAME := test_db DOCKER_LOCAL_MQ_IMAGE_NAME := mq DOCKER_LOCAL_DB_USER :=user DOCKER_LOCAL_DB_PASS :=pass -DOCKER_LOCAL_DB := my_db +DOCKER_LOCAL_DB := blockatlas # Go related variables. GOBASE := $(shell pwd) diff --git a/api/endpoint/block.go b/api/endpoint/block.go new file mode 100644 index 000000000..7b5add011 --- /dev/null +++ b/api/endpoint/block.go @@ -0,0 +1,39 @@ +package endpoint + +import ( + "errors" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +// @Summary Get Block +// @ID block_v2 +// @Description Get Block information +// @Accept json +// @Produce json +// @Tags Transactions +// @Param coin path string true "the coin name" default(zilliqa) +// @Param address path string true "the query address" default(850321) +// @Failure 500 {object} ErrorResponse +// @Router /v2/{coin}/blocks/{block} [get] +func GetBlock(c *gin.Context, blockAPI blockatlas.BlockAPI) { + blockString := c.Param("block") + blockNumber, err := strconv.ParseUint(blockString, 10, 32) + + if err != nil || blockNumber <= 1 { + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(errors.New("invalid block number"))) + return + } + + block, err := blockAPI.GetBlockByNumber(int64(blockNumber)) + + if err != nil { + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(errors.New("block number not found"))) + return + } + + c.JSON(http.StatusOK, &block) +} diff --git a/api/registry.go b/api/registry.go index 50d0cc10f..8925a6105 100644 --- a/api/registry.go +++ b/api/registry.go @@ -1,6 +1,8 @@ package api import ( + "time" + "github.com/chenjiandongx/ginprom" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -10,7 +12,6 @@ import ( "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" - "time" ) func RegisterTransactionsAPI(router gin.IRouter, api blockatlas.Platform) { @@ -38,6 +39,12 @@ func RegisterTransactionsAPI(router gin.IRouter, api blockatlas.Platform) { endpoint.GetTransactionsHistory(c, txAPI, tokenTxAPI) }) } + + if blockAPI, ok := api.(blockatlas.BlockAPI); ok { + router.GET("/v2/"+handle+"/blocks/:block", func(c *gin.Context) { + endpoint.GetBlock(c, blockAPI) + }) + } } func RegisterTokensAPI(router gin.IRouter, api blockatlas.Platform) { diff --git a/config.yml b/config.yml index 4f06471f0..d5ad0a060 100644 --- a/config.yml +++ b/config.yml @@ -41,8 +41,8 @@ observer: prefetch_count: 10 postgres: - uri: postgresql://user:pass@localhost/my_db?sslmode=disable - read_uri: postgresql://user:pass@localhost/my_db?sslmode=disable + uri: postgresql://user:pass@localhost/blockatlas?sslmode=disable + read_uri: postgresql://user:pass@localhost/blockatlas?sslmode=disable log: false # [BNB] Binance DEX: https://www.binance.org/ diff --git a/configmock.yml b/configmock.yml index 4035fe986..a91ad5c45 100644 --- a/configmock.yml +++ b/configmock.yml @@ -35,8 +35,8 @@ observer: prefetch_count: 10 postgres: - uri: postgresql://user:pass@localhost/my_db?sslmode=disable - read_uri: postgresql://user:pass@localhost/my_db?sslmode=disable + uri: postgresql://user:pass@localhost/blockatlas?sslmode=disable + read_uri: postgresql://user:pass@localhost/blockatlas?sslmode=disable log: false # [BNB] Binance DEX: https://wallet.binance.org diff --git a/docker-compose.yml b/docker-compose.yml index 6fae13f6d..dc5240ca9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -78,7 +78,7 @@ services: environment: - POSTGRES_USER=user - POSTGRES_PASSWORD=pass - - POSTGRES_DB=my_db + - POSTGRES_DB=blockatlas ports: - 5432:5432 healthcheck: diff --git a/go.mod b/go.mod index ab29c1714..ab171ffa1 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,9 @@ require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 - github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect github.com/deckarep/golang-set v1.7.1 github.com/gin-gonic/gin v1.6.3 github.com/imroc/req v0.3.0 - github.com/kr/pty v1.1.8 // indirect github.com/mitchellh/mapstructure v1.3.3 github.com/mr-tron/base58 v1.2.0 github.com/ory/dockertest v3.3.5+incompatible @@ -31,7 +29,6 @@ require ( go.elastic.co/apm/module/apmhttp v1.8.0 go.elastic.co/apm/module/apmlogrus v1.8.0 go.uber.org/atomic v1.7.0 - go.uber.org/multierr v1.5.0 // indirect golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f gopkg.in/yaml.v2 v2.3.0 diff --git a/go.sum b/go.sum index 36c615607..da0234835 100644 --- a/go.sum +++ b/go.sum @@ -64,9 +64,11 @@ github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufo github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= diff --git a/platform/zilliqa/model.go b/platform/zilliqa/model.go index 45580e011..57ce225b1 100644 --- a/platform/zilliqa/model.go +++ b/platform/zilliqa/model.go @@ -70,16 +70,25 @@ type TxRPC struct { Version string `json:"version"` } -func (t *TxRPC) toTx() *Tx { +func (t *TxRPC) toTx(header BlockHeader) *Tx { + // t.recipient is not parsed correctly. Empty strings. + to, err := hex.DecodeString(t.ToAddr) if err != nil { return nil } - height, err := strconv.ParseUint(t.Receipt.EpochNum, 10, 64) + + timestamp, err := strconv.ParseUint(header.Timestamp, 10, 64) + if err != nil { + timestamp = 0 + } + + height, err := strconv.ParseUint(header.Number, 10, 64) if err != nil { height = 0 } - gasLimt, ok := new(big.Int).SetString(t.GasLimit, 10) + + gasLimit, ok := new(big.Int).SetString(t.GasLimit, 10) if !ok { return nil } @@ -87,7 +96,7 @@ func (t *TxRPC) toTx() *Tx { if !ok { return nil } - fee := new(big.Int).Mul(gasLimt, gasPrice) + fee := new(big.Int).Mul(gasLimit, gasPrice) return &Tx{ Hash: "0x" + t.ID, @@ -96,6 +105,7 @@ func (t *TxRPC) toTx() *Tx { To: EncodeKeyHashToAddress(to), Value: t.Amount, Fee: fee.String(), + Timestamp: int64(timestamp / 1000), Signature: t.Signature, Nonce: t.Nonce, ReceiptSuccess: t.Receipt.Success, @@ -122,3 +132,12 @@ func (h HashesResponse) Txs() []string { } return result } + +type Block struct { + Header BlockHeader `json:"header"` +} + +type BlockHeader struct { + Number string `json:"BlockNum"` + Timestamp string `json:"Timestamp"` +} diff --git a/platform/zilliqa/model_test.go b/platform/zilliqa/model_test.go index bd9668d4a..b17204f8c 100644 --- a/platform/zilliqa/model_test.go +++ b/platform/zilliqa/model_test.go @@ -31,6 +31,7 @@ func TestTxRPC_toTx(t *testing.T) { To: "zil1vxdqe9ck4metep92l4lw2mju9t6wvge9zwkyyl", Value: "1380000000000", Fee: "1000000000", + Timestamp: 1603831144458, Signature: "0xF165643EA12514F62297854CE14F2C4EEFE0E19670A6A64E3C497E19442D0B36A91A8790FE320EC48DDCD3E212F0863955FB6AF5436422461916319D5133886D", Nonce: "16109", ReceiptSuccess: true, @@ -43,7 +44,9 @@ func TestTxRPC_toTx(t *testing.T) { return } - if got := txRPC.toTx(); !reflect.DeepEqual(*got, tx) { + header := BlockHeader{Number: "185343", Timestamp: "1603831144458128"} + + if got := txRPC.toTx(header); !reflect.DeepEqual(*got, tx) { t.Errorf("TxRPC.toTx() = %v, want %v", *got, tx) } } diff --git a/platform/zilliqa/rpc.go b/platform/zilliqa/rpc.go index 0118cbcef..e7e141da9 100644 --- a/platform/zilliqa/rpc.go +++ b/platform/zilliqa/rpc.go @@ -1,9 +1,10 @@ package zilliqa import ( - "github.com/imroc/req" "strconv" + "github.com/imroc/req" + "github.com/mitchellh/mapstructure" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -22,7 +23,7 @@ func (c *RpcClient) GetTx(hash string) (tx TxRPC, err error) { return } -func (c *RpcClient) GetBlockByNumber(number int64) ([]string, error) { +func (c *RpcClient) GetTransactionsHashesInBlock(number int64) ([]string, error) { strNumber := strconv.FormatInt(number, 10) requestBody := &blockatlas.RpcRequest{ JsonRpc: blockatlas.JsonRpcVersion, @@ -43,11 +44,16 @@ func (c *RpcClient) GetBlockByNumber(number int64) ([]string, error) { func (c *RpcClient) GetTxInBlock(number int64) ([]Tx, error) { txs := make([]Tx, 0) - hashes, err := c.GetBlockByNumber(number) + hashes, err := c.GetTransactionsHashesInBlock(number) if err != nil || len(hashes) == 0 { return txs, err } + block, err := c.GetBlock(number) + if err != nil { + return txs, err + } + var requests blockatlas.RpcRequests for _, hash := range hashes { requests = append(requests, &blockatlas.RpcRequest{ @@ -64,9 +70,14 @@ func (c *RpcClient) GetTxInBlock(number int64) ([]Tx, error) { if mapstructure.Decode(result.Result, &txRPC) != nil { continue } - if tx := txRPC.toTx(); tx != nil { + if tx := txRPC.toTx(block.Header); tx != nil { txs = append(txs, *tx) } } return txs, nil } + +func (c *RpcClient) GetBlock(number int64) (block Block, err error) { + err = c.RpcCall(&block, "GetTxBlock", []string{strconv.FormatInt(number, 10)}) + return +} diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go index ac6d96474..b10d72f26 100644 --- a/tests/integration/setup/postgres.go +++ b/tests/integration/setup/postgres.go @@ -12,7 +12,7 @@ import ( const ( pgUser = "user" pgPass = "pass" - pgDB = "my_db" + pgDB = "blockatlas" ) var ( From 78c01da8a7e7a3c5c513a04e4a0302440f8a7d01 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 27 Oct 2020 17:13:11 -0700 Subject: [PATCH 399/506] [Collectibles] Remove V3 API (#1258) * [Collectibles] Remove V3 API * Update block.go --- api/api.go | 1 + api/endpoint/block.go | 2 +- api/endpoint/collection.go | 52 +---------- api/registry.go | 12 +-- pkg/blockatlas/collectibles.go | 38 -------- pkg/blockatlas/marshal.go | 37 +------- pkg/blockatlas/platform.go | 3 - platform/ethereum/collection/client.go | 34 -------- platform/ethereum/collectionV3.go | 115 ------------------------- 9 files changed, 11 insertions(+), 283 deletions(-) delete mode 100644 platform/ethereum/collectionV3.go diff --git a/api/api.go b/api/api.go index 799f13454..c649698df 100644 --- a/api/api.go +++ b/api/api.go @@ -15,6 +15,7 @@ func SetupPlatformAPI(router gin.IRouter) { RegisterTransactionsAPI(router, api) RegisterTokensAPI(router, api) RegisterStakeAPI(router, api) + RegisterBlockAPI(router, api) } for _, api := range platform.CollectionsAPIs { RegisterCollectionsAPI(router, api) diff --git a/api/endpoint/block.go b/api/endpoint/block.go index 7b5add011..b943a2fcd 100644 --- a/api/endpoint/block.go +++ b/api/endpoint/block.go @@ -23,7 +23,7 @@ func GetBlock(c *gin.Context, blockAPI blockatlas.BlockAPI) { blockString := c.Param("block") blockNumber, err := strconv.ParseUint(blockString, 10, 32) - if err != nil || blockNumber <= 1 { + if err != nil || blockNumber < 1 { c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(errors.New("invalid block number"))) return } diff --git a/api/endpoint/collection.go b/api/endpoint/collection.go index 735a44318..956fe20f0 100644 --- a/api/endpoint/collection.go +++ b/api/endpoint/collection.go @@ -1,10 +1,11 @@ package endpoint import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/http" "strconv" + + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) // @Summary Get Collection @@ -64,50 +65,3 @@ func GetCollectionCategoriesFromList(c *gin.Context, apis blockatlas.Collections } c.JSON(http.StatusOK, &batch) } - -func GetCollectiblesForOwnerV3(c *gin.Context, api blockatlas.CollectionsAPI) { - collections, err := api.GetCollectionsV3(c.Param("owner")) - if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) - return - } - - c.JSON(http.StatusOK, &collections) -} - -func GetCollectiblesForSpecificCollectionAndOwnerV3(c *gin.Context, api blockatlas.CollectionsAPI) { - collectibles, err := api.GetCollectiblesV3(c.Param("owner"), c.Param("collection_id")) - if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) - return - } - c.JSON(http.StatusOK, &collectibles) -} - -func GetCollectionCategoriesFromListV3(c *gin.Context, apis blockatlas.CollectionsAPIs) { - var reqs map[string][]string - if err := c.BindJSON(&reqs); err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) - return - } - - batch := make(blockatlas.CollectionPageV3, 0) - for key, addresses := range reqs { - coinId, err := strconv.Atoi(key) - if err != nil { - continue - } - p, ok := apis[uint(coinId)] - if !ok { - continue - } - for _, address := range addresses { - collections, err := p.GetCollectionsV3(address) - if err != nil { - continue - } - batch = append(batch, collections...) - } - } - c.JSON(http.StatusOK, &batch) -} diff --git a/api/registry.go b/api/registry.go index 8925a6105..457c1260d 100644 --- a/api/registry.go +++ b/api/registry.go @@ -39,7 +39,10 @@ func RegisterTransactionsAPI(router gin.IRouter, api blockatlas.Platform) { endpoint.GetTransactionsHistory(c, txAPI, tokenTxAPI) }) } +} +func RegisterBlockAPI(router gin.IRouter, api blockatlas.Platform) { + handle := api.Coin().Handle if blockAPI, ok := api.(blockatlas.BlockAPI); ok { router.GET("/v2/"+handle+"/blocks/:block", func(c *gin.Context) { endpoint.GetBlock(c, blockAPI) @@ -74,12 +77,6 @@ func RegisterStakeAPI(router gin.IRouter, api blockatlas.Platform) { func RegisterCollectionsAPI(router gin.IRouter, api blockatlas.CollectionsAPI) { handle := api.Coin().Handle - router.GET("/v3/"+handle+"/collections/:owner/collection/:collection_id", func(c *gin.Context) { - endpoint.GetCollectiblesForSpecificCollectionAndOwnerV3(c, api) - }) - router.GET("/v3/"+handle+"/collections/:owner", func(c *gin.Context) { - endpoint.GetCollectiblesForOwnerV3(c, api) - }) router.GET("/v4/"+handle+"/collections/:owner/collection/:collection_id", func(c *gin.Context) { endpoint.GetCollectiblesForSpecificCollectionAndOwner(c, api) }) @@ -95,9 +92,6 @@ func RegisterBatchAPI(router gin.IRouter) { router.POST("/v2/staking/list", middleware.CacheMiddleware(time.Hour, func(c *gin.Context) { endpoint.GetStakeInfoForBatch(c, platform.StakeAPIs) })) - router.POST("/v3/collectibles/categories", func(c *gin.Context) { - endpoint.GetCollectionCategoriesFromListV3(c, platform.CollectionsAPIs) - }) router.POST("/v4/collectibles/categories", func(c *gin.Context) { endpoint.GetCollectionCategoriesFromList(c, platform.CollectionsAPIs) }) diff --git a/pkg/blockatlas/collectibles.go b/pkg/blockatlas/collectibles.go index bad081526..ccfb5d88f 100644 --- a/pkg/blockatlas/collectibles.go +++ b/pkg/blockatlas/collectibles.go @@ -1,23 +1,6 @@ package blockatlas type ( - CollectionV3 struct { - Id string `json:"id"` - Name string `json:"name"` - Symbol string `json:"symbol"` - Slug string `json:"slug"` - ImageUrl string `json:"image_url"` - Description string `json:"description"` - ExternalLink string `json:"external_link"` - Total int `json:"total"` - CategoryAddress string `json:"category_address"` - Address string `json:"address"` - Coin uint `json:"coin"` - // Delete in the future version, as it's now part of Collectible - Version string `json:"nft_version"` - Type string `json:"type"` - } - Collection struct { Id string `json:"id"` Name string `json:"name"` @@ -30,8 +13,6 @@ type ( Type string `json:"-"` } - CollectionPageV3 []CollectionV3 - CollectionPage []Collection Collectible struct { @@ -51,23 +32,4 @@ type ( } CollectiblePage []Collectible - - CollectibleV3 struct { - ID string `json:"id"` - CollectionID string `json:"collection_id"` - TokenID string `json:"token_id"` - CategoryContract string `json:"category_contract"` - ContractAddress string `json:"contract_address"` - Category string `json:"category"` - ImageUrl string `json:"image_url"` - ExternalLink string `json:"external_link"` - ProviderLink string `json:"provider_link"` - Type string `json:"type"` - Description string `json:"description"` - Coin uint `json:"coin"` - Name string `json:"name"` - Version string `json:"nft_version"` - } - - CollectiblePageV3 []CollectibleV3 ) diff --git a/pkg/blockatlas/marshal.go b/pkg/blockatlas/marshal.go index 8be4e22fb..ee1a513ad 100644 --- a/pkg/blockatlas/marshal.go +++ b/pkg/blockatlas/marshal.go @@ -2,10 +2,11 @@ package blockatlas import ( "encoding/json" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/numbers" "regexp" "strings" + + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/blockatlas/pkg/numbers" ) var matchNumber = regexp.MustCompile(`^\d+(\.\d+)?$`) @@ -165,35 +166,3 @@ func (r CollectiblePage) MarshalJSON() ([]byte, error) { page.Status = true return json.Marshal(page) } - -// MarshalJSON returns a wrapped list of collections in JSON -func (r CollectionPageV3) MarshalJSON() ([]byte, error) { - var page struct { - Total int `json:"total"` - Docs []CollectionV3 `json:"docs"` - Status bool `json:"status"` - } - page.Docs = []CollectionV3(r) - if page.Docs == nil { - page.Docs = make([]CollectionV3, 0) - } - page.Total = len(page.Docs) - page.Status = true - return json.Marshal(page) -} - -// MarshalJSON returns a wrapped list of collectibles in JSON -func (r CollectiblePageV3) MarshalJSON() ([]byte, error) { - var page struct { - Total int `json:"total"` - Docs []CollectibleV3 `json:"docs"` - Status bool `json:"status"` - } - page.Docs = []CollectibleV3(r) - if page.Docs == nil { - page.Docs = make([]CollectibleV3, 0) - } - page.Total = len(page.Docs) - page.Status = true - return json.Marshal(page) -} diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index a4f28c455..7b723220e 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -55,9 +55,6 @@ type ( Platform GetCollections(owner string) (CollectionPage, error) GetCollectibles(owner, collectibleID string) (CollectiblePage, error) - - GetCollectionsV3(owner string) (CollectionPageV3, error) - GetCollectiblesV3(owner, collectibleID string) (CollectiblePageV3, error) } NamingServiceAPI interface { diff --git a/platform/ethereum/collection/client.go b/platform/ethereum/collection/client.go index 3d82c6a2e..f9c785758 100644 --- a/platform/ethereum/collection/client.go +++ b/platform/ethereum/collection/client.go @@ -3,10 +3,8 @@ package collection import ( "net/url" "strconv" - "strings" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" ) type Client struct { @@ -33,35 +31,3 @@ func (c Client) GetCollectibles(owner string, collectibleID string) ([]Collectib err := c.Get(&page, "api/v1/assets", query) return page.Collectibles, err } - -func (c Client) GetCollectiblesV3(owner string, collectibleID string) (*Collection, []Collectible, error) { - collections, err := c.GetCollections(owner) - if err != nil { - return nil, nil, err - } - collection := SearchCollection(collections, collectibleID) - if collection == nil { - return nil, nil, errors.E("collectible not found", errors.TypePlatformClient, - errors.Params{"collectibleID": collectibleID}) - } - - query := url.Values{ - "owner": {owner}, - "limit": {strconv.Itoa(300)}, - } - - query.Set("collection", collection.Slug) - - var page CollectiblePage - err = c.Get(&page, "api/v1/assets", query) - return collection, page.Collectibles, err -} - -func SearchCollection(collections []Collection, collectibleID string) *Collection { - for _, i := range collections { - if strings.EqualFold(i.Slug, collectibleID) { - return &i - } - } - return nil -} diff --git a/platform/ethereum/collectionV3.go b/platform/ethereum/collectionV3.go deleted file mode 100644 index a049d5cd9..000000000 --- a/platform/ethereum/collectionV3.go +++ /dev/null @@ -1,115 +0,0 @@ -package ethereum - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/platform/ethereum/collection" - "strings" -) - -func (p *Platform) GetCollectionsV3(owner string) (blockatlas.CollectionPageV3, error) { - collections, err := p.collectible.GetCollections(owner) - if err != nil { - return nil, err - } - page := NormalizeCollectionPageV3(collections, p.CoinIndex, owner) - return page, nil -} - -func (p *Platform) GetCollectiblesV3(owner, collectibleID string) (blockatlas.CollectiblePageV3, error) { - collection, items, err := p.collectible.GetCollectiblesV3(owner, collectibleID) - if err != nil { - return nil, err - } - page := NormalizeCollectiblePageV3(collection, items, p.CoinIndex) - return page, nil -} - -func NormalizeCollectionPageV3(collections []collection.Collection, coinIndex uint, owner string) (page blockatlas.CollectionPageV3) { - for _, collection := range collections { - if len(collection.Contracts) == 0 { - continue - } - item := NormalizeCollectionV3(collection, coinIndex, owner) - if _, ok := supportedTypes[item.Type]; !ok { - continue - } - page = append(page, item) - } - return -} - -func NormalizeCollectionV3(c collection.Collection, coinIndex uint, owner string) blockatlas.CollectionV3 { - normalizeSupportedContracts(&c) - if len(c.Contracts) == 0 { - return blockatlas.CollectionV3{} - } - - description := blockatlas.GetValidParameter(c.Description, c.Contracts[0].Description) - symbol := blockatlas.GetValidParameter(c.Contracts[0].Symbol, "") - version := blockatlas.GetValidParameter(c.Contracts[0].NftVersion, "") - collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") - - return blockatlas.CollectionV3{ - Name: c.Name, - Symbol: symbol, - Slug: c.Slug, - ImageUrl: c.ImageUrl, - Description: description, - ExternalLink: c.ExternalUrl, - Total: int(c.Total.Int64()), - Id: c.Slug, - CategoryAddress: c.Slug, - Address: owner, - Version: version, - Coin: coinIndex, - Type: collectionType, - } -} - -func normalizeSupportedContracts(c *collection.Collection) { - supportedContracts := make([]collection.PrimaryAssetContract, 0) - for _, contract := range c.Contracts { - if _, ok := supportedTypes[contract.Type]; !ok { - continue - } - supportedContracts = append(supportedContracts, contract) - } - c.Contracts = supportedContracts -} - -func NormalizeCollectiblePageV3(c *collection.Collection, srcPage []collection.Collectible, coinIndex uint) (page blockatlas.CollectiblePageV3) { - normalizeSupportedContracts(c) - if len(c.Contracts) == 0 { - return - } - for _, src := range srcPage { - item := NormalizeCollectibleV3(c, src, coinIndex) - if _, ok := supportedTypes[item.Type]; !ok { - continue - } - page = append(page, item) - } - return -} - -func NormalizeCollectibleV3(c *collection.Collection, a collection.Collectible, coinIndex uint) blockatlas.CollectibleV3 { - address := blockatlas.GetValidParameter(c.Contracts[0].Address, "") - collectionType := blockatlas.GetValidParameter(c.Contracts[0].Type, "") - externalLink := blockatlas.GetValidParameter(a.ExternalLink, a.AssetContract.ExternalLink) - id := strings.Join([]string{a.AssetContract.Address, a.TokenId}, "-") - return blockatlas.CollectibleV3{ - ID: id, - CollectionID: c.Slug, - ContractAddress: address, - TokenID: a.TokenId, - CategoryContract: a.AssetContract.Address, - Name: a.Name, - Category: c.Name, - ImageUrl: a.ImagePreviewUrl, - ProviderLink: a.Permalink, - ExternalLink: externalLink, - Type: collectionType, - Description: a.Description, - Coin: coinIndex, - } -} From 335b54ae51b0ba4f5db555817acdaf2a42f4b576 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 27 Oct 2020 23:33:26 -0700 Subject: [PATCH 400/506] Remove domain service (#1259) * Remove domain service * Update client.go * Remove domain_data.json * Run go mod tidy * Create Procfile * Revert "Create Procfile" This reverts commit 29764b8253949a830beedecc56cd856a07fc7ffa. * Update Makefile * Remove mentions of domain --- Makefile | 6 +- README.md | 2 +- api/api.go | 1 - api/endpoint/domain.go | 82 ------ api/endpoint/staking.go | 13 +- api/registry.go | 5 - config.yml | 1 - configmock.yml | 1 - docs/docs.go | 269 ++++++++--------- docs/swagger.json | 271 ++++++++---------- docs/swagger.yaml | 175 +++++------ go.mod | 2 - mock/datafiles.yaml | 8 - pkg/blockatlas/platform.go | 5 - pkg/naming/naming.go | 14 - pkg/naming/naming_test.go | 31 -- platform/ethereum/base.go | 6 +- platform/ethereum/domain.go | 72 ----- platform/ethereum/domain_test.go | 31 -- platform/ethereum/ens/ens_client.go | 84 ------ platform/ethereum/ens/ens_encoder.go | 86 ------ platform/ethereum/ens/ens_encoder_test.go | 193 ------------- platform/ethereum/ens/namehash.go | 89 ------ platform/ethereum/ens/namehash_test.go | 90 ------ platform/fio/client.go | 12 - platform/fio/domain.go | 40 --- platform/fio/domain_test.go | 32 --- platform/platform.go | 14 +- platform/registry.go | 5 +- platform/zilliqa/base.go | 4 +- platform/zilliqa/client.go | 5 - platform/zilliqa/domain.go | 38 --- platform/zilliqa/domain_test.go | 29 -- scripts/run_tests_postman.sh | 1 - services/domains/domains.go | 33 --- services/domains/domains_test.go | 73 ----- .../blockatlas.postman_collection.json | 218 +------------- tests/postman/domain_data.json | 58 ---- 38 files changed, 325 insertions(+), 1774 deletions(-) delete mode 100644 api/endpoint/domain.go delete mode 100644 pkg/naming/naming.go delete mode 100644 pkg/naming/naming_test.go delete mode 100644 platform/ethereum/domain.go delete mode 100644 platform/ethereum/domain_test.go delete mode 100644 platform/ethereum/ens/ens_client.go delete mode 100644 platform/ethereum/ens/ens_encoder.go delete mode 100644 platform/ethereum/ens/ens_encoder_test.go delete mode 100644 platform/ethereum/ens/namehash.go delete mode 100644 platform/ethereum/ens/namehash_test.go delete mode 100644 platform/fio/domain.go delete mode 100644 platform/fio/domain_test.go delete mode 100644 platform/zilliqa/domain.go delete mode 100644 platform/zilliqa/domain_test.go delete mode 100644 services/domains/domains.go delete mode 100644 services/domains/domains_test.go delete mode 100644 tests/postman/domain_data.json diff --git a/Makefile b/Makefile index f30b178e6..459d275ff 100644 --- a/Makefile +++ b/Makefile @@ -201,11 +201,10 @@ newman-mocked: install-newman go-compile ## newman-mocked-params: Run mocked Postman Newman tests, after starting platform api. ## The host parameter is required. -## E.g.: $ make newman-mocked-params test=domain host=http://localhost:8437 +## E.g.: $ make newman-mocked-params test=transaction host=http://localhost:8437 newman-mocked-params: start-api-mock ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host) && \ - $(MAKE) newman-run test=domain host=$(host) && \ $(MAKE) newman-run test=staking host=$(host) && \ $(MAKE) newman-run test=token host=$(host) && \ $(MAKE) newman-run test=collection host=$(host)" @@ -215,14 +214,13 @@ else @bash -c "$(MAKE) stop" endif -## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, domain, healthcheck, observer). e.g $ make newman test=staking host=http://localhost:8420 +## newman: Run Postman Newman test, the host parameter is required, and you can specify the name of the test do you wanna run (transaction, token, staking, collection, healthcheck, observer). e.g $ make newman test=staking host=http://localhost:8420 newman: install-newman ifeq (,$(test)) @bash -c "$(MAKE) newman-run test=transaction host=$(host)" @bash -c "$(MAKE) newman-run test=token host=$(host)" @bash -c "$(MAKE) newman-run test=staking host=$(host)" @bash -c "$(MAKE) newman-run test=collection host=$(host)" - @bash -c "$(MAKE) newman-run test=domain host=$(host)" @bash -c "$(MAKE) newman-run test=healthcheck host=$(host)" else @bash -c "$(MAKE) newman-run test=$(test) host=$(host)" diff --git a/README.md b/README.md index 2e7254c01..3b00a0c65 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ The observer API watches the chain for new transactions and generates notificati Currently Block Atlas is under active development and is not well documented. If you still want to run it on your own or help to contribute, **please** pay attention that currently integration, nemwan, functional tests are not working locally without all endpoints. We are fixing that issue and soon you will be able to test all the stuff locally Blockatlas allows to: -- Get information about transactions, tokens, staking details, collectibles, crypto domains for supported coins. +- Get information about transactions, tokens, staking details, collectibles for supported coins. - Subscribe for price notifications via Rabbit MQ Platform API is independent service and can work with the specific blockchain only (like Bitcoin, Ethereum, etc) diff --git a/api/api.go b/api/api.go index c649698df..26ff79b02 100644 --- a/api/api.go +++ b/api/api.go @@ -22,7 +22,6 @@ func SetupPlatformAPI(router gin.IRouter) { } RegisterBatchAPI(router) - RegisterDomainAPI(router) RegisterBasicAPI(router) } diff --git a/api/endpoint/domain.go b/api/endpoint/domain.go deleted file mode 100644 index 5fe7c3e01..000000000 --- a/api/endpoint/domain.go +++ /dev/null @@ -1,82 +0,0 @@ -package endpoint - -import ( - "net/http" - "strconv" - "strings" - - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/services/domains" -) - -// @Summary Lookup .eth / .zil addresses -// @ID lookup_v1 -// @Description Lookup ENS/ZNS to find registered addresses -// @Produce json -// @Tags Naming -// @Param name query string empty "string name" -// @Param coin query string 60 "string coin" -// @Success 200 {object} blockatlas.Resolved -// @Failure 500 {object} ErrorResponse -// @Router /ns/lookup [get] -func GetAddressByCoinAndDomain(c *gin.Context) { - name := c.Query("name") - coinQuery := c.Query("coin") - coin, err := strconv.ParseUint(coinQuery, 10, 64) - if err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) - return - } - result, err := domains.HandleLookup(name, []uint64{coin}) - if err != nil { - c.AbortWithStatusJSON(http.StatusNotFound, errorResponse(err)) - return - } - if len(result) == 0 { - c.AbortWithStatusJSON(http.StatusNotFound, errorResponse(err)) - return - } - c.JSON(http.StatusOK, result[0]) -} - -// @Summary Lookup .eth / .zil addresses -// @ID lookup_v2 -// @Description Lookup ENS/ZNS to find registered addresses for multiple coins -// @Produce json -// @Tags Naming -// @Param name query string empty "string name" -// @Param coins query string true "List of coins" -// @Success 200 {array} blockatlas.Resolved -// @Failure 500 {object} ErrorResponse -// @Router /v2/ns/lookup [get] -func GetAddressByCoinAndDomainBatch(c *gin.Context) { - name := c.Query("name") - coinsRaw := strings.Split(c.Query("coins"), ",") - coins, err := sliceAtoi(coinsRaw) - if err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) - return - } - result, err := domains.HandleLookup(name, coins) - if err != nil { - c.AbortWithStatusJSON(http.StatusNotFound, errorResponse(err)) - return - } - if len(result) == 0 { - c.AbortWithStatusJSON(http.StatusNotFound, errorResponse(err)) - return - } - c.JSON(http.StatusOK, &result) -} - -func sliceAtoi(sa []string) ([]uint64, error) { - si := make([]uint64, 0, len(sa)) - for _, a := range sa { - i, err := strconv.ParseUint(a, 10, 64) - if err != nil { - return si, err - } - si = append(si, i) - } - return si, nil -} diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index 86171635f..7dec5ca39 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -1,14 +1,17 @@ package endpoint import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/golibs/coin" "net/http" "sort" "strconv" "strings" + + "github.com/trustwallet/blockatlas/pkg/numbers" + + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/pkg/errors" + "github.com/trustwallet/golibs/coin" ) type ( @@ -116,7 +119,7 @@ func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { coinsRaw := strings.Split(coinsRequest, ",") - coins, err := sliceAtoi(coinsRaw) + coins, err := numbers.SliceAtoi(coinsRaw) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) return diff --git a/api/registry.go b/api/registry.go index 457c1260d..e4450911f 100644 --- a/api/registry.go +++ b/api/registry.go @@ -100,11 +100,6 @@ func RegisterBatchAPI(router gin.IRouter) { }) } -func RegisterDomainAPI(router gin.IRouter) { - router.GET("/ns/lookup", endpoint.GetAddressByCoinAndDomain) - router.GET("/v2/ns/lookup", endpoint.GetAddressByCoinAndDomainBatch) -} - func RegisterBasicAPI(router gin.IRouter) { router.GET("/", endpoint.GetStatus) router.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) diff --git a/config.yml b/config.yml index d5ad0a060..170eba090 100644 --- a/config.yml +++ b/config.yml @@ -141,7 +141,6 @@ zilliqa: api: https://api.viewblock.io/v1/zilliqa # key: YOUR_API_KEY rpc: https://api.zilliqa.com - lookup: https://unstoppabledomains.com/api/v1 #[IoTeX] IoTeX: https://iotex.io iotex: diff --git a/configmock.yml b/configmock.yml index a91ad5c45..01bd05d26 100644 --- a/configmock.yml +++ b/configmock.yml @@ -135,7 +135,6 @@ zilliqa: api: http://localhost:3347/mock/zilliqa-api # key: YOUR_API_KEY rpc: https://api.zilliqa.com - lookup: http://localhost:3347/mock/unstoppabledomains/api/v1 #[IoTeX] IoTeX: https://iotex.io iotex: diff --git a/docs/docs.go b/docs/docs.go index 465e12021..af7c1e4b6 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -19,98 +19,11 @@ var doc = `{ "description": "{{.Description}}", "title": "{{.Title}}", "contact": {}, - "license": {}, "version": "{{.Version}}" }, "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/ns/lookup": { - "get": { - "description": "Lookup ENS/ZNS to find registered addresses", - "produces": [ - "application/json" - ], - "tags": [ - "Naming" - ], - "summary": "Lookup .eth / .zil addresses", - "operationId": "lookup", - "parameters": [ - { - "type": "string", - "description": "string name", - "name": "name", - "in": "query" - }, - { - "type": "string", - "description": "string coin", - "name": "coin", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.Resolved" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" - } - } - } - } - }, - "/v2/ns/lookup": { - "get": { - "description": "Lookup ENS/ZNS to find registered addresses for multiple coins", - "produces": [ - "application/json" - ], - "tags": [ - "Naming" - ], - "summary": "Lookup .eth / .zil addresses", - "operationId": "lookup", - "parameters": [ - { - "type": "string", - "description": "string name", - "name": "name", - "in": "query" - }, - { - "type": "string", - "description": "List of coins", - "name": "coins", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Resolved" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" - } - } - } - } - }, "/v2/staking/delegations": { "post": { "description": "Get Stake Delegations for multiple coins", @@ -124,7 +37,7 @@ var doc = `{ "Staking" ], "summary": "Get Multiple Stake Delegations", - "operationId": "batch_delegations", + "operationId": "staking_v2_batch", "parameters": [ { "description": "Validators addresses and coins", @@ -132,7 +45,10 @@ var doc = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/endpoint.AddressesRequest" + "type": "array", + "items": { + "$ref": "#/definitions/api_endpoint.AddressBatchRequest" + } } } ], @@ -140,7 +56,10 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.DelegationsBatchPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.DelegationResponse" + } } } } @@ -159,7 +78,7 @@ var doc = `{ "Staking" ], "summary": "Get Multiple Stake Delegations", - "operationId": "batch_delegations", + "operationId": "staking_v2", "parameters": [ { "description": "Validators addresses and coins", @@ -167,7 +86,10 @@ var doc = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/endpoint.AddressesRequest" + "type": "array", + "items": { + "$ref": "#/definitions/api_endpoint.AddressBatchRequest" + } } } ], @@ -175,7 +97,10 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.DelegationsBatchPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.DelegationResponse" + } } } } @@ -217,6 +142,48 @@ var doc = `{ } } }, + "/v2/{coin}/blocks/{block}": { + "get": { + "description": "Get Block information", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Transactions" + ], + "summary": "Get Block", + "operationId": "block_v2", + "parameters": [ + { + "type": "string", + "default": "zilliqa", + "description": "the coin name", + "name": "coin", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "850321", + "description": "the query address", + "name": "address", + "in": "path", + "required": true + } + ], + "responses": { + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + } + } + } + } + }, "/v2/{coin}/staking/delegations/{address}": { "get": { "description": "Get stake delegations from the address", @@ -259,7 +226,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/api_endpoint.ErrorResponse" } } } @@ -278,7 +245,7 @@ var doc = `{ "Staking" ], "summary": "Get Validators", - "operationId": "validators", + "operationId": "validators_v2", "parameters": [ { "type": "string", @@ -299,7 +266,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/api_endpoint.ErrorResponse" } } } @@ -341,13 +308,16 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Collection" + } } }, "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" } } } @@ -389,7 +359,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" } } } @@ -431,7 +401,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" } } } @@ -447,7 +417,7 @@ var doc = `{ "Staking" ], "summary": "Get staking info by coin ID", - "operationId": "batch_info", + "operationId": "staking_v3", "parameters": [ { "type": "string", @@ -463,14 +433,17 @@ var doc = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/blockatlas.DelegationsBatchPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.DelegationResponse" + } } } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/api_endpoint.ErrorResponse" } } } @@ -556,13 +529,16 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Collection" + } } }, "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" } } } @@ -570,6 +546,33 @@ var doc = `{ } }, "definitions": { + "api_endpoint.AddressBatchRequest": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "coin": { + "type": "integer" + } + } + }, + "api_endpoint.ErrorDetails": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "api_endpoint.ErrorResponse": { + "type": "object", + "properties": { + "error": { + "$ref": "#/definitions/api_endpoint.ErrorDetails" + } + } + }, "blockatlas.Collection": { "type": "object", "properties": { @@ -599,17 +602,10 @@ var doc = `{ } } }, - "blockatlas.CollectionPage": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Collection" - } - }, "blockatlas.Delegation": { "type": "object", "properties": { "delegator": { - "type": "object", "$ref": "#/definitions/blockatlas.StakeValidator" }, "metadata": { @@ -633,31 +629,19 @@ var doc = `{ "type": "string" }, "coin": { - "type": "object", "$ref": "#/definitions/coin.ExternalCoin" }, "delegations": { - "type": "object", - "$ref": "#/definitions/blockatlas.DelegationsPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Delegation" + } }, "details": { - "type": "object", "$ref": "#/definitions/blockatlas.StakingDetails" } } }, - "blockatlas.DelegationsBatchPage": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.DelegationResponse" - } - }, - "blockatlas.DelegationsPage": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Delegation" - } - }, "blockatlas.DocsResponse": { "type": "object", "properties": { @@ -666,17 +650,6 @@ var doc = `{ } } }, - "blockatlas.Resolved": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "result": { - "type": "string" - } - } - }, "blockatlas.ResultsResponse": { "type": "object", "properties": { @@ -692,14 +665,12 @@ var doc = `{ "type": "object", "properties": { "details": { - "type": "object", "$ref": "#/definitions/blockatlas.StakingDetails" }, "id": { "type": "string" }, "info": { - "type": "object", "$ref": "#/definitions/blockatlas.StakeValidatorInfo" }, "status": { @@ -734,7 +705,6 @@ var doc = `{ "type": "string" }, "reward": { - "type": "object", "$ref": "#/definitions/blockatlas.StakingReward" }, "type": { @@ -767,7 +737,7 @@ var doc = `{ } } }, - "endpoint.AddressBatchRequest": { + "github.com_trustwallet_blockatlas_api_endpoint.AddressBatchRequest": { "type": "object", "properties": { "address": { @@ -778,13 +748,7 @@ var doc = `{ } } }, - "endpoint.AddressesRequest": { - "type": "array", - "items": { - "$ref": "#/definitions/endpoint.AddressBatchRequest" - } - }, - "endpoint.ErrorDetails": { + "github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails": { "type": "object", "properties": { "message": { @@ -792,12 +756,11 @@ var doc = `{ } } }, - "endpoint.ErrorResponse": { + "github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse": { "type": "object", "properties": { "error": { - "type": "object", - "$ref": "#/definitions/endpoint.ErrorDetails" + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails" } } } diff --git a/docs/swagger.json b/docs/swagger.json index 610ae0451..eb5822d19 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1,96 +1,9 @@ { "swagger": "2.0", "info": { - "contact": {}, - "license": {} + "contact": {} }, "paths": { - "/ns/lookup": { - "get": { - "description": "Lookup ENS/ZNS to find registered addresses", - "produces": [ - "application/json" - ], - "tags": [ - "Naming" - ], - "summary": "Lookup .eth / .zil addresses", - "operationId": "lookup", - "parameters": [ - { - "type": "string", - "description": "string name", - "name": "name", - "in": "query" - }, - { - "type": "string", - "description": "string coin", - "name": "coin", - "in": "query" - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/blockatlas.Resolved" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" - } - } - } - } - }, - "/v2/ns/lookup": { - "get": { - "description": "Lookup ENS/ZNS to find registered addresses for multiple coins", - "produces": [ - "application/json" - ], - "tags": [ - "Naming" - ], - "summary": "Lookup .eth / .zil addresses", - "operationId": "lookup", - "parameters": [ - { - "type": "string", - "description": "string name", - "name": "name", - "in": "query" - }, - { - "type": "string", - "description": "List of coins", - "name": "coins", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Resolved" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" - } - } - } - } - }, "/v2/staking/delegations": { "post": { "description": "Get Stake Delegations for multiple coins", @@ -104,7 +17,7 @@ "Staking" ], "summary": "Get Multiple Stake Delegations", - "operationId": "batch_delegations", + "operationId": "staking_v2_batch", "parameters": [ { "description": "Validators addresses and coins", @@ -112,7 +25,10 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/endpoint.AddressesRequest" + "type": "array", + "items": { + "$ref": "#/definitions/api_endpoint.AddressBatchRequest" + } } } ], @@ -120,7 +36,10 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.DelegationsBatchPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.DelegationResponse" + } } } } @@ -139,7 +58,7 @@ "Staking" ], "summary": "Get Multiple Stake Delegations", - "operationId": "batch_delegations", + "operationId": "staking_v2", "parameters": [ { "description": "Validators addresses and coins", @@ -147,7 +66,10 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/endpoint.AddressesRequest" + "type": "array", + "items": { + "$ref": "#/definitions/api_endpoint.AddressBatchRequest" + } } } ], @@ -155,7 +77,10 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.DelegationsBatchPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.DelegationResponse" + } } } } @@ -197,6 +122,48 @@ } } }, + "/v2/{coin}/blocks/{block}": { + "get": { + "description": "Get Block information", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Transactions" + ], + "summary": "Get Block", + "operationId": "block_v2", + "parameters": [ + { + "type": "string", + "default": "zilliqa", + "description": "the coin name", + "name": "coin", + "in": "path", + "required": true + }, + { + "type": "string", + "default": "850321", + "description": "the query address", + "name": "address", + "in": "path", + "required": true + } + ], + "responses": { + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + } + } + } + } + }, "/v2/{coin}/staking/delegations/{address}": { "get": { "description": "Get stake delegations from the address", @@ -239,7 +206,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/api_endpoint.ErrorResponse" } } } @@ -258,7 +225,7 @@ "Staking" ], "summary": "Get Validators", - "operationId": "validators", + "operationId": "validators_v2", "parameters": [ { "type": "string", @@ -279,7 +246,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/api_endpoint.ErrorResponse" } } } @@ -321,13 +288,16 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Collection" + } } }, "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" } } } @@ -369,7 +339,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" } } } @@ -411,7 +381,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" } } } @@ -427,7 +397,7 @@ "Staking" ], "summary": "Get staking info by coin ID", - "operationId": "batch_info", + "operationId": "staking_v3", "parameters": [ { "type": "string", @@ -443,14 +413,17 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/blockatlas.DelegationsBatchPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.DelegationResponse" + } } } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/api_endpoint.ErrorResponse" } } } @@ -536,13 +509,16 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Collection" + } } }, "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/endpoint.ErrorResponse" + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" } } } @@ -550,6 +526,33 @@ } }, "definitions": { + "api_endpoint.AddressBatchRequest": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "coin": { + "type": "integer" + } + } + }, + "api_endpoint.ErrorDetails": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "api_endpoint.ErrorResponse": { + "type": "object", + "properties": { + "error": { + "$ref": "#/definitions/api_endpoint.ErrorDetails" + } + } + }, "blockatlas.Collection": { "type": "object", "properties": { @@ -579,17 +582,10 @@ } } }, - "blockatlas.CollectionPage": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Collection" - } - }, "blockatlas.Delegation": { "type": "object", "properties": { "delegator": { - "type": "object", "$ref": "#/definitions/blockatlas.StakeValidator" }, "metadata": { @@ -613,31 +609,19 @@ "type": "string" }, "coin": { - "type": "object", "$ref": "#/definitions/coin.ExternalCoin" }, "delegations": { - "type": "object", - "$ref": "#/definitions/blockatlas.DelegationsPage" + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Delegation" + } }, "details": { - "type": "object", "$ref": "#/definitions/blockatlas.StakingDetails" } } }, - "blockatlas.DelegationsBatchPage": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.DelegationResponse" - } - }, - "blockatlas.DelegationsPage": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Delegation" - } - }, "blockatlas.DocsResponse": { "type": "object", "properties": { @@ -646,17 +630,6 @@ } } }, - "blockatlas.Resolved": { - "type": "object", - "properties": { - "coin": { - "type": "integer" - }, - "result": { - "type": "string" - } - } - }, "blockatlas.ResultsResponse": { "type": "object", "properties": { @@ -672,14 +645,12 @@ "type": "object", "properties": { "details": { - "type": "object", "$ref": "#/definitions/blockatlas.StakingDetails" }, "id": { "type": "string" }, "info": { - "type": "object", "$ref": "#/definitions/blockatlas.StakeValidatorInfo" }, "status": { @@ -714,7 +685,6 @@ "type": "string" }, "reward": { - "type": "object", "$ref": "#/definitions/blockatlas.StakingReward" }, "type": { @@ -747,7 +717,7 @@ } } }, - "endpoint.AddressBatchRequest": { + "github.com_trustwallet_blockatlas_api_endpoint.AddressBatchRequest": { "type": "object", "properties": { "address": { @@ -758,13 +728,7 @@ } } }, - "endpoint.AddressesRequest": { - "type": "array", - "items": { - "$ref": "#/definitions/endpoint.AddressBatchRequest" - } - }, - "endpoint.ErrorDetails": { + "github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails": { "type": "object", "properties": { "message": { @@ -772,12 +736,11 @@ } } }, - "endpoint.ErrorResponse": { + "github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse": { "type": "object", "properties": { "error": { - "type": "object", - "$ref": "#/definitions/endpoint.ErrorDetails" + "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails" } } } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 836b13e3d..f5111ea46 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,4 +1,21 @@ definitions: + api_endpoint.AddressBatchRequest: + properties: + address: + type: string + coin: + type: integer + type: object + api_endpoint.ErrorDetails: + properties: + message: + type: string + type: object + api_endpoint.ErrorResponse: + properties: + error: + $ref: '#/definitions/api_endpoint.ErrorDetails' + type: object blockatlas.Collection: properties: address: @@ -18,15 +35,10 @@ definitions: total: type: integer type: object - blockatlas.CollectionPage: - items: - $ref: '#/definitions/blockatlas.Collection' - type: array blockatlas.Delegation: properties: delegator: $ref: '#/definitions/blockatlas.StakeValidator' - type: object metadata: type: object status: @@ -42,34 +54,18 @@ definitions: type: string coin: $ref: '#/definitions/coin.ExternalCoin' - type: object delegations: - $ref: '#/definitions/blockatlas.DelegationsPage' - type: object + items: + $ref: '#/definitions/blockatlas.Delegation' + type: array details: $ref: '#/definitions/blockatlas.StakingDetails' - type: object type: object - blockatlas.DelegationsBatchPage: - items: - $ref: '#/definitions/blockatlas.DelegationResponse' - type: array - blockatlas.DelegationsPage: - items: - $ref: '#/definitions/blockatlas.Delegation' - type: array blockatlas.DocsResponse: properties: docs: type: object type: object - blockatlas.Resolved: - properties: - coin: - type: integer - result: - type: string - type: object blockatlas.ResultsResponse: properties: docs: @@ -81,12 +77,10 @@ definitions: properties: details: $ref: '#/definitions/blockatlas.StakingDetails' - type: object id: type: string info: $ref: '#/definitions/blockatlas.StakeValidatorInfo' - type: object status: type: boolean type: object @@ -109,7 +103,6 @@ definitions: type: string reward: $ref: '#/definitions/blockatlas.StakingReward' - type: object type: type: string type: object @@ -129,59 +122,55 @@ definitions: symbol: type: string type: object - endpoint.AddressBatchRequest: + github.com_trustwallet_blockatlas_api_endpoint.AddressBatchRequest: properties: address: type: string coin: type: integer type: object - endpoint.AddressesRequest: - items: - $ref: '#/definitions/endpoint.AddressBatchRequest' - type: array - endpoint.ErrorDetails: + github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails: properties: message: type: string type: object - endpoint.ErrorResponse: + github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse: properties: error: - $ref: '#/definitions/endpoint.ErrorDetails' - type: object + $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails' type: object info: contact: {} - license: {} paths: - /ns/lookup: + /v2/{coin}/blocks/{block}: get: - description: Lookup ENS/ZNS to find registered addresses - operationId: lookup + consumes: + - application/json + description: Get Block information + operationId: block_v2 parameters: - - description: string name - in: query - name: name - type: string - - description: string coin - in: query + - default: zilliqa + description: the coin name + in: path name: coin + required: true + type: string + - default: "850321" + description: the query address + in: path + name: address + required: true type: string produces: - application/json responses: - "200": - description: OK - schema: - $ref: '#/definitions/blockatlas.Resolved' "500": description: Internal Server Error schema: - $ref: '#/definitions/endpoint.ErrorResponse' - summary: Lookup .eth / .zil addresses + $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse' + summary: Get Block tags: - - Naming + - Transactions /v2/{coin}/staking/delegations/{address}: get: consumes: @@ -211,7 +200,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/endpoint.ErrorResponse' + $ref: '#/definitions/api_endpoint.ErrorResponse' summary: Get Stake Delegations tags: - Staking @@ -220,7 +209,7 @@ paths: consumes: - application/json description: Get validators from the address - operationId: validators + operationId: validators_v2 parameters: - default: cosmos description: the coin name @@ -238,7 +227,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/endpoint.ErrorResponse' + $ref: '#/definitions/api_endpoint.ErrorResponse' summary: Get Validators tags: - Staking @@ -267,11 +256,13 @@ paths: "200": description: OK schema: - $ref: '#/definitions/blockatlas.CollectionPage' + items: + $ref: '#/definitions/blockatlas.Collection' + type: array "500": description: Internal Server Error schema: - $ref: '#/definitions/endpoint.ErrorResponse' + $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse' summary: Get Tokens tags: - Transactions @@ -300,7 +291,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/endpoint.ErrorResponse' + $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse' summary: Get Transactions tags: - Transactions @@ -329,60 +320,34 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/endpoint.ErrorResponse' + $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse' summary: Get Transactions by XPUB tags: - Transactions - /v2/ns/lookup: - get: - description: Lookup ENS/ZNS to find registered addresses for multiple coins - operationId: lookup - parameters: - - description: string name - in: query - name: name - type: string - - description: List of coins - in: query - name: coins - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/blockatlas.Resolved' - type: array - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/endpoint.ErrorResponse' - summary: Lookup .eth / .zil addresses - tags: - - Naming /v2/staking/delegations: post: consumes: - application/json description: Get Stake Delegations for multiple coins - operationId: batch_delegations + operationId: staking_v2_batch parameters: - description: Validators addresses and coins in: body name: delegations required: true schema: - $ref: '#/definitions/endpoint.AddressesRequest' + items: + $ref: '#/definitions/api_endpoint.AddressBatchRequest' + type: array produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/blockatlas.DelegationsBatchPage' + items: + $ref: '#/definitions/blockatlas.DelegationResponse' + type: array summary: Get Multiple Stake Delegations tags: - Staking @@ -391,21 +356,25 @@ paths: consumes: - application/json description: Get Stake Delegations for multiple coins - operationId: batch_delegations + operationId: staking_v2 parameters: - description: Validators addresses and coins in: body name: delegations required: true schema: - $ref: '#/definitions/endpoint.AddressesRequest' + items: + $ref: '#/definitions/api_endpoint.AddressBatchRequest' + type: array produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/blockatlas.DelegationsBatchPage' + items: + $ref: '#/definitions/blockatlas.DelegationResponse' + type: array summary: Get Multiple Stake Delegations tags: - Staking @@ -436,7 +405,7 @@ paths: /v3/staking/list: get: description: Get staking info by coin ID - operationId: batch_info + operationId: staking_v3 parameters: - description: List of coins in: query @@ -450,12 +419,14 @@ paths: description: OK schema: items: - $ref: '#/definitions/blockatlas.DelegationsBatchPage' + items: + $ref: '#/definitions/blockatlas.DelegationResponse' + type: array type: array "400": description: Bad Request schema: - $ref: '#/definitions/endpoint.ErrorResponse' + $ref: '#/definitions/api_endpoint.ErrorResponse' summary: Get staking info by coin ID tags: - Staking @@ -490,11 +461,13 @@ paths: "200": description: OK schema: - $ref: '#/definitions/blockatlas.CollectionPage' + items: + $ref: '#/definitions/blockatlas.Collection' + type: array "500": description: Internal Server Error schema: - $ref: '#/definitions/endpoint.ErrorResponse' + $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse' summary: Get Collection tags: - Collections diff --git a/go.mod b/go.mod index ab171ffa1..b7da3b093 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,6 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 - github.com/trustwallet/ens-coincodec v1.0.6 github.com/trustwallet/golibs v0.0.8 github.com/trustwallet/watchmarket v1.1.1 go.elastic.co/apm v1.8.0 @@ -30,7 +29,6 @@ require ( go.elastic.co/apm/module/apmlogrus v1.8.0 go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 - golang.org/x/net v0.0.0-20200506145744-7e3656a0809f gopkg.in/yaml.v2 v2.3.0 gorm.io/driver/postgres v1.0.0 gorm.io/gorm v1.20.0 diff --git a/mock/datafiles.yaml b/mock/datafiles.yaml index 4da3c2ed6..caa9a36da 100644 --- a/mock/datafiles.yaml +++ b/mock/datafiles.yaml @@ -337,14 +337,6 @@ mockURL: /mock/tron-api/wallet/listwitnesses method: GET extURL: https://api.trongrid.io/wallet/listwitnesses -- file: mock/ext-api-data/unstoppabledomains_api_v1__dpantani.zil.json - mockURL: /mock/unstoppabledomains/api/v1/dpantani.zil - method: GET - extURL: https://unstoppabledomains.com/api/v1/dpantani.zil -- file: mock/ext-api-data/unstoppabledomains_api_v1__dpantani.crypto.json - mockURL: /mock/unstoppabledomains/api/v1/dpantani.crypto - method: GET - extURL: https://unstoppabledomains.com/api/v1/dpantani.crypto - file: mock/ext-api-data/vechain-api_blocks_best.json mockURL: /mock/vechain-api/blocks/best method: GET diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 7b723220e..2af180ba3 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -57,11 +57,6 @@ type ( GetCollectibles(owner, collectibleID string) (CollectiblePage, error) } - NamingServiceAPI interface { - CanHandle(name string) bool - Lookup(coins []uint64, name string) ([]Resolved, error) - } - Platforms map[string]Platform CollectionsAPIs map[uint]CollectionsAPI diff --git a/pkg/naming/naming.go b/pkg/naming/naming.go deleted file mode 100644 index 63c47aabb..000000000 --- a/pkg/naming/naming.go +++ /dev/null @@ -1,14 +0,0 @@ -package naming - -import ( - "strings" -) - -func GetTopDomain(name, separator string) string { - lastIdx := strings.LastIndex(name, separator) - if lastIdx < 0 || lastIdx >= len(name)-1 { - return "" - } - // return tail including separator - return strings.ToLower(name[lastIdx:]) -} diff --git a/pkg/naming/naming_test.go b/pkg/naming/naming_test.go deleted file mode 100644 index c8de70705..000000000 --- a/pkg/naming/naming_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package naming - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGetTopDomain(t *testing.T) { - tests := []struct { - name, separator, wantTLD string - }{ - {"vitalik.eth", ".", ".eth"}, - {"vitalik.ETH", ".", ".eth"}, - {"vitalik.ens", ".", ".ens"}, - {"ourxyzwallet.xyz", ".", ".xyz"}, - {"Cameron.Kred", ".", ".kred"}, - {"btc.zil", ".", ".zil"}, - {"btc.crypto", ".", ".crypto"}, - {"nick@fiotestnet", "@", "@fiotestnet"}, - {"a", ".", ""}, - {"a.", ".", ""}, - {"a.b", ".", ".b"}, - {"a@b.c", ".", ".c"}, - {"a@b.c", "@", "@b.c"}, - } - for _, tt := range tests { - result := GetTopDomain(tt.name, tt.separator) - assert.Equal(t, tt.wantTLD, result) - } -} diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index 11eea4f1a..4974b2e88 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -4,7 +4,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/ethereum/blockbook" "github.com/trustwallet/blockatlas/platform/ethereum/collection" - "github.com/trustwallet/blockatlas/platform/ethereum/ens" "github.com/trustwallet/blockatlas/platform/ethereum/trustray" "github.com/trustwallet/golibs/coin" ) @@ -14,14 +13,12 @@ type Platform struct { RpcURL string client EthereumClient collectible collection.Client - ens ens.RpcClient } func Init(coinType uint, api, rpc string) *Platform { return &Platform{ CoinIndex: coinType, RpcURL: rpc, - ens: ens.RpcClient{Request: blockatlas.InitJSONClient(rpc)}, client: &trustray.Client{Request: blockatlas.InitClient(api)}, } } @@ -30,12 +27,11 @@ func InitWithBlockbook(coinType uint, blockbookApi, rpc string) *Platform { return &Platform{ CoinIndex: coinType, RpcURL: rpc, - ens: ens.RpcClient{Request: blockatlas.InitJSONClient(rpc)}, client: &blockbook.Client{Request: blockatlas.InitClient(blockbookApi)}, } } -func InitWitCollection(coinType uint, api, rpc, blockbookApi, collectionApi, collectionKey string) *Platform { +func InitWitCollection(coinType uint, rpc, blockbookApi, collectionApi, collectionKey string) *Platform { platform := InitWithBlockbook(coinType, blockbookApi, rpc) platform.collectible = collection.Client{Request: blockatlas.InitClient(collectionApi)} platform.collectible.Headers["X-API-KEY"] = collectionKey diff --git a/platform/ethereum/domain.go b/platform/ethereum/domain.go deleted file mode 100644 index 7ff5c17b5..000000000 --- a/platform/ethereum/domain.go +++ /dev/null @@ -1,72 +0,0 @@ -package ethereum - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/pkg/naming" - "github.com/trustwallet/blockatlas/platform/ethereum/ens" - "github.com/trustwallet/ens-coincodec" - "github.com/trustwallet/golibs/coin" -) - -func (p *Platform) CanHandle(name string) bool { - switch naming.GetTopDomain(name, ".") { - case ".eth": - return true - case ".xyz": - return true - case ".luxe": - return true - case ".kred": - return true - } - return false -} - -func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { - var result []blockatlas.Resolved - node, err := ens.NameHash(name) - if err != nil { - return result, errors.E(err, "name hash failed") - } - for _, coin := range coins { - resolver, err := p.ens.Resolver(node[:]) - if err != nil { - return result, errors.E(err, "query resolver failed") - } - // try to get multi coin address - address, err := p.addressForCoin("0x"+resolver, node[:], coin) - if err != nil { - logger.Error(errors.E(err, errors.Params{"coin": coin, "name": name})) - continue - } - result = append(result, blockatlas.Resolved{Coin: coin, Result: address}) - } - - return result, nil -} - -func (p *Platform) addressForCoin(resovler string, node []byte, coinID uint64) (string, error) { - result, err := p.ens.Addr(resovler, node, coinID) - if err != nil { - if coinID == coin.ETH { - // user may not set multi coin address - result, err := p.lookupLegacyETH(resovler, node) - if err != nil { - return "", errors.E(err, "query legacy address failed") - } - return result, nil - } - return "", errors.E(err, "query multi coin address failed") - } - encoded, err := coincodec.ToString(result, uint32(coinID)) - if err != nil { - return "", errors.E(err, "encode to address failed") - } - return encoded, nil -} - -func (p *Platform) lookupLegacyETH(resolver string, node []byte) (string, error) { - return p.ens.LegacyAddr(resolver, node) -} diff --git a/platform/ethereum/domain_test.go b/platform/ethereum/domain_test.go deleted file mode 100644 index 3bddce29b..000000000 --- a/platform/ethereum/domain_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package ethereum - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestCanHandle(t *testing.T) { - tests := []struct { - name string - want bool - }{ - {"vitalik.eth", true}, - {"vitalik.xyz", true}, - {"vitalik.luxe", true}, - {"vitalik.kred", true}, - {"vitalik.ETH", true}, - {"vitalik.Eth", true}, - {"vitalik.wrongdomain", false}, - {"v.eth", true}, - {".eth", true}, - {"vitalik", false}, - {"vitalik.", false}, - } - p := Init(0, "", "") - for _, tt := range tests { - res := p.CanHandle(tt.name) - assert.Equal(t, tt.want, res) - } -} diff --git a/platform/ethereum/ens/ens_client.go b/platform/ethereum/ens/ens_client.go deleted file mode 100644 index 3b50cf951..000000000 --- a/platform/ethereum/ens/ens_client.go +++ /dev/null @@ -1,84 +0,0 @@ -package ens - -import ( - "encoding/hex" - - "github.com/trustwallet/blockatlas/pkg/address" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" -) - -const ( - registry = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" -) - -type RpcClient struct { - blockatlas.Request -} - -func (c *RpcClient) EthCall(params []interface{}) (string, error) { - var res string - err := c.RpcCall(&res, "eth_call", params) - if err != nil { - return "", err - } - return res, nil -} - -func (c *RpcClient) toParams(to string, data []byte) []interface{} { - return []interface{}{ - map[string]interface{}{ - "to": to, - "data": "0x" + hex.EncodeToString(data), - }, - "latest", - } -} - -func (c *RpcClient) Resolver(node []byte) (string, error) { - data := encodeResolver(node) - params := c.toParams(registry, data) - result, err := c.EthCall(params) - if err != nil { - return "", err - } - if allZero(address.Remove0x(result)) { - return "", errors.E("unregistered name or resolver not set") - } - if len(result) < 40 { - return "", errors.E("invalid address length") - } - return result[len(result)-40:], nil -} - -func (c *RpcClient) Addr(resolver string, node []byte, coin uint64) ([]byte, error) { - data := encodeAddr(node, coin) - params := c.toParams(resolver, data) - result, err := c.EthCall(params) - if err != nil { - return nil, err - } - if len(result) < 32 { - return nil, errors.E("invalid result length") - } - return decodeBytesInHex(result), nil -} - -func (c *RpcClient) LegacyAddr(resolver string, node []byte) (string, error) { - data := encodeLegacyAddr(node) - params := c.toParams(resolver, data) - result, err := c.EthCall(params) - if err != nil || len(result) < 40 { - return "", err - } - return address.EIP55Checksum(result[len(result)-40:]), nil -} - -func allZero(s string) bool { - for _, v := range s { - if v != '0' { - return false - } - } - return true -} diff --git a/platform/ethereum/ens/ens_encoder.go b/platform/ethereum/ens/ens_encoder.go deleted file mode 100644 index e3be9aa3f..000000000 --- a/platform/ethereum/ens/ens_encoder.go +++ /dev/null @@ -1,86 +0,0 @@ -package ens - -import ( - "bytes" - "encoding/binary" - "encoding/hex" - "math/big" - "strings" - - "golang.org/x/crypto/sha3" -) - -func encodeResolver(node []byte) []byte { - data := make([]byte, 0, 36) - signature := encodeFunc("resolver(bytes32)") - data = append(data, signature...) - data = append(data, node[:]...) - return data -} - -func encodeAddr(node []byte, coinType uint64) []byte { - data := make([]byte, 0, 68) - signature := encodeFunc("addr(bytes32,uint256)") - data = append(data, signature...) - data = append(data, node...) - data = append(data, encodeCoinType(coinType)...) - return data -} - -func encodeSupportsInterface(id []byte) []byte { - data := make([]byte, 0, 8) - signature := encodeFunc("supportsInterface(bytes4)") - data = append(data, signature...) - data = append(data, id[:4]...) - return data -} - -func encodeLegacyAddr(node []byte) []byte { - data := make([]byte, 0, 36) - signature := encodeFunc("addr(bytes32)") - data = append(data, signature...) - data = append(data, node...) - return data -} - -func encodeFunc(fn string) []byte { - data := make([]byte, 0, 32) - sha := sha3.NewLegacyKeccak256() - if _, err := sha.Write([]byte(fn)); err != nil { - return data - } - sha.Sum(data) - return data[:4] -} - -func encodeCoinType(i uint64) []byte { - data := make([]byte, 24) - buf := new(bytes.Buffer) - err := binary.Write(buf, binary.BigEndian, i) - if err != nil { - return data - } - data = append(data, buf.Bytes()...) - return data -} - -func decodeBytesInHex(s string) []byte { - if strings.HasPrefix(s, "0x") { - s = strings.TrimPrefix(s, "0x") - } - bytes, err := hex.DecodeString(s) - if err != nil || len(bytes) < 32 { - return []byte{} - } - return decodeBytes(bytes) -} - -func decodeBytes(b []byte) []byte { - offset := int64(32) - count := new(big.Int) - count.SetBytes(b[:offset]) - length := new(big.Int) - length.SetBytes(b[offset : offset+count.Int64()]) - offset += count.Int64() - return b[offset : offset+length.Int64()] -} diff --git a/platform/ethereum/ens/ens_encoder_test.go b/platform/ethereum/ens/ens_encoder_test.go deleted file mode 100644 index 0fade67dd..000000000 --- a/platform/ethereum/ens/ens_encoder_test.go +++ /dev/null @@ -1,193 +0,0 @@ -package ens - -import ( - "encoding/hex" - "reflect" - "testing" -) - -func Test_encodeResolver(t *testing.T) { - tests := []struct { - name string - node string - want string - }{ - { - "Test ohmyname.eth resolver", - "5ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6", - "0178b8bf5ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - node, _ := hex.DecodeString(tt.node) - want, _ := hex.DecodeString(tt.want) - if got := encodeResolver(node[:]); !reflect.DeepEqual(got, want) { - t.Errorf("encodeResolver() = %v, want %v", hex.EncodeToString(got), tt.want) - } - }) - } -} - -func Test_encodeAddr(t *testing.T) { - type args struct { - node string - coinType uint64 - } - tests := []struct { - name string - args args - want string - }{ - { - "Test encodeAddr", - args{ - "5ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6", - 60, - }, - "f1cb7e065ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6000000000000000000000000000000000000000000000000000000000000003c", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - node, _ := hex.DecodeString(tt.args.node) - want, _ := hex.DecodeString(tt.want) - if got := encodeAddr(node, tt.args.coinType); !reflect.DeepEqual(got, want) { - t.Errorf("encodeAddr() = %v, want %v", hex.EncodeToString(got), tt.want) - } - }) - } -} - -func Test_encodeSupportsInterface(t *testing.T) { - tests := []struct { - name string - id string - want string - }{ - { - "Test encodeSupportsInterface", - "3b3b57de", - "01ffc9a73b3b57de", - }, - { - "Test encodeSupportsInterface", - "f1cb7e06", - "01ffc9a7f1cb7e06", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - id, _ := hex.DecodeString(tt.id) - want, _ := hex.DecodeString(tt.want) - if got := encodeSupportsInterface(id); !reflect.DeepEqual(got, want) { - t.Errorf("encodeSupportsInterface() = %v, want %v", hex.EncodeToString(got), tt.want) - } - }) - } -} - -func Test_encodeLegacyAddr(t *testing.T) { - tests := []struct { - name string - node string - want string - }{ - { - "Test encodeLegacyAddr", - "5ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6", - "3b3b57de5ddd0923ace8fe255c0971f8e60d7cd400ae734142a13c14d29a87deb87cdac6", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - node, _ := hex.DecodeString(tt.node) - want, _ := hex.DecodeString(tt.want) - if got := encodeLegacyAddr(node); !reflect.DeepEqual(got, want) { - t.Errorf("encodeLegacyAddr() = %v, want %v", hex.EncodeToString(got), tt.want) - } - }) - } -} - -func Test_encodeFunc(t *testing.T) { - tests := []struct { - name string - fn string - want string - }{ - { - "Test resolver", - "resolver(bytes32)", - "0178b8bf", - }, - { - "Test addr", - "addr(bytes32,uint256)", - "f1cb7e06", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - want, _ := hex.DecodeString(tt.want) - if got := encodeFunc(tt.fn); !reflect.DeepEqual(got, want) { - t.Errorf("encodeFunc() = %v, want %v", hex.EncodeToString(got), tt.want) - } - }) - } -} - -func Test_encodeCoinType(t *testing.T) { - tests := []struct { - name string - coin uint64 - want string - }{ - { - "Test Ethereum", - uint64(60), - "000000000000000000000000000000000000000000000000000000000000003c", - }, - { - "Test Bitcoin", - uint64(0), - "0000000000000000000000000000000000000000000000000000000000000000", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - want, _ := hex.DecodeString(tt.want) - if got := encodeCoinType(tt.coin); !reflect.DeepEqual(got, want) { - t.Errorf("encodeCoinType() = %v, want %v", hex.EncodeToString(got), tt.want) - } - }) - } -} - -func Test_decodeBytes(t *testing.T) { - tests := []struct { - name string - bytes string - want string - }{ - { - "Test decode bytes", - "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014c36edf48e21cf395b206352a1819de658fd7f988000000000000000000000000", - "c36edf48e21cf395b206352a1819de658fd7f988", - }, - { - "Test decode bytes 2", - "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000160014b3df10c6941f4a949f1183281844c3a210cba1e200000000000000000000", - "0014b3df10c6941f4a949f1183281844c3a210cba1e2", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - bytes, _ := hex.DecodeString(tt.bytes) - want, _ := hex.DecodeString(tt.want) - if got := decodeBytes(bytes); !reflect.DeepEqual(got, want) { - t.Errorf("decodeBytes() = %v, want %v", hex.EncodeToString(got), tt.want) - } - }) - } -} diff --git a/platform/ethereum/ens/namehash.go b/platform/ethereum/ens/namehash.go deleted file mode 100644 index ff6abc6cc..000000000 --- a/platform/ethereum/ens/namehash.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2017 Weald Technology Trading -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ens - -import ( - "strings" - - "golang.org/x/net/idna" - - "golang.org/x/crypto/sha3" -) - -var p = idna.New(idna.MapForLookup(), idna.StrictDomainName(false), idna.Transitional(false)) - -// Normalize normalizes a name according to the ENS rules -func Normalize(input string) (output string, err error) { - output, err = p.ToUnicode(input) - if err != nil { - return - } - // If the name started with a period then ToUnicode() removes it, but we want to keep it - if strings.HasPrefix(input, ".") && !strings.HasPrefix(output, ".") { - output = "." + output - } - return -} - -// LabelHash generates a simple hash for a piece of a name. -func LabelHash(label string) (hash [32]byte, err error) { - normalizedLabel, err := Normalize(label) - if err != nil { - return - } - - sha := sha3.NewLegacyKeccak256() - if _, err = sha.Write([]byte(normalizedLabel)); err != nil { - return - } - sha.Sum(hash[:0]) - return -} - -// NameHash generates a hash from a name that can be used to -// look up the name in ENS -func NameHash(name string) (hash [32]byte, err error) { - if name == "" { - return - } - normalizedName, err := Normalize(name) - if err != nil { - return - } - parts := strings.Split(normalizedName, ".") - for i := len(parts) - 1; i >= 0; i-- { - if hash, err = nameHashPart(hash, parts[i]); err != nil { - return - } - } - return -} - -func nameHashPart(currentHash [32]byte, name string) (hash [32]byte, err error) { - sha := sha3.NewLegacyKeccak256() - if _, err = sha.Write(currentHash[:]); err != nil { - return - } - nameSha := sha3.NewLegacyKeccak256() - if _, err = nameSha.Write([]byte(name)); err != nil { - return - } - nameHash := nameSha.Sum(nil) - if _, err = sha.Write(nameHash); err != nil { - return - } - sha.Sum(hash[:0]) - return -} diff --git a/platform/ethereum/ens/namehash_test.go b/platform/ethereum/ens/namehash_test.go deleted file mode 100644 index 8012c3a7e..000000000 --- a/platform/ethereum/ens/namehash_test.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2017 Weald Technology Trading -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ens - -import ( - "encoding/hex" - "testing" -) - -func TestNameHash(t *testing.T) { - tests := []struct { - input string - output string - err error - }{ - {"", "0000000000000000000000000000000000000000000000000000000000000000", nil}, - {"eth", "93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae", nil}, - {"Eth", "93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae", nil}, - {".eth", "8cc9f31a5e7af6381efc751d98d289e3f3589f1b6f19b9b989ace1788b939cf7", nil}, - {"resolver.eth", "fdd5d5de6dd63db72bbc2d487944ba13bf775b50a80805fe6fcaba9b0fba88f5", nil}, - {"foo.eth", "de9b09fd7c5f901e23a3f19fecc54828e9c848539801e86591bd9801b019f84f", nil}, - {"Foo.eth", "de9b09fd7c5f901e23a3f19fecc54828e9c848539801e86591bd9801b019f84f", nil}, - {"foo..eth", "4143a5b2f547838d3b49982e3f2ec6a26415274e5b9c3ffeb21971bbfdfaa052", nil}, - {"bar.foo.eth", "275ae88e7263cdce5ab6cf296cdd6253f5e385353fe39cfff2dd4a2b14551cf3", nil}, - {"Bar.foo.eth", "275ae88e7263cdce5ab6cf296cdd6253f5e385353fe39cfff2dd4a2b14551cf3", nil}, - {"addr.reverse", "91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2", nil}, - } - - for _, tt := range tests { - result, err := NameHash(tt.input) - if tt.err == nil { - if err != nil { - t.Fatalf("unexpected error %v", err) - } - if tt.output != hex.EncodeToString(result[:]) { - t.Errorf("Failure: %v => %v (expected %v)\n", tt.input, hex.EncodeToString(result[:]), tt.output) - } - } else { - if err == nil { - t.Fatalf("missing expected error") - } - if tt.err.Error() != err.Error() { - t.Errorf("unexpected error value %v", err) - } - } - } -} - -func TestLabelHash(t *testing.T) { - tests := []struct { - input string - output string - err error - }{ - {"", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", nil}, - {"eth", "4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0", nil}, - {"foo", "41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d", nil}, - } - - for _, tt := range tests { - output, err := LabelHash(tt.input) - if tt.err == nil { - if err != nil { - t.Fatalf("unexpected error %v", err) - } - if tt.output != hex.EncodeToString(output[:]) { - t.Errorf("Failure: %v => %v (expected %v)\n", tt.input, hex.EncodeToString(output[:]), tt.output) - } - } else { - if err == nil { - t.Fatalf("missing expected error") - } - if tt.err.Error() != err.Error() { - t.Errorf("unexpected error value %v", err) - } - } - } -} diff --git a/platform/fio/client.go b/platform/fio/client.go index 3a0299a9a..d809f52b7 100644 --- a/platform/fio/client.go +++ b/platform/fio/client.go @@ -23,15 +23,3 @@ func (c *Client) getTransactions(account string) (actions []Action, error error) } return res.Actions, nil } - -func (c *Client) lookupPubAddress(name string, coinSymbol string) (address string, error error) { - var res GetPubAddressResponse - err := c.Post(&res, "v1/chain/get_pub_address", GetPubAddressRequest{FioAddress: name, TokenCode: coinSymbol, ChainCode: coinSymbol}) - if err != nil { - return "", errors.E(err, "Error looking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": err.Error()}) - } - if res.Message != "" { - return "", errors.E("Error looking up FIO name", errors.Params{"name": name, "coinSymbol": coinSymbol, "inner_error": res.Message}) - } - return res.PublicAddress, nil -} diff --git a/platform/fio/domain.go b/platform/fio/domain.go deleted file mode 100644 index 389405e45..000000000 --- a/platform/fio/domain.go +++ /dev/null @@ -1,40 +0,0 @@ -package fio - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/naming" - "github.com/trustwallet/golibs/coin" -) - -func (p *Platform) CanHandle(name string) bool { - domain := naming.GetTopDomain(name, "@") - if len(domain) == 0 { - return false - } - switch domain { - case "@trust": - return true - case "@trustwallet": - return true - case "@binance": - return true - case "@fiomembers": - return true - } - // we match any @xxx domain! - return len(domain) >= 2 -} - -func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { - var result []blockatlas.Resolved - for _, coinId := range coins { - coinObj := coin.Coins[uint(coinId)] - address, err := p.client.lookupPubAddress(name, coinObj.Symbol) - if err != nil { - return result, err - } - result = append(result, blockatlas.Resolved{Coin: coinId, Result: address}) - } - - return result, nil -} diff --git a/platform/fio/domain_test.go b/platform/fio/domain_test.go deleted file mode 100644 index 4681f844c..000000000 --- a/platform/fio/domain_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package fio - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestCanHandle(t *testing.T) { - tests := []struct { - name string - want bool - }{ - {"vitalik@trust", true}, - {"vitalik@trustwallet", true}, - {"vitalik@binance", true}, - {"vitalik@fiomembers", true}, - {"vitalik@TRUST", true}, - {"vitalik@Trust", true}, - {"vitalik@somedomain", true}, - {"vitalik@x", true}, - {"v@trust", true}, - {"@trust", true}, - {"vitalik", false}, - {"vitalik@", false}, - } - p := Init("") - for _, tt := range tests { - res := p.CanHandle(tt.name) - assert.Equal(t, tt.want, res) - } -} diff --git a/platform/platform.go b/platform/platform.go index 7b0aca24c..370141b5f 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -81,7 +81,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Solana().Handle: solana.Init(GetApiVar(coin.SOL)), coin.Tezos().Handle: tezos.Init(GetApiVar(coin.XTZ), GetRpcVar(coin.XTZ)), coin.Binance().Handle: binance.Init(GetApiVar(coin.BNB)), - coin.Zilliqa().Handle: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL), GetVar("zilliqa.lookup")), + coin.Zilliqa().Handle: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL)), coin.Kusama().Handle: polkadot.Init(coin.KSM, GetApiVar(coin.KSM)), coin.Polkadot().Handle: polkadot.Init(coin.DOT, GetApiVar(coin.DOT)), coin.Stellar().Handle: stellar.Init(coin.XLM, GetApiVar(coin.XLM)), @@ -111,7 +111,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), coin.Bsc().Handle: ethereum.InitWithBlockbook(coin.BSCLegacy, GetApiVar(coin.BSCLegacy), GetRpcVar(coin.BSCLegacy)), coin.Smartchain().Handle: ethereum.InitWithBlockbook(coin.BSC, GetApiVar(coin.BSC), GetRpcVar(coin.BSC)), - coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), + coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), coin.Near().Handle: near.Init(GetApiVar(coin.NEAR)), coin.Elrond().Handle: elrond.Init(coin.ERD, GetApiVar(coin.ERD)), coin.Filecoin().Handle: filecoin.Init(GetApiVar(coin.FIL)), @@ -120,14 +120,6 @@ func getAllHandlers() blockatlas.Platforms { func getCollectionsHandlers() blockatlas.CollectionsAPIs { return blockatlas.CollectionsAPIs{ - coin.ETH: ethereum.InitWitCollection(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), - } -} - -func getNamingHandlers() map[uint]blockatlas.NamingServiceAPI { - return map[uint]blockatlas.NamingServiceAPI{ - coin.ETH: ethereum.Init(coin.ETH, GetApiVar(coin.ETH), GetRpcVar(coin.ETH)), - coin.FIO: fio.Init(GetApiVar(coin.FIO)), - coin.ZIL: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL), GetVar("zilliqa.lookup")), + coin.ETH: ethereum.InitWitCollection(coin.ETH, GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), } } diff --git a/platform/registry.go b/platform/registry.go index 9dc4280c7..88313bf10 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -2,6 +2,7 @@ package platform import ( "fmt" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" @@ -22,9 +23,6 @@ var ( // CollectionsAPIs contain platforms which collections services CollectionsAPIs blockatlas.CollectionsAPIs - - // NamingAPIs contain platforms which support naming services - NamingAPIs map[uint]blockatlas.NamingServiceAPI ) func getActivePlatforms(handles []string) []blockatlas.Platform { @@ -90,5 +88,4 @@ func Init(platformHandles []string) { } CollectionsAPIs = getCollectionsHandlers() - NamingAPIs = getNamingHandlers() } diff --git a/platform/zilliqa/base.go b/platform/zilliqa/base.go index 61daa8580..34ccbd5a0 100644 --- a/platform/zilliqa/base.go +++ b/platform/zilliqa/base.go @@ -8,14 +8,12 @@ import ( type Platform struct { client Client rpcClient RpcClient - udClient Client } -func Init(api, apiKey, rpc, udClient string) *Platform { +func Init(api, apiKey, rpc string) *Platform { p := &Platform{ client: Client{blockatlas.InitClient(api)}, rpcClient: RpcClient{blockatlas.InitClient(rpc)}, - udClient: Client{blockatlas.InitClient(udClient)}, } p.client.Headers["X-APIKEY"] = apiKey return p diff --git a/platform/zilliqa/client.go b/platform/zilliqa/client.go index ca2fb6724..33295dd0a 100644 --- a/platform/zilliqa/client.go +++ b/platform/zilliqa/client.go @@ -15,8 +15,3 @@ func (c *Client) GetTxsOfAddress(address string) (tx []Tx, err error) { err = c.Get(&tx, path, nil) return } - -func (c *Client) LookupName(name string) (response ZNSResponse, err error) { - err = c.Get(&response, "/"+name, nil) - return -} diff --git a/platform/zilliqa/domain.go b/platform/zilliqa/domain.go deleted file mode 100644 index 40b3001c3..000000000 --- a/platform/zilliqa/domain.go +++ /dev/null @@ -1,38 +0,0 @@ -package zilliqa - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/naming" - "github.com/trustwallet/golibs/coin" -) - -type ZNSResponse struct { - Addresses map[string]string -} - -func (p *Platform) CanHandle(name string) bool { - switch naming.GetTopDomain(name, ".") { - case ".zil": - return true - case ".crypto": - return true - } - return false -} - -func (p *Platform) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { - var result []blockatlas.Resolved - resp, err := p.udClient.LookupName(name) - if err != nil { - return result, err - } - for _, c := range coins { - symbol := coin.Coins[uint(c)].Symbol - address := resp.Addresses[symbol] - if len(address) == 0 { - continue - } - result = append(result, blockatlas.Resolved{Coin: c, Result: address}) - } - return result, nil -} diff --git a/platform/zilliqa/domain_test.go b/platform/zilliqa/domain_test.go deleted file mode 100644 index 7ce4a3dab..000000000 --- a/platform/zilliqa/domain_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package zilliqa - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestCanHandle(t *testing.T) { - tests := []struct { - name string - want bool - }{ - {"vitalik.zil", true}, - {"vitalik.crypto", true}, - {"vitalik.ZIL", true}, - {"vitalik.Zil", true}, - {"vitalik.wrongdomain", false}, - {"v.zil", true}, - {".zil", true}, - {"vitalik", false}, - {"vitalik.", false}, - } - p := Init("", "", "", "") - for _, tt := range tests { - res := p.CanHandle(tt.name) - assert.Equal(t, tt.want, res) - } -} diff --git a/scripts/run_tests_postman.sh b/scripts/run_tests_postman.sh index e18f11401..0ca3499c5 100644 --- a/scripts/run_tests_postman.sh +++ b/scripts/run_tests_postman.sh @@ -7,5 +7,4 @@ make newman test=transaction host=$HOST make newman test=token host=$1 make newman test=staking host=$1 make newman test=collection host=$1 -make newman test=domain host=$1 make newman test=observer_test host=$1 diff --git a/services/domains/domains.go b/services/domains/domains.go deleted file mode 100644 index 5421d2818..000000000 --- a/services/domains/domains.go +++ /dev/null @@ -1,33 +0,0 @@ -package domains - -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/platform" -) - -func HandleLookup(name string, coins []uint64) ([]blockatlas.Resolved, error) { - addresses := make([]blockatlas.Resolved, 0) - apis := findHandlerApis(name, platform.NamingAPIs) - if len(apis) == 0 { - return nil, errors.E("platform not found", errors.Params{"name": name, "coins": coins}) - } - for _, api := range apis { - provAddresses, err := api.Lookup(coins, name) - if err != nil { - return nil, errors.E(err, "name format not recognized", errors.Params{"name": name, "coins": coins}) - } - addresses = append(addresses, provAddresses...) - } - return addresses, nil -} - -func findHandlerApis(name string, allApis map[uint]blockatlas.NamingServiceAPI) []blockatlas.NamingServiceAPI { - apis := []blockatlas.NamingServiceAPI{} - for _, api := range allApis { - if api.CanHandle(name) { - apis = append(apis, api) - } - } - return apis -} diff --git a/services/domains/domains_test.go b/services/domains/domains_test.go deleted file mode 100644 index 8539e5d0a..000000000 --- a/services/domains/domains_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package domains - -import ( - "testing" - - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/naming" -) - -type ( - ProviderOne struct{} - ProviderTwo struct{} -) - -func (p *ProviderOne) CanHandle(name string) bool { - domain := naming.GetTopDomain(name, ".") - return domain == ".one" || domain == ".zero" -} - -func (p *ProviderOne) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { - return []blockatlas.Resolved{}, nil -} - -func (p *ProviderTwo) CanHandle(name string) bool { - domain := naming.GetTopDomain(name, ".") - return domain == ".two" || domain == ".zero" -} - -func (p *ProviderTwo) Lookup(coins []uint64, name string) ([]blockatlas.Resolved, error) { - return []blockatlas.Resolved{}, nil -} - -func setupProviders() map[uint]blockatlas.NamingServiceAPI { - return map[uint]blockatlas.NamingServiceAPI{ - 1: &ProviderOne{}, - 2: &ProviderTwo{}, - } -} - -func TestFindHandlerApis(t *testing.T) { - tests := []struct { - name string - wantCount int - }{ - { - name: "user.one", - wantCount: 1, - }, - { - name: "user.two", - wantCount: 1, - }, - { - name: "user.NOSUCHDOMAIN", - wantCount: 0, - }, - { - name: "user.zero", - wantCount: 2, - }, - { - name: "user.ONE", - wantCount: 1, - }, - } - allApis := setupProviders() - for _, tt := range tests { - res := findHandlerApis(tt.name, allApis) - if len(res) != tt.wantCount { - t.Errorf("Wrong answer %v %v %v", tt.name, len(res), tt.wantCount) - } - } -} diff --git a/tests/postman/blockatlas.postman_collection.json b/tests/postman/blockatlas.postman_collection.json index 869859918..fa8eed6ea 100644 --- a/tests/postman/blockatlas.postman_collection.json +++ b/tests/postman/blockatlas.postman_collection.json @@ -1241,222 +1241,6 @@ ], "protocolProfileBehavior": {}, "_postman_isSubFolder": true - }, - { - "name": "domain", - "item": [ - { - "name": "v2/ns/lookup", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "7312c9e7-5330-421a-9ca8-171101050e38", - "exec": [ - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "acec8baa-0ef0-4703-ab83-c555260deffa", - "exec": [ - "var Ajv = require('ajv');", - "var ajv = new Ajv({logger: console});", - "let schema = {", - " \"type\": \"array\",", - " \"minItems\": 1,", - " \"uniqueItems\": true,", - " \"items\": {", - " \"type\": \"object\",", - " \"properties\": {", - " \"result\": {", - " \"type\": \"string\"", - " },", - " \"coin\": {", - " \"type\": \"integer\"", - " }", - " }", - " }", - "};", - "", - "let domain = pm.variables.get(\"domain\");", - "let coins = pm.variables.get(\"coins\");", - "let address = pm.variables.get(\"address\");", - "var jsonData = pm.response.json();", - "var result = jsonData[0];", - "", - "pm.test(domain + \" - response must be valid and have a body\", function () {", - " pm.response.to.have.status(200);", - " pm.response.to.be.ok;", - " pm.response.to.not.be.error;", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "", - "pm.test(domain + \" - schema is valid\", function() {", - " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", - "});", - "", - "pm.test(domain + \" - address is valid: \" + address, function() {", - " pm.expect(result.result).to.eql(address);", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{platform_auth}}", - "type": "text" - } - ], - "url": { - "raw": "{{host}}/v2/ns/lookup?name={{domain}}&coins={{coins}}", - "host": [ - "{{host}}" - ], - "path": [ - "v2", - "ns", - "lookup" - ], - "query": [ - { - "key": "name", - "value": "{{domain}}" - }, - { - "key": "coins", - "value": "{{coins}}" - } - ] - } - }, - "response": [] - }, - { - "name": "ns/lookup", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "7312c9e7-5330-421a-9ca8-171101050e38", - "exec": [ - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "acec8baa-0ef0-4703-ab83-c555260deffa", - "exec": [ - "var Ajv = require('ajv');", - "var ajv = new Ajv({logger: console});", - "let schema = {", - " \"type\": \"object\",", - " \"properties\": {", - " \"result\": {", - " \"type\": \"string\"", - " },", - " \"coin\": {", - " \"type\": \"integer\"", - " }", - " }", - "};", - "", - "let domain = pm.variables.get(\"domain\");", - "let coins = pm.variables.get(\"coins\");", - "let address = pm.variables.get(\"address\");", - "var jsonData = pm.response.json();", - "", - "pm.test(domain + \" - response must be valid and have a body\", function () {", - " pm.response.to.have.status(200);", - " pm.response.to.be.ok;", - " pm.response.to.not.be.error;", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "", - "pm.test(domain + \" - schema is valid\", function() {", - " pm.expect(ajv.validate(schema, jsonData)).to.be.true;", - "});", - "", - "pm.test(domain + \" - address is valid: \" + address, function() {", - " pm.expect(jsonData.result).to.eql(address);", - "});", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{platform_auth}}", - "type": "text" - } - ], - "url": { - "raw": "{{host}}/ns/lookup?name={{domain}}&coin={{coins}}", - "host": [ - "{{host}}" - ], - "path": [ - "ns", - "lookup" - ], - "query": [ - { - "key": "name", - "value": "{{domain}}" - }, - { - "key": "coin", - "value": "{{coins}}" - } - ] - } - }, - "response": [] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "id": "1f5cb578-ecc3-4130-8d9b-68df6e576e63", - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "id": "7e7d99e8-d11d-4660-ad03-cff2454e9d1f", - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ], - "protocolProfileBehavior": {}, - "_postman_isSubFolder": true } ], "event": [ @@ -2162,4 +1946,4 @@ } ], "protocolProfileBehavior": {} -} \ No newline at end of file +} diff --git a/tests/postman/domain_data.json b/tests/postman/domain_data.json deleted file mode 100644 index 85b7ee26b..000000000 --- a/tests/postman/domain_data.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "domain": "vitalik.eth", - "coins": [ - 60 - ], - "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" - }, - { - "domain": "vitalik.luxe", - "coins": [ - 60 - ], - "address": "0xD8A667312D5260F12a306Ae7730C754d938da86c" - }, - { - "domain": "ourxyzwallet.xyz", - "coins": [ - 60 - ], - "address": "0x0C54eEAd78d555bE3cbCD451424F9A27a7843935" - }, - { - "domain": "dpantani.zil", - "coins": [ - 313 - ], - "address": "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64" - }, - { - "domain": "dpantani.crypto", - "coins": [ - 313 - ], - "address": "zil1vdntvlk47j9kh9a85klqcd9rvgze06ruhmna64" - }, - { - "domain": "trust@trust", - "coins": [ - 60 - ], - "address": "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a8F51" - }, - { - "domain": "trust@trustwallet", - "coins": [ - 60 - ], - "address": "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a0001" - }, - { - "domain": "name@somefiodomain", - "coins": [ - 60 - ], - "address": "0xce5cB6c92Da37bbBa91Bd40D4C9D4D724A3a0002" - } -] \ No newline at end of file From 6278902224aa2751ff9bdef97f1dc94c60983ac2 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Wed, 28 Oct 2020 14:53:37 +0300 Subject: [PATCH 401/506] [Indexer] Update api and db (#1262) * Update Indexer api - Add coin to db and as param to query - Use GET instead of POST * Fix tests * Add Swagger --- api/endpoint/token.go | 30 ++- api/registry.go | 2 +- config.yml | 2 +- db/asset.go | 13 +- db/models/asset.go | 1 + docs/docs.go | 194 ++++++++++------- docs/swagger.json | 196 +++++++++++------- docs/swagger.yaml | 144 ++++++++----- pkg/blockatlas/tx.go | 1 + services/tokenindexer/api.go | 2 +- services/tokenindexer/models.go | 1 + services/tokensearcher/association_test.go | 12 +- .../integration/db_test/tokenindexer_test.go | 32 +++ 13 files changed, 418 insertions(+), 212 deletions(-) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index c2b57f842..22ec72e3b 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -140,13 +140,35 @@ func GetTokensByAddressIndexer(c *gin.Context, instance tokensearcher.Instance) c.JSON(http.StatusOK, result) } +// @Description Get new tokens +// @ID tokens_new_v3 +// @Summary Get list of new tokens by coin from specific unix timstamp +// @Accept json +// @Produce json +// @Tags Transactions +// @Param from query int true "unix timestamp" +// @Param coin query int false "coin like 60" +// @Success 200 {object} tokenindexer.Response +// @Router /v3/tokens/new [get] func GetNewTokens(c *gin.Context, instance tokenindexer.Instance) { - var query tokenindexer.Request - if err := c.Bind(&query); err != nil { + var request tokenindexer.Request + fromRaw := c.Query("from") + coinRaw := c.DefaultQuery("coin", "-1") + + from, err := strconv.Atoi(fromRaw) + if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) - return } - resp, err := instance.HandleNewTokensRequest(query, c.Request.Context()) + + coin, err := strconv.Atoi(coinRaw) + if err != nil { + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) + } + + request.Coin = coin + request.From = int64(from) + + resp, err := instance.HandleNewTokensRequest(request, c.Request.Context()) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return diff --git a/api/registry.go b/api/registry.go index e4450911f..aae152ae1 100644 --- a/api/registry.go +++ b/api/registry.go @@ -112,7 +112,7 @@ func RegisterTokensSearcherAPI(router gin.IRouter, instance tokensearcher.Instan } func RegisterTokensIndexAPI(router gin.IRouter, instance tokenindexer.Instance) { - router.POST("/v3/tokens/new", func(c *gin.Context) { + router.GET("/v3/tokens/new", func(c *gin.Context) { endpoint.GetNewTokens(c, instance) }) } diff --git a/config.yml b/config.yml index 170eba090..28b29fc22 100644 --- a/config.yml +++ b/config.yml @@ -26,7 +26,7 @@ observer: # Amount of time between fetching blocks concurrently fetch_blocks_interval: 1ms # Don't request more than N blocks at once - backlog_max_blocks: 200 + backlog_max_blocks: 20 # Limit amount of transactions in batch txs_batch_limit: 3000 # Limit of push notifications in batch diff --git a/db/asset.go b/db/asset.go index db14c7e08..ddfe16729 100644 --- a/db/asset.go +++ b/db/asset.go @@ -101,12 +101,19 @@ func (i *Instance) GetAssetsByIDs(ids []string, ctx context.Context) ([]models.A return dbAssets, nil } -func (i *Instance) GetAssetsFrom(from time.Time, ctx context.Context) ([]models.Asset, error) { +func (i *Instance) GetAssetsFrom(from time.Time, coin int, ctx context.Context) ([]models.Asset, error) { db := i.Gorm.WithContext(ctx) var dbAssets []models.Asset - if err := db.Find(&dbAssets, "created_at > ?", from).Error; err != nil { - return nil, err + if coin == -1 { + if err := db.Find(&dbAssets, "created_at > ?", from).Error; err != nil { + return nil, err + } + } else { + if err := db.Find(&dbAssets, "created_at > ? and coin = ?", from, coin).Error; err != nil { + return nil, err + } } + return dbAssets, nil } diff --git a/db/models/asset.go b/db/models/asset.go index 5e323e2f9..a0c90b977 100644 --- a/db/models/asset.go +++ b/db/models/asset.go @@ -11,6 +11,7 @@ type Asset struct { Name string `gorm:"type:varchar(128)"` Symbol string `gorm:"type:varchar(128)"` Type string `gorm:"type:varchar(12)"` + Coin uint } func AssetIDs(assets []Asset) []string { diff --git a/docs/docs.go b/docs/docs.go index af7c1e4b6..507a28c29 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -19,6 +19,7 @@ var doc = `{ "description": "{{.Description}}", "title": "{{.Title}}", "contact": {}, + "license": {}, "version": "{{.Version}}" }, "host": "{{.Host}}", @@ -45,10 +46,7 @@ var doc = `{ "in": "body", "required": true, "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/api_endpoint.AddressBatchRequest" - } + "$ref": "#/definitions/endpoint.AddressesRequest" } } ], @@ -56,10 +54,7 @@ var doc = `{ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.DelegationResponse" - } + "$ref": "#/definitions/blockatlas.DelegationsBatchPage" } } } @@ -86,10 +81,7 @@ var doc = `{ "in": "body", "required": true, "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/api_endpoint.AddressBatchRequest" - } + "$ref": "#/definitions/endpoint.AddressesRequest" } } ], @@ -97,10 +89,7 @@ var doc = `{ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.DelegationResponse" - } + "$ref": "#/definitions/blockatlas.DelegationsBatchPage" } } } @@ -178,7 +167,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -226,7 +215,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -266,7 +255,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -308,16 +297,13 @@ var doc = `{ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Collection" - } + "$ref": "#/definitions/blockatlas.CollectionPage" } }, "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -359,7 +345,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -401,7 +387,7 @@ var doc = `{ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -433,17 +419,53 @@ var doc = `{ "schema": { "type": "array", "items": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.DelegationResponse" - } + "$ref": "#/definitions/blockatlas.DelegationsBatchPage" } } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" + } + } + } + } + }, + "/v3/tokens/new": { + "get": { + "description": "Get new tokens", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Transactions" + ], + "summary": "Get list of new tokens by coin from specific unix timstamp", + "operationId": "tokens_new_v3", + "parameters": [ + { + "type": "integer", + "description": "unix timestamp", + "name": "from", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "coin like 60", + "name": "coin", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/tokenindexer.Response" } } } @@ -529,16 +551,13 @@ var doc = `{ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Collection" - } + "$ref": "#/definitions/blockatlas.CollectionPage" } }, "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -546,33 +565,6 @@ var doc = `{ } }, "definitions": { - "api_endpoint.AddressBatchRequest": { - "type": "object", - "properties": { - "address": { - "type": "string" - }, - "coin": { - "type": "integer" - } - } - }, - "api_endpoint.ErrorDetails": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - } - }, - "api_endpoint.ErrorResponse": { - "type": "object", - "properties": { - "error": { - "$ref": "#/definitions/api_endpoint.ErrorDetails" - } - } - }, "blockatlas.Collection": { "type": "object", "properties": { @@ -602,10 +594,17 @@ var doc = `{ } } }, + "blockatlas.CollectionPage": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Collection" + } + }, "blockatlas.Delegation": { "type": "object", "properties": { "delegator": { + "type": "object", "$ref": "#/definitions/blockatlas.StakeValidator" }, "metadata": { @@ -629,19 +628,31 @@ var doc = `{ "type": "string" }, "coin": { + "type": "object", "$ref": "#/definitions/coin.ExternalCoin" }, "delegations": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Delegation" - } + "type": "object", + "$ref": "#/definitions/blockatlas.DelegationsPage" }, "details": { + "type": "object", "$ref": "#/definitions/blockatlas.StakingDetails" } } }, + "blockatlas.DelegationsBatchPage": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.DelegationResponse" + } + }, + "blockatlas.DelegationsPage": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Delegation" + } + }, "blockatlas.DocsResponse": { "type": "object", "properties": { @@ -665,12 +676,14 @@ var doc = `{ "type": "object", "properties": { "details": { + "type": "object", "$ref": "#/definitions/blockatlas.StakingDetails" }, "id": { "type": "string" }, "info": { + "type": "object", "$ref": "#/definitions/blockatlas.StakeValidatorInfo" }, "status": { @@ -705,6 +718,7 @@ var doc = `{ "type": "string" }, "reward": { + "type": "object", "$ref": "#/definitions/blockatlas.StakingReward" }, "type": { @@ -737,7 +751,7 @@ var doc = `{ } } }, - "github.com_trustwallet_blockatlas_api_endpoint.AddressBatchRequest": { + "endpoint.AddressBatchRequest": { "type": "object", "properties": { "address": { @@ -748,7 +762,13 @@ var doc = `{ } } }, - "github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails": { + "endpoint.AddressesRequest": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.AddressBatchRequest" + } + }, + "endpoint.ErrorDetails": { "type": "object", "properties": { "message": { @@ -756,11 +776,43 @@ var doc = `{ } } }, - "github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse": { + "endpoint.ErrorResponse": { "type": "object", "properties": { "error": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails" + "type": "object", + "$ref": "#/definitions/endpoint.ErrorDetails" + } + } + }, + "tokenindexer.Asset": { + "type": "object", + "properties": { + "asset": { + "type": "string" + }, + "decimals": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "symbol": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "tokenindexer.Response": { + "type": "object", + "properties": { + "assets": { + "type": "array", + "items": { + "$ref": "#/definitions/tokenindexer.Asset" + } } } } diff --git a/docs/swagger.json b/docs/swagger.json index eb5822d19..322372f6b 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1,7 +1,8 @@ { "swagger": "2.0", "info": { - "contact": {} + "contact": {}, + "license": {} }, "paths": { "/v2/staking/delegations": { @@ -25,10 +26,7 @@ "in": "body", "required": true, "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/api_endpoint.AddressBatchRequest" - } + "$ref": "#/definitions/endpoint.AddressesRequest" } } ], @@ -36,10 +34,7 @@ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.DelegationResponse" - } + "$ref": "#/definitions/blockatlas.DelegationsBatchPage" } } } @@ -66,10 +61,7 @@ "in": "body", "required": true, "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/api_endpoint.AddressBatchRequest" - } + "$ref": "#/definitions/endpoint.AddressesRequest" } } ], @@ -77,10 +69,7 @@ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.DelegationResponse" - } + "$ref": "#/definitions/blockatlas.DelegationsBatchPage" } } } @@ -158,7 +147,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -206,7 +195,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -246,7 +235,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -288,16 +277,13 @@ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Collection" - } + "$ref": "#/definitions/blockatlas.CollectionPage" } }, "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -339,7 +325,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -381,7 +367,7 @@ "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -413,17 +399,53 @@ "schema": { "type": "array", "items": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.DelegationResponse" - } + "$ref": "#/definitions/blockatlas.DelegationsBatchPage" } } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" + } + } + } + } + }, + "/v3/tokens/new": { + "get": { + "description": "Get new tokens", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Transactions" + ], + "summary": "Get list of new tokens by coin from specific unix timstamp", + "operationId": "tokens_new_v3", + "parameters": [ + { + "type": "integer", + "description": "unix timestamp", + "name": "from", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "coin like 60", + "name": "coin", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/tokenindexer.Response" } } } @@ -509,16 +531,13 @@ "200": { "description": "OK", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Collection" - } + "$ref": "#/definitions/blockatlas.CollectionPage" } }, "500": { "description": "Internal Server Error", "schema": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse" + "$ref": "#/definitions/endpoint.ErrorResponse" } } } @@ -526,33 +545,6 @@ } }, "definitions": { - "api_endpoint.AddressBatchRequest": { - "type": "object", - "properties": { - "address": { - "type": "string" - }, - "coin": { - "type": "integer" - } - } - }, - "api_endpoint.ErrorDetails": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - } - }, - "api_endpoint.ErrorResponse": { - "type": "object", - "properties": { - "error": { - "$ref": "#/definitions/api_endpoint.ErrorDetails" - } - } - }, "blockatlas.Collection": { "type": "object", "properties": { @@ -582,10 +574,17 @@ } } }, + "blockatlas.CollectionPage": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Collection" + } + }, "blockatlas.Delegation": { "type": "object", "properties": { "delegator": { + "type": "object", "$ref": "#/definitions/blockatlas.StakeValidator" }, "metadata": { @@ -609,19 +608,31 @@ "type": "string" }, "coin": { + "type": "object", "$ref": "#/definitions/coin.ExternalCoin" }, "delegations": { - "type": "array", - "items": { - "$ref": "#/definitions/blockatlas.Delegation" - } + "type": "object", + "$ref": "#/definitions/blockatlas.DelegationsPage" }, "details": { + "type": "object", "$ref": "#/definitions/blockatlas.StakingDetails" } } }, + "blockatlas.DelegationsBatchPage": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.DelegationResponse" + } + }, + "blockatlas.DelegationsPage": { + "type": "array", + "items": { + "$ref": "#/definitions/blockatlas.Delegation" + } + }, "blockatlas.DocsResponse": { "type": "object", "properties": { @@ -645,12 +656,14 @@ "type": "object", "properties": { "details": { + "type": "object", "$ref": "#/definitions/blockatlas.StakingDetails" }, "id": { "type": "string" }, "info": { + "type": "object", "$ref": "#/definitions/blockatlas.StakeValidatorInfo" }, "status": { @@ -685,6 +698,7 @@ "type": "string" }, "reward": { + "type": "object", "$ref": "#/definitions/blockatlas.StakingReward" }, "type": { @@ -717,7 +731,7 @@ } } }, - "github.com_trustwallet_blockatlas_api_endpoint.AddressBatchRequest": { + "endpoint.AddressBatchRequest": { "type": "object", "properties": { "address": { @@ -728,7 +742,13 @@ } } }, - "github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails": { + "endpoint.AddressesRequest": { + "type": "array", + "items": { + "$ref": "#/definitions/endpoint.AddressBatchRequest" + } + }, + "endpoint.ErrorDetails": { "type": "object", "properties": { "message": { @@ -736,11 +756,43 @@ } } }, - "github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse": { + "endpoint.ErrorResponse": { "type": "object", "properties": { "error": { - "$ref": "#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails" + "type": "object", + "$ref": "#/definitions/endpoint.ErrorDetails" + } + } + }, + "tokenindexer.Asset": { + "type": "object", + "properties": { + "asset": { + "type": "string" + }, + "decimals": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "symbol": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "tokenindexer.Response": { + "type": "object", + "properties": { + "assets": { + "type": "array", + "items": { + "$ref": "#/definitions/tokenindexer.Asset" + } } } } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index f5111ea46..47ae34120 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,21 +1,4 @@ definitions: - api_endpoint.AddressBatchRequest: - properties: - address: - type: string - coin: - type: integer - type: object - api_endpoint.ErrorDetails: - properties: - message: - type: string - type: object - api_endpoint.ErrorResponse: - properties: - error: - $ref: '#/definitions/api_endpoint.ErrorDetails' - type: object blockatlas.Collection: properties: address: @@ -35,10 +18,15 @@ definitions: total: type: integer type: object + blockatlas.CollectionPage: + items: + $ref: '#/definitions/blockatlas.Collection' + type: array blockatlas.Delegation: properties: delegator: $ref: '#/definitions/blockatlas.StakeValidator' + type: object metadata: type: object status: @@ -54,13 +42,22 @@ definitions: type: string coin: $ref: '#/definitions/coin.ExternalCoin' + type: object delegations: - items: - $ref: '#/definitions/blockatlas.Delegation' - type: array + $ref: '#/definitions/blockatlas.DelegationsPage' + type: object details: $ref: '#/definitions/blockatlas.StakingDetails' + type: object type: object + blockatlas.DelegationsBatchPage: + items: + $ref: '#/definitions/blockatlas.DelegationResponse' + type: array + blockatlas.DelegationsPage: + items: + $ref: '#/definitions/blockatlas.Delegation' + type: array blockatlas.DocsResponse: properties: docs: @@ -77,10 +74,12 @@ definitions: properties: details: $ref: '#/definitions/blockatlas.StakingDetails' + type: object id: type: string info: $ref: '#/definitions/blockatlas.StakeValidatorInfo' + type: object status: type: boolean type: object @@ -103,6 +102,7 @@ definitions: type: string reward: $ref: '#/definitions/blockatlas.StakingReward' + type: object type: type: string type: object @@ -122,25 +122,51 @@ definitions: symbol: type: string type: object - github.com_trustwallet_blockatlas_api_endpoint.AddressBatchRequest: + endpoint.AddressBatchRequest: properties: address: type: string coin: type: integer type: object - github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails: + endpoint.AddressesRequest: + items: + $ref: '#/definitions/endpoint.AddressBatchRequest' + type: array + endpoint.ErrorDetails: properties: message: type: string type: object - github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse: + endpoint.ErrorResponse: properties: error: - $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorDetails' + $ref: '#/definitions/endpoint.ErrorDetails' + type: object + type: object + tokenindexer.Asset: + properties: + asset: + type: string + decimals: + type: integer + name: + type: string + symbol: + type: string + type: + type: string + type: object + tokenindexer.Response: + properties: + assets: + items: + $ref: '#/definitions/tokenindexer.Asset' + type: array type: object info: contact: {} + license: {} paths: /v2/{coin}/blocks/{block}: get: @@ -167,7 +193,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Block tags: - Transactions @@ -200,7 +226,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/api_endpoint.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Stake Delegations tags: - Staking @@ -227,7 +253,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/api_endpoint.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Validators tags: - Staking @@ -256,13 +282,11 @@ paths: "200": description: OK schema: - items: - $ref: '#/definitions/blockatlas.Collection' - type: array + $ref: '#/definitions/blockatlas.CollectionPage' "500": description: Internal Server Error schema: - $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Tokens tags: - Transactions @@ -291,7 +315,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Transactions tags: - Transactions @@ -320,7 +344,7 @@ paths: "500": description: Internal Server Error schema: - $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Transactions by XPUB tags: - Transactions @@ -336,18 +360,14 @@ paths: name: delegations required: true schema: - items: - $ref: '#/definitions/api_endpoint.AddressBatchRequest' - type: array + $ref: '#/definitions/endpoint.AddressesRequest' produces: - application/json responses: "200": description: OK schema: - items: - $ref: '#/definitions/blockatlas.DelegationResponse' - type: array + $ref: '#/definitions/blockatlas.DelegationsBatchPage' summary: Get Multiple Stake Delegations tags: - Staking @@ -363,18 +383,14 @@ paths: name: delegations required: true schema: - items: - $ref: '#/definitions/api_endpoint.AddressBatchRequest' - type: array + $ref: '#/definitions/endpoint.AddressesRequest' produces: - application/json responses: "200": description: OK schema: - items: - $ref: '#/definitions/blockatlas.DelegationResponse' - type: array + $ref: '#/definitions/blockatlas.DelegationsBatchPage' summary: Get Multiple Stake Delegations tags: - Staking @@ -419,17 +435,41 @@ paths: description: OK schema: items: - items: - $ref: '#/definitions/blockatlas.DelegationResponse' - type: array + $ref: '#/definitions/blockatlas.DelegationsBatchPage' type: array "400": description: Bad Request schema: - $ref: '#/definitions/api_endpoint.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get staking info by coin ID tags: - Staking + /v3/tokens/new: + get: + consumes: + - application/json + description: Get new tokens + operationId: tokens_new_v3 + parameters: + - description: unix timestamp + in: query + name: from + required: true + type: integer + - description: coin like 60 + in: query + name: coin + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/tokenindexer.Response' + summary: Get list of new tokens by coin from specific unix timstamp + tags: + - Transactions /v4/{coin}/collections/{owner}/collection/{collection_id}: get: consumes: @@ -461,13 +501,11 @@ paths: "200": description: OK schema: - items: - $ref: '#/definitions/blockatlas.Collection' - type: array + $ref: '#/definitions/blockatlas.CollectionPage' "500": description: Internal Server Error schema: - $ref: '#/definitions/github.com_trustwallet_blockatlas_api_endpoint.ErrorResponse' + $ref: '#/definitions/endpoint.ErrorResponse' summary: Get Collection tags: - Collections diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index ecfb56643..2abea4993 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -530,6 +530,7 @@ func (t Tx) AssetModel() (models.Asset, bool) { if asset.Asset == "" { return models.Asset{}, false } + asset.Coin = t.Coin return asset, true } diff --git a/services/tokenindexer/api.go b/services/tokenindexer/api.go index 3a4ba6a5d..7438b1f76 100644 --- a/services/tokenindexer/api.go +++ b/services/tokenindexer/api.go @@ -17,7 +17,7 @@ func Init(database *db.Instance) Instance { func (i Instance) HandleNewTokensRequest(r Request, ctx context.Context) (Response, error) { from := time.Unix(r.From, 0) - result, err := i.database.GetAssetsFrom(from, ctx) + result, err := i.database.GetAssetsFrom(from, r.Coin, ctx) if err != nil { return Response{}, err } diff --git a/services/tokenindexer/models.go b/services/tokenindexer/models.go index c6aeb28dd..a2852b29d 100644 --- a/services/tokenindexer/models.go +++ b/services/tokenindexer/models.go @@ -2,6 +2,7 @@ package tokenindexer type Request struct { From int64 + Coin int } type Response struct { diff --git a/services/tokensearcher/association_test.go b/services/tokensearcher/association_test.go index 7d79f6cae..5d3bb4298 100644 --- a/services/tokensearcher/association_test.go +++ b/services/tokensearcher/association_test.go @@ -40,12 +40,12 @@ func Test_assetsMap(t *testing.T) { } result := assetsMap(blockatlas.Txs{tx1, tx2, tx3}, "60") - assert.Equal(t, result["60_A"], []models.Asset{{Asset: "c60_tABC", Type: "ERC20"}}) - assert.Equal(t, result["60_C"], []models.Asset{{Asset: "c60_tABC", Type: "ERC20"}}) - assert.Equal(t, result["60_D"], []models.Asset{{Asset: "c60_tEFG", Type: "ERC20"}}) - assert.Equal(t, result["60_F"], []models.Asset{{Asset: "c60_tEFG", Type: "ERC20"}}) - assert.Equal(t, result["60_Q"], []models.Asset{{Asset: "c60_tHIJ", Type: "ERC20"}}) - assert.Equal(t, result["60_L"], []models.Asset{{Asset: "c60_tHIJ", Type: "ERC20"}}) + assert.Equal(t, result["60_A"], []models.Asset{{Asset: "c60_tABC", Type: "ERC20", Coin: 60}}) + assert.Equal(t, result["60_C"], []models.Asset{{Asset: "c60_tABC", Type: "ERC20", Coin: 60}}) + assert.Equal(t, result["60_D"], []models.Asset{{Asset: "c60_tEFG", Type: "ERC20", Coin: 60}}) + assert.Equal(t, result["60_F"], []models.Asset{{Asset: "c60_tEFG", Type: "ERC20", Coin: 60}}) + assert.Equal(t, result["60_Q"], []models.Asset{{Asset: "c60_tHIJ", Type: "ERC20", Coin: 60}}) + assert.Equal(t, result["60_L"], []models.Asset{{Asset: "c60_tHIJ", Type: "ERC20", Coin: 60}}) } func Test_associationsToAdd(t *testing.T) { diff --git a/tests/integration/db_test/tokenindexer_test.go b/tests/integration/db_test/tokenindexer_test.go index 7a83724c2..dbe646475 100644 --- a/tests/integration/db_test/tokenindexer_test.go +++ b/tests/integration/db_test/tokenindexer_test.go @@ -11,6 +11,7 @@ import ( "github.com/trustwallet/blockatlas/tests/integration/setup" "sort" "testing" + "time" ) func Test_AddNewAssets_Simple(t *testing.T) { @@ -57,6 +58,37 @@ func Test_AddNewAssets_Simple(t *testing.T) { assert.Equal(t, 0, len(assets)) } +func Test_GetAssetsFrom_Simple(t *testing.T) { + setup.CleanupPgContainer(database.Gorm) + database.MemoryCache = gocache.New(gocache.NoExpiration, gocache.NoExpiration) + a := []models.Asset{ + { + Asset: "c714_a", + Coin: 714, + Decimals: 18, + Name: "A", + Symbol: "ABC", + Type: "BEP20", + }, + { + Asset: "c714_b", + Decimals: 18, + Coin: 60, + Name: "B", + Symbol: "BCD", + Type: "BEP20", + }, + } + err := database.AddNewAssets(a, context.Background()) + assert.Nil(t, err) + assets, err := database.GetAssetsFrom(time.Unix(0, 0), -1, context.Background()) + assert.Nil(t, err) + assert.NotNil(t, assets) + assets, err = database.GetAssetsFrom(time.Unix(0, 0), 60, context.Background()) + assert.Nil(t, err) + assert.Equal(t, 1, len(assets)) +} + func Test_AddNewAssets(t *testing.T) { setup.CleanupPgContainer(database.Gorm) database.MemoryCache = gocache.New(gocache.NoExpiration, gocache.NoExpiration) From ff9521ccf196151bca5a4b5dfff4da3fbb99df68 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Wed, 28 Oct 2020 15:49:21 +0300 Subject: [PATCH 402/506] [Indexer] Fix bug with missing coin at searcher (#1263) * Update Indexer api - Add coin to db and as param to query - Use GET instead of POST * Fix tests * Add Swagger * Update models.go --- services/tokensearcher/models.go | 1 + 1 file changed, 1 insertion(+) diff --git a/services/tokensearcher/models.go b/services/tokensearcher/models.go index 1f88485dc..7a78f78c5 100644 --- a/services/tokensearcher/models.go +++ b/services/tokensearcher/models.go @@ -25,6 +25,7 @@ func (nr *NodesResponse) UpdateAssetsByAddress(tokens blockatlas.TokenPage, coin Name: t.Name, Symbol: t.Symbol, Type: string(t.Type), + ID: t.Coin, }, ) } From 89ec3a755d8bd96ad3758a200efeee6c4b731aa4 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Wed, 28 Oct 2020 07:19:19 -0700 Subject: [PATCH 403/506] Add +heroku goVersion go1.15 (#1260) * Add +heroku goVersion go1.15 * Add // +heroku install ./cmd/... * Create Procfile * Create app.json * Rename uri => url * Update app.json Co-authored-by: maxUo <20925019+maxUo@users.noreply.github.com> --- Procfile | 1 + app.json | 26 ++++++++++++++++++++++++++ cmd/api/main.go | 9 +++++---- cmd/indexer/main.go | 9 +++++---- cmd/notifier/main.go | 13 +++++++------ cmd/parser/main.go | 17 +++++++++-------- cmd/searcher/main.go | 9 +++++---- cmd/subscriber/main.go | 9 +++++---- config.yml | 7 ++++--- go.mod | 5 ++++- 10 files changed, 71 insertions(+), 34 deletions(-) create mode 100644 Procfile create mode 100644 app.json diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..891cdb3a5 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: ATLAS_POSTGRES_READ_URL=$ATLAS_POSTGRES_URL bin/api -c $HOME/config.yml -p $PORT diff --git a/app.json b/app.json new file mode 100644 index 000000000..386e7d81c --- /dev/null +++ b/app.json @@ -0,0 +1,26 @@ +{ + "name": "blockatlas", + "buildpacks":[ + { + "url":"heroku/go" + } + ], + "addons": [ + "heroku-postgresql:hobby-dev", + "cloudamqp" + ], + "environments": { + "review": { + "addons": [ + { + "plan":"heroku-postgresql:hobby-dev", + "as":"ATLAS_POSTGRES" + }, + { + "plan":"cloudamqp:lemur", + "as":"ATLAS_OBSERVER_RABBITMQ" + } + ] + } + } +} diff --git a/cmd/api/main.go b/cmd/api/main.go index 2e92f7f9d..08dbb09f3 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -2,6 +2,8 @@ package main import ( "context" + "time" + "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" @@ -14,7 +16,6 @@ import ( "github.com/trustwallet/blockatlas/services/spamfilter" "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" - "time" ) const ( @@ -47,8 +48,8 @@ func init() { spamfilter.SpamList = viper.GetStringSlice("spam_words") if restAPI == "tokens" || restAPI == "all" { - pgURI := viper.GetString("postgres.uri") - pgReadUri := viper.GetString("postgres.read_uri") + pgURI := viper.GetString("postgres.url") + pgReadUri := viper.GetString("postgres.read.url") var err error database, err = db.New(pgURI, pgReadUri, logMode) @@ -57,7 +58,7 @@ func init() { } go database.RestoreConnectionWorker(ctx, time.Second*10, pgURI) - mqHost := viper.GetString("observer.rabbitmq.uri") + mqHost := viper.GetString("observer.rabbitmq.url") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") internal.InitRabbitMQ(mqHost, prefetchCount) if err := mq.TokensRegistration.Declare(); err != nil { diff --git a/cmd/indexer/main.go b/cmd/indexer/main.go index ca6b8a26a..9da5114c1 100644 --- a/cmd/indexer/main.go +++ b/cmd/indexer/main.go @@ -2,13 +2,14 @@ package main import ( "context" + "time" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/tokenindexer" - "time" ) const ( @@ -29,14 +30,14 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() - mqHost := viper.GetString("observer.rabbitmq.uri") + mqHost := viper.GetString("observer.rabbitmq.url") logMode := viper.GetBool("postgres.log") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") internal.InitRabbitMQ(mqHost, prefetchCount) - pgUri := viper.GetString("postgres.uri") - pgReadUri := viper.GetString("postgres.read_uri") + pgUri := viper.GetString("postgres.url") + pgReadUri := viper.GetString("postgres.read.url") var err error database, err = db.New(pgUri, pgReadUri, logMode) if err != nil { diff --git a/cmd/notifier/main.go b/cmd/notifier/main.go index bb6a64835..b1b4ddb24 100644 --- a/cmd/notifier/main.go +++ b/cmd/notifier/main.go @@ -2,13 +2,14 @@ package main import ( "context" + "time" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/notifier" - "time" ) const ( @@ -16,8 +17,8 @@ const ( ) var ( - ctx context.Context - cancel context.CancelFunc + ctx context.Context + cancel context.CancelFunc confPath string database *db.Instance ) @@ -29,7 +30,7 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() - mqHost := viper.GetString("observer.rabbitmq.uri") + mqHost := viper.GetString("observer.rabbitmq.url") logMode := viper.GetBool("postgres.log") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") @@ -44,8 +45,8 @@ func init() { logger.Fatal(err) } - pgUri := viper.GetString("postgres.uri") - pgReadUri := viper.GetString("postgres.read_uri") + pgUri := viper.GetString("postgres.url") + pgReadUri := viper.GetString("postgres.read.url") var err error database, err = db.New(pgUri, pgReadUri, logMode) if err != nil { diff --git a/cmd/parser/main.go b/cmd/parser/main.go index 0f12a0f2e..ab76508aa 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -3,6 +3,12 @@ package main import ( "context" "fmt" + "os" + "os/signal" + "sync" + "syscall" + "time" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" @@ -10,11 +16,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/parser" - "os" - "os/signal" - "sync" - "syscall" - "time" ) const ( @@ -38,7 +39,7 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() - mqHost := viper.GetString("observer.rabbitmq.uri") + mqHost := viper.GetString("observer.rabbitmq.url") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") platformHandles := viper.GetStringSlice("platform") @@ -67,8 +68,8 @@ func init() { logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") } - pgURI := viper.GetString("postgres.uri") - pgReadUri := viper.GetString("postgres.read_uri") + pgURI := viper.GetString("postgres.url") + pgReadUri := viper.GetString("postgres.read.url") logMode := viper.GetBool("postgres.log") var err error database, err = db.New(pgURI, pgReadUri, logMode) diff --git a/cmd/searcher/main.go b/cmd/searcher/main.go index 52908fb4b..1354136d0 100644 --- a/cmd/searcher/main.go +++ b/cmd/searcher/main.go @@ -2,6 +2,8 @@ package main import ( "context" + "time" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" @@ -9,7 +11,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/notifier" "github.com/trustwallet/blockatlas/services/tokensearcher" - "time" ) const ( @@ -30,7 +31,7 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() - mqHost := viper.GetString("observer.rabbitmq.uri") + mqHost := viper.GetString("observer.rabbitmq.url") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") internal.InitRabbitMQ(mqHost, prefetchCount) @@ -39,8 +40,8 @@ func init() { logger.Fatal(err) } - pgURI := viper.GetString("postgres.uri") - pgReadUri := viper.GetString("postgres.read_uri") + pgURI := viper.GetString("postgres.url") + pgReadUri := viper.GetString("postgres.read.url") logMode := viper.GetBool("postgres.log") var err error database, err = db.New(pgURI, pgReadUri, logMode) diff --git a/cmd/subscriber/main.go b/cmd/subscriber/main.go index 5f2551c78..e1bfcb27d 100644 --- a/cmd/subscriber/main.go +++ b/cmd/subscriber/main.go @@ -2,6 +2,8 @@ package main import ( "context" + "time" + "github.com/spf13/viper" "github.com/trustwallet/blockatlas/db" _ "github.com/trustwallet/blockatlas/docs" @@ -9,7 +11,6 @@ import ( "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/subscriber" - "time" ) const ( @@ -30,13 +31,13 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() - mqHost := viper.GetString("observer.rabbitmq.uri") + mqHost := viper.GetString("observer.rabbitmq.url") prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") internal.InitRabbitMQ(mqHost, prefetchCount) - pgURI := viper.GetString("postgres.uri") - pgReadUri := viper.GetString("postgres.read_uri") + pgURI := viper.GetString("postgres.url") + pgReadUri := viper.GetString("postgres.read.url") logMode := viper.GetBool("postgres.log") var err error database, err = db.New(pgURI, pgReadUri, logMode) diff --git a/config.yml b/config.yml index 28b29fc22..031f71807 100644 --- a/config.yml +++ b/config.yml @@ -36,13 +36,14 @@ observer: min: 3s max: 30s rabbitmq: - uri: amqp://localhost:5672 + url: amqp://localhost:5672 consumer: prefetch_count: 10 postgres: - uri: postgresql://user:pass@localhost/blockatlas?sslmode=disable - read_uri: postgresql://user:pass@localhost/blockatlas?sslmode=disable + url: postgresql://user:pass@localhost/blockatlas?sslmode=disable + read: + url: postgresql://user:pass@localhost/blockatlas?sslmode=disable log: false # [BNB] Binance DEX: https://www.binance.org/ diff --git a/go.mod b/go.mod index b7da3b093..018cfb735 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,9 @@ module github.com/trustwallet/blockatlas -go 1.14 +go 1.15 + +// +heroku goVersion go1.15 +// +heroku install ./cmd/... require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 From ed25cadc9308c5877310059fb6a297b8f3dd5416 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 29 Oct 2020 17:17:31 +0300 Subject: [PATCH 404/506] [Config] Change to new format (#1265) * Change config to new format * Fixes * Cleanup * Change platoform init * Change platoform init * Cleanup --- api/middleware/reverse_proxy.go | 17 -- cmd/api/main.go | 26 ++- cmd/indexer/main.go | 21 ++- cmd/notifier/main.go | 30 ++-- cmd/parser/main.go | 50 +++--- cmd/searcher/main.go | 29 ++-- cmd/subscriber/main.go | 23 ++- config.yml | 36 ++--- config/configuration.go | 269 ++++++++++++++++++++++++++++++-- configmock.yml | 2 +- internal/init.go | 2 +- platform/ethereum/base.go | 2 +- platform/platform.go | 125 +++++++-------- platform/registry.go | 11 -- 14 files changed, 410 insertions(+), 233 deletions(-) delete mode 100644 api/middleware/reverse_proxy.go diff --git a/api/middleware/reverse_proxy.go b/api/middleware/reverse_proxy.go deleted file mode 100644 index 868be6b1d..000000000 --- a/api/middleware/reverse_proxy.go +++ /dev/null @@ -1,17 +0,0 @@ -package middleware - -import ( - "github.com/gin-gonic/gin" - "github.com/spf13/viper" -) - -// CheckReverseProxy removes untrusted forwarded HTTP headers -// if gin.reverse_proxy is defined -func CheckReverseProxy(c *gin.Context) { - if !viper.GetBool("gin.reverse_proxy") { - c.Request.Header.Del("Forwarded") - c.Request.Header.Del("X-Forwarded-Proto") - c.Request.Header.Del("X-Forwarded-Host") - c.Request.Header.Del("X-Forwarded-For") - } -} diff --git a/cmd/api/main.go b/cmd/api/main.go index 08dbb09f3..e6e5bf74a 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -2,10 +2,10 @@ package main import ( "context" + "github.com/trustwallet/blockatlas/config" "time" "github.com/gin-gonic/gin" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/api" "github.com/trustwallet/blockatlas/db" _ "github.com/trustwallet/blockatlas/docs" @@ -41,26 +41,24 @@ func init() { internal.InitConfig(confPath) logger.InitLogger() - restAPI = viper.GetString("rest_api") - logMode := viper.GetBool("postgres.log") - engine = internal.InitEngine(viper.GetString("gin.mode")) - platform.Init(viper.GetStringSlice("platform")) - spamfilter.SpamList = viper.GetStringSlice("spam_words") + engine = internal.InitEngine(config.Default.Gin.Mode) + platform.Init(config.Default.Platform) + spamfilter.SpamList = config.Default.SpamWords if restAPI == "tokens" || restAPI == "all" { - pgURI := viper.GetString("postgres.url") - pgReadUri := viper.GetString("postgres.read.url") - var err error - database, err = db.New(pgURI, pgReadUri, logMode) + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, + config.Default.Postgres.Log) if err != nil { logger.Fatal(err) } - go database.RestoreConnectionWorker(ctx, time.Second*10, pgURI) + go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) + + internal.InitRabbitMQ( + config.Default.Observer.Rabbitmq.URL, + config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, + ) - mqHost := viper.GetString("observer.rabbitmq.url") - prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") - internal.InitRabbitMQ(mqHost, prefetchCount) if err := mq.TokensRegistration.Declare(); err != nil { logger.Fatal(err) } diff --git a/cmd/indexer/main.go b/cmd/indexer/main.go index 9da5114c1..87c258dcc 100644 --- a/cmd/indexer/main.go +++ b/cmd/indexer/main.go @@ -2,9 +2,9 @@ package main import ( "context" + "github.com/trustwallet/blockatlas/config" "time" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" @@ -19,31 +19,28 @@ const ( var ( ctx context.Context cancel context.CancelFunc - confPath string database *db.Instance ) func init() { ctx, cancel = context.WithCancel(context.Background()) - _, confPath = internal.ParseArgs("", defaultConfigPath) + _, confPath := internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) logger.InitLogger() - mqHost := viper.GetString("observer.rabbitmq.url") - logMode := viper.GetBool("postgres.log") - prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + internal.InitRabbitMQ( + config.Default.Observer.Rabbitmq.URL, + config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, + ) - internal.InitRabbitMQ(mqHost, prefetchCount) - - pgUri := viper.GetString("postgres.url") - pgReadUri := viper.GetString("postgres.read.url") var err error - database, err = db.New(pgUri, pgReadUri, logMode) + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, + config.Default.Postgres.Log) if err != nil { logger.Fatal(err) } - go database.RestoreConnectionWorker(ctx, time.Second*10, pgUri) + go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) time.Sleep(time.Millisecond) } diff --git a/cmd/notifier/main.go b/cmd/notifier/main.go index b1b4ddb24..5e85d605b 100644 --- a/cmd/notifier/main.go +++ b/cmd/notifier/main.go @@ -2,9 +2,9 @@ package main import ( "context" + "github.com/trustwallet/blockatlas/config" "time" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" @@ -19,23 +19,20 @@ const ( var ( ctx context.Context cancel context.CancelFunc - confPath string database *db.Instance ) func init() { ctx, cancel = context.WithCancel(context.Background()) - _, confPath = internal.ParseArgs("", defaultConfigPath) + _, confPath := internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) logger.InitLogger() - mqHost := viper.GetString("observer.rabbitmq.url") - logMode := viper.GetBool("postgres.log") - prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") - maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") - - internal.InitRabbitMQ(mqHost, prefetchCount) + internal.InitRabbitMQ( + config.Default.Observer.Rabbitmq.URL, + config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, + ) if err := mq.RawTransactions.Declare(); err != nil { logger.Fatal(err) @@ -45,22 +42,23 @@ func init() { logger.Fatal(err) } - pgUri := viper.GetString("postgres.url") - pgReadUri := viper.GetString("postgres.read.url") var err error - database, err = db.New(pgUri, pgReadUri, logMode) + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, + config.Default.Postgres.Log) if err != nil { logger.Fatal(err) } - go database.RestoreConnectionWorker(ctx, time.Second*10, pgUri) + go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) - if maxPushNotificationsBatchLimit == 0 { + limit := config.Default.Observer.PushNotificationsBatchLimit + if limit == 0 { notifier.MaxPushNotificationsBatchLimit = notifier.DefaultPushNotificationsBatchLimit } else { - notifier.MaxPushNotificationsBatchLimit = maxPushNotificationsBatchLimit + notifier.MaxPushNotificationsBatchLimit = uint(limit) } - logger.Info("maxPushNotificationsBatchLimit ", logger.Params{"limit": maxPushNotificationsBatchLimit}) + logger.Info("maxPushNotificationsBatchLimit ", + logger.Params{"limit": notifier.MaxPushNotificationsBatchLimit}) time.Sleep(time.Millisecond) } diff --git a/cmd/parser/main.go b/cmd/parser/main.go index ab76508aa..5151810a5 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -3,13 +3,14 @@ package main import ( "context" "fmt" + "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/services/spamfilter" "os" "os/signal" "sync" "syscall" "time" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" @@ -23,28 +24,25 @@ const ( ) var ( - ctx context.Context - cancel context.CancelFunc - confPath string - backlogTime, minInterval, maxInterval, fetchBlocksInterval time.Duration - maxBackLogBlocks int64 - txsBatchLimit uint - database *db.Instance + ctx context.Context + cancel context.CancelFunc + database *db.Instance ) func init() { ctx, cancel = context.WithCancel(context.Background()) - _, confPath = internal.ParseArgs("", defaultConfigPath) + _, confPath := internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) logger.InitLogger() - mqHost := viper.GetString("observer.rabbitmq.url") - prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") - platformHandles := viper.GetStringSlice("platform") + internal.InitRabbitMQ( + config.Default.Observer.Rabbitmq.URL, + config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, + ) - internal.InitRabbitMQ(mqHost, prefetchCount) - platform.Init(platformHandles) + platform.Init(config.Default.Platform) + spamfilter.SpamList = config.Default.SpamWords if err := mq.RawTransactions.Declare(); err != nil { logger.Fatal(err) @@ -58,25 +56,13 @@ func init() { logger.Fatal("No APIs to observe") } - txsBatchLimit = viper.GetUint("observer.txs_batch_limit") - backlogTime = viper.GetDuration("observer.backlog") - minInterval = viper.GetDuration("observer.block_poll.min") - maxInterval = viper.GetDuration("observer.block_poll.max") - fetchBlocksInterval = viper.GetDuration("observer.fetch_blocks_interval") - maxBackLogBlocks = viper.GetInt64("observer.backlog_max_blocks") - if minInterval >= maxInterval { - logger.Fatal("minimum block polling interval cannot be greater or equal than maximum") - } - - pgURI := viper.GetString("postgres.url") - pgReadUri := viper.GetString("postgres.read.url") - logMode := viper.GetBool("postgres.log") var err error - database, err = db.New(pgURI, pgReadUri, logMode) + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, + config.Default.Postgres.Log) if err != nil { logger.Fatal(err) } - go database.RestoreConnectionWorker(ctx, time.Second*10, pgURI) + go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) time.Sleep(time.Millisecond) } @@ -88,6 +74,12 @@ func main() { coinCancel = make(map[string]context.CancelFunc) stopChannel = make(chan<- struct{}, len(platform.BlockAPIs)) ) + txsBatchLimit := config.Default.Observer.TxsBatchLimit + backlogTime := config.Default.Observer.Backlog + minInterval := config.Default.Observer.BlockPoll.Min + maxInterval := config.Default.Observer.BlockPoll.Max + fetchBlocksInterval := config.Default.Observer.FetchBlocksInterval + maxBackLogBlocks := config.Default.Observer.BacklogMaxBlocks go mq.FatalWorker(time.Second * 10) diff --git a/cmd/searcher/main.go b/cmd/searcher/main.go index 1354136d0..b0a8bb078 100644 --- a/cmd/searcher/main.go +++ b/cmd/searcher/main.go @@ -2,9 +2,9 @@ package main import ( "context" + "github.com/trustwallet/blockatlas/config" "time" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" @@ -20,43 +20,42 @@ const ( var ( ctx context.Context cancel context.CancelFunc - confPath string database *db.Instance ) func init() { ctx, cancel = context.WithCancel(context.Background()) - _, confPath = internal.ParseArgs("", defaultConfigPath) + _, confPath := internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) logger.InitLogger() - mqHost := viper.GetString("observer.rabbitmq.url") - prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") - maxPushNotificationsBatchLimit := viper.GetUint("observer.push_notifications_batch_limit") - internal.InitRabbitMQ(mqHost, prefetchCount) + internal.InitRabbitMQ( + config.Default.Observer.Rabbitmq.URL, + config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, + ) if err := mq.RawTransactionsSearcher.Declare(); err != nil { logger.Fatal(err) } - pgURI := viper.GetString("postgres.url") - pgReadUri := viper.GetString("postgres.read.url") - logMode := viper.GetBool("postgres.log") var err error - database, err = db.New(pgURI, pgReadUri, logMode) + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, + config.Default.Postgres.Log) if err != nil { logger.Fatal(err) } - go database.RestoreConnectionWorker(ctx, time.Second*10, pgURI) + go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) - if maxPushNotificationsBatchLimit == 0 { + limit := config.Default.Observer.PushNotificationsBatchLimit + if limit == 0 { notifier.MaxPushNotificationsBatchLimit = notifier.DefaultPushNotificationsBatchLimit } else { - notifier.MaxPushNotificationsBatchLimit = maxPushNotificationsBatchLimit + notifier.MaxPushNotificationsBatchLimit = uint(limit) } - logger.Info("maxPushNotificationsBatchLimit ", logger.Params{"limit": maxPushNotificationsBatchLimit}) + logger.Info("maxPushNotificationsBatchLimit ", + logger.Params{"limit": notifier.MaxPushNotificationsBatchLimit}) time.Sleep(time.Millisecond) } diff --git a/cmd/subscriber/main.go b/cmd/subscriber/main.go index e1bfcb27d..c4c95784f 100644 --- a/cmd/subscriber/main.go +++ b/cmd/subscriber/main.go @@ -2,9 +2,9 @@ package main import ( "context" + "github.com/trustwallet/blockatlas/config" "time" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/db" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" @@ -20,31 +20,28 @@ const ( var ( ctx context.Context cancel context.CancelFunc - confPath string database *db.Instance ) func init() { ctx, cancel = context.WithCancel(context.Background()) - _, confPath = internal.ParseArgs("", defaultConfigPath) + _, confPath := internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) logger.InitLogger() - mqHost := viper.GetString("observer.rabbitmq.url") - prefetchCount := viper.GetInt("observer.rabbitmq.consumer.prefetch_count") + internal.InitRabbitMQ( + config.Default.Observer.Rabbitmq.URL, + config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, + ) - internal.InitRabbitMQ(mqHost, prefetchCount) - - pgURI := viper.GetString("postgres.url") - pgReadUri := viper.GetString("postgres.read.url") - logMode := viper.GetBool("postgres.log") var err error - database, err = db.New(pgURI, pgReadUri, logMode) + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, + config.Default.Postgres.Log) if err != nil { logger.Fatal(err) } - go database.RestoreConnectionWorker(ctx, time.Second*10, pgURI) + go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) time.Sleep(time.Millisecond) } @@ -58,7 +55,7 @@ func main() { logger.Fatal(err) } - subscriberType := subscriber.Subscriber(viper.GetString("subscriber")) + subscriberType := subscriber.Subscriber(config.Default.Subscriber) switch subscriberType { case subscriber.Tokens: go mq.TokensRegistration.RunConsumerWithCancelAndDbConn(subscriber.RunTokensSubscriber, database, ctx) diff --git a/config.yml b/config.yml index 031f71807..aa7f8139e 100644 --- a/config.yml +++ b/config.yml @@ -26,7 +26,7 @@ observer: # Amount of time between fetching blocks concurrently fetch_blocks_interval: 1ms # Don't request more than N blocks at once - backlog_max_blocks: 20 + backlog_max_blocks: 100 # Limit amount of transactions in batch txs_batch_limit: 3000 # Limit of push notifications in batch @@ -52,8 +52,8 @@ binance: explorer: https://explorer.binance.org # [NIM] Nimiq: https://nimiq.com -#nimiq: -# api: http://localhost:8648 +nimiq: + api: http://localhost:8648 # [XRP] Ripple: https://ripple.com ripple: @@ -74,39 +74,39 @@ tezos: # [ETH] Ethereum: https://ethereum.org ethereum: - api: https://localhost:4567 #(Trust-Ray API) blockbook_api: https://eth1.trezor.io + 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: -# api: https://localhost:4567 +classic: + api: https://localhost:4567 # [POA] POA Network: https://poa.network (Trust-Ray API) -# poa: -# api: https://localhost:4567 +poa: + api: https://localhost:4567 # [CLO] Callisto Network: https://callisto.network (Trust-Ray API) -# callisto: -# api: https://localhost:4567 +callisto: + api: https://localhost:4567 # [GO] GoChain: https://gochain.io (Trust-Ray API) -# gochain: -# api: https://localhost:4567 +gochain: + api: https://localhost:4567 # [WAN] Wanchain: https://wanchain.org (Trust-Ray API) -# wanchain: -# api: https://localhost:4567 +wanchain: + api: https://localhost:4567 # [TOMO] TomoChain: https://tomochain.com (Trust-Ray API) -# tomochain: -# api: https://localhost:4567 +tomochain: + api: https://localhost:4567 # [TT] ThunderCore: https://www.thundercore.com (Trust-Ray API) -# thundertoken: -# api: https://localhost:4567 +thundertoken: + api: https://localhost:4567 # [AION] Aion: https://aion.network aion: diff --git a/config/configuration.go b/config/configuration.go index 56c11e623..58e821b51 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -3,37 +3,276 @@ package config import ( "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/logger" + "reflect" "strings" + "time" ) -func LoadConfig(confPath string) { - // Load config from environment - viper.SetEnvPrefix("atlas") // will be uppercased automatically => ATLAS - viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) +type Configuration struct { + Gin struct { + Mode string `mapstructure:"mode"` + ReverseProxy bool `mapstructure:"reverse_proxy"` + } `mapstructure:"gin"` + Platform []string `mapstructure:"platform"` + RestAPI string `mapstructure:"rest_api"` + SpamWords []string `mapstructure:"spam_words"` + Subscriber string `mapstructure:"subscriber"` + Observer struct { + Backlog time.Duration `mapstructure:"backlog"` + FetchBlocksInterval time.Duration `mapstructure:"fetch_blocks_interval"` + BacklogMaxBlocks int64 `mapstructure:"backlog_max_blocks"` + TxsBatchLimit uint `mapstructure:"txs_batch_limit"` + PushNotificationsBatchLimit int `mapstructure:"push_notifications_batch_limit"` + BlockPoll struct { + Min time.Duration `mapstructure:"min"` + Max time.Duration `mapstructure:"max"` + } `mapstructure:"block_poll"` + Rabbitmq struct { + URL string `mapstructure:"url"` + Consumer struct { + PrefetchCount int `mapstructure:"prefetch_count"` + } `mapstructure:"consumer"` + } `mapstructure:"rabbitmq"` + } `mapstructure:"observer"` + Postgres struct { + URL string `mapstructure:"url"` + Read struct { + URL string `mapstructure:"url"` + } `mapstructure:"read"` + Log bool `mapstructure:"log"` + } `mapstructure:"postgres"` + Ethereum struct { + API string `mapstructure:"api"` + 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"` + Explorer string `mapstructure:"explorer"` + } `mapstructure:"binance"` + Ripple struct { + API string `mapstructure:"api"` + } `mapstructure:"ripple"` + Stellar struct { + API string `mapstructure:"api"` + } `mapstructure:"stellar"` + Kin struct { + API string `mapstructure:"api"` + } `mapstructure:"kin"` + Nimiq struct { + API string `mapstructure:"api"` + } `mapstructure:"nimiq"` + Tezos struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + } `mapstructure:"tezos"` + Thundertoken struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + } `mapstructure:"thundertoken"` + Gochain struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + } `mapstructure:"gochain"` + Classic struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + } `mapstructure:"classic"` + Smartchain struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + } `mapstructure:"smartchain"` + BSC struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + } `mapstructure:"bsc"` + Poa struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + } `mapstructure:"poa"` + Callisto struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + } `mapstructure:"callisto"` + Wanchain struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + } `mapstructure:"wanchain"` + Tomochain struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + } `mapstructure:"tomochain"` + Aion struct { + API string `mapstructure:"api"` + } `mapstructure:"aion"` + Icon struct { + API string `mapstructure:"api"` + } `mapstructure:"icon"` + Tron struct { + API string `mapstructure:"api"` + Explorer string `mapstructure:"explorer"` + } `mapstructure:"tron"` + Vechain struct { + API string `mapstructure:"api"` + } `mapstructure:"vechain"` + Theta struct { + API string `mapstructure:"api"` + } `mapstructure:"theta"` + Cosmos struct { + API string `mapstructure:"api"` + } `mapstructure:"cosmos"` + Ontology struct { + API string `mapstructure:"api"` + } `mapstructure:"ontology"` + Zilliqa struct { + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + Key string `mapstructure:"key"` + } `mapstructure:"zilliqa"` + Iotex struct { + API string `mapstructure:"api"` + } `mapstructure:"iotex"` + Waves struct { + API string `mapstructure:"api"` + } `mapstructure:"waves"` + Aeternity struct { + API string `mapstructure:"api"` + } `mapstructure:"aeternity"` + Nebulas struct { + API string `mapstructure:"api"` + } `mapstructure:"nebulas"` + Fio struct { + API string `mapstructure:"api"` + } `mapstructure:"fio"` + Bitcoin struct { + API string `mapstructure:"api"` + } `mapstructure:"bitcoin"` + Litecoin struct { + API string `mapstructure:"api"` + } `mapstructure:"litecoin"` + Bitcoincash struct { + API string `mapstructure:"api"` + } `mapstructure:"bitcoincash"` + Doge struct { + API string `mapstructure:"api"` + } `mapstructure:"doge"` + Dash struct { + API string `mapstructure:"api"` + } `mapstructure:"dash"` + Zcoin struct { + API string `mapstructure:"api"` + } `mapstructure:"zcoin"` + Zcash struct { + API string `mapstructure:"api"` + } `mapstructure:"zcash"` + Zelcash struct { + API string `mapstructure:"api"` + } `mapstructure:"zelcash"` + Viacoin struct { + API string `mapstructure:"api"` + } `mapstructure:"viacoin"` + Qtum struct { + API string `mapstructure:"api"` + } `mapstructure:"qtum"` + Groestlcoin struct { + API string `mapstructure:"api"` + } `mapstructure:"groestlcoin"` + Ravencoin struct { + API string `mapstructure:"api"` + } `mapstructure:"ravencoin"` + Decred struct { + API string `mapstructure:"api"` + } `mapstructure:"decred"` + Algorand struct { + API string `mapstructure:"api"` + } `mapstructure:"algorand"` + Nano struct { + API string `mapstructure:"api"` + } `mapstructure:"nano"` + Digibyte struct { + API string `mapstructure:"api"` + } `mapstructure:"digibyte"` + Harmony struct { + API string `mapstructure:"api"` + } `mapstructure:"harmony"` + Kava struct { + API string `mapstructure:"api"` + } `mapstructure:"kava"` + Kusama struct { + API string `mapstructure:"api"` + } `mapstructure:"kusama"` + Polkadot struct { + API string `mapstructure:"api"` + } `mapstructure:"polkadot"` + Solana struct { + API string `mapstructure:"api"` + } `mapstructure:"solana"` + Near struct { + API string `mapstructure:"api"` + } `mapstructure:"near"` + Elrond struct { + API string `mapstructure:"api"` + } `mapstructure:"elrond"` + Filecoin struct { + API string `mapstructure:"api"` + } `mapstructure:"filecoin"` +} + +var Default Configuration + +func Init(confPath string) { + c := Configuration{} + viper.AutomaticEnv() + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) viper.AddConfigPath(".") viper.SetConfigName("config") viper.SetConfigType("yml") - // Load config file if confPath == "" { - if err := viper.ReadInConfig(); err != nil { - if _, ok := err.(viper.ConfigFileNotFoundError); ok { - logger.Info("Config file was not supplied") - } else { - logger.Fatal("Issue reading config", err) - } + err := viper.ReadInConfig() + if err != nil { + logger.Panic(err, "Fatal error reading default config") + } else { + logger.Info("Viper using default config", logger.Params{"config": viper.ConfigFileUsed()}) } - logger.Info("Viper config", logger.Params{"config_file": viper.ConfigFileUsed()}) } else { viper.SetConfigFile(confPath) err := viper.ReadInConfig() if err != nil { - logger.Error("Failed to read config", err, - logger.Params{"config_file": confPath}) + logger.Panic(err, "Fatal error reading supplied config") } else { - logger.Info("Using config file", logger.Params{"config_file": confPath}) + logger.Info("Viper using supplied config", logger.Params{"config": viper.ConfigFileUsed()}) + } + } + + bindEnvs(c) + if err := viper.Unmarshal(&c); err != nil { + logger.Panic(err, "Error Unmarshal Viper Config File") + } + Default = c +} + +func bindEnvs(iface interface{}, parts ...string) { + ifv := reflect.ValueOf(iface) + ift := reflect.TypeOf(iface) + for i := 0; i < ift.NumField(); i++ { + v := ifv.Field(i) + t := ift.Field(i) + tv, ok := t.Tag.Lookup("mapstructure") + if !ok { + continue + } + switch v.Kind() { + case reflect.Struct: + bindEnvs(v.Interface(), append(parts, tv)...) + default: + if err := viper.BindEnv(strings.Join(append(parts, tv), ".")); err != nil { + logger.Fatal(err) + } } } } diff --git a/configmock.yml b/configmock.yml index 01bd05d26..858869e44 100644 --- a/configmock.yml +++ b/configmock.yml @@ -66,7 +66,7 @@ tezos: api: http://localhost:3347/mock/tezos-api rpc: https://mainnet.tezos.org.ua -# [ETH] Ethereum: https://ethereum.org (Trust-Ray API) +# [ETH] Ethereum: https://ethereum.org ethereum: api: http://localhost:3347/mock/eth-api blockbook_api: http://localhost:3347/mock/eth-blockbook-api diff --git a/internal/init.go b/internal/init.go index d2da34fe1..08200767d 100644 --- a/internal/init.go +++ b/internal/init.go @@ -36,7 +36,7 @@ func InitConfig(confPath string) { logger.Fatal(err) } - config.LoadConfig(confPath) + config.Init(confPath) } func InitEngine(ginMode string) *gin.Engine { diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index 4974b2e88..7a413802d 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -31,7 +31,7 @@ func InitWithBlockbook(coinType uint, blockbookApi, rpc string) *Platform { } } -func InitWitCollection(coinType uint, rpc, blockbookApi, collectionApi, collectionKey string) *Platform { +func InitWithCollection(coinType uint, rpc, blockbookApi, collectionApi, collectionKey string) *Platform { platform := InitWithBlockbook(coinType, blockbookApi, rpc) platform.collectible = collection.Client{Request: blockatlas.InitClient(collectionApi)} platform.collectible.Headers["X-API-KEY"] = collectionKey diff --git a/platform/platform.go b/platform/platform.go index 370141b5f..adc79212a 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -1,12 +1,11 @@ package platform import ( - "fmt" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/platform/filecoin" "github.com/trustwallet/blockatlas/platform/kava" - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/aeternity" "github.com/trustwallet/blockatlas/platform/aion" @@ -42,84 +41,70 @@ const ( allPlatformsHandle = "all" ) -func GetVar(name string) string { - return viper.GetString(name) -} - -func GetApiVar(coinId uint) string { - varName := fmt.Sprintf("%s.api", GetHandle(coinId)) - return GetVar(varName) -} - -func GetRpcVar(coinId uint) string { - varName := fmt.Sprintf("%s.rpc", GetHandle(coinId)) - return GetVar(varName) -} - func GetHandle(coinId uint) string { return coin.Coins[coinId].Handle } func getAllHandlers() blockatlas.Platforms { return blockatlas.Platforms{ - coin.Fio().Handle: fio.Init(GetApiVar(coin.FIO)), - coin.Aion().Handle: aion.Init(GetApiVar(coin.AION)), - coin.Icon().Handle: icon.Init(GetApiVar(coin.ICX)), - coin.Tron().Handle: tron.Init(GetApiVar(coin.TRX), GetVar("tron.explorer")), - coin.Nano().Handle: nano.Init(GetApiVar(coin.NANO)), - coin.Nimiq().Handle: nimiq.Init(GetApiVar(coin.NIM)), - coin.Iotex().Handle: iotex.Init(GetApiVar(coin.IOTX)), - coin.Theta().Handle: theta.Init(GetApiVar(coin.THETA)), - coin.Waves().Handle: waves.Init(GetApiVar(coin.WAVES)), - coin.Ripple().Handle: ripple.Init(GetApiVar(coin.XRP)), - coin.Harmony().Handle: harmony.Init(GetApiVar(coin.ONE)), - coin.Vechain().Handle: vechain.Init(GetApiVar(coin.VET)), - coin.Nebulas().Handle: nebulas.Init(GetApiVar(coin.NAS)), - coin.Ontology().Handle: ontology.Init(GetApiVar(coin.ONT)), - coin.Algorand().Handle: algorand.Init(GetApiVar(coin.ALGO)), - coin.Aeternity().Handle: aeternity.Init(GetApiVar(coin.AE)), - coin.Solana().Handle: solana.Init(GetApiVar(coin.SOL)), - coin.Tezos().Handle: tezos.Init(GetApiVar(coin.XTZ), GetRpcVar(coin.XTZ)), - coin.Binance().Handle: binance.Init(GetApiVar(coin.BNB)), - coin.Zilliqa().Handle: zilliqa.Init(GetApiVar(coin.ZIL), GetVar("zilliqa.key"), GetRpcVar(coin.ZIL)), - coin.Kusama().Handle: polkadot.Init(coin.KSM, GetApiVar(coin.KSM)), - coin.Polkadot().Handle: polkadot.Init(coin.DOT, GetApiVar(coin.DOT)), - coin.Stellar().Handle: stellar.Init(coin.XLM, GetApiVar(coin.XLM)), - coin.Kin().Handle: stellar.Init(coin.KIN, GetApiVar(coin.KIN)), - coin.Cosmos().Handle: cosmos.Init(coin.ATOM, GetApiVar(coin.ATOM)), - coin.Kava().Handle: kava.Init(coin.KAVA, GetApiVar(coin.KAVA)), - coin.Bitcoin().Handle: bitcoin.Init(coin.BTC, GetApiVar(coin.BTC)), - coin.Litecoin().Handle: bitcoin.Init(coin.LTC, GetApiVar(coin.LTC)), - coin.Bitcoincash().Handle: bitcoin.Init(coin.BCH, GetApiVar(coin.BCH)), - coin.Zcash().Handle: bitcoin.Init(coin.ZEC, GetApiVar(coin.ZEC)), - coin.Zcoin().Handle: bitcoin.Init(coin.XZC, GetApiVar(coin.XZC)), - coin.Viacoin().Handle: bitcoin.Init(coin.VIA, GetApiVar(coin.VIA)), - coin.Ravencoin().Handle: bitcoin.Init(coin.RVN, GetApiVar(coin.RVN)), - coin.Groestlcoin().Handle: bitcoin.Init(coin.GRS, GetApiVar(coin.GRS)), - coin.Zelcash().Handle: bitcoin.Init(coin.ZEL, GetApiVar(coin.ZEL)), - coin.Decred().Handle: bitcoin.Init(coin.DCR, GetApiVar(coin.DCR)), - coin.Digibyte().Handle: bitcoin.Init(coin.DGB, GetApiVar(coin.DGB)), - coin.Dash().Handle: bitcoin.Init(coin.DASH, GetApiVar(coin.DASH)), - coin.Doge().Handle: bitcoin.Init(coin.DOGE, GetApiVar(coin.DOGE)), - coin.Qtum().Handle: bitcoin.Init(coin.QTUM, GetApiVar(coin.QTUM)), - coin.Gochain().Handle: ethereum.Init(coin.GO, GetApiVar(coin.GO), GetRpcVar(coin.GO)), - coin.Thundertoken().Handle: ethereum.Init(coin.TT, GetApiVar(coin.TT), GetRpcVar(coin.TT)), - coin.Classic().Handle: ethereum.Init(coin.ETC, GetApiVar(coin.ETC), GetRpcVar(coin.ETC)), - coin.Poa().Handle: ethereum.Init(coin.POA, GetApiVar(coin.POA), GetRpcVar(coin.POA)), - coin.Callisto().Handle: ethereum.Init(coin.CLO, GetApiVar(coin.CLO), GetRpcVar(coin.CLO)), - coin.Wanchain().Handle: ethereum.Init(coin.WAN, GetApiVar(coin.WAN), GetRpcVar(coin.WAN)), - coin.Tomochain().Handle: ethereum.Init(coin.TOMO, GetApiVar(coin.TOMO), GetRpcVar(coin.TOMO)), - coin.Bsc().Handle: ethereum.InitWithBlockbook(coin.BSCLegacy, GetApiVar(coin.BSCLegacy), GetRpcVar(coin.BSCLegacy)), - coin.Smartchain().Handle: ethereum.InitWithBlockbook(coin.BSC, GetApiVar(coin.BSC), GetRpcVar(coin.BSC)), - coin.Ethereum().Handle: ethereum.InitWitCollection(coin.ETH, GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), - coin.Near().Handle: near.Init(GetApiVar(coin.NEAR)), - coin.Elrond().Handle: elrond.Init(coin.ERD, GetApiVar(coin.ERD)), - coin.Filecoin().Handle: filecoin.Init(GetApiVar(coin.FIL)), + coin.Fio().Handle: fio.Init(config.Default.Fio.API), + coin.Aion().Handle: aion.Init(config.Default.Aion.API), + coin.Icon().Handle: icon.Init(config.Default.Icon.API), + coin.Tron().Handle: tron.Init(config.Default.Tron.API, config.Default.Tron.Explorer), + coin.Nano().Handle: nano.Init(config.Default.Nano.API), + coin.Nimiq().Handle: nimiq.Init(config.Default.Nimiq.API), + coin.Iotex().Handle: iotex.Init(config.Default.Iotex.API), + coin.Theta().Handle: theta.Init(config.Default.Theta.API), + coin.Waves().Handle: waves.Init(config.Default.Waves.API), + coin.Ripple().Handle: ripple.Init(config.Default.Ripple.API), + coin.Harmony().Handle: harmony.Init(config.Default.Harmony.API), + coin.Vechain().Handle: vechain.Init(config.Default.Vechain.API), + coin.Nebulas().Handle: nebulas.Init(config.Default.Nebulas.API), + coin.Ontology().Handle: ontology.Init(config.Default.Ontology.API), + coin.Algorand().Handle: algorand.Init(config.Default.Algorand.API), + coin.Aeternity().Handle: aeternity.Init(config.Default.Aeternity.API), + coin.Solana().Handle: solana.Init(config.Default.Solana.API), + coin.Tezos().Handle: tezos.Init(config.Default.Tezos.API, config.Default.Tezos.RPC), + coin.Binance().Handle: binance.Init(config.Default.Binance.API), + coin.Zilliqa().Handle: zilliqa.Init(config.Default.Zilliqa.API, config.Default.Zilliqa.Key, config.Default.Zilliqa.RPC), + coin.Kusama().Handle: polkadot.Init(coin.KSM, config.Default.Kusama.API), + coin.Polkadot().Handle: polkadot.Init(coin.DOT, config.Default.Polkadot.API), + coin.Stellar().Handle: stellar.Init(coin.XLM, config.Default.Stellar.API), + coin.Kin().Handle: stellar.Init(coin.KIN, config.Default.Kin.API), + coin.Cosmos().Handle: cosmos.Init(coin.ATOM, 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.XZC, 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.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.Bsc().Handle: ethereum.InitWithBlockbook(coin.BSCLegacy, config.Default.BSC.API, config.Default.BSC.RPC), + coin.Smartchain().Handle: ethereum.InitWithBlockbook(coin.BSC, config.Default.Smartchain.API, config.Default.Smartchain.RPC), + coin.Ethereum().Handle: ethereum.InitWithCollection(coin.ETH, config.Default.Ethereum.RPC, 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.ERD, config.Default.Elrond.API), + coin.Filecoin().Handle: filecoin.Init(config.Default.Filecoin.API), } } func getCollectionsHandlers() blockatlas.CollectionsAPIs { return blockatlas.CollectionsAPIs{ - coin.ETH: ethereum.InitWitCollection(coin.ETH, GetRpcVar(coin.ETH), GetVar("ethereum.blockbook_api"), GetVar("ethereum.collections_api"), GetVar("ethereum.collections_api_key")), + coin.ETH: ethereum.InitWithCollection(coin.ETH, config.Default.Ethereum.RPC, config.Default.Ethereum.BlockbookAPI, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey), } } diff --git a/platform/registry.go b/platform/registry.go index 88313bf10..badbce4b8 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -1,9 +1,6 @@ package platform import ( - "fmt" - - "github.com/spf13/viper" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/pkg/logger" ) @@ -58,14 +55,6 @@ func Init(platformHandles []string) { for _, platform := range platformList { handle := platform.Coin().Handle - apiURL := fmt.Sprintf("%s.api", handle) - - if !viper.IsSet(apiURL) { - continue - } - if viper.GetString(apiURL) == "" { - continue - } p := logger.Params{ "platform": handle, From aeaaaa0fbf58479a7b4078ee00be1d90255b354e Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Fri, 30 Oct 2020 17:02:53 +0300 Subject: [PATCH 405/506] [ALL] Simplify (#1264) * Simplify api * Cleanup logs * Remove mock tests * Cleanup scripts * Revert "Remove mock tests" This reverts commit f9cafe57b9156662003c516280ffc5567a349ad7. * Fix mock tests temporary * Cleanup * Add Chart * Add Tilt * Add Prod Resource Request/Limits Co-authored-by: maxUo --- .github/stale.yml | 4 +- .github/workflows/master.yml | 148 ++++--- .github/workflows/pr-build.yml | 113 +++--- .github/workflows/pr-tests.yml | 3 - Makefile | 71 +--- Tiltfile | 27 ++ cmd/api/main.go | 65 ++-- cmd/{notifier => consumer}/main.go | 47 ++- cmd/indexer/main.go | 59 --- cmd/searcher/main.go | 71 ---- cmd/subscriber/main.go | 72 ---- config.yml | 9 - configmock.yml | 9 - db/db.go | 15 +- deployment/charts/blockatlas/.helmignore | 24 ++ deployment/charts/blockatlas/Chart.yaml | 9 + deployment/charts/blockatlas/app-readme.md | 8 + deployment/charts/blockatlas/questions.yml | 0 .../charts/blockatlas/templates/NOTES.txt | 0 .../charts/blockatlas/templates/_helpers.tpl | 52 +++ .../charts/blockatlas/templates/api.yaml | 92 +++++ .../charts/blockatlas/templates/configs.yaml | 13 + .../charts/blockatlas/templates/consumer.yaml | 70 ++++ .../charts/blockatlas/templates/ingress.yaml | 25 ++ .../blockatlas/templates/parser-binance.yaml | 77 ++++ .../blockatlas/templates/parser-bitcoin.yaml | 71 ++++ .../blockatlas/templates/parser-bsc.yaml | 69 ++++ .../blockatlas/templates/parser-classic.yaml | 69 ++++ .../blockatlas/templates/parser-cosmos.yaml | 69 ++++ .../blockatlas/templates/parser-doge.yaml | 69 ++++ .../blockatlas/templates/parser-ethereum.yaml | 69 ++++ .../blockatlas/templates/parser-kava.yaml | 71 ++++ .../blockatlas/templates/parser-litecoin.yaml | 69 ++++ .../blockatlas/templates/parser-other.yaml | 73 ++++ .../blockatlas/templates/parser-ripple.yaml | 69 ++++ .../templates/parser-smartchain.yaml | 69 ++++ .../blockatlas/templates/parser-stellar.yaml | 69 ++++ .../blockatlas/templates/parser-tezos.yaml | 69 ++++ .../blockatlas/templates/parser-tron.yaml | 69 ++++ .../charts/blockatlas/templates/postgres.yaml | 89 +++++ .../charts/blockatlas/templates/rabbitmq.yaml | 95 +++++ .../charts/blockatlas/templates/secrets.yaml | 19 + .../charts/blockatlas/values.local.yaml | 8 + deployment/charts/blockatlas/values.prod.yaml | 137 +++++++ deployment/charts/blockatlas/values.yaml | 75 ++++ scripts/.goreleaser.yml | 67 ---- scripts/run_tests_postman.sh | 10 - services/notifier/base.go | 9 +- services/notifier/delivery.go | 6 +- services/parser/parser.go | 3 - services/subscriber/subscriber.go | 3 - services/subscriber/tokens.go | 4 +- services/subscriber/transactions.go | 4 +- services/tokenindexer/indexer.go | 13 +- services/tokensearcher/tokensearcher.go | 9 +- tests/postman/collection_data.json | 8 - tests/postman/healthcheck_data.json | 4 - tests/postman/market_data.json | 51 --- tests/postman/staking_data.json | 27 -- tests/postman/token_data.json | 38 -- tests/postman/transaction_data.json | 368 ------------------ 61 files changed, 2014 insertions(+), 1090 deletions(-) create mode 100644 Tiltfile rename cmd/{notifier => consumer}/main.go (61%) delete mode 100644 cmd/indexer/main.go delete mode 100644 cmd/searcher/main.go delete mode 100644 cmd/subscriber/main.go create mode 100644 deployment/charts/blockatlas/.helmignore create mode 100644 deployment/charts/blockatlas/Chart.yaml create mode 100644 deployment/charts/blockatlas/app-readme.md create mode 100644 deployment/charts/blockatlas/questions.yml create mode 100644 deployment/charts/blockatlas/templates/NOTES.txt create mode 100644 deployment/charts/blockatlas/templates/_helpers.tpl create mode 100644 deployment/charts/blockatlas/templates/api.yaml create mode 100644 deployment/charts/blockatlas/templates/configs.yaml create mode 100644 deployment/charts/blockatlas/templates/consumer.yaml create mode 100644 deployment/charts/blockatlas/templates/ingress.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-binance.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-bitcoin.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-bsc.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-classic.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-cosmos.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-doge.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-ethereum.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-kava.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-litecoin.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-other.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-ripple.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-smartchain.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-stellar.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-tezos.yaml create mode 100644 deployment/charts/blockatlas/templates/parser-tron.yaml create mode 100644 deployment/charts/blockatlas/templates/postgres.yaml create mode 100644 deployment/charts/blockatlas/templates/rabbitmq.yaml create mode 100644 deployment/charts/blockatlas/templates/secrets.yaml create mode 100644 deployment/charts/blockatlas/values.local.yaml create mode 100644 deployment/charts/blockatlas/values.prod.yaml create mode 100644 deployment/charts/blockatlas/values.yaml delete mode 100644 scripts/.goreleaser.yml delete mode 100644 scripts/run_tests_postman.sh delete mode 100644 services/subscriber/subscriber.go delete mode 100644 tests/postman/collection_data.json delete mode 100644 tests/postman/healthcheck_data.json delete mode 100644 tests/postman/market_data.json delete mode 100644 tests/postman/staking_data.json delete mode 100644 tests/postman/token_data.json delete mode 100644 tests/postman/transaction_data.json diff --git a/.github/stale.yml b/.github/stale.yml index 3ce7f764e..406105238 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,5 +1,5 @@ # Number of days of inactivity before an issue becomes stale -daysUntilStale: 90 +daysUntilStale: 5 # Number of days of inactivity before a stale issue is closed daysUntilClose: 7 # Issues with these labels will never be considered stale @@ -14,4 +14,4 @@ markComment: > recent activity. It will be closed if no further activity occurs. Thank you for your contributions. # Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false \ No newline at end of file +closeComment: false diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index eb61c5f55..fd035a893 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -57,94 +57,82 @@ jobs: - name: Integration Test run: make integration - - name: Mock Test - run: make newman-mocked - build: name: Build runs-on: ubuntu-latest steps: - - name: Set up Go 1.x - uses: actions/setup-go@v2 - with: - go-version: ^1.13 - id: go - - - name: Check out code into the Go module directory - uses: actions/checkout@v2 - with: + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + with: ref: ${{ github.head_ref }} - - name: Get short commit hash - id: hash - run: echo "::set-output name=sha7::$(echo $(git rev-parse --short HEAD) | cut -c1-7)" - - - name: Show short hash - run: | - echo ${{ steps.hash.outputs.sha7 }} - - - name: Get dependencies - run: | - go get -v -t -d ./... - - - name: Swagger - run: make swag - - - name: Build - run: make go-build - - - name: Check user permission - id: check_for_build - uses: scherermichael-oss/action-has-permission@master - with: - required-permission: write - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Login to DockerHub Registry - if: steps.check_for_build.outputs.has-permission - run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin - - - name: Docker Build & Push Release Images - if: steps.check_for_build.outputs.has-permission - env: - API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} - PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} - OBSERVER_SUBSCRIBER_IMAGE: ${{ secrets.REGISTRY }}:subscriber-${{ steps.hash.outputs.sha7 }} - OBSERVER_NOTIFIER_IMAGE: ${{ secrets.REGISTRY }}:notifier-${{ steps.hash.outputs.sha7 }} - SEARCHER_IMAGE: ${{ secrets.REGISTRY }}:searcher-${{ steps.hash.outputs.sha7 }} - INDEXER_IMAGE: ${{ secrets.REGISTRY }}:indexer-${{ steps.hash.outputs.sha7 }} - run: | - docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . - docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . - docker build --build-arg SERVICE=subscriber/subscriber -f Dockerfile.runner -t $OBSERVER_SUBSCRIBER_IMAGE . - docker build --build-arg SERVICE=notifier/notifier -f Dockerfile.runner -t $OBSERVER_NOTIFIER_IMAGE . - docker build --build-arg SERVICE=searcher/searcher -f Dockerfile.runner -t $SEARCHER_IMAGE . - docker build --build-arg SERVICE=indexer/indexer -f Dockerfile.runner -t $INDEXER_IMAGE . - docker push $API_IMAGE - docker push $PARSER_IMAGE - docker push $OBSERVER_SUBSCRIBER_IMAGE - docker push $OBSERVER_NOTIFIER_IMAGE - docker push $SEARCHER_IMAGE - docker push $INDEXER_IMAGE + - name: Get short commit hash + id: hash + run: echo "::set-output name=sha7::$(echo $(git rev-parse --short HEAD) | cut -c1-7)" + + - name: Show short hash + run: | + echo ${{ steps.hash.outputs.sha7 }} + + - name: Get dependencies + run: | + go get -v -t -d ./... + + - name: Swagger + run: make swag + + - name: Build + run: make go-build + + - name: Check user permission + id: check_for_build + uses: scherermichael-oss/action-has-permission@master + with: + required-permission: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to DockerHub Registry + if: steps.check_for_build.outputs.has-permission + run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin + + - name: Docker Build & Push Release Images + if: steps.check_for_build.outputs.has-permission + env: + API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} + PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} + CONSUMER_IMAGE: ${{ secrets.REGISTRY }}:consumer-${{ steps.hash.outputs.sha7 }} + run: | + docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . + docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . + docker build --build-arg SERVICE=consumer/consumer -f Dockerfile.runner -t $CONSUMER_IMAGE . + docker push $API_IMAGE + docker push $PARSER_IMAGE + docker push $CONSUMER_IMAGE deploy: name: CD runs-on: ubuntu-latest - needs: [test, integration, build] + needs: [ test, integration, build ] steps: - - name: Check user permission - id: check_for_deploy - uses: scherermichael-oss/action-has-permission@master - with: - required-permission: write - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: CD Trigger - if: github.ref == 'refs/heads/master' && steps.check_for_deploy.outputs.has-permission - uses: Azure/pipelines@releases/v1 - with: - azure-devops-project-url: 'https://dev.azure.com/TrustWallet/Trust%20BlockAtlas' - azure-pipeline-name: 'AutomaticCD' - azure-devops-token: '${{ secrets.AZURE_DEVOPS_TOKEN }}' + - name: Check user permission + id: check_for_deploy + uses: scherermichael-oss/action-has-permission@master + with: + required-permission: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: CD Trigger + if: github.ref == 'refs/heads/master' && steps.check_for_deploy.outputs.has-permission + uses: Azure/pipelines@releases/v1 + with: + azure-devops-project-url: 'https://dev.azure.com/TrustWallet/Trust%20BlockAtlas' + azure-pipeline-name: 'AutomaticCD' + azure-devops-token: '${{ secrets.AZURE_DEVOPS_TOKEN }}' diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 25e746753..780598632 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -9,73 +9,64 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - name: Check user permission - id: check - uses: scherermichael-oss/action-has-permission@master - with: - required-permission: write - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up Go 1.x - if: steps.check.outputs.has-permission - uses: actions/setup-go@v2 - with: - go-version: ^1.13 - id: go + - name: Check user permission + id: check + uses: scherermichael-oss/action-has-permission@master + with: + required-permission: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Check out code into the Go module directory - if: steps.check.outputs.has-permission - uses: actions/checkout@v2 - with: + - name: Set up Go 1.x + if: steps.check.outputs.has-permission + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code into the Go module directory + if: steps.check.outputs.has-permission + uses: actions/checkout@v2 + with: ref: ${{ github.head_ref }} - - name: Get short commit hash - if: steps.check.outputs.has-permission - id: hash - run: echo "::set-output name=sha7::$(echo $(git rev-parse --short HEAD) | cut -c1-7)" + - name: Get short commit hash + if: steps.check.outputs.has-permission + id: hash + run: echo "::set-output name=sha7::$(echo $(git rev-parse --short HEAD) | cut -c1-7)" - - name: Show short hash - if: steps.check.outputs.has-permission - run: | - echo ${{ steps.hash.outputs.sha7 }} + - name: Show short hash + if: steps.check.outputs.has-permission + run: | + echo ${{ steps.hash.outputs.sha7 }} - - name: Get dependencies - if: steps.check.outputs.has-permission - run: | - go get -v -t -d ./... + - name: Get dependencies + if: steps.check.outputs.has-permission + run: | + go get -v -t -d ./... - - name: Swagger - if: steps.check.outputs.has-permission - run: make swag + - name: Swagger + if: steps.check.outputs.has-permission + run: make swag - - name: Build - if: steps.check.outputs.has-permission - run: make go-build + - name: Build + if: steps.check.outputs.has-permission + run: make go-build - - name: Login to DockerHub Registry - if: steps.check.outputs.has-permission - run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin + - name: Login to DockerHub Registry + if: steps.check.outputs.has-permission + run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin - - name: Docker Build & Push Release Images - if: steps.check.outputs.has-permission - env: - API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} - PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} - OBSERVER_SUBSCRIBER_IMAGE: ${{ secrets.REGISTRY }}:subscriber-${{ steps.hash.outputs.sha7 }} - OBSERVER_NOTIFIER_IMAGE: ${{ secrets.REGISTRY }}:notifier-${{ steps.hash.outputs.sha7 }} - SEARCHER_IMAGE: ${{ secrets.REGISTRY }}:searcher-${{ steps.hash.outputs.sha7 }} - INDEXER_IMAGE: ${{ secrets.REGISTRY }}:indexer-${{ steps.hash.outputs.sha7 }} - run: | - docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . - docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . - docker build --build-arg SERVICE=subscriber/subscriber -f Dockerfile.runner -t $OBSERVER_SUBSCRIBER_IMAGE . - docker build --build-arg SERVICE=notifier/notifier -f Dockerfile.runner -t $OBSERVER_NOTIFIER_IMAGE . - docker build --build-arg SERVICE=searcher/searcher -f Dockerfile.runner -t $SEARCHER_IMAGE . - docker build --build-arg SERVICE=indexer/indexer -f Dockerfile.runner -t $INDEXER_IMAGE . - docker push $API_IMAGE - docker push $PARSER_IMAGE - docker push $OBSERVER_SUBSCRIBER_IMAGE - docker push $OBSERVER_NOTIFIER_IMAGE - docker push $SEARCHER_IMAGE - docker push $INDEXER_IMAGE + - name: Docker Build & Push Release Images + if: steps.check.outputs.has-permission + env: + API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} + PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} + CONSUMER_IMAGE: ${{ secrets.REGISTRY }}:consumer-${{ steps.hash.outputs.sha7 }} + run: | + docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . + docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . + docker build --build-arg SERVICE=consumer/consumer -f Dockerfile.runner -t $CONSUMER_IMAGE . + docker push $API_IMAGE + docker push $PARSER_IMAGE + docker push $CONSUMER_IMAGE diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index 0476831d4..196b53885 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -50,6 +50,3 @@ jobs: - name: Integration Test run: make integration - - - name: Mock Test - run: make newman-mocked diff --git a/Makefile b/Makefile index 459d275ff..027294663 100644 --- a/Makefile +++ b/Makefile @@ -7,11 +7,8 @@ BUILD := $(shell git rev-parse --short HEAD) DATETIME := $(shell date +"%Y.%m.%d-%H:%M:%S") PROJECT_NAME := $(shell basename "$(PWD)") API := api -NOTIFIER := notifier +CONSUMER := consumer PARSER := parser -SUBSCRIBER := subscriber -SEARCHER := searcher -INDEXER := indexer COIN_FILE := coin/coins.yml COIN_GO_FILE := coin/coins.go GEN_COIN_FILE := coin/gen.go @@ -44,11 +41,8 @@ STDERR := /tmp/.$(PROJECT_NAME)-stderr.txt # PID file will keep the process id of the server PID_API := /tmp/.$(PROJECT_NAME).$(API).pid -PID_SEARCHER := /tmp/.$(PROJECT_NAME).$(SEARCHER).pid -PID_INDEXER := /tmp/.$(PROJECT_NAME).$(INDEXER).pid -PID_NOTIFIER := /tmp/.$(PROJECT_NAME).$(NOTIFIER).pid +PID_CONSUMER := /tmp/.$(PROJECT_NAME).$(CONSUMER).pid PID_PARSER := /tmp/.$(PROJECT_NAME).$(PARSER).pid -PID_SUBSCRIBER := /tmp/.$(PROJECT_NAME).$(SUBSCRIBER).pid PID_MOCKSERVER := /tmp/.$(PROJECT_NAME).mockserver.pid # Make is verbose in Linux. Make it silent. MAKEFLAGS += --silent @@ -58,7 +52,7 @@ install: go-get ## start: Start API, Observer and Sync in development mode. start: - @bash -c "$(MAKE) clean compile start-api start-parser start-notifier start-subscriber start-searcher" + @bash -c "$(MAKE) clean compile start-api start-parser start-consumer" ## start-api: Start platform api in development mode. start-api: stop @@ -81,45 +75,20 @@ start-parser: stop @cat $(PID_PARSER) | sed "/^/s/^/ \> Parser PID: /" @echo " > Error log: $(STDERR)" -## start-notifier: Start observer-notifier in development mode. -start-notifier: stop +## start-consumer: Start observer-consumer in development mode. +start-consumer: stop @echo " > Starting $(PROJECT_NAME)" - @-$(GOBIN)/$(NOTIFIER)/notifier -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_NOTIFIER) - @cat $(PID_NOTIFIER) | sed "/^/s/^/ \> Notifier PID: /" - @echo " > Error log: $(STDERR)" - -## start-subscriber: Start observer-subscriber in development mode. -start-subscriber: stop - @echo " > Starting $(PROJECT_NAME)" - @-$(GOBIN)/$(SUBSCRIBER)/subscriber -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SUBSCRIBER) - @cat $(PID_SUBSCRIBER) | sed "/^/s/^/ \> Subscriber PID: /" - @echo " > Error log: $(STDERR)" - -## start-searcher: Start searcher in development mode. -start-searcher: stop - @echo " > Starting $(PROJECT_NAME)" - @-$(GOBIN)/$(SEARCHER)/searcher -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_SEARCHER) - @cat $(PID_SEARCHER) | sed "/^/s/^/ \> Searcher PID: /" - @echo " > Error log: $(STDERR)" - -## start-indexer: Start indexer in development mode. -start-indexer: stop - @echo " > Starting $(PROJECT_NAME)" - @-$(GOBIN)/$(INDEXER)/indexer -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_INDEXER) - @cat $(PID_INDEXER) | sed "/^/s/^/ \> Indexer PID: /" + @-$(GOBIN)/$(CONSUMER)/consumer -c $(CONFIG_FILE) 2>&1 & echo $$! > $(PID_CONSUMER) + @cat $(PID_CONSUMER) | sed "/^/s/^/ \> consumer PID: /" @echo " > Error log: $(STDERR)" ## stop: Stop development mode. stop: - @-touch $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_MOCKSERVER) $(PID_SEARCHER) + @-touch $(PID_API) $(PID_CONSUMER) $(PID_PARSER) @-kill `cat $(PID_API)` 2> /dev/null || true - @-kill `cat $(PID_NOTIFIER)` 2> /dev/null || true + @-kill `cat $(PID_CONSUMER)` 2> /dev/null || true @-kill `cat $(PID_PARSER)` 2> /dev/null || true - @-kill `cat $(PID_SUBSCRIBER)` 2> /dev/null || true - @-kill `cat $(PID_MOCKSERVER)` 2> /dev/null || true - @-kill `cat $(PID_SEARCHER)` 2> /dev/null || true - @-kill `cat $(PID_INDEXER)` 2> /dev/null || true - @-rm $(PID_API) $(PID_NOTIFIER) $(PID_PARSER) $(PID_SUBSCRIBER) $(PID_INDEXER) $(PID_MOCKSERVER) $(PID_SEARCHER) + @-rm $(PID_API) $(PID_CONSUMER) $(PID_PARSER) stop-mockserver: @-touch $(PID_MOCKSERVER) @@ -237,7 +206,7 @@ endif go-compile: go-get go-build -go-build: go-build-api go-build-notifier go-build-parser go-build-subscriber go-build-searcher go-build-indexer +go-build: go-build-api go-build-consumer go-build-parser docker-shutdown: @echo " > Shutdown docker containers..." @@ -253,26 +222,14 @@ go-build-api: @echo " > Building api binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(API)/api ./cmd/$(API) -go-build-notifier: - @echo " > Building notifier binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(NOTIFIER)/notifier ./cmd/$(NOTIFIER) +go-build-consumer: + @echo " > Building consumer binary..." + GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(CONSUMER)/consumer ./cmd/$(CONSUMER) go-build-parser: @echo " > Building parser binary..." GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(PARSER)/parser ./cmd/$(PARSER) -go-build-subscriber: - @echo " > Building subscriber binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SUBSCRIBER)/subscriber ./cmd/$(SUBSCRIBER) - -go-build-searcher: - @echo " > Building searcher binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(SEARCHER)/searcher ./cmd/$(SEARCHER) - -go-build-indexer: - @echo " > Building indexer binary..." - GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(INDEXER)/indexer ./cmd/$(INDEXER) - go-generate: @echo " > Generating dependency files..." GOBIN=$(GOBIN) go generate $(generate) diff --git a/Tiltfile b/Tiltfile new file mode 100644 index 000000000..068ea08e1 --- /dev/null +++ b/Tiltfile @@ -0,0 +1,27 @@ +# -*- mode: Python -*- + +local_resource( + 'lint+tests', + 'make go-lint && make go-test && go-integration', + trigger_mode=TRIGGER_MODE_MANUAL, auto_init=False +) + +docker_build("trust/blockatlas:api-local", ".", build_args={"SERVICE":"api"}) +docker_build("trust/blockatlas:parser-local", ".", build_args={"SERVICE":"parser"}) +docker_build("trust/blockatlas:consumer-local", ".", build_args={"SERVICE":"consumer"}) + +yaml = helm( + 'deployment/charts/blockatlas', + name='local', + namespace='tilt-blockatlas-local', + values=['./deployment/charts/blockatlas/values.local.yaml'] +) + +# k8s namespace bootstrap +local('kubectl create namespace tilt-blockatlas-local || echo 1') + +k8s_yaml(yaml) +k8s_resource('api', port_forwards=8420) + +k8s_resource('postgres', port_forwards=8586) +k8s_resource('rabbitmq', port_forwards='9596:15672') diff --git a/cmd/api/main.go b/cmd/api/main.go index e6e5bf74a..87eccb641 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -2,11 +2,9 @@ package main import ( "context" - "github.com/trustwallet/blockatlas/config" - "time" - "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/api" + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/db" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" @@ -16,6 +14,7 @@ import ( "github.com/trustwallet/blockatlas/services/spamfilter" "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" + "time" ) const ( @@ -31,7 +30,6 @@ var ( database *db.Instance ts tokensearcher.Instance ti tokenindexer.Instance - restAPI string ) func init() { @@ -45,48 +43,37 @@ func init() { platform.Init(config.Default.Platform) spamfilter.SpamList = config.Default.SpamWords - if restAPI == "tokens" || restAPI == "all" { - var err error - database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, - config.Default.Postgres.Log) - if err != nil { - logger.Fatal(err) - } - go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) + var err error + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, + config.Default.Postgres.Log) + if err != nil { + logger.Fatal(err) + } + go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) - internal.InitRabbitMQ( - config.Default.Observer.Rabbitmq.URL, - config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, - ) + internal.InitRabbitMQ( + config.Default.Observer.Rabbitmq.URL, + config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, + ) - if err := mq.TokensRegistration.Declare(); err != nil { - logger.Fatal(err) - } - if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { - logger.Fatal(err) - } + if err := mq.TokensRegistration.Declare(); err != nil { + logger.Fatal(err) + } + if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { + logger.Fatal(err) + } - ts = tokensearcher.Init(database, platform.TokensAPIs, mq.TokensRegistration) - ti = tokenindexer.Init(database) + ts = tokensearcher.Init(database, platform.TokensAPIs, mq.TokensRegistration) + ti = tokenindexer.Init(database) - go mq.FatalWorker(time.Second * 10) - } + go mq.FatalWorker(time.Second * 10) } func main() { - switch restAPI { - case "swagger": - api.SetupSwaggerAPI(engine) - case "platform": - api.SetupPlatformAPI(engine) - case "tokens": - api.SetupTokensSearcherAPI(engine, ts) - default: - api.SetupTokensIndexAPI(engine, ti) - api.SetupTokensSearcherAPI(engine, ts) - api.SetupSwaggerAPI(engine) - api.SetupPlatformAPI(engine) - } + api.SetupTokensIndexAPI(engine, ti) + api.SetupTokensSearcherAPI(engine, ts) + api.SetupSwaggerAPI(engine) + api.SetupPlatformAPI(engine) internal.SetupGracefulShutdown(ctx, port, engine) cancel() diff --git a/cmd/notifier/main.go b/cmd/consumer/main.go similarity index 61% rename from cmd/notifier/main.go rename to cmd/consumer/main.go index 5e85d605b..6923f7739 100644 --- a/cmd/notifier/main.go +++ b/cmd/consumer/main.go @@ -3,13 +3,16 @@ package main import ( "context" "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/services/notifier" + "github.com/trustwallet/blockatlas/services/subscriber" + "github.com/trustwallet/blockatlas/services/tokensearcher" "time" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/services/notifier" + "github.com/trustwallet/blockatlas/services/tokenindexer" ) const ( @@ -34,14 +37,6 @@ func init() { config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, ) - if err := mq.RawTransactions.Declare(); err != nil { - logger.Fatal(err) - } - - if err := mq.TxNotifications.Declare(); err != nil { - logger.Fatal(err) - } - var err error database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, config.Default.Postgres.Log) @@ -50,23 +45,37 @@ func init() { } go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) - limit := config.Default.Observer.PushNotificationsBatchLimit - if limit == 0 { - notifier.MaxPushNotificationsBatchLimit = notifier.DefaultPushNotificationsBatchLimit - } else { - notifier.MaxPushNotificationsBatchLimit = uint(limit) - } - - logger.Info("maxPushNotificationsBatchLimit ", - logger.Params{"limit": notifier.MaxPushNotificationsBatchLimit}) - time.Sleep(time.Millisecond) } func main() { defer mq.Close() + if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { + logger.Fatal(err) + } + if err := mq.RawTransactions.Declare(); err != nil { + logger.Fatal(err) + } + if err := mq.TxNotifications.Declare(); err != nil { + logger.Fatal(err) + } + if err := mq.RawTransactionsSearcher.Declare(); err != nil { + logger.Fatal(err) + } + if err := mq.Subscriptions.Declare(); err != nil { + logger.Fatal(err) + } + if err := mq.TokensRegistration.Declare(); err != nil { + logger.Fatal(err) + } + + go mq.RawTransactionsTokenIndexer.RunConsumerWithCancelAndDbConn(tokenindexer.RunTokenIndexer, database, ctx) go mq.RawTransactions.RunConsumerWithCancelAndDbConn(notifier.RunNotifier, database, ctx) + go mq.RawTransactionsSearcher.RunConsumerWithCancelAndDbConn(tokensearcher.Run, database, ctx) + go mq.Subscriptions.RunConsumerWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, database, ctx) + go mq.TokensRegistration.RunConsumerWithCancelAndDbConn(subscriber.RunTokensSubscriber, database, ctx) + go mq.FatalWorker(time.Second * 10) internal.SetupGracefulShutdownForObserver() diff --git a/cmd/indexer/main.go b/cmd/indexer/main.go deleted file mode 100644 index 87c258dcc..000000000 --- a/cmd/indexer/main.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "context" - "github.com/trustwallet/blockatlas/config" - "time" - - "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/services/tokenindexer" -) - -const ( - defaultConfigPath = "../../config.yml" -) - -var ( - ctx context.Context - cancel context.CancelFunc - database *db.Instance -) - -func init() { - ctx, cancel = context.WithCancel(context.Background()) - _, confPath := internal.ParseArgs("", defaultConfigPath) - - internal.InitConfig(confPath) - logger.InitLogger() - - internal.InitRabbitMQ( - config.Default.Observer.Rabbitmq.URL, - config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, - ) - - var err error - database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, - config.Default.Postgres.Log) - if err != nil { - logger.Fatal(err) - } - go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) - - time.Sleep(time.Millisecond) -} - -func main() { - defer mq.Close() - - if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { - logger.Fatal(err) - } - go mq.RawTransactionsTokenIndexer.RunConsumerWithCancelAndDbConn(tokenindexer.RunTokenIndexer, database, ctx) - go mq.FatalWorker(time.Second * 10) - - internal.SetupGracefulShutdownForObserver() - cancel() -} diff --git a/cmd/searcher/main.go b/cmd/searcher/main.go deleted file mode 100644 index b0a8bb078..000000000 --- a/cmd/searcher/main.go +++ /dev/null @@ -1,71 +0,0 @@ -package main - -import ( - "context" - "github.com/trustwallet/blockatlas/config" - "time" - - "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/services/notifier" - "github.com/trustwallet/blockatlas/services/tokensearcher" -) - -const ( - defaultConfigPath = "../../config.yml" -) - -var ( - ctx context.Context - cancel context.CancelFunc - database *db.Instance -) - -func init() { - ctx, cancel = context.WithCancel(context.Background()) - _, confPath := internal.ParseArgs("", defaultConfigPath) - - internal.InitConfig(confPath) - logger.InitLogger() - - internal.InitRabbitMQ( - config.Default.Observer.Rabbitmq.URL, - config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, - ) - - if err := mq.RawTransactionsSearcher.Declare(); err != nil { - logger.Fatal(err) - } - - var err error - database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, - config.Default.Postgres.Log) - if err != nil { - logger.Fatal(err) - } - go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) - - limit := config.Default.Observer.PushNotificationsBatchLimit - if limit == 0 { - notifier.MaxPushNotificationsBatchLimit = notifier.DefaultPushNotificationsBatchLimit - } else { - notifier.MaxPushNotificationsBatchLimit = uint(limit) - } - - logger.Info("maxPushNotificationsBatchLimit ", - logger.Params{"limit": notifier.MaxPushNotificationsBatchLimit}) - - time.Sleep(time.Millisecond) -} - -func main() { - defer mq.Close() - - go mq.RawTransactionsSearcher.RunConsumerWithCancelAndDbConn(tokensearcher.Run, database, ctx) - go mq.FatalWorker(time.Second * 10) - - internal.SetupGracefulShutdownForObserver() - cancel() -} diff --git a/cmd/subscriber/main.go b/cmd/subscriber/main.go deleted file mode 100644 index c4c95784f..000000000 --- a/cmd/subscriber/main.go +++ /dev/null @@ -1,72 +0,0 @@ -package main - -import ( - "context" - "github.com/trustwallet/blockatlas/config" - "time" - - "github.com/trustwallet/blockatlas/db" - _ "github.com/trustwallet/blockatlas/docs" - "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/logger" - "github.com/trustwallet/blockatlas/services/subscriber" -) - -const ( - defaultConfigPath = "../../config.yml" -) - -var ( - ctx context.Context - cancel context.CancelFunc - database *db.Instance -) - -func init() { - ctx, cancel = context.WithCancel(context.Background()) - _, confPath := internal.ParseArgs("", defaultConfigPath) - - internal.InitConfig(confPath) - logger.InitLogger() - - internal.InitRabbitMQ( - config.Default.Observer.Rabbitmq.URL, - config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, - ) - - var err error - database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, - config.Default.Postgres.Log) - if err != nil { - logger.Fatal(err) - } - go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) - - time.Sleep(time.Millisecond) -} - -func main() { - defer mq.Close() - if err := mq.Subscriptions.Declare(); err != nil { - logger.Fatal(err) - } - if err := mq.TokensRegistration.Declare(); err != nil { - logger.Fatal(err) - } - - subscriberType := subscriber.Subscriber(config.Default.Subscriber) - switch subscriberType { - case subscriber.Tokens: - go mq.TokensRegistration.RunConsumerWithCancelAndDbConn(subscriber.RunTokensSubscriber, database, ctx) - case subscriber.Notifications: - go mq.Subscriptions.RunConsumerWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, database, ctx) - default: - logger.Fatal("bad subscriber: " + subscriberType) - } - - go mq.FatalWorker(time.Second * 10) - - internal.SetupGracefulShutdownForObserver() - cancel() -} diff --git a/config.yml b/config.yml index aa7f8139e..e9e91b9a5 100644 --- a/config.yml +++ b/config.yml @@ -2,23 +2,14 @@ gin: # Possible values: "debug", "release" mode: release - # App running behind a reverse proxy? - # If set, HTTP Forwarded headers will be respected - reverse_proxy: false # If all - run all platforms in one binary. You can pick specific coin handle to run binary only with specific coin # Example: ethereum # You can see all the coin handles at coins/coins.yml file platform: [ all ] -# Can be platform or swagger, or tokens, or all -rest_api: all - spam_words: [ "airdrop","www", "http" ] -# Can be tokens or notifications -subscriber: tokens - # The transaction watcher observer: # Don't request blocks older than this diff --git a/configmock.yml b/configmock.yml index 858869e44..47e22bca3 100644 --- a/configmock.yml +++ b/configmock.yml @@ -1,21 +1,12 @@ # Gin is the web framework gin: - # Possible values: "debug", "release" - login: admin - pass: pass mode: release - # App running behind a reverse proxy? - # If set, HTTP Forwarded headers will be respected - reverse_proxy: false # If all - run all platforms in one binary. You can pick specific coin handle to run binary only with specific coin # Example: ethereum # You can see all the coin handles at coins/coins.yml file platform: all -# Can be platform or swagger, or tokens, or all -rest_api: platform - spam_words: [ "airdrop","www", "http" ] # The transaction watcher diff --git a/db/db.go b/db/db.go index 578113afa..07d1dabbe 100644 --- a/db/db.go +++ b/db/db.go @@ -3,8 +3,6 @@ package db import ( "context" "errors" - "log" - "os" "time" "github.com/trustwallet/blockatlas/db/models" @@ -12,8 +10,6 @@ import ( gocache "github.com/patrickmn/go-cache" - gormlogger "gorm.io/gorm/logger" - "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/plugin/dbresolver" @@ -30,16 +26,7 @@ const batchCount = 3000 func New(uri, readUri string, logMode bool) (*Instance, error) { cfg := &gorm.Config{} - if logMode { - cfg.Logger = gormlogger.New( - log.New(os.Stdout, "\r\n", log.LstdFlags), - gormlogger.Config{ - SlowThreshold: time.Second, - LogLevel: gormlogger.Info, - Colorful: false, - }, - ) - } + db, err := gorm.Open(postgres.Open(uri), cfg) if err != nil { return nil, err diff --git a/deployment/charts/blockatlas/.helmignore b/deployment/charts/blockatlas/.helmignore new file mode 100644 index 000000000..2d0e3933a --- /dev/null +++ b/deployment/charts/blockatlas/.helmignore @@ -0,0 +1,24 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +values.local.yaml +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/deployment/charts/blockatlas/Chart.yaml b/deployment/charts/blockatlas/Chart.yaml new file mode 100644 index 000000000..cef514680 --- /dev/null +++ b/deployment/charts/blockatlas/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +name: blockatlas +description: A Blockatlas chart for Kubernetes + +type: application + +version: 0.0.1 + +appVersion: 2 diff --git a/deployment/charts/blockatlas/app-readme.md b/deployment/charts/blockatlas/app-readme.md new file mode 100644 index 000000000..876bcde2b --- /dev/null +++ b/deployment/charts/blockatlas/app-readme.md @@ -0,0 +1,8 @@ +### blockatlas Chart + +# Local development with Tilt + +1. Install [Tilt](https://docs.tilt.dev/install.html) +2. Install [Docker+Kubernetes](https://docs.docker.com/docker-for-mac/#kubernetes) +3. Install [Helm3](https://helm.sh/docs/intro/install/) +4. Run tilt with `tilt up` \ No newline at end of file diff --git a/deployment/charts/blockatlas/questions.yml b/deployment/charts/blockatlas/questions.yml new file mode 100644 index 000000000..e69de29bb diff --git a/deployment/charts/blockatlas/templates/NOTES.txt b/deployment/charts/blockatlas/templates/NOTES.txt new file mode 100644 index 000000000..e69de29bb diff --git a/deployment/charts/blockatlas/templates/_helpers.tpl b/deployment/charts/blockatlas/templates/_helpers.tpl new file mode 100644 index 000000000..4bbce4c18 --- /dev/null +++ b/deployment/charts/blockatlas/templates/_helpers.tpl @@ -0,0 +1,52 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "blockatlas.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "blockatlas.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "blockatlas.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "blockatlas.labels" -}} +helm.sh/chart: {{ include "blockatlas.chart" . }} +{{ include "blockatlas.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "blockatlas.selectorLabels" -}} +app.kubernetes.io/name: {{ include "blockatlas.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/deployment/charts/blockatlas/templates/api.yaml b/deployment/charts/blockatlas/templates/api.yaml new file mode 100644 index 000000000..596207185 --- /dev/null +++ b/deployment/charts/blockatlas/templates/api.yaml @@ -0,0 +1,92 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: api + namespace: {{ .Release.Namespace }} + labels: + app: api + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.apiReplicaCount }} + selector: + matchLabels: + name: api + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + type: RollingUpdate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + name: api + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-api + - name: PLATFORM + value: all + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:api-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: api + ports: + - containerPort: 8420 + name: http + protocol: TCP + resources: + {{- toYaml .Values.apiResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: api + namespace: {{ .Release.Namespace }} + labels: + {{- include "blockatlas.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: 8420 + protocol: TCP + name: http + selector: + name: api \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/configs.yaml b/deployment/charts/blockatlas/templates/configs.yaml new file mode 100644 index 000000000..5d297cc6f --- /dev/null +++ b/deployment/charts/blockatlas/templates/configs.yaml @@ -0,0 +1,13 @@ +{{- if .Values.config.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: configs + namespace: {{ .Release.Namespace }} +data: + {{- range $k, $v := .Values.configs }} + {{- range $kk, $vv := $v }} + {{ $kk }}: {{ $vv | quote }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/consumer.yaml b/deployment/charts/blockatlas/templates/consumer.yaml new file mode 100644 index 000000000..ad01eae99 --- /dev/null +++ b/deployment/charts/blockatlas/templates/consumer.yaml @@ -0,0 +1,70 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: consumer + namespace: {{ .Release.Namespace }} + labels: + app: consumer + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.consumerReplicaCount }} + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + type: RollingUpdate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-consumer + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:consumer-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: consumer + resources: + {{- toYaml .Values.consumerResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/ingress.yaml b/deployment/charts/blockatlas/templates/ingress.yaml new file mode 100644 index 000000000..da403232b --- /dev/null +++ b/deployment/charts/blockatlas/templates/ingress.yaml @@ -0,0 +1,25 @@ +{{- if .Values.ingress.enabled -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: api + namespace: {{ .Release.Namespace }} + labels: + chart: {{ template "blockatlas.chart" . }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + rules: + - host: {{ .Values.ingress.proxyHost | quote }} + http: + paths: + - blockatlas: + serviceName: api + servicePort: 8420 +{{- end }} diff --git a/deployment/charts/blockatlas/templates/parser-binance.yaml b/deployment/charts/blockatlas/templates/parser-binance.yaml new file mode 100644 index 000000000..95db0931a --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-binance.yaml @@ -0,0 +1,77 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-binance + namespace: {{ .Release.Namespace }} + labels: + app: parser-binance + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: binance + - name: OBSERVER_FETCH_BLOCKS_INTERVAL + value: 50ms + - name: OBSERVER_BLOCK_POLL_MIN + value: 5s + - name: OBSERVER_BACKLOG_MAX_BLOCKS + value: "300" + - name: OBSERVER_BACKLOG + value: 10h + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-binance + resources: + {{- toYaml .Values.parserBinanceResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-bitcoin.yaml b/deployment/charts/blockatlas/templates/parser-bitcoin.yaml new file mode 100644 index 000000000..bd415ed07 --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-bitcoin.yaml @@ -0,0 +1,71 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-bitcoin + namespace: {{ .Release.Namespace }} + labels: + app: parser-bitcoin + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: bitcoin + - name: OBSERVER_BLOCK_POLL_MIN + value: 20s + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-bitcoin + resources: + {{- toYaml .Values.parserBitcoinResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-bsc.yaml b/deployment/charts/blockatlas/templates/parser-bsc.yaml new file mode 100644 index 000000000..785924a76 --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-bsc.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-bsc + namespace: {{ .Release.Namespace }} + labels: + app: parser-bsc + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: bsc + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-bsc + resources: + {{- toYaml .Values.parserBscResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-classic.yaml b/deployment/charts/blockatlas/templates/parser-classic.yaml new file mode 100644 index 000000000..206ed1c7b --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-classic.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-classic + namespace: {{ .Release.Namespace }} + labels: + app: parser-classic + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: classic + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-classic + resources: + {{- toYaml .Values.parserClassicResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-cosmos.yaml b/deployment/charts/blockatlas/templates/parser-cosmos.yaml new file mode 100644 index 000000000..c0eefa249 --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-cosmos.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-cosmos + namespace: {{ .Release.Namespace }} + labels: + app: parser-cosmos + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: cosmos + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-cosmos + resources: + {{- toYaml .Values.parserCosmosResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-doge.yaml b/deployment/charts/blockatlas/templates/parser-doge.yaml new file mode 100644 index 000000000..9654ecd3d --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-doge.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-doge + namespace: {{ .Release.Namespace }} + labels: + app: parser-doge + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: doge + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-doge + resources: + {{- toYaml .Values.parserDogeResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-ethereum.yaml b/deployment/charts/blockatlas/templates/parser-ethereum.yaml new file mode 100644 index 000000000..dcfaf88d5 --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-ethereum.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-ethereum + namespace: {{ .Release.Namespace }} + labels: + app: parser-ethereum + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: ethereum + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-ethereum + resources: + {{- toYaml .Values.parserEthereumResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-kava.yaml b/deployment/charts/blockatlas/templates/parser-kava.yaml new file mode 100644 index 000000000..418099d8c --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-kava.yaml @@ -0,0 +1,71 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-kava + namespace: {{ .Release.Namespace }} + labels: + app: parser-kava + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: kava + - name: OBSERVER_FETCH_BLOCKS_INTERVAL + value: 100ms + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-kava + resources: + {{- toYaml .Values.parserKavaResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-litecoin.yaml b/deployment/charts/blockatlas/templates/parser-litecoin.yaml new file mode 100644 index 000000000..b6b4dc9a1 --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-litecoin.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-litecoin + namespace: {{ .Release.Namespace }} + labels: + app: parser-litecoin + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: litecoin + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-litecoin + resources: + {{- toYaml .Values.parserLitecoinResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-other.yaml b/deployment/charts/blockatlas/templates/parser-other.yaml new file mode 100644 index 000000000..611500cf7 --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-other.yaml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-other + namespace: {{ .Release.Namespace }} + labels: + app: parser-other + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: OBSERVER_FETCH_BLOCKS_INTERVAL + value: 500ms + - name: OBSERVER_BLOCK_POLL_MIN + value: 10s + - name: PLATFORM + value: aeternity,aion,algorand,bitcoincash,callisto,dash,decred,digibyte,fio,gochain,groestlcoin,harmony,icon,iotex,kin,nebulas,nimiq,ontology,poa,qtum,ravencoin,solana,theta,thundertoken,tomochain,vechain,viacoin,wanchain,waves,zcash,zcoin,zelcash,zilliqa,filecoin + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-other + resources: + {{- toYaml .Values.parserOtherResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-ripple.yaml b/deployment/charts/blockatlas/templates/parser-ripple.yaml new file mode 100644 index 000000000..085526afc --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-ripple.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-ripple + namespace: {{ .Release.Namespace }} + labels: + app: parser-ripple + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: ripple + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-ripple + resources: + {{- toYaml .Values.parserRippleResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-smartchain.yaml b/deployment/charts/blockatlas/templates/parser-smartchain.yaml new file mode 100644 index 000000000..960758379 --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-smartchain.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-smartchain + namespace: {{ .Release.Namespace }} + labels: + app: parser-smartchain + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: smartchain + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-smartchain + resources: + {{- toYaml .Values.parserSmartchainResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-stellar.yaml b/deployment/charts/blockatlas/templates/parser-stellar.yaml new file mode 100644 index 000000000..edfd9ffbc --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-stellar.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-stellar + namespace: {{ .Release.Namespace }} + labels: + app: parser-stellar + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: stellar + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-stellar + resources: + {{- toYaml .Values.parserStellarResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-tezos.yaml b/deployment/charts/blockatlas/templates/parser-tezos.yaml new file mode 100644 index 000000000..ecb71a948 --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-tezos.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-tezos + namespace: {{ .Release.Namespace }} + labels: + app: parser-tezos + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: tezos + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-tezos + resources: + {{- toYaml .Values.parserTezosResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-tron.yaml b/deployment/charts/blockatlas/templates/parser-tron.yaml new file mode 100644 index 000000000..ac65ebdb0 --- /dev/null +++ b/deployment/charts/blockatlas/templates/parser-tron.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: parser-tron + namespace: {{ .Release.Namespace }} + labels: + app: parser-tron + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "blockatlas.selectorLabels" . | nindent 6 }} + strategy: + type: Recreate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "blockatlas.selectorLabels" . | nindent 8 }} + spec: + containers: + - env: + - name: ELASTIC_APM_SERVICE_NAME + value: blockatlas-parser + - name: PLATFORM + value: tron + envFrom: + - secretRef: + name: secrets + optional: false + - configMapRef: + name: configs + optional: false + image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: parser-tron + resources: + {{- toYaml .Values.parserTronResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/postgres.yaml b/deployment/charts/blockatlas/templates/postgres.yaml new file mode 100644 index 000000000..3fc0f4776 --- /dev/null +++ b/deployment/charts/blockatlas/templates/postgres.yaml @@ -0,0 +1,89 @@ +{{- if .Values.posgtres.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postgres + namespace: {{ .Release.Namespace }} + labels: + app: postgres + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + name: postgres + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + type: RollingUpdate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + name: postgres + spec: + containers: + - env: + - name: POSTGRES_USER + value: user + - name: POSTGRES_PASSWORD + value: pass + - name: POSTGRES_DB + value: blockatlas + image: postgres + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: postgres + ports: + - containerPort: 5432 + name: 5432tcp + protocol: TCP + resources: + {{- toYaml .Values.postgresResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: postgres + namespace: {{ .Release.Namespace }} + labels: + {{- include "blockatlas.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: 5432 + protocol: TCP + name: postgres + selector: + name: postgres +{{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/rabbitmq.yaml b/deployment/charts/blockatlas/templates/rabbitmq.yaml new file mode 100644 index 000000000..2d64babff --- /dev/null +++ b/deployment/charts/blockatlas/templates/rabbitmq.yaml @@ -0,0 +1,95 @@ +{{- if .Values.rabbitmq.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: rabbitmq + namespace: {{ .Release.Namespace }} + labels: + app: rabbitmq + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + name: rabbitmq + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + type: RollingUpdate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + name: rabbitmq + spec: + containers: + - env: + - name: RABBITMQ_DEFAULT_PASS + value: lV7zO3lD + - name: RABBITMQ_DEFAULT_USER + value: user + - name: RABBITMQ_ERLANG_COOKIE + value: someStrongCookie + image: rabbitmq:3-management + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: rabbitmq + ports: + - containerPort: 5672 + name: rabbitmq + protocol: TCP + - containerPort: 15672 + name: ui + protocol: TCP + resources: + {{- toYaml .Values.rabbitmqResources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Always + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: rabbitmq + namespace: {{ .Release.Namespace }} + labels: + {{- include "blockatlas.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: 5672 + protocol: TCP + name: rabbitmq + - port: 15672 + protocol: TCP + name: ui + selector: + name: rabbitmq +{{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/secrets.yaml b/deployment/charts/blockatlas/templates/secrets.yaml new file mode 100644 index 000000000..8cdfa93b2 --- /dev/null +++ b/deployment/charts/blockatlas/templates/secrets.yaml @@ -0,0 +1,19 @@ +{{- if .Values.secret.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: secrets + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "blockatlas.name" . }} + chart: {{ template "blockatlas.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +type: Opaque +data: + {{- range $k, $v := .Values.secrets }} + {{- range $kk, $vv := $v }} + {{ $kk }}: {{ $vv | b64enc }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/values.local.yaml b/deployment/charts/blockatlas/values.local.yaml new file mode 100644 index 000000000..1cfc53324 --- /dev/null +++ b/deployment/charts/blockatlas/values.local.yaml @@ -0,0 +1,8 @@ +image: + repository: trust/blockatlas + tag: local + +secrets: + - OBSERVER_RABBITMQ_URL: amqp://user:lV7zO3lD@rabbitmq:5672 + - POSTGRES_URL: postgresql://user:pass@postgres/blockatlas?sslmode=disable + - POSTGRES_READ_URL: postgresql://user:pass@postgres/blockatlas?sslmode=disable \ No newline at end of file diff --git a/deployment/charts/blockatlas/values.prod.yaml b/deployment/charts/blockatlas/values.prod.yaml new file mode 100644 index 000000000..bcbaa4f8e --- /dev/null +++ b/deployment/charts/blockatlas/values.prod.yaml @@ -0,0 +1,137 @@ +# scaling +apiReplicaCount: 3 + +image: + repository: repositoryToReplace + tag: tagToReplace + +posgtres: + enabled: false +rabbitmq: + enabled: false +config: + enabled: false +secret: + enabled: false + +apiResources: + limits: + cpu: 200m + memory: 300Mi + requests: + cpu: 200m + memory: 300Mi + +consumerResources: + limits: + cpu: 300m + memory: 400Mi + requests: + cpu: 300m + memory: 400Mi + +parserBinanceResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserBitcoinResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserBscResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserClassicResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserCosmosResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserDogeResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserEthereumResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserKavaResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserLitecoinResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserRippleResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserOtherResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserSmartchainResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserStellarResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserTezosResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi +parserTronResources: + limits: + cpu: 30m + memory: 120Mi + requests: + cpu: 10m + memory: 120Mi \ No newline at end of file diff --git a/deployment/charts/blockatlas/values.yaml b/deployment/charts/blockatlas/values.yaml new file mode 100644 index 000000000..e9b04a882 --- /dev/null +++ b/deployment/charts/blockatlas/values.yaml @@ -0,0 +1,75 @@ +# scaling +apiReplicaCount: 1 +consumerReplicaCount: 1 + +image: + repository: repositoryToReplace + pullPolicy: IfNotPresent + tag: tagToReplace + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +# Enable postgres-test deployment. If disabled - provide external postgres connection string. +posgtres: + enabled: true +# Enable rabbitmq-test deployment. If disabled - provide external rabbitmq connection string. +rabbitmq: + enabled: true +# Enable ConfigMap deployment generation. Disable if you need to manually create the ConfigMap later. +config: + enabled: true +# Enable Secret deployment generation. Disable if you need to manually create the Secret later. +secret: + enabled: true + +service: + type: ClusterIP + +ingress: + annotations: + kubernetes.io/ingress.class: nginx + enabled: false + swaggerHost: nginx-swagger.local + proxyHost: nginx-proxy.local + +# Resources request/limit example +# someResources: +# limits: +# cpu: 100m +# memory: 128Mi +# requests: +# cpu: 100m +# memory: 128Mi + +apiResources: {} +postgresResources: {} +rabbitmqResources: {} +parserBinanceResources: {} +consumerResources: {} +parserBitcoinResources: {} +parserBscResources: {} +parserClassicResources: {} +parserCosmosResources: {} +parserDogeResources: {} +parserEthereumResources: {} +parserKavaResources: {} +parserLitecoinResources: {} +parserRippleResources: {} +parserOtherResources: {} +parserSmartchainResources: {} +parserStellarResources: {} +parserTezosResources: {} +parserTronResources: {} + +nodeSelector: {} +tolerations: [] +affinity: {} + +podAnnotations: {} +podSecurityContext: {} +securityContext: {} + +configs: [] +secrets: [] \ No newline at end of file diff --git a/scripts/.goreleaser.yml b/scripts/.goreleaser.yml deleted file mode 100644 index 0a338f976..000000000 --- a/scripts/.goreleaser.yml +++ /dev/null @@ -1,67 +0,0 @@ -before: - hooks: - - git reset --hard - - git checkout . -builds: - - id: api - binary: api - main: "./cmd/api/main.go" - goos: - - linux - goarch: - - amd64 - env: - - CGO_ENABLED=0 - - id: swagger_api - binary: swagger_api - main: "./cmd/swagger_api/main.go" - goos: - - linux - goarch: - - amd64 - env: - - CGO_ENABLED=0 - - id: parser - binary: parser - main: "./cmd/parser/main.go" - goos: - - linux - goarch: - - amd64 - env: - - CGO_ENABLED=0 - - id: subscriber - binary: subscriber - main: "./cmd/subscriber/main.go" - goos: - - linux - goarch: - - amd64 - env: - - CGO_ENABLED=0 - - id: notifier - binary: notifier - main: "./cmd/notifier/main.go" - goos: - - linux - goarch: - - amd64 - env: - - CGO_ENABLED=0 -archives: - - replacements: - amd64: 64-bit - 386: 32-bit - darwin: macOS - linux: Linux - windows: Windows -checksum: - name_template: 'checksums.txt' -snapshot: - name_template: "{{ .Tag }}-next" -changelog: - sort: asc - filters: - exclude: - - '^docs:' - - '^test:' diff --git a/scripts/run_tests_postman.sh b/scripts/run_tests_postman.sh deleted file mode 100644 index 0ca3499c5..000000000 --- a/scripts/run_tests_postman.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -# blockatlas host -HOST=$1 - -cd .. -make newman test=transaction host=$HOST -make newman test=token host=$1 -make newman test=staking host=$1 -make newman test=collection host=$1 -make newman test=observer_test host=$1 diff --git a/services/notifier/base.go b/services/notifier/base.go index dc1d85e9b..4ee0949fc 100644 --- a/services/notifier/base.go +++ b/services/notifier/base.go @@ -11,7 +11,11 @@ import ( "go.elastic.co/apm" ) -const DefaultPushNotificationsBatchLimit = 50 +const ( + DefaultPushNotificationsBatchLimit = 50 + + Notifier = "Notifier" +) var MaxPushNotificationsBatchLimit uint = DefaultPushNotificationsBatchLimit @@ -26,7 +30,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { } }() - txs, err := GetTransactionsFromDelivery(delivery, ctx) + txs, err := GetTransactionsFromDelivery(delivery, Notifier, ctx) if err != nil { logger.Error("failed to get transactions", err) } @@ -64,4 +68,5 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { for _, batch := range batches { publishNotificationBatch(batch, ctx) } + logger.Info("------------------------------------------------------------") } diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index cc5c5c189..028836c13 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -11,7 +11,7 @@ import ( "go.elastic.co/apm" ) -func GetTransactionsFromDelivery(delivery amqp.Delivery, ctx context.Context) (blockatlas.Txs, error) { +func GetTransactionsFromDelivery(delivery amqp.Delivery, service string, ctx context.Context) (blockatlas.Txs, error) { var txs blockatlas.Txs span, _ := apm.StartSpan(ctx, "GetTransactionsFromDelivery", "app") @@ -21,7 +21,7 @@ func GetTransactionsFromDelivery(delivery amqp.Delivery, ctx context.Context) (b return nil, err } - logger.Info("Consumed", logger.Params{"txs": len(txs), "coin": txs[0].Coin}) + logger.Info("Consumed", logger.Params{"service": service, "txs": len(txs), "coin": txs[0].Coin}) if len(txs) == 0 { return nil, errors.E("empty txs list") @@ -44,5 +44,5 @@ func publishNotificationBatch(batch []TransactionNotification, ctx context.Conte logger.Fatal(err) } - logger.Info("Txs batch dispatched", logger.Params{"txs": len(batch)}) + logger.Info("Txs batch dispatched", logger.Params{"service": Notifier, "txs": len(batch)}) } diff --git a/services/parser/parser.go b/services/parser/parser.go index 454cb7a6d..aef53f4c7 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -56,11 +56,8 @@ func RunParser(params Params) { return default: parse(params) - logger.Info("Sleep ...", logger.Params{"interval": params.ParsingBlocksInterval.String()}) time.Sleep(params.ParsingBlocksInterval) - logger.Info("Leaving select") } - logger.Info("Going to the next cycle... ") logger.Info("------------------------------------------------------------") } } diff --git a/services/subscriber/subscriber.go b/services/subscriber/subscriber.go deleted file mode 100644 index 7d9a0aaf2..000000000 --- a/services/subscriber/subscriber.go +++ /dev/null @@ -1,3 +0,0 @@ -package subscriber - -type Subscriber string diff --git a/services/subscriber/tokens.go b/services/subscriber/tokens.go index d5112ef69..fc41ad30f 100644 --- a/services/subscriber/tokens.go +++ b/services/subscriber/tokens.go @@ -18,7 +18,6 @@ func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { defer tx.End() ctx := apm.ContextWithTransaction(context.Background(), tx) - logger.Info("body " + string(delivery.Body)) event := make(map[string][]models.Asset) if err := json.Unmarshal(delivery.Body, &event); err != nil { if err := delivery.Ack(false); err != nil { @@ -31,8 +30,9 @@ func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { logger.Error("Failed to AddAssociationsForAddress: " + err.Error()) } } - logger.Info("Subscribed " + strconv.Itoa(len(event))) + logger.Info("Subscribed "+strconv.Itoa(len(event)), logger.Params{"service": Tokens}) if err := delivery.Ack(false); err != nil { logger.Fatal(err, err) } + logger.Info("------------------------------------------------------------") } diff --git a/services/subscriber/transactions.go b/services/subscriber/transactions.go index 05626ca4a..3f8c4a98f 100644 --- a/services/subscriber/transactions.go +++ b/services/subscriber/transactions.go @@ -11,6 +11,8 @@ import ( "strconv" ) +type Subscriber string + const ( Notifications Subscriber = "notifications" AddSubscription blockatlas.SubscriptionOperation = "AddSubscription" @@ -32,7 +34,7 @@ func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { } subscriptions := event.ParseSubscriptions(event.Subscriptions) - params := logger.Params{"operation": event.Operation, "subscriptions_len": len(subscriptions)} + params := logger.Params{"service": Notifications, "operation": event.Operation, "subscriptions_len": len(subscriptions)} switch event.Operation { case AddSubscription, UpdateSubscription: diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index 8040d3e46..2600437dc 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -11,21 +11,23 @@ import ( "go.elastic.co/apm" ) +const TokenIndexer = "TokenIndexer" + func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) { tx := apm.DefaultTracer.StartTransaction("RunTokenIndexer", "app") defer tx.End() defer func() { if err := delivery.Ack(false); err != nil { - logger.Error(err) + logger.Error(err, logger.Params{"service": TokenIndexer}) } }() ctx := apm.ContextWithTransaction(context.Background(), tx) - txs, err := notifier.GetTransactionsFromDelivery(delivery, ctx) + txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenIndexer, ctx) if err != nil { - logger.Error("failed to get transactions", err) + logger.Error("failed to get transactions", err, logger.Params{"service": TokenIndexer}) if err := delivery.Ack(false); err != nil { - logger.Error(err) + logger.Error(err, logger.Params{"service": TokenIndexer}) } return } @@ -36,9 +38,10 @@ func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) { assets := GetAssetsFromTransactions(txs) err = database.AddNewAssets(assets, ctx) if err != nil { - logger.Error("failed to add assets", err) + logger.Error("failed to add assets", err, logger.Params{"service": TokenIndexer}) return } + logger.Info("------------------------------------------------------------") } func GetAssetsFromTransactions(txs []blockatlas.Tx) []models.Asset { diff --git a/services/tokensearcher/tokensearcher.go b/services/tokensearcher/tokensearcher.go index 555a42cee..78c334e9c 100644 --- a/services/tokensearcher/tokensearcher.go +++ b/services/tokensearcher/tokensearcher.go @@ -10,12 +10,14 @@ import ( "strconv" ) +const TokenSearcher = "TokenSearcher" + func Run(database *db.Instance, delivery amqp.Delivery) { tx := apm.DefaultTracer.StartTransaction("RunNotifier", "app") defer tx.End() ctx := apm.ContextWithTransaction(context.Background(), tx) - txs, err := notifier.GetTransactionsFromDelivery(delivery, ctx) + txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenSearcher, ctx) if err != nil { logger.Error("failed to get transactions", err) if err := delivery.Ack(false); err != nil { @@ -39,11 +41,11 @@ func Run(database *db.Instance, delivery amqp.Delivery) { logger.Error(err) return } - logger.Info("associationsFromTransactions " + strconv.Itoa(len(associationsFromTransactions))) + logger.Info("AssociationsFromTransactions "+strconv.Itoa(len(associationsFromTransactions)), logger.Params{"service": TokenSearcher}) associationsToAdd := associationsToAdd(fromModelToAssociation(associationsFromTransactions), assetsMap(txs, coinID)) - logger.Info("associationsToAdd " + strconv.Itoa(len(associationsToAdd))) + logger.Info("AssociationsToAdd "+strconv.Itoa(len(associationsToAdd)), logger.Params{"service": TokenSearcher}) err = database.UpdateAssociationsForExistingAddresses(associationsToAdd, ctx) if err != nil { logger.Error(err) @@ -53,4 +55,5 @@ func Run(database *db.Instance, delivery amqp.Delivery) { if err := delivery.Ack(false); err != nil { logger.Error(err) } + logger.Info("------------------------------------------------------------") } diff --git a/tests/postman/collection_data.json b/tests/postman/collection_data.json deleted file mode 100644 index 4e09b0163..000000000 --- a/tests/postman/collection_data.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "coin": 60, - "handler": "ethereum", - "address": "0x84E79D544B4b13bC3560069cfD56A9D5bbE7521d", - "collection": "unstoppable-domains" - } -] diff --git a/tests/postman/healthcheck_data.json b/tests/postman/healthcheck_data.json deleted file mode 100644 index da1a058a9..000000000 --- a/tests/postman/healthcheck_data.json +++ /dev/null @@ -1,4 +0,0 @@ -[ - { - } -] diff --git a/tests/postman/market_data.json b/tests/postman/market_data.json deleted file mode 100644 index 061e3356e..000000000 --- a/tests/postman/market_data.json +++ /dev/null @@ -1,51 +0,0 @@ -[ - { - "coin": 60, - "type": "coin", - "currency": "USD" - }, - { - "coin": 0, - "type": "coin", - "currency": "USD" - }, - { - "coin": 2, - "type": "coin", - "currency": "USD" - }, - { - "coin": 195, - "type": "coin", - "currency": "USD" - }, - { - "coin": 714, - "type": "coin", - "currency": "USD" - }, - { - "coin": 714, - "type": "token", - "currency": "USD", - "token_id": "BTCB-1DE" - }, - { - "coin": 195, - "type": "token", - "currency": "USD", - "token_id": "TUL5yxRKeSWvceLZ3BSU5iNJcQmNxkWayh" - }, - { - "coin": 195, - "type": "token", - "currency": "USD", - "token_id": "1002413" - }, - { - "coin": 60, - "type": "token", - "currency": "EUR", - "token_id": "0xeF65887a05415bF6316204b5ffB350d4d1a19BBA" - } -] diff --git a/tests/postman/staking_data.json b/tests/postman/staking_data.json deleted file mode 100644 index 320e2a250..000000000 --- a/tests/postman/staking_data.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "handler": "tron", - "coin": 195, - "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" - }, - { - "handler": "tezos", - "coin": 1729, - "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8" - }, - { - "handler": "kava", - "coin": 459, - "address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m" - }, - { - "handler": "cosmos", - "coin": 118, - "address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq" - }, - { - "handler": "iotex", - "coin": 304, - "address": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" - } -] diff --git a/tests/postman/token_data.json b/tests/postman/token_data.json deleted file mode 100644 index f53b1c75e..000000000 --- a/tests/postman/token_data.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "handler": "tron", - "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB" - }, - { - "handler": "thundertoken", - "address": "0x0b230def08139f18a86536d9cfa150f04435414c" - }, - { - "handler": "tomochain", - "address": "0x8b353021189375591723e7384262f45709a3c3dc" - }, - { - "handler": "callisto", - "address": "0xc3d5b69f65027ddf48f894e6e90121293a2f6615" - }, - { - "handler": "gochain", - "address": "0x0Fd98FB42C439E5F6484f7E71Caa6661d81d0628" - }, - { - "handler": "poa", - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" - }, - { - "handler": "ethereum", - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" - }, - { - "handler": "binance", - "address": "bnb1jeu6gscugy6l2wyatxthkh2hmer4hzevgcmf0q" - }, - { - "handler": "classic", - "address": "0xa12105efa0663147bddee178f6a741ac15676b79" - } -] diff --git a/tests/postman/transaction_data.json b/tests/postman/transaction_data.json deleted file mode 100644 index b594767d7..000000000 --- a/tests/postman/transaction_data.json +++ /dev/null @@ -1,368 +0,0 @@ -[ - { - "handler": "harmony", - "address": "one1e4mr7tp0a76wnhv9xd0wzentdjnjnsh3fwzgfv", - "expectedTxNum": 3, - "expectedTxId": "0x73355f625d0f7ef31512657c0f669e710c8c91a67180cd28bc919cfca0a2af82" - }, - { - "handler": "nano", - "address": "nano_36e7qfxrpixge3xxujtpc87c77mn9ubu3bhywfjkr1trnubtd4qswwydhn9z", - "expectedTxNum": 3, - "expectedTxId": "05A23A254272028F349BB7E74115A5101B2048786A5437D1EBBE8807CEFF1E82" - }, - { - "handler": "algorand", - "address": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", - "expectedTxNum": 1, - "expectedTxId": "JZTKP6RRFGUDOZ7DQIR26DQWRDYZVYG2G3WDE4WLBJ77AMAEBFBA" - }, - { - "handler": "kusama", - "address": "HZaz6cUo8wJ9zjwoDtA3ZzYkrCLfDYU8b3uPmYttKFFvvRK", - "expectedTxNum": 3, - "expectedTxId": "0x9908579abffb409aef95394128f9097f0a21cfdf16675588423e31ab0d3c58e2" - }, - { - "handler": "kava", - "address": "kava1l8va9zyl50cpzv447c694k3jndelc9ygtfll2m", - "expectedTxNum": 2, - "expectedTxId": "30EFE9E830D317F84629F9DC35177577DF6713D78D354C2C469DE633900303BC" - }, - { - "handler": "zilliqa", - "address": "zil1l8ddxvejeam70qang54wnqkgtmlu5mwlgzy64z", - "expectedTxNum": 2, - "expectedTxId": "0xa5d0e0cefd6f114e9659f15016f9f4a303a8367eb373beb6909ee44f7f39834d" - }, - { - "handler": "tomochain", - "address": "0x17e4c16605e32adead5fa371bf6117df34ca0200", - "expectedTxNum": 2, - "expectedTxId": "0xb2af5ad5eebaba1da3452e0281f9b6ec9e00a5bb832793a912eb3959b6c2fdd2" - }, - { - "handler": "ethereum", - "address": "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - "expectedTxNum": 2, - "expectedTxId": "0x2a9fd94735e273526a2cde57c6a19b9d488e0c9a960565c3e19be5e12d4b4b47" - }, - { - "handler": "classic", - "address": "0x7d2d0e153026fb428b885d86de50768d4cfeac37", - "expectedTxNum": 2, - "expectedTxId": "0x8439b360732a43b4bbebe4f00b9f8b2dbe14c6bd52d70598ab7fe6c8503383fe" - }, - { - "handler": "poa", - "address": "0x55798eCbF17ce1241d543c22dCE46134c13b4bc0", - "expectedTxNum": 4, - "expectedTxId": "0x6fbe91787b01664f99ea928fb1a314aed4fcd777a9fae063ed74b838315120c3" - }, - { - "handler": "thundertoken", - "address": "0x0b230def08139f18a86536d9cfa150f04435414c", - "expectedTxNum": 2, - "expectedTxId": "0x80929a2170969364e06d253d2b853fe0b2ca3a307e61d629946b9b76e2f983cf" - }, - { - "handler": "callisto", - "address": "0x3083a7ec44ca2b038d4be4b0798152f948f0f3d7", - "expectedTxNum": 2, - "expectedTxId": "0x4052f55ee615a783abaa22a62100a45d2eee27ecab3a599e9d6691371336463e" - }, - { - "handler": "gochain", - "address": "0xEd7F2e81B0264177e0df8f275f97Fd74Fa51A896", - "expectedTxNum": 2, - "expectedTxId": "0x2637d7b0e7f66134e983e6af921700718b8a49885a9215ee8033ac384d5d1be7" - }, - { - "handler": "theta", - "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - "expectedTxNum": 2, - "expectedTxId": "0x85aaf834470dd858dc2f60c7bd535ddf08c3fcfef9456f43676462950a355b78" - }, - { - "handler": "binance", - "address": "bnb1z35wusfv8twfele77vddclka9z84ugywug48gn", - "expectedTxNum": 1, - "expectedTxId": "0CE23D9F143F7FAF192BB55F33C8FCBC1095D98410A750F63777987685E2C154" - }, - { - "handler": "tezos", - "address": "tz1foWxaV3VQyWqFbWTERS6YDJjPT6C7jPp8", - "expectedTxNum": 2, - "expectedTxId": "ooLrNAP233Qvoz3AGvjRjhk1fjG7z19UfyLEGBm1rwfHn4NSVhd" - }, - { - "handler": "tron", - "address": "TFFriedwRtWdFuzerDDtkoQTZ29smDZ1MB", - "expectedTxNum": 1, - "expectedTxId": "3ef5e225ce5bdd01333286e4ab4413ae3da8b80c24b26c5811ae78962940a8ca" - }, - { - "handler": "vechain", - "address": "0xB5e883349e68aB59307d1604555AC890fAC47128", - "expectedTxNum": 2, - "expectedTxId": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7" - }, - { - "handler": "ripple", - "address": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", - "expectedTxNum": 2, - "expectedTxId": "000BC2AFC047BE45C43886109720F44B6F3F2434D59B1A16A9B2B4FC9B9C5A13" - }, - { - "handler": "cosmos", - "address": "cosmos1dx27g0kzhwej0ekcf2k9hsktcxnmpl7fcehcvq", - "expectedTxNum": 2, - "expectedTxId": "93E43518BAE4BC137605BBB7FD5D31FDAE6427ECE57EC299C43CE786FDAEBC63" - }, - { - "handler": "iotex", - "address": "io1vg808avg2ydye8djl2axmkc9j0xhzu6vdaw6g5", - "expectedTxNum": 1, - "expectedTxId": "7aceeda86535b8dd345e1ab2176a7f12e1907aac3591cf9422a5393feadb6bb6" - }, - { - "handler": "icon", - "address": "hxee691e7bccc4eb11fee922896e9f51490e62b12e", - "expectedTxNum": 3, - "expectedTxId": "0x3b1a382884091e683350d6285d908406c149a030a7d52eb347f4571c1c904382" - }, - { - "handler": "stellar", - "address": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - "expectedTxNum": 2, - "expectedTxId": "2912d519b2c2174b0147a9e02208f3ed14820228913142f8c6a5cd360783c029" - }, - { - "handler": "nimiq", - "address": "NQ94HC9AK9D83FSJM6PT8XGNNMXLR0E53Y07", - "expectedTxNum": 2, - "expectedTxId": "8674d985ac1ea2a75fe9b35ed11d629cef8adfed50db6a5eb125351e622bb405" - }, - { - "handler": "nebulas", - "address": "n1RCYwrpLMpSpUCQ8QUDzGRg6B2PnY8R94a", - "expectedTxNum": 1, - "expectedTxId": "0d06074b64c37ed24a17162d1e0ef8a8e65122fc7758c90c969e61735bc4396a" - }, - { - "handler": "aeternity", - "address": "ak_2WGWYMgWy1opZxgA8AVzGCTavCQyUBtbKx5SrCX6E4kmDZMtJb", - "expectedTxNum": 2, - "expectedTxId": "th_WfeoRYXd13MMmDBzMXjBBdaNSSaRXkwUwJ7tFxJ7ZKPQVNXC4" - }, - { - "handler": "aion", - "address": "0xa04f0117864ccf5013861a89f08c6fc790284d72356c8a362025d31b855ed6ed", - "expectedTxNum": 2, - "expectedTxId": "0x511d3a4aafbdd26825a1655b5c7525df5bea8a8ef0f887d5490b490055b53df7" - }, - { - "handler": "kin", - "address": "GBHKUZ7C2SZ5N3X2S7O6TT6LNUWSEA2BXMSR5GTTSR6VZARSVAXIQNGH", - "expectedTxNum": 2, - "expectedTxId": "b2131beb8e0c57dfd3309914fce08ac4e094c51dc918087171150dd5b996076a" - }, - { - "handler": "ontology", - "address": "AUyL4TZ1zFEcSKDJrjFnD7vsq5iFZMZqT7", - "expectedTxNum": 1, - "expectedTxId": "0ae15301f25a5067c075a25e722f0624a813a1352363197de2dd5f61ebd2998d" - }, - { - "handler": "waves", - "address": "3PJ4q4sqriJs2y7Z45wmbLrbmV9MDecbPxD", - "expectedTxNum": 2, - "expectedTxId": "23JGFzBh65fzZArK6KSeRqjjBG5WnQshJJkUv53hCE1E" - }, - { - "handler": "digibyte", - "address": "address/DEs1RJKuASSjfphFJdxX9eidrjWewMZgAi", - "expectedTxNum": 2, - "expectedTxId": "2b7ba9b43d615fe03bc14bc18201d1bd73c7a0f8aad428accf51725743f9073a" - }, - { - "handler": "digibyte", - "address": "xpub/zpub6ricE56nzsDeTAVo4w68vQQ3tRvR6C18JjKVsgbiRFjEawGV9SuS2gfkpm5qFxjbTNPPuvAA3cqRsxNHxFwVnpYD2Lawjtb3wowbFdwmjow", - "expectedTxNum": 2, - "expectedTxId": "e13c81f4450e43ef8ef10dea8f4f9d53f357266563462df32a7fd61eb71bd190" - }, - { - "handler": "doge", - "address": "address/D5dAUAx3Ezg1q4dRgzKTBsxp4VJietWkDh", - "expectedTxNum": 2, - "expectedTxId": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9" - }, - { - "handler": "doge", - "address": "xpub/dgub8rceyfsEvGDexmvJcBqiKBrmuxWGgYJxHjtbouHTwTfQrCQcMjxyNf6vUPY4dUp23QtReFy6WGedutBk9XUaYNupUqVAZcweqGhfsudUELN", - "expectedTxNum": 2, - "expectedTxId": "8d5fc1e686ff042b4811cb6b2df406b98b2484e973cd663b442c296f2d2f78b9" - }, - { - "handler": "decred", - "address": "address/DsTxPUVFxXeNgu5fzozr4mTR4tqqMaKcvpY", - "expectedTxNum": 2, - "expectedTxId": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0" - }, - { - "handler": "decred", - "address": "xpub/dpubZFf1tYMxcku9nvDRxnYdE4yrEESrkuQFRq5RwA4KoYQKpDSRszN2emePTwLgfQpd4mZHGrHbQkKPZdjH1BcopomXRnr5Gt43rjpNEfeuJLN", - "expectedTxNum": 2, - "expectedTxId": "66e3d1622d4cb3337babf5e5a466f94b6a732e132c802cc219c6e26543d736e0" - }, - { - "handler": "zelcash", - "address": "address/t1JKRwXGfKTGfPV1z48rvoLyabk31z3xwHa", - "expectedTxNum": 2, - "expectedTxId": "58b5ce7d497d95e21ad9ebe2f2a3fb480483f77ca4de3ce1bc9a95eb9c0d18e1" - }, - { - "handler": "zelcash", - "address": "xpub/xpub6C5soBeFd2uZLCcEvsqaoGXuh9UposMMfk2jSiBKMN8rJKs9NLqjPK51gWv9mYBpUY95GtHYsofwpPRdB6FJ56cEaTJGCba5GKv55wPNZNf", - "expectedTxNum": 4, - "expectedTxId": "2de19629bbf78af114ff9cf3332229dc336be4758481b72828f1bd786e8cc41e" - }, - { - "handler": "zcoin", - "address": "address/a8EF4cpenEgEn9hm2NL5KfFK1UmSZZaQVn", - "expectedTxNum": 2, - "expectedTxId": "f1db892b13a2cb34a9a1ed0890b85050c43b95e06dc085d7f063e9207e984609" - }, - { - "handler": "zcoin", - "address": "xpub/xpub6Cgu6WtTyo99pRtTabwscog2ncj4BUbTWzk7bt7habdLYwgnXLEWH3TuR1789QSTPVsPjLMa2KQzHffyZHTkLQQyRxeEBmWHaETS2btF5fK", - "expectedTxNum": 8, - "expectedTxId": "86fb43e30f9bc2a8a6492e67e2b893680526987ae8b5ec56e2587381813927ef" - }, - { - "handler": "zcash", - "address": "address/t1LwLWo1Mo3s4RPtUpeyUD1eYd47inL3bwX", - "expectedTxNum": 2, - "expectedTxId": "ca640e5215e141a4f9c235dd91e4b99fd1e0defdd5da27d78ec2cee02d3493dc" - }, - { - "handler": "zcash", - "address": "xpub/xpub6CCXGBJ13akWuKSn4iU7CqQeXzLyDC2Y1Z83Mmg2xz11PX2EeZJJKRECz29iN4eHewRh8yfb7FpnCcjYbkqn6ynHnXW3jczPcJcenThfFeS", - "expectedTxNum": 2, - "expectedTxId": "f2438a93039faf08d39bd3df1f7b5f19a2c29ffe8753127e2956ab4461adab35" - }, - { - "handler": "bitcoin", - "address": "address/bc1qrfr44n2j4czd5c9txwlnw0yj2h82x9566fglqj", - "expectedTxNum": 2, - "expectedTxId": "36b1e721a25ea3ac2fcc09a92d4ff1e2ae4ed70d593e276806d9a9fd2a901132" - }, - { - "handler": "bitcoin", - "address": "xpub/zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - "expectedTxNum": 3, - "expectedTxId": "c6a4c82d5c7a342796e7d81237ab399918d3205f791ebc40e63501cac28c32be" - }, - { - "handler": "bitcoincash", - "address": "address/bitcoincash:qq07l6rr5lsdm3m80qxw80ku2ex0tj76vvsxpvmgme", - "expectedTxNum": 2, - "expectedTxId": "0284cb9b8deb0534efa8fc8911db1e8f9b106d00608c712d31c3680f303fbf36" - }, - { - "handler": "bitcoincash", - "address": "xpub/xpub6Bq3UUphocwroXkhA9sn8ACnZpJNuwaBehgo7WbDi2DULYnvT72Uzgsv9cE5EiP8ThDYdMyZREfbpkUY4KZ88ZaUQxXciBcZ1soSi1d8xtX", - "expectedTxNum": 3, - "expectedTxId": "269d428f01fbe49cd6d2c2ca5e6e2f0ff68aece905313932156078d4341d347a" - }, - { - "handler": "ravencoin", - "address": "address/RGkwvrUors8DtmhKy5bddFwRCTZaunjpvo", - "expectedTxNum": 2, - "expectedTxId": "fc226aad6fc28e1204b747042e8c8b25f5d28424b9669bd162ba6a0149df2f71" - }, - { - "handler": "ravencoin", - "address": "xpub/xpub6BrkWQHMnuGcvKowEn2hpvnZ41SiCsu38mgFThKU3nMzPUN9r9C26puf18rfVdHH3nDwSkeMgsjVniNDKUk5arxekekGpNyVLsWihYAfC5B", - "expectedTxNum": 3, - "expectedTxId": "5d22e5a84b0eb054b623fdc3caf88a60eaa646dc97922f06d325aa8d6f18c564" - }, - { - "handler": "viacoin", - "address": "address/VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A", - "expectedTxNum": 2, - "expectedTxId": "1b311427cd4749cbebd5c1fc70896b9e92a58d6935ba75bb40ed4a9e22e4a6cb" - }, - { - "handler": "viacoin", - "address": "xpub/zpub6qVn6ubhK9tfepuABqy8wBXXn3qUZTbpqyNBqLyqakqTrZZD9rXZ3L5MZ945g8Mu7vmMSbC7vfLtLatTgxAnVJ8ECCtwmKqCo6TJm2ZsFJK", - "expectedTxNum": 1, - "expectedTxId": "bdff404da14940abd84f7cb741fe8f77ad5de5aefbb74254caee683fe2a9b540" - }, - { - "handler": "litecoin", - "address": "address/ltc1qpm594ntjq6ayqjngf6t9td2dxtey9d7985eept", - "expectedTxNum": 2, - "expectedTxId": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1" - }, - { - "handler": "litecoin", - "address": "xpub/zpub6rpF5Uxuz4KKWePLorSz2QrHMmk1iiZvGUGgtSHpor8yiGekyRuWf5ZNmf6GUKB4v3ibQDuZp5v8RnjEGq58kR3WPtGPn8Lrg677MQ8YeKu", - "expectedTxNum": 2, - "expectedTxId": "bfce02fdd69ec01c08486b75fa5e4a93d82a0e6f346c8eade6437affb0f817b1" - }, - { - "handler": "qtum", - "address": "address/QZJbNrGT3cZ1J1AEHtgH3JWM7uLBNAejLZ", - "expectedTxNum": 2, - "expectedTxId": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67" - }, - { - "handler": "qtum", - "address": "xpub/xpub6CvFuU1yPwHjMekXqgEZjcQy22ZWiKgRUY6yAneNNyk1trZhV6ZBFSY8Vt2wygTXTVHBkfi4n823vm79yiw42w6xTL2UjKyh2W9V88sXoNd", - "expectedTxNum": 2, - "expectedTxId": "62438bb658856c3a08b89ca80e199e7031f98956ea86a135f5d6306660230f67" - }, - { - "handler": "groestlcoin", - "address": "address/33Ym3fecmWaHD19jymYt6fGd9TqSDQFfQj", - "expectedTxNum": 2, - "expectedTxId": "2640aa5de0c9603da1c0d9c16b2fd3fa0a17b1472c3aa02559d3ef5e1defceb5" - }, - { - "handler": "groestlcoin", - "address": "xpub/zpub6rWUMiiVPxjWVHffT8x3AfcbyDu8SZJAiuKUTBmhxT7Bvqk1WitxndDStG1qHN6XzRM7JgsaRaVccRFW3AprWk4Fpaev1N6QSp1aNnP5JPf", - "expectedTxNum": 2, - "expectedTxId": "686c651223b937b1223560a60631ad79ad17351c88bba67cad8ea0c95fccbb83" - }, - { - "handler": "dash", - "address": "address/XrcbsQdrFYEzbqA9nCJi8zDtnRZzNKkCtG", - "expectedTxNum": 2, - "expectedTxId": "8a1859bb849e207b7771c0301a6109a039eec955234b7848715b150f20fabeca" - }, - { - "handler": "dash", - "address": "xpub/xpub6CKAjCUKKPW7bzYEG5mzRsmzyTRp7XzauqFWNmpGVNqMqsSQpLMCN3ygEmD6ZEGVocNDrDhE7SeGot78noEWpwPDbJjfxREHC848sxNrUkD", - "expectedTxNum": 2, - "expectedTxId": "2b67e2fbe6a212286243bc539cca3c1d877e85ffec7c925e34f2bfb7b6cc498c" - }, - { - "handler": "fio", - "address": "FIO7Q3XfQ2ocGP1zYst6Sfx5qrsiZ865Cu8So2atrub9JN94so7gt", - "expectedTxNum": 1, - "expectedTxId": "2e0a7dc3640768e1d644cee871734dd2efa23e65a54c438c1ba03801d7386fb7" - }, - { - "handler": "fio", - "address": "ezsmbcy2opod", - "expectedTxNum": 1, - "expectedTxId": "2e0a7dc3640768e1d644cee871734dd2efa23e65a54c438c1ba03801d7386fb7" - }, - { - "handler": "fio", - "address": "FIO6gZthsHigy7wXeev4MKS4MuoygkxQ1yirmmUqpoubDWLJTASa2", - "expectedTxNum": 1, - "expectedTxId": "d2dd588ac5e46cb072d0a2673ea59b88187f0331b26906fabbafddbcea291450" - } -] From 6e2f450a8d01da4522964740c48bf783e529dcf4 Mon Sep 17 00:00:00 2001 From: maxUo <20925019+maxUo@users.noreply.github.com> Date: Fri, 30 Oct 2020 17:16:58 +0300 Subject: [PATCH 406/506] Update values.prod.yaml (#1266) --- deployment/charts/blockatlas/values.prod.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deployment/charts/blockatlas/values.prod.yaml b/deployment/charts/blockatlas/values.prod.yaml index bcbaa4f8e..20b70f291 100644 --- a/deployment/charts/blockatlas/values.prod.yaml +++ b/deployment/charts/blockatlas/values.prod.yaml @@ -1,5 +1,6 @@ # scaling -apiReplicaCount: 3 +apiReplicaCount: 5 +consumerReplicaCount: 5 image: repository: repositoryToReplace @@ -134,4 +135,4 @@ parserTronResources: memory: 120Mi requests: cpu: 10m - memory: 120Mi \ No newline at end of file + memory: 120Mi From e8291a2a484ec3cda642087429be7d47a9a0e1f6 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Thu, 5 Nov 2020 17:31:48 +0300 Subject: [PATCH 407/506] Remove custom logger and errors in favor of logrus and default ones (#1267) * Remove custom logger and errors in favor of logrus and default ones * Fix lint --- CONTRIBUTING.md | 32 ++--- api/endpoint/staking.go | 8 +- api/endpoint/transaction.go | 4 +- api/middleware/cache.go | 20 +-- cmd/api/main.go | 9 +- cmd/consumer/main.go | 17 ++- cmd/parser/main.go | 25 ++-- config/configuration.go | 14 +-- db/db.go | 16 +-- db/notification.go | 8 +- go.mod | 3 +- go.sum | 2 + internal/init.go | 6 +- internal/shutdown.go | 16 +-- mq/mq.go | 32 ++--- pkg/address/address.go | 10 +- pkg/blockatlas/client.go | 12 +- pkg/blockatlas/clientcache.go | 12 +- pkg/blockatlas/jsonrpc.go | 16 +-- pkg/blockatlas/marshal.go | 8 +- pkg/blockatlas/tx.go | 70 +++++------ pkg/errors/errorType.go | 44 ------- pkg/errors/errors.go | 119 ------------------ pkg/errors/helper_test.go | 47 ------- pkg/errors/helpers.go | 49 -------- pkg/logger/error.go | 56 --------- pkg/logger/logger.go | 88 ------------- pkg/numbers/decimal.go | 8 +- pkg/numbers/number.go | 4 +- platform/binance/client.go | 22 ++-- platform/bitcoin/block.go | 4 +- platform/cosmos/client.go | 9 +- platform/cosmos/stake.go | 21 ++-- platform/cosmos/transaction.go | 8 +- platform/fio/actor.go | 6 +- platform/fio/client.go | 3 +- platform/fio/transaction.go | 12 +- platform/harmony/client.go | 6 +- platform/harmony/stake.go | 9 +- platform/harmony/transaction.go | 17 ++- platform/icon/transaction.go | 6 +- platform/iotex/client.go | 7 +- platform/kava/client.go | 10 +- platform/kava/stake.go | 21 ++-- platform/kava/transaction.go | 8 +- platform/ontology/block.go | 6 +- platform/ontology/client.go | 11 +- platform/ontology/stake.go | 3 +- platform/ontology/transaction.go | 15 ++- platform/registry.go | 11 +- platform/solana/stake.go | 4 +- platform/stellar/client.go | 4 +- platform/tezos/block.go | 4 +- platform/tezos/stake.go | 6 +- platform/tezos/transaction.go | 4 +- platform/tron/client.go | 3 +- platform/tron/stake.go | 4 +- platform/tron/token.go | 8 +- platform/tron/transaction.go | 26 ++-- platform/vechain/stake.go | 3 +- platform/vechain/transaction.go | 21 ++-- services/assets/client.go | 3 +- services/assets/validator.go | 3 +- services/notifier/base.go | 8 +- services/notifier/delivery.go | 16 ++- services/parser/parser.go | 57 +++++---- services/subscriber/tokens.go | 12 +- services/subscriber/transactions.go | 41 ++++-- services/tokenindexer/indexer.go | 12 +- services/tokensearcher/api.go | 16 +-- services/tokensearcher/models.go | 4 +- services/tokensearcher/tokensearcher.go | 20 +-- .../integration/db_test/tokenindexer_test.go | 8 +- .../observer_test/full_flow_test.go | 2 +- .../observer_test/notifier_test.go | 2 +- .../integration/observer_test/parser_test.go | 6 +- 76 files changed, 432 insertions(+), 835 deletions(-) delete mode 100644 pkg/errors/errorType.go delete mode 100644 pkg/errors/errors.go delete mode 100644 pkg/errors/helper_test.go delete mode 100644 pkg/errors/helpers.go delete mode 100755 pkg/logger/error.go delete mode 100755 pkg/logger/logger.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4d765fc7e..1b839ea8e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,12 +52,12 @@ E is a convenience function for creating errors quickly: `func E(args ...interface{}) *Error` Usage: - - Wrap a generic error: `errors.E(err)` - - Wrap error with message: `errors.E(err, "new message to append")` - - Annotate error with type: `errors.E(err, errors.TypePlatformRequest)` + - Wrap a generic error: `errors.New(err)` + - Wrap error with message: `errors.New(err, "new message to append")` + - Annotate error with type: `errors.New(err, errors.TypePlatformRequest)` - Error with type and metadata: ``` -errors.E(err, errors.TypePlatformRequest, errors.Params{ +errors.New(err, errors.TypePlatformRequest, errors.Params{ "coin": "Ethereum", "method": "CurrentBlockNumber", }) @@ -75,29 +75,29 @@ Use the package `pkg/logger` for logging. The order of function parameters is arbitrary when using the logger functions. Examples: - - Log message: `logger.Info("Loading Observer API")` - - Log message with params: `logger.Info("Running application", logger.Params{"bind": bind})` - - Fatal with error: `logger.Fatal("Application failed", err)` - - Create a simple error log: `logger.Error(err)` - - Create an error log with a message: `logger.Error("Failed to initialize API", err)` + - Log message: `log.Info("Loading Observer API")` + - Log message with params: `log.Info("Running application", log.Params{"bind": bind})` + - Fatal with error: `log.Fatal("Application failed", err)` + - Create a simple error log: `log.Error(err)` + - Create an error log with a message: `log.Error("Failed to initialize API", err)` - Create an error log, with error, message, and params: ``` -p := logger.Params{ +p := log.Params{ "platform": handle, "coin": platform.Coin(), } err := platform.Init() if err != nil { - logger.Error("Failed to initialize API", err, p) + log.Error("Failed to initialize API", err, p) } ``` - Debug log: - `logger.Debug("Loading Observer API")` + `log.Debug("Loading Observer API")` or - `logger.Debug("Loading Observer API", logger.Params{"bind": bind})` + `log.Debug("Loading Observer API", log.Params{"bind": bind})` - Warning log: - `logger.Warn("Warning", err)` + `log.Warn("Warning", err)` or - `logger.Warn(err, "Warning")` + `log.Warn(err, "Warning")` or - `logger.Warn("Warning", err, logger.Params{"bind": bind})` + `log.Warn("Warning", err, log.Params{"bind": bind})` diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index 7dec5ca39..175e363ec 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -8,9 +8,9 @@ import ( "github.com/trustwallet/blockatlas/pkg/numbers" + "errors" "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/golibs/coin" ) @@ -113,7 +113,7 @@ func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { coinsRequest := c.Query("coins") if coinsRequest == "" { - c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(errors.E("empty coins list"))) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(errors.New("empty coins list"))) return } @@ -192,7 +192,7 @@ func getDelegationResponse(api blockatlas.StakeAPI, address string) (blockatlas. return blockatlas.DelegationResponse{ StakingResponse: getStakingResponse(api), Address: address, - }, errors.E("Unable to fetch delegations list", err) + }, err } balance, err := api.UndelegatedBalance(address) if err != nil { @@ -200,7 +200,7 @@ func getDelegationResponse(api blockatlas.StakeAPI, address string) (blockatlas. Delegations: delegations, Address: address, StakingResponse: getStakingResponse(api), - }, errors.E("Unable to fetch undelegated balance", err) + }, err } return blockatlas.DelegationResponse{ Balance: balance, diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 2bd2013fd..824c8d9a0 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -1,9 +1,9 @@ package endpoint import ( + "errors" "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "net/http" ) @@ -39,7 +39,7 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b default: c.AbortWithStatusJSON( http.StatusInternalServerError, - errorResponse(errors.E("Failed to find api for that coin")), + errorResponse(errors.New("Failed to find api for that coin")), ) return } diff --git a/api/middleware/cache.go b/api/middleware/cache.go index ccc500bf1..02d1cd3ad 100644 --- a/api/middleware/cache.go +++ b/api/middleware/cache.go @@ -5,11 +5,11 @@ import ( "crypto/sha1" "encoding/base64" "encoding/json" + "errors" "fmt" "github.com/gin-gonic/gin" "github.com/patrickmn/go-cache" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" + log "github.com/sirupsen/logrus" "io/ioutil" "net/http" "sync" @@ -76,7 +76,7 @@ func (w *cachedWriter) Write(data []byte) (int, error) { } b, err := json.Marshal(val) if err != nil { - return 0, errors.E("validator cache: failed to marshal cache object") + return 0, errors.New("validator cache: failed to marshal cache object") } memoryCache.cache.Set(w.key, b, w.expire) return ret, nil @@ -85,10 +85,10 @@ func (w *cachedWriter) Write(data []byte) (int, error) { func (w *cachedWriter) WriteString(data string) (n int, err error) { ret, err := w.ResponseWriter.WriteString(data) if err != nil { - return 0, errors.E(err, "fail to cache write string", errors.Params{"data": data}) + return 0, errors.New(err.Error() + " fail to cache write string") } if w.Status() != 200 { - return 0, errors.E("WriteString: invalid cache status", errors.Params{"data": data}) + return 0, errors.New("WriteString: invalid cache status") } val := cacheResponse{ w.Status(), @@ -97,7 +97,7 @@ func (w *cachedWriter) WriteString(data string) (n int, err error) { } b, err := json.Marshal(val) if err != nil { - return 0, errors.E("validator cache: failed to marshal cache object") + return 0, errors.New("validator cache: failed to marshal cache object") } memoryCache.setCache(w.key, b, w.expire) return ret, err @@ -112,7 +112,7 @@ func (mc *memCache) deleteCache(key string) { func (mc *memCache) setCache(k string, x interface{}, d time.Duration) { b, err := json.Marshal(x) if err != nil { - logger.Error(errors.E(err, "client cache cannot marshal cache object")) + log.Error(errors.New(err.Error() + "client cache cannot marshal cache object")) return } mc.RLock() @@ -128,11 +128,11 @@ func (mc *memCache) getCache(key string) (cacheResponse, error) { } r, ok := c.([]byte) if !ok { - return result, errors.E("validator cache: failed to cast cache to bytes") + return result, errors.New("validator cache: failed to cast cache to bytes") } err := json.Unmarshal(r, &result) if err != nil { - return result, errors.E(err, "not found") + return result, errors.New(err.Error() + " not found") } return result, nil } @@ -181,7 +181,7 @@ func CacheMiddleware(expiration time.Duration, handle gin.HandlerFunc) gin.Handl _, err = c.Writer.Write(mc.Data) if err != nil { memoryCache.deleteCache(key) - logger.Error(err, "cannot write data", mc) + log.Error(err, "cannot write data", mc) } } } diff --git a/cmd/api/main.go b/cmd/api/main.go index 87eccb641..58ba1da8f 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -3,13 +3,13 @@ package main import ( "context" "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/api" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/db" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/spamfilter" "github.com/trustwallet/blockatlas/services/tokenindexer" @@ -37,7 +37,6 @@ func init() { ctx, cancel = context.WithCancel(context.Background()) internal.InitConfig(confPath) - logger.InitLogger() engine = internal.InitEngine(config.Default.Gin.Mode) platform.Init(config.Default.Platform) @@ -47,7 +46,7 @@ func init() { database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, config.Default.Postgres.Log) if err != nil { - logger.Fatal(err) + log.Fatal(err) } go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) @@ -57,10 +56,10 @@ func init() { ) if err := mq.TokensRegistration.Declare(); err != nil { - logger.Fatal(err) + log.Fatal(err) } if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { - logger.Fatal(err) + log.Fatal(err) } ts = tokensearcher.Init(database, platform.TokensAPIs, mq.TokensRegistration) diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index 6923f7739..dfdf65b52 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -8,10 +8,10 @@ import ( "github.com/trustwallet/blockatlas/services/tokensearcher" "time" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/tokenindexer" ) @@ -30,7 +30,6 @@ func init() { _, confPath := internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) - logger.InitLogger() internal.InitRabbitMQ( config.Default.Observer.Rabbitmq.URL, @@ -41,7 +40,7 @@ func init() { database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, config.Default.Postgres.Log) if err != nil { - logger.Fatal(err) + log.Fatal(err) } go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) @@ -52,22 +51,22 @@ func main() { defer mq.Close() if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { - logger.Fatal(err) + log.Fatal(err) } if err := mq.RawTransactions.Declare(); err != nil { - logger.Fatal(err) + log.Fatal(err) } if err := mq.TxNotifications.Declare(); err != nil { - logger.Fatal(err) + log.Fatal(err) } if err := mq.RawTransactionsSearcher.Declare(); err != nil { - logger.Fatal(err) + log.Fatal(err) } if err := mq.Subscriptions.Declare(); err != nil { - logger.Fatal(err) + log.Fatal(err) } if err := mq.TokensRegistration.Declare(); err != nil { - logger.Fatal(err) + log.Fatal(err) } go mq.RawTransactionsTokenIndexer.RunConsumerWithCancelAndDbConn(tokenindexer.RunTokenIndexer, database, ctx) diff --git a/cmd/parser/main.go b/cmd/parser/main.go index 5151810a5..7281a7c9c 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -11,10 +11,10 @@ import ( "syscall" "time" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/parser" ) @@ -34,7 +34,6 @@ func init() { _, confPath := internal.ParseArgs("", defaultConfigPath) internal.InitConfig(confPath) - logger.InitLogger() internal.InitRabbitMQ( config.Default.Observer.Rabbitmq.URL, @@ -45,22 +44,22 @@ func init() { spamfilter.SpamList = config.Default.SpamWords if err := mq.RawTransactions.Declare(); err != nil { - logger.Fatal(err) + log.Fatal(err) } if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { - logger.Fatal(err) + log.Fatal(err) } if len(platform.BlockAPIs) == 0 { - logger.Fatal("No APIs to observe") + log.Fatal("No APIs to observe") } var err error database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, config.Default.Postgres.Log) if err != nil { - logger.Fatal(err) + log.Fatal(err) } go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) @@ -92,7 +91,7 @@ func main() { var backlogCount int if coin.BlockTime == 0 { backlogCount = 50 - logger.Warn("Unknown block time", logger.Params{"coin": coin.Handle}) + log.WithFields(log.Fields{"coin": coin.Handle}).Warn("Unknown block time") } else { backlogCount = int(backlogTime / pollInterval) } @@ -123,13 +122,13 @@ func main() { go parser.RunParser(params) - logger.Info("Parser params", logger.Params{ + log.WithFields(log.Fields{ "interval": pollInterval, "backlog": backlogCount, "Max backlog": maxBackLogBlocks, "Txs Batch limit": txsBatchLimit, "Fetching blocks interval": fetchBlocksInterval, - }) + }).Info("Parser params") wg.Done() } @@ -140,17 +139,17 @@ func main() { signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit cancel() - logger.Info("Shutdown parser ...") + log.Info("Shutdown parser ...") for coin, cancel := range coinCancel { - logger.Info(fmt.Sprintf("Starting to stop %s parser...", coin)) + log.Info(fmt.Sprintf("Starting to stop %s parser...", coin)) cancel() } for { if len(stopChannel) == len(platform.BlockAPIs) { - logger.Info("All parsers are stopped") + log.Info("All parsers are stopped") break } } - logger.Info("Exiting gracefully") + log.Info("Exiting gracefully") } diff --git a/config/configuration.go b/config/configuration.go index 58e821b51..40fb1d2d4 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -1,8 +1,8 @@ package config import ( + log "github.com/sirupsen/logrus" "github.com/spf13/viper" - "github.com/trustwallet/blockatlas/pkg/logger" "reflect" "strings" "time" @@ -235,23 +235,23 @@ func Init(confPath string) { if confPath == "" { err := viper.ReadInConfig() if err != nil { - logger.Panic(err, "Fatal error reading default config") + log.Panic(err, "Fatal error reading default config") } else { - logger.Info("Viper using default config", logger.Params{"config": viper.ConfigFileUsed()}) + log.WithFields(log.Fields{"config": viper.ConfigFileUsed()}).Info("Viper using default config") } } else { viper.SetConfigFile(confPath) err := viper.ReadInConfig() if err != nil { - logger.Panic(err, "Fatal error reading supplied config") + log.Panic(err, "Fatal error reading supplied config") } else { - logger.Info("Viper using supplied config", logger.Params{"config": viper.ConfigFileUsed()}) + log.WithFields(log.Fields{"config": viper.ConfigFileUsed()}).Info("Viper using supplied config") } } bindEnvs(c) if err := viper.Unmarshal(&c); err != nil { - logger.Panic(err, "Error Unmarshal Viper Config File") + log.Panic(err, "Error Unmarshal Viper Config File") } Default = c } @@ -271,7 +271,7 @@ func bindEnvs(iface interface{}, parts ...string) { bindEnvs(v.Interface(), append(parts, tv)...) default: if err := viper.BindEnv(strings.Join(append(parts, tv), ".")); err != nil { - logger.Fatal(err) + log.Fatal(err) } } } diff --git a/db/db.go b/db/db.go index 07d1dabbe..0b200db2a 100644 --- a/db/db.go +++ b/db/db.go @@ -5,8 +5,8 @@ import ( "errors" "time" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/logger" gocache "github.com/patrickmn/go-cache" @@ -59,20 +59,20 @@ func New(uri, readUri string, logMode bool) (*Instance, error) { } func (i *Instance) RestoreConnectionWorker(ctx context.Context, timeout time.Duration, uri string) { - logger.Info("Run PG RestoreConnectionWorker") + log.Info("Run PG RestoreConnectionWorker") t := time.NewTicker(timeout) if err := i.restoreConnection(uri); err != nil { - logger.Warn("PG is still unavailable:", err) + log.Warn("PG is still unavailable:", err) } select { case <-ctx.Done(): - logger.Info("Ctx.Done RestoreConnectionWorker exit") + log.Info("Ctx.Done RestoreConnectionWorker exit") return case <-t.C: if err := i.restoreConnection(uri); err != nil { - logger.Warn("PG is still unavailable:", err) + log.Warn("PG is still unavailable:", err) } } } @@ -84,13 +84,13 @@ func (i *Instance) restoreConnection(uri string) error { } if err = db.Ping(); err != nil { - logger.Warn("PG is not available now") - logger.Warn("Trying to connect to PG...") + log.Warn("PG is not available now") + log.Warn("Trying to connect to PG...") i.Gorm, err = gorm.Open(postgres.Open(uri), &gorm.Config{}) if err != nil { return err } - logger.Info("PG connection restored") + log.Info("PG connection restored") } return nil } diff --git a/db/notification.go b/db/notification.go index 6044645ed..9b7c07fda 100644 --- a/db/notification.go +++ b/db/notification.go @@ -2,15 +2,15 @@ package db import ( "context" + "errors" "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/errors" "gorm.io/gorm" "gorm.io/gorm/clause" ) func (i *Instance) GetSubscriptionsForNotifications(addresses []string, ctx context.Context) ([]models.NotificationSubscription, error) { if len(addresses) == 0 { - return nil, errors.E("Empty addresses") + return nil, errors.New("Empty addresses") } db := i.Gorm.WithContext(ctx) @@ -24,7 +24,7 @@ func (i *Instance) GetSubscriptionsForNotifications(addresses []string, ctx cont func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx context.Context) error { if len(addresses) == 0 { - return errors.E("Empty subscriptions") + return errors.New("Empty subscriptions") } db := i.Gorm.WithContext(ctx) return db.Transaction(func(tx *gorm.DB) error { @@ -65,7 +65,7 @@ func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx cont func (i *Instance) DeleteSubscriptionsForNotifications(addresses []string, ctx context.Context) error { if len(addresses) == 0 { - return errors.E("Empty subscriptions") + return errors.New("Empty subscriptions") } q := `DELETE FROM notification_subscriptions ns USING addresses a where ns.address_id = a.id AND a.address IN (?);` return i.Gorm.WithContext(ctx).Exec(q, addresses).Error diff --git a/go.mod b/go.mod index 018cfb735..9bd3e2a09 100644 --- a/go.mod +++ b/go.mod @@ -24,12 +24,11 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 - github.com/trustwallet/golibs v0.0.8 + github.com/trustwallet/golibs v0.0.9 github.com/trustwallet/watchmarket v1.1.1 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmhttp v1.8.0 - go.elastic.co/apm/module/apmlogrus v1.8.0 go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 gopkg.in/yaml.v2 v2.3.0 diff --git a/go.sum b/go.sum index da0234835..0a36aefdd 100644 --- a/go.sum +++ b/go.sum @@ -522,6 +522,8 @@ github.com/trustwallet/ens-coincodec v1.0.6 h1:ZPvFDJwvv4s+XCnUM7pzub8wYHy37tyJB github.com/trustwallet/ens-coincodec v1.0.6/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= github.com/trustwallet/golibs v0.0.8 h1:eviuHKqIXDs+DGgWNHF/gNTrV6jmJTfYYEHVbCeniWE= github.com/trustwallet/golibs v0.0.8/go.mod h1:QB6tQe5tvZOAPmvpeaveFwCQpTqdelSgO6UlMZN30Co= +github.com/trustwallet/golibs v0.0.9 h1:AyupOF1LZyMaZdkwnG3hxSwb5pqW2yZR7EI4hLoBrI8= +github.com/trustwallet/golibs v0.0.9/go.mod h1:QB6tQe5tvZOAPmvpeaveFwCQpTqdelSgO6UlMZN30Co= github.com/trustwallet/watchmarket v1.1.1 h1:gErSfLLDhEblFqvW8V3RyzRqq4R6MCYEDWjO6j5uJfE= github.com/trustwallet/watchmarket v1.1.1/go.mod h1:DvqzLzxXOaZajbkryVZcNgBS4yibZhk3rCc41ZSJEBs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= diff --git a/internal/init.go b/internal/init.go index 08200767d..af9e52207 100644 --- a/internal/init.go +++ b/internal/init.go @@ -3,10 +3,10 @@ package internal import ( "flag" "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/api/middleware" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/logger" "go.elastic.co/apm/module/apmgin" "path/filepath" @@ -33,7 +33,7 @@ func ParseArgs(defaultPort, defaultConfigPath string) (string, string) { func InitConfig(confPath string) { confPath, err := filepath.Abs(confPath) if err != nil { - logger.Fatal(err) + log.Fatal(err) } config.Init(confPath) @@ -54,7 +54,7 @@ func InitEngine(ginMode string) *gin.Engine { func InitRabbitMQ(rabbitURI string, prefetchCount int) { err := mq.Init(rabbitURI) if err != nil { - logger.Fatal("Failed to init Rabbit MQ", logger.Params{"uri": rabbitURI}) + log.WithFields(log.Fields{"uri": rabbitURI}).Fatal("Failed to init Rabbit MQ") } mq.PrefetchCount = prefetchCount } diff --git a/internal/shutdown.go b/internal/shutdown.go index 9d5c0ce5a..3011da6c0 100644 --- a/internal/shutdown.go +++ b/internal/shutdown.go @@ -3,7 +3,7 @@ package internal import ( "context" "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/pkg/logger" + log "github.com/sirupsen/logrus" "net/http" "os" "os/signal" @@ -19,7 +19,7 @@ func SetupGracefulShutdown(ctx context.Context, port string, engine *gin.Engine) defer func() { if err := server.Shutdown(ctx); err != nil { - logger.Fatal("Server Shutdown: ", err) + log.Fatal("Server Shutdown: ", err) } }() @@ -32,21 +32,21 @@ func SetupGracefulShutdown(ctx context.Context, port string, engine *gin.Engine) go func() { if err := server.ListenAndServe(); err != nil { - logger.Fatal("Application failed", err) + log.Fatal("Application failed", err) } }() - logger.Info("Running application", logger.Params{"bind": port}) + log.WithFields(log.Fields{"bind": port}).Info("Running application") stop := <-signalForExit - logger.Info("Stop signal Received", stop) - logger.Info("Waiting for all jobs to stop") + log.Info("Stop signal Received", stop) + log.Info("Waiting for all jobs to stop") } func SetupGracefulShutdownForObserver() { quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit - logger.Info("Shutdown ...") + log.Info("Shutdown ...") time.Sleep(time.Second * 5) - logger.Info("Exiting gracefully") + log.Info("Exiting gracefully") } diff --git a/mq/mq.go b/mq/mq.go index 2bd1bac3c..cc7c8282a 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -2,9 +2,9 @@ package mq import ( "context" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/pkg/logger" "time" ) @@ -42,12 +42,12 @@ func Init(uri string) (err error) { func Close() { err := amqpChan.Close() if err != nil { - logger.Error(err) + log.Error(err) } err = conn.Close() if err != nil { - logger.Error(err) + log.Error(err) } } @@ -72,7 +72,7 @@ func RunConsumerForChannelWithCancelAndDbConn(consumer ConsumerWithDbConn, messa for { select { case <-ctx.Done(): - logger.Info("Consumer stopped") + log.Info("Consumer stopped") return case message := <-messageChannel: if message.Body == nil { @@ -94,7 +94,7 @@ func (q Queue) GetMessageChannel() MessageChannel { nil, ) if err != nil { - logger.Fatal("MQ issue " + err.Error()) + log.Fatal("MQ issue " + err.Error()) } err = amqpChan.Qos( @@ -103,7 +103,7 @@ func (q Queue) GetMessageChannel() MessageChannel { true, ) if err != nil { - logger.Fatal("No qos limit ", err) + log.Fatal("No qos limit ", err) } return messageChannel @@ -121,7 +121,7 @@ func (q Queue) RunConsumerWithCancel(consumer Consumer, ctx context.Context) { for { select { case <-ctx.Done(): - logger.Info("Consumer stopped") + log.Info("Consumer stopped") return case message := <-messageChannel: if message.Body == nil { @@ -137,7 +137,7 @@ func (q Queue) RunConsumerWithCancelAndDbConn(consumer ConsumerWithDbConn, datab for { select { case <-ctx.Done(): - logger.Info("Consumer stopped") + log.Info("Consumer stopped") return case message := <-messageChannel: if message.Body == nil { @@ -149,23 +149,23 @@ func (q Queue) RunConsumerWithCancelAndDbConn(consumer ConsumerWithDbConn, datab } func RestoreConnectionWorker(uri string, queue Queue, timeout time.Duration) { - logger.Info("Run MQ RestoreConnectionWorker") + log.Info("Run MQ RestoreConnectionWorker") for { if conn.IsClosed() { for { - logger.Warn("MQ is not available now") - logger.Warn("Trying to connect to MQ...") + log.Warn("MQ is not available now") + log.Warn("Trying to connect to MQ...") if err := Init(uri); err != nil { - logger.Warn("MQ is still unavailable") + log.Warn("MQ is still unavailable") time.Sleep(timeout) continue } if err := queue.Declare(); err != nil { - logger.Warn("Can't declare queues:", queue) + log.Warn("Can't declare queues:", queue) time.Sleep(timeout) continue } else { - logger.Info("MQ connection restored") + log.Info("MQ connection restored") break } } @@ -175,10 +175,10 @@ func RestoreConnectionWorker(uri string, queue Queue, timeout time.Duration) { } func FatalWorker(timeout time.Duration) { - logger.Info("Run MQ FatalWorker") + log.Info("Run MQ FatalWorker") for { if conn.IsClosed() { - logger.Fatal("MQ is not available now") + log.Fatal("MQ is not available now") } time.Sleep(timeout) } diff --git a/pkg/address/address.go b/pkg/address/address.go index 9096fd6e2..964ca5065 100644 --- a/pkg/address/address.go +++ b/pkg/address/address.go @@ -4,8 +4,7 @@ import ( "crypto/sha256" "encoding/hex" "github.com/mr-tron/base58" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" + log "github.com/sirupsen/logrus" "github.com/trustwallet/golibs/coin" "golang.org/x/crypto/sha3" "strconv" @@ -28,7 +27,7 @@ func EIP55Checksum(unchecksummed string) string { sha := sha3.NewLegacyKeccak256() _, err := sha.Write(v) if err != nil { - logger.Error(err) + log.Error(err) } hash := sha.Sum(nil) @@ -53,8 +52,7 @@ func EIP55Checksum(unchecksummed string) string { func HexToAddress(hexAddr string) (b58 string, err error) { bytes, err := hex.DecodeString(hexAddr) if err != nil { - return "", errors.E(err, errors.TypePlatformUnmarshal, - errors.Params{"hexAddr": hexAddr}) + return "", err } var checksum [32]byte checksum = sha256.Sum256(bytes) @@ -72,7 +70,7 @@ func EIP55ChecksumWanchain(address string) string { sha := sha3.NewLegacyKeccak256() _, err := sha.Write(v) if err != nil { - logger.Error(err) + log.Error(err) } hash := sha.Sum(nil) diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go index f3b3e2c3f..b468328a5 100644 --- a/pkg/blockatlas/client.go +++ b/pkg/blockatlas/client.go @@ -12,8 +12,6 @@ import ( "net/url" "strings" "time" - - "github.com/trustwallet/blockatlas/pkg/errors" ) type Request struct { @@ -96,7 +94,7 @@ func (r *Request) PostWithContext(result interface{}, path string, body interfac func (r *Request) Execute(method string, url string, body io.Reader, result interface{}, ctx context.Context) error { req, err := http.NewRequest(method, url, body) if err != nil { - return errors.E(err, errors.TypePlatformRequest) + return err } for key, value := range r.Headers { @@ -107,21 +105,21 @@ func (r *Request) Execute(method string, url string, body io.Reader, result inte res, err := c.Do(req.WithContext(ctx)) if err != nil { - return errors.E(err, errors.TypePlatformRequest) + return err } err = r.ErrorHandler(res, url) if err != nil { - return errors.E(err, errors.TypePlatformError) + return err } defer res.Body.Close() b, err := ioutil.ReadAll(res.Body) if err != nil { - return errors.E(err, errors.TypePlatformUnmarshal) + return err } err = json.Unmarshal(b, result) if err != nil { - return errors.E(err, errors.TypePlatformUnmarshal) + return err } return err } diff --git a/pkg/blockatlas/clientcache.go b/pkg/blockatlas/clientcache.go index 670196dd0..21682ab81 100644 --- a/pkg/blockatlas/clientcache.go +++ b/pkg/blockatlas/clientcache.go @@ -5,9 +5,9 @@ import ( "crypto/sha1" "encoding/base64" "encoding/json" + "errors" "github.com/patrickmn/go-cache" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" + log "github.com/sirupsen/logrus" "net/url" "strings" "sync" @@ -99,7 +99,7 @@ func (mc *memCache) setCache(key string, value interface{}, duration time.Durati defer mc.RUnlock() b, err := json.Marshal(value) if err != nil { - logger.Error(errors.E(err, "client cache cannot marshal cache object")) + log.Error(errors.New(err.Error() + " client cache cannot marshal cache object")) return } memoryCache.cache.Set(key, b, duration) @@ -108,15 +108,15 @@ func (mc *memCache) setCache(key string, value interface{}, duration time.Durati func (mc *memCache) getCache(key string, value interface{}) error { c, ok := mc.cache.Get(key) if !ok { - return errors.E("validator cache: invalid cache key") + return errors.New("validator cache: invalid cache key") } r, ok := c.([]byte) if !ok { - return errors.E("validator cache: failed to cast cache to bytes") + return errors.New("validator cache: failed to cast cache to bytes") } err := json.Unmarshal(r, value) if err != nil { - return errors.E(err, "not found") + return errors.New(err.Error() + " not found") } return nil } diff --git a/pkg/blockatlas/jsonrpc.go b/pkg/blockatlas/jsonrpc.go index 0f2d79e7d..b669cc0fe 100644 --- a/pkg/blockatlas/jsonrpc.go +++ b/pkg/blockatlas/jsonrpc.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" - "github.com/trustwallet/blockatlas/pkg/errors" + "errors" ) var ( @@ -41,12 +41,12 @@ type ( func (r *RpcResponse) GetObject(toType interface{}) error { js, err := json.Marshal(r.Result) if err != nil { - return errors.E(err, "json-rpc GetObject Marshal error", errors.Params{"obj": toType}) + return err } err = json.Unmarshal(js, toType) if err != nil { - return errors.E(err, "json-rpc GetObject Unmarshal error", errors.Params{"obj": toType, "string": string(js)}) + return err } return nil } @@ -60,10 +60,7 @@ func (r *Request) RpcCall(result interface{}, method string, params interface{}) return err } if resp.Error != nil { - return errors.E("RPC Call error", errors.Params{ - "method": method, - "error_code": resp.Error.Code, - "error_message": resp.Error.Message}) + return errors.New("RPC Call error") } return resp.GetObject(result) } @@ -77,10 +74,7 @@ func (r *Request) RpcCallWithContext(result interface{}, method string, params i return err } if resp.Error != nil { - return errors.E("RPC Call error", errors.Params{ - "method": method, - "error_code": resp.Error.Code, - "error_message": resp.Error.Message}) + return errors.New("RPC Call error") } return resp.GetObject(result) } diff --git a/pkg/blockatlas/marshal.go b/pkg/blockatlas/marshal.go index ee1a513ad..be21a9563 100644 --- a/pkg/blockatlas/marshal.go +++ b/pkg/blockatlas/marshal.go @@ -5,7 +5,7 @@ import ( "regexp" "strings" - "github.com/trustwallet/blockatlas/pkg/errors" + "errors" "github.com/trustwallet/blockatlas/pkg/numbers" ) @@ -46,7 +46,7 @@ func (t *Tx) UnmarshalJSON(data []byte) error { case TxAnyAction: t.Meta = new(AnyAction) default: - return errors.E("unsupported tx type", errors.Params{"type": t.Type}) + return errors.New("unsupported tx type") } err := json.Unmarshal(raw, t.Meta) @@ -78,7 +78,7 @@ func (t *Tx) MarshalJSON() ([]byte, error) { case AnyAction, *AnyAction: t.Type = TxAnyAction default: - return nil, errors.E("unsupported tx metadata", errors.Params{"meta": t.Meta}) + return nil, errors.New("unsupported tx metadata") } // Set status to completed by default @@ -100,7 +100,7 @@ func (a *Amount) UnmarshalJSON(data []byte) error { } str := string(n) if !matchNumber.MatchString(str) { - return errors.E("not a regular decimal number", errors.Params{"str": str}) + return errors.New("not a regular decimal number") } if strings.ContainsRune(str, '.') { str, _ = numbers.DecimalToSatoshis(str) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 2abea4993..5970c8f94 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -4,8 +4,8 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/asset" "github.com/trustwallet/golibs/coin" - "github.com/trustwallet/watchmarket/pkg/watchmarket" "sort" "strconv" "strings" @@ -462,76 +462,76 @@ func GetEthereumTokenTypeByIndex(coinIndex uint) TokenType { } func (t Tx) AssetModel() (models.Asset, bool) { - var asset models.Asset + var a models.Asset switch t.Meta.(type) { case TokenTransfer: - asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(TokenTransfer).TokenID) - asset.Decimals = t.Meta.(TokenTransfer).Decimals - asset.Name = t.Meta.(TokenTransfer).Name - asset.Symbol = t.Meta.(TokenTransfer).Symbol + a.Asset = asset.BuildID(t.Coin, t.Meta.(TokenTransfer).TokenID) + a.Decimals = t.Meta.(TokenTransfer).Decimals + a.Name = t.Meta.(TokenTransfer).Name + a.Symbol = t.Meta.(TokenTransfer).Symbol tp, ok := GetTokenType(t.Coin, t.Meta.(TokenTransfer).TokenID) if !ok { return models.Asset{}, false } - asset.Type = tp + a.Type = tp case *TokenTransfer: - asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(*TokenTransfer).TokenID) - asset.Decimals = t.Meta.(*TokenTransfer).Decimals - asset.Name = t.Meta.(*TokenTransfer).Name - asset.Symbol = t.Meta.(*TokenTransfer).Symbol + a.Asset = asset.BuildID(t.Coin, t.Meta.(*TokenTransfer).TokenID) + a.Decimals = t.Meta.(*TokenTransfer).Decimals + a.Name = t.Meta.(*TokenTransfer).Name + a.Symbol = t.Meta.(*TokenTransfer).Symbol tp, ok := GetTokenType(t.Coin, t.Meta.(*TokenTransfer).TokenID) if !ok { return models.Asset{}, false } - asset.Type = tp + a.Type = tp case NativeTokenTransfer: - asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(NativeTokenTransfer).TokenID) - asset.Decimals = t.Meta.(NativeTokenTransfer).Decimals - asset.Name = t.Meta.(NativeTokenTransfer).Name - asset.Symbol = t.Meta.(NativeTokenTransfer).Symbol + a.Asset = asset.BuildID(t.Coin, t.Meta.(NativeTokenTransfer).TokenID) + a.Decimals = t.Meta.(NativeTokenTransfer).Decimals + a.Name = t.Meta.(NativeTokenTransfer).Name + a.Symbol = t.Meta.(NativeTokenTransfer).Symbol tp, ok := GetTokenType(t.Coin, t.Meta.(NativeTokenTransfer).TokenID) if !ok { return models.Asset{}, false } - asset.Type = tp + a.Type = tp case *NativeTokenTransfer: - asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(*NativeTokenTransfer).TokenID) - asset.Decimals = t.Meta.(*NativeTokenTransfer).Decimals - asset.Name = t.Meta.(*NativeTokenTransfer).Name - asset.Symbol = t.Meta.(*NativeTokenTransfer).Symbol + a.Asset = asset.BuildID(t.Coin, t.Meta.(*NativeTokenTransfer).TokenID) + a.Decimals = t.Meta.(*NativeTokenTransfer).Decimals + a.Name = t.Meta.(*NativeTokenTransfer).Name + a.Symbol = t.Meta.(*NativeTokenTransfer).Symbol tp, ok := GetTokenType(t.Coin, t.Meta.(*NativeTokenTransfer).TokenID) if !ok { return models.Asset{}, false } - asset.Type = tp + a.Type = tp case AnyAction: - asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(AnyAction).TokenID) - asset.Decimals = t.Meta.(AnyAction).Decimals - asset.Name = t.Meta.(AnyAction).Name - asset.Symbol = t.Meta.(AnyAction).Symbol + a.Asset = asset.BuildID(t.Coin, t.Meta.(AnyAction).TokenID) + a.Decimals = t.Meta.(AnyAction).Decimals + a.Name = t.Meta.(AnyAction).Name + a.Symbol = t.Meta.(AnyAction).Symbol tp, ok := GetTokenType(t.Coin, t.Meta.(AnyAction).TokenID) if !ok { return models.Asset{}, false } - asset.Type = tp + a.Type = tp case *AnyAction: - asset.Asset = watchmarket.BuildID(t.Coin, t.Meta.(*AnyAction).TokenID) - asset.Decimals = t.Meta.(*AnyAction).Decimals - asset.Name = t.Meta.(*AnyAction).Name - asset.Symbol = t.Meta.(*AnyAction).Symbol + a.Asset = asset.BuildID(t.Coin, t.Meta.(*AnyAction).TokenID) + a.Decimals = t.Meta.(*AnyAction).Decimals + a.Name = t.Meta.(*AnyAction).Name + a.Symbol = t.Meta.(*AnyAction).Symbol tp, ok := GetTokenType(t.Coin, t.Meta.(*AnyAction).TokenID) if !ok { return models.Asset{}, false } - asset.Type = tp + a.Type = tp default: return models.Asset{}, false } - if asset.Asset == "" { + if a.Asset == "" { return models.Asset{}, false } - asset.Coin = t.Coin - return asset, true + a.Coin = t.Coin + return a, true } func GetTokenType(c uint, tokenID string) (string, bool) { diff --git a/pkg/errors/errorType.go b/pkg/errors/errorType.go deleted file mode 100644 index f7f74fef1..000000000 --- a/pkg/errors/errorType.go +++ /dev/null @@ -1,44 +0,0 @@ -package errors - -import ( - "fmt" -) - -type Type uint16 - -const ( - TypeNone Type = iota - TypePlatformUnmarshal - TypePlatformNormalize - TypePlatformUnknown - TypePlatformRequest - TypePlatformClient - TypePlatformError - TypePlatformApi - TypeUnknown -) - -func (e Type) String() string { - switch e { - case TypeNone: - return "" - case TypePlatformRequest: - return "Platform Request Error" - case TypePlatformUnmarshal: - return "Platform Unmarshal Error" - case TypePlatformClient: - return "Platform Client Generic Error" - case TypePlatformApi: - return "Platform API Error" - case TypePlatformNormalize: - return "Platform Normalize Error" - case TypePlatformUnknown: - return "Platform Unknown Error" - case TypePlatformError: - return "Custom Platform Error" - case TypeUnknown: - return "Unknown Error" - default: - return fmt.Sprintf("Error: %d", int(e)) - } -} diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go deleted file mode 100644 index e82f718d5..000000000 --- a/pkg/errors/errors.go +++ /dev/null @@ -1,119 +0,0 @@ -package errors - -import ( - "encoding/json" - "errors" - "fmt" - "runtime" - "strings" -) - -type ( - Params map[string]interface{} - - // Error represents a error's specification. - Error struct { - Err error - Type Type - meta map[string]interface{} - stack []string - } -) - -var _ error = (*Error)(nil) - -func (e *Error) Error() string { - return e.String() -} - -func (e *Error) String() string { - msg := e.Err.Error() - if e.Type != TypeNone { - msg = fmt.Sprintf("%s | Type: %s", msg, e.Type.String()) - } - if len(e.stack) > 0 { - msg = fmt.Sprintf("%s | Stack: %s", msg, e.stack) - } - return msg -} - -// SetMeta sets the error's meta data. -func (e *Error) SetMeta(data Params) *Error { - e.meta = data - return e -} - -func (e *Error) Meta() string { - r, err := json.Marshal(e.meta) - if err != nil { - return "" - } - return string(r) -} - -// JSON creates a properly formatted JSON -func (e *Error) JSON() interface{} { - p := Params{} - if e.meta != nil { - p["meta"] = e.meta - } - if e.Err != nil { - p["error"] = e.Err.Error() - } - if e.Type != TypeNone { - p["type"] = e.Type.String() - } - if len(e.stack) > 0 { - p["stack"] = e.stack - } - return p -} - -// MarshalJSON implements the json.Marshaller interface. -func (e *Error) MarshalJSON() ([]byte, error) { - return json.Marshal(e.JSON()) -} - -// T create a new error with runtime stack trace. -func T(args ...interface{}) *Error { - e := E(args...) - for i := 1; i <= 5; i++ { - _, fn, line, ok := runtime.Caller(i) - if ok { - e.stack = append(e.stack, fmt.Sprintf("%s:%d", fn, line)) - } - } - return e -} - -// E create a new error. -func E(args ...interface{}) *Error { - e := &Error{Type: TypeNone, meta: make(Params)} - var message []string - for _, arg := range args { - switch arg := arg.(type) { - case nil: - continue - case string: - message = append(message, arg) - case *Error: - message = append([]string{arg.Err.Error()}, message...) - appendMap(e.meta, arg.meta) - case error: - message = append([]string{arg.Error()}, message...) - case Type: - e.Type = arg - case Params: - appendMap(e.meta, arg) - case map[string]interface{}: - appendMap(e.meta, arg) - default: - continue - } - } - if len(message) > 0 { - msg := strings.Join(message[:], ": ") - e.Err = errors.New(msg) - } - return e -} diff --git a/pkg/errors/helper_test.go b/pkg/errors/helper_test.go deleted file mode 100644 index f9a317513..000000000 --- a/pkg/errors/helper_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package errors - -import ( - "fmt" - "testing" -) - -func TestIsType(t *testing.T) { - tests := []struct { - error error - errorType Type - result bool - }{ - {fmt.Errorf("test"), TypePlatformRequest, false}, - {&Error{Type: TypePlatformRequest}, TypePlatformRequest, true}, - {&Error{Type: TypePlatformUnmarshal}, TypePlatformRequest, false}, - } - for i, tt := range tests { - t.Run(fmt.Sprintf("TestIsType %d", i), func(t *testing.T) { - s := Is(tt.error, tt.errorType) - if s != tt.result { - t.Errorf("got %t, want %t", s, tt.result) - } - }) - } -} - -func TestEqual(t *testing.T) { - tests := []struct { - err1 error - err2 error - result bool - }{ - {fmt.Errorf("test"), &Error{Type: TypePlatformRequest}, false}, - {&Error{Type: TypePlatformNormalize}, &Error{Type: TypePlatformRequest}, false}, - {&Error{Type: TypePlatformRequest}, &Error{Type: TypePlatformRequest}, true}, - {fmt.Errorf("err1"), fmt.Errorf("err2"), false}, - } - for i, tt := range tests { - t.Run(fmt.Sprintf("TestEqual %d", i), func(t *testing.T) { - s := Equal(tt.err1, tt.err2) - if s != tt.result { - t.Errorf("got %t, want %t", s, tt.result) - } - }) - } -} diff --git a/pkg/errors/helpers.go b/pkg/errors/helpers.go deleted file mode 100644 index 1cafcce81..000000000 --- a/pkg/errors/helpers.go +++ /dev/null @@ -1,49 +0,0 @@ -package errors - -// Is reports whether err is an *Error of the given Type. -// If err is nil then Is returns false. -func Is(err error, t Type) bool { - e, ok := err.(*Error) - if !ok { - return false - } - if e.Type != TypeNone { - return e.Type == t - } - if e.Err != nil { - return Is(e.Err, t) - } - return false -} - -func Equal(err1, err2 error) bool { - e1, ok := err1.(*Error) - if !ok { - return false - } - e2, ok := err2.(*Error) - if !ok { - return false - } - if e1.Err != nil && e2.Err != e1.Err { - return false - } - if e1.Type != TypeNone && e2.Type != e1.Type { - return false - } - if e1.Err != nil { - if _, ok := e1.Err.(*Error); ok { - return Equal(e1.Err, e2.Err) - } - if e2.Err == nil || e2.Err.Error() != e1.Err.Error() { - return false - } - } - return true -} - -func appendMap(root map[string]interface{}, tmp map[string]interface{}) { - for k, v := range tmp { - root[k] = v - } -} diff --git a/pkg/logger/error.go b/pkg/logger/error.go deleted file mode 100755 index 0a6411e33..000000000 --- a/pkg/logger/error.go +++ /dev/null @@ -1,56 +0,0 @@ -package logger - -import ( - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/errors" -) - -type errMessage struct { - *message - err error -} - -func Error(args ...interface{}) { - if len(args) == 0 { - Panic("call to logger.Error with no arguments") - } - e := getError(args...) - log.WithFields(e.params).Error(e.err) -} - -func Fatal(args ...interface{}) { - if len(args) == 0 { - Panic("call to logger.Fatal with no arguments") - } - e := getError(args...) - log.WithFields(e.params).Fatal(e.err) -} - -func Panic(args ...interface{}) { - if len(args) == 0 { - Panic("call to logger.Panic with no arguments") - } - e := getError(args...) - log.WithFields(e.params).Panic(e.err) -} - -func getError(args ...interface{}) *errMessage { - msg := getMessage(args...) - err := &errMessage{message: msg} - for _, arg := range args { - switch arg := arg.(type) { - case *errors.Error: - err.err = arg - case error: - err.err = errors.E(arg) - case nil: - continue - default: - continue - } - } - if err.err == nil { - err.err = errors.E(msg.message, msg.params) - } - return err -} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go deleted file mode 100755 index 221f40798..000000000 --- a/pkg/logger/logger.go +++ /dev/null @@ -1,88 +0,0 @@ -package logger - -import ( - "fmt" - log "github.com/sirupsen/logrus" - "go.elastic.co/apm/module/apmlogrus" - "os" - "strings" -) - -type Params map[string]interface{} - -func InitLogger() { - log.SetFormatter(&log.TextFormatter{}) - log.SetOutput(os.Stdout) - log.AddHook(&apmlogrus.Hook{}) -} - -type message struct { - message string - params map[string]interface{} -} - -func (msg *message) String() string { - if len(msg.params) > 0 { - return fmt.Sprintf("%s - %v", msg.message, msg.params) - } - return msg.message -} - -func Info(args ...interface{}) { - if len(args) == 0 { - Panic("call to logger.Info with no arguments") - } - msg := getMessage(args...) - log.WithFields(msg.params).Info(msg.message) -} - -func Debug(args ...interface{}) { - if len(args) == 0 { - Panic("call to logger.Debug with no arguments") - } - msg := getMessage(args...) - log.WithFields(msg.params).Debug(msg.message) -} - -func Warn(args ...interface{}) { - if len(args) == 0 { - Panic("call to logger.Warn with no arguments") - } - msg := getMessage(args...) - log.WithFields(msg.params).Warn(msg.message) -} - -func getMessage(args ...interface{}) *message { - msg := &message{params: make(Params), message: ""} - var generic []string - var message []string - for _, arg := range args { - switch arg := arg.(type) { - case nil: - continue - case error: - continue - case string: - message = append(message, arg) - case Params: - appendMap(msg.params, arg) - case map[string]interface{}: - appendMap(msg.params, arg) - default: - generic = append(generic, fmt.Sprintf("%s", arg)) - } - } - if len(message) > 0 { - msg.message = strings.Join(message[:], ": ") - } - if len(generic) > 0 { - msg.params["objects"] = strings.Join(generic[:], " | ") - } - return msg -} - -func appendMap(root map[string]interface{}, tmp map[string]interface{}) { - for k, v := range tmp { - root[k] = v - } -} diff --git a/pkg/numbers/decimal.go b/pkg/numbers/decimal.go index 72e40ef4f..580e25039 100644 --- a/pkg/numbers/decimal.go +++ b/pkg/numbers/decimal.go @@ -1,7 +1,7 @@ package numbers import ( - "github.com/trustwallet/blockatlas/pkg/errors" + "errors" "math/big" "strings" "unicode" @@ -19,11 +19,11 @@ func DecimalToSatoshis(dec string) (string, error) { out = strings.TrimLeft(out[:l-1], "0") + out[l-1:l] } if len(out) == 0 { - return "", errors.E("Invalid empty input", errors.Params{"dec": dec, "dec_trimmed": out}) + return "", errors.New("Invalid empty input") } for _, c := range out { if !unicode.IsNumber(c) { - return "", errors.E("not a number", errors.Params{"dec": dec, "c": c}) + return "", errors.New("not a number") } } return out, nil @@ -72,7 +72,7 @@ func DecimalExp(dec string, exp int) string { func HexToDecimal(hex string) (string, error) { var i big.Int if _, ok := i.SetString(hex, 0); !ok { - return "", errors.E("invalid hex", errors.Params{"hex": hex}) + return "", errors.New("invalid hex") } return i.String(), nil } diff --git a/pkg/numbers/number.go b/pkg/numbers/number.go index 101b5f69c..ed3fb56db 100644 --- a/pkg/numbers/number.go +++ b/pkg/numbers/number.go @@ -1,8 +1,8 @@ package numbers import ( + "errors" "github.com/shopspring/decimal" - "github.com/trustwallet/blockatlas/pkg/errors" "math" "math/big" "strconv" @@ -78,7 +78,7 @@ func SliceAtoi(sa []string) ([]int, error) { for _, a := range sa { i, err := strconv.Atoi(a) if err != nil { - return si, errors.E(err, "SliceAtoi error", errors.Params{"sa": sa}) + return si, errors.New(err.Error() + " SliceAtoi error") } si = append(si, i) } diff --git a/platform/binance/client.go b/platform/binance/client.go index 3229fb9d6..f4f09e2c9 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -4,8 +4,8 @@ import ( "fmt" "github.com/imroc/req" "github.com/patrickmn/go-cache" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "net/url" "strconv" "time" @@ -27,8 +27,8 @@ func (c Client) FetchLatestBlockNumber() (int64, error) { } var result NodeInfoResponse if err := resp.ToJSON(&result); err != nil { - logger.Error("URL: " + resp.Request().URL.String()) - logger.Error("Status code: " + resp.Response().Status) + log.Error("URL: " + resp.Request().URL.String()) + log.Error("Status code: " + resp.Response().Status) return 0, err } return int64(result.SyncInfo.LatestBlockHeight), nil @@ -41,8 +41,8 @@ func (c Client) FetchTransactionsInBlock(blockNumber int64) (TransactionsInBlock } var result TransactionsInBlockResponse if err := resp.ToJSON(&result); err != nil { - logger.Error("URL: " + resp.Request().URL.String()) - logger.Error("Status code: " + resp.Response().Status) + log.Error("URL: " + resp.Request().URL.String()) + log.Error("Status code: " + resp.Response().Status) return TransactionsInBlockResponse{}, err } return result, nil @@ -58,8 +58,8 @@ func (c Client) FetchTransactionsByAddressAndTokenID(address, tokenID string) ([ } var result TransactionsInBlockResponse if err := resp.ToJSON(&result); err != nil { - logger.Error("URL: " + resp.Request().URL.String()) - logger.Error("Status code: " + resp.Response().Status) + log.Error("URL: " + resp.Request().URL.String()) + log.Error("Status code: " + resp.Response().Status) return nil, err } return result.Tx, nil @@ -72,8 +72,8 @@ func (c Client) FetchAccountMeta(address string) (AccountMeta, error) { } var result AccountMeta if err := resp.ToJSON(&result); err != nil { - logger.Error("URL: " + resp.Request().URL.String()) - logger.Error("Status code: " + resp.Response().Status) + log.Error("URL: " + resp.Request().URL.String()) + log.Error("Status code: " + resp.Response().Status) return AccountMeta{}, err } return result, nil @@ -91,8 +91,8 @@ func (c Client) FetchTokens() (Tokens, error) { return nil, err } if err := resp.ToJSON(&result); err != nil { - logger.Error("URL: " + resp.Request().URL.String()) - logger.Error("Status code: " + resp.Response().Status) + log.Error("URL: " + resp.Request().URL.String()) + log.Error("Status code: " + resp.Response().Status) return nil, err } c.Cache.Set("tokens", *result, cache.DefaultExpiration) diff --git a/platform/bitcoin/block.go b/platform/bitcoin/block.go index fb3bf2283..e5be57fc6 100644 --- a/platform/bitcoin/block.go +++ b/platform/bitcoin/block.go @@ -1,8 +1,8 @@ package bitcoin import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "sync" ) @@ -27,7 +27,7 @@ func (p *Platform) GetAllBlockPages(total, num int64) []Transaction { defer wg.Done() block, err := p.client.GetTransactionsByBlock(num, page) if err != nil { - logger.Error("GetTransactionsByBlockChan", err, logger.Params{"number": num, "page": page}) + log.WithFields(log.Fields{"number": num, "page": page}).Error("GetTransactionsByBlockChan", err) return } out <- block diff --git a/platform/cosmos/client.go b/platform/cosmos/client.go index fd810dda7..78c9b1122 100644 --- a/platform/cosmos/client.go +++ b/platform/cosmos/client.go @@ -2,9 +2,8 @@ package cosmos import ( "fmt" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "net/url" "strconv" "time" @@ -52,7 +51,7 @@ func (c *Client) CurrentBlockNumber() (num int64, err error) { num, err = strconv.ParseInt(block.Meta.Header.Height, 10, 64) if err != nil { - return num, errors.E("error to ParseInt", errors.TypePlatformUnmarshal) + return num, err } return @@ -71,7 +70,7 @@ func (c *Client) GetDelegations(address string) (delegations Delegations, err er path := fmt.Sprintf("staking/delegators/%s/delegations", address) err = c.Get(&delegations, path, nil) if err != nil { - logger.Error(err, "Cosmos: Failed to get delegations for address") + log.Error(err, "Cosmos: Failed to get delegations for address") } return } @@ -80,7 +79,7 @@ func (c *Client) GetUnbondingDelegations(address string) (delegations UnbondingD path := fmt.Sprintf("staking/delegators/%s/unbonding_delegations", address) err = c.Get(&delegations, path, nil) if err != nil { - logger.Error(err, "Cosmos: Failed to get unbonding delegations for address") + log.Error(err, "Cosmos: Failed to get unbonding delegations for address") } return } diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index b94887305..1ef97352d 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -1,9 +1,8 @@ package cosmos import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" "github.com/trustwallet/golibs/coin" "strconv" @@ -44,7 +43,7 @@ func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { } inflationValue, err := strconv.ParseFloat(inflation.Result, 32) if err != nil { - return nil, errors.E("error to parse inflationValue to float", errors.TypePlatformUnmarshal) + return nil, err } for _, validator := range validators.Result { @@ -68,7 +67,7 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { func (p *Platform) GetMaxAPR() float64 { validators, err := p.GetValidators() if err != nil { - logger.Error("GetMaxAPR", logger.Params{"details": err, "platform": p.Coin().Symbol}) + log.WithFields(log.Fields{"details": err, "platform": p.Coin().Symbol}).Error("GetMaxAPR") return blockatlas.DefaultAnnualReward } @@ -111,9 +110,9 @@ func (p *Platform) UndelegatedBalance(address string) (string, error) { if err != nil { return "0", err } - for _, coin := range account.Account.Value.Coins { - if coin.Denom == p.Denom() { - return coin.Amount, nil + for _, c := range account.Account.Value.Coins { + if c.Denom == p.Denom() { + return c.Amount, nil } } return "0", nil @@ -124,7 +123,9 @@ func NormalizeDelegations(delegations []Delegation, validators blockatlas.Valida for _, v := range delegations { validator, ok := validators[v.ValidatorAddress] if !ok { - logger.Warn("Validator not found", logger.Params{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}) + log.WithFields( + log.Fields{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}, + ).Warn("Validator not found") validator = getUnknownValidator(v.ValidatorAddress) } @@ -144,7 +145,9 @@ func NormalizeUnbondingDelegations(delegations []UnbondingDelegation, validators for _, entry := range v.Entries { validator, ok := validators[v.ValidatorAddress] if !ok { - logger.Warn("Validator not found", logger.Params{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}) + log.WithFields( + log.Fields{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}, + ).Warn("Validator not found") validator = getUnknownValidator(v.ValidatorAddress) } t, _ := time.Parse(time.RFC3339, entry.CompletionTime) diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 3de7d5ffb..7d60ae0c2 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -1,8 +1,8 @@ package cosmos import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "strconv" "sync" @@ -20,7 +20,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { page := 1 txs, err := p.client.GetAddrTxs(addr, tag, page) if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"address": tag, "tag": tag}) + log.WithFields(log.Fields{"address": tag, "tag": tag}).Error("GetAddrTxs", err) return } // Condition when no more pages to paginate @@ -31,14 +31,14 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { totalPages, err := strconv.Atoi(txs.PageTotal) if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"totalPages": totalPages}) + log.WithFields(log.Fields{"totalPages": totalPages}).Error("GetAddrTxs", err) return } // gaia does support sort option, paginate to get latest transactions by passing total pages page // https://github.com/cosmos/gaia/blob/f61b391aee5d04364d2b5539692bbb187ad9b946/docs/resources/gaiacli.md#query-transactions txs2, err := p.client.GetAddrTxs(addr, tag, totalPages) if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"address": tag, "tag": tag}) + log.WithFields(log.Fields{"address": tag, "tag": tag}).Error("GetAddrTxs", err) return } out <- txs2.Txs diff --git a/platform/fio/actor.go b/platform/fio/actor.go index 4fc0a805d..6fa8d5f69 100644 --- a/platform/fio/actor.go +++ b/platform/fio/actor.go @@ -1,8 +1,8 @@ package fio import ( + "errors" "github.com/btcsuite/btcutil/base58" - "github.com/trustwallet/blockatlas/pkg/errors" ) func actorFromPublicKeyOrActor(addressOrActor string) string { @@ -35,11 +35,11 @@ func actorFromPublicKeyBytes(pkBytes []byte) string { func bytesFromPublicKeyString(address string) ([]byte, error) { if address[:3] != "FIO" { - return nil, errors.E("Invalid FIO public key prefix") + return nil, errors.New("Invalid FIO public key prefix") } array := base58.Decode(address[3:]) if len(array) != 37 { - return nil, errors.E("Invalid FIO public key length") + return nil, errors.New("Invalid FIO public key length") } return array, nil } diff --git a/platform/fio/client.go b/platform/fio/client.go index d809f52b7..455cd811e 100644 --- a/platform/fio/client.go +++ b/platform/fio/client.go @@ -2,7 +2,6 @@ package fio import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" ) // Client for FIO API @@ -19,7 +18,7 @@ func (c *Client) getTransactions(account string) (actions []Action, error error) Sort: "desc", }) if err != nil { - return nil, errors.E(err, "Error from get_actions", errors.Params{"account_name": account, "inner_error": err.Error()}) + return nil, err } return res.Actions, nil } diff --git a/platform/fio/transaction.go b/platform/fio/transaction.go index 758be6752..1a42f698f 100644 --- a/platform/fio/transaction.go +++ b/platform/fio/transaction.go @@ -8,8 +8,8 @@ import ( "strings" "time" + "errors" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" ) func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err error) { @@ -46,16 +46,16 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err // convert to action-specific data dataJSON, err := json.Marshal(action.ActionTrace.Act.Data) if err != nil { - return blockatlas.Tx{}, errors.E("Unparseable Data field") + return blockatlas.Tx{}, errors.New("Unparseable Data field") } switch action.ActionTrace.Act.Name { case "transfer": var actionData ActionDataTransfer if json.Unmarshal(dataJSON, &actionData) != nil { - return blockatlas.Tx{}, errors.E("Unparseable Data field") + return blockatlas.Tx{}, errors.New("Unparseable Data field") } if actionData.Memo == "FIO API fees. Thank you." { - return blockatlas.Tx{}, errors.E("Skip meaningless hardcoded fee action") + return blockatlas.Tx{}, errors.New("Skip meaningless hardcoded fee action") } from = actionData.From to = actionData.To @@ -69,7 +69,7 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err case "trnsfiopubky": var actionData ActionDataTrnsfiopubky if json.Unmarshal(dataJSON, &actionData) != nil { - return blockatlas.Tx{}, errors.E("Unparseable Data field") + return blockatlas.Tx{}, errors.New("Unparseable Data field") } from = actionData.Actor to = actorFromPublicKeyOrActor(actionData.PayeePublicKey) @@ -99,7 +99,7 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err tx.Direction = tx.GetTransactionDirection(account) return tx, nil } - return blockatlas.Tx{}, errors.E("Unknown action") + return blockatlas.Tx{}, errors.New("Unknown action") } func unique(txs []blockatlas.Tx) []blockatlas.Tx { diff --git a/platform/harmony/client.go b/platform/harmony/client.go index 2749c611f..a94d2d70e 100644 --- a/platform/harmony/client.go +++ b/platform/harmony/client.go @@ -4,8 +4,8 @@ import ( "fmt" "strconv" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" ) @@ -47,7 +47,7 @@ func (c *Client) GetValidators() (validators Validators, err error) { err = rpcCallStub(c, &validators.Validators, "hmy_getAllValidatorInformation", []interface{}{-1}) if err != nil { - logger.Error(err, "Harmony: Failed to get all validator addresses") + log.Error(err, "Harmony: Failed to get all validator addresses") } return @@ -57,7 +57,7 @@ func (c *Client) GetDelegations(address string) (delegations Delegations, err er err = rpcCallStub(c, &delegations.List, "hmy_getDelegationsByDelegator", []interface{}{address}) if err != nil { - logger.Error(err, "Harmony: Failed to get delegations for address") + log.Error(err, "Harmony: Failed to get delegations for address") } return } diff --git a/platform/harmony/stake.go b/platform/harmony/stake.go index 6d9d4cd07..f3f5cd14c 100644 --- a/platform/harmony/stake.go +++ b/platform/harmony/stake.go @@ -1,9 +1,8 @@ package harmony import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" "math/big" "strconv" @@ -51,7 +50,7 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { func (p *Platform) GetMaxAPR() float64 { validators, err := p.client.GetValidators() if err != nil { - logger.Error("GetMaxAPR", logger.Params{"details": err, "platform": p.Coin().Symbol}) + log.WithFields(log.Fields{"details": err, "platform": p.Coin().Symbol}).Error("GetMaxAPR") return Annual } @@ -97,7 +96,9 @@ func NormalizeDelegations(delegations []Delegation, validators blockatlas.Valida for _, v := range delegations { validator, ok := validators[v.ValidatorAddress] if !ok { - logger.Error(errors.E("Validator not found", errors.Params{"address": v.ValidatorAddress, "platform": "harmony", "delegation": v.DelegatorAddress})) + log.WithFields( + log.Fields{"address": v.ValidatorAddress, "platform": "harmony", "delegation": v.DelegatorAddress}, + ).Error("Validator not found") continue } diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index 1b88657e3..e1219f9ce 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -2,7 +2,6 @@ package harmony import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" "strconv" @@ -30,40 +29,38 @@ func NormalizeTxs(txs []Transaction) blockatlas.TxPage { return normalizeTxs } -func GetNormalizationError(err error) error { - return errors.E(err, errors.TypePlatformNormalize, errors.Params{"method": "Harmony_NormalizeTx"}) -} + func NormalizeTx(trx *Transaction) (tx blockatlas.Tx, b bool, err error) { gasPrice, err := hexToInt(trx.GasPrice) if err != nil { - return blockatlas.Tx{}, false, GetNormalizationError(err) + return blockatlas.Tx{}, false, err } gas, err := hexToInt(trx.Gas) if err != nil { - return blockatlas.Tx{}, false, GetNormalizationError(err) + return blockatlas.Tx{}, false, err } fee := gas * gasPrice literalFee := strconv.Itoa(int(fee)) literalValue, err := numbers.HexToDecimal(trx.Value) if err != nil { - return blockatlas.Tx{}, false, GetNormalizationError(err) + return blockatlas.Tx{}, false, err } block, err := hexToInt(trx.BlockNumber) if err != nil { - return blockatlas.Tx{}, false, GetNormalizationError(err) + return blockatlas.Tx{}, false, err } nonce, err := hexToInt(trx.Nonce) if err != nil { - return blockatlas.Tx{}, false, GetNormalizationError(err) + return blockatlas.Tx{}, false, err } timestamp, err := hexToInt(trx.Timestamp) if err != nil { - return blockatlas.Tx{}, false, GetNormalizationError(err) + return blockatlas.Tx{}, false, err } return blockatlas.Tx{ diff --git a/platform/icon/transaction.go b/platform/icon/transaction.go index ed1fc646c..f9e897aba 100644 --- a/platform/icon/transaction.go +++ b/platform/icon/transaction.go @@ -1,9 +1,8 @@ package icon import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" "time" @@ -31,8 +30,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { func Normalize(trx *Tx) (tx blockatlas.Tx, b bool) { date, err := time.Parse("2006-01-02T15:04:05.999Z0700", trx.CreateDate) if err != nil { - err = errors.E(err, errors.TypePlatformUnmarshal) - logger.Error(err) + log.Error(err) return tx, false } fee := numbers.DecimalExp(string(trx.Fee), 18) diff --git a/platform/iotex/client.go b/platform/iotex/client.go index 5e86adb50..88af36324 100644 --- a/platform/iotex/client.go +++ b/platform/iotex/client.go @@ -2,9 +2,8 @@ package iotex import ( "fmt" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "net/url" "strconv" ) @@ -21,7 +20,7 @@ func (c *Client) GetLatestBlock() (int64, error) { } b, err := strconv.ParseInt(chainMeta.Height, 10, 64) if err != nil { - return 0, errors.E(err, "ParseInt failed", errors.TypePlatformUnmarshal) + return 0, err } return b, nil } @@ -44,7 +43,7 @@ func (c *Client) GetTxsOfAddress(address string, start int64) (*Response, error) }) if err != nil { - logger.Error(err, "IOTEX: Failed to get transactions for address", logger.Params{"address": address}) + log.WithFields(log.Fields{"address": address}).Error(err, "IOTEX: Failed to get transactions for address") return nil, blockatlas.ErrSourceConn } return &response, err diff --git a/platform/kava/client.go b/platform/kava/client.go index a6a9dc096..6139a681f 100644 --- a/platform/kava/client.go +++ b/platform/kava/client.go @@ -2,9 +2,8 @@ package kava import ( "fmt" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "net/url" "strconv" "time" @@ -52,9 +51,8 @@ func (c *Client) CurrentBlockNumber() (num int64, err error) { num, err = strconv.ParseInt(block.Meta.Header.Height, 10, 64) if err != nil { - return num, errors.E("error to ParseInt", errors.TypePlatformUnmarshal) + return num, err } - return } @@ -71,7 +69,7 @@ func (c *Client) GetDelegations(address string) (delegations Delegations, err er path := fmt.Sprintf("staking/delegators/%s/delegations", address) err = c.Get(&delegations, path, nil) if err != nil { - logger.Error(err, "Cosmos: Failed to get delegations for address") + log.Error(err, "Cosmos: Failed to get delegations for address") } return } @@ -80,7 +78,7 @@ func (c *Client) GetUnbondingDelegations(address string) (delegations UnbondingD path := fmt.Sprintf("staking/delegators/%s/unbonding_delegations", address) err = c.Get(&delegations, path, nil) if err != nil { - logger.Error(err, "Cosmos: Failed to get unbonding delegations for address") + log.Error(err, "Cosmos: Failed to get unbonding delegations for address") } return } diff --git a/platform/kava/stake.go b/platform/kava/stake.go index 47dbc313c..e7a44cfbf 100644 --- a/platform/kava/stake.go +++ b/platform/kava/stake.go @@ -2,13 +2,14 @@ package kava import ( "fmt" + "strconv" + "time" + "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" "github.com/trustwallet/golibs/coin" - "strconv" - "time" + + log "github.com/sirupsen/logrus" ) const ( @@ -45,7 +46,7 @@ func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { } inflationValue, err := strconv.ParseFloat(inflation.Result, 32) if err != nil { - return nil, errors.E("error to parse inflationValue to float", errors.TypePlatformUnmarshal) + return nil, err } for _, validator := range validators.Result { @@ -69,7 +70,7 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { func (p *Platform) GetMaxAPR() float64 { validators, err := p.GetValidators() if err != nil { - logger.Error("GetMaxAPR", logger.Params{"details": err, "platform": p.Coin().Symbol}) + log.WithFields(log.Fields{"details": err, "platform": p.Coin().Symbol}).Error("GetMaxAPR") return blockatlas.DefaultAnnualReward } @@ -125,7 +126,9 @@ func NormalizeDelegations(delegations []Delegation, validators blockatlas.Valida for _, v := range delegations { validator, ok := validators[v.ValidatorAddress] if !ok { - logger.Warn("Validator not found", logger.Params{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}) + log.WithFields( + log.Fields{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}, + ).Warn("Validator not found") validator = getUnknownValidator(v.ValidatorAddress) } @@ -145,7 +148,9 @@ func NormalizeUnbondingDelegations(delegations []UnbondingDelegation, validators for _, entry := range v.Entries { validator, ok := validators[v.ValidatorAddress] if !ok { - logger.Warn("Validator not found", logger.Params{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}) + log.WithFields( + log.Fields{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}, + ).Warn("Validator not found") validator = getUnknownValidator(v.ValidatorAddress) } t, _ := time.Parse(time.RFC3339, entry.CompletionTime) diff --git a/platform/kava/transaction.go b/platform/kava/transaction.go index 6212e337c..f8315db2a 100644 --- a/platform/kava/transaction.go +++ b/platform/kava/transaction.go @@ -1,8 +1,8 @@ package kava import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "strconv" "sync" @@ -20,7 +20,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { page := 1 txs, err := p.client.GetAddrTxs(addr, tag, page) if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"address": tag, "tag": tag}) + log.WithFields(log.Fields{"address": tag, "tag": tag}).Error("GetAddrTxs", err) return } // Condition when no more pages to paginate @@ -31,14 +31,14 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { totalPages, err := strconv.Atoi(txs.PageTotal) if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"totalPages": totalPages}) + log.WithFields(log.Fields{"totalPages": totalPages}).Error("GetAddrTxs", err) return } // gaia does support sort option, paginate to get latest transactions by passing total pages page // https://github.com/cosmos/gaia/blob/f61b391aee5d04364d2b5539692bbb187ad9b946/docs/resources/gaiacli.md#query-transactions txs2, err := p.client.GetAddrTxs(addr, tag, totalPages) if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"address": tag, "tag": tag}) + log.WithFields(log.Fields{"address": tag, "tag": tag}).Error("GetAddrTxs", err) return } out <- txs2.Txs diff --git a/platform/ontology/block.go b/platform/ontology/block.go index f656e0cb3..3d5ed8a5b 100644 --- a/platform/ontology/block.go +++ b/platform/ontology/block.go @@ -1,17 +1,17 @@ package ontology import ( + "errors" blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" ) func (p *Platform) CurrentBlockNumber() (int64, error) { block, err := p.client.CurrentBlockNumber() if err != nil { - return 0, errors.E(err, "CurrentBlockNumber") + return 0, err } if len(block.Result.Records) == 0 { - return 0, errors.E("invalid block height result") + return 0, errors.New("invalid block height result") } return block.Result.Records[0].Height, nil } diff --git a/platform/ontology/client.go b/platform/ontology/client.go index 3844cfbcb..53445a4ed 100644 --- a/platform/ontology/client.go +++ b/platform/ontology/client.go @@ -3,7 +3,6 @@ package ontology import ( "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "net/url" ) @@ -15,7 +14,7 @@ func (c *Client) GetBalances(address string) (balances BalancesResult, err error path := fmt.Sprintf("v2/addresses/%s/native/balances", address) err = c.Get(&balances, path, nil) if err != nil || balances.Msg != MsgSuccess { - return balances, errors.E(err, "explorer client GetBalances", errors.Params{"platform": "ONT"}) + return balances, err } return } @@ -25,7 +24,7 @@ func (c *Client) GetTxsOfAddress(address string) (txPage TxsResult, err error) { path := fmt.Sprintf("v2/addresses/%s/transactions", address) err = c.Get(&txPage, path, query) if err != nil || txPage.Msg != MsgSuccess { - return txPage, errors.E(err, "explorer client GetTxsOfAddress", errors.Params{"platform": "ONT"}) + return txPage, err } return } @@ -35,7 +34,7 @@ func (c *Client) CurrentBlockNumber() (blocks BlockResult, err error) { path := "v2/blocks" err = c.Get(&blocks, path, query) if err != nil || blocks.Msg != MsgSuccess { - return blocks, errors.E(err, "explorer client CurrentBlockNumber", errors.Params{"platform": "ONT"}) + return blocks, err } return } @@ -44,7 +43,7 @@ func (c *Client) GetBlockByNumber(num int64) (block BlockResults, err error) { path := fmt.Sprintf("v2/blocks/%d", num) err = c.Get(&block, path, nil) if err != nil || block.Msg != MsgSuccess { - return block, errors.E(err, "explorer client GetBlockByNumber", errors.Params{"platform": "ONT"}) + return block, err } return } @@ -54,7 +53,7 @@ func (c *Client) GetTxDetailsByHash(hash string) (Tx, error) { var response TxResult err := c.Get(&response, path, nil) if err != nil || response.Msg != MsgSuccess { - return Tx{}, errors.E(err, "explorer client GetTxDetailsByHash", errors.Params{"platform": "ONT"}) + return Tx{}, err } var ontTxV2 Tx if response.Result.EventType == 3 { diff --git a/platform/ontology/stake.go b/platform/ontology/stake.go index ed6f84491..d2b070471 100644 --- a/platform/ontology/stake.go +++ b/platform/ontology/stake.go @@ -2,7 +2,6 @@ package ontology import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/services/assets" ) @@ -39,7 +38,7 @@ func (p *Platform) UndelegatedBalance(address string) (string, error) { } balance := acc.Result.getBalance(AssetONT) if balance == nil { - return "0", errors.E("Invalid asset balance", errors.Params{"asset": AssetONT}) + return "0", err } return balance.Balance, nil } diff --git a/platform/ontology/transaction.go b/platform/ontology/transaction.go index 765319740..a6618d7ca 100644 --- a/platform/ontology/transaction.go +++ b/platform/ontology/transaction.go @@ -1,9 +1,9 @@ package ontology import ( + "errors" + log "github.com/sirupsen/logrus" blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" "sync" @@ -16,11 +16,10 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { srcTxs, err := p.client.GetTxsOfAddress(address) if err != nil { - logger.Error(err, "Ontology: Failed to get transactions for address and token", - logger.Params{ - "address": address, - "token": token, - }) + log.WithFields(log.Fields{ + "address": address, + "token": token, + }).Error(err, "Ontology: Failed to get transactions for address and token") return blockatlas.TxPage{}, err } txPage := normalizeTxs(srcTxs.Result, AssetType(token)) @@ -123,7 +122,7 @@ func (p *Platform) getTxDetails(srcTx []Tx) ([]Tx, error) { wg.Wait() close(txsOntV2Chan) if len(txsOntV2Chan) != len(srcTx) { - return nil, errors.E("getTxDetails failed to call client.GetTxDetailsByHash http get or unmarshal") + return nil, errors.New("getTxDetails failed to call client.GetTxDetailsByHash http get or unmarshal") } var txsOntV2 []Tx for tx := range txsOntV2Chan { diff --git a/platform/registry.go b/platform/registry.go index badbce4b8..3b56d3cad 100644 --- a/platform/registry.go +++ b/platform/registry.go @@ -1,8 +1,8 @@ package platform import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" ) var ( @@ -24,12 +24,13 @@ var ( func getActivePlatforms(handles []string) []blockatlas.Platform { if len(handles) == 0 { - logger.Fatal("Please, use ATLAS_PLATFORM handle with non-empty value, see more at Readme. Example: all", logger.Params{"ATLAS_PLATFORM": handles}) + log.WithFields(log.Fields{"ATLAS_PLATFORM": handles}). + Fatal("Please, use ATLAS_PLATFORM handle with non-empty value, see more at Readme. Example: all") return nil } allPlatforms := getAllHandlers() - logger.Info("Platform API setup with: ", logger.Params{"handles": handles}) + log.WithFields(log.Fields{"handles": handles}).Info("Platform API setup with") platforms := make([]blockatlas.Platform, 0, len(handles)) @@ -56,13 +57,13 @@ func Init(platformHandles []string) { for _, platform := range platformList { handle := platform.Coin().Handle - p := logger.Params{ + p := log.Fields{ "platform": handle, "coin": platform.Coin(), } if _, exists := Platforms[handle]; exists { - logger.Fatal("Duplicate handle", p) + log.WithFields(p).Fatal("Duplicate handle") } Platforms[handle] = platform if blockAPI, ok := platform.(blockatlas.BlockAPI); ok { diff --git a/platform/solana/stake.go b/platform/solana/stake.go index 3cbbe0b33..41a8e3686 100644 --- a/platform/solana/stake.go +++ b/platform/solana/stake.go @@ -5,8 +5,8 @@ import ( "encoding/binary" "fmt" "github.com/btcsuite/btcutil/base58" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" "strconv" ) @@ -133,7 +133,7 @@ func NormalizeDelegations(stakeAccounts []StakeData, validators blockatlas.Valid votePubkey := base58.Encode(stakeState.VoterPubkey[:]) validator, ok := validators[votePubkey] if !ok { - logger.Debug(fmt.Sprintf("Unpublished solana validator: %s", votePubkey)) + log.Debug(fmt.Sprintf("Unpublished solana validator: %s", votePubkey)) continue } status := blockatlas.DelegationStatusPending diff --git a/platform/stellar/client.go b/platform/stellar/client.go index 1c5a06758..3548baa17 100644 --- a/platform/stellar/client.go +++ b/platform/stellar/client.go @@ -1,9 +1,9 @@ package stellar import ( + "errors" "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "net/url" ) @@ -39,7 +39,7 @@ func (c *Client) CurrentBlockNumber() (int64, error) { } if len(ledgers.Embedded.Records) == 0 { - return 0, errors.E("CurrentBlockNumber: Records is empty", errors.TypePlatformUnmarshal) + return 0, errors.New("CurrentBlockNumber: Records is empty") } return ledgers.Embedded.Records[0].Sequence, nil } diff --git a/platform/tezos/block.go b/platform/tezos/block.go index 8b5e596a3..8f4603817 100644 --- a/platform/tezos/block.go +++ b/platform/tezos/block.go @@ -1,8 +1,8 @@ package tezos import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" ) func (p *Platform) CurrentBlockNumber() (int64, error) { @@ -13,7 +13,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { txTypes := []string{TxTypeTransaction, TxTypeDelegation} srcTxs, err := p.client.GetBlockByNumber(num, txTypes) if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"txType": txTypes, "num": num}) + log.WithFields(log.Fields{"txType": txTypes, "num": num}).Error("GetAddrTxs", err) return nil, err } txs := NormalizeTxs(srcTxs, "") diff --git a/platform/tezos/stake.go b/platform/tezos/stake.go index 25e0ebc27..3d5065b08 100644 --- a/platform/tezos/stake.go +++ b/platform/tezos/stake.go @@ -1,8 +1,8 @@ package tezos import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" ) @@ -29,7 +29,7 @@ func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { func (p *Platform) isValidatorActive(id string) bool { res, err := p.rpcClient.fetchValidatorActivityInfo(id) if err != nil { - logger.Error("Tezos activity validator " + err.Error()) + log.Error("Tezos activity validator " + err.Error()) return false } return !res.Deactivated @@ -54,7 +54,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e func NormalizeDelegation(account Account, validators blockatlas.ValidatorMap) (blockatlas.DelegationsPage, error) { validator, ok := validators[account.Delegate] if !ok { - logger.Warn("Validator not found", logger.Params{"platform": "tezos", "delegation": account.Delegate}) + log.WithFields(log.Fields{"platform": "tezos", "delegation": account.Delegate}).Warn("Validator not found") validator = getUnknownValidator(account.Delegate) } return blockatlas.DelegationsPage{ diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index bd5168b48..f09205c4d 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -1,8 +1,8 @@ package tezos import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { txTypes := []string{TxTypeTransaction, TxTypeDelegation} txs, err := p.client.GetTxsOfAddress(address, txTypes) if err != nil { - logger.Error("GetAddrTxs", err, logger.Params{"txType": txTypes, "addr": address}) + log.WithFields(log.Fields{"txType": txTypes, "addr": address}).Error("GetAddrTxs", err) return nil, err } diff --git a/platform/tron/client.go b/platform/tron/client.go index 5eb98880e..e95210ad3 100644 --- a/platform/tron/client.go +++ b/platform/tron/client.go @@ -3,7 +3,6 @@ package tron import ( "fmt" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "net/url" "time" ) @@ -28,7 +27,7 @@ func (c *Client) fetchBlockByNumber(num int64) (Block, error) { var blocks Blocks err := c.Post(&blocks, "wallet/getblockbylimitnext", BlockRequest{StartNum: num, EndNum: num + 1}) if err != nil || blocks.Blocks == nil || len(blocks.Blocks) == 0 { - return Block{}, errors.E(err, "block not found", errors.Params{"block": num}) + return Block{}, err } return blocks.Blocks[0], nil } diff --git a/platform/tron/stake.go b/platform/tron/stake.go index c8c785939..3f38ed8c7 100644 --- a/platform/tron/stake.go +++ b/platform/tron/stake.go @@ -1,9 +1,9 @@ package tron import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/assets" "strconv" "time" @@ -98,7 +98,7 @@ func NormalizeDelegations(data *AccountData, validators blockatlas.ValidatorMap) for _, v := range data.Votes { validator, ok := validators[v.VoteAddress] if !ok { - logger.Warn("Validator not found", logger.Params{"address": v.VoteAddress, "platform": "tron"}) + log.WithFields(log.Fields{"address": v.VoteAddress, "platform": "tron"}).Warn("Validator not found") continue } delegation := blockatlas.Delegation{ diff --git a/platform/tron/token.go b/platform/tron/token.go index e6e6406be..1bd9322dc 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -1,10 +1,10 @@ package tron import ( + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" - "strings" "github.com/trustwallet/golibs/coin" + "strings" "sync" "time" ) @@ -31,7 +31,7 @@ func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, trc20Tokens, err := p.explorerClient.fetchAllTRC20Tokens(address) if err != nil { - logger.Error("Explorer error" + err.Error()) + log.Error("Explorer error" + err.Error()) } for _, t := range trc20Tokens { @@ -58,7 +58,7 @@ func (p *Platform) getTokens(ids []string) chan blockatlas.Token { time.Sleep(time.Millisecond) err := p.getTokensChannel(i, c) if err != nil { - logger.Error("tron getTokens: " + i) + log.Error("tron getTokens: " + i) } }(id, tkChan) } diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index cf3a53ec9..2509f9f6f 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -1,10 +1,10 @@ package tron import ( + "errors" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/golibs/coin" "strconv" "strings" @@ -34,7 +34,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { } func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { - unknownTokenType := errors.E("unknownTokenType") + unknownTokenType := errors.New("unknownTokenType") tokenType := getTokenType(token) switch tokenType { @@ -82,19 +82,17 @@ func (p *Platform) fetchTransactionsForTRC10Tokens(address, token string) (block tokenTxs, err := p.client.fetchTxsOfAddress(address, token) if err != nil { - return nil, errors.E(err, "TRON: failed to get token from address", errors.TypePlatformApi, - errors.Params{"address": address, "token": token}) + return nil, err } info, err := p.client.fetchTokenInfo(token) if err != nil { - return nil, errors.E(err, "TRON: failed to get token info", errors.TypePlatformApi, - errors.Params{"address": address, "token": token}) + return nil, err } for _, srcTx := range tokenTxs { tx, err := normalize(srcTx) if err != nil { - logger.Error(err) + log.Error(err) continue } if info.Data != nil && len(info.Data) > 0 { @@ -135,26 +133,22 @@ func normalizeTRC20Transactions(transactions TRC20Transactions) blockatlas.Txs { func normalize(srcTx Tx) (*blockatlas.Tx, error) { if len(srcTx.Data.Contracts) == 0 { - return nil, errors.E("TRON: transfer without contract", errors.TypePlatformApi, - errors.Params{"tx": srcTx}) + return nil, errors.New("no contracts") } contract := srcTx.Data.Contracts[0] if contract.Type != TransferContract && contract.Type != TransferAssetContract { - return nil, errors.E("TRON: invalid contract transfer", errors.TypePlatformApi, - errors.Params{"tx": srcTx, "type": contract.Type}) + return nil, errors.New("TRON: invalid contract transfer") } transfer := contract.Parameter.Value from, err := address.HexToAddress(transfer.OwnerAddress) if err != nil { - return nil, errors.E(err, "TRON: failed to get from address", errors.TypePlatformApi, - errors.Params{"tx": srcTx}) + return nil, err } to, err := address.HexToAddress(transfer.ToAddress) if err != nil { - return nil, errors.E(err, "TRON: failed to get to address", errors.TypePlatformApi, - errors.Params{"tx": srcTx}) + return nil, err } return &blockatlas.Tx{ diff --git a/platform/vechain/stake.go b/platform/vechain/stake.go index c407c3b19..191879f72 100644 --- a/platform/vechain/stake.go +++ b/platform/vechain/stake.go @@ -2,7 +2,6 @@ package vechain import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/blockatlas/services/assets" ) @@ -40,7 +39,7 @@ func (p *Platform) UndelegatedBalance(address string) (string, error) { } balance, err := numbers.HexToDecimal(acc.Balance) if err != nil { - return "0", errors.E("Invalid asset balance", errors.Params{"balance": acc.Balance}) + return "0", err } return balance, nil } diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index ade4ffbf7..9a8933ac2 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -1,10 +1,10 @@ package vechain import ( + "errors" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/pkg/numbers" "strconv" "sync" @@ -44,7 +44,7 @@ func (p *Platform) getTransactionsByIDs(ids []string) chan blockatlas.TxPage { defer wg.Done() err := p.getTransactionChannel(i, c) if err != nil { - logger.Error(err) + log.Error(err) } }(id, txChan) } @@ -56,20 +56,17 @@ func (p *Platform) getTransactionsByIDs(ids []string) chan blockatlas.TxPage { func (p *Platform) getTransactionChannel(id string, txChan chan blockatlas.TxPage) error { srcTx, err := p.client.GetTransactionByID(id) if err != nil { - return errors.E(err, "Failed to get tx", errors.TypePlatformUnmarshal, - errors.Params{"id": id}) + return err } receipt, err := p.client.GetTransactionReceiptByID(id) if err != nil { - return errors.E(err, "Failed to get tx id receipt", errors.TypePlatformUnmarshal, - errors.Params{"id": id}) + return err } txs, err := p.NormalizeTokenTransaction(srcTx, receipt) if err != nil { - return errors.E(err, "Failed to NormalizeBlockTransactions tx", errors.TypePlatformUnmarshal, - errors.Params{"tx": srcTx}) + return err } txChan <- txs return nil @@ -77,7 +74,7 @@ func (p *Platform) getTransactionChannel(id string, txChan chan blockatlas.TxPag func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (blockatlas.TxPage, error) { if receipt.Outputs == nil || len(receipt.Outputs) == 0 { - return blockatlas.TxPage{}, errors.E("NormalizeBlockTransaction: Clauses not found", errors.Params{"tx": srcTx}) + return blockatlas.TxPage{}, errors.New("NormalizeBlockTransaction: Clauses not found") } fee, err := numbers.HexToDecimal(receipt.Paid) @@ -215,7 +212,7 @@ func getTokenTransactionDirectory(originSender, topicsFrom, topicsTo string) (di if originSender == topicsTo && originSender != topicsFrom { return blockatlas.DirectionOutgoing, nil } - return "", errors.E("Unknown direction") + return "", errors.New("Unknown direction") } func getTransferDirectory(sender, recipient, addr string) (dir blockatlas.Direction, err error) { @@ -228,5 +225,5 @@ func getTransferDirectory(sender, recipient, addr string) (dir blockatlas.Direct if recipient == addr && sender != addr { return blockatlas.DirectionIncoming, nil } - return "", errors.E("Unknown direction") + return "", errors.New("Unknown direction") } diff --git a/services/assets/client.go b/services/assets/client.go index 2b03c261c..c12b051ef 100644 --- a/services/assets/client.go +++ b/services/assets/client.go @@ -2,7 +2,6 @@ package assets import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/golibs/coin" "time" ) @@ -16,7 +15,7 @@ func fetchValidatorsInfo(coin coin.Coin) (AssetValidators, error) { request := blockatlas.InitClient(AssetsURL + coin.Handle) err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) if err != nil { - return nil, errors.E(err, errors.Params{"coin": coin.Handle}) + return nil, err } return results, nil } diff --git a/services/assets/validator.go b/services/assets/validator.go index 64a12f923..115de82c8 100644 --- a/services/assets/validator.go +++ b/services/assets/validator.go @@ -2,7 +2,6 @@ package assets import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" "sort" @@ -20,7 +19,7 @@ func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) func getValidators(api blockatlas.StakeAPI) (AssetValidators, blockatlas.ValidatorPage, error) { assetsValidators, err := fetchValidatorsInfo(api.Coin()) if err != nil { - return nil, nil, errors.E(err, "unable to fetch validators list from the registry") + return nil, nil, err } validators, err := api.GetValidators() diff --git a/services/notifier/base.go b/services/notifier/base.go index 4ee0949fc..e1912f06c 100644 --- a/services/notifier/base.go +++ b/services/notifier/base.go @@ -2,10 +2,10 @@ package notifier import ( "context" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/pkg/address" - "github.com/trustwallet/blockatlas/pkg/logger" "strconv" "go.elastic.co/apm" @@ -26,13 +26,13 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { defer func() { if err := delivery.Ack(false); err != nil { - logger.Error(err) + log.Error(err) } }() txs, err := GetTransactionsFromDelivery(delivery, Notifier, ctx) if err != nil { - logger.Error("failed to get transactions", err) + log.Error("failed to get transactions", err) } allAddresses := make([]string, 0) @@ -68,5 +68,5 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { for _, batch := range batches { publishNotificationBatch(batch, ctx) } - logger.Info("------------------------------------------------------------") + log.Info("------------------------------------------------------------") } diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index 028836c13..04d3ced52 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -3,11 +3,11 @@ package notifier import ( "context" "encoding/json" + "errors" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" - "github.com/trustwallet/blockatlas/pkg/logger" "go.elastic.co/apm" ) @@ -21,10 +21,10 @@ func GetTransactionsFromDelivery(delivery amqp.Delivery, service string, ctx con return nil, err } - logger.Info("Consumed", logger.Params{"service": service, "txs": len(txs), "coin": txs[0].Coin}) + log.WithFields(log.Fields{"service": service, "txs": len(txs), "coin": txs[0].Coin}).Info("Consumed") if len(txs) == 0 { - return nil, errors.E("empty txs list") + return nil, errors.New("empty txs list") } return txs, nil } @@ -35,14 +35,12 @@ func publishNotificationBatch(batch []TransactionNotification, ctx context.Conte raw, err := json.Marshal(batch) if err != nil { - err = errors.E(err, " failed to dispatch event") - logger.Fatal(err) + log.Fatal(err) } err = mq.TxNotifications.Publish(raw) if err != nil { - err = errors.E(err, " failed to dispatch event") - logger.Fatal(err) + log.Fatal(err) } - logger.Info("Txs batch dispatched", logger.Params{"service": Notifier, "txs": len(batch)}) + log.WithFields(log.Fields{"service": Notifier, "txs": len(batch)}).Info("Txs batch dispatched") } diff --git a/services/parser/parser.go b/services/parser/parser.go index aef53f4c7..dfddec74f 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -3,16 +3,16 @@ package parser import ( "context" "encoding/json" + "errors" "fmt" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/errors" "github.com/trustwallet/blockatlas/pkg/numbers" "go.elastic.co/apm" "sync/atomic" - "github.com/trustwallet/blockatlas/pkg/logger" + log "github.com/sirupsen/logrus" "math/rand" "sort" "sync" @@ -47,18 +47,18 @@ type ( const MinTxsBatchLimit = 500 func RunParser(params Params) { - logger.Info("------------------------------------------------------------") + log.Info("------------------------------------------------------------") for { select { case <-params.Ctx.Done(): - logger.Info(fmt.Sprintf("Parser of %s stopped parsing blocks", params.Api.Coin().Handle)) + log.Info(fmt.Sprintf("Parser of %s stopped parsing blocks", params.Api.Coin().Handle)) params.StopChannel <- struct{}{} return default: parse(params) time.Sleep(params.ParsingBlocksInterval) } - logger.Info("------------------------------------------------------------") + log.Info("------------------------------------------------------------") } } @@ -77,7 +77,7 @@ func parse(params Params) { lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params, ctx) if err != nil || lastParsedBlock > currentBlock { - logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error(err) time.Sleep(params.ParsingBlocksInterval) return } @@ -86,7 +86,7 @@ func parse(params Params) { err = SaveLastParsedBlock(params, blocks, ctx) if err != nil { - logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error(err) time.Sleep(params.ParsingBlocksInterval) return } @@ -96,7 +96,7 @@ func parse(params Params) { PublishTransactionsBatch(params, txs, ctx) - logger.Info("End of parse step") + log.Info("End of parse step") } func GetBlocksIntervalToFetch(params Params, ctx context.Context) (int64, int64, error) { @@ -105,12 +105,12 @@ func GetBlocksIntervalToFetch(params Params, ctx context.Context) (int64, int64, lastParsedBlock, err := params.Database.GetLastParsedBlockNumber(params.Api.Coin().Handle, ctx) if err != nil { - return 0, 0, errors.E(err, "Polling failed: tracker didn't return last known block number") + return 0, 0, errors.New(err.Error() + " Polling failed: tracker didn't return last known block number") } currentBlock, err := params.Api.CurrentBlockNumber() currentBlock -= params.Api.Coin().MinConfirmations if err != nil { - return 0, 0, errors.E(err, "Polling failed: source didn't return chain head number") + return 0, 0, errors.New(err.Error() + "Polling failed: source didn't return chain head number") } if currentBlock-lastParsedBlock > int64(params.BacklogCount) { @@ -128,13 +128,14 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64, ctx context defer span.End() if lastParsedBlock == currentBlock { - logger.Info("No new blocks", logger.Params{"last": lastParsedBlock, "coin": params.Api.Coin().ID, "time": time.Now().Unix()}) + log.WithFields(log.Fields{"last": lastParsedBlock, "coin": params.Api.Coin().ID, "time": time.Now().Unix()}). + Info("No new blocks") return nil } blocksCount := currentBlock - lastParsedBlock if blocksCount < 0 { - logger.Error("Current block is 0", logger.Params{"coin": params.Api.Coin().Handle}) + log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error("Current block is 0") return nil } @@ -170,7 +171,7 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64, ctx context for err := range errorsChan { errorsList = append(errorsList, err) } - logger.Error("Fetch blocks errors", logger.Params{"count": len(errorsList), "blocks": errorsList}) + log.WithFields(log.Fields{"count": len(errorsList), "blocks": errorsList}).Error("Fetch blocks errors") } blocksList := make([]blockatlas.Block, 0, len(blocksChan)) @@ -178,7 +179,8 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64, ctx context blocksList = append(blocksList, block) } - logger.Info("Fetched blocks batch", logger.Params{"from": lastParsedBlock, "to": currentBlock, "total": totalCount}) + log.WithFields(log.Fields{"from": lastParsedBlock, "to": currentBlock, "total": totalCount}). + Info("Fetched blocks batch") return blocksList } @@ -187,7 +189,7 @@ func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas defer span.End() block, err := getBlockByNumberWithRetry(5, time.Second*5, api.GetBlockByNumber, num, api.Coin().Symbol, ctx) if err != nil { - return errors.E(fmt.Sprintf("%d", num)) + return fmt.Errorf("%d", num) } blocksChan <- *block return nil @@ -205,19 +207,21 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block, ctx context.C return blocks[i].Number < blocks[j].Number }) if len(blocks)-1 < 0 { - return errors.E(fmt.Sprintf("Cannot get last block number for %s", params.Api.Coin().Handle)) + return fmt.Errorf("cannot get last block number for %s", params.Api.Coin().Handle) } lastBlockNumber := blocks[len(blocks)-1].Number if lastBlockNumber <= 0 { - return errors.E(fmt.Sprintf("Parser of %s failed to save last block, lastBlockNumber <= 0", params.Api.Coin().Handle)) + return fmt.Errorf("parser of %s failed to save last block, lastBlockNumber <= 0", + params.Api.Coin().Handle) } err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().Handle, lastBlockNumber, ctx) if err != nil { return err } - logger.Info(err, "Save last parsed block", logger.Params{"block": lastBlockNumber, "coin": params.Api.Coin().Handle}) + log.WithFields(log.Fields{"block": lastBlockNumber, "coin": params.Api.Coin().Handle}). + Info(err, "Save last parsed block") return nil } @@ -243,11 +247,13 @@ func ConvertToBatch(blocks []blockatlas.Block, ctx context.Context) blockatlas.T wg.Wait() if len(txsBatch.Txs) == 0 { - logger.Info("Blocks converted to transactions batch, there is no transactions", logger.Params{"blocks": len(blocks)}) + log.WithFields(log.Fields{"blocks": len(blocks)}). + Info("Blocks converted to transactions batch, there is no transactions") return nil } - logger.Info("Blocks converted to transactions batch", logger.Params{"blocks": len(blocks), "txs": len(txsBatch.Txs)}) + log.WithFields(log.Fields{"blocks": len(blocks), "txs": len(txsBatch.Txs)}). + Info("Blocks converted to transactions batch") return txsBatch.Txs } @@ -265,7 +271,7 @@ func PublishTransactionsBatch(params Params, txs blockatlas.Txs, ctx context.Con publish(params, batch, ctx) } - logger.Info("Published transactions batch", logger.Params{"txs": len(txs), "batchCount": len(batches)}) + log.WithFields(log.Fields{"txs": len(txs), "batchCount": len(batches)}).Info("Published transactions batch") } func getTxsBatches(txs blockatlas.Txs, sizeUint uint, ctx context.Context) []blockatlas.Txs { @@ -292,13 +298,13 @@ func publish(params Params, txs blockatlas.Txs, ctx context.Context) { body, err := json.Marshal(txs) if err != nil { - logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error(err) return } for _, q := range params.Queue { err = q.Publish(body) if err != nil { - logger.Error(err, logger.Params{"coin": params.Api.Coin().Handle}) + log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error(err) return } } @@ -318,9 +324,8 @@ func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumb jitter := time.Duration(rand.Int63n(int64(sleep))) sleep = sleep + jitter/2 - logger.Info("retry GetBlockByNumber", - logger.Params{"number": n, "attempts": attempts, "sleep": sleep.String(), "symbol": symbol}, - ) + log.WithFields(log.Fields{"number": n, "attempts": attempts, "sleep": sleep.String(), "symbol": symbol}). + Info("retry GetBlockByNumber") time.Sleep(sleep) return getBlockByNumberWithRetry(attempts, sleep*2, getBlockByNumber, n, symbol, ctx) diff --git a/services/subscriber/tokens.go b/services/subscriber/tokens.go index fc41ad30f..2a69c2e23 100644 --- a/services/subscriber/tokens.go +++ b/services/subscriber/tokens.go @@ -3,10 +3,10 @@ package subscriber import ( "context" "encoding/json" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/logger" "go.elastic.co/apm" "strconv" ) @@ -21,18 +21,18 @@ func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { event := make(map[string][]models.Asset) if err := json.Unmarshal(delivery.Body, &event); err != nil { if err := delivery.Ack(false); err != nil { - logger.Fatal(err, err) + log.Fatal(err, err) } } for address, assets := range event { if err := database.AddAssociationsForAddress(address, assets, ctx); err != nil { - logger.Error("Failed to AddAssociationsForAddress: " + err.Error()) + log.Error("Failed to AddAssociationsForAddress: " + err.Error()) } } - logger.Info("Subscribed "+strconv.Itoa(len(event)), logger.Params{"service": Tokens}) + log.WithFields(log.Fields{"service": Tokens}).Info("Subscribed " + strconv.Itoa(len(event))) if err := delivery.Ack(false); err != nil { - logger.Fatal(err, err) + log.Fatal(err, err) } - logger.Info("------------------------------------------------------------") + log.Info("------------------------------------------------------------") } diff --git a/services/subscriber/transactions.go b/services/subscriber/transactions.go index 3f8c4a98f..f3a933fa4 100644 --- a/services/subscriber/transactions.go +++ b/services/subscriber/transactions.go @@ -3,10 +3,10 @@ package subscriber import ( "context" "encoding/json" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "go.elastic.co/apm" "strconv" ) @@ -30,30 +30,53 @@ func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { err := json.Unmarshal(delivery.Body, &event) if err != nil { errAck := delivery.Ack(false) - logger.Fatal(err, errAck) + log.Fatal(err, errAck) } subscriptions := event.ParseSubscriptions(event.Subscriptions) - params := logger.Params{"service": Notifications, "operation": event.Operation, "subscriptions_len": len(subscriptions)} - switch event.Operation { case AddSubscription, UpdateSubscription: err = database.AddSubscriptionsForNotifications(ToSubscriptionData(subscriptions), ctx) if err != nil { - logger.Error(err, params) + log.WithFields( + log.Fields{"service": Notifications, + "operation": event.Operation, + "subscriptions_len": len(subscriptions), + }, + ).Error(err) } - logger.Info("Added", params) + log.WithFields( + log.Fields{"service": Notifications, + "operation": event.Operation, + "subscriptions_len": len(subscriptions), + }, + ).Info("Added") case DeleteSubscription: err := database.DeleteSubscriptionsForNotifications(ToSubscriptionData(subscriptions), ctx) if err != nil { - logger.Error(err, params) + log.WithFields( + log.Fields{"service": Notifications, + "operation": event.Operation, + "subscriptions_len": len(subscriptions), + }, + ).Error(err) } - logger.Info("Deleted", params) + log.WithFields( + log.Fields{"service": Notifications, + "operation": event.Operation, + "subscriptions_len": len(subscriptions), + }, + ).Info("Added") } err = delivery.Ack(false) if err != nil { - logger.Error(err, params) + log.WithFields( + log.Fields{"service": Notifications, + "operation": event.Operation, + "subscriptions_len": len(subscriptions), + }, + ).Error(err) } } diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index 2600437dc..a9c3d8414 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -2,11 +2,11 @@ package tokenindexer import ( "context" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/notifier" "go.elastic.co/apm" ) @@ -18,16 +18,16 @@ func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) { defer tx.End() defer func() { if err := delivery.Ack(false); err != nil { - logger.Error(err, logger.Params{"service": TokenIndexer}) + log.WithFields(log.Fields{"service": TokenIndexer}).Error(err) } }() ctx := apm.ContextWithTransaction(context.Background(), tx) txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenIndexer, ctx) if err != nil { - logger.Error("failed to get transactions", err, logger.Params{"service": TokenIndexer}) + log.WithFields(log.Fields{"service": TokenIndexer}).Error("failed to get transactions", err) if err := delivery.Ack(false); err != nil { - logger.Error(err, logger.Params{"service": TokenIndexer}) + log.WithFields(log.Fields{"service": TokenIndexer}).Error(err) } return } @@ -38,10 +38,10 @@ func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) { assets := GetAssetsFromTransactions(txs) err = database.AddNewAssets(assets, ctx) if err != nil { - logger.Error("failed to add assets", err, logger.Params{"service": TokenIndexer}) + log.WithFields(log.Fields{"service": TokenIndexer}).Error("failed to add assets", err) return } - logger.Info("------------------------------------------------------------") + log.Info("------------------------------------------------------------") } func GetAssetsFromTransactions(txs []blockatlas.Tx) []models.Asset { diff --git a/services/tokensearcher/api.go b/services/tokensearcher/api.go index fe567aa50..73cb29018 100644 --- a/services/tokensearcher/api.go +++ b/services/tokensearcher/api.go @@ -3,12 +3,12 @@ package tokensearcher import ( "context" "encoding/json" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "strconv" "sync" "time" @@ -43,10 +43,10 @@ func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (map if err != nil { return nil, err } - logger.Info("subscribedAddresses " + strconv.Itoa(len(subscribedAddresses))) + log.Info("subscribedAddresses " + strconv.Itoa(len(subscribedAddresses))) unsubscribedAddresses := getUnsubscribedAddresses(subscribedAddresses, addresses) - logger.Info("unsubscribedAddresses " + strconv.Itoa(len(unsubscribedAddresses))) + log.Info("unsubscribedAddresses " + strconv.Itoa(len(unsubscribedAddresses))) assetsFromDB, err := i.database.GetAssetsMapByAddressesFromTime( subscribedAddresses, time.Unix(int64(request.From), 0), @@ -55,13 +55,13 @@ func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (map return nil, err } - logger.Info("assetsFromDB " + strconv.Itoa(len(assetsFromDB))) + log.Info("assetsFromDB " + strconv.Itoa(len(assetsFromDB))) assetsFromNodes := make(AssetsByAddress) if len(unsubscribedAddresses) != 0 { assetsFromNodes = getAssetsByAddressFromNodes(unsubscribedAddresses, i.apis) err = publishNewAddressesToQueue(i.queue, assetsFromNodes) if err != nil { - logger.Error(err) + log.Error(err) } } @@ -156,7 +156,7 @@ func fetchAssetsByAddresses(tokenAPI blockatlas.TokensAPI, addresses []string, r defer tWg.Done() tokens, err := tokenAPI.GetTokenListByAddress(address) if err != nil { - logger.Error("Chain: " + tokenAPI.Coin().Handle + " Address: " + address) + log.Error("Chain: " + tokenAPI.Coin().Handle + " Address: " + address) return } result.UpdateAssetsByAddress(tokens, int(tokenAPI.Coin().ID), address) @@ -166,9 +166,9 @@ func fetchAssetsByAddresses(tokenAPI blockatlas.TokensAPI, addresses []string, r } func publishNewAddressesToQueue(queue mq.Queue, message AssetsByAddress) error { - logger.Info("Published to queue") + log.Info("Published to queue") body, err := json.Marshal(message) - logger.Info(string(body)) + log.Info(string(body)) if err != nil { return err } diff --git a/services/tokensearcher/models.go b/services/tokensearcher/models.go index 7a78f78c5..04a8e42b4 100644 --- a/services/tokensearcher/models.go +++ b/services/tokensearcher/models.go @@ -4,7 +4,7 @@ import ( "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/watchmarket/pkg/watchmarket" + "github.com/trustwallet/golibs/asset" "sync" ) @@ -20,7 +20,7 @@ func (nr *NodesResponse) UpdateAssetsByAddress(tokens blockatlas.TokenPage, coin r := nr.AssetsByAddress[key] nr.AssetsByAddress[key] = append(r, models.Asset{ - Asset: watchmarket.BuildID(t.Coin, t.TokenID), + Asset: asset.BuildID(t.Coin, t.TokenID), Decimals: t.Decimals, Name: t.Name, Symbol: t.Symbol, diff --git a/services/tokensearcher/tokensearcher.go b/services/tokensearcher/tokensearcher.go index 78c334e9c..28efee99c 100644 --- a/services/tokensearcher/tokensearcher.go +++ b/services/tokensearcher/tokensearcher.go @@ -2,9 +2,9 @@ package tokensearcher import ( "context" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/notifier" "go.elastic.co/apm" "strconv" @@ -19,9 +19,9 @@ func Run(database *db.Instance, delivery amqp.Delivery) { txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenSearcher, ctx) if err != nil { - logger.Error("failed to get transactions", err) + log.Error("failed to get transactions", err) if err := delivery.Ack(false); err != nil { - logger.Error(err) + log.Error(err) } } if len(txs) == 0 { @@ -38,22 +38,24 @@ func Run(database *db.Instance, delivery amqp.Delivery) { associationsFromTransactions, err := database.GetAssociationsByAddresses(notifier.ToUniqueAddresses(addresses), ctx) if err != nil { - logger.Error(err) + log.Error(err) return } - logger.Info("AssociationsFromTransactions "+strconv.Itoa(len(associationsFromTransactions)), logger.Params{"service": TokenSearcher}) + log.WithFields(log.Fields{"service": TokenSearcher}). + Info("AssociationsFromTransactions " + strconv.Itoa(len(associationsFromTransactions))) associationsToAdd := associationsToAdd(fromModelToAssociation(associationsFromTransactions), assetsMap(txs, coinID)) - logger.Info("AssociationsToAdd "+strconv.Itoa(len(associationsToAdd)), logger.Params{"service": TokenSearcher}) + log.WithFields(log.Fields{"service": TokenSearcher}). + Info("AssociationsToAdd " + strconv.Itoa(len(associationsToAdd))) err = database.UpdateAssociationsForExistingAddresses(associationsToAdd, ctx) if err != nil { - logger.Error(err) + log.Error(err) return } if err := delivery.Ack(false); err != nil { - logger.Error(err) + log.Error(err) } - logger.Info("------------------------------------------------------------") + log.Info("------------------------------------------------------------") } diff --git a/tests/integration/db_test/tokenindexer_test.go b/tests/integration/db_test/tokenindexer_test.go index dbe646475..d32482cd8 100644 --- a/tests/integration/db_test/tokenindexer_test.go +++ b/tests/integration/db_test/tokenindexer_test.go @@ -5,9 +5,9 @@ package db_test import ( "context" gocache "github.com/patrickmn/go-cache" + log "github.com/sirupsen/logrus" assert "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/tests/integration/setup" "sort" "testing" @@ -202,9 +202,9 @@ func Test_AddNewAssets(t *testing.T) { sort.Slice(assets, func(i, j int) bool { return len(assets[i].Name) > len(assets[j].Name) }) - logger.Info(tt.WantedAssets) - logger.Info("----------------------") - logger.Info(assets) + log.Info(tt.WantedAssets) + log.Info("----------------------") + log.Info(assets) for i, a := range assets { assert.Equal(t, tt.WantedAssets[i].Asset, a.Asset) assert.Equal(t, tt.WantedAssets[i].Name, a.Name) diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index b9c9c0e98..108a6562d 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -7,12 +7,12 @@ import ( "encoding/json" "github.com/streadway/amqp" "github.com/stretchr/testify/assert" - "github.com/trustwallet/golibs/coin" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/notifier" "github.com/trustwallet/blockatlas/services/parser" "github.com/trustwallet/blockatlas/tests/integration/setup" + "github.com/trustwallet/golibs/coin" "go.uber.org/atomic" "testing" "time" diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index 0fdf43fcc..b5ccc8380 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -7,11 +7,11 @@ import ( "encoding/json" "github.com/streadway/amqp" "github.com/stretchr/testify/assert" - "github.com/trustwallet/golibs/coin" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/notifier" "github.com/trustwallet/blockatlas/tests/integration/setup" + "github.com/trustwallet/golibs/coin" "testing" "time" ) diff --git a/tests/integration/observer_test/parser_test.go b/tests/integration/observer_test/parser_test.go index a86fb4347..795bc0bec 100644 --- a/tests/integration/observer_test/parser_test.go +++ b/tests/integration/observer_test/parser_test.go @@ -5,11 +5,11 @@ package observer_test import ( "context" "encoding/json" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/logger" "github.com/trustwallet/blockatlas/services/parser" "github.com/trustwallet/blockatlas/tests/integration/setup" "github.com/trustwallet/golibs/coin" @@ -87,12 +87,12 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { func ConsumerToTestAmountOfBlocks(delivery amqp.Delivery, t *testing.T, cancelFunc context.CancelFunc) { var txs blockatlas.Txs if err := json.Unmarshal(delivery.Body, &txs); err != nil { - logger.Error(err) + log.Error(err) return } err := delivery.Ack(false) if err != nil { - logger.Error(err) + log.Error(err) } assert.Equal(t, len(txs), 50) From bff4a09c952352492a3fb4c9956b4fd4871dbcad Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Fri, 6 Nov 2020 14:13:23 +0300 Subject: [PATCH 408/506] [MQ] Consumer cleanup (#1268) * Ack after insert * Batch limit * Use concurrent flag for consumer * Log mq * New version of mq consumer * Use concurrent back * Cleanup --- cmd/consumer/main.go | 12 +-- db/db.go | 3 +- go.mod | 20 +++- go.sum | 95 +------------------ mq/mq.go | 41 ++++---- services/subscriber/transactions.go | 81 ++++++++++------ .../observer_test/full_flow_test.go | 3 +- .../observer_test/notifier_test.go | 2 +- .../observer_test/subscriber_test.go | 4 +- 9 files changed, 106 insertions(+), 155 deletions(-) diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index dfdf65b52..00415ddc0 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -5,6 +5,7 @@ import ( "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/services/notifier" "github.com/trustwallet/blockatlas/services/subscriber" + "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" "time" @@ -12,7 +13,6 @@ import ( "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/services/tokenindexer" ) const ( @@ -69,11 +69,11 @@ func main() { log.Fatal(err) } - go mq.RawTransactionsTokenIndexer.RunConsumerWithCancelAndDbConn(tokenindexer.RunTokenIndexer, database, ctx) - go mq.RawTransactions.RunConsumerWithCancelAndDbConn(notifier.RunNotifier, database, ctx) - go mq.RawTransactionsSearcher.RunConsumerWithCancelAndDbConn(tokensearcher.Run, database, ctx) - go mq.Subscriptions.RunConsumerWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, database, ctx) - go mq.TokensRegistration.RunConsumerWithCancelAndDbConn(subscriber.RunTokensSubscriber, database, ctx) + go mq.RawTransactionsTokenIndexer.RunConsumerWithCancelAndDbConnConcurrent(tokenindexer.RunTokenIndexer, database, ctx) + go mq.RawTransactions.RunConsumerWithCancelAndDbConnConcurrent(notifier.RunNotifier, database, ctx) + go mq.RawTransactionsSearcher.RunConsumerWithCancelAndDbConnConcurrent(tokensearcher.Run, database, ctx) + go mq.Subscriptions.RunConsumerWithCancelAndDbConnConcurrent(subscriber.RunTransactionsSubscriber, database, ctx) + go mq.TokensRegistration.RunConsumerWithCancelAndDbConnConcurrent(subscriber.RunTokensSubscriber, database, ctx) go mq.FatalWorker(time.Second * 10) diff --git a/db/db.go b/db/db.go index 0b200db2a..5a6eba4dd 100644 --- a/db/db.go +++ b/db/db.go @@ -3,6 +3,7 @@ package db import ( "context" "errors" + "gorm.io/gorm/logger" "time" log "github.com/sirupsen/logrus" @@ -25,7 +26,7 @@ type Instance struct { const batchCount = 3000 func New(uri, readUri string, logMode bool) (*Instance, error) { - cfg := &gorm.Config{} + cfg := &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)} db, err := gorm.Open(postgres.Open(uri), cfg) if err != nil { diff --git a/go.mod b/go.mod index 9bd3e2a09..1bdaaadef 100644 --- a/go.mod +++ b/go.mod @@ -6,16 +6,30 @@ go 1.15 // +heroku install ./cmd/... require ( + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/DeanThompson/ginpprof v0.0.0-20190408063150-3be636683586 + github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 + github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 + github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb // indirect github.com/deckarep/golang-set v1.7.1 + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/elastic/go-sysinfo v1.3.0 // indirect + github.com/elastic/go-windows v1.0.1 // indirect github.com/gin-gonic/gin v1.6.3 + github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/imroc/req v0.3.0 github.com/mitchellh/mapstructure v1.3.3 github.com/mr-tron/base58 v1.2.0 + github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/runc v0.1.1 // indirect github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.7.1 github.com/shopspring/decimal v1.2.0 github.com/sirupsen/logrus v1.6.0 @@ -25,14 +39,18 @@ require ( github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 github.com/trustwallet/golibs v0.0.9 - github.com/trustwallet/watchmarket v1.1.1 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmhttp v1.8.0 + go.elastic.co/fastjson v1.1.0 // indirect go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 + golang.org/x/net v0.0.0-20200506145744-7e3656a0809f // indirect + golang.org/x/tools v0.0.0-20200513175351-0951661448da // indirect gopkg.in/yaml.v2 v2.3.0 gorm.io/driver/postgres v1.0.0 gorm.io/gorm v1.20.0 gorm.io/plugin/dbresolver v1.0.0 + gotest.tools v2.2.0+incompatible // indirect + howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 // indirect ) diff --git a/go.sum b/go.sum index 0a36aefdd..ccb0faf87 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= @@ -19,8 +17,8 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DeanThompson/ginpprof v0.0.0-20190408063150-3be636683586 h1:vDSj8WQZoe+dhK9JVwkSEBwtmcJw5rJ7l1L0Yik8Ku0= +github.com/DeanThompson/ginpprof v0.0.0-20190408063150-3be636683586/go.mod h1:kMi/fSDAgvjo9TYfYwYeQ2vkyj+VTR/tB6u/Tjh39t0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= @@ -28,24 +26,17 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.13.2/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg= -github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 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= @@ -79,9 +70,6 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 h1:3Wv1E0CqL45hBs4bykb586wvZMRGKfFITHrN3ilm4FE= github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= @@ -93,8 +81,6 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c h1:4e6Zsb6LFd3kadoMiut2zcd3hCb4zywpJnQa8+NV2Cs= -github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c/go.mod h1:k5D13LCXSsMrQyfdW0yGYs4GWUvirqoxHht8qwtqyRY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cucumber/godog v0.8.1 h1:lVb+X41I4YDreE+ibZ50bdXmySxgRviYFgKY6Aw4XE8= @@ -105,9 +91,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= -github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= -github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -115,9 +98,6 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/elastic/go-sysinfo v1.1.1 h1:ZVlaLDyhVkDfjwPGU55CQRCRolNpc7P0BbyhhQZQmMI= github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-sysinfo v1.3.0 h1:eb2XFGTMlSwG/yyU9Y8jVAYLIzU2sFzWXwo2gmetyrE= @@ -126,8 +106,6 @@ github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7 github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -171,20 +149,13 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-redis/redis v6.15.3-0.20190424063336-97e6ed817821+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -202,7 +173,6 @@ github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -219,8 +189,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= @@ -305,13 +273,8 @@ github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= -github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= -github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= -github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= @@ -347,8 +310,6 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -370,11 +331,6 @@ 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/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= -github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= -github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= -github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 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= @@ -399,10 +355,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -410,7 +364,6 @@ github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVo github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -418,7 +371,6 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= @@ -429,24 +381,20 @@ 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-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -454,8 +402,6 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -517,15 +463,8 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/blockatlas v1.1.7-0.20200831100332-b573ace18512/go.mod h1:rq6APqrT+vR58h+WWrCyadT80QDKmDEJvHDllWSUwnM= -github.com/trustwallet/ens-coincodec v1.0.6 h1:ZPvFDJwvv4s+XCnUM7pzub8wYHy37tyJBNtKvgx9FDs= -github.com/trustwallet/ens-coincodec v1.0.6/go.mod h1:hTZCauB3S2Gt9M3FiRNva+xpLJXFqLyODKFF+UvH1lw= -github.com/trustwallet/golibs v0.0.8 h1:eviuHKqIXDs+DGgWNHF/gNTrV6jmJTfYYEHVbCeniWE= -github.com/trustwallet/golibs v0.0.8/go.mod h1:QB6tQe5tvZOAPmvpeaveFwCQpTqdelSgO6UlMZN30Co= github.com/trustwallet/golibs v0.0.9 h1:AyupOF1LZyMaZdkwnG3hxSwb5pqW2yZR7EI4hLoBrI8= github.com/trustwallet/golibs v0.0.9/go.mod h1:QB6tQe5tvZOAPmvpeaveFwCQpTqdelSgO6UlMZN30Co= -github.com/trustwallet/watchmarket v1.1.1 h1:gErSfLLDhEblFqvW8V3RyzRqq4R6MCYEDWjO6j5uJfE= -github.com/trustwallet/watchmarket v1.1.1/go.mod h1:DvqzLzxXOaZajbkryVZcNgBS4yibZhk3rCc41ZSJEBs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= @@ -536,31 +475,20 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -github.com/wealdtech/go-slip44 v1.0.0 h1:g0Wi5EufdD/ULZ4hcZKQ3TGlA6FZhGTCkmVzYmf+7Is= -github.com/wealdtech/go-slip44 v1.0.0/go.mod h1://S3V9M6iN1cCflLXMjJYciRPakCDubG9YpWVyW1AvM= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.elastic.co/apm v1.8.0 h1:AWEKpHwRal0yCMd4K8Oxy1HAa7xid+xq1yy+XjgoVU0= go.elastic.co/apm v1.8.0/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= go.elastic.co/apm/module/apmgin v1.8.0 h1:QcXVtFhqAcSGqC/ywzqZBHdWzJG3wyrBxgvCvAZ98do= go.elastic.co/apm/module/apmgin v1.8.0/go.mod h1:heH2rXaOluBb+ucwlG3FBCGrx56qHqoxb1KI7uBLlAk= -go.elastic.co/apm/module/apmgoredis v1.8.0/go.mod h1:J8mXOp8sOJG1/Vuz0gPB7+ovcQY6vYqpabuRsk9beBM= -go.elastic.co/apm/module/apmgorm v1.8.0 h1:1vKuD8hsbJcChcUQTBb1N8Zy1tILR5pGTExLtijyhko= -go.elastic.co/apm/module/apmgorm v1.8.0/go.mod h1:18ttEKPQr0cvRSeG95WMXoPUy2BT8Jp1EzhPU5NQYTY= go.elastic.co/apm/module/apmhttp v1.8.0 h1:5AJPefWJzWDLX/47XIDfaloGiYWkkOQEULvlrI6Ieaw= go.elastic.co/apm/module/apmhttp v1.8.0/go.mod h1:9LPFlEON51/lRbnWDfqAWErihIiAFDUMfMV27YjoWQ8= -go.elastic.co/apm/module/apmlogrus v1.8.0 h1:HSz+gNSa88zLvoX36OaCSgbqTTCn7u3GrR6WqRu8RiU= -go.elastic.co/apm/module/apmlogrus v1.8.0/go.mod h1:0TsyfBEaY5FaGS2p9UlSRhmf1T1zhmf9vcwgQTlI064= -go.elastic.co/apm/module/apmsql v1.8.0 h1:YMGTshRcC9SI8p+hJNI7OzNnk7Dn9RjwuwO0MRcbvvE= -go.elastic.co/apm/module/apmsql v1.8.0/go.mod h1:pX+PSxIcEv5BvIYJjQnODzNwJ6+DJDeLb0fzrhSOIhE= go.elastic.co/fastjson v1.0.0 h1:ooXV/ABvf+tBul26jcVViPT3sBir0PvXgibYB1IQQzg= go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs= go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4= go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -579,7 +507,6 @@ golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -587,13 +514,8 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= @@ -619,7 +541,6 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -629,7 +550,6 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -642,9 +562,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -663,9 +581,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -697,7 +613,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -732,9 +647,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -746,16 +659,13 @@ google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -805,7 +715,6 @@ gorm.io/plugin/dbresolver v1.0.0 h1:fHIWRRkoDmXkBPYyg9GMmLugcM9fcbZiG0Zy/cwiPlM= gorm.io/plugin/dbresolver v1.0.0/go.mod h1:sK1Alv120lfrjRQXrzyAw4ssxDPJjamm2cbBOZBHM68= 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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/mq/mq.go b/mq/mq.go index cc7c8282a..a3de94b77 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -68,7 +68,7 @@ func (q Queue) Publish(body []byte) error { }) } -func RunConsumerForChannelWithCancelAndDbConn(consumer ConsumerWithDbConn, messageChannel MessageChannel, database *db.Instance, ctx context.Context) { +func RunConsumerForChannelWithCancelAndDbConn(consumer ConsumerWithDbConn, messageChannel MessageChannel, database *db.Instance, concurrent bool, ctx context.Context) { for { select { case <-ctx.Done(): @@ -78,7 +78,12 @@ func RunConsumerForChannelWithCancelAndDbConn(consumer ConsumerWithDbConn, messa if message.Body == nil { continue } - go consumer(database, message) + if concurrent { + go consumer(database, message) + } else { + consumer(database, message) + } + } } } @@ -143,34 +148,24 @@ func (q Queue) RunConsumerWithCancelAndDbConn(consumer ConsumerWithDbConn, datab if message.Body == nil { continue } - go consumer(database, message) + consumer(database, message) } } } -func RestoreConnectionWorker(uri string, queue Queue, timeout time.Duration) { - log.Info("Run MQ RestoreConnectionWorker") +func (q Queue) RunConsumerWithCancelAndDbConnConcurrent(consumer ConsumerWithDbConn, database *db.Instance, ctx context.Context) { + messageChannel := q.GetMessageChannel() for { - if conn.IsClosed() { - for { - log.Warn("MQ is not available now") - log.Warn("Trying to connect to MQ...") - if err := Init(uri); err != nil { - log.Warn("MQ is still unavailable") - time.Sleep(timeout) - continue - } - if err := queue.Declare(); err != nil { - log.Warn("Can't declare queues:", queue) - time.Sleep(timeout) - continue - } else { - log.Info("MQ connection restored") - break - } + select { + case <-ctx.Done(): + log.Info("Consumer stopped") + return + case message := <-messageChannel: + if message.Body == nil { + continue } + go consumer(database, message) } - time.Sleep(timeout) } } diff --git a/services/subscriber/transactions.go b/services/subscriber/transactions.go index f3a933fa4..b100efaeb 100644 --- a/services/subscriber/transactions.go +++ b/services/subscriber/transactions.go @@ -18,6 +18,8 @@ const ( AddSubscription blockatlas.SubscriptionOperation = "AddSubscription" DeleteSubscription blockatlas.SubscriptionOperation = "DeleteSubscription" UpdateSubscription blockatlas.SubscriptionOperation = "UpdateSubscription" + + batchLimit uint = 3000 ) func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { @@ -29,22 +31,26 @@ func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { var event blockatlas.SubscriptionEvent err := json.Unmarshal(delivery.Body, &event) if err != nil { - errAck := delivery.Ack(false) - log.Fatal(err, errAck) + return } subscriptions := event.ParseSubscriptions(event.Subscriptions) switch event.Operation { case AddSubscription, UpdateSubscription: - err = database.AddSubscriptionsForNotifications(ToSubscriptionData(subscriptions), ctx) - if err != nil { - log.WithFields( - log.Fields{"service": Notifications, - "operation": event.Operation, - "subscriptions_len": len(subscriptions), - }, - ).Error(err) + allSubs := ToSubscriptionData(subscriptions) + batchedSubs := toBatch(allSubs, batchLimit) + for _, subs := range batchedSubs { + err := database.AddSubscriptionsForNotifications(subs, ctx) + if err != nil { + log.WithFields( + log.Fields{"service": Notifications, + "operation": event.Operation, + "subscriptions_len": len(subscriptions), + }, + ).Error(err) + } } + log.WithFields( log.Fields{"service": Notifications, "operation": event.Operation, @@ -52,14 +58,18 @@ func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { }, ).Info("Added") case DeleteSubscription: - err := database.DeleteSubscriptionsForNotifications(ToSubscriptionData(subscriptions), ctx) - if err != nil { - log.WithFields( - log.Fields{"service": Notifications, - "operation": event.Operation, - "subscriptions_len": len(subscriptions), - }, - ).Error(err) + allSubs := ToSubscriptionData(subscriptions) + batchedSubs := toBatch(allSubs, batchLimit) + for _, subs := range batchedSubs { + err := database.DeleteSubscriptionsForNotifications(subs, ctx) + if err != nil { + log.WithFields( + log.Fields{"service": Notifications, + "operation": event.Operation, + "subscriptions_len": len(subscriptions), + }, + ).Error(err) + } } log.WithFields( log.Fields{"service": Notifications, @@ -69,15 +79,17 @@ func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { ).Info("Added") } - err = delivery.Ack(false) - if err != nil { - log.WithFields( - log.Fields{"service": Notifications, - "operation": event.Operation, - "subscriptions_len": len(subscriptions), - }, - ).Error(err) - } + defer func() { + err = delivery.Ack(false) + if err != nil { + log.WithFields( + log.Fields{"service": Notifications, + "operation": event.Operation, + "subscriptions_len": len(subscriptions), + }, + ).Error(err) + } + }() } func ToSubscriptionData(sub []blockatlas.Subscription) []string { @@ -89,3 +101,18 @@ func ToSubscriptionData(sub []blockatlas.Subscription) []string { } return data } + +func toBatch(subs []string, sizeUint uint) [][]string { + size := int(sizeUint) + resultLength := (len(subs) + size - 1) / size + result := make([][]string, resultLength) + lo, hi := 0, size + for i := range result { + if hi > len(subs) { + hi = len(subs) + } + result[i] = subs[lo:hi:hi] + lo, hi = hi, hi+size + } + return result +} diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 108a6562d..bc7190a77 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -39,7 +39,8 @@ func TestFullFlow(t *testing.T) { go parser.RunParser(params) time.Sleep(time.Second * 2) - go mq.RunConsumerForChannelWithCancelAndDbConn(notifier.RunNotifier, rawTransactionsChannel, database, ctx) + go mq.RunConsumerForChannelWithCancelAndDbConn(notifier.RunNotifier, rawTransactionsChannel, database, true, + ctx) time.Sleep(time.Second * 5) for i := 0; i < 11; i++ { diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index b5ccc8380..b36a6575d 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -51,7 +51,7 @@ func TestNotifier(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) - go mq.RunConsumerForChannelWithCancelAndDbConn(notifier.RunNotifier, rawTransactionsChannel, database, ctx) + go mq.RunConsumerForChannelWithCancelAndDbConn(notifier.RunNotifier, rawTransactionsChannel, database, true, ctx) time.Sleep(time.Second * 3) msg := transactionsChannel.GetMessage() ConsumerToTestTransactions(msg, t) diff --git a/tests/integration/observer_test/subscriber_test.go b/tests/integration/observer_test/subscriber_test.go index fa804f05a..2f55aae72 100644 --- a/tests/integration/observer_test/subscriber_test.go +++ b/tests/integration/observer_test/subscriber_test.go @@ -50,7 +50,7 @@ func TestSubscriberAddSubscription(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) - go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, subscriptionChannel, database, ctx) + go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, subscriptionChannel, database, true, ctx) time.Sleep(time.Second * 2) cancel() } @@ -110,7 +110,7 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) - go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, subscriptionChannel, database, ctx) + go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, subscriptionChannel, database, true, ctx) time.Sleep(time.Second) cancel() } From 5174be2f7a991f9239c4f468dc7d55d54bcab624 Mon Sep 17 00:00:00 2001 From: maxUo <20925019+maxUo@users.noreply.github.com> Date: Fri, 6 Nov 2020 17:20:08 +0300 Subject: [PATCH 409/506] [Deployment] Simplify Deployment (#1269) * Update Chart * Update Chart.yaml * Update values.prod.yaml --- deployment/charts/blockatlas/Chart.yaml | 2 +- .../blockatlas/templates/parser-binance.yaml | 77 ------------ .../blockatlas/templates/parser-bitcoin.yaml | 71 ----------- .../blockatlas/templates/parser-bsc.yaml | 69 ----------- .../blockatlas/templates/parser-classic.yaml | 69 ----------- .../blockatlas/templates/parser-cosmos.yaml | 69 ----------- .../blockatlas/templates/parser-doge.yaml | 69 ----------- .../blockatlas/templates/parser-ethereum.yaml | 69 ----------- .../blockatlas/templates/parser-litecoin.yaml | 69 ----------- .../blockatlas/templates/parser-other.yaml | 73 ----------- .../blockatlas/templates/parser-ripple.yaml | 69 ----------- .../templates/parser-smartchain.yaml | 69 ----------- .../blockatlas/templates/parser-stellar.yaml | 69 ----------- .../blockatlas/templates/parser-tezos.yaml | 69 ----------- .../blockatlas/templates/parser-tron.yaml | 69 ----------- .../{parser-kava.yaml => parser.yaml} | 16 ++- deployment/charts/blockatlas/values.prod.yaml | 116 ++---------------- deployment/charts/blockatlas/values.yaml | 16 +-- 18 files changed, 21 insertions(+), 1109 deletions(-) delete mode 100644 deployment/charts/blockatlas/templates/parser-binance.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-bitcoin.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-bsc.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-classic.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-cosmos.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-doge.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-ethereum.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-litecoin.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-other.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-ripple.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-smartchain.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-stellar.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-tezos.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser-tron.yaml rename deployment/charts/blockatlas/templates/{parser-kava.yaml => parser.yaml} (87%) diff --git a/deployment/charts/blockatlas/Chart.yaml b/deployment/charts/blockatlas/Chart.yaml index cef514680..3994fd8ad 100644 --- a/deployment/charts/blockatlas/Chart.yaml +++ b/deployment/charts/blockatlas/Chart.yaml @@ -4,6 +4,6 @@ description: A Blockatlas chart for Kubernetes type: application -version: 0.0.1 +version: 0.1.0 appVersion: 2 diff --git a/deployment/charts/blockatlas/templates/parser-binance.yaml b/deployment/charts/blockatlas/templates/parser-binance.yaml deleted file mode 100644 index 95db0931a..000000000 --- a/deployment/charts/blockatlas/templates/parser-binance.yaml +++ /dev/null @@ -1,77 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-binance - namespace: {{ .Release.Namespace }} - labels: - app: parser-binance - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: binance - - name: OBSERVER_FETCH_BLOCKS_INTERVAL - value: 50ms - - name: OBSERVER_BLOCK_POLL_MIN - value: 5s - - name: OBSERVER_BACKLOG_MAX_BLOCKS - value: "300" - - name: OBSERVER_BACKLOG - value: 10h - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-binance - resources: - {{- toYaml .Values.parserBinanceResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-bitcoin.yaml b/deployment/charts/blockatlas/templates/parser-bitcoin.yaml deleted file mode 100644 index bd415ed07..000000000 --- a/deployment/charts/blockatlas/templates/parser-bitcoin.yaml +++ /dev/null @@ -1,71 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-bitcoin - namespace: {{ .Release.Namespace }} - labels: - app: parser-bitcoin - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: bitcoin - - name: OBSERVER_BLOCK_POLL_MIN - value: 20s - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-bitcoin - resources: - {{- toYaml .Values.parserBitcoinResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-bsc.yaml b/deployment/charts/blockatlas/templates/parser-bsc.yaml deleted file mode 100644 index 785924a76..000000000 --- a/deployment/charts/blockatlas/templates/parser-bsc.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-bsc - namespace: {{ .Release.Namespace }} - labels: - app: parser-bsc - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: bsc - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-bsc - resources: - {{- toYaml .Values.parserBscResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-classic.yaml b/deployment/charts/blockatlas/templates/parser-classic.yaml deleted file mode 100644 index 206ed1c7b..000000000 --- a/deployment/charts/blockatlas/templates/parser-classic.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-classic - namespace: {{ .Release.Namespace }} - labels: - app: parser-classic - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: classic - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-classic - resources: - {{- toYaml .Values.parserClassicResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-cosmos.yaml b/deployment/charts/blockatlas/templates/parser-cosmos.yaml deleted file mode 100644 index c0eefa249..000000000 --- a/deployment/charts/blockatlas/templates/parser-cosmos.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-cosmos - namespace: {{ .Release.Namespace }} - labels: - app: parser-cosmos - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: cosmos - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-cosmos - resources: - {{- toYaml .Values.parserCosmosResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-doge.yaml b/deployment/charts/blockatlas/templates/parser-doge.yaml deleted file mode 100644 index 9654ecd3d..000000000 --- a/deployment/charts/blockatlas/templates/parser-doge.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-doge - namespace: {{ .Release.Namespace }} - labels: - app: parser-doge - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: doge - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-doge - resources: - {{- toYaml .Values.parserDogeResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-ethereum.yaml b/deployment/charts/blockatlas/templates/parser-ethereum.yaml deleted file mode 100644 index dcfaf88d5..000000000 --- a/deployment/charts/blockatlas/templates/parser-ethereum.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-ethereum - namespace: {{ .Release.Namespace }} - labels: - app: parser-ethereum - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: ethereum - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-ethereum - resources: - {{- toYaml .Values.parserEthereumResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-litecoin.yaml b/deployment/charts/blockatlas/templates/parser-litecoin.yaml deleted file mode 100644 index b6b4dc9a1..000000000 --- a/deployment/charts/blockatlas/templates/parser-litecoin.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-litecoin - namespace: {{ .Release.Namespace }} - labels: - app: parser-litecoin - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: litecoin - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-litecoin - resources: - {{- toYaml .Values.parserLitecoinResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-other.yaml b/deployment/charts/blockatlas/templates/parser-other.yaml deleted file mode 100644 index 611500cf7..000000000 --- a/deployment/charts/blockatlas/templates/parser-other.yaml +++ /dev/null @@ -1,73 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-other - namespace: {{ .Release.Namespace }} - labels: - app: parser-other - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: OBSERVER_FETCH_BLOCKS_INTERVAL - value: 500ms - - name: OBSERVER_BLOCK_POLL_MIN - value: 10s - - name: PLATFORM - value: aeternity,aion,algorand,bitcoincash,callisto,dash,decred,digibyte,fio,gochain,groestlcoin,harmony,icon,iotex,kin,nebulas,nimiq,ontology,poa,qtum,ravencoin,solana,theta,thundertoken,tomochain,vechain,viacoin,wanchain,waves,zcash,zcoin,zelcash,zilliqa,filecoin - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-other - resources: - {{- toYaml .Values.parserOtherResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-ripple.yaml b/deployment/charts/blockatlas/templates/parser-ripple.yaml deleted file mode 100644 index 085526afc..000000000 --- a/deployment/charts/blockatlas/templates/parser-ripple.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-ripple - namespace: {{ .Release.Namespace }} - labels: - app: parser-ripple - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: ripple - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-ripple - resources: - {{- toYaml .Values.parserRippleResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-smartchain.yaml b/deployment/charts/blockatlas/templates/parser-smartchain.yaml deleted file mode 100644 index 960758379..000000000 --- a/deployment/charts/blockatlas/templates/parser-smartchain.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-smartchain - namespace: {{ .Release.Namespace }} - labels: - app: parser-smartchain - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: smartchain - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-smartchain - resources: - {{- toYaml .Values.parserSmartchainResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-stellar.yaml b/deployment/charts/blockatlas/templates/parser-stellar.yaml deleted file mode 100644 index edfd9ffbc..000000000 --- a/deployment/charts/blockatlas/templates/parser-stellar.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-stellar - namespace: {{ .Release.Namespace }} - labels: - app: parser-stellar - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: stellar - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-stellar - resources: - {{- toYaml .Values.parserStellarResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-tezos.yaml b/deployment/charts/blockatlas/templates/parser-tezos.yaml deleted file mode 100644 index ecb71a948..000000000 --- a/deployment/charts/blockatlas/templates/parser-tezos.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-tezos - namespace: {{ .Release.Namespace }} - labels: - app: parser-tezos - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: tezos - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-tezos - resources: - {{- toYaml .Values.parserTezosResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-tron.yaml b/deployment/charts/blockatlas/templates/parser-tron.yaml deleted file mode 100644 index ac65ebdb0..000000000 --- a/deployment/charts/blockatlas/templates/parser-tron.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser-tron - namespace: {{ .Release.Namespace }} - labels: - app: parser-tron - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: PLATFORM - value: tron - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-tron - resources: - {{- toYaml .Values.parserTronResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/parser-kava.yaml b/deployment/charts/blockatlas/templates/parser.yaml similarity index 87% rename from deployment/charts/blockatlas/templates/parser-kava.yaml rename to deployment/charts/blockatlas/templates/parser.yaml index 418099d8c..047ebcd42 100644 --- a/deployment/charts/blockatlas/templates/parser-kava.yaml +++ b/deployment/charts/blockatlas/templates/parser.yaml @@ -1,10 +1,10 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: parser-kava + name: parser namespace: {{ .Release.Namespace }} labels: - app: parser-kava + app: parser chart: {{ template "blockatlas.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} @@ -28,10 +28,14 @@ spec: - env: - name: ELASTIC_APM_SERVICE_NAME value: blockatlas-parser - - name: PLATFORM - value: kava + - name: OBSERVER_BACKLOG_MAX_BLOCKS + value: "50" + - name: OBSERVER_BLOCK_POLL_MIN + value: 7s - name: OBSERVER_FETCH_BLOCKS_INTERVAL value: 100ms + - name: PLATFORM + value: all envFrom: - secretRef: name: secrets @@ -41,9 +45,9 @@ spec: optional: false image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser-kava + name: parser resources: - {{- toYaml .Values.parserKavaResources | nindent 12 }} + {{- toYaml .Values.parserResources | nindent 12 }} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} stdin: true diff --git a/deployment/charts/blockatlas/values.prod.yaml b/deployment/charts/blockatlas/values.prod.yaml index 20b70f291..8106da3b9 100644 --- a/deployment/charts/blockatlas/values.prod.yaml +++ b/deployment/charts/blockatlas/values.prod.yaml @@ -17,11 +17,11 @@ secret: apiResources: limits: - cpu: 200m - memory: 300Mi + cpu: 300m + memory: 400Mi requests: - cpu: 200m - memory: 300Mi + cpu: 300m + memory: 400Mi consumerResources: limits: @@ -31,108 +31,10 @@ consumerResources: cpu: 300m memory: 400Mi -parserBinanceResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserBitcoinResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserBscResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserClassicResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserCosmosResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserDogeResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserEthereumResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserKavaResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserLitecoinResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserRippleResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserOtherResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserSmartchainResources: +parserResources: limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserStellarResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserTezosResources: - limits: - cpu: 30m - memory: 120Mi - requests: - cpu: 10m - memory: 120Mi -parserTronResources: - limits: - cpu: 30m - memory: 120Mi + cpu: 300m + memory: 1000Mi requests: - cpu: 10m - memory: 120Mi + cpu: 300m + memory: 1000Mi \ No newline at end of file diff --git a/deployment/charts/blockatlas/values.yaml b/deployment/charts/blockatlas/values.yaml index e9b04a882..6774dd9ed 100644 --- a/deployment/charts/blockatlas/values.yaml +++ b/deployment/charts/blockatlas/values.yaml @@ -46,22 +46,8 @@ ingress: apiResources: {} postgresResources: {} rabbitmqResources: {} -parserBinanceResources: {} consumerResources: {} -parserBitcoinResources: {} -parserBscResources: {} -parserClassicResources: {} -parserCosmosResources: {} -parserDogeResources: {} -parserEthereumResources: {} -parserKavaResources: {} -parserLitecoinResources: {} -parserRippleResources: {} -parserOtherResources: {} -parserSmartchainResources: {} -parserStellarResources: {} -parserTezosResources: {} -parserTronResources: {} +parserResources: {} nodeSelector: {} tolerations: [] From 66f3acfdc97916256304bee39051673627cbbf5d Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Mon, 9 Nov 2020 20:31:10 -0800 Subject: [PATCH 410/506] Use golibs/numbers (#1272) --- api/endpoint/staking.go | 3 +- go.mod | 2 +- go.sum | 2 + pkg/blockatlas/marshal.go | 3 +- pkg/blockatlas/tx.go | 9 +-- pkg/numbers/amount.go | 34 --------- pkg/numbers/amount_test.go | 94 ------------------------ pkg/numbers/decimal.go | 102 -------------------------- pkg/numbers/decimal_test.go | 115 ------------------------------ pkg/numbers/number.go | 86 ---------------------- pkg/numbers/number_test.go | 95 ------------------------ platform/aeternity/transaction.go | 5 +- platform/aion/transaction.go | 5 +- platform/algorand/client.go | 3 +- platform/binance/model.go | 7 +- platform/bitcoin/transaction.go | 2 +- platform/cosmos/transaction.go | 7 +- platform/harmony/client.go | 2 +- platform/harmony/transaction.go | 7 +- platform/icon/transaction.go | 5 +- platform/kava/transaction.go | 7 +- platform/ontology/transaction.go | 5 +- platform/polkadot/transaction.go | 3 +- platform/stellar/transaction.go | 5 +- platform/tezos/transaction.go | 2 +- platform/vechain/stake.go | 2 +- platform/vechain/transaction.go | 7 +- services/assets/validator.go | 5 +- services/parser/parser.go | 8 ++- 29 files changed, 62 insertions(+), 570 deletions(-) delete mode 100644 pkg/numbers/amount.go delete mode 100644 pkg/numbers/amount_test.go delete mode 100644 pkg/numbers/decimal.go delete mode 100644 pkg/numbers/decimal_test.go delete mode 100644 pkg/numbers/number.go delete mode 100644 pkg/numbers/number_test.go diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index 175e363ec..138e67a24 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -6,9 +6,10 @@ import ( "strconv" "strings" - "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/numbers" "errors" + "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" diff --git a/go.mod b/go.mod index 1bdaaadef..2a942951e 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 - github.com/trustwallet/golibs v0.0.9 + github.com/trustwallet/golibs v0.0.10 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmhttp v1.8.0 diff --git a/go.sum b/go.sum index ccb0faf87..86cdfd3b0 100644 --- a/go.sum +++ b/go.sum @@ -465,6 +465,8 @@ github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/golibs v0.0.9 h1:AyupOF1LZyMaZdkwnG3hxSwb5pqW2yZR7EI4hLoBrI8= github.com/trustwallet/golibs v0.0.9/go.mod h1:QB6tQe5tvZOAPmvpeaveFwCQpTqdelSgO6UlMZN30Co= +github.com/trustwallet/golibs v0.0.10 h1:56fXXYwTdBpEfK4QLXYmvD9dkZBM7mfhdutZT5VRtNw= +github.com/trustwallet/golibs v0.0.10/go.mod h1:V12maYRnpDX6saytwYLtUpO8I6lXgc36pguByRq0T54= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= diff --git a/pkg/blockatlas/marshal.go b/pkg/blockatlas/marshal.go index be21a9563..7cfe1a394 100644 --- a/pkg/blockatlas/marshal.go +++ b/pkg/blockatlas/marshal.go @@ -6,7 +6,8 @@ import ( "strings" "errors" - "github.com/trustwallet/blockatlas/pkg/numbers" + + "github.com/trustwallet/golibs/numbers" ) var matchNumber = regexp.MustCompile(`^\d+(\.\d+)?$`) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 5970c8f94..3c909bceb 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -1,14 +1,15 @@ package blockatlas import ( + "sort" + "strconv" + "strings" + mapset "github.com/deckarep/golang-set" "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/asset" "github.com/trustwallet/golibs/coin" - "sort" - "strconv" - "strings" + "github.com/trustwallet/golibs/numbers" ) const ( diff --git a/pkg/numbers/amount.go b/pkg/numbers/amount.go deleted file mode 100644 index d5b202181..000000000 --- a/pkg/numbers/amount.go +++ /dev/null @@ -1,34 +0,0 @@ -package numbers - -import ( - "math" - "strconv" -) - -func GetAmountValue(amount string) string { - value := ParseAmount(amount) - return strconv.FormatInt(value, 10) -} - -func ParseAmount(amount string) int64 { - value, err := strconv.ParseInt(amount, 10, 64) - if err == nil { - return value - } - return ToSatoshi(amount) -} - -func ToSatoshi(amount string) int64 { - value, err := strconv.ParseFloat(amount, 64) - if err != nil { - return 0 - } - total := value * math.Pow10(8) - return int64(total) -} - -func AddAmount(left string, right string) (sum string) { - amount1 := ParseAmount(left) - amount2 := ParseAmount(right) - return strconv.FormatInt(amount1+amount2, 10) -} diff --git a/pkg/numbers/amount_test.go b/pkg/numbers/amount_test.go deleted file mode 100644 index 8db856bcb..000000000 --- a/pkg/numbers/amount_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package numbers - -import ( - "testing" -) - -func Test_addAmount(t *testing.T) { - type args struct { - left string - right string - } - tests := []struct { - name string - args args - wantSum string - }{ - {"test zero + float", args{left: "0", right: "0.33333"}, "33333000"}, - {"test zero + int", args{left: "0", right: "333"}, "333"}, - {"test zero + zero", args{left: "0", right: "0"}, "0"}, - {"test int + float", args{left: "232", right: "0.222"}, "22200232"}, - {"test int + int", args{left: "661", right: "12"}, "673"}, - {"test int + zero", args{left: "131", right: "0"}, "131"}, - {"test float + float", args{left: "0.4141", right: "0.11211"}, "52621000"}, - {"test float + int", args{left: "3.111", right: "11"}, "311100011"}, - {"test float + zero", args{left: "0.455", right: "0"}, "45500000"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if gotSum := AddAmount(tt.args.left, tt.args.right); gotSum != tt.wantSum { - t.Errorf("AddAmount() = %v, want %v", gotSum, tt.wantSum) - } - }) - } -} - -func Test_ToSatoshi(t *testing.T) { - tests := []struct { - name string - amount string - want int64 - }{ - {"test float", "0.33333", 33333000}, - {"test int", "3333", 333300000000}, - {"test zero", "0", 0}, - {"test error", "trust", 0}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := ToSatoshi(tt.amount); got != tt.want { - t.Errorf("ToSatoshi() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_getValue(t *testing.T) { - tests := []struct { - name string - amount string - want string - }{ - {"test float", "0.33333", "33333000"}, - {"test int", "3333", "3333"}, - {"test zero", "0", "0"}, - {"test error", "trust", "0"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := GetAmountValue(tt.amount); got != tt.want { - t.Errorf("GetAmountValue() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_parseAmount(t *testing.T) { - tests := []struct { - name string - amount string - want int64 - }{ - {"test float", "0.33333", 33333000}, - {"test int", "3333", 3333}, - {"test zero", "0", 0}, - {"test error", "trust", 0}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := ParseAmount(tt.amount); got != tt.want { - t.Errorf("ParseAmount() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/numbers/decimal.go b/pkg/numbers/decimal.go deleted file mode 100644 index 580e25039..000000000 --- a/pkg/numbers/decimal.go +++ /dev/null @@ -1,102 +0,0 @@ -package numbers - -import ( - "errors" - "math/big" - "strings" - "unicode" -) - -// DecimalToSatoshis removes the comma in a decimal string -// "12.345" => "12345" -// "0.0230" => "230" -func DecimalToSatoshis(dec string) (string, error) { - out := strings.TrimLeft(dec, " ") - out = strings.TrimRight(out, " ") - out = strings.Replace(out, ".", "", 1) - // trim left 0's but keep last - if l := len(out); l >= 2 { - out = strings.TrimLeft(out[:l-1], "0") + out[l-1:l] - } - if len(out) == 0 { - return "", errors.New("Invalid empty input") - } - for _, c := range out { - if !unicode.IsNumber(c) { - return "", errors.New("not a number") - } - } - return out, nil -} - -// DecimalExp calculates dec * 10^exp in decimal string representation -func DecimalExp(dec string, exp int) string { - // 0 * n = 0 - if dec == "0" { - return "0" - } - // Get comma position - i := strings.IndexRune(dec, '.') - if i == -1 { - // Virtual comma at the end of the string - i = len(dec) - } else { - // Remove comma from underlying number - dec = strings.Replace(dec, ".", "", 1) - } - // Shift comma by exponent - i += exp - // Remove leading zeros - origSize := len(dec) - dec = strings.TrimLeft(dec, "0") - i -= origSize - len(dec) - // Fix bounds - if i <= 0 { - zeros := "" - for ; i < 0; i++ { - zeros += "0" - } - return "0." + zeros + dec - } else if i >= len(dec) { - for i > len(dec) { - dec += "0" - } - return dec - } - // No bound fix needed - return dec[:i] + "." + dec[i:] -} - -// HexToDecimal converts a hexadecimal integer to a base-10 integer -// "0x1fbad5f2e25570000" => "36582000000000000000" -func HexToDecimal(hex string) (string, error) { - var i big.Int - if _, ok := i.SetString(hex, 0); !ok { - return "", errors.New("invalid hex") - } - return i.String(), nil -} - -// CutZeroFractional cuts off a decimal separator and zeros to the right. -// Fails if the fractional part contains contains other digits than zeros. -// - CutZeroFractional("123.00000") => ("123", true) -// - CutZeroFractional("123.456") => ("", false) -func CutZeroFractional(dec string) (integer string, ok bool) { - // Get comma position - comma := strings.IndexRune(dec, '.') - if comma == -1 { - return dec, true - } - - for i := len(dec) - 1; i > comma; i-- { - if dec[i] != '0' { - return "", false - } - } - - if comma == 0 { - return "0", true - } else { - return dec[:comma], true - } -} diff --git a/pkg/numbers/decimal_test.go b/pkg/numbers/decimal_test.go deleted file mode 100644 index 3d1dbcfa0..000000000 --- a/pkg/numbers/decimal_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package numbers - -import "testing" - -func TestDecimalToSatoshis(t *testing.T) { - assertSatEquals := func(expected string, input string) { - actual, err := DecimalToSatoshis(input) - if err != nil { - t.Error(err) - } - if expected != actual { - t.Errorf("expected %s, got %s, input %s", expected, actual, input) - } - } - - assertSatError := func(input string) { - actual, err := DecimalToSatoshis(input) - if err == nil { - t.Errorf("Expected error but no error: got %s, input %s", actual, input) - } - } - - assertSatEquals("10", "1.0") - assertSatEquals("1", "0.1") - assertSatEquals("13602", "136.02") - assertSatEquals("13602", "0136.02") - assertSatEquals("1500000", "0.01500000") - assertSatEquals("0", "0") - assertSatEquals("2030", "0.002030") - assertSatEquals("101010", "0101010") - assertSatEquals("11001100", "0011001100") - assertSatEquals("376", " 376") - assertSatEquals("376", "376 ") - - assertSatError("12NotNumber34") - assertSatError("12,34") - assertSatError("") - assertSatError(" ") - assertSatError("37 6") - assertSatError("37,6") -} - -func TestDecimalExp(t *testing.T) { - assertEquals := func(inputDec string, inputExp int, expected string) { - actual := DecimalExp(inputDec, inputExp) - if expected != actual { - t.Errorf("expected: %s * (10^%d) = %s, got %s", - inputDec, inputExp, expected, actual) - } - } - - // No-Op - assertEquals("0", 300, "0") - assertEquals("0", 8, "0") - assertEquals("123", 0, "123") - assertEquals("0.456", 0, "0.456") - assertEquals("123.456", 0, "123.456") - - // In-Bounds, comma - assertEquals("12.34", -1, "1.234") - assertEquals("12.34", 1, "123.4") - - // 1 past bounds, comma - assertEquals("12.34", -2, "0.1234") - assertEquals("12.34", 2, "1234") - - // n past bounds, comma - assertEquals("12.34", -4, "0.001234") - assertEquals("12.34", 4, "123400") - - // Integer - assertEquals("1234", -1, "123.4") - assertEquals("1234", 1, "12340") - - // Denormalized - assertEquals("0.1234", -1, "0.01234") - assertEquals("0.1234", 1, "1.234") - - // Tiny - assertEquals("0.001234", -1, "0.0001234") - assertEquals("0.001234", 1, "0.01234") - assertEquals("0.000375", 8, "37500") -} - -func TestCutZeroFractional(t *testing.T) { - assertEquals := func(inputDec string, expected string, expOk bool) { - actual, ok := CutZeroFractional(inputDec) - if expected != actual || ok != expOk { - t.Errorf("expected: %s => (%s, %v), actual: (%s, %v)", - inputDec, expected, expOk, actual, ok) - } - } - - // No comma - assertEquals("", "", true) - assertEquals("eee", "eee", true) - - // Length 1 - assertEquals(".", "0", true) - assertEquals(".3", "", false) - assertEquals(".0", "0", true) - assertEquals("0.", "0", true) - assertEquals("1.0", "1", true) - assertEquals("1.1", "", false) - assertEquals("1.0.0", "", false) - - // Arbitrary content left to comma - assertEquals("eee.000", "eee", true) - assertEquals("eee.001", "", false) - assertEquals("eee.100", "", false) - - // Long strings - assertEquals("163056848705309039018274728757999527956626319283048085297785610.238523", "", false) - assertEquals("11434397695550368380599182733571088333799363173941798154.0000000000000", "11434397695550368380599182733571088333799363173941798154", true) -} diff --git a/pkg/numbers/number.go b/pkg/numbers/number.go deleted file mode 100644 index ed3fb56db..000000000 --- a/pkg/numbers/number.go +++ /dev/null @@ -1,86 +0,0 @@ -package numbers - -import ( - "errors" - "github.com/shopspring/decimal" - "math" - "math/big" - "strconv" - "strings" -) - -func Min(x, y int) int { - if x < y { - return x - } - return y -} - -func Max(x, y int64) int64 { - if x > y { - return x - } - return y -} - -func Round(num float64) int { - return int(num + math.Copysign(0.5, num)) -} - -func Float64toPrecision(num float64, precision int) float64 { - output := math.Pow(10, float64(precision)) - return float64(Round(num*output)) / output -} - -// 0.1010 => "0.101" -func Float64toString(num float64) string { - return strconv.FormatFloat(num, 'f', -1, 64) -} - -// "0.00037500" => 0.000375, "non-string-number" => 0 -func StringNumberToFloat64(str string) (float64, error) { - value, err := strconv.ParseFloat(str, 64) - if err != nil { - return 0, err - } else { - return value, nil - } -} - -func FromDecimal(dec string) string { - v, err := DecimalToSatoshis(dec) - if err != nil { - return "0" - } - return v -} - -func ToDecimal(value string, exp int) string { - num, ok := new(big.Int).SetString(value, 10) - if !ok { - return "0" - } - denom := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(exp)), nil) - rat := new(big.Rat).SetFrac(num, denom) - f, err := decimal.NewFromString(rat.FloatString(10)) - if err != nil { - return "0" - } - return f.String() -} - -func FromDecimalExp(dec string, exp int) string { - return strings.Split(DecimalExp(dec, exp), ".")[0] -} - -func SliceAtoi(sa []string) ([]int, error) { - si := make([]int, 0, len(sa)) - for _, a := range sa { - i, err := strconv.Atoi(a) - if err != nil { - return si, errors.New(err.Error() + " SliceAtoi error") - } - si = append(si, i) - } - return si, nil -} diff --git a/pkg/numbers/number_test.go b/pkg/numbers/number_test.go deleted file mode 100644 index 5af1964ff..000000000 --- a/pkg/numbers/number_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package numbers - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestMin(t *testing.T) { - assert.Equal(t, Min(1, 5), 1) - assert.Equal(t, Min(22, 5), 5) -} - -func TestMax(t *testing.T) { - assert.Equal(t, Max(1, 5), int64(5)) - assert.Equal(t, Max(22, 5), int64(22)) -} - -func TestToDecimal(t *testing.T) { - assert.Equal(t, ToDecimal("0", 18), "0") - assert.Equal(t, ToDecimal("100", 1), "10") - assert.Equal(t, ToDecimal("123123", 3), "123.123") - assert.Equal(t, ToDecimal("10012000000000000", 12), "10012") - assert.Equal(t, ToDecimal("123456789012345678901", 18), "123.4567890123") - assert.Equal(t, ToDecimal("4618", 6), "0.004618") - assert.Equal(t, ToDecimal("218218", 8), "0.00218218") - assert.Equal(t, ToDecimal("212880628", 9), "0.212880628") - assert.Equal(t, ToDecimal("4634460765323682", 18), "0.0046344608") -} - -func TestFromDecimal(t *testing.T) { - assert.Equal(t, FromDecimal("100.12"), "10012") -} - -func TestToDecimalExp(t *testing.T) { - assert.Equal(t, FromDecimalExp("10", 1), "100") - assert.Equal(t, FromDecimalExp("100", 1), "1000") - assert.Equal(t, FromDecimalExp("10012", 12), "10012000000000000") - assert.Equal(t, FromDecimalExp("123.123", 3), "123123") - //assert.Equal(t, FromDecimalExp("0.005170630816959669", 2), "") Need fix - assert.Equal(t, FromDecimalExp("0.000180508184692364", 4), "1") - assert.Equal(t, FromDecimalExp("0.004618071835862274", 6), "4618") - assert.Equal(t, FromDecimalExp("0.00216013705800604", 8), "216013") - assert.Equal(t, FromDecimalExp("0.002182187913804679", 8), "218218") - assert.Equal(t, FromDecimalExp("0.21288062808828456", 9), "212880628") - assert.Equal(t, FromDecimalExp("0.004634460765323682", 18), "4634460765323682") - assert.Equal(t, FromDecimalExp("0.00000001", 8), "1") - assert.Equal(t, FromDecimalExp("10.00000000", 8), "1000000000") -} - -func TestFloat64toPrecision(t *testing.T) { - assert.Equal(t, Float64toPrecision(3.643005, 4), 3.6430) - assert.Equal(t, Float64toPrecision(9.8233168e-5, 4), 0.0001) - assert.Equal(t, Float64toPrecision(0.8010, 4), 0.8010) - assert.Equal(t, Float64toPrecision(26.5, 4), 26.5) - assert.Equal(t, Float64toPrecision(3374, 4), 3374.0) -} - -func TestFloat64toString(t *testing.T) { - assert.Equal(t, Float64toString(0), "0") - assert.Equal(t, Float64toString(0.0), "0") - assert.Equal(t, Float64toString(0.1), "0.1") - assert.Equal(t, Float64toString(0.1010), "0.101") - assert.Equal(t, Float64toString(0.015), "0.015") - assert.Equal(t, Float64toString(1), "1") - assert.Equal(t, Float64toString(1.1), "1.1") - assert.Equal(t, Float64toString(1.015), "1.015") - assert.Equal(t, Float64toString(2800.00000000), "2800") - assert.Equal(t, Float64toString(0.00037500), "0.000375") -} - -func TestStringNumberToFloat64(t *testing.T) { - var tests = []struct { - stringNumber string - expect float64 - ecpectErr bool - }{ - {"0.29970000", 0.2997, false}, - {"0.00037500", 0.000375, false}, - {"1.0", 1, false}, - {"1", 1, false}, - {"0", 0, false}, - {"23.12", 23.120, true}, - } - - for _, tt := range tests { - t.Run("", func(t *testing.T) { - actual, err := StringNumberToFloat64(tt.stringNumber) - if tt.ecpectErr { - assert.Nil(t, err) - } else { - assert.Equal(t, tt.expect, actual) - } - }) - } -} diff --git a/platform/aeternity/transaction.go b/platform/aeternity/transaction.go index 1e67e5c50..33380a544 100644 --- a/platform/aeternity/transaction.go +++ b/platform/aeternity/transaction.go @@ -2,10 +2,11 @@ package aeternity import ( "encoding/base64" + "strings" + "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" - "strings" + "github.com/trustwallet/golibs/numbers" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/aion/transaction.go b/platform/aion/transaction.go index b20d93d39..c2675365a 100644 --- a/platform/aion/transaction.go +++ b/platform/aion/transaction.go @@ -1,10 +1,11 @@ package aion import ( + "strconv" + "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" - "strconv" + "github.com/trustwallet/golibs/numbers" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/algorand/client.go b/platform/algorand/client.go index 913a3311e..f856931bf 100644 --- a/platform/algorand/client.go +++ b/platform/algorand/client.go @@ -2,8 +2,9 @@ package algorand import ( "fmt" + "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/numbers" ) type Client struct { diff --git a/platform/binance/model.go b/platform/binance/model.go index 8ad80ee65..c928f805f 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -1,12 +1,13 @@ package binance import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" - "github.com/trustwallet/golibs/coin" "strconv" "strings" "time" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/numbers" ) const ( diff --git a/platform/bitcoin/transaction.go b/platform/bitcoin/transaction.go index 7adeb2a1d..b64b78ba7 100644 --- a/platform/bitcoin/transaction.go +++ b/platform/bitcoin/transaction.go @@ -5,8 +5,8 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/numbers" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 7d60ae0c2..4150b7f9b 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -1,12 +1,13 @@ package cosmos import ( - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "strconv" "sync" "time" + + log "github.com/sirupsen/logrus" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/numbers" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/harmony/client.go b/platform/harmony/client.go index a94d2d70e..3b069cf1a 100644 --- a/platform/harmony/client.go +++ b/platform/harmony/client.go @@ -6,7 +6,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/numbers" ) type Client struct { diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index e1219f9ce..2dd7bb4c6 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -1,10 +1,11 @@ package harmony import ( + "strconv" + "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" - "strconv" + "github.com/trustwallet/golibs/numbers" ) const Annual = 10 @@ -29,8 +30,6 @@ func NormalizeTxs(txs []Transaction) blockatlas.TxPage { return normalizeTxs } - - func NormalizeTx(trx *Transaction) (tx blockatlas.Tx, b bool, err error) { gasPrice, err := hexToInt(trx.GasPrice) if err != nil { diff --git a/platform/icon/transaction.go b/platform/icon/transaction.go index f9e897aba..9d470ddc0 100644 --- a/platform/icon/transaction.go +++ b/platform/icon/transaction.go @@ -1,11 +1,12 @@ package icon import ( + "time" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" - "time" + "github.com/trustwallet/golibs/numbers" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/kava/transaction.go b/platform/kava/transaction.go index f8315db2a..9edb05c14 100644 --- a/platform/kava/transaction.go +++ b/platform/kava/transaction.go @@ -1,12 +1,13 @@ package kava import ( - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "strconv" "sync" "time" + + log "github.com/sirupsen/logrus" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/numbers" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/ontology/transaction.go b/platform/ontology/transaction.go index a6618d7ca..47c905b08 100644 --- a/platform/ontology/transaction.go +++ b/platform/ontology/transaction.go @@ -2,11 +2,12 @@ package ontology import ( "errors" + "sync" + log "github.com/sirupsen/logrus" blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" - "sync" + "github.com/trustwallet/golibs/numbers" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/polkadot/transaction.go b/platform/polkadot/transaction.go index 5a1387c57..94b702345 100644 --- a/platform/polkadot/transaction.go +++ b/platform/polkadot/transaction.go @@ -4,9 +4,10 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/trustwallet/blockatlas/pkg/numbers" "strings" + "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) diff --git a/platform/stellar/transaction.go b/platform/stellar/transaction.go index 14caa4375..d431212a1 100644 --- a/platform/stellar/transaction.go +++ b/platform/stellar/transaction.go @@ -1,10 +1,11 @@ package stellar import ( + "time" + "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" - "time" + "github.com/trustwallet/golibs/numbers" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index f09205c4d..e400373bc 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -3,8 +3,8 @@ package tezos import ( log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/numbers" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { diff --git a/platform/vechain/stake.go b/platform/vechain/stake.go index 191879f72..802e81a0d 100644 --- a/platform/vechain/stake.go +++ b/platform/vechain/stake.go @@ -2,8 +2,8 @@ package vechain import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/golibs/numbers" ) const ( diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 9a8933ac2..ee0e05a70 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -2,12 +2,13 @@ package vechain import ( "errors" + "strconv" + "sync" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" - "strconv" - "sync" + "github.com/trustwallet/golibs/numbers" ) func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { diff --git a/services/assets/validator.go b/services/assets/validator.go index 115de82c8..90ccb4ee0 100644 --- a/services/assets/validator.go +++ b/services/assets/validator.go @@ -1,10 +1,11 @@ package assets import ( + "sort" + "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" "github.com/trustwallet/golibs/coin" - "sort" + "github.com/trustwallet/golibs/numbers" ) func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) { diff --git a/services/parser/parser.go b/services/parser/parser.go index dfddec74f..cca31e365 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -5,18 +5,20 @@ import ( "encoding/json" "errors" "fmt" + "sync/atomic" + "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/pkg/numbers" + "github.com/trustwallet/golibs/numbers" "go.elastic.co/apm" - "sync/atomic" - log "github.com/sirupsen/logrus" "math/rand" "sort" "sync" "time" + + log "github.com/sirupsen/logrus" ) type ( From 91927d835d226d8d4477db5055c8aab19de17cd7 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Mon, 16 Nov 2020 15:43:57 +0300 Subject: [PATCH 411/506] [Docker] Fix docker-compose (#1276) --- docker-compose.yml | 56 +++++++++++++++------------------------------- nginx.conf | 11 --------- 2 files changed, 18 insertions(+), 49 deletions(-) delete mode 100644 nginx.conf diff --git a/docker-compose.yml b/docker-compose.yml index dc5240ca9..88028cb3e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,61 +1,41 @@ version: '3.7' services: - nginx: - container_name: nginx - image: nginx:alpine - volumes: - - ./nginx.conf:/etc/nginx/conf.d/default.conf - ports: - - 8080:80 - links: - - platform_api - - swagger_api - - platform_api: + api: container_name: api + environment: + - POSTGRES_URL=postgresql://user:pass@postgres/blockatlas?sslmode=disable + - POSTGRES_READ_URL=postgresql://user:pass@postgres/blockatlas?sslmode=disable + - OBSERVER_RABBITMQ_URL=amqp://rabbit:5672 build: context: . args: - SERVICE=api ports: - 8420:8420 - - 8437:8437 - - swagger_api: - container_name: swagger_api - build: - context: . - args: - - SERVICE=swagger_api - ports: - - 8423:8423 - observer_notifier: + consumer: build: context: . args: - - SERVICE=notifier + - SERVICE=consumer + environment: + - POSTGRES_URL=postgresql://user:pass@postgres/blockatlas?sslmode=disable + - POSTGRES_READ_URL=postgresql://user:pass@postgres/blockatlas?sslmode=disable + - OBSERVER_RABBITMQ_URL=amqp://rabbit:5672 links: - rabbit - postgres restart: on-failure - observer_parser: + parser: build: context: . args: - SERVICE=parser - links: - - rabbit - - postgres - restart: on-failure - - observer_subscriber: - container_name: subscriber - build: - context: . - args: - - SERVICE=subscriber + environment: + - POSTGRES_URL=postgresql://user:pass@postgres/blockatlas?sslmode=disable + - POSTGRES_READ_URL=postgresql://user:pass@postgres/blockatlas?sslmode=disable + - OBSERVER_RABBITMQ_URL=amqp://rabbit:5672 links: - rabbit - postgres @@ -67,7 +47,7 @@ services: ports: - 5672:5672 healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:5672"] + test: [ "CMD", "curl", "-f", "http://localhost:5672" ] interval: 30s timeout: 10s retries: 5 @@ -82,7 +62,7 @@ services: ports: - 5432:5432 healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:5432"] + test: [ "CMD", "curl", "-f", "http://localhost:5432" ] interval: 30s timeout: 10s retries: 5 diff --git a/nginx.conf b/nginx.conf deleted file mode 100644 index 8fd11f920..000000000 --- a/nginx.conf +++ /dev/null @@ -1,11 +0,0 @@ -server { - listen 80; - - location ~* /swagger.* { - proxy_pass http://swagger_api:8423; - } - - location / { - proxy_pass http://platform_api:8420; - } -} From e3a90266b87fdc845f723d8c62c1a52a04eda228 Mon Sep 17 00:00:00 2001 From: Iuga Mihai <50499646+miiu96@users.noreply.github.com> Date: Tue, 17 Nov 2020 17:49:24 +0200 Subject: [PATCH 412/506] New transaction statuses (#1274) * new transaction status * small fix --- platform/elrond/model.go | 4 +- platform/elrond/transaction_test.go | 82 ++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/platform/elrond/model.go b/platform/elrond/model.go index ab607cca5..c4576ed1d 100644 --- a/platform/elrond/model.go +++ b/platform/elrond/model.go @@ -51,9 +51,9 @@ type Transaction struct { func (tx *Transaction) TxStatus() blockatlas.Status { switch tx.Status { - case "Success": + case "Success", "success": return blockatlas.StatusCompleted - case "Pending": + case "Pending", "pending": return blockatlas.StatusPending default: return blockatlas.StatusError diff --git a/platform/elrond/transaction_test.go b/platform/elrond/transaction_test.go index 914cf60e8..6d20d0c39 100644 --- a/platform/elrond/transaction_test.go +++ b/platform/elrond/transaction_test.go @@ -49,13 +49,43 @@ const txTransferSrc3 = ` "value":"2", "receiver":"erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - "data":"bla bla bla", + "data":"test", "signature":"", "timestamp":1588757256, "status":"Not executed", "fee": "5000" }` +const txTransferSrc4 = ` +{ + "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce":19, + "round":200, + "value":"2", + "receiver":"erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "data":"test", + "signature":"", + "timestamp":1588757256, + "status":"pending", + "fee": "5000" +}` + +const txTransferSrc5 = ` +{ + "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce":19, + "round":200, + "value":"2", + "receiver":"erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "data":"test", + "signature":"", + "timestamp":1588757256, + "status":"success", + "fee": "5000" +}` + var txTransfer1Normalized = blockatlas.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", Coin: coin.ERD, @@ -100,7 +130,43 @@ var txTransfer3Normalized = blockatlas.Tx{ To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", Fee: "5000", Status: blockatlas.StatusError, - Memo: "bla bla bla", + Memo: "test", + Sequence: 19, + Meta: blockatlas.Transfer{ + Value: "2", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionOutgoing, +} + +var txTransfer4Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.ERD, + Date: int64(1588757256), + From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + Fee: "5000", + Status: blockatlas.StatusPending, + Memo: "test", + Sequence: 19, + Meta: blockatlas.Transfer{ + Value: "2", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionOutgoing, +} + +var txTransfer5Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.ERD, + Date: int64(1588757256), + From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + Fee: "5000", + Status: blockatlas.StatusCompleted, + Memo: "test", Sequence: 19, Meta: blockatlas.Transfer{ Value: "2", @@ -134,6 +200,18 @@ func TestNormalize(t *testing.T) { apiResponse: txTransferSrc3, expected: &txTransfer3Normalized, }) + + testNormalize(t, &test{ + name: "transferPendingNewStatus", + apiResponse: txTransferSrc4, + expected: &txTransfer4Normalized, + }) + + testNormalize(t, &test{ + name: "transferSuccessNewStatus", + apiResponse: txTransferSrc5, + expected: &txTransfer5Normalized, + }) } func TestNormalizeTxs(t *testing.T) { From 8d146668fadd2b963281eb85f06edb3ea09c3c6a Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Tue, 17 Nov 2020 21:39:27 +0300 Subject: [PATCH 413/506] [Platform] Implement block api (#1279) * Setup block api * Add mock test for filecoin * Implement get block by number * Add tests * Finish with block api * Cleanup * Cleanup * Add timestamp * Add todo --- go.mod | 4 +- go.sum | 8 +- platform/filecoin/block.go | 63 + platform/filecoin/block_test.go | 84 + platform/filecoin/client.go | 35 + .../filecoin/mocks/ChainGetBlockMessages.json | 2882 +++++++++++++++++ .../mocks/ChainGetTipSetByHeight.json | 196 ++ platform/filecoin/mocks/ChainHead.json | 202 ++ platform/filecoin/models.go | 45 + services/parser/parser.go | 2 +- 10 files changed, 3511 insertions(+), 10 deletions(-) create mode 100644 platform/filecoin/block.go create mode 100644 platform/filecoin/block_test.go create mode 100644 platform/filecoin/mocks/ChainGetBlockMessages.json create mode 100644 platform/filecoin/mocks/ChainGetTipSetByHeight.json create mode 100644 platform/filecoin/mocks/ChainHead.json create mode 100644 platform/filecoin/models.go diff --git a/go.mod b/go.mod index 2a942951e..c5073f559 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ go 1.15 require ( github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect - github.com/DeanThompson/ginpprof v0.0.0-20190408063150-3be636683586 github.com/Microsoft/go-winio v0.4.14 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 @@ -31,14 +30,13 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.7.1 - github.com/shopspring/decimal v1.2.0 github.com/sirupsen/logrus v1.6.0 github.com/spf13/viper v1.7.1 github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 - github.com/trustwallet/golibs v0.0.10 + github.com/trustwallet/golibs v0.0.13 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmhttp v1.8.0 diff --git a/go.sum b/go.sum index 86cdfd3b0..38876f0f7 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,6 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DeanThompson/ginpprof v0.0.0-20190408063150-3be636683586 h1:vDSj8WQZoe+dhK9JVwkSEBwtmcJw5rJ7l1L0Yik8Ku0= -github.com/DeanThompson/ginpprof v0.0.0-20190408063150-3be636683586/go.mod h1:kMi/fSDAgvjo9TYfYwYeQ2vkyj+VTR/tB6u/Tjh39t0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= @@ -463,10 +461,8 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.9 h1:AyupOF1LZyMaZdkwnG3hxSwb5pqW2yZR7EI4hLoBrI8= -github.com/trustwallet/golibs v0.0.9/go.mod h1:QB6tQe5tvZOAPmvpeaveFwCQpTqdelSgO6UlMZN30Co= -github.com/trustwallet/golibs v0.0.10 h1:56fXXYwTdBpEfK4QLXYmvD9dkZBM7mfhdutZT5VRtNw= -github.com/trustwallet/golibs v0.0.10/go.mod h1:V12maYRnpDX6saytwYLtUpO8I6lXgc36pguByRq0T54= +github.com/trustwallet/golibs v0.0.13 h1:25XKd76pQr4i6UNoyJYGtrogpN9/YzNNwYzXoxh3h68= +github.com/trustwallet/golibs v0.0.13/go.mod h1:j+Tip4aaW3mu+81S1a+UJ8fSnKzLeJyBueApnCXXRMg= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= diff --git a/platform/filecoin/block.go b/platform/filecoin/block.go new file mode 100644 index 000000000..e96174724 --- /dev/null +++ b/platform/filecoin/block.go @@ -0,0 +1,63 @@ +package filecoin + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + response, err := p.client.getBlockHeight() + if err != nil { + return 0, err + } + return int64(response.Height), nil +} + +func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { + chainHeadResponse, err := p.client.getTipSetByHeight(num) + if err != nil { + return nil, err + } + blockResponses := make([]BlockMessageResponse, 0, len(chainHeadResponse.getCids())) + for _, cid := range chainHeadResponse.getCids() { + blockResponse, err := p.client.getBlockMessage(cid) + if err != nil { + return nil, err + } + blockResponses = append(blockResponses, blockResponse) + } + + return normalizeBlockResponses(uint64(chainHeadResponse.Height), uint64(chainHeadResponse.getTimestamp()), blockResponses), nil +} + +func normalizeBlockResponses(num, timestamp uint64, responses []BlockMessageResponse) *blockatlas.Block { + var result blockatlas.Block + result.Number = int64(num) + for _, resp := range responses { + for _, msg := range resp.SecpkMessages { + tx := normalizeBlockTx(num, timestamp, msg) + result.Txs = append(result.Txs, tx) + } + } + return &result +} + +func normalizeBlockTx(num, timestamp uint64, msg SecpkMessage) blockatlas.Tx { + return blockatlas.Tx{ + Coin: coin.Filecoin().ID, + From: msg.Message.From, + To: msg.Message.To, + // todo: use StateGetReceipt + https://documenter.getpostman.com/view/4872192/SWLh5mUd?version=latest + Fee: "0", + Block: num, + Date: int64(timestamp), + Status: blockatlas.StatusCompleted, + Sequence: uint64(msg.Message.Nonce), + Type: blockatlas.TxTransfer, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount(msg.Message.Value), + Symbol: coin.Filecoin().Symbol, + Decimals: coin.Filecoin().Decimals, + }, + } +} diff --git a/platform/filecoin/block_test.go b/platform/filecoin/block_test.go new file mode 100644 index 000000000..f97c8f77e --- /dev/null +++ b/platform/filecoin/block_test.go @@ -0,0 +1,84 @@ +package filecoin + +import ( + "encoding/json" + "fmt" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/golibs/mock" + "net/http" + "net/http/httptest" + "testing" +) + +func TestPlatform_CurrentBlockNumber(t *testing.T) { + chainHead, err := mock.JsonFromFilePathToString("mocks/ChainHead.json") + assert.Nil(t, err) + + data := make(map[string]func(http.ResponseWriter, *http.Request)) + data["/"] = func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + if _, err := fmt.Fprint(w, chainHead); err != nil { + panic(err) + } + } + + server := httptest.NewServer(mock.CreateMockedAPI(data)) + defer server.Close() + + p := Init(server.URL) + block, err := p.CurrentBlockNumber() + assert.Nil(t, err) + assert.Equal(t, int64(243590), block) +} + +func TestPlatform_GetBlockByNumber(t *testing.T) { + data := make(map[string]func(http.ResponseWriter, *http.Request)) + data["/"] = func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + + type Request map[string]interface{} + var p Request + + err := json.NewDecoder(r.Body).Decode(&p) + if err != nil { + panic(err) + } + + resp, ok := p["method"] + if !ok { + panic("bad json request") + } + var d string + + switch resp { + case "Filecoin.ChainGetTipSetByHeight": + chainHead, err := mock.JsonFromFilePathToString("mocks/ChainGetTipSetByHeight.json") + if err != nil { + panic(err) + } + d = chainHead + case "Filecoin.ChainGetBlockMessages": + blockMsg, err := mock.JsonFromFilePathToString("mocks/ChainGetBlockMessages.json") + if err != nil { + panic(err) + } + d = blockMsg + } + + if _, err := fmt.Fprint(w, d); err != nil { + panic(err) + } + } + + server := httptest.NewServer(mock.CreateMockedAPI(data)) + defer server.Close() + + p := Init(server.URL) + block, err := p.GetBlockByNumber(243590) + assert.Nil(t, err) + raw, err := json.Marshal(block) + assert.Nil(t, err) + assert.Equal(t, wantedResponse, string(raw)) +} + +const wantedResponse = `{"number":243590,"txs":[{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f029223","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246187,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f026582","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246188,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f029084","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246189,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f026721","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246190,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f027694","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246191,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028389","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246192,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f027138","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246193,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028945","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246194,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028250","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246195,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f027555","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246196,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f026860","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246197,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028806","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246198,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f026999","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246199,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028528","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246200,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028667","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246201,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f1i5kvaeurfv27jncddyvcuzgegm4j46y5u7okcza","to":"f2mgv6khl6s6oukeyi3nm3ja67s7fl3cecy2stvny","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":2,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}}]}` diff --git a/platform/filecoin/client.go b/platform/filecoin/client.go index db68d5a30..d2ab1becf 100644 --- a/platform/filecoin/client.go +++ b/platform/filecoin/client.go @@ -7,3 +7,38 @@ import ( type Client struct { blockatlas.Request } + +func (c Client) getBlockHeight() (ChainHeadResponse, error) { + var result ChainHeadResponse + err := c.RpcCall(&result, "Filecoin.ChainHead", nil) + if err != nil { + return ChainHeadResponse{}, err + } + return result, nil +} + +func (c Client) getTipSetByHeight(height int64) (ChainHeadResponse, error) { + var result ChainHeadResponse + params := []interface{}{ + height, nil, + } + err := c.RpcCall(&result, "Filecoin.ChainGetTipSetByHeight", params) + if err != nil { + return ChainHeadResponse{}, err + } + return result, nil +} + +func (c Client) getBlockMessage(cid string) (BlockMessageResponse, error) { + var result BlockMessageResponse + params := []interface{}{ + map[string]interface{}{ + "/": cid, + }, + } + err := c.RpcCall(&result, "Filecoin.ChainGetBlockMessages", params) + if err != nil { + return BlockMessageResponse{}, err + } + return result, nil +} diff --git a/platform/filecoin/mocks/ChainGetBlockMessages.json b/platform/filecoin/mocks/ChainGetBlockMessages.json new file mode 100644 index 000000000..13cad238d --- /dev/null +++ b/platform/filecoin/mocks/ChainGetBlockMessages.json @@ -0,0 +1,2882 @@ +{ + "jsonrpc": "2.0", + "result": { + "BlsMessages": [ + { + "Version": 0, + "To": "f062473", + "From": "f3qbgrbvdjmdstalvmefvisjjjfyslpjjnvxximaidqrr33defn3qfdzlkthsnuyfzc6bks72mfxky4qiajqbq", + "Nonce": 61933, + "Value": "122760309660224659", + "GasLimit": 56726101, + "GasFeeCap": "1322142693", + "GasPremium": "661071346", + "Method": 7, + "Params": "ghl4BFkHgJkOp/hm0V1R6QySU/Wmn30Q3Ao6/PUW5vWENqToGB3fUQTxVMfYjr4Av/7G+Hv1n6ukcwWaOWzAE8DjdgQRczclVlYmh7QZVIirJgHLILwtG1jpsxEMQo2miCjJ5hZ1bAQQn1g48bULsQ2WVOU90OQQHYrB3BfJmX5rtJhnPjGkcfpQLdQguLZcEOnWlH1p24CNRIpsAcUcBn5UDgPWgWUuZQ9ENuwDLmODAMRgGvI4c4u5564//jR8jSP/lQ7N0o4f9iw4xlRv/Aha58hryMgxmNW65xiAOClo/5OIgSGD6JcTWZAkd3ipaAfoIdXCxYr6XpIFeQZcDz0DkanZb/A4WRmAHUF5f4Yf+Gs8EFKGJfc8VTZZzHqelCcoIKrhiQauBnyJH7Pc2oxWO+q6auoVnTwRsim+EdD6UEqrvn/Hn+uL2LZD58NifKJRfeFtEbiIpvcNWzF6tKSc5yijGz0vdsAx5qcgF5ZdV//90RENHBopAeN1/l+/C//bQsjWcK7O0anFgI7mec48tI/y2x4eo+wukpGEba8TkDzJm/2pzyRZW8RZMu0OE0RtbZ3MP6i0l3B3tVUhwd/Uc16fmL97qyAIkYUU5T3QaNPGvbNXas7BbsQGXMq3LppHE37iuAPYGypjFD8IVtljImppA0sc6giFr39LIwVy5F3OC28rCdnp2yoR6B3BA8rYGUaDObb4kpJonRsF+WIF12HSmOQKfNrclBhVp9oNQdBfioDuohASm06Raz2ePAHovwZCh7c4z7COmhyN3zwIaGaELLCy3h0nEtgIGhk/QylhsvEoeYTCWkxQwW8EG6+LZoTHm5hiwwjRPuUvr60KP1YAT5XhnbcLhhuSxSiLnSiUlrkJ6WBMPYRsiwoZ3h/Z7bLzUQ1aNK44cGHRvNPa0AZ1khmgEKheidcCkuptWEDwURlx//rYwXhtwb2UwMnpw3g3doZqIsdu6HZsmUDGCseiQgSV0CR+B72739ZjEzMka2L8dQZi36wF6NCZKKEdYjHdw6zCXMBP3NLvGYNfEmsGDsOEeVDonMHI63bFMlYC5avy4ikhzDa+9lNA5GeuNjSdC7O1UFycauqf5kPAdPOR9hmfy3BWGMnS+3LdF92BFT7FnX5TuwbZEN+mG+gn18G2awRtMgQFSX7lUaP8lB09YABSC46iSwppSZldi2pdRzhnWSyoL9/xZ6faBeEuPMrNmaF0OBr3Kb12vbP+b9PuI84Arp570hYqiFO6+SD7niEd96zrq2SDbBEubdDwDEvP04r4UBxeiHK20Wr41+OqyX4vjCcr8DYqXkTMTyQdIv8dyNjE8nLD/vb5NrcDHhwvu5ha39ZAiJ2/3AJy4gWD5prrEn3DnWt9tfrakQG2E/hd4Q7DNy2dBRBhPuTOREYxOA+crHBt+npQnucjRSLlqj+sTzv8XWKAq6RgUacdqkYdR1mjpLoRKQ6gFWX0La7fTI1ixaQh5tZ/fvNjL+lrT+IuSaC1LPclYQnzwRowDyEVa+q/XOPwIsLVOyez/0AqRqXCmXeMX1q1PLIL3+HnaC2OWYgbPSgtSoJjHvhn2D+qw5tlSpR9GikRbqsgXHUEDbKAFo1+5egZ8+gIQxAslb0j6HoYCBidBYZXw+0iafMSSn35+1uV71lUhJPOOMue0g2Qh9bV8Ej2Z5gMh1dXEZwQWWAawytIkBRTIwWX2rtC4fD1C9uDD0yb8EZQiFvC6LhSKUVPe0VYIeswrEQRftzthSRCZITmX/HrMFUOBYseCIVIGBcTvYEQDi3+ynqSYpH/7Yi/7j+FdXr/+r5nYDZ5bGPfDPY4JGwtSh/VhseU5Dvx6iMoG+JnBfmQDL2xubQbRGit84lKP/pVH9ADCkHPY2o2271R6hNTuuv3VsPkd/pO0tos2bV39WxqoCC+5RjycKqN3FBSrdRGAqUf+BK3+xdBXXegnBVQNZtRpbFk9FblIyHeKSNnwiXIXkQGGaMsGIm9DyIsJV5h2NliVMt1K8yzQ0gMpVVeasrMZmzlpnU3CwZhs/d67BIWustfcYYuBTSRT/6/M3HPA0yS39IAYFtGgfNuG+bFUjK+2kSNrKzBLbugG7XtX8H5E+hDNITt8Aux0dwHgww0SCOfl3LplqrH1Lip0eghtwVAbGIzgL5E4Ef34bBzd1mLgavsiRNqDvaUilIMp18zdi/4NSS4iZAi4rB7Qk0Sj33rLHZSEV1QBuq0a0Ejlgn9C0N8HZinV2rl80JJQVZWKw5Mdx9oxlLseZD5hjfHTd9Dr+rxzYYDTJ7X67cn259apGu4fY5fc6dx3FWzJfomQUpoqBPvGNrMh/NqXaqARy7Q6yT2AfA2uA8DajYlywE9usXMPqRpnW7JaylSelim36KlduzTQd3ii6/ylcsGlD+YGMxesLpfW4+A/MCvdrFTxJZeZAOcW9AIbaLy7/uPwGLx/kn33V6tXN6+FPeViQImaIf/Af2iyNjziKLkySafcZ6g7JB/QvQ9itO4uGDb6lnDNe9yuOZmZ2oiucT6SdmLKpUtdfBL9XQE3sSQP5OD2f5M8g==" + }, + { + "Version": 0, + "To": "f062473", + "From": "f3qbgrbvdjmdstalvmefvisjjjfyslpjjnvxximaidqrr33defn3qfdzlkthsnuyfzc6bks72mfxky4qiajqbq", + "Nonce": 61934, + "Value": "121192496968008715", + "GasLimit": 15962483, + "GasFeeCap": "2349258570", + "GasPremium": "1174629285", + "Method": 6, + "Params": "igMZeHXYKlgpAAGC4gOB6AIggik0zQ76qfvPzTn8Vhl/D66vPsyIZgAgDhmGyKmsKkEaAAOyW4AaABtnUvQAAAA=" + }, + { + "Version": 0, + "To": "f066102", + "From": "f3xbhu7ukbh2uwy6ayzgtb2xwevdn6mpiiyfnpczjmt6rvpnemyu542dvboqw24i2nfcnw5vxvh2hp76v77ogq", + "Nonce": 201683, + "Value": "122414013498084734", + "GasLimit": 57261793, + "GasFeeCap": "1099999999", + "GasPremium": "130646", + "Method": 7, + "Params": "ghoAAZIlWQeAhqeAvS9b3Byils9iMtU2oCIUhh/4Kk28d8ywba2aZdVmNPbwYm6ezvVbJQZ+GySklF3x25k8qTSaWPFdfTsbIJAa0etlmWqNLk4k4sRfiA+96XWT+NCzZzPKXRpP1H//EYkb5kPWXPcU9D5jUUNB8wBNjclij0Otw+cmsekLpfDlZ1S1PBIkBAL6eXOkh+cUkB0XUgQHmKrLL4yNyNqqcWFwiCvdXk+/TBmDC8zxtGEhg3EKp02VAIeItB2b2KsJmIEQk9k0yiZtZtxziGq9IYaqHraynd3z+tnUuUqpOsEQpfSkk7E3VLRYd9kklataqbiDskehGbY83pMz/w0O3TeSGdKBFRlEuyuL8JHnggWZqBIPCzhTwi39m0Hb/JCqETPSH3yzBVC32T2f3+6FttpvnVjHQLJCyyhoqRPn8ywgKOa44+g/i/NvZ9zmOa5Xr5GO8IAbyuS7Sx6qvnukMKXWlSQf7MIrdOh9Hsd+0ow+tfSrwqWKl56zT66goqR5tpvs/NhdBkRw5VXKzg1UfdYuIzCRWNBk8P2AkqWhz/mBgk4wA8duWEA63JdXm5OIiUYVkC3LgbeN3SjmF17smAB7ZzLDwO2WlLuUl0/ZlF82ixda/6ut6PD2hQp4F725FgxGjgjMD1AsbE2DBTZ5j9kQsGTVwrLor1q3Kx2f1s7p9GSNyhYOahcZ4R1S6wPYiNSE0pIMA//yvB1w1ijX/P7EthtGA3IjFHfOvCF3X8OIKvjXEzwsrhYNIa+d7SNGjtWM5mWjq9GYZuJFbzOke2iUjl6TXL9HUoWfl+2GglS8xrphVPLo8Bcxp+BxtzH1rlQkMPDGSBmVBkLeEM683euchY3w9nUVsvAjJCOJPzuuyXAqjWuZTbOJyQIfBKS6Fe+mESeweVSknSgztGqwwOZtG2Po0WSudQV66vYvluphDjhRMfsmeM5dJQ65BkH8s1YU9hTkPemyAh10CMotlPpswa8GCPiKupnLeClPFvHA3LO7PWMU+qB89EKVoz9xjMAP5D2FMny6oG/PWqas0wK5gCFoGkCVedV4m7mvBNb3Vqsdw3UGZLf3ehokKMozhLfwgV+pUJDzujoA4GYq+ZrHAVLLlE6nM6awFmF+Y1BOMBSg1O3x9jK5xEsOm20ZAEV6KPzLto5b1OjnQ83WItWIPq5zmPUXKuip8zmRoJLsf4BxyRCJgwm7ViOHBfwSpSYy7bKuFUKytWg6qwD/UagOjRWifw+Z3E1QNOcBz8wdMCn13TLrEKtBRP3gnyX8kjRAI24W715DdW4agB/tQ0UruqBFUkHULTHcbH8YAu9NFC3owLSK1Yh0Chc+NoOXoCKcg/4bWQ+0sJ+XqD8hJpdFqSiE8eaXdy86PA62rAPMelhngKrKTZCRb3srbMdbA7RNk8PsdNTNZrbZiPLdESCgnx7GGkdS+uf0gr7hYOHqGhe3tLO923nQh/ayoe0ogP9zSeK3I28AB+LwKJ9cZzpJut0n96UZlOX391oS/OsGOoHYdCAGTOpVvIuY6VOBqnX3YZa4A+3jhvy0/fLZ81qPKF7wYEr+UvOCGh96W9rF3p1Xav6Nit1sXFlT6thBh1/gnjBJSAZCHi/UmTIzLRSypfRNNmTrTu/A2T378JelkL4a7Un24ndQrEAaO1LmCXw+jaQlnNBjXyeer7UBLqzxRWGm1Ud8PP8iSFUeHg9+lXN4XbA41RhHRkccxBTDlZprr8+pnNcBgY4hIswG+iXKS+XrsVHCMXsoncgkyqKWuMBCehjjDEZPUp4I8HKqkC6IROxyAdhUWJBlGblFFcIRu00KwUAspHzgqnvh8hyASq10Xkg/c06lxL63/jXyheK61W+WtUzUyRhnt63/cPPQZdDjcEO5RVkgpbjV9sLi6vOA0rAHBRguLj4TRfCEEt4mREOwzPa3yNaojnFyxJNDp+MrxiDuxFULuetwx+p+42d5hcc21MidYNZr7QLltFUr+7p97iDEmvG+n/vJC3+Lm4/afgRC3GjJGGCd5Gsm1CQzGnA0irpO3eZ+B56piKdszzf+CAJIvVO3tO7hAtfRBZfXkCc2JZlZY/HdMDzt6AWi84rusSG8bACmDIgNgM2brVn+cFstL5FwQugnvPKh61gHr59OODv5emOQBJSRGEwb7inmZro62e2jViMuA4htQi1srZOMTseJK/XA8Bm8Jg/35t5UWJOy+04oO6HEuvL6zlLpXItXz8TrnqSljkUuR6u5IHZQDGtHwSNbvW44XsldVTtfwNKAhy5YvoU3wwhLlPhqO1P1GpjYjewnj53bbDQsArEb/r0cJANIibOJcV5rYupiYREMwfBbgR9x79CYU0GLyDoWRP9YWvjLlGV/RJCWsT01KFFqrG9LcHBD2b2aAhfalqNx/EJ6NtPCs9C8h97MP9M6xZtYbjl7BdmW/QU90WoOJFjZ72UXu9FZiPkt+sgNDZzTs8mfRZ0OmJw5mMuS3VfOpH4Qmbelk27yOee91lLN2atiy+A6SBuw2n8iG/JXuhtrNNCWlhW2aHQDXd1r+NeNTNUJYpmQ" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373233, + "Value": "122697769864899223", + "GasLimit": 62472096, + "GasFeeCap": "1099999999", + "GasPremium": "130581", + "Method": 7, + "Params": "ghoADNpHWQeArJZ4yPeEDm8fNYa+hs79/Jx+kv04sxl7NxiKWu4MKrDR08o82uC6cWzsqcCe1UjAoF5YpXEZDkW7wRfRNkH9f5W7JnAyjZgPFnoSsgN0WWC6lvYPa8UQkzF9EBl00vNrFxRJaCfW86YJd4wS8iE6odP45W772RKUlibGnQAjmOBVB/so5T3e3hbO5HLUY6kQtT3JrLDoMR79wo8axE4vaIKb6bkDOZkhNZYsVJMqiYkEFQo0q9lw27ZeLaUMQQ6nkN2jYlUxFegLZhhK0BZh2jWzg+tvPDpdlRvKglkzZuqyTNYuo50kKz3TI066VGKpsrpKSGnJYkdPrpvNFbs2eRffJQHZ8Oyc8dr761xDrW/ATNCI9tcHgBqaToaqNLMGFOteIteQYJrmUY3PzkxSm+waReWbkZ18T8wkoxKaHq63Y2BYO6EK5pq2+HSjBh81q0S34o0wmurAU4QOL18t0kqRbav1NrahKxuBKzvBptNlJUaEJxr+1fiHZqo+OPzshOg4VCE0eA67fLTGWgDW53f3dj/CS8qYlGVTTqIp6l5jEJGihugQeweIUME3NdM3gK1iyVWghVieSnkKYPrK13FYi2GnFxWsodA6IU3lFZ51WJ0kyihnO4MOtw9FFP4jBS/Bg3PnNq7vyikz4KhIW5VtRESaZ+PjYypdVnjAh2TeK04KybZ17uJ0sx/D+1KpktISKDdf6n+g819z0Ua3r1R7d1YqZCuRqfvWt20QB+DXBFJ01f9DFvCU6TgDfZ/BiSdnE7dZLXdM9Xh1pNvXPY4Ad4bTR13YIUUfXZZ4UM2Lx0YgtWC291SBS8JO3+ogrMzLoB4t0epNPlgXJlOMwdm736tUJNK5GCphcvjk/Zopm5zX8iiewV7GLsbMeA7CFSeXpn9fBNJ8nM+6Ggqt6eOOEhuV+Xw0JlB8uQpUTLiGvoWYZ5GEHiTa/OHLLqVGgIvkJitIi4Cpl/bXqWWXy09tSuH5fEuNIF8bBx2fLKytZsxUjUJrlKI4Ve6QUpCPhbJ/RZzcREFO0CiY/BhmjCmxHzSBMjxg6kGO9IBcIv+sN2Z7OrBJljJb3XuSH3WlquJjLuLXaseRMrx/bUN2fUocwDCc1jW0+o/3RENhCXdgYFT6mtaVajgCg4xLscKWFqhv8C8fVAKB0CSYls/yg95MZOF5ZUNXetMTnaFifSVIXQWHxkLxTifWUWHYZq/OsXzyvvcxu4KLs66RfYKWyJPaCeXKb4vvUE8CLk1oQ8ZxjRu59m40OZ0RpqcUpIcEkET7VwoOnKclajQ3ask+Uv70VBO4wfj1+d/dMrgY6En+TdxDOXcaG/8l053xVObJlybGgJSiaLW4qKlsv7+8RU8/CwdpBcbznQfcqu8UFxzDIWSsW+Q+ZSVApc+Q7h3hFRWAcby60BEEjejpmmCE44DWHc9xA87MLoGFMpGyS9LWj5VWZ3IFoEskEy7i/wN4s88VAhhew6ngXbrfbT3p7T0i6MnWZqufL/r/PbwaFgw5AvSKLrFkqsnKYCg+Q78rkKh0FeHErKrkgkYEpTJNvIkMtv/CaaLO0FhRaUv4nORlPTAp7a/UswLm6eX2wSRqi+2UfCHDOOvH9caDTA4qOQtepl8wmRyVMcC5lV6BuLHYKdo9Pes7fiCb0rEsptUOESDwmsPUg5mfSLwHLN0gzv9PAqjr2DKChp2bT/W4YZtWPg8aIPGYdNizv4W1Ur8bgCPIleucjAHNjame1gXwL0aB7lhvvdsFbxYM+iPxp7TscAQVJZt7x+IhWUWbeqpHuU/lEusx92cLi/mKZ2sP8EQZiUZArUkF+XL14f7/nsG+i7X6wrxiHc1jsSj1pmh4gpTWe1325k+RmBelPZ2ZASkE5QbHkAF4DilAoN4bFU3ZOynYfEJUiXiajIlNYAjVCNNv7Z0WIHtUcQz7ybjoSudEmlIPPaW/6TsZ6zsx3AB+13wOCnC+Uh+El3hWjszelEkoT4qUdtJtM4VPLWy0yA43/7w3asr3Nb65coDGsDQNcVGenmNlbhwq/vklcYVBk6uxCFkA/mT104i9OiLOXlBi/Dd3/Cc4Q7MHB5pGOT+XF/V8v6I2fjw5mBFc67kdpVFpy31HHl/NalGvbIPhBlv9A8rj96Nz0ZLmDct8D1HvDQfWJ6RVYlJ8ahYDac2yCFvdzbVUoXfgN3oLAncFoBi32gBH2MQ92CH0ADnn12WOIVnVKDZC4Sn/vPlD1rSjprcxfjc1cfiuPi4+ySF2cpNBY55deY5YVySinqEgC7AE2cwYAv12+dm/ntcfNAgSo5KVC/QONbxvqw1jaAg78pbrxltSvkNsH5Lo60dUufOev1uAchYNjI4JnRBQgUn1oFtTVuaPpbsRIo4LEfApBxlEMjB2GURZ1SjHWMIS6Oaefu9qyjhtOJB7qNEahakUCibsMNIzQIYOgknCSqDKX7GDuu5kRN/dJPYAoFGCjtM5nqEkCOl624yZP8XaSUS/txo7U2Y20rDGggUrif0RjT7hPCi7XuaGxbpq9GMRfdumXzK8Ng3qZznwgYg0XIJ+" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373234, + "Value": "122695666052819139", + "GasLimit": 65087096, + "GasFeeCap": "1099999999", + "GasPremium": "130093", + "Method": 7, + "Params": "ghoADNfFWQeAqGhZKJTQSfc09CXayXhhVsnCrLxVtypJ7K/tkC4VxSM5MZfKNHHZeBx4mTRLftlxrI9pLHzLHXpSxD7jDOEmOzbAeKYUm+X+nZe6oLdN7rLu0IP6d7cSCnTn7mWI8fGCBWxaZZ8cW0HPejCxYzQltC5WwHtyEWJrM8bgG+AgvVli/AffzuxjXqWgmhrdZLzKgb5De+mmM6uARuJzlmLssi7MUY6EznZos9MX22pGkSetsoZ9e+dWCqOlTIgYvJe0rN6iW+Eoki5U078wY2KgDJ/CF272t40rD6W2I4Oj8ejt28rZlYbHKoQMpi6eVtxxsRy+rAFEwMj2RRxb7obRRwp0ktM3rmVYG+VNXVP+OA7Yp9dXA+ljoDMWa8On0RsKBcKXCx2ygpb06HfOPf1c9KnTm7FsbdwVo2BVdQdXHrurPHy7Xg4WxtBfBnJ1/DnjoD9V64fl/DIqxQXkPuVdDa3oiE7m3qBwG0/GKqSW90kDrtpzgcZlBGs2R8kj4KF3o6YRx39AtE4FghbB0AbHt1kU0IOjU0W8uza3gX5Z+Ci1vKRMF7D9VsbMbMM//5iui48j42YYYPRcWowY74r/mPPFC5U9XQImTE/yHv+6F2xpzG6yKIsweuOvioVQohDoCSDvjIK648wIO2tt2pDJLHclKrYWEeuAJBeGTDVnRIulNtv16MbXANZ+NPMcHCesiPqq1x5GTwnkwSeNOr8dHBnEb4Wpc5xwZdMCyt0csQwg5QUSofKG1TjXKFqOl6G9tq9h5an9ubMq7432W2/E/nJrRqH3mw19Ofp5RLJBSC4JlJR0yT4Zn1D9DG+BigvwoYY2zRJPiitDVCSMNu4EC4qIkik5NPc96Aq2x4An28W7IORXHiK9MQVBe5lx7g+aAQ/IZE/C5gQYv4UbI4v+VdHB/9OxA4tfn9q7YTT5Lby9pvIy6sKu8nZ8LUNoP64GklnF1hZdbY/yQBEmhHORvtVYKP6zxZVwD6yBF+gTYFp8zVP7ZG+GMukIJg4FgZ+EpxiFT4m2NXLvUulrTWT5suvwdA2cJYH0WEvEHXZmhNMWleJfGlMa/3xctW6w0S9jqSYGTexlqkDjWSiKZ/TyCcQt1CfhnqhXzJiOe2uhCxvDm7XpncrZL1ygQF2n8D91BiyqhzEccK7BCaOdZmG2f7Ikr0prpe4u8LMSKcXMLjFPc3t1i85+t9dgIBdTwRRZstYL4UyaTJ6YljSLAC0Skrgsdv6a6ahwPEb/X6TmSb2Z5JFujiDHBvg9o73OVur2hu1KHuGUy9wII4FF/M6zHSufEVnzpvSM6iSJIaMXxrUDhuq11TR/ZclY76dEu+FBteh62dz7vbuB3/lqqMnln6rWNhD2mMZFJkFossVqpCAGL0dVDXdepn7CsgTY4re3Fimplzu3TiJpWxBlNEmMQnrGa/hBavd94xIeRKW+zyji4dZsID/ZuXhlNxLGAfsorAjm86ABQdh/MfFyEvGIgValoFAv1X9Yckc2CchKDQE10GTTp+WuIWBHXtQot3f6pTJv2JyqXjWpXPog+HrI4ZKvx3PQX8PdHzjSuC3E+w2dCrXoxPxvvyMvh32mm/T3gmNAdSjZAjOoYCnnJ3b9dciSSVhx8ybsKOtlFDVvRzWi+lGVBOzSkt8btcSn05IZEbJasCBUYgVzK9Bm/1Y2b9+IkpvkJq0pEwRyIULTKUcxhohrX5U4WSfNBcRzS947lArBU7FSEt3gk1rCQOD2CNK70VQhxtCddj+AEKSWL2m/C4VCF5FU0QXwlwWNcTqJuCkhLNWX3kqGyA/wdYZE52UdPvwHVe4eJHNdPBqwnt7GIRYY8zUQBC7H2+2uwCiTocSnE2FhDMPbDFt6KiclBMd1lIcTp/9wTzIUgc0N42Cq5Q7HuRu1lSG3TL28B0i8Dw3e6xTTPbl1xPU6U4M2MwJXwXuCyTJ34HaPTrjxxwKVYOd4QK4I48kU3bFM6nn7iZ83UNGCq5U1KmtPedv1NLoQ0JKYkvJyTEQIQOATaR2SmK/lxrHU6/fF5StwKgh1uAm5qz7xu80s5ni9ijL04fbwGOMU9J/n+MwX0xA0KzcBv9KCKcJ+uVvWikKsASFapiY2o85TcUjg7GYXLJIpjQJmDbXp5v77uSoo6Lj2CATRyS6qamtRbCITZ4ZTwQD9FcukaAH3UI1Aot3tJ4CkelqQLQQ7Uy/dfbZ/GkRzVWw3D+JFI/3EM9hQct7hNQkFjorefhR8SrDqLd0dPegzwpdQrgYmJu1TjZBe4bU43M8TJdDYYWGDzUQZDndyIK0WrkpErtE63RcafMZsZp2/Gn7cEo/1GmLtx+QXx22DfaTKZ27LBs5Hv+AIOT0nXBiFkQD5QVyws0isbIQvo6OYQuiTf8EDPJv/zq9NwTjDF6r1CsXU2bFYrZfcnPmyY6pOCOJep7hP7f2lZIV8kVLczJuo5+fFXKAfX44vCXo5dSKT6w/Edcl7XsdeHr7IxKifqdZKtrjeovv7nr3UifEo6ManKfopDqalEa/z8i9nTrUu0X8O//X98o9bGcPfXn5o" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373235, + "Value": "122695449505459998", + "GasLimit": 70317096, + "GasFeeCap": "1099999999", + "GasPremium": "130215", + "Method": 7, + "Params": "ghoADN2MWQeAjhRl6jIoGrSIlI16xHakAWCdmosZpbxjiPsN2pjcarXjw9F7McSpkNANnsTXr88MojZwHergXxHnwg3+6F4+rK8lW1U2Scce995JoWF4narKN+uk18Iv2uG7nVD//uLdE7lRH34IFoFpV5h+6djM1sWnPIock15Pjf0BzKTf9OgQ6CH9wMkGyVR2kXi248/frQZy3Qb4DPoMxtO4Cd/+mf16EPmH43HAoMnpdT5EdaKInQE+Bz8uyTz+gQGNTio9tL4EAW8EIAgELj26/cd18/iztbng9jcpI+tXswZo8OBE2NwyvB0WXrBQ5yy+OO3tiBhGlOZE8h2Qoc7h4wBzx+j2DNqDQjNAp2J9F3e2XL04rdZgCm41J/MEmlUFTm+VEjK07lVgGwcWPXW/lF19FoSXRNLXcwD+bZxOIG6u+EdNCfHjGbBqilM2Redp4oz4k1fH4bGvyEtPzs8Bm7+bEm/XBxoLBJPi0caZIic7Tekv0ivFK//A+noBQUB8cnNHtt+tz79UhxbetbQPz1o0tY/zuefFG+a0bvYlLDbegsgCD1rZ8TIccO/eqH07g0JmjyC82+J+LJWMurL54BZL32IlRFmI2sEa6qmFAb8PWTPUF/1rcMxMxWmqzf+3QjWXDvPFvUx0HSLoogTbQ1+jTcHwcSljYSnFaUf9oPQVk2Es7h5EHiT9rC5+GfzrHwEDtI9BZuMJoidkkvJQyFnwjot4z8GWLEsKFbhCnpC3E6GSe1DWIP5pLaRSw+3kB2ALqsAlZzJjwxoeKdnPwZks1elew4rbc+J3NKS+Gx09T6C1vTEXxdgPnYRxASots3aetJRxCwzMrXSHjEjuQ+sjJrNqOIXAHCMpFDISMBgFb+H/pCe+nvoZwGYksg5wtIwdD+pmjc9DQug1wjQYIdVPrbHx/TfcZZkqBK/y/zFmlewqRsSrQHLyXY9IYBw/wTYYs6HCfOwRFMzx/daVeQwGpbzom7TyZaihr97GBjlMUggTcMRoumgEfhdfaLq54CG3o6435dIzL6CPcomviB61VmkT78b4YQgKj9XhGHpQV4n7ytE5mFuTV6B41NiSZyXxoQkScA+I+wfxNRinp1G65oCUh1DKTc7erQmXxvIy+r6J62uzVEfZDvh1+l07uqPoD9Cr/ziUYr2iZ1w+427XSwSeL4a4o0Dz4/nrhvLgsWorWj/e5KIQI0hElw0Hiu23j+Ktjy2ZGeF4BV3yETMJvqgq5KsMLG/Z7YfOpQDib5FXENS8uxwb8INSLzbU+gR2ixN8tabO0rVzVxKfakR1frd0SAhx4wqr8eg2fcJQa5T8Xx0seDoiDu1iLWHNaelJoe01euDlwDqh5LRa6oXkXs7Y4A9evU7h8D1CvM8fyJkzU96zDlWIVWPsnAr29mQhDSiL3jRShEPbYOcKeTtzoSs7kBdzkNcPWJ/nAr37p8lJvrwK7HU0cZebXdwb0VTaoPfrBBNZgDNWzUFH++1ahyLTtFit6Ql8FMHwTnw5k0HeTHq9rpzaPsI+l7DPLCTxraYOaRDB8WqOw0IqID/U3jh9NwV3obtebnNFMG4M3h3CuXsHyjOzWd5R/HSyegiPt9gK/kB8SYQPiRRF5PYgCjE9/08s7Vnf7YFW2SD4jCYkURGLqeICBw1yb7hN/v5CGDImpcFLNkxOpVwpINC5AAjAJ7WTgKgbPOv7VEtdCLkO2UrpjnZbvnXmdj7ibd1thnRPBbHZ/1l9p6aIU67F6VhWyo1wsRhExKYv5H1+6x43bQhp1jVKZ5eB0PRRkI3/q7W2KbRpiTW2rQ9D5TGuZbc9K4d5D91MTDdZeMlI4tYHM/mrG7cWQR/Syv4Qv3w5q2bkNz6H4+hijgFwEY9QPFCn5XE4PhfZvHOX+r/CvBwrf+pbpShTGF/49XbwLJctDoObhiFGcwkZeSPMZRnagH3+SrRhEQB86nmQG/bPoufWtjXwenmfcnPaPZad4bCOj4gsFltmDyVxn704CMNZFavnOioRoh1hKO9932GD7sQwdkYmkssMyqPGAAb0IQ+lrLf3eggDNnV5UG1YklxmZaCSCtGNwxyH4tjGPVWNzrDcswh/9xMh6wbG0e+8sYCni9TlDkrUFICLm5hoMoW8Jsq7ar8H5zrEi+WG7ipHeuxS5mwfsCxoxBaYCuoUQ+F0CIl5+l65gqxerXYM/9SbE3lSdxSBQImniiZ953cjb5906BMlO8ggMLu/nirdQLeJtqFqqf+c6sMRItn+0U3pORUHNPeAwxay0Lwsj0efvJNibcotZWqxbIk1itiSzTYIoAYHdaNA249d6aFqwxTeUp2ElCOGB7dYaMadUxr6Nx9STg4DgVrgyWAY98Z+YE9aoKmcRBqVQzjC+Q1wGPebBOtnwdhg268g/K3z/sWI5qM5Lo6eqhWnQYlT5BCQtf9lDH29etMfPE740TJvfFkqHgon/igUcB5Bda/j2kxvAAF39EunGuqchrx45izFPTjRiiPK0J2rlM4NaTeMpztjoY5FaaYF9euf3gCXQ3kcpSObePUCUvn1fp1YfVxr1cXn" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373236, + "Value": "122695456350969745", + "GasLimit": 70317096, + "GasFeeCap": "1099999999", + "GasPremium": "130089", + "Method": 7, + "Params": "ghoADN1pWQeAiv47kiOgLD7IF7RzBSVfwwBCw5c+TTg5thAHhhHa1Z7UtuPqdjPYx2JBMfXi/cHmjzmtAgZpMNNb1QPxZAJmjuy9vetE0AdY0TWpRzn9FyuEdLmD5mN3Q8QSMGlIssPDB+5l0fCAPVrx9Y7fNZuQOqrvZ88yJ18qe/at5qRxtBHtX9f7z3Kesovt4wb9n7zIh1i2oTLWjOahEyXU19GkUFkzrCT/tQG0yqXhxZK0thcZjh2S4PQaLd7vrwvAv8xsgEzjDXkA0QPMMeEmE86wh+/2rEfVnRQhLg8F7OZVgEm82n090UFbVXVD1CFUY6T5iYNsNh/EJ4yfAibJINUqQuaD+q1Nb7egfaqiYk4ur4cPAS68761CKrZCDwd7qWF4DqZbH5wtNn2foinTZtK15jOiEVmZUfcZpRqlnED2MIw2iXUqLBnMWq09v7k3VNP7iCG4FrRq7/8IkALwlFBNmys+UCNTU9yb7R4n/Vn6hk46GQLX081I5D1P1/fSvc2/rR0o3A2MBpCUIarScBCqvTYszjRS9YwnBNCcVJxaea5XT7YTYiPQog2Tn/UW78GKggw5SWWmXtlbcHe08hnS8QcKdn0FuKjm51MUS8QokDfBQMEiFk3pM1Ysjsff7n4LFFB7V68GG5D5rk9za3mOGkVTHzGXmEzT6uk/hrbzsM7UOc1WtxyAw5vGIZO1Q/VSlZABSfnFhSRmBHBlZ8QplBMyOAn7xro5tWpt2L7cW69WPcKVvuqZv5qDBThVRK5bpHkUCTUNRhks7oQpsAr/vFa9EXnQsD6JkghdUhwrbR/AMCodb0dSSCvZPfc01PfitSRA7upDmv2LKyaZcH/F6sd1+2Wf/u1JEXq+HU34rnJ5nzpLYPBFkOihQSCx+1y6D5A+LtiQOO0+mTh51tX/6s/X06XmVlCOtffeQJJeUKKY3oggehu5x6kaQlIw+a66lUZFLAxctcrwS/1+FnsStvLZE146gH/SEefAj21q8OMkcQhdUNxTo9+2iKgk7nYzsAhMYovQrke6+fGO5j7wGxby5mGARTzTY0YkGdAVLaG2itPmS57KXUmSX+JvfGjDhx3VetVHs6pxLHoThI4UlKA7GqX6oR66fLMWtqeH9m4Ud6DfHqiWiDLQ3m/s06DeElyViS2juNOBKzBhIDxCBcG1PRkcmhdWf5K/pabN6nG9iV/Rh6fKNf5mxy9zefW4gL40JHD5fMcDSQU7fBftPUS7SAE4UPLgJ2vlGvojWW0jdNzVVTNk4p6Gb6JlOBz8lLIGbHkdQsSK29xgAcaVUNeBIj7p3cjsXBVaLBjn+tOjfC2FcolhEX93Uh8VGF3ljK3iZ8BlrInEQrO6Zvg/YGByXMg2N/L9Mg+EjTjAoQ2gw85v2BvsvQVJNcpxFdFlARMRuR8N26/+/95w7IPB9JtejirGq7InYqg1EG87tF/6248TnKCzOcDzITHQA1uygpX3vTlkvRsVh/GosPdo37N5QOhdMGIGas80q4Xzb1l0YpGZjfQzmUbgNsjoz2MHkzswqcT0hMuczzQkfJAFhM8cqpcwLrxtIuYEA1fkgcp+q27FuFSCNkOEa8D/3Aklp63tpe5tyVXJXN1rAW3/IYNRSai/KdYmrtny5Z/FZKYxX3BWAosqmgRaX3xDQE73C8AaWhJclfRiOP8f2cEVh7T5BZUpOxtZQVAfPNuoTv2HOqdWrF6pRPyUQZb2BfcMpCe2IhnrHBvXXTl7Bv6An6T2a8WbCFPhAOU52zKuglx5LR9M95u72BVoh5bvxkQVoby/kv7JD1sSreMnHzw5YkIEyNlemthpp3Xgwdf0gzYcl30ykZ3a6ebrAEBHZ+7Jjc1FRHZpWaB9xdymU6gnBonGH0QFqbT7UjGrwObXEyE+iiKzj9d3orlDlVfP1W0oAXC4bjDXLIpJeH0unODH08XHjSQOT08+n8MsrsYowLb+kD2VoNnCqudGUG6nPsMRjbxBBvvZb0Vli8SEi0CVZQ0iVSgV2E/x23L6f6v8gAr+eK2DZZ69XdX5N+dmHRRDp23yzl9Sl3jBrWNHW7f+6WZg8OadKHuPffpwiSfbXdbOm+iVFyWrVRM0YHFT5kt3tzEE+JLf0qbLyVKcs7IR0iMLqDm9N96SqySlqe+v2Dr1clqGMJTQ0mpIvlk3ZQaHEapIDBxkzqPf0guC/JUlGSERXo/ru2G2Xbh5WffqqQrtidF2vBDrZGdS4IgHGB8Lp+6dskAxaFD+uMk73Ztch4cntene5DK4Sv2CefuWrxOjWs/jW/beIwWxJaklfFz9rYierr7o0JrEC/7fmd7EnltdAEL4nIomcFmZ/pVTZEYmw60yqR3OyIEHlDOhf/brqigui4koG8Vq09lxZfsTEHOsYD8i+wqp8BnfmebXuv5vbeMfTQ1rdI9ZUxijl9SJC17/Sz6ov+BN2UhV0KBGi8KmiDE+IgdUW/Uby2a8cuNS/3LS6oI0TqSndVCiP7RZoRYrleRk+xhlKq+hI0HhNXs6eAMZCfCGyOBJnGoakK53sp2iUsIhaiUdUHZvDRU7" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373237, + "Value": "122696242323970072", + "GasLimit": 54895846, + "GasFeeCap": "1099999999", + "GasPremium": "129495", + "Method": 7, + "Params": "ghoADNa3WQeArYosEiBZTVkDfAtdz86WKtHyUsXfGnvdSBc7AKOXecmHLpOHymNp80Z2TEDQ0bt0g2P6uanXL25NTdqwhTiSwi/BRRq85Uyz6eTRyVlRNEHw0RwtybHBBRXNQqsVV9PGCXQjDzfhLpHU4BRGzjF7vVkh7URYsQJbuO5/vUwacY4RbphYX4blf6+LqEHUYQlhrzmjI8lJXsdi7lMXDfT4HnxkDXT4XCIMdLkpTSV6GUTcL8r4nCUC71hm8d0O7MTeoeItP3bZtAZ4/m0Wgg0Q+9/cVgt6f3OJi56Hs/QrxRlitaEQ13+IXzcomBRcOolAsVllLWhKF/W3IJXlSfOK7MxXyB3tLPuQ4d/FhIWtOUuqD8QdrSeDxaqaY6J4oPH6CYHsk80bKcVx2qOAlmKjhhEEsObWG6h5YAx/sl+MOJDvfJmz8wwZMQoLhs/2lo/AlAUvK80xhzU/1KxV6/6rSqTLH/+/sZk2BNw02VR9ZdXG+TGlxSnaPrLvJoym8ScGiVcm/zgdrg6wkPpLa0vir5AowjEvA0ECOIp5ZGZhCoL8ZKmo+p7KkO0GEjT5xdMXjGfNbR4UrC6VmvhRiNfmwku5XczF0IClgEuO6bE2wKJxwBSOy+bXqgJhiUfOE8ydBLecLZr8+UYgLjM1bqLNJDlYm28CFQuK7Siu0Lk3XryItNAC/27HhOjcWCEWyKHOtDC5foLEmUiOCyNZgO1qP/Yf9UTwQPne92m/njnUcEaHduKBu0R38QvjOh924uPboWvFgkjy3vFj/Uk/xdacYDAjklVkVCw7GlQCQ85EfkwYBF63iZJT/Hg9I9CEoUOBrC2a8N9fSSOdLVcBPlUTfPYalTlNw/2oVRkl37LMvrIaB8wopbK7VW1GlaIFq6kJC/WjFv3U2iwjtp2DMn4lyGo2ZiqF9dhmBwZ0Tevc5Rq/TkQvlTmhxOkxOOOzBRw4g3HMKjkOQDWlYdzo2WuvzG/RijQeQmdf1lv5ij474ljnQXtSHs2Fd2kAj27PkX9bgO8z1+fUUeVm4HVxGnP96mdqfKxF2b1PT7h8KkupS6jYc+AxVXHGl2OFCpKdiJDig1BABbzMikmSbDlz6ackd9wk1SjoC89u/fIvTWqcOilj0pZPDIYTaNiG8iQk1vBMBWm/2Lcm417oD7PExKBIMFI4Oj1aQnVyBKF0BVdnShVrt1vXV/FOP0tAWWt6UZwHlBjwuEJGh+li/VeX0fPE495i/QnLHHJjzAqN3xzW0SC4i+xcEGH2+9S6oNwQDxqao33BH0JYblD3e1rBgmrujApc/jxzQIJPocoAsNngzLr9nSrLWflP4s853zWsCT+RtW1sB5vdb2JAfNRN0hVUtaDbmc+Honqp5KXn3+ju45QBeb2jo9Kj2oIjSY3uzBw2D9YOhNo53u2k2yEI5DP9mYo9XaEgVHRdUhigSdzWwjzKhaGD5tHTHwBVL5d/5kidkLNaquks0uWNeC9jfpEh/xUe0oRsdNpcFESWpHIVI7fZzkCMWEuT0csQrYfYJQAXqTtJt16d/BWeoX/ZPROgtqJzGSrO/N9sYNVTpD0WH/hITp586Vj/S1O6P6nhgKuPrPlLyCvwZZEhvrL5XZbSDL5L8umNMSAdkUaXhJ8olHle25Lzsp618U1BlIRHRG7eCELguCW7h4/5D1WFYCQKv3Nr+xa9KlS/LCgbS3IslmG7Y3KWdrTFUJi9TNawrkcSsL39nBeUUa46dyfLdb9dEFy3BaAwP++5oBz+IAog2j8euA1PYmY6Ssht3myMqhZIkXHsFtwaqeymO12d2OUBHbVz5xqzFHIEsGLk1FZ0yWw+PiB2xzEooVzk14t/2JmcsmE39iF44CeupHO5S2p0BZHrdbYXtjeFKLZ+kvlX45bL/lAQS6IykcFRbd0coOAPEto81iDGEAyo5L5ONqpTH1F7tm9hw+eXfbfViNIKo1IiNbW3/JuVX+gfl7FbaGhZjhRVXH+gkxzXlLakkycU6GzOO/9TbZCJBdS+YnT6z+bbXTJ8vGblSX5q1tWuFw9qs03xBkw6WSx+CSg1z4BKEO8jIJb8djic8OrXhB6HTPqm9MrPwkN/l8+ZrOytKgiasTpHcGLTkKfbfEK2eXNpI4UQOBYkvi+aRgNEyzqEfs4uiXPuNQRzrFhFsQDh4usKBulm56bSxsW9/Z/WWTT8Lcc/wGAbF7zeB99VQLX1BL9it3VC1VYtlUALTLoDOMkJr5aDSQprgcUKb1G088XnuUeU0nbdXBiyyS8tR5vpBaOMV4wBe7mkOQ7ZwDs+K1HDsYVvJbik7dXOZr9wLN+7/9NT0rlzWxx7+X+ZOBSeiwurdgA+GxEQFI7tBsaGXZKAplxH5v/GNljwDl6ZXfOBXOlO910TcM+Rk5GEonqaOy2RDplO2E//JoVpGjArrH+4CGEW0ADbFCsywSHPY3Oy6zbkVzOWCziwvNb2oRdQsFxfgm/Ya3yVzXVEG1pv9Yrxh/irunBAZBjBN6WshXGAI7ARwaVzCwwvoZjWfKxjzAJjhZe0fgMOIoMQiUCGJHEf" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373238, + "Value": "122696242323970072", + "GasLimit": 57416793, + "GasFeeCap": "1099999999", + "GasPremium": "130037", + "Method": 7, + "Params": "ghoADN4rWQeAr7ITO5sIL/cf9lEnBY75Zl3UEMnWgAHh0TIGNszkFJxAYAsH7fvaoXyTBC22SUgDhOuFv69Ly0drfUYnCDbei96O395/FUMsk17hBkcoCV8UyZ0qKMQZunzV978YtpzfEd/53VqXlrO9DhqVg1nB6bdId0UGGTtRbalO1i90IV6qB9l1/kA35Srxcdre1YJVmRDGahYym6BPgiRTwjDuumpgQtBLCbPFhb5ZVdfcE5WJrAw3qT99PeFaLhrptdL2mb/ZPupq6nL856poGKidfD9pHtqjdqrvtfR1OUfIirloE21SoJ6y6PwZDxpqFIjAiKO1XP8RSOGRW7NPlasaEkP2GwjqKLTsWG0RrQ5SKnCHQSG3rMXJv7GFOqISOkt4CcsXauYku3QleflLf8CwcdVJBItX8PW2eBeUYcc8V7jjAUSW/BvUGJV9vzP73LGJjGW8A45vj12JKiHwzLJQFzaMNBt94ddXvY7sJqukFjsgAdxBfzmiyMYw4PX4UtrssdxfGBwHrDBgZUywm2yRynGqlKzvG1caxngkKMQ63J+WPKy2o7st+IH0BIiPkYV4i8mZ65RGm8q2ffsNUBC0zwUpHGpNHkWQBcw/KNssvsPG0Vx95ehRR1DOZWuCwQItDIZAzsApxsLD2/czTwI6XA+H+PWtxSrQCkE7mRv1h35VxaqiJClwMf0NrwTXw+zLrW22LODvSbJSR/or0mupIkOj/SEmIwwQcIAX54hJhj89DvoUBqzF55IITIBMfDQfrWYnGE7MGOP0ZZYXd9poD7PFyi5apr2fZyJyre4CM6e2xfVREDK/2oi7r9ujY6gPjS2iLJ3eeSRvZIoNmmOtktzWRseSQdjtLXwt5f4pqhdJqDGdpe/J+6Qk79gZtBU6AKWL4fV2n0/a4l8bAKbavitFCCGzKY4npNqrVuGU4m2ypyXxKUBJswL3GOdJaVsjhkofARp9kpWMIZ4Hh68GDliDx0pd+MSDFhbYyHS+KzWqKsesAhIP/PE/R9j5EVeMprAAmZJrePPdvmvusjvWYBJ0jw8Ez+JJgvRSEQ9WsyqyuEA+R0kuSzxt+eI9bDxJmLUWm2EZAdQmOc8ls9UbXPxKl5Esc3W4whFZVJLKFH+bld+YGcK82R0L8CmkXahWD4O8KOXRtcb6UMLmkSKhZLQrI2VMMes4IwQuwM2/0Sd71C+hwp4HztY7Fog97iMotZWIT6lEqK+tBg3CswHAlh0g+8fzsJLY35yltNpHmxHGJiUsXdCiWc+6XKninX8Oj9ymZAgQvzrM1DIjM8S9jRV7bVunsXUSvWYpeR/HgjpS/WfMIwgOA7jUK0to3b+mj6M+8wDiK3cOPZRkfpfnuhi7cY46xkroBaSsiGaxz61L/fCLlicnkEl8eN5Y9LPEDAkD7GIn/b5gad076LUMyErxKhKGIGpQqSpVjEyTkSaJdAoNiScqxjbVHUQfjrsZua+WAHXxJJwuOs54HI9iDvE7coBhuUJFXo5o8bZoVlOuIuXky34auU71jm8a42SHg/qp7GOfw2GlN0sfBCy1M+VJKpcnah/LINp60j5hhJenEMFq6oLFAgLM1RWkYy/YuCRpPG3jkMyZk9NrngMSIjBmYbEjE+gq8mUZHsXVslY8TZksIMaIlLGr5rXXYjGuCgQ/2EYzVkaykLUai9mnnxz3Hfr2uKm3BujjH5pBkJJ7x2qLWUaIF2+jtam8peFbjc8N+wRPAq2bM4aTlclzHY7Xir7mqAsMFQ99CPCeO4tv+KxPcsM2sCFXndYcMSJJk1DnQZ+otXB++qjsS41yCRidKhDzRAPRdX2Xa5CtBx4CGGE9clu/CSp2m55hjaMlrz5K4yEdWZqgypq5f8amUuXXLGvoQrqb00Yz37HMmc8iQWqba7FyiPQFi/75xrKgFQoVnJsXDVg1fD5M5hEDlaOkhfJytoUVXhdLpUq22aXSzpiaJcvJpp6BXzHNVgX1s1df4SZT0sIVSg7tD29ZK1zmyBj+a+W1jOxmOLxpWlx1EEwbGXLMZq75z4xlh3EupuayPT+Gcsy+WevColVHVOleT2sZkQWeaBIOjn0/oFvTV2Dof43IQ8EBWUD2zhm1i2m4nwXvHfWEPs5xFOAr2NMREDlFJqyjroMFaV5ll1mJcGMzxyjm44Zo+83TYIfaDbHRHWSn3HLL/R6VxFAGyUyd7ES94ERy98WepxcD1NPOJpxnvkrxVpmkIYSAHQlPq3H0zvHL/WCyDk1M53Ui+Pse920oapZnmWA6XB6FfcWCCokQ8EUlsFdmyz2xLMZmhR0et9zBRNHK2ah9lYMmkJAhVYzZM5KUxPS4pGJo34zAQtGpjLO2xqkkGbzVnVkfpW6DjT5nWELGojeHO5D85IpNOdGZxi4waBVhwZ9VcOj8dvzylt0prgQhdNRO0pUQDkMnX48EOyaMPNBpAuQ2/xdA0a7u+LcBNiF+WgiG3noC/PbZZ/arLShrdf+dKhJyoLBKmsotg9or1NGKe+qX6ps1Mba7XBeUaDAPt5nosdiWfwe/JNA6uWDW9/Q5Req1" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373239, + "Value": "122696242534250876", + "GasLimit": 60125846, + "GasFeeCap": "1099999999", + "GasPremium": "129580", + "Method": 7, + "Params": "ghoADNd+WQeAtGyAW1qo8JCYg8S8MQI1YdwtZkIRHh/+IGxoXwIHL/apKRFAKfInMIqP1UduTxW6qj1w6+mmbfR126LhIJTqH4Zt8cx69Vshds59R764Mr0Wu/tEO0PwRpbT8ryJnWWqFUG71nVDi28wX7HsuRjso3vqUPx+apDTnMH+r1jV+yJB/lOXcYywvUaOpdSCBbDSs4dFPd7kWcgyHoNAyGzGvGLfkMi4HtKFDaMq/Yy80qkopZ2OGQ20HCvP7WUf4HDkt9KCXxiDjMTCauwAgdcdMRL6lUY0gxxpkEKWJ04tHAoSTpM9hJ8JvdDkmWNNKf2Bl+OREPcn3jHKJWGzBlY8ECqkdSZQWo51uNrmFvIKOFmEopjaEkrxRqn0Oyr+BAaeDH76nqafGmtayNat4xf2k9ccKa81oRlho7jXW6OlrlvMpPDtlKo0PM4NoGVsvVNOqBlc+DyQho8Jvgo25grcMV+68Sq8sxi2QvsrrK9ew2E6n/Q+mKbdmwmnVSPI08i/kkc+YUJG/5CWjyetXge1GOuVopraLGmmVKDaivChGTV1u5xig9sDWjdI1zOmNUXairs1KDkXr+wqjJdmiYeKbPXXRYJ0/veZeHLXMJENv3DQQeryJLTPP3H9JWpE9X/dDSR3QWZpSVXIsucQ8zqO6fBHzc446ewPdb4pTYNSJLVVYl44mCpBI8ucsyZweP2ptODdodGwQt+M1z1sIUip6uZxjqGbRVntJVMFbPFsGKSi+H2W9FO3LVxdfqEo6VjBpsmg7IfhSwTVZ9n0Zfk0sWFhlbEIJ7TbHnkCFXLiXeIv2TWPUPS7/KC5om0uvHMtlTnZeTQowNu6STHuKxExS2+g43QiAjuwtSupVevS5PQq3+8hiTPWPah4D0RlKoK3DYJTzEjQdZdqqLmn1Gz5cU9QKhW58gst7CdIzUdm+VN+W9JTiDsmOuW6wkrF2bX3ljA16APmBQpPNbY1qvLma/8oLSXuDhuUpbUBrk2gtkGiqhpqpkjowYrYlrYZ4AYjuRxqliNgja0umYFsETJiAKcu/PwKFuGKtOnrbkBBmMIg99LccDy7GMMkAcfQp6X1tzajZupp1X2e2cZcCwuULhV/Ksr4EVSxDuoWFOhxN4SXJb7xRXu7g6HYI10L/inPFsSUKSeWRxv1qiRKSXnJHkIsEe/XD/G4uiqY/r+dPPTqVkhAEhNV20igBi973EAckpfz6zBJh5G8p3m12YGXPesI7vKnumHu39YWXduRUOlyDv44iwokvHh34djqGjNMoz/vJX/+dnOrW5MXRpLQcc0mxbAlx3HF7aYyMpdGbSLX7M3jgUVKUWujwJvtXiyvouWODzAhiqEMxQv7Kdq80F0ynRotXm+gL9KOs4CFj1w4H39Rqis2+UbbwtiGSBg3FyLdm4TOMWtnaDdsnznsm9ngNo3C5FR4BHFyQaKR6h1TG3AXq+z/uRPlICnJSTxwjhGAcEutAO/hovSObTjjG+NaV0EDac+J0IB2skATtPq1A+kzyRkg6PcIcM3bg6RgqEFKNczPYkmfrhMf7PQ02RpB4iLwazH5grwQyjEmPlxvEkmuJntvuhOZlMzMjlpQjnUmWzxZgJglwVZgNivnuqvhiOsUc/bxOx5OcvNal4Bdma8U4eyD+xiKQkrftnnrAvKAUgG1O7vzwwNKVEdpZzl89JiO6r0pGYM/w0vrtHRR8kHXs2OldtL5+b6GDdSrmKIMZ2QtUZVTLV48SXbaFDL9Aezh+fYVZuvUseRQpWTkGRett568rnl37WhmmawhqmUb3fN89Dn7ZOwuc5TAApmMN6TtnFx1mcXMX+xoXICMNZhQUXs3VLmV3QXC8fRPr3OGwZY69NIzxWr2e0l/rTnghDX08u1Oz+mLABZA/Dbi5bKgN69085+3+eoKEomgF7A2Oyy03vLnmO/e1ZfgUdqyFAToPQMmfQR7atR24OEy9e/dSSr4wtohj+IBksERtghkTRsKEpk9tCDp0R3S5AIPlp47Tu126ABxQ3xa+wylkYjzR2myBCTYZNkzTks6kVZh63tlZHkOqH7/f9UKk/ACG+jGEtoTzmPo+gHNJg0gOH8j7sIyTBBErazR7Zd/i57+ak02mZVPAMqA6SNIvTbCMxq+txv41rSWeuwv8Cbw5RwZ8DR4UKBse+eLp4ZJCk3vfhztuCa4rF4o9KLTvXrlWzTb4ZbfVWcY+2yLCmVXkYJ9hUHRxg7ywplo5lAUr5+IzWLPv+3N+g+rOJxNkn5lffaYVuGtUkkQ0ZOvQEecPl+9hnaRXZvL1j65S++VhPueEDOXo8drad+egVi1YXN5NKi81G/LZVCNQ2EcwVgo1e9oOV9uNY4LI539drlxtWMEWK+2ZW5dr+ccBBiCgC7VPo5vqP/UQEFhOededmwpGWxFtGETNe9R2krjjzHuBwhVwV9X4h7EvZ3fKWyPFRBDD3tCc2CQzWsjN65kD65ECgRpO4ZB1yhkH47ZiQUkkpxTAtUgrsE8HlhCzi4Wk0y2qdHoGl3rhFxO8cFcn3qby9Vo+byHavfaNoVGCpJ5" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373240, + "Value": "121191532823564220", + "GasLimit": 49270421, + "GasFeeCap": "1099999999", + "GasPremium": "131042", + "Method": 6, + "Params": "igMaAAzkN9gqWCkAAYLiA4HoAiBGmuuhbRnWvt2fjHVahensPxPLCxFS1t8GmvpDp7n8PhoAA6+6gBoAC9BZ9AAAAA==" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373241, + "Value": "122696242323970072", + "GasLimit": 57510846, + "GasFeeCap": "1099999999", + "GasPremium": "131385", + "Method": 7, + "Params": "ghoADNnbWQeAkltG1WCh1aves2uF1mCsbNHKsu7FMMmn7QLiVsXAht23ZYQvYQq9fF49fa2XCjM4i0NV+xMwFVlpn0tZkUcw56Sp4r7acUz4GPGE0oRB+Iun9+43i2MrW/4tr+PLEFYLBO+42rPFEnf3YN7SFr3PM4tO17FW/JLBPZ6GHEhLxwzbu5/veb9pidQrIv/xC4dxufxByi0m5MW00ecklHxyebJrQhoOoUr5Rj0cvBAoNFg+27BmcC1vAyLYMTtjBzT/uDaFYsBkb3kgCOY8/fJ+UKhdTN+pHLn7Un97Tmp0kql8cNFm+d5O2mN4mIYT/BFGlyLZTwfVHZc8Oaz1YYZJYg43LfnYJA879UeWinm6MI6hUU1VidVr4l0UZTAY3aMrAJxQTHh62TbXNJUuddN/Hcg/z2t/vc3svMfqDPTgx3Vl0VKwB3WR5U12c+h1arpRtMJwJr6VtFKRg2CvC3T1RoT+JItcedCRFdB4cX/25WYf8cls/4zJDjGjb1ZynjZjsivxW+M53/0JWKh8upcafOzk/jAqATBz+PHrw9CZKH7O69avOtEqu5Y/+3GXJ3LvrZNcLzNZc69vbX0IoH1tmEF/9/LrsIOoGPwCHCRpV0bm5X4uAvtKEnBxENF63E0RCQg++AdJ+NHUutEDAFxKPlKTuGx6vJyszzRzyc9buOCLMSQiRPWgGgQDAzP0ThZsiogNjztBWzG9aSqbRMdKC3CWI/A1qjPW5Axw4rHEgJittlv8Ok4/iveZw44gwDpTr/k8NF4TV35NHQnzVdduO/STOGiOgVWDBImQalXedzcZ0YQV346wF8HDL0/trBHmoWzFpRkNPYzctmUfPL/jpCPsAizJTtgHt/3F8y7LBryZZKcnmz3zs5cPcNTqexUQEsUABe8Q0LSK8OW9RQecCluiIYQUovrQygV1lByxLTvLbF5xSfzcwY2dwBXU7R2Tg1LU3c2ekrGyg3sH2s4ju4XGbWwcWktxsBoADscPrII12kiH2/t8rNCjaQcH5YtmrAI3L4VBtbgema1vVRhwUdbWkFi++ChtmbroVqNztVtA9cs2Qw4jjZDoQw3yBu+dg4oBjxzgSKgufn4oJV21uy9pxMNdIy1XGlDXxuhAlqTejd/8CikcFxqNkVpDBLTXDetavDiLJHUjzttDrpBhWZpQrL8EGeqd4MtNn6dhnosTFe22uSKx/fj/YAAWqn9VrOq4P9LI8Ji/VM03XaLR994wTo4ZZePM2kMHbqHa/ekEUiKUVcpYOO2JYuSRdnWjhM0RsK5+iG4bQgjbWshHIM8U5DEqb/KoOz6QoOmvjlNaXwFTSwsXLyUraGhbbHp0iRbmG0+iEvdnhtylgcYRkcUNlhbe+gE6LA9BiL2jPb6K3QoI50TrNXpkLAhpni1hAfDonB1Pn+CNlCJkDcKIk7v9AlGixK2z8oGqcczlw8h8zvcvDJGiRHzdpc2akL12sGkbgk9EDJUi8T5oRCbEnJbJzpfLZRbw+36+jmQhlTY1AJQciWnw9ELgKVBiN08Mt2J6LKDO+L0VACq9uwNH+TllojGPGEg7aJQKBrZ9vWIsJqnDXAfjjoccwtmBWTolldHm+qwLWfYqniVFKYRq3YGGlgXivNCgMDfSRlNZNB91rfwebvm818FLkfep0eufEGc8HVC7KqI+0m8KKdSMrz0tYKWvcWzYqvR01EcPo/3fvlBM2ajxQssVrE6wFLeNpxrMpzlkeTjQAe8q2kveI0nxcGYd7AuGKHykJJGsvqEJZIiT7WbDk8qogTF+tan/lj0rNR9VbTjLvMfKWoUzb4YiJIw6NKqyWe5vlOm/9nnTaC0Td8aKRSSpFJX0flVPsl27YLPXjrC8Tbc4PwSNVKTocC4xrIwG/gDjYX1JukQbIqQcMv74rqhLLkMXXUJGAY/Y56hmklvwy9kpm8utluK5qx92YERxrMju7HhVLxngGDF92JdPBTTSKWfAVst9gCWy7ZU5raDjk+LYE//NHQx2x+y0jG7wS5mklkCq6gU26Xke6IE/k03y6vSXIJoamLHGbtkpVKyP/NNnsOFTSGLtdccKdV5Izbo0P44y++rbD0pZMNFvXK/bUk2OT4bcpwPvZ51vVzU8TmBkGKkLUQn4JDMw/mkOK/twFNxpaAXicV2cXG1ry7x5EE5mCQw/DeZ70Qkt/w9TayMZUaG913SRdLvbLeXAiOyvryN2A03pPdUCOaZnUSOF72Kbtd33hCIvN+VrRs4K8zQJ2QxZPTq+FUsG4me7MDpiMx5sEltRlnpQ9L7moy2ULvnyTZoLgttNOTlUNT0CbzG0/XigWHFsZ7N1m9Vq7TqJgoCgl4pEycQdg792yVq3OVgMfUZqp3BLaMByLQapwF2C08tpIpP7KhEg4kew7gy/8NhoagCa6PICU0FiwhXJ1quopAtAB6EUx/210N/59Byu90ixGm6qbHyzIXdAIXRYWPLT1Sg4wnkLPJOUJGbleMHJCR7no9o6IyQaDO+ewGQEmQ6fxpGQiW/ue1rDKbHHuDTSBvWdc699/oax+woWkWFtsWG9" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373242, + "Value": "122697234375112311", + "GasLimit": 62646793, + "GasFeeCap": "1099999999", + "GasPremium": "129719", + "Method": 7, + "Params": "ghoADNqoWQeAt/sv56Pd5oF45oOklsCWDkY8+6hH9MPw+UbvBIFw1pjVD/az89p5rQlZHSKxfnfbrNVt46jOjTsfF79a+aPLhCAj2vPkhrmZ/kPlPQ7nirOITauxIk+h2iFoyXcEn0tpAcvQsjnyApdnkGWd6O9lnppLUNtxLJsamqhNlbqFO+b4whNdX6wAezK84hF/5Gp1oMoVoSaP35LExLaZdOEvr5/sVwes9aIzkB5lgI2C6sOPtrnKC/TTmDecaDprbLYmtv3+GsMouIvxtg5PaIEQ/4cF8NEVfe0E2j2HTEoYl/bGGYcA9BZr/At3zJDNqlHpiYZ+nErqfP/VZ7YwZmLNwplxb2/hzfJsCmmcuQIsw317mPU33ubXKrzTciP4eTtiDXS+x7OUU1wn8XI4XSJ/XO2+3/+7hiw72Cs39c5ddd7uYcoI5EuuF0xpiLiOrtEqttXbWEqkDtTpDC75tfVi2Axb9BS8VRP43/JIJ/53BXvViJu2MhQo7xCz/32DrUa+l/Ng6FDdxQbhIFDcNTcKWuBxESMF7RZfuyWm3QcQhlh1Z4kjpBLPO1HxLKCFRyMHqbHLTORqZL4ZSJryUEysyxKLrAPu6iHNu0ATYqq6b1M8dl1hGPJDdPnvfKM/RLskAH0eTivY/zsoY0qwdcQ46JVhtOaxCuz8GqCUqmlHMMr9LtrS2fZ4NoTOU2s6gS/NpBDGCw66NZQDg8++cah16pqB9sAy5PyypClNq25x56vKoBb3RrC1ut6/1pFK6JIepSwau6P2CVktUfY0WQGLAef+/UlhYqIn4FiG6FskzLW07OcZkrTt4J2g4dBf/XKQhJcjxHc3hekTP6waiMFWNhtFHbYR8J4bjElOmGjmwkq0N92Jk2B+8MUX/E7hcAbsFaU1uvKGI0xnV7DHggw5s2b+b8FMQ21pXD5sGXnzowFqowQHv7mAYXwy4F8UCjWWlROqUjiivZffo/bYYAXuq0xrVp6Ji7Be7wzC+ckA5c+M9g4V3etmATRbbUmw4VJuiu546H4zRIINRa15ZwgHMM6Q0bSMmejNK9TDpqw+dcO8uZQ0b3N+8cq5y7NAKHmzkvpvACFq/wqvcImdSbe9O3JWY4QPYoJk6Xa1p0EESOEP5YmlrpTAuLsGe3Ysy5/6ETgTX+/rclkaGSw/N/5uuBkZR+ZnrRFPL1LptzUoSUl3FHSm0Z61iDbsk/zp4B/vsrGNsV9KQuFms0AGx8+044ULZFbEgvMxTX3Awu9eHO1aV4Foy7nCeh3zSCQXYoMejmSZZ0xES6WatypcBeVanfwIqvX/iuBV9N7NKl7wjHiweET6VC5OzMkrJCjABgiCgMhdd7FxTrjSjy2/Yp/IChRlOo6IaSqr4yYQiZ/7RtVKbpB4Q0/SISCG90zwMFByEcmBNwnBH6hHDewmZXLm1Pmfnv9dwsX41mo/XdOO9Ebxe33k/UG7uHOtv6P787w4mS/J+6rt8KfXv3gzPWDTurfJh3iKQI5tY/Hyb/1bLxWZfBG9Ics+YUKfxvbv+QBKqDnWHL+wqjcnAx0aMeEZWfkvcYAqj5FgkDh8s23BUZMVxp8mlVN9EDTsTZUcwlkZrAxfTY7N+YH40ZvwzU+LNY1YWJRN4Th8GvvB5yNIuf7Qv21p+sDHVhdEdnRG/zxCFpsxEcG+QbS0jEaiI8k4jxY3c/2RPbFVZouQvywUSUTdz1twhr3RcaDN6ttJuEBsoJePFEIDCc1LsB0rT3Fhy3lwDLLhZ0hmSYEChmCOSgv+UljuW8fkd8bBdsdVNDVBqM8yScLGtub13Iq491gTprBNLJtZ1PfxZyb2Ii7bOGA63ynLas7JFR+f9h5mZrbMo8i3AALTubVrynO7iVOKbko19FDM9i98UYkLBHZnZgP6wMXLB6NedjYAe1+nPFTOCPUOxHmvVeZYwOfjXTGK88OujaeXG9ZZETqF2qxL5d7mhrXyh1Qo4lML/epggD/9hjGTpSSdO/tAGjJxrclKIhhQRfDLbWCdmzcuOne2uztRhcyS/5PwxnqKvHVegxeQkc0ZWVOTO5s1420t4/8ZbqUoQoyzdz0XTW6wSHIE7iBWHclCB29OcqtcWpAUwe5rhEQlT9hw1kQiEeq0WwPpfYBNPAmY+9agE+rodZsv/Yjxp8yvKOxvM0RV7preBCSlCcmod7KvxPD6WeE0fR0XtuTdSXLkHthQv8esDJcrSlMTbyvk6tTG6zU7PNz0DK6AgdeN9kqphh261IdbAgG5mClpcnRqPHb2nyLBZPjxm8WZKUDLY98euqgaAb0FLliHhMvEbhV9j6bRGq2fLzYruK9craOdKHMEltkovDJ/Ihi7g07PPC59hWez1+GkvVXdinhVrAxgtLLIzm/i/uJVYr4f0yhSgKWY+/xtYNos5Bh8h9usJjiIvVu1DXZyszqrDthtZ7Mtas8bveHOS69tgdv+3w2XdLp27DVZecJZcktCctKw6ERC/0TDDy0dfhbhuE8nocwCKo0Fnh47KS5kuEEArFPOnDhOIrb5rGeLETnI4CbTCsItg4pc/JoGTecC" + }, + { + "Version": 0, + "To": "f066102", + "From": "f3xbhu7ukbh2uwy6ayzgtb2xwevdn6mpiiyfnpczjmt6rvpnemyu542dvboqw24i2nfcnw5vxvh2hp76v77ogq", + "Nonce": 201684, + "Value": "122690854497365062", + "GasLimit": 59879293, + "GasFeeCap": "1099999999", + "GasPremium": "129772", + "Method": 7, + "Params": "ghoAAanZWQeArhB/O66/hpXZoFfzHjnSsyQo2S39Iy7TrH7lUK/XFDxlKTpITJTvkmSZK5TiDtP9ooOz8B/N4UcgZL2KtPomgaxCxDqtJ2N7OJPb32tBtbown4CxR1PzAIgYQcoKznL4AsAmVw9kSlvOUd+oP/9J79piJ4xO9HqWbvjzRxgJ05+2fU0BQ3BZgWIrpGgPy+M5lqwJl0z//KjhCmfn8FJhUzIhmCoUTdLRoWtEiBspTAUDtNOwQYBWmpXRTWel1FUssKhPLvn6O7gpdjTZdUxWS1hQLXlcqMMe3tsHYH/PO/4YMg7P/6QL9zfHnHeZoIZYsCiJh7jaxHbnGocH+lsUg49wN9OF320tymmUagNhw02gEROLwgwCnR917u6AnqAxAYPeGyHDMQqC+cFSS+BRKILqSFE4clnNn4zdbXAhnPJAAvK95Rh85mOqzokqYwemsHk35d2T0CYu2B+SbP96BZcGqRax0RXhPQX/1/DEI7lXAQyUnItg/ytE4ZvkaJe8q+22aoPCwYW2fhf1eqFGX81wtmcSATsb+y3VUaCP9RI1PHKgJAPJgSEaPPX6xH/plks9r0tTCm0R2KqT/KmQTbN2VcCygiCN5AdcliBBRNEPFfNpFIEZNTs49vKSFTO0FHHQ/8dUoECYi5ZAPLJm908X2P1vy9MDLGzse2VZ2SDLemChc7woi0BZg4wM1nbygKGlrq0rdu2S5m1K3ts7uIkwXJJjQhJq7qocZSgc06BvNy2TNYqKHiCGMH6+K2LZtQqNjHfytp0kuAZqBHOQ5h9bHvWD37EuG5K1d0qH3inuVTArS8HKzn8cWLya90xtiLF4EsmbmrY5FJM6QTxkFc0OFUqNK4vTBW+t9qrspEXO726yzHkocEbjJBkSGuhBAo7F8aiTXgQYzXWjxLnwOa6xQp9bpLZc7P1c/UajJmj61Ml7cqc3ZamBmBMkVrWWhlyhmIa1VYwgGOE9s6JERsNFVOm/zS2rNB77PF4dZgiekoQTZi1ZkFNfCmu2msO5kAAQZVV0yaA80ReQTNMP0nSv2o16Hs6EhR5NoRGnzDoOmmhbKlM5jOADhzlXu7I2pRJy/bV4ii6IAP1CnGvGKVH4Puq8yqzfdvBfbRWDSWduLyaoFdHWNrt1KgQIAxPnFDAe6i0hvXp1g6twTZbHdOoeGJ2URBvzEdkE7E7UeJBbz0suTSWTcBN4b56NqGu0l4gbOg3YPY9xQtZpx2OSdy1/nrrJ/vLA/kwgxe41e5Q9ThEVXsMfmKqYqZ5Kte7ImXs7IhCRl4cScVriooBNENQtf3zIsikF5D2Ws83RxgZNWoCpaqvu/MD1n9nXXuRsrtoFu2ynyty93mNIdSzTi1vW/JDn2A7uSqjxvtWhn9+KrjCS7NE9zwlgHyq30aXGB9IeLtpj24ZD3z+YZrS5wcgHvKGDQikfaq1g1yxYxaH6Ln4XzJIEmnljrd8AJa9vgCWPt8sUzS9Zbn3fgzXZm4UiEgIRiy8A2f0yA9Oo8CeDgkMX39bRzbV/nRrzm243uett7zbKkHtY33W2LnVP+0zuBXMrYYEUSTzf3L5v3BqdraImSb7YMhs+YVThlpYntfZsgqMmx8KNBD360YAE4UIi5OYvCGmWLbMCbidI6kQIwJXfRIvsVjQnitPId57UDtO92Wu7knpy0vuGlVQvqqimvKlzdt6JD2YHO8z+5RzgzTlCo+fhPO8iz25L04Sxh0Vp6HBzZ1UirTQyp/rYry0L168AV7PIGjwysb1jjc/yR8pJdIfBGn+uxzavmMJqi7YeS9+kFpgOthBjZIu9vKmG5xYi6GM4fIlnkI8gzxJSO9TR5wwqMYX7Czopg5WRo0lEk/XPIFgRWIYc0+8SqP+BGyyt8c11biJcoA5A9w7q8m44gfRtszHeWVf0bhUqERDbye/oR3X6OrcmBZ3ZHTXKaWsSm4M/L8jsJ+5OpiMaGODUkIK3/Domp4eSNv89gCaC5TxH998JS//Uv3NvZVGMCBzU3VfimjBcbnvmQ21pj60hXvO2o0CHnktvaJoBjHXG7qGyNUhyw+Ez0+XA5gCiP2bsrmWN1ZMwKFJybaHkzv+XYJG9Uk9+gjUkCW/TgSFp5yQJ7pa3H9b95PiNC17apStruT0jU2RdBAZBGBosldduaLBC+xTSn14y1BFaAwnNph2+K+5wrDCXlIemTYuORITA3ECDHk7JMx21sdpw5wvoHsMz9VjbMUItJ5NMtCqPpRq7wwEOxx+fpq7/sW90FgX7M0RrMB0ryz2njNxROm64Pux69FYYCHmdShMEpitrZeK+CVQpYzMKWL57k+zFWvGWd/lkiZjEvZK7bMaoi5RcJ1bbwAPdspwv4LZipc4rALJoyByn96wfBpjVPEBIg+ShWbhGqxMXVPz0cI7QkJwVTULE9a7+ADbbOx3WAd1cE6yWpqXRhnkTxW8k8C/n4jGqcOkGcIfzPoaJxxH71iMT3cMfP0GMpfoIzOQ9gnkCkyLiIqdjBKFvYfddZKpbmVDZckXxpsM3hOX6udz5ZxV8Q0/LFwrHREsoz57u" + }, + { + "Version": 0, + "To": "f023530", + "From": "f3u5nfw77pc7l2dsnlbzxz3jcafyjymgbkxbp4vifaoojcvhzv3sgroez6z7rrlxh5z3xpuw4pcnwiks6xvyna", + "Nonce": 1373243, + "Value": "122696242323970072", + "GasLimit": 65261793, + "GasFeeCap": "1099999999", + "GasPremium": "129301", + "Method": 7, + "Params": "ghoADNzkWQeAry6EO1Scgou/xP/Xcs+MX5uEgGhnAYG53WJSY6oMwYBYmQDTn1yKikwA4QQTs88dotlAOtPkdfGvk31Rc6f3RSjfmHuWQn3STCAnalrUS+UyjbVLJt2FPSqLIx1pC+iIGJZMhLOJOgf8MAtnwGUmxfSgy4IFGjdbZ3t0DO4gHYkvmeTCSWU9V7U5mRi325T+gmX3U5p/svRCGSFKxthW5rFt1uUBsDWrEN4DpiKahW5xR+M98hbmslQI2WvD1eJylThdTVyre0Dx4ipT70FHfiZQh9PfAUhgPIewsZKbebM3D4fAMNcpREMTPZgTihQulSpLmcAWAJUC16eqtEFc3NzscyE/3s42fgWbMtLxioRzJA4hIF3QWKKy85UoE+dNDyoZ60z0WrfQ6leYX6kST9Fw9T9aLdJ/V1M2ZNmRfq8aGvS2VPZWHg6liInVwqEfjIMStRpClQ7/U39F882foY2Gxfvw46SRGTk/OiXKA/RXe1Ab5RtmSqOY5NjjE7qAl2EL7WQxncTfN0FMxowpT1pyQ8svvTC2yvf2P9DCTo9a4QqdigMixUORxsqgF4QEqYpCP9fg7lht/IU4XQepuhp1zYlao7VUk9gjgMFxfeh2bTe42tLfwV292f+7OQF6Ey3QN+XLZDLC4kmCqq5FCPmAnJ8xhfuSchcnXqtCFpslxVVoMZib4cPiLW+1NA0kiGnQAhJNR3CbtyaltCbErjQ0Ohj4dthwfk+ZirbmPsaZW+Yi4P4rJ48TcrZMMLusqqB7ebdeNaqVeEKJLFFAGlQhMKucW60E0x8gPnK1UhER5NGpr75V07tQstU9Ca6qgwzVIoVFzsvdcWN95eqtDG9IxI09YqKcGFSAFpAf0lZDDCvuMAAEICzK5mG01J2gEB4qs6c4fvwwq4NXaahcXEt4apHVZpVJV96MyXbdyx8xYtFRu9BkItGp0OvukoWgiVJSf034BqIXkd6Pj79tZZn2Em2eLzUSZWUrw4YQlFeK+DRuFUSU+6AMKTmkBIP4pISh4Od3ygkYlhq8yHUYgHjAktn+oQLEqxdqec2IzWLePeVnKA7DvpZarxtlbzsNsBECVdhoko094X0WJ+5Qz8rVxFKghsX1pP7eiA0s6CPWnTM59Bg6jrqpMek5+r19EYvomaVATMZWQssUszhkO/20DzDsphFCxvA0llbz9IRQ9fnp2lYBkYRtLtq0+zmglDUqbyZCiSbLnDm0EZgsaagOCU1HQ6iyK4+IlPAj6hfbJkCIZYFMiuliycssnOK8ikROh6Lk2vcVfW/uGjfVXiZcOWYY6F79os+yIioH3Or0spl2jd3weBXZkHUoIb7XqSTK/poZ2daIGM8V/j7O+i6YfAvyf9LXxIsdhMjmyF21AzFaVEWov1LoJXD4FTY2AlyGrvxpbSQkFUeYYEqtGn2sN1h9qOLgfWh67HB7iv4ZLOGzqf2lqWm7xW6O1OspoINY+mKPusX8ojwNrULxBRjYrPpmyrvM+fG4xoZLn9bC3lmtcT2cGXzyVSKq2q34kfczlhGaWxWBebY0P8EwgQuWTF4wttLB87967JHxBlSF7+SQox14zm9q1ThTwQ8+oqEjGy7aoSmxiAMdAIURxnx5nCIpAe5jLS6FDGcEHgW0GWMsWNNx5a/MwhP+/2D6DJ4kUDxteLgjIpPrYW+uk6CSaBhUeMgXXaePcCvn6sYao06lAghwGBuSn36lKb2vjJs/xjMYUZBefNJr3LFMsnZrg9dd2BBRzh7C2ZA8Rn5NGidzcqzU8bgbd1HBXKIIgrWhwWNAEkSkQoFPWvQqZ8c/oGH458h9PLhrhJYWGOP/Kmd7xgKzwTNvsJ/JATVsgNO6dWKjR0fvEppCdmKd6r61/3vlkbO5bRinzz/YMN6Bkm2vJFhdW5RnkB54IHQQDNhFAPG2RzLoo00I7LQJQ0mMRMeqtqGgyAoZLN/V9ScuhF+vjW1Zs0OuSs/91dU6gPZRRI6VkRmuQC/FEgr5G5rYVsttWYYP6nHFm/ZpcXNBQFK26KJVLXpELR81jFz7pdiD9gOkGx45OH3hOkiLohU+hYvG5RAIEk7dzM9Ug7BXsm1qjTcFPgQsSxiZXeREkUKfjIfVH6mAspz8u+rg0Nhw5XU0oilEhZsbfrIFls9lcWBM2uro40aT3A9z2JnHENSYqnJ321uXKmGISgK08WcNUylZvsjIO6enEYiOlgLCXL3RTTH9NVHTgzDO9kI6hgwf5qiCqpTSq72evYtYnuU0HHNzu8/pcP1PUn1lmbsU1Iz16TpXUtAdo9fWmvNQloBu7bNoTt6NPTAhhLj9TI28vo85yuasMm1dAIbTpJFjzJkR33rzfOQiWDE7/tCLlI3pKWR6xYYL/Qu8zUlj+sq9unMdcJUnrQRkYSttP9M5Ds8nLKBxj41tqHprRTcJABa39QuZnYkfcl4G3X4uz2OGM3Fp/4iFMWvIbzFTiYcveAzYi3V6wLl+y2wHGO6Sly7+KUtafQDAcMZ2iK6Tobjg9FlkI/yoVQcp4TrF3RSiG2/lDiai4h5zw2Q2GJJJ" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590150, + "Value": "122775790697436945", + "GasLimit": 70013903, + "GasFeeCap": "1428287750", + "GasPremium": "126494", + "Method": 7, + "Params": "ghoAF5H4WQeAoQJeXVONLwfsLPG0Xwlmv7zWaRw6VLZo7g7KmmB/5WuuEObM5MRDkJoJmQ1ewvMfr13qf4/7qHY5UuLSa1kZCrWnslwvdqy0Hb1bOGvTW5p9TI9RqDwb0L9cuDpxp4nsALm0Pq6V/GSU6tpwinX6gjChhqcQOjiXf1xP993OO5TYyMaNPF0w+s0gfvA/cf52hz2BtYnwWQUtwpEJvii0kjX5BoHh64lgnc2O5I9JTRapCFUq8kuLbHIRskn/bTWMj0E8EKvg5m/uLsv8HQr/w3b3pBvHYzIDWFZb3YpusRybbQ8TgMjFFB8+jrRVEg2NqDHbceAA8x5h0H2grLRXMJw7xOPPy6QDm7e18bH2EpbbjSLMUsAMVCfjv2gDx8WcBYiIhab++snk+UL8CBR9UM+A1S1QeE+Hf+tTh1257z6wCnIfdYAuEYbr6zXLfj7/lDAgYKu0RdPD0WZ7qgaWKD1Wdefi5CJQ2rv4v3qRALKXymASb/0a25ezCqcilKopmYDpdrnRhX1DSW2PwHkWsDcKzcD83MoV6X2FROctYoePamK618K4iGTjR9hAWX8/pxyr62ltkiD4X0sNdUvY3Ni+uSE5hc4A+vLzQ8DlcmZrbt3S3lsY2dYjeCZ5hKzoCuWiHkaXfYjmmx2xXVfXm3ykd8Tpmjm8azOVBmnE6Lg/GKY4L9QPl1aWaamDFwKelKR0g+IwyGbI1zU++5geqbQRXvgIl2Qo2GzqmxyJzbnVpjYZdufCjqQo4lDIViSLlHuptrP/ZHi0jVPCWJGl7UFo7KgbtpjU5n4vnf8eEgu+rSEbsWO53mtXIXzdfQiBhnTv5H7HOrIYWa5gR7pajCUBrVJy1VcPgJFTocXFDN9jedv5yhg7RpmhznLn44QxCwFfJnsp2+AlVKGl4ksrvLXz+Rj8nwRo5zk+r1G0owAEFscR5UjLm6GVis/gBEJ0jN2Gsya4sbTEwxFcXBBMbEXpwafhFKh0VGGkXPk+115eUsDvIZkKRhsyZz9Y2l3etpw5PWLprFitWnzZfzL+DVkQE6g331fh8u1JXj7WM5fUMeA0bVqJjXl9z1GK6NSTkXjfF6Py8tkO4CpTM0pESM+de1PQ+FV4YKTrlna9eJJC2UScU0BYCPZTO2ggB3j8AvgD++na97mTrE7InR8RPQ1rUjrSZBtZTI3SBdVh116azbLjIqC5IBauf8+j6LiYi1ew3ge2NPWTqVnNZHLc0GKl+y3ecktuOwNLbaveWdBRLGqJOwnMZgPu2l5xlUaCuEUOFIWuYPq3/xKtYbNUgnXQuwVwamtUmJQkUsHP5JCmWiCLV6ACij+nKaYWpLr0h4FMM2fCH02ap0Am+SekgbCNHiRxBfIMhIxFB7lPho/xRAodTbI24pdG7NtcNCb4FkQnkTZZ7GrLWqltXTWUFx9KYRsmlfuszZWyJnGm/4u6GrRERqy8LRWLoQ+UvQq9iRRehDMdkh6Sv0ErrdHu/Jmg9rfBjxNc1b9QKXQNojDrPjLCb3oDTLzkUO3hoSpIsJxlwhK+0MsK6GwOtzyBCLJithp8z/WD2UE/EOPdme3whlCnA8hEFk1jKeihiyLpqHBk9q2nDSUV05zzxhR/YO8PNzO5H1NnnsrXF+21Tp8exjEEYOZSC/CI2krA8pmuDGPKGsabFZxUjVh4AdcsjpxWixZpk1LPZHtKW5qbyODzBdiGKk2sIW0RERssB+Pvq13oh97LoTF1Nh6x66z2P/IHxl0y4iET3w5wx6RzhgTzNoBEH+0K4CAuTodyrf3WhYxPrUdnhi0uzFBI03kQPDiwlJxjWzv626HqHGSYTaBOm3noK7t0wIP2t7PsWqZulso2Q0nZpOHicf4ktEjLvRyjMVx6rTcuWebjbvKEK2Ui//w2GJlkO2Nu6YxWlB9eBbH79nyeno6lJFsZII5YRnK403vybVP/cfUvKvMFKSycPa1G7fh4P2c2bH5vialFiRwORBYguzxA6vzChdz55meSnrx4islfnpwCUiemSUMVrL7NOnDl5DhzFgJCEaTjjdgvdIXSdDmvuiJHJzqhm/PGt1HjM8McNmOuv7BuyZrazFhbskHrR55a7PcJVuLSmNwj8aif/ORTXkQ2CyL4FlgrE+9W6yZHP8xYDmVfmf5TbXIE2Pa5wRitaLN95GBICA/CvFl21Mr32a2VbMeL4BFnLuhx1S0jmk8L2fobqoLMintQmIeIlmDmW19OYpoErPrYrhogzxCcKkTQxQ2sXoyDMNB4stXOoQOE+c0fAkUMiVbhZymydWS3cvs/uUYahIKMkhGBOdvRR81a5y1OallhQF6/43INu0sDL8uETMVQSrp60x65y5GQ5lva7i03magAweL5PKWcscrakaDnXwMRfRHgbyWb4vrsz0zt6wx0YdwMTL2swdd35NZAoFm/EOuyAV8kPyMlAhDpDH3deavoB1ekzbsbzsd/6WCkqhQfwZH8hsfvl/UqyIG/OX1nlUnnUTnYYavU75P4YJkxeyVGcGKLm8WpdyiHzP8TrRdH4WYafc+4eCAzuQjpjUsJ" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590151, + "Value": "121191532823564220", + "GasLimit": 23838781, + "GasFeeCap": "4194845365", + "GasPremium": "125234", + "Method": 6, + "Params": "igMaABLNp9gqWCkAAYLiA4HoAiAPEvNFx4NoGGF4GNsGR5fzs52GsvfMFRMJLjPew8LKAxoAA7B/gBoAG2Kw9AAAAA==" + }, + { + "Version": 0, + "To": "f017665", + "From": "f3tdtgqemnvckqzfj6y5odjsun5ri5pl3ps7l62d5bef3ssjjkfelhw7etgakrmzzpdpy7tnzjya5sllc4xdoq", + "Nonce": 7910, + "Value": "122396137073606521", + "GasLimit": 59284851, + "GasFeeCap": "1686771549", + "GasPremium": "125607", + "Method": 7, + "Params": "ghkQm1kHgKrBo0x+GEEdI/XZFQXfKnjypA17W9+TM4CDYugyar5nDq3ABYydVmtkwkGg/g1N0KaT4QMGabpM4l2+5xQW25Y6gvsQuvggwpZTgnEcWXesvuA3N2jFfnSlfUgdYIMjvxkWrU6HXm1qAMfbIotPGRxTbO/WmGqwn1eD2wRx0Lcgq0+qTwxBI0TNHFbzDA2pvoDa/i1RMG9BbwPlsVkYcT5JuVJ+OnPV1JWbm/n/Sn0GI2SYsa1JSB3ioGk5yKM1ppWMtdI+zTpkCvJpAsIrraA9D8D1jaFYHA/73cy1Q1udsQsNRXve77MADTB8qxSdCbmrgphyBq+4neJsFLyIib50Wkc0xaxXRqylE5XILiJL9YuH6smVoWqwfYEQ2ovAuxAZKjLupmdCSx4OUYvG8CoADEqWeKUyC7e/Lt3n5wkt0ft2fqOnEHbykDPigCEUaYib9BijSvO+eYVGwSPGE5ZL9axOvAhliIlGPAoes7piI3UC9KvQlFfcqcBo7sAkt6MHHDeaee/sOZaWHBw0D2P90RI+vlpH95xtwmC3M6yGL7Bve+yukx821TfThn8Ttq7CKEL/501pHWRvzWB1OHlE2vq25QN79oWzZPvbWoY1HhR+ZE4AN9ojuAbbY1Z6lxZd2q66l4S3bbU+tVDrGBF7MnJKSH61aqDb2yCb7PhZDHteQJ+IfI8Yj7OiCtk9y4x9f3GCwzlriKpIEC2tb8Nl1XKnrXrtlE3QB1XIREI5IelXO+1g9hBbj5S+amRNCpXojwCebl6HJkDPSoqMHdr+UqrAshPQCbk2fjcxV2KU/tKnxrdY0ak7YHXhifcPzZelBTupPz5ZzT3bdplSReJ1ZBOx/PoDKsgiXuzMriD13Aar+MktcvZ0TNQ0dL1HpBakXiuNoyFIRzc1LD7WQiKahzgGPf6uqEXfs4IL4QzChmpgjfi0ThW3rg+mKoHWC7K9IQp5V4XyFVr/BSvHzXfTohAZa82etbQn67e/qQ4wvCbl6uX3uegmLEG/kILBxLH3p6jqSokM9/FGeTbbhWqgiRGBkvwvwdqBY4gWOpLwUiOGJ7H9X95k/A/36B14A4BnW0/UFPR9UDVxEILudWPivQO94t0YdYcdGViMj8eF8xOxYrY7Ki1dkb/CsTeGOQnRKWbCwpM6akHyBykOacJRQMJdYhO92ItZSgHAdZj0tT6ZnOeUm+zPoKCXMFm/LIEiNDRCz5CyC4tWd4m71rDbEcklDy35TnrBnom0pDnXEBFNdRC0Ip2SBsqRtJAp8oNTdDcINT16yjeKKvBkQ4O+hBjUtkywTFYKlP1/fkPIl29quJufhhn2ycQtPw7zyaeEz1qyeSzltTt4jtfV9i8ZgOO045KbTiNCug81dmpanWrmTYPelchoxPQMf2MxghZN70rB9jD2TrhUegAYA+5Hz0+DoYlaetdPCF8AUNDkAvvWV7q0QpqowPaij3Q64ZXBNKMElJgJEN7lPhyrN4Yp1rQUb9GvJB+SFYiPuPpM+Vevu4Qt/xS3XVdH3G2bS5UoMlNx1K4jFtX9dtSWYJfGnDLKG9j3xp6WaGRwbW01lfBy2IScuIRFn3+7MQLQvJFhAljQho/ztUct6m2agdSHJ8qwM4vNH8mu7KuJeXothYiclwknIbj7cW/X1IX5ghOlpzKtrx+0OO80WtmU1AcaAn8fWps7q3OB6v6LaoKmtWf41Jjqx8HWIps+1j+uA5l5CdSgbgHwao8nO554pu0XK00jfsAxNUoalKZAytS+Yi7SVPwFI9tonuTXfRlBoqvMtDZF9tLt2kVbGBHFaktWlsBD3xI66TtPcmQnLzNgBeEmLqMexHlaUKswuLJI/KAWiJuZuKCmI0oFUuxtRUz1uVWaZerEgoFEqKv6JGGzYinkAh3rfG/2ptF/EiQCERW9/5TjNvwJLqXqiFkK2586s0SKpnyqnS7ejcPo6z/0Y8Txz7Nsq/BIpL45kNFUtZGfFt7ZQ6RFwk9r0C6U+jRwF0GtPQa5PX5HtNT9gmLrNg3cZ/Z8G0T0joWSRN6uvrDdqH3WGOCnRaCfLpvrKFyalhYVjQsH5/Y3CYo2J6UsJdPHesWLVLh4gF508hGu87m93+HMl1zVWxHPmzFdMCVHqMCFMeH075FHSEYQByyB7no0l5oWDHFnVRBixeWIixIy0WBYlBUFhrbibYGLEWaCc9lNsRIIJJmVxVYlVP24xa1SmzR3d9bIBhMZuZRN1ah+CEDprFXoZnMulT1bMXH3UrV5nM6oSHA/az+PFpBNU5nnHFoAIdf9LWKauKJaKqZ84jO6X6o/xowgMHQpI75osEF5m6wkWLMTI4UB1UkMdysUxJ6ES8qu/S5LC3bI0bc1NHPeki/I1lB9cNeSYsZaYJisSziHvO9yF8GFVN9Rs5pvx0ypPERaFeGL7sQAFBPwg+gJuEjVt+telPAFyY2qCc92N2BAXZPhPVmxmeHNF/seomozyk2wW3LsSaG4LI4OsVMWFT5GfOz5R+KQEZwwmeO04BY7DwZFUtAvc/JSaF04H2oUlGMU4FD/9/sh/Q==" + }, + { + "Version": 0, + "To": "f017665", + "From": "f3tdtgqemnvckqzfj6y5odjsun5ri5pl3ps7l62d5bef3ssjjkfelhw7etgakrmzzpdpy7tnzjya5sllc4xdoq", + "Nonce": 7911, + "Value": "122396708499485462", + "GasLimit": 61991403, + "GasFeeCap": "1613126904", + "GasPremium": "126444", + "Method": 7, + "Params": "ghkQlFkHgIoTduK9NXxXqeSySVTJ99zwYgY6fKABZiG7d1KYceVgTriH2ZX0NPv7hg5W45OMSLVGM6GjVoQK+IVGsSoXAJrTLf/fECQeHdGQC2mnym4LnE//flGwi82adKk6HnMcHhPcJUII7ihluGjab7cenff3e5cYmjpTOI8W+hr9XLDGjhKXvbbscINtzZiN464aWq6UC1S1wYNDN+3zehfN9ObMZMEAVxy7sakrMcaGLm7dwnHcKDNtogkDsxrgnDevtZFzSfKrY2PUTHD8veZsuC37/cbb8ROE2p0LyQyTjVJic9lr9q6WLJbt22omU+zzqbjiU3QUY6PCCCeHOjlWFuJIptu6eDSKv6cRRvmqxSai0r4vZx7LAf4SnLT9CqQhuAK2jwF6nP4T8+w/l3RVLp/L5G0SQ+wU268D0P0IyRS66M8d9xM5RXJWjkHs/wSTQofuTKAr3CztARdEfa+ZD9R6ob81PL69U3pL1Y4OGHkRdTr6bREWE5SMAOO6hqQYq6YlakxlZmcdr/UZHwaqH0rycIo1cuTy08XXaWWeaTD7kl1xJM+jbYbzfLbNzoqq2opCnuEUYGlL7vgu659ao/iK0+WTQ405SjwRgDGjumohTWqEvOTTJxmi117a+wCQ8QTZAosYYeOfcBdJoLz4Cs6GafRr8Z0XjJV1HqGcmq3yI0ZPn59oGIPAQ7C+w1hUsKrtEv9GYoHYA0BUtgAu4SeYxJKsqsFt0SrVahF4obTeXcrVgwKrqAk08IY7Pfzev6gLNJ9zWP1PkeldzXG2fntwCfsr6tgOPvai7d28OL4mYVgVdnYzY8bQJzR2AyR27IDWItPl/FVMtGp8PWVv65gJ9BD0TXoQGR5FHi4gE2qDryELlJoDJtBXt/11in98rRHDZQOvqSk0AeV+pMwvb2wzRfEXKWm2VHyPXn9qxQ22nzBdAMN9vmEF3N3GQRwbnIds6CVoT5kzKnpC+8bj0CdfRnDPruI+In2m5zooHI01z14yaKF0r96RgXyHzoWl0Kn9a9SzZRSk4bh95Q4MU5zdRKZgmoIwsktkpmYWQdrqI2qJhljeHcm0/rIJXzZkUYbG+x+L/Ggsc6ddG7/4WQGVNG5AiFbKGepfedzkXUmOfcS4OxY/H8ZGFSy3Ncu4RBiErB98eU14stPUtr0zuKSm+3PojQbQdwqj1d4wMmU0/XnvYnsAwX/zPkf5J7meN5WVhd9CxsAk08MmU/m/HN3rDqUjPAxPZF2LMss7wQ3j9ZvHJUsOWfnDQJj2wgXXJqAMM9h1/GtWIeh6u1L59WpUyiKp/XfM/ji0IkhET+K01lBwi9xeKs22OV3Q4NmdzIGcCiRbY8InsADEwLGr/9hewzBHD2Ta4eIaEnNvnP9+DsMwtAqvdrSF0AMkUK6vThCWq/9qFs3i2sPtbvTdHJxkttYmu7XxEc84FloHIsMN1i57Jq//1WE8Itr1VGx0JZlG56PuyPDEV00dWQ8VN0fiMTPdfVfBmznfjm+Q/qUnD29nklzHDRL7SAPFhBGbF5kzg7K6leWCg6AHYBsWv6aNO95kctxsVBwK/dBq224EyTLXCqhwIiDSGC4YYbgss4sS18Jj3+YHq0rro4DloNeWEMzyhN3HfeOdXcB9dm42iziwqn35XEafb9+WBIeibgSfnC2ayuXxUNACpsBqSKQZghtmT+YemX0rEIJSi632TeNN3cLNIS37Jy7fGZTc25hjnMXgS9Y106C2O8K0BDF1aN0hSFqYYIfPIhXl5Yox1Uw9woteBJUyMOLM2vTcPoq0fMRUuyzgONJK5is88Ns9peTRXxrvhMgoGsI5pTL/AU37apL/nw1w9Fvucc3+qbfzuwy11Z2/AjF28hg2fOryS39yaBGTDQVtdO2OvCluMKFjWhzQQBBp3wsGQLCT+gWKcgey+PQhnxUqSo+UVGeZtlcq+hDxmdkwumaSD7rppcayXX6r8vNC1mEb4q7OBYQMPod4wX7KBczW7/XEQLpTJW5m+OidfH+J8Ygu9Ie43m0CsITUiwAEce3Zh2krPIDHxShZeqmx6knTX7UhI8fsMKBIzjJbeNqDdIuSHp198Qzvw8ugnqNSgZCsFWKtX6pJu29PnCWBSN3+mirL9IlDi2ZhDtvrMyvtbsBkYOjppse2Nje0563D9BsrH1b+ygaCzCJiHsfUcbJz+96cUazTRUexRDa7DP8EMF/uyNqUWyLer2FNPESUJauMJ4G7noBTUi9H6ftNDOerzW3BTttsa7HVLp1aaRcBUTc5jr5M8wsYX2BOi7eHYwu+fSP8+7a/dlgm+CyJX6NrGcGBzXIzCc3NgN9qBW4cgnbUUb3/4pbnvFZYxGgSrHsaqK5KvplY9jzPKQ8NOwku9i/zaoOxwW1Rdq1y6oCCOaxYmdCaiDjHtwH4wqS1MiMS5RDvagQRFplSlzR9R2t6N5rwhivp4ic1rrM9kwQdix+lNDyTYWCeuvfy0wBzenvb9yjBqLmOuuoEsEoXlEKUj7TsALsjG0eIbfPN+ZlBTfWCzGA2R3dC8aR4N9A8OqwOOtPGCg==" + }, + { + "Version": 0, + "To": "f064908", + "From": "f3sz2qsm4epwxarbgecpyp6t5e26uvn3ciouxaib7becp6r3dnjfp6cuwlinpfwpqeczg2w3udnqejennit2gq", + "Nonce": 24315, + "Value": "122486005296693490", + "GasLimit": 62358043, + "GasFeeCap": "1603642372", + "GasPremium": "125757", + "Method": 7, + "Params": "ghktDFkHgIfO16Ay8zEvgn3fMg/FBP9rz9skU7uf1dSin03CIiSDSel9Cl08miKNecUubdt93YfN7qz/2PJnovsZG6VPs5Iiz/GaKMSTqDfdCpqCHXnvebnDXobaxdao8WktA5bhbwRvxg+PR2Ezzu5+NY/waoORYJ7/HmxcomsZvaSDAYI6nnD4vlkY2TCLwgdell699IkcVFqS2wsfhazAjM3OjSwxDoaO3xq/FUlossxUoTljb9yHvwiu/lqQKl+EitLUt7AS0+5ZZsHsYtXQ7P6YXY61UeLv4u0qFRunIvitxF2v5XgrttHAvBV7PiTygMi4iq2hLZfK8fcSIvShG6EZ7VywUy0ZtoPnzMwPTycvieLuJU/W/c46HCeS48ZlVq65Xwktj8UgIRaJf/sjJb/1VaantCdGMk0aHpX62y/kmO9N8VIytzeMhw6izMqZzwz7OqZCmDWKJfGE4Hjv54ZKKZJChr4KYZb0+Mw+5ZEAgos99XSDK+j3Ag+maB4eptFh7oD1HHjaYfDr/s4GqvghvsNwBSJ59GS0kPnHBP9oLazatidONPpdSAq5aB6LeSrC34tvBLoFacu32goTVUG/wv+kHFoUYoVkcMjLybDEtMH5+54HAGgVe/K1nU6HnTh8GBOh1t2CQkA+NZKJoEni6DhwUWWH/gClC5sJeURtZ0Mdh+kuSQpwa8Mk4xjD/e+GOqxs+m+OIWaObfn8IYMsCxCmrYRWRC57n2fhxQQ+ECKghzsPbVxoybcheEwVU4/Xga/VjSNoxmzP0NMjO2Uu2ipyDb+3Z72tySpXUlkWswbc9v/rOOOetYQmKauv+Dl3DI829zktrrDn88HR7vaNGzxsr6HJRjunrO46Ys7K0DJW8Sigoft8rBTsi745zX5oPhBf4W801gmJQ6wWY+xgIFLboo/KtltotE1RAryBoLVSsrkgIg3A5MHJ7WSHK/HZ16bnhk6AywcRGzXy/BAWHtjrbMaqtERHT9khbHhyBefZR7/Qpnspmvg3FyynTZWxU63165Xu2eV8j+IvWG4N+XwTf5DDymsaP1nk6KO5ITBODfCWD1g1MttBMBK0mRceyIN0YhCosQOad1LhupSF/qa9QmO0ulBSiOBgwBFTsS8nPUK8DHJ2ZTP6MgZbnl4xKwjiIbeN7RLxkZtQp/mJEeebCPap7e+liebzCnuVRbtA563TtEhbzKHGy3bZOsnwjZOJO7kxzuVVloUHCexJ1KU3O8rjgATs85CSUwUxBfmpC+Szhds6fnLdxCXuoI/eXYc2pWe2KlNzssY/QheDljfSSzIQFsSVpBCp8WWVypbqCVAQOrN44NhjQ5RQEtngnKLoHp02veSpGCCyjIktNuyi/Mq5Qsgx2yge31w2/457Djhh2+7bAy7fHdq1iDT0Fg9dn3MNyo8sI60tRaNPmJKl2OIk+/d4vFSE8H0CGwD5k2x24obB+KYAKLQFLQmTx5OCMSSXpNw5BHh5M23Xr594aXxf3cTxE6dK76EgjSS6E0mph3+F/p+p2FvS+9pENKbFet6SNRJF3+ek1MKSetLLtBlOenfnZ7VJnUD7s9nW7Uctmv7Glj2nJUODQW/BYoQQjJ03KIJ/pO2ufwEJlq9rUmI5m8fCGGF4XyDihsj6FXP/EoAGh5Qp9x11k/s8pBUkC+KgHzp+PDvww39ekldDWOHpTb6aA4MtaVe0NdG4qTlVWMZhmE4caFbzvetM5pFZJut289M8EuPHtfB8KJb9BzfZtD8N1iuKtvPJUMlMKkdLdVKzbazUMNxZbeyk3JeW3hrdAjnBQcEQeMfX2/qO0ObPIUwwLX4exYXdAUbvRc2hF/ZqNRC9ewSLPz29jYfCf/tIjUvK1/HX/ajf+2qerby5vwmnvmss5UtrAmMw2SeVqui6W2MCnS3Zl0sXgwPB00gU+d6kVXDfHfNUUeRnjX1t5UabhV/En1zgOGgyJ/Zj5kY3cBH5pdQz4Ev8Xpbu31yp66YdCLZr3jdXDnBZrg74WgP7yzFJUG1TX9amB7Z2UbDjJXbMm/OVlpZUo7VRKEJUamvTdYmUHAXBCaza1ItrAmexRP5MuYBZaKXwRhbR3l0NUr238bXwqnR/8KQYhi2LObuJfHPmerh4+Rhe6DyuXd06oE6ipG+n2oFNDlZGop8ZxclMgjqXfgCG2AwNxjNN6xpuHTRr/AKPjjwh+MUy2/FH4aM9EqIa3lnSWUuo7gwUcg8xY1dVdl2+2q/MF0UN3mbsLi6+r3q1C3OBHjvFiWI99VO+qwP/HPTcQl+as+OYMRAMbyW2aU5b1bH+rMrnikSSGhcRTiIt93QSNa06Sy8k6KY8uU0wzP26hz6r3bCApzmBho/njrhp74CEryXgJP5x4sFNI4aQGHz5cB7bnVuHb8/AE+PoiyfLH42nnmTohcSuB/roz9iIDgul0xA4InZMN7T01XNA6SliMlkkrFdAwrKZKiP0peRtQ2+w3H5b/uCKovm61D0V57dymJqlnbUQEVO+VvVpqu+HpCswJnhf1CBuAUzn1V3GxVU3BRR4PS+bYkSpG4yFRQ==" + }, + { + "Version": 0, + "To": "f060805", + "From": "f3vn5qxkoo7rx5r7xgkbfhgnfgbbjqczooual6u2chnnig7ynzn6tdjc6rwzqpsubc7v2zhdi7h5yvaig5zfya", + "Nonce": 222893, + "Value": "122713131291931816", + "GasLimit": 50956356, + "GasFeeCap": "1962463720", + "GasPremium": "125158", + "Method": 7, + "Params": "ghoAAdYFWQeAsAcwcs2zNXXBBRo9LF2fbGWEzWxOLL/WjFN6OSmjs/h6hVC/Wo6dr9TCDHqna+Vtomk6QwGYgt9h6xdw3Chfq9XQ5XUuqdwAjzF/grZg2zPyMKWE4oryAqW7stuQIl4cCWSFSyir3X29GCNKReFkKB+bhfAt1Gwa0g2VTOwzMV4KslYQMkcip3d7ETn3x2/bqqALA1M/AeBAxpL4ptbjmjCE7IeH6ehdD8OecZ3FvwUSPtnFEdG84RIJszQ0uJfWgARwUAbCaSE7Z2APIquU9m6RfumYKkdgidINGOAeywTRpzsl4jkFl1Ko2HxG8jfxpWILX5t4aeV5W4xGxR8EZjcN2SGQWwx5KCnX221RfCXlOhZQrCl5UdTR362rwZA7ArV3M5WXA6cph1GEx1V2DDymutc9bjEoaPebDZ3+a8LprNbBIanzMBTif04Y9HmIt873Qa35bEpTsa057c2VAhWqA3wZZct+t8TdyJIYwG6+xBZ6L8HG9QxPC51qSDOskqzdgjSq6mVA4OjovNGuqxFdvowx/jjucu+hAAKG4tnZncxB8IhlScMDLTupYc7+iwe9arB45mKJRO18aCx8vKKBfSDb+Il7VTngVGhwSRnM6t4OXQGJsUtJlEeI7Dr0FUkbIS9pH3sbCqfa8I4pf8gdUdKen9hfne47X6KLuidEHY145BR3bnMaESM0TrSltrwuovxROaSNyYaEECtD7abETJC7ZmbNPxJMkuvtbdKhWPHup9SmevqSaif3rF+ztAo4FPZVNJQSrmwOWTzG9+c4oeEbl8utQD4iinvb01b5fOOVFj91CopuytXZfi5pqnOfBI9kQVMuqiAF+NiCiIgz9oV9z+NwspdHqBIDdhfy3lHsWklwCRlpDI4z/bULDLByM1ipaBv7NlDeYNAT4WZNAiV6Dvb1EZZm50pTOqRlKhjZ4FF5kJ0eLprwoPFXl26pyxws3pFDBE8maGbsSrR0ZJTSw/Kg1uDwAzFMPUUKi26hkcfPJ/1jbiqBtjA3iBN1AL9hww3X7XmQTH37+rECe9yC5ftXnse9sK9grtp7S3M9B4xOQBEyoE7VXv9tjymn8kDHdUucHqZXYEUC0GF3CaUzZ7hXmJDPS0Qx/fjIARHfjtzss754E1BnHdewB8kNvVc8F1oWRqN8Z10GC0AOXYf/EwGfewg5wj0pvmdnohprO7oFK8p4zipTyEFEmXaH7zY7GQOKd17poyUKKHwYGLOxnj9LfmQBtu3EoVf1L6kNvUaJvAD13bBr/YvylsgGsYIHfv/Re5UFiW6HcsMQiOY0zbeUEb2bdGIMTMIIs+HrP3FVVFfmFXTOI0XRs7VkMiUgGm+FvhIl+tdzn59iwSr/DGZzXd4HPrOAsEqrU7Dktr899NpeeuGutDvLGUtSEvb1YCPb9GROOgCMi+w+8xEQCHVNQ2lODn4R31kWdxafA8b/6/J16oaLVZCbi6AkUYDhCmYqxIh8K5iM5RmWRwJpeFH3RrM29iaUGy8SiquzX0TseXq49fc6CVxIlC/adwIqvezfgSjZ6CNwcmHgI14SUjCDcvoiuI+8dtK2ebuo8Qf3Jr69neFzUUFlmKUfll+D1UkYdsRqkqcC9oQJw78GNJZTMmCYvM0vw3R7uH6O0patarl8hNWMThsBDcMhuzkf9FKYv8COe4g/FSGQPTRyGJKW3Q1NwbBx7NkJJpmUNkNsLOMTljms61KMlM1dhBiRje9NH6M/lA7jX103xltUWz/SG9CuWh1wM+2irP59f+7e3CQHF5wMY1n9uMFQBJduCj/x6CTEii7nZxrYt24VCViZozgVwsCxcBmg5m2Oimzlj9+Fu5eh3xOelIhSihVeqQBF/5lqhZbhBhCZn7fqny+9ak+5oAnFkq1WTFB7PUcsvvo3xc7D+R9NCBElHg87mxLd1F1cRFuWOCeWQAQbYaDo/E8ECaIjet/bLq2yFJ/Mn/RolFn14VsQtgsX4OLGnXYXGl37a9S3SxxMMzRZ1QI1YX2JEx/oB4wdWQ1z+BNWVgUFDSfdGrbQrNa1YwRyTia5yAdNUebJmeS79OLOyo+mMmg094/+0yTdh4i1YtPHk8+w/O5XmFvwjctrEMTTKKQjszP+O5k5TlugNs4QxEtQ1V9qJvthGc/pxopdOLhQ+/cAS8vLuN7LB76DjyfYH1P58V7pj+iDjHlGH7ZVT14TtXc8Oj0zXjnplRvXeaofbabZW7JhC0fDmcjqhV2Q0fQ2Fk3zae+eVuXv3CXR74w99dJgnsNJG+0yz3PNIIB9EiUbhA/eHL5YjWNwkI5wI9Bv/gc/w9qUocEx6jnLGd2OQbVmvfy3AFYTYQZrNUlrRVkk1178zaVVgs1UyLl6+cy8rh6Ur64YbIIj9bBxaViGv+GuRD7L3XQ+gKBhQNupfs5IIZfdZBfTFszjmliqjySsrd6Gt5/sqkY1iDuAvkNYnpF4sH1UsYJgULyW1Af0TdD5Y6CVEGi9ub9LQ2+vYd3w0jJAHczb1nm+CGu/w+pdx6X88SWCwM+Z2XoUsDh6Ml5OqoCy8PqG" + }, + { + "Version": 0, + "To": "f060805", + "From": "f3vn5qxkoo7rx5r7xgkbfhgnfgbbjqczooual6u2chnnig7ynzn6tdjc6rwzqpsubc7v2zhdi7h5yvaig5zfya", + "Nonce": 222894, + "Value": "122716954489189285", + "GasLimit": 53853513, + "GasFeeCap": "1856889076", + "GasPremium": "126286", + "Method": 7, + "Params": "ghoAAdXwWQeAk9MYxTQFalxrtTDkjJU7DStHSNvk3Uz6LBIUJ3TKOOS0SfNHnr1oC2OYyhcFZoNEt4tpYUJO6joUV3hQKEFgAjgK1dEFCCsjdGQMlzZLKVZ13mvTqDST7EiJhtMlt+m7Bdx00gThuk+eSXzXOKZe2YtiC358tp7OuflGsGUz4eoZ2roiXCZaAHGI2U9H7bltmMNhPbvTaR6fLclPhaRL3LUb9hu/1i2G6p8Uh/HtjMmItebEq75gakrlnr52DArNk4k96icCNnIDl5dLRLkvtYp7a1IB8Q1roGGr9A08VLBHOJER5GCKDmlRXP91WHuoplGcCtRCVcR9EXoEPFuTEy9cFv81nD/jmEbxwycYVpA+6E+tet4Us4R57LfB2Q2kGdFOUBVARD0IhRxNw/xyvvntL2NHRDpEGctjVXhCDiXREYrBWY9EvP1f0HEMU8W1q9Z8sSW+VJ4unM0TuXCOvr+S5N7qmszqvJJ2lySFB8ZPOdELRYqQ35g+NOqoZuTogNv8ooe/7xZ0afoC4sdhX7hgPo15ffduhzIxEsRFOCkBiGgpUTUdTa0WwuxeZgCirI3t7awar2d3xcuLssgDqKMBTULeO3K53Yaac4EFURBpjST5txIU3Yp4HpP1Nxo3BTP/DWpS3sV/O+sFqzK71ynVXBQZ75UxLDr9paNvUYv9tzeHT2S6sYLFTEDUqW2AmAiz9Jikqmn5gRYC+UTGqXMOnTZJvlog0h2UlAxJpHjoePAXQTpxo3COxJetUagosKqHPe8W5WBw0lurgg4z874wJN+ocb6KnQLN4EQQUF5uA97+60MutR5oGgsyo97ppjfCZQNjPhvHcOIZ06QKzCs/MseGrq5CzU+DOfVA5ECX1yyAmxuLW2DUhx9hdoYzEl8EOMqhcZbpuM+psnQZ/bG4OZvmOsz7GVMGCJKDWFBa8hnJkXPGq5SKl8wOyqsNkU4lgWUh319qRD9twvuPf30DASUDBFtjQIsNFTK0Qbl6yzSQDMvmu85gxk21Yejup2o+adYZZEWf24o5TGTO89JMg2n6RW0x5+nEAbf1FNxAaqbmzFz118lcGvz+PzONkj5g2ydZ6Kx+pfhjwmChScXQZLLSv52uHLA/sNoJAkY8g1ugn0iEOEVMiynJCQN/ChIBh3/fdEmWMH4Gx0Z+WfSZE9LdSFVRnP2GGeULWrCQXjbokliwxTuXMiYfv8Yht9g1RnWPRcFC5aDbol8FMPCj77kMYzWP0m10IvW21KcfBzDlBQNd0La1EJJRBPegrXILzd/48Ww/PrXxeb5g9PzTKF2FgOjyxM50QLaPXRStnic5lDh/TcgAwvY4lVWfoSqR3f1E7QRRz/LsymA0NOiwgp1ZyGFUhzg9PvMuikaHezNFk0mb57AAjdgWz16hCAzpgfuKUidrbOb6WrPncGupdZnQO/kw2yewr4aBPxF6R/CJUJZ4LGb0Pdk7aBpFpQfiymEF6SBZ3bh66iqI4DEdrGX4fRc2CzlHS5MghXcHFCJbGNvnTzcmZI3q4e6Vg8rUUzwrI9fiGE49A+aVOk1Geep/drfb9MfwJ4nacDRjI/NbrAmRnYwXu8Fa9IIcqXVIaXUXkjGnE7XwKeOt6/aFLKL79JRnTmITYQ6O8AjtVIgODkzs/tuY0DBkgObxBtaYyDbImLGlx3Zw5lhz+I4sB8dCmXs4MVg26iIp3333XuHJbzUY6nuAYLAkq746s0vb6UnvcGoyzKK6DBhJRiFt+Eik2rtXd2H4VBzEIpnMEPjFTz5bx6/S9TaC+MiEob20mjHilO3Hb+Y3Uk2iQn2q0tmTLOovN6MqxjgoPRwkV8mV+hsz9sJT3Tu5hUzzp2vQqezLoW8/sto8RmCH+FyJ1caPhyKNRI6ye/NUyodZiZS4TYpwKD2dCqyAIy5sGWyuaJnEKZJXhXWQ3MMi82PU8PRCMCDf1PLrJD3jzw9yz+7dWE59IYczR8QtTGLRhOH/0enhskLa3CeNZoH7iH063mjIpVsnQQVWgmogEhHAR/nhkrT3rjIpXxuYu8HOospx+Bx6/L+0ITtgCbcdpDnEgBlCTTSOaj8SmXeXMANr8u/H+5pU66pCE7GXEjApiD2bQYdbPEB2PkwAGcG48+EcZd/1ts3gBrWXsaT5RGdYa3dAPXa1TjRXxR9Vxr98GJUXN3rirjmfmLKfeCU83tdXJpnvHWGOM0ZXqbt14CMRLUS51hI2DUO3AXOJh1yTrwDFDFoAJEQzty7lRoRoD2t1SRIhuu32a99ENa4aPD1dGlu0VfgDt/T9Dwlh8tt6j/sbyToZjTasRTtAQJRUaONOiqbKDqHywe0D/dAiKku/JT+Idu2IYPMD3ytHyjOVgDGA/xfQmPUbtcr1yeG5E42jGSqy7uXawnvTVQa/neZGwUJlDKGZAoSQa9N2Wn2ADpRlMul7YRyOX5Me6CS6Oh07RVqZn/4Ad4dKXq1LixjUUNtnafbl1xwJL7Z25MpYsmxxxnVU0Z8AdLk1hZySzWBVCSyo/qtZ1bA7dcJT87Jhk5p3uHJsnXO5FVi21qEb" + }, + { + "Version": 0, + "To": "f060805", + "From": "f3vn5qxkoo7rx5r7xgkbfhgnfgbbjqczooual6u2chnnig7ynzn6tdjc6rwzqpsubc7v2zhdi7h5yvaig5zfya", + "Nonce": 222895, + "Value": "122715790385892663", + "GasLimit": 56468513, + "GasFeeCap": "1770898412", + "GasPremium": "124738", + "Method": 7, + "Params": "ghoAAdXbWQeAgkCApDsLTxgYT2XkZ8yLIFB6r8rZ/OhO+8pMyQJANq8xqW0JQsxaKNgduR7ObocasIKZOhQJlRMfJ8vRSvnsDJfE5mCr5TYUWNfgKVG2e77ooM0+fwHy5yCGtlkNOytyF0jCx97857pPtIUwxGSBbpw5fxtdDZXpullS+mAiys87haLGIwiQgNPRWRUirLh8qWI1avf571pehmJq9W3NuuKQFL/dlIiHfI9RlmiQgeG9pTDGiZPjpRXtpAbOww60s/urlzGOZb1xac9zawlwgAi1quHv4OQpBCnXtHaOkyfPK6eWA/d9QCRGeyzzleu9qlGQnIWQlT7RcRf/R/mvZqqz3khPUZLfHKlCE7Efjuj3FyvR0bCyv6lbrgxFv9AKDyZj8M4gdB5A3pX0hKO5+Dvko8+aE6SLzO8RP/vbwbmVmdna5xbhfz8V6x2zeClrgcft/lbpicHje4gnW3fYTtVwFqfUELgwEVTuoNilH93SvkgXvzoKNKJgHv336XQejo4pqKJ5uHLejIKwZRkcoxwgHzRaJB3CBDZJfL+KJHiyI0ekSSiPNTKq6Oyv+W0BrLeFxXj1GkozzyySb7rn9T4ryl9j24wA/8bG+pCZZlJ+hBEGGPOjaM58a5XJnsh+EhhHT1cYaTYlzIVc2u8pS+Zat11keyXE6bT+wJyJek6nQZRXlxMzvP+gjPg/4b3cqbj4ROuNQ7EJsp5o+DXXbLBJkaa+o46pqrr5DQtSChbL/9MlyC6yXlnYnA9nwmz4q7j/1uRd3c0f1fiDLWG4PzIyoom9XV09LoZD+u2eZ73iLtOOtXeSnPaOLsGWq34irUIWaax6AShTUTvPyC2sCeQuxPFAHpbs2C/1FUjHfnoV12TMuRPOmuukX9AuxzeUDtLjHe+zUEbWGNGSCptuBP3EGwf6AlcTOsFPsd2PPZ7IDjJGokvLtlsWuTDasUEOi0ellzERHpxLwikOv7ZxHlmMMWCIcE5tCF3ER1P2eNWkmC3VFsl+blgcNcDtstKcpnds2dyZ8z2UsGmR4oRBgTUzuw6qiZMyAF0mIfXze721UFMgZu+gFKUDiEpKy6R8rmetngwqeatALiUmfJgG3dUR9+rnYT0VsVxnsuf7NIDA5xCbqfjcT/15DS54NtcxCYXX4muUBRNY1ATaHGQ9C13A4+7BsEz7oosJceuUiunlsN5PqPyeDWw/sa++UPdFr5AFE4cq9GP2Q6fKYShaHcfgSMTY/5drc/iTwWrPXLqdSKp0RI11lpO9YV4etPcIkEC/orYE773kyzCBADZ4P9B+0WFeW8m/m7aFUPV2+VZLtm/U6wfbL+V1ZrgpuAftt60wnSkDS1IE+MGrn1ps47L+2ALxpguJ4SKSNkehQkEzaY1Gh+ezFHL/NJcZ1flgFKTqaZJyMY6J2LoYTNXCtpLp4vvDfi1xOYLB4W0Ed6iOiUfDhF4NctI711F5u8uplMyg4oJRCV2L3sEzyorNTUdsJzmSUD24DGAYw0aIITfM3coTBpin0suDmqWQoV6zpVrmGViW82Kzjv2fAWXLm/VNi1JpGhEnwR2NewDC057zKhTOpiJEKwetbKnafO9xmXvq/Bni61uqkE3Xita25gOxWBswHtsgj6T3ySOUEvPAqPn+MZLg93wIn8h9mqnGFDYp/sxvqayxx3Hw9KlcYCIDmElTrRmow0l7kH9BMbw208Z+8hECdJ2K1UV0D3FOtF/nsLYKsnkdy+agqkvWiTRkkM+yPiuYh04S8GFzpY9RpV5+CPLgeyTboqucZoJTrjPENpZ27Iqlb5hrW9yRaFtYympU1wQRlMuziPigCrBzwLvwNziKx5fnLmV/j+jrip3JpNLNpQMqkjp9Erv8j0FQBFD0jHkQTF087XurJQXcRJahL2dsZ6PN4igjkzzyFZ6wbAyeMbDrilkAPl9/JK1LYYUPIkcLq/06RvE2qPFZ3nQzFVpPXAZTXUYakLfws6guzJkAF4zFCEis2pf8IIReYSzZm5JRinKRo9OzGr34kRG8eoQf2C3b8VI64IE1soHdQVzbCTxmdP0rnf5kDooXD6Zypy/HMOXPoBu6ugolpIL6MmNaFBS7anzGghwsrS4lFGeoMzpu31bsR/E7ZgOKyXG6Mo2oDp6kMd2i4QzozPZPFJQbY2+nXN1ka57PDGUkCSqitnsoisAtHWztjsHudGDrQe/P1IQoegQkJlti4AiIiXfUwNXecOnHV0HchyQsscED9eo4y0Rni9ZBqfdPxrONnAY2Gmt+qHbjJvMkyANC8Yh/S1iMZ3Ni9fhPgTU8yjvNo0TtNK6F3m42t9bXhh4861TZHCNjBixEPdryC+5hHcy/vGNt4D16GkpOsNi58yAXL3JJoIv2vmbv3j1twZ6LNL7eV4uZMKXzsSxS7z26Mh8Z5Hq3py82rXrEAfNLtQerlJmwE6OYe/ZFqMCIj1qZazeJUmplroqjF7P/9h6hnWRiQrdBY/YX7Eggjn8kbbjlTw4andzy3+3LVQtrUM7XNFiJqAStWloVjOz6HXQIqRXO08UgvDqfBZQt" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436202, + "Value": "121190891386160866", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "125259", + "Method": 6, + "Params": "igMaAAWC4tgqWCkAAYLiA4HoAiAXjGeAenPKhEYhjOMlet3eNt9FCdsmh+wZ1Y/nvOlWEBoAA7K+gBoAG2ea9AAAAA==" + }, + { + "Version": 0, + "To": "f010035", + "From": "f3ulm32bibybv7srwsq25dhl7grvbnyjyonmps5fgtpi65qsauf7dxbn4wlisjtpya7wsjuz6pqvzma5wak4cq", + "Nonce": 215181, + "Value": "121191532823564220", + "GasLimit": 36045333, + "GasFeeCap": "2774284260", + "GasPremium": "124738", + "Method": 6, + "Params": "igMaAALqe9gqWCkAAYLiA4HoAiBGv9fYWeoxCQE1gJb9/XzvkcCMxcCuvt+Fg3UI3w7rZxoAA68wgBoAG2Ii9AAAAA==" + }, + { + "Version": 0, + "To": "f010035", + "From": "f3ulm32bibybv7srwsq25dhl7grvbnyjyonmps5fgtpi65qsauf7dxbn4wlisjtpya7wsjuz6pqvzma5wak4cq", + "Nonce": 215182, + "Value": "121191532823564220", + "GasLimit": 36210978, + "GasFeeCap": "2761593459", + "GasPremium": "125514", + "Method": 6, + "Params": "igMaAALs69gqWCkAAYLiA4HoAiCIuUn1XgB41HB7nYxpTgnNGwxZtV7qvyylQFaCiVNVMxoAA7GrgBoAG2Ii9AAAAA==" + }, + { + "Version": 0, + "To": "f010035", + "From": "f3ulm32bibybv7srwsq25dhl7grvbnyjyonmps5fgtpi65qsauf7dxbn4wlisjtpya7wsjuz6pqvzma5wak4cq", + "Nonce": 215183, + "Value": "122742216349605539", + "GasLimit": 56775153, + "GasFeeCap": "1761333870", + "GasPremium": "125378", + "Method": 7, + "Params": "ghoAAufIWQeAqzEfyHm8Y8FO9UEEQPpc+yNWDtoRm2PkyIVuFjticZEgEboMeuaSQHY5O4thSyvpgp4uCwswGSK5rJ0AOU8hwGiChLf7hGV0EJ/28GTOJEoYXMPxAw3fyQ/FrXMzeaU4FZT1HiCsdu3SNTmjteNxzh9xf31XQUaVl1zXy19cXb1HhbS5N/yE03BebL27zd1VlI2VzYUBglZzt+3bEts667JkSB2tvMru1FHUwybL9veuiX66sFEhBAiaF9m5UPIjjPWwvlsUIjsmv6L55vTCb5loAuDK4De6xNlytRAGNjFFlt2whZeotI07UcInOG4IrTj6lvX/SBknr3o8JQJSwqTQewcX/jj+AMlM1i8/cbuubwFhnD3C4p1RnCkgNgYUBba2lIkh9nIsJDfbtjjafbMIeg+mzPQblXTi+f/+acI8KaqBvq8RNC+xDuu+/Zg2j1aAq11fyUptd+9riwrHZjrJNJWlrbIplpT9m8prjgFdkjzy+Y5BcMuTP44THs52kOluZ051tnJUKKkLzSoumXzFJ7ruExhb7GDYlcU1KGnUH1OduIdfPc5PvY/pdsV4o5LhvNS2rjLMTo/bWjsktcS0VCJerPzJ74wUPOa/RaF1xclf6qoWWaxNtQOYUEZpFR8Z3TGh/f1vaOI03OCwD12q9IIHy1Z85R+IaO6MVJVFggYPjG+bpdHPF8E5h+XiskZBE+gkVuckIUZNvIwMNOwCO5igkhsQ2oV4Oj6E8j+x03uRq9NRgYFvBzoI07eykccwVLT2vN6eB5NdQ9VYt7j0YVZ/JzmW79UFbBzQBlF4vkJmoibwKrIKanJgffjwpJ98FsoGskYEQiIWDtw/LCBc6gkP/GYgLGFUKlhQK/I9eBBdVpC9JA8mNMILClDJAj8HfdlLmwxgmJWeOuLtFrrTNfCfq95/l6bLRuCV6GgiPL4lDpJF3Q1MW+f43fyZqodFY/vanpB4J3tYrbM9V7jGfDDT5b4Qq6tRqCM+BW0qsUNG+5lHh1cxxGdUoR0SoS3ARb7x6QVkBz4/XkDvInq6ydTyETaA4qYKSLkY2Lr8w8Sra2yU8p9unv2o1Qk3jDNu4jwjqHEIcVeINR64qWZHxeyJIJSjx9hiKd8PY2TduAHomG2MZS6oQt893zkeEK0G1Cnlm22vBgKGMb4fsSGURBPiTqcDYJx0ejfxDrEiB/JWyxPPncirK0ckh+KWp5yZ6KOu/opqksvjnb17A+2v/6j4emqeiNJC+BNFkxdaz9KSYMoYIL21anTF4cjgpPQpQL6o7xEnP8Gnf292lvbbb79LHcv5FhHc+Bo/QljW5DOEnqnzsGuicv2AA6FxtikNL1ULmf0MNPbJwqeI0idS4w9W02+rC2Z16uDgEjNZuTEu+emaz2JSZT4trGTrDs2RhzxjK56mUojOraP5nT5mfkVChT5ocue7R0y7Nc3yKRWAmXqSvAPHK8T/qrfblf0f08Kyg6nKS4h7n4WNkUcZCUZDGE+r60WXtUNb/CUBerVZvG+0veuU33hMv22gguPEGzo2Md1byYDM7lhva6OwEIfOVz8fC5KEwFdvOWfPGUdymk4VXEzmw9n8Nn2DjpIh+hQBYZOnfaDK/MXrI1DHD6Y8M2XaWtfZKdQpPAnDIe/Q80mhUIFi+8zEkjOJAnmF8EdgS8CUk75lqPgPW65UBOfe7mJqax5mSvEJT+WLvW0zsWl++VsIjKv1fubwoZdArK97Bq42JH6vp23CCwo123RmQBWRIJZHoHDOG5Xv5smkyVh8Odh0929+jpDjhSsNsz7g4Oj/JTY/q4ju5Sn9osmJCI672UqNlYJhmQXth6WTbwPIH+T0fOrw8vRxl59aBYaTa926t5ZV24Xt+pVo7MFEbeecZJqyeZ6XkppGsQ3qOxQfciOst2kFyfj6Fyuq60mWU7SAoKOSAcGkKbvsjl89CnyrsvDLKNzjiS9v1/vQ8/Gw8Yaf8QCokT/dlde7zOwJoHuKKCzwnOuP9FUVuevQsRRPSTkGDPWpneYdP8Pfh5atNnlL0iW9Ca0bmEV51rmyubsrazj44Q6nETCfw9wSms3X4+8KCLYxYzDX3V9dfcqX3S7jRBhrh46plkD6iCQhszkWcDWqnkqdUWW97UOytm32VdupQqtpAZQwJ9g5m1h2rcwbX9/1uq9IEm/glwEZWvczxGHcFiT2MdufrBy4bFtJ+S3uXAnptiFwsJksEPjREHPiu/8G+eGnr8sPxU0jwc7M4wRvX+n2bEkZEkjR/zVW1U1qPA/GHfpYVtLpDZMwdEPR5DiXAW+GjkrJ4D04k3CaZweb+MfiNlMJVeoNjKbkgCyMn5de7WPJXnqb3tKtu/tM+8aYsTyOiZ8HKBuYP13UAVW+3ftrv0aBq5OX2MuTeeoPOOK/OiodIj/qNx59VrUw90HKN/1bB3DQ5WTbBD8VKv2ARw/NEDo1lm/7YfmSdbtaPeSaeN+hsojU1OgbW9egpqy1iTnZjxJLRPxLypNWwj04m52YkLIALifuFKhXRcpRPWlQaeF9NJ7NcmXIkzZHmRcpsoaE" + }, + { + "Version": 0, + "To": "f010035", + "From": "f3ulm32bibybv7srwsq25dhl7grvbnyjyonmps5fgtpi65qsauf7dxbn4wlisjtpya7wsjuz6pqvzma5wak4cq", + "Nonce": 215184, + "Value": "121191750964018119", + "GasLimit": 36627833, + "GasFeeCap": "2730164244", + "GasPremium": "125513", + "Method": 6, + "Params": "igMaAALrwdgqWCkAAYLiA4HoAiAFWVYgXDdWNgMy1eDJS+MY6GINDFLqZS6BIfdP1tZEFBoAA7BsgBoAG2Ii9AAAAA==" + }, + { + "Version": 0, + "To": "f09652", + "From": "f3ro3i54tule2vtdcsjdkzjkf6djx3wwe5znv5h4kwxprxjyojvgyqtyvxus5bj73dy64x4paiqriwupmei3va", + "Nonce": 2244661, + "Value": "121215981842951395", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "125222", + "Method": 6, + "Params": "igMaAA001dgqWCkAAYLiA4HoAiB+Zs3mG6oe4qFDLwMOT+qI4HE/MR4czzA3Wo6UT7IFBRoAA7BUgBoAG2o19AAAAA==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436203, + "Value": "121190891386160866", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "124262", + "Method": 6, + "Params": "igMaAAQEXdgqWCkAAYLiA4HoAiBuk/KHXz6m/M0Q9N9+pFSwS1+kiLpMZ3JhTLYmZfHKBxoAA7KAgBoAG2ea9AAAAA==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436204, + "Value": "121190891386160866", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "125768", + "Method": 6, + "Params": "igMaAAJ5fdgqWCkAAYLiA4HoAiA4vCrfAM5yWihPiLQ6/mncOjaiYbH6dv3zSwZWdmBMQhoAA7KjgBoAG2ea9AAAAA==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436205, + "Value": "121191102922431314", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "124559", + "Method": 6, + "Params": "igMaAAJ5T9gqWCkAAYLiA4HoAiAMjbfejFQ9fx/TUlq7yg8HP4QwCMQr1F1mD0ZTIzceKBoAA7JQgBoAG2ea9AAAAA==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436206, + "Value": "121191102922431314", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "126342", + "Method": 6, + "Params": "igMZ83fYKlgpAAGC4gOB6AIgGzHNjecC1XypcmQ2EIEAGgNW+V6AKmWtH+gTfqq3LFIaAAOx+YAaABtnmvQAAAA=" + }, + { + "Version": 0, + "To": "f022922", + "From": "f3ux4a7ylxkjhquc6t3csakgalxqlizkjth2xva57y4y67rafuy2efdlouxghatyijl3zwzmrke3i6l5z2fd5q", + "Nonce": 8502, + "Value": "122743480499653955", + "GasLimit": 56672351, + "GasFeeCap": "1764528879", + "GasPremium": "126366", + "Method": 7, + "Params": "ghkNn1kHgJNGcAAgOcWI8+PlmKIQ6V3epzLfFq0JYnkvX49Xkp8KlawF//UZ3uPWw0GyEpJCHKTY0i4lpdZ0UmBo3JqOYRK4ltjQgXpfoAIoAyXWNVoY3owWxUU+f4gW7JZnPMBMhxNTC6w0hZbCsES+JOmSFIq2MPiPIFQFPE1pSjruNze/EAjp+94hVHO0iZJIq8nzs4f37aoR0GOveJLMELA/1B4keLJ6ccAPnbIJwQsOQYP7ixac+mPjecbHjU1/xDyjQoePLSx0XjmzZsKetrT9rEdbP1m/0Lka9vL7kFw8sJeSO1mq+tWQnwAZA35qCDgp+qnSrCklssRSqw/l+8uiU3ymDUSZBI6/N2KUfO77wETZa0BYscI01nhXqEcitBl+kw7ThabSwzGY6t0d64rO/R1LhcmeeN3TYCVL1orEFRotNy2H5MqfxsomEpa7qgTfGq1hwMntaGWeuGjt1PAHzaktWyyUHdRbK6K8QDHZG7DRRTdzGkLZrhPl9bMQZl8x1rMFABfhNqKtGeyocWn7Q7TJEZCgWbAfaB9MWkJPS9ipsxQW3P6kqPG6ah1FufXqDJXaNvKgfbouI9YYYZwXbWX+k6yS3Ts10FD8nHQM8Ln/3AgZi6mpJXqAWxXrR4SZSQd3AqpKk/CrAFwx1NfhDHoDxu4uImLbrtAoYTF23bLuBK+rk1IT9JkPVeegnIYCNYa8vhJOPXCs91ch6ewKSHeSmvCz+yuaVa1WRTpBChuDSoN/R2gIcR2fMlC6W0OzJopITwD7Y93gsBJBqSaQsto8Ey+zss7uv5KpS1rN6nSPbTOwUWSR40l8f/a0+3i0NJEk8e0vIOAt5jqKoifz5QEEnMcl2eHFRj/xEYwFOFCr1UWcy+tMLvz3tR1TR7/+rgOExFRGoUUC3KkfaXmNZ4mzapmmUgDY+Gz8lQF7gGxhXxkYzdsjRfgkIq8EjrGo1ooq6NcJW9BI6YlQoYjvvmJDubuyr0SE2kN0Mttdw0EhWpxtMQgZP2rCHltOqVsRN6lwgcMhuXpn0i62emc9SUbi/k5IfwUGs6sR7XBTdm5DRZrwZzLW3VtYWwT7Q31edYzjX9DJv5e5kAhF9NtCQS/t5CX2pgri7j9iy+Ais8seO4kkz/QZQDrcqlik5bDZoAoQgtDjDSgGhzw5RWTnVV+39f1/sBFJZvpJjJVIvNREnYhRUUl0qsfN487iFImsiLW8xtfjSsCst6+baqOKNGDZrTYrsgDaozuBwqKlpmnnCRWkT+fHvX/spN+K5YXp0qFgaYc2b8fcU8RLzBO/6ho+gYYQQ1wM/Iy4oFkUhX2PeF6jj9ILBYJ9r6TOMFbXL64V587nVB3ufm8G2VqEkg7bXakqAIKtk7QtqhQ4aTg4Ze8mqKclhQrDSqZk9jfSqALm09KEukPBglqDDcIk3DGfQAtJU793cByCOyXtRZWGM2tr1r5jB8ih7pJp7gVdwa389eur4+HZ+oYdC6iwzY3HCNXZQAeTYan/uzff6C3sU1gCzSFlfO6C0OjO/cbqUYFWBlnbS6zCDPV2ol06sFM5AR3xHM15V474WtyRR/g9agK+P2RoR61unJKJEPxAvpBaNXFKpPcKeaDk9xRtb9SYs/SNQ8Ktky25MRxSPnJ89egflLgDPAdAnwm1S7qo4QPr9J7DVlPCJlhih65gRI7ijW4VFnuyH09IWGvgwNofP1eyTRf0+44zP6gKdHOfSq+ppV6J5sD6+Pb8aG8fGqmaRI+/z726qi4Y1mbs+gVvGaGb/IuXkcmD2IIslObYG4GFtnn4VQBJqeBskZ2cH07Pg+jwP/qzqqv3ZwMSIKLlfE+c9PcO6MHLCAxjYHHshYacYLkNMu8jEhxVv7LGbi139VgqWGHGX4vphGR3MCUP49INSu2wtRB3ZvYM+M+FGxnzF+KThuctMCGlos49rQSSdgMVokZkb5402osRQhI6L2TP9N7JJbtRZ/tVmjgYJ5nxcQoOj22ZoVsL8fEwdN+poGC3o2uybDwEMForNyUSNadbjuSxV9pgt2qWFU2RtbAs2dyezPk7p/0r4/XZ0myxnyEA9pvPkOwD4qkNWJ6g/zJWDmlP5Lp8Fh0mOqDr5oyLhyM1YXMeceMvG1mi2vcAMwUvj+7A5jT77n4iptQFpyv00N1w59bbWUeJ3KK5DwkMPRr3pJ/M/+A8uJYZ8TmiXI22aVezmpvGszySI597iRrdbXGwP/L2JTOnudH+eoIigPwbAP8DbfGRLpjkHNXoysB8zNSNaJcMkv9+kCvRsVvgc1Bdi7HCQWIOw7FovK+uKzd1is3KxPX/xRzyRsriQVsMSyms3pCeHqtzqKl9joodm5xNXPx3AeYoQ7+wMITLMnOefxstrTGtlCdvwqKcLrnkPuzWRLu1Kn6ZCX7sWRo/bjLBKbwml8TcenHvcw1YZksbi+Id1MXrhhjoDqvjnRclq+ryTUDoOqToVebcwLlf+L4mYkxV6RVUifA/SoFFrknspNv/BAl2u4hjEOeP8qz4f6vJW1dATTLqAfO1ndL9F7UAIuj+WPjC2+vi9A==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436207, + "Value": "122754365630378849", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "124447", + "Method": 7, + "Params": "ghnx5VkHgKzOOqjaOYKJZZLdio4oJJVcm+Vljne5hsfI7lJkksJLYTTwRLRwhEDWTTN9JCYqt6SuzWf/wZEgte1GpbDvAo9cLUlgZYWiKsezUuc2weO6SGH0PYGe60Q4ih5LYeCvGhLDbrGNRCS3XCblIqOxJG0sRtf6ppolWvL6sbHjlxs6voQveyh/bISph2gZl5b/qKqo1rIALh16CnlkaxEx0Nu9ueB2eMU0LerVQ0A2LWC0QO4uC5SFZOggO1D4cn9pRLPnV/kgXyOpfadmkwmxrInoJvmW0QU8LwWf30PsVjYeDMI3qWjz9GjPkaKgc0k++o382me05UZlAMOzxnRF6i7bmVApP0GXZ9S6nwFGbh53LwUuGHSWCpAgQn/E2Tfn7RR3m4pdmc4IRhpPJi9HalyNPVS9ndrdlKzu0zAYujXLYkaveLYDarhfD3wzDABT8LTSLaxRPqz25h97BaZ+NPkVpkivN6dxXwVC7iCtMJQc8F1V56WAA8SgcpbJVWfglqdFpm2jAe9GXJMWA09Vt+h+S0HvXaQn5eU8R2F6MH/5OPHO6A1S5XCNAm7CWhvrSJZoQo/Kz4sdx6Nek7lpRbHKwo5U5ir/Pgkzjji+ozjyw1cdqu148WLih8Y3HsqHpwLzSsdZ0asxtQ+5Uz3uNulQGYzCqpAg/o9MX/AsfrVfW4UTSlUwIEpXTg52n+pObY9vhQzFPZwQsbqSsruqSIvvwk/4MBOt/oIT9tjyhB6MsoEt7prm41Z2fuW/mEaOlIvLUXOp72qoR/2IMudcZdO0Z2avKOporgEWPrRIrGiPUxKVTDYH4MVZfCEL9pOOC7jAPiE69nL/PTMtXEoWah8oMmZpuVWRgmUQdn9mT9Bqz+PrjnQRT/IUH2AxH7AsWQe3pdvhQbRptdlxh+oy5lddsiwVAkTe12u7mnQesiwtYsyt+DRuTqCKHwQVeJOZUKIEDBSVLZ3Nl4rUmjn5eNmRn8AucEprFH7Us8A38xkfyi7z8dFTwdF5wDNQbtlYNKLXCh8QXRgqfRr2/HMa4wYQQ+wf0nUOMOAZaZpvc4Y9DNHkmhp1ms0wzq/UlF0iOYTP5O7QH4J8qdIB11omXbViJKYVfIzf294cLMwQ5M2kDwRsWVKPwKjg0gQlsE2a3Qs1Vz/rBwQNTdI7kKA4oxiDZzRrMpj+J73lTimi5bBbT7Y1vRnsA9XljuOQhFUbKJDoLpZhf9TIuZ+C8pV/9lj96EXSPJPU/DRdTKMsb4N/NASj68rZq/lgbyxnDGoFxZY8sFTYKU7oLlY9VsXEXPeX/teanurbkcwqlql+DyVluR+K/LvGAvOyAXOQb1hkKoMX+S3o+NGaLiimeQZvakC0RHFsYfGYbcCAmKhZ4Y6GNVVaVXt4leYRm+k2X2s1BRTvIUond+SF9NdSwN40JC2upIshkp8fqo2Ne5EVcb6qNhbwo+Zfdb6tVgnsTh0V57Ytw8LWAw01xznQoIBMDoThxw57XHtOMJinqkBJ+Z1ODCX/KEqNcHH9iRld4dMrT43hfLwJSG7kLX+fk4Cs3K8tEy+5ietc6Tpckulu3AkmWx1l5J/FvcM5SSEwg7UroYF7EWFaJaNTyHpiFyJwYCUOGdgux1unUGn+S1qklF7uowytZ9XYkCh2EXFhAWt5thX5DCKt8LEZ4+/n/YXNDia6TAhRBaNquiqhG6g8DImHgWn4iApY9NV57AZCbePUSYwoGmhmEF5Gn6TX17dwlQH5l5zpCvEbrjbVYlF2nY3Birnj3XknzGW1lrF9bqUNxJAEyidkkycQKl884t6s+lx+YippcqnuPz6zj6uwo4wTCg73y96EhWUKkaHEj0oexrVkeQIYwQ0cAom3tdtPrw9MQO82chueHTRPDit2pmuRi6t0Pb0fxe1IYWFeceFZbAJ8y2L2c8VvhIZJodMtLbhu9HAClWuM/4CuZe7SmZMjupE5zbkZOJQkf84xcDrhDphCfV1VA5x9JegKgqxt+7pAMwq6/CCoo0IPkv+5NKQeYOStK6T12uZmJrsT7qbo36wWHteAVINnEr1KvGNanudd3G4nJLsPeiAPPr+hd+qVBexbxxpAlWGB15GcRQcyoIcLS1GQ/B1Sdby31i52u6Cr8fFcDiaWJ3/Ls/bzLQWSfxmLRqP0Ks9vc80XlqXsNg5W68qmENiSfZ9wc0x7cFG8KiMqVISzjZV2D4spd0NzWAi1Xejd37Krls4RdQTStrcRB9OYDoc14LoPsks7wM7IPbMG8zBP0ZwLZvh9aIROclS1+QWE6w1HH36DG8L2vYAxMc3SMAuKvjoKW2esXIWI2FRGEPBj0zgRZCYSgEpve5etKz4ai76GOLj7szskv6TSJ9FlUQlg8MUH8FXj8M6JB8I70bpGyB4EyGV1NvxVNgTHXWAF1AK7XnUn33DNOhZ/+vUWMhlmvwy0Eb1+BUWCeXlKDeSncrY1x6POpDP5xqy72f/KG7RxQGKu/DUcFrBEJ6jeFdTMf2SMGiKX/EbYohSIhL332hyAwrfPX+e7z3Zf2kTMfy2CrIpIYIKbWQ==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436208, + "Value": "121191102922431314", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "125224", + "Method": 6, + "Params": "igMaAAQEgtgqWCkAAYLiA4HoAiDbbtSLkYiiT//Q5p5woO5IRmU4m408+h/Sf2iZ/TrnGxoAA7LBgBoAG2ea9AAAAA==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436209, + "Value": "121191102922431314", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "124718", + "Method": 6, + "Params": "igMaAAJ5dNgqWCkAAYLiA4HoAiCnHexDnKrIS8GleRb3cp9Z31bhpYL0Lto/1Vrts8JHORoAA7KHgBoAG2ea9AAAAA==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436210, + "Value": "122754344480600755", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "125311", + "Method": 7, + "Params": "ghnzbFkHgJFB9ZUkeuvw/CjnPmQkyGv2senXw0MWrLX2NsQ8KyybvFG9T1mY1OQokRpvTXmUi4hSs8ZCS25Qr22Vsi/RIm8Ws2aqlkrGz6DpXz7fEZSlGI0Otegj+WnmPGDIyqg/Mgc+ekmU4LWdx2K73jaLalvHOe5OVCYS1eBnwwD74gnItIa94i9T8r8d5/meEGfJN7VEqZmADlCE7lJm8/3aG7I8J6Zig521jU3JzdBR0A5q+oXPWlm+p80ACb6WDr56zKCD+rbkPyRdhGJ4vpRO710YjGM0VUh1kJUYxN2MPk6pBnxzP4f37s5oVM/XELbTf4j3O57OG1jcjYnGyHZGLXHITL+2Pj/lIEabWG+RvqG4KBrB08FfdYEnyvzOi92HlBmRzqNlw9o6bhZWoXU3Qwr9z/R5fH++gW5+7Bh0BCKo9y0P9Y/WFXq8Sjq/RwSRhIOfYgmZI4zLDMFNM2Zh+lzBixJ4TwYBUc+zVgvUvpl6VpggSH6vB5+yZHLVaH04ZJjBU2lKZFPKiDAtChHfgen2A9f3tMiidX1lo/HPvRggmodcBLm+T38FZ3CefS5GPIqSr93ozb/65CC+qtiO0jT0sXq85eXBx88hvIyxhOtBLt2Syvo73Bwbl3LFhG1jwABcEB8JtsZtS+T9u7d7ZrGglrItBl9Mt7aKZmolSZKz3VUND2lLjWO1MLoHcW0a7ZOCwAh25fJThifhrtYSLG3X1gvQospCtSPghzQ6kCFVYBQA95Flp116YDAi4kVYZICuKOF/K60yb30BCA4XBKlpRHvd2p0p2S5/e1rMDv/dQFPF2+SLspfZyDoltC6jBIOu9g0MxlNsptDXQdx27lp2dRVWgFRAjWqygd5OEAc7tZoKjD0KGDvMctNA7DRxuRI24hjL9W78/zoDTot7FE3CHUEOnwqTonU/NYuGsVydln1gGHpcCwwtNKTb84g2MovBH0y5CWY44KntPoR8PM65mSTUq/kTKYYVRZvJK688AAoOyPAtGftBTq/P1UFvJ45QCKCOcweRy++OXD5rMeesZcJSngED5xDE0U9tzZl0Joa3tidv+a4SOLzWVBNynpTjp9qveDNqmy1xDcu3KQMiu62Ej0num0H9T1cT6JFVqucaGwH9HBmaZZ41acQnLwt8OGPLDNSM/Lg3RUpVnRwxnqVab70lQ2OI3Qd/+Tm8hcrOeYxCN89saMHILlf6hoqFKOEe1lzad3MAIZfHL+A+MSIQ1KlJJUEWrV6rGHpyyzC2W6eDQvC1I0n94/2TgrCd6mCJ5Ruzj6l9Y37H3D1XITFxd1E5J0Bk3sqLPwR1a3m/fGnruCgJEQyudBkmfrCYCFgZxZwTIlzj903rEI4Q7P9poOQg3q2u+5F9Rnt4cwQiZgKxX+zH6sVyaXWAcgYIPalW8tvKzCAiTIp0lvND39/VmzZZEpbIOnxS5pq7IzihgkKc23ikZgGjnEbwja5QcmfC8iaNrM2kZ1QhHjXiY/Wrmkq8kcT9AM3gSdiH3tEDMhCOwkZxdscosCQ3tqJfbjsu/fIWvLhz+t4Xl7g/cTuCheT6uJVnScUqarYqtwy67MMjZdPDDhHdYHwd95Et691HdrKNf/iKSms/VMsTZja7v+cvwohizjKS+iqxdc3rpjthC3YWuh8NIdN29Qj2ho9I0LyuC8xH1oQU9MoioMFfed0BpwOe3ZA1f/sdf34NjofTFlcUvBQbCXqvVqQ9bw/5dhHnYS1P1B/R0DHUGmjvgEQZwyz7Sv3fkPQs61UNf/qvGbo7UZIQSaUKtrS0iZqk4gWp7lipcT4vxQoFuudHhrcxsrGEl1j4JEqasbRn4iNHsZI/RTzf9SpGX5WvuK7mBpkvKH2dxsc+Bo4DKUDL+qJs6tZ7ZAoImhREy/or51GWMB7zb6KeNYmgVxJ0rEHG8CIM6aL9raBuLUhe/2p4v8bIGFvuHr/nYVWbYc+o4Md7mTLwGKBJ3MgvW4ZPpRoWDoNquR45nbn/h7EYcyqPUqXPp5jnoaXlhSibJKoya0ZUjqg6xwO+OYEAVI/84bM2FuY3Tct08ovH/vy/msndQPSrvaGIMPf1W7zAia2gb1QtyrcBGO9qjKY/oKtqBCzbkk29I3MQXB+Jkou4zFELqmPXJA7AOcbcjJj3Q7JhugatnrpXAZwMmT2eswLQPMXIEkzPOEWjRWGpvDGn4If5ctsOKFOEVGNMmRQU6kEVFG2WhmvrIyNrpV/x7ZT4B8tgY+B2Xy7KzyH9Wq3m8RErW+2Rnm+W/iz8UFjsXxttecF24iEv3XbMpDd5p4nPus1dB2CHxPg3I577fIAI9EQGEZdCld+0/ozD8HaQjptj3dj7Rn2tzsYyMOGlVLH0keZ/iP3A1na3fZtW8dwLpv0zulq8WrxvDGbU0uj3cK2g0SaK+rLk3xg9y+pxjANpYaaMTCou/zDxFPB3i7GVweEwT15O+Hwl6tx08imknRz8EMPn3QblwCAGCPVnDqxqdSzBCt84FvOWm7zITCKsP81TASQIOuzyIg3NK+OkPnOF2vYv/m5myNaeYiZ6Xg==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436211, + "Value": "121191316741862868", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "125332", + "Method": 6, + "Params": "igMaAAQEgNgqWCkAAYLiA4HoAiBEApDWAwuMyb9ruD5ZJJsvC42fCtWbni3UpVHIsA+NKBoAA7K/gBoAG2ea9AAAAA==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436212, + "Value": "122755188912942362", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "126003", + "Method": 7, + "Params": "ghnzF1kHgIJDgP9ebAbsmyXUftNddtp0b8raBEdBRXU4P04G6Hql4ca6vLHlSu5b5/QePMF5gIKfutQWgB8mRR5/yirGXrJ2P+IiraGzbb5rlZlHVaZL8mefi/qb82Xl+syEx/ePUhghMgFGyA0Gk2Cm0r96zitAyL5gI75WNUIM+MgUBicmeCbwjOvgyS1nuxrPtH1qFJENx2ldXPjDK3BkhWVOrjv6gsOYXKjg/u/s09hLYfgch9EJzxvgEyaecZyPjjATnayzEPOb0W02U3n7XGAoXy31fPpEttRO6XC4rsciD3DcTuyg9YUzRsTz3MAENDEUP6U+JdOM5zueRQ2mIvcXnAbst6HccNqCEpayZ5jekOWugwahnbiNWhBlkvEtCpFPBwoIOQuDDRqwmWqGh34SDcyfJcQvQZ8tLSbGw9jaTpH9eNeGrlRtMZTKzpv9+qz8vZXW0OmLTGc+fXv8x+sXev7QX6jSiEna8OH64rwJVIvnUJW5ab6+MlPk9p++lRLetLRjOYZGHPuwnHjBuvtG30krOWG+K8F4jY+oeqfXbwqWpBFP1Q/VXNfMA1IkKiPWV4FKZaIJjHpmA+6HSinjSJ0HSwfxgwl5b+mMrmczvw/TawXjTwLvvEvaBwmFRQI4uBEczG0z8GVQz5wlXgRTZsAp0uckjHewxfL8EBKD6/K069OnHDkJGeTZ4eh5Pi0q2axChfO/oi5q4hEBtUI8MilO/OcSsvZOn46ju+VmvC7tyASwKzhiq1NVwtWl7JFSIo1Po9yBdUbiB0AMGLG/gfif1k2Dq1KlWdOVtEKLR4t48ZdMyqtBnB2qtKp9/O9AQ45gJNEe03VH0+YYqz19rXHOR9yGKofWthD6d2n+mRtIpkznwUXphRW+LK/4J4YQOgD5akT6uZl9G/2Mf1ZOMBLfLNG3wblZ2wBl8eKGqeX0IDrhUrLinxT7K+VU4YlQ5omQYUcCtRnLC/bRkPAUqEQf9QdkWGziKozCTpBjEYIUXgW7CG16ywfm8Ff4Zh8F+6ymwGZgk79p3PkHX5XXHmDff5OBSDAcA0B5iFLN8TXUCkKSgiEEHsI0dQ+8koMCJZddga8UDt4uyhDEFiPCj7zIMWNfvWQSFih2KUDPpqUXGTYMoHRS/3yIw3sSBJDSCQ+QhvIwS9S3OuzVLoaM8aNqIBQ1EfjlDhjp7uU4HF56NHdvKyDZlYAeZquC0Qf4k4SC6oq++pgb+S/hEvBF0ktPgjVD/2sgFNiZVGAn9WnLkFpbnM6lZAtIG5jLz8OPxI+mxGkDOpo4DKyDt6XJescmzQcE/I0Q/mI0ZQGTRDiCL7a+Kx+934Av/0IKMmwnX6wSikh6NLTxQ0O0XrLp4sIQwMyifWKdA1xHWd3MszIN+yeLjAzKEHAqCmjw72nPdwNqnT82ru8p6O3gmIK+k9LEHxDHZnY/ComfJM0sgjgtDV1WTAYVsLC4CKNCEEhVaJk/WQxHm5BvdUO/bIvCIvbh1sT2acmB6+9IhXfrenKrophuB5WR4rfJ2QD2P+b2RoaFw+Rudkhpn5pqaqbvamzYIzYBTWUghNfRZYAzvWnmW1Yi/CMQA2EJvrJ8eK89g5WddcKk70zhQEEVitH0+/uUvSf16desJG7YN0IbgrDIwl9SPyB/va18AjjPoa4dDgtVLyKsfbav7XkG84fTlsV1If6ALPYPLj3cnwOyXkmcCaUFWy7hs9dzobIRbDP0HaK52PjK+nM8h4q5Pm90d7OPu0fSWvpY0/C36IElSa2BKbwhQuI8EaSI5YgKb0YFZIgK/aHud+gFY046cjYNMmi6P3Z8qkJDiK2vFgiOb8sHX9+gheVRqeTmeFfvy7UUP5CX3NnJlZBr1UY9+KAUfv3qFQoD9q1DN/N5SyYqlwW5ZwcssUeq14FEbzQA0NKz/xHeuQHm5OwIWtX+LKc3Bed2ir3+lwbilYLYoSZdr7+L/jEmB4SdlvTve7L/Ol50cYeGqzp3z4VZm8963HBfV84yCpJDOzHbX+C6wUXep34mXtqOBLyoWxV7hETnWLi3zYITzPifLTErIT6xK5B328z+wXuRc8jKMnBxKELYG5wanSVi7Nju+spDsJfOngOczoxM0pAFNUgMkVOrhaUr06jwdDH4mT8BDaNZc2dPNsQSvnsbvUS0/tVN/qDiuYdLqhPsBcg7VdP+p7hJXbn/g1UCiVH1/0AWGPWcfkhRAyTmLWqApj+NycahxHWVW2Esia0tqQCde5tfySwD29nOkUwVl0NjBQ/VG1vN1wQFfqFqdIcNFLKjKGwodMtdlLTsToiGVWVF60FSFjMMiKcyDFpLIOjsdzuffKcFNKyDmxKAjOiIAyj5ycLuFQOAsOso87myYlqVXESxZMtlg8grpQLhD8dr0CCAb7cDI57DYvLokt8v3zPMIeNlnUxCYtnUowU0WCt3Dj0MZZmVCVu+OTQ7PM6MBKHRwdfd71odNdQsg3xMaWxBVXfQOq5DGnIVcbQXQBugYQxbQqisJd+BzGDgZfQBNg37ROalKX3zK67hpKnrDAvgDFKWDdxVZ2oUBQ==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436213, + "Value": "122755427313041337", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "125374", + "Method": 7, + "Params": "ghoABAPrWQeArYfYxETxRIaFPguS877wFDzVGUNyQULO6JngyyekRrzVRKk4cMLu2gASPBwdM50AjzsEtQgQlcEa6E5vPxpYPOkqpcPfIasS3xCgjMw90vc/vXU7mAXnxUh4WbaZxGbqBuaxAHA1r08Ht7fc4ZyUCI0AawFrMioEFQ4t0XagHLbZLIiH2CSZAuuEOFe37fVEkv7gDdnP2jVmMNkcWwljvM2BHNN3prcjqB6Dss9oZC7QhjVXlznV3id1Ie73cCbkgPjBZnGXj7iOFXJGe18G29iRcp1iifeeh7NAaMKUbbI2t/JDbEutpwr9aVEn8LmAqu+u6k00Jucy2W2xfBBCobzQh6cqpFkKSTPRL3dzr8+3OG5c9j6UgaifEfehvSf2Ftfk2HFUhiXvuk9GqlYNcGCAGphGnGnCHklNZfS3A8YYoV3f08IbLmRGQ6hXCwRvqJpV5Vm6NbzWES1eY40fNCN60l/qduiQA0h5ruV42gYNoz5DH8Ti340yURsPnzxWtJrXw7XItTh0ILJUWjxPBlAPUqWdzk8HggWQY1ZOksXSn+6FUG6EyayU79yFKTWaqgsZBK5GKc1pc6t4t9WqaGznJ9Is4C4n01KFoiO3AtwMT33eD7q6AN28SidKZqU/DoWg7qRT90Y802r3qFNyBJ0QlZm5pZfOXbrQbw3XLb90Hrq7zFk5dq/KXNwT2YlnspEydQac9k87KoDSioOdLc9hGjLt9INdXNYpztI9OLVJ2twA5XpvkLDDvO7Q7elRoqOf0FGXgQZITS/fyqY4rWBCo8RbEgwgw7B9wZTIpsSUfo0K/SYUyp2MrLYxXAc3syWCf7JE4mJaEBDcGu1uAL925HkVzUkfOz/z749VOeRBKn8HoHamy65oI0n978+wBQOc6BFfkr2odD15qy8Akt1y2zx5umYCGpMoCBag0n2fTLFWby09smfpVWtc8kCHjbdmVcZO3TLxLXRyIHdnNzk82/BKoKIkMUZ4Q5pqBHkZQeXpSU6mdSCP9oieUQuouJDYrUIm+pLpHmqkXUw5MHB7iAAT9fqn5qnYzBRiIi6QjtlwfW6CrYy5C6u8EPCmpJ+1rmMC8nPlXVM622oaGHK67CO/hQiZ/UREDsNDjrz/sddVyAaqnQFN5/YfZXMDDP0RqqMN2cA3oriiOos7z7wtj7A89wQGHIPMRqEcMYIGMLaQtfkhd5ZDJ6ouGt5Pjr0oAD/iEIQL+WHYxeoBsQxZkR543qxDkazWFc4IPOaLbucDKamyntusjRzGXUBgqqb2TY9xAsJIQk+oFs6GpGx46VbdMoUojHNAtEKxs6mDFtvu9un6ck9tNBOhR5Xstwc9Keji5/cjDXVOSyhLPBJqnM4tqnwaCOOzaGM/rCN3Is1FhgRQ7uq4nf564TfyCbV6E00zwONTAT32Fgle671Fz4tqfC3/yZiTmmgulWAMlxTrENp0by0tZf33T2BBgiDWrKhBNwyiaGWS8ohgLbwChxIbWumuRzkK0+x5UvyN+4wkSoGKzUSz6325pJ8XqtN/T3gJEN824W8xKfQQy0yZm2I7wfORyxTpYIeJKh20CsPVSLTOZfkAqAYdqSBHjHkFi+9iB5BPXwXlpjdv5aYqObkoEeEDHEJKZafwBb2sP5+OjTJ6StcmHqxDIRy7BX4bQSBumuWdH9u4Al5EVR8hFX6zFuEXiftAdBxPl1POH4lvvPAYGiyf40N0CaUOolkSBNZFZPP5OkNdrZEsSZt8P5tCuP3CIjndC6IBaapY8loQMXW1/JgeDqLh30PxgiS1BAKHiYwBcl/3gfAdnNpvAlKvrMh7uem65Xthewa+Of1vw0yKB+QuHIdZfWrZo17IceYna/pC7qmliXqvRYrJ2W0vRYfACuYqZe4PIhPfxvdRxPBzuMROkoZW4oyzF+gYLioeN1mzKlMuLQE32THuOnXoPp47yjs9v1Y1uEu5ljDYl83wP4q0pyIovsUcot8DyO4DDG4l/H8C+dEq0pTlyBIYLpuXCvByd59GLRlvGpNH7Kc+J+HznmL2jJjrg4x6tJqFRPO2VLHE4gIVAMnFJpMFuLEYrKRQpskHLrQm0sE/nhoMvOQDqAvyljz/oNd4bMLL69uCltJ2Tze/Sh5UOgvM2dMDleU6aAuzkNKXqzTldvOh016C6v/nujirC4ONeRdvJs42qCkIiEcbdKZfjwzrVKvFzkBu5amcXcp6lfdJbRRwWtIXtTj/k5Z4iXfYia502kfeTrnY4ZfZzDQHhbcIFfnubgvHrhOOIeyBaN9oxdptPdfk6KhifFbUmAgn0G+A5I2km47Jzi8luRn+XS1kytIyvFEQ4blNX6UB8AULsy/gSJ42Q33ddht8qQmfbmZ5TLl0Rznyxst3/75ADTzFXGUdGCtkm2ECajdDqVZeUPrkjBEmtN8wK5BFD0L3+2+qtfq7KWX3/dwt2sd29ywwUWUqEjEtqhhLz0FoJFh7RlJBMmVt54aoadKgsX/FsYGd4bL0qnFxvhPu7G2pn3Nmf2D5wrw3lNFv4poSivWlrs5hnZBsJ/E3R397" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436214, + "Value": "121191316741862868", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "124431", + "Method": 6, + "Params": "igMZ9A/YKlgpAAGC4gOB6AIgMzeU587paJshliehEmgTEmrlgDorWeudd4+9fs3VVAcaAAOywYAaABtnmvQAAAA=" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436215, + "Value": "122755188912942362", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "124613", + "Method": 7, + "Params": "ghoABAOhWQeAp3ORRqFCEJyn1odzQfqnlfPAUdJD2TmN/eGnJilg1zWM/CGBNuVoYNs8x5VOQ5PYtUu0aH43R8WC6HXXjTvysxrB8D9iIc74XZPqCEPlKNi//S3M/w91AU7Qk1q5oA8bBGVePIh48hrTy2gd6sOIwq5L93VQ82NGJgn8WlJf9fFtgZYBs5/ckBWnU+k1JAyghx5k22nwt89SgvJoXn1pIphpNvKklz0O2fSLMiA+Qt1dLj/2KsD8OYHwWgSqlOOngM5tDpOdy1T2922Pe/JX2Ux7oiPlbLNqTzAQSAbqZYjrLyHNdMCFiNutOYGMhzL/sWH2+MZcagSOi192MrG2RDWKwpA3k1XTZaNnySU7OHTIwGTkyN03FpfaTMTb6YlTF+jriJKiGsfxWSVTS/5KOF+pKuzo1hE9AyL2oGSTYqkxYRl8r8UpG3WqVLTChxERpDISLCohfPigxH7w+d9UAGjxTojKBY/rD3lTa04tAnFyQ8S5ABCv+PUjxkSCN9rJl2D+UWfVrukyTc86q5xe1aRiOxS0ELu4pHLCg7dN4kmZk9w504ZJyPIrR23L9obts+1bE50tHzaZ1xMwNJmPjFXpyrOGsBsxncJWJDy+QHGXqIESevuNd2ZH5cI5XfVUDzODx0Nk/l1LjB/CGIrCTS/9+3rbrLEG2gOHJxPGahd9+ndJEC82cvmXs2CDPPOIhYr5V1W/C/5vgKr58uCcRj3GBxV8MLdYpegnqTEEiYJAwt2gQBG8MFoHoV8fpMxwt6GnKWmkffXV28FSCOIMx7dG6WWm2Q6x+gId6IRfWOWHtwBXmAfTmHR3900D0Zl/q3L3j+vpwEtqWsRR/b0r3N52zPpXfXnouHIzy/UypFKabZCoHy1CjnB3arfj5zh2ARV/V/6Q6wAYlb92LvnYKDw0h4NLmXVWvGUd14fKin+asMq4roQTBkdyybZE6de6hA68sol6XLoZJnkTJFhE9EJctCYdEuX9VVc4y63fowv+qkIgHmtBUuN0nXZd7YnPkLOy0WY0OvVFJ/OQpEpNYZx/O0GTTmh2/AxYoLfzC0fjkswBBFrdf5RWBYRbO0uNrl1PBOBU8lUub+OJkKXtx5nXunu52iMTFR4KmuXGlCJYfDUN1PV1ppfQNIUtucwAAa1Z2ra1/tIu7fRfmZF3r8HXQPXvvJ5bap3kznFXWVHoRJRGWSJcBTA7R/cu8f2DhN+JtCnlIO4HIqwsB5bto90x3QnNbtDGRhYW8PG5mHxFZN5EV08VVv86/ZFiI2BzrNP3+tKNu8APePxE3ZXLHJITdXCzLJt9mcP1wIJr8o1wRr1KcVwkUxiz8x1+619pi3bTXU32WUoraFlLywnokTb+PIDCOizEhngkVDvfWhDHFiSKvuAwnGzpMNBKkjTQGbsLx+qr0cwQ2SrY/JrTd3u+yPGj2srS6imLjvqBaveer4zWLVsgM4Z0ylZ9f437hJZO29mxQqRhwMpOm1OdSnif/4x6OPnbrGdsRkcMHtnFYQTgLO0Y0EsHrRORp3J/osl+UaEeXcvRFWoLCiFnQ2S+B996Fk0IiDIl23/z2d/fthKTXbEDOM5gTm1UDzV7t+GBRcp6/q4qaqm5SHSRHfWg7qjVPH3d843/rMBUKpusoUE843uGpcv8NELlDGT4BivN6j8LFQKhJ5q3rA3Tpg6IxZ5R34kkkIieF7AHjLPKRerYHU79/cjTx6XQOjpxlMDPEJeS7LWHYUS639XPDNARmimbnmueeYWE2aorFq5sy0NauBZy4JPTuOXNI+ZclqxSE5Mi8X/E8uJS+HfQjXvAQlIJLFHfV8c8AMFnhnoojL+NN7BNAie732t3Q+gAgxJA8ktg24V5WmMwmOcP6HcK7OGj2E2xsgbOLMYhyqcM2pP0aeloeQKZAnaZfe7tGPTvSlsP0MIiCdQSIrrOG59DXJY1bhkJGcwKuIgW19tWnDUhyHcdwSJb3YC7NbOepDuj8B2crfS/qbPMyZwyiT7eSN1oe6G6YiSqSjWAxGdete0LS0Gd8mVC8LXMcG83s6dJlv/DzscWopMRBGm4URQKnQHjL+iI6f3XeXIswX8gY1hzF6v5wq18FAMe7DsOry6JD3IVh/M666sThZFmgWHfdJPR7ccj4APYLM187/Elx+uHDzAI6J3xQ8kT4qenDb3WNkobShbO44HF/QuGUMoVS5L+kDP7H6B89pNPdnydbT6/Zi8XYqqnpuxVogs+uVl5KFvW6nTQ3pX+IHMh2RJkZzsFrRBeNjMBCd/nKL3IKgO2uiYYHNtEYG7/OjYsp+6WrF2HWBhpI6E6k1cLsZprwZLKVEBrwJunJhK55Tyl+tGtJerPfQM/oYbkuLUuhtmNkykuTeFFluQSst/EuAeSQQGDYqcLtLhXfQtLbCN5ul8OH+iSHYMQfb6c+LxpBPSD9ZQCQlabh/DT/cB0Po43LpxBgAH0syuQdWrduZluZ0sQH6ajM+KgklRnfVgcjRfdnYkPdja+uXc7MMjBgOjJ3gAGWzSWnKMYiUCck+K9aBuGUqkIhlWj9OyYhMXd" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436216, + "Value": "121191316741862868", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "124919", + "Method": 6, + "Params": "igMZ8dzYKlgpAAGC4gOB6AIgs0GRwKSjB0IRGpXuRZfDiF9WnB4ngEYt83ngGO+VrFcaAAOvy4AaABtnmvQAAAA=" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436217, + "Value": "122756027681018569", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "124924", + "Method": 7, + "Params": "ghnzYFkHgKEKVAhmCkAJpOz/mdVPepPeJ38cKIA/ZKa+fY6f56oJoaK66AQtZycEI5vxZN384pJHtW0CvfFLwWDeQo2e1b6v9kvVLSQDhBkruIo2sJ9I+QTohHw2+WNcTOvWGKwZzxXt+YwG8mSfuTj1XMC9Fjo7IiKaRq9DG/kOLU768Euwyb1onzMgumxiu464/c19po8wiPfoLptSu+4la1opV3K0Shf65mY73vJI0/88So+BKxS9NYVHrjO1ahF0ZalYOrJ0u5BnSjUYR0Dno3NPUMLnRgAzBuQgi1PbNFEdP+88iB9EQeN2nkt7nxXj6cI91rGf1Mo0UCKN6W7IprNRRT2Go19SIBIRbINR5YxkiAgFpgA26Uu/LIKhMxr0XncWrQ95g5MpGkNJCb4MjzZjIZLBAaHFO/SPKYsGLNWqDMBNC61j2iY2E6gaPF4z2BiSOI4oVrP7dWzq3L11GpR1ekoaCm5u99JVGZQugFSey5WR6gH6p0zGUBT4IpXuASf15YH7OS0O+1qYCMqspaGPdhRHAEm32yQm391BtuaPs5HoyivMv2nJOmn0L9z/FIQDy6rv3snWJgeJzVYu5xvt2kx1oQNpON/h7YDVLJkC5LgzbpBcKyxOf7xP+SiTCMv+egvO27PbMMoRjmAHdupjJa0pohW/VQ4apLdIR1T0tfMmthVEt3Om6zbcZzWZbGr09pFZtx80B8408EqJTlqMNPaav2pBL/rC3YOIcJP7fC+nQr3tNyqqvNcopbrERzW72KhiY3coZETmGW7txw8307NgNs1/zX8I9gP0PgLcof0c+e2719Q94TqYeGN8d2NpTJHXNmb9PpQc3Sa7cNmAUJwYjaNeYrV6X2aPEdXOhspJH4a1Fgl86sHVQwcSIActIAdGWLa29nKwMdrjmnM5ulGnNJhmCMpnK+xdQoGlTtIWThf8OaW6cZc7qtvc9jMBZ7js9PtUJyVJ4pf+Ypx+oEdH50kfMgnLNMpTvWtBfz1I8mmRiuKpvgHuRv+PCp4XRqL01rHB191LPZcQmP0F0nLfd/NYGRVbCZY8+HszGMuez47chycDZFHJOMO0z486n4JIb5QAQ09UiVJWflxEW+Jx60ja97W1xbCaPQTgaLPOtnwLwozG8LQoyBYkP3cFZwdDB6Ayz6QKFfz8K53o96K4ss/DemfxyzwhcNSsSdKiFK/NlNgy9MsHMsTTJLpJVpG4fNxfwc66+EsT9Xink5enTx6x2qttB5Aogp8+uinLl+czRunYemMhEKNHgWKKFaBHaOpBk2BXAdhyv/Ar/EkyuiEIh58g8iZC69p1VnjBgnAb6smXmOjUCoMS3xY9WqJ81ds+0wU0HE9RS7ITliltVirMwu4RwYSy3c5rrmjd8FrKtMS/4fb6vUr4z5rkdwgxaoeGy6fDHlvbUPAHJrcPJMtIP77eTZakPMsoE++ynQms5b5wrn74LwbdxN28uLH0S0UnfV5U6UNGpvVUTv0rKdD5iubSm7FywStnP+fwvw/FSNE8lRcHRKNsV9CqCJACbQlu5AqeujqtaSAcGBxU1Bmq/7jk6qoIrqGtBwT2tuMD42Q1YTTmfiy2MuNPo4pqnDEj56ZVfwEnGbxOn3NBpGC6Kq1V7J3WOPd74XUDL9ZcZpBGexcjl4UA8+aWEhR5Oh9hs0kYGeOEf0pq+NFU+7xlMJIZxGkOoNKccprM3Mimjs0elWEF5A28in5bFYNXxgYFDlgdA77e/MPphYI/n10+Vp6T67c8+pPI4i4cTc9VrXGL/Cqf8JXJ2+74ZoCAcqS526o0ZmqYFVALsEFpkkZZjNHQyaXvU522cxL6XioAPwdYf7AXgcjG1xBn15LQpXTwIo8Aa8uG9VlVsCdZWEPGXEo/JeIU6NeJPATFeETnAr5WZLEU3RSWhuK59haC6zgNeBdSO2Y69sdTXa4AD4ofvrJ5VYjNWJLVaB43Hh/vw7SLeVh2GJR2dw3r3ZGXcuZp5yvlbl0c6mcNM65bgXvInVUDYOyj4My6NqTYafTgnUbMJ258bq2iqFIo9anFJhelSKWXBS05Zabu0JYzdO50kXu8vwDit2s48WJ8LKAAe/Z/XKP1btErB0Od/oK4EhFZXleO0dxN0IC+4hjebTZCWj+LrPNSiPG11C3EokL9K1zYOBi4/IqMKJfjnwvST+3bGX8ZIE0p8mNKIo1MxtU6Z+WC7sI4Dv0Wz5uMgLdQeII2dYpXM/vJ5WrIHo1GjjWT54qoWaUDZT/kUBi6hCjsd66akyfnEWc/KQqOVWlpO1C1fHXJoV2sUHQ/epNA8JxjG31P9zSkoQgi2sJz6FgmE+kjDyA++o3xoV/dIdXQYFvU/SwYVhcoRI9Z0IatUUUAAFnLh4ghAVALs34ipTP3/gqFILQ0sXGdojgpMtTk2IaAqzcl8Fy6SJKJ1wao/2h2soRhhDS2wLuX+OxL6bS9d4FbDZeJsHhos0ypA7L+Ew27VpxARFqWzTjYaI7ESVAbcKtByvbvOKnryzfLTqN3MqKuUj5wWLpxgOa4ZrUrVEy2DSUA/3xQWfQE8g==" + }, + { + "Version": 0, + "To": "f030347", + "From": "f3wy3ecnyzyu5jw2o2jythtzabkavohdqurbz5lhy2xylr7coxjegmg4spjfosqy5o3dtwsi4idtmucrubi7xa", + "Nonce": 436218, + "Value": "122756177830657766", + "GasLimit": 80315846, + "GasFeeCap": "1245084313", + "GasPremium": "125123", + "Method": 7, + "Params": "ghoABYJEWQeAooxR9+o3GVT86165jmu/ByFyCPuo+v7NVpbWUmW+OQYurHMUsNlpILq3vj8gr9ogt5pIgoJYHbi72jOcQdss61PuP4Ovp4k+25OSa/rY3+yPyiLYEiGS9fXKkHIeDjqVFD+YVh9DBU8y/sBMcX/GuR5HXSe2NDcCHzdCK6etyw08pi6ZfpOqRHUnh5nc09WWhHEf1WxzWxI0xjuITVldNGqTgtJ/z5KK+MU5kDRemjsYzfRne+0/nAAFMRoT0wlqrCyfari+zGCFioLxdjUDBYJBIfJhwMp6A4U1CtUvHYQemtDmgaABBv/M6fse6dHvmSKpUQd+wG/vRQr75oguDhw4ZfdFtncPNul/5HgwuRxGP1oou6pczNd2fSJxaEX4DCZZVbAnE8D9eUZIJBO+kHV9DiBD3YojyeOiAmybV37pH6i53hrbxIKWHV5Y5G6QuIKOfXl4CVnSAcsJKLdiq74ym1q/TjzHTim/Iy+gFs+vozqXiMEItcOjINcJ29I3rkSqBdvgx7uM1Ee2F4VfOiajH0neO1qEIIFN023Pi2uXMM0rN58Xcf6mqdNqvRONmJwkA6D5Pl+amr/ejAJLYr+t5Gf535bOKbIW2GT96MMloUOJPhpTWYf6EH7qfYmiDJL+Oed5nTd1/Ybj6a0bxf4Hut3sA8STJwyxNM5k4acpsE40zqReA5o5lZOvurizuaA7Z55zz4wNOwdT3S3vtSc+LuFh5XdA/WHB4Wg9kJoDvNQfjN+iaidHfuD+lQBpjidOSxWFOzD0gRn2Sn5yO7ILcaXJ6wVfGucnSFHRctgWM6wcLEzf56paC9EkxUkGtJ1HRomLYk1EEvwmUCV2hNLLKb8QhkbpxdUxs2nJ+SJWWh+bsrCkGg3D+G6HVi16B0p+eg8sqjBBteqw4SQC8pKDKrgPOAWWvz+ECp7PU/SDUL/3zJSULtpl5g4TjId2sjA4uWzVUe6vTFYms5XqhWDp/akgkqTT4teBjjvwpY9nRMV9pgwwJ/lFWl6RLG4SjyXIcajfwCEH1TgI0F70+4Sd2ejNThDCAq8z8saDwxjhFEqFvcqxPwDij7/s3NDNhzKwPeGfgYqfFw4N6dEPp0+hxRjCdK2Y3QrQEXIvnaaeQ6ZrA4+RR++VnK+d1d9aCMc772C5ScCMky0r13bYMCD7rUbVY1aDEDAcB0RWC6K+WNJ7YCE0ODeoeM7oJbmHtUJePg/I9bbwr7Am+t0oWcPTK3P2n8D/Sjcj8p2TAD/jb+wAh+mWCNwMB/L2GqjZuaTN0nq6TVuVQ45p0B8l7EXz2ylEuIf5CV8f27f5a0McUel52jyO4JT1MYCMB7whtj8daCWrG3roP7xQHi77RI1TISupdpJekKdL7qpCGXfs5GiKyfSbzVTZ05pcxdOBFpNZLhRJffxAl0+tx41uEU4r7sO6qaSIf2DN56le7CRxNm6JyyeM1lteM2S1oxeqh6YVzffmpAU/wUTDX10YLQ+HNMPcns+QoGfUNqsFCtKOt0xdX+DIcyZzzAksAOlUk2cF0uvb1HiUqW3p4bQ13+s6GJkFYNJ6kFWv0hWayy0u8BKJ7FcVWNnNK+dEq+VFhBD8dvdCJh8cJMuvUeqvlS/5Ya2XSAiiDlBHDCPEbEK60DkZFRxSo4TL5y0W7mEYDOazjn/3ja7htWtWH0jrlIzEPRXY7IqZXRUBq+M+6UDAO49IoFRbpuMOiRYOaFj8tI8ebAQwF4ty1ZgQhPKAh4aW+T6D25r1p0H92Zxoz5EMPcdWaYsHVFkFPNBfidBCh+z1qc0McCDuIijDvee67Si7WSvwR/15r14G52PZf9sm0p0BuQRigQm1oDjeimlkiSCFJDT2ljLRUKfVNBanGP3a0hpw9IMscUEDrMrVbZhhNRFpO9hIKQDRNAz9Df6MB6VecpltyjcSTePdB1+jPeUqsRK0/rT9REairNO6tp/XS3kLsxqNfwu0p9VoxdichmV3XXQX9TbP12DMVr2AukUNgI6ADifk+3EOsqNGhViPabsAS7/uFfAJPWtof1rZonOBvDG7K1aEsanKo7dJJ4PD/qZl8onGquUbSZxSQYi9Mhj/2TAoTf0ua/V6PTkPhQzkunfx4VVJvjFNMW/btgLiCes2gIc2MAOzVKE8j52jgMIWULq0RlCpd0Cpec2WDd8Yoz1M0/IMqYt5X4RRQ0LC8l2rIRnTbmFt+jcTLaJgaet424YVDOxYj5YPIirjqsrFdp1DDB/kWVEJ7oa+uOqeLfMMq6hFwS1pDdcjjS4diNyBZDbmRl5VQQyK4152svSjbP1egog3ltfpLLZ+l7tc7oKlNYJkwVvKt+jaUW8mZGwYEjT77wfkzueyKM7jp7Zm74lRNlrSohgE6cB8MNUbuiF9/mQvtkCxhzKzN9708H43C6CcTlhtmD41TACDF3KI4GLrdes0Z5zeoJXfUBQ2negm1WqP8s2rBZKck+ph0yG9613nHswjRiaaAepemfS2G5uw0meUBAQNOZku1CqiAZCIrrU6Y5L1wHYIwz3f+0YWc/yxDMzUNN3DvHdP" + }, + { + "Version": 0, + "To": "f010035", + "From": "f3ulm32bibybv7srwsq25dhl7grvbnyjyonmps5fgtpi65qsauf7dxbn4wlisjtpya7wsjuz6pqvzma5wak4cq", + "Nonce": 215185, + "Value": "122755917527069422", + "GasLimit": 59390153, + "GasFeeCap": "1683780811", + "GasPremium": "124986", + "Method": 7, + "Params": "ghoAAurFWQeAtwmODY6nZNYNslQuHzIEc0pqqAxGZnW3Qe6VC7ujHwk1Xi192ca6rc5p5OpkN8gjtH8VP14SzIcBIrkOF7zWxXJCvx9uP9oHosdxVO/0fDkbxuYysGJIC74hupDW8rs5C4s4gP/PdPqIUuSB9BoilL08NqOIsktoImf1G+gAEQcmZNpUu5kapQKVNSa4pvLZlydC20bbxgIewSSKl0MQiP4zHc5gTGK6HBCYpqHSRy0asg7pAsabZaQiY6pnz7LUr9O7D/0z/l2jRwyeS+oGBsvkTp9SN3rccdyCmeZCCut4qIFyMxuDmanYwnZsaE6HhFsevipoQhaIvyVuSZvafNHkPCrxOy8UCLcKs9r/d5CNcOwZ1gyYsJsaj2OF1f9yGKcCgAifNOGaneTxXKcE0RY5BMJf5WdzXieFbZmpHp5p+M2vJZxYwXtz/3KXqU7tki68kWtKkkO/PODVaTIX2IW4YGeDHwP5vb9gTGFrBOaBvFtcrdAlkbaAranT3593oZl2yxPVeuPL1PLmOA/Qykm+Y2lRZroA+7Q8FN5T43KhbMA2MXApBdNRZ84SIimmkenGrFg8kfHSRcI5RX4FglZj5vzrosGX7/lBwdhHXHbYU0JlaBNtBdZfcURkd+zBDODPdUuaPI9/A82ZWPAwoUdmExPgbt+r4WiawQBaVKNBrjLe8KTDpmb01kNovqDIgfDz2Po43Nsc3081g/jZhb1qE5Ly5v2ehvdfe2RMH3C/MDlEwH/9zTv5oFxge27Mt4mp5Yy+AnUW7LQVxAKHAUmFQsT1RdKwGl+L+sJNuyw9oeDLshVLi5ccKvEpOQ+ql1Y4fAXmN/8WK6wZN8n3zRoEVL9Ffj77Zeqa6eox92Wu8m5VB/7Tw41yduEFOWjzBhppWTmV40TES/x3RlPiZcxfM/7WRRriMcx9/m5o0naWVJbeoNFsqlI6mnfhFAGWi+LbQJCAtJ/Xyi5XFv+Kk+P03RjYw5Rah08MRuvNzwUyGYrG3CYALTDnEB4wd/+YrY8lTP3W2dZCeG/RqJSw6bh1DjY3KBzE8+XBnms1XCOQaXlp/UaPeccbJXlo8KqWsl6g9Q4oFgiJzW89nPz0GNW+1strqJj6N5Zvbpyd2jAIYprA7/CK4PzerN0aWkteDboB2Iq+7Y88mUfjmlyjrEOKhhd2E/Jsrabj5SsNVjyHMyqVh6XkzGOCoeDLszFLoU0PAieNyiOQI8RDRkKE1AkN+kIVJIiax6Ft/GQ0szKHJfdlRZC2y7VYE//wNULOiZDzVg6HMUVl6zZgSQBZPTlAOjn/chTZ0x8z4eNNdB9LLNRYzMhzdrfz6Fbl/yELrh6VSLV9o6VdadZT7SBqTsiLR1p9j7EAOU7k7B+Oq7Qgsd6eb11yEE+0LtWWpf/xAVUC98SemuUtw+8lfFC8xHBZ5RHfpgiEYVCGBPJWe2ZbH9ntehsZ1XBhOYpk1m3Lg6HP0y+J2r8Dh4xLzLaRKicTNYAnXPeSg9zmib5m2RWHtOjOAvBzGWBW8fDi4MIKih5anuVG6pFiYl08opds4CHT7S44WXG6/T0yode9aculJD7zX/KsBmpYOHbVXBwmjtANohzfZE5AbW4vC3HjPb8xOYplLUGM0VYxk/jC/1yG93tVFX1PkRM1dwtD6usQAaLBEaLEq+EuMqIRPrvYwZLq2u5rlQFKdgxGllzLmzYHzEyLL6e4WmjzbSohXzWVsibaGyhlng9yx4q+jjyGwVaU8Tv5tLHlSIhuOa1d9Q5cFN4QOfLNFXAw8uBXtUmurExg2CdUQwOtrgRiULEb7ImeaerTs3draC0JzMwuktB/5pFQYVGgQjQDP98Wddqns213ZME/HEukWR8QCy52A0AdLDmJG/XIWYtR2A8axoL7ZCjTj0iBlXvTQwo6OeFXBCVrbIkaRdW/aM1tWD3Z17eL6p2L0fN/yeVXqTKcnnz3BzlBAjbfq9DB/fw1CkKJhOdJ6FoqnJl6rQEer4UFne7y5+/4XjFyjbEOR1QQHBfCp7OT/mO73l73fXFUeIQvjKR2ZGE2s+tJA7TWwvQqkjgKz+rjVEi0PeMrqQfPnV6HBU4r69OB+WsHEzD79LChlyt1bo34Zfo2VHK5JrPdzNhczppVe5KtkeCz9G7A9GIAEL1xkUjIuBEYVo7Ds53GFL19dfTjZxeuWDWjQfjskmBXvAqOTViD6whPVZiSQU+dEkM0cLOvNXBI3O9bzfp+gM8jILzs+ibd4uBSxxgMTH1T99G8a3NoNenoTJyK7yYtSRXENNSKPH8B+qdp+dRvi7PUDwe4/UGPLQhvmxYQKhKNbcUecPpB8hxQkdNd5Oz5AyoDmMn4rCFC0l36kyhRqZ3f1GHxPE7bo4ixfxd5cEwJwqzXE4GLnTnLVXtrDHM2py8eSx4xuoZWT6JH+j6GFOZYuZXxRusiOE9wc77EwohmXvTeqaqckW1UfWcriml4QVkHw0cADaEbZvfqeVfMs0YOu2k0M6OKmE49xMFpBI/Y+4g5lJ7cWFvVF5d3Ae2Lg3itTggMkDYtYWiVb3x2" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590152, + "Value": "122776007428521729", + "GasLimit": 51762653, + "GasFeeCap": "1931894796", + "GasPremium": "123953", + "Method": 7, + "Params": "ghoAEsvnWQeAmVvGzDCXs/T9Dp+nEN/F6Bsa4yey2Lg++n4oq0Y2TA9RefQdOhBtGcxQz+oW6BZrlSDHkh5m8scNDZzJcgQuzaDb309KFHk5wA7VxkFlMVXrEOHFwEYDgGbRIYGRLl0CAdT+y8aWFAMs+v4sbUdVxBWXdS0RabZG0RL6iAMBD5aFjCve37q5PWhp0SEWkrlzhd3NXR9QT2FtPNbPh36vGdTBUN8fQd4N+r1txFyjMgTLBwB3taSCnLUFriF5jxkBq6Fj2Konsh/u7reNVtt4lZ/Rb6iS5UAWAGdTE8+UpCom3C2kjMMUmPvNbJgJBDUNgvUF2ZnFADqWew3NWMnyw90Gua8ybcFfSastFtxJY6zyLpuQwdna034fFi2Lf8bJC/MrygcVHLa1KXlI7Ywn/QWPMXdF1iPl3JK/eUxAZGTV6pmSdGc9/7HmfpDWswLwkPYPOP2MECH81vPFlpblKwNm1xBfVfLbVy+3sLl5r5VyeT6cQtuaN/0MTRLVdaWftfOm08lwIIs3fd5kre+ogNmBRKPMbd/9huXcKT308NZZ1zKG7nBz7MbV5lym8fdLgeAFbkI+S+QE4HBF+vmv6TwjSzpL1kumteyPzBciZ0y5KhyGli/FyUY5qwpNZAb0FMWWnVH6NCSFDtr1wgVBLlZU+6RsIkn9JjlbqB21uofT1BZgut4FdaRsC2DvTcLHpdXmNv9bztvSiwgUB3YAs12fYsIpb9Lc3nfrmIgFl/5D81xq9C57xJonmSxQBs1ohRhx3ZHAwqwAUKNo2BIztaF7HYeSiMjJhnyTNQdK30P3TWoJzhDm/aOrQt5kUUlIuNeOE2O6uEX2wtKYd5VQdw0Vm6AEQYnoThV2vFrA0CHluVC5nzB0gtfKKl7nS0zuFeMYl/ewoJlrH+itV21dLg5DxCTZIdXzny0d4CMNDBjFLI80ueiz0WKqILpHIN2ToMOmX2+L03QnS+zlkaAFS+EKYcz+OyWf12lx9GBhyl+RuOzjtZmYZeREA0rUs/zTpRE3H6OL/N9r28bRqD17sJlOVt4fEgAKcI7MFORyOqzpQnZJYaBPzwVvzUxYz1LosUHoONUWk8tEC7gTfunKynFJeFgr8mxu84iUbOoCFrX30ZY5mlvy9A3dyIm9VDDOAp9HZ/Ek2kfYrcUW1uW6Ep6CNmdaPxeUW/vubyCBF/ElPbP6QbadjP0AskYQ/Z9KjY8YmNnu+TBil7JH1TCxjs9E4Rl4RdXtA6J1XCrkgCIs2nMIzzj+kjyKBeoXtUy+uFUI6rqmMOq1XHZEsLmmoUnQt/RRIMsLMvmmrkjM8qj8oAWedTLX2ZSn0Dn+ivD5k2gLkIEJnqV0cBKozq0k9ybszn+jWleifyE5j2Bt7/3mACUX6A8EkXbEdN1VlaKZAbA7Fyg3BShtqtj8BDz9HMfL8W6fhsSQtE95koZ6WF7zA6Usk1/jU47XljotDvh7pIPqBiQIrPOErBo4L8G86UTh2yPV9sxEQcEwYuF+2Xi6o5CE++T33lkd5r92PdP1kI5bPvmYUq3rTJxuu0ZFOQgQC1tquLS+EA1d2HfMN8/Yp9YAkIO83Pp9O/N2OggGj8nBYgs3NOxIc1ek811afG+4OGz54ZPDN7Yotb3BePbJBqX0tBeP9GXV7Wu3NJAZBO6cdftbiv/9Y2dlBRgnl9/mpTWYktxkoWqRx5+//ksRkaoEWp8gaWNwB3slOvZXpT1fmmAMd+10zZMMxjSv6XZfV5lHLNmyrrOoHefvobOl+uCo1+IfTawFZvERRTHMmOSirgsjy46OKNRk2qJ0/ZC7/1evBTTQQrIkFslShAa+b3Zlc3chPCKEPxtRX50kktuo5bGTjrxRJiCaUYfrfS7VoFJPOrv8QWvVkypjd63DEQCzJpHrl7x/AW5+UdhyA2afyPwlx5ILoL8gbteuMkdD9HTU+eS8NYvlkRclupedfNuSJrTloDIhQATeEpDNrx5t0xP3YJ63DY6eCqfoqGb+KUNIgzFj50a0GpZQwj9oesMqhgBcCYriOc+hnZnXsD+oI43NDxAqtfvmDZFLKKMz2z8xoqbNV3n4Jar57yhBmAKICQ4+kKPf1dbiw3Vyt2/pqD4XUcF9X+7nO7a7SgrBkAfW06Naf3iAkNSOCsIiORQVa7MxJDeroarpRbUeCMT0BPzwS7VZJf3ZpaY9c+M9AgMMPL/NOB/xQDARvxNH3DX0hM8IoDrXX2rNRaAcsHFICwRCYeClER87msAHcG8zilH94XUXysgS/A/aveXtUL49u7bz6kEJMk9BBbCzjF7sQtp6mHkLnibffZVdhP8uYO4sQOvlORpBYtZZm84bGSagH8uzGDQ3gFlv/7degH88ZEEbvuFzuKapTxj069Hxm4R8n1CxsangXwdKYfHwJiG5hkL4gi7oQpgenD/NFPq+qK+sCpD7b56mgPCiAPbKd3RFAgD/XfFtVShR5eCC3nUA/8TV1JjWxZrKA4PQgv2YZh0srz1WCpwSa2xAjzgNiLutWogqunw7zCIjtHy9PhEM6kmn/xvXkwC9dRIg" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590153, + "Value": "121191532823564220", + "GasLimit": 24368478, + "GasFeeCap": "4103662116", + "GasPremium": "125327", + "Method": 6, + "Params": "igMaABSOZtgqWCkAAYLiA4HoAiBY4ECmlYfVx1s963Jc95jfGTB+oi7lLCgGVvLlarz6NxoAA7IigBoAG2Kw9AAAAA==" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590154, + "Value": "122774574058792739", + "GasLimit": 54471706, + "GasFeeCap": "1835815459", + "GasPremium": "124613", + "Method": 7, + "Params": "ghoAF5JPWQeAovqaFXixMYPRS9uaQq6hGkzWMWrEk3FOGOax8TKkvZ+oXLqVgBU//teIvD444eF3qRfN4Q20XzWEZhAyDT/3bvyFibNdOKMOXJjAZRY3q9USciye78+51hkJ6PKpdpWsASQAeUSRnW+QG/TaYx/Cyqt83F9wuq8eRQIgxUeki05jKh8+hASwaDzCubiYcBtLqX1Wocl8YBu59PNP77GVcdZf1vkzv+12s4D6xNxntta+clLEW9PiYhCzpWYNIySpg9odYm2ZDV7bki4dClqM5TR5sMjPv9PwzDmZDmSZKz4vplWGmjxkklz67FOMuQAAlQY+8yBln+ZPJbM1vPp7vzFqalj7kFScOiNP7f6SY2qQjZ2SE1/5HZqU5AbDmZUjA9xgI19HH0G9GUh0aAD6XoBazCeSRbPM7Y7bdTtSxNs1lRuYdb3eCIKn8gj7UAcaiCC3BAlmZ0bRzbWCHvB2Xd2vGbuax28koQ4LjjKBP6O1bMvw8xmY1F0hAEGEMmo4o9EvFy2xJn/ef6BST/IG3fyM/VkwJenQZXwxdIg6DYclQcQtG0gk5tVjSLLHu8pZl18tMqLpZAw/t+P7/viGUlPtZjrtsIHGOmJKryrDGZlRo1DyvQGCcj6k5g1OROXHCDKuIbQZc3VR1AHUHKdMQ1AQ6eDkwSJjWGCwf6Zy3tYdpclB0MNTa91lCkdr6VgCgDCNUJ1Dt8lJIIYVMedphsDMQnLZJ9XhVR/0Hs4ExqCxoHhnaDxNFcE1Gkdbb3d5to3WfvGXBv/DcqPDlafv6Pq0My+YCkWEe5o82osCVOKuuejdsTz4Pf5Dx3fZzRZqoST0gQJlrpbKypqx2B02CNnyKHa2m6MWu5lCunfsvPNGyL7HLZpGkhwwRnWu/ilZF70ApTjf1cSVA5BF1sAbrUhDyGpFnh1olwYL7zniY5ZPADi9kv1hZfS2y++XuyMflesEBN8vwOoPC7k/4UhO3qq+rwdZhSwE+h3aGm24qz5SQP3jTBPjnD8N0NiPH6eGj7lx++gFkY0C4maSL33NJ1Vu8SM+Zv8882t7DywIHXwneMF6FYvQKCa8oi0ZcaGfrToYrHdCSJpMu8K2sgPNpZx5PP9b84avmBw/KKDLFIjAgR/XtvUF3W0nuKM6cLM0FJsJxv7i5ESet11Kg8mxahD9E/QVqElglJBnVf87eCOCtmn9KRrK3W9Hb5yslsb1l5pxFyebp7BNmZNeY2i7U6nQp/hQ0/z8mLxPtfuI08mvodPgzDRTaLcPRsOeaAvNqqwDBA3DP/kIybgY6dVW0O9K+7Bh02R5girTPP2LGqFfvuiUdlPbg9JRMFQGeH8XolEbJE0J85A7QMjq927hgzx5B7b/4g5K5PQdXCWLy4m9ZdfTMS7b5/4Y6cmLFTlBGAtAMphaLfIPCl3sUDoE3IWYNrivvTfMLMwDbxXojAQyUalh5DGW71AyuF5sh/DxuTBf45x8esFcE2oh7aeadzg18sUNnVBpKzUKwpQ15Ij0wy5Q7l4arI/aa7s7+L+VsDfVxKBP6sDzgi/CeG9SO5J9dczowAIU5xko7iwf5wdoXcO5jYkxV7/iYxV0zYXAsinRfvzHONVKe0GrvY2dtvgvSfs7eJsNpiVISUW3ZIqVMwll0oYhjpDIcecAfuCUEZ1LVWqUjyM7e9ZJwgJwqT7QRX42bhtJIYKADfeLoxAVE9Ph5E1mI8yM/8OcHI5chJNgX7/gsQZJHoo/QOU8ztDSZ+KWhIrzWsJ+xGUVnxHUqDX/lRcG3qVmjCams8lhhA2OT6kw57K2IUhFf+Qi4wVIVpWwQ5p1Wj6Q2yiH/sOt1rjXAprEUIlC4Hmr3PLzrnwo9U07FNGBaT+hIaN4Ox4xaKDcqvMYyeIk6B8oDyi+8624j8XUsaaF9rDVnda/AFw2/64RPf3qLynejLLLqT20JcThwRbQNa/5kMYyZoYWZKm+4+7ioioDSO9Fzhw7rivKAI1Gtbrn2JyXiRk7cXeeSEwooZYRDDEXp9kAj4/tEMQ+JtbCyLbOdHQwAfrnp2OGlcPoUpN6sRsF53aO7vim0b/o0kiawen8AtKBpDpAHOO8fsC8bEqlBB4zERkWhrlPVqZPbvGcI0Z+mqhxVrK23e647Fa6klnaJ2YIdSizljXi+ZMAbbIGd5CX1HzvDACZmjdzQYCJjsuifrcFhDBJHXMSg7CXYHAMkKT2Q/k+dwaG5XkUFqNrixQAmaOvo6q5mWFEdk2wUfJRshdgatIOll37Kk5PTrVSV+D/bnelXtIpK445rqHty93NYXyRpEPHdZQp8qnRhPduHLy33YQVV0JJoF7E1CVHrygPpshKbCIE2QYzEFRBWNmdjQmukftkPQ6JCZhHT91Yub5GfoyPWfwmwtHftS8X0qfwCIkVAOAERO+pqgoZRUawYaQnFfIrZeHqVkER6/wxD58hlFREeb0HZ6boXtbCtqCpDteebC2J1GP+a7GDG462BObJsdRMP7wEWLRnFPYJqmVIEJfs1RCd3/LsJypBX43yrmhH7Dz2YfTGp+e4FLrj6rIE" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590155, + "Value": "122751843808482455", + "GasLimit": 67290153, + "GasFeeCap": "1486101539", + "GasPremium": "125964", + "Method": 7, + "Params": "ghoAF5JKWQeAi5R1JQseIWXYKO8KeG4JKGXvhRK1XdnKN1AUwob3UGTt7sfsxIo+KDohbB51DM6AoaNcKaure6eZ/qrX/MAI79T7Dzgo+WOorpWBAk39Sd8FCTOS+pW3tUHRlIK8Nop9EfPaiu8NKUcB8+15EcZuGBJFpmdHW9CeNkj8rIBpy8MnOKu+sYPszf+9ogg61D2WjUFDmuQSySIvIC3nUu0GJhyLAqtBHNh4PkfquZWBE0kf6qHxvrNvBh8WZIIdu8Dmi/Z+CWN00znL81Hz/0omLcNyqiHogqM16kn7AX37IwhFIlq0K1h2Ej/9TXWe6+m8puMdj6W3FPbj6dG8o8kohl8RI+813Lx//SMF5P3V1DFgqUXhjAuk+oooojKdMBYDCVQRAHQFbicnAkUadyRxxcmw1WlxAn/awSlfOSKcE/QrRB1Mx6usecFllPWWowqVt/5kJfg+MHAiIG2FR7X0r8V4UiRDDgNSukUcuCesbqV0hmgKrV5NSKIUVz/7aCODp90POt97ABbXQmYYQNmmqrTdD6fbs0yzVFDOyhrV+ikvm1xA905yS0KojsvKLTMhjgQSaRAp24IRSWZmk47pB9uCvX+bwfV7vNAxojWHKWpJLAS4Va+25L/D2ANFPjMIEkU0c5CXJtJ0Q31x2jTyNO0IrQ8xW17ZcQT77lv8vpV9DtV7eAp1wyWFlbKu0Uz0rnyBJU20taymGMZxnmTVr71rZdleTn2Y8vIms/SL8oTVUKaGnTzph+RCWKOwwcWKsduaMDvowdrj91vA2bX5nJt7REAbKJGZWUNBK969rdZgq0OrEAWupGKLiVhCQEP+sRatD4brdXL55ICa8AYejMU0soqd0MVAq10lZvc0IWd6V2/1BrIjjgpDTbbfyTZxAtj1pGCfHYGd3O2ETToxzVKhfLAvTt7dpVBM2I51eFKPoBS/hrvc3MGghMSv/UIHoWOWretkJb+vNwS7mbgFUfjBaMBgO/TRoferopMTa12Vb393j27XoeZhiI2c2lKPqn1fzaUYx1Cb/CPrFF8nI3XFvkqMYon8LS3qu7R+cb2ukO9LuIgbV5R1qM2QGXQjj8Th8QL2nbGnNVNREeIgsB3gv5d21hRVYP/uDH98lGIGFoVIzkjmfw00RfLZqMOvFHtPeEtr/T3P3kzSB2Bjsr6QGZ/qpF72YRE38zmuK0d3wR0Hr7I4WjfqG8Is7Y+soMf+XNo+xqX9wpN+Ea9DCh+eLRrtu/K+1PBwTVJ1ZKCQW0dFBql3tX/H1k8kPI76lnw7uDfAGzojGrX2J39tjDKPajetvk2P3b42apaiBgsubhCIudFtWph7JokKgOjRlUho/bukO019UQ7rcAIM279CtCyIvXtGqX7ObZv8qr0ASojgScZpLuvLzOYnEAqhAEkFD1Sq5yCWxcXe+nK7Pyc3mZQBtGLDPb9dGLDCmygMlUwpfBtwF+LtYvg7BabepyK8itRIQ8aWkiRCz/c8OuY5TtA5mLwX0zkfw/i31QqMwMsIwZ/CNWOQwi/vp9YTtwvcRFMaB4iQyM4fMEdmaNUjB1lx5So4oGS+M2FRgHJjNx6h1IO+16sA5xPBqhzXhSC6sWE4Gcv+XCASwZButH7oeIl/cDSIxykXsu2RnmEMOtqQ0MoBYU/xHzrsfih9GNlpnEg3wSCjg2Tvv9DFZtVHivxugN7KqUc+73klZBe0KvkTZ974aUL2L181nOYyr58uyooTFa7g9PcEV2Wjr/fFeQqn3BigTOeuYBhshLDUmz2nJSuTfQEA6eS17W6JitMUs/ppOZwJ0Zrq72mxu6VRe3A3NZH3Qf8hM7ULmvMlXv2Gi/iaZVkD3rG+27vUgnQ1w8gfdIWact/I1nKuB0OxC+cVJ8DpChUFICIdHOMcLB+W6JP6IyATgm25dZLcDOBsg28jCBg8bkeYx9Y5463lTwEKVpZmapFctH9deSwW/CAroLYgT1l/kUDV9p/dh0ozCyT7T1KU32aC3+ns1RcLCFLMEppOvDRIDVs9M51D8lxb8AjsJa6v8+kPT2q3qCH2v7/3v4dNXupxjIb3Zw//xzyrEhUN4x1Yl3P6hAPgkuJkvsfsbQlDobBCZuBJjOb30hL71kRkL52L0x9oinldlblTYteK2BIiz+q0GUOjjmuYWjVhu3wv2zskumN6BJWKlUsZK167GpcnX7G5BbWTAVMq6AXb4ao1TI0RHglqpJffBAazvoMKLbsHxbB/jfHuhgZp5Jgic5mer79kDNDXnjtfCxuxiEc4N3jkWEl0+1KxRpBPHBjt1yAFOYNJiYirISvUpwqtTGyRtKfSI3K5LTe3hQabBr+qGswp/vKekPgAGpiVtO6CNYkQvgBopySaOZXoC+VEW/T5+vyzwQeQmNEMTvrLD4liopbpKflfFUnRdqdzMI3nzb042r0VD4u6+jwwPPMM8w5QsjlvwpGkAyyPQ1SygtXd7VrBBGGVyoD6CZrzGZnXMkOo4hW7iZHqdiDFqXt6qWG3GewM11D1YzEDvuwgzvxj63ArXh16z+LajJRj5X12RealWlV+" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590156, + "Value": "122744018363934596", + "GasLimit": 69906403, + "GasFeeCap": "1430484128", + "GasPremium": "124958", + "Method": 7, + "Params": "ghoAFcYQWQeAuKaw90U6zUtaww/D1W5Vhf4yStm2iz1144/vSv8FqA2kuaJ9PJGit5VlNHrCKSeStUPLlSiTLvbRHN58RaMSkU4Yf9I5yzYGhf9TAH/p50P3+XisVd85V7JW80okevEkFeAUn5DFo8d2q5xeWNM7/MhwpP/KVsRqoVSck3j8nRv580Hum6iW3YYd7JdOAQaGr+D7DfNna9w5QFIgMwBxyWo6zrSjpSUwNVgmnduNlVLZQLxjx05pte72l0kOLy9Qo/ARDBHYQcAIEtOwrjpSUiBdm2poZ8qtFzsxIAKcrpJZ0ZzCVqV6zg2MurRumgB9jn5MSt4mmmYuYFGEC4f0MqiWD9rVtblmtjfaEbZiFb6fZPdzxhfyAMj4tb+RDcFlFQz1SOCtMgNc4OoW5nCuIu7yhYsWVh4kJbF9uLJ0O8jhK0AgcODoldozCGAXXLIdh7noxWPn/jW0wac03IiVdQqIXv94JQj3x9nXDI+6v2k4jVBpvfSBn2+TFwsPdMfuriX2iA+qsRKXk0tN9QhIxJiYJBTDf8E6xt3YwFlgOzFW0gYRnJyDLbiqJzqT275So3o4IQzEuRqNjNkvmshKAnK/2HpUugTK7D3PBHJ7/HwmRkdw5joOob/ucLwleDjEFVijvcrD7B/I0Avi54hhVYb5TE88gpW/BegWN/aoNhtndikhrZ06U2Y00roFX87ZtUml5AMalZIfBD/1SxCkgY0zWOupcEcvshK6zMY3S8n2nKhIY086mqGOGUWbyWvSoj57LSxxEvINVOXjD3pGLaHGV6lx+A+7fnRL5dcCrELKuCQTq+ZLBWbgea/B0MorlgGo9MRb51qgZcTAnm30cL2aQkU6DwNoKvD1z6bYoPAOkRzbmcyVfzjkyyeZyJw5C3KvfX3WbKTEmmR6qil3utr1TlCQzdnGuWzRJB3kKPzxCNA8pVuUFHJErE47DWyluJAwbom+Gdke5IeTI4eZ2i/EKiOwqcwYjnMQFBb5KyhTYr4H337jyUbDv3c3k0S8oP4RbGaL6w+/76Shw1jJOzNqcQXKLsVvQKlL72bKQO4a80vl/C8KbAHXNtP8faZaqIfJce3jp6GvzFBiU4qtPiMck3haFFw37hzXiZpEQuDBSQvvb2jTnOIm0iXH1wiXAIOXcvOfeXV6Tt86HbRkfxalsOFhLdjhSDWS+SAs7Zx9qzMiO73I7FDSn7YxTLqKsBOWjt/5bUbQvNDSFMlpel61tKOwb97DSVfTFjx7cdyLTprpfZo0EL9rZm4l0HOBmZaAiudv492joxi17XzPcJYw+a07HET7XWCdqxhPodaLLehcz5UTyANaxihxrg7ptvpYXVQka598QS/Lu3FM69ues63vzjP7Znt2wcDv8m8k2VRnqlH5oE1usen8cBasA+2M2yGrNYImwxULCTjH3fVmBS9/IYBucIaGJzNDtqhK8BRbAQECUQFHvzpQfAwukgwELjHFpxRApDF8IiIoaCCdLMiLxUqsxSbZBmaK+dj9ZeCCgslrZn0EWwNz4bj2uKde2CrvcRDqQXbczbyKIVaJydyXEBaBAnR12OoqsLd2NV7Y6LlsHKtFtfc8vGcapWpizNbztitRFNn9MqHINny58qzOYJaq4SDIVFH0GNWA0HsYXWUiKjnuYkJj/yjfAL9Z5d2V/MkyxtPraKgsHT/2iMs9r7ZDBR2u3K9F9H1PAljnBzN7JYZQ1Vc8WLvrha5dUSBPd/3sQXBpDXLC55yPrvoaVYNjKpkESxWPG/wRziLhUDNHv1vc1B5hIVyYtHocgkeXSC+MbAdUD8R+gkHSxRCVeffMkV6f6AJ2utz/RhOp0Pwjsnsfnp6o/Q2slOOI5yu3TyF0pgWNtmxqvfYAHGihIbd10ZP02pWUqFaWNHkSOpCqrwhOoSTCyTooB/q1Z1cw7GewFzek+/PDHjW53Y1ZbOPbHjjaDlScAxUkPXMlo89zhZA5IPqfsvDTkDKTqhTmqXyCrWs+plt54SDIsN92ngTkNt5nyyc66tLIR3WYis2o58TeXIeNuc31lN9NWwBk8okQkf9D8pVVDl6HTs+WxL3Gdj3tfmxN0cWzYUVVbAb1OdjIKVl5xqkrtqxgbQ20lQjZ29glEK+JeEC4+i/66/S2mChmHolHtKrNWQQumA2QLa/K/AOXZDpzAuHD16dAVoN/pyd/6StPhXxIE5yw4voa4WQgkfylyUcM2I+oU9EaiXjD5SFFs26usFWeubRn8MM/1JucSkJEzD41eJ4zTW8rLBQuca9WkNCyoQGbIBupOL+hv17QippjgvrWAY/Af7C7gqWc7KwHp93/MOsKZfGnTVWSjgus4rwVq7bE4Y6oOoqZsr54QVVYgksL2e/b3zmfZEI71UvtZ1XMkc4FA/isTKWXYPkh4b3DZFmq1X/14yfeOZ2yTGClEp8uAD3dJ11gXYcEUpFpkLTFgywwWUnc910iulIDVtKJ0Mb0XPI3ZjhKLTwCyhQ4lqxxjDl/9Lx7lkXYBXyf5XSGi/YIvs3TvqS/iuTMKUsxXvZM7Wk6b4yTvx8rDu8X" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590157, + "Value": "122780338629473282", + "GasLimit": 64308513, + "GasFeeCap": "1555004078", + "GasPremium": "124932", + "Method": 7, + "Params": "ghoAEUCVWQeApImYf7vgbGcWELtiqQ2AfaQDCqWG4pkLI1MUWQU88kQAo88hz11FsNQTyfO9P0cWh8LgtPA8fyv0rGn+UMYqQG98LTYz0peGrixCttz3kcR1rpMRnhmhcYSbwdbTotltEsS64d3YkBlFTrJ6pAEmXqAYL9QRu13GmRe2A9yLt6WdjyAnNWSE5AxnMsANcVnFkuehZQxzrxEuTTuXmFtg4zLkjBMRZvJWSRITHe3eMA3LvBpygvspvvVHy82RV86Ih8hqewHjqouku51VLEDdOLYUm7+rd5U9o18diRAnq31EE6WTdvC0Dv7nXnO5QIP2hHBjPLHrO5le4X1wX+Jync3jR2HuZeXQoyAd4hhR2NAikkZLIKiTNdrhBm+5UMghArhoRAWOwtRurKLqT89QYEPo/5zETnAPy8kb9YCugeOyeKAEeaz698VvOOE+3WRajKaPfDrMoBAeD4QFHa1WQ1kdmwlCnOIXK5I2mHO5KadygUOFuzoZdRV08tz25Yl8sTqTK0t0xFoQvhLgniL8W4rYf3YaZL4nyuGMbPXAf8jMUWFoUlm4Ms38DVNChAJcjS4ZjBGlhCM/oOFR8A/ulii6z+9Oo4S+gAkFHqxcnO3YQ6UZyOf2dK7hJnC1ZNaPF/pLJLst+w5nOEJPfTK0rGw/vmyGTUZdzA+3DmY7jZDSRQFpYabrEtfFCKD6NfAFhzNTQCue0mOjxs5xfqeexPZDIgI0J1ZzHqzI2y1gJHTbW/Xomzs4jeWOomoj4Sj2s4cUE0nxKDdJUoZuo3IEW8SRGgBv7LWWzcCit++rASi6a2wNBwRcd8DUlccln2kQtDmJsIy+VMEGbT/q4ihMlvJIQXCnWKgIZCGrNeiU8hz/EqGJmg+ZunPdUb8aLYs8DRW17oyJ4CWjRc7vI6g5YlL2eETMMPZuGMJns6DJ1L3uor+pGKCGItKd2tm/oxQqp6yB6KY/G3XOkduwwDXazga/LW3SPYz8/CdctiCJveI+1NBwBtEeL8MODditmtp0oS06CYHxZornARA8NTR2h2KA+SuDfM1r6cs2Dbpl4XIgLD+HdSwJcd5JCJGy0BOcgMKwNaw4El7bbFuyN7axrJin8CIygqFbIYc8OtPyuWrZTbdgYGoaFRQSlStRxqqFE2kf+IQ85m/ajCbeXW7+p+PAgfMMgtQea2YOH3sQpNGLt/LYB9pFcAHjztfL579CpEeY21oi2el1uKDFkzuAVceaTakSQe2whdZD5ilS82RAzHWxTGC492EXhg9Q1MedhfqawqKxq97hbyoMsWBoRHUsyomwVCJx7vFirosVJXjGeJuHWNZcD5B8Ibifn1Gyh11YUj91gcSWA+dwWiThMoGfEICnGBwfwM+2ABOzH8XqodcY2vxCsKJUVEpyPe5RF4WsMRMYeRBjhE3ZASxvttB8kcNIp4aB276fGShnphIMmeED4XU1lm0q6bCCokskjZi8tP/mGFyB6XbdxD8oExjbJZuur17JD9212aFFkVXfSK1u/4XrmU0vdDPfxqWFq8+gkr08z+dOxoxRzAGJn3hlp/J6ZpLFIhyCDj6fG6pUZnqmtDqoEx5PKI1kIHdKqNbVEIUAS7+4dVE2ljDQMqi+dWExY05zCbhkaXAGbQz9lvCp8WJG4HpREDfPI/XOBpLZNSeZLWtmeZtHbAe87wIYXIhVIOIxI9+xdMCihsplE1c17RP0XlVaqjmUvvSojjrsNOprdHbi97FJjSvSKuc9iRaBMsT3oC4bcqObFY20ja8wmW7JwLSnd9+QD8MCsBLcv5CL7vrNkuptJgU5L3Qk5NVCss1BTADblikWFQtLJs5uX0EX9LK0VGzi3H9RoBPAYp1JJcaKgfaKfuk8ukNz8CdYfNZm4zlj0Ec4AX1A9uAv96eH+K13tTgb4uiqEawP7+lv7fI7kfxSBD72MeWrnsKaqYOlWOPA3ZhwdGirU8SqeJJGmJ6K/mX6XATHl0m/AsE/+ww/KfKuj8F8qitDiB1bwcCT2b+aClUFeO1xNBx6CpcHV72JUMTvKrXqseYDKLgOMaiWfw6MbEdR+J9X/wBgMTzzOfXZS2KUDqOyZpxEIF9M+cscbQPKKroVpB3kVl4+8YR2vDjjPCUTcmKJjue05Xnh/k2mEP6MriNgfmVpwtu/bcb6NX1N0JU0GS0xKcKq6006+LcmHMzsC9E+wKwzVeBEeMg4Jd+Hqagnapm9+3RTIl4qL5SpfhrNs4S1KlLs2Csb7/NMuTW9MBs1T3zo0Mily8Mui7Sysz7d9ErlyKK6F0nAgO4a/0+urjHdoJK9e9rYboFckSULfiQowohnKjWdyqMLwrMi9STGXbPZHquZJhHccXUBlXQfiBldgNnGSz4woZnmo2jUt0roN47Y0wFi+WmCstYr+hXCrNZVqsj4OK7em+UWh0rjAGuGjJivmMqrfIMJE6ewtperWbR4WsJ7FaCWuV7M+Wq+HEIWFepjBAP9Y7qUXpFJjxaDIhZpWktJHCwaAfvGlZzSC9jdnWrFS6aGBLqh5ASE2OAqbDkz0kEG7ZVzM00n" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590158, + "Value": "122779590573780423", + "GasLimit": 67017566, + "GasFeeCap": "1492146103", + "GasPremium": "125681", + "Method": 7, + "Params": "ghoAEUCUWQeAo3NqIWyeNgBOjVUb6nXvGj6mR3z5P3NAtVAyeMNiVLOBxtgvZkUDDWT/IzxrMsCQskvZ3lgUGITo9QSSwVagq+0QMwEbG9jf+nrmJXRRdpYO9k7wAwYkrq81FU2tfeWJD5lks/PP6f2ZeB6OckB94juroEkd+zboTY5f0HY00/p+qWG2AwcVYNYFIRTlPXp3iS64gLOf1cBfNLqR+jWYY4uhidR4JI+8p/DCljOgYxEB81gSIu6XXPPOfjl2Iu/vh+0whuGtpB3xCKdp0goVtZfEIJHoPxjXKjanfI07WlDuIx641Z5mRNkhIDIJ2XGWgd/liT6nA7Q1CPqYjMFaOSRD0Yjqvh7QGW/58BHpTk4Z/cIAF1nBG6A3+WmYaq8HBLgnJAd1pFLssu3bBKblMpeN8MOxqH/Qi1KCEVp7yXBExzWablcH5imJHBR9RfrhhtvXjS9AY7KtkVXfbJbJelxITut1ZCc/mfaiIRBGNKzZpXDEu6yJyHKMU5YWMToKoLE+yGYc80QRODY0pXchTbpZGlIvrWAecmSuUlfOz9dfl/nY1fVpBXX54O6HxsQwsi9fMrzOcgRzKiCGRfV1+w3wRfbRaRyJyRDHAjDNP2dEXPfi2w3tNnQ/tebNmrSsCq46tMfDNCC71YHOH0Jaletp/GG5EvJRI2I0OAgn1bY9H8/VtvWGJDDVCPx2hI+fp+hoX82kxRglrEDP+ya9TUi9/9TdMJPa037sxLGsav4dBLRjwEPXMNUOGu5We1oqrLW8/70krVN58Z6JaiESCqBszg8mNLSQEW6jtFejY+n7Vhx3qVNynIlm67syKhBLtgCicDDtJhNXnD7A8j8BeHFYeZhDu8h7+sgTyF3azFXEdQf0rGOu1bnSNSBaQ6b5Axl9Y2q63PWAmm0UqhWtjPqH3mk902wIqPgepxzlRROFotSShGYsxRVps2wuENW6rYsfpmMxWOM4WdF18oXHggLCm/yPiTpJz6l7hFABgigm3cS6Ffp7IpmFSPeKvdTwtqe6Wp6FBvi1KnnqWAl1t/gRw7p/LIyytAWWNCUMN44mmfC7ezOeL+1ZudJL/T7khqoWjIuU2x33Rx21fVHcTlIBbTtIHmDD5nlojZzCBXoo+NlBsfqL57vYq3uXR0v7B4yDMs0nMDUzd5tXA1lCTykJoFCjJQziHvPV+7un7etWVT9PakpDrSXIxF9CkaSuoOzQYb0BqRZYRD+RAnaHsYN2BAZXbe7URaExJwdGRTqi+8/7vSg6Q9mxB4wv3v8xio3nETmxtNHk/ohsyPLRF6Zl0dBAWUYHxx3XX0dFupAws4ZwrWXwy1zkc/pv9PgDpOWIJox2WCHwJvimM3bDjKSvG/qXk334BtQTDhi+VBrCb1w9owX4jOL6qtzuRhj4DNW2pvHMhr5aWv1qiAeT/xsi+Hg8aMGOi70l/gGnQCe7IpUJT3rjnwRRcEaS1G8Tj9Zf2yF03oSiKwQZ5Ngv/fcA/NRkY3mCL83mrhs06uVkLP5+orzssUOTB0Tbh/IyoOyRt7PghLeCdmboKHV8yhua3fXLZ/dCSCYIDkASjLQPKGdMOZvW2xh4nnkNMeMHqXyPdf1M6G+MNfE0hkVCDSOu6fHZnl11djEFP/Dzs5LfQJWXvR0nn5I7XYINJWR0GaU47LUaZCIxck/0+O78t2PCf8S68AhZs6FDJnbb9lyicIU3iHM3ZUxw4xmbFjqZo2wZpoazh3GbwJeMZaFd/p0EPiE8iclcswNjwMsCcN3L5X5hI8wg18LVJgOtxJZVmRssep3cBa5WedCpOuSo8hzDxi4ezRoVRkK7ZgFk7/wCPaopwDGxvdqX6f8I04/jo7X4JFrRKWv5vCGcl+LOan87vMbd4feK9EwBpapNVPqv5bmkxsg5vuPLfyL6JJK+DSo+4OfvsKntCsb8z9Ez1npPY9O7NpPbsDoNzGWQw13J8Kzv7OrgJN4/5SYWZn4ck8UCXCVqScb6ov4p84zJY487WDC7b3tTA2pZVCW9pPiYoM/vvq2iVluxiLyQ2UBugWz/Hme2MuZhxtZ595KOb+5HOKO55rHAEgbVfZzxWq0ZfPE/5AxN3CFmW0AgczmOmKBGocmZSIxF/OIywisnJ+zfxAqi7dC7ztwLpoSkTNoKgRCS6XT+WVpen5NaU/PoC7k2t5eGb+vQ9C6nvQNXuJR6ddcqdWCHoQvB+NDUBIWOWA72yXXs80oFN2vokQ5AtZ4E+Fi4e6LaN3C/y/VslWrXmtuZiZsI33DmEWBBGHS7Z3YOhQR43iiX5ZtaFO0NqohBlBZ1wddUO6R62E94wNPXbKhnr4z8LIKSdmKvsYkWUbjoNXRcpxKqRvdV6Td+pVDsrraZH9gBA3TqNwYB+WRIiw/6ez9yGQoD0/emZIu/U3yK9H3vVOXLF5AqMmqeAtBNlvXiqVRqZqYRhEI9Y6xvSXhzessWRuHDDRuV0NE6nXoi+CQCkKBSvUH2nWfGoTJ8jFlSGDelPpYGBOa4qLvthq9EwRG9rWmxfJar6QA2NMxhoWVD+bI+lrBxTc9q" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590159, + "Value": "122772451406606032", + "GasLimit": 69538513, + "GasFeeCap": "1438052033", + "GasPremium": "124188", + "Method": 7, + "Params": "ghoAF5HCWQeAipk16C2v85pKK7nh8m4vFy/JmMB+YIKKge6a7G7mrJ9jqQFCTlRh/lV4c74p1Ermr1hK98hBjeQ5/28y4mmo9Oy1/oMpinaLsJoY9h8xjiBqSF2yZ4bz8lG4pKCC82h1A5cMWR9BC+c15SwGrGhKyxk1RI0Z4q+W0GgzAgbQ9u+C0xc3v8nYTINsDYoA4Vnzrzv/0Y7M35Hi8Ah8NuyLSL+aL9BFBvmyNyLfyN+yVbW+BeU29Odp49akBMnuQd4Ohb6kTFJ2Jvq58xfCyB1lncKIOKz3RtvqxYlCxAQnJCRLvO3z11yw6RgX8/V3yU59k46LDz9vpYvKmHjbUIBqtqqvyqaunF8JSuYMAHvmekf0caJZ/t6E/3MoKb0dEAw9EcbK639382fDV+xmg/CBNLRcV11pSVmePc73YFipHqDzqPdUue1p2RxR6VgT9e2wij/l54kiXu0ksPGsXY9W2Dq8hQu2buugmijf38/syUi1VYjaCOQ9T9IMfW/yTwVLrHtBsZCjf5YnxwgiKuAWWxc8+q55qZcGL5CRgRRl6yrcpHtmztYfydA+lCBm2vhit/9OYhUtjtpIl1XZMgZMXxqOLYtP1gEwc0GXmLbuefBGp/48ceyeU89nlijphhWnEt/bdl7sYV7+gTraGgnl1GFYHciR9C2Ay7+v5PzYUTRQ+iZ/kDLQdqP+QaAysq0rjzm08qWyB/slW5YM7CWPT3vul0397yHvI1KqNQ7EC/vVyqAfZDVpizzpCTMW3C6bmblH6Zlc+fWjQcTJajh28JKnNxV5U8E71VMLW21TodqWYQvQh5uYfo3rh5W/jg/Tj6Ufk7yZKcdbW28UQQ3CgbMSpNXvBvECg/Z3EPyz30Y9paua9yvIJibMYpDATefwD0RwYDB32UZTnu/xYwY/3uPlRNlsqnA9C1ENAN9qhHOgUvqZq/jC+pvUmYn7mHKUqWbnRdh/w5zFp2dfi1D9P7BA7uC5+yReg1lnSZYYcHFBxBQbmOSqpfyIQYVweFOOttnZTuTXt52QoDDzDCBc3iEH/pErp1TzVZyqcx1/DPkeLDTEWeB/W2z5SqMr3mLRg55B4NApBRjRsrv47hVY/rj8LfdcAryX90s/qkGkup3LTJGy+bh5XunJ9jQ41yKXGXMlkqZgiye5NyPT7nsyYM8N8GP6nnE9DZ7o/41sp1B8olPQ04sCPG6iDp7ZJf95tyt/qyYJ1CL+mtnEOsJfYZKlpevVJyCsrP4p1MNFH4Z6SEVdiXdstMwFwkCaBPCComU9pwXRJJ6DgiWbLSaRzaLlfzuoFZkdfaogLNkM+m9Uoifq2G8MEPMvCwkML1AYtaGDC4cfeFk9+NdnNeoisQPzRirWkrno9fWX6V0C2J9RsbFpPmmz6B9f5Yi0hB35FpP7tNcBxbxKVYy5MMAJlUKQYpyqBCDKYAmHEMEGIEu4ZP3yaIu3CYObEgGpSWRviq36Cw8xK44LkGrM2w5+DsMl88sb3Yahy67iAyA/JSOjpegydjnU9/Ip/H+kiVMzlPEKagLSLVqQhDBv21HlqCposv/oFm842BFUPcfjOib1CWccBN4aJhrY/SqomdPpthGNzEK5DkXYFoxafwfTDFwy8QH5ghSLIRAz5N6kiEkFH+1zmWBKw3RFLLfZN7QOF7FfuAimTSNGkEmOjcMrxnBsWhJIsO6/WBvdmw10/Ex5Kuctl0DBBjqiKajeLHLXjHSZKNFvymIf82xKy4FWYl4e2+BPfigwMehEUeTxrIgHdKubijTbH5VFuoIPw7jVhRM7Ezmju4aHO+udomSbOS8XPCBhI7G18CM/1rWsSlDNTiunrOObggZrb422DAPCtR0c1h6KWv/S1EjLNO20XIdG0x94PfH2z4O/hqafpBukcR2SuO5kXVlvIlpSbhgACeY4v7aFQ+NYPvp05nbIjgPpelpTeZ5RQRmDgiX2s3lsmss/Ymt+BDUW62DhcCZ1r5FMMg/dycuOeG+jdTy8Cy1i8kGT5ZAJvc6wTNFIeMaH/FlrO8MSL0Z739A9Ln+HrRqyVi4THhFeswLWNU8qpV/+zdz+wWHdX427tSBr74BtTLCE9xdz8+HpRKyu9R9GsrC8qp9+PeajMcEz9rcDe/i80Z3rMx5B7XY87kUUwWZM+m17iwhgh53SybWtY27yBZIBoXPGrabackos7OYDm94Pok5EQmT3YokiMEHygIVT3CfKmfX4yjqmq5NeAv4AkjJ2DQtsDRhO3vy4AOHP5ZNr8sypKhI/9X8vyiIxZrD1/HqNHFQggiwV06oExmHSqEKYbrDuYMqwhTf5b8EwIzyVEsASlVA2SrdNT8yKHfpv2NhLrBQ+TrYBg+fTiHv1gOt0hyJtflm5freF+QAWHa+D18jKJWU9IRDBUUcxJIeOOg0iwVEB7pt1gkfFtYViE6SWC07GzoVerhiKrxQKjF/PbRMaj2STUHPwPOkO9ryLDZfR7SigXPk50HZkMqzbtJBzcUoDkknWBP0e9pS0oNWvZoUZH0LMjOT/mh0/Av65exURxU690UxEpAPfiwi1" + }, + { + "Version": 0, + "To": "f023678", + "From": "f3w2xf4h44st6qtwoncs2fzwjvpclzh3luaktjv4gchysjv74es62nh7n3m5spmpag3pawjfprieop7yfyiraa", + "Nonce": 88065, + "Value": "122711999841970259", + "GasLimit": 56453513, + "GasFeeCap": "1771368949", + "GasPremium": "124471", + "Method": 7, + "Params": "ghl/cVkHgI0CopxHYXruPxi/E6yPSepNwa+KyzKaMFKrH46m4ionG1JpoGXAyy1gGwHhK+b08qogf9dkFilsvGYIQacS2TpfxIdGoSYB3cOv/e4h900hUf69L8NjSFoMvUxz8Wd3JAVwO6idS0DkADo6PezQlq6oIeuY4eAtn/ojEV2YIi+U+VP/2GBMjtn8lmo1kuz8qImgUqS8UHVXnFMEfd32FH+usKvM+u6YODkR73cIuYlRUT9zo+/cPOmIWki1vuPKAZYBgQHshDbzo5gbkNqpbg6tAZuycRCYhdBlTv2YTUQnlwnSBeQRmJuXhS/KXJtCyrLMOHJPe713xkFB1di8UiXoES3f3TOj25sv6tzHUBi9C93j2P0gYLLqQ8w6WaLgcgfjmLLzvQUbU4jHXpQg5cQhkkkqif7+4GJLYovXp+MQpAlUILzWe09A551RNsmRHqBvhO+2iYdLgYyIY1J7VCckhW40+HYHE7adnyuY/RQyKp35vyc+hrvXnUUjqAfMAYlPLPgnHVO9+W78MdvUhxdCo8LdlKopU0hXuFjBfDFKXKAEVQ2DoWBklAxmy5MCSKhV7E+70TkkpBpXfIYa9vFgtBdfajL23B2ubRu5Yvq7dzjBSUSo/grUVM5usTloigfXJcOmOVf91ciIWDuUPugf8qk/PWtBEoinAX1G1WSWo3zjrNfANtJWgHgFL6slE471rr+Ohyqjfz7QJ967aWFNPRKFK9Dvwpq2u9JabJRzAJosb80Tjaab7N0foVxpPLBIsKFBuWxk6BwUtFY2RTnDqceDQc+rem2CV6hBYKJroBQkAC4R381DQXZPQVz3547OdInTeFjqdy4fHjVblHC+hVouRkc67DpvPWa72/moJFe4Lmxg0tqdn7YXtw8zPgr/EL/s09CY1YiNfFtos34GYr7K+N1rJnmmK+Hm7vBrg2uJt46VNNow1X0/3e1eGIVY1fS0tK/Q1U/63kIAiU7Hb2k1lBxmstvuUMSDDLXK/W0kQPgXB2Ivh0X/5am9CYQeh9apU1wXWyL2yJ9WYElWhVgUzxOGJUmYA7z3UV3sZGUBSx9JEO5ziaqP3bmEYYNgX6Qbo7Ty+QnKUTT8j08m7fk9SG/K9nOYsJMDz+Owp0vbhuhA92NBPEN8I5jtzQt90z3eOVzsjuw06Na3MkPd4LTWbweojNk4jRLoXLeglyPgVR1moZ+kpR7HuZy0fZLRC1heqjYZc1MBjJ+SSSuzQzlOjrLXSgcf1+4FGlzNIbmE6FUE1GWcew9GeIuPBaEB0hyo340Y4h+8oMUl1Prs3AnshOKOh/3qyWtt7tQVRE6MAy3tKbzV6puxgICCQLMd0oVy+5LxNk3H4UlH5TqzKkX5Fs5K+5QzGXel4itxETPwx5y6vzYm6hnzyE4+DgL7pzt251GWvrue1olUKJHFsgPMneHElyoGLW4KqMp9EgRRHuhSbuqW6NTrvY9x76F0vzBWVDPMrvvaJ5Ma+K6zwGooDL2ULxcHD+oXPmn3XTVuEY7sGEncbcGVaGe/UYSVePa6YMeik+qBwgHQOnGnvCqrfihNF8tWFdptqbHqGXfKwZYOn3d4k0c9qHN5Aqa0XYdX8ecJeZQSTtaz2xA7GngdgL1ixKolJ5Tn7t/hKYOF9gt2S95YlxHossOGkAPCq2FDfeycBhpfuCPU78j8nFYAeNMECbj9lmNL5QGpI2EXSPAHlxgh4h8mmvKmLpSYhiGgOtomeCAQNfV3np0zO5TD/OMADx/8cAOLp2uL/eWgpfEN9wC0qvjB+JZ9Z6MA0pG2DzcrAUMGgAPNc8nSYxCpXQ9zoWDc3KTndYdEtnLjwxL/6KI3puL6DJvIEbXJGntc6ZJDAtylTKLWBw6hXklLd12QK5Zm7fv4b9gai0rlUsbc2LIZQkmeFBRTaxaeyTC1/stU18CaQrUFljjOJaA4JeNHeYAXnIBcqL9eCrz0p7R8sHApPMAfFJiKM4XM85skD0r8rcOfkETsblulWK49UaOlHSGYjwfOqFjj1WlM7LLnGr6v4x+joPYzmal16w8q3Na5QQDAJ6Hk4igqHClDiqcJkuFB3Ox3Oj2bX3dlduCNTHUyArzydJaH0aIIaBkqZA7OU8hd22A0Q6QjAaJxemFiJAe/0bIgiH9QVKdJ9KDo+67iHKKl7c2cdhHUefFBWAD52DGyha+BERi2q1iUAo1w2IWk26wzxgYn2PbeX5BWvCm1W3S1LvdIx5gnqFVfhCSKNlMSgF7E3FYwA5YHEEcGVQnUF8/sT1PtZV7i8vJKBg31sbaQGhDDz4OMrB4qtGL3TusZMVbpmcuBJfhY2zSK0spw+/ltBAqM/LtpVT//imtpzaxDput/IYPHsjbmSucDwh0z5WQEr1xepBE/6bc/fHy6PieUcuVA7Ms+KN+AviQxSwFFdg5b3hedy6AKXRrJE7lJ4S4CB9261tf1M3bnUjRV36mj/cWaP/tyqFheSG+ocPvxAZVmAYUxN0cmTNnjj18LI22TcDO50UEIDxfuc4q7brcQFX3XCyu/E7rlCl0xypdVFGvVXg==" + }, + { + "Version": 0, + "To": "f023678", + "From": "f3w2xf4h44st6qtwoncs2fzwjvpclzh3luaktjv4gchysjv74es62nh7n3m5spmpag3pawjfprieop7yfyiraa", + "Nonce": 88066, + "Value": "122715528785623399", + "GasLimit": 53841013, + "GasFeeCap": "1857320180", + "GasPremium": "125623", + "Method": 7, + "Params": "ghl/nlkHgKN/bfDslcp7xGL6MlEM8LDqnq/PiRNwW9/8QYCqXz+H06Hh58iXB4ESC3UFnIEkOoPoYmmGTqzNGDY+ZZNfuHneLx9bWhnAiYGzLNojwtZ9NNpShNs4uSoOUQgJthrHDw4HSIMaytruTsnucjo7UDG+QJC5hujUQBK8Mkdzg66btBq/73Z1ZiqZiacxUwDke7fmPk2kZO0/osZJDhuaY3oQZmDcl8xjADAH8/yEVRyUtyru85NA5NeI2ZsLof9ql6PX58cBueDEzUwG2q1VCflF1qdeKH1USGbj4fKmlU5+Cgh3RLzPHSGeWdp2Z2igCol77cNVfh2EClYqwfM9+h2Q9Ob5WqNQjqhQpmNg40ZJUAmAm5okLJoL+HbQdzPoKBLVlogQLxthvnLf1JRoFowxjBBxDgHmWbTUfi7KijcSIOz7C78NaClvFRoMnc9OR7BtISfrS6GAvMQu7rEzI6cgg03avk2XXUz+Kfyp4KcUlmfOGdcVngok4VnpmvcNhZSuWbjk6inlUL4mDqoMn1GjWw42CsFa/+idovzSZY4plcidS/CRhs1rDJSdWgclEbFVxUGl+9GMrtfNcjk0OkGXhtXD20IbSSkzyuyQMTITuPh6zfH6rMwaHU4ihXxL7gSm0+2UJmHXRXbyZnC3E7Gfp1tNJlH3jzmXbncOfFQ+lwaLJUSLvgJ811RkmOGBPbb5pOA+YnvvIUwJ972426PQ6i9mhsBKaSemxcEs7I53DkgWdnB439I0k+v1hN3Q+7AnK8Zj0YA1AdTJlPbo0rY8AvimcjjXyih5y+KVqlVmQSGr2mXC1601Yp8952nwfY8f1I75lYBLadrYmAtOmfEAnfE8Tiq1K070DS/ANGvoznM50C4jotM2uSmZPP86MQKlv3kZaJ78Hd/d7h54wPYmJ5bgJ4FNbKel8bXHCunmfoaUctVTQB8gLGCyKd6+SoM3xshpUjSwiAzQA6VUKUcWzahvjN9V09fMsF8//tkHVI3WrGZU8awe6ppGisQnopZn6nysOa/7MjC0wRD5lE/voOtKmCauTWn0/RR3/fcnMAU7eASegqI2TdlEUGcq35J1Cu8xdcSeizOoEwzeIpA4dNiLvhjZ05ckNJyW8exayNm3PvXHSeQDNT7PrT7aPxj5mCScfEwkzeYJ7K1Top4TsFXAHTNtGkh+pWT+qVd08TpOBVi1xFkU/zxxxH3C1Jmg0MRqwhOggcsUXhZYwcjDxovlYPkQpG8Sw1sLfHTiKv2JeV/3taxOXxYh1oPbaaUrEBQdpFR/TixPN61CPOkLqs+nEdS4+7bL4lfvnMqRTitN/GyJatW14mHZQmFaJbP+xPLA6mJEMj8HgpvrbMp5hj91RYSY439EHh2Nksc1Cqskl8gEONvXEDcNPLYMoQQwkm6/uFi3BYwyb0ID0RpSuKGoyeS2TtmTiv/ZNMzeKvsFwDq1uvpsxMYJtGasvpX6G1pSPZU6Zk2cWoFu6fKM1/L1+kosm29g9bH5qqvqW6CS5RpGwdUKivRCN1lVC6rEm7XwnMdqa8po1lU/yOMdIVs7hO5896opYhr13tl0efbuNq2sGCV4WCo7eLZwbKDyBl4iQJQS/zfCvvbwJBus3c4vqSaX3FSwhWCo6SnttRLUjPkjbGubWPRJaSaaIQDDAKaEqpIP61YGLuKviW4S0+6qZnLHgb0Ce6Y2NWvqaSCjqFlKMzM1SHAfDRcrkaGH2Z9gHmHsT0J2wDT8k3IPspIkkJNUUfHq3pCpdZHK7vez40vzJ2q7t5G0pNbpeJQiUY2rxmf9tFqQym6vY12PH/CazsnXi0/D+7xAeJ+5vSRn5jA4xVQ/AVwT7mKW4Ze3bbYgrIkbj/7c68b2XFOe73h4bkBQmZ2cWMP8rrgXc1yzRjHNPUqLTyIkNarUPhW54/VkVG47LVYkrvK/U9nJBGhPtFEWIawYujZGm2S9Vo66Fm6+PNs77W6O+y1dtqNtuak4wvQ18GHAy/rQc9eRIos61XIkkxHWQotSLBpaek6OIrdneul3nD5e+BczOqvsBe1xspZAMDdSqcdn5/Rpdgf/r69tOVVYRA09yqnrqpS7P0pvTPng222u4QXIFre3mPmlrKik3xer+Cod3ofNLF/+aAsJns3d9aqblYGPiaI920Dfpm7oiRKuRN1SlxGX0+00eSAGWlkfl8lmqXikemYt63Ti8ee6PxPB6XIebK5I0V67G3S9VIyPREUH7aboMPMqYPP87wsgbBGj3eIoNNS/DJiKgpc//sU5auCtKw91tnClPCAOCVeDOxrAz5UxjmwlDmc/mKuYv1DJKfQwIvFYMvfVmNFtm3orPWPNl6JyuPkJM76yWIZ3Cl4HGa9arXlyAf/0Jf7c0k5oa3v976bsx771ojrY412jmG3Xu2ykF2Tjl6V1ewGLFzTqzRjN0BBJNrmrIgEWXUsQy2zUt1ybzvkNVPjsZbzPfRcKwfNpbWnfUoBvLyJsC+RSJIoUetXwIGIIGEjcO5Pk5KXrvnbAoOBFqR46UBSl1XVTZ0C6pPEVUlHUquP+GJu9Xg==" + }, + { + "Version": 0, + "To": "f061740", + "From": "f3q4crr65gnmgldb4asgawtsro53jcmmn7bavuwpfulib2scbwqn32dzzcfbm7tsel72d7t52kpb6cy7chqmbq", + "Nonce": 9170, + "Value": "122768904580932846", + "GasLimit": 50852303, + "GasFeeCap": "983239638", + "GasPremium": "100974", + "Method": 7, + "Params": "ghkUmlkHgKjj8ct3py+eF4dovOTy2iPiSksrnWg4ybUNXGwMorZYqoV2omdoxn/NTQlUKkdf4bFJXAQiPx+yTeuNAI0uPP5TSsAUxQLkl5HaXcXiJmf5qli06HKmaM0mJUam4l5XiAX30EwpfdRHrDt3dr4bXm7ia6nd9wEsrOC3EToBMnep/mOXb1HAM8XRsxFxFS+rPYhYyBJShX6lnhYxLPbD5ONLzYj53g1/0pdl+E8m9lX4Wp6zpLiJk1IF3xLwD4pleo6LFc79Ioq0ZnZxCgUK1VGyhkOrUkFuiQsiNTlOWVYZbIYf7u7YQW/UsMYRIk+0X6jbGSU48+CSpGDSdUej5CqsnN6HWXrzeOFkWscJHwpDzF4MltNi/2qNhzB0i+hstAYNZhjoOVkM8cumYiUteSoHVlfNHwcMj3xlKnnYpmqpM/D3t9Wuq8QwmMmnQwOj/ogK+oJA4ujWdqSxn3LJSlPm9I+mFhcPmrWVGd9Ni4PA80coNFkBgUg2VYMp9q2PUICRbBaoHlTAofn34w88GYdXbUoPvWEq0AMzkJlPOqCteNL3mjg7AJwfA61hTnP/Sod65bgC2+hDoPMxmZbxAxxi8q8rtCiID/HRwKHkeVvC0fjmwhLw+EDzyR2qAhxXAwDaZXNTxrv/hoM8DWK/m0URYLndIh1YN5OLfop8hzg4Edh/d8ary6CkUDfdxXlZYZIw6eXMQBfYKNlcndHEXwr3g4Tk2f9sTsgLv30E06huRyIHSt6cjb5xxf/Se0CiOKDmjIOPe/79noK1M82dfIn+KrocGiVrzGP2bVcjH6TBO/Bo9E9D6CRbDIpCvunNxKb0hGT6YmwYHZ1sVvb+lbdw1GzW40qdQxsbbcJ+AkRzAwspi1IGz2VxcZbEEuElzQgMQkkJph0y0XObx5BO32uVBb3zqfS++RCDE5uwtxl75F+85C4q3vCAftwal66pdajRxK1H6K9K5FIu5Z/xt4DNwk8IAUfWWoSjrctPEQXFiuKyRQAV6gv/EhmJmtBVDbkU/cKO0lx77f3hJM2OQRhtK6OEqRWFlZJTjLVjYtFFX6/t91C6Fq0ju7XlV6aub69BKIdE07Nxeb+tQz20VRFIykrmJ1FrRIC6RcJEt1BE9QmIj0tdZX2Kz4xKw8LeTRdOcu9/MR8ZTwfgueUUVmfr5Cmbq/bw/e9XUlYGLyVylYXEPDKLp1btp4mT9E0GJYEhQsTingvjonxbpcNq92naJ4lznJxglq0wYkqnf1oGTabqMQaSgnxH+ZG+vzpynrS3mC3TE3VBu3od9mskRmQInnoVrdbXXmJUKDyjdA0S9+MJ+mY/xn7wyBhbN8con7N5yytu6/hLNaoaTw7cFoHsLuLuZTjoJw5AVLXQ4MfbyRr/aKhA5aazL2ee0ejX+w2BkKce1lFYzgg/DofkLq2xaQQjyzeync5WpmcCY7nBRylBoCXcF2eepBs9N46JY6RvEqUltoe+SEqziBLMn1kWd5Po2D+wWzNptywa+v2JDZlPYXAZGlxLAAsfrMlrYqQAWMHrCmafEPWmoZMBoA9i2g82izQrDLaTMmObhgvTXK6CMxfx4kxFWy73K7XDRqOVPKz8APcwniOrfhiAY04a7vJuj5i9+Ry3oTTAd0wKGBOHB1vDBDhehCNl47MsfBPq6vqRHLI3Y651wMRVeXoHNJr7FM6xUSnfeKJErBNjRU49vGyRAl4KjWYsHHsEzrS1onXAEmgPTJfReqroC0Rf6EMSZSezFlZt+c08SN+02pcYG+IcN+Q4U0X8rD7BH5fbD/kb4bEIGEOJ3McZOTOBcVduW/cAJtMGNco6Sw253vZ9uWMmtUbPB/OybgcBBqyNc6/WOvlOpuD+NeevZOdi7TyI1zS6k2xWOGGAKzxEK2gtaUZ0m5gBX0aavdwJIwUdX2Lyq2E9iVwwo2gyzEZvG8RImaiUkdl7RYorGfmqVioSTPh2dCnrdQhHDdd0jrmb9ADT2RppJ3KXcyF14VOlZsadGoqA3VNqOHN0ojNUKFgp5tk3ujV/+R07nOAX3YN+stG3YZRvVmSabVobZHEpy+qg8oH0T/XKYtWZlQv3xjo1PB9+ErPvrJlT1bQrF6cEZbVrn+r71xOam5iqq8TeDj/sbyhu75DsLKHGD0of5Pkm0Z9po+cPumrehkZhKAwBAa3bNdNmPGfeuvvURJrpHgHBscXTtUBn1FTKb8ySJhA+qlmLqXkBuc5hyiHmBLf/uvF5CMSYMyzw3vBMWxrToZFZJ5W46NTFiP3cnqQt8ktIIPmUAKvN8YXkPsxdWpZp9OPVAFAPi2zavEg5AT3wpN8Szo1xWm/8t3N15znphur5VCy24cE9ssUC2lNnfpkru19kj3ad6+dM3yktUFbTM/dy/QzxQ+wil4UP3oO5HkhQdj13/IX5ZWQdQxt7MREy0uadTf9DXNncirBx95kp9gptYkgMpilD3KPQbjS3tdJGhn0fYyJ5GAwOFHoH5qMj0tnXS+PqCUuzlCmFAsvPu9oKKKo6KaC2pj4MfO563pjOypd9FMaR2mgK8+dURQ==" + }, + { + "Version": 0, + "To": "f02490", + "From": "f3qlp7se6vaw6yg3sjm2pme3xbfw7avhjng2ilmkejujbmxrsv7v5netdonvcrj5rez5epawkxpnzaei27esna", + "Nonce": 152261, + "Value": "121193537706136508", + "GasLimit": 19124728, + "GasFeeCap": "1307208133", + "GasPremium": "100674", + "Method": 6, + "Params": "igMaAAE/wNgqWCkAAYLiA4HoAiAOo6lUgLI9Nf1Xupmmh5IEEs7+M5ppFmx6MNJY3tqgEhoAA7G8gBoAG2q59AAAAA==" + }, + { + "Version": 0, + "To": "f01012", + "From": "f3q2kzhc2zzwdclfj6imgiffn2xvtyfu42tz7h2gfstj7j7xjlxgefnh35dxnc3frwvpr35hgayldy6kssrt2a", + "Nonce": 590160, + "Value": "121192144352524001", + "GasLimit": 24148478, + "GasFeeCap": "1035261932", + "GasPremium": "101508", + "Method": 6, + "Params": "igMaABSOZ9gqWCkAAYLiA4HoAiAsemQbfANc8lC8X/9tIyuecAfM6BRJ6irud6yf35ZGCBoAA7IjgBoAG2Kw9AAAAA==" + }, + { + "Version": 0, + "To": "f023825", + "From": "f3woozrthpt5dqlb5kqmg4ytq4vt3fypdjauuyvr6olwszwffc6sl64olnz7smfsrkqfymxg7d2l4hl5egpz4q", + "Nonce": 167008, + "Value": "121193537706136508", + "GasLimit": 21673478, + "GasFeeCap": "1153483534", + "GasPremium": "100801", + "Method": 6, + "Params": "igMaAAFnr9gqWCkAAYLiA4HoAiAiVezmx9qjB5tFXIieW5tpk3TB/oBRr/OCLqXDTRKUPBoAA7FygBoAG2Gb9AAAAA==" + }, + { + "Version": 0, + "To": "f022922", + "From": "f3ux4a7ylxkjhquc6t3csakgalxqlizkjth2xva57y4y67rafuy2efdlouxghatyijl3zwzmrke3i6l5z2fd5q", + "Nonce": 8503, + "Value": "121189668022108035", + "GasLimit": 17643478, + "GasFeeCap": "2833908371", + "GasPremium": "100657", + "Method": 6, + "Params": "igMZD5DYKlgpAAGC4gOB6AIgIFI9s/43Kvzj7VaBAGZc+eanNqV1FD9K6eZAX/glYVUaAAOvzoAaABtnqPQAAAA=" + }, + { + "Version": 0, + "To": "f02723", + "From": "f3rjqeslxvswwtydbd3kayqodwslzx7lkbkj5sd75s5w7czsadqz2vpkm5nj5zjqqqumhbhf5cswzd4ueggrea", + "Nonce": 103220, + "Value": "122767878924261053", + "GasLimit": 53842263, + "GasFeeCap": "10524911434", + "GasPremium": "100787", + "Method": 7, + "Params": "ghm451kHgJDPEZ8kyMxtq5KCseb1OVhqBM6GyY63kty6zB+PczqPGu3/eKwEw1/e1Ul1ELVljbNanDpgbfb4gFfATF8I9MwIMWeAYyAfpcxpN/VNNN6aOM2veLW7ZZES2A1tyWCqmhPdbXgMJu4nOPvEsgL+z3GXv23pW4uOpZ5/k06+KCgzFsF4c1Jy6fA1aZzL3DFfOabt1LojJ03HmjkkHRbXBTd5Bi6wjP7v4QyyiRZnGIDQMb3INk1/UGc3LlFN5YldW6iqguJdoqVKzeShG2rlmmI6p5cGr5LV3bAn/mH8OCtN1dSl97uhbGZ4TQYbMPc3WKmETETnihLsgz9fJs3/87uaTd3CAMdkdzjCqhrANh/n2FqG4hSD9FFDYxDVunv2xBNXT9EzQOkJni7UCcvtVSOopCnjn7Od5l7XSwHsK9TCBqABS0gPoHmQSYJM7HiGuZMNs95V8Kh4YEJRAdkrJf0RHdpTWJYjWreyES+RefzZjhMbuioAggcBd4PwniTT1pZWGbcyUZ34rF6FBLHtR81ka19zOljZBmVAFlzhnFJLpdxKYEyXL91QQVj7axCTJKOu0tmq22Tcza++Bzii0DTKWW8sjjJ5x5HLqxQQN/0hOjqE7kvt1sFRucljhLpHDRKxVjaT1UxP3oxoOAWSEdEuq21RyKqD2NplaJ7me4E7mbvpebVKXsczMtYFPZAL8ZHh2Fqh93BOpuXg7MFezuHlNdZ/rxnHliw7wKdhahsD6o9ggv6UMzctdMEmFvVUHrP94lB1U7WusuJrEWMZ4ns1oSt3GMjDjelIS7cW3vAVseH5A+jTlbIx/d7dJ4gjq5mA84IQukLe1oiLz1J0vSGWvuSCSJkQ2ZLmti0U2fd+d7ncLMCp8inLK99YhLgHxAeVAMWMcnPnU+rJVCMQULzwDJgJU2VxmRleCX61DwCd+xtj5ZTOKLZ1QwCPKdyZbaYmlGQtnAi2VobjS8nmpzaP0xqgp9TBfzwv/nAKnfC8zgm8Xs1u48oXKpwdL9FmFLWkjA/guGsBi8BlEgTYLrhrjLMseLZxBFtnpvL+aiyhwUypzbfBqCXzTHjBxWSyVJR5NNyWc0Qzrd1cBGVdkiA6bnfLFbsyoAiaTUkg4Jz3WgkPVuTlRL6sCnnzkmgHlgo//QhGqIRMa9L+ZgEsr4BMKZR48c3kVYgVLHL01ctBuSrQvLIxsWC2+k61PnEhtKSiasLntsT3/98jT8WOohn+DlNwDt1YTkllOueqkD5QX68+JUyhihQ+ELMTIymg26NWsnAr1m7wGn4hNs+u+Qr4mU7fqLrmINgtHdOlLcSempNlu4ud3DzpdEKE+/y//oO2j0VjMrtWVsAcwG1gaSdxN48n8oIsA9+aN6mPEV8VYqADJTO6HB/OXuSAntdYng70A+0EdHNDqvaeekyObrnflIpx8Lo+8qIKOsfbh7At1eV6zWG24g2oUuQJCiTn/ZLc/2Z2MI6SGGq58tpTem8VD/+/bKhHQYRSd3PlLnhxriX41q8IZiuUkzwpltiNwK+YaFv20ZhFXTF0QcMdmdaEePG6x/M9CJTNR8TK+q1CaDvurxNSAiDPAi94Kz+MoaTMtBuSsPsj0DTfVA03wZlb/GRIXenLjsU4+FpkPSpYd6KtGIeSj/JLZUenlEMGZgIG4+9uxu+u/2rJsXLAxswrSaMsynjJT9UKhPOC6RTybhgYvtxcOsp6B2XdBnDsQ7k5ZbpHEpVCv4n95gZuaiEm47J7Y5iTdNICfP/qmMkdLcMXZVcbZJOdcUuj4ZDy2qw99Cv4PS2r/dUuDg1hVZI8UBDpJ8HZWdoQ+e7wU8RDiJtdAqD/5+v3QodfNLb33IsIa4AZsJSy+tmGLPbWBHMxra9HIvu3Z6loNo+CwOmupWI2TQPE/fVW80S5GWvBCg+CsK95iBosmOYveLqeBbYxrfO6t3D3kxHzB7OB80b12cvSNIGGYNEOuIQfvsba2LCAW4Qr2DNZtA2QROcg50/GcaC2HVXVZ8m8WoHLexJg5eHuee2AdpyoqRLeYOcHl6ijOap3hpRm/SCBo1izkCiQryDp3Uw/kv/sK3Mh7JD/yuhquTrmYckERBbVcj99wpHQj077Smr8+IqmVRoSUAyo/I+Qm0bIgBNdyc1nm3u5vEjC67ne9Bf9te+i0nT9aQDxWBvzWA4lNl49Q1wWTzh4TP1R4/VyAefTrIJYSb98yzHw9efXmHOAKKMRPEdYxZReHkC+D7mx5Qt7yCIT9BI/YWwQDKdpS0cdF2QwZs5OIp09kp8zpYnYmJ1W4knXkpLXDZuctqNLYyshjDu5SyThNGKiYZ9lrhuq9LY01NdGpU4gIu4ONo9khdW62ccv16OSU5hsbLjbxgvTPkE0PpAjFuZUkuMkWwJxFPU/CnsoOqYo3hDWF6LDyZSus3D4owDV1c7cVj/aoBAIYa5zUMvZkFMurh4YQeQqOvIZzsiX+onUTtZqAu6l5rMX7ADnh4ZLhI8JxtpH4sT+BTqujKiP09gIaOinAUKlUrcWFv25vsUsib8kDyZCijuNES6mPA==" + }, + { + "Version": 0, + "To": "f02723", + "From": "f3rjqeslxvswwtydbd3kayqodwslzx7lkbkj5sd75s5w7czsadqz2vpkm5nj5zjqqqumhbhf5cswzd4ueggrea", + "Nonce": 103221, + "Value": "121193649549989127", + "GasLimit": 18190333, + "GasFeeCap": "10280067024", + "GasPremium": "101022", + "Method": 6, + "Params": "igMZn/DYKlgpAAGC4gOB6AIg/ruPCfTzapIG4qy7TyCw1Yk3z14p+ugJgd2Xy0lYhQgaAAOt0YAaABtmE/QAAAA=" + }, + { + "Version": 0, + "To": "f056611", + "From": "f3qcma4wxrrzzs5y2azge73qtcpjihjpsqdehcqbfkqa3po2yoyjwbvwau4qyrxnt6sva3ihf7vbhtba5vfwsq", + "Nonce": 64846, + "Value": "121193649549989127", + "GasLimit": 19754036, + "GasFeeCap": "1265564161", + "GasPremium": "101179", + "Method": 6, + "Params": "igMZj7rYKlgpAAGC4gOB6AIg3cza/LQi6AKhSo/Vwz2D05HPD/uVPytX/qlJKtBYFSoaAAOxkIAaABti+/QAAAA=" + }, + { + "Version": 0, + "To": "f024563", + "From": "f3vgrp6y5iqp7df6jc7ibzzythlkluei5x3vivwajsko3k6za3utrr5ajly4mhgiv3xggox62nmbb4odfqih3q", + "Nonce": 466675, + "Value": "121193537706136508", + "GasLimit": 21104513, + "GasFeeCap": "1184580757", + "GasPremium": "100685", + "Method": 6, + "Params": "igMaAAOX9tgqWCkAAYLiA4HoAiCOtez3abjQga+NETnV9LhQcP8ehsYLDs3EW18IovC1FxoAA7J6gBoAC7ox9AAAAA==" + }, + { + "Version": 0, + "To": "f024563", + "From": "f3vgrp6y5iqp7df6jc7ibzzythlkluei5x3vivwajsko3k6za3utrr5ajly4mhgiv3xggox62nmbb4odfqih3q", + "Nonce": 466676, + "Value": "121193649549989127", + "GasLimit": 21818566, + "GasFeeCap": "1145813157", + "GasPremium": "99757", + "Method": 6, + "Params": "igMaAAOVttgqWCkAAYLiA4HoAiD7bz1yjLfM0YYivGULuSHTP8GYMQL/2rNjTQWnEAvaaxoAA7HygBoAC7ox9AAAAA==" + }, + { + "Version": 0, + "To": "f024563", + "From": "f3vgrp6y5iqp7df6jc7ibzzythlkluei5x3vivwajsko3k6za3utrr5ajly4mhgiv3xggox62nmbb4odfqih3q", + "Nonce": 466677, + "Value": "122741859352305200", + "GasLimit": 51052908, + "GasFeeCap": "979376140", + "GasPremium": "101163", + "Method": 7, + "Params": "ghoAA4k4WQeAoHTPtDY1c0BmyeejC4y6XAjhs2kCdQk9d7VsBjLhO0LJIw0MsVjItuzo8p3A8Hn3g4q4NctCA20rEMFHs/X2vYLBBR1KLHltD8ITcxZ0TYCWsawtEF9dSWhsXl9QQKDZGC6N6YWUZzcgQ52VNKrrw0yS6GNCIApx7n0E2yHbzIZ/EFJdeMfmRo9yv2aC1cSkiGaDwMTIk5gh2qKNzPB/Epx29olbzrvAjhvC5CcTL5rAUfazlswWNrMYohnK+0XDoDj2TzQGaMB1vzC5cT1iVjj+4t20xc4qVMnASdOiQb1e0r+fwGkdIjn7kdzUd6UmhC0A/qLLI3DgAXKrPmhAJ6nBv66HbkX97ELoII5Jd7VDKquHy8XZAnGqjXaA3rJTC2ye8htg7TlEL4p1plzZv80bx4StJkX3QRTx4BB2kb8bJezmwwJWLYXUkf9dOaUGmWnjS+h6s+0kCBr2KlfQy86VdNzCWNrvFJ9fbLElMse3OisWyELW3IJtjB6E4QLtlbmYPh9FLPlyzIZMRVn45wJ2vqZC4udye/vGUobWPkrv1wt6oDk0aggkKTQBH+w2kdaUMviMGmsZXYV7KAWtguWgPV6ru5wKdoV/0RHWwQLxc9WKEHgbmdLAZ3woBkkkGVjhIW4Ok4QTUqIIzFAI/DIHzecCGoZj0DblvNjOPjL67muE8s+K1LB/D/PQXNcUj70MC9psrV8WucEWmjwE7Hf1u4ltTmloh5JRrqxjiK60vG82jlk8BlrR9k3v5YLqmKvtL4iXVMwK5/C7ROXYuXANSqMkCRe3lIKOCEZRuJ/SKp0TDK427edsLgZk3oRggeUvNM/nD0XjvuvnkpMksVurMgTghtvxE1qco1NmbezlN7aeHyj8CNNvWkymayLrE2pPFOZAsF1D/nkEddt/W6QFhlhftkf4kK4p64C6qCqC8xbPr+Q/k8vYK6lesZY/kxC7yFutXgGRXYerENPqMtGsalwst/D6D5y7KSciIXRJ787/oNpv2ZUlYMXMuV3rsn9PMAoblgruzQos5WVEZkL/gnY4dx11uVcbk0s76ojQuYvivdBE8FKvEu8ii4VOhlY4aCVV2Jyf0FuQZKK6xDm4EsnNvmiOxl7xql6z4E8yhUOTT6LDgKRa3Hgs9afCFbHoqVcQ9udn37TDX+PNgnkgssSC/2OTuZzvWOfZFZorWIz8+ATdd+8Ii3sYapLMi5YS6WqjrhYNFFRT10G4+o/ybXsdFSzXZ/DrdDMgcdaNcFp6zxqZ1YwCKZSuSC6Jsj8i5/d84cNvcUpxyRx9F4HXuCl7sJb8FY1cl8oqPkILUndjxYYGgFYy4Y0hN0wpqFF6T5qwqiwSo6SIrn4QhJa7elGqWGwrhQ6KZUB44IDXh4fs550j6g3pSWDNHFAJDngNxcJSKcxx5pggdoCW5YnLNLWLnSMR6uebpP7LeabtHsGaB7HkrR7o6ATKCcnalHGoaGNnNskvGKFOitNZ7V84gaxjBQKfnoTFAWZf6lVm47cMTgsWwTy1OedHlsPSrPErZvX9UJuoBB+evOrtrmjgIlbV8CbGdjzHRQKcSb65kBnwsC56xp9Bdkdrj1xzk8MQCPqK6eGo4JgF4Qq4iVfJZ96lDTq0LDmGgTx6qraOyq9bi01DdAiTZb1rEqPhEOfvHOsQTOXYqnkmzh6uOfWBhhpDGkQKLTuzBcXOSiMYt+K2w+M6DCzakJIoG9Q9sIXz1iVbanR507VGhtgV9YgAuPQWxmZMotYvug5lOE7/q+K1IOtUVcw6P3PuRLh/t9w/6+wmmkGyBNAefWvxE69EMEtA2qezb8TUg3QLEyDjhuPFSzU9qF1V/x7rV1AepjVPg7IGkgjJfbK+5+FarWuazW4+Wr9LBaXc03YmzgGX7M9wVzgb0/kPDrUOnpduGWFDZuae7yVbtoOqT/5UIFzdM97jSx1+c+GX+hMGXmG1jNk/t0bdmtzXvYtSBchmogTMB2zBwvtsruoscS56IavJed8OgtrzfyvY1aasXytGB17tKhX7JZ7ZLV1+3MIzkWrhpM8drx5+TdyX9obqoZx4ESe6PGIIdzdmLyJxyt3qfyzY3HyE10wi6+8P2/4BksesLIMKYCTGLmyfr1juYk5QjwzZ0/iqCyu1tewU7+ty7BfM1G/aD5exmUzeDhF5CCR5lRTMv1/DVyCcfHMnjST3b9Zjo9NV1GYV8slYFX2Z7LWZE1Eb1mm5uzJj61HKua8+FWiM1qMT31PKzY/ht9mWL56atzYgV33ICar+M8n4y+SZdEayTa7Srbxz3zV8pBLFML5N1JSqmUu0VklSqSliXwEFGGE0QKOTQ99yE0rko829zakZaCXtaSJO7Fb8k0NZTLtAtVoD9QAGCw6a8wwIJYmqWc26oiCaRL57S8QgVDYncTTV6F8DP5N8z1+sF8QWLuCK0XoHBTaF3vjRJdTsxL3GidZkuqWtMWU6uxPSZOTsCby9GaXc51WHF/LlhfspwZlfinl9lTGcI43VVhaDOfzsYPFbbbLA+aX4sCHMl/O49cvOplz5z6CEADrp" + }, + { + "Version": 0, + "To": "f062931", + "From": "f3rim5daueumelcqpfy7zzp3rgfzb5x63dyumgk3jggsk56luojtsth4gbcv4yxgrkveg3nt4w4l3bsr4hssxa", + "Nonce": 49697, + "Value": "121193649549989127", + "GasLimit": 24215891, + "GasFeeCap": "5000000000", + "GasPremium": "100658", + "Method": 6, + "Params": "igMaAAYhWdgqWCkAAYLiA4HoAiA5Mr/z2zAfiL96IZD85gscMuJxKgYO/uDfh3eCeo+4KxoAA7JxgBoAC8ef9AAAAA==" + }, + { + "Version": 0, + "To": "f062931", + "From": "f3rim5daueumelcqpfy7zzp3rgfzb5x63dyumgk3jggsk56luojtsth4gbcv4yxgrkveg3nt4w4l3bsr4hssxa", + "Nonce": 49698, + "Value": "121193649549989127", + "GasLimit": 25805333, + "GasFeeCap": "5000000000", + "GasPremium": "100844", + "Method": 6, + "Params": "igMaABPcq9gqWCkAAYLiA4HoAiBK06uYWBCKFhad+QmgnTz7vO4LhsW3EESfkBna9q+YFBoAA7G8gBoAC8ef9AAAAA==" + }, + { + "Version": 0, + "To": "f029404", + "From": "f3rvi2y7hexd7kjfathsxnopwb63llezb2yznyi5qdceulwiwuz2hyuksqxzrrehop674ue5v2nnpmykd2dlqq", + "Nonce": 49070, + "Value": "122768968070332201", + "GasLimit": 50853553, + "GasFeeCap": "983215469", + "GasPremium": "100522", + "Method": 7, + "Params": "ghlpzlkHgIRu5QmBmTCN6I4hafaajj5HnKRhW3rhW61vHprg8bYPgd4KatrzFNh0OyncokMQsLOOr6hcXMR7HjCSK0hfj4fTVGufYCfTmNyJ/6FRxQUkxDRXxsU4iBrUJNUPiL9oVA8NEUgzuuXTiAEakaAOQoMuopjJBR2BkZ36yT4gPV3wuvQHXAd0KzJ54nTwMwcGnKLJLR4ALK//9gXRaAfcQSrQ1cMRldBKXS5DBo2u4zyljOTjR7+2FQcFS5S3modw/pjLXcd2b1oCs9f+2RYIXbCT02dJ6oQG9q8CHG82alFck9UFgQM9JgPEjrX1eByjbZZ745mh5ImO4om5/4WyCeawB3qpl/Kgrak3j7yI7ifG2mxekMkFHSVNrgtW1XfUOBUdAmm+aVda6hzqD5McOpagNt99DOI4TJVltYebDzon/3YvYD/7FMAPIGWMgqbH9YYTvDKEsPjl98yj/U4OFuJoxgNkJhCz+SsvtJQIqlJAvlPjbRNGxVYlPoUbonR7YZJ8xIXi2f+zCpC7TpQXnSQpIT1MxNEUZs0PCWLEY7M2TeUOVxTAIImj6/6UujtTBKh0NWMjgKA5IImQENJIem9aJMku4oihmJH/x/amaHpC+E76ZaBXHz0Bdkt6+1y2TQFicIrg+IRTteiQBurXdvBG62CYxzCWJSlpcfJNEd0IIqMjaJSBV4a8ithfzcE4U4Sviz13ayMW7R9SQIQiSvem1+b3wSX0VWZcxfcESCBNLLuRNQXgT5MzNJOhkeWvLLUmpjMRex0M2v0e8scLO53J8qwR1pwFyX5QiXCkuyRQUywD+Y3XMgx6csrTm8kPYZGTzdogwisGx5UuSsSh9oaxBcT3HJn3IqLvvfljbtCRF0qN3vG/choLctqcycJYPxldz62UiDZ+NQgZ5wf3/r7LyznGD8XzhW22jkL4XrwkzrOpSnVJ5POayS2hY2Xrb7Sv09Yy5thc7xRScZWAMNWw2a8z25eWQjXbVunCwJseol5vyvjtl4VfkF2yHaqe2o+rg58Cu1ITPGsiMBeExe4Opz0a2LTzR91bsYkE3qTYzErLVkhPi7oC/2vNrYN9EasccmSMIIBx3OflyL14kVFDgPo1q48nyCmhSdEBrUjuUm/k60H7FfmiIHlpYrCSKhlTX3OFbc9CLmO0sHdq/DFjW6Ihymk3UP2Kzz/1hPk1GaALO55SGnxwlw7YGxBNBJO662HJ5FV2Q4ephVuHSCRcpZEis3Fmz3ZFSC2Si5Q60x8+HXr6R4NT7oI36Ctjy7bW+pT3nwrVnDSudXxRwRs/KBH0WwTYwugMbxW354FQAhkkyBwkAR+183Ds+tVUs4sXcflscSjSsbkDZmYGfCF5NqB4BvULZzhiQT5xMFjBMSpxzn78VXs55fjfnW3SJxYV7GSRL3ktr3a7y+UYBGf+ocFPjxV4qjyTgizoFP1ENAp4W/K8RCsOUyEJwDGQILAeeVb6KBbblfOJZKvSbu6smEql6/amc4KfXqoFCA8Ja829xzLckDg/qGuf3uCoRJP1DuC0QrWabjsvqUjHsw0KN4GbXN8pE5zAjsay3sLX6/zX8kjvkze9zs0PE3PuvYd+oXZDzDbafqE7jctP6z0wgpIzZMgTUaCQOfvmh4k16F4OoDjgAt6pcpyuSEGW1gRMw2hvL++C128FP3QZHb1i/Yqep05KC6u4UvSnwshhVSK8k3+Gsvjrwcr1mcupEKsVimWi2IHLD5+lxtyDPkqmJCWkmkO+3KvHn4CmQMdevo7eVqc2s46O6s2Ve8p+orkLN0XnPKr6sfrf7XdEV3ncj+LL5Z1h4DRlEhuLTLpiTVIjSunhN+UNhw2muQcGRbLPqsWyVeHX4hvNAJpHLPZFUwMP7tl2kqW+0N/hbHpRHXHUSZEPoSW3oEGUUruE5wkJVBzt82JhMbXPCOaKbCQd/e15g63v/GJ5eVfN+nF1+TMI7afBkWOkXbX95lXk/4EqQE+67ugCfReCFWW67aPLVuaUuVCV7gyRktcjTOcDNje3PeFKy6EwrQKorMYp6bZYLJxR2Aq8jPra5lNvl9qlajC43K21G0h/24jISKRuFPZbfK6gpHiDLaDP89kIxqjXbHNL+jeaYdQDmRK5hp8Zi12JU+bHEE8nitaW3SNF0jjeQFDNsZKFsRvliG33kwudBXmyypjeyav4IOt9758o7oPeOJnYQalSE7RecA4waxTSuc9YoswZx2qaKJGQb6p2vfxI21G9P0J0ZvTfIDI89NEblJryOs2Rz8hlJHZ65jK/nf2Ih6BaWCja6acopaszz9fZYGNP29AUMpTIDvbevXnzS6sw7X+fWFQh//pNBsOdzBzKYTQ3RFpMkeyoTY7aU5O7HsH8rdVw5x3xpj5PUEL2a1EETrJZ2N2UtYjSLo8wHvaiZKVfppLRdAmQmwI+HyLApJeiu6PX66Y7OxDKnnCjv42fSSrE6lRgu4G8++M9JFZT8Crop7o69bPlhZYK5K+E8afft7nv/Coet4uazLVaFrcwWsMq5BrLk6q5gg14PSWpa8z0hnnb7ct7Fg==" + }, + { + "Version": 0, + "To": "f02438", + "From": "f3uuvgrmepryqhcpmxtcucbjsbasvcl4k226lkiyl4v7ko75zqirrbsys7jt3cqxb5jgviubit5jcfkzqbsa6a", + "Nonce": 1231061, + "Value": "122769140028509879", + "GasLimit": 57953856, + "GasFeeCap": "5000000000", + "GasPremium": "100259", + "Method": 7, + "Params": "ghoADs9XWQeAr1pMnefa23I/kHrFHHm8w5JSPhecKEXXdZL0h3zMieRUfddH6GKpnw292KlLLi4DtB/Lyvbcr21Jk51rp+Sy22BHO5F1ZD2n5dIBIPpIf+ILm6OTLg3bb7QGGBd6rF9IBROBtIb4cGZngut7SApYvJ+pfOFkLfOeiqbpUKpQUgSdh9OFrL77Du4plaeCl0TerOLCiHEayCF68B6XmZ1m/ebSdE+W9RfxAEbXdhiw5sidp2jXZa51wnuVZa2OGAgUs8ZA4GKL+/awAW+VpQdVlD6igdlsb4/PcJnU3i1DYty89el1wMYr7utlizJkYRcWiyKj6vHeIL5dU2u8EmQR6jJktlXC0VTtwVz0YLiHk6VmuXLM60mkWiNiUzPP0BCBFHoCST6Ih23Y0BLwgBVYUq3KX4hIU9xK6U+iJ+TojaI0KVB6RTtQZkNG87vmT6OmrUOx7Seg0hSrjLplR3C5rGkNVfZZ7+8M49Kzmm+FmHhrTEbyPBCuoGEWKlBIEGtFksIeGkmZNUoyPhFwdnWxK/tFnuoqXNnykz4yuv0Sj8TmEAZtqB7Vtrj2DgLCtB+4mSoY2hiIPG6DKbFtMe9BT5B/g5HCjSq5Vj8oCWqE6oDiiJgMPxJcMMlinaSUnACYB8NsR+NYPeZqU/VauLBSmpnvjxWd7DGNpN8tTOR7qAz6dOe/SAHf20S36Q7Pr3R6pkKubyYCkpjffsKSt8b/+fCs5aOI5+ayf70IogG9/uO3l2TqwrwPFpXD8RUgvY+vqXCNm+qiy7QtObg5ZTeO79IOQcAlMJ2b44Scu/YU/OKsUaUW22gRzfNm4/KBM+u+pAHDmZT1DEOk0b8QFqkzVE6uE9j9BGyhJXdpLc7ZGZYgj6gUlQcSqovIe2JmuGusB/wMjhHaUbmWSeL0iFN3hrhRA/v6MXZFPUNpAn0QU2tFtVqwMlw37ZcXo39fiWZkpwDOEeRKDT3zEublHUslZqlPXmutbrEeEqM3lNb5OrIipau4TKH9KoHs/6HNwaetjuBLgnCgNw27AsoCtBjBP2DZ/AGe5fOl6VYE3YPAWBXUGGJ+COiQV80YQQntRwbYo5m9TKZE1oEOWF7xf16yGWYSao+H1b7PbWvZiNQcJrLQufw3iIdCcvhqGVrGq6sXDy/fHeffoKZFqjuPHc0IEzEP25JMVlze6lCHlZLdWKtDQ8AKWv2xc8hUfDHAmzIWtVI/7Xzr+y0QJIe+q0bp4H14mCXj110TVeLo+r5umQm7RRqatIIKLhpEbuSbPOSArnw2NAjjqNBj+niJH0y5pHSSjzEtb80iaRGXdVlIdQCU09H3MI1BznNAttDTZgxemTsK8MoxxkHaKzzHwO4UfofF1TrfF/dChmRAsMK1DpvRjyeBRr8YHQPU+ov1d1KZBUk5OegO6SytiNxTGQyITmG9oXJHh7CV/JyI5fd+h68AwTxWBoRk0gXMQeNn5KfApS792J60DeoJ1WlUamB2ob4yacKe47XN2G5iazdcJJoYL68kAPuXzv6wpKIlfeZAjLDeZVGbr0aln1J9Drsb87yDGl4J+7SRfjKWVPljKcN+enIPPv7kRW9mgHia9+5Hk+I/91ttjJjfDAv0LCmVDFAmKIu7s5Dv6B06w9OlzD9s0VOoAqGx316D3C2EmBnvChvsvP5Z0TmOmTOMGvkbDHnlc/SHW/V3lUobSOY0q+RDdfVE72u8a4+ApoWsVum5hsVmSfp5JgX9DGBHSECHbkOhVR4DR6JGg/SeWTz1ZsGPup0jh5SxVi3DJFckQoTPt155qDUNBwbbTM8uF+do1xkEc+axlF16BfWRHVOJ4TjR48RzaPToti5KzGO0gInbhty4EYrI1Z9wvQ+LfxP/wVNzIOxAQZG7GzSw2lv+eL5JngBy0fMJs62qedbOq21dEIsPrq7JRSwBT85YlwLn+w0yKu/5cVeICZf/w4KnfhZuhROQ+duKaoCpVIb+G/wXg7r/pSkZcybxq6p54jpJlX6Us0lsPrJEZDNWCaZZ1cp7q5TqO3IfZTeZyYUufkrbtyW5cnOwZsZlIvWqTJdohHaZVxblj+Cj0xiqB+EhPFgIy4oMr4Q1OkD0F56K3Z+dkQFJhbzXma+0SB6/1jUNNULck02SYarH13HzXSiGxobGh8EdU+0wB8CbK0MtTf8OFH+ZQaVTI71lspNwZHtsT7qgLvwptmkBWJ3rLKvGZ0kBDWLoxaioNKshI1NZDRc8g0M5+9kLg/z7Ync4oEZPvNAWnqOwroFMtgBn2oR2/VLF+7GuRWSmjAyVqTpeO90JtXTierxD6K5sXaREYJMnEIsCGQwdFb6RSc/vLyZS4X8B/b3xOIQCRClnn/RycB59mJ5YCqrdEEvqT4dGXybq7iGjzmXVLeYdVy9LQ2+sgK+CbUNJdpP0gx/ZJql5GxFhCFxOe3rZH2euz8vdmPcqMooycUclRdBu+6SBEAS/ebCUtvUn9WYxeYOuwsx8LmuFhlcUDvp2IWyb4Q1FG4gLNEC/NYbF8ihuKJjRRdasInTz1l9JPZrjKITWwVSQUgtc" + }, + { + "Version": 0, + "To": "f02438", + "From": "f3uuvgrmepryqhcpmxtcucbjsbasvcl4k226lkiyl4v7ko75zqirrbsys7jt3cqxb5jgviubit5jcfkzqbsa6a", + "Nonce": 1231062, + "Value": "122769140028509879", + "GasLimit": 60945066, + "GasFeeCap": "5000000000", + "GasPremium": "100409", + "Method": 7, + "Params": "ghoADs9hWQeAtz04tUMAHij5RV9r0kGBb4LXyISXw9xzYX9gSkIryEBe1U1RbOh0XeUxrozxn5kiokvaXC7Z9e9iD/mN8Q3751471AGbCzvdWs73fa1757/AKc888YudutKV7GEJSlATAZXlx9rsAS1Iydi771f1xS4ceYHsuEyl9UOk3GE4axky3LxhvFZckj1lRImubghgs2+h4aoQU0f37TSTAfCeKFMoC+jbZ7cgZSoGAtz2ovUp1NpAsufkcfJalHAYXkoPs6Rku6V1Q6xyRQK2usxEmndMPwBQDoffHXlWYMOZMpJ7mTgFE11RYJ49EbB1MQ2Iowl1Uyd4kzTzj7Dxdakw/de5pqPHMUYdENmKSfZsDT321JqYL15cMgQheAwk5xysCq9LoISaanEdEgYLVEj84yGTCcEC0yrdfVuLUW5z4WSoLLADwZcCjU1173IWzOYglr1jL66Xl1aGbE3BdfDWc93VgfD+GthtFnJgoDFcklpSFx9mhCqdxHfV2aP80kn2jEBWM9jhuce75teAYNtxRJYw1d8L3dW1EzIip1YaiEN0Hgz4Fm1KHOWJDlXsNRZjjduP5OA8Ys81yr8TqAvO6ctMTCX5CuUUJjkISRG6LTIwmz0SSdu4/Z2wH+sENZDUCxWEtSix6KVFx4aFtwGs5bJ9uzBkyNnVH+A3bkfXhPocXam5Sz9rGVFdq8o6ddbLpBppu0SwUJMkNz8ClvOGXSZGnDPdLpfZ5H5J25drAQg49o2rSOLzck14/pohdgaVj0U2nCIHTNvw/UdOEMWaYt81yQ21YgLwFvddnjTDSM/4qvDL24XwE/YEhfBkgVVFrJ7mxP5zBgtz8CrsTXKlJmkDecUNxR5eHAol5FTLGLdglxyerpCIEwvV+KqjRqBACH0bM6fMQmvUVzZATonsdPQX04ENmX3SHQ+6A82zbzjFkco863yJoq2Wci0NIA6sqMXKnyhDo+zmiXpfxRZz0RO70JCy9LIFU7tvu7iN0chPEI77LNfFd2Zhfn0303pbtMil6r7YN1/jS7fudYVudcIclQHmrbycelALEaHM7qqj+8aMrACq0spMrPIOOm2ulr71PD/5wrpmQ+hWmOpRcYkyQQZMWGJ/Nb78TSTetFMpeANDUWQZzmKyrImDnETzFhLhtStMizWEsCVvqSZ+/RoMAKiCVb4okAGf3TkXxRP5C0UujmYEvBZWxyyIDnKLuMLHshSB4mgKjIM64A1FsQFnxVZ1zalxh6HWkywc4ltOrnaeIL0PYRo2IV8Q1KVQrwQUFPxnfTdnphvGeE0HOgXXZEpFRDXy8NA+Y7ETA6SWOUPJelsWEflzVsfQbqP8uOWJv1jHBIketK+FfkFQUtj1Pd1d/AHd+hoNOQlGFaE/ynNetLptgEaGi9SvcJeTEEgdAaKO76JCW5PfpajCU3jH2t+RJfbeUprWwk2aoCl0GduUvih+4Q8bwvo2qBTmjqdL3U8Lw8rJULU5MM9d5GuA5idSUjzDRtU8V7ovMrwtwJcJNDLPcLulTiB/BF11okui+W0fQVo2fHisKozhHjU3c1Hp1mXWUcBo2pz1EhF7vjILYEY+HudBkj+MaDlwkBPhcdd/ojIFTSxNigfBuwuoecJDbUJDUntmlkZ9xutnwR+rtXwGiR+HJDhXGTBzF5b/imcb+EjRaXT/Y7yke4pSnALgHYvR+mxKLn9c+u+35y1uYv6LHFCmQIkLA0c0sf5FcZKtRnxXc3zPBJ1EiMNMj6lIFbQLK78qkXqng7IwlIpoRVZnnTJZImFu0qy+snz6FiOdN0mLDy/Vx8RxAijwj/g1W32UoTxcHW2MbgOjiqj23ixxnxFKDvnhil5PhDBePgjhitEv23GhOMfKBJdZXKhZ6pYt8Qy3Q3DHjeHvFUInhRDelMc5Io3kY9mYB++f/KcrPzy2Ml1lEWVZsK7xyoYip7r57VvXMMKUf2PjhZl3u3ZVrK6cQs0iL+KxjTm3ZjtE2V59VLDKVkwc+yfs5gHmxW10wuLiK9MtlLCH6TrcWosPOv6jjv4YGLOtpAPf7awzUcI3sShp6ySDQp9/GYNSzS726AvG9K+TZBJB81oCUxxi5zL8MKrhLiDolUc4/55wxYP/+OyBVSb3iTp7RGtpjoQCDcF1nGi6ue+voxHK2bfEYwwQsZWXZ91TCcFPGMgUY5+I1PBfHWXWr+VXKXnNyib4NiMnMXUKu0Zq90fnrUR+ylkjg3qNpx9/lCrR18M3MfvjJs3dM2LEkuQt+thpUcBbOvWPiT6wIc2Cne207gDG4HjKbeUVYlTuq7Yq+VviOYUPVi1HuQ9rcvEJjW6Hq0mUM5RSZ6mpm6XmXEIAaT6bhYJoXb5Se8Hott1mPTmZGLB6y/mNL2njZ7SvEFClo+NUzhr4nO03hjlowCRikt4J/1RBub42v5TYEbxkjKui8DL1x1ACkiibJbuWHPMEzbD9w5SKQlNWZU4zzGZsDtd8WRBhNhLsdT8flBeQHBI8N9282OHO66gzC8LPaZN0rxV8RqId0ELuvcGaMeiFfNGvBt4BFjHFae4J" + }, + { + "Version": 0, + "To": "f02438", + "From": "f3uuvgrmepryqhcpmxtcucbjsbasvcl4k226lkiyl4v7ko75zqirrbsys7jt3cqxb5jgviubit5jcfkzqbsa6a", + "Nonce": 1231063, + "Value": "122768540505553218", + "GasLimit": 63466013, + "GasFeeCap": "5000000000", + "GasPremium": "100019", + "Method": 7, + "Params": "ghoAEFawWQeAj+AsMNXBprIGVjFy+60ihXPxwd4PF5huyzQYvSHc7mHu1VXvjNomdIrOtqL8BnA4sI3/xcDfmXvpnyL3/9lpM25fm8nhw6rnXBdu1I7NsrzDHiEIhCtI0DCDMNog6H+VBa87+offfQ8+JvFRBmyQZrmZLmk49KcqNSROVbj2P+CqG0OHDWbz6QgmTv7u+rp5je5uR+tUqCW5xGrKsIZYALrQsIxErbT488htCUNepWQvFUL0Isz1OjpYYOpSYIelsxSSbVD/ncPHCXv565llgVgOf2LdKsD4FXB+Q29PGz9Fbwxh+RLz7UvhzMDdiYWas6ERYZ404Rt01npoXfuDmKhAKVg5uUD5xbeSoFP00yRWjqgBE2wDbOdRwTS63OEQD2Ykz4VSMGjlLTBeaC0LuW3g8mpW63iQymN8+BQsAm09DTdyNi/P1cWalfwXuL8/oUzEWXZbMwDae84mqbCT2dTNpOxXfH7Q/4+onIu8I7BiyYflbVQ+ypE0jga094DbqJAgJJKpIfk151dpAW8ACKmHkrDfaMf6kQJ7+IsX3gL5iTl4sGp1SWsDPjtavaddoK/eOKF+D2U0lp2HFj9zjtFyOGtBCMJ+xN//7gHqJLSLqgIV+IHo8uhd75QzcICmEzNEMmUtqqBkW8vGBbNrpxcrYZ9LmKNCPligbXUWrLGwI2MPdBZRO78XajBdH/W6scQ0mJQYTibEhu6qloM4G/eeHm8pzgPqXuvZ3Bse8qjZ1Tf9BzFHaqq8wox9UKsooBftu29qjGymUxV65eJUlWeEJorLtbwlQ63nDhX0Dd89IvT4v7dKAEvKgGInqgnriXAtKjpdnLSgg2KQ5uoibfJlXdWQGv/rab68scGmfrRbqxqc/ZLMftCqYethc/i1CiB/FKzFzpefjQpHc0/lhOJgkMN0vyPVKL5E0VIpJWW0FdO42SVszq6QLIgYbRbSg1KyXRSef9scIQ1wo5r3gWQmqRQw62rXdzFcFbIJ/YchCOuYMlZnKEVEh6O0Oma1jS4sVTwuNRktk/tJHbSDD6mrRMHm4yqEs9CK++TbXHb9lVX0pE782jo8NIXUWLKrg4L1QfOYu18G/YpScdZiXJLOtmkHR23v72cqlLcNnYGiXoF9rqy3AQ+QhfgDr3ssFkWxivHgre00UTUzWDa7OHIaer7QOD7h0ahiPtGeJZCnX52Veh/zZj8PNwFIHC9qof6iQTKP0mgbw79PwmXOtt2ja+on3n2v+syeRh3JhYML+4rOuTqnKFQY0r3Nl4T4qeOu5RJBYSaq81RE4jsvDIia3rFNU82w4YnJfZ04v7ZO+/aABHY8fV6k+AyDQSJ7l819tQuTLQRlkK5UJXZI8bUMlnjLnpVFRJOfFhZzxAFKvihjJ6dUflxeFgceSE3TF3eqR/b4++HI1Bd7rHSRQkKtRzmSQ6kvl0zKkDWpLSIcU8L1+BdXMTlGlHXh3JvRpzcmKBe/gGdFUJQRBHkQUiTDtLPUynK1jkOg+Uk4E/xCV3xup1gRAK7pMrDLUIM9llRR6gwbjf7Nsnx7y/iUbOWKEunoXAE17GZQ2tFYIUIcF/7lEE4BEcJmt9O1VIT/hr+0UzScgpt9/gjP87vXOz0Kn1ZjG0/l7jG1AH0KNPcRWXL7fl/S+DwqJsvYFXfdBYKqDDGvkNheBbL5hOJYlHhzGzRq9UH66ZTKeiI8kl/+aoGtm/zk7BVbdbtqVrMytCow4NaXOwGgQhqMm0jSCF79FvtUPs2JTOn7gEUpsudH28ztgVMfsbWR/QHgH1GTpfXr+Dcr5YwBIfsfuXuapfxpT5y84cUFSA/KYPA1FtB4A1h1GKdjWu+QyJNjrx7UjYU4B0uN0bF/QPsleJUVOgpRlkhEUDQDsQTO0iZGUQx2HeIpAF1q5ti27mBugzOSAOi8gYrj9yxib8xxJDVrdt4oUPNCHKFbCQhooSvrG3fP7u+i+TlliyYVzhLPk/TniS0SuqJ9nKsDEOgYT+rsHc6mTfyMT0ZEfeytj3LQ/womquy2ZgUIpPRb7OP9c5EPrIrKf1mbpJIlhmfwIXDkNmQVCB7Q2s3ZFXxQ/DGyG48utb/rg34pnrShJ59jZUVdmWhJ4fAg8PnOFioMkaHu1gC1j1KaL+EjYl0MvPJnXAPKi7FhTyvJhncU5RFqG3nJBBMWG7C1JmBVtP92aqNYcn3o1MeIR+GwbkwBNLqcN/09hM6i4dVZmqOotBOf8fWDjqhR9Y0E73Cv7qogM8kPM6fpLUVTjp5SUsSudcX5Bwi0E/ThCX0k5AGM/PpuzTePpCfiW7M54Vsd8dkhPKRkwc82Bqy84QgFpManWySvr9vk5QZqeA1M8PWkW49tem29taNq5xf2vASUQ73gIiX3KadPO0VV4TLj8A6SWEfz1p+JcXu+1265NvHPT1voBKUOAeT1OUeIvb3E7uylOfJArBJ606OM4maB5zqPn5MJjdAPWlpfVjp+klJZB3nTRA7Rov8YP0wci4jLayIohUZUPaH7Qg7tIJ8cU55PxOfU29zfxlJCigKMwULJ4WCDumuY" + }, + { + "Version": 0, + "To": "f02438", + "From": "f3uuvgrmepryqhcpmxtcucbjsbasvcl4k226lkiyl4v7ko75zqirrbsys7jt3cqxb5jgviubit5jcfkzqbsa6a", + "Nonce": 1231064, + "Value": "122768497028977053", + "GasLimit": 66081013, + "GasFeeCap": "5000000000", + "GasPremium": "100452", + "Method": 7, + "Params": "ghoAEQ0SWQeAgwESuQ5cxDelU+vathd4B9CdhXp9AdyJHhXfeXqeWx8kq/CkQeKRu1uUkxCC1D6dlm+WhjX3te8f940HAADfwu7l4uOx386fBQjP+e3c/+ZpcPwjT9tjpVisLn3eoIroE9vElDhn8onIQH7dGVkwQ4JXA/i8EhAohQMOv5a/rSzFNFbti33AUM8LHYwMlcuWt7Eh9PMbsSNoBl4VSaz6VBrpYBc2AaPsTxL9nSnpEQLhKCX+pCIscCb7Ea1GWvU8hyGsjiWfQLCRMeWVVJSZ3HE8WawOzOZKnBFpVmE7iBX+aSSsMQsSGyCZsEuSQjoooo2+0bnMs+NJZjr57iALXBMumCASnPTIpdGe2pj9d9YPoLm4VVjkIlp5vMeqXzoyFjWNEsRSJ0yezaIAY6rRhFaemObox3Pk0iEQOJC+jaFIkmQ8xL2CNBPJ70BkXZcWpwaPIgA5R5dJfyiPmgL2LDLSxWKAX95fM2jiVZsgwP5ltV/EVIuk45iDPSbtYarNjvmjTH8fo/82Ae7FOtFPrBmYcv3i8eeG0UteuGLRLe6wJIhcNNcrJu3Iopwlob30mF/fv1Hag6+WYjWDmDJZg75HgTI4dXFC/M4CzrwPJg4CvENXhu9ekFSKmspVH9bCBTM0jtiOxwOgPZkt5Ba2NzF7o/9mq7Iu042oWsFfJLWQ1N1hHTx9RPqzwhkIwtvCql+SD4KOtrsj5M8xP40KxkfuWxr2w2Y0w99EJBPj3OoBYfxKnt+1LXuJYk2Znbx3i23wOWNSveakee99XUU48kQWRaem4sEnKEwlAeqBSHYPuMhcwV63pHMILXjKlVwmo+YtvmpmLMaUcT/ZKFgsVtC8SXtfrV2E49wwbcpDnmM7xcuzVsbP8YIn8FhBx9mxBDV4Vu6phkV3Tjc7/gZZLP3awJSBd0W2gXoVv4ipbPOfAPYSERmqxzkv4LKuwTxqqS8CG2JmWi+E4ZhNsIkF0IuO0wbE16ptzm/vjzqVdQXczY5dzWPFwY7+H8vJ7OvlhBjP/ZemDzAwI9Y8GJ/bENwtk9eHhD8yZDeGOn7L45YDBrs6XUcSECIDtnqjZqovmWZmaHjFPAF1jIhgVH1F//PajjpBLCR62sStk3lhfPfgtZXZdwGSK2hWkXD6GtAWCzcUdqvcY219e5mXtH78doQRN/gwSt8oUMvPEqD77tD7gmpuNycAcoSt/WDKnKOAoXFnFzDU5jXE6s6DJoElnvJx3m4ZYMss3SQ1ItBjzScI3FZhk69GVeiS+FRRb9YJkBQMfsKrTmizGCvuLQZnSG113n91aJDVigAx6OvxTNjoKNQFbwv2W03RVThXqv5KsjYxeypS8WmVMHyunPwZXIdVd9ThcgoGtJpcn3c2tGLAPy94KC0sP3bV+rV/iUoQAwx8FLntBvmoP8miOAgVbnt3PhTsYNNB0I5HrVsOtPzkLMNejLh3eqlu+xV9WscJggCQacngmBhHF1V5UG6AUMn3IShPQOAwr9eCCbDZzanvV2QB2fI8FQP+TeXXOx5tp7a97/PRfaaeyvfuw7lYHrLv9ydg5xPLqkLweanTJQNylt9AqTTioFMccV994y1Ip7IWrTweL2LypULzMN+jISOjcPKDo/PilbcTXhjMcNmW1dPfjNcJVPcLZ3k3l6rDCRfET2b5MWxSeLMSKvJ4Gpo9rombWG1ZCk+cGw3dHueZWSAXeWYAIqKoVctSBU/kjbHgH07e8n/0UYhVN9ca0p6YaqwbLqPyq5LH6QpwdPXCu+EI966CbOUiiTbHksY+tE7gqrUVrad83ELgdpsm5E8WHK2WkKDBTOjmk/7G7tqzVMB0l5QtUXzr66E11EMGlIWWFPXmK79wJet5DdV2tglr/lWjmeERYgQ8TnUXaOXMntBIjTIvQWrTyzeA6s/ACTCOgM6YFYOUTef1ztfQKaXldKyZ/qJCBcVGAbqwUAWZzPSYNGZ1dMLJCKvYrGnWoPSNM47V0B8MdKBYp7V04zjmRgqz3QqP8hEmYdhhMLoupJfsaj5wU6XcoUa3FOITqawtHw7Ov6Y9oIdbyFeXcVgBabHxXtGTXukgSZI1uviXfTpoFzWiO1oLfuIIumFylUJtYgsYrCSe58yIVwgv8YTMYbtV692q5FcFc730BuWOTHuAp/E4rKkPrrIwfwduCyvT+xTRthn+oD5aKcBv2+WDzKXX8uHbSckP1+d+o8+c51sa9ZuxD2Y/fL4ng2vcsMWegfFcVrhImbQZoH+P4pWoHUPlL2UA+N+pI70ZaqhG8D7MALe49ztSKCqWMunkrHCdxSKxNrxyzbEvmIoKPvUAQ/3KDgsqBLSnPMrgEgVNQ/g54YrQuYPZelm0x8fegOk1ESxqfMpC3DHxpxqZ13iq2OqGLL0rGefXWrrPfXb6g8n/UZDdQaP3k6hx8Zj3GEpOyBfxYFfTl2jV4v+Xou4JEdzo56WXorb2W+0v+lWEE5a0EmhWOF19WY2zPfrkuO6XUpYdd3iryCEnw+OkyKQpmaMCCdjbtK1nCXV/dmNJQ8a7NF8+1ERQkeSlAtK0" + }, + { + "Version": 0, + "To": "f02438", + "From": "f3uuvgrmepryqhcpmxtcucbjsbasvcl4k226lkiyl4v7ko75zqirrbsys7jt3cqxb5jgviubit5jcfkzqbsa6a", + "Nonce": 1231065, + "Value": "122769148210786525", + "GasLimit": 68696013, + "GasFeeCap": "5000000000", + "GasPremium": "100604", + "Method": 7, + "Params": "ghoAIE9PWQeAgqo8LRCO8zVetsjC1e+F0KNEd0zjKVOEIb73wF4IkvUvt1RT+wKOd6UpqldloEDKjcsx23ixtDjv57ZIou1E8CxFAlPOJMH+775vtdO7HAfjestsMGHzMLsYcdV6syw2GZgCFh14vcQZ71aV42OJs14o8HmmpTYZh0iBfXDQdva3e4NXs74PGILfKLpeIQjriph6VErEEp2ZdszfjegEfJeBtNyGa/vo2EpV/3ymQhJwws7e/BFsTp8OErJWNG/8qtl0mVvvBR3KYJiH8bj3q11+rUZcaqzcW7ZDC4ap3XT6iYLT96u6TJqxJrrbwzXehQRv619OtHFsF5GiEh617xnckt++Lrv96hLjNzTiv5iv/ysQZC6dqCAU4/CrBL+rEemYyZCmvW+L/xjw6U4a+iwxaK4acwvt1uo8agUcdre4NeGqIxNpwBQTf4Z1qVAjpn+vIkmvMfACkG6EUEs9wQr1Hvx+Te2Q14hMEHy7a5FCDzWd+nsNEUE25v/EFBZ8skb1KnUnoFLKmVlgyolzf6Um5xwxmm58S1ODIoR9htNZkTOUTZkotW8n9DceoQRnhOIi2C5ogHEqGgoyMoWV8cmZcntX1KR9syARqwhSCrOCwqFx2ieTeiPLcFcHGo36C4P0uziyIxvx7ol1gTVCJ+mNmExuNiJq8FTZtQAkXiHqGOFmaaUNTaBsvK/WPceRqqqXr7BKip6ruMKUBGkOoOzuDFZH3/M9yFvNdN4K6V74Se1WMXqGGlQwp6HN+UcYtxXBnsKS5F5ilP8oJREG6HaK25LzdokU5oFjAOE3OrWBc7wXqQ0fi//K2tiW0T3KmHe+Ctu/ci1nnMdUjFRZ0It/iFfE9HyTT711vvKNq7U9QJ8OuqzfCZ6yAAnZ6tdIEWATIp3Ie7PN//00p5EMq/dtdIO/0367ik9xY3eebLkaf+i+/BUzba6ktf0VxJRGqZijAWDdZxPQUm0ug1OAP7LyJTQ17HAqBRUaAEBqeU0Cu2w10ubDO5bgG1+oUA/eoRKT75ud6GMfVsV2J4zF+CBuw6GxKXFwF7CY32xuA6l389Z1apc9fsKwfkg5T/9hrIClMz8bZ/iB7gse2r3lYTwyfkx5fIBzeIU1GdLJ9y9WnUwOTLf6XwtWxtZJdKm1DARI/c8v1KY3Iy9RFBQeYE2gHMHt9cFE19oT8JM1pySSDRJntt9wKZZatT5pbRtEr7la0C4CVLnyePchzFPUIVY9CiMG/b3jUSdfY+69fy4z/lux/V8kRVsK+5W+Z4UtlkBaKEjpaKPWZU7twQ/jt7B20Df5Z+TCuXsZYjbv3/M+M2Chz6Ca+ni5FOTdbQ+yoUzNn+46OqnigeVK5t4DR3l/9iyKN5BuoZbOv/UWeYAHijuAS0FZV/oD1i7EWQjrA0prtbcb5QtKHaJOFT8iScpJgrk0rVa4DI3cVJxF0nwhD29h2QgeoSUGJO5M+jEksHh8RsmDf4VB2LsR3fqPezS7Fu4DDvgywQsrzes0GnNBnrJWPhYczSNP8CPZ8V5rqrAXrUUE0N/qqpDYNe2vT9UBkWj8NK8ddPN/7C8DbivSvoET+9I4zEWG2PAPpHcDk9Bk8nhJXv6lEsnqNY6mOHzT5Qbqf/+STn8IVD8TNRAYASFl1bMYKOZ7zYaQ+xYDElSHtEWI60D77FeBwqHt4E6v6O7WYMDigc2dGVUcDmAB4tXB9Rmmpvo21dFVxiULsMUSEKqyhUvDGKkb8Zz5sOsIKPQ6wTpCCJ2JdMY2jUItJoA16qS0gVs8mSYDKx4kiXgvejLIJTBUumeN0gG7OJgCf4EY7j8lNoO7gQwWAh47DfL+/SKWpvPb4i9kjuvZtk+qmVP50l9WcPeb+ohLkwcyjFNN/AcGII5BXNe52/YFalfs8+jfY7rQpEbfXV/CDnEu6ViDB8UpLuSMpvqtmmsk2mf/IQqkRO9iFdw6f59qyn2se1LMnoJCPs9TxNasjF1O57P/nBLvECbNQI1Bcm7cnpfMqMDLkU38wWRBGAbd5sbr3XZL7wiTmhZxadJgspcbPKZpDqCf/qPs6mNi7QJSubabJFWu0EhmhD5hZyQNdjg5Avj3DoGCovDKT+IljNrNUMIhzLOh3RT12N9ZmxxoOUKy7To8RmSVXo8uJBii0IMA8B0dFLh3PxrhRFP8ERvTSELAsjoK1un8LFFITlGCEdKOusUpDtfPL5vNjRO0ql2l9JOjYTAd5kN+RWIwr3Y1GfYtpMgkR1rLH6JMhyERM6O7yCkBO18DiX0znQZJTMyE5U2cAy93mhtlsYNeh0b6osZhFjiBjgE27/bcSl4Df44zcHIe7PE+gBbuodwH1oxIrSmDbs3FKGLHWuEio191r8n/wp3LAEby4G3qIx01N45LZJfXNSHv+CqSVEym7NuQYvzEOGnef716sTgQFIo4FHvuvrfmzrAgBklTSNNJ6PalkHoMYJZth6ujKPKoEBMn77VVZWOQoXs7DT1BrdXlFxr9Y2jBsWsJXzti6lW7/jZXDOxCAec7wHmOC1VKfwy24ZDGZAf6On8nv1iL" + }, + { + "Version": 0, + "To": "f056226", + "From": "f3rwocizqhzxr6epnkcndektzfcrhpbzj7z5xaqpihkgrfxwqmwfic42ttar6t7nekinfwqha3soogqa6vagcq", + "Nonce": 26575, + "Value": "121193537706136508", + "GasLimit": 20924983, + "GasFeeCap": "1194744100", + "GasPremium": "100383", + "Method": 6, + "Params": "igMZVPXYKlgpAAGC4gOB6AIgDkOq/Okrg0+xEg0slwNV7awDYivpdOuiQaX/bAAwaz8aAAOxIYAaABthLvQAAAA=" + }, + { + "Version": 0, + "To": "f02626", + "From": "f3sqwodtyqnzhf5hohcwlhir6pkheacdqd53bgqyud76fsbwdcplrlmn52wpucllg6x3ajnptap4mafsecq2ra", + "Nonce": 269625, + "Value": "122767706604381323", + "GasLimit": 50955106, + "GasFeeCap": "981255931", + "GasPremium": "100592", + "Method": 7, + "Params": "ghoABo0eWQeAqR0knojBmq5zQSkJ6Vy8x3J5zvRxkrHyo6NJlz+GDaKtS79Bok5m/jKFZ8J3o5Ktr/D1Qd7bJxsgNXp3HzNh4fEyhS5tvA+/otWOE/e5gPDAsBW8ZjWB0LwuBevlFl9yEAbRBoq36Y9Z2kjfuCZU4ySHXpkODrK2QjglzfFWCaFp7U96FaedU2bD2Q+DD0uKgSkRH0knxhD1XUyDeAG5EQA5Xom/mYbTxXO6MKNUfAmcolQVKM4B9XR6DFX3nyk8lBephX+Mkb0f4EXZA7M7xGolRevpoCeRXM2laFbJj5gcTKas9mrEh023yA6StpCMgpts2nTRxqndav7FiMwy2WQpxP2FEz570NtzajO35gVrFfEJ92cfBI+D4S8zN29qDPHcMwI0qSDj/HyVG87MgU7rpvSPWo1zPB7eAsd57CJkxTRTiPh0MQNQBc+qiJ/qlu6DsU6V2iYPo18gH/n+sWZdcD5he+UO2rHWlYvhNwa3NuveQmX/yCjrF/lrxFZLlGcpcain+yZ0h0pBNT4fGPickvw9udi1m7P3gzBNtZhZrcqMkQRKUXKWwh16lMuYrgxFtWg04vWLj4VTbym30KW3oFIWfvBjI0EXpFxoKAALyef83M4WRTZp0lHQDHBeD71VJ2ru08KIkXJ1RUEKujbnAc/KrBLME+MYVwrFXTEMyHvH5UaY+EpnnLb1z7DsqmiYrDKtaodquqmjhH3t+5MLtn4VKSrCfOqlMCR0gbIPszyOjg/hyjMssMjWOPu0sUYEmkslKI4xvKVSK9HbtqRaQIOqxDHGA9wfJ7dNC/EtrNah/d4wWVg5R5krnVngpdXl6w4qoQ/pLyZSUDRnZyU8rYt4xuFrHnrIK2AI4h1vVY+oLB2VBlwWdPVN3ud/EG596MKbPO3QmrC2Fs/iV18N/BiMFIPv1LwAIFdY9gg5IcKxCfQpKE4e+LAUU8ler+x5/C/zi5DabLh6Mhp7MyXMrZj6gegaSNG0tnOExH65lQHhcB1dAtV2KU8pUkIagz9PCCze0dw7aI9o+Da/C2PxTmFLOXJrDtMGtUiZ1dY2TixDtw5qvHs5oMQB5KjAgFhQrOq8kz0UI8lm1Cd0lk5oNGUYvmpWKA7sV+mkrdytFslYMM7uQYGwZhvhNxWIBh+Oc3sgIOdC0WzNe1OaJU/HuoQZFGHsBlhxrkrGe8cL/wXXy2t4D5JmBuuqs0DVkWsMIcaWnQ+bv1xk/FDhoE1HSNIc8FT941ctWP8FH8Qv4YHiEnS44MSSQT23EZqymLzqmX8ERx4gAwkfqH1VYaudXld1Mlb/azEBELbujeBXpkuair4wWR/gHwI0SMM9iYrggrPBUpAXYU2NkCokXcbdxHhYFWpPnuCtj4qWnhSBVMKZY9LxTlC28qntlKb1CUWmfGD5J3WSpvrR8NHi8rX0jrMrCuIbFQI37Ssx9AGs33D5ECChV146TkRj3JhgkVAnI0cIl+U23/t5LpJQF+WSobNjLhjWG5m0ru1P3Qbfa2CWdsIcqqMOYfA72O7jliSCtOAfBhTlk32IYo4CxZnYtuXm9JlSumq5ENg7S9fkOF7swxOIvxEzzKTNpc9sjZ5Sl0eDX93/78tHTwujsGBXjo+lFoheieX1T2U5l+NTn3631CYfYK+JByU2uEZVCwbiTQBGahmk3Re/x8bOiz7GpoVXEUtwCtIgOlAoJZYOj6+6RCttAqYUJzpFddwQh8d7oS3q/ab5QkdOwd99wogCxve8RlESH/FhFkvAc/mpIkJ2UaSsTZ436SCMAJP4uBZh0afRGRgBH9XXcRP5UR8y2mXUcicWeitjj6chQ388/vI3rIwZeCdvodte9eZLqDpkGelhi1Qvs/9cRrInG5VQSp668rkHfC1lpzKRifaR63zI6j+l944Dc5qXf5BlFRKyzbxyIKdDuOJGyTKCACLZrsxGFNKZIDD3ZZZE+giVcKpWouXLFxuPEofiByxIoDkw69iBoJYJ1sk0tquEmdZvHUhnCH4kYQgfKQ1GbfdcfJMKBM3b+L7YRRmbNil9tb9pO3aW7ldEu2inJtUZ27X/hBG/c+Ai+/r9tb/427fx8eaAPIKBveP80cxsH2wVmKxAPwqk+WJC8TuTjzCGwgqDxIhmMwvWDPEhW1Gh+pUvlvWw5TyD797nYxte9l/RDXUjB/Qgg28b4eghdZvCMqGQjUK8luV0vXtjt4O+dqTDX0aT7QS0YEJDDURfikYlpE0+rP/oPzTfbPIMspf3ZfJ2biBCkDW8EWILqae7eTpCs7FUXT86/IQB44F1VB9/qz/KIM7A7z4T+Nx08eZZIWUB8YPURRnO/NcF7oXcIP6WAGq8HT9YXMgtuf91bh3rj0F81J/IhPfToEbHs2TS6/mHN1kQLafpad2+bsnpuUXYeOc9gcam98V9JFqFZpPeCQ1XWOc8hyTQdPihNP1OGEKzlqrdKxrgCskkA6vbJSe/WF4aoJIM8+OdwjOF88nwgltOMfo0e/S5LSCGmQoCYYq9NzaRGfxdYvSaOZ8JQwUzQ1Gb0L9brE14lISo6nsG" + }, + { + "Version": 0, + "To": "f02626", + "From": "f3sqwodtyqnzhf5hohcwlhir6pkheacdqd53bgqyud76fsbwdcplrlmn52wpucllg6x3ajnptap4mafsecq2ra", + "Nonce": 269626, + "Value": "121193649549989127", + "GasLimit": 18028566, + "GasFeeCap": "1386688214", + "GasPremium": "100175", + "Method": 6, + "Params": "igMaAAaO6tgqWCkAAYLiA4HoAiC35nt7igG/5I3v69x4JyR512ADIv2IyctlZN6SAQNKbhoAA7JDgBoAG2hi9AAAAA==" + }, + { + "Version": 0, + "To": "f023825", + "From": "f3woozrthpt5dqlb5kqmg4ytq4vt3fypdjauuyvr6olwszwffc6sl64olnz7smfsrkqfymxg7d2l4hl5egpz4q", + "Nonce": 167009, + "Value": "122768003437599101", + "GasLimit": 50955106, + "GasFeeCap": "981255931", + "GasPremium": "100096", + "Method": 7, + "Params": "ghoAAWasWQeAuYLmv3u7+Omx8U37XC+1d9ZflxSG66nzeb83KF+VEAkVFmqKw8BhnDlcHVF1x5LVjgiIwanTWU01ER8+KKmlqjW7MwIM+TyDOQCcnoE2/P/lk/P+emQ3hgS794LRzdMDCdbYQWfobbS5vMGG4/YbTAQCoEp2qH0ljHZchrpJf+l/L6mRSsz84L69qN4qp57DlISt+YP91sWKUhkiDeNXQC/aIB7Zs47HTYuAX1zMdFNMy3x5z9ZjunJKI6XPcRMOr7wu8n6OYnqgOYXhJgk2IUM+I5Z9F30EIoRKSZFvxxBd1rE+4vAd6AAGbJClyofasW3IFTwrCvKXx8GWvY8ABe57y6pd0NvwGn3tNj750Dt975QJW7ivx6nv7ZLV/r0fFu6l5HWkX6lF8Sgoklxm7o9ZfIfd4e5r2Y03sEfRGzA8gdBtTSxfHOxomF7xSyyogW7lrGRt4rNOiRb7fDXwSQ0F69/wZYuyEDD15Wz2jccjmureU98LbU3zJ2tkr3SJuJ9WFyiKckH9AoE3z5LpJZhjItqFiAVKsyLfr6qGNT9keAfcNueKTAQRvhJbr4k1sqZVgTXMVuoHkJcvQ2Ljc3yay2dZepbUvPhpIdzL6KbqZOo5w7grFD+d1NwfjHecAq41Z6iib4etsi5CfLt1oNLzUlMnl8wueJEzB4tjJAIq680m+U26XFZ7sRvSrFAopbRRT3/jFlAuucvqZkWRCJWTFKvJ42pEimc+Q37+8zqLtHy2sRJupYlpMS5Mj4mvuSeGEqUbZtkckXMsb3in6+U7dy7TMkyYwa8Lrw6ASFqxyPVnMeHTRVfIfF7kzAyzqlGUIojhuYfi3Gb4KsRKoY3s2q2tJRITa7FRwYkqeZLG3MAP0kJvDwnGYz66qdUjGCshYyAQRsak7qxPl7XZitRuZGlEZZr33v6K0LhipdkoHQfizzjEvMBylNXaEsKdoiFCdf9hET6o5b/YMFj3Uw0c8Ow7ouL9d7riPcI1qOVhoc/BdGX02rd/ltgnFvA0gOSeuF+Ci66zy23Q9kgY9kwNumT5M6ttGG5MREzuSM8QkdFErexnWuEIMVfFSgb9jrfbq9P0YRkYVqke+RpbGUX6vZqpV/9paM/tKVf9Aj8UzqPPWiPuLh+x+bdpPdNrAvAD2N08hMM5ck+3bl0ezczX3AV6H5RFXcxNMNlznN3vPXDXej3Y+81a+Wtq5+eIs1kr/lNfX8yZc+3Gkyn83lkRVAZvX5Tng94Qxzo1LsZWlLYJSOpKkThfsUIzddRipPK+EXuXw1IKoRrQC4kgjiPy3uMqbajQX32cCuCoAWOrqIs4e6ZOYX3YoewHMsZHkCc5i8yHzAOz0JLJQNGd1JpNJoxMSxkw9iBtlAcY8M5mELf0T6hLvP6pPM/Z8Cx4Fsn2xEXgf0x01JYyyqPO3OLJPjtMZ3zZm58iPJunyk+cWJrb9ySx5Jdm0U+Bzbqrr7jAE98WCtO0ibaXpo1qS+aZyuTTX+1XSZNBA5EN95KUdWUQAHLSPPy9L246h30vlyc70twcHfHfdJzCayQN9yU0YxJhh8jBwxxkw6izgabOZisr0kKNI/hP5kQlSRp/oFNgCwi5RSrB1gMnejo8pdb1m72Z2jUsFkrIwGfHfXcXLQR/hJC2U8KRd77tpo/6A0gFYYcf6/jpGfK4i5HGObb1sJx+mo9VtSDh5X2bCMhv7EQi0XTgxWtvqx5LE2qsjan+MMx1P9vJkDxRm8ZOsUfc+XLuIzWzAmTRdBRBvmnY0ZtHpIvuKw47HT9hjBbettVlxSOkv/SrXjuWr2XGFjC1bFHQLyhz3T0+6h2Ch62z+djigLsDeL+bBeqQ1Kfuq1hCJ7f3xSaF5oBwIx6Je4JBDqNLK0v4pciDsJnQoINWsN0ZOhEdVjqnzjBqRJ6QAWSACaJDO4BPFWcjUmobDVTNORcV8cWe6rzzrYtwOk4dm/KwKjyY9YoUP1BEJ4EvhQQuDQnDraoU47GcNitRw0x9VCrUvOM+Zr7WrDyuGCQDPdwYscQJpmHpzOiaLkKklbbMBcthg0qegPEfOdYp3jNXasHiXqdO+NE3dDrtqP09feZfmo1W2I3M2I9Uoob9tGfuEjpu5LsQOD+qw/4Fi/7ehraoYtF6+Q4ZhkcIpDM1AZyFwUd0DJW3vjq1AMyrCIEoDNzQd0jRjDoVnrUeiTXcyJhsRNUo1ZXDE5P5yclubO6Xr1ukaONUyTomRxXgqAYcHKn3EnbF/20ty4omiViHFqd1i2R2louioy086TeBH644eULiLnDvDMK6i4EKqsiO9Ei6fdKorq900GD274HLNfg/ndvlUJ7KcSzk2hcyvGSiVeJ6YQVz/UUw0lj9rcviKPfjrsG9oYaSUgkpioE3aySRm8IGfp/0+flQzQtS/IL7YAJ1jnLd5CeLwHgsAkh3MXLfn6sAE4UGm0oasoQY3RWZXyIg+Q2dDQITcOX8dzAMoUePHVuGReg9FWJKuMJKQ+u6lCJF9aJ45ZSj8HPHM5ojCgUH3cYLK8r9H7cDserqJzxK8kzLNsxh9uD9" + }, + { + "Version": 0, + "To": "f066259", + "From": "f3vccjwrbqfu64arsar2frk6beqk6hp76jn7zoc4eahayh7r4dt6hrdpybanwgmzqzjmrprceow5tzcmygyglq", + "Nonce": 30329, + "Value": "122708859176893247", + "GasLimit": 51611101, + "GasFeeCap": "968783828", + "GasPremium": "100254", + "Method": 7, + "Params": "ghk671kHgIxgkPY8czLG6gL41afi2rwVZbr0gQbfTgbNcrrvqrQKUHUk2HUvAe/AGWq3YRbNp61TLdqdwXQvrvlMMlGUfW+ih+gcNlwy6qSArc13KVlNKTdTM9Dwoz4xqTHpg74uew2g+IhEX42olusVoFt1JXcB8hU8dF+BxECVKA4276z+6mD9H4F4CwRsDb/MkKjMZo7px4cDgvDglBhqqbjtD1BWZexIXt9FYcE5xl8ni1HQ+MK1/97vF+dcRn4Da/VVs4xy79yLzrc3nNnY0HH0QPixMap+LXiZLDuZiOxDcbqA/9FjIGGkVHflIXY7qPCj5KJu4EXoo4usKtazaEm8c7Gr/t8TCN9beUyMjmd8FwjgdUaBZ+jpUQWY/BkD8EE7zgmlS8ggrUAb1jcAptn/rsMrqW4rzU+ZpmnDbZBrts9vYlFcpdFskw7jTxOD+JHig4wJbAdlOlJn9Rz4grcOKgbD5R5dIp+EIBgCBwCDDE8uPwowdv27T9AxgQQZmMUdqIv7weRBi/R1ZMNSzYpQXDPHDDDg4nbzQdq/8OaJ+ip9pEoPeu2gFZpZ9k1YIi9g0YBlf3tPdNgYN2mxRULtp50uPH1NtDaqLcdy7rcjsmkU4G278jRRc0mp0cNVDr71AQF2i6wqOAVcFK7z7vD/War7mTfoV4xoiGumGwc/mxtWY/n53XsSNQ5bcgwln8yvJIlNkWF4eHYZidonmg6K2jGm8Ya4B1TahkwMQTV0r7a71AJuCtfZE9fxhjCVYLpJ1oNKRCUPrca/Pl0edOFBkg7zNfnPIB60mMp9LgSCSDOEKi3q2+CvA96vOiOIiZmVCYj+Jhk1iXoNQ2bZNOQujloXEy8zLoI55oE4A7BoMvLmQ+/VqO6lH2ZY0jkOH2kxhQlaqY55kXB9qxsoDZZrIkHWGRdvkkrGP7uhEyL5gn4htENBoPWtuMNjDWEVIJK1xrdX+W8BvHuswBZ6YbGq758QQwqOv6/gPzWO2RTe98vPsQjZg4gXLq/7shiGi1ZqJ4sYa2ctez61EWRcCgmqWRPrRPuJKHbY6c+vbfBbucAlGJR/q8iLl4zwa+a74vC4fYPn8wNRxtf984MmMlNHtpsU3fDiaHA+4CsT+N2UV8Y/lubRw1cIb1dYOFHXu+wQiwdgy3YD5vWMXVSHWDWW1cnRa/oxRnaYbD/UbhU/cYgf6xgkCSgFxzDTBt/9hqgYDbIid6qErCOmCV0onWSKvrinVHOyfcKamEPoB4pnXB18RdQlezW+YozGzVYnSA0tZ5ZR026WbqxQ2sa2gokBWJSVb6vOPEYSNunZQQwHxPJM+J7UkkTGb9TsQv+LRh7fB4L5FCAFL2WLGQmLW9mU0wxOmyKMFJk4f8yFwfhP3tCzVu1Ws8p10YVPkyUK5vpUUQqPVTm/j7hYs6/xxhC1PcQ3H/WbpIG/MsOfvOYjubNj76fRnx2HWO1v8TkUGImb14Ub/CC9rTuq6ww6x1psHU+3SHvx3ITf+uLIB+hAw6+gVK1HpwPj54txI9lUIBRGfqxLkmncnoDsH82YxTf7r0YxwNCmX2S0cKz5JRIZefnCQkjB6NR686g/i1PTKaNd4qt7181O1psUkuZnY7VRL2pAdIZrKYoy/Rm/FOVKrfIW8aaGBojPfUDyoncCbTuPFxevNrGL49OmdxBMWytekiyJl1FZIqY85X55QJTTZJRRbgGiFld/iMTxxTXuRVySgo1IEbPmerdnMv/bS/mPbcKtsLrDuMKeBfg/z1OtS1g0FHxoio/ILwkWbfOEd1F0jKggMyaPq/NuK5gkCrxbwAHgkGeIR1g0Cfh9c9m1hrb2tB6pMFQdSyvLhnvNf2phlpeTClyB9y31NcvNnklj9Nn8tRS/VKkfTlemb02v0eYnetOiPQbZqgRMj6WXtL6M1gv1w6b+AQrWfmPzGyaEmGxyvh8+cO+jnTBqHJarsjdc9H0V4T4Jls2Q7gvUQKgnP6z4iOYGgR6QW/qDBElry2ANltIGez5BZyG105TPOjumIC3zpVKSSVS+1TOPRhIF+JMndWETwxjap7zPY70nctzPZRgQZZ3W1hQuHDbOUdR+9KSyJblpsaUZuYJ2qDNogJZPXKtBYxiFXmppjOmIkQYdGLKpBPfCEeVO7rWy6EhdCC3WwbfT4O32E+SdsMzVuw1XcRp1DR+4w3n4JpNDTyIuNKlYct/L3GWUs/317/cn7ZJPxr08wVhqUozvv0sHRaZbcX3v+RDn7WwsLsA1noR8wK9ZSTG6IVdfTqQOeJ3ZByRVZbS8n2aHHqh34HeKd7WFcX1RWSgoGMIDh6NGRrD4s5OiPMs5E5ZTVwta9SV/vX9m0znupZLlhcPHEZbmWLP6iFho2JNDmxoVJa5qOYPCg/Oo3FFWrNaB2DN5rf2KsFWEb3Jr7x+9AD/84f21OAPXvhjcRdlAgLnatoYEpZJyffQh+4VbRuQa+cNFK3qgab6ToaTmWece+JjumZkxv4ssscxEKk9ElV+tHcVpB9SMMnCzOl8y4ncdZLyOx3Q2iqYFI0Th5qqYN3ZU/lDLcg==" + }, + { + "Version": 0, + "To": "f024483", + "From": "f3sxw2cm574k2byhi5d4ax4h556ywvi36gbbf4uvgmybtejpmp7bd5p7pvz6t2cdwifsgcreeilf7ecfeaot4a", + "Nonce": 124911, + "Value": "122756413322397522", + "GasLimit": 57957606, + "GasFeeCap": "5000000000", + "GasPremium": "100344", + "Method": 7, + "Params": "ghoAWgpjWQeAhSffUa3PruuzycWWcXMTzeSsRKGTizRIWpOvsvsUYh3DGWBEjsyS6phO2r01D0xOuAb43uUSySYKPmJaediMxbVKz13LkFCTQYdndHm0/5Bo53twKVGOrr4oyUjx8K8yFDHhHKD/cvSUhVI56Ub99v5w/tv7Lo8xFC/IXc6zyFhKyQeNq/4vymhROCBnGtI9maudEZ0XSXwIUnOaVPrJdpoBq6J73jq1cn0YhLnkJ4hU5ahEmv1qbh0M0xIUAWjstQMNVzkGhgytoSOlJ2QTjBz8QyVjBZhUOTAkqsHw3s2Jl52ZXWKA2U5eglAVSD+HkDW0Sb4AmD4VmV8NGYK4k2cUg4r8bBfPHPINGTdKIRCbTo5FT6ZfSCpyMoDKZkQeBgvut6iyGaU/lkRbWMEO3tUHbV0IozgVCjHos3lWpYsmm/5TT0Sx11iqpgiXtv4rk0R1S+1LHdTmu1wX6Bq/o0lGWa/GcD3gQVQ90vCsGOxuoI5AzTx955HH7AUjP4KvoEB57f5tyEd/GDvuWc3hReTFSwNGDgp23gd3IDrGYyJB3CLRP2OIZGZylWSRLNDogFhNd5LBfJEaP4L2BrtkuxMjrau5/l7JUYp4dLUXiHV0u0iyRoTDXap0RnhmX98oEQrYkHYg1tm/Tr71X96Q+8nuJxwRbrQxY+2cDLcg3ZoApVqvx6mnsr39duJFGddSjDjEQtOB9TiNMFYdCqtRJaE/xnfbcVeGy5innb7++cd3Y/OXc0Oyz3NEU8zuhVrkkD3pnnRPuJ2Sf8dcudtOyL/6yewhHy+9uLWx0q8Ue8EOlt33BNkNmQ094iNhTBvVpOjfNwlN2ymSohtFfkKaUhWBTSofCLZ2FQhcJ728NAr3urue4Ebi0vWLvv7gGsdbCuVi5wlM2Ju1I8yWNn4zFZ6NpP0iu7KnDKbpxI1TR/au5zkT+nEETn1v+VAl7bHytJfz/z8w4oGVG9kpYqNk4m/MGCCeUwxuIrN6P9yikflnhEMHomCXVJTK3v6yqeC5uW0DOnFVT/br6yPftgSvK4vc/OHQWKVE6WE/USUXoalDkikRPYCw9DO3jVtPzsp8kaBmLTAsmYYOffgxERGKgIASl8G1cAnKWNyqoVA0xzVtgvWxLa05+dDkwxUIzuQeFmQSxpAazgllBsFmeWg8DfJzK9rq3T2nfK5Vcg7ZJP5gBirixq5AHIsiNhy8e3lKhoZno3vTfHfUUJlmP3KPMkXrykXXXvUab0ZUPdokzn6qFLfaHIYANXta/JBzkFI9k69G4EC1/J23NrMR1zLaQC8BCQPGKWtUs2gkOh5nLEktKGXk9HBvvC8hZUH8KSp1rxLufiVCzfUvBvjRU9Zz4OZTBeqEAgh4BLnjlHuo8vtfCEM5nsUrjHQJccuU1+3yC45EFtKODOW3K+Dknqlqgjvx5Nyq2/VbEcUVeLOxXIVKCSQP74h03R5hOQouT5OArjIQTwZs11SmmmRmlkUl6N5uOfxyQfRpRaHeT3OPZFlnq8icknGMw1J62gHdkwsWpk8H+KWQM3/RqOS9GWSlc5YW3U7ZoQnG03NVZ/PjwcbPPgSJREwEqQvAR/10bc6QlbHnKsvHIOAA3pJMw2WAQ/DddRRx6I3X2sWqf+L5VxNGG54gU0ZQvfqQHB3g3DNtDD5E3DC5V3nam8lMni+ISbFFl+sHzIIKCtLWcWSc2EKibSsKnR4ipYe+cnj4PYnzk4SjsPaunjRvw/+2bOWpXG5f5yhV3NjkVF0kv9fYBmJ1rIzDGfiWuOvVAsLnnAGzt6uScw3i/c8DY1mQI45HZQLy2+7JyV7pJ7NgQ27jODi8M5/hh71kbDD1Ebd4L9BWmJWQb8tzy8XiEQMAX79kR0IOg6NkGXFbP3o+SLNLzmlVxFhqa2gynrtBWh21j+d7E+XS346YGMnp5BC3Cs3cl2HS2dDFUk93JobIkO1rDbzCiqFOrxr/S7rD3EBMV9uOgKk368SY8dy7Jz1MeiJcwgCw4Dd/9i4BVwzjmLUrgAq0cionM4PcY1QeFTmLQQL8hrIz07KoykaZka6d2tn/VklbdkeT9KIuAzLKWubwGB2FWENdWZA+EHglfj7cLT4Il0ACutvG3v7Jp/ErBcvwSUAsdQTwESvRen3/9zdUJitFTbN+XdLYLWAtTjVcRbYwAxj1krPUdQ24bNxMCr5jDF/Z5SudR8cq+C6mji+Ztj5ThKUGtrZS4YL4ayKwqHaUld2SSf1SV1pSSJHD1B4YwkIuWolhViQY83nb7lEn6c9CgOOD6sgnr47YM5iqTGfdoXEOee8lU2afMbh+VvsAZYHKwU47258u3hKzIel03M/GK4W1/BOEd8168885HoyArEJN6KwlgJ4STDYarYOsYLgqKl8Bx/8MjvGqcYK8edpjGt8kG1wzFRAzFzgD19VNEf1YvYguhcYg9dbfyzV1YNoHifWNFHHBxDMhhpk5KmBnpdcC2PxfZoX+13ykmu9Zqx4iTmaLQ8itWs6zsycBCkr7HpPpr6EgJrQaSuJ9f8M4nueWW0qrPCYKdJdc3Tge" + }, + { + "Version": 0, + "To": "f063869", + "From": "f3tfkiryke7x57vfpmzkplefvq3l45zbbdi2s7hoteu4j7dkxmf746ac3ynwegocpfwsqvgspcz5gh2hsrgraq", + "Nonce": 85717, + "Value": "122769020608844046", + "GasLimit": 57952606, + "GasFeeCap": "5000000000", + "GasPremium": "100148", + "Method": 7, + "Params": "ghoAAZGVWQeAgxxKHPAhR9juWjqAD2jyZv8F9n4au1yhsMTr2IVwsr2IElJpOvhPXxgYHPq0IeFfjDvF257J7fjHcsAxREjxT7Kmy6H5sRNithyyCOIdR6fdEcYUuzQzxRezLTkdV9m5BsvO9SGtb5k5fuhU7CdoXOQ6MrlI00fPTgBnLzIfgU3wyjPomfHNcosRK7umjO9LgjctwVUj1YmEKM+M9AE4UsgT7Pp7z9jsAeKdSelSiHaMmG1LlIoPdhh6bdEf4vmNo1K9oMedLg0dDCFR+iI8iaOkrEhzX0nvX4drLR/NVuWHuIfIcsVZMqar/KJYZbHvomTSb4F8Qf4rQ4T8a4BHu0e6E9U0saTW/GAEz/am4N3ZvZD5r6WC9T/oKT6j/PnfAX10WscPHAMEA2FZArzpWBI1GSa0E30VUb/DetkbD1hzjwx4SwsxkrhEjo61U/8Uggun0Cds9Wnl4wppEFtcfI+2itHDIYfppR/AR7fuC6k2saJXiCkoxKkB0ETp5fnopX/prN9XjR8moEWwYrVpdnl76HIqlLQe/ej5no4QQRcI3YmNjT4SNnzbSf8ODQJbjObhQU11KROcuLLaub/h6wSakXTCntVHDGs7liZPbfZoCrdJAUDUNX+vFAXf0dKLAQ9HIdfVtvjGIOeishkaRS4rIlyEXpiG1q8lfE2/Ddnn+2L84O6jaRmvxHhJvoeopcA8v9Ggt/MkGLMJIVmD+AC8wNu84jG3WPXJuzCu8/y+3Ve2AfDVSbBfRlKPa0ADrgUlGrMQbn9rLxir/PowLIOo4qNlxBv4Wwv8uDf2V+sTpf7jz0aY5ruqnxETWIPwhGF7oQV/hWGYiMjnddjEg+Ikz7P4Kp2u9Vj0CHAnRDfY+teldHfbThmzrbpA7whFDWL7kg+cMHljsXrFT+b0WymQu4s8f1rTCk/+195dyPxYRXJnSvWJHTQ8BH3o29tSsrk9q1owVckPctTpJzvQslZ8lPq08ObESI0kks6Og3bulHeftMfST37qQUtf0GB+pcaqxX5/FP3FCnXOKCLxL3pLg2/O4gAgyJU+cp+BnnYmccfRJw7QR4H5q/j757WDjFzRAr/M0R/539hIoHCsDCiDjyIo+eQtJaclB3YAsbcIPtxsLW++TOvjUPyqX295GNoskhBSZOmLOKV0aCIt4+V2sLK6aANSs4ZwAjH6yOuDmNnKlySLROCX6tcZn7MQlzPH41swmPujWPq5YSLeMPUBxSEzdbyJXXwPn80H02UydA8tz2epkboEsC3mf+uIrnmqV5ncChR+2kUEnaeJMRFGgz+QSNfbhnehVyOBcQztXquhy/Txo0daNCphQEqotJQB8xbcNksDy1wFh/8H4BfjaolRKpa0HUEU8cQa39hyxsAisvURBcFuK748EpkrB9wmJFZnF1SzDZ6WM1mIIp8G7vOuyqXTv/A2ZUy7Qm5GKUNb6qfzbrgGpY51Fr4PpztmtOcTppYAYwENQkgwgHxmEHzHpQrZDrLu/xhHMdQeYhMmwTdUJaPTGwH8GmVSg95Qub5UqCC6woYcfupUnZEwz5GwUvc5TVBtkZ6vHOgPCIQd/PzRNsg0QINPdeEtmZvcti47EwtkdJLAN74uvNcLdmcYXjWRJzktJz7HvuXuuOZxk5GD2jzyN6lnCp20GMcNxqz/r88egPfQESE9loiI30p7sJoia/2Y+iexDrUBq80LDjWditoD4ixKHQLjpktxtymmKJtrqq66E83objXvn6qPin9Dl+qc3PInPsNEmWMcOYpbfd+F4OVPa+XNq8667tKZOvAkw26+z88UTdbcW/ziRPap3GprOBSUyCUtlHduCKuDYtAFJxHIGxXIhCel8cYIytaKAwIF6IuQmcWevA+z5lU+c6M+0ilHzlbyH5C9WpZNBm1ASNxS1CiZACi+pzbb28zPDUp5AUOTK8/zsmJo5zeDz41tPLMU/7d68Q8tFHf0jyNu6NNZmplJhF8I2SifsKSBo3kndSkoJPzjCsUwmmfKBiXzWsAHlcYUehScBdny2qGssLWDsrt/gI3919N+MdnfCzQbHWNbBI030sn3GtE0xHxQWq4JA59vpbKWCt4lBF07kGIt70CkiKlqjqey+DukHAwY+HN2Oj6t42wsy0GvosUn84MxkUvjzzGqVspuYbdAokepTiJhFua5v5VIsLYYL5ACNNqXsDM2oqc/x0N1vGdNpjtmYldZFbL1nC10hA/CDlZTo00MgskR+OAmlu+uBOO/pZHB/7AT1MYR7ahtWs9ar61N5zFIBSLlMuEctoVip02SiJ4cggzkbbI/nYGrScdfyrI/B8E9Y+PgXlp6txj6mV/Ggvh/yjxwCc351odUltT9bm01opvU1TphTPZlVNioOPpPOTe6sAbzccwprkJx3wB4wFySuYlBJWfsiCqMzasavoxaGBddBn5jK5eI+NQvZMP/NKRSmlYBL6yrbYHwu0ClwnhuXLyRXHKCiDxTHoz7nWebjT/iMU1UXPOrB6wl/SyG1a6LMl+xA4Cy1PHVOcDe8mNLmZJl/0i+gIdqEuO0gBjm" + }, + { + "Version": 0, + "To": "f09696", + "From": "f3rajqmgo6oemabzarpiv4klfr3nkimzxx5sjnqfvefrazaxsoqhkwv3ucsb3dc4jmny3tts5owtlmf7vcbuka", + "Nonce": 1376, + "Value": "0", + "GasLimit": 744145733, + "GasFeeCap": "10280066222", + "GasPremium": "100220", + "Method": 5, + "Params": "hQ+BggBAgYIIWMCxTgAVAT6BxFcprATrUctaaxsGA89GhA1iJd1FmuUJ2Uo9wEqpZaVocWbYyfscMnSNGoLsIMx8hB8NMBcMH6vLzQVHEeASXs2F8Qz/9FCMN8DtXP5wd6V+z4tF6l3BoG8NrWERZKOWSFRlF13+zZVtd5MgDzu+N+6+iW3rBDyhMSU1QkShqRG16OG0p0n2ibWoDug9IWy4TbrRJdtKlW3vAaE2xjpKZUJrUwmXYnCJIxOFnLpV1QKCCC/7i5BCmMEaAAO3bVggJJ9sfEgOhJmN/XDKgAs2wpLvGXW4ArqhxFodbtB4l2Q=" + }, + { + "Version": 0, + "To": "f069919", + "From": "f3vlny6twbkprq2jden4z7xrb624bxz3v25ncoqkqdus2mwly4k3pxw7pp4jim4jsxqhhgxgehqbkqsigff5nq", + "Nonce": 9593, + "Value": "122768003437599101", + "GasLimit": 50852303, + "GasFeeCap": "983239638", + "GasPremium": "100544", + "Method": 7, + "Params": "ghkUu1kHgKMACCA0Vy3vLtA4i2THH4fy8ed4vTCZUSPMbk+5Jhg+qGny7wVjUs6eHpzK/p/6WYFgsZBKIXGoNohUvdJf0aC9iuupMo0UqlAoYdtztfxDmr2T/DWhNUhqUMEmZMwoAgnkd2yGsh5Hro4D4hIed4BT53SlAAz80thpOCFGf0ACIizHTAvR7rWs84QUsPFDV6kjsgpokNJWvxrBoY+KvPgEIIw5m5sl7YbY2Pra3903ojdwDeV5mp0SPF6oFnjs66xCME6YtrWV3fBfNU6ukh0F5HIly1ZS9IIqAJAw/od/1zZ3wgATqk0idR7TwKsaR62U3zKhTkYX1vRVBMXvrmCwTkpSRO6ihWAaKN9V4ynM9ZZDFiUj2N2mnKVWArsyYRAHzrxPiUl+X1B5kn34UW1LXPhijQpp6mvrMay/QQ1+immsWSm1UIpOSGYGsNBPMZNCFh8GwhREamyR/Yf0jThlgtojwTkkFNICoA89KkR2twF37gY37ekbFsI0v+IgbpT22CibAj20+sHCaOgSt6NUKzRzZi7/YFh3UO+2yHBE0SmfapoBIrjdrNDutxpzF6ZOZXovA/U/OLOF+f6SJnnTtLkxk6Gm6ve2DBIuL+fwqf/CSHDsRrGFosJFvOToZwza2CZl5TSBf4XdBH2pgj7xMKd+fHoiFYg/I/LLMxURijXxhCqj7VbDPuW+m+vO+bCDdP2Fell8KZ8IijP6UEWezVYoQ2I7TzABAvZ2FyUm49lJjIFaI7Yu9JhUVQa/E7K747PVVWt4PHXpqmsHyuLNCYi9ON3zYIKEo8ge46G/HKqa2N7ealo3WCvPqha+orLH47eDQ/3zgg0c61pbyocTfmeNd9eO8sI7LExAbGs1l7vPf0n29tM7Ni+nZEhDdAlmXEm+AbeQ8YVL6+o6ATZTTp1KhsTsASdZz2+kMykcjy7DRiNO/ZiXSK53kIswSIyUUm0shTjQTBiF2WFgG9IE03Tt8Afr2f/fpaIox7tZxPnUo2z/22YmQiYLATMYp7Ul1Cmp18Tr9j/r4ePCr61+01xryflFui5lkYCIWcRdaV6zG7nWOw2uDB7YYQmPNIsPx7muAFpdq4uRIoL+WHroS71t/zyzWrr+jVxzFpyicvjJFK+QiEbFDTTH0jpiyhkxQMJjSxuXCZ6CObPgCDgqEDObEhMjRwHKclC0b6Ur6LNgBBdAjlIjetBT9H5SgofLA/XaatHhSZrlMCWaCcNWmEhSYGM5VbavHUNipfbVCHNUyqs48SEjpv0eSwjmo5knE2PsasmHwNIPt5LOL+W2KLm5XQAqdI90WfoyVQ/vfEfUxdPxciSSMxpSoCR21pM+Gu9zhyxS6fNmHRnGojM7WeJDi1TEHGJVFVtcvYRDJs14eABTgSkY+kzQlYLAOAgM8cmk9IeIm0qfKvurU5TL1UoyvScyENy0RZLW4+MSVc/NHsD3cg4aka0lFUecBqqYluAWX7GtPAaTuoE28iJtmDYXUbcjYZRqgm4FZFclsE9/ukE2/wP5QcH/O36/AoUv0JU+uEt4LDseLuF1fWlGNs3rNm84B1tNu6xxEoy2Xo8xm+1IqR40npoov0EIPrhOISLDSrlHrrD9I1HGBOKf7xGgOxugfB3qNTyBswzy9cb6cIKdCSbcLW6DqlR46gN52t2hABzw+Nj0bW8QcHS5TGzywa3F+zoJc/G3Y6GrCsibnZ+rAaD/7vxWtFbRVZgeXGd6M4FFB+qUqs54hn8rthkmyE23wzs2lFHFPjEe0Ud3kpCq+YgbWpH2o7nHIbDcLrDyrOwtEPsgK92bJIx8AQJ/y6k7LC8QFXFX60uAqska77ZOYpUmZ5aCACNcfoHHyh1TDsrQQkMSlovrgwXcotrE56kg32QAMt4JrMRbQ5nDIP8B1QlJzfX/tF6dSga3+ztzpM3677OU+uJ/2LWPhfJf71ELYflzlG3/00Wrlda2/cqqSgmt031ERo/hKJjr0b12OmTjozY/Bwl7hxQFJr6u7/AG9QHH04yevqr/iPq6DsduxoXokfkwrlqr3653fIGpr0X5dPavnf9JIhnNr1kteHf/nYfQKDoSOKmRwcGCF+pnmtECyjlnPiFAva0iBUQkP4y0mp8wWQ8k3DbgvLnwFZDQpNA24lZrL5/l0o7WN34UfuqeWRFeX5QuSBIoRvTCyXhDNMXv7+qT/z1OrS+14bMpSWQXg/5dZ15TcZeCtBi57EEjWaFzMQNRp5P0ejhC7ioYFAu2Xx8GojMQyDc3qLw0gOM8X5KeEfJkoWGmoIaKqjZZFibyUk+AW5MA1PG/yqKmOtrbybNO0GJt/arYVA6CunitLejR7a3vsEi3CgQiCWmh0suetmJv1qX9bAFIGadp5Qo7Rwy7KSTFiGECCMiBYgAEs+bk6N+n2wICDh25RqvKbMpDZPf1pgBIOEqdTAC0OPO80AnHeaZn6GulVuLSEkd7xW6QhXVtpshKFNtpr2VKpG5Nfs9cX6MlqG10G2srYKqmDT8X7bMPYgh8iWMnp8i7C8wJH4mZEP3YXGGnVfchioVzqOs20g==" + }, + { + "Version": 0, + "To": "f023200", + "From": "f3uqsdyf6744kzvde6uyyq6j7sfip4o3jqdt6blrdpytvrv5itqcb3zy3s3cpdayjvm3zafeqzp6gw3synha2a", + "Nonce": 729, + "Value": "0", + "GasLimit": 658939956, + "GasFeeCap": "4552766868", + "GasPremium": "100272", + "Method": 5, + "Params": "hQyBggBAgYIIWMCRl49uQUC9mZnSBiZuZ2vJxUpbeGgs28na3CJUxJy0Ya3/K9D5pIHBx7W6p+EHjritdWznB0fqjGUgI6nwg/eqLA/uwo7B/trjOYlf9QPWFwX3YZguya+8+fJfRxKamfcThV3KGMPbMPAm/1ChZgigp5WsFz8DqJkp9cN9TqxRFAJ4rnRrpn9OtUlPkMDH3h2MOWUBTw8nO3Pykb8hGllb0UB7h/qwBBRlqxHjBeiF+gRvz4pYeithVG3VxDPdwBAaAAO3aVggU6EMoocHbe4ygRdHMtiTFu9sXVs0Mb8Ygm1kq/qLzVo=" + }, + { + "Version": 0, + "To": "f02770", + "From": "f3wcfa5vw7t54rilkeee63x4w6fhytjznk4ywaxjrbr5g5cxogvvrgllwcjtgd4hd5uask7ulzpq4qhk45pu7q", + "Nonce": 4052271, + "Value": "0", + "GasLimit": 32884453, + "GasFeeCap": "957899466", + "GasPremium": "100892", + "Method": 6, + "Params": "igMaADsiUdgqWCkAAYLiA4HoAiDyoIUiSwa4kP51dNhLOWJZeYC023Lu4HL5FeunSj1aHRoAA7GNgBoAG2Oj9AAAAA==" + }, + { + "Version": 0, + "To": "f02770", + "From": "f3wcfa5vw7t54rilkeee63x4w6fhytjznk4ywaxjrbr5g5cxogvvrgllwcjtgd4hd5uask7ulzpq4qhk45pu7q", + "Nonce": 4052272, + "Value": "0", + "GasLimit": 61709138, + "GasFeeCap": "972303324", + "GasPremium": "99914", + "Method": 7, + "Params": "ghoAOwAXWQeAkSyVOUXYl4icY69D3sajnllHdeSvDvfIR6r9/qJqvlwU9usvtthuvGstGWobAtRcshqeUlbI33WOO4G0o3k0kwrRE/j3l23pGf33TtuYCnM8+t9Ub85hC4OqdNYeisqsAwkfSrAGOjwlt/BIjViNbR4aJSBFFxz3Bw3g4xW9eqksrDvRRzKk9tDiVFnQjsVik4xq677moF0fPLdPvBA9rrteqnAJoQsnzhLld6kGF0Wk4hnAP4OFmtSaezgJ9DtplT/wFVn0GjOK07Om53+ZDXca/r1wqBqvb5NJrOgsH1O41+TxhB59nRYOIjuWflnTpuLsaSo8DSEQEmVEstz4FSE/35wmfc6KxsEfjF1agVXeog4owroBKjnCQrC+Mz5fAxq9AExyfSRjnKlsCTbHIXdZuGcmbMq6hnptudE9J/cUKa9hH51e63mhLQUQkZUVrAE4juLu/v3g5nBP7an9ECy7SUNDXbYomgxcMFHOEeXiheM5xlIfeTMFOz2MxJIQibnhGi4Y0+Sul44sVqyH+2d0MbvMBiejioaw0bvyBDt7e8LHD9fOsKGHBa27gMnYsaSi+bpjVyk6uF/cVpxzk5/rb/y8wR/z9tx8v+4npHknQ+TuGKKUh8/7/HS7+Fy9EGce0ix4VX6wSUYcqtv+Bm8X/HiJMZ95swrTTOc6qeT8V+ZdFVFKZFqkt1EiNFR7sJTXt4VwFTk0w9u4fAID6WnVWq392xG2BADGlUQjA9Uf/NFDVafhsIXfvpEqkly9rTvc1IGzjRJhBdKsrJSyTXcZfvIPK7kEcSdJ66euTSiDiXho+22zp9UuJeMPXQN1tkwAfJXclfhhDjESzxXKhGya/mWwzJegUsTzGRZ7YjqmU0k+F4S6DcuBOR5PyAc9ENvaraGOO4OmIKVG5nkXWjBNqm/8A79W5hw+wna9xs2KTQhSW1mgoTcXjEiN4vwqk0uOEnE3EbZaND13Kl0EFUnLkwH5TuhituTH0B9YxkPBZVENceQ3dh5E8lk4uO/4sETdhKfUWFM8zwazEWmnYNE3dqwsl+ackabJ6porI04s8cAPA4abz/Uc1qVxCJe1t8EsQJ4SfTJ/GU27nf2XRjrZ7WrzbqHKFYYAoWYNVYQsSkr9d9UtUctr+fVmWGtOA6L/YJ5lsFIQIwZ1sSSi3JVsRY4kaSDyaUYPnoaTZbwgFkRfJU68Y3eK5J/y4xMJmJ6fXgGrEydwgCMmnBELOiZDes+c9uZryuNNTAQHTVxODYlKWFoKAARyd776AizJmCBw4jRoVqVEB4S0Ve1zcBw3DH991nsl8F8EjIJvQ0kzUcdgQto6ifLuxnVz01xUisgd+TDs80EhXcQnI4DwIskG5DNlnipEK6f5jakHQ89fYHRFJU3/4SbJzk/GROqFC5iXDQtQgalDHbpIv4x7628KHTiyQiomQCVVrEwVMF7el/8rUVDD6oJwYM+NRRYuqrb7WJU58J7Y2szBX2/rhbpp5YK8EemvR5Kf93E77QRTevPBkOOLJsHO1HCSrJZdgjEFX5IBSJz14RT5I2L8qTiuIHZr795sl+GkupvBrRex3OrWhIwqH5X70GnPgYUvgzMLS5vLOA2YIW172nFjNkF2/OAXC1MtSEgH+z53cRE0rxl7uYVXdCHjNsL++u+cASOdIj3ZZFq4P6mJsF1r5TTt1xAe4dJJ7BmxclPz7BxMFvTX4j/SNB0V1TZzjolOj+WjnkIDhpiB1+wSeCGrUYyD6eQInpyrUuOK8hbLFd7z0JKXNAHy4uOkcqzxhriWqTqAlTqNbPkv+5oDYxCYoQgFAuzN4mJnbTSGEv0IeZ/CydV9aH9umG/qNmZKERvKiNLdT05p2HyGcDz06GswH2uKKxmihaL50TWLMzbAUEh5bs8TQvf19nUFZTRo6kZnAFYwr334jwkVGQIvnj7rvcqtNaYX1Atg8HVJoW8I8NMXCZnDxMunwr8Fh8OahTqzoNtBMNzytJIRaiVYTrACLz1LXxXIG5P5KglPH03DKZvLtSvBsJWiXq5Y4ZYs4SPkp20JqFFQWVkwOqyu9KND898yCsbUFnkZrvx3LJhgmHQBt4pJ14XlGdQI5lLRzoN5h3gV+gkHDn+PD1DBwqzUbYzajwmHjPyd8QaxAISawvPZiKyUnMkmOEswKYFSfEBIB6wxZBz4O5cq6irVVFG+0g/6aJCX06LkN+HRA5eha/w2tjYrJwS/p3ZrWEnvnYlBiJpud8AXBK1ixx8ei69eXwBTOk8WmOV09dX4DXEXHPpp01mfv4TyBWiYTpI74iqyjBCTABfSxkPclwzJyn+ZyusTjaWxqN5dsQ4gCjB9NaJ9RddwIJgKOLJw/DTzP7l4kVPl4QhmIcMegmWXGCx/0FPU3h9epm4veYiHLLl8Ni9gABlU/JDgHqiFfyRswMA3BPLJBW0SJPFRDgJTHBLGx3n70E1NSXWBFRGEZRKS3ngyAo436MaSjwgcIIOej6sri7u1lW9trWc+lWWrHLGMsLTFtfYA2Wi69Dm0miaS5eRu8E8y3pCHeXifQ2zZ0dfu" + }, + { + "Version": 0, + "To": "f034701", + "From": "f3v4tkxokoxt3cgo4eec4obq67q2wwlca4ofcaowndlqvdmkurm6lrtm3fusetp3lw63pcuoya4vw7mdoscamq", + "Nonce": 8202, + "Value": "122718951853673043", + "GasLimit": 51523171, + "GasFeeCap": "970437165", + "GasPremium": "99990", + "Method": 7, + "Params": "ghkQjFkHgI1PYHQO13mQVMTyWdTNe9qmBL1R8VUNf2iHOmXQQs53Ycr3m8+AYFwGXvOkgxjZm6gaLWF8q3viS6D9QDAgpd6x9OQ1/2bDkzixn3wmGlVysK+d8b0ucC0wigM1ksRf2QXUoGUPmjJgSnlsByaFf++DYw2tfwlvDIfii/739dWFjQj4yc2AwY1bZZoYvijtpIrOQcmNa+9vQGH8ii0qCVeu0po6VDJOWel8HJtdB3/FVmS8f60eBbaWQERYAoAGzZEVN5uoc7Uc0WMWaOYinkZqsPNRbU5yTzprtCf+DCubCFbw5RmbfDwmcd6F2xJyQqQjHSk3g9UBaP/yeV3kvw+5iLA1WPURlcz1s5ZNvXKMQ6NOco+0RChVu/sNPqDJJRgxHYuQszfTlxSmsh1riabflP0hTAE9X5cDJso4mwjpKOzOgc7FzIOWzNpI5yZf2LJyQhso27gpelA4RC1R9B96uIHPoz+zqTIs12HqhIdap4Jg86zTcczmGWaex2QEb5WNSI59PdeI0owJ3n9dFjEdaBg8o5e1YbiPeb0eWeoiozyc+2cGwAQYJJ8Wijb+bpDMn38KFqcoKY2QoksG0D7m53FrdwhqUdHNrEmp7BQd+5T9kgYyJrX2636hE/WT/AQ5Dm1WDDXHQoTIN50C56/ykULpEA7xYhUt+7Le589DCj/qzJzD95UWZ1yM/xTEpJbScGTI5regVn16TG2rvExb8jekxPSsrdiK3nAxtQBpHcMjNMeOlXl5C5AO1dewwLSJhUBDIokrWy36bk3KsB7YlMHDPTpyAsuNOwEWtZanmyzktxzJFPWRLH0thf6+GLIFP51HwgiheWDsdMu6uET+rQUzDFS7WYfomjA4Y2mpNj39K70KDM9axiACqZgXdwEFk53FYSz0AqnEx/rubXdB5w5X+tl8wZ8b9Xm2wclR8FLcpbCxDkD1iwl3R1i6O7KjqMX+W6RKE4Yweq5YvpRQZyd9GilYYP1tm+hLVKqunB9ArhEqTUHPsP1dRbDKuLGsC/jC3UYKLPSBhAXBTlelBQuAHdQcHR/7CYX4ZnjhmyFCW3JF7pqVDIfm7e+Q/K+lotX72fyqud1nKzsFaC5awaoBXYqmneZntpOtONeRwfNPZmCcuLBz2xcdYTxm3gHOx97sYs4Zd+qk2k4Y+LnIFbUyH8bjbsG+rsw+w8X9LNZehmOLW0KGnfWYh/++5aTIUWC6/k32YAHXPn7Z1t+DRtpo4DVjNwC2DEtnf6/nnL3IDvf7QemRZqI9DDYK/LU9I2Y3p7CL0cUOKEY7NBV29TztBJgetiMg/galTq9Cg11jVaEYR9wNudZzvzsIhpRPRxh+TMIAkvmzacUJ0Wh3vHmAJNiT5opZkL+cMZBHhKNJXjFG2T6GokmU8hbzZBEsanxTp7Ru2yD5PJM720iinkfQkPCQyOKYZtNfLGDyoXOdyDfiBxMJIqHQdAtMr6BTne10QCJxP0kqeg10CvK7RLC0TV8nXr7hNcEF/5ZywmGW93uv/e0VFX7HsdH7pKHVROQg0ELCk4k+Ec8PXx4HarBTIG5er6fM7F29Zft18D1SNdepjtyGt2iiQ51LAY95LYVKHIXXuAtfv6NKj7d145Z4gIIZvMdPGlonspJ3xNOSW8OJbma0cGLMi0J7DBJZFu/p/pUBL284PF81DlmiEZsNdnxwTWXEde8RR0TF2wnz1ZkpVt6WCgSjoFcgCpQn/UKsM6yHwjUuwY6JL82f+FQaGPA2KJAx7IXj5RvKNdLPou1aIahfK9Ozqm3taKW13HV+qaKjPPXtyuq+kvL0oyr8K1xxasPD4KJEXjuWZAwugD3OK7O7TYUP7rojHaB8Pz0rKd0BT+T7uz8fGQa0KZLIef+1gN7poY2jemct9JTbFTGn0ib4g77jvd3VKwibRt6LmOioXmByVaIPvxFY8xP9joS+ptwFh2I+d9mk76/XAmucd+6EAHFHW6OZorROND79r04/Ceq0JSfw0+3R95d2ilDwTntM9R2u/JkI8JhN+VtLuB47XNnJ5swkpaAgwabwsFBmiQJGWjvpRz3LFhzhFH0zIcN/pvlYbyGEcTRhFT7TRL/mSK2u1gxWg5Lr0PUEE1p0zqi3qnGA0jMOPvhLs3XxSXKRfT+lcW9GjxEockJWFJJ/JI9N46s3ARUaS345hD12zbsSCwqvhibe/AzHsBJr9VJM5y+eb5CJA7hRLwk16gZJ+42AM23yJYV1aeB+VTXtF4+q9BfKZ4qIIFAt/7C+DLHNXhPo0x2w1mpMJf+uw0+JvEiWFLYmW6XviVY8RM9Ad23ekl8bM3rqoF1BJxsnQwyz3vW//dFdst1ENQksClTtOJf6kf6tU4VM+fNbRIf5wVkPFhbzImoKVuQgTn8kucoUKbYySEAgCU6eNBFNUQ2vlBhJ4BeC+hRZVG6lpwgT9PQv7Xv/itGHKeEzrwjWPkY5WXvuQxCdqVM5fGzOQtd77ofimnyO8q33fKGxtXa9iLdWNBXE9jjRkbNSZcx/RMbECbywWDQzLHIjJYo68Na9y2UK3/hnyg==" + }, + { + "Version": 0, + "To": "f010528", + "From": "f3vsfvzod3ajckprbkjwoa4aigxggvlxexamssjyl4bleemgdyfzr7tn75b4zvzjbqh4mci2zbv6hxwai24eua", + "Nonce": 11719, + "Value": "0", + "GasLimit": 24589046, + "GasFeeCap": "4066851556", + "GasPremium": "99564", + "Method": 6, + "Params": "igMZFZrYKlgpAAGC4gOB6AIgnS6FcO30rCB/A85R2MvCLX0vv7Oo6jCBd/xpiEeJJxoaAAOxLpg9GgAUG1kaABQcnRoAFBzSGgAUHREaABQd2xoAFB3yGgAUHkEaABQeQBoAFB56GgAUHu8aABQe7hoAFB9WGgAUH8IaABQfpBoAFCB6GgAUIHUaABQgeRoAFCDdGgAUIgYaABQjUxoAFCLzGgAUI1QaABQi8hoAFCQkGgAUJGYaABQkMxoAFCTiGgAUJOEaABQk2xoAFCVSGgAUJRkaABQlGBoAFCW6GgAUJfIaABQmfxoAFCZ+GgAUJqMaABQnERoAFCdFGgAUJ4kaABQnthoAFCe4GgAUJ7kaABQoDxoAFCiBGgAUKKwaABQo6RoAFClQGgAUKdQaABQp0xoAFCpNGgAUKqQaABQq2BoAFCrXGgAUKsgaABQrZhoAFCsxGgAULC0aABQtGxoAFC0cGgAULcQaAAvMxPQAAAA=" + }, + { + "Version": 0, + "To": "f070501", + "From": "f3qc5qsbj4urud7tnd4luszvry2z5w3fwprggynnyxdcyyma3cvw4bv2vk2rduma4kbnkwruotgdisgvgmb23a", + "Nonce": 37019, + "Value": "121193537706136508", + "GasLimit": 16195071, + "GasFeeCap": "1543679555", + "GasPremium": "100162", + "Method": 6, + "Params": "igMZVfPYKlgpAAGC4gOB6AIglqxW8jRr6rgFCZQ0Yr9tQhGHa3JNd9DQpt9H72ptM0EaAAOxeYAaABtmvPQAAAA=" + }, + { + "Version": 0, + "To": "f070501", + "From": "f3qc5qsbj4urud7tnd4luszvry2z5w3fwprggynnyxdcyyma3cvw4bv2vk2rduma4kbnkwruotgdisgvgmb23a", + "Nonce": 37020, + "Value": "121193537706136508", + "GasLimit": 16614426, + "GasFeeCap": "1504716443", + "GasPremium": "99607", + "Method": 6, + "Params": "igMZVbzYKlgpAAGC4gOB6AIgfbrreWXvoNYE3GnpgR//LriQQhJX+0UARLwveLtMJxMaAAOxTYAaABtmvPQAAAA=" + }, + { + "Version": 0, + "To": "f070501", + "From": "f3qc5qsbj4urud7tnd4luszvry2z5w3fwprggynnyxdcyyma3cvw4bv2vk2rduma4kbnkwruotgdisgvgmb23a", + "Nonce": 37021, + "Value": "121193649549989127", + "GasLimit": 16840676, + "GasFeeCap": "1484500978", + "GasPremium": "100920", + "Method": 6, + "Params": "igMZVdTYKlgpAAGC4gOB6AIg/L9Vhg9A1U1uplZnWtEClPTUEx7O4W7PhHe/d8OG7ygaAAOxXIAaABtmvPQAAAA=" + }, + { + "Version": 0, + "To": "f034544", + "From": "f3ud6wdb6rmph2k4iyjelcq5imdah2cwex33cel3mxpcvpxyfqlgtfkxnl5vxia7dkwwhov34socwmc2nhbi3q", + "Nonce": 105197, + "Value": "122709345795189305", + "GasLimit": 57955106, + "GasFeeCap": "5000000000", + "GasPremium": "100070", + "Method": 7, + "Params": "ghoACTYZWQeAgixBOqEY7k3wOxTrTqL3o2LsJ0xS7gF0ZGT4IPhoKmVXJ6C5/vQsBQwX++yDY1faosYmd7MuJrSk9DgvVYhXzsupjJRIvaNaRZQ8nLdXzFyVI0UWFRVjghRpuDs77lpCDSXxehuOpgSOsu8DmV0VQHCeGF647Hv2IhnVjPoj6sM9S27BGjzsQLH4kmDE28gKqhzRvMvKLqLnE0N+13oS5xxy6v/Z4LVr9J6zfjrpgl893GXUIrVyAI6e+PEE6OWAiH/9G8iuE7kf0x/yBgF6RVkcbcf/9AegDKiDE4i1qhPtzv3C50SwgBDJDyyNkOMprYlygxAaOng2J8rGXifZaqsEpWs67kclkSoANvO9Xz5pwqusKLjoWDhh2qSN/SPeCJwSnN1qn5FGAK0LoNBklRJbWvb4f9nle3XaahGv8uZOOWVByPIXV6BiDg68/h8coieOCA/chjwPdb6pqxYVt1/6ZIVZYre/twg4uxRLK02CXaRv/wsnqccLL3Y/Ui15t1wlcrZdr0Q7qZ92Pirsf7h6XsUuvIrKQSd5gNQuMlrzdezQI5s9uGiSNmGnmuhqsllTVErKZ6TYnHgKIEtXf2iyt4DBlagupRYDRQq3Pji0qsxiXwGeJZBhFQKevOu6BL3KJkBaYszQXxfhstszTOtbi08eNBbwGfEogEIjK7JTUFJglrWRSlaZuYlv0jc2gQFi1qXUiPfYRVHGEaOp0Dni9VYPkCji11Xm6HEIn2H3SueaY6X0Iv6RhcWWIqZtqgVqFk4oA9UHHX1U1svjcO5x3ausTTXAYBAS1rrWvx4xyQltUsnSH3aVbI8eFYpjkvmib7giOSv/ThQDo+D4Xf2dF1A3QFGbitPbgepdR1ElnVZTpUs/yTvg3wnWw1d/E7jnw+Mh8RjTCBQF4scqRqv2e2OzPVXvvaJ5/OVrnbaHXUK6yP7zaVexXUYyjgr5jsItxAVI9KsPTtNm+1QO3iCJxt05Z1DWIAChQ1QWpm5KNiN8N2EGrjUvez6tJ89XrrrYR+qq88XC2oadYO1y8GajDVmt9g5T0Z6Qt9+OIAkyUOrUsMQJgFbaV2ZKj1Z5gbQWCXed3tRPiMgbUCvpFX0p2aQdSJLF5XWcfGzHVuTIrxf07eo/lM0Phm45a8ZGAV7WHaULKPsw9AmKcTis9toa370bKY0wGk22uEsHq54nDJSr1A8KT9U4egXYDHOYlBy9D3PKti2KEFV2wuT0+2bzBkVIpnjUR2bZ/x/Y5KR45txh2M6yAFQzmbOXKtWisyUyMojnD31sykoS/0M0JnhRHApQF83s6AMNjnVDhL4ANxTlNfLhqleEvRicR3uygC2fNU8l7S39aMlpaAakR8HzWMLzLn/2iytNS/9AEvt9S4Utfn/uF0gXgHObF8+zBbyq3LlrxkJKaMZ7+CaSnyIXpnC7PhyOugBeUqGp+9m6CzIqWv3gM1+fujjUBn89tYpKzIVyf0cVg4uBCQSh1J8SXh0v18vcV+mASL7Ha2PaWohnxD84UEdTkZen6faUiDYPXeViK3KfUdzmQ1k+dCYukE8EqTsJcdIee+z+jzinKLWX2VF1B7uaZVyxzWE2phoTzlhisjnDH55rjjz6unMyPD4T4IEZ/ER6jpLNCzdiHA8nfEDwF2ujVLGzXQorAtoULqt0Tmvuacv/su5LArYxsv3KvLoh+8QQsXkHPB+kkZi3j3f5z5ert3mnxZYCpSDNRkQfqw+GRGhUNRDIm/Mt7WRMwyQOYY7I59X5JU29u7HAvafuGpAjHUDbLf6GpD1o4z3eh+4t5ygaqzelPkW0FycbeqHHbsOpx/fdsOEgBQgVapOQMaNcURtzFvXVs/qSZO4C6y0050BKdEnuuWbPcIRjeLUsdwi1trWhRvYTcnF53Y/zd3kXouwtpCvQFsuUBbbOBBBF0ae++BhQ0ECoVgnXTWqYHaq4NdK7XThDcMY5faHxQFVHgg+nEtLHjKE5aj3xEhGbOM4xEtlJXKeYzRvbLYx0Vusj1zP5T+nzDuc0j2BC48VKuZ1njERjt6k2vjQmFGUIVF79XV6zKilWG4IJnEQ+AvIKFr6OtJhJgcnVSpBmh+gYTDWCVbdmmJtu54qjEfrfS22F0rMa5MhndQzmYs28WaDAlgBjMh95VwXIu+h4OJVabe1VExP6A3/7wyQby8phjH+yVTVr1RiWmjKLXPFqg4RYIrWa53tFdBQbVSVZBboow/4J8u9ioJUGe9sfxIjrONgTML45XNXzrRXdHIjWrHJBQphbVLar6Fbi+jCOOWp7m32OvqCrlQ8aFs2fN/BW7fkvSbW2PByRBmmOq3UF88a/X9OSccqnDf1me2HHLayyCFZc5rXZqJGOSTpgEv5HMK3m06xLh8gfAPVK28qumgpATqloY1/Csarj7kN8i7ycQTF7HyDrFS2Foxdpzs0faYsttB9tY8kRyHA84Hjf6UiXuwkLhCjOCHiY0EGhthOOUEeBK1cMky6gItLjdhUBNunefz2xWZhL9d0mwMYCRDDphgM6zXoUB+iM2UMOcjjVk1lsK56i" + }, + { + "Version": 0, + "To": "f025002", + "From": "f3v4ww2ac5o6l4djogf23gb4pnosre7m7374qw3rsocts73nfhy5ecvwzmyut3n4jkcoddqhe7sli77tsbi7ma", + "Nonce": 802197, + "Value": "121193148447007677", + "GasLimit": 34484473, + "GasFeeCap": "5000000000", + "GasPremium": "99924", + "Method": 6, + "Params": "igMaAWyzxNgqWCkAAYLiA4HoAiDW54JD7fImBLMWc8bhBBtyarxijp0sZt/G40Ha0gkFCxoAA7K6gBoAC8ea9AAAAA==" + }, + { + "Version": 0, + "To": "f025002", + "From": "f3v4ww2ac5o6l4djogf23gb4pnosre7m7374qw3rsocts73nfhy5ecvwzmyut3n4jkcoddqhe7sli77tsbi7ma", + "Nonce": 802198, + "Value": "121193260185693775", + "GasLimit": 34000078, + "GasFeeCap": "5000000000", + "GasPremium": "99596", + "Method": 6, + "Params": "igMaAV1xgtgqWCkAAYLiA4HoAiBpBXz7+VvTgxTkI9XnqGLLOy9K0HbjXS4/qSlKKG9GURoAA7KqgBoAC8eb9AAAAA==" + }, + { + "Version": 0, + "To": "f025002", + "From": "f3v4ww2ac5o6l4djogf23gb4pnosre7m7374qw3rsocts73nfhy5ecvwzmyut3n4jkcoddqhe7sli77tsbi7ma", + "Nonce": 802199, + "Value": "121193260185693775", + "GasLimit": 33790636, + "GasFeeCap": "5000000000", + "GasPremium": "100313", + "Method": 6, + "Params": "igMaAWaZGtgqWCkAAYLiA4HoAiASB/4SQt52vQPc2Oqc2WLC7ZxhQSzWv9+Yu4kEqE9GBhoAA7JCgBoAC8eb9AAAAA==" + }, + { + "Version": 0, + "To": "f025002", + "From": "f3v4ww2ac5o6l4djogf23gb4pnosre7m7374qw3rsocts73nfhy5ecvwzmyut3n4jkcoddqhe7sli77tsbi7ma", + "Nonce": 802200, + "Value": "121193260185693775", + "GasLimit": 33405723, + "GasFeeCap": "5000000000", + "GasPremium": "100073", + "Method": 6, + "Params": "igMaAMZu0NgqWCkAAYLiA4HoAiAaA+MNi5e4+5gIOFWyqi9CUs0FISlOysWC1ow6lM3RSxoAA7K7gBoAC8eb9AAAAA==" + }, + { + "Version": 0, + "To": "f042635", + "From": "f3rs6t75upu6a7zpnq3hkhxampoqnsz4rpvjjotdixxbrb2nqatllfsdemr3v2un25xx4z7mt2uww64exvjq7a", + "Nonce": 47303, + "Value": "122768734461156087", + "GasLimit": 50946356, + "GasFeeCap": "981424461", + "GasPremium": "99853", + "Method": 7, + "Params": "ghlkYFkHgKSPnDv4gf1D0l/GfJWSmTEw5D+WN/LZLT7/XhJVYfcaqq41P6UZgpGayLW2toodR4HxYLpfDeDvLin2frS/Gc6m7puM8ntBVw9PMEOy/gQ6A5SRzyPPfq0K0cn05sW8CxTKjVNl4ap+CZqjYMU7nWsMWzkz+iHN9S40tweRbK6qzGk+rYfxF6yGczH+qaUD8Kz9/yiOeX7GV8eeo7QeFgnnxP6uiAD7WpPmzDDPlaBVIVTBAFN6eld3ovRcTHzG4qOBzG0u8EYh+APOQJ9PttwlQ2k++bB+hxhl5vmj0swraGHJLsbQ+/Jz/euxYfZOd6uEoKjBsneK3FioeAnFv7g8nwjtFQ8v1c4E8lnhQDddjH2CDcIhfvGj0LySihndIBgg1kAv4fU45GRNiU/9HyRQtwlRB5Qb1upm8rdpQE7hGlki4FpXzbOenqO7bbqWOqPjy2tLHbSzKyFnbJ4oU/PQmDDue2zIYwwQuPcQhXse6u759HAu2RmgwS33EUsMmIQq6CgURFYb5xClN3PbEuuJGRsBXcBHsq8+1075SfeXw4jfIWX27zABa9CFGs/8LoAlM3nb+qbB+sTlXnBY86lEUeLJ79cqSzYJgzxrlxBlFQUnRuTfY+887t5iRiSAJxlcJag2AUNZWy2qYbOpEhxJMYCYH0LU16qX5VkZcFVQ6EkYBefE4Zo/mefGEW29a7kv9yOxdrLS1TizlfMvjyTmsSdo2MIVtUIh4Gki3MNgYSEM3iLBDqscHrfc2TjjcqkUYoX1lWrosvTFOjN+gj5go8PZjYrsiOEPqPIP8QMauqA+c5v8q1BETihD2QhzlqKmxvj1QHEz9Ruhk44dfXu3ORTfKIPqnJpAweMnJVN3WMF4PoK/BkQcP4jJYH8LswrwpJT1NcqsK3M0Q0qx60YDI0xMiJm7SwN2yQBvIRXbylpYht5F6i+wQC85PZOVpoEpC4QNXK6dDSKD0Di6O5SLd82oc7wtl6Ufn0pl4khEM6o/u0+f1WFwE3QlvrkaOaEZ7XOAcDV2wZfzgEgMVX+aKwIb7l6YnmqZn3P3t+9xPjR66ua4lQGTWda8x8i9eKuVW8J+/sx3Rs4jbKfGjZVlPsi98SunGchD6B+tVg2xoQNcWD8NRljsf0L933inug0YAiaCh0V9od2waAHKmBvJgaLNlKgNhiE33thxAAUbCqZoJZnp8gbj5RCqA0ZxAJjFCD8wXg4cxd3fnnPaFK6WM5w0r+RC8MM4HW7gCTwwPMZKvjgGv5X8gd1o5MctFpkfKiBq0KXtJ66ZINGMwBU6xs0wrQ3TOw3PcTFbe6sy+JOnWEBBzJV9W/OP4Je+aodRFRqe7Xuuzc6W0HId8qoYKxNddKfR+9HOCu0XtlHkmT/DDHSe2aC/W6kB6vmcTBGTDrd72apU10AV4MuwcYsYuE9jdBnvizhKXIJ/+GWxmMsyLPmfvKYLLArnaJH/44P/KzJu8YPUpsUwquSWS7KXNcynhyk6v3nnR5Y6xfjMA+jUxeCYFqWsJ/Qm+bucwbDPUiWoMj1qgNghU+PjI5rxD54btGi/YKvSNvzij+uK9YDov1+FcQ8nDW95BVFUUIkMqujPMPDioE11sawXPa2kcgEzE1sYWtXSwbVCF4QflSmHadBhUsVVXynk6bx3NAIMNo9PZF5eEWUlO8swQT13tl7Han34Ia6qa/8QwBzUGGT1bYf2KnM8ic3KeeUD1ZFTz4J6yLF798WFEtJCNYPfS3AzrfRimE3Qmjp7LcqN05YG3Nv7va5tvzHjVBIIxbSpELn+JWM3pGKI1Qz/ZIYzPgUYE8giEpcNcvsanmX4WUhhV3qQM+Iv+8E5od1pLZFZ5imC5Njh5tDuHFiz0jeqRO0S3qqqxnnD81Mn57mLSc0ylJDj94Qio4/n5fb3RxTiEjS0QS+bjci/HxUfVjTd0jiBbBrDEZY7u9OtY3E5xXz6Rw9gWZrUBCnuWw/qS7NF3du+seXGDGwwUz74Ef0BS6MDJUM5iwRgBF9ZIFWoP1MYBq8I3qf/vPaOZioF+qpt7azEtidBRCeSeRAOoLsLp+TodXhUBNVmkNeM46+psszrblaxD5h1AThAZi1jdpP//RtjKuwmczDzEuTDRe/Qrv4ju9TAnTL8Ig5OqxCTI8OBiTUVbqwdRxnURarOhRUDmNmBTk2oyieA3Vd3w1nYtbiJQ/7qPte5pNHIFL98WAJH2XgbT2s5cVMSHacvoauIFyvfVEET+sqOYpGWaDDjVwwsq8JA5D3dudd1oZH1K5HpRPwU/0gmfLCchZD4+LedpnW1KQT/E6F6RPMptNfQCN0s7JKLd2ZUrrKLcDfE5sbaX9R/1O6wc1zsoffXZJA+QpEQqQSVZfElZ8TEi8CEwtC7fv6r68h70pdfzOLh4smN8A1WiubfdkmbIJVPmwrTXklLfbUN+F3PWTgZCVY250vU2yTX5iNVZ51BEjf+sYr+jt3jetzRkXFTDgqQWpQKqsXE27wxZk6uhVBEP1Dkc6fCwygCdYlkr6RaVZYNfwRQThbrTCyqkKMbbk5plw==" + }, + { + "Version": 0, + "To": "f014395", + "From": "f3u44q4ha2k2ojdkhxflnby3rjeh7khm36eb5ggrj3v3ylq2bv4ufh6wwhblupqlcscduq5d5xqnmbbcrseo6q", + "Nonce": 103799, + "Value": "122768679653994746", + "GasLimit": 50943856, + "GasFeeCap": "1962945247", + "GasPremium": "99498", + "Method": 7, + "Params": "ghl02VkHgKzbjxXSIDu0UjgEMH4kAnwFxoQlC1W5RSVVstCLWrB3vIjDhHrvYyIKfn+P/D1kV4Daaxql635T+7MUf0kv//ZMsh46neHyQNmWMzi34PdlAqtD+Y7BmPmO4WZ/J1MEiQHkdFo907BAfFkwDGknLdCrQu43/1gdU68F5cZLn49nkKzjZVKM8mUHDn2kDXPs1LUrF1HY7a1SAawk86BZjRhvWsqPxK9efCr071KnaIJNbfT3FcCWZas3utGV5sKAL6O/A3cM9EZDh4/5cu8RLwUEmC2XhcZ/VxiBxAPT7Lg19Q3FhnAxGAum/lh88XP5HrlK7boeX4h1TX6hzUnOEhBmh+BuWnPivdvaY7aDoyGwv8rTDk/fXARo4FvaM/fleA10fs244XLegw4KdYN4p7KTjt7mvktFCAkflpkiFXSp4PkQ9pJVJraK/HoiTA8esJTlDsxj7E3mHwXf97F0dKCb97vWloxwzYSQdMhWUjguuzAqT/Hs1Itos6zTdqkgFo/OPUC7ex5suUyuAXHsE36dQw9E6N6QXB1PfI621JtKLDm/dMgbsSy3PG39QN5S/YUp8MAOihVMTF4HDVj9hGo5KWbx6C+VictpWA9VA5btWbcSvRK6+qG0+BFjJoMvjwwcb/vaQse2rpU/zD/DFsU9spefSJP8AW15P2DYFk2Uaq8JjyPpZZIXkb4UKy3QOqm5wydfsJYqgf0cctrZ2Y2FmFbgB7p/xbAdy2pQh22ZRQ33pr3oV1uZW6OHQyB6C4/m0aZWiIZHqMWzuoiICWWAuZtW//bqkFIuXaI3AT5JZmsCpB9LgLiAzB5edFSt65Xw8LGR0MH1HdBzmCRqzVFDY0rrtiGwU0PYi/MOsDTTxK/VMng+AMGkuajDpni8ZRnWTAfGEjniT9LRqjH9qxRA2iGuxyVPWw7mcX0M1Hw9vOLYiEzSKMGF0w9b28+b5ZVvyb5/lUIFW+HpV/VH6pzmZDpsd0kKOPW6l2Zq9MxR3jB9zbXVbvT6xSzZauC0+apffKUURjkfJ3bxPxS3j9Pk8dOljYu4Lziw2FzrgjNVVSsFZ8tFYx5iyDTNLYile4F2/fPIbrGXlV0GrDJt21VJKcML9unvyQKqfJY+isaUmQtOAhF/I+MPnUBwgWuVBw71+yfz6dI0c7UfCEnYqLQcjSSJ7nUXSCHhCON7/wFvDj6sy9CWt28I8pAESAiFS6aLxq3nijoe5ej11zAOe3iqxiSjXPVkuKGdrX3LRMMY5KZBkM+sywQnn9/ONUwP1KJfDRnyrdzBRmIicJEblhb3OcVnblU+BmSslnPiKBg5H3U7bLlNR+lG9DN3InGgubmr1pRBW5k/HcVOZhgzPQkzWNXSV3u/B5IYyLckRpeOXoPFK9cLN82jcbIyUpiSogIkwh7m/KmmBLUWqOsTaiHVrTMog52ahbb25VS6meSiBjuw26Il+8CKTQsl13A5Hrjy99rG0vO3XaHTcPgGuuZdLYlhPp9HW+Ti4mYI1Y5c/T1KqkwCMr01qHAtSjESeLRIWnrktUaeoWs2FYuHSD0pZAWpSnwupZ0Py9SszmsWJZZhTxMc28ZFg9SP49rZp49eYmeFumTz2MgcoAC3cPonA4SpEjBhLOrYrIQof50g7bCXOJw7Lk7Or3D1eRvYoRKzTXesR+bXYg45ceUXNZP4S7QUAjcbMZtXfmEYkvDQO24nnvylD+Bv6zhgKWXG84Ws9vtWKklbius00A0HnmcTnDNVF0A86e+eMn8AplUF1weh1ejmg5xDQ5fv5JY25o6SCCunseD0iZ95ts86cVCHq4m8G/tLhmF6b4mHTj5fwyBV31GK50LP/ZrgOebJaKqlUNr+shvQgRWRZ+tmLLwzZjwZ9hzLJIJpAf+9BiUpcUur97NfvQ/vsLfbqYcf5Q7o99J3qsa7VtmA7P/g1+6I5rynUWCf/6U/DpUE2vOcwgOSSWQXkYoe70cHtcWiDaz2m3dL5PvdcoYz7OaNKiS1ZvvZggs84b8pfIqstVXU/1JmFtQSvni3u/i2jX8+kYpXsuvAbHZPLGbpR8/3Z5g5aoQHVuQiTElHNPvt8Yoa325QiGhvDmiic9KR+Bi9i6IdC7lLO2YxUJp41MAigI1T0r0Y9jKdMCTVdqIl/FoUsVdCVkFuTchLvymDH+X3qACIely1ud58cj9kYvQgCUZNNrEMFnpHxbvHKpPQdHIRHgcSnheWIS3jVEDEEz0y4qm1+KELdwXC7Y3+JmBq30UYbyn3nraNAUUJGx1bcGuMuudwLWj/TfhoAX6bHtajhI3QqxQqCVGwLOR+cij3AR5+Ic4HtoWesGB6uNmnyOdjdbhEyt6FL1yDsNov6AbnUaeGNteVQ5F9H8AYNi+votm9hZKiqubrEiCYqaWJXxW3GocgyD32LvxUc54c6qVWWwrWWSnSvolCtzqHdvq4W+ma4X5IswPwb8fDDsnU9PpMC800JfmBcS/znQzv1AmQ44T/uPyGyOCzWtbxklP1m/yl8dh/dmk7ITZlTcrkhmLfKCMja5HcDSDjYvae1CsfKA==" + }, + { + "Version": 0, + "To": "f014395", + "From": "f3u44q4ha2k2ojdkhxflnby3rjeh7khm36eb5ggrj3v3ylq2bv4ufh6wwhblupqlcscduq5d5xqnmbbcrseo6q", + "Nonce": 103800, + "Value": "122768990236801771", + "GasLimit": 53838513, + "GasFeeCap": "1857406425", + "GasPremium": "100025", + "Method": 7, + "Params": "ghlzEVkHgK8TPzZc2Y8hJyjXfW5CBxgClci677KMV0m1jtf7jxIkjRDxXEAMBt2wRKtqrMXXGZVY4QfEJdKzWngdfFANyf0OiZjjO7hUtVXn0RscszMIJ9q4Q35Z0Xy7CduYQUBXFA0cXkt8hfp5D0jXNsOBW56h3FkuIeBHoez3D5PIhGudUbUa/5rNF7OPs//qWBkw6IFEHzhBDxGFCsek99A1iYKsIKsdxrfVfUZkaH0pXHQsO+AGBhC6QwKZWhRXJh244oQ581x65dN19KbmiKZh7uwN1GHxMnuCSUM9uGPqBH2LAcD9jDacWiVim0QVghNnXo3r6wVtUZDkWMYuKAOqBFuCiV3ZYYBGU/IMxkwx9szFOXgh5l5a2q+NrAUO9xugdQ/e3mCio20QT9cFO9EHTWf2JYQmTUlbmsr3+qKNpvjOnfjVRa43OR5TSB+Spa3AHqB5hO+3RdhYLqvVnvOwdhmWomF0/oYvHz2JZxdzRayluXOq7zNTCHdOg7xMp7H+VrHk38/7XV6DEaRfiAfKSuUZLAaPEg4//thV3feE+QQWWbSxp84pHRMgBzOhWw3LIpGPTxKVUQGM2l+q0j3JoQBoksC4BAsLNQS5rWAYVgC6kHCN5LKRQFLgMcw0183H0ww/qafQ4K/blpJKd5aJ+vJ3dQZJTqN/g3pX3R3/ojtcuq3FWWsKLr2lVRDDQFHYorFhAM2KkhswA/VC8zN2Dab8yCIh+xptdtuJLa3z1TDg9Y2MEqQ8zSAzpsedFtT7mq5juLW+pkKvB5YdHx8kj/KXo20n+ogkbXTwcFau0BAUKZZJeD9GAMiM3xM9OnSLuamYwciSOUy6wzhuT62tGBbBuNJb5Puji9dHTRoc+cEDy1K9xoPmoljNK5odJU84EBanpkBeZWYonBHmHluLnlJKbwKlCeR8XWi81p8w3/j5xqGXcbxAaFbb4S3Km0CV26474dgF3YD8ZVGmZgwgRmCROW8ey7MKQrHT0W9ZiaAJdP/TUajs4RO7E/i+e6hxZ5mJEic7cBiYb/5SF1dyOIsu1/X64Hg6ImNMV30hCjnfIoc3Z+QMYu7pivVLCgdDVrTNNHQcGkbaO3Q2GAevUvdnEhdjhhVZ11h78szayucSWZuOQqrk2on8Tr9OqkZ97gqGfJ3esz1nx92bOQSLsO3p+HhWDjlL2rh2c4Z8ZH3My5UezXwMhZEgbQ6odF6ZA5K9VOcYBCQpjD8pzZ0Vyxk1mTUN6RPrvIOGAvjQfBTuYYoM5XY/NRsGovjtOu9856Ekk+WTavp2mNVQXP4c2bGBkFX7Do9LcGByjnOLDHSnSUhJcKvWj5peUv7k0xXvv4CP6R2M1Gw9z5tx2OQ2Ex8cKINYZfB9wJRRxZPNpdmIuvntsEthVaWtZzcFHqO6kAq068UYp1SgyKANMrMepLliCuo2r5STTGOhPQKJaqY2rka4u+7Qz9kKP7VK4G8T74SJb6kP6uc7lBupvbwa3OH71xWyEWEbS8TURUy/BZQwI0vjFsuApBI0rk5CaCPilpQ7MIWHJGhxVcKEyF6RfmTaNVAueqPyF8SmM/DEzZcGKm+QXrBj4iMJc7LCe+SfcKQPv8s00OnpVoLxJGGwcZwN/2cep3h5YSoEFQ1rhuf3KwFwzv60n6mDz7C55I59ZhQ9bKYlI1YJmrPz3z+kd2aMUKlzQgOdXEa4+7H5b1GngqFWReA4C8XBLsK2I+ioX7Vc9dyVjcmprOn7oMuoCRp2bG2Y3IJiQF2MzLCk8Ktq5Q/90g2TKppT4+xViTSLTq/bKPJJKpvYZhzL51VyIXWecdH5guqZ2XlRp5kx9OlKCWZvaO/lVBJGB5yhh1lD2qtjoxa5lDMh8ILs+SFijto2ST2SlBwARsTAlMZbSsN47VF5XAVe0w4K9pYBewwc8wCcYOhP1PtQGjs2UVY4uWjs6Z8AE3+yQYYPF1GEMvuA7C1hg4iruzUUl7vkIRdwh6ariK4OAcu/hs8bd1+PmMb6k1iJde0Kf0RD+ef6aAc5bGqzqEcq9MSKdng0gNSiqoChes9ZHtqts6ASoCE20ZqwFc+xX0bxsz9s/Es6GWv+VSjH1D+B+8w+04AUBLECSbcuK6cp2mO6Hzv+thjnNE9gSEegd7u0FofBvecLcTPJHAWWIAcH0JvUClRKlRDqdReWg5PKerMFiuMqVqs+IZ7vyzTAssqKiEpLDQhQTcQRrbWB1eeF8/o9uMgcZ6zhC6cl/zF+nT5MTkz7++GJyPPDhGn1LojYqjVHIC9w4G56UMU9o2gCX/vylUoyUMGj6LdiElsWCPM+l5ehcMd8/Ez4Op+E6oziDX92XvnhqGOKmCeb6OWKC68aP4H4YQZtWbm290CAmDikAVwwcQ4hyfWc2ZlIWXbV3+K1EEuxftQikc506/orb2/Duqg2pWKEWAuXDbLpTjT36Ex4Bmx1CGY5dVQj7GErTxhLhSRSlvhDQ+OzCzO/2cXyvsR7KHX+RLnniUywdH7AKJSNGO5n2I1vUQZNm32OysnnfLkJkvBqKjzV42AO5UqpYtIx4wHvEA==" + }, + { + "Version": 0, + "To": "f025005", + "From": "f3sk3iog3qhjiz34nhzunbcndvptfj5ed2463qaoxm6hoc4qzy6mo2swgttcyj22mkcro634gg6x7p7i4zsfcq", + "Nonce": 56165, + "Value": "122768639563121807", + "GasLimit": 57952606, + "GasFeeCap": "5000000000", + "GasPremium": "99486", + "Method": 7, + "Params": "ghoABJrVWQeAmVxmUaoaG1rj4q/Sr1FFNNQ18oKP9Q8bQ2trTkzwC1GJHsev1Taonbnzb42jG5wbiQf+w25O5cK3yEtpAlqzH2EjAHf0KS1nEPkjRsekpR0WcgudEzgEaoXqwHAp4CTHEqKU1ocwxqObfs4BiSamipB+thJIfdwmRnWiE9gAvMOzfdff7pycfmmrd+P019EEqiu5kcDr6HsF2M8PFcBsXRdKtQXuMg9O2OExB7vP8ogsZSdAGJE6Ga+nvNaHyi+etAKxiU+hujTsufbUUBQdWuCAhNtGQJkQItmBF0dY1BX3+aSYHWuGZ1+v4ttHSguvql8IW12Svddo9OTDpqxj/AU0X/SxA/JrKOb3VR7LkR4dbSYGoouvRwWBwa6IdVr3FghZ38gLFXKiKebZFLqt9R35tN6XA/ajIL9Qs+5ayYrjSS6+xT5npQQvsl5yqvxCrVSm6y0F2+CZ5P9DZUNV1y9xXqg/r1xfBxgmeRqDwQSP4r/iBFv0/2LOdik85p8hixGJOHuxERW/HqG3cQ2QpsfEMDynuIYR8YqrFh46ECvIY0KEZvNKJRQkiarIWsHPkESWTgRaJMNV9RnceI9wva4s5tPCqP3gc2pjU1QpV96CSWNIrAFGpDH/JRNaUDLYDjCkoKA9A+GykEK4tzfgVDjYjNDRcddeauIcBjpWcF09K7Qv6pzLMSxxSD6iRgICjl9x6UZKsqjSge8PS6MDTO70R7JmpOqBwYTRmx5LO1Wwd+Ezpa5DYx6yPqLVZzVRoHGqLj0iesinxyuivBVLChRAAUmZlWQNChLe2+q1YVTh0aCx+UtcSDAvdvru4CN4plOdcphJgVd2iQHObFMVdhC6L3P4+av9Rs1+PV8FeP27Dfp9ZhqkbUgYCLqU39LCFIfM9b1jnLTxPvWLZe1qS0lN4fTd0X8UZIX+VdWBQ1iYPJnmLmgKteXpODO5IUULpKwzZnjH6ckLikzNO8woEmISsyu246LakCjeYu8wAYg1QYGpHVB/ni8VRwW5OzbQpmjXMHxJNUlrCp4aY+kEOYu+z917AOA0Y7lBg60Lx8i4P3SLDAr8FivFFWCshwy2gTc3uP1S+MdgL+OL29VxmPj7rtYottrcRQMo9bnrG4xbMntVJt0u31D5vsMLnFn7ESU4QnqGO+MsZyF70ho8pXMTkKQvrstNYvAlm3jB8DidYTxXDeHU3LvrE5TWMe1phGjpynbMKgXjw9uiG26iX8FB7sjS7YCjxAHfGsmku1ZBxZZ7ZuZKskaILe5FDn+doIH+Q9Kdk4I0LksrrFehxAzdiyjFyd5wCA17PtG4Zk+65kY0SpbLLfHK9E+n2qFignMDHL0zOAMDJ67rfgIYw3zjv4AB6YrabTvVJzk7FQ9Qi3LoX2MJGGIpgDHqx5PnF0YV/5icSViAPM0LyGAl57Db2CEEAIS7JOwY+81HLDBWnZTwX1rMkdSQ4vl52hLnpeg9w53lrVqKweWI4sobpSd/E/RW2ON9bAxmGnhxa8bf+hUq6HSvJIIQFhrgTYE7tujKsSxRXLsH34bzxGL4RM4f+sUchIwm0vjIjpsuOgS9Lz1FdJCOmNcBzbRmU6ruoPHsTrom3Tne1gYa1yDaTwOz4dF80KAcgh4NpHGnDKy92i2cxkf3m0DArM7dzhVpFgw8YaL26yE80vuB9srXWSgV/44wUs7guqYT7zSHxXyUqYj5/k4HpMScG/Ed1aylqHf4KsaOiURfMcI4nvYydGlx7c5bO6UGScAU93ulDBQLrUTl+8JiwRIspYd/we6nrINfxXI/mR95jtCuzU+AA1Dzfyw46Juxc77Qm7M8HiKA/rNj3J855i6VxVkArMhBl38h2CnzsJfFZ4PdIF2etYhq06/rd1CGv5xU9Utato4XFoO/rtfQStN3nbqdBo0SCFD30xHNUPIQzdJCSAManppMLXWgc7uc88rApYGEbDfyzNbTTqD8uMR0You7YM3hkvrgSNZV3shxl3HvQflK3+2LZEbtHmXxO77QcjLvppbUTcctvWQ2z7Jmqj4aS0mSic5GYEoa24o++30DHacwaqSHOafxRGY66b/74NEV2XQqgbZEVb68VTtyk7U7GOhZoOIYOnv5YJxIhs4D2Kz5XZXNrXNyl1LluH6uAakEcFpYeCHc3JLfKST2LyX3fMv9GRsuqjw4OT3Jm1Ghrx51qsNlMsYh9iQCh95OhZSQen7YD2xyVwX77Izzym2Wx9+wixGtU8Eboz/EDaVICQZINGmSWHjMmh9l9E37FgI1fnXOnIc7pu+fDNtZGQmxyNf1sWRnQpUlwAQmpgVIY/MLLY/w9DQv6EY41rTjr5Nuzx0PstLZz2SbLB7CXrjK4X4duNTj043S8rwrONeJabCADVIMR3377YdqWMV6Y10juYL8NwlVOVJB/w8zLA/T5w9+BOhf3UBnFJuj3/QsuNArfemF+HadXfzfJa9Lrr4b/BhZAdEvC7S7jh9OPeIZd1P0tNsrNdlxR+KQS5H8D3LU7/G6ZEfeqKE3Jwf/zJya3ThF5PygTKBnG0mvAtJLuh4E" + }, + { + "Version": 0, + "To": "f063869", + "From": "f3tfkiryke7x57vfpmzkplefvq3l45zbbdi2s7hoteu4j7dkxmf746ac3ynwegocpfwsqvgspcz5gh2hsrgraq", + "Nonce": 85718, + "Value": "121193649549989127", + "GasLimit": 22351583, + "GasFeeCap": "5000000000", + "GasPremium": "99804", + "Method": 6, + "Params": "igMaAAMYUNgqWCkAAYLiA4HoAiDjfeJ0ly9DC4/EOyadEZsGa3GEkGaLKl2EE2qb3r7oLhoAA7J2gBoAC8ef9AAAAA==" + }, + { + "Version": 0, + "To": "f063869", + "From": "f3tfkiryke7x57vfpmzkplefvq3l45zbbdi2s7hoteu4j7dkxmf746ac3ynwegocpfwsqvgspcz5gh2hsrgraq", + "Nonce": 85719, + "Value": "121193649549989127", + "GasLimit": 22579083, + "GasFeeCap": "5000000000", + "GasPremium": "100442", + "Method": 6, + "Params": "igMaAAxAHNgqWCkAAYLiA4HoAiBXLZwhJvR4Z5sCjmsh/CeumgpgJ0scsWW3XjuBTnxRGhoAA7LZgBoAC8ef9AAAAA==" + }, + { + "Version": 0, + "To": "f02490", + "From": "f3qlp7se6vaw6yg3sjm2pme3xbfw7avhjng2ilmkejujbmxrsv7v5netdonvcrj5rez5epawkxpnzaei27esna", + "Nonce": 152262, + "Value": "121193537706136508", + "GasLimit": 19060373, + "GasFeeCap": "1311621761", + "GasPremium": "100245", + "Method": 6, + "Params": "igMaAAFAKtgqWCkAAYLiA4HoAiClQJL/Q5il+HDys/ycAvuQHssafDmkZgUc066IPkh4LhoAA7G9gBoAG2q59AAAAA==" + }, + { + "Version": 0, + "To": "f02490", + "From": "f3qlp7se6vaw6yg3sjm2pme3xbfw7avhjng2ilmkejujbmxrsv7v5netdonvcrj5rez5epawkxpnzaei27esna", + "Nonce": 152263, + "Value": "121193649549989127", + "GasLimit": 18935373, + "GasFeeCap": "1320280302", + "GasPremium": "100033", + "Method": 6, + "Params": "igMaAAFACdgqWCkAAYLiA4HoAiADF04Gnra8VU53u4k3GmOiJ6rN7h2xGopseIZaZx+YSxoAA7G9gBoAG2q59AAAAA==" + }, + { + "Version": 0, + "To": "f02490", + "From": "f3qlp7se6vaw6yg3sjm2pme3xbfw7avhjng2ilmkejujbmxrsv7v5netdonvcrj5rez5epawkxpnzaei27esna", + "Nonce": 152264, + "Value": "121193649549989127", + "GasLimit": 18330588, + "GasFeeCap": "1363840592", + "GasPremium": "100049", + "Method": 6, + "Params": "igMaAAE/q9gqWCkAAYLiA4HoAiACEaD12Tus2RcZq6d7ArT7R0MHjleSi7uWFJMiClQGBhoAA7G8gBoAG2q59AAAAA==" + }, + { + "Version": 0, + "To": "f039515", + "From": "f3vq7krz36z3aprqkdwve5njq5grk4im6udi4xcs6d5y24gozdydlaeq3qadptzt2pkkhwdo52cnwlpy7fhbcq", + "Nonce": 97713, + "Value": "122763647555888672", + "GasLimit": 50950106, + "GasFeeCap": "1373893118", + "GasPremium": "99549", + "Method": 7, + "Params": "ghnCdVkHgKQACiygwbTXcOjx2ab5n+CsGJJvtVHLk3SfsYKUA1MqUmfGbZB9ywtEBuPd+4KsUqUWXomyb/e1yEtlP8mx/7epdqX7HzYtJ6GbSOJvh/G3F3o3/VY6GHRfbRXyQbfirQiU8/0lsleGSwz/7fWui0Yd+7SD6woA8cUJ2MoPt3LliqqS8W5EQMMHziN8QhJo+IUt+oMR7ssKJTvsnh2pvuIjNVkIVJlkcluiG1VI5dGNoBDJnJc0QV/AK/XNr1FDu4KYmuM5kN0dEjdnJaNbT2aESVcpee7EO+wk3VSoCjq5cJ1Y/58Iz1ltf8wni9fwHokepGZlvLCeaJagdZROzMxsDY9l5mtqVzjdPAEfhbPESXLnEClytE+GKFB3iayzLhNU6X7+UG6xa5H+HDLNtz8Rn5JkXvtKGFXSE1GjYN8VWDJ9uTAgn7OHn+Y0kzilU4F7IQDLKjjIC0BZXY7GyT/bzRCdMrSWHp/zpvOTPE6cwoXR78ugrA6o5mXsKUGvT6/qiQe2cZSTL98HXQFd5V3v2OfKjXh2h4Dt1m6JESETCf5x3Cwo1Ak+ke2ET5rBSIelG6KJUEXOGMIVFa8fytoh3ieNUztgHtI9dbaynRNBd59q83QmTSE0jcoK7mcsMRmYnenU0dW2cBFNWWhFvr7ezVaTrK56kvPm2c0WWorEWn8BsglwzqTGNNhZV3MBVa2/kPdxhRKeHexb41QRNEHyXccTa6KdhnVq88RhLNSYDrAHhcy8xJZwmi047G/O3Yy2mxZ591sjGwEg2Wea8E8+917Ot13G4sA8nPS/zgxnL5pbcW0ZH6N59+gt7Q3jipKrs95Sk1EnfZjLOT9h+WkPsK3EMDxPUx164BhwV4IyZ/1QJdwBoGw1x29gOx9KphlSWrBrf5/GQZMmNWauFixxUmrL7ZlMjUj2qfxkCVqmK+wjkkfBRKkCcmEw1aWkGahXbeXgiC3lY3BZI8TBmTObhbT8PWU39NoVXV/tkm6FEBvC8FZELUTyuP0YOxhim6Prk2Qcjh4DJ+9DDEfxyiwYri0vjAmnxfZuYVwnGO0qxyieDaYhKwOgj9gUFbNnt4LO/nJZoR4/fud5bnzj6KLe9VqqxU6TMdUrAJhREU7xOdaf5n7yFzuJjK8SKnbevBaWhd8oHwDsGXm8RtGYg1ANX4oQAvaXV+YIgBNy6FmYCN5Xk1Evc/Y9xfijaSQy7YNwyv1UoSsG7L0iGu0QWlAR1V8hDDlqINiYcTWNmvlPd5X+Uew/VumtCiwiiXVeWIDZsWGNeG5sYyUJXEIo8HtCCuWP9KGFKEez4g2kYxfOks4/dAuHqaxjS/bWVt3jAogWJJxbQSastlycuH6OXB/dJo5ewtkmKhWm1RYVPqQ+spyAPCDyIVSELvKlM/U7OgxmnUcHwMXr2F3+7GKpb6+ynf22emsa+UKJ+q/xqoyXIXzfuunB15k0BPYcW/1oAIcQohRNOPtRHR69ZWiUhjHj6bRfyqoIzIMuj7t+4/9GaFtsNve8Ve+zouY3/md7qpHJLRVAyC848G3onQYYaufFtLHq6TGtCZXqS9ZdGPbDTZ1RaY4eEEIM7TrfCLdiHJK/vLNDoKzPOQO5NMnhWO1jFwdXm3dg943nJAI1aXRW/9QySqLg1myyVQScksf3HAzFJBdCkz37ulRmqmwuYIwJmnDLITnH5u9PcA0GuJg5dQdU+z6rNp0QwxBp/pST0rE+DWUX934BPg1vyMIqJ1b0mbQW8uWOuOopuxBgDRdfHZWToHCYyqRKoPdZSpQ29qWMYEm431K38dR1S1+mOTkx5eUda0wXSn5IzqKlh3B0gj4+1ScA3l+7Z8B5qlRBC6RM9poq82vyG0O0wMIJrb3TUk+qkvMR+/0lOPTBpdX6DtBBmIFZ2xuJKgGYEiebYQgui7/l4GEVlgNwW4cvNrCIeRYhjsD7KMqdx4tbuE8DGJUISEE/39W2Mwf8aDonmbdtV2ApoN4MTQLnNLK4Hb/kou3MGFr15YAo9WFqpuT+vKwfwkPQHXHmer8x/J2Ir67o7hdqpA/qUDM8vJ1hhM/geeUTvZTITgd656F3w8osNabd3HP09pR+gB+mCx1bMrZFETqLGWvVuty9Cy/cNPHXk6v24nJhYAKyN9OVeNjd4W1Qkx+WBJyRPfQgXOQ9IgDhc/lYEaxdI9tR86wQy45tCu85z0QlbUsUt8DAAyyk7KKS/xp81uMBjhaEzf5xHaCWbQvakfD8hHxxo+aq4JbOC1on+HjuY27++fahcdoHIhmc/G9ob1rN5QMJIYdO1pPHx/NzW74gxO6VdlApsSZWR0aKamA6GTtHyjFvmJKepplsJFkZcUs3RXXtvTc7d61Lb9ObZTF1pIn0+/9it+W4tx8G+cVzJUhiGybOcMU8EoEm8xmmorxspWnSgRRG3Bn7cNdhKYcLntbZVnDANciaez/8VzttVEFXkzCxB10c0tT/ATZfgT2w17RstyXH1pMFoNO3K6eSNCt09JrIRsrnOIhrqNqQNDNcmLAWfJBrYXVQMAjo/TCm9Px+ERMGCg==" + }, + { + "Version": 0, + "To": "f024016", + "From": "f3sxklgufxdf3dzdluvudjqugr3v5hr3l6vcwjunsdo3nrhvtzsjejf2tlkttsw4pzut7vwkbrag7skjq3l2pq", + "Nonce": 85789, + "Value": "122768103851199153", + "GasLimit": 50857303, + "GasFeeCap": "983142971", + "GasPremium": "100583", + "Method": 7, + "Params": "ghmwEFkHgKRdV0ddSeEnkfubxJWH1ILivUGa3cfw8yUItEL0+ed0SWJi3x5poLUSZ2whrGWbX4su5TONBs5K+bhH5g/Lz0wsmhmbSB25K1G9APuzhf8eVmgNzqQoFVug/2xQ/T/KmQ6mHSRqVwAb830rqp6Wl3VL9hnvVmRNDF/SD3MthQdCzDJsH8m5os+y0hCUwFePC4KX6KOjRQA9m+zAxUndZjV3lL9dz2JBt0fY8Z/SXXEKPPybnCKJYxPTw1xnT0gnpaS+6RpShDPIMLo9hg7invv6WGXKYmqqRN5DTBaIKM02ygwdvA6fnaqyv7Nltc+doLVB6wwS9uprzncdIMqOTrmrPDPpkR8asDCbM7wQTm2tT2xV2Z/srxyVtr24oBcxpwO4Do7OEv+QwU0EHf2LV8sbh5LTePF2e2xUYxYT8np8DCllhcO8hjuVS94fpvx40Yl4BvDGlVqynQb8d7ZvGNESgqzT85dvtfNiPTH7NDbZzntg14syEF6IjU5ow0Jo96yWf4k98GFOvAjTXT3JqoyYe8I+XLBP8d2cCDf7PBwTPqZ8ykl3Ch1TQksk4Lq9UIkoCPBVGrDdlbytnRg8mHBu4o5qknZ4cgBkwtMfn3pOXNgcIYr+MQZCvZTp/lvyPRW1dNKAkhq912WSOV+SI8DVVYNdoFxNWsyaRD5zPF5PtwvBAwzT9XxnQXUrbUJjPJJ5Wk2aGNvy/N6Sh4/Avzeu/wsGAGmw7st+y6KSsSDZoPv5fAgSrIUL9ffpTnPTso2Yq9uJVVISgYZwFul6WYQCS/iXusPcxWq82yOMTX8/JzDuyOedWw+yxI+3ay2MJbhAF0e8vd7oceWtYzypR4ks6zAIAQBHB56dsJXiYJJe4CPFDBuoVjQQWMT27MQc9wZFY/RlRka11xs1eioa9m3ZnaRQ1GLfiJnuVzTw3Nuvj/3T4YiJSAXBL7pNe5OHmqsICVgc0w3upi5hLbWEIFUFuzPLetX4uh6cLyZ/B/Fd9xjWIvKKzrmJB/TlKkSWDbZiR42jFFXzbpakE9UUvw+RiZuzpIs/Tsu5FNFCCPEsl4RKOHnaarEeyVVrUtcZSLLMiT3EiiSAVh6nOdQthA3GnMOn8zuuCzBlW4l6FrJVv3XTiYOjM0BM4TpjsoBi7hYJRgEogXcGTo7OwLcZ+fgcp07K1pyIkj5ka1M8PFe+uifF2P0OcqBASUw3P2ENOIDD5tETUbiWII5Mw9WU5bkv1WqD6ZTaiExMkQQ4SSl3LTkcW02XQS7lHn9SwrQobpPfw/z9ph+o2AO26jn3i3zTWEwzzl8vQCZBBhIqQp8GPhQyglXhBauNboUWmbofr4mkXzkO91XhnzS1ALwxmPmH0z18DMtfsgoX5+xilrRanQUFlBIatFpMw1Iv0cY1hQzRjoa4Q77nLRmLgeyMk3MOpusD1dtobloiGn/gyECMstlFHUPik2HO5ScL1E7PHpKyW+7CHs3TeRz3TgkvtY6u3YisptkfWHTifkquYE3GtKjvjdWqL8xNEKrcIigy5Y5PoUm09RkQYBdC8nPXAqLt+4sLV5gNvl6x5N/6TBeBE7LCenpugTOA7+sDt+FH56kBD+fjSyx+xUTOodHuLbodGRrnSo+8WNHeP09764nIml98oAdlss2ju/ASCJsS1QHucESSql4ZLplqjyRl8sePCY6QcMDGy2a6QJsldExHXIWPeUbbFB62kBHl3Iw4LLIjjBueNVBg8YV7OPueMN7BCRPyAtR5/XYnL5dGfAe2+iXRO9bZ7gLwZ1hledu5gJlKnzOzW1z9D9GAWyghRFDswFgvs98mTZ/ghbdVoR67QA7UqbEwaKVaBwtbOEgg8IO6dAOcZXQUmZLDm5Uh5e2agsPpW+FCjZ2rHWsWgJ0e/gEVDoIDKWLuB675aBbx4RHOEO4+aJp8Cu+fYsJZ8JGFxEm5bQKhM8vGapUb/I+ZCJe73vRFRXhnCc75bJ9KW7ANtVf1tnqSYrrJRnUJKXwaxEGlz0aN5vVODXCPL+wy1ok2xDoOXhwJSpyuCnSt27BZ4zfIWkM/KNd/J2jbmKpgu5kowr2lcValn+XlgBwSgjnp0tbwyOYXvW4ibvAXsYvMpvgb6wBWd3eSCEeoy5zNsLly63ETPRV6ae2SJAlQJzxrh+vSxk12fHlFhlu4gxQDO3TgueKSYhC+ir/CUPyNUNpcVfRJPYiPzl6CyFHP/ZoxDb+vwVWWeBktKEdLjKfP5vmKtlG/H+bclE0ubZDlFFfE96ZE8bZnx4oGkjtrHwA8nv0HyJ5Q1sc4EVNbjpHqr3IUZVgLnUDlEgfc2UvksPKZpBPV5BwQHV31SCeMJGoI0ZgoCLiV5Lpcdm3TGYmTitx327ahk33FM3XX2dxMWLnJLuCJXdGEatIG7HuU6mgZxVNpak0wvXlFNjrTVAmcSi9IcsU+90XHcIbDkM6fGXdZ+cTeeqtXrWdC4TT/OPxx1Qyn02/UcJONJZo0GqfR8RhjUkQlIIwqjlTsfpnXkGMUlDWVPuyHWxW+AqxDwdwLLJRZlTwXsBZyW0uHdA==" + }, + { + "Version": 0, + "To": "f024015", + "From": "f3qgj3kzglrkipapieveoppnvoq6vxnvpp62cqtf6nzqsocptzwg3hgpgsklnmbtalc4l43lv4gwbrz26dugfq", + "Nonce": 88256, + "Value": "122767874298661230", + "GasLimit": 50948856, + "GasFeeCap": "981376304", + "GasPremium": "100962", + "Method": 7, + "Params": "ghmXnVkHgK2dTTcKLhJfI/brDJhvTeBmt+QirSaQKtp9k4xGO7W9ePeW5WW8s2QYjowt/P+UmrCfGb0ON8rd0nLTxHNMDSGQvMn01LP5syzWhR2KHmrjnHQXk2UgNgCeOnerJ3nlgAZQrpe2thw5ie32axkOhMZmtJXyArbMRO8i1v4OhXxepiVfObr9B9U0PxklIw482KI/mGUNahXqhwURo9saZYd6hg6GWkYu28mNOKUfPSyeLQ4ehNz0CrIdAwuSh9v8EKPccMYg9um7XWKGV8d6aQtZEzJZr46fYOM3jdKIqSE1o3H3OuuYEOCaIkxltZKJ/IzWU/z1kN2TSe0X2o3E/Edd97AJnErvpyEmPzI+C8VpD8DuXp0HdBDiuTpOIgnnMQTpXg15QU+lTIpidHelGxxlDPCbZ+m9NPDoy11KhOlRNb85cEodtFQ5fWzBhgLvYYDr/DT7L5hCQmbb0+lskLKCYCGzuIOFS6EYtSc+9id7qSrniXIcQBFrI/l4c0WHL5ifSsz2ZInHm/Lv8jdSxsKxAirsJ02ftzPLUesr8It9moqe3eu+do18LZr0axcqzYs+pa6PWgdFIUvlPtl8qWUdRTkFmcxxnzJqtlpGbC1mfikxYgUqGZ/iHjgoeSJRxg0reYbnhLgF9qo4+f0Rn+uOV9KUSMzTxeDA8vu8ykO8e9cJcgHu1khtsn3E1yKMRpGxxPSfRS9vJqRvfJl7bj7m3GW5RXPW2cFWj4LDCtEoQeXjWToQxWGZ55aE1aBlxbn5DruB0CW/TiH++26Do5EUsVZv8E5P88IjkKmFI5SBPtRMVjG/oLn9tH3/rNv4m4i0CnVpVzfjdsAz9S2+L2xzNunYwA2kyf5vp6rhM15kOhRWrMlx/lmhnPcd1rrFNhdOtX8TbsXeVwXqM1ASLLuwXgpyWWGRohJtsu06G74qOnfeURDPSmyGARMF3wWef5kCL3jB0TLe9G/FquDtxYvoK8mjFdv3Hb+ngu1SxgqulNBtcVXkoWy+wGIeAGcAW7DrDcUKZCvsOeDqWVJIOkrtbdjfkXNqahCGlXMedtXSbdsjoGo7cW9TmnneWrkmSIfSzYjoLzqKRz24M4HrG45ABz0l83a/iOZBwjjvFo8R8zvANZCKZ0ae3sdiG0z3oBaJp+v3oS51W8B8Xg5PzhFqa/eVF4kwrha8tkSQ7nJV1xY44ajI7408T5ppMUn8PIeG/0gCb/sk7cb2olVnY2Mo9bw/HlY4+h+6ttL018gfbyvoPjQPwdtvhZfauPjwR7iHzKdvMLSy868lWSZwqozJf1KmeWdLwXf0kZomgSwtAKae8NijMX2HFCVooCg5RYB00WnHqtoIzKBaF26ImGBztzEyKOSU7qG6MRoIKXZEUdhYAXQFZy3NMM7DF176Qwom6jW8h55UA8xqA/xZRahVE6EOgFyttP7rsxSfwlmXFs1BxS+U7Qs5UINTO/2WdLIBe0s98d+pDBlJQYTLeID1Lz5jhOqArHu8AhUhFtP7gDN49C2CmNhE4FihciaMYJd3NyI5wUQt9kr78fSkF3D3CtAXvAEFbXrIVIWRaW/a1HaA0dJt8hyje8q+GbUce6w8Ud5hXr1/5vMJlmRVCpjDi37PtJq1bFYlG2kUhiEqEy/tqVYpjQ63+ahlx4CrxxdrvA89O3n8lUqqNBxhk7VUfoV6juUQl1axfOGPRPk3YCnH9WkVGL14X6nhwWJIQ61if3bji10xrSzm4EBxL14ZMySLNbDe0PLLrfgX4Ik0Bq5vE9AqKPlg0YeyXmXBL4/ws7ogsSucyTyfJCVMd/5uKZX+1CcK0dg2tw/6L53ziCUtlNhRsBiRdBtFqNElgoSYkeR2+6CyXWdEmPBWuWqmWNP3wjqXhGti9pxNDrCY4yjCv9wXCJXXUblf9GDAwgfbSqaUNT7gXgjZYeUDC62QoH5CM1r7uSkH+AzA41wx6QpL5AHCgpWYRFsvKSGRPqawo7xAraV6L3DyJBOkU/GsI37H1R7vZEWj+22Ipddggb4m2Pylp4z4VJ5rWgkEyofYqgx3PWxnP5G/NfAKGRjqOGcuQWR6Tf5f0S8Q+KpI5HSAYnD1aorCDIBruZudu6ONAuxHVnDb67gAVxjYiiB3zfhqJJ2dhZM7zGLbxQufPyGESHptCN7862mXCgolwgoMcSmjpqWYPsCL1y2q107sFXjboHUimCErjvzQ20IDqO0kVRXxx69LiwoEyPVE15GzHEStwcF0dwBdPOL1cPBqIxdOheMEV/bFc1gON0F933ANuyclyqQ0N43MayW6iqDDwatNC9/h4bviMYsB+dpJqRCJ9rRH69BKavgS7ZPIHuJbDw3cP2lsOR5rNng4PJcAD8FbckbbkQv7sSP+QkcymmKYnjQnRmCaVGEAqDr91pNA03bh8yCX2OB5+yyMLgf2hOJQT0fSFWd2KdFaFzz9ah06eT8HDGFIVFXe80mlsg2V6ngEyH/HTjskBY/oyrFVBcWlAxy6usoFha66iuhSiYL993ZTje2P+GodMz0VaHOjKWhcveOJc5aDcGsM2g==" + }, + { + "Version": 0, + "To": "f02626", + "From": "f3sqwodtyqnzhf5hohcwlhir6pkheacdqd53bgqyud76fsbwdcplrlmn52wpucllg6x3ajnptap4mafsecq2ra", + "Nonce": 269627, + "Value": "121193649549989127", + "GasLimit": 17754728, + "GasFeeCap": "1408075640", + "GasPremium": "99846", + "Method": 6, + "Params": "igMaAAaOotgqWCkAAYLiA4HoAiChlHv6Q16GsfghrO/Wxd0IrWPxjmmHjKtYaskRiOdmOhoAA7IrgBoAG2hi9AAAAA==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127086, + "Value": "122754414950240392", + "GasLimit": 72461188, + "GasFeeCap": "966034396", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4GlkHgKufE00Ip9ZytGnNG/pzryKYbLzhZDRR3Z3nADeTrVanBN+3ZVmyC3nMMuT2cxm38qg55NTXDm2OTQ+0XgLUNrt0kLk+n4tFfBmyx5R9YLcg8c8Dod+2P5EfD5K+IXcdxRnAxJKE+JAN5MIQJgE24sJ6qUbea8ZzkI3VRM88MQUbL8ukW+vgqDdkb0Gix5Rmm5Nq1+gxp5EgU3S0I+W0j850yAPCPrA1HmeSkqaqer/Kegj4qSyhREoQwPWvVnRRF6qbDHLlq98C6NYTDHs0DJYV47Vly3xVmbjd7hXdYd2uJdveMyJdO8rKS+b70emgHqXg/yEnvpU6GQypFsUMk2sNivhiKmmbsZ4/9JfNgkdfLP8PlH7tlU5tRS79VS6gOQVSpvB1oksOmKkgFf3+x+e2279xfU0jV2OlLTcOdczoPnZc7O9qbEf5Kr1ou3XHO7fhriCUeSyUakZN+gYl5hmRfidxCQH+EWqobyUXs4nk49tDlTnTXgVYLhsTpEBc/a93/OkIMCt64PQgRLYVpnwz6l3m6AkEWaHcehrMAtJc34vXiyocy+RwEDZ+2t9jMaLVM82eoHgoI/sMrdTNXRAPDaGX/oXCics15beE0bsyoqJw11jMVB6gsiSDmiFohxCLvbVN2b/InhcSifv48L5Om+mxP4gjBzE7Z/U2agetrArFzCsFkBy/8YHJi0hL06t1iBwsURLqB/3qA7F5C/ExZBcrNVqH4XGv09LJZNVYaJT4eWDOzfRkVpqisatQlYsMGFSfU1NVHHioG/4diVdixWpZ1dqwHk1SXIB8oLJD4ngZ/HzVIRZHfZy3Ym+3pLO9JlLuFyK5QblXVMCtEQe06ZhPW/SCwxVWk3P2kufkA0EY6PdLa7EL2X4ss3vOyQKOS1G2j5RpqFKiDljS3KnDqjgQz3bjjgUoca9iqnVmjV4Ypp4TGw3C5/BmiSSB5LDsYPbdoitwFQjMUf3PaRm3qP2bVEjQBxweXBnk8CiRG0i8n9qY/FKl6hn9ZxgcdLMWGreNBwUsPvZzWIE2W+b8WcabSH7yjRKmJFlpOUOmR0tmgSzuY1QLKRnFiMvUlZOYzXfYI/NraPdDOOelV66IMfFPBI31+0P+yBvyKmVzPCri3zaK0yU3A6EOcm/m8hWF7ytwYy3hhy7JWAGcPMeiitE74fWgLdUP3iZrQRUBTRmygyyK537/1QfFoZz1DI8dtAqSAOise/HCGFp0wFYQMVlsV5dccsG4sOqSzUXML0rCugkfh8VHrsRo+C4+EpFXxDGj05NP6zRc9ghWRO6ZklR0hMgmy0+Hydf0AqWANcyIoU4CMIxPXWJBGGIJHrNMzYhYLA68SnUlF3m34C/hRgWGMsk4E75wRhFcZyIt854qKPnwRMNPgZerqn9oAgx4HRfEnt+kv+hvD9o8vHeTh+uNysvC5PvGiu5olUblNy3vY21OG0Swxe6F/E7Xh4G/+wwM9H+XwD6QC1HbzHANeXRWnBs3KnQDYOhnXdRrGGT/EeLu5qLh/JaTjmxhk63e+MfOHhYgni3fKPlgoWjoZArx2rcXkxeHzv6ZxQkOsLdYh/hqtO8q91Hn+TztuLcdUBzaZYiLVwwCdg/XV0vgOTRDqYKKTrbwo2rT5rsH+VQlQgUBY+suDoZfWsTU9xAk+Ms6z2Ien4pv5nVDHA+ZzBZzUb2tZgokbtATvs2qDQwkGVDBBg5J82dEK/hyfpE5aMPj2uruPrdnsEZJhiCSM2dABVBLGAGXoIWZkilAc9o2Y2rxik8orPzlC2X/cI4kJuro4QwB1MCNg81XoYlN6w9/3uYLHlZ2zlDO1Dj35+fgXWuUp3kw7JswQQJXX4+Q3wB//a14pCTa/6zIRjBXuXM+KaexVSByrmnONTio1XZccLhh1mzoWKheLaXURQOIu3iCdGk3aKtIEnY5X0LJOlxyzEDmp1cQq8KyMnSdOQMalA4Afb4JJCfh2EUXLJG76ZrhfGH3maXii5VP+Hwx9cG5i8WVZZ49qhls2AxHyvRaEXZ8qcYr1DgCQtjo2LTfu+U/cXxElAJc0tuPPU7+PUu1Cj5RlzlwPyVhS05wYoXJyOu3qhEUJ/2UmK7MZbAYq8MqfjAkFaPWW+7P7uUQhr2UCBQlcGZ4yHkg2RB6s3zSN1VaErYNPkm5Y3TZjBd3gyFjbZ/fouV2YzP0LJPltU1PLYbUjX1ToEeTxiSSusAyzSXNfqGGqLCD8a3BvJcVuUZe2cJa+TJsIKOvSvwzejb4Pce8+H6U8i+COibCVJLuEjh+kfQxtQm02RiZgZEI4enc1oHDVQYfxwbLK45QKtJ/R7OKISEKVUt2j7ia+RUELf4kfomL3DM9QYL/aIBlP9e0ZOrvCGLB18CrjJLiYIzdOACpsf30rERqgvfFjuxP4a/8VT/+4A7rZLLykgrZ09P/Ubg8GupnMTM+38HxFVGPoYsSI1Ky22okY0vOXs59IYzbwgWEYhiy4XXe/bKi7STSu5cm6zgcxkR9XkBRT28F72so4qCyNuft9ylrRffY1cHAEYj+Ajo/2OMeng==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127087, + "Value": "122756725122938685", + "GasLimit": 54156403, + "GasFeeCap": "1292552609", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4QVkHgKEmT1JbVaf2oDfsH8bn9dmoxxPSkcn0IgknuYp9eBsXYj6D1prKHj+3l8Rxpe2I4owLlCcHD+K0c/PelMoZrCdBMgilOB2wic9h8fSb3Da/Zkpl0nt8x5tWLITljjEvBBWygb//R42UxjY9GUgWksa1CWpeN2WlBEG00zCP5Qs1JBQDN29dYW98PkXnpM/V7I9zHQ+rGcEys2uIjobf/bldyZiGHimzcfjn5XcF9R0XCndagfS986REkeuEERaY8KMhcz+7dGdUbgj31QP0N/J5FTmRTDTr59EXN3LLQKPQ2TUwNr9MZj9imb3PZQNhwpek7UzffQa3OmQIHvyI14aqcXhyJXGmE6quXeGcabxa+n0cEZj+a8BDLNM7I3bX1gk8GY28niH0v14XhEAwvC0qQLf0mVn/eNl3KmkH4FD9yfyU/lV/ZxO/DTM7a+g7m6TdZDrdatoZVrtVJe2mLyZQRCFivztonHfT1Sv/JchLPwoQQlmL7lhmZjHb/PAy5JChQO2hhb9/maFK++Zijo2M2304UlgZ5pvAieskIT/VfYyA3p5MiDVPC6i807BNQ5iXYimHkPkQNhqdlq8wJLLzi6I988JcyP2qYrHCiZE7Ybuml6dVH9D2DCraOhqbNQDz+05JIPdFQIQjcWqXtmn3V2sLhiYlYwrP7QXUmLhFIQWbhajunei83D5IlpTa0pRcZaSBB4eq6J3vcOWNj2jUuIQ9sEXWfVINHJ7/b3dZoBslDKxsb9ZFaDOBm+sqEoZsHcUpN7zEvSTiYyzNzrLi5d6cjkrEe5uQe4I2Hmyf5XarntOyjg84lyniArwHXKsZBa6/VdhWHiV3NprP4v+sCN2RZX6kOAOt07v29M9UG9H2vmmNttEEL1Z34H+7fg/r0TCtNiQSq850+PvrW2roiBfGP28AzvrMIpGb/Ecm0qhVwmb1Ud1VJp6T96UIpZnKOlDuLH5Gi3+GHI31bINDyHlOJ/EFSVKf2Bd5mbIO14+pmL9rgVHKC53h3BQcaKqJnmRa4wlXftmSRxEEVgMVKcsAjc2teYExYzgVWaG3aYNnCXgHvtFHb81hVvf/pK3obSDPlTBk8meM9hH9nNcn/BO6++bIHjAO3k/jnqXJcLpHI2fEnzLQ46T+NmRvpAK0bPW2B3oHuUmCQTE3MrPZcGAMnCGwLiGWX44Yjq/eTiqY3iBzyJfDQOC/Algg7I3caefsNZVhc1MBqyU+RcFrdBqUPpTHOF50r0iXmh9yN4OO2r8RTHODczZwRpylEaIgtx9Vz5CSgONAGSPBHdu0ZJsORUY4FK+jS4TzhCwnZte4zc0QJL5BRZqWLbisAIw6rnBXNXEhWcrgClsZSZxgkQu/De0on0Vnm7gp+G6Lr5GRzaW4SpdKYCyQsH+XtgTDZuM6fwRREvl1/8waU72FWI7kwLsVi3c6xRwKITXOBFTs8wVsw8sTTr6vZtQZGYx05qVGz8nXW6NfuDLMInjPyuwRijNYWQ79uCTixT2SCP8sctdkyF2/ufq2CP3RNIN/lD+Hw1btgRJiK0YVDWWHk1dcFRI3jFrvceE7LRe8dKlLVyTfbkkZw9uSOhGl/qGjtAkGt7QdI86oXUVkN6SzDcHACb+BDtj55UrcuOBYgzkM/iyHI76jIrfYcbuNjwXPOknSKiajcNV8BvyvD2ZJ4VOTGDU+0nv3Jt4DQ60rP/XZo3NokKnlic7/b4ts77kJNjrVe4/3MvMY4FkS9H5WpxhzrsWqeogAJi9Ocyv6LksXNSVzPKfgLrbmZSh14YPiaRwPuC2hvjh2pwuey8VqVgKgIwfr4xCsWQ42ldWaRLdVVWeeE5T1z6ntdBIf94/rJBuxN72TfKkj6RSkVVF+DbYWRNeMkMCdgKts2dj6ZcW4+pngncUy9YbOcpigXgAG/cGpyvDcJV+HZc6TShogp/g1phikH3N1OMFzwIucfFASd8jWlakHDq0j9E2FDa7/GpYLNUMKBwVP4B/GzRfTDkGTScY3T7NkiOLiShXk2b9AnPF5+dL/F7u3pXc6SbDoYh+fuk/YCRX9DPL8g21Vq4rYIIuD0/Hm7mkGBrwNzEriqz7Y7Fn2bDIP0RzsY6u5rNQk9W4gToh4Jc8mtkrDIo9yBVkGRdP+K0aK/mf+RWnksd1CPRz/S9H0//nvoxilQLxuEdA0Wga+ux5kqaBkXOqpc2JwJhqF3ZFRGaudI5ratj0J7TEGASHE5goYypZdrXplnmeovWByoBswpeFJlIj5+xagv0WRsUVeRIFx+mBrqHsddrpchQHE6svQuJEot9VmSR15Y2fMuYoOU4jlNR+r1MXosVZfisEWVZkSwbkqFnehe1kk1dARmh6IALdKrO/eheYiE6aIhKH4kYcX0oUzROras1gNAc6bjNtNysGIZxYT+KxEp1VfxabigQRFkas1jmKgvfb54d5ToJ5xVr2/U4MQcHLMBel2a1WnZy4n9CjXLYWmpRAfVu3LPpZNAyF508RDhsh0X0/zbsY7zLgY+BnGcw9kIJW04e5g6Qu0pF/gOtxTvzs+Mglv+w==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127088, + "Value": "121192826880132287", + "GasLimit": 14588478, + "GasFeeCap": "4798307266", + "GasPremium": "100", + "Method": 6, + "Params": "igMZ+SDYKlgpAAGC4gOB6AIgLr+eYX2OJI7V4v8uDUZ8Jre4Zn+5GQhX5Ployqmpn1kaAAOzL4AaABOUkvQAAAA=" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127089, + "Value": "122753783997758719", + "GasLimit": 56768903, + "GasFeeCap": "1233069450", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4LVkHgIbjmSjhW5QIGFlYh3rlW1QWfgwNmZ+hXyhZnXv7Q4urEoLxqmbGFimK5uNguUQm5LZz3bbwsiKVZttS9hJyJ4T11PMJKUskSWXn7fTLyqvyoq6iZ9DnOr1QGD+yq9jaxQIorRDtK3w7BqAFVcsw6P73cOuYhjOuvRR5zK0AFF/COoz0CZrPHO7KgcKDcQQw64n1lWzEPZIYTlMUR7bgYvDoeHmkdq+osGRxlsTJQbprVHGYdvRg+P23vsRzJvBvx4vOSEqjGsLbTXo1pFQ4NxJbxMvn/wopEGc5BKjOI6Ev2mYubT38eo4jd5dx9b+3zYK8jWtHJFWnQCi2EoLLwMWq8u1kYgPX1Sl7jyCjzGDxC+XJKJyqV48NQ9+M684wgxMwMOpOftObYkLqS+poWWwzYA+zeulzF1Cn5c11He8CU4SUO7ATCEF5ihwvXNveVq88psGl1/qAQQ/1i/sZiizGzAWYEw9iV0bY32hl/1S10chCQdKCbaAI6Bm68oXnlZS0LKlm4xyx/g1TJQXdtXakCvS+PqODhe26pImqZGCLDruMvdRaFB0+iEszmBDLg4APMMS1fnSFOj3UA7esjISty/GT2lsWAdTw/f5JNTwqGSryafpJVN3jhPJYoYPvgwLU6/uEjJMqQE8Mud7nW6lqPD4y91tXDmJRWwlbs+iWcKsVI2orGxZJYfhPol60eqhvqGgWospnBTYJ1f9VA9J2TmZpF13Rlw2xFiqMXBNG6Hf1brWbcCJouO1hzx+T2pB2qFOs+Dh2PWq6OSoKn1HTI8Z/k8mEy3e3hPNklc2swoRe81tFXb93t0jKLHxfiqxzU7U/9bCv/Hyr5hJxJcHmS9y5WjV7Yfa2KvxiCquCLNXuwfV9TbWMIzF5Ghe5jxQtvlQYyGbfpplIN5MoX960t8Hq4r4ijR2Ses5Y6rLEzwP5J2n+pWpKZe+VghpV6IC0+Wny7nN7dUpHWxk499c6hrgRZkEI03nz2OsJI7wAUfJUJJqfEcozwesf99jNF4/VmF9ZHt/P/XpgwhIeAGUdtOEhlez5g+RoAqYezmeWaTCqCU1kgrakTZ2twU4ZgquXr1v6lcVby5mp5I8CbHZ/xH57oYciG86EKngNo8zp0Lh+dZnDT/v5jznUmoyVFQGdt9uOYd3pzs7/zbKrjN3C6nJMnZhnBcCNOx0x+jdQeLAyBNOYD88yjBYIo7qhUYBCRG/z/k5vmiijSDKFDwZdTchcn5HShoAdimZqx/pju2Bwrb4ygwSfEsSaCeZtUaOores+bzllZQIClGKvqGFa313pbD6IuUGke63djKQM9KB2Cg7EhyJfAstDIEkEh4aBSZ9LkODEkI9CDVbcXbvVKglLpLJucokI/A4SVPHfLD8sak0A8qgXAZ0e2+40kgBUiap2+XQyXCLsN8O82yaUj768Nb0B/iOGAU7bDTJBQPAxeZtvcJ3kS6hWIDXLurF/CxZKLqxwYs2RGSgKAdT0GoibCytuYuytkZO71opewT+P8MezSgRmUaKWNEBI6LUslmmq/CrtVSqmMXWQM2CAIHDyrvJ4L2UUUw+wQsuA8rls+BcjxIuNqd8DvZRPq7kMrdTy3Ih9xGlOHQolvS4MIuhM+QKRSHbt4cv0ie+4us8lCNApV31aya4W39fg5giOhgqni420/3IBXHLH9fTGGjduY8n4W+bIqHRvye34Xn+UPemeJTx8hr1JUmIHWIpPnZyc5c6OMooM4OVuTOyp5sC0FJKe7UIiw1xoF/5Tb7wYcUV6+CVKnbyZThyuLKxsafeGVqOIMJPdMapp0jYSY8DjEyD3xekz3N936xFhPNfYMCLgHF6UME026hV8j7I6EHlwrtlmfSO8MZPNvrsSHXFRzCp+lkmoLrxT2Hu19uAQ+K8NFZ5Ccrl2bXSIoAuPed9xI/0ilPOGnWu0w9Q/wLiIp3Lm1AU5G3i+/LZl5c9lQbCPCBvuzdMX5/r/OLDBpiRbm/OxEEhZnRJ0LTiO07I4Ul+bD10iH9XUhp8CH9vjnagCpcTAAEyaprfVg5cFvholS44xaC36KGAvwSk0OS/ca+9iT/HCtkyiIjsSBAnolShJIxvTSkwdIneLYZO86M0XBg7RHa/skQub+EPJtwRIfGTFyfw8D+W7xF5wNEI749chk2TCOG4hYCKesAHrdXPSMGinGXSHFdAsgZamTySJV4pRkxB4dnV4U3Lfugl1zea7qMcHwZBszO0qTouR4GrW8nYEg1GG1hCrhcMq/6Rs2qMj2NDT+cB/LM2h1kUM9cPDyRRLnoAMU2W0ZJaVESyTim87iIHp8l/TsLLOYv7QjDlf4xW24FRVv2EX+NRuxjruaZflfzSQZt65sIOvKVYVasVJvGisx/uOC1jNebLhSZldG3BDZbbN+DCPxI1uCRPnxJiMSL2Q76EZlQ3M/POmN31J5kt5+L3JQqpjYRQz4ge7ivtysg5Ry+QHNhr1hH/QFMfkbk8Zzl1el4boY3scSiKJ/OqS7mbLsjyYhJ47niSdzzO/McnCHUiuu/i4k+E7/HIpCtCCW2mo1Q==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127090, + "Value": "122753783997758719", + "GasLimit": 59381403, + "GasFeeCap": "1178820244", + "GasPremium": "100", + "Method": 7, + "Params": "ghn3vlkHgJNwLao1B9DXfmWf3sZWmhdAtaWIYHtixmFWJ/hsZ7HmxGIP5iWxGrRkSjy4fmHYaq5Con+Mb3NOTCswxv4SAcTJaiHt5stFhhugboWnZcEw6Ue+oMzKj1jJPcuLenEVkAWAKBntDNign12nJOMFLgffNR6yKwwpQyQZC2lJ6PzApJ547I6E9gXYK0Pq64+gj4T+lrIvaLu0QmCoWtfm6Sti4HpKtFrKy3mGaC01dp2r/JX8u+5jBIwfCdyaGqwNB6+TOUTie2VkFdBPkcI1NBCq1R/1i/BpDMaeu5mkIH6JOieM3T0taCocqHX9B6zzpKazHy61g4lUrmdStS6gCU9wNBxH3DTMRs2ukS5TfBMJJ25+5aDx3jKe3wfgwXpnSRm2wWjoNB0Id/nlQDKzeXo3WyXzIBh1/0H5M3zNp854ZOR7vNM0uwxdvvwgAJKlo4vrNCabQXiD8gIVPl+YobdOmhz+0aofDWcDJ4U3iqg40LLU1JnJtTaCqdQuTe9gy6XzGiqXrIvrpUiCba3S+ueY5O29JjV63TW8ITMGP0sVuTNHFct7qarn4iSFdUBMYq+rxfdFxfaViuGY0w3Pi4rh+1MFE0hbFIpu7+HwNXh7DgEbmHRXCstOq3yNYoM02gmLrw8BI3LJHupvMiGNAGmi9eg4LXHoGnuf7JKoveZWhBow2TKt/6Jn5zFx6iikT6mMtpDeYk6kqGpNXzRDlldhvcCSCJj53Pmvrn3Gn7T7VoUwR3cdHyh5tNFQ9gmKCpVzLwVEhyYrtq9Y4gUCxMe4SZzkR9fRdjNHIM0fmAbkHbPkErowhMGdWPsfo+HqmJPepwamDoW3tCCeKkquNmdG13sMZ9eNj89Gy92zXvG9Wg497mLayzY26sVro2DQ/xfgY2cHZOQilzlTwn0xgK0QUO5520vDLbL0sviPCL11qdJapHDUSPI4M/GWfkiGCI9f9BMY4iyGna3AeF3nPQKsvqxakFWKCR/e2mZiEC/t1tE4sHHWvs2OtKRcyfdboKIXrfO0uV8eJ+aC4M8nj3y1r8wEZqiV6uqi7hDzBrs3pNTOAV2RgEi1KWCNg+mn/7d7kF7+ktH0n550W8/ypat9jA2+0opE3BovEvyYpsvs/hekp6mOZ+ahF+Jfy1E2uAMsmVzEiSEhaRuu0u9qeAewWsgi9bonuCneSF263HRFUpd85zzbP96rcWpbyOh/eK28S9vh+3WyUZ9WZSXivx+xUrnBP3uDmNEN/HMzS+xPKBpDifxI7jUMbhuVMjD5bJWfLK7XdzII+O9sFBasMVJdY5LlHCSk/73gLq5UwQfOrd/weImoU00pvYT+E4xrtrgn6nSouH7JZRlslwdQd/nkBAHNVVCt3U5LUWbhLEZUOTVil/QyvEIvncAuXQOlnBU07tkzkMYiE0ovMkGUBGI7yERyfAhL225nv+ZZp5R03dyGhjuBsLhQR1U+sNrB+KSG1HlPM/bDQ+BjfS5dZkGU45HjKxh0NQT7ulYSej1WplUYqmQ0OHMhv3qv5EaKH5hrTMa+R7KtBARUb7/iOXtHaQiuJZVaHBvY+DIkD3iUDUmBC9r+vDDzrPlYSbMHh4RJVghtAG0D5oJ5xLN1aAGC3nvBtK4u3N1DvLpr0s2t4xFHw7gCwnlnVYnC+/8zHhHqsIMljspAb1ZJS8eYCmFHKIeHvO2eqEyCiQEQPGVwuSAm59jsSwcQeeH5zJMJSKtWyHnYWFuDxS/LIkR9fEb2mwLCfmfkK3AXSmZcNtgFJ6/KZ83fecRCpo/00D//qZnkmOL9qJN3WClnr57RzSJEDovYB9FzEE0vcNNBZOCoRCC8MehLcUj6QqSCu6vk9qXKL5AChsSd1+2afwSQIYHdh1t9/lhOdraLOITPTPsqU6KgIugTI4fNnwXDsYCxbBbc5wgq+oUT6BIwoFrWTHyU2cMcohf1FrpAEGxLVhnqGG5f2LknfspidgmAoraOyKKenm/3aPN6bTIo1mZQXa6Zn6a6UfiZ+s+/5J5sfj7j08IBjtU6qzbG4ovI0PBxuo6PJCtpsULUTpc4AXgb3XM3uRTyQMO8yjY6hLeHn9Tv8n7zspvh5zFeTEt8PZW9OqhYOh0zR6hwrhTBqHEfXI+KHPGTpU0L1BefDYyJCRcgGSplMvzy4xDPMSCIHLe2rggzyFO130L5zNJ/0odCDLTDHAM9xCcoihz8aYiB6tgHjJ4lP807VFOrYEHbblH1koE6TlkmxdNc18YYiK0vYrWHUS01qlixGuOAbGKw1eYTvNdWliTV2WYsyEffulM2eLk4DZvPeW6Rl14MkHPzQJwdicFkoOyePJon2kWcE7FlDCc8yK9BudKXlzjrffmnjq5fn87JqSn9QgT2aqfWXHbTJSFexDcj0jZGAlyOXWx91EhUwBUZMAKYFik//envDAKQSHENmNIp7tv+sXPzETs/Wo2UgL64oUrpHkaFo2RaIafJrfdP9km/sRJM+YSDvau5Q4svJ/ObQMN63WBEwwPjWvEfIvLeJPihvpNNhQNRn+LNWEy8iAfENhGIg3CsQw==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127091, + "Value": "122754738281267011", + "GasLimit": 61993903, + "GasFeeCap": "1129143296", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4AlkHgJLKlh97dwT2QFSIVqYf7kewuln69Bh2GRXROstim9pn1nxVLSNkUbPGV/dQ6ywsgIik5QQhUcRuksHwSK1F9FoCFH1ka7dWPmn9V3pVQaspLzUd3bVny2wvpx3D2sH4tQTpyr7H7tcL67+Ew7ckJ2AS6fBaL9ialM+R7rTjWX8vfYjeIMYqW41V6qrdBnylW4QqlFR7mus81jnEHVN435ba8StmDgVovYLVaqAu0oosZpJrY7sMn31GhilJvMBILKoYyUs+/xzjktnw5lM3r9sWwl7rp+OPMlMlTVN4iBU+9sv47/hJg/LDByCkq72Fo46D42s7wVjY1xIxMEg3y7DYY4nN6T7y0UQU2EsRBrLt1sCep8iH7tx/1xuki+XbRAy2Z+tufAvlOH0ye9mqeYFyh/Brb+OsFdzcD1459rrnvjoHdFjfF6J+QJ/ssCKQ0aecFh5JSaQH5dpJtg0y3PUShZytYoRCh9sy2rfhifOmVwSw9JqWdAHaFgxGLrv5SrBXP4FHlkmU6KVDyZ2E3PD/KwuNUl+56fY6opjD0+mZZGokF2QlvhNQY9+v1bHMO4oIqeX602bsVWzWGduCtcXusZRcOq7WxdUot7Rh3PJu3q6Es8eBKzS+xfbkwkjvOxLmaNtONrzo416eu23iOxUQXKTvj3YmXEbQ/uZEX4/vvxtJVPtXKe4FOwiWdvNq3LFbCk5i9jPec5TziVpBeGCxza32XYfixRTb3BnwlQd4mi0rWbaPWcim3tJxQWN9CI+Lr8RuprkXgKIDabESoPJULS9TUQGbfbAS0BdsyKWzkqKzWDbX2o40LWCSQ6f92KFtrewI5RK3k0SmpUvMs724fGrv7vBUR6uV6hlVE2I5fFqlsMjshCu68RvDdLk7ghF9/kTHV2cdVF50UKNL8Iv+B7KF+hst1l3GlCEpezMcXkUSaqGodwr5Mdg7b1U1FLZJ2Mhcf+1UaCalNV/nFSzghB0XFNUjr2OKqyQTMR+U+G6WPPyR7Zn3AvTEG5fS26sqMXD84+V63iFlkkrw8ha/WPQm/jd5iGfRVGBqPLaZ3fItJ4Sfc8Zb2YKUBnnDjaIffwyixHQ57elHMU9IQYuv0drUzU3UzLx1KME6pwiC9rRyMKHFuYpBGOo5aIMJkQnnP3zck571b1P/C8mplO8Lc9opbJfl0lVv7wISCiHTo5X8a3VP8D39hDh5t+NMA626xAs3hwIDZ7eK67pU/oPhE8sJzduhxdGzh2hh1eR8meBbu/gz89/FqHZryfFa6o/TygJKAVOxFxWy6X0aAPCu+LKY6DAKYl6ScmpCJ05zHb+4nlFCd5m9YLV5ZKq60JnPHCVhUdf7p+ftFNy0UCnvooKdB3s8CkkdAEuw51AOvdV4iaHzW8w4qC7WAZgi7xKhU00lWM8GLFfiyc4AAX0wkkVRYX1temVeZmiAKpqShtvf+v/MLbr8jdHB3GS7prJnd5O7mV4TLkgdZcfSYT0TGJlbQ6rdn57fDfrTs/d8t5ipXBkST4DIWMi8X8g8+YtoIRGwJ60EsjpTiNIKybNL7pTLQ7sGH+Lv4D17+JY1FgXOSXfhXUDw47gEQGkAOYFg0ZbhlsWy4Rigt37LgtdfqlgodZ9NU78MAjOJ4fLkP6i4ziXfys+XOqyBkTkf3BFn5q9UfYEE7stTnnc+jNnWZd1XsG4ENkM2dqYhMCVISHTW9wgybfLVW4Nag/alJZTJKiKdLcvDO8ZZ24V8VHg+f+3e+pTtLw7x7MznBhc0WZXS8NMo3RE7MCPJm/WaQLkfZrlaoVpyqbzLEgg6QoQWndTdDElkls+NABXzO74YYGFM+XYD315Nod8oL6Xgp6pdoV7oELnLV6clxSHJzdXmXnyDgFLy0ZZc9J1SyCeEtqMR6ZUALSRPiqN9DLbBtRN2+X6mpQz7vtR/b8k1Q8IgvpVH+nYLQlpYxeiuon1c5cKZecoYNLDsuZo3h8JnvLdMuVbknbvdR/AuvowjdJ3IM3jKkOU4/XMApxYh03RAcuqq+Azco2s6RIlAN8/geqYCidF2Gk3XQrubSIm2IGTGdWj4rUJrXh30MFNpSO2ywaKz+7d4orKiDkSRWoPCmKu6FyYaC34thVkT40giJEwFc482wLlqcI2WiyTFhgsDLZ4SnqH/urUBYt6/9hPZJBGMRVLLQWcc0jB3e88Xj+tC0Fe+v3C1L5ctVeGdw1nqUd6Dctf4nxwJrvJYNrE2zYpKlqRh3vDSRX3SSNduzECNJDd72b0veSYLKk7fWHHevAYolJsziEpI4xGdlnGJio0I0aE6Kw7lqYKuI7DsQo55RilSU8kk88lK2CBLgbA/rbODoIbOOMmep+xeW5Mpmrc7RT17jzTELH5j8xjYwD1OXtPE1e5qT7HqLBZvuZ1iAAgYJMMjmZnsUDMOxjYSbhdPhCyYnR8Vb97U4IoZoK9R5bP7MAaRAYT7QBQ0sReeH9aBrBmy1mu/veEz/yx+Vah6OmC1QfmAVQJDhjTlpZW1xomFobIF+TeL+DD10y4HKpR4DAFWaxZ2ADSxAqBwfA==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127092, + "Value": "122752513875793063", + "GasLimit": 64606403, + "GasFeeCap": "1083483938", + "GasPremium": "100", + "Method": 7, + "Params": "ghn38VkHgJkzZfWicDHnDfbHnBha+q1D71Zp3Leh3ATS/jh71oOZ8uGzbxBkkEIjOHudasyCf4HH/cvN81S9Zi7CW9KA5aoIgxL6BeA04kmn3rbBCSRbxtOHDq960SIMPd0poywqgAPkCBukRshZlHcbKw+unRGwVMXjjk5JIelAR7Bf7pr92QMu9joCf039zpYnFEkvQaJWrbP7/vVguaRJWFOe/DXX/x6OzwQrk8m6cbOj8F4um2c7l/G1yIZaBieLuWlTfq+E2tXnQUUgF1YSSHXwgncX8y/4q+wQJf/8Duq1G8e4UdB6sg3xDJjnX+iM2GguR4fupeKnjZkZJvXz9vcxBtO9PB2IFs9aH9RRM2WJKuVRpQ/I6DqDJ8xXNycmgJtPtgiM6lvRBB5+Go79JFewp2AQEsR9JP/TgEqKqJq57v8+dcgihcPpp7ltUlpbV7F/E6CGTj43SAmLPckE5ILoupEoJgaYeJONxxKcSdA3j7bXgFYTSX09LITpx5c3T7w/fYdnmIPGGIbsGjRcXEml0BPzqBl6Vwk7VhHRfjJ4dPxcsVDqv3MnHDQG65PIORekwLcG1ZKYVQwSURDnIJvVa5GbBBeGS535RGzPK+XU9O300K/lYA7Rx45nRPaC8TLhGwC2OHqR2GHsoJEnPsrAo6UPAgT54t9SXEYMZ+w9iYGLkfU8or8YL8cXZrENX9BsjpJkQSGwW8uZaR6UWYVu9p/Rfc9Jb5qjKRBWNFK94HHLW7zTxdPtQoQvP1NvrpwHYrdJWBpk5+O9T1pS0Gct/HVpLiIjBge/oC9cIbyi8gwqrwHLLlj+F+pN7VwtvogASKTMbpI5EXKUvOs0NAd9Kdm7oWZ+0O/KuyN1sI/+m4nats38kkHYQWDzf3NbxAZZahVq7M4ebxniAeNf0C+DKqSpXX2KLWjXGgITIJNylxojKIPRklVaSfiEcJZTBwlWEJOkp8s4aOkiSs56tdLLCrCo0hbHJB48HpilGl/2ITgRYhMDj9aYdR4bFCWIbNFwj49S4tDVU+x8RWWYL3UWtdVwziWxexTzkg3kSvGqdCaGi1vFoDG6brd7M500IRt0x4tEoVN3Erb7E7e+Lii11BnGFda3CuDtPonMLhG9Na5WJuLGmBsagKpEF1EAggzSTBmolQAwcxdwBDmBcRYe2EMbsPW+zffqokvgwTOSQFjj1F7HmiJKRug2bIzvSzg8P4awjEqK/xqKYbyoIfN1ITHs2UshBOVYPocClfcnQjJOQ75QNOYLg1QfSbzzsyShB4hmd8rVmXCqqOM6wlX7Ant8TwnUk6tXO+gnMtnHTlpYFbohsYd1AQI4NuzTQ1OiD4n8LS8s27kXEC74EeYM9oUV61OW2tsTu45joXR6qcSyaxO/dEyelSchNa8fwYFHmBEXARMCrR/TZVWZm/X3tzREvodgAhaOVM8ePZApp+wFX446NKGwR2JkX2k1ogBdvrTAF37az5O7YbAmuNLB8uuW9QU1HayvksDgCaW71WSBFQ6KK3vbcerpdekBXOfL45AYrssAyCOM0vkxdTzK6O81krBxYb96WRb1HeWdY0FKqLzPRF/exrOk0MdF/n9hIIll2ugt+dln+l7sRxmgGqfDu1flAIN7RkOxMOYTgswZMhtH9rIkcAnX7kAKBt9fJhd6FEyKHSbwH7l93dTijoOkjUh11llFYO1sOm5uPCtNVRRQIzO7rP4YuK/gS2PU8IQt7whG7mUpZqYKiUFZcxG+jqkEe/lepERJiIvFua39kSLyLwkZ7ntJOCTZtCw6jKOcnIUHEdLsoZ38EZYXCkL1K5VNP5Jtob6zpEApfVBYYRmKgEz2kAr0f5TCvqYOXJgWzClWnEd38QEOwVFjS2SpgtpM/Mv/j2YdtP8w15ITkEmJWa13eIRfbB7AVaS0ZgSb1QFCI7DvIdJGjM6yxsg/cW03GfoVkNXPLxgj1+TEOh7P0OPx5HmNK+eMs1etxrZalogCOHnnmTPi2Wfd5nIYObD1xj2IHJCgVihthfWgMMSbilDyD+vmPSt43Q/UZZXBxmwgFBnqomku9Tg1Yq9zNzmN3Yj5Sn742gPFo4xa7ytcYNvPN8rRHD1LqRkYU40mlTQTXZC3p0xSSleQTasQI5EquUvQJIBGH+hq0ArwmGpt4du/xWAH9XHPeclUYxXJs8A54zSYIhd3Tg2sAukTHpNmUik5Mzr5cV3HEr9axwGYyBGyNLyf7EoTwSqHKYZS7xs3ZN3BgxwVCHwd1r4PRgNLdStw/OGIfC2KaqyNslK5IlxnUg1Zr2P1vuYZmq3U2Zw9XziEu/13XYOs0aXJrsLXaLXNxR5Ddh45PlCfBL7Ar7PydPZPmXOTs5RFvYHah5ZdbYqxLCr1KOnjK1M/aG0pcPGVn0Wy7A5V5Znh8cwy2hyr6rbE5sOKejWXOg7ScbHfvRBLOP7kIyhpeduZ/WQfx+EoEdU9baxm2WZzWPOkIFLzcenQsaREr9NQqYv5r+vrDzE6LX/7vI4+cqWvEC7WKHsocVJvlz2wr6AMBb/bKzD294nfRN/YCRXeCA==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127093, + "Value": "122755128376244721", + "GasLimit": 67218903, + "GasFeeCap": "1041373733", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4CVkHgK1ptbxvIUVzzgOQhQWLO9R0+sInQQFYe6fw9dkl5HeA82+Js6M6Os/sdVbyk1ym9aZ26S/uFOBMhlGwFK1t5p2pc8YFwT40PnGOeHLKwp9U/mw1w8+BarjMTmiy1wglBA2kDDOa2DGmyfuzmnefCErVdlcCtlfJX+IF2h1TKseIpwxmVDMKRkqZ+lDzTlkcb6wPbHIDi4mVjxifm9wa+rdq+Sc6mVzZrDPjJ/MDge4+YTNWf9fPTNyzmV0pmuO75KsRhSLLSwA6rQa4bwoBxpFf7SiH4Nfzav9XEgO2n29MGTt6oum9An90vwLegVuvhaLaio9Fa3nBoZTn08+bcyr0smud99nbBpkcOIG/RAeSYgkYEGIA8CsNaH0rpXlKRQxh+4iYJ7naAoWZsQwaB2pgpBwsa2xT8Z/WyMDtABo2crPi/sxAvUx/+wgkD6VCo7fORlL/m0FaRJh3y1ksvlQPqoKtdLn1Sbjn3ltW6g4lE6CYgZ969gLMmZbp7U6fI7NOhzZ0kTaoTEjDdjMP1WSLbJmMOyjUnJO9QOuR9EpfSU4WQx8zksBAEI2j18sDAYHiqxUwU0QRekoQPEUYcnM9yJP6oKz/qK33t+sT2ej3WlGi3s7fP/V8bfqFe3FYYgeMxpr8qNqrcTpI1GWm4wnRSzA2JX/bajIsQRi6ELe9t5nBOc8C0XoSoeb8cVJ3VIdMtJEkMsTndrqb0iyTba/T+69/G6bv1l19T3ghb4mQnECP1PZ3nPu36CUeC0CBiZgwMSOp4Dv0MR5IVcK/IdgH18m64xbDEVUDTiH/HNfdlRD7vUySiJzYlslVJugGEJXyS0nSkQehxma3bZDlUCgxHI0Hlb6RQ1u3v9NVsRrPmOWtlDI5DNal3p13R8WE3hI9ZpIweWor7VHOig3LMTw5TXQq2XT3VCy7jW4q4bD5vSmgHgTUGatODaxGkHpaUqXgAnSEcjcT8zOG9bFNMgkr3H5OeZ0qqYvVlg8kdAqBiwmcQYKfLOJtFjz3HGdURI93MWU50HaGheUN2ZViHzMCPDnD4+vpRjYmxGluZrd0C7tYKoLS13O0/17f1hBQWbRk+66wKy0cmr1kxvwuyVBQFrYzJgEf/18rtcXPLDCZh6Z/oimfKRID2pTojIjliQ0iTYy0h8PdvfR3ZB1gPfF74u+jKx0dBKiKV3Cfbr7K4haDxAFBi5z3ftwvfsT9hqzPx7IOJRdMRipuOTLDY15obPfuG4Bk0enqxRyl+vPdEY7W61BWgKMzaOhBsBKUzqfSHIkgxk0398RwaJa0l3rpuCKd93scTcIiM5iL0sjNkdyiWbIcONtjPcmT+SIxy4JIRoh7QO6fztrDS/9n0c//0vnb+bRarcxgtVDHZxEFbi/KcGm1OeBGZdmmeNqutwKruSUjQpB9U3YN0HD76PD4CokEVcB/jyhHLDxarImR7iwht3bHzfWlM4Hu9SzkyIH7tRC30oLt+P2AHtnsz0BJQpBq1/uEI/6M+CB4g5EdGYASGHsjCm6sN6DG3G07u4N31FgA6ciBpVaONDlwwAM/fW+pdIr0DWjyN6tWgWXhMycKB7FVdPXrPQJuJBxZgYFSohDkXAwZjpuj0Tgro3mqKqUtuuFeFd9vA1vFxU/SFiYViIUpwFLFoBT2FBEnuBS7hZiKAYYCqtGnFKCj71u8XzZjRIsUQY30tSmxonNjUr+F4/ij4gbu1ciKNGZSxKZWaUW2PuvDOtN/j3pxJK2syD1cKznt8n9jE4oyrA5bf8Ype9qfqN5oENVJMbiJYaYpFa9GyLanz/+dSvm+3C98uNq8NEUcYzFBWnzH1qsd1bDgQG/Xd/Rthkt5gm1LXodOluhcEVQ1H8iZnHPqsatJ54uXimaSyQ5jktDS1Kzh5CkpMnGSfSEr2ODQnBWqFgs0nfMY7+Y/MiyASImKzkfjp/xkUrl9LKllGHTKeFWT6Y1PNil69E2jk8V4AMNOy4vsH/xmVfYfZ59BP+qU78m34NIwuolffEWXk6nLDj80eBu9cp42tXINLV7PJqrvQKt27OFVQj9HKqL8kqR63brY1xIP3BPHDdOxl0Y7G8V8mt28u7BQsa/A0Yyyu8TwN5Qs+6JwONkA0hgl7bgSmXrtlYqItlZUZWQktaHriAXfV1TfXFVuYB9+W4dFKvGnbQK4sv67ESgkhSar3Q9hrMkLrG+XY5XLWcjjapgRFzHbOFOyd9YUrbUf7V+J2Z2xf7IgJ1W+nNxFZXfhwsTQH7aYEYbZZXYPG9STsExRXguT7YLMo1+E4F9ARS6tSZkZEYcGQq+pkGLmLWJkNse+3mllv9IFkZAZMS//IKPixCde17u6W99/175/WrvlphlbaK6tUNaKSELiVFbY505lgXvg0SmKlrpFK9Wesf10atVSOX6EGRFr0eteP9oLKYhWuAjvG/9N4/bpM3rKt4KeW7KQgzRWkxLpBRJ6P/ORlXYqdPVVBgjvF/Bgw0Kbfu4Q3rdJSMUvh87fO0BdE779v+xjX502ECDy+zK7UpKVXKUQ4M5NCmTIShKEgbRQ+QFVaw==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127094, + "Value": "122755566180601001", + "GasLimit": 69831403, + "GasFeeCap": "1002414343", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4KVkHgJVZqGRPGmVbNkEJuzKZyJNpznSjleR6LrUWAOsHqu7CZxd9mGWWJjQObcQqkPSWFbTBhsKdBX0j2vOZKA+AMmnx5o0e53P4RAoeXAxqCUgPKVKqqn5yTquS8EWzCEf7hxLHOInRcqzhTlwd8lRxXYvbuLWAxrhmpbpAEoHj9Ya9+pqyMntRvd+vSv1Rn/EJm4X5rR8Wc0uJolYYNZKrxiUvby+11jpVcz9nq7ggESEP8QU0iE9wBbsKvKSV7EKNnaPyu8gtmMXEr/4CYM6coCsh5kvtMahp45q8CQcA3q9hU0l06at1mPZvXelfiOjGTq5Z+ClUICxdETWGEBXEqyqu02+WppUt9GUN22wfnTIiYZKWEvQ8DKSU1S8zSpO8NBXLQvVuLcCPVf51B4R1VFeDKKp/qPelhwiH9YoXAHtEsPg1w3Qs/OovyDo6Ts7KqrYvHwYd5K93XPCllLtxhZ26R/bokGLp7IqVG3+idxPzeDmkuSyyjXqpKQIdBUZMcoVVS473hh2cDgtzd6Szll9K6SjnGaalTV2/ORgDkeoayTrjVTK6FJlwReQ5lIeLpaG2UO6RcXFiXhzp5+uOwF9Dgt4Lm4+Rpf6FFPrlM7dbZINif3D928V8cM4BKOV7dQ5UB2egjhrjpDsudH51Dzwz/pwWJfZejocNRg0gDSG6Guflwbenvk1hCSkVbeFESIgPDSiVnyjvsmbmgGojC2YAlhrGRE/7l3f87jrfFsNfkYYcVIwEiusFMRzhFyhlEKzov9bZ6kEarUbKLiz9yjtzewwogBTSCCp38iZ7QmK7aN+bVFG7qWvMcqdR2seiObBpeh4zvh2+0YYUf4ZnqtDJGX1LIQooay4Z7e+jmkSEuoOr6gKt3CePvEDr4h/2uRI98ttF76ETa/3JpgT5nMaQcLBuH95RE47phBtP5K6392F6pOVSJiAGFiiijIe4nZjxXeKPCVidrHPA7repAwixGAg5wgLmM/AkD48cW0liW63DAL8lAQoC3dkCJ62ryYqrtUce7wYzKcXr7nxT1pQteus6VbRnbYHzjlyB8ipvSnj7GjOC3GtEW3ZSPQJHDJWMc2CkEsSyc1IUcjY2sla+mmTNHCi2h1XEdYYnXywG4jKD8k0K/iDqZK0EuBuF3BDs5snATiB8wbHa33vA0cVXlrj13BjBKrJb9FhI7GGdILP0f3AGvMN/2y0khuErGqwflNJgA8HDiQfsDTDDtU/nO5A5y7dzA28qGj+nFjelIHi0f14O7ClBTeYSZRcxeLlbnhhHUWoWhrvn6oXM7DUJl9SFtMje2AMBlugm7FMDA5X8adkkvAnuOdnjWWNW/Zc6MeDq2RvgKjQxezCN7KDvc8f0WxLH51p5zTzfSjZXMOObZAB766ww9RtrGo9odBL1zbV605jwvQfIMASr4fhSnIIb46cwR8VaCvGi8LkFCTYerV+nRvXHkyiBpswP2JhdQzVpsQYc2sYrorSLKu2SJluM79qq88FNESE3RQNCGsT1u3FFzzWTitFTBG4Ru4MLWtRFPQPLWAQjt9KlxUr+ViNsA2fTiJDCep9NpvX+g+r0m2wWphQ6qjCEig9xuJNrB88G/icJqLo9c0NswM0aVSiwkZojhwJIGwZNNqYUm5iCyBBbTdvQUWL8bSz6nwX4vFPUHYIP8me3ST0R7THw6377OcE4HexaSYbRsHNZJ4+AcfsdP5KBELg2H/7wIITi1uQtvjlzvYHzIejdnHatEOGm8Xbau9wXmlqybhENDQFhw8W6tMX8UCte9HZsZLMUpRscRvZ/8K/Ott6O9/pnqU/qLm3N8AEV4iao/GgVidGUukUhqMN2RvJ+AAfPaKBZLCpSQb510KMI9XIqgc2HGjLl8SI65eONZNGgymUtSshR14s8u1+tUacc7L4p5BPhE4ZIVwORyv6dpjvdNINfyBrjGSfr3KqZsvS1Ge8+sTKiUoHpoHXL+AZX9wHxpZI5uX/3b0zMuNMTgMpR5+rU50d1C2tH8u5TL01Wse0wUQbXIpchrUPqKJYtYSd2H7HujEg19yH2GmeiczuRD6Y4YrCHzbvO67+HBcoBLZswPQ1ZA7hkf6jcyiY14cvyx7mzgczMhgtXSI7zpFTnXUDwK3y9k502kfdJZr2zNfn9Vv9ILhQJxvtcfche4ai7fxkBCTM2ewqT71K+j9qEzpo66/IQq5bnXfIyxbHPIJVxU8XT7Cy9CMzbxkAMsyM0KJnEsRkp1cYOrPmt8ZjdXrZRrDXEsnGgJAA4BGVIMoGUpa3o0QinT72J4BYWNFXoX5Nn8LiJIGg30zllx7tHAD7gtkWQaaGt4KEPq3FtII0kXVtpnm45iqgfx5jmiD3QCK1kL/O+6VPprxPIG18ZSe/RYTkVSPQUvS5PDsX5e7z4OucjSJthdp2eTM8iN97V6QRc3ZH0rEwb04jFRdKC1nL2YeF+Ry931nej514PLUQUilJHuWv/issPUdf/NSVZda670kd14hsMafwBO0P7W1WzC6tna0WCOUfL8iG1I6TTqJ6xWZFAJ1tksGygr2H5WA==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127095, + "Value": "122748613666641373", + "GasLimit": 51503601, + "GasFeeCap": "1359128267", + "GasPremium": "100", + "Method": 7, + "Params": "ghn3olkHgKqx0mF/L/KhTE/5cSarLYFn8WoD0AYNaHJwHk2HWNjvdKloSdYyhEbqY0wyJVi19I1fExhnWxPiZ8f9ypixWjkU/EddSCTyQ9ZVJCBhBoznm+OggWEgpAvlke7wm1EqLQfzU2k0vMZIbg3I4X7pcHIWeIH/FnvUwxqy72OB1CC1cVctNGtaiaFxh9wKNMuk75HN4dPJAWtL74MAgmIDBTyLCxs83R1Bq4afWs0u/V3zsQpE33CHa1ePk9gayovr6YxI1WJ8umpgS82/fl1Krn5rhnw/AIWJVTKOgRMm/OunXAeIJ841cnSp7MAfs3+5rICsKKoO1LYxCqPHk9APhhF6G9sftsx16eg8yghZtbt5TxIOTYGXONF9AAAqxleBDwne6ba29KuR6FF50cn3xd2DSp5YKKtfV+jmB0rYSjEln2vLjMrTvvzYOy1XYtfE+IvLvI3716c+IYVwm9kxMpZm8rGbQKpqoPEE8J638LlYLzNla0ehB+AxW5gqn0iRlpW8ihciQOjlgWidDOZ6etqVA8PPrh3VkUF3Wfxy/+iJKU3OLJLvsnBOQ8pZQsoHr6jFMqTqyH8gCurywCsFBG5nHwcRdy5ys+iWvP/4KqfTfDh8Fc3WywvoNnsx1YsWjAFFtF0+cRwWRV0yGSrt67LrpPJPlFIo+yP4FUcTtB2aONGnBmMPF5HjzHWTGVtywJQCBmVXBjkONdi/fs29EKLMlLdw30RCIpVl/SxQmr/TPWZvvvPquuBmbq3Iv7J72pC0d1XsnuteP6Sc3IhhodyOEuSfs9YmTZLe5yC/w2aA9yYASm/6Nx7Ix0KwNglgqq9KW1FbSC8+u8W2qdrH/6xg5AQgibOAHV+knCgjkrZwUk8WEVQgEDiRC4lQymPrwwRm73MHUZFGYlWT8F7hR98i3Xz5YqTbl94mfWU2/qX0oZixr5B4nYLelu/TJY3TcoTp57AjCXXjaQuiuem826UqLy9cIyGuMr7OAOQgGBsMG+2bHgdddMKL5p1V5Q87WJYJyLAT3xLqdcC4++keXycE7u2zfPcZYB2VoEjuo4koJy0EiwRsE97UaPf49XAUapfbrLQ71+Uk7iCO4E9S/UWzHv28upE7vfWXzQnxCRvDacx00LX6gU7+7KXiO7LWiRkY+K3aPnVgX2zRdRZCuorQtJwcIdIkQbNP+n3EgTZ7bPY6oEXsy7mrqL/GxzWIxY5EsLidNlF8WqocvobrLVeiR05rlCu3kMiDvFmqF1Qlxu7+hZyTTnbW/T7iEGUrrpD/JTv5/v55sYctqpzv2cKien5Z3VMXbLeoHpfsF/ailM+wFJ0yWW/QMfs0GlClj5bFPvMRc6eKOvzYQDSRAkEM90D8y2IdmKI7rPhpgrJM+PNPaAUZQUfe/d75A/fvoAPigfASivGOjpTDjz3DGSHNVxWE6VbNZm+OmxKnBGFmFMRLNPmz+o9tNhRH/xbNhapwen2ezRzGK+eHPRkvY9eDQB2Ff/uI26jysSa8m8TfGdaWBrEzEOwKBekE4LTV+Lb43wOFJBLIOqxsXguWSUF7MIfl09J32kI/Zp0fGxZBPdd/XU0fGYHBDf9s2y0nRKOYTfMP6jcB0MAwAd9P7a4Q3nxBKuSZjZLxFokbvtGtVlWVROy5p+IyniEaji2aKgCT2OgsclWASNu1Pgj9dWGoQngXkyN9sTERQ5FuxN8H9uywZJSuumna8pn+wsJB9ZKZ+4FGnSbrlS2ld2jMKPDYYt/ygW5lV8QqjIBw0qZgZNV6qlVteI9fPnjcqhfB/LKSK5hgVdyT14ZGr+5Kmu9Gc3tmzXP1ItdB+ZUdUMlrs6iKHYZBbFjuj7WCdf1yhbkeLo+Rq+AFQm7nlrFqNCeE/XxxmNQ56apZJGtN5SR2WtgxrAkiwuie51Y6qBZQ7g7uaD/WCjRr1wDWJATVilV86nuCtXhUked3J51LdZV3ma5ErYR6Tw/L1wJT+UNgjLn/bwRq+X4zJqSUzGUMv7U/eXF+pALlpQW7tqNkn8bi6Gdz3uG2gNduGjIMIm53rLmriJ3TOGmSH9OO8i/TCaTmJ3Eg5aXPR4ujUD9HyG72MgPoMofMIvbzLPgcu4NnaJCkYiLE5icTc8s6Kz5NsKFGPEJQLsnYj5BtqOS1izviI1ZaM/+qvDuMOtPm/Aa0RgNh8dwrCFoHUaEnvcECTbyTLirHef5YNaafdOdJ9P9V4y9tjWpact3aKrrD94RNRo6gffIacGM6PxpwHoKaJicCWmyN0LNABoQ4TbX2lRhOh3FozMp+o1QLYACO4H8orIl5WK+u3vf+IwMbS3yu9BpFhPpdj43zgKdi0DGU/Kyw6i6rs+lUo5tLx5zjbykt1IHEPSJ4cpujEZbhqnBDCTAyVuN3Ixnl4DpIGivMRDvpOoWCpBvod+ZNf5aJRmLlWBkdozqZPpLbp/vUpvAzAuToCV2PN++g58FIjke2mN7ialusJR3HR5/8bwi/rVVhtodIkR/pnVE99/7zKCuMuRE1t8rBGK4PWOTvj3/uHcp/8pr86BkCYwakhtl8/XrZ3A==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127096, + "Value": "122755541281474075", + "GasLimit": 54210153, + "GasFeeCap": "1291271028", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4I1kHgKPvHWdfqFlGlTK7M3wetpAtIZNTxW2h7BwvNegxiOckj8j4VnVNQvMV3ZhfHKpU36l39CDJRGwRUzqoZTsuiEff/g+ZssvHDUGjLXKf7kCZwivs95Xx6718JsADeNEvJBQPrxmdapL3o+bUgmpNmJcwxCmmzJn5gEZ8IOCYT3LIbE0f4QLG1SmURzoV8ia3QKVcmSMf5PmqbZYaAs38Z/ZjIhTKaz6yrOfcOFEjZ0A/7ioWL/E2/rAXqkz4PFg5Cpl8Qdz1Rz5CfBTQogNXLZI64+vF4qJzW0udwo3W8g3KQZjcckoIh+XysK3RPm7fx4gOpQUxo0qhuuw6uBHQrDEX8Ak+QWQuL8Vk6ungQq7wT5hqG5UmpUrTtKoU7EppShWqJPZK1UAS5gtE23/A89MLleMno6+BIL8rizfLhuobUrG0dc/9AAC1CKXdYgo7EoFKDU+KPRRJIiDnv/oGF0jEfyzfDUO8/BUk3xgMN1g04mZmOX/i6i3ZzWOSEza+DZcr4e+S368jk3YmEqLqhLmGfAeSjYQzRtYsnl9kQA/P2HNDk3A5bbcHh99HMWnHm6Q3xLNYGdqgr/D/ZwjrF6S1v9nFtaSuaXhgZrYVNQQns0v2ysSrHAUrO3jVZeGbfA3o+Fuk1DmiU/jcBMLCbr7NLJFPog0zEY2vkKaRSJzk5RbAGl7itZu0O0oVHpgFP7DmGPXMHWyye8Y+GGjC6afErirVRN6zS4T9wGDnKHX2V7zeZ6UTTV+e/UbO9+c2pq3bGH1cWWeilsYlg2gMWaZxe4aY38n1n31YNn/TdVCHWCB3InLkjAaIJxePB+dyeKp9VH5Cb4EeVPSTYEnsaDQ3PXMCSHglHO9wMAKU4xG7skPCofdCpeQmKgv52O48PAxGnXf4DnTH4x6MiCbVCVe8DQEhuHKQRvEheFsJBoFJ4XLdgLhZ5V4BEI1EZnHTg7Ko1vsed8IwInpTQ2Oi8flBgjpfPUBhCDuQBNWMoi7IJQ0Oq+mFZZQTgDHvweYDeIEZi3BNas3V6ryEF5tycLSEMw287XfwyUa2GkT/ctXW2jqVk9aImVfGjw2jQN+W2pagNo7mYyU8RK61MEh5A0W36iya35jIxpkTta7BY5XirMvxH84yAvndqkhasC0sXAV+rAp/SPVmN5Qt614bjh6inZpKJkgE0JlGx9pzN0TruOkBrwRm6xmUGvVlvfsH66BLILgV+rz8wbJh4GTXCa3sy4jmvkTZ0WX4/tSIv14F41iOoeTlFwNFZi2voV0f9JYNIbsFsXyiPNScwZayOqpPML6PCQudpN/630ki0QItcCMb8bEgwfjntMlbSs/1qYQbXBxw9kvXtvS8BSPuaFRkkwlySc47PguGsQXEeI4gKDevgbi7q7PB2wCYm5TBDhU5oLCzXwa8EpgdaeOwJOapBDz34EKiPQk1PCjET4/4DEPU3M1SJyDQSRELeYUwiYggo4T6538d0d2L9Gw3lPPmH7t8QbjUzXGj06FgkPS4ywfTc7R1xNT0nZJfKNUpqLbwXKhIxvf/v3+bsnqtIkK088xawHhxe3bic8Ee+7UpLEuie9+TGpaGBvmMvjabhqCW34CBQtj2BtPkGmYj911Y49Dtzl1I5xw2dHH+fL46eYnGLKlln5PCVpTyF7TRAgxRlpKMME/QdNnMIw/nc5i/Nu2fWBBi4RQlQ2XP/7vl6EpVPQUpE9/0EvH3E9jvgbLcbW8/UjrSZsAM1AwSJKxu7Z0F0TVEa3Z0CXtiTIlTXvIEE4h+IctslSjcR8Gct4WWfgK61/Ga6SMQTmSZcDJjiOhOuB2Q6k0XD1ylbf9YPqeeVJYWVzpkZnMahIrrxIHAtuVvxYUum03oe7cw0UbbPB+JSxQd7wcaNT89VJtiv68gtDpEr9A/Bi5XXmmsKgjJH4bOYZ5J7RB23NhaxePtYbPzsDm9AEntT0IXmFtb7wNDUUa9btt/cQBcdjA8JqFTB9v0Hjnim/2vgjE8hruPrwfK4KQylnJWzby9lSw0o9bJPQqS8j4p8TwZaJ2qiIPUNMbnESYD/q4y/N5EuA1vGvFojHH3iOSPuheNF0MSw4+5YAQJtmrLaT3CqHN9AKvd3niTBrEPcj6QEk8XgebaIGvRw1UGPltF+bTYCLc+fyOrjJoZ+G4c4LkZreboaQ1SDM1/Hb20uXmohV/sRFhW2hUeHwTP1h7QRsssKBPMKINl3R+yK8cHKPXJlKTzkZUJ5IU0zNmrH8i7poX4r0/QnWk4VOIbWIR+KyD9VflWoGpInb8nUm87OX48mZd+u5nYuRinFBYojzAtTXBPiaJC00CCXmMOHlrPEk9rlw/2whmrWo1aSf7u/JXSa3tKcZh565QPjt3THnwlIBt+Ual2sqqe5ely1TU9r/dKHbFN6k17tsDEySJqrKPtIXJzUQtiFkiqxF7c0dzVi7ZDVBYe6XtHPEHeiTpEf2gPvtZnmIMiulmF5sh5jM0kAg1shopDE9YnTYhcQIR31fqZmROR+oKbVmpjSKoviAwt9gPbGALN9yjHShZ7ZC4gYHJkEQ==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127097, + "Value": "122757959054991489", + "GasLimit": 56822653, + "GasFeeCap": "1231903058", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4O1kHgKPo4fFI+ppayYC3OMKE1o09ZvRqnhei09okkU6KDxQSG7OV46XKyeaiNXVujmp/8YnT+jyRHmeDBv0H8qfwbwKTachKcqZ9POXyjyOxXP/mq0qFyS/UAgSNKpcrpd8frxPmcaR5nvLSQ7Y7t8aeBQpMef18ddEua/b/bf51z/IfQoackspSmX2qMc7JPkgsN4+uz6NCBauV4UBSdSTNj9OgzWP9FgYUjO+7PRfXZXcq0ioj2ihhbvHTJTL87xzH2beWYWzs5tl17IPeBYltte7IwKoiHyMDqyGY6NmUX5XFf8UQTMdhzU52zNGmVYsuI5lzFyrlITsGh3Ve1g1cToe41SwLWIgF5mRzL8tTb/HgdckHFI7cOTFw4WWDOcPmBAQiICHwohkxxry4i+yT3NE8OMX7uJcERSjUGTIo/L+bNqoSqKzm7iXkOhgH1/uAiaB8IURsCWU5r/q6f11d2qhSaK/nkmx0BHTQcHnIukg6npidcynZIxkV1WWQponHBZCzgw4Qibk0GF27U2K0bg7g2BDehXCX5rqP48JsEcGyKvMK5HSayNg6uqhzEX9FU6xoWm0LEy2fsRc4DnrWH0yns6ucXDSOwiWB+OqsJJQhGE2Mzf6bIZP5Xj/s8rxWuQXJ6slgHbaRv3TjuQTxRmXyZJcYTqyZqfAgEHcc4f2cY/geXF13VOcP0GUxmWF3QqUaZc1b84hXs3yWBTYodxP+ZHyBdsA6/6nU4yy/7PMalh12CksOhKMwZfkEvwOFyY5/fnBAO1dFqqwUKIKBS99YG2uQndTe/zDq8S9V9c5hdFabCiXgar8IcBudQRWrb7N7R0HL3rMoOuZXb0WKbO1uY+o0CBIbCzLrgijUsy5MxBN333fdGtkCPouLZtbEVAaxCvTUsCsQAerKK7MbwRanrnIVG0D226mhv8SPljQZIjHvNfSeRYM/dELsuvhES7jUrtpED9eEaleq31/8sM/tG8vyQ7ozO+MW1OaOCYL8pEJ51Vlwb2G4dQefx5WuDaB3TeOrZ++8pz+rIIMXb+sEXo9e4abjaFyna8JDwX3mxLwaiAiZ2VALKDewEN0Ie7Cs4yFMUjr7p3c7yMUlxxJxgBXGNSGJstiDLG5Y+IJ0vc8lBE1yy/m/usPvpkYSbQIP9TLfOnXV468yDzt7DSbM80mLuC0c5F5ZtWekN8QVoy+LBl0GpbSJiQMtQG9Y05TY9innJOALiTlgA9B/L9ddx5L7H7t83fHlYWYWrQQWvNPJ98WR0+DzKYxZ3E9e4rYq3EEbZu3eS5trBVYY2r80SR1qkPT+8PuOR1EMCN68ZNCkQAifvVVx3naWXK1Y5bNrvOoWAPOlnVyB5Hlm9W8mIl6GDJOxZpMl5sIlPLqs3nwOZOpXZ61rVEtCJ3w9kg2zhZq9vO7sBR8Xv8jwVoSN9NkhKo45xTTb3ewmj1ypZW/kjbJ0Ple28vop5ca3JKTU37cWy9icEl6pJeuJBD4Ci7LGswoodyPTy0cRUvW4kWkEXhWWc2aUHzY6juh3t4W05N1MzhHSh8hzjX3yudbWvlU7uZm5VLSdvAsmCXRTEVcXxlvwtjzzFo9lWY/Yo4fox+a6lSY0srpsp2Ydh1YrustnboTLLJpe+7dLOWIoc/YZC3ag4vONFn19YxN8shMzgJMMl0l0DWuRNOEx3yoRY53rRnsNR48vXaJBF5PBppSUflu+uH+AYytIjEq07KEHTX/uzSveFcPiwRNj1AqZzue0dBifP3x6YH057MTy855g0LBqFQtCC3FD5p1rjrjmLSbSjPXa/MMiIT9jyDtjjvR0H1zOQusi/KmRmrXWmSuBsNjaiKRC1T5orYZqQLNew/Wqk3znOhB0KnLFMXH0z+YewaBx9x13uC0Y9ax5bjELzk5isk7Me2zFU51tQxULXUUdoFh1BTJRDdzLKm2e79d+9GLMEJbOUcI8tNrG0qV4jzC3RELqFCgcPqlRh5XZXGfTX7kZoQGi2YHqSDQoMO64/ftHvUPcrQj2hGHv7dKK9hwGQORcvBVxDvhxMYV2OL0ijU0wg9xuWoN1mbtdTj/vMrByJK3efROyuAOrQjkS/xanvXzvY8++OIrCd5XVBcMhnZ9jSDuQ0uX9cc/ypa+C4tRct5O0/eld0iWs4AFhpgH322CoCrvSk7uWIxTUNvJCh9SWO0Q7AvKaMtlSw+qNc7EBaQfpfpgVefMWVegFe6RmIi13f8UP8PupyLZT1ne6ClyRVl/P6LS/SvFa5x1c2mPI5AXhT/ESV5y1qThYM2OU3uTykQDch9HJv69nHbtAMLCLCrsOEM0jpO32+B/qNX7Rv7His+onT/I0mzRF+zl1kNRlM4H1d3+4a5J81kJcm8o54vYm8Dp/NBOcN+p+GCs3OTAuiIlyANuBNfUo4kHhGe+bSNYXf5E0gxTRlM6btXPSAG9g1zjFhvHr+i4wYdaWT10o5+Ndm7povxZfO5RxFmCnux1v0d7dY6wTngh+pHDIC5P2JLL4YlyK2vZjQ/QrTwqb2x2PL9afrvviLx2wqOsar86rXZ6jEw==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127098, + "Value": "121193038989510198", + "GasLimit": 14923478, + "GasFeeCap": "4690595583", + "GasPremium": "100", + "Method": 6, + "Params": "igMZ+SPYKlgpAAGC4gOB6AIgwT2wh4DbEeT2D3W4y5eSBBN8BkucsOhEHQDymzkbQQ0aAAOzMIAaABOUkvQAAAA=" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127099, + "Value": "122758972752364377", + "GasLimit": 59435153, + "GasFeeCap": "1177754181", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4RVkHgJI4l9cC1FdEaNrs3sCiff2ZwDzgoqPoJxXy719WW7Ck78ZJPh8SPZDgdr5BqKX4N6l65rPiF6ti3fWo4cXByBI0zCf3gLpwWflDNTxlJZ7CoMXlkDPLo6RYXmOspHzBigNsGU1zdXrsKL5xpb8rCTbvYIMQm/WCDFfjU5R4WQoHMDOSu51O/yW28LqmJOLXaZLf3MsK434yK93GPMdqrJXD3kmMCsFjXmL3B6wPVOGn8AgNaNMyhGy2FydbCcxJAY+jGaL1+SJgas0uE8H1fRAP/s2aNZUQR9waNqWhpN/oYVi28ABk5/AR45B8tM96rq9uJAeZCBohJGPZ4G7JluJsMinhdVJRfEVuL6nQv5bu+tqw6+m1kPrPu49khuPBXhM8y7BtCpO8TAW8plIrC671MpW+uC4VY/CYkK5QdqaM7ulKqi22GN6cTntK71Q4M7mmxDgNfjE/vpxtq6No7qMObf8XgIxPOSnFWXjPmLV0tio3Tt6JSkrRod734owbL4pWOv0vdUFbUhiHcfm96dTvHPUk0P4njLZU1sP1H5nWc7fNpjH0ZTrkydyaARnAroONnwN2Ip3+EY5cP8zsEd6gIVOpOG1AxR8+gVUlcZcNZYMGyY2XlW25oYbz/ku/oQg3G2Vk2quqV6FpZPxMbjZ0ibMV9IdfKs+6NdrEpaAZV3kIbEFLcyOG1eHDkvifyaKhSI/CYtLApPC7g47OBdI7z40yhpPVE68EJ4YLynyz1RsO4pHD99VnRXV+muqsRY7jXt/HUYUSoa9gbQYl4NqkEnINnaDUQdDRI9ffx7ndnMO9tB1IqtUnbIOxqzBHbbFvt5PDTPW8whn/eibubHmYZzehJbm7IXIDJe17SJkbgeBpbdn+4uilLJp368UAegppWtPj92MkdNp0xFPnboxLhFHKXX5T3WFhV8+RXHBPiWmhGYDxsLte7wa1k9myfayLoIwLsOPJnX1FnhYqUOX4lZI5s1u+S1tZNGnT9BGALTL2H8XObkeXJ7Yt/FKeRI/4bXuF9DGp5aEQom4lMHglk7I9/jOL2eS7BFTbnC7UZsj/4scfYDv91mXDHlYRdoApbrSPVwUwCb94GaF8smnVjsMvXb+DOU5z9hnxI7jzQ0q/27PqcJIVXJZ3py4LyBCLoXxLmrAqDklMaXFCOKwKzWtOwLU9a905rTqqi1Em7Nj20MSdGDgllB4x3jhP75kQMwC6ZJq+970lT4ureqXKKROwPMjXKv6EnVJ8Bap1VkGPyI+VPiMplJQrIfE28rlEfAUddVdpLUSCYSX5312SL+5iz2UQC4+vIkSkVjc3TTCK4Qy9IrIOBnxTsjIq+LGuX6cPsfm1ZKnzUgNFgk4plyrgzYbRSgm/fQkOpeINvEbAftSR6J2fUlU58hCQ1wS/D0deSYMRVfpMCrPQQG3vxF1bU7Uas3SRBLdQvhmcp5JlhGY9kFJhDMOUNSLzFI7atzOR0mcOK/I+adZpZxqEOjhKHsLt5kNsmpXN8hK5yYyUMAZEelJjTa+rWU6hMq+byoTO4WjkMaFAs5OwN5haJo+Q8uoD1Tz9sZvFg9SZLI/ySwqyf/oC+NjXaoNI16VVsJYhIQG7HLXhf4p3kxXAABMOdxaWBjUW9gOryiRDwntu4li2nGsh/4OdJI/2oQAWeVkWq8KLy7p05XjCRm8c86Hc5DD2pBJS7/VDgRUcbO3vKQrpa/xPYBwG4OREP6KI7yxiS7AoU0ehF/jLKCWkvy0aEp+u6EnSfyM3Q5cFdaO1Z/Pgq1GOZrtDRk0GZJEQj4l7inf6XlzLMIgI73b41pN1Jo3XqwZ4xFLRAu4Rmn8UMbN8L0NIvPRBBPw4zJOv36TTQWBL7aR3TIibeP/0aDwGrYHTUFS6v6pRJRu7OOZS6w8sHMrm/bOnhGlsqhWc3X9diSJEMcfgtJMVN39Ns+5EHOy8ZXA9cye3xMArobDdS+lM1XLPM1Kqw9mkxLRcj27Rwd6JzseldWoRfh9sz+D7q5jm0+2K6H0YCVcL1QFazRr9yylBgueyn/7JF4JjrrhwUOT9qhnvnGtHlUsf4J26yGiFnyLHfKsUoM5fpie4nGlp34ZVy5njIYj0t4a1eZ2EHrX+UQSRUU36VxImA+3BQIg5oYDGqeJIRJtsVxZb9AJ9PEomj9yXSgX9cBT2ZvC7hJOHGTzwir2sDtTaspqU6F1sxMkBrm6lkts3nb5IqYp3ybdW63p2FUpb8qlu4hqDhR/b5JPlw/rAEf9T26uZW0ObvoSJ+L1lBbsHxJ/25uy91pLZtHG4q5cBYrGuW+j7WNkF+wMoJEeYtm15gy8b+tX46WGO2SFZDjkghs11HwJXvLzGbszUhRCGEYiRqAyvPtJyVYJCsHtsyfFPMGIMP1rXF3X83htOjCQkksljVKLSaCgoLy9mWbX9lhKtGjU3oEu86zY39Kd6pmK6x/6ZyF3hM8DI1M18E5Z0Nu1ij/CtntQovdVtEj/agakiZ0Gnx65yW4zeRtf5NB6zJ/CP3J1MRZEEbDfSEFJrHxdajad7NSsFxzpFJOqhgg==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127100, + "Value": "122756359815676352", + "GasLimit": 62047653, + "GasFeeCap": "1128165153", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4LFkHgIrotThDjELETIH3yy4doQwgBgtG3Rw2pxxEQQ6NK+JmMquiDnUqcIaeDUcFG55QdKdqXqYFDyn1YLQt1VPCTFEec3CsPlP6WCVcY2LfgUSJ+rZTqyHX3dPeV1MeezrcnxYTKdj7BLMEkRv8uCFwG4LfRl6a5WNrkYcCu0lJNHPD0gGvLVk9K2pQLiM1Wa3Z84jNZAvPceT3PasBmre2sUzvCTyw9z/8cHzqw7QceEFcCa+Ft5Y4zQ6VEKlnNzoiSY66tmS9dW9Db5wGnGwl05CoejYcO8ibHtSQhmeXeJ5PZ1nF0JOPxlR2Fmh4Cs1hkaMN05VKegnw5nJdOWBgZs0d3H6yzXUD2lVnHdBqqdre91MkxYOsDUUJuyRtz04A2xL65rbEqspER9t3B68XlajwwBSWOb8SwBXZMqtOncmMg3CZUqddJfTb7GSpEOxhJKUmQAYdqvSBrcCVxCX/jjVnEkxc54GzTnOjNufTR1J5TPt1XXwbxW6dk0TBoCFUzY+SMaSGLhZo6nW5AEsi9YiPK12cfhKh8Fd8c8sDBMTILhPWBMUSFybpedUa0l61cqaW7VaTEGhu+aRI4JtaJj8C0/cYwO5rIKWqydm54i9aEFjD4ezI/5NwY9aR9ncSZg03wJ/dzDA3IELabnBEWFeMqsqNJJD+1XJKS43Yz1UTlqR+giRbCC1gepJJJMOGhpG9mh+7rTg6Q29AhP5wc5zWA1s/W2xOrKn1KCw4Iu3NUErHlQNYbfZ/daOngF+IsoYnXoNftyYeHkDA7TQyOVmtI8v77Dglp93iq/Zlo0yRURjFBWRb7ra6ERcVNkjaspaoKzdyBxpYi955yJzHcorWeVKkpR0w5g4M2TnpZwfNKmltRVl4c3uDJDx02jX0BAGDK7wtM96miTj0mHUsUQJsYtOuHy6LHY6gTRzm1IqpO1GorUWrbNxkJbxnTDEviqU6ZRvlahr6GEDTvikUtMhLSyMKVFqJ9HjAoAgermOnpLNAW+Z0g2wGYSNimZxBF444XSCcZ47BSqwwFV865pYg6wpja73ofteT0ZP1I4t5kqjBFDX/ff6ExxlTfkoynrBAGMfAwrrbzVtpfKYn1hN7phLoWJUwkiTw7Jk+npxwmjyFEI3bjftoKMyxeDyWZBdL701GvhOYc6adHz8pvox6985BoV0YSJLVPPnv2y5AsRIeiGyVnBYtj7A7K/OvuIe6SEpLmX770Nbx7khwNaHgv8cPtz4V9CDiF2QtccEmKn83em6+RrGw+x7do+cGYYd5BNJ/Y0BaXFMTRGjxPlblIXhCR41++zf+WuocjPwAWTS62jcUDWQjmPcw2hOcG6X7AviOPftMtbre5BCJtZEkaDwKDLnQueDtqiSabe76QzSRuvLVH7NZ5/E3EaWldg2B3UE0g39Qv3hGKLWIACabpr94SznyMRvTEP/ddm4Yd02ZQFdnBl6XPGM5Y4dzOqBMUdpiouVU2AWqREVwtpu0QxQ08tLDU3cPgaYb52lqyDUmqaGvdt2xnZE4xqEgbqNn92duN3VqerjVE/ZcjWGqwn28KQVLlWr6pQMJbxvx9kg1aQa3QU5++wkjZtqpXbXVOmCcoi8jO5+N/3BjrcsZZt/IVxzNaMdhXl7cucQ10eED1Gp/WsukG5xRs8hmeA4OQ8JViXn6xUhT7diKf2sRqMjPWiKGCgJiXgsFEhO3LcKKyVXOwf5INFubKypI8IB/GKnlq1nmPk5tYhSZEuXnck5tiauGnYP4wZeZEfEWZCBNKD5SplRkDBVS/OZM0KEosX3Xvde1xVT6b8wX1TOwRvidWU6J2eZi6aF2VsdQXH745G8FCSSXfYeATeRl2oWPtw5lvHtClF4jB14Wq/O1wwRkBoK1iDZzbmMbQVRBKGDS06giZ6gGrKo64D1ZwAE+0ZEmwFbYdaU5+5/6SoX2SPYG47293lo/MqvRgg5YlwSAPTwyc8dPMd7MlEEjhKYPceK5r3e6EyVfMbQ0wCI3huLd0q2oxl5SCsmVU2vgY7FK4ZJNWjCO894bnWcxprijVF5b/OguSJG/c2GFTVBQ0ERrI6qI4qvtbaG4BsDBR0qA/hQpo/Zajup2hoXXX4cLcZXryXsfgGKVoes0U+B/aYFuGq/vsLMOEhSqW04nPgNvUYBhb5UCuOB3AXUTsRg9JhOx/suN0Q+LzErPHTWuUyX8V/jv0pJnwYT9btpv6UmeovJtm3WezX7pb4kxoLZJlZSe4Fg6aUxLx5zhckbrdmdrdDe1XFhzpInwwXVIpjE/DMrpKiBW1nscoqL3XrlX6R4tdG6GS9qVUfWASp8IXyagPCDKHhHm5bcdjCiW+ETTI7OeHjUayGhIXRMChI6AlCja7Rwk7nyrlUOgZATAWgVkMDAns1hsBIVf90c3op6hbBDGrG+Xyu+zqOZp9g2GSUryFw2BeoyOVLKV+9ZFmkTMn0AKiORQKGyg8C81V3wiYiBCjBfDa74jXBgTy6AgZWtjUaJO3YGMOubKLDAXcjPfI9GdyANHihLl9eMm01arQmPSIO4bGwRiFnSSIw==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127101, + "Value": "122758972752364377", + "GasLimit": 64660153, + "GasFeeCap": "1082583271", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4RlkHgIxSl5hWXAmkx6xyWnm1iW/8Sz5Ac5VmWMB8fgxTFAokifxJF7Q+BAJa02qH3/TNlY8Q3bEhroD0jyCS1NA5bZs6agHXlCM+5OYukHV0ogeSjKSikJzzrAO8ol4A16JWQAFxyGw0P0PY2Tdzv3+FEFm70Khq3IRGpwzuhMC08PDSxfhh0FCeczrWrzggOmBEHaFMcH3lKfDKxQ+HHwyBhuPUwEhUXrREstmz7ZUvSROjxFk5M+52ARaEy63c6Lya1qdi3muJSiq7GH6AiBr/853E0LJMcbrL3jpluz8tvNm4a8HzcI6trP1huKobxRA1MKBkbl65yiD1E3M6lVPVJfg2/JByS5Nrbiu+4NHVbmgsfn4f/xzp0qq7hYgJ2CtGLAQalFzoTf1TglYOu1wOznL+G+niVgyiMpVP3znMWqdORTHkgOTzgXDYw/Gd8oSr2a7Nb3cA9Bg/viRgKAvSJp/n3u2Vkwt4msUp0ok1SmaqyieA/LaNmJEkyLhWsXuTB45X72tctlljkHGCD3Kj3OKhB8vQ3qSE30vjowcrvjdp7+7aem7kIxybQDJcoUEeYIExJEFKNdOmYuOLKaEdhjyKUvD4ykGzzXvveThjpTOgn6GG6SpOerc16ZC+PmxBGwo+JdOFTIkBIYEe0kL+CNzeRlVIZKpl7dOx+/maOvtSXgyCeTukNThmf8hL9/zrNZAXVJGBzSRpJ/rZmwMqMdo5PFAeDOMk3lD06XwQG40n8s3J/WBuTG4UAk04jl45TIfO7kpEvvHBJm7ybo3NUzppLvY81vjfJVPIgol5iLCnlk27tDrcgOtR1lsJAH10FZXEsJJDDVT/DIqCX3lVgCTg3yetk0IKZ6Tta68pCB09cUyizRiL9alFEs2OwwzU2hUibAQ7Sp/XhDRLefmpH3ZyYmnqOfFMDME56AxhRZHxL5CfIxhK2oHAYuXqRA4ya4pTIecXZ8QflD5els8yVoA+yR1Rdlq4cVYaQsDyWw3fD+Nwd/gkd+IGLaKDP1T/faAlEJcyn3+ZuVVHiEjm9n4wi6rg6oM7auAhU7g+pAS+SY2T7eqYs6K7TFnHNT/yApY0a5iDU+29G1QB9Ahk12Fcw2CX2jN0v9PHPx9AkAgfoIKALqbQCgXaZr5ZhvrNIRadD9WBzU7uSn7bzXh7DKC6p2KNyjwu1tQDtp4E9eF3VWZJautPaHMGaB+U93j7ooubaEwuqeRytOeeLOGJEym7r3CwlqMF/kK8Ij5Lw1xG4Jd0uFpKYdc23fKnw/tNiaqeTnhut7f8D1JbXgzBKf/zkBnuAPnKjsHeYqINnBxKDqqjQEqeL4WeJT1jl+AjYozoNOiAPTJFBizKp+LYj2t4RFh0qqfiWf/JcT/E2VkryfUxUk4uaG/tp8/7XPrZVgQ9xet8j4MT2xB/PIzpv2Riu8Ga0WjaR+vP+iBpC6GEUfdSuK8dzmJyKrggUp5hO6nN/TqpD1yNuAYinIvxUh7c6JFwjRqNEChiSWlvzIAu+ymFntYLv8vRFSWzuYNgiKh2d6BnqH2CBGxaDm833RE4o3hOrONl2waZXHb+TpLU7nfQDxk09PEWAR/utlPZE5ZvE0KkB0qnHYBxOMfJHXLa2/6NQ78ze9unX5mZzCKfxNppPFNXV3mKifJpbuWLigPMAAZAJULRPDyp4RouU5E3z0sVBcI6gn3bNsOuR77Kc0tbIws73TL1sLCoNuHL65k974kVr8cSfsv0igzAxNNShpVKYx9Hkn6Tef88NfVuKjELtAy5+OvW84N4eyMlxJV1eDclyhrBT1r8YIAf5vwKipXaOjBHNnlAhCbIsuQKj4mdq83RUjjW6BAlnf+AboAzXW8nt2p1O5tIpBNCMzOtgCY+6FtD7+1GQnSogmwpeGL762IVZQKyKzf59J170wFtYrwut0ksRqF49NBgAPx9+qpGlCGey6daUp6S5I5isc5J4wX511tsG6bmIAZhvK7jIVS6G9YuK65ozYWQF7W8XOEF7uFui3p6kkt/54kf347jexWjz45z6nCi7ZtOeIDtMqFKxytl/gusFPCh8OI6neHLZGxhTZLNoOBxJdspciruWCwUMYKSH11wf7YV+IO+4+SUl3QSJ79c4ra4ipzW1qWln4Q3FPB1MxvV/HVmIHnyvroiHuWpZJC2P/Iq1wrDTxuqzRfQ6U/kZsh2LUQdRNjf9I745fSPTEpDg9uDi6wJ8RAPREjhuuA05jeEy64EiF5yVABIaUSw0gkdxm0eWbBn3Z/TrmGN95nxJV+Rc3JQHlHeH8MnR4fAS2hQLYee6KKebyOG24/s/1O+Rtktj6tQppXjREdwscSp1qaKEKydbgwKBxluG5XUs1g2pKB8vkMGtMXryxq7xALjsoQlKwuxbRF81L59ArXJeDgaj8vdCWZuqFCSdTwIVbg8NgFlHlWZeagYkaSl350LLcqqM0+pMnCfhTkh/QmyMxIjK7bz1scpXJ6zfxvkj1KeOI9vfLHkroU1F66Kjxk6GPFPQ4+1qSM9qfSgf65HAhpZYy3fJEqQzKAZAZLJaqdIYw==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127102, + "Value": "122756749910654062", + "GasLimit": 67272653, + "GasFeeCap": "1040541689", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4MFkHgJceloxBAdxxLgV0q8cY3sTwrwMXF3pi0DTitFK+a5VOnN6q8/dWY6GEWHxpieWLS6Pp/wcMY9oBs5qdg5ka5AVtOldlFaP5GrybhIBmVAc0pf0V0MdwKNVP5l8n7IwQ0xKiJ8WV4cQMUoicSexFyKxb/VAJ8lQwlIeulFKTq9QuiIWXR8v0zbtXWjrg+Auf4rPKWGaA2iv302Fs3BAWEMJGo6tzC3vGGjnWE+iBJjG1dwzakJri1j55KD9UM0CoArEZwuqbYO6asKa5eUxajF1sahK4WeNjOJASyE3YDHU5jdTA+U+LZX3RptXiJu5QLYeM0OGFIDda8nOKjzdf0/J5ey8YvrK2yDdOBHYGishRcY6Be99wnrMWIZd1juvbmhBWKN9RbUXius+eJprFjjMRlOAguzScvzIhCB9jnv7BN71fg5bctuONXj+TO68EPanXFbTYY1BMMzcICSF6kjIOeVMYRjFTNxsTgNSmnINclX0OJj2amC+Sl2vmPNbyyZQFYZs2O9Yf2blfqO3qqYpA3NBkTwtyH0xvPbMdV5ISl7Aa5hbbFw7v2cJued9a4Ie/OOunEYiVWoglmWX3PiNac4JuPs2msvMMtg6j6mvl6h0NJSimGbYDidWVvLwkhAZZkLYvxyUqhrWPYKGSEGykrYIn885McPOcT7JMECINedQYhzWYV/jHb3uHZ+vWCoyDB3f4sN0SqM2vkEZxRkeufYadZ5awdIrcowOu5A2Xssn/Gt75of832/9Pk069zYJzPOEd3jtid8V+v6XSpq0FkHJzxR5qJtNabWTU9Jfy8U5Eyxkt2uU6SFGvUdG9FZQVawyxuNGgaxOsDI3wtQfrfkFBJGwyvQW05q/Oe1KQdNPj6pIomJ85KI4mYl+oPxNlEInc5ARXuzBb65CXBnykrBojibnKfAK1TadVjUKrYvHZgabJKg9/9I2JAL5BlobAbuhJGdkTZNrVyVoK79Bhr8kNTd1zvoezKkwm7JN+EBUHNyCuzC3NBgix1LfYmIhLJeVL9OCrw3+i11+4QSAJ48WN4Kf+oOYSWrTQsKPRqTzUBEjxyjA4KhJzPkvNKJdT+EsU1Un3jN+G0LdyNG4h2AAd9v/1YeoHyWesBOItxwqthvyTc4oiWhNYFKoS9BNT/0nPXNl0rY8iEghP3FO/OIggKUS+WC3UNeZTvjdLnFL4zviJR4NoFHjzqaJ3Y7WOmox5kbWVCFy4LWHraBfJMJ1zzOs85RKDlExFuvbcTWMuAVPBlkdbyrv/R+DjIpJqD0ve22glXbJ034Ynu/nRFJYKRdix+t3MLzIDqOYSQgxlYZB0E8KBBdxpsB5Ig7T0U+APJ6Rv9PYpSzDwC++oGDClu6KGODhP6Ap3rqUwRwTHsog/7abqVPGIsy0ZMAa2zQjSkwI7vuJmHLEmm1VRjuklVLrmxYzPkrzupb226zcGFxr6ZavieCltJWvaOoYhoegJXNkRRVgfiBrgYfW//Cu/wc9AViCH5Onf8jt7oM6hFyFR9UVZFepM8ItUFqYumKTNIljygAJSIhnc7OJeAECtjOM1MKvE6tmF0F+S5TYqE+isbJIb3c7S9pb+5Y6RzOAKZWvkaP59qs5olsUTSsNntGHjEZc62nQzQB6YR5txhKlnNNQv+RWcU4po9Q1EUw5MhAH+GnBMKeSsj4QBHFuxq19pcbHCz+l2qIZiW0esKoNBy0QAYH9nAILaJI3tnEWqoOVvz4+j9BwQA4XlxxSCkmqm+2fOmmgsXOHPEtSrzF+X9iIlniVTb/tfd6qQl0ZYoHadEQz/bAXJpv7gi1BexRBNar1ijpj4H2ooerhbuwaGeY2MpOezxwf1ia1DyMnKZ/AmivNrrjTHQoEcKJ9mW7AgUj7L/sNEK1alq9DA8YHIvG/D45JBjRxp2A8O60PQY1sHW585FCXnU007bx4navQ8Uiq0mUrV19t+NYXXTgWwl3t+V1bnsRD27a8JI0azQrxvEXPuuwDGyRrazhdBjK2G1iIKWKJBt9Zl5KsBrMVkkbXK9pkAUxeVZ5ABt1kv0Ve2O+SynANRzrV+nj32xJOb86Bz8VtB2hk3OcnbFVW7WTmUyKK4zRQcXpX8Ut4QdZ2LOV/VGC78MEVF8vYeI3pjFl2fxSQgAXWJTitgyRb80Dcb4xS3a+LokBcziZRHYNC4P/YJUAbxpLsE2x7eJlbv7jK+wkeJh+09+ZuabonHeoAwQBV7lo9Svq2jWFJcW8PIQvwRE9SwEK1SjhGhvFNe/rSCMd+Ao/5OCkAOGiM1mmBfnea9Trdg/LTSsTJp1RezSYZSkSWYtu2VSH3q2P/f6xP9MsOCZxpLOP+it3xqnPNt6CeJXmuYQ4nqGOsBgkJObCoBe2YyZH7a+u/kpfkY1d+Ezxbc66LD1tjjDhyy6CkgCotULNVTeBO8TBFpC0EQoEE7q2jqBbUkLJZ33D/cjtxA1IlfxFxs95lSFZqI41a3xkQrT3Wh8qKuE4To4zPScDa2IUtkaIgLoXjaRyWAY9qvFttE+KiSuD9/e4nufZyRNnZ3wYXCSw==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127103, + "Value": "122759461256536804", + "GasLimit": 69886403, + "GasFeeCap": "1001625452", + "GasPremium": "100", + "Method": 7, + "Params": "ghn36FkHgLQ4+JDSWIMqqI+4d7+n2OOw+a9jU5yqgE+CmK2p+nhh2M76fPK0wcRTqtk0csnBWq628QiW+SC/pY/2SJNfDFSnG4dfvN5Dah9WclhGLnEu2Mx1xcZEBf9/0zxNypHU0wWeuWGHIisfyx3EWlzucjmgi9zo9aOxmh3/AUO0cu7Iw7xTHzYA/gZO9yvg2QHLxrNjdXzbUCCmU1jZY0ex9/Mi2vjHQsCDbPP8731n49Py5FpuZqQQa2/unMqJrgpWhapIAWIrOz7PzLvMK1GNSFKjCZEcswfJI2Co2Sy94uutsmuNHMqiNC8FfuDBmnKnhYorx8QlFsbqU2i82qncJc9nvy6EMqQ2dxfwoIW021rr590YCD45CBi/6Q4wud933wGHKppw5nWd3eeMKWw6RAGiQjqL8ujgcHxBH7YG4lEe7thKy9bcUSIavR43QpxbnpR8htVzELLcF4/tnE3zwaaOFBv3e6QF/bbFtQW2LktlG4b/XWBJtC4dfSHmFWnOsrM+EeIIlzzuZ2N6P2TGXQRkphDDza35/9E17m+XYJbCEh4CQw394YYcwbD+vvxgpZWvP35cHcWOg2hbx1jei3Z3IT0fvmBQNhA7yuJYMVfuvZ1R4Kjr/jSIN+Y5NR5svgx0CW32ES3k/SpEDrqZFu/T4a+9PijSL62X8F0ElktVp16Eq51MHqxNICRvXr+Q6JFnOpbTYgaDBvRujJdx+gznpPiEq5XgXSWNu/03t5uJkAL9ORJAkQKEGagwMGWwp5Z5Y2dOIfKJAx/BuGiFnPgA8x3SUKnvRq5SnJGqYO1c/jULikj3Y0S0AyUo97M39IdUBHBsaojiCN4HF+eutT2+Iv6R5rXA43qKkHjwkfIAqOS/fSzERsk5CnB2btDl+wsgcV9t4QB7BupdgTs6CuR3+sDn4xD1CeAOEADDhrchFJFYjcy/SCM5yIqls7J5paO07HJXwWXJZvGeot5wFl8MFdU3V52S4YVizIEs01dadfOu2JuFjCDSCAlbS+LHyoPUf8s0tuTRyS215s8cHZ5dBFpFIzb0HEdM2TECdcjGd74GrHPacjuAt8X0QE9lGortsR79n4AhJUymJuSNQMDTkrplqnmmQSGGTl3Y0M2KMcdcd5sU6keioH1JPRAnaA+IGJdR5j3XSRPucExXyU0rjlurz/5JA5kFC0VfjqofJwPHaXixQiTjrjNMdjzKE69Rjrs9Oq8lO30CeKZX0GzfGECndbrnjRKWP53Ohlp0aWUTVoVV3mALGDBuGYHN85NU5oWrIKk+tWkDbUKSM5UIyPrA+qUSTjxNlZlM1q/Ri03ydLH/mmguZqMujB3tZ7k9PQUdlG9JuooWrJpC9YH1fTA+X41C37XoGLyHNfP1OSNJ/Id4NclH+6uaM957vgpPERmgITFqPnAwnG5/XrOskRAebNgpHt1lNUumKepjUToFdfAHpmJftkrOkky/o4e7po2BYLix/k43UNYinuWWNMyB/n2huARPhbiZ9yX7q0CkICPSpFdH7NHSJCFls7Yl0VsG54IImGZ4EA1qQ+Bsu6O+Bo6gLpBAay4IAp33eSOx0nQeRTbZ8nOl5fVYooRsOpP3jETddrWftoX3mk5TSEwYMfBWTgPq35smyp6fEDlWt8FTjERmteT1Z0CQXBNgDV4eR1QNGqRVSXGHTVsFtBF3VylK77yjQ9LGMnERVdQw8ci98ZXblDrQemSPHrfstYR6ZkyO6C189/yMjj3BHl0ZZ8e+N43WAbPMKttT11sFJ1P6nCzUPEJa0MT9AbLzzX/5KTtdi7fkVTAa+cvswmkAenlXveNv01T3djlIdBSCk2IWJ8lklr2CWnYDa454C1K0L1kRD8HhPF6461lr4PCguehlv3BPFsHqaMwm8eqFIBiZwkoe5CEVZYXxsBMe6hUdyF3xX9QiJsPWti2l6uscvkGOsbdiGfEvROhgVXJUjzJspJciCQVG5OlCupXcEsOo2MjWXJdNhS6uVzNfaOXSIqo2rSEx1dCwlQjOMY2A06MaZlNkuE7ZyhFeapHWUSknOFBuop53yYDcXM4bMSY5L/V8UEbG4+vGzHgCWL/4vn/tyJmg42RY1QkAy6CuF80YqmvD5xchoRYqKqYuc0+MufR3ZIoQQJrdanFMarQ/0DXKGITEOg285yEI/wG6fHExzDX+8u2T9c9ekWP7dvwH+I8AN393MCHCD5J90XlJDuzrA+QGXSiICE1sbbM5AowuR5Fyx8HsJMMI1Khr1GH6qwkaZ55LMzVwrdPA+mGBzwuDUS1c+ZQzJmPhQ5QS2IKRlKqA051tOgP1Gg8xRWG7EzNBqqJGR/3V0MXMhoW/lfMV9kSPhNMO9lRMrrTT/gx12t5OlTyGbosb2cfu5elycSWBCL8I7CccQIolafARvqA49/tLo+DL2NEMuxcQorZof+kJ7lWXN7jOqckhvi0UP9ZOIBtkH35a1cAWaEBqa/cH+1vbw1RsbmplHYvmvbfhWeQeuvu8gAjknl08Uk1mnTvmk/S5bFiWWJM1XY/bPq6485QmTOVGuzsNKQ==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127104, + "Value": "122757766430967115", + "GasLimit": 51558601, + "GasFeeCap": "1357678421", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4PlkHgKJcbJJfQCu7p7qsF+s4LCkzROl8Qp7tro7Qc+09VARdGxSDzwi4wWoseK3Ee5yCo7lOChroCYCQr1s0CbAaZCspJxQsBrEHjSLUeVHkf3EMWl6Acwxsf+KL8d3BYuC1qBgEZsuMJFnhlEnnDDhZKSOVZDzW5wwIQybma4WC5sBV6rhug1y4LJyqpzyFxznZeoe8NPHZ1Pp/utHkuPWPArXNrCdKs8Xima0NmfYwSVyL8JSehtT9xaE3edLIeuP5u7k8BcC70yO131/+1gR/0fzUtINERIOscW9/LJF26HI8wZhpGTYKMeF/vvX4pKZU7rnCZPgm5pXtLv4uLiwKe/LrATnSYb5La8AyXh3z7Ijk2vAPmJd9yH0J/NX7LhE2rRmzYRw4EQFAhqrOH3DGIqKkkXchnfLERGhxgxrQwVm/Mm1oVfPgN6lcws7Cm00316F2XoAaPZJiVB9PHFVeb9sdVlYn4XRZo4fA+bXDHAL7ATbNQ6ODJYD6GQi/TIPRXLYB9vVCKmoBRZs9N2H9HoVU1C+awGbziUPTBqi9TocMe/2UYNs3ktyM36vGUAq2BIV5i7hW3i0mCce5b9Wxpks2oNcILe8qEdCBPyFtq61+Be8JjAyT5ikiUnc1p1PPYRSBP1pOtxhPMe9CHY+8v+u3N01UlkMpobbzTjHg36RhtBR1Vv2Rnr4cby+JluYObJX0PFnMXxoaQh2ourfhVzIgunLABwMhmprhoRVxpbAa3MhxN9VZsIl403m3Z+HWc4Dc8wr88lIg+ZEc3SXedB0rOhEf1PeaAq1Z3zf1HTs9bIUhZA3BSAFidqf+HBDVqKVsnohN3/SLNfMJM22tk+pPKT1R4J4bnPK0S3CD1h86AmbD3ErLHtQzD7wIuNUksxV6BGFUaSDFuPINoyBdj/rKOq0ayDwYj+yxls8mUv5G9oYZOqHpQhfke1ZS5jaWC47AXeoQirrdNtQmvgMLQrlpDZZf4mT2G4BhFJRzLh488ASMuvR3aAcT33jbPCrKV7Otv2Kz8rIgtLzlc8xSulllEBUczKficim4+pcMJurVQC7x/+Y2D+O8vZyrfvc2z4svwK3nhMB542yNOCHSUxIHANWy5s7NQng/FAYfEfXT/d9hldMt2Zf7w0ES+m3VMAB6+xI5oYuH6eqIlG+FLxEoJmhyM89Uf4DNxTIOawzvsUM/it2hZsAS1rhEyQmaAYBw54q1ButWONJx9zjP5xLrwniBgP7UuNwl6pU6M1FEQ0IFNhnesd0OQ4hadTXidaQENLgM6weq6mEi/Se4PIvAYnsD8NKxnzFMvNgsheUpoXZDdh+EcuPNzNtJDltKxZSatfgcY3NPLpbncEkld7l6YwRGUdWgwG1YvgdqWTSq1kAOP4rdUAIixadFlDUMkQlQt8kD27GjOJjYgQravNOCwhqYh3f/l6pVXHeyinrRMOUY6QSHgLEwoJe8AjoV7ZV5GcEHmtAzDOKjUCBC2/uNHdXj3iu3vvWnTETXmg0gtIkrM/o0i4h79PCwc1skKIp+yitQjuzgnUkjVs2ishx6L2cvy/9+8GOg0xzBaJVLg+QeXuyXKnfZKat3Y23ZsI3Fra5jHBXhFMynluuuK6fV5RaynmFS24VgKjnr7K3OoE06fjdJnH0I08q7llqPAgDd+LfmLXuFyl/tc8IE9stLyhHxIAe0oQws4fQPM5vagdqcXUc4YLWIDZuMLhU1s5NY5rhagr8T6hCSLkikl/t59+S5LwWzrhEOR4FIIdzqcvsTXM/ZYjoQYxRFzh8bOYTw1h6v6kxtjpjiHYP4VR/ihitg9YM47NI8MrNTXVUp6/UBO1q9O0iAPKAWmzbckqhRH1b2XJsYzMC2iyz4dfaipVUKNxIUKxz5soBEBoekyGPE6vjRW5G/oGwmupYrqgohVkbagmOcBcfchNBQ43J6hjqcCXDL5PpGTpFnI6gLN3FW35WWd47MvrTvM6dVHpWOc68VcYEuwhv20ZrDBk9ht9/ujlqNx8VmZoFctitaQ4VneCqDvZXHck0xJuPZaKAKD2KVAVRoIGyOhgTmdrP0GjGpTunzG3AiFohD4ZGyCZhUOFiMVVzWkKo4mZhdTIPLXsBhhCgY5zk77coaR6dBN0HYNnNZK8yTJ2BQ+ILql/45hPpPrxpB3uqcaLmgLAsDxxWa1LYALXzXBQkqneelT+bG6SJOsXhbu/zQ6Ql3VT+vnAiALeLIJx0iJuhTrZZie0H2kTbEizDEaIs+WI4vMkQ6gCGWicrlqabhqu6iF2XldS347UVnANU4humcboRhA2So/K5T3bnl4OV05s9WTFkXKQvMKsGVc5jtTsQw0P9FmraYBrQBm1cfUmmM3YvSgUYN+M3bOaSWKcTErdWqO0AwqVSCl67JlgqCkVkZVG+yjijZGYA6r9srxSnsRg6TNWw3p1Ql10QTYLFkNITmqMdJ6V5IDGPC5CytHOD0FmppqQGJWn0l+AfT2lD9VKuhzHPfecSZcSKnT9/n5CVbDQp4F94LZiIwRgLXuiWmOy3sjtzTJCo7m4fVvUaeGA==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127105, + "Value": "122753885295610962", + "GasLimit": 54265153, + "GasFeeCap": "1289962270", + "GasPremium": "100", + "Method": 7, + "Params": "ghn341kHgI5Kif7jePbSC+X1uOnkqKUSscLn/EGoUwX7M3yJkz0JCqx2ipkJsKknVKoVvaUWDJMe6Lw1t/I+yHW/gFOLhFOGjCgSFWyjbILSm7FYLq3c1V5pM5nPzccgJbXJzY2LpgXh6XcfCJmKEncu8r2eDm8j/Q0ZW5BdqLlewU8FNm7rP6og7Uh2hBij18cgY+Ax5I6UcOLDsSbm1tsU5XHaTIQiYOs2aW6+mE4nFq3ftBU34DPvCwjBiz5m+poTihV9E4RC1pwFqhZ0qPywJKgRENT+XCa7mP2HXX1usscDEprg/O2xVCOyTn6eBC979lA9+Kbj/xboqABGKLHYUgnx+ISqSM5w+7WOKI+rIvi8uG8z4qXN+8scSETnkwwgFWpINQp04Qx7eFaF5/qj7DfwJpCKT0OD40wXCzE9iqNwFmwMlSkLU67LngRqr7myLcsjI4aJ8/9R+lhZlRkxpw9CSSt6mhRA04XBumIM82rztMTmdRxBQoaZNV+zud41rVPAmrToH0ec+xbbeQVoQ7qtBgrmLjUgVAImNISISf3007MC25F9uks3U54UMNLd5oC9pIkbEKAZL/Zm2Rf+vq3IpiFCiaaoDw0PUDnahcCklPsvssQMQ3l34K1Sb9jAUOYUVAy/gvM60hW9O66V2nC3ctlK05WHDIFo6fc7ren5EmRRAeF+ZK3kHfjr5LI0LXFZiYV2GGqPG5uG9mGQFSDIg5+eDLh5qYCM0QetdelUIKmG0/VuIfpd4dVtHJbo+J3gVLEVqryLci6JO9HvEcj5g2D8C56c544s7b/aTd8rN7352qNcoR0jWGreNB/M0hg8qrLb2+JP+Ywd9IsFUoDuwmr0EARY4j+WLkmNa5yf38xw522iFBWDf4xjN6FJavENkwlRXyt6Vx1dd5gOx4w85PtVD6ZI2i6ckSgSQ1q90x29gkcSIqb8Ubnwi0/9NmjHc64cfhNbShoa9wY0KhZkle/oJyP0WY/+sRuREwJtiSwRoJIr2l4HQ4QySQxnHFewzbQkm5Nd/J1Ac4USME+wkCmpgltJp4MWbJNiMZrbOfpgnX3H4Ao6AwIyt/0XAgnWg6O/sAFmKn/UHV5C4G8IxRV95w9wJbfoOdfkK7NsGxIwl8vssL7McdpLDVz9Ec+FLAGlcp7RHldP78W0a0/wleimAFFO3WZSCYbhu9S8xAH9H7xQqQTQeXR5havia0aQeqUJDu+kNX59Y9AN6nmf8ZXuyMmYlMxQ1id/FFxQg78cR5UmgM/9b9DtARQa52Papqm2/rVM2eYn6REI3WILsdEceTtP6Xo1l7Q4apP6VwJTx4XwChaFOT69VuPY5yV8vqMifJVyryIuIT+mfWqtHDTawQCz7AnZMaC2eg71wEIojiL0SuJx3JlkoM7hQMjVwQDH3nz1rvKY6ndcYc2ck0P/QupvnMR7DXkxgo8GKdd0B+0zmcKNTQkF3XOwqhrrk5OzdEixBTl8a4pZ3s2unpm0uQxN5eG+Hp/9k+Noy0VXA8+UdP8QLWd5ZXxC0dnk/IWfnb9KiB1EnVVVxqoWzefdhnXH2ooMvs5kIvpEVzCkbSYnBO/CRbftCDr+AYcdQqrIe5wibDGE953U9AIPeJhRngtcMlJf/Z669QD3PiCBKXwqsCoau+fAQUAbZpziwgNH1JgPPTRRve8luXtTMzey6vUD0mnb+nzhisoU4t1MxVoCCD4o6M/R6ILKQHTl66VkGykmq2EJRiIkzb9IdlkhFNTzeE/IB6g/j5JABjZuIT5Av9fJw0racpglY03xl4VMYpGS6JQKSCIQWWpP0EBF7MFdk2GcV5LeVSmEgePizCqoIVV9YL+1OF/mJlt7EoXvTLlXyosCtFUlLuqfjSY6urqhnF3+MwphB3lyLgpU9C7j+2lkYZNMq1sZ3Ad8HBBUjqkNZ/tnDaCZFq3KKKE2F2GbIIUSBIAzs3F4OxnFfh5NiLsYYkgFeRJDjb3TH5TZXT5zLmQJR11PWku01P6PCIuOIPMyyYCt2G6IQjsUZjlMMcMh4l2tmvreES2LboFcTBSHbbDPjPPhtKZq/tqR6Xit5BCKamsmPchx831zXIBEfkcdayHYLi6t/ePbL4Ff1pk81bLeCBFiPFrvu44I3tZMUqaMQ+HtmUMr41aTqNU9BTOepQ+uojr2aIXyNwD5fdlN1p2Z03vboC3fWNgBCKMwbkELpvwcYO+1Yx0s6lB0igx2Tceh8gV8/WljNJTsw2PSU2fEcQ9Hz4OcYzuPUfxsUlUt8o1Xl2bDQnSbTJH1P/9Mq0iwcIqINOuPvpYYuRMQDrPXjEAyXqTP/Isrja4PEg4UQILYnX3liEnaetTMPZEX/g1IJYO6StaLv4X4+SBwClcrtRzU6JkXEf/O8vqkKV0/+rNSK/C6wMeql4wEsS0JSPk1XThPJ1g7UwNwQwF49hx2PIp/tJQwYG7F+g9EK+G4tqP3iAn33qcB4/VsCI2QQ8znqkGupCzDx6S7FS6crXeZFc3qBhn7RFDYL9WkJRXwHB/qwTvslWrx3s6eePMCAAQRZKBAOgVQFQ==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127106, + "Value": "121193260185693775", + "GasLimit": 15160978, + "GasFeeCap": "4617116389", + "GasPremium": "100", + "Method": 6, + "Params": "igMZ+WjYKlgpAAGC4gOB6AIg40lmdZj8r3lTQoeRg7WZfYR2HetQrmc6sSard4uY7mkaAAOzToAaABOUkvQAAAA=" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127107, + "Value": "122757299618655422", + "GasLimit": 56877653, + "GasFeeCap": "1230711822", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4LlkHgIHtWDxlTWvkhI5WRw+r3dFmTA5nJrel3PsCaMHJDWQgq5B1yg6DvIKIauBl49JdR4t7UMFs6eWIvkbfYq8mtATdrxf54jlaYPc4K3YQIss0uoAkIv3ZbtTIhXd9/VMmjgoVsRZ4XaCZuXw4olfQvvKlK2+iOI74R1o2AM1R2jUEe3ZvoiOpZcEDpa6xXohTgYS7Gkkhjnkta3Y67vCUHDSVx2IhX75n8NnqLQeBkQzXgB91vk0Uo1nXONd5MTQjeq/efvyGpcfDXVIVijk4ZC7x0/MZ58e+GOUifBFCp7nvzL2ze7bYopFYShIEBCVTcIRgLulD5Wb2c+NwduhKOxcwNYPUL2/EeHjwSCBbmg/vAqaHPqKQzBqeSK1iW6FCPgPZoqx24i6M+lfmpDc9yYo7JxcC0Tyeh11GXu1/KkmjXVXz0FJ/ldlUz6vSyaa+mrm3XiyRYSrHSlhwXuxlY2fC4cumh2aH8DxV9I+sEoyt037GTUMQMg2bPV3Z0Wp3t6ht9eGnpKezd71ThUzswM05tBvp0gEf6ihLgibfhUkEtHu//eXhK22f+vlDxBKc9aCxZltndLJx68nDohP+SWStpCc36EGW/opfEY2bWor9treMTzZVbB8o+YNJoUPStAf/8b/cMR2pEZPwrNHEdKAq+u0jt8RNPZDITHviuKytlBPOq7J/WGroJoGI5q2vTK9HPvCbmCbIBz2r30HAoSYflPZMSTaxvC0klfnae9NCN+nxIrp/xB/it4N1syMkH7Qc6/1Ay5p4iCv5LK/FlyxmvWQCovbw59XtT6LVZ5r4Ce9j+CCu4xG0XfvMxYeJi4xWcgXJVXNSh0shk3cSYPbWITE2dmAqVzgDpPxfT+5wDIuwXW6pwb4Z8RY5cNgzDwryt+q6S77K58lwe7J6bumAaT3ThCaL5eadK5Ap4TkncKTGevwYWWEZ48e3Djk4dqgUki2fFZg67IPAH+kntXBKumPERYVmEv6ikpMmZvaWwFaN7XbwK+GS+N2o0j+RaLCSi//ken3wikVDy9g6otBjiNHIeyUj9W+6Gq18ca08Y8WoebOZu8nAzilDTwdKrIFPcPKNbE1wC+vJFrvToJhB90AV5mth4gpGVb5lwxkAqXC46BLXmChYURO7TIQv7BTdzBScbqdP9K0Map3akcCio29ryVvnWs+C7iH0fgnmuPzl8J5c33UBSNW+Q7gw0aOVdN/kDMJcOls5TvydItE5azjs/CnCVNAID6Xy6f8QXu8dUo9OPCQf1b+gDuxCxJKnoLYag9UljTtnM9p7JzhThJAPVrbACaDEpUwmQVoBJEQXZWJPCZ2zB+ikTUM0X44nZZSVzLFqLS2nY6EsJypwhGT0w+J6GR84BTg9UP0H9MODOn22z03oQfMTR8tuXgVERMmG10vDr0qbToYpbrwJDNL4Rt9GseCL4xu9i6KSbn9qmCrdf1aCVs6tNwkEAoyEVuLZ0CHG9pQMjCwgkDJAJBPFVLnjjH2opG2FIrGmSVCZ+qerEECvfdV0+8laBrOxmo4iO75NQliMpIHZBte0f5Li4Oeah3+whXARVf9dKuXq6w1kv2PJJGgNRGK/7KUy4+cCC5tryW6k1L9+iMHt/IcBXg4sFHgf973KauwL4Va2cfQrSpYpmszY/lP36Blu2XirmhSdbPG3wM4Dlqx9DtcZNLwSao7yqkvzMkz+fjgu+i89f93FZASbcM0J+KU/D36+pzjnulkB8ogJbX2PGdTvxb9Sw11wXXoeWyTOryZPNv5itFgWxoWhcqZXKZVYVvlRY97DO9o5z7ZBV5jWBSOLsZVQYqFyf3t5Hjj1ZhibQyavTgxu0ojMW7hyUYwGjiMV4KhRIBpDOhiQxCrnhheJ1xW4Yrs/ySN901pG7qUD5ybQ1pVbu9UNC74ONw13GoM9w+bsfaKmUB1j/BA5KhRjJaj1qmX43ARmtvXmrmMbZmYp03L6PWb9S+wP15A70jyRCjmEvRR9c7Y8atILnJo4sReEUORH/OQuKp63VOTx01rxHTYDxY9sT0UlgJk5dtrl9SNXGYVOVZcRTS46KR5xp6qPo0hGr0KKPvV1YeQwaHHYuk1gSu67QkDhSqdLgOxtamkTiINug7aBX4rA0+CVug1DUSH3Sxi2c8a85IM5aznAE8Fb9igoG5z7GBehlCfm7Oleope0TTknb5fLbQAc4aBUk6bXhquNdbXggk1GYwAHDK9ElXqI5ODr36WNA7LFCTFnt1iXKDw9k+sFcPxfxqAFWT24YtFwdGGOt4DMdNwYwthMhe49+AstCYQ0m/IioBNlP0+ykvD03EqqqBy1zn3SeLtf1oqkoYtfe9ZjmAiPPgcfiABbrOrZRpkp+jCm/5I+XfID0tpYDp2Gganu38iUtkJZYLLHsZ9emg5USuepVBpAHjiDb6/prRVxL+j7ihzQSApm7vJLjeHpOW9Qq8GnRHehECIkNvIHbNkvZjLm5E2DkgYIRhl44aRdZY3X56vTi1LrBI2jxLBWv/e5YnwEFRPIVRxm640TYm5Fe50pUoY+Fd60Dwx48w==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127108, + "Value": "122757299618655422", + "GasLimit": 59490153, + "GasFeeCap": "1176665321", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4OlkHgIYx+84UF2Vz41C705Bw8MT5xsi8E58BBpEca3KtVFKJjZYLFblu/klOaImovsjiZa/sRYfVP1FhwEdLILLpO44n7ESLtn03yhwhAo9eDhusD57LI1AFkWqJGs7ondb9GhOz7LTkcfm3WjuH1V1pBXqmG9FVtkwb3awUfZK/vYVcCh1X5pz57YkR5CWe3qixcZn/v5XoCbKpD9No55NUg9eBdOunW/7C3iLMiuvGgiyjfypSZHZUHHcILvPukneJBqaGz+j8aDus46vai7gWeu3L95Le2DXtVIlgx96AAo8M5vsQbPnvM+Vxnt2pED97Q6HpgcWkpBjYHh4XAUI7Zmk/mxuNgkWR7gWmZ7LG5i2kjiz2yVg4DlXvvTtHF+LgQBbhts56mIo6Z97nL7LjvWh8YysbIPpegrTrsF8wuGpEKZOVX828FCbBYWIZWkusFYdZAtZrudZ8QL5/1gwwMKCGbNfPhDYCMN9utSmYm9QxApHnhs1/ZrxP86vl3fB8h6agD7O3oGNujdfdq1LecBkJMKd2o1MIWc/vr8fR3FbuB09rhz7ZykUq5dsdqAS6nqPUnrPejlgYNgXb1gozz3IDjbhwEzTMQ1cUh/tbMeSQXBNGI4IC+hi8jtGVEKyIvQwyvnXD6xbRXUHYoqX+lBHSmjCxA2VWADSsdlNAP+02GB1NceIirZnqB0mMJP+h6K05Id+q+amYrhmZ0SPYgRTWbIscbMDQopOfWSakfcfjzLK4NG4w5HQZBGfImVmD7qKBfvC9gGwAnjjqfSnJ6v9+XzEFy6zE1L30K3SsgcbV24RgNkWBka6xwR1Lt72VZoaL2EAh5EAeGY6afKYtZKhsqr6pjzKdLG2BVFUppC4OGWcHp9+9a8eFWQlQLzr2AAF4LlMpKw5LHuxVzD27ymlSJWd9B7oKOs7XQ1qApLfNjgzlXJEMNbQ6lwuKcs+Kkap8JrFXRLX32e92iwuAFq0pM/pB7fUWdVhFZmI8erKKQ49EGG8UCt86XjmeEebw9bSEk4tAjBBGlG0VFkpcuW4GaA6AKqkj6dC7h+ku8Mj2YdFlmSW+PhX8gxfdC6z9BIVQMOGFITPV1XYaeWGeeTlMApPRCQ78sddfhPf9Ouoauv97F3J/yXfYvOp/x60h0xF9XlwhuM1q7TjSdBgONJU1fx1iRC052vUuT/5wUkDyJ+v8+ZyzNgMdBCwrU/Rg9qMUzYPaiIsYUUNlwj3gZY7AyGWRSf2gJkJLNko32ZB/IMT/o4vg98xq0q60DNO3vIXoUj2vzS/fe44a94QNRPcqmKB3rZYN8i6Fwmkp5TG720u8K7bB7rEm0aZCfDFQU6FM2Yf7MTAsvFH1SNtZywdPNqU/CsWKwmsuIYLIIJjXNy2wuWKZ7ohKw5fUOVMCxxDlGr6rNNuByVZuegz4QEKXCwPss7zQCo8qHN7T/rnBncMgb/KvZgVqj01yDTE+W6h7Xbmi44Gt5FC3g/3NMFCI/76SIsBUwEv76zMsLeSmPzwEEPmLob/KRjF0ahCLkpEJTJIh5QAR6egfD21OReXvufXGyWah61Y3Q72IAjkGkn1FoIOCwi4Ol8pyEZZdZJaVAyqfi8P2E2X3pKA+2nW872lvjPullpGN86BLzNYsoIf9GRA7Xgy0oTxP/1nzSAXD/cn+YrwH4jm2MI3ymARu32ZcLiqWF5JQBYwtqAR7mIIfmIgaACIQY/ckIKBkaba1btHApm9PHLyEtC0+gvPjUFBiEFP/JmbjcLHrzUqD1chLCjquFlCZZllTkw4XmodwrPbfS/pNtLpTUddiO0MX/sAyxe758j/IXfb109gSlsYlAB7LzW3jgXwSMQehVJTC0xVYCl/dXOo3DqyEcDBMzRWaGZjL/YxJ4zJjhvAPm2EAmdcZ01xd2Or4lZGl/BfcMSq/QrnYRZeyGaPglw/bfqXrTRIXaYfqCAH2vHQldGkPBUiXaXFNa7aE0B21sKUlIrizx+KNzq9qQrFFko0S8gbUXjKSWmapJ6uUhwA6yiRGn22OarCBlDtLN/MIPY2bNT75aiz8B5ii3KOAUBRCwc9bZ+k6GVfIkR5mAwppFsGqRxEQ1ViQi2pTTU7wPrC5226yyvxrB/BACyspuVBi0KRgdfIM3leKt+9bh974DU6Otc9ZBVPLa0GZMDFq/w3osJl7r/b5Q5fV4IOBKmL5YRQ1aOFa+WFKMIeoj85wA0wIY4+UZ0sEoaIbExtKOKfHQCTrH0Y2SGVftrD311V2j4Bg/k6F3LAzHL2qFxiXu0CvLK0Ui9F3vbcr/HAYE6bG/LBt0vmMU4gczbHVdmzqPA/4BFf+BYAfQU74Z7PD+4x7qwiUb0YxuinZ0Y6MZ7ayNWSPcBTHYq6HztCU8E0SZm6SvpT85rff7h9qCU5eySXglYy+tjTNChS/0qK9VAYOCvrNQS06vb03hRqV+gglO8UTDE4m6ieZfHL7H1hX+Cx6FhUa/fW1M1PoXv7NRqcKFd+wkaRnOMf93guNYqft325JdUGF5veX5OX6+VrtdnY4iSewe/nccqxcp15qqw==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127109, + "Value": "121193260185693775", + "GasLimit": 15050978, + "GasFeeCap": "4650860562", + "GasPremium": "100", + "Method": 6, + "Params": "igMZ+RXYKlgpAAGC4gOB6AIgLJtI/DFbSZ8C+/mEbyXFSJeCmpxt1L3ZmlmGRRHdTmEaAAOy+IAaABOUkvQAAAA=" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127110, + "Value": "122760563480110772", + "GasLimit": 62102653, + "GasFeeCap": "1127166016", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4NVkHgI8Xonf1f/DywV6X2iwrtAJmmc6H0QAGc2TYE48tRNFi99M09hZ2TU/qc8dwoEa2CK/uiqqLkqVSTasgThMOnM7AWXtd1QYMdiHX1aAvzRHzYLwNR7Jb/ST9TCFK5V5XHQRoZT3pSmsl8ld6V/s8yxXfyFsn693NXpBe6sIPbVkwLf5lxI935P12wP6ZJdaN0IEMa7mTdqNlDyQGC2e94qF3cf5vjZNTPc0oW8WHRdYLq3yMJ1XyqMgPQNfFWXjVoKocD0wknu9fQhxSP0mgC14rT3h9orXrnn+fmvjMF0RQQnDyk1MjAHHSzX0Ra4WFZ4Bj2YxArZOVSh2MRlGX8z01rQGc7eRDwTj6v+wCq5/Czyt6bqhNo14vn/y+l45PugK3YyeXU+5VtAm45FdvsB1Jlz8i3QCR9IeY6jcvxuhKrRnQShKWRnxquutljSFP/ogyfQDdM8NBEmh4HyrTC/wxOl2MTOWrSHERiFuIaZhAS/sKrE42ha3EeRJGe34tR5hxMsUHA6VbUz7utOskjBB7QUnODJMxibK/Xe1HHI56SifDmP3zh8tQrpd6/IWFJ7aP8P0P0HQGycxGwv+WeoxAn7FFbjr0/bbqawIcdngk4LxJv+fPmORYJWml+LRr7wvYZt7AEWKrDM11fB5bVewk4FOimPGNxV3TT47Ok9b+pm9pImkFC3U5yyFz5XxMZorjY4xvQnpHt2xDmfvUs7rZCH1+UCG19X9R/m9DTAmpw4F0s6nvNjRpgrv/KRRCxZCUq6a5ko+CgQ3McF+kFO+1gejzKP5DRyXsNuBv1ZC5eSC6LwMIpcSuzjsGhrcOkYmheC34s7AAo3Thd7am0NJldnIJTbCvdaFhbarJxAYD+mkuN4C4+UfdW9/49SITQQAeZQUNjMkEny3fAyAYU0D2B8wmRjHiiKYhjvJ2ztOODAuzuqKw2MYaPgcq23OuiamDZw/CVSL9V4QasDrC9o1zLUMgvJmDkVhJoKPIaK2ja7BO7eO5Ebv8RQww+qOY+qQha1C2sg18mS0/j18Ij5v1Rs9kISVBb6pXB/QDfodJCUuhcZm6vgzYDgld5zk8w7HC4D9+EwEej9ziW7Yi0N6cxG9skCIgT4B8fdWTgdEIS0bAh83EnNyPrMnmbHQ5qhQpOB50oC26X1qmwkBOk20zOb7VyEQ68dFMGQemEMx/jO3WnKmbgNepQOaH3x9NRJNX+fVhhicfNN/r0nNQGG9NbqcNJGz4qEESy2OSjuhb4taN8XMNvOlUjsO0OqWD7qgtXK1yMnjzbo+T7+bx4TwOUU1NjB9f82yLuz2iLv6ODFORiS3dJ19t5s8nwoCZ7ZDZCttR7xp49JdWskKbKosSBbeYF+ZmUJuyDRwuehj6Gur6ZF5FFWtWitD2el+GIA800+IJGkrZNmLZsTpAl+zf07+Nt9HmgQadWaV9nGRC8qQ1eF3Jqbzl6MaCGoPTwoOwPOhh7+jS4fOOr2xb6kfSrGyPK5S8/IBwnCihXhISPjUuun7QmLmSvPMq8UiXGbgUj+ptGSRAvrWx4MWVIQdXrRwKhga7UVj6yj3hL5HyKsER1SsR/nxL93FdGzANH7Tm65aXTQeQv1Civq5fFCasMn9hQSDaGG6HWbW+pYIsH8PuLNxXr6gPg+GS1AZtRgzpEnnEqeKILj2wZqZwtp/1kJlpIQuDbdKSxDYxD7qAU60ph3ocGQdD6tosey0ERanKKmuXLt8SinA0jwkRvv9j3v/yno0ho6XTf7h/KMF9kosiN8/0qpM0ypu/ProNM4wWLm6VwiWJ2vwPmhcIFaBqoUbkEw1cDZClgbbA7rnzeYVq1toDC8NJdgcF6mKnTLIM+xEUh7+THslUlBpDgusjFN2K19+JAK/kl+epepSMwlQKFTioRW9/xMXfn3qrXAbZeKIg1k92Sq9PD1NKVWNRwgcKJR99uMeZ+MUeIjJ+xksOedP87hDfAPPjqR8sQYHKoBRWPrrtsaE5o/yYKv0bqwctNj2pqZxUjLPY41qgnAJrYNYis6VcRrvRA/NsSqMGz83WwqeGjZYB+AazDR6KbJpW7OVZqHGxyMZneHtM+oV2/YDnRAgaTyZhGGgNUbTWHvQh2r0g6n9dhRssAqG4Bd3PXJsT42p4hDHfGLddDBv9BhmrnTx554kpqGg5sw1+wiOWIdpl/oya4AAVslntakynF0/Jr0Opg/kfSbd4KkQyuHnjj2sAUkesFtF384OLnlP5fhhVWSnB3EEq9PIU8AlSHjFRChhOyUIwnDqTCaS/ncXBovg5AmOSDinc9q9h+sI0Vmh+XnOgqpfqPO+eoykFeJlaocVwmYxkjZFuTSuhMK2I8PDxAbEdrVmju6QLvLsRtFQF3aZhXMOPj/j4iL9a7pX6FEX7cixygmKeAj/iGzmY/Ga6rdjbohvX5wvO6AR0fR7n4Tpo7AmPqnsFoWDuGrfZBawmniU3RGMDtyrd1u73q7+2ywpkyhwx+6qdit8Moxd1VDB0eZbfTa/B4IUZIwId2bJyjUTZJNaVBRqADi+sfK+K1bdKWosI6g==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127111, + "Value": "122762095018351560", + "GasLimit": 64715153, + "GasFeeCap": "1081663207", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4TFkHgJdHYKXFoMGt2DLaOI1QoW5f22NX1Uefd+WYEaWktXaginE0gkL7z/Yc3mkLTpLGHLcH+d0zVOtIamTgomT8nF/dDBbhshVJOWe+rvnLTko/pUWIaq+qffSMoSorJE/BCwkAa6JA+U0nbvuvZLtsWteY9bTRNudBrDhIiNN4z3NMtdq/97nF30/c9C1wTsItnK/yW0BjfZ2ju3oRIu2nBGlNGMRuOHe/J+U3q3kqqVFgUW4nqWbwTnzQCMmNG9pNYKJh3H6QKBzq4lFYgjZe/w6qEI5mmUfsDSGutFALsl0/6sEl9j8nVPzam9CzYKiVTIh17vivllmDMqvgksEEAql3yvCbaRMfozyZhK1j69VmIGYeE+IAJTs6Ti2SbKXNGgkzMmPRssALRQU6lL5fVbNMkXLkR4TQADd9hMxy6fKdeQi9n12tSk5vtwUXA0h3bpGkWfpJ0e+cV+pXJUOcCWo26zGdRabeM+l60qNBS27Dgn/k+vetRZCPz08ixkg/DoEaVbix3cX7dgrccNFladKJpY6HI0k8sbscwmTzUH5iGCvU5Zb5OZ+HHHGdZM6hT5SsNj6Sq5ozfUTgGfsCSmBV+hf1GJ6S6iD8jc5lEyE8QiaGW4l5YUk/za40XV5Y0wN27GQRNZw/GzcVPI8Aq0NOfKlvO2aIjUMk14QKPadpKE+TT2d8OMrWUkaN/5VkCazscZ4YRtMcCT3THs+WugO6GlOpwDRY8k0otY3zBEyOX+bSrQBulWGV7g0C01nJi7NxiuISvbksCLJ4wpkTLbfrCQkhU8TDxXPradgfVsWh3IUBnB5AFZld3y2LBWUb4rU7TcbFsECm/gcMSWIckPLcLd5VsUwY8CR3xOhoWcoElfY1N34IpSqnaXwQh8I+1gAnEEXKiVqUYajIHNzrIaQLv6vMec1X8//j9GAQ710k+0whZn2hQDFE/9zMoDPlKoFHx9VlZFCy2HYsGEIhs6hRQFSjIpJSOLMIKo8xag0gGxbb8VxMfsNNu4kaRntUIqVKynUA+0uqs/2pRmoF1NJkYg3sPSVD+xH10LxDBUTNMNGCg10NErVh3CIc7c4O27Kzj6dYvfTbQHWW7Th0hKdmt16YrkicsVmQ98daJbJzoXskfNMUi1dIq/wjuJQJXQtYE81Gq/dbC/5LENz7kDuXvsrKlabMT3R0FCJjlaT6M1Yqf6eUD94OG6+dw9WX7adQuugODeOQ6OdI5FI29o/0Y6+ofuB0ON14AMrJ9p7zONb27megjYiLa4teQ0t9tpe8eE/iz1W/NIq4I+uwu5zXzewgNDIwKnx87lE4bd9n+/k+hs955RQnGZW7ily/hqYhRZfBKIlkStAwNyJLwWwCDCw/RbVPsTi22UpUyNIQErLMY85SmTY/ofWUxa7Z5ABbroMS66kIB3DZnPPWMvlY6ZFRFNhbzw1s0XwVyXmSJl+pZuXToJaKITcKL1k8n5cEI2IoKUH3cFg98tSGM0laFkwCvxUJkNs3ZZ6IJONIGL2bBTY+WIlai7SMc9In0pcOtt9TlsOvdQi8Sz6r0yg5Ojrkj1Y9VE6mTKTBxTcvDQ0Y9kZTyHN8bWoXRv7eK5A8+v7kAIMqKxmV/++CkTZemDale8XCOIHt5sIUP69jZzRuj36LhwhSyu/D5L/ksQ9rtYSgRqkjDOrJif2wbPaJckB0ZN78rnO+5nXsQY26y8maLyjdofKNPBlCjkfpCqnhKKFnp0BAKx5Ek6EuH5CNaUzWTq3dUio8hHL/HSdNd8TlFARI5JXy5X4P2yaDUqxWi1BvpVwSdqKZzRAjDzBcNkFfKSx06zu34y/sAhWd9fVWOempoVIaOZD2EaneeKBuaV3Hg/PXbd4FJNX/eQsLqrOh1LiaHgasnHNu3PXjCKksRUzrmtCu4jorZM0FwxG7L2ZEGAONuEdisJIHIjtv7yAlqZKECJxPQUrTJvzCRbh4uvRXt6OhU4aXlp/Xl7XlSln/wjXGX7Rt6yFdjd+uokAUXpG6gOlUqJUQJWvOTDnXj9sHkaLvA/Zs4txaGae4sEzUg//RJhtv6JRnRgWxFbrv+Y4qzPwjPltYmzehUapwwVZjX4UIxA1h5D8Yiod39sBpo+gog6W8mvyYSrWlMqPvbFjfy3nPIlRGgflf/PnoXg1UawsKOqCKh59xpRbNOWdeDgb5gbhhyMDtbm+Vt301pIqBNcJxstloz6pOTgGgXus00OZr5myRbFhRlaq+ZsSBm41vs7EW06C4b4fBfJgNc+2w3GFHZ0DMBF1zdRTSjYCb9fX7GPLk7Aadh4DzOeYp+FVMEX9Hl4deYtxolri6TJiyz46fmIGe91feX7ouxcDOklBhPr4zmkBdErJ+oy3d6bLFZatZh0Y3nTBJDyppgB7hk/pRco3pMdqet9q69dBKbAvqy4W/uvRTYAhd1ddd4EbzE2YBA3cgpaxVdo8GPo9LBHG4q9NnkNfgVCovb2GCf2ZOqj4hFakny64lWHvpQR1YefDxUDjIJh8NlqdxbhjzG0iLo20Oop4nXglab2EIpZdWkhqDiurH4g==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127112, + "Value": "122760994791186490", + "GasLimit": 67327653, + "GasFeeCap": "1039691670", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4T1kHgKWa2Qey1djf0ZpVgwyRhmJD+xWFIFCOGwfei5K9ElymdcSQuuIkgkAn2MJlMLCmCaZ9VHuyyGwAxjsNlSQQbKv8FBSup/cyRMZQgLbm5f+JA4Ctu5PlQts33/GkwfHALgwpzZekHR110kxmXOS5NHuH5wyV7LyMveqQ6wsL49wQWZU1gU3OMibDEIRHCXeNarM5PVfMU92AyfsAwwB4V7fCNzHUR0Eyp2ioB1t3t4e2tlnQA/OQPDTnUFDAjJJIqYxCgx7GhPaNu9q6q7o9gtzBlfQ0/9THJg2/fFcxgHv/vOXRN/qgNHJ88ge0+13Lp5B4jizTiaiflyTEPJNyyO/zc7r6pqmuQXfZPRJ3y5f/sfF5wJqOdDpe7AQcOxPFpBii5S01Mgjadtwe5scvltsaAlKbWL3a31OOqVFaud+3TNpoAwCQDAIA+bQK4g4H0bh2nbXA61YNP3nfR2PY8heZU7wY6QnEZJbqSJF7nXCSbGOore9OUFaybxTGmWDHuo2dm7dZ7vWlkBa6b2xuvuD/s2JjBtZRssn8fZhq7uPXRAAr/yjeidJde2NbnHrB2ZFIQKRDMFyF6+zG6ZJ1ezkou4JLGzoWetIbSQmL7CvTCmfS16kzMkP/0ekYEahGlQ7ohCCR7DoeKYZE/QRBdM1HJLH/qOlnf4CthQj//QdR1sxJZcS3d0P9jpMpAfEYhY5odlv/QdPau17icgiYnnkbTH0J1bt/PglqVNz8FcCci/a9rvRQYy1wFlX7A6iEb4DAgwy6ZL2bPCba82pKjEtugrMTaL3R1W+oGuEVfEjo4GDCPos7OEqhRCdib06riqdl9kKQtiKdfOHfZ2bZuT4IMWFcxO00zEBXObZ1lYS471nYDVtf5RNRQdUSTsQ1NhP05JdPK2TDmb3x5ZUAxPL1JGr/g9LRocBIZ5tNl1A42yuMelq89wEDbh7T6jH6FJQ5H9UwDYnx+gRA3cLeGMj70mkSbbjv+bNnvQccE79vbMKw7AyzrFhZlrIcfWnsyImDbniFphn0IKldVi9Xf+qJLFxM8nLvMhhHSMzDCsd91gjeBlkWK1dUFbnSxZOSSqMJQCwJGj06RCvhzJ5oE7gHG9gh48NGagGMLuXhmDef9OxFeUP6NMD/+Dzy+mRYeQ+5JMd8pVEDQZzAEiTCQZ5Y97wT289sjM3JCG9D3lFUFj2jO8CJ4MRv7fdyigXEC6mUc1Yxe7GZLcWIs3FtFSq5Ui0skV97KQ34oVCnfrjsqWnklCv3HxRJwyV4uODeAYWU9m1a2f++uVHHfrtY8YM6e3y4G3e+IX+te2VfsAnsTNM4etAteRsjGXykyZTkTLDAcZ+BKx1zwVvvUUXcysoLqPbUhQt1rkkZJA6qaWi2q6FkbFQ5y7PnklAyEVqFngKspsipqgCWTBu0YN/WVUoL29heGhDOdPb4Woncc4O5wY/uVCjGK0o1XJk118JpXq2qI1cWOP4ignmlD5LfEosA9a4wluFItq8lA48qSxTDSWXGGi82UIw249AqirU7IIpmEqPtELtJz+8c7HAxQ2BLeZkHnZSQH8ZfBrJ/Tyum+sgMBFBz9UnrHCNBJWBoSrAiMKE0aR8u/FDOglhR8/nJYkIb6qhpbDaLMFAVUmxnFRnFNymPvfyeQL2KD92DnAOuvOV5zo9qel4zvqEJUuWdkF4c7sRF+b9WJsDU5TjSu7hVqE6dPUYbvW3RCx6KIbeyQlagnoYOsNQa2BuKQ+mnMghe+q9K6d5v6XW50VqCM/m8zddJT2KN5+nyxiWzHYY0wFNxPk5UMVPD/42rvsw4ioxfgowzMkGinnSMqZHIHEvm+O4+KtvUIogEUJ5nG4aZdXe9WfxwS04W6iHT0MY+6OQ3IA5tNEF7+QtlGJuD5POK5XoihKdLOyfncxWxawH/NEr47JafEKS4tS/Am8d+gCvOCPX3nhwVAOvTPDYWVlErhCmh5Wo787BsYFP8yqn5M66K9/rGvumvRUnfMq5RrtPiyPxmdVfJTaC0MN3YtZVqhKS4Kgm+RtfP+iNLbrMPKylUQ/kQ8H430QYpZb3luH0fiVga+Ahvdo/eZE4xf9Ma+Hat775RGf7sMUVC2Yck7gaVLW9g24yuzt798bZhR7o2cn/JphPwbViIS9GyrK8gSvjHjPdA8Xpg/E7ecxYYzC547+mtKUk8MhcqdZUutmycbJZruAS9gacWsFaoSpsyRQNApkbmkCxmLvnuN6Iax1wKYuaPR/Bp3FzKXgj2q/ZhGbslb1ClpJqxmSCuhv7tQbyAci5rb9c6cSGJ77aUUhzAKOJpW2jw5tqdbppOf21UPNjBRE1cn2dnYAVXmFo/76irDdA0HyL2lLsDE483blLLWbTc+Epa8vUFBj6ePltspwen0M4sa1BjBuNP3W4lj7PEaqzSsXasPz+gwAdBJxH8x+DBJ9w7M6wo85EC7lweEGXWaCM2ZvmzSzguY+a6HFlAoSxuN6ncWpFXgLhtAzmc7kjt4cPpEAH9RkVvF2ErtAGgZ4QYZU82ke5egCjtAu1OX4DQtISaxRvnHA==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127113, + "Value": "122759250841580819", + "GasLimit": 69940153, + "GasFeeCap": "1000855688", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4L1kHgK7M70tiHbRK/52ZYGpki3O6MZ0hewmqjNrLPSSBxl2SIybf54I+YJlbznbumjaGe6ujqYh1q/B3XFcakFeLPwiQ+AO3zXDTXmHGDXoyiRB5xVWsX81Uo3xYgP/1nKOsYxQB4k0mg7oH0QWL3KYwgFWZmQg9Nwu3MsCwET0xfBXHZYreS9j0GWFUcgVXteqTTJgwsGz/Vj8oJRfRtsTs4JBtap7PcNJb/gEOV+0n93yeT+7wIRlhwbAXBMLjbRAwzYG96K4NBDfNOA3522NvDG3GvOtdBwaCMXSWtANK87O/NaUTBcRb0hjkpunjRigUMo4AhQDV/HNCRhebndG5iIrKBPjyM3nE2ngW0dTcZFcRFJBAeQRMDxL93/JZaLb6MgJOZHBW0vCXd1baUMq6Ab/eut/ZiEZ/3FBAokVJ4Sx8iOKE9tLG/bg9cjQD36WDd6sgDHfcxXwJ/O1+GeOuLVrsBmm5vNXNfn8Q5Vg5uwmeJLxzDK9JR5VWF45Si5+ApYl868WCrcp9aVICVuamMmxmB9GrjTOb99jBO4RlMkvSVAjHYRtt+uMrZdlZ04Ei7I/ID8FwA/tPRFx0JTmM8rUD+3OHdBKUGfpdbsaDkN3cFvpjji7EAEZhhIHUdKAmfwe8I7E0m6/nMn8Hj6ThuFQMc7HpvklHmQwRncG2UBKtM/wDXpLjRLJN/9F2yLG5Ro84FFL7cm5BaybqUOLSPGUfPn9EVEd0OTcpkDVfPVDlzcX6DSVwBzcu4RqD1+Ki4o90ovqENCsV9oOk+O2ggQLj3uvD+1E9zMw/mvXdPin4Lp0LouFWy/2ihYjWISDzcpHCvTLWRFqumz4MujfVZKCljFhZs7dcIH5T2uRykW64QQxdQtWMhNaC8H+B2m0Q/Q0rrFi7ZcNvXeO3cuG42KXMkA6PYMCUtfeexUEp4NQAITiUK9xNe7UE5x56wHDCMIndPCn32XT8QrMaiociCfvF7/yGnkSJEUFNHZAaAiUJI0AHHD22n1nGduHnkYqJ8ZPachTRBso+Jp99sfNK99SlFGGLmzwizvxo7gnaxU6GKRv5TGFWHlWdhWpRsmi/EqOCA52fGPBzq0q9KcWcF2nAhWz3AkQ74uNd92fy3HvIihlEWflmdRCNufiN6FoseQTD/mqehbbQ6pPOIiKtU1iTYvDODIhH94JJy7dKqZLBmMlsmVPaeevEoKL4Z9mD1qkBIkYaQOvaBU36lxPKBvTEvbzDnMw9+pQIyQeAUdmCJQIdV7vjO6s2m68EDGnQ8YD1cUbdG8ftONdb6FZ+Xpa77SWn5fT1pFHmv10RyaVkt9nyvfkjzy1SX5U+4bFQRoNntIa99f+g0rmyOZutF3gK4yqFdq9r1siwQhvGSMMS899MFe1sJWBBS7HHmHDVlAm2ThqucIO3TCAy1afjKucRr6w7GFWpJLkoSjPiMwPhoHwuCcbII2d0kNIb6dhsSIeXdByfa4DRF3y6dAJxQJvzBhFDlJ3HwzZufaK6JSk+XBNyYDwcSctd98++G350VrVlaYZz+yYq6iBBwJq0lI2P55ud7GjA0MgpTSP+AtPGYrOsObOJ2iJ6GDkH7ojOlpjZWW6FWYHQckSEWzSoqNdT4OtmmiJMiJ2IXuaesuqC8bG1S+9h3XjQ7X98VhznYBAx2taYecX4G1y0LrxVbAhlhkhOHtfbhojsYa36Ue1eDJA/phVpRmhc7HNfHKJWPKPzO+C/vdun9CzujTSyeZ3ibHiyI83J+j2Tjog2K1HoPjcKLcdOdUqq5q1HLFVG4LK+q4bf93++Ft4oPsy+t3oV8hJbE/xLly7KXWtlkltLr1luVJbKx18DPBaTtxpKPqu+rGT7bEy6iMnulvZvs45+OTMjI5F93VmLYjtiWxGLCnZXvdEss6JTNDz1vfXfPBgE820dj0IShfFTc6XZWJFLsJpMwarPPNRa6aUnjDbXiBwNTp8Job2h8YiPG7S1I6HRpd3we+0tZyn86bL2uW70EhCKj0M42jDEDm35Bv1fBmVPEHrePABn3Ip152+fQ7gxD9BwjqB/oi8jLtqA5ibP/4q0ivE6ypTkukhkzy3vz04bx4LoHW7btcof0xP7qKhVurzeaU1mctlkyAJoycw9c08W2TQ4D2wxkC5et7DGnjfLgHaHsCdG21yYFCba7xYjeEJqoNbLjqTSIzAFQZRd2dkuLSJl4eq4C/2x7cDmHspZYEmBq25NGnN3swN2LpN5Xsvxf6Bn7NS5wArnm0HWoe6nQsgd86x6K1FaV9JuVg3YKDSs1f9k1ZEk3kNCTbQm64zHnuxM0Y99wX5WUC6wHQLRGSnag4cjzLbXpVmd8D5SjrfBrfS9gJQj5v39MYTNFanhJsGZKeA1X9S+PF2NmTHznIEtpRtDkwmWBPxueC6sLypg/S1klAL7tG3mcRSGnZa6al4co6pAI3UvxvLyiHAymYQqsBbTjs2O1EmT014LZaMjNIAAYXPNQFGdbYYSDDrlmmnfMyG+zeWwvlkMHw6c9ZtiKj8hnEcg3tPNAECkupSzbzXPaffSiuWviQ==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127114, + "Value": "122758443760984234", + "GasLimit": 51612351, + "GasFeeCap": "1356264511", + "GasPremium": "100", + "Method": 7, + "Params": "ghn32FkHgLMaNwX407gma1HO0P4VHWsNlveoTlNyBqAELvibJxEmaMK6bXR8H6/jZuWCzyjVUosKwQonbIRlAtPG8By1z7wV2+YouMxNvIJXH1kO2DOJ3A6+FSKkQkL5mnCyRYcuIhmMABf+V1JWuKle+cztiJGqAOcmsAiACBs3wEyG1zdRxDaH2BPsbP6spl9R/Tn0264ZDl6Np1cagoCRPPWbs+34+4O2utJHE5Tgom6tuqow1wVp7SGN9KWN02JeaPVlHaJ4aauvkCimn5EaY6ovlhpc0jztJ9tRpYsAO0cT+BQ4T5dzn/Hn2WzIwLyfXSGnQ478e9E2wwZOGT1TMGNskVhibTSIIQsLRG2KlzU2F1qcpT5p1mqPQLxIKnJLf3HS8xWXUjje9Hhfp5gZck4MnbsTS+UCqXk2L5S/G99c7pQA0aiFUbXXR/XZkwz9c/CYy7KCIZ2SDEWeOed+1A/XV54ZxikEU/P4rWM7X/AfKFEVx15gG2LSk0yhuEwgTJAPVpF3FVp9FnENSskKheFmr3qG7KrfLto1Be2RkcNjDslR6hDtB67TeBbZ3Vq5W28RmKlC77NRy0Y0CUi8eDM2QDjJginG49lAuMVe/0gApbEgV2sxsPkueAjMk0590AwnAxmkz8k0AexH50Ln9T6R9lEDYXd2JvgB2no7H2W8ALz80VM5bXE1fx3fngTmWix9ELjULMJnZ6lzB5W5QwWCflkaJAOW6XMAk4pWWkPaRpFpqo0kIMGXiTTDob4YRhfedYhigSXCyyxk2nSe4NmaBsDlZWWZO3KhBnzJreQha+yyMBD+YbQ79isybYkaxn6vMbHClz22vBaZoCFoGLebhLnljD+GAMCWolzi8UjvCpovuU0XSeoqMvU/NsoZvIf0iRCnMFBkVxbYpj9ouP9cmjz0hdGrH3+zYV9jZVpQFGsumEunPHMEQII3GT53pJdqO5PgXeBWOJLy4P+3jWZJjUwPWeaaWRvW0CCuqSE0wSfiUv+FCg40qqmEOSDJJ7gbibV8iXqtSaVy32AAjcfpU9hV5qlfomHjSRcExH6/jB8eaIyYvxsCPgDxK3zoY43+y6KT9tUvfXR/JIyb7RHUC9XdAozWgJMv6J7vNVT6ZuVF7qS8QNK+neDd3Fi50Rk4SQ4XgymV7ifvcTp31fF7sSP6+By6DfZ8ytJlBPv9GfdMdvnacqBtDh7uJmVXCkBDmqui00Kx+pZX8Ti3QXY27F0AI3bPlYZEPsj41gGv/OrijMj72k4YNyU9wp2TOHBRYpWXvTc/WQtsP2tTCqM/KsJQAPnQmET8sCJuwoX1reDnM7Xu6/stK96HGrYoa5dp/oKLBL5vtvsScYwtAbpn+mYEp1p89Q+UNJ1lAthQpAd4xpkcGlFek0Wx5Q/N8Ylg2gQX1Ucfbv4Ta9A3OofvWCHfOT9GSZXE01e5AzpgkI41SxrW1b28j6gYM5my/4bsOLQrcG3NS2BPd4k0wvbgRPocH4pY1VoGl0oPHTvyhwIC8MNNmolY3pnnOX0ZBncdQqf4/oZBR0O7EYVzkie9sw4GZhOh2NrHkBrl9iuQSS4YFDUOx9w3L/wiVJOnv6+FL4lXdGU0MuDquo6yLyNGbwMS5Yzpu74Ry17Ae1OhW1JqU5ZQC2UxNI4VhDGefXMrQBNVLXbf0VIdV1V8Q23vQFT5PXgQs+apbtJ+XEd8ikURCCdQnGcvjbl4G/WQO0VpSIONwMznQt3izGp5CsmbhWV7UtxKeP/Bcw/SdFdUh5R8Ip/GPSvGismU2suBFn1237YQ+Rj7WKgCZnRmN8uv/HwVNSFpqZD/yxVyzUTQ4FcuqNWzlo5tx9ge9EzlBjCTlYq2U/qqP4iF0gboZn5uRGoTvarAyFBiEpm/IW05ddculZKRjFxR3De+m7mmgCSo5QnqMqxSloRp8PvvuUDXcerNF1/XvbV0cwSJfPyklgpwrEFS3W6mNY0fE8MgZLiwercYZraEXJs7JgWEj3T/dDVpbf/s6ANzgb8JmC+Xib2h0hQF82vn8PJmow5MQMzVV5B/jIwmIhte3EizNQx/NjJeCATnR6D0tX7swFiSFOZ18symwimKmsL2Yhv+KzYKDbnQ9EbN4ZzDvy8gzKPrYoB4iDeTvBAWpVeNo+CusfUS56p3In8KBtMceeMbG/orKRWfDbiK8nlqJw731Qv8+X/c/cgDRg/D6Uh1NQGN4Zw8Xwj3aHC49xsl3MDDApboEqIBrkRJS7VuLXBCL8kdLRQGDgfwHgXBKuDssDz0VszvMmQQFxSIIXde81mBE6KPEqksvcEW9vRS2B4wluuffV8UdM4lAF+R6TgrR+Cn35h5lblBU3DcNfMASH1CFLSYxIC7PCAjrGshkGVDN0ekk4LO5mNWynm8O5o9AZRY44mcSFmH8cGo7O8OV7lOPTEmNgZ8aVwOJDuE01bWstI9rtj1Mzixk79OJzjc4tuNXUQ72Ukq/+NDsPS/ywz1UNrQwJKhdw2WY94WfvjJM1spu6yiZuUIYxSQGaaSH6FiP3TP15mE0U8JCiec/QTUW6YsBQ==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127115, + "Value": "122762095018351560", + "GasLimit": 54318903, + "GasFeeCap": "1288685819", + "GasPremium": "100", + "Method": 7, + "Params": "ghn39FkHgIUGG2kenVn1EGXrDtSlDzb7MVdWF70v0ohawgYnNNkqbFw9kS60jnc+ULx7We56fIo8Fgl4nj73p6ESWa17esK1BXiNO6wAJVlCsiMHaV/D+sMN2V626GCMKHby7WfeHhPfGOdE3JVXWL4QvcHPbIt7Eh8LwRQHF4MoZ8KSfVcv5rk4ZmWaJazj9VLMPx3XZ7Rs1t5E3WY4dmxUz5nRqRMOO/5SEAMPhZSlTw8v+HMKp6gKNCLn2SjGS6BfR+2MeJctd0fy7roRpMvRCZd3htQEsp16+yLmltcmwk+rX8gBCmKQZMBc/4NNI0c+D7Q8q4MLbih3F/jBKnrSlD5cKWoSWMabaY7vKYQPdBPlJ0xcSJDfmSG5+U6s0RgLWvh37RGH8cvNBpSFa1bnFGscPirxZQ3PWpEp2W2C7KNQxFXSTONZfEdCxh2Nw8vgAhvHpKnZ++wA+NwPONrbMSGoAvlnFCUa5YZQeGD5AnJ+RCTxKE2sXQqoKL9KrReTbtfmZ5lhCaXpu6OE3i4JL8HUxZIPbVKTJE325WjqiASSctmvBLW8h7+TN9Y3xVXLVto2x649BYXtH7tmJ05K6eRlRFSQifYcLhP3IbovqxGX25WEk/MxWiZGglTh3LujSMrE4hYDGdxKEooE36k8/dtYysh8hmr2rArcYTKZwu/DEXnTBwFPc3ETVtUgPXjQZfqjNLXo25d3+xY2t8JcZsudq694RKHIEQ0s/QwCEKHpKD5DA7XlzVLYPR/rq/1ia4XlMIaKBKOZ5VK7JwjwotCbasDoEwibFYCugwd6p+4xACS2zTQR5yMWBv7RSF/kwSGo7KB4VyvzNMgqcTZ46m363bRZguyc+XsQ2x/QUWVdJuDOZ+T7mzp7CY05QXWl6L3q9hGOwDC7k4HAm4deWTyKh6OCSD9CFkmPsDsXjladWu9sfxedpvYseetHscF4VDt2EKfXa7ZuCKH10KKdA+1hCAZSCW0E5NDBuMenIzrwf5fcn3GnuiDSXyf1rvpB22idoqfCBpbiUR3k+hL+9aYjUae3ZwbCE1ifxACravxr0QTeMACrfHY+VHV+DQjCLGfjI6WhD6enTIPsl76BzkqXMjB4MAxs6VrXX+BZMwwTHXDGSYQ1GFqGgdR+CiVMBGb8pQPPFDY/XuSv4vcAN1edp0DQoQE3dJJE/tnwT6myJkqKqOPB7x14pr2WkqjP7n8+NJI0Pf9QKh2JjnYj9FxZBHgQlC92+mP1hUrtPw+upkLb4xSDoG6iKbkuZsCFadsFGJnXp/jTWdww1RFk9jr84Y7PFIZMIARWpO28PqNxoF4WiJXXlg/W2kWe5c7+ugdfV6R+7EO3vAyIyY7OzaCsw0yjV0rvycw4tcNGwLz9xhsYuy4au+h7uNf8BK41sHIO0RMJ2ZWpsUuWQW1cptPxuXMNngusvEkK9PcdOA40jYd6+FiRHNAq8FKcbGli96bWd5CMuTWSKRLeWxGe4Afr1lElOX5bHt5b/I8om9v4RISTvRqBPU73GCezx4kgugxUg7HJ39nAiytsNHraCNs+pKT5+zeG4HZmUKJ8/EBWTK1qXtsZJrDtUgSgAukvD2WAeKnigbzZaWy8gPKlP7NnxCKSKbeGhafe1oVD7O4mCf+gxYAYGVuuDbM5TauvowQOOwym1G/h1QjNsqyhYBhjaMdmIJtWDcbvV/MrlMbpIA1wiWNPAkQx/LEEpDIhBm3V7Kpo50XowdYNm4BdWyCE2RM+1VIyEDAuN7MgGk4Q+Rg9+4GMEhaB7R/nNesSKLBi5pMzwFYXWXicqFflCdDrxe9qW8umPpPBLiJBTTMuTzulWbGHT1mCRGkhy27ZMHvtBKXB4oY62gGuVfn0VpczZ9FeqK2M98DXhw3GbmeExQECdn9ESoHj+FLVXHkPNKOoxAq5vYbQ9MhbdnWxFozQW+mZu5VrhwaNQvCvHhBALxNRCmyg4Kapp/X0bJ31fDnTubYeaqLmdXdNuia8etKgH81J8fkldn0/FzHysA3crbcyt2EELyiaK/5YFFLMkHmxoLRmc/voXPwNCKkv4uMMUHsSH39lYV6ommLmG2gb04KanF3iD4rq1OSTV+gX7/s174RfK2vs+RS/Eeyda+Y5u2EEsgA3N4frxRoAAfo7PM5nHW3qOdoVdkAwz4/VMACIVQgHk2GAVJRhgRW/yDH7Z3CPkV3hB7oVZWrLjehINWC7PYKuDD5QU8JGfoG9gs3ps61UcXcepPpBftBt6tJ/b+TJ1Up07fH6NC59VGzBeuGFBEupjGU/ypFQ6gGE1pTnvLBW4vwz7tv66Q77Jkv0aLD/nNLetDTFhC4TCmjoJDO2XaPMQ0fKoAiumSIUHQwwKaaxGZAQx5rAt1eLeYtNwITOuLcLpXIt7FDqQyTAx+I7TKejCnUS7Ih+Ql7jtW7VVQHpZ2VWgp6QBgSM19p/dlJ1FfPhfZxtnV3oxi5F0+WyxEFts4IbuQ1gLLD3JyquXrPCsBg6nyG1KBbpWm/gEcA+63v58RqgVTsCH6R46JuENOKPSUskTjEFScTVv+kVXg==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127116, + "Value": "122758635195443421", + "GasLimit": 56931403, + "GasFeeCap": "1229549884", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4IFkHgKFFClbYUDwIP03Ei5aVVBJ3r+72Mk1wlb3qjwF92Eir44E8GQEmEw+BS5SHViZzwKPOr1vsLxemcXHE+Qsa8PGkbIM/y09dg1mkwmY2/uDTF48qN/1NEcgHepT3xwV9BwCQ4rtqFvwTYPVtx6SiGet2B5qNehebgXVoQZ1tKfmzeoLLHfQRXutcrgLaMq2+kZMKp5cwPT8jLEakL7b8XLrg9TO/4M0OHHhcdicTX2PY2G8Hk+Care9IeGLpoi8QxZMKv17mmIisW37C4p4BiZWFvJb69nhVghfHKghFgH34bIj8p7ut+SU/nPIoQT2dVpYzfUNv3GwW8g4rfydboJC0BlgRsae9SbEJ9X1AFm7DRG2GSf8NLFTcWIs98GYHSw1l4TalR1wCPZDdi/SapUwtReWJMvs7oSRQWrmpq/JgmUhqCmmA+mCZfWSfNEcN4rfLi/TIaeEwlNu+wfaSPh2jVLCoBZ8A6s17whGgwzueJh206UF3ivfAprSz7Zd7voShYXuYTZ7U2iw5w8e+mgLxNnFjenvSF6Q44W1VY7NQCWGjJAkkark9c12ymI8uXKCT2yDHCQTrr9uzZKsnfAXfVQfAYxxY1jpMoP2hMMNrqlOFEDKVUb1pJZ41in0rFRkvVYlN5SGmSNFZWgr+kDcCzYB0KZH6c7bUDMAonVdOIBUrKYSX15EhG51LTBQcapLMVGXGA6vMtOZyoemV5pIZwNu8XjuFy1B6aqR88hekn32f0ld92XnCZXK6P4MXtorLp5PtOQUeHxJmou7BQo2OoM/BJ8ElcxNiQ7eZh934LBpA7EqX3g4r9A8ZyKGPBJWqgxqSsCXqqsZtT3fCRaII4v9z+MRlI5ioCDfrQcmuUSjwUE6J1kXN8CTBrYNvlggt4nT8Ag2nVm6DCcnQza78n31/8stJS7n9Qi1b/KcchAGJsVhwhHa6atAAxxbPwLQqtrcQ+N6LWIPSIP6ms+dNRlQeGQtVtzeJSxLGr0+MEYApPhpjug/OcpeZcMAC8oLtpIQpSaXkF0cFhYvoRvDywI54gCELJuk0L2GpjlGCdAOJTkai36VHC6vXNw1vdLgd7rvw1JbjxwCJ2GhOp9vijq7zm97mjdxiavsSDMzE0jjcJ1pXiKfIbpEquFpKUBcKGn4nOhkAJHBGDYSyLy+1/n+pA+AtkiQvQ0oaiNz5YI5wevbA3SzRFRJ8612Og5FvC5+7ZUu4y7msQiEfT1Mi5vG4wA/4ZxFhwOyJYpiWjCujbefU2dgvQdQD4pjePJPyZxBASsdRo7+LStVWQ5NuZ5qABymdu4YOvYrECQdOHUmvUs2q0xjvWjwbuB8BCpLVk//QwW3yT5LVqz3lu1D8nhD+ShPTxy6LpQzDPui6x49ey9ik2zDE0Uqd35mXpQKi3YZIwvvtxInR+HhZm7PV9QejGuvs61cU/mw6FS07ynOyvrTs4LIniVsG+6rkT5OPM6JQCjjUXDC8u4S+0eUbJDe88LJiH7LovviUmmMzrMN//Q1GAw/YuU0lrrn6ropIA0DMpd3fdsnqONCGiXouVFUIxihYQUd6JKdxVk1MCbgnB1eKXxWIzxLwXxT3lo6bo5LWMhpYoJ80v+9v77Ikfs/gluDBRvN1v+Qk5+Udrq6PS9IIw+WzkhKR1MYN/gE81rdDgch+PgEMo46nymPxWGc8uj2EFjpKUdWJLW+d1PIrCjwtliTrD4Hvf8p+iKBK9LU+l1zJTwR0s9AsUq42UIwwsOHbZWDNWgmn/eISI2bQwjtIS5Y1hndYLVASdpOu6q2ezqxNs3sPKm96S15ivFk988aqRbNmRwus51wKiUN+urTZHq3ARs3O7arsAoR41w8pfejcGOjbM0RG4LFZ9c14yI1pM+W/6Ro/PtipJQb2eSXnPzjgRwufAM5grwM2PrkTK9LUVpMCZQNCXFKLrBogJ+oh7XniJeW5DLhSFWVl/Zu8P0D4JGHRNirG3IjSGCSiHqVD2EYzhniIGpDUkZTGAVcvNl4Z2FCUHw1W1W6ICiMLWYPQrvdlkM5l/aUAG9K70oocmULVKlw4fj3TcjiRk6RHXFzsvlvteZaIzasYhuj+8P+OspVjQotr+atmcOPZMHc3ddt6yY4wltBzxlB5YiJqqDm6RmXuFT20qKhfOcHQGhB0rqLtV5jyTwa8qyvNQdaieOOqPeEVj7+lMZT26iLTIeN45rK5LWYcBv+gcX2rnpRuOky7pEnzoLBjrKOzFDL+GkWHApuEbUjN/eSPI+BhL9NfYl97NJ3ek9zR8xTX5ZiI37kERaCCFrYx5ceYyekNKgRa5D94KbPM5Bp0JYDJI/Kr/uAa3M9fQnUILJq4iv90os2ew3RR7Jhf6E/ESc+RllbWRoxf73UIxt6ZBItzfxX2jMltNiOn428TZ/SeDPZXsJfAPy3/DhlkgMgVu2FpI14quA5VnUPuwSM5SxbhO+RSueGrjs2VzdrDtdfOTDZLPfAAjmG8zosgUnCUjgXFHaMHmxbKwYcZFhRTMDDpt7PbGQMz6vk7AUfs/UL6hf63bNbsaVHqVw==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127117, + "Value": "122760273970954837", + "GasLimit": 59543903, + "GasFeeCap": "1175603151", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4M1kHgJHeUduj8VuqzlaTYVeeODAreLcoB+uTzmI4sche4nPMLpB5F2mexMC0az+/lCykKomWOA7b0c0YurUSU/qJh98foixHJHeQAaUIN4WJAR27OqXfKJ74TiMsJyJK211TaBVTdVoi7R2UTvpE46HwCFhjgDGgBiaCgy5AtUAr4kvZDvlseanV0rqM0DY3ZwEu3pNtb2kqDvRUEPE18vbN7vQETcCaRAHExSSW0Yy/vV0go9MNR8UfQVf6wt+HahGFn7KUkUwP4GB03ptYnxW5WhyHzbiM+CZ0ikGdpdfaOUDTnlowAvg8g/KQFbXYm1SPhLAfdNMwhGhsyK05JfH6lO9smBF3E8hDxDE1J0fzghiE90K1ZKiuHQ2grYQwnPetgBQ+d4kuYU6nPSBUrqAsgQzjgW3EV8ooZ7HVBRQQ3LZwZSpI/qBFJLusqffp6OUBgrGoheML4Ec4Btk+IRU24fkvF73uXED8dhpUld+P4T7jq/sl4IItIi8GlIBeHnwDbIdlv1LyEhunCHagvCUllIq1b4yHb/lhz/wsqXLnTS+tWrjNODoZZxLoVNx3sendapHDiwo2ooorkAzxCVmcIxp5ptu5MjRpgg/YP6qwdEFcB2qPSMZ9ptw/Rz2HiGH2ChIHu1NAq6JsPbTb0W4Su4DsN0cajLZ9YFluCQ6tDXusPf2g+mfHHlciyr3SODWbnodQ9PZy4yYvcf3MiexZiru9haNbFR+ZNraK2xkUYyp1q6eGrEYChGOldHVqRWjtXKmRt95xSjdljS4MNQ3z7Ol3SlHKjVBpLtnbJFv447GllG1pdFKMvzBNwVv7n6gLyYRc9hx63rMqGLMOLJRCT7F7neY+/u2D+JRK9fUT9Lts+I0kv4OxUPbStWctZ4OPSghr6G/xE8VoLojfc5NdaXqv9fiOn6+X9mDtClc/vABeP0O4lK/oYGbcbGg47Xrikq4HvJdZ1BKxVipgQC/nb/4gSFd9dy4sMLIQnXFRiO1WitFsHiL+cfliRUMOyo5bgqoBVJUqzrdwZoMPI3C0+H6k5oFJ0hEsgRGYy/AZzS9ZnWotBEXqNwpiGxmHxE/AQZjPWZiO8lvHrMnk4S6KgpvaddGJuf6Fre0gU16OXAsVQ5xx8qCWXSmsw5DhAFS4JQAng9HYRtwvENBji/oKVSEiBoTrBLClo5fgBTurxoftuk3kNeh5sJHj7wtDBWq13pFe/1CUN+pU9UUg/m+j+tIegDnPH89kawbhi1jCy0pcCrwjMtRpppVg65q9cyb3E7LcRkGnB1BzyjA0uEky5P2oAp56PXjhPtD//aeAWpSwXPzbaMqRZIaWZsMvbg6akYQSaFR3L+qJVFbz34xo8YbuDxlHS8RiNRFpJpSjTawUikOR4g/90r0PYxVxVje8rgmZpZ6vczgIDndB04+qd7Zz5SEsHqUEJfds/chfH1XgPLe3fCla+rHDRWFR+NRwnalwu4DWUngi8qioQ35KuGzYWaDkEo4G/J+0r+7II2bZEhK9AyjJf2k+THsc0lvW84A3lUWzNS9+4QbJd/j3Lp25kiBwP7CbhfvU5/Z1Ee6t1TY0lliKx6tj9fBlx3mYRbA+1MV7JVA3PQA23zq+KHjec69jrtkuEEp1+bknN19peam04LghWP4RVRkHOwCUUgIDA36dLbuXrf3oAvPfr8zG2qcHI5lg7wArqv98eKBYQ+xbHSa0r18MjnJurmUd9Iw0wFKPPAFGSKHOmqbaaaWLjeX1HSmlUhVT5953WEFCi07xP6vhnlZSWGNNxLJ55YGZDDrX6LSIF2cPaK6XVLQGefeF99wnCc9057Uc1XTs4K6GuJ/n4oQlJi5u2urbC4WcE6tig6pQT4PPPGya9d/0UEU5hGxZ/76cBTXXLMvG3LfDB6WxTa9LZKmHhwZetA0ZffkTn8OJYbaPz+FhPrOoFiltHbU8laTN8UjjfaJRav7UrZpl0i8C8tai0dEq95CS1LXi5Q59QLM/dZgOL224BNTlz663mCW3HMHuTUbZtFpZpS7E97hmADCiGWV3g65ekuRgDKdORMp67KzQvHrP3VvHhPCMqOUAZwljzhnCoI2P6oH78gODJaOHdbmE+rWo1Nez880i+hC4Xn3fzqLJ2XHaLrRuzQXATN+MnKTexdCOuB4m8GUAhlpYOapAOw+of1Ij3aX4rmz4EnEklKuZsibh0NIpex5w/Z9otTZbyLEcSYI9UIDpPgz4h8FWna1bGVGD+/OkE2zg8GGEp/SMZSjweJP26o00ASQsCg4elrKRnNGTKLDM4rJIMOZ0s4wrXdlXTVGQ54yq/x0tOLgtRi8ts+M2oilo8xd6j6RSquoN32kB1My9HH85/ox4rZnGpjqNZVztbM5406JqbMel6qwylhiNWTfphxu8fU3Ow7L0sJSCTdR1cJc7WTIa5xHtikhStg6+QZn0hdCKtkgoMzeBhLuOTYsgSQDTLdGdPlYtFtcXgpgcN+0D2WYLI5RZAlgZr7tDApt7i9erxfTMdzIeI/p9/VCGFOjd7dal1vTsN9M6FYNvVACMO4JFYA==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127118, + "Value": "122761937365430127", + "GasLimit": 51612351, + "GasFeeCap": "1356264511", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4QFkHgLS8P7/atFtf3lGPTGItpucSOLvaaimum2yC7W3jBikTEaYu/0FTYaf1HK5m1jHpILWEfcvfyEpETy45lz6HyUie0Oklsr3cE1QBLP9QAxFoNmTU7sNM1sS37gtW5tLXQQ05Bwo5hZBmiL0L4jE7b6BS51p2jOHlA3N5hm3Alyqj4bkqShiRlJjsjSPV9ETlVqwCZwUqxLxwK7DVOXKUdRTeOOTXKkVGIEia3OCy+88OOg7x7bIuRiCtISgwZxuBf5nq8wYAcVqzhxrtxjSst0/eV9EYjX3nq2aOC8g39j/Uofj7sVswcx6MvSDG9z0q0K1BivPAaifK/zA3ZSRre0R+nTW8OaKFvBDWLfay9wLr0ZCPGsItkaZR0qetxOBQqwqHUZI9AfK4Lo0KCM62NttY5MS4lUJbKKn1VRyTT8Enz6UA7QBChO+QLGKCgoyP/ZPeyHAXYkhZaJOnqxQa/6NLAEyKGJ+jeIXMLz3CGC1FQgdAeW3HYKEQNWWL4g3aLaS6JwA9PNCfEV4bvMhHv5Ow0Bb+M1sOJvPUDHrjAR/buMSU4ieOpFC4qs3w7ISkULX3g6L3tu4eJ1AnQmeXc4cgBK/5QFW7AZZU+d4p2aeT3KbJti2/97St81JPozp8ugbUL3UysTWJsPLgVqCFaPkdJkv/bycyO0ddfuLzTe6IV57V5zPtyk0pP+lVGOTSe5J0R1hJO4JWIlgkWsFxX862O7QTWYJ5nJwDydyWJgiAOsUZ17EKYI7U9JNP6oXJn6/zyBxbd5iE9BcgKvw6xcMXtS09O8rFBWCEXijkxTMjMEfZZyeMxw2U9Mq9p5uOqIi3ZMaxxEA+qG7h862Uz9pibNaKp9+dcO+zAA7Z8Ql1CMB+SmiT4zuYiXZJKzd2zxXTyB4U0Y4tSiMRUpB9bQCxhA35KrFZ514Z0dkP86lUej+yuSozIHdCcPnzLfvG+oXvhg1U9cTHkSR2U8/yXVzylRRC0L9mkTSYZvZ9tnH5hWzlHi9h2YNlRpO1+/haAK5EZo8wf4qYsWSaN8hJKRV2CSTKpTrmCUi2DDracC9eaXtm1dvQHJrHaJtZ73LyGKTjDvJNtgfGbVVz7GBJTHi+MeepSBiorIfqeh4k1vQ6hfwIWzENCFWs8aMQ93JLGxbQ/TjHVN7Q06NAVg1oEUMpK7oi7LPcGvSXS02YAK0k3uHlvV1DwXv651L/pFseaJN35UVDhHx4q/p0tr7Duvx+wRa4+ulJ5bnbyQBEvs46nE+XADpiUA1uxIh/M208e68kqk/+d1yxiPtMY1gZcgfUmKH7gSvt2u/x+1L2TR9c3MX5GZ9J75kYu2y6kaO+h4lYksq9xXGI3dbciAC1ahSTKAL0rBO4wnzOb1jTVU0wWa6BJwvVFJciEU0nGcwyGxEXXY3lBH+aCLe8jHz/Wrd/7Hvn2utYzY5KEarZvR2EAanZ6Tr1/MXzjf40zBS+B7aMy9YersdUW3EdOyY17TZLBac1pUM8CHZb5asgWe8iBK7WFHGtkqJo+rGfXYnPoqmDO1S/711LOavrFnWaNvnqAqoRXK7tJLO0+GnXe/D53jsTsn1iRgfhnz4mDQpDJI+NjANEZiCWWxU+LVXTT/ygODOwANmFiB8N89Z+YjrVbp/s9MSqm3TNr9QG4rYRnwVLqHbseVaNWSbSY0NSn4DfYSi+3Ma6pntE7FfCd4qKABgk0uZeTWR6XAyfuZtfcKcDlrV5dz0prfSQTLkfD7Je4Rp0RaXeiLVz+DkFN+8ZQ1W+9NGgsGiWZy+KDHI4NZQAqs5b+t2VfTi0My1rmkjZB0PCMrX2ek8pPj6WIInLEPSUImpcsx+tN/BEHILzY7JsdTgb0EKokEkg73f1hIkafLBeSXOJVL2sj0R8sw9NzXm+9Lpe1fWm4uJ54mWKeA7tGPSRU7VnIUVNQSpYrMtUjmfRLGg6zQSIEmLH2l9NLa6FZBRLLb1rTtGtMH0JjZHQQzAFS78lsiss1SiYKOVQ5xAJvPadlSqkGT9Jep/SRKLbak0/KVGxNNRRyF4AsIxJwfOsA3YhlYTso7jFjJYKenrKRIlaC67IkRfJvFH1s7e2CnX0gMPIgezc549uyIX3kcX8At0Z2/1QDf6VS+6F74qUubrGeOBgVVMMUmTmDx5A6cI6I/GDKD/Dvj5qpAVtr8Jh2ZqXyzYI5u7dxzZz3FCo1Dfrmk2p/Jfh8CroOil6BQ5+pjyVNrDnkHiwXpG0qzvmd9pBlLUGRmG8I10r1G3ned1BClR1CpodCsqkFJVXxoDl/l+pUxGD10WXjrJB9cvJQOTDRh4m4ewes4w/M8cDICqT3ZsctNsejrqkQhc30XjP3smdotDpcsLrp611sKGUOroNpDIujM7Nj3irPFkvTVscjLj8UwJyT/eStRZzXKYJF4nAL11EOGr+mhV2JS2VL6ThN8rs6MfaKHF8WD46lZwBn2dX20XaujFCG14ni+ujUCfOCik+iP+oXJcPDHfIBRV/PGvG8V3ErLzzEpZDDmOlgkHYcG87O11s1M4iLKmMmHMnxad+DKNrOQ==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127119, + "Value": "121193428109079852", + "GasLimit": 14813478, + "GasFeeCap": "4725426398", + "GasPremium": "100", + "Method": 6, + "Params": "igMZ+RbYKlgpAAGC4gOB6AIgTFA8/ERxObGBdX/6k/7iwvfNsfkkGRo5QyXjXdZPbiUaAAOy+IAaABOUkvQAAAA=" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127120, + "Value": "122764152977456832", + "GasLimit": 54318903, + "GasFeeCap": "1288685819", + "GasPremium": "100", + "Method": 7, + "Params": "ghn3+FkHgLV6KhBgWD9Euo5Xz5JLFpSia1OjaDFU5bJse6uwEAIJ/rdobeQNriofO9KONlwLtaEJ357er5bmNBJXmsb7z/PniKcWjDTkyG7/L0AMNQgvfifwWUaNK9v/o3Kzc+n0EwWxo9C+dIUSUCeG6KCYq1wfq0B8a/BuQcOjxEVZlEmJnoX+333qvPk5uVzB5gfve4wxN55SJY4Mx70fXg7mGREU/DuaAWqIboz8xk55NXFa+A2z1diNobDk1ZVgLlAhGqea1Hyy733SnJuW++lJ9MOj57EXYhdz9Hvm6sAJDLuqkEak2Fvyp3j/QIfSDwyPra+dLRYAifbazML+R/6EanZjkxNetbtH+H3pn+RpvYKE6EB23wB8ViuvE61GpPiyAAoZQhoZ0GaBqLBVMxeQ0Dab6VWA8aUVw2BIQacNuWcXSlwiRp+7h1IXDCydjzUNPKj+UHICnKLhnNSNGkS77PL0xoX/B+EHU6jgw2PfjQxIUnfqyWEpWQVm6tCgURBWva8U1a17CB/s9SanDbzmStgMHo9F+3bAga7ItDjSQGGMpw2hLnYH+nTW3wML/WFOrbERGtC+iq5aWUjEF0saEjZofXevlORIA3/57ErsHBH+JqMi30oZQEmk5QQbozPHiAq/xGljlDMfn046u3/pK0jyI1tzwpVkTFRaQ9t4zzzomsLLx5LtMjfqqY2mjDOXrYXifn4ILRycf/jLGKS3FHxTNra9C/DciKQG8VFQY5m1MdB2S4yOMCt7MZrDUtADFJIBkbJw5Eabg9UUi18PrwWE+K5kaEEZuFe4LKykYd+ccGWsFCT/79PkUpOAsSTQhqRfud2McopG8/0OeYQqJRgPgRFKHqeOmQIQDGOFOQRrgc97D8C8w3FEKwbuy3AQXwUz7mtR3rBkoFTxMG06C/T9ZLXg8Ret6OYKyL8NuyahB2LS/cj0wwY2gpmWZkm09IbI1a8AjtkJQbX2u/kznBSs93K7tnsHmM6K0NnSjEQ6qalrYSLrj0nbHr5Eh0YZUqjvaGzag0y5g2KNPZP5x2Cx0c92ibbroTibziF5Ec2nf2Gg3Bbr+pFIMl1h6zn4oZIrRdBvDbzFj35a6CX6hLgpGGP8LIVRpa8dK39JHKxRelWdcOXRbd460Y50cDzXxw1mWvZ2XCSnxbswM11c2NiY3AUGlwqLth6GFijjtYMIkHBdvmq5MHoFB0X6Sp4aoYDjQsI6zTVQjzDECUqhMk2PFUYpGM265KpQUHRuE3714YhCW+24EHbYRt92ui+Kjaj0twMqnRt6WLHrn4viLd64dfv1dYxdXkmEFcMB+hEC1ghz0Jxn9ukmkTUou1t3f7ezR4K+6GWeytvDctaQQFtplCE9SMMF5kHAnKlKVtQs2aVGaXo37ml9MpUcfkUt7xaIvYDPAQ9OaZQg4iOW0m+LtJvTeepbOD/oariWTVWsroOaP0Gz+qj0O+v9gchnMYiMVbIjrxawkBtBrP8d8jBPPDeNAZDs15dPzT5wYXul4QmUiXaDM+/ttX4iKU5EZ4GTxpnxdnxLpNN9bX3KzdlTa/2s+3ElEeW2CJaC88jv8Es5WQn3Y1AT7C1aVhNmEoJ47QcnXmWIprChEu6+P+I+t2TZge3s7nPfA24/yjrRgsWeX4S+JWqUnwlu2YMXHBhsFv63zb5arg0zOLIsJMuz5NMPak7U70rruVnUx6VOfuxvjNoSGAgP+MkvvajDtLTadIjRJPsoGLOhDHzt8yBogOUIPnohimAgVAwO10U1Cbkfma1q793yWy5X2qfQfbM1wVvXtM9IstoPrjFRUV2z5cl7/PSXErjqOpiJ/9IA7EVHfudjUlXgDBYxHt/aFq0iLn6dypm1wLumqOH+h8xLbn0Qge/0bM63tj0f2NfRRWQnDpP1wvHOWIzB0ZdCCghp6sI5zzE9FeqyqvBO/jKrPaWkE3FLc7NJUOtqATJBD+P+zpY1Wzbn1haa3KuFb7WzMi3KTJ+Kl44vYMmidELIpZLEEcoto/m0it829rJsmkzcXJjWZov20rM72jIqo4JBskd8lFMS3Fc4B3g1o/rOooHZQXe8tXx4jgsqqU6uQH/K8IP9D1y0ZAR625hC+7QmxouqH5XTF0EmH7Zcflmh87+ToPAOARpQ9mMC2w0XzSxdC3QCmY8ABo5301i+txWN7eoo39l7+MNtKEcc9buKanDRoiM0FUuWXWI01TQBs1mp/gRVP0+dlUI1o5Cw3YO92GT9lhBwuI72/BHse5CP59/FMYp2hScKQMhjf04ja2/IIqIiMVRBI4fmFEC9drLOJnOabKRFx+dWJ7C+GMw+sAaHM/L9GW2OkY2c0krRGykuD8ExDX/+D5VRuo6sBoJDl5kIupjpAsYxJBHZUKwRdaf+5Kj9RXbuNLWKq7ua3Pg8LSyQhQ/TX1rHzXtXfBDjQqGqn9PNgDA4s0+d1Vu4BL9j+WO46Z8jdTVNLRBO08PmZyC0CGH1Y7I8O1hlM6JtEXIlhY4IhemHBa0O0JlsToid/RrnLdS5FPQy5huxfWY22VPdWgMGKLoahURIhQ==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127121, + "Value": "122759417454006572", + "GasLimit": 56931403, + "GasFeeCap": "1229549884", + "GasPremium": "100", + "Method": 7, + "Params": "ghn36lkHgJYGb3Y57kUkY7fQZTq7awQYaup/mThGRM6CqsauAbwPubLethZst7w9nRGAbG1UoqQzIqEp7sGpMHdElIGgWH3PVLt+95bqwlmHuOTwiMcfRMK7zFtsGYoPmX3x7v/ULwVTSfGk+te7eHyZqfBUYxLyP1FN443UnWTnzn8ux5Qg7H8Pnvqf4cefocHbW4aQtpmk8FISefNhcN/O/saNn+GMKRPmTrQdLnxcBT3mGKYIbqrXvaLBk1lzMCU2eOsbdqA36k+63viwnQJ4B7XEu4r9aohFvqjkLbH1znz0v3MI/E/yVhQyjMwcTGXlKw5MTbFwwOzcHbz03ZkyzaK8wy8YklIFYJXkUsYgFF1optYLi0oE3cyCojVeMvfmz7wYFxOf3fw88kFQdoPuGy4a0oratfy5Wd47VrctWgULxuJ0+W5PWw2HX8lCuqNbv9AuqojdPnKQOtrJpXGrOMIUy1LZewaLdpE8dz5Se1ccWdtMG1+wbl0477UpAYUjmCk6Uod69/tvE9oBSqUCC4K4AHDTrtlauTAs+PfEIBWL31BKK1ALN3rilQoCg4KusGQF1LgwBy/TKy4onUwdKjhv2ZUhYoxOQAYejQvZGGnUlqCK3g4+Hm6bOui0NIDBKxdw/AcCuDjcDuqimJFhyImdJntgfLIfvBxApwZI44nu/VbiIPQ3wWj/g88+JV4DnHONL7LLLRHdABAqh8Rc8C1pU1JCU2foSO1C27uIGNCbr/mCId84owAeJfcW8bsUFajtU4EWh9lJftUrBYt7Bz/tAKpU9fVBEB+XeQxuKblgiw+JVK1V76Edif1KLbj6fed1h7UiGtQFDymn2apOcaHDHxjmApFcSwwco3p8KZp8nsAbCeUdBXbwRyF65LEMudln+BPrpIAfYbFipwnBE8gSS0dsr250NUl6wEBhVoO4he0c9Dn/+OESy9lceSl9RHVyYozh3MAyg4qhGoy6+vyaYHeYdlflgu2MZmx3O85npH484QgrzOvbKCln6xK90oDN2KfYa8DBGlPOgZfz9k2pH9Qyp0AlNGQDeh8vqOlkppBEVGZzBtQmPO2+PY9wfvHRAIyIEI9HqyhVsKCONXV+U58lyGBG3ObKjJGEyljM+6/zzsHs5IgT/z/kdrFYYvWjVQupU8dCKAoR7gbwLgm4CpjgjsMO/Or2x4xPQGtpegWthB8dkw9d7LOdz8OqpHB9A7E7sQz4pdCUtbwOm7Vp1eXGsMoAFEL9CkjcTvPLgtx1NY9s7T/973JYZ8X/CqxzXJJuhVfLZIZKs6icXmsbf6uW64ATTclOdxxk2zCMH5mb6hLAfttFUrpOedUSa07V8rK85VSHV0td8hiIrapQ6EkIi7bRTlnKha7p+2wAYq7MsFVxFOLPD1gyEXA4k/k2HgCK0gOSx84mvfPjkFdsqOe71Cp2KiphodU2CB9JGC0k58MbvrtyU7nbfOilKcu4RooxmLFza7hHlRX7PyuQ8fYqHchi3TJu3LK1JSNL6VvgimDGLLvmI+XuyaGfyXgEYKCzNw5w/Dl9fnhES/FtU2TcyIgMkbquy/RDZqnIvK1keW7A7edXMMCDQXCXD7rGDK4d2buV+RQnLLmgrg8DROPwCaxi4y2P1BX3e2LIJbt0BufeQRBWzhCdVQKWKrEb4BPljn9WIxtJpd/Ah1dJyIQ2BAt2PWgQThal+4pPY4fBS3pvkkA/1o+e2Gj7799SUZQMEFwGqBvlodRjhdPr3iDDYfhHkl0kwSVBWvjzAG8geUp8LSHrmjNthrwA/y39zax+kFRtB9CjNM/gKbaKjLKBoLnvbJMBad2cmaFr3IteHRSJRJxzijMp/NdQ0h6Uuo/RmXmnXjwcqNeMAFvHTjLYwo/7zMlgxUAKx6vUZNTFyqXPy+daZex8N9luBbNvgxhV3D5Jvu6n2sj6rK/P/mvrmOsp5nGl9e5zJ5xzVR84WE8b32q9TXIQOaq766izLZhq/jEIp2hWIRtvrMmMQkK7rGJQApo3tEN4Oerxx/yNsfEgiOegXZwjWgYMfjjmz6RFqvcHFEDGl1mMygLJ/bWiJl8O1aFi7ZcWrFaEPjzGRfrVRQ6g8/3BJ45UE1WySZgMAGDNclS8m3OlzltoQIjB0NjOEFNV9Bu11xKoxQwO3Z/29Mi3coWlkKgAuu41QQ62aLF5eX8hEynPi1GaMlkK4JIPVTpPdTnjt4/Z14h62kEPspmT1fgehX+sCsszVplvemShONSCQG4yLBK+nJ1mvnNzfFzKi6lXRMCxvTwoM/+LxfiT+M2CbD5ExQQnIoTHPUeUidTbcXv8jEu5+e7wP9WL0+7JmbjS/6FFSRJE3PIvIqYPO8gxE5M+KjVOjKgdnen4iGocjQIWe7woG2yeAhJBAS2WPjVWpNJDcJgx5LW4U/vzlA/oYOzPUhCN2wjublGnZtHhZELerGxZPtLoSyh+YZYhlSWp2QErbYK6TzfKIBakDPXsb8AdnjnwGap3aJkltjHPpHyb37G7jWt0LUjUyAW7RxpWIpjIVgnX+WdMB2n4IiQU+A54kHr0lQ==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127122, + "Value": "122763624317044665", + "GasLimit": 59543903, + "GasFeeCap": "1175603151", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4TVkHgKH65F43X4n1vv2O4xYn4/vwmdFOdGJTtbweilMYXO4rlXiZy0gN1E16ADyVqVfnXIuB4wH4w/oy6A2z/Ij+MnVAOAIJ6rujhiFBea5b/J8zxYMNRg7LB++uc5n2KrCf+REn+ClHwCBn9UlC6YdfrzIQanumxsgR2AhhDAl+2z64I/n8p2yrJNbJmNqWOrgk9KlsT5yIknVtC7kCVgZViwxT/1RKt6+D79X5NAHX5vELdDzoUL68/X+Pi/CfB/kR3YKhcqydabZxNziTTZTz0eqcdBUVutpAeIDIyCd2PMQRsdIP51G6qCYhnW6pk9Yw7LNkbSywaysE+m32TFGFCkNVxcV6o+0N01ePCGImIQi92etLHCKcyCVVlNWNvBLZmBfBZeJHq1SP+ZsaWQUaPxxlca5IOsgZBGMwHsJSjCrejkgt4W1LS4///t1hggG7bZROzqT8ZAYgSHoCj/ULvWTC+ogjihg1NQ7ubNDY6c1OkzQ52/tSuIGAo9Ck8S1RVab8VyP2g01uMlbC02MoDgkp2PqhtsB1AM0vHbnbjkdWVDTRj6vGtFkUDwqUWMkFaq/iBIe1y/dmteGci06rLoXJZX+rRgCHzb9PpSylfV8KQqLYs+QTbPiNOEHgQ1+jMwlVdbkrOWeMHNsB7IHpabcdOhS37Ypy/c3eY4ZMOGWoDJQjlmY3eV/wtCBB+diKGKukcxLOlfWnn1chPUoZiKZ7Xt0y4jlXvml3BBEYbhABQz1BU91axRoAd7b1QK+HfI3G0q2WDjj6BHCWWY6ZCKX4KBzHs+z9/vlC38+pPR/luij6oZKPBXzt1P7fEdLt56ZstrxcaAOB6a0fAHs3fMAsEgXRNDebI5wgoiicgeZqTQjI53ok1tbkohxxMM1vqRTNgNj7oLwNtCbKtM54Pzxjw1EI6kWTJ2VA4EJntdwnKCpoQU0cY6JHIz8w2DfUeohxXkmNO35dioCePZR4h3IFgpdPSZMZqXakXNCdfw5bKUMKDZoaupSTeBnfawCQlKJBZ2+OSNnUiz/sEZg9SJIfloTzOk6Fe4DKAEgfiLJiBjNnXaebqu1dc6acGhcfFLdUAF0ThrW4o/pVwTPmFz/UZSYvBT4NDLkPCo+QsYPsWjhBH887JPz9o5Sg04m/ZhfFPWvAZpJcBmlvGa9WbLi8Wv08NstT04TEJvqCmIXx38wqp4zY31RDxN+irRiZm4mcPMI2+xL4DoL8qivm5MGICKGZTlD5lP91I8uoHAQocVImTAz013Rm43iGN9RPJqppBHOZgiSMGTGfercOCxxeoBxwXBzncrn8SJ2veLsHnHYq1lIqy4TykBLiLdX95aO/pzZ18CrUj1L2VTiBNd2lSkZopxv3Gu/txkq2uee06QpYFIcE9EIdB9MWbHXEZQJkH8gJH6ukOPtlFMdZJgCdEL+nEGnHuG2a0Ne2/YIc7AlbQ6jK2ic/mgWGVQ1GJKUUDvYYjg8LNBDpOxmUvc0qenPDp7LECVFOpAqlxumBQeeNF8FUV9XlcieGLs5saIM+jIbzB8NhfmIl+iAvbP1xEpMUnJKs9yA0jVKM5jglv5+EN4BlIP+y/ZHRJpteH4HSMVyJIrBhhzESknuvhHh9e7S2JTMo2aXQ7bjr34vQrx6lgatg0fuK4Kqpgyr7hwr+7WPjNBkN6TeLVQQu8NxvhsStHKJv//3r0CskDm00JQVT541wAAVLAecZ68Jexo0YnE3/YQ1r+w8BobfzeQFi/wkCklBVVHzpwT8VyyVTDFGcG1VwcV/ltdiZ7XQt1IwoseWCYUHRVU6m4rfBruQim69TzIBJQtj1fcb5pwcCCeHogOTqB2iLK/7Xsf0ZbaBIqySOsoL425g61AwWCmGTSZg0DEHQnMfrzhRT38ceeOOQ/1HpGfDRBkTEmlTzQQFLsfxKSMhZc+mQZERNbZ4+6wIxX6x9YroBm6L8tFRXMiDaq/7xDcoSO/Y+vwH6/YLs+fnd6q80z1jMTQIrWYkM2Y4jT/XX1W4dgT78ez/sGoZ6TU8BpQ+jEsP0GDBqEqT9ED96p696BIf7kE9wTG77h6LgemTvdobISx3g8+gh0UwL9QLbcd2Yz2YZ58FCI4DUeSprnp4DNJ7IWouEFBDVEYmKmpgRNbrkogg+srIsP79YHY64KjGxygoaxjZ95BUbfq8DT/n0Te2TdzkZl7i+AFJ0nXkqbZFhHqYX+Qba0UXN0eKrs34APmjg9dCVnJiWeXJbZo5nWgGi24jxPh6fU81SMrShDqVCk9R8blL/RsuRFNidpc1Nrk3hBhZJOKtAdAg8vIs9vSzLE6Hmclf7wsqcpJINAvSlNTigNKCzfX/0Hdw6GvNf0ypFFUW0uJcz+ySpp55DsonMku8p3xtQb0SsOqlg7ApcKLnmHDWNliQ/T3td2XU6UtnMm7+0qANG/J3uYAaS0b8qgcmWukufNsH75k0tkHHa/SdEi7hXdsLqc3wOYUs+FIRxS41+o6bXCHVVQA2LGjQCZpowuWFN1sUNf1qoVjHI0buDUDldFpMqHj6EgGm/5q5DCXY5XA==" + }, + { + "Version": 0, + "To": "f062619", + "From": "f3ucf2agr73uvr2prinrjfub3unvftrjbafpk34l4x7vwjw2stvos5ygnksfv3bghgllrcgv2sfjsaucsssb3q", + "Nonce": 127123, + "Value": "122765282966544619", + "GasLimit": 62102653, + "GasFeeCap": "1127166016", + "GasPremium": "100", + "Method": 7, + "Params": "ghn4N1kHgIVd2ZMWTtxJmMRhNAGPQ67RzVCYXuP2ojd2g1XqYAykq3aY5PO0VQEjEL+l1d216axTUFxw4QJ7kbctUUerktibRMUP3cVYmc0sjpzqafb9fTS1ro2yQ+coqC7SfHcgqRCFw85zeC44+z8pC8qq73LQxA38R2ZL8cgp+kvko9gVA029sExKyPV1YGEpNlWoCIng6TcXgpv+0hE9q/lTbGbz1F6/Eyev/jQ0bWxEkzAZqGYztaGP8xq7MY8q5Vgu1alqtap4a99HnWZHMiCOMPuNmsoapf0tL0OanhXFV/j4M0KycgdVO6c3VI+zlZMnRpLjG9cXPjhYlLZ8lPiKZ++H/kmRqgodA+7zVR/WxwJXs1Rl1aDyO8oyg4thGQSSkRBCttgRsqeSy8p/aX5qpPA2PKbJhAv0RM3vDnVs4NqWqVIbrDuGci6tc8BkoIO3yqN1+wAMCIYoTG6cwxPb6LpoDhKOnQaPDpfwL8dWNW04xWGU15kv7vh6KtUnLuFTA7jaCXCJn7UPfdcE2uvQknOFIpmBphVeF/gIibaPdp+dUfuMpRNondIkUANwfh5lXqopYFvQrYz0QFNy9mnA2K5149SiWiKzNMhai6AycIv9ZjhN4NlJplKWne8pZ1mEkBVUKxvre/kYsW6sodjZRsWnbyz/kZVz2Db9DErhrZYQ6suDraP6I7K5dtpstmhU7JEfmLMnyhjsJaJ6bn7lEAr4EBQrqSf4nglJmyjco5Jm4uh3oBIuoHuRo+Dn4ZhJVK76s3yPpRtqnpJi6EFXiDHBqXpmhOHsTrIRcbqCf/JQxZ3ByjF/5U+zSo51HFl68aQlzGfukI9qSyR0b6WLr4HFJRmcEwnRg7vvypgbpdqpPahCdGoYvKpKMJhIUGbeZw2Os2hMv8N6Yj2CM+cghhgb69Awc6YPvzeziUnNO4Q3FfebvV6hAatn0xnhyQ6wK7aCG2Ui/HAM+jyrZkqEQg4DlTvx9BHyFTtpWmNvLZMVz/wQotUxkSReiufCakFsKYqWzfJAoGSQa6ygI5Dd4DCLGSnHUjEZIS0hX1nnd3v/QbdZmABIRexgAZATiGvNao7dPPx3CC4xtXRKQzhnH3BkpKtIPpY3j84RshGdD+ueoccKHSzVGDAB8DhDx4fLXgUNxXP9ANrsh4yLdRbF78xfHk7RUsjAHTA4hzCQafEAGKngi2KEEieXF+0g6SKyxZny1t7R8Ob9wYKW2lFTelYKBNMro2noLEOvvd16RCdx11SyUu/5h01m/9ZSRy8gCoRIgV/mPPBY/AwRC3FbB0KnyBY0ooRdr++lNOKpv3V2vnj3KH2Nnmbg2LZjChJFaLCv3jBzE/vymH9Kao9WKQM5C6AiYKtdv+v137u5U9qe7S42kdDtheCsNuynxUojoRkZTsM1eaN/YV7dGs3oKy95pmQ1QFdCZ5YCcra9TlaxyQn38z8n2UrNBGonq/ageob6sm/mG39gUWdssnFwvRv9UQzdASe7jbRz9iQqFjNF/ZY+b2/y6c2LjqwOs9tMiLfYgdg/LyvbjjOYdMBjHzQYQ0HAIRofVjv8zxzDSWP4sMmaIsK3M6yL0Pcl69wGPYj+fvCXe6XFdSHnWy3Nv0nOCjTVU5koXAMjc/Jk3o6UY5CTo3Xb5yd37y3uurYCxAymQdoXfI3eIFYLH+5Zh1a7dtTl7QqkubphO7G8+PVvwrg6IHhEUKxP7iydl3NO3bmYDv1p+lq9Q+8M+4hfIZRL6nY1V3GEl5WkFsj8bIACv1/4HyPx1UgoKmyLrhXmaq2wDfmGDJ5vDs/zuiIfP+2m5jJIlchn1/xCDTXOCAA4phOIL3DOka+RF03b+tH+7oEe77M3KfKo3yX5Ua7QLP6lMINHQUzs2JJHSD540iEuhG6wWGUfF0VoeQeoBgB0EwsCVCq10ixdSsKNp/5LuEM73k4xGhpKrLn5fGPO0FVo30Zg3vaP6JkYkCo+WciAL6OdO7yCfsc5slqgpSasSHc+Owd+45QmDigtsi7+hUi7jrO8F0qsxJ8mTADxGDKmTLXwEPThjkjehn8nCbBYXPVPzDiwEyL/wvjglILAjtImmZeRJJtQ34tN4ubS/YdHE6VPRddAyMpnK9P1mCgKsxSVAKSZv2KhulkS6xWkZSMcYiVauMXdVYNh110tD067Mg/k7tnGJ0kA0uxsnJgK3uvRYVn9bru/Dk8g36BKGzZSQKrNoxL8EwTeDPGgq79NuqV6Txq8DyMmNKc8U3f829W5csEyNcMYOhrqFkPAg1qgTFMCcWN3zsR1yjaBZlNbQq7YXel7pS43NLbuPvh0Mrs5+dioYWPMssQEnZHxXPCcaeK0/uhP71Ro1SPxN76WW5mdHTw876YVxcVAxT+Xpu+V+fxcZ4zftAhOb6aTgqEIX3hfUsMDL3SukbFWsliuRgHoUl3O8GMvPRNlPuLPJZ5gKSRybImvvHUAPu9xPJMxAd47KUU1oJSlBbgENNQnnaSVVQ2/qouHITz34N8nuzoXkioZ6cb3uquoXn6ugs7AhJqpFbB/oO4fb9mbhvY5rg==" + }, + { + "Version": 0, + "To": "f024066", + "From": "f3qawdlt6il7unbnnby47325tpv24ikuisoiikz47njf3fkiyrqmvmhefbquqwsa65lhowdc2ynoqo6uzj2uxq", + "Nonce": 21320, + "Value": "122768933700265780", + "GasLimit": 50853553, + "GasFeeCap": "1966430939", + "GasPremium": "99940", + "Method": 7, + "Params": "ghk1a1kHgITLLBcgLRM/L5HbIn2C6kyPHKWUffg7rkJ6/HVrQ+U8z7YqUGz9Lkv+Fn7rDgVc+qJvOpEKgvgr7Wwi3Vbcgyso3ySyfui47eywnwJ0CRkdZ//m/uxB6ijFkDYrbApE8wFROwBxKAc0vjKv6ArXDR0NHpArGmCrhFvY/YG2wqt3TJRdd2nWwot4NGwT8GDRxrizfgLbugbVEfmIsmTiiw6yiNFOUn6Rv6GhsjcV4I2ruk9aVBOcWE5lxhm17QuFJqBU4tknMuSluj9/d3dI/fzyu9/DbE3lnL3Hw7JoKnfp/pGzrgmsZQJ+G2s4f5JCoLJArdwNA+3ZEhqXu21a1MBuqzSQp+EP5srqTmZ7fjqY5uaqYISCJFjlkU8pLzCanwnxydJW5YDudcyqkL3fj8l9PCCSGbJrvJpe1HcKF+AcAYVzmqGc3Acc3+DUSMrBFrE78ddJSN9A9aaMZBKSVxokW89x27sVwUpIDk/iTpQFJboDjc6DMIifhAwmJftUo4r8dd/NAQ9tSKgD4Ud1waIhXqolALkBSBzC308Aj63BmzzMdNneQtLOEr8gqoe9jYimGjIIuJ4kEMM9uJv/VTsz3Jqy94cWPtEngkfE+T53VEFCapg2gnurxG/yo8ns4BRx7vkpXRcojUCVPcRHQ9ZdOnjWcGalmsmrr8EjiJLFjiIupsjwTO11IyDLh4CiqoiEgJuJvgu+4PSlZlz+x0+cx3Kw13T8W+SJvIhBqL0nuY0CGGevm1KZrV1yr12YAIZCoVIiYBm3C9xNfHSgCED7MmTaBN5MxZA59aFUk9cSD4vugK2DXLgAHz7mKfPU8JPFTGB1TysYv8eo7wvODZFUEO1becAtkkqxD+VPtoPbMhormKmUMnxPSguLdtXxfwIoJ2oHD0/dEnZLpntcquKf2aajhkJdl5pTLF0qlfM50eWtwSsZbKD3eVztOgyKlYwNwHk2gMNh9+jSSQ3U9EuqCUF9oom5QvTI7NXkLJ4m5chXHTZ57M2XRB/bhKh2oKNH6807j4JKhvSTCWMH0kwZpQa6nGnnRLdGToq3c0PEhw6D2z4UM2yvxvAPjXAkSrbvlblS91gxSXSM9WCnGhgCNPtKdUROUPG5u4bxVfpnHLkRkmDSvgBG1RyB9YRENAZAXflAnSBLFCNCjpTV8fDueG6WZ5wyV65VBN6DbN4dfj91dKKybi0mcj0ntqaPZ6ruYG5YSdLBO75JOXOvnMGKTzoY96RFelQzm9oGEXHrGygZ37Br/owHr/zKV4kS9apcWhEWiZMmWd4Nk7WrVQtWrclxSVqUiRyxsk4Ilx7P8sozrSxqpS2ps2Xzi5aehI1vVdV+nvgCPOcxhBKcxvo+Drll/IbBB7NUrABMwgh6JGjGQtMMrvFc5SBjGaPH4xEd8OyQUbVVrr1V5tdbY1Sk0uV7Qq78W34ZbX60Chc1zbEJdiBatuTx6WDsugqDJIejp0pCLlCCWO37fQ9SSlc7XXAZnQTNlOFXJkIY8RnkUJAz7BGcRog0sSm0OtMGmo3G/v7kFwa1iQAdH60OhEZMJtJvoqhrjifGWKpPFBXNK7BlyagxTbugV2VhczUBZpTNHb1pk9O+BXlmjSHPYbIBAawI64vuOZvxajVLsXDi1D/Jw3vsMAirIHlAML6dLhL8c6fJiwUDOKEjcRmZRIb5V0PL6VucJN+bG63ip4tHBslL5LMBX+fFI3trqfaG4qkgqAMDfeD4RVXG78uZqi3X5g2nTnjtJKfIARDYl2epVKgLJntslqAgK/5G9W83xbWVwAuoVv/9QeywSzZDYEwBIDA8a/i1U7JJ6B0E3ft5uMfIbEKR/7G/44WtYFtCN4cYK/SNL3m/+B2BWO3ESNWNbhtmFC/2QuiBZftPbw2St/G+EfEFmSrKuU+IqHbOghTF3WECcMd0ylvSPsHOAAJiGBYvR12MY0tesf0gscCeemFuhBONxhrQa/eJ3MJdA4Wd36MhuzMv8t4YPWKBoxsnuVXUa0gjxEYDLxuKanXjDI0i5adVPzWwtMuIdZ2XtKDBkDSk4o5nP6zu75XMjIlhZ39O62ZYgiGEItJLpeS1FuZaw9+98WaAsBQIb7ijyo/0jjN5zSQLcOfYFEBvo5vBiyEQ2CJvXK+NK0R018rsd15Ae7aTb4VjMOCMNou84hUXWwtCXUwBYYAgX1cdAy1U2pDHGlrC0qvwZSgPJhqosUPXVW4Vy4NSl4qpwC3F8ZAw/w6LIZoscZXgIk6htc2eLQ44PBsWxa5S5ZeahUCPgWtBMRSKz6yjQsXkym57h6iwqcEzWEvGA063Pk9LIYJHRauH9dRpvXIN99NhLFq66GVZ7aDMuyyD8H0acu5vxpI6gQoyRf/ctumYfnm9nIS5Y99tY6lgUtxoQGsoO6o4MqlMB8PjngPIRqFPZuaW+ATAZygBOiLOulhzTDAk8V1lpcQoXqtJmC2d26hJTsduj7qNUMVOmFzYvs0xq2E8kJDawQq0KXmkLnUeteprp7HyzsYkHC/j4eogQ5JJqC/pngNvii5EfT39lK281hbyAw==" + }, + { + "Version": 0, + "To": "f070501", + "From": "f3qc5qsbj4urud7tnd4luszvry2z5w3fwprggynnyxdcyyma3cvw4bv2vk2rduma4kbnkwruotgdisgvgmb23a", + "Nonce": 37022, + "Value": "122768507334115016", + "GasLimit": 50947606, + "GasFeeCap": "981400382", + "GasPremium": "99446", + "Method": 7, + "Params": "ghlU61kHgLZcy+Ya2CWp5QVDLXgAvWPt6iY7fkLgCOTTUD6CJeRdM0bggFBWxOQCzbHffHtNTYeqG7+yI4TJJeXYaebCeFy+US00wSXEIiCAoZEPSeeFbT/q4+3rKDNCBDH7EditNwC46qggTZb3uP8sC7MaHlT1IBWqh9Q7gyPix+mWG2Hm1tE4LHZgQkzJ4tR9LsO/c4kFPeacynMaN5po/8/ZI3Tu7N6Jm7qkI9VWtr4Hc2hOUX8oKVqzOOx+2S//ASRhTYVaUICTQXUo/qcp0zihJ+HEp4EX72Cxh6TvK/Hl9cA3fgBe8VK2lETJcpw2AFXv9pRSHIwT/LpITvVq/6lPoFUuHLRFdsoLyv2SBb4Xt1CuKM72MFHVJVZr4jn0UdZG6AzDmrU4RNv+Bt/lS/XLYteRDJp64okJsaZQEetz0taG9h8RLon9w+0GlfyRjC2Siqtsj8zGIbMAN8HMYqA60slDhWtu5ru6gRg+CvfAJh4nN4QfHocLGal0hwU2euCXsIRvB8B483xh43WfZoIH26zUYvjpqk7cqJ52CzPJuk0UKKODu1CXZ637YLioJPsS4Kk5rkEpGjXGrLsYqS4Alp92KFLkrNJCEqBbzzYA6bwWT35g+5ujdmaNlOZl0CTXYhJB/Xo+HOaH8g3Q5a0/+WAzdLo1tUiDyjZgpUl2cB6PQSEIANEYZnN+IsyPyV9jv5Gx1nUNai8Uh9Bb15FxSWP8JL/2QvCNEyT36e6ztrRB+8pgaFqMPH/KC0wcOyySiLX3pNuk9gby5A82MfsXXeJDDJ/yyDCvzB+QEbZqu2Jiw9lFUOB49ZzgNA+rCm2RqZEbPoA798lRvk5g2Gp/qBq1iMymQmtr2jG8jIoT/3Dyl/xNgTFJYlmyn1fkQzKskhQ1PioZGC6ZqrsN2zwupBA5TVbY3xUN8XbCrHhitGTduOHJJdU6QCi9P3YV8RLoXa8iBlHdHVb5IOEuodv2KprPX92FkWxRs+ieNI1Q8a5PYN+DXL63idtdxpC4DFOgeY0n+4XU3ADfIO59sFUWbmy20Zsw56r9i1p+S3Nu3Eg4U7Xatg3vvlSSh2VWyU9Q3oCIgnL1J/+ym8MAC+3++ZttnQp8nIP7Fdj3zgDTjPJ9vp2I9JGAn43jkPxgGGE44wzHW8KNEc2WBEeQ1InPW1HxKRn3hHLxujUK1uQzhMZ+UtCmBYe7D0iJn0djL25nkIl2JesXhiKP0Zpb0AR3cxvkoXlQgU/1B1l9gIDap5BpQ3s+032aTgy4/1U/lw29bISUqPemgFcjOMA0lfhlVfaqQXQjqEgA+Mn7owOIkfZo9D8WcZMvA95E8lx7mfOXVYKQYI82Bi6XBegI2OVp5sUmPZ4M596VPSh9V0f3Pse6mdBq0wer5oTysxTVpWVxdQ1JFxfg/eoHNY5caSmown14Yery75hV+JcIf9Vrn4NVazDJN/aPQmTwAJOZpnP2OLCJS1VKuTTBVcJPjgQRW4S463zWMsDX8Dq1qPDZbC4zUTrsgakJtfX0GRVF98nO94m00W9NyBZB7q8ygvt4y8w09mHPvBbrJzmpA19v7O+TVFW0Z8H+xIN1aR7iHkEYGIYWPnvFKLo2BGZZsmlFi11pR4rWpUQeSlx/3jk3kkQ7sgNcLJ4ZMviidHL0jK400xlmEIBfMszs4z2Xq5rgG4hVxfItsRn8yDvnx6y5iZgte6BYyG0gWRX5fQbocGZ33oos2WG6m0OwTGq0t7u3QxC2Q7dMlZ6mti7GZiO/nMty40QsMuvIH6BpVIe93EP83aCFHqrX7N+S2nBgrFcWsUESdRx7EGMGzAP3IhP4Dfu39FDak36XSfcjSPVFlPqgp42hA+NYppxvp4QLvdcgZXx6x4xgAy8/Tqgk01He2cHqx65g8+5XRkPx2CE3vo2odQX1u7k2BqVSqpSvOS3UdiEnm6rggHWdzyru5xGSJlEtw6l9xc9yRjW8B3M1o63HW7JxVTVlvGFY5Eu+JPZ03sQXfiDQ+ZEvLlMgcSIJjoCFx6SAbSYiJXRk0DBr71FEGIKfc2Bg/aC1vd9bvl8AJuQM5Kzf1hAqj5vKQTOgV6Kj4rROR/Eq+FO2SBGBCq/FdoKEJpET/sekQND8Ag5sKSqZnPeHwrJmVkZb96qa0ysy3DFnFfG50skpU7ZpChY8ZBEwNT57jC6uXj9IvhiCUg5IKetIw9hBVgaE5QyASGx81ZDiCngopA+PXJjoo+MORbCkB4Q/gMZrrpWT15+mtOB6eNib4JBEdHCcIEC6oQQGY09KvLfRD7niM2EdSBk8Y5dozEKYWhA90bXtiDbBDNA6O/ftcMuSmBTI4fXeYoXKgwO9t13snONT9k6lST6PpZL7MpWfQ6nO6ThH6+HgLyNeFB9X8KfNH+OQfr9xYYJKoRxFMZLve9fw7nOPXU6tTBTidzjfl+vvssAq1I+WyijFQDDR5xogsh16b6G0EuDulLwrisOa7jtRE5Tdn2jLM6o1W56NqKsu57iLNs80TPuhdbUasHVKprTdVIVkqzWfwEJtvsdbhs4v7kNaoFWU6A==" + }, + { + "Version": 0, + "To": "f056226", + "From": "f3rwocizqhzxr6epnkcndektzfcrhpbzj7z5xaqpihkgrfxwqmwfic42ttar6t7nekinfwqha3soogqa6vagcq", + "Nonce": 26576, + "Value": "121193649549989127", + "GasLimit": 21913176, + "GasFeeCap": "1140866116", + "GasPremium": "99479", + "Method": 6, + "Params": "igMZVQnYKlgpAAGC4gOB6AIg2z9GfUczIzquNDMr3MEoPsGPqenClOKvbQ0VbaJaOEUaAAOxJYAaABthLvQAAAA=" + }, + { + "Version": 0, + "To": "f017193", + "From": "f3ucs3aul2hcx2zufrhp2ltpc4gxzpp2cdees5ti6lqeto7ejppxnjuoj3c7fa4vanhzuqv64kvddkdb3chu6a", + "Nonce": 96652, + "Value": "122677249059697153", + "GasLimit": 51508601, + "GasFeeCap": "970711668", + "GasPremium": "100445", + "Method": 7, + "Params": "ghoBQL66WQeAuXYmj67ZDPqfFxQqvo2abvAeLI+6cbe7bcnxHwQ5rVR34vjHwzdAxAb3/W+8w/sJiU5e/BHzGDkpWoiPFl4j91oPLH7GE0I9gNYzTKF8Eu3tZm9KFsLUVlHnOqjErWMECSQ08+14C6Qgi9pPsOOzHbas6pvLRtnYZi8o6omy3k+IgPD9gH3BcWu2AHA48vuSjkMepEcxjIEuiFsi9DymiEPJ0OXIXBICkikL3dRwO9nzviUStOOnu7rTxhDpfWhst3+UIvmi2VOeoZfL9NFERFq7L1cN1fLYxwbMozHyMAHwT2IYApp6dJWACOqUmHpRsBFnTiR3aoi2U37D++oBUSQ7346t/vy/cS4p8vxlUMONlmNBk8jcc3ZU3HgtBY/3Co4fdqkleuBVFjDHKyZLOXnJF5u6Vfz137cibNrEUjM+T6/6YWQ2kcr1T0kPWKQTkhzLJV/zdsIcwi7SozhwGaoEIEgO3W5QbO5Z+5g5wKCH6qhrIgq2vYzchC2otmR+r1gGvqlzbh9zOflLSUl/XhMc7oQec3JNZEX6ZJCDXVUdlbmbRtS2lMyq/WW4/o/PqvNV9R8Jo2eLfxHcoEVjgFIBRt3/nqDmuDySsrDVlfIiTrpI/XduBZHFJ24pYq3WAiyCGcKVJcP403ZM+IhIkv7aOZvTRvXTpYYtEsnVFVkqqgvxmfvImGTbq4XL5abjjmupeOWmKStB8c8Kvv2FPsp+WEAGdS3FFbfpEWxdHJxPO+OGFB2OPyuEzG3OZ3hJieswRYE9rd6KYQHsPDllmHWzeioXbmsnYQ0ZKvSYkIGVkeym7wKA9ZtNr29xdxB5j5jRIGxnVqX1nDOwvPMlzv09MVinxKLUfQzS7NMZBOJUGPbmTntBPoAYNMn0GlNlAuJgS2PZqwtFCzyxu6DbgQBEuBRRs12WGcDFopT/Q0+qV342QqrHsj/E2vQC/aj0q40Pm0ywK1ONKucNFhcJVKbzgwWrPCmd1Z27Fet/OuyeejAndB/5LaATMlxP4fZAgVWRyL8UhpT2yoEaAwqj8pwpr6XbPfePd4ErLGmzzI9zPHmi5oTClK2PCxFn1khDsZFljC8IbnjPaNI6+Ol3pjsF/WhiBiHXbDEQ0yyP6vuCluFE6XqR5K351jwOMZS0F67sgWneS3PdPbYUoEZ3aXY7tOZ1s4TqKKGH+zuDrIzp2ifL+v1N6eIlR9/i9RiBoqQ6sSO9KMDHdbMiKVUn46EvjeqiRZcv6hdema2QTJaKYyTBkZhsVFxvR2GzAO9EgkWu8mtBBjED41jrFtEMZbjtlkLOYP/nnxZ5oBicvAgYye+jWRFrUBreFAo3lW1JrrzmyaYRYQbUcS9RPwOADlX6UWXawMnV/6GUky/KxTkUf0vizlhTHUrwKJwuBD7oCYCmZSacJ90ojV8VCN564J62fqZ5kcLvYP3YNwhTtO4P/Tr04Ia7ZGgTiQQnTq1DhWUtihWuTiQftFErURg6Zvpi2V80SByBOg6MCxhM3GbjwaXXfDAtengt8lHtY4sDinpzAv3eM03HoaKbmT4gelbJbw4wVQXZ3RTzr+PCPO/PnHnxlhbqL4WorNxCKNX3hxAP6Ak8caUhNxEcmCTb5EwSieaa6EnXHJE7VikxBdUJ0jOwrpH6HBl0ccb3tcWCB9oqJ/tICtxIvu3avteQuRqAX3VcfqvosdQKoCQoyhQU2JWpXjIVfUxd2XPt018ZgLcxVLx+tqtwrLZl00eELZoGGyD9jlBbzuTPwzM3iCBWwDh1oFUbcrVV/AZpJqIZmOrCQp6xJ5P1Xc+INb6lNQoXcjSU3TJuPxMYCySVWxLrfqczcyEfW4mF9UIcsCG/piDm9x1eP4zbtNpmxTkT8s6xXjm2xI+PGpHzjx2QiKX9HQHbUSv1bztqLwh/6V44EQfK5LC0UcNt9jSHxqHKf4gFZMEhzIi6fxF04jTv6dfX36D6d5MNBKYmoIU0XNthqFaa9R5lwG/ln/k6bMthVIBMN17e1PPXludixOq/c+SYsJw8ANmd6cDsuAxhMPdZl10kM04sJEK6t4OzwSFepjxc/ZBosL56+1eYcO2NBo6w+eAPUW3pt1rHlXxs2rvVjvkJxEP8+Eo8At9hqy3iHqlCoOx4bMYjDiqi9d5IAkDvfFrqICnkGwx9PD8/uPpHBSbxcaIQNomHVQ1mGxs8MhltzT0rOUfdtfWpxQ8r/4xhTsM1SouQ3OxMqPWLG84bhfaaSzgEup8Ul3NGufEPu+2TA0IX/ppj4sdYb8w3fjr/SOkHJH3lnMzG3TQBFk/GoVaNlV427XiWCMzxEMhs0AyEaZ7R4B/tu0X+PrOaGTv+4caTqPwBhZjYex1OvK4XlmLl0gMFhkT6mjPsAiPzIyI6PBqiTElpuh5KE6IebiJaud7FYVu6kym/W08T+5saA4cd81R2gL30QtuWRzBf8TcS4FUOG/J8TaY0hANfY8aGEPJZ8TpJ3e9SGtpPSRZJk+hsEFEZnwB6yUZbDf+7bbRM/mDh0W+J1RR1vbHENZ6L3/tyaJrF7o4zEf/B9Jgu" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272324, + "Value": "122697968289429455", + "GasLimit": 62699293, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 7, + "Params": "ghoAAlKSWQeAqiSUjB0UKUUV62zjwxDtRGSOx0kDQy66tGug6fVAFwHHaw7R/K4kUmTlR7lueI4ojaWq/kYAFoAG49tLq5X3CTUHbUTyTaDuRZcloORipoUjsOzDuBGQazSC9PuRxWMABYaRSMksqvcUwsj5iLOKVO2JcSFszofMtc2Y+a/tLewHRzQ6GaAREGXNxp0AFFVahtLnBeoeA6jJhmT21VIp7Tef2z2+WPcfS3n+fquP28s88OZcYP2gxDoJiLyudHwcks5uHgrF7xumkqQ4DxNu4axoeBvEyRtCqGYqLE6Ztmy6uhn5KuNjQp1PEd4RJZXmpara+OdlaT+WXn2yc4VMkGtACtDDfm5FvjHsNKTYnCGZqyL9XMMv/IIwe8havob2GMRQXn3p/cNaGCYSDrMMx0dqDYjw2OmA0Y6UsKY0qKPdTD4q72FtZa/kdg9KtcYvrZiO9c4DL5bfaUTj0P0fsv8gzjjIPTobhSjo/UnMawqwykI1lGriQ9N1+CdK1pGRofuy/Fys/Hkw8Hjl79ws6gncoTDlZcf9a1Qm4/bt7nTgfpLWhxLHIcUvWUb+QlW4jI+hSbFEJsM5nWX+gBBR3WH4+C6BzLoaeMVB72bq9bfjhibQ9AfqQByhHIjPtpdeDOUSBPcqqoBqtFdT7eBqRHB+V0whXags59PGvZ4H1IqyahLzOFO++R3i1XjmkZH9kE8uE7MskLPM/2QjS7owV5GRlphOofp5k98E3e75JBQ92vVzxxfOWGXnlxfrLfh6meFAJcHmY3h98fBVKOXJZBNsqjK2LkigW6b0qDri/9eRFE+4AdjGCS5wYJeGiujXh95n2mn737wFREpaza4MjFeesTZHp/tCSx1LpW0MRFWWk7k7FlQZXyT628tSIK4CCJ9zuL7ZsSo/ED93GaYXEllVrJZqeNV2EO6GIR4qoCCaEyGHuRhfCkHfNaldICuFlZoQMjihUUQlsO049VAI4f4GOTXgCpueonkg9iFpz6kEoo6jOS2Ve/TSKTVfMfRxtrANeC/iPkgu2LBvU/hw+VpUlBlmCSoL3rVDjWmZsksDRoWdcmpEDzb2jvPJlZPurA+I3ltlQFMFlQ9IPSqf23o7f2XrqdhinRePSCLVQ2Gw3s7oQsK/V1z5+LHHpOEBGHlcgksdn9a7W0OmBa7kNwuucmXT6flTTxzqvflJPNgy82KR0pNblIiW7wILHyiXoelM4K5yl104RHLtsz+obkjvcDUO/a+HOHO+9zpU5880VXYdF4s1FJUaDz1Oh9eOmLLUyAKa4kIdst+fRLC2VGHCBA5fw/tX2USe7yVdyJexnRT4HbPNmyKQD60+U18xjRVgV0T1fbfGtxGV3xjnEYNptdfp3ckNDJQ/pAl/0RI4GxoM21O7LoQbLZBPtzuOEPqxWBhJnkf7vxKPq4vxvhKxNpiYKkYrExIZ594K7AUd4Dvu8QkB+laNrbmTR2PxibIAjFrdRc1DvC23QfYruDJ5MSQOELBxrhcL8x6ntpHjtfmmfgrrVttsydY9tAnIjrmK7Sh/sFwQoLZ4jUgHIZ4v19QS6CH1ekBQMFFgU0FgRiqr7BW6/hxrA1P939gkg9yYpnu5TvqfN8MNijr+Bcr4CQsh86g6cU2xO0lN1GdkLgsE4JriEGMOWix19dayB8tOVrI4o0CCtQ/88PyUo2rBQ71afYImrEnLV64YFhRklQd+OUnfgHD5KeTOruDPoCY/Qgak6WLfGyvG8iV3drTqqYGwiuqKOSyuqXz793mUEZ3koo9VXsbewTeeGffyhnmyRbEnmcbRvzisNK53Cpz/b1j85yADKLC+OWdLY1QULeR2BWmPz3RHQl5QAUjorj5WhLQIyfvJ6Xtfy/F696GxWNuF2439ub7FPG+JRxGX/T9n+F5tFgKpUTQjoDi6DAZenyqAZJ+Fe2vSyTXkxbFKXmw/RRGlgVM8nZpsOwU5YiXshAdhpULbRvaXjwM7tcKZInLx+lFQmbZ3GPo/JzqNFFuHeoDQMEVgF5VXWzoYuDSv/flIAe+FIwBSwX5fhtKIGdtQZYVS5fdClAPAY5OKJeXzDfrJRRt3uf2uiYFjfng2n7uNIcuF5PERxoscjrBKIH760qpDKmxdv2TYBSWQedAvtSJ42paU9kexwGTEPLWrggM3nV2Vjh8a/0i/FsO52DsXD8HigwTsHXdn5tWXGuOhyarKormuP+15s88qKgU3fZQTDfyqiTxG0G0etHgAJM/lHYKThDVsXg6U5j05GmlyeuMEKQJT1kcUuC6NlLtIOy1z3fnT50BAHRApo1bclxPTAw5WYLXnz+aVhsWliIqEldxE4OC13tcZclxcWXnNlm6EfD0Pn/GIadLrlDPXhQSC/o2nLF/HxlantoSx8rSDEiMsk29c4ge55kuXOLtuwVM/CM+2SSxM6MtaB2bMw7ibptidAFrtjCsrbwp0CUq7HwuFInLzt2cQQgdQn4H0MdJ3xW6UB44c/xOHt9+RRMCpblefwuoHpooacdFTImeGgrVGLoCK0W85zXeVggR7hvCU8f4DLRf68kJN" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272325, + "Value": "121179019654112259", + "GasLimit": 19171926, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 6, + "Params": "igMaAAJUhtgqWCkAAYLiA4HoAiA5PPmsGAZnH/YWUiNQ06VdOc/GqpxusoFQwvUGp4lNYxoAA7HzgBoAG2OT9AAAAA==" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272326, + "Value": "122699817160760096", + "GasLimit": 65314293, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 7, + "Params": "ghoAAlKIWQeApAaEeaNrK5ZjMvDRv982vuEihOLTFRvdl52H15TK8BwHVvWyKmLq9i/4JLTiZSVYtRdMKti5SA3B5UYA88nU++7O/C6J+sK9vdYoPmvtwQ+D48zui9wXX8NpM0GkPJEzCAZWxkBT8ImPHGAD+EO6AZSwTRMVrF7bfN+eY6wV82gmmaoGqu92PpRDKTm4lechtgYrpEpG2VFfItfbQoY39XIy0PZtMN6hp2ZU6a3dN3T4mfrUPK1zMQf0RMDS+xuwld3Q86i7gO+QasJ0XON82wf3HN5lkDV04k7pnnxQ4d/iBqk2xlG1CGGWLrgxLR57twX9GXCo9xy3xVS1NJX4Jr/Erthge1LRB5NC+RqtFhFn7yy5w3LwdQju/LSnSAFFFqJAqZCowfYlByW+8Q5Fzw5/M480YXYlwWAmF4LSa+iMqwaim5et7uDMmNUDxYETgAV4Ia4wLtSuJlgniOHQ8sdIcnzuDqKpGnmCakEB0LPWlVoMOYYbHWKAKP/rwpRIjvUz172ymWz53h9qDlLDn5gesubr4/zOY6vvClXLIBxYlOUOrdgsB9UW2OGEG/lng+z7Pmo/cEUg02yfIIFEhezq1UgCQ8PXn9SqIKECZMMY16fC9CeNXLijkHUmLlQRAPApCRuY+re+KqXn10pGWezuLLXEZLQUjgb+KKYWkJgHQrn1jDlUJ6ZaB6CIwA5jh+2Ds7nS/SrMJMegsT06LSnjZ9Lgws0GQ+T9DnZ6iwSdjRrkPJ07cJoxCdCbrjdzp1x3Ps+dZze8xEBeZCUFgVTSutUFzO6kZaWao5ETPbCLPbgJhhmlr1+xJEiv82qtjEmNoEuyiuNZ9pYy2EJ4rz9ILHSheB8GbXkHHYrFjHFdhtTpAI2T9Hkp8nughc5oDHbanHcD8V9KWGgP4pb65wYQ87WWMkKDGAdfF0cF+CsXALHxX61Q3qkyEWxcjRzujR68NHGHKbM9HRS3jc6dcc3u5IRg/uHCmMdOfVAxnPIuO6qGKxlH35eGFJ7GvP9PhwXas41d6mwplhnhRzlrp1YF7AJQn37mFtGwAAO3Y1GSVV4HEgodLa+gahsehOx+hecxDjnvYfDncxl+dFXfFJLoI0JtH+zfaY10K4GXAWPdosGul/YGZw1wPiyn/5D/FY36eh2Su9tGtuGPwGaWKw15di/EpeH0wMlK2hF5+lrAmx4UXvOjRpwj3uWBlS2qjIxLU6sV7E3LUipka0iZ5p58uJva9hh8Npf8QK95JlPxf7GegmxQ+Ye3cFpAZvY9g7Z8ySGY3dOBROCiWfedDmvx8XYYakctQVAUHIEqy34OqwONJtecwU+DD+GhlQKEt2Mo3MCNNb87I9PgNQIdqm4WT4eBoJ773ZKCREIMj4KbO6UAqbsjPd/t/Z+9XZfuAD0kMwg6qaAnM/pjd6hv5OM9IwVTpOsed/GprzweG6ja/jUlbey63h/TF05uIN22g7oOYoytyEfJF3po2HBGbi4rufJvZ9chxvZo1vVD4Ep6Ik9G2UL6JcO/SIGDzIs2l8dcu6b73nu7S5VSrPW8y6jsmSrDaNd6ay1QYH2v08ZQhjQ+8EpvASC0VgQaZp9ajO1c7GifEmhuyGcLm/9gwjfTQBXR1xacIE/dgaR7ysPDxb14oOEhBKUEoSonL62RAHTXRmWjSGHFiiauAqrQyg/xqqh/70xAXPgSn71lllWSiuAjZw6Wem1+RDBnleKtlRoVYmtjA7G8OhSy6RClq723DAbMAsBaCeLcMP8f4fg+R4c09FBF4cFej8bxeCpvkjGAIIDfjLKtjBcwWwPKldU1l7fA4brUCaYh6ZKb5+42qtToVFKjCu2PE47vNZtei7vKH1Z7weZ0JIpGSJDEbnHYpgT041SIpu7vGvncfreeWGpsYID6A5p+gSfZCuNNDsyC39ew5irvpWE+3jEyCEgQHNageIdGfKa3Ou865g1fXHdLlw5+DawBujNpdek6iwrdrDSIKr2ibTW5GijXeUymshSwGhw38dMALtG/7SuJhAUIkfJRz1wUNR3jVmORkDWUykZJHEtOqaNQvEQ2hZnNB33tQtkIgcG25hRY+q7ATLQ3NBY1Bor6/tR9d3tPjWMwf9PmelcSQKOEszv83KFjPw5ykLBQeqe4BkYUBpaN4h5jmDMvMCHjUSqyGKX6EWoiuUS8Q+9ad6j55itg5qMQYUF3DBF1V5CA9Gny7ELieVgWiSybJ8NBTeeXGy8NtMnJI3CybO9wZxKK8QrIFu1VfhZRM0JsRp4OkXjZ9fdupVWuEKggSLObr8CBqgd9ks8xN3su3nzI1qAAqQhC5BgV/za3K2Jw2wKMm8pUgRemUE7d5R32BmobyOaWrqhjsg4zDjGy9USHOSLt/CWYDV6JaYLUG9QQ4ycsQSZNutxxctynu6r8IPmdWjNA5kHFGYpXlsdNDAoaH1xsClJ57p0EdQ79gPcCpPqlQLypncG4V+h69kK4SazI3Sy467DAlS3tES2cXVNkZz2MTJd+Kz6v59UTbvJVut7wheg1fubp49vzzCPOuarYWUKJ7Xxx" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272327, + "Value": "122700103126176033", + "GasLimit": 67929293, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 7, + "Params": "ghoAAlKwWQeAq3ddQtempPD7yo3aFgM9H9V0oTk3E3wKCmWRZu3YqasggfWqecuE23843RE3OJ3MmJPb4wENJCvuhiGXOdxLv2Fnu3vGpZP9NBEbzj1Ihf/av0Vet8PhCmhdOGz5+5dAF+fxXO0q4haSbsd/87Y3htJnG7SIuNflcYxetTJkSedPq9+ftQvLu6yiIQ7rsGLBkR40L8LF1QV2Dr3Ku3kg5+fX+I1dh1v2430xe5dvoeBY8asbaAj+/9Gz29B8Hy9bjLCggXHH2Lslm0DUalVM2J7ksRSfppLFkDrrKaWmihvmdJPMbksii9671GZNbFxuhZzkTzhA8OJ6QfiRGkgOYlQY61isODSMyAFMke9/KxvjXQIWsOX+Br4YOdca7SFIFSPOnP3/xJN0nEW1S1Hwtv1LPKs96PzfZAm5G3LNW72aUVeHIXKTrq1CEuwLa1RahWKY2/qSjJ0DzDAIjLJ2wsADHzSUN8Gd+uxx6KDnpaY72MV6WYtv0MpE+TcJDhCupMYg+iZwUPx78uzjl0mWv492D9mRtp7EMk3zlayiQw3uVk2lMFrUStuXLdUCP/yljJpVKJhabhCfsvP7v3T5qJEeVWbLnSNQXGG2HYXGRqALSQTWFXB1jxpvqZvekpVgF1h5WEPcMy3FTOe8+FQUGN484LmcGLE7abBk+fnOnq67w9ImXKmhVd1HRULnI53OsyneV+POh5l3PWPJrM7oXTIljSxc3oYl+/GUdLIac/iVE6/+cAHc8HC7ssrWUfeRsrsbgFKR72ne1viKjdfxJEJCLJStceZBowQoDqWg/FYjJOXhRHXeb83ucu8loiTJjzu0W+aDbySl2ZGuZUnz1xZdRZHcZeG84G2rWovbu3UXyRBdP2NBCS0PehRymjxHDw33RXhZ94XoHIDlZOoAiWscfNoXIf1GRd3UKj026vG8tyWkW6OEC9j59O39tNSTqKJ7vWry/Tf6nOOtDtB3d59bBwQURKzicNsMVRzyEFpwhyy42N0sexqSkHHZ6cgBrRe/fYHzZmQhRKmW71f/1u0Kmj/y/cGlTN73W+buebg+thwVHv/tL1GlFmUwyiFKtlCuFrbBBhcH4bKHfFf0A7DdsS68381dmhs9tEAX+GXYwnS7JLK3BhbUFxMWjSuuACBqDy5SYjDejPJ94kfU+MYUOcHX4VJETefWsYqfOYg70pPPq1yocWj9F93eeuvLkEbeU9/VJmtTgz4+2rwO3pIqxTDix643FowDPHqPgy3dzj2yiRyGpAAIjGU6BamauST2/s9emlUxpM3ViVQvt7S3XPAhRcGez/DmD6KlCuiXgHb1wepq24cfpUnxR60YuY2/smm4UuGtSRoZMn60NJPFuJ9B0OpzTgsW8exD5oI6wvm1m9nT6sn9c24xiE7AGE0Jh5R3KCH47N2fAo7DBeJ/vDXVa7llAuRVHDHtuHEFXu53n8CP738mtua+96LRkfkvL71RBWMFebKZLgs+lr37MtEf2EeNJ8wfsRyt4QSIrZKzxo9TxlFwzxutBzEfgwBKI0OUi6voFrLvx5vtPw8d8Vb441bL/VRoHM62wE2RfeH4rGSDCbklTt3revx9ldf57CAUC5d9AMhT8LMrJWMMEkNIeFZBwnkmW5NDA7n9dOZrB1aBFp/amsVL5+YhBHU8LqV4rgyzT5B1iUKkpmQT1AsTYflnTyO8uU0PB2G78pduUp1u/sFWI8YKEON0jqM7LtbGgoOfWNBrACSw0yIyXHH+t1PTWhd7XhPH7qcA7r2Rj0WDMoHPEngODkIcjVaAbnsME6PsrKUoN68Aejg238pfLk1/QgJv7dHYH6FjnKdDzlC+ybozH9HU1qwLrEKAeW5IOnsdeZxqM0Vbywih+r+cgbad1DsBopnEdFV13qCbpt5qH61nXKV1uuw+Cfc86gwR3O8E3sdjrmqVq/+guZM/KdA0p0G5QzBISemv50j8UksxAlflAyjtGx3poSOmuNvYcFfSOVfxhMtjx0WCGx0+eXNf2zZdviLeb0kTKjIeJZw9309unJ/h9biXmMS94b7rUs7BjzXZKYwyXgaRzR8WYtjjB8i2cnvRNgFVcSCwnKOgQeEHdBUXxnEVtNbR3ChKnxNQb7pbWxnSDgYHNqYAssPdfBljGgZFfZCaH9iq+t+fHtpIugspTWkKAz/U/IA5pL+VKMo6u8Y4AofEaOeTffYFq7vQH0Z+7ijV9M9/MxuUPL0XEHZgEJuLjCBbrBNZq00uKQxjnqURXU588OPqeIpDksUQm/hr6ZrZC27GvlfY6/fcD69v5yy4ue5+KfJeJ+zuokXaM9J8q029QZwg8A1Ebtk/cfP85slUw5BK03U2AMRnIeBqnHDakJVv8LcyGB/w9QDblUv7isNoHs85guU7MyGv9FcZRKkIMUMfKpPE1NlDWRcbIIjtA7ust8jX/LGc58FpqYXefAUjhnj0tTSSmnrXnFNvZ1MrclcVjFY2SfiseF/fbut9jxXQ/ItqVd6yvmW/5/hF2BFWRggXs+G5CcMpOZT2pRVTAvnl21XJkqhOnXDX7F7K" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272328, + "Value": "122700380388985778", + "GasLimit": 70544293, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 7, + "Params": "ghoAAlLNWQeArkRcWoqyuoR9HyJ7612a15hTT9bPwm8PHDqTnfSU3BEsxu7c573kZbWpHPfYAjgRoPeauPwKSSGTrdNJw6p1cQTFCzktz/18uuRR6486LX6LqBcO6bgPFA4i6z0xpaa7FoLtuL59in/x8m0BjhG51+/8VX3iKuUEYGGQraZvlM/rZYKwU5gBJW6cQVLtUQrGrSA5KdaTix+7WVF1d2Krzn4yuvqhkvbH7JoNNZ2KjsJsaJ/d+Yu40ergeDVhZZiBoH/LlCPjHXeZ+q8IztLxHTyTsbeQhUX5n4dASd49WHUv4RVnOpOW2Pv9Q19xm+ggpo+0do14cD8ThF0P/1KyAwYv4pPN5glInTkOxqZLHP30f+bfts/MCPuYdYQXwFPjC5jpyYFWG3Kcz9JW6b0XX400tBj6/lAxb5bOwYruba6ZKgrYzfOT3t5xIx/9wRVWjWBP8iv/89GAtOXME8UO86YGIdCtn/Pwbu8c1nitw44FtnK45kh14L1Z4x/7p2vfglxZmtepnk5iN5oAAxLriZD2xm8MvYtEmbr3zFTPMTFhLxTDnhKtsXOTWTDFhszbizao3o6z3hp1XEsv+kLSG5SY014m83RwWU2atvG+Llv7QKQ7QLN5TV6s9rS7Slu7AW3efCSKsRt7VmvufrTaoVDiRtWHplVQo4LaJybc6RzoGs9M1O0mH32dq8HQfPBElWBg1fkDGmrvSVbbj+IlWnKDRLaeB4GRfpTk9NAEWYrBwTaThZhwldm0Z+2nZMFup/AholxHX4Nkgt3mBvNsBJry+9qVW6FseR6OsJFiWf2ApEZ6xQu599o68GNK8fo4sUF/E1fEV5L9Vhgz+13lDgqDs+hp/hOByy9IIiksazlpya+WZCiyQUS37wIsRqjRCTS3Ly6VHOoCUqPpvSj0EUB/itA6yrRUDL1eBfQeER7cM6B9nxEb0T6P1nc3lXV5r6czv5OujRvh+uMqmXX+xNoWIr56uJFvL2nd8Z3UerK2yrwp+UsGVEcob7FckPtOiwdLhDgUzAvK0IN3tkIdGjoNwpfLQwOZRnO8rg4zG+1nb9gbAva3WtOqqiXdrlsUueqk5L2rYFUsUV3a4a/5Bhdjio6s5w3pl9z/4sPDM+hWyJZ3j0BTi+EZFPp2pHRxFJfMF3vWAm2jA+5thGc5vnVmzIs7CxyAlBk6S6RhxehBp5pcZazWoLyNkHK6VvLJse3CnfvYQ73FcrGGlQ8og2C9KH2l17uO6WhLK4ZIraQ3EYky0GtxiZZVK1lczkiNmAX3qZ+oWMKuiSJ+DBdbLvWsYHCHU2F2Adah/QRjeDE/mp7QlQvXjvhN4al5uCYvkqSPDK7G1b+QWYY1IdHjSep68ZRhr7oxoJG85jFednLVIaUZIxPQMMfHfUjQEdH1CQe8DjTzJpE4wU0pagj+ob1x3wKKDaJOUwB78vGBaxT6yAN1rAqLe5YGU4Cg5WgCqVOwyNLNMUgA/Tq7+bcxTchCwM7hv5+YrOoGXvUIKzmHccmVCCa5daeRhGJ1WITip60NR+e9IQCdFYiWCBL6YuJ8RdMFN/Qw6kh1MceuXNWooXdv33auY3csFfsN2HEmi+pKd4S9JF1HYF32f6eoKvwsjwxCB+D712/eT2FEg6LSGEJsosuPetCvPhX/LO5gBfyp19Ghy8eLLq6uE/I/QuHncZQtcBu7Oj9LJnwJksGnFMgrivCCm8pBqnWz5yhpiopGnKvheRl9QppyzdhQdfYHYP0ESYxYWGGaI4IbceSOa5uI+eurshsUIGetj93Yiw8mG3x8WFGPUKPeB/22B3yQh9DrC9dJH40BMal/UfphZQnz1WHoi4fbBdzLWNWpj3IVjMBxpNjvSXa+iTJEDH5UwJ+MxeLMhqpDKKyHksSF57GdUJt/6ncLyHpBekz5C+ZiwsaDQM5ZURHZJS6dght2cAR1MXaIBcDBWCd4Fm/0Y4w+PQjFrKENAuMcNZWQkJ5nP5OdgLFEzZPilU4qG83rvBfeyJZmYT1VNj4b4CZ0DmNEL0fwFLLbmV1qsow9keSrFoVi0SSeEC6Brs88OBf0vypN2K8k7PMX04ZG9xxoeKjjTD8edmsmlXcAvezVl/WV9Be3nIpc05cMKc4emgqP/rGLbZLQRxgfJc1chSJpXHPnH8a+0ZSlBk2iusFJCvVVD55j8IY0m7M9qkDePbxvFbY74gJtbSZWi+/N+IYS7uPk+1tibNBJmJHe1JoYpn2Bel01CmgpLLAdZN1LR2kCXQECXEnaEE0qD6cPCZzV3f58XktwTEuLIhTJfLuWpIc4rXOnOdLU1u1xAl4Z89hwzafag63v5ogumrfzeXRnZRuvvDOUK0U6LAYRKIF/pMOCMwPNb77PAjTdqxpR0QNyb8r4T2J3VFi+T41r6aRawxIgEZPwDE5NpUZyfoUPF5UxQXCTlcv5UuUmlOjqIv0RsFGMo6VZHJbUH8ANQKCA4ZoxMklvtGJ8QemKJHYrl1P5p+OzA2s89joJ16AHCSPPPcApidZOVFiuNjbKDUaWkvszxnPriF4LJB8GMJFL" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272329, + "Value": "121179289731961081", + "GasLimit": 19291926, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 6, + "Params": "igMaAAJUc9gqWCkAAYLiA4HoAiAuQu/wkT+evMVRmZx1pK8qXGEnqIDvXtALyNjnildZTBoAA7HsgBoAG2OT9AAAAA==" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272330, + "Value": "122701560056894480", + "GasLimit": 51728688, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 7, + "Params": "ghoAAlLRWQeAl9Ey7OBdGVO5opciES4gHzlDNADhSwpERB948C/xcGEQmBa8jm0RibvM1OcQc+eAtvG1frd0JIF/fCn9jlmux9N5DxRsyR6ZBfy6LA2P9lBeA5vVvoDYiCKRGS1HZi2nBkYVvsJdaHot80a5mi2Sd5axtwTdBqwZBiQBDkOkzUXRAs/FHW4GC060sVHGt2oRk3ePG1k2DEXF0xFs9N7R+Wsq1P0ZqIyxkUJsIY7X1JCs43iKjdkkhX5qbQuHVPo/pgm/OswiwfRnK6xqEg+V3Kcff+2cU8BdSw4ynVqwXdsx1OUO8l5OegUEjpiEmQQqopt6skk085VFcbhI3nK4f93snIkMT62of477ubTR64+BbxvsbZ20sNnPnokBacZcBKLRLlLj1BSkwO6sY+T3ZbqvJ9puN7H1H0p/B3FqzXtya2w4RsXHLrR1SZEqSpX4o85XGnfyaqbHaWhEz35uuNkPuSO7m6w2/Kh4fxZSVMsKVAtlTiwRblEkBHIzqcnWodAOe9pBei2mcn+XO5P+uUal4y/yZmPoqqNhk6IZP2aL59h3M3dJB0J3GHh9ounQplKajBrsfy6GPyGqKtThV9y9QVp9MAsvMVxpI4F4VQl4Y99K7InXFFzSmcNPp06JAftMAdJmyAEB/iP7Lf+dDVbkG3Sz+nWkOrUicyId4uGtBr/Ubcpx2pjE0FAB6n3tr28Dms/3opP2FeKZA7iUuJHjicBzmDmNo+nTr6im4ALW6QQnK7kGB5VaAuf1hGd4sZYxVhmhaec3CNvoRf8hwGmpdmocvIU8punErCMRWt/rNBAMF53PNqGL+UHKiIi6mGhAUItuxnGWxDCChXmRAqTWkMDiriQ5bVlqIl4ptggKG8DrRa4w1Gu//6WL1QrEEzUWomHE4bC0zqnNnlNa5KkPXYpL7JFkrRrKIxzpLIvaRa1wYmLwV7+U+5QRjhw6lB5b86h/pDMIJ4jNvue5YF0c2Fsvi4x/NFbmlERsPUI7VwydPmbE2nUd03mqoimKt2PnjK/24lJbgnavKPcgU+5U5pVpc0Tncc4fT7JsS18mVN82itNBNtdjLJlnt4VkgQAgxzxGypvBPWMuTgxn1l1MHyXDQC4kcRXKyAfUnHPx8OyLOMSHTb01nqd5Z1VXEzp33JuGzptuczzHEwkFDQYSu2fOVrFZSOyOxAYt0ObtIdVGJlImp3kUtQ4THE02kjYfxsK36e/d/fGuMHIKokz9ridkCL/KrbGmwOeKvKzci14eoZm6wJ+alL7IGX6Drj/Gg5+7bR3H+0iWBbvOVBrVV2mDtx8FYgHMHlts8DpS/Lgg8GvWcl8vsoGLvmcEoE6Y/rha2scZSqfapJCZ2AyMA09/yyNnOCtTA9cxeQ2IsFzNmwoj0oVmr2+8CIH9Aj7ISDfLiQjamCUxFVDhNNrNvwB78CJZpHtOxNOfnJiJV+ZF/V/agVQZI7k77HBCgwnv7QSZ52H7HpmCPS/2vS6DAwRiB+SmCmGqsch617ZK3SW8Oq/UXcvLltrNwgCLj7cQRwX/fKlZz+YB/JNknRlsutgwHt45TqcSJrzkKGuam6P3kCLPQQa5tIzOle5suFZZuc7TcLp06v1BihY7qfh3PrS+tbR6ec997PCS8toJnQayu0+FfvOhcdjzTUf6CJoywrmpIUWvJ8EIWpzAk/oOrPWhj0APfWyyEdZMulzw1QPBl7mIh5+gnatvnyVytM4RpLir/qBbOMJWmp2nza5OHp3+e9l4An+ov9jdqRzRs8dDLGSQNuIpNwq0bROCrsAYzw7mn1Lo2x7gM2bd0XTqnquR7avUokqQGedD3y0TLNytEGVpttccNiLJxn70qCW9VTadwPVUihANoonvpW22QsJxq35TbNOhyWdyMUhPaOBqezZtYWzemMMethEJE8quOS3ul3FF5XwlGlxFbBSezEnpiBaYKf/JPmh7GPRIfCYn34gWAw5flXFHzHB4sUpaD+Xju4fP011BnT3Jz4uwvk1iCAGVDRvNOk0z7UNi+cnyi0jZtzUE0ZLjL3RNg2doSHZpB27eapR306LKsMz66XTg7vib3Tlrt2S3sC/1WhbRHRElGlbUqUmxz+r9lrTHgdZwqru9uJ9M3ANVNYrtGfeAyEo2En3GGlfMC50mi5Y5TZR1xEJl3W9lLUvmDap9X4qV9pqk3Gly/ymJNwE/RJOfVcjR+JZJbAzORgSSl+Swqaw9ewNe4rWW4UQwuIby3LWgGRVWXaQB9o6d3K3bBlX4ZE//MRA8dQAxZIa2ID9pKQdLGznlhHhum3Jthti3xstpFysPhkAFi6GSt+HuXVfRsvWRjVx3dHbcPHIXCFQenoK4QFx5vOp0s5jXjikbbPe0nFaOWhukAMrws/zTERlW1nxzVcSw8kEfx4ktsgT9MGZe9BJPMyNFgAq2AKcFMLzhfZ2TjIFGybp6UJ3K2WI1fAtIP50TFUKNmhCBxx5EnU+KMx9AWl9hgRMrkXrB9S2NsehUR5UXBA5DtKZPVbDBeTlbd/gvH1gMUxgI3VgmDDt8h1aXu0AHpNea" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272331, + "Value": "121179562045129755", + "GasLimit": 19175676, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 6, + "Params": "igMaAAJUydgqWCkAAYLiA4HoAiAo98lqNTfHYaNJnh3JuDVc9Z9bvWbRWmrd8UhOi4//GxoAA7IMgBoAG2OT9AAAAA==" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272332, + "Value": "121179562045129755", + "GasLimit": 19299426, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 6, + "Params": "igMaAAJUuNgqWCkAAYLiA4HoAiD3Ej24dGzjoSOGzTaMw5TuN4nZKkd3YIN+j6Y3S+M7TRoAA7IGgBoAG2OT9AAAAA==" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272333, + "Value": "121179562045129755", + "GasLimit": 19521926, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 6, + "Params": "igMaAAJUv9gqWCkAAYLiA4HoAiCqR0zwtfzuzjn7Y37jA8F746aOBluoa68rczWV+81mShoAA7IIgBoAG2OT9AAAAA==" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272334, + "Value": "121179836579518752", + "GasLimit": 19636926, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 6, + "Params": "igMaAAJUttgqWCkAAYLiA4HoAiCmva6TvefhQS4A5CRwiz3RCY5+Hwzc/jRML7zlYdq8TxoAA7IFgBoAG2OT9AAAAA==" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272335, + "Value": "121179836579518752", + "GasLimit": 19638176, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 6, + "Params": "igMaAAJUpdgqWCkAAYLiA4HoAiCQkpinbBlJYEEgyRjQoDs26LyV6bjO9WZsvfjPtMyASRoAA7H/gBoAG2OT9AAAAA==" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272336, + "Value": "122703763715088896", + "GasLimit": 54531793, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 7, + "Params": "ghoAAlKlWQeAraGvQuFFvseq2sbO9F8n9Aczce2lARk+b8kU3veF3sn+qd5Sw9Qrh3RDYB+CP3i/tGCpSptc/W2HlEaTKrbZ7LMyQqsPq9nMxxWF2wk87Q1o5LB+kkgorzY1fz5UVsYGDWOiDmxz+m4XQO9bxpiXLSZR8SsYEVOZRMGE9Hw1IsWZvTq6kNqlGGfGwFkwqSSDilr7JbDz6NfcW9aXxnG3uuIZV0q66kFt9F506W420k6u0NI715KI6y2SkVsFreMdlA6tj0KY0OTOzAm+25EV3H/Uwp3i6PV0a6O7T8Ek0N0CgMlZcsvaGP6jicQE3DI1hyVXMhvQZmyPZQlgZUQLrdkZHu2TLqyRzlylHTao4g9bn7GANvpGNaUSMck/icDyCVfV2IaZ9CA25H4Sx2epRtc/LPPO4PjOP0A0H4vjKBPDBLQnhgma8RV1i96el9dLiipCQJW2h5sojmImOLkzjbyj+zauRAWKQ9GfgAYxmx5L/MidSiwsEwm3ljnj2SlZlPyPJkN0k3ngbRXNHVdZFZ92Ztp4aaVuDIzcMVvPvNhNWywWibnJW6wNth24ZTWdr7c+wqQAtiZvIi53V1zlbHCDr8vn6CqRH9ivaybGnHYDFg7pSCoxrLXnIEtYz5yXCUOi/5ac7KOhc9jxVZEN+nD0kiFL+4sfaiq2s/nn1kRS/BGs1QBQVPgI3c3jEhD0jnBEcz0gIbr5jm5HLQesdaSJoFmvbt9rZUydYMS09coOnVvgSFEidnkzAqtYigKlhsVMQ0IRcBBSoWJ74jxgOnnS/flOIppAkPf7O1FijFLOSYbsYWu5fqU9Dcr2cQ6RkNdw6oQP4B5ASrcEuuWWZEgZ3gpEJFjg/ybBP7dHAhKORqRIKryu91YVUEZmnvrbAgR5mkgrZcTGAqI4nA04psyqMNtPK3Prpn61DBwopwy1uTE6RkZPs/mz/z5BqbHrt/ToyAAUwlMfBQdaRLC+t0jWF3ukr0oxe+4oJ4FkTlgsioGsOBqXwQk2B5dHvRGfo5VnA18m86H9gcoEaywBAw+NsIE8l6TdSs7FhWThtRNLbfNigncNvU3wt3lW3ff3kaUInSJK5SEgLcm1PbaTStkCMFXJGftCUBzCqDyryYpfL2DDMaCg1V+yqTl5NZnHEpiz2xI9OSwiOuASAKO1WGTqOkPhMKCJS5R/drmJcXckuEShXHmETEbOXUtseDKkqn3J9TJLvDZNi2IENLJq/nT0cAcH9BLHDL9fJ3foQTb2o97e505nxH1XbaiJ01JVhp1ND7NwuUkeV4OKX5CpNCIb0MQP2OKdhkwLvSkdbiNBTmCZEzuHmNzeG8iD/a9blOYKHdmWq+BFKE7mvMg48Io8i6EN2CqqZUY4KbSm1+T+7bQqZd6UcEN1kHliJqtxBZXa50hvNgRbqkpkLJHdK29BeNNrriMNNxurbngwoXe5J2iY9S8GegPUiAVBXlJKgUYnjnZ9YFBXMrf53ooXUBCdwE8sxWAlF9Pg14D3b0xwV17M5uYfWS3ywRw1z5WyoYqsmHUL0D3491AzVzoBg7DKHgv43NgHxm72k6HDVgYDTJZfd3j1nE1QAop4Pfa8smZ965ANdakKo2x4w6UXzWN6RIwsw/XzU+8BCqOhYik64kSgQzZMwuUaBXFSgMoKBSxWNwnyoqDimNY6JpeyPz1fX+o98MhKNOSe72vAz3H9uLWTrQooHhxAXRMXrQt0lY+0EVNWfG+JS21w+X/HsiBDQO9GHRiIY1NZz4EWvXoz35HzlnLMv//NSqnBA+1PlaxTm5NVBNxp5TUMSl4xUL7Mo+Tjh8lic+YBv+2Tmk4dZD6KxEyifgXM+bpjoTqzghiIKI0mmrI4fZm+RdqiiU1wGidRUZo95XjVDUCoKE81rPC8EdX4EvqF9fwLtqC/CYDW/kFr7J+AICGYCskn8PNPhybIdNvAygTl/T2VR8K6Rii3tUwb4oepgqh3h2Vdqpl8JP/DFMHo5jFKS1q1t6gv/CKPmGA1ErVgO/6OPK6iMwwP26EoMMtRptRy9dmyopu8/+z5ELaaP1i35BgT1KeQmo1yHdpivB3jjRO6bxf++ETzwdQQfBLSI3KLvoGatpGfQjElLPxRLyDbhc2zBwYqRLBDUMY5iacgegDsSUZ+FuFUhJrsFA2hrzSH7XY/BmCpQsAnCKz+LYWPFeyY1gFx9zNn3C9Eh+kwhXdPKRAfW4mcvfMn8wTlo4DJAtOIsTjMYkLFxEb0rIifju6j3+sIwoKOkhHLeU90pGB6bKL4JNzJB65aMzt/coNQcREWgmnpW2e9ZrJxfbhm8Ir4tpdTwNFirtAnkIoPP6VZFQBTUkQG68ZwCBaDOaOrMxZvjee0kTA6usqwIUIoN+Cw89JdjalrCx7CQfRjMXr8Ly0Iia6PnbuuOlWeFWrBORk/GNhuXiHbEIrxFdmMySx853yGINxAH/K64bpqaLSfZyxlzRNWdXwnmbp5uTs24QW6huOx+mvKUVmCpnHsEDa5Kn142EIUXToHqO6bzfW/qD9nB8xnoV7IO8PbM3zdY3Ml" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272337, + "Value": "122703481204289764", + "GasLimit": 57146793, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 7, + "Params": "ghoAAlLGWQeAuQqmNwNd4HnPVSWSbC1R2lQ63AcBEJaG/kTIBVfppO1iYy9R4/XWlGuiGyGtloBtpwh18C4r7swCpKZutdq7iK3sdGvbGSQ+2wzBfYZaFjXkFJHULXaUkRh2iR9uy045Dv5BbhHrjhIKZASRJs2sEuvk72hk7fS6nD7ey4pB/lKnFaoWIWlTV2OCttp4Ffa/q1w2JPjhhI0MqD5OVaSCT+A6Z4PpzcZpr7+UZVxeHhdx5QYJ0fngGn2i02IfFevYkpcwRhzooG7qg0ldDf7TvXOILPL1BxrAUS0qnTaek7goksoZLGTeHvLxrLAqFOuij8GJ6gVYU7XLd83GSmyhWbVOle7xRDmfpTbyXY/3l01ii3jKDgA+RWCCiPIrAOavDsFgJPJFr/98VU5AHA5W4dlC7tSJdzB3IoKxrz2+WeIvyKPQ4nU717qzqCjnmluhlXpkX45t8xA4M3A5q0Uf4UOYd9+ACsD6AHVyI0Ulc8iB9ZI01dTD0WXApu8e8fKxqQw4stUviwxLC6VqL5kAn75+SXOWQl7WfE2xDbW+YkrOfcSSl/HIkxf1T/eZI9kgrN6tpSYLRrHsEzqGPZzu7c42MTW1EEC8CizgduBPWTxNhPO0kzaB0eMF6B5KI8o2B3v4LynNCMfLv6Wx34GeYcMjUZewDqzjP33i/zjbJdJ4blGQPKE86Y+MAQtQ8FhvrQam8iefDSCVG7bPs6FXRQCD7ub8R2HAVOtTWt+i7SSRODgls0IIRKL5w6guMz0fiVT8HgIoiN3SbiTe66TZNVVZa7ceo6GlWp8AW2UFS5KBwhS9b7ruuKGqqV+deIvGpfqWyfx+QgtrV47zlfavJ8Lqc5M0toLz13Z8gMME/X66S0zhYqZMAyyuYiFpgurDCKEKv8n+qk+r4iEaA08OY5w4D9BSP1inWbHTEN8a7XqTj8MS4qqTZ3iO8i89b7/Qh7XmKP5F6vog/mfwtlq2msdTbwFJszvx62LKhfVbouVl7KcNnxvsC4JUjycl2uDEqwHn2yVf1MlRgTGvVQNmssHL+dxjzFGPL2W4LbbPZfaOnAGnhxQy4WG5QyH1rlAesimM1Ma5m54Kkm5+2iy+uBvo8zBIVO/37MHP86O3jAsXoTKp2cVE6s1DriSU0D8iDexol3UZKNr6fnKZMLcJ/yYIhrO4539ddL820iYXwZ4Twwaf74xNWN0CV8aUPFlOkuZyMc9vNdy1H4pCFTbR7eqTrtHJZrZJTU60yws+XjnRXnE1jmOxhY4xQ4shoJa3jPGfiMRq6bFDrl04Az698vbGja4WKmHjCCL7KKuyGNB3Fe33/v0xV1q84GVkvOGPmTsaG5d95iLIgBzWZprySPdQTjhLQxvU1PgAB1o/lY4m5+e3EvdIF+nUroA+8WlCGVLH9/RiQIt+mCaueC5NOql5rBVQ2cYiP7alIOVqVUUIaVEtf1B/kFY/JxNMfJZRo/A805DoX40f2ox2gu864Ugtt0FhHfoXr6ItfPh3+yb9vgHMnt30d9RCc5I/YxfKhcg2530mRp9wSph49RFlSzuQKzdVfibjIOlxuzj0xvfVfGWurqD145SAfCtO0H97k1UcR4ISpZb2THqHlzuTj2ugf0XzZBxbmWEh5K6cVGknsFyZ9KACzySjIxxUp8MOFvy2PlUdTl9tAf3+vSkwvfw4dWtYxn4dKoQn8PYtR9ls4dPfXykRci5iiqUg25pfpQa+2u43vqEp6bzU2rpNv2ZaSv2CWq0xpViGiXfxA8Kt3L5/2rWamsVpqOhMwubNqxRcmmqe5lAfv/Y3CL9k2Hys0BPxdccuIGQ4ZgKdi1pyd5seotblSX7XLPY9ugZVgMgcUjb6lIVTu6hXzCN0BkQPOP9apoCLGSj3mruTHaEMTE7CGJzwcGlaswZcMnfFEJxsI775iNUCYO3dn8oprdKSX+8kb+byyAM0Aw4wfi+0oeUAE25ZVChs+5tB3D+KgefBVzB5wEvZfal2/XjU5lPO5euRmximAbNpIbzW48JmtK86cErrTfuN/vkfjATetyk0uJFaqAn/CuVpvkVcxbS156aqVsk948PM1mg3GhS2DC2mZhF/0Ke36PknOGdvp2q8e3ee4AEAA9j0UKPIZ0nk2lN/i7lJL/0jIIBzQOAQQz+EGdddN1IzXyHed/1KGRQqMRCEERI1Yb/H4ZgeUgzbr9+tfdEJIfbqJktOgxeNfheTkuosLAnPsNrwKNFIraYMq7/jR2fHoryfbFY9Ja4KBDt0APeGfiBsw+Htmj9mTB9YIMfqfvGKhOJkH4Hhgg8qTfqhhdFwAZYgEHbDzh/2gjWztu9saW9NuUvzgS6eYf9yY40+c8Nro2UrtFSTq4miE2wRH0AEkbLwayXHtNskoSDvmhJiUH7qMcWwLMJhAV51k+tO1212KkY0ikNsB2WcVoSIY4lur5BkyXV9/Zvj43L4rxmjFSPU52ra/fYtdrgHpfwl2v/A7v30tE48i6boeVL4ZeHjBPTCi/1jSp3UpFyizci7J9DM/fCYfuQ6k1SpYRVsYcAoBtRCkUSE" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272338, + "Value": "121180081954957656", + "GasLimit": 19188176, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 6, + "Params": "igMaAAJU1tgqWCkAAYLiA4HoAiANpmpGjhAvJIES5NP3SiQMfi01pSH+0sx2va3DtoOBahoAA7IRgBoAG2OT9AAAAA==" + }, + { + "Version": 0, + "To": "f015932", + "From": "f3xasu2sehnfhqum767vhcbwilpicjtqe5j62agncdcqufkltbevemclw3g7xpt5bxgfu77zt6wbervysriyka", + "Nonce": 272339, + "Value": "122704596871133811", + "GasLimit": 59761793, + "GasFeeCap": "999999999", + "GasPremium": "1", + "Method": 7, + "Params": "ghoAAlLgWQeAhC/ykg6qjFs147nzebahU8JbGY27lp8wDnzxT2gUBhz/UN7RUsiqdB2YzAUkaGNGrsrCES7PFOE4piwzA/TBDmyuaPPcpVv+x5YpHuly27xzwJ4ZJSY3AhGOHA3Oz4mGFQKToj4sIGQlpSJAeNYrBnWpnliK1mykUL90iyase76QMlAvriPI3NCxW5mE/hDwtlgZWXk933AexjCUNLAZ3mWTdFplG4OuU3WiCW4IlMITZsG/z0Jdlm+s3kTyRjXmoWqR8Fo9+r36T7jcq0MPG6hJfxh0Sd7nuijJorGxHz5KAvkWM0k9Y0smSma8UyoZraDT+HbFI2/iOJlVEBiC6M8azacrR05WRQk8/cUXoYuwCxf6caAfhEyM5hmErGaODZBjZGQd13iXbGHk7DdQCG/dl3IAK1/X5ayLF7Ja+fVfb81XoxtApX72LZAi7/ewhe1w452jVW4F5Dw44Sw3/GSu6G0fggClVy8+8KiaDI+5Md091pUQBkBFmaM/i5VzmObEawamb+Wn3MbvmLUtvrX3Y4wFKeOxD9ADHaI+BkYU1xeR4Vs81Tdmdm8b+oJ6tCAVtInrGmvIoFBvzjstt0EbORrDn9FHinwG8aSTw4iN+0zfIDntf2FuVPfPeVSXBHYpF+VT9oXDmSpE72l/jgMKrZzdKR1+wtHwM1eBuRjosmpDo32r7zWwzpaQj3r6gEBNiq2o7KDAMJ4G3z1cM8aa20dvVYKaNE5NIh4vYMtfG0YGW1XWSR4HY1YlQ3FgsS4yrLHFRlxXO5Ahfh8T45wqZIf/lbXRf/FK8uJ63mGM2QjamgVbJDWRNryaF0ZHqTbYy1CtL3qISFi8ygtXKr/Jix9f8DtZimmArRiIPrqAi3fLj4OoX8WgoEROHetIBqpFGPw65cV6hL+C3QNZMd4m7tXrwBV7BH+nc+IXx78lKN1PsvNRRmL9AYwl178Kj92yskChd4TS/1lWVWrlsmmwvmrVThxPHQmrzg+dU4d0Pn1rDjUVVtKKUw6dcievr47v84mkQUiSSG9UXh01UwtlIbcQHOf6LXcqg7eD2djS5agt/i4fkjwdn9i2cOfKg9Ka8h4STTUikAln8SVF7Dq7EMVcHaKnf8xWcCcJRe89jtDtjlCTVxFEv1FEuFQDEfZx76JvtZUg4a2aCKZwTShnqrngP2O2qT1Rnau4wC/LxJwDdZCLqE3Wg4zrsxifjkDm/B3lODnSVhqXsVlXKPQBpw4AIdo/OHErD7kGRRfEXTM4tIVhb4aKLzlUcxNzrcaIWp5FBwR4fpgxXptcaC3j0FLpWx2lq4Z8CmSQvKB264ISM5XmZvazSpCFukqdkfI0epN9JDHRCoKYtfwYGleptOxn9cLOS3FLosC3wYlubNlsfFv9xvnUcFzRGiZrCm4Yf7BqslBlcJ7Z22dyIWmGUOPT8rIE81YUEwltGiWOfXunwXnUejf39bD4YDiqg5G5Uv4y8SFyJ8+2MlAkANGWaNMBjGlbdX9kpG/Ga5GNFkYbTgg6U8b+e+UqwMcrrpoeJovrNr1ttoqzIDXaLo2mx+tqmxcRtijwD3GODQ8V7+8WU2oGOYvYdqlkQT2qtbQsQMaplw+Ip5JhRTEbM0eaUYiIGgdVh3PgRHXXzg3HYGbWsStxQ5kkmQ4jtUHICrjvaUqeBj6c4TwX8LYkHab9Sc/YqeJqluOlmPt9K20r+6KADlTAh1I2AqKeciZIjrhzS0xleokmh1wd/BJp5SJSdpkPAT8zR/0ClLTuU3FKQmT6TU0AdRFnW92l+AhDtSzZq7BePgdAqhhu1blr/SxWfkomcbn0lioi4P0oisN5g76Rp3zKuCim0OFijl9Woo8FfpiTUcwUPGsNjJZgJD+iiTsLiMoaAnxyT+OGpSUMxHZWJj8j2WP/1QrKXLh+AhoEJLlRYttp0R6nhciUYzZtpUPBoJqy1OBGvalFAaEQqpXUYGuAIKTVXddiamvutclKlwMWYwSX1sG4WwPGx+cDKEF/cTnM47e00Z4ibJr2Q6k8sOx/OuAgtyTIAgW5pRAL87Nsg3dmeJCTniVMrIIwxX/KRiIZtGZFD5UnYIqXjV126h/r31wPUMAlpjuOj1rUsAQCXPuReROQqXsr9AEz1iDQhuJS5Iv6CkbnvxYJ8LsAtBMphaZcU1f2O0bQE9W5pauylJJUZ5ZbYxAk+RV7HQnoJEi5i2FQ8rLh6Ig86WqTPvnN6XOgRd3brjnQkBtQa0TcuaetLGrEo7C2hrsMktBUvGTHLZ+WggHDEPWURZ48njMZPlIwRjV48Vl3lTEo5h4dAnvLCAVmRf5QKO7m22pa5tfXF0Om73ov7oeQmzxZpBmtaWQiQCyUt4POhGoOG/GBN9WLglkRgxFhihbF4pIdRswX8kuoHEH0nmTg+XvIw2AHJfZBd+6Y42qrDvSQ9E0Cy9yJWkCWNAuLnEP1VL4pg95yau2c4H3qyrFFMQZe4ooYOZgX9Lq1FUMhufz0BsgPq73xfxZ3sNqJDOcE/LZA2ZwIy328cd7DYKH0RtqKn+lPzM9A0hk8s1fq" + } + ], + "SecpkMessages": [ + { + "Message": { + "Version": 0, + "To": "f029223", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246187, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "100704", + "Method": 2, + "Params": "hFUBLtmWFhIkU5XtOOjxXacrWwHtZWRJAAdRfXdOxHXaAEA=" + }, + "Signature": { + "Type": 1, + "Data": "m6eCh1ymdv2ehwuV+zDXBuKTUnd0eSPHwMy+Y2knvitQhqdfhKNs1Bg4dbBT/4dQR4Pc7vDEAWiA/mVnJOannAE=" + } + }, + { + "Message": { + "Version": 0, + "To": "f026582", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246188, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "99962", + "Method": 2, + "Params": "hFUBynEq90h80yKxW9Tubwzzx8NvF3tJAAdMPDYMkcm+AEA=" + }, + "Signature": { + "Type": 1, + "Data": "IQxkwxRDeX6jkkT2RMH0kPZwN/46vuEUiEbtcl+AFkJCbY6wfuMsKN0qedrH9nRUs+/Pl6TTK27bNH5xNzqOlQE=" + } + }, + { + "Message": { + "Version": 0, + "To": "f029084", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246189, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "99599", + "Method": 2, + "Params": "hFUBih37uGsnRLnKXmOKlhXypygZ9opJAB0OWFIh5RFQAEA=" + }, + "Signature": { + "Type": 1, + "Data": "Qgf+s9aj4b97XlAWfjhPUeba1+ZoBvD/LWW2QDpyECwQUAikS80a/us7VNG86P65jACZP9KLX7H9giQ2yuvjNAA=" + } + }, + { + "Message": { + "Version": 0, + "To": "f026721", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246190, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "99978", + "Method": 2, + "Params": "hFUBXvqhyAN7TNVuiBiZLx2PRsBfimpJAAfcRapI7AYhAEA=" + }, + "Signature": { + "Type": 1, + "Data": "5YOCgCuTp07qn0AQNfPy3yLLNkZSyJxn8k91hH4dsVcjrVqTYTzHqQ1lGexdiRQeWah/SepnG1NYG5/z2SixyAE=" + } + }, + { + "Message": { + "Version": 0, + "To": "f027694", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246191, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "99711", + "Method": 2, + "Params": "hFUBLQW46WxDslg+GgyxcyEQPNN0bIZJABbSFKUrvGdLAEA=" + }, + "Signature": { + "Type": 1, + "Data": "OEYhFJaCmcgu6GoNtLsIAys+7VceJ+iaAuQTkaJbQ6or89UkkL2427VXD73FeVkOm4XNsK9sEUfQt3S8kPO3DwE=" + } + }, + { + "Message": { + "Version": 0, + "To": "f028389", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246192, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "99877", + "Method": 2, + "Params": "hFUBLjcdJrKnodTsGj0qonu3XvbsvENJAAj/F1BB4Aq4AEA=" + }, + "Signature": { + "Type": 1, + "Data": "FOcosAmC1nJ+Qn9krm6Uot30nw5ALS7ZGqAulfvYFmNtjX3iZ0HcXLk1gUR1yyQJVYRRpeq76YsG+rrB27Q2ngA=" + } + }, + { + "Message": { + "Version": 0, + "To": "f027138", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246193, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "100406", + "Method": 2, + "Params": "hFUBhgN0Wxa9q+LW4UFQEcbjl248l7ZJAJZTyBrklEHcAEA=" + }, + "Signature": { + "Type": 1, + "Data": "P21qnhfEwCCzjVHuuWWSzO7GiNmK423dCnPtHGK+haFrLZu9L0vXxiY3ppG9oylIB2IuwpEpviKjy8ai/Z+kdQA=" + } + }, + { + "Message": { + "Version": 0, + "To": "f028945", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246194, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "99748", + "Method": 2, + "Params": "hFUBv9wkfoRlwdm6CSvanJdttMdDJgJJAIFCVfZA3U/6AEA=" + }, + "Signature": { + "Type": 1, + "Data": "eQj4kaH9EKIMYqjn0BHDI5e15dOFGOHKAn+l84D+SG9oG9TWnz+rfrlm0wjdzDkpKTGY3l5Uy7eGltxp+VkD/gA=" + } + }, + { + "Message": { + "Version": 0, + "To": "f028250", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246195, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "99927", + "Method": 2, + "Params": "hFUB9qfa8HjGsD8K7busaPt4JNQnSyRJACBvHV/8A1nRAEA=" + }, + "Signature": { + "Type": 1, + "Data": "fTEdh5ackzxnUR3ZNViB+PmiWD+Za37euqGfUBSBLpA9KI56rnOzu1c9ZwofeuF4BGX4dbmOxnrsn2IM9EVLDwE=" + } + }, + { + "Message": { + "Version": 0, + "To": "f027555", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246196, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "100456", + "Method": 2, + "Params": "hFUBzsrFoSc06Wu1VTKgOdwbOReVD/BJACsBhOvuk32oAEA=" + }, + "Signature": { + "Type": 1, + "Data": "i3zDn1vx1OzOmyrhV4TiZel9hUzUwxzx8OolPZJZq+8MxYCYX0HqPvRGFgFxszMUeS8ytpsLEwmyXY6BXjCKHgE=" + } + }, + { + "Message": { + "Version": 0, + "To": "f026860", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246197, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "100102", + "Method": 2, + "Params": "hFUBTN6KgwVxwWnnzO1GnDpzO6guRoFJAAjjV+nw5+p2AEA=" + }, + "Signature": { + "Type": 1, + "Data": "+4b63o71fJgvUFnp7mWEl+StLOZeQkf8AkW11GCHM1A61BDHZBSgUBrfJ8iH3CrKsGIZpLuABu4Im5Z8tFkAfQA=" + } + }, + { + "Message": { + "Version": 0, + "To": "f028806", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246198, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "150074", + "Method": 2, + "Params": "hFUBLE6eTeuaj48AaE86g+38LlL2GOZKAA2cN78jOR5zpwBA" + }, + "Signature": { + "Type": 1, + "Data": "FmJoKqvYQoktwMLtAwS89kormqUpeDjxfH2SvR1h/wUquxAGtocrMLWsMsiDalYv5BWTu6xQSWw3BzivttcHIgA=" + } + }, + { + "Message": { + "Version": 0, + "To": "f026999", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246199, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "150175", + "Method": 2, + "Params": "hFUBvKZ3FI5LTDX1bnqs8YNH8fqpQC5JADDHb7tfhQKWAEA=" + }, + "Signature": { + "Type": 1, + "Data": "1GeBXwCaQsK4cYGIjUzkk916iwhKtTyAmIr8dbXd30UVkUwFMfs7gP3IVvuzcKOA7Uj658/q/jykdkNuvGfLAwE=" + } + }, + { + "Message": { + "Version": 0, + "To": "f028528", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246200, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "150023", + "Method": 2, + "Params": "hFUB279Cpr+lLh/H/715+vGUs7UggU5JAJ3uv0liocsOAEA=" + }, + "Signature": { + "Type": 1, + "Data": "N65ZqKj5ZEdUz9XxH5QU/OofOcXWMTOlghOs4BCjODYyAf91STzviuGZE2YZ+qB5LbhjwipfzhiGQ/BUPa9LRgE=" + } + }, + { + "Message": { + "Version": 0, + "To": "f028667", + "From": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "Nonce": 246201, + "Value": "0", + "GasLimit": 3840470, + "GasFeeCap": "11900926092", + "GasPremium": "149402", + "Method": 2, + "Params": "hFUBpQSlxMbaZk6y+U10yxl4PCRLSOZJABR+0cU4cw3BAEA=" + }, + "Signature": { + "Type": 1, + "Data": "GDRFkkeDCxFyr0zXzRo/ktG7yYRZLff86H3c0PjBeng1xfipXRKfc1GvudlgdeSn6oQlYkdrZ6AXFSypOlLu8wA=" + } + }, + { + "Message": { + "Version": 0, + "To": "f2mgv6khl6s6oukeyi3nm3ja67s7fl3cecy2stvny", + "From": "f1i5kvaeurfv27jncddyvcuzgegm4j46y5u7okcza", + "Nonce": 2, + "Value": "0", + "GasLimit": 2221245, + "GasFeeCap": "3151385821", + "GasPremium": "100251", + "Method": 2, + "Params": "hFUBWOH9mBZi9VpvZ//EniBh/RK4GdFKAHp17DNOF2wAAABA" + }, + "Signature": { + "Type": 1, + "Data": "854MORzeNgax2hri62cDbwi+AW74Ij7HIbDA72mLySZAjSxpaN8DJNJGNNfnnLE+JCdGwWmWuKutOt0cUKv3HQA=" + } + } + ], + "Cids": [ + { + "/": "bafy2bzacedfv6z3dbz3y7l747wtm6v4sjih7yksw2bto4e5fmxwxytqf4t2cg" + }, + { + "/": "bafy2bzacea6v4gwltmtugdvwreujmnmf3k3igia5h7ytsfvyq5yik3jhbgznw" + }, + { + "/": "bafy2bzacec6ug37mcecfch4idqeaypbbskuqzckrfwhfrttkdxhdkihqhczli" + }, + { + "/": "bafy2bzacebnfxdc5vynxvpkqkgyilkdgad4wae3l42sl57tvj4jqqwei3zsrq" + }, + { + "/": "bafy2bzaceaofo6byvss2v257wsbpdct6pxzxjgi5ht6uo2nqdqzhcgmnnuwym" + }, + { + "/": "bafy2bzacec6wg7jjfxmabxklzs4gpwg62dqvg57spi4eqobndej6yxr6agili" + }, + { + "/": "bafy2bzaceb6mtzdviiicoumekvsl3kadtd3yyvnjilrpb2e4hvwchigxo2glk" + }, + { + "/": "bafy2bzacebp2wypw6vb3ghpp6bbcwttz4nifq2mkqe7rv3fw3ixuo5fwlbs7m" + }, + { + "/": "bafy2bzacec5qmbiufrhfsqkuwp4qlrhh4pza6c7to4m25prg2rvtlukutxumg" + }, + { + "/": "bafy2bzaceaccblunht2awecxt4gaarl2wbwspgvqqojnogpdgcfbqqc5n6svy" + }, + { + "/": "bafy2bzaceakpqtg7krgtnohzdbce5eswhfthq33qnniqq3snideletfn37m24" + }, + { + "/": "bafy2bzaceag5f455wukvnau2hymrlzh2rml5uz4fegeakagrbun22knbosu4s" + }, + { + "/": "bafy2bzacec746nf7ekbavo5secupvrzfk2q7ifqa3fx7nk2it6avsqeneejvi" + }, + { + "/": "bafy2bzaceaww2tmafgu7ia2w6tdjjlmln4c2s47qvzi3l6l6th6y5qtzwh2ps" + }, + { + "/": "bafy2bzacec6wa2kuywzasa7iz77u72v5xw6mfqowniv2ya2i72ncfs6vbjry6" + }, + { + "/": "bafy2bzacedlomnr45f4u6anm52iuv5lx67iqzryl6ggre22zhds5ga7wxwjl2" + }, + { + "/": "bafy2bzacedbde5bqyv4ayw4lafwnhqoz3z65ry6mzc5v7injaa5aelmmqhfb2" + }, + { + "/": "bafy2bzacecze7cp3p44ahuec7ma7givzblrvw7apbodvrfrowxct4372qlotu" + }, + { + "/": "bafy2bzacedh25tm65ivdko7oaz3jexjfyqpfyka2dq2r2quj4pgesjvq5ulbc" + }, + { + "/": "bafy2bzacecbk5holugw25qsxyt5doqlkts5zbzorhbad2wqojg4wp5ufiz5ta" + }, + { + "/": "bafy2bzacecmp5axn5rdx7bdnziwrechwfje4visnvyhs3y6zzhiuyn4lahvy4" + }, + { + "/": "bafy2bzacecgbdau27zy2n7xfyulbtibwjbtgmifxgd5hzvhuaq7i4pa43rsbk" + }, + { + "/": "bafy2bzaceb2w22i4x6y6j6p2mwrlcf4rpujpgzmiabkbai27vvws6p44tf7yi" + }, + { + "/": "bafy2bzacedmhgz55fv3xynuiknbmzu73b4ygfhqzdjvpqqd3clhqagifat5wq" + }, + { + "/": "bafy2bzacebzgoioyaxifebx63juczjmxd2nczwvy23ox32aflgu4saudqfihm" + }, + { + "/": "bafy2bzaceap76ommz77b2deqgn6ptphcnrjf2wmdpj46yexw3gg7l5xwazq4c" + }, + { + "/": "bafy2bzaceat3x7txyon6kxhc2beyvm6qr4pst2lswog6oanr7q4h76mviwsz4" + }, + { + "/": "bafy2bzaceag23ennnhcruxlevz5lq2cjx2obs4v4ps7zljemnargjwwzfj5ew" + }, + { + "/": "bafy2bzaceaaj2ycdfrtr7su42ax7vmbi3duklia3ddkai74ao4r433tvm7s5o" + }, + { + "/": "bafy2bzaceaqfnlwsypu73cmdi57i3542lx6onaciqux25vgi7yy4cxuroqohs" + }, + { + "/": "bafy2bzaceb4av53xh7cneavhg7cepo6f323lorgyn5f3w36fy46gs5ijcradg" + }, + { + "/": "bafy2bzacedpzkh7o3sg77c6shvf4vzjzrc4ka7uaq2dhlnefl27kwsxgck54o" + }, + { + "/": "bafy2bzacebnwzfm45ja7czdxsgldimsanju3sotyfth4so5aklg4bqjs5nwsc" + }, + { + "/": "bafy2bzacebgfg7mutvfivcqxwhki7lzygjv26yi4haxgngzejswjtishmtxps" + }, + { + "/": "bafy2bzaceangs6rq7iyy23vlsgn5vvwwx4pc7l73eelne7zpanun5dqy3xbeo" + }, + { + "/": "bafy2bzacea374omrotklarane74qvrydqonmtisskjfrd7braioditlb63hry" + }, + { + "/": "bafy2bzaceddofj57vkpjlqsk6s3t2atbblujq4fpvj657h4s5yvs7ieumkds4" + }, + { + "/": "bafy2bzaceaevdhwukiimdidv7xb2pdsikeelhg5jaayfquedcz7aprhhpql76" + }, + { + "/": "bafy2bzaceb7f5owlaekmrk7nhjac4z5mqqjgkiskh3yz5ueclopw3fu6bld7u" + }, + { + "/": "bafy2bzacebca7qjuntdymntls55dj3bsjnqfwvhz242phafrfyg42ze663kdy" + }, + { + "/": "bafy2bzacealpttnpjqnabrgo434ebuxjzwoitzdnkd7e7kpz2oymupzrkj2nm" + }, + { + "/": "bafy2bzacecrtb64vj3oxeuq3gvuvulmwsndfsyxw2d4cqa7cas5srnw6fkkjo" + }, + { + "/": "bafy2bzaceb6kvwm2b7eafk3srx47r3nju4wi6gjiqphn7toec24jb6wthzjrm" + }, + { + "/": "bafy2bzacedfmde6stug4hsjhnmqbjfqaxoo5htj7z7dhlgx6dm4egez2ubvsa" + }, + { + "/": "bafy2bzacebi5rr4i7oc6wbsd7ccelr25zhv22epawfiwrktu5yj5sr3kocd3k" + }, + { + "/": "bafy2bzacea7zwmpow4wj3yoyn6blub72zatryg2kpxsogqfdtrn74detisd2o" + }, + { + "/": "bafy2bzaced5pglehbf2f63cpdqhq7uw3nqjqipisvamzv4vj7o7uezxlcsjmg" + }, + { + "/": "bafy2bzaceaaeqln7mu5se43l4eg3ojozgnxpymddvduufxvexasesy6ra6v5e" + }, + { + "/": "bafy2bzaceagpksixm5j7yzk4nq7rnxy6zl2orhnfwyrkuvj6optrlxdrvkqa6" + }, + { + "/": "bafy2bzaceaqorfq4oa5e66ssw4oyryglxcpy6bvpq3dee56uaie2vs7rpoypi" + }, + { + "/": "bafy2bzaceaui57wgpuj5e3pkqfque5hrssrm7i7pnnhqteahia6nvwb2ekfis" + }, + { + "/": "bafy2bzacea2yapvdbqztp64iet3dtrkw4yke5qtjj3an4jirb3cy4ngzm6yce" + }, + { + "/": "bafy2bzacedqdcymquiwv2dex3us7mn44bgxatvxc52ouvno5vfdyttkv3cxr6" + }, + { + "/": "bafy2bzacednf746l62lowyxzzc6hdwo6qnqu6y3l5hwc3wtt3a5nat5j3thy2" + }, + { + "/": "bafy2bzaceb6qhy7gg3mkoouc6hxgj37hzmymxnq64cvzhnkj2kojyrkwvz6yi" + }, + { + "/": "bafy2bzaceae76z7ls5wc377ymh2geu36pmnx4pa44nkbxnf76csd7mrohieua" + }, + { + "/": "bafy2bzacealqllipxfdedv3vp7fhaiz5excj24palkoqj36jigzstdkmazjls" + }, + { + "/": "bafy2bzacedrz3pi3fehjnofeo5evwngtkqbvzev2erpzzuazdduzkgv67fsli" + }, + { + "/": "bafy2bzaceahe4jfesujxtlfahmo4l77wz77sk5i2vyfrpr4zy7ml3fokybg34" + }, + { + "/": "bafy2bzacebkep72hujq3xt4t5jycmvslgb3tfs4jbltl2ol73qlxd5wauygsm" + }, + { + "/": "bafy2bzaceac3vzbrjsdtzq4mcblggv4avc52erbw3nj4dwgrcdqbs3pffzftk" + }, + { + "/": "bafy2bzaceaprxoe5wgdswiqramvrit2ozn5pkrqvotxuww6xvskwky5jpceds" + }, + { + "/": "bafy2bzacedpxow7sb2roz2iasn56nam2pec5ol4k5y5gd6iqr64qgkfo4rvba" + }, + { + "/": "bafy2bzacedlodifjgof4azs4i5rt4w4chvexlnxhgwnkayabeuz5hkqwmc3tq" + }, + { + "/": "bafy2bzacecjfvxn3d6oxsey7t4nq7bwbdnb2magaydn7abtznjnjtdmin3zqi" + }, + { + "/": "bafy2bzacedxoyikiomoh3pcr7tuoddoqknx6k5w2ut5pojigkcluzfukczeza" + }, + { + "/": "bafy2bzaceaxaxbv6kr423c4gmtid4ito67wywwhknz745xuicw6wpzcbpwmfg" + }, + { + "/": "bafy2bzacebveeiuw27o6xygc7egfbiplou3wyf5tnmh3i3yy4zxxofhb2ldxg" + }, + { + "/": "bafy2bzacedmzcojbg7i2bcp7r47n6xk26qzgmd6b3dfsmfkromgzdjnr6vnhw" + }, + { + "/": "bafy2bzacecfti2ujdzcneomi3tfdciblrcm24hlonvep4uu7f7sknxs6nbv22" + }, + { + "/": "bafy2bzacedrhnwihhmkcyuhgf55sz3zwrb7s6btjxgbqu3nkp43yl4c6nwmwe" + }, + { + "/": "bafy2bzacedhqgvkn3i5ri72mo5bcxfpmzltkyl5osiduox6lj5pzs7qoyzeas" + }, + { + "/": "bafy2bzaceds5jr6unpcoo6deadvqbeqq6hgjoopij4b5dkgxeeqriq7lel2nm" + }, + { + "/": "bafy2bzacean37yl6houpzikd7qcaf65xppuhsspkkyzeyds7azosd23y35ljy" + }, + { + "/": "bafy2bzacea3raqfvay7am4ddcwf4oyjgzptvqoey35tis6i7d5wizcxsfhybg" + }, + { + "/": "bafy2bzaceaqepycsr6uizmlmcoqjqp74hnipq5ei5caiezm725vjsffrhxawo" + }, + { + "/": "bafy2bzacec646a4ftg3bhnucavra2dozdgkp3vd2y4ntlhsfzmd3ibwjlay4q" + }, + { + "/": "bafy2bzacedpo633dm7i2zfwj2xgaxcrozl6jpqdp3tz6kzcray2ihw2ehhdbg" + }, + { + "/": "bafy2bzaceb5g5okyglzg3csdudhxrbseymxud66nqrswwer3pbitksalohmcq" + }, + { + "/": "bafy2bzacedudoknop5psrvo7boijutxfg6l26gcir25gtxmpu2sjmxznxed2w" + }, + { + "/": "bafy2bzacebi3xylknfutifsy3yuxzdqoxyooiv5gxpyq6tenxmrm4bsh4pe4u" + }, + { + "/": "bafy2bzacedopnrqpxqcjgds2kpmiorb5k7533r4pja3vmo3l2lb5sabof4tbw" + }, + { + "/": "bafy2bzacedujbxmjj7kog3u7qks3wftx3n7t3wkkps5shtr2tycoq2uoo6mbc" + }, + { + "/": "bafy2bzacedki3dd4bv6ieh3yucyd3vg4xp7pu3r2v5t7iwal3fyhkm6354mig" + }, + { + "/": "bafy2bzacechjqrkcivj2l7uqrz2azmwizkuo5ik3l4xis7fgacxcqkecgfhvu" + }, + { + "/": "bafy2bzacebdcw6rslqzw3sg7qgauz7vp3pajgknujle5ifgie2ndnmo6kjwlq" + }, + { + "/": "bafy2bzacebv3t3vbrzx5ej7zgvshv3tw552t2fpx3x2my6zvwjce2wtsykuky" + }, + { + "/": "bafy2bzacec46ycpz4fs64vg45ltzksc2cooqlftpxdp47d64ad3fdoodi53z6" + }, + { + "/": "bafy2bzacedoz2clu3wachh2rdtgt6cxwxebnuz6ivpobvf66zz6jhkei4vpme" + }, + { + "/": "bafy2bzaceaufl4egkumh2vc5vfetthk2dh25t4s7id6ppxh6q7pqvsgwkp4xu" + }, + { + "/": "bafy2bzacebrwbqhv7unpqtkoqlwgza27c72jqr2fnnalazqngwh2k2jdeuoge" + }, + { + "/": "bafy2bzaced2xeldtp2q4ds5jkofacsl3bystskkqocwe3vzv5mwndu3g6v43i" + }, + { + "/": "bafy2bzaceaom3igg2pm6ojezqji655vmsfwn4fjk4jr7vkvqoy2di2p2nlye2" + }, + { + "/": "bafy2bzaceah2ihyli5b6drwdrcx5bjuqh3ur7iueqoeopvqlvodjzeb5esopc" + }, + { + "/": "bafy2bzacebqfqdq3nrdk4hikr44n763mahabj5cytay3rpyogyv7hxdxu4jzi" + }, + { + "/": "bafy2bzacedx6n6ilzummihlwqzvp2vpee3wf4sanp2igxxyueeurvfsumev7i" + }, + { + "/": "bafy2bzacecignffu6vcvbgyfsjfcnnhbz6ynjh2ziiqvfds2ufynu7n6scpai" + }, + { + "/": "bafy2bzaceazq7o25lxa6hfhzlc6aud5aiqyimdmjuexxtboyrc7jpjnhneiae" + }, + { + "/": "bafy2bzacecjmdph662yb4d2kko4bd4lchay75pslryq6ijis3y2sbx2ynl7v2" + }, + { + "/": "bafy2bzaceddztfslaohw246jytacdwtqfvibr4o7vshgckxw7slbcpxcpssei" + }, + { + "/": "bafy2bzacedecgc4i25j7ph74yyqz7utnztk7qpnsf4xvmuiqcsazux2t5lckk" + }, + { + "/": "bafy2bzacech5lo62kxb4w4te2zxovr4btrpymutyy5jio5nyjff46os2jlhh2" + }, + { + "/": "bafy2bzaceav4l6zvbx4wtyojeryirgwvjxdohmtsa3ud5opmgjzvedm4phrts" + }, + { + "/": "bafy2bzaced3gbhak2oupe3swpnpvfa7es4eiarvvonugvtwbecy5yrjbasjem" + }, + { + "/": "bafy2bzaceaxvrb6udo3oar2kfeb6b64f6fwjcf7ub4uwke2temwxufq7tqlsq" + }, + { + "/": "bafy2bzaced7edis3oajcdvgyrd2vrioxhm7ffabq37ya3iviocofckhxrpzsa" + }, + { + "/": "bafy2bzacecvfj2lsmwvq5nb2izcyzydbxtdgukavuqajvx6znqelravpirmlc" + }, + { + "/": "bafy2bzaceck4xyrmt3lrut2cqdrdcwblenmrvkvib7iioh7jhz5qxylxaisjk" + }, + { + "/": "bafy2bzacedodfnmepxcdifxup52okfiyx6gwrfaezcgxwdjmy5cexi5czwuxc" + }, + { + "/": "bafy2bzacecvbkg3k3mqt5f6ghocbrxep5bqzlpp5rmiwztw4zedrijtbydwnu" + }, + { + "/": "bafy2bzacedspuejjyvs22olevpm2augoq7pqwfq5jqqtuzg3selxfmrydnz66" + }, + { + "/": "bafy2bzacebguomvmhooifkxvwlmwzstw6sly2iictpygpgipyitxl5kwbwlli" + }, + { + "/": "bafy2bzacedidy4dni7zhpj6b6hvvvhteuvjrzj3onjrmoeqmbgxmoxsinstiu" + }, + { + "/": "bafy2bzaceaxhbuyxqpkvbhtnx7uwnr7ejombalfy6wdw3azt23gzuqzupbrtc" + }, + { + "/": "bafy2bzacecy6k6rah4tfanivk3eghc2qewirukaxtzjabotolnededxjqqnrc" + }, + { + "/": "bafy2bzacebx2swrcd6qawlhm6jpidtcwchiuoxtnzzuk2fgz4e7gnvgrs2nz4" + }, + { + "/": "bafy2bzaceccrzwgdxuwwk72tnpju6lnqwz65hov5mg4ooqdox3n5mnv4ocdak" + }, + { + "/": "bafy2bzacec5jcdiwul3qq274ye6ay2olyoij6hybuajlvfqgzrqsuucm2adqa" + }, + { + "/": "bafy2bzacecq3dhlmj4iab4byyzhfapfha25juwurfmjycw2btbymdk6f5b3su" + }, + { + "/": "bafy2bzacebm6pxzyizpxgbianayazfe5imzurbvmx43i6glrxj7piiyznivq2" + }, + { + "/": "bafy2bzacebb7wbtkmlnbmbssmjd3raqljouz7iadkuqy7pofsuy6duq3s2qn2" + }, + { + "/": "bafy2bzacedxortgzv234wnnddevk3ofu5sgvglvoeodddoyo45rgxdi76im46" + }, + { + "/": "bafy2bzacecm5hr6uvs5dvkxbhcfuf5cwnyb4bj6grt4mlrtrjukj47pf5keh6" + }, + { + "/": "bafy2bzaced3tuzh5ravyfnqjyx5e26uymsxxsdmspeijj27afxurgjermjsm6" + }, + { + "/": "bafy2bzacedfapkrtkgog6yuimjrzh4tup5qmtms24iegi6jj5236ae6jyqula" + }, + { + "/": "bafy2bzacea6f6pkynzcmadgzjpftohjbh5t2hny5ru7jo7js6v7yigjrqe4ai" + }, + { + "/": "bafy2bzacec42mhil5aacpkzvgqfvwiutxicd25ozo7aouk3pwtydcoshb3mh4" + }, + { + "/": "bafy2bzacebxnc5u7ma7lzk2n2hhub4o3qcalckl4kdgo3z3legbwdubj7n56i" + }, + { + "/": "bafy2bzacedyfk2lj4vwfv2id5csq4hfhfcbhfw5if4grjj44imfaob5xpryvy" + }, + { + "/": "bafy2bzacebd2g5mkgfrdpaegxwa35iul27532mls3nje3zqs5c7sezfufq2sw" + }, + { + "/": "bafy2bzaceaoonskvzte43reugau6652ecgxwcpjcxxdp3t7xvkg5kxd5gle6c" + }, + { + "/": "bafy2bzaceayutpz7wu6pgrdfeaqxjhfdhc5sqg5y2viyjvs5f2fmbjfccw5k4" + }, + { + "/": "bafy2bzacedgdn2nu7quq6e3wrfza5pjlmjoy7xlcopi6bmzawuidcosnhp3eq" + }, + { + "/": "bafy2bzaceblbu2jadc6hjuli5v5jvdoqosoidvmwkunuk2h5zrnl37ayen2f4" + }, + { + "/": "bafy2bzacecbmuvsyu2ayypf6ycdqpvbqh4i4zqxrgdkj5bbhwl3ntrkp35rgq" + }, + { + "/": "bafy2bzacebauvtwqrgw7uzy5ndk2htporh5owd7hcghrbx5tgszszd7oz2glq" + }, + { + "/": "bafy2bzacea4oyafell327v4othtmluxhxzwymzlvcwd2hyvqqwmaoyhhz4ejq" + }, + { + "/": "bafy2bzacebgtp2hig7fe6vvmg2qb3bpsvwgons4ajgd2mewvi4hmrv3k4pc32" + }, + { + "/": "bafy2bzacearrgqrihpgsxim6dycxvpqxc2zus6myxarvdxaw55s7wx63qmf4e" + }, + { + "/": "bafy2bzacecaufl6i37x3yueswkwgqbqle2gyd5x62mrgqtv6r6kniaykfb26e" + }, + { + "/": "bafy2bzaceb27vbmz3b6vnxrhcknj2k7ywscvti7hwz62hjvajcbuntfjya55a" + }, + { + "/": "bafy2bzacealzoacizh34y5otjrf6cm2bxq2v4rjss3mvk3qbobbdffllq65ce" + }, + { + "/": "bafy2bzaceax4ndy7yjbys4alma3pduuniyxv6pyz4zq4th5bxup3nyqi3o2uq" + }, + { + "/": "bafy2bzacebmv3xp2mumpt4b7hawq2eirlqahm2qjbuus7a2vzg7rejbreee6y" + }, + { + "/": "bafy2bzacedhxbtme5dbl4ewsa2zsr7mphd5gtwimxy6mag73e3qv6hc3qqtwq" + }, + { + "/": "bafy2bzacea3zpvmys7jtkbqip35jxryiiuxxmd7mhxbzq2loivzz4dpdtnpjm" + }, + { + "/": "bafy2bzaceb7vit7tkehsttrshl4na6y66iqmy4ei5damhtezoliqquue5dzsq" + }, + { + "/": "bafy2bzaceczzngeovyp5rlbxk3anqxshw46m6xsux5g2hb6clcvi72z2gfbq2" + }, + { + "/": "bafy2bzaceb2zduelngpedvemug5t7tgmeep7shhcwmjwd3qj2emau66k6aqhm" + }, + { + "/": "bafy2bzacedwnnsn7fn4uncghicc5mpjxhqb4s4fzp4gfrcz36bkzu5bd5xpjo" + }, + { + "/": "bafy2bzacedw6qldlkdyzo2lumxy5zqkjxyl5555zezb3rp7hif5cirb6smwng" + }, + { + "/": "bafy2bzaceavxubnlv6w2jzltgyql3tzrxyioyvtznt3yqngajl4m4gzzuiioy" + }, + { + "/": "bafy2bzacecjn2znf7c65k625ry5dvizq2inq7yrwxlcy63xqs2tl5x4kujbo2" + }, + { + "/": "bafy2bzaceatyiutvzk5fgyg6sgsxwgrghxbe6awl6wwp4haofbcadxqtzdrcs" + }, + { + "/": "bafy2bzacecyjt42zntvnmp55thtdxiqcxephkbxkq6oypcte63b4rgat6opr2" + }, + { + "/": "bafy2bzacea2bn2kjgfpcenqfkdzricsja4s5cw4ee5a22ypn2xdlzj2hd2jq4" + }, + { + "/": "bafy2bzacecqif6y5pci22pjjnvmcyk7dta5xe4ikhw2yv75fgualkhksznk7q" + }, + { + "/": "bafy2bzacecr27smdgxi5js2hxg7izbn66liymo234qqx6c4yjoglc7quediac" + }, + { + "/": "bafy2bzacedrvkmzhmelnulxrfjqrsimt4kuou6jl76svhbxgcvsho32d5whra" + }, + { + "/": "bafy2bzacebm5kwc2biyyaqswltrfgrk7cv22hcrfdkhckpqjq3awsu6pws4si" + }, + { + "/": "bafy2bzacec7pkm6xzcrotw3y5zdytbgy6udft2loqf4j2le62ruz3oulmanfa" + }, + { + "/": "bafy2bzacebpincfj5bktd6mkobriv5vwiagorvgweuo5yphn6z3ajzawv7q2y" + }, + { + "/": "bafy2bzacea6hjkpdhakn673z7lqrc5byioxre5ht554gm5zulpxpevj7dbnzo" + }, + { + "/": "bafy2bzacecxjdmz6t4h6gbcohruvmaktabhpvcxyet7tlj6bkmmbaovqrboki" + }, + { + "/": "bafy2bzaced6glm7pvr2jajenx5pkmjwee3c6y3qe2zolqhixbp6iujndqzj5e" + }, + { + "/": "bafy2bzacean2xfyr7i4tjsrqbgdiuqqc7z5wt7jsw6x3qomuebkspvjfxd7ke" + }, + { + "/": "bafy2bzacedsaz7ovgjkb7awf6s7y624bpw6js3i5lr5vas6wmkh4tirbnpphy" + }, + { + "/": "bafy2bzaceaaeyi44qw4cgie3dwkzysocj3a3xddrskwo7aqyg4h3xi4q7gjla" + }, + { + "/": "bafy2bzacedbgkhrms6hwivadwy25znnpamuzwjyib4ewgxrcejqzoq5sc5pme" + }, + { + "/": "bafy2bzaceddg2ogejnzovciqjxkgaqgg4a5pvarbfseqnjn3bjczq72ui7mw6" + }, + { + "/": "bafy2bzacec76cak2ft5t57g7eewzae2g4qlh4vdx5the64mhylguei4g2m676" + }, + { + "/": "bafy2bzaceapw3tme6fx7fg4xpfzmgkxt6bdfh2kpmvy3brpc4bxo236je62g2" + }, + { + "/": "bafy2bzacedqhopibbutecx5u6z6xcyomvzuw7fmpg2kfpfn6a3rmaoxomot2q" + }, + { + "/": "bafy2bzacecn7qvfkfcfpwvjnqk3rsviqjnacfdh644kyvkdfwkgk3xujubfm2" + }, + { + "/": "bafy2bzacebe4u63s7jvj3qt73pnulztu4jv6yq3ikulqcdtnm2hr2a43p34fa" + }, + { + "/": "bafy2bzacec42kl5w7mvbs3ic3ipih4q6eho6avhvhxxilc2jev33t6f2cytkk" + }, + { + "/": "bafy2bzacebd7tidwh6vy5lxpn3tv6i5yqn7s4rttaxrbttfdvwvtdirc6tesw" + }, + { + "/": "bafy2bzacebwd2ooq2oko7lhigoeup37tywatk2hsuhjuaa4x65f24arpkubcy" + }, + { + "/": "bafy2bzaceartfnukagy4cebtkanuj5quoh7mj2br3snghrxxopqy2h2vcvfnw" + }, + { + "/": "bafy2bzacedfxealgp3xme3o2jkuqz5ylykznec7epf3zevbf3m6n7tozltyao" + }, + { + "/": "bafy2bzacedeavfgbycmevol7khezw65nhuw3uma26fr6pmk7j6hlse2jnp3f4" + }, + { + "/": "bafy2bzacecv3nwgnz75og5kdjitqrfh4dsne3guxw6vt7ndlp3q53zo3quyto" + }, + { + "/": "bafy2bzacebapky35yjv7moo7ppjrk3k6e4qbmt6i26q7cfpgm3i4bkgt54i4k" + }, + { + "/": "bafy2bzacebz2j2dlm7p4d5cipaagzcxmcxovvetawp5uej33mzxyibyf2fqey" + }, + { + "/": "bafy2bzacebxtwc7mhhissdpk4ruxoklctk2yff2bygzrnfvdpedhx5of3ttma" + } + ] + } +} diff --git a/platform/filecoin/mocks/ChainGetTipSetByHeight.json b/platform/filecoin/mocks/ChainGetTipSetByHeight.json new file mode 100644 index 000000000..4838d132c --- /dev/null +++ b/platform/filecoin/mocks/ChainGetTipSetByHeight.json @@ -0,0 +1,196 @@ +{ + "jsonrpc": "2.0", + "result": { + "Cids": [ + { + "/": "bafy2bzaceca6n6sqyyfexclyo3yeinj3ihamd5whfpxnss6pzmdxs6obqh5mc" + } + ], + "Blocks": [ + { + "Miner": "f033130", + "Ticket": { + "VRFProof": "g0ei5BNIAWjWn24m22fh8iXY59stLoNr9TjP8aQyDbnEez87t+PLOjTcIKg18GcFDRuenomxVbdyXEn0XrhaeZ2G01cmUfveYDJG4CcIfuzX6Sh0FWiZYIhNOOoyPIiV" + }, + "ElectionProof": { + "WinCount": 1, + "VRFProof": "kTVIw/UGXzREwqiKFFTw/wkyg9yAc24A9YS5cK5tpt0F3Mmv45ezP6tjzu/OP1f4EUmuK4Z2KXLa6SganAX4RB6ueMELzgCsUvAJJaWbHeoeXG2HxZXixW8mA/wLopeD" + }, + "BeaconEntries": [ + { + "Round": 339434, + "Data": "kxqziKg0KKpF6BO/4+ONq0PuxWNE9yAYc8163CKzKmIW+IFUdFFfkxK/UYNpvtL/FGWYOIRmOq1l5jIwJ+yXtw+65cbNUdfXO5NbRws4HY6DsiN8stpuXIuujO237yup" + } + ], + "WinPoStProof": [ + { + "PoStProof": 3, + "ProofBytes": "qvj6xfDBYRDVI3YtfJxbMu17XI9pGpnd3Cx4zL6IZSafx2suJiEr0ZGVa2SO+TMzonqKAvSjSOwxrgPI45jeZy9nRYOO4VOPo5H3jGz/OwDcz1hRB2ldQLn9hWyyyaWECbUD77uhnxhR0VXFPpO7YSo/eS4h0phLY/x7PAlJE46B1ozdOuDNCx8HmJDmcfolhmX5qqtWKAyoPeBtfwhnSMZ1CS+wjMZBC8jo4M8HI2gtjQCZqlp3n3pKSlwEFwOE" + } + ], + "Parents": [ + { + "/": "bafy2bzaceb2oioogn5spogg5qd3s77h6y5nl65yg2ihtwsy7gz5ya5js2psfw" + }, + { + "/": "bafy2bzacecgvr4vq4owqyb2kosfohcz2tsjopa7iprikdruhqh6eacd5maopi" + }, + { + "/": "bafy2bzacecuyfvfsdbjydw6z2ymswcrnzcopetgwkz3ja6r252mrc3bidkgvy" + }, + { + "/": "bafy2bzacecpovgb6stxmpjagtyjnxbor375afxztmgr5z62b5dwlivwh4jq4q" + }, + { + "/": "bafy2bzacecplfcf3jpirxua4szvhbh3youjyec5u2ifeeha764lmsmqorl7rc" + } + ], + "ParentWeight": "5085326167", + "Height": 243590, + "ParentStateRoot": { + "/": "bafy2bzacedizpvzsmkr7lv5bl5zpp5y4fuyb5nz7dgdycbi4hbopiyiu534qe" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacebsijpga2dovhvvkctky3zncdkhlfp2673hpbnc2vz7pd6r2agbgm" + }, + "Messages": { + "/": "bafy2bzacedpgiddoj7tht6yafgen3br7ozllj7ysghnzfxp6jae7l4v3a37eq" + }, + "BLSAggregate": { + "Type": 2, + "Data": "sctdQjn/f+NJGpMocEeElSkB1dR/9rb9TC8PF/IdqzqUWcjXrP8NgHsMtfUsJU1GEczsyWRX59axHy/Y7Roub2/o06WwfbMIb2jjKsMNr37+PeiR5rdqTZZTd3fL6uT7" + }, + "Timestamp": 1605614100, + "BlockSig": { + "Type": 2, + "Data": "koyrqh5EW89wU9TMKls7li0g+cZkmT2vgRuixgYDQuGOc+LvZbrACtdDPE3E9wIlDXu+l8YgWy3kP9eKqycxU7EptytrUCHTTOzB4TsJU82MQYsQe8wx/pmiUqo4g5NQ" + }, + "ForkSignaling": 0, + "ParentBaseFee": "957593361" + }, + { + "Miner": "f024563", + "Ticket": { + "VRFProof": "g5h6RT/d4RRi59X3Baio+e8Xv4XRIGSNiv6IaOFfKUxRfXgdKACLkEpKaSFfy320EyU3iVZlHj0ZDOhGdAJuguO3jKUTr2eAYSAJkbs4Ii1vR2+Vl5s3Se/ke8biyOAm" + }, + "ElectionProof": { + "WinCount": 1, + "VRFProof": "hKIZ8H1FJNZKj+1o95+MHpqg7U8r/8g/9WmDJXCfxjXv5ccNbZDkJRyzJF8eq72vEw+Z/HJ1AvLg4ZELa0JJuTacSdXd/p46k2Uvp8ksIuOuTGUYvTeARKNyqyzBSB/a" + }, + "BeaconEntries": [ + { + "Round": 339434, + "Data": "kxqziKg0KKpF6BO/4+ONq0PuxWNE9yAYc8163CKzKmIW+IFUdFFfkxK/UYNpvtL/FGWYOIRmOq1l5jIwJ+yXtw+65cbNUdfXO5NbRws4HY6DsiN8stpuXIuujO237yup" + } + ], + "WinPoStProof": [ + { + "PoStProof": 3, + "ProofBytes": "l0cnzfcm5mNz7D/G4SDcKlp1p5h5JD04Zm/LQCnIoJMTWZoPwl5WH81Gs16wWOQPtJv7GTYuXal7M1sgvDwidXleqm1Yf8HGvjLdzkd/7YNmNibsHCDI0VC+UDjK/Kr4ALtPyhii5p0MFRKer1y+NkQNbnh64ZUz42h+Q1lI1WVSqMIbJULGlJg+/RYjdgMkmKvY82e6sf0T0n7694QMXbo15rzSmEhkF+2qmj7qHBfNjjMgCMLDZ7A4uFmf/EH9" + } + ], + "Parents": [ + { + "/": "bafy2bzaceb2oioogn5spogg5qd3s77h6y5nl65yg2ihtwsy7gz5ya5js2psfw" + }, + { + "/": "bafy2bzacecgvr4vq4owqyb2kosfohcz2tsjopa7iprikdruhqh6eacd5maopi" + }, + { + "/": "bafy2bzacecuyfvfsdbjydw6z2ymswcrnzcopetgwkz3ja6r252mrc3bidkgvy" + }, + { + "/": "bafy2bzacecpovgb6stxmpjagtyjnxbor375afxztmgr5z62b5dwlivwh4jq4q" + }, + { + "/": "bafy2bzacecplfcf3jpirxua4szvhbh3youjyec5u2ifeeha764lmsmqorl7rc" + } + ], + "ParentWeight": "5085326167", + "Height": 243590, + "ParentStateRoot": { + "/": "bafy2bzacedizpvzsmkr7lv5bl5zpp5y4fuyb5nz7dgdycbi4hbopiyiu534qe" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacebsijpga2dovhvvkctky3zncdkhlfp2673hpbnc2vz7pd6r2agbgm" + }, + "Messages": { + "/": "bafy2bzaceaute5p2f6muqyzaqarupxt3k3jb2wpzswnamnv2zkramjrkdcz26" + }, + "BLSAggregate": { + "Type": 2, + "Data": "uFZuhqr7pj08swYQiPCZDmiJnJBDsCxKmw1FSWYLgUBvkwPpwtSFaHj+W3o+hNYWEcZBf8spX5VArHaIt7B7W3CV2XUQlwzhptbX1K3mNfkCPiGMwB65owT/xh9O/cf7" + }, + "Timestamp": 1605614100, + "BlockSig": { + "Type": 2, + "Data": "kf6f9VTCnPX9rTzWDab8aF0OSGFfmVqH6xyL1zssyU7PwINIjQn58sP31E1sfSGfFmRmKGfv0GBa1XP9EfBZcyj7miTEe7fCLTIYaS3ZvtFLnHSmylJHSGp6H00fIzwv" + }, + "ForkSignaling": 0, + "ParentBaseFee": "957593361" + }, + { + "Miner": "f02490", + "Ticket": { + "VRFProof": "pUa1oaYhxCGlbJ5kRtV4gSh1q+ed39VKc6J45GGLa2G4ZpHDkB3YP3z7u95aq+YHCIa6WutJhSgTjCmgtS7R9shibMpgMAnq4V7V2pMe07gWKZ0DUAAIM/D7sM4XCTRv" + }, + "ElectionProof": { + "WinCount": 1, + "VRFProof": "k6UQkvSHV6sWXPKUB7KEQRh7m6n6cAIogKbVjBQHaR6e0ok3JA3tcVFh7jUX7ERpBsYoJonN4ctCIXT82B6iSwisa+yiX8/X2nKGVbmB1oaWB86jOZQc+lqUkefJrB/C" + }, + "BeaconEntries": [ + { + "Round": 339434, + "Data": "kxqziKg0KKpF6BO/4+ONq0PuxWNE9yAYc8163CKzKmIW+IFUdFFfkxK/UYNpvtL/FGWYOIRmOq1l5jIwJ+yXtw+65cbNUdfXO5NbRws4HY6DsiN8stpuXIuujO237yup" + } + ], + "WinPoStProof": [ + { + "PoStProof": 3, + "ProofBytes": "tCFxee4dl0/JELevW8wRY3ygztrR9Q3hlKu3Ehxi43WF1nKF2OxUFJgAyDRlr3DvgbttMAgQ9Sa9RUU6xZBIe6ZTs27GcNiVq99rqPgcYPMv1GFNfpz5lAJLvAODeBLhA04EcDbL9zmkfTN6nkMgKv6FSP1C2ghHB33A+qRXwVQ/WmiEb2g5rvC2X36Z9U+0kyR7ZO7Tr3/5R1J20Mlzt9gtDLyTwIlaa6xu4YzxRwcJi1461OpcOHoie/xhphk4" + } + ], + "Parents": [ + { + "/": "bafy2bzaceb2oioogn5spogg5qd3s77h6y5nl65yg2ihtwsy7gz5ya5js2psfw" + }, + { + "/": "bafy2bzacecgvr4vq4owqyb2kosfohcz2tsjopa7iprikdruhqh6eacd5maopi" + }, + { + "/": "bafy2bzacecuyfvfsdbjydw6z2ymswcrnzcopetgwkz3ja6r252mrc3bidkgvy" + }, + { + "/": "bafy2bzacecpovgb6stxmpjagtyjnxbor375afxztmgr5z62b5dwlivwh4jq4q" + }, + { + "/": "bafy2bzacecplfcf3jpirxua4szvhbh3youjyec5u2ifeeha764lmsmqorl7rc" + } + ], + "ParentWeight": "5085326167", + "Height": 243590, + "ParentStateRoot": { + "/": "bafy2bzacedizpvzsmkr7lv5bl5zpp5y4fuyb5nz7dgdycbi4hbopiyiu534qe" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacebsijpga2dovhvvkctky3zncdkhlfp2673hpbnc2vz7pd6r2agbgm" + }, + "Messages": { + "/": "bafy2bzaceaz4aw5fdtispsrpmvjckzzpcc675kpdqsl4l7khlsd2w6gpvc36i" + }, + "BLSAggregate": { + "Type": 2, + "Data": "rdcE8jas3aeVtdZN9GMINJTvLeugBr6nD0+dVBblkk4jznyYhJJR9hA56Vi722AqGKDdFLoE/vonGKwhP51QMgv0Gcg95vOgaVtSOZyBQ4ODfy9uXVaAOtm0koZZTH7T" + }, + "Timestamp": 1605614100, + "BlockSig": { + "Type": 2, + "Data": "rTn6iXHp97b5w2ktP/0EXc5esfePPcjDnh7DVMEVkjUZ62SHrYSfGlsWrzkdtY0IBITY0p3w1j2+xZ7dC5gJ863H0nM0bI6edPkuwnsPe6PcTZ2jVmWg8iHiCGnSXnK6" + }, + "ForkSignaling": 0, + "ParentBaseFee": "957593361" + } + ], + "Height": 243590 + } +} diff --git a/platform/filecoin/mocks/ChainHead.json b/platform/filecoin/mocks/ChainHead.json new file mode 100644 index 000000000..471485b21 --- /dev/null +++ b/platform/filecoin/mocks/ChainHead.json @@ -0,0 +1,202 @@ +{ + "jsonrpc": "2.0", + "result": { + "Cids": [ + { + "/": "bafy2bzaceca6n6sqyyfexclyo3yeinj3ihamd5whfpxnss6pzmdxs6obqh5mc" + }, + { + "/": "bafy2bzacedi6lyer3xf4axumo2mgtwa52qw5kmtzt5ken3w6oo2hdhg63szoa" + }, + { + "/": "bafy2bzaceb3ppcax237vxf5vwq5uckmwz2x2z3k2zfnqbjcaudrg3byzcipyi" + } + ], + "Blocks": [ + { + "Miner": "f033130", + "Ticket": { + "VRFProof": "g0ei5BNIAWjWn24m22fh8iXY59stLoNr9TjP8aQyDbnEez87t+PLOjTcIKg18GcFDRuenomxVbdyXEn0XrhaeZ2G01cmUfveYDJG4CcIfuzX6Sh0FWiZYIhNOOoyPIiV" + }, + "ElectionProof": { + "WinCount": 1, + "VRFProof": "kTVIw/UGXzREwqiKFFTw/wkyg9yAc24A9YS5cK5tpt0F3Mmv45ezP6tjzu/OP1f4EUmuK4Z2KXLa6SganAX4RB6ueMELzgCsUvAJJaWbHeoeXG2HxZXixW8mA/wLopeD" + }, + "BeaconEntries": [ + { + "Round": 339434, + "Data": "kxqziKg0KKpF6BO/4+ONq0PuxWNE9yAYc8163CKzKmIW+IFUdFFfkxK/UYNpvtL/FGWYOIRmOq1l5jIwJ+yXtw+65cbNUdfXO5NbRws4HY6DsiN8stpuXIuujO237yup" + } + ], + "WinPoStProof": [ + { + "PoStProof": 3, + "ProofBytes": "qvj6xfDBYRDVI3YtfJxbMu17XI9pGpnd3Cx4zL6IZSafx2suJiEr0ZGVa2SO+TMzonqKAvSjSOwxrgPI45jeZy9nRYOO4VOPo5H3jGz/OwDcz1hRB2ldQLn9hWyyyaWECbUD77uhnxhR0VXFPpO7YSo/eS4h0phLY/x7PAlJE46B1ozdOuDNCx8HmJDmcfolhmX5qqtWKAyoPeBtfwhnSMZ1CS+wjMZBC8jo4M8HI2gtjQCZqlp3n3pKSlwEFwOE" + } + ], + "Parents": [ + { + "/": "bafy2bzaceb2oioogn5spogg5qd3s77h6y5nl65yg2ihtwsy7gz5ya5js2psfw" + }, + { + "/": "bafy2bzacecgvr4vq4owqyb2kosfohcz2tsjopa7iprikdruhqh6eacd5maopi" + }, + { + "/": "bafy2bzacecuyfvfsdbjydw6z2ymswcrnzcopetgwkz3ja6r252mrc3bidkgvy" + }, + { + "/": "bafy2bzacecpovgb6stxmpjagtyjnxbor375afxztmgr5z62b5dwlivwh4jq4q" + }, + { + "/": "bafy2bzacecplfcf3jpirxua4szvhbh3youjyec5u2ifeeha764lmsmqorl7rc" + } + ], + "ParentWeight": "5085326167", + "Height": 243590, + "ParentStateRoot": { + "/": "bafy2bzacedizpvzsmkr7lv5bl5zpp5y4fuyb5nz7dgdycbi4hbopiyiu534qe" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacebsijpga2dovhvvkctky3zncdkhlfp2673hpbnc2vz7pd6r2agbgm" + }, + "Messages": { + "/": "bafy2bzacedpgiddoj7tht6yafgen3br7ozllj7ysghnzfxp6jae7l4v3a37eq" + }, + "BLSAggregate": { + "Type": 2, + "Data": "sctdQjn/f+NJGpMocEeElSkB1dR/9rb9TC8PF/IdqzqUWcjXrP8NgHsMtfUsJU1GEczsyWRX59axHy/Y7Roub2/o06WwfbMIb2jjKsMNr37+PeiR5rdqTZZTd3fL6uT7" + }, + "Timestamp": 1605614100, + "BlockSig": { + "Type": 2, + "Data": "koyrqh5EW89wU9TMKls7li0g+cZkmT2vgRuixgYDQuGOc+LvZbrACtdDPE3E9wIlDXu+l8YgWy3kP9eKqycxU7EptytrUCHTTOzB4TsJU82MQYsQe8wx/pmiUqo4g5NQ" + }, + "ForkSignaling": 0, + "ParentBaseFee": "957593361" + }, + { + "Miner": "f024563", + "Ticket": { + "VRFProof": "g5h6RT/d4RRi59X3Baio+e8Xv4XRIGSNiv6IaOFfKUxRfXgdKACLkEpKaSFfy320EyU3iVZlHj0ZDOhGdAJuguO3jKUTr2eAYSAJkbs4Ii1vR2+Vl5s3Se/ke8biyOAm" + }, + "ElectionProof": { + "WinCount": 1, + "VRFProof": "hKIZ8H1FJNZKj+1o95+MHpqg7U8r/8g/9WmDJXCfxjXv5ccNbZDkJRyzJF8eq72vEw+Z/HJ1AvLg4ZELa0JJuTacSdXd/p46k2Uvp8ksIuOuTGUYvTeARKNyqyzBSB/a" + }, + "BeaconEntries": [ + { + "Round": 339434, + "Data": "kxqziKg0KKpF6BO/4+ONq0PuxWNE9yAYc8163CKzKmIW+IFUdFFfkxK/UYNpvtL/FGWYOIRmOq1l5jIwJ+yXtw+65cbNUdfXO5NbRws4HY6DsiN8stpuXIuujO237yup" + } + ], + "WinPoStProof": [ + { + "PoStProof": 3, + "ProofBytes": "l0cnzfcm5mNz7D/G4SDcKlp1p5h5JD04Zm/LQCnIoJMTWZoPwl5WH81Gs16wWOQPtJv7GTYuXal7M1sgvDwidXleqm1Yf8HGvjLdzkd/7YNmNibsHCDI0VC+UDjK/Kr4ALtPyhii5p0MFRKer1y+NkQNbnh64ZUz42h+Q1lI1WVSqMIbJULGlJg+/RYjdgMkmKvY82e6sf0T0n7694QMXbo15rzSmEhkF+2qmj7qHBfNjjMgCMLDZ7A4uFmf/EH9" + } + ], + "Parents": [ + { + "/": "bafy2bzaceb2oioogn5spogg5qd3s77h6y5nl65yg2ihtwsy7gz5ya5js2psfw" + }, + { + "/": "bafy2bzacecgvr4vq4owqyb2kosfohcz2tsjopa7iprikdruhqh6eacd5maopi" + }, + { + "/": "bafy2bzacecuyfvfsdbjydw6z2ymswcrnzcopetgwkz3ja6r252mrc3bidkgvy" + }, + { + "/": "bafy2bzacecpovgb6stxmpjagtyjnxbor375afxztmgr5z62b5dwlivwh4jq4q" + }, + { + "/": "bafy2bzacecplfcf3jpirxua4szvhbh3youjyec5u2ifeeha764lmsmqorl7rc" + } + ], + "ParentWeight": "5085326167", + "Height": 243590, + "ParentStateRoot": { + "/": "bafy2bzacedizpvzsmkr7lv5bl5zpp5y4fuyb5nz7dgdycbi4hbopiyiu534qe" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacebsijpga2dovhvvkctky3zncdkhlfp2673hpbnc2vz7pd6r2agbgm" + }, + "Messages": { + "/": "bafy2bzaceaute5p2f6muqyzaqarupxt3k3jb2wpzswnamnv2zkramjrkdcz26" + }, + "BLSAggregate": { + "Type": 2, + "Data": "uFZuhqr7pj08swYQiPCZDmiJnJBDsCxKmw1FSWYLgUBvkwPpwtSFaHj+W3o+hNYWEcZBf8spX5VArHaIt7B7W3CV2XUQlwzhptbX1K3mNfkCPiGMwB65owT/xh9O/cf7" + }, + "Timestamp": 1605614100, + "BlockSig": { + "Type": 2, + "Data": "kf6f9VTCnPX9rTzWDab8aF0OSGFfmVqH6xyL1zssyU7PwINIjQn58sP31E1sfSGfFmRmKGfv0GBa1XP9EfBZcyj7miTEe7fCLTIYaS3ZvtFLnHSmylJHSGp6H00fIzwv" + }, + "ForkSignaling": 0, + "ParentBaseFee": "957593361" + }, + { + "Miner": "f02490", + "Ticket": { + "VRFProof": "pUa1oaYhxCGlbJ5kRtV4gSh1q+ed39VKc6J45GGLa2G4ZpHDkB3YP3z7u95aq+YHCIa6WutJhSgTjCmgtS7R9shibMpgMAnq4V7V2pMe07gWKZ0DUAAIM/D7sM4XCTRv" + }, + "ElectionProof": { + "WinCount": 1, + "VRFProof": "k6UQkvSHV6sWXPKUB7KEQRh7m6n6cAIogKbVjBQHaR6e0ok3JA3tcVFh7jUX7ERpBsYoJonN4ctCIXT82B6iSwisa+yiX8/X2nKGVbmB1oaWB86jOZQc+lqUkefJrB/C" + }, + "BeaconEntries": [ + { + "Round": 339434, + "Data": "kxqziKg0KKpF6BO/4+ONq0PuxWNE9yAYc8163CKzKmIW+IFUdFFfkxK/UYNpvtL/FGWYOIRmOq1l5jIwJ+yXtw+65cbNUdfXO5NbRws4HY6DsiN8stpuXIuujO237yup" + } + ], + "WinPoStProof": [ + { + "PoStProof": 3, + "ProofBytes": "tCFxee4dl0/JELevW8wRY3ygztrR9Q3hlKu3Ehxi43WF1nKF2OxUFJgAyDRlr3DvgbttMAgQ9Sa9RUU6xZBIe6ZTs27GcNiVq99rqPgcYPMv1GFNfpz5lAJLvAODeBLhA04EcDbL9zmkfTN6nkMgKv6FSP1C2ghHB33A+qRXwVQ/WmiEb2g5rvC2X36Z9U+0kyR7ZO7Tr3/5R1J20Mlzt9gtDLyTwIlaa6xu4YzxRwcJi1461OpcOHoie/xhphk4" + } + ], + "Parents": [ + { + "/": "bafy2bzaceb2oioogn5spogg5qd3s77h6y5nl65yg2ihtwsy7gz5ya5js2psfw" + }, + { + "/": "bafy2bzacecgvr4vq4owqyb2kosfohcz2tsjopa7iprikdruhqh6eacd5maopi" + }, + { + "/": "bafy2bzacecuyfvfsdbjydw6z2ymswcrnzcopetgwkz3ja6r252mrc3bidkgvy" + }, + { + "/": "bafy2bzacecpovgb6stxmpjagtyjnxbor375afxztmgr5z62b5dwlivwh4jq4q" + }, + { + "/": "bafy2bzacecplfcf3jpirxua4szvhbh3youjyec5u2ifeeha764lmsmqorl7rc" + } + ], + "ParentWeight": "5085326167", + "Height": 243590, + "ParentStateRoot": { + "/": "bafy2bzacedizpvzsmkr7lv5bl5zpp5y4fuyb5nz7dgdycbi4hbopiyiu534qe" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacebsijpga2dovhvvkctky3zncdkhlfp2673hpbnc2vz7pd6r2agbgm" + }, + "Messages": { + "/": "bafy2bzaceaz4aw5fdtispsrpmvjckzzpcc675kpdqsl4l7khlsd2w6gpvc36i" + }, + "BLSAggregate": { + "Type": 2, + "Data": "rdcE8jas3aeVtdZN9GMINJTvLeugBr6nD0+dVBblkk4jznyYhJJR9hA56Vi722AqGKDdFLoE/vonGKwhP51QMgv0Gcg95vOgaVtSOZyBQ4ODfy9uXVaAOtm0koZZTH7T" + }, + "Timestamp": 1605614100, + "BlockSig": { + "Type": 2, + "Data": "rTn6iXHp97b5w2ktP/0EXc5esfePPcjDnh7DVMEVkjUZ62SHrYSfGlsWrzkdtY0IBITY0p3w1j2+xZ7dC5gJ863H0nM0bI6edPkuwnsPe6PcTZ2jVmWg8iHiCGnSXnK6" + }, + "ForkSignaling": 0, + "ParentBaseFee": "957593361" + } + ], + "Height": 243590 + } +} diff --git a/platform/filecoin/models.go b/platform/filecoin/models.go new file mode 100644 index 000000000..4a0d8a514 --- /dev/null +++ b/platform/filecoin/models.go @@ -0,0 +1,45 @@ +package filecoin + +type ChainHeadResponse struct { + Cids []struct { + Cid string `json:"/"` + } `json:"Cids"` + Blocks []struct { + Timestamp int `json:"Timestamp"` + } + Height int `json:"Height"` +} + +type BlockMessageResponse struct { + SecpkMessages []SecpkMessage `json:"SecpkMessages"` +} + +type SecpkMessage struct { + Message struct { + Version int `json:"Version"` + To string `json:"To"` + From string `json:"From"` + Nonce int `json:"Nonce"` + Value string `json:"Value"` + GasLimit int `json:"GasLimit"` + GasFeeCap string `json:"GasFeeCap"` + GasPremium string `json:"GasPremium"` + Method int `json:"Method"` + Params interface{} `json:"Params"` + } `json:"Message"` +} + +func (c ChainHeadResponse) getCids() []string { + result := make([]string, 0, len(c.Cids)) + for _, cid := range c.Cids { + result = append(result, cid.Cid) + } + return result +} + +func (c ChainHeadResponse) getTimestamp() int64 { + if len(c.Blocks) == 0 { + return 0 + } + return int64(c.Blocks[0].Timestamp) +} diff --git a/services/parser/parser.go b/services/parser/parser.go index cca31e365..1cc525678 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -223,7 +223,7 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block, ctx context.C } log.WithFields(log.Fields{"block": lastBlockNumber, "coin": params.Api.Coin().Handle}). - Info(err, "Save last parsed block") + Info("Save last parsed block") return nil } From 91e36d7ed59b763f37a6ee9d904401f6fef32750 Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Sat, 21 Nov 2020 23:34:22 +0300 Subject: [PATCH 414/506] [DB] Fix restore connection worker (#1281) * Fix restore connection worker * Update db.go --- db/db.go | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/db/db.go b/db/db.go index 5a6eba4dd..e2687efb1 100644 --- a/db/db.go +++ b/db/db.go @@ -61,20 +61,12 @@ func New(uri, readUri string, logMode bool) (*Instance, error) { func (i *Instance) RestoreConnectionWorker(ctx context.Context, timeout time.Duration, uri string) { log.Info("Run PG RestoreConnectionWorker") - t := time.NewTicker(timeout) - if err := i.restoreConnection(uri); err != nil { - log.Warn("PG is still unavailable:", err) - } - - select { - case <-ctx.Done(): - log.Info("Ctx.Done RestoreConnectionWorker exit") - return - case <-t.C: + for { if err := i.restoreConnection(uri); err != nil { - log.Warn("PG is still unavailable:", err) + log.Error("PG is not available now") } + time.Sleep(timeout) } } @@ -84,6 +76,8 @@ func (i *Instance) restoreConnection(uri string) error { return err } + log.Info("Run restoreConnection") + if err = db.Ping(); err != nil { log.Warn("PG is not available now") log.Warn("Trying to connect to PG...") From e7a984d2262651d195e60ab6195f32a6fc75f5ff Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Mon, 23 Nov 2020 17:10:51 -0800 Subject: [PATCH 415/506] Use TokenType from golibs (#1282) * Use TokenType from golibs * Remove TokenType --- go.mod | 2 +- go.sum | 4 +- pkg/blockatlas/tx.go | 65 +++++------------------- pkg/blockatlas/tx_test.go | 51 +++---------------- platform/binance/model.go | 3 +- platform/ethereum/blockbook/model.go | 15 +++--- platform/ethereum/blockbook/token.go | 3 +- platform/ethereum/trustray/token.go | 3 +- platform/ethereum/trustray/token_test.go | 17 ++++--- platform/tron/token.go | 5 +- platform/tron/transaction.go | 11 ++-- platform/tron/transaction_test.go | 7 +-- 12 files changed, 56 insertions(+), 130 deletions(-) diff --git a/go.mod b/go.mod index c5073f559..4a0142d0f 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 - github.com/trustwallet/golibs v0.0.13 + github.com/trustwallet/golibs v0.0.15 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmhttp v1.8.0 diff --git a/go.sum b/go.sum index 38876f0f7..7f2ef139c 100644 --- a/go.sum +++ b/go.sum @@ -461,8 +461,8 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.13 h1:25XKd76pQr4i6UNoyJYGtrogpN9/YzNNwYzXoxh3h68= -github.com/trustwallet/golibs v0.0.13/go.mod h1:j+Tip4aaW3mu+81S1a+UJ8fSnKzLeJyBueApnCXXRMg= +github.com/trustwallet/golibs v0.0.15 h1:f85eXy/WsmoTSI3cYim4qpTxucW0KYHC4RDgkr1vvJo= +github.com/trustwallet/golibs v0.0.15/go.mod h1:j+Tip4aaW3mu+81S1a+UJ8fSnKzLeJyBueApnCXXRMg= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 3c909bceb..40a8c4960 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -1,6 +1,7 @@ package blockatlas import ( + "github.com/trustwallet/golibs/tokentype" "sort" "strconv" "strings" @@ -21,20 +22,6 @@ const ( DirectionIncoming Direction = "incoming" DirectionSelf Direction = "yourself" - TokenTypeERC20 TokenType = "ERC20" - TokenTypeBEP2 TokenType = "BEP2" - TokenTypeBEP8 TokenType = "BEP8" - TokenTypeBEP20 TokenType = "BEP20" - TokenTypeTRC10 TokenType = "TRC10" - TokenTypeETC20 TokenType = "ETC20" - TokenTypePOA20 TokenType = "POA20" - TokenTypeTRC20 TokenType = "TRC20" - TokenTypeTRC21 TokenType = "TRC21" - TokenTypeCLO20 TokenType = "CLO20" - TokenTypeGO20 TokenType = "G020" - TokenTypeWAN20 TokenType = "WAN20" - TokenTypeTT20 TokenType = "TT20" - TxTransfer TransactionType = "transfer" TxNativeTokenTransfer TransactionType = "native_token_transfer" TxTokenTransfer TransactionType = "token_transfer" @@ -67,7 +54,6 @@ type ( // Types of transaction statuses Direction string Status string - TokenType string TransactionType string KeyType string KeyTitle string @@ -206,12 +192,12 @@ type ( // Token describes the non-native tokens. // Examples: ERC-20, TRC-20, BEP-2 Token struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - Decimals uint `json:"decimals"` - TokenID string `json:"token_id"` - Coin uint `json:"coin"` - Type TokenType `json:"type"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals uint `json:"decimals"` + TokenID string `json:"token_id"` + Coin uint `json:"coin"` + Type tokentype.Type `json:"type"` } Txs []Tx @@ -435,33 +421,6 @@ func InferValue(tx *Tx, direction Direction, addressSet mapset.Set) Amount { return value } -func GetEthereumTokenTypeByIndex(coinIndex uint) TokenType { - var tokenType TokenType - switch coinIndex { - case coin.Ethereum().ID: - tokenType = TokenTypeERC20 - case coin.Classic().ID: - tokenType = TokenTypeETC20 - case coin.Poa().ID: - tokenType = TokenTypePOA20 - case coin.Callisto().ID: - tokenType = TokenTypeCLO20 - case coin.Wanchain().ID: - tokenType = TokenTypeWAN20 - case coin.Thundertoken().ID: - tokenType = TokenTypeTT20 - case coin.Gochain().ID: - tokenType = TokenTypeGO20 - case coin.Tomochain().ID: - tokenType = TokenTypeTRC21 - case coin.Bsc().ID, coin.Smartchain().ID: - tokenType = TokenTypeBEP20 - default: - tokenType = TokenTypeERC20 - } - return tokenType -} - func (t Tx) AssetModel() (models.Asset, bool) { var a models.Asset switch t.Meta.(type) { @@ -538,17 +497,17 @@ func (t Tx) AssetModel() (models.Asset, bool) { func GetTokenType(c uint, tokenID string) (string, bool) { switch c { case coin.Ethereum().ID: - return string(TokenTypeERC20), true + return string(tokentype.ERC20), true case coin.Tron().ID: _, err := strconv.Atoi(tokenID) if err != nil { - return string(TokenTypeTRC20), true + return string(tokentype.TRC20), true } - return string(TokenTypeTRC10), true + return string(tokentype.TRC10), true case coin.Smartchain().ID: - return string(TokenTypeBEP20), true + return string(tokentype.BEP20), true case coin.Binance().ID: - return string(TokenTypeBEP2), true + return string(tokentype.BEP2), true default: return "", false } diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 842542adc..4fd724425 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -5,6 +5,7 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/tokentype" "reflect" "sort" "testing" @@ -568,46 +569,6 @@ func TestTx_TokenID(t *testing.T) { } -func TestGetEthereumTokenTypeByIndex(t *testing.T) { - type args struct { - coinIndex uint - } - tests := []struct { - name string - args args - want TokenType - }{ - { - "Ethereum", - args{ - coinIndex: coin.Ethereum().ID, - }, - TokenTypeERC20, - }, - { - "Smart Chain", - args{ - coinIndex: coin.Smartchain().ID, - }, - TokenTypeBEP20, - }, - { - "Default Name", - args{ - coinIndex: coin.Bitcoin().ID, - }, - TokenTypeERC20, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := GetEthereumTokenTypeByIndex(tt.args.coinIndex); got != tt.want { - t.Errorf("GetEthereumTokenTypeByIndex() = %v, want %v", got, tt.want) - } - }) - } -} - func TestTokenType(t *testing.T) { type testStruct struct { Name string @@ -621,35 +582,35 @@ func TestTokenType(t *testing.T) { Name: "Tron TRC20", ID: coin.Tron().ID, TokenID: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", - WantedType: string(TokenTypeTRC20), + WantedType: string(tokentype.TRC20), WantedOk: true, }, { Name: "Tron TRC10", ID: coin.Tron().ID, TokenID: "1002000", - WantedType: string(TokenTypeTRC10), + WantedType: string(tokentype.TRC10), WantedOk: true, }, { Name: "Ethereum ERC20", ID: coin.Ethereum().ID, TokenID: "dai", - WantedType: string(TokenTypeERC20), + WantedType: string(tokentype.ERC20), WantedOk: true, }, { Name: "Binance BEP20", ID: coin.Smartchain().ID, TokenID: "busd", - WantedType: string(TokenTypeBEP20), + WantedType: string(tokentype.BEP20), WantedOk: true, }, { Name: "Binance BEP10", ID: coin.Binance().ID, TokenID: "busd", - WantedType: string(TokenTypeBEP2), + WantedType: string(tokentype.BEP2), WantedOk: true, }, { diff --git a/platform/binance/model.go b/platform/binance/model.go index c928f805f..f8c3026bf 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -1,6 +1,7 @@ package binance import ( + "github.com/trustwallet/golibs/tokentype" "strconv" "strings" "time" @@ -274,7 +275,7 @@ func normalizeToken(srcToken TokenBalance, tokens Tokens) (blockatlas.Token, boo TokenID: token.Symbol, Coin: coin.Binance().ID, Decimals: coin.Binance().Decimals, - Type: blockatlas.TokenTypeBEP2, + Type: tokentype.BEP2, } return result, true diff --git a/platform/ethereum/blockbook/model.go b/platform/ethereum/blockbook/model.go index 415b5294e..f7645ee45 100644 --- a/platform/ethereum/blockbook/model.go +++ b/platform/ethereum/blockbook/model.go @@ -1,9 +1,8 @@ package blockbook import ( + "github.com/trustwallet/golibs/tokentype" "math/big" - - "github.com/trustwallet/blockatlas/pkg/blockatlas" ) type Page struct { @@ -58,12 +57,12 @@ type TokenTransfer struct { // Token contains info about tokens held by an address type Token struct { - Balance string `json:"balance,omitempty"` - Contract string `json:"contract"` - Decimals uint `json:"decimals"` - Name string `json:"name"` - Symbol string `json:"symbol"` - Type blockatlas.TokenType `json:"type"` + Balance string `json:"balance,omitempty"` + Contract string `json:"contract"` + Decimals uint `json:"decimals"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Type tokentype.Type `json:"type"` } // EthereumSpecific contains ethereum specific transaction data diff --git a/platform/ethereum/blockbook/token.go b/platform/ethereum/blockbook/token.go index a99ff339f..5f72ce196 100644 --- a/platform/ethereum/blockbook/token.go +++ b/platform/ethereum/blockbook/token.go @@ -2,6 +2,7 @@ package blockbook import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/tokentype" ) func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) { @@ -31,6 +32,6 @@ func NormalizeToken(srcToken *Token, coinIndex uint) blockatlas.Token { TokenID: srcToken.Contract, Coin: coinIndex, Decimals: srcToken.Decimals, - Type: blockatlas.GetEthereumTokenTypeByIndex(coinIndex), + Type: tokentype.GetEthereumTokenTypeByIndex(coinIndex), } } diff --git a/platform/ethereum/trustray/token.go b/platform/ethereum/trustray/token.go index 8ce8d4165..bcd382abb 100644 --- a/platform/ethereum/trustray/token.go +++ b/platform/ethereum/trustray/token.go @@ -2,6 +2,7 @@ package trustray import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/tokentype" ) func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) { @@ -14,7 +15,7 @@ func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenP // NormalizeToken converts a Ethereum token into the generic model func NormalizeToken(srcToken *Contract, coinIndex uint) blockatlas.Token { - tokenType := blockatlas.GetEthereumTokenTypeByIndex(coinIndex) + tokenType := tokentype.GetEthereumTokenTypeByIndex(coinIndex) return blockatlas.Token{ Name: srcToken.Name, diff --git a/platform/ethereum/trustray/token_test.go b/platform/ethereum/trustray/token_test.go index ba5db892c..6bdff93a3 100644 --- a/platform/ethereum/trustray/token_test.go +++ b/platform/ethereum/trustray/token_test.go @@ -3,6 +3,7 @@ package trustray import ( "bytes" "encoding/json" + "github.com/trustwallet/golibs/tokentype" "testing" "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -40,7 +41,7 @@ func TestNormalizeToken(t *testing.T) { Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.ETH, - Type: blockatlas.TokenTypeERC20, + Type: tokentype.ERC20, }, }, {"classic etc20", @@ -52,7 +53,7 @@ func TestNormalizeToken(t *testing.T) { Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.ETC, - Type: blockatlas.TokenTypeETC20, + Type: tokentype.ETC20, }, }, {"gochain go20", @@ -64,7 +65,7 @@ func TestNormalizeToken(t *testing.T) { Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.GO, - Type: blockatlas.TokenTypeGO20, + Type: tokentype.GO20, }, }, {"thudertoken tt20", @@ -76,7 +77,7 @@ func TestNormalizeToken(t *testing.T) { Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.TT, - Type: blockatlas.TokenTypeTT20, + Type: tokentype.TT20, }, }, {"wanchain wan20", @@ -88,7 +89,7 @@ func TestNormalizeToken(t *testing.T) { Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.WAN, - Type: blockatlas.TokenTypeWAN20, + Type: tokentype.WAN20, }, }, {"poa poa20", @@ -100,7 +101,7 @@ func TestNormalizeToken(t *testing.T) { Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.POA, - Type: blockatlas.TokenTypePOA20, + Type: tokentype.POA20, }, }, {"callisto clo20", @@ -112,7 +113,7 @@ func TestNormalizeToken(t *testing.T) { Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.CLO, - Type: blockatlas.TokenTypeCLO20, + Type: tokentype.CLO20, }, }, {"unknown", @@ -124,7 +125,7 @@ func TestNormalizeToken(t *testing.T) { Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: 1999, - Type: blockatlas.TokenTypeERC20, + Type: tokentype.ERC20, }, }, } diff --git a/platform/tron/token.go b/platform/tron/token.go index 1bd9322dc..31d9c5133 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -4,6 +4,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/tokentype" "strings" "sync" "time" @@ -41,7 +42,7 @@ func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, Decimals: uint(t.Decimals), TokenID: t.ContractAddress, Coin: coin.Tron().ID, - Type: blockatlas.TokenTypeTRC20, + Type: tokentype.TRC20, }) } @@ -84,6 +85,6 @@ func NormalizeToken(info AssetInfo) blockatlas.Token { TokenID: info.ID, Coin: coin.TRX, Decimals: info.Decimals, - Type: blockatlas.TokenTypeTRC10, + Type: tokentype.TRC10, } } diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index 2509f9f6f..2f7847311 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -6,6 +6,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/tokentype" "strconv" "strings" ) @@ -38,13 +39,13 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPag tokenType := getTokenType(token) switch tokenType { - case blockatlas.TokenTypeTRC10: + case tokentype.TRC10: txs, err := p.fetchTransactionsForTRC10Tokens(address, token) if err != nil { return nil, err } return txs, nil - case blockatlas.TokenTypeTRC20: + case tokentype.TRC20: trc20Transactions, err := p.client.fetchTRC20Transactions(address) if err != nil { return nil, err @@ -55,12 +56,12 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPag } } -func getTokenType(token string) blockatlas.TokenType { +func getTokenType(token string) tokentype.Type { _, err := strconv.Atoi(token) if err != nil { - return blockatlas.TokenTypeTRC20 + return tokentype.TRC20 } else { - return blockatlas.TokenTypeTRC10 + return tokentype.TRC10 } } diff --git a/platform/tron/transaction_test.go b/platform/tron/transaction_test.go index 52ad1bd11..843df2abd 100644 --- a/platform/tron/transaction_test.go +++ b/platform/tron/transaction_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/tokentype" "net/http/httptest" "testing" ) @@ -165,10 +166,10 @@ func Test_getTokenType(t *testing.T) { tests := []struct { name string token string - want blockatlas.TokenType + want tokentype.Type }{ - {"default trc20", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", blockatlas.TokenTypeTRC20}, - {"default trc10", "1002001", blockatlas.TokenTypeTRC10}, + {"default trc20", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", tokentype.TRC20}, + {"default trc10", "1002001", tokentype.TRC10}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 94f7e1795c9e918255c369c2e96bbf0200a08837 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 26 Nov 2020 01:43:48 -0800 Subject: [PATCH 416/506] Add Heroku support (#1275) * Add worker/consumer to Procfile * Update Procfile * Decreaser observer parsing values * Remove unnessesary logs * Update parser.go * Add coin handle to logger * Adjust logs * Upgrade gorm and postgres * Add test with RunSyncConsumerWithCancelAndDbConnConcurrent * Revert "Add test with RunSyncConsumerWithCancelAndDbConnConcurrent" This reverts commit b96b9ac47c1ca8fada5f2aa8baac5c6d6bb5ea5c. * Split transactions and token queues and add comments * Filtering out token transfers * Remove spamfilter * Use RunConsumerWithCancelAndDbConn * Revert "Use RunConsumerWithCancelAndDbConn" This reverts commit 50aecd9f565f44ff26ef3108050db7704b5f6fb3. * Add logging * Update mq.go * Update main.go * Update main.go * Revert "Update main.go" This reverts commit d9daa457e8f50d336e6e3e7081042cebf5952d4f. * Add binance rpc api key support * Update golibs * Improve ConvertToBatch * Add queues initializer * Add coin to log * Update tx_test.go * Remove unused values * Update parser.go * Fix tests * Update parser.go * Update observer_test.go --- Procfile | 4 +- cmd/api/main.go | 5 +- cmd/consumer/main.go | 49 ++++----- cmd/parser/main.go | 14 +-- config.yml | 6 +- config/configuration.go | 10 +- configmock.yml | 2 - go.mod | 4 +- go.sum | 24 +++-- mq/mq.go | 21 ++-- pkg/blockatlas/tx.go | 24 +++-- pkg/blockatlas/tx_test.go | 43 +++++++- platform/binance/base.go | 4 +- platform/binance/block_test.go | 7 +- platform/binance/client.go | 33 ++++--- platform/binance/token_test.go | 5 +- platform/binance/transaction_test.go | 7 +- platform/platform.go | 2 +- services/notifier/delivery.go | 12 ++- services/parser/parser.go | 99 +++++++++---------- services/parser/parser_test.go | 83 ++++++++-------- services/spamfilter/spamfilter.go | 30 ------ services/spamfilter/spamfilter_test.go | 13 --- .../integration/db_test/tokenindexer_test.go | 4 - .../observer_test/full_flow_test.go | 2 +- .../observer_test/observer_test.go | 7 +- .../integration/observer_test/parser_test.go | 2 +- 27 files changed, 272 insertions(+), 244 deletions(-) delete mode 100644 services/spamfilter/spamfilter.go delete mode 100644 services/spamfilter/spamfilter_test.go diff --git a/Procfile b/Procfile index 891cdb3a5..8f691ac2f 100644 --- a/Procfile +++ b/Procfile @@ -1 +1,3 @@ -web: ATLAS_POSTGRES_READ_URL=$ATLAS_POSTGRES_URL bin/api -c $HOME/config.yml -p $PORT +web: bin/api -c $HOME/config.yml -p $PORT +consumer: bin/consumer -c $HOME/config.yml +parser: bin/parser -c $HOME/config.yml diff --git a/cmd/api/main.go b/cmd/api/main.go index 58ba1da8f..a513bc2ff 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -2,6 +2,8 @@ package main import ( "context" + "time" + "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/api" @@ -11,10 +13,8 @@ import ( "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/platform" - "github.com/trustwallet/blockatlas/services/spamfilter" "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" - "time" ) const ( @@ -40,7 +40,6 @@ func init() { engine = internal.InitEngine(config.Default.Gin.Mode) platform.Init(config.Default.Platform) - spamfilter.SpamList = config.Default.SpamWords var err error database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index 00415ddc0..e965728c3 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -2,12 +2,14 @@ package main import ( "context" - "github.com/trustwallet/blockatlas/config" + "time" + "github.com/trustwallet/blockatlas/services/notifier" + + "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/services/subscriber" "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" - "time" log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db" @@ -40,7 +42,7 @@ func init() { database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, config.Default.Postgres.Log) if err != nil { - log.Fatal(err) + log.Fatal("Postgres init: ", err) } go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) @@ -50,30 +52,29 @@ func init() { func main() { defer mq.Close() - if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { - log.Fatal(err) - } - if err := mq.RawTransactions.Declare(); err != nil { - log.Fatal(err) + queues := []mq.Queue{ + mq.TxNotifications, + mq.RawTransactionsTokenIndexer, + mq.RawTransactions, + mq.RawTransactionsSearcher, + mq.Subscriptions, + mq.TokensRegistration, } - if err := mq.TxNotifications.Declare(); err != nil { - log.Fatal(err) - } - if err := mq.RawTransactionsSearcher.Declare(); err != nil { - log.Fatal(err) - } - if err := mq.Subscriptions.Declare(); err != nil { - log.Fatal(err) - } - if err := mq.TokensRegistration.Declare(); err != nil { - log.Fatal(err) + + for _, queue := range queues { + err := queue.Declare() + if err != nil { + log.Fatal("Declare ", queue, err) + } } - go mq.RawTransactionsTokenIndexer.RunConsumerWithCancelAndDbConnConcurrent(tokenindexer.RunTokenIndexer, database, ctx) - go mq.RawTransactions.RunConsumerWithCancelAndDbConnConcurrent(notifier.RunNotifier, database, ctx) - go mq.RawTransactionsSearcher.RunConsumerWithCancelAndDbConnConcurrent(tokensearcher.Run, database, ctx) - go mq.Subscriptions.RunConsumerWithCancelAndDbConnConcurrent(subscriber.RunTransactionsSubscriber, database, ctx) - go mq.TokensRegistration.RunConsumerWithCancelAndDbConnConcurrent(subscriber.RunTokensSubscriber, database, ctx) + go mq.RawTransactions.RunConsumerWithCancelAndDbConn(notifier.RunNotifier, database, ctx) + + go mq.RawTransactionsTokenIndexer.RunConsumerWithCancelAndDbConn(tokenindexer.RunTokenIndexer, database, ctx) + go mq.RawTransactionsSearcher.RunConsumerWithCancelAndDbConn(tokensearcher.Run, database, ctx) + + go mq.Subscriptions.RunConsumerWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, database, ctx) + go mq.TokensRegistration.RunConsumerWithCancelAndDbConn(subscriber.RunTokensSubscriber, database, ctx) go mq.FatalWorker(time.Second * 10) diff --git a/cmd/parser/main.go b/cmd/parser/main.go index 7281a7c9c..216642bad 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -3,14 +3,14 @@ package main import ( "context" "fmt" - "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/services/spamfilter" "os" "os/signal" "sync" "syscall" "time" + "github.com/trustwallet/blockatlas/config" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" @@ -41,7 +41,6 @@ func init() { ) platform.Init(config.Default.Platform) - spamfilter.SpamList = config.Default.SpamWords if err := mq.RawTransactions.Declare(); err != nil { log.Fatal(err) @@ -104,10 +103,10 @@ func main() { coinCancel[coin.Handle] = cancel params := parser.Params{ - Ctx: ctx, - Api: api, - Queue: []mq.Queue{ - mq.RawTransactions, + Ctx: ctx, + Api: api, + TransactionsQueue: mq.RawTransactions, + TokenTransactionsQueue: []mq.Queue{ mq.RawTransactionsSearcher, mq.RawTransactionsTokenIndexer, }, @@ -123,6 +122,7 @@ func main() { go parser.RunParser(params) log.WithFields(log.Fields{ + "coin": api.Coin().Handle, "interval": pollInterval, "backlog": backlogCount, "Max backlog": maxBackLogBlocks, diff --git a/config.yml b/config.yml index e9e91b9a5..9a6736647 100644 --- a/config.yml +++ b/config.yml @@ -8,8 +8,6 @@ gin: # You can see all the coin handles at coins/coins.yml file platform: [ all ] -spam_words: [ "airdrop","www", "http" ] - # The transaction watcher observer: # Don't request blocks older than this @@ -40,7 +38,7 @@ postgres: # [BNB] Binance DEX: https://www.binance.org/ binance: api: https://dex.binance.org - explorer: https://explorer.binance.org + # key: "" # [NIM] Nimiq: https://nimiq.com nimiq: @@ -207,7 +205,7 @@ harmony: api: https://api.s0.t.hmny.io kava: - api: https://data.kava.io + api: https://kava.data.kava.io kusama: api: https://kusama.subscan.io/api diff --git a/config/configuration.go b/config/configuration.go index 40fb1d2d4..36efd8e01 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -1,11 +1,12 @@ package config import ( - log "github.com/sirupsen/logrus" - "github.com/spf13/viper" "reflect" "strings" "time" + + log "github.com/sirupsen/logrus" + "github.com/spf13/viper" ) type Configuration struct { @@ -15,7 +16,6 @@ type Configuration struct { } `mapstructure:"gin"` Platform []string `mapstructure:"platform"` RestAPI string `mapstructure:"rest_api"` - SpamWords []string `mapstructure:"spam_words"` Subscriber string `mapstructure:"subscriber"` Observer struct { Backlog time.Duration `mapstructure:"backlog"` @@ -49,8 +49,8 @@ type Configuration struct { RPC string `mapstructure:"rpc"` } `mapstructure:"ethereum"` Binance struct { - API string `mapstructure:"api"` - Explorer string `mapstructure:"explorer"` + API string `mapstructure:"api"` + Key string `mapstructure:"key"` } `mapstructure:"binance"` Ripple struct { API string `mapstructure:"api"` diff --git a/configmock.yml b/configmock.yml index 47e22bca3..cbddd7376 100644 --- a/configmock.yml +++ b/configmock.yml @@ -7,8 +7,6 @@ gin: # You can see all the coin handles at coins/coins.yml file platform: all -spam_words: [ "airdrop","www", "http" ] - # The transaction watcher observer: backlog: 3h diff --git a/go.mod b/go.mod index 4a0142d0f..61593b6c5 100644 --- a/go.mod +++ b/go.mod @@ -46,8 +46,8 @@ require ( golang.org/x/net v0.0.0-20200506145744-7e3656a0809f // indirect golang.org/x/tools v0.0.0-20200513175351-0951661448da // indirect gopkg.in/yaml.v2 v2.3.0 - gorm.io/driver/postgres v1.0.0 - gorm.io/gorm v1.20.0 + gorm.io/driver/postgres v1.0.5 + gorm.io/gorm v1.20.6 gorm.io/plugin/dbresolver v1.0.0 gotest.tools v2.2.0+incompatible // indirect howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 // indirect diff --git a/go.sum b/go.sum index 7f2ef139c..fc68381ee 100644 --- a/go.sum +++ b/go.sum @@ -229,8 +229,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.6.4 h1:S7T6cx5o2OqmxdHaXLH1ZeD1SbI8jBznyYE9Ec0RCQ8= -github.com/jackc/pgconn v1.6.4/go.mod h1:w2pne1C2tZgP+TvjqLpOigGzNqjBgQW9dUw/4Chex78= +github.com/jackc/pgconn v1.7.0 h1:pwjzcYyfmz/HQOQlENvG1OcDqauTGaqlVahq934F0/U= +github.com/jackc/pgconn v1.7.0/go.mod h1:sF/lPpNEMEOp+IYhyQGdAvrG20gWf6A1tKlr0v7JMeA= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA= @@ -244,8 +244,8 @@ github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.0.2 h1:q1Hsy66zh4vuNsajBUF2PNqfAMMfxU5mk594lPE9vjY= -github.com/jackc/pgproto3/v2 v2.0.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.5 h1:NUbEWPmCQZbMmYlTjVoNPhc0CfnYyz2bfUAh6A5ZVJM= +github.com/jackc/pgproto3/v2 v2.0.5/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= @@ -255,20 +255,21 @@ github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrU github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= -github.com/jackc/pgtype v1.4.2 h1:t+6LWm5eWPLX1H5Se702JSBcirq6uWa4jiG4wV1rAWY= -github.com/jackc/pgtype v1.4.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= +github.com/jackc/pgtype v1.5.0 h1:jzBqRk2HFG2CV4AIwgCI2PwTgm6UUoCAK2ofHHRirtc= +github.com/jackc/pgtype v1.5.0/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= -github.com/jackc/pgx/v4 v4.8.1 h1:SUbCLP2pXvf/Sr/25KsuI4aTxiFYIvpfk4l6aTSdyCw= -github.com/jackc/pgx/v4 v4.8.1/go.mod h1:4HOLxrl8wToZJReD04/yB20GDwf4KBYETvlHciCnwW0= +github.com/jackc/pgx/v4 v4.9.0 h1:6STjDqppM2ROy5p1wNDcsC7zJTjSHeuCsguZmXyzx7c= +github.com/jackc/pgx/v4 v4.9.0/go.mod h1:MNGWmViCgqbZck9ujOOBN63gK9XVGILXWCvKLGKmnms= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -704,11 +705,14 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.0.1 h1:omJoilUzyrAp0xNoio88lGJCroGdIOen9hq2A/+3ifw= gorm.io/driver/mysql v1.0.1/go.mod h1:KtqSthtg55lFp3S5kUXqlGaelnWpKitn4k1xZTnoiPw= -gorm.io/driver/postgres v1.0.0 h1:Yh4jyFQ0a7F+JPU0Gtiam/eKmpT/XFc1FKxotGqc6FM= -gorm.io/driver/postgres v1.0.0/go.mod h1:wtMFcOzmuA5QigNsgEIb7O5lhvH1tHAF1RbWmLWV4to= +gorm.io/driver/postgres v1.0.5 h1:raX6ezL/ciUmaYTvOq48jq1GE95aMC0CmxQYbxQ4Ufw= +gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOudXNCA= gorm.io/gorm v1.9.19/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.0 h1:qfIlyaZvrF7kMWY3jBdEBXkXJ2M5MFYMTppjILxS3fQ= gorm.io/gorm v1.20.0/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.20.6 h1:qa7tC1WcU+DBI/ZKMxvXy1FcrlGsvxlaKufHrT2qQ08= +gorm.io/gorm v1.20.6/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/plugin/dbresolver v1.0.0 h1:fHIWRRkoDmXkBPYyg9GMmLugcM9fcbZiG0Zy/cwiPlM= gorm.io/plugin/dbresolver v1.0.0/go.mod h1:sK1Alv120lfrjRQXrzyAw4ssxDPJjamm2cbBOZBHM68= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= diff --git a/mq/mq.go b/mq/mq.go index a3de94b77..cb20e90b7 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -2,10 +2,11 @@ package mq import ( "context" + "time" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" - "time" ) var ( @@ -22,12 +23,18 @@ type ( ) const ( - TxNotifications Queue = "txNotifications" - Subscriptions Queue = "subscriptions" - RawTransactions Queue = "rawTransactions" - RawTransactionsSearcher Queue = "rawTransactionsSearcher" + // End consumer of published transactions. Not consumed on blockatlas + TxNotifications Queue = "txNotifications" + // Address:coin subscriptions + Subscriptions Queue = "subscriptions" + // Transactions to process, if match subscriptions, pushed to TxNotifications + RawTransactions Queue = "rawTransactions" + // Token indexer for finding asset association with an address + RawTransactionsSearcher Queue = "rawTransactionsSearcher" + // Token indexer for finding new assets RawTransactionsTokenIndexer Queue = "rawTransactionsTokenIndexer" - TokensRegistration Queue = "tokensRegistration" + // Register new addresses to observers for token transfers + TokensRegistration Queue = "tokensRegistration" ) func Init(uri string) (err error) { @@ -99,7 +106,7 @@ func (q Queue) GetMessageChannel() MessageChannel { nil, ) if err != nil { - log.Fatal("MQ issue " + err.Error()) + log.Fatal("GetMessageChannel MQ issue "+err.Error(), string(q)) } err = amqpChan.Qos( diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 40a8c4960..9fdbcde95 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -203,10 +203,10 @@ type ( Txs []Tx ) -func (t Txs) FilterUniqueID() Txs { +func (txs Txs) FilterUniqueID() Txs { keys := make(map[string]bool) list := make(Txs, 0) - for _, entry := range t { + for _, entry := range txs { if _, value := keys[entry.ID]; !value { keys[entry.ID] = true list = append(list, entry) @@ -226,6 +226,18 @@ func (txs TxPage) FilterTransactionsByMemo() TxPage { return result } +func (txs Txs) FilterTransactionsByType(types []TransactionType) Txs { + result := make(Txs, 0) + for _, tx := range txs { + for _, t := range types { + if tx.Type == t { + result = append(result, tx) + } + } + } + return result +} + func AllowMemo(memo string) bool { // only allows numeric values _, err := strconv.ParseFloat(memo, 64) @@ -267,11 +279,11 @@ func (txs TxPage) FilterTransactionsByToken(token string) TxPage { return result } -func (t Txs) SortByDate() Txs { - sort.Slice(t, func(i, j int) bool { - return t[i].Date > t[j].Date +func (txs Txs) SortByDate() Txs { + sort.Slice(txs, func(i, j int) bool { + return txs[i].Date > txs[j].Date }) - return t + return txs } func (t *Tx) GetUtxoAddresses() (addresses []string) { diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index 4fd724425..cc40e507d 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -2,13 +2,14 @@ package blockatlas import ( "encoding/json" + "reflect" + "sort" + "testing" + mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/tokentype" - "reflect" - "sort" - "testing" ) var transferDst1 = Tx{ @@ -721,3 +722,39 @@ func TestTxPage_FilterTransactionsByMemo(t *testing.T) { }) } } + +func TestTxs_FilterTransactionsByType(t *testing.T) { + type args struct { + types []TransactionType + } + tests := []struct { + name string + txs Txs + args args + want Txs + }{ + { + "Token Transfers", + Txs{ + Tx{Type: TxTransfer}, + Tx{Type: TxContractCall}, + Tx{Type: TxNativeTokenTransfer}, + Tx{Type: TxTokenTransfer}, + }, + args{ + []TransactionType{TxNativeTokenTransfer, TxTokenTransfer}, + }, + Txs{ + Tx{Type: TxNativeTokenTransfer}, + Tx{Type: TxTokenTransfer}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.txs.FilterTransactionsByType(tt.args.types); !reflect.DeepEqual(got, tt.want) { + t.Errorf("FilterTransactionsByType() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/platform/binance/base.go b/platform/binance/base.go index e39ec58cc..f49c59b88 100644 --- a/platform/binance/base.go +++ b/platform/binance/base.go @@ -8,9 +8,9 @@ type Platform struct { client Client } -func Init(api string) *Platform { +func Init(api, apiKey string) *Platform { p := Platform{ - client: InitClient(api), + client: InitClient(api, apiKey), } return &p } diff --git a/platform/binance/block_test.go b/platform/binance/block_test.go index 5fcc19bfa..5a496ced9 100644 --- a/platform/binance/block_test.go +++ b/platform/binance/block_test.go @@ -2,15 +2,16 @@ package binance import ( "encoding/json" - "github.com/stretchr/testify/assert" "net/http/httptest" "testing" + + "github.com/stretchr/testify/assert" ) func TestPlatform_CurrentBlockNumber(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL) + p := Init(server.URL, "") number, err := p.CurrentBlockNumber() assert.Nil(t, err) assert.Equal(t, int64(104867535), number) @@ -19,7 +20,7 @@ func TestPlatform_CurrentBlockNumber(t *testing.T) { func TestPlatform_GetBlockByNumber(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL) + p := Init(server.URL, "") block, err := p.GetBlockByNumber(104867508) assert.Nil(t, err) res, err := json.Marshal(block) diff --git a/platform/binance/client.go b/platform/binance/client.go index f4f09e2c9..eae60f674 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -2,26 +2,37 @@ package binance import ( "fmt" + "net/http" + "net/url" + "strconv" + "time" + "github.com/imroc/req" "github.com/patrickmn/go-cache" log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "net/url" - "strconv" - "time" ) type Client struct { *cache.Cache - url string + url string + apiKey string } -func InitClient(url string) Client { - return Client{url: url, Cache: cache.New(5*time.Minute, 10*time.Minute)} +func InitClient(url, apiKey string) Client { + return Client{url: url, apiKey: apiKey, Cache: cache.New(5*time.Minute, 10*time.Minute)} +} + +func (c Client) Get(path string, params interface{}) (*req.Resp, error) { + header := make(http.Header) + if c.apiKey != "" { + header.Set("apikey", c.apiKey) + } + return req.Get(c.url+path, header, params) } func (c Client) FetchLatestBlockNumber() (int64, error) { - resp, err := req.Get(c.url+"/api/v1/node-info", nil) + resp, err := c.Get("/api/v1/node-info", nil) if err != nil { return 0, err } @@ -35,7 +46,7 @@ func (c Client) FetchLatestBlockNumber() (int64, error) { } func (c Client) FetchTransactionsInBlock(blockNumber int64) (TransactionsInBlockResponse, error) { - resp, err := req.Get(c.url+fmt.Sprintf("/api/v2/transactions-in-block/%d", blockNumber), nil) + resp, err := c.Get(fmt.Sprintf("/api/v2/transactions-in-block/%d", blockNumber), nil) if err != nil { return TransactionsInBlockResponse{}, err } @@ -52,7 +63,7 @@ func (c Client) FetchTransactionsByAddressAndTokenID(address, tokenID string) ([ startTime := strconv.Itoa(int(time.Now().AddDate(0, -3, 0).Unix() * 1000)) limit := strconv.Itoa(blockatlas.TxPerPage) params := url.Values{"address": {address}, "txAsset": {tokenID}, "startTime": {startTime}, "limit": {limit}} - resp, err := req.Get(c.url+"/api/v1/transactions", params) + resp, err := c.Get("/api/v1/transactions", params) if err != nil { return nil, err } @@ -66,7 +77,7 @@ func (c Client) FetchTransactionsByAddressAndTokenID(address, tokenID string) ([ } func (c Client) FetchAccountMeta(address string) (AccountMeta, error) { - resp, err := req.Get(c.url+fmt.Sprintf("/api/v1/account/%s", address), nil) + resp, err := c.Get(fmt.Sprintf("/api/v1/account/%s", address), nil) if err != nil { return AccountMeta{}, err } @@ -86,7 +97,7 @@ func (c Client) FetchTokens() (Tokens, error) { } result := new(Tokens) query := url.Values{"limit": {tokensLimit}} - resp, err := req.Get(c.url+"/api/v1/tokens", query) + resp, err := c.Get("/api/v1/tokens", query) if err != nil { return nil, err } diff --git a/platform/binance/token_test.go b/platform/binance/token_test.go index e01c2068d..7950dbf6c 100644 --- a/platform/binance/token_test.go +++ b/platform/binance/token_test.go @@ -2,15 +2,16 @@ package binance import ( "encoding/json" - "github.com/stretchr/testify/assert" "net/http/httptest" "testing" + + "github.com/stretchr/testify/assert" ) func TestPlatform_GetTokenListByAddress(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL) + p := Init(server.URL, "") tokens, err := p.GetTokenListByAddress("bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg") assert.Nil(t, err) diff --git a/platform/binance/transaction_test.go b/platform/binance/transaction_test.go index f3b9af8da..3bafcfbb6 100644 --- a/platform/binance/transaction_test.go +++ b/platform/binance/transaction_test.go @@ -2,15 +2,16 @@ package binance import ( "encoding/json" - "github.com/stretchr/testify/assert" "net/http/httptest" "testing" + + "github.com/stretchr/testify/assert" ) func TestPlatform_GetTxsByAddress(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL) + p := Init(server.URL, "") txs, err := p.GetTxsByAddress("bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23") assert.Nil(t, err) res, err := json.Marshal(txs) @@ -21,7 +22,7 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { func TestPlatform_GetTokenTxsByAddress(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL) + p := Init(server.URL, "") txs, err := p.GetTokenTxsByAddress("bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", "AVA-645") assert.Nil(t, err) res, err := json.Marshal(txs) diff --git a/platform/platform.go b/platform/platform.go index adc79212a..066042c0d 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -65,7 +65,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Aeternity().Handle: aeternity.Init(config.Default.Aeternity.API), coin.Solana().Handle: solana.Init(config.Default.Solana.API), coin.Tezos().Handle: tezos.Init(config.Default.Tezos.API, config.Default.Tezos.RPC), - coin.Binance().Handle: binance.Init(config.Default.Binance.API), + 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.Kusama().Handle: polkadot.Init(coin.KSM, config.Default.Kusama.API), coin.Polkadot().Handle: polkadot.Init(coin.DOT, config.Default.Polkadot.API), diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index 04d3ced52..c5bd6d58b 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -4,6 +4,9 @@ import ( "context" "encoding/json" "errors" + + "github.com/trustwallet/golibs/coin" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/mq" @@ -21,11 +24,12 @@ func GetTransactionsFromDelivery(delivery amqp.Delivery, service string, ctx con return nil, err } - log.WithFields(log.Fields{"service": service, "txs": len(txs), "coin": txs[0].Coin}).Info("Consumed") - if len(txs) == 0 { return nil, errors.New("empty txs list") } + + log.WithFields(log.Fields{"service": service, "txs": len(txs), "coin": coin.Coins[txs[0].Coin].Handle}).Info("Consumed") + return txs, nil } @@ -35,11 +39,11 @@ func publishNotificationBatch(batch []TransactionNotification, ctx context.Conte raw, err := json.Marshal(batch) if err != nil { - log.Fatal(err) + log.Fatal("publishNotificationBatch marshal: ", err) } err = mq.TxNotifications.Publish(raw) if err != nil { - log.Fatal(err) + log.Fatal("publishNotificationBatch publish:", err) } log.WithFields(log.Fields{"service": Notifier, "txs": len(batch)}).Info("Txs batch dispatched") diff --git a/services/parser/parser.go b/services/parser/parser.go index 1cc525678..6fcaef303 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -25,7 +25,8 @@ type ( Params struct { Ctx context.Context Api blockatlas.BlockAPI - Queue []mq.Queue + TransactionsQueue mq.Queue + TokenTransactionsQueue []mq.Queue ParsingBlocksInterval, FetchBlocksTimeout time.Duration BacklogCount int MaxBacklogBlocks int64 @@ -39,11 +40,6 @@ type ( stop struct { error } - - transactionsBatch struct { - sync.Mutex - blockatlas.Txs - } ) const MinTxsBatchLimit = 500 @@ -79,7 +75,7 @@ func parse(params Params) { lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params, ctx) if err != nil || lastParsedBlock > currentBlock { - log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error(err) + log.WithFields(log.Fields{"operation": "fetch GetBlocksIntervalToFetch", "coin": params.Api.Coin().Handle}).Error(err) time.Sleep(params.ParsingBlocksInterval) return } @@ -88,17 +84,17 @@ func parse(params Params) { err = SaveLastParsedBlock(params, blocks, ctx) if err != nil { - log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error(err) + log.WithFields(log.Fields{"operation": "run SaveLastParsedBlock", "coin": params.Api.Coin().Handle}).Error(err) time.Sleep(params.ParsingBlocksInterval) return } - txs := ConvertToBatch(blocks, ctx) + txs := ConvertToBatch(blocks) txs = blockatlas.Txs(blockatlas.TxPage(txs).FilterTransactionsByMemo()) PublishTransactionsBatch(params, txs, ctx) - log.Info("End of parse step") + log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Info("End of parse step") } func GetBlocksIntervalToFetch(params Params, ctx context.Context) (int64, int64, error) { @@ -130,7 +126,7 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64, ctx context defer span.End() if lastParsedBlock == currentBlock { - log.WithFields(log.Fields{"last": lastParsedBlock, "coin": params.Api.Coin().ID, "time": time.Now().Unix()}). + log.WithFields(log.Fields{"last": lastParsedBlock, "coin": params.Api.Coin().Handle, "time": time.Now().Unix()}). Info("No new blocks") return nil } @@ -173,7 +169,7 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64, ctx context for err := range errorsChan { errorsList = append(errorsList, err) } - log.WithFields(log.Fields{"count": len(errorsList), "blocks": errorsList}).Error("Fetch blocks errors") + log.WithFields(log.Fields{"coin": params.Api.Coin().Handle, "count": len(errorsList), "blocks": errorsList}).Error("Fetch blocks errors") } blocksList := make([]blockatlas.Block, 0, len(blocksChan)) @@ -181,7 +177,7 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64, ctx context blocksList = append(blocksList, block) } - log.WithFields(log.Fields{"from": lastParsedBlock, "to": currentBlock, "total": totalCount}). + log.WithFields(log.Fields{"from": lastParsedBlock, "to": currentBlock, "total": totalCount, "coin": params.Api.Coin().Handle}). Info("Fetched blocks batch") return blocksList } @@ -227,36 +223,18 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block, ctx context.C return nil } -func ConvertToBatch(blocks []blockatlas.Block, ctx context.Context) blockatlas.Txs { - span, ctx := apm.StartSpan(ctx, "ConvertToBatch", "app") - defer span.End() +func ConvertToBatch(blocks []blockatlas.Block) blockatlas.Txs { if len(blocks) == 0 { return nil } - var ( - txsBatch transactionsBatch - wg sync.WaitGroup - ) + var txs []blockatlas.Tx for _, block := range blocks { - wg.Add(1) - go func(block blockatlas.Block, wg *sync.WaitGroup) { - defer wg.Done() - txsBatch.fillBatch(block.Txs, ctx) - }(block, &wg) + txs = append(txs, block.Txs...) } - wg.Wait() - if len(txsBatch.Txs) == 0 { - log.WithFields(log.Fields{"blocks": len(blocks)}). - Info("Blocks converted to transactions batch, there is no transactions") - return nil - } - - log.WithFields(log.Fields{"blocks": len(blocks), "txs": len(txsBatch.Txs)}). - Info("Blocks converted to transactions batch") - return txsBatch.Txs + return txs } func PublishTransactionsBatch(params Params, txs blockatlas.Txs, ctx context.Context) { @@ -300,14 +278,40 @@ func publish(params Params, txs blockatlas.Txs, ctx context.Context) { body, err := json.Marshal(txs) if err != nil { - log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error(err) + log.WithFields(log.Fields{"operation": "publish marshal", "coin": params.Api.Coin().Handle}).Error(err) return } - for _, q := range params.Queue { - err = q.Publish(body) - if err != nil { - log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error(err) - return + + // Notify transactions queue + err = params.TransactionsQueue.Publish(body) + if err != nil { + log.WithFields(log.Fields{"operation": "publish transactionsQueue", "coin": params.Api.Coin().Handle}).Error(err) + return + } + + // Notify token transfers queue, if conforms to TokensAPI protocol + tokenTransfers := txs.FilterTransactionsByType([]blockatlas.TransactionType{ + blockatlas.TxTokenTransfer, + blockatlas.TxNativeTokenTransfer, + }) + + if len(tokenTransfers) == 0 { + return + } + + tokenTransfersBody, err := json.Marshal(tokenTransfers) + if err != nil { + log.WithFields(log.Fields{"operation": "marshal tokenTransfers", "coin": params.Api.Coin().Handle}).Error(err) + return + } + + if _, ok := params.Api.(blockatlas.TokensAPI); ok { + for _, q := range params.TokenTransactionsQueue { + err = q.Publish(tokenTransfersBody) + if err != nil { + log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error(err) + return + } } } } @@ -327,7 +331,7 @@ func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumb sleep = sleep + jitter/2 log.WithFields(log.Fields{"number": n, "attempts": attempts, "sleep": sleep.String(), "symbol": symbol}). - Info("retry GetBlockByNumber") + Warn("retry GetBlockByNumber") time.Sleep(sleep) return getBlockByNumberWithRetry(attempts, sleep*2, getBlockByNumber, n, symbol, ctx) @@ -335,14 +339,3 @@ func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumb } return r, err } - -func (t *transactionsBatch) fillBatch(transactions []blockatlas.Tx, ctx context.Context) { - span, _ := apm.StartSpan(ctx, "fillBatch", "app") - defer span.End() - t.Lock() - defer t.Unlock() - if len(transactions) == 0 { - return - } - t.Txs = append(t.Txs, transactions...) -} diff --git a/services/parser/parser_test.go b/services/parser/parser_test.go index 60f81d72b..ac6ecdf91 100644 --- a/services/parser/parser_test.go +++ b/services/parser/parser_test.go @@ -3,13 +3,14 @@ package parser import ( "context" "errors" + "reflect" + "testing" + "time" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "sync" - "testing" - "time" ) var ( @@ -44,47 +45,22 @@ var ( func TestFetchBlocks(t *testing.T) { params := Params{ - Ctx: nil, - Api: getMockedBlockAPI(), - Queue: []mq.Queue{""}, - ParsingBlocksInterval: 0, - FetchBlocksTimeout: 0, - BacklogCount: 0, - MaxBacklogBlocks: 0, - StopChannel: nil, - TxBatchLimit: 0, - Database: nil, + Ctx: nil, + Api: getMockedBlockAPI(), + TransactionsQueue: "", + TokenTransactionsQueue: []mq.Queue{""}, + ParsingBlocksInterval: 0, + FetchBlocksTimeout: 0, + BacklogCount: 0, + MaxBacklogBlocks: 0, + StopChannel: nil, + TxBatchLimit: 0, + Database: nil, } blocks := FetchBlocks(params, 0, 100, context.Background()) assert.Equal(t, len(blocks), 100) } -func TestParser_ConvertToBatch(t *testing.T) { - blocks := []blockatlas.Block{block, block, block, block} - txs := ConvertToBatch(blocks, context.Background()) - assert.Equal(t, 4, len(txs)) - - empty := []blockatlas.Block{} - txsEmpty := ConvertToBatch(empty, context.Background()) - assert.Equal(t, 0, len(txsEmpty)) -} - -func TestParser_add(t *testing.T) { - blocks := []blockatlas.Block{block, block, block, block} - txs := ConvertToBatch(blocks, context.Background()) - - batch := transactionsBatch{ - Mutex: sync.Mutex{}, - Txs: txs, - } - - batch.fillBatch(txs, context.Background()) - assert.Equal(t, 8, len(batch.Txs)) - - batch.fillBatch(nil, context.Background()) - assert.Equal(t, 8, len(batch.Txs)) -} - func TestParser_getBlockByNumberWithRetry(t *testing.T) { block, err := getBlockByNumberWithRetry(3, time.Millisecond*1, getBlock, 1, "", context.Background()) if err != nil { @@ -222,3 +198,32 @@ func TestGetInterval(t *testing.T) { }) } } + +func TestConvertToBatch(t *testing.T) { + type args struct { + blocks []blockatlas.Block + } + tests := []struct { + name string + args args + want blockatlas.Txs + }{ + { + "Convert to batch", + args{ + []blockatlas.Block{ + block, + block, + }, + }, + append(block.Txs, block.Txs...), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ConvertToBatch(tt.args.blocks); !reflect.DeepEqual(got, tt.want) { + t.Errorf("ConvertToBatch() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/services/spamfilter/spamfilter.go b/services/spamfilter/spamfilter.go deleted file mode 100644 index 2bfa2fbfe..000000000 --- a/services/spamfilter/spamfilter.go +++ /dev/null @@ -1,30 +0,0 @@ -package spamfilter - -import ( - "regexp" - "strings" -) - -const URLRegex = `[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)` - -var ( - SpamList []string - compiledRegexp = regexp.MustCompile(URLRegex) -) - -func ContainsSpam(name string) bool { - if isURL(name) { - return true - } - lowerCaseName := strings.ToLower(name) - for _, word := range SpamList { - if strings.Contains(lowerCaseName, word) { - return true - } - } - return false -} - -func isURL(host string) bool { - return compiledRegexp.MatchString(host) -} diff --git a/services/spamfilter/spamfilter_test.go b/services/spamfilter/spamfilter_test.go deleted file mode 100644 index c3814e9d7..000000000 --- a/services/spamfilter/spamfilter_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package spamfilter - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func Test_isURL(t *testing.T) { - assert.True(t, isURL("http://www.trust.com")) - assert.True(t, isURL("www.trust.com")) - assert.True(t, isURL("trust.com")) - assert.True(t, isURL("saa,c trust.com")) -} diff --git a/tests/integration/db_test/tokenindexer_test.go b/tests/integration/db_test/tokenindexer_test.go index d32482cd8..a9d45cdc9 100644 --- a/tests/integration/db_test/tokenindexer_test.go +++ b/tests/integration/db_test/tokenindexer_test.go @@ -5,7 +5,6 @@ package db_test import ( "context" gocache "github.com/patrickmn/go-cache" - log "github.com/sirupsen/logrus" assert "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/tests/integration/setup" @@ -202,9 +201,6 @@ func Test_AddNewAssets(t *testing.T) { sort.Slice(assets, func(i, j int) bool { return len(assets[i].Name) > len(assets[j].Name) }) - log.Info(tt.WantedAssets) - log.Info("----------------------") - log.Info(assets) for i, a := range assets { assert.Equal(t, tt.WantedAssets[i].Asset, a.Asset) assert.Equal(t, tt.WantedAssets[i].Name, a.Name) diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index bc7190a77..7acc0772a 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -34,7 +34,7 @@ func TestFullFlow(t *testing.T) { params := setupParserFull(stopChan) params.Database = database params.Ctx = ctx - params.Queue = []mq.Queue{mq.RawTransactions} + params.TransactionsQueue = mq.RawTransactions go parser.RunParser(params) time.Sleep(time.Second * 2) diff --git a/tests/integration/observer_test/observer_test.go b/tests/integration/observer_test/observer_test.go index cdaba9d39..a2a851cdc 100644 --- a/tests/integration/observer_test/observer_test.go +++ b/tests/integration/observer_test/observer_test.go @@ -3,12 +3,13 @@ package observer_test import ( - "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/tests/integration/setup" "log" "os" "testing" + + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/tests/integration/setup" ) var ( diff --git a/tests/integration/observer_test/parser_test.go b/tests/integration/observer_test/parser_test.go index 795bc0bec..3ef3f37b7 100644 --- a/tests/integration/observer_test/parser_test.go +++ b/tests/integration/observer_test/parser_test.go @@ -27,7 +27,7 @@ func TestParserFetchAndPublishBlock_NormalCase(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) params.Ctx = ctx - params.Queue = []mq.Queue{mq.RawTransactions} + params.TransactionsQueue = mq.RawTransactions go parser.RunParser(params) From 48ee65f1875d5fa2318732c5fc9f6ea9d17054b9 Mon Sep 17 00:00:00 2001 From: Iuga Mihai <50499646+miiu96@users.noreply.github.com> Date: Thu, 26 Nov 2020 17:22:28 +0200 Subject: [PATCH 417/506] Update elrond integration (#1285) * update elrond integration * fix after review --- config.yml | 2 +- platform/elrond/client.go | 6 +-- platform/elrond/model.go | 41 +++++++++++++++++++- platform/elrond/transaction.go | 11 +++--- platform/elrond/transaction_test.go | 59 +++++++++++++++++++++++++++-- 5 files changed, 105 insertions(+), 14 deletions(-) diff --git a/config.yml b/config.yml index 9a6736647..28ef7bba2 100644 --- a/config.yml +++ b/config.yml @@ -220,7 +220,7 @@ near: api: https://staging-rpc.nearprotocol.com elrond: - api: https://api.elrond.com + api: https://gateway.elrond.com filecoin: api: https://api.filscan.io:8700/rpc/v1 diff --git a/platform/elrond/client.go b/platform/elrond/client.go index 63a21a431..b5e3e0b94 100644 --- a/platform/elrond/client.go +++ b/platform/elrond/client.go @@ -28,14 +28,14 @@ func (c *Client) CurrentBlockNumber() (num int64, err error) { func (c *Client) GetBlockByNumber(height int64) (*blockatlas.Block, error) { var blockRes BlockResponse - path := fmt.Sprintf("block/%s/%d", metachainID, uint64(height)) + path := fmt.Sprintf("hyperblock/by-nonce/%d", uint64(height)) err := c.getResponse(&blockRes, path, nil) if err != nil { return nil, err } block := blockRes.Block - txs := NormalizeTxs(block.Transactions, "") + txs := NormalizeTxs(block.Transactions, "", blockRes.Block) return &blockatlas.Block{ Number: int64(block.Nonce), @@ -54,7 +54,7 @@ func (c *Client) GetTxsOfAddress(address string) (blockatlas.TxPage, error) { return nil, err } - txs := NormalizeTxs(txPage.Transactions, address) + txs := NormalizeTxs(txPage.Transactions, address, Block{}) return txs, nil } diff --git a/platform/elrond/model.go b/platform/elrond/model.go index c4576ed1d..3e75cd78e 100644 --- a/platform/elrond/model.go +++ b/platform/elrond/model.go @@ -2,11 +2,15 @@ package elrond import ( "encoding/json" + "math/big" "time" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) +const roundDurationInSeconds = 6 +const mainnetStartTime = 1596117600 + type GenericResponse struct { Data json.RawMessage `json:"data"` Code string `json:"code"` @@ -24,11 +28,12 @@ type StatusDetails struct { } type BlockResponse struct { - Block Block `json:"block"` + Block Block `json:"hyperblock"` } type Block struct { Nonce uint64 `json:"nonce"` + Round uint64 `json:"round"` Hash string `json:"hash"` Transactions []Transaction `json:"transactions"` } @@ -47,6 +52,23 @@ type Transaction struct { Timestamp time.Duration `json:"timestamp"` Status string `json:"status"` Fee string `json:"fee"` + GasPrice uint64 `json:"gasPrice,omitempty"` + GasLimit uint64 `json:"gasLimit,omitempty"` +} + +func (tx *Transaction) TxFee() blockatlas.Amount { + if tx.Fee != "0" && tx.Fee != "" { + return blockatlas.Amount(tx.Fee) + } + + // Hyperblocks API V1 does not provide the transaction fees (nor "gasUsed"). Hyperblocks API V2 will provide this information, as well. + // Until then, we can compute the fees deterministically (best-effort) in BlockAtlas, based on gasLimit and gasPrice. This logic will be soon removed from BlockAtlas, in a future PR, when the Hyperblocks API v2 becomes available. + // Note: For Smart Contract transactions, the refunds will be incompletely provided by the API (until Hyperblocks V2 becomes available): e.g. intra-shard refunds are not visible etc.) + + txFee := big.NewInt(0).SetUint64(tx.GasPrice) + txFee = txFee.Mul(txFee, big.NewInt(0).SetUint64(tx.GasLimit)) + + return blockatlas.Amount(txFee.String()) } func (tx *Transaction) TxStatus() blockatlas.Status { @@ -70,3 +92,20 @@ func (tx *Transaction) Direction(address string) blockatlas.Direction { return blockatlas.DirectionIncoming } } + +func (tx *Transaction) TxTimestamp(blockRound uint64) time.Duration { + if int64(tx.Timestamp) != 0 { + return tx.Timestamp + } + + // Minor issue (slight inconsistency) about the "timestamp" field: + // The transactions fetched by querying the endpoint "address/erd1.../transactions" come from our central Elastic Search database, and their timestamp refers to the moment of *including* those transactions in shard blocks (detail: at destination). + // However, the transactions fetched by querying the endpoint "hyperblock/by-nonce/..." come from another source - from our Observer Nodes - and their timestamp refers to the moment of *final acknowledgement*, + // according to the Protocol (detail: the moment when the Metachain notarizes the destination shard block containing the transactions). + // Note: the differences are small - e.g. a few seconds. + // This inconsistency will be fixed in Hyperblocks API V2. + + txTimestamp := mainnetStartTime + blockRound*roundDurationInSeconds + + return time.Duration(txTimestamp) +} diff --git a/platform/elrond/transaction.go b/platform/elrond/transaction.go index 156bf0e63..2ac4219ce 100644 --- a/platform/elrond/transaction.go +++ b/platform/elrond/transaction.go @@ -12,9 +12,9 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { } // NormalizeTx converts an slice of Elrond transaction info a slice of generic model transaction -func NormalizeTxs(srcTxs []Transaction, address string) (txs []blockatlas.Tx) { +func NormalizeTxs(srcTxs []Transaction, address string, block Block) (txs []blockatlas.Tx) { for _, srcTx := range srcTxs { - tx, ok := NormalizeTx(srcTx, address) + tx, ok := NormalizeTx(srcTx, address, block) if !ok { continue } @@ -24,14 +24,15 @@ func NormalizeTxs(srcTxs []Transaction, address string) (txs []blockatlas.Tx) { } // NormalizeTx converts an Elrond transaction into the generic model -func NormalizeTx(srcTx Transaction, address string) (tx blockatlas.Tx, ok bool) { +func NormalizeTx(srcTx Transaction, address string, block Block) (tx blockatlas.Tx, ok bool) { tx = blockatlas.Tx{ ID: srcTx.Hash, Coin: coin.Elrond().ID, - Date: int64(srcTx.Timestamp), + Date: int64(srcTx.TxTimestamp(block.Round)), + Block: block.Nonce, From: srcTx.Sender, To: srcTx.Receiver, - Fee: blockatlas.Amount(srcTx.Fee), + Fee: srcTx.TxFee(), Status: srcTx.TxStatus(), Sequence: srcTx.Nonce, Memo: srcTx.Data, diff --git a/platform/elrond/transaction_test.go b/platform/elrond/transaction_test.go index 6d20d0c39..16a15c33d 100644 --- a/platform/elrond/transaction_test.go +++ b/platform/elrond/transaction_test.go @@ -52,8 +52,10 @@ const txTransferSrc3 = ` "data":"test", "signature":"", "timestamp":1588757256, - "status":"Not executed", - "fee": "5000" + "status":"Fail", + "fee": "0", + "gasPrice": 5, + "gasLimit": 1000 }` const txTransferSrc4 = ` @@ -86,6 +88,21 @@ const txTransferSrc5 = ` "fee": "5000" }` +const txTransferSrc6 = ` +{ + "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce":25, + "value":"2", + "receiver":"erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "data":"test", + "signature":"", + "status":"success", + "fee": "0", + "gasPrice": 5, + "gasLimit": 1000 +}` + var txTransfer1Normalized = blockatlas.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", Coin: coin.ERD, @@ -176,6 +193,25 @@ var txTransfer5Normalized = blockatlas.Tx{ Direction: blockatlas.DirectionOutgoing, } +var txTransfer6Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.ERD, + From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + Fee: "5000", + Status: blockatlas.StatusCompleted, + Memo: "test", + Sequence: 25, + Block: 620, + Date: 1596121554, + Meta: blockatlas.Transfer{ + Value: "2", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionOutgoing, +} + type test struct { name string apiResponse string @@ -222,7 +258,7 @@ func TestNormalizeTxs(t *testing.T) { _ = json.Unmarshal([]byte(txTransferSrc1), &tx3) txs := []Transaction{tx1, tx2, tx3} - normalizedTxs := NormalizeTxs(txs, userAddress) + normalizedTxs := NormalizeTxs(txs, userAddress, Block{}) require.Equal(t, len(txs), len(normalizedTxs)) } @@ -234,7 +270,7 @@ func testNormalize(t *testing.T, _test *test) { return } - normalizedTx, ok := NormalizeTx(tx, tx.Sender) + normalizedTx, ok := NormalizeTx(tx, tx.Sender, Block{}) require.True(t, ok, _test.name+": cannot normalize tx") resJSON, err := json.Marshal(&normalizedTx) @@ -245,3 +281,18 @@ func testNormalize(t *testing.T, _test *test) { require.Equal(t, string(dstJSON), string(resJSON)) } + +func TestNormalizeTxsFromHyperblock(t *testing.T) { + var tx Transaction + + _ = json.Unmarshal([]byte(txTransferSrc6), &tx) + txs := []Transaction{tx} + + normalizedTxs := NormalizeTxs(txs, userAddress, Block{ + Nonce: 620, + Round: 659, + }) + require.Equal(t, len(txs), len(normalizedTxs)) + + require.Equal(t, []blockatlas.Tx{txTransfer6Normalized}, normalizedTxs) +} From c1abb5254a2b491babf8a4bc6f47972fd16f5df2 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 26 Nov 2020 12:44:36 -0800 Subject: [PATCH 418/506] Improve logging / remove metrics (#1286) * Improve logging / review apps * Update app.json * Remove metrics endpoint --- api/middleware/prometheus_test.go | 25 ++++++++++--------------- api/registry.go | 3 --- app.json | 4 ++-- services/parser/parser.go | 2 +- services/subscriber/tokens.go | 3 +-- 5 files changed, 14 insertions(+), 23 deletions(-) diff --git a/api/middleware/prometheus_test.go b/api/middleware/prometheus_test.go index a3c952f9d..44e8ad6d8 100644 --- a/api/middleware/prometheus_test.go +++ b/api/middleware/prometheus_test.go @@ -1,24 +1,19 @@ package middleware import ( - "github.com/chenjiandongx/ginprom" - "github.com/gin-gonic/gin" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/stretchr/testify/assert" - "net/http" "testing" ) -func TestPrometheus(t *testing.T) { - router := gin.New() - router.Use(Prometheus()) - router.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) - - w1 := performRequest("GET", "/metrics", router) - - assert.Equal(t, http.StatusOK, w1.Code) - assert.NotNil(t, w1.Body.String()) -} +//func TestPrometheus(t *testing.T) { +// router := gin.New() +// router.Use(Prometheus()) +// router.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) +// +// w1 := performRequest("GET", "/metrics", router) +// +// assert.Equal(t, http.StatusOK, w1.Code) +// assert.NotNil(t, w1.Body.String()) +//} func Test_removeAddress(t *testing.T) { tests := []struct { diff --git a/api/registry.go b/api/registry.go index aae152ae1..153fd0420 100644 --- a/api/registry.go +++ b/api/registry.go @@ -3,9 +3,7 @@ package api import ( "time" - "github.com/chenjiandongx/ginprom" "github.com/gin-gonic/gin" - "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/trustwallet/blockatlas/api/endpoint" "github.com/trustwallet/blockatlas/api/middleware" "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -102,7 +100,6 @@ func RegisterBatchAPI(router gin.IRouter) { func RegisterBasicAPI(router gin.IRouter) { router.GET("/", endpoint.GetStatus) - router.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) } func RegisterTokensSearcherAPI(router gin.IRouter, instance tokensearcher.Instance) { diff --git a/app.json b/app.json index 386e7d81c..a06ef2b75 100644 --- a/app.json +++ b/app.json @@ -14,11 +14,11 @@ "addons": [ { "plan":"heroku-postgresql:hobby-dev", - "as":"ATLAS_POSTGRES" + "as":"POSTGRES" }, { "plan":"cloudamqp:lemur", - "as":"ATLAS_OBSERVER_RABBITMQ" + "as":"OBSERVER_RABBITMQ" } ] } diff --git a/services/parser/parser.go b/services/parser/parser.go index 6fcaef303..0a9e209e8 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -75,7 +75,7 @@ func parse(params Params) { lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params, ctx) if err != nil || lastParsedBlock > currentBlock { - log.WithFields(log.Fields{"operation": "fetch GetBlocksIntervalToFetch", "coin": params.Api.Coin().Handle}).Error(err) + log.WithFields(log.Fields{"operation": "fetch GetBlocksIntervalToFetch", "lastParsedBlock": lastParsedBlock, "currentBlock": currentBlock, "coin": params.Api.Coin().Handle}).Error(err) time.Sleep(params.ParsingBlocksInterval) return } diff --git a/services/subscriber/tokens.go b/services/subscriber/tokens.go index 2a69c2e23..1fbe15e37 100644 --- a/services/subscriber/tokens.go +++ b/services/subscriber/tokens.go @@ -8,7 +8,6 @@ import ( "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" "go.elastic.co/apm" - "strconv" ) const Tokens Subscriber = "tokens" @@ -30,7 +29,7 @@ func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { log.Error("Failed to AddAssociationsForAddress: " + err.Error()) } } - log.WithFields(log.Fields{"service": Tokens}).Info("Subscribed " + strconv.Itoa(len(event))) + log.WithFields(log.Fields{"service": Tokens, "count": len(event)}).Info("Subscribed") if err := delivery.Ack(false); err != nil { log.Fatal(err, err) } From ecd476661ec61fb214825856d52b2ea7c4b6ba53 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 1 Dec 2020 00:02:58 -0800 Subject: [PATCH 419/506] [Tron] Improve tron tokens parsing (#1288) * Add login to token parsing * Update api.go * Update client.go * Update client.go * Update client.go * Update client.go * [Tron] Use int value for parsing token id of TRC10 token * Update client.go * Update client.go * Remove legacy middleware * Add caching to tron client --- api/middleware/cache.go | 187 ------------------------------ api/middleware/cache_test.go | 87 -------------- api/middleware/prometheus.go | 38 ------ api/middleware/prometheus_test.go | 37 ------ api/registry.go | 2 +- go.mod | 8 +- go.sum | 161 +++++++++++++++++++++++++ internal/init.go | 1 - platform/tron/client.go | 16 ++- platform/tron/model.go | 2 +- platform/tron/token.go | 5 +- platform/tron/token_test.go | 6 +- platform/tron/transaction.go | 2 +- platform/tron/transaction_test.go | 2 +- services/tokensearcher/api.go | 2 +- 15 files changed, 183 insertions(+), 373 deletions(-) delete mode 100644 api/middleware/cache.go delete mode 100644 api/middleware/cache_test.go delete mode 100644 api/middleware/prometheus.go delete mode 100644 api/middleware/prometheus_test.go diff --git a/api/middleware/cache.go b/api/middleware/cache.go deleted file mode 100644 index 02d1cd3ad..000000000 --- a/api/middleware/cache.go +++ /dev/null @@ -1,187 +0,0 @@ -package middleware - -import ( - "bytes" - "crypto/sha1" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "github.com/gin-gonic/gin" - "github.com/patrickmn/go-cache" - log "github.com/sirupsen/logrus" - "io/ioutil" - "net/http" - "sync" - "time" -) - -var ( - memoryCache *memCache -) - -func init() { - memoryCache = &memCache{cache: cache.New(5*time.Minute, 5*time.Minute)} -} - -type memCache struct { - sync.RWMutex - cache *cache.Cache -} - -type cacheResponse struct { - Status int - Header http.Header - Data []byte -} - -type cachedWriter struct { - gin.ResponseWriter - status int - written bool - expire time.Duration - key string -} - -func newCachedWriter(expire time.Duration, writer gin.ResponseWriter, key string) *cachedWriter { - return &cachedWriter{writer, 0, false, expire, key} -} - -func (w *cachedWriter) WriteHeader(code int) { - w.status = code - w.written = true - w.ResponseWriter.WriteHeader(code) -} - -func (w *cachedWriter) Status() int { - return w.ResponseWriter.Status() -} - -func (w *cachedWriter) Written() bool { - return w.ResponseWriter.Written() -} - -func (w *cachedWriter) Write(data []byte) (int, error) { - ret, err := w.ResponseWriter.Write(data) - if err != nil { - return 0, nil - } - if w.Status() != 200 { - return 0, nil - } - val := cacheResponse{ - w.Status(), - w.Header(), - data, - } - b, err := json.Marshal(val) - if err != nil { - return 0, errors.New("validator cache: failed to marshal cache object") - } - memoryCache.cache.Set(w.key, b, w.expire) - return ret, nil -} - -func (w *cachedWriter) WriteString(data string) (n int, err error) { - ret, err := w.ResponseWriter.WriteString(data) - if err != nil { - return 0, errors.New(err.Error() + " fail to cache write string") - } - if w.Status() != 200 { - return 0, errors.New("WriteString: invalid cache status") - } - val := cacheResponse{ - w.Status(), - w.Header(), - []byte(data), - } - b, err := json.Marshal(val) - if err != nil { - return 0, errors.New("validator cache: failed to marshal cache object") - } - memoryCache.setCache(w.key, b, w.expire) - return ret, err -} - -func (mc *memCache) deleteCache(key string) { - mc.RLock() - defer mc.RUnlock() - memoryCache.cache.Delete(key) -} - -func (mc *memCache) setCache(k string, x interface{}, d time.Duration) { - b, err := json.Marshal(x) - if err != nil { - log.Error(errors.New(err.Error() + "client cache cannot marshal cache object")) - return - } - mc.RLock() - defer mc.RUnlock() - memoryCache.cache.Set(k, b, d) -} - -func (mc *memCache) getCache(key string) (cacheResponse, error) { - var result cacheResponse - c, ok := mc.cache.Get(key) - if !ok { - return result, fmt.Errorf("gin-cache: invalid cache key %s", key) - } - r, ok := c.([]byte) - if !ok { - return result, errors.New("validator cache: failed to cast cache to bytes") - } - err := json.Unmarshal(r, &result) - if err != nil { - return result, errors.New(err.Error() + " not found") - } - return result, nil -} - -func generateKey(c *gin.Context) string { - url := c.Request.URL.String() - var b []byte - if c.Request.Body != nil { - b, _ = ioutil.ReadAll(c.Request.Body) - // Restore the io.ReadCloser to its original state - c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(b)) - } - hash := sha1.Sum(append([]byte(url), b...)) - return base64.URLEncoding.EncodeToString(hash[:]) -} - -// CacheMiddleware encapsulates a gin handler function and caches the model with an expiration time. -func CacheMiddleware(expiration time.Duration, handle gin.HandlerFunc) gin.HandlerFunc { - return func(c *gin.Context) { - defer c.Next() - key := generateKey(c) - cacheControlValue := uint(expiration.Seconds()) - mc, err := memoryCache.getCache(key) - if err != nil || mc.Data == nil { - writer := newCachedWriter(expiration, c.Writer, key) - - writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", cacheControlValue)) - - c.Writer = writer - handle(c) - if c.IsAborted() { - memoryCache.deleteCache(key) - } - return - } - - c.Writer.WriteHeader(mc.Status) - for k, vals := range mc.Header { - for _, v := range vals { - c.Writer.Header().Set(k, v) - } - } - - c.Writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", cacheControlValue)) - - _, err = c.Writer.Write(mc.Data) - if err != nil { - memoryCache.deleteCache(key) - log.Error(err, "cannot write data", mc) - } - } -} diff --git a/api/middleware/cache_test.go b/api/middleware/cache_test.go deleted file mode 100644 index 70b680b30..000000000 --- a/api/middleware/cache_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package middleware - -import ( - "fmt" - "github.com/gin-gonic/gin" - "github.com/stretchr/testify/assert" - "net/http" - "net/http/httptest" - "testing" - "time" -) - -func init() { - gin.SetMode(gin.TestMode) -} - -func performRequest(method, target string, router *gin.Engine) *httptest.ResponseRecorder { - r := httptest.NewRequest(method, target, nil) - w := httptest.NewRecorder() - router.ServeHTTP(w, r) - return w -} - -func TestWrite(t *testing.T) { - w := httptest.NewRecorder() - c, _ := gin.CreateTestContext(w) - - writer := newCachedWriter(time.Second*3, c.Writer, "mykey") - c.Writer = writer - - c.Writer.WriteHeader(http.StatusNoContent) - c.Writer.WriteHeaderNow() - _, _ = c.Writer.Write([]byte("foo")) // nolint - assert.Equal(t, http.StatusNoContent, c.Writer.Status()) - assert.Equal(t, "foo", w.Body.String()) - assert.True(t, c.Writer.Written()) -} - -func TestCachePage(t *testing.T) { - router := gin.New() - router.GET("/cache_ping", CacheMiddleware(time.Second*3, func(c *gin.Context) { - c.JSON(http.StatusOK, "pong "+fmt.Sprint(time.Now().UnixNano())) - })) - - w1 := performRequest("GET", "/cache_ping", router) - w2 := performRequest("GET", "/cache_ping", router) - - assert.Equal(t, http.StatusOK, w1.Code) - assert.Equal(t, http.StatusOK, w2.Code) - assert.Equal(t, w1.Body.String(), w2.Body.String()) -} - -func TestCachePageExpire(t *testing.T) { - router := gin.New() - router.GET("/cache_ping", CacheMiddleware(time.Second, func(c *gin.Context) { - c.JSON(http.StatusOK, "pong "+fmt.Sprint(time.Now().UnixNano())) - })) - - w1 := performRequest("GET", "/cache_ping", router) - time.Sleep(time.Second * 3) - w2 := performRequest("GET", "/cache_ping", router) - - assert.Equal(t, http.StatusOK, w1.Code) - assert.Equal(t, http.StatusOK, w2.Code) - assert.NotEqual(t, w1.Body.String(), w2.Body.String()) -} - -func TestCacheControl(t *testing.T) { - router := gin.New() - router.GET("/cache_ping_control", CacheMiddleware(time.Second*30, func(c *gin.Context) { - c.JSON(http.StatusOK, "pong "+fmt.Sprint(time.Now().UnixNano())) - })) - - w1 := performRequest("GET", "/cache_ping_control", router) - w1CacheControl := w1.Header().Get("Cache-Control") - assert.NotEqual(t, "no-cache", w1CacheControl) - time.Sleep(time.Second * 1) - w2 := performRequest("GET", "/cache_ping_control", router) - w2CacheControl := w2.Header().Get("Cache-Control") - - assert.Equal(t, w1CacheControl, w2CacheControl) - assert.Equal(t, w1.Body.String(), w2.Body.String()) - - assert.Equal(t, http.StatusOK, w1.Code) - assert.Equal(t, http.StatusOK, w2.Code) - -} diff --git a/api/middleware/prometheus.go b/api/middleware/prometheus.go deleted file mode 100644 index 0ca1d15cf..000000000 --- a/api/middleware/prometheus.go +++ /dev/null @@ -1,38 +0,0 @@ -package middleware - -import ( - "fmt" - "github.com/gin-gonic/gin" - "github.com/prometheus/client_golang/prometheus" - "regexp" -) - -var labels = []string{"status", "endpoint", "method"} - -func Prometheus() gin.HandlerFunc { - serverReqCount := prometheus.NewCounterVec( - prometheus.CounterOpts{ - Namespace: "atlas", - Name: "http_request_count_total", - Help: "Total number of HTTP requests made.", - }, labels, - ) - prometheus.MustRegister(serverReqCount) - - return func(c *gin.Context) { - c.Next() - - status := fmt.Sprintf("%d", c.Writer.Status()) - url := c.Request.URL.Path - method := c.Request.Method - - lvs := []string{status, removeAddress(url), method} - - serverReqCount.WithLabelValues(lvs...).Inc() - } -} - -func removeAddress(info string) string { - reg := regexp.MustCompile(`([a-zA-Z0-9\s]{30,})|([0-9]{4,})|(=(.*?)[^(&|$)]+)|(--[^$]+)|(&asset_contract_addresses)`) - return reg.ReplaceAllString(info, "") -} diff --git a/api/middleware/prometheus_test.go b/api/middleware/prometheus_test.go deleted file mode 100644 index 44e8ad6d8..000000000 --- a/api/middleware/prometheus_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package middleware - -import ( - "testing" -) - -//func TestPrometheus(t *testing.T) { -// router := gin.New() -// router.Use(Prometheus()) -// router.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) -// -// w1 := performRequest("GET", "/metrics", router) -// -// assert.Equal(t, http.StatusOK, w1.Code) -// assert.NotNil(t, w1.Body.String()) -//} - -func Test_removeAddress(t *testing.T) { - tests := []struct { - name string - info string - want string - }{ - {"Remove Nimiq address", "/v1/nimiq/NQ43 J7G6 K6T8 H5KJ 5CXN Q5JK 2GJ4 6DSB 7PUH", "/v1/nimiq/"}, - {"Remove Tezos address", "/v1/tezos/tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", "/v1/tezos/"}, - {"Remove Tron info", "https://api.trongrid.io/v1/accounts/TPJYCz8ppZNyvw7pTwmjajcx4Kk1MmEUhD/transactions?limit=200&only_confirmed=true&token_id=1000011", "https://api.trongrid.io/v1/accounts//transactions?limit&only_confirmed&token_id"}, - {"Remove asset id", "https://api.trongrid.io/v1/assets/1000570?", "https://api.trongrid.io/v1/assets/?"}, - {"Remove collection id", "/v2/ethereum/collections//collection/---enjin-old", "/v2/ethereum/collections//collection/"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := removeAddress(tt.info); got != tt.want { - t.Errorf("removeSensitiveInfo() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/api/registry.go b/api/registry.go index 153fd0420..dfbcaadbd 100644 --- a/api/registry.go +++ b/api/registry.go @@ -5,11 +5,11 @@ import ( "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/api/endpoint" - "github.com/trustwallet/blockatlas/api/middleware" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" + "github.com/trustwallet/golibs-networking/middleware" ) func RegisterTransactionsAPI(router gin.IRouter, api blockatlas.Platform) { diff --git a/go.mod b/go.mod index 61593b6c5..79c484e25 100644 --- a/go.mod +++ b/go.mod @@ -29,21 +29,21 @@ require ( github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.7.1 - github.com/sirupsen/logrus v1.6.0 + github.com/prometheus/client_golang v1.8.0 + github.com/sirupsen/logrus v1.7.0 github.com/spf13/viper v1.7.1 - github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 + github.com/streadway/amqp v1.0.0 github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.2.0 github.com/swaggo/swag v1.6.7 github.com/trustwallet/golibs v0.0.15 + github.com/trustwallet/golibs-networking v0.0.3 go.elastic.co/apm v1.8.0 go.elastic.co/apm/module/apmgin v1.8.0 go.elastic.co/apm/module/apmhttp v1.8.0 go.elastic.co/fastjson v1.1.0 // indirect go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 - golang.org/x/net v0.0.0-20200506145744-7e3656a0809f // indirect golang.org/x/tools v0.0.0-20200513175351-0951661448da // indirect gopkg.in/yaml.v2 v2.3.0 gorm.io/driver/postgres v1.0.5 diff --git a/go.sum b/go.sum index fc68381ee..962a154c7 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,7 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= @@ -29,17 +30,28 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 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/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -60,24 +72,32 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 h1:3Wv1E0CqL45hBs4bykb586wvZMRGKfFITHrN3ilm4FE= github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb h1:nXPkFq8X1a9ycY3GYQpFNxHh3j2JgY7zDZfq2EXMIzk= github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -96,6 +116,10 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/go-sysinfo v1.1.1 h1:ZVlaLDyhVkDfjwPGU55CQRCRolNpc7P0BbyhhQZQmMI= github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-sysinfo v1.3.0 h1:eb2XFGTMlSwG/yyU9Y8jVAYLIzU2sFzWXwo2gmetyrE= @@ -104,7 +128,12 @@ github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7 github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -121,8 +150,10 @@ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwv github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= @@ -147,15 +178,20 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -171,6 +207,9 @@ github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -183,18 +222,27 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -205,6 +253,7 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -215,9 +264,11 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U= github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= @@ -276,12 +327,16 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= @@ -290,6 +345,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= @@ -312,6 +368,9 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -330,6 +389,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/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 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= @@ -351,56 +411,98 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw= +github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4= +github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -408,6 +510,7 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -423,26 +526,36 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5NYJe/zRYDwOu9ku6YHy+Iw7l5DM= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -461,9 +574,14 @@ github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/golibs v0.0.15 h1:f85eXy/WsmoTSI3cYim4qpTxucW0KYHC4RDgkr1vvJo= github.com/trustwallet/golibs v0.0.15/go.mod h1:j+Tip4aaW3mu+81S1a+UJ8fSnKzLeJyBueApnCXXRMg= +github.com/trustwallet/golibs-networking v0.0.2 h1:E13QGT+P80H8+42wT+HNER1R7NOTx5Uh5/iOrasbaCg= +github.com/trustwallet/golibs-networking v0.0.2/go.mod h1:ZVZDbu7LW0MxnuVR280SeQIjzgUo++oc9Dft4XKrPYs= +github.com/trustwallet/golibs-networking v0.0.3 h1:eWBj1JKKhNUj1Ks+gdDji1IxboYyKp6j6Peyey5JkxA= +github.com/trustwallet/golibs-networking v0.0.3/go.mod h1:ZVZDbu7LW0MxnuVR280SeQIjzgUo++oc9Dft4XKrPYs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= @@ -473,6 +591,7 @@ github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2t github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -488,19 +607,27 @@ go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHt go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4= go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -510,6 +637,7 @@ golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaE golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -538,6 +666,7 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -549,6 +678,7 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -564,6 +694,8 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -580,6 +712,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -593,25 +726,34 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -622,6 +764,7 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -637,6 +780,7 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200513175351-0951661448da h1:ZR1ivkcQoKXKtux9Rx3Em7iiSViMxQ5suNd5PZMUkPc= golang.org/x/tools v0.0.0-20200513175351-0951661448da/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -646,12 +790,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= @@ -661,13 +807,21 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -682,8 +836,10 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= @@ -692,6 +848,7 @@ gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -717,12 +874,16 @@ gorm.io/plugin/dbresolver v1.0.0 h1:fHIWRRkoDmXkBPYyg9GMmLugcM9fcbZiG0Zy/cwiPlM= gorm.io/plugin/dbresolver v1.0.0/go.mod h1:sK1Alv120lfrjRQXrzyAw4ssxDPJjamm2cbBOZBHM68= 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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 h1:AQkaJpH+/FmqRjmXZPELom5zIERYZfwTjnHpfoVMQEc= howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/internal/init.go b/internal/init.go index af9e52207..0ab597b1a 100644 --- a/internal/init.go +++ b/internal/init.go @@ -45,7 +45,6 @@ func InitEngine(ginMode string) *gin.Engine { engine.Use(middleware.CORSMiddleware()) engine.Use(apmgin.Middleware(engine)) engine.Use(gin.Logger()) - engine.Use(middleware.Prometheus()) engine.OPTIONS("/*path", middleware.CORSMiddleware()) return engine diff --git a/platform/tron/client.go b/platform/tron/client.go index e95210ad3..e60f9f87f 100644 --- a/platform/tron/client.go +++ b/platform/tron/client.go @@ -36,18 +36,18 @@ func (c *Client) fetchTxsOfAddress(address, token string) ([]Tx, error) { path := fmt.Sprintf("v1/accounts/%s/transactions", url.PathEscape(address)) var txs Page - err := c.Get(&txs, path, url.Values{ + err := c.GetWithCache(&txs, path, url.Values{ "limit": {"25"}, "token_id": {token}, "order_by": {"block_timestamp,desc"}, - }) + }, time.Minute*1) return txs.Txs, err } func (c *Client) fetchAccount(address string) (accounts *Account, err error) { path := fmt.Sprintf("v1/accounts/%s", address) - err = c.Get(&accounts, path, nil) + err = c.GetWithCache(&accounts, path, nil, time.Minute*1) return } @@ -63,18 +63,18 @@ func (c *Client) fetchTokenInfo(id string) (asset Asset, err error) { } func (c *Client) fetchValidators() (validators Validators, err error) { - err = c.Get(&validators, "wallet/listwitnesses", nil) + err = c.GetWithCache(&validators, "wallet/listwitnesses", nil, time.Hour*1) return } func (c *Client) fetchTRC20Transactions(address string) (TRC20Transactions, error) { var result TRC20Transactions path := fmt.Sprintf("v1/accounts/%s/transactions/trc20", address) - err := c.Get(&result, path, url.Values{ + err := c.GetWithCache(&result, path, url.Values{ "limit": {"200"}, "order_by": {"block_timestamp,desc"}, "only_confirmed": {"true"}, - }) + }, time.Minute*1) if err != nil { return TRC20Transactions{}, err } @@ -84,9 +84,7 @@ func (c *Client) fetchTRC20Transactions(address string) (TRC20Transactions, erro func (c *ExplorerClient) fetchAllTRC20Tokens(address string) ([]ExplorerTrc20Tokens, error) { var result ExplorerResponse path := "api/account" - err := c.Get(&result, path, url.Values{ - "address": {address}, - }) + err := c.GetWithCache(&result, path, url.Values{"address": {address}}, time.Minute*5) if err != nil { return nil, err } diff --git a/platform/tron/model.go b/platform/tron/model.go index 840a07867..d512f9971 100644 --- a/platform/tron/model.go +++ b/platform/tron/model.go @@ -93,7 +93,7 @@ type ( AssetInfo struct { Name string `json:"name"` Symbol string `json:"abbr"` - ID string `json:"id"` + ID uint `json:"id"` Decimals uint `json:"precision"` } diff --git a/platform/tron/token.go b/platform/tron/token.go index 31d9c5133..c71922c0b 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -5,6 +5,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/tokentype" + "strconv" "strings" "sync" "time" @@ -59,7 +60,7 @@ func (p *Platform) getTokens(ids []string) chan blockatlas.Token { time.Sleep(time.Millisecond) err := p.getTokensChannel(i, c) if err != nil { - log.Error("tron getTokens: " + i) + log.WithFields(log.Fields{"token": i, "coin": coin.Tron().Handle}).Error("getTokens", err) } }(id, tkChan) } @@ -82,7 +83,7 @@ func NormalizeToken(info AssetInfo) blockatlas.Token { return blockatlas.Token{ Name: info.Name, Symbol: strings.ToUpper(info.Symbol), - TokenID: info.ID, + TokenID: strconv.Itoa(int(info.ID)), Coin: coin.TRX, Decimals: info.Decimals, Type: tokentype.TRC10, diff --git a/platform/tron/token_test.go b/platform/tron/token_test.go index 91c9a6c57..921cce93d 100644 --- a/platform/tron/token_test.go +++ b/platform/tron/token_test.go @@ -21,7 +21,7 @@ var tokenDst = blockatlas.Token{ } func TestNormalizeToken(t *testing.T) { - asset := AssetInfo{Name: "Test", Symbol: "TST", ID: "1", Decimals: 8} + asset := AssetInfo{Name: "Test", Symbol: "TST", ID: 1, Decimals: 8} actual := NormalizeToken(asset) assert.Equal(t, tokenDst, actual) } @@ -107,8 +107,8 @@ var ( mockedTrc20Response = `{"trc20token_balances":[{"name":"BeeHive","symbol":"Bee","decimals":8,"contract_address":"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK","balance":"100000000000000"},{"name":"NoleCoin","symbol":"NOLE","decimals":6,"contract_address":"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG","balance":"20000","priceInTrx":20.000000},{"name":"Enme Token","symbol":"EME","decimals":6,"contract_address":"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF","balance":"175798"},{"name":"PYRO Network","symbol":"PYRO","decimals":6,"contract_address":"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e","balance":"5000000000","priceInTrx":0.005821},{"name":"Wuhan Fried Bats","symbol":"WUHAN","decimals":4,"contract_address":"TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr","balance":"690000"},{"name":"WINK","symbol":"WIN","decimals":6,"contract_address":"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7","balance":"191543058623486","priceInTrx":0.004665},{"name":"Mono Token","symbol":"MONO","decimals":18,"contract_address":"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak","balance":"1"},{"name":"HelGro","symbol":"HGRO","decimals":6,"contract_address":"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm","balance":"20000000"},{"name":"JUST GOV","symbol":"JST","decimals":18,"contract_address":"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9","balance":"955973733483987848990056","priceInTrx":0.313300},{"name":"Tether USD","symbol":"USDT","decimals":6,"contract_address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","balance":"6781725898163","priceInTrx":64.102564}],"allowExchange":[],"address":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","frozen_supply":[],"bandwidth":{"energyRemaining":0,"totalEnergyLimit":90000000000,"totalEnergyWeight":1446707995,"netUsed":0,"storageLimit":0,"storagePercentage":0.0,"assets":{"1000542":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002446":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002721":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001510":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002962":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001479":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002288":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001594":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002683":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000541":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001079":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000145":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002608":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000821":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002845":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001759":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002726":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001230":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001467":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002798":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000894":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000532":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002830":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000017":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000494":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002398":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002552":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002551":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002672":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002037":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002950":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000935":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000938":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002438":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000491":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000096":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002671":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000493":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001064":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001581":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002270":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000322":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002589":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001411":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002467":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002742":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001414":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001535":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000567":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000165":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001011":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002342":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001132":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000562":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000287":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001815":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002907":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002746":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002748":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001090":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000278":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000157":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002578":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002577":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002852":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002459":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000396":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002573":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002454":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000959":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002736":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002858":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003022":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001038":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000983":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001433":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000743":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001953":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002646":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000985":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002524":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002001":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002881":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002488":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002521":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002762":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002927":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002926":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000745":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000744":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000746":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002000":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000181":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002116":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001301":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001425":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002876":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000176":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000451":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003049":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002597":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002918":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002636":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002999":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001825":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000856":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002517":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002230":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002071":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003041":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002072":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000003":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000520":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000884":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002544":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001854":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002822":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000006":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002662":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002669":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002384":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002263":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001203":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002897":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001565":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002775":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002657":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001204":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001446":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002892":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002939":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002814":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002250":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002099":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000190":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0}},"netPercentage":0.0,"storageUsed":0,"storageRemaining":0,"freeNetLimit":5000,"energyUsed":0,"freeNetRemaining":211,"netLimit":0,"netRemaining":0,"energyLimit":0,"freeNetUsed":4789,"totalNetWeight":26789943446,"freeNetPercentage":0.9578,"energyPercentage":0.0,"totalNetLimit":43200000000},"accountType":0,"exchanges":[],"frozen":{"total":0,"balances":[]},"accountResource":{"frozen_balance_for_energy":{}},"tokenBalances":[{"balance":346976329314696,"name":"_"},{"balance":1273,"name":"1000003"},{"balance":113,"name":"1000006"},{"balance":145,"name":"1000165"},{"balance":416,"name":"1000520"},{"balance":596,"name":"1000491"},{"balance":242,"name":"1000176","owner_address":"THG48yHsR6inxrCJk2hhxZPsFLq1ehP88V"},{"balance":62,"name":"1000542"},{"balance":53,"name":"1000494","owner_address":"TXJnVqqwLSNmdXDLWn1Yfjhe8aZH2oaAuq"},{"balance":56,"name":"1000493"},{"balance":599,"name":"1000744"},{"balance":628,"name":"1000746"},{"balance":234,"name":"1000743"},{"balance":113,"name":"1000396"},{"balance":206,"name":"1000745","owner_address":"TPCEi45wZQ1PPChUg5uqoK1D5kKnjCR8Li"},{"balance":61,"name":"1000821","owner_address":"TBm3Peu51gYwn2iPwNEDxc9vBMc3eRGUGu"},{"balance":25,"name":"1000541"},{"balance":7,"name":"1000278","owner_address":"TRMUimDekf9nDLuVMp6TKzcw4axNnajGJr"},{"balance":1,"name":"1000567","owner_address":"TFXJMhB4ZKBfcQWfCLbSyQGhonHXABaWku"},{"balance":1,"name":"1000856","owner_address":"TXf3X8YMdDho2xwA6QDbFZiTGPnk8ghfLm"},{"balance":30,"name":"1000884"},{"balance":1,"name":"1000894"},{"balance":200,"name":"1000181","owner_address":"TEmTbbvH5ZPJPZ8CbffjqonFRiAAFgfc9o"},{"balance":7,"name":"1000935","owner_address":"TPVkcFYTEi9Dia45AveiTcaYoaU9ux7xC7"},{"balance":1000,"name":"1000938","owner_address":"TNgkWTabK1rMWwgLjmLdsZbzYfGTx5Tpe9"},{"balance":10,"name":"1000017","owner_address":"TV6qcwSp38uESiDczxxb7zbJX1h2LfDs78"},{"balance":10,"name":"1001011","owner_address":"TNUbeTQXPtRXtBX3dJboVkhdhaiws29Aky"},{"balance":2,"name":"1001038","owner_address":"TFujVDp8U578L2AtsorYN3pwdXmH2HxbQv"},{"balance":100,"name":"1000983","owner_address":"TYmiZ7xCeqboiizb2jsjVQuRABXzVSjKFR"},{"balance":1,"name":"1001203","owner_address":"TBmaT8mcrdkrRL2Q6ur7grMYAcaGtfxsz7"},{"balance":1,"name":"1000190","owner_address":"TNXjXURue38Wa641pmqMH4vbJN1WZLKMnr"},{"balance":100,"name":"1001204"},{"balance":1000,"name":"1001230"},{"balance":1300000,"name":"1001301","owner_address":"TVgJEbc9NEYxVr1h6rJQiMqySePsJQDCA7"},{"balance":11,"name":"1000959"},{"balance":10,"name":"1001425"},{"balance":17,"name":"1001433","owner_address":"TWPMz6FPEAV6qP4VRMG3Y69ftEov1R7YWT"},{"balance":100,"name":"1001446"},{"balance":12,"name":"1001411","owner_address":"TPL6zNujtEQ8kp213n58UxAhGRCU3aozkc"},{"balance":12,"name":"1001467"},{"balance":100,"name":"1001414","owner_address":"TT43DgfxgMdR4BVZNua4YCwG34AgfGN6Uu"},{"balance":100,"name":"1001510","owner_address":"TPKq9bVZyM2sZ8XersMmXhy1NbjhdxRwwj"},{"balance":50,"name":"1001565","owner_address":"TKY7Vmq78b2c83fLXrPijkhQkk4EJtfViD"},{"balance":5,"name":"1001535"},{"balance":10,"name":"1000532","owner_address":"TGQwBNht8h3zev4gBtDMoQjWE2WJm1Zr9B"},{"balance":3,"name":"1001479","owner_address":"TC9FtB1EoiV3jfXgZvmqUmfeCmdWNmCxdY"},{"balance":13,"name":"1001090","owner_address":"TU1LUTYDMG6iihimUpAmdnnBthawPKh1cm","priceInTrx":0.004360},{"balance":200,"name":"1001759","owner_address":"TWKWWJAFBYyjvLtfqKCSeMyUW7TjWhkY4e"},{"balance":12,"name":"1000096","owner_address":"TSfjkVSKJGW4aybDQcxi4bpythU7WCXV3v"},{"balance":15,"name":"1001594"},{"balance":10,"name":"1001815","owner_address":"TB3iM1RsKXagV7hdz2QpWnaChptwrU3tCL"},{"balance":10,"name":"1001064","owner_address":"THnWV416C9mfJ1LFwopUjGXZEr1xFtAdrD"},{"balance":5192508733304578,"name":"1002000","owner_address":"TF5Bn4cJCT6GVeUgyCN4rBhDg42KBrpAjg","priceInTrx":0.018900},{"balance":7742069,"name":"1002037","owner_address":"TBekuTCZwPG2o88SmiS58VALkxBemoX4yS"},{"balance":585,"name":"1002001"},{"balance":5441,"name":"1002071","owner_address":"TS79aik831csqUnQgnqrKG6hov2iL8yPbD"},{"balance":80312957663126,"name":"1002072","owner_address":"TP6PtaBSMM6sfWtWWD9k77YHWGmh7K3Lae"},{"balance":520,"name":"1000451","owner_address":"THPXuypwcnWo4wi5KqFfuRjgjeT5khUDKF"},{"balance":10011237,"name":"1001953","owner_address":"TSyG9BdjsGE2GoHG9eeYKMns6zMQFDmbvS"},{"balance":5,"name":"1000562","owner_address":"TWqKTJ5JhyD7rsbbWzEvS5ZZD9Q5QPPvSH"},{"balance":50000000,"name":"1002099","owner_address":"TYWmiPERm9kWUcnduqaE5jxT7eeZxfn5SQ"},{"balance":625100,"name":"1001581","owner_address":"TNkRSKWP7VvdrisTwC8iNzUV6MRoEJh6xx"},{"balance":11000000,"name":"1002342","owner_address":"TUCd8NiBUuxrjz1kSrUbAg2JXu6o27Ukrq"},{"balance":7,"name":"1000322","owner_address":"TDGy2M9qWBepSHDEutWWxWd1JZfmAed3BP","priceInTrx":0.000422},{"balance":12,"name":"1001825","owner_address":"TPcUbNeYwwYqbX23w3sVf1X61cwpAfPK2T"},{"balance":1000,"name":"1002384","owner_address":"TFYuPxyjDTvH1TLm2phpzJFw7AhjCgu8xP"},{"balance":44444,"name":"1001132","owner_address":"TWDUanVdxEShjpbiX57ExztMCDy8vCFcHh"},{"balance":30000000,"name":"1002398","owner_address":"TUXSuMg41nJXm9TuDgF6EZWjEbP2vx1Hd4"},{"balance":10000060,"name":"1002116","owner_address":"TAEvo6MgLgV3A75L3cr3BAsLDJikWcAt3j"},{"balance":50000000,"name":"1002446","owner_address":"TJKf72NjL1cR49SHfDnPTXTFjRwjgr7v8Z"},{"balance":10000000,"name":"1002459","owner_address":"TNWy3mX85JsX2mPLgLc4cKJiWtJahhz3t3"},{"balance":1,"name":"1001079","owner_address":"TLQfc5EwZQqZc6jMNkMpxyJy5wucA6UX24"},{"balance":12345,"name":"1002467","owner_address":"TP429SKrsp4BoTiEFXHj4TNSJwqDFsygnr"},{"balance":1234,"name":"1002230","owner_address":"TWB9Q1JoB3fSLsahNq31gydRxYyWxDhSyk"},{"balance":10000000,"name":"1002288","owner_address":"TPzfpaaKUPgJPZ39YeyvBaTYNXBYpnhxDg"},{"balance":5,"name":"1002488","owner_address":"TMeAzhdgzu1sFMTsP75BffJ2tEzuGsYqR6"},{"balance":666,"name":"1002438","owner_address":"TMqNJwD3qVmuRxzzP3Q4A24fuByVBKQ39E"},{"balance":10000000,"name":"1002517","owner_address":"TP9m11ERHhE1qgDtL83c2AHHNkWvdUfKTz"},{"balance":10000000000,"name":"1002521","owner_address":"TJUwM4qk1et2nNKuESQ7UVHPjAHoRqAz3T"},{"balance":13699,"name":"1000157","owner_address":"TUahmv54ZiDnjQWG2VAeyMphebXQ4m6Hb5"},{"balance":65895,"name":"1002524","owner_address":"TRzZeBPt69utiWx1po5ghLH8uSP8uJGsa5"},{"balance":16,"name":"1000287","owner_address":"TFZCyZ18XNzMfEr6W5kLkGrs4HVmou9H3y"},{"balance":10000000,"name":"1002544","owner_address":"TQHBbjES5DNjDfDHBbpnh9qcDM7mVjSVcL"},{"balance":10000000000,"name":"1002551","owner_address":"TVrGxBCQkWjQ52D7S67UgFsUzcX4E8EsNB"},{"balance":10000000,"name":"1002573","owner_address":"TBfmGqmZtdEQNuYCz8s1izBUDxZbkPmMcj"},{"balance":10000000,"name":"1002552","owner_address":"TCxeAH2ajBqoWzqV9m5YiFTyeQ5FvzVqSH"},{"balance":1000000,"name":"1002578","owner_address":"TUjBG7C1CU7X75UmacnyrRTYLmbSeX7iDa"},{"balance":2555000,"name":"1002270","owner_address":"TMSpdYHCgZuxM7AjqKsjGMM1cpxraFuZGp"},{"balance":10000000,"name":"1002597","owner_address":"TDEBhgsdGTSzrgMsPDUQ1pt59fR6wWR7Rq"},{"balance":10000000,"name":"1002636","owner_address":"TKL54NcGXvBckkGbPjYzAmdwFs3usv8VY9"},{"balance":100000000,"name":"1002250","owner_address":"THUHfNqiYo4KS3GLM8MUU4x3wek9uPD47d"},{"balance":1000000,"name":"1002662","owner_address":"TEV5PJWga6crSeNLHmHaaco8fon6nm74wJ"},{"balance":10000000,"name":"1002672","owner_address":"TBHJCf3nymJPt1hVPjSJfH5ssJLdNMPepe"},{"balance":24120,"name":"1002657","owner_address":"TCKiVea721ycNAWonb2dpwr65AJkMiGSFb"},{"balance":1000000,"name":"1002683","owner_address":"TL6YggMQQ3YFEc41wesBMHZjDxcGpX3y5q"},{"balance":3000000,"name":"1002671","owner_address":"TDQ5q4Hf6UqR43Smp67sndMQfdTcGgP88s"},{"balance":20,"name":"1002577","owner_address":"TGZzci6a9wtcSiNekqYLP84ECRoaJ6pBwY"},{"balance":10000000,"name":"1002721","owner_address":"TUkUgsTTo74B9XG9da4d2NsaZqCKLNFwNS"},{"balance":10000,"name":"1002726","owner_address":"TRXw3Ggt3xs3fHbcoark1aeKwUZFKTYcsS"},{"balance":21092024781,"name":"1002263","owner_address":"TD5AwyiTNbKN9jQqyMzwQ6NLrWGbtAcotK"},{"balance":10000000,"name":"1002736","owner_address":"TBB19fMCf19wuiu5omtA1nAqALPpo4oa32"},{"balance":10000000,"name":"1002646","owner_address":"TRUnzvtzT6o35M4XHUvKr48yCZjw4dQyvp"},{"balance":7392000000,"name":"1002589","owner_address":"TUL9NhGQkRFLTRcHGkdoSniAeVaNPZGgot"},{"balance":10000000,"name":"1002742","owner_address":"TWfrNPVGDh1tyPVM79bfEASb7jw2bLbZPJ"},{"balance":8822711275000000,"name":"1002762","owner_address":"TRChSJM8TjQj7vvJCN9W8WBcfkJq2eBxgv"},{"balance":10000000,"name":"1002775"},{"balance":10000000,"name":"1002798","owner_address":"TBitZMK7YSUb2Q1Cm537D5iAZSJkaPdN9c"},{"balance":95,"name":"1001854","owner_address":"TSMeDkfmX6m1NZmDBrVtGPnACJCUWVkx4p"},{"balance":10000000,"name":"1002746","owner_address":"TQbbAyfcrKERXjUDf8TZfcdtjFQbCSgEfc"},{"balance":2000000,"name":"1002669","owner_address":"THhgpkHBdJDDWBPnZKRgzdvRr3qCtAa2cv"},{"balance":10000000,"name":"1002814","owner_address":"TNvq4y2A2beBENtcGknwhX6XHgk8hqgnVh"},{"balance":10000000,"name":"1002830","owner_address":"THLLMnsEKEci5e5dJHnW28QQU8AujGhSoK"},{"balance":10000000,"name":"1002845","owner_address":"TUzpDkzjWkZasA6Dx7nx5PPskMkCcNxVyQ"},{"balance":10000000,"name":"1002858","owner_address":"TRKJcugHJeffVpCAFGapZMwuH8HaTWjbof"},{"balance":200,"name":"1002454","owner_address":"TDCGkNf3XB3jRGg7bhFkNynkGw7q4kV3z9"},{"balance":10000000,"name":"1002876","owner_address":"TGqiinRV6nn8GbF5LX7zue4fpjstG1gVvu"},{"balance":20000000,"name":"1002881","owner_address":"TWpKN6y3NVXm5mMjGmPEtLpS6boGM4q8T4"},{"balance":350,"name":"1000145","owner_address":"TNFcvwJgvBRg2Dq5Qyx1gxcvqU3dwPyVNc"},{"balance":10000000,"name":"1002892","owner_address":"TECsVV1kTtx48sbdjvptq544h4H3Qqr24c"},{"balance":10000000,"name":"1002897","owner_address":"TPKqse19ALipJ1uBZHGWHzuTrQqZa4HtaM"},{"balance":2055000000,"name":"1002822","owner_address":"TURy9pFLskqTWgkZqUCUdPXkezZfYL76YQ"},{"balance":1000000,"name":"1002852","owner_address":"TUmad3hCqxu78n8GuULrdJMUB4qmTUYgv3"},{"balance":10000000,"name":"1002907","owner_address":"TKC9HMUXx3qLE7d19KWzWVjFxEcWQdSYK9"},{"balance":10000000,"name":"1002927","owner_address":"TAwRvFAqfB4bbzVCVPgGATZV5uMVs9UyVL"},{"balance":10000000,"name":"1002926","owner_address":"TF5jfDiQ3d7T5ihcBxeWS9S8xSR5tS738x"},{"balance":1000000,"name":"1002748","owner_address":"TTUAmhh9k2Yegf3TxZc86vG5E9kT24vgcw"},{"balance":189990000000,"name":"1002950","owner_address":"TNCZCGDPQ69ieJFsY1jZUohXmR46A4kM24"},{"balance":10,"name":"1000985","owner_address":"TRH5jmPx77UnMvfdvfo2m3FCkZVcBiFvqP"},{"balance":10000000,"name":"1002962","owner_address":"TFDwGwod9qopreRiirsFMwPzX4v2r662P4"},{"balance":10000000,"name":"1002918","owner_address":"TKGpTks1myPrJ9ZtEdLgpjvg1RMR2wGAFz"},{"balance":1000,"name":"1002608","owner_address":"TDPsSgBQznKEffdTMq3aspsvrmFfhL7ZcP"},{"balance":10000000,"name":"1002999","owner_address":"TTL52uBzTG7qorL7BQYdjGUY3HWWr9Kvao"},{"balance":100000000000,"name":"1003022","owner_address":"TAAJiJ1NgkEkE3w1PQk4dA8XH9rpfk5eVE"},{"balance":1000000000,"name":"1003041","owner_address":"TQADZoww5HstdsJM1GXwstqsRRnmrkThzY"},{"balance":10000000,"name":"1003049","owner_address":"THFJwSN5Z3zTc5TvkSiVh8m4kQMZaTMaqk"},{"balance":1,"name":"1002939","owner_address":"TAsSw8hUddYi8AN8EkDuAMS9r8pkriyUxs"}],"balances":[{"balance":346976329314696,"name":"_"},{"balance":1273,"name":"1000003"},{"balance":113,"name":"1000006"},{"balance":145,"name":"1000165"},{"balance":416,"name":"1000520"},{"balance":596,"name":"1000491"},{"balance":242,"name":"1000176","owner_address":"THG48yHsR6inxrCJk2hhxZPsFLq1ehP88V"},{"balance":62,"name":"1000542"},{"balance":53,"name":"1000494","owner_address":"TXJnVqqwLSNmdXDLWn1Yfjhe8aZH2oaAuq"},{"balance":56,"name":"1000493"},{"balance":599,"name":"1000744"},{"balance":628,"name":"1000746"},{"balance":234,"name":"1000743"},{"balance":113,"name":"1000396"},{"balance":206,"name":"1000745","owner_address":"TPCEi45wZQ1PPChUg5uqoK1D5kKnjCR8Li"},{"balance":61,"name":"1000821","owner_address":"TBm3Peu51gYwn2iPwNEDxc9vBMc3eRGUGu"},{"balance":25,"name":"1000541"},{"balance":7,"name":"1000278","owner_address":"TRMUimDekf9nDLuVMp6TKzcw4axNnajGJr"},{"balance":1,"name":"1000567","owner_address":"TFXJMhB4ZKBfcQWfCLbSyQGhonHXABaWku"},{"balance":1,"name":"1000856","owner_address":"TXf3X8YMdDho2xwA6QDbFZiTGPnk8ghfLm"},{"balance":30,"name":"1000884"},{"balance":1,"name":"1000894"},{"balance":200,"name":"1000181","owner_address":"TEmTbbvH5ZPJPZ8CbffjqonFRiAAFgfc9o"},{"balance":7,"name":"1000935","owner_address":"TPVkcFYTEi9Dia45AveiTcaYoaU9ux7xC7"},{"balance":1000,"name":"1000938","owner_address":"TNgkWTabK1rMWwgLjmLdsZbzYfGTx5Tpe9"},{"balance":10,"name":"1000017","owner_address":"TV6qcwSp38uESiDczxxb7zbJX1h2LfDs78"},{"balance":10,"name":"1001011","owner_address":"TNUbeTQXPtRXtBX3dJboVkhdhaiws29Aky"},{"balance":2,"name":"1001038","owner_address":"TFujVDp8U578L2AtsorYN3pwdXmH2HxbQv"},{"balance":100,"name":"1000983","owner_address":"TYmiZ7xCeqboiizb2jsjVQuRABXzVSjKFR"},{"balance":1,"name":"1001203","owner_address":"TBmaT8mcrdkrRL2Q6ur7grMYAcaGtfxsz7"},{"balance":1,"name":"1000190","owner_address":"TNXjXURue38Wa641pmqMH4vbJN1WZLKMnr"},{"balance":100,"name":"1001204"},{"balance":1000,"name":"1001230"},{"balance":1300000,"name":"1001301","owner_address":"TVgJEbc9NEYxVr1h6rJQiMqySePsJQDCA7"},{"balance":11,"name":"1000959"},{"balance":10,"name":"1001425"},{"balance":17,"name":"1001433","owner_address":"TWPMz6FPEAV6qP4VRMG3Y69ftEov1R7YWT"},{"balance":100,"name":"1001446"},{"balance":12,"name":"1001411","owner_address":"TPL6zNujtEQ8kp213n58UxAhGRCU3aozkc"},{"balance":12,"name":"1001467"},{"balance":100,"name":"1001414","owner_address":"TT43DgfxgMdR4BVZNua4YCwG34AgfGN6Uu"},{"balance":100,"name":"1001510","owner_address":"TPKq9bVZyM2sZ8XersMmXhy1NbjhdxRwwj"},{"balance":50,"name":"1001565","owner_address":"TKY7Vmq78b2c83fLXrPijkhQkk4EJtfViD"},{"balance":5,"name":"1001535"},{"balance":10,"name":"1000532","owner_address":"TGQwBNht8h3zev4gBtDMoQjWE2WJm1Zr9B"},{"balance":3,"name":"1001479","owner_address":"TC9FtB1EoiV3jfXgZvmqUmfeCmdWNmCxdY"},{"balance":13,"name":"1001090","owner_address":"TU1LUTYDMG6iihimUpAmdnnBthawPKh1cm","priceInTrx":0.004360},{"balance":200,"name":"1001759","owner_address":"TWKWWJAFBYyjvLtfqKCSeMyUW7TjWhkY4e"},{"balance":12,"name":"1000096","owner_address":"TSfjkVSKJGW4aybDQcxi4bpythU7WCXV3v"},{"balance":15,"name":"1001594"},{"balance":10,"name":"1001815","owner_address":"TB3iM1RsKXagV7hdz2QpWnaChptwrU3tCL"},{"balance":10,"name":"1001064","owner_address":"THnWV416C9mfJ1LFwopUjGXZEr1xFtAdrD"},{"balance":5192508733304578,"name":"1002000","owner_address":"TF5Bn4cJCT6GVeUgyCN4rBhDg42KBrpAjg","priceInTrx":0.018900},{"balance":7742069,"name":"1002037","owner_address":"TBekuTCZwPG2o88SmiS58VALkxBemoX4yS"},{"balance":585,"name":"1002001"},{"balance":5441,"name":"1002071","owner_address":"TS79aik831csqUnQgnqrKG6hov2iL8yPbD"},{"balance":80312957663126,"name":"1002072","owner_address":"TP6PtaBSMM6sfWtWWD9k77YHWGmh7K3Lae"},{"balance":520,"name":"1000451","owner_address":"THPXuypwcnWo4wi5KqFfuRjgjeT5khUDKF"},{"balance":10011237,"name":"1001953","owner_address":"TSyG9BdjsGE2GoHG9eeYKMns6zMQFDmbvS"},{"balance":5,"name":"1000562","owner_address":"TWqKTJ5JhyD7rsbbWzEvS5ZZD9Q5QPPvSH"},{"balance":50000000,"name":"1002099","owner_address":"TYWmiPERm9kWUcnduqaE5jxT7eeZxfn5SQ"},{"balance":625100,"name":"1001581","owner_address":"TNkRSKWP7VvdrisTwC8iNzUV6MRoEJh6xx"},{"balance":11000000,"name":"1002342","owner_address":"TUCd8NiBUuxrjz1kSrUbAg2JXu6o27Ukrq"},{"balance":7,"name":"1000322","owner_address":"TDGy2M9qWBepSHDEutWWxWd1JZfmAed3BP","priceInTrx":0.000422},{"balance":12,"name":"1001825","owner_address":"TPcUbNeYwwYqbX23w3sVf1X61cwpAfPK2T"},{"balance":1000,"name":"1002384","owner_address":"TFYuPxyjDTvH1TLm2phpzJFw7AhjCgu8xP"},{"balance":44444,"name":"1001132","owner_address":"TWDUanVdxEShjpbiX57ExztMCDy8vCFcHh"},{"balance":30000000,"name":"1002398","owner_address":"TUXSuMg41nJXm9TuDgF6EZWjEbP2vx1Hd4"},{"balance":10000060,"name":"1002116","owner_address":"TAEvo6MgLgV3A75L3cr3BAsLDJikWcAt3j"},{"balance":50000000,"name":"1002446","owner_address":"TJKf72NjL1cR49SHfDnPTXTFjRwjgr7v8Z"},{"balance":10000000,"name":"1002459","owner_address":"TNWy3mX85JsX2mPLgLc4cKJiWtJahhz3t3"},{"balance":1,"name":"1001079","owner_address":"TLQfc5EwZQqZc6jMNkMpxyJy5wucA6UX24"},{"balance":12345,"name":"1002467","owner_address":"TP429SKrsp4BoTiEFXHj4TNSJwqDFsygnr"},{"balance":1234,"name":"1002230","owner_address":"TWB9Q1JoB3fSLsahNq31gydRxYyWxDhSyk"},{"balance":10000000,"name":"1002288","owner_address":"TPzfpaaKUPgJPZ39YeyvBaTYNXBYpnhxDg"},{"balance":5,"name":"1002488","owner_address":"TMeAzhdgzu1sFMTsP75BffJ2tEzuGsYqR6"},{"balance":666,"name":"1002438","owner_address":"TMqNJwD3qVmuRxzzP3Q4A24fuByVBKQ39E"},{"balance":10000000,"name":"1002517","owner_address":"TP9m11ERHhE1qgDtL83c2AHHNkWvdUfKTz"},{"balance":10000000000,"name":"1002521","owner_address":"TJUwM4qk1et2nNKuESQ7UVHPjAHoRqAz3T"},{"balance":13699,"name":"1000157","owner_address":"TUahmv54ZiDnjQWG2VAeyMphebXQ4m6Hb5"},{"balance":65895,"name":"1002524","owner_address":"TRzZeBPt69utiWx1po5ghLH8uSP8uJGsa5"},{"balance":16,"name":"1000287","owner_address":"TFZCyZ18XNzMfEr6W5kLkGrs4HVmou9H3y"},{"balance":10000000,"name":"1002544","owner_address":"TQHBbjES5DNjDfDHBbpnh9qcDM7mVjSVcL"},{"balance":10000000000,"name":"1002551","owner_address":"TVrGxBCQkWjQ52D7S67UgFsUzcX4E8EsNB"},{"balance":10000000,"name":"1002573","owner_address":"TBfmGqmZtdEQNuYCz8s1izBUDxZbkPmMcj"},{"balance":10000000,"name":"1002552","owner_address":"TCxeAH2ajBqoWzqV9m5YiFTyeQ5FvzVqSH"},{"balance":1000000,"name":"1002578","owner_address":"TUjBG7C1CU7X75UmacnyrRTYLmbSeX7iDa"},{"balance":2555000,"name":"1002270","owner_address":"TMSpdYHCgZuxM7AjqKsjGMM1cpxraFuZGp"},{"balance":10000000,"name":"1002597","owner_address":"TDEBhgsdGTSzrgMsPDUQ1pt59fR6wWR7Rq"},{"balance":10000000,"name":"1002636","owner_address":"TKL54NcGXvBckkGbPjYzAmdwFs3usv8VY9"},{"balance":100000000,"name":"1002250","owner_address":"THUHfNqiYo4KS3GLM8MUU4x3wek9uPD47d"},{"balance":1000000,"name":"1002662","owner_address":"TEV5PJWga6crSeNLHmHaaco8fon6nm74wJ"},{"balance":10000000,"name":"1002672","owner_address":"TBHJCf3nymJPt1hVPjSJfH5ssJLdNMPepe"},{"balance":24120,"name":"1002657","owner_address":"TCKiVea721ycNAWonb2dpwr65AJkMiGSFb"},{"balance":1000000,"name":"1002683","owner_address":"TL6YggMQQ3YFEc41wesBMHZjDxcGpX3y5q"},{"balance":3000000,"name":"1002671","owner_address":"TDQ5q4Hf6UqR43Smp67sndMQfdTcGgP88s"},{"balance":20,"name":"1002577","owner_address":"TGZzci6a9wtcSiNekqYLP84ECRoaJ6pBwY"},{"balance":10000000,"name":"1002721","owner_address":"TUkUgsTTo74B9XG9da4d2NsaZqCKLNFwNS"},{"balance":10000,"name":"1002726","owner_address":"TRXw3Ggt3xs3fHbcoark1aeKwUZFKTYcsS"},{"balance":21092024781,"name":"1002263","owner_address":"TD5AwyiTNbKN9jQqyMzwQ6NLrWGbtAcotK"},{"balance":10000000,"name":"1002736","owner_address":"TBB19fMCf19wuiu5omtA1nAqALPpo4oa32"},{"balance":10000000,"name":"1002646","owner_address":"TRUnzvtzT6o35M4XHUvKr48yCZjw4dQyvp"},{"balance":7392000000,"name":"1002589","owner_address":"TUL9NhGQkRFLTRcHGkdoSniAeVaNPZGgot"},{"balance":10000000,"name":"1002742","owner_address":"TWfrNPVGDh1tyPVM79bfEASb7jw2bLbZPJ"},{"balance":8822711275000000,"name":"1002762","owner_address":"TRChSJM8TjQj7vvJCN9W8WBcfkJq2eBxgv"},{"balance":10000000,"name":"1002775"},{"balance":10000000,"name":"1002798","owner_address":"TBitZMK7YSUb2Q1Cm537D5iAZSJkaPdN9c"},{"balance":95,"name":"1001854","owner_address":"TSMeDkfmX6m1NZmDBrVtGPnACJCUWVkx4p"},{"balance":10000000,"name":"1002746","owner_address":"TQbbAyfcrKERXjUDf8TZfcdtjFQbCSgEfc"},{"balance":2000000,"name":"1002669","owner_address":"THhgpkHBdJDDWBPnZKRgzdvRr3qCtAa2cv"},{"balance":10000000,"name":"1002814","owner_address":"TNvq4y2A2beBENtcGknwhX6XHgk8hqgnVh"},{"balance":10000000,"name":"1002830","owner_address":"THLLMnsEKEci5e5dJHnW28QQU8AujGhSoK"},{"balance":10000000,"name":"1002845","owner_address":"TUzpDkzjWkZasA6Dx7nx5PPskMkCcNxVyQ"},{"balance":10000000,"name":"1002858","owner_address":"TRKJcugHJeffVpCAFGapZMwuH8HaTWjbof"},{"balance":200,"name":"1002454","owner_address":"TDCGkNf3XB3jRGg7bhFkNynkGw7q4kV3z9"},{"balance":10000000,"name":"1002876","owner_address":"TGqiinRV6nn8GbF5LX7zue4fpjstG1gVvu"},{"balance":20000000,"name":"1002881","owner_address":"TWpKN6y3NVXm5mMjGmPEtLpS6boGM4q8T4"},{"balance":350,"name":"1000145","owner_address":"TNFcvwJgvBRg2Dq5Qyx1gxcvqU3dwPyVNc"},{"balance":10000000,"name":"1002892","owner_address":"TECsVV1kTtx48sbdjvptq544h4H3Qqr24c"},{"balance":10000000,"name":"1002897","owner_address":"TPKqse19ALipJ1uBZHGWHzuTrQqZa4HtaM"},{"balance":2055000000,"name":"1002822","owner_address":"TURy9pFLskqTWgkZqUCUdPXkezZfYL76YQ"},{"balance":1000000,"name":"1002852","owner_address":"TUmad3hCqxu78n8GuULrdJMUB4qmTUYgv3"},{"balance":10000000,"name":"1002907","owner_address":"TKC9HMUXx3qLE7d19KWzWVjFxEcWQdSYK9"},{"balance":10000000,"name":"1002927","owner_address":"TAwRvFAqfB4bbzVCVPgGATZV5uMVs9UyVL"},{"balance":10000000,"name":"1002926","owner_address":"TF5jfDiQ3d7T5ihcBxeWS9S8xSR5tS738x"},{"balance":1000000,"name":"1002748","owner_address":"TTUAmhh9k2Yegf3TxZc86vG5E9kT24vgcw"},{"balance":189990000000,"name":"1002950","owner_address":"TNCZCGDPQ69ieJFsY1jZUohXmR46A4kM24"},{"balance":10,"name":"1000985","owner_address":"TRH5jmPx77UnMvfdvfo2m3FCkZVcBiFvqP"},{"balance":10000000,"name":"1002962","owner_address":"TFDwGwod9qopreRiirsFMwPzX4v2r662P4"},{"balance":10000000,"name":"1002918","owner_address":"TKGpTks1myPrJ9ZtEdLgpjvg1RMR2wGAFz"},{"balance":1000,"name":"1002608","owner_address":"TDPsSgBQznKEffdTMq3aspsvrmFfhL7ZcP"},{"balance":10000000,"name":"1002999","owner_address":"TTL52uBzTG7qorL7BQYdjGUY3HWWr9Kvao"},{"balance":100000000000,"name":"1003022","owner_address":"TAAJiJ1NgkEkE3w1PQk4dA8XH9rpfk5eVE"},{"balance":1000000000,"name":"1003041","owner_address":"TQADZoww5HstdsJM1GXwstqsRRnmrkThzY"},{"balance":10000000,"name":"1003049","owner_address":"THFJwSN5Z3zTc5TvkSiVh8m4kQMZaTMaqk"},{"balance":1,"name":"1002939","owner_address":"TAsSw8hUddYi8AN8EkDuAMS9r8pkriyUxs"}],"balance":346976329314696,"voteTotal":0,"name":"","delegated":{"sentDelegatedBandwidth":[],"sentDelegatedResource":[],"receivedDelegatedResource":[],"receivedDelegatedBandwidth":[]},"totalTransactionCount":508552,"representative":{"lastWithDrawTime":0,"allowance":0,"enabled":false,"url":""},"activePermissions":[]}` mockedTransactionsTrc20Response = `{"success":true,"meta":{"at":1592757126588,"page_size":20,"fingerprint":"2tmLC90HQEnpnJ02w3n","links":{"next":"https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D/transactions/trc20?fingerprint=2tmLC90HQEnpnJ02w3n"}},"data":[{"block_timestamp":1592757117000,"value":"500000000","type":"Transfer","transaction_id":"fb078403adfee637608c3906d9d21dd158611aba149b9993f43d0f292ce543a0","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","token_info":{"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","name":"Tether USD","symbol":"USDT","decimals":6},"_unconfirmed":true},{"block_timestamp":1592757066000,"value":"50000000","type":"Transfer","transaction_id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","token_info":{"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","name":"Tether USD","symbol":"USDT","decimals":6},"_unconfirmed":true},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","block_timestamp":1592757066000,"value":"50000000","type":"Transfer","transaction_id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV","block_timestamp":1592756784000,"value":"3988000000","type":"Transfer","transaction_id":"0b52a4ef9fb8c13fbfae2b8c3506333ec1d718f307062a15f170562818a01d0a","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am","block_timestamp":1592756763000,"value":"640990000","type":"Transfer","transaction_id":"19d2ec6174bf64beb1061475f6429cba03b64944a763686cc3551447d0e8d9d5","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756631000,"value":"1062000000","type":"Transfer","transaction_id":"efb7d44305759cfb189c9fd22720609a2ddeb7fbd7c8afe1dd8851342471da8d","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","block_timestamp":1592756610000,"value":"2000000","type":"Transfer","transaction_id":"48bd90dc3f12086178e65b9389caa8b3c74683937b86d4d61cdec77f0095994a","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R","block_timestamp":1592756589000,"value":"1000000000","type":"Transfer","transaction_id":"afd5ae7e2462c9cc899c7f730b90fd2a5e4c1315e836c92468b504ed85f0b798","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq","block_timestamp":1592756583000,"value":"21200000","type":"Transfer","transaction_id":"3d613031f4b2a0e19deeea030d1d18599b6d9799d2dd530005ead9712c6d219d","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5","block_timestamp":1592756583000,"value":"125000000","type":"Transfer","transaction_id":"cbe359c2574efbdc8fc6a892ffc54812837295067c9816d41734126c82d0c141","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC","block_timestamp":1592756583000,"value":"5277600000","type":"Transfer","transaction_id":"c87248b02a4caaa6f443c1b8c4d4588c8dd281a4687b73e6afecfba6741b50d8","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W","block_timestamp":1592756583000,"value":"485342000","type":"Transfer","transaction_id":"8584f1b6a70ead8232fed19bd653ba13e4c2a8befd070f4a9a06eca3a2e3e548","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr","block_timestamp":1592756583000,"value":"1000000000","type":"Transfer","transaction_id":"2b28b69e6747db68647acc3a62c45da5355b97acd8d2c260ee752aa9bd63a624","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x","block_timestamp":1592756583000,"value":"2000000000","type":"Transfer","transaction_id":"1da6576dec0bd303f56cbfb5712f782e0a56a8713cb661f8afd2f2533e5c6209","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK","block_timestamp":1592756583000,"value":"24216600000","type":"Transfer","transaction_id":"f9c86cce1873cb816d6cd8718e76df8839172add293bbc8d11a5f98c80f9e322","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756541000,"value":"8241997837","type":"Transfer","transaction_id":"75eb35734857daa79c38ef923a7e7eb2e3dfb23d2722762fd2b180651021643f","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756220000,"value":"18000000000","type":"Transfer","transaction_id":"adee73dadce006ff848ff30d8c5c41f033be2e5e1a8b875f6dbbaab524177d08","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592755962000,"value":"863399098","type":"Transfer","transaction_id":"3655a1156c9adcb876c6c9c9e0f5f1f39704ac4c7296fea05fedf5ca8f6b1a19","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ","block_timestamp":1592755740000,"value":"20000000","type":"Transfer","transaction_id":"03574741eb0016050a19f181e4acc4b20b70f41e11e63140c9556c31eae09fba","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug","block_timestamp":1592755722000,"value":"21161340000","type":"Transfer","transaction_id":"f3aa00595996e31dbe9528a3cb21bff987f333bf1f675420ba4fa2ad43c8205f","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}}]}` mockedTransactionsEmptyResponse = `{"success":true,"meta":{"at":1592757318961,"page_size":20,"fingerprint":"AYa6eBNpCs5E2DnumiJJJWJ3n2PYMBRFvU7BLjXD49Jm779DJ1C1hUgjwJAmQx5Y2BnkStKMjzQvcALKeQJYfW51m6sY7YEWW","links":{"next":"https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R/transactions?fingerprint=AYa6eBNpCs5E2DnumiJJJWJ3n2PYMBRFvU7BLjXD49Jm779DJ1C1hUgjwJAmQx5Y2BnkStKMjzQvcALKeQJYfW51m6sY7YEWW"}},"data":[]}` - mockedAsset1000542Response = `{"success":true,"meta":{"at":1592754266101,"page_size":1},"data":[{"id":"1000542","abbr":"FOM","description":"Fomo3D is a decentralized, trustless blockchain game.","name":"FomoThreeD","num":1,"total_supply":80000000000,"trx_num":1000000,"url":"https://fomo3d.games/","owner_address":"4134f1b9c19cf40f565661697eb47b0090ac779507","start_time":1534348821000,"end_time":1924876800000}]}` - mockedAsset1000567Response = `{"success":true,"meta":{"at":1592754347268,"page_size":1},"data":[{"id":"1000567","abbr":"os","description":"Open Decentralized Search Engine","frozen_supply":[{"frozen_amount":74000000000,"frozen_days":3652}],"name":"OtonamiS","num":100,"total_supply":99000000000,"trx_num":1000000,"url":"https://OtonamiS.com","owner_address":"413cea69143b5a5b1ff15d847a7e30e3bffa6a2247","start_time":1534773969000,"end_time":1566280800000}]}` + mockedAsset1000542Response = `{"success":true,"meta":{"at":1592754266101,"page_size":1},"data":[{"id":1000542,"abbr":"FOM","description":"Fomo3D is a decentralized, trustless blockchain game.","name":"FomoThreeD","num":1,"total_supply":80000000000,"trx_num":1000000,"url":"https://fomo3d.games/","owner_address":"4134f1b9c19cf40f565661697eb47b0090ac779507","start_time":1534348821000,"end_time":1924876800000}]}` + mockedAsset1000567Response = `{"success":true,"meta":{"at":1592754347268,"page_size":1},"data":[{"id":1000567,"abbr":"os","description":"Open Decentralized Search Engine","frozen_supply":[{"frozen_amount":74000000000,"frozen_days":3652}],"name":"OtonamiS","num":100,"total_supply":99000000000,"trx_num":1000000,"url":"https://OtonamiS.com","owner_address":"413cea69143b5a5b1ff15d847a7e30e3bffa6a2247","start_time":1534773969000,"end_time":1566280800000}]}` mockedAssetTR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6tResponse = `{"success":true,"meta":{"at":1592754347268,"page_size":1},"data":[]}` mockedAccountsResponse = `{"success":true,"meta":{"at":1592753781505,"page_size":1},"data":[{"account_resource":{"latest_consume_time_for_energy":1592753721000},"address":"4179309abcff2cf531070ca9222a1f72c4a5136874","asset":[{"key":"IPFS","value":1273},{"key":"TRXTestCoin","value":113},{"key":"Skypeople","value":145},{"key":"binance","value":416},{"key":"BitTorrent","value":596},{"key":"ofoBike","value":242},{"key":"FomoThreeD","value":62},{"key":"Durex","value":53},{"key":"Pornhub","value":56},{"key":"NBACoin","value":599},{"key":"HuobiToken","value":628},{"key":"MacCoin","value":234},{"key":"Messenger","value":113},{"key":"Bithumb","value":206},{"key":"James","value":61},{"key":"RingCoin","value":25},{"key":"DACC","value":7},{"key":"OtonamiS","value":1},{"key":"intrxChain","value":1},{"key":"TRONEX","value":30},{"key":"Petro","value":1},{"key":"KrMaToken","value":200},{"key":"KsumNole","value":7},{"key":"eFilingPlus","value":1000},{"key":"Tarquin","value":10},{"key":"KiloReX","value":10},{"key":"BESTCOIN","value":2},{"key":"Makememillionaire","value":100},{"key":"MedicCoin","value":1},{"key":"DMT","value":1},{"key":"MedIBlock","value":100},{"key":"ethereum","value":1000},{"key":"COLORBIKE","value":1300000},{"key":"WatsonAI","value":11},{"key":"Litcoin","value":10},{"key":"TronMatrixAI","value":17},{"key":"GoodKarma","value":100},{"key":"CryptoBankCoin","value":12},{"key":"EXODUS","value":12},{"key":"TRONO","value":100},{"key":"NMIToken","value":100},{"key":"Ton","value":50},{"key":"Twx","value":5},{"key":"TronLottery","value":10},{"key":"TronTokensGuardian","value":3},{"key":"TRONONE","value":13},{"key":"ELVIS","value":200},{"key":"URUNIT","value":12},{"key":"CRYPTYK","value":15},{"key":"TronRoyal","value":10}],"assetV2":[{"key":"1000542","value":62},{"key":"1000567","value":0}],"balance":346991703615806,"create_time":1535532969000,"free_asset_net_usageV2":[{"key":"1000542","value":0},{"key":"1000567","value":0}],"free_net_usage":4828,"latest_consume_free_time":1592751174000,"latest_opration_time":1592753721000,"trc20":[{"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9":"955973733483987848990056"},{"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7":"191543058623486"},{"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK":"100000000000000"},{"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t":"6849738905400"},{"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e":"5000000000"},{"TJSF4iVkzkRkYwEVNkqJkeGDaZpnFbGy9x":"500000000"},{"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm":"20000000"},{"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF":"175798"},{"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG":"20000"},{"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak":"1"}]}]}` ) diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index 2f7847311..df94fd065 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -70,7 +70,7 @@ func addTokenMeta(tx *blockatlas.Tx, srcTx Tx, tokenInfo AssetInfo) { tx.Meta = blockatlas.TokenTransfer{ Name: tokenInfo.Name, Symbol: strings.ToUpper(tokenInfo.Symbol), - TokenID: tokenInfo.ID, + TokenID: strconv.Itoa(int(tokenInfo.ID)), Decimals: tokenInfo.Decimals, Value: transfer.Amount, From: tx.From, diff --git a/platform/tron/transaction_test.go b/platform/tron/transaction_test.go index 843df2abd..eb8f39e6e 100644 --- a/platform/tron/transaction_test.go +++ b/platform/tron/transaction_test.go @@ -89,7 +89,7 @@ var tokenTransferDst = blockatlas.Tx{ }, } -var assetInfo = AssetInfo{Name: "BitTorrent", Symbol: "BTT", Decimals: 6, ID: "1002000"} +var assetInfo = AssetInfo{Name: "BitTorrent", Symbol: "BTT", Decimals: 6, ID: 1002000} type test struct { name string diff --git a/services/tokensearcher/api.go b/services/tokensearcher/api.go index 73cb29018..a0650dd27 100644 --- a/services/tokensearcher/api.go +++ b/services/tokensearcher/api.go @@ -156,7 +156,7 @@ func fetchAssetsByAddresses(tokenAPI blockatlas.TokensAPI, addresses []string, r defer tWg.Done() tokens, err := tokenAPI.GetTokenListByAddress(address) if err != nil { - log.Error("Chain: " + tokenAPI.Coin().Handle + " Address: " + address) + log.WithFields(log.Fields{"coin": tokenAPI.Coin().Handle, "address": address}).Error("Fetch GetTokenListByAddress", err) return } result.UpdateAssetsByAddress(tokens, int(tokenAPI.Coin().ID), address) From 4f8cda439b02857c653ff6857efe8819598135a7 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 1 Dec 2020 16:04:30 +0800 Subject: [PATCH 420/506] [Docs] Add features matrix (#1289) * add features matrix * remove wanchain (it's ethereum) * Add N/A info * add csv to readme, format markdown --- README.md | 92 +++++++++++++++++++++-------------------------- docs/features.csv | 29 +++++++++++++++ 2 files changed, 70 insertions(+), 51 deletions(-) create mode 100644 docs/features.csv diff --git a/README.md b/README.md index 3b00a0c65..25c9bcbf2 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ [![Go Report Card](https://goreportcard.com/badge/trustwallet/blockatlas)](https://goreportcard.com/report/TrustWallet/blockatlas) [![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=trustwallet/blockatlas)](https://dependabot.com) - > BlockAtlas is a clean explorer API and transaction observer for cryptocurrencies. BlockAtlas connects to nodes or explorer APIs of the supported coins and maps transaction data, @@ -17,51 +16,33 @@ The observer API watches the chain for new transactions and generates notificati #### Supported Coins - - - - - - - - - - - - - - - - - - - - - - +Block Atlas supports more than 25 blockchains: Bitcoin, Ethereum, Binance Chain etc, The full feature matrix is [here](docs/features.csv). ## Architecture #### NOTE + Currently Block Atlas is under active development and is not well documented. If you still want to run it on your own or help to contribute, **please** pay attention that currently integration, nemwan, functional tests are not working locally without all endpoints. We are fixing that issue and soon you will be able to test all the stuff locally Blockatlas allows to: -- Get information about transactions, tokens, staking details, collectibles for supported coins. -- Subscribe for price notifications via Rabbit MQ + +- Get information about transactions, tokens, staking details, collectibles for supported coins. +- Subscribe for price notifications via Rabbit MQ Platform API is independent service and can work with the specific blockchain only (like Bitcoin, Ethereum, etc) Notifications: -- Subscriber Producer - Create new blockatlas.SubscriptionEvent [Not implemented at Atlas, write it on your own] +- Subscriber Producer - Create new blockatlas.SubscriptionEvent [Not implemented at Atlas, write it on your own] -- Subscriber - Get subscriptions from queue, set them to the DB +- Subscriber - Get subscriptions from queue, set them to the DB -- Parser - Parse the block, convert block to the transactions batch, send to queue +- Parser - Parse the block, convert block to the transactions batch, send to queue -- Notifier - Check each transaction for having the same address as stored at DB, if so - send tx data and id to the next queue +- Notifier - Check each transaction for having the same address as stored at DB, if so - send tx data and id to the next queue + +- Notifier Consumer - Notify the user [Not implemented at Atlas, write it on your own] -- Notifier Consumer - Notify the user [Not implemented at Atlas, write it on your own] ``` New Subscriptions --(Rabbit MQ)--> Subscriber --> DB @@ -75,17 +56,19 @@ The whole flow is not available at Atlas repo. We will have integration tests wi ## Setup ### Prerequisite - * [Go Toolchain](https://golang.org/doc/install) versions 1.14+ - - Depends on what type of Blockatlas service you would like to run will also be needed. - * [Postgres](https://www.postgresql.org/download) to store user subscriptions and latest parsed block number - * [Rabbit MQ](https://www.rabbitmq.com/#getstarted) to pass subscriptions and send transaction notifications + +- [Go Toolchain](https://golang.org/doc/install) versions 1.14+ + + Depends on what type of Blockatlas service you would like to run will also be needed. +- [Postgres](https://www.postgresql.org/download) to store user subscriptions and latest parsed block number +- [Rabbit MQ](https://www.rabbitmq.com/#getstarted) to pass subscriptions and send transaction notifications ### Quick Start #### Get source code Download source to `GOPATH` + ```shell go get -u github.com/trustwallet/blockatlas cd $(go env GOPATH)/src/github.com/trustwallet/blockatlas @@ -112,12 +95,14 @@ go build -o subscriber-bin cmd/subscriber/main.go && ./subscriber-bin ### make command Build and start all services: + ```shell make go-build make start ``` Build and start individual service: + ```shell make go-build-api make start @@ -133,17 +118,20 @@ docker-compose up ``` Build and run individual service: + ```shell docker-compose build api docker-compose start api ``` ## Configuration + When any of Block Atlas services started they look up inside [default configuration](./config.yml). Most coins offering public RPC/explorer APIs are enabled, thus Block Atlas can be started and used right away, no additional configuration needed. By default starting any of the [services](#architecture) will enable all platforms To run a specific service only by passing environmental variable, e.g: `ATLAS_PLATFORM=ethereum` : + ```shell ATLAS_PLATFORM=ethereum go run cmd/api/main.go @@ -151,6 +139,7 @@ ATLAS_PLATFORM=ethereum binance bitcoin go run cmd/api/main.go # for multiple pl ``` or change in config file + ```yaml # Single platform: [ethereum] @@ -161,10 +150,12 @@ platform: [ethereum, binance, bitcoin] This way you can one platform per binary, for scalability and sustainability. To enable use of private endpoint: + ```yaml nimiq: api: http://localhost:8648 ``` + It works the same for worker - you can run all observer at 1 binary or 30 coins per 30 binaries #### Environment @@ -181,27 +172,25 @@ ATLAS_NIMIQ_API=http://localhost:8648 ## Tests ### Unit tests -``` -make test -``` + + make test + ### Mocked tests End-to-end tests with calls to external APIs has great value, but they are not suitable for regular CI verification, beacuse any external reason could break the tests. -``` -# Start API server with mocked config, at port 8437 ./ -go build -o api-bin cmd/api/main.go && ./api-bin -p 8437 -c configmock.yml -``` + # Start API server with mocked config, at port 8437 ./ + go build -o api-bin cmd/api/main.go && ./api-bin -p 8437 -c configmock.yml Therefore mocked API-level tests are used, whereby external APIs are replaced by mocks. -* External mocks are implemented as a simple, own, golang `mockserver`. It listens locally, and returns responses to specific API paths, taken from json data files. -* There is a file where API paths and corresponding data files are listed. -* Tests invoke into blockatlas through public APIs only, and are executed using *newman* (Postman cli -- `make newman-mocked`). -* Product code, and even test code should not be aware whether it runs with mocks or the real external endpoints. -* See Makefile for targets with 'mock'; platform can be started locally with mocks using `make start-platform-api-mock`. -* The newman tests can be executed with unmocked external APIs as well, but verifications may fail, because some APIs return variable responses. Unmocked tests are not intended for regular CI execution, but as ad-hoc development tests. -* General steps for creating new mocked tests: replace endpoint to localhost:3347, observe incoming calls (visible in mockserver's output), obtain real response from external API (with exact same parameters), place response in a file, add path + file to data file list. Restart mock, and verify that blockatlas provides correct output. Also, add verifications of results to the tests. +- External mocks are implemented as a simple, own, golang `mockserver`. It listens locally, and returns responses to specific API paths, taken from json data files. +- There is a file where API paths and corresponding data files are listed. +- Tests invoke into blockatlas through public APIs only, and are executed using _newman_ (Postman cli -- `make newman-mocked`). +- Product code, and even test code should not be aware whether it runs with mocks or the real external endpoints. +- See Makefile for targets with 'mock'; platform can be started locally with mocks using `make start-platform-api-mock`. +- The newman tests can be executed with unmocked external APIs as well, but verifications may fail, because some APIs return variable responses. Unmocked tests are not intended for regular CI execution, but as ad-hoc development tests. +- General steps for creating new mocked tests: replace endpoint to localhost:3347, observe incoming calls (visible in mockserver's output), obtain real response from external API (with exact same parameters), place response in a file, add path + file to data file list. Restart mock, and verify that blockatlas provides correct output. Also, add verifications of results to the tests. ## Docs @@ -217,15 +206,16 @@ brew install go-swagger ``` Render: + ```shell swagger serve docs/swagger.yaml ``` #### Updating Docs -- After creating a new route, add comments to your API source code, [See Declarative Comments Format](https://swaggo.github.io/swaggo.io/declarative_comments_format/). +- After creating a new route, add comments to your API source code, [See Declarative Comments Format](https://swaggo.github.io/swaggo.io/declarative_comments_format/). -- Run `$ make go-gen-docs` in root folder. +- Run `$ make go-gen-docs` in root folder. ## Contributing diff --git a/docs/features.csv b/docs/features.csv new file mode 100644 index 000000000..b9a04d4e7 --- /dev/null +++ b/docs/features.csv @@ -0,0 +1,29 @@ +Chain\API,Transaction list,Block parsing,Staking ,Token list,Collectiable +Bitcoin,✅,✅,N/A,N/A,N/A +Ethereum,✅,✅,,✅,✅ +ICON,✅,,N/A,N/A,N/A +Cosmos,✅,✅,✅,, +XRP,✅,✅,N/A,N/A,N/A +Stellar,✅,✅,N/A,,N/A +Nano,✅,,N/A,N/A,N/A +Tron,✅,✅,✅,✅, +FIO,✅,,N/A,N/A,N/A +Nimiq,✅,✅,N/A,N/A,N/A +Algorand,✅,✅,✅,,N/A +IoTeX,✅,✅,✅,N/A,N/A +Zilliqa,✅,✅,,N/A,N/A +Polkadot,✅,✅,,,N/A +Aion,✅,,,N/A,N/A +Aeternity,✅,,N/A,N/A,N/A +Kava,✅,✅,✅,, +Filecoin,,✅,N/A,N/A,N/A +Theta,✅,,N/A,N/A,N/A +Solana,,,✅,,N/A +Elrond,✅,✅,,N/A,N/A +BNB,✅,✅,,✅, +VeChain,✅,✅,N/A,N/A,N/A +Harmony,✅,✅,✅,N/A,N/A +Ontology,✅,✅,N/A,N/A,N/A +Tezos,✅,✅,✅,,N/A +Nebulas,✅,✅,N/A,N/A,N/A +Waves,✅,✅,,N/A,N/A From 65fedff668b65bd0d7a5191a3a880828ac27aa8f Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 1 Dec 2020 00:20:31 -0800 Subject: [PATCH 421/506] Remove deployment and simplify CI (#1291) * Remove deployment and simplify CI * Add extra logging * Delete Tiltfile * Update ci.yml --- .github/workflows/{pr-tests.yml => ci.yml} | 10 +- .github/workflows/master.yml | 138 ------------------ .github/workflows/pr-build.yml | 72 --------- Tiltfile | 27 ---- deployment/charts/blockatlas/.helmignore | 24 --- deployment/charts/blockatlas/Chart.yaml | 9 -- deployment/charts/blockatlas/app-readme.md | 8 - deployment/charts/blockatlas/questions.yml | 0 .../charts/blockatlas/templates/NOTES.txt | 0 .../charts/blockatlas/templates/_helpers.tpl | 52 ------- .../charts/blockatlas/templates/api.yaml | 92 ------------ .../charts/blockatlas/templates/configs.yaml | 13 -- .../charts/blockatlas/templates/consumer.yaml | 70 --------- .../charts/blockatlas/templates/ingress.yaml | 25 ---- .../charts/blockatlas/templates/parser.yaml | 75 ---------- .../charts/blockatlas/templates/postgres.yaml | 89 ----------- .../charts/blockatlas/templates/rabbitmq.yaml | 95 ------------ .../charts/blockatlas/templates/secrets.yaml | 19 --- .../charts/blockatlas/values.local.yaml | 8 - deployment/charts/blockatlas/values.prod.yaml | 40 ----- deployment/charts/blockatlas/values.yaml | 61 -------- services/notifier/base.go | 2 +- services/subscriber/tokens.go | 4 +- services/tokensearcher/tokensearcher.go | 4 +- 24 files changed, 11 insertions(+), 926 deletions(-) rename .github/workflows/{pr-tests.yml => ci.yml} (95%) delete mode 100644 .github/workflows/master.yml delete mode 100644 .github/workflows/pr-build.yml delete mode 100644 Tiltfile delete mode 100644 deployment/charts/blockatlas/.helmignore delete mode 100644 deployment/charts/blockatlas/Chart.yaml delete mode 100644 deployment/charts/blockatlas/app-readme.md delete mode 100644 deployment/charts/blockatlas/questions.yml delete mode 100644 deployment/charts/blockatlas/templates/NOTES.txt delete mode 100644 deployment/charts/blockatlas/templates/_helpers.tpl delete mode 100644 deployment/charts/blockatlas/templates/api.yaml delete mode 100644 deployment/charts/blockatlas/templates/configs.yaml delete mode 100644 deployment/charts/blockatlas/templates/consumer.yaml delete mode 100644 deployment/charts/blockatlas/templates/ingress.yaml delete mode 100644 deployment/charts/blockatlas/templates/parser.yaml delete mode 100644 deployment/charts/blockatlas/templates/postgres.yaml delete mode 100644 deployment/charts/blockatlas/templates/rabbitmq.yaml delete mode 100644 deployment/charts/blockatlas/templates/secrets.yaml delete mode 100644 deployment/charts/blockatlas/values.local.yaml delete mode 100644 deployment/charts/blockatlas/values.prod.yaml delete mode 100644 deployment/charts/blockatlas/values.yaml diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/ci.yml similarity index 95% rename from .github/workflows/pr-tests.yml rename to .github/workflows/ci.yml index 196b53885..73470d3de 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,8 @@ -name: Test +name: Tests on: + push: + branches: [ master ] pull_request: branches: [ master ] @@ -22,12 +24,12 @@ jobs: run: | go get -v -t -d ./... - - name: Lint - run: make lint - - name: Unit Test run: make test + - name: Lint + run: make lint + - name: Upload coverage run: bash <(curl -s https://codecov.io/bash) -f coverage.txt diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml deleted file mode 100644 index fd035a893..000000000 --- a/.github/workflows/master.yml +++ /dev/null @@ -1,138 +0,0 @@ -name: Master CI - -on: - push: - branches: [ master ] - -jobs: - test: - name: Unit Test - runs-on: ubuntu-latest - steps: - - name: Set up Go 1.x - uses: actions/setup-go@v2 - with: - go-version: ^1.13 - id: go - - - name: Check out code - uses: actions/checkout@v2 - - - name: Get dependencies - run: | - go get -v -t -d ./... - - - name: Lint - run: make lint - - - name: Swagger - run: make swag - - - name: Build - run: make go-build - - - name: Unit Test - run: make test - - - name: Upload coverage - run: bash <(curl -s https://codecov.io/bash) -f coverage.txt - - integration: - name: Integration Test - runs-on: ubuntu-latest - steps: - - name: Set up Go 1.x - uses: actions/setup-go@v2 - with: - go-version: ^1.13 - id: go - - - name: Check out code - uses: actions/checkout@v2 - - - name: Get dependencies - run: | - go get -v -t -d ./... - - - name: Integration Test - run: make integration - - build: - name: Build - runs-on: ubuntu-latest - steps: - - name: Set up Go 1.x - uses: actions/setup-go@v2 - with: - go-version: ^1.13 - id: go - - - name: Check out code into the Go module directory - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} - - - name: Get short commit hash - id: hash - run: echo "::set-output name=sha7::$(echo $(git rev-parse --short HEAD) | cut -c1-7)" - - - name: Show short hash - run: | - echo ${{ steps.hash.outputs.sha7 }} - - - name: Get dependencies - run: | - go get -v -t -d ./... - - - name: Swagger - run: make swag - - - name: Build - run: make go-build - - - name: Check user permission - id: check_for_build - uses: scherermichael-oss/action-has-permission@master - with: - required-permission: write - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Login to DockerHub Registry - if: steps.check_for_build.outputs.has-permission - run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin - - - name: Docker Build & Push Release Images - if: steps.check_for_build.outputs.has-permission - env: - API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} - PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} - CONSUMER_IMAGE: ${{ secrets.REGISTRY }}:consumer-${{ steps.hash.outputs.sha7 }} - run: | - docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . - docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . - docker build --build-arg SERVICE=consumer/consumer -f Dockerfile.runner -t $CONSUMER_IMAGE . - docker push $API_IMAGE - docker push $PARSER_IMAGE - docker push $CONSUMER_IMAGE - - deploy: - name: CD - runs-on: ubuntu-latest - needs: [ test, integration, build ] - steps: - - name: Check user permission - id: check_for_deploy - uses: scherermichael-oss/action-has-permission@master - with: - required-permission: write - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: CD Trigger - if: github.ref == 'refs/heads/master' && steps.check_for_deploy.outputs.has-permission - uses: Azure/pipelines@releases/v1 - with: - azure-devops-project-url: 'https://dev.azure.com/TrustWallet/Trust%20BlockAtlas' - azure-pipeline-name: 'AutomaticCD' - azure-devops-token: '${{ secrets.AZURE_DEVOPS_TOKEN }}' diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml deleted file mode 100644 index 780598632..000000000 --- a/.github/workflows/pr-build.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Build - -on: - pull_request: - branches: [ master ] - -jobs: - build: - name: Build - runs-on: ubuntu-latest - steps: - - name: Check user permission - id: check - uses: scherermichael-oss/action-has-permission@master - with: - required-permission: write - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up Go 1.x - if: steps.check.outputs.has-permission - uses: actions/setup-go@v2 - with: - go-version: ^1.13 - id: go - - - name: Check out code into the Go module directory - if: steps.check.outputs.has-permission - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} - - - name: Get short commit hash - if: steps.check.outputs.has-permission - id: hash - run: echo "::set-output name=sha7::$(echo $(git rev-parse --short HEAD) | cut -c1-7)" - - - name: Show short hash - if: steps.check.outputs.has-permission - run: | - echo ${{ steps.hash.outputs.sha7 }} - - - name: Get dependencies - if: steps.check.outputs.has-permission - run: | - go get -v -t -d ./... - - - name: Swagger - if: steps.check.outputs.has-permission - run: make swag - - - name: Build - if: steps.check.outputs.has-permission - run: make go-build - - - name: Login to DockerHub Registry - if: steps.check.outputs.has-permission - run: echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin - - - name: Docker Build & Push Release Images - if: steps.check.outputs.has-permission - env: - API_IMAGE: ${{ secrets.REGISTRY }}:api-${{ steps.hash.outputs.sha7 }} - PARSER_IMAGE: ${{ secrets.REGISTRY }}:parser-${{ steps.hash.outputs.sha7 }} - CONSUMER_IMAGE: ${{ secrets.REGISTRY }}:consumer-${{ steps.hash.outputs.sha7 }} - run: | - docker build --build-arg SERVICE=api/api -f Dockerfile.runner -t $API_IMAGE . - docker build --build-arg SERVICE=parser/parser -f Dockerfile.runner -t $PARSER_IMAGE . - docker build --build-arg SERVICE=consumer/consumer -f Dockerfile.runner -t $CONSUMER_IMAGE . - docker push $API_IMAGE - docker push $PARSER_IMAGE - docker push $CONSUMER_IMAGE diff --git a/Tiltfile b/Tiltfile deleted file mode 100644 index 068ea08e1..000000000 --- a/Tiltfile +++ /dev/null @@ -1,27 +0,0 @@ -# -*- mode: Python -*- - -local_resource( - 'lint+tests', - 'make go-lint && make go-test && go-integration', - trigger_mode=TRIGGER_MODE_MANUAL, auto_init=False -) - -docker_build("trust/blockatlas:api-local", ".", build_args={"SERVICE":"api"}) -docker_build("trust/blockatlas:parser-local", ".", build_args={"SERVICE":"parser"}) -docker_build("trust/blockatlas:consumer-local", ".", build_args={"SERVICE":"consumer"}) - -yaml = helm( - 'deployment/charts/blockatlas', - name='local', - namespace='tilt-blockatlas-local', - values=['./deployment/charts/blockatlas/values.local.yaml'] -) - -# k8s namespace bootstrap -local('kubectl create namespace tilt-blockatlas-local || echo 1') - -k8s_yaml(yaml) -k8s_resource('api', port_forwards=8420) - -k8s_resource('postgres', port_forwards=8586) -k8s_resource('rabbitmq', port_forwards='9596:15672') diff --git a/deployment/charts/blockatlas/.helmignore b/deployment/charts/blockatlas/.helmignore deleted file mode 100644 index 2d0e3933a..000000000 --- a/deployment/charts/blockatlas/.helmignore +++ /dev/null @@ -1,24 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -values.local.yaml -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/deployment/charts/blockatlas/Chart.yaml b/deployment/charts/blockatlas/Chart.yaml deleted file mode 100644 index 3994fd8ad..000000000 --- a/deployment/charts/blockatlas/Chart.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v2 -name: blockatlas -description: A Blockatlas chart for Kubernetes - -type: application - -version: 0.1.0 - -appVersion: 2 diff --git a/deployment/charts/blockatlas/app-readme.md b/deployment/charts/blockatlas/app-readme.md deleted file mode 100644 index 876bcde2b..000000000 --- a/deployment/charts/blockatlas/app-readme.md +++ /dev/null @@ -1,8 +0,0 @@ -### blockatlas Chart - -# Local development with Tilt - -1. Install [Tilt](https://docs.tilt.dev/install.html) -2. Install [Docker+Kubernetes](https://docs.docker.com/docker-for-mac/#kubernetes) -3. Install [Helm3](https://helm.sh/docs/intro/install/) -4. Run tilt with `tilt up` \ No newline at end of file diff --git a/deployment/charts/blockatlas/questions.yml b/deployment/charts/blockatlas/questions.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/deployment/charts/blockatlas/templates/NOTES.txt b/deployment/charts/blockatlas/templates/NOTES.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/deployment/charts/blockatlas/templates/_helpers.tpl b/deployment/charts/blockatlas/templates/_helpers.tpl deleted file mode 100644 index 4bbce4c18..000000000 --- a/deployment/charts/blockatlas/templates/_helpers.tpl +++ /dev/null @@ -1,52 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "blockatlas.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "blockatlas.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "blockatlas.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "blockatlas.labels" -}} -helm.sh/chart: {{ include "blockatlas.chart" . }} -{{ include "blockatlas.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "blockatlas.selectorLabels" -}} -app.kubernetes.io/name: {{ include "blockatlas.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} diff --git a/deployment/charts/blockatlas/templates/api.yaml b/deployment/charts/blockatlas/templates/api.yaml deleted file mode 100644 index 596207185..000000000 --- a/deployment/charts/blockatlas/templates/api.yaml +++ /dev/null @@ -1,92 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: api - namespace: {{ .Release.Namespace }} - labels: - app: api - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: {{ .Values.apiReplicaCount }} - selector: - matchLabels: - name: api - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - type: RollingUpdate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - name: api - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-api - - name: PLATFORM - value: all - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:api-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: api - ports: - - containerPort: 8420 - name: http - protocol: TCP - resources: - {{- toYaml .Values.apiResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} ---- -apiVersion: v1 -kind: Service -metadata: - name: api - namespace: {{ .Release.Namespace }} - labels: - {{- include "blockatlas.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: 8420 - protocol: TCP - name: http - selector: - name: api \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/configs.yaml b/deployment/charts/blockatlas/templates/configs.yaml deleted file mode 100644 index 5d297cc6f..000000000 --- a/deployment/charts/blockatlas/templates/configs.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- if .Values.config.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: configs - namespace: {{ .Release.Namespace }} -data: - {{- range $k, $v := .Values.configs }} - {{- range $kk, $vv := $v }} - {{ $kk }}: {{ $vv | quote }} - {{- end }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/consumer.yaml b/deployment/charts/blockatlas/templates/consumer.yaml deleted file mode 100644 index ad01eae99..000000000 --- a/deployment/charts/blockatlas/templates/consumer.yaml +++ /dev/null @@ -1,70 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: consumer - namespace: {{ .Release.Namespace }} - labels: - app: consumer - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: {{ .Values.consumerReplicaCount }} - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - type: RollingUpdate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-consumer - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:consumer-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: consumer - resources: - {{- toYaml .Values.consumerResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/ingress.yaml b/deployment/charts/blockatlas/templates/ingress.yaml deleted file mode 100644 index da403232b..000000000 --- a/deployment/charts/blockatlas/templates/ingress.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- if .Values.ingress.enabled -}} -{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1beta1 -{{- else -}} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: api - namespace: {{ .Release.Namespace }} - labels: - chart: {{ template "blockatlas.chart" . }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - rules: - - host: {{ .Values.ingress.proxyHost | quote }} - http: - paths: - - blockatlas: - serviceName: api - servicePort: 8420 -{{- end }} diff --git a/deployment/charts/blockatlas/templates/parser.yaml b/deployment/charts/blockatlas/templates/parser.yaml deleted file mode 100644 index 047ebcd42..000000000 --- a/deployment/charts/blockatlas/templates/parser.yaml +++ /dev/null @@ -1,75 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: parser - namespace: {{ .Release.Namespace }} - labels: - app: parser - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "blockatlas.selectorLabels" . | nindent 6 }} - strategy: - type: Recreate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "blockatlas.selectorLabels" . | nindent 8 }} - spec: - containers: - - env: - - name: ELASTIC_APM_SERVICE_NAME - value: blockatlas-parser - - name: OBSERVER_BACKLOG_MAX_BLOCKS - value: "50" - - name: OBSERVER_BLOCK_POLL_MIN - value: 7s - - name: OBSERVER_FETCH_BLOCKS_INTERVAL - value: 100ms - - name: PLATFORM - value: all - envFrom: - - secretRef: - name: secrets - optional: false - - configMapRef: - name: configs - optional: false - image: "{{ .Values.image.repository }}:parser-{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: parser - resources: - {{- toYaml .Values.parserResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/postgres.yaml b/deployment/charts/blockatlas/templates/postgres.yaml deleted file mode 100644 index 3fc0f4776..000000000 --- a/deployment/charts/blockatlas/templates/postgres.yaml +++ /dev/null @@ -1,89 +0,0 @@ -{{- if .Values.posgtres.enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: postgres - namespace: {{ .Release.Namespace }} - labels: - app: postgres - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - name: postgres - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - type: RollingUpdate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - name: postgres - spec: - containers: - - env: - - name: POSTGRES_USER - value: user - - name: POSTGRES_PASSWORD - value: pass - - name: POSTGRES_DB - value: blockatlas - image: postgres - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: postgres - ports: - - containerPort: 5432 - name: 5432tcp - protocol: TCP - resources: - {{- toYaml .Values.postgresResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} ---- -apiVersion: v1 -kind: Service -metadata: - name: postgres - namespace: {{ .Release.Namespace }} - labels: - {{- include "blockatlas.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: 5432 - protocol: TCP - name: postgres - selector: - name: postgres -{{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/rabbitmq.yaml b/deployment/charts/blockatlas/templates/rabbitmq.yaml deleted file mode 100644 index 2d64babff..000000000 --- a/deployment/charts/blockatlas/templates/rabbitmq.yaml +++ /dev/null @@ -1,95 +0,0 @@ -{{- if .Values.rabbitmq.enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: rabbitmq - namespace: {{ .Release.Namespace }} - labels: - app: rabbitmq - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -spec: - replicas: 1 - selector: - matchLabels: - name: rabbitmq - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - type: RollingUpdate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - name: rabbitmq - spec: - containers: - - env: - - name: RABBITMQ_DEFAULT_PASS - value: lV7zO3lD - - name: RABBITMQ_DEFAULT_USER - value: user - - name: RABBITMQ_ERLANG_COOKIE - value: someStrongCookie - image: rabbitmq:3-management - imagePullPolicy: {{ .Values.image.pullPolicy }} - name: rabbitmq - ports: - - containerPort: 5672 - name: rabbitmq - protocol: TCP - - containerPort: 15672 - name: ui - protocol: TCP - resources: - {{- toYaml .Values.rabbitmqResources | nindent 12 }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - restartPolicy: Always - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} ---- -apiVersion: v1 -kind: Service -metadata: - name: rabbitmq - namespace: {{ .Release.Namespace }} - labels: - {{- include "blockatlas.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: 5672 - protocol: TCP - name: rabbitmq - - port: 15672 - protocol: TCP - name: ui - selector: - name: rabbitmq -{{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/templates/secrets.yaml b/deployment/charts/blockatlas/templates/secrets.yaml deleted file mode 100644 index 8cdfa93b2..000000000 --- a/deployment/charts/blockatlas/templates/secrets.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if .Values.secret.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: secrets - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "blockatlas.name" . }} - chart: {{ template "blockatlas.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -type: Opaque -data: - {{- range $k, $v := .Values.secrets }} - {{- range $kk, $vv := $v }} - {{ $kk }}: {{ $vv | b64enc }} - {{- end }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/deployment/charts/blockatlas/values.local.yaml b/deployment/charts/blockatlas/values.local.yaml deleted file mode 100644 index 1cfc53324..000000000 --- a/deployment/charts/blockatlas/values.local.yaml +++ /dev/null @@ -1,8 +0,0 @@ -image: - repository: trust/blockatlas - tag: local - -secrets: - - OBSERVER_RABBITMQ_URL: amqp://user:lV7zO3lD@rabbitmq:5672 - - POSTGRES_URL: postgresql://user:pass@postgres/blockatlas?sslmode=disable - - POSTGRES_READ_URL: postgresql://user:pass@postgres/blockatlas?sslmode=disable \ No newline at end of file diff --git a/deployment/charts/blockatlas/values.prod.yaml b/deployment/charts/blockatlas/values.prod.yaml deleted file mode 100644 index 8106da3b9..000000000 --- a/deployment/charts/blockatlas/values.prod.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# scaling -apiReplicaCount: 5 -consumerReplicaCount: 5 - -image: - repository: repositoryToReplace - tag: tagToReplace - -posgtres: - enabled: false -rabbitmq: - enabled: false -config: - enabled: false -secret: - enabled: false - -apiResources: - limits: - cpu: 300m - memory: 400Mi - requests: - cpu: 300m - memory: 400Mi - -consumerResources: - limits: - cpu: 300m - memory: 400Mi - requests: - cpu: 300m - memory: 400Mi - -parserResources: - limits: - cpu: 300m - memory: 1000Mi - requests: - cpu: 300m - memory: 1000Mi \ No newline at end of file diff --git a/deployment/charts/blockatlas/values.yaml b/deployment/charts/blockatlas/values.yaml deleted file mode 100644 index 6774dd9ed..000000000 --- a/deployment/charts/blockatlas/values.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# scaling -apiReplicaCount: 1 -consumerReplicaCount: 1 - -image: - repository: repositoryToReplace - pullPolicy: IfNotPresent - tag: tagToReplace - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -# Enable postgres-test deployment. If disabled - provide external postgres connection string. -posgtres: - enabled: true -# Enable rabbitmq-test deployment. If disabled - provide external rabbitmq connection string. -rabbitmq: - enabled: true -# Enable ConfigMap deployment generation. Disable if you need to manually create the ConfigMap later. -config: - enabled: true -# Enable Secret deployment generation. Disable if you need to manually create the Secret later. -secret: - enabled: true - -service: - type: ClusterIP - -ingress: - annotations: - kubernetes.io/ingress.class: nginx - enabled: false - swaggerHost: nginx-swagger.local - proxyHost: nginx-proxy.local - -# Resources request/limit example -# someResources: -# limits: -# cpu: 100m -# memory: 128Mi -# requests: -# cpu: 100m -# memory: 128Mi - -apiResources: {} -postgresResources: {} -rabbitmqResources: {} -consumerResources: {} -parserResources: {} - -nodeSelector: {} -tolerations: [] -affinity: {} - -podAnnotations: {} -podSecurityContext: {} -securityContext: {} - -configs: [] -secrets: [] \ No newline at end of file diff --git a/services/notifier/base.go b/services/notifier/base.go index e1912f06c..2b57ce739 100644 --- a/services/notifier/base.go +++ b/services/notifier/base.go @@ -26,7 +26,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { defer func() { if err := delivery.Ack(false); err != nil { - log.Error(err) + log.WithFields(log.Fields{"service": Notifier}).Error(err) } }() diff --git a/services/subscriber/tokens.go b/services/subscriber/tokens.go index 1fbe15e37..b4692ee80 100644 --- a/services/subscriber/tokens.go +++ b/services/subscriber/tokens.go @@ -20,7 +20,7 @@ func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { event := make(map[string][]models.Asset) if err := json.Unmarshal(delivery.Body, &event); err != nil { if err := delivery.Ack(false); err != nil { - log.Fatal(err, err) + log.WithFields(log.Fields{"service": Tokens}).Error(err) } } @@ -31,7 +31,7 @@ func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { } log.WithFields(log.Fields{"service": Tokens, "count": len(event)}).Info("Subscribed") if err := delivery.Ack(false); err != nil { - log.Fatal(err, err) + log.WithFields(log.Fields{"service": Tokens}).Error(err) } log.Info("------------------------------------------------------------") } diff --git a/services/tokensearcher/tokensearcher.go b/services/tokensearcher/tokensearcher.go index 28efee99c..73734667d 100644 --- a/services/tokensearcher/tokensearcher.go +++ b/services/tokensearcher/tokensearcher.go @@ -21,7 +21,7 @@ func Run(database *db.Instance, delivery amqp.Delivery) { if err != nil { log.Error("failed to get transactions", err) if err := delivery.Ack(false); err != nil { - log.Error(err) + log.WithFields(log.Fields{"service": TokenSearcher}).Error(err) } } if len(txs) == 0 { @@ -55,7 +55,7 @@ func Run(database *db.Instance, delivery amqp.Delivery) { } if err := delivery.Ack(false); err != nil { - log.Error(err) + log.WithFields(log.Fields{"service": TokenSearcher}).Error(err) } log.Info("------------------------------------------------------------") } From bd878b7e7dd6a0c6fafa20257d43baa1f0bcd3fd Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 4 Dec 2020 17:30:12 +0800 Subject: [PATCH 422/506] [Polkadot] Adopt subscan api change (#1296) * adopt subscan api change * remove KSM from config --- config.yml | 3 - platform/platform.go | 1 - platform/polkadot/model.go | 8 +-- platform/polkadot/transaction.go | 61 ++++++++----------- platform/polkadot/transaction_test.go | 87 +++++++++++++++++++++------ 5 files changed, 98 insertions(+), 62 deletions(-) diff --git a/config.yml b/config.yml index 28ef7bba2..a8a08d5ee 100644 --- a/config.yml +++ b/config.yml @@ -207,9 +207,6 @@ harmony: kava: api: https://kava.data.kava.io -kusama: - api: https://kusama.subscan.io/api - polkadot: api: https://polkadot.subscan.io/api diff --git a/platform/platform.go b/platform/platform.go index 066042c0d..5d80e11bc 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -67,7 +67,6 @@ func getAllHandlers() blockatlas.Platforms { coin.Tezos().Handle: tezos.Init(config.Default.Tezos.API, config.Default.Tezos.RPC), 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.Kusama().Handle: polkadot.Init(coin.KSM, config.Default.Kusama.API), coin.Polkadot().Handle: polkadot.Init(coin.DOT, config.Default.Polkadot.API), coin.Stellar().Handle: stellar.Init(coin.XLM, config.Default.Stellar.API), coin.Kin().Handle: stellar.Init(coin.KIN, config.Default.Kin.API), diff --git a/platform/polkadot/model.go b/platform/polkadot/model.go index 0fdfec36a..0973f4ffc 100644 --- a/platform/polkadot/model.go +++ b/platform/polkadot/model.go @@ -30,13 +30,13 @@ type Extrinsic struct { Nonce uint64 `json:"nonce"` Hash string `json:"extrinsic_hash"` Success bool `json:"success"` + Fee string `json:"fee"` } type CallData struct { - Name string `json:"name"` - Type string `json:"type"` - Value interface{} `json:"value"` - ValueRaw string `json:"valueRaw"` + Name string `json:"name"` + Type string `json:"type"` + Value string `json:"value"` } type TransfersRequest struct { diff --git a/platform/polkadot/transaction.go b/platform/polkadot/transaction.go index 94b702345..76d8f59e7 100644 --- a/platform/polkadot/transaction.go +++ b/platform/polkadot/transaction.go @@ -3,7 +3,6 @@ package polkadot import ( "encoding/hex" "encoding/json" - "fmt" "strings" "github.com/trustwallet/golibs/numbers" @@ -74,54 +73,44 @@ func (p *Platform) NormalizeExtrinsic(srcTx *Extrinsic) *blockatlas.Tx { return nil } - var status blockatlas.Status + // only supports balances::transfer + if srcTx.CallModule != ModuleBalances || srcTx.CallModuleFunction != ModuleFunctionTransfer { + return nil + } + + // check data types + if len(datas) < 2 || datas[0].Type != "Address" || datas[1].Type != "Compact" { + return nil + } + + to := p.NormalizeAddress(datas[0].Value) + if len(to) == 0 { + return nil + } + + status := blockatlas.StatusCompleted if !srcTx.Success { status = blockatlas.StatusError - } else { - status = blockatlas.StatusCompleted } result := blockatlas.Tx{ ID: srcTx.Hash, Coin: p.Coin().ID, + From: srcTx.AccountId, + To: to, + Fee: blockatlas.Amount(srcTx.Fee), Date: int64(srcTx.Timestamp), Block: srcTx.BlockNumber, Status: status, Sequence: srcTx.Nonce, - } - - if len(datas) < 2 { - return nil - } - value := "0" - to := "" - for _, data := range datas { - vf, ok := data.Value.(float64) - if ok { - value = fmt.Sprintf("%.0f", vf) - continue - } - toAddr := p.NormalizeAddress(data.ValueRaw) - if len(toAddr) > 0 { - to = toAddr - } - } - decimals := p.Coin().Decimals - if srcTx.CallModule == ModuleBalances && - srcTx.CallModuleFunction == ModuleFunctionTransfer { - result.From = srcTx.AccountId - result.To = to - result.Fee = blockatlas.Amount(FeeTransfer) - result.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(value), + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount(datas[1].Value), Symbol: p.Coin().Symbol, - Decimals: decimals, - } - } else { - // not supported yet - return nil + Decimals: p.Coin().Decimals, + }, } + return &result } @@ -131,7 +120,7 @@ func (p *Platform) NormalizeAddress(valueRaw string) string { return "" } if network, ok := NetworkByteMap[p.Coin().Symbol]; ok && len(bytes) > 0 { - return PublicKeyToAddress(bytes[1:], network) + return PublicKeyToAddress(bytes[:], network) } return "" } diff --git a/platform/polkadot/transaction_test.go b/platform/polkadot/transaction_test.go index 95e0a8e42..7055ef75e 100644 --- a/platform/polkadot/transaction_test.go +++ b/platform/polkadot/transaction_test.go @@ -89,9 +89,9 @@ func TestNormalizeTransfer(t *testing.T) { } func TestNormalizeExtrinsic(t *testing.T) { - platform := Platform{CoinIndex: coin.KSM} type args struct { - srcTx *Extrinsic + platform Platform + srcTx *Extrinsic } tests := []struct { name string @@ -99,29 +99,32 @@ func TestNormalizeExtrinsic(t *testing.T) { wantTx *blockatlas.Tx }{ { - name: "Transfer", + name: "Transfer KSM", args: args{ + platform: Platform{CoinIndex: coin.KSM}, srcTx: &Extrinsic{ Timestamp: 1577176992, BlockNumber: 360298, CallModuleFunction: "transfer", CallModule: "balances", - Params: "[{\"name\":\"dest\",\"type\":\"Address\",\"value\":\"CtwdfrhECFs3FpvCGoiE4hwRC4UsSiM8WL899HjRdQbfYZY\",\"valueRaw\":\"ff0e33fdfb980e4499e5c3576e742a563b6a4fc0f6f598b1917fd7a6fe393ffc72\"},{\"name\":\"value\",\"type\":\"Compact\\u003cBalance\\u003e\",\"value\":10000000000,\"valueRaw\":\"0700e40b5402\"}]", + Params: "[{\"name\":\"dest\",\"type\":\"Address\",\"value\":\"0e33fdfb980e4499e5c3576e742a563b6a4fc0f6f598b1917fd7a6fe393ffc72\",\"value_raw\":\"\"},{\"name\":\"value\",\"type\":\"Compact\\u003cBalance\\u003e\",\"value\":\"10000000000\",\"value_raw\":\"\"}]", AccountId: "HKtMPUSoTC8Hts2uqcQVzPAuPRpecBt4XJ5Q1AT1GM3tp2r", Nonce: 0, Hash: "0x20cfbba19817e4b7a61e718d269de47e7067a24860fa978c2a8ead4c96a827c4", Success: true, + Fee: "100000000", }, }, wantTx: &blockatlas.Tx{ - ID: "0x20cfbba19817e4b7a61e718d269de47e7067a24860fa978c2a8ead4c96a827c4", - Coin: 434, - Date: 1577176992, - From: "HKtMPUSoTC8Hts2uqcQVzPAuPRpecBt4XJ5Q1AT1GM3tp2r", - To: "CtwdfrhECFs3FpvCGoiE4hwRC4UsSiM8WL899HjRdQbfYZY", - Block: 360298, - Status: "completed", - Fee: "100000000", + ID: "0x20cfbba19817e4b7a61e718d269de47e7067a24860fa978c2a8ead4c96a827c4", + Coin: 434, + Date: 1577176992, + From: "HKtMPUSoTC8Hts2uqcQVzPAuPRpecBt4XJ5Q1AT1GM3tp2r", + To: "CtwdfrhECFs3FpvCGoiE4hwRC4UsSiM8WL899HjRdQbfYZY", + Fee: "100000000", + Block: 360298, + Status: "completed", + Sequence: 0, Meta: blockatlas.Transfer{ Value: blockatlas.Amount("10000000000"), Symbol: "KSM", @@ -129,9 +132,44 @@ func TestNormalizeExtrinsic(t *testing.T) { }, }, }, + { + name: "Transfer DOT", + args: args{ + platform: Platform{CoinIndex: coin.DOT}, + srcTx: &Extrinsic{ + Timestamp: 1607035338, + BlockNumber: 2742892, + CallModuleFunction: "transfer", + CallModule: "balances", + Params: "[{\"name\":\"dest\",\"type\":\"Address\",\"value\":\"deb1bb215d2188d0934e803473f02b61b7990ffaea63a533a9917d5707f74d35\",\"value_raw\":\"\"},{\"name\":\"value\",\"type\":\"Compact\\u003cBalance\\u003e\",\"value\":\"16694000000\",\"value_raw\":\"\"}]", + AccountId: "13VELdVkrHf1UUH6TRYSuofJAHykL3MAw3sXG9HGR8YpgrBH", + Nonce: 1, + Hash: "0x17f92e09994e6885007bfdf4a0a5026f667e69ae94547c5c89b03d647541025e", + Success: true, + Fee: "153000000", + }, + }, + wantTx: &blockatlas.Tx{ + ID: "0x17f92e09994e6885007bfdf4a0a5026f667e69ae94547c5c89b03d647541025e", + Coin: 354, + Date: 1607035338, + From: "13VELdVkrHf1UUH6TRYSuofJAHykL3MAw3sXG9HGR8YpgrBH", + To: "162zRoDpEXQVCpPgJcoMMKZK6P8M9Ntu4myZ9ZBbDz6mqBzt", + Fee: "153000000", + Block: 2742892, + Status: "completed", + Sequence: 1, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("16694000000"), + Symbol: "DOT", + Decimals: 10, + }, + }, + }, { name: "Bond", args: args{ + platform: Platform{CoinIndex: coin.KSM}, srcTx: &Extrinsic{ Timestamp: 1577712822, BlockNumber: 447444, @@ -149,6 +187,7 @@ func TestNormalizeExtrinsic(t *testing.T) { { name: "Error Params", args: args{ + platform: Platform{CoinIndex: coin.KSM}, srcTx: &Extrinsic{ Timestamp: 1577712822, BlockNumber: 447444, @@ -166,6 +205,7 @@ func TestNormalizeExtrinsic(t *testing.T) { { name: "set_heads", args: args{ + platform: Platform{CoinIndex: coin.KSM}, srcTx: &Extrinsic{ Timestamp: 1577712822, BlockNumber: 447444, @@ -183,7 +223,7 @@ func TestNormalizeExtrinsic(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if gotTx := platform.NormalizeExtrinsic(tt.args.srcTx); !reflect.DeepEqual(gotTx, tt.wantTx) { + if gotTx := tt.args.platform.NormalizeExtrinsic(tt.args.srcTx); !reflect.DeepEqual(gotTx, tt.wantTx) { t.Errorf("Normalize() = %v\n Want = %v", gotTx, tt.wantTx) } }) @@ -191,9 +231,10 @@ func TestNormalizeExtrinsic(t *testing.T) { } func TestNormalizeAddress(t *testing.T) { - platform := Platform{CoinIndex: coin.KSM} + type args struct { - valueRaw string + platform Platform + value string } tests := []struct { name string @@ -203,21 +244,31 @@ func TestNormalizeAddress(t *testing.T) { { name: "KSM address 1", args: args{ - valueRaw: "ffe8e1b8de72651640e302b62dad1f643ec8b65a3647a7409b2896634db599ed60", + platform: Platform{CoinIndex: coin.KSM}, + value: "e8e1b8de72651640e302b62dad1f643ec8b65a3647a7409b2896634db599ed60", }, wantAddress: "HqfgRXDgCQcV8KAuTAPGuA1r91iEzinmmNBPkR9kiKhifJq", }, { name: "KSM address 2", args: args{ - valueRaw: "ffe0b3fcccfe0283cc0f8c105c68b5690aab8c5c1692a868e55eaca836c8779085", + platform: Platform{CoinIndex: coin.KSM}, + value: "e0b3fcccfe0283cc0f8c105c68b5690aab8c5c1692a868e55eaca836c8779085", }, wantAddress: "HewiDTQv92L2bVtkziZC8ASxrFUxr6ajQ62RXAnwQ8FDVmg", }, + { + name: "DOT address", + args: args{ + platform: Platform{CoinIndex: coin.DOT}, + value: "e0b3fcccfe0283cc0f8c105c68b5690aab8c5c1692a868e55eaca836c8779085", + }, + wantAddress: "165dCENc9ZGsiUgxwvxWSKdbfsxtrUqYMWymC9tC1gwGfATj", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if address := platform.NormalizeAddress(tt.args.valueRaw); address != tt.wantAddress { + if address := tt.args.platform.NormalizeAddress(tt.args.value); address != tt.wantAddress { t.Errorf("Normalize() = %v\n Want = %v", address, tt.wantAddress) } }) From 0fa3e1fac4f5aa2c44d85179a1921af3f0a2bba0 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 4 Dec 2020 17:30:48 +0800 Subject: [PATCH 423/506] [Solana] Implement tx list api (#1292) * implement solana tx list api * go mod tidy * Add estimate timestamp and error tx type test * improve make lint / integration * fix slot type --- Makefile | 7 +- go.mod | 39 ++- go.sum | 154 +++++------- platform/solana/client.go | 47 ++++ platform/solana/mocks/GetTxsByAddress.json | 1 + .../getConfirmedSignaturesForAddress2.json | 54 ++++ .../solana/mocks/getConfirmedTransaction.json | 237 ++++++++++++++++++ platform/solana/model.go | 42 ++++ platform/solana/stake_test.go | 7 +- platform/solana/transaction.go | 69 +++++ platform/solana/transaction_test.go | 113 +++++++++ 11 files changed, 648 insertions(+), 122 deletions(-) create mode 100644 platform/solana/mocks/GetTxsByAddress.json create mode 100644 platform/solana/mocks/getConfirmedSignaturesForAddress2.json create mode 100644 platform/solana/mocks/getConfirmedTransaction.json create mode 100644 platform/solana/transaction_test.go diff --git a/Makefile b/Makefile index 027294663..c3e58625d 100644 --- a/Makefile +++ b/Makefile @@ -249,7 +249,10 @@ go-test: @echo " > Running unit tests" GOBIN=$(GOBIN) go test -cover -race -coverprofile=coverage.txt -covermode=atomic -v ./... -go-integration: +go-dockertest-install: + GOBIN=$(GOBIN) go get -u github.com/ory/dockertest/v3 + +go-integration: go-dockertest-install @echo " > Running integration tests" GOBIN=$(GOBIN) TEST_CONFIG=$(CONFIG_FILE) go test -race -tags=integration -v ./tests/integration/... @@ -270,8 +273,10 @@ go-vet: GOBIN=$(GOBIN) go vet ./... go-lint-install: +ifeq (,$(wildcard test -f bin/golangci-lint)) @echo " > Installing golint" curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s +endif go-lint: @echo " > Running golint" diff --git a/go.mod b/go.mod index 79c484e25..895b8fa7a 100644 --- a/go.mod +++ b/go.mod @@ -7,48 +7,41 @@ go 1.15 require ( github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect - github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/Microsoft/go-winio v0.4.15 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 - github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 - github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb // indirect + github.com/containerd/continuity v0.0.0-20201202124332-91328d7c60e7 // indirect github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/elastic/go-sysinfo v1.3.0 // indirect - github.com/elastic/go-windows v1.0.1 // indirect github.com/gin-gonic/gin v1.6.3 github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/imroc/req v0.3.0 - github.com/mitchellh/mapstructure v1.3.3 + github.com/mitchellh/mapstructure v1.4.0 github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/opencontainers/runc v0.1.1 // indirect + 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/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.8.0 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.6.1 - github.com/swaggo/gin-swagger v1.2.0 - github.com/swaggo/swag v1.6.7 - github.com/trustwallet/golibs v0.0.15 + github.com/swaggo/gin-swagger v1.3.0 + github.com/swaggo/swag v1.6.9 + github.com/trustwallet/golibs v0.0.17 github.com/trustwallet/golibs-networking v0.0.3 - go.elastic.co/apm v1.8.0 - go.elastic.co/apm/module/apmgin v1.8.0 - go.elastic.co/apm/module/apmhttp v1.8.0 - go.elastic.co/fastjson v1.1.0 // indirect + go.elastic.co/apm v1.9.0 + go.elastic.co/apm/module/apmgin v1.9.0 + go.elastic.co/apm/module/apmhttp v1.9.0 go.uber.org/atomic v1.7.0 - golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 - golang.org/x/tools v0.0.0-20200513175351-0951661448da // indirect - gopkg.in/yaml.v2 v2.3.0 + golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 + golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect + golang.org/x/sys v0.0.0-20201202213521-69691e467435 // indirect + gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.5 - gorm.io/gorm v1.20.6 - gorm.io/plugin/dbresolver v1.0.0 + gorm.io/gorm v1.20.7 + gorm.io/plugin/dbresolver v1.0.1 gotest.tools v2.2.0+incompatible // indirect - howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 // indirect ) diff --git a/go.sum b/go.sum index 962a154c7..776765915 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15 h1:qkLXKzb1QoVatRyd/YlXZ/Kg0m5K3SPuoD82jjSOaBc= +github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -58,18 +58,14 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 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= -github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -88,8 +84,8 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb h1:nXPkFq8X1a9ycY3GYQpFNxHh3j2JgY7zDZfq2EXMIzk= -github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= +github.com/containerd/continuity v0.0.0-20201202124332-91328d7c60e7 h1:RNMG0w6AD1oHqcY2qHFrBDXny1NrJt3xMZqBfop+YBo= +github.com/containerd/continuity v0.0.0-20201202124332-91328d7c60e7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -116,18 +112,15 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/go-sysinfo v1.1.1 h1:ZVlaLDyhVkDfjwPGU55CQRCRolNpc7P0BbyhhQZQmMI= github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= -github.com/elastic/go-sysinfo v1.3.0 h1:eb2XFGTMlSwG/yyU9Y8jVAYLIzU2sFzWXwo2gmetyrE= -github.com/elastic/go-sysinfo v1.3.0/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= -github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= -github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -155,19 +148,16 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.4 h1:3Vw+rh13uq2JFNxgnMTGE1rnoieU9FmyE1gvnyylsYg= +github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.9 h1:9z9cbFuZJ7AcvOHKIY+f6Aevb4vObNDkTEyoMfO7rAc= +github.com/go-openapi/spec v0.19.9/go.mod h1:vqK/dIdLGCosfvYsQV3WfC7N3TiZSnGY2RZKoFK7X28= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= @@ -182,8 +172,9 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= +github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -203,9 +194,7 @@ github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= @@ -337,7 +326,6 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -351,13 +339,11 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -400,8 +386,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= +github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -425,16 +411,14 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -456,8 +440,6 @@ github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9 github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -470,7 +452,6 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw= github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= @@ -486,7 +467,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4= github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= @@ -497,7 +477,6 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -520,11 +499,9 @@ github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhr github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -551,14 +528,11 @@ github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5NYJe/zRYDwOu9ku6YHy+Iw7l5DM= -github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -569,41 +543,41 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= -github.com/swaggo/gin-swagger v1.2.0 h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0= github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= +github.com/swaggo/gin-swagger v1.3.0 h1:eOmp7r57oUgZPw2dJOjcGNMse9cvXcI4tTqBcnZtPsI= +github.com/swaggo/gin-swagger v1.3.0/go.mod h1:oy1BRA6WvgtCp848lhxce7BnWH4C8Bxa0m5SkWx+cS0= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= -github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= -github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= +github.com/swaggo/swag v1.6.9 h1:BukKRwZjnEcUxQt7Xgfrt9fpav0hiWw9YimdNO9wssw= +github.com/swaggo/swag v1.6.9/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.15 h1:f85eXy/WsmoTSI3cYim4qpTxucW0KYHC4RDgkr1vvJo= -github.com/trustwallet/golibs v0.0.15/go.mod h1:j+Tip4aaW3mu+81S1a+UJ8fSnKzLeJyBueApnCXXRMg= -github.com/trustwallet/golibs-networking v0.0.2 h1:E13QGT+P80H8+42wT+HNER1R7NOTx5Uh5/iOrasbaCg= -github.com/trustwallet/golibs-networking v0.0.2/go.mod h1:ZVZDbu7LW0MxnuVR280SeQIjzgUo++oc9Dft4XKrPYs= +github.com/trustwallet/golibs v0.0.17 h1:bsxF/y59/2QfqnkTFCAoiRphUljoCf9ca7BJPNTpNbk= +github.com/trustwallet/golibs v0.0.17/go.mod h1:j+Tip4aaW3mu+81S1a+UJ8fSnKzLeJyBueApnCXXRMg= github.com/trustwallet/golibs-networking v0.0.3 h1:eWBj1JKKhNUj1Ks+gdDji1IxboYyKp6j6Peyey5JkxA= github.com/trustwallet/golibs-networking v0.0.3/go.mod h1:ZVZDbu7LW0MxnuVR280SeQIjzgUo++oc9Dft4XKrPYs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.1.13 h1:nB3O5kBSQGjEQAcfe1aLUYuxmXdFKmYgBZhY32rQb6Q= +github.com/ugorji/go v1.1.13/go.mod h1:jxau1n+/wyTGLQoCkjok9r5zFa/FxT6eI5HiHKQszjc= github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.1.13 h1:013LbFhocBoIqgHeIHKlV4JWYhqogATYWZhIcH0WHn4= +github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.elastic.co/apm v1.8.0 h1:AWEKpHwRal0yCMd4K8Oxy1HAa7xid+xq1yy+XjgoVU0= -go.elastic.co/apm v1.8.0/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= -go.elastic.co/apm/module/apmgin v1.8.0 h1:QcXVtFhqAcSGqC/ywzqZBHdWzJG3wyrBxgvCvAZ98do= -go.elastic.co/apm/module/apmgin v1.8.0/go.mod h1:heH2rXaOluBb+ucwlG3FBCGrx56qHqoxb1KI7uBLlAk= -go.elastic.co/apm/module/apmhttp v1.8.0 h1:5AJPefWJzWDLX/47XIDfaloGiYWkkOQEULvlrI6Ieaw= -go.elastic.co/apm/module/apmhttp v1.8.0/go.mod h1:9LPFlEON51/lRbnWDfqAWErihIiAFDUMfMV27YjoWQ8= -go.elastic.co/fastjson v1.0.0 h1:ooXV/ABvf+tBul26jcVViPT3sBir0PvXgibYB1IQQzg= -go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs= +go.elastic.co/apm v1.9.0 h1:uLOZniTuJ2rU2fFGiNI0ZswzKr9fryHDkNMV8iVDDDI= +go.elastic.co/apm v1.9.0/go.mod h1:qoOSi09pnzJDh5fKnfY7bPmQgl8yl2tULdOu03xhui0= +go.elastic.co/apm/module/apmgin v1.9.0 h1:t3MP9pVZ1eMzIhBNl+jiMot9D+VqqFGpxuuhuiir5nw= +go.elastic.co/apm/module/apmgin v1.9.0/go.mod h1:ypUDMdqnVGK2bBjmuuyQg/1D9XE3DT6F0abehLN0tZc= +go.elastic.co/apm/module/apmhttp v1.9.0 h1:yAsxgx5bzWTFva1MJ1PqwhKsPUAUARPJ/sXIwv+uqvs= +go.elastic.co/apm/module/apmhttp v1.9.0/go.mod h1:evGjj1bVDqi47Lg2+/uKre/PDSBrOso/eTRrgeJqZyE= go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4= go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -617,7 +591,6 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -629,24 +602,22 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 h1:xYJJ3S178yv++9zXV/hnr29plCAGO9vAFG9dorqaFQc= +golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -660,15 +631,15 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -688,14 +659,13 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -705,6 +675,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -724,11 +695,11 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -737,14 +708,17 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435 h1:25AvDqqB9PrNqj1FLf2/70I4W0L19qqoaFq3gjNwbKk= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -768,7 +742,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -777,13 +750,12 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200513175351-0951661448da h1:ZR1ivkcQoKXKtux9Rx3Em7iiSViMxQ5suNd5PZMUkPc= -golang.org/x/tools v0.0.0-20200513175351-0951661448da/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200820010801-b793a1359eac h1:DugppSxw0LSF8lcjaODPJZoDzq0ElTGskTst3ZaBkHI= +golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -800,7 +772,6 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -826,11 +797,9 @@ google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLY google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -840,7 +809,6 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= @@ -854,24 +822,22 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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/mysql v1.0.1 h1:omJoilUzyrAp0xNoio88lGJCroGdIOen9hq2A/+3ifw= -gorm.io/driver/mysql v1.0.1/go.mod h1:KtqSthtg55lFp3S5kUXqlGaelnWpKitn4k1xZTnoiPw= +gorm.io/driver/mysql v1.0.2 h1:xm21Um8cR/Cg+nMwSrajf8aBUxOIC+WmH72ir/ByYR8= +gorm.io/driver/mysql v1.0.2/go.mod h1:T+Fv7Rq/8+lpS3X1KKVUbj8Y/SzbPa5esK9KpPAKXR8= gorm.io/driver/postgres v1.0.5 h1:raX6ezL/ciUmaYTvOq48jq1GE95aMC0CmxQYbxQ4Ufw= gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOudXNCA= -gorm.io/gorm v1.9.19/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.0 h1:qfIlyaZvrF7kMWY3jBdEBXkXJ2M5MFYMTppjILxS3fQ= -gorm.io/gorm v1.20.0/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.20.2/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.6 h1:qa7tC1WcU+DBI/ZKMxvXy1FcrlGsvxlaKufHrT2qQ08= -gorm.io/gorm v1.20.6/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/plugin/dbresolver v1.0.0 h1:fHIWRRkoDmXkBPYyg9GMmLugcM9fcbZiG0Zy/cwiPlM= -gorm.io/plugin/dbresolver v1.0.0/go.mod h1:sK1Alv120lfrjRQXrzyAw4ssxDPJjamm2cbBOZBHM68= +gorm.io/gorm v1.20.7 h1:rMS4CL3pNmYq1V5/X+nHHjh1Dx6dnf27+Cai5zabo+M= +gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/plugin/dbresolver v1.0.1 h1:m5QT0xhP2RgpHI9K3f1es27pN6kqbJUTZGsbDl+nEFA= +gorm.io/plugin/dbresolver v1.0.1/go.mod h1:6wjaQ00/zh2tkZo88gZbb6Ku0oruBt1x7+hvIszHPZo= 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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -882,8 +848,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= -howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 h1:AQkaJpH+/FmqRjmXZPELom5zIERYZfwTjnHpfoVMQEc= -howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/platform/solana/client.go b/platform/solana/client.go index 94c2bc611..2021510f0 100644 --- a/platform/solana/client.go +++ b/platform/solana/client.go @@ -36,3 +36,50 @@ func (c *Client) GetMinimumBalanceForRentExemption() (minimumBalance uint64, err err = c.RpcCall(&minimumBalance, "getMinimumBalanceForRentExemption", []uint64{4008}) return } + +func (c *Client) GetTransactionList(address string) ([]ConfirmedSignature, error) { + var signatures []ConfirmedSignature + params := []interface{}{ + address, + map[string]interface{}{"limit": 25}, + } + err := c.RpcCall(&signatures, "getConfirmedSignaturesForAddress2", params) + if err != nil { + return nil, err + } + return signatures, nil +} + +func (c *Client) GetTransactions(address string) ([]ConfirmedTransaction, error) { + // get tx list + signatures, err := c.GetTransactionList(address) + if err != nil { + return nil, err + } + + // build batch request + requests := make(blockatlas.RpcRequests, 0) + for _, sig := range signatures { + requests = append(requests, &blockatlas.RpcRequest{ + Method: "getConfirmedTransaction", + Params: []string{ + sig.Signature, + "jsonParsed", + }, + }) + } + var txs []ConfirmedTransaction + responses, err := c.RpcBatchCall(requests) + if err != nil { + return txs, err + } + + // convert to ConfirmedTransaction + for _, response := range responses { + var tx ConfirmedTransaction + if err := response.GetObject(&tx); err == nil { + txs = append(txs, tx) + } + } + return txs, nil +} diff --git a/platform/solana/mocks/GetTxsByAddress.json b/platform/solana/mocks/GetTxsByAddress.json new file mode 100644 index 000000000..0475d0e29 --- /dev/null +++ b/platform/solana/mocks/GetTxsByAddress.json @@ -0,0 +1 @@ +[{"id":"4aQuuc4XFP7SQrZF4z3TsFyqdRHQBF37yxK8t1jQLL97JSwGadEvUFSM4GK6DtacWzid7VT7VTaqbfJfbzzsboYt","coin":501,"from":"HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp","to":"AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q","fee":"5000","date":1588062639,"block":5632752,"status":"completed","sequence":0,"type":"transfer","direction":"incoming","memo":"","metadata":{"value":"1230000","symbol":"SOL","decimals":9}},{"id":"5QeLdXcC8GRh3KSs67Pq9sNE5uwFKkHt37crYLzcZ19ieh6RSEEGrS2r5eVXJiaXKb8M6FyKF45kHHmQRW2g1LYA","coin":501,"from":"AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q","to":"HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp","fee":"5000","date":1588026961,"block":5543556,"status":"completed","sequence":0,"type":"transfer","direction":"outgoing","memo":"","metadata":{"value":"120000","symbol":"SOL","decimals":9}}] \ No newline at end of file diff --git a/platform/solana/mocks/getConfirmedSignaturesForAddress2.json b/platform/solana/mocks/getConfirmedSignaturesForAddress2.json new file mode 100644 index 000000000..c48276582 --- /dev/null +++ b/platform/solana/mocks/getConfirmedSignaturesForAddress2.json @@ -0,0 +1,54 @@ +{ + "jsonrpc": "2.0", + "result": [ + { + "err": null, + "memo": null, + "signature": "4aQuuc4XFP7SQrZF4z3TsFyqdRHQBF37yxK8t1jQLL97JSwGadEvUFSM4GK6DtacWzid7VT7VTaqbfJfbzzsboYt", + "slot": 5632752 + }, + { + "err": null, + "memo": null, + "signature": "5QeLdXcC8GRh3KSs67Pq9sNE5uwFKkHt37crYLzcZ19ieh6RSEEGrS2r5eVXJiaXKb8M6FyKF45kHHmQRW2g1LYA", + "slot": 5543556 + }, + { + "err": null, + "memo": null, + "signature": "5Bk5b6ThBBqaPVacGjWbHSiXG58yUKi8NCyZq8Dye4iJMDZ4eoWKiPzdYLLL4VfQsJQuxvjjetZHxZ7rZiY4wsD8", + "slot": 5460244 + }, + { + "err": null, + "memo": null, + "signature": "33YpfYkBKoN2wxs27tkkhMMewxWHh9hTjDnJovz8wtB5Nshfjq4dWVSVAg7wNVrxi9yFJyNi3dNfpmfpxSk1bS85", + "slot": 5458444 + }, + { + "err": null, + "memo": null, + "signature": "5RJNtp3Upis48PuqrcTmm7gTgkMQfuEnrCauBCpPqBQZauu7PBdTefCk6zZeCHE9ESf3x9FwQvwHvXXsgXwRVJuu", + "slot": 3214148 + }, + { + "err": null, + "memo": null, + "signature": "4aCaxVsD3DwJeShU6ZzH9B8K1XCca2oqgEXkLfvXyabMTkvw1iYjjghbyZ9KdnHQqRDxcYDqGCmhZPVWiwQpBjAt", + "slot": 3194428 + }, + { + "err": null, + "memo": null, + "signature": "3Jt9Whbhd1y7gBaaJGrkFpG3nBStryfWqPRycZtte2tuRwCxDFsmoMtv1aoPaBS4yMsV6Xxbu1qX3NXMN8owNd2F", + "slot": 689909 + }, + { + "err": null, + "memo": null, + "signature": "3A4cvbLipNPA3NxYYgGAHXkWSSmwMSJi1k6NaT7wuxtr2dTbZEPLufbZ9qYTPwcifjTd3W26i3r2aP1pHi193HHH", + "slot": 493784 + } + ], + "id": 1 + } \ No newline at end of file diff --git a/platform/solana/mocks/getConfirmedTransaction.json b/platform/solana/mocks/getConfirmedTransaction.json new file mode 100644 index 000000000..fb308a677 --- /dev/null +++ b/platform/solana/mocks/getConfirmedTransaction.json @@ -0,0 +1,237 @@ +[ + { + "jsonrpc": "2.0", + "result": { + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": null, + "logMessages": null, + "postBalances": [ + 3066455000, + 31395000, + 1 + ], + "preBalances": [ + 3067690000, + 30165000, + 1 + ], + "status": { + "Ok": null + } + }, + "slot": 5632752, + "transaction": { + "message": { + "accountKeys": [ + { + "pubkey": "HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp", + "signer": true, + "writable": true + }, + { + "pubkey": "AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q", + "signer": false, + "writable": true + }, + { + "pubkey": "11111111111111111111111111111111", + "signer": false, + "writable": false + } + ], + "instructions": [ + { + "parsed": { + "info": { + "destination": "AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q", + "lamports": 1230000, + "source": "HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp" + }, + "type": "transfer" + }, + "program": "system", + "programId": "11111111111111111111111111111111" + } + ], + "recentBlockhash": "9zjmFdQM4QEvPxjdqacu7aatBwkYzfFqkXqHaJBueD1f" + }, + "signatures": [ + "4aQuuc4XFP7SQrZF4z3TsFyqdRHQBF37yxK8t1jQLL97JSwGadEvUFSM4GK6DtacWzid7VT7VTaqbfJfbzzsboYt" + ] + } + }, + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "meta": { + "err": null, + "fee": 5000, + "innerInstructions": null, + "logMessages": null, + "postBalances": [ + 30165000, + 3067690000, + 1 + ], + "preBalances": [ + 30290000, + 3067570000, + 1 + ], + "status": { + "Ok": null + } + }, + "slot": 5543556, + "transaction": { + "message": { + "accountKeys": [ + { + "pubkey": "AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q", + "signer": true, + "writable": true + }, + { + "pubkey": "HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp", + "signer": false, + "writable": true + }, + { + "pubkey": "11111111111111111111111111111111", + "signer": false, + "writable": false + } + ], + "instructions": [ + { + "parsed": { + "info": { + "destination": "HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp", + "lamports": 120000, + "source": "AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q" + }, + "type": "transfer" + }, + "program": "system", + "programId": "11111111111111111111111111111111" + } + ], + "recentBlockhash": "8u75QFEzBoj61tdiZFHQSTQnHzcagfTQAde2iijQp2r3" + }, + "signatures": [ + "5QeLdXcC8GRh3KSs67Pq9sNE5uwFKkHt37crYLzcZ19ieh6RSEEGrS2r5eVXJiaXKb8M6FyKF45kHHmQRW2g1LYA" + ] + } + }, + "id": 1 + }, + { + "jsonrpc": "2.0", + "result": { + "meta": { + "err": { + "InstructionError": [ + 0, + { + "Custom": 0 + } + ] + }, + "fee": 5000, + "innerInstructions": [], + "logMessages": [ + "Program Vote111111111111111111111111111111111111111 invoke [1]", + "Program Vote111111111111111111111111111111111111111 failed: custom program error: 0x0" + ], + "postBalances": [ + 478775796520, + 26858640, + 1, + 1, + 1 + ], + "preBalances": [ + 478775801520, + 26858640, + 1, + 1, + 1 + ], + "status": { + "Err": { + "InstructionError": [ + 0, + { + "Custom": 0 + } + ] + } + } + }, + "slot": 52838310, + "transaction": { + "message": { + "accountKeys": [ + { + "pubkey": "D32cBNvo9qmMyMSJzWqDPQ3ujYFuW9HHNjVkwxspezQr", + "signer": true, + "writable": true + }, + { + "pubkey": "YT7i3TkDv9GpbQ5qEkL7dvb3fAXSuNKwCotw2MjrWxZ", + "signer": false, + "writable": true + }, + { + "pubkey": "SysvarS1otHashes111111111111111111111111111", + "signer": false, + "writable": false + }, + { + "pubkey": "SysvarC1ock11111111111111111111111111111111", + "signer": false, + "writable": false + }, + { + "pubkey": "Vote111111111111111111111111111111111111111", + "signer": false, + "writable": false + } + ], + "instructions": [ + { + "parsed": { + "info": { + "clockSysvar": "SysvarC1ock11111111111111111111111111111111", + "slotHashesSysvar": "SysvarS1otHashes111111111111111111111111111", + "vote": { + "hash": "A9Jg1smbeMVyssPKbeK3pAkMDfLkKgAfRMK5aFELJDsZ", + "slots": [ + 52838301, + 52838302 + ], + "timestamp": 1606944861 + }, + "voteAccount": "YT7i3TkDv9GpbQ5qEkL7dvb3fAXSuNKwCotw2MjrWxZ", + "voteAuthority": "D32cBNvo9qmMyMSJzWqDPQ3ujYFuW9HHNjVkwxspezQr" + }, + "type": "vote" + }, + "program": "vote", + "programId": "Vote111111111111111111111111111111111111111" + } + ], + "recentBlockhash": "3e9FDUaHg4t1KPsi8F4tf63Kxn5H5XU7BkQnVRmxjUKA" + }, + "signatures": [ + "29ku1FzyNHgx5BZ811uj82EEnZNG6JbPuCQJvy5zuXnBfy2zgAdUubpfwEz2CfojFzxuzghms6qq9afzrzSnavdD" + ] + } + }, + "id": 1 + } + ] \ No newline at end of file diff --git a/platform/solana/model.go b/platform/solana/model.go index d9c89fc0a..6b97f01a3 100644 --- a/platform/solana/model.go +++ b/platform/solana/model.go @@ -69,3 +69,45 @@ type EpochInfo struct { SlotIndex uint64 `json:"slotIndex"` SlotsInEpoch uint64 `json:"slotsInEpoch"` } + +type ConfirmedSignature struct { + Memo string `json:"memo"` + Signature string `json:"signature"` + Slot uint64 `json:"slot"` +} + +type ConfirmedTransaction struct { + Meta Meta `json:"meta"` + Slot uint64 `json:"slot"` + Transaction Transaction `json:"transaction"` +} + +type Meta struct { + Err interface{} `json:"err"` + Fee uint64 `json:"fee"` +} + +type Info struct { + Destination string `json:"destination"` + Lamports uint64 `json:"lamports"` + Source string `json:"source"` +} + +type Parsed struct { + Info Info `json:"info"` + Type string `json:"type"` +} + +type Instructions struct { + Parsed Parsed `json:"parsed"` + Program string `json:"program"` +} + +type Message struct { + Instructions []Instructions `json:"instructions"` +} + +type Transaction struct { + Message Message `json:"message"` + Signatures []string `json:"signatures"` +} diff --git a/platform/solana/stake_test.go b/platform/solana/stake_test.go index 405360bd0..8c5dccad2 100644 --- a/platform/solana/stake_test.go +++ b/platform/solana/stake_test.go @@ -2,9 +2,10 @@ package solana import ( "encoding/json" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/stretchr/testify/assert" ) @@ -37,7 +38,7 @@ const currentValidators = ` ]` var expectedValidators = []blockatlas.Validator{ - blockatlas.Validator{ + { Status: true, ID: "2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW", Details: blockatlas.StakingDetails{ @@ -47,7 +48,7 @@ var expectedValidators = []blockatlas.Validator{ Type: blockatlas.DelegationTypeDelegate, }, }, - blockatlas.Validator{ + { Status: true, ID: "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5", Details: blockatlas.StakingDetails{ diff --git a/platform/solana/transaction.go b/platform/solana/transaction.go index 8ded47050..5338e179d 100644 --- a/platform/solana/transaction.go +++ b/platform/solana/transaction.go @@ -1,10 +1,79 @@ package solana import ( + "errors" + "strconv" + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { results := make(blockatlas.TxPage, 0) + txs, err := p.client.GetTransactions(address) + if err != nil { + return results, err + } + for _, tx := range txs { + if normalized, err := p.NormalizeTx(tx, address); err == nil { + results = append(results, normalized) + } + } return results, nil } + +func (p *Platform) NormalizeTx(tx ConfirmedTransaction, address string) (normalized blockatlas.Tx, err error) { + + // only check first instruction + if len(tx.Transaction.Message.Instructions) != 1 || len(tx.Transaction.Signatures) != 1 { + return normalized, errors.New("not supported") + } + + // only supports transfer type now + instruction := tx.Transaction.Message.Instructions[0] + if instruction.Parsed.Type != "transfer" { + return normalized, errors.New("not supported type other than transfer") + } + + // tx direction + from := instruction.Parsed.Info.Source + direction := blockatlas.DirectionIncoming + if address == from { + direction = blockatlas.DirectionOutgoing + } + + // tx status + status := blockatlas.StatusCompleted + if tx.Meta.Err != nil { + status = blockatlas.StatusError + } + + normalized = blockatlas.Tx{ + ID: tx.Transaction.Signatures[0], + Coin: p.Coin().ID, + From: from, + To: instruction.Parsed.Info.Destination, + Fee: blockatlas.Amount(strconv.FormatUint(tx.Meta.Fee, 10)), + Date: EstimateTimestamp(tx.Slot), + Block: tx.Slot, + Status: status, + Type: blockatlas.TxTransfer, + Direction: direction, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount(strconv.FormatUint(instruction.Parsed.Info.Lamports, 10)), + Symbol: p.Coin().Symbol, + Decimals: p.Coin().Decimals, + }, + } + + return normalized, nil +} + +func EstimateTimestamp(slot uint64) int64 { + var ( + blockTime uint64 = 400 //ms + sampleSlot uint64 = 52838300 + sampleTs uint64 = 1606944859 * 1000 + ) + offset := (slot - sampleSlot) * blockTime + return int64((sampleTs + offset) / 1000) +} diff --git a/platform/solana/transaction_test.go b/platform/solana/transaction_test.go new file mode 100644 index 000000000..0b831cb08 --- /dev/null +++ b/platform/solana/transaction_test.go @@ -0,0 +1,113 @@ +package solana + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/mock" +) + +func TestPlatform_GetTxsByAddress(t *testing.T) { + wanted, err := mock.JsonFromFilePathToString("mocks/GetTxsByAddress.json") + if err != nil { + panic(err) + } + data := make(map[string]func(http.ResponseWriter, *http.Request)) + data["/"] = func(w http.ResponseWriter, req *http.Request) { + w.WriteHeader(http.StatusOK) + + var r blockatlas.RpcRequest + var rs []blockatlas.RpcRequest + var response string + + buf := new(bytes.Buffer) + _, err := buf.ReadFrom(req.Body) + if err != nil { + panic(err) + } + requestBody := buf.String() + + if err := json.Unmarshal([]byte(requestBody), &r); err == nil { + switch r.Method { + case "getConfirmedSignaturesForAddress2": + signatures, err := mock.JsonFromFilePathToString("mocks/getConfirmedSignaturesForAddress2.json") + if err != nil { + panic(err) + } + response = signatures + } + } else if err := json.Unmarshal([]byte(requestBody), &rs); err == nil { + switch rs[0].Method { + case "getConfirmedTransaction": + signatures, err := mock.JsonFromFilePathToString("mocks/getConfirmedTransaction.json") + if err != nil { + panic(err) + } + response = signatures + } + } else { + panic("not valid json rpc request") + } + + if _, err := fmt.Fprint(w, response); err != nil { + panic(err) + } + } + + server := httptest.NewServer(mock.CreateMockedAPI(data)) + defer server.Close() + + p := Init(server.URL) + txs, err := p.GetTxsByAddress("AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q") + assert.Nil(t, err) + raw, err := json.Marshal(txs) + assert.Nil(t, err) + assert.Equal(t, wanted, string(raw)) +} + +func TestEstimateTimestamp(t *testing.T) { + tests := []struct { + name string + slot uint64 + want int64 + }{ + { + name: "Test 0", + slot: 0, + want: 1585809539, + }, + { + name: "Test sample slot", + slot: 52838300, + want: 1606944859, + }, + { + name: "Test nomral 1", + slot: 5632752, + want: 1588062639, + }, + { + name: "Test normal 2", + slot: 5543556, + want: 1588026961, + }, + { + name: "Test normal 3", + slot: 493784, + want: 1586007052, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := EstimateTimestamp(tt.slot); got != tt.want { + t.Errorf("EstimateTimestamp() = %v, want %v", got, tt.want) + } + }) + } +} From d0660c67168fbc36e4127e8c702d28e74a9c4ea2 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sat, 5 Dec 2020 23:55:44 -0800 Subject: [PATCH 424/506] Use gin-contrib/cors for handling CORS (#1299) --- api/middleware/cors.go | 19 ------------------- go.mod | 1 + go.sum | 7 +++++++ internal/init.go | 8 +++++--- 4 files changed, 13 insertions(+), 22 deletions(-) delete mode 100644 api/middleware/cors.go diff --git a/api/middleware/cors.go b/api/middleware/cors.go deleted file mode 100644 index 58f48fbc5..000000000 --- a/api/middleware/cors.go +++ /dev/null @@ -1,19 +0,0 @@ -package middleware - -import ( - "github.com/gin-gonic/gin" -) - -func CORSMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - c.Writer.Header().Set("Access-Control-Allow-Origin", "*") - c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") - c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") - c.Writer.Header().Set("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE") - if c.Request.Method == "OPTIONS" { - c.AbortWithStatus(204) - return - } - c.Next() - } -} diff --git a/go.mod b/go.mod index 895b8fa7a..062e62159 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect + github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/imroc/req v0.3.0 diff --git a/go.sum b/go.sum index 776765915..9f396d52a 100644 --- a/go.sum +++ b/go.sum @@ -130,6 +130,8 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA= +github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk= github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= @@ -138,6 +140,7 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -162,8 +165,10 @@ github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tF github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= @@ -347,6 +352,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -811,6 +817,7 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/internal/init.go b/internal/init.go index 0ab597b1a..f1bada34e 100644 --- a/internal/init.go +++ b/internal/init.go @@ -4,7 +4,8 @@ import ( "flag" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/api/middleware" + + "github.com/gin-contrib/cors" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/mq" "go.elastic.co/apm/module/apmgin" @@ -42,10 +43,11 @@ func InitConfig(confPath string) { func InitEngine(ginMode string) *gin.Engine { gin.SetMode(ginMode) engine := gin.New() - engine.Use(middleware.CORSMiddleware()) + + engine.Use(cors.Default()) + engine.Use(apmgin.Middleware(engine)) engine.Use(gin.Logger()) - engine.OPTIONS("/*path", middleware.CORSMiddleware()) return engine } From 48af9653e665e761cb17ab7e15bcc7c600e47d53 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Mon, 7 Dec 2020 14:57:48 -0800 Subject: [PATCH 425/506] [DB] Enable log option and consolidate read replicate (#1300) * [DB] Enable log option and consolidate read replicate * Adjust tests --- cmd/api/main.go | 3 +-- cmd/consumer/main.go | 3 +-- cmd/parser/main.go | 3 +-- config.yml | 2 -- config/configuration.go | 7 ++----- db/db.go | 19 +++++++------------ go.mod | 5 ++--- go.sum | 15 ++++----------- tests/integration/setup/postgres.go | 6 +++--- 9 files changed, 21 insertions(+), 42 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index a513bc2ff..674eaef77 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -42,8 +42,7 @@ func init() { platform.Init(config.Default.Platform) var err error - database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, - config.Default.Postgres.Log) + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Log) if err != nil { log.Fatal(err) } diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index e965728c3..fe4a44e56 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -39,8 +39,7 @@ func init() { ) var err error - database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, - config.Default.Postgres.Log) + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Log) if err != nil { log.Fatal("Postgres init: ", err) } diff --git a/cmd/parser/main.go b/cmd/parser/main.go index 216642bad..c24ca5754 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -55,8 +55,7 @@ func init() { } var err error - database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Read.URL, - config.Default.Postgres.Log) + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Log) if err != nil { log.Fatal(err) } diff --git a/config.yml b/config.yml index a8a08d5ee..eab54bb6c 100644 --- a/config.yml +++ b/config.yml @@ -31,8 +31,6 @@ observer: postgres: url: postgresql://user:pass@localhost/blockatlas?sslmode=disable - read: - url: postgresql://user:pass@localhost/blockatlas?sslmode=disable log: false # [BNB] Binance DEX: https://www.binance.org/ diff --git a/config/configuration.go b/config/configuration.go index 36efd8e01..d6d7ccb0f 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -35,11 +35,8 @@ type Configuration struct { } `mapstructure:"rabbitmq"` } `mapstructure:"observer"` Postgres struct { - URL string `mapstructure:"url"` - Read struct { - URL string `mapstructure:"url"` - } `mapstructure:"read"` - Log bool `mapstructure:"log"` + URL string `mapstructure:"url"` + Log bool `mapstructure:"log"` } `mapstructure:"postgres"` Ethereum struct { API string `mapstructure:"api"` diff --git a/db/db.go b/db/db.go index e2687efb1..bc27579af 100644 --- a/db/db.go +++ b/db/db.go @@ -13,7 +13,6 @@ import ( "gorm.io/driver/postgres" "gorm.io/gorm" - "gorm.io/plugin/dbresolver" ) type Instance struct { @@ -25,19 +24,15 @@ type Instance struct { // "Depending on the number of variables included, 2000 to 3000 is recommended." const batchCount = 3000 -func New(uri, readUri string, logMode bool) (*Instance, error) { - cfg := &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)} - - db, err := gorm.Open(postgres.Open(uri), cfg) - if err != nil { - return nil, err +func New(url string, log bool) (*Instance, error) { + var logMode logger.LogLevel + if log { + logMode = logger.Info } - err = db.Use(dbresolver.Register(dbresolver.Config{ - Replicas: []gorm.Dialector{ - postgres.Open(readUri), - }, - })) + cfg := &gorm.Config{Logger: logger.Default.LogMode(logMode)} + + db, err := gorm.Open(postgres.Open(url), cfg) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 062e62159..90b9d8941 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 - github.com/containerd/continuity v0.0.0-20201202124332-91328d7c60e7 // indirect + github.com/containerd/continuity v0.0.0-20201204194424-b0f312dbb49a // indirect github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect @@ -39,10 +39,9 @@ require ( go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect - golang.org/x/sys v0.0.0-20201202213521-69691e467435 // indirect + golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.5 gorm.io/gorm v1.20.7 - gorm.io/plugin/dbresolver v1.0.1 gotest.tools v2.2.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index 9f396d52a..511ecfdd3 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,8 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/containerd/continuity v0.0.0-20201202124332-91328d7c60e7 h1:RNMG0w6AD1oHqcY2qHFrBDXny1NrJt3xMZqBfop+YBo= -github.com/containerd/continuity v0.0.0-20201202124332-91328d7c60e7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20201204194424-b0f312dbb49a h1:SsffDYRSRlPV6Jcm8QpjPnRmiQ1265amULS37h+bwyg= +github.com/containerd/continuity v0.0.0-20201204194424-b0f312dbb49a/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -174,8 +174,6 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= @@ -720,8 +718,8 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201202213521-69691e467435 h1:25AvDqqB9PrNqj1FLf2/70I4W0L19qqoaFq3gjNwbKk= -golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -835,16 +833,11 @@ 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/mysql v1.0.2 h1:xm21Um8cR/Cg+nMwSrajf8aBUxOIC+WmH72ir/ByYR8= -gorm.io/driver/mysql v1.0.2/go.mod h1:T+Fv7Rq/8+lpS3X1KKVUbj8Y/SzbPa5esK9KpPAKXR8= gorm.io/driver/postgres v1.0.5 h1:raX6ezL/ciUmaYTvOq48jq1GE95aMC0CmxQYbxQ4Ufw= gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOudXNCA= -gorm.io/gorm v1.20.2/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.7 h1:rMS4CL3pNmYq1V5/X+nHHjh1Dx6dnf27+Cai5zabo+M= gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/plugin/dbresolver v1.0.1 h1:m5QT0xhP2RgpHI9K3f1es27pN6kqbJUTZGsbDl+nEFA= -gorm.io/plugin/dbresolver v1.0.1/go.mod h1:6wjaQ00/zh2tkZo88gZbb6Ku0oruBt1x7+hvIszHPZo= 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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go index b10d72f26..9b3584707 100644 --- a/tests/integration/setup/postgres.go +++ b/tests/integration/setup/postgres.go @@ -32,7 +32,7 @@ var ( &models.Address{}, } - uri string + url string ) func runPgContainerAndInitConnection() (*db.Instance, error) { @@ -42,7 +42,7 @@ func runPgContainerAndInitConnection() (*db.Instance, error) { err error ) err = pool.Retry(func() error { - dbConn, err = db.New(uri, uri, false) + dbConn, err = db.New(url, false) return err }) if err != nil { @@ -81,7 +81,7 @@ func runPgContainer() *dockertest.Pool { log.Fatalf("Could not start resource: %s", err) } - uri = fmt.Sprintf("postgres://%s:%s@localhost:%s/%s?sslmode=disable", + url = fmt.Sprintf("postgres://%s:%s@localhost:%s/%s?sslmode=disable", pgUser, pgPass, pgResource.GetPort("5432/tcp"), pgDB, ) return pool From aa6f6f99092f5b38f2cdc43986a658a7c6ca71b6 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 8 Dec 2020 17:21:04 -0800 Subject: [PATCH 426/506] Add sentry setup (#1301) * Add sentry setup * Update api.go --- cmd/api/main.go | 9 +- config.yml | 3 + config/configuration.go | 3 + go.mod | 3 +- go.sum | 177 ++-------------------------------- services/tokensearcher/api.go | 13 ++- 6 files changed, 34 insertions(+), 174 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index 674eaef77..b3f692a1b 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -4,6 +4,8 @@ import ( "context" "time" + "github.com/trustwallet/golibs-networking/middleware" + "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/api" @@ -35,13 +37,18 @@ var ( func init() { port, confPath = internal.ParseArgs(defaultPort, defaultConfigPath) ctx, cancel = context.WithCancel(context.Background()) + var err error internal.InitConfig(confPath) + err = middleware.SetupSentry(config.Default.Sentry.DSN) + if err != nil { + log.Error(err) + } + engine = internal.InitEngine(config.Default.Gin.Mode) platform.Init(config.Default.Platform) - var err error database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Log) if err != nil { log.Fatal(err) diff --git a/config.yml b/config.yml index eab54bb6c..1fcc46a59 100644 --- a/config.yml +++ b/config.yml @@ -222,3 +222,6 @@ filecoin: # bsc: # api: # rpc: + +sentry: + dsn: "" diff --git a/config/configuration.go b/config/configuration.go index d6d7ccb0f..746fc04d4 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -215,6 +215,9 @@ type Configuration struct { Filecoin struct { API string `mapstructure:"api"` } `mapstructure:"filecoin"` + Sentry struct { + DSN string `mapstructure:"dsn"` + } `mapstructure:"sentry"` } var Default Configuration diff --git a/go.mod b/go.mod index 90b9d8941..f48a4c362 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 + github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/containerd/continuity v0.0.0-20201204194424-b0f312dbb49a // indirect github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect @@ -32,7 +33,7 @@ require ( github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/swag v1.6.9 github.com/trustwallet/golibs v0.0.17 - github.com/trustwallet/golibs-networking v0.0.3 + github.com/trustwallet/golibs-networking v0.0.5 go.elastic.co/apm v1.9.0 go.elastic.co/apm/module/apmgin v1.9.0 go.elastic.co/apm/module/apmhttp v1.9.0 diff --git a/go.sum b/go.sum index 511ecfdd3..2efa8abdd 100644 --- a/go.sum +++ b/go.sum @@ -17,7 +17,6 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.4.15 h1:qkLXKzb1QoVatRyd/YlXZ/Kg0m5K3SPuoD82jjSOaBc= @@ -30,32 +29,18 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 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/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 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= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= @@ -68,32 +53,22 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6 h1:3Wv1E0CqL45hBs4bykb586wvZMRGKfFITHrN3ilm4FE= -github.com/chenjiandongx/ginprom v0.0.0-20200410120253-7cfb22707fa6/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/continuity v0.0.0-20201204194424-b0f312dbb49a h1:SsffDYRSRlPV6Jcm8QpjPnRmiQ1265amULS37h+bwyg= github.com/containerd/continuity v0.0.0-20201204194424-b0f312dbb49a/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -111,24 +86,18 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/go-sysinfo v1.1.1 h1:ZVlaLDyhVkDfjwPGU55CQRCRolNpc7P0BbyhhQZQmMI= github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evalphobia/logrus_sentry v0.8.2 h1:dotxHq+YLZsT1Bb45bB5UQbfCh3gM/nFFetyN46VoDQ= +github.com/evalphobia/logrus_sentry v0.8.2/go.mod h1:pKcp+vriitUqu9KiWj/VRFbRfFNUwz95/UkgG8a6MNc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA= github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk= @@ -145,11 +114,8 @@ github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -173,19 +139,14 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -198,10 +159,8 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -214,27 +173,18 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -245,7 +195,6 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -256,11 +205,9 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U= github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= @@ -319,16 +266,13 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -336,7 +280,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= @@ -358,9 +301,6 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -379,7 +319,6 @@ 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/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 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= @@ -401,91 +340,42 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc= github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw= -github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4= -github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -493,7 +383,6 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -514,27 +403,21 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -553,12 +436,11 @@ github.com/swaggo/gin-swagger v1.3.0/go.mod h1:oy1BRA6WvgtCp848lhxce7BnWH4C8Bxa0 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.6.9 h1:BukKRwZjnEcUxQt7Xgfrt9fpav0hiWw9YimdNO9wssw= github.com/swaggo/swag v1.6.9/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/golibs v0.0.17 h1:bsxF/y59/2QfqnkTFCAoiRphUljoCf9ca7BJPNTpNbk= github.com/trustwallet/golibs v0.0.17/go.mod h1:j+Tip4aaW3mu+81S1a+UJ8fSnKzLeJyBueApnCXXRMg= -github.com/trustwallet/golibs-networking v0.0.3 h1:eWBj1JKKhNUj1Ks+gdDji1IxboYyKp6j6Peyey5JkxA= -github.com/trustwallet/golibs-networking v0.0.3/go.mod h1:ZVZDbu7LW0MxnuVR280SeQIjzgUo++oc9Dft4XKrPYs= +github.com/trustwallet/golibs-networking v0.0.5 h1:7gbxSgGf6KryKaI36s+MYLGE0X9sJKwHjyLJJKx5V/Q= +github.com/trustwallet/golibs-networking v0.0.5/go.mod h1:FS8fJ7DyM+ZAs94VsmCAOlbDXJdkOcceb3d6dKujXho= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -570,7 +452,6 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/ugorji/go/codec v1.1.13 h1:013LbFhocBoIqgHeIHKlV4JWYhqogATYWZhIcH0WHn4= github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -585,26 +466,18 @@ go.elastic.co/apm/module/apmhttp v1.9.0/go.mod h1:evGjj1bVDqi47Lg2+/uKre/PDSBrOs go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4= go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -612,7 +485,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -640,7 +512,6 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -653,7 +524,6 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -661,7 +531,6 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -687,7 +556,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -700,20 +568,16 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -726,12 +590,9 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -742,7 +603,6 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -756,7 +616,6 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac h1:DugppSxw0LSF8lcjaODPJZoDzq0ElTGskTst3ZaBkHI= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -766,14 +625,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -782,21 +639,13 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -809,10 +658,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= @@ -821,12 +668,10 @@ gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -840,14 +685,10 @@ gorm.io/gorm v1.20.7 h1:rMS4CL3pNmYq1V5/X+nHHjh1Dx6dnf27+Cai5zabo+M= gorm.io/gorm v1.20.7/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-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/services/tokensearcher/api.go b/services/tokensearcher/api.go index a0650dd27..33e18725e 100644 --- a/services/tokensearcher/api.go +++ b/services/tokensearcher/api.go @@ -3,15 +3,16 @@ package tokensearcher import ( "context" "encoding/json" + "strconv" + "sync" + "time" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "strconv" - "sync" - "time" ) type ( @@ -156,7 +157,11 @@ func fetchAssetsByAddresses(tokenAPI blockatlas.TokensAPI, addresses []string, r defer tWg.Done() tokens, err := tokenAPI.GetTokenListByAddress(address) if err != nil { - log.WithFields(log.Fields{"coin": tokenAPI.Coin().Handle, "address": address}).Error("Fetch GetTokenListByAddress", err) + log.WithFields(log.Fields{ + "coin": tokenAPI.Coin().Handle, + "address": address, + "error": err, + }).Error("Fetch GetTokenListByAddress for: ", tokenAPI.Coin().Handle) return } result.UpdateAssetsByAddress(tokens, int(tokenAPI.Coin().ID), address) From 38d35ae69d8c4f8c6379bbea587344b4a2e00547 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 8 Dec 2020 18:49:09 -0800 Subject: [PATCH 427/506] Remove APM (#1302) --- api/endpoint/token.go | 13 ++-- cmd/api/main.go | 2 +- cmd/consumer/main.go | 2 +- cmd/parser/main.go | 2 +- db/addresstoasset.go | 48 ++++++------ db/asset.go | 36 +++++---- db/db.go | 10 +-- db/notification.go | 16 ++-- db/tracker.go | 15 ++-- go.mod | 9 +-- go.sum | 49 ++---------- internal/init.go | 4 +- pkg/blockatlas/client.go | 5 +- services/notifier/base.go | 20 ++--- services/notifier/delivery.go | 12 +-- services/notifier/models.go | 11 +-- services/notifier/models_test.go | 8 +- services/parser/parser.go | 76 ++++++------------- services/parser/parser_test.go | 27 ++++--- services/subscriber/tokens.go | 9 +-- services/subscriber/transactions.go | 14 +--- services/tokenindexer/api.go | 8 +- services/tokenindexer/indexer.go | 9 +-- services/tokensearcher/api.go | 14 ++-- services/tokensearcher/tokensearcher.go | 15 ++-- .../integration/db_test/subscriptions_test.go | 62 +++++++-------- .../db_test/tokenassociations_test.go | 48 ++++++------ .../integration/db_test/tokenindexer_test.go | 28 +++---- tests/integration/db_test/tracker_test.go | 12 +-- .../observer_test/full_flow_test.go | 7 +- .../observer_test/notifier_test.go | 7 +- .../observer_test/subscriber_test.go | 33 ++++---- 32 files changed, 256 insertions(+), 375 deletions(-) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index 22ec72e3b..7d55e0fa7 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -1,14 +1,15 @@ package endpoint import ( - "github.com/gin-gonic/gin" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/tokenindexer" - "github.com/trustwallet/blockatlas/services/tokensearcher" "net/http" "strconv" "sync" "time" + + "github.com/gin-gonic/gin" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/tokenindexer" + "github.com/trustwallet/blockatlas/services/tokensearcher" ) type ( @@ -132,7 +133,7 @@ func GetTokensByAddressIndexer(c *gin.Context, instance tokensearcher.Instance) c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) return } - result, err := instance.HandleTokensRequest(query, c.Request.Context()) + result, err := instance.HandleTokensRequest(query) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return @@ -168,7 +169,7 @@ func GetNewTokens(c *gin.Context, instance tokenindexer.Instance) { request.Coin = coin request.From = int64(from) - resp, err := instance.HandleNewTokensRequest(request, c.Request.Context()) + resp, err := instance.HandleNewTokensRequest(request) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return diff --git a/cmd/api/main.go b/cmd/api/main.go index b3f692a1b..f845537d0 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -53,7 +53,7 @@ func init() { if err != nil { log.Fatal(err) } - go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) + go database.RestoreConnectionWorker(time.Second*10, config.Default.Postgres.URL) internal.InitRabbitMQ( config.Default.Observer.Rabbitmq.URL, diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index fe4a44e56..973ca8205 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -43,7 +43,7 @@ func init() { if err != nil { log.Fatal("Postgres init: ", err) } - go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) + go database.RestoreConnectionWorker(time.Second*10, config.Default.Postgres.URL) time.Sleep(time.Millisecond) } diff --git a/cmd/parser/main.go b/cmd/parser/main.go index c24ca5754..2fa405768 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -59,7 +59,7 @@ func init() { if err != nil { log.Fatal(err) } - go database.RestoreConnectionWorker(ctx, time.Second*10, config.Default.Postgres.URL) + go database.RestoreConnectionWorker(time.Second*10, config.Default.Postgres.URL) time.Sleep(time.Millisecond) } diff --git a/db/addresstoasset.go b/db/addresstoasset.go index b089ca0e9..eddd72d3f 100644 --- a/db/addresstoasset.go +++ b/db/addresstoasset.go @@ -1,17 +1,16 @@ package db import ( - "context" + "time" + "github.com/trustwallet/blockatlas/db/models" "gorm.io/gorm" "gorm.io/gorm/clause" - "time" ) -func (i Instance) GetSubscribedAddressesForAssets(ctx context.Context, addresses []string) ([]models.Address, error) { - db := i.Gorm.WithContext(ctx) +func (i Instance) GetSubscribedAddressesForAssets(addresses []string) ([]models.Address, error) { var result []models.Address - err := db.Model(&models.AssetSubscription{}). + err := i.Gorm.Model(&models.AssetSubscription{}). Select("id", "address"). Joins("LEFT JOIN addresses a ON a.id = address_id"). Where("address in (?)", addresses). @@ -23,10 +22,11 @@ func (i Instance) GetSubscribedAddressesForAssets(ctx context.Context, addresses return result, nil } -func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Context) (map[string][]models.Asset, error) { - db := i.Gorm.WithContext(ctx) +func (i Instance) GetAssetsMapByAddresses(addresses []string) (map[string][]models.Asset, error) { var associations []models.AddressToAssetAssociation - if err := db.Joins("Address").Joins("Asset").Find(&associations, "address in (?)", addresses).Error; err != nil { + if err := i.Gorm.Joins("Address"). + Joins("Asset"). + Find(&associations, "address in (?)", addresses).Error; err != nil { return nil, err } @@ -38,13 +38,16 @@ func (i Instance) GetAssetsMapByAddresses(addresses []string, ctx context.Contex return result, nil } -func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) (map[string][]models.Asset, error) { +func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time.Time) (map[string][]models.Asset, error) { if len(addresses) == 0 { return map[string][]models.Asset{}, nil } - db := i.Gorm.WithContext(ctx) var associations []models.AddressToAssetAssociation - err := db.Joins("Address").Where("address in (?)", addresses).Joins("Asset").Find(&associations, "address_to_asset_associations.created_at > ?", from).Error + err := i.Gorm. + Joins("Address"). + Where("address in (?)", addresses). + Joins("Asset"). + Find(&associations, "address_to_asset_associations.created_at > ?", from).Error if err != nil { return nil, err } @@ -57,28 +60,28 @@ func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time. return result, nil } -func (i *Instance) GetAssociationsByAddresses(addresses []string, ctx context.Context) ([]models.AddressToAssetAssociation, error) { - db := i.Gorm.WithContext(ctx) +func (i *Instance) GetAssociationsByAddresses(addresses []string) ([]models.AddressToAssetAssociation, error) { var result []models.AddressToAssetAssociation - if err := db.Joins("Address").Joins("Asset").Find(&result, "address in (?)", addresses).Error; err != nil { + if err := i.Gorm. + Joins("Address"). + Joins("Asset"). + Find(&result, "address in (?)", addresses).Error; err != nil { return nil, err } return result, nil } -func (i *Instance) GetAssociationsByAddressesFromTime(addresses []string, from time.Time, ctx context.Context) ([]models.AddressToAssetAssociation, error) { - db := i.Gorm.WithContext(ctx) +func (i *Instance) GetAssociationsByAddressesFromTime(addresses []string, from time.Time) ([]models.AddressToAssetAssociation, error) { var result []models.AddressToAssetAssociation - err := db.Joins("Address").Where("address in (?)", addresses).Joins("Asset").Find(&result, "created_at > ?", from).Error + err := i.Gorm.Joins("Address").Where("address in (?)", addresses).Joins("Asset").Find(&result, "created_at > ?", from).Error if err != nil { return nil, err } return result, nil } -func (i *Instance) AddAssociationsForAddress(address string, assets []models.Asset, ctx context.Context) error { - db := i.Gorm.WithContext(ctx) - return db.Transaction(func(tx *gorm.DB) error { +func (i *Instance) AddAssociationsForAddress(address string, assets []models.Asset) error { + return i.Gorm.Transaction(func(tx *gorm.DB) error { uniqueAssets := getUniqueAssets(assets) var err error @@ -133,9 +136,8 @@ func (i *Instance) AddAssociationsForAddress(address string, assets []models.Ass }) } -func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[string][]models.Asset, ctx context.Context) error { - db := i.Gorm.WithContext(ctx) - return db.Transaction(func(tx *gorm.DB) error { +func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[string][]models.Asset) error { + return i.Gorm.Transaction(func(tx *gorm.DB) error { assets := make([]models.Asset, 0, len(associations)) for _, v := range associations { assets = append(assets, v...) diff --git a/db/asset.go b/db/asset.go index ddfe16729..97c31af73 100644 --- a/db/asset.go +++ b/db/asset.go @@ -1,7 +1,6 @@ package db import ( - "context" "encoding/json" "time" "unicode/utf8" @@ -14,8 +13,7 @@ import ( "github.com/trustwallet/blockatlas/db/models" ) -func (i *Instance) AddNewAssets(assets []models.Asset, ctx context.Context) error { - db := i.Gorm.WithContext(ctx) +func (i *Instance) AddNewAssets(assets []models.Asset) error { if len(assets) == 0 { return nil } @@ -24,7 +22,7 @@ func (i *Instance) AddNewAssets(assets []models.Asset, ctx context.Context) erro var notInMemoryAssets []models.Asset for _, a := range uniqueAssets { - _, err := i.MemoryGet(a.Asset, ctx) + _, err := i.MemoryGet(a.Asset) if err != nil { notInMemoryAssets = append(notInMemoryAssets, a) } @@ -33,13 +31,13 @@ func (i *Instance) AddNewAssets(assets []models.Asset, ctx context.Context) erro return nil } - existingAssets, err := i.GetAssetsByIDs(models.AssetIDs(notInMemoryAssets), ctx) + existingAssets, err := i.GetAssetsByIDs(models.AssetIDs(notInMemoryAssets)) if err != nil { return err } if len(existingAssets) == 0 { - i.addToMemory(notInMemoryAssets, ctx) - return db.Clauses(clause.OnConflict{DoNothing: true}).Create(¬InMemoryAssets).Error + i.addToMemory(notInMemoryAssets) + return i.Gorm.Clauses(clause.OnConflict{DoNothing: true}).Create(¬InMemoryAssets).Error } allAssetsMap := make(map[string]models.Asset) for _, ua := range notInMemoryAssets { @@ -59,11 +57,11 @@ func (i *Instance) AddNewAssets(assets []models.Asset, ctx context.Context) erro if len(newAssets) == 0 { return nil } - i.addToMemory(newAssets, ctx) + i.addToMemory(newAssets) assetsBatch := assetsBatch(newAssets, batchCount) - return db.Transaction(func(tx *gorm.DB) error { + return i.Gorm.Transaction(func(tx *gorm.DB) error { for _, na := range assetsBatch { err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&na).Error if err != nil { @@ -74,42 +72,42 @@ func (i *Instance) AddNewAssets(assets []models.Asset, ctx context.Context) erro }) } -func (i *Instance) addToMemory(newAssets []models.Asset, ctx context.Context) { +func (i *Instance) addToMemory(newAssets []models.Asset) { for _, a := range newAssets { raw, err := json.Marshal(a) if err != nil { continue } - err = i.MemorySet(a.Asset, raw, gocache.NoExpiration, ctx) + err = i.MemorySet(a.Asset, raw, gocache.NoExpiration) if err != nil { continue } } } -func (i *Instance) GetAssetsByIDs(ids []string, ctx context.Context) ([]models.Asset, error) { - db := i.Gorm.WithContext(ctx) - // todo: look why nil and len 0 make db calls rn +func (i *Instance) GetAssetsByIDs(ids []string) ([]models.Asset, error) { + //TODO: look why nil and len 0 make db calls rn if len(ids) == 0 { return nil, nil } var dbAssets []models.Asset - if err := db.Where("asset in (?)", ids).Find(&dbAssets).Error; err != nil { + if err := i.Gorm. + Where("asset in (?)", ids). + Find(&dbAssets).Error; err != nil { return nil, err } return dbAssets, nil } -func (i *Instance) GetAssetsFrom(from time.Time, coin int, ctx context.Context) ([]models.Asset, error) { - db := i.Gorm.WithContext(ctx) +func (i *Instance) GetAssetsFrom(from time.Time, coin int) ([]models.Asset, error) { var dbAssets []models.Asset if coin == -1 { - if err := db.Find(&dbAssets, "created_at > ?", from).Error; err != nil { + if err := i.Gorm.Find(&dbAssets, "created_at > ?", from).Error; err != nil { return nil, err } } else { - if err := db.Find(&dbAssets, "created_at > ? and coin = ?", from, coin).Error; err != nil { + if err := i.Gorm.Find(&dbAssets, "created_at > ? and coin = ?", from, coin).Error; err != nil { return nil, err } } diff --git a/db/db.go b/db/db.go index bc27579af..e0afb2c44 100644 --- a/db/db.go +++ b/db/db.go @@ -1,11 +1,11 @@ package db import ( - "context" "errors" - "gorm.io/gorm/logger" "time" + "gorm.io/gorm/logger" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db/models" @@ -54,7 +54,7 @@ func New(url string, log bool) (*Instance, error) { return i, nil } -func (i *Instance) RestoreConnectionWorker(ctx context.Context, timeout time.Duration, uri string) { +func (i *Instance) RestoreConnectionWorker(timeout time.Duration, uri string) { log.Info("Run PG RestoreConnectionWorker") for { @@ -85,12 +85,12 @@ func (i *Instance) restoreConnection(uri string) error { return nil } -func (i *Instance) MemorySet(key string, data []byte, exp time.Duration, ctx context.Context) error { +func (i *Instance) MemorySet(key string, data []byte, exp time.Duration) error { i.MemoryCache.Set(key, data, exp) return nil } -func (i *Instance) MemoryGet(key string, ctx context.Context) ([]byte, error) { +func (i *Instance) MemoryGet(key string) ([]byte, error) { res, ok := i.MemoryCache.Get(key) if !ok { return nil, errors.New("not found") diff --git a/db/notification.go b/db/notification.go index 9b7c07fda..bfa72b916 100644 --- a/db/notification.go +++ b/db/notification.go @@ -1,33 +1,31 @@ package db import ( - "context" "errors" + "github.com/trustwallet/blockatlas/db/models" "gorm.io/gorm" "gorm.io/gorm/clause" ) -func (i *Instance) GetSubscriptionsForNotifications(addresses []string, ctx context.Context) ([]models.NotificationSubscription, error) { +func (i *Instance) GetSubscriptionsForNotifications(addresses []string) ([]models.NotificationSubscription, error) { if len(addresses) == 0 { return nil, errors.New("Empty addresses") } - db := i.Gorm.WithContext(ctx) var subscriptionsDataList []models.NotificationSubscription - err := db.Joins("Address").Limit(len(addresses)).Find(&subscriptionsDataList, "address in (?)", addresses).Error + err := i.Gorm.Joins("Address").Limit(len(addresses)).Find(&subscriptionsDataList, "address in (?)", addresses).Error if err != nil { return nil, err } return subscriptionsDataList, nil } -func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx context.Context) error { +func (i *Instance) AddSubscriptionsForNotifications(addresses []string) error { if len(addresses) == 0 { return errors.New("Empty subscriptions") } - db := i.Gorm.WithContext(ctx) - return db.Transaction(func(tx *gorm.DB) error { + return i.Gorm.Transaction(func(tx *gorm.DB) error { uniqueAddresses := getUniqueStrings(addresses) uniqueAddressesModel := make([]models.Address, 0, len(uniqueAddresses)) for _, a := range uniqueAddresses { @@ -63,10 +61,10 @@ func (i *Instance) AddSubscriptionsForNotifications(addresses []string, ctx cont }) } -func (i *Instance) DeleteSubscriptionsForNotifications(addresses []string, ctx context.Context) error { +func (i *Instance) DeleteSubscriptionsForNotifications(addresses []string) error { if len(addresses) == 0 { return errors.New("Empty subscriptions") } q := `DELETE FROM notification_subscriptions ns USING addresses a where ns.address_id = a.id AND a.address IN (?);` - return i.Gorm.WithContext(ctx).Exec(q, addresses).Error + return i.Gorm.Exec(q, addresses).Error } diff --git a/db/tracker.go b/db/tracker.go index a55ddd7a1..fb2bafc4c 100644 --- a/db/tracker.go +++ b/db/tracker.go @@ -1,10 +1,10 @@ package db import ( - "context" + "sync" + "github.com/trustwallet/blockatlas/db/models" "gorm.io/gorm/clause" - "sync" ) var memoryCache heightBlockMap @@ -31,27 +31,26 @@ func (hbm *heightBlockMap) GetHeight(coin string) (int64, bool) { return b, ok } -func (i *Instance) GetLastParsedBlockNumber(coin string, ctx context.Context) (int64, error) { +func (i *Instance) GetLastParsedBlockNumber(coin string) (int64, error) { height, ok := memoryCache.GetHeight(coin) if ok { return height, nil } var tracker models.Tracker - db := i.Gorm.WithContext(ctx) - if err := db.Find(&tracker, "coin = ?", coin).Error; err != nil { + if err := i.Gorm. + Find(&tracker, "coin = ?", coin).Error; err != nil { return 0, nil } return tracker.Height, nil } -func (i *Instance) SetLastParsedBlockNumber(coin string, num int64, ctx context.Context) error { +func (i *Instance) SetLastParsedBlockNumber(coin string, num int64) error { memoryCache.SetHeight(coin, num) tracker := models.Tracker{ Coin: coin, Height: num, } - db := i.Gorm.WithContext(ctx) - return db.Clauses(clause.OnConflict{ + return i.Gorm.Clauses(clause.OnConflict{ Columns: []clause.Column{ { Name: "coin", diff --git a/go.mod b/go.mod index f48a4c362..bf5364610 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/containerd/continuity v0.0.0-20201204194424-b0f312dbb49a // indirect + github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 // indirect github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect @@ -34,13 +34,10 @@ require ( github.com/swaggo/swag v1.6.9 github.com/trustwallet/golibs v0.0.17 github.com/trustwallet/golibs-networking v0.0.5 - go.elastic.co/apm v1.9.0 - go.elastic.co/apm/module/apmgin v1.9.0 - go.elastic.co/apm/module/apmhttp v1.9.0 go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 - golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect - golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect + golang.org/x/net v0.0.0-20201207224615-747e23833adb // indirect + golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.5 gorm.io/gorm v1.20.7 diff --git a/go.sum b/go.sum index 2efa8abdd..d534608b2 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 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/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= -github.com/armon/go-radix v1.0.0/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/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -57,13 +55,12 @@ github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEe github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/containerd/continuity v0.0.0-20201204194424-b0f312dbb49a h1:SsffDYRSRlPV6Jcm8QpjPnRmiQ1265amULS37h+bwyg= -github.com/containerd/continuity v0.0.0-20201204194424-b0f312dbb49a/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 h1:6ejg6Lkk8dskcM7wQ28gONkukbQkM4qpj4RnYbpFzrI= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -72,8 +69,6 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/cucumber/godog v0.8.1 h1:lVb+X41I4YDreE+ibZ50bdXmySxgRviYFgKY6Aw4XE8= -github.com/cucumber/godog v0.8.1/go.mod h1:vSh3r/lM+psC1BPXvdkSEuNjmXfpVqrMGYAElF6hxnA= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -87,10 +82,6 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elastic/go-sysinfo v1.1.1 h1:ZVlaLDyhVkDfjwPGU55CQRCRolNpc7P0BbyhhQZQmMI= -github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= -github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= -github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/evalphobia/logrus_sentry v0.8.2 h1:dotxHq+YLZsT1Bb45bB5UQbfCh3gM/nFFetyN46VoDQ= github.com/evalphobia/logrus_sentry v0.8.2/go.mod h1:pKcp+vriitUqu9KiWj/VRFbRfFNUwz95/UkgG8a6MNc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -261,13 +252,10 @@ github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -319,7 +307,6 @@ 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= @@ -371,10 +358,7 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 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-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= 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= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -383,8 +367,6 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= -github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -454,17 +436,8 @@ github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCB github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.elastic.co/apm v1.9.0 h1:uLOZniTuJ2rU2fFGiNI0ZswzKr9fryHDkNMV8iVDDDI= -go.elastic.co/apm v1.9.0/go.mod h1:qoOSi09pnzJDh5fKnfY7bPmQgl8yl2tULdOu03xhui0= -go.elastic.co/apm/module/apmgin v1.9.0 h1:t3MP9pVZ1eMzIhBNl+jiMot9D+VqqFGpxuuhuiir5nw= -go.elastic.co/apm/module/apmgin v1.9.0/go.mod h1:ypUDMdqnVGK2bBjmuuyQg/1D9XE3DT6F0abehLN0tZc= -go.elastic.co/apm/module/apmhttp v1.9.0 h1:yAsxgx5bzWTFva1MJ1PqwhKsPUAUARPJ/sXIwv+uqvs= -go.elastic.co/apm/module/apmhttp v1.9.0/go.mod h1:evGjj1bVDqi47Lg2+/uKre/PDSBrOso/eTRrgeJqZyE= -go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4= -go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -512,7 +485,6 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -534,11 +506,9 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201207224615-747e23833adb h1:xj2oMIbduz83x7tzglytWT7spn6rP+9hvKjTpro6/pM= +golang.org/x/net v0.0.0-20201207224615-747e23833adb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -547,7 +517,6 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -571,19 +540,16 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso= -golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d h1:MiWWjyhUzZ+jvhZvloX6ZrUsdEghn8a64Upd8EMHglE= +golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -616,7 +582,6 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac h1:DugppSxw0LSF8lcjaODPJZoDzq0ElTGskTst3ZaBkHI= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -689,6 +654,4 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= -howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/internal/init.go b/internal/init.go index f1bada34e..c556c6720 100644 --- a/internal/init.go +++ b/internal/init.go @@ -2,13 +2,13 @@ package internal import ( "flag" + "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" "github.com/gin-contrib/cors" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/mq" - "go.elastic.co/apm/module/apmgin" "path/filepath" "time" @@ -45,8 +45,6 @@ func InitEngine(ginMode string) *gin.Engine { engine := gin.New() engine.Use(cors.Default()) - - engine.Use(apmgin.Middleware(engine)) engine.Use(gin.Logger()) return engine diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go index b468328a5..fb2fce3c6 100644 --- a/pkg/blockatlas/client.go +++ b/pkg/blockatlas/client.go @@ -5,7 +5,6 @@ import ( "context" "encoding/json" "fmt" - "go.elastic.co/apm/module/apmhttp" "io" "io/ioutil" "net/http" @@ -101,9 +100,7 @@ func (r *Request) Execute(method string, url string, body io.Reader, result inte req.Header.Set(key, value) } - c := apmhttp.WrapClient(r.HttpClient) - - res, err := c.Do(req.WithContext(ctx)) + res, err := r.HttpClient.Do(req) if err != nil { return err } diff --git a/services/notifier/base.go b/services/notifier/base.go index 2b57ce739..cd951de0c 100644 --- a/services/notifier/base.go +++ b/services/notifier/base.go @@ -1,14 +1,12 @@ package notifier import ( - "context" + "strconv" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/pkg/address" - "strconv" - - "go.elastic.co/apm" ) const ( @@ -20,17 +18,13 @@ const ( var MaxPushNotificationsBatchLimit uint = DefaultPushNotificationsBatchLimit func RunNotifier(database *db.Instance, delivery amqp.Delivery) { - tx := apm.DefaultTracer.StartTransaction("RunNotifier", "app") - defer tx.End() - ctx := apm.ContextWithTransaction(context.Background(), tx) - defer func() { if err := delivery.Ack(false); err != nil { log.WithFields(log.Fields{"service": Notifier}).Error(err) } }() - txs, err := GetTransactionsFromDelivery(delivery, Notifier, ctx) + txs, err := GetTransactionsFromDelivery(delivery, Notifier) if err != nil { log.Error("failed to get transactions", err) } @@ -48,7 +42,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { if len(txs) < 1 { return } - subscriptionsDataList, err := database.GetSubscriptionsForNotifications(addresses, ctx) + subscriptionsDataList, err := database.GetSubscriptionsForNotifications(addresses) if err != nil || len(subscriptionsDataList) == 0 { return } @@ -59,14 +53,14 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { if !ok { continue } - notificationsForAddress := buildNotificationsByAddress(ua, txs, ctx) + notificationsForAddress := buildNotificationsByAddress(ua, txs) notifications = append(notifications, notificationsForAddress...) } - batches := getNotificationBatches(notifications, MaxPushNotificationsBatchLimit, ctx) + batches := getNotificationBatches(notifications, MaxPushNotificationsBatchLimit) for _, batch := range batches { - publishNotificationBatch(batch, ctx) + publishNotificationBatch(batch) } log.Info("------------------------------------------------------------") } diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index c5bd6d58b..36f47250d 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -1,7 +1,6 @@ package notifier import ( - "context" "encoding/json" "errors" @@ -11,15 +10,11 @@ import ( "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "go.elastic.co/apm" ) -func GetTransactionsFromDelivery(delivery amqp.Delivery, service string, ctx context.Context) (blockatlas.Txs, error) { +func GetTransactionsFromDelivery(delivery amqp.Delivery, service string) (blockatlas.Txs, error) { var txs blockatlas.Txs - span, _ := apm.StartSpan(ctx, "GetTransactionsFromDelivery", "app") - defer span.End() - if err := json.Unmarshal(delivery.Body, &txs); err != nil { return nil, err } @@ -33,10 +28,7 @@ func GetTransactionsFromDelivery(delivery amqp.Delivery, service string, ctx con return txs, nil } -func publishNotificationBatch(batch []TransactionNotification, ctx context.Context) { - span, _ := apm.StartSpan(ctx, "getNotificationBatches", "app") - defer span.End() - +func publishNotificationBatch(batch []TransactionNotification) { raw, err := json.Marshal(batch) if err != nil { log.Fatal("publishNotificationBatch marshal: ", err) diff --git a/services/notifier/models.go b/services/notifier/models.go index 9227ab54c..b60f8194a 100644 --- a/services/notifier/models.go +++ b/services/notifier/models.go @@ -1,9 +1,7 @@ package notifier import ( - "context" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "go.elastic.co/apm" ) type TransactionNotification struct { @@ -11,9 +9,7 @@ type TransactionNotification struct { Result blockatlas.Tx `json:"result"` } -func getNotificationBatches(notifications []TransactionNotification, sizeUint uint, ctx context.Context) [][]TransactionNotification { - span, _ := apm.StartSpan(ctx, "getNotificationBatches", "app") - defer span.End() +func getNotificationBatches(notifications []TransactionNotification, sizeUint uint) [][]TransactionNotification { size := int(sizeUint) resultLength := (len(notifications) + size - 1) / size result := make([][]TransactionNotification, resultLength) @@ -28,10 +24,7 @@ func getNotificationBatches(notifications []TransactionNotification, sizeUint ui return result } -func buildNotificationsByAddress(address string, txs blockatlas.Txs, ctx context.Context) []TransactionNotification { - span, _ := apm.StartSpan(ctx, "buildNotification", "app") - defer span.End() - +func buildNotificationsByAddress(address string, txs blockatlas.Txs) []TransactionNotification { transactionsByAddress := toUniqueTransactions(findTransactionsByAddress(txs, address)) result := make([]TransactionNotification, 0, len(transactionsByAddress)) diff --git a/services/notifier/models_test.go b/services/notifier/models_test.go index fb2cf7dfe..b1aa6279b 100644 --- a/services/notifier/models_test.go +++ b/services/notifier/models_test.go @@ -1,12 +1,12 @@ package notifier import ( - "context" + "sort" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "sort" - "testing" ) var ( @@ -137,7 +137,7 @@ func Test_findTransactionsByAddress(t *testing.T) { } func Test_buildNotificationsByAddress(t *testing.T) { - notifications := buildNotificationsByAddress("tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", []blockatlas.Tx{nativeTokenTransfer, tokenTransfer}, context.Background()) + notifications := buildNotificationsByAddress("tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", []blockatlas.Tx{nativeTokenTransfer, tokenTransfer}) sort.Slice(notifications, func(i, j int) bool { return notifications[i].Action < notifications[j].Action }) diff --git a/services/parser/parser.go b/services/parser/parser.go index 0a9e209e8..3efe20af5 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -7,17 +7,16 @@ import ( "fmt" "sync/atomic" - "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/numbers" - "go.elastic.co/apm" - "math/rand" "sort" "sync" "time" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/numbers" + log "github.com/sirupsen/logrus" ) @@ -68,21 +67,16 @@ func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duratio } func parse(params Params) { - tx := apm.DefaultTracer.StartTransaction("parse", "app") - defer tx.End() - - ctx := apm.ContextWithTransaction(context.Background(), tx) - - lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params, ctx) + lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params) if err != nil || lastParsedBlock > currentBlock { log.WithFields(log.Fields{"operation": "fetch GetBlocksIntervalToFetch", "lastParsedBlock": lastParsedBlock, "currentBlock": currentBlock, "coin": params.Api.Coin().Handle}).Error(err) time.Sleep(params.ParsingBlocksInterval) return } - blocks := FetchBlocks(params, lastParsedBlock, currentBlock, ctx) + blocks := FetchBlocks(params, lastParsedBlock, currentBlock) - err = SaveLastParsedBlock(params, blocks, ctx) + err = SaveLastParsedBlock(params, blocks) if err != nil { log.WithFields(log.Fields{"operation": "run SaveLastParsedBlock", "coin": params.Api.Coin().Handle}).Error(err) time.Sleep(params.ParsingBlocksInterval) @@ -92,16 +86,13 @@ func parse(params Params) { txs := ConvertToBatch(blocks) txs = blockatlas.Txs(blockatlas.TxPage(txs).FilterTransactionsByMemo()) - PublishTransactionsBatch(params, txs, ctx) + PublishTransactionsBatch(params, txs) log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Info("End of parse step") } -func GetBlocksIntervalToFetch(params Params, ctx context.Context) (int64, int64, error) { - span, ctx := apm.StartSpan(ctx, "GetBlocksIntervalToFetch", "app") - defer span.End() - - lastParsedBlock, err := params.Database.GetLastParsedBlockNumber(params.Api.Coin().Handle, ctx) +func GetBlocksIntervalToFetch(params Params) (int64, int64, error) { + lastParsedBlock, err := params.Database.GetLastParsedBlockNumber(params.Api.Coin().Handle) if err != nil { return 0, 0, errors.New(err.Error() + " Polling failed: tracker didn't return last known block number") } @@ -121,10 +112,7 @@ func GetBlocksIntervalToFetch(params Params, ctx context.Context) (int64, int64, return lastParsedBlock, currentBlock, nil } -func FetchBlocks(params Params, lastParsedBlock, currentBlock int64, ctx context.Context) []blockatlas.Block { - span, ctx := apm.StartSpan(ctx, "FetchBlocks", "app") - defer span.End() - +func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatlas.Block { if lastParsedBlock == currentBlock { log.WithFields(log.Fields{"last": lastParsedBlock, "coin": params.Api.Coin().Handle, "time": time.Now().Unix()}). Info("No new blocks") @@ -149,7 +137,7 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64, ctx context time.Sleep(params.FetchBlocksTimeout) go func(i int64, wg *sync.WaitGroup) { defer wg.Done() - err := fetchBlock(params.Api, i, blocksChan, ctx) + err := fetchBlock(params.Api, i, blocksChan) if err != nil { errorsChan <- err return @@ -182,10 +170,8 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64, ctx context return blocksList } -func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas.Block, ctx context.Context) error { - span, ctx := apm.StartSpan(ctx, "fetchBlock", "app") - defer span.End() - block, err := getBlockByNumberWithRetry(5, time.Second*5, api.GetBlockByNumber, num, api.Coin().Symbol, ctx) +func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas.Block) error { + block, err := getBlockByNumberWithRetry(5, time.Second*5, api.GetBlockByNumber, num, api.Coin().Symbol) if err != nil { return fmt.Errorf("%d", num) } @@ -193,10 +179,7 @@ func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas return nil } -func SaveLastParsedBlock(params Params, blocks []blockatlas.Block, ctx context.Context) error { - span, ctx := apm.StartSpan(ctx, "SaveLastParsedBlock", "app") - defer span.End() - +func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { if len(blocks) == 0 { return nil } @@ -213,7 +196,7 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block, ctx context.C return fmt.Errorf("parser of %s failed to save last block, lastBlockNumber <= 0", params.Api.Coin().Handle) } - err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().Handle, lastBlockNumber, ctx) + err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().Handle, lastBlockNumber) if err != nil { return err } @@ -237,27 +220,21 @@ func ConvertToBatch(blocks []blockatlas.Block) blockatlas.Txs { return txs } -func PublishTransactionsBatch(params Params, txs blockatlas.Txs, ctx context.Context) { - span, ctx := apm.StartSpan(ctx, "PublishTransactionsBatch", "app") - defer span.End() - +func PublishTransactionsBatch(params Params, txs blockatlas.Txs) { if len(txs) == 0 { return } - batches := getTxsBatches(txs, params.TxBatchLimit, ctx) + batches := getTxsBatches(txs, params.TxBatchLimit) for _, batch := range batches { - publish(params, batch, ctx) + publish(params, batch) } log.WithFields(log.Fields{"txs": len(txs), "batchCount": len(batches)}).Info("Published transactions batch") } -func getTxsBatches(txs blockatlas.Txs, sizeUint uint, ctx context.Context) []blockatlas.Txs { - span, _ := apm.StartSpan(ctx, "getTxsBatches", "app") - defer span.End() - +func getTxsBatches(txs blockatlas.Txs, sizeUint uint) []blockatlas.Txs { size := int(sizeUint) resultLength := (len(txs) + size - 1) / size result := make([]blockatlas.Txs, resultLength) @@ -272,10 +249,7 @@ func getTxsBatches(txs blockatlas.Txs, sizeUint uint, ctx context.Context) []blo return result } -func publish(params Params, txs blockatlas.Txs, ctx context.Context) { - span, _ := apm.StartSpan(ctx, "publish", "app") - defer span.End() - +func publish(params Params, txs blockatlas.Txs) { body, err := json.Marshal(txs) if err != nil { log.WithFields(log.Fields{"operation": "publish marshal", "coin": params.Api.Coin().Handle}).Error(err) @@ -316,9 +290,7 @@ func publish(params Params, txs blockatlas.Txs, ctx context.Context) { } } -func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64, symbol string, ctx context.Context) (*blockatlas.Block, error) { - span, ctx := apm.StartSpan(ctx, "getBlockByNumberWithRetry", "app") - defer span.End() +func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64, symbol string) (*blockatlas.Block, error) { r, err := getBlockByNumber(n) if err != nil { if s, ok := err.(stop); ok { @@ -334,7 +306,7 @@ func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumb Warn("retry GetBlockByNumber") time.Sleep(sleep) - return getBlockByNumberWithRetry(attempts, sleep*2, getBlockByNumber, n, symbol, ctx) + return getBlockByNumberWithRetry(attempts, sleep*2, getBlockByNumber, n, symbol) } } return r, err diff --git a/services/parser/parser_test.go b/services/parser/parser_test.go index ac6ecdf91..20a268cd0 100644 --- a/services/parser/parser_test.go +++ b/services/parser/parser_test.go @@ -1,7 +1,6 @@ package parser import ( - "context" "errors" "reflect" "testing" @@ -57,12 +56,12 @@ func TestFetchBlocks(t *testing.T) { TxBatchLimit: 0, Database: nil, } - blocks := FetchBlocks(params, 0, 100, context.Background()) + blocks := FetchBlocks(params, 0, 100) assert.Equal(t, len(blocks), 100) } func TestParser_getBlockByNumberWithRetry(t *testing.T) { - block, err := getBlockByNumberWithRetry(3, time.Millisecond*1, getBlock, 1, "", context.Background()) + block, err := getBlockByNumberWithRetry(3, time.Millisecond*1, getBlock, 1, "") if err != nil { t.Error(err) } @@ -74,7 +73,7 @@ func TestParser_getBlockByNumberWithRetry(t *testing.T) { func TestParser_getBlockByNumberWithRetry_Error(t *testing.T) { now := time.Now() - block, err := getBlockByNumberWithRetry(2, time.Millisecond*2, getBlock, 0, "", context.Background()) + block, err := getBlockByNumberWithRetry(2, time.Millisecond*2, getBlock, 0, "") elapsed := time.Since(now) if err == nil { t.Error("getBlockByNumberWithRetry method need fail") @@ -119,36 +118,36 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { func TestGetTxBatches(t *testing.T) { txs := make(blockatlas.Txs, 10000) - batches := getTxsBatches(txs, 1000, context.Background()) + batches := getTxsBatches(txs, 1000) assert.Len(t, batches, 10) - batches = getTxsBatches(txs, 100, context.Background()) + batches = getTxsBatches(txs, 100) assert.Len(t, batches, 100) - batches = getTxsBatches(txs, 500, context.Background()) + batches = getTxsBatches(txs, 500) assert.Len(t, batches, 20) txs = make(blockatlas.Txs, 3800) - batches = getTxsBatches(txs, 100, context.Background()) + batches = getTxsBatches(txs, 100) assert.Len(t, batches, 38) - batches = getTxsBatches(txs, 1000, context.Background()) + batches = getTxsBatches(txs, 1000) assert.Len(t, batches, 4) txs = make(blockatlas.Txs, 5000) - batches = getTxsBatches(txs, 10000, context.Background()) + batches = getTxsBatches(txs, 10000) assert.Len(t, batches, 1) txs = make(blockatlas.Txs, 0) - batches = getTxsBatches(txs, 100, context.Background()) + batches = getTxsBatches(txs, 100) assert.Len(t, batches, 0) txs = make(blockatlas.Txs, 0) - batches = getTxsBatches(txs, 100, context.Background()) + batches = getTxsBatches(txs, 100) assert.Len(t, batches, 0) - batches = getTxsBatches(nil, 100, context.Background()) + batches = getTxsBatches(nil, 100) assert.Len(t, batches, 0) txs = make(blockatlas.Txs, 1000000) - batches = getTxsBatches(txs, 5000, context.Background()) + batches = getTxsBatches(txs, 5000) assert.Len(t, batches, 200) } diff --git a/services/subscriber/tokens.go b/services/subscriber/tokens.go index b4692ee80..6b95a686c 100644 --- a/services/subscriber/tokens.go +++ b/services/subscriber/tokens.go @@ -1,22 +1,17 @@ package subscriber import ( - "context" "encoding/json" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" - "go.elastic.co/apm" ) const Tokens Subscriber = "tokens" func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { - tx := apm.DefaultTracer.StartTransaction("RunTokensSubscriber", "app") - defer tx.End() - - ctx := apm.ContextWithTransaction(context.Background(), tx) event := make(map[string][]models.Asset) if err := json.Unmarshal(delivery.Body, &event); err != nil { if err := delivery.Ack(false); err != nil { @@ -25,7 +20,7 @@ func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { } for address, assets := range event { - if err := database.AddAssociationsForAddress(address, assets, ctx); err != nil { + if err := database.AddAssociationsForAddress(address, assets); err != nil { log.Error("Failed to AddAssociationsForAddress: " + err.Error()) } } diff --git a/services/subscriber/transactions.go b/services/subscriber/transactions.go index b100efaeb..f9cc7bfab 100644 --- a/services/subscriber/transactions.go +++ b/services/subscriber/transactions.go @@ -1,14 +1,13 @@ package subscriber import ( - "context" "encoding/json" + "strconv" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "go.elastic.co/apm" - "strconv" ) type Subscriber string @@ -23,11 +22,6 @@ const ( ) func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { - tx := apm.DefaultTracer.StartTransaction("RunTransactionsSubscriber", "app") - defer tx.End() - - ctx := apm.ContextWithTransaction(context.Background(), tx) - var event blockatlas.SubscriptionEvent err := json.Unmarshal(delivery.Body, &event) if err != nil { @@ -40,7 +34,7 @@ func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { allSubs := ToSubscriptionData(subscriptions) batchedSubs := toBatch(allSubs, batchLimit) for _, subs := range batchedSubs { - err := database.AddSubscriptionsForNotifications(subs, ctx) + err := database.AddSubscriptionsForNotifications(subs) if err != nil { log.WithFields( log.Fields{"service": Notifications, @@ -61,7 +55,7 @@ func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { allSubs := ToSubscriptionData(subscriptions) batchedSubs := toBatch(allSubs, batchLimit) for _, subs := range batchedSubs { - err := database.DeleteSubscriptionsForNotifications(subs, ctx) + err := database.DeleteSubscriptionsForNotifications(subs) if err != nil { log.WithFields( log.Fields{"service": Notifications, diff --git a/services/tokenindexer/api.go b/services/tokenindexer/api.go index 7438b1f76..87d8690c6 100644 --- a/services/tokenindexer/api.go +++ b/services/tokenindexer/api.go @@ -1,10 +1,10 @@ package tokenindexer import ( - "context" + "time" + "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" - "time" ) type Instance struct { @@ -15,9 +15,9 @@ func Init(database *db.Instance) Instance { return Instance{database: database} } -func (i Instance) HandleNewTokensRequest(r Request, ctx context.Context) (Response, error) { +func (i Instance) HandleNewTokensRequest(r Request) (Response, error) { from := time.Unix(r.From, 0) - result, err := i.database.GetAssetsFrom(from, r.Coin, ctx) + result, err := i.database.GetAssetsFrom(from, r.Coin) if err != nil { return Response{}, err } diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index a9c3d8414..7bcf5fa43 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -1,29 +1,24 @@ package tokenindexer import ( - "context" log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/notifier" - "go.elastic.co/apm" ) const TokenIndexer = "TokenIndexer" func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) { - tx := apm.DefaultTracer.StartTransaction("RunTokenIndexer", "app") - defer tx.End() defer func() { if err := delivery.Ack(false); err != nil { log.WithFields(log.Fields{"service": TokenIndexer}).Error(err) } }() - ctx := apm.ContextWithTransaction(context.Background(), tx) - txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenIndexer, ctx) + txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenIndexer) if err != nil { log.WithFields(log.Fields{"service": TokenIndexer}).Error("failed to get transactions", err) if err := delivery.Ack(false); err != nil { @@ -36,7 +31,7 @@ func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) { } assets := GetAssetsFromTransactions(txs) - err = database.AddNewAssets(assets, ctx) + err = database.AddNewAssets(assets) if err != nil { log.WithFields(log.Fields{"service": TokenIndexer}).Error("failed to add assets", err) return diff --git a/services/tokensearcher/api.go b/services/tokensearcher/api.go index 33e18725e..2d776fa38 100644 --- a/services/tokensearcher/api.go +++ b/services/tokensearcher/api.go @@ -1,7 +1,6 @@ package tokensearcher import ( - "context" "encoding/json" "strconv" "sync" @@ -34,13 +33,13 @@ func Init(database *db.Instance, apis map[uint]blockatlas.TokensAPI, queue mq.Qu return Instance{database: database, apis: apis, queue: queue} } -func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (map[string][]string, error) { +func (i Instance) HandleTokensRequest(request Request) (map[string][]string, error) { addresses := getAddressesFromRequest(request) if len(addresses) == 0 { return nil, nil } - subscribedAddresses, err := getSubscribedAddresses(i.database, addresses, ctx) + subscribedAddresses, err := getSubscribedAddresses(i.database, addresses) if err != nil { return nil, err } @@ -48,10 +47,7 @@ func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (map unsubscribedAddresses := getUnsubscribedAddresses(subscribedAddresses, addresses) log.Info("unsubscribedAddresses " + strconv.Itoa(len(unsubscribedAddresses))) - assetsFromDB, err := i.database.GetAssetsMapByAddressesFromTime( - subscribedAddresses, - time.Unix(int64(request.From), 0), - ctx) + assetsFromDB, err := i.database.GetAssetsMapByAddressesFromTime(subscribedAddresses, time.Unix(int64(request.From), 0)) if err != nil { return nil, err } @@ -69,8 +65,8 @@ func (i Instance) HandleTokensRequest(request Request, ctx context.Context) (map return getAssetsToResponse(assetsFromDB, assetsFromNodes, addresses), nil } -func getSubscribedAddresses(database *db.Instance, addresses []string, ctx context.Context) ([]string, error) { - subscribedAddressesModel, err := database.GetSubscribedAddressesForAssets(ctx, addresses) +func getSubscribedAddresses(database *db.Instance, addresses []string) ([]string, error) { + subscribedAddressesModel, err := database.GetSubscribedAddressesForAssets(addresses) if err != nil { return nil, err } diff --git a/services/tokensearcher/tokensearcher.go b/services/tokensearcher/tokensearcher.go index 73734667d..84bc3a38c 100644 --- a/services/tokensearcher/tokensearcher.go +++ b/services/tokensearcher/tokensearcher.go @@ -1,23 +1,18 @@ package tokensearcher import ( - "context" + "strconv" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/services/notifier" - "go.elastic.co/apm" - "strconv" ) const TokenSearcher = "TokenSearcher" func Run(database *db.Instance, delivery amqp.Delivery) { - tx := apm.DefaultTracer.StartTransaction("RunNotifier", "app") - defer tx.End() - ctx := apm.ContextWithTransaction(context.Background(), tx) - - txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenSearcher, ctx) + txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenSearcher) if err != nil { log.Error("failed to get transactions", err) if err := delivery.Ack(false); err != nil { @@ -36,7 +31,7 @@ func Run(database *db.Instance, delivery amqp.Delivery) { addresses[i] = coinID + "_" + addresses[i] } - associationsFromTransactions, err := database.GetAssociationsByAddresses(notifier.ToUniqueAddresses(addresses), ctx) + associationsFromTransactions, err := database.GetAssociationsByAddresses(notifier.ToUniqueAddresses(addresses)) if err != nil { log.Error(err) return @@ -48,7 +43,7 @@ func Run(database *db.Instance, delivery amqp.Delivery) { log.WithFields(log.Fields{"service": TokenSearcher}). Info("AssociationsToAdd " + strconv.Itoa(len(associationsToAdd))) - err = database.UpdateAssociationsForExistingAddresses(associationsToAdd, ctx) + err = database.UpdateAssociationsForExistingAddresses(associationsToAdd) if err != nil { log.Error(err) return diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go index 34f503da1..f28adc066 100644 --- a/tests/integration/db_test/subscriptions_test.go +++ b/tests/integration/db_test/subscriptions_test.go @@ -3,12 +3,12 @@ package db_test import ( - "context" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/subscriber" "github.com/trustwallet/blockatlas/tests/integration/setup" - "testing" ) func TestDb_AddSubscriptionsBulk(t *testing.T) { @@ -19,9 +19,9 @@ func TestDb_AddSubscriptionsBulk(t *testing.T) { subscriptions = append(subscriptions, "testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr") } - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriptions)) for i := 0; i < 100; i++ { - s, err := database.GetSubscriptionsForNotifications([]string{"testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr"}, context.Background()) + s, err := database.GetSubscriptionsForNotifications([]string{"testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr"}) assert.Nil(t, err) assert.NotNil(t, s) } @@ -30,21 +30,21 @@ func TestDb_AddSubscriptionsBulk(t *testing.T) { func TestDb_AddSubscriptions(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - assert.Nil(t, database.AddSubscriptionsForNotifications([]string{"60_testAddr", "60_testAddr2", "60_testAddr3"}, context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications([]string{"60_testAddr", "60_testAddr2", "60_testAddr3"})) - subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) + subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) assert.Equal(t, "60_testAddr", subs[0].Address.Address) - subs, err = database.GetSubscriptionsForNotifications([]string{"60_testAddr2"}, context.Background()) + subs, err = database.GetSubscriptionsForNotifications([]string{"60_testAddr2"}) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) assert.Equal(t, "60_testAddr2", subs[0].Address.Address) - subs, err = database.GetSubscriptionsForNotifications([]string{"60_testAddr3"}, context.Background()) + subs, err = database.GetSubscriptionsForNotifications([]string{"60_testAddr3"}) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) @@ -81,32 +81,32 @@ func TestDb_FindSubscriptions(t *testing.T) { Address: "ETCAddress", }) - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptionsA), context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptionsA))) var subscriptionsB []blockatlas.Subscription for _, sub := range subscriptionsA { subscriptionsB = append(subscriptionsB, sub) } - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptionsB), context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptionsB))) - returnedSubs, err := database.GetSubscriptionsForNotifications([]string{"60_etherAddress"}, context.Background()) + returnedSubs, err := database.GetSubscriptionsForNotifications([]string{"60_etherAddress"}) assert.Nil(t, err) assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"714_binanceAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"714_binanceAddress"}) assert.Nil(t, err) assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"144_XLMAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"144_XLMAddress"}) assert.Nil(t, err) assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"148_AtomAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"148_AtomAddress"}) assert.Nil(t, err) assert.Equal(t, 1, len(returnedSubs)) - returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"61_ETCAddress"}, context.Background()) + returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"61_ETCAddress"}) assert.Nil(t, err) assert.Equal(t, 1, len(returnedSubs)) } @@ -119,36 +119,36 @@ func TestDb_DeleteSubscriptions(t *testing.T) { "144_testAddr3", } - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriptions, context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriptions)) - subs60, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) + subs60, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) assert.Nil(t, err) assert.NotNil(t, subs60) assert.Equal(t, 1, len(subs60)) - subs714, err := database.GetSubscriptionsForNotifications([]string{"714_testAddr2"}, context.Background()) + subs714, err := database.GetSubscriptionsForNotifications([]string{"714_testAddr2"}) assert.Nil(t, err) assert.NotNil(t, subs714) assert.Equal(t, 1, len(subs714)) - subs144, err := database.GetSubscriptionsForNotifications([]string{"144_testAddr3"}, context.Background()) + subs144, err := database.GetSubscriptionsForNotifications([]string{"144_testAddr3"}) assert.Nil(t, err) assert.NotNil(t, subs144) assert.Equal(t, 1, len(subs144)) - assert.Nil(t, database.DeleteSubscriptionsForNotifications([]string{subscriptions[0]}, context.Background())) + assert.Nil(t, database.DeleteSubscriptionsForNotifications([]string{subscriptions[0]})) - subs714N2, err := database.GetSubscriptionsForNotifications([]string{"714_testAddr2"}, context.Background()) + subs714N2, err := database.GetSubscriptionsForNotifications([]string{"714_testAddr2"}) assert.Nil(t, err) assert.NotNil(t, subs714N2) assert.Equal(t, 1, len(subs714N2)) - subs144N2, err := database.GetSubscriptionsForNotifications([]string{"144_testAddr3"}, context.Background()) + subs144N2, err := database.GetSubscriptionsForNotifications([]string{"144_testAddr3"}) assert.Nil(t, err) assert.NotNil(t, subs144N2) assert.Equal(t, 1, len(subs144N2)) - subs60N2, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) + subs60N2, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) assert.Nil(t, err) assert.Len(t, subs60N2, 0) } @@ -164,9 +164,9 @@ func TestDb_DuplicateEntries(t *testing.T) { }) } - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions), context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions))) - subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) + subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) assert.Nil(t, err) assert.NotNil(t, subs) assert.Equal(t, 1, len(subs)) @@ -180,20 +180,20 @@ func TestDb_CreateDeleteCreate(t *testing.T) { Address: "testAddr", }) - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions), context.Background())) - subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions))) + subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) assert.Nil(t, err) assert.Equal(t, 1, len(subs)) - assert.Nil(t, database.DeleteSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background())) + assert.Nil(t, database.DeleteSubscriptionsForNotifications([]string{"60_testAddr"})) - subs2, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) + subs2, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) assert.Nil(t, err) assert.Equal(t, 0, len(subs2)) - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions), context.Background())) + assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions))) - subs3, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}, context.Background()) + subs3, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) assert.Nil(t, err) assert.Equal(t, 1, len(subs3)) } diff --git a/tests/integration/db_test/tokenassociations_test.go b/tests/integration/db_test/tokenassociations_test.go index 8b297b748..7398bb399 100644 --- a/tests/integration/db_test/tokenassociations_test.go +++ b/tests/integration/db_test/tokenassociations_test.go @@ -3,13 +3,13 @@ package db_test import ( - "context" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/tests/integration/setup" "sort" "testing" "time" + + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/tests/integration/setup" ) func Test_GetAssetsMapByAddresses(t *testing.T) { @@ -17,13 +17,13 @@ func Test_GetAssetsMapByAddresses(t *testing.T) { assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} - err := database.AddAssociationsForAddress("a", assets, context.Background()) + err := database.AddAssociationsForAddress("a", assets) assert.Nil(t, err) - err = database.AddAssociationsForAddress("b", nil, context.Background()) + err = database.AddAssociationsForAddress("b", nil) assert.Nil(t, err) - m, err := database.GetAssetsMapByAddresses([]string{"a", "b"}, context.Background()) + m, err := database.GetAssetsMapByAddresses([]string{"a", "b"}) assert.Nil(t, err) wantedMap := make(map[string][]models.Asset) wantedMap["a"] = assets @@ -40,13 +40,13 @@ func Test_GetAssetsMapByAddressesFromTime(t *testing.T) { assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} - err := database.AddAssociationsForAddress("a", assets, context.Background()) + err := database.AddAssociationsForAddress("a", assets) assert.Nil(t, err) - err = database.AddAssociationsForAddress("b", nil, context.Background()) + err = database.AddAssociationsForAddress("b", nil) assert.Nil(t, err) tm := time.Now().Unix() - 100 - m, err := database.GetAssetsMapByAddressesFromTime([]string{"a", "b"}, time.Unix(tm, 0), context.Background()) + m, err := database.GetAssetsMapByAddressesFromTime([]string{"a", "b"}, time.Unix(tm, 0)) assert.Nil(t, err) wantedMap := make(map[string][]models.Asset) wantedMap["a"] = assets @@ -57,7 +57,7 @@ func Test_GetAssetsMapByAddressesFromTime(t *testing.T) { } } - m, err = database.GetAssetsMapByAddressesFromTime([]string{"a", "b"}, time.Unix(tm+101, 0), context.Background()) + m, err = database.GetAssetsMapByAddressesFromTime([]string{"a", "b"}, time.Unix(tm+101, 0)) assert.Nil(t, err) assert.Equal(t, 0, len(m)) } @@ -67,13 +67,13 @@ func Test_GetSubscribedAddressesForAssets(t *testing.T) { assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} - err := database.AddAssociationsForAddress("a", assets, context.Background()) + err := database.AddAssociationsForAddress("a", assets) assert.Nil(t, err) - err = database.AddAssociationsForAddress("b", nil, context.Background()) + err = database.AddAssociationsForAddress("b", nil) assert.Nil(t, err) - m, err := database.GetSubscribedAddressesForAssets(context.Background(), []string{"a", "b"}) + m, err := database.GetSubscribedAddressesForAssets([]string{"a", "b"}) assert.Nil(t, err) assert.Equal(t, 2, len(m)) } @@ -82,10 +82,10 @@ func Test_AddNewAssociationForAddress(t *testing.T) { setup.CleanupPgContainer(database.Gorm) assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} - err := database.AddAssociationsForAddress("a", assets, context.Background()) + err := database.AddAssociationsForAddress("a", assets) assert.Nil(t, err) - associations, err := database.GetAssociationsByAddresses([]string{"a"}, context.Background()) + associations, err := database.GetAssociationsByAddresses([]string{"a"}) assert.Nil(t, err) var assetIDsFromDB []models.Asset @@ -105,10 +105,10 @@ func Test_AddNewAssociationForAddress(t *testing.T) { assert.Equal(t, assetIDsFromDB[i].Asset, a.Asset) } - err = database.AddAssociationsForAddress("b", nil, context.Background()) + err = database.AddAssociationsForAddress("b", nil) assert.Nil(t, err) - associations2, err := database.GetAssociationsByAddresses([]string{"b"}, context.Background()) + associations2, err := database.GetAssociationsByAddresses([]string{"b"}) assert.Nil(t, err) assert.NotNil(t, associations2) } @@ -117,10 +117,10 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { setup.CleanupPgContainer(database.Gorm) assets := []models.Asset{{Asset: "f"}} - err := database.AddAssociationsForAddress("A", assets, context.Background()) + err := database.AddAssociationsForAddress("A", assets) assert.Nil(t, err) - err = database.AddAssociationsForAddress("B", assets, context.Background()) + err = database.AddAssociationsForAddress("B", assets) assert.Nil(t, err) assetsForA := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} @@ -130,10 +130,10 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { updateMap["A"] = assetsForA updateMap["B"] = assetsForB - err = database.UpdateAssociationsForExistingAddresses(updateMap, context.Background()) + err = database.UpdateAssociationsForExistingAddresses(updateMap) assert.Nil(t, err) - associationsA, err := database.GetAssociationsByAddresses([]string{"A"}, context.Background()) + associationsA, err := database.GetAssociationsByAddresses([]string{"A"}) assert.Nil(t, err) var assetIDsFromDBA []models.Asset @@ -154,7 +154,7 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { assert.Equal(t, assetIDsFromDBA[i].Asset, a.Asset) } - associationsB, err := database.GetAssociationsByAddresses([]string{"B"}, context.Background()) + associationsB, err := database.GetAssociationsByAddresses([]string{"B"}) assert.Nil(t, err) var assetIDsFromDBB []models.Asset @@ -175,7 +175,7 @@ func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { assert.Equal(t, assetIDsFromDBB[i].Asset, a.Asset) } - associationsAB, err := database.GetAssociationsByAddresses([]string{"A", "B"}, context.Background()) + associationsAB, err := database.GetAssociationsByAddresses([]string{"A", "B"}) assert.Nil(t, err) var assetIDsFromDBAB []models.Asset diff --git a/tests/integration/db_test/tokenindexer_test.go b/tests/integration/db_test/tokenindexer_test.go index a9d45cdc9..1198d74be 100644 --- a/tests/integration/db_test/tokenindexer_test.go +++ b/tests/integration/db_test/tokenindexer_test.go @@ -3,14 +3,14 @@ package db_test import ( - "context" + "sort" + "testing" + "time" + gocache "github.com/patrickmn/go-cache" assert "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/tests/integration/setup" - "sort" - "testing" - "time" ) func Test_AddNewAssets_Simple(t *testing.T) { @@ -30,9 +30,9 @@ func Test_AddNewAssets_Simple(t *testing.T) { Type: "BEP20", }, } - err := database.AddNewAssets(a, context.Background()) + err := database.AddNewAssets(a) assert.Nil(t, err) - assets, err := database.GetAssetsByIDs([]string{"c714_b", "c714_a"}, context.Background()) + assets, err := database.GetAssetsByIDs([]string{"c714_b", "c714_a"}) assert.Nil(t, err) assert.NotNil(t, assets) a = append(a, models.Asset{ @@ -42,7 +42,7 @@ func Test_AddNewAssets_Simple(t *testing.T) { Symbol: "DTS", Type: "BEP20", }) - err = database.AddNewAssets(a, context.Background()) + err = database.AddNewAssets(a) assert.Nil(t, err) err = database.AddNewAssets([]models.Asset{{ Asset: "c714_p", @@ -50,9 +50,9 @@ func Test_AddNewAssets_Simple(t *testing.T) { Name: "D", Symbol: "DTS", Type: "BEP20", - }}, context.Background()) + }}) assert.Nil(t, err) - assets, err = database.GetAssetsByIDs([]string{"c714_p"}, context.Background()) + assets, err = database.GetAssetsByIDs([]string{"c714_p"}) assert.Nil(t, err) assert.Equal(t, 0, len(assets)) } @@ -78,12 +78,12 @@ func Test_GetAssetsFrom_Simple(t *testing.T) { Type: "BEP20", }, } - err := database.AddNewAssets(a, context.Background()) + err := database.AddNewAssets(a) assert.Nil(t, err) - assets, err := database.GetAssetsFrom(time.Unix(0, 0), -1, context.Background()) + assets, err := database.GetAssetsFrom(time.Unix(0, 0), -1) assert.Nil(t, err) assert.NotNil(t, assets) - assets, err = database.GetAssetsFrom(time.Unix(0, 0), 60, context.Background()) + assets, err = database.GetAssetsFrom(time.Unix(0, 0), 60) assert.Nil(t, err) assert.Equal(t, 1, len(assets)) } @@ -191,9 +191,9 @@ func Test_AddNewAssets(t *testing.T) { for _, tt := range tests { t.Run(tt.Name, func(t *testing.T) { - err := database.AddNewAssets(tt.Assets, context.Background()) + err := database.AddNewAssets(tt.Assets) assert.Equal(t, tt.WantedErr, err) - assets, err := database.GetAssetsByIDs(tt.AssetsIDs, context.Background()) + assets, err := database.GetAssetsByIDs(tt.AssetsIDs) assert.Nil(t, err) sort.Slice(tt.WantedAssets, func(i, j int) bool { return len(tt.WantedAssets[i].Name) > len(tt.WantedAssets[j].Name) diff --git a/tests/integration/db_test/tracker_test.go b/tests/integration/db_test/tracker_test.go index 5ba03bcda..a4c8e6a9d 100644 --- a/tests/integration/db_test/tracker_test.go +++ b/tests/integration/db_test/tracker_test.go @@ -3,24 +3,24 @@ package db_test import ( - "context" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/tests/integration/setup" - "testing" ) func TestDb_SetBlock(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 0, context.Background())) + assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 0)) - block, err := database.GetLastParsedBlockNumber("ethereum", context.Background()) + block, err := database.GetLastParsedBlockNumber("ethereum") assert.Nil(t, err) assert.Equal(t, block, int64(0)) - assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 110, context.Background())) + assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 110)) - newBlock, err := database.GetLastParsedBlockNumber("ethereum", context.Background()) + newBlock, err := database.GetLastParsedBlockNumber("ethereum") assert.Nil(t, err) assert.Equal(t, newBlock, int64(110)) } diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 7acc0772a..240f17728 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -5,6 +5,9 @@ package observer_test import ( "context" "encoding/json" + "testing" + "time" + "github.com/streadway/amqp" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/mq" @@ -14,8 +17,6 @@ import ( "github.com/trustwallet/blockatlas/tests/integration/setup" "github.com/trustwallet/golibs/coin" "go.uber.org/atomic" - "testing" - "time" ) var ( @@ -24,7 +25,7 @@ var ( func TestFullFlow(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptionsForNotifications([]string{"60_testAddress"}, context.Background()) + err := database.AddSubscriptionsForNotifications([]string{"60_testAddress"}) assert.Nil(t, err) ctx, cancel := context.WithCancel(context.Background()) diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index b36a6575d..d1cf2e2fe 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -5,6 +5,9 @@ package observer_test import ( "context" "encoding/json" + "testing" + "time" + "github.com/streadway/amqp" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/mq" @@ -12,8 +15,6 @@ import ( "github.com/trustwallet/blockatlas/services/notifier" "github.com/trustwallet/blockatlas/tests/integration/setup" "github.com/trustwallet/golibs/coin" - "testing" - "time" ) var ( @@ -43,7 +44,7 @@ var ( func TestNotifier(t *testing.T) { setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptionsForNotifications([]string{"714_tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"}, context.Background()) + err := database.AddSubscriptionsForNotifications([]string{"714_tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"}) assert.Nil(t, err) err = produceTxs(txs) diff --git a/tests/integration/observer_test/subscriber_test.go b/tests/integration/observer_test/subscriber_test.go index 2f55aae72..d9c42190f 100644 --- a/tests/integration/observer_test/subscriber_test.go +++ b/tests/integration/observer_test/subscriber_test.go @@ -5,16 +5,17 @@ package observer_test import ( "context" "encoding/json" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/subscriber" - "github.com/trustwallet/blockatlas/tests/integration/setup" "io/ioutil" "path/filepath" "runtime" "testing" "time" + + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/subscriber" + "github.com/trustwallet/blockatlas/tests/integration/setup" ) func TestSubscriberAddSubscription(t *testing.T) { @@ -56,7 +57,7 @@ func TestSubscriberAddSubscription(t *testing.T) { } for _, wanted := range wantedEvents { - result, err := database.GetSubscriptionsForNotifications([]string{wanted.Address}, context.Background()) + result, err := database.GetSubscriptionsForNotifications([]string{wanted.Address}) assert.Nil(t, err) assert.Equal(t, result[0].Address.Address, wanted.Address) } @@ -90,16 +91,16 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { } database.AddSubscriptionsForNotifications( - []string{"61_0x0000000000000000000000000000000000000000"}, context.Background()) + []string{"61_0x0000000000000000000000000000000000000000"}) database.AddSubscriptionsForNotifications( - []string{"62_0x0000000000000000000000000000000000000000"}, context.Background()) + []string{"62_0x0000000000000000000000000000000000000000"}) database.AddSubscriptionsForNotifications( - []string{"63_0x0000000000000000000000000000000000000000"}, context.Background()) + []string{"63_0x0000000000000000000000000000000000000000"}) database.AddSubscriptionsForNotifications( - []string{"64_0x0000000000000000000000000000000000000000"}, context.Background()) + []string{"64_0x0000000000000000000000000000000000000000"}) for _, event := range givenEvents { body, err := json.Marshal(event) @@ -116,28 +117,28 @@ func TestSubscriber_UpdateSubscription(t *testing.T) { } for _, wanted := range wantedEvents { - result, err := database.GetSubscriptionsForNotifications([]string{wanted.Address}, context.Background()) + result, err := database.GetSubscriptionsForNotifications([]string{wanted.Address}) assert.Nil(t, err) assert.Len(t, result, 1) } - abs61, err := database.GetSubscriptionsForNotifications([]string{"61_0x0000000000000000000000000000000000000000"}, context.Background()) + abs61, err := database.GetSubscriptionsForNotifications([]string{"61_0x0000000000000000000000000000000000000000"}) assert.Nil(t, err) assert.Len(t, abs61, 1) - abs62, err := database.GetSubscriptionsForNotifications([]string{"62_0x0000000000000000000000000000000000000000"}, context.Background()) + abs62, err := database.GetSubscriptionsForNotifications([]string{"62_0x0000000000000000000000000000000000000000"}) assert.Nil(t, err) assert.Len(t, abs62, 1) - abs63, err := database.GetSubscriptionsForNotifications([]string{"63_0x0000000000000000000000000000000000000000"}, context.Background()) + abs63, err := database.GetSubscriptionsForNotifications([]string{"63_0x0000000000000000000000000000000000000000"}) assert.Nil(t, err) assert.Len(t, abs63, 1) - abs64, err := database.GetSubscriptionsForNotifications([]string{"64_0x0000000000000000000000000000000000000000"}, context.Background()) + abs64, err := database.GetSubscriptionsForNotifications([]string{"64_0x0000000000000000000000000000000000000000"}) assert.Nil(t, err) assert.Len(t, abs64, 1) - abs65, err := database.GetSubscriptionsForNotifications([]string{"65_0x0000000000000000000000000000000000000000"}, context.Background()) + abs65, err := database.GetSubscriptionsForNotifications([]string{"65_0x0000000000000000000000000000000000000000"}) assert.Nil(t, err) assert.Len(t, abs65, 0) } From 54872881e017d3c2eeb2c007a330b857cd75bff7 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 9 Dec 2020 11:11:18 +0800 Subject: [PATCH 428/506] use golibs (#1305) --- api/registry.go | 2 +- cmd/api/main.go | 2 +- go.mod | 3 +-- go.sum | 29 +++++------------------------ 4 files changed, 8 insertions(+), 28 deletions(-) diff --git a/api/registry.go b/api/registry.go index dfbcaadbd..55602813d 100644 --- a/api/registry.go +++ b/api/registry.go @@ -9,7 +9,7 @@ import ( "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" - "github.com/trustwallet/golibs-networking/middleware" + "github.com/trustwallet/golibs/middleware" ) func RegisterTransactionsAPI(router gin.IRouter, api blockatlas.Platform) { diff --git a/cmd/api/main.go b/cmd/api/main.go index f845537d0..1a1dcc467 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/trustwallet/golibs-networking/middleware" + "github.com/trustwallet/golibs/middleware" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" diff --git a/go.mod b/go.mod index bf5364610..15487314a 100644 --- a/go.mod +++ b/go.mod @@ -32,8 +32,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/swag v1.6.9 - github.com/trustwallet/golibs v0.0.17 - github.com/trustwallet/golibs-networking v0.0.5 + github.com/trustwallet/golibs v0.0.18 go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201207224615-747e23833adb // indirect diff --git a/go.sum b/go.sum index d534608b2..33da3e260 100644 --- a/go.sum +++ b/go.sum @@ -144,21 +144,13 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -261,9 +253,8 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -419,10 +410,8 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.6.9 h1:BukKRwZjnEcUxQt7Xgfrt9fpav0hiWw9YimdNO9wssw= github.com/swaggo/swag v1.6.9/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.17 h1:bsxF/y59/2QfqnkTFCAoiRphUljoCf9ca7BJPNTpNbk= -github.com/trustwallet/golibs v0.0.17/go.mod h1:j+Tip4aaW3mu+81S1a+UJ8fSnKzLeJyBueApnCXXRMg= -github.com/trustwallet/golibs-networking v0.0.5 h1:7gbxSgGf6KryKaI36s+MYLGE0X9sJKwHjyLJJKx5V/Q= -github.com/trustwallet/golibs-networking v0.0.5/go.mod h1:FS8fJ7DyM+ZAs94VsmCAOlbDXJdkOcceb3d6dKujXho= +github.com/trustwallet/golibs v0.0.18 h1:FfLeSeCkZUMr4uNwSA5oWsV4FnTCicesCZOMn5SnzL0= +github.com/trustwallet/golibs v0.0.18/go.mod h1:OF0QTvtLg9qWRYrL7ch7j9ZhCLVga0MHTZ1tlJGaf88= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -546,7 +535,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d h1:MiWWjyhUzZ+jvhZvloX6ZrUsdEghn8a64Upd8EMHglE= golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -611,13 +599,6 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 8271ea51caa737ceaab2d1ba4adeb38dc4fec3da Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 9 Dec 2020 19:56:32 -0800 Subject: [PATCH 429/506] Bump gorm.io/gorm from 1.20.7 to 1.20.8 (#1307) Bumps [gorm.io/gorm](https://github.com/go-gorm/gorm) from 1.20.7 to 1.20.8. - [Release notes](https://github.com/go-gorm/gorm/releases) - [Commits](https://github.com/go-gorm/gorm/compare/v1.20.7...v1.20.8) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 15487314a..c7867d3e3 100644 --- a/go.mod +++ b/go.mod @@ -39,6 +39,6 @@ require ( golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.5 - gorm.io/gorm v1.20.7 + gorm.io/gorm v1.20.8 gotest.tools v2.2.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index 33da3e260..cf8fa2437 100644 --- a/go.sum +++ b/go.sum @@ -629,6 +629,7 @@ gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOud gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.7 h1:rMS4CL3pNmYq1V5/X+nHHjh1Dx6dnf27+Cai5zabo+M= gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.20.8/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= From 94f2beaafc759efe5ecbe56256261fc4675bf6c5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 9 Dec 2020 19:56:44 -0800 Subject: [PATCH 430/506] Bump github.com/swaggo/swag from 1.6.9 to 1.7.0 (#1306) Bumps [github.com/swaggo/swag](https://github.com/swaggo/swag) from 1.6.9 to 1.7.0. - [Release notes](https://github.com/swaggo/swag/releases) - [Changelog](https://github.com/swaggo/swag/blob/master/.goreleaser.yml) - [Commits](https://github.com/swaggo/swag/compare/v1.6.9...v1.7.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c7867d3e3..7e074023d 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/streadway/amqp v1.0.0 github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.3.0 - github.com/swaggo/swag v1.6.9 + github.com/swaggo/swag v1.7.0 github.com/trustwallet/golibs v0.0.18 go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 diff --git a/go.sum b/go.sum index cf8fa2437..33bd52d26 100644 --- a/go.sum +++ b/go.sum @@ -117,9 +117,11 @@ github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.9 h1:9z9cbFuZJ7AcvOHKIY+f6Aevb4vObNDkTEyoMfO7rAc= github.com/go-openapi/spec v0.19.9/go.mod h1:vqK/dIdLGCosfvYsQV3WfC7N3TiZSnGY2RZKoFK7X28= +github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= @@ -409,6 +411,7 @@ github.com/swaggo/gin-swagger v1.3.0/go.mod h1:oy1BRA6WvgtCp848lhxce7BnWH4C8Bxa0 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.6.9 h1:BukKRwZjnEcUxQt7Xgfrt9fpav0hiWw9YimdNO9wssw= github.com/swaggo/swag v1.6.9/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI= +github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/golibs v0.0.18 h1:FfLeSeCkZUMr4uNwSA5oWsV4FnTCicesCZOMn5SnzL0= github.com/trustwallet/golibs v0.0.18/go.mod h1:OF0QTvtLg9qWRYrL7ch7j9ZhCLVga0MHTZ1tlJGaf88= @@ -424,8 +427,10 @@ github.com/ugorji/go/codec v1.1.13 h1:013LbFhocBoIqgHeIHKlV4JWYhqogATYWZhIcH0WHn github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -496,6 +501,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201207224615-747e23833adb h1:xj2oMIbduz83x7tzglytWT7spn6rP+9hvKjTpro6/pM= golang.org/x/net v0.0.0-20201207224615-747e23833adb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -507,6 +514,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -544,6 +552,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -572,12 +581,14 @@ golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac h1:DugppSxw0LSF8lcjaODPJZoDzq0ElTGskTst3ZaBkHI= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -617,6 +628,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From 1eaa8deb7614b2b22a6b2c7231605186a9637465 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 14 Dec 2020 17:23:13 +0800 Subject: [PATCH 431/506] [eGLD] Update symbol names (#1311) * Update symbol names * go mod tidy --- go.mod | 2 +- go.sum | 30 ++++++++++------------------- platform/elrond/transaction_test.go | 12 ++++++------ platform/platform.go | 4 ++-- 4 files changed, 19 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index 7e074023d..ea377a0e4 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/swag v1.7.0 - github.com/trustwallet/golibs v0.0.18 + github.com/trustwallet/golibs v0.0.21 go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201207224615-747e23833adb // indirect diff --git a/go.sum b/go.sum index 33bd52d26..cc2c64e28 100644 --- a/go.sum +++ b/go.sum @@ -115,12 +115,12 @@ github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3Hfo github.com/go-openapi/jsonreference v0.19.4 h1:3Vw+rh13uq2JFNxgnMTGE1rnoieU9FmyE1gvnyylsYg= github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.9 h1:9z9cbFuZJ7AcvOHKIY+f6Aevb4vObNDkTEyoMfO7rAc= -github.com/go-openapi/spec v0.19.9/go.mod h1:vqK/dIdLGCosfvYsQV3WfC7N3TiZSnGY2RZKoFK7X28= +github.com/go-openapi/spec v0.19.14 h1:r4fbYFo6N4ZelmSX8G6p+cv/hZRXzcuqQIADGT1iNKM= github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.11 h1:RFTu/dlFySpyVvJDfp/7674JY4SDglYWKztbiIGFpmc= github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -133,9 +133,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= -github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -405,31 +404,25 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= -github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= github.com/swaggo/gin-swagger v1.3.0 h1:eOmp7r57oUgZPw2dJOjcGNMse9cvXcI4tTqBcnZtPsI= github.com/swaggo/gin-swagger v1.3.0/go.mod h1:oy1BRA6WvgtCp848lhxce7BnWH4C8Bxa0m5SkWx+cS0= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= -github.com/swaggo/swag v1.6.9 h1:BukKRwZjnEcUxQt7Xgfrt9fpav0hiWw9YimdNO9wssw= -github.com/swaggo/swag v1.6.9/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI= +github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.18 h1:FfLeSeCkZUMr4uNwSA5oWsV4FnTCicesCZOMn5SnzL0= -github.com/trustwallet/golibs v0.0.18/go.mod h1:OF0QTvtLg9qWRYrL7ch7j9ZhCLVga0MHTZ1tlJGaf88= +github.com/trustwallet/golibs v0.0.21 h1:gUPra/RHK+06bM39jrtoNCz1IZWWWcnjXDtYE9+B2vs= +github.com/trustwallet/golibs v0.0.21/go.mod h1:OF0QTvtLg9qWRYrL7ch7j9ZhCLVga0MHTZ1tlJGaf88= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.1.13 h1:nB3O5kBSQGjEQAcfe1aLUYuxmXdFKmYgBZhY32rQb6Q= github.com/ugorji/go v1.1.13/go.mod h1:jxau1n+/wyTGLQoCkjok9r5zFa/FxT6eI5HiHKQszjc= github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.13 h1:013LbFhocBoIqgHeIHKlV4JWYhqogATYWZhIcH0WHn4= github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -500,7 +493,6 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201207224615-747e23833adb h1:xj2oMIbduz83x7tzglytWT7spn6rP+9hvKjTpro6/pM= @@ -513,7 +505,6 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -540,7 +531,6 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -552,6 +542,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -579,8 +570,7 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200820010801-b793a1359eac h1:DugppSxw0LSF8lcjaODPJZoDzq0ElTGskTst3ZaBkHI= -golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e h1:t96dS3DO8DGjawSLJL/HIdz8CycAd2v07XxqB3UPTi0= golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -588,6 +578,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -639,8 +630,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gorm.io/driver/postgres v1.0.5 h1:raX6ezL/ciUmaYTvOq48jq1GE95aMC0CmxQYbxQ4Ufw= gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOudXNCA= gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.7 h1:rMS4CL3pNmYq1V5/X+nHHjh1Dx6dnf27+Cai5zabo+M= -gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.20.8 h1:iToaOdZgjNvlc44NFkxfLa3U9q63qwaxt0FdNCiwOMs= gorm.io/gorm v1.20.8/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= diff --git a/platform/elrond/transaction_test.go b/platform/elrond/transaction_test.go index 16a15c33d..7cb66576c 100644 --- a/platform/elrond/transaction_test.go +++ b/platform/elrond/transaction_test.go @@ -105,7 +105,7 @@ const txTransferSrc6 = ` var txTransfer1Normalized = blockatlas.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.ERD, + Coin: coin.EGLD, Date: int64(1587715632), From: "metachain", To: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", @@ -123,7 +123,7 @@ var txTransfer1Normalized = blockatlas.Tx{ var txTransfer2Normalized = blockatlas.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.ERD, + Coin: coin.EGLD, Date: int64(1588757256), From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", To: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", @@ -141,7 +141,7 @@ var txTransfer2Normalized = blockatlas.Tx{ var txTransfer3Normalized = blockatlas.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.ERD, + Coin: coin.EGLD, Date: int64(1588757256), From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", @@ -159,7 +159,7 @@ var txTransfer3Normalized = blockatlas.Tx{ var txTransfer4Normalized = blockatlas.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.ERD, + Coin: coin.EGLD, Date: int64(1588757256), From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", @@ -177,7 +177,7 @@ var txTransfer4Normalized = blockatlas.Tx{ var txTransfer5Normalized = blockatlas.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.ERD, + Coin: coin.EGLD, Date: int64(1588757256), From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", @@ -195,7 +195,7 @@ var txTransfer5Normalized = blockatlas.Tx{ var txTransfer6Normalized = blockatlas.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.ERD, + Coin: coin.EGLD, From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", Fee: "5000", diff --git a/platform/platform.go b/platform/platform.go index 5d80e11bc..1f381e29b 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -76,7 +76,7 @@ func getAllHandlers() blockatlas.Platforms { 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.XZC, config.Default.Zcoin.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), @@ -97,7 +97,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Smartchain().Handle: ethereum.InitWithBlockbook(coin.BSC, config.Default.Smartchain.API, config.Default.Smartchain.RPC), coin.Ethereum().Handle: ethereum.InitWithCollection(coin.ETH, config.Default.Ethereum.RPC, 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.ERD, config.Default.Elrond.API), + coin.Elrond().Handle: elrond.Init(coin.EGLD, config.Default.Elrond.API), coin.Filecoin().Handle: filecoin.Init(config.Default.Filecoin.API), } } From ec3a23abaca5b853b119b6e07748e571b6705557 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 15 Dec 2020 09:58:26 +0800 Subject: [PATCH 432/506] Use golibs/network (#1314) * use golibs/network * bump master tag --- api/registry.go | 2 +- cmd/api/main.go | 2 +- go.mod | 3 ++- go.sum | 10 +++++----- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/api/registry.go b/api/registry.go index 55602813d..efaf2aa1e 100644 --- a/api/registry.go +++ b/api/registry.go @@ -9,7 +9,7 @@ import ( "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/tokenindexer" "github.com/trustwallet/blockatlas/services/tokensearcher" - "github.com/trustwallet/golibs/middleware" + "github.com/trustwallet/golibs/network/middleware" ) func RegisterTransactionsAPI(router gin.IRouter, api blockatlas.Platform) { diff --git a/cmd/api/main.go b/cmd/api/main.go index 1a1dcc467..4bcd46a07 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/trustwallet/golibs/middleware" + "github.com/trustwallet/golibs/network/middleware" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" diff --git a/go.mod b/go.mod index ea377a0e4..0ea831926 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,8 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/swag v1.7.0 - github.com/trustwallet/golibs v0.0.21 + github.com/trustwallet/golibs v0.0.23 + github.com/trustwallet/golibs/network v0.0.0-20201215012452-c5d526fed5df go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201207224615-747e23833adb // indirect diff --git a/go.sum b/go.sum index cc2c64e28..a13cd82da 100644 --- a/go.sum +++ b/go.sum @@ -410,8 +410,10 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.21 h1:gUPra/RHK+06bM39jrtoNCz1IZWWWcnjXDtYE9+B2vs= -github.com/trustwallet/golibs v0.0.21/go.mod h1:OF0QTvtLg9qWRYrL7ch7j9ZhCLVga0MHTZ1tlJGaf88= +github.com/trustwallet/golibs v0.0.23 h1:AGmmD52idzGypf2MX5BXuq6Pz+AEUGkyCOnfKODK/2U= +github.com/trustwallet/golibs v0.0.23/go.mod h1:Vi63TTS0yRAPwFIIKe7tw1yTgd71RACQqgZpUcWTv04= +github.com/trustwallet/golibs/network v0.0.0-20201215012452-c5d526fed5df h1:ps2pYgkR6p/YExq9pOmLNTVRm0CwjEKH0mOPD2rsj/Q= +github.com/trustwallet/golibs/network v0.0.0-20201215012452-c5d526fed5df/go.mod h1:klL63JlvgRSc+vpAd5TsTsyqR75+N2mPYd1PCg/+jBo= 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= @@ -531,7 +533,6 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d h1:MiWWjyhUzZ+jvhZvloX6ZrUsdEghn8a64Upd8EMHglE= @@ -603,9 +604,8 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= From c8cfdc251c291fa59719a907a7391c99b6d94e20 Mon Sep 17 00:00:00 2001 From: Maksim Rasputin <133312+madcake@users.noreply.github.com> Date: Wed, 16 Dec 2020 00:02:00 +0700 Subject: [PATCH 433/506] Add pubsub and mq implementation (#1310) * Add pubsub and mq implementation * Add pubsub test * Add first test to mq pubsub and fix issues --- go.mod | 9 +- go.sum | 28 ++++ pubsub/mqclient/mq_client.go | 182 +++++++++++++++++++++ pubsub/mqclient/mq_stream.go | 95 +++++++++++ pubsub/pubsub.go | 34 ++++ tests/integration/pubsub/pubsub_mq_test.go | 94 +++++++++++ 6 files changed, 439 insertions(+), 3 deletions(-) create mode 100644 pubsub/mqclient/mq_client.go create mode 100644 pubsub/mqclient/mq_stream.go create mode 100644 pubsub/pubsub.go create mode 100644 tests/integration/pubsub/pubsub_mq_test.go diff --git a/go.mod b/go.mod index 0ea831926..c8fda26c4 100644 --- a/go.mod +++ b/go.mod @@ -7,11 +7,12 @@ go 1.15 require ( github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect - github.com/Microsoft/go-winio v0.4.15 // indirect + github.com/Microsoft/go-winio v0.4.16 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 // indirect github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect @@ -21,10 +22,12 @@ require ( github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/imroc/req v0.3.0 github.com/mitchellh/mapstructure v1.4.0 + github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf // indirect github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v1.0.0-rc9 // indirect github.com/ory/dockertest v3.3.5+incompatible + github.com/ory/dockertest/v3 v3.6.2 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible github.com/sirupsen/logrus v1.7.0 github.com/spf13/viper v1.7.1 @@ -36,8 +39,8 @@ require ( github.com/trustwallet/golibs/network v0.0.0-20201215012452-c5d526fed5df go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 - golang.org/x/net v0.0.0-20201207224615-747e23833adb // indirect - golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d // indirect + golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 // indirect + golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.5 gorm.io/gorm v1.20.8 diff --git a/go.sum b/go.sum index a13cd82da..df921e434 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,11 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15 h1:qkLXKzb1QoVatRyd/YlXZ/Kg0m5K3SPuoD82jjSOaBc= github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -53,12 +56,17 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 h1:6ejg6Lkk8dskcM7wQ28gONkukbQkM4qpj4RnYbpFzrI= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -69,6 +77,8 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -152,6 +162,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -276,6 +287,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -310,6 +322,10 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 h1:SPoLlS9qUUnXcIY4pvA4CTwYjk0Is5f4UPEkeESr53k= +github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2/go.mod h1:TjQg8pa4iejrUrjiz0MCtMV38jdMNW4doKSiBrEvCQQ= +github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf h1:Un6PNx5oMK6CCwO3QTUyPiK2mtZnPrpDl5UnZ64eCkw= +github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -323,6 +339,7 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -331,6 +348,8 @@ github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.6.2 h1:Q3Y8naCMyC1Nw91BHum1bGyEsNQc/UOIYS3ZoPoou0g= +github.com/ory/dockertest/v3 v3.6.2/go.mod h1:EFLcVUOl8qCwp9NyDAcCDtq/QviLtYswW/VbWzUnTNE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -499,6 +518,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201207224615-747e23833adb h1:xj2oMIbduz83x7tzglytWT7spn6rP+9hvKjTpro6/pM= golang.org/x/net v0.0.0-20201207224615-747e23833adb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 h1:lwlPPsmjDKK0J6eG6xDWd5XPehI0R024zxjDnw3esPA= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -534,10 +555,14 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d h1:MiWWjyhUzZ+jvhZvloX6ZrUsdEghn8a64Upd8EMHglE= golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f h1:QdHQnPce6K4XQewki9WNbG5KOROuDzqO3NaYjI1cXJ0= +golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -562,6 +587,7 @@ golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -621,6 +647,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -634,6 +661,7 @@ gorm.io/gorm v1.20.8 h1:iToaOdZgjNvlc44NFkxfLa3U9q63qwaxt0FdNCiwOMs= gorm.io/gorm v1.20.8/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= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pubsub/mqclient/mq_client.go b/pubsub/mqclient/mq_client.go new file mode 100644 index 000000000..603edf710 --- /dev/null +++ b/pubsub/mqclient/mq_client.go @@ -0,0 +1,182 @@ +package mqclient + +import ( + "context" + "errors" + log "github.com/sirupsen/logrus" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/pubsub" + "go.uber.org/atomic" + "time" +) + +var ( + reconnectDelay = 5 * time.Second + resendDelay = 5 * time.Second +) + +type Client struct { + uri string + conn *amqp.Connection + channel *amqp.Channel + prefetchCount int + streams []*pubsub.Stream + ctx context.Context + notifyClose chan *amqp.Error + notifyConfirm chan amqp.Confirmation + isConnected *atomic.Bool + alive *atomic.Bool +} + +func New(uri string, prefetchCount int, ctx context.Context) (client pubsub.Client) { + client = &Client{ + uri: uri, + ctx: ctx, + alive: atomic.NewBool(false), + isConnected: atomic.NewBool(false), + prefetchCount: prefetchCount, + streams: []*pubsub.Stream{}, + } + return client +} + +func (c *Client) Connect() error { + conn, err := amqp.Dial(c.uri) + if err != nil { + log.Error("Client.connect MQ Dial issue " + err.Error()) + return err + } + ch, err := conn.Channel() + if err != nil { + log.Error("Client.connect MQ Channel issue " + err.Error()) + return err + } + err = ch.Confirm(false) + if err != nil { + log.Error("Client.connect MQ Channel issue " + err.Error()) + } + log.Debug("Interface: ", c) + c.conn = conn + c.channel = ch + c.notifyClose = make(chan *amqp.Error) + c.notifyConfirm = make(chan amqp.Confirmation) + c.channel.NotifyClose(c.notifyClose) + c.channel.NotifyPublish(c.notifyConfirm) + c.isConnected.Store(true) + return nil +} + +func (c *Client) Run() error { + log.Debug("Interface: ", c) + if c.conn == nil { + return errors.New("connect firstly") + } + go c.handleReconnect() + err := c.channel.Qos(c.prefetchCount, 0, false) + if err != nil { + return errors.New("Client.connect MQ Qos issue " + err.Error()) + } + for _, stream := range c.streams { + if !(*stream).IsConnected() { + go (*stream).Connect(c.ctx) + } + } + return nil +} + +func (c *Client) IsConnected() bool { + return c.isConnected.Load() +} + +func (c *Client) AddStream(consumer *pubsub.Consumer, isWriteOnly bool) error { + var stream pubsub.Stream = &Stream{ + consumer: consumer, + client: c, + isConnected: atomic.NewBool(false), + isWriteOnly: isWriteOnly, + channel: c.channel, + } + go stream.Connect(c.ctx) // Try connect, if client isn't run it will wait run + c.streams = append(c.streams, &stream) + return nil +} + +func (c *Client) Push(queue string, data []byte) error { + if !c.isConnected.Load() { + // TODO: Is should wait connect to RabbitMQ or not? + return errors.New("failed to push push: not connected") + } + + //todo Add stream waiting + for { + err := c.PushUnsafe(queue, data) + if err != nil { + log.Error("Client.Push MQ issue " + err.Error()) + if err == pubsub.ErrDisconnected { + continue + } + return err + } + select { + case confirm := <-c.notifyConfirm: + if confirm.Ack { + return nil + } + case <-time.After(resendDelay): + } + } +} + +func (c *Client) PushUnsafe(queue string, data []byte) error { + if !c.isConnected.Load() { + return pubsub.ErrDisconnected + } + return c.channel.Publish( + "", // Exchange + string(queue), // Routing key + false, // Mandatory + false, // Immediate + amqp.Publishing{ + ContentType: "text/plain", + Body: data, + }, + ) +} + +func (c *Client) Close() error { + err := c.channel.Close() + if err != nil { + return errors.New("Client.Close MQ issue " + err.Error()) + } + + err = c.conn.Close() + if err != nil { + return errors.New("Client.Close MQ issue " + err.Error()) + } + return nil +} + +func (c *Client) handleReconnect() { + for c.alive.Load() { + log.Debug("Try connect after alive") + c.isConnected.Store(false) + for c.Connect() != nil { + log.Debug("Try connect") + if !c.alive.Load() { + return + } + select { + case <-c.ctx.Done(): + return + case <-time.After(reconnectDelay + time.Second): + // Add metric + } + } + select { + case <-c.ctx.Done(): + log.Fatal("Fucking end") + return + case <-c.notifyClose: + } + } +} diff --git a/pubsub/mqclient/mq_stream.go b/pubsub/mqclient/mq_stream.go new file mode 100644 index 000000000..04336b94a --- /dev/null +++ b/pubsub/mqclient/mq_stream.go @@ -0,0 +1,95 @@ +package mqclient + +import ( + "context" + log "github.com/sirupsen/logrus" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/pubsub" + "go.uber.org/atomic" + "time" +) + +type Stream struct { + consumer *pubsub.Consumer + client pubsub.Client + channel *amqp.Channel + isConnected *atomic.Bool + isWriteOnly bool +} + +func (s *Stream) Connect(cancelCtx context.Context) { + s.isConnected.Store(true) + for { + if s.client.IsConnected() { + break + } + time.Sleep(1 * time.Second) + } + s.declareQueue() + if s.isWriteOnly { + return + } + messageChannel, err := s.channel.Consume( + (*s.consumer).GetQueue(), + "", + false, + false, + false, + false, + nil, + ) + if err != nil { + s.isConnected.Store(false) + log.Fatal("GetMessageChannel MQ issue "+err.Error(), (*s.consumer).GetQueue()) + } + for { + select { + case <-cancelCtx.Done(): + log.Info("Consumer stopped") + return + case msg, ok := <-messageChannel: + if !ok { + s.isConnected.Store(false) + return + } + if msg.Body != nil { + s.delivery(msg) + } + } + } +} +func (s *Stream) GetConsumer() *pubsub.Consumer { + return s.consumer +} + +func (s *Stream) GetClient() *pubsub.Client { + return &s.client +} + +func (s *Stream) IsConnected() bool { + return s.isConnected.Load() +} + +func (s *Stream) IsWriteOnly() bool { + return s.isWriteOnly +} + +func (s *Stream) declareQueue() { + _, err := s.channel.QueueDeclare((*s.consumer).GetQueue(), true, false, false, false, nil) + if err != nil { + log.Fatal("Stream.Init MQ issue "+err.Error(), (*s.consumer).GetQueue()) + } +} + +func (s *Stream) delivery(msg amqp.Delivery) { + if (*s.consumer).Callback(msg) == nil { + ack((*s.consumer).GetQueue(), msg) + } +} + +func ack(queue string, msg amqp.Delivery) { + err := msg.Ack(false) + if err != nil { + log.Error("Stream Ack MQ issue on queue: ", queue, err) + } +} diff --git a/pubsub/pubsub.go b/pubsub/pubsub.go new file mode 100644 index 000000000..300930af9 --- /dev/null +++ b/pubsub/pubsub.go @@ -0,0 +1,34 @@ +package pubsub + +import ( + "context" + "errors" + "github.com/streadway/amqp" +) + +var ( + ErrDisconnected = errors.New("disconnected from rabbitmq, trying to reconnect") +) + +type Client interface { + Connect() error + Run() error + IsConnected() bool + AddStream(consumer *Consumer, isWriteOnly bool) error + Push(queue string, data []byte) error + PushUnsafe(queue string, data []byte) error + Close() error +} + +type Stream interface { + Connect(cancelCtx context.Context) + GetConsumer() *Consumer + GetClient() *Client + IsConnected() bool + IsWriteOnly() bool +} + +type Consumer interface { + GetQueue() string + Callback(msg amqp.Delivery) error +} diff --git a/tests/integration/pubsub/pubsub_mq_test.go b/tests/integration/pubsub/pubsub_mq_test.go new file mode 100644 index 000000000..545f7fbc4 --- /dev/null +++ b/tests/integration/pubsub/pubsub_mq_test.go @@ -0,0 +1,94 @@ +// +build integration + +package pubsub_test + +import ( + "context" + "fmt" + "github.com/ory/dockertest" + log "github.com/sirupsen/logrus" + "github.com/streadway/amqp" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pubsub" + "github.com/trustwallet/blockatlas/pubsub/mqclient" + "os" + "sync" + "testing" + "time" +) + +var ( + mqResource *dockertest.Resource + mqClient pubsub.Client + ctx context.Context +) + +type RawTransactionConsumer struct { + TestFunc func(delivery amqp.Delivery) +} + +func (c RawTransactionConsumer) GetQueue() string { + return string("test_queue") +} + +func (c RawTransactionConsumer) Callback(msg amqp.Delivery) error { + c.TestFunc(msg) + return nil +} + +func TestMain(m *testing.M) { + ctx = context.Background() + if err := runMQContainer(); err != nil { + log.Fatal("container doesn't start: ", err) + } + + code := m.Run() + + log.Error(stopMQContainer()) + os.Exit(code) +} + +func TestMqConnect(t *testing.T) { + var wg sync.WaitGroup + wg.Add(1) + var consumer pubsub.Consumer + consumer = RawTransactionConsumer{ + TestFunc: func(msg amqp.Delivery) { + defer wg.Done() + assert.Equal(t, string(msg.Body), `{"message":"test"}`) + }, + } + assert.Nil(t, mqClient.AddStream(&consumer, false)) + time.Sleep(10 * time.Second) + assert.Nil(t, mqClient.Push(consumer.GetQueue(), []byte(`{"message":"test"}`))) + wg.Wait() +} + +func runMQContainer() error { + var err error + pool, err := dockertest.NewPool("") + if err != nil { + log.Fatalf("Could not connect to docker: %s", err) + } + + mqResource, err = pool.Run("rabbitmq", "latest", nil) + if err != nil { + log.Fatalf("Could not start resource: %s", err) + } + //time.Sleep(10 * time.Second) + if err = pool.Retry(func() error { + uri := fmt.Sprintf("amqp://localhost:%s", mqResource.GetPort("5672/tcp")) + mqClient = mqclient.New(uri, 10, ctx) + return mqClient.Connect() + }); err != nil { + stopMQContainer() + return err + } + + return mqClient.Run() +} + +func stopMQContainer() error { + mqClient.Close() + return mqResource.Close() +} From 087307fb1904f631888d07e9b67afb31ce0a2e25 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 17 Dec 2020 16:04:07 -0800 Subject: [PATCH 434/506] [Parse] Improve/optimize parsing blocks (#1330) * Remove unused params * Update parser.go * go mod tidy * Update parser_test.go * Avoid using batches for transactions and push single transaction * Update notifier_test.go --- cmd/api/main.go | 2 +- cmd/consumer/main.go | 2 +- cmd/parser/main.go | 10 +- config.yml | 7 +- config/configuration.go | 26 ++---- go.mod | 7 +- go.sum | 17 ++-- pkg/address/address.go | 5 +- pkg/address/address_test.go | 26 +----- services/notifier/base.go | 15 +-- services/notifier/delivery.go | 38 ++++---- services/notifier/models.go | 15 --- services/parser/parser.go | 89 +++++++----------- services/parser/parser_test.go | 92 ------------------- .../observer_test/full_flow_test.go | 7 +- .../observer_test/notifier_test.go | 6 +- .../integration/observer_test/parser_test.go | 6 +- 17 files changed, 98 insertions(+), 272 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index 4bcd46a07..363293ac5 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -57,7 +57,7 @@ func init() { internal.InitRabbitMQ( config.Default.Observer.Rabbitmq.URL, - config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, + config.Default.Observer.Rabbitmq.PrefetchCount, ) if err := mq.TokensRegistration.Declare(); err != nil { diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index 973ca8205..7d24307af 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -35,7 +35,7 @@ func init() { internal.InitRabbitMQ( config.Default.Observer.Rabbitmq.URL, - config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, + config.Default.Observer.Rabbitmq.PrefetchCount, ) var err error diff --git a/cmd/parser/main.go b/cmd/parser/main.go index 2fa405768..b6921332c 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -37,7 +37,7 @@ func init() { internal.InitRabbitMQ( config.Default.Observer.Rabbitmq.URL, - config.Default.Observer.Rabbitmq.Consumer.PrefetchCount, + config.Default.Observer.Rabbitmq.PrefetchCount, ) platform.Init(config.Default.Platform) @@ -71,7 +71,6 @@ func main() { coinCancel = make(map[string]context.CancelFunc) stopChannel = make(chan<- struct{}, len(platform.BlockAPIs)) ) - txsBatchLimit := config.Default.Observer.TxsBatchLimit backlogTime := config.Default.Observer.Backlog minInterval := config.Default.Observer.BlockPoll.Min maxInterval := config.Default.Observer.BlockPoll.Max @@ -94,11 +93,6 @@ func main() { backlogCount = int(backlogTime / pollInterval) } - // do not allow - if txsBatchLimit < parser.MinTxsBatchLimit { - txsBatchLimit = parser.MinTxsBatchLimit - } - coinCancel[coin.Handle] = cancel params := parser.Params{ @@ -114,7 +108,6 @@ func main() { BacklogCount: backlogCount, MaxBacklogBlocks: maxBackLogBlocks, StopChannel: stopChannel, - TxBatchLimit: txsBatchLimit, Database: database, } @@ -125,7 +118,6 @@ func main() { "interval": pollInterval, "backlog": backlogCount, "Max backlog": maxBackLogBlocks, - "Txs Batch limit": txsBatchLimit, "Fetching blocks interval": fetchBlocksInterval, }).Info("Parser params") diff --git a/config.yml b/config.yml index 1fcc46a59..ad829ec35 100644 --- a/config.yml +++ b/config.yml @@ -16,18 +16,13 @@ observer: fetch_blocks_interval: 1ms # Don't request more than N blocks at once backlog_max_blocks: 100 - # Limit amount of transactions in batch - txs_batch_limit: 3000 - # Limit of push notifications in batch - push_notifications_batch_limit: 50 # Block polling interval block_poll: min: 3s max: 30s rabbitmq: url: amqp://localhost:5672 - consumer: - prefetch_count: 10 + prefetch_count: 10 postgres: url: postgresql://user:pass@localhost/blockatlas?sslmode=disable diff --git a/config/configuration.go b/config/configuration.go index 746fc04d4..e61f5d82f 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -11,27 +11,21 @@ import ( type Configuration struct { Gin struct { - Mode string `mapstructure:"mode"` - ReverseProxy bool `mapstructure:"reverse_proxy"` + Mode string `mapstructure:"mode"` } `mapstructure:"gin"` - Platform []string `mapstructure:"platform"` - RestAPI string `mapstructure:"rest_api"` - Subscriber string `mapstructure:"subscriber"` - Observer struct { - Backlog time.Duration `mapstructure:"backlog"` - FetchBlocksInterval time.Duration `mapstructure:"fetch_blocks_interval"` - BacklogMaxBlocks int64 `mapstructure:"backlog_max_blocks"` - TxsBatchLimit uint `mapstructure:"txs_batch_limit"` - PushNotificationsBatchLimit int `mapstructure:"push_notifications_batch_limit"` - BlockPoll struct { + Platform []string `mapstructure:"platform"` + RestAPI string `mapstructure:"rest_api"` + Observer struct { + Backlog time.Duration `mapstructure:"backlog"` + FetchBlocksInterval time.Duration `mapstructure:"fetch_blocks_interval"` + BacklogMaxBlocks int64 `mapstructure:"backlog_max_blocks"` + BlockPoll struct { Min time.Duration `mapstructure:"min"` Max time.Duration `mapstructure:"max"` } `mapstructure:"block_poll"` Rabbitmq struct { - URL string `mapstructure:"url"` - Consumer struct { - PrefetchCount int `mapstructure:"prefetch_count"` - } `mapstructure:"consumer"` + URL string `mapstructure:"url"` + PrefetchCount int `mapstructure:"prefetch_count"` } `mapstructure:"rabbitmq"` } `mapstructure:"observer"` Postgres struct { diff --git a/go.mod b/go.mod index c8fda26c4..3d2e89d61 100644 --- a/go.mod +++ b/go.mod @@ -19,10 +19,11 @@ require ( github.com/docker/go-units v0.4.0 // indirect github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 + github.com/google/go-cmp v0.4.0 // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/imroc/req v0.3.0 github.com/mitchellh/mapstructure v1.4.0 - github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf // indirect + github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v1.0.0-rc9 // indirect @@ -39,8 +40,8 @@ require ( github.com/trustwallet/golibs/network v0.0.0-20201215012452-c5d526fed5df go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 - golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 // indirect - golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f // indirect + golang.org/x/net v0.0.0-20201216054612-986b41b23924 // indirect + golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.5 gorm.io/gorm v1.20.8 diff --git a/go.sum b/go.sum index df921e434..cb291605e 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,6 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.15 h1:qkLXKzb1QoVatRyd/YlXZ/Kg0m5K3SPuoD82jjSOaBc= -github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -162,6 +160,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -324,8 +323,8 @@ github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwz github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 h1:SPoLlS9qUUnXcIY4pvA4CTwYjk0Is5f4UPEkeESr53k= github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2/go.mod h1:TjQg8pa4iejrUrjiz0MCtMV38jdMNW4doKSiBrEvCQQ= -github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf h1:Un6PNx5oMK6CCwO3QTUyPiK2mtZnPrpDl5UnZ64eCkw= -github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -514,12 +513,13 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201207224615-747e23833adb h1:xj2oMIbduz83x7tzglytWT7spn6rP+9hvKjTpro6/pM= -golang.org/x/net v0.0.0-20201207224615-747e23833adb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 h1:lwlPPsmjDKK0J6eG6xDWd5XPehI0R024zxjDnw3esPA= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY= +golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -554,13 +554,14 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d h1:MiWWjyhUzZ+jvhZvloX6ZrUsdEghn8a64Upd8EMHglE= -golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f h1:QdHQnPce6K4XQewki9WNbG5KOROuDzqO3NaYjI1cXJ0= golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e h1:AyodaIpKjppX+cBfTASF2E1US3H2JFBj920Ot3rtDjs= +golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/address/address.go b/pkg/address/address.go index 964ca5065..e057bbdc0 100644 --- a/pkg/address/address.go +++ b/pkg/address/address.go @@ -3,12 +3,13 @@ package address import ( "crypto/sha256" "encoding/hex" + "strconv" + "strings" + "github.com/mr-tron/base58" log "github.com/sirupsen/logrus" "github.com/trustwallet/golibs/coin" "golang.org/x/crypto/sha3" - "strconv" - "strings" ) const prefixBitcoinCash = "bitcoincash:" diff --git a/pkg/address/address_test.go b/pkg/address/address_test.go index 8c60ecc50..1b46c9f93 100644 --- a/pkg/address/address_test.go +++ b/pkg/address/address_test.go @@ -1,34 +1,12 @@ package address import ( + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/golibs/coin" - "testing" ) -func TestEIP55Checksum(t *testing.T) { - tests := []struct { - name string - unchecksummed string - want string - }{ - {"test checksum 1", "checktest", "0xChecKTeSt"}, - {"test checksum 2", "trustwallet", "0xtrUstWaLlET"}, - {"test checksum number", "16345785d8a0000", "0x16345785d8A0000"}, - {"test checksum hex", "fffdefefed", "0xFfFDEfeFeD"}, - {"test checksum 3", "0x0000000000000000003731342d4f4e452d354639", "0x0000000000000000003731342d4f4E452d354639"}, - {"test checksum 4", "0000000000000000003731342d4f4e452d354639", "0x0000000000000000003731342d4f4E452d354639"}, - {"test checksum Ethereum address", "0x84a0d77c693adabe0ebc48f88b3ffff010577051", "0x84A0d77c693aDAbE0ebc48F88b3fFFF010577051"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := EIP55Checksum(tt.unchecksummed); got != tt.want { - t.Errorf("EIP55Checksum() = %v, want %v", got, tt.want) - } - }) - } -} - func TestEIP55ChecksumWanchain(t *testing.T) { var ( addr1Wan = "0xae96137e0e05681ed2f5d1af272c3ee512939d0f" diff --git a/services/notifier/base.go b/services/notifier/base.go index cd951de0c..6c0bb20e4 100644 --- a/services/notifier/base.go +++ b/services/notifier/base.go @@ -10,13 +10,9 @@ import ( ) const ( - DefaultPushNotificationsBatchLimit = 50 - Notifier = "Notifier" ) -var MaxPushNotificationsBatchLimit uint = DefaultPushNotificationsBatchLimit - func RunNotifier(database *db.Instance, delivery amqp.Delivery) { defer func() { if err := delivery.Ack(false); err != nil { @@ -39,7 +35,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { addresses[i] = strconv.Itoa(int(txs[0].Coin)) + "_" + addresses[i] } - if len(txs) < 1 { + if len(txs) == 0 { return } subscriptionsDataList, err := database.GetSubscriptionsForNotifications(addresses) @@ -56,11 +52,10 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { notificationsForAddress := buildNotificationsByAddress(ua, txs) notifications = append(notifications, notificationsForAddress...) } - - batches := getNotificationBatches(notifications, MaxPushNotificationsBatchLimit) - - for _, batch := range batches { - publishNotificationBatch(batch) + err = publishNotifications(notifications) + if err != nil { + log.WithFields(log.Fields{"service": Notifier}).Error(err) } + log.Info("------------------------------------------------------------") } diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index 36f47250d..fdf0504ff 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -2,9 +2,6 @@ package notifier import ( "encoding/json" - "errors" - - "github.com/trustwallet/golibs/coin" log "github.com/sirupsen/logrus" "github.com/streadway/amqp" @@ -13,30 +10,31 @@ import ( ) func GetTransactionsFromDelivery(delivery amqp.Delivery, service string) (blockatlas.Txs, error) { - var txs blockatlas.Txs + var transactions blockatlas.Txs - if err := json.Unmarshal(delivery.Body, &txs); err != nil { + if err := json.Unmarshal(delivery.Body, &transactions); err != nil { return nil, err } - if len(txs) == 0 { - return nil, errors.New("empty txs list") - } - - log.WithFields(log.Fields{"service": service, "txs": len(txs), "coin": coin.Coins[txs[0].Coin].Handle}).Info("Consumed") + log.WithFields(log.Fields{"service": service, "notifications": len(transactions)}).Info("Consumed") - return txs, nil + return transactions, nil } -func publishNotificationBatch(batch []TransactionNotification) { - raw, err := json.Marshal(batch) - if err != nil { - log.Fatal("publishNotificationBatch marshal: ", err) - } - err = mq.TxNotifications.Publish(raw) - if err != nil { - log.Fatal("publishNotificationBatch publish:", err) +func publishNotifications(notifications []TransactionNotification) error { + for _, notification := range notifications { + raw, err := json.Marshal(notification) + if err != nil { + return err + } + //Use use Tx() / Commit() to provide consistency + err = mq.TxNotifications.Publish(raw) + if err != nil { + return err + } } - log.WithFields(log.Fields{"service": Notifier, "txs": len(batch)}).Info("Txs batch dispatched") + log.WithFields(log.Fields{"service": Notifier, "notifications": len(notifications)}).Info("Notifications send") + + return nil } diff --git a/services/notifier/models.go b/services/notifier/models.go index b60f8194a..65748e0b7 100644 --- a/services/notifier/models.go +++ b/services/notifier/models.go @@ -9,21 +9,6 @@ type TransactionNotification struct { Result blockatlas.Tx `json:"result"` } -func getNotificationBatches(notifications []TransactionNotification, sizeUint uint) [][]TransactionNotification { - size := int(sizeUint) - resultLength := (len(notifications) + size - 1) / size - result := make([][]TransactionNotification, resultLength) - lo, hi := 0, size - for i := range result { - if hi > len(notifications) { - hi = len(notifications) - } - result[i] = notifications[lo:hi:hi] - lo, hi = hi, hi+size - } - return result -} - func buildNotificationsByAddress(address string, txs blockatlas.Txs) []TransactionNotification { transactionsByAddress := toUniqueTransactions(findTransactionsByAddress(txs, address)) diff --git a/services/parser/parser.go b/services/parser/parser.go index 3efe20af5..cf804b8be 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -30,7 +30,6 @@ type ( BacklogCount int MaxBacklogBlocks int64 StopChannel chan<- struct{} - TxBatchLimit uint Database *db.Instance } @@ -41,8 +40,6 @@ type ( } ) -const MinTxsBatchLimit = 500 - func RunParser(params Params) { log.Info("------------------------------------------------------------") for { @@ -83,10 +80,17 @@ func parse(params Params) { return } - txs := ConvertToBatch(blocks) - txs = blockatlas.Txs(blockatlas.TxPage(txs).FilterTransactionsByMemo()) + var txs []blockatlas.Tx + for _, block := range blocks { + txs = append(txs, block.Txs...) + } + txs = blockatlas.TxPage(txs).FilterTransactionsByMemo() + + publish(params, txs) - PublishTransactionsBatch(params, txs) + log.WithFields(log.Fields{ + "transactions": len(txs), + }).Info("Published transactions") log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Info("End of parse step") } @@ -114,8 +118,10 @@ func GetBlocksIntervalToFetch(params Params) (int64, int64, error) { func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatlas.Block { if lastParsedBlock == currentBlock { - log.WithFields(log.Fields{"last": lastParsedBlock, "coin": params.Api.Coin().Handle, "time": time.Now().Unix()}). - Info("No new blocks") + log.WithFields(log.Fields{ + "block": lastParsedBlock, + "coin": params.Api.Coin().Handle, + }).Info("No new blocks") return nil } @@ -165,8 +171,13 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatla blocksList = append(blocksList, block) } - log.WithFields(log.Fields{"from": lastParsedBlock, "to": currentBlock, "total": totalCount, "coin": params.Api.Coin().Handle}). - Info("Fetched blocks batch") + log.WithFields(log.Fields{ + "from": lastParsedBlock, + "to": currentBlock, + "total": totalCount, + "coin": params.Api.Coin().Handle}, + ).Info("Fetched blocks batch") + return blocksList } @@ -193,63 +204,27 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { lastBlockNumber := blocks[len(blocks)-1].Number if lastBlockNumber <= 0 { - return fmt.Errorf("parser of %s failed to save last block, lastBlockNumber <= 0", - params.Api.Coin().Handle) + return fmt.Errorf("parser of %s failed to save last block, lastBlockNumber <= 0", params.Api.Coin().Handle) } err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().Handle, lastBlockNumber) if err != nil { return err } - log.WithFields(log.Fields{"block": lastBlockNumber, "coin": params.Api.Coin().Handle}). - Info("Save last parsed block") + log.WithFields(log.Fields{ + "block": lastBlockNumber, + "coin": params.Api.Coin().Handle, + }).Info("Save last parsed block") + return nil } -func ConvertToBatch(blocks []blockatlas.Block) blockatlas.Txs { - if len(blocks) == 0 { - return nil - } - - var txs []blockatlas.Tx - - for _, block := range blocks { - txs = append(txs, block.Txs...) - } - - return txs -} +func publish(params Params, txs blockatlas.Txs) { -func PublishTransactionsBatch(params Params, txs blockatlas.Txs) { if len(txs) == 0 { return } - batches := getTxsBatches(txs, params.TxBatchLimit) - - for _, batch := range batches { - publish(params, batch) - } - - log.WithFields(log.Fields{"txs": len(txs), "batchCount": len(batches)}).Info("Published transactions batch") -} - -func getTxsBatches(txs blockatlas.Txs, sizeUint uint) []blockatlas.Txs { - size := int(sizeUint) - resultLength := (len(txs) + size - 1) / size - result := make([]blockatlas.Txs, resultLength) - lo, hi := 0, size - for i := range result { - if hi > len(txs) { - hi = len(txs) - } - result[i] = txs[lo:hi:hi] - lo, hi = hi, hi+size - } - return result -} - -func publish(params Params, txs blockatlas.Txs) { body, err := json.Marshal(txs) if err != nil { log.WithFields(log.Fields{"operation": "publish marshal", "coin": params.Api.Coin().Handle}).Error(err) @@ -302,8 +277,12 @@ func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumb jitter := time.Duration(rand.Int63n(int64(sleep))) sleep = sleep + jitter/2 - log.WithFields(log.Fields{"number": n, "attempts": attempts, "sleep": sleep.String(), "symbol": symbol}). - Warn("retry GetBlockByNumber") + log.WithFields(log.Fields{ + "number": n, + "attempts": attempts, + "sleep": sleep.String(), + "symbol": symbol}, + ).Warn("retry GetBlockByNumber") time.Sleep(sleep) return getBlockByNumberWithRetry(attempts, sleep*2, getBlockByNumber, n, symbol) diff --git a/services/parser/parser_test.go b/services/parser/parser_test.go index 20a268cd0..a00d72860 100644 --- a/services/parser/parser_test.go +++ b/services/parser/parser_test.go @@ -2,7 +2,6 @@ package parser import ( "errors" - "reflect" "testing" "time" @@ -14,32 +13,6 @@ import ( var ( wantedMockedNumber int64 - - block = blockatlas.Block{ - Number: 110, - ID: "", - Txs: []blockatlas.Tx{ - { - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: blockatlas.NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, - }, - }, - } ) func TestFetchBlocks(t *testing.T) { @@ -53,7 +26,6 @@ func TestFetchBlocks(t *testing.T) { BacklogCount: 0, MaxBacklogBlocks: 0, StopChannel: nil, - TxBatchLimit: 0, Database: nil, } blocks := FetchBlocks(params, 0, 100) @@ -116,41 +88,6 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { return &blockatlas.Block{}, nil } -func TestGetTxBatches(t *testing.T) { - txs := make(blockatlas.Txs, 10000) - batches := getTxsBatches(txs, 1000) - assert.Len(t, batches, 10) - batches = getTxsBatches(txs, 100) - assert.Len(t, batches, 100) - batches = getTxsBatches(txs, 500) - assert.Len(t, batches, 20) - - txs = make(blockatlas.Txs, 3800) - batches = getTxsBatches(txs, 100) - assert.Len(t, batches, 38) - batches = getTxsBatches(txs, 1000) - assert.Len(t, batches, 4) - - txs = make(blockatlas.Txs, 5000) - batches = getTxsBatches(txs, 10000) - assert.Len(t, batches, 1) - - txs = make(blockatlas.Txs, 0) - batches = getTxsBatches(txs, 100) - assert.Len(t, batches, 0) - - txs = make(blockatlas.Txs, 0) - batches = getTxsBatches(txs, 100) - assert.Len(t, batches, 0) - - batches = getTxsBatches(nil, 100) - assert.Len(t, batches, 0) - - txs = make(blockatlas.Txs, 1000000) - batches = getTxsBatches(txs, 5000) - assert.Len(t, batches, 200) -} - func TestGetInterval(t *testing.T) { min, _ := time.ParseDuration("2s") max, _ := time.ParseDuration("30s") @@ -197,32 +134,3 @@ func TestGetInterval(t *testing.T) { }) } } - -func TestConvertToBatch(t *testing.T) { - type args struct { - blocks []blockatlas.Block - } - tests := []struct { - name string - args args - want blockatlas.Txs - }{ - { - "Convert to batch", - args{ - []blockatlas.Block{ - block, - block, - }, - }, - append(block.Txs, block.Txs...), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := ConvertToBatch(tt.args.blocks); !reflect.DeepEqual(got, tt.want) { - t.Errorf("ConvertToBatch() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 240f17728..687ff82d5 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -102,8 +102,8 @@ func (p *PlatformFullFlow) GetBlockByNumber(num int64) (*blockatlas.Block, error } func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel context.CancelFunc, counter int) { - var notifications []notifier.TransactionNotification - if err := json.Unmarshal(delivery.Body, ¬ifications); err != nil { + var notification notifier.TransactionNotification + if err := json.Unmarshal(delivery.Body, ¬ification); err != nil { assert.Nil(t, err) return } @@ -136,7 +136,7 @@ func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel Memo: "123", Meta: &memo, }, - }, notifications[0]) + }, notification) if counter == 10 { cancel() @@ -157,7 +157,6 @@ func setupParserFull(stopChan chan<- struct{}) parser.Params { ParsingBlocksInterval: pollInterval, BacklogCount: backlogCount, MaxBacklogBlocks: int64(maxBatchBlocksAmount), - TxBatchLimit: 100, StopChannel: stopChan, } } diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index d1cf2e2fe..af25eb046 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -60,8 +60,8 @@ func TestNotifier(t *testing.T) { } func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { - var notifications []notifier.TransactionNotification - if err := json.Unmarshal(delivery.Body, ¬ifications); err != nil { + var notification notifier.TransactionNotification + if err := json.Unmarshal(delivery.Body, ¬ification); err != nil { assert.Nil(t, err) return } @@ -96,7 +96,7 @@ func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { Memo: "test", Meta: &memo, }, - }, notifications[0]) + }, notification) return } diff --git a/tests/integration/observer_test/parser_test.go b/tests/integration/observer_test/parser_test.go index 3ef3f37b7..868f3dd9a 100644 --- a/tests/integration/observer_test/parser_test.go +++ b/tests/integration/observer_test/parser_test.go @@ -5,6 +5,9 @@ package observer_test import ( "context" "encoding/json" + "testing" + "time" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/stretchr/testify/assert" @@ -13,8 +16,6 @@ import ( "github.com/trustwallet/blockatlas/services/parser" "github.com/trustwallet/blockatlas/tests/integration/setup" "github.com/trustwallet/golibs/coin" - "testing" - "time" ) func TestParserFetchAndPublishBlock_NormalCase(t *testing.T) { @@ -113,7 +114,6 @@ func setupParser(stopChan chan struct{}) parser.Params { ParsingBlocksInterval: pollInterval, BacklogCount: backlogCount, MaxBacklogBlocks: int64(maxBatchBlocksAmount), - TxBatchLimit: 100, StopChannel: stopChan, } } From 5cb5b9fcb5c83e5ea6c5b36c195106b5a612fcc0 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Mon, 21 Dec 2020 22:45:13 -0800 Subject: [PATCH 435/506] Remove KIN support (#1333) * Switch back to * Remove KIN support --- config.yml | 4 ---- config/configuration.go | 3 --- platform/platform.go | 1 - services/notifier/delivery.go | 17 +++++++---------- .../integration/observer_test/full_flow_test.go | 6 +++--- .../integration/observer_test/notifier_test.go | 6 +++--- 6 files changed, 13 insertions(+), 24 deletions(-) diff --git a/config.yml b/config.yml index ad829ec35..818410042 100644 --- a/config.yml +++ b/config.yml @@ -45,10 +45,6 @@ ripple: stellar: api: https://horizon.stellar.org -# [KIN] Kin: https://www.kin.org -kin: - api: https://horizon-block-explorer.kininfrastructure.com - # [XTZ] Tezos: https://tezos.com tezos: api: https://api.tzstats.com/explorer # https://tzstats.com/docs/api/index.html#introduction diff --git a/config/configuration.go b/config/configuration.go index e61f5d82f..df8cc5bf3 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -49,9 +49,6 @@ type Configuration struct { Stellar struct { API string `mapstructure:"api"` } `mapstructure:"stellar"` - Kin struct { - API string `mapstructure:"api"` - } `mapstructure:"kin"` Nimiq struct { API string `mapstructure:"api"` } `mapstructure:"nimiq"` diff --git a/platform/platform.go b/platform/platform.go index 1f381e29b..487d3237d 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -69,7 +69,6 @@ func getAllHandlers() blockatlas.Platforms { 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.Kin().Handle: stellar.Init(coin.KIN, config.Default.Kin.API), coin.Cosmos().Handle: cosmos.Init(coin.ATOM, 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), diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index fdf0504ff..4d3864b7d 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -22,16 +22,13 @@ func GetTransactionsFromDelivery(delivery amqp.Delivery, service string) (blocka } func publishNotifications(notifications []TransactionNotification) error { - for _, notification := range notifications { - raw, err := json.Marshal(notification) - if err != nil { - return err - } - //Use use Tx() / Commit() to provide consistency - err = mq.TxNotifications.Publish(raw) - if err != nil { - return err - } + raw, err := json.Marshal(notifications) + if err != nil { + return err + } + err = mq.TxNotifications.Publish(raw) + if err != nil { + return err } log.WithFields(log.Fields{"service": Notifier, "notifications": len(notifications)}).Info("Notifications send") diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go index 687ff82d5..2c949108f 100644 --- a/tests/integration/observer_test/full_flow_test.go +++ b/tests/integration/observer_test/full_flow_test.go @@ -102,8 +102,8 @@ func (p *PlatformFullFlow) GetBlockByNumber(num int64) (*blockatlas.Block, error } func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel context.CancelFunc, counter int) { - var notification notifier.TransactionNotification - if err := json.Unmarshal(delivery.Body, ¬ification); err != nil { + var notifications []notifier.TransactionNotification + if err := json.Unmarshal(delivery.Body, ¬ifications); err != nil { assert.Nil(t, err) return } @@ -136,7 +136,7 @@ func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel Memo: "123", Meta: &memo, }, - }, notification) + }, notifications[0]) if counter == 10 { cancel() diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go index af25eb046..d1cf2e2fe 100644 --- a/tests/integration/observer_test/notifier_test.go +++ b/tests/integration/observer_test/notifier_test.go @@ -60,8 +60,8 @@ func TestNotifier(t *testing.T) { } func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { - var notification notifier.TransactionNotification - if err := json.Unmarshal(delivery.Body, ¬ification); err != nil { + var notifications []notifier.TransactionNotification + if err := json.Unmarshal(delivery.Body, ¬ifications); err != nil { assert.Nil(t, err) return } @@ -96,7 +96,7 @@ func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { Memo: "test", Meta: &memo, }, - }, notification) + }, notifications[0]) return } From 54840980e6c32378609c5aabb1a754fec0bdbf38 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 22 Dec 2020 17:48:43 +0900 Subject: [PATCH 436/506] move pubsub package to golibs (#1326) * move pubsub package to golibs * move pubsub test to golibs too --- go.mod | 7 +- go.sum | 37 +---- pubsub/mqclient/mq_client.go | 182 --------------------- pubsub/mqclient/mq_stream.go | 95 ----------- pubsub/pubsub.go | 34 ---- tests/integration/pubsub/pubsub_mq_test.go | 94 ----------- 6 files changed, 6 insertions(+), 443 deletions(-) delete mode 100644 pubsub/mqclient/mq_client.go delete mode 100644 pubsub/mqclient/mq_stream.go delete mode 100644 pubsub/pubsub.go delete mode 100644 tests/integration/pubsub/pubsub_mq_test.go diff --git a/go.mod b/go.mod index 3d2e89d61..f70455e0b 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 // indirect github.com/deckarep/golang-set v1.7.1 github.com/docker/go-connections v0.4.0 // indirect @@ -23,12 +22,10 @@ require ( github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/imroc/req v0.3.0 github.com/mitchellh/mapstructure v1.4.0 - github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v1.0.0-rc9 // indirect github.com/ory/dockertest v3.3.5+incompatible - github.com/ory/dockertest/v3 v3.6.2 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible github.com/sirupsen/logrus v1.7.0 github.com/spf13/viper v1.7.1 @@ -36,8 +33,8 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/swag v1.7.0 - github.com/trustwallet/golibs v0.0.23 - github.com/trustwallet/golibs/network v0.0.0-20201215012452-c5d526fed5df + github.com/trustwallet/golibs v0.0.26 + github.com/trustwallet/golibs/network v0.0.0-20201216013232-f564db1c6ecd go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201216054612-986b41b23924 // indirect diff --git a/go.sum b/go.sum index cb291605e..356801871 100644 --- a/go.sum +++ b/go.sum @@ -19,7 +19,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -54,17 +53,12 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= -github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= -github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 h1:6ejg6Lkk8dskcM7wQ28gONkukbQkM4qpj4RnYbpFzrI= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -75,8 +69,6 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -126,7 +118,6 @@ github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd github.com/go-openapi/spec v0.19.14 h1:r4fbYFo6N4ZelmSX8G6p+cv/hZRXzcuqQIADGT1iNKM= github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.11 h1:RFTu/dlFySpyVvJDfp/7674JY4SDglYWKztbiIGFpmc= github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY= @@ -158,7 +149,6 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -286,7 +276,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -321,10 +310,6 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 h1:SPoLlS9qUUnXcIY4pvA4CTwYjk0Is5f4UPEkeESr53k= -github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2/go.mod h1:TjQg8pa4iejrUrjiz0MCtMV38jdMNW4doKSiBrEvCQQ= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -338,7 +323,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -347,8 +331,6 @@ github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/ory/dockertest/v3 v3.6.2 h1:Q3Y8naCMyC1Nw91BHum1bGyEsNQc/UOIYS3ZoPoou0g= -github.com/ory/dockertest/v3 v3.6.2/go.mod h1:EFLcVUOl8qCwp9NyDAcCDtq/QviLtYswW/VbWzUnTNE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -428,10 +410,10 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.23 h1:AGmmD52idzGypf2MX5BXuq6Pz+AEUGkyCOnfKODK/2U= -github.com/trustwallet/golibs v0.0.23/go.mod h1:Vi63TTS0yRAPwFIIKe7tw1yTgd71RACQqgZpUcWTv04= -github.com/trustwallet/golibs/network v0.0.0-20201215012452-c5d526fed5df h1:ps2pYgkR6p/YExq9pOmLNTVRm0CwjEKH0mOPD2rsj/Q= -github.com/trustwallet/golibs/network v0.0.0-20201215012452-c5d526fed5df/go.mod h1:klL63JlvgRSc+vpAd5TsTsyqR75+N2mPYd1PCg/+jBo= +github.com/trustwallet/golibs v0.0.26 h1:8Cfym03kkkvQkzdp7ZBPIX0583jmL5d0x910psyHbpM= +github.com/trustwallet/golibs v0.0.26/go.mod h1:Vi63TTS0yRAPwFIIKe7tw1yTgd71RACQqgZpUcWTv04= +github.com/trustwallet/golibs/network v0.0.0-20201216013232-f564db1c6ecd h1:7G8l+qBLmLu45AClEbBs1puJS0j2TSvpjFztQTxg1YI= +github.com/trustwallet/golibs/network v0.0.0-20201216013232-f564db1c6ecd/go.mod h1:klL63JlvgRSc+vpAd5TsTsyqR75+N2mPYd1PCg/+jBo= 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= @@ -513,11 +495,8 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 h1:lwlPPsmjDKK0J6eG6xDWd5XPehI0R024zxjDnw3esPA= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -554,12 +533,9 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f h1:QdHQnPce6K4XQewki9WNbG5KOROuDzqO3NaYjI1cXJ0= -golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e h1:AyodaIpKjppX+cBfTASF2E1US3H2JFBj920Ot3rtDjs= golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -567,7 +543,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -588,7 +563,6 @@ golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -604,7 +578,6 @@ golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -648,7 +621,6 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -662,7 +634,6 @@ gorm.io/gorm v1.20.8 h1:iToaOdZgjNvlc44NFkxfLa3U9q63qwaxt0FdNCiwOMs= gorm.io/gorm v1.20.8/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= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pubsub/mqclient/mq_client.go b/pubsub/mqclient/mq_client.go deleted file mode 100644 index 603edf710..000000000 --- a/pubsub/mqclient/mq_client.go +++ /dev/null @@ -1,182 +0,0 @@ -package mqclient - -import ( - "context" - "errors" - log "github.com/sirupsen/logrus" - "github.com/streadway/amqp" - "github.com/trustwallet/blockatlas/pubsub" - "go.uber.org/atomic" - "time" -) - -var ( - reconnectDelay = 5 * time.Second - resendDelay = 5 * time.Second -) - -type Client struct { - uri string - conn *amqp.Connection - channel *amqp.Channel - prefetchCount int - streams []*pubsub.Stream - ctx context.Context - notifyClose chan *amqp.Error - notifyConfirm chan amqp.Confirmation - isConnected *atomic.Bool - alive *atomic.Bool -} - -func New(uri string, prefetchCount int, ctx context.Context) (client pubsub.Client) { - client = &Client{ - uri: uri, - ctx: ctx, - alive: atomic.NewBool(false), - isConnected: atomic.NewBool(false), - prefetchCount: prefetchCount, - streams: []*pubsub.Stream{}, - } - return client -} - -func (c *Client) Connect() error { - conn, err := amqp.Dial(c.uri) - if err != nil { - log.Error("Client.connect MQ Dial issue " + err.Error()) - return err - } - ch, err := conn.Channel() - if err != nil { - log.Error("Client.connect MQ Channel issue " + err.Error()) - return err - } - err = ch.Confirm(false) - if err != nil { - log.Error("Client.connect MQ Channel issue " + err.Error()) - } - log.Debug("Interface: ", c) - c.conn = conn - c.channel = ch - c.notifyClose = make(chan *amqp.Error) - c.notifyConfirm = make(chan amqp.Confirmation) - c.channel.NotifyClose(c.notifyClose) - c.channel.NotifyPublish(c.notifyConfirm) - c.isConnected.Store(true) - return nil -} - -func (c *Client) Run() error { - log.Debug("Interface: ", c) - if c.conn == nil { - return errors.New("connect firstly") - } - go c.handleReconnect() - err := c.channel.Qos(c.prefetchCount, 0, false) - if err != nil { - return errors.New("Client.connect MQ Qos issue " + err.Error()) - } - for _, stream := range c.streams { - if !(*stream).IsConnected() { - go (*stream).Connect(c.ctx) - } - } - return nil -} - -func (c *Client) IsConnected() bool { - return c.isConnected.Load() -} - -func (c *Client) AddStream(consumer *pubsub.Consumer, isWriteOnly bool) error { - var stream pubsub.Stream = &Stream{ - consumer: consumer, - client: c, - isConnected: atomic.NewBool(false), - isWriteOnly: isWriteOnly, - channel: c.channel, - } - go stream.Connect(c.ctx) // Try connect, if client isn't run it will wait run - c.streams = append(c.streams, &stream) - return nil -} - -func (c *Client) Push(queue string, data []byte) error { - if !c.isConnected.Load() { - // TODO: Is should wait connect to RabbitMQ or not? - return errors.New("failed to push push: not connected") - } - - //todo Add stream waiting - for { - err := c.PushUnsafe(queue, data) - if err != nil { - log.Error("Client.Push MQ issue " + err.Error()) - if err == pubsub.ErrDisconnected { - continue - } - return err - } - select { - case confirm := <-c.notifyConfirm: - if confirm.Ack { - return nil - } - case <-time.After(resendDelay): - } - } -} - -func (c *Client) PushUnsafe(queue string, data []byte) error { - if !c.isConnected.Load() { - return pubsub.ErrDisconnected - } - return c.channel.Publish( - "", // Exchange - string(queue), // Routing key - false, // Mandatory - false, // Immediate - amqp.Publishing{ - ContentType: "text/plain", - Body: data, - }, - ) -} - -func (c *Client) Close() error { - err := c.channel.Close() - if err != nil { - return errors.New("Client.Close MQ issue " + err.Error()) - } - - err = c.conn.Close() - if err != nil { - return errors.New("Client.Close MQ issue " + err.Error()) - } - return nil -} - -func (c *Client) handleReconnect() { - for c.alive.Load() { - log.Debug("Try connect after alive") - c.isConnected.Store(false) - for c.Connect() != nil { - log.Debug("Try connect") - if !c.alive.Load() { - return - } - select { - case <-c.ctx.Done(): - return - case <-time.After(reconnectDelay + time.Second): - // Add metric - } - } - select { - case <-c.ctx.Done(): - log.Fatal("Fucking end") - return - case <-c.notifyClose: - } - } -} diff --git a/pubsub/mqclient/mq_stream.go b/pubsub/mqclient/mq_stream.go deleted file mode 100644 index 04336b94a..000000000 --- a/pubsub/mqclient/mq_stream.go +++ /dev/null @@ -1,95 +0,0 @@ -package mqclient - -import ( - "context" - log "github.com/sirupsen/logrus" - "github.com/streadway/amqp" - "github.com/trustwallet/blockatlas/pubsub" - "go.uber.org/atomic" - "time" -) - -type Stream struct { - consumer *pubsub.Consumer - client pubsub.Client - channel *amqp.Channel - isConnected *atomic.Bool - isWriteOnly bool -} - -func (s *Stream) Connect(cancelCtx context.Context) { - s.isConnected.Store(true) - for { - if s.client.IsConnected() { - break - } - time.Sleep(1 * time.Second) - } - s.declareQueue() - if s.isWriteOnly { - return - } - messageChannel, err := s.channel.Consume( - (*s.consumer).GetQueue(), - "", - false, - false, - false, - false, - nil, - ) - if err != nil { - s.isConnected.Store(false) - log.Fatal("GetMessageChannel MQ issue "+err.Error(), (*s.consumer).GetQueue()) - } - for { - select { - case <-cancelCtx.Done(): - log.Info("Consumer stopped") - return - case msg, ok := <-messageChannel: - if !ok { - s.isConnected.Store(false) - return - } - if msg.Body != nil { - s.delivery(msg) - } - } - } -} -func (s *Stream) GetConsumer() *pubsub.Consumer { - return s.consumer -} - -func (s *Stream) GetClient() *pubsub.Client { - return &s.client -} - -func (s *Stream) IsConnected() bool { - return s.isConnected.Load() -} - -func (s *Stream) IsWriteOnly() bool { - return s.isWriteOnly -} - -func (s *Stream) declareQueue() { - _, err := s.channel.QueueDeclare((*s.consumer).GetQueue(), true, false, false, false, nil) - if err != nil { - log.Fatal("Stream.Init MQ issue "+err.Error(), (*s.consumer).GetQueue()) - } -} - -func (s *Stream) delivery(msg amqp.Delivery) { - if (*s.consumer).Callback(msg) == nil { - ack((*s.consumer).GetQueue(), msg) - } -} - -func ack(queue string, msg amqp.Delivery) { - err := msg.Ack(false) - if err != nil { - log.Error("Stream Ack MQ issue on queue: ", queue, err) - } -} diff --git a/pubsub/pubsub.go b/pubsub/pubsub.go deleted file mode 100644 index 300930af9..000000000 --- a/pubsub/pubsub.go +++ /dev/null @@ -1,34 +0,0 @@ -package pubsub - -import ( - "context" - "errors" - "github.com/streadway/amqp" -) - -var ( - ErrDisconnected = errors.New("disconnected from rabbitmq, trying to reconnect") -) - -type Client interface { - Connect() error - Run() error - IsConnected() bool - AddStream(consumer *Consumer, isWriteOnly bool) error - Push(queue string, data []byte) error - PushUnsafe(queue string, data []byte) error - Close() error -} - -type Stream interface { - Connect(cancelCtx context.Context) - GetConsumer() *Consumer - GetClient() *Client - IsConnected() bool - IsWriteOnly() bool -} - -type Consumer interface { - GetQueue() string - Callback(msg amqp.Delivery) error -} diff --git a/tests/integration/pubsub/pubsub_mq_test.go b/tests/integration/pubsub/pubsub_mq_test.go deleted file mode 100644 index 545f7fbc4..000000000 --- a/tests/integration/pubsub/pubsub_mq_test.go +++ /dev/null @@ -1,94 +0,0 @@ -// +build integration - -package pubsub_test - -import ( - "context" - "fmt" - "github.com/ory/dockertest" - log "github.com/sirupsen/logrus" - "github.com/streadway/amqp" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pubsub" - "github.com/trustwallet/blockatlas/pubsub/mqclient" - "os" - "sync" - "testing" - "time" -) - -var ( - mqResource *dockertest.Resource - mqClient pubsub.Client - ctx context.Context -) - -type RawTransactionConsumer struct { - TestFunc func(delivery amqp.Delivery) -} - -func (c RawTransactionConsumer) GetQueue() string { - return string("test_queue") -} - -func (c RawTransactionConsumer) Callback(msg amqp.Delivery) error { - c.TestFunc(msg) - return nil -} - -func TestMain(m *testing.M) { - ctx = context.Background() - if err := runMQContainer(); err != nil { - log.Fatal("container doesn't start: ", err) - } - - code := m.Run() - - log.Error(stopMQContainer()) - os.Exit(code) -} - -func TestMqConnect(t *testing.T) { - var wg sync.WaitGroup - wg.Add(1) - var consumer pubsub.Consumer - consumer = RawTransactionConsumer{ - TestFunc: func(msg amqp.Delivery) { - defer wg.Done() - assert.Equal(t, string(msg.Body), `{"message":"test"}`) - }, - } - assert.Nil(t, mqClient.AddStream(&consumer, false)) - time.Sleep(10 * time.Second) - assert.Nil(t, mqClient.Push(consumer.GetQueue(), []byte(`{"message":"test"}`))) - wg.Wait() -} - -func runMQContainer() error { - var err error - pool, err := dockertest.NewPool("") - if err != nil { - log.Fatalf("Could not connect to docker: %s", err) - } - - mqResource, err = pool.Run("rabbitmq", "latest", nil) - if err != nil { - log.Fatalf("Could not start resource: %s", err) - } - //time.Sleep(10 * time.Second) - if err = pool.Retry(func() error { - uri := fmt.Sprintf("amqp://localhost:%s", mqResource.GetPort("5672/tcp")) - mqClient = mqclient.New(uri, 10, ctx) - return mqClient.Connect() - }); err != nil { - stopMQContainer() - return err - } - - return mqClient.Run() -} - -func stopMQContainer() error { - mqClient.Close() - return mqResource.Close() -} From 368e2b306b1f352d807c3a89d6f8b755b073105c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 25 Dec 2020 22:24:15 +0900 Subject: [PATCH 437/506] Bump gorm.io/driver/postgres from 1.0.5 to 1.0.6 (#1334) Bumps [gorm.io/driver/postgres](https://github.com/go-gorm/postgres) from 1.0.5 to 1.0.6. - [Release notes](https://github.com/go-gorm/postgres/releases) - [Commits](https://github.com/go-gorm/postgres/compare/v1.0.5...v1.0.6) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f70455e0b..cc6e869a0 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( golang.org/x/net v0.0.0-20201216054612-986b41b23924 // indirect golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e // indirect gopkg.in/yaml.v2 v2.4.0 - gorm.io/driver/postgres v1.0.5 + gorm.io/driver/postgres v1.0.6 gorm.io/gorm v1.20.8 gotest.tools v2.2.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index 356801871..0c18ea539 100644 --- a/go.sum +++ b/go.sum @@ -205,6 +205,7 @@ github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.7.0 h1:pwjzcYyfmz/HQOQlENvG1OcDqauTGaqlVahq934F0/U= github.com/jackc/pgconn v1.7.0/go.mod h1:sF/lPpNEMEOp+IYhyQGdAvrG20gWf6A1tKlr0v7JMeA= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA= @@ -220,6 +221,7 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1: github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.5 h1:NUbEWPmCQZbMmYlTjVoNPhc0CfnYyz2bfUAh6A5ZVJM= github.com/jackc/pgproto3/v2 v2.0.5/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= @@ -231,6 +233,7 @@ github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkAL github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= github.com/jackc/pgtype v1.5.0 h1:jzBqRk2HFG2CV4AIwgCI2PwTgm6UUoCAK2ofHHRirtc= github.com/jackc/pgtype v1.5.0/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= +github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= @@ -239,11 +242,13 @@ github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6 github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= github.com/jackc/pgx/v4 v4.9.0 h1:6STjDqppM2ROy5p1wNDcsC7zJTjSHeuCsguZmXyzx7c= github.com/jackc/pgx/v4 v4.9.0/go.mod h1:MNGWmViCgqbZck9ujOOBN63gK9XVGILXWCvKLGKmnms= +github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= @@ -629,6 +634,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.0.5 h1:raX6ezL/ciUmaYTvOq48jq1GE95aMC0CmxQYbxQ4Ufw= gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOudXNCA= +gorm.io/driver/postgres v1.0.6/go.mod h1:r0nvX27yHDNbVeXMM9Y+9i5xSePcT18RfH8clP6wpwI= gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.8 h1:iToaOdZgjNvlc44NFkxfLa3U9q63qwaxt0FdNCiwOMs= gorm.io/gorm v1.20.8/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= From ecd5724f6f0f2c1f077fbc4653352600ce5d7d18 Mon Sep 17 00:00:00 2001 From: Viacheslav Kulish <32914239+vcoolish@users.noreply.github.com> Date: Sat, 26 Dec 2020 01:36:27 +0200 Subject: [PATCH 438/506] Add Kava token transactions support (#1332) * Add Kava token transactions support * Check empty messages --- platform/kava/client.go | 2 +- platform/kava/transaction.go | 47 ++++++++- platform/kava/transaction_test.go | 156 ++++++++++++++++++++++++++---- 3 files changed, 183 insertions(+), 22 deletions(-) diff --git a/platform/kava/client.go b/platform/kava/client.go index 6139a681f..21b25f3fa 100644 --- a/platform/kava/client.go +++ b/platform/kava/client.go @@ -14,7 +14,7 @@ type Client struct { blockatlas.Request } -// GetAddrTxs - get all ATOM transactions for a given address +// GetAddrTxs - get all KAVA transactions for a given address func (c *Client) GetAddrTxs(address, tag string, page int) (txs TxPage, err error) { query := url.Values{ tag: {address}, diff --git a/platform/kava/transaction.go b/platform/kava/transaction.go index 9edb05c14..cb0e4684b 100644 --- a/platform/kava/transaction.go +++ b/platform/kava/transaction.go @@ -2,6 +2,7 @@ package kava import ( "strconv" + "strings" "sync" "time" @@ -10,7 +11,13 @@ import ( "github.com/trustwallet/golibs/numbers" ) +const kavaDenom = "ukava" + func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + return p.GetTokenTxsByAddress(address, kavaDenom) +} + +func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { tagsList := []string{"transfer.recipient", "message.sender"} var wg sync.WaitGroup out := make(chan []Tx, len(tagsList)) @@ -49,11 +56,26 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { close(out) srcTxs := make([]Tx, 0) for r := range out { - srcTxs = append(srcTxs, r...) + filteredTxs := p.FilterTxsByDenom(r, token) + srcTxs = append(srcTxs, filteredTxs...) } return p.NormalizeTxs(srcTxs), nil } +func (p *Platform) FilterTxsByDenom(txs []Tx, denom string) []Tx { + filteredTxs := make([]Tx, 0) + for _, tx := range txs { + messages := tx.Data.Contents.Message + if len(messages) == 0 { + continue + } + if messages[0].Value.(MessageValueTransfer).Amount[0].Denom == denom { + filteredTxs = append(filteredTxs, tx) + } + } + return filteredTxs +} + // NormalizeTxs converts multiple Cosmos transactions func (p *Platform) NormalizeTxs(srcTxs []Tx) blockatlas.TxPage { txMap := make(map[string]bool) @@ -132,7 +154,8 @@ func (p *Platform) fillTransfer(tx *blockatlas.Tx, transfer MessageValueTransfer if len(transfer.Amount) == 0 { return } - value, err := numbers.DecimalToSatoshis(transfer.Amount[0].Quantity) + amount := transfer.Amount[0] + value, err := numbers.DecimalToSatoshis(amount.Quantity) if err != nil { return } @@ -144,6 +167,26 @@ func (p *Platform) fillTransfer(tx *blockatlas.Tx, transfer MessageValueTransfer Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, } + switch { + case amount.Denom == kavaDenom: + tx.Type = blockatlas.TxTransfer + tx.Meta = blockatlas.Transfer{ + Value: blockatlas.Amount(value), + Symbol: p.Coin().Symbol, + Decimals: p.Coin().Decimals, + } + default: + tx.Type = blockatlas.TxNativeTokenTransfer + tx.Meta = blockatlas.NativeTokenTransfer{ + Decimals: p.Coin().Decimals, + From: tx.From, + Symbol: strings.ToUpper(amount.Denom), + Name: amount.Denom, + To: tx.To, + TokenID: amount.Denom, + Value: blockatlas.Amount(value), + } + } } func (p *Platform) fillDelegate(tx *blockatlas.Tx, delegate MessageValueDelegate, events Events, msgType TxType) { diff --git a/platform/kava/transaction_test.go b/platform/kava/transaction_test.go index 0419a1c31..c5f9d07c9 100644 --- a/platform/kava/transaction_test.go +++ b/platform/kava/transaction_test.go @@ -48,7 +48,7 @@ const transferSrc = ` "to_address": "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae", "amount": [ { - "denom": "uatom", + "denom": "ukava", "amount": "2271999999" } ] @@ -58,7 +58,7 @@ const transferSrc = ` "fee": { "amount": [ { - "denom": "uatom", + "denom": "ukava", "amount": "1" } ], @@ -118,7 +118,7 @@ const transferSrcKava = ` "to_address": "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0", "amount": [ { - "denom": "uatom", + "denom": "ukava", "amount": "2271999999" } ] @@ -128,7 +128,7 @@ const transferSrcKava = ` "fee": { "amount": [ { - "denom": "uatom", + "denom": "ukava", "amount": "1" } ], @@ -149,6 +149,97 @@ const transferSrcKava = ` "timestamp": "2019-05-04T17:57:57Z" }` +const transferSrcKavaToken = ` +{ + "height": "645538", + "txhash": "514D43780335A1C516850FEE5692F59E9A9DF1D8D986FC62AC434BEB58EDB8E2", + "raw_log": "[{\"msg_index\":0,\"log\":\"\",\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"send\"},{\"key\":\"sender\",\"value\":\"kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7\"},{\"key\":\"module\",\"value\":\"bank\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"kava1wj2swfmeakxdrlqemvpzx2a4ljux9l4xq6qmcn\"},{\"key\":\"sender\",\"value\":\"kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7\"},{\"key\":\"amount\",\"value\":\"10000000000hard\"}]}]}]", + "logs": [ + { + "msg_index": 0, + "log": "", + "events": [ + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" + }, + { + "key": "module", + "value": "bank" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "kava1wj2swfmeakxdrlqemvpzx2a4ljux9l4xq6qmcn" + }, + { + "key": "sender", + "value": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7" + }, + { + "key": "amount", + "value": "10000000000hard" + } + ] + } + ] + } + ], + "gas_wanted": "200000", + "gas_used": "74794", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7", + "to_address": "kava1wj2swfmeakxdrlqemvpzx2a4ljux9l4xq6qmcn", + "amount": [ + { + "denom": "hard", + "amount": "10000000000" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "ukava", + "amount": "30" + } + ], + "gas": "200000" +}, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A/Uf73aHoxZXS7SvKweW4Ijo723YDLuhwhir6JSmVmWe" + }, + "signature": "Cuse3VunNLXi19GxASZD0fFMWeelEKe8DnC7nIYyS6FGqXzN+KP9hAdct7g9jczGT+4emVsQtiLvuM9Racrnyg==" + } + ], + "memo": "" +} +}, + "timestamp": "2020-12-19T10:49:24Z" +}` + const failedTransferSrc = ` { "height": "5552", @@ -168,7 +259,7 @@ const failedTransferSrc = ` "to_address": "cosmos1za4pu5gxm80fg6sx0956f88l2sx7jfg2vf7nlc", "amount": [ { - "denom": "uatom", + "denom": "ukava", "amount": "100000" } ] @@ -178,7 +269,7 @@ const failedTransferSrc = ` "fee": { "amount": [ { - "denom": "uatom", + "denom": "ukava", "amount": "2000" } ], @@ -237,7 +328,7 @@ const delegateSrc = ` "delegator_address":"cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3", "validator_address":"cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", "amount":{ - "denom":"uatom", + "denom":"ukava", "amount":"49920" } } @@ -246,7 +337,7 @@ const delegateSrc = ` "fee":{ "amount":[ { - "denom":"uatom", + "denom":"ukava", "amount":"5000" } ], @@ -310,7 +401,7 @@ const unDelegateSrc = ` "delegator_address":"cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94", "validator_address":"cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v", "amount":{ - "denom":"uatom", + "denom":"ukava", "amount":"5100000000" } } @@ -319,7 +410,7 @@ const unDelegateSrc = ` "fee":{ "amount":[ { - "denom":"uatom", + "denom":"ukava", "amount":"5000" } ], @@ -375,7 +466,7 @@ const claimRewardSrc1 = ` "fee": { "amount": [ { - "denom": "uatom", + "denom": "ukava", "amount": "1000" } ], @@ -400,7 +491,7 @@ const claimRewardSrc1 = ` "attributes": [ { "key": "amount", - "value": "1138uatom" + "value": "1138ukava" }, { "key": "validator", @@ -408,7 +499,7 @@ const claimRewardSrc1 = ` }, { "key": "amount", - "value": "40612uatom" + "value": "40612ukava" }, { "key": "validator", @@ -416,7 +507,7 @@ const claimRewardSrc1 = ` }, { "key": "amount", - "value": "954uatom" + "value": "954ukava" }, { "key": "validator", @@ -424,7 +515,7 @@ const claimRewardSrc1 = ` }, { "key": "amount", - "value": "43574uatom" + "value": "43574ukava" }, { "key": "amount" @@ -457,7 +548,7 @@ const claimRewardSrc2 = ` "delegator_address": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", "validator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", "amount": { - "denom": "uatom", + "denom": "ukava", "amount": "2692326" } } @@ -466,7 +557,7 @@ const claimRewardSrc2 = ` "fee": { "amount": [ { - "denom": "uatom", + "denom": "ukava", "amount": "0" } ], @@ -512,7 +603,7 @@ const claimRewardSrc2 = ` }, { "key": "amount", - "value": "2692701uatom" + "value": "2692701ukava" } ] }, @@ -521,7 +612,7 @@ const claimRewardSrc2 = ` "attributes": [ { "key": "amount", - "value": "2692701uatom" + "value": "2692701ukava" }, { "key": "validator", @@ -566,6 +657,27 @@ var transferDstKava = blockatlas.Tx{ }, } +var transferDstKavaToken = blockatlas.Tx{ + ID: "514D43780335A1C516850FEE5692F59E9A9DF1D8D986FC62AC434BEB58EDB8E2", + Coin: coin.KAVA, + From: "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7", + To: "kava1wj2swfmeakxdrlqemvpzx2a4ljux9l4xq6qmcn", + Fee: "30", + Date: 1608374964, + Block: 645538, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxNativeTokenTransfer, + Meta: blockatlas.NativeTokenTransfer{ + Value: "10000000000", + Symbol: "HARD", + Decimals: 6, + From: "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7", + To: "kava1wj2swfmeakxdrlqemvpzx2a4ljux9l4xq6qmcn", + TokenID: "hard", + Name: "hard", + }, +} + var delegateDst = blockatlas.Tx{ ID: "11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7", Coin: coin.ATOM, @@ -729,6 +841,12 @@ func TestNormalize(t *testing.T) { transferSrcKava, transferDstKava, }, + { + "test kava transfer token tx", + kava, + transferSrcKavaToken, + transferDstKavaToken, + }, } for _, tt := range tests { testNormalize(t, tt) From 6888153624a24e07ef1f7a43a903cf73a71e0fde Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 26 Dec 2020 08:43:04 +0900 Subject: [PATCH 439/506] [Filecoin] Add transactions list (#1335) * implement filecoin tx list * add normalize tests * separate rpc/explorer client * remove /api from config --- .gitignore | 1 + config.yml | 1 + config/configuration.go | 3 +- platform/filecoin/base.go | 10 ++- platform/filecoin/block.go | 17 +++-- platform/filecoin/block_test.go | 9 ++- platform/filecoin/explorer/client.go | 23 ++++++ platform/filecoin/explorer/models.go | 22 ++++++ platform/filecoin/models.go | 45 ------------ platform/filecoin/{ => rpc}/client.go | 8 +- platform/filecoin/rpc/models.go | 47 ++++++++++++ platform/filecoin/transaction.go | 43 +++++++++++ platform/filecoin/transaction_test.go | 102 ++++++++++++++++++++++++++ platform/platform.go | 2 +- 14 files changed, 267 insertions(+), 66 deletions(-) create mode 100644 platform/filecoin/explorer/client.go create mode 100644 platform/filecoin/explorer/models.go delete mode 100644 platform/filecoin/models.go rename platform/filecoin/{ => rpc}/client.go (78%) create mode 100644 platform/filecoin/rpc/models.go create mode 100644 platform/filecoin/transaction_test.go diff --git a/.gitignore b/.gitignore index 5cf4f5ab7..0780fb7c5 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ _cgo_gotypes.go _cgo_export.* _testmain.go +__debug_bin *.exe *.test diff --git a/config.yml b/config.yml index 818410042..3e33930a1 100644 --- a/config.yml +++ b/config.yml @@ -210,6 +210,7 @@ elrond: filecoin: api: https://api.filscan.io:8700/rpc/v1 + explorer: https://filfox.info # bsc: # api: # rpc: diff --git a/config/configuration.go b/config/configuration.go index df8cc5bf3..0bca947f3 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -204,7 +204,8 @@ type Configuration struct { API string `mapstructure:"api"` } `mapstructure:"elrond"` Filecoin struct { - API string `mapstructure:"api"` + API string `mapstructure:"api"` + Explorer string `mapstructure:"explorer"` } `mapstructure:"filecoin"` Sentry struct { DSN string `mapstructure:"dsn"` diff --git a/platform/filecoin/base.go b/platform/filecoin/base.go index cb04661d2..51dda72b7 100644 --- a/platform/filecoin/base.go +++ b/platform/filecoin/base.go @@ -2,16 +2,20 @@ package filecoin import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/filecoin/explorer" + "github.com/trustwallet/blockatlas/platform/filecoin/rpc" "github.com/trustwallet/golibs/coin" ) type Platform struct { - client Client + client rpc.Client + explorer explorer.Client } -func Init(api string) *Platform { +func Init(api, explorerApi string) *Platform { p := &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: rpc.Client{Request: blockatlas.InitClient(api)}, + explorer: explorer.Client{Request: blockatlas.InitClient(explorerApi)}, } return p } diff --git a/platform/filecoin/block.go b/platform/filecoin/block.go index e96174724..3bb9f2b6b 100644 --- a/platform/filecoin/block.go +++ b/platform/filecoin/block.go @@ -2,11 +2,12 @@ package filecoin import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/filecoin/rpc" "github.com/trustwallet/golibs/coin" ) func (p *Platform) CurrentBlockNumber() (int64, error) { - response, err := p.client.getBlockHeight() + response, err := p.client.GetBlockHeight() if err != nil { return 0, err } @@ -14,23 +15,23 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { } func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - chainHeadResponse, err := p.client.getTipSetByHeight(num) + chainHeadResponse, err := p.client.GetTipSetByHeight(num) if err != nil { return nil, err } - blockResponses := make([]BlockMessageResponse, 0, len(chainHeadResponse.getCids())) - for _, cid := range chainHeadResponse.getCids() { - blockResponse, err := p.client.getBlockMessage(cid) + blockResponses := make([]rpc.BlockMessageResponse, 0, len(chainHeadResponse.GetCids())) + for _, cid := range chainHeadResponse.GetCids() { + blockResponse, err := p.client.GetBlockMessage(cid) if err != nil { return nil, err } blockResponses = append(blockResponses, blockResponse) } - return normalizeBlockResponses(uint64(chainHeadResponse.Height), uint64(chainHeadResponse.getTimestamp()), blockResponses), nil + return normalizeBlockResponses(uint64(chainHeadResponse.Height), uint64(chainHeadResponse.GetTimestamp()), blockResponses), nil } -func normalizeBlockResponses(num, timestamp uint64, responses []BlockMessageResponse) *blockatlas.Block { +func normalizeBlockResponses(num, timestamp uint64, responses []rpc.BlockMessageResponse) *blockatlas.Block { var result blockatlas.Block result.Number = int64(num) for _, resp := range responses { @@ -42,7 +43,7 @@ func normalizeBlockResponses(num, timestamp uint64, responses []BlockMessageResp return &result } -func normalizeBlockTx(num, timestamp uint64, msg SecpkMessage) blockatlas.Tx { +func normalizeBlockTx(num, timestamp uint64, msg rpc.SecpkMessage) blockatlas.Tx { return blockatlas.Tx{ Coin: coin.Filecoin().ID, From: msg.Message.From, diff --git a/platform/filecoin/block_test.go b/platform/filecoin/block_test.go index f97c8f77e..fdfee400c 100644 --- a/platform/filecoin/block_test.go +++ b/platform/filecoin/block_test.go @@ -3,11 +3,12 @@ package filecoin import ( "encoding/json" "fmt" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/golibs/mock" "net/http" "net/http/httptest" "testing" + + "github.com/stretchr/testify/assert" + "github.com/trustwallet/golibs/mock" ) func TestPlatform_CurrentBlockNumber(t *testing.T) { @@ -25,7 +26,7 @@ func TestPlatform_CurrentBlockNumber(t *testing.T) { server := httptest.NewServer(mock.CreateMockedAPI(data)) defer server.Close() - p := Init(server.URL) + p := Init(server.URL, "") block, err := p.CurrentBlockNumber() assert.Nil(t, err) assert.Equal(t, int64(243590), block) @@ -73,7 +74,7 @@ func TestPlatform_GetBlockByNumber(t *testing.T) { server := httptest.NewServer(mock.CreateMockedAPI(data)) defer server.Close() - p := Init(server.URL) + p := Init(server.URL, "") block, err := p.GetBlockByNumber(243590) assert.Nil(t, err) raw, err := json.Marshal(block) diff --git a/platform/filecoin/explorer/client.go b/platform/filecoin/explorer/client.go new file mode 100644 index 000000000..339db58fb --- /dev/null +++ b/platform/filecoin/explorer/client.go @@ -0,0 +1,23 @@ +package explorer + +import ( + "fmt" + "net/url" + "strconv" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Client struct { + blockatlas.Request +} + +func (c Client) GetMessagesByAddress(address string, pageSize int) (res Response, err error) { + path := fmt.Sprintf("/api/v1/address/%s/messages", address) + query := url.Values{"pageSize": {strconv.Itoa(pageSize)}} + err = c.Get(&res, path, query) + if err != nil { + return res, err + } + return +} diff --git a/platform/filecoin/explorer/models.go b/platform/filecoin/explorer/models.go new file mode 100644 index 000000000..389d00a27 --- /dev/null +++ b/platform/filecoin/explorer/models.go @@ -0,0 +1,22 @@ +package explorer + +type Response struct { + TotalCount int `json:"totalCount"` + Messages []Message `json:"messages"` +} + +type Receipt struct { + ExitCode int `json:"exitCode"` +} + +type Message struct { + Cid string `json:"cid"` + Height uint64 `json:"height"` + Timestamp int64 `json:"timestamp"` + From string `json:"from"` + To string `json:"to"` + Nonce uint64 `json:"nonce"` + Value string `json:"value"` + Method string `json:"method"` + Receipt Receipt `json:"receipt"` +} diff --git a/platform/filecoin/models.go b/platform/filecoin/models.go deleted file mode 100644 index 4a0d8a514..000000000 --- a/platform/filecoin/models.go +++ /dev/null @@ -1,45 +0,0 @@ -package filecoin - -type ChainHeadResponse struct { - Cids []struct { - Cid string `json:"/"` - } `json:"Cids"` - Blocks []struct { - Timestamp int `json:"Timestamp"` - } - Height int `json:"Height"` -} - -type BlockMessageResponse struct { - SecpkMessages []SecpkMessage `json:"SecpkMessages"` -} - -type SecpkMessage struct { - Message struct { - Version int `json:"Version"` - To string `json:"To"` - From string `json:"From"` - Nonce int `json:"Nonce"` - Value string `json:"Value"` - GasLimit int `json:"GasLimit"` - GasFeeCap string `json:"GasFeeCap"` - GasPremium string `json:"GasPremium"` - Method int `json:"Method"` - Params interface{} `json:"Params"` - } `json:"Message"` -} - -func (c ChainHeadResponse) getCids() []string { - result := make([]string, 0, len(c.Cids)) - for _, cid := range c.Cids { - result = append(result, cid.Cid) - } - return result -} - -func (c ChainHeadResponse) getTimestamp() int64 { - if len(c.Blocks) == 0 { - return 0 - } - return int64(c.Blocks[0].Timestamp) -} diff --git a/platform/filecoin/client.go b/platform/filecoin/rpc/client.go similarity index 78% rename from platform/filecoin/client.go rename to platform/filecoin/rpc/client.go index d2ab1becf..0865e0195 100644 --- a/platform/filecoin/client.go +++ b/platform/filecoin/rpc/client.go @@ -1,4 +1,4 @@ -package filecoin +package rpc import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -8,7 +8,7 @@ type Client struct { blockatlas.Request } -func (c Client) getBlockHeight() (ChainHeadResponse, error) { +func (c Client) GetBlockHeight() (ChainHeadResponse, error) { var result ChainHeadResponse err := c.RpcCall(&result, "Filecoin.ChainHead", nil) if err != nil { @@ -17,7 +17,7 @@ func (c Client) getBlockHeight() (ChainHeadResponse, error) { return result, nil } -func (c Client) getTipSetByHeight(height int64) (ChainHeadResponse, error) { +func (c Client) GetTipSetByHeight(height int64) (ChainHeadResponse, error) { var result ChainHeadResponse params := []interface{}{ height, nil, @@ -29,7 +29,7 @@ func (c Client) getTipSetByHeight(height int64) (ChainHeadResponse, error) { return result, nil } -func (c Client) getBlockMessage(cid string) (BlockMessageResponse, error) { +func (c Client) GetBlockMessage(cid string) (BlockMessageResponse, error) { var result BlockMessageResponse params := []interface{}{ map[string]interface{}{ diff --git a/platform/filecoin/rpc/models.go b/platform/filecoin/rpc/models.go new file mode 100644 index 000000000..6da56df0b --- /dev/null +++ b/platform/filecoin/rpc/models.go @@ -0,0 +1,47 @@ +package rpc + +type ChainHeadResponse struct { + Cids []struct { + Cid string `json:"/"` + } `json:"Cids"` + Blocks []struct { + Timestamp int `json:"Timestamp"` + } + Height int `json:"Height"` +} + +type BlockMessageResponse struct { + SecpkMessages []SecpkMessage `json:"SecpkMessages"` +} + +type SecpkMessage struct { + Message Message `json:"Message"` +} + +type Message struct { + Version int `json:"Version"` + To string `json:"To"` + From string `json:"From"` + Nonce int `json:"Nonce"` + Value string `json:"Value"` + GasLimit int `json:"GasLimit"` + GasFeeCap string `json:"GasFeeCap"` + GasPremium string `json:"GasPremium"` + Method int `json:"Method"` + Params interface{} `json:"Params"` +} + +func (c ChainHeadResponse) GetCids() []string { + result := make([]string, 0, len(c.Cids)) + for _, cid := range c.Cids { + result = append(result, cid.Cid) + } + return result +} + +func (c ChainHeadResponse) GetTimestamp() int64 { + if len(c.Blocks) == 0 { + return 0 + } + return int64(c.Blocks[0].Timestamp) +} diff --git a/platform/filecoin/transaction.go b/platform/filecoin/transaction.go index c4325d8b2..743b66284 100644 --- a/platform/filecoin/transaction.go +++ b/platform/filecoin/transaction.go @@ -2,9 +2,52 @@ package filecoin import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/filecoin/explorer" ) +const messageMethod = "Send" + func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { + res, err := p.explorer.GetMessagesByAddress(address, blockatlas.TxPerPage) + if err != nil { + return nil, err + } normalized := make([]blockatlas.Tx, 0) + for _, message := range res.Messages { + // skip non transfer messages + if message.Method != messageMethod { + continue + } + normalized = append(normalized, p.NormalizeMessage(message, address)) + } + return normalized, nil } + +func (p *Platform) NormalizeMessage(message explorer.Message, address string) blockatlas.Tx { + status := blockatlas.StatusCompleted + if message.Receipt.ExitCode != 0 { + status = blockatlas.StatusError + } + direction := blockatlas.DirectionOutgoing + if message.From != address { + direction = blockatlas.DirectionIncoming + } + return blockatlas.Tx{ + ID: message.Cid, + Coin: p.Coin().ID, + From: message.From, + To: message.To, + Date: message.Timestamp, + Block: message.Height, + Status: status, + Sequence: message.Nonce, + Type: blockatlas.TxTransfer, + Direction: direction, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount(message.Value), + Symbol: p.Coin().Symbol, + Decimals: p.Coin().Decimals, + }, + } +} diff --git a/platform/filecoin/transaction_test.go b/platform/filecoin/transaction_test.go new file mode 100644 index 000000000..459504217 --- /dev/null +++ b/platform/filecoin/transaction_test.go @@ -0,0 +1,102 @@ +package filecoin + +import ( + "reflect" + "testing" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/filecoin/explorer" +) + +func TestPlatform_NormalizeMessage(t *testing.T) { + type args struct { + message explorer.Message + address string + } + tests := []struct { + name string + args args + want blockatlas.Tx + }{ + { + name: "Test transfer", + args: args{ + message: explorer.Message{ + Cid: "bafy2bzacectkidmsel5gn5qamrqhcgqgqefhdzlqukry3rc2ase4yqdbxazqi", + Height: 305641, + Timestamp: 1607475630, + From: "f1mdseaz4gkbz2cq2kf4q3xqbws5ongyt7vdbvzoa", + To: "f16hhfi2xkkmpsi4c5mmgwbkgk5wslfcaflefsqpy", + Nonce: 6, + Value: "298040241318833792", + Method: "Send", + Receipt: explorer.Receipt{ + ExitCode: 0, + }, + }, + address: "f16hhfi2xkkmpsi4c5mmgwbkgk5wslfcaflefsqpy", + }, + want: blockatlas.Tx{ + ID: "bafy2bzacectkidmsel5gn5qamrqhcgqgqefhdzlqukry3rc2ase4yqdbxazqi", + Coin: 461, + From: "f1mdseaz4gkbz2cq2kf4q3xqbws5ongyt7vdbvzoa", + To: "f16hhfi2xkkmpsi4c5mmgwbkgk5wslfcaflefsqpy", + Date: 1607475630, + Block: 305641, + Status: "completed", + Sequence: 6, + Type: "transfer", + Direction: "incoming", + Meta: blockatlas.Transfer{ + Value: "298040241318833792", + Symbol: "FIL", + Decimals: 18, + }, + }, + }, + { + name: "Test transfer failed", + args: args{ + message: explorer.Message{ + Cid: "bafy2bzacebgbszawdnrl7flgrb2ixt4f6lsb4jjqywv3bsekplpsiswexepha", + Height: 310103, + Timestamp: 1607609490, + From: "f16hhfi2xkkmpsi4c5mmgwbkgk5wslfcaflefsqpy", + To: "f1elvpho4c6iba6xrlok3773cxbvq32thlofezw5y", + Nonce: 23, + Value: "1000000000000000", + Method: "Send", + Receipt: explorer.Receipt{ + ExitCode: 7, + }, + }, + address: "f16hhfi2xkkmpsi4c5mmgwbkgk5wslfcaflefsqpy", + }, + want: blockatlas.Tx{ + ID: "bafy2bzacebgbszawdnrl7flgrb2ixt4f6lsb4jjqywv3bsekplpsiswexepha", + Coin: 461, + From: "f16hhfi2xkkmpsi4c5mmgwbkgk5wslfcaflefsqpy", + To: "f1elvpho4c6iba6xrlok3773cxbvq32thlofezw5y", + Date: 1607609490, + Block: 310103, + Status: "error", + Sequence: 23, + Type: "transfer", + Direction: "outgoing", + Meta: blockatlas.Transfer{ + Value: "1000000000000000", + Symbol: "FIL", + Decimals: 18, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Platform{} + if got := p.NormalizeMessage(tt.args.message, tt.args.address); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Platform.NormalizeMessage() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/platform/platform.go b/platform/platform.go index 487d3237d..018aa8b2f 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -97,7 +97,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Ethereum().Handle: ethereum.InitWithCollection(coin.ETH, config.Default.Ethereum.RPC, 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.Filecoin().Handle: filecoin.Init(config.Default.Filecoin.API), + coin.Filecoin().Handle: filecoin.Init(config.Default.Filecoin.API, config.Default.Filecoin.Explorer), } } From d39192889f5c3b211a07d4bad6d72eba05a07ed8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 28 Dec 2020 16:42:54 -0800 Subject: [PATCH 440/506] Bump gorm.io/gorm from 1.20.8 to 1.20.9 (#1338) Bumps [gorm.io/gorm](https://github.com/go-gorm/gorm) from 1.20.8 to 1.20.9. - [Release notes](https://github.com/go-gorm/gorm/releases) - [Commits](https://github.com/go-gorm/gorm/compare/v1.20.8...v1.20.9) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index cc6e869a0..915a25507 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,6 @@ require ( golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.6 - gorm.io/gorm v1.20.8 + gorm.io/gorm v1.20.9 gotest.tools v2.2.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index 0c18ea539..9f7a1e1ca 100644 --- a/go.sum +++ b/go.sum @@ -638,6 +638,7 @@ gorm.io/driver/postgres v1.0.6/go.mod h1:r0nvX27yHDNbVeXMM9Y+9i5xSePcT18RfH8clP6 gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= 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.9/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= From c686ac6df3352c783cce1b0074de9bff813cadea Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 29 Dec 2020 09:43:03 +0900 Subject: [PATCH 441/506] Update issue templates and labels (#1337) * update issue templates and labels * remove Improvement * configure todo bot --- .github/CODEOWNERS | 2 +- .github/ISSUE_TEMPLATE/bug_report.md | 14 ++--------- .github/ISSUE_TEMPLATE/feature_request.md | 10 ++------ .github/ISSUE_TEMPLATE/improvement.md | 21 ---------------- .github/ISSUE_TEMPLATE/maintance.md | 16 ------------ .github/ISSUE_TEMPLATE/question.md | 18 ------------- .../PULL_REQUEST_TEMPLATE/new_blockchain.md | 25 ------------------- .github/config.yml | 3 +++ 8 files changed, 8 insertions(+), 101 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/improvement.md delete mode 100644 .github/ISSUE_TEMPLATE/maintance.md delete mode 100644 .github/ISSUE_TEMPLATE/question.md delete mode 100644 .github/PULL_REQUEST_TEMPLATE/new_blockchain.md create mode 100644 .github/config.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 91d2b9989..5fd563ee3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @EnoRage +* @hewigovens \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index afeaa8837..599037255 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,19 +1,12 @@ --- name: Bug report -about: Create a report to help us improve +about: Report a bug title: '' -labels: 'Type: Bug' +labels: 'Bug' assignees: '' --- - - ## Summary of Bug @@ -38,6 +31,3 @@ ____ ``` {} ``` - - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 82e5f266b..a06a5e183 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,18 +1,12 @@ --- name: Feature request -about: Suggest an idea for this project +about: Suggest new feature title: '' -labels: 'Type: New Feature' +labels: 'New Feature' assignees: '' --- - - ## Summary diff --git a/.github/ISSUE_TEMPLATE/improvement.md b/.github/ISSUE_TEMPLATE/improvement.md deleted file mode 100644 index f1e0f329a..000000000 --- a/.github/ISSUE_TEMPLATE/improvement.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: Enhancement -about: Improve existing architecture -title: '' -labels: 'Type: Enhancement' -assignees: '' - ---- - - - -## Current Functionality - - -## Possible Improvement - diff --git a/.github/ISSUE_TEMPLATE/maintance.md b/.github/ISSUE_TEMPLATE/maintance.md deleted file mode 100644 index 38e8634d4..000000000 --- a/.github/ISSUE_TEMPLATE/maintance.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: Maintance -about: Deprecate old functionality or routes -title: '' -labels: 'Type: Maintance' -assignees: '' - ---- - - - diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index f40d6757c..000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: Question -about: Ask anything related to this repo -title: '' -labels: 'Type: Question' -assignees: '' - ---- - - - -## How can we help ? - - diff --git a/.github/PULL_REQUEST_TEMPLATE/new_blockchain.md b/.github/PULL_REQUEST_TEMPLATE/new_blockchain.md deleted file mode 100644 index cd52368d0..000000000 --- a/.github/PULL_REQUEST_TEMPLATE/new_blockchain.md +++ /dev/null @@ -1,25 +0,0 @@ -# Adding a new blockchain - -Please follow this checklist: - - - `platform/mycoin` - - [ ] `model.go`: Platform-specific models - - [ ] `client.go`: Platform getter methods (API, RPC) - - [ ] `api.go`: - - Gin route: _GET /mycoin/txs_ - - Getting blockchain info - - Normalizing platform-specific - models to BlockAtlas model - - [ ] `api_test.go` - - Unit tests - - Check if normalization from - response body matches expected model - - [ ] `test/main.go`: - Add example address for integration test - - [ ] `loaders.go`: Add route - - [ ] `config.yml`: Add default config - (comment out if no public endpoint) - - [ ] `config.go`: Add default config - -If you have any questions, contact us at -https://t.me/walletcore or @terorie / @vikmeup on Telegram. diff --git a/.github/config.yml b/.github/config.yml new file mode 100644 index 000000000..13299ed72 --- /dev/null +++ b/.github/config.yml @@ -0,0 +1,3 @@ +todo: + label: "Bot: Todo" + \ No newline at end of file From 78f04aeab4caf23cebfc62a1084b0ceb5e80505b Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 4 Jan 2021 15:17:08 +0900 Subject: [PATCH 442/506] [FIO] Ignore tx sent to fio.treasury (#1343) * ignore tx sent to fio.treasury remove hardcode memo check * extract const variables --- go.sum | 18 ++++++------------ platform/fio/transaction.go | 20 ++++++++++++++------ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/go.sum b/go.sum index 9f7a1e1ca..64b349f83 100644 --- a/go.sum +++ b/go.sum @@ -203,8 +203,7 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.7.0 h1:pwjzcYyfmz/HQOQlENvG1OcDqauTGaqlVahq934F0/U= -github.com/jackc/pgconn v1.7.0/go.mod h1:sF/lPpNEMEOp+IYhyQGdAvrG20gWf6A1tKlr0v7JMeA= +github.com/jackc/pgconn v1.8.0 h1:FmjZ0rOyXTr1wfWs45i4a9vjnjWUAGpMuQLD9OSs+lw= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= @@ -219,8 +218,7 @@ github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.0.5 h1:NUbEWPmCQZbMmYlTjVoNPhc0CfnYyz2bfUAh6A5ZVJM= -github.com/jackc/pgproto3/v2 v2.0.5/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.6 h1:b1105ZGEMFe7aCvrT1Cca3VoVb4ZFMaFJLJcg/3zD+8= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= @@ -231,8 +229,7 @@ github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrU github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= -github.com/jackc/pgtype v1.5.0 h1:jzBqRk2HFG2CV4AIwgCI2PwTgm6UUoCAK2ofHHRirtc= -github.com/jackc/pgtype v1.5.0/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= +github.com/jackc/pgtype v1.6.2 h1:b3pDeuhbbzBYcg5kwNmNDun4pFUD/0AAr1kLXZLeNt8= github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= @@ -240,14 +237,12 @@ github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQ github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= -github.com/jackc/pgx/v4 v4.9.0 h1:6STjDqppM2ROy5p1wNDcsC7zJTjSHeuCsguZmXyzx7c= -github.com/jackc/pgx/v4 v4.9.0/go.mod h1:MNGWmViCgqbZck9ujOOBN63gK9XVGILXWCvKLGKmnms= +github.com/jackc/pgx/v4 v4.10.1 h1:/6Q3ye4myIj6AaplUm+eRcz4OhK9HAvFf4ePsG40LJY= github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -632,12 +627,11 @@ 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.5 h1:raX6ezL/ciUmaYTvOq48jq1GE95aMC0CmxQYbxQ4Ufw= -gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOudXNCA= +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.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= 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.9 h1:M3aIZKXAC1PtPVu9t3WGwkBTE1le5c2telz3I/qjRNg= gorm.io/gorm v1.20.9/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= diff --git a/platform/fio/transaction.go b/platform/fio/transaction.go index 1a42f698f..fd3ba9865 100644 --- a/platform/fio/transaction.go +++ b/platform/fio/transaction.go @@ -9,9 +9,17 @@ import ( "time" "errors" + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) +const ( + contractToken = "fio.token" + contractTreasury = "fio.treasury" + actionTransfer = "transfer" + actionTransferPubkey = "trnsfiopubky" +) + func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err error) { // take actor from address account := actorFromPublicKeyOrActor(address) @@ -41,21 +49,21 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err ) const dateFormat string = "2006-01-02T15:04:05" - if action.ActionTrace.Act.Account == "fio.token" && - (action.ActionTrace.Act.Name == "transfer" || action.ActionTrace.Act.Name == "trnsfiopubky") { + if action.ActionTrace.Act.Account == contractToken && + (action.ActionTrace.Act.Name == actionTransfer || action.ActionTrace.Act.Name == actionTransferPubkey) { // convert to action-specific data dataJSON, err := json.Marshal(action.ActionTrace.Act.Data) if err != nil { return blockatlas.Tx{}, errors.New("Unparseable Data field") } switch action.ActionTrace.Act.Name { - case "transfer": + case actionTransfer: var actionData ActionDataTransfer if json.Unmarshal(dataJSON, &actionData) != nil { return blockatlas.Tx{}, errors.New("Unparseable Data field") } - if actionData.Memo == "FIO API fees. Thank you." { - return blockatlas.Tx{}, errors.New("Skip meaningless hardcoded fee action") + if actionData.To == contractTreasury { + return blockatlas.Tx{}, errors.New("Skip tx sent to treasury, usually fee") } from = actionData.From to = actionData.To @@ -66,7 +74,7 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err // fee unknown memo = actionData.Memo sequence = action.ActionSeq - case "trnsfiopubky": + case actionTransferPubkey: var actionData ActionDataTrnsfiopubky if json.Unmarshal(dataJSON, &actionData) != nil { return blockatlas.Tx{}, errors.New("Unparseable Data field") From 648416316778cf624ff46b3ba00d29e5700b381e Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Mon, 4 Jan 2021 22:59:25 -0800 Subject: [PATCH 443/506] Refactor Subscription functionality (#1341) * Update parser.go * Refactor subscriptions * go mod tidy * Fix lint issues * Update Procfile * [Tokens] v3/tokens/new returns invalid JSON response Fix: https://github.com/trustwallet/blockatlas/issues/1315 * Avoid skipping blocks while parsing Fixes: https://github.com/trustwallet/blockatlas/issues/1316 * Update parser.go * Update block.go * Remove unnessesary route /v2/tokens * Add IsValid asset * Add setup step * Update client.go * Update Procfile * Update golibs * Update parser.go * Include to parse last block * Update parser.go * Remove redundant tests --- Procfile | 5 +- api/api.go | 6 +- api/endpoint/block.go | 2 +- api/endpoint/token.go | 108 +------ api/registry.go | 13 +- cmd/api/main.go | 32 +-- cmd/consumer/main.go | 75 +++-- cmd/parser/main.go | 59 ++-- cmd/setup/main.go | 70 +++++ config.yml | 11 +- config/configuration.go | 14 +- configmock.yml | 6 +- db/addresstoasset.go | 263 ------------------ db/asset.go | 108 ++++--- db/db.go | 32 +-- db/models/address.go | 10 - db/models/addresstoasset.go | 16 -- db/models/asset.go | 26 +- db/models/asset_test.go | 66 +++++ db/models/subscriptions.go | 24 +- db/notification.go | 70 ----- db/subscription.go | 60 ++++ go.mod | 21 +- go.sum | 55 +++- internal/init.go | 9 +- internal/mq.go | 29 ++ internal/shutdown.go | 52 ---- mq/mq.go | 187 ------------- pkg/blockatlas/observer.go | 13 +- pkg/blockatlas/tx.go | 15 +- platform/binance/client.go | 11 - platform/vechain/transaction.go | 2 +- services/notifier/base.go | 27 +- services/notifier/delivery.go | 5 +- services/parser/parser.go | 103 ++++--- services/parser/parser_test.go | 107 ++++++- services/subscriber/subscriber.go | 55 ++++ services/subscriber/tokens.go | 32 --- services/subscriber/transactions.go | 112 -------- services/subscriber/transactions_test.go | 25 -- services/tokenindexer/api.go | 27 +- services/tokenindexer/indexer.go | 126 +++++++-- services/tokenindexer/indexer_subscribe.go | 58 ++++ services/tokenindexer/models.go | 16 +- services/tokensearcher/api.go | 194 ------------- services/tokensearcher/api_test.go | 94 ------- services/tokensearcher/association.go | 60 ---- services/tokensearcher/association_test.go | 100 ------- services/tokensearcher/models.go | 33 --- services/tokensearcher/tokensearcher.go | 56 ---- .../integration/db_test/subscriptions_test.go | 199 ------------- .../db_test/tokenassociations_test.go | 198 ------------- .../integration/db_test/tokenindexer_test.go | 43 --- .../data/given_subscriptions_added.json | 34 --- .../data/given_subscriptions_deleted.json | 34 --- .../data/wanted_subscriptions_added.json | 18 -- .../observer_test/full_flow_test.go | 162 ----------- .../observer_test/notifier_test.go | 110 -------- .../observer_test/observer_test.go | 41 --- .../integration/observer_test/parser_test.go | 119 -------- .../observer_test/subscriber_test.go | 144 ---------- tests/integration/setup/mq.go | 5 +- tests/integration/setup/postgres.go | 9 +- 63 files changed, 931 insertions(+), 2885 deletions(-) create mode 100644 cmd/setup/main.go delete mode 100644 db/addresstoasset.go delete mode 100644 db/models/address.go delete mode 100644 db/models/addresstoasset.go create mode 100644 db/models/asset_test.go delete mode 100644 db/notification.go create mode 100644 db/subscription.go create mode 100644 internal/mq.go delete mode 100644 internal/shutdown.go delete mode 100644 mq/mq.go create mode 100644 services/subscriber/subscriber.go delete mode 100644 services/subscriber/tokens.go delete mode 100644 services/subscriber/transactions.go delete mode 100644 services/subscriber/transactions_test.go create mode 100644 services/tokenindexer/indexer_subscribe.go delete mode 100644 services/tokensearcher/api.go delete mode 100644 services/tokensearcher/api_test.go delete mode 100644 services/tokensearcher/association.go delete mode 100644 services/tokensearcher/association_test.go delete mode 100644 services/tokensearcher/models.go delete mode 100644 services/tokensearcher/tokensearcher.go delete mode 100644 tests/integration/db_test/subscriptions_test.go delete mode 100644 tests/integration/db_test/tokenassociations_test.go delete mode 100644 tests/integration/observer_test/data/given_subscriptions_added.json delete mode 100644 tests/integration/observer_test/data/given_subscriptions_deleted.json delete mode 100644 tests/integration/observer_test/data/wanted_subscriptions_added.json delete mode 100644 tests/integration/observer_test/full_flow_test.go delete mode 100644 tests/integration/observer_test/notifier_test.go delete mode 100644 tests/integration/observer_test/observer_test.go delete mode 100644 tests/integration/observer_test/parser_test.go delete mode 100644 tests/integration/observer_test/subscriber_test.go diff --git a/Procfile b/Procfile index 8f691ac2f..ebaa81234 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,6 @@ +release: bin/setup -c $HOME/config.yml web: bin/api -c $HOME/config.yml -p $PORT -consumer: bin/consumer -c $HOME/config.yml +consumer-transactions: CONSUMER_SERVICE=transactions bin/consumer -c $HOME/config.yml +consumer-subscriptions: CONSUMER_SERVICE=subscriptions bin/consumer -c $HOME/config.yml +consumer-tokens: CONSUMER_SERVICE=tokens bin/consumer -c $HOME/config.yml parser: bin/parser -c $HOME/config.yml diff --git a/api/api.go b/api/api.go index 26ff79b02..2e9c95063 100644 --- a/api/api.go +++ b/api/api.go @@ -7,7 +7,6 @@ import ( _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/tokenindexer" - "github.com/trustwallet/blockatlas/services/tokensearcher" ) func SetupPlatformAPI(router gin.IRouter) { @@ -25,13 +24,10 @@ func SetupPlatformAPI(router gin.IRouter) { RegisterBasicAPI(router) } -func SetupTokensSearcherAPI(router gin.IRouter, instance tokensearcher.Instance) { - RegisterTokensSearcherAPI(router, instance) -} - func SetupTokensIndexAPI(router gin.IRouter, instance tokenindexer.Instance) { RegisterTokensIndexAPI(router, instance) } + func SetupSwaggerAPI(router gin.IRouter) { router.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) } diff --git a/api/endpoint/block.go b/api/endpoint/block.go index b943a2fcd..50b0942d8 100644 --- a/api/endpoint/block.go +++ b/api/endpoint/block.go @@ -31,7 +31,7 @@ func GetBlock(c *gin.Context, blockAPI blockatlas.BlockAPI) { block, err := blockAPI.GetBlockByNumber(int64(blockNumber)) if err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(errors.New("block number not found"))) + c.AbortWithStatusJSON(http.StatusNotFound, errorResponse(errors.New("block number not found"))) return } diff --git a/api/endpoint/token.go b/api/endpoint/token.go index 7d55e0fa7..d0e1b792e 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -3,20 +3,10 @@ package endpoint import ( "net/http" "strconv" - "sync" - "time" "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/tokenindexer" - "github.com/trustwallet/blockatlas/services/tokensearcher" -) - -type ( - tokensResult struct { - Result blockatlas.TokenPage - mu sync.Mutex - } ) // @Summary Get Tokens @@ -45,95 +35,13 @@ func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &result}) } -// @Description Get tokens -// @ID tokens_v3 -// @Summary Get list of tokens by map: coin -> [addresses] -// @Accept json -// @Produce json -// @Tags Transactions -// @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) -// @Success 200 {object} blockatlas.ResultsResponse -// @Router /v2/tokens [post] -func GetTokens(c *gin.Context, apis map[uint]blockatlas.TokensAPI) { - var query map[string][]string - if err := c.Bind(&query); err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) - return - } - result := tokensResult{ - Result: make(blockatlas.TokenPage, 0), - mu: sync.Mutex{}, - } - var wg sync.WaitGroup - for coinStr, addresses := range query { - coinNum, err := strconv.ParseUint(coinStr, 10, 32) - if err != nil { - continue - } - api, ok := apis[uint(coinNum)] - if !ok { - continue - } - wg.Add(1) - go getTokens(api, addresses, &result, &wg) - } - wg.Wait() - c.JSON(http.StatusOK, blockatlas.ResultsResponse{Total: len(result.Result), Results: &result.Result}) -} - -func getTokens(tokenAPI blockatlas.TokensAPI, addresses []string, data *tokensResult, wg *sync.WaitGroup) { - var ( - tokenPagesChan = make(chan blockatlas.TokenPage, len(addresses)) - wgLocal sync.WaitGroup - timeout = time.Second * 3 - ) - defer wg.Done() - for _, address := range addresses { - wgLocal.Add(1) - go func(address string, wg *sync.WaitGroup) { - defer wg.Done() - - stopChan := make(chan struct{}) - pageChan := make(chan blockatlas.TokenPage) - - go func() { - defer close(stopChan) - defer close(pageChan) - tokenPage, err := tokenAPI.GetTokenListByAddress(address) - if err != nil { - stopChan <- struct{}{} - return - } - pageChan <- tokenPage - }() - - select { - case <-time.After(timeout): - return - case <-stopChan: - return - case p := <-pageChan: - tokenPagesChan <- p - } - }(address, &wgLocal) - } - wgLocal.Wait() - close(tokenPagesChan) - data.mu.Lock() - for page := range tokenPagesChan { - r := data.Result - data.Result = append(r, page...) - } - data.mu.Unlock() -} - -func GetTokensByAddressIndexer(c *gin.Context, instance tokensearcher.Instance) { - var query tokensearcher.Request +func GetTokensByAddressV3(c *gin.Context, instance tokenindexer.Instance) { + var query tokenindexer.GetTokensByAddressRequest if err := c.Bind(&query); err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) return } - result, err := instance.HandleTokensRequest(query) + result, err := instance.GetTokensByAddress(query) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return @@ -148,25 +56,17 @@ func GetTokensByAddressIndexer(c *gin.Context, instance tokensearcher.Instance) // @Produce json // @Tags Transactions // @Param from query int true "unix timestamp" -// @Param coin query int false "coin like 60" // @Success 200 {object} tokenindexer.Response // @Router /v3/tokens/new [get] func GetNewTokens(c *gin.Context, instance tokenindexer.Instance) { var request tokenindexer.Request fromRaw := c.Query("from") - coinRaw := c.DefaultQuery("coin", "-1") from, err := strconv.Atoi(fromRaw) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) + return } - - coin, err := strconv.Atoi(coinRaw) - if err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) - } - - request.Coin = coin request.From = int64(from) resp, err := instance.HandleNewTokensRequest(request) diff --git a/api/registry.go b/api/registry.go index efaf2aa1e..48f5feed9 100644 --- a/api/registry.go +++ b/api/registry.go @@ -8,7 +8,6 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/tokenindexer" - "github.com/trustwallet/blockatlas/services/tokensearcher" "github.com/trustwallet/golibs/network/middleware" ) @@ -93,23 +92,17 @@ func RegisterBatchAPI(router gin.IRouter) { router.POST("/v4/collectibles/categories", func(c *gin.Context) { endpoint.GetCollectionCategoriesFromList(c, platform.CollectionsAPIs) }) - router.POST("/v2/tokens", func(c *gin.Context) { - endpoint.GetTokens(c, platform.TokensAPIs) - }) } func RegisterBasicAPI(router gin.IRouter) { router.GET("/", endpoint.GetStatus) } -func RegisterTokensSearcherAPI(router gin.IRouter, instance tokensearcher.Instance) { - router.POST("/v3/tokens", func(c *gin.Context) { - endpoint.GetTokensByAddressIndexer(c, instance) - }) -} - func RegisterTokensIndexAPI(router gin.IRouter, instance tokenindexer.Instance) { router.GET("/v3/tokens/new", func(c *gin.Context) { endpoint.GetNewTokens(c, instance) }) + router.POST("/v3/tokens", func(c *gin.Context) { + endpoint.GetTokensByAddressV3(c, instance) + }) } diff --git a/cmd/api/main.go b/cmd/api/main.go index 363293ac5..8ce7ac020 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -4,6 +4,8 @@ import ( "context" "time" + golibsGin "github.com/trustwallet/golibs/network/gin" + "github.com/trustwallet/golibs/network/middleware" "github.com/gin-gonic/gin" @@ -13,10 +15,8 @@ import ( "github.com/trustwallet/blockatlas/db" _ "github.com/trustwallet/blockatlas/docs" "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/tokenindexer" - "github.com/trustwallet/blockatlas/services/tokensearcher" ) const ( @@ -30,8 +30,7 @@ var ( port, confPath string engine *gin.Engine database *db.Instance - ts tokensearcher.Instance - ti tokenindexer.Instance + tokenIndexer tokenindexer.Instance ) func init() { @@ -41,8 +40,7 @@ func init() { internal.InitConfig(confPath) - err = middleware.SetupSentry(config.Default.Sentry.DSN) - if err != nil { + if err := middleware.SetupSentry(config.Default.Sentry.DSN); err != nil { log.Error(err) } @@ -55,30 +53,14 @@ func init() { } go database.RestoreConnectionWorker(time.Second*10, config.Default.Postgres.URL) - internal.InitRabbitMQ( - config.Default.Observer.Rabbitmq.URL, - config.Default.Observer.Rabbitmq.PrefetchCount, - ) - - if err := mq.TokensRegistration.Declare(); err != nil { - log.Fatal(err) - } - if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { - log.Fatal(err) - } - - ts = tokensearcher.Init(database, platform.TokensAPIs, mq.TokensRegistration) - ti = tokenindexer.Init(database) - - go mq.FatalWorker(time.Second * 10) + tokenIndexer = tokenindexer.Init(database) } func main() { - api.SetupTokensIndexAPI(engine, ti) - api.SetupTokensSearcherAPI(engine, ts) + api.SetupTokensIndexAPI(engine, tokenIndexer) api.SetupSwaggerAPI(engine) api.SetupPlatformAPI(engine) - internal.SetupGracefulShutdown(ctx, port, engine) + golibsGin.SetupGracefulShutdown(ctx, port, engine) cancel() } diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index 7d24307af..0679446a4 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -4,17 +4,22 @@ import ( "context" "time" + "github.com/trustwallet/golibs/network/middleware" + + "github.com/trustwallet/blockatlas/platform" + + "github.com/trustwallet/golibs/network/mq" + + "github.com/trustwallet/blockatlas/services/tokenindexer" + "github.com/trustwallet/blockatlas/services/notifier" "github.com/trustwallet/blockatlas/config" "github.com/trustwallet/blockatlas/services/subscriber" - "github.com/trustwallet/blockatlas/services/tokenindexer" - "github.com/trustwallet/blockatlas/services/tokensearcher" log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/mq" ) const ( @@ -25,6 +30,10 @@ var ( ctx context.Context cancel context.CancelFunc database *db.Instance + + transactions = "transactions" + tokens = "tokens" + subscriptions = "subscriptions" ) func init() { @@ -33,10 +42,10 @@ func init() { internal.InitConfig(confPath) - internal.InitRabbitMQ( - config.Default.Observer.Rabbitmq.URL, - config.Default.Observer.Rabbitmq.PrefetchCount, - ) + if err := middleware.SetupSentry(config.Default.Sentry.DSN); err != nil { + log.Error(err) + } + internal.InitMQ(config.Default.Observer.Rabbitmq.URL) var err error database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Log) @@ -45,38 +54,46 @@ func init() { } go database.RestoreConnectionWorker(time.Second*10, config.Default.Postgres.URL) - time.Sleep(time.Millisecond) + tokenindexer.Init(database) } func main() { defer mq.Close() - queues := []mq.Queue{ - mq.TxNotifications, - mq.RawTransactionsTokenIndexer, - mq.RawTransactions, - mq.RawTransactionsSearcher, - mq.Subscriptions, - mq.TokensRegistration, + // RunTokenIndexerSubscribe requires to fetch data from token apis. Improve later + platform.Init(config.Default.Platform) + + options := mq.ConsumerOptions{Workers: config.Default.Consumer.Workers} + + switch config.Default.Consumer.Service { + case transactions: + setupTransactionsConsumer(options, ctx) + case subscriptions: + setupSubscriptionsConsumer(options, ctx) + case tokens: + setupTokensConsumer(options, ctx) + default: + setupTransactionsConsumer(options, ctx) + setupSubscriptionsConsumer(options, ctx) + setupTokensConsumer(options, ctx) } - for _, queue := range queues { - err := queue.Declare() - if err != nil { - log.Fatal("Declare ", queue, err) - } - } + go mq.FatalWorker(time.Second * 10) - go mq.RawTransactions.RunConsumerWithCancelAndDbConn(notifier.RunNotifier, database, ctx) + middleware.SetupGracefulShutdown(time.Second * 5) - go mq.RawTransactionsTokenIndexer.RunConsumerWithCancelAndDbConn(tokenindexer.RunTokenIndexer, database, ctx) - go mq.RawTransactionsSearcher.RunConsumerWithCancelAndDbConn(tokensearcher.Run, database, ctx) + cancel() +} - go mq.Subscriptions.RunConsumerWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, database, ctx) - go mq.TokensRegistration.RunConsumerWithCancelAndDbConn(subscriber.RunTokensSubscriber, database, ctx) +func setupTransactionsConsumer(options mq.ConsumerOptions, ctx context.Context) { + go internal.RawTransactions.RunConsumer(internal.ConsumerDatabase{Database: database, Delivery: notifier.RunNotifier}, options, ctx) +} - go mq.FatalWorker(time.Second * 10) +func setupSubscriptionsConsumer(options mq.ConsumerOptions, ctx context.Context) { + go internal.Subscriptions.RunConsumer(internal.ConsumerDatabase{Database: database, Delivery: subscriber.RunSubscriber}, options, ctx) + go internal.SubscriptionsTokens.RunConsumer(tokenindexer.ConsumerIndexer{Database: database, TokensAPIs: platform.TokensAPIs, Delivery: tokenindexer.RunTokenIndexerSubscribe}, options, ctx) +} - internal.SetupGracefulShutdownForObserver() - cancel() +func setupTokensConsumer(options mq.ConsumerOptions, ctx context.Context) { + go internal.RawTokens.RunConsumer(internal.ConsumerDatabase{Database: database, Delivery: tokenindexer.RunTokenIndexer}, options, ctx) } diff --git a/cmd/parser/main.go b/cmd/parser/main.go index b6921332c..84be424d1 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -9,14 +9,16 @@ import ( "syscall" "time" + "github.com/trustwallet/golibs/network/middleware" + "github.com/trustwallet/blockatlas/config" log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/platform" "github.com/trustwallet/blockatlas/services/parser" + "github.com/trustwallet/golibs/network/mq" ) const ( @@ -35,20 +37,12 @@ func init() { internal.InitConfig(confPath) - internal.InitRabbitMQ( - config.Default.Observer.Rabbitmq.URL, - config.Default.Observer.Rabbitmq.PrefetchCount, - ) - - platform.Init(config.Default.Platform) - - if err := mq.RawTransactions.Declare(); err != nil { - log.Fatal(err) + if err := middleware.SetupSentry(config.Default.Sentry.DSN); err != nil { + log.Error(err) } - if err := mq.RawTransactionsTokenIndexer.Declare(); err != nil { - log.Fatal(err) - } + internal.InitMQ(config.Default.Observer.Rabbitmq.URL) + platform.Init(config.Default.Platform) if len(platform.BlockAPIs) == 0 { log.Fatal("No APIs to observe") @@ -71,54 +65,37 @@ func main() { coinCancel = make(map[string]context.CancelFunc) stopChannel = make(chan<- struct{}, len(platform.BlockAPIs)) ) - backlogTime := config.Default.Observer.Backlog minInterval := config.Default.Observer.BlockPoll.Min maxInterval := config.Default.Observer.BlockPoll.Max - fetchBlocksInterval := config.Default.Observer.FetchBlocksInterval - maxBackLogBlocks := config.Default.Observer.BacklogMaxBlocks + fetchBlocksTimeout := config.Default.Observer.FetchBlocksInterval + maxBlocks := config.Default.Observer.BlockPoll.MaxBlocks go mq.FatalWorker(time.Second * 10) wg.Add(len(platform.BlockAPIs)) for _, api := range platform.BlockAPIs { - time.Sleep(time.Millisecond * 5) coin := api.Coin() pollInterval := parser.GetInterval(coin.BlockTime, minInterval, maxInterval) - var backlogCount int - if coin.BlockTime == 0 { - backlogCount = 50 - log.WithFields(log.Fields{"coin": coin.Handle}).Warn("Unknown block time") - } else { - backlogCount = int(backlogTime / pollInterval) - } - coinCancel[coin.Handle] = cancel params := parser.Params{ - Ctx: ctx, - Api: api, - TransactionsQueue: mq.RawTransactions, - TokenTransactionsQueue: []mq.Queue{ - mq.RawTransactionsSearcher, - mq.RawTransactionsTokenIndexer, - }, + Api: api, + TransactionsExchange: internal.RawTransactionsExchange, ParsingBlocksInterval: pollInterval, - FetchBlocksTimeout: fetchBlocksInterval, - BacklogCount: backlogCount, - MaxBacklogBlocks: maxBackLogBlocks, + FetchBlocksTimeout: fetchBlocksTimeout, + MaxBlocks: maxBlocks, StopChannel: stopChannel, Database: database, } - go parser.RunParser(params) + go parser.RunParser(params, ctx) log.WithFields(log.Fields{ - "coin": api.Coin().Handle, - "interval": pollInterval, - "backlog": backlogCount, - "Max backlog": maxBackLogBlocks, - "Fetching blocks interval": fetchBlocksInterval, + "coin": api.Coin().Handle, + "interval": pollInterval, + "max blocks": maxBlocks, + "fetch blocks timeout": fetchBlocksTimeout, }).Info("Parser params") wg.Done() diff --git a/cmd/setup/main.go b/cmd/setup/main.go new file mode 100644 index 000000000..33de320c7 --- /dev/null +++ b/cmd/setup/main.go @@ -0,0 +1,70 @@ +package main + +import ( + "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/golibs/network/middleware" + "github.com/trustwallet/golibs/network/mq" + + log "github.com/sirupsen/logrus" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/platform" +) + +const ( + defaultConfigPath = "../../config.yml" +) + +var ( + database *db.Instance +) + +func init() { + _, confPath := internal.ParseArgs("", defaultConfigPath) + + internal.InitConfig(confPath) + internal.InitMQ(config.Default.Observer.Rabbitmq.URL) + platform.Init(config.Default.Platform) + + var err error + database, err = db.New(config.Default.Postgres.URL, config.Default.Postgres.Log) + if err != nil { + log.Fatal(err) + } +} + +func main() { + log.Info("Start setup") + + if err := middleware.SetupSentry(config.Default.Sentry.DSN); err != nil { + log.Error(err) + } + + if err := db.Setup(database.Gorm); err != nil { + log.Fatal(err) + } + + if err := internal.RawTransactionsExchange.Declare("topic"); err != nil { + log.Fatal(err) + } + + queues := []mq.Queue{ + internal.TxNotifications, + internal.RawTransactions, + internal.Subscriptions, + internal.SubscriptionsTokens, + internal.RawTokens, + internal.Subscriptions, + } + for _, queue := range queues { + if err := queue.Declare(); err != nil { + log.Fatal("Queue declare: ", queue, err) + } + } + + if err := internal.RawTransactionsExchange.Bind([]mq.Queue{internal.RawTokens, internal.RawTransactions}); err != nil { + log.Fatal("Transactions Exchange bind: ", err) + } + + log.Info("Finish setup") +} diff --git a/config.yml b/config.yml index 3e33930a1..75311acaa 100644 --- a/config.yml +++ b/config.yml @@ -10,24 +10,25 @@ platform: [ all ] # The transaction watcher observer: - # Don't request blocks older than this - backlog: 3h # Amount of time between fetching blocks concurrently fetch_blocks_interval: 1ms - # Don't request more than N blocks at once - backlog_max_blocks: 100 # Block polling interval block_poll: min: 3s max: 30s + # Don't request more than N blocks at once + max_blocks: 15 rabbitmq: url: amqp://localhost:5672 - prefetch_count: 10 postgres: url: postgresql://user:pass@localhost/blockatlas?sslmode=disable log: false +consumer: + service: "" + workers: 8 + # [BNB] Binance DEX: https://www.binance.org/ binance: api: https://dex.binance.org diff --git a/config/configuration.go b/config/configuration.go index 0bca947f3..0292ba6ea 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -16,16 +16,14 @@ type Configuration struct { Platform []string `mapstructure:"platform"` RestAPI string `mapstructure:"rest_api"` Observer struct { - Backlog time.Duration `mapstructure:"backlog"` FetchBlocksInterval time.Duration `mapstructure:"fetch_blocks_interval"` - BacklogMaxBlocks int64 `mapstructure:"backlog_max_blocks"` BlockPoll struct { - Min time.Duration `mapstructure:"min"` - Max time.Duration `mapstructure:"max"` + Min time.Duration `mapstructure:"min"` + Max time.Duration `mapstructure:"max"` + MaxBlocks int64 `mapstructure:"max_blocks"` } `mapstructure:"block_poll"` Rabbitmq struct { - URL string `mapstructure:"url"` - PrefetchCount int `mapstructure:"prefetch_count"` + URL string `mapstructure:"url"` } `mapstructure:"rabbitmq"` } `mapstructure:"observer"` Postgres struct { @@ -210,6 +208,10 @@ type Configuration struct { Sentry struct { DSN string `mapstructure:"dsn"` } `mapstructure:"sentry"` + Consumer struct { + Service string `mapstructure:"service"` + Workers int `mapstructure:"workers"` + } `mapstructure:"consumer"` } var Default Configuration diff --git a/configmock.yml b/configmock.yml index cbddd7376..7a3d9477c 100644 --- a/configmock.yml +++ b/configmock.yml @@ -9,15 +9,11 @@ platform: all # The transaction watcher observer: - backlog: 3h - # Don't request more than N blocks at once - backlog_max_blocks: 200 - # Max connections to open to API - stream_conns: 16 # Block polling interval block_poll: min: 3s max: 30s + max_blocks: 15 rabbitmq: uri: amqp://rabbit:5672 consumer: diff --git a/db/addresstoasset.go b/db/addresstoasset.go deleted file mode 100644 index eddd72d3f..000000000 --- a/db/addresstoasset.go +++ /dev/null @@ -1,263 +0,0 @@ -package db - -import ( - "time" - - "github.com/trustwallet/blockatlas/db/models" - "gorm.io/gorm" - "gorm.io/gorm/clause" -) - -func (i Instance) GetSubscribedAddressesForAssets(addresses []string) ([]models.Address, error) { - var result []models.Address - err := i.Gorm.Model(&models.AssetSubscription{}). - Select("id", "address"). - Joins("LEFT JOIN addresses a ON a.id = address_id"). - Where("address in (?)", addresses). - Scan(&result). - Limit(len(addresses)).Error - if err != nil { - return nil, err - } - return result, nil -} - -func (i Instance) GetAssetsMapByAddresses(addresses []string) (map[string][]models.Asset, error) { - var associations []models.AddressToAssetAssociation - if err := i.Gorm.Joins("Address"). - Joins("Asset"). - Find(&associations, "address in (?)", addresses).Error; err != nil { - return nil, err - } - - result := make(map[string][]models.Asset) - for _, a := range associations { - assets := result[a.Address.Address] - result[a.Address.Address] = append(assets, a.Asset) - } - return result, nil -} - -func (i Instance) GetAssetsMapByAddressesFromTime(addresses []string, from time.Time) (map[string][]models.Asset, error) { - if len(addresses) == 0 { - return map[string][]models.Asset{}, nil - } - var associations []models.AddressToAssetAssociation - err := i.Gorm. - Joins("Address"). - Where("address in (?)", addresses). - Joins("Asset"). - Find(&associations, "address_to_asset_associations.created_at > ?", from).Error - if err != nil { - return nil, err - } - - result := make(map[string][]models.Asset) - for _, a := range associations { - assets := result[a.Address.Address] - result[a.Address.Address] = append(assets, a.Asset) - } - return result, nil -} - -func (i *Instance) GetAssociationsByAddresses(addresses []string) ([]models.AddressToAssetAssociation, error) { - var result []models.AddressToAssetAssociation - if err := i.Gorm. - Joins("Address"). - Joins("Asset"). - Find(&result, "address in (?)", addresses).Error; err != nil { - return nil, err - } - return result, nil -} - -func (i *Instance) GetAssociationsByAddressesFromTime(addresses []string, from time.Time) ([]models.AddressToAssetAssociation, error) { - var result []models.AddressToAssetAssociation - err := i.Gorm.Joins("Address").Where("address in (?)", addresses).Joins("Asset").Find(&result, "created_at > ?", from).Error - if err != nil { - return nil, err - } - return result, nil -} - -func (i *Instance) AddAssociationsForAddress(address string, assets []models.Asset) error { - return i.Gorm.Transaction(func(tx *gorm.DB) error { - uniqueAssets := getUniqueAssets(assets) - - var err error - dbAddress := models.Address{Address: address} - err = tx.Clauses(clause.OnConflict{DoNothing: true}).FirstOrCreate(&dbAddress, "address = ?", address).Error - if err != nil { - return err - } - - if len(uniqueAssets) > 0 { - if err = tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssets).Error; err != nil { - return err - } - } - - var dbAssets []models.Asset - if len(uniqueAssets) > 0 { - err = tx. - Where("asset in (?)", models.AssetIDs(uniqueAssets)). - Find(&dbAssets).Error - if err != nil { - return err - } - } - - assetsSub := models.AssetSubscription{AddressID: dbAddress.ID} - err = tx.Clauses(clause.OnConflict{ - Columns: []clause.Column{ - { - Name: "address_id", - }, - }, - DoUpdates: clause.Assignments(map[string]interface{}{ - "deleted_at": nil, - }), - }).Create(&assetsSub).Error - if err != nil { - return err - } - - result := make([]models.AddressToAssetAssociation, 0, len(dbAssets)) - for _, asset := range dbAssets { - result = append(result, models.AddressToAssetAssociation{ - AddressID: dbAddress.ID, - AssetID: asset.ID, - }) - } - if len(result) > 0 { - return tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error - } - return nil - }) -} - -func (i *Instance) UpdateAssociationsForExistingAddresses(associations map[string][]models.Asset) error { - return i.Gorm.Transaction(func(tx *gorm.DB) error { - assets := make([]models.Asset, 0, len(associations)) - for _, v := range associations { - assets = append(assets, v...) - } - - if len(assets) == 0 { - return nil - } - - uniqueAssets := getUniqueAssets(assets) - uniqueAssetsModel := make([]models.Asset, 0, len(uniqueAssets)) - for _, l := range uniqueAssets { - uniqueAssetsModel = append(uniqueAssetsModel, models.Asset{Asset: l.Asset}) - } - if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAssetsModel).Error; err != nil { - return err - } - - var dbAssets []models.Asset - err := tx. - Where("asset in (?)", models.AssetIDs(uniqueAssets)). - Find(&dbAssets). - Limit(len(uniqueAssets)). - Error - if err != nil { - return err - } - - assetsMap := makeMapAssets(dbAssets) - - addresses := make([]string, 0, len(associations)) - for k := range associations { - addresses = append(addresses, k) - } - - var dbAddresses []models.Address - if err := tx.Find(&dbAddresses, "address in (?)", addresses).Limit(len(addresses)).Error; err != nil { - return err - } - - var addressSubs []models.AssetSubscription - for _, a := range dbAddresses { - sub := models.AssetSubscription{AddressID: a.ID} - addressSubs = append(addressSubs, sub) - } - - err = tx.Clauses(clause.OnConflict{ - Columns: []clause.Column{ - { - Name: "address_id", - }, - }, - DoUpdates: clause.Assignments(map[string]interface{}{ - "deleted_at": nil, - }), - }).Create(&addressSubs).Error - if err != nil { - return err - } - - addressesMap := makeMapAddress(dbAddresses) - - var result []models.AddressToAssetAssociation - for address, assets := range associations { - for _, asset := range assets { - addressID, ok := addressesMap[address] - if !ok || addressID == 0 { - continue - } - assetID, ok := assetsMap[asset.Asset] - if !ok || assetID == 0 { - continue - } - r := models.AddressToAssetAssociation{ - AddressID: addressID, - AssetID: assetID, - } - result = append(result, r) - } - } - return tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error - }) -} - -func makeMapAssets(addresses []models.Asset) map[string]uint { - result := make(map[string]uint) - for _, a := range addresses { - result[a.Asset] = a.ID - } - return result -} - -func makeMapAddress(addresses []models.Address) map[string]uint { - result := make(map[string]uint) - for _, a := range addresses { - result[a.Address] = a.ID - } - return result -} - -func getUniqueStrings(values []string) []string { - keys := make(map[string]struct{}) - var list []string - for _, entry := range values { - if _, value := keys[entry]; !value { - keys[entry] = struct{}{} - list = append(list, entry) - } - } - return list -} - -func getUniqueAssets(values []models.Asset) []models.Asset { - keys := make(map[string]struct{}) - var list []models.Asset - for _, entry := range values { - if _, value := keys[entry.Asset]; !value { - keys[entry.Asset] = struct{}{} - list = append(list, entry) - } - } - return list -} diff --git a/db/asset.go b/db/asset.go index 97c31af73..ba1616bed 100644 --- a/db/asset.go +++ b/db/asset.go @@ -3,7 +3,6 @@ package db import ( "encoding/json" "time" - "unicode/utf8" "gorm.io/gorm" "gorm.io/gorm/clause" @@ -13,12 +12,51 @@ import ( "github.com/trustwallet/blockatlas/db/models" ) +func (i *Instance) GetAsset(assetId string) (models.Asset, error) { + var asset models.Asset + err := i.Gorm. + First(&asset, "asset = ?", assetId).Error + if err != nil { + return asset, err + } + return asset, nil +} + +func (i *Instance) GetAssetsByIDs(ids []string) ([]models.Asset, error) { + //TODO: look why nil and len 0 make db calls rn + if len(ids) == 0 { + return nil, nil + } + + var dbAssets []models.Asset + if err := i.Gorm. + Where("asset in (?)", ids). + Find(&dbAssets).Error; err != nil { + return nil, err + } + return dbAssets, nil +} + +func (i *Instance) GetSubscriptionsByAddressIDs(ids []string, from time.Time) ([]models.SubscriptionsAssetAssociation, error) { + var associations []models.SubscriptionsAssetAssociation + if err := i.Gorm. + Joins("join subscriptions on subscriptions.id = subscriptions_asset_associations.subscription_id", ids). + Preload("Subscription"). + Preload("Asset"). + Where("subscriptions.address in (?)", ids). + Where("subscriptions_asset_associations.created_at > ?", from). + Find(&associations).Error; err != nil { + return nil, err + } + return associations, nil +} + func (i *Instance) AddNewAssets(assets []models.Asset) error { if len(assets) == 0 { return nil } + uniqueAssets := getUniqueAssets(assets) - uniqueAssets = filterAssets(uniqueAssets) var notInMemoryAssets []models.Asset for _, a := range uniqueAssets { @@ -59,10 +97,8 @@ func (i *Instance) AddNewAssets(assets []models.Asset) error { } i.addToMemory(newAssets) - assetsBatch := assetsBatch(newAssets, batchCount) - return i.Gorm.Transaction(func(tx *gorm.DB) error { - for _, na := range assetsBatch { + for _, na := range newAssets { err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&na).Error if err != nil { return err @@ -85,64 +121,24 @@ func (i *Instance) addToMemory(newAssets []models.Asset) { } } -func (i *Instance) GetAssetsByIDs(ids []string) ([]models.Asset, error) { - //TODO: look why nil and len 0 make db calls rn - if len(ids) == 0 { - return nil, nil - } - +func (i *Instance) GetAssetsFrom(from time.Time) ([]models.Asset, error) { var dbAssets []models.Asset if err := i.Gorm. - Where("asset in (?)", ids). - Find(&dbAssets).Error; err != nil { + Find(&dbAssets, "created_at > ?", from). + Limit(10000).Error; err != nil { return nil, err } return dbAssets, nil } -func (i *Instance) GetAssetsFrom(from time.Time, coin int) ([]models.Asset, error) { - var dbAssets []models.Asset - if coin == -1 { - if err := i.Gorm.Find(&dbAssets, "created_at > ?", from).Error; err != nil { - return nil, err - } - } else { - if err := i.Gorm.Find(&dbAssets, "created_at > ? and coin = ?", from, coin).Error; err != nil { - return nil, err - } - } - - return dbAssets, nil -} - -func assetsBatch(values []models.Asset, sizeUint uint) [][]models.Asset { - size := int(sizeUint) - resultLength := (len(values) + size - 1) / size - result := make([][]models.Asset, resultLength) - lo, hi := 0, size - for i := range result { - if hi > len(values) { - hi = len(values) - } - result[i] = values[lo:hi:hi] - lo, hi = hi, hi+size - } - return result -} - -func filterAssets(values []models.Asset) []models.Asset { - result := make([]models.Asset, 0, len(values)) - for _, v := range values { - valuesAreAtUTF8 := utf8.ValidString(v.Asset) && - utf8.ValidString(v.Type) && - utf8.ValidString(v.Symbol) && - utf8.ValidString(v.Name) - valuesAreNotEmpty := v.Asset != "" && - v.Type != "" && v.Symbol != "" && - v.Name != "" && v.Decimals != 0 - if valuesAreAtUTF8 && valuesAreNotEmpty { - result = append(result, v) +func getUniqueAssets(values []models.Asset) []models.Asset { + keys := make(map[string]bool) + var list []models.Asset + for _, entry := range values { + if _, value := keys[entry.Asset]; !value { + keys[entry.Asset] = true + list = append(list, entry) } } - return result + return list } diff --git a/db/db.go b/db/db.go index e0afb2c44..bdeb65ab0 100644 --- a/db/db.go +++ b/db/db.go @@ -4,12 +4,12 @@ import ( "errors" "time" - "gorm.io/gorm/logger" - - log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/db/models" + "gorm.io/gorm/logger" + gocache "github.com/patrickmn/go-cache" + log "github.com/sirupsen/logrus" "gorm.io/driver/postgres" "gorm.io/gorm" @@ -20,10 +20,6 @@ type Instance struct { MemoryCache *gocache.Cache } -// By gorm-bulk-insert author: -// "Depending on the number of variables included, 2000 to 3000 is recommended." -const batchCount = 3000 - func New(url string, log bool) (*Instance, error) { var logMode logger.LogLevel if log { @@ -37,23 +33,21 @@ func New(url string, log bool) (*Instance, error) { return nil, err } - err = db.AutoMigrate( - &models.NotificationSubscription{}, - &models.Tracker{}, - &models.Asset{}, - &models.AssetSubscription{}, - &models.Address{}, - &models.AddressToAssetAssociation{}, - ) - if err != nil { - return nil, err - } mc := gocache.New(gocache.NoExpiration, gocache.NoExpiration) i := &Instance{Gorm: db, MemoryCache: mc} return i, nil } +func Setup(db *gorm.DB) error { + return db.AutoMigrate( + &models.Tracker{}, + &models.Asset{}, + &models.Subscription{}, + &models.SubscriptionsAssetAssociation{}, + ) +} + func (i *Instance) RestoreConnectionWorker(timeout time.Duration, uri string) { log.Info("Run PG RestoreConnectionWorker") @@ -71,8 +65,6 @@ func (i *Instance) restoreConnection(uri string) error { return err } - log.Info("Run restoreConnection") - if err = db.Ping(); err != nil { log.Warn("PG is not available now") log.Warn("Trying to connect to PG...") diff --git a/db/models/address.go b/db/models/address.go deleted file mode 100644 index 9ef66921d..000000000 --- a/db/models/address.go +++ /dev/null @@ -1,10 +0,0 @@ -package models - -type Address struct { - ID uint `gorm:"primary_key"` - Address string `gorm:"type:varchar(128); uniqueIndex"` -} - -// Use such model in future -// Coin uint `gorm:"index:idx_coin;" sql:"unique_index:idx_ca"` -// Address string `gorm:"index:idx_address; type:varchar(128)" sql:"unique_index:idx_ca"` diff --git a/db/models/addresstoasset.go b/db/models/addresstoasset.go deleted file mode 100644 index e86322ca8..000000000 --- a/db/models/addresstoasset.go +++ /dev/null @@ -1,16 +0,0 @@ -package models - -import ( - "time" -) - -type AddressToAssetAssociation struct { - CreatedAt time.Time `gorm:"index:,"` - DeletedAt *time.Time `gorm:"index:,; default:NULL"` - - Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"primaryKey; autoIncrement:false; index:,"` - - Asset Asset `gorm:"ForeignKey:AssetID; not null"` - AssetID uint `gorm:"primaryKey; autoIncrement:false; index:,"` -} diff --git a/db/models/asset.go b/db/models/asset.go index a0c90b977..8bfdde554 100644 --- a/db/models/asset.go +++ b/db/models/asset.go @@ -1,6 +1,10 @@ package models -import "time" +import ( + "errors" + "time" + "unicode/utf8" +) type Asset struct { CreatedAt time.Time `gorm:"index:,"` @@ -14,6 +18,26 @@ type Asset struct { Coin uint } +func (asset *Asset) IsValid() error { + if len(asset.Name) >= 32 { + return errors.New("name should be less than 32") + } + if len(asset.Symbol) >= 32 { + return errors.New("name should be less than 32") + } + stringValues := []string{asset.Asset, asset.Type, asset.Symbol, asset.Name} + + for _, value := range stringValues { + if value == "" { + return errors.New("empty value for asset: " + asset.Asset) + } + if !utf8.ValidString(value) { + return errors.New("not valid utf8 string: " + value) + } + } + return nil +} + func AssetIDs(assets []Asset) []string { result := make([]string, 0, len(assets)) for _, a := range assets { diff --git a/db/models/asset_test.go b/db/models/asset_test.go new file mode 100644 index 000000000..8dc1e105d --- /dev/null +++ b/db/models/asset_test.go @@ -0,0 +1,66 @@ +package models + +import ( + "testing" + "time" +) + +func TestAsset_isValid1(t *testing.T) { + type fields struct { + CreatedAt time.Time + ID uint + Asset string + Decimals uint + Name string + Symbol string + Type string + Coin uint + } + tests := []struct { + name string + fields fields + wantErr bool + }{ + { + "Valid asset", + fields{ + Asset: "c60", + Decimals: 18, + Name: "Ethereum", + Symbol: "ETH", + Type: "coin", + Coin: 60, + }, + false, + }, + { + "Bytes32 name", + fields{ + Asset: "c60_t0xfFED56a180f23fD32Bc6A1d8d3c09c283aB594A8", + Decimals: 0, + Name: "\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000", + Symbol: "FL", + Type: "ERC20", + Coin: 60, + }, + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + asset := &Asset{ + CreatedAt: tt.fields.CreatedAt, + ID: tt.fields.ID, + Asset: tt.fields.Asset, + Decimals: tt.fields.Decimals, + Name: tt.fields.Name, + Symbol: tt.fields.Symbol, + Type: tt.fields.Type, + Coin: tt.fields.Coin, + } + if err := asset.IsValid(); (err != nil) != tt.wantErr { + t.Errorf("isValid() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index 207246697..816a2b27f 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -1,17 +1,23 @@ package models -import "time" +import ( + "time" +) type ( - NotificationSubscription struct { - DeletedAt *time.Time `gorm:"default:NULL; index"` - Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"primary_key; autoIncrement:false"` + // Subscription for address and asset associations + Subscription struct { + ID uint `gorm:"primaryKey;"` + CreatedAt time.Time + Address string `gorm:"uniqueIndex:idx_address; type:varchar(128); not null;"` } - AssetSubscription struct { - DeletedAt *time.Time `gorm:"default:NULL; index"` - Address Address `gorm:"ForeignKey:AddressID; not null"` - AddressID uint `gorm:"primary_key; autoIncrement:false"` + SubscriptionsAssetAssociation struct { + CreatedAt time.Time `gorm:"index;"` + Subscription Subscription `gorm:"ForeignKey:SubscriptionId; not null"` + SubscriptionId uint `gorm:"primary_key; autoIncrement:false; index"` + + Asset Asset `gorm:"ForeignKey:AssetId; not null"` + AssetId uint `gorm:"primary_key; autoIncrement:false; index"` } ) diff --git a/db/notification.go b/db/notification.go deleted file mode 100644 index bfa72b916..000000000 --- a/db/notification.go +++ /dev/null @@ -1,70 +0,0 @@ -package db - -import ( - "errors" - - "github.com/trustwallet/blockatlas/db/models" - "gorm.io/gorm" - "gorm.io/gorm/clause" -) - -func (i *Instance) GetSubscriptionsForNotifications(addresses []string) ([]models.NotificationSubscription, error) { - if len(addresses) == 0 { - return nil, errors.New("Empty addresses") - } - - var subscriptionsDataList []models.NotificationSubscription - err := i.Gorm.Joins("Address").Limit(len(addresses)).Find(&subscriptionsDataList, "address in (?)", addresses).Error - if err != nil { - return nil, err - } - return subscriptionsDataList, nil -} - -func (i *Instance) AddSubscriptionsForNotifications(addresses []string) error { - if len(addresses) == 0 { - return errors.New("Empty subscriptions") - } - return i.Gorm.Transaction(func(tx *gorm.DB) error { - uniqueAddresses := getUniqueStrings(addresses) - uniqueAddressesModel := make([]models.Address, 0, len(uniqueAddresses)) - for _, a := range uniqueAddresses { - uniqueAddressesModel = append(uniqueAddressesModel, models.Address{ - Address: a, - }) - } - - err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&uniqueAddressesModel).Error - if err != nil { - return err - } - - var dbAddresses []models.Address - if err = tx.Find(&dbAddresses, "address in (?)", uniqueAddresses).Error; err != nil { - return err - } - - result := make([]models.NotificationSubscription, 0, len(dbAddresses)) - for _, a := range dbAddresses { - result = append(result, models.NotificationSubscription{AddressID: a.ID}) - } - return tx.Clauses(clause.OnConflict{ - Columns: []clause.Column{ - { - Name: "address_id", - }, - }, - DoUpdates: clause.Assignments(map[string]interface{}{ - "deleted_at": nil, - }), - }).Create(&result).Error - }) -} - -func (i *Instance) DeleteSubscriptionsForNotifications(addresses []string) error { - if len(addresses) == 0 { - return errors.New("Empty subscriptions") - } - q := `DELETE FROM notification_subscriptions ns USING addresses a where ns.address_id = a.id AND a.address IN (?);` - return i.Gorm.Exec(q, addresses).Error -} diff --git a/db/subscription.go b/db/subscription.go new file mode 100644 index 000000000..79b638357 --- /dev/null +++ b/db/subscription.go @@ -0,0 +1,60 @@ +package db + +import ( + "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "gorm.io/gorm/clause" +) + +func (i *Instance) CreateSubscriptions(addresses []blockatlas.Subscription) error { + if len(addresses) == 0 { + return nil + } + result := make([]models.Subscription, 0) + for _, address := range addresses { + result = append(result, models.Subscription{Address: address.AddressID()}) + } + return i.Gorm. + Clauses(clause.OnConflict{DoNothing: true}). + Create(&result).Error +} + +func (i *Instance) GetSubscriptions(addresses []string) ([]models.Subscription, error) { + var subscriptions []models.Subscription + err := i.Gorm.Find(&subscriptions, "address in (?)", addresses).Error + if err != nil { + return nil, err + } + return subscriptions, nil +} + +func (i *Instance) DeleteSubscriptions(addresses []string) error { + subscriptions, err := i.GetSubscriptions(addresses) + if err != nil { + return err + } + if len(subscriptions) == 0 { + return nil + } + subscriptionsIds := make([]uint, 0) + for _, subscription := range subscriptions { + subscriptionsIds = append(subscriptionsIds, subscription.ID) + } + if err = i.Gorm. + Where("subscription_id in (?)", subscriptionsIds). + Delete(&models.SubscriptionsAssetAssociation{}).Error; err != nil { + return err + } + return i.Gorm. + Where("id in (?)", subscriptionsIds). + Delete(&models.Subscription{}).Error +} + +func (i *Instance) CreateSubscriptionsAssets(associations []models.SubscriptionsAssetAssociation) error { + if len(associations) == 0 { + return nil + } + return i.Gorm. + Clauses(clause.OnConflict{DoNothing: true}). + Create(&associations).Error +} diff --git a/go.mod b/go.mod index 915a25507..28cbcb427 100644 --- a/go.mod +++ b/go.mod @@ -6,26 +6,20 @@ go 1.15 // +heroku install ./cmd/... require ( - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect - github.com/Microsoft/go-winio v0.4.16 // indirect - github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 - github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/deckarep/golang-set v1.7.1 - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.4.0 // indirect + github.com/getsentry/raven-go v0.2.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 - github.com/google/go-cmp v0.4.0 // indirect - github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/imroc/req v0.3.0 github.com/mitchellh/mapstructure v1.4.0 + github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect github.com/mr-tron/base58 v1.2.0 - github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v1.0.0-rc9 // indirect github.com/ory/dockertest v3.3.5+incompatible + github.com/ory/dockertest/v3 v3.6.3 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible github.com/sirupsen/logrus v1.7.0 github.com/spf13/viper v1.7.1 @@ -34,13 +28,12 @@ require ( github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/swag v1.7.0 github.com/trustwallet/golibs v0.0.26 - github.com/trustwallet/golibs/network v0.0.0-20201216013232-f564db1c6ecd + github.com/trustwallet/golibs/network v0.0.0-20210105062859-04e821673147 go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 - golang.org/x/net v0.0.0-20201216054612-986b41b23924 // indirect - golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e // indirect + golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect + golang.org/x/sys v0.0.0-20210104204734-6f8348627aad // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.6 gorm.io/gorm v1.20.9 - gotest.tools v2.2.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index 64b349f83..2025bdf56 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -53,12 +54,17 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 h1:6ejg6Lkk8dskcM7wQ28gONkukbQkM4qpj4RnYbpFzrI= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -69,6 +75,8 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -150,8 +158,9 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -276,11 +285,14 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= +github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -310,6 +322,10 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 h1:SPoLlS9qUUnXcIY4pvA4CTwYjk0Is5f4UPEkeESr53k= +github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2/go.mod h1:TjQg8pa4iejrUrjiz0MCtMV38jdMNW4doKSiBrEvCQQ= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -323,14 +339,18 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc= github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.6.3 h1:L8JWiGgR+fnj90AEOkTFIEp4j5uWAK72P3IUsYgn2cs= +github.com/ory/dockertest/v3 v3.6.3/go.mod h1:EFLcVUOl8qCwp9NyDAcCDtq/QviLtYswW/VbWzUnTNE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -412,8 +432,24 @@ 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.26 h1:8Cfym03kkkvQkzdp7ZBPIX0583jmL5d0x910psyHbpM= github.com/trustwallet/golibs v0.0.26/go.mod h1:Vi63TTS0yRAPwFIIKe7tw1yTgd71RACQqgZpUcWTv04= -github.com/trustwallet/golibs/network v0.0.0-20201216013232-f564db1c6ecd h1:7G8l+qBLmLu45AClEbBs1puJS0j2TSvpjFztQTxg1YI= -github.com/trustwallet/golibs/network v0.0.0-20201216013232-f564db1c6ecd/go.mod h1:klL63JlvgRSc+vpAd5TsTsyqR75+N2mPYd1PCg/+jBo= +github.com/trustwallet/golibs/network v0.0.0-20201230050918-14143fadb599 h1:FFfIqpBTRr3j0UDxqdAghhf/nQ+mdAjVSUS+evrlLX4= +github.com/trustwallet/golibs/network v0.0.0-20201230050918-14143fadb599/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs/network v0.0.0-20210104211257-93dbcade3020 h1:qCdSiwsTl3298l5AgRwwnX71ZjrtXs1G2alJ9rGjGlE= +github.com/trustwallet/golibs/network v0.0.0-20210104211257-93dbcade3020/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs/network v0.0.0-20210104211641-8220d564ec5b h1:ByEWkqd8282NByRkpfeamYC93evnKXl7KTARE2fXEGw= +github.com/trustwallet/golibs/network v0.0.0-20210104211641-8220d564ec5b/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs/network v0.0.0-20210104213645-d89799a54570 h1:48um24W0y2fOt2wkUqIf7to3nxTPycdOMRNBXLvGm8s= +github.com/trustwallet/golibs/network v0.0.0-20210104213645-d89799a54570/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs/network v0.0.0-20210104232605-ad31e67e25d2 h1:c6QTCG1t33HT4PbBvuxB5esKV5A/Z4k0M4lBBe+xSso= +github.com/trustwallet/golibs/network v0.0.0-20210104232605-ad31e67e25d2/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs/network v0.0.0-20210105041738-9bc894a4eb36 h1:LvxbcMgzxwtNc3aIWXVO6UBOb+gPI5p6gqCQT3n54r0= +github.com/trustwallet/golibs/network v0.0.0-20210105041738-9bc894a4eb36/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs/network v0.0.0-20210105053024-ba940057a9f6 h1:2dmW1RjE8YqkhowBn+YbCNDNuFLt6ca9DPG296avuzU= +github.com/trustwallet/golibs/network v0.0.0-20210105053024-ba940057a9f6/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs/network v0.0.0-20210105061744-4e36d6077394 h1:aErM6e62NxCsCh9VUGQf7ajWQJZD13bjR3hLZilaH6M= +github.com/trustwallet/golibs/network v0.0.0-20210105061744-4e36d6077394/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs/network v0.0.0-20210105062859-04e821673147 h1:Ll8rCpI8ldt2wre2bI94+vLUkHnIMZUwsUYnjpDcT+8= +github.com/trustwallet/golibs/network v0.0.0-20210105062859-04e821673147/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= 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= @@ -495,10 +531,13 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -533,11 +572,14 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e h1:AyodaIpKjppX+cBfTASF2E1US3H2JFBj920Ot3rtDjs= -golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo= +golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad h1:MCsdmFSdEd4UEa5TKS5JztCRHK/WtvNei1edOj5RSRo= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -563,6 +605,7 @@ golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -621,6 +664,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -635,6 +679,7 @@ gorm.io/gorm v1.20.9 h1:M3aIZKXAC1PtPVu9t3WGwkBTE1le5c2telz3I/qjRNg= gorm.io/gorm v1.20.9/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= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/init.go b/internal/init.go index c556c6720..df9f5d7a2 100644 --- a/internal/init.go +++ b/internal/init.go @@ -8,7 +8,7 @@ import ( "github.com/gin-contrib/cors" "github.com/trustwallet/blockatlas/config" - "github.com/trustwallet/blockatlas/mq" + "github.com/trustwallet/golibs/network/mq" "path/filepath" "time" @@ -50,10 +50,9 @@ func InitEngine(ginMode string) *gin.Engine { return engine } -func InitRabbitMQ(rabbitURI string, prefetchCount int) { - err := mq.Init(rabbitURI) +func InitMQ(url string) { + err := mq.Init(url) if err != nil { - log.WithFields(log.Fields{"uri": rabbitURI}).Fatal("Failed to init Rabbit MQ") + log.Fatal("Failed to init Rabbit MQ", err) } - mq.PrefetchCount = prefetchCount } diff --git a/internal/mq.go b/internal/mq.go new file mode 100644 index 000000000..3fa3a643b --- /dev/null +++ b/internal/mq.go @@ -0,0 +1,29 @@ +package internal + +import ( + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/golibs/network/mq" +) + +const ( + // End consumer of published transactions. Not consumed on blockatlas + TxNotifications mq.Queue = "txNotifications" + // Address:coin subscriptions + Subscriptions mq.Queue = "subscriptions" + SubscriptionsTokens mq.Queue = "subscriptions_tokens" + + // Transactions to process, if match subscriptions, pushed to TxNotifications + RawTransactions mq.Queue = "rawTransactions" + RawTokens mq.Queue = "rawTokens" + RawTransactionsExchange mq.Exchange = "raw_transactions" +) + +type ConsumerDatabase struct { + Database *db.Instance + Delivery func(*db.Instance, amqp.Delivery) error +} + +func (c ConsumerDatabase) Callback(msg amqp.Delivery) error { + return c.Delivery(c.Database, msg) +} diff --git a/internal/shutdown.go b/internal/shutdown.go deleted file mode 100644 index 3011da6c0..000000000 --- a/internal/shutdown.go +++ /dev/null @@ -1,52 +0,0 @@ -package internal - -import ( - "context" - "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - "net/http" - "os" - "os/signal" - "syscall" - "time" -) - -func SetupGracefulShutdown(ctx context.Context, port string, engine *gin.Engine) { - server := &http.Server{ - Addr: ":" + port, - Handler: engine, - } - - defer func() { - if err := server.Shutdown(ctx); err != nil { - log.Fatal("Server Shutdown: ", err) - } - }() - - signalForExit := make(chan os.Signal, 1) - signal.Notify(signalForExit, - syscall.SIGHUP, - syscall.SIGINT, - syscall.SIGTERM, - syscall.SIGQUIT) - - go func() { - if err := server.ListenAndServe(); err != nil { - log.Fatal("Application failed", err) - } - }() - log.WithFields(log.Fields{"bind": port}).Info("Running application") - - stop := <-signalForExit - log.Info("Stop signal Received", stop) - log.Info("Waiting for all jobs to stop") -} - -func SetupGracefulShutdownForObserver() { - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit - log.Info("Shutdown ...") - time.Sleep(time.Second * 5) - log.Info("Exiting gracefully") -} diff --git a/mq/mq.go b/mq/mq.go deleted file mode 100644 index cb20e90b7..000000000 --- a/mq/mq.go +++ /dev/null @@ -1,187 +0,0 @@ -package mq - -import ( - "context" - "time" - - log "github.com/sirupsen/logrus" - "github.com/streadway/amqp" - "github.com/trustwallet/blockatlas/db" -) - -var ( - PrefetchCount int - amqpChan *amqp.Channel - conn *amqp.Connection -) - -type ( - Queue string - Consumer func(amqp.Delivery) - ConsumerWithDbConn func(*db.Instance, amqp.Delivery) - MessageChannel <-chan amqp.Delivery -) - -const ( - // End consumer of published transactions. Not consumed on blockatlas - TxNotifications Queue = "txNotifications" - // Address:coin subscriptions - Subscriptions Queue = "subscriptions" - // Transactions to process, if match subscriptions, pushed to TxNotifications - RawTransactions Queue = "rawTransactions" - // Token indexer for finding asset association with an address - RawTransactionsSearcher Queue = "rawTransactionsSearcher" - // Token indexer for finding new assets - RawTransactionsTokenIndexer Queue = "rawTransactionsTokenIndexer" - // Register new addresses to observers for token transfers - TokensRegistration Queue = "tokensRegistration" -) - -func Init(uri string) (err error) { - conn, err = amqp.Dial(uri) - if err != nil { - return err - } - amqpChan, err = conn.Channel() - return err -} - -func Close() { - err := amqpChan.Close() - if err != nil { - log.Error(err) - } - - err = conn.Close() - if err != nil { - log.Error(err) - } -} - -func (mc MessageChannel) GetMessage() amqp.Delivery { - return <-mc -} - -func (q Queue) Declare() error { - _, err := amqpChan.QueueDeclare(string(q), true, false, false, false, nil) - return err -} - -func (q Queue) Publish(body []byte) error { - return amqpChan.Publish("", string(q), false, false, amqp.Publishing{ - DeliveryMode: amqp.Persistent, - ContentType: "text/plain", - Body: body, - }) -} - -func RunConsumerForChannelWithCancelAndDbConn(consumer ConsumerWithDbConn, messageChannel MessageChannel, database *db.Instance, concurrent bool, ctx context.Context) { - for { - select { - case <-ctx.Done(): - log.Info("Consumer stopped") - return - case message := <-messageChannel: - if message.Body == nil { - continue - } - if concurrent { - go consumer(database, message) - } else { - consumer(database, message) - } - - } - } -} - -func (q Queue) GetMessageChannel() MessageChannel { - messageChannel, err := amqpChan.Consume( - string(q), - "", - false, - false, - false, - false, - nil, - ) - if err != nil { - log.Fatal("GetMessageChannel MQ issue "+err.Error(), string(q)) - } - - err = amqpChan.Qos( - PrefetchCount, - 0, - true, - ) - if err != nil { - log.Fatal("No qos limit ", err) - } - - return messageChannel -} - -func (q Queue) RunConsumer(consumer Consumer) { - messageChannel := q.GetMessageChannel() - for data := range messageChannel { - go consumer(data) - } -} - -func (q Queue) RunConsumerWithCancel(consumer Consumer, ctx context.Context) { - messageChannel := q.GetMessageChannel() - for { - select { - case <-ctx.Done(): - log.Info("Consumer stopped") - return - case message := <-messageChannel: - if message.Body == nil { - continue - } - go consumer(message) - } - } -} - -func (q Queue) RunConsumerWithCancelAndDbConn(consumer ConsumerWithDbConn, database *db.Instance, ctx context.Context) { - messageChannel := q.GetMessageChannel() - for { - select { - case <-ctx.Done(): - log.Info("Consumer stopped") - return - case message := <-messageChannel: - if message.Body == nil { - continue - } - consumer(database, message) - } - } -} - -func (q Queue) RunConsumerWithCancelAndDbConnConcurrent(consumer ConsumerWithDbConn, database *db.Instance, ctx context.Context) { - messageChannel := q.GetMessageChannel() - for { - select { - case <-ctx.Done(): - log.Info("Consumer stopped") - return - case message := <-messageChannel: - if message.Body == nil { - continue - } - go consumer(database, message) - } - } -} - -func FatalWorker(timeout time.Duration) { - log.Info("Run MQ FatalWorker") - for { - if conn.IsClosed() { - log.Fatal("MQ is not available now") - } - time.Sleep(timeout) - } -} diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go index 0caaaebe9..166114da6 100644 --- a/pkg/blockatlas/observer.go +++ b/pkg/blockatlas/observer.go @@ -21,13 +21,16 @@ type ( Height int64 `json:"height"` Error string `json:"error,omitempty"` } - - Observer struct { - Status bool `json:"status"` - Message string `json:"message"` - } ) +func (v *Subscription) AddressID() string { + return GetAddressID(strconv.Itoa(int(v.Coin)), v.Address) +} + +func GetAddressID(coin, address string) string { + return coin + "_" + address +} + func (e *SubscriptionEvent) ParseSubscriptions(s Subscriptions) []Subscription { subs := make([]Subscription, 0) for coinStr, perCoin := range s { diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 9fdbcde95..9e6797ef4 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -1,11 +1,12 @@ package blockatlas import ( - "github.com/trustwallet/golibs/tokentype" "sort" "strconv" "strings" + "github.com/trustwallet/golibs/tokentype" + mapset "github.com/deckarep/golang-set" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/golibs/asset" @@ -203,6 +204,10 @@ type ( Txs []Tx ) +func (t Token) AssetId() string { + return asset.BuildID(t.Coin, t.TokenID) +} + func (txs Txs) FilterUniqueID() Txs { keys := make(map[string]bool) list := make(Txs, 0) @@ -337,8 +342,6 @@ func (t *Tx) TokenID() (string, bool) { tokenID = t.Meta.(*NativeTokenTransfer).TokenID case TokenTransfer: tokenID = t.Meta.(TokenTransfer).TokenID - case *TokenTransfer: - tokenID = t.Meta.(*TokenTransfer).TokenID case AnyAction: tokenID = t.Meta.(AnyAction).TokenID case *AnyAction: @@ -499,10 +502,12 @@ func (t Tx) AssetModel() (models.Asset, bool) { default: return models.Asset{}, false } - if a.Asset == "" { + a.Coin = t.Coin + + if a.IsValid() != nil { return models.Asset{}, false } - a.Coin = t.Coin + return a, true } diff --git a/platform/binance/client.go b/platform/binance/client.go index eae60f674..1ce3074be 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -9,7 +9,6 @@ import ( "github.com/imroc/req" "github.com/patrickmn/go-cache" - log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -38,8 +37,6 @@ func (c Client) FetchLatestBlockNumber() (int64, error) { } var result NodeInfoResponse if err := resp.ToJSON(&result); err != nil { - log.Error("URL: " + resp.Request().URL.String()) - log.Error("Status code: " + resp.Response().Status) return 0, err } return int64(result.SyncInfo.LatestBlockHeight), nil @@ -52,8 +49,6 @@ func (c Client) FetchTransactionsInBlock(blockNumber int64) (TransactionsInBlock } var result TransactionsInBlockResponse if err := resp.ToJSON(&result); err != nil { - log.Error("URL: " + resp.Request().URL.String()) - log.Error("Status code: " + resp.Response().Status) return TransactionsInBlockResponse{}, err } return result, nil @@ -69,8 +64,6 @@ func (c Client) FetchTransactionsByAddressAndTokenID(address, tokenID string) ([ } var result TransactionsInBlockResponse if err := resp.ToJSON(&result); err != nil { - log.Error("URL: " + resp.Request().URL.String()) - log.Error("Status code: " + resp.Response().Status) return nil, err } return result.Tx, nil @@ -83,8 +76,6 @@ func (c Client) FetchAccountMeta(address string) (AccountMeta, error) { } var result AccountMeta if err := resp.ToJSON(&result); err != nil { - log.Error("URL: " + resp.Request().URL.String()) - log.Error("Status code: " + resp.Response().Status) return AccountMeta{}, err } return result, nil @@ -102,8 +93,6 @@ func (c Client) FetchTokens() (Tokens, error) { return nil, err } if err := resp.ToJSON(&result); err != nil { - log.Error("URL: " + resp.Request().URL.String()) - log.Error("Status code: " + resp.Response().Status) return nil, err } c.Cache.Set("tokens", *result, cache.DefaultExpiration) diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index ee0e05a70..9e702dae1 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -75,7 +75,7 @@ func (p *Platform) getTransactionChannel(id string, txChan chan blockatlas.TxPag func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (blockatlas.TxPage, error) { if receipt.Outputs == nil || len(receipt.Outputs) == 0 { - return blockatlas.TxPage{}, errors.New("NormalizeBlockTransaction: Clauses not found") + return blockatlas.TxPage{}, errors.New("NormalizeBlockTransaction: Clauses not found: " + srcTx.Id) } fee, err := numbers.HexToDecimal(receipt.Paid) diff --git a/services/notifier/base.go b/services/notifier/base.go index 6c0bb20e4..3de2edb6a 100644 --- a/services/notifier/base.go +++ b/services/notifier/base.go @@ -13,13 +13,7 @@ const ( Notifier = "Notifier" ) -func RunNotifier(database *db.Instance, delivery amqp.Delivery) { - defer func() { - if err := delivery.Ack(false); err != nil { - log.WithFields(log.Fields{"service": Notifier}).Error(err) - } - }() - +func RunNotifier(database *db.Instance, delivery amqp.Delivery) error { txs, err := GetTransactionsFromDelivery(delivery, Notifier) if err != nil { log.Error("failed to get transactions", err) @@ -36,26 +30,31 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) { } if len(txs) == 0 { - return + return nil } - subscriptionsDataList, err := database.GetSubscriptionsForNotifications(addresses) - if err != nil || len(subscriptionsDataList) == 0 { - return + subscriptions, err := database.GetSubscriptions(addresses) + if err != nil { + return nil } notifications := make([]TransactionNotification, 0) - for _, sub := range subscriptionsDataList { - ua, _, ok := address.UnprefixedAddress(sub.Address.Address) + for _, sub := range subscriptions { + ua, _, ok := address.UnprefixedAddress(sub.Address) if !ok { continue } notificationsForAddress := buildNotificationsByAddress(ua, txs) notifications = append(notifications, notificationsForAddress...) } + + if len(notifications) == 0 { + return nil + } + err = publishNotifications(notifications) if err != nil { log.WithFields(log.Fields{"service": Notifier}).Error(err) } - log.Info("------------------------------------------------------------") + return nil } diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index 4d3864b7d..5e62c25dd 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -3,9 +3,10 @@ package notifier import ( "encoding/json" + "github.com/trustwallet/blockatlas/internal" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" - "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -26,7 +27,7 @@ func publishNotifications(notifications []TransactionNotification) error { if err != nil { return err } - err = mq.TxNotifications.Publish(raw) + err = internal.TxNotifications.Publish(raw) if err != nil { return err } diff --git a/services/parser/parser.go b/services/parser/parser.go index cf804b8be..d420ff589 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -5,16 +5,19 @@ import ( "encoding/json" "errors" "fmt" + "strconv" "sync/atomic" + "github.com/getsentry/raven-go" + "math/rand" "sort" "sync" "time" "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/network/mq" "github.com/trustwallet/golibs/numbers" log "github.com/sirupsen/logrus" @@ -22,13 +25,10 @@ import ( type ( Params struct { - Ctx context.Context Api blockatlas.BlockAPI - TransactionsQueue mq.Queue - TokenTransactionsQueue []mq.Queue + TransactionsExchange mq.Exchange ParsingBlocksInterval, FetchBlocksTimeout time.Duration - BacklogCount int - MaxBacklogBlocks int64 + MaxBlocks int64 StopChannel chan<- struct{} Database *db.Instance } @@ -40,17 +40,16 @@ type ( } ) -func RunParser(params Params) { +func RunParser(params Params, ctx context.Context) { log.Info("------------------------------------------------------------") for { select { - case <-params.Ctx.Done(): + case <-ctx.Done(): log.Info(fmt.Sprintf("Parser of %s stopped parsing blocks", params.Api.Coin().Handle)) params.StopChannel <- struct{}{} return default: parse(params) - time.Sleep(params.ParsingBlocksInterval) } log.Info("------------------------------------------------------------") } @@ -66,12 +65,20 @@ func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duratio func parse(params Params) { lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params) if err != nil || lastParsedBlock > currentBlock { - log.WithFields(log.Fields{"operation": "fetch GetBlocksIntervalToFetch", "lastParsedBlock": lastParsedBlock, "currentBlock": currentBlock, "coin": params.Api.Coin().Handle}).Error(err) + log.WithFields(log.Fields{ + "operation": "fetch GetBlocksIntervalToFetch", + "coin": params.Api.Coin().Handle, + "tags": raven.Tags{{Key: "coin", Value: params.Api.Coin().Handle}}, + }).Error(err) time.Sleep(params.ParsingBlocksInterval) return } - blocks := FetchBlocks(params, lastParsedBlock, currentBlock) + blocks, err := FetchBlocks(params, lastParsedBlock, currentBlock) + if err != nil { + time.Sleep(params.ParsingBlocksInterval) + return + } err = SaveLastParsedBlock(params, blocks) if err != nil { @@ -89,6 +96,7 @@ func parse(params Params) { publish(params, txs) log.WithFields(log.Fields{ + "coin": params.Api.Coin().Handle, "transactions": len(txs), }).Info("Published transactions") @@ -101,34 +109,45 @@ func GetBlocksIntervalToFetch(params Params) (int64, int64, error) { return 0, 0, errors.New(err.Error() + " Polling failed: tracker didn't return last known block number") } currentBlock, err := params.Api.CurrentBlockNumber() - currentBlock -= params.Api.Coin().MinConfirmations if err != nil { - return 0, 0, errors.New(err.Error() + "Polling failed: source didn't return chain head number") + return 0, 0, errors.New(err.Error() + "Polling failed: source didn't return chain head number. lastParsedBlock: " + strconv.Itoa(int(lastParsedBlock))) } + currentBlock -= params.Api.Coin().MinConfirmations - if currentBlock-lastParsedBlock > int64(params.BacklogCount) { - lastParsedBlock = currentBlock - int64(params.BacklogCount) + return GetNextBlocksToParse(lastParsedBlock, currentBlock, params.MaxBlocks) +} + +func GetNextBlocksToParse(lastParsedBlock int64, currentBlock int64, maxBlocks int64) (int64, int64, error) { + if lastParsedBlock == currentBlock { + return lastParsedBlock, currentBlock, nil + } + if lastParsedBlock > currentBlock { + return lastParsedBlock, lastParsedBlock, nil } - if currentBlock-lastParsedBlock > params.MaxBacklogBlocks { - lastParsedBlock = currentBlock - params.MaxBacklogBlocks + var endParseBlock = currentBlock + var nextBlock = lastParsedBlock + 1 + + if currentBlock-lastParsedBlock > maxBlocks { + endParseBlock = nextBlock + maxBlocks } - return lastParsedBlock, currentBlock, nil + + return nextBlock, endParseBlock + 1, nil } -func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatlas.Block { +func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) ([]blockatlas.Block, error) { if lastParsedBlock == currentBlock { log.WithFields(log.Fields{ - "block": lastParsedBlock, - "coin": params.Api.Coin().Handle, + "current_block": lastParsedBlock, + "coin": params.Api.Coin().Handle, }).Info("No new blocks") - return nil + return nil, errors.New("no new blocks") } blocksCount := currentBlock - lastParsedBlock if blocksCount < 0 { log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error("Current block is 0") - return nil + return nil, errors.New("current block is 0") } var ( @@ -138,7 +157,7 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatla wg sync.WaitGroup ) - for i := lastParsedBlock + 1; i <= currentBlock; i++ { + for i := lastParsedBlock; i <= currentBlock-1; i++ { wg.Add(1) time.Sleep(params.FetchBlocksTimeout) go func(i int64, wg *sync.WaitGroup) { @@ -166,19 +185,19 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) []blockatla log.WithFields(log.Fields{"coin": params.Api.Coin().Handle, "count": len(errorsList), "blocks": errorsList}).Error("Fetch blocks errors") } - blocksList := make([]blockatlas.Block, 0, len(blocksChan)) + blocks := make([]blockatlas.Block, 0, len(blocksChan)) for block := range blocksChan { - blocksList = append(blocksList, block) + blocks = append(blocks, block) } log.WithFields(log.Fields{ "from": lastParsedBlock, - "to": currentBlock, + "to": currentBlock - 1, "total": totalCount, "coin": params.Api.Coin().Handle}, ).Info("Fetched blocks batch") - return blocksList + return blocks, nil } func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas.Block) error { @@ -232,37 +251,11 @@ func publish(params Params, txs blockatlas.Txs) { } // Notify transactions queue - err = params.TransactionsQueue.Publish(body) + err = params.TransactionsExchange.Publish(body) if err != nil { log.WithFields(log.Fields{"operation": "publish transactionsQueue", "coin": params.Api.Coin().Handle}).Error(err) return } - - // Notify token transfers queue, if conforms to TokensAPI protocol - tokenTransfers := txs.FilterTransactionsByType([]blockatlas.TransactionType{ - blockatlas.TxTokenTransfer, - blockatlas.TxNativeTokenTransfer, - }) - - if len(tokenTransfers) == 0 { - return - } - - tokenTransfersBody, err := json.Marshal(tokenTransfers) - if err != nil { - log.WithFields(log.Fields{"operation": "marshal tokenTransfers", "coin": params.Api.Coin().Handle}).Error(err) - return - } - - if _, ok := params.Api.(blockatlas.TokensAPI); ok { - for _, q := range params.TokenTransactionsQueue { - err = q.Publish(tokenTransfersBody) - if err != nil { - log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Error(err) - return - } - } - } } func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64, symbol string) (*blockatlas.Block, error) { diff --git a/services/parser/parser_test.go b/services/parser/parser_test.go index a00d72860..8b3b70922 100644 --- a/services/parser/parser_test.go +++ b/services/parser/parser_test.go @@ -6,7 +6,6 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/mq" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" ) @@ -17,19 +16,17 @@ var ( func TestFetchBlocks(t *testing.T) { params := Params{ - Ctx: nil, - Api: getMockedBlockAPI(), - TransactionsQueue: "", - TokenTransactionsQueue: []mq.Queue{""}, - ParsingBlocksInterval: 0, - FetchBlocksTimeout: 0, - BacklogCount: 0, - MaxBacklogBlocks: 0, - StopChannel: nil, - Database: nil, + Api: getMockedBlockAPI(), + TransactionsExchange: "", + ParsingBlocksInterval: 0, + FetchBlocksTimeout: 0, + MaxBlocks: 0, + StopChannel: nil, + Database: nil, } - blocks := FetchBlocks(params, 0, 100) + blocks, err := FetchBlocks(params, 0, 100) assert.Equal(t, len(blocks), 100) + assert.Nil(t, err) } func TestParser_getBlockByNumberWithRetry(t *testing.T) { @@ -134,3 +131,89 @@ func TestGetInterval(t *testing.T) { }) } } + +func TestGetNextBlocksToParse(t *testing.T) { + type args struct { + lastParsedBlock int64 + currentBlock int64 + maxBlocks int64 + } + tests := []struct { + name string + args args + want int64 + want1 int64 + wantErr bool + }{ + { + "Test behind blocks", + args{ + lastParsedBlock: 10, + currentBlock: 25, + maxBlocks: 3, + }, + 11, + 15, + false, + }, + { + "Test when only 1 block to parse", + args{ + lastParsedBlock: 10, + currentBlock: 13, + maxBlocks: 5, + }, + 11, + 14, + false, + }, + { + "Test same block", + args{ + lastParsedBlock: 10, + currentBlock: 10, + maxBlocks: 3, + }, + 10, + 10, + false, + }, + { + "Last parsed block ahead", + args{ + lastParsedBlock: 15, + currentBlock: 10, + maxBlocks: 3, + }, + 15, + 15, + false, + }, + { + "Parse last block", + args{ + lastParsedBlock: 15, + currentBlock: 15, + maxBlocks: 3, + }, + 15, + 15, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1, err := GetNextBlocksToParse(tt.args.lastParsedBlock, tt.args.currentBlock, tt.args.maxBlocks) + if (err != nil) != tt.wantErr { + t.Errorf("GetNextBlocksToParse() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("GetNextBlocksToParse() got = %v, want %v", got, tt.want) + } + if got1 != tt.want1 { + t.Errorf("GetNextBlocksToParse() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} diff --git a/services/subscriber/subscriber.go b/services/subscriber/subscriber.go new file mode 100644 index 000000000..98d91ffd7 --- /dev/null +++ b/services/subscriber/subscriber.go @@ -0,0 +1,55 @@ +package subscriber + +import ( + "encoding/json" + + "github.com/trustwallet/blockatlas/internal" + + log "github.com/sirupsen/logrus" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/pkg/blockatlas" +) + +type Subscriber string + +const ( + Notifications Subscriber = "notifications" + AddSubscription blockatlas.SubscriptionOperation = "AddSubscription" + DeleteSubscription blockatlas.SubscriptionOperation = "DeleteSubscription" +) + +func RunSubscriber(database *db.Instance, delivery amqp.Delivery) error { + var event blockatlas.SubscriptionEvent + err := json.Unmarshal(delivery.Body, &event) + if err != nil { + log.WithFields(log.Fields{"service": Notifications, "event": event}).Error(err) + return err + } + + subscriptions := event.ParseSubscriptions(event.Subscriptions) + switch event.Operation { + case AddSubscription: + err := database.CreateSubscriptions(subscriptions) + if err != nil { + log.WithFields(log.Fields{"service": Notifications, "operation": event.Operation, "subscriptions": len(subscriptions)}).Error(err) + return err + } + log.WithFields(log.Fields{"service": Notifications, "operation": event.Operation, "subscriptions": len(subscriptions)}).Info("Add subscriptions") + case DeleteSubscription: + subscriptionsIds := make([]string, 0) + for _, subscription := range subscriptions { + subscriptionsIds = append(subscriptionsIds, subscription.AddressID()) + } + return database.DeleteSubscriptions(subscriptionsIds) + } + + // Pass over subscribed addresses to find all associated tokens to such addresses + err = internal.SubscriptionsTokens.Publish(delivery.Body) + if err != nil { + log.Error(err) + return nil + } + + return nil +} diff --git a/services/subscriber/tokens.go b/services/subscriber/tokens.go deleted file mode 100644 index 6b95a686c..000000000 --- a/services/subscriber/tokens.go +++ /dev/null @@ -1,32 +0,0 @@ -package subscriber - -import ( - "encoding/json" - - log "github.com/sirupsen/logrus" - "github.com/streadway/amqp" - "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/db/models" -) - -const Tokens Subscriber = "tokens" - -func RunTokensSubscriber(database *db.Instance, delivery amqp.Delivery) { - event := make(map[string][]models.Asset) - if err := json.Unmarshal(delivery.Body, &event); err != nil { - if err := delivery.Ack(false); err != nil { - log.WithFields(log.Fields{"service": Tokens}).Error(err) - } - } - - for address, assets := range event { - if err := database.AddAssociationsForAddress(address, assets); err != nil { - log.Error("Failed to AddAssociationsForAddress: " + err.Error()) - } - } - log.WithFields(log.Fields{"service": Tokens, "count": len(event)}).Info("Subscribed") - if err := delivery.Ack(false); err != nil { - log.WithFields(log.Fields{"service": Tokens}).Error(err) - } - log.Info("------------------------------------------------------------") -} diff --git a/services/subscriber/transactions.go b/services/subscriber/transactions.go deleted file mode 100644 index f9cc7bfab..000000000 --- a/services/subscriber/transactions.go +++ /dev/null @@ -1,112 +0,0 @@ -package subscriber - -import ( - "encoding/json" - "strconv" - - log "github.com/sirupsen/logrus" - "github.com/streadway/amqp" - "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) - -type Subscriber string - -const ( - Notifications Subscriber = "notifications" - AddSubscription blockatlas.SubscriptionOperation = "AddSubscription" - DeleteSubscription blockatlas.SubscriptionOperation = "DeleteSubscription" - UpdateSubscription blockatlas.SubscriptionOperation = "UpdateSubscription" - - batchLimit uint = 3000 -) - -func RunTransactionsSubscriber(database *db.Instance, delivery amqp.Delivery) { - var event blockatlas.SubscriptionEvent - err := json.Unmarshal(delivery.Body, &event) - if err != nil { - return - } - - subscriptions := event.ParseSubscriptions(event.Subscriptions) - switch event.Operation { - case AddSubscription, UpdateSubscription: - allSubs := ToSubscriptionData(subscriptions) - batchedSubs := toBatch(allSubs, batchLimit) - for _, subs := range batchedSubs { - err := database.AddSubscriptionsForNotifications(subs) - if err != nil { - log.WithFields( - log.Fields{"service": Notifications, - "operation": event.Operation, - "subscriptions_len": len(subscriptions), - }, - ).Error(err) - } - } - - log.WithFields( - log.Fields{"service": Notifications, - "operation": event.Operation, - "subscriptions_len": len(subscriptions), - }, - ).Info("Added") - case DeleteSubscription: - allSubs := ToSubscriptionData(subscriptions) - batchedSubs := toBatch(allSubs, batchLimit) - for _, subs := range batchedSubs { - err := database.DeleteSubscriptionsForNotifications(subs) - if err != nil { - log.WithFields( - log.Fields{"service": Notifications, - "operation": event.Operation, - "subscriptions_len": len(subscriptions), - }, - ).Error(err) - } - } - log.WithFields( - log.Fields{"service": Notifications, - "operation": event.Operation, - "subscriptions_len": len(subscriptions), - }, - ).Info("Added") - } - - defer func() { - err = delivery.Ack(false) - if err != nil { - log.WithFields( - log.Fields{"service": Notifications, - "operation": event.Operation, - "subscriptions_len": len(subscriptions), - }, - ).Error(err) - } - }() -} - -func ToSubscriptionData(sub []blockatlas.Subscription) []string { - data := make([]string, 0, len(sub)) - for _, s := range sub { - coinStr := strconv.FormatUint(uint64(s.Coin), 10) - address := coinStr + "_" + s.Address - data = append(data, address) - } - return data -} - -func toBatch(subs []string, sizeUint uint) [][]string { - size := int(sizeUint) - resultLength := (len(subs) + size - 1) / size - result := make([][]string, resultLength) - lo, hi := 0, size - for i := range result { - if hi > len(subs) { - hi = len(subs) - } - result[i] = subs[lo:hi:hi] - lo, hi = hi, hi+size - } - return result -} diff --git a/services/subscriber/transactions_test.go b/services/subscriber/transactions_test.go deleted file mode 100644 index ab27df743..000000000 --- a/services/subscriber/transactions_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package subscriber - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" -) - -func TestToSubscriptionData(t *testing.T) { - sub := blockatlas.Subscription{ - Coin: 60, - Address: "A", - } - sub2 := blockatlas.Subscription{ - Coin: 60, - Address: "B", - } - - expected := "60_A" - expected1 := "60_B" - res := ToSubscriptionData([]blockatlas.Subscription{sub, sub2}) - assert.Equal(t, 2, len(res)) - assert.Equal(t, expected, res[0]) - assert.Equal(t, expected1, res[1]) -} diff --git a/services/tokenindexer/api.go b/services/tokenindexer/api.go index 87d8690c6..3b9852a44 100644 --- a/services/tokenindexer/api.go +++ b/services/tokenindexer/api.go @@ -3,6 +3,8 @@ package tokenindexer import ( "time" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" ) @@ -17,13 +19,36 @@ func Init(database *db.Instance) Instance { func (i Instance) HandleNewTokensRequest(r Request) (Response, error) { from := time.Unix(r.From, 0) - result, err := i.database.GetAssetsFrom(from, r.Coin) + result, err := i.database.GetAssetsFrom(from) if err != nil { return Response{}, err } return normalize(result), nil } +func (i Instance) GetTokensByAddress(r GetTokensByAddressRequest) (GetTokensByAddressResponse, error) { + list := make([]string, 0) + + for coin, coins := range r.AddressesByCoin { + for _, address := range coins { + list = append(list, blockatlas.GetAddressID(coin, address)) + } + } + from := time.Unix(int64(r.From), 0) + associations, err := i.database.GetSubscriptionsByAddressIDs(list, from) + if err != nil { + return GetTokensByAddressResponse{}, err + } + + assetIds := make([]string, 0) + + for _, association := range associations { + assetIds = append(assetIds, association.Asset.Asset) + } + + return assetIds, nil +} + func normalize(dbAssets []models.Asset) Response { var result []Asset for _, a := range dbAssets { diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index 7bcf5fa43..e8de8b150 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -1,6 +1,8 @@ package tokenindexer import ( + "strconv" + log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" @@ -9,47 +11,131 @@ import ( "github.com/trustwallet/blockatlas/services/notifier" ) -const TokenIndexer = "TokenIndexer" - -func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) { - defer func() { - if err := delivery.Ack(false); err != nil { - log.WithFields(log.Fields{"service": TokenIndexer}).Error(err) - } - }() +const ( + TokenIndexer = "TokenIndexer" + SubscriptionsTokenIndexer = "SubscriptionsTokenIndexer" +) +func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) error { txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenIndexer) if err != nil { log.WithFields(log.Fields{"service": TokenIndexer}).Error("failed to get transactions", err) - if err := delivery.Ack(false); err != nil { - log.WithFields(log.Fields{"service": TokenIndexer}).Error(err) - } - return + return err } + txs = txs.FilterTransactionsByType([]blockatlas.TransactionType{ + blockatlas.TxTokenTransfer, + blockatlas.TxNativeTokenTransfer, + }) + if len(txs) == 0 { - return + return nil } + // Add new assets to db + assets := GetAssetsFromTransactions(txs) err = database.AddNewAssets(assets) if err != nil { - log.WithFields(log.Fields{"service": TokenIndexer}).Error("failed to add assets", err) - return + log.WithFields(log.Fields{"service": TokenIndexer}).Error("Failed to add new assets", err) + return err + } + + // Add asset <> address association + addressAssetsMap := assetsMap(txs) + + return CreateAssociations(database, addressAssetsMap) +} + +func CreateAssociations(database *db.Instance, addressAssetsMap map[string][]string) error { + associations, err := calculateSubscriptionAssetAssociations(database, addressAssetsMap) + if err != nil { + return err + } + return database.CreateSubscriptionsAssets(associations) +} + +func calculateSubscriptionAssetAssociations(database *db.Instance, addressAssetsMap map[string][]string) ([]models.SubscriptionsAssetAssociation, error) { + associations := make([]models.SubscriptionsAssetAssociation, 0) + + addressIds := make([]string, 0) + assetIds := make([]string, 0) + for addressId, assets := range addressAssetsMap { + addressIds = append(addressIds, addressId) + + assetIds = append(assetIds, assets...) + } + + if len(addressIds) == 0 || len(assetIds) == 0 { + return associations, nil + } + + subscriptions, err := database.GetSubscriptions(addressIds) + if err != nil { + return associations, err + } + + assets, err := database.GetAssetsByIDs(assetIds) + if err != nil { + return associations, err + } + + assetsMap := map[string]models.Asset{} + for _, asset := range assets { + assetsMap[asset.Asset] = asset + } + + subscriptionsMap := map[string]models.Subscription{} + for _, subscription := range subscriptions { + subscriptionsMap[subscription.Address] = subscription + } + + for addressId, assets := range addressAssetsMap { + subscription, ok := subscriptionsMap[addressId] + if !ok { + continue + } + + for _, assetId := range assets { + asset, ok := assetsMap[assetId] + if !ok { + continue + } + association := models.SubscriptionsAssetAssociation{ + SubscriptionId: subscription.ID, + AssetId: asset.ID, + } + associations = append(associations, association) + } } - log.Info("------------------------------------------------------------") + + return associations, nil } func GetAssetsFromTransactions(txs []blockatlas.Tx) []models.Asset { - var result []models.Asset + var assets []models.Asset for _, tx := range txs { - a, ok := tx.AssetModel() + asset, ok := tx.AssetModel() if !ok { continue } - if a.Asset == "" { + assets = append(assets, asset) + } + return assets +} + +func assetsMap(txs blockatlas.Txs) map[string][]string { + result := make(map[string][]string) + for _, tx := range txs { + prefix := strconv.Itoa(int(tx.Coin)) + "_" + addresses := tx.GetAddresses() + asset, ok := tx.AssetModel() + if !ok { continue } - result = append(result, a) + for _, address := range addresses { + assetIDs := result[prefix+address] + result[prefix+address] = append(assetIDs, asset.Asset) + } } return result } diff --git a/services/tokenindexer/indexer_subscribe.go b/services/tokenindexer/indexer_subscribe.go new file mode 100644 index 000000000..5a97612b8 --- /dev/null +++ b/services/tokenindexer/indexer_subscribe.go @@ -0,0 +1,58 @@ +package tokenindexer + +import ( + "encoding/json" + + log "github.com/sirupsen/logrus" + "github.com/streadway/amqp" + "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/subscriber" +) + +type ConsumerIndexer struct { + Database *db.Instance + TokensAPIs map[uint]blockatlas.TokensAPI + Delivery func(*db.Instance, map[uint]blockatlas.TokensAPI, amqp.Delivery) error +} + +func (c ConsumerIndexer) Callback(msg amqp.Delivery) error { + return c.Delivery(c.Database, c.TokensAPIs, msg) +} + +func RunTokenIndexerSubscribe(database *db.Instance, apis map[uint]blockatlas.TokensAPI, delivery amqp.Delivery) error { + var event blockatlas.SubscriptionEvent + err := json.Unmarshal(delivery.Body, &event) + if err != nil { + log.WithFields(log.Fields{"service": SubscriptionsTokenIndexer, "event": event}).Error(err) + return err + } + + subscriptions := event.ParseSubscriptions(event.Subscriptions) + switch event.Operation { + case subscriber.AddSubscription: + addressAssetsMap := map[string][]string{} + + for _, coinAddress := range subscriptions { + api, ok := apis[coinAddress.Coin] + if !ok { + continue + } + assets, err := api.GetTokenListByAddress(coinAddress.Address) + if err != nil { + continue + } + assetIds := make([]string, 0) + for _, asset := range assets { + assetIds = append(assetIds, asset.AssetId()) + } + addressAssetsMap[coinAddress.AddressID()] = assetIds + } + return CreateAssociations(database, addressAssetsMap) + case subscriber.DeleteSubscription: + //No action is needed + break + } + + return nil +} diff --git a/services/tokenindexer/models.go b/services/tokenindexer/models.go index a2852b29d..0b9fc3b45 100644 --- a/services/tokenindexer/models.go +++ b/services/tokenindexer/models.go @@ -1,9 +1,17 @@ package tokenindexer -type Request struct { - From int64 - Coin int -} +type ( + Request struct { + From int64 + } + + GetTokensByAddressRequest struct { + AddressesByCoin map[string][]string `json:"addresses"` + From uint `json:"from"` + } + + GetTokensByAddressResponse []string +) type Response struct { Assets []Asset `json:"assets"` diff --git a/services/tokensearcher/api.go b/services/tokensearcher/api.go deleted file mode 100644 index 2d776fa38..000000000 --- a/services/tokensearcher/api.go +++ /dev/null @@ -1,194 +0,0 @@ -package tokensearcher - -import ( - "encoding/json" - "strconv" - "sync" - "time" - - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/address" - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) - -type ( - AddressesByCoin map[uint][]string - AssetsByAddress map[string][]models.Asset - Request struct { - AddressesByCoin map[string][]string `json:"addresses"` - From uint `json:"from"` - } -) - -type Instance struct { - database *db.Instance - apis map[uint]blockatlas.TokensAPI - queue mq.Queue -} - -func Init(database *db.Instance, apis map[uint]blockatlas.TokensAPI, queue mq.Queue) Instance { - return Instance{database: database, apis: apis, queue: queue} -} - -func (i Instance) HandleTokensRequest(request Request) (map[string][]string, error) { - addresses := getAddressesFromRequest(request) - if len(addresses) == 0 { - return nil, nil - } - - subscribedAddresses, err := getSubscribedAddresses(i.database, addresses) - if err != nil { - return nil, err - } - log.Info("subscribedAddresses " + strconv.Itoa(len(subscribedAddresses))) - unsubscribedAddresses := getUnsubscribedAddresses(subscribedAddresses, addresses) - - log.Info("unsubscribedAddresses " + strconv.Itoa(len(unsubscribedAddresses))) - assetsFromDB, err := i.database.GetAssetsMapByAddressesFromTime(subscribedAddresses, time.Unix(int64(request.From), 0)) - if err != nil { - return nil, err - } - - log.Info("assetsFromDB " + strconv.Itoa(len(assetsFromDB))) - assetsFromNodes := make(AssetsByAddress) - if len(unsubscribedAddresses) != 0 { - assetsFromNodes = getAssetsByAddressFromNodes(unsubscribedAddresses, i.apis) - err = publishNewAddressesToQueue(i.queue, assetsFromNodes) - if err != nil { - log.Error(err) - } - } - - return getAssetsToResponse(assetsFromDB, assetsFromNodes, addresses), nil -} - -func getSubscribedAddresses(database *db.Instance, addresses []string) ([]string, error) { - subscribedAddressesModel, err := database.GetSubscribedAddressesForAssets(addresses) - if err != nil { - return nil, err - } - - subscribedAddresses := make([]string, 0, len(subscribedAddressesModel)) - for _, a := range subscribedAddressesModel { - subscribedAddresses = append(subscribedAddresses, a.Address) - } - return subscribedAddresses, nil -} - -func getAddressesFromRequest(request Request) []string { - var addresses []string - for coinID, requestAddresses := range request.AddressesByCoin { - for _, a := range requestAddresses { - addresses = append(addresses, coinID+"_"+a) - } - } - return addresses -} - -func getUnsubscribedAddresses(subscribed []string, all []string) AddressesByCoin { - addressesByCoin := make(AddressesByCoin) - subscribedMap := make(map[string]bool) - for _, a := range subscribed { - subscribedMap[a] = true - } - for _, a := range all { - _, ok := subscribedMap[a] - if !ok { - ua, coinID, ok := address.UnprefixedAddress(a) - if !ok { - continue - } - currentAddresses := addressesByCoin[coinID] - addressesByCoin[coinID] = append(currentAddresses, ua) - } - } - return addressesByCoin -} - -func getAddressesToRegisterByCoin(assetsByAddresses AssetsByAddress, addresses []string) AddressesByCoin { - addressesByCoin := make(AddressesByCoin) - addressesFromRequestMap := make(map[string]bool) - for _, a := range addresses { - addressesFromRequestMap[a] = true - } - for _, a := range addresses { - _, ok := assetsByAddresses[a] - if !ok { - ua, coinID, ok := address.UnprefixedAddress(a) - if !ok { - continue - } - currentAddresses := addressesByCoin[coinID] - addressesByCoin[coinID] = append(currentAddresses, ua) - } - } - return addressesByCoin -} - -func getAssetsByAddressFromNodes(addressesByCoin AddressesByCoin, apis map[uint]blockatlas.TokensAPI) AssetsByAddress { - a := NodesResponse{AssetsByAddress: make(AssetsByAddress)} - var wg sync.WaitGroup - for coinID, addresses := range addressesByCoin { - api, ok := apis[coinID] - if !ok { - continue - } - wg.Add(1) - go fetchAssetsByAddresses(api, addresses, &a, &wg) - } - wg.Wait() - return a.AssetsByAddress -} - -func fetchAssetsByAddresses(tokenAPI blockatlas.TokensAPI, addresses []string, result *NodesResponse, wg *sync.WaitGroup) { - defer wg.Done() - - var tWg sync.WaitGroup - tWg.Add(len(addresses)) - for _, a := range addresses { - go func(address string, tWg *sync.WaitGroup) { - defer tWg.Done() - tokens, err := tokenAPI.GetTokenListByAddress(address) - if err != nil { - log.WithFields(log.Fields{ - "coin": tokenAPI.Coin().Handle, - "address": address, - "error": err, - }).Error("Fetch GetTokenListByAddress for: ", tokenAPI.Coin().Handle) - return - } - result.UpdateAssetsByAddress(tokens, int(tokenAPI.Coin().ID), address) - }(a, &tWg) - } - tWg.Wait() -} - -func publishNewAddressesToQueue(queue mq.Queue, message AssetsByAddress) error { - log.Info("Published to queue") - body, err := json.Marshal(message) - log.Info(string(body)) - if err != nil { - return err - } - return queue.Publish(body) -} - -func getAssetsToResponse(dbAssetsMap, nodesAssetsMap AssetsByAddress, addresses []string) map[string][]string { - result := make(map[string][]string) - for _, address := range addresses { - dbAddresses, ok := dbAssetsMap[address] - if !ok { - nodesAssets, ok := nodesAssetsMap[address] - if !ok { - continue - } - result[address] = models.AssetIDs(nodesAssets) - continue - } - result[address] = models.AssetIDs(dbAddresses) - } - return result -} diff --git a/services/tokensearcher/api_test.go b/services/tokensearcher/api_test.go deleted file mode 100644 index ec80ac330..000000000 --- a/services/tokensearcher/api_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package tokensearcher - -import ( - "errors" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/coin" - "testing" -) - -func Test_getAddressesFromRequest(t *testing.T) { - request := Request{ - AddressesByCoin: make(map[string][]string), - From: 0, - } - request.AddressesByCoin["60"] = []string{"1", "2", "3"} - r := getAddressesFromRequest(request) - assert.Equal(t, []string{"60_1", "60_2", "60_3"}, r) -} - -func Test_getUnsubscribedAddresses(t *testing.T) { - r := getUnsubscribedAddresses([]string{"60_1"}, []string{"60_1", "714_2", "714_22", "118_3"}) - assert.Equal(t, []string{"2", "22"}, r[714]) - assert.Equal(t, []string{"3"}, r[118]) -} - -func Test_getAddressesToRegisterByCoin(t *testing.T) { - addressFromDB := make(map[string][]models.Asset) - addressFromDB["60_a"] = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} - addressFromDB["714_b"] = []models.Asset{{Asset: "1"}, {Asset: "3"}} - - addressesFromRequest := []string{"60_a", "714_b", "118_c"} - result := getAddressesToRegisterByCoin(addressFromDB, addressesFromRequest) - - c, ok := result[118] - assert.True(t, ok) - assert.Equal(t, []string{"c"}, c) -} - -func Test_getAssetsToResponse(t *testing.T) { - addressFromDB := make(map[string][]models.Asset) - addressFromDB["60_a"] = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} - addressFromDB["714_b"] = []models.Asset{{Asset: "1"}, {Asset: "3"}} - - addressFromNodes := make(map[string][]models.Asset) - addressFromNodes["118_c"] = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} - - addressesFromRequest := []string{"60_a", "714_b", "118_c"} - - result := getAssetsToResponse(addressFromDB, addressFromNodes, addressesFromRequest) - assert.NotNil(t, result) - - assert.Equal(t, []string{"1", "2", "3"}, result["60_a"]) - assert.Equal(t, []string{"1", "3"}, result["714_b"]) - assert.Equal(t, []string{"1", "2", "3"}, result["118_c"]) -} - -func Test_getAssetsForAddressesFromNodes(t *testing.T) { - apis := make(map[uint]blockatlas.TokensAPI) - mock0 := mockedTokenAPI{WantedToken: "ABC", WantedCoin: 0} - mock60 := mockedTokenAPI{WantedToken: "XYZ", WantedCoin: 60} - apis[0] = mock0 - apis[60] = mock60 - - addresses := make(map[uint][]string) - addresses[0] = []string{"A", "B", "C"} - addresses[60] = []string{"X", "Y", "Z"} - result := getAssetsByAddressFromNodes(addresses, apis) - assert.NotNil(t, result) -} - -type mockedTokenAPI struct { - WantedCoin uint - WantedToken string -} - -func (m mockedTokenAPI) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { - if address == "Y" { - return nil, errors.New("failed") - } - tk := blockatlas.Token{ - Name: "", - Symbol: "", - Decimals: 0, - TokenID: m.WantedToken, - Coin: m.WantedCoin, - Type: "", - } - return blockatlas.TokenPage{tk}, nil -} -func (m mockedTokenAPI) Coin() coin.Coin { - return coin.Coin{ID: m.WantedCoin} -} diff --git a/services/tokensearcher/association.go b/services/tokensearcher/association.go deleted file mode 100644 index de61ed3d8..000000000 --- a/services/tokensearcher/association.go +++ /dev/null @@ -1,60 +0,0 @@ -package tokensearcher - -import ( - "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "strings" -) - -func assetsMap(txs blockatlas.Txs, coinID string) map[string][]models.Asset { - result := make(map[string][]models.Asset) - prefix := coinID + "_" - for _, tx := range txs { - addresses := tx.GetAddresses() - asset, ok := tx.AssetModel() - if !ok { - continue - } - for _, a := range addresses { - assetIDs := result[prefix+a] - result[prefix+a] = append(assetIDs, asset) - } - } - return result -} - -func associationsToAdd(oldAssociations map[string][]models.Asset, newAssociations map[string][]models.Asset) map[string][]models.Asset { - result := make(map[string][]models.Asset) - for oldAddresses, oldAssets := range oldAssociations { - for newAddresses, newAssets := range newAssociations { - if strings.EqualFold(oldAddresses, newAddresses) { - m := result[newAddresses] - result[newAddresses] = append(m, newAssociationsForAddress(oldAssets, newAssets)...) - } - } - } - return result -} - -func newAssociationsForAddress(oldAssociations []models.Asset, newAssociations []models.Asset) []models.Asset { - var result []models.Asset - oldM := make(map[string]bool) - for _, o := range oldAssociations { - oldM[o.Asset] = true - } - for _, n := range newAssociations { - if ok := oldM[n.Asset]; !ok { - result = append(result, n) - } - } - return result -} - -func fromModelToAssociation(associations []models.AddressToAssetAssociation) map[string][]models.Asset { - result := make(map[string][]models.Asset) - for _, a := range associations { - m := result[a.Address.Address] - result[a.Address.Address] = append(m, a.Asset) - } - return result -} diff --git a/services/tokensearcher/association_test.go b/services/tokensearcher/association_test.go deleted file mode 100644 index 5d3bb4298..000000000 --- a/services/tokensearcher/association_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package tokensearcher - -import ( - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" -) - -func Test_assetsMap(t *testing.T) { - tx1 := blockatlas.Tx{ - Coin: 60, - From: "A", - To: "B", - Meta: blockatlas.NativeTokenTransfer{ - TokenID: "ABC", - From: "A", - To: "C", - }, - } - - tx2 := blockatlas.Tx{ - Coin: 60, - From: "D", - To: "V", - Meta: blockatlas.TokenTransfer{ - TokenID: "EFG", - From: "D", - To: "F", - }, - } - - tx3 := blockatlas.Tx{ - Coin: 60, - From: "Q", - To: "L", - Meta: blockatlas.AnyAction{ - TokenID: "HIJ", - }, - } - - result := assetsMap(blockatlas.Txs{tx1, tx2, tx3}, "60") - assert.Equal(t, result["60_A"], []models.Asset{{Asset: "c60_tABC", Type: "ERC20", Coin: 60}}) - assert.Equal(t, result["60_C"], []models.Asset{{Asset: "c60_tABC", Type: "ERC20", Coin: 60}}) - assert.Equal(t, result["60_D"], []models.Asset{{Asset: "c60_tEFG", Type: "ERC20", Coin: 60}}) - assert.Equal(t, result["60_F"], []models.Asset{{Asset: "c60_tEFG", Type: "ERC20", Coin: 60}}) - assert.Equal(t, result["60_Q"], []models.Asset{{Asset: "c60_tHIJ", Type: "ERC20", Coin: 60}}) - assert.Equal(t, result["60_L"], []models.Asset{{Asset: "c60_tHIJ", Type: "ERC20", Coin: 60}}) -} - -func Test_associationsToAdd(t *testing.T) { - o := make(map[string][]models.Asset) - n := make(map[string][]models.Asset) - - o["A"] = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} - o["B"] = []models.Asset{{Asset: "3"}, {Asset: "4"}, {Asset: "5"}} - - n["A"] = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "5"}} - n["B"] = []models.Asset{{Asset: "3"}, {Asset: "9"}, {Asset: "8"}} - - result := associationsToAdd(o, n) - - assert.Equal(t, result["A"], []models.Asset{{Asset: "5"}}) - assert.Equal(t, result["B"], []models.Asset{{Asset: "9"}, {Asset: "8"}}) -} - -func Test_newAssociationsForAddress(t *testing.T) { - o := []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} - n := []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}, {Asset: "4"}, {Asset: "5"}} - - result := newAssociationsForAddress(o, n) - assert.Equal(t, result, []models.Asset{{Asset: "4"}, {Asset: "5"}}) - - o = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} - n = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} - - result = newAssociationsForAddress(o, n) - assert.Equal(t, len(result), len([]string{})) - - o = []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}} - n = []models.Asset{{Asset: "1"}, {Asset: "2"}} - - result = newAssociationsForAddress(o, n) - assert.Equal(t, len(result), len([]string{})) -} - -func Test_fromModelToAssociation(t *testing.T) { - a := []models.AddressToAssetAssociation{ - {Address: models.Address{Address: "A"}, Asset: models.Asset{Asset: "1"}}, - {Address: models.Address{Address: "A"}, Asset: models.Asset{Asset: "2"}}, - {Address: models.Address{Address: "A"}, Asset: models.Asset{Asset: "3"}}, - {Address: models.Address{Address: "B"}, Asset: models.Asset{Asset: "2"}}, - {Address: models.Address{Address: "B"}, Asset: models.Asset{Asset: "3"}}, - {Address: models.Address{Address: "B"}, Asset: models.Asset{Asset: "4"}}, - } - - result := fromModelToAssociation(a) - assert.Equal(t, result["A"], []models.Asset{{Asset: "1"}, {Asset: "2"}, {Asset: "3"}}) - assert.Equal(t, result["B"], []models.Asset{{Asset: "2"}, {Asset: "3"}, {Asset: "4"}}) -} diff --git a/services/tokensearcher/models.go b/services/tokensearcher/models.go deleted file mode 100644 index 04a8e42b4..000000000 --- a/services/tokensearcher/models.go +++ /dev/null @@ -1,33 +0,0 @@ -package tokensearcher - -import ( - "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/address" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/asset" - "sync" -) - -type NodesResponse struct { - sync.Mutex - AssetsByAddress AssetsByAddress -} - -func (nr *NodesResponse) UpdateAssetsByAddress(tokens blockatlas.TokenPage, coin int, a string) { - nr.Lock() - for _, t := range tokens { - key := address.PrefixedAddress(uint(coin), a) - r := nr.AssetsByAddress[key] - nr.AssetsByAddress[key] = append(r, - models.Asset{ - Asset: asset.BuildID(t.Coin, t.TokenID), - Decimals: t.Decimals, - Name: t.Name, - Symbol: t.Symbol, - Type: string(t.Type), - ID: t.Coin, - }, - ) - } - nr.Unlock() -} diff --git a/services/tokensearcher/tokensearcher.go b/services/tokensearcher/tokensearcher.go deleted file mode 100644 index 84bc3a38c..000000000 --- a/services/tokensearcher/tokensearcher.go +++ /dev/null @@ -1,56 +0,0 @@ -package tokensearcher - -import ( - "strconv" - - log "github.com/sirupsen/logrus" - "github.com/streadway/amqp" - "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/services/notifier" -) - -const TokenSearcher = "TokenSearcher" - -func Run(database *db.Instance, delivery amqp.Delivery) { - txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenSearcher) - if err != nil { - log.Error("failed to get transactions", err) - if err := delivery.Ack(false); err != nil { - log.WithFields(log.Fields{"service": TokenSearcher}).Error(err) - } - } - if len(txs) == 0 { - return - } - coinID := strconv.Itoa(int(txs[0].Coin)) - var addresses []string - for _, tx := range txs { - addresses = append(addresses, tx.GetAddresses()...) - } - for i := range addresses { - addresses[i] = coinID + "_" + addresses[i] - } - - associationsFromTransactions, err := database.GetAssociationsByAddresses(notifier.ToUniqueAddresses(addresses)) - if err != nil { - log.Error(err) - return - } - log.WithFields(log.Fields{"service": TokenSearcher}). - Info("AssociationsFromTransactions " + strconv.Itoa(len(associationsFromTransactions))) - - associationsToAdd := associationsToAdd(fromModelToAssociation(associationsFromTransactions), assetsMap(txs, coinID)) - - log.WithFields(log.Fields{"service": TokenSearcher}). - Info("AssociationsToAdd " + strconv.Itoa(len(associationsToAdd))) - err = database.UpdateAssociationsForExistingAddresses(associationsToAdd) - if err != nil { - log.Error(err) - return - } - - if err := delivery.Ack(false); err != nil { - log.WithFields(log.Fields{"service": TokenSearcher}).Error(err) - } - log.Info("------------------------------------------------------------") -} diff --git a/tests/integration/db_test/subscriptions_test.go b/tests/integration/db_test/subscriptions_test.go deleted file mode 100644 index f28adc066..000000000 --- a/tests/integration/db_test/subscriptions_test.go +++ /dev/null @@ -1,199 +0,0 @@ -// +build integration - -package db_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/subscriber" - "github.com/trustwallet/blockatlas/tests/integration/setup" -) - -func TestDb_AddSubscriptionsBulk(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - var subscriptions []string - - for i := 0; i < 100; i++ { - subscriptions = append(subscriptions, "testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr") - } - - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriptions)) - for i := 0; i < 100; i++ { - s, err := database.GetSubscriptionsForNotifications([]string{"testAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddrtestAddr"}) - assert.Nil(t, err) - assert.NotNil(t, s) - } -} - -func TestDb_AddSubscriptions(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - - assert.Nil(t, database.AddSubscriptionsForNotifications([]string{"60_testAddr", "60_testAddr2", "60_testAddr3"})) - - subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) - assert.Nil(t, err) - assert.NotNil(t, subs) - assert.Equal(t, 1, len(subs)) - assert.Equal(t, "60_testAddr", subs[0].Address.Address) - - subs, err = database.GetSubscriptionsForNotifications([]string{"60_testAddr2"}) - assert.Nil(t, err) - assert.NotNil(t, subs) - assert.Equal(t, 1, len(subs)) - assert.Equal(t, "60_testAddr2", subs[0].Address.Address) - - subs, err = database.GetSubscriptionsForNotifications([]string{"60_testAddr3"}) - assert.Nil(t, err) - assert.NotNil(t, subs) - assert.Equal(t, 1, len(subs)) - assert.Equal(t, "60_testAddr3", subs[0].Address.Address) -} - -func TestDb_FindSubscriptions(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - - var subscriptionsA []blockatlas.Subscription - - subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ - Coin: 60, - Address: "etherAddress", - }) - - subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ - Coin: 714, - Address: "binanceAddress", - }) - - subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ - Coin: 148, - Address: "AtomAddress", - }) - - subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ - Coin: 144, - Address: "XLMAddress", - }) - - subscriptionsA = append(subscriptionsA, blockatlas.Subscription{ - Coin: 61, - Address: "ETCAddress", - }) - - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptionsA))) - - var subscriptionsB []blockatlas.Subscription - - for _, sub := range subscriptionsA { - subscriptionsB = append(subscriptionsB, sub) - } - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptionsB))) - - returnedSubs, err := database.GetSubscriptionsForNotifications([]string{"60_etherAddress"}) - assert.Nil(t, err) - assert.Equal(t, 1, len(returnedSubs)) - - returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"714_binanceAddress"}) - assert.Nil(t, err) - assert.Equal(t, 1, len(returnedSubs)) - - returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"144_XLMAddress"}) - assert.Nil(t, err) - assert.Equal(t, 1, len(returnedSubs)) - - returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"148_AtomAddress"}) - assert.Nil(t, err) - assert.Equal(t, 1, len(returnedSubs)) - - returnedSubs, err = database.GetSubscriptionsForNotifications([]string{"61_ETCAddress"}) - assert.Nil(t, err) - assert.Equal(t, 1, len(returnedSubs)) -} - -func TestDb_DeleteSubscriptions(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - subscriptions := []string{ - "60_testAddr", - "714_testAddr2", - "144_testAddr3", - } - - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriptions)) - - subs60, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) - assert.Nil(t, err) - assert.NotNil(t, subs60) - assert.Equal(t, 1, len(subs60)) - - subs714, err := database.GetSubscriptionsForNotifications([]string{"714_testAddr2"}) - assert.Nil(t, err) - assert.NotNil(t, subs714) - assert.Equal(t, 1, len(subs714)) - - subs144, err := database.GetSubscriptionsForNotifications([]string{"144_testAddr3"}) - assert.Nil(t, err) - assert.NotNil(t, subs144) - assert.Equal(t, 1, len(subs144)) - - assert.Nil(t, database.DeleteSubscriptionsForNotifications([]string{subscriptions[0]})) - - subs714N2, err := database.GetSubscriptionsForNotifications([]string{"714_testAddr2"}) - assert.Nil(t, err) - assert.NotNil(t, subs714N2) - assert.Equal(t, 1, len(subs714N2)) - - subs144N2, err := database.GetSubscriptionsForNotifications([]string{"144_testAddr3"}) - assert.Nil(t, err) - assert.NotNil(t, subs144N2) - assert.Equal(t, 1, len(subs144N2)) - - subs60N2, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) - assert.Nil(t, err) - assert.Len(t, subs60N2, 0) -} - -func TestDb_DuplicateEntries(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - var subscriptions []blockatlas.Subscription - - for i := 0; i < 10; i++ { - subscriptions = append(subscriptions, blockatlas.Subscription{ - Coin: 60, - Address: "testAddr", - }) - } - - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions))) - - subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) - assert.Nil(t, err) - assert.NotNil(t, subs) - assert.Equal(t, 1, len(subs)) -} - -func TestDb_CreateDeleteCreate(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - var subscriptions []blockatlas.Subscription - subscriptions = append(subscriptions, blockatlas.Subscription{ - Coin: 60, - Address: "testAddr", - }) - - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions))) - subs, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) - assert.Nil(t, err) - assert.Equal(t, 1, len(subs)) - - assert.Nil(t, database.DeleteSubscriptionsForNotifications([]string{"60_testAddr"})) - - subs2, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) - assert.Nil(t, err) - assert.Equal(t, 0, len(subs2)) - - assert.Nil(t, database.AddSubscriptionsForNotifications(subscriber.ToSubscriptionData(subscriptions))) - - subs3, err := database.GetSubscriptionsForNotifications([]string{"60_testAddr"}) - assert.Nil(t, err) - assert.Equal(t, 1, len(subs3)) -} diff --git a/tests/integration/db_test/tokenassociations_test.go b/tests/integration/db_test/tokenassociations_test.go deleted file mode 100644 index 7398bb399..000000000 --- a/tests/integration/db_test/tokenassociations_test.go +++ /dev/null @@ -1,198 +0,0 @@ -// +build integration - -package db_test - -import ( - "sort" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/tests/integration/setup" -) - -func Test_GetAssetsMapByAddresses(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - - assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} - - err := database.AddAssociationsForAddress("a", assets) - assert.Nil(t, err) - - err = database.AddAssociationsForAddress("b", nil) - assert.Nil(t, err) - - m, err := database.GetAssetsMapByAddresses([]string{"a", "b"}) - assert.Nil(t, err) - wantedMap := make(map[string][]models.Asset) - wantedMap["a"] = assets - for i, a := range m { - for ii, aa := range a { - assert.Equal(t, wantedMap[i][ii].Asset, aa.Asset) - } - } - -} - -func Test_GetAssetsMapByAddressesFromTime(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - - assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} - - err := database.AddAssociationsForAddress("a", assets) - assert.Nil(t, err) - - err = database.AddAssociationsForAddress("b", nil) - assert.Nil(t, err) - tm := time.Now().Unix() - 100 - m, err := database.GetAssetsMapByAddressesFromTime([]string{"a", "b"}, time.Unix(tm, 0)) - assert.Nil(t, err) - wantedMap := make(map[string][]models.Asset) - wantedMap["a"] = assets - - for i, a := range m { - for ii, aa := range a { - assert.Equal(t, wantedMap[i][ii].Asset, aa.Asset) - } - } - - m, err = database.GetAssetsMapByAddressesFromTime([]string{"a", "b"}, time.Unix(tm+101, 0)) - assert.Nil(t, err) - assert.Equal(t, 0, len(m)) -} - -func Test_GetSubscribedAddressesForAssets(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - - assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} - - err := database.AddAssociationsForAddress("a", assets) - assert.Nil(t, err) - - err = database.AddAssociationsForAddress("b", nil) - assert.Nil(t, err) - - m, err := database.GetSubscribedAddressesForAssets([]string{"a", "b"}) - assert.Nil(t, err) - assert.Equal(t, 2, len(m)) -} - -func Test_AddNewAssociationForAddress(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - assets := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} - - err := database.AddAssociationsForAddress("a", assets) - assert.Nil(t, err) - - associations, err := database.GetAssociationsByAddresses([]string{"a"}) - assert.Nil(t, err) - - var assetIDsFromDB []models.Asset - for _, a := range associations { - assetIDsFromDB = append(assetIDsFromDB, a.Asset) - } - - sort.Slice(assets, func(i, j int) bool { - return len(assets[i].Asset) > len(assets[j].Asset) - }) - - sort.Slice(assetIDsFromDB, func(i, j int) bool { - return len(assetIDsFromDB[i].Asset) > len(assetIDsFromDB[j].Asset) - }) - - for i, a := range assets { - assert.Equal(t, assetIDsFromDB[i].Asset, a.Asset) - } - - err = database.AddAssociationsForAddress("b", nil) - assert.Nil(t, err) - - associations2, err := database.GetAssociationsByAddresses([]string{"b"}) - assert.Nil(t, err) - assert.NotNil(t, associations2) -} - -func Test_UpdateAssociationsForExistingAddresses(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - assets := []models.Asset{{Asset: "f"}} - - err := database.AddAssociationsForAddress("A", assets) - assert.Nil(t, err) - - err = database.AddAssociationsForAddress("B", assets) - assert.Nil(t, err) - - assetsForA := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}} - assetsForB := []models.Asset{{Asset: "bbb"}, {Asset: "cccc"}} - - updateMap := make(map[string][]models.Asset) - updateMap["A"] = assetsForA - updateMap["B"] = assetsForB - - err = database.UpdateAssociationsForExistingAddresses(updateMap) - assert.Nil(t, err) - - associationsA, err := database.GetAssociationsByAddresses([]string{"A"}) - assert.Nil(t, err) - - var assetIDsFromDBA []models.Asset - for _, a := range associationsA { - assetIDsFromDBA = append(assetIDsFromDBA, a.Asset) - } - assetsA := []models.Asset{{Asset: "aa"}, {Asset: "bbb"}, {Asset: "cccc"}, {Asset: "f"}} - - sort.Slice(assetsA, func(i, j int) bool { - return len(assetsA[i].Asset) > len(assetsA[j].Asset) - }) - - sort.Slice(assetIDsFromDBA, func(i, j int) bool { - return len(assetIDsFromDBA[i].Asset) > len(assetIDsFromDBA[j].Asset) - }) - - for i, a := range assetsA { - assert.Equal(t, assetIDsFromDBA[i].Asset, a.Asset) - } - - associationsB, err := database.GetAssociationsByAddresses([]string{"B"}) - assert.Nil(t, err) - - var assetIDsFromDBB []models.Asset - for _, a := range associationsB { - assetIDsFromDBB = append(assetIDsFromDBB, a.Asset) - } - assetsB := []models.Asset{{Asset: "bbb"}, {Asset: "cccc"}, {Asset: "f"}} - - sort.Slice(assetsB, func(i, j int) bool { - return len(assetsB[i].Asset) > len(assetsB[j].Asset) - }) - - sort.Slice(assetIDsFromDBB, func(i, j int) bool { - return len(assetIDsFromDBB[i].Asset) > len(assetIDsFromDBB[j].Asset) - }) - - for i, a := range assetsB { - assert.Equal(t, assetIDsFromDBB[i].Asset, a.Asset) - } - - associationsAB, err := database.GetAssociationsByAddresses([]string{"A", "B"}) - assert.Nil(t, err) - - var assetIDsFromDBAB []models.Asset - for _, a := range associationsAB { - assetIDsFromDBAB = append(assetIDsFromDBAB, a.Asset) - } - assetsAB := []models.Asset{{Asset: "cccc"}, {Asset: "cccc"}, {Asset: "bbb"}, {Asset: "bbb"}, {Asset: "aa"}, {Asset: "f"}, {Asset: "f"}} - - sort.Slice(assetsAB, func(i, j int) bool { - return len(assetsAB[i].Asset) > len(assetsAB[j].Asset) - }) - - sort.Slice(assetIDsFromDBAB, func(i, j int) bool { - return len(assetIDsFromDBAB[i].Asset) > len(assetIDsFromDBAB[j].Asset) - }) - - for i, a := range assetsAB { - assert.Equal(t, assetIDsFromDBAB[i].Asset, a.Asset) - } -} diff --git a/tests/integration/db_test/tokenindexer_test.go b/tests/integration/db_test/tokenindexer_test.go index 1198d74be..5a795fa93 100644 --- a/tests/integration/db_test/tokenindexer_test.go +++ b/tests/integration/db_test/tokenindexer_test.go @@ -5,7 +5,6 @@ package db_test import ( "sort" "testing" - "time" gocache "github.com/patrickmn/go-cache" assert "github.com/stretchr/testify/assert" @@ -44,48 +43,6 @@ func Test_AddNewAssets_Simple(t *testing.T) { }) err = database.AddNewAssets(a) assert.Nil(t, err) - err = database.AddNewAssets([]models.Asset{{ - Asset: "c714_p", - Decimals: 0, - Name: "D", - Symbol: "DTS", - Type: "BEP20", - }}) - assert.Nil(t, err) - assets, err = database.GetAssetsByIDs([]string{"c714_p"}) - assert.Nil(t, err) - assert.Equal(t, 0, len(assets)) -} - -func Test_GetAssetsFrom_Simple(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - database.MemoryCache = gocache.New(gocache.NoExpiration, gocache.NoExpiration) - a := []models.Asset{ - { - Asset: "c714_a", - Coin: 714, - Decimals: 18, - Name: "A", - Symbol: "ABC", - Type: "BEP20", - }, - { - Asset: "c714_b", - Decimals: 18, - Coin: 60, - Name: "B", - Symbol: "BCD", - Type: "BEP20", - }, - } - err := database.AddNewAssets(a) - assert.Nil(t, err) - assets, err := database.GetAssetsFrom(time.Unix(0, 0), -1) - assert.Nil(t, err) - assert.NotNil(t, assets) - assets, err = database.GetAssetsFrom(time.Unix(0, 0), 60) - assert.Nil(t, err) - assert.Equal(t, 1, len(assets)) } func Test_AddNewAssets(t *testing.T) { diff --git a/tests/integration/observer_test/data/given_subscriptions_added.json b/tests/integration/observer_test/data/given_subscriptions_added.json deleted file mode 100644 index e046cbd4d..000000000 --- a/tests/integration/observer_test/data/given_subscriptions_added.json +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "subscriptions": { - "60": [ - "0x0000000000000000000000000000000000000000" - ] - }, - "operation": "AddSubscription" - }, - { - "subscriptions": { - "118": [ - "0x0000000000000000000000000000000000000001" - ] - }, - "operation": "AddSubscription" - }, - { - "subscriptions": { - "714": [ - "0x0000000000000000000000000000000000000002" - ] - }, - "operation": "AddSubscription" - }, - { - "subscriptions": { - "144": [ - "0x0000000000000000000000000000000000000003" - ] - }, - "operation": "AddSubscription" - } -] diff --git a/tests/integration/observer_test/data/given_subscriptions_deleted.json b/tests/integration/observer_test/data/given_subscriptions_deleted.json deleted file mode 100644 index 7eaf817cd..000000000 --- a/tests/integration/observer_test/data/given_subscriptions_deleted.json +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "subscriptions": { - "60": [ - "0x0000000000000000000000000000000000000000" - ] - }, - "operation": "UpdateSubscription" - }, - { - "subscriptions": { - "118": [ - "0x0000000000000000000000000000000000000001" - ] - }, - "operation": "UpdateSubscription" - }, - { - "subscriptions": { - "714": [ - "0x0000000000000000000000000000000000000002" - ] - }, - "operation": "UpdateSubscription" - }, - { - "subscriptions": { - "144": [ - "0x0000000000000000000000000000000000000003" - ] - }, - "operation": "UpdateSubscription" - } -] diff --git a/tests/integration/observer_test/data/wanted_subscriptions_added.json b/tests/integration/observer_test/data/wanted_subscriptions_added.json deleted file mode 100644 index febd62730..000000000 --- a/tests/integration/observer_test/data/wanted_subscriptions_added.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "coin": 60, - "address": "60_0x0000000000000000000000000000000000000000" - }, - { - "coin": 118, - "address": "118_0x0000000000000000000000000000000000000001" - }, - { - "coin": 714, - "address": "714_0x0000000000000000000000000000000000000002" - }, - { - "coin": 144, - "address": "144_0x0000000000000000000000000000000000000003" - } -] diff --git a/tests/integration/observer_test/full_flow_test.go b/tests/integration/observer_test/full_flow_test.go deleted file mode 100644 index 2c949108f..000000000 --- a/tests/integration/observer_test/full_flow_test.go +++ /dev/null @@ -1,162 +0,0 @@ -// +build integration - -package observer_test - -import ( - "context" - "encoding/json" - "testing" - "time" - - "github.com/streadway/amqp" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/notifier" - "github.com/trustwallet/blockatlas/services/parser" - "github.com/trustwallet/blockatlas/tests/integration/setup" - "github.com/trustwallet/golibs/coin" - "go.uber.org/atomic" -) - -var ( - currentBlockNumberCounter atomic.Int32 -) - -func TestFullFlow(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - err := database.AddSubscriptionsForNotifications([]string{"60_testAddress"}) - assert.Nil(t, err) - - ctx, cancel := context.WithCancel(context.Background()) - - stopChan := make(chan struct{}, 1) - - params := setupParserFull(stopChan) - params.Database = database - params.Ctx = ctx - params.TransactionsQueue = mq.RawTransactions - - go parser.RunParser(params) - time.Sleep(time.Second * 2) - - go mq.RunConsumerForChannelWithCancelAndDbConn(notifier.RunNotifier, rawTransactionsChannel, database, true, - ctx) - time.Sleep(time.Second * 5) - - for i := 0; i < 11; i++ { - x := transactionsChannel.GetMessage() - ConsumerToTestTransactionsFull(x, t, cancel, i) - } - <-stopChan -} - -func getMockedBlockAPIFull() blockatlas.BlockAPI { - p := PlatformFullFlow{CoinIndex: 60} - return &p -} - -type PlatformFullFlow struct { - CoinIndex uint -} - -func (p *PlatformFullFlow) CurrentBlockNumber() (int64, error) { - i := currentBlockNumberCounter.Load() - currentBlockNumberCounter.Add(1) - return int64(i), nil -} - -func (p *PlatformFullFlow) Coin() coin.Coin { - return coin.Coins[p.CoinIndex] -} - -func (p *PlatformFullFlow) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - if num < 100 { - return &blockatlas.Block{ - Number: num, - ID: "", - Txs: []blockatlas.Tx{ - { - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.ETH, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "testAddress", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "123", - Meta: blockatlas.NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "testAddress", - }, - }, - }, - }, nil - } - return &blockatlas.Block{}, nil -} - -func ConsumerToTestTransactionsFull(delivery amqp.Delivery, t *testing.T, cancel context.CancelFunc, counter int) { - var notifications []notifier.TransactionNotification - if err := json.Unmarshal(delivery.Body, ¬ifications); err != nil { - assert.Nil(t, err) - return - } - err := delivery.Ack(false) - if err != nil { - assert.Nil(t, err) - } - memo := blockatlas.NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "testAddress", - } - - assert.Equal(t, notifier.TransactionNotification{ - Action: blockatlas.TxNativeTokenTransfer, - Result: blockatlas.Tx{ - Type: blockatlas.TxNativeTokenTransfer, - Direction: "incoming", - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.ETH, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "testAddress", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "123", - Meta: &memo, - }, - }, notifications[0]) - - if counter == 10 { - cancel() - } -} - -func setupParserFull(stopChan chan<- struct{}) parser.Params { - minTime := time.Second - maxTime := time.Second * 2 - maxBatchBlocksAmount := 1 - - pollInterval := parser.GetInterval(0, minTime, maxTime) - - backlogCount := 1 - - return parser.Params{ - Api: getMockedBlockAPIFull(), - ParsingBlocksInterval: pollInterval, - BacklogCount: backlogCount, - MaxBacklogBlocks: int64(maxBatchBlocksAmount), - StopChannel: stopChan, - } -} diff --git a/tests/integration/observer_test/notifier_test.go b/tests/integration/observer_test/notifier_test.go deleted file mode 100644 index d1cf2e2fe..000000000 --- a/tests/integration/observer_test/notifier_test.go +++ /dev/null @@ -1,110 +0,0 @@ -// +build integration - -package observer_test - -import ( - "context" - "encoding/json" - "testing" - "time" - - "github.com/streadway/amqp" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/notifier" - "github.com/trustwallet/blockatlas/tests/integration/setup" - "github.com/trustwallet/golibs/coin" -) - -var ( - txs = blockatlas.Txs{ - { - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: blockatlas.NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, - }, - } -) - -func TestNotifier(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - - err := database.AddSubscriptionsForNotifications([]string{"714_tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a"}) - assert.Nil(t, err) - - err = produceTxs(txs) - assert.Nil(t, err) - - ctx, cancel := context.WithCancel(context.Background()) - - go mq.RunConsumerForChannelWithCancelAndDbConn(notifier.RunNotifier, rawTransactionsChannel, database, true, ctx) - time.Sleep(time.Second * 3) - msg := transactionsChannel.GetMessage() - ConsumerToTestTransactions(msg, t) - cancel() -} - -func ConsumerToTestTransactions(delivery amqp.Delivery, t *testing.T) { - var notifications []notifier.TransactionNotification - if err := json.Unmarshal(delivery.Body, ¬ifications); err != nil { - assert.Nil(t, err) - return - } - err := delivery.Ack(false) - if err != nil { - assert.Nil(t, err) - } - - memo := blockatlas.NativeTokenTransfer{ - Name: "", - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - } - - assert.Equal(t, notifier.TransactionNotification{ - Action: blockatlas.TxNativeTokenTransfer, - Result: blockatlas.Tx{ - Type: blockatlas.TxNativeTokenTransfer, - Direction: "outgoing", - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "test", - Meta: &memo, - }, - }, notifications[0]) - - return -} - -func produceTxs(txs blockatlas.Txs) error { - body, err := json.Marshal(txs) - if err != nil { - return err - } - return mq.RawTransactions.Publish(body) -} diff --git a/tests/integration/observer_test/observer_test.go b/tests/integration/observer_test/observer_test.go deleted file mode 100644 index a2a851cdc..000000000 --- a/tests/integration/observer_test/observer_test.go +++ /dev/null @@ -1,41 +0,0 @@ -// +build integration - -package observer_test - -import ( - "log" - "os" - "testing" - - "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/tests/integration/setup" -) - -var ( - rawTransactionsChannel, transactionsChannel, subscriptionChannel mq.MessageChannel - database *db.Instance -) - -func TestMain(m *testing.M) { - database = setup.RunPgContainer() - setup.RunMQContainer() - if err := mq.RawTransactions.Declare(); err != nil { - log.Fatal(err) - } - if err := mq.TxNotifications.Declare(); err != nil { - log.Fatal(err) - } - if err := mq.Subscriptions.Declare(); err != nil { - log.Fatal(err) - } - rawTransactionsChannel = mq.RawTransactions.GetMessageChannel() - subscriptionChannel = mq.Subscriptions.GetMessageChannel() - transactionsChannel = mq.TxNotifications.GetMessageChannel() - - code := m.Run() - - setup.StopMQContainer() - setup.StopPgContainer() - os.Exit(code) -} diff --git a/tests/integration/observer_test/parser_test.go b/tests/integration/observer_test/parser_test.go deleted file mode 100644 index 868f3dd9a..000000000 --- a/tests/integration/observer_test/parser_test.go +++ /dev/null @@ -1,119 +0,0 @@ -// +build integration - -package observer_test - -import ( - "context" - "encoding/json" - "testing" - "time" - - log "github.com/sirupsen/logrus" - "github.com/streadway/amqp" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/parser" - "github.com/trustwallet/blockatlas/tests/integration/setup" - "github.com/trustwallet/golibs/coin" -) - -func TestParserFetchAndPublishBlock_NormalCase(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - stopChan := make(chan struct{}, 1) - - params := setupParser(stopChan) - params.Database = database - - ctx, cancel := context.WithCancel(context.Background()) - - params.Ctx = ctx - params.TransactionsQueue = mq.RawTransactions - - go parser.RunParser(params) - - time.Sleep(time.Microsecond) - ConsumerToTestAmountOfBlocks(rawTransactionsChannel.GetMessage(), t, cancel) - <-stopChan -} - -func getMockedBlockAPI() blockatlas.BlockAPI { - p := Platform{CoinIndex: 60} - return &p -} - -type Platform struct { - CoinIndex uint -} - -func (p *Platform) CurrentBlockNumber() (int64, error) { - return int64(100), nil -} - -func (p *Platform) Coin() coin.Coin { - return coin.Coins[p.CoinIndex] -} - -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - if num < 101 { - return &blockatlas.Block{ - Number: num, - ID: "", - Txs: []blockatlas.Tx{ - { - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: blockatlas.StatusCompleted, - Memo: "google.com", - Meta: blockatlas.NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, - }, - }, - }, nil - } - return &blockatlas.Block{}, nil -} - -func ConsumerToTestAmountOfBlocks(delivery amqp.Delivery, t *testing.T, cancelFunc context.CancelFunc) { - var txs blockatlas.Txs - if err := json.Unmarshal(delivery.Body, &txs); err != nil { - log.Error(err) - return - } - err := delivery.Ack(false) - if err != nil { - log.Error(err) - } - - assert.Equal(t, len(txs), 50) - cancelFunc() -} - -func setupParser(stopChan chan struct{}) parser.Params { - minTime := time.Second - maxTime := time.Second * 2 - maxBatchBlocksAmount := 100 - - pollInterval := parser.GetInterval(0, minTime, maxTime) - - backlogCount := 50 - - return parser.Params{ - Api: getMockedBlockAPI(), - ParsingBlocksInterval: pollInterval, - BacklogCount: backlogCount, - MaxBacklogBlocks: int64(maxBatchBlocksAmount), - StopChannel: stopChan, - } -} diff --git a/tests/integration/observer_test/subscriber_test.go b/tests/integration/observer_test/subscriber_test.go deleted file mode 100644 index d9c42190f..000000000 --- a/tests/integration/observer_test/subscriber_test.go +++ /dev/null @@ -1,144 +0,0 @@ -// +build integration - -package observer_test - -import ( - "context" - "encoding/json" - "io/ioutil" - "path/filepath" - "runtime" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/mq" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/subscriber" - "github.com/trustwallet/blockatlas/tests/integration/setup" -) - -func TestSubscriberAddSubscription(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - - _, goFile, _, _ := runtime.Caller(0) - testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_added.json") - testFileGiven, err := ioutil.ReadFile(testFilePathGiven) - if err != nil { - t.Fatal(err) - } - var givenEvents []blockatlas.SubscriptionEvent - if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { - t.Fatal(err) - } - - testFilePathWanted := filepath.Join(filepath.Dir(goFile), "data", "wanted_subscriptions_added.json") - testFileWanted, err := ioutil.ReadFile(testFilePathWanted) - if err != nil { - t.Fatal(err) - } - var wantedEvents []blockatlas.Subscription - if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { - t.Fatal(err) - } - - for _, event := range givenEvents { - body, err := json.Marshal(event) - assert.Nil(t, err) - - err = mq.Subscriptions.Publish(body) - assert.Nil(t, err) - - ctx, cancel := context.WithCancel(context.Background()) - - go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, subscriptionChannel, database, true, ctx) - time.Sleep(time.Second * 2) - cancel() - } - - for _, wanted := range wantedEvents { - result, err := database.GetSubscriptionsForNotifications([]string{wanted.Address}) - assert.Nil(t, err) - assert.Equal(t, result[0].Address.Address, wanted.Address) - } -} - -func TestSubscriber_UpdateSubscription(t *testing.T) { - setup.CleanupPgContainer(database.Gorm) - _, goFile, _, _ := runtime.Caller(0) - testFilePathGiven := filepath.Join(filepath.Dir(goFile), "data", "given_subscriptions_deleted.json") - testFileGiven, err := ioutil.ReadFile(testFilePathGiven) - if err != nil { - t.Fatal(err) - } - var givenEvents []blockatlas.SubscriptionEvent - if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { - t.Fatal(err) - } - - if err := json.Unmarshal(testFileGiven, &givenEvents); err != nil { - t.Fatal(err) - } - - testFilePathWanted := filepath.Join(filepath.Dir(goFile), "data", "wanted_subscriptions_added.json") - testFileWanted, err := ioutil.ReadFile(testFilePathWanted) - if err != nil { - t.Fatal(err) - } - var wantedEvents []blockatlas.Subscription - if err := json.Unmarshal(testFileWanted, &wantedEvents); err != nil { - t.Fatal(err) - } - - database.AddSubscriptionsForNotifications( - []string{"61_0x0000000000000000000000000000000000000000"}) - - database.AddSubscriptionsForNotifications( - []string{"62_0x0000000000000000000000000000000000000000"}) - - database.AddSubscriptionsForNotifications( - []string{"63_0x0000000000000000000000000000000000000000"}) - - database.AddSubscriptionsForNotifications( - []string{"64_0x0000000000000000000000000000000000000000"}) - - for _, event := range givenEvents { - body, err := json.Marshal(event) - assert.Nil(t, err) - - err = mq.Subscriptions.Publish(body) - assert.Nil(t, err) - - ctx, cancel := context.WithCancel(context.Background()) - - go mq.RunConsumerForChannelWithCancelAndDbConn(subscriber.RunTransactionsSubscriber, subscriptionChannel, database, true, ctx) - time.Sleep(time.Second) - cancel() - } - - for _, wanted := range wantedEvents { - result, err := database.GetSubscriptionsForNotifications([]string{wanted.Address}) - assert.Nil(t, err) - assert.Len(t, result, 1) - } - - abs61, err := database.GetSubscriptionsForNotifications([]string{"61_0x0000000000000000000000000000000000000000"}) - assert.Nil(t, err) - assert.Len(t, abs61, 1) - - abs62, err := database.GetSubscriptionsForNotifications([]string{"62_0x0000000000000000000000000000000000000000"}) - assert.Nil(t, err) - assert.Len(t, abs62, 1) - - abs63, err := database.GetSubscriptionsForNotifications([]string{"63_0x0000000000000000000000000000000000000000"}) - assert.Nil(t, err) - assert.Len(t, abs63, 1) - - abs64, err := database.GetSubscriptionsForNotifications([]string{"64_0x0000000000000000000000000000000000000000"}) - assert.Nil(t, err) - assert.Len(t, abs64, 1) - - abs65, err := database.GetSubscriptionsForNotifications([]string{"65_0x0000000000000000000000000000000000000000"}) - assert.Nil(t, err) - assert.Len(t, abs65, 0) -} diff --git a/tests/integration/setup/mq.go b/tests/integration/setup/mq.go index dc1cb294b..4ac9146e8 100644 --- a/tests/integration/setup/mq.go +++ b/tests/integration/setup/mq.go @@ -2,9 +2,10 @@ package setup import ( "fmt" - "github.com/ory/dockertest" - "github.com/trustwallet/blockatlas/mq" "log" + + "github.com/ory/dockertest" + "github.com/trustwallet/golibs/network/mq" ) var ( diff --git a/tests/integration/setup/postgres.go b/tests/integration/setup/postgres.go index 9b3584707..036a5930b 100644 --- a/tests/integration/setup/postgres.go +++ b/tests/integration/setup/postgres.go @@ -2,11 +2,12 @@ package setup import ( "fmt" + "log" + "github.com/ory/dockertest" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" "gorm.io/gorm" - "log" ) const ( @@ -24,12 +25,10 @@ var ( } tables = []interface{}{ - &models.AssetSubscription{}, - &models.NotificationSubscription{}, &models.Tracker{}, - &models.AddressToAssetAssociation{}, &models.Asset{}, - &models.Address{}, + &models.Subscription{}, + &models.SubscriptionsAssetAssociation{}, } url string From 774af806ef17363d0db140d246f681ce21cec558 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 5 Jan 2021 01:02:35 -0800 Subject: [PATCH 444/506] [Algorand] Integrate v2 API (#1344) * [Algorand] Integrate v2 API * Fix normalize test * Implement GetLatestBlock --- config.yml | 3 +- config/configuration.go | 1 + platform/algorand/base.go | 5 +-- platform/algorand/client.go | 64 ++++++++------------------- platform/algorand/model.go | 24 +++++----- platform/algorand/transaction.go | 2 +- platform/algorand/transaction_test.go | 58 +++++++++++++----------- platform/platform.go | 2 +- 8 files changed, 67 insertions(+), 92 deletions(-) diff --git a/config.yml b/config.yml index 75311acaa..b483f7750 100644 --- a/config.yml +++ b/config.yml @@ -183,7 +183,8 @@ decred: api: https://blockbook.decred.org:9161 algorand: - api: https://mainnet-algorand.api.purestake.io/ps1 + api: https://api.algoexplorer.io/idx2 + key: "" nano: api: https://nanoverse.io/api/node diff --git a/config/configuration.go b/config/configuration.go index 0292ba6ea..ece354014 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -173,6 +173,7 @@ type Configuration struct { } `mapstructure:"decred"` Algorand struct { API string `mapstructure:"api"` + Key string `mapstructure:"key"` } `mapstructure:"algorand"` Nano struct { API string `mapstructure:"api"` diff --git a/platform/algorand/base.go b/platform/algorand/base.go index 019b5354a..c47946452 100644 --- a/platform/algorand/base.go +++ b/platform/algorand/base.go @@ -1,7 +1,6 @@ package algorand import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" ) @@ -9,9 +8,9 @@ type Platform struct { client Client } -func Init(api string) *Platform { +func Init(api, apiKey string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: InitClient(api, apiKey), } } diff --git a/platform/algorand/client.go b/platform/algorand/client.go index f856931bf..084a6fd7f 100644 --- a/platform/algorand/client.go +++ b/platform/algorand/client.go @@ -2,91 +2,65 @@ package algorand import ( "fmt" + "strconv" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/numbers" ) type Client struct { blockatlas.Request } -func InitClient(baseUrl string) Client { +func InitClient(url, apiKey string) Client { return Client{ Request: blockatlas.Request{ HttpClient: blockatlas.DefaultClient, ErrorHandler: blockatlas.DefaultErrorHandler, - BaseUrl: baseUrl, + Headers: map[string]string{"X-Indexer-API-Token": apiKey}, + BaseUrl: url, }, } } func (c *Client) GetLatestBlock() (int64, error) { var status Status - err := c.Get(&status, "v1/status", nil) + err := c.Get(&status, "health", nil) if err != nil { return 0, err } - return status.LastRound, nil -} - -func (c *Client) GetBlock(number int64) (BlockResponse, error) { - path := fmt.Sprintf("v1/block/%d", number) - var resp BlockResponse - err := c.Get(&resp, path, nil) + block, err := strconv.Atoi(status.Block) if err != nil { - return resp, err - } - - normalizedTxs := make([]Transaction, 0) - //TODO: Read GetTxsOfAddress explanation - for _, t := range resp.Transactions.Transactions { - normalized := normalizeTx(&t, resp) - normalizedTxs = append(normalizedTxs, *normalized) + return 0, err } - resp.Transactions.Transactions = normalizedTxs - return resp, nil + return int64(block), nil } func (c *Client) GetTxsInBlock(number int64) ([]Transaction, error) { - block, err := c.GetBlock(number) - return block.Transactions.Transactions, err + path := fmt.Sprintf("v2/blocks/%d", number) + var resp BlockResponse + err := c.Get(&resp, path, nil) + if err != nil { + return []Transaction{}, err + } + return resp.Transactions, err } +//deprecated, no longer need to support staking func (c *Client) GetAccount(address string) (account *Account, err error) { - path := fmt.Sprintf("v1/account/%s", address) + path := fmt.Sprintf("v2/accounts/%s", address) err = c.Get(&account, path, nil) return } func (c *Client) GetTxsOfAddress(address string) ([]Transaction, error) { var response TransactionsResponse - path := fmt.Sprintf("v1/account/%s/transactions", address) + path := fmt.Sprintf("v2/accounts/%s/transactions", address) err := c.Get(&response, path, nil) if err != nil { return nil, blockatlas.ErrSourceConn } - results := make([]Transaction, 0) - - //FIXME. Currently fetching the last 6 transactions and get 6 blocks for each to retrieve timestamp. - //Algorand team promised to provide endpoint soon that will contain timestamp value inside TransactionsResponse response - //Get latest 6 transactions, which is enough until new endpoint fixes it. - txs := response.Transactions[:numbers.Min(6, len(response.Transactions))] - - for _, t := range txs { - block, err := c.GetBlock(int64(t.Round)) - if err == nil { - normalizeTx(&t, block) - results = append(results, t) - } - } - - return results, err -} -func normalizeTx(transaction *Transaction, block BlockResponse) *Transaction { - transaction.Timestamp = block.Timestamp - return transaction + return response.Transactions, err } diff --git a/platform/algorand/model.go b/platform/algorand/model.go index 7915b17a9..87e66c544 100644 --- a/platform/algorand/model.go +++ b/platform/algorand/model.go @@ -21,29 +21,25 @@ type TransactionsResponse struct { } type BlockResponse struct { - Timestamp uint64 `json:"timestamp"` - Transactions BlockTransactions `json:"txns"` -} - -type BlockTransactions struct { + Timestamp uint64 `json:"timestamp"` Transactions []Transaction `json:"transactions"` } type Transaction struct { - Type TransactionType `json:"type"` - Hash string `json:"tx"` - From string `json:"from"` + Type TransactionType `json:"tx-type"` + Hash string `json:"id"` + From string `json:"sender"` Fee uint64 `json:"fee"` - Round uint64 `json:"round"` - Payment TransactionPayment `json:"payment"` - Timestamp uint64 `json:"timestamp,omitempty"` + Round uint64 `json:"confirmed-round"` + Payment TransactionPayment `json:"payment-transaction"` + Timestamp uint64 `json:"round-time"` } type TransactionPayment struct { - To string `json:"to"` - Amount uint64 `json:"amount"` + Receiver string `json:"receiver"` + Amount uint64 `json:"amount"` } type Status struct { - LastRound int64 `json:"lastRound"` + Block string `json:"message"` } diff --git a/platform/algorand/transaction.go b/platform/algorand/transaction.go index 2eb677a06..ca977a60d 100644 --- a/platform/algorand/transaction.go +++ b/platform/algorand/transaction.go @@ -37,7 +37,7 @@ func Normalize(tx Transaction) (result blockatlas.Tx, ok bool) { ID: tx.Hash, Coin: coin.ALGO, From: tx.From, - To: tx.Payment.To, + To: tx.Payment.Receiver, Fee: blockatlas.Amount(strconv.Itoa(int(tx.Fee))), Date: int64(tx.Timestamp), Block: tx.Round, diff --git a/platform/algorand/transaction_test.go b/platform/algorand/transaction_test.go index d5b09eb99..d466185f5 100644 --- a/platform/algorand/transaction_test.go +++ b/platform/algorand/transaction_test.go @@ -2,40 +2,44 @@ package algorand import ( "encoding/json" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" ) const ( transfer = ` { - "transactions":[ - { - "type":"pay", - "tx":"C2LK3CGBPIGERLPFUXE6INSBJGHOXU7YZMEGELWMVSBASFJYOOQQ", - "from":"5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", - "fee":1000, - "first-round":2031300, - "last-round":2031749, - "noteb64":"6OZ0TFd0HPw=", - "round":2031351, - "poolerror":"", - "payment":{ - "to":"4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", - "close":"", - "closeamount":0, - "amount":1, - "torewards":3237690, - "closerewards":0 - }, - "fromrewards":0, - "genesisID":"mainnet-v1.0", - "genesishashb64":"wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=", - "group":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" - } - ] + "transactions":[ + { + "close-rewards":0, + "closing-amount":0, + "confirmed-round":2031351, + "fee":1000, + "first-valid":2031300, + "genesis-hash":"wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=", + "genesis-id":"mainnet-v1.0", + "id":"C2LK3CGBPIGERLPFUXE6INSBJGHOXU7YZMEGELWMVSBASFJYOOQQ", + "intra-round-offset":57, + "last-valid":2031749, + "note":"6OZ0TFd0HPw=", + "payment-transaction":{ + "amount":1, + "close-amount":0, + "receiver":"4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U" + }, + "receiver-rewards":3237690, + "round-time":1569123058, + "sender":"5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", + "sender-rewards":0, + "signature":{ + "sig":"J1G/vapWXJJjuFcsUPut9ffHrFnXsg1GRQlLyqhTOC0V78zCw3OIAYgeg6k/xiX5NDLLrgy4aYF1hhsEXGZ2Dg==" + }, + "tx-type":"pay" + } + ] } ` ) @@ -47,7 +51,7 @@ var expected = []*blockatlas.Tx{ From: "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", To: "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", Fee: blockatlas.Amount("1000"), - Date: 0, + Date: 1569123058, Block: 2031351, Status: blockatlas.StatusCompleted, Type: blockatlas.TxTransfer, diff --git a/platform/platform.go b/platform/platform.go index 018aa8b2f..42ef2de19 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -61,7 +61,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Vechain().Handle: vechain.Init(config.Default.Vechain.API), coin.Nebulas().Handle: nebulas.Init(config.Default.Nebulas.API), coin.Ontology().Handle: ontology.Init(config.Default.Ontology.API), - coin.Algorand().Handle: algorand.Init(config.Default.Algorand.API), + coin.Algorand().Handle: algorand.Init(config.Default.Algorand.API, config.Default.Algorand.Key), coin.Aeternity().Handle: aeternity.Init(config.Default.Aeternity.API), coin.Solana().Handle: solana.Init(config.Default.Solana.API), coin.Tezos().Handle: tezos.Init(config.Default.Tezos.API, config.Default.Tezos.RPC), From dce5c74aa041c079a93819fe51eac40894dc73c0 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:35:16 +0800 Subject: [PATCH 445/506] Use address/client/jsonrpc from golibs (#1340) * use golibs client * use address package from golibs * bump golibs * add tests --- go.mod | 8 +- go.sum | 50 +------ pkg/address/address.go | 134 ------------------- pkg/address/address_test.go | 148 --------------------- pkg/blockatlas/client.go | 137 ------------------- pkg/blockatlas/clientcache.go | 136 ------------------- pkg/blockatlas/clientcache_test.go | 75 ----------- pkg/blockatlas/jsonrpc.go | 111 ---------------- pkg/blockatlas/jsonrpc_test.go | 35 ----- platform/aeternity/base.go | 4 +- platform/aeternity/client.go | 5 +- platform/aion/base.go | 4 +- platform/aion/client.go | 5 +- platform/algorand/client.go | 9 +- platform/bitcoin/base.go | 4 +- platform/bitcoin/client.go | 3 +- platform/cosmos/base.go | 4 +- platform/cosmos/client.go | 7 +- platform/elrond/base.go | 4 +- platform/elrond/client.go | 3 +- platform/ethereum/base.go | 8 +- platform/ethereum/blockbook/client.go | 4 +- platform/ethereum/blockbook/transaction.go | 15 ++- platform/ethereum/collection/client.go | 4 +- platform/ethereum/trustray/client.go | 4 +- platform/ethereum/trustray/transaction.go | 21 ++- platform/filecoin/base.go | 6 +- platform/filecoin/explorer/client.go | 4 +- platform/filecoin/rpc/client.go | 6 +- platform/fio/base.go | 4 +- platform/fio/client.go | 6 +- platform/harmony/base.go | 4 +- platform/harmony/client.go | 4 +- platform/icon/base.go | 4 +- platform/icon/client.go | 6 +- platform/iotex/base.go | 4 +- platform/iotex/client.go | 8 +- platform/kava/base.go | 4 +- platform/kava/client.go | 7 +- platform/nano/base.go | 4 +- platform/nano/client.go | 3 +- platform/near/base.go | 4 +- platform/near/client.go | 6 +- platform/nebulas/base.go | 4 +- platform/nebulas/client.go | 5 +- platform/nimiq/base.go | 4 +- platform/nimiq/client.go | 6 +- platform/ontology/base.go | 4 +- platform/ontology/client.go | 5 +- platform/polkadot/base.go | 4 +- platform/polkadot/client.go | 3 +- platform/ripple/base.go | 4 +- platform/ripple/client.go | 5 +- platform/solana/base.go | 4 +- platform/solana/client.go | 8 +- platform/solana/transaction_test.go | 6 +- platform/stellar/base.go | 4 +- platform/stellar/client.go | 5 +- platform/tezos/base.go | 6 +- platform/tezos/client.go | 5 +- platform/tezos/rpc.go | 5 +- platform/theta/base.go | 4 +- platform/theta/client.go | 5 +- platform/tron/address.go | 23 ++++ platform/tron/address_test.go | 31 +++++ platform/tron/base.go | 6 +- platform/tron/client.go | 7 +- platform/tron/stake.go | 8 +- platform/tron/transaction.go | 10 +- platform/vechain/base.go | 4 +- platform/vechain/client.go | 5 +- platform/vechain/transaction.go | 42 ++++-- platform/waves/base.go | 4 +- platform/waves/client.go | 5 +- platform/zilliqa/base.go | 6 +- platform/zilliqa/client.go | 4 +- platform/zilliqa/model.go | 10 +- platform/zilliqa/rpc.go | 12 +- services/assets/client.go | 7 +- services/notifier/base.go | 20 ++- services/notifier/base_test.go | 58 ++++++++ 81 files changed, 376 insertions(+), 1008 deletions(-) delete mode 100644 pkg/address/address.go delete mode 100644 pkg/address/address_test.go delete mode 100644 pkg/blockatlas/client.go delete mode 100644 pkg/blockatlas/clientcache.go delete mode 100644 pkg/blockatlas/clientcache_test.go delete mode 100644 pkg/blockatlas/jsonrpc.go delete mode 100644 pkg/blockatlas/jsonrpc_test.go create mode 100644 platform/tron/address.go create mode 100644 platform/tron/address_test.go create mode 100644 services/notifier/base_test.go diff --git a/go.mod b/go.mod index 28cbcb427..65ccb33e9 100644 --- a/go.mod +++ b/go.mod @@ -8,18 +8,15 @@ go 1.15 require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 - github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/deckarep/golang-set v1.7.1 github.com/getsentry/raven-go v0.2.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 github.com/imroc/req v0.3.0 github.com/mitchellh/mapstructure v1.4.0 - github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/runc v1.0.0-rc9 // indirect github.com/ory/dockertest v3.3.5+incompatible - github.com/ory/dockertest/v3 v3.6.3 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible github.com/sirupsen/logrus v1.7.0 github.com/spf13/viper v1.7.1 @@ -27,9 +24,8 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/swag v1.7.0 - github.com/trustwallet/golibs v0.0.26 - github.com/trustwallet/golibs/network v0.0.0-20210105062859-04e821673147 - go.uber.org/atomic v1.7.0 + github.com/trustwallet/golibs v0.0.28 + github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect golang.org/x/sys v0.0.0-20210104204734-6f8348627aad // indirect diff --git a/go.sum b/go.sum index 2025bdf56..cc05ad0d5 100644 --- a/go.sum +++ b/go.sum @@ -19,7 +19,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -54,17 +53,12 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= -github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= -github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 h1:6ejg6Lkk8dskcM7wQ28gONkukbQkM4qpj4RnYbpFzrI= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -75,8 +69,6 @@ github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -157,8 +149,8 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -285,7 +277,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -322,10 +313,6 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 h1:SPoLlS9qUUnXcIY4pvA4CTwYjk0Is5f4UPEkeESr53k= -github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2/go.mod h1:TjQg8pa4iejrUrjiz0MCtMV38jdMNW4doKSiBrEvCQQ= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -339,7 +326,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -349,14 +335,13 @@ github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/ory/dockertest/v3 v3.6.3 h1:L8JWiGgR+fnj90AEOkTFIEp4j5uWAK72P3IUsYgn2cs= -github.com/ory/dockertest/v3 v3.6.3/go.mod h1:EFLcVUOl8qCwp9NyDAcCDtq/QviLtYswW/VbWzUnTNE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -430,26 +415,10 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.26 h1:8Cfym03kkkvQkzdp7ZBPIX0583jmL5d0x910psyHbpM= -github.com/trustwallet/golibs v0.0.26/go.mod h1:Vi63TTS0yRAPwFIIKe7tw1yTgd71RACQqgZpUcWTv04= -github.com/trustwallet/golibs/network v0.0.0-20201230050918-14143fadb599 h1:FFfIqpBTRr3j0UDxqdAghhf/nQ+mdAjVSUS+evrlLX4= -github.com/trustwallet/golibs/network v0.0.0-20201230050918-14143fadb599/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= -github.com/trustwallet/golibs/network v0.0.0-20210104211257-93dbcade3020 h1:qCdSiwsTl3298l5AgRwwnX71ZjrtXs1G2alJ9rGjGlE= -github.com/trustwallet/golibs/network v0.0.0-20210104211257-93dbcade3020/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= -github.com/trustwallet/golibs/network v0.0.0-20210104211641-8220d564ec5b h1:ByEWkqd8282NByRkpfeamYC93evnKXl7KTARE2fXEGw= -github.com/trustwallet/golibs/network v0.0.0-20210104211641-8220d564ec5b/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= -github.com/trustwallet/golibs/network v0.0.0-20210104213645-d89799a54570 h1:48um24W0y2fOt2wkUqIf7to3nxTPycdOMRNBXLvGm8s= -github.com/trustwallet/golibs/network v0.0.0-20210104213645-d89799a54570/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= -github.com/trustwallet/golibs/network v0.0.0-20210104232605-ad31e67e25d2 h1:c6QTCG1t33HT4PbBvuxB5esKV5A/Z4k0M4lBBe+xSso= -github.com/trustwallet/golibs/network v0.0.0-20210104232605-ad31e67e25d2/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= -github.com/trustwallet/golibs/network v0.0.0-20210105041738-9bc894a4eb36 h1:LvxbcMgzxwtNc3aIWXVO6UBOb+gPI5p6gqCQT3n54r0= -github.com/trustwallet/golibs/network v0.0.0-20210105041738-9bc894a4eb36/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= -github.com/trustwallet/golibs/network v0.0.0-20210105053024-ba940057a9f6 h1:2dmW1RjE8YqkhowBn+YbCNDNuFLt6ca9DPG296avuzU= -github.com/trustwallet/golibs/network v0.0.0-20210105053024-ba940057a9f6/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= -github.com/trustwallet/golibs/network v0.0.0-20210105061744-4e36d6077394 h1:aErM6e62NxCsCh9VUGQf7ajWQJZD13bjR3hLZilaH6M= -github.com/trustwallet/golibs/network v0.0.0-20210105061744-4e36d6077394/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= -github.com/trustwallet/golibs/network v0.0.0-20210105062859-04e821673147 h1:Ll8rCpI8ldt2wre2bI94+vLUkHnIMZUwsUYnjpDcT+8= -github.com/trustwallet/golibs/network v0.0.0-20210105062859-04e821673147/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs v0.0.28 h1:EesgBxbSY9NXR6IarAnLU/XH7srnidF1hnkX0eLDti4= +github.com/trustwallet/golibs v0.0.28/go.mod h1:otCh9cT8r7VlojZv5zACgUpUyAhNrd5kD5YRV6xW9Iw= +github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08 h1:6MVjdC1zYVwiytclgHLxS6ojdYiM7gfVqMSDkjuulS4= +github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= 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= @@ -531,7 +500,6 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY= @@ -572,12 +540,9 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo= -golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad h1:MCsdmFSdEd4UEa5TKS5JztCRHK/WtvNei1edOj5RSRo= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -605,7 +570,6 @@ golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -664,7 +628,6 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -679,7 +642,6 @@ gorm.io/gorm v1.20.9 h1:M3aIZKXAC1PtPVu9t3WGwkBTE1le5c2telz3I/qjRNg= gorm.io/gorm v1.20.9/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= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/address/address.go b/pkg/address/address.go deleted file mode 100644 index e057bbdc0..000000000 --- a/pkg/address/address.go +++ /dev/null @@ -1,134 +0,0 @@ -package address - -import ( - "crypto/sha256" - "encoding/hex" - "strconv" - "strings" - - "github.com/mr-tron/base58" - log "github.com/sirupsen/logrus" - "github.com/trustwallet/golibs/coin" - "golang.org/x/crypto/sha3" -) - -const prefixBitcoinCash = "bitcoincash:" - -// Decode decodes a hex string with 0x prefix. -func Remove0x(input string) string { - if strings.HasPrefix(input, "0x") { - return input[2:] - } - return input -} - -// Hex returns an EIP55-compliant hex string representation of the address. -func EIP55Checksum(unchecksummed string) string { - v := []byte(Remove0x(strings.ToLower(unchecksummed))) - sha := sha3.NewLegacyKeccak256() - _, err := sha.Write(v) - if err != nil { - log.Error(err) - } - hash := sha.Sum(nil) - - result := v - for i := 0; i < len(result); i++ { - hashByte := hash[i/2] - if i%2 == 0 { - hashByte = hashByte >> 4 - } else { - hashByte &= 0xf - } - if result[i] > '9' && hashByte > 7 { - result[i] -= 32 - } - } - val := string(result) - return "0x" + val -} - -// HexToAddress converts a hex representation of a Tron address -// into a Base58 string with a 4 byte checksum. -func HexToAddress(hexAddr string) (b58 string, err error) { - bytes, err := hex.DecodeString(hexAddr) - if err != nil { - return "", err - } - var checksum [32]byte - checksum = sha256.Sum256(bytes) - checksum = sha256.Sum256(checksum[:]) - bytes = append(bytes, checksum[:4]...) - b58 = base58.EncodeAlphabet(bytes, base58.BTCAlphabet) - return -} - -// Returns an EIP55 Wanchain compliant hex string representation of the address. -// See https://wandevs.org/docs/difference-between-wanchain-and-ethereum/ -// https://github.com/wanchain/go-wanchain/blob/b238c203ca7dc6a578d57c0c473bec0fcf2431bd/common/types.go#L173 -func EIP55ChecksumWanchain(address string) string { - v := []byte(Remove0x(strings.ToLower(address))) - sha := sha3.NewLegacyKeccak256() - _, err := sha.Write(v) - if err != nil { - log.Error(err) - } - hash := sha.Sum(nil) - - result := v - for i := 0; i < len(result); i++ { - hashByte := hash[i/2] - if i%2 == 0 { - hashByte = hashByte >> 4 - } else { - hashByte &= 0xf - } - if result[i] > '9' && hashByte <= 7 { - result[i] -= 32 - } - } - return "0x" + string(result) -} - -func ToEIP55ByCoinID(str string, coinID uint) string { - switch coinID { - case coin.ETH, coin.POA, coin.ETC, coin.TOMO, coin.CLO, coin.TT, coin.GO: - return EIP55Checksum(str) - case coin.WAN: - return EIP55ChecksumWanchain(str) - default: - return str - } -} - -func removePrefix(address string) string { - return strings.TrimPrefix(address, prefixBitcoinCash) -} - -func FormatAddress(address string, coinID uint) string { - switch coinID { - case coin.ETH, coin.POA, coin.ETC, coin.TOMO, coin.CLO, coin.TT, coin.GO, coin.WAN: - return ToEIP55ByCoinID(address, coinID) - case coin.BCH: - return removePrefix(address) - default: - return address - } -} - -func PrefixedAddress(coinID uint, address string) string { - return strconv.Itoa(int(coinID)) + "_" + address -} - -func UnprefixedAddress(address string) (string, uint, bool) { - result := strings.Split(address, "_") - if len(result) != 2 { - return "", 0, false - } - id, err := strconv.Atoi(result[0]) - if err != nil { - return "", 0, false - } - return result[1], uint(id), true - -} diff --git a/pkg/address/address_test.go b/pkg/address/address_test.go deleted file mode 100644 index 1b46c9f93..000000000 --- a/pkg/address/address_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package address - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/trustwallet/golibs/coin" -) - -func TestEIP55ChecksumWanchain(t *testing.T) { - var ( - addr1Wan = "0xae96137e0e05681ed2f5d1af272c3ee512939d0f" - addr1WANEIP55 = "0xaE96137e0E05681Ed2f5d1af272c3EE512939d0f" - tests = []struct { - name string - unchecksummed string - want string - }{ - {"test 1", addr1Wan, addr1WANEIP55}, - {"test 2", addr1WANEIP55, addr1WANEIP55}, - } - ) - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := EIP55ChecksumWanchain(tt.unchecksummed); got != tt.want { - t.Errorf("EIP55ChecksumWanchain() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestRemove0x(t *testing.T) { - tests := []struct { - name string - input string - want string - }{ - {"remove 0x from addres", "0x158079ee67fce2f58472a96584a73c7ab9ac95c1", "158079ee67fce2f58472a96584a73c7ab9ac95c1"}, - {"remove 0x from hash", "0x230798fe22abff459b004675bf827a4089326a296fa4165d0c2ad27688e03e0c", "230798fe22abff459b004675bf827a4089326a296fa4165d0c2ad27688e03e0c"}, - {"remove 0x hex value", "0xfffdefefed", "fffdefefed"}, - {"remove 0x hex number", "0x16345785d8a0000", "16345785d8a0000"}, - {"remove hex without 0x", "trustwallet", "trustwallet"}, - {"remove hex number without 0x", "16345785d8a0000", "16345785d8a0000"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := Remove0x(tt.input); got != tt.want { - t.Errorf("Remove0x() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestHexToAddress(t *testing.T) { - in := "4182dd6b9966724ae2fdc79b416c7588da67ff1b35" - expected := "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9" - got, err := HexToAddress(in) - if err != nil { - t.Fatal(err) - } - if expected != got { - t.Fatalf("expected %s, got %s", expected, got) - } -} - -func TestToEIP55ByCoinID(t *testing.T) { - var ( - addr1 = "0xea674fdde714fd979de3edf0f56aa9716b898ec8" - addr1EIP55 = "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8" - wanAddrLowercase = "0xae96137e0e05681ed2f5d1af272c3ee512939d0f" - wanAddrEIP55Checksum = "0xAe96137E0e05681eD2F5D1AF272C3ee512939D0F" - wanAddrEIP55ChecksumWanchain = "0xaE96137e0E05681Ed2f5d1af272c3EE512939d0f" - tests = []struct { - name, address, expectedAddress string - coinID uint - }{ - {"Ethereum", addr1, addr1EIP55, coin.ETH}, - {"Ethereum Classic", addr1, addr1EIP55, coin.ETC}, - {"POA", addr1, addr1EIP55, coin.POA}, - {"Callisto", addr1, addr1EIP55, coin.CLO}, - {"Tomochain", addr1, addr1EIP55, coin.TOMO}, - {"Thunder", addr1, addr1EIP55, coin.TT}, - {"Thunder", addr1, addr1EIP55, coin.TT}, - {"GoChain", addr1, addr1EIP55, coin.GO}, - {"Wanchain 1", wanAddrLowercase, wanAddrEIP55ChecksumWanchain, coin.WAN}, - {"Wanchain 2", wanAddrEIP55Checksum, wanAddrEIP55ChecksumWanchain, coin.WAN}, - {"Non Ethereum like chain 1", "", "", coin.TRX}, - {"Non Ethereum like chain 2", addr1, addr1, coin.BNB}, - } - ) - - t.Run("Test TestToEIP55ByCoinID", func(t *testing.T) { - for _, tt := range tests { - actual := ToEIP55ByCoinID(tt.address, tt.coinID) - assert.Equal(t, tt.expectedAddress, actual) - } - }) -} - -func TestFormatAddress(t *testing.T) { - var ( - addr1 = "0xea674fdde714fd979de3edf0f56aa9716b898ec8" - addr1EIP55 = "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8" - wanAddrLowercase = "0xae96137e0e05681ed2f5d1af272c3ee512939d0f" - wanAddrEIP55Checksum = "0xAe96137E0e05681eD2F5D1AF272C3ee512939D0F" - wanAddrEIP55ChecksumWanchain = "0xaE96137e0E05681Ed2f5d1af272c3EE512939d0f" - tests = []struct { - name, address, expectedAddress string - coinID uint - }{ - {"Ethereum", addr1, addr1EIP55, coin.ETH}, - {"Ethereum Classic", addr1, addr1EIP55, coin.ETC}, - {"POA", addr1, addr1EIP55, coin.POA}, - {"Callisto", addr1, addr1EIP55, coin.CLO}, - {"Tomochain", addr1, addr1EIP55, coin.TOMO}, - {"Thunder", addr1, addr1EIP55, coin.TT}, - {"Thunder", addr1, addr1EIP55, coin.TT}, - {"GoChain", addr1, addr1EIP55, coin.GO}, - {"Wanchain 1", wanAddrLowercase, wanAddrEIP55ChecksumWanchain, coin.WAN}, - {"Wanchain 2", wanAddrEIP55Checksum, wanAddrEIP55ChecksumWanchain, coin.WAN}, - {"Non Ethereum like chain 1", "", "", coin.TRX}, - {"Non Ethereum like chain 2", addr1, addr1, coin.BNB}, - {"Bitcoin cash case with prefix", "bitcoincash:qzzhnrz43k86r3shen9se96uqeu5mxe0msa2auy85w", "qzzhnrz43k86r3shen9se96uqeu5mxe0msa2auy85w", coin.BCH}, - {"Bitcoin cash case without prefix", "qr5q38d4g02u976jtl7s2ygsewlpaaaylsp2jm6wpf", "qr5q38d4g02u976jtl7s2ygsewlpaaaylsp2jm6wpf", coin.BCH}, - {"Bitcoin cash case without prefix", "qr5q38d4g02u976jtl7s2ygsewlpaaaylsp2jm6wpf", "qr5q38d4g02u976jtl7s2ygsewlpaaaylsp2jm6wpf", coin.BTC}, - } - ) - - t.Run("Test TestToEIP55ByCoinID", func(t *testing.T) { - for _, tt := range tests { - actual := FormatAddress(tt.address, tt.coinID) - assert.Equal(t, tt.expectedAddress, actual) - } - }) -} - -func TestUnprefixedAddress(t *testing.T) { - address, id, ok := UnprefixedAddress("60_a") - assert.Equal(t, "a", address) - assert.Equal(t, uint(60), id) - assert.True(t, ok) -} - -func TestPrefixedAddress(t *testing.T) { - address := PrefixedAddress(60, "a") - assert.Equal(t, "60_a", address) -} diff --git a/pkg/blockatlas/client.go b/pkg/blockatlas/client.go deleted file mode 100644 index fb2fce3c6..000000000 --- a/pkg/blockatlas/client.go +++ /dev/null @@ -1,137 +0,0 @@ -package blockatlas - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "strings" - "time" -) - -type Request struct { - BaseUrl string - Headers map[string]string - HttpClient *http.Client - ErrorHandler func(res *http.Response, uri string) error -} - -func (r *Request) SetTimeout(seconds time.Duration) { - r.HttpClient.Timeout = time.Second * seconds -} - -func InitClient(baseUrl string) Request { - return Request{ - Headers: make(map[string]string), - HttpClient: DefaultClient, - ErrorHandler: DefaultErrorHandler, - BaseUrl: baseUrl, - } -} - -func InitJSONClient(baseUrl string) Request { - headers := map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - } - return Request{ - Headers: headers, - HttpClient: DefaultClient, - ErrorHandler: DefaultErrorHandler, - BaseUrl: baseUrl, - } -} - -var DefaultClient = &http.Client{ - Timeout: time.Second * 15, -} - -var DefaultErrorHandler = func(res *http.Response, uri string) error { - return nil -} - -func (r *Request) GetWithContext(result interface{}, path string, query url.Values, ctx context.Context) error { - var queryStr = "" - if query != nil { - queryStr = query.Encode() - } - uri := strings.Join([]string{r.GetBase(path), queryStr}, "?") - return r.Execute("GET", uri, nil, result, ctx) -} - -func (r *Request) Get(result interface{}, path string, query url.Values) error { - var queryStr = "" - if query != nil { - queryStr = query.Encode() - } - uri := strings.Join([]string{r.GetBase(path), queryStr}, "?") - return r.Execute("GET", uri, nil, result, context.Background()) -} - -func (r *Request) Post(result interface{}, path string, body interface{}) error { - buf, err := GetBody(body) - if err != nil { - return err - } - uri := r.GetBase(path) - return r.Execute("POST", uri, buf, result, context.Background()) -} - -func (r *Request) PostWithContext(result interface{}, path string, body interface{}, ctx context.Context) error { - buf, err := GetBody(body) - if err != nil { - return err - } - uri := r.GetBase(path) - return r.Execute("POST", uri, buf, result, ctx) -} - -func (r *Request) Execute(method string, url string, body io.Reader, result interface{}, ctx context.Context) error { - req, err := http.NewRequest(method, url, body) - if err != nil { - return err - } - - for key, value := range r.Headers { - req.Header.Set(key, value) - } - - res, err := r.HttpClient.Do(req) - if err != nil { - return err - } - - err = r.ErrorHandler(res, url) - if err != nil { - return err - } - defer res.Body.Close() - b, err := ioutil.ReadAll(res.Body) - if err != nil { - return err - } - err = json.Unmarshal(b, result) - if err != nil { - return err - } - return err -} - -func (r *Request) GetBase(path string) string { - if path == "" { - return r.BaseUrl - } - return fmt.Sprintf("%s/%s", r.BaseUrl, path) -} - -func GetBody(body interface{}) (buf io.ReadWriter, err error) { - if body != nil { - buf = new(bytes.Buffer) - err = json.NewEncoder(buf).Encode(body) - } - return -} diff --git a/pkg/blockatlas/clientcache.go b/pkg/blockatlas/clientcache.go deleted file mode 100644 index 21682ab81..000000000 --- a/pkg/blockatlas/clientcache.go +++ /dev/null @@ -1,136 +0,0 @@ -package blockatlas - -import ( - "context" - "crypto/sha1" - "encoding/base64" - "encoding/json" - "errors" - "github.com/patrickmn/go-cache" - log "github.com/sirupsen/logrus" - "net/url" - "strings" - "sync" - "time" -) - -var ( - memoryCache *memCache -) - -func init() { - memoryCache = &memCache{cache: cache.New(5*time.Minute, 5*time.Minute)} -} - -type memCache struct { - sync.RWMutex - cache *cache.Cache -} - -func (r *Request) PostWithCache(result interface{}, path string, body interface{}, cache time.Duration) error { - key := r.generateKey(path, nil, body) - err := memoryCache.getCache(key, result) - if err == nil { - return nil - } - - err = r.Post(result, path, body) - if err != nil { - return err - } - memoryCache.setCache(key, result, cache) - return err -} - -func (r *Request) PostWithCacheAndContext(result interface{}, path string, body interface{}, cache time.Duration, ctx context.Context) error { - key := r.generateKey(path, nil, body) - err := memoryCache.getCache(key, result) - if err == nil { - return nil - } - - err = r.PostWithContext(result, path, body, ctx) - if err != nil { - return err - } - memoryCache.setCache(key, result, cache) - return err -} - -func (r *Request) GetWithCache(result interface{}, path string, query url.Values, cache time.Duration) error { - key := r.generateKey(path, query, nil) - err := memoryCache.getCache(key, result) - if err == nil { - return nil - } - - err = r.Get(result, path, query) - if err != nil { - return err - } - memoryCache.setCache(key, result, cache) - return err -} - -func (r *Request) GetWithCacheAndContext(result interface{}, path string, query url.Values, cache time.Duration, ctx context.Context) error { - key := r.generateKey(path, query, nil) - err := memoryCache.getCache(key, result) - if err == nil { - return nil - } - - err = r.Get(result, path, query) - if err != nil { - return err - } - memoryCache.setCache(key, result, cache) - return err -} - -//nolint -func (mc *memCache) deleteCache(key string) { - mc.RLock() - defer mc.RUnlock() - memoryCache.cache.Delete(key) -} - -func (mc *memCache) setCache(key string, value interface{}, duration time.Duration) { - mc.RLock() - defer mc.RUnlock() - b, err := json.Marshal(value) - if err != nil { - log.Error(errors.New(err.Error() + " client cache cannot marshal cache object")) - return - } - memoryCache.cache.Set(key, b, duration) -} - -func (mc *memCache) getCache(key string, value interface{}) error { - c, ok := mc.cache.Get(key) - if !ok { - return errors.New("validator cache: invalid cache key") - } - r, ok := c.([]byte) - if !ok { - return errors.New("validator cache: failed to cast cache to bytes") - } - err := json.Unmarshal(r, value) - if err != nil { - return errors.New(err.Error() + " not found") - } - return nil -} - -func (r *Request) generateKey(path string, query url.Values, body interface{}) string { - var queryStr = "" - if query != nil { - queryStr = query.Encode() - } - requestUrl := strings.Join([]string{r.GetBase(path), queryStr}, "?") - var b []byte - if body != nil { - b, _ = json.Marshal(body) - } - hash := sha1.Sum(append([]byte(requestUrl), b...)) - return base64.URLEncoding.EncodeToString(hash[:]) -} diff --git a/pkg/blockatlas/clientcache_test.go b/pkg/blockatlas/clientcache_test.go deleted file mode 100644 index 8cf455cd7..000000000 --- a/pkg/blockatlas/clientcache_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package blockatlas - -import ( - "net/url" - "testing" -) - -func TestRequest_generateKey(t *testing.T) { - type args struct { - baseUrl string - path string - query url.Values - body interface{} - } - tests := []struct { - name string - args args - want string - }{ - { - name: "test cosmos key without params", - args: args{ - baseUrl: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos", - path: "validators/list.json", - }, - want: "ukpgy7t9m_vLHvyQL82smBoTov4=", - }, - { - name: "test cosmos key with params", - args: args{ - baseUrl: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos", - path: "validators/list.json", - query: url.Values{"address": {"TQZskDJJRGAHifeKoQ7wLey42iGvwp3"}, "visible": {"false"}}, - }, - want: "jkkaXhzkelj5l3WE_B57Q1IY0Qo=", - }, - {name: "test tron key without params ", - args: args{ - baseUrl: "https://api.trongrid.io", - path: "wallet/getaccount", - }, - want: "PIoOx2azFYta4KMAtt0lttrqquM=", - }, - {name: "test tron key with params 1", - args: args{ - baseUrl: "https://api.trongrid.io", - path: "wallet/getaccount", - body: struct { - Address string `json:"address"` - Visible bool `json:"visible"` - }{Address: "TQZskDJJRGAHifeKoQ7wLC4QDyB2iGvwp2", Visible: true}, - }, - want: "h0noiR5a4M_RGQBH7805sgGl_HE=", - }, - {name: "test tron key with params 2", - args: args{ - baseUrl: "https://api.trongrid.io", - path: "wallet/getaccount", - body: struct { - Address string `json:"address"` - Visible bool `json:"visible"` - }{Address: "TQZskDJJRGAHifeKoQ7wLey42iGvwp3", Visible: false}, - }, - want: "Admv3wAXHkirPi4SaIXimDgLbow=", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := &Request{BaseUrl: tt.args.baseUrl} - if got := r.generateKey(tt.args.path, tt.args.query, tt.args.body); got != tt.want { - t.Errorf("generateKey() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/blockatlas/jsonrpc.go b/pkg/blockatlas/jsonrpc.go deleted file mode 100644 index b669cc0fe..000000000 --- a/pkg/blockatlas/jsonrpc.go +++ /dev/null @@ -1,111 +0,0 @@ -package blockatlas - -import ( - "context" - "encoding/json" - - "errors" -) - -var ( - requestId = int64(0) -) - -const ( - JsonRpcVersion = "2.0" -) - -type ( - RpcRequests []*RpcRequest - - RpcRequest struct { - JsonRpc string `json:"jsonrpc"` - Method string `json:"method"` - Params interface{} `json:"params,omitempty"` - Id int64 `json:"id,omitempty"` - } - - RpcResponse struct { - JsonRpc string `json:"jsonrpc"` - Error *RpcError `json:"error,omitempty"` - Result interface{} `json:"result,omitempty"` - Id int64 `json:"id,omitempty"` - } - - RpcError struct { - Code int `json:"code"` - Message string `json:"message"` - } -) - -func (r *RpcResponse) GetObject(toType interface{}) error { - js, err := json.Marshal(r.Result) - if err != nil { - return err - } - - err = json.Unmarshal(js, toType) - if err != nil { - return err - } - return nil -} - -func (r *Request) RpcCall(result interface{}, method string, params interface{}) error { - - req := &RpcRequest{JsonRpc: JsonRpcVersion, Method: method, Params: params, Id: genId()} - var resp *RpcResponse - err := r.Post(&resp, "", req) - if err != nil { - return err - } - if resp.Error != nil { - return errors.New("RPC Call error") - } - return resp.GetObject(result) -} - -func (r *Request) RpcCallWithContext(result interface{}, method string, params interface{}, ctx context.Context) error { - - req := &RpcRequest{JsonRpc: JsonRpcVersion, Method: method, Params: params, Id: genId()} - var resp *RpcResponse - err := r.PostWithContext(&resp, "", req, ctx) - if err != nil { - return err - } - if resp.Error != nil { - return errors.New("RPC Call error") - } - return resp.GetObject(result) -} - -func (r *Request) RpcBatchCallWithContext(requests RpcRequests, ctx context.Context) ([]RpcResponse, error) { - var resp []RpcResponse - err := r.PostWithContext(&resp, "", requests.fillDefaultValues(), ctx) - if err != nil { - return nil, err - } - return resp, nil -} - -func (r *Request) RpcBatchCall(requests RpcRequests) ([]RpcResponse, error) { - var resp []RpcResponse - err := r.Post(&resp, "", requests.fillDefaultValues()) - if err != nil { - return nil, err - } - return resp, nil -} - -func (rs RpcRequests) fillDefaultValues() RpcRequests { - for _, r := range rs { - r.JsonRpc = JsonRpcVersion - r.Id = genId() - } - return rs -} - -func genId() int64 { - requestId += 1 - return requestId -} diff --git a/pkg/blockatlas/jsonrpc_test.go b/pkg/blockatlas/jsonrpc_test.go deleted file mode 100644 index 0ee82a211..000000000 --- a/pkg/blockatlas/jsonrpc_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package blockatlas - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestRpcRequests_fillDefaultValues(t *testing.T) { - tests := []struct { - name string - rs RpcRequests - want RpcRequests - }{ - { - "test 1", - RpcRequests{{Method: "method1", Params: "params1"}}, - RpcRequests{{Method: "method1", Params: "params1", JsonRpc: JsonRpcVersion, Id: 1}}, - }, { - "test 2", - RpcRequests{ - {Method: "method1", Params: "params1"}, {Method: "method2", Params: "params2"}}, - RpcRequests{ - {Method: "method1", Params: "params1", JsonRpc: JsonRpcVersion, Id: 2}, - {Method: "method2", Params: "params2", JsonRpc: JsonRpcVersion, Id: 3}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := tt.rs.fillDefaultValues() - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/platform/aeternity/base.go b/platform/aeternity/base.go index ea445b5e8..2ee49143b 100644 --- a/platform/aeternity/base.go +++ b/platform/aeternity/base.go @@ -1,7 +1,7 @@ package aeternity import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/aeternity/client.go b/platform/aeternity/client.go index 89dbc0a77..a6fe45276 100644 --- a/platform/aeternity/client.go +++ b/platform/aeternity/client.go @@ -2,13 +2,14 @@ package aeternity import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" "strconv" + + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxs(address string, limit int) ([]Transaction, error) { diff --git a/platform/aion/base.go b/platform/aion/base.go index 6b5e2db3f..86b6f6b62 100644 --- a/platform/aion/base.go +++ b/platform/aion/base.go @@ -1,7 +1,7 @@ package aion import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/aion/client.go b/platform/aion/client.go index b82e8445f..68bf4dbee 100644 --- a/platform/aion/client.go +++ b/platform/aion/client.go @@ -1,13 +1,14 @@ package aion import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" "strconv" + + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxsOfAddress(address string, num int) (txPage *TxPage, err error) { diff --git a/platform/algorand/client.go b/platform/algorand/client.go index 084a6fd7f..cc30c32fc 100644 --- a/platform/algorand/client.go +++ b/platform/algorand/client.go @@ -5,17 +5,18 @@ import ( "strconv" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func InitClient(url, apiKey string) Client { return Client{ - Request: blockatlas.Request{ - HttpClient: blockatlas.DefaultClient, - ErrorHandler: blockatlas.DefaultErrorHandler, + Request: client.Request{ + HttpClient: client.DefaultClient, + ErrorHandler: client.DefaultErrorHandler, Headers: map[string]string{"X-Indexer-API-Token": apiKey}, BaseUrl: url, }, diff --git a/platform/bitcoin/base.go b/platform/bitcoin/base.go index ae0a2f871..1073972ab 100644 --- a/platform/bitcoin/base.go +++ b/platform/bitcoin/base.go @@ -1,7 +1,7 @@ package bitcoin import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/bitcoin/client.go b/platform/bitcoin/client.go index 6e3df4753..d6b05c55d 100644 --- a/platform/bitcoin/client.go +++ b/platform/bitcoin/client.go @@ -6,10 +6,11 @@ import ( "strconv" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTransactions(address string) (transactions TransactionsList, err error) { diff --git a/platform/cosmos/base.go b/platform/cosmos/base.go index b5ecc3a0c..a7227e292 100644 --- a/platform/cosmos/base.go +++ b/platform/cosmos/base.go @@ -1,7 +1,7 @@ package cosmos import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/cosmos/client.go b/platform/cosmos/client.go index 78c9b1122..cf4b0ed0f 100644 --- a/platform/cosmos/client.go +++ b/platform/cosmos/client.go @@ -2,16 +2,17 @@ package cosmos import ( "fmt" - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" "strconv" "time" + + log "github.com/sirupsen/logrus" + "github.com/trustwallet/golibs/client" ) // Client - the HTTP client type Client struct { - blockatlas.Request + client.Request } // GetAddrTxs - get all ATOM transactions for a given address diff --git a/platform/elrond/base.go b/platform/elrond/base.go index c1833c64c..55204675d 100644 --- a/platform/elrond/base.go +++ b/platform/elrond/base.go @@ -1,7 +1,7 @@ package elrond import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{blockatlas.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api)}, } } diff --git a/platform/elrond/client.go b/platform/elrond/client.go index b5e3e0b94..d935feda2 100644 --- a/platform/elrond/client.go +++ b/platform/elrond/client.go @@ -6,10 +6,11 @@ import ( "net/url" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) CurrentBlockNumber() (num int64, err error) { diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index 7a413802d..fa26e3ddd 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -1,10 +1,10 @@ package ethereum import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/ethereum/blockbook" "github.com/trustwallet/blockatlas/platform/ethereum/collection" "github.com/trustwallet/blockatlas/platform/ethereum/trustray" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -19,7 +19,7 @@ func Init(coinType uint, api, rpc string) *Platform { return &Platform{ CoinIndex: coinType, RpcURL: rpc, - client: &trustray.Client{Request: blockatlas.InitClient(api)}, + client: &trustray.Client{Request: client.InitClient(api)}, } } @@ -27,13 +27,13 @@ func InitWithBlockbook(coinType uint, blockbookApi, rpc string) *Platform { return &Platform{ CoinIndex: coinType, RpcURL: rpc, - client: &blockbook.Client{Request: blockatlas.InitClient(blockbookApi)}, + client: &blockbook.Client{Request: client.InitClient(blockbookApi)}, } } func InitWithCollection(coinType uint, rpc, blockbookApi, collectionApi, collectionKey string) *Platform { platform := InitWithBlockbook(coinType, blockbookApi, rpc) - platform.collectible = collection.Client{Request: blockatlas.InitClient(collectionApi)} + platform.collectible = collection.Client{Request: client.InitClient(collectionApi)} platform.collectible.Headers["X-API-KEY"] = collectionKey return platform } diff --git a/platform/ethereum/blockbook/client.go b/platform/ethereum/blockbook/client.go index ea9717e4c..c654652a9 100644 --- a/platform/ethereum/blockbook/client.go +++ b/platform/ethereum/blockbook/client.go @@ -4,11 +4,11 @@ import ( "fmt" "net/url" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxs(address string) (*Page, error) { diff --git a/platform/ethereum/blockbook/transaction.go b/platform/ethereum/blockbook/transaction.go index 89f7f2e04..3a641f136 100644 --- a/platform/ethereum/blockbook/transaction.go +++ b/platform/ethereum/blockbook/transaction.go @@ -3,8 +3,8 @@ package blockbook import ( "strings" - Address "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" + Address "github.com/trustwallet/golibs/address" "github.com/trustwallet/golibs/coin" ) @@ -24,12 +24,17 @@ func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas. return NormalizePage(page, address, token, coinIndex), nil } -func NormalizePage(srcPage *Page, address, token string, coinIndex uint) blockatlas.TxPage { - var txs []blockatlas.Tx - normalizedAddr := Address.EIP55Checksum(address) +func NormalizePage(srcPage *Page, address, token string, coinIndex uint) (txs blockatlas.TxPage) { + normalizedAddr, err := Address.EIP55Checksum(address) + if err != nil { + return + } var normalizedToken string if token != "" { - normalizedToken = Address.EIP55Checksum(token) + normalizedToken, err = Address.EIP55Checksum(token) + if err != nil { + return + } } for _, srcTx := range srcPage.Transactions { tx := normalizeTxWithAddress(&srcTx, normalizedAddr, normalizedToken, coinIndex) diff --git a/platform/ethereum/collection/client.go b/platform/ethereum/collection/client.go index f9c785758..c2c646a71 100644 --- a/platform/ethereum/collection/client.go +++ b/platform/ethereum/collection/client.go @@ -4,11 +4,11 @@ import ( "net/url" "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c Client) GetCollections(owner string) (page []Collection, err error) { diff --git a/platform/ethereum/trustray/client.go b/platform/ethereum/trustray/client.go index fa117deb5..f1261438f 100644 --- a/platform/ethereum/trustray/client.go +++ b/platform/ethereum/trustray/client.go @@ -4,11 +4,11 @@ import ( "fmt" "net/url" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxs(address string) (*Page, error) { diff --git a/platform/ethereum/trustray/transaction.go b/platform/ethereum/trustray/transaction.go index 2e52ecf75..274ea49e5 100644 --- a/platform/ethereum/trustray/transaction.go +++ b/platform/ethereum/trustray/transaction.go @@ -3,8 +3,8 @@ package trustray import ( "math/big" - "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/address" "github.com/trustwallet/golibs/coin" ) @@ -70,10 +70,14 @@ func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas // Token transfer transaction if op.Type == blockatlas.TxTokenTransfer && op.Contract != nil { tokenTx := baseTx + tokenId, err := address.ToEIP55ByCoinID(op.Contract.Address, coinIndex) + if err != nil { + return + } tokenTx.Meta = blockatlas.TokenTransfer{ Name: op.Contract.Name, Symbol: op.Contract.Symbol, - TokenID: address.ToEIP55ByCoinID(op.Contract.Address, coinIndex), + TokenID: tokenId, Decimals: op.Contract.Decimals, Value: blockatlas.Amount(op.Value), From: op.From, @@ -99,13 +103,20 @@ func extractBase(srcTx *Doc, coinIndex uint) (base blockatlas.Tx, ok bool) { } fee := calcFee(srcTx.GasPrice, srcTx.GasUsed) - + from, err := address.ToEIP55ByCoinID(srcTx.From, coinIndex) + if err != nil { + return base, false + } + to, err := address.ToEIP55ByCoinID(srcTx.To, coinIndex) + if err != nil { + return base, false + } base = blockatlas.Tx{ ID: srcTx.ID, Coin: coinIndex, Fee: blockatlas.Amount(fee), - From: address.ToEIP55ByCoinID(srcTx.From, coinIndex), - To: address.ToEIP55ByCoinID(srcTx.To, coinIndex), + From: from, + To: to, Date: srcTx.Timestamp, Block: srcTx.BlockNumber, Status: status, diff --git a/platform/filecoin/base.go b/platform/filecoin/base.go index 51dda72b7..38f3930cb 100644 --- a/platform/filecoin/base.go +++ b/platform/filecoin/base.go @@ -1,9 +1,9 @@ package filecoin import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/filecoin/explorer" "github.com/trustwallet/blockatlas/platform/filecoin/rpc" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -14,8 +14,8 @@ type Platform struct { func Init(api, explorerApi string) *Platform { p := &Platform{ - client: rpc.Client{Request: blockatlas.InitClient(api)}, - explorer: explorer.Client{Request: blockatlas.InitClient(explorerApi)}, + client: rpc.Client{Request: client.InitClient(api)}, + explorer: explorer.Client{Request: client.InitClient(explorerApi)}, } return p } diff --git a/platform/filecoin/explorer/client.go b/platform/filecoin/explorer/client.go index 339db58fb..f3c650bdf 100644 --- a/platform/filecoin/explorer/client.go +++ b/platform/filecoin/explorer/client.go @@ -5,11 +5,11 @@ import ( "net/url" "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c Client) GetMessagesByAddress(address string, pageSize int) (res Response, err error) { diff --git a/platform/filecoin/rpc/client.go b/platform/filecoin/rpc/client.go index 0865e0195..321ca4149 100644 --- a/platform/filecoin/rpc/client.go +++ b/platform/filecoin/rpc/client.go @@ -1,11 +1,9 @@ package rpc -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/client" type Client struct { - blockatlas.Request + client.Request } func (c Client) GetBlockHeight() (ChainHeadResponse, error) { diff --git a/platform/fio/base.go b/platform/fio/base.go index aad0f32aa..56dff74de 100644 --- a/platform/fio/base.go +++ b/platform/fio/base.go @@ -1,7 +1,7 @@ package fio import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api)}, } } diff --git a/platform/fio/client.go b/platform/fio/client.go index 455cd811e..4b64c4eb6 100644 --- a/platform/fio/client.go +++ b/platform/fio/client.go @@ -1,12 +1,10 @@ package fio -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/client" // Client for FIO API type Client struct { - blockatlas.Request + client.Request } func (c *Client) getTransactions(account string) (actions []Action, error error) { diff --git a/platform/harmony/base.go b/platform/harmony/base.go index 9b5b073d7..ba1323014 100644 --- a/platform/harmony/base.go +++ b/platform/harmony/base.go @@ -1,7 +1,7 @@ package harmony import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{blockatlas.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api)}, } return p } diff --git a/platform/harmony/client.go b/platform/harmony/client.go index 3b069cf1a..e54adfd51 100644 --- a/platform/harmony/client.go +++ b/platform/harmony/client.go @@ -5,12 +5,12 @@ import ( "strconv" log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/numbers" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxsOfAddress(address string) (txPage *TxResult, err error) { diff --git a/platform/icon/base.go b/platform/icon/base.go index 250edd7a6..09c84794b 100644 --- a/platform/icon/base.go +++ b/platform/icon/base.go @@ -1,7 +1,7 @@ package icon import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/icon/client.go b/platform/icon/client.go index 2e296a2de..25f7fa04e 100644 --- a/platform/icon/client.go +++ b/platform/icon/client.go @@ -1,13 +1,15 @@ package icon import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" "strconv" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetAddressTransactions(address string) ([]Tx, error) { diff --git a/platform/iotex/base.go b/platform/iotex/base.go index fbd9fabec..610deb3ed 100644 --- a/platform/iotex/base.go +++ b/platform/iotex/base.go @@ -1,7 +1,7 @@ package iotex import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/iotex/client.go b/platform/iotex/client.go index 88af36324..86eaf15a9 100644 --- a/platform/iotex/client.go +++ b/platform/iotex/client.go @@ -2,14 +2,16 @@ package iotex import ( "fmt" - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" "strconv" + + log "github.com/sirupsen/logrus" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetLatestBlock() (int64, error) { diff --git a/platform/kava/base.go b/platform/kava/base.go index 2552186bf..51c5bfa3f 100644 --- a/platform/kava/base.go +++ b/platform/kava/base.go @@ -1,7 +1,7 @@ package kava import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/kava/client.go b/platform/kava/client.go index 21b25f3fa..6359b0400 100644 --- a/platform/kava/client.go +++ b/platform/kava/client.go @@ -2,16 +2,17 @@ package kava import ( "fmt" - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" "strconv" "time" + + log "github.com/sirupsen/logrus" + "github.com/trustwallet/golibs/client" ) // Client - the HTTP client type Client struct { - blockatlas.Request + client.Request } // GetAddrTxs - get all KAVA transactions for a given address diff --git a/platform/nano/base.go b/platform/nano/base.go index d76b22c1b..84edf3c0f 100644 --- a/platform/nano/base.go +++ b/platform/nano/base.go @@ -1,7 +1,7 @@ package nano import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{blockatlas.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api)}, } return p } diff --git a/platform/nano/client.go b/platform/nano/client.go index 9d8d86696..655e6a6ec 100644 --- a/platform/nano/client.go +++ b/platform/nano/client.go @@ -4,10 +4,11 @@ import ( "strconv" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetAccountHistory(address string) (history AccountHistory, err error) { diff --git a/platform/near/base.go b/platform/near/base.go index 04828078b..e373f55a6 100644 --- a/platform/near/base.go +++ b/platform/near/base.go @@ -1,7 +1,7 @@ package near import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } return p } diff --git a/platform/near/client.go b/platform/near/client.go index f39de7d88..c289b3ea1 100644 --- a/platform/near/client.go +++ b/platform/near/client.go @@ -1,9 +1,7 @@ package near -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/client" type Client struct { - blockatlas.Request + client.Request } diff --git a/platform/nebulas/base.go b/platform/nebulas/base.go index a165ba77a..bb2cd9ea8 100644 --- a/platform/nebulas/base.go +++ b/platform/nebulas/base.go @@ -1,7 +1,7 @@ package nebulas import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/nebulas/client.go b/platform/nebulas/client.go index d9ad319de..15790dbd8 100644 --- a/platform/nebulas/client.go +++ b/platform/nebulas/client.go @@ -1,15 +1,16 @@ package nebulas import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" "strconv" + + "github.com/trustwallet/golibs/client" ) const TxTypeBinary = "binary" type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxs(address string, page int) ([]Transaction, error) { diff --git a/platform/nimiq/base.go b/platform/nimiq/base.go index 5c845c37b..ddb988fbc 100644 --- a/platform/nimiq/base.go +++ b/platform/nimiq/base.go @@ -1,7 +1,7 @@ package nimiq import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api)}, } } diff --git a/platform/nimiq/client.go b/platform/nimiq/client.go index 7a292dac5..4d91af9ad 100644 --- a/platform/nimiq/client.go +++ b/platform/nimiq/client.go @@ -1,12 +1,14 @@ package nimiq import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "strconv" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxsOfAddress(address string) (tx []Tx, err error) { diff --git a/platform/ontology/base.go b/platform/ontology/base.go index 157f0dd68..cf279458e 100644 --- a/platform/ontology/base.go +++ b/platform/ontology/base.go @@ -1,7 +1,7 @@ package ontology import ( - blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/ontology/client.go b/platform/ontology/client.go index 53445a4ed..470ec6cef 100644 --- a/platform/ontology/client.go +++ b/platform/ontology/client.go @@ -2,12 +2,13 @@ package ontology import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" + + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetBalances(address string) (balances BalancesResult, err error) { diff --git a/platform/polkadot/base.go b/platform/polkadot/base.go index c847a757c..3f5eb8edc 100644 --- a/platform/polkadot/base.go +++ b/platform/polkadot/base.go @@ -1,7 +1,7 @@ package polkadot import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{blockatlas.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api)}, } } diff --git a/platform/polkadot/client.go b/platform/polkadot/client.go index 125f1c914..fd931d267 100644 --- a/platform/polkadot/client.go +++ b/platform/polkadot/client.go @@ -4,10 +4,11 @@ import ( "strconv" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTransfersOfAddress(address string) ([]Transfer, error) { diff --git a/platform/ripple/base.go b/platform/ripple/base.go index 339fd6899..56a2c018a 100644 --- a/platform/ripple/base.go +++ b/platform/ripple/base.go @@ -1,7 +1,7 @@ package ripple import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/ripple/client.go b/platform/ripple/client.go index 6900f4a04..f297a74e9 100644 --- a/platform/ripple/client.go +++ b/platform/ripple/client.go @@ -2,12 +2,13 @@ package ripple import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" + + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxsOfAddress(address string) ([]Tx, error) { diff --git a/platform/solana/base.go b/platform/solana/base.go index 6dfa983b9..dcdb5f7e4 100644 --- a/platform/solana/base.go +++ b/platform/solana/base.go @@ -1,7 +1,7 @@ package solana import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{blockatlas.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api)}, } return p } diff --git a/platform/solana/client.go b/platform/solana/client.go index 2021510f0..524bc9c34 100644 --- a/platform/solana/client.go +++ b/platform/solana/client.go @@ -1,13 +1,13 @@ package solana import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) const stakeProgramId = "Stake11111111111111111111111111111111111111" type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetCurrentVoteAccounts() (validators []VoteAccount, err error) { @@ -58,9 +58,9 @@ func (c *Client) GetTransactions(address string) ([]ConfirmedTransaction, error) } // build batch request - requests := make(blockatlas.RpcRequests, 0) + requests := make(client.RpcRequests, 0) for _, sig := range signatures { - requests = append(requests, &blockatlas.RpcRequest{ + requests = append(requests, &client.RpcRequest{ Method: "getConfirmedTransaction", Params: []string{ sig.Signature, diff --git a/platform/solana/transaction_test.go b/platform/solana/transaction_test.go index 0b831cb08..c31a1231e 100644 --- a/platform/solana/transaction_test.go +++ b/platform/solana/transaction_test.go @@ -9,7 +9,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/mock" ) @@ -22,8 +22,8 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { data["/"] = func(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusOK) - var r blockatlas.RpcRequest - var rs []blockatlas.RpcRequest + var r client.RpcRequest + var rs []client.RpcRequest var response string buf := new(bytes.Buffer) diff --git a/platform/stellar/base.go b/platform/stellar/base.go index 4fe753e66..98e073408 100644 --- a/platform/stellar/base.go +++ b/platform/stellar/base.go @@ -1,7 +1,7 @@ package stellar import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/stellar/client.go b/platform/stellar/client.go index 3548baa17..85c468a5e 100644 --- a/platform/stellar/client.go +++ b/platform/stellar/client.go @@ -3,12 +3,13 @@ package stellar import ( "errors" "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" + + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxsOfAddress(address string) ([]Payment, error) { diff --git a/platform/tezos/base.go b/platform/tezos/base.go index 459d75878..e9e92317b 100644 --- a/platform/tezos/base.go +++ b/platform/tezos/base.go @@ -1,7 +1,7 @@ package tezos import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -12,8 +12,8 @@ type Platform struct { func Init(api, rpc string) *Platform { p := &Platform{ - client: Client{blockatlas.InitClient(api)}, - rpcClient: RpcClient{blockatlas.InitClient(rpc)}, + client: Client{client.InitClient(api)}, + rpcClient: RpcClient{client.InitClient(rpc)}, } p.client.SetTimeout(35) return p diff --git a/platform/tezos/client.go b/platform/tezos/client.go index d47564454..5a07f7456 100644 --- a/platform/tezos/client.go +++ b/platform/tezos/client.go @@ -2,13 +2,14 @@ package tezos import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" "strings" + + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxsOfAddress(address string, txType []string) (txs ExplorerAccount, err error) { diff --git a/platform/tezos/rpc.go b/platform/tezos/rpc.go index 1e068888c..e1033358f 100644 --- a/platform/tezos/rpc.go +++ b/platform/tezos/rpc.go @@ -2,12 +2,13 @@ package tezos import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "time" + + "github.com/trustwallet/golibs/client" ) type RpcClient struct { - blockatlas.Request + client.Request } type PeriodType string diff --git a/platform/theta/base.go b/platform/theta/base.go index 4d1a9e731..5e8053c1c 100644 --- a/platform/theta/base.go +++ b/platform/theta/base.go @@ -1,7 +1,7 @@ package theta import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/theta/client.go b/platform/theta/client.go index 54653e582..45f48eb43 100644 --- a/platform/theta/client.go +++ b/platform/theta/client.go @@ -2,12 +2,13 @@ package theta import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" + + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) FetchAddressTransactions(address string) ([]Tx, error) { diff --git a/platform/tron/address.go b/platform/tron/address.go new file mode 100644 index 000000000..086bc16c8 --- /dev/null +++ b/platform/tron/address.go @@ -0,0 +1,23 @@ +package tron + +import ( + "crypto/sha256" + "encoding/hex" + + "github.com/mr-tron/base58" +) + +// HexToAddress converts a hex representation of a Tron address +// into a Base58 string with a 4 byte checksum. +func HexToAddress(hexAddr string) (b58 string, err error) { + bytes, err := hex.DecodeString(hexAddr) + if err != nil { + return "", err + } + var checksum [32]byte + checksum = sha256.Sum256(bytes) + checksum = sha256.Sum256(checksum[:]) + bytes = append(bytes, checksum[:4]...) + b58 = base58.EncodeAlphabet(bytes, base58.BTCAlphabet) + return +} diff --git a/platform/tron/address_test.go b/platform/tron/address_test.go new file mode 100644 index 000000000..d8c6e0fdf --- /dev/null +++ b/platform/tron/address_test.go @@ -0,0 +1,31 @@ +package tron + +import "testing" + +func TestHexToAddress(t *testing.T) { + tests := []struct { + name string + hexAddr string + want string + wantErr bool + }{ + { + name: "Test hex to base58 address", + hexAddr: "4182dd6b9966724ae2fdc79b416c7588da67ff1b35", + want: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotB58, err := HexToAddress(tt.hexAddr) + if (err != nil) != tt.wantErr { + t.Errorf("HexToAddress() error = %v, wantErr %v", err, tt.wantErr) + return + } + if gotB58 != tt.want { + t.Errorf("HexToAddress() = %v, want %v", gotB58, tt.want) + } + }) + } +} diff --git a/platform/tron/base.go b/platform/tron/base.go index 361ac206c..d43fa810a 100644 --- a/platform/tron/base.go +++ b/platform/tron/base.go @@ -1,7 +1,7 @@ package tron import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -12,8 +12,8 @@ type Platform struct { func Init(api, explorerApi string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, - explorerClient: ExplorerClient{blockatlas.InitClient(explorerApi)}, + client: Client{client.InitClient(api)}, + explorerClient: ExplorerClient{client.InitClient(explorerApi)}, } } diff --git a/platform/tron/client.go b/platform/tron/client.go index e60f9f87f..89f62640f 100644 --- a/platform/tron/client.go +++ b/platform/tron/client.go @@ -2,18 +2,19 @@ package tron import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/url" "time" + + "github.com/trustwallet/golibs/client" ) type ( Client struct { - blockatlas.Request + client.Request } ExplorerClient struct { - blockatlas.Request + client.Request } ) diff --git a/platform/tron/stake.go b/platform/tron/stake.go index 3f38ed8c7..d4ae50aef 100644 --- a/platform/tron/stake.go +++ b/platform/tron/stake.go @@ -1,12 +1,12 @@ package tron import ( + "strconv" + "time" + log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/assets" - "strconv" - "time" ) const Annual = 0.74 @@ -81,7 +81,7 @@ func (p *Platform) UndelegatedBalance(address string) (string, error) { } func normalizeValidator(v Validator) (validator blockatlas.Validator, ok bool) { - a, err := address.HexToAddress(v.Address) + a, err := HexToAddress(v.Address) if err != nil { return validator, false } diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index df94fd065..f69fba527 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -2,13 +2,13 @@ package tron import ( "errors" + "strconv" + "strings" + log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/tokentype" - "strconv" - "strings" ) func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { @@ -143,11 +143,11 @@ func normalize(srcTx Tx) (*blockatlas.Tx, error) { } transfer := contract.Parameter.Value - from, err := address.HexToAddress(transfer.OwnerAddress) + from, err := HexToAddress(transfer.OwnerAddress) if err != nil { return nil, err } - to, err := address.HexToAddress(transfer.ToAddress) + to, err := HexToAddress(transfer.ToAddress) if err != nil { return nil, err } diff --git a/platform/vechain/base.go b/platform/vechain/base.go index 846f3e4a9..86444e4a7 100644 --- a/platform/vechain/base.go +++ b/platform/vechain/base.go @@ -1,7 +1,7 @@ package vechain import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api)}, } } diff --git a/platform/vechain/client.go b/platform/vechain/client.go index fe29099ff..42803b722 100644 --- a/platform/vechain/client.go +++ b/platform/vechain/client.go @@ -2,12 +2,13 @@ package vechain import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "strings" + + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetCurrentBlock() (int64, error) { diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 9e702dae1..74b65edfc 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -6,8 +6,8 @@ import ( "sync" log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/address" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/address" "github.com/trustwallet/golibs/numbers" ) @@ -93,10 +93,23 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (block if err != nil { continue } - originSender := address.EIP55Checksum(blockatlas.GetValidParameter(srcTx.Origin, srcTx.Meta.TxOrigin)) - originReceiver := address.EIP55Checksum(event.Address) - topicsFrom := address.EIP55Checksum(getRecipientAddress(event.Topics[1])) - topicsTo := address.EIP55Checksum(getRecipientAddress(event.Topics[2])) + + originSender, err := address.EIP55Checksum(blockatlas.GetValidParameter(srcTx.Origin, srcTx.Meta.TxOrigin)) + if err != nil { + continue + } + originReceiver, err := address.EIP55Checksum(event.Address) + if err != nil { + continue + } + topicsFrom, err := address.EIP55Checksum(getRecipientAddress(event.Topics[1])) + if err != nil { + continue + } + topicsTo, err := address.EIP55Checksum(getRecipientAddress(event.Topics[2])) + if err != nil { + continue + } direction, err := getTokenTransactionDirectory(originSender, topicsFrom, topicsTo) if err != nil { @@ -154,16 +167,25 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func (p *Platform) NormalizeTransaction(srcTx LogTransfer, trxId Tx, addr string) (blockatlas.Tx, error) { +func (p *Platform) NormalizeTransaction(srcTx LogTransfer, trxId Tx, addr string) (tx blockatlas.Tx, err error) { value, err := numbers.HexToDecimal(srcTx.Amount) if err != nil { - return blockatlas.Tx{}, err + return } fee := strconv.Itoa(trxId.Gas) - sender := address.EIP55Checksum(srcTx.Sender) - recipient := address.EIP55Checksum(srcTx.Recipient) - addrChecksum := address.EIP55Checksum(addr) + sender, err := address.EIP55Checksum(srcTx.Sender) + if err != nil { + return + } + recipient, err := address.EIP55Checksum(srcTx.Recipient) + if err != nil { + return + } + addrChecksum, err := address.EIP55Checksum(addr) + if err != nil { + return + } directory, err := getTransferDirectory(sender, recipient, addrChecksum) if err != nil { diff --git a/platform/waves/base.go b/platform/waves/base.go index 1471ebf01..d8374ec72 100644 --- a/platform/waves/base.go +++ b/platform/waves/base.go @@ -1,7 +1,7 @@ package waves import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{blockatlas.InitClient(api)}, + client: Client{client.InitClient(api)}, } } diff --git a/platform/waves/client.go b/platform/waves/client.go index cab7d0c5c..37c7f77a4 100644 --- a/platform/waves/client.go +++ b/platform/waves/client.go @@ -2,11 +2,12 @@ package waves import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxs(address string, limit int) ([]Transaction, error) { diff --git a/platform/zilliqa/base.go b/platform/zilliqa/base.go index 34ccbd5a0..cee31fea6 100644 --- a/platform/zilliqa/base.go +++ b/platform/zilliqa/base.go @@ -1,7 +1,7 @@ package zilliqa import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -12,8 +12,8 @@ type Platform struct { func Init(api, apiKey, rpc string) *Platform { p := &Platform{ - client: Client{blockatlas.InitClient(api)}, - rpcClient: RpcClient{blockatlas.InitClient(rpc)}, + client: Client{client.InitClient(api)}, + rpcClient: RpcClient{client.InitClient(rpc)}, } p.client.Headers["X-APIKEY"] = apiKey return p diff --git a/platform/zilliqa/client.go b/platform/zilliqa/client.go index 33295dd0a..34fc136e0 100644 --- a/platform/zilliqa/client.go +++ b/platform/zilliqa/client.go @@ -3,11 +3,11 @@ package zilliqa import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - blockatlas.Request + client.Request } func (c *Client) GetTxsOfAddress(address string) (tx []Tx, err error) { diff --git a/platform/zilliqa/model.go b/platform/zilliqa/model.go index 57ce225b1..108427931 100644 --- a/platform/zilliqa/model.go +++ b/platform/zilliqa/model.go @@ -5,7 +5,7 @@ import ( "math/big" "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type BlockTxs [][]string @@ -113,10 +113,10 @@ func (t *TxRPC) toTx(header BlockHeader) *Tx { } type BlockTxRpc struct { - JsonRpc string `json:"jsonrpc"` - Error *blockatlas.RpcError `json:"error,omitempty"` - Result BlockTxs `json:"result,omitempty"` - Id string `json:"id,omitempty"` + JsonRpc string `json:"jsonrpc"` + Error *client.RpcError `json:"error,omitempty"` + Result BlockTxs `json:"result,omitempty"` + Id string `json:"id,omitempty"` } type HashesResponse struct { diff --git a/platform/zilliqa/rpc.go b/platform/zilliqa/rpc.go index e7e141da9..3bae0be83 100644 --- a/platform/zilliqa/rpc.go +++ b/platform/zilliqa/rpc.go @@ -6,11 +6,11 @@ import ( "github.com/imroc/req" "github.com/mitchellh/mapstructure" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type RpcClient struct { - blockatlas.Request + client.Request } func (c *RpcClient) GetBlockchainInfo() (info *ChainInfo, err error) { @@ -25,8 +25,8 @@ func (c *RpcClient) GetTx(hash string) (tx TxRPC, err error) { func (c *RpcClient) GetTransactionsHashesInBlock(number int64) ([]string, error) { strNumber := strconv.FormatInt(number, 10) - requestBody := &blockatlas.RpcRequest{ - JsonRpc: blockatlas.JsonRpcVersion, + requestBody := &client.RpcRequest{ + JsonRpc: client.JsonRpcVersion, Method: "GetTransactionsForTxBlock", Params: []string{strNumber}, Id: number, @@ -54,9 +54,9 @@ func (c *RpcClient) GetTxInBlock(number int64) ([]Tx, error) { return txs, err } - var requests blockatlas.RpcRequests + var requests client.RpcRequests for _, hash := range hashes { - requests = append(requests, &blockatlas.RpcRequest{ + requests = append(requests, &client.RpcRequest{ Method: "GetTransaction", Params: []string{hash}, }) diff --git a/services/assets/client.go b/services/assets/client.go index c12b051ef..03885877a 100644 --- a/services/assets/client.go +++ b/services/assets/client.go @@ -1,9 +1,10 @@ package assets import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/coin" "time" + + "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/coin" ) const ( @@ -12,7 +13,7 @@ const ( func fetchValidatorsInfo(coin coin.Coin) (AssetValidators, error) { var results AssetValidators - request := blockatlas.InitClient(AssetsURL + coin.Handle) + request := client.InitClient(AssetsURL + coin.Handle) err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) if err != nil { return nil, err diff --git a/services/notifier/base.go b/services/notifier/base.go index 3de2edb6a..d5193ae88 100644 --- a/services/notifier/base.go +++ b/services/notifier/base.go @@ -2,11 +2,11 @@ package notifier import ( "strconv" + "strings" log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/pkg/address" ) const ( @@ -39,7 +39,7 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) error { notifications := make([]TransactionNotification, 0) for _, sub := range subscriptions { - ua, _, ok := address.UnprefixedAddress(sub.Address) + ua, _, ok := UnprefixedAddress(sub.Address) if !ok { continue } @@ -58,3 +58,19 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) error { return nil } + +func UnprefixedAddress(address string) (string, uint, bool) { + result := strings.Split(address, "_") + if len(result) != 2 { + return "", 0, false + } + addr := result[1] + if len(addr) == 0 { + return "", 0, false + } + id, err := strconv.Atoi(result[0]) + if err != nil { + return "", 0, false + } + return addr, uint(id), true +} diff --git a/services/notifier/base_test.go b/services/notifier/base_test.go new file mode 100644 index 000000000..04c8801f7 --- /dev/null +++ b/services/notifier/base_test.go @@ -0,0 +1,58 @@ +package notifier + +import ( + "testing" +) + +func TestUnprefixedAddress(t *testing.T) { + tests := []struct { + name string + address string + want string + coin uint + ok bool + }{ + { + name: "Test invalid address", + address: "60", + want: "", + coin: 0, + ok: false, + }, + { + name: "Test invalid address 2", + address: "60_", + want: "", + coin: 0, + ok: false, + }, + { + name: "Test invalid coin", + address: "asdf_0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", + want: "", + coin: 0, + ok: false, + }, + { + name: "Test ETH", + address: "60_0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", + want: "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", + coin: 60, + ok: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1, got2 := UnprefixedAddress(tt.address) + if got != tt.want { + t.Errorf("UnprefixedAddress() got = %v, want %v", got, tt.want) + } + if got1 != tt.coin { + t.Errorf("UnprefixedAddress() got1 = %v, want %v", got1, tt.coin) + } + if got2 != tt.ok { + t.Errorf("UnprefixedAddress() got2 = %v, want %v", got2, tt.ok) + } + }) + } +} From 393b2100969c72c51f2705ba3b8c0c9fd2671e66 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 6 Jan 2021 07:53:17 +0800 Subject: [PATCH 446/506] Remove imroc/req dependency and setup client errors log (#1345) * cleanup binance/zilliqa client * Implement internal client to log errors * Update client.go Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> --- go.mod | 1 - internal/client.go | 55 +++++++++++++++++++++++++++++++ platform/aeternity/base.go | 4 +-- platform/aion/base.go | 4 +-- platform/binance/client.go | 64 ++++++++++-------------------------- platform/bitcoin/base.go | 4 +-- platform/cosmos/base.go | 4 +-- platform/elrond/base.go | 4 +-- platform/ethereum/base.go | 8 ++--- platform/filecoin/base.go | 6 ++-- platform/fio/base.go | 4 +-- platform/harmony/base.go | 4 +-- platform/icon/base.go | 4 +-- platform/iotex/base.go | 4 +-- platform/kava/base.go | 4 +-- platform/nano/base.go | 4 +-- platform/near/base.go | 4 +-- platform/nebulas/base.go | 4 +-- platform/nimiq/base.go | 4 +-- platform/ontology/base.go | 4 +-- platform/polkadot/base.go | 4 +-- platform/ripple/base.go | 4 +-- platform/solana/base.go | 4 +-- platform/stellar/base.go | 4 +-- platform/tezos/base.go | 6 ++-- platform/theta/base.go | 4 +-- platform/tron/base.go | 6 ++-- platform/tron/token_test.go | 5 +-- platform/vechain/base.go | 4 +-- platform/waves/base.go | 4 +-- platform/zilliqa/base.go | 6 ++-- platform/zilliqa/rpc.go | 9 ++--- services/assets/client.go | 7 ++-- services/assets/validator.go | 2 +- 34 files changed, 143 insertions(+), 120 deletions(-) create mode 100644 internal/client.go diff --git a/go.mod b/go.mod index 65ccb33e9..83873f481 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/getsentry/raven-go v0.2.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 - github.com/imroc/req v0.3.0 github.com/mitchellh/mapstructure v1.4.0 github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/runc v1.0.0-rc9 // indirect diff --git a/internal/client.go b/internal/client.go new file mode 100644 index 000000000..f30e09d11 --- /dev/null +++ b/internal/client.go @@ -0,0 +1,55 @@ +package internal + +import ( + "net/http" + "strconv" + + "github.com/getsentry/raven-go" + + log "github.com/sirupsen/logrus" + + "github.com/trustwallet/golibs/client" +) + +type Client struct { + client.Request +} + +var errorHandler = func(res *http.Response, uri string) error { + //Improve ways to identify if worth logging the error + if res.StatusCode == http.StatusOK || res.StatusCode == http.StatusNotFound { + return nil + } + log.WithFields(log.Fields{ + "tags": raven.Tags{ + {Key: "status_code", Value: strconv.Itoa(res.StatusCode)}, + {Key: "host", Value: res.Request.Host}, + {Key: "url", Value: uri}, + }, + "fingerprint": []string{"client_errors"}, + }).Error("Client Errors") + + return nil +} + +func InitClient(url string) client.Request { + return client.Request{ + Headers: map[string]string{}, + HttpClient: client.DefaultClient, + ErrorHandler: errorHandler, + BaseUrl: url, + } +} + +func InitJSONClient(baseUrl string) client.Request { + headers := map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + } + return client.Request{ + Headers: headers, + HttpClient: client.DefaultClient, + ErrorHandler: errorHandler, + BaseUrl: baseUrl, + } +} diff --git a/platform/aeternity/base.go b/platform/aeternity/base.go index 2ee49143b..840d7f2fb 100644 --- a/platform/aeternity/base.go +++ b/platform/aeternity/base.go @@ -1,7 +1,7 @@ package aeternity import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/aion/base.go b/platform/aion/base.go index 86b6f6b62..aa5705e0d 100644 --- a/platform/aion/base.go +++ b/platform/aion/base.go @@ -1,7 +1,7 @@ package aion import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/binance/client.go b/platform/binance/client.go index 1ce3074be..9bedcae25 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -2,99 +2,71 @@ package binance import ( "fmt" - "net/http" "net/url" "strconv" "time" - "github.com/imroc/req" - "github.com/patrickmn/go-cache" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/client" ) type Client struct { - *cache.Cache - url string - apiKey string + client.Request } func InitClient(url, apiKey string) Client { - return Client{url: url, apiKey: apiKey, Cache: cache.New(5*time.Minute, 10*time.Minute)} -} - -func (c Client) Get(path string, params interface{}) (*req.Resp, error) { - header := make(http.Header) - if c.apiKey != "" { - header.Set("apikey", c.apiKey) - } - return req.Get(c.url+path, header, params) + c := Client{internal.InitClient(url)} + c.Headers["apikey"] = apiKey + return c } func (c Client) FetchLatestBlockNumber() (int64, error) { - resp, err := c.Get("/api/v1/node-info", nil) - if err != nil { - return 0, err - } var result NodeInfoResponse - if err := resp.ToJSON(&result); err != nil { + err := c.Get(&result, "api/v1/node-info", nil) + if err != nil { return 0, err } return int64(result.SyncInfo.LatestBlockHeight), nil } func (c Client) FetchTransactionsInBlock(blockNumber int64) (TransactionsInBlockResponse, error) { - resp, err := c.Get(fmt.Sprintf("/api/v2/transactions-in-block/%d", blockNumber), nil) - if err != nil { - return TransactionsInBlockResponse{}, err - } var result TransactionsInBlockResponse - if err := resp.ToJSON(&result); err != nil { + err := c.Get(&result, fmt.Sprintf("api/v2/transactions-in-block/%d", blockNumber), nil) + if err != nil { return TransactionsInBlockResponse{}, err } return result, nil } func (c Client) FetchTransactionsByAddressAndTokenID(address, tokenID string) ([]Tx, error) { + var result TransactionsInBlockResponse startTime := strconv.Itoa(int(time.Now().AddDate(0, -3, 0).Unix() * 1000)) limit := strconv.Itoa(blockatlas.TxPerPage) params := url.Values{"address": {address}, "txAsset": {tokenID}, "startTime": {startTime}, "limit": {limit}} - resp, err := c.Get("/api/v1/transactions", params) + err := c.Get(&result, "api/v1/transactions", params) if err != nil { return nil, err } - var result TransactionsInBlockResponse - if err := resp.ToJSON(&result); err != nil { - return nil, err - } return result.Tx, nil } func (c Client) FetchAccountMeta(address string) (AccountMeta, error) { - resp, err := c.Get(fmt.Sprintf("/api/v1/account/%s", address), nil) - if err != nil { - return AccountMeta{}, err - } var result AccountMeta - if err := resp.ToJSON(&result); err != nil { + err := c.Get(&result, fmt.Sprintf("api/v1/account/%s", address), nil) + if err != nil { return AccountMeta{}, err } return result, nil } func (c Client) FetchTokens() (Tokens, error) { - cachedResult, ok := c.Cache.Get("tokens") - if ok { - return cachedResult.(Tokens), nil - } - result := new(Tokens) + var result Tokens query := url.Values{"limit": {tokensLimit}} - resp, err := c.Get("/api/v1/tokens", query) + err := c.GetWithCache(&result, "api/v1/tokens", query, 5*time.Minute) if err != nil { return nil, err } - if err := resp.ToJSON(&result); err != nil { - return nil, err - } - c.Cache.Set("tokens", *result, cache.DefaultExpiration) - return *result, nil + return result, nil } diff --git a/platform/bitcoin/base.go b/platform/bitcoin/base.go index 1073972ab..14e85ec1a 100644 --- a/platform/bitcoin/base.go +++ b/platform/bitcoin/base.go @@ -1,7 +1,7 @@ package bitcoin import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/cosmos/base.go b/platform/cosmos/base.go index a7227e292..72aa87af3 100644 --- a/platform/cosmos/base.go +++ b/platform/cosmos/base.go @@ -1,7 +1,7 @@ package cosmos import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/elrond/base.go b/platform/elrond/base.go index 55204675d..f531b4345 100644 --- a/platform/elrond/base.go +++ b/platform/elrond/base.go @@ -1,7 +1,7 @@ package elrond import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{client.InitJSONClient(api)}, + client: Client{internal.InitJSONClient(api)}, } } diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index fa26e3ddd..cebc5a32f 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -1,10 +1,10 @@ package ethereum import ( + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/platform/ethereum/blockbook" "github.com/trustwallet/blockatlas/platform/ethereum/collection" "github.com/trustwallet/blockatlas/platform/ethereum/trustray" - "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -19,7 +19,7 @@ func Init(coinType uint, api, rpc string) *Platform { return &Platform{ CoinIndex: coinType, RpcURL: rpc, - client: &trustray.Client{Request: client.InitClient(api)}, + client: &trustray.Client{Request: internal.InitClient(api)}, } } @@ -27,13 +27,13 @@ func InitWithBlockbook(coinType uint, blockbookApi, rpc string) *Platform { return &Platform{ CoinIndex: coinType, RpcURL: rpc, - client: &blockbook.Client{Request: client.InitClient(blockbookApi)}, + client: &blockbook.Client{Request: internal.InitClient(blockbookApi)}, } } func InitWithCollection(coinType uint, rpc, blockbookApi, collectionApi, collectionKey string) *Platform { platform := InitWithBlockbook(coinType, blockbookApi, rpc) - platform.collectible = collection.Client{Request: client.InitClient(collectionApi)} + platform.collectible = collection.Client{Request: internal.InitClient(collectionApi)} platform.collectible.Headers["X-API-KEY"] = collectionKey return platform } diff --git a/platform/filecoin/base.go b/platform/filecoin/base.go index 38f3930cb..471527078 100644 --- a/platform/filecoin/base.go +++ b/platform/filecoin/base.go @@ -1,9 +1,9 @@ package filecoin import ( + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/platform/filecoin/explorer" "github.com/trustwallet/blockatlas/platform/filecoin/rpc" - "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -14,8 +14,8 @@ type Platform struct { func Init(api, explorerApi string) *Platform { p := &Platform{ - client: rpc.Client{Request: client.InitClient(api)}, - explorer: explorer.Client{Request: client.InitClient(explorerApi)}, + client: rpc.Client{Request: internal.InitClient(api)}, + explorer: explorer.Client{Request: internal.InitClient(explorerApi)}, } return p } diff --git a/platform/fio/base.go b/platform/fio/base.go index 56dff74de..3e13fca08 100644 --- a/platform/fio/base.go +++ b/platform/fio/base.go @@ -1,7 +1,7 @@ package fio import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitJSONClient(api)}, + client: Client{internal.InitJSONClient(api)}, } } diff --git a/platform/harmony/base.go b/platform/harmony/base.go index ba1323014..3e3805d8d 100644 --- a/platform/harmony/base.go +++ b/platform/harmony/base.go @@ -1,7 +1,7 @@ package harmony import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{client.InitJSONClient(api)}, + client: Client{internal.InitJSONClient(api)}, } return p } diff --git a/platform/icon/base.go b/platform/icon/base.go index 09c84794b..1a025de2d 100644 --- a/platform/icon/base.go +++ b/platform/icon/base.go @@ -1,7 +1,7 @@ package icon import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/iotex/base.go b/platform/iotex/base.go index 610deb3ed..f216a49c6 100644 --- a/platform/iotex/base.go +++ b/platform/iotex/base.go @@ -1,7 +1,7 @@ package iotex import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/kava/base.go b/platform/kava/base.go index 51c5bfa3f..5cd3a8f75 100644 --- a/platform/kava/base.go +++ b/platform/kava/base.go @@ -1,7 +1,7 @@ package kava import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/nano/base.go b/platform/nano/base.go index 84edf3c0f..dfd3dfe6e 100644 --- a/platform/nano/base.go +++ b/platform/nano/base.go @@ -1,7 +1,7 @@ package nano import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{client.InitJSONClient(api)}, + client: Client{internal.InitJSONClient(api)}, } return p } diff --git a/platform/near/base.go b/platform/near/base.go index e373f55a6..b10c7422d 100644 --- a/platform/near/base.go +++ b/platform/near/base.go @@ -1,7 +1,7 @@ package near import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } return p } diff --git a/platform/nebulas/base.go b/platform/nebulas/base.go index bb2cd9ea8..5b71800a0 100644 --- a/platform/nebulas/base.go +++ b/platform/nebulas/base.go @@ -1,7 +1,7 @@ package nebulas import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/nimiq/base.go b/platform/nimiq/base.go index ddb988fbc..fdcaeeff5 100644 --- a/platform/nimiq/base.go +++ b/platform/nimiq/base.go @@ -1,7 +1,7 @@ package nimiq import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitJSONClient(api)}, + client: Client{internal.InitJSONClient(api)}, } } diff --git a/platform/ontology/base.go b/platform/ontology/base.go index cf279458e..8f6d92bec 100644 --- a/platform/ontology/base.go +++ b/platform/ontology/base.go @@ -1,7 +1,7 @@ package ontology import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/polkadot/base.go b/platform/polkadot/base.go index 3f5eb8edc..665c875ea 100644 --- a/platform/polkadot/base.go +++ b/platform/polkadot/base.go @@ -1,7 +1,7 @@ package polkadot import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{client.InitJSONClient(api)}, + client: Client{internal.InitJSONClient(api)}, } } diff --git a/platform/ripple/base.go b/platform/ripple/base.go index 56a2c018a..b3f584285 100644 --- a/platform/ripple/base.go +++ b/platform/ripple/base.go @@ -1,7 +1,7 @@ package ripple import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/solana/base.go b/platform/solana/base.go index dcdb5f7e4..a017ba9ce 100644 --- a/platform/solana/base.go +++ b/platform/solana/base.go @@ -1,7 +1,7 @@ package solana import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{client.InitJSONClient(api)}, + client: Client{internal.InitJSONClient(api)}, } return p } diff --git a/platform/stellar/base.go b/platform/stellar/base.go index 98e073408..321362456 100644 --- a/platform/stellar/base.go +++ b/platform/stellar/base.go @@ -1,7 +1,7 @@ package stellar import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -13,7 +13,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/tezos/base.go b/platform/tezos/base.go index e9e92317b..964df8387 100644 --- a/platform/tezos/base.go +++ b/platform/tezos/base.go @@ -1,7 +1,7 @@ package tezos import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -12,8 +12,8 @@ type Platform struct { func Init(api, rpc string) *Platform { p := &Platform{ - client: Client{client.InitClient(api)}, - rpcClient: RpcClient{client.InitClient(rpc)}, + client: Client{internal.InitClient(api)}, + rpcClient: RpcClient{internal.InitClient(rpc)}, } p.client.SetTimeout(35) return p diff --git a/platform/theta/base.go b/platform/theta/base.go index 5e8053c1c..05d735c79 100644 --- a/platform/theta/base.go +++ b/platform/theta/base.go @@ -1,7 +1,7 @@ package theta import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/tron/base.go b/platform/tron/base.go index d43fa810a..fa514ca42 100644 --- a/platform/tron/base.go +++ b/platform/tron/base.go @@ -1,7 +1,7 @@ package tron import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -12,8 +12,8 @@ type Platform struct { func Init(api, explorerApi string) *Platform { return &Platform{ - client: Client{client.InitClient(api)}, - explorerClient: ExplorerClient{client.InitClient(explorerApi)}, + client: Client{internal.InitClient(api)}, + explorerClient: ExplorerClient{internal.InitClient(explorerApi)}, } } diff --git a/platform/tron/token_test.go b/platform/tron/token_test.go index 921cce93d..919eed210 100644 --- a/platform/tron/token_test.go +++ b/platform/tron/token_test.go @@ -3,12 +3,13 @@ package tron import ( "encoding/json" "fmt" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/http" "net/http/httptest" "sort" "testing" + + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) var tokenDst = blockatlas.Token{ diff --git a/platform/vechain/base.go b/platform/vechain/base.go index 86444e4a7..e1e532e06 100644 --- a/platform/vechain/base.go +++ b/platform/vechain/base.go @@ -1,7 +1,7 @@ package vechain import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitJSONClient(api)}, + client: Client{internal.InitJSONClient(api)}, } } diff --git a/platform/waves/base.go b/platform/waves/base.go index d8374ec72..d9a2a70a7 100644 --- a/platform/waves/base.go +++ b/platform/waves/base.go @@ -1,7 +1,7 @@ package waves import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -11,7 +11,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{client.InitClient(api)}, + client: Client{internal.InitClient(api)}, } } diff --git a/platform/zilliqa/base.go b/platform/zilliqa/base.go index cee31fea6..2fe8c7790 100644 --- a/platform/zilliqa/base.go +++ b/platform/zilliqa/base.go @@ -1,7 +1,7 @@ package zilliqa import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/golibs/coin" ) @@ -12,8 +12,8 @@ type Platform struct { func Init(api, apiKey, rpc string) *Platform { p := &Platform{ - client: Client{client.InitClient(api)}, - rpcClient: RpcClient{client.InitClient(rpc)}, + client: Client{internal.InitClient(api)}, + rpcClient: RpcClient{internal.InitClient(rpc)}, } p.client.Headers["X-APIKEY"] = apiKey return p diff --git a/platform/zilliqa/rpc.go b/platform/zilliqa/rpc.go index 3bae0be83..ccfce78ef 100644 --- a/platform/zilliqa/rpc.go +++ b/platform/zilliqa/rpc.go @@ -3,8 +3,6 @@ package zilliqa import ( "strconv" - "github.com/imroc/req" - "github.com/mitchellh/mapstructure" "github.com/trustwallet/golibs/client" ) @@ -31,12 +29,9 @@ func (c *RpcClient) GetTransactionsHashesInBlock(number int64) ([]string, error) Params: []string{strNumber}, Id: number, } - resp, err := req.Post(c.BaseUrl, req.BodyJSON(requestBody)) - if err != nil { - return nil, err - } var result HashesResponse - if err = resp.ToJSON(&result); err != nil { + err := c.Post(&result, "/", requestBody) + if err != nil { return nil, err } return result.Txs(), nil diff --git a/services/assets/client.go b/services/assets/client.go index 03885877a..a1df61b29 100644 --- a/services/assets/client.go +++ b/services/assets/client.go @@ -3,17 +3,18 @@ package assets import ( "time" - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/coin" ) const ( - AssetsURL = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/" + URL = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/" ) func fetchValidatorsInfo(coin coin.Coin) (AssetValidators, error) { var results AssetValidators - request := client.InitClient(AssetsURL + coin.Handle) + request := internal.InitClient(URL + coin.Handle) err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) if err != nil { return nil, err diff --git a/services/assets/validator.go b/services/assets/validator.go index 90ccb4ee0..ec0d2790a 100644 --- a/services/assets/validator.go +++ b/services/assets/validator.go @@ -69,5 +69,5 @@ func calculateAnnual(annual float64, commission float64) float64 { } func getImage(c coin.Coin, ID string) string { - return AssetsURL + c.Handle + "/validators/assets/" + ID + "/logo.png" + return URL + c.Handle + "/validators/assets/" + ID + "/logo.png" } From 3132b7764abbbae23913c180ea0c0627a3da8fd7 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 5 Jan 2021 16:24:18 -0800 Subject: [PATCH 447/506] [Cosmos] Improve transaction fetching (#1346) If number of available pages is 0, client will try to request: txs?limit=25&message.recipient=cosmos1s9....q&page=0 - which will always return 400 errors --- platform/cosmos/transaction.go | 2 +- platform/kava/transaction.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 4150b7f9b..034455489 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -25,7 +25,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return } // Condition when no more pages to paginate - if txs.PageTotal == "1" { + if txs.PageTotal == "1" || txs.PageTotal == "0" { out <- txs.Txs return } diff --git a/platform/kava/transaction.go b/platform/kava/transaction.go index cb0e4684b..cdc171322 100644 --- a/platform/kava/transaction.go +++ b/platform/kava/transaction.go @@ -32,7 +32,7 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPag return } // Condition when no more pages to paginate - if txs.PageTotal == "1" { + if txs.PageTotal == "1" || txs.PageTotal == "0" { out <- txs.Txs return } From 39e69e2ee1ee29ba0f06c3bf9f005d9cf3854e3c Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 6 Jan 2021 09:37:54 +0800 Subject: [PATCH 448/506] [Tezos] Get validators info from baking bad api (#1339) * get bakers info from baking bad api * Add normalize test * filter from assets list * set name, website info from assets * MinDelegation might have float value * Add 1 hour cache * change raw github url --- config.yml | 1 + config/configuration.go | 5 +- platform/cosmos/stake_test.go | 5 +- platform/harmony/stake_test.go | 7 +- platform/kava/stake_test.go | 5 +- platform/platform.go | 2 +- platform/solana/stake_test.go | 2 +- platform/tezos/baker.go | 67 +++++++++++++++ platform/tezos/baker_test.go | 137 ++++++++++++++++++++++++++++++ platform/tezos/base.go | 12 +-- platform/tezos/model.go | 15 +++- platform/tezos/stake.go | 7 +- platform/tezos/stake_test.go | 9 +- platform/tron/stake_test.go | 7 +- services/assets/client.go | 4 +- services/assets/model.go | 2 +- services/assets/model_test.go | 5 +- services/assets/validator.go | 8 +- services/assets/validator_test.go | 15 ++-- 19 files changed, 271 insertions(+), 44 deletions(-) create mode 100644 platform/tezos/baker.go create mode 100644 platform/tezos/baker_test.go diff --git a/config.yml b/config.yml index b483f7750..3001b68d1 100644 --- a/config.yml +++ b/config.yml @@ -50,6 +50,7 @@ stellar: tezos: api: https://api.tzstats.com/explorer # https://tzstats.com/docs/api/index.html#introduction rpc: https://mainnet-tezos.giganode.io + baker: https://api.baking-bad.org # [ETH] Ethereum: https://ethereum.org ethereum: diff --git a/config/configuration.go b/config/configuration.go index ece354014..eb9fe307b 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -51,8 +51,9 @@ type Configuration struct { API string `mapstructure:"api"` } `mapstructure:"nimiq"` Tezos struct { - API string `mapstructure:"api"` - RPC string `mapstructure:"rpc"` + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + Baker string `mapstructure:"baker"` } `mapstructure:"tezos"` Thundertoken struct { API string `mapstructure:"api"` diff --git a/platform/cosmos/stake_test.go b/platform/cosmos/stake_test.go index 18acf1d2a..4204673a3 100644 --- a/platform/cosmos/stake_test.go +++ b/platform/cosmos/stake_test.go @@ -2,9 +2,10 @@ package cosmos import ( "encoding/json" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/stretchr/testify/assert" ) @@ -95,7 +96,7 @@ var validator1 = blockatlas.StakeValidator{ Info: blockatlas.StakeValidatorInfo{ Name: "Certus One", Description: "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment.", - Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys/logo.png", + Image: "https://assets.trustwalletapp.com/blockchains/cosmos/validators/assets/cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys/logo.png", Website: "https://certus.one", }, Details: blockatlas.StakingDetails{ diff --git a/platform/harmony/stake_test.go b/platform/harmony/stake_test.go index c4fc8ebe8..e98f9d3ac 100644 --- a/platform/harmony/stake_test.go +++ b/platform/harmony/stake_test.go @@ -2,10 +2,11 @@ package harmony import ( "encoding/json" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "strconv" "testing" + + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) const validatorSrc = ` @@ -116,7 +117,7 @@ var validator1 = blockatlas.StakeValidator{ Info: blockatlas.StakeValidatorInfo{ Name: "Harmony One", Description: "Stake and earn rewards with the most secure and stable validator. Operated by Harmony One Inc.", - Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/harmony/validators/assets/one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy/logo.png", + Image: "https://assets.trustwalletapp.com/blockchains/harmony/validators/assets/one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy/logo.png", Website: "https://harmony.one", }, Details: blockatlas.StakingDetails{ diff --git a/platform/kava/stake_test.go b/platform/kava/stake_test.go index a177ce2c0..958d23e6d 100644 --- a/platform/kava/stake_test.go +++ b/platform/kava/stake_test.go @@ -2,9 +2,10 @@ package kava import ( "encoding/json" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/stretchr/testify/assert" ) @@ -98,7 +99,7 @@ var validator1 = blockatlas.StakeValidator{ Info: blockatlas.StakeValidatorInfo{ Name: "Certus One", Description: "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment.", - Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys/logo.png", + Image: "https://assets.trustwalletapp.com/blockchains/cosmos/validators/assets/cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys/logo.png", Website: "https://certus.one", }, Details: blockatlas.StakingDetails{ diff --git a/platform/platform.go b/platform/platform.go index 42ef2de19..5721ca6d8 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -64,7 +64,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Algorand().Handle: algorand.Init(config.Default.Algorand.API, config.Default.Algorand.Key), coin.Aeternity().Handle: aeternity.Init(config.Default.Aeternity.API), coin.Solana().Handle: solana.Init(config.Default.Solana.API), - coin.Tezos().Handle: tezos.Init(config.Default.Tezos.API, config.Default.Tezos.RPC), + 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), diff --git a/platform/solana/stake_test.go b/platform/solana/stake_test.go index 8c5dccad2..c09238df2 100644 --- a/platform/solana/stake_test.go +++ b/platform/solana/stake_test.go @@ -152,7 +152,7 @@ var stakeValidator = blockatlas.StakeValidator{ Info: blockatlas.StakeValidatorInfo{ Name: "Certus One", Description: "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment.", - Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/solana/validators/assets/2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW/logo.png", + Image: "https://assets.trustwalletapp.com/blockchains/solana/validators/assets/2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW/logo.png", Website: "https://certus.one", }, Details: getDetails(), diff --git a/platform/tezos/baker.go b/platform/tezos/baker.go new file mode 100644 index 000000000..a45f37590 --- /dev/null +++ b/platform/tezos/baker.go @@ -0,0 +1,67 @@ +package tezos + +import ( + "math" + "strconv" + "time" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/coin" +) + +const ( + cacheTime = 1 * time.Hour +) + +type BakerClient struct { + client.Request +} + +func (c *BakerClient) GetBakers() (validators blockatlas.StakeValidators, err error) { + var bakers []Baker + err = c.GetWithCache(&bakers, "v2/bakers", nil, cacheTime) + if err != nil { + return + } + assetsValidators, err := assets.GetchValidatorsInfo(coin.Tezos()) + if err != nil { + return + } + validatorMap := assetsValidators.ToMap() + for _, baker := range bakers { + if av, ok := validatorMap[baker.Address]; ok { + validators = append(validators, NormalizeStakeValidator(baker, av)) + } + } + return +} + +func NormalizeStakeValidator(baker Baker, assetValidator assets.AssetValidator) blockatlas.StakeValidator { + status := true + if baker.FreeSpace < 0 || baker.ServiceHealth != "active" || !baker.OpenForDelegation { + status = false + } + + amount := uint64(math.Ceil(baker.MinDelegation)) + + return blockatlas.StakeValidator{ + ID: baker.Address, + Status: status, + Info: blockatlas.StakeValidatorInfo{ + Name: assetValidator.Name, + Description: assetValidator.Description, + Website: assetValidator.Website, + Image: assets.GetImageURL(coin.Tezos(), baker.Address), + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: math.Round(baker.EstimatedRoi*10000) / 100, + }, + LockTime: LockTime, + MinimumAmount: blockatlas.Amount(strconv.FormatUint(amount, 10)), + Type: blockatlas.DelegationTypeDelegate, + }, + } +} diff --git a/platform/tezos/baker_test.go b/platform/tezos/baker_test.go new file mode 100644 index 000000000..3bfcb8d01 --- /dev/null +++ b/platform/tezos/baker_test.go @@ -0,0 +1,137 @@ +package tezos + +import ( + "reflect" + "testing" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/services/assets" +) + +func TestNormalizeStakeValidators(t *testing.T) { + tests := []struct { + name string + av assets.AssetValidator + baker Baker + validator blockatlas.StakeValidator + }{ + { + name: "Test normalize negative free space", + av: assets.AssetValidator{ + ID: "tz1fJHFn6sWEd3NnBPngACuw2dggTv6nQZ7g", + Name: "Baking Team from assets", + Description: "Baking team is full", + Website: "https://mytezosbaker.com/bakingteam", + }, + baker: Baker{ + Address: "tz1fJHFn6sWEd3NnBPngACuw2dggTv6nQZ7g", + Name: "Baking Team", + Logo: "https://services.tzkt.io/v1/avatars/tz1fJHFn6sWEd3NnBPngACuw2dggTv6nQZ7g", + FreeSpace: -54723.23208699998, + Fee: 0, + MinDelegation: 1000, + OpenForDelegation: true, + EstimatedRoi: 0.060643, + ServiceHealth: "active", + }, + validator: blockatlas.StakeValidator{ + ID: "tz1fJHFn6sWEd3NnBPngACuw2dggTv6nQZ7g", + Status: false, + Info: blockatlas.StakeValidatorInfo{ + Name: "Baking Team from assets", + Description: "Baking team is full", + Website: "https://mytezosbaker.com/bakingteam", + Image: "https://assets.trustwalletapp.com/blockchains/tezos/validators/assets/tz1fJHFn6sWEd3NnBPngACuw2dggTv6nQZ7g/logo.png", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 6.06, + }, + MinimumAmount: "1000", + Type: "delegate", + }, + }, + }, + { + name: "Test normalize negative free space", + av: assets.AssetValidator{ + ID: "tz1gcna2xxZj2eNp1LaMyAhVJ49mEFj4FH26", + Name: "Exaion Baker", + Description: "Exaion is first French corporate to participate in the Tezos ecosystem as a corporate baker.", + Website: "https://www.edf.fr/en/the-edf-group", + }, + baker: Baker{ + Address: "tz1gcna2xxZj2eNp1LaMyAhVJ49mEFj4FH26", + Name: "Exaion Baker", + Logo: "https://services.tzkt.io/v1/avatars/tz1gcna2xxZj2eNp1LaMyAhVJ49mEFj4FH26", + FreeSpace: 7947.711756999997, + Fee: 0.04, + MinDelegation: 0, + OpenForDelegation: true, + EstimatedRoi: 0.058896, + ServiceHealth: "active", + }, + validator: blockatlas.StakeValidator{ + ID: "tz1gcna2xxZj2eNp1LaMyAhVJ49mEFj4FH26", + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "Exaion Baker", + Image: "https://assets.trustwalletapp.com/blockchains/tezos/validators/assets/tz1gcna2xxZj2eNp1LaMyAhVJ49mEFj4FH26/logo.png", + Description: "Exaion is first French corporate to participate in the Tezos ecosystem as a corporate baker.", + Website: "https://www.edf.fr/en/the-edf-group", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 5.89, + }, + MinimumAmount: "0", + Type: "delegate", + }, + }, + }, + { + name: "Test", + av: assets.AssetValidator{ + ID: "tz1dbfppLAAxXZNtf2SDps7rch3qfUznKSoK", + Name: "Coinhouse", + Description: "The reliable and safe way to invest in cryptocurrencies", + Website: "https://www.coinhouse.com/", + }, + baker: Baker{ + Address: "tz1dbfppLAAxXZNtf2SDps7rch3qfUznKSoK", + Name: "Coinhouse", + Logo: "https://services.tzkt.io/v1/avatars/tz1dbfppLAAxXZNtf2SDps7rch3qfUznKSoK", + FreeSpace: 91005.65305700002, + Fee: 0.08, + MinDelegation: 0.1, + OpenForDelegation: false, + EstimatedRoi: 0.056598, + ServiceHealth: "active", + }, + validator: blockatlas.StakeValidator{ + ID: "tz1dbfppLAAxXZNtf2SDps7rch3qfUznKSoK", + Status: false, + Info: blockatlas.StakeValidatorInfo{ + Name: "Coinhouse", + Image: "https://assets.trustwalletapp.com/blockchains/tezos/validators/assets/tz1dbfppLAAxXZNtf2SDps7rch3qfUznKSoK/logo.png", + Description: "The reliable and safe way to invest in cryptocurrencies", + Website: "https://www.coinhouse.com/", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 5.66, + }, + MinimumAmount: "1", + Type: "delegate", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotValidator := NormalizeStakeValidator(tt.baker, tt.av); !reflect.DeepEqual(gotValidator, tt.validator) { + t.Errorf("NormalizeStakeValidators() = %v, want %v", gotValidator, tt.validator) + } + }) + } +} diff --git a/platform/tezos/base.go b/platform/tezos/base.go index 964df8387..625f09401 100644 --- a/platform/tezos/base.go +++ b/platform/tezos/base.go @@ -6,14 +6,16 @@ import ( ) type Platform struct { - client Client - rpcClient RpcClient + client Client + rpcClient RpcClient + bakerClient BakerClient } -func Init(api, rpc string) *Platform { +func Init(api, rpc, baker string) *Platform { p := &Platform{ - client: Client{internal.InitClient(api)}, - rpcClient: RpcClient{internal.InitClient(rpc)}, + client: Client{internal.InitClient(api)}, + rpcClient: RpcClient{internal.InitClient(rpc)}, + bakerClient: BakerClient{internal.InitClient(baker)}, } p.client.SetTimeout(35) return p diff --git a/platform/tezos/model.go b/platform/tezos/model.go index 02f93bfbe..c7cf49c55 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -2,8 +2,9 @@ package tezos import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "time" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) const ( @@ -54,6 +55,18 @@ type ( ActivityValidatorInfo struct { Deactivated bool `json:"deactivated"` } + + Baker struct { + Address string `json:"address"` + Name string `json:"name"` + Logo string `json:"logo"` + FreeSpace float64 `json:"freeSpace"` + Fee float64 `json:"fee"` + MinDelegation float64 `json:"minDelegation"` + OpenForDelegation bool `json:"openForDelegation"` + EstimatedRoi float64 `json:"estimatedRoi"` + ServiceHealth string `json:"serviceHealth"` + } ) func (t *Transaction) Status() blockatlas.Status { diff --git a/platform/tezos/stake.go b/platform/tezos/stake.go index 3d5065b08..ba02919c5 100644 --- a/platform/tezos/stake.go +++ b/platform/tezos/stake.go @@ -3,7 +3,6 @@ package tezos import ( log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/assets" ) const ( @@ -13,7 +12,7 @@ const ( ) func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { - validators, err := assets.GetValidatorsMap(p) + validators, err := p.bakerClient.GetBakers() if err != nil { return nil, err } @@ -44,11 +43,11 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e return make(blockatlas.DelegationsPage, 0), nil } - validators, err := assets.GetValidatorsMap(p) + validators, err := p.bakerClient.GetBakers() if err != nil { return nil, err } - return NormalizeDelegation(account, validators) + return NormalizeDelegation(account, validators.ToMap()) } func NormalizeDelegation(account Account, validators blockatlas.ValidatorMap) (blockatlas.DelegationsPage, error) { diff --git a/platform/tezos/stake_test.go b/platform/tezos/stake_test.go index 7fb4e8ad4..f06df8c4b 100644 --- a/platform/tezos/stake_test.go +++ b/platform/tezos/stake_test.go @@ -3,11 +3,12 @@ package tezos import ( "encoding/json" "fmt" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "net/http" "net/http/httptest" "testing" + + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) const accountSrc = ` @@ -38,7 +39,7 @@ var stakeValidator = blockatlas.StakeValidator{ Info: blockatlas.StakeValidatorInfo{ Name: "stake.fish", Description: "Leading validator for Proof of Stake blockchains. Stake your cryptocurrencies with us. We know validating.", - Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/tezos/validators/assets/tz2fcnbrerxtattnx6iimr1uj5jsdxvdhm93/logo.png", + Image: "https://assets.trustwalletapp.com/blockchains/tezos/validators/assets/tz2fcnbrerxtattnx6iimr1uj5jsdxvdhm93/logo.png", Website: "https://stake.fish/", }, Details: getDetails(), @@ -80,7 +81,7 @@ func TestPlatform_isValidatorActive(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL, server.URL) + p := Init(server.URL, server.URL, server.URL) assert.True(t, p.isValidatorActive("tz1V3yg82mcrPJbegqVCPn6bC8w1CSTRp3f8")) } diff --git a/platform/tron/stake_test.go b/platform/tron/stake_test.go index c9ae23a83..3a89a0984 100644 --- a/platform/tron/stake_test.go +++ b/platform/tron/stake_test.go @@ -2,9 +2,10 @@ package tron import ( "encoding/json" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" ) func TestNormalizeValidator(t *testing.T) { @@ -74,7 +75,7 @@ var validator1 = blockatlas.StakeValidator{ Info: blockatlas.StakeValidatorInfo{ Name: "Sesameseed", Description: "Sesameseed is a blockchain community providing fair and transparent representation in delegated governance by rewarding Voters for their participation on Tron and Ontology.", - Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/tron/validators/assets/tgzz8gjyiyrqpfmdwnlxfgpulvnmpcswvp/logo.png", + Image: "https://assets.trustwalletapp.com/blockchains/tron/validators/assets/tgzz8gjyiyrqpfmdwnlxfgpulvnmpcswvp/logo.png", Website: "https://www.sesameseed.org", }, Details: blockatlas.StakingDetails{ @@ -92,7 +93,7 @@ var validator2 = blockatlas.StakeValidator{ Info: blockatlas.StakeValidatorInfo{ Name: "InfStones", Description: "World's leading cloud infrastructure and staking as a service provicer for blockchains. Supernodes on EOS, TRON, VeChain, Ontology, LOOM, IOST and many other chains.", - Image: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/tron/validators/assets/tpmgfspxlqgom8skutrbhcdkthjrhfbgkw/logo.png", + Image: "https://assets.trustwalletapp.com/blockchains/tron/validators/assets/tpmgfspxlqgom8skutrbhcdkthjrhfbgkw/logo.png", Website: "https://infstones.io/", }, Details: blockatlas.StakingDetails{ diff --git a/services/assets/client.go b/services/assets/client.go index a1df61b29..e82e995e7 100644 --- a/services/assets/client.go +++ b/services/assets/client.go @@ -9,10 +9,10 @@ import ( ) const ( - URL = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/" + URL = "https://assets.trustwalletapp.com/blockchains/" ) -func fetchValidatorsInfo(coin coin.Coin) (AssetValidators, error) { +func GetchValidatorsInfo(coin coin.Coin) (AssetValidators, error) { var results AssetValidators request := internal.InitClient(URL + coin.Handle) err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) diff --git a/services/assets/model.go b/services/assets/model.go index 28ad72a16..2f516d92c 100644 --- a/services/assets/model.go +++ b/services/assets/model.go @@ -28,7 +28,7 @@ type ( } ) -func (av AssetValidators) toMap() AssetValidatorMap { +func (av AssetValidators) ToMap() AssetValidatorMap { validators := make(AssetValidatorMap) for _, v := range av { validators[v.ID] = v diff --git a/services/assets/model_test.go b/services/assets/model_test.go index 0145819ff..e8b8e42b0 100644 --- a/services/assets/model_test.go +++ b/services/assets/model_test.go @@ -1,8 +1,9 @@ package assets import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestAssetValidators_toMap(t *testing.T) { @@ -17,7 +18,7 @@ func TestAssetValidators_toMap(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := tt.av.toMap() + got := tt.av.ToMap() assert.Equal(t, tt.want, got) }) } diff --git a/services/assets/validator.go b/services/assets/validator.go index ec0d2790a..29ba46989 100644 --- a/services/assets/validator.go +++ b/services/assets/validator.go @@ -18,7 +18,7 @@ func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) } func getValidators(api blockatlas.StakeAPI) (AssetValidators, blockatlas.ValidatorPage, error) { - assetsValidators, err := fetchValidatorsInfo(api.Coin()) + assetsValidators, err := GetchValidatorsInfo(api.Coin()) if err != nil { return nil, nil, err } @@ -32,7 +32,7 @@ func getValidators(api blockatlas.StakeAPI) (AssetValidators, blockatlas.Validat func normalizeValidators(assetsValidators AssetValidators, rpcValidators []blockatlas.Validator, coin coin.Coin) blockatlas.StakeValidators { results := make(blockatlas.StakeValidators, 0) - assetsMap := assetsValidators.toMap() + assetsMap := assetsValidators.ToMap() for _, v := range rpcValidators { asset, ok := assetsMap[v.ID] if !ok { @@ -58,7 +58,7 @@ func normalizeValidator(rpcValidator blockatlas.Validator, assetValidator AssetV Info: blockatlas.StakeValidatorInfo{ Name: assetValidator.Name, Description: assetValidator.Description, - Image: getImage(coin, rpcValidator.ID), + Image: GetImageURL(coin, rpcValidator.ID), Website: assetValidator.Website, }, Details: details, @@ -68,6 +68,6 @@ func calculateAnnual(annual float64, commission float64) float64 { return (annual * (100 - commission)) / 100 } -func getImage(c coin.Coin, ID string) string { +func GetImageURL(c coin.Coin, ID string) string { return URL + c.Handle + "/validators/assets/" + ID + "/logo.png" } diff --git a/services/assets/validator_test.go b/services/assets/validator_test.go index 231ffa624..7d4974181 100644 --- a/services/assets/validator_test.go +++ b/services/assets/validator_test.go @@ -1,10 +1,11 @@ package assets import ( + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" ) var ( @@ -76,7 +77,7 @@ var ( Info: blockatlas.StakeValidatorInfo{ Name: "🐠stake.fish", Description: "Leading validator for Proof of Stake blockchains.", - Image: getImage(tezosCoin, "test1"), + Image: GetImageURL(tezosCoin, "test1"), Website: "https://stake.fish/", }, Details: blockatlas.StakingDetails{ @@ -88,7 +89,7 @@ var ( Info: blockatlas.StakeValidatorInfo{ Name: "Spider", Description: "yo", - Image: getImage(cosmosCoin, "test1"), + Image: GetImageURL(cosmosCoin, "test1"), Website: "https://tw.com", }, Details: blockatlas.StakingDetails{ @@ -100,7 +101,7 @@ var ( Info: blockatlas.StakeValidatorInfo{ Name: "Spider", Description: "yo", - Image: getImage(cosmosCoin, "test1"), + Image: GetImageURL(cosmosCoin, "test1"), Website: "https://tw.com", }, Details: blockatlas.StakingDetails{ @@ -112,7 +113,7 @@ var ( Info: blockatlas.StakeValidatorInfo{ Name: "Man", Description: "lo", - Image: getImage(cosmosCoin, "test2"), + Image: GetImageURL(cosmosCoin, "test2"), Website: "https://tw.com", }, Details: blockatlas.StakingDetails{ @@ -122,8 +123,8 @@ var ( ) func TestGetImage(t *testing.T) { - image := getImage(cosmosCoin, "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp") - expected := "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/cosmos/validators/assets/TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp/logo.png" + image := GetImageURL(cosmosCoin, "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp") + expected := "https://assets.trustwalletapp.com/blockchains/cosmos/validators/assets/TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp/logo.png" assert.Equal(t, expected, image) } From f650d618431eda850d2e31782f7680a1712b4179 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Wed, 6 Jan 2021 21:30:34 -0800 Subject: [PATCH 449/506] Improve error handling for client requests (#1349) * Remove unnessesary logs * Use updated golibs * Update token.go * Update to v0.0.29 --- go.mod | 2 +- go.sum | 4 ++-- internal/client.go | 22 ++++++++++------------ platform/bitcoin/block.go | 5 ++--- platform/cosmos/stake.go | 6 +++--- platform/cosmos/transaction.go | 4 ---- platform/filecoin/explorer/client.go | 2 +- platform/harmony/stake.go | 6 +++--- platform/iotex/client.go | 2 -- platform/kava/stake.go | 1 - platform/kava/transaction.go | 4 ---- platform/ontology/transaction.go | 5 ----- platform/tezos/block.go | 2 -- platform/tezos/transaction.go | 2 -- platform/tron/token.go | 14 +++++--------- services/parser/parser.go | 23 ++++++++++++----------- 16 files changed, 39 insertions(+), 65 deletions(-) diff --git a/go.mod b/go.mod index 83873f481..ee963d591 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/swag v1.7.0 - github.com/trustwallet/golibs v0.0.28 + github.com/trustwallet/golibs v0.0.29 github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect diff --git a/go.sum b/go.sum index cc05ad0d5..908cd6ec3 100644 --- a/go.sum +++ b/go.sum @@ -415,8 +415,8 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.28 h1:EesgBxbSY9NXR6IarAnLU/XH7srnidF1hnkX0eLDti4= -github.com/trustwallet/golibs v0.0.28/go.mod h1:otCh9cT8r7VlojZv5zACgUpUyAhNrd5kD5YRV6xW9Iw= +github.com/trustwallet/golibs v0.0.29 h1:ZHpV1co5OEWNxnMk1qhlczYcZiMuLI/4r1KuyrRJRN8= +github.com/trustwallet/golibs v0.0.29/go.mod h1:otCh9cT8r7VlojZv5zACgUpUyAhNrd5kD5YRV6xW9Iw= github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08 h1:6MVjdC1zYVwiytclgHLxS6ojdYiM7gfVqMSDkjuulS4= github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= diff --git a/internal/client.go b/internal/client.go index f30e09d11..a507f48ac 100644 --- a/internal/client.go +++ b/internal/client.go @@ -5,9 +5,7 @@ import ( "strconv" "github.com/getsentry/raven-go" - log "github.com/sirupsen/logrus" - "github.com/trustwallet/golibs/client" ) @@ -16,18 +14,18 @@ type Client struct { } var errorHandler = func(res *http.Response, uri string) error { + statusCode := res.StatusCode //Improve ways to identify if worth logging the error - if res.StatusCode == http.StatusOK || res.StatusCode == http.StatusNotFound { - return nil + if statusCode != http.StatusOK && statusCode != http.StatusNotFound { + log.WithFields(log.Fields{ + "tags": raven.Tags{ + {Key: "status_code", Value: strconv.Itoa(res.StatusCode)}, + {Key: "host", Value: res.Request.Host}, + {Key: "url", Value: uri}, + }, + "fingerprint": []string{"client_errors"}, + }).Error("Client Errors") } - log.WithFields(log.Fields{ - "tags": raven.Tags{ - {Key: "status_code", Value: strconv.Itoa(res.StatusCode)}, - {Key: "host", Value: res.Request.Host}, - {Key: "url", Value: uri}, - }, - "fingerprint": []string{"client_errors"}, - }).Error("Client Errors") return nil } diff --git a/platform/bitcoin/block.go b/platform/bitcoin/block.go index e5be57fc6..9407fa893 100644 --- a/platform/bitcoin/block.go +++ b/platform/bitcoin/block.go @@ -1,9 +1,9 @@ package bitcoin import ( - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "sync" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" ) func (p *Platform) CurrentBlockNumber() (int64, error) { @@ -27,7 +27,6 @@ func (p *Platform) GetAllBlockPages(total, num int64) []Transaction { defer wg.Done() block, err := p.client.GetTransactionsByBlock(num, page) if err != nil { - log.WithFields(log.Fields{"number": num, "page": page}).Error("GetTransactionsByBlockChan", err) return } out <- block diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index 1ef97352d..7d484866f 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -1,12 +1,13 @@ package cosmos import ( + "strconv" + "time" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/assets" "github.com/trustwallet/golibs/coin" - "strconv" - "time" ) const ( @@ -67,7 +68,6 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { func (p *Platform) GetMaxAPR() float64 { validators, err := p.GetValidators() if err != nil { - log.WithFields(log.Fields{"details": err, "platform": p.Coin().Symbol}).Error("GetMaxAPR") return blockatlas.DefaultAnnualReward } diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 034455489..70a9c8e15 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -5,7 +5,6 @@ import ( "sync" "time" - log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/numbers" ) @@ -21,7 +20,6 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { page := 1 txs, err := p.client.GetAddrTxs(addr, tag, page) if err != nil { - log.WithFields(log.Fields{"address": tag, "tag": tag}).Error("GetAddrTxs", err) return } // Condition when no more pages to paginate @@ -32,14 +30,12 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { totalPages, err := strconv.Atoi(txs.PageTotal) if err != nil { - log.WithFields(log.Fields{"totalPages": totalPages}).Error("GetAddrTxs", err) return } // gaia does support sort option, paginate to get latest transactions by passing total pages page // https://github.com/cosmos/gaia/blob/f61b391aee5d04364d2b5539692bbb187ad9b946/docs/resources/gaiacli.md#query-transactions txs2, err := p.client.GetAddrTxs(addr, tag, totalPages) if err != nil { - log.WithFields(log.Fields{"address": tag, "tag": tag}).Error("GetAddrTxs", err) return } out <- txs2.Txs diff --git a/platform/filecoin/explorer/client.go b/platform/filecoin/explorer/client.go index f3c650bdf..30d59e237 100644 --- a/platform/filecoin/explorer/client.go +++ b/platform/filecoin/explorer/client.go @@ -13,7 +13,7 @@ type Client struct { } func (c Client) GetMessagesByAddress(address string, pageSize int) (res Response, err error) { - path := fmt.Sprintf("/api/v1/address/%s/messages", address) + path := fmt.Sprintf("api/v1/address/%s/messages", address) query := url.Values{"pageSize": {strconv.Itoa(pageSize)}} err = c.Get(&res, path, query) if err != nil { diff --git a/platform/harmony/stake.go b/platform/harmony/stake.go index f3f5cd14c..461f1fd9f 100644 --- a/platform/harmony/stake.go +++ b/platform/harmony/stake.go @@ -1,11 +1,12 @@ package harmony import ( + "math/big" + "strconv" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/assets" - "math/big" - "strconv" ) const ( @@ -50,7 +51,6 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { func (p *Platform) GetMaxAPR() float64 { validators, err := p.client.GetValidators() if err != nil { - log.WithFields(log.Fields{"details": err, "platform": p.Coin().Symbol}).Error("GetMaxAPR") return Annual } diff --git a/platform/iotex/client.go b/platform/iotex/client.go index 86eaf15a9..2cdb53375 100644 --- a/platform/iotex/client.go +++ b/platform/iotex/client.go @@ -5,7 +5,6 @@ import ( "net/url" "strconv" - log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/client" ) @@ -45,7 +44,6 @@ func (c *Client) GetTxsOfAddress(address string, start int64) (*Response, error) }) if err != nil { - log.WithFields(log.Fields{"address": address}).Error(err, "IOTEX: Failed to get transactions for address") return nil, blockatlas.ErrSourceConn } return &response, err diff --git a/platform/kava/stake.go b/platform/kava/stake.go index e7a44cfbf..56e8cbc36 100644 --- a/platform/kava/stake.go +++ b/platform/kava/stake.go @@ -70,7 +70,6 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { func (p *Platform) GetMaxAPR() float64 { validators, err := p.GetValidators() if err != nil { - log.WithFields(log.Fields{"details": err, "platform": p.Coin().Symbol}).Error("GetMaxAPR") return blockatlas.DefaultAnnualReward } diff --git a/platform/kava/transaction.go b/platform/kava/transaction.go index cdc171322..e58719199 100644 --- a/platform/kava/transaction.go +++ b/platform/kava/transaction.go @@ -6,7 +6,6 @@ import ( "sync" "time" - log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/numbers" ) @@ -28,7 +27,6 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPag page := 1 txs, err := p.client.GetAddrTxs(addr, tag, page) if err != nil { - log.WithFields(log.Fields{"address": tag, "tag": tag}).Error("GetAddrTxs", err) return } // Condition when no more pages to paginate @@ -39,14 +37,12 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPag totalPages, err := strconv.Atoi(txs.PageTotal) if err != nil { - log.WithFields(log.Fields{"totalPages": totalPages}).Error("GetAddrTxs", err) return } // gaia does support sort option, paginate to get latest transactions by passing total pages page // https://github.com/cosmos/gaia/blob/f61b391aee5d04364d2b5539692bbb187ad9b946/docs/resources/gaiacli.md#query-transactions txs2, err := p.client.GetAddrTxs(addr, tag, totalPages) if err != nil { - log.WithFields(log.Fields{"address": tag, "tag": tag}).Error("GetAddrTxs", err) return } out <- txs2.Txs diff --git a/platform/ontology/transaction.go b/platform/ontology/transaction.go index 47c905b08..b59598a4e 100644 --- a/platform/ontology/transaction.go +++ b/platform/ontology/transaction.go @@ -4,7 +4,6 @@ import ( "errors" "sync" - log "github.com/sirupsen/logrus" blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" @@ -17,10 +16,6 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { srcTxs, err := p.client.GetTxsOfAddress(address) if err != nil { - log.WithFields(log.Fields{ - "address": address, - "token": token, - }).Error(err, "Ontology: Failed to get transactions for address and token") return blockatlas.TxPage{}, err } txPage := normalizeTxs(srcTxs.Result, AssetType(token)) diff --git a/platform/tezos/block.go b/platform/tezos/block.go index 8f4603817..b8fe9493a 100644 --- a/platform/tezos/block.go +++ b/platform/tezos/block.go @@ -1,7 +1,6 @@ package tezos import ( - log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -13,7 +12,6 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { txTypes := []string{TxTypeTransaction, TxTypeDelegation} srcTxs, err := p.client.GetBlockByNumber(num, txTypes) if err != nil { - log.WithFields(log.Fields{"txType": txTypes, "num": num}).Error("GetAddrTxs", err) return nil, err } txs := NormalizeTxs(srcTxs, "") diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index e400373bc..bd548f597 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -1,7 +1,6 @@ package tezos import ( - log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" @@ -11,7 +10,6 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { txTypes := []string{TxTypeTransaction, TxTypeDelegation} txs, err := p.client.GetTxsOfAddress(address, txTypes) if err != nil { - log.WithFields(log.Fields{"txType": txTypes, "addr": address}).Error("GetAddrTxs", err) return nil, err } diff --git a/platform/tron/token.go b/platform/tron/token.go index c71922c0b..423d6494d 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -1,14 +1,14 @@ package tron import ( + "strconv" + "strings" + "sync" + log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/tokentype" - "strconv" - "strings" - "sync" - "time" ) func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { @@ -57,11 +57,7 @@ func (p *Platform) getTokens(ids []string) chan blockatlas.Token { wg.Add(1) go func(i string, c chan blockatlas.Token) { defer wg.Done() - time.Sleep(time.Millisecond) - err := p.getTokensChannel(i, c) - if err != nil { - log.WithFields(log.Fields{"token": i, "coin": coin.Tron().Handle}).Error("getTokens", err) - } + _ = p.getTokensChannel(i, c) }(id, tkChan) } wg.Wait() diff --git a/services/parser/parser.go b/services/parser/parser.go index d420ff589..c3894b754 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -93,7 +93,14 @@ func parse(params Params) { } txs = blockatlas.TxPage(txs).FilterTransactionsByMemo() - publish(params, txs) + err = publish(params, txs) + if err != nil { + log.WithFields(log.Fields{ + "coin": params.Api.Coin().Handle, + "transactions": len(txs), + "error": err, + }).Info("Publish Error") + } log.WithFields(log.Fields{ "coin": params.Api.Coin().Handle, @@ -238,24 +245,18 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { return nil } -func publish(params Params, txs blockatlas.Txs) { +func publish(params Params, txs blockatlas.Txs) error { if len(txs) == 0 { - return + return nil } body, err := json.Marshal(txs) if err != nil { log.WithFields(log.Fields{"operation": "publish marshal", "coin": params.Api.Coin().Handle}).Error(err) - return - } - - // Notify transactions queue - err = params.TransactionsExchange.Publish(body) - if err != nil { - log.WithFields(log.Fields{"operation": "publish transactionsQueue", "coin": params.Api.Coin().Handle}).Error(err) - return + return err } + return params.TransactionsExchange.Publish(body) } func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64, symbol string) (*blockatlas.Block, error) { From aefe236dd34b4b01a1d410fd5968f4bd7e9c6175 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 7 Jan 2021 02:55:39 -0800 Subject: [PATCH 450/506] Consolidate bitcoin client with blockbook (#1350) * Remove unnessesary logs * Update token.go * Consolidate bitcoin client with blockbook * Update marshal.go * Update go.sum * Update to golibs v0.0.30 * Move to bitcoin folder * Update subscriptions.go --- db/models/subscriptions.go | 2 +- go.mod | 4 +- go.sum | 6 +- pkg/blockatlas/marshal.go | 2 +- pkg/blockatlas/tx.go | 5 +- platform/bitcoin/base.go | 5 +- platform/bitcoin/block.go | 43 +----- .../{ethereum => bitcoin}/blockbook/block.go | 13 +- platform/bitcoin/blockbook/client.go | 129 +++++++++++++++++ platform/bitcoin/blockbook/model.go | 131 ++++++++++++++++++ .../blockbook/model_extension.go | 22 +-- .../{ethereum => bitcoin}/blockbook/token.go | 0 .../blockbook/token_test.go | 0 .../blockbook/transaction.go | 4 +- .../blockbook/transaction_test.go | 4 +- platform/bitcoin/client.go | 60 -------- platform/bitcoin/model.go | 97 ------------- platform/bitcoin/transaction.go | 23 ++- platform/bitcoin/transaction_test.go | 14 +- platform/elrond/client.go | 1 - platform/ethereum/base.go | 2 +- platform/ethereum/blockbook/client.go | 55 -------- platform/ethereum/blockbook/model.go | 76 ---------- platform/ethereum/trustray/block.go | 3 - platform/harmony/block.go | 1 - platform/nimiq/block.go | 1 - platform/stellar/block.go | 1 - platform/vechain/block.go | 1 - services/parser/parser.go | 20 ++- services/subscriber/subscriber.go | 2 +- 30 files changed, 333 insertions(+), 394 deletions(-) rename platform/{ethereum => bitcoin}/blockbook/block.go (53%) create mode 100644 platform/bitcoin/blockbook/client.go create mode 100644 platform/bitcoin/blockbook/model.go rename platform/{ethereum => bitcoin}/blockbook/model_extension.go (58%) rename platform/{ethereum => bitcoin}/blockbook/token.go (100%) rename platform/{ethereum => bitcoin}/blockbook/token_test.go (100%) rename platform/{ethereum => bitcoin}/blockbook/transaction.go (97%) rename platform/{ethereum => bitcoin}/blockbook/transaction_test.go (98%) delete mode 100644 platform/bitcoin/client.go delete mode 100644 platform/bitcoin/model.go delete mode 100644 platform/ethereum/blockbook/client.go delete mode 100644 platform/ethereum/blockbook/model.go diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index 816a2b27f..f986ff259 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -9,7 +9,7 @@ type ( Subscription struct { ID uint `gorm:"primaryKey;"` CreatedAt time.Time - Address string `gorm:"uniqueIndex:idx_address; type:varchar(128); not null;"` + Address string `gorm:"uniqueIndex:idx_address; type:varchar(256); not null;"` } SubscriptionsAssetAssociation struct { diff --git a/go.mod b/go.mod index ee963d591..5af93227c 100644 --- a/go.mod +++ b/go.mod @@ -23,11 +23,11 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/swag v1.7.0 - github.com/trustwallet/golibs v0.0.29 + github.com/trustwallet/golibs v0.0.30 github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect - golang.org/x/sys v0.0.0-20210104204734-6f8348627aad // indirect + golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.6 gorm.io/gorm v1.20.9 diff --git a/go.sum b/go.sum index 908cd6ec3..90d8417ac 100644 --- a/go.sum +++ b/go.sum @@ -417,6 +417,8 @@ 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.29 h1:ZHpV1co5OEWNxnMk1qhlczYcZiMuLI/4r1KuyrRJRN8= github.com/trustwallet/golibs v0.0.29/go.mod h1:otCh9cT8r7VlojZv5zACgUpUyAhNrd5kD5YRV6xW9Iw= +github.com/trustwallet/golibs v0.0.30 h1:bsuwKSUX9dtn/368H/gnYd2uCF/rXbhw3uIZ9sh3wLY= +github.com/trustwallet/golibs v0.0.30/go.mod h1:otCh9cT8r7VlojZv5zACgUpUyAhNrd5kD5YRV6xW9Iw= github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08 h1:6MVjdC1zYVwiytclgHLxS6ojdYiM7gfVqMSDkjuulS4= github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -543,8 +545,8 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad h1:MCsdmFSdEd4UEa5TKS5JztCRHK/WtvNei1edOj5RSRo= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 h1:/dSxr6gT0FNI1MO5WLJo8mTmItROeOKTkDn+7OwWBos= +golang.org/x/sys v0.0.0-20210105210732-16f7687f5001/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/blockatlas/marshal.go b/pkg/blockatlas/marshal.go index 7cfe1a394..aa6d00a6a 100644 --- a/pkg/blockatlas/marshal.go +++ b/pkg/blockatlas/marshal.go @@ -101,7 +101,7 @@ func (a *Amount) UnmarshalJSON(data []byte) error { } str := string(n) if !matchNumber.MatchString(str) { - return errors.New("not a regular decimal number") + return errors.New("not a regular decimal number: " + str) } if strings.ContainsRune(str, '.') { str, _ = numbers.DecimalToSatoshis(str) diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go index 9e6797ef4..4a97dfea9 100644 --- a/pkg/blockatlas/tx.go +++ b/pkg/blockatlas/tx.go @@ -60,9 +60,8 @@ type ( KeyTitle string Block struct { - Number int64 `json:"number"` - ID string `json:"id,omitempty"` - Txs []Tx `json:"txs"` + Number int64 `json:"number"` + Txs []Tx `json:"txs"` } // TxPage is a page of transactions diff --git a/platform/bitcoin/base.go b/platform/bitcoin/base.go index 14e85ec1a..742ed96f0 100644 --- a/platform/bitcoin/base.go +++ b/platform/bitcoin/base.go @@ -2,18 +2,19 @@ package bitcoin import ( "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/blockatlas/platform/bitcoin/blockbook" "github.com/trustwallet/golibs/coin" ) type Platform struct { - client Client + client blockbook.Client CoinIndex uint } func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{internal.InitClient(api)}, + client: blockbook.Client{Request: internal.InitClient(api)}, } } diff --git a/platform/bitcoin/block.go b/platform/bitcoin/block.go index 9407fa893..12bce3d84 100644 --- a/platform/bitcoin/block.go +++ b/platform/bitcoin/block.go @@ -1,60 +1,25 @@ package bitcoin import ( - "sync" - "github.com/trustwallet/blockatlas/pkg/blockatlas" ) func (p *Platform) CurrentBlockNumber() (int64, error) { - status, err := p.client.GetBlockNumber() - return status.Backend.Blocks, err -} - -func (p *Platform) GetAllBlockPages(total, num int64) []Transaction { - txs := make([]Transaction, 0) - if total <= 1 { - return txs - } - - start := int64(1) - var wg sync.WaitGroup - out := make(chan TransactionsList, int(total-start)) - wg.Add(int(total - start)) - for start < total { - start++ - go func(page, num int64, out chan TransactionsList, wg *sync.WaitGroup) { - defer wg.Done() - block, err := p.client.GetTransactionsByBlock(num, page) - if err != nil { - return - } - out <- block - }(start, num, out, &wg) - } - wg.Wait() - close(out) - for r := range out { - txs = append(txs, r.TransactionList()...) - } - return txs + return p.client.GetCurrentBlockNumber() } func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - page := int64(1) - block, err := p.client.GetTransactionsByBlock(num, page) + block, err := p.client.GetAllTransactionsByBlockNumber(num) if err != nil { return nil, err } - txPages := p.GetAllBlockPages(block.TotalPages, num) - txs := append(txPages, block.TransactionList()...) var normalized []blockatlas.Tx - for _, tx := range txs { + for _, tx := range block { normalized = append(normalized, normalizeTransaction(tx, p.CoinIndex)) } return &blockatlas.Block{ Number: num, - ID: block.Hash, Txs: normalized, }, nil + } diff --git a/platform/ethereum/blockbook/block.go b/platform/bitcoin/blockbook/block.go similarity index 53% rename from platform/ethereum/blockbook/block.go rename to platform/bitcoin/blockbook/block.go index e630b9d8d..98e4d336a 100644 --- a/platform/ethereum/blockbook/block.go +++ b/platform/bitcoin/blockbook/block.go @@ -1,25 +1,20 @@ package blockbook import ( - "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" ) func (c *Client) GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, error) { - block, err := c.GetBlock(num) + block, err := c.GetAllTransactionsByBlockNumber(num) if err != nil { return nil, err } - - txs := make([]blockatlas.Tx, 0, len(block.Transactions)) - for _, srcTx := range block.Transactions { - tx := normalizeTx(&srcTx, coinIndex) - txs = append(txs, tx) + txs := make([]blockatlas.Tx, 0) + for _, srcTx := range block { + txs = append(txs, normalizeTx(&srcTx, coinIndex)) } return &blockatlas.Block{ Number: num, - ID: strconv.FormatInt(num, 10), Txs: txs, }, nil } diff --git a/platform/bitcoin/blockbook/client.go b/platform/bitcoin/blockbook/client.go new file mode 100644 index 000000000..712dbf54d --- /dev/null +++ b/platform/bitcoin/blockbook/client.go @@ -0,0 +1,129 @@ +package blockbook + +import ( + "fmt" + "net/url" + "strconv" + "sync" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + + "github.com/trustwallet/golibs/client" +) + +type Client struct { + client.Request +} + +// Block + +func (c *Client) GetCurrentBlockNumber() (int64, error) { + var nodeInfo NodeInfo + err := c.Get(&nodeInfo, "api", nil) + if err != nil { + return 0, err + } + return nodeInfo.Blockbook.BestHeight, nil +} + +// Tokens + +func (c *Client) GetTokens(address string) ([]Token, error) { + var res TransactionsList + path := fmt.Sprintf("api/v2/address/%s", address) + query := url.Values{"details": {"tokenBalances"}} + err := c.Get(&res, path, query) + return res.Tokens, err +} + +// Transactions +func (c *Client) GetAllTransactionsByBlockNumber(num int64) ([]Transaction, error) { + page := int64(1) + block, err := c.GetTransactionsByBlockNumber(num, page) + if err != nil { + return nil, err + } + txPages := c.getAllBlockPages(block.TotalPages, num) + txs := append(txPages, block.TransactionList()...) + return txs, nil +} + +func (c *Client) GetTxs(address string) (TransactionsList, error) { + return c.getTransactionsForContract(address, "", blockatlas.TxPerPage) +} + +func (c *Client) GetTxsWithContract(address, contract string) (TransactionsList, error) { + return c.getTransactionsForContract(address, contract, blockatlas.TxPerPage) +} + +func (c *Client) GetTransactionsByBlockNumber(number int64, page int64) (block TransactionsList, err error) { + path := fmt.Sprintf("api/v2/block/%s", strconv.FormatInt(number, 10)) + args := url.Values{ + "page": {strconv.FormatInt(page, 10)}, + } + err = c.Get(&block, path, args) + return block, err +} + +func (c *Client) getTransactionsForContract(address, contract string, limit int) (transactions TransactionsList, err error) { + path := fmt.Sprintf("api/v2/address/%s", address) + err = c.Get(&transactions, path, url.Values{ + "page": {"1"}, + "details": {"txs"}, + "pageSize": {strconv.Itoa(limit)}, + "contract": {contract}, + }) + return transactions, err +} + +func (c *Client) GetTransactionsByXpub(xpub string) (transactions TransactionsList, err error) { + path := fmt.Sprintf("api/v2/xpub/%s", xpub) + args := url.Values{ + "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, + "details": {"txs"}, + "tokens": {"derived"}, + } + err = c.Get(&transactions, path, args) + return transactions, err +} + +func (c *Client) GetAddressesFromXpub(xpub string) (tokens []Token, err error) { + path := fmt.Sprintf("api/v2/xpub/%s", xpub) + args := url.Values{ + "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, + "details": {"txs"}, + "tokens": {"derived"}, + } + var transactions TransactionsList + err = c.Get(&transactions, path, args) + return transactions.Tokens, err +} + +func (c *Client) getAllBlockPages(total, num int64) []Transaction { + txs := make([]Transaction, 0) + if total <= 1 { + return txs + } + + start := int64(1) + var wg sync.WaitGroup + out := make(chan TransactionsList, int(total-start)) + wg.Add(int(total - start)) + for start < total { + start++ + go func(page, num int64, out chan TransactionsList, wg *sync.WaitGroup) { + defer wg.Done() + block, err := c.GetTransactionsByBlockNumber(num, page) + if err != nil { + return + } + out <- block + }(start, num, out, &wg) + } + wg.Wait() + close(out) + for r := range out { + txs = append(txs, r.TransactionList()...) + } + return txs +} diff --git a/platform/bitcoin/blockbook/model.go b/platform/bitcoin/blockbook/model.go new file mode 100644 index 000000000..0e27e31d4 --- /dev/null +++ b/platform/bitcoin/blockbook/model.go @@ -0,0 +1,131 @@ +package blockbook + +import ( + "encoding/json" + "math/big" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + + "github.com/trustwallet/golibs/tokentype" +) + +type NodeInfo struct { + Blockbook *Blockbook `json:"blockbook"` +} + +type Blockbook struct { + BestHeight int64 `json:"bestHeight"` +} + +type TokenTransfer struct { + Decimals uint `json:"decimals"` + From string `json:"from"` + Name string `json:"name"` + Symbol string `json:"symbol"` + To string `json:"to"` + Token string `json:"token"` + Type string `json:"type"` + Value string `json:"value"` +} + +// Token contains info about tokens held by an address +type Token struct { + Balance string `json:"balance,omitempty"` + Contract string `json:"contract"` + Decimals uint `json:"decimals"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Type tokentype.Type `json:"type"` +} + +// EthereumSpecific contains ethereum specific transaction data +type EthereumSpecific struct { + Status int `json:"status"` // -1 pending, 0 Fail, 1 OK + Nonce uint64 `json:"nonce"` + GasLimit *big.Int `json:"gasLimit"` + GasUsed *big.Int `json:"gasUsed"` + GasPrice string `json:"gasPrice"` + Data string `json:"data,omitempty"` +} + +type TransactionsList struct { + Page int64 `json:"page"` + TotalPages int64 `json:"totalPages"` + ItemsOnPage int64 `json:"itemsOnPage"` + Transactions []Transaction `json:"transactions,omitempty"` + Txs interface{} `json:"txs,omitempty"` + Tokens []Token `json:"tokens,omitempty"` + TxCount int64 `json:"txCount,omitempty"` + Hash string `json:"hash,omitempty"` +} + +func (tl *TransactionsList) TransactionList() []Transaction { + if tl.Transactions != nil { + return tl.Transactions + } + b, err := json.Marshal(tl.Txs) + if err != nil { + return tl.Transactions + } + var txs []Transaction + err = json.Unmarshal(b, &txs) + if err != nil { + return tl.Transactions + } + return txs +} + +type Transaction struct { + ID string `json:"txid"` + Version uint64 `json:"version"` + Vin []Output `json:"vin"` + Vout []Output `json:"vout"` + BlockHash string `json:"blockHash"` + BlockHeight int64 `json:"blockHeight"` + Confirmations uint64 `json:"confirmations"` + BlockTime int64 `json:"blockTime"` + Value string `json:"value"` + ValueOut string `json:"valueOut"` + Fees string `json:"fees"` + TokenTransfers []TokenTransfer `json:"tokenTransfers,omitempty"` + EthereumSpecific *EthereumSpecific `json:"ethereumSpecific,omitempty"` +} + +func (transaction Transaction) Amount() string { + if len(transaction.Value) == 0 { + return transaction.ValueOut + } + return transaction.Value +} + +func (transaction Transaction) GetStatus() blockatlas.Status { + if transaction.Confirmations == 0 { + return blockatlas.StatusPending + } + return blockatlas.StatusCompleted +} + +func (transaction Transaction) GetBlockHeight() uint64 { + if transaction.BlockHeight > 0 { + return uint64(transaction.BlockHeight) + } + return 0 +} + +type Output struct { + TxId string `json:"txid,omitempty"` + Value string `json:"value,omitempty"` + Addresses []string `json:"addresses,omitempty"` + ScriptPubKey ScriptPubKey `json:"scriptPubKey,omitempty"` +} + +type ScriptPubKey struct { + Addresses []string `json:"addresses,omitempty"` +} + +func (o Output) OutputAddress() []string { + if len(o.Addresses) == 0 { + return o.ScriptPubKey.Addresses + } + return o.Addresses +} diff --git a/platform/ethereum/blockbook/model_extension.go b/platform/bitcoin/blockbook/model_extension.go similarity index 58% rename from platform/ethereum/blockbook/model_extension.go rename to platform/bitcoin/blockbook/model_extension.go index 40d96deda..787ce710e 100644 --- a/platform/ethereum/blockbook/model_extension.go +++ b/platform/bitcoin/blockbook/model_extension.go @@ -19,21 +19,21 @@ func (s *EthereumSpecific) GetStatus() (blockatlas.Status, string) { } } -func (t *Transaction) FromAddress() string { - if len(t.Vin) > 0 && len(t.Vin[0].Addresses) > 0 { - return t.Vin[0].Addresses[0] +func (transaction *Transaction) FromAddress() string { + if len(transaction.Vin) > 0 && len(transaction.Vin[0].Addresses) > 0 { + return transaction.Vin[0].Addresses[0] } return "" } -func (t *Transaction) GetFee() string { - status, _ := t.EthereumSpecific.GetStatus() +func (transaction *Transaction) GetFee() string { + status, _ := transaction.EthereumSpecific.GetStatus() if status != blockatlas.StatusPending { - return t.Fees + return transaction.Fees } - gasLimit := t.EthereumSpecific.GasLimit - gasPrice, ok := new(big.Int).SetString(t.EthereumSpecific.GasPrice, 10) + gasLimit := transaction.EthereumSpecific.GasLimit + gasPrice, ok := new(big.Int).SetString(transaction.EthereumSpecific.GasPrice, 10) if gasLimit == nil || !ok { return "0" } @@ -41,9 +41,9 @@ func (t *Transaction) GetFee() string { return fee.String() } -func (t *Transaction) ToAddress() string { - if len(t.Vout) > 0 && len(t.Vout[0].Addresses) > 0 { - return t.Vout[0].Addresses[0] +func (transaction *Transaction) ToAddress() string { + if len(transaction.Vout) > 0 && len(transaction.Vout[0].Addresses) > 0 { + return transaction.Vout[0].Addresses[0] } return "" } diff --git a/platform/ethereum/blockbook/token.go b/platform/bitcoin/blockbook/token.go similarity index 100% rename from platform/ethereum/blockbook/token.go rename to platform/bitcoin/blockbook/token.go diff --git a/platform/ethereum/blockbook/token_test.go b/platform/bitcoin/blockbook/token_test.go similarity index 100% rename from platform/ethereum/blockbook/token_test.go rename to platform/bitcoin/blockbook/token_test.go diff --git a/platform/ethereum/blockbook/transaction.go b/platform/bitcoin/blockbook/transaction.go similarity index 97% rename from platform/ethereum/blockbook/transaction.go rename to platform/bitcoin/blockbook/transaction.go index 3a641f136..23e40ff67 100644 --- a/platform/ethereum/blockbook/transaction.go +++ b/platform/bitcoin/blockbook/transaction.go @@ -24,7 +24,7 @@ func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas. return NormalizePage(page, address, token, coinIndex), nil } -func NormalizePage(srcPage *Page, address, token string, coinIndex uint) (txs blockatlas.TxPage) { +func NormalizePage(srcPage TransactionsList, address, token string, coinIndex uint) (txs blockatlas.TxPage) { normalizedAddr, err := Address.EIP55Checksum(address) if err != nil { return @@ -46,7 +46,7 @@ func NormalizePage(srcPage *Page, address, token string, coinIndex uint) (txs bl func normalizeTx(srcTx *Transaction, coinIndex uint) blockatlas.Tx { status, errReason := srcTx.EthereumSpecific.GetStatus() normalized := blockatlas.Tx{ - ID: srcTx.TxID, + ID: srcTx.ID, Coin: coinIndex, From: srcTx.FromAddress(), To: srcTx.ToAddress(), diff --git a/platform/ethereum/blockbook/transaction_test.go b/platform/bitcoin/blockbook/transaction_test.go similarity index 98% rename from platform/ethereum/blockbook/transaction_test.go rename to platform/bitcoin/blockbook/transaction_test.go index 859358934..dc5b324b9 100644 --- a/platform/ethereum/blockbook/transaction_test.go +++ b/platform/bitcoin/blockbook/transaction_test.go @@ -365,14 +365,14 @@ func TestNormalizePage(t *testing.T) { }, } for _, tt := range tests { - var page Page + var page TransactionsList var txPage blockatlas.TxPage err := json.Unmarshal([]byte(tt.args.srcPage), &page) assert.Nil(t, err) err = json.Unmarshal([]byte(tt.want), &txPage) assert.Nil(t, err) t.Run(tt.name, func(t *testing.T) { - got := NormalizePage(&page, tt.args.address, tt.args.token, tt.args.coinIndex) + got := NormalizePage(page, tt.args.address, tt.args.token, tt.args.coinIndex) gotJson, err := json.Marshal(got) assert.Nil(t, err) gotTxPage, err := json.Marshal(txPage) diff --git a/platform/bitcoin/client.go b/platform/bitcoin/client.go deleted file mode 100644 index d6b05c55d..000000000 --- a/platform/bitcoin/client.go +++ /dev/null @@ -1,60 +0,0 @@ -package bitcoin - -import ( - "fmt" - "net/url" - "strconv" - - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/client" -) - -type Client struct { - client.Request -} - -func (c *Client) GetTransactions(address string) (transactions TransactionsList, err error) { - path := fmt.Sprintf("api/v2/address/%s", address) - err = c.Get(&transactions, path, url.Values{ - "details": {"txs"}, - "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, - }) - return transactions, err -} - -func (c *Client) GetTransactionsByXpub(xpub string) (transactions TransactionsList, err error) { - path := fmt.Sprintf("api/v2/xpub/%s", xpub) - args := url.Values{ - "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, - "details": {"txs"}, - "tokens": {"derived"}, - } - err = c.Get(&transactions, path, args) - return transactions, err -} - -func (c *Client) GetAddressesFromXpub(xpub string) (tokens []Token, err error) { - path := fmt.Sprintf("api/v2/xpub/%s", xpub) - args := url.Values{ - "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, - "details": {"txs"}, - "tokens": {"derived"}, - } - var transactions TransactionsList - err = c.Get(&transactions, path, args) - return transactions.Tokens, err -} - -func (c *Client) GetTransactionsByBlock(number int64, page int64) (block TransactionsList, err error) { - path := fmt.Sprintf("api/v2/block/%s", strconv.FormatInt(number, 10)) - args := url.Values{ - "page": {strconv.FormatInt(page, 10)}, - } - err = c.Get(&block, path, args) - return block, err -} - -func (c *Client) GetBlockNumber() (status BlockchainStatus, err error) { - err = c.Get(&status, "api", nil) - return status, err -} diff --git a/platform/bitcoin/model.go b/platform/bitcoin/model.go deleted file mode 100644 index 545a6b831..000000000 --- a/platform/bitcoin/model.go +++ /dev/null @@ -1,97 +0,0 @@ -package bitcoin - -import "encoding/json" - -type TransactionsList struct { - Page int64 `json:"page"` - TotalPages int64 `json:"totalPages"` - ItemsOnPage int64 `json:"itemsOnPage"` - Transactions []Transaction `json:"transactions,omitempty"` - Txs interface{} `json:"txs,omitempty"` - Tokens []Token `json:"tokens,omitempty"` - TxCount int64 `json:"txCount,omitempty"` - Hash string `json:"hash,omitempty"` -} - -func (tl *TransactionsList) TransactionList() []Transaction { - if tl.Transactions != nil { - return tl.Transactions - } - b, err := json.Marshal(tl.Txs) - if err != nil { - return tl.Transactions - } - var txs []Transaction - err = json.Unmarshal(b, &txs) - if err != nil { - return tl.Transactions - } - return txs -} - -type Tx struct { - ID string `json:"id"` -} - -type Transaction struct { - ID string `json:"txid"` - Version uint64 `json:"version"` - Vin []Output `json:"vin"` - Vout []Output `json:"vout"` - BlockHash string `json:"blockHash"` - BlockHeight int64 `json:"blockHeight"` - Confirmations uint64 `json:"confirmations"` - BlockTime uint64 `json:"blockTime"` - Value string `json:"value"` - ValueOut string `json:"valueOut"` - Fees string `json:"fees"` -} - -func (transaction Transaction) Amount() string { - if len(transaction.Value) == 0 { - return transaction.ValueOut - } - return transaction.Value -} - -type Output struct { - TxId string `json:"txid,omitempty"` - Value string `json:"value,omitempty"` - Addresses []string `json:"addresses,omitempty"` - ScriptPubKey ScriptPubKey `json:"scriptPubKey,omitempty"` -} - -type ScriptPubKey struct { - Addresses []string `json:"addresses,omitempty"` -} - -func (o Output) OutputAddress() []string { - if len(o.Addresses) == 0 { - return o.ScriptPubKey.Addresses - } - return o.Addresses -} - -type Token struct { - Type string `json:"type"` - Name string `json:"name"` - Path string `json:"path"` - Transfers int `json:"transfers"` - Balance string `json:"balance"` -} - -type BlockchainStatus struct { - Backend Backend `json:"backend"` -} - -type Backend struct { - Chain string `json:"chain"` - Blocks int64 `json:"blocks"` -} - -func (transaction Transaction) GetBlockHeight() uint64 { - if transaction.BlockHeight > 0 { - return uint64(transaction.BlockHeight) - } - return 0 -} diff --git a/platform/bitcoin/transaction.go b/platform/bitcoin/transaction.go index b64b78ba7..bde4c4464 100644 --- a/platform/bitcoin/transaction.go +++ b/platform/bitcoin/transaction.go @@ -3,6 +3,8 @@ package bitcoin import ( "sort" + "github.com/trustwallet/blockatlas/platform/bitcoin/blockbook" + mapset "github.com/deckarep/golang-set" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" @@ -46,7 +48,7 @@ func (p *Platform) getTxsByXpub(xpub string) ([]blockatlas.Tx, error) { } func (p *Platform) getTxsByAddress(address string) ([]blockatlas.Tx, error) { - sourceTxs, err := p.client.GetTransactions(address) + sourceTxs, err := p.client.GetTxs(address) if err != nil { return []blockatlas.Tx{}, err } @@ -56,7 +58,7 @@ func (p *Platform) getTxsByAddress(address string) ([]blockatlas.Tx, error) { return txs, nil } -func normalizeTxs(sourceTxs TransactionsList, coinIndex uint, addressSet mapset.Set) []blockatlas.Tx { +func normalizeTxs(sourceTxs blockbook.TransactionsList, coinIndex uint, addressSet mapset.Set) []blockatlas.Tx { var txs []blockatlas.Tx for _, transaction := range sourceTxs.TransactionList() { if tx, ok := normalizeTransfer(transaction, coinIndex, addressSet); ok { @@ -66,7 +68,7 @@ func normalizeTxs(sourceTxs TransactionsList, coinIndex uint, addressSet mapset. return txs } -func normalizeTransfer(transaction Transaction, coinIndex uint, addressSet mapset.Set) (tx blockatlas.Tx, ok bool) { +func normalizeTransfer(transaction blockbook.Transaction, coinIndex uint, addressSet mapset.Set) (tx blockatlas.Tx, ok bool) { tx = normalizeTransaction(transaction, coinIndex) direction := blockatlas.InferDirection(&tx, addressSet) value := blockatlas.InferValue(&tx, direction, addressSet) @@ -81,7 +83,7 @@ func normalizeTransfer(transaction Transaction, coinIndex uint, addressSet mapse return tx, true } -func normalizeTransaction(tx Transaction, coinIndex uint) blockatlas.Tx { +func normalizeTransaction(tx blockbook.Transaction, coinIndex uint) blockatlas.Tx { inputs := parseOutputs(tx.Vin) outputs := parseOutputs(tx.Vout) from := "" @@ -104,10 +106,10 @@ func normalizeTransaction(tx Transaction, coinIndex uint) blockatlas.Tx { Inputs: inputs, Outputs: outputs, Fee: fees, - Date: int64(tx.BlockTime), + Date: tx.BlockTime, Type: blockatlas.TxTransfer, Block: tx.GetBlockHeight(), - Status: tx.getStatus(), + Status: tx.GetStatus(), Sequence: 0, Meta: blockatlas.Transfer{ Value: amount, @@ -117,7 +119,7 @@ func normalizeTransaction(tx Transaction, coinIndex uint) blockatlas.Tx { } } -func parseOutputs(outputs []Output) (addresses []blockatlas.TxOutput) { +func parseOutputs(outputs []blockbook.Output) (addresses []blockatlas.TxOutput) { set := make(map[string]*blockatlas.TxOutput) var ordered []string for _, output := range outputs { @@ -140,10 +142,3 @@ func parseOutputs(outputs []Output) (addresses []blockatlas.TxOutput) { } return addresses } - -func (transaction *Transaction) getStatus() blockatlas.Status { - if transaction.Confirmations == 0 { - return blockatlas.StatusPending - } - return blockatlas.StatusCompleted -} diff --git a/platform/bitcoin/transaction_test.go b/platform/bitcoin/transaction_test.go index 11a681872..e801b07fc 100644 --- a/platform/bitcoin/transaction_test.go +++ b/platform/bitcoin/transaction_test.go @@ -6,6 +6,8 @@ import ( "reflect" "testing" + "github.com/trustwallet/blockatlas/platform/bitcoin/blockbook" + mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" @@ -239,7 +241,7 @@ func TestNormalizeTransfer(t *testing.T) { } for _, test := range tests { - var transaction Transaction + var transaction blockbook.Transaction rErr := json.Unmarshal([]byte(test.RawTx), &transaction) if rErr != nil { @@ -273,15 +275,15 @@ func TestNormalizeTransfer(t *testing.T) { func TestTransactionStatus(t *testing.T) { tests := []struct { - Tx Transaction + Tx blockbook.Transaction Expected blockatlas.Status }{ - {Transaction{Confirmations: 0}, blockatlas.StatusPending}, - {Transaction{Confirmations: 1}, blockatlas.StatusCompleted}, + {blockbook.Transaction{Confirmations: 0}, blockatlas.StatusPending}, + {blockbook.Transaction{Confirmations: 1}, blockatlas.StatusCompleted}, } for _, test := range tests { - assert.Equal(t, test.Expected, test.Tx.getStatus()) + assert.Equal(t, test.Expected, test.Tx.GetStatus()) } } @@ -367,7 +369,7 @@ func TestParseOutputs(t *testing.T) { }, } for _, tt := range tests { - var outputs []Output + var outputs []blockbook.Output _ = json.Unmarshal([]byte(tt.outputs), &outputs) want := parseOutputs(outputs) t.Run(tt.name, func(t *testing.T) { diff --git a/platform/elrond/client.go b/platform/elrond/client.go index d935feda2..3d1911bd3 100644 --- a/platform/elrond/client.go +++ b/platform/elrond/client.go @@ -40,7 +40,6 @@ func (c *Client) GetBlockByNumber(height int64) (*blockatlas.Block, error) { return &blockatlas.Block{ Number: int64(block.Nonce), - ID: block.Hash, Txs: txs, }, nil } diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index cebc5a32f..7829984bb 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -2,7 +2,7 @@ package ethereum import ( "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/platform/ethereum/blockbook" + "github.com/trustwallet/blockatlas/platform/bitcoin/blockbook" "github.com/trustwallet/blockatlas/platform/ethereum/collection" "github.com/trustwallet/blockatlas/platform/ethereum/trustray" "github.com/trustwallet/golibs/coin" diff --git a/platform/ethereum/blockbook/client.go b/platform/ethereum/blockbook/client.go deleted file mode 100644 index c654652a9..000000000 --- a/platform/ethereum/blockbook/client.go +++ /dev/null @@ -1,55 +0,0 @@ -package blockbook - -import ( - "fmt" - "net/url" - - "github.com/trustwallet/golibs/client" -) - -type Client struct { - client.Request -} - -func (c *Client) GetTxs(address string) (*Page, error) { - return c.getTransactions(address, "") -} - -func (c *Client) GetTxsWithContract(address, contract string) (*Page, error) { - return c.getTransactions(address, contract) -} - -func (c *Client) GetTokens(address string) ([]Token, error) { - return c.getTokens(address) -} - -func (c *Client) GetCurrentBlockNumber() (int64, error) { - var nodeInfo NodeInfo - err := c.Get(&nodeInfo, "api", nil) - if err != nil { - return 0, err - } - return nodeInfo.Blockbook.BestHeight, nil -} - -func (c *Client) GetBlock(num int64) (block Block, err error) { - path := fmt.Sprintf("api/v2/block/%d", num) - err = c.Get(&block, path, nil) - return -} - -func (c *Client) getTransactions(address, contract string) (page *Page, err error) { - path := fmt.Sprintf("api/v2/address/%s", address) - query := url.Values{"page": {"1"}, "pageSize": {"25"}, "details": {"txs"}, "contract": {contract}} - err = c.Get(&page, path, query) - return -} - -func (c *Client) getTokens(address string) ([]Token, error) { - var res Page - path := fmt.Sprintf("api/v2/address/%s", address) - query := url.Values{"details": {"tokenBalances"}} - err := c.Get(&res, path, query) - - return res.Tokens, err -} diff --git a/platform/ethereum/blockbook/model.go b/platform/ethereum/blockbook/model.go deleted file mode 100644 index f7645ee45..000000000 --- a/platform/ethereum/blockbook/model.go +++ /dev/null @@ -1,76 +0,0 @@ -package blockbook - -import ( - "github.com/trustwallet/golibs/tokentype" - "math/big" -) - -type Page struct { - Transactions []Transaction `json:"transactions,omitempty"` - Tokens []Token `json:"tokens,omitempty"` -} - -type NodeInfo struct { - Blockbook *Blockbook `json:"blockbook"` - Backend *Backend `json:"backend"` -} - -type Blockbook struct { - BestHeight int64 `json:"bestHeight"` -} - -type Backend struct { - Blocks int64 `json:"blocks"` -} - -type Block struct { - Transactions []Transaction `json:"txs"` -} - -type Transaction struct { - TxID string `json:"txid"` - Vin []Output `json:"vin"` - Vout []Output `json:"vout"` - BlockHeight int64 `json:"blockHeight"` - BlockTime int64 `json:"blockTime"` - Value string `json:"value"` - Fees string `json:"fees"` - TokenTransfers []TokenTransfer `json:"tokenTransfers,omitempty"` - EthereumSpecific *EthereumSpecific `json:"ethereumSpecific,omitempty"` -} - -type Output struct { - Value string `json:"value,omitempty"` - Addresses []string `json:"addresses"` -} - -type TokenTransfer struct { - Decimals uint `json:"decimals"` - From string `json:"from"` - Name string `json:"name"` - Symbol string `json:"symbol"` - To string `json:"to"` - Token string `json:"token"` - Type string `json:"type"` - Value string `json:"value"` -} - -// Token contains info about tokens held by an address -type Token struct { - Balance string `json:"balance,omitempty"` - Contract string `json:"contract"` - Decimals uint `json:"decimals"` - Name string `json:"name"` - Symbol string `json:"symbol"` - Type tokentype.Type `json:"type"` -} - -// EthereumSpecific contains ethereum specific transaction data -type EthereumSpecific struct { - Status int `json:"status"` // -1 pending, 0 Fail, 1 OK - Nonce uint64 `json:"nonce"` - GasLimit *big.Int `json:"gasLimit"` - GasUsed *big.Int `json:"gasUsed"` - GasPrice string `json:"gasPrice"` - Data string `json:"data,omitempty"` -} diff --git a/platform/ethereum/trustray/block.go b/platform/ethereum/trustray/block.go index 208432ea7..f0d614a19 100644 --- a/platform/ethereum/trustray/block.go +++ b/platform/ethereum/trustray/block.go @@ -1,8 +1,6 @@ package trustray import ( - "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" ) @@ -17,7 +15,6 @@ func (c *Client) GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, } return &blockatlas.Block{ Number: num, - ID: strconv.FormatInt(num, 10), Txs: txs, }, nil } diff --git a/platform/harmony/block.go b/platform/harmony/block.go index c6e90cb42..b3af79b59 100644 --- a/platform/harmony/block.go +++ b/platform/harmony/block.go @@ -23,7 +23,6 @@ func (p *Platform) NormalizeBlock(block *BlockInfo) blockatlas.Block { return blockatlas.Block{} } return blockatlas.Block{ - ID: block.Hash, Number: int64(blockNumber), Txs: NormalizeTxs(block.Transactions), } diff --git a/platform/nimiq/block.go b/platform/nimiq/block.go index e24584790..819005b7b 100644 --- a/platform/nimiq/block.go +++ b/platform/nimiq/block.go @@ -21,7 +21,6 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { func NormalizeBlock(srcBlock *Block) blockatlas.Block { return blockatlas.Block{ Number: srcBlock.Number, - ID: srcBlock.Hash, Txs: NormalizeTxs(srcBlock.Txs), } } diff --git a/platform/stellar/block.go b/platform/stellar/block.go index 0de588d8b..2dcdc94d7 100644 --- a/platform/stellar/block.go +++ b/platform/stellar/block.go @@ -18,7 +18,6 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { } func (p *Platform) NormalizeBlock(block *Block) blockatlas.Block { return blockatlas.Block{ - ID: block.Ledger.Id, Number: block.Ledger.Sequence, Txs: p.NormalizePayments(block.Payments), } diff --git a/platform/vechain/block.go b/platform/vechain/block.go index bae6e1ccd..6566aa5ca 100644 --- a/platform/vechain/block.go +++ b/platform/vechain/block.go @@ -20,7 +20,6 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { } return &blockatlas.Block{ Number: num, - ID: block.Id, Txs: txs, }, nil } diff --git a/services/parser/parser.go b/services/parser/parser.go index c3894b754..9d6d6aae2 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -82,7 +82,14 @@ func parse(params Params) { err = SaveLastParsedBlock(params, blocks) if err != nil { - log.WithFields(log.Fields{"operation": "run SaveLastParsedBlock", "coin": params.Api.Coin().Handle}).Error(err) + log.WithFields(log.Fields{ + "operation": "run SaveLastParsedBlock", + "coin": params.Api.Coin().Handle, + "blocks": blocks, + "lastParsedBlock": lastParsedBlock, + "currentBlock": currentBlock, + "tags": raven.Tags{{Key: "coin", Value: params.Api.Coin().Handle}}, + }).Error(err) time.Sleep(params.ParsingBlocksInterval) return } @@ -189,7 +196,16 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) ([]blockatl for err := range errorsChan { errorsList = append(errorsList, err) } - log.WithFields(log.Fields{"coin": params.Api.Coin().Handle, "count": len(errorsList), "blocks": errorsList}).Error("Fetch blocks errors") + log.WithFields(log.Fields{ + "coin": params.Api.Coin().Handle, + "count": len(errorsList), + "blocks": errorsList, + "tags": raven.Tags{ + {Key: "coin", Value: params.Api.Coin().Handle}, + }, + }).Error("Fetch Blocks Errors") + + return []blockatlas.Block{}, fmt.Errorf("unable to fetch blocks: %d: %d", lastParsedBlock, currentBlock) } blocks := make([]blockatlas.Block, 0, len(blocksChan)) diff --git a/services/subscriber/subscriber.go b/services/subscriber/subscriber.go index 98d91ffd7..84e884444 100644 --- a/services/subscriber/subscriber.go +++ b/services/subscriber/subscriber.go @@ -32,7 +32,7 @@ func RunSubscriber(database *db.Instance, delivery amqp.Delivery) error { case AddSubscription: err := database.CreateSubscriptions(subscriptions) if err != nil { - log.WithFields(log.Fields{"service": Notifications, "operation": event.Operation, "subscriptions": len(subscriptions)}).Error(err) + log.WithFields(log.Fields{"service": Notifications, "operation": event.Operation, "subscriptions": subscriptions}).Error(err) return err } log.WithFields(log.Fields{"service": Notifications, "operation": event.Operation, "subscriptions": len(subscriptions)}).Info("Add subscriptions") From b4f6dc360bed412ff555aa981d83e4421380f104 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 7 Jan 2021 19:44:33 +0800 Subject: [PATCH 451/506] cleanup tests (#1348) --- .gitattributes | 1 + .github/workflows/ci.yml | 2 +- mock/mockserver/mockserver_test.go | 18 +- pkg/blockatlas/marshal_test.go | 52 +- pkg/blockatlas/mocks/bnb_token_response.json | 577 +++++ pkg/blockatlas/mocks/bnb_token_txs.json | 577 +++++ pkg/blockatlas/mocks/nim_tx.json | 14 + pkg/blockatlas/observer_test.go | 3 +- pkg/blockatlas/tx_test.go | 231 +- platform/aeternity/mocks/transfer.json | 19 + platform/aeternity/transaction_test.go | 128 +- platform/aion/mocks/transfer.json | 21 + platform/aion/transaction.go | 15 +- platform/aion/transaction_test.go | 114 +- platform/algorand/mocks/transfer.json | 30 + platform/algorand/transaction_test.go | 114 +- platform/binance/base_test.go | 29 +- platform/binance/block_test.go | 4 +- .../binance/mocks/account_meta_response.json | 61 + .../binance/mocks/block_multi_no_orders.json | 33 + .../binance/mocks/block_multi_response.json | 59 + platform/binance/mocks/block_no_orders.json | 19 + platform/binance/mocks/block_response.json | 54 + platform/binance/mocks/node_info.json | 57 + platform/binance/mocks/tokens.json | 26 + platform/binance/mocks/tokens_response.json | 802 +++++++ platform/binance/mocks/txs.json | 352 +++ platform/binance/mocks/txs_ava_response.json | 505 ++++ platform/binance/mocks/txs_response.json | 505 ++++ platform/binance/model_test.go | 18 +- platform/binance/token_test.go | 6 +- platform/binance/transaction_test.go | 3 +- platform/bitcoin/mocks/incoming_tx.json | 40 + platform/bitcoin/mocks/outgoing_tx.json | 30 + platform/bitcoin/mocks/pending_tx.json | 40 + platform/bitcoin/transaction_test.go | 296 +-- platform/cosmos/mocks/claim_1.json | 92 + platform/cosmos/mocks/claim_2.json | 96 + platform/cosmos/mocks/delegate_tx.json | 66 + platform/cosmos/mocks/delegation.json | 8 + platform/cosmos/mocks/transfer.json | 68 + platform/cosmos/mocks/transfer_failed.json | 48 + platform/cosmos/mocks/transfer_kava.json | 68 + platform/cosmos/mocks/unbonding.json | 14 + platform/cosmos/mocks/undelegate_tx.json | 71 + platform/cosmos/mocks/validator.json | 25 + platform/cosmos/stake_test.go | 109 +- platform/cosmos/transaction_test.go | 807 ++----- platform/elrond/mocks/tx.json | 13 + platform/elrond/mocks/tx_2.json | 13 + platform/elrond/mocks/tx_3.json | 15 + platform/elrond/mocks/tx_4.json | 13 + platform/elrond/mocks/tx_5.json | 13 + platform/elrond/mocks/tx_6.json | 13 + platform/elrond/transaction_test.go | 311 +-- platform/ethereum/collection_test.go | 349 +-- .../ethereum/mocks/opensea_collectible.json | 24 + .../ethereum/mocks/opensea_collections.json | 219 ++ platform/ethereum/transaction_test.go | 51 +- platform/ethereum/trustray/token_test.go | 11 +- .../ethereum/trustray/transaction_test.go | 12 +- platform/filecoin/block.go | 1 + platform/filecoin/block_test.go | 10 +- platform/filecoin/mocks/response.json | 229 ++ platform/fio/actor_test.go | 3 +- platform/harmony/mocks/delegation.json | 9 + platform/harmony/mocks/transfer.json | 19 + platform/harmony/mocks/validator.json | 65 + platform/harmony/stake_test.go | 126 +- platform/harmony/transaction_test.go | 121 +- platform/icon/mocks/transfer.json | 14 + platform/icon/transaction_test.go | 106 +- platform/iotex/mocks/transfer.json | 70 + platform/iotex/transaction.go | 3 +- platform/iotex/transaction_test.go | 168 +- platform/kava/transaction_test.go | 3 +- platform/nebulas/mocks/transfer.json | 19 + platform/nebulas/transaction_test.go | 116 +- .../getTransactionsByAddress_50.json | 0 platform/nimiq/mocks/pending_tx.json | 11 + platform/nimiq/mocks/tx.json | 16 + platform/nimiq/transaction_test.go | 59 +- platform/ontology/mocks/block_response.json | 60 + platform/ontology/mocks/transfer_fee.json | 18 + platform/ontology/mocks/transfer_ong.json | 18 + platform/ontology/mocks/transfer_ont.json | 25 + platform/ontology/mocks/transfer_rewards.json | 25 + platform/ontology/transaction.go | 1 + platform/ontology/transaction_test.go | 117 +- platform/ripple/mocks/payment.json | 31 + platform/ripple/mocks/payment_2.json | 37 + platform/ripple/mocks/payment_3.json | 8 + platform/ripple/mocks/payment_4.json | 34 + platform/ripple/mocks/payment_failed.json | 22 + platform/ripple/transaction_test.go | 360 +-- platform/solana/mocks/currentValidators.json | 38 + platform/solana/stake_test.go | 250 +- platform/stellar/mocks/create_tx.json | 13 + platform/stellar/mocks/transfer_tx.json | 18 + platform/stellar/transaction_test.go | 100 +- platform/tezos/mocks/account.json | 4 + platform/tezos/mocks/delegation_response.json | 483 ++++ platform/tezos/mocks/validator.json | 1 + platform/tezos/model_test.go | 3 +- platform/tezos/stake_test.go | 92 +- platform/tezos/transaction_test.go | 3 +- platform/theta/mocks/tfuel_transfer.json | 33 + platform/theta/mocks/theta_transfer.json | 32 + platform/theta/transaction_test.go | 161 +- platform/tron/mocks/delegation.json | 23 + platform/tron/mocks/delegation_2.json | 15 + platform/tron/mocks/token_transfer.json | 19 + platform/tron/mocks/token_txs_response.json | 442 ++++ .../tron/mocks/tokens/accounts_response.json | 87 + .../mocks/tokens/accounts_txs_response.json | 931 ++++++++ .../mocks/tokens/asset_1000542_response.json | 19 + .../mocks/tokens/asset_1000567_response.json | 20 + .../mocks/tokens/asset_tr7nh_response.json | 5 + .../tron/mocks/tokens/tokens_response.json | 98 + .../tron/mocks/tokens/trc20_response.json | 2107 +++++++++++++++++ .../tron/mocks/tokens/txs_empty_response.json | 12 + .../tron/mocks/tokens/txs_trc20_response.json | 295 +++ platform/tron/mocks/transfer.json | 18 + platform/tron/mocks/txs_response.json | 100 + platform/tron/stake_test.go | 169 +- platform/tron/token_test.go | 47 +- platform/tron/transaction_test.go | 135 +- platform/vechain/mocks/transfer.json | 13 + platform/vechain/mocks/transfer_log.json | 25 + platform/vechain/mocks/transfer_receipt.json | 31 + platform/vechain/mocks/tx_id.json | 4 + platform/vechain/transaction_test.go | 166 +- platform/waves/mocks/different_txs.json | 47 + platform/waves/mocks/transfer.json | 20 + platform/waves/transaction_test.go | 152 +- platform/zilliqa/mocks/transfer.json | 13 + platform/zilliqa/transaction.go | 1 + platform/zilliqa/transaction_test.go | 119 +- services/assets/validator_test.go | 6 + tests/integration/db_test/db_run_test.go | 5 +- 140 files changed, 12096 insertions(+), 3587 deletions(-) create mode 100644 pkg/blockatlas/mocks/bnb_token_response.json create mode 100644 pkg/blockatlas/mocks/bnb_token_txs.json create mode 100644 pkg/blockatlas/mocks/nim_tx.json create mode 100644 platform/aeternity/mocks/transfer.json create mode 100644 platform/aion/mocks/transfer.json create mode 100644 platform/algorand/mocks/transfer.json create mode 100644 platform/binance/mocks/account_meta_response.json create mode 100644 platform/binance/mocks/block_multi_no_orders.json create mode 100644 platform/binance/mocks/block_multi_response.json create mode 100644 platform/binance/mocks/block_no_orders.json create mode 100644 platform/binance/mocks/block_response.json create mode 100644 platform/binance/mocks/node_info.json create mode 100644 platform/binance/mocks/tokens.json create mode 100644 platform/binance/mocks/tokens_response.json create mode 100644 platform/binance/mocks/txs.json create mode 100644 platform/binance/mocks/txs_ava_response.json create mode 100644 platform/binance/mocks/txs_response.json create mode 100644 platform/bitcoin/mocks/incoming_tx.json create mode 100644 platform/bitcoin/mocks/outgoing_tx.json create mode 100644 platform/bitcoin/mocks/pending_tx.json create mode 100644 platform/cosmos/mocks/claim_1.json create mode 100644 platform/cosmos/mocks/claim_2.json create mode 100644 platform/cosmos/mocks/delegate_tx.json create mode 100644 platform/cosmos/mocks/delegation.json create mode 100644 platform/cosmos/mocks/transfer.json create mode 100644 platform/cosmos/mocks/transfer_failed.json create mode 100644 platform/cosmos/mocks/transfer_kava.json create mode 100644 platform/cosmos/mocks/unbonding.json create mode 100644 platform/cosmos/mocks/undelegate_tx.json create mode 100644 platform/cosmos/mocks/validator.json create mode 100644 platform/elrond/mocks/tx.json create mode 100644 platform/elrond/mocks/tx_2.json create mode 100644 platform/elrond/mocks/tx_3.json create mode 100644 platform/elrond/mocks/tx_4.json create mode 100644 platform/elrond/mocks/tx_5.json create mode 100644 platform/elrond/mocks/tx_6.json create mode 100644 platform/ethereum/mocks/opensea_collectible.json create mode 100644 platform/ethereum/mocks/opensea_collections.json create mode 100644 platform/filecoin/mocks/response.json create mode 100644 platform/harmony/mocks/delegation.json create mode 100644 platform/harmony/mocks/transfer.json create mode 100644 platform/harmony/mocks/validator.json create mode 100644 platform/icon/mocks/transfer.json create mode 100644 platform/iotex/mocks/transfer.json create mode 100644 platform/nebulas/mocks/transfer.json rename platform/nimiq/{tests => mocks}/getTransactionsByAddress_50.json (100%) create mode 100644 platform/nimiq/mocks/pending_tx.json create mode 100644 platform/nimiq/mocks/tx.json create mode 100644 platform/ontology/mocks/block_response.json create mode 100644 platform/ontology/mocks/transfer_fee.json create mode 100644 platform/ontology/mocks/transfer_ong.json create mode 100644 platform/ontology/mocks/transfer_ont.json create mode 100644 platform/ontology/mocks/transfer_rewards.json create mode 100644 platform/ripple/mocks/payment.json create mode 100644 platform/ripple/mocks/payment_2.json create mode 100644 platform/ripple/mocks/payment_3.json create mode 100644 platform/ripple/mocks/payment_4.json create mode 100644 platform/ripple/mocks/payment_failed.json create mode 100644 platform/solana/mocks/currentValidators.json create mode 100644 platform/stellar/mocks/create_tx.json create mode 100644 platform/stellar/mocks/transfer_tx.json create mode 100644 platform/tezos/mocks/account.json create mode 100644 platform/tezos/mocks/delegation_response.json create mode 100644 platform/tezos/mocks/validator.json create mode 100644 platform/theta/mocks/tfuel_transfer.json create mode 100644 platform/theta/mocks/theta_transfer.json create mode 100644 platform/tron/mocks/delegation.json create mode 100644 platform/tron/mocks/delegation_2.json create mode 100644 platform/tron/mocks/token_transfer.json create mode 100644 platform/tron/mocks/token_txs_response.json create mode 100644 platform/tron/mocks/tokens/accounts_response.json create mode 100644 platform/tron/mocks/tokens/accounts_txs_response.json create mode 100644 platform/tron/mocks/tokens/asset_1000542_response.json create mode 100644 platform/tron/mocks/tokens/asset_1000567_response.json create mode 100644 platform/tron/mocks/tokens/asset_tr7nh_response.json create mode 100644 platform/tron/mocks/tokens/tokens_response.json create mode 100644 platform/tron/mocks/tokens/trc20_response.json create mode 100644 platform/tron/mocks/tokens/txs_empty_response.json create mode 100644 platform/tron/mocks/tokens/txs_trc20_response.json create mode 100644 platform/tron/mocks/transfer.json create mode 100644 platform/tron/mocks/txs_response.json create mode 100644 platform/vechain/mocks/transfer.json create mode 100644 platform/vechain/mocks/transfer_log.json create mode 100644 platform/vechain/mocks/transfer_receipt.json create mode 100644 platform/vechain/mocks/tx_id.json create mode 100644 platform/waves/mocks/different_txs.json create mode 100644 platform/waves/mocks/transfer.json create mode 100644 platform/zilliqa/mocks/transfer.json diff --git a/.gitattributes b/.gitattributes index 385a3fa58..73cfcd162 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ mock/ext-api-dyson/* linguist-vendored +*.json linguist-vendored diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73470d3de..c13894169 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: ^1.13 + go-version: ^1.15.6 id: go - name: Check out code diff --git a/mock/mockserver/mockserver_test.go b/mock/mockserver/mockserver_test.go index 8a636c2b5..93ab22ac0 100644 --- a/mock/mockserver/mockserver_test.go +++ b/mock/mockserver/mockserver_test.go @@ -6,47 +6,47 @@ import ( func TestMatchQueryParams(t *testing.T) { tests := [][]string{ - []string{ + { "a=1&b=20", "a=1&b=20", "true", }, - []string{ + { "a=1&b=20", "a=1&b=20&c=3", "true", }, - []string{ + { "a=1&b=20", "b=20&a=1", "true", }, - []string{ + { "a=1&b=20", "a=1&b=500", "false", }, - []string{ + { "a=1&b=20", "a=123&b=20", "false", }, - []string{ + { "a=1&b=20", "a=1", "false", }, - []string{ + { "a=1&b=20", "b=20", "false", }, - []string{ + { "", "c=500", "true", }, - []string{ + { "", "", "true", diff --git a/pkg/blockatlas/marshal_test.go b/pkg/blockatlas/marshal_test.go index 96d683afc..deaeca373 100644 --- a/pkg/blockatlas/marshal_test.go +++ b/pkg/blockatlas/marshal_test.go @@ -3,41 +3,31 @@ package blockatlas import ( "bytes" "encoding/json" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/golibs/coin" "reflect" "sort" "testing" + + "github.com/stretchr/testify/assert" + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" ) -var txJSON = []byte(`{ - "id": "14beb212aaefd06d7c6c0b25fc5ec242a2de2725af0a2827c105e743222cacd6", - "coin": 242, - "from": "NQ11 P00L 2HYP TUK8 VY6L 2N22 MMBU MHHR BSAA", - "to": "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA", - "fee": "138", - "date": 1548954343, - "block": 419040, - "status": "completed", - "type": "transfer", - "metadata": { - "value": "5004160" +var ( + txJSON, _ = mock.JsonFromFilePathToString("mocks/" + "nim_tx.json") + txModel = Tx{ + ID: "14beb212aaefd06d7c6c0b25fc5ec242a2de2725af0a2827c105e743222cacd6", + Coin: coin.NIM, + From: "NQ11 P00L 2HYP TUK8 VY6L 2N22 MMBU MHHR BSAA", + To: "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA", + Fee: "138", + Date: 1548954343, + Block: 419040, + Status: StatusCompleted, + Meta: &Transfer{ + Value: "5004160", + }, } -}`) - -var txModel = Tx{ - ID: "14beb212aaefd06d7c6c0b25fc5ec242a2de2725af0a2827c105e743222cacd6", - Coin: coin.NIM, - From: "NQ11 P00L 2HYP TUK8 VY6L 2N22 MMBU MHHR BSAA", - To: "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA", - Fee: "138", - Date: 1548954343, - Block: 419040, - Status: StatusCompleted, - Meta: &Transfer{ - Value: "5004160", - }, -} +) func TestTx_UnmarshalJSON(t *testing.T) { // Expect to get txModel, but with type set @@ -46,7 +36,7 @@ func TestTx_UnmarshalJSON(t *testing.T) { // Unmarshal source var got Tx - err := json.Unmarshal(txJSON, &got) + err := json.Unmarshal([]byte(txJSON), &got) if err != nil { t.Fatal(err) } @@ -75,7 +65,7 @@ func TestTx_MarshalJSON(t *testing.T) { } // Compare expected and output JSON - bytes.Equal(got, txJSON) + bytes.Equal(got, []byte(txJSON)) } func TestSortTxPage(t *testing.T) { diff --git a/pkg/blockatlas/mocks/bnb_token_response.json b/pkg/blockatlas/mocks/bnb_token_response.json new file mode 100644 index 000000000..7b355b5f7 --- /dev/null +++ b/pkg/blockatlas/mocks/bnb_token_response.json @@ -0,0 +1,577 @@ +[ + { + "id": "59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592484005, + "block": 95113723, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103643577", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "1089263465", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592442063, + "block": 95008674, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "1998400000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3", + "coin": 714, + "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592429461, + "block": 94977026, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2511060524", + "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592348463, + "block": 94777896, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "10998400000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592253063, + "block": 94538295, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "4146300000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592250904, + "block": 94532906, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103335769", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "63266290000", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592246708, + "block": 94522375, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "104150629", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "4512670728", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592245803, + "block": 94520016, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103335769", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "58689300000", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592244606, + "block": 94517032, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "108137171", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "1053055990", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592237402, + "block": 94498680, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "8479394653", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592223002, + "block": 94462381, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "38451401547", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592220661, + "block": 94456416, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "99998300000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592201404, + "block": 94407633, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103229158", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "1089751117", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592194201, + "block": 94389286, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "1098704296", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592179801, + "block": 94352682, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2461605848", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592177461, + "block": 94346701, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2324800000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592165402, + "block": 94316303, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "156671627595", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592163611, + "block": 94311779, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "106835633", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2042060818", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592158202, + "block": 94298059, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "3101371", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592154601, + "block": 94288998, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "367696585025", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592073191, + "block": 94084342, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103335769", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2503750000", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592066528, + "block": 94067506, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103335769", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "12959997250", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2", + "coin": 714, + "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592060464, + "block": 94052345, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2781326500", + "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E", + "coin": 714, + "from": "bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592060463, + "block": 94052341, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "39644614000", + "from": "bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592053265, + "block": 94034212, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "40798300000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + } +] diff --git a/pkg/blockatlas/mocks/bnb_token_txs.json b/pkg/blockatlas/mocks/bnb_token_txs.json new file mode 100644 index 000000000..7b355b5f7 --- /dev/null +++ b/pkg/blockatlas/mocks/bnb_token_txs.json @@ -0,0 +1,577 @@ +[ + { + "id": "59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592484005, + "block": 95113723, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103643577", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "1089263465", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592442063, + "block": 95008674, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "1998400000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3", + "coin": 714, + "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592429461, + "block": 94977026, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2511060524", + "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592348463, + "block": 94777896, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "10998400000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592253063, + "block": 94538295, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "4146300000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592250904, + "block": 94532906, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103335769", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "63266290000", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592246708, + "block": 94522375, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "104150629", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "4512670728", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592245803, + "block": 94520016, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103335769", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "58689300000", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592244606, + "block": 94517032, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "108137171", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "1053055990", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592237402, + "block": 94498680, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "8479394653", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592223002, + "block": 94462381, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "38451401547", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592220661, + "block": 94456416, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "99998300000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592201404, + "block": 94407633, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103229158", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "1089751117", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592194201, + "block": 94389286, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "1098704296", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592179801, + "block": 94352682, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2461605848", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592177461, + "block": 94346701, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2324800000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592165402, + "block": 94316303, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "156671627595", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592163611, + "block": 94311779, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "106835633", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2042060818", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592158202, + "block": 94298059, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "3101371", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592154601, + "block": 94288998, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103268674", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "367696585025", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592073191, + "block": 94084342, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103335769", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2503750000", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1592066528, + "block": 94067506, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "outgoing", + "memo": "103335769", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "12959997250", + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" + } + }, + { + "id": "FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2", + "coin": 714, + "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592060464, + "block": 94052345, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "2781326500", + "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E", + "coin": 714, + "from": "bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592060463, + "block": 94052341, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "39644614000", + "from": "bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + }, + { + "id": "19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "fee": "37500", + "date": 1592053265, + "block": 94034212, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "", + "symbol": "BUSD", + "token_id": "BUSD-BD1", + "decimals": 8, + "value": "40798300000", + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" + } + } +] diff --git a/pkg/blockatlas/mocks/nim_tx.json b/pkg/blockatlas/mocks/nim_tx.json new file mode 100644 index 000000000..16fb7b6e8 --- /dev/null +++ b/pkg/blockatlas/mocks/nim_tx.json @@ -0,0 +1,14 @@ +{ + "id": "14beb212aaefd06d7c6c0b25fc5ec242a2de2725af0a2827c105e743222cacd6", + "coin": 242, + "from": "NQ11 P00L 2HYP TUK8 VY6L 2N22 MMBU MHHR BSAA", + "to": "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA", + "fee": "138", + "date": 1548954343, + "block": 419040, + "status": "completed", + "type": "transfer", + "metadata": { + "value": "5004160" + } +} diff --git a/pkg/blockatlas/observer_test.go b/pkg/blockatlas/observer_test.go index b0386c4f9..f61e2abe5 100644 --- a/pkg/blockatlas/observer_test.go +++ b/pkg/blockatlas/observer_test.go @@ -1,9 +1,10 @@ package blockatlas import ( - "github.com/stretchr/testify/assert" "sort" "testing" + + "github.com/stretchr/testify/assert" ) func Test_parseSubscriptions(t *testing.T) { diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go index cc40e507d..e6659475c 100644 --- a/pkg/blockatlas/tx_test.go +++ b/pkg/blockatlas/tx_test.go @@ -9,109 +9,112 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" "github.com/trustwallet/golibs/tokentype" ) -var transferDst1 = Tx{ - ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", - Coin: coin.BNB, - From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - To: "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5", - Fee: "125000", - Date: 1555049867, - Block: 7761368, - Status: StatusCompleted, - Memo: "test", - Meta: Transfer{ - Value: "10000000000000", - Decimals: 8, - Symbol: "BNB", - }, -} - -var nativeTransferDst1 = Tx{ - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: StatusCompleted, - Memo: "test", - Meta: NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, -} - -var utxoTransferDst1 = Tx{ - ID: "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - Coin: coin.BTC, - Inputs: []TxOutput{ - { - Address: "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", - Value: "1", - }, - { - Address: "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh", - Value: "1", +var ( + transferDst1 = Tx{ + ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", + Coin: coin.BNB, + From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", + To: "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5", + Fee: "125000", + Date: 1555049867, + Block: 7761368, + Status: StatusCompleted, + Memo: "test", + Meta: Transfer{ + Value: "10000000000000", + Decimals: 8, + Symbol: "BNB", }, - { - Address: "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737", - Value: "1", + } + + nativeTransferDst1 = Tx{ + ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", + Coin: coin.BNB, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", + Fee: "125000", + Date: 1555117625, + Block: 7928667, + Status: StatusCompleted, + Memo: "test", + Meta: NativeTokenTransfer{ + TokenID: "YLC-D8B", + Symbol: "YLC", + Value: "210572645", + Decimals: 8, + From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", + To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", }, - }, - Outputs: []TxOutput{ - { - Address: "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", - Value: "3", - }, - }, - Fee: "125000", - Date: 1555117625, - Block: 592400, - Status: StatusCompleted, - Memo: "test", -} + } -var utxoTransferDst2 = Tx{ - ID: "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - Coin: coin.BTC, - Inputs: []TxOutput{ - { - Address: "bc1q6e8sdxlgc7ekqkqyevtrx8wshfv7sg66z3z6ce", - Value: "4", + utxoTransferDst1 = Tx{ + ID: "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", + Coin: coin.BTC, + Inputs: []TxOutput{ + { + Address: "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", + Value: "1", + }, + { + Address: "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh", + Value: "1", + }, + { + Address: "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737", + Value: "1", + }, }, - { - Address: "bc1q7nn4txus4g6fc5v7d2tha35ely8mfpd8qvv6eg", - Value: "2", + Outputs: []TxOutput{ + { + Address: "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", + Value: "3", + }, }, - }, - Outputs: []TxOutput{ - { - Address: "bc1q2fpry7zwqh575huc9urwfdvjtuvz508wez56ff", - Value: "3", + Fee: "125000", + Date: 1555117625, + Block: 592400, + Status: StatusCompleted, + Memo: "test", + } + + utxoTransferDst2 = Tx{ + ID: "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", + Coin: coin.BTC, + Inputs: []TxOutput{ + { + Address: "bc1q6e8sdxlgc7ekqkqyevtrx8wshfv7sg66z3z6ce", + Value: "4", + }, + { + Address: "bc1q7nn4txus4g6fc5v7d2tha35ely8mfpd8qvv6eg", + Value: "2", + }, }, - { - Address: "bc1qk3yj6h79qw7tnsg4durc9sd5fpd3qt0p0m8u5p", - Value: "1", + Outputs: []TxOutput{ + { + Address: "bc1q2fpry7zwqh575huc9urwfdvjtuvz508wez56ff", + Value: "3", + }, + { + Address: "bc1qk3yj6h79qw7tnsg4durc9sd5fpd3qt0p0m8u5p", + Value: "1", + }, + { + Address: "bc1qm8836plkzft2rhh23z6j8s9s8fxrzd4zag95z8", + Value: "2", + }, }, - { - Address: "bc1qm8836plkzft2rhh23z6j8s9s8fxrzd4zag95z8", - Value: "2", - }, - }, - Fee: "125000", - Date: 1555117625, - Block: 592400, - Status: StatusCompleted, - Memo: "test", -} + Fee: "125000", + Date: 1555117625, + Block: 592400, + Status: StatusCompleted, + Memo: "test", + } +) func TestTx_GetAddresses(t *testing.T) { assert.Equal(t, transferDst1.GetAddresses(), []string{"tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5"}) @@ -119,8 +122,19 @@ func TestTx_GetAddresses(t *testing.T) { } func TestTx_GetUtxoAddresses(t *testing.T) { - assert.Equal(t, utxoTransferDst1.GetUtxoAddresses(), []string{"bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh", "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737", "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6"}) - assert.Equal(t, utxoTransferDst2.GetUtxoAddresses(), []string{"bc1q6e8sdxlgc7ekqkqyevtrx8wshfv7sg66z3z6ce", "bc1q7nn4txus4g6fc5v7d2tha35ely8mfpd8qvv6eg", "bc1q2fpry7zwqh575huc9urwfdvjtuvz508wez56ff", "bc1qk3yj6h79qw7tnsg4durc9sd5fpd3qt0p0m8u5p", "bc1qm8836plkzft2rhh23z6j8s9s8fxrzd4zag95z8"}) + assert.Equal(t, utxoTransferDst1.GetUtxoAddresses(), []string{ + "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", + "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh", + "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737", + "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", + }) + assert.Equal(t, utxoTransferDst2.GetUtxoAddresses(), []string{ + "bc1q6e8sdxlgc7ekqkqyevtrx8wshfv7sg66z3z6ce", + "bc1q7nn4txus4g6fc5v7d2tha35ely8mfpd8qvv6eg", + "bc1q2fpry7zwqh575huc9urwfdvjtuvz508wez56ff", + "bc1qk3yj6h79qw7tnsg4durc9sd5fpd3qt0p0m8u5p", + "bc1qm8836plkzft2rhh23z6j8s9s8fxrzd4zag95z8", + }) } func Test_getDirection(t *testing.T) { @@ -332,20 +346,29 @@ func Test_inferUtxoValue(t *testing.T) { // zpub: zpub6r9CEhEkruYbEcu2yQCaRKQ1qufTa4zLrx6ezs31P627UpAepVNBE2td3d3mHnSaXyRbwksRwDJGzLBWQeZPFMut8N3BvXpcwRwEWGEwAnq var ( - btcSet = mapset.NewSet("bc1qfrrncxmf7skye2glyef95xlpmrlmf2e8qlav2l", "bc1qxm90n0rxkadhdkvglev56k60qths73luzlnn7a", - "bc1q2sykr9c342mjpm9mwnps8ksk6e35lz75rpdlfe", "bc1qs86ucvr3unce2grvfp77433npy66nzha9w0e3c") + btcSet = mapset.NewSet( + "bc1qfrrncxmf7skye2glyef95xlpmrlmf2e8qlav2l", + "bc1qxm90n0rxkadhdkvglev56k60qths73luzlnn7a", + "bc1q2sykr9c342mjpm9mwnps8ksk6e35lz75rpdlfe", + "bc1qs86ucvr3unce2grvfp77433npy66nzha9w0e3c", + ) + btcInputs1 = []TxOutput{{Address: "bc1q2sykr9c342mjpm9mwnps8ksk6e35lz75rpdlfe"}} btcOutputs1 = []TxOutput{{Address: "bc1q6wf7tj62f0uwr6almah3666th2ejefdg72ek6t"}} - btcInputs2 = []TxOutput{{ + + btcInputs2 = []TxOutput{{ Address: "3CgvDkzcJ7yMZe75jNBem6Bj6nkMAWwMEf"}, {Address: "3LyzYcB54pm9EAMmzXpFfb1kzEDAFvqBgT"}, {Address: "3Q6DYour5q5WdMhyXsyPgBeAqPCXchzCsF"}, - {Address: "3JZZM1rwst7G5izxbFL7KNvy7ZiZ47SVqG"}} + {Address: "3JZZM1rwst7G5izxbFL7KNvy7ZiZ47SVqG"}, + } + btcOutputs2 = []TxOutput{ {Address: "139f1CrnLWvVajGzs3ZtpQhbGWxM599sho"}, {Address: "3LyzYcB54pm9EAMmzXpFfb1kzEDAFvqBgT"}, {Address: "bc1q9mx5tm66zs7epa4skvyuf2vfuwmtnlttj74cnl"}, - {Address: "3JZZM1rwst7G5izxbFL7KNvy7ZiZ47SVqG"}} + {Address: "3JZZM1rwst7G5izxbFL7KNvy7ZiZ47SVqG"}, + } dogeSet = mapset.NewSet("DB49sNjVdxyREXEBEzUV54TrQYYpvi3Be7") dogeInputs = []TxOutput{{Address: "DAukM5pPtGdbPxMX1u2LYHoyhbDhEFHbnH"}} @@ -632,10 +655,8 @@ func TestTokenType(t *testing.T) { } var ( - beforeTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` - //beforeTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"trust.com","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` - wantedTransactionsToken = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103643577","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` - //wantedTransactionsMemo = `[{"id":"59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592484005,"block":95113723,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089263465","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592442063,"block":95008674,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592429461,"block":94977026,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2511060524","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592348463,"block":94777896,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"10998400000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592253063,"block":94538295,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4146300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592250904,"block":94532906,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"63266290000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592246708,"block":94522375,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"104150629","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"4512670728","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592245803,"block":94520016,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"58689300000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592244606,"block":94517032,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"108137171","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1053055990","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592237402,"block":94498680,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"8479394653","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592223002,"block":94462381,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"38451401547","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592220661,"block":94456416,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"99998300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592201404,"block":94407633,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103229158","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1089751117","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592194201,"block":94389286,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"1098704296","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592179801,"block":94352682,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2461605848","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592177461,"block":94346701,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2324800000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592165402,"block":94316303,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"156671627595","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592163611,"block":94311779,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"106835633","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2042060818","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592158202,"block":94298059,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"3101371","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592154601,"block":94288998,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103268674","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"367696585025","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592073191,"block":94084342,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2503750000","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1592066528,"block":94067506,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"outgoing","memo":"103335769","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"12959997250","from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23"}},{"id":"FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2","coin":714,"from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060464,"block":94052345,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"2781326500","from":"bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E","coin":714,"from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592060463,"block":94052341,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"39644614000","from":"bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}},{"id":"19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","fee":"37500","date":1592053265,"block":94034212,"status":"completed","sequence":0,"type":"native_token_transfer","direction":"incoming","memo":"","metadata":{"name":"","symbol":"BUSD","token_id":"BUSD-BD1","decimals":8,"value":"40798300000","from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp"}}]` + beforeTransactionsToken, _ = mock.JsonFromFilePathToString("mocks/bnb_token_txs.json") + wantedTransactionsToken, _ = mock.JsonFromFilePathToString("mocks/bnb_token_response.json") ) func Test_filterTransactionsByToken(t *testing.T) { @@ -644,7 +665,7 @@ func Test_filterTransactionsByToken(t *testing.T) { result := p.FilterTransactionsByToken("BUSD-BD1") rawResult, err := json.Marshal(result) assert.Nil(t, err) - assert.Equal(t, wantedTransactionsToken, string(rawResult)) + assert.JSONEq(t, wantedTransactionsToken, string(rawResult)) } func Test_AllowMemo(t *testing.T) { diff --git a/platform/aeternity/mocks/transfer.json b/platform/aeternity/mocks/transfer.json new file mode 100644 index 000000000..f060dfe8f --- /dev/null +++ b/platform/aeternity/mocks/transfer.json @@ -0,0 +1,19 @@ +{ + "block_hash": "mh_sJqfsWuuhA7vXDJLYFVtpagCSTmfmhzdqKWFR4pU5LK4D8W8T", + "block_height": 113579, + "hash": "th_oJfBC6KZKaKsL4WXTq1ZtFiSE8Wp2PQYEnwyZqtudyHcU3Qg6", + "signatures": [ + "sg_F3Ecfu5g6FcPyHrgZue96hVHthnXW7CbuDUEoKwWqWvbE84xb3ifB57AGTaH1WzDr4x1cnv4biLqTorjq9ZqhzCFVJC5c" + ], + "time": 1563848658206, + "tx": { + "amount": 252550000000000000000, + "fee": 20500000000000, + "nonce": 251291, + "payload": "ba_SGVsbG8sIE1pbmVyISAvWW91cnMgQmVlcG9vbC4vKXcQag==", + "recipient_id": "ak_ZWrS6xGhzxBasKmMbVSACfRioWqPyM5jNqMpBQ5ngP75RS6pS", + "sender_id": "ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv", + "type": "SpendTx", + "version": 1 + } +} diff --git a/platform/aeternity/transaction_test.go b/platform/aeternity/transaction_test.go index 4b4a6f153..0b9af941c 100644 --- a/platform/aeternity/transaction_test.go +++ b/platform/aeternity/transaction_test.go @@ -1,92 +1,64 @@ package aeternity import ( - "encoding/json" + "reflect" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" + "github.com/trustwallet/golibs/mock" ) -const transferTransaction = ` -{ - "block_hash": "mh_sJqfsWuuhA7vXDJLYFVtpagCSTmfmhzdqKWFR4pU5LK4D8W8T", - "block_height": 113579, - "hash": "th_oJfBC6KZKaKsL4WXTq1ZtFiSE8Wp2PQYEnwyZqtudyHcU3Qg6", - "signatures": [ - "sg_F3Ecfu5g6FcPyHrgZue96hVHthnXW7CbuDUEoKwWqWvbE84xb3ifB57AGTaH1WzDr4x1cnv4biLqTorjq9ZqhzCFVJC5c" - ], - "time": 1563848658206, - "tx": { - "amount": 252550000000000000000, - "fee": 20500000000000, - "nonce": 251291, - "payload": "ba_SGVsbG8sIE1pbmVyISAvWW91cnMgQmVlcG9vbC4vKXcQag==", - "recipient_id": "ak_ZWrS6xGhzxBasKmMbVSACfRioWqPyM5jNqMpBQ5ngP75RS6pS", - "sender_id": "ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv", - "type": "SpendTx", - "version": 1 - } - } -` - -var transferDst = blockatlas.Tx{ - ID: "th_oJfBC6KZKaKsL4WXTq1ZtFiSE8Wp2PQYEnwyZqtudyHcU3Qg6", - Coin: coin.AE, - From: "ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv", - To: "ak_ZWrS6xGhzxBasKmMbVSACfRioWqPyM5jNqMpBQ5ngP75RS6pS", - Fee: "20500000000000", - Date: 1563848658, - Block: 113579, - Status: blockatlas.StatusCompleted, - Memo: "Hello, Miner! /Yours Beepool./", - Sequence: 251291, - Meta: blockatlas.Transfer{ - Value: "252550000000000000000", - Symbol: "AE", - Decimals: 18, - }, -} - -type test struct { - name string - apiResponse string - expected *blockatlas.Tx - token string -} - -func testNormalize(t *testing.T, _test *test) { - var srcTx Transaction - err := json.Unmarshal([]byte(_test.apiResponse), &srcTx) - if err != nil { - t.Error(err) - return +func TestNormalizeTx(t *testing.T) { + type args struct { + filename string } - - tx, err := NormalizeTx(&srcTx) - assert.Nil(t, err) - - resJSON, err := json.Marshal(&tx) - if err != nil { - t.Fatal(err) + tests := []struct { + name string + args args + wantTx blockatlas.Tx + wantErr bool + }{ + { + name: "Test normalize transaction", + args: args{ + filename: "transfer.json", + }, + wantTx: blockatlas.Tx{ + ID: "th_oJfBC6KZKaKsL4WXTq1ZtFiSE8Wp2PQYEnwyZqtudyHcU3Qg6", + Coin: coin.AE, + From: "ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv", + To: "ak_ZWrS6xGhzxBasKmMbVSACfRioWqPyM5jNqMpBQ5ngP75RS6pS", + Fee: "20500000000000", + Date: 1563848658, + Block: 113579, + Status: blockatlas.StatusCompleted, + Memo: "Hello, Miner! /Yours Beepool./", + Sequence: 251291, + Meta: blockatlas.Transfer{ + Value: "252550000000000000000", + Symbol: "AE", + Decimals: 18, + }, + }, + wantErr: false, + }, } - - dstJSON, err := json.Marshal(_test.expected) - if err != nil { - println(string(resJSON)) - println(string(dstJSON)) - t.Fatal(err) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx Transaction + _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + gotTx, err := NormalizeTx(&srcTx) + if (err != nil) != tt.wantErr { + t.Errorf("NormalizeTx() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotTx, tt.wantTx) { + t.Errorf("NormalizeTx() gotTx = %v, want %v", gotTx, tt.wantTx) + } + }) } - assert.Equal(t, resJSON, dstJSON) -} - -func TestNormalize(t *testing.T) { - testNormalize(t, &test{ - name: "transfer", - apiResponse: transferTransaction, - expected: &transferDst, - token: "", - }) } func TestPayloadEncoding(t *testing.T) { diff --git a/platform/aion/mocks/transfer.json b/platform/aion/mocks/transfer.json new file mode 100644 index 000000000..dc300b603 --- /dev/null +++ b/platform/aion/mocks/transfer.json @@ -0,0 +1,21 @@ +{ + "blockHash": "68364cfa1873c42f3c2ef659349ca101c4c691a0385fd1c1677f92a96f7332ca", + "nrgPrice": 10000000000, + "toAddr": "a09b8c4c40bd7a81e969b8f6f291074206196a99948b03c6a469892931a3c258", + "contractAddr": "", + "data": "", + "year": 2019, + "transactionIndex": 7, + "nonce": "170c", + "transactionHash": "af3c2f5087fc3332154dc9d11c27e312f30ff829dbc5436aec8cc4342c7dc384", + "transactionTimestamp": 1554862205533375, + "nrgConsumed": 21000, + "month": 4, + "blockNumber": 2880919, + "blockTimestamp": 1554862228, + "transactionLog": "[]", + "fromAddr": "a07981da70ce919e1db5f051c3c386eb526e6ce8b9e2bfd56e3f3d754b0a17f3", + "day": 10, + "value": 11.903810405853733, + "txError": "" +} diff --git a/platform/aion/transaction.go b/platform/aion/transaction.go index c2675365a..404b38c1d 100644 --- a/platform/aion/transaction.go +++ b/platform/aion/transaction.go @@ -26,13 +26,14 @@ func NormalizeTx(srcTx *Tx) (tx blockatlas.Tx, ok bool) { } return blockatlas.Tx{ - ID: "0x" + srcTx.TransactionHash, - Coin: coin.AION, - Date: srcTx.BlockTimestamp, - From: "0x" + srcTx.FromAddr, - To: "0x" + srcTx.ToAddr, - Fee: blockatlas.Amount(fee), - Block: srcTx.BlockNumber, + ID: "0x" + srcTx.TransactionHash, + Coin: coin.AION, + Date: srcTx.BlockTimestamp, + From: "0x" + srcTx.FromAddr, + To: "0x" + srcTx.ToAddr, + Fee: blockatlas.Amount(fee), + Block: srcTx.BlockNumber, + Status: blockatlas.StatusCompleted, Meta: blockatlas.Transfer{ Value: blockatlas.Amount(value), Symbol: coin.Coins[coin.AION].Symbol, diff --git a/platform/aion/transaction_test.go b/platform/aion/transaction_test.go index 43e09bafa..e33b93af9 100644 --- a/platform/aion/transaction_test.go +++ b/platform/aion/transaction_test.go @@ -1,78 +1,58 @@ package aion import ( - "bytes" - "encoding/json" + "reflect" + "testing" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" + "github.com/trustwallet/golibs/mock" ) -const transferSrc = ` -{ - "blockHash": "68364cfa1873c42f3c2ef659349ca101c4c691a0385fd1c1677f92a96f7332ca", - "nrgPrice": 10000000000, - "toAddr": "a09b8c4c40bd7a81e969b8f6f291074206196a99948b03c6a469892931a3c258", - "contractAddr": "", - "data": "", - "year": 2019, - "transactionIndex": 7, - "nonce": "170c", - "transactionHash": "af3c2f5087fc3332154dc9d11c27e312f30ff829dbc5436aec8cc4342c7dc384", - "transactionTimestamp": 1554862205533375, - "nrgConsumed": 21000, - "month": 4, - "blockNumber": 2880919, - "blockTimestamp": 1554862228, - "transactionLog": "[]", - "fromAddr": "a07981da70ce919e1db5f051c3c386eb526e6ce8b9e2bfd56e3f3d754b0a17f3", - "day": 10, - "value": 11.903810405853733, - "txError": "" -}` - -var transferDst = blockatlas.Tx{ - ID: "0xaf3c2f5087fc3332154dc9d11c27e312f30ff829dbc5436aec8cc4342c7dc384", - Coin: coin.AION, - From: "0xa07981da70ce919e1db5f051c3c386eb526e6ce8b9e2bfd56e3f3d754b0a17f3", - To: "0xa09b8c4c40bd7a81e969b8f6f291074206196a99948b03c6a469892931a3c258", - Fee: "21000", - Date: 1554862228, - Block: 2880919, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: "11903810405853733000", - Symbol: "AION", - Decimals: 18, - }, -} - -func TestNormalize(t *testing.T) { - var srcTx Tx - err := json.Unmarshal([]byte(transferSrc), &srcTx) - if err != nil { - t.Error(err) - return +func TestNormalizeTx(t *testing.T) { + type args struct { + srcTx string } - - resTx, ok := NormalizeTx(&srcTx) - if !ok { - t.Fatal("Can't normalize transaction") - } - - resJSON, err := json.Marshal(&resTx) - if err != nil { - t.Fatal(err) + tests := []struct { + name string + args args + wantTx blockatlas.Tx + wantOk bool + }{ + { + name: "Test normalize transfer", + args: args{ + srcTx: "transfer.json", + }, + wantTx: blockatlas.Tx{ + ID: "0xaf3c2f5087fc3332154dc9d11c27e312f30ff829dbc5436aec8cc4342c7dc384", + Coin: coin.AION, + From: "0xa07981da70ce919e1db5f051c3c386eb526e6ce8b9e2bfd56e3f3d754b0a17f3", + To: "0xa09b8c4c40bd7a81e969b8f6f291074206196a99948b03c6a469892931a3c258", + Fee: "21000", + Date: 1554862228, + Block: 2880919, + Status: blockatlas.StatusCompleted, + Meta: blockatlas.Transfer{ + Value: "11903810405853733000", + Symbol: "AION", + Decimals: 18, + }, + }, + wantOk: true, + }, } - - dstJSON, err := json.Marshal(&transferDst) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error("tx don't equal") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx Tx + _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.srcTx, &srcTx) + gotTx, gotOk := NormalizeTx(&srcTx) + if !reflect.DeepEqual(gotTx, tt.wantTx) { + t.Errorf("NormalizeTx() gotTx = %v, want %v", gotTx, tt.wantTx) + } + if gotOk != tt.wantOk { + t.Errorf("NormalizeTx() gotOk = %v, want %v", gotOk, tt.wantOk) + } + }) } } diff --git a/platform/algorand/mocks/transfer.json b/platform/algorand/mocks/transfer.json new file mode 100644 index 000000000..09fd0dda7 --- /dev/null +++ b/platform/algorand/mocks/transfer.json @@ -0,0 +1,30 @@ +{ + "transactions": [ + { + "close-rewards": 0, + "closing-amount": 0, + "confirmed-round": 2031351, + "fee": 1000, + "first-valid": 2031300, + "genesis-hash": "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=", + "genesis-id": "mainnet-v1.0", + "id": "C2LK3CGBPIGERLPFUXE6INSBJGHOXU7YZMEGELWMVSBASFJYOOQQ", + "intra-round-offset": 57, + "last-valid": 2031749, + "note": "6OZ0TFd0HPw=", + "payment-transaction": { + "amount": 1, + "close-amount": 0, + "receiver": "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U" + }, + "receiver-rewards": 3237690, + "round-time": 1569123058, + "sender": "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", + "sender-rewards": 0, + "signature": { + "sig": "J1G/vapWXJJjuFcsUPut9ffHrFnXsg1GRQlLyqhTOC0V78zCw3OIAYgeg6k/xiX5NDLLrgy4aYF1hhsEXGZ2Dg==" + }, + "tx-type": "pay" + } + ] +} diff --git a/platform/algorand/transaction_test.go b/platform/algorand/transaction_test.go index d466185f5..a945fb2a2 100644 --- a/platform/algorand/transaction_test.go +++ b/platform/algorand/transaction_test.go @@ -1,78 +1,60 @@ package algorand import ( - "encoding/json" + "reflect" "testing" - "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" ) -const ( - transfer = ` -{ - "transactions":[ - { - "close-rewards":0, - "closing-amount":0, - "confirmed-round":2031351, - "fee":1000, - "first-valid":2031300, - "genesis-hash":"wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=", - "genesis-id":"mainnet-v1.0", - "id":"C2LK3CGBPIGERLPFUXE6INSBJGHOXU7YZMEGELWMVSBASFJYOOQQ", - "intra-round-offset":57, - "last-valid":2031749, - "note":"6OZ0TFd0HPw=", - "payment-transaction":{ - "amount":1, - "close-amount":0, - "receiver":"4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U" - }, - "receiver-rewards":3237690, - "round-time":1569123058, - "sender":"5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", - "sender-rewards":0, - "signature":{ - "sig":"J1G/vapWXJJjuFcsUPut9ffHrFnXsg1GRQlLyqhTOC0V78zCw3OIAYgeg6k/xiX5NDLLrgy4aYF1hhsEXGZ2Dg==" - }, - "tx-type":"pay" - } - ] -} -` -) - -var expected = []*blockatlas.Tx{ - { - ID: "C2LK3CGBPIGERLPFUXE6INSBJGHOXU7YZMEGELWMVSBASFJYOOQQ", - Coin: coin.ALGO, - From: "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", - To: "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", - Fee: blockatlas.Amount("1000"), - Date: 1569123058, - Block: 2031351, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1"), - Symbol: "ALGO", - Decimals: 6, +func TestNormalizeTx(t *testing.T) { + type args struct { + filename string + } + tests := []struct { + name string + args args + wantTx blockatlas.Tx + ok bool + }{ + { + name: "Test normalize transaction", + args: args{ + filename: "transfer.json", + }, + wantTx: blockatlas.Tx{ + ID: "C2LK3CGBPIGERLPFUXE6INSBJGHOXU7YZMEGELWMVSBASFJYOOQQ", + Coin: coin.ALGO, + From: "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", + To: "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", + Fee: blockatlas.Amount("1000"), + Date: 1569123058, + Block: 2031351, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxTransfer, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("1"), + Symbol: "ALGO", + Decimals: 6, + }, + }, + ok: true, }, - }, - nil, - nil, -} - -func TestNormalize(t *testing.T) { - var act TransactionsResponse - assert.NoError(t, json.Unmarshal([]byte(transfer), &act)) - assert.Equal(t, 1, len(act.Transactions)) - - for i, v := range act.Transactions { - tx, ok := Normalize(v) - assert.True(t, ok) - assert.Equal(t, expected[i], &tx) + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var response TransactionsResponse + _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &response) + gotTx, ok := Normalize(response.Transactions[0]) + if ok != tt.ok { + t.Errorf("Normalize() ok = %v, wantOk %v", ok, tt.ok) + return + } + if !reflect.DeepEqual(gotTx, tt.wantTx) { + t.Errorf("Normalize() gotTx = %v, want %v", gotTx, tt.wantTx) + } + }) } } diff --git a/platform/binance/base_test.go b/platform/binance/base_test.go index 9d633904b..e166b5c10 100644 --- a/platform/binance/base_test.go +++ b/platform/binance/base_test.go @@ -3,23 +3,22 @@ package binance import ( "fmt" "net/http" + + "github.com/trustwallet/golibs/mock" ) -const ( - //wantedBlock = `{"number":104867508,"txs":[{"id":"4CD5BAA433BABA63D862141A4A2F9235B0BA5CBAB8114C93A0556ECA4EC7A68A","coin":714,"from":"bnb1l83kstts7lt9dpgawzechnrgjq54dql36dyspc","to":"","fee":"0","date":1596472337,"block":104867508,"status":"completed","sequence":1023322,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Cancel Order","key":"cancel_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"0"}},{"id":"9B87D17581F2AC73D2999EDE56535E50D9D4DB75150A92A90122190F77D47755","coin":714,"from":"bnb1c4czpzvn0ttdcpnv3cy2858l2m9frxdfgk4jr0","to":"bnb1g2ukzn702napq3levm54m2z3p2gam7upern9aq","fee":"37500","date":1596472337,"block":104867508,"status":"completed","sequence":6,"type":"transfer","memo":"","metadata":{"value":"24481570","symbol":"BNB","decimals":8}},{"id":"5C0580AC983C1CF36F1656D9E8B062CD0578839BEFC839EFD6720FF315B45EEB","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596472337,"block":104867508,"status":"completed","sequence":1509154,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"10500000000"}}]}` - wantedBlockNoOrders = `{"number":104867508,"txs":[{"id":"9B87D17581F2AC73D2999EDE56535E50D9D4DB75150A92A90122190F77D47755","coin":714,"from":"bnb1c4czpzvn0ttdcpnv3cy2858l2m9frxdfgk4jr0","to":"bnb1g2ukzn702napq3levm54m2z3p2gam7upern9aq","fee":"37500","date":1596472337,"block":104867508,"status":"completed","sequence":6,"type":"transfer","memo":"","metadata":{"value":"24481570","symbol":"BNB","decimals":8}}]}` - wantedTxs = `[{"id":"771B07C8D921B5995524C163E9D4504C31A9E07EC858263A53EA007484009C90","coin":714,"from":"bnb1d83u9afqw296ejw9jdfhc22f0ljr23nn7pradx","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826106,"block":105722032,"status":"completed","sequence":33,"type":"transfer","memo":"106890151","metadata":{"value":"120740436","symbol":"BNB","decimals":8}},{"id":"1C5682716D2D34DD01428AD8D4200081FBDA06CE886B77499F755E9D93B0FF20","coin":714,"from":"bnb1k9ktd79psysucucyxqcd5r9ahuuygk8gh3ly8q","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826069,"block":105721942,"status":"completed","sequence":64,"type":"transfer","memo":"103215089","metadata":{"value":"229350524","symbol":"BNB","decimals":8}},{"id":"C728F7C13977649FCDF9B8E983A9E3AA257EB5596DBCA2A2580584312B5AA535","coin":714,"from":"bnb155svs6sgxe55rnvs6ghprtqu0mh69kehphsppd","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826063,"block":105721925,"status":"completed","sequence":23121,"type":"transfer","memo":"101045880","metadata":{"value":"11964120000","symbol":"BNB","decimals":8}},{"id":"794302F9C6562358581A3A8432AF82CD70DF0DA345C917BDE21DDF9A9D4B9DE7","coin":714,"from":"bnb14gk6m77tswyks9nnadm92mdy3066wj42t60z0l","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826058,"block":105721913,"status":"completed","sequence":11228,"type":"transfer","memo":"100341541","metadata":{"value":"456000000","symbol":"BNB","decimals":8}},{"id":"2827377A04E3B22DD654A02AD4BA50B3CB83973B6B9BA1A423ABD5045873850C","coin":714,"from":"bnb132gvg9gdthtaf6xgkk9jkmsep56fv62vg95unv","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826024,"block":105721828,"status":"completed","sequence":4,"type":"transfer","memo":"105772095","metadata":{"value":"1045498916","symbol":"BNB","decimals":8}},{"id":"AACC80FDA9C45DCD7F6DBAA40A2EB600FF6EBB24A5A840578D4AB306C3427385","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596826006,"block":105721785,"status":"completed","sequence":65,"type":"transfer","memo":"109027392","metadata":{"value":"8750000000","symbol":"BNB","decimals":8}},{"id":"66CF0F65442FD35A3B91CC2655CE60E565D13EEFC6BDB1C5AF9F9E484C8B6295","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825967,"block":105721686,"status":"completed","sequence":896,"type":"transfer","memo":"107780643","metadata":{"value":"878900000","symbol":"BNB","decimals":8}},{"id":"81EA185BE754809E40FCBF1B07A0C389F39DECD38D56302D980534850996B144","coin":714,"from":"bnb12nq7fhh3t8q0m9s2n5gqwd9gcx0j85yn0h5zcu","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825888,"block":105721490,"status":"completed","sequence":0,"type":"transfer","memo":"101210049","metadata":{"value":"4498159221","symbol":"BNB","decimals":8}},{"id":"24ED2153427ABACD7F6DB53A1339D9C2573D720FDE6EC45B0047CB146227FF9A","coin":714,"from":"bnb1s5qucugaxv7gkzyg4kacf225s6mhj0ysejn8jq","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825847,"block":105721385,"status":"completed","sequence":40,"type":"transfer","memo":"104298046","metadata":{"value":"34300000000","symbol":"BNB","decimals":8}},{"id":"411A27CE85D0928BC5908DA5BA288CB52E152C1E54FA35042147A90FCEBAB29C","coin":714,"from":"bnb1erj09eqrnz06jv2acxhhy7s3k0q6w4hfmj9rey","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825789,"block":105721238,"status":"completed","sequence":12,"type":"transfer","memo":"107303874","metadata":{"value":"6319074","symbol":"BNB","decimals":8}},{"id":"25359F7277760004BBD42557B3E50F86F06B096478840E057C6F394BF63F6081","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825692,"block":105720997,"status":"completed","sequence":57,"type":"transfer","memo":"109027392","metadata":{"value":"1090000000","symbol":"BNB","decimals":8}},{"id":"1DB710AF4983D9CAFB24AC3DD7C2C6EBC7752F347E5A7599840AB3EFBD436C5D","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825639,"block":105720867,"status":"completed","sequence":56,"type":"transfer","memo":"109027392","metadata":{"value":"2000000000","symbol":"BNB","decimals":8}},{"id":"B7C799B9853ECA41F02241B67E294E2642AE88BBF551DE188A73C48D1A0E821D","coin":714,"from":"bnb1q2994t0djzsy0q2fc62jruxr22nxq6y8l4503l","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825619,"block":105720816,"status":"completed","sequence":1,"type":"transfer","memo":"108202494","metadata":{"value":"295957149","symbol":"BNB","decimals":8}},{"id":"865C098D021CC649FC83B2442092E4D6F0777488163E5797DA9D264C87F1F4F4","coin":714,"from":"bnb16xqcchlutsm8g6gk7wvlzukeu2sy9xt2u77056","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825548,"block":105720641,"status":"completed","sequence":33,"type":"transfer","memo":"102080722","metadata":{"value":"1373501799","symbol":"BNB","decimals":8}},{"id":"1D4F777D1D227D57E4D4BAC3E83FB203147E7B0E7429E60A48A9053372359174","coin":714,"from":"bnb1t6tk66zncqqt7twnfyxx22fn9t3wz3nac5hkck","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825500,"block":105720519,"status":"completed","sequence":14,"type":"transfer","memo":"106456805","metadata":{"value":"1490609","symbol":"BNB","decimals":8}},{"id":"9A818687D52B4E9E0C5F962E6E464ECC6348D6A41AE2C5DD051A5EF71E15B1AC","coin":714,"from":"bnb1v47qw5acc72c34uwt7t9wm9ztqtg6678dmrssa","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825415,"block":105720307,"status":"completed","sequence":6273,"type":"transfer","memo":"104471384","metadata":{"value":"356700000","symbol":"BNB","decimals":8}},{"id":"6C7D4469525E44501ED03BA38A6D54A04DFD6AD2D13328761DA4602A3D777332","coin":714,"from":"bnb1tzet704pc6zjsl3xcwdexn6xlu0zc092y0n4ay","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825348,"block":105720136,"status":"completed","sequence":721,"type":"transfer","memo":"101245732","metadata":{"value":"93900000","symbol":"BNB","decimals":8}},{"id":"8C47875F09371B45C0A29D7C6EF308A1C499D1BBECD5A56E0561B40675AF2D26","coin":714,"from":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825311,"block":105720042,"status":"completed","sequence":1912,"type":"transfer","memo":"101186586","metadata":{"value":"95193451","symbol":"BNB","decimals":8}},{"id":"39A48766F8ACC33B3BB1B4F442ABFDFBC695F440D72795794A01E8E446CE8EAE","coin":714,"from":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825298,"block":105720010,"status":"completed","sequence":47,"type":"transfer","memo":"109027392","metadata":{"value":"480000000","symbol":"BNB","decimals":8}},{"id":"54248E3C09713E3870F661749A8690DAD46A8078C7346C497EB4E166564420F4","coin":714,"from":"bnb1hc304lytvp9jnumnjmppq97erm70r7muzv6y98","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825237,"block":105719860,"status":"completed","sequence":1,"type":"transfer","memo":"105261446","metadata":{"value":"10210962500","symbol":"BNB","decimals":8}},{"id":"ADDDB705AB8C2B1AF58D7EDCAEC00C893A6CD87281D7A7146689E9FE1A846EAE","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825173,"block":105719705,"status":"completed","sequence":895,"type":"transfer","memo":"103617121","metadata":{"value":"297900000","symbol":"BNB","decimals":8}},{"id":"7C338C78BBBCD998628CCAF85211883AACB159201755501139F56E0D2A7941A4","coin":714,"from":"bnb1pys084nlc8gqm7lvjje4kt39dn84vd2xsvnwqa","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825147,"block":105719641,"status":"completed","sequence":18,"type":"transfer","memo":"108802310","metadata":{"value":"200000000","symbol":"BNB","decimals":8}},{"id":"6DD7120E43CD5031E2DD6C7977D141B74CA41C8E476D8AE972A9DA2D2EFD2D84","coin":714,"from":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825061,"block":105719428,"status":"completed","sequence":894,"type":"transfer","memo":"102393444","metadata":{"value":"677900000","symbol":"BNB","decimals":8}},{"id":"86FB14C637D7B0A4AA123FFF76C5C541C70568B67E3F5BC63EB0FDEDEF30301F","coin":714,"from":"bnb17nak8gnucl6lcze0d04def4de77a33qh29f6ur","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825051,"block":105719403,"status":"completed","sequence":3,"type":"transfer","memo":"109823910","metadata":{"value":"900000","symbol":"BNB","decimals":8}},{"id":"1DEEFC0A838F80704574951DF15969CCE34654BE2007BF77F9521A1B4686BE33","coin":714,"from":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"37500","date":1596825014,"block":105719312,"status":"completed","sequence":1431,"type":"transfer","memo":"103268674","metadata":{"value":"315739000","symbol":"BNB","decimals":8}}]` - wantedTokens = `[{"name":"Travala.com Token","symbol":"AVA","decimals":8,"token_id":"AVA-645","coin":714,"type":"BEP2"},{"name":"Binance Chain Native Token","symbol":"BNB","decimals":8,"token_id":"BNB","coin":714,"type":"BEP2"},{"name":"Binance USD","symbol":"BUSD","decimals":8,"token_id":"BUSD-BD1","coin":714,"type":"BEP2"}]` - //wantedTxsAva = `[{"id":"2BF49DF1D10D9A20438376E760352734DAEBD5D92D6CAA14735EE095A3F65FD3","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827621,"block":105725696,"status":"completed","sequence":1594673,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"2700000000"}},{"id":"C858D15E2745A61D0D3D354750E4462792160FFBB9927739587FFAAEDEFA00FF","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827612,"block":105725676,"status":"completed","sequence":1594670,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"13100000000"}},{"id":"9BDCF416622AA4E8F11162747614585FD840F5721D7163A68BC03EC94E855DEE","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827611,"block":105725673,"status":"completed","sequence":1594669,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1700000000"}},{"id":"52512D9498D4CF51997A5A62C0A55252776B00C888D2D01502C68B56E892F42E","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827603,"block":105725652,"status":"completed","sequence":1594666,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"2200000000"}},{"id":"1BAF96AB01E7AB5A7746CA7E76B293CD636D55713C7CCE71FD0E0ED8ACE05C92","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827600,"block":105725646,"status":"completed","sequence":1594665,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"9990419EFE1B327966EBAAFFC2771046E1AC2E4DDFAD8A93C55DE105A2948A8D","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827591,"block":105725624,"status":"completed","sequence":1594662,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"10800000000"}},{"id":"922F86E110E897233A7B43C0D31397923298C176EBE6F33D98B70ACB911A497A","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827589,"block":105725620,"status":"completed","sequence":1594661,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1800000000"}},{"id":"925A208AFDCD718F8383F7559C7BBA5AE616B693A6029F57BFB67AEBB1CE5F3C","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827580,"block":105725597,"status":"completed","sequence":1594658,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"8200000000"}},{"id":"2B69327D6C0C7B9061AAD962BF4838E3B630A844439013E0EBEFC5B722205774","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827571,"block":105725575,"status":"completed","sequence":1594655,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"BB6FD86C9738C2991F587996ABBAC1151DF1F9DE57FDCC977BB0D8FBAD31188A","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827552,"block":105725529,"status":"completed","sequence":1594653,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"2500000000"}},{"id":"97856635BDBA4B0B3EAAA76EA46D848A2DFE3AAE554A33D308CFC4474C769290","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827550,"block":105725526,"status":"completed","sequence":1594652,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"5500000000"}},{"id":"4B4EC65A5972CC15C4B410339ED0081C4BB57F4E08F2A35744845F5A71531B59","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827537,"block":105725493,"status":"completed","sequence":1594648,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1700000000"}},{"id":"86B5FFDDB06E0973A05434DDB858868A45EDA8B07E0D75125FEAEBA1093D4EA5","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827535,"block":105725489,"status":"completed","sequence":1594647,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"11800000000"}},{"id":"D20757EB130E8146D1A12E869BE69EC2CB03193D8E62467327B09A5D73BBC6F8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827529,"block":105725473,"status":"completed","sequence":1594645,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"3300000000"}},{"id":"04291A7AE08A78C5E5AE216C67D17B6A4260950FFAB6FD3D1C1B991E3B7BB935","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827527,"block":105725470,"status":"completed","sequence":1594644,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"14600000000"}},{"id":"31E16E3F53DD476475256C8D872AF3FD86DC44F3085EF87DDE3643E20C0CE624","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827518,"block":105725448,"status":"completed","sequence":1594641,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1800000000"}},{"id":"1D61A9E35893BB51DE4AE63FA6898FCAE14B6D48F7A2EFD0B51DCCACF6E36B88","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827517,"block":105725446,"status":"completed","sequence":1594640,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"13700000000"}},{"id":"AB9E29B110844BD76F58B058CC20F1E13B37A1AAC4F09978BDE159F1B09B585E","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827509,"block":105725425,"status":"completed","sequence":1594637,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1500000000"}},{"id":"F81649BAF3D888E3772C8708D255FE91E0CDB2818006A1FC96FFBDAC24BDE675","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827508,"block":105725422,"status":"completed","sequence":1594636,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"8700000000"}},{"id":"71B25BF61219BC87980EB67064C346801C01B00FFE52932799E28FB20DAF41D8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827499,"block":105725401,"status":"completed","sequence":1594633,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"1200000000"}},{"id":"3424BFCA860A878FDCF304AD414EDE2AB3B0FF258CA940CD1269F469ED7C422C","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827490,"block":105725379,"status":"completed","sequence":1594630,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"7600000000"}},{"id":"46FFA039B955953D4F19BE7D56FA793B71F34BFB460D9B84A152B554E9219C44","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827488,"block":105725375,"status":"completed","sequence":1594629,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"13900000000"}},{"id":"701100D3783744D633FF34A6E211CEB923EA9BCE6D87A64211801E71F71AEE03","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827469,"block":105725327,"status":"completed","sequence":1594627,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"4900000000"}},{"id":"B12B30509B45CEFE526DAADDAC6399F902B30418859042D7A23F9A2FB311A6C8","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827467,"block":105725323,"status":"completed","sequence":1594626,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"BUY","symbol":"AVA","decimals":8,"value":"2700000000"}},{"id":"933819F35F0F89FB2D58DC50CD15FABB3DA0B817BFCD39A8DDC99DFEC1663F7D","coin":714,"from":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","to":"","fee":"0","date":1596827458,"block":105725301,"status":"completed","sequence":1594623,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Place Order","key":"place_order","token_id":"AVA-645","name":"SELL","symbol":"AVA","decimals":8,"value":"9500000000"}}]` - //wantedBlockMulti = `{"number":105529271,"txs":[{"id":"432FF828B1DC1C4DAF13A51B6AE7ADD9932B7FC6526C28F7FE9C905F95472820","coin":714,"from":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","to":"","fee":"0","date":1596746326,"block":105529271,"status":"completed","sequence":11317170,"type":"any_action","direction":"outgoing","memo":"","metadata":{"coin":714,"title":"Cancel Order","key":"cancel_order","token_id":"","name":"","symbol":"","decimals":8,"value":"0"}},{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","to":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","fee":"60000","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"1","symbol":"BNB","decimals":8}},{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb1t38ccns9var4ac4yj2ylmu99r9ecmggr8ye5e5","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"0","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"39421249","symbol":"BNB","decimals":8}}]}` - wantedBlockMultiNoOrders = `{"number":105529271,"txs":[{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","to":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","fee":"60000","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"1","symbol":"BNB","decimals":8}},{"id":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","coin":714,"from":"bnb1t38ccns9var4ac4yj2ylmu99r9ecmggr8ye5e5","to":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","fee":"0","date":1596746326,"block":105529271,"status":"completed","sequence":2300,"type":"transfer","memo":"0","metadata":{"value":"39421249","symbol":"BNB","decimals":8}}]}` - wantedTxsResponse = `{"tx":[{"txHash":"771B07C8D921B5995524C163E9D4504C31A9E07EC858263A53EA007484009C90","blockHeight":105722032,"txType":"TRANSFER","timeStamp":"2020-08-07T18:48:26.284Z","fromAddr":"bnb1d83u9afqw296ejw9jdfhc22f0ljr23nn7pradx","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"1.20740436","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":104,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"106890151","source":1,"sequence":33},{"txHash":"1C5682716D2D34DD01428AD8D4200081FBDA06CE886B77499F755E9D93B0FF20","blockHeight":105721942,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:49.895Z","fromAddr":"bnb1k9ktd79psysucucyxqcd5r9ahuuygk8gh3ly8q","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.29350524","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":140,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"103215089","source":2,"sequence":64},{"txHash":"C728F7C13977649FCDF9B8E983A9E3AA257EB5596DBCA2A2580584312B5AA535","blockHeight":105721925,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:43.111Z","fromAddr":"bnb155svs6sgxe55rnvs6ghprtqu0mh69kehphsppd","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"119.64120000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":147,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101045880","source":1,"sequence":23121},{"txHash":"794302F9C6562358581A3A8432AF82CD70DF0DA345C917BDE21DDF9A9D4B9DE7","blockHeight":105721913,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:38.279Z","fromAddr":"bnb14gk6m77tswyks9nnadm92mdy3066wj42t60z0l","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"4.56000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":152,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"100341541","source":1,"sequence":11228},{"txHash":"2827377A04E3B22DD654A02AD4BA50B3CB83973B6B9BA1A423ABD5045873850C","blockHeight":105721828,"txType":"TRANSFER","timeStamp":"2020-08-07T18:47:04.205Z","fromAddr":"bnb132gvg9gdthtaf6xgkk9jkmsep56fv62vg95unv","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"10.45498916","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":186,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"105772095","source":2,"sequence":4},{"txHash":"AACC80FDA9C45DCD7F6DBAA40A2EB600FF6EBB24A5A840578D4AB306C3427385","blockHeight":105721785,"txType":"TRANSFER","timeStamp":"2020-08-07T18:46:46.832Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"87.50000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":203,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":65},{"txHash":"66CF0F65442FD35A3B91CC2655CE60E565D13EEFC6BDB1C5AF9F9E484C8B6295","blockHeight":105721686,"txType":"TRANSFER","timeStamp":"2020-08-07T18:46:07.122Z","fromAddr":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"8.78900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":243,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"107780643","source":0,"sequence":896},{"txHash":"81EA185BE754809E40FCBF1B07A0C389F39DECD38D56302D980534850996B144","blockHeight":105721490,"txType":"TRANSFER","timeStamp":"2020-08-07T18:44:48.958Z","fromAddr":"bnb12nq7fhh3t8q0m9s2n5gqwd9gcx0j85yn0h5zcu","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"44.98159221","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":321,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101210049","source":0,"sequence":0},{"txHash":"24ED2153427ABACD7F6DB53A1339D9C2573D720FDE6EC45B0047CB146227FF9A","blockHeight":105721385,"txType":"TRANSFER","timeStamp":"2020-08-07T18:44:07.201Z","fromAddr":"bnb1s5qucugaxv7gkzyg4kacf225s6mhj0ysejn8jq","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"343.00000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":363,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"104298046","source":2,"sequence":40},{"txHash":"411A27CE85D0928BC5908DA5BA288CB52E152C1E54FA35042147A90FCEBAB29C","blockHeight":105721238,"txType":"TRANSFER","timeStamp":"2020-08-07T18:43:09.084Z","fromAddr":"bnb1erj09eqrnz06jv2acxhhy7s3k0q6w4hfmj9rey","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.06319074","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":421,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"107303874","source":2,"sequence":12},{"txHash":"25359F7277760004BBD42557B3E50F86F06B096478840E057C6F394BF63F6081","blockHeight":105720997,"txType":"TRANSFER","timeStamp":"2020-08-07T18:41:32.193Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"10.90000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":518,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":57},{"txHash":"1DB710AF4983D9CAFB24AC3DD7C2C6EBC7752F347E5A7599840AB3EFBD436C5D","blockHeight":105720867,"txType":"TRANSFER","timeStamp":"2020-08-07T18:40:39.623Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"20.00000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":570,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":56},{"txHash":"B7C799B9853ECA41F02241B67E294E2642AE88BBF551DE188A73C48D1A0E821D","blockHeight":105720816,"txType":"TRANSFER","timeStamp":"2020-08-07T18:40:19.123Z","fromAddr":"bnb1q2994t0djzsy0q2fc62jruxr22nxq6y8l4503l","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.95957149","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":591,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"108202494","source":0,"sequence":1},{"txHash":"865C098D021CC649FC83B2442092E4D6F0777488163E5797DA9D264C87F1F4F4","blockHeight":105720641,"txType":"TRANSFER","timeStamp":"2020-08-07T18:39:08.972Z","fromAddr":"bnb16xqcchlutsm8g6gk7wvlzukeu2sy9xt2u77056","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"13.73501799","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":661,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"102080722","source":1,"sequence":33},{"txHash":"1D4F777D1D227D57E4D4BAC3E83FB203147E7B0E7429E60A48A9053372359174","blockHeight":105720519,"txType":"TRANSFER","timeStamp":"2020-08-07T18:38:20.149Z","fromAddr":"bnb1t6tk66zncqqt7twnfyxx22fn9t3wz3nac5hkck","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.01490609","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":710,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"106456805","source":2,"sequence":14},{"txHash":"9A818687D52B4E9E0C5F962E6E464ECC6348D6A41AE2C5DD051A5EF71E15B1AC","blockHeight":105720307,"txType":"TRANSFER","timeStamp":"2020-08-07T18:36:55.571Z","fromAddr":"bnb1v47qw5acc72c34uwt7t9wm9ztqtg6678dmrssa","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"3.56700000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":794,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"104471384","source":2,"sequence":6273},{"txHash":"6C7D4469525E44501ED03BA38A6D54A04DFD6AD2D13328761DA4602A3D777332","blockHeight":105720136,"txType":"TRANSFER","timeStamp":"2020-08-07T18:35:48.142Z","fromAddr":"bnb1tzet704pc6zjsl3xcwdexn6xlu0zc092y0n4ay","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.93900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":862,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101245732","source":0,"sequence":721},{"txHash":"8C47875F09371B45C0A29D7C6EF308A1C499D1BBECD5A56E0561B40675AF2D26","blockHeight":105720042,"txType":"TRANSFER","timeStamp":"2020-08-07T18:35:11.247Z","fromAddr":"bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.95193451","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":899,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"101186586","source":2,"sequence":1912},{"txHash":"39A48766F8ACC33B3BB1B4F442ABFDFBC695F440D72795794A01E8E446CE8EAE","blockHeight":105720010,"txType":"TRANSFER","timeStamp":"2020-08-07T18:34:58.634Z","fromAddr":"bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"4.80000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":911,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109027392","source":1,"sequence":47},{"txHash":"54248E3C09713E3870F661749A8690DAD46A8078C7346C497EB4E166564420F4","blockHeight":105719860,"txType":"TRANSFER","timeStamp":"2020-08-07T18:33:57.102Z","fromAddr":"bnb1hc304lytvp9jnumnjmppq97erm70r7muzv6y98","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"102.10962500","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":973,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"105261446","source":0,"sequence":1},{"txHash":"ADDDB705AB8C2B1AF58D7EDCAEC00C893A6CD87281D7A7146689E9FE1A846EAE","blockHeight":105719705,"txType":"TRANSFER","timeStamp":"2020-08-07T18:32:53.527Z","fromAddr":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.97900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1036,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"103617121","source":0,"sequence":895},{"txHash":"7C338C78BBBCD998628CCAF85211883AACB159201755501139F56E0D2A7941A4","blockHeight":105719641,"txType":"TRANSFER","timeStamp":"2020-08-07T18:32:27.476Z","fromAddr":"bnb1pys084nlc8gqm7lvjje4kt39dn84vd2xsvnwqa","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"2.00000000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1062,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"108802310","source":0,"sequence":18},{"txHash":"6DD7120E43CD5031E2DD6C7977D141B74CA41C8E476D8AE972A9DA2D2EFD2D84","blockHeight":105719428,"txType":"TRANSFER","timeStamp":"2020-08-07T18:31:01.143Z","fromAddr":"bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"6.77900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1149,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"102393444","source":0,"sequence":894},{"txHash":"86FB14C637D7B0A4AA123FFF76C5C541C70568B67E3F5BC63EB0FDEDEF30301F","blockHeight":105719403,"txType":"TRANSFER","timeStamp":"2020-08-07T18:30:51.089Z","fromAddr":"bnb17nak8gnucl6lcze0d04def4de77a33qh29f6ur","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"0.00900000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1159,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"109823910","source":2,"sequence":3},{"txHash":"1DEEFC0A838F80704574951DF15969CCE34654BE2007BF77F9521A1B4686BE33","blockHeight":105719312,"txType":"TRANSFER","timeStamp":"2020-08-07T18:30:14.498Z","fromAddr":"bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","value":"3.15739000","txAsset":"BNB","txFee":"0.00037500","proposalId":null,"txAge":1195,"orderId":null,"code":0,"data":null,"confirmBlocks":0,"memo":"103268674","source":2,"sequence":1431}],"total":1636}` - wantedAccountMetaResponse = `{"account_number":398176,"address":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","balances":[{"free":"366.87270502","frozen":"0.00000000","locked":"2226.00000000","symbol":"AVA-645"},{"free":"6.51198688","frozen":"0.00000000","locked":"0.00000000","symbol":"BNB"},{"free":"850.41375978","frozen":"0.00000000","locked":"3220.00483000","symbol":"BUSD-BD1"}],"flags":0,"public_key":[2,241,253,162,68,84,67,180,235,15,238,212,39,75,236,33,202,249,109,68,247,56,104,66,240,219,8,22,245,187,84,46,54],"sequence":1595533}` - wantedTokensResponse = `[{"mintable":true,"name":"Africa Stable-Coin","original_symbol":"ABCD","owner":"bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms","symbol":"ABCD-5D8","total_supply":"3000000.00000000"},{"mintable":false,"name":"Aditus","original_symbol":"ADI","owner":"bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps","symbol":"ADI-6BB","total_supply":"750000000.00000000"},{"mintable":false,"name":"Aergo","original_symbol":"AERGO","owner":"bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl","symbol":"AERGO-46B","total_supply":"500000000.00000000"},{"mintable":false,"name":"Alaris","original_symbol":"ALA","owner":"bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7","symbol":"ALA-DCD","total_supply":"60000000.00000000"},{"mintable":false,"name":"ANKR","original_symbol":"ANKR","owner":"bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn","symbol":"ANKR-E97","total_supply":"10000000000.00000000"},{"mintable":false,"name":"Aeron","original_symbol":"ARN","owner":"bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne","symbol":"ARN-71B","total_supply":"20000000.00000000"},{"mintable":true,"name":"ARPA","original_symbol":"ARPA","owner":"bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c","symbol":"ARPA-575","total_supply":"12000000.00000000"},{"mintable":false,"name":"Maecenas ART Token","original_symbol":"ART","owner":"bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l","symbol":"ART-3C9","total_supply":"100000000.00000000"},{"mintable":true,"name":"Atlas Protocol","original_symbol":"ATP","owner":"bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf","symbol":"ATP-38C","total_supply":"40000000.00000000"},{"mintable":false,"name":"Travala.com Token","original_symbol":"AVA","owner":"bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c","symbol":"AVA-645","total_supply":"61228716.00000000"},{"mintable":true,"name":"“Atomic","original_symbol":"AWC","owner":"bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw","symbol":"AWC-8B2","total_supply":"147.00000000"},{"mintable":false,"name":"Atomic Wallet Token","original_symbol":"AWC","owner":"bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw","symbol":"AWC-986","total_supply":"50000000.00000000"},{"mintable":false,"name":"AXPR.B","original_symbol":"AXPR","owner":"bnb1zpnmet0vhfupn9ysu26gukzj7a2xkkcry22n9t","symbol":"AXPR-777","total_supply":"347955111.02000000"},{"mintable":true,"name":"BAWnetwork","original_symbol":"BAW","owner":"bnb1umdp5z4hugur26tcgf48fhr0548fv0q0fga84u","symbol":"BAW-DFB","total_supply":"25000000000.00000000"},{"mintable":true,"name":"BCH BEP2","original_symbol":"BCH","owner":"bnb15tjhzw85wyywwp7zvc4l3ux3j0393rzp9exl0p","symbol":"BCH-1FD","total_supply":"5000.00000000"},{"mintable":false,"name":"Blockmason Credit Protocol","original_symbol":"BCPT","owner":"bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew","symbol":"BCPT-95A","total_supply":"116158667.00000000"},{"mintable":true,"name":"3X Short Bitcoin Token","original_symbol":"BEAR","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"BEAR-14C","total_supply":"50301.00000000"},{"mintable":false,"name":"EOSBet Token","original_symbol":"BET","owner":"bnb1rgylg0f3ka24a63rnq926quvet438fxrz3320c","symbol":"BET-844","total_supply":"88000000.00000000"},{"mintable":false,"name":"BETX Token","original_symbol":"BETX","owner":"bnb15v9e3c4wy8vpex0c5fj702lexjesh30v2203f2","symbol":"BETX-A0C","total_supply":"200000000.00000000"},{"mintable":true,"name":"Binance GBP Stable Coin","original_symbol":"BGBP","owner":"bnb1r4ag7kd90rptlhcuuc8trh60v4m4vvzrfyecta","symbol":"BGBP-CF3","total_supply":"200.00000000"},{"mintable":true,"name":"Humanity First Token","original_symbol":"BHFT","owner":"bnb148t3u8zxa44vhydes5qa8xnxuzuq6zgyxmzt6d","symbol":"BHFT-BBE","total_supply":"636425000.00000000"},{"mintable":true,"name":"BIDR BEP2","original_symbol":"BIDR","owner":"bnb1v7hlk89x4t6wtfx89wrvhxj5wcv7sxjrve6dav","symbol":"BIDR-0E9","total_supply":"13700000000.00000000"},{"mintable":false,"name":"Bitwires Token","original_symbol":"BKBT","owner":"bnb104p50kz2uvep5s5u6j0lr6vkl6rp5g4653d7w4","symbol":"BKBT-3A6","total_supply":"10000000000.00000000"},{"mintable":true,"name":"Binance KRW","original_symbol":"BKRW","owner":"bnb18kha55gvsxl7gkdh8y329hu3p6wndh6jkwqnxn","symbol":"BKRW-AB7","total_supply":"1571020711.00000000"},{"mintable":false,"name":"Blockmason Link","original_symbol":"BLINK","owner":"bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew","symbol":"BLINK-9C6","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Binance Chain Native Token","original_symbol":"BNB","owner":"bnb1ultyhpw2p2ktvr68swz56570lgj2rdsadq3ym2","symbol":"BNB","total_supply":"176406560.90000000"},{"mintable":false,"name":"BOLT Token","original_symbol":"BOLT","owner":"bnb177ujwmshxu8r9za4vy9ztqn65tmr54ddw958rt","symbol":"BOLT-4C6","total_supply":"980230000.00000000"},{"mintable":false,"name":"Bitcloud Pro","original_symbol":"BPRO","owner":"bnb1482svhhrffpga5wmqw8068af4c9u2q9dp3hg4m","symbol":"BPRO-5A6","total_supply":"5000000000.00000000"},{"mintable":true,"name":"BQTX","original_symbol":"BQTX","owner":"bnb1j42h6j40htujnjmtp4ckw4zx27vp0f93cvmua8","symbol":"BQTX-235","total_supply":"1000000.00000000"},{"mintable":false,"name":"BOOSTO","original_symbol":"BST2","owner":"bnb19k2av7cmdvp9f0qkeu5vfl59yp8ftqv2s55dzs","symbol":"BST2-2F2","total_supply":"500000000.00000000"},{"mintable":true,"name":"Bitcoin BEP2","original_symbol":"BTCB","owner":"bnb1akey87kt0r8y3fmhu2l8eyzdjvt9ptl5cppz0v","symbol":"BTCB-1DE","total_supply":"9001.00000000"},{"mintable":true,"name":"BTTB","original_symbol":"BTTB","owner":"bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq","symbol":"BTTB-D31","total_supply":"1000000000.00000000"},{"mintable":true,"name":"3x Long Bitcoin Token","original_symbol":"BULL","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"BULL-BE4","total_supply":"604.80000000"},{"mintable":true,"name":"Binance USD","original_symbol":"BUSD","owner":"bnb19v2ayq6k6e5x6ny3jdutdm6kpqn3n6mxheegvj","symbol":"BUSD-BD1","total_supply":"26000000.00000000"},{"mintable":false,"name":"Bezant Token","original_symbol":"BZNT","owner":"bnb1w5a5jywe3cu20uq6n6x3vmzcq342s6st4cz73s","symbol":"BZNT-464","total_supply":"964511442.00000000"},{"mintable":false,"name":"CanYaCoin","original_symbol":"CAN","owner":"bnb16w59lfh4y2cqvu8f7yr000ll37ldh4w6hnz7l0","symbol":"CAN-677","total_supply":"95827000.00000000"},{"mintable":false,"name":"CASHAA","original_symbol":"CAS","owner":"bnb1xkw2sagpx6t0cmwzapxpv94tupvqk7tpgy72ku","symbol":"CAS-167","total_supply":"1000000000.00000000"},{"mintable":false,"name":"Cubiex","original_symbol":"CBIX","owner":"bnb1jlm66w38gpfuqr4s2jcfwlcrlx46p05thdnv7g","symbol":"CBIX-3C9","total_supply":"150000000.00000000"},{"mintable":false,"name":"CryptoBonusMiles","original_symbol":"CBM","owner":"bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne","symbol":"CBM-4B2","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Clipper Coin","original_symbol":"CCCX","owner":"bnb1ry99rte8gfnn9c6at9mlmrrq6p2k4u7732j9h7","symbol":"CCCX-10D","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Chiliz","original_symbol":"CHZ","owner":"bnb1cghr4z8ag440tv4wnk3l6wzynytlpvfqltm9ph","symbol":"CHZ-ECD","total_supply":"8888888888.00000000"},{"mintable":false,"name":"Crypto Neo-value Neural System","original_symbol":"CNNS","owner":"bnb193wdp4gdnm58urnsjf8nv57lxt58sckt2k50ss","symbol":"CNNS-E16","total_supply":"10000000000.00000000"},{"mintable":false,"name":"Contentos","original_symbol":"COS","owner":"bnb1u9j9hkst6gf09dkdvxlj7puk8c7vh68a0kkmht","symbol":"COS-2E4","total_supply":"9400000000.00000000"},{"mintable":true,"name":"COTI","original_symbol":"COTI","owner":"bnb1kn733gkku9xsqkuk6wcz86gftqtl4qvthvrj5m","symbol":"COTI-CBB","total_supply":"80000000.00000000"},{"mintable":false,"name":"Covalent Token","original_symbol":"COVA","owner":"bnb1pucvxaf3l9rslupza75r9fca9h5892ntumszfm","symbol":"COVA-218","total_supply":"6500000000.00000000"},{"mintable":false,"name":"CPChain","original_symbol":"CPC","owner":"bnb1wq4rlwrmvvltlarvypql8wrr4vlh0dczd8uksg","symbol":"CPC-FED","total_supply":"150000000.00000000"},{"mintable":false,"name":"Crypterium Token","original_symbol":"CRPT","owner":"bnb17fk3uvagucxzpvmdvd373fapqsahxvzevdard9","symbol":"CRPT-8C9","total_supply":"99968575.14285720"},{"mintable":false,"name":"“Consentium”","original_symbol":"CSM","owner":"bnb1gguz7vcrlf7a87et8u5gt40f0890qvkpkn9y79","symbol":"CSM-734","total_supply":"84000000.00000000"},{"mintable":true,"name":"Carbon Dollar","original_symbol":"CUSD","owner":"bnb1y9797dtklkm3haajsfnevm9ruuxs5fyf5rpj67","symbol":"CUSD-24B","total_supply":"9999999999.00000000"},{"mintable":false,"name":"Konstellation Network","original_symbol":"DARC","owner":"bnb1gyhnhdns4vf63nfzfq7g25czj8swjgrz3rhah8","symbol":"DARC-24B","total_supply":"1000000000.00000000"},{"mintable":true,"name":"DeepCloud","original_symbol":"DEEP","owner":"bnb1t0ws9gvnjm7j7qssk8te7m2dt5hmm8s3amqk2d","symbol":"DEEP-9D3","total_supply":"200000000.00000000"},{"mintable":false,"name":"DeFi Token","original_symbol":"DEFI","owner":"bnb1q5xefr07503pqtfrl5sfyyhlghxwc80d4vpas2","symbol":"DEFI-FA5","total_supply":"2500000000.00000000"},{"mintable":true,"name":"DOS Network Token","original_symbol":"DOS","owner":"bnb13gse9n7mvrjg5w2cymnt4nmxkgj200k9k2l2nh","symbol":"DOS-120","total_supply":"1000000000.00000000"},{"mintable":false,"name":"DREP","original_symbol":"DREP","owner":"bnb1ez5s9v4rcgsmhwr4fkrnlv6zwsukjnh4y754kn","symbol":"DREP-7D2","total_supply":"10000000000.00000000"},{"mintable":true,"name":"Dusk Network","original_symbol":"DUSK","owner":"bnb1dfls6c8y39l7qq4gj2479wkehg85pt5m07y94g","symbol":"DUSK-45E","total_supply":"50000000.00000000"},{"mintable":false,"name":"eBoost","original_symbol":"EBST","owner":"bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7","symbol":"EBST-783","total_supply":"80838159.07000000"},{"mintable":true,"name":"Ormeus Ecosystem","original_symbol":"ECO","owner":"bnb1tr49nv08k828n2lqfw0vrgvwj7xtep5kg8wr4c","symbol":"ECO-083","total_supply":"5000000000.00000000"},{"mintable":false,"name":"Energy Eco Token","original_symbol":"EET","owner":"bnb1pt353m8ygvvgy4f2ud9xx85tl7fqewkrksh6r5","symbol":"EET-45C","total_supply":"600000000.00000000"},{"mintable":false,"name":"Hut34 Entropy","original_symbol":"ENTRP","owner":"bnb1wu0hu9pelx3yvplysx0je7d93htcandpj86aev","symbol":"ENTRP-C8D","total_supply":"100000000.00000000"},{"mintable":true,"name":"EOS BEP2","original_symbol":"EOS","owner":"bnb1la8alalwjzkchd67wza3r75lj5rm7m9e85ffqr","symbol":"EOS-CDD","total_supply":"500000.00000000"},{"mintable":true,"name":"3X Short EOS Token","original_symbol":"EOSBEAR","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"EOSBEAR-721","total_supply":"32301.00000000"},{"mintable":true,"name":"3X Long EOS Token","original_symbol":"EOSBULL","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"EOSBULL-F0D","total_supply":"456191.00000000"},{"mintable":false,"name":"EQUAL","original_symbol":"EQL","owner":"bnb1uz0s54rzv022dh66l7atwk83wqcet9qstgg358","symbol":"EQL-586","total_supply":"675259060.00000000"},{"mintable":true,"name":"Elrond","original_symbol":"ERD","owner":"bnb1m5uzzfxs7x05sl28gg96zyecn9jwgtkpyeftyn","symbol":"ERD-D06","total_supply":"13000000000.00000000"},{"mintable":true,"name":"ETH BEP2","original_symbol":"ETH","owner":"bnb1yss2345dphss8c823dh2jzje2w8k8x4jguuxhf","symbol":"ETH-1C9","total_supply":"10000.00000000"},{"mintable":true,"name":"3X Short Ethereum Token","original_symbol":"ETHBEAR","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"ETHBEAR-B2B","total_supply":"61821.00000000"},{"mintable":true,"name":"3X Long Ethereum Token","original_symbol":"ETHBULL","owner":"bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees","symbol":"ETHBULL-D33","total_supply":"33684.00000000"},{"mintable":true,"name":"everiToken","original_symbol":"EVT","owner":"bnb1v3fl4kuwuhzf3g7ghscsq7uzmu5dw50waseptd","symbol":"EVT-49B","total_supply":"1000000000.00000000"},{"mintable":true,"name":"The Force Token","original_symbol":"FOR","owner":"bnb1c46nhwdwm3u2mlfhx6t07fls25shnvktpr9w9m","symbol":"FOR-997","total_supply":"100000000.00000000"},{"mintable":false,"name":"Ferrum Network Token","original_symbol":"FRM","owner":"bnb1um8ntkgwle8yrdk0yn5hwdf7hckjpyjjg29k2p","symbol":"FRM-DE7","total_supply":"164609374.50000000"},{"mintable":false,"name":"Fusion","original_symbol":"FSN","owner":"bnb17mnutyduat9fe02r2dawp3kn4rnaqamp5kpg0c","symbol":"FSN-E14","total_supply":"57344000.00000000"},{"mintable":true,"name":"Fantom","original_symbol":"FTM","owner":"bnb1f6sxnf3nhn9fcfwkuccrzvl2pgu3sq0m8pyjhw","symbol":"FTM-A64","total_supply":"952500000.00000000"},{"mintable":true,"name":"FTX Token","original_symbol":"FTT","owner":"bnb1msxdh7e7smpg68gxxhs0p3fhuj9tzhrxa4c2x2","symbol":"FTT-F11","total_supply":"10000000.00000000"},{"mintable":true,"name":"Givly Coin","original_symbol":"GIV","owner":"bnb13jzr6sqz72fl0edg2tpqp8tddyzvyt4su2490m","symbol":"GIV-94E","total_supply":"1000000000.00000000"},{"mintable":false,"name":"GoWithMi","original_symbol":"GMAT","owner":"bnb1yltla9mnk8999ygmjjn3kwmmz2zs94a9v20sca","symbol":"GMAT-FC8","total_supply":"14900000000.00000000"},{"mintable":false,"name":"Global Gaming","original_symbol":"GMNG","owner":"bnb1qe6zxqptfxw0kh38t8pg6c3qa527n2x2a87qvm","symbol":"GMNG-F3E","total_supply":"5000000000.00000000"},{"mintable":false,"name":"GTEX","original_symbol":"GTEX","owner":"bnb1nksrzfl24he9xtvdvpypsl6r5jnh5x2uf9s82z","symbol":"GTEX-71B","total_supply":"4000000000.00000000"},{"mintable":false,"name":"Gifto","original_symbol":"GTO","owner":"bnb1lvp8k3zenlfp2pl2nyaf428xjgh385m258gzvq","symbol":"GTO-908","total_supply":"1000000000.00000000"},{"mintable":true,"name":"“Hermes","original_symbol":"HEC","owner":"bnb1dfyydqkmsv5m0rs0pa4uut2gwrcsahppktns2t","symbol":"HEC-1A9","total_supply":"100000000.00000000"},{"mintable":false,"name":"Honest","original_symbol":"HNST","owner":"bnb1k9fv2hz0w3l9v9z4g9samg3gtc7nc2xgyqw5u0","symbol":"HNST-3C9","total_supply":"400000000.00000000"},{"mintable":true,"name":"Hyperion Token","original_symbol":"HYN","owner":"bnb1q5cqecuy2g7syl8fssp9a7v2sjamtrzlr3pa0n","symbol":"HYN-F21","total_supply":"10000000000.00000000"},{"mintable":true,"name":"Rupiah Token","original_symbol":"IDRTB","owner":"bnb1wc44duax6pygh23psx0u945skvs3eh7w59e4sp","symbol":"IDRTB-178","total_supply":"90000000000.00000000"},{"mintable":false,"name":"IKU","original_symbol":"IKU","owner":"bnb1f52tc9l0qg337qtgu4n024ayllc78wxpc5xhvd","symbol":"IKU-416","total_supply":"300000000.00000000"},{"mintable":true,"name":"IRIS Network","original_symbol":"IRIS","owner":"bnb1dcpm0jjj8el8g6ekr3mvjxa8kptgu4e5xzvqv8","symbol":"IRIS-D88","total_supply":"2000000000.00000000"},{"mintable":false,"name":"JDXUCoin","original_symbol":"JDXU","owner":"bnb1dwcsg0t86g7935zpxc054n97styzgdtnu2kzg6","symbol":"JDXU-706","total_supply":"1000000000.00000000"},{"mintable":false,"name":"Kambria Token","original_symbol":"KAT","owner":"bnb1l68n6equtr925lhnentyq54zfrzqyj45lg8uwj","symbol":"KAT-7BB","total_supply":"3700000000.00000000"},{"mintable":true,"name":"Kava BEP2 Token","original_symbol":"KAVA","owner":"bnb1uyekdn62yur9zuctzqyd9ckasfvqttjz9c33me","symbol":"KAVA-10C","total_supply":"271190.72181900"},{"mintable":false,"name":"Sessia Kicks","original_symbol":"KICKS","owner":"bnb130tmwjd3fc79eh6f5ezl2326ur8rqpsxeeq30x","symbol":"KICKS-162","total_supply":"5000000.00000000"},{"mintable":true,"name":"Lambda","original_symbol":"LAMB","owner":"bnb19vnwdjwthm9unxe9hxdxmgm6qw0d42d2lmcesw","symbol":"LAMB-46C","total_supply":"5000000.00000000"},{"mintable":false,"name":"Lend-Borrow-Asset","original_symbol":"LBA","owner":"bnb1m8r74hr532lfwtaf5e88cxeakd36ut0ufpd4yu","symbol":"LBA-340","total_supply":"1000000000.00000000"},{"mintable":true,"name":"LITION","original_symbol":"LIT","owner":"bnb1fhlxwqlwd7cm5fmurg0wmsaalshnp7lwu46nk9","symbol":"LIT-099","total_supply":"145061313.45061312"},{"mintable":true,"name":"Loki","original_symbol":"LOKI","owner":"bnb1j5sft8wp7tktjwauy30x79f3tqa53fycmgxxs0","symbol":"LOKI-6A9","total_supply":"3000000.00000000"},{"mintable":true,"name":"LTC BEP2","original_symbol":"LTC","owner":"bnb1cn4sqm79wqmr8rey923r34cp2wrtyhlr9easpg","symbol":"LTC-F07","total_supply":"18500.00000000"},{"mintable":false,"name":"LTO Network","original_symbol":"LTO","owner":"bnb1ac6p45m00pv36y9mu48e5xr73fyxke3zv2rhmq","symbol":"LTO-BDF","total_supply":"500000000.00000000"},{"mintable":false,"name":"LYFE","original_symbol":"LYFE","owner":"bnb1k0779dltjkl6a05v5uq06zym62hcufzcqu6gq7","symbol":"LYFE-6AB","total_supply":"231250000.00000000"},{"mintable":false,"name":"Matic Token","original_symbol":"MATIC","owner":"bnb1a6nkf3g7c2z0jcrqhp8c9upcwmme0y49qx58nz","symbol":"MATIC-84A","total_supply":"10000000000.00000000"},{"mintable":false,"name":"Moviebloc","original_symbol":"MBL","owner":"bnb17p8rc0z5vlysff2wc7xehff464dm0v7nhl27xq","symbol":"MBL-2D2","total_supply":"30000000000.00000000"},{"mintable":true,"name":"Mcashchain","original_symbol":"MCASH","owner":"bnb1q420q7qpyv7tghfp6aac7vnjq74dhkeutdhqsg","symbol":"MCASH-869","total_supply":"200000000.00000000"},{"mintable":false,"name":"Magic Cube Token","original_symbol":"MCC","owner":"bnb14nt79d6hzhjefkys2cgrc9nrzugdjwwtggfmu4","symbol":"MCC-33B","total_supply":"20000000000.00000000"},{"mintable":false,"name":"MDAB","original_symbol":"MDAB","owner":"bnb1m3edd4q4nd3wxg9vm3xe8pnfnetu5yjmhtnrqz","symbol":"MDAB-D42","total_supply":"1000000000.00000000"}]` - wantedTxsResponseAva = `{"tx":[{"txHash":"2BF49DF1D10D9A20438376E760352734DAEBD5D92D6CAA14735EE095A3F65FD3","blockHeight":105725696,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:41.390Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"47.98467000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":5,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594674","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77721\",\"quantity\":\"27\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594674\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594673},{"txHash":"C858D15E2745A61D0D3D354750E4462792160FFBB9927739587FFAAEDEFA00FF","blockHeight":105725676,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:32.989Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"250.85976000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":13,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594671","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.91496\",\"quantity\":\"131\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594671\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594670},{"txHash":"9BDCF416622AA4E8F11162747614585FD840F5721D7163A68BC03EC94E855DEE","blockHeight":105725673,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:31.760Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"30.17126000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":14,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594670","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77478\",\"quantity\":\"17\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594670\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594669},{"txHash":"52512D9498D4CF51997A5A62C0A55252776B00C888D2D01502C68B56E892F42E","blockHeight":105725652,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:23.040Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"41.48298000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":23,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594667","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.88559\",\"quantity\":\"22\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594667\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594666},{"txHash":"1BAF96AB01E7AB5A7746CA7E76B293CD636D55713C7CCE71FD0E0ED8ACE05C92","blockHeight":105725646,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:20.614Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"26.59905000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":26,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594666","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77327\",\"quantity\":\"15\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594666\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594665},{"txHash":"9990419EFE1B327966EBAAFFC2771046E1AC2E4DDFAD8A93C55DE105A2948A8D","blockHeight":105725624,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:11.499Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"206.81568000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":35,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594663","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.91496\",\"quantity\":\"108\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594663\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594662},{"txHash":"922F86E110E897233A7B43C0D31397923298C176EBE6F33D98B70ACB911A497A","blockHeight":105725620,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:09.679Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"31.95630000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":36,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594662","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77535\",\"quantity\":\"18\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594662\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594661},{"txHash":"925A208AFDCD718F8383F7559C7BBA5AE616B693A6029F57BFB67AEBB1CE5F3C","blockHeight":105725597,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:13:00.237Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"135.99044000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":46,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594659","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65842\",\"quantity\":\"82\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594659\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594658},{"txHash":"2B69327D6C0C7B9061AAD962BF4838E3B630A844439013E0EBEFC5B722205774","blockHeight":105725575,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:51.165Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"26.39040000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":55,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594656","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.75936\",\"quantity\":\"15\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594656\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594655},{"txHash":"BB6FD86C9738C2991F587996ABBAC1151DF1F9DE57FDCC977BB0D8FBAD31188A","blockHeight":105725529,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:32.108Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"44.90475000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":74,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594654","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79619\",\"quantity\":\"25\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594654\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594653},{"txHash":"97856635BDBA4B0B3EAAA76EA46D848A2DFE3AAE554A33D308CFC4474C769290","blockHeight":105725526,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:30.917Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"94.10225000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":75,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594653","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.71095\",\"quantity\":\"55\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594653\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594652},{"txHash":"4B4EC65A5972CC15C4B410339ED0081C4BB57F4E08F2A35744845F5A71531B59","blockHeight":105725493,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:17.373Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"30.49341000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":89,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594649","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79373\",\"quantity\":\"17\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594649\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594648},{"txHash":"86B5FFDDB06E0973A05434DDB858868A45EDA8B07E0D75125FEAEBA1093D4EA5","blockHeight":105725489,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:15.680Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"195.81982000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":90,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594648","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"118\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594648\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594647},{"txHash":"D20757EB130E8146D1A12E869BE69EC2CB03193D8E62467327B09A5D73BBC6F8","blockHeight":105725473,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:09.086Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"59.27427000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":97,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594646","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79619\",\"quantity\":\"33\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594646\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594645},{"txHash":"04291A7AE08A78C5E5AE216C67D17B6A4260950FFAB6FD3D1C1B991E3B7BB935","blockHeight":105725470,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:12:07.990Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"242.28554000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":98,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594645","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"146\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594645\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594644},{"txHash":"31E16E3F53DD476475256C8D872AF3FD86DC44F3085EF87DDE3643E20C0CE624","blockHeight":105725448,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:58.857Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"32.30208000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":107,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594642","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79456\",\"quantity\":\"18\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594642\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594641},{"txHash":"1D61A9E35893BB51DE4AE63FA6898FCAE14B6D48F7A2EFD0B51DCCACF6E36B88","blockHeight":105725446,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:57.974Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"227.35013000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":108,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594641","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"137\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594641\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594640},{"txHash":"AB9E29B110844BD76F58B058CC20F1E13B37A1AAC4F09978BDE159F1B09B585E","blockHeight":105725425,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:49.358Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"26.88420000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":117,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594638","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79228\",\"quantity\":\"15\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594638\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594637},{"txHash":"F81649BAF3D888E3772C8708D255FE91E0CDB2818006A1FC96FFBDAC24BDE675","blockHeight":105725422,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:48.006Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"144.37563000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":118,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594637","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"87\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594637\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594636},{"txHash":"71B25BF61219BC87980EB67064C346801C01B00FFE52932799E28FB20DAF41D8","blockHeight":105725401,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:39.380Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"21.47556000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":127,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594634","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.78963\",\"quantity\":\"12\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594634\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594633},{"txHash":"3424BFCA860A878FDCF304AD414EDE2AB3B0FF258CA940CD1269F469ED7C422C","blockHeight":105725379,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:30.336Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"144.92516000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":136,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594631","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.90691\",\"quantity\":\"76\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594631\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594630},{"txHash":"46FFA039B955953D4F19BE7D56FA793B71F34BFB460D9B84A152B554E9219C44","blockHeight":105725375,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:28.671Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"231.90204000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":137,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594630","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.66836\",\"quantity\":\"139\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594630\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594629},{"txHash":"701100D3783744D633FF34A6E211CEB923EA9BCE6D87A64211801E71F71AEE03","blockHeight":105725327,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:09.184Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"92.81678000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":157,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594628","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.89422\",\"quantity\":\"49\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594628\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594627},{"txHash":"B12B30509B45CEFE526DAADDAC6399F902B30418859042D7A23F9A2FB311A6C8","blockHeight":105725323,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:11:07.404Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"47.87208000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":159,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594627","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77304\",\"quantity\":\"27\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594627\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594626},{"txHash":"933819F35F0F89FB2D58DC50CD15FABB3DA0B817BFCD39A8DDC99DFEC1663F7D","blockHeight":105725301,"txType":"NEW_ORDER","timeStamp":"2020-08-07T19:10:58.404Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"181.49465000","txAsset":"AVA-645","txFee":"0.00000000","proposalId":null,"txAge":168,"orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594624","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.91047\",\"quantity\":\"95\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594624\"}}","confirmBlocks":0,"memo":"","source":0,"sequence":1594623}],"total":11603}` - wantedBlockResponseMulti = `{"blockHeight":105529271,"tx":[{"txHash":"432FF828B1DC1C4DAF13A51B6AE7ADD9932B7FC6526C28F7FE9C905F95472820","blockHeight":105529271,"txType":"CANCEL_ORDER","timeStamp":"2020-08-06T20:38:46.583Z","fromAddr":"bnb1z35wusfv8twfele77vddclka9z84ugywug48gn","toAddr":null,"value":null,"txAsset":null,"txFee":null,"code":0,"data":"{\"orderData\":{\"orderId\":\"1468EE412C3ADC9CFF3EF31ADC7EDD288F5E208E-11315084\"}}","memo":"","source":0,"sequence":11317170},{"txHash":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","blockHeight":105529271,"txType":"TRANSFER","timeStamp":"2020-08-06T20:38:46.583Z","fromAddr":null,"toAddr":null,"value":null,"txAsset":null,"txFee":null,"code":0,"data":null,"memo":"0","source":1,"sequence":2300,"subTransactions":[{"txHash":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","blockHeight":105529271,"txType":"TRANSFER","fromAddr":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","toAddr":"bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w","txAsset":"BNB","txFee":"0.00060000","value":"0.00000001"},{"txHash":"CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067","blockHeight":105529271,"txType":"TRANSFER","fromAddr":"bnb1t38ccns9var4ac4yj2ylmu99r9ecmggr8ye5e5","toAddr":"bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23","txAsset":"BNB","txFee":null,"value":"0.39421249"}]}]}` - mockedBlockResponse = `{"blockHeight":104867508,"tx":[{"txHash":"4CD5BAA433BABA63D862141A4A2F9235B0BA5CBAB8114C93A0556ECA4EC7A68A","blockHeight":104867508,"txType":"CANCEL_ORDER","timeStamp":"2020-08-03T16:32:17.963Z","fromAddr":"bnb1l83kstts7lt9dpgawzechnrgjq54dql36dyspc","toAddr":null,"value":null,"txAsset":null,"txFee":null,"code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.94064\",\"quantity\":\"40\",\"timeInForce\":\"GTE\",\"orderId\":\"F9E3682D70F7D656851D70B38BCC6890295683F1-1023254\"}}","memo":"","source":0,"sequence":1023322},{"txHash":"9B87D17581F2AC73D2999EDE56535E50D9D4DB75150A92A90122190F77D47755","blockHeight":104867508,"txType":"TRANSFER","timeStamp":"2020-08-03T16:32:17.963Z","fromAddr":"bnb1c4czpzvn0ttdcpnv3cy2858l2m9frxdfgk4jr0","toAddr":"bnb1g2ukzn702napq3levm54m2z3p2gam7upern9aq","value":"0.24481570","txAsset":"BNB","txFee":"0.00037500","code":0,"data":null,"memo":"","source":0,"sequence":6},{"txHash":"5C0580AC983C1CF36F1656D9E8B062CD0578839BEFC839EFD6720FF315B45EEB","blockHeight":104867508,"txType":"NEW_ORDER","timeStamp":"2020-08-03T16:32:17.963Z","fromAddr":"bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg","toAddr":null,"value":"169.20330000","txAsset":"AVA-645","txFee":"0.00000000","orderId":"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1509155","code":0,"data":"{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.61146\",\"quantity\":\"105\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1509155\"}}","memo":"","source":0,"sequence":1509154}]}` - mockedNodeInfo = `{"node_info":{"protocol_version":{"p2p":7,"block":10,"app":0},"id":"46ba46d5b6fcb61b7839881a75b081123297f7cf","listen_addr":"10.212.32.84:27146","network":"Binance-Chain-Tigris","version":"0.32.3","channels":"3640202122233038","moniker":"Ararat","other":{"tx_index":"on","rpc_address":"tcp://0.0.0.0:27147"}},"sync_info":{"latest_block_hash":"507BB016F306906569F12883617A4231AB51DAF5FA5004C8F70B17CDF73A8B40","latest_app_hash":"A96FA3DB1FAC12D325845FFEE679EC52CB944BE4B343BC016CE4707FA63EE2BE","latest_block_height":104867535,"latest_block_time":"2020-08-03T16:32:29.834625465Z","catching_up":false},"validator_info":{"address":"B7707D9F593C62E85BB9E1A2366D12A97CD5DFF2","pub_key":[113,242,215,184,236,28,139,153,166,83,66,155,1,24,205,32,31,121,79,64,157,15,234,77,101,177,182,98,242,176,0,99],"voting_power":1000000000000}}` +var ( + wantedBlockNoOrders, _ = mock.JsonFromFilePathToString("mocks/block_no_orders.json") + wantedTxs, _ = mock.JsonFromFilePathToString("mocks/txs.json") + wantedTokens, _ = mock.JsonFromFilePathToString("mocks/tokens.json") + wantedBlockMultiNoOrders, _ = mock.JsonFromFilePathToString("mocks/block_multi_no_orders.json") + wantedTxsResponse, _ = mock.JsonFromFilePathToString("mocks/txs_response.json") + wantedAccountMetaResponse, _ = mock.JsonFromFilePathToString("mocks/account_meta_response.json") + wantedTokensResponse, _ = mock.JsonFromFilePathToString("mocks/tokens_response.json") + wantedTxsResponseAva, _ = mock.JsonFromFilePathToString("mocks/txs_ava_response.json") + wantedBlockResponseMulti, _ = mock.JsonFromFilePathToString("mocks/block_multi_response.json") + mockedBlockResponse, _ = mock.JsonFromFilePathToString("mocks/block_response.json") + mockedNodeInfo, _ = mock.JsonFromFilePathToString("mocks/node_info.json") ) func createMockedAPI() http.Handler { diff --git a/platform/binance/block_test.go b/platform/binance/block_test.go index 5a496ced9..4e1447d02 100644 --- a/platform/binance/block_test.go +++ b/platform/binance/block_test.go @@ -25,11 +25,11 @@ func TestPlatform_GetBlockByNumber(t *testing.T) { assert.Nil(t, err) res, err := json.Marshal(block) assert.Nil(t, err) - assert.Equal(t, wantedBlockNoOrders, string(res)) + assert.JSONEq(t, wantedBlockNoOrders, string(res)) blockMulti, err := p.GetBlockByNumber(105529271) assert.Nil(t, err) resMulti, err := json.Marshal(blockMulti) assert.Nil(t, err) - assert.Equal(t, wantedBlockMultiNoOrders, string(resMulti)) + assert.JSONEq(t, wantedBlockMultiNoOrders, string(resMulti)) } diff --git a/platform/binance/mocks/account_meta_response.json b/platform/binance/mocks/account_meta_response.json new file mode 100644 index 000000000..774123a1c --- /dev/null +++ b/platform/binance/mocks/account_meta_response.json @@ -0,0 +1,61 @@ +{ + "account_number": 398176, + "address": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "balances": [ + { + "free": "366.87270502", + "frozen": "0.00000000", + "locked": "2226.00000000", + "symbol": "AVA-645" + }, + { + "free": "6.51198688", + "frozen": "0.00000000", + "locked": "0.00000000", + "symbol": "BNB" + }, + { + "free": "850.41375978", + "frozen": "0.00000000", + "locked": "3220.00483000", + "symbol": "BUSD-BD1" + } + ], + "flags": 0, + "public_key": [ + 2, + 241, + 253, + 162, + 68, + 84, + 67, + 180, + 235, + 15, + 238, + 212, + 39, + 75, + 236, + 33, + 202, + 249, + 109, + 68, + 247, + 56, + 104, + 66, + 240, + 219, + 8, + 22, + 245, + 187, + 84, + 46, + 54 + ], + "sequence": 1595533 +} diff --git a/platform/binance/mocks/block_multi_no_orders.json b/platform/binance/mocks/block_multi_no_orders.json new file mode 100644 index 000000000..a1e3cfcb7 --- /dev/null +++ b/platform/binance/mocks/block_multi_no_orders.json @@ -0,0 +1,33 @@ +{ + "number": 105529271, + "txs": [ + { + "id": "CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067", + "coin": 714, + "from": "bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w", + "to": "bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w", + "fee": "60000", + "date": 1596746326, + "block": 105529271, + "status": "completed", + "sequence": 2300, + "type": "transfer", + "memo": "0", + "metadata": { "value": "1", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067", + "coin": 714, + "from": "bnb1t38ccns9var4ac4yj2ylmu99r9ecmggr8ye5e5", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "0", + "date": 1596746326, + "block": 105529271, + "status": "completed", + "sequence": 2300, + "type": "transfer", + "memo": "0", + "metadata": { "value": "39421249", "symbol": "BNB", "decimals": 8 } + } + ] +} diff --git a/platform/binance/mocks/block_multi_response.json b/platform/binance/mocks/block_multi_response.json new file mode 100644 index 000000000..661c0a852 --- /dev/null +++ b/platform/binance/mocks/block_multi_response.json @@ -0,0 +1,59 @@ +{ + "blockHeight": 105529271, + "tx": [ + { + "txHash": "432FF828B1DC1C4DAF13A51B6AE7ADD9932B7FC6526C28F7FE9C905F95472820", + "blockHeight": 105529271, + "txType": "CANCEL_ORDER", + "timeStamp": "2020-08-06T20:38:46.583Z", + "fromAddr": "bnb1z35wusfv8twfele77vddclka9z84ugywug48gn", + "toAddr": null, + "value": null, + "txAsset": null, + "txFee": null, + "code": 0, + "data": "{\"orderData\":{\"orderId\":\"1468EE412C3ADC9CFF3EF31ADC7EDD288F5E208E-11315084\"}}", + "memo": "", + "source": 0, + "sequence": 11317170 + }, + { + "txHash": "CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067", + "blockHeight": 105529271, + "txType": "TRANSFER", + "timeStamp": "2020-08-06T20:38:46.583Z", + "fromAddr": null, + "toAddr": null, + "value": null, + "txAsset": null, + "txFee": null, + "code": 0, + "data": null, + "memo": "0", + "source": 1, + "sequence": 2300, + "subTransactions": [ + { + "txHash": "CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067", + "blockHeight": 105529271, + "txType": "TRANSFER", + "fromAddr": "bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w", + "toAddr": "bnb15qced76xere38hmmpe644u5kd8v4lzl9gsex9w", + "txAsset": "BNB", + "txFee": "0.00060000", + "value": "0.00000001" + }, + { + "txHash": "CC7C3EF1407373FDA74B005E64683AB5865126DE93A5FAF755FF5CC948992067", + "blockHeight": 105529271, + "txType": "TRANSFER", + "fromAddr": "bnb1t38ccns9var4ac4yj2ylmu99r9ecmggr8ye5e5", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "txAsset": "BNB", + "txFee": null, + "value": "0.39421249" + } + ] + } + ] +} diff --git a/platform/binance/mocks/block_no_orders.json b/platform/binance/mocks/block_no_orders.json new file mode 100644 index 000000000..304f546f6 --- /dev/null +++ b/platform/binance/mocks/block_no_orders.json @@ -0,0 +1,19 @@ +{ + "number": 104867508, + "txs": [ + { + "id": "9B87D17581F2AC73D2999EDE56535E50D9D4DB75150A92A90122190F77D47755", + "coin": 714, + "from": "bnb1c4czpzvn0ttdcpnv3cy2858l2m9frxdfgk4jr0", + "to": "bnb1g2ukzn702napq3levm54m2z3p2gam7upern9aq", + "fee": "37500", + "date": 1596472337, + "block": 104867508, + "status": "completed", + "sequence": 6, + "type": "transfer", + "memo": "", + "metadata": { "value": "24481570", "symbol": "BNB", "decimals": 8 } + } + ] +} diff --git a/platform/binance/mocks/block_response.json b/platform/binance/mocks/block_response.json new file mode 100644 index 000000000..5e9d58638 --- /dev/null +++ b/platform/binance/mocks/block_response.json @@ -0,0 +1,54 @@ +{ + "blockHeight": 104867508, + "tx": [ + { + "txHash": "4CD5BAA433BABA63D862141A4A2F9235B0BA5CBAB8114C93A0556ECA4EC7A68A", + "blockHeight": 104867508, + "txType": "CANCEL_ORDER", + "timeStamp": "2020-08-03T16:32:17.963Z", + "fromAddr": "bnb1l83kstts7lt9dpgawzechnrgjq54dql36dyspc", + "toAddr": null, + "value": null, + "txAsset": null, + "txFee": null, + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.94064\",\"quantity\":\"40\",\"timeInForce\":\"GTE\",\"orderId\":\"F9E3682D70F7D656851D70B38BCC6890295683F1-1023254\"}}", + "memo": "", + "source": 0, + "sequence": 1023322 + }, + { + "txHash": "9B87D17581F2AC73D2999EDE56535E50D9D4DB75150A92A90122190F77D47755", + "blockHeight": 104867508, + "txType": "TRANSFER", + "timeStamp": "2020-08-03T16:32:17.963Z", + "fromAddr": "bnb1c4czpzvn0ttdcpnv3cy2858l2m9frxdfgk4jr0", + "toAddr": "bnb1g2ukzn702napq3levm54m2z3p2gam7upern9aq", + "value": "0.24481570", + "txAsset": "BNB", + "txFee": "0.00037500", + "code": 0, + "data": null, + "memo": "", + "source": 0, + "sequence": 6 + }, + { + "txHash": "5C0580AC983C1CF36F1656D9E8B062CD0578839BEFC839EFD6720FF315B45EEB", + "blockHeight": 104867508, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-03T16:32:17.963Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "169.20330000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1509155", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.61146\",\"quantity\":\"105\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1509155\"}}", + "memo": "", + "source": 0, + "sequence": 1509154 + } + ] +} diff --git a/platform/binance/mocks/node_info.json b/platform/binance/mocks/node_info.json new file mode 100644 index 000000000..5b059912b --- /dev/null +++ b/platform/binance/mocks/node_info.json @@ -0,0 +1,57 @@ +{ + "node_info": { + "protocol_version": { "p2p": 7, "block": 10, "app": 0 }, + "id": "46ba46d5b6fcb61b7839881a75b081123297f7cf", + "listen_addr": "10.212.32.84:27146", + "network": "Binance-Chain-Tigris", + "version": "0.32.3", + "channels": "3640202122233038", + "moniker": "Ararat", + "other": { "tx_index": "on", "rpc_address": "tcp://0.0.0.0:27147" } + }, + "sync_info": { + "latest_block_hash": "507BB016F306906569F12883617A4231AB51DAF5FA5004C8F70B17CDF73A8B40", + "latest_app_hash": "A96FA3DB1FAC12D325845FFEE679EC52CB944BE4B343BC016CE4707FA63EE2BE", + "latest_block_height": 104867535, + "latest_block_time": "2020-08-03T16:32:29.834625465Z", + "catching_up": false + }, + "validator_info": { + "address": "B7707D9F593C62E85BB9E1A2366D12A97CD5DFF2", + "pub_key": [ + 113, + 242, + 215, + 184, + 236, + 28, + 139, + 153, + 166, + 83, + 66, + 155, + 1, + 24, + 205, + 32, + 31, + 121, + 79, + 64, + 157, + 15, + 234, + 77, + 101, + 177, + 182, + 98, + 242, + 176, + 0, + 99 + ], + "voting_power": 1000000000000 + } +} diff --git a/platform/binance/mocks/tokens.json b/platform/binance/mocks/tokens.json new file mode 100644 index 000000000..8f8d1bcae --- /dev/null +++ b/platform/binance/mocks/tokens.json @@ -0,0 +1,26 @@ +[ + { + "name": "Travala.com Token", + "symbol": "AVA", + "decimals": 8, + "token_id": "AVA-645", + "coin": 714, + "type": "BEP2" + }, + { + "name": "Binance Chain Native Token", + "symbol": "BNB", + "decimals": 8, + "token_id": "BNB", + "coin": 714, + "type": "BEP2" + }, + { + "name": "Binance USD", + "symbol": "BUSD", + "decimals": 8, + "token_id": "BUSD-BD1", + "coin": 714, + "type": "BEP2" + } +] diff --git a/platform/binance/mocks/tokens_response.json b/platform/binance/mocks/tokens_response.json new file mode 100644 index 000000000..26e9613cf --- /dev/null +++ b/platform/binance/mocks/tokens_response.json @@ -0,0 +1,802 @@ +[ + { + "mintable": true, + "name": "Africa Stable-Coin", + "original_symbol": "ABCD", + "owner": "bnb1ujvzeuft0ezf9fu4u0mk52t8mc7t8geyfkevms", + "symbol": "ABCD-5D8", + "total_supply": "3000000.00000000" + }, + { + "mintable": false, + "name": "Aditus", + "original_symbol": "ADI", + "owner": "bnb1djdymfgzknmcsu9dzm9s0uavdszn0cl82z4hps", + "symbol": "ADI-6BB", + "total_supply": "750000000.00000000" + }, + { + "mintable": false, + "name": "Aergo", + "original_symbol": "AERGO", + "owner": "bnb1llqhwwwmh878844tm3g8v47k0t7xtnhl4hggjl", + "symbol": "AERGO-46B", + "total_supply": "500000000.00000000" + }, + { + "mintable": false, + "name": "Alaris", + "original_symbol": "ALA", + "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", + "symbol": "ALA-DCD", + "total_supply": "60000000.00000000" + }, + { + "mintable": false, + "name": "ANKR", + "original_symbol": "ANKR", + "owner": "bnb1hvg059mkwleum35j6y2qjn4fvmgl7zxtlah4tn", + "symbol": "ANKR-E97", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Aeron", + "original_symbol": "ARN", + "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", + "symbol": "ARN-71B", + "total_supply": "20000000.00000000" + }, + { + "mintable": true, + "name": "ARPA", + "original_symbol": "ARPA", + "owner": "bnb1mecnt25u3j9ne7th5av7hqvnmzvyrr7ny8hg8c", + "symbol": "ARPA-575", + "total_supply": "12000000.00000000" + }, + { + "mintable": false, + "name": "Maecenas ART Token", + "original_symbol": "ART", + "owner": "bnb13plj9kycvcew5v0achpatnd5l5pacys9h0gu8l", + "symbol": "ART-3C9", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "Atlas Protocol", + "original_symbol": "ATP", + "owner": "bnb1msw3avv894nlpeu0vn4qlkl0r65a3rp7gtz5hf", + "symbol": "ATP-38C", + "total_supply": "40000000.00000000" + }, + { + "mintable": false, + "name": "Travala.com Token", + "original_symbol": "AVA", + "owner": "bnb1dm9c7gccgd07td5r69m50u8fg8danfgqvlhj6c", + "symbol": "AVA-645", + "total_supply": "61228716.00000000" + }, + { + "mintable": true, + "name": "“Atomic", + "original_symbol": "AWC", + "owner": "bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw", + "symbol": "AWC-8B2", + "total_supply": "147.00000000" + }, + { + "mintable": false, + "name": "Atomic Wallet Token", + "original_symbol": "AWC", + "owner": "bnb1g5xj69c0s0x646hug7j3vr6eamlkf7jw3cr3yw", + "symbol": "AWC-986", + "total_supply": "50000000.00000000" + }, + { + "mintable": false, + "name": "AXPR.B", + "original_symbol": "AXPR", + "owner": "bnb1zpnmet0vhfupn9ysu26gukzj7a2xkkcry22n9t", + "symbol": "AXPR-777", + "total_supply": "347955111.02000000" + }, + { + "mintable": true, + "name": "BAWnetwork", + "original_symbol": "BAW", + "owner": "bnb1umdp5z4hugur26tcgf48fhr0548fv0q0fga84u", + "symbol": "BAW-DFB", + "total_supply": "25000000000.00000000" + }, + { + "mintable": true, + "name": "BCH BEP2", + "original_symbol": "BCH", + "owner": "bnb15tjhzw85wyywwp7zvc4l3ux3j0393rzp9exl0p", + "symbol": "BCH-1FD", + "total_supply": "5000.00000000" + }, + { + "mintable": false, + "name": "Blockmason Credit Protocol", + "original_symbol": "BCPT", + "owner": "bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew", + "symbol": "BCPT-95A", + "total_supply": "116158667.00000000" + }, + { + "mintable": true, + "name": "3X Short Bitcoin Token", + "original_symbol": "BEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "BEAR-14C", + "total_supply": "50301.00000000" + }, + { + "mintable": false, + "name": "EOSBet Token", + "original_symbol": "BET", + "owner": "bnb1rgylg0f3ka24a63rnq926quvet438fxrz3320c", + "symbol": "BET-844", + "total_supply": "88000000.00000000" + }, + { + "mintable": false, + "name": "BETX Token", + "original_symbol": "BETX", + "owner": "bnb15v9e3c4wy8vpex0c5fj702lexjesh30v2203f2", + "symbol": "BETX-A0C", + "total_supply": "200000000.00000000" + }, + { + "mintable": true, + "name": "Binance GBP Stable Coin", + "original_symbol": "BGBP", + "owner": "bnb1r4ag7kd90rptlhcuuc8trh60v4m4vvzrfyecta", + "symbol": "BGBP-CF3", + "total_supply": "200.00000000" + }, + { + "mintable": true, + "name": "Humanity First Token", + "original_symbol": "BHFT", + "owner": "bnb148t3u8zxa44vhydes5qa8xnxuzuq6zgyxmzt6d", + "symbol": "BHFT-BBE", + "total_supply": "636425000.00000000" + }, + { + "mintable": true, + "name": "BIDR BEP2", + "original_symbol": "BIDR", + "owner": "bnb1v7hlk89x4t6wtfx89wrvhxj5wcv7sxjrve6dav", + "symbol": "BIDR-0E9", + "total_supply": "13700000000.00000000" + }, + { + "mintable": false, + "name": "Bitwires Token", + "original_symbol": "BKBT", + "owner": "bnb104p50kz2uvep5s5u6j0lr6vkl6rp5g4653d7w4", + "symbol": "BKBT-3A6", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Binance KRW", + "original_symbol": "BKRW", + "owner": "bnb18kha55gvsxl7gkdh8y329hu3p6wndh6jkwqnxn", + "symbol": "BKRW-AB7", + "total_supply": "1571020711.00000000" + }, + { + "mintable": false, + "name": "Blockmason Link", + "original_symbol": "BLINK", + "owner": "bnb1ed7sfac04uzkg8lsxmgl7sxlj8pvyrpnyjm9ew", + "symbol": "BLINK-9C6", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "Binance Chain Native Token", + "original_symbol": "BNB", + "owner": "bnb1ultyhpw2p2ktvr68swz56570lgj2rdsadq3ym2", + "symbol": "BNB", + "total_supply": "176406560.90000000" + }, + { + "mintable": false, + "name": "BOLT Token", + "original_symbol": "BOLT", + "owner": "bnb177ujwmshxu8r9za4vy9ztqn65tmr54ddw958rt", + "symbol": "BOLT-4C6", + "total_supply": "980230000.00000000" + }, + { + "mintable": false, + "name": "Bitcloud Pro", + "original_symbol": "BPRO", + "owner": "bnb1482svhhrffpga5wmqw8068af4c9u2q9dp3hg4m", + "symbol": "BPRO-5A6", + "total_supply": "5000000000.00000000" + }, + { + "mintable": true, + "name": "BQTX", + "original_symbol": "BQTX", + "owner": "bnb1j42h6j40htujnjmtp4ckw4zx27vp0f93cvmua8", + "symbol": "BQTX-235", + "total_supply": "1000000.00000000" + }, + { + "mintable": false, + "name": "BOOSTO", + "original_symbol": "BST2", + "owner": "bnb19k2av7cmdvp9f0qkeu5vfl59yp8ftqv2s55dzs", + "symbol": "BST2-2F2", + "total_supply": "500000000.00000000" + }, + { + "mintable": true, + "name": "Bitcoin BEP2", + "original_symbol": "BTCB", + "owner": "bnb1akey87kt0r8y3fmhu2l8eyzdjvt9ptl5cppz0v", + "symbol": "BTCB-1DE", + "total_supply": "9001.00000000" + }, + { + "mintable": true, + "name": "BTTB", + "original_symbol": "BTTB", + "owner": "bnb1srm577fgsjg363vsqt8td4tat5arzfvkjchqgq", + "symbol": "BTTB-D31", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "3x Long Bitcoin Token", + "original_symbol": "BULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "BULL-BE4", + "total_supply": "604.80000000" + }, + { + "mintable": true, + "name": "Binance USD", + "original_symbol": "BUSD", + "owner": "bnb19v2ayq6k6e5x6ny3jdutdm6kpqn3n6mxheegvj", + "symbol": "BUSD-BD1", + "total_supply": "26000000.00000000" + }, + { + "mintable": false, + "name": "Bezant Token", + "original_symbol": "BZNT", + "owner": "bnb1w5a5jywe3cu20uq6n6x3vmzcq342s6st4cz73s", + "symbol": "BZNT-464", + "total_supply": "964511442.00000000" + }, + { + "mintable": false, + "name": "CanYaCoin", + "original_symbol": "CAN", + "owner": "bnb16w59lfh4y2cqvu8f7yr000ll37ldh4w6hnz7l0", + "symbol": "CAN-677", + "total_supply": "95827000.00000000" + }, + { + "mintable": false, + "name": "CASHAA", + "original_symbol": "CAS", + "owner": "bnb1xkw2sagpx6t0cmwzapxpv94tupvqk7tpgy72ku", + "symbol": "CAS-167", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "Cubiex", + "original_symbol": "CBIX", + "owner": "bnb1jlm66w38gpfuqr4s2jcfwlcrlx46p05thdnv7g", + "symbol": "CBIX-3C9", + "total_supply": "150000000.00000000" + }, + { + "mintable": false, + "name": "CryptoBonusMiles", + "original_symbol": "CBM", + "owner": "bnb1dq8ae0ayztqp99peggq5sygzf3n7u2ze4t0jne", + "symbol": "CBM-4B2", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "Clipper Coin", + "original_symbol": "CCCX", + "owner": "bnb1ry99rte8gfnn9c6at9mlmrrq6p2k4u7732j9h7", + "symbol": "CCCX-10D", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "Chiliz", + "original_symbol": "CHZ", + "owner": "bnb1cghr4z8ag440tv4wnk3l6wzynytlpvfqltm9ph", + "symbol": "CHZ-ECD", + "total_supply": "8888888888.00000000" + }, + { + "mintable": false, + "name": "Crypto Neo-value Neural System", + "original_symbol": "CNNS", + "owner": "bnb193wdp4gdnm58urnsjf8nv57lxt58sckt2k50ss", + "symbol": "CNNS-E16", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Contentos", + "original_symbol": "COS", + "owner": "bnb1u9j9hkst6gf09dkdvxlj7puk8c7vh68a0kkmht", + "symbol": "COS-2E4", + "total_supply": "9400000000.00000000" + }, + { + "mintable": true, + "name": "COTI", + "original_symbol": "COTI", + "owner": "bnb1kn733gkku9xsqkuk6wcz86gftqtl4qvthvrj5m", + "symbol": "COTI-CBB", + "total_supply": "80000000.00000000" + }, + { + "mintable": false, + "name": "Covalent Token", + "original_symbol": "COVA", + "owner": "bnb1pucvxaf3l9rslupza75r9fca9h5892ntumszfm", + "symbol": "COVA-218", + "total_supply": "6500000000.00000000" + }, + { + "mintable": false, + "name": "CPChain", + "original_symbol": "CPC", + "owner": "bnb1wq4rlwrmvvltlarvypql8wrr4vlh0dczd8uksg", + "symbol": "CPC-FED", + "total_supply": "150000000.00000000" + }, + { + "mintable": false, + "name": "Crypterium Token", + "original_symbol": "CRPT", + "owner": "bnb17fk3uvagucxzpvmdvd373fapqsahxvzevdard9", + "symbol": "CRPT-8C9", + "total_supply": "99968575.14285720" + }, + { + "mintable": false, + "name": "“Consentium”", + "original_symbol": "CSM", + "owner": "bnb1gguz7vcrlf7a87et8u5gt40f0890qvkpkn9y79", + "symbol": "CSM-734", + "total_supply": "84000000.00000000" + }, + { + "mintable": true, + "name": "Carbon Dollar", + "original_symbol": "CUSD", + "owner": "bnb1y9797dtklkm3haajsfnevm9ruuxs5fyf5rpj67", + "symbol": "CUSD-24B", + "total_supply": "9999999999.00000000" + }, + { + "mintable": false, + "name": "Konstellation Network", + "original_symbol": "DARC", + "owner": "bnb1gyhnhdns4vf63nfzfq7g25czj8swjgrz3rhah8", + "symbol": "DARC-24B", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "DeepCloud", + "original_symbol": "DEEP", + "owner": "bnb1t0ws9gvnjm7j7qssk8te7m2dt5hmm8s3amqk2d", + "symbol": "DEEP-9D3", + "total_supply": "200000000.00000000" + }, + { + "mintable": false, + "name": "DeFi Token", + "original_symbol": "DEFI", + "owner": "bnb1q5xefr07503pqtfrl5sfyyhlghxwc80d4vpas2", + "symbol": "DEFI-FA5", + "total_supply": "2500000000.00000000" + }, + { + "mintable": true, + "name": "DOS Network Token", + "original_symbol": "DOS", + "owner": "bnb13gse9n7mvrjg5w2cymnt4nmxkgj200k9k2l2nh", + "symbol": "DOS-120", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "DREP", + "original_symbol": "DREP", + "owner": "bnb1ez5s9v4rcgsmhwr4fkrnlv6zwsukjnh4y754kn", + "symbol": "DREP-7D2", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Dusk Network", + "original_symbol": "DUSK", + "owner": "bnb1dfls6c8y39l7qq4gj2479wkehg85pt5m07y94g", + "symbol": "DUSK-45E", + "total_supply": "50000000.00000000" + }, + { + "mintable": false, + "name": "eBoost", + "original_symbol": "EBST", + "owner": "bnb1pmdkvw6cquwylr46wcrl82xzmul0y2jpj5cwx7", + "symbol": "EBST-783", + "total_supply": "80838159.07000000" + }, + { + "mintable": true, + "name": "Ormeus Ecosystem", + "original_symbol": "ECO", + "owner": "bnb1tr49nv08k828n2lqfw0vrgvwj7xtep5kg8wr4c", + "symbol": "ECO-083", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "Energy Eco Token", + "original_symbol": "EET", + "owner": "bnb1pt353m8ygvvgy4f2ud9xx85tl7fqewkrksh6r5", + "symbol": "EET-45C", + "total_supply": "600000000.00000000" + }, + { + "mintable": false, + "name": "Hut34 Entropy", + "original_symbol": "ENTRP", + "owner": "bnb1wu0hu9pelx3yvplysx0je7d93htcandpj86aev", + "symbol": "ENTRP-C8D", + "total_supply": "100000000.00000000" + }, + { + "mintable": true, + "name": "EOS BEP2", + "original_symbol": "EOS", + "owner": "bnb1la8alalwjzkchd67wza3r75lj5rm7m9e85ffqr", + "symbol": "EOS-CDD", + "total_supply": "500000.00000000" + }, + { + "mintable": true, + "name": "3X Short EOS Token", + "original_symbol": "EOSBEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "EOSBEAR-721", + "total_supply": "32301.00000000" + }, + { + "mintable": true, + "name": "3X Long EOS Token", + "original_symbol": "EOSBULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "EOSBULL-F0D", + "total_supply": "456191.00000000" + }, + { + "mintable": false, + "name": "EQUAL", + "original_symbol": "EQL", + "owner": "bnb1uz0s54rzv022dh66l7atwk83wqcet9qstgg358", + "symbol": "EQL-586", + "total_supply": "675259060.00000000" + }, + { + "mintable": true, + "name": "Elrond", + "original_symbol": "ERD", + "owner": "bnb1m5uzzfxs7x05sl28gg96zyecn9jwgtkpyeftyn", + "symbol": "ERD-D06", + "total_supply": "13000000000.00000000" + }, + { + "mintable": true, + "name": "ETH BEP2", + "original_symbol": "ETH", + "owner": "bnb1yss2345dphss8c823dh2jzje2w8k8x4jguuxhf", + "symbol": "ETH-1C9", + "total_supply": "10000.00000000" + }, + { + "mintable": true, + "name": "3X Short Ethereum Token", + "original_symbol": "ETHBEAR", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "ETHBEAR-B2B", + "total_supply": "61821.00000000" + }, + { + "mintable": true, + "name": "3X Long Ethereum Token", + "original_symbol": "ETHBULL", + "owner": "bnb1ff4r0t7j8ll8lf3gm2ltdu3hjy4w690j7vvees", + "symbol": "ETHBULL-D33", + "total_supply": "33684.00000000" + }, + { + "mintable": true, + "name": "everiToken", + "original_symbol": "EVT", + "owner": "bnb1v3fl4kuwuhzf3g7ghscsq7uzmu5dw50waseptd", + "symbol": "EVT-49B", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "The Force Token", + "original_symbol": "FOR", + "owner": "bnb1c46nhwdwm3u2mlfhx6t07fls25shnvktpr9w9m", + "symbol": "FOR-997", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "Ferrum Network Token", + "original_symbol": "FRM", + "owner": "bnb1um8ntkgwle8yrdk0yn5hwdf7hckjpyjjg29k2p", + "symbol": "FRM-DE7", + "total_supply": "164609374.50000000" + }, + { + "mintable": false, + "name": "Fusion", + "original_symbol": "FSN", + "owner": "bnb17mnutyduat9fe02r2dawp3kn4rnaqamp5kpg0c", + "symbol": "FSN-E14", + "total_supply": "57344000.00000000" + }, + { + "mintable": true, + "name": "Fantom", + "original_symbol": "FTM", + "owner": "bnb1f6sxnf3nhn9fcfwkuccrzvl2pgu3sq0m8pyjhw", + "symbol": "FTM-A64", + "total_supply": "952500000.00000000" + }, + { + "mintable": true, + "name": "FTX Token", + "original_symbol": "FTT", + "owner": "bnb1msxdh7e7smpg68gxxhs0p3fhuj9tzhrxa4c2x2", + "symbol": "FTT-F11", + "total_supply": "10000000.00000000" + }, + { + "mintable": true, + "name": "Givly Coin", + "original_symbol": "GIV", + "owner": "bnb13jzr6sqz72fl0edg2tpqp8tddyzvyt4su2490m", + "symbol": "GIV-94E", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "GoWithMi", + "original_symbol": "GMAT", + "owner": "bnb1yltla9mnk8999ygmjjn3kwmmz2zs94a9v20sca", + "symbol": "GMAT-FC8", + "total_supply": "14900000000.00000000" + }, + { + "mintable": false, + "name": "Global Gaming", + "original_symbol": "GMNG", + "owner": "bnb1qe6zxqptfxw0kh38t8pg6c3qa527n2x2a87qvm", + "symbol": "GMNG-F3E", + "total_supply": "5000000000.00000000" + }, + { + "mintable": false, + "name": "GTEX", + "original_symbol": "GTEX", + "owner": "bnb1nksrzfl24he9xtvdvpypsl6r5jnh5x2uf9s82z", + "symbol": "GTEX-71B", + "total_supply": "4000000000.00000000" + }, + { + "mintable": false, + "name": "Gifto", + "original_symbol": "GTO", + "owner": "bnb1lvp8k3zenlfp2pl2nyaf428xjgh385m258gzvq", + "symbol": "GTO-908", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "“Hermes", + "original_symbol": "HEC", + "owner": "bnb1dfyydqkmsv5m0rs0pa4uut2gwrcsahppktns2t", + "symbol": "HEC-1A9", + "total_supply": "100000000.00000000" + }, + { + "mintable": false, + "name": "Honest", + "original_symbol": "HNST", + "owner": "bnb1k9fv2hz0w3l9v9z4g9samg3gtc7nc2xgyqw5u0", + "symbol": "HNST-3C9", + "total_supply": "400000000.00000000" + }, + { + "mintable": true, + "name": "Hyperion Token", + "original_symbol": "HYN", + "owner": "bnb1q5cqecuy2g7syl8fssp9a7v2sjamtrzlr3pa0n", + "symbol": "HYN-F21", + "total_supply": "10000000000.00000000" + }, + { + "mintable": true, + "name": "Rupiah Token", + "original_symbol": "IDRTB", + "owner": "bnb1wc44duax6pygh23psx0u945skvs3eh7w59e4sp", + "symbol": "IDRTB-178", + "total_supply": "90000000000.00000000" + }, + { + "mintable": false, + "name": "IKU", + "original_symbol": "IKU", + "owner": "bnb1f52tc9l0qg337qtgu4n024ayllc78wxpc5xhvd", + "symbol": "IKU-416", + "total_supply": "300000000.00000000" + }, + { + "mintable": true, + "name": "IRIS Network", + "original_symbol": "IRIS", + "owner": "bnb1dcpm0jjj8el8g6ekr3mvjxa8kptgu4e5xzvqv8", + "symbol": "IRIS-D88", + "total_supply": "2000000000.00000000" + }, + { + "mintable": false, + "name": "JDXUCoin", + "original_symbol": "JDXU", + "owner": "bnb1dwcsg0t86g7935zpxc054n97styzgdtnu2kzg6", + "symbol": "JDXU-706", + "total_supply": "1000000000.00000000" + }, + { + "mintable": false, + "name": "Kambria Token", + "original_symbol": "KAT", + "owner": "bnb1l68n6equtr925lhnentyq54zfrzqyj45lg8uwj", + "symbol": "KAT-7BB", + "total_supply": "3700000000.00000000" + }, + { + "mintable": true, + "name": "Kava BEP2 Token", + "original_symbol": "KAVA", + "owner": "bnb1uyekdn62yur9zuctzqyd9ckasfvqttjz9c33me", + "symbol": "KAVA-10C", + "total_supply": "271190.72181900" + }, + { + "mintable": false, + "name": "Sessia Kicks", + "original_symbol": "KICKS", + "owner": "bnb130tmwjd3fc79eh6f5ezl2326ur8rqpsxeeq30x", + "symbol": "KICKS-162", + "total_supply": "5000000.00000000" + }, + { + "mintable": true, + "name": "Lambda", + "original_symbol": "LAMB", + "owner": "bnb19vnwdjwthm9unxe9hxdxmgm6qw0d42d2lmcesw", + "symbol": "LAMB-46C", + "total_supply": "5000000.00000000" + }, + { + "mintable": false, + "name": "Lend-Borrow-Asset", + "original_symbol": "LBA", + "owner": "bnb1m8r74hr532lfwtaf5e88cxeakd36ut0ufpd4yu", + "symbol": "LBA-340", + "total_supply": "1000000000.00000000" + }, + { + "mintable": true, + "name": "LITION", + "original_symbol": "LIT", + "owner": "bnb1fhlxwqlwd7cm5fmurg0wmsaalshnp7lwu46nk9", + "symbol": "LIT-099", + "total_supply": "145061313.45061312" + }, + { + "mintable": true, + "name": "Loki", + "original_symbol": "LOKI", + "owner": "bnb1j5sft8wp7tktjwauy30x79f3tqa53fycmgxxs0", + "symbol": "LOKI-6A9", + "total_supply": "3000000.00000000" + }, + { + "mintable": true, + "name": "LTC BEP2", + "original_symbol": "LTC", + "owner": "bnb1cn4sqm79wqmr8rey923r34cp2wrtyhlr9easpg", + "symbol": "LTC-F07", + "total_supply": "18500.00000000" + }, + { + "mintable": false, + "name": "LTO Network", + "original_symbol": "LTO", + "owner": "bnb1ac6p45m00pv36y9mu48e5xr73fyxke3zv2rhmq", + "symbol": "LTO-BDF", + "total_supply": "500000000.00000000" + }, + { + "mintable": false, + "name": "LYFE", + "original_symbol": "LYFE", + "owner": "bnb1k0779dltjkl6a05v5uq06zym62hcufzcqu6gq7", + "symbol": "LYFE-6AB", + "total_supply": "231250000.00000000" + }, + { + "mintable": false, + "name": "Matic Token", + "original_symbol": "MATIC", + "owner": "bnb1a6nkf3g7c2z0jcrqhp8c9upcwmme0y49qx58nz", + "symbol": "MATIC-84A", + "total_supply": "10000000000.00000000" + }, + { + "mintable": false, + "name": "Moviebloc", + "original_symbol": "MBL", + "owner": "bnb17p8rc0z5vlysff2wc7xehff464dm0v7nhl27xq", + "symbol": "MBL-2D2", + "total_supply": "30000000000.00000000" + }, + { + "mintable": true, + "name": "Mcashchain", + "original_symbol": "MCASH", + "owner": "bnb1q420q7qpyv7tghfp6aac7vnjq74dhkeutdhqsg", + "symbol": "MCASH-869", + "total_supply": "200000000.00000000" + }, + { + "mintable": false, + "name": "Magic Cube Token", + "original_symbol": "MCC", + "owner": "bnb14nt79d6hzhjefkys2cgrc9nrzugdjwwtggfmu4", + "symbol": "MCC-33B", + "total_supply": "20000000000.00000000" + }, + { + "mintable": false, + "name": "MDAB", + "original_symbol": "MDAB", + "owner": "bnb1m3edd4q4nd3wxg9vm3xe8pnfnetu5yjmhtnrqz", + "symbol": "MDAB-D42", + "total_supply": "1000000000.00000000" + } +] diff --git a/platform/binance/mocks/txs.json b/platform/binance/mocks/txs.json new file mode 100644 index 000000000..7491ddcab --- /dev/null +++ b/platform/binance/mocks/txs.json @@ -0,0 +1,352 @@ +[ + { + "id": "771B07C8D921B5995524C163E9D4504C31A9E07EC858263A53EA007484009C90", + "coin": 714, + "from": "bnb1d83u9afqw296ejw9jdfhc22f0ljr23nn7pradx", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596826106, + "block": 105722032, + "status": "completed", + "sequence": 33, + "type": "transfer", + "memo": "106890151", + "metadata": { "value": "120740436", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "1C5682716D2D34DD01428AD8D4200081FBDA06CE886B77499F755E9D93B0FF20", + "coin": 714, + "from": "bnb1k9ktd79psysucucyxqcd5r9ahuuygk8gh3ly8q", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596826069, + "block": 105721942, + "status": "completed", + "sequence": 64, + "type": "transfer", + "memo": "103215089", + "metadata": { "value": "229350524", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "C728F7C13977649FCDF9B8E983A9E3AA257EB5596DBCA2A2580584312B5AA535", + "coin": 714, + "from": "bnb155svs6sgxe55rnvs6ghprtqu0mh69kehphsppd", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596826063, + "block": 105721925, + "status": "completed", + "sequence": 23121, + "type": "transfer", + "memo": "101045880", + "metadata": { "value": "11964120000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "794302F9C6562358581A3A8432AF82CD70DF0DA345C917BDE21DDF9A9D4B9DE7", + "coin": 714, + "from": "bnb14gk6m77tswyks9nnadm92mdy3066wj42t60z0l", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596826058, + "block": 105721913, + "status": "completed", + "sequence": 11228, + "type": "transfer", + "memo": "100341541", + "metadata": { "value": "456000000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "2827377A04E3B22DD654A02AD4BA50B3CB83973B6B9BA1A423ABD5045873850C", + "coin": 714, + "from": "bnb132gvg9gdthtaf6xgkk9jkmsep56fv62vg95unv", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596826024, + "block": 105721828, + "status": "completed", + "sequence": 4, + "type": "transfer", + "memo": "105772095", + "metadata": { "value": "1045498916", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "AACC80FDA9C45DCD7F6DBAA40A2EB600FF6EBB24A5A840578D4AB306C3427385", + "coin": 714, + "from": "bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596826006, + "block": 105721785, + "status": "completed", + "sequence": 65, + "type": "transfer", + "memo": "109027392", + "metadata": { "value": "8750000000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "66CF0F65442FD35A3B91CC2655CE60E565D13EEFC6BDB1C5AF9F9E484C8B6295", + "coin": 714, + "from": "bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825967, + "block": 105721686, + "status": "completed", + "sequence": 896, + "type": "transfer", + "memo": "107780643", + "metadata": { "value": "878900000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "81EA185BE754809E40FCBF1B07A0C389F39DECD38D56302D980534850996B144", + "coin": 714, + "from": "bnb12nq7fhh3t8q0m9s2n5gqwd9gcx0j85yn0h5zcu", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825888, + "block": 105721490, + "status": "completed", + "sequence": 0, + "type": "transfer", + "memo": "101210049", + "metadata": { "value": "4498159221", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "24ED2153427ABACD7F6DB53A1339D9C2573D720FDE6EC45B0047CB146227FF9A", + "coin": 714, + "from": "bnb1s5qucugaxv7gkzyg4kacf225s6mhj0ysejn8jq", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825847, + "block": 105721385, + "status": "completed", + "sequence": 40, + "type": "transfer", + "memo": "104298046", + "metadata": { "value": "34300000000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "411A27CE85D0928BC5908DA5BA288CB52E152C1E54FA35042147A90FCEBAB29C", + "coin": 714, + "from": "bnb1erj09eqrnz06jv2acxhhy7s3k0q6w4hfmj9rey", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825789, + "block": 105721238, + "status": "completed", + "sequence": 12, + "type": "transfer", + "memo": "107303874", + "metadata": { "value": "6319074", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "25359F7277760004BBD42557B3E50F86F06B096478840E057C6F394BF63F6081", + "coin": 714, + "from": "bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825692, + "block": 105720997, + "status": "completed", + "sequence": 57, + "type": "transfer", + "memo": "109027392", + "metadata": { "value": "1090000000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "1DB710AF4983D9CAFB24AC3DD7C2C6EBC7752F347E5A7599840AB3EFBD436C5D", + "coin": 714, + "from": "bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825639, + "block": 105720867, + "status": "completed", + "sequence": 56, + "type": "transfer", + "memo": "109027392", + "metadata": { "value": "2000000000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "B7C799B9853ECA41F02241B67E294E2642AE88BBF551DE188A73C48D1A0E821D", + "coin": 714, + "from": "bnb1q2994t0djzsy0q2fc62jruxr22nxq6y8l4503l", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825619, + "block": 105720816, + "status": "completed", + "sequence": 1, + "type": "transfer", + "memo": "108202494", + "metadata": { "value": "295957149", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "865C098D021CC649FC83B2442092E4D6F0777488163E5797DA9D264C87F1F4F4", + "coin": 714, + "from": "bnb16xqcchlutsm8g6gk7wvlzukeu2sy9xt2u77056", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825548, + "block": 105720641, + "status": "completed", + "sequence": 33, + "type": "transfer", + "memo": "102080722", + "metadata": { "value": "1373501799", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "1D4F777D1D227D57E4D4BAC3E83FB203147E7B0E7429E60A48A9053372359174", + "coin": 714, + "from": "bnb1t6tk66zncqqt7twnfyxx22fn9t3wz3nac5hkck", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825500, + "block": 105720519, + "status": "completed", + "sequence": 14, + "type": "transfer", + "memo": "106456805", + "metadata": { "value": "1490609", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "9A818687D52B4E9E0C5F962E6E464ECC6348D6A41AE2C5DD051A5EF71E15B1AC", + "coin": 714, + "from": "bnb1v47qw5acc72c34uwt7t9wm9ztqtg6678dmrssa", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825415, + "block": 105720307, + "status": "completed", + "sequence": 6273, + "type": "transfer", + "memo": "104471384", + "metadata": { "value": "356700000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "6C7D4469525E44501ED03BA38A6D54A04DFD6AD2D13328761DA4602A3D777332", + "coin": 714, + "from": "bnb1tzet704pc6zjsl3xcwdexn6xlu0zc092y0n4ay", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825348, + "block": 105720136, + "status": "completed", + "sequence": 721, + "type": "transfer", + "memo": "101245732", + "metadata": { "value": "93900000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "8C47875F09371B45C0A29D7C6EF308A1C499D1BBECD5A56E0561B40675AF2D26", + "coin": 714, + "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825311, + "block": 105720042, + "status": "completed", + "sequence": 1912, + "type": "transfer", + "memo": "101186586", + "metadata": { "value": "95193451", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "39A48766F8ACC33B3BB1B4F442ABFDFBC695F440D72795794A01E8E446CE8EAE", + "coin": 714, + "from": "bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825298, + "block": 105720010, + "status": "completed", + "sequence": 47, + "type": "transfer", + "memo": "109027392", + "metadata": { "value": "480000000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "54248E3C09713E3870F661749A8690DAD46A8078C7346C497EB4E166564420F4", + "coin": 714, + "from": "bnb1hc304lytvp9jnumnjmppq97erm70r7muzv6y98", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825237, + "block": 105719860, + "status": "completed", + "sequence": 1, + "type": "transfer", + "memo": "105261446", + "metadata": { "value": "10210962500", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "ADDDB705AB8C2B1AF58D7EDCAEC00C893A6CD87281D7A7146689E9FE1A846EAE", + "coin": 714, + "from": "bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825173, + "block": 105719705, + "status": "completed", + "sequence": 895, + "type": "transfer", + "memo": "103617121", + "metadata": { "value": "297900000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "7C338C78BBBCD998628CCAF85211883AACB159201755501139F56E0D2A7941A4", + "coin": 714, + "from": "bnb1pys084nlc8gqm7lvjje4kt39dn84vd2xsvnwqa", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825147, + "block": 105719641, + "status": "completed", + "sequence": 18, + "type": "transfer", + "memo": "108802310", + "metadata": { "value": "200000000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "6DD7120E43CD5031E2DD6C7977D141B74CA41C8E476D8AE972A9DA2D2EFD2D84", + "coin": 714, + "from": "bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825061, + "block": 105719428, + "status": "completed", + "sequence": 894, + "type": "transfer", + "memo": "102393444", + "metadata": { "value": "677900000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "86FB14C637D7B0A4AA123FFF76C5C541C70568B67E3F5BC63EB0FDEDEF30301F", + "coin": 714, + "from": "bnb17nak8gnucl6lcze0d04def4de77a33qh29f6ur", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825051, + "block": 105719403, + "status": "completed", + "sequence": 3, + "type": "transfer", + "memo": "109823910", + "metadata": { "value": "900000", "symbol": "BNB", "decimals": 8 } + }, + { + "id": "1DEEFC0A838F80704574951DF15969CCE34654BE2007BF77F9521A1B4686BE33", + "coin": 714, + "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "fee": "37500", + "date": 1596825014, + "block": 105719312, + "status": "completed", + "sequence": 1431, + "type": "transfer", + "memo": "103268674", + "metadata": { "value": "315739000", "symbol": "BNB", "decimals": 8 } + } +] diff --git a/platform/binance/mocks/txs_ava_response.json b/platform/binance/mocks/txs_ava_response.json new file mode 100644 index 000000000..92fc48811 --- /dev/null +++ b/platform/binance/mocks/txs_ava_response.json @@ -0,0 +1,505 @@ +{ + "tx": [ + { + "txHash": "2BF49DF1D10D9A20438376E760352734DAEBD5D92D6CAA14735EE095A3F65FD3", + "blockHeight": 105725696, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:13:41.390Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "47.98467000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 5, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594674", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77721\",\"quantity\":\"27\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594674\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594673 + }, + { + "txHash": "C858D15E2745A61D0D3D354750E4462792160FFBB9927739587FFAAEDEFA00FF", + "blockHeight": 105725676, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:13:32.989Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "250.85976000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 13, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594671", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.91496\",\"quantity\":\"131\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594671\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594670 + }, + { + "txHash": "9BDCF416622AA4E8F11162747614585FD840F5721D7163A68BC03EC94E855DEE", + "blockHeight": 105725673, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:13:31.760Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "30.17126000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 14, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594670", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77478\",\"quantity\":\"17\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594670\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594669 + }, + { + "txHash": "52512D9498D4CF51997A5A62C0A55252776B00C888D2D01502C68B56E892F42E", + "blockHeight": 105725652, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:13:23.040Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "41.48298000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 23, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594667", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.88559\",\"quantity\":\"22\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594667\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594666 + }, + { + "txHash": "1BAF96AB01E7AB5A7746CA7E76B293CD636D55713C7CCE71FD0E0ED8ACE05C92", + "blockHeight": 105725646, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:13:20.614Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "26.59905000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 26, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594666", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77327\",\"quantity\":\"15\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594666\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594665 + }, + { + "txHash": "9990419EFE1B327966EBAAFFC2771046E1AC2E4DDFAD8A93C55DE105A2948A8D", + "blockHeight": 105725624, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:13:11.499Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "206.81568000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 35, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594663", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.91496\",\"quantity\":\"108\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594663\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594662 + }, + { + "txHash": "922F86E110E897233A7B43C0D31397923298C176EBE6F33D98B70ACB911A497A", + "blockHeight": 105725620, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:13:09.679Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "31.95630000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 36, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594662", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77535\",\"quantity\":\"18\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594662\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594661 + }, + { + "txHash": "925A208AFDCD718F8383F7559C7BBA5AE616B693A6029F57BFB67AEBB1CE5F3C", + "blockHeight": 105725597, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:13:00.237Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "135.99044000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 46, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594659", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65842\",\"quantity\":\"82\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594659\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594658 + }, + { + "txHash": "2B69327D6C0C7B9061AAD962BF4838E3B630A844439013E0EBEFC5B722205774", + "blockHeight": 105725575, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:12:51.165Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "26.39040000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 55, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594656", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.75936\",\"quantity\":\"15\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594656\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594655 + }, + { + "txHash": "BB6FD86C9738C2991F587996ABBAC1151DF1F9DE57FDCC977BB0D8FBAD31188A", + "blockHeight": 105725529, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:12:32.108Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "44.90475000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 74, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594654", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79619\",\"quantity\":\"25\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594654\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594653 + }, + { + "txHash": "97856635BDBA4B0B3EAAA76EA46D848A2DFE3AAE554A33D308CFC4474C769290", + "blockHeight": 105725526, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:12:30.917Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "94.10225000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 75, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594653", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.71095\",\"quantity\":\"55\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594653\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594652 + }, + { + "txHash": "4B4EC65A5972CC15C4B410339ED0081C4BB57F4E08F2A35744845F5A71531B59", + "blockHeight": 105725493, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:12:17.373Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "30.49341000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 89, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594649", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79373\",\"quantity\":\"17\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594649\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594648 + }, + { + "txHash": "86B5FFDDB06E0973A05434DDB858868A45EDA8B07E0D75125FEAEBA1093D4EA5", + "blockHeight": 105725489, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:12:15.680Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "195.81982000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 90, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594648", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"118\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594648\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594647 + }, + { + "txHash": "D20757EB130E8146D1A12E869BE69EC2CB03193D8E62467327B09A5D73BBC6F8", + "blockHeight": 105725473, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:12:09.086Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "59.27427000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 97, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594646", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79619\",\"quantity\":\"33\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594646\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594645 + }, + { + "txHash": "04291A7AE08A78C5E5AE216C67D17B6A4260950FFAB6FD3D1C1B991E3B7BB935", + "blockHeight": 105725470, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:12:07.990Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "242.28554000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 98, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594645", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"146\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594645\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594644 + }, + { + "txHash": "31E16E3F53DD476475256C8D872AF3FD86DC44F3085EF87DDE3643E20C0CE624", + "blockHeight": 105725448, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:11:58.857Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "32.30208000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 107, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594642", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79456\",\"quantity\":\"18\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594642\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594641 + }, + { + "txHash": "1D61A9E35893BB51DE4AE63FA6898FCAE14B6D48F7A2EFD0B51DCCACF6E36B88", + "blockHeight": 105725446, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:11:57.974Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "227.35013000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 108, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594641", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"137\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594641\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594640 + }, + { + "txHash": "AB9E29B110844BD76F58B058CC20F1E13B37A1AAC4F09978BDE159F1B09B585E", + "blockHeight": 105725425, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:11:49.358Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "26.88420000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 117, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594638", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.79228\",\"quantity\":\"15\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594638\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594637 + }, + { + "txHash": "F81649BAF3D888E3772C8708D255FE91E0CDB2818006A1FC96FFBDAC24BDE675", + "blockHeight": 105725422, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:11:48.006Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "144.37563000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 118, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594637", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.65949\",\"quantity\":\"87\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594637\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594636 + }, + { + "txHash": "71B25BF61219BC87980EB67064C346801C01B00FFE52932799E28FB20DAF41D8", + "blockHeight": 105725401, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:11:39.380Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "21.47556000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 127, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594634", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.78963\",\"quantity\":\"12\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594634\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594633 + }, + { + "txHash": "3424BFCA860A878FDCF304AD414EDE2AB3B0FF258CA940CD1269F469ED7C422C", + "blockHeight": 105725379, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:11:30.336Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "144.92516000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 136, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594631", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.90691\",\"quantity\":\"76\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594631\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594630 + }, + { + "txHash": "46FFA039B955953D4F19BE7D56FA793B71F34BFB460D9B84A152B554E9219C44", + "blockHeight": 105725375, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:11:28.671Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "231.90204000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 137, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594630", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.66836\",\"quantity\":\"139\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594630\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594629 + }, + { + "txHash": "701100D3783744D633FF34A6E211CEB923EA9BCE6D87A64211801E71F71AEE03", + "blockHeight": 105725327, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:11:09.184Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "92.81678000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 157, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594628", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.89422\",\"quantity\":\"49\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594628\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594627 + }, + { + "txHash": "B12B30509B45CEFE526DAADDAC6399F902B30418859042D7A23F9A2FB311A6C8", + "blockHeight": 105725323, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:11:07.404Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "47.87208000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 159, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594627", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"BUY\",\"price\":\"1.77304\",\"quantity\":\"27\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594627\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594626 + }, + { + "txHash": "933819F35F0F89FB2D58DC50CD15FABB3DA0B817BFCD39A8DDC99DFEC1663F7D", + "blockHeight": 105725301, + "txType": "NEW_ORDER", + "timeStamp": "2020-08-07T19:10:58.404Z", + "fromAddr": "bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", + "toAddr": null, + "value": "181.49465000", + "txAsset": "AVA-645", + "txFee": "0.00000000", + "proposalId": null, + "txAge": 168, + "orderId": "7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594624", + "code": 0, + "data": "{\"orderData\":{\"symbol\":\"AVA-645_BUSD-BD1\",\"orderType\":\"LIMIT\",\"side\":\"SELL\",\"price\":\"1.91047\",\"quantity\":\"95\",\"timeInForce\":\"GTE\",\"orderId\":\"7783C148DC7D2CBC504C0CC569B57A593FE53E70-1594624\"}}", + "confirmBlocks": 0, + "memo": "", + "source": 0, + "sequence": 1594623 + } + ], + "total": 11603 +} diff --git a/platform/binance/mocks/txs_response.json b/platform/binance/mocks/txs_response.json new file mode 100644 index 000000000..9ed842e27 --- /dev/null +++ b/platform/binance/mocks/txs_response.json @@ -0,0 +1,505 @@ +{ + "tx": [ + { + "txHash": "771B07C8D921B5995524C163E9D4504C31A9E07EC858263A53EA007484009C90", + "blockHeight": 105722032, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:48:26.284Z", + "fromAddr": "bnb1d83u9afqw296ejw9jdfhc22f0ljr23nn7pradx", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "1.20740436", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 104, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "106890151", + "source": 1, + "sequence": 33 + }, + { + "txHash": "1C5682716D2D34DD01428AD8D4200081FBDA06CE886B77499F755E9D93B0FF20", + "blockHeight": 105721942, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:47:49.895Z", + "fromAddr": "bnb1k9ktd79psysucucyxqcd5r9ahuuygk8gh3ly8q", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "2.29350524", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 140, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "103215089", + "source": 2, + "sequence": 64 + }, + { + "txHash": "C728F7C13977649FCDF9B8E983A9E3AA257EB5596DBCA2A2580584312B5AA535", + "blockHeight": 105721925, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:47:43.111Z", + "fromAddr": "bnb155svs6sgxe55rnvs6ghprtqu0mh69kehphsppd", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "119.64120000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 147, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "101045880", + "source": 1, + "sequence": 23121 + }, + { + "txHash": "794302F9C6562358581A3A8432AF82CD70DF0DA345C917BDE21DDF9A9D4B9DE7", + "blockHeight": 105721913, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:47:38.279Z", + "fromAddr": "bnb14gk6m77tswyks9nnadm92mdy3066wj42t60z0l", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "4.56000000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 152, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "100341541", + "source": 1, + "sequence": 11228 + }, + { + "txHash": "2827377A04E3B22DD654A02AD4BA50B3CB83973B6B9BA1A423ABD5045873850C", + "blockHeight": 105721828, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:47:04.205Z", + "fromAddr": "bnb132gvg9gdthtaf6xgkk9jkmsep56fv62vg95unv", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "10.45498916", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 186, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "105772095", + "source": 2, + "sequence": 4 + }, + { + "txHash": "AACC80FDA9C45DCD7F6DBAA40A2EB600FF6EBB24A5A840578D4AB306C3427385", + "blockHeight": 105721785, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:46:46.832Z", + "fromAddr": "bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "87.50000000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 203, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "109027392", + "source": 1, + "sequence": 65 + }, + { + "txHash": "66CF0F65442FD35A3B91CC2655CE60E565D13EEFC6BDB1C5AF9F9E484C8B6295", + "blockHeight": 105721686, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:46:07.122Z", + "fromAddr": "bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "8.78900000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 243, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "107780643", + "source": 0, + "sequence": 896 + }, + { + "txHash": "81EA185BE754809E40FCBF1B07A0C389F39DECD38D56302D980534850996B144", + "blockHeight": 105721490, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:44:48.958Z", + "fromAddr": "bnb12nq7fhh3t8q0m9s2n5gqwd9gcx0j85yn0h5zcu", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "44.98159221", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 321, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "101210049", + "source": 0, + "sequence": 0 + }, + { + "txHash": "24ED2153427ABACD7F6DB53A1339D9C2573D720FDE6EC45B0047CB146227FF9A", + "blockHeight": 105721385, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:44:07.201Z", + "fromAddr": "bnb1s5qucugaxv7gkzyg4kacf225s6mhj0ysejn8jq", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "343.00000000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 363, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "104298046", + "source": 2, + "sequence": 40 + }, + { + "txHash": "411A27CE85D0928BC5908DA5BA288CB52E152C1E54FA35042147A90FCEBAB29C", + "blockHeight": 105721238, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:43:09.084Z", + "fromAddr": "bnb1erj09eqrnz06jv2acxhhy7s3k0q6w4hfmj9rey", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "0.06319074", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 421, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "107303874", + "source": 2, + "sequence": 12 + }, + { + "txHash": "25359F7277760004BBD42557B3E50F86F06B096478840E057C6F394BF63F6081", + "blockHeight": 105720997, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:41:32.193Z", + "fromAddr": "bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "10.90000000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 518, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "109027392", + "source": 1, + "sequence": 57 + }, + { + "txHash": "1DB710AF4983D9CAFB24AC3DD7C2C6EBC7752F347E5A7599840AB3EFBD436C5D", + "blockHeight": 105720867, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:40:39.623Z", + "fromAddr": "bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "20.00000000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 570, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "109027392", + "source": 1, + "sequence": 56 + }, + { + "txHash": "B7C799B9853ECA41F02241B67E294E2642AE88BBF551DE188A73C48D1A0E821D", + "blockHeight": 105720816, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:40:19.123Z", + "fromAddr": "bnb1q2994t0djzsy0q2fc62jruxr22nxq6y8l4503l", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "2.95957149", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 591, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "108202494", + "source": 0, + "sequence": 1 + }, + { + "txHash": "865C098D021CC649FC83B2442092E4D6F0777488163E5797DA9D264C87F1F4F4", + "blockHeight": 105720641, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:39:08.972Z", + "fromAddr": "bnb16xqcchlutsm8g6gk7wvlzukeu2sy9xt2u77056", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "13.73501799", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 661, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "102080722", + "source": 1, + "sequence": 33 + }, + { + "txHash": "1D4F777D1D227D57E4D4BAC3E83FB203147E7B0E7429E60A48A9053372359174", + "blockHeight": 105720519, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:38:20.149Z", + "fromAddr": "bnb1t6tk66zncqqt7twnfyxx22fn9t3wz3nac5hkck", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "0.01490609", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 710, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "106456805", + "source": 2, + "sequence": 14 + }, + { + "txHash": "9A818687D52B4E9E0C5F962E6E464ECC6348D6A41AE2C5DD051A5EF71E15B1AC", + "blockHeight": 105720307, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:36:55.571Z", + "fromAddr": "bnb1v47qw5acc72c34uwt7t9wm9ztqtg6678dmrssa", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "3.56700000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 794, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "104471384", + "source": 2, + "sequence": 6273 + }, + { + "txHash": "6C7D4469525E44501ED03BA38A6D54A04DFD6AD2D13328761DA4602A3D777332", + "blockHeight": 105720136, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:35:48.142Z", + "fromAddr": "bnb1tzet704pc6zjsl3xcwdexn6xlu0zc092y0n4ay", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "0.93900000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 862, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "101245732", + "source": 0, + "sequence": 721 + }, + { + "txHash": "8C47875F09371B45C0A29D7C6EF308A1C499D1BBECD5A56E0561B40675AF2D26", + "blockHeight": 105720042, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:35:11.247Z", + "fromAddr": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "0.95193451", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 899, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "101186586", + "source": 2, + "sequence": 1912 + }, + { + "txHash": "39A48766F8ACC33B3BB1B4F442ABFDFBC695F440D72795794A01E8E446CE8EAE", + "blockHeight": 105720010, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:34:58.634Z", + "fromAddr": "bnb10y4hu5psc7hztlczrhzgghfjzufnqyfrrml3yn", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "4.80000000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 911, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "109027392", + "source": 1, + "sequence": 47 + }, + { + "txHash": "54248E3C09713E3870F661749A8690DAD46A8078C7346C497EB4E166564420F4", + "blockHeight": 105719860, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:33:57.102Z", + "fromAddr": "bnb1hc304lytvp9jnumnjmppq97erm70r7muzv6y98", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "102.10962500", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 973, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "105261446", + "source": 0, + "sequence": 1 + }, + { + "txHash": "ADDDB705AB8C2B1AF58D7EDCAEC00C893A6CD87281D7A7146689E9FE1A846EAE", + "blockHeight": 105719705, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:32:53.527Z", + "fromAddr": "bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "2.97900000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 1036, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "103617121", + "source": 0, + "sequence": 895 + }, + { + "txHash": "7C338C78BBBCD998628CCAF85211883AACB159201755501139F56E0D2A7941A4", + "blockHeight": 105719641, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:32:27.476Z", + "fromAddr": "bnb1pys084nlc8gqm7lvjje4kt39dn84vd2xsvnwqa", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "2.00000000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 1062, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "108802310", + "source": 0, + "sequence": 18 + }, + { + "txHash": "6DD7120E43CD5031E2DD6C7977D141B74CA41C8E476D8AE972A9DA2D2EFD2D84", + "blockHeight": 105719428, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:31:01.143Z", + "fromAddr": "bnb17g92armmr926kd88umh7u90vglq4ghjtku6ssc", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "6.77900000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 1149, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "102393444", + "source": 0, + "sequence": 894 + }, + { + "txHash": "86FB14C637D7B0A4AA123FFF76C5C541C70568B67E3F5BC63EB0FDEDEF30301F", + "blockHeight": 105719403, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:30:51.089Z", + "fromAddr": "bnb17nak8gnucl6lcze0d04def4de77a33qh29f6ur", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "0.00900000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 1159, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "109823910", + "source": 2, + "sequence": 3 + }, + { + "txHash": "1DEEFC0A838F80704574951DF15969CCE34654BE2007BF77F9521A1B4686BE33", + "blockHeight": 105719312, + "txType": "TRANSFER", + "timeStamp": "2020-08-07T18:30:14.498Z", + "fromAddr": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", + "toAddr": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", + "value": "3.15739000", + "txAsset": "BNB", + "txFee": "0.00037500", + "proposalId": null, + "txAge": 1195, + "orderId": null, + "code": 0, + "data": null, + "confirmBlocks": 0, + "memo": "103268674", + "source": 2, + "sequence": 1431 + } + ], + "total": 1636 +} diff --git a/platform/binance/model_test.go b/platform/binance/model_test.go index 8073699da..a6feecec6 100644 --- a/platform/binance/model_test.go +++ b/platform/binance/model_test.go @@ -23,23 +23,7 @@ func Test_isZeroBalance(t *testing.T) { {"Empty others are not 0", TokenBalance{"", "0.00000001", "0.00000001", "BNB"}, false}, {"Empty others are 0", TokenBalance{"", "0.00000000", "0.00000000", "BNB"}, false}, {"Big", TokenBalance{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999" + - "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "0.00000000", "0.00000000", "BNB"}, false}, + "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "0.00000000", "0.00000000", "BNB"}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/platform/binance/token_test.go b/platform/binance/token_test.go index 7950dbf6c..98d0ce400 100644 --- a/platform/binance/token_test.go +++ b/platform/binance/token_test.go @@ -17,17 +17,17 @@ func TestPlatform_GetTokenListByAddress(t *testing.T) { assert.Nil(t, err) res, err := json.Marshal(tokens) assert.Nil(t, err) - assert.Equal(t, wantedTokens, string(res)) + assert.JSONEq(t, wantedTokens, string(res)) tokens, err = p.GetTokenListByAddress("bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg") assert.Nil(t, err) res, err = json.Marshal(tokens) assert.Nil(t, err) - assert.Equal(t, wantedTokens, string(res)) + assert.JSONEq(t, wantedTokens, string(res)) tokens, err = p.GetTokenListByAddress("bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg") assert.Nil(t, err) res, err = json.Marshal(tokens) assert.Nil(t, err) - assert.Equal(t, wantedTokens, string(res)) + assert.JSONEq(t, wantedTokens, string(res)) } diff --git a/platform/binance/transaction_test.go b/platform/binance/transaction_test.go index 3bafcfbb6..4f7870037 100644 --- a/platform/binance/transaction_test.go +++ b/platform/binance/transaction_test.go @@ -16,7 +16,7 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { assert.Nil(t, err) res, err := json.Marshal(txs) assert.Nil(t, err) - assert.Equal(t, wantedTxs, string(res)) + assert.JSONEq(t, wantedTxs, string(res)) } func TestPlatform_GetTokenTxsByAddress(t *testing.T) { @@ -28,5 +28,4 @@ func TestPlatform_GetTokenTxsByAddress(t *testing.T) { res, err := json.Marshal(txs) assert.Nil(t, err) assert.Len(t, res, 2) - //assert.Equal(t, wantedTxsAva, string(res)) } diff --git a/platform/bitcoin/mocks/incoming_tx.json b/platform/bitcoin/mocks/incoming_tx.json new file mode 100644 index 000000000..06f8258fc --- /dev/null +++ b/platform/bitcoin/mocks/incoming_tx.json @@ -0,0 +1,40 @@ +{ + "txid": "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", + "version": 4, + "vin": [ + { + "txid": "5a3664328ac4e1c0688729573296c2ec69dd9a7cf98d49967b41520be794229b", + "n": 0, + "addresses": ["t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD"], + "isAddress": true, + "value": "387582", + "hex": "483045022100ec29a476dac49578339a92e6c20451aaf3ff6691efaf7d4d3113d07589771ca702203c0c173bdc356300edbd64cdfaa868b97c13ebc403026b283eb5e1fca398db8b012103729cc4211cf70f87c70c3cef90e0ca9b91e99b42364b8c600d5781277647de5f" + } + ], + "vout": [ + { + "value": "200997", + "n": 0, + "spent": true, + "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", + "addresses": ["t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM"], + "isAddress": true + }, + { + "value": "186359", + "n": 1, + "spent": true, + "hex": "76a91484f0258cb7974993e6af928921b7f699c51a309488ac", + "addresses": ["t1VzWtLj9CSAK3QnxA7uuiK6XhJrjGjKoy4"], + "isAddress": true + } + ], + "blockHash": "0000000000a8248c4a14a2dcb74d92855bf9440da9b7b1e6d4baa14ee7e3081c", + "blockHeight": 479017, + "confirmations": 116233, + "blockTime": 1549793065, + "value": "387356", + "valueIn": "387582", + "fees": "226", + "hex": "0400008085202f89019b2294e70b52417b96498df97c9add69ecc2963257298768c0e1c48a3264365a000000006b483045022100ec29a476dac49578339a92e6c20451aaf3ff6691efaf7d4d3113d07589771ca702203c0c173bdc356300edbd64cdfaa868b97c13ebc403026b283eb5e1fca398db8b012103729cc4211cf70f87c70c3cef90e0ca9b91e99b42364b8c600d5781277647de5f000000000225110300000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988acf7d70200000000001976a91484f0258cb7974993e6af928921b7f699c51a309488ac00000000000000000000000000000000000000" +} diff --git a/platform/bitcoin/mocks/outgoing_tx.json b/platform/bitcoin/mocks/outgoing_tx.json new file mode 100644 index 000000000..4a0c75b77 --- /dev/null +++ b/platform/bitcoin/mocks/outgoing_tx.json @@ -0,0 +1,30 @@ +{ + "txid": "df63ddab7d4eed2fb6cb40d4d0519e7e5ac7cf5ad556b2edbd45963ea1a2931c", + "version": 1, + "vin": [ + { + "txid": "bf19be44d7dc3e1e6771801a1d250c7207fa9b09d8df9b0ee1b028b6c153475e", + "sequence": 4294967295, + "n": 0, + "addresses": ["3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC"], + "value": "777200", + "hex": "00483045022100e9d0db3bb20a5828ab9dae7cd8373064ce087cc9c8e3def87034d5c2f6f3abb9022047d7c27b355c6487cff40bfbd45742d26d727f3135b2396d8f1abc371c51870c01473044022016280108af73079a69f378218ad4259f02c4e4b6f52c573729650cb3645bc9180220785973cb4e5c4ec6340dc77dc56cec3fb74ebd7296cf1d14344d4f3e157658bb014cc952410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d4621353ae" + } + ], + "vout": [ + { + "value": "677012", + "n": 0, + "hex": "a91499fa965ad13a9580ed7a64ac24b2ecad30f1209a87", + "addresses": ["3FjBW1KL9L8aYtdKzJ8FhCNxmXB7dXDRw4"] + } + ], + "blockHash": "00000000000000000011b58c01ede5a602eec61ebaf097aaa6e682ef2819536e", + "blockHeight": 585094, + "confirmations": 1997, + "blockTime": 1562945790, + "value": "677012", + "valueIn": "777200", + "fees": "100188", + "hex": "01000000015e4753c1b628b0e10e9bdfd8099bfa07720c251d1a8071671e3edcd744be19bf00000000fd5d0100483045022100e9d0db3bb20a5828ab9dae7cd8373064ce087cc9c8e3def87034d5c2f6f3abb9022047d7c27b355c6487cff40bfbd45742d26d727f3135b2396d8f1abc371c51870c01473044022016280108af73079a69f378218ad4259f02c4e4b6f52c573729650cb3645bc9180220785973cb4e5c4ec6340dc77dc56cec3fb74ebd7296cf1d14344d4f3e157658bb014cc952410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d4621353aeffffffff0194540a000000000017a91499fa965ad13a9580ed7a64ac24b2ecad30f1209a8700000000" +} diff --git a/platform/bitcoin/mocks/pending_tx.json b/platform/bitcoin/mocks/pending_tx.json new file mode 100644 index 000000000..d90c87e77 --- /dev/null +++ b/platform/bitcoin/mocks/pending_tx.json @@ -0,0 +1,40 @@ +{ + "txid": "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", + "version": 4, + "vin": [ + { + "txid": "5a3664328ac4e1c0688729573296c2ec69dd9a7cf98d49967b41520be794229b", + "n": 0, + "addresses": ["t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD"], + "isAddress": true, + "value": "387582", + "hex": "483045022100ec29a476dac49578339a92e6c20451aaf3ff6691efaf7d4d3113d07589771ca702203c0c173bdc356300edbd64cdfaa868b97c13ebc403026b283eb5e1fca398db8b012103729cc4211cf70f87c70c3cef90e0ca9b91e99b42364b8c600d5781277647de5f" + } + ], + "vout": [ + { + "value": "200997", + "n": 0, + "spent": true, + "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", + "addresses": ["t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM"], + "isAddress": true + }, + { + "value": "186359", + "n": 1, + "spent": true, + "hex": "76a91484f0258cb7974993e6af928921b7f699c51a309488ac", + "addresses": ["t1VzWtLj9CSAK3QnxA7uuiK6XhJrjGjKoy4"], + "isAddress": true + } + ], + "blockHash": "0000000000a8248c4a14a2dcb74d92855bf9440da9b7b1e6d4baa14ee7e3081c", + "blockHeight": -1, + "confirmations": 116233, + "blockTime": 1549793065, + "value": "387356", + "valueIn": "387582", + "fees": "226", + "hex": "0400008085202f89019b2294e70b52417b96498df97c9add69ecc2963257298768c0e1c48a3264365a000000006b483045022100ec29a476dac49578339a92e6c20451aaf3ff6691efaf7d4d3113d07589771ca702203c0c173bdc356300edbd64cdfaa868b97c13ebc403026b283eb5e1fca398db8b012103729cc4211cf70f87c70c3cef90e0ca9b91e99b42364b8c600d5781277647de5f000000000225110300000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988acf7d70200000000001976a91484f0258cb7974993e6af928921b7f699c51a309488ac00000000000000000000000000000000000000" +} diff --git a/platform/bitcoin/transaction_test.go b/platform/bitcoin/transaction_test.go index e801b07fc..84b32cfc2 100644 --- a/platform/bitcoin/transaction_test.go +++ b/platform/bitcoin/transaction_test.go @@ -1,7 +1,6 @@ package bitcoin import ( - "bytes" "encoding/json" "reflect" "testing" @@ -12,212 +11,115 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" ) -const outgoingTx = `{ - "txid":"df63ddab7d4eed2fb6cb40d4d0519e7e5ac7cf5ad556b2edbd45963ea1a2931c", - "version":1, - "vin":[ - { - "txid":"bf19be44d7dc3e1e6771801a1d250c7207fa9b09d8df9b0ee1b028b6c153475e", - "sequence":4294967295, - "n":0, - "addresses":[ - "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC" - ], - "value":"777200", - "hex":"00483045022100e9d0db3bb20a5828ab9dae7cd8373064ce087cc9c8e3def87034d5c2f6f3abb9022047d7c27b355c6487cff40bfbd45742d26d727f3135b2396d8f1abc371c51870c01473044022016280108af73079a69f378218ad4259f02c4e4b6f52c573729650cb3645bc9180220785973cb4e5c4ec6340dc77dc56cec3fb74ebd7296cf1d14344d4f3e157658bb014cc952410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d4621353ae"} - ], - "vout":[ - { - "value":"677012", - "n":0, - "hex":"a91499fa965ad13a9580ed7a64ac24b2ecad30f1209a87", - "addresses":["3FjBW1KL9L8aYtdKzJ8FhCNxmXB7dXDRw4"] - } - ], - "blockHash":"00000000000000000011b58c01ede5a602eec61ebaf097aaa6e682ef2819536e", - "blockHeight":585094, - "confirmations":1997, - "blockTime":1562945790, - "value":"677012", - "valueIn":"777200", - "fees":"100188", - "hex":"01000000015e4753c1b628b0e10e9bdfd8099bfa07720c251d1a8071671e3edcd744be19bf00000000fd5d0100483045022100e9d0db3bb20a5828ab9dae7cd8373064ce087cc9c8e3def87034d5c2f6f3abb9022047d7c27b355c6487cff40bfbd45742d26d727f3135b2396d8f1abc371c51870c01473044022016280108af73079a69f378218ad4259f02c4e4b6f52c573729650cb3645bc9180220785973cb4e5c4ec6340dc77dc56cec3fb74ebd7296cf1d14344d4f3e157658bb014cc952410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d4621353aeffffffff0194540a000000000017a91499fa965ad13a9580ed7a64ac24b2ecad30f1209a8700000000" -}` - -const incomingTx = `{ - "txid": "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", - "version": 4, - "vin": [{ - "txid": "5a3664328ac4e1c0688729573296c2ec69dd9a7cf98d49967b41520be794229b", - "n": 0, - "addresses": ["t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD"], - "isAddress": true, - "value": "387582", - "hex": "483045022100ec29a476dac49578339a92e6c20451aaf3ff6691efaf7d4d3113d07589771ca702203c0c173bdc356300edbd64cdfaa868b97c13ebc403026b283eb5e1fca398db8b012103729cc4211cf70f87c70c3cef90e0ca9b91e99b42364b8c600d5781277647de5f" - }], - "vout": [{ - "value": "200997", - "n": 0, - "spent": true, - "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", - "addresses": ["t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM"], - "isAddress": true - }, { - "value": "186359", - "n": 1, - "spent": true, - "hex": "76a91484f0258cb7974993e6af928921b7f699c51a309488ac", - "addresses": ["t1VzWtLj9CSAK3QnxA7uuiK6XhJrjGjKoy4"], - "isAddress": true - }], - "blockHash": "0000000000a8248c4a14a2dcb74d92855bf9440da9b7b1e6d4baa14ee7e3081c", - "blockHeight": 479017, - "confirmations": 116233, - "blockTime": 1549793065, - "value": "387356", - "valueIn": "387582", - "fees": "226", - "hex": "0400008085202f89019b2294e70b52417b96498df97c9add69ecc2963257298768c0e1c48a3264365a000000006b483045022100ec29a476dac49578339a92e6c20451aaf3ff6691efaf7d4d3113d07589771ca702203c0c173bdc356300edbd64cdfaa868b97c13ebc403026b283eb5e1fca398db8b012103729cc4211cf70f87c70c3cef90e0ca9b91e99b42364b8c600d5781277647de5f000000000225110300000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988acf7d70200000000001976a91484f0258cb7974993e6af928921b7f699c51a309488ac00000000000000000000000000000000000000" -}` - -const pendingTx = `{ - "txid": "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", - "version": 4, - "vin": [{ - "txid": "5a3664328ac4e1c0688729573296c2ec69dd9a7cf98d49967b41520be794229b", - "n": 0, - "addresses": ["t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD"], - "isAddress": true, - "value": "387582", - "hex": "483045022100ec29a476dac49578339a92e6c20451aaf3ff6691efaf7d4d3113d07589771ca702203c0c173bdc356300edbd64cdfaa868b97c13ebc403026b283eb5e1fca398db8b012103729cc4211cf70f87c70c3cef90e0ca9b91e99b42364b8c600d5781277647de5f" - }], - "vout": [{ - "value": "200997", - "n": 0, - "spent": true, - "hex": "76a9146fd73e7c147d8ccc15fda31d8429e70f302b843988ac", - "addresses": ["t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM"], - "isAddress": true - }, { - "value": "186359", - "n": 1, - "spent": true, - "hex": "76a91484f0258cb7974993e6af928921b7f699c51a309488ac", - "addresses": ["t1VzWtLj9CSAK3QnxA7uuiK6XhJrjGjKoy4"], - "isAddress": true - }], - "blockHash": "0000000000a8248c4a14a2dcb74d92855bf9440da9b7b1e6d4baa14ee7e3081c", - "blockHeight": -1, - "confirmations": 116233, - "blockTime": 1549793065, - "value": "387356", - "valueIn": "387582", - "fees": "226", - "hex": "0400008085202f89019b2294e70b52417b96498df97c9add69ecc2963257298768c0e1c48a3264365a000000006b483045022100ec29a476dac49578339a92e6c20451aaf3ff6691efaf7d4d3113d07589771ca702203c0c173bdc356300edbd64cdfaa868b97c13ebc403026b283eb5e1fca398db8b012103729cc4211cf70f87c70c3cef90e0ca9b91e99b42364b8c600d5781277647de5f000000000225110300000000001976a9146fd73e7c147d8ccc15fda31d8429e70f302b843988acf7d70200000000001976a91484f0258cb7974993e6af928921b7f699c51a309488ac00000000000000000000000000000000000000" -}` +var ( + outgoingTx, _ = mock.JsonFromFilePathToString("mocks/" + "outgoing_tx.json") + incomingTx, _ = mock.JsonFromFilePathToString("mocks/" + "incoming_tx.json") + pendingTx, _ = mock.JsonFromFilePathToString("mocks/" + "pending_tx.json") -var expectedOutgoingTx = blockatlas.Tx{ - ID: "df63ddab7d4eed2fb6cb40d4d0519e7e5ac7cf5ad556b2edbd45963ea1a2931c", - Coin: coin.BTC, - From: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC", - To: "3FjBW1KL9L8aYtdKzJ8FhCNxmXB7dXDRw4", - Inputs: []blockatlas.TxOutput{ - { - Address: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC", - Value: "777200", + expectedOutgoingTx = blockatlas.Tx{ + ID: "df63ddab7d4eed2fb6cb40d4d0519e7e5ac7cf5ad556b2edbd45963ea1a2931c", + Coin: coin.BTC, + From: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC", + To: "3FjBW1KL9L8aYtdKzJ8FhCNxmXB7dXDRw4", + Inputs: []blockatlas.TxOutput{ + { + Address: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC", + Value: "777200", + }, }, - }, - Outputs: []blockatlas.TxOutput{ - { - Address: "3FjBW1KL9L8aYtdKzJ8FhCNxmXB7dXDRw4", - Value: "677012", + Outputs: []blockatlas.TxOutput{ + { + Address: "3FjBW1KL9L8aYtdKzJ8FhCNxmXB7dXDRw4", + Value: "677012", + }, }, - }, - Fee: "100188", - Date: 1562945790, - Type: "transfer", - Status: blockatlas.StatusCompleted, - Block: 585094, - Sequence: 0, - Direction: blockatlas.DirectionSelf, - Meta: blockatlas.Transfer{ - Value: "677012", - Symbol: "BTC", - Decimals: 8, - }, -} + Fee: "100188", + Date: 1562945790, + Type: "transfer", + Status: blockatlas.StatusCompleted, + Block: 585094, + Sequence: 0, + Direction: blockatlas.DirectionSelf, + Meta: blockatlas.Transfer{ + Value: "677012", + Symbol: "BTC", + Decimals: 8, + }, + } -var expectedIncomingTx = blockatlas.Tx{ - ID: "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", - Coin: coin.ZEC, - From: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", - To: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", - Inputs: []blockatlas.TxOutput{ - { - Address: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", - Value: "387582", + expectedIncomingTx = blockatlas.Tx{ + ID: "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", + Coin: coin.ZEC, + From: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", + To: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", + Inputs: []blockatlas.TxOutput{ + { + Address: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", + Value: "387582", + }, }, - }, - Outputs: []blockatlas.TxOutput{ - { - Address: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", - Value: "200997", + Outputs: []blockatlas.TxOutput{ + { + Address: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", + Value: "200997", + }, + { + Address: "t1VzWtLj9CSAK3QnxA7uuiK6XhJrjGjKoy4", + Value: "186359", + }, }, - { - Address: "t1VzWtLj9CSAK3QnxA7uuiK6XhJrjGjKoy4", - Value: "186359", + Fee: "226", + Date: 1549793065, + Type: "transfer", + Status: blockatlas.StatusCompleted, + Block: 479017, + Sequence: 0, + Direction: blockatlas.DirectionIncoming, + Meta: blockatlas.Transfer{ + Value: "200997", + Symbol: "ZEC", + Decimals: 8, }, - }, - Fee: "226", - Date: 1549793065, - Type: "transfer", - Status: blockatlas.StatusCompleted, - Block: 479017, - Sequence: 0, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.Transfer{ - Value: "200997", - Symbol: "ZEC", - Decimals: 8, - }, -} + } -var expectedPendingTx = blockatlas.Tx{ - ID: "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", - Coin: coin.ZEC, - From: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", - To: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", - Inputs: []blockatlas.TxOutput{ - { - Address: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", - Value: "387582", + expectedPendingTx = blockatlas.Tx{ + ID: "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", + Coin: coin.ZEC, + From: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", + To: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", + Inputs: []blockatlas.TxOutput{ + { + Address: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", + Value: "387582", + }, }, - }, - Outputs: []blockatlas.TxOutput{ - { - Address: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", - Value: "200997", + Outputs: []blockatlas.TxOutput{ + { + Address: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", + Value: "200997", + }, + { + Address: "t1VzWtLj9CSAK3QnxA7uuiK6XhJrjGjKoy4", + Value: "186359", + }, }, - { - Address: "t1VzWtLj9CSAK3QnxA7uuiK6XhJrjGjKoy4", - Value: "186359", + Fee: "226", + Date: 1549793065, + Type: "transfer", + Status: blockatlas.StatusCompleted, + Block: 0, + Sequence: 0, + Direction: blockatlas.DirectionIncoming, + Meta: blockatlas.Transfer{ + Value: "200997", + Symbol: "ZEC", + Decimals: 8, }, - }, - Fee: "226", - Date: 1549793065, - Type: "transfer", - Status: blockatlas.StatusCompleted, - Block: 0, - Sequence: 0, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.Transfer{ - Value: "200997", - Symbol: "ZEC", - Decimals: 8, - }, -} + } +) func TestNormalizeTransfer(t *testing.T) { @@ -265,11 +167,7 @@ func TestNormalizeTransfer(t *testing.T) { t.Fatal(err) } - if !bytes.Equal(actual, expected) { - println(string(actual)) - println(string(expected)) - t.Error("Transactions not equal") - } + assert.JSONEq(t, string(actual), string(expected)) } } diff --git a/platform/cosmos/mocks/claim_1.json b/platform/cosmos/mocks/claim_1.json new file mode 100644 index 000000000..e3a324535 --- /dev/null +++ b/platform/cosmos/mocks/claim_1.json @@ -0,0 +1,92 @@ +{ + "height": "79678", + "txhash": "C382DCFDC30E2DA294421DAEAD5862F118592A7B000EE91F6BEF8452A1F525D7", + "gas_wanted": "1600000", + "gas_used": "492252", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgWithdrawDelegationReward", + "value": { + "delegator_address": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", + "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + } + }, + { + "type": "cosmos-sdk/MsgWithdrawDelegationReward", + "value": { + "delegator_address": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", + "validator_address": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2" + } + }, + { + "type": "cosmos-sdk/MsgWithdrawDelegationReward", + "value": { + "delegator_address": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", + "validator_address": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw" + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1000" + } + ], + "gas": "1600000" + }, + "memo": "" + } + }, + "timestamp": "2019-12-18T03:04:33Z", + "events": [ + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug" + } + ] + }, + { + "type": "withdraw_rewards", + "attributes": [ + { + "key": "amount", + "value": "1138uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "40612uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2" + }, + { + "key": "amount", + "value": "954uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw" + }, + { + "key": "amount", + "value": "43574uatom" + }, + { + "key": "amount" + } + ] + } + ] +} diff --git a/platform/cosmos/mocks/claim_2.json b/platform/cosmos/mocks/claim_2.json new file mode 100644 index 000000000..73899bad2 --- /dev/null +++ b/platform/cosmos/mocks/claim_2.json @@ -0,0 +1,96 @@ +{ + "height": "54561", + "txhash": "082BA88EC055A7C343A353297EAC104CE87C659E0DDD84621C9AC3C284232800", + "gas_wanted": "300000", + "gas_used": "156772", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgWithdrawDelegationReward", + "value": { + "delegator_address": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", + "validator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + } + }, + { + "type": "cosmos-sdk/MsgDelegate", + "value": { + "delegator_address": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", + "validator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", + "amount": { + "denom": "uatom", + "amount": "2692326" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "0" + } + ], + "gas": "300000" + }, + "memo": "复投" + } + }, + "timestamp": "2019-12-16T02:21:03Z", + "events": [ + { + "type": "delegate", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + }, + { + "key": "amount", + "value": "2692326" + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "module", + "value": "distribution" + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46" + }, + { + "key": "amount", + "value": "2692701uatom" + } + ] + }, + { + "type": "withdraw_rewards", + "attributes": [ + { + "key": "amount", + "value": "2692701uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + } + ] + } + ] +} diff --git a/platform/cosmos/mocks/delegate_tx.json b/platform/cosmos/mocks/delegate_tx.json new file mode 100644 index 000000000..bf21c5b2f --- /dev/null +++ b/platform/cosmos/mocks/delegate_tx.json @@ -0,0 +1,66 @@ +{ + "height": "1258202", + "txhash": "11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7", + "raw_log": "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", + "logs": [ + { + "msg_index": "0", + "success": true, + "log": "" + } + ], + "gas_wanted": "200000", + "gas_used": "103206", + "tags": [ + { + "key": "action", + "value": "delegate" + }, + { + "key": "delegator", + "value": "cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3" + }, + { + "key": "destination-validator", + "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + } + ], + "tx": { + "type": "auth/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgDelegate", + "value": { + "delegator_address": "cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3", + "validator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", + "amount": { + "denom": "uatom", + "amount": "49920" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "5000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "AsZL4GaIEGW6ogh1rEasxHtmirpeBnycLz4VR0rSVr9p" + }, + "signature": "w6sNVzTSsE32ERbBdYYySSp6nj+4xNODuq5GKRVb8q04jMHUbx9AhuZeAhYrkvdkzOl3bD7vRYGx9P1V6yHj0A==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-08-01T04:10:16Z" +} diff --git a/platform/cosmos/mocks/delegation.json b/platform/cosmos/mocks/delegation.json new file mode 100644 index 000000000..05faf9af7 --- /dev/null +++ b/platform/cosmos/mocks/delegation.json @@ -0,0 +1,8 @@ +[ + { + "delegator_address": "cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0", + "validator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", + "shares": "109999.000001746056062372", + "balance": "109999.000001746056062372" + } +] diff --git a/platform/cosmos/mocks/transfer.json b/platform/cosmos/mocks/transfer.json new file mode 100644 index 000000000..4c4587fb2 --- /dev/null +++ b/platform/cosmos/mocks/transfer.json @@ -0,0 +1,68 @@ +{ + "height": "151980", + "txhash": "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", + "raw_log": "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", + "logs": [ + { + "msg_index": "0", + "success": true, + "log": "" + } + ], + "gas_wanted": "100000", + "gas_used": "27678", + "tags": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl" + }, + { + "key": "recipient", + "value": "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae" + } + ], + "tx": { + "type": "auth/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl", + "to_address": "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae", + "amount": [ + { + "denom": "uatom", + "amount": "2271999999" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1" + } + ], + "gas": "100000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A21fdP6IbVC9hER5smiim8I4EbFeIF/bW81IKwmmsdjH" + }, + "signature": "MuR85p714L94tCenogRqzLh1bsbmhKTjs1L9JJPdhSVwQKh61EGlLqYGoUeN/n9xb+OOR9ESUOh2CAzVulKoVQ==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-05-04T17:57:57Z" +} diff --git a/platform/cosmos/mocks/transfer_failed.json b/platform/cosmos/mocks/transfer_failed.json new file mode 100644 index 000000000..e3afe3aec --- /dev/null +++ b/platform/cosmos/mocks/transfer_failed.json @@ -0,0 +1,48 @@ +{ + "height": "5552", + "txhash": "5E78C65A8C1A6C8239EBBBBF2E42020E6ADBA8037EDEA83BF88E1A9159CF13B8", + "code": 12, + "raw_log": "{\"codespace\":\"sdk\",\"code\":12,\"message\":\"out of gas in location: WritePerByte; gasWanted: 40000, gasUsed: 40480\"}", + "gas_wanted": "40000", + "gas_used": "40480", + "tx": { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "cosmos1shpfyt7psrff2ux7nznxvj6f7gq59fcqng5mku", + "to_address": "cosmos1za4pu5gxm80fg6sx0956f88l2sx7jfg2vf7nlc", + "amount": [ + { + "denom": "uatom", + "amount": "100000" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "2000" + } + ], + "gas": "40000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A0IDIokqw01U2YcdylvqD/sJHW5w9puS5vZWSf2GUaqL" + }, + "signature": "1Kwp4dBZUbVV6Fk8AFcmNfSqi7MXFfqyLvHexFZXoqcKh+sNuezry89RhDAWgSMNLyaK20hI2XcUyks+Vo4QEQ==" + } + ], + "memo": "UniCoins registration rewards" + } + }, + "timestamp": "2019-12-12T03:21:42Z" +} diff --git a/platform/cosmos/mocks/transfer_kava.json b/platform/cosmos/mocks/transfer_kava.json new file mode 100644 index 000000000..f1a4e8570 --- /dev/null +++ b/platform/cosmos/mocks/transfer_kava.json @@ -0,0 +1,68 @@ +{ + "height": "151980", + "txhash": "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", + "raw_log": "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", + "logs": [ + { + "msg_index": "0", + "success": true, + "log": "" + } + ], + "gas_wanted": "100000", + "gas_used": "27678", + "tags": [ + { + "key": "action", + "value": "send" + }, + { + "key": "sender", + "value": "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn" + }, + { + "key": "recipient", + "value": "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0" + } + ], + "tx": { + "type": "auth/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn", + "to_address": "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0", + "amount": [ + { + "denom": "uatom", + "amount": "2271999999" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "1" + } + ], + "gas": "100000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A21fdP6IbVC9hER5smiim8I4EbFeIF/bW81IKwmmsdjH" + }, + "signature": "MuR85p714L94tCenogRqzLh1bsbmhKTjs1L9JJPdhSVwQKh61EGlLqYGoUeN/n9xb+OOR9ESUOh2CAzVulKoVQ==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-05-04T17:57:57Z" +} diff --git a/platform/cosmos/mocks/unbonding.json b/platform/cosmos/mocks/unbonding.json new file mode 100644 index 000000000..b5b91aafd --- /dev/null +++ b/platform/cosmos/mocks/unbonding.json @@ -0,0 +1,14 @@ +[ + { + "delegator_address": "cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0", + "validator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", + "entries": [ + { + "creation_height": "0", + "completion_time": "2020-01-01T06:54:18.441436491Z", + "initial_balance": "109999", + "balance": "109999" + } + ] + } +] diff --git a/platform/cosmos/mocks/undelegate_tx.json b/platform/cosmos/mocks/undelegate_tx.json new file mode 100644 index 000000000..c10967a3c --- /dev/null +++ b/platform/cosmos/mocks/undelegate_tx.json @@ -0,0 +1,71 @@ +{ + "height": "1257037", + "txhash": "A1EC36741FEF681F4A77B8F6032AD081100EE5ECB4CC76AEAC2174BC6B871CFE", + "data": "0C0889ECF7EA0510FB9D8CAD03", + "raw_log": "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", + "logs": [ + { + "msg_index": "0", + "success": true, + "log": "" + } + ], + "gas_wanted": "200000", + "gas_used": "107804", + "tags": [ + { + "key": "action", + "value": "begin_unbonding" + }, + { + "key": "delegator", + "value": "cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94" + }, + { + "key": "source-validator", + "value": "cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v" + }, + { + "key": "end-time", + "value": "2019-08-22T01:55:21Z" + } + ], + "tx": { + "type": "auth/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgUndelegate", + "value": { + "delegator_address": "cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94", + "validator_address": "cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v", + "amount": { + "denom": "uatom", + "amount": "5100000000" + } + } + } + ], + "fee": { + "amount": [ + { + "denom": "uatom", + "amount": "5000" + } + ], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A+tPzMXCW7vxmW5VN9Q/CO+fxnEXYlSMOklDVgaFutQD" + }, + "signature": "rh25A/RTm8TUTUGOGhufqxn9vLFef/04xEKMJLUD5QhBVabRADvEgAP1J842XTDtVBS0SpVD/MrPduqRp0nNzg==" + } + ], + "memo": "" + } + }, + "timestamp": "2019-08-01T01:55:21Z" +} diff --git a/platform/cosmos/mocks/validator.json b/platform/cosmos/mocks/validator.json new file mode 100644 index 000000000..8bb377c70 --- /dev/null +++ b/platform/cosmos/mocks/validator.json @@ -0,0 +1,25 @@ +{ + "operator_address": "cosmosvaloper1lktjhnzkpkz3ehrg8psvmwhafg56kfss3q3t8m", + "consensus_pubkey": "cosmosvalconspub1zcjduepqelcwpat987h9yq0ck6g9fsc8t0mththk547gwvk0w4wnkpl0stnspr3hdc", + "jailed": false, + "status": 2, + "tokens": "1557750969185", + "delegator_shares": "1557750969185.000000000000000000", + "description": { + "moniker": "Umbrella ☔", + "identity": "A530AC4D75991FE2", + "website": "https://umbrellavalidator.com", + "details": "One of the winners of Cosmos Game of Stakes, and HackAtom3." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.070400000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.100000000000000000", + "update_time": "2019-08-05T07:10:23.689753607Z" + } + }, + "min_self_delegation": "1" +} diff --git a/platform/cosmos/stake_test.go b/platform/cosmos/stake_test.go index 4204673a3..e856593f6 100644 --- a/platform/cosmos/stake_test.go +++ b/platform/cosmos/stake_test.go @@ -7,66 +7,37 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/stretchr/testify/assert" + "github.com/trustwallet/golibs/mock" ) -const validatorSrc = ` -{ - "operator_address": "cosmosvaloper1lktjhnzkpkz3ehrg8psvmwhafg56kfss3q3t8m", - "consensus_pubkey": "cosmosvalconspub1zcjduepqelcwpat987h9yq0ck6g9fsc8t0mththk547gwvk0w4wnkpl0stnspr3hdc", - "jailed": false, - "status": 2, - "tokens": "1557750969185", - "delegator_shares": "1557750969185.000000000000000000", - "description": { - "moniker": "Umbrella ☔", - "identity": "A530AC4D75991FE2", - "website": "https://umbrellavalidator.com", - "details": "One of the winners of Cosmos Game of Stakes, and HackAtom3." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.070400000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000", - "update_time": "2019-08-05T07:10:23.689753607Z" - } - }, - "min_self_delegation": "1" -}` - -const delegationsSrc = ` -[ - { - "delegator_address": "cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0", - "validator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", - "shares": "109999.000001746056062372", - "balance": "109999.000001746056062372" - } -]` - -const unbondingDelegationsSrc = ` -[ - { - "delegator_address": "cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0", - "validator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", - "entries": [ - { - "creation_height": "0", - "completion_time": "2020-01-01T06:54:18.441436491Z", - "initial_balance": "109999", - "balance": "109999" - } - ] - } -]` - -var stakingPool = Pool{"1222", "200"} - -var cosmosValidator = Validator{Commission: CosmosCommission{CosmosCommissionRates{Rate: "0.4"}}} - -var inflation = 0.7 +var ( + validatorSrc, _ = mock.JsonFromFilePathToString("mocks/" + "validator.json") + delegationsSrc, _ = mock.JsonFromFilePathToString("mocks/" + "delegation.json") + unbondingDelegationsSrc, _ = mock.JsonFromFilePathToString("mocks/" + "unbonding.json") + stakingPool = Pool{"1222", "200"} + cosmosValidator = Validator{Commission: CosmosCommission{CosmosCommissionRates{Rate: "0.4"}}} + inflation = 0.7 + validatorMap = blockatlas.ValidatorMap{ + "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys": validator1, + } + validator1 = blockatlas.StakeValidator{ + ID: "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "Certus One", + Description: "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment.", + Image: "https://assets.trustwalletapp.com/blockchains/cosmos/validators/assets/cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys/logo.png", + Website: "https://certus.one", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 9.259735525366604, + }, + LockTime: lockTime, + MinimumAmount: minimumAmount, + }, + } +) func TestNormalizeValidator(t *testing.T) { var v Validator @@ -90,28 +61,6 @@ func TestCalculateAnnualReward(t *testing.T) { assert.Equal(t, 298.61999703347686, result) } -var validator1 = blockatlas.StakeValidator{ - ID: "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", - Status: true, - Info: blockatlas.StakeValidatorInfo{ - Name: "Certus One", - Description: "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment.", - Image: "https://assets.trustwalletapp.com/blockchains/cosmos/validators/assets/cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys/logo.png", - Website: "https://certus.one", - }, - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{ - Annual: 9.259735525366604, - }, - LockTime: lockTime, - MinimumAmount: minimumAmount, - }, -} - -var validatorMap = blockatlas.ValidatorMap{ - "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys": validator1, -} - func TestNormalizeDelegations(t *testing.T) { var delegations []Delegation err := json.Unmarshal([]byte(delegationsSrc), &delegations) diff --git a/platform/cosmos/transaction_test.go b/platform/cosmos/transaction_test.go index d13788c6b..d62f5a567 100644 --- a/platform/cosmos/transaction_test.go +++ b/platform/cosmos/transaction_test.go @@ -2,677 +2,166 @@ package cosmos import ( "encoding/json" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" ) -const transferSrc = ` -{ - "height": "151980", - "txhash": "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", - "raw_log": "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", - "logs": [ - { - "msg_index": "0", - "success": true, - "log": "" - } - ], - "gas_wanted": "100000", - "gas_used": "27678", - "tags": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl" - }, - { - "key": "recipient", - "value": "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae" - } - ], - "tx": { - "type": "auth/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgSend", - "value": { - "from_address": "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl", - "to_address": "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae", - "amount": [ - { - "denom": "uatom", - "amount": "2271999999" - } - ] - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "1" - } - ], - "gas": "100000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A21fdP6IbVC9hER5smiim8I4EbFeIF/bW81IKwmmsdjH" - }, - "signature": "MuR85p714L94tCenogRqzLh1bsbmhKTjs1L9JJPdhSVwQKh61EGlLqYGoUeN/n9xb+OOR9ESUOh2CAzVulKoVQ==" - } - ], - "memo": "" - } - }, - "timestamp": "2019-05-04T17:57:57Z" -}` - -const transferSrcKava = ` -{ - "height": "151980", - "txhash": "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", - "raw_log": "[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", - "logs": [ - { - "msg_index": "0", - "success": true, - "log": "" - } - ], - "gas_wanted": "100000", - "gas_used": "27678", - "tags": [ - { - "key": "action", - "value": "send" - }, - { - "key": "sender", - "value": "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn" - }, - { - "key": "recipient", - "value": "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0" - } - ], - "tx": { - "type": "auth/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgSend", - "value": { - "from_address": "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn", - "to_address": "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0", - "amount": [ - { - "denom": "uatom", - "amount": "2271999999" - } - ] - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "1" - } - ], - "gas": "100000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A21fdP6IbVC9hER5smiim8I4EbFeIF/bW81IKwmmsdjH" - }, - "signature": "MuR85p714L94tCenogRqzLh1bsbmhKTjs1L9JJPdhSVwQKh61EGlLqYGoUeN/n9xb+OOR9ESUOh2CAzVulKoVQ==" - } - ], - "memo": "" - } - }, - "timestamp": "2019-05-04T17:57:57Z" -}` - -const failedTransferSrc = ` -{ - "height": "5552", - "txhash": "5E78C65A8C1A6C8239EBBBBF2E42020E6ADBA8037EDEA83BF88E1A9159CF13B8", - "code": 12, - "raw_log": "{\"codespace\":\"sdk\",\"code\":12,\"message\":\"out of gas in location: WritePerByte; gasWanted: 40000, gasUsed: 40480\"}", - "gas_wanted": "40000", - "gas_used": "40480", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgSend", - "value": { - "from_address": "cosmos1shpfyt7psrff2ux7nznxvj6f7gq59fcqng5mku", - "to_address": "cosmos1za4pu5gxm80fg6sx0956f88l2sx7jfg2vf7nlc", - "amount": [ - { - "denom": "uatom", - "amount": "100000" - } - ] - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "2000" - } - ], - "gas": "40000" - }, - "signatures": [ - { - "pub_key": { - "type": "tendermint/PubKeySecp256k1", - "value": "A0IDIokqw01U2YcdylvqD/sJHW5w9puS5vZWSf2GUaqL" - }, - "signature": "1Kwp4dBZUbVV6Fk8AFcmNfSqi7MXFfqyLvHexFZXoqcKh+sNuezry89RhDAWgSMNLyaK20hI2XcUyks+Vo4QEQ==" - } - ], - "memo": "UniCoins registration rewards" - } - }, - "timestamp": "2019-12-12T03:21:42Z" -}` - -const delegateSrc = ` -{ - "height":"1258202", - "txhash":"11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7", - "raw_log":"[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", - "logs":[ - { - "msg_index":"0", - "success":true, - "log":"" - } - ], - "gas_wanted":"200000", - "gas_used":"103206", - "tags":[ - { - "key":"action", - "value":"delegate" - }, - { - "key":"delegator", - "value":"cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3" - }, - { - "key":"destination-validator", - "value":"cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" - } - ], - "tx":{ - "type":"auth/StdTx", - "value":{ - "msg":[ - { - "type":"cosmos-sdk/MsgDelegate", - "value":{ - "delegator_address":"cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3", - "validator_address":"cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", - "amount":{ - "denom":"uatom", - "amount":"49920" - } - } - } - ], - "fee":{ - "amount":[ - { - "denom":"uatom", - "amount":"5000" - } - ], - "gas":"200000" - }, - "signatures":[ - { - "pub_key":{ - "type":"tendermint/PubKeySecp256k1", - "value":"AsZL4GaIEGW6ogh1rEasxHtmirpeBnycLz4VR0rSVr9p" - }, - "signature":"w6sNVzTSsE32ERbBdYYySSp6nj+4xNODuq5GKRVb8q04jMHUbx9AhuZeAhYrkvdkzOl3bD7vRYGx9P1V6yHj0A==" - } - ], - "memo":"" - } - }, - "timestamp":"2019-08-01T04:10:16Z" -}` - -const unDelegateSrc = ` -{ - "height":"1257037", - "txhash":"A1EC36741FEF681F4A77B8F6032AD081100EE5ECB4CC76AEAC2174BC6B871CFE", - "data":"0C0889ECF7EA0510FB9D8CAD03", - "raw_log":"[{\"msg_index\":\"0\",\"success\":true,\"log\":\"\"}]", - "logs":[ - { - "msg_index":"0", - "success":true, - "log":"" - } - ], - "gas_wanted":"200000", - "gas_used":"107804", - "tags":[ - { - "key":"action", - "value":"begin_unbonding" - }, - { - "key":"delegator", - "value":"cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94" - }, - { - "key":"source-validator", - "value":"cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v" - }, - { - "key":"end-time", - "value":"2019-08-22T01:55:21Z" - } - ], - "tx":{ - "type":"auth/StdTx", - "value":{ - "msg":[ - { - "type":"cosmos-sdk/MsgUndelegate", - "value":{ - "delegator_address":"cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94", - "validator_address":"cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v", - "amount":{ - "denom":"uatom", - "amount":"5100000000" - } - } - } - ], - "fee":{ - "amount":[ - { - "denom":"uatom", - "amount":"5000" - } - ], - "gas":"200000" - }, - "signatures":[ - { - "pub_key":{ - "type":"tendermint/PubKeySecp256k1", - "value":"A+tPzMXCW7vxmW5VN9Q/CO+fxnEXYlSMOklDVgaFutQD" - }, - "signature":"rh25A/RTm8TUTUGOGhufqxn9vLFef/04xEKMJLUD5QhBVabRADvEgAP1J842XTDtVBS0SpVD/MrPduqRp0nNzg==" - } - ], - "memo":"" - } - }, - "timestamp":"2019-08-01T01:55:21Z" -}` - -const claimRewardSrc1 = ` -{ - "height": "79678", - "txhash": "C382DCFDC30E2DA294421DAEAD5862F118592A7B000EE91F6BEF8452A1F525D7", - "gas_wanted": "1600000", - "gas_used": "492252", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgWithdrawDelegationReward", - "value": { - "delegator_address": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", - "validator_address": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - } - }, - { - "type": "cosmos-sdk/MsgWithdrawDelegationReward", - "value": { - "delegator_address": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", - "validator_address": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2" - } - }, - { - "type": "cosmos-sdk/MsgWithdrawDelegationReward", - "value": { - "delegator_address": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", - "validator_address": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw" - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "1000" - } - ], - "gas": "1600000" - }, - "memo": "" - } - }, - "timestamp": "2019-12-18T03:04:33Z", - "events": [ - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug" - } - ] - }, - { - "type": "withdraw_rewards", - "attributes": [ - { - "key": "amount", - "value": "1138uatom" - }, - { - "key": "validator", - "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - }, - { - "key": "amount", - "value": "40612uatom" - }, - { - "key": "validator", - "value": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2" - }, - { - "key": "amount", - "value": "954uatom" - }, - { - "key": "validator", - "value": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw" - }, - { - "key": "amount", - "value": "43574uatom" - }, - { - "key": "amount" - } - ] - } - ] -}` - -const claimRewardSrc2 = ` -{ - "height": "54561", - "txhash": "082BA88EC055A7C343A353297EAC104CE87C659E0DDD84621C9AC3C284232800", - "gas_wanted": "300000", - "gas_used": "156772", - "tx": { - "type": "cosmos-sdk/StdTx", - "value": { - "msg": [ - { - "type": "cosmos-sdk/MsgWithdrawDelegationReward", - "value": { - "delegator_address": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", - "validator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" - } - }, - { - "type": "cosmos-sdk/MsgDelegate", - "value": { - "delegator_address": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", - "validator_address": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", - "amount": { - "denom": "uatom", - "amount": "2692326" - } - } - } - ], - "fee": { - "amount": [ - { - "denom": "uatom", - "amount": "0" - } - ], - "gas": "300000" - }, - "memo": "复投" - } - }, - "timestamp": "2019-12-16T02:21:03Z", - "events": [ - { - "type": "delegate", - "attributes": [ - { - "key": "validator", - "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" - }, - { - "key": "amount", - "value": "2692326" - } - ] - }, - { - "type": "message", - "attributes": [ - { - "key": "sender", - "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" - }, - { - "key": "module", - "value": "distribution" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46" - }, - { - "key": "amount", - "value": "2692701uatom" - } - ] - }, - { - "type": "withdraw_rewards", - "attributes": [ - { - "key": "amount", - "value": "2692701uatom" - }, - { - "key": "validator", - "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" - } - ] - } - ] -}` - -var transferDst = blockatlas.Tx{ - ID: "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", - Coin: coin.ATOM, - From: "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl", - To: "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae", - Fee: "1", - Date: 1556992677, - Block: 151980, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ - Value: "2271999999", - Symbol: coin.Cosmos().Symbol, - Decimals: 6, - }, -} +var ( + transferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer.json") + transferSrcKava, _ = mock.JsonFromFilePathToString("mocks/" + "transfer_kava.json") + failedTransferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer_failed.json") + delegateSrc, _ = mock.JsonFromFilePathToString("mocks/" + "delegate_tx.json") + unDelegateSrc, _ = mock.JsonFromFilePathToString("mocks/" + "undelegate_tx.json") + claimRewardSrc1, _ = mock.JsonFromFilePathToString("mocks/" + "claim_1.json") + claimRewardSrc2, _ = mock.JsonFromFilePathToString("mocks/" + "claim_2.json") + + transferDst = blockatlas.Tx{ + ID: "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", + Coin: coin.ATOM, + From: "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl", + To: "cosmos1nynns8ex9fq6sjjfj8k79ymkdz4sqth06xexae", + Fee: "1", + Date: 1556992677, + Block: 151980, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxTransfer, + Meta: blockatlas.Transfer{ + Value: "2271999999", + Symbol: coin.Cosmos().Symbol, + Decimals: 6, + }, + } -var transferDstKava = blockatlas.Tx{ - ID: "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", - Coin: coin.KAVA, - From: "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn", - To: "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0", - Fee: "1", - Date: 1556992677, - Block: 151980, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ - Value: "2271999999", - Symbol: coin.Kava().Symbol, - Decimals: 6, - }, -} + transferDstKava = blockatlas.Tx{ + ID: "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", + Coin: coin.KAVA, + From: "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn", + To: "kava1z89utvygweg5l56fsk8ak7t6hh88fd0agl98n0", + Fee: "1", + Date: 1556992677, + Block: 151980, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxTransfer, + Meta: blockatlas.Transfer{ + Value: "2271999999", + Symbol: coin.Kava().Symbol, + Decimals: 6, + }, + } -var delegateDst = blockatlas.Tx{ - ID: "11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7", - Coin: coin.ATOM, - From: "cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3", - To: "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", - Fee: "5000", - Date: 1564632616, - Block: 1258202, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionOutgoing, - Meta: blockatlas.AnyAction{ - Coin: coin.ATOM, - Title: blockatlas.AnyActionDelegation, - Key: blockatlas.KeyStakeDelegate, - Name: coin.Cosmos().Name, - Symbol: coin.Coins[coin.ATOM].Symbol, - Decimals: coin.Coins[coin.ATOM].Decimals, - Value: "49920", - }, -} + delegateDst = blockatlas.Tx{ + ID: "11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7", + Coin: coin.ATOM, + From: "cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3", + To: "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", + Fee: "5000", + Date: 1564632616, + Block: 1258202, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxAnyAction, + Direction: blockatlas.DirectionOutgoing, + Meta: blockatlas.AnyAction{ + Coin: coin.ATOM, + Title: blockatlas.AnyActionDelegation, + Key: blockatlas.KeyStakeDelegate, + Name: coin.Cosmos().Name, + Symbol: coin.Coins[coin.ATOM].Symbol, + Decimals: coin.Coins[coin.ATOM].Decimals, + Value: "49920", + }, + } -var unDelegateDst = blockatlas.Tx{ - ID: "A1EC36741FEF681F4A77B8F6032AD081100EE5ECB4CC76AEAC2174BC6B871CFE", - Coin: coin.ATOM, - From: "cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94", - To: "cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v", - Fee: "5000", - Date: 1564624521, - Block: 1257037, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.AnyAction{ - Coin: coin.ATOM, - Title: blockatlas.AnyActionUndelegation, - Key: blockatlas.KeyStakeDelegate, - Name: coin.Cosmos().Name, - Symbol: coin.Coins[coin.ATOM].Symbol, - Decimals: coin.Coins[coin.ATOM].Decimals, - Value: "5100000000", - }, -} + unDelegateDst = blockatlas.Tx{ + ID: "A1EC36741FEF681F4A77B8F6032AD081100EE5ECB4CC76AEAC2174BC6B871CFE", + Coin: coin.ATOM, + From: "cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94", + To: "cosmosvaloper1te8nxpc2myjfrhaty0dnzdhs5ahdh5agzuym9v", + Fee: "5000", + Date: 1564624521, + Block: 1257037, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxAnyAction, + Direction: blockatlas.DirectionIncoming, + Meta: blockatlas.AnyAction{ + Coin: coin.ATOM, + Title: blockatlas.AnyActionUndelegation, + Key: blockatlas.KeyStakeDelegate, + Name: coin.Cosmos().Name, + Symbol: coin.Coins[coin.ATOM].Symbol, + Decimals: coin.Coins[coin.ATOM].Decimals, + Value: "5100000000", + }, + } -var claimRewardDst2 = blockatlas.Tx{ - ID: "082BA88EC055A7C343A353297EAC104CE87C659E0DDD84621C9AC3C284232800", - Coin: coin.ATOM, - From: "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", - To: "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", - Fee: "0", - Date: 1576462863, - Block: 54561, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionIncoming, - Memo: "复投", - Meta: blockatlas.AnyAction{ - Coin: coin.ATOM, - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, - Name: coin.Cosmos().Name, - Symbol: coin.Coins[coin.ATOM].Symbol, - Decimals: coin.Coins[coin.ATOM].Decimals, - Value: "2692701", - }, -} + claimRewardDst2 = blockatlas.Tx{ + ID: "082BA88EC055A7C343A353297EAC104CE87C659E0DDD84621C9AC3C284232800", + Coin: coin.ATOM, + From: "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", + To: "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2", + Fee: "0", + Date: 1576462863, + Block: 54561, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxAnyAction, + Direction: blockatlas.DirectionIncoming, + Memo: "复投", + Meta: blockatlas.AnyAction{ + Coin: coin.ATOM, + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + Name: coin.Cosmos().Name, + Symbol: coin.Coins[coin.ATOM].Symbol, + Decimals: coin.Coins[coin.ATOM].Decimals, + Value: "2692701", + }, + } -var claimRewardDst1 = blockatlas.Tx{ - ID: "C382DCFDC30E2DA294421DAEAD5862F118592A7B000EE91F6BEF8452A1F525D7", - Coin: coin.ATOM, - From: "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", - To: "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", - Fee: "1000", - Date: 1576638273, - Block: 79678, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionIncoming, - Memo: "", - Meta: blockatlas.AnyAction{ - Coin: coin.ATOM, - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, - Name: coin.Cosmos().Name, - Symbol: coin.Coins[coin.ATOM].Symbol, - Decimals: coin.Coins[coin.ATOM].Decimals, - Value: "86278", - }, -} + claimRewardDst1 = blockatlas.Tx{ + ID: "C382DCFDC30E2DA294421DAEAD5862F118592A7B000EE91F6BEF8452A1F525D7", + Coin: coin.ATOM, + From: "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", + To: "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5", + Fee: "1000", + Date: 1576638273, + Block: 79678, + Status: blockatlas.StatusCompleted, + Type: blockatlas.TxAnyAction, + Direction: blockatlas.DirectionIncoming, + Memo: "", + Meta: blockatlas.AnyAction{ + Coin: coin.ATOM, + Title: blockatlas.AnyActionClaimRewards, + Key: blockatlas.KeyStakeClaimRewards, + Name: coin.Cosmos().Name, + Symbol: coin.Coins[coin.ATOM].Symbol, + Decimals: coin.Coins[coin.ATOM].Decimals, + Value: "86278", + }, + } -var failedTransferDst = blockatlas.Tx{ - ID: "5E78C65A8C1A6C8239EBBBBF2E42020E6ADBA8037EDEA83BF88E1A9159CF13B8", - Coin: coin.ATOM, - From: "cosmos1shpfyt7psrff2ux7nznxvj6f7gq59fcqng5mku", - To: "cosmos1za4pu5gxm80fg6sx0956f88l2sx7jfg2vf7nlc", - Fee: "2000", - Date: 1576120902, - Block: 5552, - Status: blockatlas.StatusError, - Type: blockatlas.TxTransfer, - Memo: "UniCoins registration rewards", - Meta: blockatlas.Transfer{ - Value: "100000", - Symbol: coin.Cosmos().Symbol, - Decimals: 6, - }, -} + failedTransferDst = blockatlas.Tx{ + ID: "5E78C65A8C1A6C8239EBBBBF2E42020E6ADBA8037EDEA83BF88E1A9159CF13B8", + Coin: coin.ATOM, + From: "cosmos1shpfyt7psrff2ux7nznxvj6f7gq59fcqng5mku", + To: "cosmos1za4pu5gxm80fg6sx0956f88l2sx7jfg2vf7nlc", + Fee: "2000", + Date: 1576120902, + Block: 5552, + Status: blockatlas.StatusError, + Type: blockatlas.TxTransfer, + Memo: "UniCoins registration rewards", + Meta: blockatlas.Transfer{ + Value: "100000", + Symbol: coin.Cosmos().Symbol, + Decimals: 6, + }, + } +) type test struct { name string diff --git a/platform/elrond/mocks/tx.json b/platform/elrond/mocks/tx.json new file mode 100644 index 000000000..95ca22c53 --- /dev/null +++ b/platform/elrond/mocks/tx.json @@ -0,0 +1,13 @@ +{ + "hash": "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce": 0, + "round": 35462, + "value": "82516976060558456822", + "receiver": "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "sender": "4294967295", + "data": "ok", + "signature": "", + "timestamp": 1587715632, + "status": "Success", + "fee": "1000" +} diff --git a/platform/elrond/mocks/tx_2.json b/platform/elrond/mocks/tx_2.json new file mode 100644 index 000000000..f614f65d9 --- /dev/null +++ b/platform/elrond/mocks/tx_2.json @@ -0,0 +1,13 @@ +{ + "hash": "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce": 1, + "round": 100, + "value": "2000", + "receiver": "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "sender": "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "data": "money", + "signature": "", + "timestamp": 1588757256, + "status": "Pending", + "fee": "1500" +} diff --git a/platform/elrond/mocks/tx_3.json b/platform/elrond/mocks/tx_3.json new file mode 100644 index 000000000..555b93d00 --- /dev/null +++ b/platform/elrond/mocks/tx_3.json @@ -0,0 +1,15 @@ +{ + "hash": "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce": 19, + "round": 200, + "value": "2", + "receiver": "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + "sender": "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "data": "test", + "signature": "", + "timestamp": 1588757256, + "status": "Fail", + "fee": "0", + "gasPrice": 5, + "gasLimit": 1000 +} diff --git a/platform/elrond/mocks/tx_4.json b/platform/elrond/mocks/tx_4.json new file mode 100644 index 000000000..01148eb58 --- /dev/null +++ b/platform/elrond/mocks/tx_4.json @@ -0,0 +1,13 @@ +{ + "hash": "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce": 19, + "round": 200, + "value": "2", + "receiver": "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + "sender": "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "data": "test", + "signature": "", + "timestamp": 1588757256, + "status": "pending", + "fee": "5000" +} diff --git a/platform/elrond/mocks/tx_5.json b/platform/elrond/mocks/tx_5.json new file mode 100644 index 000000000..3052dd79b --- /dev/null +++ b/platform/elrond/mocks/tx_5.json @@ -0,0 +1,13 @@ +{ + "hash": "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce": 19, + "round": 200, + "value": "2", + "receiver": "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + "sender": "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "data": "test", + "signature": "", + "timestamp": 1588757256, + "status": "success", + "fee": "5000" +} diff --git a/platform/elrond/mocks/tx_6.json b/platform/elrond/mocks/tx_6.json new file mode 100644 index 000000000..12cf70a76 --- /dev/null +++ b/platform/elrond/mocks/tx_6.json @@ -0,0 +1,13 @@ +{ + "hash": "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + "nonce": 25, + "value": "2", + "receiver": "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + "sender": "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + "data": "test", + "signature": "", + "status": "success", + "fee": "0", + "gasPrice": 5, + "gasLimit": 1000 +} diff --git a/platform/elrond/transaction_test.go b/platform/elrond/transaction_test.go index 7cb66576c..29fcf4d45 100644 --- a/platform/elrond/transaction_test.go +++ b/platform/elrond/transaction_test.go @@ -7,210 +7,127 @@ import ( "github.com/stretchr/testify/require" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" ) -const userAddress = `erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0` - -const txTransferSrc1 = ` -{ - "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - "nonce":0, - "round":35462, - "value":"82516976060558456822", - "receiver":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - "sender":"4294967295", - "data":"ok", - "signature":"", - "timestamp":1587715632, - "status":"Success", - "fee": "1000" -}` - -const txTransferSrc2 = ` -{ - "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - "nonce":1, - "round":100, - "value":"2000", - "receiver":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - "data":"money", - "signature":"", - "timestamp":1588757256, - "status":"Pending", - "fee": "1500" -}` - -const txTransferSrc3 = ` -{ - "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - "nonce":19, - "round":200, - "value":"2", - "receiver":"erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", - "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - "data":"test", - "signature":"", - "timestamp":1588757256, - "status":"Fail", - "fee": "0", - "gasPrice": 5, - "gasLimit": 1000 -}` - -const txTransferSrc4 = ` -{ - "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - "nonce":19, - "round":200, - "value":"2", - "receiver":"erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", - "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - "data":"test", - "signature":"", - "timestamp":1588757256, - "status":"pending", - "fee": "5000" -}` - -const txTransferSrc5 = ` -{ - "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - "nonce":19, - "round":200, - "value":"2", - "receiver":"erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", - "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - "data":"test", - "signature":"", - "timestamp":1588757256, - "status":"success", - "fee": "5000" -}` - -const txTransferSrc6 = ` -{ - "hash":"30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - "nonce":25, - "value":"2", - "receiver":"erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", - "sender":"erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - "data":"test", - "signature":"", - "status":"success", - "fee": "0", - "gasPrice": 5, - "gasLimit": 1000 -}` - -var txTransfer1Normalized = blockatlas.Tx{ - ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.EGLD, - Date: int64(1587715632), - From: "metachain", - To: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - Fee: "1000", - Status: blockatlas.StatusCompleted, - Memo: "ok", - Sequence: 0, - Meta: blockatlas.Transfer{ - Value: "82516976060558456822", - Symbol: coin.Elrond().Symbol, - Decimals: coin.Elrond().Decimals, - }, - Direction: blockatlas.DirectionOutgoing, -} +var ( + userAddress = `erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0` + txTransferSrc1, _ = mock.JsonFromFilePathToString("mocks/tx.json") + txTransferSrc2, _ = mock.JsonFromFilePathToString("mocks/tx_2.json") + txTransferSrc3, _ = mock.JsonFromFilePathToString("mocks/tx_3.json") + txTransferSrc4, _ = mock.JsonFromFilePathToString("mocks/tx_4.json") + txTransferSrc5, _ = mock.JsonFromFilePathToString("mocks/tx_5.json") + txTransferSrc6, _ = mock.JsonFromFilePathToString("mocks/tx_6.json") + + txTransfer1Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.EGLD, + Date: int64(1587715632), + From: "metachain", + To: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + Fee: "1000", + Status: blockatlas.StatusCompleted, + Memo: "ok", + Sequence: 0, + Meta: blockatlas.Transfer{ + Value: "82516976060558456822", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionOutgoing, + } -var txTransfer2Normalized = blockatlas.Tx{ - ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.EGLD, - Date: int64(1588757256), - From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - To: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - Fee: "1500", - Status: blockatlas.StatusPending, - Memo: "money", - Sequence: 1, - Meta: blockatlas.Transfer{ - Value: "2000", - Symbol: coin.Elrond().Symbol, - Decimals: coin.Elrond().Decimals, - }, - Direction: blockatlas.DirectionSelf, -} + txTransfer2Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.EGLD, + Date: int64(1588757256), + From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + To: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + Fee: "1500", + Status: blockatlas.StatusPending, + Memo: "money", + Sequence: 1, + Meta: blockatlas.Transfer{ + Value: "2000", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionSelf, + } -var txTransfer3Normalized = blockatlas.Tx{ - ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.EGLD, - Date: int64(1588757256), - From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", - Fee: "5000", - Status: blockatlas.StatusError, - Memo: "test", - Sequence: 19, - Meta: blockatlas.Transfer{ - Value: "2", - Symbol: coin.Elrond().Symbol, - Decimals: coin.Elrond().Decimals, - }, - Direction: blockatlas.DirectionOutgoing, -} + txTransfer3Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.EGLD, + Date: int64(1588757256), + From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + Fee: "5000", + Status: blockatlas.StatusError, + Memo: "test", + Sequence: 19, + Meta: blockatlas.Transfer{ + Value: "2", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionOutgoing, + } -var txTransfer4Normalized = blockatlas.Tx{ - ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.EGLD, - Date: int64(1588757256), - From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", - Fee: "5000", - Status: blockatlas.StatusPending, - Memo: "test", - Sequence: 19, - Meta: blockatlas.Transfer{ - Value: "2", - Symbol: coin.Elrond().Symbol, - Decimals: coin.Elrond().Decimals, - }, - Direction: blockatlas.DirectionOutgoing, -} + txTransfer4Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.EGLD, + Date: int64(1588757256), + From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + Fee: "5000", + Status: blockatlas.StatusPending, + Memo: "test", + Sequence: 19, + Meta: blockatlas.Transfer{ + Value: "2", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionOutgoing, + } -var txTransfer5Normalized = blockatlas.Tx{ - ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.EGLD, - Date: int64(1588757256), - From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", - Fee: "5000", - Status: blockatlas.StatusCompleted, - Memo: "test", - Sequence: 19, - Meta: blockatlas.Transfer{ - Value: "2", - Symbol: coin.Elrond().Symbol, - Decimals: coin.Elrond().Decimals, - }, - Direction: blockatlas.DirectionOutgoing, -} + txTransfer5Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.EGLD, + Date: int64(1588757256), + From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + Fee: "5000", + Status: blockatlas.StatusCompleted, + Memo: "test", + Sequence: 19, + Meta: blockatlas.Transfer{ + Value: "2", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionOutgoing, + } -var txTransfer6Normalized = blockatlas.Tx{ - ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", - Coin: coin.EGLD, - From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", - To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", - Fee: "5000", - Status: blockatlas.StatusCompleted, - Memo: "test", - Sequence: 25, - Block: 620, - Date: 1596121554, - Meta: blockatlas.Transfer{ - Value: "2", - Symbol: coin.Elrond().Symbol, - Decimals: coin.Elrond().Decimals, - }, - Direction: blockatlas.DirectionOutgoing, -} + txTransfer6Normalized = blockatlas.Tx{ + ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", + Coin: coin.EGLD, + From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", + To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", + Fee: "5000", + Status: blockatlas.StatusCompleted, + Memo: "test", + Sequence: 25, + Block: 620, + Date: 1596121554, + Meta: blockatlas.Transfer{ + Value: "2", + Symbol: coin.Elrond().Symbol, + Decimals: coin.Elrond().Decimals, + }, + Direction: blockatlas.DirectionOutgoing, + } +) type test struct { name string diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/collection_test.go index 797ff885e..eb3dc7ca8 100644 --- a/platform/ethereum/collection_test.go +++ b/platform/ethereum/collection_test.go @@ -2,271 +2,68 @@ package ethereum import ( "encoding/json" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/ethereum/collection" "github.com/trustwallet/golibs/coin" - "testing" + "github.com/trustwallet/golibs/mock" ) -const collectionsOwnerV4 = "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" +var ( + collectionsOwnerV4 = "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" + collectionsSrcV4, _ = mock.JsonFromFilePathToString("mocks/opensea_collections.json") + collectibleSrcV4, _ = mock.JsonFromFilePathToString("mocks/opensea_collectible.json") -const collectionsSrcV4 = ` -[ - { - "primary_asset_contracts":[ - { - "address":"0x06012c8cf97bead5deae237070f9587f8e7a266d", - "name":"CryptoKitties", - "symbol":"CKITTY", - "description":"CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - "external_link":"https://www.cryptokitties.co/", - "nft_version":"1.0", - "schema_name":"ERC721", - "display_data":{ - "images":[ - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/564155.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/546630.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/441529.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/552435.svg", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/524748.png", - "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/540800.svg" - ], - "card_display_style":"padded" - }, - "image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png" - } - ], - "name":"CryptoKitties", - "slug":"cryptokitties", - "image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", - "description":"CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - "external_url":"https://www.cryptokitties.co/", - "featured_image_url":"https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556589429.png", - "created_date":"2019-04-26T22:13:04.207050", - "owned_asset_count":3 - }, - { - "primary_asset_contracts":[ - { - "address":"0xfaafdc07907ff5120a76b34b731b278c38d6043c", - "name":"Enjin", - "symbol":"", - "description":"", - "external_link":null, - "nft_version":null, - "schema_name":"ERC1155", - "display_data":{ + collection1DstV4 = blockatlas.Collection{ + Name: "CryptoKitties", + ImageUrl: "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", + Description: "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + ExternalLink: "https://www.cryptokitties.co/", + Total: 3, + Id: "cryptokitties", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Coin: 60, + } - }, - "owner":null, - "created_date":"2019-08-02T23:43:14.666153", - "asset_contract_type":"semi-fungible" - } - ], - "name":"Age of Rust", - "slug":"age-of-rust", - "image_url":"https://storage.opensea.io/age-of-rust-1561960816.jpg", - "description":"Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", - "external_url":"https://www.ageofrust.games/", - "featured_image_url":null, - "created_date":"2019-09-03T02:35:56.063685", - "owned_asset_count":1 - }, - { - "primary_asset_contracts":[ - { - "address":"0xee85966b4974d3c6f71a2779cc3b6f53afbc2b68", - "asset_contract_type":"fungible", - "created_date":"2019-10-16T07:36:16.102163", - "name":"Rare Chest", - "nft_version":null, - "opensea_version":null, - "owner":1610615, - "schema_name":"ERC20", - "symbol":"", - "total_supply":"1", - "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat":false, - "dev_buyer_fee_basis_points":0, - "dev_seller_fee_basis_points":0, - "only_proxied_transfers":false, - "opensea_buyer_fee_basis_points":0, - "opensea_seller_fee_basis_points":250, - "buyer_fee_basis_points":0, - "seller_fee_basis_points":250, - "payout_address":null - }, - { - "address":"0x20d4cec36528e1c4563c1bfbe3de06aba70b22b4", - "asset_contract_type":"fungible", - "created_date":"2019-10-16T08:06:42.727997", - "name":"Legendary Chest", - "nft_version":null, - "opensea_version":null, - "owner":1610615, - "schema_name":"ERC20", - "symbol":"", - "total_supply":"1", - "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat":false, - "dev_buyer_fee_basis_points":0, - "dev_seller_fee_basis_points":0, - "only_proxied_transfers":false, - "opensea_buyer_fee_basis_points":0, - "opensea_seller_fee_basis_points":250, - "buyer_fee_basis_points":0, - "seller_fee_basis_points":250, - "payout_address":null - }, - { - "address":"0x0e3a2a1f2146d86a604adc220b4967a898d7fe07", - "asset_contract_type":"non-fungible", - "created_date":"2019-11-01T06:39:04.363034", - "name":"Gods Unchained Cards", - "nft_version":"3.0", - "opensea_version":null, - "owner":1691695, - "schema_name":"ERC721", - "symbol":"", - "total_supply":"1", - "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat":false, - "dev_buyer_fee_basis_points":0, - "dev_seller_fee_basis_points":0, - "only_proxied_transfers":false, - "opensea_buyer_fee_basis_points":0, - "opensea_seller_fee_basis_points":250, - "buyer_fee_basis_points":0, - "seller_fee_basis_points":250, - "payout_address":null - }, - { - "address":"0x564cb55c655f727b61d9baf258b547ca04e9e548", - "asset_contract_type":"non-fungible", - "created_date":"2019-10-29T12:28:37.643714", - "name":"Gods Unchained", - "nft_version":"3.0", - "opensea_version":null, - "owner":1691695, - "schema_name":"ERC721", - "symbol":"", - "total_supply":"205", - "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "external_link":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "default_to_fiat":false, - "dev_buyer_fee_basis_points":0, - "dev_seller_fee_basis_points":0, - "only_proxied_transfers":false, - "opensea_buyer_fee_basis_points":0, - "opensea_seller_fee_basis_points":250, - "buyer_fee_basis_points":0, - "seller_fee_basis_points":250, - "payout_address":null - } - ], - "traits":{ - "mana":{ - "min":1, - "max":18 - }, - "health":{ - "min":1, - "max":16 - }, - "attack":{ - "min":1, - "max":16 - } - }, - "stats":{ - "seven_day_volume":270.564697067863, - "seven_day_change":-0.014179906699531201, - "total_volume":11825.0384171324, - "count":6835331, - "num_owners":10791, - "market_cap":150892.14138332763, - "average_price":0.0396514694030496, - "items_sold":298233 - }, - "banner_image_url":null, - "chat_url":null, - "created_date":"2019-11-13T03:01:42.051246", - "default_to_fiat":false, - "description":"Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - "dev_buyer_fee_basis_points":"0", - "dev_seller_fee_basis_points":"0", - "display_data":{ - "images":[ - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/25233.png", - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/152875.png", - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/25669.png", - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9237.png", - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9228.png", - "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9231.png" - ], - "card_display_style":"contain" - }, - "external_url":"https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - "featured":true, - "featured_image_url":"https://storage.opensea.io/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab-featured-1556589419.png", - "hidden":false, - "image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - "is_subject_to_whitelist":false, - "large_image_url":"https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ", - "name":"Gods Unchained", - "only_proxied_transfers":false, - "opensea_buyer_fee_basis_points":"0", - "opensea_seller_fee_basis_points":"250", - "payout_address":null, - "require_email":false, - "short_description":null, - "slug":"gods-unchained", - "wiki_url":null, - "owned_asset_count":535 - } -] -` + collection2DstV4 = blockatlas.Collection{ + Name: "Age of Rust", + ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", + Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", + ExternalLink: "https://www.ageofrust.games/", + Total: 1, + Id: "age-of-rust", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Coin: 60, + } -var collection1DstV4 = blockatlas.Collection{ - Name: "CryptoKitties", - ImageUrl: "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", - Description: "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", - ExternalLink: "https://www.cryptokitties.co/", - Total: 3, - Id: "cryptokitties", - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - Coin: 60, -} - -var collection2DstV4 = blockatlas.Collection{ - Name: "Age of Rust", - ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", - Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", - ExternalLink: "https://www.ageofrust.games/", - Total: 1, - Id: "age-of-rust", - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - Coin: 60, -} + collection3DstV4 = blockatlas.Collection{ + Name: "Gods Unchained", + ImageUrl: "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + Description: "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + ExternalLink: "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + Total: 535, + Id: "gods-unchained", + Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", + Coin: 60, + } -var collection3DstV4 = blockatlas.Collection{ - Name: "Gods Unchained", - ImageUrl: "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", - Description: "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", - ExternalLink: "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", - Total: 535, - Id: "gods-unchained", - Address: "0x0875BCab22dE3d02402bc38aEe4104e1239374a7", - Coin: 60, -} + collectibleDstV4 = blockatlas.Collectible{ + ID: "0xfaafdc07907ff5120a76b34b731b278c38d6043c-54277541829991970107421667568590323026590803461896874578610080514640537714688", + CollectionID: "age-of-rust", + TokenID: "54277541829991970107421667568590323026590803461896874578610080514640537714688", + ContractAddress: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + Category: "Age of Rust", + ImageUrl: "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", + ExternalLink: "https://opensea.io/", + ProviderLink: "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688", + Type: "ERC1155", + Description: "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", + Coin: 60, + Name: "Rustbits", + } +) func TestNormalizeCollectionV4(t *testing.T) { var collections []collection.Collection @@ -278,48 +75,6 @@ func TestNormalizeCollectionV4(t *testing.T) { assert.Equal(t, page, expected, "collections don't equal") } -const collectibleSrcV4 = ` -[ - { - "token_id": "54277541829991970107421667568590323026590803461896874578610080514640537714688", - "image_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858806.png", - "image_preview_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", - "name": "Rustbits", - "description": "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", - "external_link": "", - "asset_contract": { - "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - "name": "Enjin", - "external_link": null, - "nft_version": null, - "schema_name": "ERC1155", - "display_data": {} - }, - "collection": { - "slug": "age-of-rust", - "name": "Age of Rust", - "external_url": "https://opensea.io/" - }, - "permalink": "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688" - } -] -` - -var collectibleDstV4 = blockatlas.Collectible{ - ID: "0xfaafdc07907ff5120a76b34b731b278c38d6043c-54277541829991970107421667568590323026590803461896874578610080514640537714688", - CollectionID: "age-of-rust", - TokenID: "54277541829991970107421667568590323026590803461896874578610080514640537714688", - ContractAddress: "0xfaafdc07907ff5120a76b34b731b278c38d6043c", - Category: "Age of Rust", - ImageUrl: "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", - ExternalLink: "https://opensea.io/", - ProviderLink: "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688", - Type: "ERC1155", - Description: "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", - Coin: 60, - Name: "Rustbits", -} - func TestNormalizeCollectibleV4(t *testing.T) { var collectibles []collection.Collectible err := json.Unmarshal([]byte(collectibleSrcV4), &collectibles) diff --git a/platform/ethereum/mocks/opensea_collectible.json b/platform/ethereum/mocks/opensea_collectible.json new file mode 100644 index 000000000..4fff8c06e --- /dev/null +++ b/platform/ethereum/mocks/opensea_collectible.json @@ -0,0 +1,24 @@ +[ + { + "token_id": "54277541829991970107421667568590323026590803461896874578610080514640537714688", + "image_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858806.png", + "image_preview_url": "https://storage.opensea.io/0xfaafdc07907ff5120a76b34b731b278c38d6043c-preview/54277541829991970107421667568590323026590803461896874578610080514640537714688-1564858807.png", + "name": "Rustbits", + "description": "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", + "external_link": "", + "asset_contract": { + "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + "name": "Enjin", + "external_link": null, + "nft_version": null, + "schema_name": "ERC1155", + "display_data": {} + }, + "collection": { + "slug": "age-of-rust", + "name": "Age of Rust", + "external_url": "https://opensea.io/" + }, + "permalink": "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688" + } +] diff --git a/platform/ethereum/mocks/opensea_collections.json b/platform/ethereum/mocks/opensea_collections.json new file mode 100644 index 000000000..f59bfab50 --- /dev/null +++ b/platform/ethereum/mocks/opensea_collections.json @@ -0,0 +1,219 @@ +[ + { + "primary_asset_contracts": [ + { + "address": "0x06012c8cf97bead5deae237070f9587f8e7a266d", + "name": "CryptoKitties", + "symbol": "CKITTY", + "description": "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + "external_link": "https://www.cryptokitties.co/", + "nft_version": "1.0", + "schema_name": "ERC721", + "display_data": { + "images": [ + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/564155.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/546630.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/441529.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/552435.svg", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/524748.png", + "https://storage.googleapis.com/ck-kitty-image/0x06012c8cf97bead5deae237070f9587f8e7a266d/540800.svg" + ], + "card_display_style": "padded" + }, + "image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png" + } + ], + "name": "CryptoKitties", + "slug": "cryptokitties", + "image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", + "description": "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", + "external_url": "https://www.cryptokitties.co/", + "featured_image_url": "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556589429.png", + "created_date": "2019-04-26T22:13:04.207050", + "owned_asset_count": 3 + }, + { + "primary_asset_contracts": [ + { + "address": "0xfaafdc07907ff5120a76b34b731b278c38d6043c", + "name": "Enjin", + "symbol": "", + "description": "", + "external_link": null, + "nft_version": null, + "schema_name": "ERC1155", + "display_data": {}, + "owner": null, + "created_date": "2019-08-02T23:43:14.666153", + "asset_contract_type": "semi-fungible" + } + ], + "name": "Age of Rust", + "slug": "age-of-rust", + "image_url": "https://storage.opensea.io/age-of-rust-1561960816.jpg", + "description": "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", + "external_url": "https://www.ageofrust.games/", + "featured_image_url": null, + "created_date": "2019-09-03T02:35:56.063685", + "owned_asset_count": 1 + }, + { + "primary_asset_contracts": [ + { + "address": "0xee85966b4974d3c6f71a2779cc3b6f53afbc2b68", + "asset_contract_type": "fungible", + "created_date": "2019-10-16T07:36:16.102163", + "name": "Rare Chest", + "nft_version": null, + "opensea_version": null, + "owner": 1610615, + "schema_name": "ERC20", + "symbol": "", + "total_supply": "1", + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + { + "address": "0x20d4cec36528e1c4563c1bfbe3de06aba70b22b4", + "asset_contract_type": "fungible", + "created_date": "2019-10-16T08:06:42.727997", + "name": "Legendary Chest", + "nft_version": null, + "opensea_version": null, + "owner": 1610615, + "schema_name": "ERC20", + "symbol": "", + "total_supply": "1", + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + { + "address": "0x0e3a2a1f2146d86a604adc220b4967a898d7fe07", + "asset_contract_type": "non-fungible", + "created_date": "2019-11-01T06:39:04.363034", + "name": "Gods Unchained Cards", + "nft_version": "3.0", + "opensea_version": null, + "owner": 1691695, + "schema_name": "ERC721", + "symbol": "", + "total_supply": "1", + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + }, + { + "address": "0x564cb55c655f727b61d9baf258b547ca04e9e548", + "asset_contract_type": "non-fungible", + "created_date": "2019-10-29T12:28:37.643714", + "name": "Gods Unchained", + "nft_version": "3.0", + "opensea_version": null, + "owner": 1691695, + "schema_name": "ERC721", + "symbol": "", + "total_supply": "205", + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "external_link": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "default_to_fiat": false, + "dev_buyer_fee_basis_points": 0, + "dev_seller_fee_basis_points": 0, + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": 0, + "opensea_seller_fee_basis_points": 250, + "buyer_fee_basis_points": 0, + "seller_fee_basis_points": 250, + "payout_address": null + } + ], + "traits": { + "mana": { + "min": 1, + "max": 18 + }, + "health": { + "min": 1, + "max": 16 + }, + "attack": { + "min": 1, + "max": 16 + } + }, + "stats": { + "seven_day_volume": 270.564697067863, + "seven_day_change": -0.014179906699531201, + "total_volume": 11825.0384171324, + "count": 6835331, + "num_owners": 10791, + "market_cap": 150892.14138332763, + "average_price": 0.0396514694030496, + "items_sold": 298233 + }, + "banner_image_url": null, + "chat_url": null, + "created_date": "2019-11-13T03:01:42.051246", + "default_to_fiat": false, + "description": "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", + "dev_buyer_fee_basis_points": "0", + "dev_seller_fee_basis_points": "0", + "display_data": { + "images": [ + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/25233.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/152875.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/25669.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9237.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9228.png", + "https://storage.googleapis.com/opensea-prod.appspot.com/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab/9231.png" + ], + "card_display_style": "contain" + }, + "external_url": "https://godsunchained.com/?refcode=0x5b3256965e7C3cF26E11FCAf296DfC8807C01073", + "featured": true, + "featured_image_url": "https://storage.opensea.io/0x6ebeaf8e8e946f0716e6533a6f2cefc83f60e8ab-featured-1556589419.png", + "hidden": false, + "image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", + "is_subject_to_whitelist": false, + "large_image_url": "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ", + "name": "Gods Unchained", + "only_proxied_transfers": false, + "opensea_buyer_fee_basis_points": "0", + "opensea_seller_fee_basis_points": "250", + "payout_address": null, + "require_email": false, + "short_description": null, + "slug": "gods-unchained", + "wiki_url": null, + "owned_asset_count": 535 + } +] diff --git a/platform/ethereum/transaction_test.go b/platform/ethereum/transaction_test.go index abf0c312b..7f165e8bd 100644 --- a/platform/ethereum/transaction_test.go +++ b/platform/ethereum/transaction_test.go @@ -1,11 +1,28 @@ package ethereum import ( + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" ) +type Client string + +var ( + tx = blockatlas.Tx{ + ID: "1", + Coin: 60, + From: "A", + To: "B", + } + page = blockatlas.TxPage([]blockatlas.Tx{tx}) + c Client +) + +func getTxClientMock() EthereumClient { + return &c +} func TestPlatform_GetTokenTxsByAddress(t *testing.T) { p := Platform{ client: getTxClientMock(), @@ -26,35 +43,6 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { assert.Equal(t, page, resp) } -func getTxClientMock() EthereumClient { - return &c -} - -var tx = blockatlas.Tx{ - ID: "1", - Coin: 60, - From: "A", - To: "B", - Fee: "", - Date: 0, - Block: 0, - Status: "", - Error: "", - Sequence: 0, - Type: "", - Inputs: nil, - Outputs: nil, - Direction: "", - Memo: "", - Meta: nil, -} - -var page = blockatlas.TxPage([]blockatlas.Tx{tx}) - -type Client string - -var c Client - func (c Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) { txs := make([]blockatlas.Tx, 0) txs = append(txs, tx) @@ -66,12 +54,15 @@ func (c Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas.T txs = append(txs, tx) return txs, nil } + func (c Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) { return blockatlas.TokenPage{}, nil } + func (c Client) GetCurrentBlockNumber() (int64, error) { return 0, nil } + func (c Client) GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, error) { return nil, nil } diff --git a/platform/ethereum/trustray/token_test.go b/platform/ethereum/trustray/token_test.go index 6bdff93a3..64599ca6c 100644 --- a/platform/ethereum/trustray/token_test.go +++ b/platform/ethereum/trustray/token_test.go @@ -1,11 +1,12 @@ package trustray import ( - "bytes" "encoding/json" - "github.com/trustwallet/golibs/tokentype" "testing" + "github.com/stretchr/testify/assert" + "github.com/trustwallet/golibs/tokentype" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" ) @@ -160,9 +161,5 @@ func testNormalizeToken(t *testing.T, _test *testToken) { t.Fatal(err) } - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error("token: token don't equal") - } + assert.JSONEq(t, string(resJSON), string(dstJSON)) } diff --git a/platform/ethereum/trustray/transaction_test.go b/platform/ethereum/trustray/transaction_test.go index 5258c956d..bef1f3a9f 100644 --- a/platform/ethereum/trustray/transaction_test.go +++ b/platform/ethereum/trustray/transaction_test.go @@ -1,11 +1,12 @@ package trustray import ( - "bytes" "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" ) const tokenTransferSrc = ` @@ -218,12 +219,7 @@ func TestNormalize(t *testing.T) { t.Fatal(err) } - if !bytes.Equal(resJSON, dstJSON) { - println("\n", "Test failed ", tt.name) - println("resJSON", string(resJSON)) - println("dstJSON", string(dstJSON)) - t.Error(tt.name + ": tx don't equal") - } + assert.JSONEq(t, string(resJSON), string(dstJSON)) } }) } diff --git a/platform/filecoin/block.go b/platform/filecoin/block.go index 3bb9f2b6b..a020dd606 100644 --- a/platform/filecoin/block.go +++ b/platform/filecoin/block.go @@ -55,6 +55,7 @@ func normalizeBlockTx(num, timestamp uint64, msg rpc.SecpkMessage) blockatlas.Tx Status: blockatlas.StatusCompleted, Sequence: uint64(msg.Message.Nonce), Type: blockatlas.TxTransfer, + Memo: "", Meta: blockatlas.Transfer{ Value: blockatlas.Amount(msg.Message.Value), Symbol: coin.Filecoin().Symbol, diff --git a/platform/filecoin/block_test.go b/platform/filecoin/block_test.go index fdfee400c..278ed8395 100644 --- a/platform/filecoin/block_test.go +++ b/platform/filecoin/block_test.go @@ -77,9 +77,9 @@ func TestPlatform_GetBlockByNumber(t *testing.T) { p := Init(server.URL, "") block, err := p.GetBlockByNumber(243590) assert.Nil(t, err) - raw, err := json.Marshal(block) - assert.Nil(t, err) - assert.Equal(t, wantedResponse, string(raw)) -} -const wantedResponse = `{"number":243590,"txs":[{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f029223","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246187,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f026582","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246188,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f029084","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246189,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f026721","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246190,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f027694","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246191,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028389","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246192,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f027138","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246193,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028945","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246194,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028250","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246195,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f027555","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246196,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f026860","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246197,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028806","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246198,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f026999","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246199,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028528","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246200,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq","to":"f028667","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":246201,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}},{"id":"","coin":461,"from":"f1i5kvaeurfv27jncddyvcuzgegm4j46y5u7okcza","to":"f2mgv6khl6s6oukeyi3nm3ja67s7fl3cecy2stvny","fee":"0","date":1605614100,"block":243590,"status":"completed","sequence":2,"type":"transfer","memo":"","metadata":{"value":"0","symbol":"FIL","decimals":18}}]}` + blockJson, _ := json.Marshal(block) + wanted, _ := mock.JsonFromFilePathToString("mocks/response.json") + + assert.JSONEq(t, string(blockJson), wanted) +} diff --git a/platform/filecoin/mocks/response.json b/platform/filecoin/mocks/response.json new file mode 100644 index 000000000..9e8f1952b --- /dev/null +++ b/platform/filecoin/mocks/response.json @@ -0,0 +1,229 @@ +{ + "number": 243590, + "txs": [ + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f029223", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246187, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f026582", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246188, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f029084", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246189, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f026721", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246190, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f027694", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246191, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f028389", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246192, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f027138", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246193, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f028945", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246194, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f028250", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246195, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f027555", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246196, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f026860", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246197, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f028806", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246198, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f026999", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246199, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f028528", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246200, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f13sb4pa34qzf35txnan4fqjfkwwqgldz6ekh5trq", + "to": "f028667", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 246201, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + }, + { + "id": "", + "coin": 461, + "from": "f1i5kvaeurfv27jncddyvcuzgegm4j46y5u7okcza", + "to": "f2mgv6khl6s6oukeyi3nm3ja67s7fl3cecy2stvny", + "fee": "0", + "date": 1605614100, + "block": 243590, + "status": "completed", + "sequence": 2, + "type": "transfer", + "memo": "", + "metadata": { "value": "0", "symbol": "FIL", "decimals": 18 } + } + ] +} diff --git a/platform/fio/actor_test.go b/platform/fio/actor_test.go index df2db0fcc..3580b92ad 100644 --- a/platform/fio/actor_test.go +++ b/platform/fio/actor_test.go @@ -2,8 +2,9 @@ package fio import ( "encoding/hex" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestActorFromPublicKey(t *testing.T) { diff --git a/platform/harmony/mocks/delegation.json b/platform/harmony/mocks/delegation.json new file mode 100644 index 000000000..bba639e7e --- /dev/null +++ b/platform/harmony/mocks/delegation.json @@ -0,0 +1,9 @@ +[ + { + "validator_address": "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", + "delegator_address": "one1pf75h0t4am90z8uv3y0dgunfqp4lj8wr3t5rsp", + "amount": 12345678900000000000, + "reward": 15854399877248931866418, + "Undelegations": [] + } +] diff --git a/platform/harmony/mocks/transfer.json b/platform/harmony/mocks/transfer.json new file mode 100644 index 000000000..898ac8de9 --- /dev/null +++ b/platform/harmony/mocks/transfer.json @@ -0,0 +1,19 @@ +{ + "blockHash": "0x0bde901cd3599aa082482777fd0a7fed3f02b7b5a9096b7ea7b2fcb8addaa05d", + "blockNumber": "0x12", + "from": "one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7", + "gas": "0x5208", + "gasPrice": "0x3b9aca00", + "hash": "0x230798fe22abff459b004675bf827a4089326a296fa4165d0c2ad27688e03e0c", + "input": "0x", + "nonce": "0x0", + "to": "one129r9pj3sk0re76f7zs3qz92rggmdgjhtwge62k", + "transactionIndex": "0x1", + "value": "0x16345785d8a0000", + "shardID": 0, + "toShardID": 0, + "v": "0x27", + "r": "0x57766aa1304e97f8b71a9fa54a61b61ce8ef9ad177fcb337dd81827aad184327", + "s": "0x3b3e5767899e8af5e75d62243a725371f08705b91e2305459e6fd8e8d2646651", + "timestamp": "0x5DF5234E" +} diff --git a/platform/harmony/mocks/validator.json b/platform/harmony/mocks/validator.json new file mode 100644 index 000000000..68f61ca0c --- /dev/null +++ b/platform/harmony/mocks/validator.json @@ -0,0 +1,65 @@ +{ + "validator": { + "bls-public-keys": [ + "29fb5d202e2f6f7955b425dc706fc0b29047067e51ba583fbb017c0f51186d5e1eaf6dd4059848be311ab5a49d625309" + ], + "last-epoch-in-committee": 18, + "min-self-delegation": 10999000000000000000000, + "max-total-delegation": 100000000000000000000000000, + "rate": "0.100000000000000000", + "max-rate": "0.100000000000000000", + "max-change-rate": "0.100000000000000000", + "update-height": 88, + "name": "sieemma node", + "identity": "sieemma node by ankr", + "website": "www.ankr.com", + "security-contact": "info@ankr.com", + "details": "This validator is launched from app.ankr.com", + "creation-height": 88, + "address": "one1v8pukmelacy3xdap773rpg5pax3tmu40wmwr2j", + "delegations": [ + { + "delegator-address": "one1v8pukmelacy3xdap773rpg5pax3tmu40wmwr2j", + "amount": 10999000000000000000000, + "reward": 2328233463148225437028, + "undelegations": [] + } + ] + }, + "current-epoch-performance": { + "current-epoch-signing-percent": { + "current-epoch-signed": 3, + "current-epoch-to-sign": 3, + "num-beacon-blocks-until-next-epoch": 37, + "current-epoch-signing-percentage": "1.000000000000000000" + } + }, + "metrics": { + "by-bls-key": [ + { + "key": { + "bls-public-key": "29fb5d202e2f6f7955b425dc706fc0b29047067e51ba583fbb017c0f51186d5e1eaf6dd4059848be311ab5a49d625309", + "group-percent": "0.056856187290969900", + "effective-stake": "85000000000000000000000.000000000000000000", + "earning-account": "one1v8pukmelacy3xdap773rpg5pax3tmu40wmwr2j", + "overall-percent": "0.018193979933110368", + "shard-id": 1 + }, + "earned-reward": 4478494623655913952 + } + ] + }, + "total-delegation": 10999000000000000000000, + "currently-in-committee": true, + "epos-status": "currently elected", + "epos-winning-stake": "85000000000000000000000.000000000000000000", + "booted-status": null, + "lifetime": { + "reward-accumulated": 2328233463148225437028, + "blocks": { + "to-sign": 525, + "signed": 504 + }, + "apr": "12.345" + } +} diff --git a/platform/harmony/stake_test.go b/platform/harmony/stake_test.go index e98f9d3ac..1e5ef9f0f 100644 --- a/platform/harmony/stake_test.go +++ b/platform/harmony/stake_test.go @@ -7,85 +7,33 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/mock" ) -const validatorSrc = ` - { - "validator": { - "bls-public-keys": [ - "29fb5d202e2f6f7955b425dc706fc0b29047067e51ba583fbb017c0f51186d5e1eaf6dd4059848be311ab5a49d625309" - ], - "last-epoch-in-committee": 18, - "min-self-delegation": 10999000000000000000000, - "max-total-delegation": 100000000000000000000000000, - "rate": "0.100000000000000000", - "max-rate": "0.100000000000000000", - "max-change-rate": "0.100000000000000000", - "update-height": 88, - "name": "sieemma node", - "identity": "sieemma node by ankr", - "website": "www.ankr.com", - "security-contact": "info@ankr.com", - "details": "This validator is launched from app.ankr.com", - "creation-height": 88, - "address": "one1v8pukmelacy3xdap773rpg5pax3tmu40wmwr2j", - "delegations": [ - { - "delegator-address": "one1v8pukmelacy3xdap773rpg5pax3tmu40wmwr2j", - "amount": 10999000000000000000000, - "reward": 2328233463148225437028, - "undelegations": [] - } - ] - }, - "current-epoch-performance": { - "current-epoch-signing-percent": { - "current-epoch-signed": 3, - "current-epoch-to-sign": 3, - "num-beacon-blocks-until-next-epoch": 37, - "current-epoch-signing-percentage": "1.000000000000000000" - } - }, - "metrics": { - "by-bls-key": [ - { - "key": { - "bls-public-key": "29fb5d202e2f6f7955b425dc706fc0b29047067e51ba583fbb017c0f51186d5e1eaf6dd4059848be311ab5a49d625309", - "group-percent": "0.056856187290969900", - "effective-stake": "85000000000000000000000.000000000000000000", - "earning-account": "one1v8pukmelacy3xdap773rpg5pax3tmu40wmwr2j", - "overall-percent": "0.018193979933110368", - "shard-id": 1 - }, - "earned-reward": 4478494623655913952 - } - ] - }, - "total-delegation": 10999000000000000000000, - "currently-in-committee": true, - "epos-status": "currently elected", - "epos-winning-stake": "85000000000000000000000.000000000000000000", - "booted-status": null, - "lifetime": { - "reward-accumulated": 2328233463148225437028, - "blocks": { - "to-sign": 525, - "signed": 504 - }, - "apr": "12.345" +var ( + validatorSrc, _ = mock.JsonFromFilePathToString("mocks/" + "validator.json") + delegationsSrc, _ = mock.JsonFromFilePathToString("mocks/" + "delegation.json") + validatorMap = blockatlas.ValidatorMap{ + "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy": validator1, } -}` - -const delegationsSrc = ` -[ - { - "validator_address": "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", - "delegator_address": "one1pf75h0t4am90z8uv3y0dgunfqp4lj8wr3t5rsp", - "amount": 12345678900000000000, - "reward": 15854399877248931866418, - "Undelegations": [] + validator1 = blockatlas.StakeValidator{ + ID: "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "Harmony One", + Description: "Stake and earn rewards with the most secure and stable validator. Operated by Harmony One Inc.", + Image: "https://assets.trustwalletapp.com/blockchains/harmony/validators/assets/one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy/logo.png", + Website: "https://harmony.one", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 10, + }, + LockTime: 0, + MinimumAmount: "0", + }, } -]` +) func TestNormalizeValidator(t *testing.T) { var v Validator @@ -111,28 +59,6 @@ func TestNormalizeValidator(t *testing.T) { assert.Equal(t, expected, result) } -var validator1 = blockatlas.StakeValidator{ - ID: "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", - Status: true, - Info: blockatlas.StakeValidatorInfo{ - Name: "Harmony One", - Description: "Stake and earn rewards with the most secure and stable validator. Operated by Harmony One Inc.", - Image: "https://assets.trustwalletapp.com/blockchains/harmony/validators/assets/one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy/logo.png", - Website: "https://harmony.one", - }, - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{ - Annual: 10, - }, - LockTime: 0, - MinimumAmount: "0", - }, -} - -var validatorMap = blockatlas.ValidatorMap{ - "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy": validator1, -} - func TestNormalizeDelegations(t *testing.T) { var delegations []Delegation err := json.Unmarshal([]byte(delegationsSrc), &delegations) @@ -176,7 +102,7 @@ func TestGetValidators(t *testing.T) { } var validators = []Validator{ - Validator{ + { Info: ValidatorInfo{ Address: "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", }, @@ -204,7 +130,7 @@ func TestGetDelegation(t *testing.T) { } var delegations = []Delegation{ - Delegation{ + { DelegatorAddress: "one1a0au0p33zrns49h3qw7prn02s4wphu0ggcqrhm", ValidatorAddress: "one1a0au0p33zrns49h3qw7prn02s4wphu0ggcqrhm", Amount: 100, @@ -212,7 +138,7 @@ func TestGetDelegation(t *testing.T) { } var validators = []Validator{ - Validator{ + { Info: ValidatorInfo{ Address: "one1a0au0p33zrns49h3qw7prn02s4wphu0ggcqrhm", }, diff --git a/platform/harmony/transaction_test.go b/platform/harmony/transaction_test.go index 75861f29b..0def9f830 100644 --- a/platform/harmony/transaction_test.go +++ b/platform/harmony/transaction_test.go @@ -1,78 +1,65 @@ package harmony import ( - "bytes" - "encoding/json" + "reflect" + "testing" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" + "github.com/trustwallet/golibs/mock" ) -const transferSrc = ` -{ - "blockHash": "0x0bde901cd3599aa082482777fd0a7fed3f02b7b5a9096b7ea7b2fcb8addaa05d", - "blockNumber": "0x12", - "from": "one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7", - "gas": "0x5208", - "gasPrice": "0x3b9aca00", - "hash": "0x230798fe22abff459b004675bf827a4089326a296fa4165d0c2ad27688e03e0c", - "input": "0x", - "nonce": "0x0", - "to": "one129r9pj3sk0re76f7zs3qz92rggmdgjhtwge62k", - "transactionIndex": "0x1", - "value": "0x16345785d8a0000", - "shardID": 0, - "toShardID": 0, - "v": "0x27", - "r": "0x57766aa1304e97f8b71a9fa54a61b61ce8ef9ad177fcb337dd81827aad184327", - "s": "0x3b3e5767899e8af5e75d62243a725371f08705b91e2305459e6fd8e8d2646651", - "timestamp": "0x5DF5234E" -} -` - -var transferDst = blockatlas.Tx{ - ID: "0x230798fe22abff459b004675bf827a4089326a296fa4165d0c2ad27688e03e0c", - Coin: coin.ONE, - From: "one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7", - To: "one129r9pj3sk0re76f7zs3qz92rggmdgjhtwge62k", - Fee: "21000000000000", - Date: 1576346446, - Block: 18, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: "100000000000000000", - Symbol: "ONE", - Decimals: 18, - }, -} - -func TestNormalize(t *testing.T) { - var srcTx Transaction - err := json.Unmarshal([]byte(transferSrc), &srcTx) - if err != nil { - t.Error(err) - return +func TestNormalizeTx(t *testing.T) { + type args struct { + filename string } - - resTx, isGood, err := NormalizeTx(&srcTx) - - if !isGood || err != nil { - t.Fatal() - } - - resJSON, err := json.Marshal(&resTx) - if err != nil { - t.Fatal(err) + tests := []struct { + name string + args args + wantTx blockatlas.Tx + wantB bool + wantErr bool + }{ + { + name: "Test normalize transaction", + args: args{ + filename: "transfer.json", + }, + wantTx: blockatlas.Tx{ + ID: "0x230798fe22abff459b004675bf827a4089326a296fa4165d0c2ad27688e03e0c", + Coin: coin.ONE, + From: "one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7", + To: "one129r9pj3sk0re76f7zs3qz92rggmdgjhtwge62k", + Fee: "21000000000000", + Date: 1576346446, + Block: 18, + Type: blockatlas.TxTransfer, + Status: blockatlas.StatusCompleted, + Meta: blockatlas.Transfer{ + Value: "100000000000000000", + Symbol: "ONE", + Decimals: 18, + }, + }, + wantB: true, + wantErr: false, + }, } - - dstJSON, err := json.Marshal(&transferDst) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error("tx don't equal") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx Transaction + _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + gotTx, gotB, err := NormalizeTx(&srcTx) + if (err != nil) != tt.wantErr { + t.Errorf("NormalizeTx() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotTx, tt.wantTx) { + t.Errorf("NormalizeTx() gotTx = %v, want %v", gotTx, tt.wantTx) + } + if gotB != tt.wantB { + t.Errorf("NormalizeTx() gotB = %v, want %v", gotB, tt.wantB) + } + }) } } diff --git a/platform/icon/mocks/transfer.json b/platform/icon/mocks/transfer.json new file mode 100644 index 000000000..b8a31426a --- /dev/null +++ b/platform/icon/mocks/transfer.json @@ -0,0 +1,14 @@ +{ + "txHash": "0x34b8b6ec3a52710c24074f5e298f4a9c67bb61a0a1dde20e695efaeb30ff3754", + "height": 357832, + "createDate": "2019-04-16T06:36:34.000+0000", + "fromAddr": "hx1b8959dd5c57d2c502e22ee0a887d33baec09091", + "toAddr": "cx334db6519871cb2bfd154cec0905ced4ea142de1", + "txType": "1", + "dataType": "call", + "amount": "0.00347", + "fee": "0.0017476", + "state": 1, + "targetContractAddr": "cx334db6519871cb2bfd154cec0905ced4ea142de1", + "id": 730841 +} diff --git a/platform/icon/transaction_test.go b/platform/icon/transaction_test.go index df7735627..758b4e2fb 100644 --- a/platform/icon/transaction_test.go +++ b/platform/icon/transaction_test.go @@ -1,68 +1,60 @@ package icon import ( - "bytes" - "encoding/json" + "reflect" + "testing" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" + "github.com/trustwallet/golibs/mock" ) -const basicSrc = ` -{ - "txHash": "0x34b8b6ec3a52710c24074f5e298f4a9c67bb61a0a1dde20e695efaeb30ff3754", - "height": 357832, - "createDate": "2019-04-16T06:36:34.000+0000", - "fromAddr": "hx1b8959dd5c57d2c502e22ee0a887d33baec09091", - "toAddr": "cx334db6519871cb2bfd154cec0905ced4ea142de1", - "txType": "1", - "dataType": "call", - "amount": "0.00347", - "fee": "0.0017476", - "state": 1, - "targetContractAddr": "cx334db6519871cb2bfd154cec0905ced4ea142de1", - "id": 730841 -} -` - -var basicDst = blockatlas.Tx{ - ID: "0x34b8b6ec3a52710c24074f5e298f4a9c67bb61a0a1dde20e695efaeb30ff3754", - Coin: coin.ICX, - From: "hx1b8959dd5c57d2c502e22ee0a887d33baec09091", - To: "cx334db6519871cb2bfd154cec0905ced4ea142de1", - Fee: "1747600000000000", - Date: 1555396594, - Block: 357832, - Meta: blockatlas.Transfer{ - Value: "3470000000000000", - Symbol: "ICX", - Decimals: 18, - }, -} - -func TestNormalize(t *testing.T) { - var srcTx Tx - err := json.Unmarshal([]byte(basicSrc), &srcTx) - - if err != nil { - t.Error(err) - return - } - - tx, _ := Normalize(&srcTx) - resJSON, err := json.Marshal(&tx) - if err != nil { - t.Fatal(err) +func TestNormalizeTx(t *testing.T) { + type args struct { + filename string } - - dstJSON, err := json.Marshal(&basicDst) - if err != nil { - t.Fatal(err) + tests := []struct { + name string + args args + wantTx blockatlas.Tx + ok bool + }{ + { + name: "Test normalize transaction", + args: args{ + filename: "transfer.json", + }, + wantTx: blockatlas.Tx{ + ID: "0x34b8b6ec3a52710c24074f5e298f4a9c67bb61a0a1dde20e695efaeb30ff3754", + Coin: coin.ICX, + From: "hx1b8959dd5c57d2c502e22ee0a887d33baec09091", + To: "cx334db6519871cb2bfd154cec0905ced4ea142de1", + Fee: "1747600000000000", + Date: 1555396594, + Block: 357832, + Status: "completed", + Type: "transfer", + Meta: blockatlas.Transfer{ + Value: "3470000000000000", + Symbol: "ICX", + Decimals: 18, + }, + }, + ok: true, + }, } - - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error("Transactions not equal") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx Tx + _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + gotTx, ok := Normalize(&srcTx) + if ok != tt.ok { + t.Errorf("Normalize() ok = %v, wantOk %v", ok, tt.ok) + return + } + if !reflect.DeepEqual(gotTx, tt.wantTx) { + t.Errorf("Normalize() gotTx = %v, want %v", gotTx, tt.wantTx) + } + }) } } diff --git a/platform/iotex/mocks/transfer.json b/platform/iotex/mocks/transfer.json new file mode 100644 index 000000000..3f223135b --- /dev/null +++ b/platform/iotex/mocks/transfer.json @@ -0,0 +1,70 @@ +{ + "actionInfo": [ + { + "action": { + "core": { + "version": 1, + "nonce": "3", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "21000000000000000000", + "recipient": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" + } + }, + "senderPubKey": "BKCXbZcntIxrdPFZdWratLOfKU2yUUc0LuF/ilB3JoQzd/mvXaUbPuBpIE/sUtxGo0YxcAcN0cylCo1EIPQwJqc=", + "signature": "V4JBmqjFU+UmdVKQZ1+2CVElZ8sUMz1m0wfJEE5J7hFAG72nD2oI0wrLnTGBM0CaD1BjNGJvELYKi/g5IvO3AgE=" + }, + "actHash": "109b75cb688a5347268cbf11b20fa90fd0a14e92a42ba735c046bbf1a6e66ad7", + "blkHash": "42ace162549ec8d44641d7da7184d1e12ebd4111b0d2888a2d97d88a7c4fa04b", + "blkHeight": "96202", + "sender": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", + "gasFee": "10000000000000000", + "timestamp": "2019-05-03T06:09:00Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "3", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "21000000000000000000", + "recipient": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" + } + }, + "senderPubKey": "BKCXbZcntIxrdPFZdWratLOfKU2yUUc0LuF/ilB3JoQzd/mvXaUbPuBpIE/sUtxGo0YxcAcN0cylCo1EIPQwJqc=", + "signature": "V4JBmqjFU+UmdVKQZ1+2CVElZ8sUMz1m0wfJEE5J7hFAG72nD2oI0wrLnTGBM0CaD1BjNGJvELYKi/g5IvO3AgE=" + }, + "actHash": "109b75cb688a5347268cbf11b20fa90fd0a14e92a42ba735c046bbf1a6e66ad7", + "blkHash": "42ace162549ec8d44641d7da7184d1e12ebd4111b0d2888a2d97d88a7c4fa04b", + "blkHeight": "0", + "sender": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", + "gasFee": "10000000000000000", + "timestamp": "2019-05-03T06:09:00Z" + }, + { + "action": { + "core": { + "version": 1, + "nonce": "3.1", + "gasLimit": "10000", + "gasPrice": "1000000000000", + "transfer": { + "amount": "21000000000000000000", + "recipient": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" + } + }, + "senderPubKey": "BKCXbZcntIxrdPFZdWratLOfKU2yUUc0LuF/ilB3JoQzd/mvXaUbPuBpIE/sUtxGo0YxcAcN0cylCo1EIPQwJqc=", + "signature": "V4JBmqjFU+UmdVKQZ1+2CVElZ8sUMz1m0wfJEE5J7hFAG72nD2oI0wrLnTGBM0CaD1BjNGJvELYKi/g5IvO3AgE=" + }, + "actHash": "109b75cb688a5347268cbf11b20fa90fd0a14e92a42ba735c046bbf1a6e66ad7", + "blkHash": "42ace162549ec8d44641d7da7184d1e12ebd4111b0d2888a2d97d88a7c4fa04b", + "blkHeight": "96202", + "sender": "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", + "gasFee": "10000000000000000", + "timestamp": "2019-05-03T06:09:00Z" + } + ] +} diff --git a/platform/iotex/transaction.go b/platform/iotex/transaction.go index 9b2ad9c3d..e80a39eb8 100644 --- a/platform/iotex/transaction.go +++ b/platform/iotex/transaction.go @@ -1,10 +1,11 @@ package iotex import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "strconv" "time" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" ) diff --git a/platform/iotex/transaction_test.go b/platform/iotex/transaction_test.go index 717fd4e6e..d23c1638c 100644 --- a/platform/iotex/transaction_test.go +++ b/platform/iotex/transaction_test.go @@ -1,131 +1,61 @@ package iotex import ( - "encoding/json" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "reflect" "testing" - "github.com/stretchr/testify/assert" - + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" ) -const ( - transfer = ` -{ - "actionInfo": - [ - { - "action": - { - "core": - { - "version":1, - "nonce":"3", - "gasLimit":"10000", - "gasPrice":"1000000000000", - "transfer": - { - "amount":"21000000000000000000", - "recipient":"io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" - } - }, - "senderPubKey":"BKCXbZcntIxrdPFZdWratLOfKU2yUUc0LuF/ilB3JoQzd/mvXaUbPuBpIE/sUtxGo0YxcAcN0cylCo1EIPQwJqc=", - "signature":"V4JBmqjFU+UmdVKQZ1+2CVElZ8sUMz1m0wfJEE5J7hFAG72nD2oI0wrLnTGBM0CaD1BjNGJvELYKi/g5IvO3AgE=" - }, - "actHash":"109b75cb688a5347268cbf11b20fa90fd0a14e92a42ba735c046bbf1a6e66ad7", - "blkHash":"42ace162549ec8d44641d7da7184d1e12ebd4111b0d2888a2d97d88a7c4fa04b", - "blkHeight":"96202", - "sender":"io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", - "gasFee":"10000000000000000", - "timestamp":"2019-05-03T06:09:00Z" - }, - { - "action": - { - "core": - { - "version":1, - "nonce":"3", - "gasLimit":"10000", - "gasPrice":"1000000000000", - "transfer": - { - "amount":"21000000000000000000", - "recipient":"io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" - } - }, - "senderPubKey":"BKCXbZcntIxrdPFZdWratLOfKU2yUUc0LuF/ilB3JoQzd/mvXaUbPuBpIE/sUtxGo0YxcAcN0cylCo1EIPQwJqc=", - "signature":"V4JBmqjFU+UmdVKQZ1+2CVElZ8sUMz1m0wfJEE5J7hFAG72nD2oI0wrLnTGBM0CaD1BjNGJvELYKi/g5IvO3AgE=" - }, - "actHash":"109b75cb688a5347268cbf11b20fa90fd0a14e92a42ba735c046bbf1a6e66ad7", - "blkHash":"42ace162549ec8d44641d7da7184d1e12ebd4111b0d2888a2d97d88a7c4fa04b", - "blkHeight":"0", - "sender":"io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", - "gasFee":"10000000000000000", - "timestamp":"2019-05-03T06:09:00Z" - }, - { - "action": - { - "core": - { - "version":1, - "nonce":"3.1", - "gasLimit":"10000", - "gasPrice":"1000000000000", - "transfer": - { - "amount":"21000000000000000000", - "recipient":"io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m" - } - }, - "senderPubKey":"BKCXbZcntIxrdPFZdWratLOfKU2yUUc0LuF/ilB3JoQzd/mvXaUbPuBpIE/sUtxGo0YxcAcN0cylCo1EIPQwJqc=", - "signature":"V4JBmqjFU+UmdVKQZ1+2CVElZ8sUMz1m0wfJEE5J7hFAG72nD2oI0wrLnTGBM0CaD1BjNGJvELYKi/g5IvO3AgE=" - }, - "actHash":"109b75cb688a5347268cbf11b20fa90fd0a14e92a42ba735c046bbf1a6e66ad7", - "blkHash":"42ace162549ec8d44641d7da7184d1e12ebd4111b0d2888a2d97d88a7c4fa04b", - "blkHeight":"96202", - "sender":"io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", - "gasFee":"10000000000000000", - "timestamp":"2019-05-03T06:09:00Z" - } - ] -} -` -) - -var expected = []*blockatlas.Tx{ - { - ID: "109b75cb688a5347268cbf11b20fa90fd0a14e92a42ba735c046bbf1a6e66ad7", - Coin: coin.IOTX, - From: "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", - To: "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", - Fee: blockatlas.Amount("10000000000000000"), - Date: int64(1556863740), - Block: 96202, - Status: blockatlas.StatusCompleted, - Sequence: uint64(3), - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("21000000000000000000"), - Symbol: "IOTX", - Decimals: 18, - }, - }, - nil, - nil, -} - func TestNormalize(t *testing.T) { - a := assert.New(t) - - var act Response - a.NoError(json.Unmarshal([]byte(transfer), &act)) - a.Equal(3, len(act.ActionInfo)) + type args struct { + filename string + } + tests := []struct { + name string + args args + want []*blockatlas.Tx + }{ + { + name: "Test normalize actions", + args: args{ + filename: "transfer.json", + }, + want: []*blockatlas.Tx{ + { + ID: "109b75cb688a5347268cbf11b20fa90fd0a14e92a42ba735c046bbf1a6e66ad7", + Coin: coin.IOTX, + From: "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", + To: "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", + Fee: blockatlas.Amount("10000000000000000"), + Date: int64(1556863740), + Block: 96202, + Status: blockatlas.StatusCompleted, + Sequence: uint64(3), + Type: blockatlas.TxTransfer, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("21000000000000000000"), + Symbol: "IOTX", + Decimals: 18, + }, + }, + nil, + nil, + }, + }, + } - for i, v := range act.ActionInfo { - tx := Normalize(v) - a.Equal(expected[i], tx) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var response Response + _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &response) + for i, v := range response.ActionInfo { + if got := Normalize(v); !reflect.DeepEqual(got, tt.want[i]) { + t.Errorf("Normalize() = %v, want %v", got, tt.want[i]) + } + } + }) } } diff --git a/platform/kava/transaction_test.go b/platform/kava/transaction_test.go index c5f9d07c9..662d1fcb8 100644 --- a/platform/kava/transaction_test.go +++ b/platform/kava/transaction_test.go @@ -2,9 +2,10 @@ package kava import ( "encoding/json" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" "github.com/trustwallet/golibs/coin" ) diff --git a/platform/nebulas/mocks/transfer.json b/platform/nebulas/mocks/transfer.json new file mode 100644 index 000000000..f40d067d4 --- /dev/null +++ b/platform/nebulas/mocks/transfer.json @@ -0,0 +1,19 @@ +{ + "hash": "96bd280d60447b7dbcdb3fa76a99856e0422a76304e9d01d0c87e1dfceb6d952", + "block": { + "height": 2848548 + }, + "from": { + "hash": "n1Yv9xJJcH4UjoJPVDGdUCL2CxK29asFuyV" + }, + "to": { + "hash": "n1TFrmLUDTe5ggQaWJiXHSqNSRzKYdaV6hQ" + }, + "value": "500000000000000000", + "nonce": 7, + "status": 1, + "timestamp": 1565213205000, + "type": "binary", + "currentTimestamp": 1565361175536, + "txFee": "400000000000000" +} diff --git a/platform/nebulas/transaction_test.go b/platform/nebulas/transaction_test.go index c809ad5ea..fa38c7e02 100644 --- a/platform/nebulas/transaction_test.go +++ b/platform/nebulas/transaction_test.go @@ -1,84 +1,54 @@ package nebulas import ( - "bytes" - "encoding/json" - "github.com/stretchr/testify/assert" + "reflect" + "testing" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" + "github.com/trustwallet/golibs/mock" ) -const transferSrc = ` -{ - "hash": "96bd280d60447b7dbcdb3fa76a99856e0422a76304e9d01d0c87e1dfceb6d952", - "block": { - "height": 2848548 - }, - "from": { - "hash": "n1Yv9xJJcH4UjoJPVDGdUCL2CxK29asFuyV" - }, - "to": { - "hash": "n1TFrmLUDTe5ggQaWJiXHSqNSRzKYdaV6hQ" - }, - "value": "500000000000000000", - "nonce": 7, - "status": 1, - "timestamp": 1565213205000, - "type": "binary", - "currentTimestamp": 1565361175536, - "txFee": "400000000000000" -}` - -var transferDst = blockatlas.Tx{ - ID: "96bd280d60447b7dbcdb3fa76a99856e0422a76304e9d01d0c87e1dfceb6d952", - Coin: coin.NAS, - From: "n1Yv9xJJcH4UjoJPVDGdUCL2CxK29asFuyV", - To: "n1TFrmLUDTe5ggQaWJiXHSqNSRzKYdaV6hQ", - Fee: "400000000000000", - Sequence: 7, - Date: 1565213205, - Block: 2848548, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: "500000000000000000", - Symbol: "NAS", - Decimals: 18, - }, -} - -func TestNormalize(t *testing.T) { - var srcTx Transaction - err := json.Unmarshal([]byte(transferSrc), &srcTx) - if err != nil { - t.Error(err) - return +func TestNormalizeTx(t *testing.T) { + type args struct { + filename string } - - resTx := NormalizeTx(srcTx) - - resJSON, err := json.Marshal(&resTx) - if err != nil { - t.Fatal(err) + tests := []struct { + name string + args args + wantTx blockatlas.Tx + }{ + { + name: "Test normalize transaction", + args: args{ + filename: "transfer.json", + }, + wantTx: blockatlas.Tx{ + ID: "96bd280d60447b7dbcdb3fa76a99856e0422a76304e9d01d0c87e1dfceb6d952", + Coin: coin.NAS, + From: "n1Yv9xJJcH4UjoJPVDGdUCL2CxK29asFuyV", + To: "n1TFrmLUDTe5ggQaWJiXHSqNSRzKYdaV6hQ", + Fee: "400000000000000", + Sequence: 7, + Date: 1565213205, + Block: 2848548, + Status: blockatlas.StatusCompleted, + Meta: blockatlas.Transfer{ + Value: "500000000000000000", + Symbol: "NAS", + Decimals: 18, + }, + }, + }, } - - dstJSON, err := json.Marshal(&transferDst) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error("tx don't equal") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx Transaction + _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + gotTx := NormalizeTx(srcTx) + if !reflect.DeepEqual(gotTx, tt.wantTx) { + t.Errorf("NormalizeTx() gotTx = %v, want %v", gotTx, tt.wantTx) + } + }) } } - -func TestNormalizeTxs(t *testing.T) { - txs := []Transaction{ - Transaction{}, - Transaction{}, - } - - assert.Equal(t, 2, len(NormalizeTxs(txs))) -} diff --git a/platform/nimiq/tests/getTransactionsByAddress_50.json b/platform/nimiq/mocks/getTransactionsByAddress_50.json similarity index 100% rename from platform/nimiq/tests/getTransactionsByAddress_50.json rename to platform/nimiq/mocks/getTransactionsByAddress_50.json diff --git a/platform/nimiq/mocks/pending_tx.json b/platform/nimiq/mocks/pending_tx.json new file mode 100644 index 000000000..56335f594 --- /dev/null +++ b/platform/nimiq/mocks/pending_tx.json @@ -0,0 +1,11 @@ +{ + "data": null, + "fee": 300, + "flags": 0, + "from": "d48182276127b149a9710e78c436fb4bc1c4dc0b", + "fromAddress": "NQ74 SJ0Q 49T1 4XQL KABH 1RUC 8DPT 9F0U 9P0B", + "hash": "79719d16f3f347cc98c35cd7a9af708cdce97de578b5135c5ae4393fd7920d61", + "to": "0a17218ffdc42385f45329ba4089919236dd2743", + "toAddress": "NQ97 18BJ 33YV QGHQ BV2K 56V4 12CH J8TD S9S3", + "value": 100000 +} diff --git a/platform/nimiq/mocks/tx.json b/platform/nimiq/mocks/tx.json new file mode 100644 index 000000000..cdbd29538 --- /dev/null +++ b/platform/nimiq/mocks/tx.json @@ -0,0 +1,16 @@ +{ + "hash": "8b219949f4c1dfe9e7a9cdc5dbbc507e40dc16f44a1a5182ed6125c9a6891a50", + "blockHash": "ab36a0909c6ed5761a984ef261d9c3456b7c1aea6a52d531c5bf2518526a32e6", + "blockNumber": 252575, + "timestamp": 1538924505, + "confirmations": 271245, + "transactionIndex": 37, + "from": "4a88aaad038f9b8248865c4b9249efc554960e16", + "fromAddress": "NQ69 9A4A MB83 HXDQ 4J46 BH5R 4JFF QMA9 C3GN", + "to": "ad25610feb43d75307763d3f010822a757027429", + "toAddress": "NQ15 MLJN 23YB 8FBM 61TN 7LYG 2212 LVBG 4V19", + "value": 10000000000000, + "fee": 138, + "data": null, + "flags": 0 +} diff --git a/platform/nimiq/transaction_test.go b/platform/nimiq/transaction_test.go index 40528b8b4..27f737ef7 100644 --- a/platform/nimiq/transaction_test.go +++ b/platform/nimiq/transaction_test.go @@ -2,54 +2,22 @@ package nimiq import ( "encoding/json" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/coin" - "io/ioutil" + "fmt" "math" - "path/filepath" - "runtime" "sort" "testing" "time" -) -const ( - basicSrc = ` -{ - "hash": "8b219949f4c1dfe9e7a9cdc5dbbc507e40dc16f44a1a5182ed6125c9a6891a50", - "blockHash": "ab36a0909c6ed5761a984ef261d9c3456b7c1aea6a52d531c5bf2518526a32e6", - "blockNumber": 252575, - "timestamp": 1538924505, - "confirmations": 271245, - "transactionIndex": 37, - "from": "4a88aaad038f9b8248865c4b9249efc554960e16", - "fromAddress": "NQ69 9A4A MB83 HXDQ 4J46 BH5R 4JFF QMA9 C3GN", - "to": "ad25610feb43d75307763d3f010822a757027429", - "toAddress": "NQ15 MLJN 23YB 8FBM 61TN 7LYG 2212 LVBG 4V19", - "value": 10000000000000, - "fee": 138, - "data": null, - "flags": 0 -} -` - pendingSrc = ` -{ - "data": null, - "fee": 300, - "flags": 0, - "from": "d48182276127b149a9710e78c436fb4bc1c4dc0b", - "fromAddress": "NQ74 SJ0Q 49T1 4XQL KABH 1RUC 8DPT 9F0U 9P0B", - "hash": "79719d16f3f347cc98c35cd7a9af708cdce97de578b5135c5ae4393fd7920d61", - "to": "0a17218ffdc42385f45329ba4089919236dd2743", - "toAddress": "NQ97 18BJ 33YV QGHQ BV2K 56V4 12CH J8TD S9S3", - "value": 100000 -} -` + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" ) var ( - basicDst = blockatlas.Tx{ + basicSrc, _ = mock.JsonFromFilePathToString("mocks/" + "tx.json") + pendingSrc, _ = mock.JsonFromFilePathToString("mocks/" + "pending_tx.json") + basicDst = blockatlas.Tx{ ID: "8b219949f4c1dfe9e7a9cdc5dbbc507e40dc16f44a1a5182ed6125c9a6891a50", Coin: coin.NIM, From: "NQ69 9A4A MB83 HXDQ 4J46 BH5R 4JFF QMA9 C3GN", @@ -94,6 +62,7 @@ func TestNormalizeTx1(t *testing.T) { var srcTx Tx err := json.Unmarshal([]byte(tt.srcTx), &srcTx) if err != nil { + fmt.Println(tt.srcTx) t.Error(err) return } @@ -108,16 +77,8 @@ func TestNormalizeTx1(t *testing.T) { } func TestNormalizeTxs_Ordering(t *testing.T) { - _, goFile, _, _ := runtime.Caller(0) - testFilePath := filepath.Join(filepath.Dir(goFile), "tests", "getTransactionsByAddress_50.json") - testFile, err := ioutil.ReadFile(testFilePath) - if err != nil { - t.Fatal(err) - } var srcTxs []Tx - if err := json.Unmarshal(testFile, &srcTxs); err != nil { - t.Fatal(err) - } + _ = mock.ParseJsonFromFilePath("mocks/getTransactionsByAddress_50.json", &srcTxs) txs := NormalizeTxs(srcTxs) if len(txs) != 4 { t.Fatalf("Unexpected count: %d", len(txs)) diff --git a/platform/ontology/mocks/block_response.json b/platform/ontology/mocks/block_response.json new file mode 100644 index 000000000..695272e3a --- /dev/null +++ b/platform/ontology/mocks/block_response.json @@ -0,0 +1,60 @@ +[ + { + "id": "266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb", + "coin": 1024, + "from": "AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE", + "to": "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + "fee": "10000000", + "date": 1580481541, + "block": 7707834, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "memo": "", + "metadata": { + "name": "Ontology Gas", + "symbol": "ONG", + "token_id": "ong", + "decimals": 9, + "value": "51000000000000", + "from": "AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE", + "to": "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx" + } + }, + { + "id": "2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd", + "coin": 1024, + "from": "ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz", + "to": "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + "fee": "10000000", + "date": 1580481541, + "block": 7707834, + "status": "completed", + "sequence": 0, + "type": "native_token_transfer", + "memo": "", + "metadata": { + "name": "Ontology Gas", + "symbol": "ONG", + "token_id": "ong", + "decimals": 9, + "value": "113200000000", + "from": "ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz", + "to": "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx" + } + }, + { + "id": "40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3", + "coin": 1024, + "from": "Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS", + "to": "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + "fee": "10000000", + "date": 1580481541, + "block": 7707834, + "status": "completed", + "sequence": 0, + "type": "transfer", + "memo": "", + "metadata": { "value": "10949", "symbol": "ONT", "decimals": 0 } + } +] diff --git a/platform/ontology/mocks/transfer_fee.json b/platform/ontology/mocks/transfer_fee.json new file mode 100644 index 000000000..aef03db36 --- /dev/null +++ b/platform/ontology/mocks/transfer_fee.json @@ -0,0 +1,18 @@ +{ + "tx_hash": "92a79aed526f31999e22d9e3912d4125d3f85ec3c63eede4b7dde4a041826095", + "tx_type": 209, + "tx_time": 1578902776, + "block_height": 7571071, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.01", + "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] +} diff --git a/platform/ontology/mocks/transfer_ong.json b/platform/ontology/mocks/transfer_ong.json new file mode 100644 index 000000000..3586eeb83 --- /dev/null +++ b/platform/ontology/mocks/transfer_ong.json @@ -0,0 +1,18 @@ +{ + "tx_hash": "e5946ba02f56e17c3709db2bc91f43f76ee3a359006586024daa5c4ad8c54e78", + "tx_type": 209, + "tx_time": 1577631515, + "block_height": 7457989, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "14.69", + "from_address": "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", + "to_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] +} diff --git a/platform/ontology/mocks/transfer_ont.json b/platform/ontology/mocks/transfer_ont.json new file mode 100644 index 000000000..77f8b5415 --- /dev/null +++ b/platform/ontology/mocks/transfer_ont.json @@ -0,0 +1,25 @@ +{ + "tx_hash": "ea0e5d8e389cb96760887094194ca359ac998b2f607be470a576861b91e2bf52", + "tx_type": 209, + "tx_time": 1578903628, + "block_height": 7571132, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "5", + "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "to_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "asset_name": "ont", + "contract_hash": "0100000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] +} diff --git a/platform/ontology/mocks/transfer_rewards.json b/platform/ontology/mocks/transfer_rewards.json new file mode 100644 index 000000000..b81ac4b7b --- /dev/null +++ b/platform/ontology/mocks/transfer_rewards.json @@ -0,0 +1,25 @@ +{ + "tx_hash": "d7554dcdf01f394b9107ff598df6d84e4c3b00ccf1e720b8c09abf085cbe4987", + "tx_type": 209, + "tx_time": 1579699532, + "block_height": 7644328, + "fee": "0.01", + "block_index": 1, + "confirm_flag": 1, + "transfers": [ + { + "amount": "0.03534404", + "from_address": "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", + "to_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + }, + { + "amount": "0.01", + "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", + "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", + "asset_name": "ong", + "contract_hash": "0200000000000000000000000000000000000000" + } + ] +} diff --git a/platform/ontology/transaction.go b/platform/ontology/transaction.go index b59598a4e..2ed00fe1e 100644 --- a/platform/ontology/transaction.go +++ b/platform/ontology/transaction.go @@ -38,6 +38,7 @@ func Normalize(srcTx *Tx, assetName AssetType) (tx blockatlas.Tx, ok bool) { Date: srcTx.Time, Block: srcTx.Height, Status: status, + Memo: "", } switch assetName { diff --git a/platform/ontology/transaction_test.go b/platform/ontology/transaction_test.go index fe51342da..6f0a5bc68 100644 --- a/platform/ontology/transaction_test.go +++ b/platform/ontology/transaction_test.go @@ -2,108 +2,20 @@ package ontology import ( "encoding/json" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" -) - -const ( - srcOntTransfer = ` -{ - "tx_hash": "ea0e5d8e389cb96760887094194ca359ac998b2f607be470a576861b91e2bf52", - "tx_type": 209, - "tx_time": 1578903628, - "block_height": 7571132, - "fee": "0.01", - "block_index": 1, - "confirm_flag": 1, - "transfers": [ - { - "amount": "5", - "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", - "to_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", - "asset_name": "ont", - "contract_hash": "0100000000000000000000000000000000000000" - }, - { - "amount": "0.01", - "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", - "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - } - ] -}` - - srcOngTransfer = ` -{ - "tx_hash": "e5946ba02f56e17c3709db2bc91f43f76ee3a359006586024daa5c4ad8c54e78", - "tx_type": 209, - "tx_time": 1577631515, - "block_height": 7457989, - "fee": "0.01", - "block_index": 1, - "confirm_flag": 1, - "transfers": [ - { - "amount": "14.69", - "from_address": "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", - "to_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - } - ] -}` - - srcRewardTransfer = ` -{ - "tx_hash": "d7554dcdf01f394b9107ff598df6d84e4c3b00ccf1e720b8c09abf085cbe4987", - "tx_type": 209, - "tx_time": 1579699532, - "block_height": 7644328, - "fee": "0.01", - "block_index": 1, - "confirm_flag": 1, - "transfers": [ - { - "amount": "0.03534404", - "from_address": "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", - "to_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - }, - { - "amount": "0.01", - "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", - "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - } - ] -}` - srcFeeTransfer = ` -{ - "tx_hash": "92a79aed526f31999e22d9e3912d4125d3f85ec3c63eede4b7dde4a041826095", - "tx_type": 209, - "tx_time": 1578902776, - "block_height": 7571071, - "fee": "0.01", - "block_index": 1, - "confirm_flag": 1, - "transfers": [ - { - "amount": "0.01", - "from_address": "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", - "to_address": "AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK", - "asset_name": "ong", - "contract_hash": "0200000000000000000000000000000000000000" - } - ] -}` + "github.com/trustwallet/golibs/mock" ) var ( + srcOntTransfer, _ = mock.JsonFromFilePathToString("mocks/transfer_ont.json") + srcOngTransfer, _ = mock.JsonFromFilePathToString("mocks/transfer_ong.json") + srcRewardTransfer, _ = mock.JsonFromFilePathToString("mocks/transfer_rewards.json") + srcFeeTransfer, _ = mock.JsonFromFilePathToString("mocks/transfer_fee.json") + dstOntTransfer = blockatlas.Tx{ ID: "ea0e5d8e389cb96760887094194ca359ac998b2f607be470a576861b91e2bf52", Coin: coin.ONT, @@ -238,7 +150,7 @@ var ( Transfers: Transfers{ { Amount: "113.2", - AssetName: "ont", + AssetName: "ong", FromAddress: "ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz", ToAddress: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", }, @@ -285,10 +197,9 @@ var ( func TestNormalizeBlock(t *testing.T) { block := normalizeTxs([]Tx{ontTxResp1.Result, ontTxResp2.Result, ontTxResp3.Result}, AssetAll) - got, err := json.Marshal(block) - if err != nil { - t.Fatal(err) - } - want := `[{"id":"266d9d7282a5601bf6cb8fc5368a76a2aa54f45731a063a699a692487bcbd0cb","coin":1024,"from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","sequence":0,"type":"native_token_transfer","memo":"","metadata":{"name":"Ontology Gas","symbol":"ONG","token_id":"ong","decimals":9,"value":"51000000000000","from":"AbEeCHUWpzQaxUN7G1a83N3P2XtVLuMLaE","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx"}},{"id":"2935268c5715f1f2015ba828681c39399dedbe7a24ed628ef7b85d9aac8045fd","coin":1024,"from":"ANdrA47zDXUu8MCkMdD3FYPmpSNGYeAvKz","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"113.2","symbol":"ONT","decimals":0}},{"id":"40976edc1306b0e5f55b90c8d3ca248bb544e5ebbadb02be6146ba0a0de402c3","coin":1024,"from":"Abg2gs6pfpQu82jXbm8EYGiipRBvf9ktVS","to":"ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx","fee":"10000000","date":1580481541,"block":7707834,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"10949","symbol":"ONT","decimals":0}}]` - assert.Equal(t, want, string(got)) + var want blockatlas.TxPage + _ = mock.ParseJsonFromFilePath("mocks/block_response.json", &want) + lhs, _ := json.Marshal(block) + rhs, _ := json.Marshal(want) + assert.JSONEq(t, string(lhs), string(rhs)) } diff --git a/platform/ripple/mocks/payment.json b/platform/ripple/mocks/payment.json new file mode 100644 index 000000000..5d52f1574 --- /dev/null +++ b/platform/ripple/mocks/payment.json @@ -0,0 +1,31 @@ +{ + "hash": "40279A3DE51148BD41409DADF29DE8DCCD50F5AEE30840827B2C4C81C4E36505", + "ledger_index": 34698103, + "date": "2017-12-01T22:45:30+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147483648, + "Sequence": 21, + "LastLedgerSequence": 34698105, + "DestinationTag": 2500, + "Amount": "100000000", + "Fee": "3115", + "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", + "TxnSignature": "3045022100D14057AA2A868F54FC7CA2E44C8310D9A944446580EAA45936A75CFFDD00425602205CCBFACB55AB0F5B02659F1EBE619FC04DE75B0227C8EB148DC6D08CABBAB072", + "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq", + "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", + "Memos": [ + { + "Memo": { + "MemoType": "636C69656E74", + "MemoFormat": "7274312E342E332D31332D6735383261336135" + } + } + ] + }, + "meta": { + "TransactionIndex": 20, + "TransactionResult": "tesSUCCESS", + "delivered_amount": "100000000" + } +} diff --git a/platform/ripple/mocks/payment_2.json b/platform/ripple/mocks/payment_2.json new file mode 100644 index 000000000..c6777b6f5 --- /dev/null +++ b/platform/ripple/mocks/payment_2.json @@ -0,0 +1,37 @@ +{ + "hash": "3D8512E02414EF5A6BC00281D945735E85DED9EF739B1DCA9EABE04D9EEC72C1", + "ledger_index": 49163909, + "date": "2019-08-06T17:58:01+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147614720, + "Sequence": 115, + "DestinationTag": 0, + "LastLedgerSequence": 49163911, + "Amount": "1000000000", + "Fee": "120", + "SendMax": { + "value": "0.001", + "currency": "USD", + "issuer": "rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq" + }, + "SigningPubKey": "030E4853E7D0B0E2D3C1233EADCB1B1C35DE75AD4AECD94AC534B3057537753B94", + "TxnSignature": "3045022100EBBDDB5D2F59472463CA03429DDDED4F06648FF097662697CCFF3C5C9C36091202205367A18FE65F767D6C6D256B2F7058BBA3C5D35655AD881A94EFC4BA2C2422DF", + "Account": "raz97dHvnyBcnYTbXGYxhV8bGyr1aPrE5w", + "Destination": "rna8qC8Y9uLd2vzYtSEa1AJcdD3896zQ9S", + "Memos": [ + { + "Memo": { + "MemoType": "636C69656E74", + "MemoData": "726D2D312E322E34" + } + } + ] + }, + "meta": { + "TransactionIndex": 24, + "DeliveredAmount": "3100", + "TransactionResult": "tesSUCCESS", + "delivered_amount": "3100" + } +} diff --git a/platform/ripple/mocks/payment_3.json b/platform/ripple/mocks/payment_3.json new file mode 100644 index 000000000..30a71b642 --- /dev/null +++ b/platform/ripple/mocks/payment_3.json @@ -0,0 +1,8 @@ +{ + "hash": "3D8512E02414EF5A6BC00281D945735E85DED9EF739B1DCA9EABE04D9EEC72C1", + "ledger_index": 49163909, + "date": "2019-08-06T17:58:01+00:00", + "tx": { + "TransactionType": "SetRegularKey" + } +} diff --git a/platform/ripple/mocks/payment_4.json b/platform/ripple/mocks/payment_4.json new file mode 100644 index 000000000..d2e800771 --- /dev/null +++ b/platform/ripple/mocks/payment_4.json @@ -0,0 +1,34 @@ +{ + "hash": "1D849E3A0041357EE373C7E17C9564F890047475492D9530B5F20A3BD6D95822", + "ledger_index": 49841027, + "date": "2019-09-06T01:48:32+00:00", + "tx": { + "TransactionType": "Payment", + "Flags": 2147942400, + "Sequence": 292765, + "LastLedgerSequence": 49841035, + "Amount": { + "value": "100000", + "currency": "ETH", + "issuer": "rJavT3eWaX9FubZFHtCvymJ6ZhSgJdMyNx" + }, + "Fee": "162", + "SendMax": "100000000000", + "Account": "r4NT6UfELQyoS689VLye22B3SfgvpM3nHY", + "Destination": "rJavT3eWaX9FubZFHtCvymJ6ZhSgJdMyNx" + }, + "meta": { + "TransactionIndex": 16, + "DeliveredAmount": { + "value": "533.92", + "currency": "ETH", + "issuer": "rJavT3eWaX9FubZFHtCvymJ6ZhSgJdMyNx" + }, + "TransactionResult": "tesSUCCESS", + "delivered_amount": { + "value": "533.92", + "currency": "ETH", + "issuer": "rJavT3eWaX9FubZFHtCvymJ6ZhSgJdMyNx" + } + } +} diff --git a/platform/ripple/mocks/payment_failed.json b/platform/ripple/mocks/payment_failed.json new file mode 100644 index 000000000..1b65ce4ec --- /dev/null +++ b/platform/ripple/mocks/payment_failed.json @@ -0,0 +1,22 @@ +{ + "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" + } +} diff --git a/platform/ripple/transaction_test.go b/platform/ripple/transaction_test.go index 6cfdc3c6e..f34a50a9e 100644 --- a/platform/ripple/transaction_test.go +++ b/platform/ripple/transaction_test.go @@ -1,259 +1,123 @@ package ripple import ( - "encoding/json" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "reflect" "testing" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" ) -const paymentSrc = ` -{ - "hash": "40279A3DE51148BD41409DADF29DE8DCCD50F5AEE30840827B2C4C81C4E36505", - "ledger_index": 34698103, - "date": "2017-12-01T22:45:30+00:00", - "tx": { - "TransactionType": "Payment", - "Flags": 2147483648, - "Sequence": 21, - "LastLedgerSequence": 34698105, - "DestinationTag": 2500, - "Amount": "100000000", - "Fee": "3115", - "SigningPubKey": "03807050F9E271B2E49B0FF658362EF37DBFDD31435E610B6E11C52879DF8A9907", - "TxnSignature": "3045022100D14057AA2A868F54FC7CA2E44C8310D9A944446580EAA45936A75CFFDD00425602205CCBFACB55AB0F5B02659F1EBE619FC04DE75B0227C8EB148DC6D08CABBAB072", - "Account": "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq", - "Destination": "rMQ98K56yXJbDGv49ZSmW51sLn94Xe1mu1", - "Memos": [ - { - "Memo": { - "MemoType": "636C69656E74", - "MemoFormat": "7274312E342E332D31332D6735383261336135" - } +func TestNormalizeTx(t *testing.T) { + type args struct { + filename string + } + tests := []struct { + name string + args args + wantTx blockatlas.Tx + ok bool + }{ + { + name: "Test normalize payment", + args: args{ + filename: "payment.json", + }, + wantTx: blockatlas.Tx{ + 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", + Decimals: 6, + }, + }, + ok: true, + }, + { + name: "Test normalize payment 2", + args: args{ + filename: "payment_2.json", + }, + wantTx: blockatlas.Tx{ + 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", + Decimals: 6, + }, + }, + ok: true, + }, + { + name: "Test normalize failed payment", + args: args{ + filename: "payment_failed.json", + }, + wantTx: blockatlas.Tx{ + ID: "B9086F7EB895E943C4DDA9F1B582E6E7DE35F4FB91AD13C50AB74F854DC0EBE0", + Coin: coin.XRP, + From: "rJb5KsHsDHF1YS5B5DU6QCkH5NsPaKQTcy", + To: "rfHj5CuhajwdrzW2C8Y7EDXbx1QMiD5SXP", + Fee: "100000", + Date: 1581590872, + Block: 53401154, + Memo: "", + Status: blockatlas.StatusError, + Meta: blockatlas.Transfer{ + Value: "24999750000", + Symbol: "XRP", + Decimals: 6, + }, + }, + ok: true, + }, + { + name: "Test normalize SetRegularKey transfer", + args: args{ + filename: "payment_3.json", + }, + wantTx: blockatlas.Tx{}, + ok: false, + }, + { + name: "Test normalize token transfer", + args: args{ + filename: "payment_4.json", + }, + wantTx: blockatlas.Tx{}, + ok: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx Tx + _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + gotTx, err := NormalizeTx(&srcTx) + if err != tt.ok { + t.Errorf("NormalizeTx() error = %v, ok %v", err, tt.ok) + return + } + if !reflect.DeepEqual(gotTx, tt.wantTx) { + t.Errorf("NormalizeTx() gotTx = %v, want %v", gotTx, tt.wantTx) } - ] - }, - "meta": { - "TransactionIndex": 20, - "TransactionResult": "tesSUCCESS", - "delivered_amount": "100000000" + }) } } -` - -var paymentDst = blockatlas.Tx{ - 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", - Decimals: 6, - }, -} - -const paymentSrc2 = ` -{ - "hash":"3D8512E02414EF5A6BC00281D945735E85DED9EF739B1DCA9EABE04D9EEC72C1", - "ledger_index":49163909, - "date":"2019-08-06T17:58:01+00:00", - "tx":{ - "TransactionType":"Payment", - "Flags":2147614720, - "Sequence":115, - "DestinationTag":0, - "LastLedgerSequence":49163911, - "Amount":"1000000000", - "Fee":"120", - "SendMax":{ - "value":"0.001", - "currency":"USD", - "issuer":"rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq" - }, - "SigningPubKey":"030E4853E7D0B0E2D3C1233EADCB1B1C35DE75AD4AECD94AC534B3057537753B94", - "TxnSignature":"3045022100EBBDDB5D2F59472463CA03429DDDED4F06648FF097662697CCFF3C5C9C36091202205367A18FE65F767D6C6D256B2F7058BBA3C5D35655AD881A94EFC4BA2C2422DF", - "Account":"raz97dHvnyBcnYTbXGYxhV8bGyr1aPrE5w", - "Destination":"rna8qC8Y9uLd2vzYtSEa1AJcdD3896zQ9S", - "Memos":[ - { - "Memo":{ - "MemoType":"636C69656E74", - "MemoData":"726D2D312E322E34" - } - } - ] - }, - "meta":{ - "TransactionIndex":24, - "DeliveredAmount":"3100", - "TransactionResult":"tesSUCCESS", - "delivered_amount":"3100" - } -} -` - -var paymentDst2 = blockatlas.Tx{ - 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", - Decimals: 6, - }, -} - -const paymentSrc3 = ` -{ - "hash":"3D8512E02414EF5A6BC00281D945735E85DED9EF739B1DCA9EABE04D9EEC72C1", - "ledger_index":49163909, - "date":"2019-08-06T17:58:01+00:00", - "tx":{ - "TransactionType": "SetRegularKey" - } -} -` - -const paymentSrc4 = ` -{ - "hash": "1D849E3A0041357EE373C7E17C9564F890047475492D9530B5F20A3BD6D95822", - "ledger_index": 49841027, - "date": "2019-09-06T01:48:32+00:00", - "tx": { - "TransactionType": "Payment", - "Flags": 2147942400, - "Sequence": 292765, - "LastLedgerSequence": 49841035, - "Amount": { - "value": "100000", - "currency": "ETH", - "issuer": "rJavT3eWaX9FubZFHtCvymJ6ZhSgJdMyNx" - }, - "Fee": "162", - "SendMax": "100000000000", - "Account": "r4NT6UfELQyoS689VLye22B3SfgvpM3nHY", - "Destination": "rJavT3eWaX9FubZFHtCvymJ6ZhSgJdMyNx" - }, - "meta": { - "TransactionIndex": 16, - "DeliveredAmount": { - "value": "533.92", - "currency": "ETH", - "issuer": "rJavT3eWaX9FubZFHtCvymJ6ZhSgJdMyNx" - }, - "TransactionResult": "tesSUCCESS", - "delivered_amount": { - "value": "533.92", - "currency": "ETH", - "issuer": "rJavT3eWaX9FubZFHtCvymJ6ZhSgJdMyNx" - } - } -} -` - -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.StatusError, - Meta: blockatlas.Transfer{ - Value: "24999750000", - Symbol: "XRP", - Decimals: 6, - }, -} - -type test struct { - name string - apiResponse string - normalize bool - expected blockatlas.Tx -} - -func TestNormalize(t *testing.T) { - testNormalize(t, &test{ - name: "payment 1", - apiResponse: paymentSrc, - 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) { - t.Run(_test.name, func(t *testing.T) { - var payment Tx - err := json.Unmarshal([]byte(_test.apiResponse), &payment) - assert.Nil(t, err) - tx, ok := NormalizeTx(&payment) - assert.Equal(t, ok, _test.normalize, "tx could not be normalized") - assert.Equal(t, _test.expected, tx, "tx don't equal") - }) -} diff --git a/platform/solana/mocks/currentValidators.json b/platform/solana/mocks/currentValidators.json new file mode 100644 index 000000000..9640d66c2 --- /dev/null +++ b/platform/solana/mocks/currentValidators.json @@ -0,0 +1,38 @@ +[ + { + "activatedStake": 3733867423940, + "commission": 100, + "epochCredits": [ + [70, 524224, 516032], + [71, 532416, 524224], + [72, 540608, 532416], + [73, 548800, 540608], + [74, 556992, 548800], + [75, 565184, 556992], + [76, 573376, 565184], + [77, 581568, 573376], + [78, 589760, 581568], + [79, 597952, 589760], + [80, 601055, 597952] + ], + "epochVoteAccount": true, + "lastVote": 601085, + "nodePubkey": "boot1Z6jb15CLqpaMTn2CxktktwZpRAVAgHZEW6SxQ7", + "rootSlot": 601054, + "votePubkey": "2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW" + }, + { + "activatedStake": 10540011934, + "commission": 100, + "epochCredits": [ + [78, 4760, 0], + [79, 12952, 4760], + [80, 16055, 12952] + ], + "epochVoteAccount": true, + "lastVote": 601085, + "nodePubkey": "B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY", + "rootSlot": 601054, + "votePubkey": "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5" + } +] diff --git a/platform/solana/stake_test.go b/platform/solana/stake_test.go index c09238df2..646ea9d65 100644 --- a/platform/solana/stake_test.go +++ b/platform/solana/stake_test.go @@ -5,60 +5,126 @@ import ( "testing" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/mock" "github.com/stretchr/testify/assert" ) -const currentValidators = ` -[ - { - "activatedStake": 3733867423940, - "commission": 100, - "epochCredits": [ - [70,524224,516032],[71,532416,524224],[72,540608,532416],[73,548800,540608],[74,556992,548800],[75,565184,556992],[76,573376,565184],[77,581568,573376],[78,589760,581568],[79,597952,589760],[80,601055,597952] - ], - "epochVoteAccount": true, - "lastVote": 601085, - "nodePubkey": "boot1Z6jb15CLqpaMTn2CxktktwZpRAVAgHZEW6SxQ7", - "rootSlot": 601054, - "votePubkey": "2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW" - }, - { - "activatedStake": 10540011934, - "commission": 100 , - "epochCredits": [ - [78,4760,0],[79,12952,4760],[80,16055,12952] - ], - "epochVoteAccount": true, - "lastVote": 601085, - "nodePubkey": "B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY", - "rootSlot": 601054, - "votePubkey": "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5" - } -]` - -var expectedValidators = []blockatlas.Validator{ - { - Status: true, - ID: "2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW", - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: blockatlas.Amount("2282881"), - LockTime: 0, - Type: blockatlas.DelegationTypeDelegate, +var ( + currentValidators, _ = mock.JsonFromFilePathToString("mocks/" + "currentValidators.json") + expectedValidators = []blockatlas.Validator{ + { + Status: true, + ID: "2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW", + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 0}, + MinimumAmount: blockatlas.Amount("2282881"), + LockTime: 0, + Type: blockatlas.DelegationTypeDelegate, + }, }, - }, - { - Status: true, + { + Status: true, + ID: "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5", + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: 0}, + MinimumAmount: blockatlas.Amount("2282881"), + LockTime: 0, + Type: blockatlas.DelegationTypeDelegate, + }, + }, + } + + keyedStakeAccount = KeyedAccount{ + Account: Account{ + Data: "mrWMHx6j3BkmepJy67XLycC7LVeiq2NBESfV2YNmZvY62xT5jTgKnMzRBQheYtAuajncAniTEmU8QxgkpnytnXynTrMSJN4p6ihefU5cobkyCeSwMKugKGuBbyDLjQoUMu6BUKjDTFvjpJUHFCgz1Vaa8HSVscUqqRcioByf3owMUwHmEYsF8vuouLAqEQmo61wFkKfZELxLrhBbi2PQQZucryrnNDKXV4DY3oegLy9aMnMDZUeoDtDPPiJeM2F1Trh8ZkH1sQL6sQ5V", + Executable: false, + Lamports: 100000000000, + Owner: "Stake11111111111111111111111111111111111111", + RentEpoch: 80, + }, + Pubkey: "EgR17fgGmwQQaMZPsuJdk9oHw2xY8TJQj3Bp44o24mar", + } + + stakeState = StakeData{ + State: 2, + RentExemptReserve: 2282880, + AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + UnixTimestamp: 0, + LockupEpoch: 0, + Custodian: arrayOfPubkey("11111111111111111111111111111111"), + VoterPubkey: arrayOfPubkey("5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5"), + Stake: 99997717120, + ActivationEpoch: 79, + DeactivationEpoch: ^uint64(0), + WarmupCooldownRate: 0.25, + CreditsObserved: 21143, + } + + deactivatedStakeState = StakeData{ + State: 2, + RentExemptReserve: 2282880, + AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + UnixTimestamp: 0, + LockupEpoch: 0, + Custodian: arrayOfPubkey("11111111111111111111111111111111"), + VoterPubkey: arrayOfPubkey("5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5"), + Stake: 99997717120, + ActivationEpoch: 70, + DeactivationEpoch: 78, + WarmupCooldownRate: 0.25, + CreditsObserved: 21143, + } + + unpublishedValidatorStakeState = StakeData{ + State: 2, + RentExemptReserve: 2282880, + AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), + UnixTimestamp: 0, + LockupEpoch: 0, + Custodian: arrayOfPubkey("11111111111111111111111111111111"), + VoterPubkey: arrayOfPubkey("BNTmegvdXzNVyc3UMTWSMSfJUryjr3fXEVErtdqrfs6y"), + Stake: 99997717120, + ActivationEpoch: 70, + DeactivationEpoch: 78, + WarmupCooldownRate: 0.25, + CreditsObserved: 21143, + } + + stakeValidator = blockatlas.StakeValidator{ ID: "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5", - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: blockatlas.Amount("2282881"), - LockTime: 0, - Type: blockatlas.DelegationTypeDelegate, + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "Certus One", + Description: "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment.", + Image: "https://assets.trustwalletapp.com/blockchains/solana/validators/assets/2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW/logo.png", + Website: "https://certus.one", }, - }, -} + Details: getDetails(), + } + + validatorMap = blockatlas.ValidatorMap{ + "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5": stakeValidator, + } + + epochInfo = EpochInfo{ + AbsoluteSlot: 165763, + Epoch: 80, + SlotIndex: 1923, + SlotsInEpoch: 2048, + } + + delegation = blockatlas.DelegationsPage{ + { + Delegator: stakeValidator, + Value: "99997717120", + Status: blockatlas.DelegationStatusActive, + }, + } +) func TestNormalizeValidator(t *testing.T) { var validators []VoteAccount @@ -71,65 +137,6 @@ func TestNormalizeValidator(t *testing.T) { } } -var keyedStakeAccount = KeyedAccount{ - Account: Account{ - Data: "mrWMHx6j3BkmepJy67XLycC7LVeiq2NBESfV2YNmZvY62xT5jTgKnMzRBQheYtAuajncAniTEmU8QxgkpnytnXynTrMSJN4p6ihefU5cobkyCeSwMKugKGuBbyDLjQoUMu6BUKjDTFvjpJUHFCgz1Vaa8HSVscUqqRcioByf3owMUwHmEYsF8vuouLAqEQmo61wFkKfZELxLrhBbi2PQQZucryrnNDKXV4DY3oegLy9aMnMDZUeoDtDPPiJeM2F1Trh8ZkH1sQL6sQ5V", - Executable: false, - Lamports: 100000000000, - Owner: "Stake11111111111111111111111111111111111111", - RentEpoch: 80, - }, - Pubkey: "EgR17fgGmwQQaMZPsuJdk9oHw2xY8TJQj3Bp44o24mar", -} - -var stakeState = StakeData{ - State: 2, - RentExemptReserve: 2282880, - AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - UnixTimestamp: 0, - LockupEpoch: 0, - Custodian: arrayOfPubkey("11111111111111111111111111111111"), - VoterPubkey: arrayOfPubkey("5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5"), - Stake: 99997717120, - ActivationEpoch: 79, - DeactivationEpoch: ^uint64(0), - WarmupCooldownRate: 0.25, - CreditsObserved: 21143, -} - -var deactivatedStakeState = StakeData{ - State: 2, - RentExemptReserve: 2282880, - AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - UnixTimestamp: 0, - LockupEpoch: 0, - Custodian: arrayOfPubkey("11111111111111111111111111111111"), - VoterPubkey: arrayOfPubkey("5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5"), - Stake: 99997717120, - ActivationEpoch: 70, - DeactivationEpoch: 78, - WarmupCooldownRate: 0.25, - CreditsObserved: 21143, -} - -var unpublishedValidatorStakeState = StakeData{ - State: 2, - RentExemptReserve: 2282880, - AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - UnixTimestamp: 0, - LockupEpoch: 0, - Custodian: arrayOfPubkey("11111111111111111111111111111111"), - VoterPubkey: arrayOfPubkey("BNTmegvdXzNVyc3UMTWSMSfJUryjr3fXEVErtdqrfs6y"), - Stake: 99997717120, - ActivationEpoch: 70, - DeactivationEpoch: 78, - WarmupCooldownRate: 0.25, - CreditsObserved: 21143, -} - func TestParseStakeData(t *testing.T) { result, err := parseStakeData(keyedStakeAccount.Account) @@ -146,37 +153,6 @@ func TestIsAuthorized(t *testing.T) { assert.False(t, isAuthorized(account, address)) } -var stakeValidator = blockatlas.StakeValidator{ - ID: "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5", - Status: true, - Info: blockatlas.StakeValidatorInfo{ - Name: "Certus One", - Description: "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment.", - Image: "https://assets.trustwalletapp.com/blockchains/solana/validators/assets/2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW/logo.png", - Website: "https://certus.one", - }, - Details: getDetails(), -} - -var validatorMap = blockatlas.ValidatorMap{ - "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5": stakeValidator, -} - -var epochInfo = EpochInfo{ - AbsoluteSlot: 165763, - Epoch: 80, - SlotIndex: 1923, - SlotsInEpoch: 2048, -} - -var delegation = blockatlas.DelegationsPage{ - { - Delegator: stakeValidator, - Value: "99997717120", - Status: blockatlas.DelegationStatusActive, - }, -} - func TestNormalizeDelegations(t *testing.T) { stakeAccounts := []StakeData{stakeState, deactivatedStakeState, unpublishedValidatorStakeState} result, err := NormalizeDelegations(stakeAccounts, validatorMap, epochInfo) diff --git a/platform/stellar/mocks/create_tx.json b/platform/stellar/mocks/create_tx.json new file mode 100644 index 000000000..e50548c10 --- /dev/null +++ b/platform/stellar/mocks/create_tx.json @@ -0,0 +1,13 @@ +{ + "id": "25002129911451649", + "paging_token": "25002129911451649", + "transaction_successful": true, + "source_account": "GBEZOC5U4TVH7ZY5N3FLYHTCZSI6VFGTULG7PBITLF5ZEBPJXFT46YZM", + "type": "create_account", + "type_i": 0, + "created_at": "2016-08-10T17:30:20Z", + "transaction_hash": "8b96cf3a660b85ef80b5a84c032cacdb93bb139cfe7e929b974ea9eaa0d29141", + "starting_balance": "47326939370.0000000", + "funder": "GBEZOC5U4TVH7ZY5N3FLYHTCZSI6VFGTULG7PBITLF5ZEBPJXFT46YZM", + "account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" +} diff --git a/platform/stellar/mocks/transfer_tx.json b/platform/stellar/mocks/transfer_tx.json new file mode 100644 index 000000000..53a9eba7b --- /dev/null +++ b/platform/stellar/mocks/transfer_tx.json @@ -0,0 +1,18 @@ +{ + "id": "25008572362395649", + "paging_token": "25008572362395649", + "transaction_successful": true, + "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "type": "payment", + "type_i": 1, + "created_at": "2016-08-10T19:39:01Z", + "transaction_hash": "a596dc910bae20b5bbe64aa7aa3f42acbd55769b98307878f5ad095e994bc9cf", + "asset_type": "native", + "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + "to": "GAX3BRBNB5WTJ2GNEFFH7A4CZKT2FORYABDDBZR5FIIT3P7FLS2EFOZZ", + "amount": "100000000.0000000", + "transaction": { + "memo": "testing", + "ledger": 123 + } +} diff --git a/platform/stellar/transaction_test.go b/platform/stellar/transaction_test.go index 57c30d2fc..3d9c5188a 100644 --- a/platform/stellar/transaction_test.go +++ b/platform/stellar/transaction_test.go @@ -2,79 +2,49 @@ package stellar import ( "encoding/json" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" + "github.com/trustwallet/golibs/mock" ) -const createSrc = ` -{ - "id": "25002129911451649", - "paging_token": "25002129911451649", - "transaction_successful": true, - "source_account": "GBEZOC5U4TVH7ZY5N3FLYHTCZSI6VFGTULG7PBITLF5ZEBPJXFT46YZM", - "type": "create_account", - "type_i": 0, - "created_at": "2016-08-10T17:30:20Z", - "transaction_hash": "8b96cf3a660b85ef80b5a84c032cacdb93bb139cfe7e929b974ea9eaa0d29141", - "starting_balance": "47326939370.0000000", - "funder": "GBEZOC5U4TVH7ZY5N3FLYHTCZSI6VFGTULG7PBITLF5ZEBPJXFT46YZM", - "account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX" -} -` - -var createDst = blockatlas.Tx{ - ID: "8b96cf3a660b85ef80b5a84c032cacdb93bb139cfe7e929b974ea9eaa0d29141", - Coin: coin.XLM, - From: "GBEZOC5U4TVH7ZY5N3FLYHTCZSI6VFGTULG7PBITLF5ZEBPJXFT46YZM", - To: "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - Fee: "100", - Date: 1470850220, - Block: 0, - Meta: blockatlas.Transfer{ - Value: "473269393700000000", - Symbol: "XLM", - Decimals: 7, - }, -} +var ( + createSrc, _ = mock.JsonFromFilePathToString("mocks/" + "create_tx.json") + transferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer_tx.json") -const transferSrc = ` -{ - "id": "25008572362395649", - "paging_token": "25008572362395649", - "transaction_successful": true, - "source_account": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - "type": "payment", - "type_i": 1, - "created_at": "2016-08-10T19:39:01Z", - "transaction_hash": "a596dc910bae20b5bbe64aa7aa3f42acbd55769b98307878f5ad095e994bc9cf", - "asset_type": "native", - "from": "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - "to": "GAX3BRBNB5WTJ2GNEFFH7A4CZKT2FORYABDDBZR5FIIT3P7FLS2EFOZZ", - "amount": "100000000.0000000", - "transaction": { - "memo": "testing", - "ledger": 123 + createDst = blockatlas.Tx{ + ID: "8b96cf3a660b85ef80b5a84c032cacdb93bb139cfe7e929b974ea9eaa0d29141", + Coin: coin.XLM, + From: "GBEZOC5U4TVH7ZY5N3FLYHTCZSI6VFGTULG7PBITLF5ZEBPJXFT46YZM", + To: "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + Fee: "100", + Date: 1470850220, + Block: 0, + Meta: blockatlas.Transfer{ + Value: "473269393700000000", + Symbol: "XLM", + Decimals: 7, + }, } -} -` -var transferDst = blockatlas.Tx{ - ID: "a596dc910bae20b5bbe64aa7aa3f42acbd55769b98307878f5ad095e994bc9cf", - Coin: coin.XLM, - From: "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", - To: "GAX3BRBNB5WTJ2GNEFFH7A4CZKT2FORYABDDBZR5FIIT3P7FLS2EFOZZ", - Fee: "100", - Date: 1470857941, - Memo: "testing", - Block: 123, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1000000000000000"), - Symbol: "XLM", - Decimals: 7, - }, -} + transferDst = blockatlas.Tx{ + ID: "a596dc910bae20b5bbe64aa7aa3f42acbd55769b98307878f5ad095e994bc9cf", + Coin: coin.XLM, + From: "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", + To: "GAX3BRBNB5WTJ2GNEFFH7A4CZKT2FORYABDDBZR5FIIT3P7FLS2EFOZZ", + Fee: "100", + Date: 1470857941, + Memo: "testing", + Block: 123, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("1000000000000000"), + Symbol: "XLM", + Decimals: 7, + }, + } +) type test struct { name string diff --git a/platform/tezos/mocks/account.json b/platform/tezos/mocks/account.json new file mode 100644 index 000000000..ef26566d2 --- /dev/null +++ b/platform/tezos/mocks/account.json @@ -0,0 +1,4 @@ +{ + "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "balance": "91237897" +} diff --git a/platform/tezos/mocks/delegation_response.json b/platform/tezos/mocks/delegation_response.json new file mode 100644 index 000000000..5cd933ea2 --- /dev/null +++ b/platform/tezos/mocks/delegation_response.json @@ -0,0 +1,483 @@ +{ + "balance": "19924380870", + "frozen_balance": "16854253212", + "frozen_balance_by_cycle": [ + { + "cycle": 240, + "deposit": "3072000000", + "fees": "15676", + "rewards": "90000000" + }, + { + "cycle": 241, + "deposit": "3328000000", + "fees": "621522", + "rewards": "95000000" + }, + { + "cycle": 242, + "deposit": "3648000000", + "fees": "4360", + "rewards": "101250000" + }, + { + "cycle": 243, + "deposit": "3392000000", + "fees": "28321", + "rewards": "125833333" + }, + { + "cycle": 244, + "deposit": "2816000000", + "fees": "0", + "rewards": "55000000" + }, + { "cycle": 245, "deposit": "128000000", "fees": "0", "rewards": "2500000" } + ], + "staking_balance": "163002104470", + "delegated_contracts": [ + "tz1YGsmfUfed8fmG4QLhGB1Y3gCMX44t1JTc", + "tz1WnfCXDniXhHzbXEPTQ1JSoyb7EzotYJs3", + "tz1RqtpgLw3uedpWaDVC5WAdvNfiUnsY7ZC5", + "tz1eLjmx4j7QLX2RabyS8Pf3sSe1U6H2UZji", + "tz1TYhMcdYah6QJWQbL853x4Rn6fSvtHhqDf", + "tz1XcmqCntUEzrpV6xcvw449Ro83KU5W3vv6", + "tz1QfbGBmr5dvha6agPcmsvnaz2EfcctW4ZJ", + "tz1bN4kotiEE7dAEsTGWpNTF2DnjJw9NNSoD", + "tz1hoj3Lw71qgsQf5a7cdhdU9crEH3mAAaNn", + "tz1SfvgWvSBxNsgta6UCmytMTPHzMsmjMB54", + "tz1ZsKynrRs8KNe3ao1ZMaKk6he6VUWtjcFU", + "tz1ZEKCiu7QspFVZL1svyr9vvir7tTm5CEdW", + "tz1gScW33c2EjpusjaPCm7r82QVZsALnNsXk", + "tz1TDnm46TxwLRbihJf2yTQLJGJYe6k7N3Kw", + "tz1NQCizMgAvmjhMJEidnTNPFEPHxA6XLY65", + "tz1dp6YqFkjoDZqrceSEC7cKFDEWbynyv7UV", + "tz1RctGdDVhQFoqL99bXJvYTwQNJWEL2Rx6Y", + "tz1hqd37vwxZcNeiNMrz6kpujusPRxcaFyhv", + "tz1crpuStZ66tv89kZMQbiGHk2C2RyD87o2S", + "tz1a45AtW3gs964AxC7X2sShAj9wsBGQjsWQ", + "tz1Xi1AtnoAv74PAQFDUY67TEjww1J2e6FaQ", + "tz1XqSWe3M9eEd2mueqEWmgKZLoYVJCRC92B", + "tz1Y5JZMUEsuX9oicG9AqXG8XWPHmKeWFrb8", + "tz1LVtuGkbCgEZsZhbzu1sonVg5xZyrrWqGD", + "tz1cfqx7H6qsXgsLTHFn7hWjdkU1SjpzpFyx", + "tz1SFMBqUwq6JJP1mQZfp8ae4GsfGSM8812Y", + "tz1LeU73Tm2eBcUV1prcHLjK1Pb7KgC8rPTu", + "tz1dMvyK57FBfUqzSenaWSoY1Rng77KxwTT8", + "tz1S382giorXLVdzw79LVcMj5MLJkYK8Ex8d", + "tz1TAscJC43xhPBNBESuNupw3FhLsfE4Ghxd", + "tz1eACKAsqr5faLgsE3ACdHeejrdM4igY2qj", + "tz1Ln7pr3Bf7Yxmnf57iEkgEUvo7PrMh3HJh", + "tz1XC1DbtQjUu2udaeVbSa3G2rrU9dJKmN6V", + "tz1PCa2Drre9MaJ5pcKpQHh8A75LDEYYA4rq", + "tz1S7SacT3Pe8EfDfMEnR7fdvDamZDiwVMoQ", + "tz1U6V2mWc6zd31yFXME5Xnoifo3PeHQhuJA", + "tz1V54Uhpp2i8pUVEFNcmhrkJqfDZhqb5F5C", + "tz1aTmVHkGBChKHfAqdJjjadkP4rz4MDjbJS", + "tz1dpijoKv5dCFT1BvtEmxy4YLcCsAc9ZGeh", + "tz1Mmv9StLbPu3jYVBDoKgNJTb3FD5wuA2vA", + "tz1PkJZs2Eb3ouLd9cTf4wSQ3n9aMz7YLGNR", + "tz1YpTsHeubr7WQaKu3Yfs3m1gKw5QP1MbdM", + "tz1ZP1EgEkNwB1nYA8bQdJ7YcttsbJuJCZLe", + "tz1Wh7XciNS6oUTW14bQ5PD7pQjqae2tNA8S", + "tz1bgRKKwMc4s8fxTDJrauCx3NoGLSRJ5B49", + "tz1URZ8CPFhzLz3UjQD9zUjTZY38XwGTCiKn", + "tz1KrUvC8nUGRnk4RXtqAFLsJj4cbtXjR5Wg", + "tz1f8eDjy48LDcWrrNTF3wwkGEjyXqDcoMro", + "tz1RStdCWJXpVVvYvAB5VZXgzrxPGoHpEhjK", + "tz1LWjsR3LiBDPyvuf7S1qJxaVKNZV9TSbaW", + "KT1DMboG5KtaPbMTaA2PeV8FqRcqbt9adzQE", + "tz1iq1eA7i2ogVCQ52g3zeSEqCrFTSVxhE2c", + "tz1Y9tfG6Gs5oFdLtcE9obQaxbwZyK8CTn6e", + "tz1XotDGePt679YtqexwfFvE9AutjdkvemH2", + "tz1LG4KEFVjp1MxSCXQWUSyoZpE4Nq3gbxHy", + "tz1TMRCpNgKAdp8GH3jXAVR3MuLMMPZBzevi", + "tz1hZY5ix3GTTUMAsv6anwD2817RspnnEb81", + "tz1gzPsf717fNkpFVQYuNAKBBQngqGx6CFJz", + "tz1TTxhXmRRdMAKdF7ykdyybgg1baD686JWs", + "tz1dPnbKhnmJo3J7S2rokMSmTtaWNGDeQuYa", + "tz1irRBG7qLAeo6URDn4bnUb9NByoLQUHN7K", + "tz1d9d9brjpFRrErRF8tT5StDve7svAQueTB", + "tz1SBRVFKJCaDnPRzHrn1Pc7NG61tqNY1HpM", + "tz1h4Ag9NixUomVaFo8MatDpEL84JEEs9oFx", + "tz1NVzxdVF2gy276bGAt3TFJHWUMtnS5BZrN", + "tz1Ytb5C7xDvWArsif3cEfWC7NpEiWkGVcW4", + "tz1WQ4w3WQUzReKAehyDKkVQjiVNJLuWoCrx", + "tz1StPqh4Jybs5yE4adLLBvrirwm7cuoEMC3", + "tz1f5yKJQwdEx1XbqUreT5E5MG2ddoP9sxG6", + "tz1hVxLkK7fDPCsgRytKyqSYoRGdPYkRAHK4", + "tz1Qs7gcTNMN759qBUukQmfA6cUeWzqtU7sq", + "tz1SsR67T1ykErBtVinVMCWhvwrUWBMkzxQu", + "tz1QD8a5kJBGHArP1DHECBzj4gbRPZuBGGL9", + "tz1inQ6S764Btu5HgHRGMg72Tee5UjQtri7y", + "tz1asvE47tkUoYPrb6HrVzkHVhfx3roZA56f", + "tz1ZqdsHNTeYLCw3Etw1BwMTRbU3Ji42HT4N", + "tz1Zd43K6xBnpddV2pv2PcbKPBXpYo6qAAxc", + "tz1YbEBGE1KQXAMLiQEnXVKLoNKVAmtQxJ2y", + "tz1QFhih66LJDFpm9T6a2gWdg7551k65C9ke", + "tz1T4RpJjC671WadSwA145zMZNSCmvcwGL5R", + "tz1Pibvp7EttcPX56CTvmxPsSLqwsDhd2fC1", + "tz1cFu4B4afDVkcojpv43h7wbv8169VA7mSU", + "tz1ixKgGdRoSzsp57qe5WXHLbeu2GRpXYmGW", + "KT1M6T4ft8UXXwFxa6QxRU3T1JDEKQBRK8Li", + "tz1csRh2tzRZw8dcuAm1LMCMUQBEq7N3EmY7", + "tz1gaz2QgwUTyZypSmMx72oUrraD1hZ4CWEB", + "tz1TpW2WB8Y9mYsDp2Lx4EoKcocyFWApScFy", + "tz1f9Hg7KF6xKLabL4UNLPdtJeohQbuJrVa2", + "tz1Q8Q7sT3r7pdGGyYEtX7v6jTxCwJ3bSdtJ", + "tz1iLAxh9M6xcaNMVhb5hGxZb9qvzBVwo5UT", + "tz1XXHuK4tMKJZBQDeDFCpzWdH4g26Q42gFW", + "tz1VvZYohqJvKzTKsRYcfuQuak6LYFao9hkD", + "KT1E6sM9KBpYWoK7ZxoxrcAzbngVhn9ZxkPw", + "tz1TuBtRJ5bGa7KRyhiZcoFiZTHXnuq4wz4X", + "tz1fQRtYbQqenvb171siK8KqScBZKHrsqKW4", + "tz1dn9tn4UqhwLiAShcaq63oiwzQ7X8aySTz", + "tz1Uvknh1VNhYYQbhFaP1rDU1GNtFpGWG98c", + "tz1ZosT8MD6tibQDYLbhfTm5Z9oQPL2f7LwP", + "tz1Yk9Mz6hSBrq7qWLUZKDqcuwyu19i7FS4Q", + "tz1i5wEnEp1Wf4WiL7dFxiTj81VSiDprGWyZ", + "tz1fQv9BGCjZC29DFPSmqNxkjFx2tLzRy9Kn", + "tz1M7TVpisBJfPkkjrfsnK7CZyRbVb2Vdooa", + "tz1TJ6ZPJVrAFZUNhReL9FnhzXXd86Hmtk3d", + "tz1hbeGj3krpLMdKMumeukTatZcDCG9RGnyT", + "tz1Xm41xUyqvV5caWkpx1ym2p8uTvJPKZMdw", + "tz1XZEpd7EnfzmjYKfRY2zrfEd4trBJWBybN", + "tz1QZAQoaXbLXW3WjYB8os5xjwe4mB62KjPi", + "tz1gd8XNS2Me4oRXq9XTkTX9kYumRM4Y6rXf", + "tz1aK1rKDWDSa31kB1SwP1tD3BvPTNQWXwwK", + "tz1Ui8BtvQpJpF155ppgMZSEpCKEDuLXNMX4", + "tz1ioGHFTom3ojBbcfgEb8mt1f1ceobVEcEq", + "tz1LxreKnQEFW2QB3dZDX1bNThcW8vmem4E8", + "tz1gu2wRjBfY7jpMokMDZGNZVBE5n98J65g4", + "tz1dfAqA9rhx1tFuu86FdhBwKMwaisVe1dEg", + "tz1ND2YvsV6mnWSUHA2bd1oUcTmshMbxYV1M", + "tz1aSBidSCjNqLcEk8BYvA43EenEZNtsvkuW", + "tz1e8Fk5whgxrPzTZAMiW2FbatdaABNt5hpX", + "tz1QeU3SH1pGYTWmKfZKovH2RiiqSnd3zFPo", + "tz1UkUgyb3Au9GeQx6YbcJJaafNDpgGRLDeV", + "tz1WPnZxticG6xGpHNhaV9kvU1PfgYiMXp7A", + "tz1LKVTXzQtDwQWXJpbe88Q2U5TceBrEJf5i", + "tz1X4tzFR73YRBBora46aevdGn3aqz5UzdrJ", + "tz1PouWF6hyoHmMYAGuwDBAXJKL4Z8yixEwq", + "tz1ib38e3VCZgvRxc2Gj6KtAgAv9FkWx3xt1", + "tz1Ndenm8uaonPs8oo7iqXQ6RRho6cG8GBd1", + "tz1WRAfQ4c98Lxz5k2j5QFwcaw31Z6zSuiza", + "tz1W7G8pgorMWDcWSsTpQLuQoKqVPk6MNTV5", + "tz1NY7t1otGmLV9VuhdApzsqwwqGEK6iLeyH", + "tz1MA5ywEYaPNzJWeLWBDfvAfZmryeFdrexy", + "tz1Rzq5gz824wG4gt4MPX13oKojnY3cJVTAB", + "KT1MmHkxDKy16ETe6CKY6Hs3SXGzAeMKHcmy", + "tz1aYL7YjKn8zFV8kCNMg5qjJTXQ5sPhnVQU", + "tz1Mqazkg2SgqB4ibXxpFudp2HVYEZ2s3t59", + "tz1X1o4zSNrnTDouETFM9AXQzamWcUkEj59n", + "tz1Qe9fqiQnizh5gzuURT3J24MQxd7A9qxTt", + "tz1UWyf2N1yCiEkfyCKdyMitKMAaUWACWpro", + "tz1LYCQsxVf2RdDEWcG5N1zY72XskyXevciC", + "tz1XD2yz8UQYGJ6BRb7h7wZp854fQXC9DQFm", + "tz1iiT4XbLvffTJbGhuiCg3ofaaNdLX2thSu", + "tz1YrCk1KZu9wwn9vCUYuZp8medpViizrZwK", + "tz1QPmsd6BS9CUAugcNGJP9me8V6qtEEYrV8", + "tz1adgGe3ghX6DH7kh1BAasaCGrf6ermGY53", + "tz1M7PNxBBCUx14jfdv5ZERWZWBhPJVjKHJD", + "tz1VcWpMRqd5xxoauw1urcnPQ2kZZxhbqgcv", + "tz1Y2nVkzQQmdVnDcuo6VDAgnBufoUHLXR3r", + "tz1bGvZzpjJZHzFJGQYWPVg4JQ7arsmX3CBW", + "tz1ZGn1qwM2Bg65xqNx37XB4ptSQnRh7LjED", + "tz1Pku546auwaUBm4Wht1zwZtfxg7ic81p6Z", + "tz1R5yUME8wSYtyZNpfWdoPZcQgNLtaUUvef", + "tz1b5HuS35FKB7qWvFuALXX6ZFspEWWJVjxP", + "tz1ihSZ12F2y6H778E6L4ciWzvX7rfPwmGQd", + "tz1T4yyuchdPqtZSbtsaBS3GLqLeUg8dJmb4", + "tz1LnRcJUtFBKcht4n2jo2PAJF1ufwAVa1nL", + "tz1iwdFtYWaicwc1dfJA6YmN7eRCX1RkaGuz", + "tz1aD3HxUFLSr6tmYuP7HKvx7t8WgKTY5pYs", + "tz1XJMJ7XjbHkkFkAWw9C8ocjfmkmTBXo5TG", + "tz1PfUUZ1YTRqP7qkjsSR1X7TCeYbRpnCfaj", + "tz1aLVDxteKdmBRaRMcQPQaEL2ExbDwQA7fP", + "tz1QoFWg86UsKYjtskkmBkz58mftgHLrvrci", + "tz1ZWbmnG1sb4KCkrjii1FoiJ1RcJEg7Tf5V", + "tz1VGrdEoiWdSpUFGZAbX6hxuQAJjEXqXvwW", + "tz1Q8gvcfGC74oaWx2Gb4TipRLb7aEfsWyAG", + "tz1QVsVf5VQfihDiBED7ZMn5Ai637z9GwfpB", + "tz1Nqf8Do6NFXncMzGhYasnif7iTJ8UgGHTn", + "tz1KotnQg3tbzTLxYJc9XW3dagmYjAMHzYV7", + "tz1QzMbAcThy4EX8ENvHZm2BVxQMmCY7wsUw", + "tz1YKTfdWtb6gzr26mRsLsGCNK8TBBVEHC1E", + "tz1egRyJLzTmC4aMUCRZLKEhtYd2MyD9f8RP", + "tz1NJFR2PLvbijMGGZ9LnW88CZxo1SSFxsxR", + "tz1fU6Zxx14MCEqfkSwDWRMqFmYmhygSJrcK", + "tz1aN9Gp5FXc7CQoR8MGSf3VUFohe6f9rFJ6", + "tz1KuQ5yDerio8tW294zHsYofWc8TQ3xnbaJ", + "tz1Yi1qojMoS2JhESiE4vAeo7dWUqQbnEQeL", + "tz1RxecATFfopVUvE9HS45rL6rgzGVg4cFG2", + "tz1hXRjun9ou7YN7sFKJJsgHPkGpdXzamzKY", + "tz1dWg4SYTFiYfPrDGBNCaNZunjCi9CyK8PU", + "tz1N7CRoQTrTjM6BG6PK4XfwnkEERKj1GgTt", + "tz1T8RkwAcBBwc9uCovercc6Qr326ezqtoij", + "tz1UkDYB4RgqBcRL7yYSikc8r6fpAeRVP9c4", + "tz1WLjJEwxQK3hbnZWkmEzGzQ988MdQVq1iB", + "tz1bLijXE1D8XxHjzK9wBK2udxNqXbHkMzFg", + "tz1VMWRzCPN9E7NLBfSHxFVzjZ2vxNPKRXCT", + "tz1eUfNmzeZWccsAV2ZzCovjMR4HSDH6eiiq", + "tz1VASv4WieYkgmUCeh2j5ftEw72NkkuCDje", + "tz1fZH9g6npSMZgSGzcaqegnuftJ1AcNEQ6F", + "tz1QGzvcCDezxV439D5cjRaTFXC8Y2bF6qTw", + "tz1PxPHvFdkGY7XkyuV2eUDYH3wxuerKiYiC", + "tz1YJUngcjMCStvP7MABMVBPyFkU3BupNymQ", + "tz1NoKTHMvzPooEbyeMHQBaia7Ekf8aTrv8g", + "tz1aQHYPPW8dq7ucWUccV74cEyzt6AiMjrfj", + "tz1dpCdky48ELUbjrzY89Uy4fTukmmJdr9tJ", + "tz1SQcKWYJCatD4jVFRNtR8UVBmtZT5VAM3x", + "tz1a6rVyLh6z7akANZsBuxSb2g9gNthXuFM1", + "tz1eNv53m15QQhKYyREahAx6LCK9YYczEUPe", + "tz1Z5Lgu8CDhbWNdyEzXkCC2TrkHrSDVwMWp", + "tz1Prq1iQE4xMn3JqwK6rMaJXoGjS9sfWM3L", + "tz1hxtCEcD7idQJEDiJEq37vBkoRcwF6KC2X", + "tz1ZTmAakWGa9fefwoaomG7wFPQhPXepyxdT", + "tz1dXKPAsBG4DG6oKki84UVTBYw5doTGbu95", + "tz1ZGCukFkDD5ns2aA8HuKGrE68DVmbhLvvs", + "tz1cvSwVukfoTNS16f1Y12mHYqsrnCK2z7ZM", + "tz1PV34FXaBY5mqLLyjG8TdzNCo5SUz51d1a", + "tz1KxhXker6qezyPyzpLcTVXxAadWuaRMB8Y", + "tz1cZmvFJgdJfUoBF2USegkoEq653qx3KgxB", + "tz1M8NxQupHMQ5uW1k25wCYYdxMWojKfiVNa", + "tz1eqnkA7YZS5uVhH42WfZkwkECTxCkUqKJG", + "tz1Z2ERSqjQjTtGdv6XZJ9ZoffxAQVCLHrLM", + "tz1iXW4XFVvg1QS6bGhuPo1VCGT6WTgEaoA5", + "tz1VMDp7io6vgXo8jsLcgbsUB6Vc9mdAw69x", + "tz1edVs2PENzexqcwWv22pwu4HfcgXbKcV4R", + "tz1LSUEVASTpic9FawaAMtZgR39LSYmPYcLM", + "tz1REnhE8TEzXdcWSRrzBYPWuveyY61Pe79R", + "tz1TrDkd3wtJcYnXZiB1kdoHtDJ61eP4QMA2", + "tz1fKL8yNKW98UGCE5duxSyM11QqzFBvQW36", + "tz1dPXJpxXqqLeoCs3X4GfribJKfyFVH1Jta", + "tz1NhzBdBcokEFPuzfdMrjihST3WU1F7uTGe", + "tz1crd1XnXNsCfgXVaHzYpsAe6XBEuhcYRF5", + "tz1N7T11AEwWAoqE6pYyU8ZYcdfBnMyPmr4X", + "tz1f5V7ijjQ8WBN5UUAnQvGcdXg7cAPxGCUu", + "KT1Vhqza4MMuELxENaiBYc6UB7syRpaZ12LF", + "tz1g81GLa2GeT6AgQ3CxtYBdwD3kwMLR1Hpt", + "tz1ifm8828dvFuS8wbwqCGhyoGKoXMAkpqbz", + "tz1ZfX2axfXid7Bnt2BiSv6QonweVFuuaAhM", + "tz1aJtqVgev1Jrc4utBfgZDj83ZFLjJKiZJu", + "tz1TyyjZ9adDW6rranHNXQVqEMp4Zb2rhegW", + "tz1iZS4BRLqyLbWbyyKt3e9gvAa6MJnDM2qj", + "tz1XM3wst4ioyMBHdkCVMdo3nfqYzb6zqbpn", + "tz1g54U8WwX4h7sVAfwNAMfmN191E1nYD42V", + "tz1ifvWnxwudcmQptnvbb5aRyDyWLLdUJmv3", + "tz1RDNwx22yxJ5x24ZxsrqFtA4bXY4gtwm4Q", + "tz1YvE23HCvxMNPqWsgQyYMw8Rm2UeMnPCMs", + "tz1dYeNiX8ayqUAc1SzDnr1iy259L5Djf1Rg", + "tz1Xrk1gZ6UGs2zr1RBCgexckHpS8CjgtdX2", + "tz1cp2AxYptGFABzTbnEWo62Rhixc5HKpjFu", + "tz1SCWJXrAiGQmoBPMLGifjrbTi7HnKgEDdu", + "tz1fxbW6z9xts7LnbXqvcdoqwp13rBavG6hP", + "tz1imF1LwtUxRojZSK6povb8mePfxQyk7UiF", + "tz1faBfWwvmovgkngNv2v4bW313jrepqdjAW", + "tz1XPjXcjWvqiNC4erXakoCiMY9Xx3omBRvZ", + "tz1iuPqyGQepHBWiVgTTdndbpnfkqckQb94n", + "tz1Kuu9FQu6L4bkNwLt39BGWAMSfDefWMCR7", + "tz1eEea8fmMweaMGbtUSa3AVWE8pgC7WM5Ym", + "tz1ceedKUzespKvmnaZApaXXcZTDJdVjenBa", + "tz1QbVugeaLaXJXqgD9s1gAYMwAJkW9rTgn3", + "tz1NqVdJps7ppiy5EbahVuAmDw1iKjhHsXG9", + "tz1UJ6u1bGV182edaXg5uPdbJq1qHR6xdJSZ", + "tz1fQiLH4SyuXumvKejsnQZgdnJ33J3kCqk6", + "tz1SBTErzCAU6o85X4xTdRzzCHQ79JkmGgRx", + "KT1UXH1LJ33HSaEvzW1Pk92tLbGEdsqcN93q", + "tz1iRk79QEsJ6Lj5F7pGaTAiQKTYw9RSUqzU", + "tz1ZKvoYkCB8otTqdWp1Mm3WvemXMQCSpsgT", + "tz1R6esD6XuzJ7hrC3ngrWdafh9FFJ9NV3oT", + "tz1bsVgtu9zggDAMvHWPWZET1wMEMTfzDTL1", + "tz1ivnzrqG3bpXuDchcS5KCpQMvEvB14Wxw2", + "tz1MaKRHHCaUqfaY8SgiHBzNNgvUF8EiB9RE", + "tz1LN4xvgHB9dqiuc9fqco1ZEwDueXDgDw8T", + "tz1i55Li1zdF52PXSKGavRjmE6pCpSgmA5To", + "tz1V9wpVevfkEfNe2JnsBGuzQKJfpGzvs6vB", + "tz1dGRzqFXkur4d4HEr5q5ULSTpxtT8a8y3t", + "tz1QVCn1BYxpeWSVsu6ZvoSm1vMwFs3U49ZV", + "tz1Ltc6HqhjcMEXGnW8wSaqEJfi4kse77oHS", + "tz1LzvmQDVt7iTDevkAu6TZAd6LkhYaw5i8W", + "tz1cGaQgUitUa9TYfDdgAKLY5zyh5GUVHPzs", + "tz1YMFNXmBU81a3hkDAf5w6oADRPuieefX4i", + "tz1QMMwLkiHSRxXMP2LUuLfvw4HCq2c5JfMk", + "tz1UYdeecJh8w5EoraCHT1TgKA1bL4jGaDWJ", + "tz1Lor69x8DPG9AJ5xSthwVqQ8XtqLvnSofa", + "tz1NUHJF4PcYq1QbN3sW7RX76b81r96hKKoz", + "tz1YEhhVsJTQkxcgD24tQEjfhBKETkdBip9H", + "tz1SVDQFfuBiQV8qbhjw5YGxxVWFkPvEmodP", + "tz1hjZuttQSUcSbkg47i1izUMykXCcdqq1zx", + "tz1fF85RhHDzszowsTj9KGwcFwfDjfWqX7UM", + "tz1LsXSAtqk2UaAi5UqPgnxiMSx5aNarTiZt", + "tz1ZMLcTZuhe1FrCtbbTyiEp4r7PBbQZ52HQ", + "tz1dLBPNqqKTEqWEMqyzh64jdTVMoaZij9sm", + "tz1VvsF4iSFq7KVV4YFznaN7ZQYSNqcrQbyS", + "tz1ZbdR5gF7VrGT81o2Ny4c9UVfCc7gzB8En", + "tz1gC8bBi8dJKzEn97fvc1cp31qBctXUHfPv", + "tz1WsYZt814Mg9brcP2scWD9CcCywj8NnRBQ", + "tz1fv4smnQUbKXARxBKkUh5tQtADqFMKKQDJ", + "tz1i3UYmtRdoDwcHFSRV2e3Tk47fchbwUMwT", + "tz1XGjuyXeeCK3EuHYnSVMqqeJj41aNDzGDG", + "tz1SgfF5YhWA7Y1L5kEwv5cgRTbLm998fJC5", + "tz1SoikxCAviVXxs3pdc8UArM6unU1mffMHV", + "tz1NnvH3F8SfaB39KvD7Wyep1ytDCXjPoCJ4", + "tz1VCjP2P3sBtCLQXKkDG6xRyz1o6Sh4cngZ", + "tz1YqLMuu5gqPcWZjGAaCY4cHgKFW1bUYeKR", + "tz1Nev8pcv8qZDK2q2Ps4isYMtcJpXWaGcUa", + "tz1RrEVWkWxxQY5uLuBbVU2WR9W3EFtU8iKf", + "tz1dfc5ei2TSihvEpFnyTTb9nuQbDWvEEEvN", + "tz1iGL8vPK2DNvYf67FrqdsTDyXCtpBMbgkC", + "tz1YXFAkEgAbgy5Mrsr2DnPhbuq2WnBhnDCa", + "tz1SJLqfbEyGJ21wfhMJvxgu2EjQ346o22mZ", + "tz1NwPTbuzs8s6mrGEJisP9CaXC458jjzzPF", + "tz1VGdetQxEuDWGQYE5BDREBvpzQY9javJyp", + "tz1awa88jNvcsmbBHXbGLk6fcqEycYZecic8", + "tz1dJKVHdNapMkayYcmHFVYutVXXHx5mTKri", + "tz1NneEsPdJRrDgse4TzLpRqvbksphYBXBMY", + "tz1gtGWmzyGZTz7D1BheVa4ooocxjwamba4R", + "tz1VXvbmwHskMRHcbcCLi6bihPt5KNtMgVeX", + "tz1T5MBz5WXy4mCrdVHy19zrFDa3uu5vuKG3", + "tz1TH3yto3yViq21nG84zmcTmuvRfVgfMRGf", + "tz1eJ7HaiQu85aNYwXnYByr4voQJe65wWTzv", + "tz1Vz1XhyYidM2zjSZoN2H5Ku3a4ctHVvGm7", + "tz1MVTqQAvvurF7Abs4vBmPUoSFtqPuXacmv", + "tz1hFFvzPH5DxuHA4ivQvrtEX92FGntGMRBi", + "tz1fmLPPwGznV4R6vFyW8sswUZYwcYLJeYAp", + "tz1N6Xh2h2K4unzgXv1XitABtA3eB26wDAUD", + "tz1iGEPSzjQN8PzT5FrGUzhRQnx59hVzeXn8", + "KT1Prk9xaXSd7uz4NzWQfZ8bWyY4csVvox5w", + "tz1et74jh4CLmpfmvYCG5398iygUkdL962fy", + "KT1PHojJp48asdfyvT9kMmnsEzB6cdUGpwFf", + "tz1fNt7sqTh21sekaMdsPTQvjYsC1SduMagV", + "tz1idn8cD2bFaftnFzvJ2gik9wGuWKDGmhsP", + "tz1Qz93toMBURzKyjbECFe8YKAwARu8t1C3C", + "KT1FBMtK4T7K5UC3nuc8YRG3wnQK3oaCH9Uo", + "tz1Ly6UMQm3NCmDQ2udu6WvPCJGqauhR9FWk", + "tz1epXpov9hcoRUaGVJ222t67udd3vV6jn35", + "tz1ZVR7QMhJWCKEhp4SdynXNnikdxTs5XxQT", + "KT1KRdu1hDLtDRufZqNMU2z42uKrXhmsmzJd", + "tz1ivo3rkUgJQ1Nbe4VEhNetCREAvbGZwi25", + "tz1UBQvZkovRpZwML86qTpL59gedS1FeWpRw", + "tz1d9CzUNaFMmsnUZTihrz6wDA8ZP3GvAKbj", + "tz1MZHrRbLDMczK4xtJP1BrRdoYnoMq6c3P7", + "tz1Rw3VKh9yAWLWaQMhzWoRRQoEouGTCzgV7", + "tz1iABqHT2J4XKEnHp8JYJNiXEJtFg8r9RbC", + "tz1fxdeeUWT6YG5aSQcaJVU5sbeFCQYKCvPX", + "tz1dNA8PnEfRgV4ZqrX3i43Lh7Rxpx9bwy78", + "tz1MEEdk9w54LTcHz1oSkwAY9UUSepg8WrFG", + "tz1Zgo1nWvejNmjhzqEYPoRc57JhWrKhetAH", + "tz1gk9E28K1b6xQNw2wFLG9WERwzKDDwVNT9", + "tz1ftbRcC92jdKCTj91Qor9EkoJUcwqFFvH4", + "tz1hjorZSyLWMvupoBgWZsKbDFyca4B6wK36", + "tz1YNktyxUEzwpKq6QaWafka5CeKokJAEqi5", + "tz1KiuNcJNJ451967gXPwSDLvQmXryMvgTmL", + "tz1XDqZ4z2d5sRLkywYRwEMBQH5hHzaCaRre", + "tz1aQNn7eMC7kP1EyQetvocKS4TXmzEd5Gaw", + "tz1fnBJmAxoJbfAaMcCar3Aa8MFFH69dKYJv", + "tz1cZwxsasN1KorL8hYJPBy7gaBdNtsbjNvm", + "tz1b5qJrAgViKFPM5BdLeVasrxest7EWnf5z", + "tz1h87YTFnTCHKHTUEG2BxWq7DSRf861U8e6", + "tz1LPjWu1P11x1aizsD9wmqzey7ob66vvymg", + "tz1NBmAeLwsXxLcvAwJXM4nS199qkFcH4313", + "tz1cPL3YSMFiRC2yiMvSr7RLPVg5H5XhNvgW", + "tz1ZzGYssgyWGEZYVgCpMiYA1eBMWxRVrrqP", + "tz1ZgEQPeGYXeMLePL5sgR94RrRxwbsyK85z", + "tz1NcRjeevWE6E5B1pBsDexSB3cPJDTpQ9UL", + "tz1dBhoxSAU58V43Kvb7hG71iRxsfzmj7Z2y", + "tz1UwEDdQfpdcnYtfU7BRqXGPXbeaJmXk63c", + "tz1cpiGQS4rjtqnbndrbRnihtUjKH8aa1yHf", + "tz1eBdroBUqaUQ4h4xYXB26z67L8cj6ZyLsx", + "tz1Lk6U6erqH6EEuqMqk6u8gjqtJybZTirDs", + "tz1iAeHTDNZSwJjXaqbRyfyp96ych9j36tW1", + "tz1PDpbmvvBbFcEzctGfNt9mvvVTgTWxGGPZ", + "tz1RkXsWMgAtz85cD4iBckPC8xUFf3fPUFw2", + "tz1LcGrFcHLS9jgmWij4u7EWJDRrnU4xhVGL", + "tz1R752LZLPkJ1dhMs49zJqDcRZMic7nvL6g", + "tz1bpSiotWsQCz7jLjU4FV5K9PCZ79jinbs5", + "tz1bbsn8DMXJMEW7gVeuBbpMFBf65dq3VTtv", + "tz1V7aymCngroTZBxraVxp5kRtLh8qFRLcMN", + "tz1WxVo86ucoAE5RwCUe3tHTVV7r2GwRRvMN", + "tz1VXY3dXhE1s5huXnyFT7vfXgNroR5hTdjr", + "tz1LrYXWJ8Z3eKLSAYfCUaoZjpaqNrTqEd8w", + "tz1ZdYg6spcG9yk4ZXHHLcgNL2p8Y5wyhWYp", + "tz1PSqayN9mB1Wxk9SMjcGixX5PX9zRvtLZ8", + "tz1Pnke8YsfcDZfcqpZwpyFxLFCzEnSG9ews", + "tz1Qcgog1zYs6evgGP6aNEpGvDnCa7rAPvx5", + "tz1R5S8M9FAHs3eYjKY9ci3RD6iBgV8QCiLM", + "tz1iwGHsJu1Mq3eGGj2dmp5xj7N9kqxvuJzy", + "tz1TiEvTkhsuF5drB6Q9gDAQ3ejjp9GkMjdw", + "tz1LQPiugXCFuDit9232iqWGfj41PQGaCKvV", + "tz1TkAAz3CXdKiN4T8jAqxfWCBddQ39Vcewf", + "tz1ViczpurHDugWPgYzh5sE7Y7CDUB6qxseX", + "tz1NMf4uWqQNaVLFLjztKMpYphGdGSPu89pu", + "tz1ViNQrnj5aPjhZ9EQ1UuFcH6UUALqo3EUU", + "tz1Zqneq8GbnQ1G3g1Jnh9Vv4qGMnzLXbt3s", + "tz1dHH1xpCwZXE66WWK4SKDPLzF1JHX5KC96", + "tz1aXL6EouwJR3yMDK9jgD7zL5tpM12Vx3RY", + "tz1gtaaw2gzQjJmx8R17BRpYdkR9haE7i811", + "tz1aj98BzdTbicVFrqSYeAFjRwHGmRAwo2J6", + "tz1TS2ByHGPAgDb2AYv3bQWakG1tiH7uPwQb", + "tz1Q1t1xazVvEgN1dmxPCDXt8hqK9BY6qF5T", + "tz1fYzKUnmF873zvfcyUaX6yvRHbNTqakkSw", + "tz1g81md3cSqEtozkZggJnvRUNbMCbFHETqL", + "tz1bENLm1iQRnPsybc6HvrfR3W2nvuGErdFK", + "tz1TktVVrHESq3mdw6hpohXQFjbpGkdERsKT", + "tz1YSQ3PA5t3drYuAXYX5VE2mRcK143vjkKJ", + "tz1VFsJNozUp4mmtpv98bS2Q3B72qXWagDsq", + "tz1W47pyCkjpiWRAHmR9rHTmM5a1Yf9dtzkB", + "tz1Td2RL3zTSRZFac1SaXVxcXeAXHzTATsAU", + "KT1Tvqr6CTN3Lj2usqGPNG5Uog8JdgnDnhps", + "KT1CStwHYoGYzXENQamy2nc251enF5wk7Yjy", + "tz1UZuJ7Ae3m3rhsBjig955Fcy8vyfPYTDEr", + "tz1Qs9UZiWESjBJAA1SkqDm4eMDm78wo1QpN", + "tz1ZeovPMP8hy3PaJDg7AC8HP3rjNKpfRFes", + "tz1dkzioZTg4E3yVShiX1hdpAkE84wYhzRL8", + "KT1QhJRX8884Ccb9EKpNNFsbB27P6sRoqo4t", + "tz1Ww975VPEgcZdiTQGahABVkMf8yrcZb9A3", + "tz1RBv1smMW4xtTWG53fkzRZJGPmMotNJTEE", + "tz1cQD5tsef53FPzMmN5kLoLjvLD7VAGGQU5", + "tz1SUwahJKb5V9dxwk8N8quQWc5bQ1Zm6cva", + "tz1ciLo5K3g1pHPJKjEQp4WNvu6e9bxDtmwT", + "tz1ZTv3NVL4ry3qHZdmo7Y4rLjciHRcmptbA", + "tz1Z8TYYJsQgCqvvMtDo9Z56CzAtdVEi88NA", + "tz1hqbwdkxsh2MNaqoPVNycWA6cu1EKonKy8", + "tz1M4QhH1WQqrQWtsnDvyAqtfm3S7UcFAb78", + "tz1hxJteiSNWfmj12WdmHaPsdGtbZxZn1W9H", + "tz1cEnJ8Cu9AJcrfg9tajTmBEyTXPJM4teKP", + "tz1eSjS3Q2Rc36o2hHMRNX5pErtfGQRH9spH", + "tz1W7XN1Si3eGg4b6a7opsZ8EKjdiYVvmtfR", + "tz1gwyEjft79QrS5RKgLM3WozabfFeXn5kSC", + "tz1avdpHLEVbCKJPbFRD8pqySrZjPT64meHC", + "tz1NjziRqzmncVzU3CHXyo5BSVsn5CwXrUxS", + "tz1diyBGHXh6QR88Ps8guLmv8yCyyYTSoYjK", + "tz1RNVWP9MqtDSukfN9xZjNibKUMyq9ih2m1", + "tz1N1wThWmdxubf8y18ySS4KG69tR7icTHLn", + "tz1P96NympEyX7h4K5az2H8qr5vi7HyYGd7T", + "tz1Y7Ft4jEFvKE3dAHMUSwz9W3gXAWvN2ADR", + "tz1ND1DoSpPTtyooQQLxfNq7w8FR9dw9ZzuR", + "tz1SuBRZzrE98AeHRMy25zbNxwQfT5Wv1Cpp", + "tz1Q8HLHCFUFQVn38UeiSCNJUQsZxF2d6vtp", + "tz1TJrVZoozuTqzdeMakTnJQEogvm4q2531m", + "tz1TnfvKsMQajLzijg2EoKpE5yBGmXDiRQ1K", + "tz1gzg3UU6UMjVMGrcuetgnQ6btdVUGxYfyP", + "tz1KwcHHYUT7kMKeY6zXwUAq9Kuj3ryeX1iy", + "tz1WXuFmAiWqreKWY465FEps1Ei2XrAyHGGt", + "tz1TZafuJ3eWM3d3mckARNaP2oxBNyjLQVG6", + "tz1N7mPBeSrRsAgcukmRj2Twp6fvNshT1Uyc", + "tz1gFFSNHfQeNED9wYqThHMJZm5CNe6sFEUE", + "tz1L5xtPTd4XceH85n9W8vB3TjK45XGt63hC", + "tz1h6rqcMhAoEG2cMhiPjdJoemaHenY9mH7L", + "tz1bK9XE8khrUn7VxmEuNzF6FidGqpjTTXDs", + "tz1NUZw2MUG2AmSrtwTF3qdAUwgqBfnAGyu2", + "tz1ichwjUoGrUSawDKP6wMVLghJNX196aEBi", + "tz1UEEsxKrP1FH3RtUFt2esg7UdFQ74VeasS", + "tz1aNF6AiXu5uG6LENhYvJMwqYJc1bKTRuKr", + "KT1AG7uQwt3VX6JZah9KbD8n4sYSyaTUNqB3", + "tz1byac5DY5hA7dJ3uPvWvYAsWcAcdAGy953", + "tz1abWuJnBvT9o5TWzkEA2u3BbQ2mqFNoX3e", + "tz1Qin5ErcHtxtZV1njJ3cmzjw6GghWsEGGc" + ], + "delegated_balance": "143547306933", + "deactivated": false, + "grace_period": 251 +} diff --git a/platform/tezos/mocks/validator.json b/platform/tezos/mocks/validator.json new file mode 100644 index 000000000..01568a018 --- /dev/null +++ b/platform/tezos/mocks/validator.json @@ -0,0 +1 @@ +[{ "pkh": "tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m", "rolls": 3726 }] diff --git a/platform/tezos/model_test.go b/platform/tezos/model_test.go index cb3ee9643..2add90286 100644 --- a/platform/tezos/model_test.go +++ b/platform/tezos/model_test.go @@ -1,9 +1,10 @@ package tezos import ( + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" ) var ( diff --git a/platform/tezos/stake_test.go b/platform/tezos/stake_test.go index f06df8c4b..d18c7db9d 100644 --- a/platform/tezos/stake_test.go +++ b/platform/tezos/stake_test.go @@ -8,56 +8,52 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/mock" ) -const accountSrc = ` -{ - "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - "balance": "91237897" -}` - -const validatorSrc = ` -[ - {"pkh":"tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m","rolls":3726} -] -` - -var validator = blockatlas.Validator{ - Status: true, - ID: "tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m", - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: Annual}, - MinimumAmount: blockatlas.Amount("0"), - Type: blockatlas.DelegationTypeDelegate, - }, -} - -var stakeValidator = blockatlas.StakeValidator{ - ID: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", - Status: true, - Info: blockatlas.StakeValidatorInfo{ - Name: "stake.fish", - Description: "Leading validator for Proof of Stake blockchains. Stake your cryptocurrencies with us. We know validating.", - Image: "https://assets.trustwalletapp.com/blockchains/tezos/validators/assets/tz2fcnbrerxtattnx6iimr1uj5jsdxvdhm93/logo.png", - Website: "https://stake.fish/", - }, - Details: getDetails(), -} - -var validatorMap = blockatlas.ValidatorMap{ - "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93": stakeValidator, -} - -var delegationsBalance = "91237897" - -var delegation = blockatlas.DelegationsPage{ - { - Delegator: stakeValidator, - Value: delegationsBalance, - Status: blockatlas.DelegationStatusActive, - }, -} +var ( + accountSrc, _ = mock.JsonFromFilePathToString("mocks/" + "account.json") + validatorSrc, _ = mock.JsonFromFilePathToString("mocks/" + "validator.json") + mockedTezosResponse, _ = mock.JsonFromFilePathToString("mocks/" + "delegation_response.json") + + validator = blockatlas.Validator{ + Status: true, + ID: "tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m", + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: Annual}, + MinimumAmount: blockatlas.Amount("0"), + Type: blockatlas.DelegationTypeDelegate, + }, + } + + stakeValidator = blockatlas.StakeValidator{ + ID: "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "stake.fish", + Description: "Leading validator for Proof of Stake blockchains. Stake your cryptocurrencies with us. We know validating.", + Image: "https://assets.trustwalletapp.com/blockchains/tezos/validators/assets/tz2fcnbrerxtattnx6iimr1uj5jsdxvdhm93/logo.png", + Website: "https://stake.fish/", + }, + Details: getDetails(), + } + + validatorMap = blockatlas.ValidatorMap{ + "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93": stakeValidator, + } + + delegationsBalance = "91237897" + + delegation = blockatlas.DelegationsPage{ + { + Delegator: stakeValidator, + Value: delegationsBalance, + Status: blockatlas.DelegationStatusActive, + }, + } +) func TestNormalizeValidator(t *testing.T) { var v []Validator @@ -85,8 +81,6 @@ func TestPlatform_isValidatorActive(t *testing.T) { assert.True(t, p.isValidatorActive("tz1V3yg82mcrPJbegqVCPn6bC8w1CSTRp3f8")) } -var mockedTezosResponse = `{"balance":"19924380870","frozen_balance":"16854253212","frozen_balance_by_cycle":[{"cycle":240,"deposit":"3072000000","fees":"15676","rewards":"90000000"},{"cycle":241,"deposit":"3328000000","fees":"621522","rewards":"95000000"},{"cycle":242,"deposit":"3648000000","fees":"4360","rewards":"101250000"},{"cycle":243,"deposit":"3392000000","fees":"28321","rewards":"125833333"},{"cycle":244,"deposit":"2816000000","fees":"0","rewards":"55000000"},{"cycle":245,"deposit":"128000000","fees":"0","rewards":"2500000"}],"staking_balance":"163002104470","delegated_contracts":["tz1YGsmfUfed8fmG4QLhGB1Y3gCMX44t1JTc","tz1WnfCXDniXhHzbXEPTQ1JSoyb7EzotYJs3","tz1RqtpgLw3uedpWaDVC5WAdvNfiUnsY7ZC5","tz1eLjmx4j7QLX2RabyS8Pf3sSe1U6H2UZji","tz1TYhMcdYah6QJWQbL853x4Rn6fSvtHhqDf","tz1XcmqCntUEzrpV6xcvw449Ro83KU5W3vv6","tz1QfbGBmr5dvha6agPcmsvnaz2EfcctW4ZJ","tz1bN4kotiEE7dAEsTGWpNTF2DnjJw9NNSoD","tz1hoj3Lw71qgsQf5a7cdhdU9crEH3mAAaNn","tz1SfvgWvSBxNsgta6UCmytMTPHzMsmjMB54","tz1ZsKynrRs8KNe3ao1ZMaKk6he6VUWtjcFU","tz1ZEKCiu7QspFVZL1svyr9vvir7tTm5CEdW","tz1gScW33c2EjpusjaPCm7r82QVZsALnNsXk","tz1TDnm46TxwLRbihJf2yTQLJGJYe6k7N3Kw","tz1NQCizMgAvmjhMJEidnTNPFEPHxA6XLY65","tz1dp6YqFkjoDZqrceSEC7cKFDEWbynyv7UV","tz1RctGdDVhQFoqL99bXJvYTwQNJWEL2Rx6Y","tz1hqd37vwxZcNeiNMrz6kpujusPRxcaFyhv","tz1crpuStZ66tv89kZMQbiGHk2C2RyD87o2S","tz1a45AtW3gs964AxC7X2sShAj9wsBGQjsWQ","tz1Xi1AtnoAv74PAQFDUY67TEjww1J2e6FaQ","tz1XqSWe3M9eEd2mueqEWmgKZLoYVJCRC92B","tz1Y5JZMUEsuX9oicG9AqXG8XWPHmKeWFrb8","tz1LVtuGkbCgEZsZhbzu1sonVg5xZyrrWqGD","tz1cfqx7H6qsXgsLTHFn7hWjdkU1SjpzpFyx","tz1SFMBqUwq6JJP1mQZfp8ae4GsfGSM8812Y","tz1LeU73Tm2eBcUV1prcHLjK1Pb7KgC8rPTu","tz1dMvyK57FBfUqzSenaWSoY1Rng77KxwTT8","tz1S382giorXLVdzw79LVcMj5MLJkYK8Ex8d","tz1TAscJC43xhPBNBESuNupw3FhLsfE4Ghxd","tz1eACKAsqr5faLgsE3ACdHeejrdM4igY2qj","tz1Ln7pr3Bf7Yxmnf57iEkgEUvo7PrMh3HJh","tz1XC1DbtQjUu2udaeVbSa3G2rrU9dJKmN6V","tz1PCa2Drre9MaJ5pcKpQHh8A75LDEYYA4rq","tz1S7SacT3Pe8EfDfMEnR7fdvDamZDiwVMoQ","tz1U6V2mWc6zd31yFXME5Xnoifo3PeHQhuJA","tz1V54Uhpp2i8pUVEFNcmhrkJqfDZhqb5F5C","tz1aTmVHkGBChKHfAqdJjjadkP4rz4MDjbJS","tz1dpijoKv5dCFT1BvtEmxy4YLcCsAc9ZGeh","tz1Mmv9StLbPu3jYVBDoKgNJTb3FD5wuA2vA","tz1PkJZs2Eb3ouLd9cTf4wSQ3n9aMz7YLGNR","tz1YpTsHeubr7WQaKu3Yfs3m1gKw5QP1MbdM","tz1ZP1EgEkNwB1nYA8bQdJ7YcttsbJuJCZLe","tz1Wh7XciNS6oUTW14bQ5PD7pQjqae2tNA8S","tz1bgRKKwMc4s8fxTDJrauCx3NoGLSRJ5B49","tz1URZ8CPFhzLz3UjQD9zUjTZY38XwGTCiKn","tz1KrUvC8nUGRnk4RXtqAFLsJj4cbtXjR5Wg","tz1f8eDjy48LDcWrrNTF3wwkGEjyXqDcoMro","tz1RStdCWJXpVVvYvAB5VZXgzrxPGoHpEhjK","tz1LWjsR3LiBDPyvuf7S1qJxaVKNZV9TSbaW","KT1DMboG5KtaPbMTaA2PeV8FqRcqbt9adzQE","tz1iq1eA7i2ogVCQ52g3zeSEqCrFTSVxhE2c","tz1Y9tfG6Gs5oFdLtcE9obQaxbwZyK8CTn6e","tz1XotDGePt679YtqexwfFvE9AutjdkvemH2","tz1LG4KEFVjp1MxSCXQWUSyoZpE4Nq3gbxHy","tz1TMRCpNgKAdp8GH3jXAVR3MuLMMPZBzevi","tz1hZY5ix3GTTUMAsv6anwD2817RspnnEb81","tz1gzPsf717fNkpFVQYuNAKBBQngqGx6CFJz","tz1TTxhXmRRdMAKdF7ykdyybgg1baD686JWs","tz1dPnbKhnmJo3J7S2rokMSmTtaWNGDeQuYa","tz1irRBG7qLAeo6URDn4bnUb9NByoLQUHN7K","tz1d9d9brjpFRrErRF8tT5StDve7svAQueTB","tz1SBRVFKJCaDnPRzHrn1Pc7NG61tqNY1HpM","tz1h4Ag9NixUomVaFo8MatDpEL84JEEs9oFx","tz1NVzxdVF2gy276bGAt3TFJHWUMtnS5BZrN","tz1Ytb5C7xDvWArsif3cEfWC7NpEiWkGVcW4","tz1WQ4w3WQUzReKAehyDKkVQjiVNJLuWoCrx","tz1StPqh4Jybs5yE4adLLBvrirwm7cuoEMC3","tz1f5yKJQwdEx1XbqUreT5E5MG2ddoP9sxG6","tz1hVxLkK7fDPCsgRytKyqSYoRGdPYkRAHK4","tz1Qs7gcTNMN759qBUukQmfA6cUeWzqtU7sq","tz1SsR67T1ykErBtVinVMCWhvwrUWBMkzxQu","tz1QD8a5kJBGHArP1DHECBzj4gbRPZuBGGL9","tz1inQ6S764Btu5HgHRGMg72Tee5UjQtri7y","tz1asvE47tkUoYPrb6HrVzkHVhfx3roZA56f","tz1ZqdsHNTeYLCw3Etw1BwMTRbU3Ji42HT4N","tz1Zd43K6xBnpddV2pv2PcbKPBXpYo6qAAxc","tz1YbEBGE1KQXAMLiQEnXVKLoNKVAmtQxJ2y","tz1QFhih66LJDFpm9T6a2gWdg7551k65C9ke","tz1T4RpJjC671WadSwA145zMZNSCmvcwGL5R","tz1Pibvp7EttcPX56CTvmxPsSLqwsDhd2fC1","tz1cFu4B4afDVkcojpv43h7wbv8169VA7mSU","tz1ixKgGdRoSzsp57qe5WXHLbeu2GRpXYmGW","KT1M6T4ft8UXXwFxa6QxRU3T1JDEKQBRK8Li","tz1csRh2tzRZw8dcuAm1LMCMUQBEq7N3EmY7","tz1gaz2QgwUTyZypSmMx72oUrraD1hZ4CWEB","tz1TpW2WB8Y9mYsDp2Lx4EoKcocyFWApScFy","tz1f9Hg7KF6xKLabL4UNLPdtJeohQbuJrVa2","tz1Q8Q7sT3r7pdGGyYEtX7v6jTxCwJ3bSdtJ","tz1iLAxh9M6xcaNMVhb5hGxZb9qvzBVwo5UT","tz1XXHuK4tMKJZBQDeDFCpzWdH4g26Q42gFW","tz1VvZYohqJvKzTKsRYcfuQuak6LYFao9hkD","KT1E6sM9KBpYWoK7ZxoxrcAzbngVhn9ZxkPw","tz1TuBtRJ5bGa7KRyhiZcoFiZTHXnuq4wz4X","tz1fQRtYbQqenvb171siK8KqScBZKHrsqKW4","tz1dn9tn4UqhwLiAShcaq63oiwzQ7X8aySTz","tz1Uvknh1VNhYYQbhFaP1rDU1GNtFpGWG98c","tz1ZosT8MD6tibQDYLbhfTm5Z9oQPL2f7LwP","tz1Yk9Mz6hSBrq7qWLUZKDqcuwyu19i7FS4Q","tz1i5wEnEp1Wf4WiL7dFxiTj81VSiDprGWyZ","tz1fQv9BGCjZC29DFPSmqNxkjFx2tLzRy9Kn","tz1M7TVpisBJfPkkjrfsnK7CZyRbVb2Vdooa","tz1TJ6ZPJVrAFZUNhReL9FnhzXXd86Hmtk3d","tz1hbeGj3krpLMdKMumeukTatZcDCG9RGnyT","tz1Xm41xUyqvV5caWkpx1ym2p8uTvJPKZMdw","tz1XZEpd7EnfzmjYKfRY2zrfEd4trBJWBybN","tz1QZAQoaXbLXW3WjYB8os5xjwe4mB62KjPi","tz1gd8XNS2Me4oRXq9XTkTX9kYumRM4Y6rXf","tz1aK1rKDWDSa31kB1SwP1tD3BvPTNQWXwwK","tz1Ui8BtvQpJpF155ppgMZSEpCKEDuLXNMX4","tz1ioGHFTom3ojBbcfgEb8mt1f1ceobVEcEq","tz1LxreKnQEFW2QB3dZDX1bNThcW8vmem4E8","tz1gu2wRjBfY7jpMokMDZGNZVBE5n98J65g4","tz1dfAqA9rhx1tFuu86FdhBwKMwaisVe1dEg","tz1ND2YvsV6mnWSUHA2bd1oUcTmshMbxYV1M","tz1aSBidSCjNqLcEk8BYvA43EenEZNtsvkuW","tz1e8Fk5whgxrPzTZAMiW2FbatdaABNt5hpX","tz1QeU3SH1pGYTWmKfZKovH2RiiqSnd3zFPo","tz1UkUgyb3Au9GeQx6YbcJJaafNDpgGRLDeV","tz1WPnZxticG6xGpHNhaV9kvU1PfgYiMXp7A","tz1LKVTXzQtDwQWXJpbe88Q2U5TceBrEJf5i","tz1X4tzFR73YRBBora46aevdGn3aqz5UzdrJ","tz1PouWF6hyoHmMYAGuwDBAXJKL4Z8yixEwq","tz1ib38e3VCZgvRxc2Gj6KtAgAv9FkWx3xt1","tz1Ndenm8uaonPs8oo7iqXQ6RRho6cG8GBd1","tz1WRAfQ4c98Lxz5k2j5QFwcaw31Z6zSuiza","tz1W7G8pgorMWDcWSsTpQLuQoKqVPk6MNTV5","tz1NY7t1otGmLV9VuhdApzsqwwqGEK6iLeyH","tz1MA5ywEYaPNzJWeLWBDfvAfZmryeFdrexy","tz1Rzq5gz824wG4gt4MPX13oKojnY3cJVTAB","KT1MmHkxDKy16ETe6CKY6Hs3SXGzAeMKHcmy","tz1aYL7YjKn8zFV8kCNMg5qjJTXQ5sPhnVQU","tz1Mqazkg2SgqB4ibXxpFudp2HVYEZ2s3t59","tz1X1o4zSNrnTDouETFM9AXQzamWcUkEj59n","tz1Qe9fqiQnizh5gzuURT3J24MQxd7A9qxTt","tz1UWyf2N1yCiEkfyCKdyMitKMAaUWACWpro","tz1LYCQsxVf2RdDEWcG5N1zY72XskyXevciC","tz1XD2yz8UQYGJ6BRb7h7wZp854fQXC9DQFm","tz1iiT4XbLvffTJbGhuiCg3ofaaNdLX2thSu","tz1YrCk1KZu9wwn9vCUYuZp8medpViizrZwK","tz1QPmsd6BS9CUAugcNGJP9me8V6qtEEYrV8","tz1adgGe3ghX6DH7kh1BAasaCGrf6ermGY53","tz1M7PNxBBCUx14jfdv5ZERWZWBhPJVjKHJD","tz1VcWpMRqd5xxoauw1urcnPQ2kZZxhbqgcv","tz1Y2nVkzQQmdVnDcuo6VDAgnBufoUHLXR3r","tz1bGvZzpjJZHzFJGQYWPVg4JQ7arsmX3CBW","tz1ZGn1qwM2Bg65xqNx37XB4ptSQnRh7LjED","tz1Pku546auwaUBm4Wht1zwZtfxg7ic81p6Z","tz1R5yUME8wSYtyZNpfWdoPZcQgNLtaUUvef","tz1b5HuS35FKB7qWvFuALXX6ZFspEWWJVjxP","tz1ihSZ12F2y6H778E6L4ciWzvX7rfPwmGQd","tz1T4yyuchdPqtZSbtsaBS3GLqLeUg8dJmb4","tz1LnRcJUtFBKcht4n2jo2PAJF1ufwAVa1nL","tz1iwdFtYWaicwc1dfJA6YmN7eRCX1RkaGuz","tz1aD3HxUFLSr6tmYuP7HKvx7t8WgKTY5pYs","tz1XJMJ7XjbHkkFkAWw9C8ocjfmkmTBXo5TG","tz1PfUUZ1YTRqP7qkjsSR1X7TCeYbRpnCfaj","tz1aLVDxteKdmBRaRMcQPQaEL2ExbDwQA7fP","tz1QoFWg86UsKYjtskkmBkz58mftgHLrvrci","tz1ZWbmnG1sb4KCkrjii1FoiJ1RcJEg7Tf5V","tz1VGrdEoiWdSpUFGZAbX6hxuQAJjEXqXvwW","tz1Q8gvcfGC74oaWx2Gb4TipRLb7aEfsWyAG","tz1QVsVf5VQfihDiBED7ZMn5Ai637z9GwfpB","tz1Nqf8Do6NFXncMzGhYasnif7iTJ8UgGHTn","tz1KotnQg3tbzTLxYJc9XW3dagmYjAMHzYV7","tz1QzMbAcThy4EX8ENvHZm2BVxQMmCY7wsUw","tz1YKTfdWtb6gzr26mRsLsGCNK8TBBVEHC1E","tz1egRyJLzTmC4aMUCRZLKEhtYd2MyD9f8RP","tz1NJFR2PLvbijMGGZ9LnW88CZxo1SSFxsxR","tz1fU6Zxx14MCEqfkSwDWRMqFmYmhygSJrcK","tz1aN9Gp5FXc7CQoR8MGSf3VUFohe6f9rFJ6","tz1KuQ5yDerio8tW294zHsYofWc8TQ3xnbaJ","tz1Yi1qojMoS2JhESiE4vAeo7dWUqQbnEQeL","tz1RxecATFfopVUvE9HS45rL6rgzGVg4cFG2","tz1hXRjun9ou7YN7sFKJJsgHPkGpdXzamzKY","tz1dWg4SYTFiYfPrDGBNCaNZunjCi9CyK8PU","tz1N7CRoQTrTjM6BG6PK4XfwnkEERKj1GgTt","tz1T8RkwAcBBwc9uCovercc6Qr326ezqtoij","tz1UkDYB4RgqBcRL7yYSikc8r6fpAeRVP9c4","tz1WLjJEwxQK3hbnZWkmEzGzQ988MdQVq1iB","tz1bLijXE1D8XxHjzK9wBK2udxNqXbHkMzFg","tz1VMWRzCPN9E7NLBfSHxFVzjZ2vxNPKRXCT","tz1eUfNmzeZWccsAV2ZzCovjMR4HSDH6eiiq","tz1VASv4WieYkgmUCeh2j5ftEw72NkkuCDje","tz1fZH9g6npSMZgSGzcaqegnuftJ1AcNEQ6F","tz1QGzvcCDezxV439D5cjRaTFXC8Y2bF6qTw","tz1PxPHvFdkGY7XkyuV2eUDYH3wxuerKiYiC","tz1YJUngcjMCStvP7MABMVBPyFkU3BupNymQ","tz1NoKTHMvzPooEbyeMHQBaia7Ekf8aTrv8g","tz1aQHYPPW8dq7ucWUccV74cEyzt6AiMjrfj","tz1dpCdky48ELUbjrzY89Uy4fTukmmJdr9tJ","tz1SQcKWYJCatD4jVFRNtR8UVBmtZT5VAM3x","tz1a6rVyLh6z7akANZsBuxSb2g9gNthXuFM1","tz1eNv53m15QQhKYyREahAx6LCK9YYczEUPe","tz1Z5Lgu8CDhbWNdyEzXkCC2TrkHrSDVwMWp","tz1Prq1iQE4xMn3JqwK6rMaJXoGjS9sfWM3L","tz1hxtCEcD7idQJEDiJEq37vBkoRcwF6KC2X","tz1ZTmAakWGa9fefwoaomG7wFPQhPXepyxdT","tz1dXKPAsBG4DG6oKki84UVTBYw5doTGbu95","tz1ZGCukFkDD5ns2aA8HuKGrE68DVmbhLvvs","tz1cvSwVukfoTNS16f1Y12mHYqsrnCK2z7ZM","tz1PV34FXaBY5mqLLyjG8TdzNCo5SUz51d1a","tz1KxhXker6qezyPyzpLcTVXxAadWuaRMB8Y","tz1cZmvFJgdJfUoBF2USegkoEq653qx3KgxB","tz1M8NxQupHMQ5uW1k25wCYYdxMWojKfiVNa","tz1eqnkA7YZS5uVhH42WfZkwkECTxCkUqKJG","tz1Z2ERSqjQjTtGdv6XZJ9ZoffxAQVCLHrLM","tz1iXW4XFVvg1QS6bGhuPo1VCGT6WTgEaoA5","tz1VMDp7io6vgXo8jsLcgbsUB6Vc9mdAw69x","tz1edVs2PENzexqcwWv22pwu4HfcgXbKcV4R","tz1LSUEVASTpic9FawaAMtZgR39LSYmPYcLM","tz1REnhE8TEzXdcWSRrzBYPWuveyY61Pe79R","tz1TrDkd3wtJcYnXZiB1kdoHtDJ61eP4QMA2","tz1fKL8yNKW98UGCE5duxSyM11QqzFBvQW36","tz1dPXJpxXqqLeoCs3X4GfribJKfyFVH1Jta","tz1NhzBdBcokEFPuzfdMrjihST3WU1F7uTGe","tz1crd1XnXNsCfgXVaHzYpsAe6XBEuhcYRF5","tz1N7T11AEwWAoqE6pYyU8ZYcdfBnMyPmr4X","tz1f5V7ijjQ8WBN5UUAnQvGcdXg7cAPxGCUu","KT1Vhqza4MMuELxENaiBYc6UB7syRpaZ12LF","tz1g81GLa2GeT6AgQ3CxtYBdwD3kwMLR1Hpt","tz1ifm8828dvFuS8wbwqCGhyoGKoXMAkpqbz","tz1ZfX2axfXid7Bnt2BiSv6QonweVFuuaAhM","tz1aJtqVgev1Jrc4utBfgZDj83ZFLjJKiZJu","tz1TyyjZ9adDW6rranHNXQVqEMp4Zb2rhegW","tz1iZS4BRLqyLbWbyyKt3e9gvAa6MJnDM2qj","tz1XM3wst4ioyMBHdkCVMdo3nfqYzb6zqbpn","tz1g54U8WwX4h7sVAfwNAMfmN191E1nYD42V","tz1ifvWnxwudcmQptnvbb5aRyDyWLLdUJmv3","tz1RDNwx22yxJ5x24ZxsrqFtA4bXY4gtwm4Q","tz1YvE23HCvxMNPqWsgQyYMw8Rm2UeMnPCMs","tz1dYeNiX8ayqUAc1SzDnr1iy259L5Djf1Rg","tz1Xrk1gZ6UGs2zr1RBCgexckHpS8CjgtdX2","tz1cp2AxYptGFABzTbnEWo62Rhixc5HKpjFu","tz1SCWJXrAiGQmoBPMLGifjrbTi7HnKgEDdu","tz1fxbW6z9xts7LnbXqvcdoqwp13rBavG6hP","tz1imF1LwtUxRojZSK6povb8mePfxQyk7UiF","tz1faBfWwvmovgkngNv2v4bW313jrepqdjAW","tz1XPjXcjWvqiNC4erXakoCiMY9Xx3omBRvZ","tz1iuPqyGQepHBWiVgTTdndbpnfkqckQb94n","tz1Kuu9FQu6L4bkNwLt39BGWAMSfDefWMCR7","tz1eEea8fmMweaMGbtUSa3AVWE8pgC7WM5Ym","tz1ceedKUzespKvmnaZApaXXcZTDJdVjenBa","tz1QbVugeaLaXJXqgD9s1gAYMwAJkW9rTgn3","tz1NqVdJps7ppiy5EbahVuAmDw1iKjhHsXG9","tz1UJ6u1bGV182edaXg5uPdbJq1qHR6xdJSZ","tz1fQiLH4SyuXumvKejsnQZgdnJ33J3kCqk6","tz1SBTErzCAU6o85X4xTdRzzCHQ79JkmGgRx","KT1UXH1LJ33HSaEvzW1Pk92tLbGEdsqcN93q","tz1iRk79QEsJ6Lj5F7pGaTAiQKTYw9RSUqzU","tz1ZKvoYkCB8otTqdWp1Mm3WvemXMQCSpsgT","tz1R6esD6XuzJ7hrC3ngrWdafh9FFJ9NV3oT","tz1bsVgtu9zggDAMvHWPWZET1wMEMTfzDTL1","tz1ivnzrqG3bpXuDchcS5KCpQMvEvB14Wxw2","tz1MaKRHHCaUqfaY8SgiHBzNNgvUF8EiB9RE","tz1LN4xvgHB9dqiuc9fqco1ZEwDueXDgDw8T","tz1i55Li1zdF52PXSKGavRjmE6pCpSgmA5To","tz1V9wpVevfkEfNe2JnsBGuzQKJfpGzvs6vB","tz1dGRzqFXkur4d4HEr5q5ULSTpxtT8a8y3t","tz1QVCn1BYxpeWSVsu6ZvoSm1vMwFs3U49ZV","tz1Ltc6HqhjcMEXGnW8wSaqEJfi4kse77oHS","tz1LzvmQDVt7iTDevkAu6TZAd6LkhYaw5i8W","tz1cGaQgUitUa9TYfDdgAKLY5zyh5GUVHPzs","tz1YMFNXmBU81a3hkDAf5w6oADRPuieefX4i","tz1QMMwLkiHSRxXMP2LUuLfvw4HCq2c5JfMk","tz1UYdeecJh8w5EoraCHT1TgKA1bL4jGaDWJ","tz1Lor69x8DPG9AJ5xSthwVqQ8XtqLvnSofa","tz1NUHJF4PcYq1QbN3sW7RX76b81r96hKKoz","tz1YEhhVsJTQkxcgD24tQEjfhBKETkdBip9H","tz1SVDQFfuBiQV8qbhjw5YGxxVWFkPvEmodP","tz1hjZuttQSUcSbkg47i1izUMykXCcdqq1zx","tz1fF85RhHDzszowsTj9KGwcFwfDjfWqX7UM","tz1LsXSAtqk2UaAi5UqPgnxiMSx5aNarTiZt","tz1ZMLcTZuhe1FrCtbbTyiEp4r7PBbQZ52HQ","tz1dLBPNqqKTEqWEMqyzh64jdTVMoaZij9sm","tz1VvsF4iSFq7KVV4YFznaN7ZQYSNqcrQbyS","tz1ZbdR5gF7VrGT81o2Ny4c9UVfCc7gzB8En","tz1gC8bBi8dJKzEn97fvc1cp31qBctXUHfPv","tz1WsYZt814Mg9brcP2scWD9CcCywj8NnRBQ","tz1fv4smnQUbKXARxBKkUh5tQtADqFMKKQDJ","tz1i3UYmtRdoDwcHFSRV2e3Tk47fchbwUMwT","tz1XGjuyXeeCK3EuHYnSVMqqeJj41aNDzGDG","tz1SgfF5YhWA7Y1L5kEwv5cgRTbLm998fJC5","tz1SoikxCAviVXxs3pdc8UArM6unU1mffMHV","tz1NnvH3F8SfaB39KvD7Wyep1ytDCXjPoCJ4","tz1VCjP2P3sBtCLQXKkDG6xRyz1o6Sh4cngZ","tz1YqLMuu5gqPcWZjGAaCY4cHgKFW1bUYeKR","tz1Nev8pcv8qZDK2q2Ps4isYMtcJpXWaGcUa","tz1RrEVWkWxxQY5uLuBbVU2WR9W3EFtU8iKf","tz1dfc5ei2TSihvEpFnyTTb9nuQbDWvEEEvN","tz1iGL8vPK2DNvYf67FrqdsTDyXCtpBMbgkC","tz1YXFAkEgAbgy5Mrsr2DnPhbuq2WnBhnDCa","tz1SJLqfbEyGJ21wfhMJvxgu2EjQ346o22mZ","tz1NwPTbuzs8s6mrGEJisP9CaXC458jjzzPF","tz1VGdetQxEuDWGQYE5BDREBvpzQY9javJyp","tz1awa88jNvcsmbBHXbGLk6fcqEycYZecic8","tz1dJKVHdNapMkayYcmHFVYutVXXHx5mTKri","tz1NneEsPdJRrDgse4TzLpRqvbksphYBXBMY","tz1gtGWmzyGZTz7D1BheVa4ooocxjwamba4R","tz1VXvbmwHskMRHcbcCLi6bihPt5KNtMgVeX","tz1T5MBz5WXy4mCrdVHy19zrFDa3uu5vuKG3","tz1TH3yto3yViq21nG84zmcTmuvRfVgfMRGf","tz1eJ7HaiQu85aNYwXnYByr4voQJe65wWTzv","tz1Vz1XhyYidM2zjSZoN2H5Ku3a4ctHVvGm7","tz1MVTqQAvvurF7Abs4vBmPUoSFtqPuXacmv","tz1hFFvzPH5DxuHA4ivQvrtEX92FGntGMRBi","tz1fmLPPwGznV4R6vFyW8sswUZYwcYLJeYAp","tz1N6Xh2h2K4unzgXv1XitABtA3eB26wDAUD","tz1iGEPSzjQN8PzT5FrGUzhRQnx59hVzeXn8","KT1Prk9xaXSd7uz4NzWQfZ8bWyY4csVvox5w","tz1et74jh4CLmpfmvYCG5398iygUkdL962fy","KT1PHojJp48asdfyvT9kMmnsEzB6cdUGpwFf","tz1fNt7sqTh21sekaMdsPTQvjYsC1SduMagV","tz1idn8cD2bFaftnFzvJ2gik9wGuWKDGmhsP","tz1Qz93toMBURzKyjbECFe8YKAwARu8t1C3C","KT1FBMtK4T7K5UC3nuc8YRG3wnQK3oaCH9Uo","tz1Ly6UMQm3NCmDQ2udu6WvPCJGqauhR9FWk","tz1epXpov9hcoRUaGVJ222t67udd3vV6jn35","tz1ZVR7QMhJWCKEhp4SdynXNnikdxTs5XxQT","KT1KRdu1hDLtDRufZqNMU2z42uKrXhmsmzJd","tz1ivo3rkUgJQ1Nbe4VEhNetCREAvbGZwi25","tz1UBQvZkovRpZwML86qTpL59gedS1FeWpRw","tz1d9CzUNaFMmsnUZTihrz6wDA8ZP3GvAKbj","tz1MZHrRbLDMczK4xtJP1BrRdoYnoMq6c3P7","tz1Rw3VKh9yAWLWaQMhzWoRRQoEouGTCzgV7","tz1iABqHT2J4XKEnHp8JYJNiXEJtFg8r9RbC","tz1fxdeeUWT6YG5aSQcaJVU5sbeFCQYKCvPX","tz1dNA8PnEfRgV4ZqrX3i43Lh7Rxpx9bwy78","tz1MEEdk9w54LTcHz1oSkwAY9UUSepg8WrFG","tz1Zgo1nWvejNmjhzqEYPoRc57JhWrKhetAH","tz1gk9E28K1b6xQNw2wFLG9WERwzKDDwVNT9","tz1ftbRcC92jdKCTj91Qor9EkoJUcwqFFvH4","tz1hjorZSyLWMvupoBgWZsKbDFyca4B6wK36","tz1YNktyxUEzwpKq6QaWafka5CeKokJAEqi5","tz1KiuNcJNJ451967gXPwSDLvQmXryMvgTmL","tz1XDqZ4z2d5sRLkywYRwEMBQH5hHzaCaRre","tz1aQNn7eMC7kP1EyQetvocKS4TXmzEd5Gaw","tz1fnBJmAxoJbfAaMcCar3Aa8MFFH69dKYJv","tz1cZwxsasN1KorL8hYJPBy7gaBdNtsbjNvm","tz1b5qJrAgViKFPM5BdLeVasrxest7EWnf5z","tz1h87YTFnTCHKHTUEG2BxWq7DSRf861U8e6","tz1LPjWu1P11x1aizsD9wmqzey7ob66vvymg","tz1NBmAeLwsXxLcvAwJXM4nS199qkFcH4313","tz1cPL3YSMFiRC2yiMvSr7RLPVg5H5XhNvgW","tz1ZzGYssgyWGEZYVgCpMiYA1eBMWxRVrrqP","tz1ZgEQPeGYXeMLePL5sgR94RrRxwbsyK85z","tz1NcRjeevWE6E5B1pBsDexSB3cPJDTpQ9UL","tz1dBhoxSAU58V43Kvb7hG71iRxsfzmj7Z2y","tz1UwEDdQfpdcnYtfU7BRqXGPXbeaJmXk63c","tz1cpiGQS4rjtqnbndrbRnihtUjKH8aa1yHf","tz1eBdroBUqaUQ4h4xYXB26z67L8cj6ZyLsx","tz1Lk6U6erqH6EEuqMqk6u8gjqtJybZTirDs","tz1iAeHTDNZSwJjXaqbRyfyp96ych9j36tW1","tz1PDpbmvvBbFcEzctGfNt9mvvVTgTWxGGPZ","tz1RkXsWMgAtz85cD4iBckPC8xUFf3fPUFw2","tz1LcGrFcHLS9jgmWij4u7EWJDRrnU4xhVGL","tz1R752LZLPkJ1dhMs49zJqDcRZMic7nvL6g","tz1bpSiotWsQCz7jLjU4FV5K9PCZ79jinbs5","tz1bbsn8DMXJMEW7gVeuBbpMFBf65dq3VTtv","tz1V7aymCngroTZBxraVxp5kRtLh8qFRLcMN","tz1WxVo86ucoAE5RwCUe3tHTVV7r2GwRRvMN","tz1VXY3dXhE1s5huXnyFT7vfXgNroR5hTdjr","tz1LrYXWJ8Z3eKLSAYfCUaoZjpaqNrTqEd8w","tz1ZdYg6spcG9yk4ZXHHLcgNL2p8Y5wyhWYp","tz1PSqayN9mB1Wxk9SMjcGixX5PX9zRvtLZ8","tz1Pnke8YsfcDZfcqpZwpyFxLFCzEnSG9ews","tz1Qcgog1zYs6evgGP6aNEpGvDnCa7rAPvx5","tz1R5S8M9FAHs3eYjKY9ci3RD6iBgV8QCiLM","tz1iwGHsJu1Mq3eGGj2dmp5xj7N9kqxvuJzy","tz1TiEvTkhsuF5drB6Q9gDAQ3ejjp9GkMjdw","tz1LQPiugXCFuDit9232iqWGfj41PQGaCKvV","tz1TkAAz3CXdKiN4T8jAqxfWCBddQ39Vcewf","tz1ViczpurHDugWPgYzh5sE7Y7CDUB6qxseX","tz1NMf4uWqQNaVLFLjztKMpYphGdGSPu89pu","tz1ViNQrnj5aPjhZ9EQ1UuFcH6UUALqo3EUU","tz1Zqneq8GbnQ1G3g1Jnh9Vv4qGMnzLXbt3s","tz1dHH1xpCwZXE66WWK4SKDPLzF1JHX5KC96","tz1aXL6EouwJR3yMDK9jgD7zL5tpM12Vx3RY","tz1gtaaw2gzQjJmx8R17BRpYdkR9haE7i811","tz1aj98BzdTbicVFrqSYeAFjRwHGmRAwo2J6","tz1TS2ByHGPAgDb2AYv3bQWakG1tiH7uPwQb","tz1Q1t1xazVvEgN1dmxPCDXt8hqK9BY6qF5T","tz1fYzKUnmF873zvfcyUaX6yvRHbNTqakkSw","tz1g81md3cSqEtozkZggJnvRUNbMCbFHETqL","tz1bENLm1iQRnPsybc6HvrfR3W2nvuGErdFK","tz1TktVVrHESq3mdw6hpohXQFjbpGkdERsKT","tz1YSQ3PA5t3drYuAXYX5VE2mRcK143vjkKJ","tz1VFsJNozUp4mmtpv98bS2Q3B72qXWagDsq","tz1W47pyCkjpiWRAHmR9rHTmM5a1Yf9dtzkB","tz1Td2RL3zTSRZFac1SaXVxcXeAXHzTATsAU","KT1Tvqr6CTN3Lj2usqGPNG5Uog8JdgnDnhps","KT1CStwHYoGYzXENQamy2nc251enF5wk7Yjy","tz1UZuJ7Ae3m3rhsBjig955Fcy8vyfPYTDEr","tz1Qs9UZiWESjBJAA1SkqDm4eMDm78wo1QpN","tz1ZeovPMP8hy3PaJDg7AC8HP3rjNKpfRFes","tz1dkzioZTg4E3yVShiX1hdpAkE84wYhzRL8","KT1QhJRX8884Ccb9EKpNNFsbB27P6sRoqo4t","tz1Ww975VPEgcZdiTQGahABVkMf8yrcZb9A3","tz1RBv1smMW4xtTWG53fkzRZJGPmMotNJTEE","tz1cQD5tsef53FPzMmN5kLoLjvLD7VAGGQU5","tz1SUwahJKb5V9dxwk8N8quQWc5bQ1Zm6cva","tz1ciLo5K3g1pHPJKjEQp4WNvu6e9bxDtmwT","tz1ZTv3NVL4ry3qHZdmo7Y4rLjciHRcmptbA","tz1Z8TYYJsQgCqvvMtDo9Z56CzAtdVEi88NA","tz1hqbwdkxsh2MNaqoPVNycWA6cu1EKonKy8","tz1M4QhH1WQqrQWtsnDvyAqtfm3S7UcFAb78","tz1hxJteiSNWfmj12WdmHaPsdGtbZxZn1W9H","tz1cEnJ8Cu9AJcrfg9tajTmBEyTXPJM4teKP","tz1eSjS3Q2Rc36o2hHMRNX5pErtfGQRH9spH","tz1W7XN1Si3eGg4b6a7opsZ8EKjdiYVvmtfR","tz1gwyEjft79QrS5RKgLM3WozabfFeXn5kSC","tz1avdpHLEVbCKJPbFRD8pqySrZjPT64meHC","tz1NjziRqzmncVzU3CHXyo5BSVsn5CwXrUxS","tz1diyBGHXh6QR88Ps8guLmv8yCyyYTSoYjK","tz1RNVWP9MqtDSukfN9xZjNibKUMyq9ih2m1","tz1N1wThWmdxubf8y18ySS4KG69tR7icTHLn","tz1P96NympEyX7h4K5az2H8qr5vi7HyYGd7T","tz1Y7Ft4jEFvKE3dAHMUSwz9W3gXAWvN2ADR","tz1ND1DoSpPTtyooQQLxfNq7w8FR9dw9ZzuR","tz1SuBRZzrE98AeHRMy25zbNxwQfT5Wv1Cpp","tz1Q8HLHCFUFQVn38UeiSCNJUQsZxF2d6vtp","tz1TJrVZoozuTqzdeMakTnJQEogvm4q2531m","tz1TnfvKsMQajLzijg2EoKpE5yBGmXDiRQ1K","tz1gzg3UU6UMjVMGrcuetgnQ6btdVUGxYfyP","tz1KwcHHYUT7kMKeY6zXwUAq9Kuj3ryeX1iy","tz1WXuFmAiWqreKWY465FEps1Ei2XrAyHGGt","tz1TZafuJ3eWM3d3mckARNaP2oxBNyjLQVG6","tz1N7mPBeSrRsAgcukmRj2Twp6fvNshT1Uyc","tz1gFFSNHfQeNED9wYqThHMJZm5CNe6sFEUE","tz1L5xtPTd4XceH85n9W8vB3TjK45XGt63hC","tz1h6rqcMhAoEG2cMhiPjdJoemaHenY9mH7L","tz1bK9XE8khrUn7VxmEuNzF6FidGqpjTTXDs","tz1NUZw2MUG2AmSrtwTF3qdAUwgqBfnAGyu2","tz1ichwjUoGrUSawDKP6wMVLghJNX196aEBi","tz1UEEsxKrP1FH3RtUFt2esg7UdFQ74VeasS","tz1aNF6AiXu5uG6LENhYvJMwqYJc1bKTRuKr","KT1AG7uQwt3VX6JZah9KbD8n4sYSyaTUNqB3","tz1byac5DY5hA7dJ3uPvWvYAsWcAcdAGy953","tz1abWuJnBvT9o5TWzkEA2u3BbQ2mqFNoX3e","tz1Qin5ErcHtxtZV1njJ3cmzjw6GghWsEGGc"],"delegated_balance":"143547306933","deactivated":false,"grace_period":251}` - func createMockedAPI() http.Handler { r := http.NewServeMux() diff --git a/platform/tezos/transaction_test.go b/platform/tezos/transaction_test.go index aa98ce7f2..43a4b4017 100644 --- a/platform/tezos/transaction_test.go +++ b/platform/tezos/transaction_test.go @@ -1,9 +1,10 @@ package tezos import ( + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "testing" ) var ( diff --git a/platform/theta/mocks/tfuel_transfer.json b/platform/theta/mocks/tfuel_transfer.json new file mode 100644 index 000000000..ac9e15fb6 --- /dev/null +++ b/platform/theta/mocks/tfuel_transfer.json @@ -0,0 +1,33 @@ +{ + "hash": "0x558cb5ec877119c2c84a677277efb5b3059adb830c6e74971b3dbe93221b7132", + "type": 2, + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "0", + "tfuelwei": "44326000000000000" + }, + "sequence": "44" + } + ], + "outputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "0", + "tfuelwei": "44324000000000000" + } + } + ] + }, + "number": 7785266, + "block_height": "700327", + "timestamp": "1557136821", + "status": "finalized" +} diff --git a/platform/theta/mocks/theta_transfer.json b/platform/theta/mocks/theta_transfer.json new file mode 100644 index 000000000..cf4b05c98 --- /dev/null +++ b/platform/theta/mocks/theta_transfer.json @@ -0,0 +1,32 @@ +{ + "hash": "0x413d8423fd1e6df99fc57f425dfd58c791c877657b364c62c15905ade5114a70", + "data": { + "fee": { + "thetawei": "0", + "tfuelwei": "2000000000000" + }, + "inputs": [ + { + "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + "coins": { + "thetawei": "4000000000000000000", + "tfuelwei": "2000000000000" + }, + "sequence": "43" + } + ], + "outputs": [ + { + "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + "coins": { + "thetawei": "4000000000000000000", + "tfuelwei": "0" + } + } + ] + }, + "number": 7785228, + "block_height": "700321", + "timestamp": "1557136781", + "status": "finalized" +} diff --git a/platform/theta/transaction_test.go b/platform/theta/transaction_test.go index e3f521fa5..f6fb7ba22 100644 --- a/platform/theta/transaction_test.go +++ b/platform/theta/transaction_test.go @@ -1,124 +1,61 @@ package theta import ( - "bytes" "encoding/json" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" + "github.com/trustwallet/golibs/mock" ) -var thetaTransfer = `{ - "hash": "0x413d8423fd1e6df99fc57f425dfd58c791c877657b364c62c15905ade5114a70", - "data": { - "fee": { - "thetawei": "0", - "tfuelwei": "2000000000000" - }, - "inputs": [ - { - "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - "coins": { - "thetawei": "4000000000000000000", - "tfuelwei": "2000000000000" - }, - "sequence": "43" - } - ], - "outputs": [ - { - "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", - "coins": { - "thetawei": "4000000000000000000", - "tfuelwei": "0" - } - } - ] - }, - "number": 7785228, - "block_height": "700321", - "timestamp": "1557136781", - "status": "finalized" -}` +var ( + thetaTransfer, _ = mock.JsonFromFilePathToString("mocks/" + "theta_transfer.json") + tFuelTransfer, _ = mock.JsonFromFilePathToString("mocks/" + "tfuel_transfer.json") -var tFuelTransfer = ` -{ - "hash": "0x558cb5ec877119c2c84a677277efb5b3059adb830c6e74971b3dbe93221b7132", - "type": 2, - "data": { - "fee": { - "thetawei": "0", - "tfuelwei": "2000000000000" + expectedTransferTrx = blockatlas.Tx{ + ID: "0x413d8423fd1e6df99fc57f425dfd58c791c877657b364c62c15905ade5114a70", + Coin: coin.THETA, + From: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + To: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + Fee: "2000000000000", + Date: 1557136781, + Type: "transfer", + Status: blockatlas.StatusCompleted, + Block: 700321, + Sequence: 43, + Direction: blockatlas.DirectionOutgoing, + Meta: blockatlas.Transfer{ + Value: "4000000000000000000", + Symbol: "THETA", + Decimals: 18, }, - "inputs": [ - { - "address": "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", - "coins": { - "thetawei": "0", - "tfuelwei": "44326000000000000" - }, - "sequence": "44" - } - ], - "outputs": [ - { - "address": "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - "coins": { - "thetawei": "0", - "tfuelwei": "44324000000000000" - } - } - ] - }, - "number": 7785266, - "block_height": "700327", - "timestamp": "1557136821", - "status": "finalized" -} -` - -var expectedTransferTrx = blockatlas.Tx{ - ID: "0x413d8423fd1e6df99fc57f425dfd58c791c877657b364c62c15905ade5114a70", - Coin: coin.THETA, - From: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - To: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", - Fee: "2000000000000", - Date: 1557136781, - Type: "transfer", - Status: blockatlas.StatusCompleted, - Block: 700321, - Sequence: 43, - Direction: blockatlas.DirectionOutgoing, - Meta: blockatlas.Transfer{ - Value: "4000000000000000000", - Symbol: "THETA", - Decimals: 18, - }, -} + } -var expectedTfuelTransfer = blockatlas.Tx{ - ID: "0x558cb5ec877119c2c84a677277efb5b3059adb830c6e74971b3dbe93221b7132", - Coin: coin.THETA, - From: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", - To: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - Fee: "2000000000000", - Date: 1557136821, - Type: blockatlas.TxNativeTokenTransfer, - Status: blockatlas.StatusCompleted, - Sequence: 44, - Block: 700327, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.NativeTokenTransfer{ - Name: "Theta Fuel", - Symbol: "TFUEL", - TokenID: "tfuel", - Decimals: 18, - Value: "44324000000000000", - From: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", - To: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", - }, -} + expectedTfuelTransfer = blockatlas.Tx{ + ID: "0x558cb5ec877119c2c84a677277efb5b3059adb830c6e74971b3dbe93221b7132", + Coin: coin.THETA, + From: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + To: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + Fee: "2000000000000", + Date: 1557136821, + Type: blockatlas.TxNativeTokenTransfer, + Status: blockatlas.StatusCompleted, + Sequence: 44, + Block: 700327, + Direction: blockatlas.DirectionIncoming, + Meta: blockatlas.NativeTokenTransfer{ + Name: "Theta Fuel", + Symbol: "TFUEL", + TokenID: "tfuel", + Decimals: 18, + Value: "44324000000000000", + From: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", + To: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", + }, + } +) func TestNormalize(t *testing.T) { tests := []struct { @@ -156,11 +93,7 @@ func TestNormalize(t *testing.T) { t.Fatal(err) } - if !bytes.Equal(actual, expected) { - println(string(actual)) - println(string(expected)) - t.Error("Transactions not equal") - } + assert.JSONEq(t, string(actual), string(expected)) } } diff --git a/platform/tron/mocks/delegation.json b/platform/tron/mocks/delegation.json new file mode 100644 index 000000000..9c02c402a --- /dev/null +++ b/platform/tron/mocks/delegation.json @@ -0,0 +1,23 @@ +{ + "address": "419241920da7d6bb487a33a6df3838e3d208f0b251", + "frozen": [ + { + "expire_time": 10437262001000, + "frozen_balance": "35000000" + } + ], + "votes": [ + { + "vote_address": "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp", + "vote_count": 21 + }, + { + "vote_address": "TPMGfspxLQGom8sKutrbHcDKtHjRHFbGKw", + "vote_count": 5 + }, + { + "vote_address": "TPMGfspxLQGom8sKutrbHcDKtHjRHFbGKw", + "vote_count": 5 + } + ] +} diff --git a/platform/tron/mocks/delegation_2.json b/platform/tron/mocks/delegation_2.json new file mode 100644 index 000000000..ade0c411b --- /dev/null +++ b/platform/tron/mocks/delegation_2.json @@ -0,0 +1,15 @@ +{ + "address": "419241920da7d6bb487a33a6df3838e3d208f0b251", + "frozen": [ + { + "expire_time": 1569465251000, + "frozen_balance": "5000000" + } + ], + "votes": [ + { + "vote_address": "TPMGfspxLQGom8sKutrbHcDKtHjRHFbGKw", + "vote_count": 5 + } + ] +} diff --git a/platform/tron/mocks/token_transfer.json b/platform/tron/mocks/token_transfer.json new file mode 100644 index 000000000..82f3ea4aa --- /dev/null +++ b/platform/tron/mocks/token_transfer.json @@ -0,0 +1,19 @@ +{ + "block_timestamp": 1564797900000, + "raw_data": { + "contract": [ + { + "parameter": { + "value": { + "amount": 2776267, + "asset_name": "1002000", + "owner_address": "4182dd6b9966724ae2fdc79b416c7588da67ff1b35", + "to_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261" + } + }, + "type": "TransferAssetContract" + } + ] + }, + "txID": "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df" +} diff --git a/platform/tron/mocks/token_txs_response.json b/platform/tron/mocks/token_txs_response.json new file mode 100644 index 000000000..b0929ef01 --- /dev/null +++ b/platform/tron/mocks/token_txs_response.json @@ -0,0 +1,442 @@ +[ + { + "id": "fb078403adfee637608c3906d9d21dd158611aba149b9993f43d0f292ce543a0", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A", + "fee": "0", + "date": 1592757117, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "500000000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A" + } + }, + { + "id": "c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd", + "fee": "0", + "date": 1592757066, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "50000000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd" + } + }, + { + "id": "c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd", + "fee": "0", + "date": 1592757066, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "50000000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd" + } + }, + { + "id": "0b52a4ef9fb8c13fbfae2b8c3506333ec1d718f307062a15f170562818a01d0a", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV", + "fee": "0", + "date": 1592756784, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "3988000000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV" + } + }, + { + "id": "19d2ec6174bf64beb1061475f6429cba03b64944a763686cc3551447d0e8d9d5", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am", + "fee": "0", + "date": 1592756763, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "640990000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am" + } + }, + { + "id": "efb7d44305759cfb189c9fd22720609a2ddeb7fbd7c8afe1dd8851342471da8d", + "coin": 195, + "from": "TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "fee": "0", + "date": 1592756631, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "1062000000", + "from": "TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D" + } + }, + { + "id": "48bd90dc3f12086178e65b9389caa8b3c74683937b86d4d61cdec77f0095994a", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A", + "fee": "0", + "date": 1592756610, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "2000000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A" + } + }, + { + "id": "afd5ae7e2462c9cc899c7f730b90fd2a5e4c1315e836c92468b504ed85f0b798", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R", + "fee": "0", + "date": 1592756589, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "1000000000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R" + } + }, + { + "id": "3d613031f4b2a0e19deeea030d1d18599b6d9799d2dd530005ead9712c6d219d", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq", + "fee": "0", + "date": 1592756583, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "21200000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq" + } + }, + { + "id": "cbe359c2574efbdc8fc6a892ffc54812837295067c9816d41734126c82d0c141", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5", + "fee": "0", + "date": 1592756583, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "125000000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5" + } + }, + { + "id": "c87248b02a4caaa6f443c1b8c4d4588c8dd281a4687b73e6afecfba6741b50d8", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC", + "fee": "0", + "date": 1592756583, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "5277600000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC" + } + }, + { + "id": "8584f1b6a70ead8232fed19bd653ba13e4c2a8befd070f4a9a06eca3a2e3e548", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W", + "fee": "0", + "date": 1592756583, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "485342000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W" + } + }, + { + "id": "2b28b69e6747db68647acc3a62c45da5355b97acd8d2c260ee752aa9bd63a624", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr", + "fee": "0", + "date": 1592756583, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "1000000000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr" + } + }, + { + "id": "1da6576dec0bd303f56cbfb5712f782e0a56a8713cb661f8afd2f2533e5c6209", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x", + "fee": "0", + "date": 1592756583, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "2000000000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x" + } + }, + { + "id": "f9c86cce1873cb816d6cd8718e76df8839172add293bbc8d11a5f98c80f9e322", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK", + "fee": "0", + "date": 1592756583, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "24216600000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK" + } + }, + { + "id": "75eb35734857daa79c38ef923a7e7eb2e3dfb23d2722762fd2b180651021643f", + "coin": 195, + "from": "TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "fee": "0", + "date": 1592756541, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "8241997837", + "from": "TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D" + } + }, + { + "id": "adee73dadce006ff848ff30d8c5c41f033be2e5e1a8b875f6dbbaab524177d08", + "coin": 195, + "from": "TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "fee": "0", + "date": 1592756220, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "18000000000", + "from": "TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D" + } + }, + { + "id": "3655a1156c9adcb876c6c9c9e0f5f1f39704ac4c7296fea05fedf5ca8f6b1a19", + "coin": 195, + "from": "TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "fee": "0", + "date": 1592755962, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "863399098", + "from": "TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D" + } + }, + { + "id": "03574741eb0016050a19f181e4acc4b20b70f41e11e63140c9556c31eae09fba", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ", + "fee": "0", + "date": 1592755740, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "20000000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ" + } + }, + { + "id": "f3aa00595996e31dbe9528a3cb21bff987f333bf1f675420ba4fa2ad43c8205f", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug", + "fee": "0", + "date": 1592755722, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "token_transfer", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "decimals": 6, + "value": "21161340000", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug" + } + } +] diff --git a/platform/tron/mocks/tokens/accounts_response.json b/platform/tron/mocks/tokens/accounts_response.json new file mode 100644 index 000000000..fa3ddfdd6 --- /dev/null +++ b/platform/tron/mocks/tokens/accounts_response.json @@ -0,0 +1,87 @@ +{ + "success": true, + "meta": { "at": 1592753781505, "page_size": 1 }, + "data": [ + { + "account_resource": { "latest_consume_time_for_energy": 1592753721000 }, + "address": "4179309abcff2cf531070ca9222a1f72c4a5136874", + "asset": [ + { "key": "IPFS", "value": 1273 }, + { "key": "TRXTestCoin", "value": 113 }, + { "key": "Skypeople", "value": 145 }, + { "key": "binance", "value": 416 }, + { "key": "BitTorrent", "value": 596 }, + { "key": "ofoBike", "value": 242 }, + { "key": "FomoThreeD", "value": 62 }, + { "key": "Durex", "value": 53 }, + { "key": "Pornhub", "value": 56 }, + { "key": "NBACoin", "value": 599 }, + { "key": "HuobiToken", "value": 628 }, + { "key": "MacCoin", "value": 234 }, + { "key": "Messenger", "value": 113 }, + { "key": "Bithumb", "value": 206 }, + { "key": "James", "value": 61 }, + { "key": "RingCoin", "value": 25 }, + { "key": "DACC", "value": 7 }, + { "key": "OtonamiS", "value": 1 }, + { "key": "intrxChain", "value": 1 }, + { "key": "TRONEX", "value": 30 }, + { "key": "Petro", "value": 1 }, + { "key": "KrMaToken", "value": 200 }, + { "key": "KsumNole", "value": 7 }, + { "key": "eFilingPlus", "value": 1000 }, + { "key": "Tarquin", "value": 10 }, + { "key": "KiloReX", "value": 10 }, + { "key": "BESTCOIN", "value": 2 }, + { "key": "Makememillionaire", "value": 100 }, + { "key": "MedicCoin", "value": 1 }, + { "key": "DMT", "value": 1 }, + { "key": "MedIBlock", "value": 100 }, + { "key": "ethereum", "value": 1000 }, + { "key": "COLORBIKE", "value": 1300000 }, + { "key": "WatsonAI", "value": 11 }, + { "key": "Litcoin", "value": 10 }, + { "key": "TronMatrixAI", "value": 17 }, + { "key": "GoodKarma", "value": 100 }, + { "key": "CryptoBankCoin", "value": 12 }, + { "key": "EXODUS", "value": 12 }, + { "key": "TRONO", "value": 100 }, + { "key": "NMIToken", "value": 100 }, + { "key": "Ton", "value": 50 }, + { "key": "Twx", "value": 5 }, + { "key": "TronLottery", "value": 10 }, + { "key": "TronTokensGuardian", "value": 3 }, + { "key": "TRONONE", "value": 13 }, + { "key": "ELVIS", "value": 200 }, + { "key": "URUNIT", "value": 12 }, + { "key": "CRYPTYK", "value": 15 }, + { "key": "TronRoyal", "value": 10 } + ], + "assetV2": [ + { "key": "1000542", "value": 62 }, + { "key": "1000567", "value": 0 } + ], + "balance": 346991703615806, + "create_time": 1535532969000, + "free_asset_net_usageV2": [ + { "key": "1000542", "value": 0 }, + { "key": "1000567", "value": 0 } + ], + "free_net_usage": 4828, + "latest_consume_free_time": 1592751174000, + "latest_opration_time": 1592753721000, + "trc20": [ + { "TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9": "955973733483987848990056" }, + { "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7": "191543058623486" }, + { "TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK": "100000000000000" }, + { "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t": "6849738905400" }, + { "TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e": "5000000000" }, + { "TJSF4iVkzkRkYwEVNkqJkeGDaZpnFbGy9x": "500000000" }, + { "TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm": "20000000" }, + { "TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF": "175798" }, + { "TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG": "20000" }, + { "TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak": "1" } + ] + } + ] +} diff --git a/platform/tron/mocks/tokens/accounts_txs_response.json b/platform/tron/mocks/tokens/accounts_txs_response.json new file mode 100644 index 000000000..ce7f0870c --- /dev/null +++ b/platform/tron/mocks/tokens/accounts_txs_response.json @@ -0,0 +1,931 @@ +{ + "success": true, + "meta": { + "at": 1592755486554, + "page_size": 25, + "fingerprint": "4CwRecxbH99eRRkU2FFkGRCvoQGwphNyRcTTiM1GfUrkoQ1fG9Kcc8ADZo7pSCYXja28JWKUACy2Xt6UG1Fa5tSZh5dqpUEuTi1W", + "links": { + "next": "https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R/transactions?limit=25&order_by=block_timestamp%2Cdesc&token_id=&fingerprint=4CwRecxbH99eRRkU2FFkGRCvoQGwphNyRcTTiM1GfUrkoQ1fG9Kcc8ADZo7pSCYXja28JWKUACy2Xt6UG1Fa5tSZh5dqpUEuTi1W" + } + }, + "data": [ + { + "blockNumber": 20829763, + "block_timestamp": 1592755239000, + "energy_fee": 296310, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb0000000000000000000000413b334848f75cf8c27ec975bcc7cc7e54f140b3c000000000000000000000000000000000000000000000000000000000cd0e33a0", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758890000, + "fee_limit": 1000000000, + "ref_block_bytes": "d62e", + "ref_block_hash": "bbf7d06ee7004d5a", + "timestamp": 1592755233594 + }, + "raw_data_hex": "0a02d62e2208bbf7d06ee7004d5a4090dccfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413b334848f75cf8c27ec975bcc7cc7e54f140b3c000000000000000000000000000000000000000000000000000000000cd0e33a070bac6f0bcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 299770 }], + "signature": [ + "c9a405be8b12f92747cc0f0d979606807a03edcefd154bcf517ce26f8bf681400d6cdacda11c98e7ae61d51905f7113658a786d6022b97e025f5a7e99b53845d01" + ], + "txID": "18f5908a7e208e16bfb892a5b06df75675d3142d03a0d99d270ac46143b78d06" + }, + { + "blockNumber": 20829760, + "block_timestamp": 1592755230000, + "energy_fee": 146310, + "energy_usage": 0, + "energy_usage_total": 14631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb00000000000000000000004158a82464024027b8e81bd1997cc7ba8f26a01314000000000000000000000000000000000000000000000000000000001dce7a58", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758881000, + "fee_limit": 1000000000, + "ref_block_bytes": "d62b", + "ref_block_hash": "38ebe631e633b827", + "timestamp": 1592755223352 + }, + "raw_data_hex": "0a02d62b220838ebe631e633b82740e895cfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb00000000000000000000004158a82464024027b8e81bd1997cc7ba8f26a01314000000000000000000000000000000000000000000000000000000001dce7a5870b8f6efbcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 149770 }], + "signature": [ + "39ee8b2e7ab589538f3a976644399ba60667ede4d9611229298d52f5aeb01a6624e2346703d8a19edc9f457b89a0dbb800ae87d049ad3a7d72353fde77635f1a00" + ], + "txID": "2a9eda92b9a2a0e56d29000ad24daae7d577c5db44d2b737f6a35584cd81b5e0" + }, + { + "blockNumber": 20829760, + "block_timestamp": 1592755230000, + "energy_fee": 119110, + "energy_usage": 0, + "energy_usage_total": 14631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac84000000000000000000000000000000000000000000000000000000037e11d600", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758881000, + "fee_limit": 1000000000, + "ref_block_bytes": "d62b", + "ref_block_hash": "38ebe631e633b827", + "timestamp": 1592755223053 + }, + "raw_data_hex": "0a02d62b220838ebe631e633b82740e895cfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac84000000000000000000000000000000000000000000000000000000037e11d600708df4efbcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 122570 }], + "signature": [ + "710a4b8543a9f605acc809ebe5b8a3a3b4681ebf2123fcdda39187bde86c9bc839cf6d882d9d15052b94ed6bba6474f9fdf09e73afefe40f6bad909029cadd2500" + ], + "txID": "c838b8a683d39c6f1a8a173e6fffc5cc9122acc690f5e35fa7c1935cc5eae540" + }, + { + "blockNumber": 20829742, + "block_timestamp": 1592755176000, + "energy_fee": 296310, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb000000000000000000000041c80ab7aac02a3d4b3d89ee781cddce55286bcf2d000000000000000000000000000000000000000000000000000000000bebc200", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758830000, + "fee_limit": 1000000000, + "ref_block_bytes": "d61a", + "ref_block_hash": "b1015d64daa873a3", + "timestamp": 1592755172703 + }, + "raw_data_hex": "0a02d61a2208b1015d64daa873a340b087ccbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041c80ab7aac02a3d4b3d89ee781cddce55286bcf2d000000000000000000000000000000000000000000000000000000000bebc20070dfeaecbcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 299770 }], + "signature": [ + "a7583c4e402eff463b083de5cfcbaadc46ed8601e2346f20d01eb0ec7a6824d869be27371f8c0e5a38a708df724be60a818b9647757bdde73ed743ff9324115c01" + ], + "txID": "ad631a0e55bd2bb64747bf388dc92084c32506843c19a0a2b69234b4d4e56a6b" + }, + { + "blockNumber": 20829732, + "block_timestamp": 1592755146000, + "energy_fee": 231500, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb0000000000000000000000410d4fd52433f30edd0b512f59fa021527bbd7de610000000000000000000000000000000000000000000000000000000001c9c380", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758800000, + "fee_limit": 1000000000, + "ref_block_bytes": "d610", + "ref_block_hash": "2a14293035535e85", + "timestamp": 1592755142312 + }, + "raw_data_hex": "0a02d61022082a14293035535e8540809dcabead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000410d4fd52433f30edd0b512f59fa021527bbd7de610000000000000000000000000000000000000000000000000000000001c9c38070a8fdeabcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 234960 }], + "signature": [ + "3095c2130ee5d4da72246a17098b587c25108e1c1884f9128911e079997dd25c45e0b0acfc99e3ee4367c4670e2117dd24884c32ae0ea15ec9f9368910e4c42801" + ], + "txID": "f1920eefa4de8370bc349fbd6ca73e24d9000d9d8fe5c71260a2902d3b49b02a" + }, + { + "blockNumber": 20829718, + "block_timestamp": 1592755104000, + "energy_fee": 166720, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb00000000000000000000004135c4d4a5544d25a2f25a7cda73d57c45a36578bc0000000000000000000000000000000000000000000000000000000010089d40", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758761000, + "fee_limit": 1000000000, + "ref_block_bytes": "d603", + "ref_block_hash": "f84579e34d118430", + "timestamp": 1592755101713 + }, + "raw_data_hex": "0a02d6032208f84579e34d11843040a8ecc7bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb00000000000000000000004135c4d4a5544d25a2f25a7cda73d57c45a36578bc0000000000000000000000000000000000000000000000000000000010089d407091c0e8bcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 170180 }], + "signature": [ + "816b2747c6c1f6be139d233118b4b1e3c3942d62f56d1b0c8a496851ea233c5c1b6e0e0a13e22c3a4c1bd106eb6c0e987d5c84f9fcc29ee7b86bd4d1874ade9601" + ], + "txID": "cec1061166e4924123356b8066872b641956691d1b1f11a12f293c54e7178362" + }, + { + "blockNumber": 20829716, + "block_timestamp": 1592755098000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 2690, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferContract", + "value": { + "amount": 13195916000, + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874", + "to_address": "41d9378a9849912a41ec1f0e4677c074edf0516241" + } + }, + "type": "TransferContract" + } + ], + "expiration": 1592758749000, + "fee_limit": 0, + "ref_block_bytes": "d5ff", + "ref_block_hash": "c753125289c79c7c", + "timestamp": 1592755089996 + }, + "raw_data_hex": "0a02d5ff2208c753125289c79c7c40c88ec7bead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a154179309abcff2cf531070ca9222a1f72c4a5136874121541d9378a9849912a41ec1f0e4677c074edf051624118e0e5a6943170cce4e7bcad2e", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 2690 }], + "signature": [ + "bae63e4214b0ab611079beabca020c82fbcada902f1f0c13106e7c4ba463efb25610d13b00b28cd19b54f648b88a4b05a08583b44b4f4179c2c605b42b22ad4b00" + ], + "txID": "3fca53c08ccb48bb625439a58998713d8ecc3dc1348cc3cfab912e0815b62b1a" + }, + { + "blockNumber": 20829708, + "block_timestamp": 1592755074000, + "energy_fee": 146310, + "energy_usage": 0, + "energy_usage_total": 14631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005fc2678", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758719000, + "fee_limit": 1000000000, + "ref_block_bytes": "d5f5", + "ref_block_hash": "84843b5d1de30802", + "timestamp": 1592755061404 + }, + "raw_data_hex": "0a02d5f5220884843b5d1de308024098a4c5bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005fc2678709c85e6bcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 149770 }], + "signature": [ + "6dd6709cee109df62c3a7f196f45d3efa16c25738c1c4ea371cce18443016c8911a2d65fd4f2d7b4932aed34634169adc981db081522b094e63d9528882b3de801" + ], + "txID": "8e886732999efe30e0d7c93eee40c41f058f33c82194141317768810a5a84b82" + }, + { + "blockNumber": 20829681, + "block_timestamp": 1592754993000, + "energy_fee": 231500, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005e5eb10", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758638000, + "fee_limit": 1000000000, + "ref_block_bytes": "d5da", + "ref_block_hash": "3234615516f16ee9", + "timestamp": 1592754980996 + }, + "raw_data_hex": "0a02d5da22083234615516f16ee940b0abc0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005e5eb10708491e1bcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 234960 }], + "signature": [ + "896243c9d9c8ba595deafb81b7c4fc283271e0f46aa7031f270d91a383ce997a09f4a3aa6fb0478a7dac9b7df295dcf232f8bf4941583848f45bd8e258f9482e01" + ], + "txID": "8b7c9f9f29cbf9ced22761f918d19471b3bb638438e6cc23e8104fed7dda1ef3" + }, + { + "blockNumber": 20829627, + "block_timestamp": 1592754831000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 2850, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferAssetContract", + "value": { + "amount": 7639170000000, + "asset_name": "1002000", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874", + "to_address": "410a60e164aa897ef76779164dff6e36161980c6fb" + } + }, + "type": "TransferAssetContract" + } + ], + "expiration": 1592758479000, + "fee_limit": 0, + "ref_block_bytes": "d5a5", + "ref_block_hash": "462e1cfdbe99a85b", + "timestamp": 1592754820511 + }, + "raw_data_hex": "0a02d5a52208462e1cfdbe99a85b4098d1b6bead2e5a79080212750a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123f0a073130303230303012154179309abcff2cf531070ca9222a1f72c4a51368741a15410a60e164aa897ef76779164dff6e36161980c6fb2080c98e90aade01709fabd7bcad2e", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 2850 }], + "signature": [ + "b49c878a8e85339fc4917e7f20625b38b941871c86572d2c01322ec26575c7024c34b498e464109a03f8e42df24cc0868910a0e7b1f7c174f5005a483a93dac600" + ], + "txID": "79010512f8e58574cbd066d1a1bd1c7f46f65e59e3b7733010047ff8350f15f1" + }, + { + "blockNumber": 20829617, + "block_timestamp": 1592754801000, + "energy_fee": 296310, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb0000000000000000000000412b764790f38a7373d56dfdf4f866fa027e28c8af0000000000000000000000000000000000000000000000000000000071006010", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758449000, + "fee_limit": 1000000000, + "ref_block_bytes": "d59b", + "ref_block_hash": "beab372f7f7d493b", + "timestamp": 1592754790236 + }, + "raw_data_hex": "0a02d59b2208beab372f7f7d493b40e8e6b4bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000412b764790f38a7373d56dfdf4f866fa027e28c8af000000000000000000000000000000000000000000000000000000007100601070dcbed5bcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 299770 }], + "signature": [ + "52b662780f176048c4fd9e8db15756d0ef397cb60a8be6ea3421993ec2c6e1636d9aaf8a596f9255c182284e1efbd5410e2a11d10b82b4e4fec5a43ffea357cc01" + ], + "txID": "809ec9beb99cf756bb02155199a35b766f3ec18dd6bea6b3d69dd38f6b51138f" + }, + { + "blockNumber": 20829617, + "block_timestamp": 1592754801000, + "energy_fee": 166700, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb000000000000000000000041d8692da59c130875e13587a82bc93b917c49526a0000000000000000000000000000000000000000000000000000000054c92b70", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758449000, + "fee_limit": 1000000000, + "ref_block_bytes": "d59b", + "ref_block_hash": "beab372f7f7d493b", + "timestamp": 1592754789857 + }, + "raw_data_hex": "0a02d59b2208beab372f7f7d493b40e8e6b4bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041d8692da59c130875e13587a82bc93b917c49526a0000000000000000000000000000000000000000000000000000000054c92b7070e1bbd5bcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 170160 }], + "signature": [ + "fe96d2be46a37f89531d10cdca823ec82c603a3bb9f858aa76db20468e8d9d6058de643460e11b50e0982fa6ab6b81439cee6c9286b5d6bb7c18206e2ab066fb01" + ], + "txID": "bc0c429e33d3c668e5e5a55831efb3aba7e917c52cd3892aeb252f1a7b2ddb41" + }, + { + "blockNumber": 20829596, + "block_timestamp": 1592754738000, + "energy_fee": 166700, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb000000000000000000000041ec853dc8fe0dab78d3234ba356ebae7984da322c00000000000000000000000000000000000000000000000000000004a817c800", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758386000, + "fee_limit": 1000000000, + "ref_block_bytes": "d586", + "ref_block_hash": "4007c65312ba945c", + "timestamp": 1592754729408 + }, + "raw_data_hex": "0a02d58622084007c65312ba945c40d0fab0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041ec853dc8fe0dab78d3234ba356ebae7984da322c00000000000000000000000000000000000000000000000000000004a817c80070c0e3d1bcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 170160 }], + "signature": [ + "93119466b23346e095d256537f2bf8c639dd157f896eaaff972f0be83663bca34a21df4e25fa61ba071588a58f98874a58705844a8cc36a321bf30e722028c8201" + ], + "txID": "3bcd581a833abb16529e1f5187615866ba72f2e61c590c993f5b461ba5073d45" + }, + { + "blockNumber": 20829592, + "block_timestamp": 1592754726000, + "energy_fee": 296310, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac8400000000000000000000000000000000000000000000000000000000001e8480", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758377000, + "fee_limit": 1000000000, + "ref_block_bytes": "d583", + "ref_block_hash": "0bc07e9ae4eb32b0", + "timestamp": 1592754719032 + }, + "raw_data_hex": "0a02d58322080bc07e9ae4eb32b040a8b4b0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac8400000000000000000000000000000000000000000000000000000000001e848070b892d1bcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 299770 }], + "signature": [ + "80fe656c430afb348327f279a2d454d277bf64564111e49118ed85f1021528920ba5be044956084f543a087a61aa14b595a4fc2cc6aff2ad2ac5d7533a6b122f01" + ], + "txID": "3baff897a2b39720727549216ea6f4bc580eed2f239967e158e9e7ea74146822" + }, + { + "blockNumber": 20829589, + "block_timestamp": 1592754717000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 2690, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferContract", + "value": { + "amount": 8737000000, + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874", + "to_address": "412886fdc89587dbe8a57d0b9589581bd084384d5f" + } + }, + "type": "TransferContract" + } + ], + "expiration": 1592758368000, + "fee_limit": 0, + "ref_block_bytes": "d580", + "ref_block_hash": "ebf8d3b3837d87a8", + "timestamp": 1592754708731 + }, + "raw_data_hex": "0a02d5802208ebf8d3b3837d87a84080eeafbead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a154179309abcff2cf531070ca9222a1f72c4a51368741215412886fdc89587dbe8a57d0b9589581bd084384d5f18c09490c62070fbc1d0bcad2e", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 2690 }], + "signature": [ + "b92bdde424aee97b4e7a63716056daa963afce89701bf6d8c8b1b6221f65afb94b8ff3865650aff83d590cad87359ae5f272ed732738093a0a9aa587cc3503aa01" + ], + "txID": "b38fb6328e1fa622b7762eed856778551845c33723491e36baf357f00cc48002" + }, + { + "blockNumber": 20829585, + "block_timestamp": 1592754705000, + "energy_fee": 43900, + "energy_usage": 0, + "energy_usage_total": 14631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb0000000000000000000000416128e41b6aa8c531b05999c2861f846459fb10e60000000000000000000000000000000000000000000000000000000005f5e100", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758356000, + "fee_limit": 1000000000, + "ref_block_bytes": "d57c", + "ref_block_hash": "c7c6e5795625dc5b", + "timestamp": 1592754698724 + }, + "raw_data_hex": "0a02d57c2208c7c6e5795625dc5b40a090afbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000416128e41b6aa8c531b05999c2861f846459fb10e60000000000000000000000000000000000000000000000000000000005f5e10070e4f3cfbcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 47360 }], + "signature": [ + "b90e38665957e47ba8f7731e3b8c943471cd6ef9a95efcd25ad880323f2e397b56927e943c7e605a1996900fe269db6edbc7d7ff094f23393c6546ef0927bae300" + ], + "txID": "d8d53a627fa9f885ad77dcc2f3d3a5eceece36d1ef0f54990dff900484550304" + }, + { + "blockNumber": 20829577, + "block_timestamp": 1592754681000, + "energy_fee": 296310, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb000000000000000000000041dd81641cca9a855b7a657153fdda9b3f469693660000000000000000000000000000000000000000000000000000000217a31ba0", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758335000, + "fee_limit": 1000000000, + "ref_block_bytes": "d575", + "ref_block_hash": "003bba00242a2488", + "timestamp": 1592754678392 + }, + "raw_data_hex": "0a02d5752208003bba00242a24884098ecadbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd81641cca9a855b7a657153fdda9b3f469693660000000000000000000000000000000000000000000000000000000217a31ba070f8d4cebcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 299770 }], + "signature": [ + "0abe6787b18631ae746b4a9c9669e3e878b88c3628a3656e3709b4036b14414525bdb9cdb3c97fce48c9d21f2afab9492a436861e2e85ec1f68bab078859eb1d01" + ], + "txID": "b419c05c877e0176619ec3659470c71822a7840a91a940169eaaf1abb9c38fea" + }, + { + "blockNumber": 20829564, + "block_timestamp": 1592754642000, + "energy_fee": 43900, + "energy_usage": 0, + "energy_usage_total": 14631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb000000000000000000000041a3af64559a63856c625b02e9def8a4dc0f63f38b0000000000000000000000000000000000000000000000000000000010c18918", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758287000, + "fee_limit": 1000000000, + "ref_block_bytes": "d565", + "ref_block_hash": "afd9deb62b6fa5e0", + "timestamp": 1592754628020 + }, + "raw_data_hex": "0a02d5652208afd9deb62b6fa5e04098f5aabead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041a3af64559a63856c625b02e9def8a4dc0f63f38b0000000000000000000000000000000000000000000000000000000010c1891870b4cbcbbcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 47360 }], + "signature": [ + "070c1a53f2fc6b12825b99c9179899e1effbbdf2fad17d273b64bc47f16ee53a0f56096d4ef6ce58aeee65083dcdef8f3c808d6889a990c23a8d45a84cd69bf101" + ], + "txID": "abb6c40f8f8afcc69fb5b549ffb17bd779fa6588dbbbd5e4ee8568839462b37a" + }, + { + "blockNumber": 20829535, + "block_timestamp": 1592754555000, + "energy_fee": 296310, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb0000000000000000000000410ae0647bbaa1aebafcc9a360d0e22a791a215c930000000000000000000000000000000000000000000000000000000011e1a300", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758206000, + "fee_limit": 1000000000, + "ref_block_bytes": "d54a", + "ref_block_hash": "d27814b2e9763d5d", + "timestamp": 1592754547598 + }, + "raw_data_hex": "0a02d54a2208d27814b2e9763d5d40b0fca5bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000410ae0647bbaa1aebafcc9a360d0e22a791a215c930000000000000000000000000000000000000000000000000000000011e1a300708ed7c6bcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 299770 }], + "signature": [ + "6a0f4d4d5021c46d522f45552b20218ea16c437e6e87130339c90752f63f7a805763699bad3b22fb3199efdce75f1929ac94482be8551107b051ae4b9ef532bb01" + ], + "txID": "7da3a7819e4de9311464963f829e3ceeff0a045bbd587030deba863a04d250db" + }, + { + "blockNumber": 20829504, + "block_timestamp": 1592754462000, + "energy_fee": 166700, + "energy_usage": 0, + "energy_usage_total": 29631, + "internal_transactions": [], + "net_fee": 3460, + "net_usage": 0, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TriggerSmartContract", + "value": { + "call_value": 0, + "contract_address": "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "data": "a9059cbb000000000000000000000041042b5bc43cf6aabae0533f4f671eb810615c32be0000000000000000000000000000000000000000000000000000000054c92b70", + "owner_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TriggerSmartContract" + } + ], + "expiration": 1592758116000, + "fee_limit": 1000000000, + "ref_block_bytes": "d52c", + "ref_block_hash": "9486bdd9554ef09e", + "timestamp": 1592754457197 + }, + "raw_data_hex": "0a02d52c22089486bdd9554ef09e40a0bda0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041042b5bc43cf6aabae0533f4f671eb810615c32be0000000000000000000000000000000000000000000000000000000054c92b7070ed94c1bcad2e90018094ebdc03", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 170160 }], + "signature": [ + "2bfe810fa90d3aee965ff990fd68490ce9c8421844c1e792a57faeb556e5c9b004499016ace19afdb49ba65531c2d829890b4c6a14a7e58c6b71bfdacc7709e201" + ], + "txID": "4d5e74b87f782060e0657a48898626a51a1bf2dcccfc2083955fa4f43e4516b0" + }, + { + "blockNumber": 20829499, + "block_timestamp": 1592754447000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 0, + "net_usage": 268, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferContract", + "value": { + "amount": 2538461, + "owner_address": "41da03247c21301eaf0538c1b9f79e5c8ea7cbb386", + "to_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TransferContract" + } + ], + "expiration": 1592758089000, + "fee_limit": 0, + "ref_block_bytes": "d523", + "ref_block_hash": "dc512cab1e07f960", + "timestamp": 1592754430099 + }, + "raw_data_hex": "0a02d5232208dc512cab1e07f96040a8ea9ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541da03247c21301eaf0538c1b9f79e5c8ea7cbb38612154179309abcff2cf531070ca9222a1f72c4a513687418ddf79a017093c1bfbcad2e", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 0 }], + "signature": [ + "0b542abf1657965deeb06123636f6e4ccaea5f4ab0a14f81f3164b286cb6ede37c62d701c796ae86cbd5c908009e5ac6db73d4532a9976ce5b30df47460957d601" + ], + "txID": "82efc8456a3c38a0919af416a53363405ced78db7c13e1b94a79ebcea98f9909" + }, + { + "blockNumber": 20829498, + "block_timestamp": 1592754444000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 0, + "net_usage": 268, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferContract", + "value": { + "amount": 30000000, + "owner_address": "41f3eb90cf03d6301e1d10b6095113494bc704992c", + "to_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TransferContract" + } + ], + "expiration": 1592758089000, + "fee_limit": 0, + "ref_block_bytes": "d523", + "ref_block_hash": "dc512cab1e07f960", + "timestamp": 1592754429791 + }, + "raw_data_hex": "0a02d5232208dc512cab1e07f96040a8ea9ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541f3eb90cf03d6301e1d10b6095113494bc704992c12154179309abcff2cf531070ca9222a1f72c4a5136874188087a70e70dfbebfbcad2e", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 0 }], + "signature": [ + "d44a181a6ff560bbcd8a89f9b14247f3d3c781020404eb6462926f3e60dfe32c38ee17f0e752346229de30db033352240152891a168285581558f80af90f83fd00" + ], + "txID": "a336bd174c127d38bf2325bc9c927059af099e8cfb91159750a1b1be16dd0bd4" + }, + { + "blockNumber": 20829498, + "block_timestamp": 1592754444000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 0, + "net_usage": 268, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferContract", + "value": { + "amount": 111337320, + "owner_address": "41b4fd934c73429b27c1e9180e04ccfc44c14f15a9", + "to_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TransferContract" + } + ], + "expiration": 1592758086000, + "fee_limit": 0, + "ref_block_bytes": "d522", + "ref_block_hash": "9ecd3926187cf28e", + "timestamp": 1592754429463 + }, + "raw_data_hex": "0a02d52222089ecd3926187cf28e40f0d29ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541b4fd934c73429b27c1e9180e04ccfc44c14f15a912154179309abcff2cf531070ca9222a1f72c4a513687418e8be8b357097bcbfbcad2e", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 0 }], + "signature": [ + "a40ce5f8ab4d9283fd9982eb38aa2a8b8ad9aeaa9bfc8acc220673a367fd420c034f89110e74a99745a96e103b883a85036c64e1c992a7a12c594f11954bacca01" + ], + "txID": "007bbcc3855f4bf51bd76e63d7776160c115c803e227f7c44c7d1fd1bd587611" + }, + { + "blockNumber": 20829498, + "block_timestamp": 1592754444000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 0, + "net_usage": 268, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferContract", + "value": { + "amount": 200000000, + "owner_address": "413c5d20a6b1747c65903e2874614d6b8a038b818c", + "to_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TransferContract" + } + ], + "expiration": 1592758086000, + "fee_limit": 0, + "ref_block_bytes": "d522", + "ref_block_hash": "9ecd3926187cf28e", + "timestamp": 1592754429137 + }, + "raw_data_hex": "0a02d52222089ecd3926187cf28e40f0d29ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a15413c5d20a6b1747c65903e2874614d6b8a038b818c12154179309abcff2cf531070ca9222a1f72c4a5136874188084af5f70d1b9bfbcad2e", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 0 }], + "signature": [ + "9192ee355f2b8c4b21cb68d5b5b2647a4ccb3a00c2bdaeb65cddef4785e7a31e364e21ef3c8b78628c8d342d6f7727ab391b064c1f0b02105e300108ca9cf88800" + ], + "txID": "9351e87b129142844f000a52911daf36fc95677dfe2846abcd28ea0d8fe2e2ea" + }, + { + "blockNumber": 20829498, + "block_timestamp": 1592754444000, + "energy_fee": 0, + "energy_usage": 0, + "energy_usage_total": 0, + "internal_transactions": [], + "net_fee": 0, + "net_usage": 269, + "raw_data": { + "contract": [ + { + "parameter": { + "type_url": "type.googleapis.com/protocol.TransferContract", + "value": { + "amount": 511000000, + "owner_address": "414a5a0f19fd4b1c85208764a7a8cdcdb88171fc71", + "to_address": "4179309abcff2cf531070ca9222a1f72c4a5136874" + } + }, + "type": "TransferContract" + } + ], + "expiration": 1592758086000, + "fee_limit": 0, + "ref_block_bytes": "d522", + "ref_block_hash": "9ecd3926187cf28e", + "timestamp": 1592754428706 + }, + "raw_data_hex": "0a02d52222089ecd3926187cf28e40f0d29ebead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a15414a5a0f19fd4b1c85208764a7a8cdcdb88171fc7112154179309abcff2cf531070ca9222a1f72c4a513687418c0fbd4f30170a2b6bfbcad2e", + "ret": [{ "code": "SUCESS", "contractRet": "SUCCESS", "fee": 0 }], + "signature": [ + "fac73d7f6540a63c27717cbe04197d8ae89bd906f6c59eba71cc3a2630e29d9b6e0e4400b5e316289e5b6608d84a1a47673674605e48776f8d97aa3dedcfc60301" + ], + "txID": "008ebda5749c38e26a69717faa66e6f4fd8a0d358c9b947192765cc9843cff5a" + } + ] +} diff --git a/platform/tron/mocks/tokens/asset_1000542_response.json b/platform/tron/mocks/tokens/asset_1000542_response.json new file mode 100644 index 000000000..b365fc6a1 --- /dev/null +++ b/platform/tron/mocks/tokens/asset_1000542_response.json @@ -0,0 +1,19 @@ +{ + "success": true, + "meta": { "at": 1592754266101, "page_size": 1 }, + "data": [ + { + "id": 1000542, + "abbr": "FOM", + "description": "Fomo3D is a decentralized, trustless blockchain game.", + "name": "FomoThreeD", + "num": 1, + "total_supply": 80000000000, + "trx_num": 1000000, + "url": "https://fomo3d.games/", + "owner_address": "4134f1b9c19cf40f565661697eb47b0090ac779507", + "start_time": 1534348821000, + "end_time": 1924876800000 + } + ] +} diff --git a/platform/tron/mocks/tokens/asset_1000567_response.json b/platform/tron/mocks/tokens/asset_1000567_response.json new file mode 100644 index 000000000..b8dd645fc --- /dev/null +++ b/platform/tron/mocks/tokens/asset_1000567_response.json @@ -0,0 +1,20 @@ +{ + "success": true, + "meta": { "at": 1592754347268, "page_size": 1 }, + "data": [ + { + "id": 1000567, + "abbr": "os", + "description": "Open Decentralized Search Engine", + "frozen_supply": [{ "frozen_amount": 74000000000, "frozen_days": 3652 }], + "name": "OtonamiS", + "num": 100, + "total_supply": 99000000000, + "trx_num": 1000000, + "url": "https://OtonamiS.com", + "owner_address": "413cea69143b5a5b1ff15d847a7e30e3bffa6a2247", + "start_time": 1534773969000, + "end_time": 1566280800000 + } + ] +} diff --git a/platform/tron/mocks/tokens/asset_tr7nh_response.json b/platform/tron/mocks/tokens/asset_tr7nh_response.json new file mode 100644 index 000000000..afd44c32b --- /dev/null +++ b/platform/tron/mocks/tokens/asset_tr7nh_response.json @@ -0,0 +1,5 @@ +{ + "success": true, + "meta": { "at": 1592754347268, "page_size": 1 }, + "data": [] +} diff --git a/platform/tron/mocks/tokens/tokens_response.json b/platform/tron/mocks/tokens/tokens_response.json new file mode 100644 index 000000000..41de9abbe --- /dev/null +++ b/platform/tron/mocks/tokens/tokens_response.json @@ -0,0 +1,98 @@ +[ + { + "name": "FomoThreeD", + "symbol": "FOM", + "decimals": 0, + "token_id": "1000542", + "coin": 195, + "type": "TRC10" + }, + { + "name": "OtonamiS", + "symbol": "OS", + "decimals": 0, + "token_id": "1000567", + "coin": 195, + "type": "TRC10" + }, + { + "name": "JUST GOV", + "symbol": "JST", + "decimals": 18, + "token_id": "TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9", + "coin": 195, + "type": "TRC20" + }, + { + "name": "Enme Token", + "symbol": "EME", + "decimals": 6, + "token_id": "TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF", + "coin": 195, + "type": "TRC20" + }, + { + "name": "BeeHive", + "symbol": "BEE", + "decimals": 8, + "token_id": "TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK", + "coin": 195, + "type": "TRC20" + }, + { + "name": "Mono Token", + "symbol": "MONO", + "decimals": 18, + "token_id": "TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak", + "coin": 195, + "type": "TRC20" + }, + { + "name": "WINK", + "symbol": "WIN", + "decimals": 6, + "token_id": "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7", + "coin": 195, + "type": "TRC20" + }, + { + "name": "PYRO Network", + "symbol": "PYRO", + "decimals": 6, + "token_id": "TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e", + "coin": 195, + "type": "TRC20" + }, + { + "name": "NoleCoin", + "symbol": "NOLE", + "decimals": 6, + "token_id": "TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG", + "coin": 195, + "type": "TRC20" + }, + { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "coin": 195, + "type": "TRC20" + }, + { + "name": "Wuhan Fried Bats", + "symbol": "WUHAN", + "decimals": 4, + "token_id": "TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr", + "coin": 195, + "type": "TRC20" + }, + { + "name": "HelGro", + "symbol": "HGRO", + "decimals": 6, + "token_id": "TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm", + "coin": 195, + "type": "TRC20" + } +] diff --git a/platform/tron/mocks/tokens/trc20_response.json b/platform/tron/mocks/tokens/trc20_response.json new file mode 100644 index 000000000..bb72b3408 --- /dev/null +++ b/platform/tron/mocks/tokens/trc20_response.json @@ -0,0 +1,2107 @@ +{ + "trc20token_balances": [ + { + "name": "BeeHive", + "symbol": "Bee", + "decimals": 8, + "contract_address": "TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK", + "balance": "100000000000000" + }, + { + "name": "NoleCoin", + "symbol": "NOLE", + "decimals": 6, + "contract_address": "TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG", + "balance": "20000", + "priceInTrx": 20.0 + }, + { + "name": "Enme Token", + "symbol": "EME", + "decimals": 6, + "contract_address": "TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF", + "balance": "175798" + }, + { + "name": "PYRO Network", + "symbol": "PYRO", + "decimals": 6, + "contract_address": "TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e", + "balance": "5000000000", + "priceInTrx": 0.005821 + }, + { + "name": "Wuhan Fried Bats", + "symbol": "WUHAN", + "decimals": 4, + "contract_address": "TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr", + "balance": "690000" + }, + { + "name": "WINK", + "symbol": "WIN", + "decimals": 6, + "contract_address": "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7", + "balance": "191543058623486", + "priceInTrx": 0.004665 + }, + { + "name": "Mono Token", + "symbol": "MONO", + "decimals": 18, + "contract_address": "TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak", + "balance": "1" + }, + { + "name": "HelGro", + "symbol": "HGRO", + "decimals": 6, + "contract_address": "TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm", + "balance": "20000000" + }, + { + "name": "JUST GOV", + "symbol": "JST", + "decimals": 18, + "contract_address": "TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9", + "balance": "955973733483987848990056", + "priceInTrx": 0.3133 + }, + { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "balance": "6781725898163", + "priceInTrx": 64.102564 + } + ], + "allowExchange": [], + "address": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R", + "frozen_supply": [], + "bandwidth": { + "energyRemaining": 0, + "totalEnergyLimit": 90000000000, + "totalEnergyWeight": 1446707995, + "netUsed": 0, + "storageLimit": 0, + "storagePercentage": 0.0, + "assets": { + "1000542": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002446": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002721": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001510": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002962": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001479": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002288": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001594": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002683": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000541": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001079": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000145": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002608": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000821": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002845": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001759": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002726": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001230": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001467": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002798": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000894": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000532": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002830": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000017": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000494": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002398": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002552": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002551": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002672": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002037": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002950": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000935": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000938": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002438": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000491": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000096": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002671": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000493": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001064": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001581": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002270": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000322": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002589": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001411": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002467": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002742": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001414": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001535": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000567": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000165": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001011": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002342": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001132": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000562": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000287": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001815": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002907": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002746": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002748": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001090": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000278": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000157": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002578": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002577": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002852": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002459": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000396": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002573": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002454": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000959": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002736": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002858": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1003022": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001038": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000983": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001433": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000743": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001953": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002646": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000985": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002524": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002001": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002881": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002488": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002521": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002762": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002927": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002926": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000745": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000744": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000746": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002000": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000181": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002116": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001301": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001425": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002876": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000176": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000451": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1003049": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002597": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002918": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002636": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002999": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001825": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000856": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002517": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002230": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002071": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1003041": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002072": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000003": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000520": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000884": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002544": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001854": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002822": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000006": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002662": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002669": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002384": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002263": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001203": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002897": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001565": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002775": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002657": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001204": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1001446": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002892": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002939": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002814": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002250": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1002099": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + }, + "1000190": { + "netPercentage": 0.0, + "netLimit": 0, + "netRemaining": 0, + "netUsed": 0 + } + }, + "netPercentage": 0.0, + "storageUsed": 0, + "storageRemaining": 0, + "freeNetLimit": 5000, + "energyUsed": 0, + "freeNetRemaining": 211, + "netLimit": 0, + "netRemaining": 0, + "energyLimit": 0, + "freeNetUsed": 4789, + "totalNetWeight": 26789943446, + "freeNetPercentage": 0.9578, + "energyPercentage": 0.0, + "totalNetLimit": 43200000000 + }, + "accountType": 0, + "exchanges": [], + "frozen": { "total": 0, "balances": [] }, + "accountResource": { "frozen_balance_for_energy": {} }, + "tokenBalances": [ + { "balance": 346976329314696, "name": "_" }, + { "balance": 1273, "name": "1000003" }, + { "balance": 113, "name": "1000006" }, + { "balance": 145, "name": "1000165" }, + { "balance": 416, "name": "1000520" }, + { "balance": 596, "name": "1000491" }, + { + "balance": 242, + "name": "1000176", + "owner_address": "THG48yHsR6inxrCJk2hhxZPsFLq1ehP88V" + }, + { "balance": 62, "name": "1000542" }, + { + "balance": 53, + "name": "1000494", + "owner_address": "TXJnVqqwLSNmdXDLWn1Yfjhe8aZH2oaAuq" + }, + { "balance": 56, "name": "1000493" }, + { "balance": 599, "name": "1000744" }, + { "balance": 628, "name": "1000746" }, + { "balance": 234, "name": "1000743" }, + { "balance": 113, "name": "1000396" }, + { + "balance": 206, + "name": "1000745", + "owner_address": "TPCEi45wZQ1PPChUg5uqoK1D5kKnjCR8Li" + }, + { + "balance": 61, + "name": "1000821", + "owner_address": "TBm3Peu51gYwn2iPwNEDxc9vBMc3eRGUGu" + }, + { "balance": 25, "name": "1000541" }, + { + "balance": 7, + "name": "1000278", + "owner_address": "TRMUimDekf9nDLuVMp6TKzcw4axNnajGJr" + }, + { + "balance": 1, + "name": "1000567", + "owner_address": "TFXJMhB4ZKBfcQWfCLbSyQGhonHXABaWku" + }, + { + "balance": 1, + "name": "1000856", + "owner_address": "TXf3X8YMdDho2xwA6QDbFZiTGPnk8ghfLm" + }, + { "balance": 30, "name": "1000884" }, + { "balance": 1, "name": "1000894" }, + { + "balance": 200, + "name": "1000181", + "owner_address": "TEmTbbvH5ZPJPZ8CbffjqonFRiAAFgfc9o" + }, + { + "balance": 7, + "name": "1000935", + "owner_address": "TPVkcFYTEi9Dia45AveiTcaYoaU9ux7xC7" + }, + { + "balance": 1000, + "name": "1000938", + "owner_address": "TNgkWTabK1rMWwgLjmLdsZbzYfGTx5Tpe9" + }, + { + "balance": 10, + "name": "1000017", + "owner_address": "TV6qcwSp38uESiDczxxb7zbJX1h2LfDs78" + }, + { + "balance": 10, + "name": "1001011", + "owner_address": "TNUbeTQXPtRXtBX3dJboVkhdhaiws29Aky" + }, + { + "balance": 2, + "name": "1001038", + "owner_address": "TFujVDp8U578L2AtsorYN3pwdXmH2HxbQv" + }, + { + "balance": 100, + "name": "1000983", + "owner_address": "TYmiZ7xCeqboiizb2jsjVQuRABXzVSjKFR" + }, + { + "balance": 1, + "name": "1001203", + "owner_address": "TBmaT8mcrdkrRL2Q6ur7grMYAcaGtfxsz7" + }, + { + "balance": 1, + "name": "1000190", + "owner_address": "TNXjXURue38Wa641pmqMH4vbJN1WZLKMnr" + }, + { "balance": 100, "name": "1001204" }, + { "balance": 1000, "name": "1001230" }, + { + "balance": 1300000, + "name": "1001301", + "owner_address": "TVgJEbc9NEYxVr1h6rJQiMqySePsJQDCA7" + }, + { "balance": 11, "name": "1000959" }, + { "balance": 10, "name": "1001425" }, + { + "balance": 17, + "name": "1001433", + "owner_address": "TWPMz6FPEAV6qP4VRMG3Y69ftEov1R7YWT" + }, + { "balance": 100, "name": "1001446" }, + { + "balance": 12, + "name": "1001411", + "owner_address": "TPL6zNujtEQ8kp213n58UxAhGRCU3aozkc" + }, + { "balance": 12, "name": "1001467" }, + { + "balance": 100, + "name": "1001414", + "owner_address": "TT43DgfxgMdR4BVZNua4YCwG34AgfGN6Uu" + }, + { + "balance": 100, + "name": "1001510", + "owner_address": "TPKq9bVZyM2sZ8XersMmXhy1NbjhdxRwwj" + }, + { + "balance": 50, + "name": "1001565", + "owner_address": "TKY7Vmq78b2c83fLXrPijkhQkk4EJtfViD" + }, + { "balance": 5, "name": "1001535" }, + { + "balance": 10, + "name": "1000532", + "owner_address": "TGQwBNht8h3zev4gBtDMoQjWE2WJm1Zr9B" + }, + { + "balance": 3, + "name": "1001479", + "owner_address": "TC9FtB1EoiV3jfXgZvmqUmfeCmdWNmCxdY" + }, + { + "balance": 13, + "name": "1001090", + "owner_address": "TU1LUTYDMG6iihimUpAmdnnBthawPKh1cm", + "priceInTrx": 0.00436 + }, + { + "balance": 200, + "name": "1001759", + "owner_address": "TWKWWJAFBYyjvLtfqKCSeMyUW7TjWhkY4e" + }, + { + "balance": 12, + "name": "1000096", + "owner_address": "TSfjkVSKJGW4aybDQcxi4bpythU7WCXV3v" + }, + { "balance": 15, "name": "1001594" }, + { + "balance": 10, + "name": "1001815", + "owner_address": "TB3iM1RsKXagV7hdz2QpWnaChptwrU3tCL" + }, + { + "balance": 10, + "name": "1001064", + "owner_address": "THnWV416C9mfJ1LFwopUjGXZEr1xFtAdrD" + }, + { + "balance": 5192508733304578, + "name": "1002000", + "owner_address": "TF5Bn4cJCT6GVeUgyCN4rBhDg42KBrpAjg", + "priceInTrx": 0.0189 + }, + { + "balance": 7742069, + "name": "1002037", + "owner_address": "TBekuTCZwPG2o88SmiS58VALkxBemoX4yS" + }, + { "balance": 585, "name": "1002001" }, + { + "balance": 5441, + "name": "1002071", + "owner_address": "TS79aik831csqUnQgnqrKG6hov2iL8yPbD" + }, + { + "balance": 80312957663126, + "name": "1002072", + "owner_address": "TP6PtaBSMM6sfWtWWD9k77YHWGmh7K3Lae" + }, + { + "balance": 520, + "name": "1000451", + "owner_address": "THPXuypwcnWo4wi5KqFfuRjgjeT5khUDKF" + }, + { + "balance": 10011237, + "name": "1001953", + "owner_address": "TSyG9BdjsGE2GoHG9eeYKMns6zMQFDmbvS" + }, + { + "balance": 5, + "name": "1000562", + "owner_address": "TWqKTJ5JhyD7rsbbWzEvS5ZZD9Q5QPPvSH" + }, + { + "balance": 50000000, + "name": "1002099", + "owner_address": "TYWmiPERm9kWUcnduqaE5jxT7eeZxfn5SQ" + }, + { + "balance": 625100, + "name": "1001581", + "owner_address": "TNkRSKWP7VvdrisTwC8iNzUV6MRoEJh6xx" + }, + { + "balance": 11000000, + "name": "1002342", + "owner_address": "TUCd8NiBUuxrjz1kSrUbAg2JXu6o27Ukrq" + }, + { + "balance": 7, + "name": "1000322", + "owner_address": "TDGy2M9qWBepSHDEutWWxWd1JZfmAed3BP", + "priceInTrx": 0.000422 + }, + { + "balance": 12, + "name": "1001825", + "owner_address": "TPcUbNeYwwYqbX23w3sVf1X61cwpAfPK2T" + }, + { + "balance": 1000, + "name": "1002384", + "owner_address": "TFYuPxyjDTvH1TLm2phpzJFw7AhjCgu8xP" + }, + { + "balance": 44444, + "name": "1001132", + "owner_address": "TWDUanVdxEShjpbiX57ExztMCDy8vCFcHh" + }, + { + "balance": 30000000, + "name": "1002398", + "owner_address": "TUXSuMg41nJXm9TuDgF6EZWjEbP2vx1Hd4" + }, + { + "balance": 10000060, + "name": "1002116", + "owner_address": "TAEvo6MgLgV3A75L3cr3BAsLDJikWcAt3j" + }, + { + "balance": 50000000, + "name": "1002446", + "owner_address": "TJKf72NjL1cR49SHfDnPTXTFjRwjgr7v8Z" + }, + { + "balance": 10000000, + "name": "1002459", + "owner_address": "TNWy3mX85JsX2mPLgLc4cKJiWtJahhz3t3" + }, + { + "balance": 1, + "name": "1001079", + "owner_address": "TLQfc5EwZQqZc6jMNkMpxyJy5wucA6UX24" + }, + { + "balance": 12345, + "name": "1002467", + "owner_address": "TP429SKrsp4BoTiEFXHj4TNSJwqDFsygnr" + }, + { + "balance": 1234, + "name": "1002230", + "owner_address": "TWB9Q1JoB3fSLsahNq31gydRxYyWxDhSyk" + }, + { + "balance": 10000000, + "name": "1002288", + "owner_address": "TPzfpaaKUPgJPZ39YeyvBaTYNXBYpnhxDg" + }, + { + "balance": 5, + "name": "1002488", + "owner_address": "TMeAzhdgzu1sFMTsP75BffJ2tEzuGsYqR6" + }, + { + "balance": 666, + "name": "1002438", + "owner_address": "TMqNJwD3qVmuRxzzP3Q4A24fuByVBKQ39E" + }, + { + "balance": 10000000, + "name": "1002517", + "owner_address": "TP9m11ERHhE1qgDtL83c2AHHNkWvdUfKTz" + }, + { + "balance": 10000000000, + "name": "1002521", + "owner_address": "TJUwM4qk1et2nNKuESQ7UVHPjAHoRqAz3T" + }, + { + "balance": 13699, + "name": "1000157", + "owner_address": "TUahmv54ZiDnjQWG2VAeyMphebXQ4m6Hb5" + }, + { + "balance": 65895, + "name": "1002524", + "owner_address": "TRzZeBPt69utiWx1po5ghLH8uSP8uJGsa5" + }, + { + "balance": 16, + "name": "1000287", + "owner_address": "TFZCyZ18XNzMfEr6W5kLkGrs4HVmou9H3y" + }, + { + "balance": 10000000, + "name": "1002544", + "owner_address": "TQHBbjES5DNjDfDHBbpnh9qcDM7mVjSVcL" + }, + { + "balance": 10000000000, + "name": "1002551", + "owner_address": "TVrGxBCQkWjQ52D7S67UgFsUzcX4E8EsNB" + }, + { + "balance": 10000000, + "name": "1002573", + "owner_address": "TBfmGqmZtdEQNuYCz8s1izBUDxZbkPmMcj" + }, + { + "balance": 10000000, + "name": "1002552", + "owner_address": "TCxeAH2ajBqoWzqV9m5YiFTyeQ5FvzVqSH" + }, + { + "balance": 1000000, + "name": "1002578", + "owner_address": "TUjBG7C1CU7X75UmacnyrRTYLmbSeX7iDa" + }, + { + "balance": 2555000, + "name": "1002270", + "owner_address": "TMSpdYHCgZuxM7AjqKsjGMM1cpxraFuZGp" + }, + { + "balance": 10000000, + "name": "1002597", + "owner_address": "TDEBhgsdGTSzrgMsPDUQ1pt59fR6wWR7Rq" + }, + { + "balance": 10000000, + "name": "1002636", + "owner_address": "TKL54NcGXvBckkGbPjYzAmdwFs3usv8VY9" + }, + { + "balance": 100000000, + "name": "1002250", + "owner_address": "THUHfNqiYo4KS3GLM8MUU4x3wek9uPD47d" + }, + { + "balance": 1000000, + "name": "1002662", + "owner_address": "TEV5PJWga6crSeNLHmHaaco8fon6nm74wJ" + }, + { + "balance": 10000000, + "name": "1002672", + "owner_address": "TBHJCf3nymJPt1hVPjSJfH5ssJLdNMPepe" + }, + { + "balance": 24120, + "name": "1002657", + "owner_address": "TCKiVea721ycNAWonb2dpwr65AJkMiGSFb" + }, + { + "balance": 1000000, + "name": "1002683", + "owner_address": "TL6YggMQQ3YFEc41wesBMHZjDxcGpX3y5q" + }, + { + "balance": 3000000, + "name": "1002671", + "owner_address": "TDQ5q4Hf6UqR43Smp67sndMQfdTcGgP88s" + }, + { + "balance": 20, + "name": "1002577", + "owner_address": "TGZzci6a9wtcSiNekqYLP84ECRoaJ6pBwY" + }, + { + "balance": 10000000, + "name": "1002721", + "owner_address": "TUkUgsTTo74B9XG9da4d2NsaZqCKLNFwNS" + }, + { + "balance": 10000, + "name": "1002726", + "owner_address": "TRXw3Ggt3xs3fHbcoark1aeKwUZFKTYcsS" + }, + { + "balance": 21092024781, + "name": "1002263", + "owner_address": "TD5AwyiTNbKN9jQqyMzwQ6NLrWGbtAcotK" + }, + { + "balance": 10000000, + "name": "1002736", + "owner_address": "TBB19fMCf19wuiu5omtA1nAqALPpo4oa32" + }, + { + "balance": 10000000, + "name": "1002646", + "owner_address": "TRUnzvtzT6o35M4XHUvKr48yCZjw4dQyvp" + }, + { + "balance": 7392000000, + "name": "1002589", + "owner_address": "TUL9NhGQkRFLTRcHGkdoSniAeVaNPZGgot" + }, + { + "balance": 10000000, + "name": "1002742", + "owner_address": "TWfrNPVGDh1tyPVM79bfEASb7jw2bLbZPJ" + }, + { + "balance": 8822711275000000, + "name": "1002762", + "owner_address": "TRChSJM8TjQj7vvJCN9W8WBcfkJq2eBxgv" + }, + { "balance": 10000000, "name": "1002775" }, + { + "balance": 10000000, + "name": "1002798", + "owner_address": "TBitZMK7YSUb2Q1Cm537D5iAZSJkaPdN9c" + }, + { + "balance": 95, + "name": "1001854", + "owner_address": "TSMeDkfmX6m1NZmDBrVtGPnACJCUWVkx4p" + }, + { + "balance": 10000000, + "name": "1002746", + "owner_address": "TQbbAyfcrKERXjUDf8TZfcdtjFQbCSgEfc" + }, + { + "balance": 2000000, + "name": "1002669", + "owner_address": "THhgpkHBdJDDWBPnZKRgzdvRr3qCtAa2cv" + }, + { + "balance": 10000000, + "name": "1002814", + "owner_address": "TNvq4y2A2beBENtcGknwhX6XHgk8hqgnVh" + }, + { + "balance": 10000000, + "name": "1002830", + "owner_address": "THLLMnsEKEci5e5dJHnW28QQU8AujGhSoK" + }, + { + "balance": 10000000, + "name": "1002845", + "owner_address": "TUzpDkzjWkZasA6Dx7nx5PPskMkCcNxVyQ" + }, + { + "balance": 10000000, + "name": "1002858", + "owner_address": "TRKJcugHJeffVpCAFGapZMwuH8HaTWjbof" + }, + { + "balance": 200, + "name": "1002454", + "owner_address": "TDCGkNf3XB3jRGg7bhFkNynkGw7q4kV3z9" + }, + { + "balance": 10000000, + "name": "1002876", + "owner_address": "TGqiinRV6nn8GbF5LX7zue4fpjstG1gVvu" + }, + { + "balance": 20000000, + "name": "1002881", + "owner_address": "TWpKN6y3NVXm5mMjGmPEtLpS6boGM4q8T4" + }, + { + "balance": 350, + "name": "1000145", + "owner_address": "TNFcvwJgvBRg2Dq5Qyx1gxcvqU3dwPyVNc" + }, + { + "balance": 10000000, + "name": "1002892", + "owner_address": "TECsVV1kTtx48sbdjvptq544h4H3Qqr24c" + }, + { + "balance": 10000000, + "name": "1002897", + "owner_address": "TPKqse19ALipJ1uBZHGWHzuTrQqZa4HtaM" + }, + { + "balance": 2055000000, + "name": "1002822", + "owner_address": "TURy9pFLskqTWgkZqUCUdPXkezZfYL76YQ" + }, + { + "balance": 1000000, + "name": "1002852", + "owner_address": "TUmad3hCqxu78n8GuULrdJMUB4qmTUYgv3" + }, + { + "balance": 10000000, + "name": "1002907", + "owner_address": "TKC9HMUXx3qLE7d19KWzWVjFxEcWQdSYK9" + }, + { + "balance": 10000000, + "name": "1002927", + "owner_address": "TAwRvFAqfB4bbzVCVPgGATZV5uMVs9UyVL" + }, + { + "balance": 10000000, + "name": "1002926", + "owner_address": "TF5jfDiQ3d7T5ihcBxeWS9S8xSR5tS738x" + }, + { + "balance": 1000000, + "name": "1002748", + "owner_address": "TTUAmhh9k2Yegf3TxZc86vG5E9kT24vgcw" + }, + { + "balance": 189990000000, + "name": "1002950", + "owner_address": "TNCZCGDPQ69ieJFsY1jZUohXmR46A4kM24" + }, + { + "balance": 10, + "name": "1000985", + "owner_address": "TRH5jmPx77UnMvfdvfo2m3FCkZVcBiFvqP" + }, + { + "balance": 10000000, + "name": "1002962", + "owner_address": "TFDwGwod9qopreRiirsFMwPzX4v2r662P4" + }, + { + "balance": 10000000, + "name": "1002918", + "owner_address": "TKGpTks1myPrJ9ZtEdLgpjvg1RMR2wGAFz" + }, + { + "balance": 1000, + "name": "1002608", + "owner_address": "TDPsSgBQznKEffdTMq3aspsvrmFfhL7ZcP" + }, + { + "balance": 10000000, + "name": "1002999", + "owner_address": "TTL52uBzTG7qorL7BQYdjGUY3HWWr9Kvao" + }, + { + "balance": 100000000000, + "name": "1003022", + "owner_address": "TAAJiJ1NgkEkE3w1PQk4dA8XH9rpfk5eVE" + }, + { + "balance": 1000000000, + "name": "1003041", + "owner_address": "TQADZoww5HstdsJM1GXwstqsRRnmrkThzY" + }, + { + "balance": 10000000, + "name": "1003049", + "owner_address": "THFJwSN5Z3zTc5TvkSiVh8m4kQMZaTMaqk" + }, + { + "balance": 1, + "name": "1002939", + "owner_address": "TAsSw8hUddYi8AN8EkDuAMS9r8pkriyUxs" + } + ], + "balances": [ + { "balance": 346976329314696, "name": "_" }, + { "balance": 1273, "name": "1000003" }, + { "balance": 113, "name": "1000006" }, + { "balance": 145, "name": "1000165" }, + { "balance": 416, "name": "1000520" }, + { "balance": 596, "name": "1000491" }, + { + "balance": 242, + "name": "1000176", + "owner_address": "THG48yHsR6inxrCJk2hhxZPsFLq1ehP88V" + }, + { "balance": 62, "name": "1000542" }, + { + "balance": 53, + "name": "1000494", + "owner_address": "TXJnVqqwLSNmdXDLWn1Yfjhe8aZH2oaAuq" + }, + { "balance": 56, "name": "1000493" }, + { "balance": 599, "name": "1000744" }, + { "balance": 628, "name": "1000746" }, + { "balance": 234, "name": "1000743" }, + { "balance": 113, "name": "1000396" }, + { + "balance": 206, + "name": "1000745", + "owner_address": "TPCEi45wZQ1PPChUg5uqoK1D5kKnjCR8Li" + }, + { + "balance": 61, + "name": "1000821", + "owner_address": "TBm3Peu51gYwn2iPwNEDxc9vBMc3eRGUGu" + }, + { "balance": 25, "name": "1000541" }, + { + "balance": 7, + "name": "1000278", + "owner_address": "TRMUimDekf9nDLuVMp6TKzcw4axNnajGJr" + }, + { + "balance": 1, + "name": "1000567", + "owner_address": "TFXJMhB4ZKBfcQWfCLbSyQGhonHXABaWku" + }, + { + "balance": 1, + "name": "1000856", + "owner_address": "TXf3X8YMdDho2xwA6QDbFZiTGPnk8ghfLm" + }, + { "balance": 30, "name": "1000884" }, + { "balance": 1, "name": "1000894" }, + { + "balance": 200, + "name": "1000181", + "owner_address": "TEmTbbvH5ZPJPZ8CbffjqonFRiAAFgfc9o" + }, + { + "balance": 7, + "name": "1000935", + "owner_address": "TPVkcFYTEi9Dia45AveiTcaYoaU9ux7xC7" + }, + { + "balance": 1000, + "name": "1000938", + "owner_address": "TNgkWTabK1rMWwgLjmLdsZbzYfGTx5Tpe9" + }, + { + "balance": 10, + "name": "1000017", + "owner_address": "TV6qcwSp38uESiDczxxb7zbJX1h2LfDs78" + }, + { + "balance": 10, + "name": "1001011", + "owner_address": "TNUbeTQXPtRXtBX3dJboVkhdhaiws29Aky" + }, + { + "balance": 2, + "name": "1001038", + "owner_address": "TFujVDp8U578L2AtsorYN3pwdXmH2HxbQv" + }, + { + "balance": 100, + "name": "1000983", + "owner_address": "TYmiZ7xCeqboiizb2jsjVQuRABXzVSjKFR" + }, + { + "balance": 1, + "name": "1001203", + "owner_address": "TBmaT8mcrdkrRL2Q6ur7grMYAcaGtfxsz7" + }, + { + "balance": 1, + "name": "1000190", + "owner_address": "TNXjXURue38Wa641pmqMH4vbJN1WZLKMnr" + }, + { "balance": 100, "name": "1001204" }, + { "balance": 1000, "name": "1001230" }, + { + "balance": 1300000, + "name": "1001301", + "owner_address": "TVgJEbc9NEYxVr1h6rJQiMqySePsJQDCA7" + }, + { "balance": 11, "name": "1000959" }, + { "balance": 10, "name": "1001425" }, + { + "balance": 17, + "name": "1001433", + "owner_address": "TWPMz6FPEAV6qP4VRMG3Y69ftEov1R7YWT" + }, + { "balance": 100, "name": "1001446" }, + { + "balance": 12, + "name": "1001411", + "owner_address": "TPL6zNujtEQ8kp213n58UxAhGRCU3aozkc" + }, + { "balance": 12, "name": "1001467" }, + { + "balance": 100, + "name": "1001414", + "owner_address": "TT43DgfxgMdR4BVZNua4YCwG34AgfGN6Uu" + }, + { + "balance": 100, + "name": "1001510", + "owner_address": "TPKq9bVZyM2sZ8XersMmXhy1NbjhdxRwwj" + }, + { + "balance": 50, + "name": "1001565", + "owner_address": "TKY7Vmq78b2c83fLXrPijkhQkk4EJtfViD" + }, + { "balance": 5, "name": "1001535" }, + { + "balance": 10, + "name": "1000532", + "owner_address": "TGQwBNht8h3zev4gBtDMoQjWE2WJm1Zr9B" + }, + { + "balance": 3, + "name": "1001479", + "owner_address": "TC9FtB1EoiV3jfXgZvmqUmfeCmdWNmCxdY" + }, + { + "balance": 13, + "name": "1001090", + "owner_address": "TU1LUTYDMG6iihimUpAmdnnBthawPKh1cm", + "priceInTrx": 0.00436 + }, + { + "balance": 200, + "name": "1001759", + "owner_address": "TWKWWJAFBYyjvLtfqKCSeMyUW7TjWhkY4e" + }, + { + "balance": 12, + "name": "1000096", + "owner_address": "TSfjkVSKJGW4aybDQcxi4bpythU7WCXV3v" + }, + { "balance": 15, "name": "1001594" }, + { + "balance": 10, + "name": "1001815", + "owner_address": "TB3iM1RsKXagV7hdz2QpWnaChptwrU3tCL" + }, + { + "balance": 10, + "name": "1001064", + "owner_address": "THnWV416C9mfJ1LFwopUjGXZEr1xFtAdrD" + }, + { + "balance": 5192508733304578, + "name": "1002000", + "owner_address": "TF5Bn4cJCT6GVeUgyCN4rBhDg42KBrpAjg", + "priceInTrx": 0.0189 + }, + { + "balance": 7742069, + "name": "1002037", + "owner_address": "TBekuTCZwPG2o88SmiS58VALkxBemoX4yS" + }, + { "balance": 585, "name": "1002001" }, + { + "balance": 5441, + "name": "1002071", + "owner_address": "TS79aik831csqUnQgnqrKG6hov2iL8yPbD" + }, + { + "balance": 80312957663126, + "name": "1002072", + "owner_address": "TP6PtaBSMM6sfWtWWD9k77YHWGmh7K3Lae" + }, + { + "balance": 520, + "name": "1000451", + "owner_address": "THPXuypwcnWo4wi5KqFfuRjgjeT5khUDKF" + }, + { + "balance": 10011237, + "name": "1001953", + "owner_address": "TSyG9BdjsGE2GoHG9eeYKMns6zMQFDmbvS" + }, + { + "balance": 5, + "name": "1000562", + "owner_address": "TWqKTJ5JhyD7rsbbWzEvS5ZZD9Q5QPPvSH" + }, + { + "balance": 50000000, + "name": "1002099", + "owner_address": "TYWmiPERm9kWUcnduqaE5jxT7eeZxfn5SQ" + }, + { + "balance": 625100, + "name": "1001581", + "owner_address": "TNkRSKWP7VvdrisTwC8iNzUV6MRoEJh6xx" + }, + { + "balance": 11000000, + "name": "1002342", + "owner_address": "TUCd8NiBUuxrjz1kSrUbAg2JXu6o27Ukrq" + }, + { + "balance": 7, + "name": "1000322", + "owner_address": "TDGy2M9qWBepSHDEutWWxWd1JZfmAed3BP", + "priceInTrx": 0.000422 + }, + { + "balance": 12, + "name": "1001825", + "owner_address": "TPcUbNeYwwYqbX23w3sVf1X61cwpAfPK2T" + }, + { + "balance": 1000, + "name": "1002384", + "owner_address": "TFYuPxyjDTvH1TLm2phpzJFw7AhjCgu8xP" + }, + { + "balance": 44444, + "name": "1001132", + "owner_address": "TWDUanVdxEShjpbiX57ExztMCDy8vCFcHh" + }, + { + "balance": 30000000, + "name": "1002398", + "owner_address": "TUXSuMg41nJXm9TuDgF6EZWjEbP2vx1Hd4" + }, + { + "balance": 10000060, + "name": "1002116", + "owner_address": "TAEvo6MgLgV3A75L3cr3BAsLDJikWcAt3j" + }, + { + "balance": 50000000, + "name": "1002446", + "owner_address": "TJKf72NjL1cR49SHfDnPTXTFjRwjgr7v8Z" + }, + { + "balance": 10000000, + "name": "1002459", + "owner_address": "TNWy3mX85JsX2mPLgLc4cKJiWtJahhz3t3" + }, + { + "balance": 1, + "name": "1001079", + "owner_address": "TLQfc5EwZQqZc6jMNkMpxyJy5wucA6UX24" + }, + { + "balance": 12345, + "name": "1002467", + "owner_address": "TP429SKrsp4BoTiEFXHj4TNSJwqDFsygnr" + }, + { + "balance": 1234, + "name": "1002230", + "owner_address": "TWB9Q1JoB3fSLsahNq31gydRxYyWxDhSyk" + }, + { + "balance": 10000000, + "name": "1002288", + "owner_address": "TPzfpaaKUPgJPZ39YeyvBaTYNXBYpnhxDg" + }, + { + "balance": 5, + "name": "1002488", + "owner_address": "TMeAzhdgzu1sFMTsP75BffJ2tEzuGsYqR6" + }, + { + "balance": 666, + "name": "1002438", + "owner_address": "TMqNJwD3qVmuRxzzP3Q4A24fuByVBKQ39E" + }, + { + "balance": 10000000, + "name": "1002517", + "owner_address": "TP9m11ERHhE1qgDtL83c2AHHNkWvdUfKTz" + }, + { + "balance": 10000000000, + "name": "1002521", + "owner_address": "TJUwM4qk1et2nNKuESQ7UVHPjAHoRqAz3T" + }, + { + "balance": 13699, + "name": "1000157", + "owner_address": "TUahmv54ZiDnjQWG2VAeyMphebXQ4m6Hb5" + }, + { + "balance": 65895, + "name": "1002524", + "owner_address": "TRzZeBPt69utiWx1po5ghLH8uSP8uJGsa5" + }, + { + "balance": 16, + "name": "1000287", + "owner_address": "TFZCyZ18XNzMfEr6W5kLkGrs4HVmou9H3y" + }, + { + "balance": 10000000, + "name": "1002544", + "owner_address": "TQHBbjES5DNjDfDHBbpnh9qcDM7mVjSVcL" + }, + { + "balance": 10000000000, + "name": "1002551", + "owner_address": "TVrGxBCQkWjQ52D7S67UgFsUzcX4E8EsNB" + }, + { + "balance": 10000000, + "name": "1002573", + "owner_address": "TBfmGqmZtdEQNuYCz8s1izBUDxZbkPmMcj" + }, + { + "balance": 10000000, + "name": "1002552", + "owner_address": "TCxeAH2ajBqoWzqV9m5YiFTyeQ5FvzVqSH" + }, + { + "balance": 1000000, + "name": "1002578", + "owner_address": "TUjBG7C1CU7X75UmacnyrRTYLmbSeX7iDa" + }, + { + "balance": 2555000, + "name": "1002270", + "owner_address": "TMSpdYHCgZuxM7AjqKsjGMM1cpxraFuZGp" + }, + { + "balance": 10000000, + "name": "1002597", + "owner_address": "TDEBhgsdGTSzrgMsPDUQ1pt59fR6wWR7Rq" + }, + { + "balance": 10000000, + "name": "1002636", + "owner_address": "TKL54NcGXvBckkGbPjYzAmdwFs3usv8VY9" + }, + { + "balance": 100000000, + "name": "1002250", + "owner_address": "THUHfNqiYo4KS3GLM8MUU4x3wek9uPD47d" + }, + { + "balance": 1000000, + "name": "1002662", + "owner_address": "TEV5PJWga6crSeNLHmHaaco8fon6nm74wJ" + }, + { + "balance": 10000000, + "name": "1002672", + "owner_address": "TBHJCf3nymJPt1hVPjSJfH5ssJLdNMPepe" + }, + { + "balance": 24120, + "name": "1002657", + "owner_address": "TCKiVea721ycNAWonb2dpwr65AJkMiGSFb" + }, + { + "balance": 1000000, + "name": "1002683", + "owner_address": "TL6YggMQQ3YFEc41wesBMHZjDxcGpX3y5q" + }, + { + "balance": 3000000, + "name": "1002671", + "owner_address": "TDQ5q4Hf6UqR43Smp67sndMQfdTcGgP88s" + }, + { + "balance": 20, + "name": "1002577", + "owner_address": "TGZzci6a9wtcSiNekqYLP84ECRoaJ6pBwY" + }, + { + "balance": 10000000, + "name": "1002721", + "owner_address": "TUkUgsTTo74B9XG9da4d2NsaZqCKLNFwNS" + }, + { + "balance": 10000, + "name": "1002726", + "owner_address": "TRXw3Ggt3xs3fHbcoark1aeKwUZFKTYcsS" + }, + { + "balance": 21092024781, + "name": "1002263", + "owner_address": "TD5AwyiTNbKN9jQqyMzwQ6NLrWGbtAcotK" + }, + { + "balance": 10000000, + "name": "1002736", + "owner_address": "TBB19fMCf19wuiu5omtA1nAqALPpo4oa32" + }, + { + "balance": 10000000, + "name": "1002646", + "owner_address": "TRUnzvtzT6o35M4XHUvKr48yCZjw4dQyvp" + }, + { + "balance": 7392000000, + "name": "1002589", + "owner_address": "TUL9NhGQkRFLTRcHGkdoSniAeVaNPZGgot" + }, + { + "balance": 10000000, + "name": "1002742", + "owner_address": "TWfrNPVGDh1tyPVM79bfEASb7jw2bLbZPJ" + }, + { + "balance": 8822711275000000, + "name": "1002762", + "owner_address": "TRChSJM8TjQj7vvJCN9W8WBcfkJq2eBxgv" + }, + { "balance": 10000000, "name": "1002775" }, + { + "balance": 10000000, + "name": "1002798", + "owner_address": "TBitZMK7YSUb2Q1Cm537D5iAZSJkaPdN9c" + }, + { + "balance": 95, + "name": "1001854", + "owner_address": "TSMeDkfmX6m1NZmDBrVtGPnACJCUWVkx4p" + }, + { + "balance": 10000000, + "name": "1002746", + "owner_address": "TQbbAyfcrKERXjUDf8TZfcdtjFQbCSgEfc" + }, + { + "balance": 2000000, + "name": "1002669", + "owner_address": "THhgpkHBdJDDWBPnZKRgzdvRr3qCtAa2cv" + }, + { + "balance": 10000000, + "name": "1002814", + "owner_address": "TNvq4y2A2beBENtcGknwhX6XHgk8hqgnVh" + }, + { + "balance": 10000000, + "name": "1002830", + "owner_address": "THLLMnsEKEci5e5dJHnW28QQU8AujGhSoK" + }, + { + "balance": 10000000, + "name": "1002845", + "owner_address": "TUzpDkzjWkZasA6Dx7nx5PPskMkCcNxVyQ" + }, + { + "balance": 10000000, + "name": "1002858", + "owner_address": "TRKJcugHJeffVpCAFGapZMwuH8HaTWjbof" + }, + { + "balance": 200, + "name": "1002454", + "owner_address": "TDCGkNf3XB3jRGg7bhFkNynkGw7q4kV3z9" + }, + { + "balance": 10000000, + "name": "1002876", + "owner_address": "TGqiinRV6nn8GbF5LX7zue4fpjstG1gVvu" + }, + { + "balance": 20000000, + "name": "1002881", + "owner_address": "TWpKN6y3NVXm5mMjGmPEtLpS6boGM4q8T4" + }, + { + "balance": 350, + "name": "1000145", + "owner_address": "TNFcvwJgvBRg2Dq5Qyx1gxcvqU3dwPyVNc" + }, + { + "balance": 10000000, + "name": "1002892", + "owner_address": "TECsVV1kTtx48sbdjvptq544h4H3Qqr24c" + }, + { + "balance": 10000000, + "name": "1002897", + "owner_address": "TPKqse19ALipJ1uBZHGWHzuTrQqZa4HtaM" + }, + { + "balance": 2055000000, + "name": "1002822", + "owner_address": "TURy9pFLskqTWgkZqUCUdPXkezZfYL76YQ" + }, + { + "balance": 1000000, + "name": "1002852", + "owner_address": "TUmad3hCqxu78n8GuULrdJMUB4qmTUYgv3" + }, + { + "balance": 10000000, + "name": "1002907", + "owner_address": "TKC9HMUXx3qLE7d19KWzWVjFxEcWQdSYK9" + }, + { + "balance": 10000000, + "name": "1002927", + "owner_address": "TAwRvFAqfB4bbzVCVPgGATZV5uMVs9UyVL" + }, + { + "balance": 10000000, + "name": "1002926", + "owner_address": "TF5jfDiQ3d7T5ihcBxeWS9S8xSR5tS738x" + }, + { + "balance": 1000000, + "name": "1002748", + "owner_address": "TTUAmhh9k2Yegf3TxZc86vG5E9kT24vgcw" + }, + { + "balance": 189990000000, + "name": "1002950", + "owner_address": "TNCZCGDPQ69ieJFsY1jZUohXmR46A4kM24" + }, + { + "balance": 10, + "name": "1000985", + "owner_address": "TRH5jmPx77UnMvfdvfo2m3FCkZVcBiFvqP" + }, + { + "balance": 10000000, + "name": "1002962", + "owner_address": "TFDwGwod9qopreRiirsFMwPzX4v2r662P4" + }, + { + "balance": 10000000, + "name": "1002918", + "owner_address": "TKGpTks1myPrJ9ZtEdLgpjvg1RMR2wGAFz" + }, + { + "balance": 1000, + "name": "1002608", + "owner_address": "TDPsSgBQznKEffdTMq3aspsvrmFfhL7ZcP" + }, + { + "balance": 10000000, + "name": "1002999", + "owner_address": "TTL52uBzTG7qorL7BQYdjGUY3HWWr9Kvao" + }, + { + "balance": 100000000000, + "name": "1003022", + "owner_address": "TAAJiJ1NgkEkE3w1PQk4dA8XH9rpfk5eVE" + }, + { + "balance": 1000000000, + "name": "1003041", + "owner_address": "TQADZoww5HstdsJM1GXwstqsRRnmrkThzY" + }, + { + "balance": 10000000, + "name": "1003049", + "owner_address": "THFJwSN5Z3zTc5TvkSiVh8m4kQMZaTMaqk" + }, + { + "balance": 1, + "name": "1002939", + "owner_address": "TAsSw8hUddYi8AN8EkDuAMS9r8pkriyUxs" + } + ], + "balance": 346976329314696, + "voteTotal": 0, + "name": "", + "delegated": { + "sentDelegatedBandwidth": [], + "sentDelegatedResource": [], + "receivedDelegatedResource": [], + "receivedDelegatedBandwidth": [] + }, + "totalTransactionCount": 508552, + "representative": { + "lastWithDrawTime": 0, + "allowance": 0, + "enabled": false, + "url": "" + }, + "activePermissions": [] +} diff --git a/platform/tron/mocks/tokens/txs_empty_response.json b/platform/tron/mocks/tokens/txs_empty_response.json new file mode 100644 index 000000000..f9b0e1de5 --- /dev/null +++ b/platform/tron/mocks/tokens/txs_empty_response.json @@ -0,0 +1,12 @@ +{ + "success": true, + "meta": { + "at": 1592757318961, + "page_size": 20, + "fingerprint": "AYa6eBNpCs5E2DnumiJJJWJ3n2PYMBRFvU7BLjXD49Jm779DJ1C1hUgjwJAmQx5Y2BnkStKMjzQvcALKeQJYfW51m6sY7YEWW", + "links": { + "next": "https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R/transactions?fingerprint=AYa6eBNpCs5E2DnumiJJJWJ3n2PYMBRFvU7BLjXD49Jm779DJ1C1hUgjwJAmQx5Y2BnkStKMjzQvcALKeQJYfW51m6sY7YEWW" + } + }, + "data": [] +} diff --git a/platform/tron/mocks/tokens/txs_trc20_response.json b/platform/tron/mocks/tokens/txs_trc20_response.json new file mode 100644 index 000000000..3655b74d2 --- /dev/null +++ b/platform/tron/mocks/tokens/txs_trc20_response.json @@ -0,0 +1,295 @@ +{ + "success": true, + "meta": { + "at": 1592757126588, + "page_size": 20, + "fingerprint": "2tmLC90HQEnpnJ02w3n", + "links": { + "next": "https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D/transactions/trc20?fingerprint=2tmLC90HQEnpnJ02w3n" + } + }, + "data": [ + { + "block_timestamp": 1592757117000, + "value": "500000000", + "type": "Transfer", + "transaction_id": "fb078403adfee637608c3906d9d21dd158611aba149b9993f43d0f292ce543a0", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A", + "token_info": { + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6 + }, + "_unconfirmed": true + }, + { + "block_timestamp": 1592757066000, + "value": "50000000", + "type": "Transfer", + "transaction_id": "c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022", + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd", + "token_info": { + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6 + }, + "_unconfirmed": true + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd", + "block_timestamp": 1592757066000, + "value": "50000000", + "type": "Transfer", + "transaction_id": "c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV", + "block_timestamp": 1592756784000, + "value": "3988000000", + "type": "Transfer", + "transaction_id": "0b52a4ef9fb8c13fbfae2b8c3506333ec1d718f307062a15f170562818a01d0a", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am", + "block_timestamp": 1592756763000, + "value": "640990000", + "type": "Transfer", + "transaction_id": "19d2ec6174bf64beb1061475f6429cba03b64944a763686cc3551447d0e8d9d5", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "block_timestamp": 1592756631000, + "value": "1062000000", + "type": "Transfer", + "transaction_id": "efb7d44305759cfb189c9fd22720609a2ddeb7fbd7c8afe1dd8851342471da8d", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A", + "block_timestamp": 1592756610000, + "value": "2000000", + "type": "Transfer", + "transaction_id": "48bd90dc3f12086178e65b9389caa8b3c74683937b86d4d61cdec77f0095994a", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R", + "block_timestamp": 1592756589000, + "value": "1000000000", + "type": "Transfer", + "transaction_id": "afd5ae7e2462c9cc899c7f730b90fd2a5e4c1315e836c92468b504ed85f0b798", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq", + "block_timestamp": 1592756583000, + "value": "21200000", + "type": "Transfer", + "transaction_id": "3d613031f4b2a0e19deeea030d1d18599b6d9799d2dd530005ead9712c6d219d", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5", + "block_timestamp": 1592756583000, + "value": "125000000", + "type": "Transfer", + "transaction_id": "cbe359c2574efbdc8fc6a892ffc54812837295067c9816d41734126c82d0c141", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC", + "block_timestamp": 1592756583000, + "value": "5277600000", + "type": "Transfer", + "transaction_id": "c87248b02a4caaa6f443c1b8c4d4588c8dd281a4687b73e6afecfba6741b50d8", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W", + "block_timestamp": 1592756583000, + "value": "485342000", + "type": "Transfer", + "transaction_id": "8584f1b6a70ead8232fed19bd653ba13e4c2a8befd070f4a9a06eca3a2e3e548", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr", + "block_timestamp": 1592756583000, + "value": "1000000000", + "type": "Transfer", + "transaction_id": "2b28b69e6747db68647acc3a62c45da5355b97acd8d2c260ee752aa9bd63a624", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x", + "block_timestamp": 1592756583000, + "value": "2000000000", + "type": "Transfer", + "transaction_id": "1da6576dec0bd303f56cbfb5712f782e0a56a8713cb661f8afd2f2533e5c6209", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK", + "block_timestamp": 1592756583000, + "value": "24216600000", + "type": "Transfer", + "transaction_id": "f9c86cce1873cb816d6cd8718e76df8839172add293bbc8d11a5f98c80f9e322", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "block_timestamp": 1592756541000, + "value": "8241997837", + "type": "Transfer", + "transaction_id": "75eb35734857daa79c38ef923a7e7eb2e3dfb23d2722762fd2b180651021643f", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "block_timestamp": 1592756220000, + "value": "18000000000", + "type": "Transfer", + "transaction_id": "adee73dadce006ff848ff30d8c5c41f033be2e5e1a8b875f6dbbaab524177d08", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "block_timestamp": 1592755962000, + "value": "863399098", + "type": "Transfer", + "transaction_id": "3655a1156c9adcb876c6c9c9e0f5f1f39704ac4c7296fea05fedf5ca8f6b1a19", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ", + "block_timestamp": 1592755740000, + "value": "20000000", + "type": "Transfer", + "transaction_id": "03574741eb0016050a19f181e4acc4b20b70f41e11e63140c9556c31eae09fba", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + }, + { + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D", + "to": "TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug", + "block_timestamp": 1592755722000, + "value": "21161340000", + "type": "Transfer", + "transaction_id": "f3aa00595996e31dbe9528a3cb21bff987f333bf1f675420ba4fa2ad43c8205f", + "token_info": { + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" + } + } + ] +} diff --git a/platform/tron/mocks/transfer.json b/platform/tron/mocks/transfer.json new file mode 100644 index 000000000..44bade683 --- /dev/null +++ b/platform/tron/mocks/transfer.json @@ -0,0 +1,18 @@ +{ + "block_timestamp": 1564797900000, + "raw_data": { + "contract": [ + { + "parameter": { + "value": { + "amount": 100666888000000, + "owner_address": "4182dd6b9966724ae2fdc79b416c7588da67ff1b35", + "to_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261" + } + }, + "type": "TransferContract" + } + ] + }, + "txID": "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df" +} diff --git a/platform/tron/mocks/txs_response.json b/platform/tron/mocks/txs_response.json new file mode 100644 index 000000000..1de56a7e2 --- /dev/null +++ b/platform/tron/mocks/txs_response.json @@ -0,0 +1,100 @@ +[ + { + "id": "3fca53c08ccb48bb625439a58998713d8ecc3dc1348cc3cfab912e0815b62b1a", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R", + "to": "TVmkAmaQrY6raatYozLtcQCGqWP6VaPnHU", + "fee": "0", + "date": 1592755098, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "transfer", + "memo": "", + "metadata": { "value": "13195916000", "symbol": "TRX", "decimals": 6 } + }, + { + "id": "b38fb6328e1fa622b7762eed856778551845c33723491e36baf357f00cc48002", + "coin": 195, + "from": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R", + "to": "TDfVk6U7i6m82ZCRprbrfz7QE3sTEnN1Xs", + "fee": "0", + "date": 1592754717, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "transfer", + "memo": "", + "metadata": { "value": "8737000000", "symbol": "TRX", "decimals": 6 } + }, + { + "id": "82efc8456a3c38a0919af416a53363405ced78db7c13e1b94a79ebcea98f9909", + "coin": 195, + "from": "TVqx5Dx54HgBQFfpN7KN4MWiHEnRXbch7a", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R", + "fee": "0", + "date": 1592754447, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "transfer", + "memo": "", + "metadata": { "value": "2538461", "symbol": "TRX", "decimals": 6 } + }, + { + "id": "a336bd174c127d38bf2325bc9c927059af099e8cfb91159750a1b1be16dd0bd4", + "coin": 195, + "from": "TYCwQ4bC1mHR6heAe1qgHrktFtyJ8mKkC3", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R", + "fee": "0", + "date": 1592754444, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "transfer", + "memo": "", + "metadata": { "value": "30000000", "symbol": "TRX", "decimals": 6 } + }, + { + "id": "007bbcc3855f4bf51bd76e63d7776160c115c803e227f7c44c7d1fd1bd587611", + "coin": 195, + "from": "TSUCQKEKhXREEaod5WgSKETKjYUhL2TUV7", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R", + "fee": "0", + "date": 1592754444, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "transfer", + "memo": "", + "metadata": { "value": "111337320", "symbol": "TRX", "decimals": 6 } + }, + { + "id": "9351e87b129142844f000a52911daf36fc95677dfe2846abcd28ea0d8fe2e2ea", + "coin": 195, + "from": "TFUP7BdBj61oyTHt52McZC5Q1w6CKzyNCN", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R", + "fee": "0", + "date": 1592754444, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "transfer", + "memo": "", + "metadata": { "value": "200000000", "symbol": "TRX", "decimals": 6 } + }, + { + "id": "008ebda5749c38e26a69717faa66e6f4fd8a0d358c9b947192765cc9843cff5a", + "coin": 195, + "from": "TGkLtfPuPhkG4RzewwkgNHfPxTwb5YRq6b", + "to": "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R", + "fee": "0", + "date": 1592754444, + "block": 0, + "status": "completed", + "sequence": 0, + "type": "transfer", + "memo": "", + "metadata": { "value": "511000000", "symbol": "TRX", "decimals": 6 } + } +] diff --git a/platform/tron/stake_test.go b/platform/tron/stake_test.go index 3a89a0984..ef041700c 100644 --- a/platform/tron/stake_test.go +++ b/platform/tron/stake_test.go @@ -6,129 +6,92 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/mock" ) -func TestNormalizeValidator(t *testing.T) { - validator := Validator{Address: "414d1ef8673f916debb7e2515a8f3ecaf2611034aa"} +var ( + delegationsSrc1, _ = mock.JsonFromFilePathToString("mocks/" + "delegation.json") + delegationsSrc2, _ = mock.JsonFromFilePathToString("mocks/" + "delegation_2.json") - actual, _ := normalizeValidator(validator) - expected := blockatlas.Validator{ + validator1 = blockatlas.StakeValidator{ ID: "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp", Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "Sesameseed", + Description: "Sesameseed is a blockchain community providing fair and transparent representation in delegated governance by rewarding Voters for their participation on Tron and Ontology.", + Image: "https://assets.trustwalletapp.com/blockchains/tron/validators/assets/tgzz8gjyiyrqpfmdwnlxfgpulvnmpcswvp/logo.png", + Website: "https://www.sesameseed.org", + }, Details: blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{ - Annual: Annual, + Annual: 4.32, }, LockTime: 259200, MinimumAmount: "1000000", - Type: blockatlas.DelegationTypeDelegate, }, } - assert.Equal(t, expected, actual) -} -const delegationsSrc1 = ` -{ - "address": "419241920da7d6bb487a33a6df3838e3d208f0b251", - "frozen": [ - { - "expire_time": 10437262001000, - "frozen_balance": "35000000" - } - ], - "votes": [ - { - "vote_address": "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp", - "vote_count": 21 - }, - { - "vote_address": "TPMGfspxLQGom8sKutrbHcDKtHjRHFbGKw", - "vote_count": 5 - }, - { - "vote_address": "TPMGfspxLQGom8sKutrbHcDKtHjRHFbGKw", - "vote_count": 5 + validator2 = blockatlas.StakeValidator{ + ID: "TPMGfspxLQGom8sKutrbHcDKtHjRHFbGKw", + Status: true, + Info: blockatlas.StakeValidatorInfo{ + Name: "InfStones", + Description: "World's leading cloud infrastructure and staking as a service provicer for blockchains. Supernodes on EOS, TRON, VeChain, Ontology, LOOM, IOST and many other chains.", + Image: "https://assets.trustwalletapp.com/blockchains/tron/validators/assets/tpmgfspxlqgom8skutrbhcdkthjrhfbgkw/logo.png", + Website: "https://infstones.io/", + }, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: 4.32, + }, + LockTime: 259200, + MinimumAmount: "1000000", + }, } - ] -}` -const delegationsSrc2 = ` -{ - "address": "419241920da7d6bb487a33a6df3838e3d208f0b251", - "frozen": [ - { - "expire_time": 1569465251000, - "frozen_balance": "5000000" + delegation1 = blockatlas.Delegation{ + Delegator: validator1, + Value: "21000000", + Status: blockatlas.DelegationStatusPending, } - ], - "votes": [ - { - "vote_address": "TPMGfspxLQGom8sKutrbHcDKtHjRHFbGKw", - "vote_count": 5 + delegation2 = blockatlas.Delegation{ + Delegator: validator2, + Value: "5000000", + Status: blockatlas.DelegationStatusPending, } - ] -}` + delegation3 = blockatlas.Delegation{ + Delegator: validator2, + Value: "5000000", + Status: blockatlas.DelegationStatusPending, + } + delegation4 = blockatlas.Delegation{ + Delegator: validator2, + Value: "5000000", + Status: blockatlas.DelegationStatusActive, + } + validatorMap = blockatlas.ValidatorMap{ + "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp": validator1, + "TPMGfspxLQGom8sKutrbHcDKtHjRHFbGKw": validator2, + } +) -var validator1 = blockatlas.StakeValidator{ - ID: "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp", - Status: true, - Info: blockatlas.StakeValidatorInfo{ - Name: "Sesameseed", - Description: "Sesameseed is a blockchain community providing fair and transparent representation in delegated governance by rewarding Voters for their participation on Tron and Ontology.", - Image: "https://assets.trustwalletapp.com/blockchains/tron/validators/assets/tgzz8gjyiyrqpfmdwnlxfgpulvnmpcswvp/logo.png", - Website: "https://www.sesameseed.org", - }, - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{ - Annual: 4.32, - }, - LockTime: 259200, - MinimumAmount: "1000000", - }, -} +func TestNormalizeValidator(t *testing.T) { + validator := Validator{Address: "414d1ef8673f916debb7e2515a8f3ecaf2611034aa"} -var validator2 = blockatlas.StakeValidator{ - ID: "TPMGfspxLQGom8sKutrbHcDKtHjRHFbGKw", - Status: true, - Info: blockatlas.StakeValidatorInfo{ - Name: "InfStones", - Description: "World's leading cloud infrastructure and staking as a service provicer for blockchains. Supernodes on EOS, TRON, VeChain, Ontology, LOOM, IOST and many other chains.", - Image: "https://assets.trustwalletapp.com/blockchains/tron/validators/assets/tpmgfspxlqgom8skutrbhcdkthjrhfbgkw/logo.png", - Website: "https://infstones.io/", - }, - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{ - Annual: 4.32, + actual, _ := normalizeValidator(validator) + expected := blockatlas.Validator{ + ID: "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp", + Status: true, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{ + Annual: Annual, + }, + LockTime: 259200, + MinimumAmount: "1000000", + Type: blockatlas.DelegationTypeDelegate, }, - LockTime: 259200, - MinimumAmount: "1000000", - }, -} - -var delegation1 = blockatlas.Delegation{ - Delegator: validator1, - Value: "21000000", - Status: blockatlas.DelegationStatusPending, -} -var delegation2 = blockatlas.Delegation{ - Delegator: validator2, - Value: "5000000", - Status: blockatlas.DelegationStatusPending, -} -var delegation3 = blockatlas.Delegation{ - Delegator: validator2, - Value: "5000000", - Status: blockatlas.DelegationStatusPending, -} -var delegation4 = blockatlas.Delegation{ - Delegator: validator2, - Value: "5000000", - Status: blockatlas.DelegationStatusActive, -} - -var validatorMap = blockatlas.ValidatorMap{ - "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp": validator1, - "TPMGfspxLQGom8sKutrbHcDKtHjRHFbGKw": validator2, + } + assert.Equal(t, expected, actual) } func TestNormalizeDelegations(t *testing.T) { diff --git a/platform/tron/token_test.go b/platform/tron/token_test.go index 919eed210..7ebae9726 100644 --- a/platform/tron/token_test.go +++ b/platform/tron/token_test.go @@ -10,16 +10,19 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/mock" ) -var tokenDst = blockatlas.Token{ - Name: "Test", - Symbol: "TST", - Decimals: 8, - TokenID: "1", - Coin: 195, - Type: "TRC10", -} +var ( + tokenDst = blockatlas.Token{ + Name: "Test", + Symbol: "TST", + Decimals: 8, + TokenID: "1", + Coin: 195, + Type: "TRC10", + } +) func TestNormalizeToken(t *testing.T) { asset := AssetInfo{Name: "Test", Symbol: "TST", ID: 1, Decimals: 8} @@ -39,9 +42,21 @@ func TestPlatform_GetTokenListByAddress(t *testing.T) { }) rawRes, err := json.Marshal(res) assert.Nil(t, err) - assert.Equal(t, wantedTokensResponse, string(rawRes)) + assert.JSONEq(t, wantedTokensResponse, string(rawRes)) } +var ( + wantedTokensResponse, _ = mock.JsonFromFilePathToString("mocks/tokens/tokens_response.json") + mockedAccountsTransactionsResponse, _ = mock.JsonFromFilePathToString("mocks/tokens/accounts_txs_response.json") + mockedTrc20Response, _ = mock.JsonFromFilePathToString("mocks/tokens/trc20_response.json") + mockedTransactionsTrc20Response, _ = mock.JsonFromFilePathToString("mocks/tokens/txs_trc20_response.json") + mockedTransactionsEmptyResponse, _ = mock.JsonFromFilePathToString("mocks/tokens/txs_empty_response.json") + mockedAsset1000542Response, _ = mock.JsonFromFilePathToString("mocks/tokens/asset_1000542_response.json") + mockedAsset1000567Response, _ = mock.JsonFromFilePathToString("mocks/tokens/asset_1000567_response.json") + mockedAssetTR7NHResponse, _ = mock.JsonFromFilePathToString("mocks/tokens/asset_tr7nh_response.json") + mockedAccountsResponse, _ = mock.JsonFromFilePathToString("mocks/tokens/accounts_response.json") +) + func createMockedAPI() http.Handler { r := http.NewServeMux() @@ -67,7 +82,7 @@ func createMockedAPI() http.Handler { }) r.HandleFunc("/v1/assets/TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - if _, err := fmt.Fprint(w, mockedAssetTR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6tResponse); err != nil { + if _, err := fmt.Fprint(w, mockedAssetTR7NHResponse); err != nil { panic(err) } }) @@ -101,15 +116,3 @@ func createMockedAPI() http.Handler { return r } - -var ( - wantedTokensResponse = `[{"name":"FomoThreeD","symbol":"FOM","decimals":0,"token_id":"1000542","coin":195,"type":"TRC10"},{"name":"OtonamiS","symbol":"OS","decimals":0,"token_id":"1000567","coin":195,"type":"TRC10"},{"name":"JUST GOV","symbol":"JST","decimals":18,"token_id":"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9","coin":195,"type":"TRC20"},{"name":"Enme Token","symbol":"EME","decimals":6,"token_id":"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF","coin":195,"type":"TRC20"},{"name":"BeeHive","symbol":"BEE","decimals":8,"token_id":"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK","coin":195,"type":"TRC20"},{"name":"Mono Token","symbol":"MONO","decimals":18,"token_id":"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak","coin":195,"type":"TRC20"},{"name":"WINK","symbol":"WIN","decimals":6,"token_id":"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7","coin":195,"type":"TRC20"},{"name":"PYRO Network","symbol":"PYRO","decimals":6,"token_id":"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e","coin":195,"type":"TRC20"},{"name":"NoleCoin","symbol":"NOLE","decimals":6,"token_id":"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG","coin":195,"type":"TRC20"},{"name":"Tether USD","symbol":"USDT","decimals":6,"token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","coin":195,"type":"TRC20"},{"name":"Wuhan Fried Bats","symbol":"WUHAN","decimals":4,"token_id":"TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr","coin":195,"type":"TRC20"},{"name":"HelGro","symbol":"HGRO","decimals":6,"token_id":"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm","coin":195,"type":"TRC20"}]` - mockedAccountsTransactionsResponse = `{"success":true,"meta":{"at":1592755486554,"page_size":25,"fingerprint":"4CwRecxbH99eRRkU2FFkGRCvoQGwphNyRcTTiM1GfUrkoQ1fG9Kcc8ADZo7pSCYXja28JWKUACy2Xt6UG1Fa5tSZh5dqpUEuTi1W","links":{"next":"https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R/transactions?limit=25&order_by=block_timestamp%2Cdesc&token_id=&fingerprint=4CwRecxbH99eRRkU2FFkGRCvoQGwphNyRcTTiM1GfUrkoQ1fG9Kcc8ADZo7pSCYXja28JWKUACy2Xt6UG1Fa5tSZh5dqpUEuTi1W"}},"data":[{"blockNumber":20829763,"block_timestamp":1592755239000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000413b334848f75cf8c27ec975bcc7cc7e54f140b3c000000000000000000000000000000000000000000000000000000000cd0e33a0","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758890000,"fee_limit":1000000000,"ref_block_bytes":"d62e","ref_block_hash":"bbf7d06ee7004d5a","timestamp":1592755233594},"raw_data_hex":"0a02d62e2208bbf7d06ee7004d5a4090dccfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413b334848f75cf8c27ec975bcc7cc7e54f140b3c000000000000000000000000000000000000000000000000000000000cd0e33a070bac6f0bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["c9a405be8b12f92747cc0f0d979606807a03edcefd154bcf517ce26f8bf681400d6cdacda11c98e7ae61d51905f7113658a786d6022b97e025f5a7e99b53845d01"],"txID":"18f5908a7e208e16bfb892a5b06df75675d3142d03a0d99d270ac46143b78d06"},{"blockNumber":20829760,"block_timestamp":1592755230000,"energy_fee":146310,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb00000000000000000000004158a82464024027b8e81bd1997cc7ba8f26a01314000000000000000000000000000000000000000000000000000000001dce7a58","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758881000,"fee_limit":1000000000,"ref_block_bytes":"d62b","ref_block_hash":"38ebe631e633b827","timestamp":1592755223352},"raw_data_hex":"0a02d62b220838ebe631e633b82740e895cfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb00000000000000000000004158a82464024027b8e81bd1997cc7ba8f26a01314000000000000000000000000000000000000000000000000000000001dce7a5870b8f6efbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":149770}],"signature":["39ee8b2e7ab589538f3a976644399ba60667ede4d9611229298d52f5aeb01a6624e2346703d8a19edc9f457b89a0dbb800ae87d049ad3a7d72353fde77635f1a00"],"txID":"2a9eda92b9a2a0e56d29000ad24daae7d577c5db44d2b737f6a35584cd81b5e0"},{"blockNumber":20829760,"block_timestamp":1592755230000,"energy_fee":119110,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac84000000000000000000000000000000000000000000000000000000037e11d600","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758881000,"fee_limit":1000000000,"ref_block_bytes":"d62b","ref_block_hash":"38ebe631e633b827","timestamp":1592755223053},"raw_data_hex":"0a02d62b220838ebe631e633b82740e895cfbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac84000000000000000000000000000000000000000000000000000000037e11d600708df4efbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":122570}],"signature":["710a4b8543a9f605acc809ebe5b8a3a3b4681ebf2123fcdda39187bde86c9bc839cf6d882d9d15052b94ed6bba6474f9fdf09e73afefe40f6bad909029cadd2500"],"txID":"c838b8a683d39c6f1a8a173e6fffc5cc9122acc690f5e35fa7c1935cc5eae540"},{"blockNumber":20829742,"block_timestamp":1592755176000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041c80ab7aac02a3d4b3d89ee781cddce55286bcf2d000000000000000000000000000000000000000000000000000000000bebc200","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758830000,"fee_limit":1000000000,"ref_block_bytes":"d61a","ref_block_hash":"b1015d64daa873a3","timestamp":1592755172703},"raw_data_hex":"0a02d61a2208b1015d64daa873a340b087ccbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041c80ab7aac02a3d4b3d89ee781cddce55286bcf2d000000000000000000000000000000000000000000000000000000000bebc20070dfeaecbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["a7583c4e402eff463b083de5cfcbaadc46ed8601e2346f20d01eb0ec7a6824d869be27371f8c0e5a38a708df724be60a818b9647757bdde73ed743ff9324115c01"],"txID":"ad631a0e55bd2bb64747bf388dc92084c32506843c19a0a2b69234b4d4e56a6b"},{"blockNumber":20829732,"block_timestamp":1592755146000,"energy_fee":231500,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000410d4fd52433f30edd0b512f59fa021527bbd7de610000000000000000000000000000000000000000000000000000000001c9c380","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758800000,"fee_limit":1000000000,"ref_block_bytes":"d610","ref_block_hash":"2a14293035535e85","timestamp":1592755142312},"raw_data_hex":"0a02d61022082a14293035535e8540809dcabead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000410d4fd52433f30edd0b512f59fa021527bbd7de610000000000000000000000000000000000000000000000000000000001c9c38070a8fdeabcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":234960}],"signature":["3095c2130ee5d4da72246a17098b587c25108e1c1884f9128911e079997dd25c45e0b0acfc99e3ee4367c4670e2117dd24884c32ae0ea15ec9f9368910e4c42801"],"txID":"f1920eefa4de8370bc349fbd6ca73e24d9000d9d8fe5c71260a2902d3b49b02a"},{"blockNumber":20829718,"block_timestamp":1592755104000,"energy_fee":166720,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb00000000000000000000004135c4d4a5544d25a2f25a7cda73d57c45a36578bc0000000000000000000000000000000000000000000000000000000010089d40","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758761000,"fee_limit":1000000000,"ref_block_bytes":"d603","ref_block_hash":"f84579e34d118430","timestamp":1592755101713},"raw_data_hex":"0a02d6032208f84579e34d11843040a8ecc7bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb00000000000000000000004135c4d4a5544d25a2f25a7cda73d57c45a36578bc0000000000000000000000000000000000000000000000000000000010089d407091c0e8bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170180}],"signature":["816b2747c6c1f6be139d233118b4b1e3c3942d62f56d1b0c8a496851ea233c5c1b6e0e0a13e22c3a4c1bd106eb6c0e987d5c84f9fcc29ee7b86bd4d1874ade9601"],"txID":"cec1061166e4924123356b8066872b641956691d1b1f11a12f293c54e7178362"},{"blockNumber":20829716,"block_timestamp":1592755098000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":2690,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":13195916000,"owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874","to_address":"41d9378a9849912a41ec1f0e4677c074edf0516241"}},"type":"TransferContract"}],"expiration":1592758749000,"fee_limit":0,"ref_block_bytes":"d5ff","ref_block_hash":"c753125289c79c7c","timestamp":1592755089996},"raw_data_hex":"0a02d5ff2208c753125289c79c7c40c88ec7bead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a154179309abcff2cf531070ca9222a1f72c4a5136874121541d9378a9849912a41ec1f0e4677c074edf051624118e0e5a6943170cce4e7bcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":2690}],"signature":["bae63e4214b0ab611079beabca020c82fbcada902f1f0c13106e7c4ba463efb25610d13b00b28cd19b54f648b88a4b05a08583b44b4f4179c2c605b42b22ad4b00"],"txID":"3fca53c08ccb48bb625439a58998713d8ecc3dc1348cc3cfab912e0815b62b1a"},{"blockNumber":20829708,"block_timestamp":1592755074000,"energy_fee":146310,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005fc2678","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758719000,"fee_limit":1000000000,"ref_block_bytes":"d5f5","ref_block_hash":"84843b5d1de30802","timestamp":1592755061404},"raw_data_hex":"0a02d5f5220884843b5d1de308024098a4c5bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005fc2678709c85e6bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":149770}],"signature":["6dd6709cee109df62c3a7f196f45d3efa16c25738c1c4ea371cce18443016c8911a2d65fd4f2d7b4932aed34634169adc981db081522b094e63d9528882b3de801"],"txID":"8e886732999efe30e0d7c93eee40c41f058f33c82194141317768810a5a84b82"},{"blockNumber":20829681,"block_timestamp":1592754993000,"energy_fee":231500,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005e5eb10","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758638000,"fee_limit":1000000000,"ref_block_bytes":"d5da","ref_block_hash":"3234615516f16ee9","timestamp":1592754980996},"raw_data_hex":"0a02d5da22083234615516f16ee940b0abc0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd61209cd00224690ace233bb7257b054a49015a0000000000000000000000000000000000000000000000000000000005e5eb10708491e1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":234960}],"signature":["896243c9d9c8ba595deafb81b7c4fc283271e0f46aa7031f270d91a383ce997a09f4a3aa6fb0478a7dac9b7df295dcf232f8bf4941583848f45bd8e258f9482e01"],"txID":"8b7c9f9f29cbf9ced22761f918d19471b3bb638438e6cc23e8104fed7dda1ef3"},{"blockNumber":20829627,"block_timestamp":1592754831000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":2850,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferAssetContract","value":{"amount":7639170000000,"asset_name":"1002000","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874","to_address":"410a60e164aa897ef76779164dff6e36161980c6fb"}},"type":"TransferAssetContract"}],"expiration":1592758479000,"fee_limit":0,"ref_block_bytes":"d5a5","ref_block_hash":"462e1cfdbe99a85b","timestamp":1592754820511},"raw_data_hex":"0a02d5a52208462e1cfdbe99a85b4098d1b6bead2e5a79080212750a32747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e736665724173736574436f6e7472616374123f0a073130303230303012154179309abcff2cf531070ca9222a1f72c4a51368741a15410a60e164aa897ef76779164dff6e36161980c6fb2080c98e90aade01709fabd7bcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":2850}],"signature":["b49c878a8e85339fc4917e7f20625b38b941871c86572d2c01322ec26575c7024c34b498e464109a03f8e42df24cc0868910a0e7b1f7c174f5005a483a93dac600"],"txID":"79010512f8e58574cbd066d1a1bd1c7f46f65e59e3b7733010047ff8350f15f1"},{"blockNumber":20829617,"block_timestamp":1592754801000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000412b764790f38a7373d56dfdf4f866fa027e28c8af0000000000000000000000000000000000000000000000000000000071006010","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758449000,"fee_limit":1000000000,"ref_block_bytes":"d59b","ref_block_hash":"beab372f7f7d493b","timestamp":1592754790236},"raw_data_hex":"0a02d59b2208beab372f7f7d493b40e8e6b4bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000412b764790f38a7373d56dfdf4f866fa027e28c8af000000000000000000000000000000000000000000000000000000007100601070dcbed5bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["52b662780f176048c4fd9e8db15756d0ef397cb60a8be6ea3421993ec2c6e1636d9aaf8a596f9255c182284e1efbd5410e2a11d10b82b4e4fec5a43ffea357cc01"],"txID":"809ec9beb99cf756bb02155199a35b766f3ec18dd6bea6b3d69dd38f6b51138f"},{"blockNumber":20829617,"block_timestamp":1592754801000,"energy_fee":166700,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041d8692da59c130875e13587a82bc93b917c49526a0000000000000000000000000000000000000000000000000000000054c92b70","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758449000,"fee_limit":1000000000,"ref_block_bytes":"d59b","ref_block_hash":"beab372f7f7d493b","timestamp":1592754789857},"raw_data_hex":"0a02d59b2208beab372f7f7d493b40e8e6b4bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041d8692da59c130875e13587a82bc93b917c49526a0000000000000000000000000000000000000000000000000000000054c92b7070e1bbd5bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170160}],"signature":["fe96d2be46a37f89531d10cdca823ec82c603a3bb9f858aa76db20468e8d9d6058de643460e11b50e0982fa6ab6b81439cee6c9286b5d6bb7c18206e2ab066fb01"],"txID":"bc0c429e33d3c668e5e5a55831efb3aba7e917c52cd3892aeb252f1a7b2ddb41"},{"blockNumber":20829596,"block_timestamp":1592754738000,"energy_fee":166700,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041ec853dc8fe0dab78d3234ba356ebae7984da322c00000000000000000000000000000000000000000000000000000004a817c800","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758386000,"fee_limit":1000000000,"ref_block_bytes":"d586","ref_block_hash":"4007c65312ba945c","timestamp":1592754729408},"raw_data_hex":"0a02d58622084007c65312ba945c40d0fab0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041ec853dc8fe0dab78d3234ba356ebae7984da322c00000000000000000000000000000000000000000000000000000004a817c80070c0e3d1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170160}],"signature":["93119466b23346e095d256537f2bf8c639dd157f896eaaff972f0be83663bca34a21df4e25fa61ba071588a58f98874a58705844a8cc36a321bf30e722028c8201"],"txID":"3bcd581a833abb16529e1f5187615866ba72f2e61c590c993f5b461ba5073d45"},{"blockNumber":20829592,"block_timestamp":1592754726000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac8400000000000000000000000000000000000000000000000000000000001e8480","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758377000,"fee_limit":1000000000,"ref_block_bytes":"d583","ref_block_hash":"0bc07e9ae4eb32b0","timestamp":1592754719032},"raw_data_hex":"0a02d58322080bc07e9ae4eb32b040a8b4b0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000413c51c36069e0a1fdf3278907ecd5a05e90a3ac8400000000000000000000000000000000000000000000000000000000001e848070b892d1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["80fe656c430afb348327f279a2d454d277bf64564111e49118ed85f1021528920ba5be044956084f543a087a61aa14b595a4fc2cc6aff2ad2ac5d7533a6b122f01"],"txID":"3baff897a2b39720727549216ea6f4bc580eed2f239967e158e9e7ea74146822"},{"blockNumber":20829589,"block_timestamp":1592754717000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":2690,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":8737000000,"owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874","to_address":"412886fdc89587dbe8a57d0b9589581bd084384d5f"}},"type":"TransferContract"}],"expiration":1592758368000,"fee_limit":0,"ref_block_bytes":"d580","ref_block_hash":"ebf8d3b3837d87a8","timestamp":1592754708731},"raw_data_hex":"0a02d5802208ebf8d3b3837d87a84080eeafbead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a154179309abcff2cf531070ca9222a1f72c4a51368741215412886fdc89587dbe8a57d0b9589581bd084384d5f18c09490c62070fbc1d0bcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":2690}],"signature":["b92bdde424aee97b4e7a63716056daa963afce89701bf6d8c8b1b6221f65afb94b8ff3865650aff83d590cad87359ae5f272ed732738093a0a9aa587cc3503aa01"],"txID":"b38fb6328e1fa622b7762eed856778551845c33723491e36baf357f00cc48002"},{"blockNumber":20829585,"block_timestamp":1592754705000,"energy_fee":43900,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000416128e41b6aa8c531b05999c2861f846459fb10e60000000000000000000000000000000000000000000000000000000005f5e100","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758356000,"fee_limit":1000000000,"ref_block_bytes":"d57c","ref_block_hash":"c7c6e5795625dc5b","timestamp":1592754698724},"raw_data_hex":"0a02d57c2208c7c6e5795625dc5b40a090afbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000416128e41b6aa8c531b05999c2861f846459fb10e60000000000000000000000000000000000000000000000000000000005f5e10070e4f3cfbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":47360}],"signature":["b90e38665957e47ba8f7731e3b8c943471cd6ef9a95efcd25ad880323f2e397b56927e943c7e605a1996900fe269db6edbc7d7ff094f23393c6546ef0927bae300"],"txID":"d8d53a627fa9f885ad77dcc2f3d3a5eceece36d1ef0f54990dff900484550304"},{"blockNumber":20829577,"block_timestamp":1592754681000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041dd81641cca9a855b7a657153fdda9b3f469693660000000000000000000000000000000000000000000000000000000217a31ba0","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758335000,"fee_limit":1000000000,"ref_block_bytes":"d575","ref_block_hash":"003bba00242a2488","timestamp":1592754678392},"raw_data_hex":"0a02d5752208003bba00242a24884098ecadbead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041dd81641cca9a855b7a657153fdda9b3f469693660000000000000000000000000000000000000000000000000000000217a31ba070f8d4cebcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["0abe6787b18631ae746b4a9c9669e3e878b88c3628a3656e3709b4036b14414525bdb9cdb3c97fce48c9d21f2afab9492a436861e2e85ec1f68bab078859eb1d01"],"txID":"b419c05c877e0176619ec3659470c71822a7840a91a940169eaaf1abb9c38fea"},{"blockNumber":20829564,"block_timestamp":1592754642000,"energy_fee":43900,"energy_usage":0,"energy_usage_total":14631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041a3af64559a63856c625b02e9def8a4dc0f63f38b0000000000000000000000000000000000000000000000000000000010c18918","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758287000,"fee_limit":1000000000,"ref_block_bytes":"d565","ref_block_hash":"afd9deb62b6fa5e0","timestamp":1592754628020},"raw_data_hex":"0a02d5652208afd9deb62b6fa5e04098f5aabead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041a3af64559a63856c625b02e9def8a4dc0f63f38b0000000000000000000000000000000000000000000000000000000010c1891870b4cbcbbcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":47360}],"signature":["070c1a53f2fc6b12825b99c9179899e1effbbdf2fad17d273b64bc47f16ee53a0f56096d4ef6ce58aeee65083dcdef8f3c808d6889a990c23a8d45a84cd69bf101"],"txID":"abb6c40f8f8afcc69fb5b549ffb17bd779fa6588dbbbd5e4ee8568839462b37a"},{"blockNumber":20829535,"block_timestamp":1592754555000,"energy_fee":296310,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb0000000000000000000000410ae0647bbaa1aebafcc9a360d0e22a791a215c930000000000000000000000000000000000000000000000000000000011e1a300","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758206000,"fee_limit":1000000000,"ref_block_bytes":"d54a","ref_block_hash":"d27814b2e9763d5d","timestamp":1592754547598},"raw_data_hex":"0a02d54a2208d27814b2e9763d5d40b0fca5bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000410ae0647bbaa1aebafcc9a360d0e22a791a215c930000000000000000000000000000000000000000000000000000000011e1a300708ed7c6bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":299770}],"signature":["6a0f4d4d5021c46d522f45552b20218ea16c437e6e87130339c90752f63f7a805763699bad3b22fb3199efdce75f1929ac94482be8551107b051ae4b9ef532bb01"],"txID":"7da3a7819e4de9311464963f829e3ceeff0a045bbd587030deba863a04d250db"},{"blockNumber":20829504,"block_timestamp":1592754462000,"energy_fee":166700,"energy_usage":0,"energy_usage_total":29631,"internal_transactions":[],"net_fee":3460,"net_usage":0,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TriggerSmartContract","value":{"call_value":0,"contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c","data":"a9059cbb000000000000000000000041042b5bc43cf6aabae0533f4f671eb810615c32be0000000000000000000000000000000000000000000000000000000054c92b70","owner_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TriggerSmartContract"}],"expiration":1592758116000,"fee_limit":1000000000,"ref_block_bytes":"d52c","ref_block_hash":"9486bdd9554ef09e","timestamp":1592754457197},"raw_data_hex":"0a02d52c22089486bdd9554ef09e40a0bda0bead2e5aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a154179309abcff2cf531070ca9222a1f72c4a5136874121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000041042b5bc43cf6aabae0533f4f671eb810615c32be0000000000000000000000000000000000000000000000000000000054c92b7070ed94c1bcad2e90018094ebdc03","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":170160}],"signature":["2bfe810fa90d3aee965ff990fd68490ce9c8421844c1e792a57faeb556e5c9b004499016ace19afdb49ba65531c2d829890b4c6a14a7e58c6b71bfdacc7709e201"],"txID":"4d5e74b87f782060e0657a48898626a51a1bf2dcccfc2083955fa4f43e4516b0"},{"blockNumber":20829499,"block_timestamp":1592754447000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":2538461,"owner_address":"41da03247c21301eaf0538c1b9f79e5c8ea7cbb386","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758089000,"fee_limit":0,"ref_block_bytes":"d523","ref_block_hash":"dc512cab1e07f960","timestamp":1592754430099},"raw_data_hex":"0a02d5232208dc512cab1e07f96040a8ea9ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541da03247c21301eaf0538c1b9f79e5c8ea7cbb38612154179309abcff2cf531070ca9222a1f72c4a513687418ddf79a017093c1bfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["0b542abf1657965deeb06123636f6e4ccaea5f4ab0a14f81f3164b286cb6ede37c62d701c796ae86cbd5c908009e5ac6db73d4532a9976ce5b30df47460957d601"],"txID":"82efc8456a3c38a0919af416a53363405ced78db7c13e1b94a79ebcea98f9909"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":30000000,"owner_address":"41f3eb90cf03d6301e1d10b6095113494bc704992c","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758089000,"fee_limit":0,"ref_block_bytes":"d523","ref_block_hash":"dc512cab1e07f960","timestamp":1592754429791},"raw_data_hex":"0a02d5232208dc512cab1e07f96040a8ea9ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541f3eb90cf03d6301e1d10b6095113494bc704992c12154179309abcff2cf531070ca9222a1f72c4a5136874188087a70e70dfbebfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["d44a181a6ff560bbcd8a89f9b14247f3d3c781020404eb6462926f3e60dfe32c38ee17f0e752346229de30db033352240152891a168285581558f80af90f83fd00"],"txID":"a336bd174c127d38bf2325bc9c927059af099e8cfb91159750a1b1be16dd0bd4"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":111337320,"owner_address":"41b4fd934c73429b27c1e9180e04ccfc44c14f15a9","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758086000,"fee_limit":0,"ref_block_bytes":"d522","ref_block_hash":"9ecd3926187cf28e","timestamp":1592754429463},"raw_data_hex":"0a02d52222089ecd3926187cf28e40f0d29ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a1541b4fd934c73429b27c1e9180e04ccfc44c14f15a912154179309abcff2cf531070ca9222a1f72c4a513687418e8be8b357097bcbfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["a40ce5f8ab4d9283fd9982eb38aa2a8b8ad9aeaa9bfc8acc220673a367fd420c034f89110e74a99745a96e103b883a85036c64e1c992a7a12c594f11954bacca01"],"txID":"007bbcc3855f4bf51bd76e63d7776160c115c803e227f7c44c7d1fd1bd587611"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":268,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":200000000,"owner_address":"413c5d20a6b1747c65903e2874614d6b8a038b818c","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758086000,"fee_limit":0,"ref_block_bytes":"d522","ref_block_hash":"9ecd3926187cf28e","timestamp":1592754429137},"raw_data_hex":"0a02d52222089ecd3926187cf28e40f0d29ebead2e5a68080112640a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412330a15413c5d20a6b1747c65903e2874614d6b8a038b818c12154179309abcff2cf531070ca9222a1f72c4a5136874188084af5f70d1b9bfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["9192ee355f2b8c4b21cb68d5b5b2647a4ccb3a00c2bdaeb65cddef4785e7a31e364e21ef3c8b78628c8d342d6f7727ab391b064c1f0b02105e300108ca9cf88800"],"txID":"9351e87b129142844f000a52911daf36fc95677dfe2846abcd28ea0d8fe2e2ea"},{"blockNumber":20829498,"block_timestamp":1592754444000,"energy_fee":0,"energy_usage":0,"energy_usage_total":0,"internal_transactions":[],"net_fee":0,"net_usage":269,"raw_data":{"contract":[{"parameter":{"type_url":"type.googleapis.com/protocol.TransferContract","value":{"amount":511000000,"owner_address":"414a5a0f19fd4b1c85208764a7a8cdcdb88171fc71","to_address":"4179309abcff2cf531070ca9222a1f72c4a5136874"}},"type":"TransferContract"}],"expiration":1592758086000,"fee_limit":0,"ref_block_bytes":"d522","ref_block_hash":"9ecd3926187cf28e","timestamp":1592754428706},"raw_data_hex":"0a02d52222089ecd3926187cf28e40f0d29ebead2e5a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a15414a5a0f19fd4b1c85208764a7a8cdcdb88171fc7112154179309abcff2cf531070ca9222a1f72c4a513687418c0fbd4f30170a2b6bfbcad2e","ret":[{"code":"SUCESS","contractRet":"SUCCESS","fee":0}],"signature":["fac73d7f6540a63c27717cbe04197d8ae89bd906f6c59eba71cc3a2630e29d9b6e0e4400b5e316289e5b6608d84a1a47673674605e48776f8d97aa3dedcfc60301"],"txID":"008ebda5749c38e26a69717faa66e6f4fd8a0d358c9b947192765cc9843cff5a"}]}` - mockedTrc20Response = `{"trc20token_balances":[{"name":"BeeHive","symbol":"Bee","decimals":8,"contract_address":"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK","balance":"100000000000000"},{"name":"NoleCoin","symbol":"NOLE","decimals":6,"contract_address":"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG","balance":"20000","priceInTrx":20.000000},{"name":"Enme Token","symbol":"EME","decimals":6,"contract_address":"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF","balance":"175798"},{"name":"PYRO Network","symbol":"PYRO","decimals":6,"contract_address":"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e","balance":"5000000000","priceInTrx":0.005821},{"name":"Wuhan Fried Bats","symbol":"WUHAN","decimals":4,"contract_address":"TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr","balance":"690000"},{"name":"WINK","symbol":"WIN","decimals":6,"contract_address":"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7","balance":"191543058623486","priceInTrx":0.004665},{"name":"Mono Token","symbol":"MONO","decimals":18,"contract_address":"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak","balance":"1"},{"name":"HelGro","symbol":"HGRO","decimals":6,"contract_address":"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm","balance":"20000000"},{"name":"JUST GOV","symbol":"JST","decimals":18,"contract_address":"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9","balance":"955973733483987848990056","priceInTrx":0.313300},{"name":"Tether USD","symbol":"USDT","decimals":6,"contract_address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","balance":"6781725898163","priceInTrx":64.102564}],"allowExchange":[],"address":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","frozen_supply":[],"bandwidth":{"energyRemaining":0,"totalEnergyLimit":90000000000,"totalEnergyWeight":1446707995,"netUsed":0,"storageLimit":0,"storagePercentage":0.0,"assets":{"1000542":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002446":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002721":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001510":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002962":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001479":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002288":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001594":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002683":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000541":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001079":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000145":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002608":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000821":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002845":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001759":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002726":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001230":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001467":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002798":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000894":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000532":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002830":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000017":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000494":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002398":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002552":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002551":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002672":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002037":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002950":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000935":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000938":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002438":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000491":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000096":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002671":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000493":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001064":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001581":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002270":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000322":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002589":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001411":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002467":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002742":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001414":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001535":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000567":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000165":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001011":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002342":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001132":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000562":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000287":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001815":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002907":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002746":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002748":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001090":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000278":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000157":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002578":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002577":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002852":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002459":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000396":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002573":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002454":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000959":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002736":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002858":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003022":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001038":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000983":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001433":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000743":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001953":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002646":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000985":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002524":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002001":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002881":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002488":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002521":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002762":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002927":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002926":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000745":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000744":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000746":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002000":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000181":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002116":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001301":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001425":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002876":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000176":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000451":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003049":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002597":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002918":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002636":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002999":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001825":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000856":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002517":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002230":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002071":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1003041":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002072":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000003":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000520":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000884":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002544":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001854":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002822":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000006":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002662":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002669":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002384":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002263":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001203":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002897":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001565":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002775":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002657":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001204":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1001446":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002892":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002939":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002814":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002250":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1002099":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0},"1000190":{"netPercentage":0.0,"netLimit":0,"netRemaining":0,"netUsed":0}},"netPercentage":0.0,"storageUsed":0,"storageRemaining":0,"freeNetLimit":5000,"energyUsed":0,"freeNetRemaining":211,"netLimit":0,"netRemaining":0,"energyLimit":0,"freeNetUsed":4789,"totalNetWeight":26789943446,"freeNetPercentage":0.9578,"energyPercentage":0.0,"totalNetLimit":43200000000},"accountType":0,"exchanges":[],"frozen":{"total":0,"balances":[]},"accountResource":{"frozen_balance_for_energy":{}},"tokenBalances":[{"balance":346976329314696,"name":"_"},{"balance":1273,"name":"1000003"},{"balance":113,"name":"1000006"},{"balance":145,"name":"1000165"},{"balance":416,"name":"1000520"},{"balance":596,"name":"1000491"},{"balance":242,"name":"1000176","owner_address":"THG48yHsR6inxrCJk2hhxZPsFLq1ehP88V"},{"balance":62,"name":"1000542"},{"balance":53,"name":"1000494","owner_address":"TXJnVqqwLSNmdXDLWn1Yfjhe8aZH2oaAuq"},{"balance":56,"name":"1000493"},{"balance":599,"name":"1000744"},{"balance":628,"name":"1000746"},{"balance":234,"name":"1000743"},{"balance":113,"name":"1000396"},{"balance":206,"name":"1000745","owner_address":"TPCEi45wZQ1PPChUg5uqoK1D5kKnjCR8Li"},{"balance":61,"name":"1000821","owner_address":"TBm3Peu51gYwn2iPwNEDxc9vBMc3eRGUGu"},{"balance":25,"name":"1000541"},{"balance":7,"name":"1000278","owner_address":"TRMUimDekf9nDLuVMp6TKzcw4axNnajGJr"},{"balance":1,"name":"1000567","owner_address":"TFXJMhB4ZKBfcQWfCLbSyQGhonHXABaWku"},{"balance":1,"name":"1000856","owner_address":"TXf3X8YMdDho2xwA6QDbFZiTGPnk8ghfLm"},{"balance":30,"name":"1000884"},{"balance":1,"name":"1000894"},{"balance":200,"name":"1000181","owner_address":"TEmTbbvH5ZPJPZ8CbffjqonFRiAAFgfc9o"},{"balance":7,"name":"1000935","owner_address":"TPVkcFYTEi9Dia45AveiTcaYoaU9ux7xC7"},{"balance":1000,"name":"1000938","owner_address":"TNgkWTabK1rMWwgLjmLdsZbzYfGTx5Tpe9"},{"balance":10,"name":"1000017","owner_address":"TV6qcwSp38uESiDczxxb7zbJX1h2LfDs78"},{"balance":10,"name":"1001011","owner_address":"TNUbeTQXPtRXtBX3dJboVkhdhaiws29Aky"},{"balance":2,"name":"1001038","owner_address":"TFujVDp8U578L2AtsorYN3pwdXmH2HxbQv"},{"balance":100,"name":"1000983","owner_address":"TYmiZ7xCeqboiizb2jsjVQuRABXzVSjKFR"},{"balance":1,"name":"1001203","owner_address":"TBmaT8mcrdkrRL2Q6ur7grMYAcaGtfxsz7"},{"balance":1,"name":"1000190","owner_address":"TNXjXURue38Wa641pmqMH4vbJN1WZLKMnr"},{"balance":100,"name":"1001204"},{"balance":1000,"name":"1001230"},{"balance":1300000,"name":"1001301","owner_address":"TVgJEbc9NEYxVr1h6rJQiMqySePsJQDCA7"},{"balance":11,"name":"1000959"},{"balance":10,"name":"1001425"},{"balance":17,"name":"1001433","owner_address":"TWPMz6FPEAV6qP4VRMG3Y69ftEov1R7YWT"},{"balance":100,"name":"1001446"},{"balance":12,"name":"1001411","owner_address":"TPL6zNujtEQ8kp213n58UxAhGRCU3aozkc"},{"balance":12,"name":"1001467"},{"balance":100,"name":"1001414","owner_address":"TT43DgfxgMdR4BVZNua4YCwG34AgfGN6Uu"},{"balance":100,"name":"1001510","owner_address":"TPKq9bVZyM2sZ8XersMmXhy1NbjhdxRwwj"},{"balance":50,"name":"1001565","owner_address":"TKY7Vmq78b2c83fLXrPijkhQkk4EJtfViD"},{"balance":5,"name":"1001535"},{"balance":10,"name":"1000532","owner_address":"TGQwBNht8h3zev4gBtDMoQjWE2WJm1Zr9B"},{"balance":3,"name":"1001479","owner_address":"TC9FtB1EoiV3jfXgZvmqUmfeCmdWNmCxdY"},{"balance":13,"name":"1001090","owner_address":"TU1LUTYDMG6iihimUpAmdnnBthawPKh1cm","priceInTrx":0.004360},{"balance":200,"name":"1001759","owner_address":"TWKWWJAFBYyjvLtfqKCSeMyUW7TjWhkY4e"},{"balance":12,"name":"1000096","owner_address":"TSfjkVSKJGW4aybDQcxi4bpythU7WCXV3v"},{"balance":15,"name":"1001594"},{"balance":10,"name":"1001815","owner_address":"TB3iM1RsKXagV7hdz2QpWnaChptwrU3tCL"},{"balance":10,"name":"1001064","owner_address":"THnWV416C9mfJ1LFwopUjGXZEr1xFtAdrD"},{"balance":5192508733304578,"name":"1002000","owner_address":"TF5Bn4cJCT6GVeUgyCN4rBhDg42KBrpAjg","priceInTrx":0.018900},{"balance":7742069,"name":"1002037","owner_address":"TBekuTCZwPG2o88SmiS58VALkxBemoX4yS"},{"balance":585,"name":"1002001"},{"balance":5441,"name":"1002071","owner_address":"TS79aik831csqUnQgnqrKG6hov2iL8yPbD"},{"balance":80312957663126,"name":"1002072","owner_address":"TP6PtaBSMM6sfWtWWD9k77YHWGmh7K3Lae"},{"balance":520,"name":"1000451","owner_address":"THPXuypwcnWo4wi5KqFfuRjgjeT5khUDKF"},{"balance":10011237,"name":"1001953","owner_address":"TSyG9BdjsGE2GoHG9eeYKMns6zMQFDmbvS"},{"balance":5,"name":"1000562","owner_address":"TWqKTJ5JhyD7rsbbWzEvS5ZZD9Q5QPPvSH"},{"balance":50000000,"name":"1002099","owner_address":"TYWmiPERm9kWUcnduqaE5jxT7eeZxfn5SQ"},{"balance":625100,"name":"1001581","owner_address":"TNkRSKWP7VvdrisTwC8iNzUV6MRoEJh6xx"},{"balance":11000000,"name":"1002342","owner_address":"TUCd8NiBUuxrjz1kSrUbAg2JXu6o27Ukrq"},{"balance":7,"name":"1000322","owner_address":"TDGy2M9qWBepSHDEutWWxWd1JZfmAed3BP","priceInTrx":0.000422},{"balance":12,"name":"1001825","owner_address":"TPcUbNeYwwYqbX23w3sVf1X61cwpAfPK2T"},{"balance":1000,"name":"1002384","owner_address":"TFYuPxyjDTvH1TLm2phpzJFw7AhjCgu8xP"},{"balance":44444,"name":"1001132","owner_address":"TWDUanVdxEShjpbiX57ExztMCDy8vCFcHh"},{"balance":30000000,"name":"1002398","owner_address":"TUXSuMg41nJXm9TuDgF6EZWjEbP2vx1Hd4"},{"balance":10000060,"name":"1002116","owner_address":"TAEvo6MgLgV3A75L3cr3BAsLDJikWcAt3j"},{"balance":50000000,"name":"1002446","owner_address":"TJKf72NjL1cR49SHfDnPTXTFjRwjgr7v8Z"},{"balance":10000000,"name":"1002459","owner_address":"TNWy3mX85JsX2mPLgLc4cKJiWtJahhz3t3"},{"balance":1,"name":"1001079","owner_address":"TLQfc5EwZQqZc6jMNkMpxyJy5wucA6UX24"},{"balance":12345,"name":"1002467","owner_address":"TP429SKrsp4BoTiEFXHj4TNSJwqDFsygnr"},{"balance":1234,"name":"1002230","owner_address":"TWB9Q1JoB3fSLsahNq31gydRxYyWxDhSyk"},{"balance":10000000,"name":"1002288","owner_address":"TPzfpaaKUPgJPZ39YeyvBaTYNXBYpnhxDg"},{"balance":5,"name":"1002488","owner_address":"TMeAzhdgzu1sFMTsP75BffJ2tEzuGsYqR6"},{"balance":666,"name":"1002438","owner_address":"TMqNJwD3qVmuRxzzP3Q4A24fuByVBKQ39E"},{"balance":10000000,"name":"1002517","owner_address":"TP9m11ERHhE1qgDtL83c2AHHNkWvdUfKTz"},{"balance":10000000000,"name":"1002521","owner_address":"TJUwM4qk1et2nNKuESQ7UVHPjAHoRqAz3T"},{"balance":13699,"name":"1000157","owner_address":"TUahmv54ZiDnjQWG2VAeyMphebXQ4m6Hb5"},{"balance":65895,"name":"1002524","owner_address":"TRzZeBPt69utiWx1po5ghLH8uSP8uJGsa5"},{"balance":16,"name":"1000287","owner_address":"TFZCyZ18XNzMfEr6W5kLkGrs4HVmou9H3y"},{"balance":10000000,"name":"1002544","owner_address":"TQHBbjES5DNjDfDHBbpnh9qcDM7mVjSVcL"},{"balance":10000000000,"name":"1002551","owner_address":"TVrGxBCQkWjQ52D7S67UgFsUzcX4E8EsNB"},{"balance":10000000,"name":"1002573","owner_address":"TBfmGqmZtdEQNuYCz8s1izBUDxZbkPmMcj"},{"balance":10000000,"name":"1002552","owner_address":"TCxeAH2ajBqoWzqV9m5YiFTyeQ5FvzVqSH"},{"balance":1000000,"name":"1002578","owner_address":"TUjBG7C1CU7X75UmacnyrRTYLmbSeX7iDa"},{"balance":2555000,"name":"1002270","owner_address":"TMSpdYHCgZuxM7AjqKsjGMM1cpxraFuZGp"},{"balance":10000000,"name":"1002597","owner_address":"TDEBhgsdGTSzrgMsPDUQ1pt59fR6wWR7Rq"},{"balance":10000000,"name":"1002636","owner_address":"TKL54NcGXvBckkGbPjYzAmdwFs3usv8VY9"},{"balance":100000000,"name":"1002250","owner_address":"THUHfNqiYo4KS3GLM8MUU4x3wek9uPD47d"},{"balance":1000000,"name":"1002662","owner_address":"TEV5PJWga6crSeNLHmHaaco8fon6nm74wJ"},{"balance":10000000,"name":"1002672","owner_address":"TBHJCf3nymJPt1hVPjSJfH5ssJLdNMPepe"},{"balance":24120,"name":"1002657","owner_address":"TCKiVea721ycNAWonb2dpwr65AJkMiGSFb"},{"balance":1000000,"name":"1002683","owner_address":"TL6YggMQQ3YFEc41wesBMHZjDxcGpX3y5q"},{"balance":3000000,"name":"1002671","owner_address":"TDQ5q4Hf6UqR43Smp67sndMQfdTcGgP88s"},{"balance":20,"name":"1002577","owner_address":"TGZzci6a9wtcSiNekqYLP84ECRoaJ6pBwY"},{"balance":10000000,"name":"1002721","owner_address":"TUkUgsTTo74B9XG9da4d2NsaZqCKLNFwNS"},{"balance":10000,"name":"1002726","owner_address":"TRXw3Ggt3xs3fHbcoark1aeKwUZFKTYcsS"},{"balance":21092024781,"name":"1002263","owner_address":"TD5AwyiTNbKN9jQqyMzwQ6NLrWGbtAcotK"},{"balance":10000000,"name":"1002736","owner_address":"TBB19fMCf19wuiu5omtA1nAqALPpo4oa32"},{"balance":10000000,"name":"1002646","owner_address":"TRUnzvtzT6o35M4XHUvKr48yCZjw4dQyvp"},{"balance":7392000000,"name":"1002589","owner_address":"TUL9NhGQkRFLTRcHGkdoSniAeVaNPZGgot"},{"balance":10000000,"name":"1002742","owner_address":"TWfrNPVGDh1tyPVM79bfEASb7jw2bLbZPJ"},{"balance":8822711275000000,"name":"1002762","owner_address":"TRChSJM8TjQj7vvJCN9W8WBcfkJq2eBxgv"},{"balance":10000000,"name":"1002775"},{"balance":10000000,"name":"1002798","owner_address":"TBitZMK7YSUb2Q1Cm537D5iAZSJkaPdN9c"},{"balance":95,"name":"1001854","owner_address":"TSMeDkfmX6m1NZmDBrVtGPnACJCUWVkx4p"},{"balance":10000000,"name":"1002746","owner_address":"TQbbAyfcrKERXjUDf8TZfcdtjFQbCSgEfc"},{"balance":2000000,"name":"1002669","owner_address":"THhgpkHBdJDDWBPnZKRgzdvRr3qCtAa2cv"},{"balance":10000000,"name":"1002814","owner_address":"TNvq4y2A2beBENtcGknwhX6XHgk8hqgnVh"},{"balance":10000000,"name":"1002830","owner_address":"THLLMnsEKEci5e5dJHnW28QQU8AujGhSoK"},{"balance":10000000,"name":"1002845","owner_address":"TUzpDkzjWkZasA6Dx7nx5PPskMkCcNxVyQ"},{"balance":10000000,"name":"1002858","owner_address":"TRKJcugHJeffVpCAFGapZMwuH8HaTWjbof"},{"balance":200,"name":"1002454","owner_address":"TDCGkNf3XB3jRGg7bhFkNynkGw7q4kV3z9"},{"balance":10000000,"name":"1002876","owner_address":"TGqiinRV6nn8GbF5LX7zue4fpjstG1gVvu"},{"balance":20000000,"name":"1002881","owner_address":"TWpKN6y3NVXm5mMjGmPEtLpS6boGM4q8T4"},{"balance":350,"name":"1000145","owner_address":"TNFcvwJgvBRg2Dq5Qyx1gxcvqU3dwPyVNc"},{"balance":10000000,"name":"1002892","owner_address":"TECsVV1kTtx48sbdjvptq544h4H3Qqr24c"},{"balance":10000000,"name":"1002897","owner_address":"TPKqse19ALipJ1uBZHGWHzuTrQqZa4HtaM"},{"balance":2055000000,"name":"1002822","owner_address":"TURy9pFLskqTWgkZqUCUdPXkezZfYL76YQ"},{"balance":1000000,"name":"1002852","owner_address":"TUmad3hCqxu78n8GuULrdJMUB4qmTUYgv3"},{"balance":10000000,"name":"1002907","owner_address":"TKC9HMUXx3qLE7d19KWzWVjFxEcWQdSYK9"},{"balance":10000000,"name":"1002927","owner_address":"TAwRvFAqfB4bbzVCVPgGATZV5uMVs9UyVL"},{"balance":10000000,"name":"1002926","owner_address":"TF5jfDiQ3d7T5ihcBxeWS9S8xSR5tS738x"},{"balance":1000000,"name":"1002748","owner_address":"TTUAmhh9k2Yegf3TxZc86vG5E9kT24vgcw"},{"balance":189990000000,"name":"1002950","owner_address":"TNCZCGDPQ69ieJFsY1jZUohXmR46A4kM24"},{"balance":10,"name":"1000985","owner_address":"TRH5jmPx77UnMvfdvfo2m3FCkZVcBiFvqP"},{"balance":10000000,"name":"1002962","owner_address":"TFDwGwod9qopreRiirsFMwPzX4v2r662P4"},{"balance":10000000,"name":"1002918","owner_address":"TKGpTks1myPrJ9ZtEdLgpjvg1RMR2wGAFz"},{"balance":1000,"name":"1002608","owner_address":"TDPsSgBQznKEffdTMq3aspsvrmFfhL7ZcP"},{"balance":10000000,"name":"1002999","owner_address":"TTL52uBzTG7qorL7BQYdjGUY3HWWr9Kvao"},{"balance":100000000000,"name":"1003022","owner_address":"TAAJiJ1NgkEkE3w1PQk4dA8XH9rpfk5eVE"},{"balance":1000000000,"name":"1003041","owner_address":"TQADZoww5HstdsJM1GXwstqsRRnmrkThzY"},{"balance":10000000,"name":"1003049","owner_address":"THFJwSN5Z3zTc5TvkSiVh8m4kQMZaTMaqk"},{"balance":1,"name":"1002939","owner_address":"TAsSw8hUddYi8AN8EkDuAMS9r8pkriyUxs"}],"balances":[{"balance":346976329314696,"name":"_"},{"balance":1273,"name":"1000003"},{"balance":113,"name":"1000006"},{"balance":145,"name":"1000165"},{"balance":416,"name":"1000520"},{"balance":596,"name":"1000491"},{"balance":242,"name":"1000176","owner_address":"THG48yHsR6inxrCJk2hhxZPsFLq1ehP88V"},{"balance":62,"name":"1000542"},{"balance":53,"name":"1000494","owner_address":"TXJnVqqwLSNmdXDLWn1Yfjhe8aZH2oaAuq"},{"balance":56,"name":"1000493"},{"balance":599,"name":"1000744"},{"balance":628,"name":"1000746"},{"balance":234,"name":"1000743"},{"balance":113,"name":"1000396"},{"balance":206,"name":"1000745","owner_address":"TPCEi45wZQ1PPChUg5uqoK1D5kKnjCR8Li"},{"balance":61,"name":"1000821","owner_address":"TBm3Peu51gYwn2iPwNEDxc9vBMc3eRGUGu"},{"balance":25,"name":"1000541"},{"balance":7,"name":"1000278","owner_address":"TRMUimDekf9nDLuVMp6TKzcw4axNnajGJr"},{"balance":1,"name":"1000567","owner_address":"TFXJMhB4ZKBfcQWfCLbSyQGhonHXABaWku"},{"balance":1,"name":"1000856","owner_address":"TXf3X8YMdDho2xwA6QDbFZiTGPnk8ghfLm"},{"balance":30,"name":"1000884"},{"balance":1,"name":"1000894"},{"balance":200,"name":"1000181","owner_address":"TEmTbbvH5ZPJPZ8CbffjqonFRiAAFgfc9o"},{"balance":7,"name":"1000935","owner_address":"TPVkcFYTEi9Dia45AveiTcaYoaU9ux7xC7"},{"balance":1000,"name":"1000938","owner_address":"TNgkWTabK1rMWwgLjmLdsZbzYfGTx5Tpe9"},{"balance":10,"name":"1000017","owner_address":"TV6qcwSp38uESiDczxxb7zbJX1h2LfDs78"},{"balance":10,"name":"1001011","owner_address":"TNUbeTQXPtRXtBX3dJboVkhdhaiws29Aky"},{"balance":2,"name":"1001038","owner_address":"TFujVDp8U578L2AtsorYN3pwdXmH2HxbQv"},{"balance":100,"name":"1000983","owner_address":"TYmiZ7xCeqboiizb2jsjVQuRABXzVSjKFR"},{"balance":1,"name":"1001203","owner_address":"TBmaT8mcrdkrRL2Q6ur7grMYAcaGtfxsz7"},{"balance":1,"name":"1000190","owner_address":"TNXjXURue38Wa641pmqMH4vbJN1WZLKMnr"},{"balance":100,"name":"1001204"},{"balance":1000,"name":"1001230"},{"balance":1300000,"name":"1001301","owner_address":"TVgJEbc9NEYxVr1h6rJQiMqySePsJQDCA7"},{"balance":11,"name":"1000959"},{"balance":10,"name":"1001425"},{"balance":17,"name":"1001433","owner_address":"TWPMz6FPEAV6qP4VRMG3Y69ftEov1R7YWT"},{"balance":100,"name":"1001446"},{"balance":12,"name":"1001411","owner_address":"TPL6zNujtEQ8kp213n58UxAhGRCU3aozkc"},{"balance":12,"name":"1001467"},{"balance":100,"name":"1001414","owner_address":"TT43DgfxgMdR4BVZNua4YCwG34AgfGN6Uu"},{"balance":100,"name":"1001510","owner_address":"TPKq9bVZyM2sZ8XersMmXhy1NbjhdxRwwj"},{"balance":50,"name":"1001565","owner_address":"TKY7Vmq78b2c83fLXrPijkhQkk4EJtfViD"},{"balance":5,"name":"1001535"},{"balance":10,"name":"1000532","owner_address":"TGQwBNht8h3zev4gBtDMoQjWE2WJm1Zr9B"},{"balance":3,"name":"1001479","owner_address":"TC9FtB1EoiV3jfXgZvmqUmfeCmdWNmCxdY"},{"balance":13,"name":"1001090","owner_address":"TU1LUTYDMG6iihimUpAmdnnBthawPKh1cm","priceInTrx":0.004360},{"balance":200,"name":"1001759","owner_address":"TWKWWJAFBYyjvLtfqKCSeMyUW7TjWhkY4e"},{"balance":12,"name":"1000096","owner_address":"TSfjkVSKJGW4aybDQcxi4bpythU7WCXV3v"},{"balance":15,"name":"1001594"},{"balance":10,"name":"1001815","owner_address":"TB3iM1RsKXagV7hdz2QpWnaChptwrU3tCL"},{"balance":10,"name":"1001064","owner_address":"THnWV416C9mfJ1LFwopUjGXZEr1xFtAdrD"},{"balance":5192508733304578,"name":"1002000","owner_address":"TF5Bn4cJCT6GVeUgyCN4rBhDg42KBrpAjg","priceInTrx":0.018900},{"balance":7742069,"name":"1002037","owner_address":"TBekuTCZwPG2o88SmiS58VALkxBemoX4yS"},{"balance":585,"name":"1002001"},{"balance":5441,"name":"1002071","owner_address":"TS79aik831csqUnQgnqrKG6hov2iL8yPbD"},{"balance":80312957663126,"name":"1002072","owner_address":"TP6PtaBSMM6sfWtWWD9k77YHWGmh7K3Lae"},{"balance":520,"name":"1000451","owner_address":"THPXuypwcnWo4wi5KqFfuRjgjeT5khUDKF"},{"balance":10011237,"name":"1001953","owner_address":"TSyG9BdjsGE2GoHG9eeYKMns6zMQFDmbvS"},{"balance":5,"name":"1000562","owner_address":"TWqKTJ5JhyD7rsbbWzEvS5ZZD9Q5QPPvSH"},{"balance":50000000,"name":"1002099","owner_address":"TYWmiPERm9kWUcnduqaE5jxT7eeZxfn5SQ"},{"balance":625100,"name":"1001581","owner_address":"TNkRSKWP7VvdrisTwC8iNzUV6MRoEJh6xx"},{"balance":11000000,"name":"1002342","owner_address":"TUCd8NiBUuxrjz1kSrUbAg2JXu6o27Ukrq"},{"balance":7,"name":"1000322","owner_address":"TDGy2M9qWBepSHDEutWWxWd1JZfmAed3BP","priceInTrx":0.000422},{"balance":12,"name":"1001825","owner_address":"TPcUbNeYwwYqbX23w3sVf1X61cwpAfPK2T"},{"balance":1000,"name":"1002384","owner_address":"TFYuPxyjDTvH1TLm2phpzJFw7AhjCgu8xP"},{"balance":44444,"name":"1001132","owner_address":"TWDUanVdxEShjpbiX57ExztMCDy8vCFcHh"},{"balance":30000000,"name":"1002398","owner_address":"TUXSuMg41nJXm9TuDgF6EZWjEbP2vx1Hd4"},{"balance":10000060,"name":"1002116","owner_address":"TAEvo6MgLgV3A75L3cr3BAsLDJikWcAt3j"},{"balance":50000000,"name":"1002446","owner_address":"TJKf72NjL1cR49SHfDnPTXTFjRwjgr7v8Z"},{"balance":10000000,"name":"1002459","owner_address":"TNWy3mX85JsX2mPLgLc4cKJiWtJahhz3t3"},{"balance":1,"name":"1001079","owner_address":"TLQfc5EwZQqZc6jMNkMpxyJy5wucA6UX24"},{"balance":12345,"name":"1002467","owner_address":"TP429SKrsp4BoTiEFXHj4TNSJwqDFsygnr"},{"balance":1234,"name":"1002230","owner_address":"TWB9Q1JoB3fSLsahNq31gydRxYyWxDhSyk"},{"balance":10000000,"name":"1002288","owner_address":"TPzfpaaKUPgJPZ39YeyvBaTYNXBYpnhxDg"},{"balance":5,"name":"1002488","owner_address":"TMeAzhdgzu1sFMTsP75BffJ2tEzuGsYqR6"},{"balance":666,"name":"1002438","owner_address":"TMqNJwD3qVmuRxzzP3Q4A24fuByVBKQ39E"},{"balance":10000000,"name":"1002517","owner_address":"TP9m11ERHhE1qgDtL83c2AHHNkWvdUfKTz"},{"balance":10000000000,"name":"1002521","owner_address":"TJUwM4qk1et2nNKuESQ7UVHPjAHoRqAz3T"},{"balance":13699,"name":"1000157","owner_address":"TUahmv54ZiDnjQWG2VAeyMphebXQ4m6Hb5"},{"balance":65895,"name":"1002524","owner_address":"TRzZeBPt69utiWx1po5ghLH8uSP8uJGsa5"},{"balance":16,"name":"1000287","owner_address":"TFZCyZ18XNzMfEr6W5kLkGrs4HVmou9H3y"},{"balance":10000000,"name":"1002544","owner_address":"TQHBbjES5DNjDfDHBbpnh9qcDM7mVjSVcL"},{"balance":10000000000,"name":"1002551","owner_address":"TVrGxBCQkWjQ52D7S67UgFsUzcX4E8EsNB"},{"balance":10000000,"name":"1002573","owner_address":"TBfmGqmZtdEQNuYCz8s1izBUDxZbkPmMcj"},{"balance":10000000,"name":"1002552","owner_address":"TCxeAH2ajBqoWzqV9m5YiFTyeQ5FvzVqSH"},{"balance":1000000,"name":"1002578","owner_address":"TUjBG7C1CU7X75UmacnyrRTYLmbSeX7iDa"},{"balance":2555000,"name":"1002270","owner_address":"TMSpdYHCgZuxM7AjqKsjGMM1cpxraFuZGp"},{"balance":10000000,"name":"1002597","owner_address":"TDEBhgsdGTSzrgMsPDUQ1pt59fR6wWR7Rq"},{"balance":10000000,"name":"1002636","owner_address":"TKL54NcGXvBckkGbPjYzAmdwFs3usv8VY9"},{"balance":100000000,"name":"1002250","owner_address":"THUHfNqiYo4KS3GLM8MUU4x3wek9uPD47d"},{"balance":1000000,"name":"1002662","owner_address":"TEV5PJWga6crSeNLHmHaaco8fon6nm74wJ"},{"balance":10000000,"name":"1002672","owner_address":"TBHJCf3nymJPt1hVPjSJfH5ssJLdNMPepe"},{"balance":24120,"name":"1002657","owner_address":"TCKiVea721ycNAWonb2dpwr65AJkMiGSFb"},{"balance":1000000,"name":"1002683","owner_address":"TL6YggMQQ3YFEc41wesBMHZjDxcGpX3y5q"},{"balance":3000000,"name":"1002671","owner_address":"TDQ5q4Hf6UqR43Smp67sndMQfdTcGgP88s"},{"balance":20,"name":"1002577","owner_address":"TGZzci6a9wtcSiNekqYLP84ECRoaJ6pBwY"},{"balance":10000000,"name":"1002721","owner_address":"TUkUgsTTo74B9XG9da4d2NsaZqCKLNFwNS"},{"balance":10000,"name":"1002726","owner_address":"TRXw3Ggt3xs3fHbcoark1aeKwUZFKTYcsS"},{"balance":21092024781,"name":"1002263","owner_address":"TD5AwyiTNbKN9jQqyMzwQ6NLrWGbtAcotK"},{"balance":10000000,"name":"1002736","owner_address":"TBB19fMCf19wuiu5omtA1nAqALPpo4oa32"},{"balance":10000000,"name":"1002646","owner_address":"TRUnzvtzT6o35M4XHUvKr48yCZjw4dQyvp"},{"balance":7392000000,"name":"1002589","owner_address":"TUL9NhGQkRFLTRcHGkdoSniAeVaNPZGgot"},{"balance":10000000,"name":"1002742","owner_address":"TWfrNPVGDh1tyPVM79bfEASb7jw2bLbZPJ"},{"balance":8822711275000000,"name":"1002762","owner_address":"TRChSJM8TjQj7vvJCN9W8WBcfkJq2eBxgv"},{"balance":10000000,"name":"1002775"},{"balance":10000000,"name":"1002798","owner_address":"TBitZMK7YSUb2Q1Cm537D5iAZSJkaPdN9c"},{"balance":95,"name":"1001854","owner_address":"TSMeDkfmX6m1NZmDBrVtGPnACJCUWVkx4p"},{"balance":10000000,"name":"1002746","owner_address":"TQbbAyfcrKERXjUDf8TZfcdtjFQbCSgEfc"},{"balance":2000000,"name":"1002669","owner_address":"THhgpkHBdJDDWBPnZKRgzdvRr3qCtAa2cv"},{"balance":10000000,"name":"1002814","owner_address":"TNvq4y2A2beBENtcGknwhX6XHgk8hqgnVh"},{"balance":10000000,"name":"1002830","owner_address":"THLLMnsEKEci5e5dJHnW28QQU8AujGhSoK"},{"balance":10000000,"name":"1002845","owner_address":"TUzpDkzjWkZasA6Dx7nx5PPskMkCcNxVyQ"},{"balance":10000000,"name":"1002858","owner_address":"TRKJcugHJeffVpCAFGapZMwuH8HaTWjbof"},{"balance":200,"name":"1002454","owner_address":"TDCGkNf3XB3jRGg7bhFkNynkGw7q4kV3z9"},{"balance":10000000,"name":"1002876","owner_address":"TGqiinRV6nn8GbF5LX7zue4fpjstG1gVvu"},{"balance":20000000,"name":"1002881","owner_address":"TWpKN6y3NVXm5mMjGmPEtLpS6boGM4q8T4"},{"balance":350,"name":"1000145","owner_address":"TNFcvwJgvBRg2Dq5Qyx1gxcvqU3dwPyVNc"},{"balance":10000000,"name":"1002892","owner_address":"TECsVV1kTtx48sbdjvptq544h4H3Qqr24c"},{"balance":10000000,"name":"1002897","owner_address":"TPKqse19ALipJ1uBZHGWHzuTrQqZa4HtaM"},{"balance":2055000000,"name":"1002822","owner_address":"TURy9pFLskqTWgkZqUCUdPXkezZfYL76YQ"},{"balance":1000000,"name":"1002852","owner_address":"TUmad3hCqxu78n8GuULrdJMUB4qmTUYgv3"},{"balance":10000000,"name":"1002907","owner_address":"TKC9HMUXx3qLE7d19KWzWVjFxEcWQdSYK9"},{"balance":10000000,"name":"1002927","owner_address":"TAwRvFAqfB4bbzVCVPgGATZV5uMVs9UyVL"},{"balance":10000000,"name":"1002926","owner_address":"TF5jfDiQ3d7T5ihcBxeWS9S8xSR5tS738x"},{"balance":1000000,"name":"1002748","owner_address":"TTUAmhh9k2Yegf3TxZc86vG5E9kT24vgcw"},{"balance":189990000000,"name":"1002950","owner_address":"TNCZCGDPQ69ieJFsY1jZUohXmR46A4kM24"},{"balance":10,"name":"1000985","owner_address":"TRH5jmPx77UnMvfdvfo2m3FCkZVcBiFvqP"},{"balance":10000000,"name":"1002962","owner_address":"TFDwGwod9qopreRiirsFMwPzX4v2r662P4"},{"balance":10000000,"name":"1002918","owner_address":"TKGpTks1myPrJ9ZtEdLgpjvg1RMR2wGAFz"},{"balance":1000,"name":"1002608","owner_address":"TDPsSgBQznKEffdTMq3aspsvrmFfhL7ZcP"},{"balance":10000000,"name":"1002999","owner_address":"TTL52uBzTG7qorL7BQYdjGUY3HWWr9Kvao"},{"balance":100000000000,"name":"1003022","owner_address":"TAAJiJ1NgkEkE3w1PQk4dA8XH9rpfk5eVE"},{"balance":1000000000,"name":"1003041","owner_address":"TQADZoww5HstdsJM1GXwstqsRRnmrkThzY"},{"balance":10000000,"name":"1003049","owner_address":"THFJwSN5Z3zTc5TvkSiVh8m4kQMZaTMaqk"},{"balance":1,"name":"1002939","owner_address":"TAsSw8hUddYi8AN8EkDuAMS9r8pkriyUxs"}],"balance":346976329314696,"voteTotal":0,"name":"","delegated":{"sentDelegatedBandwidth":[],"sentDelegatedResource":[],"receivedDelegatedResource":[],"receivedDelegatedBandwidth":[]},"totalTransactionCount":508552,"representative":{"lastWithDrawTime":0,"allowance":0,"enabled":false,"url":""},"activePermissions":[]}` - mockedTransactionsTrc20Response = `{"success":true,"meta":{"at":1592757126588,"page_size":20,"fingerprint":"2tmLC90HQEnpnJ02w3n","links":{"next":"https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D/transactions/trc20?fingerprint=2tmLC90HQEnpnJ02w3n"}},"data":[{"block_timestamp":1592757117000,"value":"500000000","type":"Transfer","transaction_id":"fb078403adfee637608c3906d9d21dd158611aba149b9993f43d0f292ce543a0","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","token_info":{"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","name":"Tether USD","symbol":"USDT","decimals":6},"_unconfirmed":true},{"block_timestamp":1592757066000,"value":"50000000","type":"Transfer","transaction_id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","token_info":{"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","name":"Tether USD","symbol":"USDT","decimals":6},"_unconfirmed":true},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","block_timestamp":1592757066000,"value":"50000000","type":"Transfer","transaction_id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV","block_timestamp":1592756784000,"value":"3988000000","type":"Transfer","transaction_id":"0b52a4ef9fb8c13fbfae2b8c3506333ec1d718f307062a15f170562818a01d0a","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am","block_timestamp":1592756763000,"value":"640990000","type":"Transfer","transaction_id":"19d2ec6174bf64beb1061475f6429cba03b64944a763686cc3551447d0e8d9d5","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756631000,"value":"1062000000","type":"Transfer","transaction_id":"efb7d44305759cfb189c9fd22720609a2ddeb7fbd7c8afe1dd8851342471da8d","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","block_timestamp":1592756610000,"value":"2000000","type":"Transfer","transaction_id":"48bd90dc3f12086178e65b9389caa8b3c74683937b86d4d61cdec77f0095994a","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R","block_timestamp":1592756589000,"value":"1000000000","type":"Transfer","transaction_id":"afd5ae7e2462c9cc899c7f730b90fd2a5e4c1315e836c92468b504ed85f0b798","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq","block_timestamp":1592756583000,"value":"21200000","type":"Transfer","transaction_id":"3d613031f4b2a0e19deeea030d1d18599b6d9799d2dd530005ead9712c6d219d","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5","block_timestamp":1592756583000,"value":"125000000","type":"Transfer","transaction_id":"cbe359c2574efbdc8fc6a892ffc54812837295067c9816d41734126c82d0c141","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC","block_timestamp":1592756583000,"value":"5277600000","type":"Transfer","transaction_id":"c87248b02a4caaa6f443c1b8c4d4588c8dd281a4687b73e6afecfba6741b50d8","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W","block_timestamp":1592756583000,"value":"485342000","type":"Transfer","transaction_id":"8584f1b6a70ead8232fed19bd653ba13e4c2a8befd070f4a9a06eca3a2e3e548","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr","block_timestamp":1592756583000,"value":"1000000000","type":"Transfer","transaction_id":"2b28b69e6747db68647acc3a62c45da5355b97acd8d2c260ee752aa9bd63a624","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x","block_timestamp":1592756583000,"value":"2000000000","type":"Transfer","transaction_id":"1da6576dec0bd303f56cbfb5712f782e0a56a8713cb661f8afd2f2533e5c6209","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK","block_timestamp":1592756583000,"value":"24216600000","type":"Transfer","transaction_id":"f9c86cce1873cb816d6cd8718e76df8839172add293bbc8d11a5f98c80f9e322","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756541000,"value":"8241997837","type":"Transfer","transaction_id":"75eb35734857daa79c38ef923a7e7eb2e3dfb23d2722762fd2b180651021643f","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592756220000,"value":"18000000000","type":"Transfer","transaction_id":"adee73dadce006ff848ff30d8c5c41f033be2e5e1a8b875f6dbbaab524177d08","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","block_timestamp":1592755962000,"value":"863399098","type":"Transfer","transaction_id":"3655a1156c9adcb876c6c9c9e0f5f1f39704ac4c7296fea05fedf5ca8f6b1a19","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ","block_timestamp":1592755740000,"value":"20000000","type":"Transfer","transaction_id":"03574741eb0016050a19f181e4acc4b20b70f41e11e63140c9556c31eae09fba","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}},{"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug","block_timestamp":1592755722000,"value":"21161340000","type":"Transfer","transaction_id":"f3aa00595996e31dbe9528a3cb21bff987f333bf1f675420ba4fa2ad43c8205f","token_info":{"name":"Tether USD","symbol":"USDT","decimals":6,"address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}}]}` - mockedTransactionsEmptyResponse = `{"success":true,"meta":{"at":1592757318961,"page_size":20,"fingerprint":"AYa6eBNpCs5E2DnumiJJJWJ3n2PYMBRFvU7BLjXD49Jm779DJ1C1hUgjwJAmQx5Y2BnkStKMjzQvcALKeQJYfW51m6sY7YEWW","links":{"next":"https://api.trongrid.io:443/v1/accounts/TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R/transactions?fingerprint=AYa6eBNpCs5E2DnumiJJJWJ3n2PYMBRFvU7BLjXD49Jm779DJ1C1hUgjwJAmQx5Y2BnkStKMjzQvcALKeQJYfW51m6sY7YEWW"}},"data":[]}` - mockedAsset1000542Response = `{"success":true,"meta":{"at":1592754266101,"page_size":1},"data":[{"id":1000542,"abbr":"FOM","description":"Fomo3D is a decentralized, trustless blockchain game.","name":"FomoThreeD","num":1,"total_supply":80000000000,"trx_num":1000000,"url":"https://fomo3d.games/","owner_address":"4134f1b9c19cf40f565661697eb47b0090ac779507","start_time":1534348821000,"end_time":1924876800000}]}` - mockedAsset1000567Response = `{"success":true,"meta":{"at":1592754347268,"page_size":1},"data":[{"id":1000567,"abbr":"os","description":"Open Decentralized Search Engine","frozen_supply":[{"frozen_amount":74000000000,"frozen_days":3652}],"name":"OtonamiS","num":100,"total_supply":99000000000,"trx_num":1000000,"url":"https://OtonamiS.com","owner_address":"413cea69143b5a5b1ff15d847a7e30e3bffa6a2247","start_time":1534773969000,"end_time":1566280800000}]}` - mockedAssetTR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6tResponse = `{"success":true,"meta":{"at":1592754347268,"page_size":1},"data":[]}` - mockedAccountsResponse = `{"success":true,"meta":{"at":1592753781505,"page_size":1},"data":[{"account_resource":{"latest_consume_time_for_energy":1592753721000},"address":"4179309abcff2cf531070ca9222a1f72c4a5136874","asset":[{"key":"IPFS","value":1273},{"key":"TRXTestCoin","value":113},{"key":"Skypeople","value":145},{"key":"binance","value":416},{"key":"BitTorrent","value":596},{"key":"ofoBike","value":242},{"key":"FomoThreeD","value":62},{"key":"Durex","value":53},{"key":"Pornhub","value":56},{"key":"NBACoin","value":599},{"key":"HuobiToken","value":628},{"key":"MacCoin","value":234},{"key":"Messenger","value":113},{"key":"Bithumb","value":206},{"key":"James","value":61},{"key":"RingCoin","value":25},{"key":"DACC","value":7},{"key":"OtonamiS","value":1},{"key":"intrxChain","value":1},{"key":"TRONEX","value":30},{"key":"Petro","value":1},{"key":"KrMaToken","value":200},{"key":"KsumNole","value":7},{"key":"eFilingPlus","value":1000},{"key":"Tarquin","value":10},{"key":"KiloReX","value":10},{"key":"BESTCOIN","value":2},{"key":"Makememillionaire","value":100},{"key":"MedicCoin","value":1},{"key":"DMT","value":1},{"key":"MedIBlock","value":100},{"key":"ethereum","value":1000},{"key":"COLORBIKE","value":1300000},{"key":"WatsonAI","value":11},{"key":"Litcoin","value":10},{"key":"TronMatrixAI","value":17},{"key":"GoodKarma","value":100},{"key":"CryptoBankCoin","value":12},{"key":"EXODUS","value":12},{"key":"TRONO","value":100},{"key":"NMIToken","value":100},{"key":"Ton","value":50},{"key":"Twx","value":5},{"key":"TronLottery","value":10},{"key":"TronTokensGuardian","value":3},{"key":"TRONONE","value":13},{"key":"ELVIS","value":200},{"key":"URUNIT","value":12},{"key":"CRYPTYK","value":15},{"key":"TronRoyal","value":10}],"assetV2":[{"key":"1000542","value":62},{"key":"1000567","value":0}],"balance":346991703615806,"create_time":1535532969000,"free_asset_net_usageV2":[{"key":"1000542","value":0},{"key":"1000567","value":0}],"free_net_usage":4828,"latest_consume_free_time":1592751174000,"latest_opration_time":1592753721000,"trc20":[{"TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9":"955973733483987848990056"},{"TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7":"191543058623486"},{"TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK":"100000000000000"},{"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t":"6849738905400"},{"TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e":"5000000000"},{"TJSF4iVkzkRkYwEVNkqJkeGDaZpnFbGy9x":"500000000"},{"TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm":"20000000"},{"TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF":"175798"},{"TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG":"20000"},{"TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak":"1"}]}]}` -) diff --git a/platform/tron/transaction_test.go b/platform/tron/transaction_test.go index eb8f39e6e..556ff753a 100644 --- a/platform/tron/transaction_test.go +++ b/platform/tron/transaction_test.go @@ -2,94 +2,60 @@ package tron import ( "encoding/json" + "net/http/httptest" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" "github.com/trustwallet/golibs/tokentype" - "net/http/httptest" - "testing" ) -const transferSrc = ` -{ - "block_timestamp": 1564797900000, - "raw_data": { - "contract": [ - { - "parameter": { - "value": { - "amount": 100666888000000, - "owner_address": "4182dd6b9966724ae2fdc79b416c7588da67ff1b35", - "to_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261" - } - }, - "type": "TransferContract" - } - ] - }, - "txID": "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df" -} -` - -const tokenTransferSrc = ` -{ - "block_timestamp": 1564797900000, - "raw_data": { - "contract": [ - { - "parameter": { - "value": { - "amount": 2776267, - "asset_name": "1002000", - "owner_address": "4182dd6b9966724ae2fdc79b416c7588da67ff1b35", - "to_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261" - } - }, - "type": "TransferAssetContract" - } - ] - }, - "txID": "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df" -} -` - -var transferDst = blockatlas.Tx{ - ID: "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df", - Coin: coin.TRX, - From: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", - To: "TAUN6FwrnwwmaEqYcckffC7wYmbaS6cBiX", - Fee: "0", // TODO - Date: 1564797900, - Block: 0, // TODO - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: "100666888000000", - Symbol: "TRX", - Decimals: 6, - }, -} +var ( + transferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer.json") + tokenTransferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "token_transfer.json") + wantedTransactionsWithToken, _ = mock.JsonFromFilePathToString("mocks/" + "token_txs_response.json") + wantedTransactionsOnly, _ = mock.JsonFromFilePathToString("mocks/" + "txs_response.json") + + transferDst = blockatlas.Tx{ + ID: "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df", + Coin: coin.TRX, + From: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", + To: "TAUN6FwrnwwmaEqYcckffC7wYmbaS6cBiX", + Fee: "0", // TODO + Date: 1564797900, + Block: 0, // TODO + Status: blockatlas.StatusCompleted, + Meta: blockatlas.Transfer{ + Value: "100666888000000", + Symbol: "TRX", + Decimals: 6, + }, + } -var tokenTransferDst = blockatlas.Tx{ - ID: "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df", - Coin: coin.TRX, - From: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", - To: "TAUN6FwrnwwmaEqYcckffC7wYmbaS6cBiX", - Fee: "0", // TODO - Date: 1564797900, - Block: 0, // TODO - Status: blockatlas.StatusCompleted, - Meta: blockatlas.TokenTransfer{ - Name: "BitTorrent", - Symbol: "BTT", - TokenID: "1002000", - Decimals: 6, - Value: "2776267", - From: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", - To: "TAUN6FwrnwwmaEqYcckffC7wYmbaS6cBiX", - }, -} + tokenTransferDst = blockatlas.Tx{ + ID: "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df", + Coin: coin.TRX, + From: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", + To: "TAUN6FwrnwwmaEqYcckffC7wYmbaS6cBiX", + Fee: "0", // TODO + Date: 1564797900, + Block: 0, // TODO + Status: blockatlas.StatusCompleted, + Meta: blockatlas.TokenTransfer{ + Name: "BitTorrent", + Symbol: "BTT", + TokenID: "1002000", + Decimals: 6, + Value: "2776267", + From: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", + To: "TAUN6FwrnwwmaEqYcckffC7wYmbaS6cBiX", + }, + } -var assetInfo = AssetInfo{Name: "BitTorrent", Symbol: "BTT", Decimals: 6, ID: 1002000} + assetInfo = AssetInfo{Name: "BitTorrent", Symbol: "BTT", Decimals: 6, ID: 1002000} +) type test struct { name string @@ -146,7 +112,7 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { rawRes, err := json.Marshal(res) assert.Nil(t, err) - assert.Equal(t, wantedTransactionsOnly, string(rawRes)) + assert.JSONEq(t, wantedTransactionsOnly, string(rawRes)) } func TestPlatform_GetTokenTxsByAddress(t *testing.T) { @@ -159,7 +125,7 @@ func TestPlatform_GetTokenTxsByAddress(t *testing.T) { rawRes, err := json.Marshal(res) assert.Nil(t, err) - assert.Equal(t, wantedTransactionsWithToken, string(rawRes)) + assert.JSONEq(t, wantedTransactionsWithToken, string(rawRes)) } func Test_getTokenType(t *testing.T) { @@ -177,8 +143,3 @@ func Test_getTokenType(t *testing.T) { }) } } - -var ( - wantedTransactionsWithToken = `[{"id":"fb078403adfee637608c3906d9d21dd158611aba149b9993f43d0f292ce543a0","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","fee":"0","date":1592757117,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"500000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A"}},{"id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","fee":"0","date":1592757066,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"50000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd"}},{"id":"c4052b526e5cd21e1f023c31cce6b6a13eb9d8aeae3ae80fcefe6038dfbeb022","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd","fee":"0","date":1592757066,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"50000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXJTFuXzfoPbWKCnw47AYxMzgVPUyhJGRd"}},{"id":"0b52a4ef9fb8c13fbfae2b8c3506333ec1d718f307062a15f170562818a01d0a","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV","fee":"0","date":1592756784,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"3988000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TFNEJYAKBVgc17X6fPppZ8ayaf9yswmMYV"}},{"id":"19d2ec6174bf64beb1061475f6429cba03b64944a763686cc3551447d0e8d9d5","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am","fee":"0","date":1592756763,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"640990000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGYETHZr2MTkFDe8GqwdVFPfadofTVk4am"}},{"id":"efb7d44305759cfb189c9fd22720609a2ddeb7fbd7c8afe1dd8851342471da8d","coin":195,"from":"TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","fee":"0","date":1592756631,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"1062000000","from":"TAxbLztoanFhYu4TuS5RabaJYGnUkfzNKG","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D"}},{"id":"48bd90dc3f12086178e65b9389caa8b3c74683937b86d4d61cdec77f0095994a","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A","fee":"0","date":1592756610,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"2000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGg7zHY9qd36aN3jLVDDRuiFeJjaaAtx8A"}},{"id":"afd5ae7e2462c9cc899c7f730b90fd2a5e4c1315e836c92468b504ed85f0b798","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R","fee":"0","date":1592756589,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"1000000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TN6Wy4j37wn3vxynynrKemWhDsUBHYje3R"}},{"id":"3d613031f4b2a0e19deeea030d1d18599b6d9799d2dd530005ead9712c6d219d","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"21200000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TXP7prwMqugLFWZRwcJAWuKZ4UN4wz3ifq"}},{"id":"cbe359c2574efbdc8fc6a892ffc54812837295067c9816d41734126c82d0c141","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"125000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TBStJt5wDtLqeUvGEasqd55uo1CbDTCsf5"}},{"id":"c87248b02a4caaa6f443c1b8c4d4588c8dd281a4687b73e6afecfba6741b50d8","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"5277600000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TJ2qhZSQ9g5YqEAJgYfPZZxn1djbf5ogkC"}},{"id":"8584f1b6a70ead8232fed19bd653ba13e4c2a8befd070f4a9a06eca3a2e3e548","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"485342000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TRqyhrttStrn1o7gS3mmgKrmkVw6qyw23W"}},{"id":"2b28b69e6747db68647acc3a62c45da5355b97acd8d2c260ee752aa9bd63a624","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"1000000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TLdYhJeKCLKxVm33JL8GAyi6i6zrSz8VFr"}},{"id":"1da6576dec0bd303f56cbfb5712f782e0a56a8713cb661f8afd2f2533e5c6209","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"2000000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TDpRQi5HguNpasa9Cn7AJyrn646nRDAH6x"}},{"id":"f9c86cce1873cb816d6cd8718e76df8839172add293bbc8d11a5f98c80f9e322","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK","fee":"0","date":1592756583,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"24216600000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TGy3K5iDbxm8SM34UTWWniNsS13FtLnHkK"}},{"id":"75eb35734857daa79c38ef923a7e7eb2e3dfb23d2722762fd2b180651021643f","coin":195,"from":"TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","fee":"0","date":1592756541,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"8241997837","from":"TGMTZMty79L9psKi5b4vwXZPJaiCb9k6mV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D"}},{"id":"adee73dadce006ff848ff30d8c5c41f033be2e5e1a8b875f6dbbaab524177d08","coin":195,"from":"TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","fee":"0","date":1592756220,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"18000000000","from":"TUwgGpDrVBc3uDZg3Tj9BZZN8xkLK29yzH","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D"}},{"id":"3655a1156c9adcb876c6c9c9e0f5f1f39704ac4c7296fea05fedf5ca8f6b1a19","coin":195,"from":"TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","fee":"0","date":1592755962,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"863399098","from":"TMaDtMFGJ8BBiNXchGBQmRBWi2mpfi2kdV","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D"}},{"id":"03574741eb0016050a19f181e4acc4b20b70f41e11e63140c9556c31eae09fba","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ","fee":"0","date":1592755740,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"20000000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TH7AaBSjS4NYuF3r8vXQcuwVXmGrv9iwYQ"}},{"id":"f3aa00595996e31dbe9528a3cb21bff987f333bf1f675420ba4fa2ad43c8205f","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug","fee":"0","date":1592755722,"block":0,"status":"completed","sequence":0,"type":"token_transfer","memo":"","metadata":{"name":"Tether USD","symbol":"USDT","token_id":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","decimals":6,"value":"21161340000","from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9D","to":"TA1VFEzYiU8oB9P1xdhMaFJ7BZ6FvUTyug"}}]` - wantedTransactionsOnly = `[{"id":"3fca53c08ccb48bb625439a58998713d8ecc3dc1348cc3cfab912e0815b62b1a","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","to":"TVmkAmaQrY6raatYozLtcQCGqWP6VaPnHU","fee":"0","date":1592755098,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"13195916000","symbol":"TRX","decimals":6}},{"id":"b38fb6328e1fa622b7762eed856778551845c33723491e36baf357f00cc48002","coin":195,"from":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","to":"TDfVk6U7i6m82ZCRprbrfz7QE3sTEnN1Xs","fee":"0","date":1592754717,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"8737000000","symbol":"TRX","decimals":6}},{"id":"82efc8456a3c38a0919af416a53363405ced78db7c13e1b94a79ebcea98f9909","coin":195,"from":"TVqx5Dx54HgBQFfpN7KN4MWiHEnRXbch7a","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","fee":"0","date":1592754447,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"2538461","symbol":"TRX","decimals":6}},{"id":"a336bd174c127d38bf2325bc9c927059af099e8cfb91159750a1b1be16dd0bd4","coin":195,"from":"TYCwQ4bC1mHR6heAe1qgHrktFtyJ8mKkC3","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","fee":"0","date":1592754444,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"30000000","symbol":"TRX","decimals":6}},{"id":"007bbcc3855f4bf51bd76e63d7776160c115c803e227f7c44c7d1fd1bd587611","coin":195,"from":"TSUCQKEKhXREEaod5WgSKETKjYUhL2TUV7","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","fee":"0","date":1592754444,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"111337320","symbol":"TRX","decimals":6}},{"id":"9351e87b129142844f000a52911daf36fc95677dfe2846abcd28ea0d8fe2e2ea","coin":195,"from":"TFUP7BdBj61oyTHt52McZC5Q1w6CKzyNCN","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","fee":"0","date":1592754444,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"200000000","symbol":"TRX","decimals":6}},{"id":"008ebda5749c38e26a69717faa66e6f4fd8a0d358c9b947192765cc9843cff5a","coin":195,"from":"TGkLtfPuPhkG4RzewwkgNHfPxTwb5YRq6b","to":"TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R","fee":"0","date":1592754444,"block":0,"status":"completed","sequence":0,"type":"transfer","memo":"","metadata":{"value":"511000000","symbol":"TRX","decimals":6}}]` -) diff --git a/platform/vechain/mocks/transfer.json b/platform/vechain/mocks/transfer.json new file mode 100644 index 000000000..0df4afced --- /dev/null +++ b/platform/vechain/mocks/transfer.json @@ -0,0 +1,13 @@ +{ + "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", + "recipient": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", + "amount": "0x12b1815d00738000", + "meta": { + "blockID": "0x004313a4bd4286e821b684cc1749deb3df12fa2a8114435fbd35baa155e82016", + "blockNumber": 4395940, + "blockTimestamp": 1574410670, + "txID": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "clauseIndex": 0 + } +} diff --git a/platform/vechain/mocks/transfer_log.json b/platform/vechain/mocks/transfer_log.json new file mode 100644 index 000000000..e66c5e7b5 --- /dev/null +++ b/platform/vechain/mocks/transfer_log.json @@ -0,0 +1,25 @@ +{ + "id": "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", + "chainTag": 74, + "blockRef": "0x0042e02a2ae04200", + "expiration": 720, + "clauses": [ + { + "to": "0x0000000000000000000000000000456e65726779", + "value": "0x0", + "data": "0xa9059cbb000000000000000000000000b5e883349e68ab59307d1604555ac890fac47128000000000000000000000000000000000000000000000003afb087b876900000" + } + ], + "gasPriceCoef": 0, + "gas": 80000, + "origin": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", + "delegator": null, + "nonce": "0x4a8569d", + "dependsOn": null, + "size": 189, + "meta": { + "blockID": "0x0042e02cebd1bec003d31526dba338c1b9eeeefdef722fb147e9d31690fbff1e", + "blockNumber": 4382764, + "blockTimestamp": 1574278180 + } +} diff --git a/platform/vechain/mocks/transfer_receipt.json b/platform/vechain/mocks/transfer_receipt.json new file mode 100644 index 000000000..a134f1372 --- /dev/null +++ b/platform/vechain/mocks/transfer_receipt.json @@ -0,0 +1,31 @@ +{ + "gasUsed": 36582, + "gasPayer": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", + "paid": "0x1fbad5f2e25570000", + "reward": "0x984d9c8dd8008000", + "reverted": false, + "meta": { + "blockID": "0x0042e02cebd1bec003d31526dba338c1b9eeeefdef722fb147e9d31690fbff1e", + "blockNumber": 4382764, + "blockTimestamp": 1574278180, + "txID": "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", + "txOrigin": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405" + }, + "outputs": [ + { + "contractAddress": null, + "events": [ + { + "address": "0x0000000000000000000000000000456e65726779", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000002c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", + "0x000000000000000000000000b5e883349e68ab59307d1604555ac890fac47128" + ], + "data": "0x000000000000000000000000000000000000000000000003afb087b876900000" + } + ], + "transfers": [] + } + ] +} diff --git a/platform/vechain/mocks/tx_id.json b/platform/vechain/mocks/tx_id.json new file mode 100644 index 000000000..8aa9827c3 --- /dev/null +++ b/platform/vechain/mocks/tx_id.json @@ -0,0 +1,4 @@ +{ + "gas": 21000, + "nonce": "0x8cff29df64a414f8" +} diff --git a/platform/vechain/transaction_test.go b/platform/vechain/transaction_test.go index 06d9f780d..56fcb4745 100644 --- a/platform/vechain/transaction_test.go +++ b/platform/vechain/transaction_test.go @@ -2,47 +2,61 @@ package vechain import ( "encoding/json" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "testing" + "github.com/trustwallet/golibs/mock" ) -const transferSrc = `{ - "sender": "0xb5e883349e68ab59307d1604555ac890fac47128", - "recipient": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", - "amount": "0x12b1815d00738000", - "meta": { - "blockID": "0x004313a4bd4286e821b684cc1749deb3df12fa2a8114435fbd35baa155e82016", - "blockNumber": 4395940, - "blockTimestamp": 1574410670, - "txID": "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", - "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128", - "clauseIndex": 0 - } - }` -const trxId = `{ - "gas": 21000, - "nonce": "0x8cff29df64a414f8" -}` +var ( + transferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer.json") + trxId, _ = mock.JsonFromFilePathToString("mocks/" + "tx_id.json") + transferLogSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer_log.json") + trxReceipt, _ = mock.JsonFromFilePathToString("mocks/" + "transfer_receipt.json") -var expectedTransfer = blockatlas.Tx{ - ID: "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", - Coin: coin.VET, - From: "0xB5e883349e68aB59307d1604555AC890fAC47128", - To: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", - Date: 1574410670, - Type: blockatlas.TxTransfer, - Fee: blockatlas.Amount("21000"), - Status: blockatlas.StatusCompleted, - Block: 4395940, - Direction: blockatlas.DirectionOutgoing, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1347000000000000000"), - Decimals: 18, - Symbol: "VET", - }, -} + expectedTransfer = blockatlas.Tx{ + ID: "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", + Coin: coin.VET, + From: "0xB5e883349e68aB59307d1604555AC890fAC47128", + To: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", + Date: 1574410670, + Type: blockatlas.TxTransfer, + Fee: blockatlas.Amount("21000"), + Status: blockatlas.StatusCompleted, + Block: 4395940, + Direction: blockatlas.DirectionOutgoing, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("1347000000000000000"), + Decimals: 18, + Symbol: "VET", + }, + } + expectedTransferLog = blockatlas.TxPage{ + { + ID: "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", + Coin: coin.VET, + From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", + To: "0x0000000000000000000000000000456E65726779", + Date: 1574278180, + Type: blockatlas.TxTokenTransfer, + Fee: blockatlas.Amount("36582000000000000000"), + Status: blockatlas.StatusCompleted, + Block: 4382764, + Direction: blockatlas.DirectionIncoming, + Meta: blockatlas.TokenTransfer{ + Name: gasTokenName, + Symbol: gasTokenSymbol, + TokenID: "0x0000000000000000000000000000456E65726779", + From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", + To: "0xB5e883349e68aB59307d1604555AC890fAC47128", + Value: blockatlas.Amount("68000000000000000000"), + Decimals: 18, + }, + }, + } +) func TestNormalizeTransaction(t *testing.T) { tests := []struct { @@ -75,88 +89,6 @@ func TestNormalizeTransaction(t *testing.T) { } } -const transferLogSrc = `{ - "id": "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", - "chainTag": 74, - "blockRef": "0x0042e02a2ae04200", - "expiration": 720, - "clauses": [ - { - "to": "0x0000000000000000000000000000456e65726779", - "value": "0x0", - "data": "0xa9059cbb000000000000000000000000b5e883349e68ab59307d1604555ac890fac47128000000000000000000000000000000000000000000000003afb087b876900000" - } - ], - "gasPriceCoef": 0, - "gas": 80000, - "origin": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", - "delegator": null, - "nonce": "0x4a8569d", - "dependsOn": null, - "size": 189, - "meta": { - "blockID": "0x0042e02cebd1bec003d31526dba338c1b9eeeefdef722fb147e9d31690fbff1e", - "blockNumber": 4382764, - "blockTimestamp": 1574278180 - } -}` - -const trxReceipt = `{ - "gasUsed": 36582, - "gasPayer": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", - "paid": "0x1fbad5f2e25570000", - "reward": "0x984d9c8dd8008000", - "reverted": false, - "meta": { - "blockID": "0x0042e02cebd1bec003d31526dba338c1b9eeeefdef722fb147e9d31690fbff1e", - "blockNumber": 4382764, - "blockTimestamp": 1574278180, - "txID": "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", - "txOrigin": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405" - }, - "outputs": [ - { - "contractAddress": null, - "events": [ - { - "address": "0x0000000000000000000000000000456e65726779", - "topics": [ - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - "0x0000000000000000000000002c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", - "0x000000000000000000000000b5e883349e68ab59307d1604555ac890fac47128" - ], - "data": "0x000000000000000000000000000000000000000000000003afb087b876900000" - } - ], - "transfers": [] - } - ] -}` - -var expectedTransferLog = blockatlas.TxPage{ - { - ID: "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", - Coin: coin.VET, - From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", - To: "0x0000000000000000000000000000456E65726779", - Date: 1574278180, - Type: blockatlas.TxTokenTransfer, - Fee: blockatlas.Amount("36582000000000000000"), - Status: blockatlas.StatusCompleted, - Block: 4382764, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.TokenTransfer{ - Name: gasTokenName, - Symbol: gasTokenSymbol, - TokenID: "0x0000000000000000000000000000456E65726779", - From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", - To: "0xB5e883349e68aB59307d1604555AC890fAC47128", - Value: blockatlas.Amount("68000000000000000000"), - Decimals: 18, - }, - }, -} - func TestNormalizeTokenTransaction(t *testing.T) { tests := []struct { name string diff --git a/platform/waves/mocks/different_txs.json b/platform/waves/mocks/different_txs.json new file mode 100644 index 000000000..2c1cdae4a --- /dev/null +++ b/platform/waves/mocks/different_txs.json @@ -0,0 +1,47 @@ +[ + [ + { + "type": 10, + "timestamp": 1516171819000, + "sender": "3MtrNP7AkTRuBhX4CBti6iT21pQpEnmHtyw", + "fee": 100000, + "alias": "ALIAS" + }, + { + "type": 10, + "id": "9q7X84wFuVvKqRdDQeWbtBmpsHt9SXFbvPPtUuKBVxxr", + "sender": "3MtrNP7AkTRuBhX4CBti6iT21pQpEnmHtyw", + "senderPublicKey": "G6h72icCSjdW2A89QWDb37hyXJoYKq3XuCUJY2joS3EU", + "fee": 100000000, + "timestamp": 46305781705234713, + "signature": "4gQyPXzJFEzMbsCd9u5n3B2WauEc4172ssyrXCL882oNa8NfNihnpKianHXrHWnZs1RzDLbQ9rcRYnSqxKWfEPJG", + "alias": "dajzmj6gfuzmbfnhamsbuxivc" + }, + { + "type": 4, + "id": "52GG9U2e6foYRKp5vAzsTQ86aDAABfRJ7synz7ohBp19", + "sender": "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", + "senderPublicKey": "CRxqEuxhdZBEHX42MU4FfyJxuHmbDBTaHMhM3Uki7pLw", + "recipient": "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", + "assetId": null, + "amount": 100000, + "feeAsset": null, + "fee": 100000, + "timestamp": 1479313236091, + "attachment": "string", + "signature": "GknccUA79dBcwWgKjqB7vYHcnsj7caYETfncJhRkkaetbQon7DxbpMmvK9LYqUkirJp17geBJCRTNkHEoAjtsUm", + "height": 7782 + }, + { + "type": 2, + "id": "4XE4M9eSoVWVdHwDYXqZsXhEc4q8PH9mDMUBegCSBBVHJyP2Yb1ZoGi59c1Qzq2TowLmymLNkFQjWp95CdddnyBW", + "fee": 100000, + "timestamp": 1479313097422, + "signature": "4XE4M9eSoVWVdHwDYXqZsXhEc4q8PH9mDMUBegCSBBVHJyP2Yb1ZoGi59c1Qzq2TowLmymLNkFQjWp95CdddnyBW", + "sender": "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", + "senderPublicKey": "CRxqEuxhdZBEHX42MU4FfyJxuHmbDBTaHMhM3Uki7pLw", + "recipient": "3N9iRMou3pgmyPbFZn5QZQvBTQBkL2fR6R1", + "amount": 1000000000 + } + ] +] diff --git a/platform/waves/mocks/transfer.json b/platform/waves/mocks/transfer.json new file mode 100644 index 000000000..db2a2e229 --- /dev/null +++ b/platform/waves/mocks/transfer.json @@ -0,0 +1,20 @@ +{ + "type": 4, + "id": "7QoQc9qMUBCfY4QV35mgBsT8eTXybvGkM2HTumtAvBUL", + "sender": "3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", + "senderPublicKey": "Ao159h5j1piHBhoEbCAYyaiKNd6uoKvcdwzRZF9za3Vv", + "fee": 100000, + "timestamp": 1561048131740, + "signature": "4WjDwn5t34PLHzgH1NfA4DYdt4PdTbGQDjDdxwKrp82QTQSHFRrgSJXWU2FTYe82afvgUDhnipSKxaiGzMWWo2HW", + "proofs": [ + "4WjDwn5t34PLHzgH1NfA4DYdt4PdTbGQDjDdxwKrp82QTQSHFRrgSJXWU2FTYe82afvgUDhnipSKxaiGzMWWo2HW" + ], + "version": 1, + "recipient": "3PKWyVAmHom1sevggiXVfbGUc3kS85qT4Va", + "assetId": null, + "feeAssetId": null, + "feeAsset": null, + "amount": 9481600000, + "attachment": "", + "height": 1580410 +} diff --git a/platform/waves/transaction_test.go b/platform/waves/transaction_test.go index 0848cc02d..95ad5b909 100644 --- a/platform/waves/transaction_test.go +++ b/platform/waves/transaction_test.go @@ -1,112 +1,52 @@ package waves import ( - "bytes" "encoding/json" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "testing" + + "github.com/stretchr/testify/assert" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/mock" ) -const transferV1 = ` -{ - "type":4, - "id":"7QoQc9qMUBCfY4QV35mgBsT8eTXybvGkM2HTumtAvBUL", - "sender":"3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", - "senderPublicKey":"Ao159h5j1piHBhoEbCAYyaiKNd6uoKvcdwzRZF9za3Vv", - "fee":100000, - "timestamp":1561048131740, - "signature":"4WjDwn5t34PLHzgH1NfA4DYdt4PdTbGQDjDdxwKrp82QTQSHFRrgSJXWU2FTYe82afvgUDhnipSKxaiGzMWWo2HW", - "proofs":["4WjDwn5t34PLHzgH1NfA4DYdt4PdTbGQDjDdxwKrp82QTQSHFRrgSJXWU2FTYe82afvgUDhnipSKxaiGzMWWo2HW"], - "version":1, - "recipient":"3PKWyVAmHom1sevggiXVfbGUc3kS85qT4Va", - "assetId":null, - "feeAssetId":null, - "feeAsset":null, - "amount":9481600000, - "attachment":"", - "height":1580410 -}` - -const differentTxs = ` -[[ - { - "type": 10, - "timestamp": 1516171819000, - "sender": "3MtrNP7AkTRuBhX4CBti6iT21pQpEnmHtyw", - "fee": 100000, - "alias": "ALIAS" - }, - { - "type":10, - "id":"9q7X84wFuVvKqRdDQeWbtBmpsHt9SXFbvPPtUuKBVxxr", - "sender":"3MtrNP7AkTRuBhX4CBti6iT21pQpEnmHtyw", - "senderPublicKey":"G6h72icCSjdW2A89QWDb37hyXJoYKq3XuCUJY2joS3EU", - "fee":100000000, - "timestamp":46305781705234713, - "signature":"4gQyPXzJFEzMbsCd9u5n3B2WauEc4172ssyrXCL882oNa8NfNihnpKianHXrHWnZs1RzDLbQ9rcRYnSqxKWfEPJG", - "alias":"dajzmj6gfuzmbfnhamsbuxivc" - }, - { - "type": 4, - "id": "52GG9U2e6foYRKp5vAzsTQ86aDAABfRJ7synz7ohBp19", - "sender": "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", - "senderPublicKey": "CRxqEuxhdZBEHX42MU4FfyJxuHmbDBTaHMhM3Uki7pLw", - "recipient": "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", - "assetId": null, - "amount": 100000, - "feeAsset": null, - "fee": 100000, - "timestamp": 1479313236091, - "attachment": "string", - "signature": "GknccUA79dBcwWgKjqB7vYHcnsj7caYETfncJhRkkaetbQon7DxbpMmvK9LYqUkirJp17geBJCRTNkHEoAjtsUm", - "height": 7782 - }, - { - "type": 2, - "id": "4XE4M9eSoVWVdHwDYXqZsXhEc4q8PH9mDMUBegCSBBVHJyP2Yb1ZoGi59c1Qzq2TowLmymLNkFQjWp95CdddnyBW", - "fee": 100000, - "timestamp": 1479313097422, - "signature": "4XE4M9eSoVWVdHwDYXqZsXhEc4q8PH9mDMUBegCSBBVHJyP2Yb1ZoGi59c1Qzq2TowLmymLNkFQjWp95CdddnyBW", - "sender": "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", - "senderPublicKey": "CRxqEuxhdZBEHX42MU4FfyJxuHmbDBTaHMhM3Uki7pLw", - "recipient": "3N9iRMou3pgmyPbFZn5QZQvBTQBkL2fR6R1", - "amount": 1000000000 +var ( + transferV1, _ = mock.JsonFromFilePathToString("mocks/" + "transfer.json") + differentTxs, _ = mock.JsonFromFilePathToString("mocks/" + "different_txs.json") + + transferV1Obj = blockatlas.Tx{ + ID: "7QoQc9qMUBCfY4QV35mgBsT8eTXybvGkM2HTumtAvBUL", + Coin: 5741564, + From: "3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", + To: "3PKWyVAmHom1sevggiXVfbGUc3kS85qT4Va", + Fee: "100000", + Date: 1561048131, + Block: 1580410, + Status: blockatlas.StatusCompleted, + Memo: "", + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("9481600000"), + Symbol: "WAVES", + Decimals: 8, + }, } -]]` - -var transferV1Obj = blockatlas.Tx{ - ID: "7QoQc9qMUBCfY4QV35mgBsT8eTXybvGkM2HTumtAvBUL", - Coin: 5741564, - From: "3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", - To: "3PKWyVAmHom1sevggiXVfbGUc3kS85qT4Va", - Fee: "100000", - Date: 1561048131, - Block: 1580410, - Status: blockatlas.StatusCompleted, - Memo: "", - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("9481600000"), - Symbol: "WAVES", - Decimals: 8, - }, -} -var differentTxsObj = blockatlas.Tx{ - ID: "52GG9U2e6foYRKp5vAzsTQ86aDAABfRJ7synz7ohBp19", - Coin: 5741564, - From: "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", - To: "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", - Fee: "100000", - Date: 1479313236, - Block: 7782, - Memo: "string", - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("100000"), - Symbol: "WAVES", - Decimals: 8, - }, -} + differentTxsObj = blockatlas.Tx{ + ID: "52GG9U2e6foYRKp5vAzsTQ86aDAABfRJ7synz7ohBp19", + Coin: 5741564, + From: "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", + To: "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", + Fee: "100000", + Date: 1479313236, + Block: 7782, + Memo: "string", + Status: blockatlas.StatusCompleted, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("100000"), + Symbol: "WAVES", + Decimals: 8, + }, + } +) type txParseTest struct { name string @@ -153,11 +93,7 @@ func testParseTx(t *testing.T, _test *txParseTest) { t.Fatal(err) } - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error(_test.name + ": tx don't equal") - } + assert.JSONEq(t, string(resJSON), string(dstJSON)) } func testFilterTxs(t *testing.T, _test *txFilterTest) { @@ -187,9 +123,5 @@ func testFilterTxs(t *testing.T, _test *txFilterTest) { t.Fatal(err) } - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error(_test.name + ": txs don't equal") - } + assert.JSONEq(t, string(resJSON), string(dstJSON)) } diff --git a/platform/zilliqa/mocks/transfer.json b/platform/zilliqa/mocks/transfer.json new file mode 100644 index 000000000..377285b75 --- /dev/null +++ b/platform/zilliqa/mocks/transfer.json @@ -0,0 +1,13 @@ +{ + "hash": "0xd44413c79e7518152f3b05ef1edff8ef59afd06119b16d09c8bc72e94fed7843", + "blockHeight": 104282, + "from": "0x88af5ba10796d9091d6893eed4db23ef0bbbca37", + "to": "0x7fccacf066a5f26ee3affc2ed1fa9810deaa632c", + "value": "7997000000000", + "fee": "1000000000", + "timestamp": 1557889788637, + "signature": "0xF0F159C5B47079E36AABC7693E61FEE9D104BDE34F4FEADA62A5066F6363E05B382E65B9381CE8138CC6824A5B62CC60EDA8B7CF13A65264F8482279DF6F768B", + "nonce": "3", + "receiptSuccess": true, + "events": [] +} diff --git a/platform/zilliqa/transaction.go b/platform/zilliqa/transaction.go index 4d55afc5d..9cd195a73 100644 --- a/platform/zilliqa/transaction.go +++ b/platform/zilliqa/transaction.go @@ -33,6 +33,7 @@ func Normalize(srcTx *Tx) (tx blockatlas.Tx) { To: srcTx.To, Fee: blockatlas.Amount(srcTx.Fee), Block: srcTx.BlockHeight, + Status: blockatlas.StatusCompleted, Sequence: srcTx.NonceValue(), Meta: blockatlas.Transfer{ Value: blockatlas.Amount(srcTx.Value), diff --git a/platform/zilliqa/transaction_test.go b/platform/zilliqa/transaction_test.go index 046fd522a..7980da449 100644 --- a/platform/zilliqa/transaction_test.go +++ b/platform/zilliqa/transaction_test.go @@ -1,86 +1,57 @@ package zilliqa import ( - "bytes" - "encoding/json" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "reflect" "testing" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" ) -const transferTransaction = ` -{ - "hash": "0xd44413c79e7518152f3b05ef1edff8ef59afd06119b16d09c8bc72e94fed7843", - "blockHeight": 104282, - "from": "0x88af5ba10796d9091d6893eed4db23ef0bbbca37", - "to": "0x7fccacf066a5f26ee3affc2ed1fa9810deaa632c", - "value": "7997000000000", - "fee": "1000000000", - "timestamp": 1557889788637, - "signature": "0xF0F159C5B47079E36AABC7693E61FEE9D104BDE34F4FEADA62A5066F6363E05B382E65B9381CE8138CC6824A5B62CC60EDA8B7CF13A65264F8482279DF6F768B", - "nonce": "3", - "receiptSuccess": true, - "events": [] -}` - -var transferDst = blockatlas.Tx{ - ID: "0xd44413c79e7518152f3b05ef1edff8ef59afd06119b16d09c8bc72e94fed7843", - Coin: coin.ZIL, - From: "0x88af5ba10796d9091d6893eed4db23ef0bbbca37", - To: "0x7fccacf066a5f26ee3affc2ed1fa9810deaa632c", - Fee: "1000000000", - Date: 1557889788, - Block: 104282, - Status: blockatlas.StatusCompleted, - Sequence: 3, - Memo: "", - Meta: blockatlas.Transfer{ - Value: "7997000000000", - Symbol: "ZIL", - Decimals: 12, - }, -} - -type test struct { - name string - apiResponse string - expected *blockatlas.Tx - token string -} - -func TestNormalize(t *testing.T) { - testNormalize(t, &test{ - name: "transfer", - apiResponse: transferTransaction, - expected: &transferDst, - token: "", - }) -} - -func testNormalize(t *testing.T, _test *test) { - var srcTx Tx - err := json.Unmarshal([]byte(_test.apiResponse), &srcTx) - if err != nil { - t.Error(err) - return +func TestNormalizeTx(t *testing.T) { + type args struct { + filename string } - - tx := Normalize(&srcTx) - - resJSON, err := json.Marshal(&tx) - if err != nil { - t.Fatal(err) + tests := []struct { + name string + args args + wantTx blockatlas.Tx + wantErr bool + }{ + { + name: "Test normalize transaction", + args: args{ + filename: "transfer.json", + }, + wantTx: blockatlas.Tx{ + ID: "0xd44413c79e7518152f3b05ef1edff8ef59afd06119b16d09c8bc72e94fed7843", + Coin: coin.ZIL, + From: "0x88af5ba10796d9091d6893eed4db23ef0bbbca37", + To: "0x7fccacf066a5f26ee3affc2ed1fa9810deaa632c", + Fee: "1000000000", + Date: 1557889788, + Block: 104282, + Status: blockatlas.StatusCompleted, + Sequence: 3, + Memo: "", + Meta: blockatlas.Transfer{ + Value: "7997000000000", + Symbol: "ZIL", + Decimals: 12, + }, + }, + }, } - - dstJSON, err := json.Marshal(_test.expected) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(resJSON, dstJSON) { - println(string(resJSON)) - println(string(dstJSON)) - t.Error("transfer: tx don't equal") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx Tx + _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + gotTx := Normalize(&srcTx) + if !reflect.DeepEqual(gotTx, tt.wantTx) { + t.Errorf("NormalizeTx() gotTx = %v, want %v", gotTx, tt.wantTx) + } + }) } } diff --git a/services/assets/validator_test.go b/services/assets/validator_test.go index 7d4974181..7b4f72f1a 100644 --- a/services/assets/validator_test.go +++ b/services/assets/validator_test.go @@ -22,6 +22,7 @@ var ( Status: true, }, } + assets1 = []AssetValidator{ { ID: "test1", @@ -38,6 +39,7 @@ var ( Status: ValidatorStatus{Disabled: true}, }, } + assets2 = []AssetValidator{ { ID: "test1", @@ -72,6 +74,7 @@ var ( Staking: StakingInfo{MinDelegation: 10}, }, } + expectTezosVal1 = blockatlas.StakeValidator{ ID: "test1", Status: true, Info: blockatlas.StakeValidatorInfo{ @@ -84,6 +87,7 @@ var ( MinimumAmount: blockatlas.Amount("10"), }, } + expectedCosmosStakeValidator = blockatlas.StakeValidator{ ID: "test1", Status: true, Info: blockatlas.StakeValidatorInfo{ @@ -96,6 +100,7 @@ var ( MinimumAmount: blockatlas.Amount("0"), }, } + expectedCosmosStakeValidatorDisabled1 = blockatlas.StakeValidator{ ID: "test1", Status: false, Info: blockatlas.StakeValidatorInfo{ @@ -108,6 +113,7 @@ var ( MinimumAmount: blockatlas.Amount("0"), }, } + expectedCosmosStakeValidatorDisabled2 = blockatlas.StakeValidator{ ID: "test2", Status: false, Info: blockatlas.StakeValidatorInfo{ diff --git a/tests/integration/db_test/db_run_test.go b/tests/integration/db_test/db_run_test.go index 86847e667..986418483 100644 --- a/tests/integration/db_test/db_run_test.go +++ b/tests/integration/db_test/db_run_test.go @@ -3,11 +3,12 @@ package db_test import ( + "os" + "testing" + "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/tests/integration/setup" - "os" - "testing" ) var database *db.Instance From f7001674553836acfffb83bfbeb189267248593b Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 8 Jan 2021 09:49:08 +0800 Subject: [PATCH 452/506] [Tezos] Adopt new block api url (#1353) * Adopt new url * op is deprecated --- platform/tezos/client.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/tezos/client.go b/platform/tezos/client.go index 5a07f7456..ec8936cea 100644 --- a/platform/tezos/client.go +++ b/platform/tezos/client.go @@ -30,13 +30,13 @@ func (c *Client) GetCurrentBlock() (int64, error) { } func (c *Client) GetBlockByNumber(num int64, txType []string) ([]Transaction, error) { - var blockOps ExplorerAccount - path := fmt.Sprintf("account/%d/op", num) + var blockOps []Transaction + path := fmt.Sprintf("block/%d/operations", num) types := strings.Join(txType, ",") err := c.Get(&blockOps, path, url.Values{ "limit": {"5000"}, // https://github.com/blockwatch-cc/tzindex/issues/17#issuecomment-604967761 "type": {types}, }) - return blockOps.Transactions, err + return blockOps, err } From 962a8b8cf0f16274f6a73c3ddf18ef14717c35ab Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Fri, 8 Jan 2021 23:54:41 -0800 Subject: [PATCH 453/506] [Subscriptions] Remove pg deadlock for create subscription (#1356) * Remove unnecessary logging * Add log to get GetTransactionsFromDelivery * Remove CoinStatus * Update subscription.go --- db/subscription.go | 8 +++++--- pkg/blockatlas/observer.go | 5 ----- platform/cosmos/client.go | 5 ++--- platform/kava/client.go | 5 ++--- services/notifier/base.go | 3 ++- services/tokenindexer/indexer.go | 2 +- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/db/subscription.go b/db/subscription.go index 79b638357..4a607f94e 100644 --- a/db/subscription.go +++ b/db/subscription.go @@ -3,6 +3,7 @@ package db import ( "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" + "gorm.io/gorm" "gorm.io/gorm/clause" ) @@ -14,9 +15,10 @@ func (i *Instance) CreateSubscriptions(addresses []blockatlas.Subscription) erro for _, address := range addresses { result = append(result, models.Subscription{Address: address.AddressID()}) } - return i.Gorm. - Clauses(clause.OnConflict{DoNothing: true}). - Create(&result).Error + + return i.Gorm.Transaction(func(tx *gorm.DB) error { + return tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error + }) } func (i *Instance) GetSubscriptions(addresses []string) ([]models.Subscription, error) { diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go index 166114da6..bb7aa0d19 100644 --- a/pkg/blockatlas/observer.go +++ b/pkg/blockatlas/observer.go @@ -16,11 +16,6 @@ type ( Coin uint `json:"coin"` Address string `json:"address"` } - - CoinStatus struct { - Height int64 `json:"height"` - Error string `json:"error,omitempty"` - } ) func (v *Subscription) AddressID() string { diff --git a/platform/cosmos/client.go b/platform/cosmos/client.go index cf4b0ed0f..6014fefe5 100644 --- a/platform/cosmos/client.go +++ b/platform/cosmos/client.go @@ -6,7 +6,6 @@ import ( "strconv" "time" - log "github.com/sirupsen/logrus" "github.com/trustwallet/golibs/client" ) @@ -71,7 +70,7 @@ func (c *Client) GetDelegations(address string) (delegations Delegations, err er path := fmt.Sprintf("staking/delegators/%s/delegations", address) err = c.Get(&delegations, path, nil) if err != nil { - log.Error(err, "Cosmos: Failed to get delegations for address") + return delegations, err } return } @@ -80,7 +79,7 @@ func (c *Client) GetUnbondingDelegations(address string) (delegations UnbondingD path := fmt.Sprintf("staking/delegators/%s/unbonding_delegations", address) err = c.Get(&delegations, path, nil) if err != nil { - log.Error(err, "Cosmos: Failed to get unbonding delegations for address") + return delegations, err } return } diff --git a/platform/kava/client.go b/platform/kava/client.go index 6359b0400..5bfc03543 100644 --- a/platform/kava/client.go +++ b/platform/kava/client.go @@ -6,7 +6,6 @@ import ( "strconv" "time" - log "github.com/sirupsen/logrus" "github.com/trustwallet/golibs/client" ) @@ -70,7 +69,7 @@ func (c *Client) GetDelegations(address string) (delegations Delegations, err er path := fmt.Sprintf("staking/delegators/%s/delegations", address) err = c.Get(&delegations, path, nil) if err != nil { - log.Error(err, "Cosmos: Failed to get delegations for address") + return delegations, err } return } @@ -79,7 +78,7 @@ func (c *Client) GetUnbondingDelegations(address string) (delegations UnbondingD path := fmt.Sprintf("staking/delegators/%s/unbonding_delegations", address) err = c.Get(&delegations, path, nil) if err != nil { - log.Error(err, "Cosmos: Failed to get unbonding delegations for address") + return delegations, err } return } diff --git a/services/notifier/base.go b/services/notifier/base.go index d5193ae88..872dd3b86 100644 --- a/services/notifier/base.go +++ b/services/notifier/base.go @@ -16,7 +16,8 @@ const ( func RunNotifier(database *db.Instance, delivery amqp.Delivery) error { txs, err := GetTransactionsFromDelivery(delivery, Notifier) if err != nil { - log.Error("failed to get transactions", err) + log.WithFields(log.Fields{"service": Notifier, "txs": txs}).Error("failed to get transactions: ", err) + return err } allAddresses := make([]string, 0) diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index e8de8b150..fac397524 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -19,7 +19,7 @@ const ( func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) error { txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenIndexer) if err != nil { - log.WithFields(log.Fields{"service": TokenIndexer}).Error("failed to get transactions", err) + log.WithFields(log.Fields{"service": TokenIndexer, "txs": txs}).Error("failed to get transactions: ", err) return err } txs = txs.FilterTransactionsByType([]blockatlas.TransactionType{ From 91419e211a73db69b5aa0b53f44141bceea073de Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 12 Jan 2021 11:00:05 +0800 Subject: [PATCH 454/506] Fix vechain normalize reverted tx (#1357) --- platform/vechain/mocks/reverted_receipt.json | 15 +++ platform/vechain/mocks/reverted_tx.json | 30 ++++++ platform/vechain/model.go | 5 +- platform/vechain/transaction.go | 45 ++++++-- platform/vechain/transaction_test.go | 106 +++++++++++-------- 5 files changed, 143 insertions(+), 58 deletions(-) create mode 100644 platform/vechain/mocks/reverted_receipt.json create mode 100644 platform/vechain/mocks/reverted_tx.json diff --git a/platform/vechain/mocks/reverted_receipt.json b/platform/vechain/mocks/reverted_receipt.json new file mode 100644 index 000000000..70877ac3f --- /dev/null +++ b/platform/vechain/mocks/reverted_receipt.json @@ -0,0 +1,15 @@ +{ + "gasUsed": 82618, + "gasPayer": "0x7cffb7632252bae3766734d61f148f0ea78fc08c", + "paid": "0x47a8e194565390000", + "reward": "0x157f76dfb37f78000", + "reverted": true, + "meta": { + "blockID": "0x0079ce53965d837f959154813e163ce4d89f51421bdd540f3facb454929ab7fe", + "blockNumber": 7982675, + "blockTimestamp": 1610326580, + "txID": "0x7fae32a743e42eaec54642e2a5742a185299f5b4bedaf12c60f65705661de932", + "txOrigin": "0x7cffb7632252bae3766734d61f148f0ea78fc08c" + }, + "outputs": [] +} diff --git a/platform/vechain/mocks/reverted_tx.json b/platform/vechain/mocks/reverted_tx.json new file mode 100644 index 000000000..fa130c379 --- /dev/null +++ b/platform/vechain/mocks/reverted_tx.json @@ -0,0 +1,30 @@ +{ + "id": "0x7fae32a743e42eaec54642e2a5742a185299f5b4bedaf12c60f65705661de932", + "chainTag": 74, + "blockRef": "0x0079ce52eccee5e8", + "expiration": 18, + "clauses": [ + { + "to": "0xf8e1faa0367298b55f57ed17f7a2ff3f5f1d1628", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000c96b1e1a436c5ecf150ac7a7de64c0eec73883e000000000000000000000000000000000000000000000001043561a8829300000" + }, + { + "to": "0xc96b1e1a436c5ecf150ac7a7de64c0eec73883e0", + "value": "0x0", + "data": "0x6d6aa5bb000000000000000000000000000000000000000000000000000000003b9aca5800000000000000000000000000000000000000000000001043561a8829300000" + } + ], + "gasPriceCoef": 0, + "gas": 82618, + "origin": "0x7cffb7632252bae3766734d61f148f0ea78fc08c", + "delegator": null, + "nonce": "0x15a6dce553e53070", + "dependsOn": null, + "size": 286, + "meta": { + "blockID": "0x0079ce53965d837f959154813e163ce4d89f51421bdd540f3facb454929ab7fe", + "blockNumber": 7982675, + "blockTimestamp": 1610326580 + } +} diff --git a/platform/vechain/model.go b/platform/vechain/model.go index 0d9fff073..4e1fda3a9 100644 --- a/platform/vechain/model.go +++ b/platform/vechain/model.go @@ -55,8 +55,9 @@ type Tx struct { } type TxReceipt struct { - Paid string `json:"paid"` - Outputs []Output `json:"outputs"` + Reverted bool `json:"reverted"` + Paid string `json:"paid"` + Outputs []Output `json:"outputs"` } type Output struct { diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 74b65edfc..6d11df8fd 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -74,16 +74,47 @@ func (p *Platform) getTransactionChannel(id string, txChan chan blockatlas.TxPag } func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (blockatlas.TxPage, error) { - if receipt.Outputs == nil || len(receipt.Outputs) == 0 { - return blockatlas.TxPage{}, errors.New("NormalizeBlockTransaction: Clauses not found: " + srcTx.Id) - } + txs := make(blockatlas.TxPage, 0) fee, err := numbers.HexToDecimal(receipt.Paid) if err != nil { - return blockatlas.TxPage{}, err + return txs, err + } + + originSender, err := address.EIP55Checksum(blockatlas.GetValidParameter(srcTx.Origin, srcTx.Meta.TxOrigin)) + if err != nil { + return txs, err + } + + if receipt.Reverted { + var to string + if len(srcTx.Clauses) > 0 { + to = srcTx.Clauses[0].To + if checksumTo, err := address.EIP55Checksum(to); err == nil { + to = checksumTo + } + } else { + return txs, errors.New("NormalizeBlockTransaction: srcTx.Clauses not found: " + srcTx.Id) + } + + txs = append(txs, blockatlas.Tx{ + ID: srcTx.Id, + Coin: p.Coin().ID, + From: originSender, + To: to, + Fee: blockatlas.Amount(fee), + Date: srcTx.Meta.BlockTimestamp, + Type: blockatlas.TxTokenTransfer, + Block: srcTx.Meta.BlockNumber, + Status: blockatlas.StatusError, + }) + return txs, nil + } + + if receipt.Outputs == nil || len(receipt.Outputs) == 0 { + return blockatlas.TxPage{}, errors.New("NormalizeBlockTransaction: receipt.Outputs not found: " + srcTx.Id) } - txs := make(blockatlas.TxPage, 0) for _, output := range receipt.Outputs { if len(output.Events) == 0 || len(output.Events[0].Topics) < 3 { continue @@ -94,10 +125,6 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (block continue } - originSender, err := address.EIP55Checksum(blockatlas.GetValidParameter(srcTx.Origin, srcTx.Meta.TxOrigin)) - if err != nil { - continue - } originReceiver, err := address.EIP55Checksum(event.Address) if err != nil { continue diff --git a/platform/vechain/transaction_test.go b/platform/vechain/transaction_test.go index 56fcb4745..29275e343 100644 --- a/platform/vechain/transaction_test.go +++ b/platform/vechain/transaction_test.go @@ -11,51 +11,12 @@ import ( ) var ( - transferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer.json") - trxId, _ = mock.JsonFromFilePathToString("mocks/" + "tx_id.json") - transferLogSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer_log.json") - trxReceipt, _ = mock.JsonFromFilePathToString("mocks/" + "transfer_receipt.json") - - expectedTransfer = blockatlas.Tx{ - ID: "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", - Coin: coin.VET, - From: "0xB5e883349e68aB59307d1604555AC890fAC47128", - To: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", - Date: 1574410670, - Type: blockatlas.TxTransfer, - Fee: blockatlas.Amount("21000"), - Status: blockatlas.StatusCompleted, - Block: 4395940, - Direction: blockatlas.DirectionOutgoing, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1347000000000000000"), - Decimals: 18, - Symbol: "VET", - }, - } - expectedTransferLog = blockatlas.TxPage{ - { - ID: "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", - Coin: coin.VET, - From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", - To: "0x0000000000000000000000000000456E65726779", - Date: 1574278180, - Type: blockatlas.TxTokenTransfer, - Fee: blockatlas.Amount("36582000000000000000"), - Status: blockatlas.StatusCompleted, - Block: 4382764, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.TokenTransfer{ - Name: gasTokenName, - Symbol: gasTokenSymbol, - TokenID: "0x0000000000000000000000000000456E65726779", - From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", - To: "0xB5e883349e68aB59307d1604555AC890fAC47128", - Value: blockatlas.Amount("68000000000000000000"), - Decimals: 18, - }, - }, - } + transferSrc, _ = mock.JsonFromFilePathToString("mocks/transfer.json") + trxId, _ = mock.JsonFromFilePathToString("mocks/tx_id.json") + transferLogSrc, _ = mock.JsonFromFilePathToString("mocks/transfer_log.json") + trxReceipt, _ = mock.JsonFromFilePathToString("mocks/transfer_receipt.json") + revertedTx, _ = mock.JsonFromFilePathToString("mocks/reverted_tx.json") + revertedReceipt, _ = mock.JsonFromFilePathToString("mocks/reverted_receipt.json") ) func TestNormalizeTransaction(t *testing.T) { @@ -66,7 +27,23 @@ func TestNormalizeTransaction(t *testing.T) { txId string expected blockatlas.Tx }{ - {"Test normalize VET transfer transaction", "0xb5e883349e68ab59307d1604555ac890fac47128", transferSrc, trxId, expectedTransfer}, + {"Test normalize VET transfer transaction", "0xb5e883349e68ab59307d1604555ac890fac47128", transferSrc, trxId, blockatlas.Tx{ + ID: "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", + Coin: coin.VET, + From: "0xB5e883349e68aB59307d1604555AC890fAC47128", + To: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", + Date: 1574410670, + Type: blockatlas.TxTransfer, + Fee: blockatlas.Amount("21000"), + Status: blockatlas.StatusCompleted, + Block: 4395940, + Direction: blockatlas.DirectionOutgoing, + Meta: blockatlas.Transfer{ + Value: blockatlas.Amount("1347000000000000000"), + Decimals: 18, + Symbol: "VET", + }, + }}, } platform := Platform{} @@ -96,7 +73,42 @@ func TestNormalizeTokenTransaction(t *testing.T) { txReceipt string expected blockatlas.TxPage }{ - {"Normalize VIP180 token transfer", transferLogSrc, trxReceipt, expectedTransferLog}, + {"Normalize VIP180 token transfer", transferLogSrc, trxReceipt, blockatlas.TxPage{ + { + ID: "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", + Coin: coin.VET, + From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", + To: "0x0000000000000000000000000000456E65726779", + Date: 1574278180, + Type: blockatlas.TxTokenTransfer, + Fee: blockatlas.Amount("36582000000000000000"), + Status: blockatlas.StatusCompleted, + Block: 4382764, + Direction: blockatlas.DirectionIncoming, + Meta: blockatlas.TokenTransfer{ + Name: gasTokenName, + Symbol: gasTokenSymbol, + TokenID: "0x0000000000000000000000000000456E65726779", + From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", + To: "0xB5e883349e68aB59307d1604555AC890fAC47128", + Value: blockatlas.Amount("68000000000000000000"), + Decimals: 18, + }, + }, + }}, + {"Normalize reverted token transfer", revertedTx, revertedReceipt, blockatlas.TxPage{ + { + ID: "0x7fae32a743e42eaec54642e2a5742a185299f5b4bedaf12c60f65705661de932", + Coin: coin.VET, + From: "0x7cFFB7632252Bae3766734d61F148f0Ea78Fc08C", + To: "0xf8e1fAa0367298b55F57Ed17F7a2FF3F5F1D1628", + Date: 1610326580, + Type: blockatlas.TxTokenTransfer, + Fee: blockatlas.Amount("82618000000000000000"), + Status: blockatlas.StatusError, + Block: 7982675, + }, + }}, } platform := Platform{} From 494c6844242af2a3d0432ba782cc4fb06fe97d87 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 13 Jan 2021 10:00:35 +0800 Subject: [PATCH 455/506] Move Tx.go to golibs (#1358) * move Tx.go to golibs * refactor AssetFrom * remove imroc/req * combine tx and token type * use latest golibs tag --- api/endpoint/collection.go | 5 +- api/endpoint/token.go | 5 +- api/endpoint/transaction.go | 22 +- db/models/asset.go | 73 ++ docs/docs.go | 6 +- docs/swagger.json | 6 +- docs/swagger.yaml | 6 +- go.mod | 4 +- go.sum | 20 +- pkg/blockatlas/collectibles.go | 35 - pkg/blockatlas/marshal.go | 169 ---- pkg/blockatlas/marshal_test.go | 87 -- pkg/blockatlas/mocks/bnb_token_response.json | 577 ------------- pkg/blockatlas/mocks/bnb_token_txs.json | 577 ------------- pkg/blockatlas/mocks/nim_tx.json | 14 - pkg/blockatlas/naming_service.go | 6 - pkg/blockatlas/platform.go | 15 +- pkg/blockatlas/staking.go | 7 +- pkg/blockatlas/tx.go | 530 ------------ pkg/blockatlas/tx_test.go | 781 ------------------ platform/aeternity/transaction.go | 22 +- platform/aeternity/transaction_test.go | 12 +- platform/aion/transaction.go | 22 +- platform/aion/transaction_test.go | 12 +- platform/algorand/block.go | 8 +- platform/algorand/transaction.go | 22 +- platform/algorand/transaction_test.go | 18 +- platform/binance/base_test.go | 22 +- platform/binance/block.go | 6 +- platform/binance/client.go | 4 +- platform/binance/model.go | 97 +-- platform/binance/token.go | 6 +- platform/binance/transaction.go | 6 +- platform/bitcoin/block.go | 10 +- platform/bitcoin/blockbook/block.go | 10 +- platform/bitcoin/blockbook/client.go | 11 +- platform/bitcoin/blockbook/model.go | 22 +- platform/bitcoin/blockbook/model_extension.go | 22 +- platform/bitcoin/blockbook/token.go | 15 +- platform/bitcoin/blockbook/token_test.go | 10 +- platform/bitcoin/blockbook/transaction.go | 50 +- .../bitcoin/blockbook/transaction_test.go | 4 +- platform/bitcoin/transaction.go | 52 +- platform/bitcoin/transaction_test.go | 60 +- platform/cosmos/block.go | 8 +- platform/cosmos/stake_test.go | 6 +- platform/cosmos/transaction.go | 58 +- platform/cosmos/transaction_test.go | 100 +-- platform/elrond/block.go | 4 +- platform/elrond/client.go | 8 +- platform/elrond/model.go | 24 +- platform/elrond/transaction.go | 14 +- platform/elrond/transaction_test.go | 68 +- platform/ethereum/client.go | 16 +- platform/ethereum/collection.go | 18 +- platform/ethereum/collection_test.go | 18 +- platform/ethereum/transaction.go | 8 +- platform/ethereum/transaction_test.go | 20 +- platform/ethereum/trustray/block.go | 10 +- platform/ethereum/trustray/model.go | 18 +- platform/ethereum/trustray/token.go | 15 +- platform/ethereum/trustray/token_test.go | 39 +- platform/ethereum/trustray/transaction.go | 36 +- .../ethereum/trustray/transaction_test.go | 30 +- platform/filecoin/block.go | 20 +- platform/filecoin/block_test.go | 8 +- platform/filecoin/transaction.go | 26 +- platform/filecoin/transaction_test.go | 12 +- platform/fio/transaction.go | 40 +- platform/harmony/block.go | 12 +- platform/harmony/stake.go | 3 +- platform/harmony/stake_test.go | 4 +- platform/harmony/transaction.go | 38 +- platform/harmony/transaction_test.go | 14 +- platform/icon/client.go | 4 +- platform/icon/transaction.go | 20 +- platform/icon/transaction_test.go | 10 +- platform/iotex/block.go | 10 +- platform/iotex/client.go | 3 +- platform/iotex/model.go | 8 +- platform/iotex/stake.go | 3 +- platform/iotex/transaction.go | 23 +- platform/iotex/transaction_test.go | 18 +- platform/kava/block.go | 8 +- platform/kava/transaction.go | 72 +- platform/kava/transaction_test.go | 92 +-- platform/nano/client.go | 4 +- platform/nano/transaction.go | 22 +- platform/nano/transaction_test.go | 16 +- platform/near/transaction.go | 8 +- platform/nebulas/transaction.go | 26 +- platform/nebulas/transaction_test.go | 12 +- platform/nimiq/block.go | 10 +- platform/nimiq/client.go | 4 +- platform/nimiq/model.go | 23 +- platform/nimiq/transaction.go | 21 +- platform/nimiq/transaction_test.go | 18 +- platform/ontology/block.go | 7 +- platform/ontology/transaction.go | 48 +- platform/ontology/transaction_test.go | 44 +- platform/polkadot/block.go | 8 +- platform/polkadot/client.go | 6 +- platform/polkadot/transaction.go | 39 +- platform/polkadot/transaction_test.go | 30 +- platform/ripple/block.go | 8 +- platform/ripple/model.go | 22 +- platform/ripple/transaction.go | 29 +- platform/ripple/transaction_test.go | 29 +- platform/solana/stake.go | 6 +- platform/solana/stake_test.go | 7 +- platform/solana/transaction.go | 26 +- platform/solana/transaction_test.go | 6 +- platform/stellar/block.go | 10 +- platform/stellar/transaction.go | 16 +- platform/stellar/transaction_test.go | 18 +- platform/tezos/baker.go | 3 +- platform/tezos/block.go | 8 +- platform/tezos/model.go | 28 +- platform/tezos/model_test.go | 34 +- platform/tezos/stake_test.go | 9 +- platform/tezos/transaction.go | 28 +- platform/tezos/transaction_test.go | 8 +- platform/theta/transaction.go | 37 +- platform/theta/transaction_test.go | 36 +- platform/tron/block.go | 17 +- platform/tron/model.go | 12 +- platform/tron/stake.go | 3 +- platform/tron/stake_test.go | 4 +- platform/tron/token.go | 25 +- platform/tron/token_test.go | 22 +- platform/tron/transaction.go | 49 +- platform/tron/transaction_test.go | 31 +- platform/vechain/block.go | 10 +- platform/vechain/transaction.go | 75 +- platform/vechain/transaction_test.go | 72 +- platform/waves/block.go | 8 +- platform/waves/transaction.go | 22 +- platform/waves/transaction_test.go | 28 +- platform/zilliqa/block.go | 8 +- platform/zilliqa/transaction.go | 22 +- platform/zilliqa/transaction_test.go | 13 +- services/assets/validator.go | 3 +- services/assets/validator_test.go | 9 +- services/notifier/delivery.go | 6 +- services/notifier/models.go | 20 +- services/notifier/models_test.go | 40 +- services/parser/parser.go | 23 +- services/parser/parser_test.go | 9 +- services/tokenindexer/indexer.go | 16 +- 149 files changed, 1465 insertions(+), 4230 deletions(-) delete mode 100644 pkg/blockatlas/collectibles.go delete mode 100644 pkg/blockatlas/marshal.go delete mode 100644 pkg/blockatlas/marshal_test.go delete mode 100644 pkg/blockatlas/mocks/bnb_token_response.json delete mode 100644 pkg/blockatlas/mocks/bnb_token_txs.json delete mode 100644 pkg/blockatlas/mocks/nim_tx.json delete mode 100644 pkg/blockatlas/naming_service.go delete mode 100644 pkg/blockatlas/tx.go delete mode 100644 pkg/blockatlas/tx_test.go diff --git a/api/endpoint/collection.go b/api/endpoint/collection.go index 956fe20f0..f98012178 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/types" ) // @Summary Get Collection @@ -17,7 +18,7 @@ import ( // @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) -// @Success 200 {object} blockatlas.CollectionPage +// @Success 200 {object} types.CollectionPage // @Failure 500 {object} ErrorResponse // @Router /v4/{coin}/collections/{owner}/collection/{collection_id} [get] func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas.CollectionsAPI) { @@ -45,7 +46,7 @@ func GetCollectionCategoriesFromList(c *gin.Context, apis blockatlas.Collections return } - batch := make(blockatlas.CollectionPage, 0) + batch := make(types.CollectionPage, 0) for key, addresses := range reqs { coinId, err := strconv.Atoi(key) if err != nil { diff --git a/api/endpoint/token.go b/api/endpoint/token.go index d0e1b792e..316fa30fd 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -7,6 +7,7 @@ import ( "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/tokenindexer" + "github.com/trustwallet/golibs/types" ) // @Summary Get Tokens @@ -17,13 +18,13 @@ import ( // @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 +// @Success 200 {object} types.CollectionPage // @Failure 500 {object} ErrorResponse // @Router /v2/{coin}/tokens/{address} [get] func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { address := c.Param("address") if address == "" { - c.JSON(http.StatusOK, blockatlas.TxPage{}) + c.JSON(http.StatusOK, types.TxPage{}) return } diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 824c8d9a0..f232001c9 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -2,9 +2,11 @@ package endpoint import ( "errors" + "net/http" + "github.com/gin-gonic/gin" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "net/http" + "github.com/trustwallet/golibs/types" ) // @Summary Get Transactions @@ -27,7 +29,7 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b token := c.Query("token") var ( - txs []blockatlas.Tx + txs []types.Tx err error ) @@ -73,8 +75,8 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b } } var ( - page = make(blockatlas.TxPage, 0) - filteredTxs = blockatlas.Txs(txs).FilterUniqueID().SortByDate() + page = make(types.TxPage, 0) + filteredTxs = types.Txs(txs).FilterUniqueID().SortByDate() ) for _, tx := range filteredTxs { tx.Direction = tx.GetTransactionDirection(address) @@ -86,8 +88,8 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b page = page.FilterTransactionsByToken(token) } - if len(page) > blockatlas.TxPerPage { - page = page[0:blockatlas.TxPerPage] + if len(page) > types.TxPerPage { + page = page[0:types.TxPerPage] } c.JSON(http.StatusOK, &page) @@ -141,12 +143,12 @@ func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { } } var ( - filteredTxs = blockatlas.Txs(txs).FilterUniqueID().SortByDate() - page = blockatlas.TxPage(filteredTxs) + filteredTxs = types.Txs(txs).FilterUniqueID().SortByDate() + page = types.TxPage(filteredTxs) ) page = page.FilterTransactionsByMemo() - if len(page) > blockatlas.TxPerPage { - page = page[0:blockatlas.TxPerPage] + if len(page) > types.TxPerPage { + page = page[0:types.TxPerPage] } c.JSON(http.StatusOK, &page) diff --git a/db/models/asset.go b/db/models/asset.go index 8bfdde554..a961eaa18 100644 --- a/db/models/asset.go +++ b/db/models/asset.go @@ -4,6 +4,9 @@ import ( "errors" "time" "unicode/utf8" + + "github.com/trustwallet/golibs/asset" + "github.com/trustwallet/golibs/types" ) type Asset struct { @@ -18,6 +21,76 @@ type Asset struct { Coin uint } +func AssetFrom(t types.Tx) (a Asset, ok bool) { + a.Coin = t.Coin + switch t.Meta.(type) { + case types.TokenTransfer: + transfer := t.Meta.(types.TokenTransfer) + a, ok = assetFromTokenTransfer(&t, &transfer) + case *types.TokenTransfer: + transfer := t.Meta.(*types.TokenTransfer) + a, ok = assetFromTokenTransfer(&t, transfer) + case types.NativeTokenTransfer: + transfer := t.Meta.(types.NativeTokenTransfer) + a, ok = assetFromNativeTokenTransfer(&t, &transfer) + case *types.NativeTokenTransfer: + transfer := t.Meta.(*types.NativeTokenTransfer) + a, ok = assetFromNativeTokenTransfer(&t, transfer) + case types.AnyAction: + action := t.Meta.(types.AnyAction) + a, ok = assetFromAnyAction(&t, &action) + case *types.AnyAction: + action := t.Meta.(*types.AnyAction) + a, ok = assetFromAnyAction(&t, action) + default: + break + } + + if !ok || a.IsValid() != nil { + return Asset{}, false + } + return +} + +func assetFromTokenTransfer(t *types.Tx, transfer *types.TokenTransfer) (a Asset, ok bool) { + tp, ok := types.GetTokenType(t.Coin, transfer.TokenID) + if !ok { + return + } + a.Asset = asset.BuildID(t.Coin, transfer.TokenID) + a.Decimals = transfer.Decimals + a.Name = transfer.Name + a.Symbol = transfer.Symbol + a.Type = tp + return +} + +func assetFromNativeTokenTransfer(t *types.Tx, transfer *types.NativeTokenTransfer) (a Asset, ok bool) { + tp, ok := types.GetTokenType(t.Coin, transfer.TokenID) + if !ok { + return + } + a.Asset = asset.BuildID(t.Coin, transfer.TokenID) + a.Decimals = transfer.Decimals + a.Name = transfer.Name + a.Symbol = transfer.Symbol + a.Type = tp + return +} + +func assetFromAnyAction(t *types.Tx, action *types.AnyAction) (a Asset, ok bool) { + tp, ok := types.GetTokenType(t.Coin, action.TokenID) + if !ok { + return + } + a.Asset = asset.BuildID(t.Coin, action.TokenID) + a.Decimals = action.Decimals + a.Name = action.Name + a.Symbol = action.Symbol + a.Type = tp + return +} + func (asset *Asset) IsValid() error { if len(asset.Name) >= 32 { return errors.New("name should be less than 32") diff --git a/docs/docs.go b/docs/docs.go index 507a28c29..ec99327d8 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -297,7 +297,7 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" + "$ref": "#/definitions/types.CollectionPage" } }, "500": { @@ -551,7 +551,7 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" + "$ref": "#/definitions/types.CollectionPage" } }, "500": { @@ -594,7 +594,7 @@ var doc = `{ } } }, - "blockatlas.CollectionPage": { + "types.CollectionPage": { "type": "array", "items": { "$ref": "#/definitions/blockatlas.Collection" diff --git a/docs/swagger.json b/docs/swagger.json index 322372f6b..4fcea199b 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -277,7 +277,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" + "$ref": "#/definitions/types.CollectionPage" } }, "500": { @@ -531,7 +531,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/blockatlas.CollectionPage" + "$ref": "#/definitions/types.CollectionPage" } }, "500": { @@ -574,7 +574,7 @@ } } }, - "blockatlas.CollectionPage": { + "types.CollectionPage": { "type": "array", "items": { "$ref": "#/definitions/blockatlas.Collection" diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 47ae34120..c0c29c495 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -18,7 +18,7 @@ definitions: total: type: integer type: object - blockatlas.CollectionPage: + types.CollectionPage: items: $ref: '#/definitions/blockatlas.Collection' type: array @@ -282,7 +282,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/blockatlas.CollectionPage' + $ref: '#/definitions/types.CollectionPage' "500": description: Internal Server Error schema: @@ -501,7 +501,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/blockatlas.CollectionPage' + $ref: '#/definitions/types.CollectionPage' "500": description: Internal Server Error schema: diff --git a/go.mod b/go.mod index 5af93227c..30c9a7b14 100644 --- a/go.mod +++ b/go.mod @@ -23,8 +23,8 @@ require ( github.com/stretchr/testify v1.6.1 github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/swag v1.7.0 - github.com/trustwallet/golibs v0.0.30 - github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08 + github.com/trustwallet/golibs v0.0.31 + github.com/trustwallet/golibs/network v0.0.0-20210112030915-7e676f1ce53b golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect diff --git a/go.sum b/go.sum index 90d8417ac..8293506de 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,7 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cenkalti/backoff v1.1.0 h1:QnvVp8ikKCDWOsFheytRCoYWYPO/ObCTBGxT19Hc+yE= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= @@ -190,8 +191,6 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U= -github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= @@ -415,12 +414,14 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.29 h1:ZHpV1co5OEWNxnMk1qhlczYcZiMuLI/4r1KuyrRJRN8= -github.com/trustwallet/golibs v0.0.29/go.mod h1:otCh9cT8r7VlojZv5zACgUpUyAhNrd5kD5YRV6xW9Iw= -github.com/trustwallet/golibs v0.0.30 h1:bsuwKSUX9dtn/368H/gnYd2uCF/rXbhw3uIZ9sh3wLY= -github.com/trustwallet/golibs v0.0.30/go.mod h1:otCh9cT8r7VlojZv5zACgUpUyAhNrd5kD5YRV6xW9Iw= -github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08 h1:6MVjdC1zYVwiytclgHLxS6ojdYiM7gfVqMSDkjuulS4= -github.com/trustwallet/golibs/network v0.0.0-20210105080443-03598d944b08/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs v0.0.31-0.20210111093217-efd7dac63bce h1:o+uU7PzPptwcW0z85S77B3dk5tIr1v7fd3cAFjdWbac= +github.com/trustwallet/golibs v0.0.31-0.20210111093217-efd7dac63bce/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= +github.com/trustwallet/golibs v0.0.31 h1:Ii5WqqN2TjTHAyXBYpvck7ImtqdNNITeO/zlqfd0E4o= +github.com/trustwallet/golibs v0.0.31/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= +github.com/trustwallet/golibs/network v0.0.0-20210107055554-eac147c5e524 h1:cHw4uer/5KexBPrK6Tx3viq/GRtTE22LtCBFPbQY7II= +github.com/trustwallet/golibs/network v0.0.0-20210107055554-eac147c5e524/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs/network v0.0.0-20210112030915-7e676f1ce53b h1:sAfeSYHLxCGW00mIv/+P8T03SiW0JP4OLAccuMAjz6M= +github.com/trustwallet/golibs/network v0.0.0-20210112030915-7e676f1ce53b/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= 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= @@ -542,6 +543,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -615,6 +617,8 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= diff --git a/pkg/blockatlas/collectibles.go b/pkg/blockatlas/collectibles.go deleted file mode 100644 index ccfb5d88f..000000000 --- a/pkg/blockatlas/collectibles.go +++ /dev/null @@ -1,35 +0,0 @@ -package blockatlas - -type ( - Collection struct { - Id string `json:"id"` - Name string `json:"name"` - ImageUrl string `json:"image_url"` - Description string `json:"description"` - ExternalLink string `json:"external_link"` - Total int `json:"total"` - Address string `json:"address"` - Coin uint `json:"coin"` - Type string `json:"-"` - } - - CollectionPage []Collection - - Collectible struct { - ID string `json:"id"` - CollectionID string `json:"collection_id"` - TokenID string `json:"token_id"` - ContractAddress string `json:"contract_address"` - Category string `json:"category"` - ImageUrl string `json:"image_url"` - ExternalLink string `json:"external_link"` - ProviderLink string `json:"provider_link"` - Type string `json:"type"` - Description string `json:"description"` - Coin uint `json:"coin"` - Name string `json:"name"` - Version string `json:"nft_version"` - } - - CollectiblePage []Collectible -) diff --git a/pkg/blockatlas/marshal.go b/pkg/blockatlas/marshal.go deleted file mode 100644 index aa6d00a6a..000000000 --- a/pkg/blockatlas/marshal.go +++ /dev/null @@ -1,169 +0,0 @@ -package blockatlas - -import ( - "encoding/json" - "regexp" - "strings" - - "errors" - - "github.com/trustwallet/golibs/numbers" -) - -var matchNumber = regexp.MustCompile(`^\d+(\.\d+)?$`) - -// Tx, but with default JSON marshalling methods -type wrappedTx Tx - -// UnmarshalJSON creates a transaction along with metadata from a JSON object. -// Fails if the meta object can't be read. -func (t *Tx) UnmarshalJSON(data []byte) error { - // Wrap the Tx type to avoid infinite recursion - var wrapped wrappedTx - - var raw json.RawMessage - wrapped.Meta = &raw - if err := json.Unmarshal(data, &wrapped); err != nil { - return err - } - - *t = Tx(wrapped) - - switch t.Type { - case TxTransfer: - t.Meta = new(Transfer) - case TxMultiCurrencyTransfer: - t.Meta = new(MultiCurrencyTransfer) - case TxNativeTokenTransfer: - t.Meta = new(NativeTokenTransfer) - case TxTokenTransfer: - t.Meta = new(TokenTransfer) - case TxCollectibleTransfer: - t.Meta = new(CollectibleTransfer) - case TxTokenSwap: - t.Meta = new(TokenSwap) - case TxContractCall: - t.Meta = new(ContractCall) - case TxAnyAction: - t.Meta = new(AnyAction) - default: - return errors.New("unsupported tx type") - } - - err := json.Unmarshal(raw, t.Meta) - if err != nil { - return err - } - return nil -} - -// MarshalJSON creates a JSON object from a transaction. -// Sets the Type field to the currect value based on the Meta type. -func (t *Tx) MarshalJSON() ([]byte, error) { - // Set type from metadata content - switch t.Meta.(type) { - case Transfer, *Transfer: - t.Type = TxTransfer - case MultiCurrencyTransfer, *MultiCurrencyTransfer: - t.Type = TxMultiCurrencyTransfer - case NativeTokenTransfer, *NativeTokenTransfer: - t.Type = TxNativeTokenTransfer - case TokenTransfer, *TokenTransfer: - t.Type = TxTokenTransfer - case CollectibleTransfer, *CollectibleTransfer: - t.Type = TxCollectibleTransfer - case TokenSwap, *TokenSwap: - t.Type = TxTokenSwap - case ContractCall, *ContractCall: - t.Type = TxContractCall - case AnyAction, *AnyAction: - t.Type = TxAnyAction - default: - return nil, errors.New("unsupported tx metadata") - } - - // Set status to completed by default - if t.Status == "" { - t.Status = StatusCompleted - } - - // Wrap the Tx type to avoid infinite recursion - return json.Marshal(wrappedTx(*t)) -} - -// UnmarshalJSON reads an amount from a JSON string or number. -// Comma separators get dropped with address.DecimalToSatoshis. -func (a *Amount) UnmarshalJSON(data []byte) error { - var n json.Number - err := json.Unmarshal(data, &n) - if err != nil { - return err - } - str := string(n) - if !matchNumber.MatchString(str) { - return errors.New("not a regular decimal number: " + str) - } - if strings.ContainsRune(str, '.') { - str, _ = numbers.DecimalToSatoshis(str) - } - *a = Amount(str) - return nil -} - -// MarshalJSON returns a JSON string representing the amount -func (a *Amount) MarshalJSON() ([]byte, error) { - return json.Marshal(string(*a)) -} - -// Sort sorts the response by date, descending -func (txs TxPage) Len() int { return len(txs) } -func (txs TxPage) Less(i, j int) bool { return txs[i].Date > txs[j].Date } -func (txs TxPage) Swap(i, j int) { txs[i], txs[j] = txs[j], txs[i] } - -// MarshalJSON returns a wrapped list of transactions in JSON -func (r *TxPage) MarshalJSON() ([]byte, error) { - var page struct { - Total int `json:"total"` - Docs []Tx `json:"docs"` - Status bool `json:"status"` - } - page.Docs = *r - if page.Docs == nil { - page.Docs = make([]Tx, 0) - } - page.Total = len(page.Docs) - page.Status = true - return json.Marshal(page) -} - -// MarshalJSON returns a wrapped list of collections in JSON -func (r CollectionPage) MarshalJSON() ([]byte, error) { - var page struct { - Total int `json:"total"` - Docs []Collection `json:"docs"` - Status bool `json:"status"` - } - page.Docs = []Collection(r) - if page.Docs == nil { - page.Docs = make([]Collection, 0) - } - page.Total = len(page.Docs) - page.Status = true - return json.Marshal(page) -} - -// MarshalJSON returns a wrapped list of collectibles in JSON -func (r CollectiblePage) MarshalJSON() ([]byte, error) { - var page struct { - Total int `json:"total"` - Docs []Collectible `json:"docs"` - Status bool `json:"status"` - } - page.Docs = []Collectible(r) - if page.Docs == nil { - page.Docs = make([]Collectible, 0) - } - page.Total = len(page.Docs) - page.Status = true - return json.Marshal(page) -} diff --git a/pkg/blockatlas/marshal_test.go b/pkg/blockatlas/marshal_test.go deleted file mode 100644 index deaeca373..000000000 --- a/pkg/blockatlas/marshal_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package blockatlas - -import ( - "bytes" - "encoding/json" - "reflect" - "sort" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/trustwallet/golibs/coin" - "github.com/trustwallet/golibs/mock" -) - -var ( - txJSON, _ = mock.JsonFromFilePathToString("mocks/" + "nim_tx.json") - txModel = Tx{ - ID: "14beb212aaefd06d7c6c0b25fc5ec242a2de2725af0a2827c105e743222cacd6", - Coin: coin.NIM, - From: "NQ11 P00L 2HYP TUK8 VY6L 2N22 MMBU MHHR BSAA", - To: "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA", - Fee: "138", - Date: 1548954343, - Block: 419040, - Status: StatusCompleted, - Meta: &Transfer{ - Value: "5004160", - }, - } -) - -func TestTx_UnmarshalJSON(t *testing.T) { - // Expect to get txModel, but with type set - expected := txModel - expected.Type = TxTransfer - - // Unmarshal source - var got Tx - err := json.Unmarshal([]byte(txJSON), &got) - if err != nil { - t.Fatal(err) - } - - // Compare got and expected - if !reflect.DeepEqual(expected, got) { - t.Error("txs not equal") - } -} - -func TestTx_MarshalJSON(t *testing.T) { - // Input is txModel without type - input := txModel - - // Marshal transaction - got, err := json.MarshalIndent(&input, "", "\t") - if err != nil { - t.Fatal(err) - } - - // After marshal, the type should be set - if input.Type == "" { - t.Fatal("type was not set") - } else if input.Type != TxTransfer { - t.Fatal("wrong type set") - } - - // Compare expected and output JSON - bytes.Equal(got, []byte(txJSON)) -} - -func TestSortTxPage(t *testing.T) { - tests := []struct { - name string - page TxPage - want TxPage - }{ - {"test sort 1", TxPage{{Date: 5}, {Date: 2}, {Date: 1}, {Date: 4}, {Date: 3}}, TxPage{{Date: 5}, {Date: 4}, {Date: 3}, {Date: 2}, {Date: 1}}}, - {"test sort 2", TxPage{{Date: 100}, {Date: 2}, {Date: 33}, {Date: 409}}, TxPage{{Date: 409}, {Date: 100}, {Date: 33}, {Date: 2}}}, - {"test sort 3", TxPage{{Date: 100}, {Date: 2}, {Date: 100}}, TxPage{{Date: 100}, {Date: 100}, {Date: 2}}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - sort.Sort(tt.page) - assert.Equal(t, tt.want, tt.page) - }) - } -} diff --git a/pkg/blockatlas/mocks/bnb_token_response.json b/pkg/blockatlas/mocks/bnb_token_response.json deleted file mode 100644 index 7b355b5f7..000000000 --- a/pkg/blockatlas/mocks/bnb_token_response.json +++ /dev/null @@ -1,577 +0,0 @@ -[ - { - "id": "59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592484005, - "block": 95113723, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103643577", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "1089263465", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592442063, - "block": 95008674, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "1998400000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3", - "coin": 714, - "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592429461, - "block": 94977026, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2511060524", - "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592348463, - "block": 94777896, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "10998400000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592253063, - "block": 94538295, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "4146300000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592250904, - "block": 94532906, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103335769", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "63266290000", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592246708, - "block": 94522375, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "104150629", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "4512670728", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592245803, - "block": 94520016, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103335769", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "58689300000", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592244606, - "block": 94517032, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "108137171", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "1053055990", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592237402, - "block": 94498680, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "8479394653", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592223002, - "block": 94462381, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "38451401547", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592220661, - "block": 94456416, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "99998300000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592201404, - "block": 94407633, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103229158", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "1089751117", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592194201, - "block": 94389286, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "1098704296", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592179801, - "block": 94352682, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2461605848", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592177461, - "block": 94346701, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2324800000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592165402, - "block": 94316303, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "156671627595", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592163611, - "block": 94311779, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "106835633", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2042060818", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592158202, - "block": 94298059, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "3101371", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592154601, - "block": 94288998, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "367696585025", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592073191, - "block": 94084342, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103335769", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2503750000", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592066528, - "block": 94067506, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103335769", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "12959997250", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2", - "coin": 714, - "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592060464, - "block": 94052345, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2781326500", - "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E", - "coin": 714, - "from": "bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592060463, - "block": 94052341, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "39644614000", - "from": "bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592053265, - "block": 94034212, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "40798300000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - } -] diff --git a/pkg/blockatlas/mocks/bnb_token_txs.json b/pkg/blockatlas/mocks/bnb_token_txs.json deleted file mode 100644 index 7b355b5f7..000000000 --- a/pkg/blockatlas/mocks/bnb_token_txs.json +++ /dev/null @@ -1,577 +0,0 @@ -[ - { - "id": "59FE2D56F0E2320023D5D579497FF4E5FD8B226AEF14AADCE089A241BE0051DA", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592484005, - "block": 95113723, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103643577", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "1089263465", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "DA10ACADF3BF23072CBAAEA02E51C48331DDE588EC16BA6AA0FF79F9F37CD08E", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592442063, - "block": 95008674, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "1998400000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "1B7696018A0BEB07EB41F1E8D7A20B64AA9DB6AFDC61CD30EFA082D4E8650BD3", - "coin": 714, - "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592429461, - "block": 94977026, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2511060524", - "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "B98EF6224FD385830CFE88B431FE4F098D1ABAFB349A138DD11235FD02B619B7", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592348463, - "block": 94777896, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "10998400000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "C6E37E9966BD52EB612B23DAD30BFD68BE05D4670B7FDC64DA2C109305247330", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592253063, - "block": 94538295, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "4146300000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "A9F58764D7F9555000FD0C1BD0B403953F05AE2DD9E094127315BE8FBF0FA19E", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592250904, - "block": 94532906, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103335769", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "63266290000", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "91B7F8348917289F08A9C2B5BAF8F6673AB6808C9F2CAD4930BC5BB62AAA469B", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592246708, - "block": 94522375, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "104150629", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "4512670728", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "62A224A212083CC53142230A0598107305C7659B687F4B17FDBDA1D03008679E", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592245803, - "block": 94520016, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103335769", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "58689300000", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "5E2D321690FFD6BBCD0247DDCE07A1D41AE659F6C11F0662DDD6C7D8242E3D00", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592244606, - "block": 94517032, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "108137171", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "1053055990", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "E7A814D1E23F269914FB4CDECF61D6A3D8D900684CFC8280BBB7989A3EF6C071", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592237402, - "block": 94498680, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "8479394653", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "8B71C1AA5C4C636127E8A08D67AB7DF4BC5E4EFA25F99F12A34FFF3B8928BB14", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592223002, - "block": 94462381, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "38451401547", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "4C96992F1D5D971C1C9D787C0D96EE342875147D083E79759BF569CE9E2F63B4", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592220661, - "block": 94456416, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "99998300000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "2001461D2CCF84864B999235B6A0B08A2A75649367A7F809651E73C2D49E94F3", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592201404, - "block": 94407633, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103229158", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "1089751117", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "0AE83A51E05BB34C8FE0AA0AC376B9C7AE8960A9A77EB9C687B29994A53D1159", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592194201, - "block": 94389286, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "1098704296", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "68C4BA1864A52EA78FD99610FB9FE64DDB86EDDA2F020D7E250AB8E3E8E5CF32", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592179801, - "block": 94352682, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2461605848", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "5D6939D3AE2AFDFF6A3ECA5DD48CB5D8D2F0389A35C414806CF284B453DA5133", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592177461, - "block": 94346701, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2324800000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "5714D3F5C442E2491EEF8BCA9D3CBDF18005C5B1D67BA1A7E873ADFC46F6F4B8", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592165402, - "block": 94316303, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "156671627595", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "1823E07FBB966050060D127B266F9FB64F30DF1F549C3906BDE234D66A060766", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592163611, - "block": 94311779, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "106835633", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2042060818", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "A0A6DA82F4F4610145635FFB1F52CF8EC5F8F51BDF0256B5B0F77D3D5692E2CA", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592158202, - "block": 94298059, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "3101371", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "B380CF3BA7831EBD82240CFCC369572FCC022ECA3A91A7F11743D07C1599F636", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592154601, - "block": 94288998, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103268674", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "367696585025", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "7ABEF721E2A3D2B70583F4641FE426D0CAE55AD11C7021809289E504917E4569", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592073191, - "block": 94084342, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103335769", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2503750000", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "C422B298A2EABD7EA503CC1F525C20BEB606FB83D01FE760A69F0FA57DB65B03", - "coin": 714, - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23", - "fee": "37500", - "date": 1592066528, - "block": 94067506, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "outgoing", - "memo": "103335769", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "12959997250", - "from": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "to": "bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23" - } - }, - { - "id": "FD656B1D90C660F4F6D74E4C0584AC11ED0626F6FBF5E8C33D0E9131F5DB04C2", - "coin": 714, - "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592060464, - "block": 94052345, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "2781326500", - "from": "bnb1f87wdfjeqx5yju5vgjrz62u32lhrqxztscxrxj", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "0447FA8D100F715DCE70513AB9ECF5BCF16D38A6C450B33DE0257BB654FBD50E", - "coin": 714, - "from": "bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592060463, - "block": 94052341, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "39644614000", - "from": "bnb1xyq7ttkzq4ekmn26kwn2ul2f6ludplnhlqcf6k", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - }, - { - "id": "19583E4A440801AA458F06D655D9745FE0A75B76FF776CEA65455A9C9D9F59D9", - "coin": 714, - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp", - "fee": "37500", - "date": 1592053265, - "block": 94034212, - "status": "completed", - "sequence": 0, - "type": "native_token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "", - "symbol": "BUSD", - "token_id": "BUSD-BD1", - "decimals": 8, - "value": "40798300000", - "from": "bnb1yjlk7f47qf0z97ph6pxc00s2s0yw048edmtjtw", - "to": "bnb1t7hpl286qgvsg08lvx6ac9ul0msy4k2ud8dukp" - } - } -] diff --git a/pkg/blockatlas/mocks/nim_tx.json b/pkg/blockatlas/mocks/nim_tx.json deleted file mode 100644 index 16fb7b6e8..000000000 --- a/pkg/blockatlas/mocks/nim_tx.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": "14beb212aaefd06d7c6c0b25fc5ec242a2de2725af0a2827c105e743222cacd6", - "coin": 242, - "from": "NQ11 P00L 2HYP TUK8 VY6L 2N22 MMBU MHHR BSAA", - "to": "NQ86 2H8F YGU5 RM77 QSN9 LYLH C56A CYYR 0MLA", - "fee": "138", - "date": 1548954343, - "block": 419040, - "status": "completed", - "type": "transfer", - "metadata": { - "value": "5004160" - } -} diff --git a/pkg/blockatlas/naming_service.go b/pkg/blockatlas/naming_service.go deleted file mode 100644 index ca44b4479..000000000 --- a/pkg/blockatlas/naming_service.go +++ /dev/null @@ -1,6 +0,0 @@ -package blockatlas - -type Resolved struct { - Result string `json:"result"` - Coin uint64 `json:"coin"` -} diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 2af180ba3..09020c766 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -2,6 +2,7 @@ package blockatlas import ( "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) type ( @@ -14,31 +15,31 @@ type ( BlockAPI interface { Platform CurrentBlockNumber() (int64, error) - GetBlockByNumber(num int64) (*Block, error) + GetBlockByNumber(num int64) (*types.Block, error) } // TxAPI provides transaction lookups based on address TxAPI interface { Platform - GetTxsByAddress(address string) (TxPage, error) + GetTxsByAddress(address string) (types.TxPage, error) } // TokenTxAPI provides token transaction lookups TokenTxAPI interface { Platform - GetTokenTxsByAddress(address, token string) (TxPage, error) + GetTokenTxsByAddress(address, token string) (types.TxPage, error) } // TxUtxoAPI provides transaction lookup based on address and XPUB (Bitcoin-style) TxUtxoAPI interface { TxAPI - GetTxsByXpub(xpub string) (TxPage, error) + GetTxsByXpub(xpub string) (types.TxPage, error) } // TokensAPI provides token lookups TokensAPI interface { Platform - GetTokenListByAddress(address string) (TokenPage, error) + GetTokenListByAddress(address string) (types.TokenPage, error) } // StakingAPI provides staking information @@ -53,8 +54,8 @@ type ( CollectionsAPI interface { Platform - GetCollections(owner string) (CollectionPage, error) - GetCollectibles(owner, collectibleID string) (CollectiblePage, error) + GetCollections(owner string) (types.CollectionPage, error) + GetCollectibles(owner, collectibleID string) (types.CollectiblePage, error) } Platforms map[string]Platform diff --git a/pkg/blockatlas/staking.go b/pkg/blockatlas/staking.go index 3f82b1fe6..f8260ab4d 100644 --- a/pkg/blockatlas/staking.go +++ b/pkg/blockatlas/staking.go @@ -1,6 +1,9 @@ package blockatlas -import "github.com/trustwallet/golibs/coin" +import ( + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" +) const ( DelegationStatusActive DelegationStatus = "active" @@ -31,7 +34,7 @@ type ( StakingDetails struct { Reward StakingReward `json:"reward"` LockTime int `json:"locktime"` - MinimumAmount Amount `json:"minimum_amount"` + MinimumAmount types.Amount `json:"minimum_amount"` Type DelegationType `json:"type"` } diff --git a/pkg/blockatlas/tx.go b/pkg/blockatlas/tx.go deleted file mode 100644 index 4a97dfea9..000000000 --- a/pkg/blockatlas/tx.go +++ /dev/null @@ -1,530 +0,0 @@ -package blockatlas - -import ( - "sort" - "strconv" - "strings" - - "github.com/trustwallet/golibs/tokentype" - - mapset "github.com/deckarep/golang-set" - "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/golibs/asset" - "github.com/trustwallet/golibs/coin" - "github.com/trustwallet/golibs/numbers" -) - -const ( - StatusCompleted Status = "completed" - StatusPending Status = "pending" - StatusError Status = "error" - - DirectionOutgoing Direction = "outgoing" - DirectionIncoming Direction = "incoming" - DirectionSelf Direction = "yourself" - - TxTransfer TransactionType = "transfer" - TxNativeTokenTransfer TransactionType = "native_token_transfer" - TxTokenTransfer TransactionType = "token_transfer" - TxCollectibleTransfer TransactionType = "collectible_transfer" - TxTokenSwap TransactionType = "token_swap" - TxContractCall TransactionType = "contract_call" - TxAnyAction TransactionType = "any_action" - TxMultiCurrencyTransfer TransactionType = "multi_currency_transfer" - - KeyPlaceOrder KeyType = "place_order" - KeyCancelOrder KeyType = "cancel_order" - KeyIssueToken KeyType = "issue_token" - KeyBurnToken KeyType = "burn_token" - KeyMintToken KeyType = "mint_token" - KeyApproveToken KeyType = "approve_token" - KeyStakeDelegate KeyType = "stake_delegate" - KeyStakeClaimRewards KeyType = "stake_claim_rewards" - - KeyTitlePlaceOrder KeyTitle = "Place Order" - KeyTitleCancelOrder KeyTitle = "Cancel Order" - AnyActionDelegation KeyTitle = "Delegation" - AnyActionUndelegation KeyTitle = "Undelegation" - AnyActionClaimRewards KeyTitle = "Claim Rewards" - - // TxPerPage says how many transactions to return per page - TxPerPage = 25 -) - -type ( - // Types of transaction statuses - Direction string - Status string - TransactionType string - KeyType string - KeyTitle string - - Block struct { - Number int64 `json:"number"` - Txs []Tx `json:"txs"` - } - - // TxPage is a page of transactions - TxPage []Tx - - // Amount is a positive decimal integer string. - // It is written in the smallest possible unit (e.g. Wei, Satoshis) - Amount string - - // Tx describes an on-chain transaction generically - Tx struct { - // Unique identifier - ID string `json:"id"` - // SLIP-44 coin index of the platform - Coin uint `json:"coin"` - // Address of the transaction sender - From string `json:"from"` - // Address of the transaction recipient - To string `json:"to"` - // Transaction fee (native currency) - Fee Amount `json:"fee"` - // Unix timestamp of the block the transaction was included in - Date int64 `json:"date"` - // Height of the block the transaction was included in - Block uint64 `json:"block"` - // Status of the transaction e.g: "completed", "pending", "error" - Status Status `json:"status"` - // Empty if the transaction "completed" or "pending", else error explaining why the transaction failed (optional) - Error string `json:"error,omitempty"` - // Transaction nonce or sequence - Sequence uint64 `json:"sequence"` - // Type of metadata - Type TransactionType `json:"type"` - // Input addresses - Inputs []TxOutput `json:"inputs,omitempty"` - // Output addresses - Outputs []TxOutput `json:"outputs,omitempty"` - // Transaction Direction - Direction Direction `json:"direction,omitempty"` - // Meta data object - Memo string `json:"memo"` - Meta interface{} `json:"metadata"` - } - - TxOutput struct { - Address string `json:"address"` - Value Amount `json:"value"` - } - - // Transfer describes the transfer of currency native to the platform - Transfer struct { - Value Amount `json:"value"` - Symbol string `json:"symbol"` - Decimals uint `json:"decimals"` - } - - // NativeTokenTransfer describes the transfer of native tokens. - // Example: Stellar Tokens, TRC10 - NativeTokenTransfer struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - TokenID string `json:"token_id"` - Decimals uint `json:"decimals"` - Value Amount `json:"value"` - From string `json:"from"` - To string `json:"to"` - } - - // TokenTransfer describes the transfer of non-native tokens. - // Examples: ERC-20, TRC20 - TokenTransfer struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - TokenID string `json:"token_id"` - Decimals uint `json:"decimals"` - Value Amount `json:"value"` - From string `json:"from"` - To string `json:"to"` - } - - // CollectibleTransfer describes the transfer of a - // "collectible", unique token. - CollectibleTransfer struct { - Name string `json:"name"` - Contract string `json:"contract"` - ImageURL string `json:"image_url"` - } - - // TokenSwap describes the exchange of two different tokens - TokenSwap struct { - Input TokenTransfer `json:"input"` - Output TokenTransfer `json:"output"` - } - - // ContractCall describes a - ContractCall struct { - Input string `json:"input"` - Value string `json:"value"` - } - - // Currency describes currency information with its amount - Currency struct { - Token Token `json:"token"` - Value Amount `json:"value"` - } - - // MultiCurrencyTransfer describes the transfer of multiple currency native to the platform - MultiCurrencyTransfer struct { - Currencies []Currency `json:"currencies"` - Fees []Currency `json:"fees"` - } - - // AnyAction describes all other types - AnyAction struct { - Coin uint `json:"coin"` - Title KeyTitle `json:"title"` - Key KeyType `json:"key"` - TokenID string `json:"token_id"` - Name string `json:"name"` - Symbol string `json:"symbol"` - Decimals uint `json:"decimals"` - Value Amount `json:"value"` - } - - // TokenPage is a page of transactions. - TokenPage []Token - - // Token describes the non-native tokens. - // Examples: ERC-20, TRC-20, BEP-2 - Token struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - Decimals uint `json:"decimals"` - TokenID string `json:"token_id"` - Coin uint `json:"coin"` - Type tokentype.Type `json:"type"` - } - - Txs []Tx -) - -func (t Token) AssetId() string { - return asset.BuildID(t.Coin, t.TokenID) -} - -func (txs Txs) FilterUniqueID() Txs { - keys := make(map[string]bool) - list := make(Txs, 0) - for _, entry := range txs { - if _, value := keys[entry.ID]; !value { - keys[entry.ID] = true - list = append(list, entry) - } - } - return list -} - -func (txs TxPage) FilterTransactionsByMemo() TxPage { - result := make(TxPage, 0) - for _, tx := range txs { - if !AllowMemo(tx.Memo) { - tx.Memo = "" - } - result = append(result, tx) - } - return result -} - -func (txs Txs) FilterTransactionsByType(types []TransactionType) Txs { - result := make(Txs, 0) - for _, tx := range txs { - for _, t := range types { - if tx.Type == t { - result = append(result, tx) - } - } - } - return result -} - -func AllowMemo(memo string) bool { - // only allows numeric values - _, err := strconv.ParseFloat(memo, 64) - return err == nil -} - -func (txs TxPage) FilterTransactionsByToken(token string) TxPage { - result := make(TxPage, 0) - for _, tx := range txs { - switch tx.Meta.(type) { - case TokenTransfer: - if strings.EqualFold(tx.Meta.(TokenTransfer).TokenID, token) { - result = append(result, tx) - } - case *TokenTransfer: - if strings.EqualFold(tx.Meta.(*TokenTransfer).TokenID, token) { - result = append(result, tx) - } - case NativeTokenTransfer: - if strings.EqualFold(tx.Meta.(NativeTokenTransfer).TokenID, token) { - result = append(result, tx) - } - case *NativeTokenTransfer: - if strings.EqualFold(tx.Meta.(*NativeTokenTransfer).TokenID, token) { - result = append(result, tx) - } - case AnyAction: - if strings.EqualFold(tx.Meta.(AnyAction).TokenID, token) { - result = append(result, tx) - } - case *AnyAction: - if strings.EqualFold(tx.Meta.(*AnyAction).TokenID, token) { - result = append(result, tx) - } - default: - continue - } - } - return result -} - -func (txs Txs) SortByDate() Txs { - sort.Slice(txs, func(i, j int) bool { - return txs[i].Date > txs[j].Date - }) - return txs -} - -func (t *Tx) GetUtxoAddresses() (addresses []string) { - for _, input := range t.Inputs { - addresses = append(addresses, input.Address) - } - - for _, output := range t.Outputs { - addresses = append(addresses, output.Address) - } - - return addresses -} - -func (t *Tx) GetAddresses() []string { - addresses := make([]string, 0) - switch t.Meta.(type) { - case Transfer, *Transfer, CollectibleTransfer, *CollectibleTransfer, ContractCall, *ContractCall, AnyAction, *AnyAction, MultiCurrencyTransfer, *MultiCurrencyTransfer: - return append(addresses, t.From, t.To) - case NativeTokenTransfer: - return append(addresses, t.Meta.(NativeTokenTransfer).From, t.Meta.(NativeTokenTransfer).To) - case *NativeTokenTransfer: - return append(addresses, t.Meta.(*NativeTokenTransfer).From, t.Meta.(*NativeTokenTransfer).To) - case TokenTransfer: - return append(addresses, t.Meta.(TokenTransfer).From, t.Meta.(TokenTransfer).To) - case *TokenTransfer: - return append(addresses, t.Meta.(*TokenTransfer).From, t.Meta.(*TokenTransfer).To) - case TokenSwap: - { - m := t.Meta.(TokenSwap) - return append(addresses, m.Input.From, m.Input.To, m.Output.From, m.Output.To) - } - case *TokenSwap: - { - m := t.Meta.(*TokenSwap) - return append(addresses, m.Input.From, m.Input.To, m.Output.From, m.Output.To) - } - default: - return addresses - } -} - -func (t *Tx) TokenID() (string, bool) { - var tokenID string - switch t.Meta.(type) { - case Transfer, *Transfer, CollectibleTransfer, *CollectibleTransfer, ContractCall, *ContractCall, MultiCurrencyTransfer, *MultiCurrencyTransfer: - return "", false - case NativeTokenTransfer: - tokenID = t.Meta.(NativeTokenTransfer).TokenID - case *NativeTokenTransfer: - tokenID = t.Meta.(*NativeTokenTransfer).TokenID - case TokenTransfer: - tokenID = t.Meta.(TokenTransfer).TokenID - case AnyAction: - tokenID = t.Meta.(AnyAction).TokenID - case *AnyAction: - tokenID = t.Meta.(*AnyAction).TokenID - default: - return "", false - } - return tokenID, true -} - -func (t *Tx) GetTransactionDirection(address string) Direction { - if t.Direction != "" { - return t.Direction - } - if len(t.Inputs) > 0 && len(t.Outputs) > 0 { - addressSet := mapset.NewSet(address) - return InferDirection(t, addressSet) - } - switch meta := t.Meta.(type) { - case *TokenTransfer: - return determineTransactionDirection(address, meta.From, meta.To) - case *NativeTokenTransfer: - return determineTransactionDirection(address, meta.From, meta.To) - case TokenTransfer: - return determineTransactionDirection(address, meta.From, meta.To) - case NativeTokenTransfer: - return determineTransactionDirection(address, meta.From, meta.To) - default: - return determineTransactionDirection(address, t.From, t.To) - } -} - -func determineTransactionDirection(address, from, to string) Direction { - if address == to { - if from == to { - return DirectionSelf - } - return DirectionIncoming - } - return DirectionOutgoing -} - -func (t *Tx) InferUtxoValue(address string, coinIndex uint) { - if len(t.Inputs) > 0 && len(t.Outputs) > 0 { - addressSet := mapset.NewSet(address) - value := InferValue(t, t.Direction, addressSet) - t.Meta = Transfer{ - Value: value, - Symbol: coin.Coins[coinIndex].Symbol, - Decimals: coin.Coins[coinIndex].Decimals, - } - } -} - -func InferDirection(tx *Tx, addressSet mapset.Set) Direction { - inputSet := mapset.NewSet() - for _, address := range tx.Inputs { - inputSet.Add(address.Address) - } - outputSet := mapset.NewSet() - for _, address := range tx.Outputs { - outputSet.Add(address.Address) - } - intersect := addressSet.Intersect(inputSet) - if intersect.Cardinality() == 0 { - return DirectionIncoming - } - if outputSet.IsProperSubset(addressSet) || outputSet.Equal(inputSet) { - return DirectionSelf - } - return DirectionOutgoing -} - -func InferValue(tx *Tx, direction Direction, addressSet mapset.Set) Amount { - value := Amount("0") - if len(tx.Outputs) == 0 { - return value - } - if direction == DirectionOutgoing || direction == DirectionSelf { - value = tx.Outputs[0].Value - } else if direction == DirectionIncoming { - amount := value - for _, output := range tx.Outputs { - if !addressSet.Contains(output.Address) { - continue - } - value := numbers.AddAmount(string(amount), string(output.Value)) - amount = Amount(value) - } - value = amount - } - return value -} - -func (t Tx) AssetModel() (models.Asset, bool) { - var a models.Asset - switch t.Meta.(type) { - case TokenTransfer: - a.Asset = asset.BuildID(t.Coin, t.Meta.(TokenTransfer).TokenID) - a.Decimals = t.Meta.(TokenTransfer).Decimals - a.Name = t.Meta.(TokenTransfer).Name - a.Symbol = t.Meta.(TokenTransfer).Symbol - tp, ok := GetTokenType(t.Coin, t.Meta.(TokenTransfer).TokenID) - if !ok { - return models.Asset{}, false - } - a.Type = tp - case *TokenTransfer: - a.Asset = asset.BuildID(t.Coin, t.Meta.(*TokenTransfer).TokenID) - a.Decimals = t.Meta.(*TokenTransfer).Decimals - a.Name = t.Meta.(*TokenTransfer).Name - a.Symbol = t.Meta.(*TokenTransfer).Symbol - tp, ok := GetTokenType(t.Coin, t.Meta.(*TokenTransfer).TokenID) - if !ok { - return models.Asset{}, false - } - a.Type = tp - case NativeTokenTransfer: - a.Asset = asset.BuildID(t.Coin, t.Meta.(NativeTokenTransfer).TokenID) - a.Decimals = t.Meta.(NativeTokenTransfer).Decimals - a.Name = t.Meta.(NativeTokenTransfer).Name - a.Symbol = t.Meta.(NativeTokenTransfer).Symbol - tp, ok := GetTokenType(t.Coin, t.Meta.(NativeTokenTransfer).TokenID) - if !ok { - return models.Asset{}, false - } - a.Type = tp - case *NativeTokenTransfer: - a.Asset = asset.BuildID(t.Coin, t.Meta.(*NativeTokenTransfer).TokenID) - a.Decimals = t.Meta.(*NativeTokenTransfer).Decimals - a.Name = t.Meta.(*NativeTokenTransfer).Name - a.Symbol = t.Meta.(*NativeTokenTransfer).Symbol - tp, ok := GetTokenType(t.Coin, t.Meta.(*NativeTokenTransfer).TokenID) - if !ok { - return models.Asset{}, false - } - a.Type = tp - case AnyAction: - a.Asset = asset.BuildID(t.Coin, t.Meta.(AnyAction).TokenID) - a.Decimals = t.Meta.(AnyAction).Decimals - a.Name = t.Meta.(AnyAction).Name - a.Symbol = t.Meta.(AnyAction).Symbol - tp, ok := GetTokenType(t.Coin, t.Meta.(AnyAction).TokenID) - if !ok { - return models.Asset{}, false - } - a.Type = tp - case *AnyAction: - a.Asset = asset.BuildID(t.Coin, t.Meta.(*AnyAction).TokenID) - a.Decimals = t.Meta.(*AnyAction).Decimals - a.Name = t.Meta.(*AnyAction).Name - a.Symbol = t.Meta.(*AnyAction).Symbol - tp, ok := GetTokenType(t.Coin, t.Meta.(*AnyAction).TokenID) - if !ok { - return models.Asset{}, false - } - a.Type = tp - default: - return models.Asset{}, false - } - a.Coin = t.Coin - - if a.IsValid() != nil { - return models.Asset{}, false - } - - return a, true -} - -func GetTokenType(c uint, tokenID string) (string, bool) { - switch c { - case coin.Ethereum().ID: - return string(tokentype.ERC20), true - case coin.Tron().ID: - _, err := strconv.Atoi(tokenID) - if err != nil { - return string(tokentype.TRC20), true - } - return string(tokentype.TRC10), true - case coin.Smartchain().ID: - return string(tokentype.BEP20), true - case coin.Binance().ID: - return string(tokentype.BEP2), true - default: - return "", false - } -} diff --git a/pkg/blockatlas/tx_test.go b/pkg/blockatlas/tx_test.go deleted file mode 100644 index e6659475c..000000000 --- a/pkg/blockatlas/tx_test.go +++ /dev/null @@ -1,781 +0,0 @@ -package blockatlas - -import ( - "encoding/json" - "reflect" - "sort" - "testing" - - mapset "github.com/deckarep/golang-set" - "github.com/stretchr/testify/assert" - "github.com/trustwallet/golibs/coin" - "github.com/trustwallet/golibs/mock" - "github.com/trustwallet/golibs/tokentype" -) - -var ( - transferDst1 = Tx{ - ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44555", - Coin: coin.BNB, - From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", - To: "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5", - Fee: "125000", - Date: 1555049867, - Block: 7761368, - Status: StatusCompleted, - Memo: "test", - Meta: Transfer{ - Value: "10000000000000", - Decimals: 8, - Symbol: "BNB", - }, - } - - nativeTransferDst1 = Tx{ - ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", - Coin: coin.BNB, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - Fee: "125000", - Date: 1555117625, - Block: 7928667, - Status: StatusCompleted, - Memo: "test", - Meta: NativeTokenTransfer{ - TokenID: "YLC-D8B", - Symbol: "YLC", - Value: "210572645", - Decimals: 8, - From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", - To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", - }, - } - - utxoTransferDst1 = Tx{ - ID: "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - Coin: coin.BTC, - Inputs: []TxOutput{ - { - Address: "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", - Value: "1", - }, - { - Address: "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh", - Value: "1", - }, - { - Address: "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737", - Value: "1", - }, - }, - Outputs: []TxOutput{ - { - Address: "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", - Value: "3", - }, - }, - Fee: "125000", - Date: 1555117625, - Block: 592400, - Status: StatusCompleted, - Memo: "test", - } - - utxoTransferDst2 = Tx{ - ID: "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", - Coin: coin.BTC, - Inputs: []TxOutput{ - { - Address: "bc1q6e8sdxlgc7ekqkqyevtrx8wshfv7sg66z3z6ce", - Value: "4", - }, - { - Address: "bc1q7nn4txus4g6fc5v7d2tha35ely8mfpd8qvv6eg", - Value: "2", - }, - }, - Outputs: []TxOutput{ - { - Address: "bc1q2fpry7zwqh575huc9urwfdvjtuvz508wez56ff", - Value: "3", - }, - { - Address: "bc1qk3yj6h79qw7tnsg4durc9sd5fpd3qt0p0m8u5p", - Value: "1", - }, - { - Address: "bc1qm8836plkzft2rhh23z6j8s9s8fxrzd4zag95z8", - Value: "2", - }, - }, - Fee: "125000", - Date: 1555117625, - Block: 592400, - Status: StatusCompleted, - Memo: "test", - } -) - -func TestTx_GetAddresses(t *testing.T) { - assert.Equal(t, transferDst1.GetAddresses(), []string{"tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", "tbnb1sylyjw032eajr9cyllp26n04300qzzre38qyv5"}) - assert.Equal(t, nativeTransferDst1.GetAddresses(), []string{"tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex"}) -} - -func TestTx_GetUtxoAddresses(t *testing.T) { - assert.Equal(t, utxoTransferDst1.GetUtxoAddresses(), []string{ - "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", - "bc1qc7ekqf2t0elfsmtgr2mgd7da2up4vgq8uqk2nh", - "bc1qv454wacvnenr3hzzldjqn8cgfltdlxwe96h737", - "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", - }) - assert.Equal(t, utxoTransferDst2.GetUtxoAddresses(), []string{ - "bc1q6e8sdxlgc7ekqkqyevtrx8wshfv7sg66z3z6ce", - "bc1q7nn4txus4g6fc5v7d2tha35ely8mfpd8qvv6eg", - "bc1q2fpry7zwqh575huc9urwfdvjtuvz508wez56ff", - "bc1qk3yj6h79qw7tnsg4durc9sd5fpd3qt0p0m8u5p", - "bc1qm8836plkzft2rhh23z6j8s9s8fxrzd4zag95z8", - }) -} - -func Test_getDirection(t *testing.T) { - type args struct { - tx Tx - address string - } - tests := []struct { - name string - args args - want Direction - }{ - {"Test Direction Self", - args{ - Tx{ - From: "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1", To: "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, - "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, DirectionSelf, - }, - {"Test Direction Outgoing", - args{ - Tx{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7"}, - "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB"}, DirectionOutgoing, - }, - {"Test Direction Incoming", - args{ - Tx{ - From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", To: "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, - "0xfc10cab6a50a1ab10c56983c80cc82afc6559cf1"}, DirectionIncoming, - }, - {"Test UTXO Direction Self", - args{ - Tx{ - Outputs: []TxOutput{ - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "72934112534"}, - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "500000000"}, - }, - Inputs: []TxOutput{ - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "73196112534"}, - }, - }, "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", - }, DirectionSelf, - }, - {"Test UTXO Direction Outgoing", - args{ - Tx{ - Outputs: []TxOutput{ - {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, - {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, - }, - Inputs: []TxOutput{ - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, - }, - }, "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", - }, DirectionOutgoing, - }, - {"Test UTXO Direction Incoming", - args{ - Tx{ - Outputs: []TxOutput{ - {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, - {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, - }, - Inputs: []TxOutput{ - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, - }, - }, "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", - }, DirectionIncoming, - }, - {"Test NativeTokenTransfer Direction Self", - args{ - Tx{ - Meta: &NativeTokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, DirectionSelf, - }, - {"Test NativeTokenTransfer Direction Outgoing", - args{ - Tx{ - Meta: &NativeTokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, DirectionOutgoing, - }, - {"Test NativeTokenTransfer Direction Incoming", - args{ - Tx{ - Meta: &NativeTokenTransfer{ - From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, DirectionIncoming, - }, - {"Test TokenTransfer Direction Self", - args{ - Tx{ - Meta: &TokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, DirectionSelf, - }, - {"Test TokenTransfer Direction Outgoing", - args{ - Tx{ - Meta: &TokenTransfer{ - From: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - To: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, DirectionOutgoing, - }, - {"Test TokenTransfer Direction Incoming", - args{ - Tx{ - Meta: &TokenTransfer{ - From: "0x74c8199372c584DAB8b14c519bc8BC8C622F37b7", - To: "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, - }, "0x5574Cd97432cEd0D7Caf58ac3c4fEDB2061C98fB", - }, DirectionIncoming, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.args.tx.GetTransactionDirection(tt.args.address); got != tt.want { - t.Errorf("getTransactionDirection() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_inferUtxoValue(t *testing.T) { - type args struct { - tx Tx - address string - coinIndex uint - } - tests := []struct { - name string - args args - wantAmount Amount - }{ - {"Test UTXO Direction Self", - args{ - Tx{ - Outputs: []TxOutput{ - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "72934112534"}, - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "500000000"}, - }, - Inputs: []TxOutput{ - {Address: "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", Value: "73196112534"}, - }, - }, "DAzruJfMBhd1vcQ13gVVyqb2g1vSEo2d5S", 3, - }, Amount("72934112534"), - }, - {"Test UTXO Direction Outgoing", - args{ - Tx{ - Outputs: []TxOutput{ - {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, - {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, - }, - Inputs: []TxOutput{ - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, - }, - }, "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", 0, - }, Amount("4471835"), - }, - {"Test UTXO Direction Incoming", - args{ - Tx{ - Outputs: []TxOutput{ - {Address: "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", Value: "4471835"}, - {Address: "324Wmkkbr9uT9xnLUqFvCA3ntqqpqEZQDp", Value: "1600000"}, - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1262899630"}, - }, - Inputs: []TxOutput{ - {Address: "32yRH5tNnFtAXE844wNrHN7Bf3SBcb3Uhd", Value: "1268998877"}, - }, - }, "3BMEXVshYmWqc8qcQLyBQPgRgAPfogWdJ4", 0, - }, Amount("4471835"), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - expect := Transfer{ - Value: tt.wantAmount, - Symbol: coin.Coins[tt.args.coinIndex].Symbol, - Decimals: coin.Coins[tt.args.coinIndex].Decimals, - } - tt.args.tx.Direction = tt.args.tx.GetTransactionDirection(tt.args.address) - if tt.args.tx.InferUtxoValue(tt.args.address, tt.args.coinIndex); tt.args.tx.Meta != expect { - t.Errorf("inferUtxoValue() = %v, want %v", tt.args.tx.Meta, expect) - } - }) - } -} - -// zpub: zpub6r9CEhEkruYbEcu2yQCaRKQ1qufTa4zLrx6ezs31P627UpAepVNBE2td3d3mHnSaXyRbwksRwDJGzLBWQeZPFMut8N3BvXpcwRwEWGEwAnq -var ( - btcSet = mapset.NewSet( - "bc1qfrrncxmf7skye2glyef95xlpmrlmf2e8qlav2l", - "bc1qxm90n0rxkadhdkvglev56k60qths73luzlnn7a", - "bc1q2sykr9c342mjpm9mwnps8ksk6e35lz75rpdlfe", - "bc1qs86ucvr3unce2grvfp77433npy66nzha9w0e3c", - ) - - btcInputs1 = []TxOutput{{Address: "bc1q2sykr9c342mjpm9mwnps8ksk6e35lz75rpdlfe"}} - btcOutputs1 = []TxOutput{{Address: "bc1q6wf7tj62f0uwr6almah3666th2ejefdg72ek6t"}} - - btcInputs2 = []TxOutput{{ - Address: "3CgvDkzcJ7yMZe75jNBem6Bj6nkMAWwMEf"}, - {Address: "3LyzYcB54pm9EAMmzXpFfb1kzEDAFvqBgT"}, - {Address: "3Q6DYour5q5WdMhyXsyPgBeAqPCXchzCsF"}, - {Address: "3JZZM1rwst7G5izxbFL7KNvy7ZiZ47SVqG"}, - } - - btcOutputs2 = []TxOutput{ - {Address: "139f1CrnLWvVajGzs3ZtpQhbGWxM599sho"}, - {Address: "3LyzYcB54pm9EAMmzXpFfb1kzEDAFvqBgT"}, - {Address: "bc1q9mx5tm66zs7epa4skvyuf2vfuwmtnlttj74cnl"}, - {Address: "3JZZM1rwst7G5izxbFL7KNvy7ZiZ47SVqG"}, - } - - dogeSet = mapset.NewSet("DB49sNjVdxyREXEBEzUV54TrQYYpvi3Be7") - dogeInputs = []TxOutput{{Address: "DAukM5pPtGdbPxMX1u2LYHoyhbDhEFHbnH"}} - dogeOutputs = []TxOutput{{Address: "DB49sNjVdxyREXEBEzUV54TrQYYpvi3Be7"}, {Address: "DAukM5pPtGdbPxMX1u2LYHoyhbDhEFHbnH"}} -) - -func TestInferDirection(t *testing.T) { - tests := []struct { - AddressSet mapset.Set - Inputs []TxOutput - Outputs []TxOutput - Expected Direction - Coin uint - }{ - { - btcSet, - btcInputs1, - btcOutputs1, - DirectionOutgoing, - coin.BTC, - }, - { - btcSet, - btcInputs2, - btcOutputs2, - DirectionIncoming, - coin.BTC, - }, - { - dogeSet, - dogeInputs, - dogeOutputs, - DirectionIncoming, - coin.DOGE, - }, - } - - for _, test := range tests { - tx := Tx{ - Inputs: test.Inputs, - Outputs: test.Outputs, - } - - direction := InferDirection(&tx, test.AddressSet) - if direction != test.Expected { - t.Errorf("direction is not %s", test.Expected) - } - } -} - -func TestTx_GetTransactionDirection(t *testing.T) { - txMeta := TokenTransfer{ - Name: "Kyber Network Crystal", - Symbol: "KNC", - TokenID: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - Decimals: 18, - Value: "100000000000000", - From: "0x08777CB1e80F45642752662B04886Df2d271E049", - To: "0x38d45371993eEc84f38FEDf93C646aA2D2267CEA", - } - - tx := Tx{ - ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c4", - Coin: 60, - From: "0x08777CB1e80F45642752662B04886Df2d271E049", - To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - Fee: "52473000000000", - Date: 1585169424, - Block: 9742705, - Status: "completed", - Sequence: 149, - Type: "token_transfer", - Meta: txMeta, - } - - tx.Direction = tx.GetTransactionDirection("0x38d45371993eEc84f38FEDf93C646aA2D2267CEA") - assert.Equal(t, Direction("incoming"), tx.Direction) - - tx.Meta = &txMeta - - tx.Direction = tx.GetTransactionDirection("0x38d45371993eEc84f38FEDf93C646aA2D2267CEA") - assert.Equal(t, Direction("incoming"), tx.Direction) - - tx.Direction = DirectionSelf - tx.Direction = tx.GetTransactionDirection("0x38d45371993eEc84f38FEDf93C646aA2D2267CEA") - assert.Equal(t, Direction("yourself"), tx.Direction) -} - -func TestTxs_FilterUniqueID(t *testing.T) { - tx := Tx{ - ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c4", - Coin: 60, - From: "0x08777CB1e80F45642752662B04886Df2d271E049", - To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - Fee: "52473000000000", - Date: 1585169424, - Block: 9742705, - Status: "completed", - Sequence: 149, - Type: "token_transfer", - } - tx2 := Tx{ - ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c4", - Coin: 60, - From: "0x08777CB1e80F45642752662B04886Df2d271E049", - To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - Fee: "52473000000000", - Date: 1585169424, - Block: 9742705, - Status: "completed", - Sequence: 149, - Type: "token_transfer", - } - - txs := make([]Tx, 0) - txs = append(txs, tx) - txs = append(txs, tx2) - - entry := Txs(txs) - - result := entry.FilterUniqueID() - - assert.Equal(t, entry[:1], result) -} - -func TestTxs_SortByDate(t *testing.T) { - tx := Tx{ - ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c4", - Coin: 60, - From: "0x08777CB1e80F45642752662B04886Df2d271E049", - To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - Fee: "52473000000000", - Date: 1585169423, - Block: 9742705, - Status: "completed", - Sequence: 149, - Type: "token_transfer", - } - tx2 := Tx{ - ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c5", - Coin: 60, - From: "0x08777CB1e80F45642752662B04886Df2d271E049", - To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - Fee: "52473000000000", - Date: 1585169424, - Block: 9742705, - Status: "completed", - Sequence: 149, - Type: "token_transfer", - } - tx3 := Tx{ - ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c6", - Coin: 60, - From: "0x08777CB1e80F45642752662B04886Df2d271E049", - To: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - Fee: "52473000000000", - Date: 1585169425, - Block: 9742705, - Status: "completed", - Sequence: 149, - Type: "token_transfer", - } - - txs := make([]Tx, 0) - txs = append(txs, tx) - txs = append(txs, tx2) - txs = append(txs, tx3) - - entry := Txs(txs) - isNotSorted := sort.SliceIsSorted(entry, func(i, j int) bool { - return entry[i].Date > entry[j].Date - }) - assert.True(t, !isNotSorted) - result := entry.SortByDate() - isSorted := sort.SliceIsSorted(result, func(i, j int) bool { - return result[i].Date > result[j].Date - }) - assert.True(t, isSorted) -} - -func TestTx_TokenID(t *testing.T) { - tx1 := Tx{ - Coin: 60, - From: "A", - To: "B", - Meta: NativeTokenTransfer{ - TokenID: "ABC", - From: "A", - To: "C", - }, - } - - tx2 := Tx{ - Coin: 60, - From: "D", - To: "V", - Meta: TokenTransfer{ - TokenID: "EFG", - From: "D", - To: "F", - }, - } - - tx3 := Tx{ - Coin: 60, - From: "Q", - To: "L", - Meta: AnyAction{ - TokenID: "HIJ", - }, - } - - token1, ok1 := tx1.TokenID() - assert.True(t, ok1) - assert.Equal(t, token1, "ABC") - token2, ok2 := tx2.TokenID() - assert.True(t, ok2) - assert.Equal(t, token2, "EFG") - token3, ok3 := tx3.TokenID() - assert.Equal(t, token3, "HIJ") - assert.True(t, ok3) - -} - -func TestTokenType(t *testing.T) { - type testStruct struct { - Name string - ID uint - TokenID string - WantedType string - WantedOk bool - } - tests := []testStruct{ - { - Name: "Tron TRC20", - ID: coin.Tron().ID, - TokenID: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", - WantedType: string(tokentype.TRC20), - WantedOk: true, - }, - { - Name: "Tron TRC10", - ID: coin.Tron().ID, - TokenID: "1002000", - WantedType: string(tokentype.TRC10), - WantedOk: true, - }, - { - Name: "Ethereum ERC20", - ID: coin.Ethereum().ID, - TokenID: "dai", - WantedType: string(tokentype.ERC20), - WantedOk: true, - }, - { - Name: "Binance BEP20", - ID: coin.Smartchain().ID, - TokenID: "busd", - WantedType: string(tokentype.BEP20), - WantedOk: true, - }, - { - Name: "Binance BEP10", - ID: coin.Binance().ID, - TokenID: "busd", - WantedType: string(tokentype.BEP2), - WantedOk: true, - }, - { - Name: "Wrong", - ID: coin.Bitcoin().ID, - TokenID: "busd", - WantedType: "", - WantedOk: false, - }, - } - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - expectedType, expectedOk := GetTokenType(tt.ID, tt.TokenID) - assert.Equal(t, tt.WantedType, expectedType) - assert.Equal(t, tt.WantedOk, expectedOk) - }) - } -} - -var ( - beforeTransactionsToken, _ = mock.JsonFromFilePathToString("mocks/bnb_token_txs.json") - wantedTransactionsToken, _ = mock.JsonFromFilePathToString("mocks/bnb_token_response.json") -) - -func Test_filterTransactionsByToken(t *testing.T) { - var p TxPage - assert.Nil(t, json.Unmarshal([]byte(beforeTransactionsToken), &p)) - result := p.FilterTransactionsByToken("BUSD-BD1") - rawResult, err := json.Marshal(result) - assert.Nil(t, err) - assert.JSONEq(t, wantedTransactionsToken, string(rawResult)) -} - -func Test_AllowMemo(t *testing.T) { - type args struct { - memo string - } - tests := []struct { - name string - args args - want bool - }{ - { - "Numeric memo", - args{memo: "123"}, - true, - }, - { - "Numeric memo", - args{memo: "12356172321321"}, - true, - }, - { - "Numeric memo", - args{memo: "test"}, - false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := AllowMemo(tt.args.memo); got != tt.want { - t.Errorf("isMemoAllowed() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestTxPage_FilterTransactionsByMemo(t *testing.T) { - tests := []struct { - name string - txs TxPage - want TxPage - }{ - { - name: "Allow memo", - txs: TxPage{ - { - Memo: "123", - }, - }, - want: TxPage{ - { - Memo: "123", - }, - }, - }, - { - name: "Disallow memo", - txs: TxPage{ - { - Memo: "test", - }, - }, - want: TxPage{ - { - Memo: "", - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.txs.FilterTransactionsByMemo(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("FilterTransactionsByMemo() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestTxs_FilterTransactionsByType(t *testing.T) { - type args struct { - types []TransactionType - } - tests := []struct { - name string - txs Txs - args args - want Txs - }{ - { - "Token Transfers", - Txs{ - Tx{Type: TxTransfer}, - Tx{Type: TxContractCall}, - Tx{Type: TxNativeTokenTransfer}, - Tx{Type: TxTokenTransfer}, - }, - args{ - []TransactionType{TxNativeTokenTransfer, TxTokenTransfer}, - }, - Txs{ - Tx{Type: TxNativeTokenTransfer}, - Tx{Type: TxTokenTransfer}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.txs.FilterTransactionsByType(tt.args.types); !reflect.DeepEqual(got, tt.want) { - t.Errorf("FilterTransactionsByType() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/platform/aeternity/transaction.go b/platform/aeternity/transaction.go index 33380a544..5544e9479 100644 --- a/platform/aeternity/transaction.go +++ b/platform/aeternity/transaction.go @@ -4,18 +4,18 @@ import ( "encoding/base64" "strings" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - addressTxs, err := p.client.GetTxs(address, blockatlas.TxPerPage) +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { + addressTxs, err := p.client.GetTxs(address, types.TxPerPage) if err != nil { return nil, err } - var txs []blockatlas.Tx + var txs []types.Tx for _, srcTx := range addressTxs { tx, err := NormalizeTx(&srcTx) if err != nil { @@ -26,27 +26,27 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func NormalizeTx(srcTx *Transaction) (blockatlas.Tx, error) { +func NormalizeTx(srcTx *Transaction) (types.Tx, error) { txValue := srcTx.TxValue decimals := coin.Coins[coin.AE].Decimals amountFloat, err := txValue.Amount.Float64() if err != nil { - return blockatlas.Tx{}, err + return types.Tx{}, err } amount := numbers.Float64toString(amountFloat) - return blockatlas.Tx{ + return types.Tx{ ID: srcTx.Hash, Coin: coin.AE, From: txValue.Sender, To: txValue.Recipient, - Fee: blockatlas.Amount(txValue.Fee), + Fee: types.Amount(txValue.Fee), Date: srcTx.Timestamp / 1000, Block: srcTx.BlockHeight, Memo: getPayload(txValue.Payload), - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Sequence: txValue.Nonce, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(amount), + Meta: types.Transfer{ + Value: types.Amount(amount), Symbol: coin.Coins[coin.AE].Symbol, Decimals: decimals, }, diff --git a/platform/aeternity/transaction_test.go b/platform/aeternity/transaction_test.go index 0b9af941c..e99d4e8db 100644 --- a/platform/aeternity/transaction_test.go +++ b/platform/aeternity/transaction_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) func TestNormalizeTx(t *testing.T) { @@ -17,7 +17,7 @@ func TestNormalizeTx(t *testing.T) { tests := []struct { name string args args - wantTx blockatlas.Tx + wantTx types.Tx wantErr bool }{ { @@ -25,7 +25,7 @@ func TestNormalizeTx(t *testing.T) { args: args{ filename: "transfer.json", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "th_oJfBC6KZKaKsL4WXTq1ZtFiSE8Wp2PQYEnwyZqtudyHcU3Qg6", Coin: coin.AE, From: "ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv", @@ -33,10 +33,10 @@ func TestNormalizeTx(t *testing.T) { Fee: "20500000000000", Date: 1563848658, Block: 113579, - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Memo: "Hello, Miner! /Yours Beepool./", Sequence: 251291, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "252550000000000000000", Symbol: "AE", Decimals: 18, @@ -48,7 +48,7 @@ func TestNormalizeTx(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var srcTx Transaction - _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &srcTx) gotTx, err := NormalizeTx(&srcTx) if (err != nil) != tt.wantErr { t.Errorf("NormalizeTx() error = %v, wantErr %v", err, tt.wantErr) diff --git a/platform/aion/transaction.go b/platform/aion/transaction.go index 404b38c1d..6d89e9c19 100644 --- a/platform/aion/transaction.go +++ b/platform/aion/transaction.go @@ -3,13 +3,13 @@ package aion import ( "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - if srcTxs, err := p.client.GetTxsOfAddress(address, blockatlas.TxPerPage); err == nil { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { + if srcTxs, err := p.client.GetTxsOfAddress(address, types.TxPerPage); err == nil { return NormalizeTxs(srcTxs.Content), err } else { return nil, err @@ -17,7 +17,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { } // NormalizeTx converts an Aion transaction into the generic model -func NormalizeTx(srcTx *Tx) (tx blockatlas.Tx, ok bool) { +func NormalizeTx(srcTx *Tx) (tx types.Tx, ok bool) { fee := strconv.Itoa(srcTx.NrgConsumed) value := numbers.DecimalExp(string(srcTx.Value), 18) value, ok = numbers.CutZeroFractional(value) @@ -25,17 +25,17 @@ func NormalizeTx(srcTx *Tx) (tx blockatlas.Tx, ok bool) { return tx, false } - return blockatlas.Tx{ + return types.Tx{ ID: "0x" + srcTx.TransactionHash, Coin: coin.AION, Date: srcTx.BlockTimestamp, From: "0x" + srcTx.FromAddr, To: "0x" + srcTx.ToAddr, - Fee: blockatlas.Amount(fee), + Fee: types.Amount(fee), Block: srcTx.BlockNumber, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(value), + Status: types.StatusCompleted, + Meta: types.Transfer{ + Value: types.Amount(value), Symbol: coin.Coins[coin.AION].Symbol, Decimals: coin.Coins[coin.AION].Decimals, }, @@ -43,8 +43,8 @@ func NormalizeTx(srcTx *Tx) (tx blockatlas.Tx, ok bool) { } // NormalizeTxs converts multiple Aion transactions -func NormalizeTxs(srcTxs []Tx) []blockatlas.Tx { - var txs []blockatlas.Tx +func NormalizeTxs(srcTxs []Tx) []types.Tx { + var txs []types.Tx for _, srcTx := range srcTxs { tx, ok := NormalizeTx(&srcTx) if ok { diff --git a/platform/aion/transaction_test.go b/platform/aion/transaction_test.go index e33b93af9..3b2855058 100644 --- a/platform/aion/transaction_test.go +++ b/platform/aion/transaction_test.go @@ -4,9 +4,9 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) func TestNormalizeTx(t *testing.T) { @@ -16,7 +16,7 @@ func TestNormalizeTx(t *testing.T) { tests := []struct { name string args args - wantTx blockatlas.Tx + wantTx types.Tx wantOk bool }{ { @@ -24,7 +24,7 @@ func TestNormalizeTx(t *testing.T) { args: args{ srcTx: "transfer.json", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "0xaf3c2f5087fc3332154dc9d11c27e312f30ff829dbc5436aec8cc4342c7dc384", Coin: coin.AION, From: "0xa07981da70ce919e1db5f051c3c386eb526e6ce8b9e2bfd56e3f3d754b0a17f3", @@ -32,8 +32,8 @@ func TestNormalizeTx(t *testing.T) { Fee: "21000", Date: 1554862228, Block: 2880919, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Meta: types.Transfer{ Value: "11903810405853733000", Symbol: "AION", Decimals: 18, @@ -45,7 +45,7 @@ func TestNormalizeTx(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var srcTx Tx - _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.srcTx, &srcTx) + _ = mock.JsonModelFromFilePath("mocks/"+tt.args.srcTx, &srcTx) gotTx, gotOk := NormalizeTx(&srcTx) if !reflect.DeepEqual(gotTx, tt.wantTx) { t.Errorf("NormalizeTx() gotTx = %v, want %v", gotTx, tt.wantTx) diff --git a/platform/algorand/block.go b/platform/algorand/block.go index b9260aaa6..9294fa291 100644 --- a/platform/algorand/block.go +++ b/platform/algorand/block.go @@ -1,20 +1,18 @@ package algorand -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.GetLatestBlock() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { txs, err := p.client.GetTxsInBlock(num) if err != nil { return nil, err } - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: NormalizeTxs(txs), }, nil diff --git a/platform/algorand/transaction.go b/platform/algorand/transaction.go index ca977a60d..80be3a3f5 100644 --- a/platform/algorand/transaction.go +++ b/platform/algorand/transaction.go @@ -3,11 +3,11 @@ package algorand import ( "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { txs, err := p.client.GetTxsOfAddress(address) if err != nil { return nil, err @@ -15,8 +15,8 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return NormalizeTxs(txs), nil } -func NormalizeTxs(txs []Transaction) []blockatlas.Tx { - result := make([]blockatlas.Tx, 0) +func NormalizeTxs(txs []Transaction) []types.Tx { + result := make([]types.Tx, 0) for _, tx := range txs { if normalized, ok := Normalize(tx); ok { @@ -27,24 +27,24 @@ func NormalizeTxs(txs []Transaction) []blockatlas.Tx { return result } -func Normalize(tx Transaction) (result blockatlas.Tx, ok bool) { +func Normalize(tx Transaction) (result types.Tx, ok bool) { if tx.Type != TransactionTypePay { return result, false } - return blockatlas.Tx{ + return types.Tx{ ID: tx.Hash, Coin: coin.ALGO, From: tx.From, To: tx.Payment.Receiver, - Fee: blockatlas.Amount(strconv.Itoa(int(tx.Fee))), + Fee: types.Amount(strconv.Itoa(int(tx.Fee))), Date: int64(tx.Timestamp), Block: tx.Round, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(strconv.Itoa(int(tx.Payment.Amount))), + Status: types.StatusCompleted, + 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, }, diff --git a/platform/algorand/transaction_test.go b/platform/algorand/transaction_test.go index a945fb2a2..a4eab9d25 100644 --- a/platform/algorand/transaction_test.go +++ b/platform/algorand/transaction_test.go @@ -4,9 +4,9 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) func TestNormalizeTx(t *testing.T) { @@ -16,7 +16,7 @@ func TestNormalizeTx(t *testing.T) { tests := []struct { name string args args - wantTx blockatlas.Tx + wantTx types.Tx ok bool }{ { @@ -24,18 +24,18 @@ func TestNormalizeTx(t *testing.T) { args: args{ filename: "transfer.json", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "C2LK3CGBPIGERLPFUXE6INSBJGHOXU7YZMEGELWMVSBASFJYOOQQ", Coin: coin.ALGO, From: "5TSQNIL54GB545B3WLC6OVH653SHAELMHU6MSVNGTUNMOEHAMWG7EC3AA4", To: "4EZFQABCVQTHQCK3HQBIYGC4NV2VM42FZHEFTVH77ROG4ZGREC6Y7V5T2U", - Fee: blockatlas.Amount("1000"), + Fee: types.Amount("1000"), Date: 1569123058, Block: 2031351, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1"), + Status: types.StatusCompleted, + Type: types.TxTransfer, + Meta: types.Transfer{ + Value: types.Amount("1"), Symbol: "ALGO", Decimals: 6, }, @@ -46,7 +46,7 @@ func TestNormalizeTx(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var response TransactionsResponse - _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &response) + _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &response) gotTx, ok := Normalize(response.Transactions[0]) if ok != tt.ok { t.Errorf("Normalize() ok = %v, wantOk %v", ok, tt.ok) diff --git a/platform/binance/base_test.go b/platform/binance/base_test.go index e166b5c10..5241df002 100644 --- a/platform/binance/base_test.go +++ b/platform/binance/base_test.go @@ -8,17 +8,17 @@ import ( ) var ( - wantedBlockNoOrders, _ = mock.JsonFromFilePathToString("mocks/block_no_orders.json") - wantedTxs, _ = mock.JsonFromFilePathToString("mocks/txs.json") - wantedTokens, _ = mock.JsonFromFilePathToString("mocks/tokens.json") - wantedBlockMultiNoOrders, _ = mock.JsonFromFilePathToString("mocks/block_multi_no_orders.json") - wantedTxsResponse, _ = mock.JsonFromFilePathToString("mocks/txs_response.json") - wantedAccountMetaResponse, _ = mock.JsonFromFilePathToString("mocks/account_meta_response.json") - wantedTokensResponse, _ = mock.JsonFromFilePathToString("mocks/tokens_response.json") - wantedTxsResponseAva, _ = mock.JsonFromFilePathToString("mocks/txs_ava_response.json") - wantedBlockResponseMulti, _ = mock.JsonFromFilePathToString("mocks/block_multi_response.json") - mockedBlockResponse, _ = mock.JsonFromFilePathToString("mocks/block_response.json") - mockedNodeInfo, _ = mock.JsonFromFilePathToString("mocks/node_info.json") + wantedBlockNoOrders, _ = mock.JsonStringFromFilePath("mocks/block_no_orders.json") + wantedTxs, _ = mock.JsonStringFromFilePath("mocks/txs.json") + wantedTokens, _ = mock.JsonStringFromFilePath("mocks/tokens.json") + wantedBlockMultiNoOrders, _ = mock.JsonStringFromFilePath("mocks/block_multi_no_orders.json") + wantedTxsResponse, _ = mock.JsonStringFromFilePath("mocks/txs_response.json") + wantedAccountMetaResponse, _ = mock.JsonStringFromFilePath("mocks/account_meta_response.json") + wantedTokensResponse, _ = mock.JsonStringFromFilePath("mocks/tokens_response.json") + wantedTxsResponseAva, _ = mock.JsonStringFromFilePath("mocks/txs_ava_response.json") + wantedBlockResponseMulti, _ = mock.JsonStringFromFilePath("mocks/block_multi_response.json") + mockedBlockResponse, _ = mock.JsonStringFromFilePath("mocks/block_response.json") + mockedNodeInfo, _ = mock.JsonStringFromFilePath("mocks/node_info.json") ) func createMockedAPI() http.Handler { diff --git a/platform/binance/block.go b/platform/binance/block.go index 49492b2c4..92831e042 100644 --- a/platform/binance/block.go +++ b/platform/binance/block.go @@ -1,8 +1,6 @@ package binance -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { block, err := p.client.FetchLatestBlockNumber() @@ -12,7 +10,7 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { return block, nil } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { transactionInBlockResponse, err := p.client.FetchTransactionsInBlock(num) if err != nil { return nil, err diff --git a/platform/binance/client.go b/platform/binance/client.go index 9bedcae25..b48caa7da 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -8,8 +8,8 @@ import ( "github.com/trustwallet/blockatlas/internal" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/types" ) type Client struct { @@ -43,7 +43,7 @@ func (c Client) FetchTransactionsInBlock(blockNumber int64) (TransactionsInBlock func (c Client) FetchTransactionsByAddressAndTokenID(address, tokenID string) ([]Tx, error) { var result TransactionsInBlockResponse startTime := strconv.Itoa(int(time.Now().AddDate(0, -3, 0).Unix() * 1000)) - limit := strconv.Itoa(blockatlas.TxPerPage) + limit := strconv.Itoa(types.TxPerPage) params := url.Values{"address": {address}, "txAsset": {tokenID}, "startTime": {startTime}, "limit": {limit}} err := c.Get(&result, "api/v1/transactions", params) if err != nil { diff --git a/platform/binance/model.go b/platform/binance/model.go index f8c3026bf..fb152892a 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -1,12 +1,12 @@ package binance import ( - "github.com/trustwallet/golibs/tokentype" "strconv" "strings" "time" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" + "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" ) @@ -104,18 +104,18 @@ type ( } ) -func normalizeBlock(response TransactionsInBlockResponse) blockatlas.Block { - result := blockatlas.Block{ +func normalizeBlock(response TransactionsInBlockResponse) types.Block { + result := types.Block{ Number: int64(response.BlockHeight), } result.Txs = normalizeTransactions(response.Tx) return result } -func normalizeTransactions(txs []Tx) []blockatlas.Tx { - totalTxs := make([]blockatlas.Tx, 0, len(txs)) +func normalizeTransactions(txs []Tx) []types.Tx { + totalTxs := make([]types.Tx, 0, len(txs)) for _, t := range txs { - var txs []blockatlas.Tx + var txs []types.Tx switch t.TxType { case CancelOrder, NewOrder: //txs = append(txs, normalizeOrderTransaction(t)) @@ -132,21 +132,21 @@ func normalizeTransactions(txs []Tx) []blockatlas.Tx { return totalTxs } -func normalizeTransferTransaction(t Tx) blockatlas.Tx { +func normalizeTransferTransaction(t Tx) types.Tx { tx := normalizeBaseOfTransaction(t) tx.To = t.ToAddr.(string) tx.From = t.FromAddr.(string) switch { case t.TxAsset == BNBAsset: - tx.Type = blockatlas.TxTransfer - tx.Meta = blockatlas.Transfer{ + tx.Type = types.TxTransfer + tx.Meta = types.Transfer{ Value: normalizeAmount(t.Value), Symbol: coin.Binance().Symbol, Decimals: coin.Binance().Decimals, } case t.TxAsset != "": - tx.Type = blockatlas.TxNativeTokenTransfer - tx.Meta = blockatlas.NativeTokenTransfer{ + tx.Type = types.TxNativeTokenTransfer + tx.Meta = types.NativeTokenTransfer{ Decimals: coin.Binance().Decimals, From: t.FromAddr.(string), Symbol: getTokenSymbolFromID(t.TxAsset), @@ -159,10 +159,10 @@ func normalizeTransferTransaction(t Tx) blockatlas.Tx { return tx } -func normalizeMultiTransferTransaction(t Tx) []blockatlas.Tx { - txs := make([]blockatlas.Tx, 0, len(t.SubTransactions)) +func normalizeMultiTransferTransaction(t Tx) []types.Tx { + txs := make([]types.Tx, 0, len(t.SubTransactions)) for _, subTx := range t.SubTransactions { - tx := blockatlas.Tx{ + tx := types.Tx{ ID: subTx.TxHash, Coin: coin.Binance().ID, From: subTx.FromAddr, @@ -170,21 +170,21 @@ func normalizeMultiTransferTransaction(t Tx) []blockatlas.Tx { Fee: normalizeFee(subTx.TxFee), Date: t.TimeStamp.Unix(), Block: uint64(t.BlockHeight), - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Sequence: uint64(t.Sequence), Memo: t.Memo, } switch { case subTx.TxAsset == BNBAsset: - tx.Type = blockatlas.TxTransfer - tx.Meta = blockatlas.Transfer{ + tx.Type = types.TxTransfer + tx.Meta = types.Transfer{ Value: normalizeAmount(subTx.Value), Symbol: coin.Binance().Symbol, Decimals: coin.Binance().Decimals, } case subTx.TxAsset != "": - tx.Type = blockatlas.TxNativeTokenTransfer - tx.Meta = blockatlas.NativeTokenTransfer{ + tx.Type = types.TxNativeTokenTransfer + tx.Meta = types.NativeTokenTransfer{ Decimals: coin.Binance().Decimals, Name: getTokenSymbolFromID(subTx.TxAsset), From: subTx.FromAddr, @@ -201,53 +201,22 @@ func normalizeMultiTransferTransaction(t Tx) []blockatlas.Tx { return txs } -func normalizeBaseOfTransaction(t Tx) blockatlas.Tx { - return blockatlas.Tx{ +func normalizeBaseOfTransaction(t Tx) types.Tx { + return types.Tx{ ID: t.TxHash, Coin: coin.Binance().ID, From: t.FromAddr.(string), Fee: normalizeFee(t.TxFee), Date: t.TimeStamp.Unix(), Block: uint64(t.BlockHeight), - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Sequence: uint64(t.Sequence), Memo: t.Memo, } } -//func normalizeOrderTransaction(t Tx) blockatlas.Tx { -// tx := normalizeBaseOfTransaction(t) -// tx.Type = blockatlas.TxAnyAction -// meta := blockatlas.AnyAction{ -// Coin: coin.Binance().ID, -// Decimals: coin.Binance().Decimals, -// } -// -// data, err := getTransactionData(t.Data) -// if err == nil { -// base, _ := getTokenIDsFromPair(data.OrderData.Symbol) -// meta.TokenID = base -// meta.Value = blockatlas.Amount(numbers.FromDecimalExp(data.OrderData.Quantity, int(coin.Binance().Decimals))) -// meta.Name = data.OrderData.Side -// meta.Symbol = getTokenSymbolFromID(base) -// } -// switch t.TxType { -// case CancelOrder: -// meta.Title = blockatlas.KeyTitleCancelOrder -// meta.Key = blockatlas.KeyCancelOrder -// meta.Value = "0" -// case NewOrder: -// meta.Title = blockatlas.KeyTitlePlaceOrder -// meta.Key = blockatlas.KeyPlaceOrder -// } -// -// tx.Meta = meta -// tx.Direction = blockatlas.DirectionOutgoing -// return tx -//} - -func normalizeTokens(srcBalance []TokenBalance, tokens Tokens) []blockatlas.Token { - tokensList := make([]blockatlas.Token, 0, len(srcBalance)) +func normalizeTokens(srcBalance []TokenBalance, tokens Tokens) []types.Token { + tokensList := make([]types.Token, 0, len(srcBalance)) for _, srcToken := range srcBalance { token, ok := normalizeToken(srcToken, tokens) if !ok { @@ -258,8 +227,8 @@ func normalizeTokens(srcBalance []TokenBalance, tokens Tokens) []blockatlas.Toke return tokensList } -func normalizeToken(srcToken TokenBalance, tokens Tokens) (blockatlas.Token, bool) { - var result blockatlas.Token +func normalizeToken(srcToken TokenBalance, tokens Tokens) (types.Token, bool) { + var result types.Token if srcToken.isAllZeroBalance() { return result, false } @@ -269,13 +238,13 @@ func normalizeToken(srcToken TokenBalance, tokens Tokens) (blockatlas.Token, boo return result, false } - result = blockatlas.Token{ + result = types.Token{ Name: token.Name, Symbol: token.OriginalSymbol, TokenID: token.Symbol, Coin: coin.Binance().ID, Decimals: coin.Binance().Decimals, - Type: tokentype.BEP2, + Type: types.BEP2, } return result, true @@ -303,15 +272,15 @@ func getTokenSymbolFromID(tokenID string) string { return tokenID } -func normalizeAmount(amount string) blockatlas.Amount { +func normalizeAmount(amount string) types.Amount { val := numbers.DecimalExp(amount, int(coin.Binance().Decimals)) - return blockatlas.Amount(val) + return types.Amount(val) } -func normalizeFee(amount string) blockatlas.Amount { +func normalizeFee(amount string) types.Amount { a, err := numbers.StringNumberToFloat64(amount) if a != 0 && err == nil { - return blockatlas.Amount(numbers.DecimalExp(amount, int(coin.Binance().Decimals))) + return types.Amount(numbers.DecimalExp(amount, int(coin.Binance().Decimals))) } else { return "0" } diff --git a/platform/binance/token.go b/platform/binance/token.go index 490d4162a..8448cb219 100644 --- a/platform/binance/token.go +++ b/platform/binance/token.go @@ -1,10 +1,8 @@ package binance -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" -func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { +func (p *Platform) GetTokenListByAddress(address string) (types.TokenPage, error) { account, err := p.client.FetchAccountMeta(address) if err != nil || len(account.Balances) == 0 { return nil, nil diff --git a/platform/binance/transaction.go b/platform/binance/transaction.go index ca73e1584..32b58ff2d 100644 --- a/platform/binance/transaction.go +++ b/platform/binance/transaction.go @@ -1,11 +1,11 @@ package binance import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { txsFromClient, err := p.client.FetchTransactionsByAddressAndTokenID(address, coin.Binance().Symbol) if err != nil { return nil, err @@ -13,7 +13,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return normalizeTransactions(txsFromClient), nil } -func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, error) { txsFromClient, err := p.client.FetchTransactionsByAddressAndTokenID(address, token) if err != nil { return nil, err diff --git a/platform/bitcoin/block.go b/platform/bitcoin/block.go index 12bce3d84..61b12f175 100644 --- a/platform/bitcoin/block.go +++ b/platform/bitcoin/block.go @@ -1,23 +1,21 @@ package bitcoin -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.GetCurrentBlockNumber() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { block, err := p.client.GetAllTransactionsByBlockNumber(num) if err != nil { return nil, err } - var normalized []blockatlas.Tx + var normalized []types.Tx for _, tx := range block { normalized = append(normalized, normalizeTransaction(tx, p.CoinIndex)) } - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: normalized, }, nil diff --git a/platform/bitcoin/blockbook/block.go b/platform/bitcoin/blockbook/block.go index 98e4d336a..b59394a72 100644 --- a/platform/bitcoin/blockbook/block.go +++ b/platform/bitcoin/blockbook/block.go @@ -1,19 +1,17 @@ package blockbook -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" -func (c *Client) GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, error) { +func (c *Client) GetBlockByNumber(num int64, coinIndex uint) (*types.Block, error) { block, err := c.GetAllTransactionsByBlockNumber(num) if err != nil { return nil, err } - txs := make([]blockatlas.Tx, 0) + txs := make([]types.Tx, 0) for _, srcTx := range block { txs = append(txs, normalizeTx(&srcTx, coinIndex)) } - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil diff --git a/platform/bitcoin/blockbook/client.go b/platform/bitcoin/blockbook/client.go index 712dbf54d..ead0c5c45 100644 --- a/platform/bitcoin/blockbook/client.go +++ b/platform/bitcoin/blockbook/client.go @@ -6,9 +6,8 @@ import ( "strconv" "sync" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/types" ) type Client struct { @@ -49,11 +48,11 @@ func (c *Client) GetAllTransactionsByBlockNumber(num int64) ([]Transaction, erro } func (c *Client) GetTxs(address string) (TransactionsList, error) { - return c.getTransactionsForContract(address, "", blockatlas.TxPerPage) + return c.getTransactionsForContract(address, "", types.TxPerPage) } func (c *Client) GetTxsWithContract(address, contract string) (TransactionsList, error) { - return c.getTransactionsForContract(address, contract, blockatlas.TxPerPage) + return c.getTransactionsForContract(address, contract, types.TxPerPage) } func (c *Client) GetTransactionsByBlockNumber(number int64, page int64) (block TransactionsList, err error) { @@ -79,7 +78,7 @@ func (c *Client) getTransactionsForContract(address, contract string, limit int) func (c *Client) GetTransactionsByXpub(xpub string) (transactions TransactionsList, err error) { path := fmt.Sprintf("api/v2/xpub/%s", xpub) args := url.Values{ - "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, + "pageSize": {strconv.Itoa(types.TxPerPage)}, "details": {"txs"}, "tokens": {"derived"}, } @@ -90,7 +89,7 @@ func (c *Client) GetTransactionsByXpub(xpub string) (transactions TransactionsLi func (c *Client) GetAddressesFromXpub(xpub string) (tokens []Token, err error) { path := fmt.Sprintf("api/v2/xpub/%s", xpub) args := url.Values{ - "pageSize": {strconv.Itoa(blockatlas.TxPerPage)}, + "pageSize": {strconv.Itoa(types.TxPerPage)}, "details": {"txs"}, "tokens": {"derived"}, } diff --git a/platform/bitcoin/blockbook/model.go b/platform/bitcoin/blockbook/model.go index 0e27e31d4..2cc0c679a 100644 --- a/platform/bitcoin/blockbook/model.go +++ b/platform/bitcoin/blockbook/model.go @@ -4,9 +4,7 @@ import ( "encoding/json" "math/big" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - - "github.com/trustwallet/golibs/tokentype" + "github.com/trustwallet/golibs/types" ) type NodeInfo struct { @@ -30,12 +28,12 @@ type TokenTransfer struct { // Token contains info about tokens held by an address type Token struct { - Balance string `json:"balance,omitempty"` - Contract string `json:"contract"` - Decimals uint `json:"decimals"` - Name string `json:"name"` - Symbol string `json:"symbol"` - Type tokentype.Type `json:"type"` + Balance string `json:"balance,omitempty"` + Contract string `json:"contract"` + Decimals uint `json:"decimals"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Type types.TokenType `json:"type"` } // EthereumSpecific contains ethereum specific transaction data @@ -98,11 +96,11 @@ func (transaction Transaction) Amount() string { return transaction.Value } -func (transaction Transaction) GetStatus() blockatlas.Status { +func (transaction Transaction) GetStatus() types.Status { if transaction.Confirmations == 0 { - return blockatlas.StatusPending + return types.StatusPending } - return blockatlas.StatusCompleted + return types.StatusCompleted } func (transaction Transaction) GetBlockHeight() uint64 { diff --git a/platform/bitcoin/blockbook/model_extension.go b/platform/bitcoin/blockbook/model_extension.go index 787ce710e..007e9dbf6 100644 --- a/platform/bitcoin/blockbook/model_extension.go +++ b/platform/bitcoin/blockbook/model_extension.go @@ -3,19 +3,19 @@ package blockbook import ( "math/big" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) -func (s *EthereumSpecific) GetStatus() (blockatlas.Status, string) { +func (s *EthereumSpecific) GetStatus() (types.Status, string) { switch s.Status { case -1: - return blockatlas.StatusPending, "" + return types.StatusPending, "" case 0: - return blockatlas.StatusError, "Error" + return types.StatusError, "Error" case 1: - return blockatlas.StatusCompleted, "" + return types.StatusCompleted, "" default: - return blockatlas.StatusError, "Unable to define transaction status" + return types.StatusError, "Unable to define transaction status" } } @@ -28,7 +28,7 @@ func (transaction *Transaction) FromAddress() string { func (transaction *Transaction) GetFee() string { status, _ := transaction.EthereumSpecific.GetStatus() - if status != blockatlas.StatusPending { + if status != types.StatusPending { return transaction.Fees } @@ -48,12 +48,12 @@ func (transaction *Transaction) ToAddress() string { return "" } -func GetDirection(address, from, to string) blockatlas.Direction { +func GetDirection(address, from, to string) types.Direction { if address == from && address == to { - return blockatlas.DirectionSelf + return types.DirectionSelf } if address == from { - return blockatlas.DirectionOutgoing + return types.DirectionOutgoing } - return blockatlas.DirectionIncoming + return types.DirectionIncoming } diff --git a/platform/bitcoin/blockbook/token.go b/platform/bitcoin/blockbook/token.go index 5f72ce196..09d4ac440 100644 --- a/platform/bitcoin/blockbook/token.go +++ b/platform/bitcoin/blockbook/token.go @@ -1,11 +1,10 @@ package blockbook import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/tokentype" + "github.com/trustwallet/golibs/types" ) -func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) { +func (c *Client) GetTokenList(address string, coinIndex uint) (types.TokenPage, error) { tokens, err := c.GetTokens(address) if err != nil { return nil, err @@ -13,8 +12,8 @@ func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenP return NormalizeTokens(tokens, coinIndex), nil } -func NormalizeTokens(srcTokens []Token, coinIndex uint) []blockatlas.Token { - tokenPage := make([]blockatlas.Token, 0, len(srcTokens)) +func NormalizeTokens(srcTokens []Token, coinIndex uint) []types.Token { + tokenPage := make([]types.Token, 0, len(srcTokens)) for _, srcToken := range srcTokens { if srcToken.Balance == "0" || srcToken.Balance == "" { continue @@ -25,13 +24,13 @@ func NormalizeTokens(srcTokens []Token, coinIndex uint) []blockatlas.Token { return tokenPage } -func NormalizeToken(srcToken *Token, coinIndex uint) blockatlas.Token { - return blockatlas.Token{ +func NormalizeToken(srcToken *Token, coinIndex uint) types.Token { + return types.Token{ Name: srcToken.Name, Symbol: srcToken.Symbol, TokenID: srcToken.Contract, Coin: coinIndex, Decimals: srcToken.Decimals, - Type: tokentype.GetEthereumTokenTypeByIndex(coinIndex), + Type: types.GetEthereumTokenTypeByIndex(coinIndex), } } diff --git a/platform/bitcoin/blockbook/token_test.go b/platform/bitcoin/blockbook/token_test.go index 72beaa855..560bd44d1 100644 --- a/platform/bitcoin/blockbook/token_test.go +++ b/platform/bitcoin/blockbook/token_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) func TestNormalizeToken(t *testing.T) { @@ -15,7 +15,7 @@ func TestNormalizeToken(t *testing.T) { tests := []struct { name string args args - want []blockatlas.Token + want []types.Token }{ { name: "Should normalize and return token with balance", @@ -27,7 +27,7 @@ func TestNormalizeToken(t *testing.T) { Symbol: "USDC", Decimals: 6}, coinIndex: 60}, - want: []blockatlas.Token{ + want: []types.Token{ { Type: "ERC20", Name: "USD//C", @@ -44,7 +44,7 @@ func TestNormalizeToken(t *testing.T) { Symbol: "USDC", Decimals: 6}, coinIndex: 60}, - want: []blockatlas.Token{}, + want: []types.Token{}, }, { name: "Should not return token with zero balance", args: args{srcToken: Token{ @@ -55,7 +55,7 @@ func TestNormalizeToken(t *testing.T) { Symbol: "USDC", Decimals: 6}, coinIndex: 60}, - want: []blockatlas.Token{}, + want: []types.Token{}, }, } for _, tt := range tests { diff --git a/platform/bitcoin/blockbook/transaction.go b/platform/bitcoin/blockbook/transaction.go index 23e40ff67..f2a412e46 100644 --- a/platform/bitcoin/blockbook/transaction.go +++ b/platform/bitcoin/blockbook/transaction.go @@ -3,12 +3,12 @@ package blockbook import ( "strings" - "github.com/trustwallet/blockatlas/pkg/blockatlas" Address "github.com/trustwallet/golibs/address" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (c *Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) { +func (c *Client) GetTransactions(address string, coinIndex uint) (types.TxPage, error) { page, err := c.GetTxs(address) if err != nil { return nil, err @@ -16,7 +16,7 @@ func (c *Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxP return NormalizePage(page, address, "", coinIndex), nil } -func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas.TxPage, error) { +func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (types.TxPage, error) { page, err := c.GetTxsWithContract(address, token) if err != nil { return nil, err @@ -24,7 +24,7 @@ func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas. return NormalizePage(page, address, token, coinIndex), nil } -func NormalizePage(srcPage TransactionsList, address, token string, coinIndex uint) (txs blockatlas.TxPage) { +func NormalizePage(srcPage TransactionsList, address, token string, coinIndex uint) (txs types.TxPage) { normalizedAddr, err := Address.EIP55Checksum(address) if err != nil { return @@ -43,14 +43,14 @@ func NormalizePage(srcPage TransactionsList, address, token string, coinIndex ui return txs } -func normalizeTx(srcTx *Transaction, coinIndex uint) blockatlas.Tx { +func normalizeTx(srcTx *Transaction, coinIndex uint) types.Tx { status, errReason := srcTx.EthereumSpecific.GetStatus() - normalized := blockatlas.Tx{ + normalized := types.Tx{ ID: srcTx.ID, Coin: coinIndex, From: srcTx.FromAddress(), To: srcTx.ToAddress(), - Fee: blockatlas.Amount(srcTx.GetFee()), + Fee: types.Amount(srcTx.GetFee()), Date: srcTx.BlockTime, Block: normalizeBlockHeight(srcTx.BlockHeight), Status: status, @@ -61,7 +61,7 @@ func normalizeTx(srcTx *Transaction, coinIndex uint) blockatlas.Tx { return normalized } -func normalizeTxWithAddress(srcTx *Transaction, address, token string, coinIndex uint) blockatlas.Tx { +func normalizeTxWithAddress(srcTx *Transaction, address, token string, coinIndex uint) types.Tx { normalized := normalizeTx(srcTx, coinIndex) normalized.Direction = GetDirection(address, normalized.From, normalized.To) fillMetaWithAddress(&normalized, srcTx, address, token, coinIndex) @@ -75,27 +75,27 @@ func normalizeBlockHeight(height int64) uint64 { return uint64(height) } -func fillMeta(final *blockatlas.Tx, tx *Transaction, coinIndex uint) { +func fillMeta(final *types.Tx, tx *Transaction, coinIndex uint) { if ok := fillTokenTransfer(final, tx, coinIndex); !ok { fillTransferOrContract(final, tx, coinIndex) } } -func fillMetaWithAddress(final *blockatlas.Tx, tx *Transaction, address, token string, coinIndex uint) { +func fillMetaWithAddress(final *types.Tx, tx *Transaction, address, token string, coinIndex uint) { if ok := fillTokenTransferWithAddress(final, tx, address, token, coinIndex); !ok { fillTransferOrContract(final, tx, coinIndex) } } -func fillTokenTransfer(final *blockatlas.Tx, tx *Transaction, coinIndex uint) bool { +func fillTokenTransfer(final *types.Tx, tx *Transaction, coinIndex uint) bool { if len(tx.TokenTransfers) == 1 { transfer := tx.TokenTransfers[0] - final.Meta = blockatlas.TokenTransfer{ + final.Meta = types.TokenTransfer{ Name: transfer.Name, Symbol: transfer.Symbol, TokenID: transfer.Token, Decimals: transfer.Decimals, - Value: blockatlas.Amount(transfer.Value), + Value: types.Amount(transfer.Value), From: transfer.From, To: transfer.To, } @@ -104,7 +104,7 @@ func fillTokenTransfer(final *blockatlas.Tx, tx *Transaction, coinIndex uint) bo return false } -func fillTokenTransferWithAddress(final *blockatlas.Tx, tx *Transaction, address, token string, coinIndex uint) bool { +func fillTokenTransferWithAddress(final *types.Tx, tx *Transaction, address, token string, coinIndex uint) bool { if len(tx.TokenTransfers) == 1 { transfer := tx.TokenTransfers[0] if transfer.To == address || transfer.From == address { @@ -115,17 +115,17 @@ func fillTokenTransferWithAddress(final *blockatlas.Tx, tx *Transaction, address } } direction := GetDirection(address, transfer.From, transfer.To) - metadata := blockatlas.TokenTransfer{ + metadata := types.TokenTransfer{ Name: transfer.Name, Symbol: transfer.Symbol, TokenID: transfer.Token, Decimals: transfer.Decimals, - Value: blockatlas.Amount(transfer.Value), + Value: types.Amount(transfer.Value), } - if direction == blockatlas.DirectionSelf { + if direction == types.DirectionSelf { metadata.From = address metadata.To = address - } else if direction == blockatlas.DirectionOutgoing { + } else if direction == types.DirectionOutgoing { metadata.From = address metadata.To = transfer.To } else { @@ -140,11 +140,11 @@ func fillTokenTransferWithAddress(final *blockatlas.Tx, tx *Transaction, address return false } -func fillTransferOrContract(final *blockatlas.Tx, tx *Transaction, coinIndex uint) { +func fillTransferOrContract(final *types.Tx, tx *Transaction, coinIndex uint) { gasUsed := tx.EthereumSpecific.GasUsed if gasUsed != nil && gasUsed.Int64() == 21000 { - final.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(tx.Value), + final.Meta = types.Transfer{ + Value: types.Amount(tx.Value), Symbol: coin.Coins[coinIndex].Symbol, Decimals: coin.Coins[coinIndex].Decimals, } @@ -153,19 +153,19 @@ func fillTransferOrContract(final *blockatlas.Tx, tx *Transaction, coinIndex uin data := tx.EthereumSpecific.Data if data == "" { // old node doesn't have data field - final.Meta = blockatlas.ContractCall{ + final.Meta = types.ContractCall{ Input: "0x", Value: tx.Value, } } else { if len(strings.TrimPrefix(data, "0x")) > 0 { - final.Meta = blockatlas.ContractCall{ + final.Meta = types.ContractCall{ Input: data, Value: tx.Value, } } else { - final.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(tx.Value), + final.Meta = types.Transfer{ + Value: types.Amount(tx.Value), Symbol: coin.Coins[coinIndex].Symbol, Decimals: coin.Coins[coinIndex].Decimals, } diff --git a/platform/bitcoin/blockbook/transaction_test.go b/platform/bitcoin/blockbook/transaction_test.go index dc5b324b9..877157f6e 100644 --- a/platform/bitcoin/blockbook/transaction_test.go +++ b/platform/bitcoin/blockbook/transaction_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) func TestNormalizePage(t *testing.T) { @@ -366,7 +366,7 @@ func TestNormalizePage(t *testing.T) { } for _, tt := range tests { var page TransactionsList - var txPage blockatlas.TxPage + var txPage types.TxPage err := json.Unmarshal([]byte(tt.args.srcPage), &page) assert.Nil(t, err) err = json.Unmarshal([]byte(tt.want), &txPage) diff --git a/platform/bitcoin/transaction.go b/platform/bitcoin/transaction.go index bde4c4464..a8dc8c2fc 100644 --- a/platform/bitcoin/transaction.go +++ b/platform/bitcoin/transaction.go @@ -6,36 +6,36 @@ import ( "github.com/trustwallet/blockatlas/platform/bitcoin/blockbook" mapset "github.com/deckarep/golang-set" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { txs, err := p.getTxsByAddress(address) if err != nil { return nil, err } - txPage := blockatlas.TxPage(txs) + txPage := types.TxPage(txs) sort.Sort(txPage) return txPage, nil } -func (p *Platform) GetTxsByXpub(xpub string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByXpub(xpub string) (types.TxPage, error) { txs, err := p.getTxsByXpub(xpub) if err != nil { return nil, err } - txPage := blockatlas.TxPage(txs) + txPage := types.TxPage(txs) sort.Sort(txPage) return txPage, nil } -func (p *Platform) getTxsByXpub(xpub string) ([]blockatlas.Tx, error) { +func (p *Platform) getTxsByXpub(xpub string) ([]types.Tx, error) { sourceTxs, err := p.client.GetTransactionsByXpub(xpub) if err != nil { - return []blockatlas.Tx{}, err + return []types.Tx{}, err } addressSet := mapset.NewSet() @@ -47,10 +47,10 @@ func (p *Platform) getTxsByXpub(xpub string) ([]blockatlas.Tx, error) { return txs, nil } -func (p *Platform) getTxsByAddress(address string) ([]blockatlas.Tx, error) { +func (p *Platform) getTxsByAddress(address string) ([]types.Tx, error) { sourceTxs, err := p.client.GetTxs(address) if err != nil { - return []blockatlas.Tx{}, err + return []types.Tx{}, err } addressSet := mapset.NewSet() addressSet.Add(address) @@ -58,8 +58,8 @@ func (p *Platform) getTxsByAddress(address string) ([]blockatlas.Tx, error) { return txs, nil } -func normalizeTxs(sourceTxs blockbook.TransactionsList, coinIndex uint, addressSet mapset.Set) []blockatlas.Tx { - var txs []blockatlas.Tx +func normalizeTxs(sourceTxs blockbook.TransactionsList, coinIndex uint, addressSet mapset.Set) []types.Tx { + var txs []types.Tx for _, transaction := range sourceTxs.TransactionList() { if tx, ok := normalizeTransfer(transaction, coinIndex, addressSet); ok { txs = append(txs, tx) @@ -68,13 +68,13 @@ func normalizeTxs(sourceTxs blockbook.TransactionsList, coinIndex uint, addressS return txs } -func normalizeTransfer(transaction blockbook.Transaction, coinIndex uint, addressSet mapset.Set) (tx blockatlas.Tx, ok bool) { +func normalizeTransfer(transaction blockbook.Transaction, coinIndex uint, addressSet mapset.Set) (tx types.Tx, ok bool) { tx = normalizeTransaction(transaction, coinIndex) - direction := blockatlas.InferDirection(&tx, addressSet) - value := blockatlas.InferValue(&tx, direction, addressSet) + direction := types.InferDirection(&tx, addressSet) + value := types.InferValue(&tx, direction, addressSet) tx.Direction = direction - tx.Meta = blockatlas.Transfer{ + tx.Meta = types.Transfer{ Value: value, Symbol: coin.Coins[coinIndex].Symbol, Decimals: coin.Coins[coinIndex].Decimals, @@ -83,7 +83,7 @@ func normalizeTransfer(transaction blockbook.Transaction, coinIndex uint, addres return tx, true } -func normalizeTransaction(tx blockbook.Transaction, coinIndex uint) blockatlas.Tx { +func normalizeTransaction(tx blockbook.Transaction, coinIndex uint) types.Tx { inputs := parseOutputs(tx.Vin) outputs := parseOutputs(tx.Vout) from := "" @@ -95,10 +95,10 @@ func normalizeTransaction(tx blockbook.Transaction, coinIndex uint) blockatlas.T if len(outputs) > 0 { to = outputs[0].Address } - amount := blockatlas.Amount(tx.Amount()) - fees := blockatlas.Amount(numbers.GetAmountValue(tx.Fees)) + amount := types.Amount(tx.Amount()) + fees := types.Amount(numbers.GetAmountValue(tx.Fees)) - return blockatlas.Tx{ + return types.Tx{ ID: tx.ID, Coin: coinIndex, From: from, @@ -107,11 +107,11 @@ func normalizeTransaction(tx blockbook.Transaction, coinIndex uint) blockatlas.T Outputs: outputs, Fee: fees, Date: tx.BlockTime, - Type: blockatlas.TxTransfer, + Type: types.TxTransfer, Block: tx.GetBlockHeight(), Status: tx.GetStatus(), Sequence: 0, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: amount, Symbol: coin.Coins[coinIndex].Symbol, Decimals: coin.Coins[coinIndex].Decimals, @@ -119,19 +119,19 @@ func normalizeTransaction(tx blockbook.Transaction, coinIndex uint) blockatlas.T } } -func parseOutputs(outputs []blockbook.Output) (addresses []blockatlas.TxOutput) { - set := make(map[string]*blockatlas.TxOutput) +func parseOutputs(outputs []blockbook.Output) (addresses []types.TxOutput) { + set := make(map[string]*types.TxOutput) var ordered []string for _, output := range outputs { for _, address := range output.OutputAddress() { if val, ok := set[address]; ok { value := numbers.AddAmount(string(val.Value), output.Value) - val.Value = blockatlas.Amount(value) + val.Value = types.Amount(value) } else { amount := numbers.GetAmountValue(output.Value) - set[address] = &blockatlas.TxOutput{ + set[address] = &types.TxOutput{ Address: address, - Value: blockatlas.Amount(amount), + Value: types.Amount(amount), } ordered = append(ordered, address) } diff --git a/platform/bitcoin/transaction_test.go b/platform/bitcoin/transaction_test.go index 84b32cfc2..70329e90b 100644 --- a/platform/bitcoin/transaction_test.go +++ b/platform/bitcoin/transaction_test.go @@ -9,28 +9,28 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( - outgoingTx, _ = mock.JsonFromFilePathToString("mocks/" + "outgoing_tx.json") - incomingTx, _ = mock.JsonFromFilePathToString("mocks/" + "incoming_tx.json") - pendingTx, _ = mock.JsonFromFilePathToString("mocks/" + "pending_tx.json") + outgoingTx, _ = mock.JsonStringFromFilePath("mocks/" + "outgoing_tx.json") + incomingTx, _ = mock.JsonStringFromFilePath("mocks/" + "incoming_tx.json") + pendingTx, _ = mock.JsonStringFromFilePath("mocks/" + "pending_tx.json") - expectedOutgoingTx = blockatlas.Tx{ + expectedOutgoingTx = types.Tx{ ID: "df63ddab7d4eed2fb6cb40d4d0519e7e5ac7cf5ad556b2edbd45963ea1a2931c", Coin: coin.BTC, From: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC", To: "3FjBW1KL9L8aYtdKzJ8FhCNxmXB7dXDRw4", - Inputs: []blockatlas.TxOutput{ + Inputs: []types.TxOutput{ { Address: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC", Value: "777200", }, }, - Outputs: []blockatlas.TxOutput{ + Outputs: []types.TxOutput{ { Address: "3FjBW1KL9L8aYtdKzJ8FhCNxmXB7dXDRw4", Value: "677012", @@ -39,29 +39,29 @@ var ( Fee: "100188", Date: 1562945790, Type: "transfer", - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Block: 585094, Sequence: 0, - Direction: blockatlas.DirectionSelf, - Meta: blockatlas.Transfer{ + Direction: types.DirectionSelf, + Meta: types.Transfer{ Value: "677012", Symbol: "BTC", Decimals: 8, }, } - expectedIncomingTx = blockatlas.Tx{ + expectedIncomingTx = types.Tx{ ID: "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", Coin: coin.ZEC, From: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", To: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", - Inputs: []blockatlas.TxOutput{ + Inputs: []types.TxOutput{ { Address: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", Value: "387582", }, }, - Outputs: []blockatlas.TxOutput{ + Outputs: []types.TxOutput{ { Address: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", Value: "200997", @@ -74,29 +74,29 @@ var ( Fee: "226", Date: 1549793065, Type: "transfer", - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Block: 479017, Sequence: 0, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.Transfer{ + Direction: types.DirectionIncoming, + Meta: types.Transfer{ Value: "200997", Symbol: "ZEC", Decimals: 8, }, } - expectedPendingTx = blockatlas.Tx{ + expectedPendingTx = types.Tx{ ID: "a2d70bee124510c476f159fa83cdb34d663fc6020c81aad19b238601d679fed7", Coin: coin.ZEC, From: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", To: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", - Inputs: []blockatlas.TxOutput{ + Inputs: []types.TxOutput{ { Address: "t1T7cLkvDVScjw95WguoAZbbT8mrdqVtpiD", Value: "387582", }, }, - Outputs: []blockatlas.TxOutput{ + Outputs: []types.TxOutput{ { Address: "t1U4xs3qMxc2TL8wwYufmBngA5mewLHRwhM", Value: "200997", @@ -109,11 +109,11 @@ var ( Fee: "226", Date: 1549793065, Type: "transfer", - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Block: 0, Sequence: 0, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.Transfer{ + Direction: types.DirectionIncoming, + Meta: types.Transfer{ Value: "200997", Symbol: "ZEC", Decimals: 8, @@ -134,7 +134,7 @@ func TestNormalizeTransfer(t *testing.T) { tests := []struct { RawTx string - Expected blockatlas.Tx + Expected types.Tx AddressSet mapset.Set }{ {outgoingTx, expectedOutgoingTx, outgoingTxSet}, @@ -150,7 +150,7 @@ func TestNormalizeTransfer(t *testing.T) { t.Fatal(rErr) } - var readyTx blockatlas.Tx + var readyTx types.Tx normTx, ok := normalizeTransfer(transaction, test.Expected.Coin, test.AddressSet) if !ok { t.Fatal("Bitcoin: Can't normalize transaction", readyTx) @@ -174,10 +174,10 @@ func TestNormalizeTransfer(t *testing.T) { func TestTransactionStatus(t *testing.T) { tests := []struct { Tx blockbook.Transaction - Expected blockatlas.Status + Expected types.Status }{ - {blockbook.Transaction{Confirmations: 0}, blockatlas.StatusPending}, - {blockbook.Transaction{Confirmations: 1}, blockatlas.StatusCompleted}, + {blockbook.Transaction{Confirmations: 0}, types.StatusPending}, + {blockbook.Transaction{Confirmations: 1}, types.StatusCompleted}, } for _, test := range tests { @@ -189,7 +189,7 @@ func TestParseOutputs(t *testing.T) { tests := []struct { name string outputs string - want []blockatlas.TxOutput + want []types.TxOutput }{ { name: "Test Doge inputs from 0xb02977b96e5c65fd807e28230375c1267ded1de7c2c43292bf36552283bc5696", @@ -226,7 +226,7 @@ func TestParseOutputs(t *testing.T) { "value": "500000000", "hex": "473044022047cad0afd2aa4ff9b3fc45a6afb40b9745c1b39499a96df803f899d189f3822c0220267464d2954de54825717b93e3597a0915c71aecf1215ed33021bef376813b9a012103565519e77659aae844889ae12609309f85a8d22bf815c4daa418e457c7cb01eb" }]`, - want: []blockatlas.TxOutput{ + want: []types.TxOutput{ { Address: "DPoYGk1wGQ3uWs5G3exd9WKvVyu8weKYVA", Value: "1010000000", @@ -254,7 +254,7 @@ func TestParseOutputs(t *testing.T) { ], "isAddress": true }]`, - want: []blockatlas.TxOutput{ + want: []types.TxOutput{ { Address: "DRryKEukopEDv7cm6Y1Li6232VHEjnXptA", Value: "1000000000", diff --git a/platform/cosmos/block.go b/platform/cosmos/block.go index 509f372fd..3d053733a 100644 --- a/platform/cosmos/block.go +++ b/platform/cosmos/block.go @@ -1,17 +1,15 @@ package cosmos -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { srcTxs, err := p.client.GetBlockByNumber(num) if err != nil { return nil, err } txs := p.NormalizeTxs(srcTxs.Txs) - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil diff --git a/platform/cosmos/stake_test.go b/platform/cosmos/stake_test.go index e856593f6..b169cdb82 100644 --- a/platform/cosmos/stake_test.go +++ b/platform/cosmos/stake_test.go @@ -11,9 +11,9 @@ import ( ) var ( - validatorSrc, _ = mock.JsonFromFilePathToString("mocks/" + "validator.json") - delegationsSrc, _ = mock.JsonFromFilePathToString("mocks/" + "delegation.json") - unbondingDelegationsSrc, _ = mock.JsonFromFilePathToString("mocks/" + "unbonding.json") + validatorSrc, _ = mock.JsonStringFromFilePath("mocks/" + "validator.json") + delegationsSrc, _ = mock.JsonStringFromFilePath("mocks/" + "delegation.json") + unbondingDelegationsSrc, _ = mock.JsonStringFromFilePath("mocks/" + "unbonding.json") stakingPool = Pool{"1222", "200"} cosmosValidator = Validator{Commission: CosmosCommission{CosmosCommissionRates{Rate: "0.4"}}} inflation = 0.7 diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 70a9c8e15..5a5343936 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -5,11 +5,11 @@ import ( "sync" "time" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { tagsList := []string{"transfer.recipient", "message.sender"} var wg sync.WaitGroup out := make(chan []Tx, len(tagsList)) @@ -51,9 +51,9 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { } // NormalizeTxs converts multiple Cosmos transactions -func (p *Platform) NormalizeTxs(srcTxs []Tx) blockatlas.TxPage { +func (p *Platform) NormalizeTxs(srcTxs []Tx) types.TxPage { txMap := make(map[string]bool) - txs := make(blockatlas.TxPage, 0) + txs := make(types.TxPage, 0) for _, srcTx := range srcTxs { _, ok := txMap[srcTx.ID] if ok { @@ -69,14 +69,14 @@ func (p *Platform) NormalizeTxs(srcTxs []Tx) blockatlas.TxPage { } // Normalize converts an Cosmos transaction into the generic model -func (p *Platform) Normalize(srcTx *Tx) (tx blockatlas.Tx, ok bool) { +func (p *Platform) Normalize(srcTx *Tx) (tx types.Tx, ok bool) { date, err := time.Parse("2006-01-02T15:04:05Z", srcTx.Date) if err != nil { - return blockatlas.Tx{}, false + return types.Tx{}, false } block, err := strconv.ParseUint(srcTx.Block, 10, 64) if err != nil { - return blockatlas.Tx{}, false + return types.Tx{}, false } // Sometimes fees can be null objects (in the case of no fees e.g. F044F91441C460EDCD90E0063A65356676B7B20684D94C731CF4FAB204035B41) fee := "0" @@ -85,23 +85,23 @@ func (p *Platform) Normalize(srcTx *Tx) (tx blockatlas.Tx, ok bool) { if len(qty) > 0 && qty != fee { fee, err = numbers.DecimalToSatoshis(srcTx.Data.Contents.Fee.FeeAmount[0].Quantity) if err != nil { - return blockatlas.Tx{}, false + return types.Tx{}, false } } } - status := blockatlas.StatusCompleted + status := types.StatusCompleted // https://github.com/cosmos/cosmos-sdk/blob/95ddc242ad024ca78a359a13122dade6f14fd676/types/errors/errors.go#L19 if srcTx.Code > 0 { - status = blockatlas.StatusError + status = types.StatusError } - tx = blockatlas.Tx{ + tx = types.Tx{ ID: srcTx.ID, Coin: p.Coin().ID, Date: date.Unix(), Status: status, - Fee: blockatlas.Amount(fee), + Fee: types.Amount(fee), Block: block, Memo: srcTx.Data.Contents.Memo, } @@ -124,7 +124,7 @@ func (p *Platform) Normalize(srcTx *Tx) (tx blockatlas.Tx, ok bool) { return tx, false } -func (p *Platform) fillTransfer(tx *blockatlas.Tx, transfer MessageValueTransfer) { +func (p *Platform) fillTransfer(tx *types.Tx, transfer MessageValueTransfer) { if len(transfer.Amount) == 0 { return } @@ -134,15 +134,15 @@ func (p *Platform) fillTransfer(tx *blockatlas.Tx, transfer MessageValueTransfer } tx.From = transfer.FromAddr tx.To = transfer.ToAddr - tx.Type = blockatlas.TxTransfer - tx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(value), + tx.Type = types.TxTransfer + tx.Meta = types.Transfer{ + Value: types.Amount(value), Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, } } -func (p *Platform) fillDelegate(tx *blockatlas.Tx, delegate MessageValueDelegate, events Events, msgType TxType) { +func (p *Platform) fillDelegate(tx *types.Tx, delegate MessageValueDelegate, events Events, msgType TxType) { value := "" if len(delegate.Amount.Quantity) > 0 { var err error @@ -153,30 +153,30 @@ func (p *Platform) fillDelegate(tx *blockatlas.Tx, delegate MessageValueDelegate } tx.From = delegate.DelegatorAddr tx.To = delegate.ValidatorAddr - tx.Type = blockatlas.TxAnyAction + tx.Type = types.TxAnyAction - key := blockatlas.KeyStakeDelegate - title := blockatlas.KeyTitle("") + key := types.KeyStakeDelegate + title := types.KeyTitle("") switch msgType { case MsgDelegate: - tx.Direction = blockatlas.DirectionOutgoing - title = blockatlas.AnyActionDelegation + tx.Direction = types.DirectionOutgoing + title = types.AnyActionDelegation case MsgUndelegate: - tx.Direction = blockatlas.DirectionIncoming - title = blockatlas.AnyActionUndelegation + tx.Direction = types.DirectionIncoming + title = types.AnyActionUndelegation case MsgWithdrawDelegationReward: - tx.Direction = blockatlas.DirectionIncoming - title = blockatlas.AnyActionClaimRewards - key = blockatlas.KeyStakeClaimRewards + tx.Direction = types.DirectionIncoming + title = types.AnyActionClaimRewards + key = types.KeyStakeClaimRewards value = events.GetWithdrawRewardValue() } - tx.Meta = blockatlas.AnyAction{ + tx.Meta = types.AnyAction{ Coin: p.Coin().ID, Title: title, Key: key, Name: p.Coin().Name, Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, - Value: blockatlas.Amount(value), + Value: types.Amount(value), } } diff --git a/platform/cosmos/transaction_test.go b/platform/cosmos/transaction_test.go index d62f5a567..d0355aac7 100644 --- a/platform/cosmos/transaction_test.go +++ b/platform/cosmos/transaction_test.go @@ -5,22 +5,22 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( - transferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer.json") - transferSrcKava, _ = mock.JsonFromFilePathToString("mocks/" + "transfer_kava.json") - failedTransferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer_failed.json") - delegateSrc, _ = mock.JsonFromFilePathToString("mocks/" + "delegate_tx.json") - unDelegateSrc, _ = mock.JsonFromFilePathToString("mocks/" + "undelegate_tx.json") - claimRewardSrc1, _ = mock.JsonFromFilePathToString("mocks/" + "claim_1.json") - claimRewardSrc2, _ = mock.JsonFromFilePathToString("mocks/" + "claim_2.json") - - transferDst = blockatlas.Tx{ + transferSrc, _ = mock.JsonStringFromFilePath("mocks/" + "transfer.json") + transferSrcKava, _ = mock.JsonStringFromFilePath("mocks/" + "transfer_kava.json") + failedTransferSrc, _ = mock.JsonStringFromFilePath("mocks/" + "transfer_failed.json") + delegateSrc, _ = mock.JsonStringFromFilePath("mocks/" + "delegate_tx.json") + unDelegateSrc, _ = mock.JsonStringFromFilePath("mocks/" + "undelegate_tx.json") + claimRewardSrc1, _ = mock.JsonStringFromFilePath("mocks/" + "claim_1.json") + claimRewardSrc2, _ = mock.JsonStringFromFilePath("mocks/" + "claim_2.json") + + transferDst = types.Tx{ ID: "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", Coin: coin.ATOM, From: "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl", @@ -28,16 +28,16 @@ var ( Fee: "1", Date: 1556992677, Block: 151980, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Type: types.TxTransfer, + Meta: types.Transfer{ Value: "2271999999", Symbol: coin.Cosmos().Symbol, Decimals: 6, }, } - transferDstKava = blockatlas.Tx{ + transferDstKava = types.Tx{ ID: "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", Coin: coin.KAVA, From: "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn", @@ -45,16 +45,16 @@ var ( Fee: "1", Date: 1556992677, Block: 151980, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Type: types.TxTransfer, + Meta: types.Transfer{ Value: "2271999999", Symbol: coin.Kava().Symbol, Decimals: 6, }, } - delegateDst = blockatlas.Tx{ + delegateDst = types.Tx{ ID: "11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7", Coin: coin.ATOM, From: "cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3", @@ -62,13 +62,13 @@ var ( Fee: "5000", Date: 1564632616, Block: 1258202, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionOutgoing, - Meta: blockatlas.AnyAction{ + Status: types.StatusCompleted, + Type: types.TxAnyAction, + Direction: types.DirectionOutgoing, + Meta: types.AnyAction{ Coin: coin.ATOM, - Title: blockatlas.AnyActionDelegation, - Key: blockatlas.KeyStakeDelegate, + Title: types.AnyActionDelegation, + Key: types.KeyStakeDelegate, Name: coin.Cosmos().Name, Symbol: coin.Coins[coin.ATOM].Symbol, Decimals: coin.Coins[coin.ATOM].Decimals, @@ -76,7 +76,7 @@ var ( }, } - unDelegateDst = blockatlas.Tx{ + unDelegateDst = types.Tx{ ID: "A1EC36741FEF681F4A77B8F6032AD081100EE5ECB4CC76AEAC2174BC6B871CFE", Coin: coin.ATOM, From: "cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94", @@ -84,13 +84,13 @@ var ( Fee: "5000", Date: 1564624521, Block: 1257037, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.AnyAction{ + Status: types.StatusCompleted, + Type: types.TxAnyAction, + Direction: types.DirectionIncoming, + Meta: types.AnyAction{ Coin: coin.ATOM, - Title: blockatlas.AnyActionUndelegation, - Key: blockatlas.KeyStakeDelegate, + Title: types.AnyActionUndelegation, + Key: types.KeyStakeDelegate, Name: coin.Cosmos().Name, Symbol: coin.Coins[coin.ATOM].Symbol, Decimals: coin.Coins[coin.ATOM].Decimals, @@ -98,7 +98,7 @@ var ( }, } - claimRewardDst2 = blockatlas.Tx{ + claimRewardDst2 = types.Tx{ ID: "082BA88EC055A7C343A353297EAC104CE87C659E0DDD84621C9AC3C284232800", Coin: coin.ATOM, From: "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", @@ -106,14 +106,14 @@ var ( Fee: "0", Date: 1576462863, Block: 54561, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionIncoming, + Status: types.StatusCompleted, + Type: types.TxAnyAction, + Direction: types.DirectionIncoming, Memo: "复投", - Meta: blockatlas.AnyAction{ + Meta: types.AnyAction{ Coin: coin.ATOM, - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, + Title: types.AnyActionClaimRewards, + Key: types.KeyStakeClaimRewards, Name: coin.Cosmos().Name, Symbol: coin.Coins[coin.ATOM].Symbol, Decimals: coin.Coins[coin.ATOM].Decimals, @@ -121,7 +121,7 @@ var ( }, } - claimRewardDst1 = blockatlas.Tx{ + claimRewardDst1 = types.Tx{ ID: "C382DCFDC30E2DA294421DAEAD5862F118592A7B000EE91F6BEF8452A1F525D7", Coin: coin.ATOM, From: "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", @@ -129,14 +129,14 @@ var ( Fee: "1000", Date: 1576638273, Block: 79678, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionIncoming, + Status: types.StatusCompleted, + Type: types.TxAnyAction, + Direction: types.DirectionIncoming, Memo: "", - Meta: blockatlas.AnyAction{ + Meta: types.AnyAction{ Coin: coin.ATOM, - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, + Title: types.AnyActionClaimRewards, + Key: types.KeyStakeClaimRewards, Name: coin.Cosmos().Name, Symbol: coin.Coins[coin.ATOM].Symbol, Decimals: coin.Coins[coin.ATOM].Decimals, @@ -144,7 +144,7 @@ var ( }, } - failedTransferDst = blockatlas.Tx{ + failedTransferDst = types.Tx{ ID: "5E78C65A8C1A6C8239EBBBBF2E42020E6ADBA8037EDEA83BF88E1A9159CF13B8", Coin: coin.ATOM, From: "cosmos1shpfyt7psrff2ux7nznxvj6f7gq59fcqng5mku", @@ -152,10 +152,10 @@ var ( Fee: "2000", Date: 1576120902, Block: 5552, - Status: blockatlas.StatusError, - Type: blockatlas.TxTransfer, + Status: types.StatusError, + Type: types.TxTransfer, Memo: "UniCoins registration rewards", - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "100000", Symbol: coin.Cosmos().Symbol, Decimals: 6, @@ -167,7 +167,7 @@ type test struct { name string platform Platform Data string - want blockatlas.Tx + want types.Tx } func TestNormalize(t *testing.T) { diff --git a/platform/elrond/block.go b/platform/elrond/block.go index 65ed53ff3..10a0a99da 100644 --- a/platform/elrond/block.go +++ b/platform/elrond/block.go @@ -1,11 +1,11 @@ package elrond -import "github.com/trustwallet/blockatlas/pkg/blockatlas" +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.CurrentBlockNumber() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { return p.client.GetBlockByNumber(num) } diff --git a/platform/elrond/client.go b/platform/elrond/client.go index 3d1911bd3..c862da9eb 100644 --- a/platform/elrond/client.go +++ b/platform/elrond/client.go @@ -5,8 +5,8 @@ import ( "fmt" "net/url" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/types" ) type Client struct { @@ -26,7 +26,7 @@ func (c *Client) CurrentBlockNumber() (num int64, err error) { return int64(latestNonce), nil } -func (c *Client) GetBlockByNumber(height int64) (*blockatlas.Block, error) { +func (c *Client) GetBlockByNumber(height int64) (*types.Block, error) { var blockRes BlockResponse path := fmt.Sprintf("hyperblock/by-nonce/%d", uint64(height)) @@ -38,13 +38,13 @@ func (c *Client) GetBlockByNumber(height int64) (*blockatlas.Block, error) { block := blockRes.Block txs := NormalizeTxs(block.Transactions, "", blockRes.Block) - return &blockatlas.Block{ + return &types.Block{ Number: int64(block.Nonce), Txs: txs, }, nil } -func (c *Client) GetTxsOfAddress(address string) (blockatlas.TxPage, error) { +func (c *Client) GetTxsOfAddress(address string) (types.TxPage, error) { var txPage TransactionsPage // TODO: enable pagination of Elrond transactions in the future. // TODO: currently Elrond only fetches the most recent 20 transactions. diff --git a/platform/elrond/model.go b/platform/elrond/model.go index 3e75cd78e..422cd49ab 100644 --- a/platform/elrond/model.go +++ b/platform/elrond/model.go @@ -5,7 +5,7 @@ import ( "math/big" "time" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) const roundDurationInSeconds = 6 @@ -56,9 +56,9 @@ type Transaction struct { GasLimit uint64 `json:"gasLimit,omitempty"` } -func (tx *Transaction) TxFee() blockatlas.Amount { +func (tx *Transaction) TxFee() types.Amount { if tx.Fee != "0" && tx.Fee != "" { - return blockatlas.Amount(tx.Fee) + return types.Amount(tx.Fee) } // Hyperblocks API V1 does not provide the transaction fees (nor "gasUsed"). Hyperblocks API V2 will provide this information, as well. @@ -68,28 +68,28 @@ func (tx *Transaction) TxFee() blockatlas.Amount { txFee := big.NewInt(0).SetUint64(tx.GasPrice) txFee = txFee.Mul(txFee, big.NewInt(0).SetUint64(tx.GasLimit)) - return blockatlas.Amount(txFee.String()) + return types.Amount(txFee.String()) } -func (tx *Transaction) TxStatus() blockatlas.Status { +func (tx *Transaction) TxStatus() types.Status { switch tx.Status { case "Success", "success": - return blockatlas.StatusCompleted + return types.StatusCompleted case "Pending", "pending": - return blockatlas.StatusPending + return types.StatusPending default: - return blockatlas.StatusError + return types.StatusError } } -func (tx *Transaction) Direction(address string) blockatlas.Direction { +func (tx *Transaction) Direction(address string) types.Direction { switch { case tx.Sender == address && tx.Receiver == address: - return blockatlas.DirectionSelf + return types.DirectionSelf case tx.Sender == address && tx.Receiver != address: - return blockatlas.DirectionOutgoing + return types.DirectionOutgoing default: - return blockatlas.DirectionIncoming + return types.DirectionIncoming } } diff --git a/platform/elrond/transaction.go b/platform/elrond/transaction.go index 2ac4219ce..cf130b833 100644 --- a/platform/elrond/transaction.go +++ b/platform/elrond/transaction.go @@ -1,18 +1,18 @@ package elrond import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) const metachainID = "4294967295" -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return p.client.GetTxsOfAddress(address) } // NormalizeTx converts an slice of Elrond transaction info a slice of generic model transaction -func NormalizeTxs(srcTxs []Transaction, address string, block Block) (txs []blockatlas.Tx) { +func NormalizeTxs(srcTxs []Transaction, address string, block Block) (txs []types.Tx) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(srcTx, address, block) if !ok { @@ -24,8 +24,8 @@ func NormalizeTxs(srcTxs []Transaction, address string, block Block) (txs []bloc } // NormalizeTx converts an Elrond transaction into the generic model -func NormalizeTx(srcTx Transaction, address string, block Block) (tx blockatlas.Tx, ok bool) { - tx = blockatlas.Tx{ +func NormalizeTx(srcTx Transaction, address string, block Block) (tx types.Tx, ok bool) { + tx = types.Tx{ ID: srcTx.Hash, Coin: coin.Elrond().ID, Date: int64(srcTx.TxTimestamp(block.Round)), @@ -36,8 +36,8 @@ func NormalizeTx(srcTx Transaction, address string, block Block) (tx blockatlas. Status: srcTx.TxStatus(), Sequence: srcTx.Nonce, Memo: srcTx.Data, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(srcTx.Value), + Meta: types.Transfer{ + Value: types.Amount(srcTx.Value), Symbol: coin.Elrond().Symbol, Decimals: coin.Elrond().Decimals, }, diff --git a/platform/elrond/transaction_test.go b/platform/elrond/transaction_test.go index 29fcf4d45..afd23afb0 100644 --- a/platform/elrond/transaction_test.go +++ b/platform/elrond/transaction_test.go @@ -5,134 +5,134 @@ import ( "testing" "github.com/stretchr/testify/require" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( userAddress = `erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0` - txTransferSrc1, _ = mock.JsonFromFilePathToString("mocks/tx.json") - txTransferSrc2, _ = mock.JsonFromFilePathToString("mocks/tx_2.json") - txTransferSrc3, _ = mock.JsonFromFilePathToString("mocks/tx_3.json") - txTransferSrc4, _ = mock.JsonFromFilePathToString("mocks/tx_4.json") - txTransferSrc5, _ = mock.JsonFromFilePathToString("mocks/tx_5.json") - txTransferSrc6, _ = mock.JsonFromFilePathToString("mocks/tx_6.json") - - txTransfer1Normalized = blockatlas.Tx{ + txTransferSrc1, _ = mock.JsonStringFromFilePath("mocks/tx.json") + txTransferSrc2, _ = mock.JsonStringFromFilePath("mocks/tx_2.json") + txTransferSrc3, _ = mock.JsonStringFromFilePath("mocks/tx_3.json") + txTransferSrc4, _ = mock.JsonStringFromFilePath("mocks/tx_4.json") + txTransferSrc5, _ = mock.JsonStringFromFilePath("mocks/tx_5.json") + txTransferSrc6, _ = mock.JsonStringFromFilePath("mocks/tx_6.json") + + txTransfer1Normalized = types.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", Coin: coin.EGLD, Date: int64(1587715632), From: "metachain", To: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", Fee: "1000", - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Memo: "ok", Sequence: 0, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "82516976060558456822", Symbol: coin.Elrond().Symbol, Decimals: coin.Elrond().Decimals, }, - Direction: blockatlas.DirectionOutgoing, + Direction: types.DirectionOutgoing, } - txTransfer2Normalized = blockatlas.Tx{ + txTransfer2Normalized = types.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", Coin: coin.EGLD, Date: int64(1588757256), From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", To: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", Fee: "1500", - Status: blockatlas.StatusPending, + Status: types.StatusPending, Memo: "money", Sequence: 1, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "2000", Symbol: coin.Elrond().Symbol, Decimals: coin.Elrond().Decimals, }, - Direction: blockatlas.DirectionSelf, + Direction: types.DirectionSelf, } - txTransfer3Normalized = blockatlas.Tx{ + txTransfer3Normalized = types.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", Coin: coin.EGLD, Date: int64(1588757256), From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", Fee: "5000", - Status: blockatlas.StatusError, + Status: types.StatusError, Memo: "test", Sequence: 19, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "2", Symbol: coin.Elrond().Symbol, Decimals: coin.Elrond().Decimals, }, - Direction: blockatlas.DirectionOutgoing, + Direction: types.DirectionOutgoing, } - txTransfer4Normalized = blockatlas.Tx{ + txTransfer4Normalized = types.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", Coin: coin.EGLD, Date: int64(1588757256), From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", Fee: "5000", - Status: blockatlas.StatusPending, + Status: types.StatusPending, Memo: "test", Sequence: 19, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "2", Symbol: coin.Elrond().Symbol, Decimals: coin.Elrond().Decimals, }, - Direction: blockatlas.DirectionOutgoing, + Direction: types.DirectionOutgoing, } - txTransfer5Normalized = blockatlas.Tx{ + txTransfer5Normalized = types.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", Coin: coin.EGLD, Date: int64(1588757256), From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", Fee: "5000", - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Memo: "test", Sequence: 19, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "2", Symbol: coin.Elrond().Symbol, Decimals: coin.Elrond().Decimals, }, - Direction: blockatlas.DirectionOutgoing, + Direction: types.DirectionOutgoing, } - txTransfer6Normalized = blockatlas.Tx{ + txTransfer6Normalized = types.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", Coin: coin.EGLD, From: "erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0", To: "erd1v0ce6rapup6rwma5sltyv05xhp33u543nex75a7j39vsz9m6squq6mxm7y", Fee: "5000", - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Memo: "test", Sequence: 25, Block: 620, Date: 1596121554, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "2", Symbol: coin.Elrond().Symbol, Decimals: coin.Elrond().Decimals, }, - Direction: blockatlas.DirectionOutgoing, + Direction: types.DirectionOutgoing, } ) type test struct { name string apiResponse string - expected *blockatlas.Tx + expected *types.Tx } func TestNormalize(t *testing.T) { @@ -211,5 +211,5 @@ func TestNormalizeTxsFromHyperblock(t *testing.T) { }) require.Equal(t, len(txs), len(normalizedTxs)) - require.Equal(t, []blockatlas.Tx{txTransfer6Normalized}, normalizedTxs) + require.Equal(t, []types.Tx{txTransfer6Normalized}, normalizedTxs) } diff --git a/platform/ethereum/client.go b/platform/ethereum/client.go index c095eb793..622927192 100644 --- a/platform/ethereum/client.go +++ b/platform/ethereum/client.go @@ -1,18 +1,16 @@ package ethereum -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" type EthereumClient interface { - GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) - GetTokenTxs(address, token string, coinIndex uint) (blockatlas.TxPage, error) - GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) + GetTransactions(address string, coinIndex uint) (types.TxPage, error) + GetTokenTxs(address, token string, coinIndex uint) (types.TxPage, error) + GetTokenList(address string, coinIndex uint) (types.TokenPage, error) GetCurrentBlockNumber() (int64, error) - GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, error) + GetBlockByNumber(num int64, coinIndex uint) (*types.Block, error) } -func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { +func (p *Platform) GetTokenListByAddress(address string) (types.TokenPage, error) { return p.client.GetTokenList(address, p.CoinIndex) } @@ -20,6 +18,6 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.GetCurrentBlockNumber() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { return p.client.GetBlockByNumber(num, p.CoinIndex) } diff --git a/platform/ethereum/collection.go b/platform/ethereum/collection.go index 2ef0bd1d6..07d33dd33 100644 --- a/platform/ethereum/collection.go +++ b/platform/ethereum/collection.go @@ -3,15 +3,15 @@ package ethereum import ( "strings" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/ethereum/collection" + "github.com/trustwallet/golibs/types" ) var ( supportedTypes = map[string]bool{"ERC721": true, "ERC1155": true} ) -func (p *Platform) GetCollections(owner string) (blockatlas.CollectionPage, error) { +func (p *Platform) GetCollections(owner string) (types.CollectionPage, error) { collections, err := p.collectible.GetCollections(owner) if err != nil { return nil, err @@ -19,7 +19,7 @@ func (p *Platform) GetCollections(owner string) (blockatlas.CollectionPage, erro return NormalizeCollections(collections, p.CoinIndex, owner), nil } -func (p *Platform) GetCollectibles(owner, collectibleID string) (blockatlas.CollectiblePage, error) { +func (p *Platform) GetCollectibles(owner, collectibleID string) (types.CollectiblePage, error) { items, err := p.collectible.GetCollectibles(owner, collectibleID) if err != nil { return nil, err @@ -27,7 +27,7 @@ func (p *Platform) GetCollectibles(owner, collectibleID string) (blockatlas.Coll return NormalizeCollectiblePage(items, p.CoinIndex), nil } -func NormalizeCollections(collections []collection.Collection, coinIndex uint, owner string) (page blockatlas.CollectionPage) { +func NormalizeCollections(collections []collection.Collection, coinIndex uint, owner string) (page types.CollectionPage) { for _, collection := range collections { item := NormalizeCollection(collection, coinIndex, owner) page = append(page, item) @@ -35,8 +35,8 @@ func NormalizeCollections(collections []collection.Collection, coinIndex uint, o return page } -func NormalizeCollection(c collection.Collection, coinIndex uint, owner string) blockatlas.Collection { - return blockatlas.Collection{ +func NormalizeCollection(c collection.Collection, coinIndex uint, owner string) types.Collection { + return types.Collection{ Name: c.Name, ImageUrl: c.ImageUrl, Description: c.Description, @@ -48,7 +48,7 @@ func NormalizeCollection(c collection.Collection, coinIndex uint, owner string) } } -func NormalizeCollectiblePage(collectibles []collection.Collectible, coinIndex uint) (page blockatlas.CollectiblePage) { +func NormalizeCollectiblePage(collectibles []collection.Collectible, coinIndex uint) (page types.CollectiblePage) { for _, collectible := range collectibles { item := NormalizeCollectible(collectible, coinIndex) if _, ok := supportedTypes[item.Type]; ok { @@ -58,9 +58,9 @@ func NormalizeCollectiblePage(collectibles []collection.Collectible, coinIndex u return page } -func NormalizeCollectible(c collection.Collectible, coinIndex uint) blockatlas.Collectible { +func NormalizeCollectible(c collection.Collectible, coinIndex uint) types.Collectible { id := strings.Join([]string{c.AssetContract.Address, c.TokenId}, "-") - return blockatlas.Collectible{ + return types.Collectible{ ID: id, CollectionID: c.Collection.Slug, TokenID: c.TokenId, diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/collection_test.go index eb3dc7ca8..cb1c01254 100644 --- a/platform/ethereum/collection_test.go +++ b/platform/ethereum/collection_test.go @@ -5,18 +5,18 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/ethereum/collection" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( collectionsOwnerV4 = "0x0875BCab22dE3d02402bc38aEe4104e1239374a7" - collectionsSrcV4, _ = mock.JsonFromFilePathToString("mocks/opensea_collections.json") - collectibleSrcV4, _ = mock.JsonFromFilePathToString("mocks/opensea_collectible.json") + collectionsSrcV4, _ = mock.JsonStringFromFilePath("mocks/opensea_collections.json") + collectibleSrcV4, _ = mock.JsonStringFromFilePath("mocks/opensea_collectible.json") - collection1DstV4 = blockatlas.Collection{ + collection1DstV4 = types.Collection{ Name: "CryptoKitties", ImageUrl: "https://storage.opensea.io/0x06012c8cf97bead5deae237070f9587f8e7a266d-featured-1556588705.png", Description: "CryptoKitties is a game centered around breedable, collectible, and oh-so-adorable creatures we call CryptoKitties! Each cat is one-of-a-kind and 100% owned by you; it cannot be replicated, taken away, or destroyed.", @@ -27,7 +27,7 @@ var ( Coin: 60, } - collection2DstV4 = blockatlas.Collection{ + collection2DstV4 = types.Collection{ Name: "Age of Rust", ImageUrl: "https://storage.opensea.io/age-of-rust-1561960816.jpg", Description: "Year 4424: The search begins for new life on the other side of the galaxy. Explore abandoned space stations, mysterious caverns, and ruins on far away worlds in order to unlock puzzles and secrets! Beware the rogue machines!", @@ -38,7 +38,7 @@ var ( Coin: 60, } - collection3DstV4 = blockatlas.Collection{ + collection3DstV4 = types.Collection{ Name: "Gods Unchained", ImageUrl: "https://lh3.googleusercontent.com/yArciVdcDv3O2R-O8XCxx3YEYZdzpiCMdossjUgv0kpLIluUQ1bYN_dyEk5xcvBEOgeq0zNIoWOh7TL9DvUEv--OLQ=s60", Description: "Gods Unchained is a free-to-play, turn-based competitive trading card game in which cards can be bought and sold on the OpenSea marketplace. Players use their collection to build decks of cards, and select a God to play with at the start of each match. The goal of the game is to reduce your opponent's life to zero. Each deck contains exactly 30 cards. On OpenSea, cards can be sold for a fixed price, auctioned, or sold in bundles.", @@ -49,7 +49,7 @@ var ( Coin: 60, } - collectibleDstV4 = blockatlas.Collectible{ + collectibleDstV4 = types.Collectible{ ID: "0xfaafdc07907ff5120a76b34b731b278c38d6043c-54277541829991970107421667568590323026590803461896874578610080514640537714688", CollectionID: "age-of-rust", TokenID: "54277541829991970107421667568590323026590803461896874578610080514640537714688", @@ -71,7 +71,7 @@ func TestNormalizeCollectionV4(t *testing.T) { assert.Nil(t, err) page := NormalizeCollections(collections, coin.ETH, collectionsOwnerV4) assert.Equal(t, 3, len(page), "collections could not be normalized") - expected := blockatlas.CollectionPage{collection1DstV4, collection2DstV4, collection3DstV4} + expected := types.CollectionPage{collection1DstV4, collection2DstV4, collection3DstV4} assert.Equal(t, page, expected, "collections don't equal") } @@ -81,6 +81,6 @@ func TestNormalizeCollectibleV4(t *testing.T) { assert.Nil(t, err) page := NormalizeCollectiblePage(collectibles, coin.ETH) assert.Equal(t, len(page), 1, "collectible could not be normalized") - expected := blockatlas.CollectiblePage{collectibleDstV4} + expected := types.CollectiblePage{collectibleDstV4} assert.Equal(t, page, expected, "collectible don't equal") } diff --git a/platform/ethereum/transaction.go b/platform/ethereum/transaction.go index 997a60181..e0568bcbd 100644 --- a/platform/ethereum/transaction.go +++ b/platform/ethereum/transaction.go @@ -1,13 +1,11 @@ package ethereum -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return p.client.GetTransactions(address, p.CoinIndex) } -func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address string, token string) (types.TxPage, error) { return p.client.GetTokenTxs(address, token, p.CoinIndex) } diff --git a/platform/ethereum/transaction_test.go b/platform/ethereum/transaction_test.go index 7f165e8bd..ceb0ba2a3 100644 --- a/platform/ethereum/transaction_test.go +++ b/platform/ethereum/transaction_test.go @@ -4,19 +4,19 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) type Client string var ( - tx = blockatlas.Tx{ + tx = types.Tx{ ID: "1", Coin: 60, From: "A", To: "B", } - page = blockatlas.TxPage([]blockatlas.Tx{tx}) + page = types.TxPage([]types.Tx{tx}) c Client ) @@ -43,26 +43,26 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { assert.Equal(t, page, resp) } -func (c Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) { - txs := make([]blockatlas.Tx, 0) +func (c Client) GetTransactions(address string, coinIndex uint) (types.TxPage, error) { + txs := make([]types.Tx, 0) txs = append(txs, tx) return txs, nil } -func (c Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas.TxPage, error) { - txs := make([]blockatlas.Tx, 0) +func (c Client) GetTokenTxs(address, token string, coinIndex uint) (types.TxPage, error) { + txs := make([]types.Tx, 0) txs = append(txs, tx) return txs, nil } -func (c Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) { - return blockatlas.TokenPage{}, nil +func (c Client) GetTokenList(address string, coinIndex uint) (types.TokenPage, error) { + return types.TokenPage{}, nil } func (c Client) GetCurrentBlockNumber() (int64, error) { return 0, nil } -func (c Client) GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, error) { +func (c Client) GetBlockByNumber(num int64, coinIndex uint) (*types.Block, error) { return nil, nil } diff --git a/platform/ethereum/trustray/block.go b/platform/ethereum/trustray/block.go index f0d614a19..b399299ea 100644 --- a/platform/ethereum/trustray/block.go +++ b/platform/ethereum/trustray/block.go @@ -1,19 +1,17 @@ package trustray -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" -func (c *Client) GetBlockByNumber(num int64, coinIndex uint) (*blockatlas.Block, error) { +func (c *Client) GetBlockByNumber(num int64, coinIndex uint) (*types.Block, error) { srcPage, err := c.GetBlock(num) if err != nil { return nil, err } - var txs []blockatlas.Tx + var txs []types.Tx for _, srcTx := range srcPage { txs = AppendTxs(txs, &srcTx, coinIndex) } - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil diff --git a/platform/ethereum/trustray/model.go b/platform/ethereum/trustray/model.go index 3e97715cc..b29b96e4c 100644 --- a/platform/ethereum/trustray/model.go +++ b/platform/ethereum/trustray/model.go @@ -1,8 +1,6 @@ package trustray -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" type Page struct { Total uint `json:"total"` @@ -33,13 +31,13 @@ type Doc struct { } type Op struct { - TxID string `json:"transactionId"` - Contract *Contract `json:"contract"` - From string `json:"from"` - To string `json:"to"` - Type blockatlas.TransactionType `json:"type"` - Value string `json:"value"` - Coin uint `json:"coin"` + TxID string `json:"transactionId"` + Contract *Contract `json:"contract"` + From string `json:"from"` + To string `json:"to"` + Type types.TransactionType `json:"type"` + Value string `json:"value"` + Coin uint `json:"coin"` } type Contract struct { diff --git a/platform/ethereum/trustray/token.go b/platform/ethereum/trustray/token.go index bcd382abb..ef3846612 100644 --- a/platform/ethereum/trustray/token.go +++ b/platform/ethereum/trustray/token.go @@ -1,11 +1,10 @@ package trustray import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/tokentype" + "github.com/trustwallet/golibs/types" ) -func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenPage, error) { +func (c *Client) GetTokenList(address string, coinIndex uint) (types.TokenPage, error) { account, err := c.GetTokens(address) if err != nil { return nil, err @@ -14,10 +13,10 @@ func (c *Client) GetTokenList(address string, coinIndex uint) (blockatlas.TokenP } // NormalizeToken converts a Ethereum token into the generic model -func NormalizeToken(srcToken *Contract, coinIndex uint) blockatlas.Token { - tokenType := tokentype.GetEthereumTokenTypeByIndex(coinIndex) +func NormalizeToken(srcToken *Contract, coinIndex uint) types.Token { + tokenType := types.GetEthereumTokenTypeByIndex(coinIndex) - return blockatlas.Token{ + return types.Token{ Name: srcToken.Name, Symbol: srcToken.Symbol, TokenID: srcToken.Address, @@ -28,8 +27,8 @@ func NormalizeToken(srcToken *Contract, coinIndex uint) blockatlas.Token { } // NormalizeTxs converts multiple Ethereum tokens -func NormalizeTokens(srcTokens []Contract, coinIndex uint) []blockatlas.Token { - tokenPage := make([]blockatlas.Token, 0) +func NormalizeTokens(srcTokens []Contract, coinIndex uint) []types.Token { + tokenPage := make([]types.Token, 0) for _, srcToken := range srcTokens { token := NormalizeToken(&srcToken, coinIndex) tokenPage = append(tokenPage, token) diff --git a/platform/ethereum/trustray/token_test.go b/platform/ethereum/trustray/token_test.go index 64599ca6c..85ea3fff9 100644 --- a/platform/ethereum/trustray/token_test.go +++ b/platform/ethereum/trustray/token_test.go @@ -5,9 +5,8 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/golibs/tokentype" + "github.com/trustwallet/golibs/types" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" ) @@ -21,7 +20,7 @@ const tokenSrc = ` type testToken struct { apiResponse string - expected *blockatlas.Token + expected *types.Token coin int } @@ -30,103 +29,103 @@ func TestNormalizeToken(t *testing.T) { name string tokenRaw string coin int - want blockatlas.Token + want types.Token }{ { "ethereum erc20", tokenSrc, coin.ETH, - blockatlas.Token{ + types.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.ETH, - Type: tokentype.ERC20, + Type: types.ERC20, }, }, {"classic etc20", tokenSrc, coin.ETC, - blockatlas.Token{ + types.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.ETC, - Type: tokentype.ETC20, + Type: types.ETC20, }, }, {"gochain go20", tokenSrc, coin.GO, - blockatlas.Token{ + types.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.GO, - Type: tokentype.GO20, + Type: types.GO20, }, }, {"thudertoken tt20", tokenSrc, coin.TT, - blockatlas.Token{ + types.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.TT, - Type: tokentype.TT20, + Type: types.TT20, }, }, {"wanchain wan20", tokenSrc, coin.WAN, - blockatlas.Token{ + types.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.WAN, - Type: tokentype.WAN20, + Type: types.WAN20, }, }, {"poa poa20", tokenSrc, coin.POA, - blockatlas.Token{ + types.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.POA, - Type: tokentype.POA20, + Type: types.POA20, }, }, {"callisto clo20", tokenSrc, coin.CLO, - blockatlas.Token{ + types.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: coin.CLO, - Type: tokentype.CLO20, + Type: types.CLO20, }, }, {"unknown", tokenSrc, 1999, - blockatlas.Token{ + types.Token{ Name: "FusChain", Symbol: "FUS", Decimals: 18, TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", Coin: 1999, - Type: tokentype.ERC20, + Type: types.ERC20, }, }, } diff --git a/platform/ethereum/trustray/transaction.go b/platform/ethereum/trustray/transaction.go index 274ea49e5..9aaba6b60 100644 --- a/platform/ethereum/trustray/transaction.go +++ b/platform/ethereum/trustray/transaction.go @@ -3,12 +3,12 @@ package trustray import ( "math/big" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/address" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (c *Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxPage, error) { +func (c *Client) GetTransactions(address string, coinIndex uint) (types.TxPage, error) { page, err := c.GetTxs(address) if err != nil { return nil, err @@ -16,7 +16,7 @@ func (c *Client) GetTransactions(address string, coinIndex uint) (blockatlas.TxP return normalizePage(page, address, coinIndex), nil } -func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas.TxPage, error) { +func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (types.TxPage, error) { page, err := c.GetTxsWithContract(address, token) if err != nil { return nil, err @@ -24,8 +24,8 @@ func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (blockatlas. return normalizePage(page, address, coinIndex), nil } -func normalizePage(srcPage *Page, address string, coinIndex uint) blockatlas.TxPage { - var txs []blockatlas.Tx +func normalizePage(srcPage *Page, address string, coinIndex uint) types.TxPage { + var txs []types.Tx for i, srcTx := range srcPage.Docs { txs = AppendTxs(txs, &srcTx, coinIndex) txs[i].Direction = txs[i].GetTransactionDirection(address) @@ -33,7 +33,7 @@ func normalizePage(srcPage *Page, address string, coinIndex uint) blockatlas.TxP return txs } -func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas.Tx) { +func AppendTxs(in []types.Tx, srcTx *Doc, coinIndex uint) (out []types.Tx) { out = in baseTx, ok := extractBase(srcTx, coinIndex) if !ok { @@ -43,8 +43,8 @@ func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas // Native ETH transaction if len(srcTx.Ops) == 0 && srcTx.Input == "0x" { transferTx := baseTx - transferTx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(srcTx.Value), + transferTx.Meta = types.Transfer{ + Value: types.Amount(srcTx.Value), Symbol: coin.Coins[coinIndex].Symbol, Decimals: coin.Coins[coinIndex].Decimals, } @@ -55,7 +55,7 @@ func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas // Smart Contract Call if len(srcTx.Ops) == 0 && srcTx.Input != "0x" { contractTx := baseTx - contractTx.Meta = blockatlas.ContractCall{ + contractTx.Meta = types.ContractCall{ Input: srcTx.Input, Value: srcTx.Value, } @@ -68,18 +68,18 @@ func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas } op := &srcTx.Ops[0] // Token transfer transaction - if op.Type == blockatlas.TxTokenTransfer && op.Contract != nil { + if op.Type == types.TxTokenTransfer && op.Contract != nil { tokenTx := baseTx tokenId, err := address.ToEIP55ByCoinID(op.Contract.Address, coinIndex) if err != nil { return } - tokenTx.Meta = blockatlas.TokenTransfer{ + tokenTx.Meta = types.TokenTransfer{ Name: op.Contract.Name, Symbol: op.Contract.Symbol, TokenID: tokenId, Decimals: op.Contract.Decimals, - Value: blockatlas.Amount(op.Value), + Value: types.Amount(op.Value), From: op.From, To: op.To, } @@ -89,16 +89,16 @@ func AppendTxs(in []blockatlas.Tx, srcTx *Doc, coinIndex uint) (out []blockatlas return } -func extractBase(srcTx *Doc, coinIndex uint) (base blockatlas.Tx, ok bool) { +func extractBase(srcTx *Doc, coinIndex uint) (base types.Tx, ok bool) { var ( - status blockatlas.Status + status types.Status errReason string ) if srcTx.Error == "" { - status = blockatlas.StatusCompleted + status = types.StatusCompleted } else { - status = blockatlas.StatusError + status = types.StatusError errReason = srcTx.Error } @@ -111,10 +111,10 @@ func extractBase(srcTx *Doc, coinIndex uint) (base blockatlas.Tx, ok bool) { if err != nil { return base, false } - base = blockatlas.Tx{ + base = types.Tx{ ID: srcTx.ID, Coin: coinIndex, - Fee: blockatlas.Amount(fee), + Fee: types.Amount(fee), From: from, To: to, Date: srcTx.Timestamp, diff --git a/platform/ethereum/trustray/transaction_test.go b/platform/ethereum/trustray/transaction_test.go index bef1f3a9f..5f2ea0243 100644 --- a/platform/ethereum/trustray/transaction_test.go +++ b/platform/ethereum/trustray/transaction_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) const tokenTransferSrc = ` @@ -114,7 +114,7 @@ var ( addr2 = "0xaA4D790076f1Bf7511a0A0AC498C89e13e1eFE17" contract1 = "0xf3586684107CE0859c44aa2b2E0fB8cd8731a15a" ) -var tokenTransferDst = blockatlas.Tx{ +var tokenTransferDst = types.Tx{ ID: "0x7777854580f273df61e0162e1a41b3e1e05ab8b9f553036fa9329a90dd7e9ab2", Coin: coin.ETH, From: addr1, @@ -123,8 +123,8 @@ var tokenTransferDst = blockatlas.Tx{ Date: 1554248437, Block: 7491945, Sequence: 88, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.TokenTransfer{ + Status: types.StatusCompleted, + Meta: types.TokenTransfer{ Name: "KaratBank Coin", Symbol: "KBC", TokenID: contract1, @@ -135,7 +135,7 @@ var tokenTransferDst = blockatlas.Tx{ }, } -var contractCallDst = blockatlas.Tx{ +var contractCallDst = types.Tx{ ID: "0x34ab0028a9aa794d5cc12887e7b813cec17889948276b301028f24a408da6da4", Coin: coin.ETH, From: "0xc9a16a82c284EFC3cB0fE8C891ab85d6EBa0EeFB", @@ -144,14 +144,14 @@ var contractCallDst = blockatlas.Tx{ Date: 1554661737, Block: 7522627, Sequence: 534, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.ContractCall{ + Status: types.StatusCompleted, + Meta: types.ContractCall{ Input: "0xfffdefefed", Value: "1800000000000000000", }, } -var transferDst = blockatlas.Tx{ +var transferDst = types.Tx{ ID: "0x77f8a3b2203933493d103a1637de814b4853410b1fb2981c4d2cff4d7a3071ab", Coin: coin.ETH, From: "0xf5AeA47E57c058881B31EE8fcE1002C409188F06", @@ -160,15 +160,15 @@ var transferDst = blockatlas.Tx{ Date: 1554663642, Block: 7522781, Sequence: 88, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Meta: types.Transfer{ Value: "1999895000000000000", Symbol: "ETH", Decimals: 18, }, } -var failedDst = blockatlas.Tx{ +var failedDst = types.Tx{ ID: "0x8dfe7e859f7bdcea4e6f4ada18567d96a51c3aa29e618ef09b80ae99385e191e", Coin: coin.ETH, From: "0x4b55af7cE28A113D794F9A9940fe1506f37aA619", @@ -177,9 +177,9 @@ var failedDst = blockatlas.Tx{ Date: 1554662399, Block: 7522678, Sequence: 1, - Status: blockatlas.StatusError, + Status: types.StatusError, Error: "Error", - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "59859820000000000", Symbol: "ETH", Decimals: 18, @@ -191,7 +191,7 @@ func TestNormalize(t *testing.T) { doc Doc tests = []struct { name, apiResponse string - expected *blockatlas.Tx + expected *types.Tx }{ {"transfer", transferSrc, &transferDst}, {"token transfer", tokenTransferSrc, &tokenTransferDst}, @@ -214,7 +214,7 @@ func TestNormalize(t *testing.T) { t.Fatal(err) } - dstJSON, err := json.Marshal([]blockatlas.Tx{*tt.expected}) + dstJSON, err := json.Marshal([]types.Tx{*tt.expected}) if err != nil { t.Fatal(err) } diff --git a/platform/filecoin/block.go b/platform/filecoin/block.go index a020dd606..f4ed2eb6e 100644 --- a/platform/filecoin/block.go +++ b/platform/filecoin/block.go @@ -1,9 +1,9 @@ package filecoin import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/filecoin/rpc" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) func (p *Platform) CurrentBlockNumber() (int64, error) { @@ -14,7 +14,7 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { return int64(response.Height), nil } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { chainHeadResponse, err := p.client.GetTipSetByHeight(num) if err != nil { return nil, err @@ -31,8 +31,8 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { return normalizeBlockResponses(uint64(chainHeadResponse.Height), uint64(chainHeadResponse.GetTimestamp()), blockResponses), nil } -func normalizeBlockResponses(num, timestamp uint64, responses []rpc.BlockMessageResponse) *blockatlas.Block { - var result blockatlas.Block +func normalizeBlockResponses(num, timestamp uint64, responses []rpc.BlockMessageResponse) *types.Block { + var result types.Block result.Number = int64(num) for _, resp := range responses { for _, msg := range resp.SecpkMessages { @@ -43,8 +43,8 @@ func normalizeBlockResponses(num, timestamp uint64, responses []rpc.BlockMessage return &result } -func normalizeBlockTx(num, timestamp uint64, msg rpc.SecpkMessage) blockatlas.Tx { - return blockatlas.Tx{ +func normalizeBlockTx(num, timestamp uint64, msg rpc.SecpkMessage) types.Tx { + return types.Tx{ Coin: coin.Filecoin().ID, From: msg.Message.From, To: msg.Message.To, @@ -52,12 +52,12 @@ func normalizeBlockTx(num, timestamp uint64, msg rpc.SecpkMessage) blockatlas.Tx Fee: "0", Block: num, Date: int64(timestamp), - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Sequence: uint64(msg.Message.Nonce), - Type: blockatlas.TxTransfer, + Type: types.TxTransfer, Memo: "", - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(msg.Message.Value), + Meta: types.Transfer{ + Value: types.Amount(msg.Message.Value), Symbol: coin.Filecoin().Symbol, Decimals: coin.Filecoin().Decimals, }, diff --git a/platform/filecoin/block_test.go b/platform/filecoin/block_test.go index 278ed8395..36c51148a 100644 --- a/platform/filecoin/block_test.go +++ b/platform/filecoin/block_test.go @@ -12,7 +12,7 @@ import ( ) func TestPlatform_CurrentBlockNumber(t *testing.T) { - chainHead, err := mock.JsonFromFilePathToString("mocks/ChainHead.json") + chainHead, err := mock.JsonStringFromFilePath("mocks/ChainHead.json") assert.Nil(t, err) data := make(map[string]func(http.ResponseWriter, *http.Request)) @@ -53,13 +53,13 @@ func TestPlatform_GetBlockByNumber(t *testing.T) { switch resp { case "Filecoin.ChainGetTipSetByHeight": - chainHead, err := mock.JsonFromFilePathToString("mocks/ChainGetTipSetByHeight.json") + chainHead, err := mock.JsonStringFromFilePath("mocks/ChainGetTipSetByHeight.json") if err != nil { panic(err) } d = chainHead case "Filecoin.ChainGetBlockMessages": - blockMsg, err := mock.JsonFromFilePathToString("mocks/ChainGetBlockMessages.json") + blockMsg, err := mock.JsonStringFromFilePath("mocks/ChainGetBlockMessages.json") if err != nil { panic(err) } @@ -79,7 +79,7 @@ func TestPlatform_GetBlockByNumber(t *testing.T) { assert.Nil(t, err) blockJson, _ := json.Marshal(block) - wanted, _ := mock.JsonFromFilePathToString("mocks/response.json") + wanted, _ := mock.JsonStringFromFilePath("mocks/response.json") assert.JSONEq(t, string(blockJson), wanted) } diff --git a/platform/filecoin/transaction.go b/platform/filecoin/transaction.go index 743b66284..90c34d49d 100644 --- a/platform/filecoin/transaction.go +++ b/platform/filecoin/transaction.go @@ -1,18 +1,18 @@ package filecoin import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/filecoin/explorer" + "github.com/trustwallet/golibs/types" ) const messageMethod = "Send" -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - res, err := p.explorer.GetMessagesByAddress(address, blockatlas.TxPerPage) +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { + res, err := p.explorer.GetMessagesByAddress(address, types.TxPerPage) if err != nil { return nil, err } - normalized := make([]blockatlas.Tx, 0) + normalized := make([]types.Tx, 0) for _, message := range res.Messages { // skip non transfer messages if message.Method != messageMethod { @@ -24,16 +24,16 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return normalized, nil } -func (p *Platform) NormalizeMessage(message explorer.Message, address string) blockatlas.Tx { - status := blockatlas.StatusCompleted +func (p *Platform) NormalizeMessage(message explorer.Message, address string) types.Tx { + status := types.StatusCompleted if message.Receipt.ExitCode != 0 { - status = blockatlas.StatusError + status = types.StatusError } - direction := blockatlas.DirectionOutgoing + direction := types.DirectionOutgoing if message.From != address { - direction = blockatlas.DirectionIncoming + direction = types.DirectionIncoming } - return blockatlas.Tx{ + return types.Tx{ ID: message.Cid, Coin: p.Coin().ID, From: message.From, @@ -42,10 +42,10 @@ func (p *Platform) NormalizeMessage(message explorer.Message, address string) bl Block: message.Height, Status: status, Sequence: message.Nonce, - Type: blockatlas.TxTransfer, + Type: types.TxTransfer, Direction: direction, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(message.Value), + Meta: types.Transfer{ + Value: types.Amount(message.Value), Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, }, diff --git a/platform/filecoin/transaction_test.go b/platform/filecoin/transaction_test.go index 459504217..ce2334249 100644 --- a/platform/filecoin/transaction_test.go +++ b/platform/filecoin/transaction_test.go @@ -4,8 +4,8 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/filecoin/explorer" + "github.com/trustwallet/golibs/types" ) func TestPlatform_NormalizeMessage(t *testing.T) { @@ -16,7 +16,7 @@ func TestPlatform_NormalizeMessage(t *testing.T) { tests := []struct { name string args args - want blockatlas.Tx + want types.Tx }{ { name: "Test transfer", @@ -36,7 +36,7 @@ func TestPlatform_NormalizeMessage(t *testing.T) { }, address: "f16hhfi2xkkmpsi4c5mmgwbkgk5wslfcaflefsqpy", }, - want: blockatlas.Tx{ + want: types.Tx{ ID: "bafy2bzacectkidmsel5gn5qamrqhcgqgqefhdzlqukry3rc2ase4yqdbxazqi", Coin: 461, From: "f1mdseaz4gkbz2cq2kf4q3xqbws5ongyt7vdbvzoa", @@ -47,7 +47,7 @@ func TestPlatform_NormalizeMessage(t *testing.T) { Sequence: 6, Type: "transfer", Direction: "incoming", - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "298040241318833792", Symbol: "FIL", Decimals: 18, @@ -72,7 +72,7 @@ func TestPlatform_NormalizeMessage(t *testing.T) { }, address: "f16hhfi2xkkmpsi4c5mmgwbkgk5wslfcaflefsqpy", }, - want: blockatlas.Tx{ + want: types.Tx{ ID: "bafy2bzacebgbszawdnrl7flgrb2ixt4f6lsb4jjqywv3bsekplpsiswexepha", Coin: 461, From: "f16hhfi2xkkmpsi4c5mmgwbkgk5wslfcaflefsqpy", @@ -83,7 +83,7 @@ func TestPlatform_NormalizeMessage(t *testing.T) { Sequence: 23, Type: "transfer", Direction: "outgoing", - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "1000000000000000", Symbol: "FIL", Decimals: 18, diff --git a/platform/fio/transaction.go b/platform/fio/transaction.go index fd3ba9865..5603da7c0 100644 --- a/platform/fio/transaction.go +++ b/platform/fio/transaction.go @@ -10,7 +10,7 @@ import ( "errors" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) const ( @@ -20,14 +20,14 @@ const ( actionTransferPubkey = "trnsfiopubky" ) -func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err error) { +func (p *Platform) GetTxsByAddress(address string) (page types.TxPage, err error) { // take actor from address account := actorFromPublicKeyOrActor(address) actions, err := p.client.getTransactions(account) if err != nil { return nil, err } - txs := make([]blockatlas.Tx, 0) + txs := make([]types.Tx, 0) for _, a := range actions { tx, err := p.Normalize(&a, account) if err != nil { @@ -36,15 +36,15 @@ func (p *Platform) GetTxsByAddress(address string) (page blockatlas.TxPage, err txs = append(txs, tx) } txs = unique(txs) - txPage := blockatlas.TxPage(txs) + txPage := types.TxPage(txs) sort.Sort(txPage) return txPage, nil } -func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, error) { +func (p *Platform) Normalize(action *Action, account string) (types.Tx, error) { var ( to, from, memo string - amount, fee blockatlas.Amount + amount, fee types.Amount sequence uint64 ) const dateFormat string = "2006-01-02T15:04:05" @@ -54,22 +54,22 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err // convert to action-specific data dataJSON, err := json.Marshal(action.ActionTrace.Act.Data) if err != nil { - return blockatlas.Tx{}, errors.New("Unparseable Data field") + return types.Tx{}, errors.New("Unparseable Data field") } switch action.ActionTrace.Act.Name { case actionTransfer: var actionData ActionDataTransfer if json.Unmarshal(dataJSON, &actionData) != nil { - return blockatlas.Tx{}, errors.New("Unparseable Data field") + return types.Tx{}, errors.New("Unparseable Data field") } if actionData.To == contractTreasury { - return blockatlas.Tx{}, errors.New("Skip tx sent to treasury, usually fee") + return types.Tx{}, errors.New("Skip tx sent to treasury, usually fee") } from = actionData.From to = actionData.To amountNum, err := strconv.ParseFloat(strings.Split(actionData.Quantity, " ")[0], 64) if err == nil { - amount = blockatlas.Amount(strconv.Itoa(int(amountNum * 1000000000))) + amount = types.Amount(strconv.Itoa(int(amountNum * 1000000000))) } // fee unknown memo = actionData.Memo @@ -77,16 +77,16 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err case actionTransferPubkey: var actionData ActionDataTrnsfiopubky if json.Unmarshal(dataJSON, &actionData) != nil { - return blockatlas.Tx{}, errors.New("Unparseable Data field") + return types.Tx{}, errors.New("Unparseable Data field") } from = actionData.Actor to = actorFromPublicKeyOrActor(actionData.PayeePublicKey) - amount = blockatlas.Amount(strconv.FormatInt(actionData.Amount, 10)) - fee = blockatlas.Amount(strconv.FormatInt(actionData.MaxFee, 10)) + amount = types.Amount(strconv.FormatInt(actionData.Amount, 10)) + fee = types.Amount(strconv.FormatInt(actionData.MaxFee, 10)) // not set sequence because it might be duplicated } date, _ := time.Parse(dateFormat, action.BlockTime) - tx := blockatlas.Tx{ + tx := types.Tx{ ID: action.ActionTrace.TrxID, Coin: p.Coin().ID, Date: date.Unix(), @@ -94,25 +94,25 @@ func (p *Platform) Normalize(action *Action, account string) (blockatlas.Tx, err To: to, Block: action.BlockNum, Sequence: sequence, - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Fee: fee, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: amount, Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, }, Memo: memo, - Type: blockatlas.TxTransfer, + Type: types.TxTransfer, } tx.Direction = tx.GetTransactionDirection(account) return tx, nil } - return blockatlas.Tx{}, errors.New("Unknown action") + return types.Tx{}, errors.New("Unknown action") } -func unique(txs []blockatlas.Tx) []blockatlas.Tx { +func unique(txs []types.Tx) []types.Tx { set := make(map[string]struct{}) - var result []blockatlas.Tx + var result []types.Tx for _, tx := range txs { id := fmt.Sprintf("%s-%d", tx.ID, tx.Sequence) if _, ok := set[id]; ok { diff --git a/platform/harmony/block.go b/platform/harmony/block.go index b3af79b59..11f013115 100644 --- a/platform/harmony/block.go +++ b/platform/harmony/block.go @@ -1,14 +1,12 @@ package harmony -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.CurrentBlockNumber() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { srcBlock, err := p.client.GetBlockByNumber(num) if err != nil { return nil, err @@ -17,12 +15,12 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { return &block, nil } -func (p *Platform) NormalizeBlock(block *BlockInfo) blockatlas.Block { +func (p *Platform) NormalizeBlock(block *BlockInfo) types.Block { blockNumber, err := hexToInt(block.Number) if err != nil { - return blockatlas.Block{} + return types.Block{} } - return blockatlas.Block{ + return types.Block{ Number: int64(blockNumber), Txs: NormalizeTxs(block.Transactions), } diff --git a/platform/harmony/stake.go b/platform/harmony/stake.go index 461f1fd9f..f694b34d0 100644 --- a/platform/harmony/stake.go +++ b/platform/harmony/stake.go @@ -7,6 +7,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/golibs/types" ) const ( @@ -121,7 +122,7 @@ func NormalizeDelegations(delegations []Delegation, validators blockatlas.Valida func getDetails(apr float64) blockatlas.StakingDetails { return blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: apr}, - MinimumAmount: blockatlas.Amount("1000"), + MinimumAmount: types.Amount("1000"), LockTime: lockTime, Type: blockatlas.DelegationTypeDelegate, } diff --git a/platform/harmony/stake_test.go b/platform/harmony/stake_test.go index 1e5ef9f0f..2fad4119a 100644 --- a/platform/harmony/stake_test.go +++ b/platform/harmony/stake_test.go @@ -11,8 +11,8 @@ import ( ) var ( - validatorSrc, _ = mock.JsonFromFilePathToString("mocks/" + "validator.json") - delegationsSrc, _ = mock.JsonFromFilePathToString("mocks/" + "delegation.json") + validatorSrc, _ = mock.JsonStringFromFilePath("mocks/" + "validator.json") + delegationsSrc, _ = mock.JsonStringFromFilePath("mocks/" + "delegation.json") validatorMap = blockatlas.ValidatorMap{ "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy": validator1, } diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index 2dd7bb4c6..ab8af9584 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -3,78 +3,78 @@ package harmony import ( "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) const Annual = 10 -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { result, err := p.client.GetTxsOfAddress(address) if err != nil { - return blockatlas.TxPage{}, err + return types.TxPage{}, err } return NormalizeTxs(result.Transactions), err } -func NormalizeTxs(txs []Transaction) blockatlas.TxPage { - normalizeTxs := make([]blockatlas.Tx, 0) +func NormalizeTxs(txs []Transaction) types.TxPage { + normalizeTxs := make([]types.Tx, 0) for _, srcTx := range txs { normalized, isCorrect, err := NormalizeTx(&srcTx) if !isCorrect || err != nil { - return []blockatlas.Tx{} + return []types.Tx{} } normalizeTxs = append(normalizeTxs, normalized) } return normalizeTxs } -func NormalizeTx(trx *Transaction) (tx blockatlas.Tx, b bool, err error) { +func NormalizeTx(trx *Transaction) (tx types.Tx, b bool, err error) { gasPrice, err := hexToInt(trx.GasPrice) if err != nil { - return blockatlas.Tx{}, false, err + return types.Tx{}, false, err } gas, err := hexToInt(trx.Gas) if err != nil { - return blockatlas.Tx{}, false, err + return types.Tx{}, false, err } fee := gas * gasPrice literalFee := strconv.Itoa(int(fee)) literalValue, err := numbers.HexToDecimal(trx.Value) if err != nil { - return blockatlas.Tx{}, false, err + return types.Tx{}, false, err } block, err := hexToInt(trx.BlockNumber) if err != nil { - return blockatlas.Tx{}, false, err + return types.Tx{}, false, err } nonce, err := hexToInt(trx.Nonce) if err != nil { - return blockatlas.Tx{}, false, err + return types.Tx{}, false, err } timestamp, err := hexToInt(trx.Timestamp) if err != nil { - return blockatlas.Tx{}, false, err + return types.Tx{}, false, err } - return blockatlas.Tx{ + return types.Tx{ ID: trx.Hash, Coin: coin.ONE, From: trx.From, To: trx.To, - Fee: blockatlas.Amount(literalFee), - Status: blockatlas.StatusCompleted, + Fee: types.Amount(literalFee), + Status: types.StatusCompleted, Sequence: nonce, Date: int64(timestamp), - Type: blockatlas.TxTransfer, + Type: types.TxTransfer, Block: block, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(literalValue), + Meta: types.Transfer{ + Value: types.Amount(literalValue), Symbol: coin.Coins[coin.ONE].Symbol, Decimals: coin.Coins[coin.ONE].Decimals, }, diff --git a/platform/harmony/transaction_test.go b/platform/harmony/transaction_test.go index 0def9f830..73f16ee16 100644 --- a/platform/harmony/transaction_test.go +++ b/platform/harmony/transaction_test.go @@ -4,9 +4,9 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) func TestNormalizeTx(t *testing.T) { @@ -16,7 +16,7 @@ func TestNormalizeTx(t *testing.T) { tests := []struct { name string args args - wantTx blockatlas.Tx + wantTx types.Tx wantB bool wantErr bool }{ @@ -25,7 +25,7 @@ func TestNormalizeTx(t *testing.T) { args: args{ filename: "transfer.json", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "0x230798fe22abff459b004675bf827a4089326a296fa4165d0c2ad27688e03e0c", Coin: coin.ONE, From: "one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7", @@ -33,9 +33,9 @@ func TestNormalizeTx(t *testing.T) { Fee: "21000000000000", Date: 1576346446, Block: 18, - Type: blockatlas.TxTransfer, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ + Type: types.TxTransfer, + Status: types.StatusCompleted, + Meta: types.Transfer{ Value: "100000000000000000", Symbol: "ONE", Decimals: 18, @@ -48,7 +48,7 @@ func TestNormalizeTx(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var srcTx Transaction - _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &srcTx) gotTx, gotB, err := NormalizeTx(&srcTx) if (err != nil) != tt.wantErr { t.Errorf("NormalizeTx() error = %v, wantErr %v", err, tt.wantErr) diff --git a/platform/icon/client.go b/platform/icon/client.go index 25f7fa04e..1484c06d4 100644 --- a/platform/icon/client.go +++ b/platform/icon/client.go @@ -4,8 +4,8 @@ import ( "net/url" "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/types" ) type Client struct { @@ -15,7 +15,7 @@ type Client struct { func (c *Client) GetAddressTransactions(address string) ([]Tx, error) { query := url.Values{ "address": {address}, - "count": {strconv.Itoa(blockatlas.TxPerPage)}, + "count": {strconv.Itoa(types.TxPerPage)}, } var res Response err := c.Get(&res, "address/txList", query) diff --git a/platform/icon/transaction.go b/platform/icon/transaction.go index 9d470ddc0..6fed6e1b9 100644 --- a/platform/icon/transaction.go +++ b/platform/icon/transaction.go @@ -4,18 +4,18 @@ import ( "time" log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { trxs, err := p.client.GetAddressTransactions(address) if err != nil { return nil, err } - nTrxs := make([]blockatlas.Tx, 0) + nTrxs := make([]types.Tx, 0) for _, trx := range trxs { nTrx, ok := Normalize(&trx) if !ok { @@ -28,7 +28,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { } // Normalize converts an Icon transaction into the generic model -func Normalize(trx *Tx) (tx blockatlas.Tx, b bool) { +func Normalize(trx *Tx) (tx types.Tx, b bool) { date, err := time.Parse("2006-01-02T15:04:05.999Z0700", trx.CreateDate) if err != nil { log.Error(err) @@ -37,18 +37,18 @@ func Normalize(trx *Tx) (tx blockatlas.Tx, b bool) { fee := numbers.DecimalExp(string(trx.Fee), 18) value := numbers.DecimalExp(string(trx.Amount), 18) - return blockatlas.Tx{ + return types.Tx{ ID: trx.TxHash, Coin: coin.ICX, From: trx.FromAddr, To: trx.ToAddr, - Fee: blockatlas.Amount(fee), - Status: blockatlas.StatusCompleted, + Fee: types.Amount(fee), + Status: types.StatusCompleted, Date: date.Unix(), - Type: blockatlas.TxTransfer, + Type: types.TxTransfer, Block: trx.Height, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(value), + Meta: types.Transfer{ + Value: types.Amount(value), Symbol: coin.Coins[coin.ICX].Symbol, Decimals: coin.Coins[coin.ICX].Decimals, }, diff --git a/platform/icon/transaction_test.go b/platform/icon/transaction_test.go index 758b4e2fb..b5ea3ad0f 100644 --- a/platform/icon/transaction_test.go +++ b/platform/icon/transaction_test.go @@ -4,9 +4,9 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) func TestNormalizeTx(t *testing.T) { @@ -16,7 +16,7 @@ func TestNormalizeTx(t *testing.T) { tests := []struct { name string args args - wantTx blockatlas.Tx + wantTx types.Tx ok bool }{ { @@ -24,7 +24,7 @@ func TestNormalizeTx(t *testing.T) { args: args{ filename: "transfer.json", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "0x34b8b6ec3a52710c24074f5e298f4a9c67bb61a0a1dde20e695efaeb30ff3754", Coin: coin.ICX, From: "hx1b8959dd5c57d2c502e22ee0a887d33baec09091", @@ -34,7 +34,7 @@ func TestNormalizeTx(t *testing.T) { Block: 357832, Status: "completed", Type: "transfer", - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "3470000000000000", Symbol: "ICX", Decimals: 18, @@ -46,7 +46,7 @@ func TestNormalizeTx(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var srcTx Tx - _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &srcTx) gotTx, ok := Normalize(&srcTx) if ok != tt.ok { t.Errorf("Normalize() ok = %v, wantOk %v", ok, tt.ok) diff --git a/platform/iotex/block.go b/platform/iotex/block.go index 6e5d3f5ff..872cf9aeb 100644 --- a/platform/iotex/block.go +++ b/platform/iotex/block.go @@ -1,15 +1,13 @@ package iotex -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.GetLatestBlock() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - var normalized []blockatlas.Tx +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { + var normalized []types.Tx txs, err := p.client.GetTxsInBlock(num) if err != nil { return nil, err @@ -22,7 +20,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { } } - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: normalized, }, nil diff --git a/platform/iotex/client.go b/platform/iotex/client.go index 2cdb53375..1143493a3 100644 --- a/platform/iotex/client.go +++ b/platform/iotex/client.go @@ -7,6 +7,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/types" ) type Client struct { @@ -40,7 +41,7 @@ func (c *Client) GetTxsOfAddress(address string, start int64) (*Response, error) var response Response err := c.Get(&response, "actions/addr/"+address, url.Values{ "start": {strconv.FormatInt(start, 10)}, - "count": {strconv.Itoa(blockatlas.TxPerPage)}, + "count": {strconv.Itoa(types.TxPerPage)}, }) if err != nil { diff --git a/platform/iotex/model.go b/platform/iotex/model.go index d616d8a5d..a15dd6573 100644 --- a/platform/iotex/model.go +++ b/platform/iotex/model.go @@ -1,8 +1,6 @@ package iotex -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" type Response struct { ActionInfo []*ActionInfo `json:"actionInfo"` @@ -39,8 +37,8 @@ type ActionCore struct { } type Transfer struct { - Amount blockatlas.Amount `json:"amount"` - Recipient string `json:"recipient"` + Amount types.Amount `json:"amount"` + Recipient string `json:"recipient"` } type ChainMeta struct { diff --git a/platform/iotex/stake.go b/platform/iotex/stake.go index bdab23966..5ccbefbf7 100644 --- a/platform/iotex/stake.go +++ b/platform/iotex/stake.go @@ -3,6 +3,7 @@ package iotex import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/golibs/types" ) func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { @@ -28,7 +29,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e func (p *Platform) GetDetails() blockatlas.StakingDetails { return blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: blockatlas.Amount("100000000000000000000"), + MinimumAmount: types.Amount("100000000000000000000"), LockTime: 259200, Type: blockatlas.DelegationTypeDelegate, } diff --git a/platform/iotex/transaction.go b/platform/iotex/transaction.go index e80a39eb8..4da1c7caf 100644 --- a/platform/iotex/transaction.go +++ b/platform/iotex/transaction.go @@ -4,13 +4,12 @@ import ( "strconv" "time" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - txs := make([]blockatlas.Tx, 0) +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { + txs := make([]types.Tx, 0) var start int64 totalTrx, err := p.client.GetAddressTotalTransactions(address) @@ -18,8 +17,8 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return nil, err } - if totalTrx >= blockatlas.TxPerPage { - start = totalTrx - blockatlas.TxPerPage + if totalTrx >= types.TxPerPage { + start = totalTrx - types.TxPerPage } actions, err := p.client.GetTxsOfAddress(address, start) @@ -38,7 +37,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { } // Normalize converts an Iotex transaction into the generic model -func Normalize(trx *ActionInfo) *blockatlas.Tx { +func Normalize(trx *ActionInfo) *types.Tx { if trx.Action == nil { return nil } @@ -67,18 +66,18 @@ func Normalize(trx *ActionInfo) *blockatlas.Tx { if trx.GasFee == "" { trx.GasFee = "0" } - return &blockatlas.Tx{ + return &types.Tx{ ID: trx.ActHash, Coin: coin.IOTX, From: trx.Sender, To: trx.Action.Core.Transfer.Recipient, - Fee: blockatlas.Amount(trx.GasFee), + Fee: types.Amount(trx.GasFee), Date: date.Unix(), Block: uint64(height), - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Sequence: uint64(nonce), - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ + Type: types.TxTransfer, + Meta: types.Transfer{ Value: trx.Action.Core.Transfer.Amount, Symbol: coin.Coins[coin.IOTX].Symbol, Decimals: coin.Coins[coin.IOTX].Decimals, diff --git a/platform/iotex/transaction_test.go b/platform/iotex/transaction_test.go index d23c1638c..fb51f53f5 100644 --- a/platform/iotex/transaction_test.go +++ b/platform/iotex/transaction_test.go @@ -4,9 +4,9 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) func TestNormalize(t *testing.T) { @@ -16,27 +16,27 @@ func TestNormalize(t *testing.T) { tests := []struct { name string args args - want []*blockatlas.Tx + want []*types.Tx }{ { name: "Test normalize actions", args: args{ filename: "transfer.json", }, - want: []*blockatlas.Tx{ + want: []*types.Tx{ { ID: "109b75cb688a5347268cbf11b20fa90fd0a14e92a42ba735c046bbf1a6e66ad7", Coin: coin.IOTX, From: "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", To: "io1mwekae7qqwlr23220k5n9z3fmjxz72tuchra3m", - Fee: blockatlas.Amount("10000000000000000"), + Fee: types.Amount("10000000000000000"), Date: int64(1556863740), Block: 96202, - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Sequence: uint64(3), - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("21000000000000000000"), + Type: types.TxTransfer, + Meta: types.Transfer{ + Value: types.Amount("21000000000000000000"), Symbol: "IOTX", Decimals: 18, }, @@ -50,7 +50,7 @@ func TestNormalize(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var response Response - _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &response) + _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &response) for i, v := range response.ActionInfo { if got := Normalize(v); !reflect.DeepEqual(got, tt.want[i]) { t.Errorf("Normalize() = %v, want %v", got, tt.want[i]) diff --git a/platform/kava/block.go b/platform/kava/block.go index ce03a0e3e..3732dd420 100644 --- a/platform/kava/block.go +++ b/platform/kava/block.go @@ -1,17 +1,15 @@ package kava -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { srcTxs, err := p.client.GetBlockByNumber(num) if err != nil { return nil, err } txs := p.NormalizeTxs(srcTxs.Txs) - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil diff --git a/platform/kava/transaction.go b/platform/kava/transaction.go index e58719199..408d566bc 100644 --- a/platform/kava/transaction.go +++ b/platform/kava/transaction.go @@ -6,17 +6,17 @@ import ( "sync" "time" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) const kavaDenom = "ukava" -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return p.GetTokenTxsByAddress(address, kavaDenom) } -func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, error) { tagsList := []string{"transfer.recipient", "message.sender"} var wg sync.WaitGroup out := make(chan []Tx, len(tagsList)) @@ -73,9 +73,9 @@ func (p *Platform) FilterTxsByDenom(txs []Tx, denom string) []Tx { } // NormalizeTxs converts multiple Cosmos transactions -func (p *Platform) NormalizeTxs(srcTxs []Tx) blockatlas.TxPage { +func (p *Platform) NormalizeTxs(srcTxs []Tx) types.TxPage { txMap := make(map[string]bool) - txs := make(blockatlas.TxPage, 0) + txs := make(types.TxPage, 0) for _, srcTx := range srcTxs { _, ok := txMap[srcTx.ID] if ok { @@ -91,14 +91,14 @@ func (p *Platform) NormalizeTxs(srcTxs []Tx) blockatlas.TxPage { } // Normalize converts an Cosmos transaction into the generic model -func (p *Platform) Normalize(srcTx *Tx) (tx blockatlas.Tx, ok bool) { +func (p *Platform) Normalize(srcTx *Tx) (tx types.Tx, ok bool) { date, err := time.Parse("2006-01-02T15:04:05Z", srcTx.Date) if err != nil { - return blockatlas.Tx{}, false + return types.Tx{}, false } block, err := strconv.ParseUint(srcTx.Block, 10, 64) if err != nil { - return blockatlas.Tx{}, false + return types.Tx{}, false } // Sometimes fees can be null objects (in the case of no fees e.g. F044F91441C460EDCD90E0063A65356676B7B20684D94C731CF4FAB204035B41) fee := "0" @@ -107,23 +107,23 @@ func (p *Platform) Normalize(srcTx *Tx) (tx blockatlas.Tx, ok bool) { if len(qty) > 0 && qty != fee { fee, err = numbers.DecimalToSatoshis(srcTx.Data.Contents.Fee.FeeAmount[0].Quantity) if err != nil { - return blockatlas.Tx{}, false + return types.Tx{}, false } } } - status := blockatlas.StatusCompleted + status := types.StatusCompleted // https://github.com/cosmos/cosmos-sdk/blob/95ddc242ad024ca78a359a13122dade6f14fd676/types/errors/errors.go#L19 if srcTx.Code > 0 { - status = blockatlas.StatusError + status = types.StatusError } - tx = blockatlas.Tx{ + tx = types.Tx{ ID: srcTx.ID, Coin: p.Coin().ID, Date: date.Unix(), Status: status, - Fee: blockatlas.Amount(fee), + Fee: types.Amount(fee), Block: block, Memo: srcTx.Data.Contents.Memo, } @@ -146,7 +146,7 @@ func (p *Platform) Normalize(srcTx *Tx) (tx blockatlas.Tx, ok bool) { return tx, false } -func (p *Platform) fillTransfer(tx *blockatlas.Tx, transfer MessageValueTransfer) { +func (p *Platform) fillTransfer(tx *types.Tx, transfer MessageValueTransfer) { if len(transfer.Amount) == 0 { return } @@ -157,35 +157,35 @@ func (p *Platform) fillTransfer(tx *blockatlas.Tx, transfer MessageValueTransfer } tx.From = transfer.FromAddr tx.To = transfer.ToAddr - tx.Type = blockatlas.TxTransfer - tx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(value), + tx.Type = types.TxTransfer + tx.Meta = types.Transfer{ + Value: types.Amount(value), Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, } switch { case amount.Denom == kavaDenom: - tx.Type = blockatlas.TxTransfer - tx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(value), + tx.Type = types.TxTransfer + tx.Meta = types.Transfer{ + Value: types.Amount(value), Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, } default: - tx.Type = blockatlas.TxNativeTokenTransfer - tx.Meta = blockatlas.NativeTokenTransfer{ + tx.Type = types.TxNativeTokenTransfer + tx.Meta = types.NativeTokenTransfer{ Decimals: p.Coin().Decimals, From: tx.From, Symbol: strings.ToUpper(amount.Denom), Name: amount.Denom, To: tx.To, TokenID: amount.Denom, - Value: blockatlas.Amount(value), + Value: types.Amount(value), } } } -func (p *Platform) fillDelegate(tx *blockatlas.Tx, delegate MessageValueDelegate, events Events, msgType TxType) { +func (p *Platform) fillDelegate(tx *types.Tx, delegate MessageValueDelegate, events Events, msgType TxType) { value := "" if len(delegate.Amount.Quantity) > 0 { var err error @@ -196,30 +196,30 @@ func (p *Platform) fillDelegate(tx *blockatlas.Tx, delegate MessageValueDelegate } tx.From = delegate.DelegatorAddr tx.To = delegate.ValidatorAddr - tx.Type = blockatlas.TxAnyAction + tx.Type = types.TxAnyAction - key := blockatlas.KeyStakeDelegate - title := blockatlas.KeyTitle("") + key := types.KeyStakeDelegate + title := types.KeyTitle("") switch msgType { case MsgDelegate: - tx.Direction = blockatlas.DirectionOutgoing - title = blockatlas.AnyActionDelegation + tx.Direction = types.DirectionOutgoing + title = types.AnyActionDelegation case MsgUndelegate: - tx.Direction = blockatlas.DirectionIncoming - title = blockatlas.AnyActionUndelegation + tx.Direction = types.DirectionIncoming + title = types.AnyActionUndelegation case MsgWithdrawDelegationReward: - tx.Direction = blockatlas.DirectionIncoming - title = blockatlas.AnyActionClaimRewards - key = blockatlas.KeyStakeClaimRewards + tx.Direction = types.DirectionIncoming + title = types.AnyActionClaimRewards + key = types.KeyStakeClaimRewards value = events.GetWithdrawRewardValue() } - tx.Meta = blockatlas.AnyAction{ + tx.Meta = types.AnyAction{ Coin: p.Coin().ID, Title: title, Key: key, Name: p.Coin().Name, Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, - Value: blockatlas.Amount(value), + Value: types.Amount(value), } } diff --git a/platform/kava/transaction_test.go b/platform/kava/transaction_test.go index 662d1fcb8..daf3aaab9 100644 --- a/platform/kava/transaction_test.go +++ b/platform/kava/transaction_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) const transferSrc = ` @@ -624,7 +624,7 @@ const claimRewardSrc2 = ` ] }` -var transferDst = blockatlas.Tx{ +var transferDst = types.Tx{ ID: "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", Coin: coin.ATOM, From: "cosmos1rw62phusuv9vzraezr55k0vsqssvz6ed52zyrl", @@ -632,16 +632,16 @@ var transferDst = blockatlas.Tx{ Fee: "1", Date: 1556992677, Block: 151980, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Type: types.TxTransfer, + Meta: types.Transfer{ Value: "2271999999", Symbol: coin.Cosmos().Symbol, Decimals: 6, }, } -var transferDstKava = blockatlas.Tx{ +var transferDstKava = types.Tx{ ID: "E19B011D20D862DA0BEA7F24E3BC6DFF666EE6E044FCD9BD95B073478086DBB6", Coin: coin.KAVA, From: "kava17wcggpjx007uc09s8y4hwrj8f228mlwe0n0upn", @@ -649,16 +649,16 @@ var transferDstKava = blockatlas.Tx{ Fee: "1", Date: 1556992677, Block: 151980, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxTransfer, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Type: types.TxTransfer, + Meta: types.Transfer{ Value: "2271999999", Symbol: coin.Kava().Symbol, Decimals: 6, }, } -var transferDstKavaToken = blockatlas.Tx{ +var transferDstKavaToken = types.Tx{ ID: "514D43780335A1C516850FEE5692F59E9A9DF1D8D986FC62AC434BEB58EDB8E2", Coin: coin.KAVA, From: "kava1ys70jvnajkv88529ys6urjcyle3k2j9r24g6a7", @@ -666,9 +666,9 @@ var transferDstKavaToken = blockatlas.Tx{ Fee: "30", Date: 1608374964, Block: 645538, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxNativeTokenTransfer, - Meta: blockatlas.NativeTokenTransfer{ + Status: types.StatusCompleted, + Type: types.TxNativeTokenTransfer, + Meta: types.NativeTokenTransfer{ Value: "10000000000", Symbol: "HARD", Decimals: 6, @@ -679,7 +679,7 @@ var transferDstKavaToken = blockatlas.Tx{ }, } -var delegateDst = blockatlas.Tx{ +var delegateDst = types.Tx{ ID: "11078091D1D5BD84F4275B6CEE02170428944DB0E8EEC37E980551435F6D04C7", Coin: coin.ATOM, From: "cosmos1237l0vauhw78qtwq045jd24ay4urpec6r3xfn3", @@ -687,13 +687,13 @@ var delegateDst = blockatlas.Tx{ Fee: "5000", Date: 1564632616, Block: 1258202, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionOutgoing, - Meta: blockatlas.AnyAction{ + Status: types.StatusCompleted, + Type: types.TxAnyAction, + Direction: types.DirectionOutgoing, + Meta: types.AnyAction{ Coin: coin.ATOM, - Title: blockatlas.AnyActionDelegation, - Key: blockatlas.KeyStakeDelegate, + Title: types.AnyActionDelegation, + Key: types.KeyStakeDelegate, Name: coin.Cosmos().Name, Symbol: coin.Coins[coin.ATOM].Symbol, Decimals: coin.Coins[coin.ATOM].Decimals, @@ -701,7 +701,7 @@ var delegateDst = blockatlas.Tx{ }, } -var unDelegateDst = blockatlas.Tx{ +var unDelegateDst = types.Tx{ ID: "A1EC36741FEF681F4A77B8F6032AD081100EE5ECB4CC76AEAC2174BC6B871CFE", Coin: coin.ATOM, From: "cosmos137rrp4p8n0nqcft0mwc62tdnyhhzf80knv5t94", @@ -709,13 +709,13 @@ var unDelegateDst = blockatlas.Tx{ Fee: "5000", Date: 1564624521, Block: 1257037, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.AnyAction{ + Status: types.StatusCompleted, + Type: types.TxAnyAction, + Direction: types.DirectionIncoming, + Meta: types.AnyAction{ Coin: coin.ATOM, - Title: blockatlas.AnyActionUndelegation, - Key: blockatlas.KeyStakeDelegate, + Title: types.AnyActionUndelegation, + Key: types.KeyStakeDelegate, Name: coin.Cosmos().Name, Symbol: coin.Coins[coin.ATOM].Symbol, Decimals: coin.Coins[coin.ATOM].Decimals, @@ -723,7 +723,7 @@ var unDelegateDst = blockatlas.Tx{ }, } -var claimRewardDst2 = blockatlas.Tx{ +var claimRewardDst2 = types.Tx{ ID: "082BA88EC055A7C343A353297EAC104CE87C659E0DDD84621C9AC3C284232800", Coin: coin.ATOM, From: "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46", @@ -731,14 +731,14 @@ var claimRewardDst2 = blockatlas.Tx{ Fee: "0", Date: 1576462863, Block: 54561, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionIncoming, + Status: types.StatusCompleted, + Type: types.TxAnyAction, + Direction: types.DirectionIncoming, Memo: "复投", - Meta: blockatlas.AnyAction{ + Meta: types.AnyAction{ Coin: coin.ATOM, - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, + Title: types.AnyActionClaimRewards, + Key: types.KeyStakeClaimRewards, Name: coin.Cosmos().Name, Symbol: coin.Coins[coin.ATOM].Symbol, Decimals: coin.Coins[coin.ATOM].Decimals, @@ -746,7 +746,7 @@ var claimRewardDst2 = blockatlas.Tx{ }, } -var claimRewardDst1 = blockatlas.Tx{ +var claimRewardDst1 = types.Tx{ ID: "C382DCFDC30E2DA294421DAEAD5862F118592A7B000EE91F6BEF8452A1F525D7", Coin: coin.ATOM, From: "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug", @@ -754,14 +754,14 @@ var claimRewardDst1 = blockatlas.Tx{ Fee: "1000", Date: 1576638273, Block: 79678, - Status: blockatlas.StatusCompleted, - Type: blockatlas.TxAnyAction, - Direction: blockatlas.DirectionIncoming, + Status: types.StatusCompleted, + Type: types.TxAnyAction, + Direction: types.DirectionIncoming, Memo: "", - Meta: blockatlas.AnyAction{ + Meta: types.AnyAction{ Coin: coin.ATOM, - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, + Title: types.AnyActionClaimRewards, + Key: types.KeyStakeClaimRewards, Name: coin.Cosmos().Name, Symbol: coin.Coins[coin.ATOM].Symbol, Decimals: coin.Coins[coin.ATOM].Decimals, @@ -769,7 +769,7 @@ var claimRewardDst1 = blockatlas.Tx{ }, } -var failedTransferDst = blockatlas.Tx{ +var failedTransferDst = types.Tx{ ID: "5E78C65A8C1A6C8239EBBBBF2E42020E6ADBA8037EDEA83BF88E1A9159CF13B8", Coin: coin.ATOM, From: "cosmos1shpfyt7psrff2ux7nznxvj6f7gq59fcqng5mku", @@ -777,10 +777,10 @@ var failedTransferDst = blockatlas.Tx{ Fee: "2000", Date: 1576120902, Block: 5552, - Status: blockatlas.StatusError, - Type: blockatlas.TxTransfer, + Status: types.StatusError, + Type: types.TxTransfer, Memo: "UniCoins registration rewards", - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "100000", Symbol: coin.Cosmos().Symbol, Decimals: 6, @@ -791,7 +791,7 @@ type test struct { name string platform Platform Data string - want blockatlas.Tx + want types.Tx } func TestNormalize(t *testing.T) { diff --git a/platform/nano/client.go b/platform/nano/client.go index 655e6a6ec..550fa723f 100644 --- a/platform/nano/client.go +++ b/platform/nano/client.go @@ -3,8 +3,8 @@ package nano import ( "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/types" ) type Client struct { @@ -12,7 +12,7 @@ type Client struct { } func (c *Client) GetAccountHistory(address string) (history AccountHistory, err error) { - count := strconv.Itoa(blockatlas.TxPerPage) + count := strconv.Itoa(types.TxPerPage) err = c.Post(&history, "", AccountHistoryRequest{Action: "account_history", Account: address, Count: count}) return } diff --git a/platform/nano/transaction.go b/platform/nano/transaction.go index c509b8baf..4b956b133 100644 --- a/platform/nano/transaction.go +++ b/platform/nano/transaction.go @@ -4,11 +4,11 @@ import ( "encoding/json" "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - normalized := make([]blockatlas.Tx, 0) +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { + normalized := make([]types.Tx, 0) history, err := p.client.GetAccountHistory(address) if err != nil { return normalized, err @@ -34,7 +34,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return normalized, nil } -func (p *Platform) Normalize(srcTx *Transaction, account string) (blockatlas.Tx, error) { +func (p *Platform) Normalize(srcTx *Transaction, account string) (types.Tx, error) { var from string var to string @@ -46,20 +46,20 @@ func (p *Platform) Normalize(srcTx *Transaction, account string) (blockatlas.Tx, to = account } - status := blockatlas.StatusCompleted + status := types.StatusCompleted height, err := strconv.ParseUint(srcTx.Height, 10, 64) if err != nil { - return blockatlas.Tx{}, err + return types.Tx{}, err } if height == 0 { - status = blockatlas.StatusPending + status = types.StatusPending } timestamp, err := strconv.ParseInt(srcTx.LocalTimestamp, 10, 64) if err != nil { - return blockatlas.Tx{}, err + return types.Tx{}, err } - tx := blockatlas.Tx{ + tx := types.Tx{ ID: srcTx.Hash, Coin: p.Coin().ID, Date: timestamp, @@ -68,8 +68,8 @@ func (p *Platform) Normalize(srcTx *Transaction, account string) (blockatlas.Tx, Block: height, Status: status, Fee: "0", - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(srcTx.Amount), + Meta: types.Transfer{ + Value: types.Amount(srcTx.Amount), Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, }, diff --git a/platform/nano/transaction_test.go b/platform/nano/transaction_test.go index 84c4ce13f..37d8690ed 100644 --- a/platform/nano/transaction_test.go +++ b/platform/nano/transaction_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) func TestNormalize(t *testing.T) { @@ -16,7 +16,7 @@ func TestNormalize(t *testing.T) { tests := []struct { name string args args - wantTx blockatlas.Tx + wantTx types.Tx }{ { name: "Send", @@ -31,7 +31,7 @@ func TestNormalize(t *testing.T) { }, account: "nano_3ifzdoxn7keh7tn8zuwty1yr8k5pmaxoq6jpp3jidbjbfnz6hyanh89x6rwj", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "455C1A3E14E2A645EE4DFA120820614DE3A9876BA2673D0D38494396F3650227", Coin: 165, Date: 1573006938, @@ -40,8 +40,8 @@ func TestNormalize(t *testing.T) { Block: 4, Status: "completed", Fee: "0", - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("45000000000000000000000000000"), + Meta: types.Transfer{ + Value: types.Amount("45000000000000000000000000000"), Symbol: "NANO", Decimals: 30, }, @@ -60,7 +60,7 @@ func TestNormalize(t *testing.T) { }, account: "nano_3ifzdoxn7keh7tn8zuwty1yr8k5pmaxoq6jpp3jidbjbfnz6hyanh89x6rwj", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "5D6B19DE75D8C1BAF7D91FBDA71AFC5F0FED68D483DEC5A51F0767A2384D0DE2", Coin: 165, Date: 1570862429, @@ -69,8 +69,8 @@ func TestNormalize(t *testing.T) { Block: 1, Status: "completed", Fee: "0", - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("90000000000000000000000000000"), + Meta: types.Transfer{ + Value: types.Amount("90000000000000000000000000000"), Symbol: "NANO", Decimals: 30, }, diff --git a/platform/near/transaction.go b/platform/near/transaction.go index 0f9421868..0f2ed25fd 100644 --- a/platform/near/transaction.go +++ b/platform/near/transaction.go @@ -1,10 +1,8 @@ package near -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - normalized := make([]blockatlas.Tx, 0) +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { + normalized := make([]types.Tx, 0) return normalized, nil } diff --git a/platform/nebulas/transaction.go b/platform/nebulas/transaction.go index dcff7c674..0f0d7899b 100644 --- a/platform/nebulas/transaction.go +++ b/platform/nebulas/transaction.go @@ -1,11 +1,11 @@ package nebulas import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { txs, err := p.client.GetTxs(address, 1) if err != nil { return nil, err @@ -18,43 +18,43 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.GetLatestBlock() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { txs, err := p.client.GetBlockByNumber(num) if err != nil { return nil, err } - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: NormalizeTxs(txs), }, nil } -func NormalizeTxs(txs []Transaction) []blockatlas.Tx { - normalizeTxs := make([]blockatlas.Tx, 0) +func NormalizeTxs(txs []Transaction) []types.Tx { + normalizeTxs := make([]types.Tx, 0) for _, srcTx := range txs { normalizeTxs = append(normalizeTxs, NormalizeTx(srcTx)) } return normalizeTxs } -func NormalizeTx(srcTx Transaction) blockatlas.Tx { - var status = blockatlas.StatusCompleted +func NormalizeTx(srcTx Transaction) types.Tx { + var status = types.StatusCompleted if srcTx.Status == 0 { - status = blockatlas.StatusError + status = types.StatusError } - return blockatlas.Tx{ + return types.Tx{ ID: srcTx.Hash, Coin: coin.NAS, From: srcTx.From.Hash, To: srcTx.To.Hash, - Fee: blockatlas.Amount(srcTx.TxFee), + Fee: types.Amount(srcTx.TxFee), Date: int64(srcTx.Timestamp) / 1000, Block: srcTx.Block.Height, Status: status, Sequence: srcTx.Nonce, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(srcTx.Value), + Meta: types.Transfer{ + Value: types.Amount(srcTx.Value), Symbol: coin.Coins[coin.NAS].Symbol, Decimals: coin.Coins[coin.NAS].Decimals, }, diff --git a/platform/nebulas/transaction_test.go b/platform/nebulas/transaction_test.go index fa38c7e02..92a6e4e31 100644 --- a/platform/nebulas/transaction_test.go +++ b/platform/nebulas/transaction_test.go @@ -4,9 +4,9 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) func TestNormalizeTx(t *testing.T) { @@ -16,14 +16,14 @@ func TestNormalizeTx(t *testing.T) { tests := []struct { name string args args - wantTx blockatlas.Tx + wantTx types.Tx }{ { name: "Test normalize transaction", args: args{ filename: "transfer.json", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "96bd280d60447b7dbcdb3fa76a99856e0422a76304e9d01d0c87e1dfceb6d952", Coin: coin.NAS, From: "n1Yv9xJJcH4UjoJPVDGdUCL2CxK29asFuyV", @@ -32,8 +32,8 @@ func TestNormalizeTx(t *testing.T) { Sequence: 7, Date: 1565213205, Block: 2848548, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Meta: types.Transfer{ Value: "500000000000000000", Symbol: "NAS", Decimals: 18, @@ -44,7 +44,7 @@ func TestNormalizeTx(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var srcTx Transaction - _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &srcTx) gotTx := NormalizeTx(srcTx) if !reflect.DeepEqual(gotTx, tt.wantTx) { t.Errorf("NormalizeTx() gotTx = %v, want %v", gotTx, tt.wantTx) diff --git a/platform/nimiq/block.go b/platform/nimiq/block.go index 819005b7b..a4a49eb58 100644 --- a/platform/nimiq/block.go +++ b/platform/nimiq/block.go @@ -1,14 +1,12 @@ package nimiq -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.CurrentBlockNumber() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { srcBlock, err := p.client.GetBlockByNumber(num) if err != nil { return nil, err @@ -18,8 +16,8 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { } // NormalizeBlock converts a Nimiq block into the generic model -func NormalizeBlock(srcBlock *Block) blockatlas.Block { - return blockatlas.Block{ +func NormalizeBlock(srcBlock *Block) types.Block { + return types.Block{ Number: srcBlock.Number, Txs: NormalizeTxs(srcBlock.Txs), } diff --git a/platform/nimiq/client.go b/platform/nimiq/client.go index 4d91af9ad..7837a2bbe 100644 --- a/platform/nimiq/client.go +++ b/platform/nimiq/client.go @@ -3,8 +3,8 @@ package nimiq import ( "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/types" ) type Client struct { @@ -12,7 +12,7 @@ type Client struct { } func (c *Client) GetTxsOfAddress(address string) (tx []Tx, err error) { - err = c.RpcCall(&tx, "getTransactionsByAddress", []string{address, strconv.Itoa(blockatlas.TxPerPage)}) + err = c.RpcCall(&tx, "getTransactionsByAddress", []string{address, strconv.Itoa(types.TxPerPage)}) return } diff --git a/platform/nimiq/model.go b/platform/nimiq/model.go index 6c8bc1de7..b47c7f9fa 100644 --- a/platform/nimiq/model.go +++ b/platform/nimiq/model.go @@ -2,20 +2,21 @@ package nimiq import ( "encoding/json" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + + "github.com/trustwallet/golibs/types" ) type Tx struct { - Hash string `json:"hash"` - BlockHash string `json:"blockHash"` - BlockNumber uint64 `json:"blockNumber"` - Timestamp json.Number `json:"timestamp"` - Confirmations int `json:"confirmations"` - TxIndex int `json:"transactionIndex"` - FromAddress string `json:"fromAddress"` - ToAddress string `json:"toAddress"` - Value blockatlas.Amount `json:"value"` - Fee blockatlas.Amount `json:"fee"` + Hash string `json:"hash"` + BlockHash string `json:"blockHash"` + BlockNumber uint64 `json:"blockNumber"` + Timestamp json.Number `json:"timestamp"` + Confirmations int `json:"confirmations"` + TxIndex int `json:"transactionIndex"` + FromAddress string `json:"fromAddress"` + ToAddress string `json:"toAddress"` + Value types.Amount `json:"value"` + Fee types.Amount `json:"fee"` } type Block struct { diff --git a/platform/nimiq/transaction.go b/platform/nimiq/transaction.go index 1d99fb63b..2a0e14321 100644 --- a/platform/nimiq/transaction.go +++ b/platform/nimiq/transaction.go @@ -1,13 +1,14 @@ package nimiq import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/coin" "sort" "time" + + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { srcTxs, err := p.client.GetTxsOfAddress(address) if err != nil { return nil, err @@ -16,13 +17,13 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { } // NormalizeTx converts a Nimiq transaction into the generic model -func NormalizeTx(srcTx *Tx) blockatlas.Tx { +func NormalizeTx(srcTx *Tx) types.Tx { date, err := srcTx.Timestamp.Int64() // Pending transaction doesn't have a timestamp, we gonna use the current time if err != nil || len(srcTx.BlockHash) == 0 { date = time.Now().Unix() } - return blockatlas.Tx{ + return types.Tx{ ID: srcTx.Hash, Coin: coin.NIM, Date: date, @@ -30,7 +31,7 @@ func NormalizeTx(srcTx *Tx) blockatlas.Tx { To: srcTx.ToAddress, Fee: srcTx.Fee, Block: srcTx.BlockNumber, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: srcTx.Value, Symbol: coin.Coins[coin.NIM].Symbol, Decimals: coin.Coins[coin.NIM].Decimals, @@ -39,14 +40,14 @@ func NormalizeTx(srcTx *Tx) blockatlas.Tx { } // NormalizeTxs converts multiple Nimiq transactions -func NormalizeTxs(srcTxs []Tx) []blockatlas.Tx { +func NormalizeTxs(srcTxs []Tx) []types.Tx { sort.SliceStable(srcTxs, func(i, j int) bool { return srcTxs[i].BlockNumber > srcTxs[j].BlockNumber }) - if len(srcTxs) > blockatlas.TxPerPage { - srcTxs = srcTxs[:blockatlas.TxPerPage] + if len(srcTxs) > types.TxPerPage { + srcTxs = srcTxs[:types.TxPerPage] } - txs := make([]blockatlas.Tx, len(srcTxs)) + txs := make([]types.Tx, len(srcTxs)) for i, srcTx := range srcTxs { txs[i] = NormalizeTx(&srcTx) } diff --git a/platform/nimiq/transaction_test.go b/platform/nimiq/transaction_test.go index 27f737ef7..8ab42644b 100644 --- a/platform/nimiq/transaction_test.go +++ b/platform/nimiq/transaction_test.go @@ -9,15 +9,15 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( - basicSrc, _ = mock.JsonFromFilePathToString("mocks/" + "tx.json") - pendingSrc, _ = mock.JsonFromFilePathToString("mocks/" + "pending_tx.json") - basicDst = blockatlas.Tx{ + basicSrc, _ = mock.JsonStringFromFilePath("mocks/" + "tx.json") + pendingSrc, _ = mock.JsonStringFromFilePath("mocks/" + "pending_tx.json") + basicDst = types.Tx{ ID: "8b219949f4c1dfe9e7a9cdc5dbbc507e40dc16f44a1a5182ed6125c9a6891a50", Coin: coin.NIM, From: "NQ69 9A4A MB83 HXDQ 4J46 BH5R 4JFF QMA9 C3GN", @@ -25,13 +25,13 @@ var ( Fee: "138", Date: 1538924505, Block: 252575, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "10000000000000", Symbol: "NIM", Decimals: 5, }, } - pendingDst = blockatlas.Tx{ + pendingDst = types.Tx{ ID: "79719d16f3f347cc98c35cd7a9af708cdce97de578b5135c5ae4393fd7920d61", Coin: coin.NIM, From: "NQ74 SJ0Q 49T1 4XQL KABH 1RUC 8DPT 9F0U 9P0B", @@ -39,7 +39,7 @@ var ( Fee: "300", Date: 666666, // special placholder value Block: 0, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "100000", Symbol: "NIM", Decimals: 5, @@ -52,7 +52,7 @@ func TestNormalizeTx1(t *testing.T) { tests := []struct { name string srcTx string - want blockatlas.Tx + want types.Tx }{ {"test transaction", basicSrc, basicDst}, {"test pending transaction", pendingSrc, pendingDst}, @@ -78,7 +78,7 @@ func TestNormalizeTx1(t *testing.T) { func TestNormalizeTxs_Ordering(t *testing.T) { var srcTxs []Tx - _ = mock.ParseJsonFromFilePath("mocks/getTransactionsByAddress_50.json", &srcTxs) + _ = mock.JsonModelFromFilePath("mocks/getTransactionsByAddress_50.json", &srcTxs) txs := NormalizeTxs(srcTxs) if len(txs) != 4 { t.Fatalf("Unexpected count: %d", len(txs)) diff --git a/platform/ontology/block.go b/platform/ontology/block.go index 3d5ed8a5b..482f37442 100644 --- a/platform/ontology/block.go +++ b/platform/ontology/block.go @@ -2,7 +2,8 @@ package ontology import ( "errors" - blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" + + "github.com/trustwallet/golibs/types" ) func (p *Platform) CurrentBlockNumber() (int64, error) { @@ -16,7 +17,7 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { return block.Result.Records[0].Height, nil } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { blockOnt, err := p.client.GetBlockByNumber(num) if err != nil { return nil, err @@ -26,7 +27,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { return nil, err } txs := normalizeTxs(txsRaw, AssetAll) - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil diff --git a/platform/ontology/transaction.go b/platform/ontology/transaction.go index 2ed00fe1e..c8c910962 100644 --- a/platform/ontology/transaction.go +++ b/platform/ontology/transaction.go @@ -4,37 +4,37 @@ import ( "errors" "sync" - blockatlas "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return p.GetTokenTxsByAddress(address, string(AssetONT)) } -func (p *Platform) GetTokenTxsByAddress(address string, token string) (blockatlas.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address string, token string) (types.TxPage, error) { srcTxs, err := p.client.GetTxsOfAddress(address) if err != nil { - return blockatlas.TxPage{}, err + return types.TxPage{}, err } txPage := normalizeTxs(srcTxs.Result, AssetType(token)) return txPage, nil } -func Normalize(srcTx *Tx, assetName AssetType) (tx blockatlas.Tx, ok bool) { +func Normalize(srcTx *Tx, assetName AssetType) (tx types.Tx, ok bool) { if len(srcTx.getTransfers()) < 1 { return tx, false } fee := numbers.DecimalExp(srcTx.Fee, ONGDecimals) - status := blockatlas.StatusCompleted + status := types.StatusCompleted if srcTx.ConfirmFlag != 1 { - status = blockatlas.StatusError + status = types.StatusError } - tx = blockatlas.Tx{ + tx = types.Tx{ ID: srcTx.Hash, Coin: coin.ONT, - Fee: blockatlas.Amount(fee), + Fee: types.Amount(fee), Date: srcTx.Time, Block: srcTx.Height, Status: status, @@ -50,23 +50,23 @@ func Normalize(srcTx *Tx, assetName AssetType) (tx blockatlas.Tx, ok bool) { return tx, false } -func normalizeONT(tx blockatlas.Tx, transfers Transfers) (blockatlas.Tx, bool) { +func normalizeONT(tx types.Tx, transfers Transfers) (types.Tx, bool) { transfer := transfers.getTransfer(AssetONT) if transfer == nil { return tx, false } tx.From = transfer.FromAddress tx.To = transfer.ToAddress - tx.Type = blockatlas.TxTransfer - tx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(transfer.Amount), + tx.Type = types.TxTransfer + tx.Meta = types.Transfer{ + Value: types.Amount(transfer.Amount), Symbol: coin.Ontology().Symbol, Decimals: coin.Ontology().Decimals, } return tx, true } -func normalizeONG(tx blockatlas.Tx, transfers Transfers) (blockatlas.Tx, bool) { +func normalizeONG(tx types.Tx, transfers Transfers) (types.Tx, bool) { transfer := transfers.getTransfer(AssetONG) if transfer == nil { return tx, false @@ -77,26 +77,26 @@ func normalizeONG(tx blockatlas.Tx, transfers Transfers) (blockatlas.Tx, bool) { tx.To = to value := numbers.DecimalExp(transfer.Amount, ONGDecimals) if transfers.isClaimReward() { - tx.Type = blockatlas.TxAnyAction - tx.Meta = blockatlas.AnyAction{ + tx.Type = types.TxAnyAction + tx.Meta = types.AnyAction{ Coin: coin.Ontology().ID, Name: "Ontology Gas", Symbol: "ONG", TokenID: string(AssetONG), Decimals: ONGDecimals, - Value: blockatlas.Amount(value), - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, + Value: types.Amount(value), + Title: types.AnyActionClaimRewards, + Key: types.KeyStakeClaimRewards, } return tx, true } - tx.Type = blockatlas.TxNativeTokenTransfer - tx.Meta = blockatlas.NativeTokenTransfer{ + tx.Type = types.TxNativeTokenTransfer + tx.Meta = types.NativeTokenTransfer{ Name: "Ontology Gas", Symbol: "ONG", TokenID: string(AssetONG), Decimals: ONGDecimals, - Value: blockatlas.Amount(value), + Value: types.Amount(value), From: from, To: to, } @@ -130,8 +130,8 @@ func (p *Platform) getTxDetails(srcTx []Tx) ([]Tx, error) { return txsOntV2, nil } -func normalizeTxs(srcTxs []Tx, assetType AssetType) blockatlas.TxPage { - var txs blockatlas.TxPage +func normalizeTxs(srcTxs []Tx, assetType AssetType) types.TxPage { + var txs types.TxPage for _, srcTx := range srcTxs { transfer := srcTx.getTransfers().getTransfer(assetType) if transfer == nil { diff --git a/platform/ontology/transaction_test.go b/platform/ontology/transaction_test.go index 6f0a5bc68..44c0587ee 100644 --- a/platform/ontology/transaction_test.go +++ b/platform/ontology/transaction_test.go @@ -5,18 +5,18 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( - srcOntTransfer, _ = mock.JsonFromFilePathToString("mocks/transfer_ont.json") - srcOngTransfer, _ = mock.JsonFromFilePathToString("mocks/transfer_ong.json") - srcRewardTransfer, _ = mock.JsonFromFilePathToString("mocks/transfer_rewards.json") - srcFeeTransfer, _ = mock.JsonFromFilePathToString("mocks/transfer_fee.json") + srcOntTransfer, _ = mock.JsonStringFromFilePath("mocks/transfer_ont.json") + srcOngTransfer, _ = mock.JsonStringFromFilePath("mocks/transfer_ong.json") + srcRewardTransfer, _ = mock.JsonStringFromFilePath("mocks/transfer_rewards.json") + srcFeeTransfer, _ = mock.JsonStringFromFilePath("mocks/transfer_fee.json") - dstOntTransfer = blockatlas.Tx{ + dstOntTransfer = types.Tx{ ID: "ea0e5d8e389cb96760887094194ca359ac998b2f607be470a576861b91e2bf52", Coin: coin.ONT, From: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", @@ -24,25 +24,25 @@ var ( Fee: "10000000", Date: 1578903628, Type: "transfer", - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Block: 7571132, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "5", Symbol: "ONT", Decimals: 0, }, } - dstOngTransfer = blockatlas.Tx{ + dstOngTransfer = types.Tx{ ID: "e5946ba02f56e17c3709db2bc91f43f76ee3a359006586024daa5c4ad8c54e78", Coin: coin.ONT, From: "ASLbwuar3ZTbUbLPnCgjGUw2WHhMfvJJtx", To: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", Fee: "10000000", Date: 1577631515, - Type: blockatlas.TxNativeTokenTransfer, - Status: blockatlas.StatusCompleted, + Type: types.TxNativeTokenTransfer, + Status: types.StatusCompleted, Block: 7457989, - Meta: blockatlas.NativeTokenTransfer{ + Meta: types.NativeTokenTransfer{ Name: "Ontology Gas", Symbol: "ONG", TokenID: "ong", @@ -52,25 +52,25 @@ var ( To: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", }, } - dstRewardTransfer = blockatlas.Tx{ + dstRewardTransfer = types.Tx{ ID: "d7554dcdf01f394b9107ff598df6d84e4c3b00ccf1e720b8c09abf085cbe4987", Coin: coin.ONT, From: "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", To: "ARFXGXSmgFT2h9EiS4D5fen127Lzi48Eij", Fee: "10000000", Date: 1579699532, - Type: blockatlas.TxAnyAction, - Status: blockatlas.StatusCompleted, + Type: types.TxAnyAction, + Status: types.StatusCompleted, Block: 7644328, - Meta: blockatlas.AnyAction{ + Meta: types.AnyAction{ Coin: coin.Ontology().ID, Name: "Ontology Gas", Symbol: "ONG", TokenID: "ong", Decimals: 9, Value: "35344040", - Title: blockatlas.AnyActionClaimRewards, - Key: blockatlas.KeyStakeClaimRewards, + Title: types.AnyActionClaimRewards, + Key: types.KeyStakeClaimRewards, }, } ) @@ -80,13 +80,13 @@ func TestNormalize(t *testing.T) { name string Transaction string AssetName AssetType - Expected blockatlas.Tx + Expected types.Tx wantErr bool }{ {"normalize ont", srcOntTransfer, AssetONT, dstOntTransfer, false}, {"normalize ong", srcOngTransfer, AssetONG, dstOngTransfer, false}, {"normalize claim reward", srcRewardTransfer, AssetONG, dstRewardTransfer, false}, - {"normalize fee", srcFeeTransfer, AssetONG, blockatlas.Tx{}, true}, + {"normalize fee", srcFeeTransfer, AssetONG, types.Tx{}, true}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -197,8 +197,8 @@ var ( func TestNormalizeBlock(t *testing.T) { block := normalizeTxs([]Tx{ontTxResp1.Result, ontTxResp2.Result, ontTxResp3.Result}, AssetAll) - var want blockatlas.TxPage - _ = mock.ParseJsonFromFilePath("mocks/block_response.json", &want) + var want types.TxPage + _ = mock.JsonModelFromFilePath("mocks/block_response.json", &want) lhs, _ := json.Marshal(block) rhs, _ := json.Marshal(want) assert.JSONEq(t, string(lhs), string(rhs)) diff --git a/platform/polkadot/block.go b/platform/polkadot/block.go index 7008fe947..bbafaa1f5 100644 --- a/platform/polkadot/block.go +++ b/platform/polkadot/block.go @@ -1,17 +1,15 @@ package polkadot -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.GetCurrentBlock() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { if srcBlock, err := p.client.GetBlockByNumber(num); err == nil { txs := p.NormalizeExtrinsics(srcBlock) - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil diff --git a/platform/polkadot/client.go b/platform/polkadot/client.go index fd931d267..3a0ec2119 100644 --- a/platform/polkadot/client.go +++ b/platform/polkadot/client.go @@ -3,8 +3,8 @@ package polkadot import ( "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/types" ) type Client struct { @@ -13,7 +13,7 @@ type Client struct { func (c *Client) GetTransfersOfAddress(address string) ([]Transfer, error) { var res SubscanResponse - err := c.Post(&res, "scan/transfers", TransfersRequest{Address: address, Row: blockatlas.TxPerPage}) + err := c.Post(&res, "scan/transfers", TransfersRequest{Address: address, Row: types.TxPerPage}) if err != nil { return nil, err } @@ -22,7 +22,7 @@ func (c *Client) GetTransfersOfAddress(address string) ([]Transfer, error) { func (c *Client) GetExtrinsicsOfAddress(address string) ([]Extrinsic, error) { var res SubscanResponse - err := c.Post(&res, "scan/extrinsics", TransfersRequest{Address: address, Row: blockatlas.TxPerPage}) + err := c.Post(&res, "scan/extrinsics", TransfersRequest{Address: address, Row: types.TxPerPage}) if err != nil { return nil, err } diff --git a/platform/polkadot/transaction.go b/platform/polkadot/transaction.go index 76d8f59e7..8e0346198 100644 --- a/platform/polkadot/transaction.go +++ b/platform/polkadot/transaction.go @@ -6,8 +6,7 @@ import ( "strings" "github.com/trustwallet/golibs/numbers" - - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) var NetworkByteMap = map[string]byte{ @@ -15,13 +14,13 @@ var NetworkByteMap = map[string]byte{ "KSM": 0x02, } -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { transfers, err := p.client.GetTransfersOfAddress(address) if err != nil { return nil, err } - txs := make([]blockatlas.Tx, 0) + txs := make([]types.Tx, 0) for _, srcTx := range transfers { tx := p.NormalizeTransfer(&srcTx) txs = append(txs, tx) @@ -30,24 +29,24 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func (p *Platform) NormalizeTransfer(srcTx *Transfer) blockatlas.Tx { +func (p *Platform) NormalizeTransfer(srcTx *Transfer) types.Tx { decimals := p.Coin().Decimals amount := strings.Split(numbers.DecimalExp(srcTx.Amount, int(decimals)), ".")[0] - status := blockatlas.StatusCompleted + status := types.StatusCompleted if !srcTx.Success { - status = blockatlas.StatusError + status = types.StatusError } - result := blockatlas.Tx{ + result := types.Tx{ ID: srcTx.Hash, Coin: p.Coin().ID, Date: int64(srcTx.Timestamp), From: srcTx.From, To: srcTx.To, - Fee: blockatlas.Amount(FeeTransfer), // API will return fee later + Fee: types.Amount(FeeTransfer), // API will return fee later Block: srcTx.BlockNumber, Status: status, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(amount), + Meta: types.Transfer{ + Value: types.Amount(amount), Symbol: p.Coin().Symbol, Decimals: decimals, }, @@ -55,8 +54,8 @@ func (p *Platform) NormalizeTransfer(srcTx *Transfer) blockatlas.Tx { return result } -func (p *Platform) NormalizeExtrinsics(extrinsics []Extrinsic) []blockatlas.Tx { - txs := make([]blockatlas.Tx, 0) +func (p *Platform) NormalizeExtrinsics(extrinsics []Extrinsic) []types.Tx { + txs := make([]types.Tx, 0) for _, srcTx := range extrinsics { tx := p.NormalizeExtrinsic(&srcTx) if tx != nil { @@ -66,7 +65,7 @@ func (p *Platform) NormalizeExtrinsics(extrinsics []Extrinsic) []blockatlas.Tx { return txs } -func (p *Platform) NormalizeExtrinsic(srcTx *Extrinsic) *blockatlas.Tx { +func (p *Platform) NormalizeExtrinsic(srcTx *Extrinsic) *types.Tx { var datas []CallData err := json.Unmarshal([]byte(srcTx.Params), &datas) if err != nil { @@ -88,24 +87,24 @@ func (p *Platform) NormalizeExtrinsic(srcTx *Extrinsic) *blockatlas.Tx { return nil } - status := blockatlas.StatusCompleted + status := types.StatusCompleted if !srcTx.Success { - status = blockatlas.StatusError + status = types.StatusError } - result := blockatlas.Tx{ + result := types.Tx{ ID: srcTx.Hash, Coin: p.Coin().ID, From: srcTx.AccountId, To: to, - Fee: blockatlas.Amount(srcTx.Fee), + Fee: types.Amount(srcTx.Fee), Date: int64(srcTx.Timestamp), Block: srcTx.BlockNumber, Status: status, Sequence: srcTx.Nonce, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(datas[1].Value), + Meta: types.Transfer{ + Value: types.Amount(datas[1].Value), Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, }, diff --git a/platform/polkadot/transaction_test.go b/platform/polkadot/transaction_test.go index 7055ef75e..10195d8bf 100644 --- a/platform/polkadot/transaction_test.go +++ b/platform/polkadot/transaction_test.go @@ -4,8 +4,8 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) func TestNormalizeTransfer(t *testing.T) { @@ -16,7 +16,7 @@ func TestNormalizeTransfer(t *testing.T) { tests := []struct { name string args args - wantTx blockatlas.Tx + wantTx types.Tx }{ { name: "Receive 1", @@ -32,7 +32,7 @@ func TestNormalizeTransfer(t *testing.T) { Success: true, }, }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "0x20cfbba19817e4b7a61e718d269de47e7067a24860fa978c2a8ead4c96a827c4", Coin: 434, Date: 1577176992, @@ -41,8 +41,8 @@ func TestNormalizeTransfer(t *testing.T) { Block: 360298, Status: "completed", Fee: "100000000", - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("10000000000"), + Meta: types.Transfer{ + Value: types.Amount("10000000000"), Symbol: "KSM", Decimals: 12, }, @@ -62,7 +62,7 @@ func TestNormalizeTransfer(t *testing.T) { Success: true, }, }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "0xe0be47f6ce0e62a218f197dd68599989376ee7e951d54c3c6146e2c5c5eacd1f", Coin: 434, Date: 1575525432, @@ -71,8 +71,8 @@ func TestNormalizeTransfer(t *testing.T) { Block: 90672, Status: "completed", Fee: "100000000", - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("210000000000000"), + Meta: types.Transfer{ + Value: types.Amount("210000000000000"), Symbol: "KSM", Decimals: 12, }, @@ -96,7 +96,7 @@ func TestNormalizeExtrinsic(t *testing.T) { tests := []struct { name string args args - wantTx *blockatlas.Tx + wantTx *types.Tx }{ { name: "Transfer KSM", @@ -115,7 +115,7 @@ func TestNormalizeExtrinsic(t *testing.T) { Fee: "100000000", }, }, - wantTx: &blockatlas.Tx{ + wantTx: &types.Tx{ ID: "0x20cfbba19817e4b7a61e718d269de47e7067a24860fa978c2a8ead4c96a827c4", Coin: 434, Date: 1577176992, @@ -125,8 +125,8 @@ func TestNormalizeExtrinsic(t *testing.T) { Block: 360298, Status: "completed", Sequence: 0, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("10000000000"), + Meta: types.Transfer{ + Value: types.Amount("10000000000"), Symbol: "KSM", Decimals: 12, }, @@ -149,7 +149,7 @@ func TestNormalizeExtrinsic(t *testing.T) { Fee: "153000000", }, }, - wantTx: &blockatlas.Tx{ + wantTx: &types.Tx{ ID: "0x17f92e09994e6885007bfdf4a0a5026f667e69ae94547c5c89b03d647541025e", Coin: 354, Date: 1607035338, @@ -159,8 +159,8 @@ func TestNormalizeExtrinsic(t *testing.T) { Block: 2742892, Status: "completed", Sequence: 1, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("16694000000"), + Meta: types.Transfer{ + Value: types.Amount("16694000000"), Symbol: "DOT", Decimals: 10, }, diff --git a/platform/ripple/block.go b/platform/ripple/block.go index 6509272bf..0eecb9162 100644 --- a/platform/ripple/block.go +++ b/platform/ripple/block.go @@ -1,17 +1,15 @@ package ripple -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.GetCurrentBlock() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { if srcBlock, err := p.client.GetBlockByNumber(num); err == nil { txs := NormalizeTxs(srcBlock) - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil diff --git a/platform/ripple/model.go b/platform/ripple/model.go index af5101efb..baa13d1bf 100644 --- a/platform/ripple/model.go +++ b/platform/ripple/model.go @@ -1,8 +1,6 @@ package ripple -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" type TransactionType string type TransactionResult string @@ -30,15 +28,15 @@ type Tx struct { } type Payment struct { - TransactionType TransactionType `json:"TransactionType"` - Flags uint64 `json:"Flags"` - Sequence uint64 `json:"Sequence"` - Fee blockatlas.Amount `json:"Fee"` - SigningPubKey string `json:"SigningPubKey"` - TxnSignature string `json:"TxnSignature"` - Account string `json:"Account"` - Destination string `json:"Destination"` - DestinationTag int64 `json:"DestinationTag,omitempty"` + TransactionType TransactionType `json:"TransactionType"` + Flags uint64 `json:"Flags"` + Sequence uint64 `json:"Sequence"` + Fee types.Amount `json:"Fee"` + SigningPubKey string `json:"SigningPubKey"` + TxnSignature string `json:"TxnSignature"` + Account string `json:"Account"` + Destination string `json:"Destination"` + DestinationTag int64 `json:"DestinationTag,omitempty"` } type Meta struct { diff --git a/platform/ripple/transaction.go b/platform/ripple/transaction.go index e536b1338..a8e5caecb 100644 --- a/platform/ripple/transaction.go +++ b/platform/ripple/transaction.go @@ -1,19 +1,20 @@ package ripple import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/coin" "strconv" "time" + + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { s, err := p.client.GetTxsOfAddress(address) if err != nil { return nil, err } - txs := make([]blockatlas.Tx, 0) + txs := make([]types.Tx, 0) for _, srcTx := range s { tx, ok := NormalizeTx(&srcTx) if !ok { @@ -25,10 +26,10 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func NormalizeTxs(srcTxs []Tx) (txs []blockatlas.Tx) { +func NormalizeTxs(srcTxs []Tx) (txs []types.Tx) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(&srcTx) - if !ok || len(txs) >= blockatlas.TxPerPage { + if !ok || len(txs) >= types.TxPerPage { continue } txs = append(txs, tx) @@ -37,7 +38,7 @@ func NormalizeTxs(srcTxs []Tx) (txs []blockatlas.Tx) { } // Normalize converts a Ripple transaction into the generic model -func NormalizeTx(srcTx *Tx) (blockatlas.Tx, bool) { +func NormalizeTx(srcTx *Tx) (types.Tx, bool) { unix := int64(0) date, err := time.Parse("2006-01-02T15:04:05-07:00", srcTx.Date) if err == nil { @@ -46,19 +47,19 @@ func NormalizeTx(srcTx *Tx) (blockatlas.Tx, bool) { v, vok := srcTx.Meta.DeliveredAmount.(string) if !vok || len(v) == 0 { - return blockatlas.Tx{}, false + return types.Tx{}, false } if srcTx.Payment.TransactionType != transactionPayment { - return blockatlas.Tx{}, false + return types.Tx{}, false } - status := blockatlas.StatusCompleted + status := types.StatusCompleted if srcTx.Meta.TransactionResult != transactionResultSuccess { - status = blockatlas.StatusError + status = types.StatusError } - result := blockatlas.Tx{ + result := types.Tx{ ID: srcTx.Hash, Coin: coin.XRP, Date: unix, @@ -67,8 +68,8 @@ func NormalizeTx(srcTx *Tx) (blockatlas.Tx, bool) { Fee: srcTx.Payment.Fee, Block: srcTx.LedgerIndex, Status: status, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(v), + Meta: types.Transfer{ + Value: types.Amount(v), Symbol: coin.Coins[coin.XRP].Symbol, Decimals: coin.Coins[coin.XRP].Decimals, }, diff --git a/platform/ripple/transaction_test.go b/platform/ripple/transaction_test.go index f34a50a9e..621981b3c 100644 --- a/platform/ripple/transaction_test.go +++ b/platform/ripple/transaction_test.go @@ -4,10 +4,9 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) func TestNormalizeTx(t *testing.T) { @@ -17,7 +16,7 @@ func TestNormalizeTx(t *testing.T) { tests := []struct { name string args args - wantTx blockatlas.Tx + wantTx types.Tx ok bool }{ { @@ -25,7 +24,7 @@ func TestNormalizeTx(t *testing.T) { args: args{ filename: "payment.json", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "40279A3DE51148BD41409DADF29DE8DCCD50F5AEE30840827B2C4C81C4E36505", Coin: coin.XRP, From: "rGSxFjoqmWz54PycrgQBQ5dB6e7TUpMxzq", @@ -34,8 +33,8 @@ func TestNormalizeTx(t *testing.T) { Date: 1512168330, Block: 34698103, Memo: "2500", - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Meta: types.Transfer{ Value: "100000000", Symbol: "XRP", Decimals: 6, @@ -48,7 +47,7 @@ func TestNormalizeTx(t *testing.T) { args: args{ filename: "payment_2.json", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "3D8512E02414EF5A6BC00281D945735E85DED9EF739B1DCA9EABE04D9EEC72C1", Coin: coin.XRP, From: "raz97dHvnyBcnYTbXGYxhV8bGyr1aPrE5w", @@ -57,8 +56,8 @@ func TestNormalizeTx(t *testing.T) { Date: 1565114281, Block: 49163909, Memo: "", - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Meta: types.Transfer{ Value: "3100", Symbol: "XRP", Decimals: 6, @@ -71,7 +70,7 @@ func TestNormalizeTx(t *testing.T) { args: args{ filename: "payment_failed.json", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "B9086F7EB895E943C4DDA9F1B582E6E7DE35F4FB91AD13C50AB74F854DC0EBE0", Coin: coin.XRP, From: "rJb5KsHsDHF1YS5B5DU6QCkH5NsPaKQTcy", @@ -80,8 +79,8 @@ func TestNormalizeTx(t *testing.T) { Date: 1581590872, Block: 53401154, Memo: "", - Status: blockatlas.StatusError, - Meta: blockatlas.Transfer{ + Status: types.StatusError, + Meta: types.Transfer{ Value: "24999750000", Symbol: "XRP", Decimals: 6, @@ -94,7 +93,7 @@ func TestNormalizeTx(t *testing.T) { args: args{ filename: "payment_3.json", }, - wantTx: blockatlas.Tx{}, + wantTx: types.Tx{}, ok: false, }, { @@ -102,14 +101,14 @@ func TestNormalizeTx(t *testing.T) { args: args{ filename: "payment_4.json", }, - wantTx: blockatlas.Tx{}, + wantTx: types.Tx{}, ok: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var srcTx Tx - _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &srcTx) gotTx, err := NormalizeTx(&srcTx) if err != tt.ok { t.Errorf("NormalizeTx() error = %v, ok %v", err, tt.ok) diff --git a/platform/solana/stake.go b/platform/solana/stake.go index 41a8e3686..8ae8114e0 100644 --- a/platform/solana/stake.go +++ b/platform/solana/stake.go @@ -4,11 +4,13 @@ import ( "bytes" "encoding/binary" "fmt" + "strconv" + "github.com/btcsuite/btcutil/base58" log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/assets" - "strconv" + "github.com/trustwallet/golibs/types" ) func arrayOfPubkey(pubkey string) [32]byte { @@ -68,7 +70,7 @@ func normalizeValidator(v VoteAccount, minimumBalance uint64) (validator blockat ID: v.VotePubkey, Details: blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: blockatlas.Amount(minimumAmount), + MinimumAmount: types.Amount(minimumAmount), LockTime: 0, Type: blockatlas.DelegationTypeDelegate, }, diff --git a/platform/solana/stake_test.go b/platform/solana/stake_test.go index 646ea9d65..319f698dd 100644 --- a/platform/solana/stake_test.go +++ b/platform/solana/stake_test.go @@ -6,19 +6,20 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" "github.com/stretchr/testify/assert" ) var ( - currentValidators, _ = mock.JsonFromFilePathToString("mocks/" + "currentValidators.json") + currentValidators, _ = mock.JsonStringFromFilePath("mocks/" + "currentValidators.json") expectedValidators = []blockatlas.Validator{ { Status: true, ID: "2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW", Details: blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: blockatlas.Amount("2282881"), + MinimumAmount: types.Amount("2282881"), LockTime: 0, Type: blockatlas.DelegationTypeDelegate, }, @@ -28,7 +29,7 @@ var ( ID: "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5", Details: blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: blockatlas.Amount("2282881"), + MinimumAmount: types.Amount("2282881"), LockTime: 0, Type: blockatlas.DelegationTypeDelegate, }, diff --git a/platform/solana/transaction.go b/platform/solana/transaction.go index 5338e179d..4262fee7f 100644 --- a/platform/solana/transaction.go +++ b/platform/solana/transaction.go @@ -4,11 +4,11 @@ import ( "errors" "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - results := make(blockatlas.TxPage, 0) +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { + results := make(types.TxPage, 0) txs, err := p.client.GetTransactions(address) if err != nil { return results, err @@ -21,7 +21,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return results, nil } -func (p *Platform) NormalizeTx(tx ConfirmedTransaction, address string) (normalized blockatlas.Tx, err error) { +func (p *Platform) NormalizeTx(tx ConfirmedTransaction, address string) (normalized types.Tx, err error) { // only check first instruction if len(tx.Transaction.Message.Instructions) != 1 || len(tx.Transaction.Signatures) != 1 { @@ -36,30 +36,30 @@ func (p *Platform) NormalizeTx(tx ConfirmedTransaction, address string) (normali // tx direction from := instruction.Parsed.Info.Source - direction := blockatlas.DirectionIncoming + direction := types.DirectionIncoming if address == from { - direction = blockatlas.DirectionOutgoing + direction = types.DirectionOutgoing } // tx status - status := blockatlas.StatusCompleted + status := types.StatusCompleted if tx.Meta.Err != nil { - status = blockatlas.StatusError + status = types.StatusError } - normalized = blockatlas.Tx{ + normalized = types.Tx{ ID: tx.Transaction.Signatures[0], Coin: p.Coin().ID, From: from, To: instruction.Parsed.Info.Destination, - Fee: blockatlas.Amount(strconv.FormatUint(tx.Meta.Fee, 10)), + Fee: types.Amount(strconv.FormatUint(tx.Meta.Fee, 10)), Date: EstimateTimestamp(tx.Slot), Block: tx.Slot, Status: status, - Type: blockatlas.TxTransfer, + Type: types.TxTransfer, Direction: direction, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(strconv.FormatUint(instruction.Parsed.Info.Lamports, 10)), + Meta: types.Transfer{ + Value: types.Amount(strconv.FormatUint(instruction.Parsed.Info.Lamports, 10)), Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, }, diff --git a/platform/solana/transaction_test.go b/platform/solana/transaction_test.go index c31a1231e..c8c8d421c 100644 --- a/platform/solana/transaction_test.go +++ b/platform/solana/transaction_test.go @@ -14,7 +14,7 @@ import ( ) func TestPlatform_GetTxsByAddress(t *testing.T) { - wanted, err := mock.JsonFromFilePathToString("mocks/GetTxsByAddress.json") + wanted, err := mock.JsonStringFromFilePath("mocks/GetTxsByAddress.json") if err != nil { panic(err) } @@ -36,7 +36,7 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { if err := json.Unmarshal([]byte(requestBody), &r); err == nil { switch r.Method { case "getConfirmedSignaturesForAddress2": - signatures, err := mock.JsonFromFilePathToString("mocks/getConfirmedSignaturesForAddress2.json") + signatures, err := mock.JsonStringFromFilePath("mocks/getConfirmedSignaturesForAddress2.json") if err != nil { panic(err) } @@ -45,7 +45,7 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { } else if err := json.Unmarshal([]byte(requestBody), &rs); err == nil { switch rs[0].Method { case "getConfirmedTransaction": - signatures, err := mock.JsonFromFilePathToString("mocks/getConfirmedTransaction.json") + signatures, err := mock.JsonStringFromFilePath("mocks/getConfirmedTransaction.json") if err != nil { panic(err) } diff --git a/platform/stellar/block.go b/platform/stellar/block.go index 2dcdc94d7..60c40dc75 100644 --- a/platform/stellar/block.go +++ b/platform/stellar/block.go @@ -1,14 +1,12 @@ package stellar -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.CurrentBlockNumber() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { if srcBlock, err := p.client.GetBlockByNumber(num); err == nil { block := p.NormalizeBlock(srcBlock) return &block, nil @@ -16,8 +14,8 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { return nil, err } } -func (p *Platform) NormalizeBlock(block *Block) blockatlas.Block { - return blockatlas.Block{ +func (p *Platform) NormalizeBlock(block *Block) types.Block { + return types.Block{ Number: block.Ledger.Sequence, Txs: p.NormalizePayments(block.Payments), } diff --git a/platform/stellar/transaction.go b/platform/stellar/transaction.go index d431212a1..1ba66a9ab 100644 --- a/platform/stellar/transaction.go +++ b/platform/stellar/transaction.go @@ -3,12 +3,12 @@ package stellar import ( "time" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { payments, err := p.client.GetTxsOfAddress(address) if err != nil { return nil, err @@ -17,8 +17,8 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return p.NormalizePayments(payments), nil } -func (p *Platform) NormalizePayments(payments []Payment) []blockatlas.Tx { - txs := make([]blockatlas.Tx, 0, len(payments)) +func (p *Platform) NormalizePayments(payments []Payment) []types.Tx { + txs := make([]types.Tx, 0, len(payments)) for _, payment := range payments { if tx, ok := Normalize(&payment, p.CoinIndex); ok { txs = append(txs, tx) @@ -28,7 +28,7 @@ func (p *Platform) NormalizePayments(payments []Payment) []blockatlas.Tx { } // Normalize converts a Stellar-based transaction into the generic model -func Normalize(payment *Payment, nativeCoinIndex uint) (tx blockatlas.Tx, ok bool) { +func Normalize(payment *Payment, nativeCoinIndex uint) (tx types.Tx, ok bool) { switch payment.Type { case PaymentType: if payment.AssetType != Native { @@ -58,7 +58,7 @@ func Normalize(payment *Payment, nativeCoinIndex uint) (tx blockatlas.Tx, ok boo if err != nil { return tx, false } - return blockatlas.Tx{ + return types.Tx{ ID: payment.TransactionHash, Coin: nativeCoinIndex, From: from, @@ -67,8 +67,8 @@ func Normalize(payment *Payment, nativeCoinIndex uint) (tx blockatlas.Tx, ok boo Date: date.Unix(), Memo: payment.Transaction.Memo, Block: payment.Transaction.Ledger, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(value), + Meta: types.Transfer{ + Value: types.Amount(value), Symbol: coin.Coins[nativeCoinIndex].Symbol, Decimals: coin.Coins[nativeCoinIndex].Decimals, }, diff --git a/platform/stellar/transaction_test.go b/platform/stellar/transaction_test.go index 3d9c5188a..e3045af39 100644 --- a/platform/stellar/transaction_test.go +++ b/platform/stellar/transaction_test.go @@ -5,16 +5,16 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( - createSrc, _ = mock.JsonFromFilePathToString("mocks/" + "create_tx.json") - transferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer_tx.json") + createSrc, _ = mock.JsonStringFromFilePath("mocks/" + "create_tx.json") + transferSrc, _ = mock.JsonStringFromFilePath("mocks/" + "transfer_tx.json") - createDst = blockatlas.Tx{ + createDst = types.Tx{ ID: "8b96cf3a660b85ef80b5a84c032cacdb93bb139cfe7e929b974ea9eaa0d29141", Coin: coin.XLM, From: "GBEZOC5U4TVH7ZY5N3FLYHTCZSI6VFGTULG7PBITLF5ZEBPJXFT46YZM", @@ -22,14 +22,14 @@ var ( Fee: "100", Date: 1470850220, Block: 0, - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "473269393700000000", Symbol: "XLM", Decimals: 7, }, } - transferDst = blockatlas.Tx{ + transferDst = types.Tx{ ID: "a596dc910bae20b5bbe64aa7aa3f42acbd55769b98307878f5ad095e994bc9cf", Coin: coin.XLM, From: "GDKIJJIKXLOM2NRMPNQZUUYK24ZPVFC6426GZAEP3KUK6KEJLACCWNMX", @@ -38,8 +38,8 @@ var ( Date: 1470857941, Memo: "testing", Block: 123, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1000000000000000"), + Meta: types.Transfer{ + Value: types.Amount("1000000000000000"), Symbol: "XLM", Decimals: 7, }, @@ -49,7 +49,7 @@ var ( type test struct { name string apiResponse string - expected *blockatlas.Tx + expected *types.Tx } func TestNormalize(t *testing.T) { diff --git a/platform/tezos/baker.go b/platform/tezos/baker.go index a45f37590..d2fb19dba 100644 --- a/platform/tezos/baker.go +++ b/platform/tezos/baker.go @@ -9,6 +9,7 @@ import ( "github.com/trustwallet/blockatlas/services/assets" "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) const ( @@ -60,7 +61,7 @@ func NormalizeStakeValidator(baker Baker, assetValidator assets.AssetValidator) Annual: math.Round(baker.EstimatedRoi*10000) / 100, }, LockTime: LockTime, - MinimumAmount: blockatlas.Amount(strconv.FormatUint(amount, 10)), + MinimumAmount: types.Amount(strconv.FormatUint(amount, 10)), Type: blockatlas.DelegationTypeDelegate, }, } diff --git a/platform/tezos/block.go b/platform/tezos/block.go index b8fe9493a..3a0d3b22a 100644 --- a/platform/tezos/block.go +++ b/platform/tezos/block.go @@ -1,21 +1,19 @@ package tezos -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.GetCurrentBlock() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { txTypes := []string{TxTypeTransaction, TxTypeDelegation} srcTxs, err := p.client.GetBlockByNumber(num, txTypes) if err != nil { return nil, err } txs := NormalizeTxs(srcTxs, "") - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil diff --git a/platform/tezos/model.go b/platform/tezos/model.go index c7cf49c55..f14c44714 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) const ( @@ -69,12 +69,12 @@ type ( } ) -func (t *Transaction) Status() blockatlas.Status { +func (t *Transaction) Status() types.Status { switch t.Stat { case TxStatusApplied: - return blockatlas.StatusCompleted + return types.StatusCompleted default: - return blockatlas.StatusError + return types.StatusError } } @@ -86,14 +86,14 @@ func (t *Transaction) ErrorMsg() string { } } -func (t *Transaction) Title(address string) (blockatlas.KeyTitle, bool) { +func (t *Transaction) Title(address string) (types.KeyTitle, bool) { if t.Type == TxTypeDelegation { if address == t.Sender && t.Delegate != "" && t.Receiver == "" { - return blockatlas.AnyActionDelegation, true + return types.AnyActionDelegation, true } if address == t.Sender && t.Delegate == "" && t.Receiver != "" { - return blockatlas.AnyActionUndelegation, true + return types.AnyActionUndelegation, true } } @@ -109,26 +109,26 @@ func (t *Transaction) BlockTimestamp() int64 { return unix } -func (t *Transaction) TransferType() (blockatlas.TransactionType, bool) { +func (t *Transaction) TransferType() (types.TransactionType, bool) { switch t.Type { case TxTypeTransaction: - return blockatlas.TxTransfer, true + return types.TxTransfer, true case TxTypeDelegation: - return blockatlas.TxAnyAction, true + return types.TxAnyAction, true default: return "unsupported type", false } } -func (t *Transaction) Direction(address string) blockatlas.Direction { +func (t *Transaction) Direction(address string) types.Direction { if t.Sender == address && t.Receiver == address { - return blockatlas.DirectionSelf + return types.DirectionSelf } if t.Sender == address && t.Receiver != address { - return blockatlas.DirectionOutgoing + return types.DirectionOutgoing } - return blockatlas.DirectionIncoming + return types.DirectionIncoming } func (t *Transaction) GetReceiver() string { diff --git a/platform/tezos/model_test.go b/platform/tezos/model_test.go index 2add90286..951b70977 100644 --- a/platform/tezos/model_test.go +++ b/platform/tezos/model_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) var ( @@ -16,12 +16,12 @@ func TestTransaction_Status(t *testing.T) { testStatus := []struct { name string in Transaction - out blockatlas.Status + out types.Status }{ - {"Status completed", Transaction{Stat: "applied"}, blockatlas.StatusCompleted}, - {"Status error", Transaction{Stat: "failed"}, blockatlas.StatusError}, - {"Status error", Transaction{Stat: ""}, blockatlas.StatusError}, - {"Status error", Transaction{Stat: "something else"}, blockatlas.StatusError}, + {"Status completed", Transaction{Stat: "applied"}, types.StatusCompleted}, + {"Status error", Transaction{Stat: "failed"}, types.StatusError}, + {"Status error", Transaction{Stat: ""}, types.StatusError}, + {"Status error", Transaction{Stat: "something else"}, types.StatusError}, } for _, tt := range testStatus { @@ -49,10 +49,10 @@ func TestTransaction_Status(t *testing.T) { name string address string in Transaction - out blockatlas.KeyTitle + out types.KeyTitle }{ - {"Delegation title", addr1, Transaction{Sender: addr1, Delegate: addr2, Receiver: "", Type: TxTypeDelegation}, blockatlas.AnyActionDelegation}, - {"Undelegation title", addr1, Transaction{Sender: addr1, Delegate: "", Receiver: addr2, Type: TxTypeDelegation}, blockatlas.AnyActionUndelegation}, + {"Delegation title", addr1, Transaction{Sender: addr1, Delegate: addr2, Receiver: "", Type: TxTypeDelegation}, types.AnyActionDelegation}, + {"Undelegation title", addr1, Transaction{Sender: addr1, Delegate: "", Receiver: addr2, Type: TxTypeDelegation}, types.AnyActionUndelegation}, {"Unsupported title", addr1, Transaction{Sender: addr1, Delegate: addr1, Receiver: addr1}, "unsupported title"}, {"Unsupported title", addr1, Transaction{Sender: addr1, Delegate: addr2, Receiver: addr1}, "unsupported title"}, {"Unsupported title", addr1, Transaction{Sender: addr1, Delegate: addr1, Receiver: addr2}, "unsupported title"}, @@ -83,10 +83,10 @@ func TestTransaction_Status(t *testing.T) { testsTransferType := []struct { name string in Transaction - out blockatlas.TransactionType + out types.TransactionType }{ - {"Type should be transaction", Transaction{Type: "transaction"}, blockatlas.TxTransfer}, - {"Type should be delegation", Transaction{Type: "delegation"}, blockatlas.TxAnyAction}, + {"Type should be transaction", Transaction{Type: "transaction"}, types.TxTransfer}, + {"Type should be delegation", Transaction{Type: "delegation"}, types.TxAnyAction}, {"Type unsupported", Transaction{Type: "bake"}, "unsupported type"}, } @@ -100,12 +100,12 @@ func TestTransaction_Status(t *testing.T) { testsDirection := []struct { name string in Transaction - out blockatlas.Direction + out types.Direction address string }{ - {"Direction self", Transaction{Sender: addr1, Receiver: addr1}, blockatlas.DirectionSelf, addr1}, - {"Direction outgoing", Transaction{Sender: addr1, Receiver: addr2}, blockatlas.DirectionOutgoing, addr1}, - {"Direction incoming", Transaction{Sender: addr2, Receiver: addr1}, blockatlas.DirectionIncoming, addr1}, + {"Direction self", Transaction{Sender: addr1, Receiver: addr1}, types.DirectionSelf, addr1}, + {"Direction outgoing", Transaction{Sender: addr1, Receiver: addr2}, types.DirectionOutgoing, addr1}, + {"Direction incoming", Transaction{Sender: addr2, Receiver: addr1}, types.DirectionIncoming, addr1}, } for _, tt := range testsDirection { @@ -117,7 +117,7 @@ func TestTransaction_Status(t *testing.T) { testsNormalize := []struct { name string in Transaction - out blockatlas.Tx + out types.Tx address string }{ {"Normalize XTZ transfer", tezosTransfer, normalizedTezosTransfer, addr1}, diff --git a/platform/tezos/stake_test.go b/platform/tezos/stake_test.go index d18c7db9d..008929406 100644 --- a/platform/tezos/stake_test.go +++ b/platform/tezos/stake_test.go @@ -11,19 +11,20 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( - accountSrc, _ = mock.JsonFromFilePathToString("mocks/" + "account.json") - validatorSrc, _ = mock.JsonFromFilePathToString("mocks/" + "validator.json") - mockedTezosResponse, _ = mock.JsonFromFilePathToString("mocks/" + "delegation_response.json") + accountSrc, _ = mock.JsonStringFromFilePath("mocks/" + "account.json") + validatorSrc, _ = mock.JsonStringFromFilePath("mocks/" + "validator.json") + mockedTezosResponse, _ = mock.JsonStringFromFilePath("mocks/" + "delegation_response.json") validator = blockatlas.Validator{ Status: true, ID: "tz2TSvNTh2epDMhZHrw73nV9piBX7kLZ9K9m", Details: blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: Annual}, - MinimumAmount: blockatlas.Amount("0"), + MinimumAmount: types.Amount("0"), Type: blockatlas.DelegationTypeDelegate, }, } diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index bd548f597..f61a89818 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -1,12 +1,12 @@ package tezos import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { txTypes := []string{TxTypeTransaction, TxTypeDelegation} txs, err := p.client.GetTxsOfAddress(address, txTypes) if err != nil { @@ -16,7 +16,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return NormalizeTxs(txs.Transactions, address), nil } -func NormalizeTxs(srcTxs []Transaction, address string) (txs []blockatlas.Tx) { +func NormalizeTxs(srcTxs []Transaction, address string) (txs []types.Tx) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(srcTx, address) if !ok { @@ -28,19 +28,19 @@ func NormalizeTxs(srcTxs []Transaction, address string) (txs []blockatlas.Tx) { } // NormalizeTx converts a Tezos transaction into the generic model -func NormalizeTx(srcTx Transaction, address string) (blockatlas.Tx, bool) { - var tx blockatlas.Tx +func NormalizeTx(srcTx Transaction, address string) (types.Tx, bool) { + var tx types.Tx tt, ok := srcTx.TransferType() if !ok { return tx, false } - tx = blockatlas.Tx{ + tx = types.Tx{ Block: srcTx.Height, Coin: coin.XTZ, Date: srcTx.BlockTimestamp(), Error: srcTx.ErrorMsg(), - Fee: blockatlas.Amount(numbers.DecimalExp(numbers.Float64toString(srcTx.Fee), 6)), + Fee: types.Amount(numbers.DecimalExp(numbers.Float64toString(srcTx.Fee), 6)), From: srcTx.Sender, ID: srcTx.Hash, Status: srcTx.Status(), @@ -51,30 +51,30 @@ func NormalizeTx(srcTx Transaction, address string) (blockatlas.Tx, bool) { tx.Direction = srcTx.Direction(address) } - value := blockatlas.Amount(numbers.DecimalExp(numbers.Float64toString(srcTx.Volume), 6)) + value := types.Amount(numbers.DecimalExp(numbers.Float64toString(srcTx.Volume), 6)) switch tt { - case blockatlas.TxAnyAction: + case types.TxAnyAction: title, ok := srcTx.Title(address) if !ok { return tx, false } - tx.Meta = blockatlas.AnyAction{ + tx.Meta = types.AnyAction{ Coin: coin.Tezos().ID, Title: title, - Key: blockatlas.KeyStakeDelegate, + Key: types.KeyStakeDelegate, Name: coin.Tezos().Name, Symbol: coin.Tezos().Symbol, Decimals: coin.Tezos().Decimals, Value: value, } - case blockatlas.TxTransfer: - tx.Meta = blockatlas.Transfer{ + case types.TxTransfer: + tx.Meta = types.Transfer{ Value: value, Symbol: coin.Coins[coin.XTZ].Symbol, Decimals: coin.Coins[coin.XTZ].Decimals, } default: - return blockatlas.Tx{}, false + return types.Tx{}, false } return tx, true } diff --git a/platform/tezos/transaction_test.go b/platform/tezos/transaction_test.go index 43a4b4017..d986741dc 100644 --- a/platform/tezos/transaction_test.go +++ b/platform/tezos/transaction_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) var ( @@ -22,7 +22,7 @@ var ( //Errors: {{ID: "proto.005-PsBabyM1.delegate.unchanged"}, Kind: "temporary"} } - normalizedTezosTransfer = blockatlas.Tx{ + normalizedTezosTransfer = types.Tx{ ID: "op6GzJ3a3wGJTu4KuD2WNCVJdwEU5WKDXV6EyjsBYMEjyPQWozF", Coin: 1729, From: addr1, @@ -34,7 +34,7 @@ var ( Type: "transfer", Direction: "yourself", Memo: "", - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "1", Symbol: "XTZ", Decimals: 6, @@ -46,7 +46,7 @@ func TestNormalizeTx(t *testing.T) { tests := []struct { name string in Transaction - out blockatlas.Tx + out types.Tx address string }{ {"Normalize XTZ transfer", tezosTransfer, normalizedTezosTransfer, addr1}, diff --git a/platform/theta/transaction.go b/platform/theta/transaction.go index 7d4d55b5d..57c182770 100644 --- a/platform/theta/transaction.go +++ b/platform/theta/transaction.go @@ -2,24 +2,25 @@ package theta import ( "fmt" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/coin" "strconv" "strings" + + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { // Endpoint supports queries without token query parameter return p.GetTokenTxsByAddress(address, "") } -func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, error) { trx, err := p.client.FetchAddressTransactions(address) if err != nil { return nil, err } - var txs []blockatlas.Tx + var txs []types.Tx for _, tr := range trx { if tr.Type != SendTransaction { continue @@ -34,14 +35,14 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPag return txs, nil } -func Normalize(trx *Tx, address, token string) (tx blockatlas.Tx, ok bool) { +func Normalize(trx *Tx, address, token string) (tx types.Tx, ok bool) { time, _ := strconv.ParseInt(trx.Timestamp, 10, 64) block, _ := strconv.ParseUint(trx.BlockHeight, 10, 64) - tx = blockatlas.Tx{ + tx = types.Tx{ ID: trx.Hash, Coin: coin.THETA, - Fee: blockatlas.Amount(trx.Data.Fee.Tfuelwei), + Fee: types.Amount(trx.Data.Fee.Tfuelwei), Date: time, Block: block, Sequence: block, @@ -68,9 +69,9 @@ func Normalize(trx *Tx, address, token string) (tx blockatlas.Tx, ok bool) { tx.To = output.Address tx.Sequence = sequence tx.Direction = direction - tx.Type = blockatlas.TxTransfer - tx.Meta = blockatlas.Transfer{ - Value: blockatlas.Amount(output.Coins.Thetawei), + tx.Type = types.TxTransfer + tx.Meta = types.Transfer{ + Value: types.Amount(output.Coins.Thetawei), Symbol: coin.Coins[coin.THETA].Symbol, Decimals: coin.Coins[coin.THETA].Decimals, } @@ -91,13 +92,13 @@ func Normalize(trx *Tx, address, token string) (tx blockatlas.Tx, ok bool) { tx.To = to tx.Sequence = sequence tx.Direction = direction - tx.Type = blockatlas.TxNativeTokenTransfer - tx.Meta = blockatlas.NativeTokenTransfer{ + tx.Type = types.TxNativeTokenTransfer + tx.Meta = types.NativeTokenTransfer{ Name: "Theta Fuel", Symbol: "TFUEL", TokenID: "tfuel", Decimals: 18, - Value: blockatlas.Amount(output.Coins.Tfuelwei), + Value: types.Amount(output.Coins.Tfuelwei), From: from, To: to, } @@ -109,18 +110,18 @@ func Normalize(trx *Tx, address, token string) (tx blockatlas.Tx, ok bool) { } // Get transaction direction -func getDirection(a string, inputs Input, outputs Output) (dir blockatlas.Direction, err error) { +func getDirection(a string, inputs Input, outputs Output) (dir types.Direction, err error) { address := strings.ToLower(a) inAddr := inputs.Address outAddr := outputs.Address switch { case inAddr == address && outAddr == address: - return blockatlas.DirectionSelf, nil + return types.DirectionSelf, nil case inAddr == address && outAddr != address: - return blockatlas.DirectionOutgoing, nil + return types.DirectionOutgoing, nil case inAddr != address && outAddr == address: - return blockatlas.DirectionIncoming, nil + return types.DirectionIncoming, nil } return "", fmt.Errorf("direction unknown") diff --git a/platform/theta/transaction_test.go b/platform/theta/transaction_test.go index f6fb7ba22..77fdc0b34 100644 --- a/platform/theta/transaction_test.go +++ b/platform/theta/transaction_test.go @@ -5,16 +5,16 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( - thetaTransfer, _ = mock.JsonFromFilePathToString("mocks/" + "theta_transfer.json") - tFuelTransfer, _ = mock.JsonFromFilePathToString("mocks/" + "tfuel_transfer.json") + thetaTransfer, _ = mock.JsonStringFromFilePath("mocks/" + "theta_transfer.json") + tFuelTransfer, _ = mock.JsonStringFromFilePath("mocks/" + "tfuel_transfer.json") - expectedTransferTrx = blockatlas.Tx{ + expectedTransferTrx = types.Tx{ ID: "0x413d8423fd1e6df99fc57f425dfd58c791c877657b364c62c15905ade5114a70", Coin: coin.THETA, From: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", @@ -22,30 +22,30 @@ var ( Fee: "2000000000000", Date: 1557136781, Type: "transfer", - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Block: 700321, Sequence: 43, - Direction: blockatlas.DirectionOutgoing, - Meta: blockatlas.Transfer{ + Direction: types.DirectionOutgoing, + Meta: types.Transfer{ Value: "4000000000000000000", Symbol: "THETA", Decimals: 18, }, } - expectedTfuelTransfer = blockatlas.Tx{ + expectedTfuelTransfer = types.Tx{ ID: "0x558cb5ec877119c2c84a677277efb5b3059adb830c6e74971b3dbe93221b7132", Coin: coin.THETA, From: "0x0a7d7141e9abe5d1c760cffa1129c6eb94f35a2a", To: "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", Fee: "2000000000000", Date: 1557136821, - Type: blockatlas.TxNativeTokenTransfer, - Status: blockatlas.StatusCompleted, + Type: types.TxNativeTokenTransfer, + Status: types.StatusCompleted, Sequence: 44, Block: 700327, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.NativeTokenTransfer{ + Direction: types.DirectionIncoming, + Meta: types.NativeTokenTransfer{ Name: "Theta Fuel", Symbol: "TFUEL", TokenID: "tfuel", @@ -62,7 +62,7 @@ func TestNormalize(t *testing.T) { Transaction string Address string Token string - Expected blockatlas.Tx + Expected types.Tx }{ {thetaTransfer, "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", "", expectedTransferTrx}, {tFuelTransfer, "0xac0eeb6ee3e32e2c74e14ac74155063e4f4f981f", "tfuel", expectedTfuelTransfer}, @@ -76,7 +76,7 @@ func TestNormalize(t *testing.T) { t.Fatal("THETA: Can't unmarshal transaction", tErr) } - var readyTx blockatlas.Tx + var readyTx types.Tx normTx, ok := Normalize(&trx, test.Address, test.Token) if !ok { t.Fatal("THETA: Can't normalize transaction", readyTx) @@ -104,13 +104,13 @@ func TestGetDirection(t *testing.T) { tests := []struct { address string - expectedDir blockatlas.Direction + expectedDir types.Direction trxInput Input trxOutput Output }{ - {address: addrChecksum, expectedDir: blockatlas.DirectionSelf, trxInput: Input{Address: addr}, trxOutput: Output{Address: addr}}, - {address: addrChecksum, expectedDir: blockatlas.DirectionOutgoing, trxInput: Input{Address: addr}, trxOutput: Output{Address: otherAddr}}, - {address: addrChecksum, expectedDir: blockatlas.DirectionIncoming, trxInput: Input{Address: otherAddr}, trxOutput: Output{Address: addr}}, + {address: addrChecksum, expectedDir: types.DirectionSelf, trxInput: Input{Address: addr}, trxOutput: Output{Address: addr}}, + {address: addrChecksum, expectedDir: types.DirectionOutgoing, trxInput: Input{Address: addr}, trxOutput: Output{Address: otherAddr}}, + {address: addrChecksum, expectedDir: types.DirectionIncoming, trxInput: Input{Address: otherAddr}, trxOutput: Output{Address: addr}}, } for _, test := range tests { diff --git a/platform/tron/block.go b/platform/tron/block.go index 66c2e853f..80995e2a2 100644 --- a/platform/tron/block.go +++ b/platform/tron/block.go @@ -2,38 +2,39 @@ package tron import ( "encoding/hex" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "sync" + + "github.com/trustwallet/golibs/types" ) func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.fetchCurrentBlockNumber() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { block, err := p.client.fetchBlockByNumber(num) if err != nil { return nil, err } txsChan := p.NormalizeBlockTxs(block.Txs) - txs := make(blockatlas.TxPage, 0) + txs := make(types.TxPage, 0) for cTxs := range txsChan { txs = append(txs, cTxs) } - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil } -func (p *Platform) NormalizeBlockTxs(srcTxs []Tx) chan blockatlas.Tx { - txChan := make(chan blockatlas.Tx, len(srcTxs)) +func (p *Platform) NormalizeBlockTxs(srcTxs []Tx) chan types.Tx { + txChan := make(chan types.Tx, len(srcTxs)) var wg sync.WaitGroup for _, srcTx := range srcTxs { wg.Add(1) - go func(s Tx, c chan blockatlas.Tx) { + go func(s Tx, c chan types.Tx) { defer wg.Done() p.NormalizeBlockChannel(s, c) }(srcTx, txChan) @@ -43,7 +44,7 @@ func (p *Platform) NormalizeBlockTxs(srcTxs []Tx) chan blockatlas.Tx { return txChan } -func (p *Platform) NormalizeBlockChannel(srcTx Tx, txChan chan blockatlas.Tx) { +func (p *Platform) NormalizeBlockChannel(srcTx Tx, txChan chan types.Tx) { if len(srcTx.Data.Contracts) == 0 { return } diff --git a/platform/tron/model.go b/platform/tron/model.go index d512f9971..03d3a88a0 100644 --- a/platform/tron/model.go +++ b/platform/tron/model.go @@ -1,8 +1,6 @@ package tron -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" type ( BlockRequest struct { @@ -54,10 +52,10 @@ type ( } TransferValue struct { - Amount blockatlas.Amount `json:"amount"` - OwnerAddress string `json:"owner_address"` - ToAddress string `json:"to_address"` - AssetName string `json:"asset_name,omitempty"` + Amount types.Amount `json:"amount"` + OwnerAddress string `json:"owner_address"` + ToAddress string `json:"to_address"` + AssetName string `json:"asset_name,omitempty"` } Account struct { diff --git a/platform/tron/stake.go b/platform/tron/stake.go index d4ae50aef..54e276de7 100644 --- a/platform/tron/stake.go +++ b/platform/tron/stake.go @@ -7,6 +7,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/assets" + "github.com/trustwallet/golibs/types" ) const Annual = 0.74 @@ -45,7 +46,7 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { func getDetails() blockatlas.StakingDetails { return blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: Annual}, - MinimumAmount: blockatlas.Amount("1000000"), + MinimumAmount: types.Amount("1000000"), LockTime: 259200, Type: blockatlas.DelegationTypeDelegate, } diff --git a/platform/tron/stake_test.go b/platform/tron/stake_test.go index ef041700c..26c0e1246 100644 --- a/platform/tron/stake_test.go +++ b/platform/tron/stake_test.go @@ -10,8 +10,8 @@ import ( ) var ( - delegationsSrc1, _ = mock.JsonFromFilePathToString("mocks/" + "delegation.json") - delegationsSrc2, _ = mock.JsonFromFilePathToString("mocks/" + "delegation_2.json") + delegationsSrc1, _ = mock.JsonStringFromFilePath("mocks/" + "delegation.json") + delegationsSrc2, _ = mock.JsonStringFromFilePath("mocks/" + "delegation_2.json") validator1 = blockatlas.StakeValidator{ ID: "TGzz8gjYiYRqpfmDwnLxfgPuLVNmpCswVp", diff --git a/platform/tron/token.go b/platform/tron/token.go index 423d6494d..8d6bd6084 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -6,17 +6,16 @@ import ( "sync" log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "github.com/trustwallet/golibs/tokentype" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, error) { +func (p *Platform) GetTokenListByAddress(address string) (types.TokenPage, error) { tokens, err := p.client.fetchAccount(address) if err != nil { return nil, err } - tokenPage := make(blockatlas.TokenPage, 0) + tokenPage := make(types.TokenPage, 0) if len(tokens.Data) == 0 { return tokenPage, nil } @@ -37,25 +36,25 @@ func (p *Platform) GetTokenListByAddress(address string) (blockatlas.TokenPage, } for _, t := range trc20Tokens { - tokenPage = append(tokenPage, blockatlas.Token{ + tokenPage = append(tokenPage, types.Token{ Name: t.Name, Symbol: strings.ToUpper(t.Symbol), Decimals: uint(t.Decimals), TokenID: t.ContractAddress, Coin: coin.Tron().ID, - Type: tokentype.TRC20, + Type: types.TRC20, }) } return tokenPage, nil } -func (p *Platform) getTokens(ids []string) chan blockatlas.Token { - tkChan := make(chan blockatlas.Token, len(ids)) +func (p *Platform) getTokens(ids []string) chan types.Token { + tkChan := make(chan types.Token, len(ids)) var wg sync.WaitGroup for _, id := range ids { wg.Add(1) - go func(i string, c chan blockatlas.Token) { + go func(i string, c chan types.Token) { defer wg.Done() _ = p.getTokensChannel(i, c) }(id, tkChan) @@ -65,7 +64,7 @@ func (p *Platform) getTokens(ids []string) chan blockatlas.Token { return tkChan } -func (p *Platform) getTokensChannel(id string, tkChan chan blockatlas.Token) error { +func (p *Platform) getTokensChannel(id string, tkChan chan types.Token) error { info, err := p.client.fetchTokenInfo(id) if err != nil || len(info.Data) == 0 { return err @@ -75,13 +74,13 @@ func (p *Platform) getTokensChannel(id string, tkChan chan blockatlas.Token) err return nil } -func NormalizeToken(info AssetInfo) blockatlas.Token { - return blockatlas.Token{ +func NormalizeToken(info AssetInfo) types.Token { + return types.Token{ Name: info.Name, Symbol: strings.ToUpper(info.Symbol), TokenID: strconv.Itoa(int(info.ID)), Coin: coin.TRX, Decimals: info.Decimals, - Type: tokentype.TRC10, + Type: types.TRC10, } } diff --git a/platform/tron/token_test.go b/platform/tron/token_test.go index 7ebae9726..3246267c8 100644 --- a/platform/tron/token_test.go +++ b/platform/tron/token_test.go @@ -9,12 +9,12 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( - tokenDst = blockatlas.Token{ + tokenDst = types.Token{ Name: "Test", Symbol: "TST", Decimals: 8, @@ -46,15 +46,15 @@ func TestPlatform_GetTokenListByAddress(t *testing.T) { } var ( - wantedTokensResponse, _ = mock.JsonFromFilePathToString("mocks/tokens/tokens_response.json") - mockedAccountsTransactionsResponse, _ = mock.JsonFromFilePathToString("mocks/tokens/accounts_txs_response.json") - mockedTrc20Response, _ = mock.JsonFromFilePathToString("mocks/tokens/trc20_response.json") - mockedTransactionsTrc20Response, _ = mock.JsonFromFilePathToString("mocks/tokens/txs_trc20_response.json") - mockedTransactionsEmptyResponse, _ = mock.JsonFromFilePathToString("mocks/tokens/txs_empty_response.json") - mockedAsset1000542Response, _ = mock.JsonFromFilePathToString("mocks/tokens/asset_1000542_response.json") - mockedAsset1000567Response, _ = mock.JsonFromFilePathToString("mocks/tokens/asset_1000567_response.json") - mockedAssetTR7NHResponse, _ = mock.JsonFromFilePathToString("mocks/tokens/asset_tr7nh_response.json") - mockedAccountsResponse, _ = mock.JsonFromFilePathToString("mocks/tokens/accounts_response.json") + wantedTokensResponse, _ = mock.JsonStringFromFilePath("mocks/tokens/tokens_response.json") + mockedAccountsTransactionsResponse, _ = mock.JsonStringFromFilePath("mocks/tokens/accounts_txs_response.json") + mockedTrc20Response, _ = mock.JsonStringFromFilePath("mocks/tokens/trc20_response.json") + mockedTransactionsTrc20Response, _ = mock.JsonStringFromFilePath("mocks/tokens/txs_trc20_response.json") + mockedTransactionsEmptyResponse, _ = mock.JsonStringFromFilePath("mocks/tokens/txs_empty_response.json") + mockedAsset1000542Response, _ = mock.JsonStringFromFilePath("mocks/tokens/asset_1000542_response.json") + mockedAsset1000567Response, _ = mock.JsonStringFromFilePath("mocks/tokens/asset_1000567_response.json") + mockedAssetTR7NHResponse, _ = mock.JsonStringFromFilePath("mocks/tokens/asset_tr7nh_response.json") + mockedAccountsResponse, _ = mock.JsonStringFromFilePath("mocks/tokens/accounts_response.json") ) func createMockedAPI() http.Handler { diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index f69fba527..af8eb104f 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -6,18 +6,17 @@ import ( "strings" log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" - "github.com/trustwallet/golibs/tokentype" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { Txs, err := p.client.fetchTxsOfAddress(address, "") if err != nil && len(Txs) == 0 { return nil, err } - txs := make(blockatlas.TxPage, 0) + txs := make(types.TxPage, 0) for _, srcTx := range Txs { tx, err := normalize(srcTx) if err != nil { @@ -34,40 +33,40 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, error) { unknownTokenType := errors.New("unknownTokenType") tokenType := getTokenType(token) switch tokenType { - case tokentype.TRC10: + case types.TRC10: txs, err := p.fetchTransactionsForTRC10Tokens(address, token) if err != nil { return nil, err } return txs, nil - case tokentype.TRC20: + case types.TRC20: trc20Transactions, err := p.client.fetchTRC20Transactions(address) if err != nil { return nil, err } - return blockatlas.TxPage(normalizeTRC20Transactions(trc20Transactions)), nil + return types.TxPage(normalizeTRC20Transactions(trc20Transactions)), nil default: return nil, unknownTokenType } } -func getTokenType(token string) tokentype.Type { +func getTokenType(token string) types.TokenType { _, err := strconv.Atoi(token) if err != nil { - return tokentype.TRC20 + return types.TRC20 } else { - return tokentype.TRC10 + return types.TRC10 } } -func addTokenMeta(tx *blockatlas.Tx, srcTx Tx, tokenInfo AssetInfo) { +func addTokenMeta(tx *types.Tx, srcTx Tx, tokenInfo AssetInfo) { transfer := srcTx.Data.Contracts[0].Parameter.Value - tx.Meta = blockatlas.TokenTransfer{ + tx.Meta = types.TokenTransfer{ Name: tokenInfo.Name, Symbol: strings.ToUpper(tokenInfo.Symbol), TokenID: strconv.Itoa(int(tokenInfo.ID)), @@ -78,8 +77,8 @@ func addTokenMeta(tx *blockatlas.Tx, srcTx Tx, tokenInfo AssetInfo) { } } -func (p *Platform) fetchTransactionsForTRC10Tokens(address, token string) (blockatlas.TxPage, error) { - txs := make(blockatlas.TxPage, 0) +func (p *Platform) fetchTransactionsForTRC10Tokens(address, token string) (types.TxPage, error) { + txs := make(types.TxPage, 0) tokenTxs, err := p.client.fetchTxsOfAddress(address, token) if err != nil { @@ -105,10 +104,10 @@ func (p *Platform) fetchTransactionsForTRC10Tokens(address, token string) (block return txs, nil } -func normalizeTRC20Transactions(transactions TRC20Transactions) blockatlas.Txs { - txs := make(blockatlas.Txs, 0, len(transactions.Data)) +func normalizeTRC20Transactions(transactions TRC20Transactions) types.Txs { + txs := make(types.Txs, 0, len(transactions.Data)) for _, rawTx := range transactions.Data { - tx := blockatlas.Tx{ + tx := types.Tx{ ID: rawTx.TransactionID, Coin: coin.TRX, Date: rawTx.BlockTimestamp / 1000, @@ -116,13 +115,13 @@ func normalizeTRC20Transactions(transactions TRC20Transactions) blockatlas.Txs { To: rawTx.To, Fee: "0", Block: 0, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.TokenTransfer{ + Status: types.StatusCompleted, + Meta: types.TokenTransfer{ Name: rawTx.TokenInfo.Name, Symbol: rawTx.TokenInfo.Symbol, TokenID: rawTx.TokenInfo.Address, Decimals: uint(rawTx.TokenInfo.Decimals), - Value: blockatlas.Amount(rawTx.Value), + Value: types.Amount(rawTx.Value), From: rawTx.From, To: rawTx.To, }, @@ -132,7 +131,7 @@ func normalizeTRC20Transactions(transactions TRC20Transactions) blockatlas.Txs { return txs } -func normalize(srcTx Tx) (*blockatlas.Tx, error) { +func normalize(srcTx Tx) (*types.Tx, error) { if len(srcTx.Data.Contracts) == 0 { return nil, errors.New("no contracts") } @@ -152,7 +151,7 @@ func normalize(srcTx Tx) (*blockatlas.Tx, error) { return nil, err } - return &blockatlas.Tx{ + return &types.Tx{ ID: srcTx.ID, Coin: coin.TRX, Date: srcTx.BlockTime / 1000, @@ -160,8 +159,8 @@ func normalize(srcTx Tx) (*blockatlas.Tx, error) { To: to, Fee: "0", Block: 0, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Meta: types.Transfer{ Value: transfer.Amount, Symbol: coin.Coins[coin.TRX].Symbol, Decimals: coin.Coins[coin.TRX].Decimals, diff --git a/platform/tron/transaction_test.go b/platform/tron/transaction_test.go index 556ff753a..fccd80bd4 100644 --- a/platform/tron/transaction_test.go +++ b/platform/tron/transaction_test.go @@ -6,19 +6,18 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" - "github.com/trustwallet/golibs/tokentype" + "github.com/trustwallet/golibs/types" ) var ( - transferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "transfer.json") - tokenTransferSrc, _ = mock.JsonFromFilePathToString("mocks/" + "token_transfer.json") - wantedTransactionsWithToken, _ = mock.JsonFromFilePathToString("mocks/" + "token_txs_response.json") - wantedTransactionsOnly, _ = mock.JsonFromFilePathToString("mocks/" + "txs_response.json") + transferSrc, _ = mock.JsonStringFromFilePath("mocks/" + "transfer.json") + tokenTransferSrc, _ = mock.JsonStringFromFilePath("mocks/" + "token_transfer.json") + wantedTransactionsWithToken, _ = mock.JsonStringFromFilePath("mocks/" + "token_txs_response.json") + wantedTransactionsOnly, _ = mock.JsonStringFromFilePath("mocks/" + "txs_response.json") - transferDst = blockatlas.Tx{ + transferDst = types.Tx{ ID: "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df", Coin: coin.TRX, From: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", @@ -26,15 +25,15 @@ var ( Fee: "0", // TODO Date: 1564797900, Block: 0, // TODO - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ + Status: types.StatusCompleted, + Meta: types.Transfer{ Value: "100666888000000", Symbol: "TRX", Decimals: 6, }, } - tokenTransferDst = blockatlas.Tx{ + tokenTransferDst = types.Tx{ ID: "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df", Coin: coin.TRX, From: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", @@ -42,8 +41,8 @@ var ( Fee: "0", // TODO Date: 1564797900, Block: 0, // TODO - Status: blockatlas.StatusCompleted, - Meta: blockatlas.TokenTransfer{ + Status: types.StatusCompleted, + Meta: types.TokenTransfer{ Name: "BitTorrent", Symbol: "BTT", TokenID: "1002000", @@ -60,7 +59,7 @@ var ( type test struct { name string apiResponse string - expected *blockatlas.Tx + expected *types.Tx } func TestNormalizeTokenTransfer(t *testing.T) { @@ -132,10 +131,10 @@ func Test_getTokenType(t *testing.T) { tests := []struct { name string token string - want tokentype.Type + want types.TokenType }{ - {"default trc20", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", tokentype.TRC20}, - {"default trc10", "1002001", tokentype.TRC10}, + {"default trc20", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", types.TRC20}, + {"default trc10", "1002001", types.TRC10}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/platform/vechain/block.go b/platform/vechain/block.go index 6566aa5ca..ac8b4f237 100644 --- a/platform/vechain/block.go +++ b/platform/vechain/block.go @@ -1,24 +1,22 @@ package vechain -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { return p.client.GetCurrentBlock() } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { block, err := p.client.GetBlockByNumber(num) if err != nil { return nil, err } cTxs := p.getTransactionsByIDs(block.Transactions) - txs := make(blockatlas.TxPage, 0) + txs := make(types.TxPage, 0) for t := range cTxs { txs = append(txs, t...) } - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 6d11df8fd..5e7e9a09b 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -9,9 +9,10 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/address" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, error) { if token != gasTokenAddress { return nil, nil } @@ -29,19 +30,19 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (blockatlas.TxPag } cTxs := p.getTransactionsByIDs(eventsIDs) - txs := make(blockatlas.TxPage, 0) + txs := make(types.TxPage, 0) for t := range cTxs { txs = append(txs, t...) } return txs, nil } -func (p *Platform) getTransactionsByIDs(ids []string) chan blockatlas.TxPage { - txChan := make(chan blockatlas.TxPage, len(ids)) +func (p *Platform) getTransactionsByIDs(ids []string) chan types.TxPage { + txChan := make(chan types.TxPage, len(ids)) var wg sync.WaitGroup for _, id := range ids { wg.Add(1) - go func(i string, c chan blockatlas.TxPage) { + go func(i string, c chan types.TxPage) { defer wg.Done() err := p.getTransactionChannel(i, c) if err != nil { @@ -54,7 +55,7 @@ func (p *Platform) getTransactionsByIDs(ids []string) chan blockatlas.TxPage { return txChan } -func (p *Platform) getTransactionChannel(id string, txChan chan blockatlas.TxPage) error { +func (p *Platform) getTransactionChannel(id string, txChan chan types.TxPage) error { srcTx, err := p.client.GetTransactionByID(id) if err != nil { return err @@ -73,8 +74,8 @@ func (p *Platform) getTransactionChannel(id string, txChan chan blockatlas.TxPag return nil } -func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (blockatlas.TxPage, error) { - txs := make(blockatlas.TxPage, 0) +func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types.TxPage, error) { + txs := make(types.TxPage, 0) fee, err := numbers.HexToDecimal(receipt.Paid) if err != nil { @@ -97,22 +98,22 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (block return txs, errors.New("NormalizeBlockTransaction: srcTx.Clauses not found: " + srcTx.Id) } - txs = append(txs, blockatlas.Tx{ + txs = append(txs, types.Tx{ ID: srcTx.Id, Coin: p.Coin().ID, From: originSender, To: to, - Fee: blockatlas.Amount(fee), + Fee: types.Amount(fee), Date: srcTx.Meta.BlockTimestamp, - Type: blockatlas.TxTokenTransfer, + Type: types.TxTokenTransfer, Block: srcTx.Meta.BlockNumber, - Status: blockatlas.StatusError, + Status: types.StatusError, }) return txs, nil } if receipt.Outputs == nil || len(receipt.Outputs) == 0 { - return blockatlas.TxPage{}, errors.New("NormalizeBlockTransaction: receipt.Outputs not found: " + srcTx.Id) + return types.TxPage{}, errors.New("NormalizeBlockTransaction: receipt.Outputs not found: " + srcTx.Id) } for _, output := range receipt.Outputs { @@ -143,22 +144,22 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (block continue } - txs = append(txs, blockatlas.Tx{ + txs = append(txs, types.Tx{ ID: srcTx.Id, Coin: p.Coin().ID, From: originSender, To: originReceiver, - Fee: blockatlas.Amount(fee), + Fee: types.Amount(fee), Date: srcTx.Meta.BlockTimestamp, - Type: blockatlas.TxTokenTransfer, + Type: types.TxTokenTransfer, Block: srcTx.Meta.BlockNumber, - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Direction: direction, - Meta: blockatlas.TokenTransfer{ + Meta: types.TokenTransfer{ // the only supported Token on VeChain is its Gas token Name: gasTokenName, TokenID: originReceiver, - Value: blockatlas.Amount(value), + Value: types.Amount(value), Symbol: gasTokenSymbol, Decimals: gasTokenDecimals, From: originSender, @@ -169,7 +170,7 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (block return txs, nil } -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { headBlock, err := p.CurrentBlockNumber() if err != nil { return nil, err @@ -179,7 +180,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return nil, err } - txs := make(blockatlas.TxPage, 0) + txs := make(types.TxPage, 0) for _, t := range transfers { trxId, err := p.client.GetTransactionByID(t.Meta.TxId) if err != nil { @@ -194,7 +195,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func (p *Platform) NormalizeTransaction(srcTx LogTransfer, trxId Tx, addr string) (tx blockatlas.Tx, err error) { +func (p *Platform) NormalizeTransaction(srcTx LogTransfer, trxId Tx, addr string) (tx types.Tx, err error) { value, err := numbers.HexToDecimal(srcTx.Amount) if err != nil { return @@ -216,22 +217,22 @@ func (p *Platform) NormalizeTransaction(srcTx LogTransfer, trxId Tx, addr string directory, err := getTransferDirectory(sender, recipient, addrChecksum) if err != nil { - return blockatlas.Tx{}, err + return types.Tx{}, err } - return blockatlas.Tx{ + return types.Tx{ ID: srcTx.Meta.TxId, Coin: p.Coin().ID, From: sender, To: recipient, - Fee: blockatlas.Amount(fee), + Fee: types.Amount(fee), Date: srcTx.Meta.BlockTimestamp, - Type: blockatlas.TxTransfer, + Type: types.TxTransfer, Block: srcTx.Meta.BlockNumber, Direction: directory, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(value), + Status: types.StatusCompleted, + Meta: types.Transfer{ + Value: types.Amount(value), Symbol: p.Coin().Symbol, Decimals: p.Coin().Decimals, }, @@ -252,28 +253,28 @@ func getRecipientAddress(hex string) string { return "0x" + hex[len(hex)-40:] } -func getTokenTransactionDirectory(originSender, topicsFrom, topicsTo string) (dir blockatlas.Direction, err error) { +func getTokenTransactionDirectory(originSender, topicsFrom, topicsTo string) (dir types.Direction, err error) { if originSender == topicsFrom && originSender == topicsTo { - return blockatlas.DirectionSelf, nil + return types.DirectionSelf, nil } if originSender == topicsFrom && originSender != topicsTo { - return blockatlas.DirectionIncoming, nil + return types.DirectionIncoming, nil } if originSender == topicsTo && originSender != topicsFrom { - return blockatlas.DirectionOutgoing, nil + return types.DirectionOutgoing, nil } return "", errors.New("Unknown direction") } -func getTransferDirectory(sender, recipient, addr string) (dir blockatlas.Direction, err error) { +func getTransferDirectory(sender, recipient, addr string) (dir types.Direction, err error) { if sender == addr && recipient == addr { - return blockatlas.DirectionSelf, nil + return types.DirectionSelf, nil } if sender == addr && recipient != addr { - return blockatlas.DirectionOutgoing, nil + return types.DirectionOutgoing, nil } if recipient == addr && sender != addr { - return blockatlas.DirectionIncoming, nil + return types.DirectionIncoming, nil } return "", errors.New("Unknown direction") } diff --git a/platform/vechain/transaction_test.go b/platform/vechain/transaction_test.go index 29275e343..3c250832c 100644 --- a/platform/vechain/transaction_test.go +++ b/platform/vechain/transaction_test.go @@ -5,18 +5,18 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( - transferSrc, _ = mock.JsonFromFilePathToString("mocks/transfer.json") - trxId, _ = mock.JsonFromFilePathToString("mocks/tx_id.json") - transferLogSrc, _ = mock.JsonFromFilePathToString("mocks/transfer_log.json") - trxReceipt, _ = mock.JsonFromFilePathToString("mocks/transfer_receipt.json") - revertedTx, _ = mock.JsonFromFilePathToString("mocks/reverted_tx.json") - revertedReceipt, _ = mock.JsonFromFilePathToString("mocks/reverted_receipt.json") + transferSrc, _ = mock.JsonStringFromFilePath("mocks/transfer.json") + trxId, _ = mock.JsonStringFromFilePath("mocks/tx_id.json") + transferLogSrc, _ = mock.JsonStringFromFilePath("mocks/transfer_log.json") + trxReceipt, _ = mock.JsonStringFromFilePath("mocks/transfer_receipt.json") + revertedTx, _ = mock.JsonStringFromFilePath("mocks/reverted_tx.json") + revertedReceipt, _ = mock.JsonStringFromFilePath("mocks/reverted_receipt.json") ) func TestNormalizeTransaction(t *testing.T) { @@ -25,21 +25,21 @@ func TestNormalizeTransaction(t *testing.T) { addr string txData string txId string - expected blockatlas.Tx + expected types.Tx }{ - {"Test normalize VET transfer transaction", "0xb5e883349e68ab59307d1604555ac890fac47128", transferSrc, trxId, blockatlas.Tx{ + {"Test normalize VET transfer transaction", "0xb5e883349e68ab59307d1604555ac890fac47128", transferSrc, trxId, types.Tx{ ID: "0x702edd54bd4e13e0012798cc8b2dfa52f7150173945103d203fae26b8e3d2ed7", Coin: coin.VET, From: "0xB5e883349e68aB59307d1604555AC890fAC47128", To: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", Date: 1574410670, - Type: blockatlas.TxTransfer, - Fee: blockatlas.Amount("21000"), - Status: blockatlas.StatusCompleted, + Type: types.TxTransfer, + Fee: types.Amount("21000"), + Status: types.StatusCompleted, Block: 4395940, - Direction: blockatlas.DirectionOutgoing, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("1347000000000000000"), + Direction: types.DirectionOutgoing, + Meta: types.Transfer{ + Value: types.Amount("1347000000000000000"), Decimals: 18, Symbol: "VET", }, @@ -71,41 +71,41 @@ func TestNormalizeTokenTransaction(t *testing.T) { name string txData string txReceipt string - expected blockatlas.TxPage + expected types.TxPage }{ - {"Normalize VIP180 token transfer", transferLogSrc, trxReceipt, blockatlas.TxPage{ + {"Normalize VIP180 token transfer", transferLogSrc, trxReceipt, types.TxPage{ { ID: "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", Coin: coin.VET, From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", To: "0x0000000000000000000000000000456E65726779", Date: 1574278180, - Type: blockatlas.TxTokenTransfer, - Fee: blockatlas.Amount("36582000000000000000"), - Status: blockatlas.StatusCompleted, + Type: types.TxTokenTransfer, + Fee: types.Amount("36582000000000000000"), + Status: types.StatusCompleted, Block: 4382764, - Direction: blockatlas.DirectionIncoming, - Meta: blockatlas.TokenTransfer{ + Direction: types.DirectionIncoming, + Meta: types.TokenTransfer{ Name: gasTokenName, Symbol: gasTokenSymbol, TokenID: "0x0000000000000000000000000000456E65726779", From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", To: "0xB5e883349e68aB59307d1604555AC890fAC47128", - Value: blockatlas.Amount("68000000000000000000"), + Value: types.Amount("68000000000000000000"), Decimals: 18, }, }, }}, - {"Normalize reverted token transfer", revertedTx, revertedReceipt, blockatlas.TxPage{ + {"Normalize reverted token transfer", revertedTx, revertedReceipt, types.TxPage{ { ID: "0x7fae32a743e42eaec54642e2a5742a185299f5b4bedaf12c60f65705661de932", Coin: coin.VET, From: "0x7cFFB7632252Bae3766734d61F148f0Ea78Fc08C", To: "0xf8e1fAa0367298b55F57Ed17F7a2FF3F5F1D1628", Date: 1610326580, - Type: blockatlas.TxTokenTransfer, - Fee: blockatlas.Amount("82618000000000000000"), - Status: blockatlas.StatusError, + Type: types.TxTokenTransfer, + Fee: types.Amount("82618000000000000000"), + Status: types.StatusError, Block: 7982675, }, }}, @@ -182,12 +182,12 @@ func Test_getTokenTransactionDirectory(t *testing.T) { originSender string topicsFrom string topicsTo string - expected blockatlas.Direction + expected types.Direction expectErr bool }{ - {"Self direction", addr1, addr1, addr1, blockatlas.DirectionSelf, false}, - {"In direction", addr1, addr1, addr2, blockatlas.DirectionIncoming, false}, - {"Out direction", addr1, addr2, addr1, blockatlas.DirectionOutgoing, false}, + {"Self direction", addr1, addr1, addr1, types.DirectionSelf, false}, + {"In direction", addr1, addr1, addr2, types.DirectionIncoming, false}, + {"Out direction", addr1, addr2, addr1, types.DirectionOutgoing, false}, {"Unknown direction", addr1, addr2, addr2, "", true}, } @@ -210,13 +210,13 @@ func Test_getTransferDirectory(t *testing.T) { sender string recipient string address string - expected blockatlas.Direction + expected types.Direction expectErr bool }{ - {"Self direction for addr1", addr1, addr1, addr1, blockatlas.DirectionSelf, false}, - {"Self direction for addr2", addr2, addr2, addr2, blockatlas.DirectionSelf, false}, - {"Out direction", addr1, addr2, addr1, blockatlas.DirectionOutgoing, false}, - {"In direction", addr1, addr2, addr2, blockatlas.DirectionIncoming, false}, + {"Self direction for addr1", addr1, addr1, addr1, types.DirectionSelf, false}, + {"Self direction for addr2", addr2, addr2, addr2, types.DirectionSelf, false}, + {"Out direction", addr1, addr2, addr1, types.DirectionOutgoing, false}, + {"In direction", addr1, addr2, addr2, types.DirectionIncoming, false}, } for _, tt := range tests { diff --git a/platform/waves/block.go b/platform/waves/block.go index 4d7d9d9d1..7edfad969 100644 --- a/platform/waves/block.go +++ b/platform/waves/block.go @@ -1,8 +1,6 @@ package waves -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" func (p *Platform) CurrentBlockNumber() (int64, error) { currentBlock, err := p.client.GetCurrentBlock() @@ -12,14 +10,14 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { return currentBlock.Height, nil } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { srcTxs, err := p.client.GetBlockByNumber(num) if err != nil { return nil, err } txs := NormalizeTxs(srcTxs.Transactions) - return &blockatlas.Block{ + return &types.Block{ Number: num, Txs: txs, }, nil diff --git a/platform/waves/transaction.go b/platform/waves/transaction.go index 4ec70a2ad..7ea630b64 100644 --- a/platform/waves/transaction.go +++ b/platform/waves/transaction.go @@ -1,13 +1,13 @@ package waves import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "strconv" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { addressTxs, err := p.client.GetTxs(address, 25) if err != nil { return nil, err @@ -18,10 +18,10 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return txs, nil } -func NormalizeTxs(srcTxs []Transaction) (txs []blockatlas.Tx) { +func NormalizeTxs(srcTxs []Transaction) (txs []types.Tx) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(&srcTx) - if !ok || len(txs) >= blockatlas.TxPerPage { + if !ok || len(txs) >= types.TxPerPage { continue } txs = append(txs, tx) @@ -29,22 +29,22 @@ func NormalizeTxs(srcTxs []Transaction) (txs []blockatlas.Tx) { return } -func NormalizeTx(srcTx *Transaction) (tx blockatlas.Tx, ok bool) { - var result blockatlas.Tx +func NormalizeTx(srcTx *Transaction) (tx types.Tx, ok bool) { + var result types.Tx if srcTx.Type == 4 && len(srcTx.AssetId) == 0 { - result = blockatlas.Tx{ + result = types.Tx{ ID: srcTx.Id, Coin: coin.WAVES, From: srcTx.Sender, To: srcTx.Recipient, - Fee: blockatlas.Amount(strconv.Itoa(int(srcTx.Fee))), + Fee: types.Amount(strconv.Itoa(int(srcTx.Fee))), Date: int64(srcTx.Timestamp) / 1000, Block: srcTx.Block, Memo: srcTx.Attachment, - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(strconv.Itoa(int(srcTx.Amount))), + Status: types.StatusCompleted, + Meta: types.Transfer{ + Value: types.Amount(strconv.Itoa(int(srcTx.Amount))), Symbol: coin.Coins[coin.WAVES].Symbol, Decimals: coin.Coins[coin.WAVES].Decimals, }, diff --git a/platform/waves/transaction_test.go b/platform/waves/transaction_test.go index 95ad5b909..9aa4f876b 100644 --- a/platform/waves/transaction_test.go +++ b/platform/waves/transaction_test.go @@ -5,15 +5,15 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) var ( - transferV1, _ = mock.JsonFromFilePathToString("mocks/" + "transfer.json") - differentTxs, _ = mock.JsonFromFilePathToString("mocks/" + "different_txs.json") + transferV1, _ = mock.JsonStringFromFilePath("mocks/" + "transfer.json") + differentTxs, _ = mock.JsonStringFromFilePath("mocks/" + "different_txs.json") - transferV1Obj = blockatlas.Tx{ + transferV1Obj = types.Tx{ ID: "7QoQc9qMUBCfY4QV35mgBsT8eTXybvGkM2HTumtAvBUL", Coin: 5741564, From: "3PLrCnhKyX5iFbGDxbqqMvea5VAqxMcinPW", @@ -21,16 +21,16 @@ var ( Fee: "100000", Date: 1561048131, Block: 1580410, - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Memo: "", - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("9481600000"), + Meta: types.Transfer{ + Value: types.Amount("9481600000"), Symbol: "WAVES", Decimals: 8, }, } - differentTxsObj = blockatlas.Tx{ + differentTxsObj = types.Tx{ ID: "52GG9U2e6foYRKp5vAzsTQ86aDAABfRJ7synz7ohBp19", Coin: 5741564, From: "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", @@ -39,9 +39,9 @@ var ( Date: 1479313236, Block: 7782, Memo: "string", - Status: blockatlas.StatusCompleted, - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount("100000"), + Status: types.StatusCompleted, + Meta: types.Transfer{ + Value: types.Amount("100000"), Symbol: "WAVES", Decimals: 8, }, @@ -51,13 +51,13 @@ var ( type txParseTest struct { name string apiResponse string - expected *blockatlas.Tx + expected *types.Tx } type txFilterTest struct { name string apiResponse string - expected blockatlas.Tx + expected types.Tx } func TestNormalize(t *testing.T) { @@ -103,7 +103,7 @@ func testFilterTxs(t *testing.T, _test *txFilterTest) { t.Error(err) return } - var res blockatlas.Tx + var res types.Tx for _, tx := range txs[0] { if tx.Type == 4 { n, ok := NormalizeTx(&tx) diff --git a/platform/zilliqa/block.go b/platform/zilliqa/block.go index 4180c65d1..91022a759 100644 --- a/platform/zilliqa/block.go +++ b/platform/zilliqa/block.go @@ -3,7 +3,7 @@ package zilliqa import ( "strconv" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" ) func (p *Platform) CurrentBlockNumber() (int64, error) { @@ -19,8 +19,8 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { return block, nil } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - var normalized []blockatlas.Tx +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { + var normalized []types.Tx txs, err := p.rpcClient.GetTxInBlock(num) if err != nil { return nil, err @@ -31,7 +31,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { normalized = append(normalized, tx) } - block := blockatlas.Block{ + block := types.Block{ Number: num, Txs: normalized, } diff --git a/platform/zilliqa/transaction.go b/platform/zilliqa/transaction.go index 9cd195a73..1ed5407d1 100644 --- a/platform/zilliqa/transaction.go +++ b/platform/zilliqa/transaction.go @@ -1,12 +1,12 @@ package zilliqa import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { - var normalized []blockatlas.Tx +func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { + var normalized []types.Tx txs, err := p.client.GetTxsOfAddress(address) if err != nil { @@ -15,7 +15,7 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { for _, srcTx := range txs { tx := Normalize(&srcTx) - if len(normalized) >= blockatlas.TxPerPage { + if len(normalized) >= types.TxPerPage { break } normalized = append(normalized, tx) @@ -24,25 +24,25 @@ func (p *Platform) GetTxsByAddress(address string) (blockatlas.TxPage, error) { return normalized, nil } -func Normalize(srcTx *Tx) (tx blockatlas.Tx) { - tx = blockatlas.Tx{ +func Normalize(srcTx *Tx) (tx types.Tx) { + tx = types.Tx{ ID: srcTx.Hash, Coin: coin.ZIL, Date: srcTx.Timestamp / 1000, From: srcTx.From, To: srcTx.To, - Fee: blockatlas.Amount(srcTx.Fee), + Fee: types.Amount(srcTx.Fee), Block: srcTx.BlockHeight, - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Sequence: srcTx.NonceValue(), - Meta: blockatlas.Transfer{ - Value: blockatlas.Amount(srcTx.Value), + Meta: types.Transfer{ + Value: types.Amount(srcTx.Value), Symbol: coin.Coins[coin.ZIL].Symbol, Decimals: coin.Coins[coin.ZIL].Decimals, }, } if !srcTx.ReceiptSuccess { - tx.Status = blockatlas.StatusError + tx.Status = types.StatusError } return tx } diff --git a/platform/zilliqa/transaction_test.go b/platform/zilliqa/transaction_test.go index 7980da449..cb52d33de 100644 --- a/platform/zilliqa/transaction_test.go +++ b/platform/zilliqa/transaction_test.go @@ -4,10 +4,9 @@ import ( "reflect" "testing" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" ) func TestNormalizeTx(t *testing.T) { @@ -17,7 +16,7 @@ func TestNormalizeTx(t *testing.T) { tests := []struct { name string args args - wantTx blockatlas.Tx + wantTx types.Tx wantErr bool }{ { @@ -25,7 +24,7 @@ func TestNormalizeTx(t *testing.T) { args: args{ filename: "transfer.json", }, - wantTx: blockatlas.Tx{ + wantTx: types.Tx{ ID: "0xd44413c79e7518152f3b05ef1edff8ef59afd06119b16d09c8bc72e94fed7843", Coin: coin.ZIL, From: "0x88af5ba10796d9091d6893eed4db23ef0bbbca37", @@ -33,10 +32,10 @@ func TestNormalizeTx(t *testing.T) { Fee: "1000000000", Date: 1557889788, Block: 104282, - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Sequence: 3, Memo: "", - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "7997000000000", Symbol: "ZIL", Decimals: 12, @@ -47,7 +46,7 @@ func TestNormalizeTx(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var srcTx Tx - _ = mock.ParseJsonFromFilePath("mocks/"+tt.args.filename, &srcTx) + _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &srcTx) gotTx := Normalize(&srcTx) if !reflect.DeepEqual(gotTx, tt.wantTx) { t.Errorf("NormalizeTx() gotTx = %v, want %v", gotTx, tt.wantTx) diff --git a/services/assets/validator.go b/services/assets/validator.go index 29ba46989..1863eca51 100644 --- a/services/assets/validator.go +++ b/services/assets/validator.go @@ -6,6 +6,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" ) func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) { @@ -49,7 +50,7 @@ func normalizeValidators(assetsValidators AssetValidators, rpcValidators []block func normalizeValidator(rpcValidator blockatlas.Validator, assetValidator AssetValidator, coin coin.Coin) blockatlas.StakeValidator { details := rpcValidator.Details - details.MinimumAmount = blockatlas.Amount(numbers.Float64toString(assetValidator.Staking.MinDelegation)) + details.MinimumAmount = types.Amount(numbers.Float64toString(assetValidator.Staking.MinDelegation)) details.Reward.Annual = calculateAnnual(details.Reward.Annual, assetValidator.Payout.Commission) return blockatlas.StakeValidator{ diff --git a/services/assets/validator_test.go b/services/assets/validator_test.go index 7b4f72f1a..733204e68 100644 --- a/services/assets/validator_test.go +++ b/services/assets/validator_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) var ( @@ -84,7 +85,7 @@ var ( Website: "https://stake.fish/", }, Details: blockatlas.StakingDetails{ - MinimumAmount: blockatlas.Amount("10"), + MinimumAmount: types.Amount("10"), }, } @@ -97,7 +98,7 @@ var ( Website: "https://tw.com", }, Details: blockatlas.StakingDetails{ - MinimumAmount: blockatlas.Amount("0"), + MinimumAmount: types.Amount("0"), }, } @@ -110,7 +111,7 @@ var ( Website: "https://tw.com", }, Details: blockatlas.StakingDetails{ - MinimumAmount: blockatlas.Amount("0"), + MinimumAmount: types.Amount("0"), }, } @@ -123,7 +124,7 @@ var ( Website: "https://tw.com", }, Details: blockatlas.StakingDetails{ - MinimumAmount: blockatlas.Amount("0"), + MinimumAmount: types.Amount("0"), }, } ) diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index 5e62c25dd..e61ddbdef 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -4,14 +4,14 @@ import ( "encoding/json" "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/types" log "github.com/sirupsen/logrus" "github.com/streadway/amqp" - "github.com/trustwallet/blockatlas/pkg/blockatlas" ) -func GetTransactionsFromDelivery(delivery amqp.Delivery, service string) (blockatlas.Txs, error) { - var transactions blockatlas.Txs +func GetTransactionsFromDelivery(delivery amqp.Delivery, service string) (types.Txs, error) { + var transactions types.Txs if err := json.Unmarshal(delivery.Body, &transactions); err != nil { return nil, err diff --git a/services/notifier/models.go b/services/notifier/models.go index 65748e0b7..c3d479483 100644 --- a/services/notifier/models.go +++ b/services/notifier/models.go @@ -1,15 +1,13 @@ package notifier -import ( - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) +import "github.com/trustwallet/golibs/types" type TransactionNotification struct { - Action blockatlas.TransactionType `json:"action"` - Result blockatlas.Tx `json:"result"` + Action types.TransactionType `json:"action"` + Result types.Tx `json:"result"` } -func buildNotificationsByAddress(address string, txs blockatlas.Txs) []TransactionNotification { +func buildNotificationsByAddress(address string, txs types.Txs) []TransactionNotification { transactionsByAddress := toUniqueTransactions(findTransactionsByAddress(txs, address)) result := make([]TransactionNotification, 0, len(transactionsByAddress)) @@ -34,9 +32,9 @@ func ToUniqueAddresses(addresses []string) []string { return list } -func toUniqueTransactions(txs []blockatlas.Tx) []blockatlas.Tx { +func toUniqueTransactions(txs []types.Tx) []types.Tx { keys := make(map[string]bool) - var list []blockatlas.Tx + var list []types.Tx for _, entry := range txs { key := entry.ID + string(entry.Direction) if _, value := keys[key]; !value { @@ -47,8 +45,8 @@ func toUniqueTransactions(txs []blockatlas.Tx) []blockatlas.Tx { return list } -func findTransactionsByAddress(txs blockatlas.Txs, address string) []blockatlas.Tx { - result := make([]blockatlas.Tx, 0) +func findTransactionsByAddress(txs types.Txs, address string) []types.Tx { + result := make([]types.Tx, 0) for _, tx := range txs { if containsAddress(tx, address) { result = append(result, tx) @@ -57,7 +55,7 @@ func findTransactionsByAddress(txs blockatlas.Txs, address string) []blockatlas. return result } -func containsAddress(tx blockatlas.Tx, address string) bool { +func containsAddress(tx types.Tx, address string) bool { allAddresses := tx.GetAddresses() txAddresses := ToUniqueAddresses(allAddresses) for _, a := range txAddresses { diff --git a/services/notifier/models_test.go b/services/notifier/models_test.go index b1aa6279b..ba1e106de 100644 --- a/services/notifier/models_test.go +++ b/services/notifier/models_test.go @@ -5,12 +5,12 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) var ( - nativeTokenTransfer = blockatlas.Tx{ + nativeTokenTransfer = types.Tx{ ID: "95CF63FAA27579A9B6AF84EF8B2DFEAC29627479E9C98E7F5AE4535E213FA4C9", Coin: coin.BNB, From: "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", @@ -18,9 +18,9 @@ var ( Fee: "125000", Date: 1555117625, Block: 7928667, - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Memo: "test", - Meta: blockatlas.NativeTokenTransfer{ + Meta: types.NativeTokenTransfer{ TokenID: "YLC-D8B", Symbol: "YLC", Value: "210572645", @@ -29,7 +29,7 @@ var ( To: "tbnb12hlquylu78cjylk5zshxpdj6hf3t0tahwjt3ex", }, } - tokenTransfer = blockatlas.Tx{ + tokenTransfer = types.Tx{ ID: "0xbcd1a43e796de4035e5e2991d8db332958e36031d54cb1d3a08d2cb790e338c4", Coin: 60, From: "0x08777CB1e80F45642752662B04886Df2d271E049", @@ -40,7 +40,7 @@ var ( Status: "completed", Sequence: 149, Type: "token_transfer", - Meta: blockatlas.TokenTransfer{ + Meta: types.TokenTransfer{ Name: "Kyber Network Crystal", Symbol: "KNC", TokenID: "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", @@ -50,7 +50,7 @@ var ( To: "0x38d45371993eEc84f38FEDf93C646aA2D2267CEA", }, } - transfer = blockatlas.Tx{ + transfer = types.Tx{ ID: "1681EE543FB4B5A628EF21D746E031F018E226D127044A4F9BA5EE2542A44556", Coin: coin.BNB, From: "tbnb1fhr04azuhcj0dulm7ka40y0cqjlafwae9k9gk2", @@ -58,18 +58,18 @@ var ( Fee: "125000", Date: 1555049867, Block: 7761368, - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Memo: "test", - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "10000000000000", Decimals: 8, Symbol: "BNB", }, } - utxoTransfer = blockatlas.Tx{ + utxoTransfer = types.Tx{ ID: "zpub6ruK9k6YGm8BRHWvTiQcrEPnFkuRDJhR7mPYzV2LDvjpLa5CuGgrhCYVZjMGcLcFqv9b2WvsFtY2Gb3xq8NVq8qhk9veozrA2W9QaWtihrC", Coin: coin.BTC, - Inputs: []blockatlas.TxOutput{ + Inputs: []types.TxOutput{ { Address: "bc1qhn03cww757mnnlpkdvvfkaydxqygm86nvkm92h", Value: "1", @@ -83,7 +83,7 @@ var ( Value: "1", }, }, - Outputs: []blockatlas.TxOutput{ + Outputs: []types.TxOutput{ { Address: "bc1qjcslq88cht8llqmh3aqshjx9we9msv386jvxl6", Value: "3", @@ -94,9 +94,9 @@ var ( Fee: "125000", Date: 1555117625, Block: 592400, - Status: blockatlas.StatusCompleted, + Status: types.StatusCompleted, Memo: "test", - Meta: blockatlas.Transfer{ + Meta: types.Transfer{ Value: "10000000000000", Decimals: 8, Symbol: "BNB", @@ -126,21 +126,21 @@ func Test_containsAddress(t *testing.T) { } func Test_findTransactionsByAddress(t *testing.T) { - res := findTransactionsByAddress([]blockatlas.Tx{nativeTokenTransfer, tokenTransfer}, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a") + res := findTransactionsByAddress([]types.Tx{nativeTokenTransfer, tokenTransfer}, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a") sort.Slice(res, func(i, j int) bool { return res[i].ID < res[j].ID }) - assert.Equal(t, []blockatlas.Tx{nativeTokenTransfer}, res) + assert.Equal(t, []types.Tx{nativeTokenTransfer}, res) - resFail := findTransactionsByAddress([]blockatlas.Tx{nativeTokenTransfer, tokenTransfer}, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced") - assert.Equal(t, []blockatlas.Tx{}, resFail) + resFail := findTransactionsByAddress([]types.Tx{nativeTokenTransfer, tokenTransfer}, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced") + assert.Equal(t, []types.Tx{}, resFail) } func Test_buildNotificationsByAddress(t *testing.T) { - notifications := buildNotificationsByAddress("tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", []blockatlas.Tx{nativeTokenTransfer, tokenTransfer}) + notifications := buildNotificationsByAddress("tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", []types.Tx{nativeTokenTransfer, tokenTransfer}) sort.Slice(notifications, func(i, j int) bool { return notifications[i].Action < notifications[j].Action }) - nativeTokenTransfer.Direction = blockatlas.DirectionOutgoing + nativeTokenTransfer.Direction = types.DirectionOutgoing assert.Equal(t, nativeTokenTransfer, notifications[0].Result) } diff --git a/services/parser/parser.go b/services/parser/parser.go index 9d6d6aae2..0326e80f5 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -19,6 +19,7 @@ import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/network/mq" "github.com/trustwallet/golibs/numbers" + "github.com/trustwallet/golibs/types" log "github.com/sirupsen/logrus" ) @@ -33,7 +34,7 @@ type ( Database *db.Instance } - GetBlockByNumber func(num int64) (*blockatlas.Block, error) + GetBlockByNumber func(num int64) (*types.Block, error) stop struct { error @@ -94,11 +95,11 @@ func parse(params Params) { return } - var txs []blockatlas.Tx + var txs []types.Tx for _, block := range blocks { txs = append(txs, block.Txs...) } - txs = blockatlas.TxPage(txs).FilterTransactionsByMemo() + txs = types.TxPage(txs).FilterTransactionsByMemo() err = publish(params, txs) if err != nil { @@ -149,7 +150,7 @@ func GetNextBlocksToParse(lastParsedBlock int64, currentBlock int64, maxBlocks i return nextBlock, endParseBlock + 1, nil } -func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) ([]blockatlas.Block, error) { +func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) ([]types.Block, error) { if lastParsedBlock == currentBlock { log.WithFields(log.Fields{ "current_block": lastParsedBlock, @@ -165,7 +166,7 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) ([]blockatl } var ( - blocksChan = make(chan blockatlas.Block, blocksCount) + blocksChan = make(chan types.Block, blocksCount) errorsChan = make(chan error, blocksCount) totalCount int32 wg sync.WaitGroup @@ -205,10 +206,10 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) ([]blockatl }, }).Error("Fetch Blocks Errors") - return []blockatlas.Block{}, fmt.Errorf("unable to fetch blocks: %d: %d", lastParsedBlock, currentBlock) + return []types.Block{}, fmt.Errorf("unable to fetch blocks: %d: %d", lastParsedBlock, currentBlock) } - blocks := make([]blockatlas.Block, 0, len(blocksChan)) + blocks := make([]types.Block, 0, len(blocksChan)) for block := range blocksChan { blocks = append(blocks, block) } @@ -223,7 +224,7 @@ func FetchBlocks(params Params, lastParsedBlock, currentBlock int64) ([]blockatl return blocks, nil } -func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas.Block) error { +func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- types.Block) error { block, err := getBlockByNumberWithRetry(5, time.Second*5, api.GetBlockByNumber, num, api.Coin().Symbol) if err != nil { return fmt.Errorf("%d", num) @@ -232,7 +233,7 @@ func fetchBlock(api blockatlas.BlockAPI, num int64, blocksChan chan<- blockatlas return nil } -func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { +func SaveLastParsedBlock(params Params, blocks []types.Block) error { if len(blocks) == 0 { return nil } @@ -261,7 +262,7 @@ func SaveLastParsedBlock(params Params, blocks []blockatlas.Block) error { return nil } -func publish(params Params, txs blockatlas.Txs) error { +func publish(params Params, txs types.Txs) error { if len(txs) == 0 { return nil @@ -275,7 +276,7 @@ func publish(params Params, txs blockatlas.Txs) error { return params.TransactionsExchange.Publish(body) } -func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64, symbol string) (*blockatlas.Block, error) { +func getBlockByNumberWithRetry(attempts int, sleep time.Duration, getBlockByNumber GetBlockByNumber, n int64, symbol string) (*types.Block, error) { r, err := getBlockByNumber(n) if err != nil { if s, ok := err.(stop); ok { diff --git a/services/parser/parser_test.go b/services/parser/parser_test.go index 8b3b70922..c340beadd 100644 --- a/services/parser/parser_test.go +++ b/services/parser/parser_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" ) var ( @@ -57,11 +58,11 @@ func TestParser_getBlockByNumberWithRetry_Error(t *testing.T) { } } -func getBlock(num int64) (*blockatlas.Block, error) { +func getBlock(num int64) (*types.Block, error) { if num == 0 { return nil, errors.New("test") } - return &blockatlas.Block{}, nil + return &types.Block{}, nil } func getMockedBlockAPI() blockatlas.BlockAPI { @@ -81,8 +82,8 @@ func (p *Platform) Coin() coin.Coin { return coin.Coins[p.CoinIndex] } -func (p *Platform) GetBlockByNumber(num int64) (*blockatlas.Block, error) { - return &blockatlas.Block{}, nil +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { + return &types.Block{}, nil } func TestGetInterval(t *testing.T) { diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index fac397524..d3d70fbf8 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -7,8 +7,8 @@ import ( "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/services/notifier" + "github.com/trustwallet/golibs/types" ) const ( @@ -22,9 +22,9 @@ func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) error { log.WithFields(log.Fields{"service": TokenIndexer, "txs": txs}).Error("failed to get transactions: ", err) return err } - txs = txs.FilterTransactionsByType([]blockatlas.TransactionType{ - blockatlas.TxTokenTransfer, - blockatlas.TxNativeTokenTransfer, + txs = txs.FilterTransactionsByType([]types.TransactionType{ + types.TxTokenTransfer, + types.TxNativeTokenTransfer, }) if len(txs) == 0 { @@ -111,10 +111,10 @@ func calculateSubscriptionAssetAssociations(database *db.Instance, addressAssets return associations, nil } -func GetAssetsFromTransactions(txs []blockatlas.Tx) []models.Asset { +func GetAssetsFromTransactions(txs []types.Tx) []models.Asset { var assets []models.Asset for _, tx := range txs { - asset, ok := tx.AssetModel() + asset, ok := models.AssetFrom(tx) if !ok { continue } @@ -123,12 +123,12 @@ func GetAssetsFromTransactions(txs []blockatlas.Tx) []models.Asset { return assets } -func assetsMap(txs blockatlas.Txs) map[string][]string { +func assetsMap(txs types.Txs) map[string][]string { result := make(map[string][]string) for _, tx := range txs { prefix := strconv.Itoa(int(tx.Coin)) + "_" addresses := tx.GetAddresses() - asset, ok := tx.AssetModel() + asset, ok := models.AssetFrom(tx) if !ok { continue } From 37ed4f7e8f78412d3e3529d1db2cba66f0e057ad Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 13 Jan 2021 12:20:06 -0800 Subject: [PATCH 456/506] Bump github.com/mitchellh/mapstructure from 1.4.0 to 1.4.1 (#1362) Bumps [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) from 1.4.0 to 1.4.1. - [Release notes](https://github.com/mitchellh/mapstructure/releases) - [Changelog](https://github.com/mitchellh/mapstructure/blob/master/CHANGELOG.md) - [Commits](https://github.com/mitchellh/mapstructure/compare/v1.4.0...v1.4.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 30c9a7b14..35cf84be8 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/getsentry/raven-go v0.2.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 - github.com/mitchellh/mapstructure v1.4.0 + github.com/mitchellh/mapstructure v1.4.1 github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/runc v1.0.0-rc9 // indirect github.com/ory/dockertest v3.3.5+incompatible diff --git a/go.sum b/go.sum index 8293506de..d97984f59 100644 --- a/go.sum +++ b/go.sum @@ -312,6 +312,7 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= From 3a772c4cad95dddf5ac151ea20c2952f3f0a1e3d Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 14 Jan 2021 08:40:31 +0800 Subject: [PATCH 457/506] [Tezos] Implement block api from rpc (#1354) * implement block api from tezos rpc * parse delegation operation --- go.mod | 1 + go.sum | 11 +- platform/tezos/block.go | 114 +- platform/tezos/block_test.go | 146 +++ platform/tezos/client.go | 19 - platform/tezos/mocks/rpc_block_1292516.json | 1154 +++++++++++++++++++ platform/tezos/model.go | 4 - platform/tezos/rpc.go | 14 + platform/tezos/rpc_model.go | 39 + 9 files changed, 1464 insertions(+), 38 deletions(-) create mode 100644 platform/tezos/block_test.go create mode 100644 platform/tezos/mocks/rpc_block_1292516.json create mode 100644 platform/tezos/rpc_model.go diff --git a/go.mod b/go.mod index 35cf84be8..caca910ff 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/getsentry/raven-go v0.2.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 + github.com/itchyny/timefmt-go v0.1.1 github.com/mitchellh/mapstructure v1.4.1 github.com/mr-tron/base58 v1.2.0 github.com/opencontainers/runc v1.0.0-rc9 // indirect diff --git a/go.sum b/go.sum index d97984f59..8dc881072 100644 --- a/go.sum +++ b/go.sum @@ -51,7 +51,6 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/cenkalti/backoff v1.1.0 h1:QnvVp8ikKCDWOsFheytRCoYWYPO/ObCTBGxT19Hc+yE= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= @@ -192,6 +191,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/itchyny/timefmt-go v0.1.1 h1:rLpnm9xxb39PEEVzO0n4IRp0q6/RmBc7Dy/rE4HrA0U= +github.com/itchyny/timefmt-go v0.1.1/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= @@ -310,8 +311,7 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= -github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -399,6 +399,7 @@ github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -415,12 +416,8 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.31-0.20210111093217-efd7dac63bce h1:o+uU7PzPptwcW0z85S77B3dk5tIr1v7fd3cAFjdWbac= -github.com/trustwallet/golibs v0.0.31-0.20210111093217-efd7dac63bce/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= github.com/trustwallet/golibs v0.0.31 h1:Ii5WqqN2TjTHAyXBYpvck7ImtqdNNITeO/zlqfd0E4o= github.com/trustwallet/golibs v0.0.31/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= -github.com/trustwallet/golibs/network v0.0.0-20210107055554-eac147c5e524 h1:cHw4uer/5KexBPrK6Tx3viq/GRtTE22LtCBFPbQY7II= -github.com/trustwallet/golibs/network v0.0.0-20210107055554-eac147c5e524/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= github.com/trustwallet/golibs/network v0.0.0-20210112030915-7e676f1ce53b h1:sAfeSYHLxCGW00mIv/+P8T03SiW0JP4OLAccuMAjz6M= github.com/trustwallet/golibs/network v0.0.0-20210112030915-7e676f1ce53b/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= diff --git a/platform/tezos/block.go b/platform/tezos/block.go index 3a0d3b22a..c5983cc0c 100644 --- a/platform/tezos/block.go +++ b/platform/tezos/block.go @@ -1,20 +1,118 @@ package tezos -import "github.com/trustwallet/golibs/types" +import ( + "encoding/json" + "errors" + + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" + + "github.com/itchyny/timefmt-go" +) func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.GetCurrentBlock() + return p.rpcClient.GetBlockHead() } func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { - txTypes := []string{TxTypeTransaction, TxTypeDelegation} - srcTxs, err := p.client.GetBlockByNumber(num, txTypes) + block, err := p.rpcClient.GetBlockByNumber(num) if err != nil { return nil, err } - txs := NormalizeTxs(srcTxs, "") - return &types.Block{ - Number: num, - Txs: txs, + return NormalizeRpcBlock(block) +} + +func NormalizeRpcBlock(block RpcBlock) (*types.Block, error) { + txs := []types.Tx{} + + for _, ops := range block.Operations { + for _, op := range ops { + for _, content := range op.Contents { + if tx, err := mapTransaction(content); err == nil { + if normalized, err := NormalizeRpcTransaction(tx, block.Header); err == nil { + normalized.ID = op.Hash + txs = append(txs, normalized) + } + } + } + } + } + + return &types.Block{Number: block.Header.Level, Txs: txs}, nil +} + +func NormalizeRpcTransaction(tx RpcTransaction, header RpcBlockHeader) (types.Tx, error) { + coin := coin.Tezos() + + var metadata interface{} + var to string + var txType types.TransactionType + switch tx.Kind { + case TxTypeTransaction: + to = tx.Destination + txType = types.TxTransfer + metadata = types.Transfer{ + Value: types.Amount(tx.Amount), + Symbol: coin.Symbol, + Decimals: coin.Decimals, + } + case TxTypeDelegation: + var title types.KeyTitle + if len(tx.Delegate) == 0 { + title = types.AnyActionUndelegation + } else { + title = types.AnyActionDelegation + to = tx.Delegate + } + txType = types.TxAnyAction + metadata = types.AnyAction{ + Coin: coin.ID, + Title: title, + Key: types.KeyStakeDelegate, + Name: coin.Name, + Symbol: coin.Symbol, + Decimals: coin.Decimals, + } + default: + return types.Tx{}, errors.New("not supported operation kind: " + tx.Kind) + } + + date, err := timefmt.Parse(header.Timestamp, "%Y-%m-%dT%H:%M:%SZ") + if err != nil { + return types.Tx{}, err + } + + var status types.Status + if tx.Metadata.OperationResult.Status == TxStatusApplied { + status = types.StatusCompleted + } else { + status = types.StatusError + } + + return types.Tx{ + Coin: coin.ID, + From: tx.Source, + To: to, + Fee: types.Amount(tx.Fee), + Date: date.Unix(), + Block: uint64(header.Level), + Status: status, + Type: txType, + Meta: metadata, }, nil } + +func mapTransaction(content interface{}) (RpcTransaction, error) { + bytes, err := json.Marshal(content) + if err != nil { + return RpcTransaction{}, err + } + + var tx RpcTransaction + err = json.Unmarshal(bytes, &tx) + if err != nil { + return RpcTransaction{}, err + } + + return tx, nil +} diff --git a/platform/tezos/block_test.go b/platform/tezos/block_test.go new file mode 100644 index 000000000..aa5141b36 --- /dev/null +++ b/platform/tezos/block_test.go @@ -0,0 +1,146 @@ +package tezos + +import ( + "fmt" + "reflect" + "testing" + + "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" +) + +func TestNormalizeRpcBlock(t *testing.T) { + type args struct { + filename string + } + tests := []struct { + name string + args args + want *types.Block + wantErr bool + }{ + { + name: "Test normalize block 1292516", + args: args{ + filename: "rpc_block_1292516.json", + }, + want: &types.Block{ + Number: 1292516, + Txs: []types.Tx{ + { + ID: "oo25sEdAT3YDb83WNdMSxRv4E6V2Rt6Jc8msgTio7R4FBnAiFmj", + Coin: 1729, + From: "tz1SiPXX4MYGNJNDsRc7n8hkvUqFzg8xqF9m", + To: "tz1LGrjCS3Jj3YZyRx3mHMmEXRJVQeVnoYYi", + Fee: "2940", + Date: 1610065014, + Block: 1292516, + Status: "completed", + Sequence: 0, + Type: "transfer", + Memo: "", + Meta: types.Transfer{ + Value: "5278500000", + Symbol: "XTZ", + Decimals: 6, + }, + }, + { + ID: "ooPykS2pw28FveDV3FojeXmThtuCATDJdn93iFjrRxFaEytait2", + Coin: 1729, + From: "tz1MKCMt9dQDccykzripUGk5439BwEWthqx5", + To: "tz1S1Aew75hMrPUymqenKfHo8FspppXKpW7h", + Fee: "9008", + Date: 1610065014, + Block: 1292516, + Status: "completed", + Sequence: 0, + Type: "any_action", + Memo: "", + Meta: types.AnyAction{ + Coin: 1729, + Title: "Delegation", + Key: "stake_delegate", + Name: "Tezos", + Symbol: "XTZ", + Decimals: 6, + }, + }, + { + ID: "ooFFpMbVAJMkxNYFqxERDumptXS2kSEJQqTwoovVPinayJehB8f", + Coin: 1729, + From: "tz1YbzpfsfRtSiYJWcvpWEDHPNe3kkqEvY56", + To: "tz1L1c5YoQMaciYGB8gpzWoHbscBmtsTsknF", + Fee: "30000", + Date: 1610065014, + Block: 1292516, + Status: "completed", + Sequence: 0, + Type: "transfer", + Memo: "", + Meta: types.Transfer{ + Value: "290691675", + Symbol: "XTZ", + Decimals: 6, + }, + }, + { + ID: "opLbuEsuf9NmzgikvAG4sVaS7NJedzXHcz53iQPon6QurLP8Ztv", + Coin: 1729, + From: "tz1XbmS2Z3ya36JDqo1P1y3VU8t4RU2LJW6J", + To: "", + Fee: "2500", + Date: 1610065014, + Block: 1292516, + Status: "completed", + Sequence: 0, + Type: "any_action", + Memo: "", + Meta: types.AnyAction{ + Coin: 1729, + Title: "Undelegation", + Key: "stake_delegate", + Name: "Tezos", + Symbol: "XTZ", + Decimals: 6, + }, + }, + { + ID: "opNgBb87Cnpjr29Uc4CRuXpWgTfhPx2h76S5txrPJELa5XYiidZ", + Coin: 1729, + From: "tz1c5wM9826YcUNQ8a17z9eUYpKQ3oW3zfmJ", + To: "KT19kgnqC5VWoxktLRdRUERbyUPku9YioE8W", + Fee: "824", + Date: 1610065014, + Block: 1292516, + Status: "completed", + Sequence: 0, + Type: "transfer", + Memo: "", + Meta: types.Transfer{ + Value: "0", + Symbol: "XTZ", + Decimals: 6, + }, + }, + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + var block RpcBlock + _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &block) + t.Run(tt.name, func(t *testing.T) { + got, err := NormalizeRpcBlock(block) + fmt.Println(got) + if (err != nil) != tt.wantErr { + t.Errorf("NormalizeRpcBlock() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NormalizeRpcBlock() = %v, \nwant %v", got, tt.want) + } + }) + } +} diff --git a/platform/tezos/client.go b/platform/tezos/client.go index ec8936cea..9d6eedba9 100644 --- a/platform/tezos/client.go +++ b/platform/tezos/client.go @@ -21,22 +21,3 @@ func (c *Client) GetTxsOfAddress(address string, txType []string) (txs ExplorerA }) return } - -// Get last indexed block by explorer -func (c *Client) GetCurrentBlock() (int64, error) { - var status Status - err := c.Get(&status, "status", nil) - return status.Indexed, err -} - -func (c *Client) GetBlockByNumber(num int64, txType []string) ([]Transaction, error) { - var blockOps []Transaction - path := fmt.Sprintf("block/%d/operations", num) - types := strings.Join(txType, ",") - - err := c.Get(&blockOps, path, url.Values{ - "limit": {"5000"}, // https://github.com/blockwatch-cc/tzindex/issues/17#issuecomment-604967761 - "type": {types}, - }) - return blockOps, err -} diff --git a/platform/tezos/mocks/rpc_block_1292516.json b/platform/tezos/mocks/rpc_block_1292516.json new file mode 100644 index 000000000..0ce432d8f --- /dev/null +++ b/platform/tezos/mocks/rpc_block_1292516.json @@ -0,0 +1,1154 @@ +{ + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "BLgbDJqfRXCYL7e4FQkDqqxR9istymAYh3V6yGnZEfoa4EYhDJw", + "header": { + "level": 1292516, + "proto": 7, + "predecessor": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "timestamp": "2021-01-08T00:16:54Z", + "validation_pass": 4, + "operations_hash": "LLoapCgveRMpGZTfYmsu5AMPiUMqKk6WoKU7nX9cDEJ22jTwr8R2j", + "fitness": [ + "01", + "000000000009b8e4" + ], + "context": "CoVfQGE41eiTzwjQSgq3VQQBAniKoTFJN1GKRwE1Rk2vU8Mqzozq", + "priority": 0, + "proof_of_work_nonce": "e69b63f1d8e70100", + "signature": "sigQ4L61R9DeFV1JspU81ECRZtBp3gMAFLQY8rBpuxbVsLsUPo1prkHDHEuoztFU9aSuy7H5r9U68CTMrbEteUygN2kz7Ef4" + }, + "metadata": { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "next_protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "test_chain_status": { + "status": "running", + "chain_id": "NetXbKBPL76Ndcj", + "genesis": "BLjzqqoRoF16U6u1BsZupCEYCEsCfgKhtfFWZ2FJr2wdV1uCJPe", + "protocol": "PtEdoTezd3RHSC31mpxxo1npxFjoWWcFgQtxapi51Z8TLu6v6Uq", + "expiration": "2021-01-20T08:08:04Z" + }, + "max_operations_ttl": 60, + "max_operation_data_length": 16384, + "max_block_header_length": 238, + "max_operation_list_length": [ + { + "max_size": 32768, + "max_op": 32 + }, + { + "max_size": 32768 + }, + { + "max_size": 135168, + "max_op": 132 + }, + { + "max_size": 524288 + } + ], + "baker": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "level": { + "level": 1292516, + "level_position": 1292515, + "cycle": 315, + "cycle_position": 2275, + "voting_period": 39, + "voting_period_position": 14563, + "expected_commitment": false + }, + "voting_period_kind": "testing", + "nonce_hash": null, + "consumed_gas": "10252559", + "deactivated": [], + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "change": "-512000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "cycle": 315, + "change": "512000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "cycle": 315, + "change": "40000000" + } + ] + }, + "operations": [ + [ + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "opHLT62KF7GKrK26xo7MB3rtC4PyYodrUjzwc8kFfKFEKsbxBHh", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1LBEKXaxQbd5Gtzbc1ATCwc3pppu81aWGc", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1LBEKXaxQbd5Gtzbc1ATCwc3pppu81aWGc", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1LBEKXaxQbd5Gtzbc1ATCwc3pppu81aWGc", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz1LBEKXaxQbd5Gtzbc1ATCwc3pppu81aWGc", + "slots": [ + 26 + ] + } + } + ], + "signature": "sigkHkptuXLXoJE5rDgB1r4wjHP9iMh3m9H8soexwQSQiRNgEkqLKULiu82f6DczzYNaPv3mAdBPVBUDW1Yo1yYMNSVt9p13" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "op7EWp6L9ShsDg9JeJ2xSVryQ8WYE3AdWn8t2R72haLTigqcpfc", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1LcuQHNVQEWP2fZjk1QYZGNrfLDwrT3SyZ", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1LcuQHNVQEWP2fZjk1QYZGNrfLDwrT3SyZ", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1LcuQHNVQEWP2fZjk1QYZGNrfLDwrT3SyZ", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz1LcuQHNVQEWP2fZjk1QYZGNrfLDwrT3SyZ", + "slots": [ + 4 + ] + } + } + ], + "signature": "sigNrvASXxs5EQYnxbb1Fsk3pmHWQwx5jEtXLt2cHKRxraewWPeGeh9z3LXjtbXj53xUFBrjm6ir3781Urg6DgZZanF2ci38" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "ont1RcGeWmfFSWkXksXZgdfzYviM6nxy6PTo1B4zniTqc3joNZL", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1MGTFJXpQmtxLi8QJ7AuVRgM2L2Qfn9w9i", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1MGTFJXpQmtxLi8QJ7AuVRgM2L2Qfn9w9i", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1MGTFJXpQmtxLi8QJ7AuVRgM2L2Qfn9w9i", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz1MGTFJXpQmtxLi8QJ7AuVRgM2L2Qfn9w9i", + "slots": [ + 24 + ] + } + } + ], + "signature": "sigaU5DLRT5aNVJriDu6KaVpqn4GQPZLyNZAmN3z68xnYZprM8JbsWdViAGrExXgi6AE1ivSSez3XgkAMkas46kM9aob7Juk" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "oni3KonGeSuWTZFN1gL9QzfJQUuECH5WBAaZbkXkb8mYZ2Wi12c", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1eEnQhbwf6trb8Q8mPb2RaPkNk2rN7BKi8", + "change": "-128000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1eEnQhbwf6trb8Q8mPb2RaPkNk2rN7BKi8", + "cycle": 315, + "change": "128000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1eEnQhbwf6trb8Q8mPb2RaPkNk2rN7BKi8", + "cycle": 315, + "change": "2500000" + } + ], + "delegate": "tz1eEnQhbwf6trb8Q8mPb2RaPkNk2rN7BKi8", + "slots": [ + 14, + 5 + ] + } + } + ], + "signature": "sigecQ7WZ6DKDi7vf9grAipamFD4oByJeNRZgeHbBqNSmRyhjuiYoaK7XkqzQ9CnghuJFWfJh2JuCLYz2Xi97itvriU5FScD" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "ooQf7pyd4rX38P6stjrz7cgiESZ3hvhkivEv3N9iweUmihiHEZp", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz2FCNBrERXtaTtNX6iimR1UJ5JSDxvdHM93", + "slots": [ + 16 + ] + } + } + ], + "signature": "sigrGKAuAKGjLMkHcaNF4vHZJiCYEtaGhT5TWgmiEYGZEgRMnbx2YAYB2agYssCW9EAdPmorgRGQUvFNxdh1ErR8fDPJTKAq" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "ooUYKCanX3vJccWTsdc6bmCxLJy72oTwfaK7Hs1ro5SQxpsJNaN", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz1WCd2jm4uSt4vntk4vSuUWoZQGhLcDuR9q", + "slots": [ + 1 + ] + } + } + ], + "signature": "sigT9K4qPf5C58GfTEy3rEnupij2bjwL5GP5o8XLBSZePKCrvoB882FoQZyuraxgdCdW69JkGSGtMZbP1iwyNoeZVcq7pTQE" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "ooXUxXEazWx581aJaXESkRQJmmpTJyCvXsS5qZs5eN9Rwne6CuB", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1YhNsiRRU8aHNGg7NK3uuP6UDAyacJernB", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1YhNsiRRU8aHNGg7NK3uuP6UDAyacJernB", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1YhNsiRRU8aHNGg7NK3uuP6UDAyacJernB", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz1YhNsiRRU8aHNGg7NK3uuP6UDAyacJernB", + "slots": [ + 8 + ] + } + } + ], + "signature": "sigQahH6yGcrjmp27BSvRTyLeSoX1dBAg8hKjvcxey7EyHZUTr4h4WfC26XMzNwV7fqPQstJSLQ7kLMaweMm1iAqJdiPEwC9" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "oo6AxrjAi5BogkuUjibw652m2zso7FwDci5iYpxZefaSLnbUZzn", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1VmiY38m3y95HqQLjMwqnMS7sdMfGomzKi", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1VmiY38m3y95HqQLjMwqnMS7sdMfGomzKi", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1VmiY38m3y95HqQLjMwqnMS7sdMfGomzKi", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz1VmiY38m3y95HqQLjMwqnMS7sdMfGomzKi", + "slots": [ + 18 + ] + } + } + ], + "signature": "sigkcBaWP9hDxughJm189p6NVSKJuuXTqA4vUVjJDSPYLNRSSNbErbgX3miiFXeT8A3Mn6bByX5zTa55xBbj7eWqA5j6DDoa" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "oof6obQhnjWYF2zCa3TJKTYVRf6LBFqhNw1K8Bamum7FYKyPMuj", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "change": "-384000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "cycle": 315, + "change": "384000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "cycle": 315, + "change": "7500000" + } + ], + "delegate": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "slots": [ + 31, + 28, + 23, + 15, + 7, + 3 + ] + } + } + ], + "signature": "sigfaMBbxsFN6ycsDjMJnE9h3nFRhapYVzZNwyHorRX26o7cCK8KxL73s4qLBxcpd1UxVQpbc2Tn2a52bwSaadUAE7jeYyhP" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "opWsXTj7bu6J3djS92rkm6WhzXzWHUgv4FdLuC8Y37BEeF4NpR2", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1gfArv665EUkSg2ojMBzcbfwuPxAvqPvjo", + "change": "-128000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1gfArv665EUkSg2ojMBzcbfwuPxAvqPvjo", + "cycle": 315, + "change": "128000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1gfArv665EUkSg2ojMBzcbfwuPxAvqPvjo", + "cycle": 315, + "change": "2500000" + } + ], + "delegate": "tz1gfArv665EUkSg2ojMBzcbfwuPxAvqPvjo", + "slots": [ + 21, + 10 + ] + } + } + ], + "signature": "sigmhF5F43MsFWJzBf3WZ9C9iVNvQccvcoMMe9qvsD78gEo6cfSpV5VgfQF1rnFQADEnpHYiZ27mzRj153DebiEpje9ssMZ8" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "oo6rDhNZRSPwxWYLHHPdYXzr8i5YQMYwCtFaCm7Rmac6tqzFtjb", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz3adcvQaKXTCg12zbninqo3q8ptKKtDFTLv", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz3adcvQaKXTCg12zbninqo3q8ptKKtDFTLv", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz3adcvQaKXTCg12zbninqo3q8ptKKtDFTLv", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz3adcvQaKXTCg12zbninqo3q8ptKKtDFTLv", + "slots": [ + 19 + ] + } + } + ], + "signature": "sigkoSk5yS8w9bhAQFJdmxLhvg4ojvteTdNwDjYH7xSjyiyJKzQYiUfHNwgCg6KDcF9sdmiH7Am4zQbEKvivS3V33q6L9zvQ" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "ongTApNddtKjxcibvoLYo6hBVQB8ADMnygWdAxUWPZ5FhEkVtRc", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1Ldzz6k1BHdhuKvAtMRX7h5kJSMHESMHLC", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1Ldzz6k1BHdhuKvAtMRX7h5kJSMHESMHLC", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1Ldzz6k1BHdhuKvAtMRX7h5kJSMHESMHLC", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz1Ldzz6k1BHdhuKvAtMRX7h5kJSMHESMHLC", + "slots": [ + 17 + ] + } + } + ], + "signature": "sigShgwQLVRmz3tSeBFAVF5xMF9nrYfCVNqzcdi1kj1dpHcHxvuCNj3dY1Ey3jUk68FhyoQjNv9QD4auAEYcECEFJSfBhfqi" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "ooGhj6ojVWczDFVdR7eUgvbEiTKAzA5mxa84v5bKtLDaz3qSBBc", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r", + "slots": [ + 25 + ] + } + } + ], + "signature": "siggXjKBYBkFyQgJxZaB8NBQcFn1nNLvr5jxvMBu68bPwasjSkBQNLZBLYbapx7Ff1qLGnNzJ1CrTwToYdaiLCdMGgjZEVaf" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "opZbhKntXP3gdqoXhULZGH1Weg4jbNaFfGEmJ8ygE7XQxaaxWV4", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz3NExpXn9aPNZPorRE4SdjJ2RGrfbJgMAaV", + "change": "-256000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz3NExpXn9aPNZPorRE4SdjJ2RGrfbJgMAaV", + "cycle": 315, + "change": "256000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz3NExpXn9aPNZPorRE4SdjJ2RGrfbJgMAaV", + "cycle": 315, + "change": "5000000" + } + ], + "delegate": "tz3NExpXn9aPNZPorRE4SdjJ2RGrfbJgMAaV", + "slots": [ + 30, + 27, + 12, + 2 + ] + } + } + ], + "signature": "sigUZ8f6oav8XWD6bxkbcvQusfMmH9Z4wuynhnHHaiX68mrzqQxDDsxFpRC6hAac1X2aK1UKqQGmxj9dBZATRbjPz637yRTf" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "ooLowfcbB9v82VkHCpTRgNyoVZnycXpWrNttMvpLiRZJZD3osKZ", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1MXFrtZoaXckE41bjUCSjAjAap3AFDSr3N", + "change": "-128000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz1MXFrtZoaXckE41bjUCSjAjAap3AFDSr3N", + "cycle": 315, + "change": "128000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz1MXFrtZoaXckE41bjUCSjAjAap3AFDSr3N", + "cycle": 315, + "change": "2500000" + } + ], + "delegate": "tz1MXFrtZoaXckE41bjUCSjAjAap3AFDSr3N", + "slots": [ + 9, + 6 + ] + } + } + ], + "signature": "sigkW3z2d8VfDkLmce13BoPyRNjPSX1896oRRFnu79khg6oRLLefytWJc4S1TLJxonBbXbmkTRNFDbrXz9yMLNZUER56LDAN" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "opFdTB2KuvM4QWni6Y7CDTXYq9GXbqGJzCYLZRPgJat49iE7Hbm", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz3RDC3Jdn4j15J7bBHZd29EUee9gVB1CxD9", + "change": "-128000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz3RDC3Jdn4j15J7bBHZd29EUee9gVB1CxD9", + "cycle": 315, + "change": "128000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz3RDC3Jdn4j15J7bBHZd29EUee9gVB1CxD9", + "cycle": 315, + "change": "2500000" + } + ], + "delegate": "tz3RDC3Jdn4j15J7bBHZd29EUee9gVB1CxD9", + "slots": [ + 29, + 11 + ] + } + } + ], + "signature": "sigbDVnYyYn7NQS6KvufAhabostdJn7nmLhLgL2ZwmQEQc6HFWKYChuv3SqEfy7oTFcNtKjezKX5q3wd4vvhNCkJHbE5puRj" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "oo1izHJH2vjuMu7vM8xnxxvTtwDdyuXfxAyhB5Mr6kKnV7rvF9X", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz3bvNMQ95vfAYtG8193ymshqjSvmxiCUuR5", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz3bvNMQ95vfAYtG8193ymshqjSvmxiCUuR5", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz3bvNMQ95vfAYtG8193ymshqjSvmxiCUuR5", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz3bvNMQ95vfAYtG8193ymshqjSvmxiCUuR5", + "slots": [ + 20 + ] + } + } + ], + "signature": "sigtg2nhv9sXBwpDiVnxmcaRztNNdLctPbzGP7SssfLZqrPFZ4jYrEra7CjuRNEEyjzNCpZx7C2zzPvranTTkX87f8msmBou" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "onxZ3XHmTEKWGSDRWuLvfzC5z2UFm4aYCU4XNkudzZ9Uwj8yEZ9", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz3bTdwZinP8U1JmSweNzVKhmwafqWmFWRfk", + "change": "-64000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz3bTdwZinP8U1JmSweNzVKhmwafqWmFWRfk", + "cycle": 315, + "change": "64000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz3bTdwZinP8U1JmSweNzVKhmwafqWmFWRfk", + "cycle": 315, + "change": "1250000" + } + ], + "delegate": "tz3bTdwZinP8U1JmSweNzVKhmwafqWmFWRfk", + "slots": [ + 0 + ] + } + } + ], + "signature": "sigj3q9Y5Ek1GAYJWqMYAjHh31vdxyPq844dfE96mBHS5mqQcYtH4mDmLP5SpphZ2TBUyepdDizfWhbJEXBHVVAQ2pWddYzZ" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "oocdLLz42VJAqKxohMUZq4aYNUEB75Ca9yadktVDGJTsxakjX2x", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "endorsement", + "level": 1292515, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz3RB4aoyjov4KEVRbuhvQ1CKJgBJMWhaeB8", + "change": "-128000000" + }, + { + "kind": "freezer", + "category": "deposits", + "delegate": "tz3RB4aoyjov4KEVRbuhvQ1CKJgBJMWhaeB8", + "cycle": 315, + "change": "128000000" + }, + { + "kind": "freezer", + "category": "rewards", + "delegate": "tz3RB4aoyjov4KEVRbuhvQ1CKJgBJMWhaeB8", + "cycle": 315, + "change": "2500000" + } + ], + "delegate": "tz3RB4aoyjov4KEVRbuhvQ1CKJgBJMWhaeB8", + "slots": [ + 22, + 13 + ] + } + } + ], + "signature": "sigs2jRm2CnqKvZAADPALAqmmQuhUeyoMXrNRYECQhCRtBR9ChzaVH6DzsTYyoAcnr15Nh4EC8H7tTsoKqfVxS2n4juEEC2q" + } + ], + [], + [], + [ + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "oo25sEdAT3YDb83WNdMSxRv4E6V2Rt6Jc8msgTio7R4FBnAiFmj", + "branch": "BLKdyZ3g3apF7bS2iWiKGbURiUQRu5MnngqUH9YB4cbLtpXKvD3", + "contents": [ + { + "kind": "transaction", + "source": "tz1SiPXX4MYGNJNDsRc7n8hkvUqFzg8xqF9m", + "fee": "2940", + "counter": "2173287", + "gas_limit": "15400", + "storage_limit": "300", + "amount": "5278500000", + "destination": "tz1LGrjCS3Jj3YZyRx3mHMmEXRJVQeVnoYYi", + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1SiPXX4MYGNJNDsRc7n8hkvUqFzg8xqF9m", + "change": "-2940" + }, + { + "kind": "freezer", + "category": "fees", + "delegate": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "cycle": 315, + "change": "2940" + } + ], + "operation_result": { + "status": "applied", + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1SiPXX4MYGNJNDsRc7n8hkvUqFzg8xqF9m", + "change": "-5278500000" + }, + { + "kind": "contract", + "contract": "tz1LGrjCS3Jj3YZyRx3mHMmEXRJVQeVnoYYi", + "change": "5278500000" + } + ], + "consumed_gas": "1427", + "consumed_milligas": "1427000" + } + } + } + ], + "signature": "sigcBCi9WMmTnKZ9SkJeBsepWoBvTGfPyhVRc77ukTLnYGuXRTdrtjg647umQcbCGji2QD5Qm8U6KVTeodv8vhmYV3X8K5Lp" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "ooPykS2pw28FveDV3FojeXmThtuCATDJdn93iFjrRxFaEytait2", + "branch": "BLKdyZ3g3apF7bS2iWiKGbURiUQRu5MnngqUH9YB4cbLtpXKvD3", + "contents": [ + { + "kind": "delegation", + "source": "tz1MKCMt9dQDccykzripUGk5439BwEWthqx5", + "fee": "9008", + "counter": "3419875", + "gas_limit": "18136", + "storage_limit": "257", + "delegate": "tz1S1Aew75hMrPUymqenKfHo8FspppXKpW7h", + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1MKCMt9dQDccykzripUGk5439BwEWthqx5", + "change": "-9008" + }, + { + "kind": "freezer", + "category": "fees", + "delegate": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "cycle": 315, + "change": "9008" + } + ], + "operation_result": { + "status": "applied", + "consumed_gas": "1000", + "consumed_milligas": "1000000" + } + } + } + ], + "signature": "sigXUYjE4Pmj712QvZ25rkTew6j61SeUv7wDuZXuKY71VAf5M5g9B4Hi3aAvsYiKMGmtSqnf48RQLb3MVfwocQXSJY8JzDbx" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "ooFFpMbVAJMkxNYFqxERDumptXS2kSEJQqTwoovVPinayJehB8f", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "transaction", + "source": "tz1YbzpfsfRtSiYJWcvpWEDHPNe3kkqEvY56", + "fee": "30000", + "counter": "3790318", + "gas_limit": "18000", + "storage_limit": "257", + "amount": "290691675", + "destination": "tz1L1c5YoQMaciYGB8gpzWoHbscBmtsTsknF", + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1YbzpfsfRtSiYJWcvpWEDHPNe3kkqEvY56", + "change": "-30000" + }, + { + "kind": "freezer", + "category": "fees", + "delegate": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "cycle": 315, + "change": "30000" + } + ], + "operation_result": { + "status": "applied", + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1YbzpfsfRtSiYJWcvpWEDHPNe3kkqEvY56", + "change": "-290691675" + }, + { + "kind": "contract", + "contract": "tz1L1c5YoQMaciYGB8gpzWoHbscBmtsTsknF", + "change": "290691675" + } + ], + "consumed_gas": "1827", + "consumed_milligas": "1827000" + } + } + } + ], + "signature": "sigr2d12s1X4umxZGVYwrpbhSRTSBryo8pbHXHxumHrcSimcuePKkzVdtnvxm8xU74aFBKtjzxzvGDaaXrQhN85S2PULLJGu" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "opLbuEsuf9NmzgikvAG4sVaS7NJedzXHcz53iQPon6QurLP8Ztv", + "branch": "BMQNTsyxPQU24bBVgfZSQpshrhYdTZoXBq5K15opDaVQ5fJBqhC", + "contents": [ + { + "kind": "delegation", + "source": "tz1XbmS2Z3ya36JDqo1P1y3VU8t4RU2LJW6J", + "fee": "2500", + "counter": "5375544", + "gas_limit": "18136", + "storage_limit": "257", + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1XbmS2Z3ya36JDqo1P1y3VU8t4RU2LJW6J", + "change": "-2500" + }, + { + "kind": "freezer", + "category": "fees", + "delegate": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "cycle": 315, + "change": "2500" + } + ], + "operation_result": { + "status": "applied", + "consumed_gas": "1000", + "consumed_milligas": "1000000" + } + } + } + ], + "signature": "sigt3eD7T3RrqUqqxcUy4aBoZNuRzjAECc2WXaJWjBYRk5sbRRMxHBnonq2zjXtkZcYhnY1VrkjbPwccc816eeNG2EcbLdif" + }, + { + "protocol": "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo", + "chain_id": "NetXdQprcVkpaWU", + "hash": "opNgBb87Cnpjr29Uc4CRuXpWgTfhPx2h76S5txrPJELa5XYiidZ", + "branch": "BLKdyZ3g3apF7bS2iWiKGbURiUQRu5MnngqUH9YB4cbLtpXKvD3", + "contents": [ + { + "kind": "transaction", + "source": "tz1c5wM9826YcUNQ8a17z9eUYpKQ3oW3zfmJ", + "fee": "824", + "counter": "5988504", + "gas_limit": "5104", + "storage_limit": "0", + "amount": "0", + "destination": "KT19kgnqC5VWoxktLRdRUERbyUPku9YioE8W", + "parameters": { + "entrypoint": "update_value", + "value": { + "prim": "Pair", + "args": [ + { + "string": "2021-01-08T00:15:00Z" + }, + { + "prim": "Pair", + "args": [ + { + "int": "253" + }, + { + "prim": "Pair", + "args": [ + { + "int": "88" + }, + { + "int": "224" + } + ] + } + ] + } + ] + } + }, + "metadata": { + "balance_updates": [ + { + "kind": "contract", + "contract": "tz1c5wM9826YcUNQ8a17z9eUYpKQ3oW3zfmJ", + "change": "-824" + }, + { + "kind": "freezer", + "category": "fees", + "delegate": "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk", + "cycle": 315, + "change": "824" + } + ], + "operation_result": { + "status": "applied", + "storage": { + "prim": "Pair", + "args": [ + { + "prim": "Pair", + "args": [ + { + "int": "1610064900" + }, + { + "prim": "Pair", + "args": [ + { + "int": "253" + }, + { + "prim": "Pair", + "args": [ + { + "int": "88" + }, + { + "int": "224" + } + ] + } + ] + } + ] + }, + { + "bytes": "0000b4685dc0a9a5cc28942065288413ce5bea2f76a0" + } + ] + }, + "consumed_gas": "4904", + "consumed_milligas": "4903559", + "storage_size": "621" + } + } + } + ], + "signature": "sigkWvegrNtN149DWqPVJB4Fi2gw3BcowmAF3bW8CNXi6iq8ML6DD9fLw71PFZnVkQJPpR9pvfwBP89wpNfA4gXmLDftgGj5" + } + ] + ] +} diff --git a/platform/tezos/model.go b/platform/tezos/model.go index f14c44714..d90c0b78f 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -44,10 +44,6 @@ type ( Kind string `json:"kind"` } - Status struct { - Indexed int64 `json:"indexed"` - } - Validator struct { Address string `json:"pkh"` } diff --git a/platform/tezos/rpc.go b/platform/tezos/rpc.go index e1033358f..089a9fb5b 100644 --- a/platform/tezos/rpc.go +++ b/platform/tezos/rpc.go @@ -17,6 +17,20 @@ const ( TestingPeriodType PeriodType = "testing" ) +func (c *RpcClient) GetBlockHead() (int64, error) { + var head RpcBlockHeader + err := c.Get(&head, "chains/main/blocks/head/header", nil) + if err != nil { + return 0, err + } + return int64(head.Level), nil +} + +func (c *RpcClient) GetBlockByNumber(num int64) (block RpcBlock, err error) { + err = c.Get(&block, fmt.Sprintf("chains/main/blocks/%d", num), nil) + return +} + func (c *RpcClient) GetValidators(blockID string) (validators []Validator, err error) { err = c.Get(&validators, fmt.Sprintf("chains/main/blocks/%s/votes/listings", blockID), nil) return diff --git a/platform/tezos/rpc_model.go b/platform/tezos/rpc_model.go new file mode 100644 index 000000000..067699f2a --- /dev/null +++ b/platform/tezos/rpc_model.go @@ -0,0 +1,39 @@ +package tezos + +type RpcBlockHeader struct { + Level int64 `json:"level"` + Timestamp string `json:"timestamp"` +} + +type RpcOperationContent struct { + Hash string `json:"hash"` + Contents []interface{} `json:"contents"` +} + +type RpcTransaction struct { + Kind string `json:"kind"` + Source string `json:"source"` + Fee string `json:"fee"` + Counter string `json:"counter"` + GasLimit string `json:"gas_limit"` + StorageLimit string `json:"storage_limit"` + Amount string `json:"amount,omitempty"` + Destination string `json:"destination,omitempty"` + Delegate string `json:"delegate,omitempty"` + Metadata RpcMetadata `json:"metadata"` +} + +type RpcOperationContents []RpcOperationContent + +type RpcBlock struct { + Header RpcBlockHeader `json:"header"` + Operations []RpcOperationContents `json:"operations"` +} + +type RpcMetadata struct { + OperationResult OperationResult `json:"operation_result"` +} + +type OperationResult struct { + Status string `json:"status"` +} From 1509fb4e15fecb2063abda50f5fc670a318412f2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 13 Jan 2021 23:33:11 -0800 Subject: [PATCH 458/506] Bump github.com/stretchr/testify from 1.6.1 to 1.7.0 (#1366) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.6.1 to 1.7.0. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.6.1...v1.7.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index caca910ff..89f1a0894 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( 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.6.1 + 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.31 diff --git a/go.sum b/go.sum index 8dc881072..6277f11c8 100644 --- a/go.sum +++ b/go.sum @@ -407,6 +407,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= From 370592b33cfaed2a28d51c73418f859e630557a1 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 14 Jan 2021 00:34:18 -0800 Subject: [PATCH 459/506] Improve blockbook parsing and avoid deadlock for adding subscriptions (#1363) * Update subscription.go * Update init.go * Update parser.go * Add order to Find(&dbAssets). * Add pg transaction to adding new assets * Update indexer_subscribe.go * Add blockbook check for in sync * Update gorm to v1.20.11 * Disable RunTokenIndexerSubscribe * Remove CreatedAt * Remove tx.Clauses * Use tx * Remove tx for some calls * Add UPDATE NOWAIT for GetSubscriptions * Add uniqueIndex to address * Use 1 worker for subscriptions * Update main.go * Do value assigment for creation subscriptions * Remove duplicate subscriptions * Remove RestoreConnectionWorker * Update subscription.go * Set workers to 1 to avoid deadlocks * Use InitDefaultConsumerOptions * Improve client host logging * fix lint --- api/endpoint/token.go | 5 ++-- cmd/api/main.go | 2 -- cmd/consumer/main.go | 7 +++-- cmd/parser/main.go | 3 -- db/asset.go | 20 ++++--------- db/db.go | 33 +--------------------- db/models/subscriptions.go | 6 ++-- db/subscription.go | 20 ++++++------- go.mod | 6 ++-- go.sum | 13 +++++---- internal/client.go | 2 +- internal/init.go | 4 ++- platform/bitcoin/blockbook/client.go | 6 ++++ platform/bitcoin/blockbook/model.go | 1 + services/parser/parser.go | 14 ++++----- services/tokenindexer/api.go | 2 +- services/tokenindexer/indexer_subscribe.go | 2 +- 17 files changed, 56 insertions(+), 90 deletions(-) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index 316fa30fd..994a0c1ce 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -1,6 +1,7 @@ package endpoint import ( + "errors" "net/http" "strconv" @@ -65,12 +66,12 @@ func GetNewTokens(c *gin.Context, instance tokenindexer.Instance) { from, err := strconv.Atoi(fromRaw) if err != nil { - c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(err)) + c.AbortWithStatusJSON(http.StatusBadRequest, errorResponse(errors.New("invalid from param"))) return } request.From = int64(from) - resp, err := instance.HandleNewTokensRequest(request) + resp, err := instance.GetNewTokensRequest(request) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return diff --git a/cmd/api/main.go b/cmd/api/main.go index 8ce7ac020..98a166473 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "time" golibsGin "github.com/trustwallet/golibs/network/gin" @@ -51,7 +50,6 @@ func init() { if err != nil { log.Fatal(err) } - go database.RestoreConnectionWorker(time.Second*10, config.Default.Postgres.URL) tokenIndexer = tokenindexer.Init(database) } diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index 0679446a4..cb26f90fd 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -52,7 +52,6 @@ func init() { if err != nil { log.Fatal("Postgres init: ", err) } - go database.RestoreConnectionWorker(time.Second*10, config.Default.Postgres.URL) tokenindexer.Init(database) } @@ -63,7 +62,7 @@ func main() { // RunTokenIndexerSubscribe requires to fetch data from token apis. Improve later platform.Init(config.Default.Platform) - options := mq.ConsumerOptions{Workers: config.Default.Consumer.Workers} + options := mq.InitDefaultConsumerOptions(config.Default.Consumer.Workers) switch config.Default.Consumer.Service { case transactions: @@ -90,7 +89,9 @@ func setupTransactionsConsumer(options mq.ConsumerOptions, ctx context.Context) } func setupSubscriptionsConsumer(options mq.ConsumerOptions, ctx context.Context) { - go internal.Subscriptions.RunConsumer(internal.ConsumerDatabase{Database: database, Delivery: subscriber.RunSubscriber}, options, ctx) + // Special case options to avoid unknown deadlock on insert + subscriptionsOptions := mq.InitDefaultConsumerOptions(1) + go internal.Subscriptions.RunConsumer(internal.ConsumerDatabase{Database: database, Delivery: subscriber.RunSubscriber}, subscriptionsOptions, ctx) go internal.SubscriptionsTokens.RunConsumer(tokenindexer.ConsumerIndexer{Database: database, TokensAPIs: platform.TokensAPIs, Delivery: tokenindexer.RunTokenIndexerSubscribe}, options, ctx) } diff --git a/cmd/parser/main.go b/cmd/parser/main.go index 84be424d1..b9eff7034 100644 --- a/cmd/parser/main.go +++ b/cmd/parser/main.go @@ -53,9 +53,6 @@ func init() { if err != nil { log.Fatal(err) } - go database.RestoreConnectionWorker(time.Second*10, config.Default.Postgres.URL) - - time.Sleep(time.Millisecond) } func main() { diff --git a/db/asset.go b/db/asset.go index ba1616bed..b0a527523 100644 --- a/db/asset.go +++ b/db/asset.go @@ -4,7 +4,6 @@ import ( "encoding/json" "time" - "gorm.io/gorm" "gorm.io/gorm/clause" gocache "github.com/patrickmn/go-cache" @@ -14,8 +13,7 @@ import ( func (i *Instance) GetAsset(assetId string) (models.Asset, error) { var asset models.Asset - err := i.Gorm. - First(&asset, "asset = ?", assetId).Error + err := i.Gorm.First(&asset, "asset = ?", assetId).Error if err != nil { return asset, err } @@ -97,15 +95,7 @@ func (i *Instance) AddNewAssets(assets []models.Asset) error { } i.addToMemory(newAssets) - return i.Gorm.Transaction(func(tx *gorm.DB) error { - for _, na := range newAssets { - err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&na).Error - if err != nil { - return err - } - } - return nil - }) + return i.Gorm.Clauses(clause.OnConflict{DoNothing: true}).Create(&newAssets).Error } func (i *Instance) addToMemory(newAssets []models.Asset) { @@ -124,8 +114,10 @@ func (i *Instance) addToMemory(newAssets []models.Asset) { func (i *Instance) GetAssetsFrom(from time.Time) ([]models.Asset, error) { var dbAssets []models.Asset if err := i.Gorm. - Find(&dbAssets, "created_at > ?", from). - Limit(10000).Error; err != nil { + Where("created_at > ?", from). + Order("created_at desc"). + Limit(1000). + Find(&dbAssets).Error; err != nil { return nil, err } return dbAssets, nil diff --git a/db/db.go b/db/db.go index bdeb65ab0..c26c719d5 100644 --- a/db/db.go +++ b/db/db.go @@ -9,8 +9,6 @@ import ( "gorm.io/gorm/logger" gocache "github.com/patrickmn/go-cache" - log "github.com/sirupsen/logrus" - "gorm.io/driver/postgres" "gorm.io/gorm" ) @@ -26,7 +24,7 @@ func New(url string, log bool) (*Instance, error) { logMode = logger.Info } - cfg := &gorm.Config{Logger: logger.Default.LogMode(logMode)} + cfg := &gorm.Config{Logger: logger.Default.LogMode(logMode), SkipDefaultTransaction: true} db, err := gorm.Open(postgres.Open(url), cfg) if err != nil { @@ -48,35 +46,6 @@ func Setup(db *gorm.DB) error { ) } -func (i *Instance) RestoreConnectionWorker(timeout time.Duration, uri string) { - log.Info("Run PG RestoreConnectionWorker") - - for { - if err := i.restoreConnection(uri); err != nil { - log.Error("PG is not available now") - } - time.Sleep(timeout) - } -} - -func (i *Instance) restoreConnection(uri string) error { - db, err := i.Gorm.DB() - if err != nil { - return err - } - - if err = db.Ping(); err != nil { - log.Warn("PG is not available now") - log.Warn("Trying to connect to PG...") - i.Gorm, err = gorm.Open(postgres.Open(uri), &gorm.Config{}) - if err != nil { - return err - } - log.Info("PG connection restored") - } - return nil -} - func (i *Instance) MemorySet(key string, data []byte, exp time.Duration) error { i.MemoryCache.Set(key, data, exp) return nil diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index f986ff259..d0bc32a6d 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -5,11 +5,9 @@ import ( ) type ( - // Subscription for address and asset associations Subscription struct { - ID uint `gorm:"primaryKey;"` - CreatedAt time.Time - Address string `gorm:"uniqueIndex:idx_address; type:varchar(256); not null;"` + ID uint `gorm:"primaryKey;"` + Address string `gorm:"uniqueIndex; type:varchar(256); not null;"` } SubscriptionsAssetAssociation struct { diff --git a/db/subscription.go b/db/subscription.go index 4a607f94e..53cc19194 100644 --- a/db/subscription.go +++ b/db/subscription.go @@ -3,7 +3,6 @@ package db import ( "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "gorm.io/gorm" "gorm.io/gorm/clause" ) @@ -11,19 +10,22 @@ func (i *Instance) CreateSubscriptions(addresses []blockatlas.Subscription) erro if len(addresses) == 0 { return nil } - result := make([]models.Subscription, 0) + // remove duplicates + addressIds := make(map[string]bool) for _, address := range addresses { - result = append(result, models.Subscription{Address: address.AddressID()}) + addressIds[address.AddressID()] = true + } + result := make([]models.Subscription, 0) + for addressId := range addressIds { + result = append(result, models.Subscription{Address: addressId}) } - return i.Gorm.Transaction(func(tx *gorm.DB) error { - return tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error - }) + return i.Gorm.Clauses(clause.OnConflict{DoNothing: true}).Create(&result).Error } func (i *Instance) GetSubscriptions(addresses []string) ([]models.Subscription, error) { var subscriptions []models.Subscription - err := i.Gorm.Find(&subscriptions, "address in (?)", addresses).Error + err := i.Gorm.Find(&subscriptions, "address in ?", addresses).Error if err != nil { return nil, err } @@ -56,7 +58,5 @@ func (i *Instance) CreateSubscriptionsAssets(associations []models.Subscriptions if len(associations) == 0 { return nil } - return i.Gorm. - Clauses(clause.OnConflict{DoNothing: true}). - Create(&associations).Error + return i.Gorm.Clauses(clause.OnConflict{DoNothing: true}).Create(&associations).Error } diff --git a/go.mod b/go.mod index 89f1a0894..80ef65db5 100644 --- a/go.mod +++ b/go.mod @@ -24,12 +24,12 @@ require ( 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.31 - github.com/trustwallet/golibs/network v0.0.0-20210112030915-7e676f1ce53b + github.com/trustwallet/golibs v0.0.32 + github.com/trustwallet/golibs/network v0.0.0-20210113212158-b74318d7ab45 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.6 - gorm.io/gorm v1.20.9 + gorm.io/gorm v1.20.11 ) diff --git a/go.sum b/go.sum index 6277f11c8..dbf3b644b 100644 --- a/go.sum +++ b/go.sum @@ -407,6 +407,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -417,10 +418,10 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.31 h1:Ii5WqqN2TjTHAyXBYpvck7ImtqdNNITeO/zlqfd0E4o= -github.com/trustwallet/golibs v0.0.31/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= -github.com/trustwallet/golibs/network v0.0.0-20210112030915-7e676f1ce53b h1:sAfeSYHLxCGW00mIv/+P8T03SiW0JP4OLAccuMAjz6M= -github.com/trustwallet/golibs/network v0.0.0-20210112030915-7e676f1ce53b/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs v0.0.32 h1:3kBJ6bX2t2HdIEjbuKk/WsExgxHUZVH1JkNbPdofeVs= +github.com/trustwallet/golibs v0.0.32/go.mod h1:MhWay9yOMBj3yEXTd1EepmxOwekbhVq4F1cIYAD2WRE= +github.com/trustwallet/golibs/network v0.0.0-20210113212158-b74318d7ab45 h1:zaobIG3KO/CHpY1o/rGouYFHCWIzLE6uYSUwz2JCLmw= +github.com/trustwallet/golibs/network v0.0.0-20210113212158-b74318d7ab45/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= 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= @@ -643,8 +644,8 @@ 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.9 h1:M3aIZKXAC1PtPVu9t3WGwkBTE1le5c2telz3I/qjRNg= -gorm.io/gorm v1.20.9/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= 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/client.go b/internal/client.go index a507f48ac..c134672d1 100644 --- a/internal/client.go +++ b/internal/client.go @@ -20,7 +20,7 @@ var errorHandler = func(res *http.Response, uri string) error { log.WithFields(log.Fields{ "tags": raven.Tags{ {Key: "status_code", Value: strconv.Itoa(res.StatusCode)}, - {Key: "host", Value: res.Request.Host}, + {Key: "host", Value: res.Request.URL.Host}, {Key: "url", Value: uri}, }, "fingerprint": []string{"client_errors"}, diff --git a/internal/init.go b/internal/init.go index df9f5d7a2..1abdf98f9 100644 --- a/internal/init.go +++ b/internal/init.go @@ -3,6 +3,8 @@ package internal import ( "flag" + "github.com/trustwallet/golibs/network/middleware" + "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" @@ -45,7 +47,7 @@ func InitEngine(ginMode string) *gin.Engine { engine := gin.New() engine.Use(cors.Default()) - engine.Use(gin.Logger()) + engine.Use(middleware.Logger()) return engine } diff --git a/platform/bitcoin/blockbook/client.go b/platform/bitcoin/blockbook/client.go index ead0c5c45..be2b3fd08 100644 --- a/platform/bitcoin/blockbook/client.go +++ b/platform/bitcoin/blockbook/client.go @@ -1,6 +1,7 @@ package blockbook import ( + "errors" "fmt" "net/url" "strconv" @@ -22,6 +23,11 @@ func (c *Client) GetCurrentBlockNumber() (int64, error) { if err != nil { return 0, err } + // If not in sync, latest block might not be available yet. + if !nodeInfo.Blockbook.InSync { + return 0, errors.New("not in sync to get current block number") + } + return nodeInfo.Blockbook.BestHeight, nil } diff --git a/platform/bitcoin/blockbook/model.go b/platform/bitcoin/blockbook/model.go index 2cc0c679a..d538b0910 100644 --- a/platform/bitcoin/blockbook/model.go +++ b/platform/bitcoin/blockbook/model.go @@ -13,6 +13,7 @@ type NodeInfo struct { type Blockbook struct { BestHeight int64 `json:"bestHeight"` + InSync bool `json:"inSync"` } type TokenTransfer struct { diff --git a/services/parser/parser.go b/services/parser/parser.go index 0326e80f5..aa255e7a1 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -65,12 +65,12 @@ func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duratio func parse(params Params) { lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params) - if err != nil || lastParsedBlock > currentBlock { - log.WithFields(log.Fields{ - "operation": "fetch GetBlocksIntervalToFetch", - "coin": params.Api.Coin().Handle, - "tags": raven.Tags{{Key: "coin", Value: params.Api.Coin().Handle}}, - }).Error(err) + if err != nil { + time.Sleep(params.ParsingBlocksInterval) + return + } + + if lastParsedBlock > currentBlock { time.Sleep(params.ParsingBlocksInterval) return } @@ -247,7 +247,7 @@ func SaveLastParsedBlock(params Params, blocks []types.Block) error { lastBlockNumber := blocks[len(blocks)-1].Number if lastBlockNumber <= 0 { - return fmt.Errorf("parser of %s failed to save last block, lastBlockNumber <= 0", params.Api.Coin().Handle) + return fmt.Errorf("parser of %s failed to save last block, lastBlockNumber <= 0: %d", params.Api.Coin().Handle, lastBlockNumber) } err := params.Database.SetLastParsedBlockNumber(params.Api.Coin().Handle, lastBlockNumber) if err != nil { diff --git a/services/tokenindexer/api.go b/services/tokenindexer/api.go index 3b9852a44..551a4c86d 100644 --- a/services/tokenindexer/api.go +++ b/services/tokenindexer/api.go @@ -17,7 +17,7 @@ func Init(database *db.Instance) Instance { return Instance{database: database} } -func (i Instance) HandleNewTokensRequest(r Request) (Response, error) { +func (i Instance) GetNewTokensRequest(r Request) (Response, error) { from := time.Unix(r.From, 0) result, err := i.database.GetAssetsFrom(from) if err != nil { diff --git a/services/tokenindexer/indexer_subscribe.go b/services/tokenindexer/indexer_subscribe.go index 5a97612b8..26cec46e5 100644 --- a/services/tokenindexer/indexer_subscribe.go +++ b/services/tokenindexer/indexer_subscribe.go @@ -51,7 +51,7 @@ func RunTokenIndexerSubscribe(database *db.Instance, apis map[uint]blockatlas.To return CreateAssociations(database, addressAssetsMap) case subscriber.DeleteSubscription: //No action is needed - break + return nil } return nil From ce3600e70611faad0dcbb07820ce984d2a7a38c4 Mon Sep 17 00:00:00 2001 From: Viacheslav Kulish <32914239+vcoolish@users.noreply.github.com> Date: Fri, 15 Jan 2021 08:10:41 +0200 Subject: [PATCH 460/506] Fix Kava denom filter (#1365) --- platform/kava/transaction.go | 9 +++++- platform/kava/transaction_test.go | 47 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/platform/kava/transaction.go b/platform/kava/transaction.go index 408d566bc..087c5e89e 100644 --- a/platform/kava/transaction.go +++ b/platform/kava/transaction.go @@ -65,7 +65,14 @@ func (p *Platform) FilterTxsByDenom(txs []Tx, denom string) []Tx { if len(messages) == 0 { continue } - if messages[0].Value.(MessageValueTransfer).Amount[0].Denom == denom { + var amount Amount + switch messages[0].Value.(type) { + case MessageValueTransfer: + amount = messages[0].Value.(MessageValueTransfer).Amount[0] + case MessageValueDelegate: + amount = messages[0].Value.(MessageValueDelegate).Amount + } + if amount.Denom == denom { filteredTxs = append(filteredTxs, tx) } } diff --git a/platform/kava/transaction_test.go b/platform/kava/transaction_test.go index daf3aaab9..872b18f4c 100644 --- a/platform/kava/transaction_test.go +++ b/platform/kava/transaction_test.go @@ -794,6 +794,13 @@ type test struct { want types.Tx } +type filterTest struct { + name string + platform Platform + Data []string + want []types.Tx +} + func TestNormalize(t *testing.T) { cosmos := Platform{CoinIndex: coin.ATOM} @@ -854,6 +861,46 @@ func TestNormalize(t *testing.T) { } } +func TestFilterByDenom(t *testing.T) { + + kava := Platform{CoinIndex: coin.KAVA} + + test := filterTest{ + "test transfer tx", + kava, + []string{ + transferSrc, + delegateSrc, + unDelegateSrc, + claimRewardSrc1, + claimRewardSrc2, + failedTransferSrc, + transferSrcKava, + transferSrcKavaToken, + }, + []types.Tx{transferDstKavaToken}, + } + + testFilter(t, test) +} + +func testFilter(t *testing.T, test filterTest) { + t.Run(test.name, func(t *testing.T) { + srcTxs := make([]Tx, 0) + for _, tx := range test.Data { + var srcTx Tx + err := json.Unmarshal([]byte(tx), &srcTx) + assert.Nil(t, err) + srcTxs = append(srcTxs, srcTx) + } + tx := test.platform.FilterTxsByDenom(srcTxs, "hard") + assert.Equal(t, len(test.want), len(tx), "length: filtered to expected 1 tx") + normalized, ok := test.platform.Normalize(&tx[0]) + assert.True(t, ok) + assert.Equal(t, test.want[0], normalized, "denom: filtered txs are equal") + }) +} + func testNormalize(t *testing.T, tt test) { t.Run(tt.name, func(t *testing.T) { var srcTx Tx From 2567009cef1ac1a48cc484205afa07e574791117 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 19 Jan 2021 15:30:42 +0900 Subject: [PATCH 461/506] Improve Tezos, Tron parsing and error handling (#1370) * Update golibs/network * Add consumer tags * Add subscriptions tokens * Update main.go * Update naming * Update delivery.go * Update parser.go * Update delivery.go * Fix tezos parsing * Add proper logging for getting messages from the consumer * Update golibs/network * Update golibs/network * Update golibs/network * Update indexer_subscribe.go * Update token.go * fetch balance for delegation txs (#1369) * return error * add string() * Update base.go * Update indexer.go * Add Unable to unmarshal MQ Message * revert fetch account balance in block parsing * re-fix fetch balance for tezos account * Update indexer_subscribe.go * Revert "Update indexer_subscribe.go" This reverts commit 659a2e3dcd8b62bcce5d3bfbe35801da37cdc4d6. * move subscription to types * use model in types * Remove normalizer for tokens and return just asset ids * Remove unused code * Use golibs v0.0.33 * Update token.go * Update client.go Co-authored-by: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> --- Procfile | 7 +- api/endpoint/token.go | 4 +- cmd/consumer/main.go | 46 ++++++-- config.yml | 2 +- config/configuration.go | 1 + db/subscription.go | 4 +- go.mod | 2 +- go.sum | 4 +- internal/mq.go | 5 + pkg/blockatlas/observer.go | 44 ------- pkg/blockatlas/observer_test.go | 70 ------------ pkg/blockatlas/platform.go | 2 +- platform/binance/mocks/tokens.json | 27 +---- platform/binance/model.go | 8 +- platform/binance/token.go | 4 +- platform/bitcoin/blockbook/token.go | 22 +--- platform/bitcoin/blockbook/token_test.go | 15 +-- platform/ethereum/client.go | 4 +- platform/ethereum/transaction_test.go | 4 +- platform/ethereum/trustray/token.go | 10 +- platform/platform.go | 2 +- platform/tezos/block.go | 100 ++++++++++------ platform/tezos/block_test.go | 11 +- platform/tezos/model.go | 4 + platform/tezos/rpc.go | 17 +++ platform/tezos/rpc_mock.go | 9 ++ platform/tron/base.go | 10 +- platform/tron/block.go | 2 +- platform/tron/client.go | 26 +---- .../tron/mocks/tokens/tokens_response.json | 107 ++---------------- platform/tron/stake.go | 2 +- platform/tron/token.go | 86 +++----------- platform/tron/token_test.go | 20 +--- platform/tron/transaction.go | 6 +- services/notifier/base.go | 17 +-- services/notifier/delivery.go | 2 +- services/notifier/models.go | 11 +- services/parser/parser.go | 8 +- services/subscriber/subscriber.go | 24 ++-- services/tokenindexer/api.go | 5 +- services/tokenindexer/indexer.go | 14 +-- services/tokenindexer/indexer_subscribe.go | 25 ++-- 42 files changed, 275 insertions(+), 518 deletions(-) delete mode 100644 pkg/blockatlas/observer.go delete mode 100644 pkg/blockatlas/observer_test.go create mode 100644 platform/tezos/rpc_mock.go diff --git a/Procfile b/Procfile index ebaa81234..c06f6e448 100644 --- a/Procfile +++ b/Procfile @@ -1,6 +1,7 @@ release: bin/setup -c $HOME/config.yml web: bin/api -c $HOME/config.yml -p $PORT -consumer-transactions: CONSUMER_SERVICE=transactions bin/consumer -c $HOME/config.yml -consumer-subscriptions: CONSUMER_SERVICE=subscriptions bin/consumer -c $HOME/config.yml -consumer-tokens: CONSUMER_SERVICE=tokens bin/consumer -c $HOME/config.yml +consumer_transactions: CONSUMER_SERVICE=transactions bin/consumer -c $HOME/config.yml +consumer_subscriptions: CONSUMER_SERVICE=subscriptions bin/consumer -c $HOME/config.yml +consumer_subscriptions_tokens: CONSUMER_SERVICE=subscriptions_tokens bin/consumer -c $HOME/config.yml +consumer_tokens: CONSUMER_SERVICE=tokens bin/consumer -c $HOME/config.yml parser: bin/parser -c $HOME/config.yml diff --git a/api/endpoint/token.go b/api/endpoint/token.go index 994a0c1ce..dfdb975c7 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -19,7 +19,7 @@ import ( // @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} types.CollectionPage +// @Success 200 {object} []string // @Failure 500 {object} ErrorResponse // @Router /v2/{coin}/tokens/{address} [get] func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { @@ -34,7 +34,7 @@ func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return } - c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &result}) + c.JSON(http.StatusOK, result) } func GetTokensByAddressV3(c *gin.Context, instance tokenindexer.Instance) { diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index cb26f90fd..bba2018f4 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -31,9 +31,10 @@ var ( cancel context.CancelFunc database *db.Instance - transactions = "transactions" - tokens = "tokens" - subscriptions = "subscriptions" + transactions = "transactions" + tokens = "tokens" + subscriptions = "subscriptions" + subscriptionsTokens = "subscriptions_tokens" ) func init() { @@ -63,17 +64,22 @@ func main() { platform.Init(config.Default.Platform) options := mq.InitDefaultConsumerOptions(config.Default.Consumer.Workers) + // Special case options to avoid unknown deadlock on insert + subscriptionsOptions := mq.InitDefaultConsumerOptions(1) switch config.Default.Consumer.Service { case transactions: setupTransactionsConsumer(options, ctx) case subscriptions: - setupSubscriptionsConsumer(options, ctx) + setupSubscriptionsConsumer(subscriptionsOptions, ctx) + case subscriptionsTokens: + setupSubscriptionsTokensConsumer(options, ctx) case tokens: setupTokensConsumer(options, ctx) default: setupTransactionsConsumer(options, ctx) - setupSubscriptionsConsumer(options, ctx) + setupSubscriptionsConsumer(subscriptionsOptions, ctx) + setupSubscriptionsTokensConsumer(options, ctx) setupTokensConsumer(options, ctx) } @@ -85,16 +91,34 @@ func main() { } func setupTransactionsConsumer(options mq.ConsumerOptions, ctx context.Context) { - go internal.RawTransactions.RunConsumer(internal.ConsumerDatabase{Database: database, Delivery: notifier.RunNotifier}, options, ctx) + go internal.RawTransactions.RunConsumer(internal.ConsumerDatabase{ + Database: database, + Delivery: notifier.RunNotifier, + Tag: transactions, + }, options, ctx) } func setupSubscriptionsConsumer(options mq.ConsumerOptions, ctx context.Context) { - // Special case options to avoid unknown deadlock on insert - subscriptionsOptions := mq.InitDefaultConsumerOptions(1) - go internal.Subscriptions.RunConsumer(internal.ConsumerDatabase{Database: database, Delivery: subscriber.RunSubscriber}, subscriptionsOptions, ctx) - go internal.SubscriptionsTokens.RunConsumer(tokenindexer.ConsumerIndexer{Database: database, TokensAPIs: platform.TokensAPIs, Delivery: tokenindexer.RunTokenIndexerSubscribe}, options, ctx) + go internal.Subscriptions.RunConsumer(internal.ConsumerDatabase{ + Database: database, + Delivery: subscriber.RunSubscriber, + Tag: subscriptions, + }, options, ctx) +} + +func setupSubscriptionsTokensConsumer(options mq.ConsumerOptions, ctx context.Context) { + go internal.SubscriptionsTokens.RunConsumer(tokenindexer.ConsumerIndexer{ + Database: database, + TokensAPIs: platform.TokensAPIs, + Delivery: tokenindexer.RunTokenIndexerSubscribe, + Tag: subscriptionsTokens, + }, options, ctx) } func setupTokensConsumer(options mq.ConsumerOptions, ctx context.Context) { - go internal.RawTokens.RunConsumer(internal.ConsumerDatabase{Database: database, Delivery: tokenindexer.RunTokenIndexer}, options, ctx) + go internal.RawTokens.RunConsumer(internal.ConsumerDatabase{ + Database: database, + Delivery: tokenindexer.RunTokenIndexer, + Tag: tokens, + }, options, ctx) } diff --git a/config.yml b/config.yml index 3001b68d1..72640d54b 100644 --- a/config.yml +++ b/config.yml @@ -99,7 +99,7 @@ icon: # [TRX] Tron: https://tron.network/ tron: api: https://api.trongrid.io - explorer: https://apilist.tronscan.org + grid: https://api.trongrid.io # trongrid api # [VET] VeChain: https://www.vechain.org vechain: diff --git a/config/configuration.go b/config/configuration.go index eb9fe307b..301536566 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -99,6 +99,7 @@ type Configuration struct { } `mapstructure:"icon"` Tron struct { API string `mapstructure:"api"` + Grid string `mapstructure:"grid"` Explorer string `mapstructure:"explorer"` } `mapstructure:"tron"` Vechain struct { diff --git a/db/subscription.go b/db/subscription.go index 53cc19194..4dbb72064 100644 --- a/db/subscription.go +++ b/db/subscription.go @@ -2,11 +2,11 @@ package db import ( "github.com/trustwallet/blockatlas/db/models" - "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" "gorm.io/gorm/clause" ) -func (i *Instance) CreateSubscriptions(addresses []blockatlas.Subscription) error { +func (i *Instance) CreateSubscriptions(addresses []types.Subscription) error { if len(addresses) == 0 { return nil } diff --git a/go.mod b/go.mod index 80ef65db5..fe6c6b989 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( 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.32 + github.com/trustwallet/golibs v0.0.33 github.com/trustwallet/golibs/network v0.0.0-20210113212158-b74318d7ab45 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect diff --git a/go.sum b/go.sum index dbf3b644b..b5904ba13 100644 --- a/go.sum +++ b/go.sum @@ -418,8 +418,8 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.32 h1:3kBJ6bX2t2HdIEjbuKk/WsExgxHUZVH1JkNbPdofeVs= -github.com/trustwallet/golibs v0.0.32/go.mod h1:MhWay9yOMBj3yEXTd1EepmxOwekbhVq4F1cIYAD2WRE= +github.com/trustwallet/golibs v0.0.33 h1:nADMzgTh/MH+4UHK/TfsZ77VVmMUrFPVIIyMBhbDW0M= +github.com/trustwallet/golibs v0.0.33/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= github.com/trustwallet/golibs/network v0.0.0-20210113212158-b74318d7ab45 h1:zaobIG3KO/CHpY1o/rGouYFHCWIzLE6uYSUwz2JCLmw= github.com/trustwallet/golibs/network v0.0.0-20210113212158-b74318d7ab45/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= diff --git a/internal/mq.go b/internal/mq.go index 3fa3a643b..e41ff9b50 100644 --- a/internal/mq.go +++ b/internal/mq.go @@ -22,8 +22,13 @@ const ( type ConsumerDatabase struct { Database *db.Instance Delivery func(*db.Instance, amqp.Delivery) error + Tag string } func (c ConsumerDatabase) Callback(msg amqp.Delivery) error { return c.Delivery(c.Database, msg) } + +func (c ConsumerDatabase) ConsumerTag() string { + return c.Tag +} diff --git a/pkg/blockatlas/observer.go b/pkg/blockatlas/observer.go deleted file mode 100644 index bb7aa0d19..000000000 --- a/pkg/blockatlas/observer.go +++ /dev/null @@ -1,44 +0,0 @@ -package blockatlas - -import "strconv" - -type ( - Subscriptions map[string][]string - - SubscriptionOperation string - - SubscriptionEvent struct { - Subscriptions Subscriptions `json:"subscriptions"` - Operation SubscriptionOperation `json:"operation"` - } - - Subscription struct { - Coin uint `json:"coin"` - Address string `json:"address"` - } -) - -func (v *Subscription) AddressID() string { - return GetAddressID(strconv.Itoa(int(v.Coin)), v.Address) -} - -func GetAddressID(coin, address string) string { - return coin + "_" + address -} - -func (e *SubscriptionEvent) ParseSubscriptions(s Subscriptions) []Subscription { - subs := make([]Subscription, 0) - for coinStr, perCoin := range s { - coin, err := strconv.Atoi(coinStr) - if err != nil { - continue - } - for _, addr := range perCoin { - subs = append(subs, Subscription{ - Coin: uint(coin), - Address: addr, - }) - } - } - return subs -} diff --git a/pkg/blockatlas/observer_test.go b/pkg/blockatlas/observer_test.go deleted file mode 100644 index f61e2abe5..000000000 --- a/pkg/blockatlas/observer_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package blockatlas - -import ( - "sort" - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_parseSubscriptions(t *testing.T) { - tests := []struct { - name string - subscriptions SubscriptionEvent - wantSubs []Subscription - }{ - { - name: "guid with 1 coin", - subscriptions: SubscriptionEvent{ - Subscriptions: Subscriptions{ - "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, - }, - }, - wantSubs: []Subscription{ - { - Coin: 0, - Address: "xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", - }, - { - Coin: 0, - Address: "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL", - }, - }, - }, - { - name: "guid with 2 coins", - subscriptions: SubscriptionEvent{ - Subscriptions: Subscriptions{ - "2": {"zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc"}, - "0": {"xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL"}, - }, - }, - wantSubs: []Subscription{ - { - Coin: 2, - Address: "zpub6rH4MwgyTmuexAX6HAraks5cKv5BbtmwdLirvnU5845ovUJb4abgjt9DtXK4ZEaToRrNj8dQznuLC6Nka4eMviGMinCVMUxKLpuyddcG9Vc", - }, - { - Coin: 0, - Address: "xpub6BpYi6J1GZzfY3yY7DbhLLccF3efQa18nQngM3jaehgtNSoEgk6UtPULpC3oK5oA3trczY8Ld34LFw1USMPfGHwTEizdD5QyGcMyuh2UoBA", - }, - { - Coin: 0, - Address: "xpub6CYwPfnPJLPquufPkb98coSb3mdy1CgaZrWUtYWGJTJ4VWZUbzH9HLGy7nHpP7DG4UdTkYYpirkTWQSP7pWHsrk24Nos5oYNHpfr4BgPVTL", - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotSubs := tt.subscriptions.ParseSubscriptions(tt.subscriptions.Subscriptions) - sort.Slice(gotSubs, func(i, j int) bool { - return gotSubs[i].Coin > gotSubs[j].Coin - }) - sort.Slice(tt.wantSubs, func(i, j int) bool { - return tt.wantSubs[i].Coin > tt.wantSubs[j].Coin - }) - assert.EqualValues(t, tt.wantSubs, gotSubs) - }) - } -} diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 09020c766..5e718b5b2 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -39,7 +39,7 @@ type ( // TokensAPI provides token lookups TokensAPI interface { Platform - GetTokenListByAddress(address string) (types.TokenPage, error) + GetTokenListByAddress(address string) ([]string, error) } // StakingAPI provides staking information diff --git a/platform/binance/mocks/tokens.json b/platform/binance/mocks/tokens.json index 8f8d1bcae..c165618a7 100644 --- a/platform/binance/mocks/tokens.json +++ b/platform/binance/mocks/tokens.json @@ -1,26 +1,5 @@ [ - { - "name": "Travala.com Token", - "symbol": "AVA", - "decimals": 8, - "token_id": "AVA-645", - "coin": 714, - "type": "BEP2" - }, - { - "name": "Binance Chain Native Token", - "symbol": "BNB", - "decimals": 8, - "token_id": "BNB", - "coin": 714, - "type": "BEP2" - }, - { - "name": "Binance USD", - "symbol": "BUSD", - "decimals": 8, - "token_id": "BUSD-BD1", - "coin": 714, - "type": "BEP2" - } + "c714_tAVA-645", + "c714_tBNB", + "c714_tBUSD-BD1" ] diff --git a/platform/binance/model.go b/platform/binance/model.go index fb152892a..dfa2c2b9b 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -215,16 +215,16 @@ func normalizeBaseOfTransaction(t Tx) types.Tx { } } -func normalizeTokens(srcBalance []TokenBalance, tokens Tokens) []types.Token { - tokensList := make([]types.Token, 0, len(srcBalance)) +func normalizeTokens(srcBalance []TokenBalance, tokens Tokens) []string { + assetIds := make([]string, 0) for _, srcToken := range srcBalance { token, ok := normalizeToken(srcToken, tokens) if !ok { continue } - tokensList = append(tokensList, token) + assetIds = append(assetIds, token.AssetId()) } - return tokensList + return assetIds } func normalizeToken(srcToken TokenBalance, tokens Tokens) (types.Token, bool) { diff --git a/platform/binance/token.go b/platform/binance/token.go index 8448cb219..2989314b7 100644 --- a/platform/binance/token.go +++ b/platform/binance/token.go @@ -1,8 +1,6 @@ package binance -import "github.com/trustwallet/golibs/types" - -func (p *Platform) GetTokenListByAddress(address string) (types.TokenPage, error) { +func (p *Platform) GetTokenListByAddress(address string) ([]string, error) { account, err := p.client.FetchAccountMeta(address) if err != nil || len(account.Balances) == 0 { return nil, nil diff --git a/platform/bitcoin/blockbook/token.go b/platform/bitcoin/blockbook/token.go index 09d4ac440..429faa9b1 100644 --- a/platform/bitcoin/blockbook/token.go +++ b/platform/bitcoin/blockbook/token.go @@ -1,10 +1,10 @@ package blockbook import ( - "github.com/trustwallet/golibs/types" + "github.com/trustwallet/golibs/asset" ) -func (c *Client) GetTokenList(address string, coinIndex uint) (types.TokenPage, error) { +func (c *Client) GetTokenList(address string, coinIndex uint) ([]string, error) { tokens, err := c.GetTokens(address) if err != nil { return nil, err @@ -12,25 +12,13 @@ func (c *Client) GetTokenList(address string, coinIndex uint) (types.TokenPage, return NormalizeTokens(tokens, coinIndex), nil } -func NormalizeTokens(srcTokens []Token, coinIndex uint) []types.Token { - tokenPage := make([]types.Token, 0, len(srcTokens)) +func NormalizeTokens(srcTokens []Token, coinIndex uint) []string { + tokenPage := make([]string, 0) for _, srcToken := range srcTokens { if srcToken.Balance == "0" || srcToken.Balance == "" { continue } - token := NormalizeToken(&srcToken, coinIndex) - tokenPage = append(tokenPage, token) + tokenPage = append(tokenPage, asset.BuildID(coinIndex, srcToken.Contract)) } return tokenPage } - -func NormalizeToken(srcToken *Token, coinIndex uint) types.Token { - return types.Token{ - Name: srcToken.Name, - Symbol: srcToken.Symbol, - TokenID: srcToken.Contract, - Coin: coinIndex, - Decimals: srcToken.Decimals, - Type: types.GetEthereumTokenTypeByIndex(coinIndex), - } -} diff --git a/platform/bitcoin/blockbook/token_test.go b/platform/bitcoin/blockbook/token_test.go index 560bd44d1..a1a1ed0c1 100644 --- a/platform/bitcoin/blockbook/token_test.go +++ b/platform/bitcoin/blockbook/token_test.go @@ -3,8 +3,6 @@ package blockbook import ( "reflect" "testing" - - "github.com/trustwallet/golibs/types" ) func TestNormalizeToken(t *testing.T) { @@ -15,7 +13,7 @@ func TestNormalizeToken(t *testing.T) { tests := []struct { name string args args - want []types.Token + want []string }{ { name: "Should normalize and return token with balance", @@ -27,12 +25,7 @@ func TestNormalizeToken(t *testing.T) { Symbol: "USDC", Decimals: 6}, coinIndex: 60}, - want: []types.Token{ - { - Type: "ERC20", - Name: "USD//C", - TokenID: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - Symbol: "USDC", Decimals: 6, Coin: 60}}, + want: []string{"c60_t0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"}, }, { name: "Should not return token with zero balance", @@ -44,7 +37,7 @@ func TestNormalizeToken(t *testing.T) { Symbol: "USDC", Decimals: 6}, coinIndex: 60}, - want: []types.Token{}, + want: []string{}, }, { name: "Should not return token with zero balance", args: args{srcToken: Token{ @@ -55,7 +48,7 @@ func TestNormalizeToken(t *testing.T) { Symbol: "USDC", Decimals: 6}, coinIndex: 60}, - want: []types.Token{}, + want: []string{}, }, } for _, tt := range tests { diff --git a/platform/ethereum/client.go b/platform/ethereum/client.go index 622927192..219765a30 100644 --- a/platform/ethereum/client.go +++ b/platform/ethereum/client.go @@ -5,12 +5,12 @@ import "github.com/trustwallet/golibs/types" type EthereumClient interface { GetTransactions(address string, coinIndex uint) (types.TxPage, error) GetTokenTxs(address, token string, coinIndex uint) (types.TxPage, error) - GetTokenList(address string, coinIndex uint) (types.TokenPage, error) + GetTokenList(address string, coinIndex uint) ([]string, error) GetCurrentBlockNumber() (int64, error) GetBlockByNumber(num int64, coinIndex uint) (*types.Block, error) } -func (p *Platform) GetTokenListByAddress(address string) (types.TokenPage, error) { +func (p *Platform) GetTokenListByAddress(address string) ([]string, error) { return p.client.GetTokenList(address, p.CoinIndex) } diff --git a/platform/ethereum/transaction_test.go b/platform/ethereum/transaction_test.go index ceb0ba2a3..5c846ba48 100644 --- a/platform/ethereum/transaction_test.go +++ b/platform/ethereum/transaction_test.go @@ -55,8 +55,8 @@ func (c Client) GetTokenTxs(address, token string, coinIndex uint) (types.TxPage return txs, nil } -func (c Client) GetTokenList(address string, coinIndex uint) (types.TokenPage, error) { - return types.TokenPage{}, nil +func (c Client) GetTokenList(address string, coinIndex uint) ([]string, error) { + return []string{}, nil } func (c Client) GetCurrentBlockNumber() (int64, error) { diff --git a/platform/ethereum/trustray/token.go b/platform/ethereum/trustray/token.go index ef3846612..78b07d599 100644 --- a/platform/ethereum/trustray/token.go +++ b/platform/ethereum/trustray/token.go @@ -4,7 +4,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (c *Client) GetTokenList(address string, coinIndex uint) (types.TokenPage, error) { +func (c *Client) GetTokenList(address string, coinIndex uint) ([]string, error) { account, err := c.GetTokens(address) if err != nil { return nil, err @@ -27,11 +27,11 @@ func NormalizeToken(srcToken *Contract, coinIndex uint) types.Token { } // NormalizeTxs converts multiple Ethereum tokens -func NormalizeTokens(srcTokens []Contract, coinIndex uint) []types.Token { - tokenPage := make([]types.Token, 0) +func NormalizeTokens(srcTokens []Contract, coinIndex uint) []string { + assetIds := make([]string, 0) for _, srcToken := range srcTokens { token := NormalizeToken(&srcToken, coinIndex) - tokenPage = append(tokenPage, token) + assetIds = append(assetIds, token.AssetId()) } - return tokenPage + return assetIds } diff --git a/platform/platform.go b/platform/platform.go index 5721ca6d8..1f59a60c7 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -50,7 +50,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Fio().Handle: fio.Init(config.Default.Fio.API), coin.Aion().Handle: aion.Init(config.Default.Aion.API), coin.Icon().Handle: icon.Init(config.Default.Icon.API), - coin.Tron().Handle: tron.Init(config.Default.Tron.API, config.Default.Tron.Explorer), + coin.Tron().Handle: tron.Init(config.Default.Tron.API, config.Default.Tron.Grid), coin.Nano().Handle: nano.Init(config.Default.Nano.API), coin.Nimiq().Handle: nimiq.Init(config.Default.Nimiq.API), coin.Iotex().Handle: iotex.Init(config.Default.Iotex.API), diff --git a/platform/tezos/block.go b/platform/tezos/block.go index c5983cc0c..eda597942 100644 --- a/platform/tezos/block.go +++ b/platform/tezos/block.go @@ -2,7 +2,7 @@ package tezos import ( "encoding/json" - "errors" + "fmt" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/types" @@ -19,20 +19,36 @@ func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { if err != nil { return nil, err } - return NormalizeRpcBlock(block) + + return ProcessRpcBlock(block, &p.rpcClient) } -func NormalizeRpcBlock(block RpcBlock) (*types.Block, error) { +func ProcessRpcBlock(block RpcBlock, rpcClient IRpcClient) (*types.Block, error) { txs := []types.Tx{} for _, ops := range block.Operations { for _, op := range ops { for _, content := range op.Contents { if tx, err := mapTransaction(content); err == nil { - if normalized, err := NormalizeRpcTransaction(tx, block.Header); err == nil { - normalized.ID = op.Hash - txs = append(txs, normalized) + if !(tx.Kind == TxTypeDelegation || tx.Kind == TxTypeTransaction) { + continue + } + + balance := tx.Amount + if len(balance) == 0 { + account, err := rpcClient.GetAccountBalanceAtBlock(tx.Source, block.Header.Level) + if err != nil { + return nil, err + } + balance = account.Balance } + + normalized, err := NormalizeRpcTransaction(tx, block.Header, balance) + if err != nil { + return nil, err + } + normalized.ID = op.Hash + txs = append(txs, normalized) } } } @@ -41,40 +57,19 @@ func NormalizeRpcBlock(block RpcBlock) (*types.Block, error) { return &types.Block{Number: block.Header.Level, Txs: txs}, nil } -func NormalizeRpcTransaction(tx RpcTransaction, header RpcBlockHeader) (types.Tx, error) { - coin := coin.Tezos() +func NormalizeRpcTransaction(tx RpcTransaction, header RpcBlockHeader, balance string) (types.Tx, error) { - var metadata interface{} var to string var txType types.TransactionType switch tx.Kind { case TxTypeTransaction: to = tx.Destination txType = types.TxTransfer - metadata = types.Transfer{ - Value: types.Amount(tx.Amount), - Symbol: coin.Symbol, - Decimals: coin.Decimals, - } case TxTypeDelegation: - var title types.KeyTitle - if len(tx.Delegate) == 0 { - title = types.AnyActionUndelegation - } else { - title = types.AnyActionDelegation - to = tx.Delegate - } + to = tx.Delegate txType = types.TxAnyAction - metadata = types.AnyAction{ - Coin: coin.ID, - Title: title, - Key: types.KeyStakeDelegate, - Name: coin.Name, - Symbol: coin.Symbol, - Decimals: coin.Decimals, - } default: - return types.Tx{}, errors.New("not supported operation kind: " + tx.Kind) + return types.Tx{}, fmt.Errorf("not supported operation kind: %s", tx.Kind) } date, err := timefmt.Parse(header.Timestamp, "%Y-%m-%dT%H:%M:%SZ") @@ -82,15 +77,18 @@ func NormalizeRpcTransaction(tx RpcTransaction, header RpcBlockHeader) (types.Tx return types.Tx{}, err } - var status types.Status - if tx.Metadata.OperationResult.Status == TxStatusApplied { - status = types.StatusCompleted - } else { + metadata, err := mapMetadat(tx, balance) + if err != nil { + return types.Tx{}, err + } + + status := types.StatusCompleted + if tx.Metadata.OperationResult.Status != TxStatusApplied { status = types.StatusError } return types.Tx{ - Coin: coin.ID, + Coin: coin.Tezos().ID, From: tx.Source, To: to, Fee: types.Amount(tx.Fee), @@ -102,6 +100,38 @@ func NormalizeRpcTransaction(tx RpcTransaction, header RpcBlockHeader) (types.Tx }, nil } +func mapMetadat(tx RpcTransaction, balance string) (interface{}, error) { + coin := coin.Tezos() + + switch tx.Kind { + case TxTypeTransaction: + return types.Transfer{ + Value: types.Amount(balance), + Symbol: coin.Symbol, + Decimals: coin.Decimals, + }, nil + case TxTypeDelegation: + var title types.KeyTitle + if len(tx.Delegate) == 0 { + title = types.AnyActionUndelegation + } else { + title = types.AnyActionDelegation + } + + return types.AnyAction{ + Coin: coin.ID, + Title: title, + Key: types.KeyStakeDelegate, + Name: coin.Name, + Symbol: coin.Symbol, + Decimals: coin.Decimals, + Value: types.Amount(balance), + }, nil + default: + return nil, fmt.Errorf("not supported metadata for kind: %s", tx.Kind) + } +} + func mapTransaction(content interface{}) (RpcTransaction, error) { bytes, err := json.Marshal(content) if err != nil { diff --git a/platform/tezos/block_test.go b/platform/tezos/block_test.go index aa5141b36..149052d29 100644 --- a/platform/tezos/block_test.go +++ b/platform/tezos/block_test.go @@ -9,7 +9,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func TestNormalizeRpcBlock(t *testing.T) { +func TestProcessRpcBlock(t *testing.T) { type args struct { filename string } @@ -64,6 +64,7 @@ func TestNormalizeRpcBlock(t *testing.T) { Name: "Tezos", Symbol: "XTZ", Decimals: 6, + Value: "163965", }, }, { @@ -103,6 +104,7 @@ func TestNormalizeRpcBlock(t *testing.T) { Name: "Tezos", Symbol: "XTZ", Decimals: 6, + Value: "163965", }, }, { @@ -131,15 +133,16 @@ func TestNormalizeRpcBlock(t *testing.T) { for _, tt := range tests { var block RpcBlock _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &block) + rpcClient := &RpcClientMock{Balance: "163965"} t.Run(tt.name, func(t *testing.T) { - got, err := NormalizeRpcBlock(block) + got, err := ProcessRpcBlock(block, rpcClient) fmt.Println(got) if (err != nil) != tt.wantErr { - t.Errorf("NormalizeRpcBlock() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ProcessRpcBlock() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("NormalizeRpcBlock() = %v, \nwant %v", got, tt.want) + t.Errorf("ProcessRpcBlock() = %v, \nwant %v", got, tt.want) } }) } diff --git a/platform/tezos/model.go b/platform/tezos/model.go index d90c0b78f..6181eb385 100644 --- a/platform/tezos/model.go +++ b/platform/tezos/model.go @@ -20,6 +20,10 @@ type ( Delegate string `json:"delegate"` } + AccountBalance struct { + Balance string `json:"balance"` + } + ExplorerAccount struct { Transactions []Transaction `json:"ops"` } diff --git a/platform/tezos/rpc.go b/platform/tezos/rpc.go index 089a9fb5b..b0f271f96 100644 --- a/platform/tezos/rpc.go +++ b/platform/tezos/rpc.go @@ -2,11 +2,16 @@ package tezos import ( "fmt" + "strconv" "time" "github.com/trustwallet/golibs/client" ) +type IRpcClient interface { + GetAccountBalanceAtBlock(address string, block int64) (account AccountBalance, err error) +} + type RpcClient struct { client.Request } @@ -46,6 +51,18 @@ func (c *RpcClient) GetAccount(address string) (account Account, err error) { return } +func (c *RpcClient) GetAccountBalanceAtBlock(address string, block int64) (account AccountBalance, err error) { + var head string + if block == 0 { + head = "head" + } else { + head = strconv.FormatInt(block, 10) + } + path := fmt.Sprintf("chains/main/blocks/%s/context/contracts/%s", head, address) + err = c.Get(&account, path, nil) + return +} + func (c *RpcClient) fetchValidatorActivityInfo(id string) (ActivityValidatorInfo, error) { var info ActivityValidatorInfo path := fmt.Sprintf("/chains/main/blocks/head/context/delegates/%s", id) diff --git a/platform/tezos/rpc_mock.go b/platform/tezos/rpc_mock.go new file mode 100644 index 000000000..9847ca83d --- /dev/null +++ b/platform/tezos/rpc_mock.go @@ -0,0 +1,9 @@ +package tezos + +type RpcClientMock struct { + Balance string +} + +func (r *RpcClientMock) GetAccountBalanceAtBlock(address string, block int64) (account AccountBalance, err error) { + return AccountBalance{Balance: r.Balance}, nil +} diff --git a/platform/tron/base.go b/platform/tron/base.go index fa514ca42..e6cb9b572 100644 --- a/platform/tron/base.go +++ b/platform/tron/base.go @@ -6,14 +6,14 @@ import ( ) type Platform struct { - client Client - explorerClient ExplorerClient + client Client + gridClient GridClient } -func Init(api, explorerApi string) *Platform { +func Init(api, gridApi string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, - explorerClient: ExplorerClient{internal.InitClient(explorerApi)}, + client: Client{internal.InitClient(api)}, + gridClient: GridClient{internal.InitClient(api)}, } } diff --git a/platform/tron/block.go b/platform/tron/block.go index 80995e2a2..3c6d289fb 100644 --- a/platform/tron/block.go +++ b/platform/tron/block.go @@ -57,7 +57,7 @@ func (p *Platform) NormalizeBlockChannel(srcTx Tx, txChan chan types.Tx) { if len(transfer.AssetName) > 0 { assetName, err := hex.DecodeString(transfer.AssetName[:]) if err == nil { - info, err := p.client.fetchTokenInfo(string(assetName)) + info, err := p.gridClient.fetchTokenInfo(string(assetName)) if err == nil && len(info.Data) > 0 { addTokenMeta(tx, srcTx, info.Data[0]) } diff --git a/platform/tron/client.go b/platform/tron/client.go index 89f62640f..86676136a 100644 --- a/platform/tron/client.go +++ b/platform/tron/client.go @@ -9,11 +9,10 @@ import ( ) type ( - Client struct { + GridClient struct { client.Request } - - ExplorerClient struct { + Client struct { client.Request } ) @@ -33,7 +32,7 @@ func (c *Client) fetchBlockByNumber(num int64) (Block, error) { return blocks.Blocks[0], nil } -func (c *Client) fetchTxsOfAddress(address, token string) ([]Tx, error) { +func (c *GridClient) fetchTxsOfAddress(address, token string) ([]Tx, error) { path := fmt.Sprintf("v1/accounts/%s/transactions", url.PathEscape(address)) var txs Page @@ -46,9 +45,9 @@ func (c *Client) fetchTxsOfAddress(address, token string) ([]Tx, error) { return txs.Txs, err } -func (c *Client) fetchAccount(address string) (accounts *Account, err error) { +func (c *GridClient) fetchAccount(address string) (accounts *Account, err error) { path := fmt.Sprintf("v1/accounts/%s", address) - err = c.GetWithCache(&accounts, path, nil, time.Minute*1) + err = c.GetWithCache(&accounts, path, nil, time.Second*1) return } @@ -57,7 +56,7 @@ func (c *Client) fetchAccountVotes(address string) (account *AccountData, err er return } -func (c *Client) fetchTokenInfo(id string) (asset Asset, err error) { +func (c *GridClient) fetchTokenInfo(id string) (asset Asset, err error) { path := fmt.Sprintf("v1/assets/%s", id) err = c.GetWithCache(&asset, path, nil, time.Hour*24) return @@ -81,16 +80,3 @@ func (c *Client) fetchTRC20Transactions(address string) (TRC20Transactions, erro } return result, nil } - -func (c *ExplorerClient) fetchAllTRC20Tokens(address string) ([]ExplorerTrc20Tokens, error) { - var result ExplorerResponse - path := "api/account" - err := c.GetWithCache(&result, path, url.Values{"address": {address}}, time.Minute*5) - if err != nil { - return nil, err - } - if result.ExplorerTrc20Tokens != nil { - return result.ExplorerTrc20Tokens, nil - } - return nil, nil -} diff --git a/platform/tron/mocks/tokens/tokens_response.json b/platform/tron/mocks/tokens/tokens_response.json index 41de9abbe..36caf4060 100644 --- a/platform/tron/mocks/tokens/tokens_response.json +++ b/platform/tron/mocks/tokens/tokens_response.json @@ -1,98 +1,13 @@ [ - { - "name": "FomoThreeD", - "symbol": "FOM", - "decimals": 0, - "token_id": "1000542", - "coin": 195, - "type": "TRC10" - }, - { - "name": "OtonamiS", - "symbol": "OS", - "decimals": 0, - "token_id": "1000567", - "coin": 195, - "type": "TRC10" - }, - { - "name": "JUST GOV", - "symbol": "JST", - "decimals": 18, - "token_id": "TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9", - "coin": 195, - "type": "TRC20" - }, - { - "name": "Enme Token", - "symbol": "EME", - "decimals": 6, - "token_id": "TCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF", - "coin": 195, - "type": "TRC20" - }, - { - "name": "BeeHive", - "symbol": "BEE", - "decimals": 8, - "token_id": "TG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK", - "coin": 195, - "type": "TRC20" - }, - { - "name": "Mono Token", - "symbol": "MONO", - "decimals": 18, - "token_id": "TLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak", - "coin": 195, - "type": "TRC20" - }, - { - "name": "WINK", - "symbol": "WIN", - "decimals": 6, - "token_id": "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7", - "coin": 195, - "type": "TRC20" - }, - { - "name": "PYRO Network", - "symbol": "PYRO", - "decimals": 6, - "token_id": "TMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e", - "coin": 195, - "type": "TRC20" - }, - { - "name": "NoleCoin", - "symbol": "NOLE", - "decimals": 6, - "token_id": "TPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG", - "coin": 195, - "type": "TRC20" - }, - { - "name": "Tether USD", - "symbol": "USDT", - "decimals": 6, - "token_id": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", - "coin": 195, - "type": "TRC20" - }, - { - "name": "Wuhan Fried Bats", - "symbol": "WUHAN", - "decimals": 4, - "token_id": "TSzjFRf8bQ46kRndWaHYKSq1P5HzRJfPvr", - "coin": 195, - "type": "TRC20" - }, - { - "name": "HelGro", - "symbol": "HGRO", - "decimals": 6, - "token_id": "TTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm", - "coin": 195, - "type": "TRC20" - } + "c195_t1000567", + "c195_tTCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9", + "c195_tTCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF", + "c195_tTG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK", + "c195_tTJSF4iVkzkRkYwEVNkqJkeGDaZpnFbGy9x", + "c195_tTLKyLt4MXuvvdFvUUc3Zma4rZyj2t87Mak", + "c195_tTLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7", + "c195_tTMCMPzmosnQ8UAYW1zcBwjLTxDq8ce4Y5e", + "c195_tTPt8DTDBZYfJ9fuyRjdWJr4PP68tRfptLG", + "c195_tTR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "c195_tTTvVC9jv5AfDdHuGeCMcQg6QftmNnfQiVm" ] diff --git a/platform/tron/stake.go b/platform/tron/stake.go index 54e276de7..35dff0d48 100644 --- a/platform/tron/stake.go +++ b/platform/tron/stake.go @@ -70,7 +70,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e } func (p *Platform) UndelegatedBalance(address string) (string, error) { - account, err := p.client.fetchAccount(address) + account, err := p.gridClient.fetchAccount(address) if err != nil { return "0", err } diff --git a/platform/tron/token.go b/platform/tron/token.go index 8d6bd6084..9c19291e3 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -1,86 +1,32 @@ package tron import ( - "strconv" - "strings" - "sync" - - log "github.com/sirupsen/logrus" - "github.com/trustwallet/golibs/coin" - "github.com/trustwallet/golibs/types" + "github.com/trustwallet/golibs/asset" ) -func (p *Platform) GetTokenListByAddress(address string) (types.TokenPage, error) { - tokens, err := p.client.fetchAccount(address) +func (p *Platform) GetTokenListByAddress(address string) ([]string, error) { + assetIds := make([]string, 0) + tokens, err := p.gridClient.fetchAccount(address) if err != nil { - return nil, err + return assetIds, err } - tokenPage := make(types.TokenPage, 0) if len(tokens.Data) == 0 { - return tokenPage, nil + return assetIds, nil } + data := tokens.Data[0] var tokenIds []string - for _, v := range tokens.Data[0].AssetsV2 { - tokenIds = append(tokenIds, v.Key) - } - - tokensChan := p.getTokens(tokenIds) - for info := range tokensChan { - tokenPage = append(tokenPage, info) + for _, v := range data.AssetsV2 { + tokenIds = append(assetIds, v.Key) } - - trc20Tokens, err := p.explorerClient.fetchAllTRC20Tokens(address) - if err != nil { - log.Error("Explorer error" + err.Error()) + for _, trc20Tokens := range data.Trc20 { + for key := range trc20Tokens { + tokenIds = append(tokenIds, key) + } } - - for _, t := range trc20Tokens { - tokenPage = append(tokenPage, types.Token{ - Name: t.Name, - Symbol: strings.ToUpper(t.Symbol), - Decimals: uint(t.Decimals), - TokenID: t.ContractAddress, - Coin: coin.Tron().ID, - Type: types.TRC20, - }) + for _, tokenId := range tokenIds { + assetIds = append(assetIds, asset.BuildID(p.Coin().ID, tokenId)) } - return tokenPage, nil -} - -func (p *Platform) getTokens(ids []string) chan types.Token { - tkChan := make(chan types.Token, len(ids)) - var wg sync.WaitGroup - for _, id := range ids { - wg.Add(1) - go func(i string, c chan types.Token) { - defer wg.Done() - _ = p.getTokensChannel(i, c) - }(id, tkChan) - } - wg.Wait() - close(tkChan) - return tkChan -} - -func (p *Platform) getTokensChannel(id string, tkChan chan types.Token) error { - info, err := p.client.fetchTokenInfo(id) - if err != nil || len(info.Data) == 0 { - return err - } - asset := NormalizeToken(info.Data[0]) - tkChan <- asset - return nil -} - -func NormalizeToken(info AssetInfo) types.Token { - return types.Token{ - Name: info.Name, - Symbol: strings.ToUpper(info.Symbol), - TokenID: strconv.Itoa(int(info.ID)), - Coin: coin.TRX, - Decimals: info.Decimals, - Type: types.TRC10, - } + return assetIds, nil } diff --git a/platform/tron/token_test.go b/platform/tron/token_test.go index 3246267c8..8ccde9594 100644 --- a/platform/tron/token_test.go +++ b/platform/tron/token_test.go @@ -10,26 +10,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/trustwallet/golibs/mock" - "github.com/trustwallet/golibs/types" ) -var ( - tokenDst = types.Token{ - Name: "Test", - Symbol: "TST", - Decimals: 8, - TokenID: "1", - Coin: 195, - Type: "TRC10", - } -) - -func TestNormalizeToken(t *testing.T) { - asset := AssetInfo{Name: "Test", Symbol: "TST", ID: 1, Decimals: 8} - actual := NormalizeToken(asset) - assert.Equal(t, tokenDst, actual) -} - func TestPlatform_GetTokenListByAddress(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() @@ -38,7 +20,7 @@ func TestPlatform_GetTokenListByAddress(t *testing.T) { res, err := p.GetTokenListByAddress("TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R") assert.Nil(t, err) sort.Slice(res, func(i, j int) bool { - return res[i].TokenID < res[j].TokenID + return res[i] < res[j] }) rawRes, err := json.Marshal(res) assert.Nil(t, err) diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index af8eb104f..8ee82b726 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -11,7 +11,7 @@ import ( ) func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { - Txs, err := p.client.fetchTxsOfAddress(address, "") + Txs, err := p.gridClient.fetchTxsOfAddress(address, "") if err != nil && len(Txs) == 0 { return nil, err } @@ -80,12 +80,12 @@ func addTokenMeta(tx *types.Tx, srcTx Tx, tokenInfo AssetInfo) { func (p *Platform) fetchTransactionsForTRC10Tokens(address, token string) (types.TxPage, error) { txs := make(types.TxPage, 0) - tokenTxs, err := p.client.fetchTxsOfAddress(address, token) + tokenTxs, err := p.gridClient.fetchTxsOfAddress(address, token) if err != nil { return nil, err } - info, err := p.client.fetchTokenInfo(token) + info, err := p.gridClient.fetchTokenInfo(token) if err != nil { return nil, err } diff --git a/services/notifier/base.go b/services/notifier/base.go index 872dd3b86..a942af319 100644 --- a/services/notifier/base.go +++ b/services/notifier/base.go @@ -7,6 +7,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" + "github.com/trustwallet/golibs/types" ) const ( @@ -14,23 +15,23 @@ const ( ) func RunNotifier(database *db.Instance, delivery amqp.Delivery) error { - txs, err := GetTransactionsFromDelivery(delivery, Notifier) + transactions, err := GetTransactionsFromDelivery(delivery, Notifier) if err != nil { - log.WithFields(log.Fields{"service": Notifier, "txs": txs}).Error("failed to get transactions: ", err) - return err + log.WithFields(log.Fields{"service": Notifier, "body": string(delivery.Body), "error": err}).Error("Unable to unmarshal MQ Message") + return nil } allAddresses := make([]string, 0) - for _, tx := range txs { + for _, tx := range transactions { allAddresses = append(allAddresses, tx.GetAddresses()...) } addresses := ToUniqueAddresses(allAddresses) for i := range addresses { - addresses[i] = strconv.Itoa(int(txs[0].Coin)) + "_" + addresses[i] + addresses[i] = strconv.Itoa(int(transactions[0].Coin)) + "_" + addresses[i] } - if len(txs) == 0 { + if len(transactions) == 0 { return nil } subscriptions, err := database.GetSubscriptions(addresses) @@ -38,13 +39,13 @@ func RunNotifier(database *db.Instance, delivery amqp.Delivery) error { return nil } - notifications := make([]TransactionNotification, 0) + notifications := make([]types.TransactionNotification, 0) for _, sub := range subscriptions { ua, _, ok := UnprefixedAddress(sub.Address) if !ok { continue } - notificationsForAddress := buildNotificationsByAddress(ua, txs) + notificationsForAddress := buildNotificationsByAddress(ua, transactions) notifications = append(notifications, notificationsForAddress...) } diff --git a/services/notifier/delivery.go b/services/notifier/delivery.go index e61ddbdef..4a5d3e534 100644 --- a/services/notifier/delivery.go +++ b/services/notifier/delivery.go @@ -22,7 +22,7 @@ func GetTransactionsFromDelivery(delivery amqp.Delivery, service string) (types. return transactions, nil } -func publishNotifications(notifications []TransactionNotification) error { +func publishNotifications(notifications []types.TransactionNotification) error { raw, err := json.Marshal(notifications) if err != nil { return err diff --git a/services/notifier/models.go b/services/notifier/models.go index c3d479483..37edf666e 100644 --- a/services/notifier/models.go +++ b/services/notifier/models.go @@ -2,19 +2,14 @@ package notifier import "github.com/trustwallet/golibs/types" -type TransactionNotification struct { - Action types.TransactionType `json:"action"` - Result types.Tx `json:"result"` -} - -func buildNotificationsByAddress(address string, txs types.Txs) []TransactionNotification { +func buildNotificationsByAddress(address string, txs types.Txs) []types.TransactionNotification { transactionsByAddress := toUniqueTransactions(findTransactionsByAddress(txs, address)) - result := make([]TransactionNotification, 0, len(transactionsByAddress)) + result := make([]types.TransactionNotification, 0, len(transactionsByAddress)) for _, tx := range transactionsByAddress { tx.Direction = tx.GetTransactionDirection(address) tx.InferUtxoValue(address, tx.Coin) - result = append(result, TransactionNotification{Action: tx.Type, Result: tx}) + result = append(result, types.TransactionNotification{Action: tx.Type, Result: tx}) } return result diff --git a/services/parser/parser.go b/services/parser/parser.go index aa255e7a1..e37a44a67 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -262,15 +262,15 @@ func SaveLastParsedBlock(params Params, blocks []types.Block) error { return nil } -func publish(params Params, txs types.Txs) error { +func publish(params Params, transactions types.Txs) error { - if len(txs) == 0 { + if len(transactions) == 0 { return nil } - body, err := json.Marshal(txs) + body, err := json.Marshal(transactions) if err != nil { - log.WithFields(log.Fields{"operation": "publish marshal", "coin": params.Api.Coin().Handle}).Error(err) + log.WithFields(log.Fields{"operation": "publish marshal", "transactions": transactions, "coin": params.Api.Coin().Handle}).Error(err) return err } return params.TransactionsExchange.Publish(body) diff --git a/services/subscriber/subscriber.go b/services/subscriber/subscriber.go index 84e884444..733ae36dd 100644 --- a/services/subscriber/subscriber.go +++ b/services/subscriber/subscriber.go @@ -8,35 +8,27 @@ import ( log "github.com/sirupsen/logrus" "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" - "github.com/trustwallet/blockatlas/pkg/blockatlas" -) - -type Subscriber string - -const ( - Notifications Subscriber = "notifications" - AddSubscription blockatlas.SubscriptionOperation = "AddSubscription" - DeleteSubscription blockatlas.SubscriptionOperation = "DeleteSubscription" + "github.com/trustwallet/golibs/types" ) func RunSubscriber(database *db.Instance, delivery amqp.Delivery) error { - var event blockatlas.SubscriptionEvent + var event types.SubscriptionEvent err := json.Unmarshal(delivery.Body, &event) if err != nil { - log.WithFields(log.Fields{"service": Notifications, "event": event}).Error(err) - return err + log.WithFields(log.Fields{"service": types.Notifications, "body": string(delivery.Body), "error": err}).Error("Unable to unmarshal MQ Message") + return nil } subscriptions := event.ParseSubscriptions(event.Subscriptions) switch event.Operation { - case AddSubscription: + case types.AddSubscription: err := database.CreateSubscriptions(subscriptions) if err != nil { - log.WithFields(log.Fields{"service": Notifications, "operation": event.Operation, "subscriptions": subscriptions}).Error(err) + log.WithFields(log.Fields{"service": types.Notifications, "operation": event.Operation, "subscriptions": subscriptions}).Error(err) return err } - log.WithFields(log.Fields{"service": Notifications, "operation": event.Operation, "subscriptions": len(subscriptions)}).Info("Add subscriptions") - case DeleteSubscription: + log.WithFields(log.Fields{"service": types.Notifications, "operation": event.Operation, "subscriptions": len(subscriptions)}).Info("Add subscriptions") + case types.DeleteSubscription: subscriptionsIds := make([]string, 0) for _, subscription := range subscriptions { subscriptionsIds = append(subscriptionsIds, subscription.AddressID()) diff --git a/services/tokenindexer/api.go b/services/tokenindexer/api.go index 551a4c86d..ff6d0c47e 100644 --- a/services/tokenindexer/api.go +++ b/services/tokenindexer/api.go @@ -3,10 +3,9 @@ package tokenindexer import ( "time" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" + "github.com/trustwallet/golibs/types" ) type Instance struct { @@ -31,7 +30,7 @@ func (i Instance) GetTokensByAddress(r GetTokensByAddressRequest) (GetTokensByAd for coin, coins := range r.AddressesByCoin { for _, address := range coins { - list = append(list, blockatlas.GetAddressID(coin, address)) + list = append(list, types.GetAddressID(coin, address)) } } from := time.Unix(int64(r.From), 0) diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index d3d70fbf8..44c2c970e 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -17,23 +17,23 @@ const ( ) func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) error { - txs, err := notifier.GetTransactionsFromDelivery(delivery, TokenIndexer) + transactions, err := notifier.GetTransactionsFromDelivery(delivery, TokenIndexer) if err != nil { - log.WithFields(log.Fields{"service": TokenIndexer, "txs": txs}).Error("failed to get transactions: ", err) - return err + log.WithFields(log.Fields{"service": TokenIndexer, "body": string(delivery.Body), "error": err}).Error("Unable to unmarshal MQ Message") + return nil } - txs = txs.FilterTransactionsByType([]types.TransactionType{ + transactions = transactions.FilterTransactionsByType([]types.TransactionType{ types.TxTokenTransfer, types.TxNativeTokenTransfer, }) - if len(txs) == 0 { + if len(transactions) == 0 { return nil } // Add new assets to db - assets := GetAssetsFromTransactions(txs) + assets := GetAssetsFromTransactions(transactions) err = database.AddNewAssets(assets) if err != nil { log.WithFields(log.Fields{"service": TokenIndexer}).Error("Failed to add new assets", err) @@ -41,7 +41,7 @@ func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) error { } // Add asset <> address association - addressAssetsMap := assetsMap(txs) + addressAssetsMap := assetsMap(transactions) return CreateAssociations(database, addressAssetsMap) } diff --git a/services/tokenindexer/indexer_subscribe.go b/services/tokenindexer/indexer_subscribe.go index 26cec46e5..bb87414b0 100644 --- a/services/tokenindexer/indexer_subscribe.go +++ b/services/tokenindexer/indexer_subscribe.go @@ -7,30 +7,37 @@ import ( "github.com/streadway/amqp" "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/subscriber" + "github.com/trustwallet/golibs/types" ) type ConsumerIndexer struct { Database *db.Instance TokensAPIs map[uint]blockatlas.TokensAPI Delivery func(*db.Instance, map[uint]blockatlas.TokensAPI, amqp.Delivery) error + Tag string } func (c ConsumerIndexer) Callback(msg amqp.Delivery) error { return c.Delivery(c.Database, c.TokensAPIs, msg) } +func (c ConsumerIndexer) ConsumerTag() string { + return c.Tag +} + func RunTokenIndexerSubscribe(database *db.Instance, apis map[uint]blockatlas.TokensAPI, delivery amqp.Delivery) error { - var event blockatlas.SubscriptionEvent + var event types.SubscriptionEvent err := json.Unmarshal(delivery.Body, &event) if err != nil { - log.WithFields(log.Fields{"service": SubscriptionsTokenIndexer, "event": event}).Error(err) - return err + log.WithFields(log.Fields{"service": SubscriptionsTokenIndexer, "body": string(delivery.Body), "error": err}).Error("Unable to unmarshal MQ Message") + return nil } + log.WithFields(log.Fields{"service": TokenIndexer, "event": event.Operation, "subscriptions": len(event.Subscriptions)}).Info("Processing") + subscriptions := event.ParseSubscriptions(event.Subscriptions) switch event.Operation { - case subscriber.AddSubscription: + case types.AddSubscription: addressAssetsMap := map[string][]string{} for _, coinAddress := range subscriptions { @@ -38,18 +45,14 @@ func RunTokenIndexerSubscribe(database *db.Instance, apis map[uint]blockatlas.To if !ok { continue } - assets, err := api.GetTokenListByAddress(coinAddress.Address) + assetIds, err := api.GetTokenListByAddress(coinAddress.Address) if err != nil { continue } - assetIds := make([]string, 0) - for _, asset := range assets { - assetIds = append(assetIds, asset.AssetId()) - } addressAssetsMap[coinAddress.AddressID()] = assetIds } return CreateAssociations(database, addressAssetsMap) - case subscriber.DeleteSubscription: + case types.DeleteSubscription: //No action is needed return nil } From 0b074e7c965c5348366a9edd3ec9fc1fbe6b7bee Mon Sep 17 00:00:00 2001 From: Iuga Mihai <50499646+miiu96@users.noreply.github.com> Date: Tue, 19 Jan 2021 08:30:52 +0200 Subject: [PATCH 462/506] Bug fix elrond integration (#1373) * ignore tx with negative value * rename --- platform/elrond/mocks/scr_negative_value.json | 9 ++++++++ platform/elrond/model.go | 5 +++++ platform/elrond/transaction.go | 4 ++++ platform/elrond/transaction_test.go | 22 ++++++++++--------- 4 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 platform/elrond/mocks/scr_negative_value.json diff --git a/platform/elrond/mocks/scr_negative_value.json b/platform/elrond/mocks/scr_negative_value.json new file mode 100644 index 000000000..a5cd93652 --- /dev/null +++ b/platform/elrond/mocks/scr_negative_value.json @@ -0,0 +1,9 @@ +{ + "hash": "a96ed4816f5312d00361cc16037e19e0cffa4765a79a808d54d89db58fd76aa6", + "value": "-2500000000000000000000", + "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqplllst77y4l", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqplllst77y4l", + "gasPrice": 1000000000, + "signature": "", + "status": "success" +} diff --git a/platform/elrond/model.go b/platform/elrond/model.go index 422cd49ab..705f8ea37 100644 --- a/platform/elrond/model.go +++ b/platform/elrond/model.go @@ -3,6 +3,7 @@ package elrond import ( "encoding/json" "math/big" + "strings" "time" "github.com/trustwallet/golibs/types" @@ -93,6 +94,10 @@ func (tx *Transaction) Direction(address string) types.Direction { } } +func (tx *Transaction) HasNegativeValue() bool { + return strings.HasPrefix(tx.Value, "-") +} + func (tx *Transaction) TxTimestamp(blockRound uint64) time.Duration { if int64(tx.Timestamp) != 0 { return tx.Timestamp diff --git a/platform/elrond/transaction.go b/platform/elrond/transaction.go index cf130b833..ebfdedf43 100644 --- a/platform/elrond/transaction.go +++ b/platform/elrond/transaction.go @@ -25,6 +25,10 @@ func NormalizeTxs(srcTxs []Transaction, address string, block Block) (txs []type // NormalizeTx converts an Elrond transaction into the generic model func NormalizeTx(srcTx Transaction, address string, block Block) (tx types.Tx, ok bool) { + if srcTx.HasNegativeValue() { + return types.Tx{}, false + } + tx = types.Tx{ ID: srcTx.Hash, Coin: coin.Elrond().ID, diff --git a/platform/elrond/transaction_test.go b/platform/elrond/transaction_test.go index afd23afb0..0d671811a 100644 --- a/platform/elrond/transaction_test.go +++ b/platform/elrond/transaction_test.go @@ -11,13 +11,14 @@ import ( ) var ( - userAddress = `erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0` - txTransferSrc1, _ = mock.JsonStringFromFilePath("mocks/tx.json") - txTransferSrc2, _ = mock.JsonStringFromFilePath("mocks/tx_2.json") - txTransferSrc3, _ = mock.JsonStringFromFilePath("mocks/tx_3.json") - txTransferSrc4, _ = mock.JsonStringFromFilePath("mocks/tx_4.json") - txTransferSrc5, _ = mock.JsonStringFromFilePath("mocks/tx_5.json") - txTransferSrc6, _ = mock.JsonStringFromFilePath("mocks/tx_6.json") + userAddress = `erd10yagg2vme2jns9zqf9xn8kl86fkc6dr063vnuj0mz2kk2jw0qwuqmfmaw0` + txTransferSrc1, _ = mock.JsonStringFromFilePath("mocks/tx.json") + txTransferSrc2, _ = mock.JsonStringFromFilePath("mocks/tx_2.json") + txTransferSrc3, _ = mock.JsonStringFromFilePath("mocks/tx_3.json") + txTransferSrc4, _ = mock.JsonStringFromFilePath("mocks/tx_4.json") + txTransferSrc5, _ = mock.JsonStringFromFilePath("mocks/tx_5.json") + txTransferSrc6, _ = mock.JsonStringFromFilePath("mocks/tx_6.json") + scrNegativeValue, _ = mock.JsonStringFromFilePath("mocks/scr_negative_value.json") txTransfer1Normalized = types.Tx{ ID: "30d404cc7a42b0158b95f6adfbf9a517627d60f6c7e497c1442dfdb6460285df", @@ -168,15 +169,16 @@ func TestNormalize(t *testing.T) { } func TestNormalizeTxs(t *testing.T) { - var tx1, tx2, tx3 Transaction + var tx1, tx2, tx3, scrNegative Transaction _ = json.Unmarshal([]byte(txTransferSrc1), &tx1) _ = json.Unmarshal([]byte(txTransferSrc1), &tx2) _ = json.Unmarshal([]byte(txTransferSrc1), &tx3) + _ = json.Unmarshal([]byte(scrNegativeValue), &scrNegative) - txs := []Transaction{tx1, tx2, tx3} + txs := []Transaction{tx1, tx2, tx3, scrNegative} normalizedTxs := NormalizeTxs(txs, userAddress, Block{}) - require.Equal(t, len(txs), len(normalizedTxs)) + require.Equal(t, len(txs)-1, len(normalizedTxs)) } func testNormalize(t *testing.T, _test *test) { From bc326fdc3e28e9b371cbb21ea7d0d01398d04a1c Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 19 Jan 2021 15:31:10 +0900 Subject: [PATCH 463/506] [Vechain] Fix VTHO token transaction direction (#1374) * Fix vtho tx direction * revert golibs --- ...eceipt.json => incoming_vtho_receipt.json} | 18 +-- platform/vechain/mocks/incoming_vtho_tx.json | 25 +++++ .../vechain/mocks/outgoing_vtho_receipt.json | 31 ++++++ platform/vechain/mocks/outgoing_vtho_tx.json | 25 +++++ platform/vechain/mocks/transfer_log.json | 25 ----- platform/vechain/transaction.go | 67 ++++++----- platform/vechain/transaction_test.go | 104 +++++++++--------- 7 files changed, 171 insertions(+), 124 deletions(-) rename platform/vechain/mocks/{transfer_receipt.json => incoming_vtho_receipt.json} (54%) create mode 100644 platform/vechain/mocks/incoming_vtho_tx.json create mode 100644 platform/vechain/mocks/outgoing_vtho_receipt.json create mode 100644 platform/vechain/mocks/outgoing_vtho_tx.json delete mode 100644 platform/vechain/mocks/transfer_log.json diff --git a/platform/vechain/mocks/transfer_receipt.json b/platform/vechain/mocks/incoming_vtho_receipt.json similarity index 54% rename from platform/vechain/mocks/transfer_receipt.json rename to platform/vechain/mocks/incoming_vtho_receipt.json index a134f1372..6e18c6bc8 100644 --- a/platform/vechain/mocks/transfer_receipt.json +++ b/platform/vechain/mocks/incoming_vtho_receipt.json @@ -1,15 +1,15 @@ { "gasUsed": 36582, - "gasPayer": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", + "gasPayer": "0xb5e883349e68ab59307d1604555ac890fac47128", "paid": "0x1fbad5f2e25570000", "reward": "0x984d9c8dd8008000", "reverted": false, "meta": { - "blockID": "0x0042e02cebd1bec003d31526dba338c1b9eeeefdef722fb147e9d31690fbff1e", - "blockNumber": 4382764, - "blockTimestamp": 1574278180, - "txID": "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", - "txOrigin": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405" + "blockID": "0x007ac4b1a18c0fc3a11f44285d6a42eff591a99312d303c105a4f4de7fa10575", + "blockNumber": 8045745, + "blockTimestamp": 1610958460, + "txID": "0xb356fa7b3a371f1518a5f9bc51e951d0dac2ef04d58b532c7ca50a52aa5cddb4", + "txOrigin": "0xb5e883349e68ab59307d1604555ac890fac47128" }, "outputs": [ { @@ -19,10 +19,10 @@ "address": "0x0000000000000000000000000000456e65726779", "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - "0x0000000000000000000000002c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", - "0x000000000000000000000000b5e883349e68ab59307d1604555ac890fac47128" + "0x000000000000000000000000b5e883349e68ab59307d1604555ac890fac47128", + "0x000000000000000000000000e99399dd211ef54c301a5d1aa813471d92122ea8" ], - "data": "0x000000000000000000000000000000000000000000000003afb087b876900000" + "data": "0x00000000000000000000000000000000000000000000003635c9adc5dea00000" } ], "transfers": [] diff --git a/platform/vechain/mocks/incoming_vtho_tx.json b/platform/vechain/mocks/incoming_vtho_tx.json new file mode 100644 index 000000000..93c7737c7 --- /dev/null +++ b/platform/vechain/mocks/incoming_vtho_tx.json @@ -0,0 +1,25 @@ +{ + "id": "0xb356fa7b3a371f1518a5f9bc51e951d0dac2ef04d58b532c7ca50a52aa5cddb4", + "chainTag": 74, + "blockRef": "0x007ac4b0b0c47a00", + "expiration": 720, + "clauses": [ + { + "to": "0x0000000000000000000000000000456e65726779", + "value": "0x0", + "data": "0xa9059cbb000000000000000000000000e99399dd211ef54c301a5d1aa813471d92122ea800000000000000000000000000000000000000000000003635c9adc5dea00000" + } + ], + "gasPriceCoef": 0, + "gas": 43245, + "origin": "0xb5e883349e68ab59307d1604555ac890fac47128", + "delegator": null, + "nonce": "0x2a2e2da5", + "dependsOn": null, + "size": 188, + "meta": { + "blockID": "0x007ac4b1a18c0fc3a11f44285d6a42eff591a99312d303c105a4f4de7fa10575", + "blockNumber": 8045745, + "blockTimestamp": 1610958460 + } +} diff --git a/platform/vechain/mocks/outgoing_vtho_receipt.json b/platform/vechain/mocks/outgoing_vtho_receipt.json new file mode 100644 index 000000000..72b86278d --- /dev/null +++ b/platform/vechain/mocks/outgoing_vtho_receipt.json @@ -0,0 +1,31 @@ +{ + "gasUsed": 36518, + "gasPayer": "0xe99399dd211ef54c301a5d1aa813471d92122ea8", + "paid": "0x1fac9ff84f3b70000", + "reward": "0x980966417c508000", + "reverted": false, + "meta": { + "blockID": "0x007ac4bc8090b67c3e3c395e5e986226eab3a8619250807cf32b0c247f6d513c", + "blockNumber": 8045756, + "blockTimestamp": 1610958570, + "txID": "0x0677f91de4787d295087acec0a7ba317b0019fbf296fed630fdb5afbfca97a58", + "txOrigin": "0xe99399dd211ef54c301a5d1aa813471d92122ea8" + }, + "outputs": [ + { + "contractAddress": null, + "events": [ + { + "address": "0x0000000000000000000000000000456e65726779", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000e99399dd211ef54c301a5d1aa813471d92122ea8", + "0x000000000000000000000000b5e883349e68ab59307d1604555ac890fac47128" + ], + "data": "0x0000000000000000000000000000000000000000000000006124fee993bc0000" + } + ], + "transfers": [] + } + ] +} diff --git a/platform/vechain/mocks/outgoing_vtho_tx.json b/platform/vechain/mocks/outgoing_vtho_tx.json new file mode 100644 index 000000000..93a05cbab --- /dev/null +++ b/platform/vechain/mocks/outgoing_vtho_tx.json @@ -0,0 +1,25 @@ +{ + "id": "0x0677f91de4787d295087acec0a7ba317b0019fbf296fed630fdb5afbfca97a58", + "chainTag": 74, + "blockRef": "0x007ac4babac47a00", + "expiration": 720, + "clauses": [ + { + "to": "0x0000000000000000000000000000456e65726779", + "value": "0x0", + "data": "0xa9059cbb000000000000000000000000b5e883349e68ab59307d1604555ac890fac471280000000000000000000000000000000000000000000000006124fee993bc0000" + } + ], + "gasPriceCoef": 0, + "gas": 43181, + "origin": "0xe99399dd211ef54c301a5d1aa813471d92122ea8", + "delegator": null, + "nonce": "0x2bb08067", + "dependsOn": null, + "size": 188, + "meta": { + "blockID": "0x007ac4bc8090b67c3e3c395e5e986226eab3a8619250807cf32b0c247f6d513c", + "blockNumber": 8045756, + "blockTimestamp": 1610958570 + } +} diff --git a/platform/vechain/mocks/transfer_log.json b/platform/vechain/mocks/transfer_log.json deleted file mode 100644 index e66c5e7b5..000000000 --- a/platform/vechain/mocks/transfer_log.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "id": "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", - "chainTag": 74, - "blockRef": "0x0042e02a2ae04200", - "expiration": 720, - "clauses": [ - { - "to": "0x0000000000000000000000000000456e65726779", - "value": "0x0", - "data": "0xa9059cbb000000000000000000000000b5e883349e68ab59307d1604555ac890fac47128000000000000000000000000000000000000000000000003afb087b876900000" - } - ], - "gasPriceCoef": 0, - "gas": 80000, - "origin": "0x2c7a8d5cce0d5e6a8a31233b7dc3dae9aae4b405", - "delegator": null, - "nonce": "0x4a8569d", - "dependsOn": null, - "size": 189, - "meta": { - "blockID": "0x0042e02cebd1bec003d31526dba338c1b9eeeefdef722fb147e9d31690fbff1e", - "blockNumber": 4382764, - "blockTimestamp": 1574278180 - } -} diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 5e7e9a09b..2272bac79 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -34,6 +34,12 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, er for t := range cTxs { txs = append(txs, t...) } + + // NormalizeTokenTransaction won't set tx direction anymore, set it here + for _, tx := range txs { + updateTransactionDirection(&tx, address) + } + return txs, nil } @@ -130,31 +136,22 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types if err != nil { continue } - topicsFrom, err := address.EIP55Checksum(getRecipientAddress(event.Topics[1])) - if err != nil { - continue - } - topicsTo, err := address.EIP55Checksum(getRecipientAddress(event.Topics[2])) - if err != nil { - continue - } - direction, err := getTokenTransactionDirectory(originSender, topicsFrom, topicsTo) + topicsTo, err := address.EIP55Checksum(getRecipientAddress(event.Topics[2])) if err != nil { continue } txs = append(txs, types.Tx{ - ID: srcTx.Id, - Coin: p.Coin().ID, - From: originSender, - To: originReceiver, - Fee: types.Amount(fee), - Date: srcTx.Meta.BlockTimestamp, - Type: types.TxTokenTransfer, - Block: srcTx.Meta.BlockNumber, - Status: types.StatusCompleted, - Direction: direction, + ID: srcTx.Id, + Coin: p.Coin().ID, + From: originSender, + To: originReceiver, + Fee: types.Amount(fee), + Date: srcTx.Meta.BlockTimestamp, + Type: types.TxTokenTransfer, + Block: srcTx.Meta.BlockNumber, + Status: types.StatusCompleted, Meta: types.TokenTransfer{ // the only supported Token on VeChain is its Gas token Name: gasTokenName, @@ -215,7 +212,7 @@ func (p *Platform) NormalizeTransaction(srcTx LogTransfer, trxId Tx, addr string return } - directory, err := getTransferDirectory(sender, recipient, addrChecksum) + direction, err := getTransactionDirection(sender, recipient, addrChecksum) if err != nil { return types.Tx{}, err } @@ -229,7 +226,7 @@ func (p *Platform) NormalizeTransaction(srcTx LogTransfer, trxId Tx, addr string Date: srcTx.Meta.BlockTimestamp, Type: types.TxTransfer, Block: srcTx.Meta.BlockNumber, - Direction: directory, + Direction: direction, Status: types.StatusCompleted, Meta: types.Transfer{ Value: types.Amount(value), @@ -253,28 +250,28 @@ func getRecipientAddress(hex string) string { return "0x" + hex[len(hex)-40:] } -func getTokenTransactionDirectory(originSender, topicsFrom, topicsTo string) (dir types.Direction, err error) { - if originSender == topicsFrom && originSender == topicsTo { - return types.DirectionSelf, nil - } - if originSender == topicsFrom && originSender != topicsTo { - return types.DirectionIncoming, nil +func updateTransactionDirection(tx *types.Tx, addr string) { + meta, ok := tx.Meta.(types.TokenTransfer) + if !ok { + return } - if originSender == topicsTo && originSender != topicsFrom { - return types.DirectionOutgoing, nil + direction, err := getTransactionDirection(tx.From, meta.To, addr) + if err != nil { + return } - return "", errors.New("Unknown direction") + tx.Direction = direction } -func getTransferDirectory(sender, recipient, addr string) (dir types.Direction, err error) { +func getTransactionDirection(sender, recipient, addr string) (types.Direction, error) { + if sender != addr && recipient != addr { + return "", errors.New("Unknown direction") + } if sender == addr && recipient == addr { return types.DirectionSelf, nil } - if sender == addr && recipient != addr { + if sender == addr { return types.DirectionOutgoing, nil - } - if recipient == addr && sender != addr { + } else { return types.DirectionIncoming, nil } - return "", errors.New("Unknown direction") } diff --git a/platform/vechain/transaction_test.go b/platform/vechain/transaction_test.go index 3c250832c..87fdd9691 100644 --- a/platform/vechain/transaction_test.go +++ b/platform/vechain/transaction_test.go @@ -10,16 +10,12 @@ import ( "github.com/trustwallet/golibs/types" ) -var ( - transferSrc, _ = mock.JsonStringFromFilePath("mocks/transfer.json") - trxId, _ = mock.JsonStringFromFilePath("mocks/tx_id.json") - transferLogSrc, _ = mock.JsonStringFromFilePath("mocks/transfer_log.json") - trxReceipt, _ = mock.JsonStringFromFilePath("mocks/transfer_receipt.json") - revertedTx, _ = mock.JsonStringFromFilePath("mocks/reverted_tx.json") - revertedReceipt, _ = mock.JsonStringFromFilePath("mocks/reverted_receipt.json") -) - func TestNormalizeTransaction(t *testing.T) { + var ( + transferSrc, _ = mock.JsonStringFromFilePath("mocks/transfer.json") + trxId, _ = mock.JsonStringFromFilePath("mocks/tx_id.json") + ) + tests := []struct { name string addr string @@ -68,35 +64,59 @@ func TestNormalizeTransaction(t *testing.T) { func TestNormalizeTokenTransaction(t *testing.T) { tests := []struct { - name string - txData string - txReceipt string - expected types.TxPage + name string + txFile string + receiptFile string + address string + expected types.TxPage }{ - {"Normalize VIP180 token transfer", transferLogSrc, trxReceipt, types.TxPage{ + {"Normalize outgoing VTHO tx", "outgoing_vtho_tx.json", "outgoing_vtho_receipt.json", "0xe99399dd211eF54c301A5d1AA813471d92122eA8", types.TxPage{ + { + ID: "0x0677f91de4787d295087acec0a7ba317b0019fbf296fed630fdb5afbfca97a58", + Coin: coin.VET, + From: "0xe99399dd211eF54c301A5d1AA813471d92122eA8", + To: "0x0000000000000000000000000000456E65726779", + Date: 1610958570, + Type: types.TxTokenTransfer, + Fee: types.Amount("36518000000000000000"), + Status: types.StatusCompleted, + Block: 8045756, + Direction: types.DirectionOutgoing, + Meta: types.TokenTransfer{ + Name: gasTokenName, + Symbol: gasTokenSymbol, + TokenID: "0x0000000000000000000000000000456E65726779", + From: "0xe99399dd211eF54c301A5d1AA813471d92122eA8", + To: "0xB5e883349e68aB59307d1604555AC890fAC47128", + Value: types.Amount("7000000000000000000"), + Decimals: 18, + }, + }, + }}, + {"Normalize incoming VTHO tx", "incoming_vtho_tx.json", "incoming_vtho_receipt.json", "0xe99399dd211eF54c301A5d1AA813471d92122eA8", types.TxPage{ { - ID: "0x42f5eba46ddcc458243c753545a3faa849502d078efbc5b74baddea9e6ea5b04", + ID: "0xb356fa7b3a371f1518a5f9bc51e951d0dac2ef04d58b532c7ca50a52aa5cddb4", Coin: coin.VET, - From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", + From: "0xB5e883349e68aB59307d1604555AC890fAC47128", To: "0x0000000000000000000000000000456E65726779", - Date: 1574278180, + Date: 1610958460, Type: types.TxTokenTransfer, Fee: types.Amount("36582000000000000000"), Status: types.StatusCompleted, - Block: 4382764, + Block: 8045745, Direction: types.DirectionIncoming, Meta: types.TokenTransfer{ Name: gasTokenName, Symbol: gasTokenSymbol, TokenID: "0x0000000000000000000000000000456E65726779", - From: "0x2c7A8d5ccE0d5E6a8a31233B7Dc3DAE9AaE4b405", - To: "0xB5e883349e68aB59307d1604555AC890fAC47128", - Value: types.Amount("68000000000000000000"), + From: "0xB5e883349e68aB59307d1604555AC890fAC47128", + To: "0xe99399dd211eF54c301A5d1AA813471d92122eA8", + Value: types.Amount("1000000000000000000000"), Decimals: 18, }, }, }}, - {"Normalize reverted token transfer", revertedTx, revertedReceipt, types.TxPage{ + {"Normalize reverted token transfer", "reverted_tx.json", "reverted_receipt.json", "0x7cFFB7632252Bae3766734d61F148f0Ea78Fc08C", types.TxPage{ { ID: "0x7fae32a743e42eaec54642e2a5742a185299f5b4bedaf12c60f65705661de932", Coin: coin.VET, @@ -116,16 +136,18 @@ func TestNormalizeTokenTransaction(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var tx Tx - err := json.Unmarshal([]byte(tt.txData), &tx) + err := mock.JsonModelFromFilePath("mocks/"+tt.txFile, &tx) assert.Nil(t, err) var receipt TxReceipt - errR := json.Unmarshal([]byte(tt.txReceipt), &receipt) - assert.Nil(t, errR) + err = mock.JsonModelFromFilePath("mocks/"+tt.receiptFile, &receipt) + assert.Nil(t, err) actual, err := platform.NormalizeTokenTransaction(tx, receipt) assert.Nil(t, err) + updateTransactionDirection(&actual[0], tt.address) + assert.Equal(t, len(actual), 1, "tx could not be normalized") assert.Equal(t, tt.expected, actual, "tx don't equal") }) @@ -174,35 +196,7 @@ func Test_getRecipientAddress(t *testing.T) { } } -func Test_getTokenTransactionDirectory(t *testing.T) { - addr1 := "0xb5e883349e68ab59307d1604555ac890fac47128" - addr2 := "0eec2bbedbb8b18357dab0b753cd1893bb832284" - tests := []struct { - name string - originSender string - topicsFrom string - topicsTo string - expected types.Direction - expectErr bool - }{ - {"Self direction", addr1, addr1, addr1, types.DirectionSelf, false}, - {"In direction", addr1, addr1, addr2, types.DirectionIncoming, false}, - {"Out direction", addr1, addr2, addr1, types.DirectionOutgoing, false}, - {"Unknown direction", addr1, addr2, addr2, "", true}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - actual, err := getTokenTransactionDirectory(tt.originSender, tt.topicsFrom, tt.topicsTo) - if tt.expectErr { - assert.NotNil(t, err) - } - assert.Equal(t, tt.expected, actual) - }) - } -} - -func Test_getTransferDirectory(t *testing.T) { +func Test_getTransactionDirection(t *testing.T) { addr1 := "0xb5e883349e68ab59307d1604555ac890fac47128" addr2 := "0eec2bbedbb8b18357dab0b753cd1893bb832284" tests := []struct { @@ -221,7 +215,7 @@ func Test_getTransferDirectory(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - actual, err := getTransferDirectory(tt.sender, tt.recipient, tt.address) + actual, err := getTransactionDirection(tt.sender, tt.recipient, tt.address) if tt.expectErr { assert.NotNil(t, err) } From 13762c2da986461d9943aff70cd0c4869dfd94e1 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Mon, 18 Jan 2021 23:30:39 -0800 Subject: [PATCH 464/506] Add Sentry Error handler (#1375) --- go.mod | 4 ++-- go.sum | 8 ++++---- internal/client.go | 27 +++------------------------ 3 files changed, 9 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index fe6c6b989..c4a79ff37 100644 --- a/go.mod +++ b/go.mod @@ -24,8 +24,8 @@ require ( 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.33 - github.com/trustwallet/golibs/network v0.0.0-20210113212158-b74318d7ab45 + github.com/trustwallet/golibs v0.0.34 + github.com/trustwallet/golibs/network v0.0.0-20210119064642-74e68ef98cfe golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect diff --git a/go.sum b/go.sum index b5904ba13..633a4d268 100644 --- a/go.sum +++ b/go.sum @@ -418,10 +418,10 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.33 h1:nADMzgTh/MH+4UHK/TfsZ77VVmMUrFPVIIyMBhbDW0M= -github.com/trustwallet/golibs v0.0.33/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= -github.com/trustwallet/golibs/network v0.0.0-20210113212158-b74318d7ab45 h1:zaobIG3KO/CHpY1o/rGouYFHCWIzLE6uYSUwz2JCLmw= -github.com/trustwallet/golibs/network v0.0.0-20210113212158-b74318d7ab45/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs v0.0.34 h1:/6XobjSYf2YZ5tqJLf4ZqhNZGNuXsRyM61ZCwt5tuxo= +github.com/trustwallet/golibs v0.0.34/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= +github.com/trustwallet/golibs/network v0.0.0-20210119064642-74e68ef98cfe h1:nQGIQUV8JQzYZLN0jNRW8v+p6+UlC83ikNGZCsrEHl8= +github.com/trustwallet/golibs/network v0.0.0-20210119064642-74e68ef98cfe/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= 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= diff --git a/internal/client.go b/internal/client.go index c134672d1..07c53dff4 100644 --- a/internal/client.go +++ b/internal/client.go @@ -1,40 +1,19 @@ package internal import ( - "net/http" - "strconv" - - "github.com/getsentry/raven-go" - log "github.com/sirupsen/logrus" "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/network/middleware" ) type Client struct { client.Request } -var errorHandler = func(res *http.Response, uri string) error { - statusCode := res.StatusCode - //Improve ways to identify if worth logging the error - if statusCode != http.StatusOK && statusCode != http.StatusNotFound { - log.WithFields(log.Fields{ - "tags": raven.Tags{ - {Key: "status_code", Value: strconv.Itoa(res.StatusCode)}, - {Key: "host", Value: res.Request.URL.Host}, - {Key: "url", Value: uri}, - }, - "fingerprint": []string{"client_errors"}, - }).Error("Client Errors") - } - - return nil -} - func InitClient(url string) client.Request { return client.Request{ Headers: map[string]string{}, HttpClient: client.DefaultClient, - ErrorHandler: errorHandler, + ErrorHandler: middleware.SentryErrorHandler, BaseUrl: url, } } @@ -47,7 +26,7 @@ func InitJSONClient(baseUrl string) client.Request { return client.Request{ Headers: headers, HttpClient: client.DefaultClient, - ErrorHandler: errorHandler, + ErrorHandler: middleware.SentryErrorHandler, BaseUrl: baseUrl, } } From 222822e8894fc904c387cfa12d66657cd1303ca8 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Tue, 19 Jan 2021 11:45:51 -0800 Subject: [PATCH 465/506] Consolidate Asset Response and Asset type (#1376) --- api/endpoint/collection.go | 2 +- api/endpoint/staking.go | 10 +++++----- go.mod | 2 +- go.sum | 2 ++ pkg/blockatlas/models.go | 5 ----- services/tokenindexer/api.go | 18 ++++++++++-------- services/tokenindexer/models.go | 13 ------------- 7 files changed, 19 insertions(+), 33 deletions(-) diff --git a/api/endpoint/collection.go b/api/endpoint/collection.go index f98012178..cebf4af70 100644 --- a/api/endpoint/collection.go +++ b/api/endpoint/collection.go @@ -37,7 +37,7 @@ func GetCollectiblesForSpecificCollectionAndOwner(c *gin.Context, api blockatlas // @Produce json // @Tags Collections // @Param data body string true "Payload" default({"60": ["0xb3624367b1ab37daef42e1a3a2ced012359659b0"]}) -// @Success 200 {object} blockatlas.DocsResponse +// @Success 200 {object} blockatlas.ResultsResponse // @Router /v4/collectibles/categories [post] func GetCollectionCategoriesFromList(c *gin.Context, apis blockatlas.CollectionsAPIs) { var reqs map[string][]string diff --git a/api/endpoint/staking.go b/api/endpoint/staking.go index 138e67a24..ec2b159c6 100644 --- a/api/endpoint/staking.go +++ b/api/endpoint/staking.go @@ -67,7 +67,7 @@ func GetStakeDelegationsWithAllInfoForBatch(c *gin.Context, apis map[string]bloc delegation.Delegations = sortDelegations(delegation.Delegations) batch = append(batch, delegation) } - c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &batch}) + c.JSON(http.StatusOK, blockatlas.ResultsResponse{Results: &batch}) } // @Summary Get Multiple Stake Delegations @@ -99,7 +99,7 @@ func GetStakeInfoForBatch(c *gin.Context, apis map[string]blockatlas.StakeAPI) { staking := getStakingResponse(p) batch = append(batch, staking) } - c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &batch}) + c.JSON(http.StatusOK, blockatlas.ResultsResponse{Results: &batch}) } // @Summary Get staking info by coin ID @@ -144,7 +144,7 @@ func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { staking := getStakingResponse(p) batch = append(batch, staking) } - c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &batch}) + c.JSON(http.StatusOK, blockatlas.ResultsResponse{Results: &batch}) } // @Summary Get Validators @@ -154,7 +154,7 @@ func GetStakeInfoForCoins(c *gin.Context, apis map[string]blockatlas.StakeAPI) { // @Produce json // @Tags Staking // @Param coin path string true "the coin name" default(cosmos) -// @Success 200 {object} blockatlas.DocsResponse +// @Success 200 {object} blockatlas.ResultsResponse // @Failure 500 {object} ErrorResponse // @Router /v2/{coin}/staking/validators [get] func GetValidators(c *gin.Context, api blockatlas.StakeAPI) { @@ -163,7 +163,7 @@ func GetValidators(c *gin.Context, api blockatlas.StakeAPI) { c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) return } - c.JSON(http.StatusOK, blockatlas.DocsResponse{Docs: &results}) + c.JSON(http.StatusOK, blockatlas.ResultsResponse{Results: &results}) } // @Summary Get Stake Delegations diff --git a/go.mod b/go.mod index c4a79ff37..96cab21f1 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( 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.34 + github.com/trustwallet/golibs v0.0.35 github.com/trustwallet/golibs/network v0.0.0-20210119064642-74e68ef98cfe golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect diff --git a/go.sum b/go.sum index 633a4d268..66c908b4c 100644 --- a/go.sum +++ b/go.sum @@ -420,6 +420,8 @@ 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.34 h1:/6XobjSYf2YZ5tqJLf4ZqhNZGNuXsRyM61ZCwt5tuxo= github.com/trustwallet/golibs v0.0.34/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= +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/network v0.0.0-20210119064642-74e68ef98cfe h1:nQGIQUV8JQzYZLN0jNRW8v+p6+UlC83ikNGZCsrEHl8= github.com/trustwallet/golibs/network v0.0.0-20210119064642-74e68ef98cfe/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= diff --git a/pkg/blockatlas/models.go b/pkg/blockatlas/models.go index 1a881bbd8..ec88d86e8 100644 --- a/pkg/blockatlas/models.go +++ b/pkg/blockatlas/models.go @@ -1,12 +1,7 @@ package blockatlas type ( - DocsResponse struct { - Docs interface{} `json:"docs"` - } - ResultsResponse struct { - Total int `json:"total"` Results interface{} `json:"docs"` } ) diff --git a/services/tokenindexer/api.go b/services/tokenindexer/api.go index ff6d0c47e..72c502585 100644 --- a/services/tokenindexer/api.go +++ b/services/tokenindexer/api.go @@ -3,6 +3,8 @@ package tokenindexer import ( "time" + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/db" "github.com/trustwallet/blockatlas/db/models" "github.com/trustwallet/golibs/types" @@ -16,11 +18,11 @@ func Init(database *db.Instance) Instance { return Instance{database: database} } -func (i Instance) GetNewTokensRequest(r Request) (Response, error) { +func (i Instance) GetNewTokensRequest(r Request) (blockatlas.ResultsResponse, error) { from := time.Unix(r.From, 0) result, err := i.database.GetAssetsFrom(from) if err != nil { - return Response{}, err + return blockatlas.ResultsResponse{}, err } return normalize(result), nil } @@ -48,17 +50,17 @@ func (i Instance) GetTokensByAddress(r GetTokensByAddressRequest) (GetTokensByAd return assetIds, nil } -func normalize(dbAssets []models.Asset) Response { - var result []Asset +func normalize(dbAssets []models.Asset) blockatlas.ResultsResponse { + var result []types.Asset for _, a := range dbAssets { - asset := Asset{ - Asset: a.Asset, + asset := types.Asset{ + Id: a.Asset, Name: a.Name, Symbol: a.Symbol, - Type: a.Type, + Type: types.TokenType(a.Type), Decimals: a.Decimals, } result = append(result, asset) } - return Response{Assets: result} + return blockatlas.ResultsResponse{Results: result} } diff --git a/services/tokenindexer/models.go b/services/tokenindexer/models.go index 0b9fc3b45..230551132 100644 --- a/services/tokenindexer/models.go +++ b/services/tokenindexer/models.go @@ -12,16 +12,3 @@ type ( GetTokensByAddressResponse []string ) - -type Response struct { - Assets []Asset `json:"assets"` -} - -type Asset struct { - Asset string `json:"asset"` - Name string `json:"name"` - Symbol string `json:"symbol"` - Type string `json:"type"` - - Decimals uint `json:"decimals"` -} From d26234547724c5a27ebed6043feb78bf1d53f31c Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 21 Jan 2021 10:02:38 -0800 Subject: [PATCH 466/506] Upgrade to golibs v0.0.39 and client update (#1378) --- go.mod | 4 ++-- go.sum | 4 ++++ internal/client.go | 32 -------------------------------- platform/aeternity/base.go | 5 +++-- platform/aion/base.go | 5 +++-- platform/algorand/client.go | 13 +++++-------- platform/binance/client.go | 4 ++-- platform/bitcoin/base.go | 5 +++-- platform/cosmos/base.go | 5 +++-- platform/elrond/base.go | 5 +++-- platform/ethereum/base.go | 9 +++++---- platform/filecoin/base.go | 7 ++++--- platform/fio/base.go | 5 +++-- platform/harmony/base.go | 5 +++-- platform/icon/base.go | 5 +++-- platform/iotex/base.go | 5 +++-- platform/kava/base.go | 5 +++-- platform/nano/base.go | 5 +++-- platform/near/base.go | 5 +++-- platform/nebulas/base.go | 5 +++-- platform/nimiq/base.go | 5 +++-- platform/ontology/base.go | 5 +++-- platform/polkadot/base.go | 5 +++-- platform/ripple/base.go | 5 +++-- platform/solana/base.go | 5 +++-- platform/stellar/base.go | 5 +++-- platform/tezos/base.go | 9 +++++---- platform/theta/base.go | 5 +++-- platform/tron/base.go | 7 ++++--- platform/vechain/base.go | 5 +++-- platform/waves/base.go | 5 +++-- platform/zilliqa/base.go | 7 ++++--- services/assets/client.go | 5 +++-- 33 files changed, 104 insertions(+), 107 deletions(-) delete mode 100644 internal/client.go diff --git a/go.mod b/go.mod index 96cab21f1..fc88b66d3 100644 --- a/go.mod +++ b/go.mod @@ -24,8 +24,8 @@ require ( 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.35 - github.com/trustwallet/golibs/network v0.0.0-20210119064642-74e68ef98cfe + github.com/trustwallet/golibs v0.0.39 + github.com/trustwallet/golibs/network v0.0.0-20210121062720-6eaa67ade593 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect diff --git a/go.sum b/go.sum index 66c908b4c..25c629115 100644 --- a/go.sum +++ b/go.sum @@ -422,8 +422,12 @@ github.com/trustwallet/golibs v0.0.34 h1:/6XobjSYf2YZ5tqJLf4ZqhNZGNuXsRyM61ZCwt5 github.com/trustwallet/golibs v0.0.34/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= 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.39 h1:OQ+zkc6mr266e3BCXwxg8NppkyDPKpvTHVJS7ejVML4= +github.com/trustwallet/golibs v0.0.39/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= github.com/trustwallet/golibs/network v0.0.0-20210119064642-74e68ef98cfe h1:nQGIQUV8JQzYZLN0jNRW8v+p6+UlC83ikNGZCsrEHl8= github.com/trustwallet/golibs/network v0.0.0-20210119064642-74e68ef98cfe/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs/network v0.0.0-20210121062720-6eaa67ade593 h1:J+nbswDE9lS2ITYW4SgFxTvo8lz+LEwIokyZZaC58Ps= +github.com/trustwallet/golibs/network v0.0.0-20210121062720-6eaa67ade593/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= diff --git a/internal/client.go b/internal/client.go deleted file mode 100644 index 07c53dff4..000000000 --- a/internal/client.go +++ /dev/null @@ -1,32 +0,0 @@ -package internal - -import ( - "github.com/trustwallet/golibs/client" - "github.com/trustwallet/golibs/network/middleware" -) - -type Client struct { - client.Request -} - -func InitClient(url string) client.Request { - return client.Request{ - Headers: map[string]string{}, - HttpClient: client.DefaultClient, - ErrorHandler: middleware.SentryErrorHandler, - BaseUrl: url, - } -} - -func InitJSONClient(baseUrl string) client.Request { - headers := map[string]string{ - "Content-Type": "application/json", - "Accept": "application/json", - } - return client.Request{ - Headers: headers, - HttpClient: client.DefaultClient, - ErrorHandler: middleware.SentryErrorHandler, - BaseUrl: baseUrl, - } -} diff --git a/platform/aeternity/base.go b/platform/aeternity/base.go index 840d7f2fb..3ce61c221 100644 --- a/platform/aeternity/base.go +++ b/platform/aeternity/base.go @@ -1,8 +1,9 @@ package aeternity import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/aion/base.go b/platform/aion/base.go index aa5705e0d..e110731dd 100644 --- a/platform/aion/base.go +++ b/platform/aion/base.go @@ -1,8 +1,9 @@ package aion import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/algorand/client.go b/platform/algorand/client.go index cc30c32fc..427ce7468 100644 --- a/platform/algorand/client.go +++ b/platform/algorand/client.go @@ -4,6 +4,8 @@ import ( "fmt" "strconv" + "github.com/trustwallet/golibs/network/middleware" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/client" ) @@ -13,14 +15,9 @@ type Client struct { } func InitClient(url, apiKey string) Client { - return Client{ - Request: client.Request{ - HttpClient: client.DefaultClient, - ErrorHandler: client.DefaultErrorHandler, - Headers: map[string]string{"X-Indexer-API-Token": apiKey}, - BaseUrl: url, - }, - } + request := client.InitClient(url, middleware.SentryErrorHandler) + request.Headers = map[string]string{"X-Indexer-API-Token": apiKey} + return Client{request} } func (c *Client) GetLatestBlock() (int64, error) { diff --git a/platform/binance/client.go b/platform/binance/client.go index b48caa7da..64549b6aa 100644 --- a/platform/binance/client.go +++ b/platform/binance/client.go @@ -6,7 +6,7 @@ import ( "strconv" "time" - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/network/middleware" "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/types" @@ -17,7 +17,7 @@ type Client struct { } func InitClient(url, apiKey string) Client { - c := Client{internal.InitClient(url)} + c := Client{client.InitClient(url, middleware.SentryErrorHandler)} c.Headers["apikey"] = apiKey return c } diff --git a/platform/bitcoin/base.go b/platform/bitcoin/base.go index 742ed96f0..15f0a281d 100644 --- a/platform/bitcoin/base.go +++ b/platform/bitcoin/base.go @@ -1,9 +1,10 @@ package bitcoin import ( - "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/platform/bitcoin/blockbook" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -14,7 +15,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: blockbook.Client{Request: internal.InitClient(api)}, + client: blockbook.Client{Request: client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/cosmos/base.go b/platform/cosmos/base.go index 72aa87af3..f5842cd0d 100644 --- a/platform/cosmos/base.go +++ b/platform/cosmos/base.go @@ -1,8 +1,9 @@ package cosmos import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -13,7 +14,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/elrond/base.go b/platform/elrond/base.go index f531b4345..eeb64940c 100644 --- a/platform/elrond/base.go +++ b/platform/elrond/base.go @@ -1,8 +1,9 @@ package elrond import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -13,7 +14,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{internal.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index 7829984bb..c2b528bef 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -1,11 +1,12 @@ package ethereum import ( - "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/platform/bitcoin/blockbook" "github.com/trustwallet/blockatlas/platform/ethereum/collection" "github.com/trustwallet/blockatlas/platform/ethereum/trustray" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -19,7 +20,7 @@ func Init(coinType uint, api, rpc string) *Platform { return &Platform{ CoinIndex: coinType, RpcURL: rpc, - client: &trustray.Client{Request: internal.InitClient(api)}, + client: &trustray.Client{Request: client.InitClient(api, middleware.SentryErrorHandler)}, } } @@ -27,13 +28,13 @@ func InitWithBlockbook(coinType uint, blockbookApi, rpc string) *Platform { return &Platform{ CoinIndex: coinType, RpcURL: rpc, - client: &blockbook.Client{Request: internal.InitClient(blockbookApi)}, + client: &blockbook.Client{Request: client.InitClient(blockbookApi, middleware.SentryErrorHandler)}, } } func InitWithCollection(coinType uint, rpc, blockbookApi, collectionApi, collectionKey string) *Platform { platform := InitWithBlockbook(coinType, blockbookApi, rpc) - platform.collectible = collection.Client{Request: internal.InitClient(collectionApi)} + platform.collectible = collection.Client{Request: client.InitClient(collectionApi, middleware.SentryErrorHandler)} platform.collectible.Headers["X-API-KEY"] = collectionKey return platform } diff --git a/platform/filecoin/base.go b/platform/filecoin/base.go index 471527078..97016a4d1 100644 --- a/platform/filecoin/base.go +++ b/platform/filecoin/base.go @@ -1,10 +1,11 @@ package filecoin import ( - "github.com/trustwallet/blockatlas/internal" "github.com/trustwallet/blockatlas/platform/filecoin/explorer" "github.com/trustwallet/blockatlas/platform/filecoin/rpc" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -14,8 +15,8 @@ type Platform struct { func Init(api, explorerApi string) *Platform { p := &Platform{ - client: rpc.Client{Request: internal.InitClient(api)}, - explorer: explorer.Client{Request: internal.InitClient(explorerApi)}, + client: rpc.Client{Request: client.InitClient(api, middleware.SentryErrorHandler)}, + explorer: explorer.Client{Request: client.InitClient(explorerApi, middleware.SentryErrorHandler)}, } return p } diff --git a/platform/fio/base.go b/platform/fio/base.go index 3e13fca08..1605417b7 100644 --- a/platform/fio/base.go +++ b/platform/fio/base.go @@ -1,8 +1,9 @@ package fio import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/harmony/base.go b/platform/harmony/base.go index 3e3805d8d..1d4d766db 100644 --- a/platform/harmony/base.go +++ b/platform/harmony/base.go @@ -1,8 +1,9 @@ package harmony import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{internal.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api, middleware.SentryErrorHandler)}, } return p } diff --git a/platform/icon/base.go b/platform/icon/base.go index 1a025de2d..8d1562995 100644 --- a/platform/icon/base.go +++ b/platform/icon/base.go @@ -1,8 +1,9 @@ package icon import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/iotex/base.go b/platform/iotex/base.go index f216a49c6..bed4435e3 100644 --- a/platform/iotex/base.go +++ b/platform/iotex/base.go @@ -1,8 +1,9 @@ package iotex import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/kava/base.go b/platform/kava/base.go index 5cd3a8f75..f7f580cdd 100644 --- a/platform/kava/base.go +++ b/platform/kava/base.go @@ -1,8 +1,9 @@ package kava import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -13,7 +14,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/nano/base.go b/platform/nano/base.go index dfd3dfe6e..ce657bab4 100644 --- a/platform/nano/base.go +++ b/platform/nano/base.go @@ -1,8 +1,9 @@ package nano import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{internal.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api, middleware.SentryErrorHandler)}, } return p } diff --git a/platform/near/base.go b/platform/near/base.go index b10c7422d..427c7927d 100644 --- a/platform/near/base.go +++ b/platform/near/base.go @@ -1,8 +1,9 @@ package near import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } return p } diff --git a/platform/nebulas/base.go b/platform/nebulas/base.go index 5b71800a0..99dfedff4 100644 --- a/platform/nebulas/base.go +++ b/platform/nebulas/base.go @@ -1,8 +1,9 @@ package nebulas import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/nimiq/base.go b/platform/nimiq/base.go index fdcaeeff5..7a65ee9fe 100644 --- a/platform/nimiq/base.go +++ b/platform/nimiq/base.go @@ -1,8 +1,9 @@ package nimiq import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/ontology/base.go b/platform/ontology/base.go index 8f6d92bec..a46941389 100644 --- a/platform/ontology/base.go +++ b/platform/ontology/base.go @@ -1,8 +1,9 @@ package ontology import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/polkadot/base.go b/platform/polkadot/base.go index 665c875ea..0d6cb9ab2 100644 --- a/platform/polkadot/base.go +++ b/platform/polkadot/base.go @@ -1,8 +1,9 @@ package polkadot import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -13,7 +14,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{internal.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/ripple/base.go b/platform/ripple/base.go index b3f584285..1c09c9621 100644 --- a/platform/ripple/base.go +++ b/platform/ripple/base.go @@ -1,8 +1,9 @@ package ripple import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/solana/base.go b/platform/solana/base.go index a017ba9ce..d693e29ad 100644 --- a/platform/solana/base.go +++ b/platform/solana/base.go @@ -1,8 +1,9 @@ package solana import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { p := &Platform{ - client: Client{internal.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api, middleware.SentryErrorHandler)}, } return p } diff --git a/platform/stellar/base.go b/platform/stellar/base.go index 321362456..8b3c9726b 100644 --- a/platform/stellar/base.go +++ b/platform/stellar/base.go @@ -1,8 +1,9 @@ package stellar import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -13,7 +14,7 @@ type Platform struct { func Init(coin uint, api string) *Platform { return &Platform{ CoinIndex: coin, - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/tezos/base.go b/platform/tezos/base.go index 625f09401..eee523d40 100644 --- a/platform/tezos/base.go +++ b/platform/tezos/base.go @@ -1,8 +1,9 @@ package tezos import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -13,9 +14,9 @@ type Platform struct { func Init(api, rpc, baker string) *Platform { p := &Platform{ - client: Client{internal.InitClient(api)}, - rpcClient: RpcClient{internal.InitClient(rpc)}, - bakerClient: BakerClient{internal.InitClient(baker)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, + rpcClient: RpcClient{client.InitClient(rpc, middleware.SentryErrorHandler)}, + bakerClient: BakerClient{client.InitClient(baker, middleware.SentryErrorHandler)}, } p.client.SetTimeout(35) return p diff --git a/platform/theta/base.go b/platform/theta/base.go index 05d735c79..503aa1acd 100644 --- a/platform/theta/base.go +++ b/platform/theta/base.go @@ -1,8 +1,9 @@ package theta import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/tron/base.go b/platform/tron/base.go index e6cb9b572..71359f210 100644 --- a/platform/tron/base.go +++ b/platform/tron/base.go @@ -1,8 +1,9 @@ package tron import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -12,8 +13,8 @@ type Platform struct { func Init(api, gridApi string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, - gridClient: GridClient{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, + gridClient: GridClient{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/vechain/base.go b/platform/vechain/base.go index e1e532e06..cd9a01e64 100644 --- a/platform/vechain/base.go +++ b/platform/vechain/base.go @@ -1,8 +1,9 @@ package vechain import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitJSONClient(api)}, + client: Client{client.InitJSONClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/waves/base.go b/platform/waves/base.go index d9a2a70a7..2a38b9a7b 100644 --- a/platform/waves/base.go +++ b/platform/waves/base.go @@ -1,8 +1,9 @@ package waves import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -11,7 +12,7 @@ type Platform struct { func Init(api string) *Platform { return &Platform{ - client: Client{internal.InitClient(api)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, } } diff --git a/platform/zilliqa/base.go b/platform/zilliqa/base.go index 2fe8c7790..2e3813416 100644 --- a/platform/zilliqa/base.go +++ b/platform/zilliqa/base.go @@ -1,8 +1,9 @@ package zilliqa import ( - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { @@ -12,8 +13,8 @@ type Platform struct { func Init(api, apiKey, rpc string) *Platform { p := &Platform{ - client: Client{internal.InitClient(api)}, - rpcClient: RpcClient{internal.InitClient(rpc)}, + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, + rpcClient: RpcClient{client.InitClient(rpc, middleware.SentryErrorHandler)}, } p.client.Headers["X-APIKEY"] = apiKey return p diff --git a/services/assets/client.go b/services/assets/client.go index e82e995e7..1d8ae5cae 100644 --- a/services/assets/client.go +++ b/services/assets/client.go @@ -3,8 +3,9 @@ package assets import ( "time" - "github.com/trustwallet/blockatlas/internal" + "github.com/trustwallet/golibs/network/middleware" + "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" ) @@ -14,7 +15,7 @@ const ( func GetchValidatorsInfo(coin coin.Coin) (AssetValidators, error) { var results AssetValidators - request := internal.InitClient(URL + coin.Handle) + request := client.InitClient(URL+coin.Handle, middleware.SentryErrorHandler) err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) if err != nil { return nil, err From a722330b69138ada884ee03f362dd79fbdf874e6 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 22 Jan 2021 10:23:54 +0900 Subject: [PATCH 467/506] [Collection] Add bounce collection api (#1329) * add bounce collection api * Fix collectibles/categories * address review comments --- config.yml | 8 +- config/configuration.go | 10 +- pkg/blockatlas/collectible.go | 7 ++ platform/ethereum/base.go | 16 ++- platform/ethereum/block.go | 11 ++ platform/ethereum/bounce/client.go | 88 +++++++++++++++ platform/ethereum/bounce/collection.go | 103 ++++++++++++++++++ platform/ethereum/bounce/model.go | 48 ++++++++ platform/ethereum/client.go | 13 +-- platform/ethereum/collection.go | 71 +----------- platform/ethereum/collection/client.go | 33 ------ platform/ethereum/opensea/client.go | 40 +++++++ platform/ethereum/opensea/collection.go | 76 +++++++++++++ .../ethereum/{ => opensea}/collection_test.go | 7 +- .../mocks/opensea_collectible.json | 0 .../mocks/opensea_collections.json | 0 .../ethereum/{collection => opensea}/model.go | 2 +- platform/ethereum/transaction.go | 4 + platform/platform.go | 9 +- 19 files changed, 414 insertions(+), 132 deletions(-) create mode 100644 pkg/blockatlas/collectible.go create mode 100644 platform/ethereum/block.go create mode 100644 platform/ethereum/bounce/client.go create mode 100644 platform/ethereum/bounce/collection.go create mode 100644 platform/ethereum/bounce/model.go delete mode 100644 platform/ethereum/collection/client.go create mode 100644 platform/ethereum/opensea/client.go create mode 100644 platform/ethereum/opensea/collection.go rename platform/ethereum/{ => opensea}/collection_test.go (96%) rename platform/ethereum/{ => opensea}/mocks/opensea_collectible.json (100%) rename platform/ethereum/{ => opensea}/mocks/opensea_collections.json (100%) rename platform/ethereum/{collection => opensea}/model.go (99%) diff --git a/config.yml b/config.yml index 72640d54b..69d0bdc8b 100644 --- a/config.yml +++ b/config.yml @@ -214,9 +214,11 @@ elrond: filecoin: api: https://api.filscan.io:8700/rpc/v1 explorer: https://filfox.info - # bsc: - # api: - # rpc: + +# smartchain: +# api: +# rpc: https://bsc-dataseed.nariox.org +# collections_api: https://nftview.bounce.finance sentry: dsn: "" diff --git a/config/configuration.go b/config/configuration.go index 301536566..175ba4e26 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -68,12 +68,14 @@ type Configuration struct { RPC string `mapstructure:"rpc"` } `mapstructure:"classic"` Smartchain struct { - API string `mapstructure:"api"` - RPC string `mapstructure:"rpc"` + 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"` + API string `mapstructure:"api"` + RPC string `mapstructure:"rpc"` + CollectionsAPI string `mapstructure:"collections_api"` } `mapstructure:"bsc"` Poa struct { API string `mapstructure:"api"` diff --git a/pkg/blockatlas/collectible.go b/pkg/blockatlas/collectible.go new file mode 100644 index 000000000..4d478a4c4 --- /dev/null +++ b/pkg/blockatlas/collectible.go @@ -0,0 +1,7 @@ +package blockatlas + +import "fmt" + +func GenCollectibleId(contract, tokenId string) string { + return fmt.Sprintf("%s-%s", contract, tokenId) +} diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index c2b528bef..3cf04c24d 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -2,7 +2,8 @@ package ethereum import ( "github.com/trustwallet/blockatlas/platform/bitcoin/blockbook" - "github.com/trustwallet/blockatlas/platform/ethereum/collection" + "github.com/trustwallet/blockatlas/platform/ethereum/bounce" + "github.com/trustwallet/blockatlas/platform/ethereum/opensea" "github.com/trustwallet/blockatlas/platform/ethereum/trustray" "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" @@ -13,7 +14,7 @@ type Platform struct { CoinIndex uint RpcURL string client EthereumClient - collectible collection.Client + collectible CollectibleClient } func Init(coinType uint, api, rpc string) *Platform { @@ -32,10 +33,15 @@ func InitWithBlockbook(coinType uint, blockbookApi, rpc string) *Platform { } } -func InitWithCollection(coinType uint, rpc, blockbookApi, collectionApi, collectionKey string) *Platform { +func InitWithOpenSea(coinType uint, rpc, blockbookApi, collectionApi, collectionKey string) *Platform { platform := InitWithBlockbook(coinType, blockbookApi, rpc) - platform.collectible = collection.Client{Request: client.InitClient(collectionApi, middleware.SentryErrorHandler)} - platform.collectible.Headers["X-API-KEY"] = collectionKey + platform.collectible = opensea.InitClient(collectionApi, collectionKey) + return platform +} + +func InitWithBounce(coinType uint, rpc, blockbookApi, collectionApi string) *Platform { + platform := InitWithBlockbook(coinType, blockbookApi, rpc) + platform.collectible = bounce.InitClient(collectionApi) return platform } diff --git a/platform/ethereum/block.go b/platform/ethereum/block.go new file mode 100644 index 000000000..b8860090d --- /dev/null +++ b/platform/ethereum/block.go @@ -0,0 +1,11 @@ +package ethereum + +import "github.com/trustwallet/golibs/types" + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.GetCurrentBlockNumber() +} + +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { + return p.client.GetBlockByNumber(num, p.CoinIndex) +} diff --git a/platform/ethereum/bounce/client.go b/platform/ethereum/bounce/client.go new file mode 100644 index 000000000..04fb8cd97 --- /dev/null +++ b/platform/ethereum/bounce/client.go @@ -0,0 +1,88 @@ +package bounce + +import ( + "errors" + "fmt" + "net/url" + "strconv" + "strings" + + "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/network/middleware" +) + +const ( + httpScheme = "http" + ipfsScheme = "ipfs" +) + +type Client struct { + client.Request +} + +func InitClient(url string) *Client { + c := Client{client.InitClient(url, middleware.SentryErrorHandler)} + return &c +} + +func (c Client) getCollections(owner string, chainId int) ([]Collection, error) { + query := url.Values{ + "address": {owner}, + "chain_id": {strconv.Itoa(chainId)}, + } + var resp CollectionResponse + err := c.Get(&resp, "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) { + query := url.Values{ + "user_addr": {owner}, + "contract_addr": {collectionID}, + "chain_id": {strconv.Itoa(chainId)}, + } + + var resp CollectibleResponse + err := c.Get(&resp, "erc721", query) + if err != nil { + return nil, err + } + return resp.Data.Collectibles, err +} + +func fetchTokenURI(uri string) (info CollectionInfo, err error) { + url, err := url.Parse(uri) + if err != nil { + return + } + + var c client.Request + if strings.HasPrefix(url.Scheme, httpScheme) { + c = client.InitClient(uri, middleware.SentryErrorHandler) + } else if strings.HasPrefix(url.Scheme, ipfsScheme) { + c = client.InitClient(ipfsGatewayUrl(url), middleware.SentryErrorHandler) + } else { + return info, errors.New("not supported url scheme: " + url.Scheme) + } + + err = c.Get(&info, "", nil) + return +} + +func normalizeImageUrl(uri string) string { + url, err := url.Parse(uri) + if err != nil { + return uri + } + if url.Scheme != ipfsScheme { + return uri + } + return ipfsGatewayUrl(url) +} + +func ipfsGatewayUrl(url *url.URL) string { + return fmt.Sprintf("https://ipfs.io/ipfs/%s%s", url.Host, url.Path) +} diff --git a/platform/ethereum/bounce/collection.go b/platform/ethereum/bounce/collection.go new file mode 100644 index 000000000..0058cf6ce --- /dev/null +++ b/platform/ethereum/bounce/collection.go @@ -0,0 +1,103 @@ +package bounce + +import ( + "strconv" + + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" +) + +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) + if err != nil { + return nil, err + } + return c.NormalizeCollections(collections, coinIndex, owner) + +} + +func (c *Client) GetCollectibles(owner, collectionID string, coinIndex uint) (types.CollectiblePage, error) { + collectibles, err := c.getCollectibles(owner, collectionID, bscChainId) + if err != nil { + return nil, err + } + return c.NormalizeCollectibles(collectibles, coinIndex) +} + +func (c *Client) NormalizeCollections(collections []Collection, coinIndex uint, owner string) (types.CollectionPage, error) { + page := make(types.CollectionPage, 0) + category := map[string]bool{} + for _, cl := range collections { + + // existed category + if _, ok := category[cl.ContractAddr]; ok { + continue + } + + total, err := strconv.Atoi(cl.Balance) + if err != nil { + continue + } + // skip empty info token + if len(cl.TokenURI) == 0 { + continue + } + + info, err := fetchTokenURI(cl.TokenURI) + if err != nil { + return nil, err + } + + // skip empty name/image + if len(info.Name) == 0 || len(info.Image) == 0 { + continue + } + + page = append(page, types.Collection{ + Id: cl.ContractAddr, + Name: info.Name, + ImageUrl: normalizeImageUrl(info.Image), + Description: info.Description, + ExternalLink: cl.TokenURI, + Total: total, + Address: owner, + Coin: coinIndex, + Type: "ERC" + cl.TokenType, + }) + category[cl.ContractAddr] = true + } + return page, nil +} + +func (c *Client) NormalizeCollectibles(collectibles []Collectible, coinIndex uint) (types.CollectiblePage, error) { + if len(collectibles) == 0 { + return types.CollectiblePage{}, nil + } + page := make(types.CollectiblePage, 0) + info, err := fetchTokenURI(collectibles[0].TokenURI) + if err != nil { + 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, + }) + } + return page, nil +} diff --git a/platform/ethereum/bounce/model.go b/platform/ethereum/bounce/model.go new file mode 100644 index 000000000..8e1d54c9f --- /dev/null +++ b/platform/ethereum/bounce/model.go @@ -0,0 +1,48 @@ +package bounce + +type Response struct { + CodeStatus int `json:"codeStatus"` + Msg string `json:"msg"` +} + +type Collectible struct { + ContractAddr string `json:"contract_addr"` + TokenID int `json:"token_id"` + OwnerAddr string `json:"owner_addr"` + ChainID int `json:"chain_id"` + TokenURI string `json:"token_uri"` +} + +type CollectibleList struct { + Collectibles []Collectible `json:"tokens"` +} + +type CollectibleResponse struct { + Response + Data CollectibleList `json:"data"` +} + +type Collection struct { + ContractAddr string `json:"contract_addr"` + TokenType string `json:"token_type"` + TokenID int `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"` +} + +type CollectionResponse struct { + Response + Data CollectionList `json:"data"` +} + +type CollectionInfo struct { + Name string `json:"name"` + Description string `json:"description"` + Image string `json:"image"` +} diff --git a/platform/ethereum/client.go b/platform/ethereum/client.go index 219765a30..020345c88 100644 --- a/platform/ethereum/client.go +++ b/platform/ethereum/client.go @@ -10,14 +10,7 @@ type EthereumClient interface { GetBlockByNumber(num int64, coinIndex uint) (*types.Block, error) } -func (p *Platform) GetTokenListByAddress(address string) ([]string, error) { - return p.client.GetTokenList(address, p.CoinIndex) -} - -func (p *Platform) CurrentBlockNumber() (int64, error) { - return p.client.GetCurrentBlockNumber() -} - -func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { - return p.client.GetBlockByNumber(num, p.CoinIndex) +type CollectibleClient interface { + GetCollections(owner string, coinIndex uint) (types.CollectionPage, error) + GetCollectibles(owner, collectionID string, coinIndex uint) (types.CollectiblePage, error) } diff --git a/platform/ethereum/collection.go b/platform/ethereum/collection.go index 07d33dd33..2ef9e7670 100644 --- a/platform/ethereum/collection.go +++ b/platform/ethereum/collection.go @@ -1,78 +1,13 @@ package ethereum import ( - "strings" - - "github.com/trustwallet/blockatlas/platform/ethereum/collection" "github.com/trustwallet/golibs/types" ) -var ( - supportedTypes = map[string]bool{"ERC721": true, "ERC1155": true} -) - func (p *Platform) GetCollections(owner string) (types.CollectionPage, error) { - collections, err := p.collectible.GetCollections(owner) - if err != nil { - return nil, err - } - return NormalizeCollections(collections, p.CoinIndex, owner), nil -} - -func (p *Platform) GetCollectibles(owner, collectibleID string) (types.CollectiblePage, error) { - items, err := p.collectible.GetCollectibles(owner, collectibleID) - if err != nil { - return nil, err - } - return NormalizeCollectiblePage(items, p.CoinIndex), nil -} - -func NormalizeCollections(collections []collection.Collection, coinIndex uint, owner string) (page types.CollectionPage) { - for _, collection := range collections { - item := NormalizeCollection(collection, coinIndex, owner) - page = append(page, item) - } - return page -} - -func NormalizeCollection(c collection.Collection, coinIndex uint, owner string) types.Collection { - return types.Collection{ - Name: c.Name, - ImageUrl: c.ImageUrl, - Description: c.Description, - ExternalLink: c.ExternalUrl, - Total: int(c.Total.Int64()), - Id: c.Slug, - Address: owner, - Coin: coinIndex, - } -} - -func NormalizeCollectiblePage(collectibles []collection.Collectible, coinIndex uint) (page types.CollectiblePage) { - for _, collectible := range collectibles { - item := NormalizeCollectible(collectible, coinIndex) - if _, ok := supportedTypes[item.Type]; ok { - page = append(page, item) - } - } - return page + return p.collectible.GetCollections(owner, p.CoinIndex) } -func NormalizeCollectible(c collection.Collectible, coinIndex uint) types.Collectible { - id := strings.Join([]string{c.AssetContract.Address, c.TokenId}, "-") - return types.Collectible{ - ID: id, - CollectionID: c.Collection.Slug, - TokenID: c.TokenId, - ContractAddress: c.AssetContract.Address, - Name: c.Name, - Category: c.Collection.Name, - ImageUrl: c.ImagePreviewUrl, - ProviderLink: c.Permalink, - ExternalLink: c.Collection.ExternalLink, - Type: c.AssetContract.Type, - Description: c.Description, - Coin: coinIndex, - Version: c.AssetContract.Version, - } +func (p *Platform) GetCollectibles(owner, collectionID string) (types.CollectiblePage, error) { + return p.collectible.GetCollectibles(owner, collectionID, p.CoinIndex) } diff --git a/platform/ethereum/collection/client.go b/platform/ethereum/collection/client.go deleted file mode 100644 index c2c646a71..000000000 --- a/platform/ethereum/collection/client.go +++ /dev/null @@ -1,33 +0,0 @@ -package collection - -import ( - "net/url" - "strconv" - - "github.com/trustwallet/golibs/client" -) - -type Client struct { - client.Request -} - -func (c Client) GetCollections(owner string) (page []Collection, err error) { - query := url.Values{ - "asset_owner": {owner}, - "limit": {"1000"}, - } - err = c.Get(&page, "api/v1/collections", query) - return -} - -func (c Client) GetCollectibles(owner string, collectibleID string) ([]Collectible, error) { - query := url.Values{ - "owner": {owner}, - "collection": {collectibleID}, - "limit": {strconv.Itoa(300)}, - } - - var page CollectiblePage - err := c.Get(&page, "api/v1/assets", query) - return page.Collectibles, err -} diff --git a/platform/ethereum/opensea/client.go b/platform/ethereum/opensea/client.go new file mode 100644 index 000000000..8a308deb3 --- /dev/null +++ b/platform/ethereum/opensea/client.go @@ -0,0 +1,40 @@ +package opensea + +import ( + "net/url" + "strconv" + + "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/network/middleware" +) + +type Client struct { + client.Request +} + +func InitClient(api string, apiKey string) *Client { + c := Client{client.InitClient(api, middleware.SentryErrorHandler)} + c.Headers["X-API-KEY"] = apiKey + return &c +} + +func (c Client) GetCollectionsByOwner(owner string) (page []Collection, err error) { + query := url.Values{ + "asset_owner": {owner}, + "limit": {"1000"}, + } + err = c.Get(&page, "api/v1/collections", query) + return +} + +func (c Client) GetCollectiblesByCollectionId(owner string, collectionId string) ([]Collectible, error) { + query := url.Values{ + "owner": {owner}, + "collection": {collectionId}, + "limit": {strconv.Itoa(300)}, + } + + var page CollectiblePage + err := c.Get(&page, "api/v1/assets", query) + return page.Collectibles, err +} diff --git a/platform/ethereum/opensea/collection.go b/platform/ethereum/opensea/collection.go new file mode 100644 index 000000000..3e9f16b9a --- /dev/null +++ b/platform/ethereum/opensea/collection.go @@ -0,0 +1,76 @@ +package opensea + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/types" +) + +var ( + supportedTypes = map[string]bool{"ERC721": true, "ERC1155": true} +) + +func (c *Client) GetCollections(owner string, coinIndex uint) (types.CollectionPage, error) { + collections, err := c.GetCollectionsByOwner(owner) + if err != nil { + return nil, err + } + return NormalizeCollections(collections, coinIndex, owner), nil + +} + +func (c *Client) GetCollectibles(owner, collectionId string, coinIndex uint) (types.CollectiblePage, error) { + items, err := c.GetCollectiblesByCollectionId(owner, collectionId) + if err != nil { + return nil, err + } + return NormalizeCollectiblePage(items, coinIndex), nil +} + +func NormalizeCollections(collections []Collection, coinIndex uint, owner string) (page types.CollectionPage) { + for _, collection := range collections { + item := NormalizeCollection(collection, coinIndex, owner) + page = append(page, item) + } + return page +} + +func NormalizeCollection(c Collection, coinIndex uint, owner string) types.Collection { + return types.Collection{ + Name: c.Name, + ImageUrl: c.ImageUrl, + Description: c.Description, + ExternalLink: c.ExternalUrl, + Total: int(c.Total.Int64()), + Id: c.Slug, + Address: owner, + Coin: coinIndex, + } +} + +func NormalizeCollectiblePage(collectibles []Collectible, coinIndex uint) (page types.CollectiblePage) { + for _, collectible := range collectibles { + item := NormalizeCollectible(collectible, coinIndex) + if _, ok := supportedTypes[item.Type]; ok { + page = append(page, item) + } + } + return page +} + +func NormalizeCollectible(c Collectible, coinIndex uint) types.Collectible { + return types.Collectible{ + ID: blockatlas.GenCollectibleId(c.AssetContract.Address, c.TokenId), + CollectionID: c.Collection.Slug, + TokenID: c.TokenId, + ContractAddress: c.AssetContract.Address, + Name: c.Name, + Category: c.Collection.Name, + ImageUrl: c.ImagePreviewUrl, + ProviderLink: c.Permalink, + ExternalLink: c.Collection.ExternalLink, + Type: c.AssetContract.Type, + Description: c.Description, + Coin: coinIndex, + Version: c.AssetContract.Version, + } +} diff --git a/platform/ethereum/collection_test.go b/platform/ethereum/opensea/collection_test.go similarity index 96% rename from platform/ethereum/collection_test.go rename to platform/ethereum/opensea/collection_test.go index cb1c01254..5524bbf3e 100644 --- a/platform/ethereum/collection_test.go +++ b/platform/ethereum/opensea/collection_test.go @@ -1,11 +1,10 @@ -package ethereum +package opensea import ( "encoding/json" "testing" "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/platform/ethereum/collection" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" "github.com/trustwallet/golibs/types" @@ -66,7 +65,7 @@ var ( ) func TestNormalizeCollectionV4(t *testing.T) { - var collections []collection.Collection + var collections []Collection err := json.Unmarshal([]byte(collectionsSrcV4), &collections) assert.Nil(t, err) page := NormalizeCollections(collections, coin.ETH, collectionsOwnerV4) @@ -76,7 +75,7 @@ func TestNormalizeCollectionV4(t *testing.T) { } func TestNormalizeCollectibleV4(t *testing.T) { - var collectibles []collection.Collectible + var collectibles []Collectible err := json.Unmarshal([]byte(collectibleSrcV4), &collectibles) assert.Nil(t, err) page := NormalizeCollectiblePage(collectibles, coin.ETH) diff --git a/platform/ethereum/mocks/opensea_collectible.json b/platform/ethereum/opensea/mocks/opensea_collectible.json similarity index 100% rename from platform/ethereum/mocks/opensea_collectible.json rename to platform/ethereum/opensea/mocks/opensea_collectible.json diff --git a/platform/ethereum/mocks/opensea_collections.json b/platform/ethereum/opensea/mocks/opensea_collections.json similarity index 100% rename from platform/ethereum/mocks/opensea_collections.json rename to platform/ethereum/opensea/mocks/opensea_collections.json diff --git a/platform/ethereum/collection/model.go b/platform/ethereum/opensea/model.go similarity index 99% rename from platform/ethereum/collection/model.go rename to platform/ethereum/opensea/model.go index 706529544..1d63b22e1 100644 --- a/platform/ethereum/collection/model.go +++ b/platform/ethereum/opensea/model.go @@ -1,4 +1,4 @@ -package collection +package opensea import ( "math/big" diff --git a/platform/ethereum/transaction.go b/platform/ethereum/transaction.go index e0568bcbd..89348a5a9 100644 --- a/platform/ethereum/transaction.go +++ b/platform/ethereum/transaction.go @@ -9,3 +9,7 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { func (p *Platform) GetTokenTxsByAddress(address string, token string) (types.TxPage, error) { return p.client.GetTokenTxs(address, token, p.CoinIndex) } + +func (p *Platform) GetTokenListByAddress(address string) ([]string, error) { + return p.client.GetTokenList(address, p.CoinIndex) +} diff --git a/platform/platform.go b/platform/platform.go index 1f59a60c7..ffc050441 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -92,9 +92,9 @@ func getAllHandlers() blockatlas.Platforms { 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.Bsc().Handle: ethereum.InitWithBlockbook(coin.BSCLegacy, config.Default.BSC.API, config.Default.BSC.RPC), - coin.Smartchain().Handle: ethereum.InitWithBlockbook(coin.BSC, config.Default.Smartchain.API, config.Default.Smartchain.RPC), - coin.Ethereum().Handle: ethereum.InitWithCollection(coin.ETH, config.Default.Ethereum.RPC, config.Default.Ethereum.BlockbookAPI, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey), + coin.Bsc().Handle: ethereum.InitWithBounce(coin.BSCLegacy, config.Default.BSC.RPC, config.Default.BSC.API, config.Default.BSC.CollectionsAPI), + 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.Near().Handle: near.Init(config.Default.Near.API), coin.Elrond().Handle: elrond.Init(coin.EGLD, config.Default.Elrond.API), coin.Filecoin().Handle: filecoin.Init(config.Default.Filecoin.API, config.Default.Filecoin.Explorer), @@ -103,6 +103,7 @@ func getAllHandlers() blockatlas.Platforms { func getCollectionsHandlers() blockatlas.CollectionsAPIs { return blockatlas.CollectionsAPIs{ - coin.ETH: ethereum.InitWithCollection(coin.ETH, config.Default.Ethereum.RPC, config.Default.Ethereum.BlockbookAPI, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey), + coin.ETH: ethereum.InitWithOpenSea(coin.ETH, config.Default.Ethereum.RPC, config.Default.Ethereum.BlockbookAPI, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey), + coin.BSC: ethereum.InitWithBounce(coin.BSC, config.Default.Smartchain.RPC, config.Default.Smartchain.API, config.Default.Smartchain.CollectionsAPI), } } From 53efdedf019c2ce171daf73a8a744f64c6129948 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Fri, 22 Jan 2021 12:19:13 -0800 Subject: [PATCH 468/506] Add GetTokenListIdsByAddress to TokensAPI (#1379) * Add GetTokenListIdsByAddress to TokensAPI * Add tokens/:address/ids route * Update model.go * Update model.go * Use []types.Token * Update token.go * Update go.sum --- api/endpoint/token.go | 15 +++++++++ api/registry.go | 3 ++ go.mod | 2 +- go.sum | 8 ++--- pkg/blockatlas/platform.go | 3 +- platform/binance/mocks/tokens.json | 27 ++++++++++++++-- platform/binance/model.go | 24 +++----------- platform/binance/token.go | 14 ++++++++- platform/bitcoin/blockbook/token.go | 26 +++++++++++----- platform/bitcoin/blockbook/token_test.go | 31 +++++++++++++------ platform/ethereum/client.go | 2 +- platform/ethereum/transaction.go | 14 +++++++-- platform/ethereum/transaction_test.go | 4 +-- platform/ethereum/trustray/token.go | 10 +++--- .../tron/mocks/tokens/tokens_response.json | 1 - platform/tron/token.go | 22 ++++++------- platform/tron/token_test.go | 2 +- services/tokenindexer/indexer_subscribe.go | 2 +- 18 files changed, 136 insertions(+), 74 deletions(-) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index dfdb975c7..8df391fe2 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -37,6 +37,21 @@ func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { c.JSON(http.StatusOK, result) } +func GetTokensIdsByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { + address := c.Param("address") + if address == "" { + c.JSON(http.StatusOK, types.TxPage{}) + return + } + + result, err := tokenAPI.GetTokenListIdsByAddress(address) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, errorResponse(err)) + return + } + c.JSON(http.StatusOK, result) +} + func GetTokensByAddressV3(c *gin.Context, instance tokenindexer.Instance) { var query tokenindexer.GetTokensByAddressRequest if err := c.Bind(&query); err != nil { diff --git a/api/registry.go b/api/registry.go index 48f5feed9..9534656c7 100644 --- a/api/registry.go +++ b/api/registry.go @@ -56,6 +56,9 @@ func RegisterTokensAPI(router gin.IRouter, api blockatlas.Platform) { router.GET("/v2/"+handle+"/tokens/:address", func(c *gin.Context) { endpoint.GetTokensByAddress(c, tokenAPI) }) + router.GET("/v2/"+handle+"/tokens/:address/ids", func(c *gin.Context) { + endpoint.GetTokensIdsByAddress(c, tokenAPI) + }) } func RegisterStakeAPI(router gin.IRouter, api blockatlas.Platform) { diff --git a/go.mod b/go.mod index fc88b66d3..1d356bd43 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( 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.39 + github.com/trustwallet/golibs v0.0.40 github.com/trustwallet/golibs/network v0.0.0-20210121062720-6eaa67ade593 golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect diff --git a/go.sum b/go.sum index 25c629115..939b6725c 100644 --- a/go.sum +++ b/go.sum @@ -418,14 +418,10 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/trustwallet/golibs v0.0.34 h1:/6XobjSYf2YZ5tqJLf4ZqhNZGNuXsRyM61ZCwt5tuxo= -github.com/trustwallet/golibs v0.0.34/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= 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.39 h1:OQ+zkc6mr266e3BCXwxg8NppkyDPKpvTHVJS7ejVML4= -github.com/trustwallet/golibs v0.0.39/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= -github.com/trustwallet/golibs/network v0.0.0-20210119064642-74e68ef98cfe h1:nQGIQUV8JQzYZLN0jNRW8v+p6+UlC83ikNGZCsrEHl8= -github.com/trustwallet/golibs/network v0.0.0-20210119064642-74e68ef98cfe/go.mod h1:RMMyjp4qUcVhWidjE+XYzQgOtSXuhIKSB5pnLCA3WqY= +github.com/trustwallet/golibs v0.0.40 h1:9zWFFQNaCHSQfEyPQ6gD9Wdq4NL0du9ERbHVDKK58rM= +github.com/trustwallet/golibs v0.0.40/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= github.com/trustwallet/golibs/network v0.0.0-20210121062720-6eaa67ade593 h1:J+nbswDE9lS2ITYW4SgFxTvo8lz+LEwIokyZZaC58Ps= github.com/trustwallet/golibs/network v0.0.0-20210121062720-6eaa67ade593/go.mod h1:LDMLFnOnwmC30WuCCIJ56TWeXxwCVcrMFJYeC6GEnxY= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 5e718b5b2..001201c00 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -39,7 +39,8 @@ type ( // TokensAPI provides token lookups TokensAPI interface { Platform - GetTokenListByAddress(address string) ([]string, error) + GetTokenListByAddress(address string) ([]types.Token, error) + GetTokenListIdsByAddress(address string) ([]string, error) } // StakingAPI provides staking information diff --git a/platform/binance/mocks/tokens.json b/platform/binance/mocks/tokens.json index c165618a7..8f8d1bcae 100644 --- a/platform/binance/mocks/tokens.json +++ b/platform/binance/mocks/tokens.json @@ -1,5 +1,26 @@ [ - "c714_tAVA-645", - "c714_tBNB", - "c714_tBUSD-BD1" + { + "name": "Travala.com Token", + "symbol": "AVA", + "decimals": 8, + "token_id": "AVA-645", + "coin": 714, + "type": "BEP2" + }, + { + "name": "Binance Chain Native Token", + "symbol": "BNB", + "decimals": 8, + "token_id": "BNB", + "coin": 714, + "type": "BEP2" + }, + { + "name": "Binance USD", + "symbol": "BUSD", + "decimals": 8, + "token_id": "BUSD-BD1", + "coin": 714, + "type": "BEP2" + } ] diff --git a/platform/binance/model.go b/platform/binance/model.go index dfa2c2b9b..e6539550b 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -215,14 +215,12 @@ func normalizeBaseOfTransaction(t Tx) types.Tx { } } -func normalizeTokens(srcBalance []TokenBalance, tokens Tokens) []string { - assetIds := make([]string, 0) +func normalizeTokens(srcBalance []TokenBalance, tokens Tokens) []types.Token { + assetIds := make([]types.Token, 0) for _, srcToken := range srcBalance { - token, ok := normalizeToken(srcToken, tokens) - if !ok { - continue + if token, ok := normalizeToken(srcToken, tokens); ok { + assetIds = append(assetIds, token) } - assetIds = append(assetIds, token.AssetId()) } return assetIds } @@ -250,20 +248,6 @@ func normalizeToken(srcToken TokenBalance, tokens Tokens) (types.Token, bool) { return result, true } -//func getTransactionData(rawOrderData string) (TransactionData, error) { -// var result TransactionData -// err := json.Unmarshal([]byte(rawOrderData), &result) -// return result, err -//} -// -//func getTokenIDsFromPair(pair string) (string, string) { -// result := strings.Split(pair, "_") -// if len(result) == 1 || len(result) == 0 { -// return pair, pair -// } -// return result[0], result[1] -//} - func getTokenSymbolFromID(tokenID string) string { s := strings.Split(tokenID, "-") if len(s) > 1 { diff --git a/platform/binance/token.go b/platform/binance/token.go index 2989314b7..4ae4ac7f2 100644 --- a/platform/binance/token.go +++ b/platform/binance/token.go @@ -1,6 +1,10 @@ package binance -func (p *Platform) GetTokenListByAddress(address string) ([]string, error) { +import ( + "github.com/trustwallet/golibs/types" +) + +func (p *Platform) GetTokenListByAddress(address string) ([]types.Token, error) { account, err := p.client.FetchAccountMeta(address) if err != nil || len(account.Balances) == 0 { return nil, nil @@ -11,3 +15,11 @@ func (p *Platform) GetTokenListByAddress(address string) ([]string, error) { } return normalizeTokens(account.Balances, tokens), nil } + +func (p *Platform) GetTokenListIdsByAddress(address string) ([]string, error) { + assets, err := p.GetTokenListByAddress(address) + if err != nil { + return []string{}, err + } + return types.GetAssetsIds(assets), nil +} diff --git a/platform/bitcoin/blockbook/token.go b/platform/bitcoin/blockbook/token.go index 429faa9b1..da04de1b3 100644 --- a/platform/bitcoin/blockbook/token.go +++ b/platform/bitcoin/blockbook/token.go @@ -1,10 +1,10 @@ package blockbook import ( - "github.com/trustwallet/golibs/asset" + "github.com/trustwallet/golibs/types" ) -func (c *Client) GetTokenList(address string, coinIndex uint) ([]string, error) { +func (c *Client) GetTokenList(address string, coinIndex uint) ([]types.Token, error) { tokens, err := c.GetTokens(address) if err != nil { return nil, err @@ -12,13 +12,25 @@ func (c *Client) GetTokenList(address string, coinIndex uint) ([]string, error) return NormalizeTokens(tokens, coinIndex), nil } -func NormalizeTokens(srcTokens []Token, coinIndex uint) []string { - tokenPage := make([]string, 0) - for _, srcToken := range srcTokens { +func NormalizeTokens(tokens []Token, coinIndex uint) []types.Token { + assets := make([]types.Token, 0) + for _, srcToken := range tokens { if srcToken.Balance == "0" || srcToken.Balance == "" { continue } - tokenPage = append(tokenPage, asset.BuildID(coinIndex, srcToken.Contract)) + token := NormalizeToken(&srcToken, coinIndex) + assets = append(assets, token) + } + return assets +} + +func NormalizeToken(srcToken *Token, coinIndex uint) types.Token { + return types.Token{ + Name: srcToken.Name, + Symbol: srcToken.Symbol, + TokenID: srcToken.Contract, + Coin: coinIndex, + Decimals: srcToken.Decimals, + Type: types.GetEthereumTokenTypeByIndex(coinIndex), } - return tokenPage } diff --git a/platform/bitcoin/blockbook/token_test.go b/platform/bitcoin/blockbook/token_test.go index a1a1ed0c1..135527790 100644 --- a/platform/bitcoin/blockbook/token_test.go +++ b/platform/bitcoin/blockbook/token_test.go @@ -3,6 +3,8 @@ package blockbook import ( "reflect" "testing" + + "github.com/trustwallet/golibs/types" ) func TestNormalizeToken(t *testing.T) { @@ -13,42 +15,53 @@ func TestNormalizeToken(t *testing.T) { tests := []struct { name string args args - want []string + want []types.Token }{ { name: "Should normalize and return token with balance", args: args{srcToken: Token{ Balance: "100", Type: "ERC20", - Name: "USD//C", + Name: "USD Coin", Contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", Symbol: "USDC", Decimals: 6}, coinIndex: 60}, - want: []string{"c60_t0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"}, + want: []types.Token{ + { + Type: "ERC20", + Name: "USD Coin", + TokenID: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + Symbol: "USDC", + Decimals: 6, + Coin: 60, + }, + }, }, { name: "Should not return token with zero balance", args: args{srcToken: Token{ Balance: "0", Type: "ERC20", - Name: "USD//C", + Name: "USD Coin", Contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", Symbol: "USDC", Decimals: 6}, - coinIndex: 60}, - want: []string{}, + coinIndex: 60, + }, + want: []types.Token{}, }, { name: "Should not return token with zero balance", args: args{srcToken: Token{ Balance: "", Type: "ERC20", - Name: "USD//C", + Name: "USD Coin", Contract: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", Symbol: "USDC", Decimals: 6}, - coinIndex: 60}, - want: []string{}, + coinIndex: 60, + }, + want: []types.Token{}, }, } for _, tt := range tests { diff --git a/platform/ethereum/client.go b/platform/ethereum/client.go index 020345c88..1a81fa976 100644 --- a/platform/ethereum/client.go +++ b/platform/ethereum/client.go @@ -5,7 +5,7 @@ import "github.com/trustwallet/golibs/types" type EthereumClient interface { GetTransactions(address string, coinIndex uint) (types.TxPage, error) GetTokenTxs(address, token string, coinIndex uint) (types.TxPage, error) - GetTokenList(address string, coinIndex uint) ([]string, error) + GetTokenList(address string, coinIndex uint) ([]types.Token, error) GetCurrentBlockNumber() (int64, error) GetBlockByNumber(num int64, coinIndex uint) (*types.Block, error) } diff --git a/platform/ethereum/transaction.go b/platform/ethereum/transaction.go index 89348a5a9..564cf7ce4 100644 --- a/platform/ethereum/transaction.go +++ b/platform/ethereum/transaction.go @@ -1,6 +1,8 @@ package ethereum -import "github.com/trustwallet/golibs/types" +import ( + "github.com/trustwallet/golibs/types" +) func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return p.client.GetTransactions(address, p.CoinIndex) @@ -10,6 +12,14 @@ func (p *Platform) GetTokenTxsByAddress(address string, token string) (types.TxP return p.client.GetTokenTxs(address, token, p.CoinIndex) } -func (p *Platform) GetTokenListByAddress(address string) ([]string, error) { +func (p *Platform) GetTokenListByAddress(address string) ([]types.Token, error) { return p.client.GetTokenList(address, p.CoinIndex) } + +func (p *Platform) GetTokenListIdsByAddress(address string) ([]string, error) { + assets, err := p.GetTokenListByAddress(address) + if err != nil { + return []string{}, err + } + return types.GetAssetsIds(assets), nil +} diff --git a/platform/ethereum/transaction_test.go b/platform/ethereum/transaction_test.go index 5c846ba48..b7d697b75 100644 --- a/platform/ethereum/transaction_test.go +++ b/platform/ethereum/transaction_test.go @@ -55,8 +55,8 @@ func (c Client) GetTokenTxs(address, token string, coinIndex uint) (types.TxPage return txs, nil } -func (c Client) GetTokenList(address string, coinIndex uint) ([]string, error) { - return []string{}, nil +func (c Client) GetTokenList(address string, coinIndex uint) ([]types.Token, error) { + return []types.Token{}, nil } func (c Client) GetCurrentBlockNumber() (int64, error) { diff --git a/platform/ethereum/trustray/token.go b/platform/ethereum/trustray/token.go index 78b07d599..c2d773293 100644 --- a/platform/ethereum/trustray/token.go +++ b/platform/ethereum/trustray/token.go @@ -4,7 +4,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (c *Client) GetTokenList(address string, coinIndex uint) ([]string, error) { +func (c *Client) GetTokenList(address string, coinIndex uint) ([]types.Token, error) { account, err := c.GetTokens(address) if err != nil { return nil, err @@ -27,11 +27,11 @@ func NormalizeToken(srcToken *Contract, coinIndex uint) types.Token { } // NormalizeTxs converts multiple Ethereum tokens -func NormalizeTokens(srcTokens []Contract, coinIndex uint) []string { - assetIds := make([]string, 0) +func NormalizeTokens(srcTokens []Contract, coinIndex uint) []types.Token { + assets := make([]types.Token, 0) for _, srcToken := range srcTokens { token := NormalizeToken(&srcToken, coinIndex) - assetIds = append(assetIds, token.AssetId()) + assets = append(assets, token) } - return assetIds + return assets } diff --git a/platform/tron/mocks/tokens/tokens_response.json b/platform/tron/mocks/tokens/tokens_response.json index 36caf4060..da85d0769 100644 --- a/platform/tron/mocks/tokens/tokens_response.json +++ b/platform/tron/mocks/tokens/tokens_response.json @@ -1,5 +1,4 @@ [ - "c195_t1000567", "c195_tTCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9", "c195_tTCRhVHPv6efvXgogNMhiunAMXFKcMmv2pF", "c195_tTG7Z1ptC7nRkaniDVRhHSyLycaroaS5PdK", diff --git a/platform/tron/token.go b/platform/tron/token.go index 9c19291e3..105a5024e 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -2,9 +2,14 @@ package tron import ( "github.com/trustwallet/golibs/asset" + "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTokenListByAddress(address string) ([]string, error) { +func (p *Platform) GetTokenListByAddress(address string) ([]types.Token, error) { + return []types.Token{}, nil +} + +func (p *Platform) GetTokenListIdsByAddress(address string) ([]string, error) { assetIds := make([]string, 0) tokens, err := p.gridClient.fetchAccount(address) if err != nil { @@ -13,20 +18,11 @@ func (p *Platform) GetTokenListByAddress(address string) ([]string, error) { if len(tokens.Data) == 0 { return assetIds, nil } - data := tokens.Data[0] - - var tokenIds []string - for _, v := range data.AssetsV2 { - tokenIds = append(assetIds, v.Key) - } - for _, trc20Tokens := range data.Trc20 { - for key := range trc20Tokens { - tokenIds = append(tokenIds, key) + for _, trc20Tokens := range tokens.Data[0].Trc20 { + for assetId := range trc20Tokens { + assetIds = append(assetIds, asset.BuildID(p.Coin().ID, assetId)) } } - for _, tokenId := range tokenIds { - assetIds = append(assetIds, asset.BuildID(p.Coin().ID, tokenId)) - } return assetIds, nil } diff --git a/platform/tron/token_test.go b/platform/tron/token_test.go index 8ccde9594..f7af4dd7a 100644 --- a/platform/tron/token_test.go +++ b/platform/tron/token_test.go @@ -17,7 +17,7 @@ func TestPlatform_GetTokenListByAddress(t *testing.T) { defer server.Close() p := Init(server.URL, server.URL) - res, err := p.GetTokenListByAddress("TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R") + res, err := p.GetTokenListIdsByAddress("TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R") assert.Nil(t, err) sort.Slice(res, func(i, j int) bool { return res[i] < res[j] diff --git a/services/tokenindexer/indexer_subscribe.go b/services/tokenindexer/indexer_subscribe.go index bb87414b0..8ccdfa9a2 100644 --- a/services/tokenindexer/indexer_subscribe.go +++ b/services/tokenindexer/indexer_subscribe.go @@ -45,7 +45,7 @@ func RunTokenIndexerSubscribe(database *db.Instance, apis map[uint]blockatlas.To if !ok { continue } - assetIds, err := api.GetTokenListByAddress(coinAddress.Address) + assetIds, err := api.GetTokenListIdsByAddress(coinAddress.Address) if err != nil { continue } From 97d9869e21aa5f0c6ed2ca36a72ac321f4f4ef15 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Fri, 22 Jan 2021 12:36:02 -0800 Subject: [PATCH 469/506] [Consumer] Implement prefetch limit (#1380) * [Consumer] Implement prefetch limit * Delete codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 62 ---------------------- cmd/consumer/main.go | 1 + config.yml | 1 + config/configuration.go | 5 +- go.mod | 4 +- go.sum | 8 +-- internal/mq.go | 4 -- services/tokenindexer/indexer_subscribe.go | 4 -- 8 files changed, 11 insertions(+), 78 deletions(-) delete mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 973d564b7..000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: [master] - pull_request: - # The branches below must be a subset of the branches above - branches: [master] - schedule: - - cron: '0 1 * * 5' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - # Override automatic language detection by changing the below list - # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['go'] - # Learn more... - # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index bba2018f4..12dbb3c3d 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -64,6 +64,7 @@ func main() { platform.Init(config.Default.Platform) options := mq.InitDefaultConsumerOptions(config.Default.Consumer.Workers) + options.PrefetchLimit = config.Default.Consumer.Prefetch // Special case options to avoid unknown deadlock on insert subscriptionsOptions := mq.InitDefaultConsumerOptions(1) diff --git a/config.yml b/config.yml index 69d0bdc8b..11e71f675 100644 --- a/config.yml +++ b/config.yml @@ -27,6 +27,7 @@ postgres: consumer: service: "" + prefetch: 8 workers: 8 # [BNB] Binance DEX: https://www.binance.org/ diff --git a/config/configuration.go b/config/configuration.go index 175ba4e26..0f149f50a 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -214,8 +214,9 @@ type Configuration struct { DSN string `mapstructure:"dsn"` } `mapstructure:"sentry"` Consumer struct { - Service string `mapstructure:"service"` - Workers int `mapstructure:"workers"` + Service string `mapstructure:"service"` + Prefetch int `mapstructure:"prefetch"` + Workers int `mapstructure:"workers"` } `mapstructure:"consumer"` } diff --git a/go.mod b/go.mod index 1d356bd43..ed6ddf9f5 100644 --- a/go.mod +++ b/go.mod @@ -24,8 +24,8 @@ require ( 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.40 - github.com/trustwallet/golibs/network v0.0.0-20210121062720-6eaa67ade593 + github.com/trustwallet/golibs v0.0.41 + github.com/trustwallet/golibs/network v0.0.0-20210122201441-617190ec568d golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect diff --git a/go.sum b/go.sum index 939b6725c..eb8cc6914 100644 --- a/go.sum +++ b/go.sum @@ -420,10 +420,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.40 h1:9zWFFQNaCHSQfEyPQ6gD9Wdq4NL0du9ERbHVDKK58rM= -github.com/trustwallet/golibs v0.0.40/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= -github.com/trustwallet/golibs/network v0.0.0-20210121062720-6eaa67ade593 h1:J+nbswDE9lS2ITYW4SgFxTvo8lz+LEwIokyZZaC58Ps= -github.com/trustwallet/golibs/network v0.0.0-20210121062720-6eaa67ade593/go.mod h1:LDMLFnOnwmC30WuCCIJ56TWeXxwCVcrMFJYeC6GEnxY= +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/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= diff --git a/internal/mq.go b/internal/mq.go index e41ff9b50..13e61eff4 100644 --- a/internal/mq.go +++ b/internal/mq.go @@ -28,7 +28,3 @@ type ConsumerDatabase struct { func (c ConsumerDatabase) Callback(msg amqp.Delivery) error { return c.Delivery(c.Database, msg) } - -func (c ConsumerDatabase) ConsumerTag() string { - return c.Tag -} diff --git a/services/tokenindexer/indexer_subscribe.go b/services/tokenindexer/indexer_subscribe.go index 8ccdfa9a2..f19df1ce6 100644 --- a/services/tokenindexer/indexer_subscribe.go +++ b/services/tokenindexer/indexer_subscribe.go @@ -21,10 +21,6 @@ func (c ConsumerIndexer) Callback(msg amqp.Delivery) error { return c.Delivery(c.Database, c.TokensAPIs, msg) } -func (c ConsumerIndexer) ConsumerTag() string { - return c.Tag -} - func RunTokenIndexerSubscribe(database *db.Instance, apis map[uint]blockatlas.TokensAPI, delivery amqp.Delivery) error { var event types.SubscriptionEvent err := json.Unmarshal(delivery.Body, &event) From a85abde7b97e0e47b393e76603005eced356db6a Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sat, 23 Jan 2021 16:44:41 -0800 Subject: [PATCH 470/506] Add ability to disable parsing for specific coin (#1382) * Add ability to disable parsing for specific coin * Fix TestDb_SetBlock tests --- db/models/tracker.go | 1 + db/tracker.go | 37 ++--------------------- go.mod | 4 +-- go.sum | 8 ++--- services/parser/parser.go | 21 +++++++++---- tests/integration/db_test/tracker_test.go | 4 +-- 6 files changed, 27 insertions(+), 48 deletions(-) diff --git a/db/models/tracker.go b/db/models/tracker.go index 14bbd3523..fdead1ce4 100644 --- a/db/models/tracker.go +++ b/db/models/tracker.go @@ -6,4 +6,5 @@ type Tracker struct { UpdatedAt time.Time Coin string `gorm:"primary_key:true; type:varchar(64)"` Height int64 + Enabled bool `gorm:"default:true" sql:"index"` } diff --git a/db/tracker.go b/db/tracker.go index fb2bafc4c..08e61e084 100644 --- a/db/tracker.go +++ b/db/tracker.go @@ -1,51 +1,20 @@ package db import ( - "sync" - "github.com/trustwallet/blockatlas/db/models" "gorm.io/gorm/clause" ) -var memoryCache heightBlockMap - -func init() { - memoryCache.m = make(map[string]int64) -} - -type heightBlockMap struct { - m map[string]int64 - sync.RWMutex -} - -func (hbm *heightBlockMap) SetHeight(coin string, b int64) { - hbm.Lock() - defer hbm.Unlock() - hbm.m[coin] = b -} - -func (hbm *heightBlockMap) GetHeight(coin string) (int64, bool) { - hbm.RLock() - defer hbm.RUnlock() - b, ok := hbm.m[coin] - return b, ok -} - -func (i *Instance) GetLastParsedBlockNumber(coin string) (int64, error) { - height, ok := memoryCache.GetHeight(coin) - if ok { - return height, nil - } +func (i *Instance) GetLastParsedBlockNumber(coin string) (models.Tracker, error) { var tracker models.Tracker if err := i.Gorm. Find(&tracker, "coin = ?", coin).Error; err != nil { - return 0, nil + return tracker, err } - return tracker.Height, nil + return tracker, nil } func (i *Instance) SetLastParsedBlockNumber(coin string, num int64) error { - memoryCache.SetHeight(coin, num) tracker := models.Tracker{ Coin: coin, Height: num, diff --git a/go.mod b/go.mod index ed6ddf9f5..c045efa17 100644 --- a/go.mod +++ b/go.mod @@ -27,8 +27,8 @@ require ( github.com/trustwallet/golibs v0.0.41 github.com/trustwallet/golibs/network v0.0.0-20210122201441-617190ec568d golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 - golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect - golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect + 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 diff --git a/go.sum b/go.sum index eb8cc6914..b67c7a23d 100644 --- a/go.sum +++ b/go.sum @@ -509,8 +509,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -549,8 +549,8 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 h1:/dSxr6gT0FNI1MO5WLJo8mTmItROeOKTkDn+7OwWBos= -golang.org/x/sys v0.0.0-20210105210732-16f7687f5001/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210123231150-1d476976d117 h1:M1sK0uTIn2x3HD5sySUPBg7ml5hmlQ/t7n7cIM6My9w= +golang.org/x/sys v0.0.0-20210123231150-1d476976d117/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/services/parser/parser.go b/services/parser/parser.go index e37a44a67..413bbee41 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -8,6 +8,8 @@ import ( "strconv" "sync/atomic" + "github.com/trustwallet/blockatlas/db/models" + "github.com/getsentry/raven-go" "math/rand" @@ -64,7 +66,17 @@ func GetInterval(value int, minInterval, maxInterval time.Duration) time.Duratio } func parse(params Params) { - lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params) + coinTracker, err := params.Database.GetLastParsedBlockNumber(params.Api.Coin().Handle) + if err != nil { + time.Sleep(params.ParsingBlocksInterval) + return + } + if !coinTracker.Enabled { + time.Sleep(params.ParsingBlocksInterval) + return + } + + lastParsedBlock, currentBlock, err := GetBlocksIntervalToFetch(params, coinTracker) if err != nil { time.Sleep(params.ParsingBlocksInterval) return @@ -118,11 +130,8 @@ func parse(params Params) { log.WithFields(log.Fields{"coin": params.Api.Coin().Handle}).Info("End of parse step") } -func GetBlocksIntervalToFetch(params Params) (int64, int64, error) { - lastParsedBlock, err := params.Database.GetLastParsedBlockNumber(params.Api.Coin().Handle) - if err != nil { - return 0, 0, errors.New(err.Error() + " Polling failed: tracker didn't return last known block number") - } +func GetBlocksIntervalToFetch(params Params, tracker models.Tracker) (int64, int64, error) { + lastParsedBlock := tracker.Height currentBlock, err := params.Api.CurrentBlockNumber() if err != nil { return 0, 0, errors.New(err.Error() + "Polling failed: source didn't return chain head number. lastParsedBlock: " + strconv.Itoa(int(lastParsedBlock))) diff --git a/tests/integration/db_test/tracker_test.go b/tests/integration/db_test/tracker_test.go index a4c8e6a9d..72e8b573a 100644 --- a/tests/integration/db_test/tracker_test.go +++ b/tests/integration/db_test/tracker_test.go @@ -16,11 +16,11 @@ func TestDb_SetBlock(t *testing.T) { block, err := database.GetLastParsedBlockNumber("ethereum") assert.Nil(t, err) - assert.Equal(t, block, int64(0)) + assert.Equal(t, block.Height, int64(0)) assert.Nil(t, database.SetLastParsedBlockNumber("ethereum", 110)) newBlock, err := database.GetLastParsedBlockNumber("ethereum") assert.Nil(t, err) - assert.Equal(t, newBlock, int64(110)) + assert.Equal(t, newBlock.Height, int64(110)) } From 0b5536d2e69af4452c1f24949d49e1321403aa32 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Sat, 23 Jan 2021 17:28:46 -0800 Subject: [PATCH 471/506] Add Procfiles for deployment (#1383) --- deployment/Procfile-consumer | 5 +++++ deployment/Procfile-parser | 2 ++ deployment/Procfile-web | 2 ++ 3 files changed, 9 insertions(+) create mode 100644 deployment/Procfile-consumer create mode 100644 deployment/Procfile-parser create mode 100644 deployment/Procfile-web diff --git a/deployment/Procfile-consumer b/deployment/Procfile-consumer new file mode 100644 index 000000000..e0b19f1b2 --- /dev/null +++ b/deployment/Procfile-consumer @@ -0,0 +1,5 @@ +release: bin/setup -c $HOME/config.yml +transactions: CONSUMER_SERVICE=transactions bin/consumer -c $HOME/config.yml +subscriptions: CONSUMER_SERVICE=subscriptions bin/consumer -c $HOME/config.yml +subscriptions_tokens: CONSUMER_SERVICE=subscriptions_tokens bin/consumer -c $HOME/config.yml +tokens: CONSUMER_SERVICE=tokens bin/consumer -c $HOME/config.yml diff --git a/deployment/Procfile-parser b/deployment/Procfile-parser new file mode 100644 index 000000000..16ddc5fb8 --- /dev/null +++ b/deployment/Procfile-parser @@ -0,0 +1,2 @@ +release: bin/setup -c $HOME/config.yml +parser: bin/parser -c $HOME/config.yml diff --git a/deployment/Procfile-web b/deployment/Procfile-web new file mode 100644 index 000000000..b91d503df --- /dev/null +++ b/deployment/Procfile-web @@ -0,0 +1,2 @@ +release: bin/setup -c $HOME/config.yml +web: bin/api -c $HOME/config.yml -p $PORT From a91d566ca88c2a22d9c862d291382357d971b397 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sun, 24 Jan 2021 10:43:01 +0900 Subject: [PATCH 472/506] Temporary disable collectibles for bsc (#1384) * temporary disable bsc * remove bsc route --- platform/platform.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/platform/platform.go b/platform/platform.go index ffc050441..ce218ce80 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -92,7 +92,6 @@ func getAllHandlers() blockatlas.Platforms { 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.Bsc().Handle: ethereum.InitWithBounce(coin.BSCLegacy, config.Default.BSC.RPC, config.Default.BSC.API, config.Default.BSC.CollectionsAPI), 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.Near().Handle: near.Init(config.Default.Near.API), @@ -104,6 +103,5 @@ func getAllHandlers() blockatlas.Platforms { 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.BSC: ethereum.InitWithBounce(coin.BSC, config.Default.Smartchain.RPC, config.Default.Smartchain.API, config.Default.Smartchain.CollectionsAPI), } } From 141718ecfacfa256dda20f03a19f778dad8ace6b Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 26 Jan 2021 13:08:57 +0900 Subject: [PATCH 473/506] [Collectible] check coins in collectible api (#1386) * update golibs/coin, check coins in collectible api * adopt v2 api and remove chain id * add ipfs wrap tests * remove RPC url for ethereum --- api/endpoint/collection.go | 21 ++++++-- config.yml | 8 ++- config/configuration.go | 7 --- go.mod | 4 +- go.sum | 8 +-- platform/aeternity/base.go | 2 +- platform/aeternity/transaction.go | 6 +-- platform/aeternity/transaction_test.go | 2 +- platform/algorand/base.go | 2 +- platform/algorand/transaction.go | 6 +-- platform/algorand/transaction_test.go | 2 +- platform/bitcoin/transaction_test.go | 6 +-- platform/cosmos/transaction_test.go | 53 ++++++++++--------- platform/elrond/transaction_test.go | 12 ++--- platform/ethereum/base.go | 15 +++--- platform/ethereum/bounce/client.go | 24 ++++----- platform/ethereum/bounce/client_test.go | 31 +++++++++++ platform/ethereum/bounce/collection.go | 18 +++---- platform/ethereum/bounce/model.go | 12 ++--- platform/ethereum/opensea/collection_test.go | 4 +- platform/ethereum/trustray/token_test.go | 24 ++++----- .../ethereum/trustray/transaction_test.go | 10 ++-- platform/filecoin/base.go | 2 +- platform/harmony/base.go | 2 +- platform/harmony/transaction.go | 6 +-- platform/harmony/transaction_test.go | 2 +- platform/icon/base.go | 2 +- platform/icon/transaction.go | 6 +-- platform/icon/transaction_test.go | 2 +- platform/iotex/base.go | 2 +- platform/iotex/transaction.go | 6 +-- platform/iotex/transaction_test.go | 2 +- platform/kava/transaction_test.go | 38 ++++++------- platform/nebulas/base.go | 2 +- platform/nebulas/transaction.go | 6 +-- platform/nebulas/transaction_test.go | 2 +- platform/nimiq/base.go | 2 +- platform/nimiq/transaction.go | 6 +-- platform/nimiq/transaction_test.go | 4 +- platform/ontology/base.go | 2 +- platform/ontology/transaction.go | 2 +- platform/ontology/transaction_test.go | 6 +-- platform/platform.go | 51 +++++++++--------- platform/polkadot/transaction_test.go | 18 +++---- platform/ripple/base.go | 2 +- platform/ripple/transaction.go | 6 +-- platform/ripple/transaction_test.go | 6 +-- platform/solana/base.go | 2 +- platform/stellar/transaction_test.go | 6 +-- platform/tezos/base.go | 2 +- platform/tezos/transaction.go | 6 +-- platform/tron/base.go | 2 +- platform/tron/transaction.go | 8 +-- platform/tron/transaction_test.go | 4 +- platform/vechain/base.go | 2 +- platform/vechain/transaction_test.go | 8 +-- platform/zilliqa/base.go | 2 +- platform/zilliqa/transaction.go | 6 +-- platform/zilliqa/transaction_test.go | 2 +- services/notifier/models_test.go | 6 +-- 60 files changed, 276 insertions(+), 242 deletions(-) create mode 100644 platform/ethereum/bounce/client_test.go diff --git a/api/endpoint/collection.go b/api/endpoint/collection.go index cebf4af70..a57313f0a 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/config.yml b/config.yml index 11e71f675..24a1b0ab7 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,9 @@ filecoin: api: https://api.filscan.io:8700/rpc/v1 explorer: https://filfox.info -# smartchain: -# api: -# rpc: https://bsc-dataseed.nariox.org -# collections_api: https://nftview.bounce.finance +smartchain: + api: + collections_api: https://nftview.bounce.finance sentry: dsn: "" diff --git a/config/configuration.go b/config/configuration.go index 0f149f50a..0a5466f16 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"` diff --git a/go.mod b/go.mod index c045efa17..ec85e5be0 100644 --- a/go.mod +++ b/go.mod @@ -24,8 +24,8 @@ require ( 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 diff --git a/go.sum b/go.sum index b67c7a23d..f732280e9 100644 --- a/go.sum +++ b/go.sum @@ -420,10 +420,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= diff --git a/platform/aeternity/base.go b/platform/aeternity/base.go index 3ce61c221..9b17b6168 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 5544e9479..9038fa7a0 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/aeternity/transaction_test.go b/platform/aeternity/transaction_test.go index e99d4e8db..4d42e2f18 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/base.go b/platform/algorand/base.go index c47946452..24bb60857 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 80be3a3f5..89db41ac8 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/algorand/transaction_test.go b/platform/algorand/transaction_test.go index a4eab9d25..d9db60a3c 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 70329e90b..6bbe0648b 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 d0355aac7..e55f71101 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 0d671811a..6405de979 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/base.go b/platform/ethereum/base.go index 3cf04c24d..3f2446fae 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 04fb8cd97..465cf7956 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/client_test.go b/platform/ethereum/bounce/client_test.go new file mode 100644 index 000000000..96182f203 --- /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.go b/platform/ethereum/bounce/collection.go index 0058cf6ce..e03f870d7 100644 --- a/platform/ethereum/bounce/collection.go +++ b/platform/ethereum/bounce/collection.go @@ -8,12 +8,11 @@ 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 } @@ -22,7 +21,7 @@ func (c *Client) GetCollections(owner string, coinIndex uint) (types.CollectionP } 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 } @@ -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, @@ -84,14 +83,13 @@ 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), + ID: blockatlas.GenCollectibleId(c.ContractAddr, c.TokenID), CollectionID: c.ContractAddr, - TokenID: tokenId, + TokenID: c.TokenID, ContractAddress: c.ContractAddr, - ImageUrl: normalizeImageUrl(info.Image), - ExternalLink: c.TokenURI, + ImageUrl: normalizeUrl(info.Image), + ExternalLink: normalizeUrl(c.TokenURI), Type: string(types.ERC721), Description: info.Description, Coin: coinIndex, diff --git a/platform/ethereum/bounce/model.go b/platform/ethereum/bounce/model.go index 8e1d54c9f..88c9fc116 100644 --- a/platform/ethereum/bounce/model.go +++ b/platform/ethereum/bounce/model.go @@ -1,15 +1,14 @@ 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"` + TokenID string `json:"token_id"` OwnerAddr string `json:"owner_addr"` - ChainID int `json:"chain_id"` TokenURI string `json:"token_uri"` } @@ -25,15 +24,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/ethereum/opensea/collection_test.go b/platform/ethereum/opensea/collection_test.go index 5524bbf3e..494842e45 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 85ea3fff9..aea1f8cc8 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 5f2ea0243..4aec0edd0 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/filecoin/base.go b/platform/filecoin/base.go index 97016a4d1..ce454d3fa 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 1d4d766db..18b2b98eb 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 ab8af9584..144e11677 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/harmony/transaction_test.go b/platform/harmony/transaction_test.go index 73f16ee16..d9c524de8 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/base.go b/platform/icon/base.go index 8d1562995..8950fbdfd 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 6fed6e1b9..ffd795b29 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/icon/transaction_test.go b/platform/icon/transaction_test.go index b5ea3ad0f..583ecba00 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/base.go b/platform/iotex/base.go index bed4435e3..e053e37a5 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 4da1c7caf..2cbe0af36 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/iotex/transaction_test.go b/platform/iotex/transaction_test.go index fb51f53f5..66faf0ee2 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 872b18f4c..d2d9a2c8e 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/base.go b/platform/nebulas/base.go index 99dfedff4..341899467 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 0f0d7899b..b51d49657 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/nebulas/transaction_test.go b/platform/nebulas/transaction_test.go index 92a6e4e31..f59eebdfb 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/base.go b/platform/nimiq/base.go index 7a65ee9fe..690992cbf 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 2a0e14321..5124a7978 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/nimiq/transaction_test.go b/platform/nimiq/transaction_test.go index 8ab42644b..f9a270942 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/base.go b/platform/ontology/base.go index a46941389..6047ac590 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 c8c910962..e98d6ea77 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/ontology/transaction_test.go b/platform/ontology/transaction_test.go index 44c0587ee..e385dcf56 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/platform.go b/platform/platform.go index ce218ce80..171c374e4 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/polkadot/transaction_test.go b/platform/polkadot/transaction_test.go index 10195d8bf..37bab42e2 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/base.go b/platform/ripple/base.go index 1c09c9621..2f0111d86 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 a8e5caecb..2e6b17c65 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/ripple/transaction_test.go b/platform/ripple/transaction_test.go index 621981b3c..242a7d976 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/solana/base.go b/platform/solana/base.go index d693e29ad..cb1b4037c 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/stellar/transaction_test.go b/platform/stellar/transaction_test.go index e3045af39..c25df6b62 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/tezos/base.go b/platform/tezos/base.go index eee523d40..b06820874 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 f61a89818..c78140081 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 71359f210..e29bc75f6 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 8ee82b726..47026718c 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/tron/transaction_test.go b/platform/tron/transaction_test.go index fccd80bd4..e193e5a06 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/base.go b/platform/vechain/base.go index cd9a01e64..17d2979fd 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/vechain/transaction_test.go b/platform/vechain/transaction_test.go index 87fdd9691..1220a9397 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/base.go b/platform/zilliqa/base.go index 2e3813416..0ebacba58 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 1ed5407d1..a2f7f7961 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 { diff --git a/platform/zilliqa/transaction_test.go b/platform/zilliqa/transaction_test.go index cb52d33de..f65f4cbb1 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 ba1e106de..ef62df7d5 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", From 5d978d39a8c30352870cd98e5aa03f8829724152 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 28 Jan 2021 10:13:15 +0900 Subject: [PATCH 474/506] Bump gorm.io/driver/postgres from 1.0.6 to 1.0.7 (#1391) Bumps [gorm.io/driver/postgres](https://github.com/go-gorm/postgres) from 1.0.6 to 1.0.7. - [Release notes](https://github.com/go-gorm/postgres/releases) - [Commits](https://github.com/go-gorm/postgres/compare/v1.0.6...v1.0.7) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index ec85e5be0..93892dd36 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,6 @@ require ( 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 f732280e9..1d2f80d72 100644 --- a/go.sum +++ b/go.sum @@ -644,10 +644,12 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie 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/driver/postgres v1.0.7/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg= 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/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= From d8bb28415640390658e314c1a50b12ceb907b328 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 28 Jan 2021 16:00:12 +0900 Subject: [PATCH 475/506] return category and add tests (#1393) --- go.sum | 8 +- platform/ethereum/bounce/collection.go | 44 ++++++---- platform/ethereum/bounce/collection_test.go | 87 +++++++++++++++++++ .../ethereum/bounce/mocks/artwork_nft.json | 22 +++++ .../ethereum/bounce/mocks/pancake_bunny.json | 21 +++++ platform/ethereum/bounce/model.go | 1 + 6 files changed, 160 insertions(+), 23 deletions(-) create mode 100644 platform/ethereum/bounce/collection_test.go create mode 100644 platform/ethereum/bounce/mocks/artwork_nft.json create mode 100644 platform/ethereum/bounce/mocks/pancake_bunny.json diff --git a/go.sum b/go.sum index 1d2f80d72..f9689a028 100644 --- a/go.sum +++ b/go.sum @@ -642,13 +642,9 @@ 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/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.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/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= diff --git a/platform/ethereum/bounce/collection.go b/platform/ethereum/bounce/collection.go index e03f870d7..1fd17a6fc 100644 --- a/platform/ethereum/bounce/collection.go +++ b/platform/ethereum/bounce/collection.go @@ -16,7 +16,7 @@ func (c *Client) GetCollections(owner string, coinIndex uint) (types.CollectionP if err != nil { return nil, err } - return c.NormalizeCollections(collections, coinIndex, owner) + return c.processCollections(collections, coinIndex, owner) } @@ -25,10 +25,10 @@ func (c *Client) GetCollectibles(owner, collectionID string, coinIndex uint) (ty 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 { @@ -73,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 } @@ -83,19 +83,29 @@ func (c *Client) NormalizeCollectibles(collectibles []Collectible, coinIndex uin return nil, err } for _, c := range collectibles { - page = append(page, types.Collectible{ - ID: blockatlas.GenCollectibleId(c.ContractAddr, c.TokenID), - CollectionID: c.ContractAddr, - TokenID: c.TokenID, - ContractAddress: c.ContractAddr, - ImageUrl: normalizeUrl(info.Image), - ExternalLink: normalizeUrl(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/collection_test.go b/platform/ethereum/bounce/collection_test.go new file mode 100644 index 000000000..a7da964f3 --- /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/bounce/mocks/artwork_nft.json b/platform/ethereum/bounce/mocks/artwork_nft.json new file mode 100644 index 000000000..1cc752141 --- /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 000000000..decb0f85a --- /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 88c9fc116..cbec7ccc5 100644 --- a/platform/ethereum/bounce/model.go +++ b/platform/ethereum/bounce/model.go @@ -7,6 +7,7 @@ type Response struct { type Collectible struct { ContractAddr string `json:"contract_addr"` + ContractName string `json:"contract_name,omitempty"` TokenID string `json:"token_id"` OwnerAddr string `json:"owner_addr"` TokenURI string `json:"token_uri"` From af13ce626a502363be9207cab8ed40ef8fc117c7 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Thu, 28 Jan 2021 18:51:38 -0800 Subject: [PATCH 476/506] Implement basic block parsing metrics (#1381) * add * Update metrics.go * Add metrics config * Update metrics.go --- api/api.go | 6 +++++ cmd/api/main.go | 5 ++++ config.yml | 3 +++ config/configuration.go | 3 +++ db/models/tracker.go | 1 + db/tracker.go | 9 +++++++ go.mod | 1 + go.sum | 6 +++++ internal/metrics/metrics.go | 51 +++++++++++++++++++++++++++++++++++++ 9 files changed, 85 insertions(+) create mode 100644 internal/metrics/metrics.go diff --git a/api/api.go b/api/api.go index 2e9c95063..978d51fc1 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/cmd/api/main.go b/cmd/api/main.go index 98a166473..303bd3ddf 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 24a1b0ab7..f06968e7b 100644 --- a/config.yml +++ b/config.yml @@ -221,3 +221,6 @@ smartchain: sentry: dsn: "" + +metrics: + path: metrics diff --git a/config/configuration.go b/config/configuration.go index 0a5466f16..80a0bed0f 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -206,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 fdead1ce4..87b471fa3 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 08e61e084..0cf6dbc65 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 93892dd36..6b0af5c23 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ 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 diff --git a/go.sum b/go.sum index f9689a028..3727e1394 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= diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go new file mode 100644 index 000000000..23b6008fa --- /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) +} From 8dd3e775059bf3c9bb5978e7763657adb1113801 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 1 Feb 2021 11:35:25 +0900 Subject: [PATCH 477/506] [Collectible/Bounce] return contract name for both collection and collectible (#1397) * return contract name for both collection and collectible * Fix balance for category * merge prometheus/client_golang update --- go.mod | 2 +- go.sum | 6 +++++ platform/ethereum/bounce/collection.go | 32 ++++++++++++++++++-------- platform/ethereum/bounce/model.go | 1 + 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 6b0af5c23..74159bff6 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ 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/prometheus/client_golang v0.9.4 github.com/sirupsen/logrus v1.7.0 github.com/spf13/viper v1.7.1 github.com/streadway/amqp v1.0.0 diff --git a/go.sum b/go.sum index 3727e1394..2827728c7 100644 --- a/go.sum +++ b/go.sum @@ -353,15 +353,21 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr 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_golang v0.9.4 h1:Y8E/JaaPbmFSW2V81Ab/d8yZFYQQGbni1b1jPcG9Y6A= +github.com/prometheus/client_golang v0.9.4/go.mod h1:oCXIBxdI62A4cR6aTRJCgetEjecSIYzOEaeAn4iYEpM= 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/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= +github.com/prometheus/common v0.4.1/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/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= +github.com/prometheus/procfs v0.0.2/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= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= diff --git a/platform/ethereum/bounce/collection.go b/platform/ethereum/bounce/collection.go index 1fd17a6fc..6b6c4500f 100644 --- a/platform/ethereum/bounce/collection.go +++ b/platform/ethereum/bounce/collection.go @@ -30,23 +30,29 @@ func (c *Client) GetCollectibles(owner, collectionID string, coinIndex uint) (ty func (c *Client) processCollections(collections []Collection, coinIndex uint, owner string) (types.CollectionPage, error) { page := make(types.CollectionPage, 0) - category := map[string]bool{} + categories := map[string]*types.Collection{} + for _, cl := range collections { - // existed category - if _, ok := category[cl.ContractAddr]; ok { + // skip invalid balance + total, err := strconv.Atoi(cl.Balance) + if err != nil { continue } - total, err := strconv.Atoi(cl.Balance) - if err != nil { + // udpate existed balance + existed, ok := categories[cl.ContractAddr] + if ok { + existed.Total = existed.Total + total continue } + // skip empty info token if len(cl.TokenURI) == 0 { continue } + // fetch token info info, err := fetchTokenURI(cl.TokenURI) if err != nil { return nil, err @@ -57,9 +63,14 @@ func (c *Client) processCollections(collections []Collection, coinIndex uint, ow continue } - page = append(page, types.Collection{ + contractName := cl.ContractName + if len(contractName) == 0 { + contractName = info.Name + } + + categories[cl.ContractAddr] = &types.Collection{ Id: cl.ContractAddr, - Name: info.Name, + Name: contractName, ImageUrl: normalizeUrl(info.Image), Description: info.Description, ExternalLink: normalizeUrl(cl.TokenURI), @@ -67,8 +78,11 @@ func (c *Client) processCollections(collections []Collection, coinIndex uint, ow Address: owner, Coin: coinIndex, Type: "ERC" + cl.TokenType, - }) - category[cl.ContractAddr] = true + } + } + + for _, c := range categories { + page = append(page, *c) } return page, nil } diff --git a/platform/ethereum/bounce/model.go b/platform/ethereum/bounce/model.go index cbec7ccc5..3fd49aac3 100644 --- a/platform/ethereum/bounce/model.go +++ b/platform/ethereum/bounce/model.go @@ -24,6 +24,7 @@ type CollectibleResponse struct { type Collection struct { ContractAddr string `json:"contract_addr"` + ContractName string `json:"contract_name,omitempty"` TokenType string `json:"token_type"` TokenID string `json:"token_id"` OwnerAddr string `json:"owner_addr"` From 45dff5fd1c9d521abed7fba570c6ec4ac93d31c5 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 1 Feb 2021 13:36:14 +0900 Subject: [PATCH 478/506] [Vechain] Fix non gas token parsing (#1398) * Fix vechain parsing non VTHO token * Fix bounce typo * don't return error if ignored * fix test --- platform/ethereum/bounce/collection.go | 8 +- platform/vechain/transaction.go | 113 ++++++++++++++++--------- platform/vechain/transaction_test.go | 60 +++++++------ 3 files changed, 111 insertions(+), 70 deletions(-) diff --git a/platform/ethereum/bounce/collection.go b/platform/ethereum/bounce/collection.go index 6b6c4500f..db1925288 100644 --- a/platform/ethereum/bounce/collection.go +++ b/platform/ethereum/bounce/collection.go @@ -92,11 +92,11 @@ func (c *Client) processCollectibles(collectibles []Collectible, coinIndex uint) return types.CollectiblePage{}, nil } page := make(types.CollectiblePage, 0) - info, err := fetchTokenURI(collectibles[0].TokenURI) - if err != nil { - return nil, err - } for _, c := range collectibles { + info, err := fetchTokenURI(c.TokenURI) + if err != nil { + return nil, err + } normalized := normalizeCollectible(c, coinIndex, info) page = append(page, normalized) } diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 2272bac79..874a1045d 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -6,8 +6,10 @@ import ( "sync" log "github.com/sirupsen/logrus" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/address" + "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/numbers" "github.com/trustwallet/golibs/types" ) @@ -72,7 +74,7 @@ func (p *Platform) getTransactionChannel(id string, txChan chan types.TxPage) er return err } - txs, err := p.NormalizeTokenTransaction(srcTx, receipt) + txs, err := NormalizeTokenTransaction(srcTx, receipt) if err != nil { return err } @@ -80,44 +82,14 @@ func (p *Platform) getTransactionChannel(id string, txChan chan types.TxPage) er return nil } -func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types.TxPage, error) { - txs := make(types.TxPage, 0) - - fee, err := numbers.HexToDecimal(receipt.Paid) - if err != nil { - return txs, err - } - - originSender, err := address.EIP55Checksum(blockatlas.GetValidParameter(srcTx.Origin, srcTx.Meta.TxOrigin)) - if err != nil { - return txs, err - } - +func NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types.TxPage, error) { + // the only supported Token on VeChain is its Gas token if receipt.Reverted { - var to string - if len(srcTx.Clauses) > 0 { - to = srcTx.Clauses[0].To - if checksumTo, err := address.EIP55Checksum(to); err == nil { - to = checksumTo - } - } else { - return txs, errors.New("NormalizeBlockTransaction: srcTx.Clauses not found: " + srcTx.Id) - } - - txs = append(txs, types.Tx{ - ID: srcTx.Id, - Coin: p.Coin().ID, - From: originSender, - To: to, - Fee: types.Amount(fee), - Date: srcTx.Meta.BlockTimestamp, - Type: types.TxTokenTransfer, - Block: srcTx.Meta.BlockNumber, - Status: types.StatusError, - }) - return txs, nil + return normalizeRevertedTokenTransaction(srcTx, receipt) } + txs := make(types.TxPage, 0) + if receipt.Outputs == nil || len(receipt.Outputs) == 0 { return types.TxPage{}, errors.New("NormalizeBlockTransaction: receipt.Outputs not found: " + srcTx.Id) } @@ -126,7 +98,19 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types if len(output.Events) == 0 || len(output.Events[0].Topics) < 3 { continue } + + fee, err := numbers.HexToDecimal(receipt.Paid) + if err != nil { + return txs, err + } + + originSender, err := address.EIP55Checksum(blockatlas.GetValidParameter(srcTx.Origin, srcTx.Meta.TxOrigin)) + if err != nil { + return txs, err + } + event := output.Events[0] + value, err := numbers.HexToDecimal(event.Data) if err != nil { continue @@ -137,6 +121,10 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types continue } + if originReceiver != gasTokenAddress { + continue + } + topicsTo, err := address.EIP55Checksum(getRecipientAddress(event.Topics[2])) if err != nil { continue @@ -144,7 +132,7 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types txs = append(txs, types.Tx{ ID: srcTx.Id, - Coin: p.Coin().ID, + Coin: coin.VECHAIN, From: originSender, To: originReceiver, Fee: types.Amount(fee), @@ -153,7 +141,6 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types Block: srcTx.Meta.BlockNumber, Status: types.StatusCompleted, Meta: types.TokenTransfer{ - // the only supported Token on VeChain is its Gas token Name: gasTokenName, TokenID: originReceiver, Value: types.Amount(value), @@ -167,6 +154,56 @@ func (p *Platform) NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types return txs, nil } +func normalizeRevertedTokenTransaction(srcTx Tx, receipt TxReceipt) (types.TxPage, error) { + txs := make(types.TxPage, 0) + + fee, err := numbers.HexToDecimal(receipt.Paid) + if err != nil { + return txs, err + } + + originSender, err := address.EIP55Checksum(blockatlas.GetValidParameter(srcTx.Origin, srcTx.Meta.TxOrigin)) + if err != nil { + return txs, err + } + + var to string + if len(srcTx.Clauses) > 0 { + to = srcTx.Clauses[0].To + if checksumTo, err := address.EIP55Checksum(to); err == nil { + to = checksumTo + } + } else { + return txs, errors.New("NormalizeBlockTransaction: srcTx.Clauses not found: " + srcTx.Id) + } + + if to != gasTokenAddress { + return txs, nil + } + + txs = append(txs, types.Tx{ + ID: srcTx.Id, + Coin: coin.VECHAIN, + From: originSender, + To: to, + Fee: types.Amount(fee), + Date: srcTx.Meta.BlockTimestamp, + Type: types.TxTokenTransfer, + Block: srcTx.Meta.BlockNumber, + Status: types.StatusError, + Meta: types.TokenTransfer{ + Name: gasTokenName, + TokenID: gasTokenAddress, + Value: "0", + Symbol: gasTokenSymbol, + Decimals: gasTokenDecimals, + From: originSender, + To: to, + }, + }) + return txs, nil +} + func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { headBlock, err := p.CurrentBlockNumber() if err != nil { diff --git a/platform/vechain/transaction_test.go b/platform/vechain/transaction_test.go index 1220a9397..29c2b3b29 100644 --- a/platform/vechain/transaction_test.go +++ b/platform/vechain/transaction_test.go @@ -69,9 +69,14 @@ func TestNormalizeTokenTransaction(t *testing.T) { receiptFile string address string expected types.TxPage + wantErr error }{ - {"Normalize outgoing VTHO tx", "outgoing_vtho_tx.json", "outgoing_vtho_receipt.json", "0xe99399dd211eF54c301A5d1AA813471d92122eA8", types.TxPage{ - { + { + name: "Normalize outgoing VTHO tx", + txFile: "outgoing_vtho_tx.json", + receiptFile: "outgoing_vtho_receipt.json", + address: "0xe99399dd211eF54c301A5d1AA813471d92122eA8", + expected: types.TxPage{{ ID: "0x0677f91de4787d295087acec0a7ba317b0019fbf296fed630fdb5afbfca97a58", Coin: coin.VECHAIN, From: "0xe99399dd211eF54c301A5d1AA813471d92122eA8", @@ -91,10 +96,15 @@ func TestNormalizeTokenTransaction(t *testing.T) { Value: types.Amount("7000000000000000000"), Decimals: 18, }, - }, - }}, - {"Normalize incoming VTHO tx", "incoming_vtho_tx.json", "incoming_vtho_receipt.json", "0xe99399dd211eF54c301A5d1AA813471d92122eA8", types.TxPage{ - { + }}, + wantErr: nil, + }, + { + name: "Normalize incoming VTHO tx", + txFile: "incoming_vtho_tx.json", + receiptFile: "incoming_vtho_receipt.json", + address: "0xe99399dd211eF54c301A5d1AA813471d92122eA8", + expected: types.TxPage{{ ID: "0xb356fa7b3a371f1518a5f9bc51e951d0dac2ef04d58b532c7ca50a52aa5cddb4", Coin: coin.VECHAIN, From: "0xB5e883349e68aB59307d1604555AC890fAC47128", @@ -114,25 +124,19 @@ func TestNormalizeTokenTransaction(t *testing.T) { Value: types.Amount("1000000000000000000000"), Decimals: 18, }, - }, - }}, - {"Normalize reverted token transfer", "reverted_tx.json", "reverted_receipt.json", "0x7cFFB7632252Bae3766734d61F148f0Ea78Fc08C", types.TxPage{ - { - ID: "0x7fae32a743e42eaec54642e2a5742a185299f5b4bedaf12c60f65705661de932", - Coin: coin.VECHAIN, - From: "0x7cFFB7632252Bae3766734d61F148f0Ea78Fc08C", - To: "0xf8e1fAa0367298b55F57Ed17F7a2FF3F5F1D1628", - Date: 1610326580, - Type: types.TxTokenTransfer, - Fee: types.Amount("82618000000000000000"), - Status: types.StatusError, - Block: 7982675, - }, - }}, + }}, + wantErr: nil, + }, + { + name: "Normalize reverted token transfer", + txFile: "reverted_tx.json", + receiptFile: "reverted_receipt.json", + address: "0x7cFFB7632252Bae3766734d61F148f0Ea78Fc08C", + expected: types.TxPage{}, + wantErr: nil, + }, } - platform := Platform{} - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var tx Tx @@ -143,12 +147,12 @@ func TestNormalizeTokenTransaction(t *testing.T) { err = mock.JsonModelFromFilePath("mocks/"+tt.receiptFile, &receipt) assert.Nil(t, err) - actual, err := platform.NormalizeTokenTransaction(tx, receipt) - assert.Nil(t, err) + actual, err := NormalizeTokenTransaction(tx, receipt) + assert.Equal(t, err, tt.wantErr) - updateTransactionDirection(&actual[0], tt.address) - - assert.Equal(t, len(actual), 1, "tx could not be normalized") + if len(actual) != 0 { + updateTransactionDirection(&actual[0], tt.address) + } assert.Equal(t, tt.expected, actual, "tx don't equal") }) } From e4338073713c92ef245f779e13e9f6e73081214d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 1 Feb 2021 18:22:55 -0800 Subject: [PATCH 479/506] Bump gorm.io/driver/postgres from 1.0.7 to 1.0.8 (#1399) Bumps [gorm.io/driver/postgres](https://github.com/go-gorm/postgres) from 1.0.7 to 1.0.8. - [Release notes](https://github.com/go-gorm/postgres/releases) - [Commits](https://github.com/go-gorm/postgres/compare/v1.0.7...v1.0.8) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 74159bff6..05f2bec0f 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,6 @@ require ( 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.7 + gorm.io/driver/postgres v1.0.8 gorm.io/gorm v1.20.12 ) diff --git a/go.sum b/go.sum index 2827728c7..20db22173 100644 --- a/go.sum +++ b/go.sum @@ -656,6 +656,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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/driver/postgres v1.0.8/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= From 92cbf6380c7e285f462bfa2d1b6d8a608fbfc911 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 3 Feb 2021 10:34:11 +0900 Subject: [PATCH 480/506] Handle multiple token transfers in contract call (#1403) --- db/models/asset.go | 62 ++-- db/models/asset_test.go | 67 ++++ go.mod | 2 +- go.sum | 4 +- .../blockbook/mocks/blockbook_txs.json | 218 +++++++++++ .../bitcoin/blockbook/mocks/expected_txs.json | 127 +++++++ platform/bitcoin/blockbook/transaction.go | 39 +- .../bitcoin/blockbook/transaction_test.go | 349 +----------------- platform/vechain/transaction.go | 4 +- services/tokenindexer/indexer.go | 37 +- 10 files changed, 505 insertions(+), 404 deletions(-) create mode 100644 platform/bitcoin/blockbook/mocks/blockbook_txs.json create mode 100644 platform/bitcoin/blockbook/mocks/expected_txs.json diff --git a/db/models/asset.go b/db/models/asset.go index a961eaa18..3fd039efe 100644 --- a/db/models/asset.go +++ b/db/models/asset.go @@ -21,51 +21,61 @@ type Asset struct { Coin uint } -func AssetFrom(t types.Tx) (a Asset, ok bool) { - a.Coin = t.Coin +func AssetsFrom(t types.Tx) (assets []Asset) { switch t.Meta.(type) { case types.TokenTransfer: transfer := t.Meta.(types.TokenTransfer) - a, ok = assetFromTokenTransfer(&t, &transfer) + if asset, ok := AssetFromTokenTransfer(&t, transfer); ok { + assets = append(assets, asset) + } case *types.TokenTransfer: transfer := t.Meta.(*types.TokenTransfer) - a, ok = assetFromTokenTransfer(&t, transfer) + if asset, ok := AssetFromTokenTransfer(&t, *transfer); ok { + assets = append(assets, asset) + } case types.NativeTokenTransfer: transfer := t.Meta.(types.NativeTokenTransfer) - a, ok = assetFromNativeTokenTransfer(&t, &transfer) + if asset, ok := AssetFromNativeTokenTransfer(&t, &transfer); ok { + assets = append(assets, asset) + } case *types.NativeTokenTransfer: transfer := t.Meta.(*types.NativeTokenTransfer) - a, ok = assetFromNativeTokenTransfer(&t, transfer) - case types.AnyAction: - action := t.Meta.(types.AnyAction) - a, ok = assetFromAnyAction(&t, &action) - case *types.AnyAction: - action := t.Meta.(*types.AnyAction) - a, ok = assetFromAnyAction(&t, action) + if asset, ok := AssetFromNativeTokenTransfer(&t, transfer); ok { + assets = append(assets, asset) + } default: break } - if !ok || a.IsValid() != nil { - return Asset{}, false + for _, transfer := range t.TokenTransfers { + //Improve this later. Making cure we only include assets associated with current addresses + for _, address := range t.GetAddresses() { + if address == transfer.To || address == transfer.From { + if asset, ok := AssetFromTokenTransfer(&t, transfer); ok { + assets = append(assets, asset) + } + } + } } + return } -func assetFromTokenTransfer(t *types.Tx, transfer *types.TokenTransfer) (a Asset, ok bool) { +func AssetFromTokenTransfer(t *types.Tx, transfer types.TokenTransfer) (a Asset, ok bool) { tp, ok := types.GetTokenType(t.Coin, transfer.TokenID) if !ok { - return + return a, ok } a.Asset = asset.BuildID(t.Coin, transfer.TokenID) a.Decimals = transfer.Decimals a.Name = transfer.Name a.Symbol = transfer.Symbol a.Type = tp - return + a.Coin = t.Coin + return a, a.IsValid() == nil } -func assetFromNativeTokenTransfer(t *types.Tx, transfer *types.NativeTokenTransfer) (a Asset, ok bool) { +func AssetFromNativeTokenTransfer(t *types.Tx, transfer *types.NativeTokenTransfer) (a Asset, ok bool) { tp, ok := types.GetTokenType(t.Coin, transfer.TokenID) if !ok { return @@ -75,20 +85,8 @@ func assetFromNativeTokenTransfer(t *types.Tx, transfer *types.NativeTokenTransf a.Name = transfer.Name a.Symbol = transfer.Symbol a.Type = tp - return -} - -func assetFromAnyAction(t *types.Tx, action *types.AnyAction) (a Asset, ok bool) { - tp, ok := types.GetTokenType(t.Coin, action.TokenID) - if !ok { - return - } - a.Asset = asset.BuildID(t.Coin, action.TokenID) - a.Decimals = action.Decimals - a.Name = action.Name - a.Symbol = action.Symbol - a.Type = tp - return + a.Coin = t.Coin + return a, a.IsValid() == nil } func (asset *Asset) IsValid() error { diff --git a/db/models/asset_test.go b/db/models/asset_test.go index 8dc1e105d..0f5cd60b9 100644 --- a/db/models/asset_test.go +++ b/db/models/asset_test.go @@ -1,8 +1,11 @@ package models import ( + "reflect" "testing" "time" + + "github.com/trustwallet/golibs/types" ) func TestAsset_isValid1(t *testing.T) { @@ -64,3 +67,67 @@ func TestAsset_isValid1(t *testing.T) { }) } } + +func TestAssetsFrom(t *testing.T) { + type args struct { + t types.Tx + } + tests := []struct { + name string + args args + wantAssets []Asset + }{ + { + "Token Transfer", + args{t: types.Tx{ + Coin: 60, + Type: types.TxTokenTransfer, + TokenTransfers: []types.TokenTransfer{ + { + Name: "Trust Wallet", + Symbol: "TWT", + TokenID: "TWT-123", + Decimals: 8, + Value: "1", + From: "0x1", + To: "0x2", + }, + }, + Meta: types.TokenTransfer{ + Name: "TW 2", + Symbol: "TWT2", + TokenID: "TWT2-123", + Decimals: 18, + Value: "0", + From: "0x2", + To: "0x123", + }, + }}, + []Asset{ + { + Asset: "c60_tTWT2-123", + Decimals: 18, + Name: "TW 2", + Symbol: "TWT2", + Type: "ERC20", + Coin: 60, + }, + { + Asset: "c60_tTWT-123", + Decimals: 8, + Name: "Trust Wallet", + Symbol: "TWT", + Type: "ERC20", + Coin: 60, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotAssets := AssetsFrom(tt.args.t); !reflect.DeepEqual(gotAssets, tt.wantAssets) { + t.Errorf("AssetsFrom() = %v, want %v", gotAssets, tt.wantAssets) + } + }) + } +} diff --git a/go.mod b/go.mod index 05f2bec0f..66688dbee 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( 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.1.0 + github.com/trustwallet/golibs v0.1.1 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 diff --git a/go.sum b/go.sum index 20db22173..52df5a16f 100644 --- a/go.sum +++ b/go.sum @@ -432,8 +432,8 @@ 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.1.0 h1:uo52Hy3WTfGkkd1Y7ti5Hl6BPhvudXG5BlmhBtgtQ6Y= -github.com/trustwallet/golibs v0.1.0/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= +github.com/trustwallet/golibs v0.1.1 h1:ZV5zbPbGD/dHcX3jnIcmdq24Llou230xYGHhK2WVvWQ= +github.com/trustwallet/golibs v0.1.1/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= diff --git a/platform/bitcoin/blockbook/mocks/blockbook_txs.json b/platform/bitcoin/blockbook/mocks/blockbook_txs.json new file mode 100644 index 000000000..e8053d5a0 --- /dev/null +++ b/platform/bitcoin/blockbook/mocks/blockbook_txs.json @@ -0,0 +1,218 @@ +{ + "transactions": [ + { + "txid": "0xb1a32935f9b015bcfdda1b2e3d281b3780d1a6f7a2d4406e05ec2b826b2349cb", + "vin": [ + { + "n": 0, + "addresses": ["0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1"], + "isAddress": true + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "addresses": ["0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849"], + "isAddress": true + } + ], + "blockHash": "0x90d6b2e0fb0f983a15738206c8e9951db53624f5e9b29628fd8b71c5400430cb", + "blockHeight": 8958320, + "confirmations": 825021, + "blockTime": 1574107019, + "value": "0", + "fees": "227056700000000", + "tokenTransfers": [ + { + "type": "ERC20", + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849", + "token": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "name": "Dai Stablecoin v1.0", + "symbol": "DAI", + "decimals": 18, + "value": "2255656573089233195" + }, + { + "type": "ERC20", + "from": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849", + "to": "0xad37fd42185Ba63009177058208dd1be4b136e6b", + "token": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "name": "Dai Stablecoin v1.0", + "symbol": "DAI", + "decimals": 18, + "value": "2255656573089233195" + }, + { + "type": "ERC20", + "from": "0x0000000000000000000000000000000000000000", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "token": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "name": "Dai Stablecoin", + "symbol": "DAI", + "decimals": 18, + "value": "2255656573089233195" + } + ], + "ethereumSpecific": { + "status": 1, + "nonce": 378, + "gasLimit": 3703313, + "gasUsed": 174659, + "gasPrice": "1300000000" + } + }, + { + "txid": "0x17bb2b5e61f34119d4d4fbfae406ad3d854f0a00f13013d77de9aab7179f183f", + "vin": [ + { + "n": 0, + "addresses": ["0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1"], + "isAddress": true + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "addresses": ["0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359"], + "isAddress": true + } + ], + "blockHash": "0xcee3a57858e3629785fb6e7ca34e68605fe3d2f149b73138f38314a3ef935723", + "blockHeight": 9852430, + "confirmations": 67071, + "blockTime": 1586627561, + "value": "0", + "fees": "87378000000000", + "tokenTransfers": [ + { + "type": "ERC20", + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "token": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "name": "Dai Stablecoin v1.0", + "symbol": "DAI", + "decimals": 18, + "value": "100000000000000" + } + ], + "ethereumSpecific": { + "status": 1, + "nonce": 523, + "gasLimit": 43323, + "gasUsed": 29126, + "gasPrice": "3000000000" + } + }, + { + "txid": "0x7a3929f2fad5e61f535ed5c1317f34e739655d582bc1b0161b9869b0957df6af", + "vin": [ + { + "n": 0, + "addresses": ["0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1"], + "isAddress": true + } + ], + "vout": [ + { + "value": "567000000000000", + "n": 0, + "addresses": ["0x47331175b23C2f067204B506CA1501c26731C990"], + "isAddress": true + } + ], + "blockHash": "0xf08fd4b1d6ace92bf9516bbed37de100025f8b0879a80a92359a08f37e788b95", + "blockHeight": 10050786, + "confirmations": 43, + "blockTime": 1589278824, + "value": "567000000000000", + "fees": "407799043328112", + "ethereumSpecific": { + "status": 1, + "nonce": 535, + "gasLimit": 33000, + "gasUsed": 21064, + "gasPrice": "19360000158", + "data": "0xdeadbeef" + } + }, + { + "txid": "0xb1a56570bcb072d376630b987bd1f44ecc8f2c20ece52f02c9245296d3e3da39", + "vin": [ + { + "n": 0, + "addresses": ["0x2A0A572d77F6d6Ce62C6539E679d943824c3b218"], + "isAddress": true + } + ], + "vout": [ + { + "value": "0", + "n": 0, + "addresses": ["0xdAC17F958D2ee523a2206206994597C13D831ec7"], + "isAddress": true + } + ], + "blockHeight": -1, + "confirmations": 0, + "blockTime": 1589279659, + "value": "0", + "fees": "0", + "rbf": true, + "tokenTransfers": [ + { + "type": "ERC20", + "from": "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "token": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "name": "Tether USD", + "symbol": "USDT", + "decimals": 6, + "value": "23000000" + } + ], + "ethereumSpecific": { + "status": -1, + "nonce": 15647, + "gasLimit": 100000, + "gasUsed": null, + "gasPrice": "28560000000", + "data": "0xa9059cbb000000000000000000000000595031ff9bf6e0c1de20349e1377f43934f8951400000000000000000000000000000000000000000000000000000000015ef3c0" + } + }, + { + "txid": "0xfe7cce9928450e356f3332485e611781e407425b5888b8b2c7c66afaa4787cb1", + "vin": [ + { + "n": 0, + "addresses": ["0x267be1C1D684F78cb4F6a176C4911b741E4Ffdc0"], + "isAddress": true + } + ], + "vout": [ + { + "value": "295000000000000000", + "n": 0, + "addresses": ["0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1"], + "isAddress": true + } + ], + "blockHeight": -1, + "confirmations": 0, + "blockTime": 1589287339, + "value": "295000000000000000", + "fees": "0", + "rbf": true, + "ethereumSpecific": { + "status": -1, + "nonce": 1282636, + "gasLimit": 30000, + "gasUsed": null, + "gasPrice": "24255000245", + "data": "0x" + } + } + ] +} diff --git a/platform/bitcoin/blockbook/mocks/expected_txs.json b/platform/bitcoin/blockbook/mocks/expected_txs.json new file mode 100644 index 000000000..1c1cdc528 --- /dev/null +++ b/platform/bitcoin/blockbook/mocks/expected_txs.json @@ -0,0 +1,127 @@ +[{ + "id": "0xb1a32935f9b015bcfdda1b2e3d281b3780d1a6f7a2d4406e05ec2b826b2349cb", + "coin": 60, + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849", + "fee": "227056700000000", + "date": 1574107019, + "block": 8958320, + "status": "completed", + "sequence": 378, + "token_transfers": [ + { + "name": "Dai Stablecoin v1.0", + "symbol": "DAI", + "token_id": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "decimals": 18, + "value": "2255656573089233195", + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849" + }, + { + "name": "Dai Stablecoin v1.0", + "symbol": "DAI", + "token_id": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "decimals": 18, + "value": "2255656573089233195", + "from": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849", + "to": "0xad37fd42185Ba63009177058208dd1be4b136e6b" + }, + { + "name": "Dai Stablecoin", + "symbol": "DAI", + "token_id": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "decimals": 18, + "value": "2255656573089233195", + "from": "0x0000000000000000000000000000000000000000", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + } + ], + "type": "contract_call", + "direction": "outgoing", + "memo": "", + "metadata": { + "input": "0x", + "value": "0" + } + },{ + "id": "0x17bb2b5e61f34119d4d4fbfae406ad3d854f0a00f13013d77de9aab7179f183f", + "coin": 60, + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "fee": "87378000000000", + "date": 1586627561, + "block": 9852430, + "status": "completed", + "sequence": 523, + "type": "token_transfer", + "direction": "yourself", + "memo": "", + "metadata": { + "name": "Dai Stablecoin v1.0", + "symbol": "DAI", + "token_id": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "decimals": 18, + "value": "100000000000000", + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + } + },{ + "id": "0x7a3929f2fad5e61f535ed5c1317f34e739655d582bc1b0161b9869b0957df6af", + "coin": 60, + "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "to": "0x47331175b23C2f067204B506CA1501c26731C990", + "fee": "407799043328112", + "date": 1589278824, + "block": 10050786, + "status": "completed", + "sequence": 535, + "type": "contract_call", + "direction": "outgoing", + "memo": "", + "metadata": { + "input": "0xdeadbeef", + "value": "567000000000000" + } + },{ + "id": "0xb1a56570bcb072d376630b987bd1f44ecc8f2c20ece52f02c9245296d3e3da39", + "coin": 60, + "from": "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218", + "to": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "fee": "2856000000000000", + "date": 1589279659, + "block": 0, + "status": "pending", + "sequence": 15647, + "type": "token_transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "name": "Tether USD", + "symbol": "USDT", + "token_id": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "decimals": 6, + "value": "23000000", + "from": "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" + } + },{ + "id": "0xfe7cce9928450e356f3332485e611781e407425b5888b8b2c7c66afaa4787cb1", + "coin": 60, + "from": "0x267be1C1D684F78cb4F6a176C4911b741E4Ffdc0", + "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", + "fee": "727650007350000", + "date": 1589287339, + "block": 0, + "status": "pending", + "sequence": 1282636, + "type": "transfer", + "direction": "incoming", + "memo": "", + "metadata": { + "value": "295000000000000000", + "symbol": "ETH", + "decimals": 18 + } + } + ] \ No newline at end of file diff --git a/platform/bitcoin/blockbook/transaction.go b/platform/bitcoin/blockbook/transaction.go index f2a412e46..7753c0018 100644 --- a/platform/bitcoin/blockbook/transaction.go +++ b/platform/bitcoin/blockbook/transaction.go @@ -46,16 +46,17 @@ func NormalizePage(srcPage TransactionsList, address, token string, coinIndex ui func normalizeTx(srcTx *Transaction, coinIndex uint) types.Tx { status, errReason := srcTx.EthereumSpecific.GetStatus() normalized := types.Tx{ - ID: srcTx.ID, - Coin: coinIndex, - From: srcTx.FromAddress(), - To: srcTx.ToAddress(), - Fee: types.Amount(srcTx.GetFee()), - Date: srcTx.BlockTime, - Block: normalizeBlockHeight(srcTx.BlockHeight), - Status: status, - Error: errReason, - Sequence: srcTx.EthereumSpecific.Nonce, + ID: srcTx.ID, + Coin: coinIndex, + From: srcTx.FromAddress(), + To: srcTx.ToAddress(), + Fee: types.Amount(srcTx.GetFee()), + Date: srcTx.BlockTime, + Block: normalizeBlockHeight(srcTx.BlockHeight), + Status: status, + Error: errReason, + Sequence: srcTx.EthereumSpecific.Nonce, + TokenTransfers: normalizeTokenTransfers(srcTx.TokenTransfers), } fillMeta(&normalized, srcTx, coinIndex) return normalized @@ -75,6 +76,22 @@ func normalizeBlockHeight(height int64) uint64 { return uint64(height) } +func normalizeTokenTransfers(tokenTransfers []TokenTransfer) []types.TokenTransfer { + result := make([]types.TokenTransfer, 0) + for _, transfer := range tokenTransfers { + result = append(result, types.TokenTransfer{ + Name: transfer.Name, + Symbol: transfer.Symbol, + TokenID: transfer.Token, + Decimals: transfer.Decimals, + Value: types.Amount(transfer.Value), + From: transfer.From, + To: transfer.To, + }) + } + return result +} + func fillMeta(final *types.Tx, tx *Transaction, coinIndex uint) { if ok := fillTokenTransfer(final, tx, coinIndex); !ok { fillTransferOrContract(final, tx, coinIndex) @@ -99,6 +116,7 @@ func fillTokenTransfer(final *types.Tx, tx *Transaction, coinIndex uint) bool { From: transfer.From, To: transfer.To, } + final.TokenTransfers = []types.TokenTransfer{} return true } return false @@ -134,6 +152,7 @@ func fillTokenTransferWithAddress(final *types.Tx, tx *Transaction, address, tok } final.Direction = direction final.Meta = metadata + final.TokenTransfers = []types.TokenTransfer{} return true } } diff --git a/platform/bitcoin/blockbook/transaction_test.go b/platform/bitcoin/blockbook/transaction_test.go index 877157f6e..4cbaf7029 100644 --- a/platform/bitcoin/blockbook/transaction_test.go +++ b/platform/bitcoin/blockbook/transaction_test.go @@ -5,9 +5,15 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/trustwallet/golibs/mock" "github.com/trustwallet/golibs/types" ) +var ( + srcPage, _ = mock.JsonStringFromFilePath("mocks/blockbook_txs.json") + want, _ = mock.JsonStringFromFilePath("mocks/expected_txs.json") +) + func TestNormalizePage(t *testing.T) { type args struct { srcPage string @@ -23,345 +29,12 @@ func TestNormalizePage(t *testing.T) { { name: "Test normalize blockbook txs", args: args{ - srcPage: `{ - "transactions": [ - { - "txid": "0xb1a32935f9b015bcfdda1b2e3d281b3780d1a6f7a2d4406e05ec2b826b2349cb", - "vin": [ - { - "n": 0, - "addresses": [ - "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" - ], - "isAddress": true - } - ], - "vout": [ - { - "value": "0", - "n": 0, - "addresses": [ - "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849" - ], - "isAddress": true - } - ], - "blockHash": "0x90d6b2e0fb0f983a15738206c8e9951db53624f5e9b29628fd8b71c5400430cb", - "blockHeight": 8958320, - "confirmations": 825021, - "blockTime": 1574107019, - "value": "0", - "fees": "227056700000000", - "tokenTransfers": [ - { - "type": "ERC20", - "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "to": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849", - "token": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", - "name": "Dai Stablecoin v1.0", - "symbol": "DAI", - "decimals": 18, - "value": "2255656573089233195" - }, - { - "type": "ERC20", - "from": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849", - "to": "0xad37fd42185Ba63009177058208dd1be4b136e6b", - "token": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", - "name": "Dai Stablecoin v1.0", - "symbol": "DAI", - "decimals": 18, - "value": "2255656573089233195" - }, - { - "type": "ERC20", - "from": "0x0000000000000000000000000000000000000000", - "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "token": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "name": "Dai Stablecoin", - "symbol": "DAI", - "decimals": 18, - "value": "2255656573089233195" - } - ], - "ethereumSpecific": { - "status": 1, - "nonce": 378, - "gasLimit": 3703313, - "gasUsed": 174659, - "gasPrice": "1300000000" - } - }, - { - "txid": "0x17bb2b5e61f34119d4d4fbfae406ad3d854f0a00f13013d77de9aab7179f183f", - "vin": [ - { - "n": 0, - "addresses": [ - "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" - ], - "isAddress": true - } - ], - "vout": [ - { - "value": "0", - "n": 0, - "addresses": [ - "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359" - ], - "isAddress": true - } - ], - "blockHash": "0xcee3a57858e3629785fb6e7ca34e68605fe3d2f149b73138f38314a3ef935723", - "blockHeight": 9852430, - "confirmations": 67071, - "blockTime": 1586627561, - "value": "0", - "fees": "87378000000000", - "tokenTransfers": [ - { - "type": "ERC20", - "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "token": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", - "name": "Dai Stablecoin v1.0", - "symbol": "DAI", - "decimals": 18, - "value": "100000000000000" - } - ], - "ethereumSpecific": { - "status": 1, - "nonce": 523, - "gasLimit": 43323, - "gasUsed": 29126, - "gasPrice": "3000000000" - } - }, - { - "txid": "0x7a3929f2fad5e61f535ed5c1317f34e739655d582bc1b0161b9869b0957df6af", - "vin": [ - { - "n": 0, - "addresses": [ - "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" - ], - "isAddress": true - } - ], - "vout": [ - { - "value": "567000000000000", - "n": 0, - "addresses": [ - "0x47331175b23C2f067204B506CA1501c26731C990" - ], - "isAddress": true - } - ], - "blockHash": "0xf08fd4b1d6ace92bf9516bbed37de100025f8b0879a80a92359a08f37e788b95", - "blockHeight": 10050786, - "confirmations": 43, - "blockTime": 1589278824, - "value": "567000000000000", - "fees": "407799043328112", - "ethereumSpecific": { - "status": 1, - "nonce": 535, - "gasLimit": 33000, - "gasUsed": 21064, - "gasPrice": "19360000158", - "data": "0xdeadbeef" - } - }, - { - "txid": "0xb1a56570bcb072d376630b987bd1f44ecc8f2c20ece52f02c9245296d3e3da39", - "vin": [ - { - "n": 0, - "addresses": [ - "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218" - ], - "isAddress": true - } - ], - "vout": [ - { - "value": "0", - "n": 0, - "addresses": [ - "0xdAC17F958D2ee523a2206206994597C13D831ec7" - ], - "isAddress": true - } - ], - "blockHeight": -1, - "confirmations": 0, - "blockTime": 1589279659, - "value": "0", - "fees": "0", - "rbf": true, - "tokenTransfers": [ - { - "type": "ERC20", - "from": "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218", - "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "token": "0xdAC17F958D2ee523a2206206994597C13D831ec7", - "name": "Tether USD", - "symbol": "USDT", - "decimals": 6, - "value": "23000000" - } - ], - "ethereumSpecific": { - "status": -1, - "nonce": 15647, - "gasLimit": 100000, - "gasUsed": null, - "gasPrice": "28560000000", - "data": "0xa9059cbb000000000000000000000000595031ff9bf6e0c1de20349e1377f43934f8951400000000000000000000000000000000000000000000000000000000015ef3c0" - } - }, - { - "txid": "0xfe7cce9928450e356f3332485e611781e407425b5888b8b2c7c66afaa4787cb1", - "vin": [ - { - "n": 0, - "addresses": [ - "0x267be1C1D684F78cb4F6a176C4911b741E4Ffdc0" - ], - "isAddress": true - } - ], - "vout": [ - { - "value": "295000000000000000", - "n": 0, - "addresses": [ - "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" - ], - "isAddress": true - } - ], - "blockHeight": -1, - "confirmations": 0, - "blockTime": 1589287339, - "value": "295000000000000000", - "fees": "0", - "rbf": true, - "ethereumSpecific": { - "status": -1, - "nonce": 1282636, - "gasLimit": 30000, - "gasUsed": null, - "gasPrice": "24255000245", - "data": "0x" - } - } - ]}`, + srcPage: srcPage, address: "0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1", token: "", coinIndex: 60, }, - want: `[{ - "id": "0xb1a32935f9b015bcfdda1b2e3d281b3780d1a6f7a2d4406e05ec2b826b2349cb", - "coin": 60, - "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "to": "0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849", - "fee": "227056700000000", - "date": 1574107019, - "block": 8958320, - "status": "completed", - "sequence": 378, - "type": "contract_call", - "direction": "outgoing", - "memo": "", - "metadata": { - "input": "0x", - "value": "0" - } - },{ - "id": "0x17bb2b5e61f34119d4d4fbfae406ad3d854f0a00f13013d77de9aab7179f183f", - "coin": 60, - "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "to": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", - "fee": "87378000000000", - "date": 1586627561, - "block": 9852430, - "status": "completed", - "sequence": 523, - "type": "token_transfer", - "direction": "yourself", - "memo": "", - "metadata": { - "name": "Dai Stablecoin v1.0", - "symbol": "DAI", - "token_id": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", - "decimals": 18, - "value": "100000000000000", - "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" - } - },{ - "id": "0x7a3929f2fad5e61f535ed5c1317f34e739655d582bc1b0161b9869b0957df6af", - "coin": 60, - "from": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "to": "0x47331175b23C2f067204B506CA1501c26731C990", - "fee": "407799043328112", - "date": 1589278824, - "block": 10050786, - "status": "completed", - "sequence": 535, - "type": "contract_call", - "direction": "outgoing", - "memo": "", - "metadata": { - "input": "0xdeadbeef", - "value": "567000000000000" - } - },{ - "id": "0xb1a56570bcb072d376630b987bd1f44ecc8f2c20ece52f02c9245296d3e3da39", - "coin": 60, - "from": "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218", - "to": "0xdAC17F958D2ee523a2206206994597C13D831ec7", - "fee": "2856000000000000", - "date": 1589279659, - "block": 0, - "status": "pending", - "sequence": 15647, - "type": "token_transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "name": "Tether USD", - "symbol": "USDT", - "token_id": "0xdAC17F958D2ee523a2206206994597C13D831ec7", - "decimals": 6, - "value": "23000000", - "from": "0x2A0A572d77F6d6Ce62C6539E679d943824c3b218", - "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1" - } - },{ - "id": "0xfe7cce9928450e356f3332485e611781e407425b5888b8b2c7c66afaa4787cb1", - "coin": 60, - "from": "0x267be1C1D684F78cb4F6a176C4911b741E4Ffdc0", - "to": "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1", - "fee": "727650007350000", - "date": 1589287339, - "block": 0, - "status": "pending", - "sequence": 1282636, - "type": "transfer", - "direction": "incoming", - "memo": "", - "metadata": { - "value": "295000000000000000", - "symbol": "ETH", - "decimals": 18 - } - } - ]`, + want: want, }, } for _, tt := range tests { @@ -375,11 +48,9 @@ func TestNormalizePage(t *testing.T) { got := NormalizePage(page, tt.args.address, tt.args.token, tt.args.coinIndex) gotJson, err := json.Marshal(got) assert.Nil(t, err) - gotTxPage, err := json.Marshal(txPage) + wantTxPage, err := json.Marshal(txPage) assert.Nil(t, err) - if string(gotJson) != string(gotTxPage) { - t.Errorf("NormalizePage() = %v, want %v", string(gotJson), string(gotTxPage)) - } + assert.JSONEq(t, string(gotJson), string(wantTxPage)) }) } } diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 874a1045d..3c2b978fa 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -54,7 +54,9 @@ func (p *Platform) getTransactionsByIDs(ids []string) chan types.TxPage { defer wg.Done() err := p.getTransactionChannel(i, c) if err != nil { - log.Error(err) + log.WithFields(log.Fields{ + "hash": i, + }).Error("Vechain Tx error") } }(id, txChan) } diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index 44c2c970e..065b0ed65 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -22,18 +22,19 @@ func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) error { log.WithFields(log.Fields{"service": TokenIndexer, "body": string(delivery.Body), "error": err}).Error("Unable to unmarshal MQ Message") return nil } - transactions = transactions.FilterTransactionsByType([]types.TransactionType{ + + assetsTxs := transactions.FilterTransactionsByType([]types.TransactionType{ + types.TxContractCall, types.TxTokenTransfer, types.TxNativeTokenTransfer, }) - if len(transactions) == 0 { + if len(assetsTxs) == 0 { return nil } // Add new assets to db - - assets := GetAssetsFromTransactions(transactions) + assets := GetAssetsFromTransactions(assetsTxs) err = database.AddNewAssets(assets) if err != nil { log.WithFields(log.Fields{"service": TokenIndexer}).Error("Failed to add new assets", err) @@ -41,7 +42,7 @@ func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) error { } // Add asset <> address association - addressAssetsMap := assetsMap(transactions) + addressAssetsMap := assetsMap(assetsTxs) return CreateAssociations(database, addressAssetsMap) } @@ -112,15 +113,12 @@ func calculateSubscriptionAssetAssociations(database *db.Instance, addressAssets } func GetAssetsFromTransactions(txs []types.Tx) []models.Asset { - var assets []models.Asset + var result []models.Asset for _, tx := range txs { - asset, ok := models.AssetFrom(tx) - if !ok { - continue - } - assets = append(assets, asset) + assets := models.AssetsFrom(tx) + result = append(result, assets...) } - return assets + return result } func assetsMap(txs types.Txs) map[string][]string { @@ -128,13 +126,14 @@ func assetsMap(txs types.Txs) map[string][]string { for _, tx := range txs { prefix := strconv.Itoa(int(tx.Coin)) + "_" addresses := tx.GetAddresses() - asset, ok := models.AssetFrom(tx) - if !ok { - continue - } - for _, address := range addresses { - assetIDs := result[prefix+address] - result[prefix+address] = append(assetIDs, asset.Asset) + assets := models.AssetsFrom(tx) + + for _, asset := range assets { + for _, address := range addresses { + assetId := prefix + address + assetIDs := result[assetId] + result[assetId] = append(assetIDs, asset.Asset) + } } } return result From 59473efa836822c1d74ee8cc9344d6cd7115a785 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 8 Feb 2021 09:45:07 +0900 Subject: [PATCH 481/506] [Zilliqa] small batch json rpc requests (#1407) * organize code into sub package rpc/viewblock * break into batches * smaller batch size * move code to golibs * bump golibs version * remove not used log --- go.mod | 2 +- go.sum | 7 +- platform/vechain/transaction.go | 9 +- platform/zilliqa/base.go | 15 ++-- platform/zilliqa/block.go | 11 ++- platform/zilliqa/model.go | 99 +--------------------- platform/zilliqa/model_test.go | 56 ++---------- platform/zilliqa/rpc.go | 78 ----------------- platform/zilliqa/rpc/client.go | 95 +++++++++++++++++++++ platform/zilliqa/rpc/model.go | 66 +++++++++++++++ platform/zilliqa/rpc/model_test.go | 28 ++++++ platform/zilliqa/transaction.go | 3 +- platform/zilliqa/transaction_test.go | 3 +- platform/zilliqa/{ => viewblock}/client.go | 9 +- platform/zilliqa/viewblock/model.go | 34 ++++++++ platform/zilliqa/viewblock/model_test.go | 28 ++++++ 16 files changed, 296 insertions(+), 247 deletions(-) delete mode 100644 platform/zilliqa/rpc.go create mode 100644 platform/zilliqa/rpc/client.go create mode 100644 platform/zilliqa/rpc/model.go create mode 100644 platform/zilliqa/rpc/model_test.go rename platform/zilliqa/{ => viewblock}/client.go (53%) create mode 100644 platform/zilliqa/viewblock/model.go create mode 100644 platform/zilliqa/viewblock/model_test.go diff --git a/go.mod b/go.mod index 66688dbee..7d66f339a 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( 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.1.1 + github.com/trustwallet/golibs v0.1.2 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 diff --git a/go.sum b/go.sum index 52df5a16f..8b34dc86d 100644 --- a/go.sum +++ b/go.sum @@ -432,8 +432,8 @@ 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.1.1 h1:ZV5zbPbGD/dHcX3jnIcmdq24Llou230xYGHhK2WVvWQ= -github.com/trustwallet/golibs v0.1.1/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= +github.com/trustwallet/golibs v0.1.2 h1:YitiMP/RzQUJo+ZAJRjBh8BBl5bf+ZJV2hqiZiUMQSw= +github.com/trustwallet/golibs v0.1.2/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= @@ -654,8 +654,7 @@ 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.7 h1:uCVjh1w7DSZ20Duo10JadA+1a0OZpgJk/o/z8pFpNQs= -gorm.io/driver/postgres v1.0.7/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg= +gorm.io/driver/postgres v1.0.8 h1:PAgM+PaHOSAeroTjHkCHCBIHHoBIf9RgPWGo8dF2DA8= gorm.io/driver/postgres v1.0.8/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= diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 3c2b978fa..b449ffe60 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -5,8 +5,6 @@ import ( "strconv" "sync" - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/address" "github.com/trustwallet/golibs/coin" @@ -52,12 +50,7 @@ func (p *Platform) getTransactionsByIDs(ids []string) chan types.TxPage { wg.Add(1) go func(i string, c chan types.TxPage) { defer wg.Done() - err := p.getTransactionChannel(i, c) - if err != nil { - log.WithFields(log.Fields{ - "hash": i, - }).Error("Vechain Tx error") - } + _ = p.getTransactionChannel(i, c) }(id, txChan) } wg.Wait() diff --git a/platform/zilliqa/base.go b/platform/zilliqa/base.go index 0ebacba58..7f4b87573 100644 --- a/platform/zilliqa/base.go +++ b/platform/zilliqa/base.go @@ -1,22 +1,21 @@ package zilliqa import ( - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/platform/zilliqa/rpc" + "github.com/trustwallet/blockatlas/platform/zilliqa/viewblock" "github.com/trustwallet/golibs/coin" - "github.com/trustwallet/golibs/network/middleware" ) type Platform struct { - client Client - rpcClient RpcClient + client viewblock.Client + rpcClient rpc.Client } -func Init(api, apiKey, rpc string) *Platform { +func Init(api, apiKey, rpcUrl string) *Platform { p := &Platform{ - client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, - rpcClient: RpcClient{client.InitClient(rpc, middleware.SentryErrorHandler)}, + client: viewblock.InitClient(api, apiKey), + rpcClient: rpc.InitClient(rpcUrl), } - p.client.Headers["X-APIKEY"] = apiKey return p } diff --git a/platform/zilliqa/block.go b/platform/zilliqa/block.go index 91022a759..8cc60c5f5 100644 --- a/platform/zilliqa/block.go +++ b/platform/zilliqa/block.go @@ -3,6 +3,7 @@ package zilliqa import ( "strconv" + "github.com/trustwallet/blockatlas/platform/zilliqa/viewblock" "github.com/trustwallet/golibs/types" ) @@ -21,11 +22,19 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { var normalized []types.Tx - txs, err := p.rpcClient.GetTxInBlock(num) + var txs []viewblock.Tx + + header, rpcTxs, err := p.rpcClient.GetTxInBlock(num) if err != nil { return nil, err } + for _, tx := range rpcTxs { + if tx := TxFromRpc(tx, header); tx != nil { + txs = append(txs, *tx) + } + } + for _, srcTx := range txs { tx := Normalize(&srcTx) normalized = append(normalized, tx) diff --git a/platform/zilliqa/model.go b/platform/zilliqa/model.go index 108427931..43fd8ef79 100644 --- a/platform/zilliqa/model.go +++ b/platform/zilliqa/model.go @@ -5,72 +5,11 @@ import ( "math/big" "strconv" - "github.com/trustwallet/golibs/client" + "github.com/trustwallet/blockatlas/platform/zilliqa/rpc" + "github.com/trustwallet/blockatlas/platform/zilliqa/viewblock" ) -type BlockTxs [][]string - -func (b BlockTxs) txs() []string { - txs := make([]string, 0) - for _, ids := range b { - txs = append(txs, ids...) - } - return txs -} - -type Tx struct { - Hash string `json:"hash"` - BlockHeight uint64 `json:"blockHeight"` - From string `json:"from"` - To string `json:"to"` - Value string `json:"value"` - Fee string `json:"fee"` - Timestamp int64 `json:"timestamp"` - Signature string `json:"signature"` - Nonce interface{} `json:"nonce"` - ReceiptSuccess bool `json:"receiptSuccess"` -} - -func (tx Tx) NonceValue() uint64 { - switch n := tx.Nonce.(type) { - case string: - r, err := strconv.Atoi(n) - if err != nil { - break - } - return uint64(r) - case int: - return uint64(n) - case float64: - return uint64(n) - } - return 0 -} - -type ChainInfo struct { - NumTxBlocks string `json:"NumTxBlocks"` -} - -type TxReceipt struct { - CumulativeGas string `json:"cumulative_gas"` - EpochNum string `json:"epoch_num"` - Success bool `json:"success"` -} - -type TxRPC struct { - ID string `json:"ID"` - Amount string `json:"amount"` - GasLimit string `json:"gasLimit"` - GasPrice string `json:"gasPrice"` - Nonce string `json:"nonce"` - Receipt TxReceipt `json:"receipt"` - SenderPubKey string `json:"senderPubKey"` - Signature string `json:"signature"` - ToAddr string `json:"toAddr"` - Version string `json:"version"` -} - -func (t *TxRPC) toTx(header BlockHeader) *Tx { +func TxFromRpc(t rpc.Tx, header rpc.BlockHeader) *viewblock.Tx { // t.recipient is not parsed correctly. Empty strings. to, err := hex.DecodeString(t.ToAddr) @@ -98,7 +37,7 @@ func (t *TxRPC) toTx(header BlockHeader) *Tx { } fee := new(big.Int).Mul(gasLimit, gasPrice) - return &Tx{ + return &viewblock.Tx{ Hash: "0x" + t.ID, BlockHeight: height, From: EncodePublicKeyToAddress(t.SenderPubKey), @@ -111,33 +50,3 @@ func (t *TxRPC) toTx(header BlockHeader) *Tx { ReceiptSuccess: t.Receipt.Success, } } - -type BlockTxRpc struct { - JsonRpc string `json:"jsonrpc"` - Error *client.RpcError `json:"error,omitempty"` - Result BlockTxs `json:"result,omitempty"` - Id string `json:"id,omitempty"` -} - -type HashesResponse struct { - ID int `json:"id"` - Jsonrpc string `json:"jsonrpc"` - Result [][]string `json:"result"` -} - -func (h HashesResponse) Txs() []string { - var result []string - for _, subRes := range h.Result { - result = append(result, subRes...) - } - return result -} - -type Block struct { - Header BlockHeader `json:"header"` -} - -type BlockHeader struct { - Number string `json:"BlockNum"` - Timestamp string `json:"Timestamp"` -} diff --git a/platform/zilliqa/model_test.go b/platform/zilliqa/model_test.go index b17204f8c..d187a4c3f 100644 --- a/platform/zilliqa/model_test.go +++ b/platform/zilliqa/model_test.go @@ -4,6 +4,9 @@ import ( "encoding/json" "reflect" "testing" + + "github.com/trustwallet/blockatlas/platform/zilliqa/rpc" + "github.com/trustwallet/blockatlas/platform/zilliqa/viewblock" ) const transaction = `{ @@ -24,7 +27,7 @@ const transaction = `{ }` func TestTxRPC_toTx(t *testing.T) { - tx := Tx{ + tx := viewblock.Tx{ Hash: "0xf73cf0a229a3d71e1a5c2ac4acbab598c706e64882a2e7c5ed6e406ce69fc16c", BlockHeight: 185343, From: "zil1jrpjd8pjuv50cfkfr7eu6yrm3rn5u8rulqhqpz", @@ -37,61 +40,16 @@ func TestTxRPC_toTx(t *testing.T) { ReceiptSuccess: true, } - var txRPC TxRPC + var txRPC rpc.Tx err := json.Unmarshal([]byte(transaction), &txRPC) if err != nil { t.Error(err) return } - header := BlockHeader{Number: "185343", Timestamp: "1603831144458128"} + header := rpc.BlockHeader{Number: "185343", Timestamp: "1603831144458128"} - if got := txRPC.toTx(header); !reflect.DeepEqual(*got, tx) { + if got := TxFromRpc(txRPC, header); !reflect.DeepEqual(*got, tx) { t.Errorf("TxRPC.toTx() = %v, want %v", *got, tx) } } - -func TestTx_NonceValue(t *testing.T) { - tests := []struct { - name string - nonce interface{} - want uint64 - }{ - {"test int", 0, 0}, - {"test float", 3.4, 3}, - {"test string", "33", 33}, - {"test error string", "test", 0}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tx := Tx{ - Nonce: tt.nonce, - } - if got := tx.NonceValue(); got != tt.want { - t.Errorf("NonceValue() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestBlockTxs_txs(t *testing.T) { - tests := []struct { - name string - b BlockTxs - want []string - }{ - {"test 1 tx", BlockTxs{{"tx1"}, {}}, []string{"tx1"}}, - {"test 2 txs 1", BlockTxs{{"tx1"}, {"tx2"}}, []string{"tx1", "tx2"}}, - {"test 2 txs 2", BlockTxs{{"tx1", "tx2"}}, []string{"tx1", "tx2"}}, - {"test 3 txs 1", BlockTxs{{"tx1", "tx2"}, {"tx3"}}, []string{"tx1", "tx2", "tx3"}}, - {"test 3 txs 2", BlockTxs{{"tx1"}, {"tx2"}, {"tx3"}}, []string{"tx1", "tx2", "tx3"}}, - {"test 4 txs", BlockTxs{{"tx1", "tx2"}, {"tx3"}, {"tx4"}}, []string{"tx1", "tx2", "tx3", "tx4"}}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.b.txs(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("txs() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/platform/zilliqa/rpc.go b/platform/zilliqa/rpc.go deleted file mode 100644 index ccfce78ef..000000000 --- a/platform/zilliqa/rpc.go +++ /dev/null @@ -1,78 +0,0 @@ -package zilliqa - -import ( - "strconv" - - "github.com/mitchellh/mapstructure" - "github.com/trustwallet/golibs/client" -) - -type RpcClient struct { - client.Request -} - -func (c *RpcClient) GetBlockchainInfo() (info *ChainInfo, err error) { - err = c.RpcCall(&info, "GetBlockchainInfo", nil) - return -} - -func (c *RpcClient) GetTx(hash string) (tx TxRPC, err error) { - err = c.RpcCall(&tx, "GetTransaction", []string{hash}) - return -} - -func (c *RpcClient) GetTransactionsHashesInBlock(number int64) ([]string, error) { - strNumber := strconv.FormatInt(number, 10) - requestBody := &client.RpcRequest{ - JsonRpc: client.JsonRpcVersion, - Method: "GetTransactionsForTxBlock", - Params: []string{strNumber}, - Id: number, - } - var result HashesResponse - err := c.Post(&result, "/", requestBody) - if err != nil { - return nil, err - } - return result.Txs(), nil -} - -func (c *RpcClient) GetTxInBlock(number int64) ([]Tx, error) { - txs := make([]Tx, 0) - hashes, err := c.GetTransactionsHashesInBlock(number) - if err != nil || len(hashes) == 0 { - return txs, err - } - - block, err := c.GetBlock(number) - if err != nil { - return txs, err - } - - var requests client.RpcRequests - for _, hash := range hashes { - requests = append(requests, &client.RpcRequest{ - Method: "GetTransaction", - Params: []string{hash}, - }) - } - responses, err := c.RpcBatchCall(requests) - if err != nil { - return nil, err - } - for _, result := range responses { - var txRPC TxRPC - if mapstructure.Decode(result.Result, &txRPC) != nil { - continue - } - if tx := txRPC.toTx(block.Header); tx != nil { - txs = append(txs, *tx) - } - } - return txs, nil -} - -func (c *RpcClient) GetBlock(number int64) (block Block, err error) { - err = c.RpcCall(&block, "GetTxBlock", []string{strconv.FormatInt(number, 10)}) - return -} diff --git a/platform/zilliqa/rpc/client.go b/platform/zilliqa/rpc/client.go new file mode 100644 index 000000000..1be7edbb1 --- /dev/null +++ b/platform/zilliqa/rpc/client.go @@ -0,0 +1,95 @@ +package rpc + +import ( + "strconv" + + "github.com/mitchellh/mapstructure" + "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/network/middleware" +) + +type Client struct { + client.Request +} + +func InitClient(url string) Client { + return Client{client.InitClient(url, middleware.SentryErrorHandler)} +} + +func (c *Client) GetBlockchainInfo() (info *ChainInfo, err error) { + err = c.RpcCall(&info, "GetBlockchainInfo", nil) + return +} + +func (c *Client) GetTx(hash string) (tx Tx, err error) { + err = c.RpcCall(&tx, "GetTransaction", []string{hash}) + return +} + +func (c *Client) GetBlock(number int64) (block Block, err error) { + err = c.RpcCall(&block, "GetTxBlock", []string{strconv.FormatInt(number, 10)}) + return +} + +func (c *Client) GetTransactionsHashesInBlock(number int64) ([]string, error) { + strNumber := strconv.FormatInt(number, 10) + requestBody := &client.RpcRequest{ + JsonRpc: client.JsonRpcVersion, + Method: "GetTransactionsForTxBlock", + Params: []string{strNumber}, + Id: number, + } + var result HashesResponse + err := c.Post(&result, "/", requestBody) + if err != nil { + return nil, err + } + return result.Txs(), nil +} + +func (c *Client) GetTxInBlock(number int64) (header BlockHeader, txs []Tx, err error) { + hashes, err := c.GetTransactionsHashesInBlock(number) + if err != nil || len(hashes) == 0 { + return + } + + block, err := c.GetBlock(number) + if err != nil { + return + } + + // Avoid 413 Payload Too Large + elements := make([]interface{}, len(hashes)) + for i := range elements { + elements[i] = hashes[i] + } + requests := client.MakeBatchRequests(elements, 500, mapHash) + + var responses []client.RpcResponse + for _, reqs := range requests { + resps, e := c.RpcBatchCall(reqs) + if e != nil { + err = e + return + } + responses = append(responses, resps...) + } + + for _, result := range responses { + var tx Tx + if mapstructure.Decode(result.Result, &tx) != nil { + continue + } + txs = append(txs, tx) + } + + return block.Header, txs, nil +} + +func mapHash(hash interface{}) client.RpcRequest { + array := []interface{}{hash} + return client.RpcRequest{ + Method: "GetTransaction", + Params: array, + } +} diff --git a/platform/zilliqa/rpc/model.go b/platform/zilliqa/rpc/model.go new file mode 100644 index 000000000..802088adf --- /dev/null +++ b/platform/zilliqa/rpc/model.go @@ -0,0 +1,66 @@ +package rpc + +import "github.com/trustwallet/golibs/client" + +type BlockTxs [][]string + +func (b BlockTxs) txs() []string { + txs := make([]string, 0) + for _, ids := range b { + txs = append(txs, ids...) + } + return txs +} + +type ChainInfo struct { + NumTxBlocks string `json:"NumTxBlocks"` +} + +type Receipt struct { + CumulativeGas string `json:"cumulative_gas"` + EpochNum string `json:"epoch_num"` + Success bool `json:"success"` +} + +type Tx struct { + ID string `json:"ID"` + Amount string `json:"amount"` + GasLimit string `json:"gasLimit"` + GasPrice string `json:"gasPrice"` + Nonce string `json:"nonce"` + Receipt Receipt `json:"receipt"` + SenderPubKey string `json:"senderPubKey"` + Signature string `json:"signature"` + ToAddr string `json:"toAddr"` + Version string `json:"version"` +} + +type HashesResponse struct { + ID int `json:"id"` + Jsonrpc string `json:"jsonrpc"` + Result [][]string `json:"result"` +} + +func (h HashesResponse) Txs() []string { + var result []string + for _, subRes := range h.Result { + result = append(result, subRes...) + } + return result +} + +type BlockTxRpc struct { + JsonRpc string `json:"jsonrpc"` + Error *client.RpcError `json:"error,omitempty"` + Result BlockTxs `json:"result,omitempty"` + Id string `json:"id,omitempty"` +} + +type Block struct { + Header BlockHeader `json:"header"` +} + +type BlockHeader struct { + Number string `json:"BlockNum"` + Timestamp string `json:"Timestamp"` +} diff --git a/platform/zilliqa/rpc/model_test.go b/platform/zilliqa/rpc/model_test.go new file mode 100644 index 000000000..d30dc5014 --- /dev/null +++ b/platform/zilliqa/rpc/model_test.go @@ -0,0 +1,28 @@ +package rpc + +import ( + "reflect" + "testing" +) + +func TestBlockTxs_txs(t *testing.T) { + tests := []struct { + name string + b BlockTxs + want []string + }{ + {"test 1 tx", BlockTxs{{"tx1"}, {}}, []string{"tx1"}}, + {"test 2 txs 1", BlockTxs{{"tx1"}, {"tx2"}}, []string{"tx1", "tx2"}}, + {"test 2 txs 2", BlockTxs{{"tx1", "tx2"}}, []string{"tx1", "tx2"}}, + {"test 3 txs 1", BlockTxs{{"tx1", "tx2"}, {"tx3"}}, []string{"tx1", "tx2", "tx3"}}, + {"test 3 txs 2", BlockTxs{{"tx1"}, {"tx2"}, {"tx3"}}, []string{"tx1", "tx2", "tx3"}}, + {"test 4 txs", BlockTxs{{"tx1", "tx2"}, {"tx3"}, {"tx4"}}, []string{"tx1", "tx2", "tx3", "tx4"}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.b.txs(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("txs() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/platform/zilliqa/transaction.go b/platform/zilliqa/transaction.go index a2f7f7961..0173f1e62 100644 --- a/platform/zilliqa/transaction.go +++ b/platform/zilliqa/transaction.go @@ -1,6 +1,7 @@ package zilliqa import ( + "github.com/trustwallet/blockatlas/platform/zilliqa/viewblock" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/types" ) @@ -24,7 +25,7 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return normalized, nil } -func Normalize(srcTx *Tx) (tx types.Tx) { +func Normalize(srcTx *viewblock.Tx) (tx types.Tx) { tx = types.Tx{ ID: srcTx.Hash, Coin: coin.ZILLIQA, diff --git a/platform/zilliqa/transaction_test.go b/platform/zilliqa/transaction_test.go index f65f4cbb1..674e2a296 100644 --- a/platform/zilliqa/transaction_test.go +++ b/platform/zilliqa/transaction_test.go @@ -4,6 +4,7 @@ import ( "reflect" "testing" + "github.com/trustwallet/blockatlas/platform/zilliqa/viewblock" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/mock" "github.com/trustwallet/golibs/types" @@ -45,7 +46,7 @@ func TestNormalizeTx(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var srcTx Tx + var srcTx viewblock.Tx _ = mock.JsonModelFromFilePath("mocks/"+tt.args.filename, &srcTx) gotTx := Normalize(&srcTx) if !reflect.DeepEqual(gotTx, tt.wantTx) { diff --git a/platform/zilliqa/client.go b/platform/zilliqa/viewblock/client.go similarity index 53% rename from platform/zilliqa/client.go rename to platform/zilliqa/viewblock/client.go index 34fc136e0..7cc9a276a 100644 --- a/platform/zilliqa/client.go +++ b/platform/zilliqa/viewblock/client.go @@ -1,15 +1,22 @@ -package zilliqa +package viewblock import ( "fmt" "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/network/middleware" ) type Client struct { client.Request } +func InitClient(api, apiKey string) Client { + c := Client{client.InitClient(api, middleware.SentryErrorHandler)} + c.Headers["X-APIKEY"] = apiKey + return c +} + func (c *Client) GetTxsOfAddress(address string) (tx []Tx, err error) { path := fmt.Sprintf("addresses/%s/txs", address) err = c.Get(&tx, path, nil) diff --git a/platform/zilliqa/viewblock/model.go b/platform/zilliqa/viewblock/model.go new file mode 100644 index 000000000..0d79d3963 --- /dev/null +++ b/platform/zilliqa/viewblock/model.go @@ -0,0 +1,34 @@ +package viewblock + +import ( + "strconv" +) + +type Tx struct { + Hash string `json:"hash"` + BlockHeight uint64 `json:"blockHeight"` + From string `json:"from"` + To string `json:"to"` + Value string `json:"value"` + Fee string `json:"fee"` + Timestamp int64 `json:"timestamp"` + Signature string `json:"signature"` + Nonce interface{} `json:"nonce"` + ReceiptSuccess bool `json:"receiptSuccess"` +} + +func (tx Tx) NonceValue() uint64 { + switch n := tx.Nonce.(type) { + case string: + r, err := strconv.Atoi(n) + if err != nil { + break + } + return uint64(r) + case int: + return uint64(n) + case float64: + return uint64(n) + } + return 0 +} diff --git a/platform/zilliqa/viewblock/model_test.go b/platform/zilliqa/viewblock/model_test.go new file mode 100644 index 000000000..c6fed418e --- /dev/null +++ b/platform/zilliqa/viewblock/model_test.go @@ -0,0 +1,28 @@ +package viewblock + +import ( + "testing" +) + +func TestTx_NonceValue(t *testing.T) { + tests := []struct { + name string + nonce interface{} + want uint64 + }{ + {"test int", 0, 0}, + {"test float", 3.4, 3}, + {"test string", "33", 33}, + {"test error string", "test", 0}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tx := Tx{ + Nonce: tt.nonce, + } + if got := tx.NonceValue(); got != tt.want { + t.Errorf("NonceValue() = %v, want %v", got, tt.want) + } + }) + } +} From e83500e6a18ebc51f13a7088cba5a080b7ef9e5a Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Fri, 12 Feb 2021 16:55:28 -0800 Subject: [PATCH 482/506] Remove trust-ray dependency (#1412) * Remove trust-ray dependency * Use InitWithBlockbook initializer --- config.yml | 17 +- config/configuration.go | 1 - platform/ethereum/base.go | 8 - platform/ethereum/trustray/block.go | 18 -- platform/ethereum/trustray/client.go | 46 ---- platform/ethereum/trustray/model.go | 53 ----- platform/ethereum/trustray/token.go | 37 --- platform/ethereum/trustray/token_test.go | 164 ------------- platform/ethereum/trustray/transaction.go | 139 ----------- .../ethereum/trustray/transaction_test.go | 225 ------------------ platform/platform.go | 18 +- 11 files changed, 17 insertions(+), 709 deletions(-) delete mode 100644 platform/ethereum/trustray/block.go delete mode 100644 platform/ethereum/trustray/client.go delete mode 100644 platform/ethereum/trustray/model.go delete mode 100644 platform/ethereum/trustray/token.go delete mode 100644 platform/ethereum/trustray/token_test.go delete mode 100644 platform/ethereum/trustray/transaction.go delete mode 100644 platform/ethereum/trustray/transaction_test.go diff --git a/config.yml b/config.yml index f06968e7b..7e19127bb 100644 --- a/config.yml +++ b/config.yml @@ -55,8 +55,7 @@ tezos: # [ETH] Ethereum: https://ethereum.org ethereum: - blockbook_api: https://eth1.trezor.io - api: https://localhost:4567 #(Trust-Ray API) + api: https://eth1.trezor.io collections_api: https://api.opensea.io # collections_api_key: [opensea_api_key] @@ -64,27 +63,27 @@ ethereum: classic: api: https://localhost:4567 -# [POA] POA Network: https://poa.network (Trust-Ray API) +# [POA] POA Network: https://poa.network poa: api: https://localhost:4567 -# [CLO] Callisto Network: https://callisto.network (Trust-Ray API) +# [CLO] Callisto Network: https://callisto.network callisto: api: https://localhost:4567 -# [GO] GoChain: https://gochain.io (Trust-Ray API) +# [GO] GoChain: https://gochain.io gochain: api: https://localhost:4567 -# [WAN] Wanchain: https://wanchain.org (Trust-Ray API) +# [WAN] Wanchain: https://wanchain.org wanchain: api: https://localhost:4567 -# [TOMO] TomoChain: https://tomochain.com (Trust-Ray API) +# [TOMO] TomoChain: https://tomochain.com tomochain: api: https://localhost:4567 -# [TT] ThunderCore: https://www.thundercore.com (Trust-Ray API) +# [TT] ThunderCore: https://www.thundercore.com thundertoken: api: https://localhost:4567 @@ -216,7 +215,7 @@ filecoin: explorer: https://filfox.info smartchain: - api: + api: "" collections_api: https://nftview.bounce.finance sentry: diff --git a/config/configuration.go b/config/configuration.go index 80a0bed0f..6f109dc22 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -32,7 +32,6 @@ type Configuration struct { } `mapstructure:"postgres"` Ethereum struct { API string `mapstructure:"api"` - BlockbookAPI string `mapstructure:"blockbook_api"` CollectionsAPI string `mapstructure:"collections_api"` CollectionsKey string `mapstructure:"collections_api_key"` } `mapstructure:"ethereum"` diff --git a/platform/ethereum/base.go b/platform/ethereum/base.go index 3f2446fae..18c246f6a 100644 --- a/platform/ethereum/base.go +++ b/platform/ethereum/base.go @@ -4,7 +4,6 @@ import ( "github.com/trustwallet/blockatlas/platform/bitcoin/blockbook" "github.com/trustwallet/blockatlas/platform/ethereum/bounce" "github.com/trustwallet/blockatlas/platform/ethereum/opensea" - "github.com/trustwallet/blockatlas/platform/ethereum/trustray" "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/network/middleware" @@ -16,13 +15,6 @@ type Platform struct { collectible CollectibleClient } -func InitTrustRay(coinType uint, api string) *Platform { - return &Platform{ - CoinIndex: coinType, - client: &trustray.Client{Request: client.InitClient(api, middleware.SentryErrorHandler)}, - } -} - func InitWithBlockbook(coinType uint, blockbookApi string) *Platform { return &Platform{ CoinIndex: coinType, diff --git a/platform/ethereum/trustray/block.go b/platform/ethereum/trustray/block.go deleted file mode 100644 index b399299ea..000000000 --- a/platform/ethereum/trustray/block.go +++ /dev/null @@ -1,18 +0,0 @@ -package trustray - -import "github.com/trustwallet/golibs/types" - -func (c *Client) GetBlockByNumber(num int64, coinIndex uint) (*types.Block, error) { - srcPage, err := c.GetBlock(num) - if err != nil { - return nil, err - } - var txs []types.Tx - for _, srcTx := range srcPage { - txs = AppendTxs(txs, &srcTx, coinIndex) - } - return &types.Block{ - Number: num, - Txs: txs, - }, nil -} diff --git a/platform/ethereum/trustray/client.go b/platform/ethereum/trustray/client.go deleted file mode 100644 index f1261438f..000000000 --- a/platform/ethereum/trustray/client.go +++ /dev/null @@ -1,46 +0,0 @@ -package trustray - -import ( - "fmt" - "net/url" - - "github.com/trustwallet/golibs/client" -) - -type Client struct { - client.Request -} - -func (c *Client) GetTxs(address string) (*Page, error) { - return c.getTxs(url.Values{"address": {address}}) -} - -func (c *Client) GetTxsWithContract(address, contract string) (*Page, error) { - return c.getTxs(url.Values{"address": {address}, "contract": {contract}}) -} - -func (c *Client) getTxs(query url.Values) (page *Page, err error) { - err = c.Get(&page, "transactions", query) - return -} - -func (c *Client) GetBlock(num int64) (page []Doc, err error) { - path := fmt.Sprintf("transactions/block/%d", num) - err = c.Get(&page, path, nil) - return -} - -func (c *Client) GetCurrentBlockNumber() (int64, error) { - var nodeInfo NodeInfo - err := c.Get(&nodeInfo, "node_info", nil) - if err != nil { - return 0, err - } - return nodeInfo.LatestBlock, nil -} - -func (c *Client) GetTokens(address string) (tp *TokenPage, err error) { - query := url.Values{"address": {address}} - err = c.Get(&tp, "tokens", query) - return -} diff --git a/platform/ethereum/trustray/model.go b/platform/ethereum/trustray/model.go deleted file mode 100644 index b29b96e4c..000000000 --- a/platform/ethereum/trustray/model.go +++ /dev/null @@ -1,53 +0,0 @@ -package trustray - -import "github.com/trustwallet/golibs/types" - -type Page struct { - Total uint `json:"total"` - Docs []Doc `json:"docs"` -} - -type TokenPage struct { - Total uint `json:"total"` - Docs []Contract `json:"docs"` -} - -type Doc struct { - Ops []Op `json:"operations"` - Contract string `json:"contract"` - ID string `json:"id"` - BlockNumber uint64 `json:"blockNumber"` - Timestamp int64 `json:"time"` - Nonce uint64 `json:"nonce"` - From string `json:"from"` - To string `json:"to"` - Value string `json:"value"` - Gas string `json:"gas"` - GasPrice string `json:"gasPrice"` - GasUsed string `json:"gasUsed"` - Input string `json:"input"` - Error string `json:"error"` - Coin uint `json:"coin"` -} - -type Op struct { - TxID string `json:"transactionId"` - Contract *Contract `json:"contract"` - From string `json:"from"` - To string `json:"to"` - Type types.TransactionType `json:"type"` - Value string `json:"value"` - Coin uint `json:"coin"` -} - -type Contract struct { - Address string `json:"address"` - Symbol string `json:"symbol"` - Decimals uint `json:"decimals"` - TotalSupply string `json:"totalSupply,omitempty"` - Name string `json:"name"` -} - -type NodeInfo struct { - LatestBlock int64 `json:"latest_block"` -} diff --git a/platform/ethereum/trustray/token.go b/platform/ethereum/trustray/token.go deleted file mode 100644 index c2d773293..000000000 --- a/platform/ethereum/trustray/token.go +++ /dev/null @@ -1,37 +0,0 @@ -package trustray - -import ( - "github.com/trustwallet/golibs/types" -) - -func (c *Client) GetTokenList(address string, coinIndex uint) ([]types.Token, error) { - account, err := c.GetTokens(address) - if err != nil { - return nil, err - } - return NormalizeTokens(account.Docs, coinIndex), nil -} - -// NormalizeToken converts a Ethereum token into the generic model -func NormalizeToken(srcToken *Contract, coinIndex uint) types.Token { - tokenType := types.GetEthereumTokenTypeByIndex(coinIndex) - - return types.Token{ - Name: srcToken.Name, - Symbol: srcToken.Symbol, - TokenID: srcToken.Address, - Coin: coinIndex, - Decimals: srcToken.Decimals, - Type: tokenType, - } -} - -// NormalizeTxs converts multiple Ethereum tokens -func NormalizeTokens(srcTokens []Contract, coinIndex uint) []types.Token { - assets := make([]types.Token, 0) - for _, srcToken := range srcTokens { - token := NormalizeToken(&srcToken, coinIndex) - assets = append(assets, token) - } - return assets -} diff --git a/platform/ethereum/trustray/token_test.go b/platform/ethereum/trustray/token_test.go deleted file mode 100644 index aea1f8cc8..000000000 --- a/platform/ethereum/trustray/token_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package trustray - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/trustwallet/golibs/types" - - "github.com/trustwallet/golibs/coin" -) - -const tokenSrc = ` -{ - "address": "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - "name": "FusChain", - "decimals": 18, - "symbol": "FUS" -}` - -type testToken struct { - apiResponse string - expected *types.Token - coin int -} - -func TestNormalizeToken(t *testing.T) { - var tests = []struct { - name string - tokenRaw string - coin int - want types.Token - }{ - { - "ethereum erc20", - tokenSrc, - coin.ETHEREUM, - types.Token{ - Name: "FusChain", - Symbol: "FUS", - Decimals: 18, - TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - Coin: coin.ETHEREUM, - Type: types.ERC20, - }, - }, - {"classic etc20", - tokenSrc, - coin.CLASSIC, - types.Token{ - Name: "FusChain", - Symbol: "FUS", - Decimals: 18, - TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - Coin: coin.CLASSIC, - Type: types.ETC20, - }, - }, - {"gochain go20", - tokenSrc, - coin.GOCHAIN, - types.Token{ - Name: "FusChain", - Symbol: "FUS", - Decimals: 18, - TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - Coin: coin.GOCHAIN, - Type: types.GO20, - }, - }, - {"thudertoken tt20", - tokenSrc, - coin.THUNDERTOKEN, - types.Token{ - Name: "FusChain", - Symbol: "FUS", - Decimals: 18, - TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - Coin: coin.THUNDERTOKEN, - Type: types.TT20, - }, - }, - {"wanchain wan20", - tokenSrc, - coin.WANCHAIN, - types.Token{ - Name: "FusChain", - Symbol: "FUS", - Decimals: 18, - TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - Coin: coin.WANCHAIN, - Type: types.WAN20, - }, - }, - {"poa poa20", - tokenSrc, - coin.POA, - types.Token{ - Name: "FusChain", - Symbol: "FUS", - Decimals: 18, - TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - Coin: coin.POA, - Type: types.POA20, - }, - }, - {"callisto clo20", - tokenSrc, - coin.CALLISTO, - types.Token{ - Name: "FusChain", - Symbol: "FUS", - Decimals: 18, - TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - Coin: coin.CALLISTO, - Type: types.CLO20, - }, - }, - {"unknown", - tokenSrc, - 1999, - types.Token{ - Name: "FusChain", - Symbol: "FUS", - Decimals: 18, - TokenID: "0xa14839c9837657EFcDE754EbEAF5cbECDd801B2A", - Coin: 1999, - Type: types.ERC20, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - testNormalizeToken(t, &testToken{ - apiResponse: tt.tokenRaw, - expected: &tt.want, - coin: tt.coin, - }) - }) - } - -} - -func testNormalizeToken(t *testing.T, _test *testToken) { - var token Contract - err := json.Unmarshal([]byte(_test.apiResponse), &token) - if err != nil { - t.Error(err) - return - } - tk := NormalizeToken(&token, uint(_test.coin)) - - resJSON, err := json.Marshal(&tk) - if err != nil { - t.Fatal(err) - } - - dstJSON, err := json.Marshal(_test.expected) - if err != nil { - t.Fatal(err) - } - - assert.JSONEq(t, string(resJSON), string(dstJSON)) -} diff --git a/platform/ethereum/trustray/transaction.go b/platform/ethereum/trustray/transaction.go deleted file mode 100644 index 9aaba6b60..000000000 --- a/platform/ethereum/trustray/transaction.go +++ /dev/null @@ -1,139 +0,0 @@ -package trustray - -import ( - "math/big" - - "github.com/trustwallet/golibs/address" - "github.com/trustwallet/golibs/coin" - "github.com/trustwallet/golibs/types" -) - -func (c *Client) GetTransactions(address string, coinIndex uint) (types.TxPage, error) { - page, err := c.GetTxs(address) - if err != nil { - return nil, err - } - return normalizePage(page, address, coinIndex), nil -} - -func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (types.TxPage, error) { - page, err := c.GetTxsWithContract(address, token) - if err != nil { - return nil, err - } - return normalizePage(page, address, coinIndex), nil -} - -func normalizePage(srcPage *Page, address string, coinIndex uint) types.TxPage { - var txs []types.Tx - for i, srcTx := range srcPage.Docs { - txs = AppendTxs(txs, &srcTx, coinIndex) - txs[i].Direction = txs[i].GetTransactionDirection(address) - } - return txs -} - -func AppendTxs(in []types.Tx, srcTx *Doc, coinIndex uint) (out []types.Tx) { - out = in - baseTx, ok := extractBase(srcTx, coinIndex) - if !ok { - return - } - - // Native ETH transaction - if len(srcTx.Ops) == 0 && srcTx.Input == "0x" { - transferTx := baseTx - transferTx.Meta = types.Transfer{ - Value: types.Amount(srcTx.Value), - Symbol: coin.Coins[coinIndex].Symbol, - Decimals: coin.Coins[coinIndex].Decimals, - } - out = append(out, transferTx) - return - } - - // Smart Contract Call - if len(srcTx.Ops) == 0 && srcTx.Input != "0x" { - contractTx := baseTx - contractTx.Meta = types.ContractCall{ - Input: srcTx.Input, - Value: srcTx.Value, - } - out = append(out, contractTx) - return - } - - if len(srcTx.Ops) == 0 { - return - } - op := &srcTx.Ops[0] - // Token transfer transaction - if op.Type == types.TxTokenTransfer && op.Contract != nil { - tokenTx := baseTx - tokenId, err := address.ToEIP55ByCoinID(op.Contract.Address, coinIndex) - if err != nil { - return - } - tokenTx.Meta = types.TokenTransfer{ - Name: op.Contract.Name, - Symbol: op.Contract.Symbol, - TokenID: tokenId, - Decimals: op.Contract.Decimals, - Value: types.Amount(op.Value), - From: op.From, - To: op.To, - } - out = append(out, tokenTx) - return - } - return -} - -func extractBase(srcTx *Doc, coinIndex uint) (base types.Tx, ok bool) { - var ( - status types.Status - errReason string - ) - - if srcTx.Error == "" { - status = types.StatusCompleted - } else { - status = types.StatusError - errReason = srcTx.Error - } - - fee := calcFee(srcTx.GasPrice, srcTx.GasUsed) - from, err := address.ToEIP55ByCoinID(srcTx.From, coinIndex) - if err != nil { - return base, false - } - to, err := address.ToEIP55ByCoinID(srcTx.To, coinIndex) - if err != nil { - return base, false - } - base = types.Tx{ - ID: srcTx.ID, - Coin: coinIndex, - Fee: types.Amount(fee), - From: from, - To: to, - Date: srcTx.Timestamp, - Block: srcTx.BlockNumber, - Status: status, - Error: errReason, - Sequence: srcTx.Nonce, - } - - return base, true -} - -func calcFee(gasPrice string, gasUsed string) string { - var gasPriceBig, gasUsedBig, feeBig big.Int - - gasPriceBig.SetString(gasPrice, 10) - gasUsedBig.SetString(gasUsed, 10) - - feeBig.Mul(&gasPriceBig, &gasUsedBig) - - return feeBig.String() -} diff --git a/platform/ethereum/trustray/transaction_test.go b/platform/ethereum/trustray/transaction_test.go deleted file mode 100644 index 4aec0edd0..000000000 --- a/platform/ethereum/trustray/transaction_test.go +++ /dev/null @@ -1,225 +0,0 @@ -package trustray - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/trustwallet/golibs/coin" - "github.com/trustwallet/golibs/types" -) - -const tokenTransferSrc = ` -{ - "operations": [ - { - "transactionId": "0x7777854580f273df61e0162e1a41b3e1e05ab8b9f553036fa9329a90dd7e9ab2-0", - "contract": { - "address": "0xf3586684107ce0859c44aa2b2e0fb8cd8731a15a", - "symbol": "KBC", - "decimals": 7, - "totalSupply": "120000000000000000", - "name": "KaratBank Coin" - }, - "from": "0xd35F30D194684a391C63A6decEd7d3dd5207c265", - "to": "0xaA4D790076f1Bf7511a0A0AC498C89e13e1eFE17", - "type": "token_transfer", - "value": "4291000000", - "coin": 60 - } - ], - "contract": null, - "_id": "0x7777854580f273df61e0162e1a41b3e1e05ab8b9f553036fa9329a90dd7e9ab2", - "blockNumber": 7491945, - "time": 1554248437, - "nonce": 88, - "from": "0xd35f30d194684a391c63a6deced7d3dd5207c265", - "to": "0xf3586684107ce0859c44aa2b2e0fb8cd8731a15a", - "value": "0", - "gas": "67497", - "gasPrice": "6900000256", - "gasUsed": "51921", - "input": "0xa9059cbb000000000000000000000000aa4d790076f1bf7511a0a0ac498c89e13e1efe1700000000000000000000000000000000000000000000000000000000ffc376c0", - "error": "", - "id": "0x7777854580f273df61e0162e1a41b3e1e05ab8b9f553036fa9329a90dd7e9ab2", - "coin": 60 -}` - -const contractCallSrc = ` -{ - "addresses": [ - "0x09862ed5908c0a336f9f92e5ffeb9768deac6091" - ], - "operations": [], - "contract": "0xe4dc0f23b1a3f2c47dc288a22f72e100e9b1cd70", - "_id": "0x34ab0028a9aa794d5cc12887e7b813cec17889948276b301028f24a408da6da4", - "blockNumber": 7522627, - "time": 1554661737, - "nonce": 534, - "from": "0xc9a16a82c284efc3cb0fe8c891ab85d6eba0eefb", - "to": "0xc67f9c909c4d185e4a5d21d642c27d05a145a76c", - "value": "1800000000000000000", - "gas": "1000000", - "gasPrice": "2000000000", - "gasUsed": "21340", - "input": "0xfffdefefed", - "error": "", - "id": "0x34ab0028a9aa794d5cc12887e7b813cec17889948276b301028f24a408da6da4", - "coin": 60 -} -` - -const transferSrc = ` -{ - "operations": [], - "contract": null, - "_id": "0x77f8a3b2203933493d103a1637de814b4853410b1fb2981c4d2cff4d7a3071ab", - "blockNumber": 7522781, - "time": 1554663642, - "nonce": 88, - "from": "0xf5aea47e57c058881b31ee8fce1002c409188f06", - "to": "0x0ae933a89d9e249d0873cfc7ca022fcb3f1280ce", - "value": "1999895000000000000", - "gas": "21000", - "gasPrice": "5000000000", - "gasUsed": "21000", - "input": "0x", - "error": "", - "id": "0x77f8a3b2203933493d103a1637de814b4853410b1fb2981c4d2cff4d7a3071ab", - "coin": 60 -}` - -const failedSrc = ` -{ - "operations": [], - "contract": null, - "_id": "0x8dfe7e859f7bdcea4e6f4ada18567d96a51c3aa29e618ef09b80ae99385e191e", - "blockNumber": 7522678, - "time": 1554662399, - "nonce": 1, - "from": "0x4b55af7ce28a113d794f9a9940fe1506f37aa619", - "to": "0xe65f787c8561a4b15771111bb427274dedfe85d7", - "value": "59859820000000000", - "gas": "21000", - "gasPrice": "3000000000", - "gasUsed": "21000", - "input": "0x", - "error": "Error", - "id": "0x8dfe7e859f7bdcea4e6f4ada18567d96a51c3aa29e618ef09b80ae99385e191e", - "coin": 60 -}` - -var ( - addr1 = "0xd35F30D194684a391C63A6decEd7d3dd5207c265" - addr2 = "0xaA4D790076f1Bf7511a0A0AC498C89e13e1eFE17" - contract1 = "0xf3586684107CE0859c44aa2b2E0fB8cd8731a15a" -) -var tokenTransferDst = types.Tx{ - ID: "0x7777854580f273df61e0162e1a41b3e1e05ab8b9f553036fa9329a90dd7e9ab2", - Coin: coin.ETHEREUM, - From: addr1, - To: contract1, - Fee: "358254913291776", - Date: 1554248437, - Block: 7491945, - Sequence: 88, - Status: types.StatusCompleted, - Meta: types.TokenTransfer{ - Name: "KaratBank Coin", - Symbol: "KBC", - TokenID: contract1, - Decimals: 7, - Value: "4291000000", - From: addr1, - To: addr2, - }, -} - -var contractCallDst = types.Tx{ - ID: "0x34ab0028a9aa794d5cc12887e7b813cec17889948276b301028f24a408da6da4", - Coin: coin.ETHEREUM, - From: "0xc9a16a82c284EFC3cB0fE8C891ab85d6EBa0EeFB", - To: "0xc67f9C909C4d185E4A5d21D642c27D05A145a76c", - Fee: "42680000000000", - Date: 1554661737, - Block: 7522627, - Sequence: 534, - Status: types.StatusCompleted, - Meta: types.ContractCall{ - Input: "0xfffdefefed", - Value: "1800000000000000000", - }, -} - -var transferDst = types.Tx{ - ID: "0x77f8a3b2203933493d103a1637de814b4853410b1fb2981c4d2cff4d7a3071ab", - Coin: coin.ETHEREUM, - From: "0xf5AeA47E57c058881B31EE8fcE1002C409188F06", - To: "0x0Ae933A89D9E249D0873cfc7CA022fCB3F1280Ce", - Fee: "105000000000000", - Date: 1554663642, - Block: 7522781, - Sequence: 88, - Status: types.StatusCompleted, - Meta: types.Transfer{ - Value: "1999895000000000000", - Symbol: "ETH", - Decimals: 18, - }, -} - -var failedDst = types.Tx{ - ID: "0x8dfe7e859f7bdcea4e6f4ada18567d96a51c3aa29e618ef09b80ae99385e191e", - Coin: coin.ETHEREUM, - From: "0x4b55af7cE28A113D794F9A9940fe1506f37aA619", - To: "0xE65f787c8561A4b15771111bb427274deDfe85D7", - Fee: "63000000000000", - Date: 1554662399, - Block: 7522678, - Sequence: 1, - Status: types.StatusError, - Error: "Error", - Meta: types.Transfer{ - Value: "59859820000000000", - Symbol: "ETH", - Decimals: 18, - }, -} - -func TestNormalize(t *testing.T) { - var ( - doc Doc - tests = []struct { - name, apiResponse string - expected *types.Tx - }{ - {"transfer", transferSrc, &transferDst}, - {"token transfer", tokenTransferSrc, &tokenTransferDst}, - {"contract call", contractCallSrc, &contractCallDst}, - {"failed transaction", failedSrc, &failedDst}, - } - ) - - t.Run("TestNormalize", func(t *testing.T) { - for _, tt := range tests { - err := json.Unmarshal([]byte(tt.apiResponse), &doc) - if err != nil { - t.Error(err) - return - } - res := AppendTxs(nil, &doc, coin.ETHEREUM) - - resJSON, err := json.Marshal(res) - if err != nil { - t.Fatal(err) - } - - dstJSON, err := json.Marshal([]types.Tx{*tt.expected}) - if err != nil { - t.Fatal(err) - } - - assert.JSONEq(t, string(resJSON), string(dstJSON)) - } - }) -} diff --git a/platform/platform.go b/platform/platform.go index 171c374e4..1a7f17101 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -85,15 +85,15 @@ func getAllHandlers() blockatlas.Platforms { 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.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.Gochain().Handle: ethereum.InitWithBlockbook(coin.GOCHAIN, config.Default.Gochain.API), + coin.Thundertoken().Handle: ethereum.InitWithBlockbook(coin.THUNDERTOKEN, config.Default.Thundertoken.API), + coin.Classic().Handle: ethereum.InitWithBlockbook(coin.CLASSIC, config.Default.Classic.API), + coin.Poa().Handle: ethereum.InitWithBlockbook(coin.POA, config.Default.Poa.API), + coin.Callisto().Handle: ethereum.InitWithBlockbook(coin.CALLISTO, config.Default.Callisto.API), + coin.Wanchain().Handle: ethereum.InitWithBlockbook(coin.WANCHAIN, config.Default.Wanchain.API), + coin.Tomochain().Handle: ethereum.InitWithBlockbook(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.Ethereum().Handle: ethereum.InitWithOpenSea(coin.ETHEREUM, config.Default.Ethereum.API, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey), coin.Near().Handle: near.Init(config.Default.Near.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), @@ -102,7 +102,7 @@ func getAllHandlers() blockatlas.Platforms { func getCollectionsHandlers() blockatlas.CollectionsAPIs { return blockatlas.CollectionsAPIs{ - coin.ETHEREUM: ethereum.InitWithOpenSea(coin.ETHEREUM, config.Default.Ethereum.BlockbookAPI, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey), + coin.ETHEREUM: ethereum.InitWithOpenSea(coin.ETHEREUM, config.Default.Ethereum.API, config.Default.Ethereum.CollectionsAPI, config.Default.Ethereum.CollectionsKey), coin.SMARTCHAIN: ethereum.InitWithBounce(coin.SMARTCHAIN, config.Default.Smartchain.API, config.Default.Smartchain.CollectionsAPI), } } From cc84c66958df8c558670cf25f206eb5bb9bd9be2 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 13 Feb 2021 10:14:44 +0900 Subject: [PATCH 483/506] remove async for vechain (#1410) --- platform/vechain/block.go | 14 +++---- platform/vechain/transaction.go | 67 ++++++++++++++------------------- 2 files changed, 34 insertions(+), 47 deletions(-) diff --git a/platform/vechain/block.go b/platform/vechain/block.go index ac8b4f237..5cb22b387 100644 --- a/platform/vechain/block.go +++ b/platform/vechain/block.go @@ -11,13 +11,11 @@ func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { if err != nil { return nil, err } - cTxs := p.getTransactionsByIDs(block.Transactions) - txs := make(types.TxPage, 0) - for t := range cTxs { - txs = append(txs, t...) + + txs, err := p.getTransactionsByIDs(block.Transactions) + if err != nil { + return nil, err } - return &types.Block{ - Number: num, - Txs: txs, - }, nil + + return &types.Block{Number: num, Txs: txs}, nil } diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index b449ffe60..93d6f8bd7 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -3,7 +3,6 @@ package vechain import ( "errors" "strconv" - "sync" "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/address" @@ -12,27 +11,29 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (page types.TxPage, err error) { if token != gasTokenAddress { - return nil, nil + return } - curBlock, err := p.CurrentBlockNumber() + + blockNumber, err := p.CurrentBlockNumber() if err != nil { - return nil, err + return } - events, err := p.client.GetLogsEvent(address, token, curBlock) + + events, err := p.client.GetLogsEvent(address, token, blockNumber) if err != nil { - return nil, err + return } + eventsIDs := make([]string, 0) for _, event := range events { eventsIDs = append(eventsIDs, event.Meta.TxId) } - cTxs := p.getTransactionsByIDs(eventsIDs) - txs := make(types.TxPage, 0) - for t := range cTxs { - txs = append(txs, t...) + txs, err := p.getTransactionsByIDs(eventsIDs) + if err != nil { + return } // NormalizeTokenTransaction won't set tx direction anymore, set it here @@ -43,38 +44,26 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, er return txs, nil } -func (p *Platform) getTransactionsByIDs(ids []string) chan types.TxPage { - txChan := make(chan types.TxPage, len(ids)) - var wg sync.WaitGroup +func (p *Platform) getTransactionsByIDs(ids []string) (types.TxPage, error) { + page := types.TxPage{} for _, id := range ids { - wg.Add(1) - go func(i string, c chan types.TxPage) { - defer wg.Done() - _ = p.getTransactionChannel(i, c) - }(id, txChan) - } - wg.Wait() - close(txChan) - return txChan -} - -func (p *Platform) getTransactionChannel(id string, txChan chan types.TxPage) error { - srcTx, err := p.client.GetTransactionByID(id) - if err != nil { - return err - } + tx, err := p.client.GetTransactionByID(id) + if err != nil { + return nil, err + } - receipt, err := p.client.GetTransactionReceiptByID(id) - if err != nil { - return err - } + receipt, err := p.client.GetTransactionReceiptByID(id) + if err != nil { + return page, err + } - txs, err := NormalizeTokenTransaction(srcTx, receipt) - if err != nil { - return err + txs, err := NormalizeTokenTransaction(tx, receipt) + if err != nil { + return page, err + } + page = append(page, txs...) } - txChan <- txs - return nil + return page, nil } func NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types.TxPage, error) { From ec137f5bb16cbe2ee40ffb3648e4b7f06a31051c Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Wed, 17 Feb 2021 14:04:39 -0800 Subject: [PATCH 484/506] Add enabled to metrics (#1416) --- internal/metrics/metrics.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 23b6008fa..901952167 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -1,6 +1,7 @@ package metrics import ( + "strconv" "time" "github.com/trustwallet/blockatlas/db" @@ -33,7 +34,7 @@ func setupUpdateTrackerMetrics(db *db.Instance) { continue } for _, tracker := range trackers { - labels := prometheus.Labels{"coin": tracker.Coin, "priority": tracker.Priority} + labels := prometheus.Labels{"coin": tracker.Coin, "priority": tracker.Priority, "enabled": strconv.FormatBool(tracker.Enabled)} workerBlockParsing.With(labels).Set(float64(tracker.Height)) } time.Sleep(1 * time.Second) From 31539d1b3ffa06ef4a9aafb43000e038faf306ff Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Wed, 17 Feb 2021 14:18:27 -0800 Subject: [PATCH 485/506] Add enabled to list of GaugeOpts --- internal/metrics/metrics.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 901952167..831b69881 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -22,6 +22,7 @@ var ( []string{ "coin", "priority", + "enabled", }, ) ) From f41a1d0a6a50d2af8d15b3e4b39549d847fb82f3 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 18 Feb 2021 08:11:59 +0900 Subject: [PATCH 486/506] [Solana] support block parsing (#1413) * support solana block parsing * code cleanup, staking api will be implemented in client * handle skipped block * use existing method --- go.mod | 4 +- go.sum | 8 +- pkg/blockatlas/models.go | 10 ++ platform/solana/base.go | 5 +- platform/solana/block.go | 37 ++++ platform/solana/client.go | 48 ++---- platform/solana/mocks/GetTxsByAddress.json | 33 +++- platform/solana/mocks/currentValidators.json | 38 ---- .../solana/mocks/getConfirmedTransaction.json | 3 + platform/solana/model.go | 98 +++-------- platform/solana/stake.go | 156 ----------------- platform/solana/stake_test.go | 162 ------------------ platform/solana/transaction.go | 92 ++++++---- platform/solana/transaction_test.go | 43 +---- 14 files changed, 190 insertions(+), 547 deletions(-) create mode 100644 platform/solana/block.go delete mode 100644 platform/solana/mocks/currentValidators.json delete mode 100644 platform/solana/stake.go delete mode 100644 platform/solana/stake_test.go diff --git a/go.mod b/go.mod index 7d66f339a..b473a55ec 100644 --- a/go.mod +++ b/go.mod @@ -19,13 +19,13 @@ require ( github.com/ory/dockertest v3.3.5+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible github.com/prometheus/client_golang v0.9.4 - github.com/sirupsen/logrus v1.7.0 + github.com/sirupsen/logrus v1.7.1 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.1.2 + github.com/trustwallet/golibs v0.1.3 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 diff --git a/go.sum b/go.sum index 8b34dc86d..51e19db8f 100644 --- a/go.sum +++ b/go.sum @@ -285,6 +285,8 @@ github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= +github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -389,6 +391,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.7.1 h1:rsizeFmZP+GYwyb4V6t6qpG7ZNWzA2bvgW/yC2xHCcg= +github.com/sirupsen/logrus v1.7.1/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -432,8 +436,8 @@ 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.1.2 h1:YitiMP/RzQUJo+ZAJRjBh8BBl5bf+ZJV2hqiZiUMQSw= -github.com/trustwallet/golibs v0.1.2/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= +github.com/trustwallet/golibs v0.1.3 h1:KTGXo3k9bxNPMI/DeAY6QiRZ9OWPH6M6dxZU5n50+zQ= +github.com/trustwallet/golibs v0.1.3/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= diff --git a/pkg/blockatlas/models.go b/pkg/blockatlas/models.go index ec88d86e8..6ae14fc0d 100644 --- a/pkg/blockatlas/models.go +++ b/pkg/blockatlas/models.go @@ -1,7 +1,17 @@ package blockatlas +import "encoding/json" + type ( ResultsResponse struct { Results interface{} `json:"docs"` } ) + +func MapJsonObject(from interface{}, to interface{}) error { + bytes, err := json.Marshal(from) + if err != nil { + return err + } + return json.Unmarshal(bytes, to) +} diff --git a/platform/solana/base.go b/platform/solana/base.go index cb1b4037c..fba50c047 100644 --- a/platform/solana/base.go +++ b/platform/solana/base.go @@ -11,10 +11,7 @@ type Platform struct { } func Init(api string) *Platform { - p := &Platform{ - client: Client{client.InitJSONClient(api, middleware.SentryErrorHandler)}, - } - return p + return &Platform{client: Client{client.InitJSONClient(api, middleware.SentryErrorHandler)}} } func (p *Platform) Coin() coin.Coin { diff --git a/platform/solana/block.go b/platform/solana/block.go new file mode 100644 index 000000000..315f46704 --- /dev/null +++ b/platform/solana/block.go @@ -0,0 +1,37 @@ +package solana + +import ( + "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/types" +) + +const ( + errorSkipped = -32009 +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + return p.client.GetLasteBlock() +} + +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { + block, err := p.client.GetTransactionsInBlock(num) + if err != nil { + // solana might skip some block which makes block number is not consecutive + rpcError, ok := err.(*client.RpcError) + if ok && rpcError.Code == errorSkipped { + return &types.Block{Number: num, Txs: []types.Tx{}}, nil + } + return nil, err + } + + txs := make([]types.Tx, 0) + for _, tx := range block.Transactions { + normalized, err := p.NormalizeTx(tx, uint64(num), block.BlockTime) + if err != nil { + continue + } + txs = append(txs, normalized) + } + + return &types.Block{Number: num, Txs: txs}, nil +} diff --git a/platform/solana/client.go b/platform/solana/client.go index 524bc9c34..0741e3952 100644 --- a/platform/solana/client.go +++ b/platform/solana/client.go @@ -4,27 +4,17 @@ import ( "github.com/trustwallet/golibs/client" ) -const stakeProgramId = "Stake11111111111111111111111111111111111111" - type Client struct { client.Request } -func (c *Client) GetCurrentVoteAccounts() (validators []VoteAccount, err error) { - var v VoteAccounts - err = c.RpcCall(&v, "getVoteAccounts", []string{}) - return v.Current, err -} - -func (c *Client) GetStakeAccounts() (accounts []KeyedAccount, err error) { - err = c.RpcCall(&accounts, "getProgramAccounts", []string{stakeProgramId}) - return -} - -func (c *Client) GetAccount(pubkey string) (account Account, err error) { - var r RpcAccount - err = c.RpcCall(&r, "getAccountInfo", []string{pubkey}) - return r.Account, err +func (c *Client) GetLasteBlock() (int64, error) { + var epoch EpochInfo + err := c.RpcCall(&epoch, "getEpochInfo", []string{}) + if err != nil { + return 0, err + } + return int64(epoch.BlockHeight), nil } func (c *Client) GetEpochInfo() (epochInfo EpochInfo, err error) { @@ -32,12 +22,7 @@ func (c *Client) GetEpochInfo() (epochInfo EpochInfo, err error) { return } -func (c *Client) GetMinimumBalanceForRentExemption() (minimumBalance uint64, err error) { - err = c.RpcCall(&minimumBalance, "getMinimumBalanceForRentExemption", []uint64{4008}) - return -} - -func (c *Client) GetTransactionList(address string) ([]ConfirmedSignature, error) { +func (c *Client) GetTransactionsByAddress(address string) ([]ConfirmedTransaction, error) { var signatures []ConfirmedSignature params := []interface{}{ address, @@ -47,16 +32,11 @@ func (c *Client) GetTransactionList(address string) ([]ConfirmedSignature, error if err != nil { return nil, err } - return signatures, nil -} -func (c *Client) GetTransactions(address string) ([]ConfirmedTransaction, error) { - // get tx list - signatures, err := c.GetTransactionList(address) - if err != nil { - return nil, err - } + return c.GetTransactionSignatures(signatures) +} +func (c *Client) GetTransactionSignatures(signatures []ConfirmedSignature) ([]ConfirmedTransaction, error) { // build batch request requests := make(client.RpcRequests, 0) for _, sig := range signatures { @@ -82,4 +62,10 @@ func (c *Client) GetTransactions(address string) ([]ConfirmedTransaction, error) } } return txs, nil + +} + +func (c *Client) GetTransactionsInBlock(num int64) (block Block, err error) { + err = c.RpcCall(&block, "getConfirmedBlock", []interface{}{num, "jsonParsed"}) + return } diff --git a/platform/solana/mocks/GetTxsByAddress.json b/platform/solana/mocks/GetTxsByAddress.json index 0475d0e29..c7bf25281 100644 --- a/platform/solana/mocks/GetTxsByAddress.json +++ b/platform/solana/mocks/GetTxsByAddress.json @@ -1 +1,32 @@ -[{"id":"4aQuuc4XFP7SQrZF4z3TsFyqdRHQBF37yxK8t1jQLL97JSwGadEvUFSM4GK6DtacWzid7VT7VTaqbfJfbzzsboYt","coin":501,"from":"HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp","to":"AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q","fee":"5000","date":1588062639,"block":5632752,"status":"completed","sequence":0,"type":"transfer","direction":"incoming","memo":"","metadata":{"value":"1230000","symbol":"SOL","decimals":9}},{"id":"5QeLdXcC8GRh3KSs67Pq9sNE5uwFKkHt37crYLzcZ19ieh6RSEEGrS2r5eVXJiaXKb8M6FyKF45kHHmQRW2g1LYA","coin":501,"from":"AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q","to":"HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp","fee":"5000","date":1588026961,"block":5543556,"status":"completed","sequence":0,"type":"transfer","direction":"outgoing","memo":"","metadata":{"value":"120000","symbol":"SOL","decimals":9}}] \ No newline at end of file +[ + { + "id": "4aQuuc4XFP7SQrZF4z3TsFyqdRHQBF37yxK8t1jQLL97JSwGadEvUFSM4GK6DtacWzid7VT7VTaqbfJfbzzsboYt", + "coin": 501, + "from": "HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp", + "to": "AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q", + "fee": "5000", + "date": 1588062639, + "block": 5632752, + "status": "completed", + "sequence": 0, + "type": "transfer", + "direction": "incoming", + "memo": "", + "metadata": { "value": "1230000", "symbol": "SOL", "decimals": 9 } + }, + { + "id": "5QeLdXcC8GRh3KSs67Pq9sNE5uwFKkHt37crYLzcZ19ieh6RSEEGrS2r5eVXJiaXKb8M6FyKF45kHHmQRW2g1LYA", + "coin": 501, + "from": "AHy6YZA8BsHgQfVkk7MbwpAN94iyN7Nf1zN4nPqUN32Q", + "to": "HBYC51YrGFAZ8rM7Sj8e9uqKggpSrDYrinQDZzvMtqQp", + "fee": "5000", + "date": 1588026961, + "block": 5543556, + "status": "completed", + "sequence": 0, + "type": "transfer", + "direction": "outgoing", + "memo": "", + "metadata": { "value": "120000", "symbol": "SOL", "decimals": 9 } + } +] diff --git a/platform/solana/mocks/currentValidators.json b/platform/solana/mocks/currentValidators.json deleted file mode 100644 index 9640d66c2..000000000 --- a/platform/solana/mocks/currentValidators.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "activatedStake": 3733867423940, - "commission": 100, - "epochCredits": [ - [70, 524224, 516032], - [71, 532416, 524224], - [72, 540608, 532416], - [73, 548800, 540608], - [74, 556992, 548800], - [75, 565184, 556992], - [76, 573376, 565184], - [77, 581568, 573376], - [78, 589760, 581568], - [79, 597952, 589760], - [80, 601055, 597952] - ], - "epochVoteAccount": true, - "lastVote": 601085, - "nodePubkey": "boot1Z6jb15CLqpaMTn2CxktktwZpRAVAgHZEW6SxQ7", - "rootSlot": 601054, - "votePubkey": "2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW" - }, - { - "activatedStake": 10540011934, - "commission": 100, - "epochCredits": [ - [78, 4760, 0], - [79, 12952, 4760], - [80, 16055, 12952] - ], - "epochVoteAccount": true, - "lastVote": 601085, - "nodePubkey": "B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY", - "rootSlot": 601054, - "votePubkey": "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5" - } -] diff --git a/platform/solana/mocks/getConfirmedTransaction.json b/platform/solana/mocks/getConfirmedTransaction.json index fb308a677..ce54fc419 100644 --- a/platform/solana/mocks/getConfirmedTransaction.json +++ b/platform/solana/mocks/getConfirmedTransaction.json @@ -2,6 +2,7 @@ { "jsonrpc": "2.0", "result": { + "blockTime": 1588062639, "meta": { "err": null, "fee": 5000, @@ -67,6 +68,7 @@ { "jsonrpc": "2.0", "result": { + "blockTime": 1588026961, "meta": { "err": null, "fee": 5000, @@ -132,6 +134,7 @@ { "jsonrpc": "2.0", "result": { + "blockTime": 1613388458, "meta": { "err": { "InstructionError": [ diff --git a/platform/solana/model.go b/platform/solana/model.go index 6b97f01a3..3bb94c7c1 100644 --- a/platform/solana/model.go +++ b/platform/solana/model.go @@ -1,75 +1,18 @@ package solana -const ( - StakeStateUninitialized StakeState = 0 - StakeStateInitialized StakeState = 1 - StakeStateDelegated StakeState = 2 - StakeStateRewardsPool StakeState = 3 -) - -type StakeState uint32 - -type VoteAccount struct { - NodePubkey string `json:"nodePubkey"` - VotePubkey string `json:"votePubkey"` - Commission uint64 `json:"commission"` - ActivatedStake uint64 `json:"activatedStake"` - RootSlot uint64 `json:"rootSlot"` - LastVote uint64 `json:"lastVote"` - EpochCredits [][]uint64 `json:"epochCredits"` - EpochVoteAccount bool `json:"epochVoteAccount"` -} - -type VoteAccounts struct { - Current []VoteAccount `json:"current"` - Delinquent []VoteAccount `json:"delinquent"` -} - -type Account struct { - Data string `json:"data"` - Executable bool `json:"executable"` - Lamports uint64 `json:"lamports"` - Owner string `json:"owner"` - RentEpoch uint64 `json:"rentEpoch"` -} - -type KeyedAccount struct { - Account Account `json:"account"` - Pubkey string `json:"pubkey"` -} - -type RpcAccount struct { - Context RpcContext `json:"context"` - Account Account `json:"value"` -} - -type RpcContext struct { - Slot uint64 `json:"slot"` -} - -type StakeData struct { - State StakeState - RentExemptReserve uint64 - AuthorizedStaker [32]byte - AuthorizedWithdrawer [32]byte - UnixTimestamp int64 - LockupEpoch uint64 - Custodian [32]byte - VoterPubkey [32]byte - Stake uint64 - ActivationEpoch uint64 - DeactivationEpoch uint64 - WarmupCooldownRate float64 - CreditsObserved uint64 -} - type EpochInfo struct { AbsoluteSlot uint64 `json:"absoluteSlot"` + BlockHeight uint64 `json:"blockHeight"` Epoch uint64 `json:"epoch"` SlotIndex uint64 `json:"slotIndex"` SlotsInEpoch uint64 `json:"slotsInEpoch"` } +type Block struct { + BlockTime int64 `json:"blockTime"` + Transactions []ConfirmedTransaction `json:"transactions"` +} + type ConfirmedSignature struct { Memo string `json:"memo"` Signature string `json:"signature"` @@ -78,7 +21,8 @@ type ConfirmedSignature struct { type ConfirmedTransaction struct { Meta Meta `json:"meta"` - Slot uint64 `json:"slot"` + BlockTime int64 `json:"blockTime,omitempty"` + Slot uint64 `json:"slot,omitempty"` Transaction Transaction `json:"transaction"` } @@ -87,24 +31,36 @@ type Meta struct { Fee uint64 `json:"fee"` } -type Info struct { +type TransferInfo struct { Destination string `json:"destination"` Lamports uint64 `json:"lamports"` Source string `json:"source"` } type Parsed struct { - Info Info `json:"info"` - Type string `json:"type"` + Info interface{} `json:"info"` + Type string `json:"type"` +} + +type TokenTransferInfo struct { + Destination string `json:"destination"` + Mint string `json:"mint"` + Source string `json:"source"` + TokenAmount TokenAmount `json:"tokenAmount"` +} + +type TokenAmount struct { + Amount string `json:"amount"` + Decimals uint `json:"decimals"` } -type Instructions struct { - Parsed Parsed `json:"parsed"` - Program string `json:"program"` +type Instruction struct { + Parsed interface{} `json:"parsed"` + Program string `json:"program"` } type Message struct { - Instructions []Instructions `json:"instructions"` + Instructions []Instruction `json:"instructions"` } type Transaction struct { diff --git a/platform/solana/stake.go b/platform/solana/stake.go deleted file mode 100644 index 8ae8114e0..000000000 --- a/platform/solana/stake.go +++ /dev/null @@ -1,156 +0,0 @@ -package solana - -import ( - "bytes" - "encoding/binary" - "fmt" - "strconv" - - "github.com/btcsuite/btcutil/base58" - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/assets" - "github.com/trustwallet/golibs/types" -) - -func arrayOfPubkey(pubkey string) [32]byte { - var array [32]byte - copy(array[:], base58.Decode(pubkey)) - return array -} - -func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { - validators, err := assets.GetValidatorsMap(p) - if err != nil { - return nil, err - } - result := make(blockatlas.StakeValidators, 0, len(validators)) - for _, v := range validators { - result = append(result, v) - } - return result, nil -} - -func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { - results := make(blockatlas.ValidatorPage, 0) - - validators, err := p.client.GetCurrentVoteAccounts() - if err != nil { - return results, err - } - - minimumBalance, err := p.client.GetMinimumBalanceForRentExemption() - if err != nil { - minimumBalance = 0 - } - - for _, v := range validators { - results = append(results, normalizeValidator(v, minimumBalance)) - } - return results, nil -} - -func (p *Platform) GetDetails() blockatlas.StakingDetails { - return getDetails() -} - -func getDetails() blockatlas.StakingDetails { - return blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: "0", - LockTime: 0, - Type: blockatlas.DelegationTypeDelegate, - } -} - -func normalizeValidator(v VoteAccount, minimumBalance uint64) (validator blockatlas.Validator) { - minimumAmount := strconv.FormatUint(minimumBalance+1, 10) // Must stake at least 1 lamport - return blockatlas.Validator{ - Status: true, - ID: v.VotePubkey, - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: types.Amount(minimumAmount), - LockTime: 0, - Type: blockatlas.DelegationTypeDelegate, - }, - } -} - -func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { - accounts, err := p.client.GetStakeAccounts() - if err != nil { - return nil, err - } - - stakeAccounts := make([]StakeData, 0) - for _, keyedAccount := range accounts { - account, err := parseStakeData(keyedAccount.Account) - if err != nil { - return nil, err - } - if account.State == StakeStateDelegated && isAuthorized(account, address) { - stakeAccounts = append(stakeAccounts, account) - } - } - if len(stakeAccounts) == 0 { - return make(blockatlas.DelegationsPage, 0), nil - } - - validators, err := assets.GetValidatorsMap(p) - if err != nil { - return nil, err - } - - epochInfo, err := p.client.GetEpochInfo() - if err != nil { - return nil, err - } - - return NormalizeDelegations(stakeAccounts, validators, epochInfo) -} - -func parseStakeData(account Account) (stakeAccount StakeData, err error) { - buffer := base58.Decode(account.Data) - r := bytes.NewReader(buffer) - err = binary.Read(r, binary.LittleEndian, &stakeAccount) - return -} - -func isAuthorized(stakeAccount StakeData, address string) bool { - return stakeAccount.AuthorizedStaker == arrayOfPubkey(address) -} - -func (p *Platform) UndelegatedBalance(address string) (string, error) { - account, err := p.client.GetAccount(address) - if err != nil { - return "0", err - } - return strconv.FormatUint(account.Lamports, 10), nil -} - -func NormalizeDelegations(stakeAccounts []StakeData, validators blockatlas.ValidatorMap, epochInfo EpochInfo) (blockatlas.DelegationsPage, error) { - results := make([]blockatlas.Delegation, 0) - for _, stakeState := range stakeAccounts { - votePubkey := base58.Encode(stakeState.VoterPubkey[:]) - validator, ok := validators[votePubkey] - if !ok { - log.Debug(fmt.Sprintf("Unpublished solana validator: %s", votePubkey)) - continue - } - status := blockatlas.DelegationStatusPending - if stakeState.ActivationEpoch > 0 && stakeState.ActivationEpoch <= epochInfo.Epoch { - status = blockatlas.DelegationStatusActive - } - if epochInfo.Epoch > stakeState.DeactivationEpoch { - continue - } - delegation := blockatlas.Delegation{ - Delegator: validator, - Value: strconv.FormatUint(stakeState.Stake, 10), - Status: status, - } - results = append(results, delegation) - } - return results, nil -} diff --git a/platform/solana/stake_test.go b/platform/solana/stake_test.go deleted file mode 100644 index 319f698dd..000000000 --- a/platform/solana/stake_test.go +++ /dev/null @@ -1,162 +0,0 @@ -package solana - -import ( - "encoding/json" - "testing" - - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/mock" - "github.com/trustwallet/golibs/types" - - "github.com/stretchr/testify/assert" -) - -var ( - currentValidators, _ = mock.JsonStringFromFilePath("mocks/" + "currentValidators.json") - expectedValidators = []blockatlas.Validator{ - { - Status: true, - ID: "2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW", - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: types.Amount("2282881"), - LockTime: 0, - Type: blockatlas.DelegationTypeDelegate, - }, - }, - { - Status: true, - ID: "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5", - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 0}, - MinimumAmount: types.Amount("2282881"), - LockTime: 0, - Type: blockatlas.DelegationTypeDelegate, - }, - }, - } - - keyedStakeAccount = KeyedAccount{ - Account: Account{ - Data: "mrWMHx6j3BkmepJy67XLycC7LVeiq2NBESfV2YNmZvY62xT5jTgKnMzRBQheYtAuajncAniTEmU8QxgkpnytnXynTrMSJN4p6ihefU5cobkyCeSwMKugKGuBbyDLjQoUMu6BUKjDTFvjpJUHFCgz1Vaa8HSVscUqqRcioByf3owMUwHmEYsF8vuouLAqEQmo61wFkKfZELxLrhBbi2PQQZucryrnNDKXV4DY3oegLy9aMnMDZUeoDtDPPiJeM2F1Trh8ZkH1sQL6sQ5V", - Executable: false, - Lamports: 100000000000, - Owner: "Stake11111111111111111111111111111111111111", - RentEpoch: 80, - }, - Pubkey: "EgR17fgGmwQQaMZPsuJdk9oHw2xY8TJQj3Bp44o24mar", - } - - stakeState = StakeData{ - State: 2, - RentExemptReserve: 2282880, - AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - UnixTimestamp: 0, - LockupEpoch: 0, - Custodian: arrayOfPubkey("11111111111111111111111111111111"), - VoterPubkey: arrayOfPubkey("5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5"), - Stake: 99997717120, - ActivationEpoch: 79, - DeactivationEpoch: ^uint64(0), - WarmupCooldownRate: 0.25, - CreditsObserved: 21143, - } - - deactivatedStakeState = StakeData{ - State: 2, - RentExemptReserve: 2282880, - AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - UnixTimestamp: 0, - LockupEpoch: 0, - Custodian: arrayOfPubkey("11111111111111111111111111111111"), - VoterPubkey: arrayOfPubkey("5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5"), - Stake: 99997717120, - ActivationEpoch: 70, - DeactivationEpoch: 78, - WarmupCooldownRate: 0.25, - CreditsObserved: 21143, - } - - unpublishedValidatorStakeState = StakeData{ - State: 2, - RentExemptReserve: 2282880, - AuthorizedStaker: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - AuthorizedWithdrawer: arrayOfPubkey("B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY"), - UnixTimestamp: 0, - LockupEpoch: 0, - Custodian: arrayOfPubkey("11111111111111111111111111111111"), - VoterPubkey: arrayOfPubkey("BNTmegvdXzNVyc3UMTWSMSfJUryjr3fXEVErtdqrfs6y"), - Stake: 99997717120, - ActivationEpoch: 70, - DeactivationEpoch: 78, - WarmupCooldownRate: 0.25, - CreditsObserved: 21143, - } - - stakeValidator = blockatlas.StakeValidator{ - ID: "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5", - Status: true, - Info: blockatlas.StakeValidatorInfo{ - Name: "Certus One", - Description: "Stake and earn rewards with the most secure and stable validator. Winner of the Game of Stakes. Operated by Certus One Inc. By delegating, you confirm that you are aware of the risk of slashing and that Certus One Inc is not liable for any potential damages to your investment.", - Image: "https://assets.trustwalletapp.com/blockchains/solana/validators/assets/2Afu38M1KaSfDBpjZjnJb9BSWP6YkBkoPiBfnFedD7JW/logo.png", - Website: "https://certus.one", - }, - Details: getDetails(), - } - - validatorMap = blockatlas.ValidatorMap{ - "5CgQubGD1uwodwCe5UXDADbC69SiqXR8qq6pDMSm7ut5": stakeValidator, - } - - epochInfo = EpochInfo{ - AbsoluteSlot: 165763, - Epoch: 80, - SlotIndex: 1923, - SlotsInEpoch: 2048, - } - - delegation = blockatlas.DelegationsPage{ - { - Delegator: stakeValidator, - Value: "99997717120", - Status: blockatlas.DelegationStatusActive, - }, - } -) - -func TestNormalizeValidator(t *testing.T) { - var validators []VoteAccount - minimumBalanceForRentExemption := uint64(2282880) // Arbitrary value; minimumBalanceForRentExemption is calculated from account data size - err := json.Unmarshal([]byte(currentValidators), &validators) - assert.Nil(t, err) - for i, v := range validators { - result := normalizeValidator(v, minimumBalanceForRentExemption) - assert.Equal(t, expectedValidators[i], result) - } -} - -func TestParseStakeData(t *testing.T) { - - result, err := parseStakeData(keyedStakeAccount.Account) - assert.Nil(t, err) - assert.Equal(t, result, stakeState) -} - -func TestIsAuthorized(t *testing.T) { - address := "B52Da5MCyTcyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY" - account, _ := parseStakeData(keyedStakeAccount.Account) - assert.True(t, isAuthorized(account, address)) - - address = "BADaddresscyVJEsR9RUnbf715YuBAJMxCEEPzyZXgvY" - assert.False(t, isAuthorized(account, address)) -} - -func TestNormalizeDelegations(t *testing.T) { - stakeAccounts := []StakeData{stakeState, deactivatedStakeState, unpublishedValidatorStakeState} - result, err := NormalizeDelegations(stakeAccounts, validatorMap, epochInfo) - assert.NoError(t, err) - assert.Equal(t, delegation, result) -} diff --git a/platform/solana/transaction.go b/platform/solana/transaction.go index 4262fee7f..a1cd48860 100644 --- a/platform/solana/transaction.go +++ b/platform/solana/transaction.go @@ -2,43 +2,61 @@ package solana import ( "errors" + "fmt" "strconv" + "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/golibs/types" ) +const ( + programSystem = "system" + programToken = "spl-token" + + instructionTransfer = "transfer" + // will support instructionTransferChecked later + // instructionTransferChecked = "transferChecked" +) + func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { results := make(types.TxPage, 0) - txs, err := p.client.GetTransactions(address) + txs, err := p.client.GetTransactionsByAddress(address) if err != nil { return results, err } for _, tx := range txs { - if normalized, err := p.NormalizeTx(tx, address); err == nil { + if tx.BlockTime == 0 { + continue + } + if normalized, err := p.NormalizeTx(tx, tx.Slot, tx.BlockTime); err == nil { + normalized.Direction = normalized.GetTransactionDirection(address) results = append(results, normalized) } } return results, nil } -func (p *Platform) NormalizeTx(tx ConfirmedTransaction, address string) (normalized types.Tx, err error) { +func (p *Platform) NormalizeTx(tx ConfirmedTransaction, slot uint64, timestamp int64) (normalized types.Tx, err error) { // only check first instruction if len(tx.Transaction.Message.Instructions) != 1 || len(tx.Transaction.Signatures) != 1 { - return normalized, errors.New("not supported") + err = errors.New("not supported instructions/signatures count") + return } - // only supports transfer type now + // only supports transfer and token transfer instruction := tx.Transaction.Message.Instructions[0] - if instruction.Parsed.Type != "transfer" { - return normalized, errors.New("not supported type other than transfer") + + if instruction.Program != programSystem && instruction.Program != programToken { + err = fmt.Errorf("not supported program: %s", instruction.Program) + return } - // tx direction - from := instruction.Parsed.Info.Source - direction := types.DirectionIncoming - if address == from { - direction = types.DirectionOutgoing + var parsed Parsed + err = blockatlas.MapJsonObject(instruction.Parsed, &parsed) + + if err != nil { + return } // tx status @@ -48,32 +66,30 @@ func (p *Platform) NormalizeTx(tx ConfirmedTransaction, address string) (normali } normalized = types.Tx{ - ID: tx.Transaction.Signatures[0], - Coin: p.Coin().ID, - From: from, - To: instruction.Parsed.Info.Destination, - Fee: types.Amount(strconv.FormatUint(tx.Meta.Fee, 10)), - Date: EstimateTimestamp(tx.Slot), - Block: tx.Slot, - Status: status, - Type: types.TxTransfer, - Direction: direction, - Meta: types.Transfer{ - Value: types.Amount(strconv.FormatUint(instruction.Parsed.Info.Lamports, 10)), - Symbol: p.Coin().Symbol, - Decimals: p.Coin().Decimals, - }, + ID: tx.Transaction.Signatures[0], + Coin: p.Coin().ID, + Fee: types.Amount(strconv.FormatUint(tx.Meta.Fee, 10)), + Date: timestamp, + Block: slot, + Status: status, } - return normalized, nil -} - -func EstimateTimestamp(slot uint64) int64 { - var ( - blockTime uint64 = 400 //ms - sampleSlot uint64 = 52838300 - sampleTs uint64 = 1606944859 * 1000 - ) - offset := (slot - sampleSlot) * blockTime - return int64((sampleTs + offset) / 1000) + switch parsed.Type { + case instructionTransfer: + var transfer TransferInfo + err = blockatlas.MapJsonObject(parsed.Info, &transfer) + if err == nil { + normalized.From = transfer.Source + normalized.To = transfer.Destination + normalized.Type = types.TxTransfer + normalized.Meta = types.Transfer{ + Value: types.Amount(strconv.FormatUint(transfer.Lamports, 10)), + Symbol: p.Coin().Symbol, + Decimals: p.Coin().Decimals, + } + } + default: + err = fmt.Errorf("not supported type: %s", parsed.Type) + } + return } diff --git a/platform/solana/transaction_test.go b/platform/solana/transaction_test.go index c8c8d421c..2cea578f0 100644 --- a/platform/solana/transaction_test.go +++ b/platform/solana/transaction_test.go @@ -68,46 +68,5 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { assert.Nil(t, err) raw, err := json.Marshal(txs) assert.Nil(t, err) - assert.Equal(t, wanted, string(raw)) -} - -func TestEstimateTimestamp(t *testing.T) { - tests := []struct { - name string - slot uint64 - want int64 - }{ - { - name: "Test 0", - slot: 0, - want: 1585809539, - }, - { - name: "Test sample slot", - slot: 52838300, - want: 1606944859, - }, - { - name: "Test nomral 1", - slot: 5632752, - want: 1588062639, - }, - { - name: "Test normal 2", - slot: 5543556, - want: 1588026961, - }, - { - name: "Test normal 3", - slot: 493784, - want: 1586007052, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := EstimateTimestamp(tt.slot); got != tt.want { - t.Errorf("EstimateTimestamp() = %v, want %v", got, tt.want) - } - }) - } + assert.JSONEq(t, wanted, string(raw)) } From 99b6f571e8ea6eaa3f7c5b0de3617ad2d99037b7 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Thu, 18 Feb 2021 16:03:04 +0900 Subject: [PATCH 487/506] ignore sending empty requests (#1418) --- platform/solana/client.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/platform/solana/client.go b/platform/solana/client.go index 0741e3952..5d764db5f 100644 --- a/platform/solana/client.go +++ b/platform/solana/client.go @@ -37,6 +37,13 @@ func (c *Client) GetTransactionsByAddress(address string) ([]ConfirmedTransactio } func (c *Client) GetTransactionSignatures(signatures []ConfirmedSignature) ([]ConfirmedTransaction, error) { + var txs []ConfirmedTransaction + + // check empty + if len(signatures) == 0 { + return txs, nil + } + // build batch request requests := make(client.RpcRequests, 0) for _, sig := range signatures { @@ -48,7 +55,7 @@ func (c *Client) GetTransactionSignatures(signatures []ConfirmedSignature) ([]Co }, }) } - var txs []ConfirmedTransaction + responses, err := c.RpcBatchCall(requests) if err != nil { return txs, err @@ -62,7 +69,6 @@ func (c *Client) GetTransactionSignatures(signatures []ConfirmedSignature) ([]Co } } return txs, nil - } func (c *Client) GetTransactionsInBlock(num int64) (block Block, err error) { From 3fd5743e5251b3f393a01fd0522117d2c4b2b067 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 20 Feb 2021 17:24:45 +0900 Subject: [PATCH 488/506] [Cosmos] Fix new api changes (#1420) * Fix bonded constant * delegation model fix --- platform/cosmos/client.go | 2 +- platform/cosmos/mocks/delegation.json | 9 +++++---- platform/cosmos/model.go | 12 ++++++++---- platform/cosmos/stake.go | 10 +++++----- platform/cosmos/stake_test.go | 2 +- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/platform/cosmos/client.go b/platform/cosmos/client.go index 6014fefe5..52fc39263 100644 --- a/platform/cosmos/client.go +++ b/platform/cosmos/client.go @@ -30,7 +30,7 @@ func (c *Client) GetAddrTxs(address, tag string, page int) (txs TxPage, err erro func (c *Client) GetValidators() (validators Validators, err error) { query := url.Values{ - "status": {"bonded"}, + "status": {"BOND_STATUS_BONDED"}, } err = c.GetWithCache(&validators, "staking/validators", query, time.Minute*10) return diff --git a/platform/cosmos/mocks/delegation.json b/platform/cosmos/mocks/delegation.json index 05faf9af7..a374e03db 100644 --- a/platform/cosmos/mocks/delegation.json +++ b/platform/cosmos/mocks/delegation.json @@ -1,8 +1,9 @@ [ { - "delegator_address": "cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0", - "validator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", - "shares": "109999.000001746056062372", - "balance": "109999.000001746056062372" + "delegation": { + "delegator_address": "cosmos135qla4294zxarqhhgxsx0sw56yssa3z0f78pm0", + "validator_address": "cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys", + "shares": "109999.000001746056062372" + } } ] diff --git a/platform/cosmos/model.go b/platform/cosmos/model.go index 23dec863d..efae7f714 100644 --- a/platform/cosmos/model.go +++ b/platform/cosmos/model.go @@ -165,21 +165,25 @@ type Inflation struct { } type Delegations struct { - List []Delegation `json:"result"` + List []DelegationValue `json:"result"` +} + +type DelegationValue struct { + Delegation Delegation `json:"delegation"` } type Delegation struct { DelegatorAddress string `json:"delegator_address"` ValidatorAddress string `json:"validator_address"` - Balance string `json:"balance,omitempty"` + Shares string `json:"shares"` } func (d *Delegation) Value() string { - shares := strings.Split(d.Balance, ".") + shares := strings.Split(d.Shares, ".") if len(shares) > 0 { return shares[0] } - return d.Balance + return d.Shares } type UnbondingDelegations struct { diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index 7d484866f..7f15ca26a 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -118,20 +118,20 @@ func (p *Platform) UndelegatedBalance(address string) (string, error) { return "0", nil } -func NormalizeDelegations(delegations []Delegation, validators blockatlas.ValidatorMap) []blockatlas.Delegation { +func NormalizeDelegations(delegations []DelegationValue, validators blockatlas.ValidatorMap) []blockatlas.Delegation { results := make([]blockatlas.Delegation, 0) for _, v := range delegations { - validator, ok := validators[v.ValidatorAddress] + validator, ok := validators[v.Delegation.ValidatorAddress] if !ok { log.WithFields( - log.Fields{"address": v.ValidatorAddress, "platform": "cosmos", "delegation": v.DelegatorAddress}, + log.Fields{"address": v.Delegation.ValidatorAddress, "platform": "cosmos", "delegation": v.Delegation.DelegatorAddress}, ).Warn("Validator not found") - validator = getUnknownValidator(v.ValidatorAddress) + validator = getUnknownValidator(v.Delegation.ValidatorAddress) } delegation := blockatlas.Delegation{ Delegator: validator, - Value: v.Value(), + Value: v.Delegation.Value(), Status: blockatlas.DelegationStatusActive, } results = append(results, delegation) diff --git a/platform/cosmos/stake_test.go b/platform/cosmos/stake_test.go index b169cdb82..bf6c0f7f4 100644 --- a/platform/cosmos/stake_test.go +++ b/platform/cosmos/stake_test.go @@ -62,7 +62,7 @@ func TestCalculateAnnualReward(t *testing.T) { } func TestNormalizeDelegations(t *testing.T) { - var delegations []Delegation + var delegations []DelegationValue err := json.Unmarshal([]byte(delegationsSrc), &delegations) assert.NoError(t, err) assert.NotNil(t, delegations) From e0975ba387fe129b255ee2cc3862d4a20997783e Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 22 Feb 2021 08:47:33 +0900 Subject: [PATCH 489/506] Refactor types.TxPage (#1417) * refactor TxPage * golibs v0.1.4 * ignore internal GetTransaction error * Fix wrong return type --- api/endpoint/token.go | 4 +-- api/endpoint/transaction.go | 35 +++++++++---------- go.mod | 8 +++-- go.sum | 19 +++++----- pkg/blockatlas/platform.go | 6 ++-- platform/aeternity/transaction.go | 4 +-- platform/aion/transaction.go | 6 ++-- platform/algorand/transaction.go | 6 ++-- platform/binance/model.go | 10 +++--- platform/binance/transaction.go | 4 +-- platform/bitcoin/block.go | 2 +- platform/bitcoin/blockbook/block.go | 16 +++++++-- platform/bitcoin/blockbook/client.go | 17 +++++++++ platform/bitcoin/blockbook/transaction.go | 6 ++-- .../bitcoin/blockbook/transaction_test.go | 10 +++--- platform/bitcoin/transaction.go | 26 +++++++------- platform/cosmos/transaction.go | 6 ++-- platform/elrond/client.go | 2 +- platform/elrond/transaction.go | 4 +-- platform/elrond/transaction_test.go | 2 +- platform/ethereum/client.go | 4 +-- platform/ethereum/transaction.go | 4 +-- platform/ethereum/transaction_test.go | 10 +++--- platform/filecoin/transaction.go | 4 +-- platform/fio/transaction.go | 13 ++++--- platform/harmony/transaction.go | 10 +++--- platform/icon/transaction.go | 4 +-- platform/iotex/block.go | 2 +- platform/iotex/transaction.go | 4 +-- platform/kava/transaction.go | 8 ++--- platform/kava/transaction_test.go | 4 +-- platform/nano/transaction.go | 4 +-- platform/near/transaction.go | 4 +-- platform/nebulas/transaction.go | 6 ++-- platform/nimiq/transaction.go | 6 ++-- platform/ontology/transaction.go | 10 +++--- platform/ontology/transaction_test.go | 2 +- platform/polkadot/transaction.go | 8 ++--- platform/ripple/transaction.go | 6 ++-- platform/solana/block.go | 4 +-- platform/solana/transaction.go | 4 +-- platform/stellar/transaction.go | 6 ++-- platform/tezos/block.go | 2 +- platform/tezos/block_test.go | 2 +- platform/tezos/transaction.go | 4 +-- platform/theta/transaction.go | 6 ++-- platform/tron/block.go | 2 +- platform/tron/transaction.go | 12 +++---- platform/vechain/transaction.go | 20 +++++------ platform/vechain/transaction_test.go | 8 ++--- platform/waves/transaction.go | 4 +-- platform/zilliqa/block.go | 2 +- platform/zilliqa/transaction.go | 4 +-- services/notifier/models.go | 8 ++--- services/notifier/models_test.go | 10 +++--- services/parser/parser.go | 4 +-- services/tokenindexer/indexer.go | 2 +- 57 files changed, 218 insertions(+), 192 deletions(-) diff --git a/api/endpoint/token.go b/api/endpoint/token.go index 8df391fe2..99a7011d4 100644 --- a/api/endpoint/token.go +++ b/api/endpoint/token.go @@ -25,7 +25,7 @@ import ( func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { address := c.Param("address") if address == "" { - c.JSON(http.StatusOK, types.TxPage{}) + c.JSON(http.StatusOK, []types.Token{}) return } @@ -40,7 +40,7 @@ func GetTokensByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { func GetTokensIdsByAddress(c *gin.Context, tokenAPI blockatlas.TokensAPI) { address := c.Param("address") if address == "" { - c.JSON(http.StatusOK, types.TxPage{}) + c.JSON(http.StatusOK, []string{}) return } diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index f232001c9..21a9dd169 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -29,7 +29,7 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b token := c.Query("token") var ( - txs []types.Tx + txs types.Txs err error ) @@ -74,25 +74,23 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b return } } - var ( - page = make(types.TxPage, 0) - filteredTxs = types.Txs(txs).FilterUniqueID().SortByDate() - ) + + filteredTxs := txs.FilterUniqueID().SortByDate() + for _, tx := range filteredTxs { tx.Direction = tx.GetTransactionDirection(address) - page = append(page, tx) } - page = page.FilterTransactionsByMemo() + filteredTxs = filteredTxs.FilterTransactionsByMemo() if token != "" { - page = page.FilterTransactionsByToken(token) + filteredTxs = filteredTxs.FilterTransactionsByToken(token) } - if len(page) > types.TxPerPage { - page = page[0:types.TxPerPage] + if len(filteredTxs) > types.TxPerPage { + filteredTxs = filteredTxs[0:types.TxPerPage] } - c.JSON(http.StatusOK, &page) + c.JSON(http.StatusOK, types.NewTxPage(filteredTxs)) } // @Summary Get Transactions by XPUB @@ -142,14 +140,13 @@ func GetTransactionsByXpub(c *gin.Context, api blockatlas.TxUtxoAPI) { return } } - var ( - filteredTxs = types.Txs(txs).FilterUniqueID().SortByDate() - page = types.TxPage(filteredTxs) - ) - page = page.FilterTransactionsByMemo() - if len(page) > types.TxPerPage { - page = page[0:types.TxPerPage] + + filteredTxs := txs.FilterUniqueID().SortByDate() + filteredTxs = filteredTxs.FilterTransactionsByMemo() + + if len(filteredTxs) > types.TxPerPage { + filteredTxs = filteredTxs[0:types.TxPerPage] } - c.JSON(http.StatusOK, &page) + c.JSON(http.StatusOK, types.NewTxPage(filteredTxs)) } diff --git a/go.mod b/go.mod index b473a55ec..8887adeb7 100644 --- a/go.mod +++ b/go.mod @@ -8,28 +8,30 @@ go 1.15 require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 + github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e // indirect github.com/deckarep/golang-set v1.7.1 github.com/getsentry/raven-go v0.2.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 github.com/itchyny/timefmt-go v0.1.1 + github.com/magefile/mage v1.11.0 // indirect github.com/mitchellh/mapstructure v1.4.1 github.com/mr-tron/base58 v1.2.0 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.4 - github.com/sirupsen/logrus v1.7.1 + github.com/sirupsen/logrus v1.8.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.1.3 + github.com/trustwallet/golibs v0.1.5-0.20210221020700-68a97014621e 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 + golang.org/x/sys v0.0.0-20210217105451-b926d437f341 // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.8 gorm.io/gorm v1.20.12 diff --git a/go.sum b/go.sum index 51e19db8f..6cde99b4c 100644 --- a/go.sum +++ b/go.sum @@ -62,6 +62,8 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 h1:6ejg6Lkk8dskcM7wQ28gONkukbQkM4qpj4RnYbpFzrI= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e h1:6JKvHHt396/qabvMhnhUZvWaHZzfVfldxE60TK8YLhg= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -287,6 +289,8 @@ github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls= +github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -391,8 +395,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.7.1 h1:rsizeFmZP+GYwyb4V6t6qpG7ZNWzA2bvgW/yC2xHCcg= -github.com/sirupsen/logrus v1.7.1/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= +github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU= +github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -436,8 +440,8 @@ 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.1.3 h1:KTGXo3k9bxNPMI/DeAY6QiRZ9OWPH6M6dxZU5n50+zQ= -github.com/trustwallet/golibs v0.1.3/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= +github.com/trustwallet/golibs v0.1.5-0.20210221020700-68a97014621e h1:r25XctsRfYH3FefG8TEgum1zKREPxOC4ts/qcLOw5fc= +github.com/trustwallet/golibs v0.1.5-0.20210221020700-68a97014621e/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= @@ -459,7 +463,6 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -523,7 +526,6 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -565,8 +567,8 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210123231150-1d476976d117 h1:M1sK0uTIn2x3HD5sySUPBg7ml5hmlQ/t7n7cIM6My9w= -golang.org/x/sys v0.0.0-20210123231150-1d476976d117/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210217105451-b926d437f341 h1:2/QtM1mL37YmcsT8HaDNHDgTqqFVw+zr8UzMiBVLzYU= +golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -633,7 +635,6 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/blockatlas/platform.go b/pkg/blockatlas/platform.go index 001201c00..60d825f57 100644 --- a/pkg/blockatlas/platform.go +++ b/pkg/blockatlas/platform.go @@ -21,19 +21,19 @@ type ( // TxAPI provides transaction lookups based on address TxAPI interface { Platform - GetTxsByAddress(address string) (types.TxPage, error) + GetTxsByAddress(address string) (types.Txs, error) } // TokenTxAPI provides token transaction lookups TokenTxAPI interface { Platform - GetTokenTxsByAddress(address, token string) (types.TxPage, error) + GetTokenTxsByAddress(address, token string) (types.Txs, error) } // TxUtxoAPI provides transaction lookup based on address and XPUB (Bitcoin-style) TxUtxoAPI interface { TxAPI - GetTxsByXpub(xpub string) (types.TxPage, error) + GetTxsByXpub(xpub string) (types.Txs, error) } // TokensAPI provides token lookups diff --git a/platform/aeternity/transaction.go b/platform/aeternity/transaction.go index 9038fa7a0..7bc7e9125 100644 --- a/platform/aeternity/transaction.go +++ b/platform/aeternity/transaction.go @@ -9,13 +9,13 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { addressTxs, err := p.client.GetTxs(address, types.TxPerPage) if err != nil { return nil, err } - var txs []types.Tx + var txs types.Txs for _, srcTx := range addressTxs { tx, err := NormalizeTx(&srcTx) if err != nil { diff --git a/platform/aion/transaction.go b/platform/aion/transaction.go index 6d89e9c19..bf108ce0a 100644 --- a/platform/aion/transaction.go +++ b/platform/aion/transaction.go @@ -8,7 +8,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { if srcTxs, err := p.client.GetTxsOfAddress(address, types.TxPerPage); err == nil { return NormalizeTxs(srcTxs.Content), err } else { @@ -43,8 +43,8 @@ func NormalizeTx(srcTx *Tx) (tx types.Tx, ok bool) { } // NormalizeTxs converts multiple Aion transactions -func NormalizeTxs(srcTxs []Tx) []types.Tx { - var txs []types.Tx +func NormalizeTxs(srcTxs []Tx) types.Txs { + var txs types.Txs for _, srcTx := range srcTxs { tx, ok := NormalizeTx(&srcTx) if ok { diff --git a/platform/algorand/transaction.go b/platform/algorand/transaction.go index 89db41ac8..d5776f009 100644 --- a/platform/algorand/transaction.go +++ b/platform/algorand/transaction.go @@ -7,7 +7,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { txs, err := p.client.GetTxsOfAddress(address) if err != nil { return nil, err @@ -15,8 +15,8 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return NormalizeTxs(txs), nil } -func NormalizeTxs(txs []Transaction) []types.Tx { - result := make([]types.Tx, 0) +func NormalizeTxs(txs []Transaction) types.Txs { + result := make(types.Txs, 0) for _, tx := range txs { if normalized, ok := Normalize(tx); ok { diff --git a/platform/binance/model.go b/platform/binance/model.go index e6539550b..d4ccaf05e 100644 --- a/platform/binance/model.go +++ b/platform/binance/model.go @@ -112,10 +112,10 @@ func normalizeBlock(response TransactionsInBlockResponse) types.Block { return result } -func normalizeTransactions(txs []Tx) []types.Tx { - totalTxs := make([]types.Tx, 0, len(txs)) +func normalizeTransactions(txs []Tx) types.Txs { + totalTxs := make(types.Txs, 0, len(txs)) for _, t := range txs { - var txs []types.Tx + var txs types.Txs switch t.TxType { case CancelOrder, NewOrder: //txs = append(txs, normalizeOrderTransaction(t)) @@ -159,8 +159,8 @@ func normalizeTransferTransaction(t Tx) types.Tx { return tx } -func normalizeMultiTransferTransaction(t Tx) []types.Tx { - txs := make([]types.Tx, 0, len(t.SubTransactions)) +func normalizeMultiTransferTransaction(t Tx) types.Txs { + txs := make(types.Txs, 0, len(t.SubTransactions)) for _, subTx := range t.SubTransactions { tx := types.Tx{ ID: subTx.TxHash, diff --git a/platform/binance/transaction.go b/platform/binance/transaction.go index 32b58ff2d..1f80983ca 100644 --- a/platform/binance/transaction.go +++ b/platform/binance/transaction.go @@ -5,7 +5,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { txsFromClient, err := p.client.FetchTransactionsByAddressAndTokenID(address, coin.Binance().Symbol) if err != nil { return nil, err @@ -13,7 +13,7 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return normalizeTransactions(txsFromClient), nil } -func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (types.Txs, error) { txsFromClient, err := p.client.FetchTransactionsByAddressAndTokenID(address, token) if err != nil { return nil, err diff --git a/platform/bitcoin/block.go b/platform/bitcoin/block.go index 61b12f175..a0248781d 100644 --- a/platform/bitcoin/block.go +++ b/platform/bitcoin/block.go @@ -11,7 +11,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { if err != nil { return nil, err } - var normalized []types.Tx + var normalized types.Txs for _, tx := range block { normalized = append(normalized, normalizeTransaction(tx, p.CoinIndex)) } diff --git a/platform/bitcoin/blockbook/block.go b/platform/bitcoin/blockbook/block.go index b59394a72..0894469d4 100644 --- a/platform/bitcoin/blockbook/block.go +++ b/platform/bitcoin/blockbook/block.go @@ -1,13 +1,25 @@ package blockbook -import "github.com/trustwallet/golibs/types" +import ( + "strings" + + "github.com/trustwallet/golibs/types" +) + +const ( + transactionError = "Internal server error: GetTransaction 0x" +) func (c *Client) GetBlockByNumber(num int64, coinIndex uint) (*types.Block, error) { block, err := c.GetAllTransactionsByBlockNumber(num) if err != nil { + err2, ok := err.(*ClientError) + if ok && strings.HasPrefix(err2.Error(), transactionError) { + return &types.Block{Number: num, Txs: types.Txs{}}, nil + } return nil, err } - txs := make([]types.Tx, 0) + txs := make(types.Txs, 0) for _, srcTx := range block { txs = append(txs, normalizeTx(&srcTx, coinIndex)) } diff --git a/platform/bitcoin/blockbook/client.go b/platform/bitcoin/blockbook/client.go index be2b3fd08..9466a9d4b 100644 --- a/platform/bitcoin/blockbook/client.go +++ b/platform/bitcoin/blockbook/client.go @@ -1,6 +1,7 @@ package blockbook import ( + "encoding/json" "errors" "fmt" "net/url" @@ -15,6 +16,14 @@ type Client struct { client.Request } +type ClientError struct { + Err string `json:"error"` +} + +func (c *ClientError) Error() string { + return c.Err +} + // Block func (c *Client) GetCurrentBlockNumber() (int64, error) { @@ -46,6 +55,14 @@ func (c *Client) GetAllTransactionsByBlockNumber(num int64) ([]Transaction, erro page := int64(1) block, err := c.GetTransactionsByBlockNumber(num, page) if err != nil { + httpError, ok := err.(*client.HttpError) + if ok { + var clientError ClientError + err2 := json.Unmarshal(httpError.Body, &clientError) + if err2 == nil { + return nil, &clientError + } + } return nil, err } txPages := c.getAllBlockPages(block.TotalPages, num) diff --git a/platform/bitcoin/blockbook/transaction.go b/platform/bitcoin/blockbook/transaction.go index 7753c0018..8a2ff2141 100644 --- a/platform/bitcoin/blockbook/transaction.go +++ b/platform/bitcoin/blockbook/transaction.go @@ -8,7 +8,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (c *Client) GetTransactions(address string, coinIndex uint) (types.TxPage, error) { +func (c *Client) GetTransactions(address string, coinIndex uint) (types.Txs, error) { page, err := c.GetTxs(address) if err != nil { return nil, err @@ -16,7 +16,7 @@ func (c *Client) GetTransactions(address string, coinIndex uint) (types.TxPage, return NormalizePage(page, address, "", coinIndex), nil } -func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (types.TxPage, error) { +func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (types.Txs, error) { page, err := c.GetTxsWithContract(address, token) if err != nil { return nil, err @@ -24,7 +24,7 @@ func (c *Client) GetTokenTxs(address, token string, coinIndex uint) (types.TxPag return NormalizePage(page, address, token, coinIndex), nil } -func NormalizePage(srcPage TransactionsList, address, token string, coinIndex uint) (txs types.TxPage) { +func NormalizePage(srcPage TransactionsList, address, token string, coinIndex uint) (txs types.Txs) { normalizedAddr, err := Address.EIP55Checksum(address) if err != nil { return diff --git a/platform/bitcoin/blockbook/transaction_test.go b/platform/bitcoin/blockbook/transaction_test.go index 4cbaf7029..0f7ece289 100644 --- a/platform/bitcoin/blockbook/transaction_test.go +++ b/platform/bitcoin/blockbook/transaction_test.go @@ -14,7 +14,7 @@ var ( want, _ = mock.JsonStringFromFilePath("mocks/expected_txs.json") ) -func TestNormalizePage(t *testing.T) { +func TestNormalizeTxs(t *testing.T) { type args struct { srcPage string address string @@ -39,18 +39,18 @@ func TestNormalizePage(t *testing.T) { } for _, tt := range tests { var page TransactionsList - var txPage types.TxPage + var txs types.Txs err := json.Unmarshal([]byte(tt.args.srcPage), &page) assert.Nil(t, err) - err = json.Unmarshal([]byte(tt.want), &txPage) + err = json.Unmarshal([]byte(tt.want), &txs) assert.Nil(t, err) t.Run(tt.name, func(t *testing.T) { got := NormalizePage(page, tt.args.address, tt.args.token, tt.args.coinIndex) gotJson, err := json.Marshal(got) assert.Nil(t, err) - wantTxPage, err := json.Marshal(txPage) + wantTxs, err := json.Marshal(txs) assert.Nil(t, err) - assert.JSONEq(t, string(gotJson), string(wantTxPage)) + assert.JSONEq(t, string(gotJson), string(wantTxs)) }) } } diff --git a/platform/bitcoin/transaction.go b/platform/bitcoin/transaction.go index a8dc8c2fc..878c630ac 100644 --- a/platform/bitcoin/transaction.go +++ b/platform/bitcoin/transaction.go @@ -11,31 +11,29 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { txs, err := p.getTxsByAddress(address) if err != nil { return nil, err } - txPage := types.TxPage(txs) - sort.Sort(txPage) - return txPage, nil + sort.Sort(txs) + return txs, nil } -func (p *Platform) GetTxsByXpub(xpub string) (types.TxPage, error) { +func (p *Platform) GetTxsByXpub(xpub string) (types.Txs, error) { txs, err := p.getTxsByXpub(xpub) if err != nil { return nil, err } - txPage := types.TxPage(txs) - sort.Sort(txPage) - return txPage, nil + sort.Sort(txs) + return txs, nil } -func (p *Platform) getTxsByXpub(xpub string) ([]types.Tx, error) { +func (p *Platform) getTxsByXpub(xpub string) (types.Txs, error) { sourceTxs, err := p.client.GetTransactionsByXpub(xpub) if err != nil { - return []types.Tx{}, err + return types.Txs{}, err } addressSet := mapset.NewSet() @@ -47,10 +45,10 @@ func (p *Platform) getTxsByXpub(xpub string) ([]types.Tx, error) { return txs, nil } -func (p *Platform) getTxsByAddress(address string) ([]types.Tx, error) { +func (p *Platform) getTxsByAddress(address string) (types.Txs, error) { sourceTxs, err := p.client.GetTxs(address) if err != nil { - return []types.Tx{}, err + return types.Txs{}, err } addressSet := mapset.NewSet() addressSet.Add(address) @@ -58,8 +56,8 @@ func (p *Platform) getTxsByAddress(address string) ([]types.Tx, error) { return txs, nil } -func normalizeTxs(sourceTxs blockbook.TransactionsList, coinIndex uint, addressSet mapset.Set) []types.Tx { - var txs []types.Tx +func normalizeTxs(sourceTxs blockbook.TransactionsList, coinIndex uint, addressSet mapset.Set) types.Txs { + var txs types.Txs for _, transaction := range sourceTxs.TransactionList() { if tx, ok := normalizeTransfer(transaction, coinIndex, addressSet); ok { txs = append(txs, tx) diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 5a5343936..189c3d1f1 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -9,7 +9,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { tagsList := []string{"transfer.recipient", "message.sender"} var wg sync.WaitGroup out := make(chan []Tx, len(tagsList)) @@ -51,9 +51,9 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { } // NormalizeTxs converts multiple Cosmos transactions -func (p *Platform) NormalizeTxs(srcTxs []Tx) types.TxPage { +func (p *Platform) NormalizeTxs(srcTxs []Tx) types.Txs { txMap := make(map[string]bool) - txs := make(types.TxPage, 0) + txs := make(types.Txs, 0) for _, srcTx := range srcTxs { _, ok := txMap[srcTx.ID] if ok { diff --git a/platform/elrond/client.go b/platform/elrond/client.go index c862da9eb..38d9ef61e 100644 --- a/platform/elrond/client.go +++ b/platform/elrond/client.go @@ -44,7 +44,7 @@ func (c *Client) GetBlockByNumber(height int64) (*types.Block, error) { }, nil } -func (c *Client) GetTxsOfAddress(address string) (types.TxPage, error) { +func (c *Client) GetTxsOfAddress(address string) (types.Txs, error) { var txPage TransactionsPage // TODO: enable pagination of Elrond transactions in the future. // TODO: currently Elrond only fetches the most recent 20 transactions. diff --git a/platform/elrond/transaction.go b/platform/elrond/transaction.go index ebfdedf43..d62c17d47 100644 --- a/platform/elrond/transaction.go +++ b/platform/elrond/transaction.go @@ -7,12 +7,12 @@ import ( const metachainID = "4294967295" -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { return p.client.GetTxsOfAddress(address) } // NormalizeTx converts an slice of Elrond transaction info a slice of generic model transaction -func NormalizeTxs(srcTxs []Transaction, address string, block Block) (txs []types.Tx) { +func NormalizeTxs(srcTxs []Transaction, address string, block Block) (txs types.Txs) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(srcTx, address, block) if !ok { diff --git a/platform/elrond/transaction_test.go b/platform/elrond/transaction_test.go index 6405de979..4db07b7a8 100644 --- a/platform/elrond/transaction_test.go +++ b/platform/elrond/transaction_test.go @@ -213,5 +213,5 @@ func TestNormalizeTxsFromHyperblock(t *testing.T) { }) require.Equal(t, len(txs), len(normalizedTxs)) - require.Equal(t, []types.Tx{txTransfer6Normalized}, normalizedTxs) + require.Equal(t, types.Txs{txTransfer6Normalized}, normalizedTxs) } diff --git a/platform/ethereum/client.go b/platform/ethereum/client.go index 1a81fa976..1d8693a00 100644 --- a/platform/ethereum/client.go +++ b/platform/ethereum/client.go @@ -3,8 +3,8 @@ package ethereum import "github.com/trustwallet/golibs/types" type EthereumClient interface { - GetTransactions(address string, coinIndex uint) (types.TxPage, error) - GetTokenTxs(address, token string, coinIndex uint) (types.TxPage, error) + GetTransactions(address string, coinIndex uint) (types.Txs, error) + GetTokenTxs(address, token string, coinIndex uint) (types.Txs, error) GetTokenList(address string, coinIndex uint) ([]types.Token, error) GetCurrentBlockNumber() (int64, error) GetBlockByNumber(num int64, coinIndex uint) (*types.Block, error) diff --git a/platform/ethereum/transaction.go b/platform/ethereum/transaction.go index 564cf7ce4..8be6891bf 100644 --- a/platform/ethereum/transaction.go +++ b/platform/ethereum/transaction.go @@ -4,11 +4,11 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { return p.client.GetTransactions(address, p.CoinIndex) } -func (p *Platform) GetTokenTxsByAddress(address string, token string) (types.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address string, token string) (types.Txs, error) { return p.client.GetTokenTxs(address, token, p.CoinIndex) } diff --git a/platform/ethereum/transaction_test.go b/platform/ethereum/transaction_test.go index b7d697b75..44077cc7b 100644 --- a/platform/ethereum/transaction_test.go +++ b/platform/ethereum/transaction_test.go @@ -16,7 +16,7 @@ var ( From: "A", To: "B", } - page = types.TxPage([]types.Tx{tx}) + page = types.Txs{tx} c Client ) @@ -43,14 +43,14 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { assert.Equal(t, page, resp) } -func (c Client) GetTransactions(address string, coinIndex uint) (types.TxPage, error) { - txs := make([]types.Tx, 0) +func (c Client) GetTransactions(address string, coinIndex uint) (types.Txs, error) { + txs := make(types.Txs, 0) txs = append(txs, tx) return txs, nil } -func (c Client) GetTokenTxs(address, token string, coinIndex uint) (types.TxPage, error) { - txs := make([]types.Tx, 0) +func (c Client) GetTokenTxs(address, token string, coinIndex uint) (types.Txs, error) { + txs := make(types.Txs, 0) txs = append(txs, tx) return txs, nil } diff --git a/platform/filecoin/transaction.go b/platform/filecoin/transaction.go index 90c34d49d..70e880bd7 100644 --- a/platform/filecoin/transaction.go +++ b/platform/filecoin/transaction.go @@ -7,12 +7,12 @@ import ( const messageMethod = "Send" -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { res, err := p.explorer.GetMessagesByAddress(address, types.TxPerPage) if err != nil { return nil, err } - normalized := make([]types.Tx, 0) + normalized := make(types.Txs, 0) for _, message := range res.Messages { // skip non transfer messages if message.Method != messageMethod { diff --git a/platform/fio/transaction.go b/platform/fio/transaction.go index 5603da7c0..cef228919 100644 --- a/platform/fio/transaction.go +++ b/platform/fio/transaction.go @@ -20,14 +20,14 @@ const ( actionTransferPubkey = "trnsfiopubky" ) -func (p *Platform) GetTxsByAddress(address string) (page types.TxPage, err error) { +func (p *Platform) GetTxsByAddress(address string) (page types.Txs, err error) { // take actor from address account := actorFromPublicKeyOrActor(address) actions, err := p.client.getTransactions(account) if err != nil { return nil, err } - txs := make([]types.Tx, 0) + txs := make(types.Txs, 0) for _, a := range actions { tx, err := p.Normalize(&a, account) if err != nil { @@ -36,9 +36,8 @@ func (p *Platform) GetTxsByAddress(address string) (page types.TxPage, err error txs = append(txs, tx) } txs = unique(txs) - txPage := types.TxPage(txs) - sort.Sort(txPage) - return txPage, nil + sort.Sort(txs) + return txs, nil } func (p *Platform) Normalize(action *Action, account string) (types.Tx, error) { @@ -110,9 +109,9 @@ func (p *Platform) Normalize(action *Action, account string) (types.Tx, error) { return types.Tx{}, errors.New("Unknown action") } -func unique(txs []types.Tx) []types.Tx { +func unique(txs types.Txs) types.Txs { set := make(map[string]struct{}) - var result []types.Tx + var result types.Txs for _, tx := range txs { id := fmt.Sprintf("%s-%d", tx.ID, tx.Sequence) if _, ok := set[id]; ok { diff --git a/platform/harmony/transaction.go b/platform/harmony/transaction.go index 144e11677..8f5fb9ca8 100644 --- a/platform/harmony/transaction.go +++ b/platform/harmony/transaction.go @@ -10,20 +10,20 @@ import ( const Annual = 10 -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { result, err := p.client.GetTxsOfAddress(address) if err != nil { - return types.TxPage{}, err + return types.Txs{}, err } return NormalizeTxs(result.Transactions), err } -func NormalizeTxs(txs []Transaction) types.TxPage { - normalizeTxs := make([]types.Tx, 0) +func NormalizeTxs(txs []Transaction) types.Txs { + normalizeTxs := make(types.Txs, 0) for _, srcTx := range txs { normalized, isCorrect, err := NormalizeTx(&srcTx) if !isCorrect || err != nil { - return []types.Tx{} + return types.Txs{} } normalizeTxs = append(normalizeTxs, normalized) } diff --git a/platform/icon/transaction.go b/platform/icon/transaction.go index ffd795b29..6faabd66a 100644 --- a/platform/icon/transaction.go +++ b/platform/icon/transaction.go @@ -9,13 +9,13 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { trxs, err := p.client.GetAddressTransactions(address) if err != nil { return nil, err } - nTrxs := make([]types.Tx, 0) + nTrxs := make(types.Txs, 0) for _, trx := range trxs { nTrx, ok := Normalize(&trx) if !ok { diff --git a/platform/iotex/block.go b/platform/iotex/block.go index 872cf9aeb..a0a3804e0 100644 --- a/platform/iotex/block.go +++ b/platform/iotex/block.go @@ -7,7 +7,7 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { } func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { - var normalized []types.Tx + var normalized types.Txs txs, err := p.client.GetTxsInBlock(num) if err != nil { return nil, err diff --git a/platform/iotex/transaction.go b/platform/iotex/transaction.go index 2cbe0af36..e68640f89 100644 --- a/platform/iotex/transaction.go +++ b/platform/iotex/transaction.go @@ -8,8 +8,8 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { - txs := make([]types.Tx, 0) +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { + txs := make(types.Txs, 0) var start int64 totalTrx, err := p.client.GetAddressTotalTransactions(address) diff --git a/platform/kava/transaction.go b/platform/kava/transaction.go index 087c5e89e..931863b35 100644 --- a/platform/kava/transaction.go +++ b/platform/kava/transaction.go @@ -12,11 +12,11 @@ import ( const kavaDenom = "ukava" -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { return p.GetTokenTxsByAddress(address, kavaDenom) } -func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (types.Txs, error) { tagsList := []string{"transfer.recipient", "message.sender"} var wg sync.WaitGroup out := make(chan []Tx, len(tagsList)) @@ -80,9 +80,9 @@ func (p *Platform) FilterTxsByDenom(txs []Tx, denom string) []Tx { } // NormalizeTxs converts multiple Cosmos transactions -func (p *Platform) NormalizeTxs(srcTxs []Tx) types.TxPage { +func (p *Platform) NormalizeTxs(srcTxs []Tx) types.Txs { txMap := make(map[string]bool) - txs := make(types.TxPage, 0) + txs := make(types.Txs, 0) for _, srcTx := range srcTxs { _, ok := txMap[srcTx.ID] if ok { diff --git a/platform/kava/transaction_test.go b/platform/kava/transaction_test.go index d2d9a2c8e..dc348453b 100644 --- a/platform/kava/transaction_test.go +++ b/platform/kava/transaction_test.go @@ -798,7 +798,7 @@ type filterTest struct { name string platform Platform Data []string - want []types.Tx + want types.Txs } func TestNormalize(t *testing.T) { @@ -878,7 +878,7 @@ func TestFilterByDenom(t *testing.T) { transferSrcKava, transferSrcKavaToken, }, - []types.Tx{transferDstKavaToken}, + types.Txs{transferDstKavaToken}, } testFilter(t, test) diff --git a/platform/nano/transaction.go b/platform/nano/transaction.go index 4b956b133..a84fa0b9a 100644 --- a/platform/nano/transaction.go +++ b/platform/nano/transaction.go @@ -7,8 +7,8 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { - normalized := make([]types.Tx, 0) +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { + normalized := make(types.Txs, 0) history, err := p.client.GetAccountHistory(address) if err != nil { return normalized, err diff --git a/platform/near/transaction.go b/platform/near/transaction.go index 0f2ed25fd..42a3a0e32 100644 --- a/platform/near/transaction.go +++ b/platform/near/transaction.go @@ -2,7 +2,7 @@ package near import "github.com/trustwallet/golibs/types" -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { - normalized := make([]types.Tx, 0) +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { + normalized := make(types.Txs, 0) return normalized, nil } diff --git a/platform/nebulas/transaction.go b/platform/nebulas/transaction.go index b51d49657..4dcb6d042 100644 --- a/platform/nebulas/transaction.go +++ b/platform/nebulas/transaction.go @@ -5,7 +5,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { txs, err := p.client.GetTxs(address, 1) if err != nil { return nil, err @@ -30,8 +30,8 @@ func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { }, nil } -func NormalizeTxs(txs []Transaction) []types.Tx { - normalizeTxs := make([]types.Tx, 0) +func NormalizeTxs(txs []Transaction) types.Txs { + normalizeTxs := make(types.Txs, 0) for _, srcTx := range txs { normalizeTxs = append(normalizeTxs, NormalizeTx(srcTx)) } diff --git a/platform/nimiq/transaction.go b/platform/nimiq/transaction.go index 5124a7978..f2fd00bbe 100644 --- a/platform/nimiq/transaction.go +++ b/platform/nimiq/transaction.go @@ -8,7 +8,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { srcTxs, err := p.client.GetTxsOfAddress(address) if err != nil { return nil, err @@ -40,14 +40,14 @@ func NormalizeTx(srcTx *Tx) types.Tx { } // NormalizeTxs converts multiple Nimiq transactions -func NormalizeTxs(srcTxs []Tx) []types.Tx { +func NormalizeTxs(srcTxs []Tx) types.Txs { sort.SliceStable(srcTxs, func(i, j int) bool { return srcTxs[i].BlockNumber > srcTxs[j].BlockNumber }) if len(srcTxs) > types.TxPerPage { srcTxs = srcTxs[:types.TxPerPage] } - txs := make([]types.Tx, len(srcTxs)) + txs := make(types.Txs, len(srcTxs)) for i, srcTx := range srcTxs { txs[i] = NormalizeTx(&srcTx) } diff --git a/platform/ontology/transaction.go b/platform/ontology/transaction.go index e98d6ea77..19ff782c2 100644 --- a/platform/ontology/transaction.go +++ b/platform/ontology/transaction.go @@ -9,14 +9,14 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { return p.GetTokenTxsByAddress(address, string(AssetONT)) } -func (p *Platform) GetTokenTxsByAddress(address string, token string) (types.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address string, token string) (types.Txs, error) { srcTxs, err := p.client.GetTxsOfAddress(address) if err != nil { - return types.TxPage{}, err + return types.Txs{}, err } txPage := normalizeTxs(srcTxs.Result, AssetType(token)) return txPage, nil @@ -130,8 +130,8 @@ func (p *Platform) getTxDetails(srcTx []Tx) ([]Tx, error) { return txsOntV2, nil } -func normalizeTxs(srcTxs []Tx, assetType AssetType) types.TxPage { - var txs types.TxPage +func normalizeTxs(srcTxs []Tx, assetType AssetType) types.Txs { + txs := make(types.Txs, 0) for _, srcTx := range srcTxs { transfer := srcTx.getTransfers().getTransfer(assetType) if transfer == nil { diff --git a/platform/ontology/transaction_test.go b/platform/ontology/transaction_test.go index e385dcf56..118911321 100644 --- a/platform/ontology/transaction_test.go +++ b/platform/ontology/transaction_test.go @@ -197,7 +197,7 @@ var ( func TestNormalizeBlock(t *testing.T) { block := normalizeTxs([]Tx{ontTxResp1.Result, ontTxResp2.Result, ontTxResp3.Result}, AssetAll) - var want types.TxPage + var want types.Txs _ = mock.JsonModelFromFilePath("mocks/block_response.json", &want) lhs, _ := json.Marshal(block) rhs, _ := json.Marshal(want) diff --git a/platform/polkadot/transaction.go b/platform/polkadot/transaction.go index 8e0346198..bdd22c82e 100644 --- a/platform/polkadot/transaction.go +++ b/platform/polkadot/transaction.go @@ -14,13 +14,13 @@ var NetworkByteMap = map[string]byte{ "KSM": 0x02, } -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { transfers, err := p.client.GetTransfersOfAddress(address) if err != nil { return nil, err } - txs := make([]types.Tx, 0) + txs := make(types.Txs, 0) for _, srcTx := range transfers { tx := p.NormalizeTransfer(&srcTx) txs = append(txs, tx) @@ -54,8 +54,8 @@ func (p *Platform) NormalizeTransfer(srcTx *Transfer) types.Tx { return result } -func (p *Platform) NormalizeExtrinsics(extrinsics []Extrinsic) []types.Tx { - txs := make([]types.Tx, 0) +func (p *Platform) NormalizeExtrinsics(extrinsics []Extrinsic) types.Txs { + txs := make(types.Txs, 0) for _, srcTx := range extrinsics { tx := p.NormalizeExtrinsic(&srcTx) if tx != nil { diff --git a/platform/ripple/transaction.go b/platform/ripple/transaction.go index 2e6b17c65..5b16fa207 100644 --- a/platform/ripple/transaction.go +++ b/platform/ripple/transaction.go @@ -8,13 +8,13 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { s, err := p.client.GetTxsOfAddress(address) if err != nil { return nil, err } - txs := make([]types.Tx, 0) + txs := make(types.Txs, 0) for _, srcTx := range s { tx, ok := NormalizeTx(&srcTx) if !ok { @@ -26,7 +26,7 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return txs, nil } -func NormalizeTxs(srcTxs []Tx) (txs []types.Tx) { +func NormalizeTxs(srcTxs []Tx) (txs types.Txs) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(&srcTx) if !ok || len(txs) >= types.TxPerPage { diff --git a/platform/solana/block.go b/platform/solana/block.go index 315f46704..4605f16b5 100644 --- a/platform/solana/block.go +++ b/platform/solana/block.go @@ -19,12 +19,12 @@ func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { // solana might skip some block which makes block number is not consecutive rpcError, ok := err.(*client.RpcError) if ok && rpcError.Code == errorSkipped { - return &types.Block{Number: num, Txs: []types.Tx{}}, nil + return &types.Block{Number: num, Txs: types.Txs{}}, nil } return nil, err } - txs := make([]types.Tx, 0) + txs := make(types.Txs, 0) for _, tx := range block.Transactions { normalized, err := p.NormalizeTx(tx, uint64(num), block.BlockTime) if err != nil { diff --git a/platform/solana/transaction.go b/platform/solana/transaction.go index a1cd48860..eeecf91f4 100644 --- a/platform/solana/transaction.go +++ b/platform/solana/transaction.go @@ -18,8 +18,8 @@ const ( // instructionTransferChecked = "transferChecked" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { - results := make(types.TxPage, 0) +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { + results := make(types.Txs, 0) txs, err := p.client.GetTransactionsByAddress(address) if err != nil { return results, err diff --git a/platform/stellar/transaction.go b/platform/stellar/transaction.go index 1ba66a9ab..1177e8c37 100644 --- a/platform/stellar/transaction.go +++ b/platform/stellar/transaction.go @@ -8,7 +8,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { payments, err := p.client.GetTxsOfAddress(address) if err != nil { return nil, err @@ -17,8 +17,8 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return p.NormalizePayments(payments), nil } -func (p *Platform) NormalizePayments(payments []Payment) []types.Tx { - txs := make([]types.Tx, 0, len(payments)) +func (p *Platform) NormalizePayments(payments []Payment) types.Txs { + txs := make(types.Txs, 0, len(payments)) for _, payment := range payments { if tx, ok := Normalize(&payment, p.CoinIndex); ok { txs = append(txs, tx) diff --git a/platform/tezos/block.go b/platform/tezos/block.go index eda597942..ea23c438c 100644 --- a/platform/tezos/block.go +++ b/platform/tezos/block.go @@ -24,7 +24,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { } func ProcessRpcBlock(block RpcBlock, rpcClient IRpcClient) (*types.Block, error) { - txs := []types.Tx{} + txs := types.Txs{} for _, ops := range block.Operations { for _, op := range ops { diff --git a/platform/tezos/block_test.go b/platform/tezos/block_test.go index 149052d29..967b498cf 100644 --- a/platform/tezos/block_test.go +++ b/platform/tezos/block_test.go @@ -26,7 +26,7 @@ func TestProcessRpcBlock(t *testing.T) { }, want: &types.Block{ Number: 1292516, - Txs: []types.Tx{ + Txs: types.Txs{ { ID: "oo25sEdAT3YDb83WNdMSxRv4E6V2Rt6Jc8msgTio7R4FBnAiFmj", Coin: 1729, diff --git a/platform/tezos/transaction.go b/platform/tezos/transaction.go index c78140081..28222d47f 100644 --- a/platform/tezos/transaction.go +++ b/platform/tezos/transaction.go @@ -6,7 +6,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { txTypes := []string{TxTypeTransaction, TxTypeDelegation} txs, err := p.client.GetTxsOfAddress(address, txTypes) if err != nil { @@ -16,7 +16,7 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return NormalizeTxs(txs.Transactions, address), nil } -func NormalizeTxs(srcTxs []Transaction, address string) (txs []types.Tx) { +func NormalizeTxs(srcTxs []Transaction, address string) (txs types.Txs) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(srcTx, address) if !ok { diff --git a/platform/theta/transaction.go b/platform/theta/transaction.go index 57c182770..80027659a 100644 --- a/platform/theta/transaction.go +++ b/platform/theta/transaction.go @@ -9,18 +9,18 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { // Endpoint supports queries without token query parameter return p.GetTokenTxsByAddress(address, "") } -func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (types.Txs, error) { trx, err := p.client.FetchAddressTransactions(address) if err != nil { return nil, err } - var txs []types.Tx + var txs types.Txs for _, tr := range trx { if tr.Type != SendTransaction { continue diff --git a/platform/tron/block.go b/platform/tron/block.go index 3c6d289fb..fde45f4d2 100644 --- a/platform/tron/block.go +++ b/platform/tron/block.go @@ -18,7 +18,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { } txsChan := p.NormalizeBlockTxs(block.Txs) - txs := make(types.TxPage, 0) + txs := make(types.Txs, 0) for cTxs := range txsChan { txs = append(txs, cTxs) } diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index 47026718c..9bb1954f3 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -10,13 +10,13 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { Txs, err := p.gridClient.fetchTxsOfAddress(address, "") if err != nil && len(Txs) == 0 { return nil, err } - txs := make(types.TxPage, 0) + txs := make(types.Txs, 0) for _, srcTx := range Txs { tx, err := normalize(srcTx) if err != nil { @@ -33,7 +33,7 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return txs, nil } -func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (types.Txs, error) { unknownTokenType := errors.New("unknownTokenType") tokenType := getTokenType(token) @@ -49,7 +49,7 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (types.TxPage, er if err != nil { return nil, err } - return types.TxPage(normalizeTRC20Transactions(trc20Transactions)), nil + return normalizeTRC20Transactions(trc20Transactions), nil default: return nil, unknownTokenType } @@ -77,8 +77,8 @@ func addTokenMeta(tx *types.Tx, srcTx Tx, tokenInfo AssetInfo) { } } -func (p *Platform) fetchTransactionsForTRC10Tokens(address, token string) (types.TxPage, error) { - txs := make(types.TxPage, 0) +func (p *Platform) fetchTransactionsForTRC10Tokens(address, token string) (types.Txs, error) { + txs := make(types.Txs, 0) tokenTxs, err := p.gridClient.fetchTxsOfAddress(address, token) if err != nil { diff --git a/platform/vechain/transaction.go b/platform/vechain/transaction.go index 93d6f8bd7..376e3c98e 100644 --- a/platform/vechain/transaction.go +++ b/platform/vechain/transaction.go @@ -11,7 +11,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTokenTxsByAddress(address, token string) (page types.TxPage, err error) { +func (p *Platform) GetTokenTxsByAddress(address, token string) (page types.Txs, err error) { if token != gasTokenAddress { return } @@ -44,8 +44,8 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (page types.TxPag return txs, nil } -func (p *Platform) getTransactionsByIDs(ids []string) (types.TxPage, error) { - page := types.TxPage{} +func (p *Platform) getTransactionsByIDs(ids []string) (types.Txs, error) { + page := types.Txs{} for _, id := range ids { tx, err := p.client.GetTransactionByID(id) if err != nil { @@ -66,16 +66,16 @@ func (p *Platform) getTransactionsByIDs(ids []string) (types.TxPage, error) { return page, nil } -func NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types.TxPage, error) { +func NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types.Txs, error) { // the only supported Token on VeChain is its Gas token if receipt.Reverted { return normalizeRevertedTokenTransaction(srcTx, receipt) } - txs := make(types.TxPage, 0) + txs := make(types.Txs, 0) if receipt.Outputs == nil || len(receipt.Outputs) == 0 { - return types.TxPage{}, errors.New("NormalizeBlockTransaction: receipt.Outputs not found: " + srcTx.Id) + return types.Txs{}, errors.New("NormalizeBlockTransaction: receipt.Outputs not found: " + srcTx.Id) } for _, output := range receipt.Outputs { @@ -138,8 +138,8 @@ func NormalizeTokenTransaction(srcTx Tx, receipt TxReceipt) (types.TxPage, error return txs, nil } -func normalizeRevertedTokenTransaction(srcTx Tx, receipt TxReceipt) (types.TxPage, error) { - txs := make(types.TxPage, 0) +func normalizeRevertedTokenTransaction(srcTx Tx, receipt TxReceipt) (types.Txs, error) { + txs := make(types.Txs, 0) fee, err := numbers.HexToDecimal(receipt.Paid) if err != nil { @@ -188,7 +188,7 @@ func normalizeRevertedTokenTransaction(srcTx Tx, receipt TxReceipt) (types.TxPag return txs, nil } -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { headBlock, err := p.CurrentBlockNumber() if err != nil { return nil, err @@ -198,7 +198,7 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return nil, err } - txs := make(types.TxPage, 0) + txs := make(types.Txs, 0) for _, t := range transfers { trxId, err := p.client.GetTransactionByID(t.Meta.TxId) if err != nil { diff --git a/platform/vechain/transaction_test.go b/platform/vechain/transaction_test.go index 29c2b3b29..e159a15a8 100644 --- a/platform/vechain/transaction_test.go +++ b/platform/vechain/transaction_test.go @@ -68,7 +68,7 @@ func TestNormalizeTokenTransaction(t *testing.T) { txFile string receiptFile string address string - expected types.TxPage + expected types.Txs wantErr error }{ { @@ -76,7 +76,7 @@ func TestNormalizeTokenTransaction(t *testing.T) { txFile: "outgoing_vtho_tx.json", receiptFile: "outgoing_vtho_receipt.json", address: "0xe99399dd211eF54c301A5d1AA813471d92122eA8", - expected: types.TxPage{{ + expected: types.Txs{{ ID: "0x0677f91de4787d295087acec0a7ba317b0019fbf296fed630fdb5afbfca97a58", Coin: coin.VECHAIN, From: "0xe99399dd211eF54c301A5d1AA813471d92122eA8", @@ -104,7 +104,7 @@ func TestNormalizeTokenTransaction(t *testing.T) { txFile: "incoming_vtho_tx.json", receiptFile: "incoming_vtho_receipt.json", address: "0xe99399dd211eF54c301A5d1AA813471d92122eA8", - expected: types.TxPage{{ + expected: types.Txs{{ ID: "0xb356fa7b3a371f1518a5f9bc51e951d0dac2ef04d58b532c7ca50a52aa5cddb4", Coin: coin.VECHAIN, From: "0xB5e883349e68aB59307d1604555AC890fAC47128", @@ -132,7 +132,7 @@ func TestNormalizeTokenTransaction(t *testing.T) { txFile: "reverted_tx.json", receiptFile: "reverted_receipt.json", address: "0x7cFFB7632252Bae3766734d61F148f0Ea78Fc08C", - expected: types.TxPage{}, + expected: types.Txs{}, wantErr: nil, }, } diff --git a/platform/waves/transaction.go b/platform/waves/transaction.go index 7ea630b64..670d658f3 100644 --- a/platform/waves/transaction.go +++ b/platform/waves/transaction.go @@ -7,7 +7,7 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { addressTxs, err := p.client.GetTxs(address, 25) if err != nil { return nil, err @@ -18,7 +18,7 @@ func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { return txs, nil } -func NormalizeTxs(srcTxs []Transaction) (txs []types.Tx) { +func NormalizeTxs(srcTxs []Transaction) (txs types.Txs) { for _, srcTx := range srcTxs { tx, ok := NormalizeTx(&srcTx) if !ok || len(txs) >= types.TxPerPage { diff --git a/platform/zilliqa/block.go b/platform/zilliqa/block.go index 8cc60c5f5..1b409f37d 100644 --- a/platform/zilliqa/block.go +++ b/platform/zilliqa/block.go @@ -21,7 +21,7 @@ func (p *Platform) CurrentBlockNumber() (int64, error) { } func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { - var normalized []types.Tx + var normalized types.Txs var txs []viewblock.Tx header, rpcTxs, err := p.rpcClient.GetTxInBlock(num) diff --git a/platform/zilliqa/transaction.go b/platform/zilliqa/transaction.go index 0173f1e62..c2cd1782d 100644 --- a/platform/zilliqa/transaction.go +++ b/platform/zilliqa/transaction.go @@ -6,8 +6,8 @@ import ( "github.com/trustwallet/golibs/types" ) -func (p *Platform) GetTxsByAddress(address string) (types.TxPage, error) { - var normalized []types.Tx +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { + var normalized types.Txs txs, err := p.client.GetTxsOfAddress(address) if err != nil { diff --git a/services/notifier/models.go b/services/notifier/models.go index 37edf666e..cb35e4bee 100644 --- a/services/notifier/models.go +++ b/services/notifier/models.go @@ -27,9 +27,9 @@ func ToUniqueAddresses(addresses []string) []string { return list } -func toUniqueTransactions(txs []types.Tx) []types.Tx { +func toUniqueTransactions(txs types.Txs) types.Txs { keys := make(map[string]bool) - var list []types.Tx + var list types.Txs for _, entry := range txs { key := entry.ID + string(entry.Direction) if _, value := keys[key]; !value { @@ -40,8 +40,8 @@ func toUniqueTransactions(txs []types.Tx) []types.Tx { return list } -func findTransactionsByAddress(txs types.Txs, address string) []types.Tx { - result := make([]types.Tx, 0) +func findTransactionsByAddress(txs types.Txs, address string) types.Txs { + result := make(types.Txs, 0) for _, tx := range txs { if containsAddress(tx, address) { result = append(result, tx) diff --git a/services/notifier/models_test.go b/services/notifier/models_test.go index ef62df7d5..ee836ac4f 100644 --- a/services/notifier/models_test.go +++ b/services/notifier/models_test.go @@ -126,18 +126,18 @@ func Test_containsAddress(t *testing.T) { } func Test_findTransactionsByAddress(t *testing.T) { - res := findTransactionsByAddress([]types.Tx{nativeTokenTransfer, tokenTransfer}, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a") + res := findTransactionsByAddress(types.Txs{nativeTokenTransfer, tokenTransfer}, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a") sort.Slice(res, func(i, j int) bool { return res[i].ID < res[j].ID }) - assert.Equal(t, []types.Tx{nativeTokenTransfer}, res) + assert.Equal(t, types.Txs{nativeTokenTransfer}, res) - resFail := findTransactionsByAddress([]types.Tx{nativeTokenTransfer, tokenTransfer}, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced") - assert.Equal(t, []types.Tx{}, resFail) + resFail := findTransactionsByAddress(types.Txs{nativeTokenTransfer, tokenTransfer}, "tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced") + assert.Equal(t, types.Txs{}, resFail) } func Test_buildNotificationsByAddress(t *testing.T) { - notifications := buildNotificationsByAddress("tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", []types.Tx{nativeTokenTransfer, tokenTransfer}) + notifications := buildNotificationsByAddress("tbnb1ttyn4csghfgyxreu7lmdu3lcplhqhxtzced45a", types.Txs{nativeTokenTransfer, tokenTransfer}) sort.Slice(notifications, func(i, j int) bool { return notifications[i].Action < notifications[j].Action }) diff --git a/services/parser/parser.go b/services/parser/parser.go index 413bbee41..197789545 100644 --- a/services/parser/parser.go +++ b/services/parser/parser.go @@ -107,11 +107,11 @@ func parse(params Params) { return } - var txs []types.Tx + var txs types.Txs for _, block := range blocks { txs = append(txs, block.Txs...) } - txs = types.TxPage(txs).FilterTransactionsByMemo() + txs = txs.FilterTransactionsByMemo() err = publish(params, txs) if err != nil { diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index 065b0ed65..632daf307 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -112,7 +112,7 @@ func calculateSubscriptionAssetAssociations(database *db.Instance, addressAssets return associations, nil } -func GetAssetsFromTransactions(txs []types.Tx) []models.Asset { +func GetAssetsFromTransactions(txs types.Txs) []models.Asset { var result []models.Asset for _, tx := range txs { assets := models.AssetsFrom(tx) From ab4058af13ebe36bc287d8f5ec60406d83ae481f Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 26 Feb 2021 01:54:40 +0900 Subject: [PATCH 490/506] [Cosmos] Fix claim rewards amount (#1422) * Fix cosmos txs model * Fix tx.Direction not set * bump golibs version --- api/endpoint/transaction.go | 13 +++-- go.mod | 4 +- go.sum | 8 +-- platform/cosmos/mocks/claim_1.json | 82 +++++++++++++++------------- platform/cosmos/mocks/claim_2.json | 88 ++++++++++++++++-------------- platform/cosmos/model.go | 28 ++++++---- platform/cosmos/transaction.go | 6 +- 7 files changed, 122 insertions(+), 107 deletions(-) diff --git a/api/endpoint/transaction.go b/api/endpoint/transaction.go index 21a9dd169..62fc938f7 100644 --- a/api/endpoint/transaction.go +++ b/api/endpoint/transaction.go @@ -76,11 +76,6 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b } filteredTxs := txs.FilterUniqueID().SortByDate() - - for _, tx := range filteredTxs { - tx.Direction = tx.GetTransactionDirection(address) - } - filteredTxs = filteredTxs.FilterTransactionsByMemo() if token != "" { filteredTxs = filteredTxs.FilterTransactionsByToken(token) @@ -90,7 +85,13 @@ func GetTransactionsHistory(c *gin.Context, txAPI blockatlas.TxAPI, tokenTxAPI b filteredTxs = filteredTxs[0:types.TxPerPage] } - c.JSON(http.StatusOK, types.NewTxPage(filteredTxs)) + // modify in loop + result := make(types.Txs, len(filteredTxs)) + for i, t := range filteredTxs { + result[i] = t + result[i].Direction = t.GetTransactionDirection(address) + } + c.JSON(http.StatusOK, types.NewTxPage(result)) } // @Summary Get Transactions by XPUB diff --git a/go.mod b/go.mod index 8887adeb7..dbe5e90c0 100644 --- a/go.mod +++ b/go.mod @@ -27,8 +27,8 @@ require ( 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.1.5-0.20210221020700-68a97014621e - github.com/trustwallet/golibs/network v0.0.0-20210124080535-8638b407c4ab + github.com/trustwallet/golibs v0.1.5 + github.com/trustwallet/golibs/network v0.0.0-20210222000450-7376c687b4e9 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-20210217105451-b926d437f341 // indirect diff --git a/go.sum b/go.sum index 6cde99b4c..4b34a1000 100644 --- a/go.sum +++ b/go.sum @@ -440,10 +440,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.1.5-0.20210221020700-68a97014621e h1:r25XctsRfYH3FefG8TEgum1zKREPxOC4ts/qcLOw5fc= -github.com/trustwallet/golibs v0.1.5-0.20210221020700-68a97014621e/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/trustwallet/golibs v0.1.5 h1:8kMIWrU38a1Rfl9kLXo0egN+PBtSXr78T2sc+UpJ4Q8= +github.com/trustwallet/golibs v0.1.5/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= +github.com/trustwallet/golibs/network v0.0.0-20210222000450-7376c687b4e9 h1:OEmmVI2SDcwy1vS3C3rS3oj0zUZQnrbLixPWtpmL9Uk= +github.com/trustwallet/golibs/network v0.0.0-20210222000450-7376c687b4e9/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= diff --git a/platform/cosmos/mocks/claim_1.json b/platform/cosmos/mocks/claim_1.json index e3a324535..647337e98 100644 --- a/platform/cosmos/mocks/claim_1.json +++ b/platform/cosmos/mocks/claim_1.json @@ -42,49 +42,53 @@ } }, "timestamp": "2019-12-18T03:04:33Z", - "events": [ + "logs": [ { - "type": "transfer", - "attributes": [ + "events": [ { - "key": "recipient", - "value": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug" - } - ] - }, - { - "type": "withdraw_rewards", - "attributes": [ - { - "key": "amount", - "value": "1138uatom" - }, - { - "key": "validator", - "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" - }, - { - "key": "amount", - "value": "40612uatom" - }, - { - "key": "validator", - "value": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2" - }, - { - "key": "amount", - "value": "954uatom" - }, - { - "key": "validator", - "value": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw" - }, - { - "key": "amount", - "value": "43574uatom" + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1cxehfdhfm96ljpktdxsj0k6xp9gtuheghwgqug" + } + ] }, { - "key": "amount" + "type": "withdraw_rewards", + "attributes": [ + { + "key": "amount", + "value": "1138uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper1ptyzewnns2kn37ewtmv6ppsvhdnmeapvtfc9y5" + }, + { + "key": "amount", + "value": "40612uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper1fhr7e04ct0zslmkzqt9smakg3sxrdve6ulclj2" + }, + { + "key": "amount", + "value": "954uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper1we6knm8qartmmh2r0qfpsz6pq0s7emv3e0meuw" + }, + { + "key": "amount", + "value": "43574uatom" + }, + { + "key": "amount" + } + ] } ] } diff --git a/platform/cosmos/mocks/claim_2.json b/platform/cosmos/mocks/claim_2.json index 73899bad2..d1fcf21cc 100644 --- a/platform/cosmos/mocks/claim_2.json +++ b/platform/cosmos/mocks/claim_2.json @@ -39,56 +39,60 @@ } }, "timestamp": "2019-12-16T02:21:03Z", - "events": [ + "logs": [ { - "type": "delegate", - "attributes": [ + "events": [ { - "key": "validator", - "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" - }, - { - "key": "amount", - "value": "2692326" - } - ] - }, - { - "type": "message", - "attributes": [ - { - "key": "sender", - "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + "type": "delegate", + "attributes": [ + { + "key": "validator", + "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + }, + { + "key": "amount", + "value": "2692326" + } + ] }, { - "key": "module", - "value": "distribution" - } - ] - }, - { - "type": "transfer", - "attributes": [ - { - "key": "recipient", - "value": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46" + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl" + }, + { + "key": "module", + "value": "distribution" + } + ] }, { - "key": "amount", - "value": "2692701uatom" - } - ] - }, - { - "type": "withdraw_rewards", - "attributes": [ - { - "key": "amount", - "value": "2692701uatom" + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "cosmos1y6yvdel7zys8x60gz9067fjpcpygsn62ae9x46" + }, + { + "key": "amount", + "value": "2692701uatom" + } + ] }, { - "key": "validator", - "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + "type": "withdraw_rewards", + "attributes": [ + { + "key": "amount", + "value": "2692701uatom" + }, + { + "key": "validator", + "value": "cosmosvaloper12w6tynmjzq4l8zdla3v4x0jt8lt4rcz5gk7zg2" + } + ] } ] } diff --git a/platform/cosmos/model.go b/platform/cosmos/model.go index efae7f714..f3402985d 100644 --- a/platform/cosmos/model.go +++ b/platform/cosmos/model.go @@ -39,12 +39,12 @@ const ( // Tx - Base transaction object. Always returned as part of an array type Tx struct { - Block string `json:"height"` - Code int `json:"code"` - Date string `json:"timestamp"` - ID string `json:"txhash"` - Data Data `json:"tx"` - Events Events `json:"events"` + Block string `json:"height"` + Code int `json:"code"` + Date string `json:"timestamp"` + ID string `json:"txhash"` + Data Data `json:"tx"` + Logs Logs `json:"logs"` } type TxPage struct { @@ -58,13 +58,19 @@ type Event struct { Attributes Attributes `json:"Attributes"` } -type Events []*Event +type Events struct { + Events []Event `json:"events"` +} + +type Logs []*Events -func (e Events) GetWithdrawRewardValue() string { +func (l Logs) GetWithdrawRewardValue() string { result := int64(0) - for _, att := range e { - if att.Type == EventWithdrawRewards { - result += att.Attributes.GetWithdrawRewardValue() + for _, log := range l { + for _, att := range log.Events { + if att.Type == EventWithdrawRewards { + result += att.Attributes.GetWithdrawRewardValue() + } } } return strconv.FormatInt(result, 10) diff --git a/platform/cosmos/transaction.go b/platform/cosmos/transaction.go index 189c3d1f1..f483ecbe1 100644 --- a/platform/cosmos/transaction.go +++ b/platform/cosmos/transaction.go @@ -118,7 +118,7 @@ func (p *Platform) Normalize(srcTx *Tx) (tx types.Tx, ok bool) { return tx, true case MessageValueDelegate: delegate := msg.Value.(MessageValueDelegate) - p.fillDelegate(&tx, delegate, srcTx.Events, msg.Type) + p.fillDelegate(&tx, delegate, srcTx.Logs, msg.Type) return tx, true } return tx, false @@ -142,7 +142,7 @@ func (p *Platform) fillTransfer(tx *types.Tx, transfer MessageValueTransfer) { } } -func (p *Platform) fillDelegate(tx *types.Tx, delegate MessageValueDelegate, events Events, msgType TxType) { +func (p *Platform) fillDelegate(tx *types.Tx, delegate MessageValueDelegate, logs Logs, msgType TxType) { value := "" if len(delegate.Amount.Quantity) > 0 { var err error @@ -168,7 +168,7 @@ func (p *Platform) fillDelegate(tx *types.Tx, delegate MessageValueDelegate, eve tx.Direction = types.DirectionIncoming title = types.AnyActionClaimRewards key = types.KeyStakeClaimRewards - value = events.GetWithdrawRewardValue() + value = logs.GetWithdrawRewardValue() } tx.Meta = types.AnyAction{ Coin: p.Coin().ID, From 2db4f4fa550c06dc4056294f8be60712c2b7e81d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 27 Feb 2021 20:57:40 -0800 Subject: [PATCH 491/506] Bump github.com/itchyny/timefmt-go from 0.1.1 to 0.1.2 (#1428) Bumps [github.com/itchyny/timefmt-go](https://github.com/itchyny/timefmt-go) from 0.1.1 to 0.1.2. - [Release notes](https://github.com/itchyny/timefmt-go/releases) - [Changelog](https://github.com/itchyny/timefmt-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/itchyny/timefmt-go/compare/v0.1.1...v0.1.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index dbe5e90c0..887b716db 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/getsentry/raven-go v0.2.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 - github.com/itchyny/timefmt-go v0.1.1 + github.com/itchyny/timefmt-go v0.1.2 github.com/magefile/mage v1.11.0 // indirect github.com/mitchellh/mapstructure v1.4.1 github.com/mr-tron/base58 v1.2.0 diff --git a/go.sum b/go.sum index 4b34a1000..cf899d34e 100644 --- a/go.sum +++ b/go.sum @@ -196,6 +196,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/itchyny/timefmt-go v0.1.1 h1:rLpnm9xxb39PEEVzO0n4IRp0q6/RmBc7Dy/rE4HrA0U= github.com/itchyny/timefmt-go v0.1.1/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= +github.com/itchyny/timefmt-go v0.1.2/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= From 03eb45473c870263a9cd63b232e0a9de12253449 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Mon, 1 Mar 2021 23:47:00 -0800 Subject: [PATCH 492/506] Use api/v2 for blockbook GetCurrentBlockNumber --- platform/bitcoin/blockbook/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/bitcoin/blockbook/client.go b/platform/bitcoin/blockbook/client.go index 9466a9d4b..7aa51aade 100644 --- a/platform/bitcoin/blockbook/client.go +++ b/platform/bitcoin/blockbook/client.go @@ -28,7 +28,7 @@ func (c *ClientError) Error() string { func (c *Client) GetCurrentBlockNumber() (int64, error) { var nodeInfo NodeInfo - err := c.Get(&nodeInfo, "api", nil) + err := c.Get(&nodeInfo, "api/v2", nil) if err != nil { return 0, err } From 3709bdd9d1e1d9975605546c2863841be323f2e6 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 5 Mar 2021 07:05:24 +0900 Subject: [PATCH 493/506] [Binance] Add bnb staking apr (#1430) --- config.yml | 3 +- config/configuration.go | 5 +- go.sum | 3 +- pkg/blockatlas/staking.go | 16 ++- platform/binance/base.go | 9 +- platform/binance/block_test.go | 4 +- platform/binance/stake.go | 62 +++++++++ platform/binance/staking/client.go | 26 ++++ platform/binance/staking/model.go | 12 ++ platform/binance/token_test.go | 2 +- platform/binance/transaction_test.go | 4 +- platform/cosmos/stake.go | 26 +--- platform/harmony/client.go | 20 --- platform/harmony/model.go | 28 ----- platform/harmony/stake.go | 137 -------------------- platform/harmony/stake_test.go | 182 --------------------------- platform/kava/stake.go | 26 +--- platform/platform.go | 2 +- 18 files changed, 143 insertions(+), 424 deletions(-) create mode 100644 platform/binance/stake.go create mode 100644 platform/binance/staking/client.go create mode 100644 platform/binance/staking/model.go delete mode 100644 platform/harmony/stake.go delete mode 100644 platform/harmony/stake_test.go diff --git a/config.yml b/config.yml index 7e19127bb..fe8ff2cd6 100644 --- a/config.yml +++ b/config.yml @@ -33,7 +33,8 @@ consumer: # [BNB] Binance DEX: https://www.binance.org/ binance: api: https://dex.binance.org - # key: "" + key: "" + staking_api: "https://api.binance.org" # [NIM] Nimiq: https://nimiq.com nimiq: diff --git a/config/configuration.go b/config/configuration.go index 6f109dc22..f939973a8 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -36,8 +36,9 @@ type Configuration struct { CollectionsKey string `mapstructure:"collections_api_key"` } `mapstructure:"ethereum"` Binance struct { - API string `mapstructure:"api"` - Key string `mapstructure:"key"` + API string `mapstructure:"api"` + Key string `mapstructure:"key"` + StakingAPI string `mapstructure:"staking_api"` } `mapstructure:"binance"` Ripple struct { API string `mapstructure:"api"` diff --git a/go.sum b/go.sum index cf899d34e..88c5d5391 100644 --- a/go.sum +++ b/go.sum @@ -194,8 +194,7 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/itchyny/timefmt-go v0.1.1 h1:rLpnm9xxb39PEEVzO0n4IRp0q6/RmBc7Dy/rE4HrA0U= -github.com/itchyny/timefmt-go v0.1.1/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= +github.com/itchyny/timefmt-go v0.1.2 h1:q0Xa4P5it6K6D7ISsbLAMwx1PnWlixDcJL6/sFs93Hs= github.com/itchyny/timefmt-go v0.1.2/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= diff --git a/pkg/blockatlas/staking.go b/pkg/blockatlas/staking.go index f8260ab4d..452eb1598 100644 --- a/pkg/blockatlas/staking.go +++ b/pkg/blockatlas/staking.go @@ -12,7 +12,7 @@ const ( DelegationTypeAuto DelegationType = "auto" DelegationTypeDelegate DelegationType = "delegate" - DefaultAnnualReward = 0 + DefaultAnnualReward = 0.0 ) type ( @@ -82,10 +82,20 @@ type ( } ) -func (sv StakeValidators) ToMap() ValidatorMap { +func (s StakeValidators) ToMap() ValidatorMap { validators := make(ValidatorMap) - for _, v := range sv { + for _, v := range s { validators[v.ID] = v } return validators } + +func FindHightestAPR(validators []Validator) float64 { + var apr = 0.0 + for _, v := range validators { + if apr < v.Details.Reward.Annual { + apr = v.Details.Reward.Annual + } + } + return apr +} diff --git a/platform/binance/base.go b/platform/binance/base.go index f49c59b88..c6042f691 100644 --- a/platform/binance/base.go +++ b/platform/binance/base.go @@ -1,16 +1,19 @@ package binance import ( + "github.com/trustwallet/blockatlas/platform/binance/staking" "github.com/trustwallet/golibs/coin" ) type Platform struct { - client Client + client Client + stakingClient staking.Client } -func Init(api, apiKey string) *Platform { +func Init(api, apiKey, stakingApi string) *Platform { p := Platform{ - client: InitClient(api, apiKey), + client: InitClient(api, apiKey), + stakingClient: staking.InitClient(stakingApi), } return &p } diff --git a/platform/binance/block_test.go b/platform/binance/block_test.go index 4e1447d02..c6f40dd33 100644 --- a/platform/binance/block_test.go +++ b/platform/binance/block_test.go @@ -11,7 +11,7 @@ import ( func TestPlatform_CurrentBlockNumber(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL, "") + p := Init(server.URL, "", "") number, err := p.CurrentBlockNumber() assert.Nil(t, err) assert.Equal(t, int64(104867535), number) @@ -20,7 +20,7 @@ func TestPlatform_CurrentBlockNumber(t *testing.T) { func TestPlatform_GetBlockByNumber(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL, "") + p := Init(server.URL, "", "") block, err := p.GetBlockByNumber(104867508) assert.Nil(t, err) res, err := json.Marshal(block) diff --git a/platform/binance/stake.go b/platform/binance/stake.go new file mode 100644 index 000000000..5a3b8a417 --- /dev/null +++ b/platform/binance/stake.go @@ -0,0 +1,62 @@ +package binance + +import ( + "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/blockatlas/platform/binance/staking" +) + +const ( + lockTime = 604800 // 7 days + minimumAmount = "100000000" // 1 BNB +) + +func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { + return blockatlas.StakeValidators{}, nil +} + +func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { + validators, err := p.stakingClient.GetValidators() + if err != nil { + return nil, err + } + result := make(blockatlas.ValidatorPage, 0) + for _, validator := range validators.Validators { + result = append(result, normalizeValidator(validator)) + } + return result, nil +} + +func (p *Platform) GetDetails() blockatlas.StakingDetails { + apr := blockatlas.DefaultAnnualReward + validators, err := p.GetValidators() + if err == nil { + apr = blockatlas.FindHightestAPR(validators) + } + return blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: apr}, + MinimumAmount: minimumAmount, + LockTime: lockTime, + Type: blockatlas.DelegationTypeDelegate, + } +} + +func (p *Platform) UndelegatedBalance(address string) (string, error) { + return "0", nil +} + +func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { + return blockatlas.DelegationsPage{}, nil +} + +func normalizeValidator(v staking.Validator) blockatlas.Validator { + return blockatlas.Validator{ + Status: v.Status == 0, + ID: v.Validator, + Details: blockatlas.StakingDetails{ + Reward: blockatlas.StakingReward{Annual: v.APR}, + MinimumAmount: minimumAmount, + LockTime: lockTime, + Type: blockatlas.DelegationTypeDelegate, + }, + } +} diff --git a/platform/binance/staking/client.go b/platform/binance/staking/client.go new file mode 100644 index 000000000..9ec27ea0e --- /dev/null +++ b/platform/binance/staking/client.go @@ -0,0 +1,26 @@ +package staking + +import ( + "net/url" + + "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/network/middleware" +) + +type Client struct { + client.Request +} + +func InitClient(url string) Client { + c := Client{client.InitClient(url, middleware.SentryErrorHandler)} + return c +} + +func (c *Client) GetValidators() (validators Validators, err error) { + params := url.Values{ + "limit": {"100"}, + "offset": {"0"}, + } + err = c.Get(&validators, "/v1/staking/chains/bsc/validators", params) + return +} diff --git a/platform/binance/staking/model.go b/platform/binance/staking/model.go new file mode 100644 index 000000000..9df34a956 --- /dev/null +++ b/platform/binance/staking/model.go @@ -0,0 +1,12 @@ +package staking + +type Validators struct { + Total int `json:"total"` + Validators []Validator `json:"validators"` +} + +type Validator struct { + Validator string `json:"validator"` + Status int `json:"status"` + APR float64 `json:"apr"` +} diff --git a/platform/binance/token_test.go b/platform/binance/token_test.go index 98d0ce400..005997b4b 100644 --- a/platform/binance/token_test.go +++ b/platform/binance/token_test.go @@ -11,7 +11,7 @@ import ( func TestPlatform_GetTokenListByAddress(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL, "") + p := Init(server.URL, "", "") tokens, err := p.GetTokenListByAddress("bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg") assert.Nil(t, err) diff --git a/platform/binance/transaction_test.go b/platform/binance/transaction_test.go index 4f7870037..ffd81a49a 100644 --- a/platform/binance/transaction_test.go +++ b/platform/binance/transaction_test.go @@ -11,7 +11,7 @@ import ( func TestPlatform_GetTxsByAddress(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL, "") + p := Init(server.URL, "", "") txs, err := p.GetTxsByAddress("bnb136ns6lfw4zs5hg4n85vdthaad7hq5m4gtkgf23") assert.Nil(t, err) res, err := json.Marshal(txs) @@ -22,7 +22,7 @@ func TestPlatform_GetTxsByAddress(t *testing.T) { func TestPlatform_GetTokenTxsByAddress(t *testing.T) { server := httptest.NewServer(createMockedAPI()) defer server.Close() - p := Init(server.URL, "") + p := Init(server.URL, "", "") txs, err := p.GetTokenTxsByAddress("bnb1w7puzjxu05ktc5zvpnzkndt6tyl720nsutzvpg", "AVA-645") assert.Nil(t, err) res, err := json.Marshal(txs) diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index 7f15ca26a..9b3cf4923 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -55,33 +55,19 @@ func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { } func (p *Platform) GetDetails() blockatlas.StakingDetails { + apr := blockatlas.DefaultAnnualReward + validators, err := p.GetValidators() + if err == nil { + apr = blockatlas.FindHightestAPR(validators) + } return blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{ - Annual: p.GetMaxAPR(), - }, + Reward: blockatlas.StakingReward{Annual: apr}, MinimumAmount: minimumAmount, LockTime: lockTime, Type: blockatlas.DelegationTypeDelegate, } } -func (p *Platform) GetMaxAPR() float64 { - validators, err := p.GetValidators() - if err != nil { - return blockatlas.DefaultAnnualReward - } - - var max = 0.0 - for _, e := range validators { - v := e.Details.Reward.Annual - if v > max { - max = v - } - } - - return max -} - func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { results := make(blockatlas.DelegationsPage, 0) delegations, err := p.client.GetDelegations(address) diff --git a/platform/harmony/client.go b/platform/harmony/client.go index e54adfd51..4a074956d 100644 --- a/platform/harmony/client.go +++ b/platform/harmony/client.go @@ -4,7 +4,6 @@ import ( "fmt" "strconv" - log "github.com/sirupsen/logrus" "github.com/trustwallet/golibs/client" "github.com/trustwallet/golibs/numbers" ) @@ -43,25 +42,6 @@ func (c *Client) GetBlockByNumber(num int64) (info BlockInfo, err error) { return } -func (c *Client) GetValidators() (validators Validators, err error) { - err = rpcCallStub(c, &validators.Validators, "hmy_getAllValidatorInformation", []interface{}{-1}) - - if err != nil { - log.Error(err, "Harmony: Failed to get all validator addresses") - } - - return -} - -func (c *Client) GetDelegations(address string) (delegations Delegations, err error) { - err = rpcCallStub(c, &delegations.List, "hmy_getDelegationsByDelegator", []interface{}{address}) - - if err != nil { - log.Error(err, "Harmony: Failed to get delegations for address") - } - return -} - func (c *Client) GetBalance(address string) (string, error) { var result string err := rpcCallStub(c, &result, "hmy_getBalance", []interface{}{address, "latest"}) diff --git a/platform/harmony/model.go b/platform/harmony/model.go index a9db97b2f..a4134e22c 100644 --- a/platform/harmony/model.go +++ b/platform/harmony/model.go @@ -26,31 +26,3 @@ type BlockInfo struct { Number string `json:"number"` Transactions []Transaction `json:"transactions"` } - -type ValidatorInfo struct { - Address string `json:"address"` -} - -type LifetimeInfo struct { - Apr string `json:"apr"` -} - -type Validator struct { - Info ValidatorInfo `json:"validator"` - Active bool `json:"currently-in-committee"` - Lifetime LifetimeInfo `json:"lifetime"` -} - -type Validators struct { - Validators []Validator `json:"result"` -} - -type Delegation struct { - DelegatorAddress string `json:"delegator_address"` - ValidatorAddress string `json:"validator_address"` - Amount float64 `json:"amount"` -} - -type Delegations struct { - List []Delegation `json:"result"` -} diff --git a/platform/harmony/stake.go b/platform/harmony/stake.go deleted file mode 100644 index f694b34d0..000000000 --- a/platform/harmony/stake.go +++ /dev/null @@ -1,137 +0,0 @@ -package harmony - -import ( - "math/big" - "strconv" - - log "github.com/sirupsen/logrus" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/blockatlas/services/assets" - "github.com/trustwallet/golibs/types" -) - -const ( - lockTime = 604800 // in seconds (7 epochs or 7 days) -) - -func (p *Platform) GetActiveValidators() (blockatlas.StakeValidators, error) { - validators, err := assets.GetValidatorsMap(p) - if err != nil { - return nil, err - } - result := make(blockatlas.StakeValidators, 0, len(validators)) - for _, v := range validators { - result = append(result, v) - } - return result, nil -} - -func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { - results := make(blockatlas.ValidatorPage, 0) - validators, err := p.client.GetValidators() - if err != nil { - return results, err - } - - for _, v := range validators.Validators { - var apr float64 - if apr, err = strconv.ParseFloat(v.Lifetime.Apr, 64); err != nil { - apr = 0 - } - results = append(results, normalizeValidator(v, apr)) - } - - return results, nil -} - -func (p *Platform) GetDetails() blockatlas.StakingDetails { - apr := p.GetMaxAPR() - return getDetails(apr) -} - -func (p *Platform) GetMaxAPR() float64 { - validators, err := p.client.GetValidators() - if err != nil { - return Annual - } - - var max = 0.0 - for _, e := range validators.Validators { - var apr float64 - if apr, err = strconv.ParseFloat(e.Lifetime.Apr, 64); err != nil { - apr = 0.0 - } - - if apr > max { - max = apr - } - } - - return max -} - -func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { - delegations, err := p.client.GetDelegations(address) - if err != nil { - return nil, err - } - - validators, err := assets.GetValidatorsMap(p) - if err != nil { - return nil, err - } - - return NormalizeDelegations(delegations.List, validators), nil -} - -func (p *Platform) UndelegatedBalance(address string) (string, error) { - balance, err := p.client.GetBalance(address) - if err != nil { - return "0", err - } - return balance, nil -} - -func NormalizeDelegations(delegations []Delegation, validators blockatlas.ValidatorMap) []blockatlas.Delegation { - results := make([]blockatlas.Delegation, 0) - for _, v := range delegations { - validator, ok := validators[v.ValidatorAddress] - if !ok { - log.WithFields( - log.Fields{"address": v.ValidatorAddress, "platform": "harmony", "delegation": v.DelegatorAddress}, - ).Error("Validator not found") - continue - } - - bigval := new(big.Float) - bigval.SetFloat64(v.Amount) - - result := new(big.Int) - bigval.Int(result) // store converted number in result - - delegation := blockatlas.Delegation{ - Delegator: validator, - Value: result.String(), // v.Amount.String(), - Status: blockatlas.DelegationStatusActive, - } - results = append(results, delegation) - } - return results -} - -func getDetails(apr float64) blockatlas.StakingDetails { - return blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: apr}, - MinimumAmount: types.Amount("1000"), - LockTime: lockTime, - Type: blockatlas.DelegationTypeDelegate, - } -} - -func normalizeValidator(v Validator, apr float64) (validator blockatlas.Validator) { - return blockatlas.Validator{ - Status: v.Active, - ID: v.Info.Address, - Details: getDetails(apr), - } -} diff --git a/platform/harmony/stake_test.go b/platform/harmony/stake_test.go deleted file mode 100644 index 2fad4119a..000000000 --- a/platform/harmony/stake_test.go +++ /dev/null @@ -1,182 +0,0 @@ -package harmony - -import ( - "encoding/json" - "strconv" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/trustwallet/blockatlas/pkg/blockatlas" - "github.com/trustwallet/golibs/mock" -) - -var ( - validatorSrc, _ = mock.JsonStringFromFilePath("mocks/" + "validator.json") - delegationsSrc, _ = mock.JsonStringFromFilePath("mocks/" + "delegation.json") - validatorMap = blockatlas.ValidatorMap{ - "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy": validator1, - } - validator1 = blockatlas.StakeValidator{ - ID: "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", - Status: true, - Info: blockatlas.StakeValidatorInfo{ - Name: "Harmony One", - Description: "Stake and earn rewards with the most secure and stable validator. Operated by Harmony One Inc.", - Image: "https://assets.trustwalletapp.com/blockchains/harmony/validators/assets/one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy/logo.png", - Website: "https://harmony.one", - }, - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{ - Annual: 10, - }, - LockTime: 0, - MinimumAmount: "0", - }, - } -) - -func TestNormalizeValidator(t *testing.T) { - var v Validator - _ = json.Unmarshal([]byte(validatorSrc), &v) - expected := blockatlas.Validator{ - Status: v.Active, - ID: v.Info.Address, - Details: blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 12.345}, - LockTime: lockTime, - MinimumAmount: "1000", - Type: blockatlas.DelegationTypeDelegate, - }, - } - - var apr float64 - var err error - if apr, err = strconv.ParseFloat(v.Lifetime.Apr, 64); err != nil { - apr = 0 - } - - result := normalizeValidator(v, apr) - assert.Equal(t, expected, result) -} - -func TestNormalizeDelegations(t *testing.T) { - var delegations []Delegation - err := json.Unmarshal([]byte(delegationsSrc), &delegations) - assert.NoError(t, err) - assert.NotNil(t, delegations) - - expected := []blockatlas.Delegation{ - { - Delegator: validator1, - Value: "12345678900000000000", - Status: blockatlas.DelegationStatusActive, - }, - } - result := NormalizeDelegations(delegations, validatorMap) - assert.Equal(t, expected, result) -} - -func TestHexToInt(t *testing.T) { - result, _ := hexToInt("0x604800") - - assert.Equal(t, uint64(6309888), result) -} - -func TestGetDetails(t *testing.T) { - var expected = blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: 10}, - LockTime: lockTime, - MinimumAmount: "1000", - Type: blockatlas.DelegationTypeDelegate, - } - - result := getDetails(10) - assert.Equal(t, expected, result) -} - -func TestGetValidators(t *testing.T) { - var c Client - - p := Platform{ - client: c, - } - - var validators = []Validator{ - { - Info: ValidatorInfo{ - Address: "one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy", - }, - Active: true, - Lifetime: LifetimeInfo{Apr: "10"}, - }, - } - - rpcCallStub = func(c *Client, result interface{}, method string, params interface{}) error { - jsonData, _ := json.Marshal(validators) - _ = json.Unmarshal(jsonData, result) - return nil - } - - result, _ := p.GetValidators() - assert.Equal(t, lockTime, result[0].Details.LockTime) - assert.Equal(t, float64(10), result[0].Details.Reward.Annual) -} - -func TestGetDelegation(t *testing.T) { - var c Client - - p := Platform{ - client: c, - } - - var delegations = []Delegation{ - { - DelegatorAddress: "one1a0au0p33zrns49h3qw7prn02s4wphu0ggcqrhm", - ValidatorAddress: "one1a0au0p33zrns49h3qw7prn02s4wphu0ggcqrhm", - Amount: 100, - }, - } - - var validators = []Validator{ - { - Info: ValidatorInfo{ - Address: "one1a0au0p33zrns49h3qw7prn02s4wphu0ggcqrhm", - }, - Active: true, - Lifetime: LifetimeInfo{Apr: "10"}, - }, - } - - rpcCallStub = func(c *Client, result interface{}, method string, params interface{}) error { - if method == "hmy_getAllValidatorInformation" { - jsonData, _ := json.Marshal(validators) - _ = json.Unmarshal(jsonData, result) - } else { - jsonData, _ := json.Marshal(delegations) - _ = json.Unmarshal(jsonData, result) - } - return nil - } - - result, _ := p.GetDelegations("one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy") - assert.Equal(t, delegations[0].DelegatorAddress, result[0].Delegator.ID) -} - -func TestGeBalance(t *testing.T) { - var c Client - - p := Platform{ - client: c, - } - - var balance = "0x100" - - rpcCallStub = func(c *Client, result interface{}, method string, params interface{}) error { - jsonData, _ := json.Marshal(balance) - _ = json.Unmarshal(jsonData, result) - return nil - } - - result, _ := p.UndelegatedBalance("one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy") - assert.Equal(t, "256", result) -} diff --git a/platform/kava/stake.go b/platform/kava/stake.go index 56e8cbc36..fdce7f112 100644 --- a/platform/kava/stake.go +++ b/platform/kava/stake.go @@ -57,33 +57,19 @@ func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { } func (p *Platform) GetDetails() blockatlas.StakingDetails { + apr := blockatlas.DefaultAnnualReward + validators, err := p.GetValidators() + if err == nil { + apr = blockatlas.FindHightestAPR(validators) + } return blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{ - Annual: p.GetMaxAPR(), - }, + Reward: blockatlas.StakingReward{Annual: apr}, MinimumAmount: minimumAmount, LockTime: lockTime, Type: blockatlas.DelegationTypeDelegate, } } -func (p *Platform) GetMaxAPR() float64 { - validators, err := p.GetValidators() - if err != nil { - return blockatlas.DefaultAnnualReward - } - - var max = 0.0 - for _, e := range validators { - v := e.Details.Reward.Annual - if v > max { - max = v - } - } - - return max -} - func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, error) { results := make(blockatlas.DelegationsPage, 0) delegations, err := p.client.GetDelegations(address) diff --git a/platform/platform.go b/platform/platform.go index 1a7f17101..0602101c3 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -65,7 +65,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Aeternity().Handle: aeternity.Init(config.Default.Aeternity.API), coin.Solana().Handle: solana.Init(config.Default.Solana.API), 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.Binance().Handle: binance.Init(config.Default.Binance.API, config.Default.Binance.Key, config.Default.Binance.StakingAPI), coin.Zilliqa().Handle: zilliqa.Init(config.Default.Zilliqa.API, config.Default.Zilliqa.Key, config.Default.Zilliqa.RPC), coin.Polkadot().Handle: polkadot.Init(coin.POLKADOT, config.Default.Polkadot.API), coin.Stellar().Handle: stellar.Init(coin.STELLAR, config.Default.Stellar.API), From 6d823522bac8fa28ea98d39fc699a37b38fc6d22 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Fri, 5 Mar 2021 07:48:52 +0900 Subject: [PATCH 494/506] fix percent (#1431) --- platform/binance/stake.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/binance/stake.go b/platform/binance/stake.go index 5a3b8a417..b5ccc7e44 100644 --- a/platform/binance/stake.go +++ b/platform/binance/stake.go @@ -33,7 +33,7 @@ func (p *Platform) GetDetails() blockatlas.StakingDetails { apr = blockatlas.FindHightestAPR(validators) } return blockatlas.StakingDetails{ - Reward: blockatlas.StakingReward{Annual: apr}, + Reward: blockatlas.StakingReward{Annual: apr * 100}, MinimumAmount: minimumAmount, LockTime: lockTime, Type: blockatlas.DelegationTypeDelegate, From f0b6aeaef758b715fa57e2eb77b8a9b3766a5650 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Sat, 6 Mar 2021 11:29:26 +0900 Subject: [PATCH 495/506] Changes: (#1432) * filter trusted and active validators * fix one typo --- platform/binance/stake.go | 17 +++++++++++++++++ platform/tezos/baker.go | 2 +- services/assets/client.go | 2 +- services/assets/validator.go | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/platform/binance/stake.go b/platform/binance/stake.go index b5ccc7e44..512066694 100644 --- a/platform/binance/stake.go +++ b/platform/binance/stake.go @@ -3,6 +3,7 @@ package binance import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" "github.com/trustwallet/blockatlas/platform/binance/staking" + "github.com/trustwallet/blockatlas/services/assets" ) const ( @@ -19,8 +20,24 @@ func (p *Platform) GetValidators() (blockatlas.ValidatorPage, error) { if err != nil { return nil, err } + + assetsValidators, err := assets.GetValidatorsInfo(p.Coin()) + if err != nil { + return nil, err + } + + assetsMap := assetsValidators.ToMap() result := make(blockatlas.ValidatorPage, 0) + for _, validator := range validators.Validators { + // filter trusted + if _, ok := assetsMap[validator.Validator]; !ok { + continue + } + // filter inactive + if validator.Status != 0 { + continue + } result = append(result, normalizeValidator(validator)) } return result, nil diff --git a/platform/tezos/baker.go b/platform/tezos/baker.go index d2fb19dba..8ea61bd69 100644 --- a/platform/tezos/baker.go +++ b/platform/tezos/baker.go @@ -26,7 +26,7 @@ func (c *BakerClient) GetBakers() (validators blockatlas.StakeValidators, err er if err != nil { return } - assetsValidators, err := assets.GetchValidatorsInfo(coin.Tezos()) + assetsValidators, err := assets.GetValidatorsInfo(coin.Tezos()) if err != nil { return } diff --git a/services/assets/client.go b/services/assets/client.go index 1d8ae5cae..0abde523f 100644 --- a/services/assets/client.go +++ b/services/assets/client.go @@ -13,7 +13,7 @@ const ( URL = "https://assets.trustwalletapp.com/blockchains/" ) -func GetchValidatorsInfo(coin coin.Coin) (AssetValidators, error) { +func GetValidatorsInfo(coin coin.Coin) (AssetValidators, error) { var results AssetValidators request := client.InitClient(URL+coin.Handle, middleware.SentryErrorHandler) err := request.GetWithCache(&results, "validators/list.json", nil, time.Hour*1) diff --git a/services/assets/validator.go b/services/assets/validator.go index 1863eca51..17bddb5c0 100644 --- a/services/assets/validator.go +++ b/services/assets/validator.go @@ -19,7 +19,7 @@ func GetValidatorsMap(api blockatlas.StakeAPI) (blockatlas.ValidatorMap, error) } func getValidators(api blockatlas.StakeAPI) (AssetValidators, blockatlas.ValidatorPage, error) { - assetsValidators, err := GetchValidatorsInfo(api.Coin()) + assetsValidators, err := GetValidatorsInfo(api.Coin()) if err != nil { return nil, nil, err } From 7749987ae9719d2a967ec0cdbdecaef102e16560 Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Mon, 8 Mar 2021 18:39:28 +0900 Subject: [PATCH 496/506] result might be null (#1434) --- services/tokenindexer/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/tokenindexer/api.go b/services/tokenindexer/api.go index 72c502585..0e563b831 100644 --- a/services/tokenindexer/api.go +++ b/services/tokenindexer/api.go @@ -51,7 +51,7 @@ func (i Instance) GetTokensByAddress(r GetTokensByAddressRequest) (GetTokensByAd } func normalize(dbAssets []models.Asset) blockatlas.ResultsResponse { - var result []types.Asset + result := make([]types.Asset, 0) for _, a := range dbAssets { asset := types.Asset{ Id: a.Asset, From 37bfa8510ef10fc59653dce89c7d461c39077784 Mon Sep 17 00:00:00 2001 From: Viacheslav Kulish <32914239+vcoolish@users.noreply.github.com> Date: Mon, 8 Mar 2021 20:34:37 +0200 Subject: [PATCH 497/506] Fix Cosmos Validator status (#1436) --- platform/cosmos/mocks/validator.json | 19 ++++++++++--------- platform/cosmos/stake.go | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/platform/cosmos/mocks/validator.json b/platform/cosmos/mocks/validator.json index 8bb377c70..ce86167a5 100644 --- a/platform/cosmos/mocks/validator.json +++ b/platform/cosmos/mocks/validator.json @@ -1,25 +1,26 @@ { "operator_address": "cosmosvaloper1lktjhnzkpkz3ehrg8psvmwhafg56kfss3q3t8m", - "consensus_pubkey": "cosmosvalconspub1zcjduepqelcwpat987h9yq0ck6g9fsc8t0mththk547gwvk0w4wnkpl0stnspr3hdc", - "jailed": false, - "status": 2, - "tokens": "1557750969185", - "delegator_shares": "1557750969185.000000000000000000", + "consensus_pubkey": { + "type": "tendermint/PubKeyEd25519", + "value": "z/Dg9WU/rlIB+LaQVMMHW/a7rvalfIcyz3VdOwfvguc=" + }, + "status": 3, + "tokens": "597103578752", + "delegator_shares": "597103578752.000000000000000000", "description": { "moniker": "Umbrella ☔", "identity": "A530AC4D75991FE2", "website": "https://umbrellavalidator.com", "details": "One of the winners of Cosmos Game of Stakes, and HackAtom3." }, - "unbonding_height": "0", "unbonding_time": "1970-01-01T00:00:00Z", "commission": { "commission_rates": { "rate": "0.070400000000000000", "max_rate": "1.000000000000000000", - "max_change_rate": "0.100000000000000000", - "update_time": "2019-08-05T07:10:23.689753607Z" - } + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2020-09-01T18:40:38.071399488Z" }, "min_self_delegation": "1" } diff --git a/platform/cosmos/stake.go b/platform/cosmos/stake.go index 9b3cf4923..c66741255 100644 --- a/platform/cosmos/stake.go +++ b/platform/cosmos/stake.go @@ -154,7 +154,7 @@ func NormalizeUnbondingDelegations(delegations []UnbondingDelegation, validators func normalizeValidator(v Validator, p Pool, inflation float64) (validator blockatlas.Validator) { reward := CalculateAnnualReward(p, inflation, v) return blockatlas.Validator{ - Status: v.Status == 2, + Status: v.Status == 3, ID: v.Address, Details: blockatlas.StakingDetails{ Reward: blockatlas.StakingReward{Annual: reward}, From 3c9d1d37f11a62a87af8cee8054f54297159073d Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Wed, 10 Mar 2021 09:50:57 +0900 Subject: [PATCH 498/506] [Collectible] Add transfer fee for ERC1155 (#1435) * return TransferFee * add optional transfer_fee * update test --- config.yml | 2 +- go.mod | 4 ++-- go.sum | 20 ++++--------------- platform/ethereum/opensea/collection.go | 11 +++++++++- platform/ethereum/opensea/collection_test.go | 4 ++++ .../opensea/mocks/opensea_collectible.json | 13 +++++++++++- platform/ethereum/opensea/model.go | 8 ++++++++ 7 files changed, 41 insertions(+), 21 deletions(-) diff --git a/config.yml b/config.yml index fe8ff2cd6..008f305e6 100644 --- a/config.yml +++ b/config.yml @@ -197,7 +197,7 @@ harmony: api: https://api.s0.t.hmny.io kava: - api: https://kava.data.kava.io + api: https://api.kava.io polkadot: api: https://polkadot.subscan.io/api diff --git a/go.mod b/go.mod index 887b716db..85ed610a8 100644 --- a/go.mod +++ b/go.mod @@ -27,8 +27,8 @@ require ( 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.1.5 - github.com/trustwallet/golibs/network v0.0.0-20210222000450-7376c687b4e9 + github.com/trustwallet/golibs v0.1.8 + github.com/trustwallet/golibs/network v0.0.0-20210302024139-c340cb937103 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-20210217105451-b926d437f341 // indirect diff --git a/go.sum b/go.sum index 88c5d5391..581424068 100644 --- a/go.sum +++ b/go.sum @@ -60,7 +60,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 h1:6ejg6Lkk8dskcM7wQ28gONkukbQkM4qpj4RnYbpFzrI= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e h1:6JKvHHt396/qabvMhnhUZvWaHZzfVfldxE60TK8YLhg= github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= @@ -152,7 +151,6 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -283,11 +281,9 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls= github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= @@ -349,7 +345,6 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -357,7 +352,6 @@ 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_golang v0.9.4 h1:Y8E/JaaPbmFSW2V81Ab/d8yZFYQQGbni1b1jPcG9Y6A= github.com/prometheus/client_golang v0.9.4/go.mod h1:oCXIBxdI62A4cR6aTRJCgetEjecSIYzOEaeAn4iYEpM= @@ -365,12 +359,10 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: 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/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= github.com/prometheus/common v0.4.1/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/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -393,7 +385,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU= github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= @@ -419,13 +410,11 @@ github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -438,12 +427,11 @@ github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+t github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= 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.1.5 h1:8kMIWrU38a1Rfl9kLXo0egN+PBtSXr78T2sc+UpJ4Q8= -github.com/trustwallet/golibs v0.1.5/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= -github.com/trustwallet/golibs/network v0.0.0-20210222000450-7376c687b4e9 h1:OEmmVI2SDcwy1vS3C3rS3oj0zUZQnrbLixPWtpmL9Uk= -github.com/trustwallet/golibs/network v0.0.0-20210222000450-7376c687b4e9/go.mod h1:LDMLFnOnwmC30WuCCIJ56TWeXxwCVcrMFJYeC6GEnxY= +github.com/trustwallet/golibs v0.1.8 h1:g/c2RY8XZxOjoT8ZaXUS1X7zeaXvYuy3IJScqZcwMeA= +github.com/trustwallet/golibs v0.1.8/go.mod h1:SQ3mijAuOTX9GRyaqph3NY2ox04JD5WQ6PkWqX2NB8w= +github.com/trustwallet/golibs/network v0.0.0-20210302024139-c340cb937103 h1:RQVyaTFRRu37c+1kj+O2Z18doNAHOElMh8Q+/DrQi0I= +github.com/trustwallet/golibs/network v0.0.0-20210302024139-c340cb937103/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= diff --git a/platform/ethereum/opensea/collection.go b/platform/ethereum/opensea/collection.go index 3e9f16b9a..b202988f6 100644 --- a/platform/ethereum/opensea/collection.go +++ b/platform/ethereum/opensea/collection.go @@ -2,6 +2,8 @@ package opensea import ( "github.com/trustwallet/blockatlas/pkg/blockatlas" + "github.com/trustwallet/golibs/asset" + "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/types" ) @@ -58,7 +60,7 @@ func NormalizeCollectiblePage(collectibles []Collectible, coinIndex uint) (page } func NormalizeCollectible(c Collectible, coinIndex uint) types.Collectible { - return types.Collectible{ + collectible := types.Collectible{ ID: blockatlas.GenCollectibleId(c.AssetContract.Address, c.TokenId), CollectionID: c.Collection.Slug, TokenID: c.TokenId, @@ -73,4 +75,11 @@ func NormalizeCollectible(c Collectible, coinIndex uint) types.Collectible { Coin: coinIndex, Version: c.AssetContract.Version, } + if c.FeeToken != nil { + collectible.TransferFee = &types.CollectibleTransferFee{ + Asset: asset.BuildID(coin.ETHEREUM, c.FeeToken.Address), + Amount: c.TransferFee, + } + } + return collectible } diff --git a/platform/ethereum/opensea/collection_test.go b/platform/ethereum/opensea/collection_test.go index 494842e45..c2beb0056 100644 --- a/platform/ethereum/opensea/collection_test.go +++ b/platform/ethereum/opensea/collection_test.go @@ -61,6 +61,10 @@ var ( Description: "Rustbits are the main token of use within the Age of Rust game universe. You need Rustbits to not only play Age of Rust, but also to purchase in-game cryptoitems as well. Rustbits are radioactive rust scraped off of hulls of abandoned ships that are in orbit around a hidden planet, which is also a gas giant. The planet is so radioactive, it damages ships and kills anyone that gets close to it. Getting bits of rust off of ships is highly rare and prized.", Coin: 60, Name: "Rustbits", + TransferFee: &types.CollectibleTransferFee{ + Asset: "c60_t0xf629cbd94d3791c9250152bd8dfbdf380e2a3b9c", + Amount: "0", + }, } ) diff --git a/platform/ethereum/opensea/mocks/opensea_collectible.json b/platform/ethereum/opensea/mocks/opensea_collectible.json index 4fff8c06e..137029c93 100644 --- a/platform/ethereum/opensea/mocks/opensea_collectible.json +++ b/platform/ethereum/opensea/mocks/opensea_collectible.json @@ -19,6 +19,17 @@ "name": "Age of Rust", "external_url": "https://opensea.io/" }, - "permalink": "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688" + "permalink": "https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/54277541829991970107421667568590323026590803461896874578610080514640537714688", + "transfer_fee_payment_token": { + "id": 18, + "symbol": "ENJ", + "address": "0xf629cbd94d3791c9250152bd8dfbdf380e2a3b9c", + "image_url": "https://lh3.googleusercontent.com/l9kffrrCmJQ4rmUONIKoV2tx1cQr3ejM2oKhtg08njtUo11tCCwmvTVgA2wD3akBIoMTdepIwrc62e105rRtmin6", + "name": "Enjin Token", + "decimals": 18, + "eth_price": "0.000950396392036", + "usd_price": "1.610000000000000098" + }, + "transfer_fee": "0" } ] diff --git a/platform/ethereum/opensea/model.go b/platform/ethereum/opensea/model.go index 1d63b22e1..0f00276fc 100644 --- a/platform/ethereum/opensea/model.go +++ b/platform/ethereum/opensea/model.go @@ -25,6 +25,10 @@ type PrimaryAssetContract struct { Url string `json:"external_link"` } +type TransferFeeToken struct { + Address string `json:"address"` +} + type DisplayData struct { Images []string `json:"images"` } @@ -43,6 +47,10 @@ type Collectible struct { Permalink string `json:"permalink"` Description string `json:"description"` Collection CollectibleCollections `json:"collection"` + + // only available for ERC1155 + FeeToken *TransferFeeToken `json:"transfer_fee_payment_token,omitempty"` + TransferFee string `json:"transfer_fee,omitempty"` } type CollectibleCollections struct { From 56de9d70e6b825590b48b5ec145a8f1216c7aff4 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Fri, 2 Apr 2021 12:45:54 -0700 Subject: [PATCH 499/506] Add updatedAt to SubscriptionsAssetAssociation + trongrid (#1439) * Add updatedAt to SubscriptionsAssetAssociation * Update indexer.go * Use updated_at when fetching subscriptions_asset_associations * Update api.go * Update registry.go * Update subscription.go * Remove TRC10 token transfer * Fix lint issues * Delete token_transfer.json * Implement trongrid api key --- api/registry.go | 2 +- config.yml | 2 +- config/configuration.go | 5 +-- db/asset.go | 2 +- db/models/subscriptions.go | 1 + db/subscription.go | 6 ++- platform/platform.go | 2 +- platform/tron/base.go | 10 ++--- platform/tron/block.go | 46 +++-------------------- platform/tron/client.go | 13 +------ platform/tron/mocks/token_transfer.json | 19 ---------- platform/tron/stake.go | 2 +- platform/tron/token.go | 2 +- platform/tron/transaction.go | 50 +------------------------ platform/tron/transaction_test.go | 43 --------------------- services/tokenindexer/api.go | 8 +++- services/tokenindexer/indexer.go | 13 +++++-- services/tokenindexer/models.go | 8 +++- 18 files changed, 51 insertions(+), 183 deletions(-) delete mode 100644 platform/tron/mocks/token_transfer.json diff --git a/api/registry.go b/api/registry.go index 9534656c7..65345ec82 100644 --- a/api/registry.go +++ b/api/registry.go @@ -105,7 +105,7 @@ func RegisterTokensIndexAPI(router gin.IRouter, instance tokenindexer.Instance) router.GET("/v3/tokens/new", func(c *gin.Context) { endpoint.GetNewTokens(c, instance) }) - router.POST("/v3/tokens", func(c *gin.Context) { + router.POST("/v1/assets/associations", func(c *gin.Context) { endpoint.GetTokensByAddressV3(c, instance) }) } diff --git a/config.yml b/config.yml index 008f305e6..3dc32d8b1 100644 --- a/config.yml +++ b/config.yml @@ -99,7 +99,7 @@ icon: # [TRX] Tron: https://tron.network/ tron: api: https://api.trongrid.io - grid: https://api.trongrid.io # trongrid api + key: "" # [VET] VeChain: https://www.vechain.org vechain: diff --git a/config/configuration.go b/config/configuration.go index f939973a8..ee192796b 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -93,9 +93,8 @@ type Configuration struct { API string `mapstructure:"api"` } `mapstructure:"icon"` Tron struct { - API string `mapstructure:"api"` - Grid string `mapstructure:"grid"` - Explorer string `mapstructure:"explorer"` + API string `mapstructure:"api"` + Key string `mapstructure:"key"` } `mapstructure:"tron"` Vechain struct { API string `mapstructure:"api"` diff --git a/db/asset.go b/db/asset.go index b0a527523..9ac1dd63d 100644 --- a/db/asset.go +++ b/db/asset.go @@ -42,7 +42,7 @@ func (i *Instance) GetSubscriptionsByAddressIDs(ids []string, from time.Time) ([ Preload("Subscription"). Preload("Asset"). Where("subscriptions.address in (?)", ids). - Where("subscriptions_asset_associations.created_at > ?", from). + Where("subscriptions_asset_associations.updated_at > ?", from). Find(&associations).Error; err != nil { return nil, err } diff --git a/db/models/subscriptions.go b/db/models/subscriptions.go index d0bc32a6d..28b608b11 100644 --- a/db/models/subscriptions.go +++ b/db/models/subscriptions.go @@ -12,6 +12,7 @@ type ( SubscriptionsAssetAssociation struct { CreatedAt time.Time `gorm:"index;"` + UpdatedAt time.Time `gorm:"index;"` Subscription Subscription `gorm:"ForeignKey:SubscriptionId; not null"` SubscriptionId uint `gorm:"primary_key; autoIncrement:false; index"` diff --git a/db/subscription.go b/db/subscription.go index 4dbb72064..922acd3c7 100644 --- a/db/subscription.go +++ b/db/subscription.go @@ -58,5 +58,9 @@ func (i *Instance) CreateSubscriptionsAssets(associations []models.Subscriptions if len(associations) == 0 { return nil } - return i.Gorm.Clauses(clause.OnConflict{DoNothing: true}).Create(&associations).Error + return i.Gorm.Clauses( + clause.OnConflict{ + OnConstraint: "subscriptions_asset_associations_pkey", + DoUpdates: clause.AssignmentColumns([]string{"updated_at"})}, + ).Create(&associations).Error } diff --git a/platform/platform.go b/platform/platform.go index 0602101c3..ced515ca7 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -50,7 +50,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Fio().Handle: fio.Init(config.Default.Fio.API), coin.Aion().Handle: aion.Init(config.Default.Aion.API), coin.Icon().Handle: icon.Init(config.Default.Icon.API), - coin.Tron().Handle: tron.Init(config.Default.Tron.API, config.Default.Tron.Grid), + coin.Tron().Handle: tron.Init(config.Default.Tron.API, config.Default.Tron.Key), coin.Nano().Handle: nano.Init(config.Default.Nano.API), coin.Nimiq().Handle: nimiq.Init(config.Default.Nimiq.API), coin.Iotex().Handle: iotex.Init(config.Default.Iotex.API), diff --git a/platform/tron/base.go b/platform/tron/base.go index e29bc75f6..6b97d8a2d 100644 --- a/platform/tron/base.go +++ b/platform/tron/base.go @@ -7,14 +7,14 @@ import ( ) type Platform struct { - client Client - gridClient GridClient + client Client } -func Init(api, gridApi string) *Platform { +func Init(api, apiKey string) *Platform { + request := client.InitClient(api, middleware.SentryErrorHandler) + request.Headers = map[string]string{"TRON-PRO-API-KEY": apiKey} return &Platform{ - client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, - gridClient: GridClient{client.InitClient(api, middleware.SentryErrorHandler)}, + client: Client{request}, } } diff --git a/platform/tron/block.go b/platform/tron/block.go index fde45f4d2..ad97d94b2 100644 --- a/platform/tron/block.go +++ b/platform/tron/block.go @@ -1,9 +1,6 @@ package tron import ( - "encoding/hex" - "sync" - "github.com/trustwallet/golibs/types" ) @@ -17,11 +14,7 @@ func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { return nil, err } - txsChan := p.NormalizeBlockTxs(block.Txs) - txs := make(types.Txs, 0) - for cTxs := range txsChan { - txs = append(txs, cTxs) - } + txs := p.NormalizeBlockTxs(block.Txs) return &types.Block{ Number: num, @@ -29,39 +22,12 @@ func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { }, nil } -func (p *Platform) NormalizeBlockTxs(srcTxs []Tx) chan types.Tx { - txChan := make(chan types.Tx, len(srcTxs)) - var wg sync.WaitGroup +func (p *Platform) NormalizeBlockTxs(srcTxs []Tx) []types.Tx { + txs := make([]types.Tx, 0) for _, srcTx := range srcTxs { - wg.Add(1) - go func(s Tx, c chan types.Tx) { - defer wg.Done() - p.NormalizeBlockChannel(s, c) - }(srcTx, txChan) - } - wg.Wait() - close(txChan) - return txChan -} - -func (p *Platform) NormalizeBlockChannel(srcTx Tx, txChan chan types.Tx) { - if len(srcTx.Data.Contracts) == 0 { - return - } - - tx, err := normalize(srcTx) - if err != nil { - return - } - transfer := srcTx.Data.Contracts[0].Parameter.Value - if len(transfer.AssetName) > 0 { - assetName, err := hex.DecodeString(transfer.AssetName[:]) - if err == nil { - info, err := p.gridClient.fetchTokenInfo(string(assetName)) - if err == nil && len(info.Data) > 0 { - addTokenMeta(tx, srcTx, info.Data[0]) - } + if tx, err := normalize(srcTx); err == nil { + txs = append(txs, *tx) } } - txChan <- *tx + return txs } diff --git a/platform/tron/client.go b/platform/tron/client.go index 86676136a..7c6899427 100644 --- a/platform/tron/client.go +++ b/platform/tron/client.go @@ -9,9 +9,6 @@ import ( ) type ( - GridClient struct { - client.Request - } Client struct { client.Request } @@ -32,7 +29,7 @@ func (c *Client) fetchBlockByNumber(num int64) (Block, error) { return blocks.Blocks[0], nil } -func (c *GridClient) fetchTxsOfAddress(address, token string) ([]Tx, error) { +func (c *Client) fetchTxsOfAddress(address, token string) ([]Tx, error) { path := fmt.Sprintf("v1/accounts/%s/transactions", url.PathEscape(address)) var txs Page @@ -45,7 +42,7 @@ func (c *GridClient) fetchTxsOfAddress(address, token string) ([]Tx, error) { return txs.Txs, err } -func (c *GridClient) fetchAccount(address string) (accounts *Account, err error) { +func (c *Client) fetchAccount(address string) (accounts *Account, err error) { path := fmt.Sprintf("v1/accounts/%s", address) err = c.GetWithCache(&accounts, path, nil, time.Second*1) return @@ -56,12 +53,6 @@ func (c *Client) fetchAccountVotes(address string) (account *AccountData, err er return } -func (c *GridClient) fetchTokenInfo(id string) (asset Asset, err error) { - path := fmt.Sprintf("v1/assets/%s", id) - err = c.GetWithCache(&asset, path, nil, time.Hour*24) - return -} - func (c *Client) fetchValidators() (validators Validators, err error) { err = c.GetWithCache(&validators, "wallet/listwitnesses", nil, time.Hour*1) return diff --git a/platform/tron/mocks/token_transfer.json b/platform/tron/mocks/token_transfer.json deleted file mode 100644 index 82f3ea4aa..000000000 --- a/platform/tron/mocks/token_transfer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "block_timestamp": 1564797900000, - "raw_data": { - "contract": [ - { - "parameter": { - "value": { - "amount": 2776267, - "asset_name": "1002000", - "owner_address": "4182dd6b9966724ae2fdc79b416c7588da67ff1b35", - "to_address": "410583a68a3bcd86c25ab1bee482bac04a216b0261" - } - }, - "type": "TransferAssetContract" - } - ] - }, - "txID": "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df" -} diff --git a/platform/tron/stake.go b/platform/tron/stake.go index 35dff0d48..54e276de7 100644 --- a/platform/tron/stake.go +++ b/platform/tron/stake.go @@ -70,7 +70,7 @@ func (p *Platform) GetDelegations(address string) (blockatlas.DelegationsPage, e } func (p *Platform) UndelegatedBalance(address string) (string, error) { - account, err := p.gridClient.fetchAccount(address) + account, err := p.client.fetchAccount(address) if err != nil { return "0", err } diff --git a/platform/tron/token.go b/platform/tron/token.go index 105a5024e..72062bdc0 100644 --- a/platform/tron/token.go +++ b/platform/tron/token.go @@ -11,7 +11,7 @@ func (p *Platform) GetTokenListByAddress(address string) ([]types.Token, error) func (p *Platform) GetTokenListIdsByAddress(address string) ([]string, error) { assetIds := make([]string, 0) - tokens, err := p.gridClient.fetchAccount(address) + tokens, err := p.client.fetchAccount(address) if err != nil { return assetIds, err } diff --git a/platform/tron/transaction.go b/platform/tron/transaction.go index 9bb1954f3..0eaa161c4 100644 --- a/platform/tron/transaction.go +++ b/platform/tron/transaction.go @@ -3,15 +3,13 @@ package tron import ( "errors" "strconv" - "strings" - log "github.com/sirupsen/logrus" "github.com/trustwallet/golibs/coin" "github.com/trustwallet/golibs/types" ) func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { - Txs, err := p.gridClient.fetchTxsOfAddress(address, "") + Txs, err := p.client.fetchTxsOfAddress(address, "") if err != nil && len(Txs) == 0 { return nil, err } @@ -39,11 +37,7 @@ func (p *Platform) GetTokenTxsByAddress(address, token string) (types.Txs, error switch tokenType { case types.TRC10: - txs, err := p.fetchTransactionsForTRC10Tokens(address, token) - if err != nil { - return nil, err - } - return txs, nil + return types.Txs{}, nil case types.TRC20: trc20Transactions, err := p.client.fetchTRC20Transactions(address) if err != nil { @@ -64,46 +58,6 @@ func getTokenType(token string) types.TokenType { } } -func addTokenMeta(tx *types.Tx, srcTx Tx, tokenInfo AssetInfo) { - transfer := srcTx.Data.Contracts[0].Parameter.Value - tx.Meta = types.TokenTransfer{ - Name: tokenInfo.Name, - Symbol: strings.ToUpper(tokenInfo.Symbol), - TokenID: strconv.Itoa(int(tokenInfo.ID)), - Decimals: tokenInfo.Decimals, - Value: transfer.Amount, - From: tx.From, - To: tx.To, - } -} - -func (p *Platform) fetchTransactionsForTRC10Tokens(address, token string) (types.Txs, error) { - txs := make(types.Txs, 0) - - tokenTxs, err := p.gridClient.fetchTxsOfAddress(address, token) - if err != nil { - return nil, err - } - - info, err := p.gridClient.fetchTokenInfo(token) - if err != nil { - return nil, err - } - for _, srcTx := range tokenTxs { - tx, err := normalize(srcTx) - if err != nil { - log.Error(err) - continue - } - if info.Data != nil && len(info.Data) > 0 { - addTokenMeta(tx, srcTx, info.Data[0]) - } - - txs = append(txs, *tx) - } - return txs, nil -} - func normalizeTRC20Transactions(transactions TRC20Transactions) types.Txs { txs := make(types.Txs, 0, len(transactions.Data)) for _, rawTx := range transactions.Data { diff --git a/platform/tron/transaction_test.go b/platform/tron/transaction_test.go index e193e5a06..40138116c 100644 --- a/platform/tron/transaction_test.go +++ b/platform/tron/transaction_test.go @@ -13,7 +13,6 @@ import ( var ( transferSrc, _ = mock.JsonStringFromFilePath("mocks/" + "transfer.json") - tokenTransferSrc, _ = mock.JsonStringFromFilePath("mocks/" + "token_transfer.json") wantedTransactionsWithToken, _ = mock.JsonStringFromFilePath("mocks/" + "token_txs_response.json") wantedTransactionsOnly, _ = mock.JsonStringFromFilePath("mocks/" + "txs_response.json") @@ -32,28 +31,6 @@ var ( Decimals: 6, }, } - - tokenTransferDst = types.Tx{ - ID: "24a10f7a503e78adc0d7e380b68005531b09e16b9e3f7b524e33f40985d287df", - Coin: coin.TRON, - From: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", - To: "TAUN6FwrnwwmaEqYcckffC7wYmbaS6cBiX", - Fee: "0", // TODO - Date: 1564797900, - Block: 0, // TODO - Status: types.StatusCompleted, - Meta: types.TokenTransfer{ - Name: "BitTorrent", - Symbol: "BTT", - TokenID: "1002000", - Decimals: 6, - Value: "2776267", - From: "TMuA6YqfCeX8EhbfYEg5y7S4DqzSJireY9", - To: "TAUN6FwrnwwmaEqYcckffC7wYmbaS6cBiX", - }, - } - - assetInfo = AssetInfo{Name: "BitTorrent", Symbol: "BTT", Decimals: 6, ID: 1002000} ) type test struct { @@ -62,26 +39,6 @@ type test struct { expected *types.Tx } -func TestNormalizeTokenTransfer(t *testing.T) { - testNormalizeTokenTransfer(t, &test{ - name: "token transfer", - apiResponse: tokenTransferSrc, - expected: &tokenTransferDst, - }) -} - -func testNormalizeTokenTransfer(t *testing.T, _test *test) { - var srcTx Tx - err := json.Unmarshal([]byte(_test.apiResponse), &srcTx) - assert.NoError(t, err) - assert.NotNil(t, srcTx) - res, err := normalize(srcTx) - assert.NoError(t, err) - assert.NotNil(t, res) - addTokenMeta(res, srcTx, assetInfo) - assert.Equal(t, _test.expected, res) -} - func TestNormalize(t *testing.T) { testNormalize(t, &test{ name: "transfer", diff --git a/services/tokenindexer/api.go b/services/tokenindexer/api.go index 0e563b831..6a584542e 100644 --- a/services/tokenindexer/api.go +++ b/services/tokenindexer/api.go @@ -41,10 +41,14 @@ func (i Instance) GetTokensByAddress(r GetTokensByAddressRequest) (GetTokensByAd return GetTokensByAddressResponse{}, err } - assetIds := make([]string, 0) + assetIds := make([]GetTokensAsset, 0) for _, association := range associations { - assetIds = append(assetIds, association.Asset.Asset) + assetIds = append(assetIds, GetTokensAsset{ + AssetId: association.Asset.Asset, + CreatedAt: association.CreatedAt.Unix(), + UpdatedAt: association.UpdatedAt.Unix(), + }) } return assetIds, nil diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index 632daf307..0295be77b 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -90,6 +90,7 @@ func calculateSubscriptionAssetAssociations(database *db.Instance, addressAssets subscriptionsMap[subscription.Address] = subscription } + uniqueMap := map[string]bool{} for addressId, assets := range addressAssetsMap { subscription, ok := subscriptionsMap[addressId] if !ok { @@ -101,11 +102,15 @@ func calculateSubscriptionAssetAssociations(database *db.Instance, addressAssets if !ok { continue } - association := models.SubscriptionsAssetAssociation{ - SubscriptionId: subscription.ID, - AssetId: asset.ID, + subscriptionKey := strconv.Itoa(int(asset.ID)) + "_" + strconv.Itoa(int(subscription.ID)) + if _, ok := uniqueMap[subscriptionKey]; !ok { + association := models.SubscriptionsAssetAssociation{ + SubscriptionId: subscription.ID, + AssetId: asset.ID, + } + associations = append(associations, association) + uniqueMap[subscriptionKey] = true } - associations = append(associations, association) } } diff --git a/services/tokenindexer/models.go b/services/tokenindexer/models.go index 230551132..704b089e6 100644 --- a/services/tokenindexer/models.go +++ b/services/tokenindexer/models.go @@ -10,5 +10,11 @@ type ( From uint `json:"from"` } - GetTokensByAddressResponse []string + GetTokensAsset struct { + AssetId string `json:"asset_id"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` + } + + GetTokensByAddressResponse []GetTokensAsset ) From ed5f25ff613031d5f3c6eb46c2825fdfb050ffa6 Mon Sep 17 00:00:00 2001 From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com> Date: Mon, 5 Apr 2021 11:51:30 -0700 Subject: [PATCH 500/506] [Theta] Add API Key (#1443) * Add theta chain key * Update base.go * Update base.go --- config.yml | 1 + config/configuration.go | 1 + platform/platform.go | 2 +- platform/theta/base.go | 6 ++++-- platform/tron/base.go | 3 ++- services/tokenindexer/indexer.go | 2 +- 6 files changed, 10 insertions(+), 5 deletions(-) diff --git a/config.yml b/config.yml index 3dc32d8b1..c7cd628ed 100644 --- a/config.yml +++ b/config.yml @@ -108,6 +108,7 @@ vechain: # [THETA] THETA: https://www.thetatoken.org/ theta: api: https://explorer.thetatoken.org:9000/api + key: "" # [ATOM] Cosmos: https://cosmos.network/ cosmos: diff --git a/config/configuration.go b/config/configuration.go index ee192796b..dc82d9b15 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -101,6 +101,7 @@ type Configuration struct { } `mapstructure:"vechain"` Theta struct { API string `mapstructure:"api"` + Key string `mapstructure:"key"` } `mapstructure:"theta"` Cosmos struct { API string `mapstructure:"api"` diff --git a/platform/platform.go b/platform/platform.go index ced515ca7..920a824d8 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -54,7 +54,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Nano().Handle: nano.Init(config.Default.Nano.API), coin.Nimiq().Handle: nimiq.Init(config.Default.Nimiq.API), coin.Iotex().Handle: iotex.Init(config.Default.Iotex.API), - coin.Theta().Handle: theta.Init(config.Default.Theta.API), + coin.Theta().Handle: theta.Init(config.Default.Theta.API, config.Default.Theta.Key), coin.Waves().Handle: waves.Init(config.Default.Waves.API), coin.Ripple().Handle: ripple.Init(config.Default.Ripple.API), coin.Harmony().Handle: harmony.Init(config.Default.Harmony.API), diff --git a/platform/theta/base.go b/platform/theta/base.go index 503aa1acd..4cdc41325 100644 --- a/platform/theta/base.go +++ b/platform/theta/base.go @@ -10,9 +10,11 @@ type Platform struct { client Client } -func Init(api string) *Platform { +func Init(api, key string) *Platform { + request := client.InitClient(api, middleware.SentryErrorHandler) + request.Headers = map[string]string{"x-api-token": key} return &Platform{ - client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, + client: Client{request}, } } diff --git a/platform/tron/base.go b/platform/tron/base.go index 6b97d8a2d..ca52fca15 100644 --- a/platform/tron/base.go +++ b/platform/tron/base.go @@ -12,7 +12,8 @@ type Platform struct { func Init(api, apiKey string) *Platform { request := client.InitClient(api, middleware.SentryErrorHandler) - request.Headers = map[string]string{"TRON-PRO-API-KEY": apiKey} + //TODO: Add when ready + //request.Headers = map[string]string{"TRON-PRO-API-KEY": apiKey} return &Platform{ client: Client{request}, } diff --git a/services/tokenindexer/indexer.go b/services/tokenindexer/indexer.go index 0295be77b..53826589d 100644 --- a/services/tokenindexer/indexer.go +++ b/services/tokenindexer/indexer.go @@ -37,7 +37,7 @@ func RunTokenIndexer(database *db.Instance, delivery amqp.Delivery) error { assets := GetAssetsFromTransactions(assetsTxs) err = database.AddNewAssets(assets) if err != nil { - log.WithFields(log.Fields{"service": TokenIndexer}).Error("Failed to add new assets", err) + log.WithFields(log.Fields{"service": TokenIndexer, "assets": assets}).Error("Failed to add new assets", err) return err } From 696fb97b7b3197a7da4bb692122a8028ea4e07cf Mon Sep 17 00:00:00 2001 From: hewigovens <360470+hewigovens@users.noreply.github.com> Date: Tue, 6 Apr 2021 03:51:52 +0900 Subject: [PATCH 501/506] [Cosmos] Fix blocks/latest API json response (#1442) * Fix blocks/latest json response * update naming --- platform/cosmos/client.go | 6 +++--- platform/cosmos/model.go | 9 +++------ platform/kava/client.go | 6 +++--- platform/kava/model.go | 9 +++------ 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/platform/cosmos/client.go b/platform/cosmos/client.go index 52fc39263..106e1bfe5 100644 --- a/platform/cosmos/client.go +++ b/platform/cosmos/client.go @@ -42,14 +42,14 @@ func (c *Client) GetBlockByNumber(num int64) (txs TxPage, err error) { } func (c *Client) CurrentBlockNumber() (num int64, err error) { - var block Block - err = c.Get(&block, "blocks/latest", nil) + var latest LasteBlock + err = c.Get(&latest, "blocks/latest", nil) if err != nil { return num, err } - num, err = strconv.ParseInt(block.Meta.Header.Height, 10, 64) + num, err = strconv.ParseInt(latest.Block.Header.Height, 10, 64) if err != nil { return num, err } diff --git a/platform/cosmos/model.go b/platform/cosmos/model.go index f3402985d..49b705b2f 100644 --- a/platform/cosmos/model.go +++ b/platform/cosmos/model.go @@ -216,17 +216,14 @@ type Pool struct { BondedTokens string `json:"bonded_tokens"` } -// Block - top object of get las block request -type Block struct { - Meta BlockMeta `json:"block_meta"` +type LasteBlock struct { + Block Block `json:"block"` } -//BlockMeta - "Block" sub object -type BlockMeta struct { +type Block struct { Header BlockHeader `json:"header"` } -//BlockHeader - "BlockMeta" sub object, height type BlockHeader struct { Height string `json:"height"` } diff --git a/platform/kava/client.go b/platform/kava/client.go index 5bfc03543..a1027bb35 100644 --- a/platform/kava/client.go +++ b/platform/kava/client.go @@ -42,14 +42,14 @@ func (c *Client) GetBlockByNumber(num int64) (txs TxPage, err error) { } func (c *Client) CurrentBlockNumber() (num int64, err error) { - var block Block - err = c.Get(&block, "blocks/latest", nil) + var latest LasteBlock + err = c.Get(&latest, "blocks/latest", nil) if err != nil { return num, err } - num, err = strconv.ParseInt(block.Meta.Header.Height, 10, 64) + num, err = strconv.ParseInt(latest.Block.Header.Height, 10, 64) if err != nil { return num, err } diff --git a/platform/kava/model.go b/platform/kava/model.go index 10093f19c..cb69497a4 100644 --- a/platform/kava/model.go +++ b/platform/kava/model.go @@ -210,17 +210,14 @@ type Pool struct { BondedTokens string `json:"bonded_tokens"` } -// Block - top object of get las block request -type Block struct { - Meta BlockMeta `json:"block"` +type LasteBlock struct { + Block Block `json:"block"` } -//BlockMeta - "Block" sub object -type BlockMeta struct { +type Block struct { Header BlockHeader `json:"header"` } -//BlockHeader - "BlockMeta" sub object, height type BlockHeader struct { Height string `json:"height"` } From 30ce4091856d20b906ded12660a8bc0071ab3f8e Mon Sep 17 00:00:00 2001 From: Anonyma <44095730+Anonyma@users.noreply.github.com> Date: Mon, 10 May 2021 08:01:27 +0200 Subject: [PATCH 502/506] [OASIS] Add Oasis platform (#1421) * Base Oasis integration * Update to use golibs dependency Update "block/tip" endpoint Remove /coin folder (now imported from golibs) Small changes in test Update models to match new ones * Add tests (cases: with fee, without fee, with error) * Add REST API URL * Update with requested changes * Add further requested changes Co-authored-by: Z --- config.yml | 3 + config/configuration.go | 3 + go.sum | 3 + platform/oasis/base.go | 22 ++++++ platform/oasis/block.go | 26 +++++++ platform/oasis/client.go | 42 +++++++++++ platform/oasis/mocks/tx_with_error.json | 12 ++++ platform/oasis/mocks/tx_with_fee.json | 11 +++ platform/oasis/mocks/tx_without_fee.json | 11 +++ platform/oasis/model.go | 28 ++++++++ platform/oasis/transaction.go | 54 ++++++++++++++ platform/oasis/transaction_test.go | 90 ++++++++++++++++++++++++ platform/platform.go | 2 + 13 files changed, 307 insertions(+) create mode 100644 platform/oasis/base.go create mode 100644 platform/oasis/block.go create mode 100644 platform/oasis/client.go create mode 100644 platform/oasis/mocks/tx_with_error.json create mode 100644 platform/oasis/mocks/tx_with_fee.json create mode 100644 platform/oasis/mocks/tx_without_fee.json create mode 100644 platform/oasis/model.go create mode 100644 platform/oasis/transaction.go create mode 100644 platform/oasis/transaction_test.go diff --git a/config.yml b/config.yml index c7cd628ed..5d10c7a89 100644 --- a/config.yml +++ b/config.yml @@ -215,6 +215,9 @@ elrond: filecoin: api: https://api.filscan.io:8700/rpc/v1 explorer: https://filfox.info + +oasis: + api: https://oasis.atlas.zondax.ch smartchain: api: "" diff --git a/config/configuration.go b/config/configuration.go index dc82d9b15..a094c1837 100755 --- a/config/configuration.go +++ b/config/configuration.go @@ -203,6 +203,9 @@ type Configuration struct { API string `mapstructure:"api"` Explorer string `mapstructure:"explorer"` } `mapstructure:"filecoin"` + Oasis struct { + API string `mapstructure:"api"` + } `mapstructure:"oasis"` Sentry struct { DSN string `mapstructure:"dsn"` } `mapstructure:"sentry"` diff --git a/go.sum b/go.sum index 581424068..922ac31d5 100644 --- a/go.sum +++ b/go.sum @@ -451,6 +451,7 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -514,6 +515,7 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -623,6 +625,7 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/platform/oasis/base.go b/platform/oasis/base.go new file mode 100644 index 000000000..8c55d4837 --- /dev/null +++ b/platform/oasis/base.go @@ -0,0 +1,22 @@ +package oasis + +import ( + "github.com/trustwallet/golibs/client" + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/network/middleware" +) + +type Platform struct { + client Client +} + +func Init(api string) *Platform { + p := &Platform{ + client: Client{client.InitClient(api, middleware.SentryErrorHandler)}, + } + return p +} + +func (p *Platform) Coin() coin.Coin { + return coin.Oasis() +} diff --git a/platform/oasis/block.go b/platform/oasis/block.go new file mode 100644 index 000000000..b42e9eab5 --- /dev/null +++ b/platform/oasis/block.go @@ -0,0 +1,26 @@ +package oasis + +import ( + "github.com/trustwallet/golibs/types" +) + +func (p *Platform) CurrentBlockNumber() (int64, error) { + num, err := p.client.GetCurrentBlock() + if err != nil { + return 0, err + } + return num, nil +} + +func (p *Platform) GetBlockByNumber(num int64) (*types.Block, error) { + srcBlock, err := p.client.GetBlockByNumber(num) + if err == nil { + txs := NormalizeTxs(*srcBlock) + return &types.Block{ + Number: num, + Txs: txs, + }, nil + } + + return nil, err +} diff --git a/platform/oasis/client.go b/platform/oasis/client.go new file mode 100644 index 000000000..1f9db9609 --- /dev/null +++ b/platform/oasis/client.go @@ -0,0 +1,42 @@ +package oasis + +import ( + "github.com/trustwallet/golibs/client" +) + +type Client struct { + client.Request +} + +func (c *Client) GetCurrentBlock() (int64, error) { + var blk int64 + + err := c.Post(&blk, "block/tip", nil) + if err != nil { + return 0, err + } + + return blk, nil +} + +func (c *Client) GetBlockByNumber(num int64) (*[]Transaction, error) { + var txs []Transaction + + err := c.Post(&txs, "transactions/block", BlockRequest{BlockIdentifier: num}) + if err != nil { + return nil, err + } + + return &txs, nil +} + +func (c *Client) GetTrxOfAddress(address string) (*[]Transaction, error) { + var txs []Transaction + + err := c.Post(&txs, "transactions/address", TransactionsByAddressRequest{Address: address}) + if err != nil { + return nil, err + } + + return &txs, nil +} diff --git a/platform/oasis/mocks/tx_with_error.json b/platform/oasis/mocks/tx_with_error.json new file mode 100644 index 000000000..f0867f1a5 --- /dev/null +++ b/platform/oasis/mocks/tx_with_error.json @@ -0,0 +1,12 @@ +{ + "tx_hash": "6df10a2d114739ee6007fbd2ae0905b2ae81be6fc1d8ff6c5a9f404923263b84", + "from": "oasis1qrmp3lmcuvxhr9dq90mrrxe2yxzwfqw9xcvqujpu", + "to": "oasis1qqnv3peudzvekhulf8v3ht29z4cthkhy7gkxmph5", + "amount": "10", + "fee": "10", + "date": 1605774037000, + "block": 712027, + "success": false, + "error_message": "insufficient balance", + "sequence": 1 +} diff --git a/platform/oasis/mocks/tx_with_fee.json b/platform/oasis/mocks/tx_with_fee.json new file mode 100644 index 000000000..8ab1730db --- /dev/null +++ b/platform/oasis/mocks/tx_with_fee.json @@ -0,0 +1,11 @@ +{ + "tx_hash": "2b06966eaf27d830cc3c91fe2e38c0d26d38430cf8754be786f66a084ab127d2", + "from": "oasis1qp29h8ykmxet46eqzw0wennrmmy4al3xzv37m3ca", + "to": "oasis1qz9re9hc0k9qxrhvww7x9zrfv8x8jpr4kcr2twr2", + "amount": "1000000000", + "fee": "15000", + "date": 1605717688000, + "block": 702410, + "success": true, + "sequence": 1 +} diff --git a/platform/oasis/mocks/tx_without_fee.json b/platform/oasis/mocks/tx_without_fee.json new file mode 100644 index 000000000..192441189 --- /dev/null +++ b/platform/oasis/mocks/tx_without_fee.json @@ -0,0 +1,11 @@ +{ + "tx_hash": "a49afb8055ef3bbb4fca1e162886ab32b71c5a0d49555793342971237b031972", + "from": "oasis1qpcgnf84hnvvfvzup542rhc8kjyvqf4aqqlj5kqh", + "to": "oasis1qz9re9hc0k9qxrhvww7x9zrfv8x8jpr4kcr2twr2", + "amount": "170000000000", + "fee": "0", + "date": 1610472221000, + "block": 1502238, + "success": true, + "sequence": 5 +} diff --git a/platform/oasis/model.go b/platform/oasis/model.go new file mode 100644 index 000000000..2debfd034 --- /dev/null +++ b/platform/oasis/model.go @@ -0,0 +1,28 @@ +package oasis + +type Block struct { + Height int64 `json:"height"` + Hash string `json:"hash"` + Timestamp int64 `json:"timestamp"` +} + +type BlockRequest struct { + BlockIdentifier int64 `json:"block_identifier"` +} + +type Transaction struct { + Hash string `json:"tx_hash"` + From string `json:"from"` + To string `json:"to"` + Amount string `json:"amount"` + Fee string `json:"fee"` + Date int64 `json:"date"` + Block uint64 `json:"block"` + Success bool `json:"success"` + ErrorMsg string `json:"error_message,omitempty"` + Sequence uint64 `json:"sequence"` +} + +type TransactionsByAddressRequest struct { + Address string `json:"address"` +} diff --git a/platform/oasis/transaction.go b/platform/oasis/transaction.go new file mode 100644 index 000000000..a43e0073f --- /dev/null +++ b/platform/oasis/transaction.go @@ -0,0 +1,54 @@ +package oasis + +import ( + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/types" +) + +func (p *Platform) GetTxsByAddress(address string) (types.Txs, error) { + txs, err := p.client.GetTrxOfAddress(address) + if err != nil { + return nil, err + } + + return NormalizeTxs(*txs), nil +} + +func NormalizeTxs(srcTxs []Transaction) types.Txs { + var txs types.Txs + for _, srcTx := range srcTxs { + tx := NormalizeTx(srcTx) + txs = append(txs, tx) + } + return txs +} + +func NormalizeTx(srcTx Transaction) types.Tx { + symbol := coin.Coins[coin.OASIS].Symbol + decimals := coin.Coins[coin.OASIS].Decimals + + status := types.StatusCompleted + if !srcTx.Success { + status = types.StatusError + } + + nTx := types.Tx{ + ID: srcTx.Hash, + Coin: coin.OASIS, + From: srcTx.From, + To: srcTx.To, + Fee: types.Amount(srcTx.Fee), + Date: srcTx.Date, + Block: srcTx.Block, + Status: status, + Error: srcTx.ErrorMsg, + Sequence: srcTx.Sequence, + Meta: types.Transfer{ + Value: types.Amount(srcTx.Amount), + Symbol: symbol, + Decimals: decimals, + }, + } + + return nTx +} diff --git a/platform/oasis/transaction_test.go b/platform/oasis/transaction_test.go new file mode 100644 index 000000000..d22fd641b --- /dev/null +++ b/platform/oasis/transaction_test.go @@ -0,0 +1,90 @@ +package oasis + +import ( + "github.com/stretchr/testify/assert" + "github.com/trustwallet/golibs/coin" + "github.com/trustwallet/golibs/mock" + "github.com/trustwallet/golibs/types" + "testing" +) + +func TestNormalizeTx(t *testing.T) { + tests := []struct { + name string + filename string + wantTx types.Tx + }{ + { + name: "Test normalize successful transaction without fee", + filename: "tx_without_fee.json", + wantTx: types.Tx{ + ID: "a49afb8055ef3bbb4fca1e162886ab32b71c5a0d49555793342971237b031972", + Coin: coin.OASIS, + From: "oasis1qpcgnf84hnvvfvzup542rhc8kjyvqf4aqqlj5kqh", + To: "oasis1qz9re9hc0k9qxrhvww7x9zrfv8x8jpr4kcr2twr2", + Fee: "0", + Date: 1610472221000, + Block: 1502238, + Status: types.StatusCompleted, + Sequence: 5, + Meta: types.Transfer{ + Value: "170000000000", + Symbol: "ROSE", + Decimals: 9, + }, + }, + }, + { + name: "Test normalize successful transaction with fee", + filename: "tx_with_fee.json", + wantTx: types.Tx{ + ID: "2b06966eaf27d830cc3c91fe2e38c0d26d38430cf8754be786f66a084ab127d2", + Coin: coin.OASIS, + From: "oasis1qp29h8ykmxet46eqzw0wennrmmy4al3xzv37m3ca", + To: "oasis1qz9re9hc0k9qxrhvww7x9zrfv8x8jpr4kcr2twr2", + Fee: "15000", + Date: 1605717688000, + Block: 702410, + Status: types.StatusCompleted, + Sequence: 1, + Meta: types.Transfer{ + Value: "1000000000", + Symbol: "ROSE", + Decimals: 9, + }, + }, + }, + { + name: "Test normalize transaction with error", + filename: "tx_with_error.json", + wantTx: types.Tx{ + ID: "6df10a2d114739ee6007fbd2ae0905b2ae81be6fc1d8ff6c5a9f404923263b84", + Coin: coin.OASIS, + From: "oasis1qrmp3lmcuvxhr9dq90mrrxe2yxzwfqw9xcvqujpu", + To: "oasis1qqnv3peudzvekhulf8v3ht29z4cthkhy7gkxmph5", + Fee: "10", + Date: 1605774037000, + Block: 712027, + Status: types.StatusError, + Error: "insufficient balance", + Sequence: 1, + Meta: types.Transfer{ + Value: "10", + Symbol: "ROSE", + Decimals: 9, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var srcTx Transaction + + err := mock.JsonModelFromFilePath("mocks/"+tt.filename, &srcTx) + assert.Nil(t, err) + + gotTx := NormalizeTx(srcTx) + assert.ObjectsAreEqual(gotTx, tt.wantTx) + }) + } +} diff --git a/platform/platform.go b/platform/platform.go index 920a824d8..13ac899ae 100644 --- a/platform/platform.go +++ b/platform/platform.go @@ -2,6 +2,7 @@ package platform import ( "github.com/trustwallet/blockatlas/config" + "github.com/trustwallet/blockatlas/platform/oasis" "github.com/trustwallet/blockatlas/platform/filecoin" "github.com/trustwallet/blockatlas/platform/kava" @@ -97,6 +98,7 @@ func getAllHandlers() blockatlas.Platforms { coin.Near().Handle: near.Init(config.Default.Near.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), + coin.Oasis().Handle: oasis.Init(config.Default.Oasis.API), } } From 2163c7c62502b80d72f79679874602f3af05f6bd Mon Sep 17 00:00:00 2001 From: Emmanuel Date: Wed, 30 Jun 2021 18:13:42 -0300 Subject: [PATCH 503/506] Fix CI tests (#1451) * apply go mod tidy * add missing dependency --- go.mod | 17 ++++++--- go.sum | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 85ed610a8..9f7336a07 100644 --- a/go.mod +++ b/go.mod @@ -6,22 +6,28 @@ go 1.15 // +heroku install ./cmd/... require ( + github.com/Microsoft/go-winio v0.5.0 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 - github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e // indirect + github.com/cenkalti/backoff/v3 v3.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.1.1 // indirect + github.com/containerd/continuity v0.1.0 // indirect github.com/deckarep/golang-set v1.7.1 github.com/getsentry/raven-go v0.2.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.6.3 github.com/itchyny/timefmt-go v0.1.2 + github.com/jackc/pgconn v1.8.0 // indirect github.com/magefile/mage v1.11.0 // indirect github.com/mitchellh/mapstructure v1.4.1 + github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/mr-tron/base58 v1.2.0 - github.com/opencontainers/runc v1.0.0-rc9 // indirect + github.com/opencontainers/runc v1.0.0 // indirect github.com/ory/dockertest v3.3.5+incompatible + github.com/ory/dockertest/v3 v3.7.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible github.com/prometheus/client_golang v0.9.4 - github.com/sirupsen/logrus v1.8.0 + github.com/sirupsen/logrus v1.8.1 github.com/spf13/viper v1.7.1 github.com/streadway/amqp v1.0.0 github.com/stretchr/testify v1.7.0 @@ -29,9 +35,10 @@ require ( github.com/swaggo/swag v1.7.0 github.com/trustwallet/golibs v0.1.8 github.com/trustwallet/golibs/network v0.0.0-20210302024139-c340cb937103 + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect 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-20210217105451-b926d437f341 // indirect + golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.8 gorm.io/gorm v1.20.12 diff --git a/go.sum b/go.sum index 922ac31d5..a231bda51 100644 --- a/go.sum +++ b/go.sum @@ -14,13 +14,18 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -35,12 +40,14 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 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/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= @@ -54,23 +61,39 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/cilium/ebpf v0.6.1/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e h1:6JKvHHt396/qabvMhnhUZvWaHZzfVfldxE60TK8YLhg= github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -79,6 +102,10 @@ github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9r github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/cli v20.10.7+incompatible h1:pv/3NqibQKphWZiAskMzdz8w0PRbtTaEB+f6NwdU7Is= +github.com/docker/cli v20.10.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ= +github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= @@ -87,6 +114,7 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/evalphobia/logrus_sentry v0.8.2 h1:dotxHq+YLZsT1Bb45bB5UQbfCh3gM/nFFetyN46VoDQ= github.com/evalphobia/logrus_sentry v0.8.2/go.mod h1:pKcp+vriitUqu9KiWj/VRFbRfFNUwz95/UkgG8a6MNc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= @@ -134,10 +162,13 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -148,21 +179,35 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= @@ -191,6 +236,8 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/itchyny/timefmt-go v0.1.2 h1:q0Xa4P5it6K6D7ISsbLAMwx1PnWlixDcJL6/sFs93Hs= github.com/itchyny/timefmt-go v0.1.2/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= @@ -263,6 +310,7 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -271,6 +319,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= @@ -278,6 +327,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -287,6 +337,7 @@ github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls= github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -310,6 +361,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= @@ -317,6 +369,10 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -325,11 +381,13 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -337,8 +395,14 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc= github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0 h1:QOhAQAYUlKeofuyeKdR6ITvOnXLPbEAjPMjz9wCUXcU= +github.com/opencontainers/runc v1.0.0/go.mod h1:MU2S3KEB2ZExnhnAQYbwjdYV6HwKtDlNbA2Z2OeNDeA= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.7.0 h1:Bijzonc69Ont3OU0a3TWKJ1Rzlh3TsDXP1JrTAkSmsM= +github.com/ory/dockertest/v3 v3.7.0/go.mod h1:PvCCgnP7AfBZeVrzwiUTjZx/IUXlGLC1zQlUQrLIlUE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -376,6 +440,7 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= @@ -388,6 +453,8 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU= github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -399,11 +466,13 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= @@ -426,6 +495,7 @@ github.com/swaggo/gin-swagger v1.3.0/go.mod h1:oy1BRA6WvgtCp848lhxce7BnWH4C8Bxa0 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/trustwallet/golibs v0.0.35/go.mod h1:VI0APImKAYxvJ8MnMD6aHSKvnArXUd3NgNEghX5P+K8= github.com/trustwallet/golibs v0.1.8 h1:g/c2RY8XZxOjoT8ZaXUS1X7zeaXvYuy3IJScqZcwMeA= @@ -441,8 +511,20 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/ugorji/go/codec v1.1.13 h1:013LbFhocBoIqgHeIHKlV4JWYhqogATYWZhIcH0WHn4= github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -451,7 +533,6 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -492,6 +573,7 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -508,17 +590,21 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -527,7 +613,9 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -545,20 +633,30 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210217105451-b926d437f341 h1:2/QtM1mL37YmcsT8HaDNHDgTqqFVw+zr8UzMiBVLzYU= golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -567,6 +665,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -584,6 +684,7 @@ golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -593,8 +694,10 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e h1:t96dS3DO8DGjawSLJL/HIdz8CycAd2v07XxqB3UPTi0= golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -622,10 +725,18 @@ google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBr google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -656,6 +767,7 @@ 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= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 0d7acd180f71d37a43ce9cbba11dd21350ceb97a Mon Sep 17 00:00:00 2001 From: Nick Kozlov <22479658+EnoRage@users.noreply.github.com> Date: Wed, 23 Feb 2022 02:49:38 +0300 Subject: [PATCH 504/506] Remove duplicate (#1471) Remove duplicate during queue declaration at cmd/setup/main.go --- cmd/setup/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/setup/main.go b/cmd/setup/main.go index 33de320c7..fb2da5a8e 100644 --- a/cmd/setup/main.go +++ b/cmd/setup/main.go @@ -54,7 +54,6 @@ func main() { internal.Subscriptions, internal.SubscriptionsTokens, internal.RawTokens, - internal.Subscriptions, } for _, queue := range queues { if err := queue.Declare(); err != nil { From 93163b1b120743ef9c57f145109e0fe688e3c0d3 Mon Sep 17 00:00:00 2001 From: Dmytro <2937451+vorotech@users.noreply.github.com> Date: Wed, 16 Mar 2022 10:24:08 +0200 Subject: [PATCH 505/506] upgraded some packages & go mod tidy (#1478) Co-authored-by: vorotech --- go.mod | 19 +++------ go.sum | 129 ++++++++++++++------------------------------------------- 2 files changed, 37 insertions(+), 111 deletions(-) diff --git a/go.mod b/go.mod index 9f7336a07..edd84eca0 100644 --- a/go.mod +++ b/go.mod @@ -6,25 +6,20 @@ go 1.15 // +heroku install ./cmd/... require ( - github.com/Microsoft/go-winio v0.5.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.5.2 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/btcsuite/btcutil v1.0.2 - github.com/cenkalti/backoff/v3 v3.0.0 // indirect - github.com/cenkalti/backoff/v4 v4.1.1 // indirect github.com/containerd/continuity v0.1.0 // indirect github.com/deckarep/golang-set v1.7.1 github.com/getsentry/raven-go v0.2.0 github.com/gin-contrib/cors v1.3.1 - github.com/gin-gonic/gin v1.6.3 + github.com/gin-gonic/gin v1.7.7 github.com/itchyny/timefmt-go v0.1.2 - github.com/jackc/pgconn v1.8.0 // indirect - github.com/magefile/mage v1.11.0 // indirect github.com/mitchellh/mapstructure v1.4.1 - github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/mr-tron/base58 v1.2.0 - github.com/opencontainers/runc v1.0.0 // indirect + github.com/opencontainers/runc v1.1.0 // indirect github.com/ory/dockertest v3.3.5+incompatible - github.com/ory/dockertest/v3 v3.7.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible github.com/prometheus/client_golang v0.9.4 github.com/sirupsen/logrus v1.8.1 @@ -35,10 +30,8 @@ require ( github.com/swaggo/swag v1.7.0 github.com/trustwallet/golibs v0.1.8 github.com/trustwallet/golibs/network v0.0.0-20210302024139-c340cb937103 - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 - golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect - golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect + golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd + golang.org/x/tools v0.0.0-20210106214847-113979e3529a // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/postgres v1.0.8 gorm.io/gorm v1.20.12 diff --git a/go.sum b/go.sum index a231bda51..13cd10500 100644 --- a/go.sum +++ b/go.sum @@ -12,7 +12,6 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= @@ -21,11 +20,9 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= -github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -47,7 +44,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 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/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= @@ -61,23 +57,16 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= -github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= -github.com/cilium/ebpf v0.6.1/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= -github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e h1:6JKvHHt396/qabvMhnhUZvWaHZzfVfldxE60TK8YLhg= -github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -92,8 +81,7 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -102,10 +90,6 @@ github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9r github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/cli v20.10.7+incompatible h1:pv/3NqibQKphWZiAskMzdz8w0PRbtTaEB+f6NwdU7Is= -github.com/docker/cli v20.10.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ= -github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= @@ -131,8 +115,9 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -159,16 +144,16 @@ github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTM github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -177,32 +162,22 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -236,8 +211,6 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/itchyny/timefmt-go v0.1.2 h1:q0Xa4P5it6K6D7ISsbLAMwx1PnWlixDcJL6/sFs93Hs= github.com/itchyny/timefmt-go v0.1.2/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= @@ -310,15 +283,14 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= @@ -327,16 +299,12 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= -github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls= -github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -369,10 +337,7 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -387,22 +352,17 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc= -github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0 h1:QOhAQAYUlKeofuyeKdR6ITvOnXLPbEAjPMjz9wCUXcU= -github.com/opencontainers/runc v1.0.0/go.mod h1:MU2S3KEB2ZExnhnAQYbwjdYV6HwKtDlNbA2Z2OeNDeA= +github.com/opencontainers/runc v1.1.0 h1:O9+X96OcDjkmmZyfaG996kV7yq8HsoU2h1XRRQcefG8= +github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/ory/dockertest/v3 v3.7.0 h1:Bijzonc69Ont3OU0a3TWKJ1Rzlh3TsDXP1JrTAkSmsM= -github.com/ory/dockertest/v3 v3.7.0/go.mod h1:PvCCgnP7AfBZeVrzwiUTjZx/IUXlGLC1zQlUQrLIlUE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -440,7 +400,7 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= @@ -451,8 +411,6 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU= -github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -515,16 +473,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -553,8 +503,8 @@ golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 h1:xYJJ3S178yv++9zXV/hnr29plCAGO9vAFG9dorqaFQc= -golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -573,7 +523,6 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -596,15 +545,12 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -613,7 +559,6 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -644,26 +589,22 @@ golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210217105451-b926d437f341 h1:2/QtM1mL37YmcsT8HaDNHDgTqqFVw+zr8UzMiBVLzYU= -golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c h1:DHcbWVXeY+0Y8HHKR+rbLwnoh2F4tNCY7rTiHJ30RmA= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -684,7 +625,6 @@ golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -694,9 +634,8 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e h1:t96dS3DO8DGjawSLJL/HIdz8CycAd2v07XxqB3UPTi0= golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -727,14 +666,9 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -767,7 +701,6 @@ 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= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 90cae3b2e11c85bd3b7dd304ab34465477634813 Mon Sep 17 00:00:00 2001 From: vorotech Date: Wed, 16 Mar 2022 10:35:31 +0200 Subject: [PATCH 506/506] not maintained notice --- README.md | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 25c9bcbf2..8360baa74 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,18 @@ # Block Atlas by Trust Wallet +THIS REPO IS NO LONGER MAINTAINED + +--- + ![Go Version](https://img.shields.io/github/go-mod/go-version/TrustWallet/blockatlas) -![CI](https://github.com/trustwallet/blockatlas/workflows/CI/badge.svg) [![codecov](https://codecov.io/gh/trustwallet/blockatlas/branch/master/graph/badge.svg)](https://codecov.io/gh/trustwallet/blockatlas) [![Go Report Card](https://goreportcard.com/badge/trustwallet/blockatlas)](https://goreportcard.com/report/TrustWallet/blockatlas) -[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=trustwallet/blockatlas)](https://dependabot.com) > BlockAtlas is a clean explorer API and transaction observer for cryptocurrencies. BlockAtlas connects to nodes or explorer APIs of the supported coins and maps transaction data, account transaction history into a generic, easy to work with JSON format. -It is in production use at the [Trust Wallet app](https://trustwallet.com/), -the official cryptocurrency wallet of Binance. Also is in production at the [BUTTON Wallet](https://buttonwallet.com), Telegram based non-custodial wallet. + The observer API watches the chain for new transactions and generates notifications by guids. #### Supported Coins @@ -20,10 +21,6 @@ Block Atlas supports more than 25 blockchains: Bitcoin, Ethereum, Binance Chain ## Architecture -#### NOTE - -Currently Block Atlas is under active development and is not well documented. If you still want to run it on your own or help to contribute, **please** pay attention that currently integration, nemwan, functional tests are not working locally without all endpoints. We are fixing that issue and soon you will be able to test all the stuff locally - Blockatlas allows to: - Get information about transactions, tokens, staking details, collectibles for supported coins. @@ -216,15 +213,3 @@ swagger serve docs/swagger.yaml - After creating a new route, add comments to your API source code, [See Declarative Comments Format](https://swaggo.github.io/swaggo.io/declarative_comments_format/). - Run `$ make go-gen-docs` in root folder. - -## Contributing - -If you'd like to add support for a new blockchain, feel free to file a pull request. -Note that most tokens that run on top of other chains are already supported and -don't require code changes (e.g. ERC-20). - -The best way to submit feedback and report bugs is to open a GitHub issue. -Please be sure to include your operating system, version number, and -[steps](https://gist.github.com/nrollr/eb24336b8fb8e7ba5630) to reproduce reported bugs. - -More resources for developers are in [CONTRIBUTING.md](CONTRIBUTING.md).